]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
NVMe-Cli Shannon Plugin-add support for shannon systems.
authoryongxing <yongxing.sun@shannon-sys.com>
Mon, 10 Jun 2019 14:56:33 +0000 (22:56 +0800)
committeryongxing <yongxing.sun@shannon-sys.com>
Mon, 10 Jun 2019 14:56:33 +0000 (22:56 +0800)
    Hello,current NVMe-Cli tools hasn't supprot for shannon systems, we want to add it.
    May we add some specific commands?
    We add four NVMe commands for shannon temporarily,smart-log-add, get-feature-add, set-feature-add,
    and id-ctrl.

    Any problems, please contact me with:

    Email:yongxing.sun@shannon-sys.com

Makefile
plugins/shannon/shannon-nvme.c [new file with mode: 0644]
plugins/shannon/shannon-nvme.h [new file with mode: 0644]

index ebb6b75b4a12ec06d1b130ae13817d5b74864152..5081c2b8d588dac5dbacb9e95fa02c4df016e4af 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -45,7 +45,8 @@ PLUGIN_OBJS :=                                        \
        plugins/toshiba/toshiba-nvme.o          \
        plugins/micron/micron-nvme.o            \
        plugins/seagate/seagate-nvme.o          \
-       plugins/virtium/virtium-nvme.o
+       plugins/virtium/virtium-nvme.o          \
+       plugins/shannon/shannon-nvme.o
 
 nvme: nvme.c nvme.h $(OBJS) $(PLUGIN_OBJS) NVME-VERSION-FILE
        $(CC) $(CPPFLAGS) $(CFLAGS) nvme.c -o $(NVME) $(OBJS) $(PLUGIN_OBJS) $(LDFLAGS)
diff --git a/plugins/shannon/shannon-nvme.c b/plugins/shannon/shannon-nvme.c
new file mode 100644 (file)
index 0000000..8b97f2e
--- /dev/null
@@ -0,0 +1,356 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include "linux/nvme_ioctl.h"
+
+#include "common.h"
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "json.h"
+#include "plugin.h"
+
+#include "argconfig.h"
+#include "suffix.h"
+
+#define CREATE_CMD
+#include "shannon-nvme.h"
+
+typedef enum {
+       PROGRAM_FAIL_CNT,
+       ERASE_FAIL_CNT,
+       WEARLEVELING_COUNT,
+       E2E_ERR_CNT,
+       CRC_ERR_CNT,
+       TIME_WORKLOAD_MEDIA_WEAR,       
+       TIME_WORKLOAD_HOST_READS,       
+       TIME_WORKLOAD_TIMER,            
+       THERMAL_THROTTLE,             
+       RETRY_BUFFER_OVERFLOW,          
+       PLL_LOCK_LOSS,                          
+       NAND_WRITE,
+       HOST_WRITE,
+       ADD_SMART_ITEMS,
+}addtional_smart_items;
+
+#pragma pack(push,1)
+struct nvme_shannon_smart_log_item {
+       __u8                    _resv[5];
+       union {
+               __u8            item_val[6];
+               struct wear_level {
+                       __le16  min;
+                       __le16  max;
+                       __le16  avg;
+               } wear_level ;
+               struct thermal_throttle {
+                       __u8    st;
+                       __u32   count;
+               } thermal_throttle;
+       };
+       __u8                    resv;
+};
+#pragma pack(pop)
+
+struct nvme_shannon_smart_log {
+       struct nvme_shannon_smart_log_item items[ADD_SMART_ITEMS];
+        __u8  vend_spec_resv; 
+};
+
+static void show_shannon_smart_log(struct nvme_shannon_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                               value\n");
+       printf("program_fail_count              : %"PRIu64"\n",
+               int48_to_long(smart->items[PROGRAM_FAIL_CNT].item_val));
+       printf("erase_fail_count                : %"PRIu64"\n",
+               int48_to_long(smart->items[ERASE_FAIL_CNT].item_val));
+       printf("wear_leveling                   : min: %u, max: %u, avg: %u\n",
+               le16_to_cpu(smart->items[WEARLEVELING_COUNT].wear_level.min),
+               le16_to_cpu(smart->items[WEARLEVELING_COUNT].wear_level.max),
+               le16_to_cpu(smart->items[WEARLEVELING_COUNT].wear_level.avg));
+       printf("end_to_end_error_detection_count: %"PRIu64"\n",
+               int48_to_long(smart->items[E2E_ERR_CNT].item_val));
+       printf("crc_error_count                 : %"PRIu64"\n",
+               int48_to_long(smart->items[CRC_ERR_CNT].item_val));
+       printf("timed_workload_media_wear       : %.3f%%\n",
+               ((float)int48_to_long(smart->items[TIME_WORKLOAD_MEDIA_WEAR].item_val)) / 1024);
+       printf("timed_workload_host_reads       : %"PRIu64"%%\n",
+               int48_to_long(smart->items[TIME_WORKLOAD_HOST_READS].item_val));
+       printf("timed_workload_timer            : %"PRIu64" min\n",
+               int48_to_long(smart->items[TIME_WORKLOAD_TIMER].item_val));
+       printf("thermal_throttle_status         : CurTTState: %u%%, TTActiveCnt: %u\n",
+               smart->items[THERMAL_THROTTLE].thermal_throttle.st,
+               smart->items[THERMAL_THROTTLE].thermal_throttle.count);
+       printf("retry_buffer_overflow_count     : %"PRIu64"\n",
+               int48_to_long(smart->items[RETRY_BUFFER_OVERFLOW].item_val));
+       printf("pll_lock_loss_count             : %"PRIu64"\n",
+               int48_to_long(smart->items[PLL_LOCK_LOSS].item_val));
+       printf("nand_bytes_written              : sectors: %"PRIu64"\n",
+               int48_to_long(smart->items[NAND_WRITE].item_val));
+       printf("host_bytes_written              : sectors: %"PRIu64"\n",
+               int48_to_long(smart->items[HOST_WRITE].item_val));
+}
+
+
+static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       struct nvme_shannon_smart_log smart_log;
+       int err, fd;
+       char *desc = "Get Shannon vendor specific additional smart log (optionally, "\
+                     "for the specified namespace), and show it.";
+       const char *namespace = "(optional) desired namespace";
+       const char *raw = "dump output in binary format";
+       struct config {
+               __u32 namespace_id;
+               int   raw_binary;
+       };
+
+       struct config cfg = {
+               .namespace_id = NVME_NSID_ALL,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id, required_argument, namespace},
+               {"raw-binary",   'b', "",    CFG_NONE,     &cfg.raw_binary,   no_argument,       raw},
+               {NULL}
+       };
+
+       fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+
+       err = nvme_get_log(fd, cfg.namespace_id, 0xca, false,
+                  sizeof(smart_log), &smart_log);
+       if (!err) {
+               if (!cfg.raw_binary)
+                       show_shannon_smart_log(&smart_log, cfg.namespace_id, devicename);
+               else
+                       d_raw((unsigned char *)&smart_log, sizeof(smart_log));
+       }
+       else if (err > 0)
+               fprintf(stderr, "NVMe Status:%s(%x)\n",
+                                       nvme_status_to_string(err), err);
+       return err;
+}
+
+static int get_additional_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Read operating parameters of the "\
+               "specified controller. Operating parameters are grouped "\
+               "and identified by Feature Identifiers; each Feature "\
+               "Identifier contains one or more attributes that may affect "\
+               "behaviour of the feature. Each Feature has three possible "\
+               "settings: default, saveable, and current. If a Feature is "\
+               "saveable, it may be modified by set-feature. Default values "\
+               "are vendor-specific and not changeable. Use set-feature to "\
+               "change saveable Features.\n\n"\
+               "Available additional feature id:\n"\
+               "0x02:  Shannon power management\n";
+       const char *raw_binary = "show infos in binary format";
+       const char *namespace_id = "identifier of desired namespace";
+       const char *feature_id = "hexadecimal feature name";
+       const char *sel = "[0-3]: curr./default/saved/supp.";
+       const char *data_len = "buffer len (if) data is returned";
+       const char *cdw11 = "dword 11 for interrupt vector config";
+       const char *human_readable = "show infos in readable format";
+       int err, fd;
+       __u32 result;
+       void *buf = NULL;
+
+       struct config {
+               __u32 namespace_id;
+               __u32 feature_id;
+               __u8  sel;
+               __u32 cdw11;
+               __u32 data_len;
+               int  raw_binary;
+               int  human_readable;
+       };
+
+       struct config cfg = {
+               .namespace_id = 1,
+               .feature_id   = 0,
+               .sel          = 0,
+               .cdw11        = 0,
+               .data_len     = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id",   'n', "NUM", CFG_POSITIVE, &cfg.namespace_id,   required_argument, namespace_id},
+               {"feature-id",     'f', "NUM", CFG_POSITIVE, &cfg.feature_id,     required_argument, feature_id},
+               {"sel",            's', "NUM", CFG_BYTE,     &cfg.sel,            required_argument, sel},
+               {"data-len",       'l', "NUM", CFG_POSITIVE, &cfg.data_len,       required_argument, data_len},
+               {"raw-binary",     'b', "FLAG", CFG_NONE,     &cfg.raw_binary,     no_argument,       raw_binary},
+               {"cdw11",          'c', "NUM", CFG_POSITIVE, &cfg.cdw11,          required_argument, cdw11},
+               {"human-readable", 'H', "FLAG", CFG_NONE,     &cfg.human_readable, no_argument,       human_readable},
+               {NULL}
+       };
+
+       fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+       if (fd < 0)
+               return fd;
+
+       if (cfg.sel > 7) {
+               fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
+               close(fd);
+               return EINVAL;
+       }
+       if (!cfg.feature_id) {
+               fprintf(stderr, "feature-id required param\n");
+               close(fd);
+               return EINVAL;
+       }
+       if (cfg.data_len) {
+               if (posix_memalign(&buf, getpagesize(), cfg.data_len))
+               {
+                       close(fd);
+                       exit(ENOMEM);
+               }
+               memset(buf, 0, cfg.data_len);
+       }
+
+       err = nvme_get_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.sel, cfg.cdw11,
+                       cfg.data_len, buf, &result);
+       if (!err) {
+               printf("get-feature:0x%02x (%s), %s value: %#08x\n", cfg.feature_id,
+                               nvme_feature_to_string(cfg.feature_id),
+                               nvme_select_to_string(cfg.sel), result);
+               if (cfg.human_readable)
+                       nvme_feature_show_fields(cfg.feature_id, result, buf);
+               else {
+                       if (buf) {
+                               if (!cfg.raw_binary)
+                                       d(buf, cfg.data_len, 16, 1);
+                               else
+                                       d_raw(buf, cfg.data_len);
+                       }
+               }
+       } else if (err > 0)
+               fprintf(stderr, "NVMe Status:%s(%x)\n",
+                               nvme_status_to_string(err), err);
+       if (buf)
+               free(buf);
+       return err;
+}
+
+static int set_additional_feature(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       const char *desc = "Modify the saveable or changeable "\
+               "current operating parameters of the controller. Operating "\
+               "parameters are grouped and identified by Feature "\
+               "Identifiers. Feature settings can be applied to the entire "\
+               "controller and all associated namespaces, or to only a few "\
+               "namespace(s) associated with the controller. Default values "\
+               "for each Feature are vendor-specific and may not be modified."\
+               "Use get-feature to determine which Features are supported by "\
+               "the controller and are saveable/changeable.\n\n"\
+               "Available additional feature id:\n"\
+               "0x02:  Shannon power management\n";
+       const char *namespace_id = "desired namespace";
+       const char *feature_id = "hex feature name (required)";
+       const char *data_len = "buffer length if data required";
+       const char *data = "optional file for feature data (default stdin)";
+       const char *value = "new value of feature (required)";
+       const char *save = "specifies that the controller shall save the attribute";
+       int err, fd;
+       __u32 result;
+       void *buf = NULL;
+       int ffd = STDIN_FILENO;
+
+       struct config {
+               char *file;
+               __u32 namespace_id;
+               __u32 feature_id;
+               __u32 value;
+               __u32 data_len;
+               int   save;
+       };
+
+       struct config cfg = {
+               .file         = "",
+               .namespace_id = 0,
+               .feature_id   = 0,
+               .value        = 0,
+               .data_len     = 0,
+               .save         = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", 'n', "NUM",  CFG_POSITIVE, &cfg.namespace_id, required_argument, namespace_id},
+               {"feature-id",   'f', "NUM",  CFG_POSITIVE, &cfg.feature_id,   required_argument, feature_id},
+               {"value",        'v', "NUM",  CFG_POSITIVE, &cfg.value,        required_argument, value},
+               {"data-len",     'l', "NUM",  CFG_POSITIVE, &cfg.data_len,     required_argument, data_len},
+               {"data",         'd', "FILE", CFG_STRING,   &cfg.file,         required_argument, data},
+               {"save",         's', "FLAG", CFG_NONE,     &cfg.save,         no_argument, save},
+               {NULL}
+       };
+
+       fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+       if (fd < 0)
+               return fd;
+
+       if (!cfg.feature_id) {
+               fprintf(stderr, "feature-id required param\n");
+               close(fd);
+               return EINVAL;
+       }
+
+       if (cfg.data_len) {
+               if (posix_memalign(&buf, getpagesize(), cfg.data_len)){
+                       fprintf(stderr, "can not allocate feature payload\n");
+                       close(fd);
+                       return ENOMEM;
+               }
+               memset(buf, 0, cfg.data_len);
+       }
+
+       if (buf) {
+               if (strlen(cfg.file)) {
+                       ffd = open(cfg.file, O_RDONLY);
+                       if (ffd <= 0) {
+                               fprintf(stderr, "no firmware file provided\n");
+                               err = EINVAL;
+                               goto free;
+                       }
+               }
+               err = read(ffd, (void *)buf, cfg.data_len);
+               if (err < 0) {
+                       fprintf(stderr, "failed to read data buffer from input file\n");
+                       err = EINVAL;
+                       goto free;
+               }
+       }
+
+       err = nvme_set_feature(fd, cfg.namespace_id, cfg.feature_id, cfg.value,
+                               0, cfg.save, cfg.data_len, buf, &result);
+       if (err < 0) {
+               perror("set-feature");
+               goto free;
+       }
+       if (!err) {
+               printf("set-feature:%02x (%s), value:%#08x\n", cfg.feature_id,
+                       nvme_feature_to_string(cfg.feature_id), cfg.value);
+               if (buf)
+                       d(buf, cfg.data_len, 16, 1);
+       } else if (err > 0)
+               fprintf(stderr, "NVMe Status:%s(%x)\n",
+                               nvme_status_to_string(err), err);
+
+free:
+       if (buf)
+               free(buf);
+       return err;
+}
+
+static int shannon_id_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       return __id_ctrl(argc, argv, cmd, plugin, NULL);
+}
+
+
+
diff --git a/plugins/shannon/shannon-nvme.h b/plugins/shannon/shannon-nvme.h
new file mode 100644 (file)
index 0000000..d40732e
--- /dev/null
@@ -0,0 +1,20 @@
+#undef CMD_INC_FILE
+#define CMD_INC_FILE plugins/shannon/shannon-nvme
+
+#if !defined(SHANNON_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define SHANNON_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("shannon", "Shannon vendor specific extensions"),
+       COMMAND_LIST(
+               ENTRY("smart-log-add", "Retrieve Shannon SMART Log, show it", get_additional_smart_log)
+               ENTRY("get-feature-add", "Get Shannon feature and show the resulting value", get_additional_feature)
+               ENTRY("set-feature-add", "Set a Shannon feature and show the resulting value", set_additional_feature)
+               ENTRY("id-ctrl", "Shannon NVMe Identify Controller", shannon_id_ctrl)
+       )
+);
+
+#endif
+
+#include "define_cmd.h"