diff --git a/plugins/ocp/ocp-nvme.h b/plugins/ocp/ocp-nvme.h index 0d964c2e6c..7af99decce 100644 --- a/plugins/ocp/ocp-nvme.h +++ b/plugins/ocp/ocp-nvme.h @@ -11,7 +11,7 @@ #if !defined(OCP_NVME) || defined(CMD_HEADER_MULTI_READ) #define OCP_NVME -#define OCP_PLUGIN_VERSION "2.9.3" +#define OCP_PLUGIN_VERSION "2.11.0" #include "cmd.h" PLUGIN(NAME("ocp", "OCP cloud SSD extensions", OCP_PLUGIN_VERSION), diff --git a/plugins/ocp/ocp-telemetry-decode.c b/plugins/ocp/ocp-telemetry-decode.c index 1a6ebe38ec..0f902368ab 100644 --- a/plugins/ocp/ocp-telemetry-decode.c +++ b/plugins/ocp/ocp-telemetry-decode.c @@ -1204,10 +1204,15 @@ int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_e struct json_object *pstats_array, FILE *fp) { if (pstatistic_entry == NULL) { - nvme_show_error("Input buffer was NULL"); + nvme_show_error("Statistics Input buffer was NULL"); return -1; } + if (pstatistic_entry->statistic_id == STATISTICS_RESERVED_ID) + /* End of statistics entries, return -1 to stop processing the buffer */ + return -1; + + unsigned int data_size = pstatistic_entry->statistic_data_size * SIZE_OF_DWORD; __u8 *pdata = (__u8 *)pstatistic_entry + sizeof(struct nvme_ocp_telemetry_statistic_descriptor); @@ -1236,8 +1241,33 @@ int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_e pstatistic_entry->statistic_data_size); json_add_formatted_u32_str(pstatistics_object, STR_RESERVED, pstatistic_entry->reserved); - json_add_formatted_var_size_str(pstatistics_object, STR_STATISTICS_SPECIFIC_DATA, - pdata, data_size); + if (pstatistic_entry->statistic_id == MAX_DIE_BAD_BLOCK_ID) { + json_add_formatted_u32_str(pstatistics_object, + STR_STATISTICS_WORST_DIE_PERCENT, + pdata[0]); + json_add_formatted_u32_str(pstatistics_object, + STR_STATISTICS_WORST_DIE_RAW, + *(__u16 *)&pdata[2]); + } else if (pstatistic_entry->statistic_id == MAX_NAND_CHANNEL_BAD_BLOCK_ID) { + json_add_formatted_u32_str(pstatistics_object, + STR_STATISTICS_WORST_NAND_CHANNEL_PERCENT, + pdata[0]); + json_add_formatted_u32_str(pstatistics_object, + STR_STATISTICS_WORST_NAND_CHANNEL_RAW, + *(__u16 *)&pdata[2]); + } else if (pstatistic_entry->statistic_id == MIN_NAND_CHANNEL_BAD_BLOCK_ID) { + json_add_formatted_u32_str(pstatistics_object, + STR_STATISTICS_BEST_NAND_CHANNEL_PERCENT, + pdata[0]); + json_add_formatted_u32_str(pstatistics_object, + STR_STATISTICS_BEST_NAND_CHANNEL_RAW, + *(__u16 *)&pdata[2]); + } else { + json_add_formatted_var_size_str(pstatistics_object, + STR_STATISTICS_SPECIFIC_DATA, + pdata, + data_size); + } if (pstatistics_object != NULL) json_array_add_value_object(pstats_array, pstatistics_object); @@ -1257,8 +1287,33 @@ int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_e fprintf(fp, "%s: 0x%x\n", STR_STATISTICS_DATA_SIZE, pstatistic_entry->statistic_data_size); fprintf(fp, "%s: 0x%x\n", STR_RESERVED, pstatistic_entry->reserved); - print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA, pdata, - data_size, fp); + if (pstatistic_entry->statistic_id == MAX_DIE_BAD_BLOCK_ID) { + fprintf(fp, "%s: 0x%02x\n", STR_STATISTICS_WORST_DIE_PERCENT, + pdata[0]); + fprintf(fp, "%s: 0x%04x\n", STR_STATISTICS_WORST_DIE_RAW, + *(__u16 *)&pdata[2]); + } else if (pstatistic_entry->statistic_id == + MAX_NAND_CHANNEL_BAD_BLOCK_ID) { + fprintf(fp, "%s: 0x%02x\n", + STR_STATISTICS_WORST_NAND_CHANNEL_PERCENT, + pdata[0]); + fprintf(fp, "%s: 0x%04x\n", + STR_STATISTICS_WORST_NAND_CHANNEL_RAW, + *(__u16 *)&pdata[2]); + } else if (pstatistic_entry->statistic_id == + MIN_NAND_CHANNEL_BAD_BLOCK_ID) { + fprintf(fp, "%s: 0x%02x\n", + STR_STATISTICS_BEST_NAND_CHANNEL_PERCENT, + pdata[0]); + fprintf(fp, "%s: 0x%04x\n", + STR_STATISTICS_BEST_NAND_CHANNEL_RAW, + *(__u16 *)&pdata[2]); + } else { + print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA, + pdata, + data_size, + fp); + } fprintf(fp, STR_LINE2); } else { printf("%s: 0x%x\n", STR_STATISTICS_IDENTIFIER, @@ -1275,8 +1330,33 @@ int parse_statistic(struct nvme_ocp_telemetry_statistic_descriptor *pstatistic_e printf("%s: 0x%x\n", STR_STATISTICS_DATA_SIZE, pstatistic_entry->statistic_data_size); printf("%s: 0x%x\n", STR_RESERVED, pstatistic_entry->reserved); - print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA, pdata, - data_size, fp); + if (pstatistic_entry->statistic_id == MAX_DIE_BAD_BLOCK_ID) { + printf("%s: 0x%02x\n", STR_STATISTICS_WORST_DIE_PERCENT, + pdata[0]); + printf("%s: 0x%04x\n", STR_STATISTICS_WORST_DIE_RAW, + *(__u16 *)&pdata[2]); + } else if (pstatistic_entry->statistic_id == + MAX_NAND_CHANNEL_BAD_BLOCK_ID) { + printf("%s: 0x%02x\n", + STR_STATISTICS_WORST_NAND_CHANNEL_PERCENT, + pdata[0]); + printf("%s: 0x%04x\n", + STR_STATISTICS_WORST_NAND_CHANNEL_RAW, + *(__u16 *)&pdata[2]); + } else if (pstatistic_entry->statistic_id == + MIN_NAND_CHANNEL_BAD_BLOCK_ID) { + printf("%s: 0x%02x\n", + STR_STATISTICS_BEST_NAND_CHANNEL_PERCENT, + pdata[0]); + printf("%s: 0x%04x\n", + STR_STATISTICS_BEST_NAND_CHANNEL_RAW, + *(__u16 *)&pdata[2]); + } else { + print_formatted_var_size_str(STR_STATISTICS_SPECIFIC_DATA, + pdata, + data_size, + fp); + } printf(STR_LINE2); } } @@ -1297,6 +1377,7 @@ int parse_statistics(struct json_object *root, struct nvme_ocp_telemetry_offsets __u32 stats_da_1_start_dw = 0, stats_da_1_size_dw = 0; __u32 stats_da_2_start_dw = 0, stats_da_2_size_dw = 0; __u8 *pstats_offset = NULL; + int parse_rc = 0; if (poffsets->data_area == 1) { __u32 stats_da_1_start = *(__u32 *)(pda1_ocp_header_offset + @@ -1336,7 +1417,11 @@ int parse_statistics(struct json_object *root, struct nvme_ocp_telemetry_offsets (struct nvme_ocp_telemetry_statistic_descriptor *) (pstats_offset + offset_to_move); - parse_statistic(pstatistic_entry, pstats_array, fp); + parse_rc = parse_statistic(pstatistic_entry, pstats_array, fp); + if (parse_rc < 0) + /* end of stats entries or null pointer, so break */ + break; + offset_to_move += (pstatistic_entry->statistic_data_size * SIZE_OF_DWORD + stat_des_size); } diff --git a/plugins/ocp/ocp-telemetry-decode.h b/plugins/ocp/ocp-telemetry-decode.h index 094c920e24..8e1aa03bdc 100644 --- a/plugins/ocp/ocp-telemetry-decode.h +++ b/plugins/ocp/ocp-telemetry-decode.h @@ -459,6 +459,12 @@ struct telemetry_data_area_1 { #define STR_STATISTICS_DATA_SIZE "Statistic Data Size" #define STR_RESERVED "Reserved" #define STR_STATISTICS_SPECIFIC_DATA "Statistic Specific Data" +#define STR_STATISTICS_WORST_DIE_PERCENT "Worst die % of bad blocks" +#define STR_STATISTICS_WORST_DIE_RAW "Worst die raw number of bad blocks" +#define STR_STATISTICS_WORST_NAND_CHANNEL_PERCENT "Worst NAND channel % of bad blocks" +#define STR_STATISTICS_WORST_NAND_CHANNEL_RAW "Worst NAND channel number of bad blocks" +#define STR_STATISTICS_BEST_NAND_CHANNEL_PERCENT "Best NAND channel % of bad blocks" +#define STR_STATISTICS_BEST_NAND_CHANNEL_RAW "Best NAND channel number of bad blocks" #define STR_CLASS_SPECIFIC_DATA "Class Specific Data" #define STR_DBG_EVENT_CLASS_TYPE "Debug Event Class type" #define STR_EVENT_IDENTIFIER "Event Identifier" @@ -496,6 +502,47 @@ enum ocp_telemetry_string_tables { VU_EVENT_STRING }; +/** + * enum ocp_telemetry_statistics_identifiers - OCP Statistics Identifiers + */ +enum ocp_telemetry_statistic_identifiers { + STATISTICS_RESERVED_ID = 0x00, + OUTSTANDING_ADMIN_CMDS_ID = 0x01, + HOST_WRTIE_BANDWIDTH_ID = 0x02, + GW_WRITE_BANDWITH_ID = 0x03, + ACTIVE_NAMESPACES_ID = 0x04, + INTERNAL_WRITE_WORKLOAD_ID = 0x05, + INTERNAL_READ_WORKLOAD_ID = 0x06, + INTERNAL_WRITE_QUEUE_DEPTH_ID = 0x07, + INTERNAL_READ_QUEUE_DEPTH_ID = 0x08, + PENDING_TRIM_LBA_COUNT_ID = 0x09, + HOST_TRIM_LBA_REQUEST_COUNT_ID = 0x0A, + CURRENT_NVME_POWER_STATE_ID = 0x0B, + CURRENT_DSSD_POWER_STATE_ID = 0x0C, + PROGRAM_FAIL_COUNT_ID = 0x0D, + ERASE_FAIL_COUNT_ID = 0x0E, + READ_DISTURB_WRITES_ID = 0x0F, + + RETENTION_WRITES_ID = 0x10, + WEAR_LEVELING_WRITES_ID = 0x11, + READ_RECOVERY_WRITES_ID = 0x12, + GC_WRITES_ID = 0x13, + SRAM_CORRECTABLE_COUNT_ID = 0x14, + DRAM_CORRECTABLE_COUNT_ID = 0x15, + SRAM_UNCORRECTABLE_COUNT_ID = 0x16, + DRAM_UNCORRECTABLE_COUNT_ID = 0x17, + DATA_INTEGRITY_ERROR_COUNT_ID = 0x18, + READ_RETRY_ERROR_COUNT_ID = 0x19, + PERST_EVENTS_COUNT_ID = 0x1A, + MAX_DIE_BAD_BLOCK_ID = 0x1B, + MAX_NAND_CHANNEL_BAD_BLOCK_ID = 0x1C, + MIN_NAND_CHANNEL_BAD_BLOCK_ID = 0x1D, + + //RESERVED = 7FFFh-1Eh, + //VENDOR_UNIQUE_CLASS_TYPE = FFFFh-8000h, +}; + + /** * enum ocp_telemetry_debug_event_class_types - OCP Debug Event Class types * @RESERVED_CLASS_TYPE: Reserved class