diff --git a/plugins/solidigm/solidigm-nvme.h b/plugins/solidigm/solidigm-nvme.h index 5428ffb760..e73cf7b50c 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.15" +#define SOLIDIGM_PLUGIN_VERSION "1.16" PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION), COMMAND_LIST( diff --git a/plugins/solidigm/solidigm-telemetry/cod.c b/plugins/solidigm/solidigm-telemetry/cod.c index 363822a556..8cebc212ea 100644 --- a/plugins/solidigm/solidigm-telemetry/cod.c +++ b/plugins/solidigm/solidigm-telemetry/cod.c @@ -6,6 +6,7 @@ */ #include "common.h" #include "cod.h" +#include "header.h" const char *oemDataMapDesc[] = { "Media Read Count", //Uid 0x00 @@ -170,18 +171,27 @@ void solidigm_telemetry_log_cod_parse(struct telemetry_log *tl) 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)); + case STRING: { + struct json_object *str_obj = NULL; + + sldm_uint8_array_to_string(val, item.DataFieldSizeInBytes, &str_obj); + json_object_object_add(cod, key, str_obj); break; - case TWO_BYTE_ASCII: - json_object_object_add(cod, key, - json_object_new_string_len((const char *)val, 2)); + } + case TWO_BYTE_ASCII: { + struct json_object *str_obj = NULL; + + sldm_uint8_array_to_string(val, 2, &str_obj); + json_object_object_add(cod, key, str_obj); break; - case FOUR_BYTE_ASCII: - json_object_object_add(cod, key, - json_object_new_string_len((const char *)val, 4)); + } + case FOUR_BYTE_ASCII: { + struct json_object *str_obj = NULL; + + sldm_uint8_array_to_string(val, 4, &str_obj); + json_object_object_add(cod, key, str_obj); break; + } default: SOLIDIGM_LOG_WARNING("Warning: Unknown COD field type (%d)", item.DataFieldMapUid); break; diff --git a/plugins/solidigm/solidigm-telemetry/data-area.c b/plugins/solidigm/solidigm-telemetry/data-area.c index 81bb5a1d2d..1a7209e409 100644 --- a/plugins/solidigm/solidigm-telemetry/data-area.c +++ b/plugins/solidigm/solidigm-telemetry/data-area.c @@ -47,23 +47,8 @@ static bool uint8_array_try_string(const struct telemetry_log *tl, // Get direct pointer to the UINT8 array in the telemetry log const uint8_t *data_ptr = (const uint8_t *)tl->log + offset_byte; - // Calculate actual string length (stopping at null terminator if found) - size_t actual_length = 0; - - for (actual_length = 0; actual_length < array_size; actual_length++) { - if (data_ptr[actual_length] == '\0') - break; - } - // making sure trailing bytes are nulls - for (size_t i = actual_length; i < array_size; i++) { - if (data_ptr[i] != '\0') - return false; - } - - // Create JSON string directly from the data without intermediate buffer - *str_obj = json_object_new_string_len((const char *)data_ptr, actual_length); - - return true; + // Use the generic converter function + return sldm_uint8_array_to_string(data_ptr, array_size, str_obj); } static void reverse_string(char *buff, size_t len) @@ -575,11 +560,14 @@ static void telemetry_log_data_area_toc_parse(const struct telemetry_log *tl, &header_nlogName)) { int nlogName = json_object_get_int(header_nlogName); char *name = (char *)&nlogName; + struct json_object *nlog_name_obj = NULL; reverse_string(name, sizeof(uint32_t)); + sldm_uint8_array_to_string((const uint8_t *)name, + sizeof(uint32_t), + &nlog_name_obj); json_object_object_add(header_nlogSelect, "nlogName", - json_object_new_string_len(name, - sizeof(uint32_t))); + nlog_name_obj); } } // Overwrite the object name diff --git a/plugins/solidigm/solidigm-telemetry/header.c b/plugins/solidigm/solidigm-telemetry/header.c index 0a8361df20..3ab0375abf 100644 --- a/plugins/solidigm/solidigm-telemetry/header.c +++ b/plugins/solidigm/solidigm-telemetry/header.c @@ -8,6 +8,57 @@ #include "common.h" #include "header.h" +bool sldm_uint8_array_to_string(const uint8_t *data_ptr, uint32_t array_size, + struct json_object **str_obj) +{ + if (!data_ptr || !str_obj) { + if (str_obj) + *str_obj = json_object_new_string("Error: Invalid parameters"); + return false; + } + + // Calculate actual string length (stopping at null terminator if found) + size_t actual_length = 0; + bool is_ascii = true; + + for (actual_length = 0; actual_length < array_size; actual_length++) { + if (data_ptr[actual_length] == '\0') + break; + // Check if character is ASCII printable (0x20-0x7E) or common whitespace + // (0x09, 0x0A, 0x0D) + if (!((data_ptr[actual_length] >= 0x20 && data_ptr[actual_length] <= 0x7E) || + data_ptr[actual_length] == 0x09 || data_ptr[actual_length] == 0x0A || + data_ptr[actual_length] == 0x0D)) { + is_ascii = false; + } + } + + // Check if there is data after the null terminator + bool has_data_after_terminator = false; + + for (size_t i = actual_length; i < array_size; i++) { + if (data_ptr[i] != '\0') { + has_data_after_terminator = true; + // Also check ASCII for data after null terminator + if (!((data_ptr[i] >= 0x20 && data_ptr[i] <= 0x7E) || + data_ptr[i] == 0x09 || data_ptr[i] == 0x0A || + data_ptr[i] == 0x0D)) { + is_ascii = false; + } + break; + } + } + + // If there is data after the terminator, use the whole array_size + size_t string_length = has_data_after_terminator ? array_size : actual_length; + + // Create JSON string directly from the data + *str_obj = json_object_new_string_len((const char *)data_ptr, string_length); + + // Return true only if data is ASCII and no data after null terminator + return is_ascii && !has_data_after_terminator; +} + #pragma pack(push, reason_indentifier, 1) struct reason_indentifier_1_0 { uint16_t versionMajor; @@ -85,44 +136,46 @@ static void telemetry_log_reason_id_parse1_0_ext(const struct telemetry_log *tl, struct json_object *reason_id) { const struct reason_indentifier_1_0 *ri; - struct json_object *reserved; + struct json_object *reserved = NULL; + struct json_object *firmware_str_obj = NULL; + struct json_object *bootloader_str_obj = NULL; + struct json_object *serial_str_obj = NULL; 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++) { - struct json_object *val = json_object_new_int(ri->Reserved[i]); - - json_object_array_add(reserved, val); - } + sldm_uint8_array_to_string((const uint8_t *)ri->FirmwareVersion, + sizeof(ri->FirmwareVersion), &firmware_str_obj); + json_object_object_add(reason_id, "firmwareVersion", firmware_str_obj); + sldm_uint8_array_to_string((const uint8_t *)ri->BootloaderVersion, + sizeof(ri->BootloaderVersion), &bootloader_str_obj); + json_object_object_add(reason_id, "bootloaderVersion", bootloader_str_obj); + sldm_uint8_array_to_string((const uint8_t *)ri->SerialNumber, + sizeof(ri->SerialNumber), &serial_str_obj); + json_object_object_add(reason_id, "serialNumber", serial_str_obj); + + sldm_uint8_array_to_string((const uint8_t *)ri->Reserved, + sizeof(ri->Reserved), &reserved); + json_object_object_add(reason_id, "reserved", reserved); } static void telemetry_log_reason_id_parse1_1_ext(const struct telemetry_log *tl, struct json_object *reason_id) { const struct reason_indentifier_1_1 *ri; - struct json_object *reserved; + struct json_object *reserved = NULL; + struct json_object *firmware_str_obj2 = NULL; + struct json_object *bootloader_str_obj2 = NULL; + struct json_object *serial_str_obj2 = NULL; 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))); + sldm_uint8_array_to_string((const uint8_t *)ri->FirmwareVersion, + sizeof(ri->FirmwareVersion), &firmware_str_obj2); + json_object_object_add(reason_id, "firmwareVersion", firmware_str_obj2); + sldm_uint8_array_to_string((const uint8_t *)ri->BootloaderVersion, + sizeof(ri->BootloaderVersion), &bootloader_str_obj2); + json_object_object_add(reason_id, "bootloaderVersion", bootloader_str_obj2); + sldm_uint8_array_to_string((const uint8_t *)ri->SerialNumber, + sizeof(ri->SerialNumber), &serial_str_obj2); + json_object_object_add(reason_id, "serialNumber", serial_str_obj2); json_object_add_value_uint64(reason_id, "oemDataMapOffset", le64_to_cpu(ri->OemDataMapOffset)); json_object_add_value_uint(reason_id, "telemetryMajorVersion", @@ -130,27 +183,24 @@ static void telemetry_log_reason_id_parse1_1_ext(const struct telemetry_log *tl, 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++) { - struct json_object *val = json_object_new_int(ri->Reserved[i]); - - json_object_array_add(reserved, val); - } + sldm_uint8_array_to_string((const uint8_t *)ri->Reserved, + sizeof(ri->Reserved), &reserved); + json_object_object_add(reason_id, "reserved", reserved); } static void telemetry_log_reason_id_parse1_2_ext(const struct telemetry_log *tl, struct json_object *reason_id) { const struct reason_indentifier_1_2 *ri; - struct json_object *dp_reserved; - struct json_object *reserved; + struct json_object *dp_reserved = NULL; + struct json_object *reserved = NULL; + struct json_object *serial_str_obj3 = NULL; 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))); + sldm_uint8_array_to_string((const uint8_t *)ri->SerialNumber, + sizeof(ri->SerialNumber), &serial_str_obj3); + json_object_object_add(reason_id, "serialNumber", serial_str_obj3); json_object_add_value_uint64(reason_id, "oemDataMapOffset", le64_to_cpu(ri->OemDataMapOffset)); json_object_add_value_uint(reason_id, "telemetryMajorVersion", @@ -159,58 +209,44 @@ static void telemetry_log_reason_id_parse1_2_ext(const struct telemetry_log *tl, 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++) { - struct 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++) { - struct json_object *val = json_object_new_int(ri->DualPortReserved[i]); + sldm_uint8_array_to_string((const uint8_t *)ri->Reserved2, + sizeof(ri->Reserved2), &reserved); + json_object_object_add(reason_id, "reserved2", reserved); - json_object_array_add(dp_reserved, val); - } + sldm_uint8_array_to_string((const uint8_t *)ri->DualPortReserved, + sizeof(ri->DualPortReserved), &dp_reserved); + json_object_object_add(reason_id, "dualPortReserved", dp_reserved); } static void telemetry_log_reason_id_parse_ocp_2_5(const struct telemetry_log *tl, struct json_object *reason_id) { const struct reason_identifier_ocp_2_5 *ri; - struct json_object *reserved; - struct json_object *vu_extension; + struct json_object *reserved = NULL; + struct json_object *vu_extension = NULL; + struct json_object *error_str_obj = NULL; + struct json_object *file_str_obj = NULL; ri = (struct reason_identifier_ocp_2_5 *) tl->log->rsnident; - json_object_object_add(reason_id, "errorId", - json_object_new_string_len(ri->errorId, - sizeof(ri->errorId))); - json_object_object_add(reason_id, "fileId", - json_object_new_string_len(ri->fileId, - sizeof(ri->fileId))); + sldm_uint8_array_to_string((const uint8_t *)ri->errorId, + sizeof(ri->errorId), &error_str_obj); + json_object_object_add(reason_id, "errorId", error_str_obj); + sldm_uint8_array_to_string((const uint8_t *)ri->fileId, + sizeof(ri->fileId), &file_str_obj); + json_object_object_add(reason_id, "fileId", file_str_obj); json_object_add_value_uint(reason_id, "lineNum", le16_to_cpu(ri->lineNum)); json_object_add_value_uint(reason_id, "validLineNum", ri->validFlags.validLineNum); json_object_add_value_uint(reason_id, "validFileId", ri->validFlags.validFileId); json_object_add_value_uint(reason_id, "validErrorId", ri->validFlags.validErrorId); json_object_add_value_uint(reason_id, "validVuExtension", ri->validFlags.validVuExtension); - reserved = json_create_array(); - json_object_add_value_array(reason_id, "reserved", reserved); - for (int i = 0; i < sizeof(ri->reserved); i++) { - struct json_object *val = json_object_new_int(ri->reserved[i]); + sldm_uint8_array_to_string((const uint8_t *)ri->reserved, + sizeof(ri->reserved), &reserved); + json_object_object_add(reason_id, "reserved", reserved); - json_object_array_add(reserved, val); - } - - vu_extension = json_create_array(); - json_object_add_value_array(reason_id, "vuExtension", vu_extension); - for (int i = 0; i < sizeof(ri->vuExtension); i++) { - struct json_object *val = json_object_new_int(ri->vuExtension[i]); - - json_object_array_add(vu_extension, val); - } + sldm_uint8_array_to_string((const uint8_t *)ri->vuExtension, + sizeof(ri->vuExtension), &vu_extension); + json_object_object_add(reason_id, "vuExtension", vu_extension); } static void solidigm_telemetry_log_reason_id_parse(const struct telemetry_log *tl, struct json_object *reason_id) @@ -219,6 +255,7 @@ static void solidigm_telemetry_log_reason_id_parse(const struct telemetry_log *t (struct reason_indentifier_1_0 *) tl->log->rsnident; uint16_t version_major = le16_to_cpu(ri1_0->versionMajor); uint16_t version_minor = le16_to_cpu(ri1_0->versionMinor); + struct json_object *drive_status_obj = NULL; if (tl->is_ocp) { telemetry_log_reason_id_parse_ocp_2_5(tl, reason_id); @@ -228,9 +265,9 @@ static void solidigm_telemetry_log_reason_id_parse(const struct telemetry_log *t 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))); + sldm_uint8_array_to_string((const uint8_t *)ri1_0->DriveStatus, + sizeof(ri1_0->DriveStatus), &drive_status_obj); + json_object_add_value_object(reason_id, "driveStatus", drive_status_obj); if (version_major == 1) { switch (version_minor) { @@ -250,7 +287,7 @@ static void solidigm_telemetry_log_reason_id_parse(const struct telemetry_log *t bool solidigm_telemetry_log_header_parse(const struct telemetry_log *tl) { const struct nvme_telemetry_log *log; - struct json_object *ieee_oui_id; + struct json_object *ieee_oui_id = NULL; struct json_object *reason_id; struct json_object *header; diff --git a/plugins/solidigm/solidigm-telemetry/header.h b/plugins/solidigm/solidigm-telemetry/header.h index 027af5573a..e181d19ffb 100644 --- a/plugins/solidigm/solidigm-telemetry/header.h +++ b/plugins/solidigm/solidigm-telemetry/header.h @@ -6,4 +6,7 @@ */ #include "telemetry-log.h" + +bool sldm_uint8_array_to_string(const uint8_t *data_ptr, uint32_t array_size, + struct json_object **str_obj); bool solidigm_telemetry_log_header_parse(const struct telemetry_log *tl); diff --git a/plugins/solidigm/solidigm-telemetry/nlog.c b/plugins/solidigm/solidigm-telemetry/nlog.c index 366abaefd3..b5ad9b78bd 100644 --- a/plugins/solidigm/solidigm-telemetry/nlog.c +++ b/plugins/solidigm/solidigm-telemetry/nlog.c @@ -18,6 +18,12 @@ LOG_ENTRY_NUM_ARGS_MAX) #define MAX_HEADER_MISMATCH_TRACK 10 + +struct header_mismatch { + uint32_t prev; + uint32_t miss; +}; + static int formats_find(struct json_object *formats, uint32_t val, struct json_object **format) { char hex_header[STR_HEX32_SIZE]; @@ -32,11 +38,13 @@ static uint32_t nlog_get_pos(const uint32_t *nlog, const uint32_t nlog_size, int } static uint32_t nlog_get_events(const uint32_t *nlog, const uint32_t nlog_size, int start_offset, - struct json_object *formats, struct json_object *events, uint32_t *tail_mismatches) + struct json_object *formats, struct json_object *events, + struct header_mismatch *tail_mismatches) { uint32_t event_count = 0; int last_bad_header_pos = nlog_size + 1; // invalid nlog offset uint32_t tail_count = 0; + uint32_t prev_header = 0; for (int i = nlog_size - start_offset - 1; i >= -start_offset; i--) { struct json_object *format = NULL; @@ -48,8 +56,10 @@ static uint32_t nlog_get_events(const uint32_t *nlog, const uint32_t nlog_size, //check if found circular buffer tail if (i != (last_bad_header_pos - 1)) { if (tail_mismatches && - (tail_count < MAX_HEADER_MISMATCH_TRACK)) - tail_mismatches[tail_count] = header; + (tail_count < MAX_HEADER_MISMATCH_TRACK)) { + tail_mismatches[tail_count].prev = prev_header; + tail_mismatches[tail_count].miss = header; + } tail_count++; } last_bad_header_pos = i; @@ -77,6 +87,7 @@ static uint32_t nlog_get_events(const uint32_t *nlog, const uint32_t nlog_size, } i -= 2 + num_data; event_count++; + prev_header = header; } return tail_count; } @@ -86,14 +97,14 @@ int solidigm_nlog_parse(const char *buffer, uint64_t buff_size, struct json_obje { uint32_t smaller_tail_count = UINT32_MAX; int best_offset = 0; - uint32_t offset_tail_mismatches[LOG_ENTRY_MAX_SIZE][MAX_HEADER_MISMATCH_TRACK]; + struct header_mismatch tail_mismatches[LOG_ENTRY_MAX_SIZE][MAX_HEADER_MISMATCH_TRACK]; struct json_object *events = json_object_new_array(); const uint32_t *nlog = (uint32_t *)buffer; const uint32_t nlog_size = buff_size / sizeof(uint32_t); for (int i = 0; i < LOG_ENTRY_MAX_SIZE; i++) { uint32_t tail_count = nlog_get_events(nlog, nlog_size, i, formats, NULL, - offset_tail_mismatches[i]); + tail_mismatches[i]); if (tail_count < smaller_tail_count) { best_offset = i; smaller_tail_count = tail_count; @@ -102,25 +113,27 @@ int solidigm_nlog_parse(const char *buffer, uint64_t buff_size, struct json_obje break; } if (smaller_tail_count > 1) { - const char *name = ""; + int obj_id = -1; int media_bank = -1; - char str_mismatches[(STR_HEX32_SIZE + 1) * MAX_HEADER_MISMATCH_TRACK]; + char str_mismatches[(STR_HEX32_SIZE + 1) * 2 * MAX_HEADER_MISMATCH_TRACK]; int pos = 0; int show_mismatch_num = smaller_tail_count < MAX_HEADER_MISMATCH_TRACK ? smaller_tail_count : MAX_HEADER_MISMATCH_TRACK; struct json_object *jobj; - if (json_object_object_get_ex(metadata, "objName", &jobj)) - name = json_object_get_string(jobj); + if (json_object_object_get_ex(metadata, "objectId", &jobj)) + obj_id = json_object_get_int(jobj); if (json_object_object_get_ex(metadata, "mediaBankId", &jobj)) media_bank = json_object_get_int(jobj); for (int i = 0; i < show_mismatch_num; i++) - pos += snprintf(&str_mismatches[pos], STR_HEX32_SIZE + 1, "0x%08X ", - offset_tail_mismatches[best_offset][i]); + pos += snprintf(&str_mismatches[pos], (STR_HEX32_SIZE + 1) * 2, + "0x%08X-0x%08X ", + tail_mismatches[best_offset][i].prev, + tail_mismatches[best_offset][i].miss); - SOLIDIGM_LOG_WARNING("%s:%d with %d header mismatches ( %s). Configuration file may be missing format headers.", - name, media_bank, smaller_tail_count, str_mismatches); + SOLIDIGM_LOG_WARNING("Warning: obj:%d-%d with %d header sequence mismatches ( %s).", + obj_id, media_bank, smaller_tail_count, str_mismatches); } nlog_get_events(nlog, nlog_size, best_offset, formats, events, NULL);