]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
plugins/ssstc: add a new plugin for SSSTC driver
authorkobyou <kobyou@126.com>
Wed, 24 Apr 2024 03:30:00 +0000 (11:30 +0800)
committerDaniel Wagner <wagi@monom.org>
Wed, 24 Apr 2024 09:26:37 +0000 (11:26 +0200)
Signed-off-by: kobyou <kobyou@126.com>
plugins/meson.build
plugins/ssstc/ssstc-nvme.c [new file with mode: 0644]
plugins/ssstc/ssstc-nvme.h [new file with mode: 0644]

index bb4c9ad7a1ead3d547aa3abafa29d423f614fad0..e919d2736138d889ae306e401a2bf665976f6016 100644 (file)
@@ -26,6 +26,7 @@ if json_c_dep.found()
     'plugins/wdc/wdc-utils.c',
     'plugins/ymtc/ymtc-nvme.c',
     'plugins/zns/zns.c',
+    'plugins/ssstc/ssstc-nvme.c',
   ]
   subdir('solidigm')
   subdir('ocp')
diff --git a/plugins/ssstc/ssstc-nvme.c b/plugins/ssstc/ssstc-nvme.c
new file mode 100644 (file)
index 0000000..03e4fe3
--- /dev/null
@@ -0,0 +1,430 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#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;
+
+}
diff --git a/plugins/ssstc/ssstc-nvme.h b/plugins/ssstc/ssstc-nvme.h
new file mode 100644 (file)
index 0000000..e34fa50
--- /dev/null
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/ssstc/ssstc-nvme
+
+#if !defined(SSSTC_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define SSSTC_NVME
+
+#include "cmd.h"
+PLUGIN(NAME("ssstc", "SSSTC vendor specific extensions", NVME_VERSION),
+       COMMAND_LIST(
+               ENTRY("smart-log-add", "Retrieve ssstc SMART Log, show it", ssstc_get_add_smart_log)
+       )
+);
+#endif
+
+#include "define_cmd.h"