summaryrefslogtreecommitdiffstats
path: root/plugins/ssstc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--plugins/ssstc/ssstc-nvme.c430
-rw-r--r--plugins/ssstc/ssstc-nvme.h16
2 files changed, 446 insertions, 0 deletions
diff --git a/plugins/ssstc/ssstc-nvme.c b/plugins/ssstc/ssstc-nvme.c
new file mode 100644
index 0000000..03e4fe3
--- /dev/null
+++ b/plugins/ssstc/ssstc-nvme.c
@@ -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
index 0000000..e34fa50
--- /dev/null
+++ b/plugins/ssstc/ssstc-nvme.h
@@ -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"