Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/solidigm/solidigm-nvme.h
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
23 changes: 23 additions & 0 deletions plugins/solidigm/solidigm-telemetry/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
Expand Down
9 changes: 6 additions & 3 deletions plugins/solidigm/solidigm-telemetry/data-area.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
Expand Down
138 changes: 114 additions & 24 deletions plugins/solidigm/solidigm-telemetry/skht.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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();

Expand All @@ -194,20 +283,21 @@ 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();

json_object_object_add(tl->root, description_str, debug_info_obj);
sldm_debug_info_parse(tl, NVME_LOG_TELEM_BLOCK_SIZE + offset,
size, debug_info_obj);
}
free(description_str);
}
}
2 changes: 1 addition & 1 deletion plugins/solidigm/solidigm-telemetry/skht.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion plugins/solidigm/solidigm-telemetry/telemetry-log.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Loading