From 22ddbb2208d62f9550f0be6aa5e6c97691c6ab01 Mon Sep 17 00:00:00 2001 From: Leonardo da Cunha Date: Fri, 8 May 2026 17:16:31 -0700 Subject: [PATCH 1/2] plugins/solidigm: Additional telemetry configuration wildcard. Added telemetry configuration version number wildcards, besides the previous "*" wildcard. Signed-off-by: Leonardo da Cunha --- plugins/solidigm/solidigm-telemetry/config.c | 23 ++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/plugins/solidigm/solidigm-telemetry/config.c b/plugins/solidigm/solidigm-telemetry/config.c index c66c04a7d9..ac2fe56cd5 100644 --- a/plugins/solidigm/solidigm-telemetry/config.c +++ b/plugins/solidigm/solidigm-telemetry/config.c @@ -43,6 +43,10 @@ static bool config_get_by_version(const struct json_object *obj, if (json_object_object_get_ex(major_obj, "*", value)) return value != NULL; + /* Try alternative minor version wildcard */ + if (json_object_object_get_ex(major_obj, "49374", value)) + return value != NULL; + SOLIDIGM_LOG_WARNING( "Warning: Object %s version major %d found but minor %d not found\n", key, version_major, version_minor); @@ -57,6 +61,25 @@ static bool config_get_by_version(const struct json_object *obj, /* Try wildcard minor version */ if (json_object_object_get_ex(major_obj, "*", value)) return value != NULL; + + /* Try alternative minor version wildcard */ + if (json_object_object_get_ex(major_obj, "49374", value)) + return value != NULL; + } + + /* Try alternative major version wildcard */ + if (json_object_object_get_ex(obj, "47837", &major_obj)) { + /* Try exact minor version match */ + if (json_object_object_get_ex(major_obj, str_subkey, value)) + return value != NULL; + + /* Try wildcard minor version */ + if (json_object_object_get_ex(major_obj, "*", value)) + return value != NULL; + + /* Try alternative minor version wildcard */ + if (json_object_object_get_ex(major_obj, "49374", value)) + return value != NULL; } return false; From ff2df443e9878e347fa5ae443b679d159dbc7d9c Mon Sep 17 00:00:00 2001 From: Leonardo da Cunha Date: Tue, 19 May 2026 13:58:39 -0700 Subject: [PATCH 2/2] plugins/solidigm: Additional signature detection into Telemetry parser. A product line changed signature location to accommodate OCP spec. Propagating header offset in abstract data type. Fixed broken segment parser because nDescription not being converted to string. Fixed warning about Data Area size. Signed-off-by: Leonardo da Cunha --- plugins/solidigm/solidigm-nvme.h | 2 +- .../solidigm/solidigm-telemetry/data-area.c | 9 +- plugins/solidigm/solidigm-telemetry/skht.c | 138 +++++++++++++++--- plugins/solidigm/solidigm-telemetry/skht.h | 2 +- .../solidigm-telemetry/telemetry-log.h | 2 +- 5 files changed, 123 insertions(+), 30 deletions(-) diff --git a/plugins/solidigm/solidigm-nvme.h b/plugins/solidigm/solidigm-nvme.h index 052fe99c62..b9a72cfcb0 100644 --- a/plugins/solidigm/solidigm-nvme.h +++ b/plugins/solidigm/solidigm-nvme.h @@ -13,7 +13,7 @@ #include "cmd.h" -#define SOLIDIGM_PLUGIN_VERSION "1.21" +#define SOLIDIGM_PLUGIN_VERSION "1.22" PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION), COMMAND_LIST( diff --git a/plugins/solidigm/solidigm-telemetry/data-area.c b/plugins/solidigm/solidigm-telemetry/data-area.c index bf5a4a1499..189d8e8d03 100644 --- a/plugins/solidigm/solidigm-telemetry/data-area.c +++ b/plugins/solidigm/solidigm-telemetry/data-area.c @@ -361,7 +361,9 @@ static int telemetry_log_data_area_get_offset(const struct telemetry_log *tl, *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)) { + if (last < *offset) + return -1; /* DA is absent or empty, skip silently */ + if ((*offset > tl->log_size) || (last > tl->log_size)) { SOLIDIGM_LOG_WARNING("Warning: Data Area %d don't fit this Telemetry log.", da); return -1; } @@ -610,7 +612,8 @@ int solidigm_telemetry_log_data_areas_parse(struct telemetry_log *tl, struct json_object *toc_array = NULL; solidigm_telemetry_log_da1_check_ocp(tl); - sldm_telemetry_da2_check_skhT(tl); + sldm_telemetry_check_for_skhT(tl); + // if TELEMETRY_CONFIG_META available copy it to the output for better // context in the output data if (tl->configuration) { @@ -631,7 +634,7 @@ int solidigm_telemetry_log_data_areas_parse(struct telemetry_log *tl, if (tl->is_ocp) first_da = NVME_TELEMETRY_DA_3; - if (tl->is_skhT) { + if (tl->skhT_offset) { if (last_da >= NVME_TELEMETRY_DA_2) sldm_telemetry_skhT_parse(tl); if (last_da >= NVME_TELEMETRY_DA_3) diff --git a/plugins/solidigm/solidigm-telemetry/skht.c b/plugins/solidigm/solidigm-telemetry/skht.c index 44e3b708e6..a27d1c7f1a 100644 --- a/plugins/solidigm/solidigm-telemetry/skht.c +++ b/plugins/solidigm/solidigm-telemetry/skht.c @@ -14,36 +14,80 @@ #include "data-area.h" #include "debug-info.h" -void sldm_telemetry_da2_check_skhT(struct telemetry_log *tl) +static char *json_byte_array_to_string(struct json_object *array) +{ + size_t len = json_object_array_length(array); + char *str = malloc(len + 1); + + if (!str) + return NULL; + for (size_t i = 0; i < len; i++) + str[i] = (char)json_object_get_int( + json_object_array_get_idx(array, i)); + str[len] = '\0'; + return str; +} + +void sldm_telemetry_check_for_skhT(struct telemetry_log *tl) { const uint32_t expected_signature = 0x54686B73; // "skhT" in little-endian - uint16_t da2_offset = (tl->log->dalb1 + 1) * NVME_LOG_TELEM_BLOCK_SIZE; - uint32_t signature = 0; - - // Basic bounds checking - if (tl->log_size >= (da2_offset + sizeof(uint32_t))) { - // Read the first 4 bytes as the signature - memcpy(&signature, (char *)tl->log + da2_offset, sizeof(uint32_t)); - tl->is_skhT = (signature == expected_signature); - } else { - tl->is_skhT = false; + const uint32_t da2_offset = + ((uint32_t)(tl->log->dalb1 + 1) * NVME_LOG_TELEM_BLOCK_SIZE); + const uint32_t da3_offset = + ((uint32_t)(tl->log->dalb2 + 1) * NVME_LOG_TELEM_BLOCK_SIZE); + + tl->skhT_offset = 0; + if (!tl->is_ocp) { + // Basic bounds checking + if (tl->log_size >= (da2_offset + sizeof(uint32_t))) { + // Read the first 4 bytes as the signature + uint32_t signature = + *(uint32_t *)((char *)tl->log + da2_offset); + + if (signature == expected_signature) + tl->skhT_offset = da2_offset; + } + return; + } + // For OCP drives, the signature is located after the segment headers + // in Data Area 3 + if (tl->log_size >= (da3_offset + sizeof(uint32_t))) { + uint32_t num_segments = + *(uint32_t *)((char *)tl->log + da3_offset); + // check if num_segments is greater than 0 and less than a + // reasonable limit to avoid overflow + if (num_segments == 0 || num_segments > 1000) + return; + uint16_t segment_header_size = ((num_segments - 1) / 10 + 1) * + NVME_LOG_TELEM_BLOCK_SIZE; + + if (tl->log_size >= + (da3_offset + segment_header_size + sizeof(uint32_t))) { + uint32_t signature = *(uint32_t *)((char *)tl->log + + da3_offset + segment_header_size); + + if (signature == expected_signature) + tl->skhT_offset = + da3_offset + segment_header_size; + } } } void sldm_telemetry_skhT_parse(struct telemetry_log *tl) { - uint16_t da2_offset = (tl->log->dalb1 + 1) * NVME_LOG_TELEM_BLOCK_SIZE; + uint32_t header_offset = tl->skhT_offset; struct json_object *hynix_header_def = NULL; bool has_struct = false; struct json_object *build_info_def = NULL; bool has_build_info = false; struct json_object *size_bit_obj = NULL; uint32_t hynix_header_size_bits = 0; - uint16_t build_info_offset = da2_offset; + uint32_t build_info_offset = header_offset; // Basic validation - if (tl->log_size < da2_offset) { - SOLIDIGM_LOG_WARNING("Warning: Data Area 2 offset is beyond telemetry log size."); + if (tl->log_size < header_offset) { + SOLIDIGM_LOG_WARNING( + "Warning: skhT header offset is beyond telemetry log size."); return; } @@ -59,7 +103,8 @@ void sldm_telemetry_skhT_parse(struct telemetry_log *tl) } // Parse HynixHeader directly into tl->root - if (sldm_telemetry_structure_parse(tl, hynix_header_def, da2_offset * NUM_BITS_IN_BYTE, + if (sldm_telemetry_structure_parse(tl, hynix_header_def, + header_offset * NUM_BITS_IN_BYTE, tl->root, NULL) != 0) { SOLIDIGM_LOG_WARNING("Failed to parse HynixHeader structure"); return; @@ -88,7 +133,8 @@ void sldm_telemetry_skhT_parse(struct telemetry_log *tl) } // Parse BuildInfo directly into tl->root - if (sldm_telemetry_structure_parse(tl, build_info_def, build_info_offset * NUM_BITS_IN_BYTE, + if (sldm_telemetry_structure_parse(tl, build_info_def, + build_info_offset * NUM_BITS_IN_BYTE, tl->root, NULL) != 0) { SOLIDIGM_LOG_WARNING("Failed to parse BuildInfo structure"); return; @@ -99,7 +145,7 @@ void sldm_telemetry_sktT_segment_parse(struct telemetry_log *tl, struct json_object *toc_array, struct json_object *tele_obj_array) { - uint16_t da3_offset = (tl->log->dalb2 + 1) * NVME_LOG_TELEM_BLOCK_SIZE; + uint32_t da3_offset = (tl->log->dalb2 + 1) * NVME_LOG_TELEM_BLOCK_SIZE; struct json_object *segment_header_definition = NULL; struct json_object *segment_header_obj = NULL; struct json_object *num_segments_obj = NULL; @@ -154,7 +200,7 @@ void sldm_telemetry_sktT_segment_parse(struct telemetry_log *tl, struct json_object *description_obj = NULL; uint32_t offset = 0; uint32_t size = 0; - const char *description_str = NULL; + char *description_str = NULL; // Get segment info from the parsed JSON structure descriptor_obj = json_object_array_get_idx(descriptors_obj, i); @@ -181,11 +227,54 @@ void sldm_telemetry_sktT_segment_parse(struct telemetry_log *tl, continue; } - if (json_object_object_get_ex(descriptor_obj, "nDescription", &description_obj)) - description_str = json_object_get_string(description_obj); + // Get the description for this segment + if (json_object_object_get_ex(descriptor_obj, + "nDescription", + &description_obj)) { + if (json_object_get_type(description_obj) == + json_type_array) { + description_str = + json_byte_array_to_string( + description_obj); + /* replace json array with string in output + * for better readability + */ + json_object_object_add(descriptor_obj, + "nDescription", + json_object_new_string( + description_str)); + } + } else { + SOLIDIGM_LOG_WARNING( + "nDescription not found for segment %d", i); + json_object_put(descriptor); + continue; + } + + struct json_object *type_name_obj = NULL; + + if (json_object_object_get_ex(descriptor_obj, "nTypeName", + &type_name_obj) && + json_object_get_type(type_name_obj) == json_type_array) { + char *type_name_alloc = + json_byte_array_to_string(type_name_obj); + + json_object_object_add(descriptor_obj, "nTypeName", + json_object_new_string( + type_name_alloc)); + free(type_name_alloc); + } + + if (description_str == 0) { + SOLIDIGM_LOG_WARNING( + "Warning: nDescription is NULL for segment %d", + i); + json_object_put(descriptor); + continue; + } // check if descriptions starts with "TRACKER_DATA" - if (description_str && strncmp(description_str, "TRACKER_DATA", + if (strncmp(description_str, "TRACKER_DATA", sizeof("TRACKER_DATA") - 1) == 0) { struct json_object *tracker_obj = json_object_new_object(); @@ -194,14 +283,14 @@ void sldm_telemetry_sktT_segment_parse(struct telemetry_log *tl, sldm_tracker_parse(tl, NVME_LOG_TELEM_BLOCK_SIZE + offset, size, tracker_obj); } - if (description_str && strncmp(description_str, "UART_LOG_INFO", + if (strncmp(description_str, "UART_LOG_INFO", sizeof("UART_LOG_INFO") - 1) == 0) { json_object_object_add(tl->root, description_str, json_object_new_string( (char *)tl->log + NVME_LOG_TELEM_BLOCK_SIZE + offset)); } - if (description_str && strncmp(description_str, "DEBUG_INFO", + if (strncmp(description_str, "DEBUG_INFO", sizeof("DEBUG_INFO") - 1) == 0) { struct json_object *debug_info_obj = json_object_new_object(); @@ -209,5 +298,6 @@ void sldm_telemetry_sktT_segment_parse(struct telemetry_log *tl, sldm_debug_info_parse(tl, NVME_LOG_TELEM_BLOCK_SIZE + offset, size, debug_info_obj); } + free(description_str); } } diff --git a/plugins/solidigm/solidigm-telemetry/skht.h b/plugins/solidigm/solidigm-telemetry/skht.h index d14e0e7fba..98f79316bd 100644 --- a/plugins/solidigm/solidigm-telemetry/skht.h +++ b/plugins/solidigm/solidigm-telemetry/skht.h @@ -13,7 +13,7 @@ #define SKT_VER_MAJOR 47837 #define SKT_VER_MINOR 49374 -void sldm_telemetry_da2_check_skhT(struct telemetry_log *tl); +void sldm_telemetry_check_for_skhT(struct telemetry_log *tl); void sldm_telemetry_sktT_segment_parse(struct telemetry_log *tl, struct json_object *toc_array, struct json_object *tele_obj_array); diff --git a/plugins/solidigm/solidigm-telemetry/telemetry-log.h b/plugins/solidigm/solidigm-telemetry/telemetry-log.h index 79136b42ce..8442e4a927 100644 --- a/plugins/solidigm/solidigm-telemetry/telemetry-log.h +++ b/plugins/solidigm/solidigm-telemetry/telemetry-log.h @@ -27,7 +27,7 @@ struct telemetry_log { struct json_object *root; struct json_object *configuration; bool is_ocp; - bool is_skhT; + uint32_t skhT_offset; }; #endif /* _SOLIDIGM_TELEMETRY_LOG_H */