nvme_show_status(err);
}
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
dev_close(dev);
return err;
}
} else {
fprintf(stderr, "Could not read feature id 0xE2.\n");
}
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
dev_close(dev);
return err;
}
#include "cmd.h"
-#define SOLIDIGM_PLUGIN_VERSION "0.5"
+#define SOLIDIGM_PLUGIN_VERSION "0.6"
PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION),
COMMAND_LIST(
nvme_show_status(err);
}
+ /* Redundant close() to make static code analysis happy */
+ close(dev->direct.fd);
dev_close(dev);
return err;
}
#include "solidigm-telemetry.h"
#include "solidigm-telemetry/telemetry-log.h"
#include "solidigm-telemetry/cod.h"
-#include "solidigm-telemetry/reason-id.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;
+ 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 *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,
+ .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 = parse_and_open(&dev, argc, argv, desc, opts);
+ 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) {
- fprintf(stderr, "Invalid host-generate value '%d'\n", cfg.host_gen);
+ SOLIDIGM_LOG_WARNING("Invalid host-generate value '%d'", cfg.host_gen);
err = EINVAL;
goto close_fd;
}
-
- 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) {
- fprintf(stderr, "get-telemetry-log: %s\n",
- nvme_strerror(errno));
- goto close_fd;
- } else if (err > 0) {
- nvme_show_status(err);
- fprintf(stderr, "Failed to acquire telemetry log %d!\n", err);
- goto close_fd;
+ if (cfg.cfg_file) {
+ char *conf_str = 0;
+ size_t length;
+
+ 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);
}
- solidigm_telemetry_log_reason_id_parse(&tl);
- solidigm_telemetry_log_cod_parse(&tl);
-
+ 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");
- free(tl.log);
-
close_fd:
- dev_close(dev);
+ 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;
-}
\ No newline at end of file
+}
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, "reason_identifier", &reason_id)) {
- return;
- }
- if (!json_object_object_get_ex(reason_id, "OemDataMapOffset", &COD_offset)) {
- return;
- }
+
+ 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 + sizeof(struct cod_header)) > tl->log_size) {
- fprintf(stderr, "COD map header out of bounds.\n");
+ SOLIDIGM_LOG_WARNING("Warning: COD map header out of bounds.");
return;
}
uint32_t signature = be32_to_cpu(data->header.Signature);
if ( signature != OEMSIGNATURE){
- fprintf(stderr, "Unsupported COD data signature %x!\n", signature);
+ SOLIDIGM_LOG_WARNING("Warning: Unsupported COD data signature %x!", signature);
return;
}
if ((offset + data->header.MapSizeInBytes) > tl->log_size){
- fprintf(stderr, "COD map data out of bounds.\n");
+ SOLIDIGM_LOG_WARNING("Warning: COD map data out of bounds.");
return;
}
for (int i =0 ; i < data->header.EntryCount; i++) {
if ((offset + sizeof(struct cod_header) + (i + 1) * sizeof(struct cod_item)) >
tl->log_size){
- fprintf(stderr, "COD data out of bounds at item %d!\n", i);
+ SOLIDIGM_LOG_WARNING("Warning: COD data out of bounds at item %d!", i);
return;
}
struct cod_item item = data->items[i];
switch(item.dataFieldType){
case(INTEGER):
if (item.issigned) {
- json_object_object_add(cod, key,
+ 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));
json_object_add_value_float(cod, key, *(float *) val);
break;
case(STRING):
- json_object_object_add(cod, key,
+ 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_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_object_add(cod, key,
json_object_new_string_len((const char *)val, 4));
break;
default:
- fprintf(stderr,"Unknown COD field type (%d)\n", item.DataFieldMapUid);
+ SOLIDIGM_LOG_WARNING("Warning: Unknown COD field type (%d)", item.DataFieldMapUid);
}
}
-// SPDX-License-Identifier: MIT-0
+/* SPDX-License-Identifier: MIT-0 */
/*
* Copyright (c) 2022 Solidigm.
*
--- /dev/null
+// SPDX-License-Identifier: MIT-0
+/*
+ * 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;
+}
--- /dev/null
+/* SPDX-License-Identifier: MIT-0 */
+/*
+ * 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);
--- /dev/null
+// SPDX-License-Identifier: MIT-0
+/*
+ * 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 > %lu).",
+ 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;
+}
--- /dev/null
+/* SPDX-License-Identifier: MIT-0 */
+/*
+ * 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);
--- /dev/null
+// SPDX-License-Identifier: MIT-0
+/*
+ * 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;
+}
-// SPDX-License-Identifier: MIT-0
+/* SPDX-License-Identifier: MIT-0 */
/*
* Copyright (c) 2022 Solidigm.
*
*/
#include "telemetry-log.h"
-void solidigm_telemetry_log_reason_id_parse(struct telemetry_log *tl);
+bool solidigm_telemetry_log_header_parse(const struct telemetry_log *tl);
sources += [
'plugins/solidigm/solidigm-telemetry/cod.c',
- 'plugins/solidigm/solidigm-telemetry/reason-id.c',
+ 'plugins/solidigm/solidigm-telemetry/header.c',
+ 'plugins/solidigm/solidigm-telemetry/config.c',
+ 'plugins/solidigm/solidigm-telemetry/data-area.c',
]
+++ /dev/null
-// SPDX-License-Identifier: MIT-0
-/*
- * Copyright (c) 2022 Solidigm.
- *
- * Author: leonardo.da.cunha@solidigm.com
- */
-
-#include "common.h"
-#include "reason-id.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
-};
-
-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
-};
-
-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
-};
-#pragma pack(pop, reason_indentifier)
-
-static void telemetry_log_reason_id_parse1_0_ext(struct telemetry_log *tl, json_object *reason_id)
-{
- const struct reason_indentifier_1_0 *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)));
- json_object *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(struct telemetry_log *tl, json_object *reason_id)
-{
- const struct reason_indentifier_1_1 *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));
- json_object *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(struct telemetry_log *tl, json_object *reason_id)
-{
- const struct reason_indentifier_1_2 *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);
- json_object *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);
- }
- json_object *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);
- }
-}
-
-void solidigm_telemetry_log_reason_id_parse(struct telemetry_log *tl)
-{
- json_object *reason_id = json_create_object();
- 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_object(tl->root, "reason_identifier", reason_id);
- 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_object_add(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);
- }
- }
-}
-// SPDX-License-Identifier: MIT-0
+/* SPDX-License-Identifier: MIT-0 */
/*
* Copyright (c) 2022 Solidigm.
*
#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 */
\ No newline at end of file