]> www.infradead.org Git - users/hch/nvme-cli.git/commitdiff
Add memblaze vendor specific SMART Log support
authorWenwei Tao <wenwei.tao@memblaze.com>
Fri, 1 Jul 2016 09:46:13 +0000 (17:46 +0800)
committerKeith Busch <keith.busch@intel.com>
Thu, 7 Jul 2016 14:58:44 +0000 (10:58 -0400)
Signed-off-by: Wenwei Tao <wenwei.tao@memblaze.com>
Makefile
memblaze-nvme.c [new file with mode: 0644]
memblaze-nvme.h [new file with mode: 0644]
nvme-print.c
nvme-print.h

index 47d3559732633919c5e28930aee48eaf44835974..dbcce3e290f68bfbe84db7783da9848bfda24822 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -32,7 +32,7 @@ NVME_DPKG_VERSION=1~`lsb_release -sc`
 
 OBJS := argconfig.o suffix.o parser.o nvme-print.o nvme-ioctl.o \
        nvme-lightnvm.o fabrics.o json.o plugin.o intel-nvme.o \
-       lnvm-nvme.o
+       lnvm-nvme.o memblaze-nvme.o
 
 nvme: nvme.c nvme.h $(OBJS) NVME-VERSION-FILE
        $(CC) $(CPPFLAGS) $(CFLAGS) nvme.c $(LDFLAGS) -o $(NVME) $(OBJS)
diff --git a/memblaze-nvme.c b/memblaze-nvme.c
new file mode 100644 (file)
index 0000000..8496b56
--- /dev/null
@@ -0,0 +1,172 @@
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/fs.h>
+
+#include "linux/nvme_ioctl.h"
+
+#include "nvme.h"
+#include "nvme-print.h"
+#include "nvme-ioctl.h"
+#include "plugin.h"
+
+#include "argconfig.h"
+#include "suffix.h"
+
+#define CREATE_CMD
+#include "memblaze-nvme.h"
+
+enum {
+       TOTAL_WRITE,
+       TOTAL_READ,
+       THERMAL_THROTTLE,
+       TEMPT_SINCE_RESET,
+       POWER_CONSUMPTION,
+       TEMPT_SINCE_BOOTUP,
+       NR_SMART_ITEMS,
+};
+
+#pragma pack(push, 1)
+struct nvme_memblaze_smart_log_item {
+       __u8 id[3];
+       __u8 nmval[2];
+       union {
+               __u8 rawval[6];
+               struct temperature {
+                       __le16 max;
+                       __le16 min;
+                       __le16 curr;
+               } temperature;
+               struct power {
+                       __le16 max;
+                       __le16 min;
+                       __le16 curr;
+               } power;
+               struct thermal_throttle_mb {
+                       __u8 on;
+                       __u32 count;
+               } thermal_throttle;
+               struct temperature_p {
+                       __le16 max;
+                       __le16 min;
+               } temperature_p;
+       };
+       __u8 resv;
+};
+#pragma pack(pop)
+
+struct nvme_memblaze_smart_log {
+       struct nvme_memblaze_smart_log_item items[NR_SMART_ITEMS];
+       __u8 resv[512 - sizeof(struct nvme_memblaze_smart_log_item) * NR_SMART_ITEMS];
+};
+
+/*
+ * Return -1 if @fw1 < @fw2
+ * Return 0 if @fw1 == @fw2
+ * Return 1 if @fw1 > @fw2
+ */
+static int compare_fw_version(const char *fw1, const char *fw2)
+{
+       while (*fw1 != '\0') {
+               if (*fw2 == '\0' || *fw1 > *fw2)
+                       return 1;
+               if (*fw1 < *fw2)
+                       return -1;
+               fw1++;
+               fw2++;
+       }
+
+       if (*fw2 != '\0')
+               return -1;
+
+       return 0;
+}
+
+static int show_memblaze_smart_log(int fd, __u32 nsid, const char *devname,
+               struct nvme_memblaze_smart_log *smart)
+{
+       struct nvme_id_ctrl ctrl;
+       char fw_ver[10];
+       int err = 0;
+
+       err = nvme_identify_ctrl(fd, &ctrl);
+       if (err)
+               return err;
+       snprintf(fw_ver, sizeof(fw_ver), "%c.%c%c.%c%c%c%c",
+               ctrl.fr[0], ctrl.fr[1], ctrl.fr[2], ctrl.fr[3],
+               ctrl.fr[4], ctrl.fr[5], ctrl.fr[6]);
+
+       printf("Additional Smart Log for NVME device:%s namespace-id:%x\n", devname, nsid);
+
+       printf("Total write in GB since last factory reset                      : %lu\n",
+               int48_to_long(smart->items[TOTAL_WRITE].rawval));
+       printf("Total read in GB since last factory reset                       : %lu\n",
+               int48_to_long(smart->items[TOTAL_READ].rawval));
+
+       printf("Thermal throttling status[1:HTP in progress]                    : %u\n",
+               smart->items[THERMAL_THROTTLE].thermal_throttle.on);
+       printf("Total thermal throttling minutes since power on                 : %u\n",
+               smart->items[THERMAL_THROTTLE].thermal_throttle.count);
+
+       printf("Maximum temperature in Kelvin since last factory reset          : %u\n",
+               le16toh(smart->items[TEMPT_SINCE_RESET].temperature.max));
+       printf("Minimum temperature in Kelvin since last factory reset          : %u\n",
+               le16toh(smart->items[TEMPT_SINCE_RESET].temperature.min));
+       if (compare_fw_version(fw_ver, "0.09.0300") != 0) {
+               printf("Maximum temperature in Kelvin since power on                    : %u\n",
+                       le16toh(smart->items[TEMPT_SINCE_BOOTUP].temperature_p.max));
+               printf("Minimum temperature in Kelvin since power on                    : %u\n",
+                       le16toh(smart->items[TEMPT_SINCE_BOOTUP].temperature_p.min));
+       }
+       printf("Current temperature in Kelvin                                   : %u\n",
+               le16toh(smart->items[TEMPT_SINCE_RESET].temperature.curr));
+
+       printf("Maximum power in watt since power on                            : %u\n",
+               le16toh(smart->items[POWER_CONSUMPTION].power.max));
+       printf("Minimum power in watt since power on                            : %u\n",
+               le16toh(smart->items[POWER_CONSUMPTION].power.min));
+       printf("Current power in watt                                           : %u\n",
+               le16toh(smart->items[POWER_CONSUMPTION].power.curr));
+
+       return err;
+}
+
+static int get_additional_smart_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       struct nvme_memblaze_smart_log smart_log;
+       int err, fd;
+       char *desc = "Get Memblaze 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 = 0xffffffff,
+       };
+
+       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},
+               {0}
+       };
+
+       fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+
+       err = nvme_get_log(fd, cfg.namespace_id, 0xca, sizeof(smart_log), &smart_log);
+       if (!err) {
+               if (!cfg.raw_binary)
+                       err = show_memblaze_smart_log(fd, cfg.namespace_id, devicename, &smart_log);
+               else
+                       d_raw((unsigned char *)&smart_log, sizeof(smart_log));
+       }
+       if (err > 0)
+               fprintf(stderr, "NVMe Status:%s(%x)\n", nvme_status_to_string(err), err);
+
+       return err;
+}
diff --git a/memblaze-nvme.h b/memblaze-nvme.h
new file mode 100644 (file)
index 0000000..f921df4
--- /dev/null
@@ -0,0 +1,17 @@
+#undef CMD_INC_FILE
+#define CMD_INC_FILE memblaze-nvme
+
+#if !defined(MEMBLAZE_NVME) || defined(CMD_HEADER_MULTI_READ)
+#define MEMBLAZE_NVME
+
+#include "cmd.h"
+
+PLUGIN(NAME("memblaze", "Memblaze vendor specific extensions"),
+       COMMAND_LIST(
+               ENTRY("smart-log-add", "Retrieve Memblaze SMART Log, show it", get_additional_smart_log)
+       )
+);
+
+#endif
+
+#include "define_cmd.h"
index 9a3673fd1a85c166354f12f76806a702e8658fdd..a0247685f039618d4f80ae6949f022aef381d1e4 100644 (file)
@@ -738,7 +738,7 @@ void show_fw_log(struct nvme_firmware_log_page *fw_log, const char *devname)
                                                fw_to_string(fw_log->frs[i]));
 }
 
-static unsigned long int48_to_long(__u8 *data)
+unsigned long int48_to_long(__u8 *data)
 {
        int i;
        long result = 0;
index a38f15f859f0222cf56dd3819f91fa70c17461b6..5dd0eab90f77e07f3e273dc870c30908330a18a4 100644 (file)
@@ -13,6 +13,8 @@ enum {
 void d(unsigned char *buf, int len, int width, int group);
 void d_raw(unsigned char *buf, unsigned len);
 
+unsigned long int48_to_long(__u8 *data);
+
 void __show_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode, void (*vendor_show)(__u8 *vs));
 void show_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, unsigned int mode);
 void show_nvme_id_ns(struct nvme_id_ns *ns, unsigned int flags);