// SPDX-License-Identifier: GPL-2.0-or-later #include #include #include #include #include #include #include "common.h" #include "nvme.h" #include "libnvme.h" #include "plugin.h" #include "linux/types.h" #include "nvme-print.h" #define CREATE_CMD #include "ssstc-nvme.h" struct __packed nvme_additional_smart_log_item { __u8 key; __u8 norm; union __packed { __u8 raw[6]; struct __packed wear_level { __le16 min; __le16 max; __le16 avg; } wear_level; }; __u8 _rp[2]; }; struct nvme_additional_smart_log { struct nvme_additional_smart_log_item program_fail_cnt; struct nvme_additional_smart_log_item erase_fail_cnt; struct nvme_additional_smart_log_item wear_leveling_cnt; struct nvme_additional_smart_log_item e2e_err_cnt; struct nvme_additional_smart_log_item crc_err_cnt; struct nvme_additional_smart_log_item nand_bytes_written; struct nvme_additional_smart_log_item host_bytes_written; struct nvme_additional_smart_log_item reallocated_sector_count; struct nvme_additional_smart_log_item uncorrectable_sector_count; struct nvme_additional_smart_log_item NAND_ECC_Detection_Count; struct nvme_additional_smart_log_item NAND_ECC_Correction_Count; struct nvme_additional_smart_log_item Bad_Block_Failure_Rate; struct nvme_additional_smart_log_item GC_Count; struct nvme_additional_smart_log_item DRAM_UECC_Detection_Count; struct nvme_additional_smart_log_item SRAM_UECC_Detection_Count; struct nvme_additional_smart_log_item Raid_Recovery_Fail_Count; struct nvme_additional_smart_log_item Inflight_Command; struct nvme_additional_smart_log_item Internal_End_to_End_Dect_Count; struct nvme_additional_smart_log_item PCIe_Correctable_Error_Count; struct nvme_additional_smart_log_item die_fail_count; struct nvme_additional_smart_log_item wear_leveling_exec_count; struct nvme_additional_smart_log_item read_disturb_count; struct nvme_additional_smart_log_item data_retention_count; }; static void show_ssstc_add_smart_log_jsn(struct nvme_additional_smart_log *smart, unsigned int nsid, const char *devname) { struct json_object *root, *entry_stats, *dev_stats, *multi; __uint16_t wear_level_min = 0; __uint16_t wear_level_max = 0; __uint16_t wear_level_avg = 0; uint64_t raw_val = 0; root = json_create_object(); json_object_add_value_string(root, "SSSTC Smart log", devname); dev_stats = json_create_object(); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->program_fail_cnt.key); json_object_add_value_int(entry_stats, "normalized", smart->program_fail_cnt.norm); raw_val = int48_to_long(smart->program_fail_cnt.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "program_fail_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->erase_fail_cnt.key); json_object_add_value_int(entry_stats, "normalized", smart->erase_fail_cnt.norm); raw_val = int48_to_long(smart->erase_fail_cnt.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "erase_fail_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->wear_leveling_cnt.key); json_object_add_value_int(entry_stats, "normalized", smart->wear_leveling_cnt.norm); multi = json_create_object(); wear_level_min = le16_to_cpu(smart->wear_leveling_cnt.wear_level.min); wear_level_max = le16_to_cpu(smart->wear_leveling_cnt.wear_level.max); wear_level_avg = le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg); json_object_add_value_int(multi, "min", wear_level_min); json_object_add_value_int(multi, "max", wear_level_max); json_object_add_value_int(multi, "avg", wear_level_avg); json_object_add_value_object(entry_stats, "raw", multi); json_object_add_value_object(dev_stats, "wear_leveling", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->e2e_err_cnt.key); json_object_add_value_int(entry_stats, "normalized", smart->e2e_err_cnt.norm); multi = json_create_object(); wear_level_min = le16_to_cpu(smart->e2e_err_cnt.wear_level.min); wear_level_max = le16_to_cpu(smart->e2e_err_cnt.wear_level.max); wear_level_avg = le16_to_cpu(smart->e2e_err_cnt.wear_level.avg); json_object_add_value_int(multi, "guard check error", wear_level_min); json_object_add_value_int(multi, "application tag check error", wear_level_max); json_object_add_value_int(multi, "reference tag check error", wear_level_avg); json_object_add_value_object(entry_stats, "raw", multi); json_object_add_value_object(dev_stats, "end_to_end_error_dect_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->crc_err_cnt.key); json_object_add_value_int(entry_stats, "normalized", smart->crc_err_cnt.norm); raw_val = int48_to_long(smart->crc_err_cnt.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "crc_error_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->nand_bytes_written.key); json_object_add_value_int(entry_stats, "normalized", smart->nand_bytes_written.norm); raw_val = int48_to_long(smart->nand_bytes_written.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "nand_bytes_written", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->host_bytes_written.key); json_object_add_value_int(entry_stats, "normalized", smart->host_bytes_written.norm); raw_val = int48_to_long(smart->host_bytes_written.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "host_bytes_written", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->reallocated_sector_count.key); json_object_add_value_int(entry_stats, "normalized", smart->reallocated_sector_count.norm); raw_val = int48_to_long(smart->reallocated_sector_count.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "reallocated_sector_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->uncorrectable_sector_count.key); json_object_add_value_int(entry_stats, "normalized", smart->uncorrectable_sector_count.norm); raw_val = int48_to_long(smart->uncorrectable_sector_count.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "uncorrectable_sector_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->NAND_ECC_Detection_Count.key); json_object_add_value_int(entry_stats, "normalized", smart->NAND_ECC_Detection_Count.norm); raw_val = int48_to_long(smart->NAND_ECC_Detection_Count.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "NAND_ECC_detection_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->NAND_ECC_Correction_Count.key); json_object_add_value_int(entry_stats, "normalized", smart->NAND_ECC_Correction_Count.norm); raw_val = int48_to_long(smart->NAND_ECC_Correction_Count.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "NAND_ECC_correction_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->GC_Count.key); json_object_add_value_int(entry_stats, "normalized", smart->GC_Count.norm); raw_val = int48_to_long(smart->GC_Count.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "GC_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->DRAM_UECC_Detection_Count.key); json_object_add_value_int(entry_stats, "normalized", smart->DRAM_UECC_Detection_Count.norm); multi = json_create_object(); wear_level_max = le16_to_cpu(smart->DRAM_UECC_Detection_Count.wear_level.max); wear_level_avg = le16_to_cpu(smart->DRAM_UECC_Detection_Count.wear_level.avg); json_object_add_value_int(multi, "1-Bit Err", wear_level_max); json_object_add_value_int(multi, "2-Bit Err", wear_level_avg); json_object_add_value_object(entry_stats, "raw", multi); json_object_add_value_object(dev_stats, "DRAM_UECC_detection_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->SRAM_UECC_Detection_Count.key); json_object_add_value_int(entry_stats, "normalized", smart->SRAM_UECC_Detection_Count.norm); multi = json_create_object(); wear_level_min = le16_to_cpu(smart->SRAM_UECC_Detection_Count.wear_level.min); wear_level_max = le16_to_cpu(smart->SRAM_UECC_Detection_Count.wear_level.max); wear_level_avg = le16_to_cpu(smart->SRAM_UECC_Detection_Count.wear_level.avg); json_object_add_value_int(multi, "parity error detected", wear_level_min); json_object_add_value_int(multi, "ecc error detection", wear_level_max); json_object_add_value_int(multi, "axi data parity errors", wear_level_avg); json_object_add_value_object(entry_stats, "raw", multi); json_object_add_value_object(dev_stats, "SRAM_UECC_Detection_Count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->Raid_Recovery_Fail_Count.key); json_object_add_value_int(entry_stats, "normalized", smart->Raid_Recovery_Fail_Count.norm); raw_val = int48_to_long(smart->Raid_Recovery_Fail_Count.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "raid_Recovery_fail_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->Inflight_Command.key); json_object_add_value_int(entry_stats, "normalized", smart->Inflight_Command.norm); multi = json_create_object(); wear_level_min = le16_to_cpu(smart->Inflight_Command.wear_level.min); wear_level_max = le16_to_cpu(smart->Inflight_Command.wear_level.max); wear_level_avg = le16_to_cpu(smart->Inflight_Command.wear_level.avg); json_object_add_value_int(multi, "Read Cmd", wear_level_min); json_object_add_value_int(multi, "Write Cmd", wear_level_max); json_object_add_value_int(multi, "Admin Cmd", wear_level_avg); json_object_add_value_object(entry_stats, "raw", multi); json_object_add_value_object(dev_stats, "Inflight_Command", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->Internal_End_to_End_Dect_Count.key); json_object_add_value_int(entry_stats, "normalized", 100); multi = json_create_object(); wear_level_min = le16_to_cpu(smart->Internal_End_to_End_Dect_Count.wear_level.min); wear_level_max = le16_to_cpu(smart->Internal_End_to_End_Dect_Count.wear_level.max); wear_level_avg = le16_to_cpu(smart->Internal_End_to_End_Dect_Count.wear_level.avg); json_object_add_value_int(multi, "read hcrc", wear_level_min); json_object_add_value_int(multi, "write hcrc", wear_level_max); json_object_add_value_int(multi, "reserved", wear_level_avg); json_object_add_value_object(entry_stats, "raw", multi); json_object_add_value_object(dev_stats, "internal_end_to_end_dect_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->die_fail_count.key); json_object_add_value_int(entry_stats, "normalized", smart->die_fail_count.norm); raw_val = int48_to_long(smart->die_fail_count.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "die_fail_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->wear_leveling_exec_count.key); json_object_add_value_int(entry_stats, "normalized", smart->wear_leveling_exec_count.norm); raw_val = int48_to_long(smart->wear_leveling_exec_count.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "wear_leveling_exec_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->read_disturb_count.key); json_object_add_value_int(entry_stats, "normalized", smart->read_disturb_count.norm); raw_val = int48_to_long(smart->read_disturb_count.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "read_disturb_count", entry_stats); entry_stats = json_create_object(); json_object_add_value_int(entry_stats, "#id", smart->data_retention_count.key); json_object_add_value_int(entry_stats, "normalized", smart->data_retention_count.norm); raw_val = int48_to_long(smart->data_retention_count.raw); json_object_add_value_int(entry_stats, "raw", raw_val); json_object_add_value_object(dev_stats, "data_retention_count", entry_stats); json_object_add_value_object(root, "Device stats", dev_stats); json_print_object(root, NULL); json_free_object(root); } static void show_ssstc_add_smart_log(struct nvme_additional_smart_log *smart, unsigned int nsid, const char *devname) { printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", devname, nsid); printf("key #id normalized raw\n"); printf("program_fail_count : %03d %3d%% %"PRIu64"\n", smart->program_fail_cnt.key, smart->program_fail_cnt.norm, int48_to_long(smart->program_fail_cnt.raw)); printf("erase_fail_count : %03d %3d%% %"PRIu64"\n", smart->erase_fail_cnt.key, smart->erase_fail_cnt.norm, int48_to_long(smart->erase_fail_cnt.raw)); printf("wear_leveling : %03d %3d%% min: %u, max: %u, avg: %u\n", smart->wear_leveling_cnt.key, smart->wear_leveling_cnt.norm, le16_to_cpu(smart->wear_leveling_cnt.wear_level.min), le16_to_cpu(smart->wear_leveling_cnt.wear_level.max), le16_to_cpu(smart->wear_leveling_cnt.wear_level.avg)); printf("end_to_end_error_dect_count : %03d %3d%% " "guard check error: %u, " "application tag check error: %u, " "reference tag check error: %u\n", smart->e2e_err_cnt.key, smart->e2e_err_cnt.norm, le16_to_cpu(smart->e2e_err_cnt.wear_level.min), le16_to_cpu(smart->e2e_err_cnt.wear_level.max), le16_to_cpu(smart->e2e_err_cnt.wear_level.avg)); printf("crc_error_count : %03d %3d%% %"PRIu64"\n", smart->crc_err_cnt.key, smart->crc_err_cnt.norm, int48_to_long(smart->crc_err_cnt.raw)); printf("nand_bytes_written : %03d %3d%% sectors: %"PRIu64"\n", smart->nand_bytes_written.key, smart->nand_bytes_written.norm, int48_to_long(smart->nand_bytes_written.raw)); printf("host_bytes_written : %3d %3d%% sectors: %"PRIu64"\n", smart->host_bytes_written.key, smart->host_bytes_written.norm, int48_to_long(smart->host_bytes_written.raw)); printf("reallocated_sector_count : %03d %3d%% %"PRIu64"\n", smart->reallocated_sector_count.key, smart->reallocated_sector_count.norm, int48_to_long(smart->reallocated_sector_count.raw)); printf("uncorrectable_sector_count : %03d %3d%% %"PRIu64"\n", smart->uncorrectable_sector_count.key, smart->uncorrectable_sector_count.norm, int48_to_long(smart->uncorrectable_sector_count.raw)); printf("NAND_ECC_detection_count : %03d %3d%% %"PRIu64"\n", smart->NAND_ECC_Detection_Count.key, smart->NAND_ECC_Detection_Count.norm, int48_to_long(smart->NAND_ECC_Detection_Count.raw)); printf("NAND_ECC_correction_count : %03d %3d%% %"PRIu64"\n", smart->NAND_ECC_Correction_Count.key, smart->NAND_ECC_Correction_Count.norm, int48_to_long(smart->NAND_ECC_Correction_Count.raw)); printf("GC_count : %03d %3d%% %"PRIu64"\n", smart->GC_Count.key, smart->GC_Count.norm, int48_to_long(smart->GC_Count.raw)); printf("DRAM_UECC_detection_count : %03d %3d%% 1-Bit Err: %u, 2-Bit Err: %u\n", smart->DRAM_UECC_Detection_Count.key, smart->DRAM_UECC_Detection_Count.norm, le16_to_cpu(smart->DRAM_UECC_Detection_Count.wear_level.max), le16_to_cpu(smart->DRAM_UECC_Detection_Count.wear_level.avg)); printf("SRAM_UECC_Detection_Count : %03d %3d%% " "parity error detected: %u, " "ecc error detection: %u, " "axi data parity errors: %u\n", smart->SRAM_UECC_Detection_Count.key, smart->SRAM_UECC_Detection_Count.norm, le16_to_cpu(smart->SRAM_UECC_Detection_Count.wear_level.min), le16_to_cpu(smart->SRAM_UECC_Detection_Count.wear_level.max), le16_to_cpu(smart->SRAM_UECC_Detection_Count.wear_level.avg)); printf("raid_recovery_fail_count : %03d %3d%% %"PRIu64"\n", smart->Raid_Recovery_Fail_Count.key, smart->Raid_Recovery_Fail_Count.norm, int48_to_long(smart->Raid_Recovery_Fail_Count.raw)); printf("Inflight_Command : %03d %3d%% " "Read Cmd: %u, Write Cmd: %u, Admin Cmd: %u\n", smart->Inflight_Command.key, smart->Inflight_Command.norm, le16_to_cpu(smart->Inflight_Command.wear_level.min), le16_to_cpu(smart->Inflight_Command.wear_level.max), le16_to_cpu(smart->Inflight_Command.wear_level.avg)); printf("internal_end_to_end_dect_count : %03d %3d%% " "read hcrc: %u, write hcrc: %u, reserved: %u\n", smart->Internal_End_to_End_Dect_Count.key, 100, le16_to_cpu(smart->Internal_End_to_End_Dect_Count.wear_level.min), le16_to_cpu(smart->Internal_End_to_End_Dect_Count.wear_level.max), le16_to_cpu(smart->Internal_End_to_End_Dect_Count.wear_level.avg)); printf("die_fail_count : %03d %3d%% %"PRIu64"\n", smart->die_fail_count.key, smart->die_fail_count.norm, int48_to_long(smart->die_fail_count.raw)); printf("wear_leveling_exec_count : %03d %3d%% %"PRIu64"\n", smart->wear_leveling_exec_count.key, smart->wear_leveling_exec_count.norm, int48_to_long(smart->wear_leveling_exec_count.raw)); printf("read_disturb_count : %03d %3d%% %"PRIu64"\n", smart->read_disturb_count.key, smart->read_disturb_count.norm, int48_to_long(smart->read_disturb_count.raw)); printf("data_retention_count : %03d %3d%% %"PRIu64"\n", smart->data_retention_count.key, smart->data_retention_count.norm, int48_to_long(smart->data_retention_count.raw)); } static int ssstc_get_add_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Get SSSTC vendor specific additional smart log\n" "(optionally, for the specified namespace), and show it."; const char *namespace = "(optional) desired namespace"; const char *raw = "Dump output in binary format"; const char *json = "Dump output in json format"; struct nvme_additional_smart_log smart_log_add; struct nvme_dev *dev; int err; struct config { __u32 namespace_id; bool raw_binary; bool json; }; struct config cfg = { .namespace_id = NVME_NSID_ALL, }; OPT_ARGS(opts) = { OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace), OPT_FLAG("raw-binary", 'b', &cfg.raw_binary, raw), OPT_FLAG("json", 'j', &cfg.json, json), OPT_END() }; err = parse_and_open(&dev, argc, argv, desc, opts); if (err) return err; err = nvme_get_log_simple(dev_fd(dev), 0xca, sizeof(smart_log_add), &smart_log_add); if (!err) { if (cfg.json) show_ssstc_add_smart_log_jsn(&smart_log_add, cfg.namespace_id, dev->name); else if (!cfg.raw_binary) show_ssstc_add_smart_log(&smart_log_add, cfg.namespace_id, dev->name); else d_raw((unsigned char *)&smart_log_add, sizeof(smart_log_add)); } else if (err > 0) { nvme_show_status(err); } dev_close(dev); return err; }