Merging upstream version 2.2.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
c6eb8bc90e
commit
965e6654c3
446 changed files with 8369 additions and 4059 deletions
|
@ -2,4 +2,6 @@ sources += [
|
|||
'plugins/solidigm/solidigm-smart.c',
|
||||
'plugins/solidigm/solidigm-garbage-collection.c',
|
||||
'plugins/solidigm/solidigm-latency-tracking.c',
|
||||
'plugins/solidigm/solidigm-telemetry.c',
|
||||
]
|
||||
subdir('solidigm-telemetry')
|
||||
|
|
|
@ -56,13 +56,15 @@ static void vu_gc_log_show(garbage_control_collection_log_t *payload, const char
|
|||
|
||||
for (int i = 0; i < VU_GC_MAX_ITEMS; i++) {
|
||||
gc_item_t item = payload->item[i];
|
||||
printf("%-13lu %d\n",le64_to_cpu(item.timestamp), le32_to_cpu(item.timer_type));
|
||||
printf("%-13" PRIu64 " %d\n", le64_to_cpu(item.timestamp), le32_to_cpu(item.timer_type));
|
||||
}
|
||||
}
|
||||
|
||||
int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "Get and parse Solidigm vendor specific garbage collection event log.";
|
||||
struct nvme_dev *dev;
|
||||
int err;
|
||||
|
||||
struct config {
|
||||
char *output_format;
|
||||
|
@ -77,35 +79,37 @@ int solidigm_get_garbage_collection_log(int argc, char **argv, struct command *c
|
|||
OPT_END()
|
||||
};
|
||||
|
||||
int fd = parse_and_open(argc, argv, desc, opts);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
enum nvme_print_flags flags = validate_output_format(cfg.output_format);
|
||||
if (flags == -EINVAL) {
|
||||
fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format);
|
||||
close(fd);
|
||||
return flags;
|
||||
dev_close(dev);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
garbage_control_collection_log_t gc_log;
|
||||
const int solidigm_vu_gc_log_id = 0xfd;
|
||||
|
||||
int err = nvme_get_log_simple(fd, solidigm_vu_gc_log_id, sizeof(gc_log), &gc_log);
|
||||
err = nvme_get_log_simple(dev_fd(dev), solidigm_vu_gc_log_id,
|
||||
sizeof(gc_log), &gc_log);
|
||||
if (!err) {
|
||||
if (flags & BINARY) {
|
||||
d_raw((unsigned char *)&gc_log, sizeof(gc_log));
|
||||
} else if (flags & JSON) {
|
||||
vu_gc_log_show_json(&gc_log, devicename);
|
||||
vu_gc_log_show_json(&gc_log, dev->name);
|
||||
} else {
|
||||
vu_gc_log_show(&gc_log, devicename);
|
||||
vu_gc_log_show(&gc_log, dev->name);
|
||||
}
|
||||
}
|
||||
else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
/* Redundant close() to make static code analysis happy */
|
||||
close(dev->direct.fd);
|
||||
dev_close(dev);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -216,7 +216,7 @@ static void latency_tracker_pre_parse(struct latency_tracker *lt)
|
|||
printf("Major Revision: %u\nMinor Revision: %u\n",
|
||||
le16_to_cpu(lt->stats.version_major), le16_to_cpu(lt->stats.version_minor));
|
||||
if (lt->has_average_latency_field) {
|
||||
printf("Average Latency: %lu\n", le64_to_cpu(lt->stats.average_latency));
|
||||
printf("Average Latency: %" PRIu64 "\n", le64_to_cpu(lt->stats.average_latency));
|
||||
}
|
||||
print_dash_separator();
|
||||
printf("%-12s%-12s%-12s%-20s\n", "Bucket", "Start", "End", "Value");
|
||||
|
@ -385,6 +385,7 @@ int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd
|
|||
struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "Get and Parse Solidigm Latency Tracking Statistics log.";
|
||||
struct nvme_dev *dev;
|
||||
__u32 enabled;
|
||||
int err;
|
||||
|
||||
|
@ -407,43 +408,45 @@ int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd
|
|||
OPT_END()
|
||||
};
|
||||
|
||||
lt.fd = parse_and_open(argc, argv, desc, opts);
|
||||
if (lt.fd < 0)
|
||||
return lt.fd;
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
lt.fd = dev_fd(dev);
|
||||
|
||||
lt.print_flags = validate_output_format(lt.cfg.output_format);
|
||||
if (lt.print_flags == -EINVAL) {
|
||||
fprintf(stderr, "Invalid output format '%s'\n", lt.cfg.output_format);
|
||||
close(lt.fd);
|
||||
dev_close(dev);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (lt.cfg.type > 0xf) {
|
||||
fprintf(stderr, "Invalid Log type value '%d'\n", lt.cfg.type);
|
||||
close(lt.fd);
|
||||
dev_close(dev);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (lt.cfg.type && !(lt.cfg.read || lt.cfg.write)) {
|
||||
fprintf(stderr, "Log type option valid only when retrieving statistics\n");
|
||||
close(lt.fd);
|
||||
dev_close(dev);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
err = latency_tracking_enable(<);
|
||||
if (err){
|
||||
close(lt.fd);
|
||||
dev_close(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = latency_tracker_get_log(<);
|
||||
if (err){
|
||||
close(lt.fd);
|
||||
dev_close(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((lt.cfg.read || lt.cfg.write || lt.cfg.enable || lt.cfg.disable)) {
|
||||
close(lt.fd);
|
||||
dev_close(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -465,6 +468,8 @@ int solidigm_get_latency_tracking_log(int argc, char **argv, struct command *cmd
|
|||
} else {
|
||||
fprintf(stderr, "Could not read feature id 0xE2.\n");
|
||||
}
|
||||
close(lt.fd);
|
||||
/* Redundant close() to make static code analysis happy */
|
||||
close(dev->direct.fd);
|
||||
dev_close(dev);
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "solidigm-smart.h"
|
||||
#include "solidigm-garbage-collection.h"
|
||||
#include "solidigm-latency-tracking.h"
|
||||
#include "solidigm-telemetry.h"
|
||||
|
||||
static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
|
@ -27,4 +28,9 @@ static int get_garbage_collection_log(int argc, char **argv, struct command *cmd
|
|||
static int get_latency_tracking_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
return solidigm_get_latency_tracking_log(argc, argv, cmd, plugin);
|
||||
}
|
||||
|
||||
static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
return solidigm_get_telemetry_log(argc, argv, cmd, plugin);
|
||||
}
|
|
@ -13,13 +13,14 @@
|
|||
|
||||
#include "cmd.h"
|
||||
|
||||
#define SOLIDIGM_PLUGIN_VERSION "0.4"
|
||||
#define SOLIDIGM_PLUGIN_VERSION "0.6"
|
||||
|
||||
PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION),
|
||||
COMMAND_LIST(
|
||||
ENTRY("smart-log-add", "Retrieve Solidigm SMART Log", get_additional_smart_log)
|
||||
ENTRY("garbage-collect-log", "Retrieve Garbage Collection Log", get_garbage_collection_log)
|
||||
ENTRY("latency-tracking-log", "Enable/Retrieve Latency tracking Log", get_latency_tracking_log)
|
||||
ENTRY("parse-telemetry-log", "Parse Telemetry Log binary", get_telemetry_log)
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <endian.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "nvme.h"
|
||||
|
@ -201,7 +199,8 @@ int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd
|
|||
const int solidigm_vu_smart_log_id = 0xCA;
|
||||
vu_smart_log_t smart_log_payload;
|
||||
enum nvme_print_flags flags;
|
||||
int fd, err;
|
||||
struct nvme_dev *dev;
|
||||
int err;
|
||||
|
||||
struct config {
|
||||
__u32 namespace_id;
|
||||
|
@ -219,32 +218,36 @@ int solidigm_get_additional_smart_log(int argc, char **argv, struct command *cmd
|
|||
OPT_END()
|
||||
};
|
||||
|
||||
fd = parse_and_open(argc, argv, desc, opts);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
flags = validate_output_format(cfg.output_format);
|
||||
if (flags == -EINVAL) {
|
||||
fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format);
|
||||
close(fd);
|
||||
dev_close(dev);
|
||||
return flags;
|
||||
}
|
||||
|
||||
err = nvme_get_log_simple(fd, solidigm_vu_smart_log_id, sizeof(smart_log_payload), &smart_log_payload);
|
||||
err = nvme_get_log_simple(dev_fd(dev), solidigm_vu_smart_log_id,
|
||||
sizeof(smart_log_payload), &smart_log_payload);
|
||||
if (!err) {
|
||||
if (flags & JSON) {
|
||||
vu_smart_log_show_json(&smart_log_payload, cfg.namespace_id, devicename);
|
||||
vu_smart_log_show_json(&smart_log_payload,
|
||||
cfg.namespace_id, dev->name);
|
||||
} else if (flags & BINARY) {
|
||||
d_raw((unsigned char *)&smart_log_payload, sizeof(smart_log_payload));
|
||||
} else {
|
||||
vu_smart_log_show(&smart_log_payload, cfg.namespace_id, devicename);
|
||||
vu_smart_log_show(&smart_log_payload, cfg.namespace_id,
|
||||
dev->name);
|
||||
}
|
||||
} else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
/* Redundant close() to make static code analysis happy */
|
||||
close(dev->direct.fd);
|
||||
dev_close(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
183
plugins/solidigm/solidigm-telemetry.c
Normal file
183
plugins/solidigm/solidigm-telemetry.c
Normal file
|
@ -0,0 +1,183 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "nvme.h"
|
||||
#include "libnvme.h"
|
||||
#include "plugin.h"
|
||||
#include "nvme-print.h"
|
||||
#include "solidigm-telemetry.h"
|
||||
#include "solidigm-telemetry/telemetry-log.h"
|
||||
#include "solidigm-telemetry/cod.h"
|
||||
#include "solidigm-telemetry/header.h"
|
||||
#include "solidigm-telemetry/config.h"
|
||||
#include "solidigm-telemetry/data-area.h"
|
||||
|
||||
static int read_file2buffer(char *file_name, char **buffer, size_t *length)
|
||||
{
|
||||
FILE *fd = fopen(file_name, "rb");
|
||||
|
||||
if (!fd)
|
||||
return errno;
|
||||
|
||||
fseek(fd, 0, SEEK_END);
|
||||
size_t length_bytes = ftell(fd);
|
||||
|
||||
fseek(fd, 0, SEEK_SET);
|
||||
|
||||
*buffer = malloc(length_bytes);
|
||||
if (!*buffer) {
|
||||
fclose(fd);
|
||||
return errno;
|
||||
}
|
||||
*length = fread(*buffer, 1, length_bytes, fd);
|
||||
fclose(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct config {
|
||||
__u32 host_gen;
|
||||
bool ctrl_init;
|
||||
int data_area;
|
||||
char *cfg_file;
|
||||
bool is_input_file;
|
||||
};
|
||||
|
||||
int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
|
||||
{
|
||||
const char *desc = "Parse Solidigm Telemetry log";
|
||||
const char *hgen = "Controls when to generate new host initiated report. Default value '1' generates new host initiated report, value '0' causes retrieval of existing log.";
|
||||
const char *cgen = "Gather report generated by the controller.";
|
||||
const char *dgen = "Pick which telemetry data area to report. Default is 3 to fetch areas 1-3. Valid options are 1, 2, 3, 4.";
|
||||
const char *cfile = "JSON configuration file";
|
||||
const char *sfile = "data source <device> is binary file containing log dump instead of block or character device";
|
||||
struct nvme_dev *dev;
|
||||
|
||||
struct telemetry_log tl = {
|
||||
.root = json_create_object(),
|
||||
.log = NULL,
|
||||
};
|
||||
|
||||
struct config cfg = {
|
||||
.host_gen = 1,
|
||||
.ctrl_init = false,
|
||||
.data_area = 3,
|
||||
.cfg_file = NULL,
|
||||
.is_input_file = false,
|
||||
};
|
||||
|
||||
OPT_ARGS(opts) = {
|
||||
OPT_UINT("host-generate", 'g', &cfg.host_gen, hgen),
|
||||
OPT_FLAG("controller-init", 'c', &cfg.ctrl_init, cgen),
|
||||
OPT_UINT("data-area", 'd', &cfg.data_area, dgen),
|
||||
OPT_FILE("config-file", 'j', &cfg.cfg_file, cfile),
|
||||
OPT_FLAG("source-file", 's', &cfg.is_input_file, sfile),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
int err = argconfig_parse(argc, argv, desc, opts);
|
||||
|
||||
if (err)
|
||||
goto ret;
|
||||
|
||||
if (cfg.is_input_file) {
|
||||
if (optind >= argc) {
|
||||
err = errno = EINVAL;
|
||||
perror(argv[0]);
|
||||
goto ret;
|
||||
}
|
||||
char *binary_file_name = argv[optind];
|
||||
|
||||
err = read_file2buffer(binary_file_name, (char **)&tl.log, &tl.log_size);
|
||||
} else {
|
||||
err = parse_and_open(&dev, argc, argv, desc, opts);
|
||||
}
|
||||
if (err)
|
||||
goto ret;
|
||||
|
||||
if (cfg.host_gen > 1) {
|
||||
SOLIDIGM_LOG_WARNING("Invalid host-generate value '%d'", cfg.host_gen);
|
||||
err = EINVAL;
|
||||
goto close_fd;
|
||||
}
|
||||
|
||||
if (cfg.cfg_file) {
|
||||
char *conf_str = 0;
|
||||
size_t length = 0;
|
||||
|
||||
err = read_file2buffer(cfg.cfg_file, &conf_str, &length);
|
||||
if (err) {
|
||||
SOLIDIGM_LOG_WARNING("Failed to open JSON configuration file %s: %s!",
|
||||
cfg.cfg_file, strerror(err));
|
||||
goto close_fd;
|
||||
}
|
||||
json_tokener * jstok = json_tokener_new();
|
||||
|
||||
tl.configuration = json_tokener_parse_ex(jstok, conf_str, length);
|
||||
if (jstok->err != json_tokener_success) {
|
||||
SOLIDIGM_LOG_WARNING("Parsing error on JSON configuration file %s: %s (at offset %d)",
|
||||
cfg.cfg_file,
|
||||
json_tokener_error_desc(jstok->err),
|
||||
jstok->char_offset);
|
||||
json_tokener_free(jstok);
|
||||
err = EINVAL;
|
||||
goto close_fd;
|
||||
}
|
||||
json_tokener_free(jstok);
|
||||
}
|
||||
|
||||
if (!cfg.is_input_file) {
|
||||
if (cfg.ctrl_init)
|
||||
err = nvme_get_ctrl_telemetry(dev_fd(dev), true,
|
||||
&tl.log, cfg.data_area,
|
||||
&tl.log_size);
|
||||
else if (cfg.host_gen)
|
||||
err = nvme_get_new_host_telemetry(dev_fd(dev), &tl.log,
|
||||
cfg.data_area,
|
||||
&tl.log_size);
|
||||
else
|
||||
err = nvme_get_host_telemetry(dev_fd(dev), &tl.log,
|
||||
cfg.data_area,
|
||||
&tl.log_size);
|
||||
|
||||
if (err < 0) {
|
||||
SOLIDIGM_LOG_WARNING("get-telemetry-log: %s",
|
||||
nvme_strerror(errno));
|
||||
goto close_fd;
|
||||
} else if (err > 0) {
|
||||
nvme_show_status(err);
|
||||
SOLIDIGM_LOG_WARNING("Failed to acquire telemetry log %d!", err);
|
||||
goto close_fd;
|
||||
}
|
||||
}
|
||||
solidigm_telemetry_log_header_parse(&tl);
|
||||
if (cfg.cfg_file)
|
||||
solidigm_telemetry_log_data_areas_parse(&tl, cfg.data_area);
|
||||
else
|
||||
solidigm_telemetry_log_cod_parse(&tl);
|
||||
|
||||
json_print_object(tl.root, NULL);
|
||||
json_free_object(tl.root);
|
||||
printf("\n");
|
||||
|
||||
close_fd:
|
||||
if (!cfg.is_input_file) {
|
||||
/* Redundant close() to make static code analysis happy */
|
||||
close(dev->direct.fd);
|
||||
dev_close(dev);
|
||||
}
|
||||
ret:
|
||||
json_free_object(tl.configuration);
|
||||
free(tl.log);
|
||||
return err;
|
||||
}
|
8
plugins/solidigm/solidigm-telemetry.h
Normal file
8
plugins/solidigm/solidigm-telemetry.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (c) 2022 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
|
||||
int solidigm_get_telemetry_log(int argc, char **argv, struct command *cmd, struct plugin *plugin);
|
194
plugins/solidigm/solidigm-telemetry/cod.c
Normal file
194
plugins/solidigm/solidigm-telemetry/cod.c
Normal file
|
@ -0,0 +1,194 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright (c) 2022 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "cod.h"
|
||||
|
||||
const char *oemDataMapDesc[] = {
|
||||
"Media Read Count", //Uid 0x00
|
||||
"Host Read count", //Uid 0x01
|
||||
"Media Write Count", //Uid 0x02
|
||||
"Host Write Count", //Uid 0x03
|
||||
"Device Model", // 0x04
|
||||
"Serial Number", // 0x05
|
||||
"Firmware Revision", // 0x06
|
||||
"Drive Status", // 0x07
|
||||
"Minimum Temperature", // 0x08
|
||||
"Maximum Temperature", // 0x09
|
||||
"Power Loss Protection Status", // 0x0a
|
||||
"Lifetime Unsafe Shutdown Count", // 0x0b
|
||||
"Lifetime Power Cycle Count", // 0x0c
|
||||
"Minimum Read Latency", // 0x0d
|
||||
"Maximum Read Latency", // 0x0e
|
||||
"Average Read Latency", // 0x0f
|
||||
"Minimum Write Latency", // 0x10
|
||||
"Maximum Write Latency", // 0x11
|
||||
"Average Write Latency", // 0x12
|
||||
"Grown Defects Count", // 0x13
|
||||
"DQS Recovery Count", // 0x14
|
||||
"Program Fail Count", // 0x15
|
||||
"Erase Fail Count", // 0x16
|
||||
"Defrag Writes in Progress Count", // 0x17
|
||||
"Total Defrag Writes Count", // 0x18
|
||||
"Max Die Offline Number", // 0x19
|
||||
"Current Die Offline Number", // 0x1A
|
||||
"XOR Enable Status", // 0x1B
|
||||
"Media Life Used", // 0x1C
|
||||
"Uncorrectable Error Count", // 0x1D
|
||||
"Current Wear Range Delta", // 0x1E
|
||||
"Read Errors Corrected by XOR", // 0x1F
|
||||
"Background Data Refresh", // 0x20
|
||||
"Pmic Vin History Data 1 Min", // 0x21
|
||||
"Pmic Vin History Data 1 Max", // 0x22
|
||||
"Pmic Vin History Data 1 Avg", // 0x23
|
||||
"Pmic Vin History Data 2 Min", // 0x24
|
||||
"Pmic Vin History Data 2 Max", // 0x25
|
||||
"Pmic Vin History Data 2 Avg", // 0x26
|
||||
"Pmic Vin History Data Total Readings", // 0x27
|
||||
"All Time Current Max Wear Level", // 0x28
|
||||
"Media Wear Remaining", // 0x29
|
||||
"Total Non-Defrag Writes", // 0x2A
|
||||
"Number of sectors relocated in reaction to an error" //Uid 0x2B = 43
|
||||
};
|
||||
|
||||
static const char * getOemDataMapDescription(__u32 id)
|
||||
{
|
||||
if (id < (sizeof(oemDataMapDesc) / sizeof(oemDataMapDesc[0]))) {
|
||||
return oemDataMapDesc[id];
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
#define OEMSIGNATURE 0x504D4443
|
||||
|
||||
#pragma pack(push, cod, 1)
|
||||
struct cod_header
|
||||
{
|
||||
uint32_t versionMajor;
|
||||
uint32_t versionMinor;
|
||||
uint32_t Signature; //!Fixed signature value (0x504D4443) for identification and validation
|
||||
uint32_t MapSizeInBytes; //!Total size of the map data structure in bytes
|
||||
uint32_t EntryCount; //!Total number of entries in the entry list
|
||||
uint8_t Reserved[12];
|
||||
};
|
||||
|
||||
struct cod_item
|
||||
{
|
||||
uint32_t DataFieldMapUid; //!The data field unique identifier value
|
||||
uint32_t reserved1 : 8;
|
||||
uint32_t dataFieldType : 8;
|
||||
uint32_t issigned : 1;
|
||||
uint32_t bigEndian : 1;
|
||||
uint32_t dataInvalid : 1;
|
||||
uint32_t reserved2 : 13;
|
||||
uint32_t DataFieldSizeInBytes;
|
||||
uint8_t Reserved1[4];
|
||||
uint64_t DataFieldOffset;
|
||||
uint8_t Reserved2[8];
|
||||
};
|
||||
|
||||
struct cod_map
|
||||
{
|
||||
struct cod_header header;
|
||||
struct cod_item items[];
|
||||
};
|
||||
|
||||
#pragma pack(pop, cod)
|
||||
|
||||
void solidigm_telemetry_log_cod_parse(struct telemetry_log *tl)
|
||||
{
|
||||
enum cod_field_type
|
||||
{
|
||||
INTEGER,
|
||||
FLOAT,
|
||||
STRING,
|
||||
TWO_BYTE_ASCII,
|
||||
FOUR_BYTE_ASCII,
|
||||
|
||||
UNKNOWN = 0xFF,
|
||||
};
|
||||
json_object *telemetry_header = NULL;
|
||||
json_object *COD_offset = NULL;
|
||||
json_object *reason_id = NULL;
|
||||
|
||||
if (!json_object_object_get_ex(tl->root, "telemetryHeader", &telemetry_header))
|
||||
return;
|
||||
if (!json_object_object_get_ex(telemetry_header, "reasonIdentifier", &reason_id))
|
||||
return;
|
||||
if (!json_object_object_get_ex(reason_id, "OemDataMapOffset", &COD_offset))
|
||||
return;
|
||||
|
||||
__u64 offset = json_object_get_int(COD_offset);
|
||||
|
||||
if (offset == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((offset + sizeof(struct cod_header)) > tl->log_size) {
|
||||
SOLIDIGM_LOG_WARNING("Warning: COD map header out of bounds.");
|
||||
return;
|
||||
}
|
||||
|
||||
const struct cod_map *data = (struct cod_map *) (((__u8 *)tl->log ) + offset);
|
||||
|
||||
uint32_t signature = be32_to_cpu(data->header.Signature);
|
||||
if ( signature != OEMSIGNATURE){
|
||||
SOLIDIGM_LOG_WARNING("Warning: Unsupported COD data signature %x!", signature);
|
||||
return;
|
||||
}
|
||||
if ((offset + data->header.MapSizeInBytes) > tl->log_size){
|
||||
SOLIDIGM_LOG_WARNING("Warning: COD map data out of bounds.");
|
||||
return;
|
||||
}
|
||||
|
||||
json_object *cod = json_create_object();
|
||||
json_object_object_add(tl->root, "cod", cod);
|
||||
|
||||
for (int i =0 ; i < data->header.EntryCount; i++) {
|
||||
if ((offset + sizeof(struct cod_header) + (i + 1) * sizeof(struct cod_item)) >
|
||||
tl->log_size){
|
||||
SOLIDIGM_LOG_WARNING("Warning: COD data out of bounds at item %d!", i);
|
||||
return;
|
||||
}
|
||||
struct cod_item item = data->items[i];
|
||||
if (item.DataFieldOffset + item.DataFieldOffset > tl->log_size) {
|
||||
continue;
|
||||
}
|
||||
if (item.dataInvalid) {
|
||||
continue;
|
||||
}
|
||||
uint8_t *val = ((uint8_t *)tl->log )+ item.DataFieldOffset;
|
||||
const char *key = getOemDataMapDescription(item.DataFieldMapUid);
|
||||
switch(item.dataFieldType){
|
||||
case(INTEGER):
|
||||
if (item.issigned) {
|
||||
json_object_object_add(cod, key,
|
||||
json_object_new_int64(le64_to_cpu(*(uint64_t *)val)));
|
||||
} else {
|
||||
json_object_add_value_uint64(cod, key, le64_to_cpu(*(uint64_t *)val));
|
||||
}
|
||||
break;
|
||||
case(FLOAT):
|
||||
json_object_add_value_float(cod, key, *(float *) val);
|
||||
break;
|
||||
case(STRING):
|
||||
json_object_object_add(cod, key,
|
||||
json_object_new_string_len((const char *)val, item.DataFieldSizeInBytes));
|
||||
break;
|
||||
case(TWO_BYTE_ASCII):
|
||||
json_object_object_add(cod, key,
|
||||
json_object_new_string_len((const char *)val,2));
|
||||
break;
|
||||
case(FOUR_BYTE_ASCII):
|
||||
json_object_object_add(cod, key,
|
||||
json_object_new_string_len((const char *)val, 4));
|
||||
break;
|
||||
default:
|
||||
SOLIDIGM_LOG_WARNING("Warning: Unknown COD field type (%d)", item.DataFieldMapUid);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
9
plugins/solidigm/solidigm-telemetry/cod.h
Normal file
9
plugins/solidigm/solidigm-telemetry/cod.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright (c) 2022 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
|
||||
#include "telemetry-log.h"
|
||||
void solidigm_telemetry_log_cod_parse(struct telemetry_log *tl);
|
44
plugins/solidigm/solidigm-telemetry/config.c
Normal file
44
plugins/solidigm/solidigm-telemetry/config.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright (c) 2022 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include "util/json.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// max 16 bit unsigned integer nummber 65535
|
||||
#define MAX_16BIT_NUM_AS_STRING_SIZE 6
|
||||
|
||||
static bool config_get_by_version(const json_object *obj, int version_major,
|
||||
int version_minor, json_object **value)
|
||||
{
|
||||
char str_key[MAX_16BIT_NUM_AS_STRING_SIZE];
|
||||
char str_subkey[MAX_16BIT_NUM_AS_STRING_SIZE];
|
||||
|
||||
snprintf(str_key, sizeof(str_key), "%d", version_major);
|
||||
snprintf(str_subkey, sizeof(str_subkey), "%d", version_minor);
|
||||
json_object *major_obj = NULL;
|
||||
|
||||
if (!json_object_object_get_ex(obj, str_key, &major_obj))
|
||||
return false;
|
||||
if (!json_object_object_get_ex(major_obj, str_subkey, value))
|
||||
return false;
|
||||
return value != NULL;
|
||||
}
|
||||
|
||||
bool solidigm_config_get_by_token_version(const json_object *obj, int token_id,
|
||||
int version_major, int version_minor,
|
||||
json_object **value)
|
||||
{
|
||||
json_object *token_obj = NULL;
|
||||
char str_key[MAX_16BIT_NUM_AS_STRING_SIZE];
|
||||
|
||||
snprintf(str_key, sizeof(str_key), "%d", token_id);
|
||||
if (!json_object_object_get_ex(obj, str_key, &token_obj))
|
||||
return false;
|
||||
if (!config_get_by_version(token_obj, version_major, version_minor, value))
|
||||
return false;
|
||||
return value != NULL;
|
||||
}
|
10
plugins/solidigm/solidigm-telemetry/config.h
Normal file
10
plugins/solidigm/solidigm-telemetry/config.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright (c) 2022 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include "util/json.h"
|
||||
|
||||
bool solidigm_config_get_by_token_version(const json_object *obj, int key, int subkey, int subsubkey, json_object **value);
|
424
plugins/solidigm/solidigm-telemetry/data-area.c
Normal file
424
plugins/solidigm/solidigm-telemetry/data-area.c
Normal file
|
@ -0,0 +1,424 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright (c) 2022 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "data-area.h"
|
||||
#include "config.h"
|
||||
#include <ctype.h>
|
||||
|
||||
#define SIGNED_INT_PREFIX "int"
|
||||
#define BITS_IN_BYTE 8
|
||||
|
||||
#define MAX_WARNING_SIZE 1024
|
||||
|
||||
static bool telemetry_log_get_value(const struct telemetry_log *tl,
|
||||
uint32_t offset_bit, uint32_t size_bit,
|
||||
bool is_signed, json_object **val_obj)
|
||||
{
|
||||
uint32_t offset_bit_from_byte;
|
||||
uint32_t additional_size_byte;
|
||||
uint32_t offset_byte;
|
||||
uint32_t val;
|
||||
|
||||
if (size_bit == 0) {
|
||||
char err_msg[MAX_WARNING_SIZE];
|
||||
|
||||
snprintf(err_msg, MAX_WARNING_SIZE,
|
||||
"Value with size_bit=0 not supported.");
|
||||
*val_obj = json_object_new_string(err_msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
additional_size_byte = (size_bit - 1) ? (size_bit - 1) / BITS_IN_BYTE : 0;
|
||||
offset_byte = offset_bit / BITS_IN_BYTE;
|
||||
|
||||
if (offset_byte > (tl->log_size - additional_size_byte)) {
|
||||
char err_msg[MAX_WARNING_SIZE];
|
||||
|
||||
snprintf(err_msg, MAX_WARNING_SIZE,
|
||||
"Value offset greater than binary size (%u > %zu).",
|
||||
offset_byte, tl->log_size);
|
||||
*val_obj = json_object_new_string(err_msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
offset_bit_from_byte = offset_bit - (offset_byte * BITS_IN_BYTE);
|
||||
|
||||
if ((size_bit + offset_bit_from_byte) > (sizeof(uint64_t) * BITS_IN_BYTE)) {
|
||||
char err_msg[MAX_WARNING_SIZE];
|
||||
|
||||
snprintf(err_msg, MAX_WARNING_SIZE,
|
||||
"Value crossing 64 bit, byte aligned bounday, "
|
||||
"not supported. size_bit=%u, offset_bit_from_byte=%u.",
|
||||
size_bit, offset_bit_from_byte);
|
||||
*val_obj = json_object_new_string(err_msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
val = *(uint64_t *)(((char *)tl->log) + offset_byte);
|
||||
val >>= offset_bit_from_byte;
|
||||
if (size_bit < 64)
|
||||
val &= (1ULL << size_bit) - 1;
|
||||
if (is_signed) {
|
||||
if (val >> (size_bit - 1))
|
||||
val |= -1ULL << size_bit;
|
||||
*val_obj = json_object_new_int64(val);
|
||||
} else {
|
||||
*val_obj = json_object_new_uint64(val);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int telemetry_log_structure_parse(const struct telemetry_log *tl,
|
||||
json_object *struct_def,
|
||||
size_t parent_offset_bit,
|
||||
json_object *output,
|
||||
json_object *metadata)
|
||||
{
|
||||
json_object *obj_arraySizeArray = NULL;
|
||||
json_object *obj = NULL;
|
||||
json_object *obj_memberList;
|
||||
json_object *major_dimension;
|
||||
json_object *sub_output;
|
||||
bool is_enumeration = false;
|
||||
bool has_member_list;
|
||||
const char *type = "";
|
||||
const char *name;
|
||||
size_t array_rank;
|
||||
size_t offset_bit;
|
||||
size_t size_bit;
|
||||
uint32_t linear_array_pos_bit;
|
||||
|
||||
if (!json_object_object_get_ex(struct_def, "name", &obj)) {
|
||||
SOLIDIGM_LOG_WARNING("Warning: Structure definition missing property 'name': %s",
|
||||
json_object_to_json_string(struct_def));
|
||||
return -1;
|
||||
}
|
||||
|
||||
name = json_object_get_string(obj);
|
||||
|
||||
if (metadata) {
|
||||
json_object_get(obj);
|
||||
json_object_object_add(metadata, "objName", obj);
|
||||
}
|
||||
|
||||
if (json_object_object_get_ex(struct_def, "type", &obj))
|
||||
type = json_object_get_string(obj);
|
||||
|
||||
if (!json_object_object_get_ex(struct_def, "offsetBit", &obj)) {
|
||||
SOLIDIGM_LOG_WARNING("Warning: Structure definition missing "
|
||||
"property 'offsetBit': %s",
|
||||
json_object_to_json_string(struct_def));
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset_bit = json_object_get_uint64(obj);
|
||||
|
||||
if (!json_object_object_get_ex(struct_def, "sizeBit", &obj)) {
|
||||
SOLIDIGM_LOG_WARNING("Warning: Structure definition missing "
|
||||
"property 'sizeBit': %s",
|
||||
json_object_to_json_string(struct_def));
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_bit = json_object_get_uint64(obj);
|
||||
|
||||
if (json_object_object_get_ex(struct_def, "enum", &obj))
|
||||
is_enumeration = json_object_get_boolean(obj);
|
||||
|
||||
has_member_list = json_object_object_get_ex(struct_def,
|
||||
"memberList",
|
||||
&obj_memberList);
|
||||
|
||||
if (!json_object_object_get_ex(struct_def, "arraySize",
|
||||
&obj_arraySizeArray)) {
|
||||
SOLIDIGM_LOG_WARNING("Warning: Structure definition missing "
|
||||
"property 'arraySize': %s",
|
||||
json_object_to_json_string(struct_def));
|
||||
return -1;
|
||||
}
|
||||
|
||||
array_rank = json_object_array_length(obj_arraySizeArray);
|
||||
if (array_rank == 0) {
|
||||
SOLIDIGM_LOG_WARNING("Warning: Structure property 'arraySize' "
|
||||
"don't support flexible array: %s",
|
||||
json_object_to_json_string(struct_def));
|
||||
return -1;
|
||||
}
|
||||
uint32_t array_size_dimension[array_rank];
|
||||
|
||||
for (size_t i = 0; i < array_rank; i++) {
|
||||
json_object *dimension = json_object_array_get_idx(obj_arraySizeArray, i);
|
||||
|
||||
array_size_dimension[i] = json_object_get_uint64(dimension);
|
||||
major_dimension = dimension;
|
||||
}
|
||||
if (array_rank > 1) {
|
||||
uint32_t linear_pos_per_index = array_size_dimension[0];
|
||||
uint32_t prev_index_offset_bit = 0;
|
||||
json_object *dimension_output;
|
||||
|
||||
for (int i = 1; i < (array_rank - 1); i++)
|
||||
linear_pos_per_index *= array_size_dimension[i];
|
||||
|
||||
dimension_output = json_create_array();
|
||||
if (json_object_get_type(output) == json_type_array)
|
||||
json_object_array_add(output, dimension_output);
|
||||
else
|
||||
json_object_add_value_array(output, name, dimension_output);
|
||||
|
||||
/*
|
||||
* Make sure major_dimension object will not be
|
||||
* deleted from memory when deleted from array
|
||||
*/
|
||||
json_object_get(major_dimension);
|
||||
json_object_array_del_idx(obj_arraySizeArray, array_rank - 1, 1);
|
||||
|
||||
for (int i = 0 ; i < array_size_dimension[0]; i++) {
|
||||
json_object *sub_array = json_create_array();
|
||||
size_t offset;
|
||||
|
||||
offset = parent_offset_bit + prev_index_offset_bit;
|
||||
|
||||
json_object_array_add(dimension_output, sub_array);
|
||||
telemetry_log_structure_parse(tl, struct_def,
|
||||
offset, sub_array, NULL);
|
||||
prev_index_offset_bit += linear_pos_per_index * size_bit;
|
||||
}
|
||||
|
||||
json_object_array_put_idx(obj_arraySizeArray, array_rank - 1,
|
||||
major_dimension);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
linear_array_pos_bit = 0;
|
||||
sub_output = output;
|
||||
|
||||
if (array_size_dimension[0] > 1) {
|
||||
sub_output = json_create_array();
|
||||
if (json_object_get_type(output) == json_type_array)
|
||||
json_object_array_add(output, sub_output);
|
||||
else
|
||||
json_object_add_value_array(output, name, sub_output);
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < array_size_dimension[0]; j++) {
|
||||
if (is_enumeration || !has_member_list) {
|
||||
bool is_signed = !strncmp(type, SIGNED_INT_PREFIX, sizeof(SIGNED_INT_PREFIX)-1);
|
||||
json_object *val_obj;
|
||||
size_t offset;
|
||||
|
||||
offset = parent_offset_bit + offset_bit + linear_array_pos_bit;
|
||||
if (telemetry_log_get_value(tl, offset, size_bit, is_signed, &val_obj)) {
|
||||
if (array_size_dimension[0] > 1)
|
||||
json_object_array_put_idx(sub_output, j, val_obj);
|
||||
else
|
||||
json_object_object_add(sub_output, name, val_obj);
|
||||
} else {
|
||||
SOLIDIGM_LOG_WARNING("Warning: %s From property '%s', "
|
||||
"array index %u, structure definition: %s",
|
||||
json_object_get_string(val_obj),
|
||||
name, j, json_object_to_json_string(struct_def));
|
||||
json_free_object(val_obj);
|
||||
}
|
||||
} else {
|
||||
json_object *sub_sub_output = json_object_new_object();
|
||||
int num_members;
|
||||
|
||||
if (array_size_dimension[0] > 1)
|
||||
json_object_array_put_idx(sub_output, j, sub_sub_output);
|
||||
else
|
||||
json_object_add_value_object(sub_output, name, sub_sub_output);
|
||||
|
||||
num_members = json_object_array_length(obj_memberList);
|
||||
for (int k = 0; k < num_members; k++) {
|
||||
json_object *member = json_object_array_get_idx(obj_memberList, k);
|
||||
size_t offset;
|
||||
|
||||
offset = parent_offset_bit + offset_bit + linear_array_pos_bit;
|
||||
telemetry_log_structure_parse(tl, member, offset,
|
||||
sub_sub_output, NULL);
|
||||
}
|
||||
}
|
||||
linear_array_pos_bit += size_bit;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int telemetry_log_data_area_get_offset(const struct telemetry_log *tl,
|
||||
enum nvme_telemetry_da da,
|
||||
uint32_t *offset, uint32_t *size)
|
||||
{
|
||||
uint32_t offset_blocks = 1;
|
||||
uint32_t last_block = tl->log->dalb1;
|
||||
uint32_t last;
|
||||
|
||||
switch (da) {
|
||||
case NVME_TELEMETRY_DA_1:
|
||||
offset_blocks = 1;
|
||||
last_block = tl->log->dalb1;
|
||||
break;
|
||||
case NVME_TELEMETRY_DA_2:
|
||||
offset_blocks = tl->log->dalb1 + 1;
|
||||
last_block = tl->log->dalb2;
|
||||
break;
|
||||
case NVME_TELEMETRY_DA_3:
|
||||
offset_blocks = tl->log->dalb2 + 1;
|
||||
last_block = tl->log->dalb3;
|
||||
break;
|
||||
case NVME_TELEMETRY_DA_4:
|
||||
offset_blocks = tl->log->dalb3 + 1;
|
||||
last_block = tl->log->dalb4;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
*offset = offset_blocks * NVME_LOG_TELEM_BLOCK_SIZE;
|
||||
last = (last_block + 1) * NVME_LOG_TELEM_BLOCK_SIZE;
|
||||
*size = last - *offset;
|
||||
if ((*offset > tl->log_size) || (last > tl->log_size) || (last <= *offset)) {
|
||||
SOLIDIGM_LOG_WARNING("Warning: Data Area %d don't fit this Telemetry log.", da);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct toc_item {
|
||||
uint32_t OffsetBytes;
|
||||
uint32_t ContentSizeBytes;
|
||||
};
|
||||
|
||||
struct data_area_header {
|
||||
uint8_t versionMajor;
|
||||
uint8_t versionMinor;
|
||||
uint16_t TableOfContentsCount;
|
||||
uint32_t DataAreaSize;
|
||||
uint8_t Reserved[8];
|
||||
};
|
||||
|
||||
struct table_of_contents {
|
||||
struct data_area_header header;
|
||||
struct toc_item items[];
|
||||
};
|
||||
|
||||
struct telemetry_object_header {
|
||||
uint16_t versionMajor;
|
||||
uint16_t versionMinor;
|
||||
uint32_t Token;
|
||||
uint8_t CoreId;
|
||||
uint8_t Reserved[3];
|
||||
};
|
||||
|
||||
|
||||
static void telemetry_log_data_area_toc_parse(const struct telemetry_log *tl,
|
||||
enum nvme_telemetry_da da,
|
||||
json_object *toc_array,
|
||||
json_object *tele_obj_array)
|
||||
{
|
||||
|
||||
const struct telemetry_object_header *header;
|
||||
const struct table_of_contents *toc;
|
||||
char *payload;
|
||||
uint32_t da_offset;
|
||||
uint32_t da_size;
|
||||
|
||||
if (telemetry_log_data_area_get_offset(tl, da, &da_offset, &da_size))
|
||||
return;
|
||||
|
||||
toc = (struct table_of_contents *)(((char *)tl->log) + da_offset);
|
||||
payload = (char *) tl->log;
|
||||
|
||||
for (int i = 0; i < toc->header.TableOfContentsCount; i++) {
|
||||
json_object *structure_definition = NULL;
|
||||
json_object *toc_item;
|
||||
uint32_t obj_offset;
|
||||
bool has_struct;
|
||||
|
||||
if ((char *)&toc->items[i] > (((char *)toc) + da_size - sizeof(const struct toc_item))) {
|
||||
SOLIDIGM_LOG_WARNING("Warning: Data Area %d, "
|
||||
"Table of Contents item %d "
|
||||
"crossed Data Area size.", da, i);
|
||||
return;
|
||||
}
|
||||
|
||||
obj_offset = toc->items[i].OffsetBytes;
|
||||
if ((obj_offset + sizeof(const struct telemetry_object_header)) > da_size) {
|
||||
SOLIDIGM_LOG_WARNING("Warning: Data Area %d, item %d "
|
||||
"data, crossed Data Area size.", da, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
toc_item = json_create_object();
|
||||
json_object_array_add(toc_array, toc_item);
|
||||
json_object_add_value_uint(toc_item, "dataArea", da);
|
||||
json_object_add_value_uint(toc_item, "dataAreaIndex", i);
|
||||
json_object_add_value_uint(toc_item, "dataAreaOffset", obj_offset);
|
||||
json_object_add_value_uint(toc_item, "fileOffset", obj_offset + da_offset);
|
||||
json_object_add_value_uint(toc_item, "size", toc->items[i].ContentSizeBytes);
|
||||
|
||||
header = (const struct telemetry_object_header *) (payload + da_offset + obj_offset);
|
||||
json_object_add_value_uint(toc_item, "telemMajor", header->versionMajor);
|
||||
json_object_add_value_uint(toc_item, "telemMinor", header->versionMinor);
|
||||
json_object_add_value_uint(toc_item, "objectId", header->Token);
|
||||
json_object_add_value_uint(toc_item, "mediaBankId", header->CoreId);
|
||||
|
||||
has_struct = solidigm_config_get_by_token_version(tl->configuration,
|
||||
header->Token,
|
||||
header->versionMajor,
|
||||
header->versionMinor,
|
||||
&structure_definition);
|
||||
|
||||
if (has_struct) {
|
||||
json_object *tele_obj_item = json_create_object();
|
||||
|
||||
json_object_array_add(tele_obj_array, tele_obj_item);
|
||||
json_object_get(toc_item);
|
||||
json_object_add_value_object(tele_obj_item, "metadata", toc_item);
|
||||
json_object *parsed_struct = json_object_new_object();
|
||||
|
||||
json_object_add_value_object(tele_obj_item, "objectData", parsed_struct);
|
||||
json_object *obj_hasTelemObjHdr = NULL;
|
||||
uint32_t header_offset = sizeof(const struct telemetry_object_header);
|
||||
uint32_t file_offset;
|
||||
|
||||
if (json_object_object_get_ex(structure_definition,
|
||||
"hasTelemObjHdr",
|
||||
&obj_hasTelemObjHdr)) {
|
||||
bool hasHeader = json_object_get_boolean(obj_hasTelemObjHdr);
|
||||
|
||||
if (hasHeader)
|
||||
header_offset = 0;
|
||||
}
|
||||
|
||||
file_offset = da_offset + obj_offset + header_offset;
|
||||
telemetry_log_structure_parse(tl, structure_definition,
|
||||
BITS_IN_BYTE * file_offset,
|
||||
parsed_struct, toc_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int solidigm_telemetry_log_data_areas_parse(const struct telemetry_log *tl,
|
||||
enum nvme_telemetry_da last_da)
|
||||
{
|
||||
json_object *tele_obj_array = json_create_array();
|
||||
json_object *toc_array = json_create_array();
|
||||
|
||||
json_object_add_value_array(tl->root, "tableOfContents", toc_array);
|
||||
json_object_add_value_array(tl->root, "telemetryObjects", tele_obj_array);
|
||||
|
||||
for (enum nvme_telemetry_da da = NVME_TELEMETRY_DA_1; da <= last_da; da++)
|
||||
telemetry_log_data_area_toc_parse(tl, da, toc_array, tele_obj_array);
|
||||
|
||||
return 0;
|
||||
}
|
11
plugins/solidigm/solidigm-telemetry/data-area.h
Normal file
11
plugins/solidigm/solidigm-telemetry/data-area.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright (c) 2022 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "telemetry-log.h"
|
||||
|
||||
int solidigm_telemetry_log_data_areas_parse(const struct telemetry_log *tl,
|
||||
enum nvme_telemetry_da last_da);
|
199
plugins/solidigm/solidigm-telemetry/header.c
Normal file
199
plugins/solidigm/solidigm-telemetry/header.c
Normal file
|
@ -0,0 +1,199 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright (c) 2022 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "header.h"
|
||||
|
||||
#pragma pack(push, reason_indentifier, 1)
|
||||
struct reason_indentifier_1_0
|
||||
{
|
||||
uint16_t versionMajor;
|
||||
uint16_t versionMinor;
|
||||
uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue.
|
||||
char DriveStatus[20]; //! Drive Status String (for example: "Healthy", "*BAD_CONTEXT_2020")
|
||||
char FirmwareVersion[12]; //! Similar to IdentifyController.FR
|
||||
char BootloaderVersion[12]; //! Bootloader version string
|
||||
char SerialNumber[20]; //! Device serial number
|
||||
uint8_t Reserved[56]; //! Reserved for future usage
|
||||
};
|
||||
static_assert(sizeof(const struct reason_indentifier_1_0) ==
|
||||
MEMBER_SIZE(struct nvme_telemetry_log, rsnident),
|
||||
"Size mismatch for reason_indentifier_1_0");
|
||||
|
||||
struct reason_indentifier_1_1
|
||||
{
|
||||
uint16_t versionMajor;
|
||||
uint16_t versionMinor;
|
||||
uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue.
|
||||
char DriveStatus[20]; //! Drive Status String (for example: "Healthy", "*BAD_CONTEXT_2020")
|
||||
char FirmwareVersion[12]; //! Similar to IdentifyController.FR
|
||||
char BootloaderVersion[12]; //! Bootloader version string
|
||||
char SerialNumber[20]; //! Device serial number
|
||||
uint64_t OemDataMapOffset; //! Customer Data Map Object Log Offset
|
||||
uint8_t TelemetryMajorVersion; //! Shadow of version in TOC
|
||||
uint8_t TelemetryMinorVersion; //! Shadow of version in TOC
|
||||
uint8_t Reserved[46]; //! Reserved for future usage
|
||||
};
|
||||
static_assert(sizeof(const struct reason_indentifier_1_1) ==
|
||||
MEMBER_SIZE(struct nvme_telemetry_log, rsnident),
|
||||
"Size mismatch for reason_indentifier_1_1");
|
||||
|
||||
struct reason_indentifier_1_2
|
||||
{
|
||||
uint16_t versionMajor;
|
||||
uint16_t versionMinor;
|
||||
uint32_t reasonCode; //! 0 denotes no issue. All other values denote a potential issue.
|
||||
char DriveStatus[20]; //! Drive Status String (for example: "Healthy", "*BAD_CONTEXT_2020")
|
||||
uint8_t Reserved1[24]; //! pad over Fields removed from version 1.1
|
||||
char SerialNumber[20]; //! Device serial number
|
||||
uint64_t OemDataMapOffset; //! Customer Data Map Object Log Offset
|
||||
uint8_t TelemetryMajorVersion; //! Shadow of version in TOC
|
||||
uint8_t TelemetryMinorVersion; //! Shadow of version in TOC
|
||||
uint8_t ProductFamilyId;
|
||||
uint8_t Reserved2[5]; //! Reserved for future usage
|
||||
uint8_t DualPortReserved[40]; //! Reserved for dual port
|
||||
};
|
||||
static_assert(sizeof(const struct reason_indentifier_1_2) ==
|
||||
MEMBER_SIZE(struct nvme_telemetry_log, rsnident),
|
||||
"Size mismatch for reason_indentifier_1_2");
|
||||
#pragma pack(pop, reason_indentifier)
|
||||
|
||||
static void telemetry_log_reason_id_parse1_0_ext(const struct telemetry_log *tl,
|
||||
json_object *reason_id)
|
||||
{
|
||||
const struct reason_indentifier_1_0 *ri;
|
||||
json_object *reserved;
|
||||
|
||||
ri = (struct reason_indentifier_1_0 *) tl->log->rsnident;
|
||||
json_object_object_add(reason_id, "FirmwareVersion", json_object_new_string_len(ri->FirmwareVersion, sizeof(ri->FirmwareVersion)));
|
||||
json_object_object_add(reason_id, "BootloaderVersion", json_object_new_string_len(ri->BootloaderVersion, sizeof(ri->BootloaderVersion)));
|
||||
json_object_object_add(reason_id, "SerialNumber", json_object_new_string_len(ri->SerialNumber, sizeof(ri->SerialNumber)));
|
||||
|
||||
reserved = json_create_array();
|
||||
json_object_add_value_array(reason_id, "Reserved", reserved);
|
||||
for ( int i=0; i < sizeof(ri->Reserved); i++) {
|
||||
json_object *val = json_object_new_int(ri->Reserved[i]);
|
||||
json_object_array_add(reserved, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void telemetry_log_reason_id_parse1_1_ext(const struct telemetry_log *tl,
|
||||
json_object *reason_id)
|
||||
{
|
||||
const struct reason_indentifier_1_1 *ri;
|
||||
json_object *reserved;
|
||||
|
||||
ri = (struct reason_indentifier_1_1 *) tl->log->rsnident;
|
||||
json_object_object_add(reason_id, "FirmwareVersion", json_object_new_string_len(ri->FirmwareVersion, sizeof(ri->FirmwareVersion)));
|
||||
json_object_object_add(reason_id, "BootloaderVersion", json_object_new_string_len(ri->BootloaderVersion, sizeof(ri->BootloaderVersion)));
|
||||
json_object_object_add(reason_id, "SerialNumber", json_object_new_string_len(ri->SerialNumber, sizeof(ri->SerialNumber)));
|
||||
json_object_add_value_uint64(reason_id, "OemDataMapOffset", le64_to_cpu(ri->OemDataMapOffset));
|
||||
json_object_add_value_uint(reason_id, "TelemetryMajorVersion", le16_to_cpu(ri->TelemetryMajorVersion));
|
||||
json_object_add_value_uint(reason_id, "TelemetryMinorVersion", le16_to_cpu(ri->TelemetryMinorVersion));
|
||||
|
||||
reserved = json_create_array();
|
||||
json_object_add_value_array(reason_id, "Reserved", reserved);
|
||||
for (int i = 0; i < sizeof(ri->Reserved); i++) {
|
||||
json_object *val = json_object_new_int(ri->Reserved[i]);
|
||||
json_object_array_add(reserved, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void telemetry_log_reason_id_parse1_2_ext(const struct telemetry_log *tl,
|
||||
json_object *reason_id)
|
||||
{
|
||||
const struct reason_indentifier_1_2 *ri;
|
||||
json_object *dp_reserved;
|
||||
json_object *reserved;
|
||||
|
||||
ri = (struct reason_indentifier_1_2 *) tl->log->rsnident;
|
||||
|
||||
json_object_object_add(reason_id, "SerialNumber", json_object_new_string_len(ri->SerialNumber, sizeof(ri->SerialNumber)));
|
||||
json_object_add_value_uint64(reason_id, "OemDataMapOffset", le64_to_cpu(ri->OemDataMapOffset));
|
||||
json_object_add_value_uint(reason_id, "TelemetryMajorVersion", le16_to_cpu(ri->TelemetryMajorVersion));
|
||||
json_object_add_value_uint(reason_id, "TelemetryMinorVersion", le16_to_cpu(ri->TelemetryMinorVersion));
|
||||
json_object_add_value_uint(reason_id, "ProductFamilyId", ri->ProductFamilyId);
|
||||
|
||||
reserved = json_create_array();
|
||||
json_object_add_value_array(reason_id, "Reserved2", reserved);
|
||||
for (int i = 0; i < sizeof(ri->Reserved2); i++) {
|
||||
json_object *val = json_object_new_int(ri->Reserved2[i]);
|
||||
json_object_array_add(reserved, val);
|
||||
}
|
||||
|
||||
dp_reserved = json_create_array();
|
||||
json_object_add_value_array(reason_id, "DualPortReserved", dp_reserved);
|
||||
for (int i = 0; i < sizeof(ri->DualPortReserved); i++) {
|
||||
json_object *val = json_object_new_int(ri->DualPortReserved[i]);
|
||||
json_object_array_add(dp_reserved, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void solidigm_telemetry_log_reason_id_parse(const struct telemetry_log *tl, json_object *reason_id)
|
||||
{
|
||||
const struct reason_indentifier_1_0 *ri1_0 =
|
||||
(struct reason_indentifier_1_0 *) tl->log->rsnident;
|
||||
__u16 version_major = le16_to_cpu(ri1_0->versionMajor);
|
||||
__u16 version_minor = le16_to_cpu(ri1_0->versionMinor);
|
||||
|
||||
json_object_add_value_uint(reason_id, "versionMajor", version_major);
|
||||
json_object_add_value_uint(reason_id, "versionMinor", version_minor);
|
||||
json_object_add_value_uint(reason_id, "reasonCode", le32_to_cpu(ri1_0->reasonCode));
|
||||
json_object_add_value_object(reason_id, "DriveStatus", json_object_new_string_len(ri1_0->DriveStatus, sizeof(ri1_0->DriveStatus)));
|
||||
if (version_major == 1) {
|
||||
switch (version_minor) {
|
||||
case 0:
|
||||
telemetry_log_reason_id_parse1_0_ext(tl, reason_id);
|
||||
break;
|
||||
case 1:
|
||||
telemetry_log_reason_id_parse1_1_ext(tl, reason_id);
|
||||
break;
|
||||
default:
|
||||
telemetry_log_reason_id_parse1_2_ext(tl, reason_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool solidigm_telemetry_log_header_parse(const struct telemetry_log *tl)
|
||||
{
|
||||
const struct nvme_telemetry_log *log;
|
||||
json_object *ieee_oui_id;
|
||||
json_object *reason_id;
|
||||
json_object *header;
|
||||
|
||||
if (tl->log_size < sizeof(const struct nvme_telemetry_log)) {
|
||||
SOLIDIGM_LOG_WARNING("Telemetry log too short.");
|
||||
return false;
|
||||
}
|
||||
|
||||
header = json_create_object();
|
||||
|
||||
json_object_object_add(tl->root, "telemetryHeader", header);
|
||||
log = tl->log;
|
||||
|
||||
json_object_add_value_uint(header, "logIdentifier", log->lpi);
|
||||
ieee_oui_id = json_create_array();
|
||||
|
||||
json_object_object_add(header, "ieeeOuiIdentifier", ieee_oui_id);
|
||||
for (int i = 0; i < sizeof(log->ieee); i++) {
|
||||
json_object *val = json_object_new_int(log->ieee[i]);
|
||||
|
||||
json_object_array_add(ieee_oui_id, val);
|
||||
}
|
||||
json_object_add_value_uint(header, "dataArea1LastBlock", log->dalb1);
|
||||
json_object_add_value_uint(header, "dataArea2LastBlock", log->dalb2);
|
||||
json_object_add_value_uint(header, "dataArea3LastBlock", log->dalb3);
|
||||
json_object_add_value_uint(header, "hostInitiatedDataGeneration", log->hostdgn);
|
||||
json_object_add_value_uint(header, "controllerInitiatedDataAvailable", log->ctrlavail);
|
||||
json_object_add_value_uint(header, "controllerInitiatedDataGeneration", log->ctrldgn);
|
||||
|
||||
reason_id = json_create_object();
|
||||
json_object_add_value_object(header, "reasonIdentifier", reason_id);
|
||||
solidigm_telemetry_log_reason_id_parse(tl, reason_id);
|
||||
|
||||
return true;
|
||||
}
|
9
plugins/solidigm/solidigm-telemetry/header.h
Normal file
9
plugins/solidigm/solidigm-telemetry/header.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright (c) 2022 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
|
||||
#include "telemetry-log.h"
|
||||
bool solidigm_telemetry_log_header_parse(const struct telemetry_log *tl);
|
6
plugins/solidigm/solidigm-telemetry/meson.build
Normal file
6
plugins/solidigm/solidigm-telemetry/meson.build
Normal file
|
@ -0,0 +1,6 @@
|
|||
sources += [
|
||||
'plugins/solidigm/solidigm-telemetry/cod.c',
|
||||
'plugins/solidigm/solidigm-telemetry/header.c',
|
||||
'plugins/solidigm/solidigm-telemetry/config.c',
|
||||
'plugins/solidigm/solidigm-telemetry/data-area.c',
|
||||
]
|
31
plugins/solidigm/solidigm-telemetry/telemetry-log.h
Normal file
31
plugins/solidigm/solidigm-telemetry/telemetry-log.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright (c) 2022 Solidigm.
|
||||
*
|
||||
* Author: leonardo.da.cunha@solidigm.com
|
||||
*/
|
||||
|
||||
#ifndef _SOLIDIGM_TELEMETRY_LOG_H
|
||||
#define _SOLIDIGM_TELEMETRY_LOG_H
|
||||
|
||||
#include "libnvme.h"
|
||||
#include "util/json.h"
|
||||
#include <assert.h>
|
||||
|
||||
#if !defined __cplusplus
|
||||
#define static_assert _Static_assert
|
||||
#endif
|
||||
|
||||
#define VA_ARGS(...), ##__VA_ARGS__
|
||||
#define SOLIDIGM_LOG_WARNING(format, ...) fprintf(stderr, format"\n" VA_ARGS(__VA_ARGS__))
|
||||
|
||||
#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
|
||||
|
||||
struct telemetry_log {
|
||||
struct nvme_telemetry_log *log;
|
||||
size_t log_size;
|
||||
json_object *root;
|
||||
json_object *configuration;
|
||||
};
|
||||
|
||||
#endif /* _SOLIDIGM_TELEMETRY_LOG_H */
|
Loading…
Add table
Add a link
Reference in a new issue