]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
Add support for NVMe Sets log page
authorKeith Busch <keith.busch@gmail.com>
Sat, 17 Feb 2018 18:09:01 +0000 (11:09 -0700)
committerKeith Busch <keith.busch@gmail.com>
Sun, 18 Feb 2018 17:43:09 +0000 (10:43 -0700)
Implemented from ratified TP4018

Signed-off-by: Keith Busch <keith.busch@gmail.com>
linux/nvme.h
nvme-builtin.h
nvme-ioctl.c
nvme-ioctl.h
nvme-print.c
nvme-print.h
nvme.c

index 127d63678bb7df334598753c43df853ae1067d08..437b92d3d1441841668b5e204f442464dd1287e6 100644 (file)
@@ -405,6 +405,18 @@ struct nvme_telemetry_log_page_hdr {
        __u8    telemetry_dataarea[0];
 };
 
+struct nvme_endurance_group_log {
+       __u32   rsvd0;
+       __u8    avl_spare_threshold;
+       __u8    percent_used;
+       __u8    rsvd6[26];
+       __u8    endurance_estimate[16];
+       __u8    data_units_read[16];
+       __u8    data_units_written[16];
+       __u8    media_units_written[16];
+       __u8    rsvd96[416];
+};
+
 struct nvme_smart_log {
        __u8                    critical_warning;
        __u8                    temperature[2];
@@ -813,6 +825,7 @@ enum {
        NVME_LOG_CMD_EFFECTS    = 0x05,
        NVME_LOG_TELEMETRY_HOST = 0x07,
        NVME_LOG_TELEMETRY_CTRL = 0x08,
+       NVME_LOG_ENDURANCE_GROUP = 0x09,
        NVME_LOG_DISC           = 0x70,
        NVME_LOG_RESERVATION    = 0x80,
        NVME_LOG_SANITIZE       = 0x81,
index f745e33a2072e2bd7c919222381760ec4ac84b19..75055c330fd0483cd465e3d1834297b6364e5763 100644 (file)
@@ -25,6 +25,7 @@ COMMAND_LIST(
        ENTRY("smart-log", "Retrieve SMART Log, show it", get_smart_log)
        ENTRY("error-log", "Retrieve Error Log, show it", get_error_log)
        ENTRY("effects-log", "Retrieve Command Effects Log, show it", get_effects_log)
+       ENTRY("endurance-log", "Retrieve Endurance Group Log, show it", get_endurance_log)
        ENTRY("get-feature", "Get feature and show the resulting value", get_feature)
        ENTRY("set-feature", "Set a feature and show the resulting value", set_feature)
        ENTRY("set-property", "Set a property and show the resulting value", set_property)
index 770ff8c15229bb8964060eec1e25fb814f7c4208..d17d702fc2ff5483fc2fbb9fb2df8f29cedb7f0f 100644 (file)
@@ -382,7 +382,7 @@ int nvme_identify_ns_descs(int fd, __u32 nsid, void *data)
 }
 
 int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
-                 __u32 data_len, void *data)
+                 __u16 lsi, __u32 data_len, void *data)
 {
        struct nvme_admin_cmd cmd = {
                .opcode         = nvme_admin_get_log_page,
@@ -397,7 +397,7 @@ int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
        if (lsp)
                 cmd.cdw10 |= lsp << 8;
 
-       cmd.cdw11 = numdu;
+       cmd.cdw11 = numdu | (lsi << 16);
        cmd.cdw12 = lpo;
        cmd.cdw13 = (lpo >> 32);
 
@@ -408,7 +408,7 @@ int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
 int nvme_get_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data)
 {
        return nvme_get_log13(fd, nsid, log_id, NVME_NO_LOG_LSP, NVME_NO_LOG_LPO,
-                             data_len, data);
+                             0, data_len, data);
 }
 
 int nvme_get_telemetry_log(int fd, void *lp, int generate_report,
@@ -417,15 +417,15 @@ int nvme_get_telemetry_log(int fd, void *lp, int generate_report,
        if (ctrl_init)
                return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_CTRL,
                                      NVME_NO_LOG_LSP, offset,
-                                     log_page_size, lp);
+                                     0, log_page_size, lp);
        if (generate_report)
                return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_HOST,
                                      NVME_TELEM_LSP_CREATE, offset,
-                                     log_page_size, lp);
+                                     0, log_page_size, lp);
        else
                return nvme_get_log13(fd, NVME_NSID_ALL, NVME_LOG_TELEMETRY_HOST,
                                      NVME_NO_LOG_LSP, offset,
-                                     log_page_size, lp);
+                                     0, log_page_size, lp);
 }
 
 int nvme_fw_log(int fd, struct nvme_firmware_log_page *fw_log)
@@ -438,6 +438,12 @@ int nvme_error_log(int fd, int entries, struct nvme_error_log_page *err_log)
        return nvme_get_log(fd, NVME_NSID_ALL, NVME_LOG_ERROR, entries * sizeof(*err_log), err_log);
 }
 
+int nvme_endurance_log(int fd, __u16 group_id, struct nvme_endurance_group_log *endurance_log)
+{
+       return nvme_get_log13(fd, 0, NVME_LOG_ENDURANCE_GROUP, 0, 0, group_id,
+                       sizeof(*endurance_log), endurance_log);
+}
+
 int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log)
 {
        return nvme_get_log(fd, nsid, NVME_LOG_SMART, sizeof(*smart_log), smart_log);
index 69a303b2744baa68832f792c981961ee547b3446..954a9929d5fac2f56c1501fad48008622f35947f 100644 (file)
@@ -79,7 +79,7 @@ int nvme_identify_ns_list(int fd, __u32 nsid, bool all, void *data);
 int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data);
 int nvme_identify_ns_descs(int fd, __u32 nsid, void *data);
 int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo,
-                  __u32 data_len, void *data);
+                  __u16 group_id, __u32 data_len, void *data);
 int nvme_get_log(int fd, __u32 nsid, __u8 log_id, __u32 data_len, void *data);
 
 
@@ -91,6 +91,8 @@ int nvme_smart_log(int fd, __u32 nsid, struct nvme_smart_log *smart_log);
 int nvme_effects_log(int fd, struct nvme_effects_log_page *effects_log);
 int nvme_discovery_log(int fd, struct nvmf_disc_rsp_page_hdr *log, __u32 size);
 int nvme_sanitize_log(int fd, struct nvme_sanitize_log_page *sanitize_log);
+int nvme_endurance_log(int fd, __u16 group_id,
+                      struct nvme_endurance_group_log *endurance_log);
 
 int nvme_feature(int fd, __u8 opcode, __u32 nsid, __u32 cdw10,
                 __u32 cdw11, __u32 cdw12, __u32 data_len, void *data,
index e729a3c967d2c7421bc8c567232352bb4cb3a4a0..eeb952fabb29965f05cbf3a5c9933533b31cd7b2 100644 (file)
@@ -1157,6 +1157,22 @@ uint64_t int48_to_long(__u8 *data)
        return result;
 }
 
+void show_endurance_log(struct nvme_endurance_group_log *endurance_group,
+                       __u16 group_id, const char *devname)
+{
+       printf("Endurance Group Log for NVME device:%s Group ID:%x\n", devname, group_id);
+       printf("avl_spare_threshold   : %u\n", endurance_group->avl_spare_threshold);
+       printf("percent_used          : %u%%\n", endurance_group->percent_used);
+       printf("endurance_estimate    : %'.0Lf\n",
+               int128_to_double(endurance_group->endurance_estimate));
+       printf("data_units_read       : %'.0Lf\n",
+               int128_to_double(endurance_group->data_units_read));
+       printf("data_units_written    : %'.0Lf\n",
+               int128_to_double(endurance_group->data_units_written));
+       printf("media_units_written   : %'.0Lf\n",
+               int128_to_double(endurance_group->media_units_written));
+}
+
 void show_smart_log(struct nvme_smart_log *smart, unsigned int nsid, const char *devname)
 {
        /* convert temperature from Kelvin to Celsius */
@@ -2079,6 +2095,30 @@ void json_fw_log(struct nvme_firmware_log_page *fw_log, const char *devname)
        json_free_object(root);
 }
 
+void json_endurance_log(struct nvme_endurance_group_log *endurance_group,
+                       __u16 group_id, const char *devname)
+{
+       struct json_object *root;
+
+       long double endurance_estimate= int128_to_double(endurance_group->endurance_estimate);
+       long double data_units_read= int128_to_double(endurance_group->data_units_read);
+       long double data_units_written= int128_to_double(endurance_group->data_units_written);
+       long double media_units_written= int128_to_double(endurance_group->media_units_written);
+
+       root = json_create_object();
+
+       json_object_add_value_int(root, "avl_spare_threshold", endurance_group->avl_spare_threshold);
+       json_object_add_value_int(root, "percent_used", endurance_group->percent_used);
+       json_object_add_value_float(root, "endurance_estimate", endurance_estimate);
+       json_object_add_value_float(root, "data_units_read", data_units_read);
+       json_object_add_value_float(root, "data_units_written", data_units_written);
+       json_object_add_value_float(root, "mediate_write_commands", media_units_written);
+
+       json_print_object(root, NULL);
+       printf("\n");
+       json_free_object(root);
+}
+
 void json_smart_log(struct nvme_smart_log *smart, unsigned int nsid, const char *devname)
 {
        struct json_object *root;
index 748f6d0341bbc4eef37546049343502b83cd9252..3372b28ee3f4b4eeb50b10d3719390740ff688df 100644 (file)
@@ -26,6 +26,8 @@ void show_error_log(struct nvme_error_log_page *err_log, int entries, const char
 void show_smart_log(struct nvme_smart_log *smart, unsigned int nsid, const char *devname);
 void show_fw_log(struct nvme_firmware_log_page *fw_log, const char *devname);
 void show_effects_log(struct nvme_effects_log_page *effects, unsigned int flags);
+void show_endurance_log(struct nvme_endurance_group_log *endurance_group,
+                       __u16 group_id, const char *devname);
 void show_sanitize_log(struct nvme_sanitize_log_page *sanitize, unsigned int mode, const char *devname);
 void show_ctrl_registers(void *bar, unsigned int mode, bool fabrics);
 void show_nvme_id_ns_descs(void *data);
@@ -47,6 +49,8 @@ void json_smart_log(struct nvme_smart_log *smart, unsigned int nsid, const char
 void json_effects_log(struct nvme_effects_log_page *effects_log, const char *devname);
 void json_sanitize_log(struct nvme_sanitize_log_page *sanitize_log, const char *devname);
 void json_fw_log(struct nvme_firmware_log_page *fw_log, const char *devname);
+void json_endurance_log(struct nvme_endurance_group_log *endurance_group,
+                       __u16 group_id, const char *devname);
 void json_print_list_items(struct list_item *items, unsigned amnt);
 void json_nvme_id_ns_descs(void *data);
 void json_print_nvme_subsystem_list(struct subsys_list_item *slist, int n);
diff --git a/nvme.c b/nvme.c
index fad7fcc056f540e1a73c46297de58b143db5680b..d460fb766dbcce51eb66929131167e926216e127 100644 (file)
--- a/nvme.c
+++ b/nvme.c
@@ -341,6 +341,57 @@ static int get_telemetry_log(int argc, char **argv, struct command *cmd, struct
        return err;
 }
 
+static int get_endurance_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
+{
+       struct nvme_endurance_group_log endurance_log;
+
+       const char *desc = "Retrieves endurance groups log page and prints the log.";
+       const char *group_id = "The endurance group identifier";
+
+       int err, fd;
+       int fmt;
+
+       struct config {
+               char *output_format;
+               __u16 group_id;
+       };
+
+       struct config cfg = {
+               .output_format = "normal",
+               .group_id = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"output-format", 'o', "FMT", CFG_STRING, &cfg.output_format, required_argument, output_format},
+               {"group-id",      'g', "NUM", CFG_SHORT,  &cfg.group_id,      required_argument, group_id},
+       };
+
+       fd = parse_and_open(argc, argv, desc, command_line_options, &cfg, sizeof(cfg));
+       if (fd < 0)
+               return fd;
+
+       fmt = validate_output_format(cfg.output_format);
+       if (fmt < 0)
+               return fmt;
+
+       err = nvme_endurance_log(fd, cfg.group_id, &endurance_log);
+       if (!err) {
+               if (fmt == BINARY)
+                       d_raw((unsigned char *)&endurance_log, sizeof(endurance_log));
+               else if (fmt == JSON)
+                       json_endurance_log(&endurance_log, cfg.group_id, devicename);
+               else
+                       show_endurance_log(&endurance_log, cfg.group_id, devicename);
+       } else if (err > 0)
+               fprintf(stderr, "NVMe Status:%s(%x)\n",
+                                       nvme_status_to_string(err), err);
+       else
+               perror("endurance log");
+
+       close(fd);
+       return err;
+}
+
 static int get_effects_log(int argc, char **argv, struct command *cmd, struct plugin *plugin)
 {
        const char *desc = "Retrieve command effects log page and print the table.";
@@ -610,7 +661,7 @@ static int get_log(int argc, char **argv, struct command *cmd, struct plugin *pl
                }
 
                err = nvme_get_log13(fd, cfg.namespace_id, cfg.log_id,
-                                    cfg.lsp, cfg.lpo,
+                                    cfg.lsp, cfg.lpo, 0,
                                     cfg.log_len, log);
                if (!err) {
                        if (!cfg.raw_binary) {