]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
solidigm: Add Solidigm pluging for vendor specific SMART fields.
authorda Cunha, Leonardo <leonardo.da.cunha@solidigmtechnology.com>
Fri, 18 Mar 2022 19:45:43 +0000 (15:45 -0400)
committerDaniel Wagner <dwagner@suse.de>
Tue, 17 May 2022 10:50:32 +0000 (12:50 +0200)
plugins/meson.build
plugins/solidigm/solidigm-nvme.h [new file with mode: 0644]
plugins/solidigm/solidigm-smart.c [new file with mode: 0644]

index 6f213620232da722db26deebca95431cce1e9a52..6783c0b01cd86b05e7c847f4d883ba4d7892055d 100644 (file)
@@ -10,6 +10,7 @@ sources += [
   'plugins/scaleflux/sfx-nvme.c',
   'plugins/seagate/seagate-nvme.c',
   'plugins/shannon/shannon-nvme.c',
+  'plugins/solidigm/solidigm-smart.c',
   'plugins/toshiba/toshiba-nvme.c',
   'plugins/transcend/transcend-nvme.c',
   'plugins/virtium/virtium-nvme.c',
diff --git a/plugins/solidigm/solidigm-nvme.h b/plugins/solidigm/solidigm-nvme.h
new file mode 100644 (file)
index 0000000..d7035cf
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ *
+ *   Author: leonardo.da.cunha@solidigm.com
+ */
+
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/solidigm/solidigm-nvme
+
+#if !defined(SOLIDIGM_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define SOLIDIGM_NVME
+
+#include "cmd.h"
+
+#define SOLIDIGM_PLUGIN_VERSION "0.1"
+
+PLUGIN(NAME("solidigm", "Solidigm vendor specific extensions", SOLIDIGM_PLUGIN_VERSION),
+       COMMAND_LIST(
+               ENTRY("smart-log-add", "Retrieve Solidigm SMART Log", get_additional_smart_log)
+       )
+);
+
+#endif
+
+#include "define_cmd.h"
diff --git a/plugins/solidigm/solidigm-smart.c b/plugins/solidigm/solidigm-smart.c
new file mode 100644 (file)
index 0000000..d056369
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2022 Solidigm.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ *
+ *   Author: leonardo.da.cunha@solidigm.com
+ */
+
+#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 "solidigm-nvme.h"
+
+struct  __attribute__((packed)) nvme_additional_smart_log_item {
+       __u8                    id;
+       __u8                    _kp[2];
+       __u8                    normalized;
+       __u8                    _np;
+       union __attribute__((packed)) {
+               __u8            raw[6];
+               struct __attribute__((packed))  wear_level {
+                       __le16  min;
+                       __le16  max;
+                       __le16  avg;
+               } wear_level;
+               struct __attribute__((packed)) thermal_throttle {
+                       __u8    pct;
+                       __u32   count;
+               } thermal_throttle;
+       } ;
+       __u8                    _rp;
+} ;
+typedef struct nvme_additional_smart_log_item smart_log_item_t;
+
+#define VU_SMART_PAGE_SIZE 512
+#define VU_SMART_MAX_ITEMS VU_SMART_PAGE_SIZE / sizeof(smart_log_item_t)
+typedef struct vu_smart_log {
+       smart_log_item_t item[VU_SMART_MAX_ITEMS];
+} vu_smart_log_t;
+
+static char *id_to_name(__u8 id)
+{
+       switch (id) {
+       case 0x0D:
+               return "soft_ecc_error_rate";
+       case 0x05:
+               return "relocatable_sector_count";
+       case 0xAB:
+               return "program_fail_count";
+       case 0xAC:
+               return "erase_fail_count";
+       case 0xAD:
+               return "wear_leveling_count";
+       case 0xAE:
+               return "unexpected_power_loss";
+       case 0xB8:
+               return "e2e_error_detect_count";
+       case 0xC7:
+               return "crc_error_count";
+       case 0xE2:
+               return "media_wear_percentage";
+       case 0xE3:
+               return "host_reads";
+       case 0xE4:
+               return "timed_work_load";
+       case 0xE5:
+               return "read_commands_in_flight_counter";
+       case 0xE6:
+               return "write_commands_in_flight_counter";
+       case 0xEA:
+               return "thermal_throttle_status";
+       case 0xF0:
+               return "retry_buffer_overflow_counter";
+       case 0xF3:
+               return "pll_lock_loss_counter";
+       case 0xF4:
+               return "nand_bytes_written";
+       case 0xF5:
+               return "host_bytes_written";
+       case 0xF6:
+               return "host_context_wear_used";
+       case 0xF7:
+               return "performance_status_indicator";
+       case 0xF8:
+               return "media_bytes_read";
+       case 0xF9:
+               return "available_fw_downgrades";
+       case 0xFA:
+               return "host_read_collision_count";
+       case 0xFB:
+               return "host_write_collision_count";
+       case 0xFC:
+               return "xor_pass_count";
+       case 0xFD:
+               return "xor_fail_count";
+       case 0xFE:
+               return "xor_invoked_count";
+       default:
+               return "unknown";
+       }
+}
+
+static void smart_log_item_print(smart_log_item_t *item)
+{
+       if (!item->id) {
+               return;
+       }
+
+       printf("%#x    %-45s  %3d         ",
+               item->id, id_to_name(item->id), item->normalized);
+
+       switch (item->id) {
+       case 0xAD:
+               printf("min: %u, max: %u, avg: %u\n",
+                       le16_to_cpu(item->wear_level.min),
+                       le16_to_cpu(item->wear_level.max),
+                       le16_to_cpu(item->wear_level.avg));
+               return;
+       case 0xEA:
+               printf("%u%%, cnt: %u\n",
+                       item->thermal_throttle.pct,
+                       le32_to_cpu(item->thermal_throttle.count));
+               return;
+       default:
+               printf("%"PRIu64"\n", int48_to_long(item->raw));
+       }
+}
+
+static void smart_log_item_add_json(smart_log_item_t *item, struct json_object *dev_stats)
+{
+       struct json_object *entry_stats = json_create_object();
+
+       if (!item->id) {
+               return;
+       }
+
+       json_object_add_value_int(entry_stats, "normalized", item->normalized);
+
+       switch (item->id) {
+       case 0xAD:
+               json_object_add_value_int(entry_stats, "min", le16_to_cpu(item->wear_level.min));
+               json_object_add_value_int(entry_stats, "max", le16_to_cpu(item->wear_level.max));
+               json_object_add_value_int(entry_stats, "avg", le16_to_cpu(item->wear_level.avg));
+               break;
+       case 0xEA:
+               json_object_add_value_int(entry_stats, "percentage", item->thermal_throttle.pct);
+               json_object_add_value_int(entry_stats, "count", le32_to_cpu(item->thermal_throttle.count));
+               break;
+       default:
+               json_object_add_value_int(entry_stats, "raw", int48_to_long(item->raw));
+       }
+       json_object_add_value_object(dev_stats, id_to_name(item->id), entry_stats);
+}
+
+static void vu_smart_log_show_json(vu_smart_log_t *payload, unsigned int nsid, const char *devname)
+{
+       struct json_object *dev_stats = json_create_object();
+       smart_log_item_t *item = payload->item;
+       struct json_object *root;
+
+       for (int i = 0; i < VU_SMART_MAX_ITEMS; i++) {
+               smart_log_item_add_json(&item[i], dev_stats);
+       }
+
+       root = json_create_object();
+       json_object_add_value_string(root, "Solidigm SMART log", devname);
+       json_object_add_value_object(root, "Device stats", dev_stats);
+
+       json_print_object(root, NULL);
+       json_free_object(root);
+}
+
+static void vu_smart_log_show(vu_smart_log_t *payload, unsigned int nsid, const char *devname)
+{
+       smart_log_item_t *item = payload->item;
+
+       printf("Additional Smart Log for NVME device:%s namespace-id:%x\n",
+               devname, nsid);
+       printf("ID             KEY                                 Normalized     Raw\n");
+
+       for (int i = 0; i < VU_SMART_MAX_ITEMS; i++) {
+               smart_log_item_print(&item[i]);
+       }
+}
+
+static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Get Solidigm vendor specific smart log (optionally, "\
+                     "for the specified namespace), and show it.";
+       const int solidigm_vu_smart_log_id = 0xCA;
+       vu_smart_log_t smart_log_payload;
+       enum nvme_print_flags flags;
+       int fd, err;
+
+       struct config {
+               __u32   namespace_id;
+               char    *output_format;
+               int     raw_binary;
+       };
+
+       struct config cfg = {
+               .namespace_id   = NVME_NSID_ALL,
+               .output_format  = "normal",
+               .raw_binary     = 0
+       };
+
+       OPT_ARGS(opts) = {
+               OPT_UINT("namespace-id",   'n', &cfg.namespace_id,   "(optional) desired namespace"),
+               OPT_FMT("output-format",   'o', &cfg.output_format,  output_format),
+               OPT_FLAG("raw-binary",     'b', &cfg.raw_binary,     "Dump output in binary format"),
+               OPT_END()
+       };
+
+       fd = parse_and_open(argc, argv, desc, opts);
+       if (fd < 0) {
+               return fd;
+       }
+
+       flags = validate_output_format(cfg.output_format);
+       if (flags == -EINVAL) {
+               fprintf(stderr, "Invalid output format '%s'\n", cfg.output_format);
+               close(fd);
+               return fd;
+       }
+       if (cfg.raw_binary)     {
+               flags = BINARY;
+       }
+
+       err = nvme_get_log_simple(fd, solidigm_vu_smart_log_id, sizeof(smart_log_payload), &smart_log_payload);
+       if (!err) {
+               if (flags & JSON) {
+                       vu_smart_log_show_json(&smart_log_payload, cfg.namespace_id, devicename);
+               } else if (flags & BINARY) {
+                       d_raw((unsigned char *)&smart_log_payload, sizeof(smart_log_payload));
+               } else {
+                       vu_smart_log_show(&smart_log_payload, cfg.namespace_id, devicename);
+               }
+       } else if (err > 0) {
+               nvme_show_status(err);
+       }
+
+       close(fd);
+       return err;
+}
+