]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
Update effects-log to handle multiple command sets
authorAndreas Hindborg <andreas.hindborg@wdc.com>
Thu, 9 Sep 2021 07:27:25 +0000 (07:27 +0000)
committerKeith Busch <kbusch@kernel.org>
Wed, 6 Oct 2021 11:05:23 +0000 (05:05 -0600)
This patch updates the effects-log command to correctly handle multiple
supported command sets. As each command set is allowed to support a distinct
subset of commands, the log page must to be reported for each command set.

Signed-off-by: Andreas Hindborg <andreas.hindborg@wdc.com>
Makefile
nvme-print.c
nvme-print.h
nvme.c

index 5fbdfd0bf697e37fabfb7f4bdf3923e754d121f5..2e43862f6fc9e9ab509af8bef79b4fd80fce8339 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -62,7 +62,7 @@ default: $(NVME)
 NVME-VERSION-FILE: FORCE
        @$(SHELL_PATH) ./NVME-VERSION-GEN
 -include NVME-VERSION-FILE
-override CFLAGS += -DNVME_VERSION='"$(NVME_VERSION)"' -I$(LIBNVMEDIR)src/
+override CFLAGS += -DNVME_VERSION='"$(NVME_VERSION)"' -I$(LIBNVMEDIR)src/ -I$(LIBNVMEDIR)/ccan
 
 NVME_DPKG_VERSION=1~`lsb_release -sc`
 
index af00a0bfbd5400ae6f75d4f3cbaf3298b1421de3..4fdcecbee5586e36d7fe8f2bfbfc3cc59859a7a3 100644 (file)
@@ -807,7 +807,8 @@ add:
        json_free_object(root);
 }
 
-static void json_effects_log(struct nvme_cmd_effects_log *effects_log)
+struct json_object* json_effects_log(enum nvme_csi csi,
+                            struct nvme_cmd_effects_log *effects_log)
 {
        struct json_object *root;
        struct json_object *acs;
@@ -817,6 +818,8 @@ static void json_effects_log(struct nvme_cmd_effects_log *effects_log)
        __u32 effect;
 
        root = json_create_object();
+       json_object_add_value_uint(root, "command_set_identifier", csi);
+
        acs = json_create_object();
        for (opcode = 0; opcode < 256; opcode++) {
                effect = le32_to_cpu(effects_log->acs[opcode]);
@@ -840,9 +843,24 @@ static void json_effects_log(struct nvme_cmd_effects_log *effects_log)
        }
 
        json_object_add_value_object(root, "io_cmd_set", iocs);
-       json_print_object(root, NULL);
+       return root;
+}
+
+void json_effects_log_list(struct list_head *list) {
+       struct json_object *json_list;
+       nvme_effects_log_node_t *node;
+
+       json_list = json_create_array();
+       
+       list_for_each(list, node, node) {
+               json_object *json_page =
+                       json_effects_log(node->csi, &node->effects);
+               json_array_add_value_object(json_list, json_page);
+       }
+
+       json_print_object(json_list, NULL);
        printf("\n");
-       json_free_object(root);
+       json_free_object(json_list);
 }
 
 static void json_sanitize_log(struct nvme_sanitize_log_page *sanitize_log,
@@ -4771,24 +4789,45 @@ void nvme_print_effects_log_segment(int admin, int a, int b, struct nvme_cmd_eff
        free(stream_location);
 }
 
-void nvme_print_effects_log_page(struct nvme_cmd_effects_log *effects, int flags) {
+void nvme_print_effects_log_page(enum nvme_csi csi, struct nvme_cmd_effects_log *effects, int flags) {
        int human = flags & VERBOSE;
 
+       switch (csi) {
+       case NVME_CSI_NVM:
+               printf("NVM Command Set Log Page\n");
+               printf("%-.80s\n", dash);
+               break;
+       case NVME_CSI_ZNS:
+               printf("ZNS Command Set Log Page\n");
+               printf("%-.80s\n", dash);
+               break;
+       default:
+               printf("Unknown Command Set Log Page\n");
+               printf("%-.80s\n", dash);
+               break;
+       }
+
        nvme_print_effects_log_segment(1, 0, 0xbf, effects, "Admin Commands", human);
        nvme_print_effects_log_segment(1, 0xc0, 0xff, effects, "Vendor Specific Admin Commands", human);
        nvme_print_effects_log_segment(0, 0, 0x80, effects, "I/O Commands", human);
        nvme_print_effects_log_segment(0, 0x80, 0x100, effects, "Vendor Specific I/O Commands", human);
 }
 
-void nvme_show_effects_log(struct nvme_cmd_effects_log *effects,
-                          unsigned int flags)
+void nvme_print_effects_log_pages(struct list_head *list,
+                          int flags)
 {
-       if (flags & BINARY)
-               return d_raw((unsigned char *)effects, sizeof(*effects));
-       else if (flags & JSON)
-               return json_effects_log(effects);
+       if (flags & JSON)
+               return json_effects_log_list(list);
 
-       nvme_print_effects_log_page(effects, flags);
+       nvme_effects_log_node_t *node;
+       list_for_each(list, node, node) {
+               if (flags & BINARY) {
+                       d_raw((unsigned char *)&node->effects, sizeof(node->effects));
+               }
+               else {
+                       nvme_print_effects_log_page(node->csi, &node->effects, flags);
+               }
+       }
 }
 
 uint64_t int48_to_long(__u8 *data)
index c3ba64ae7091147a038abe46bd87e3082d24e6e0..aa153e0fbaf946230dae27e41ca9f1b66bcb9fb5 100644 (file)
@@ -4,6 +4,14 @@
 #include "nvme.h"
 #include <inttypes.h>
 
+#include <ccan/list/list.h>
+
+typedef struct nvme_effects_log_node {
+       enum nvme_csi csi;
+       struct nvme_cmd_effects_log effects;
+       struct list_node node;
+} nvme_effects_log_node_t;
+
 void d(unsigned char *buf, int len, int width, int group);
 void d_raw(unsigned char *buf, unsigned len);
 uint64_t int48_to_long(__u8 *data);
@@ -31,7 +39,7 @@ void nvme_show_self_test_log(struct nvme_self_test_log *self_test, __u8 dst_entr
        __u32 size, const char *devname, enum nvme_print_flags flags);
 void nvme_show_fw_log(struct nvme_firmware_slot *fw_log, const char *devname,
        enum nvme_print_flags flags);
-void nvme_show_effects_log(struct nvme_cmd_effects_log *effects, unsigned int flags);
+void nvme_print_effects_log_pages(struct list_head *list, int flags);
 void nvme_show_changed_ns_list_log(struct nvme_ns_list *log,
        const char *devname, enum nvme_print_flags flags);
 void nvme_show_endurance_log(struct nvme_endurance_group_log *endurance_log,
diff --git a/nvme.c b/nvme.c
index e5b6d3bbea5a3f2e7c924503bbecbf98214e9055..bfb2cf11cd094bbb6b5d900201186261aebc17e4 100644 (file)
--- a/nvme.c
+++ b/nvme.c
@@ -24,6 +24,8 @@
  * This program uses NVMe IOCTLs to run native nvme commands to a device.
  */
 
+#include "nvme/tree.h"
+#include "nvme/types.h"
 #include <errno.h>
 #include <getopt.h>
 #include <fcntl.h>
@@ -85,8 +87,9 @@ static struct program nvme = {
 const char *output_format = "Output format: normal|json|binary";
 static const char *output_format_no_binary = "Output format: normal|json";
 
-static void *__nvme_alloc(size_t len, bool *huge)
-{
+static void *mmap_registers(nvme_root_t r, const char *dev);
+
+static void *__nvme_alloc(size_t len, bool *huge) {
        void *p;
 
        if (!posix_memalign(&p, getpagesize(), len)) {
@@ -489,30 +492,60 @@ ret:
        return nvme_status_to_errno(err, false);
 }
 
+void collect_effects_log(int fd, enum nvme_csi csi, struct list_head *list, int flags)
+{
+       int err;
+       nvme_effects_log_node_t *node = malloc(sizeof(nvme_effects_log_node_t));
+       if (!node) {
+               perror("Failed to allocate memory");
+               return;
+       }
+       node->csi = csi;
+
+       err = nvme_get_log_cmd_effects(fd, csi, &node->effects);
+       if (!err) {
+               list_add(list, &node->node);
+               return;
+       }
+       else if (err > 0)
+               nvme_show_status(err);
+       else
+               perror("effects log page");
+
+       free(node);
+}
+
 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.";
        const char *raw = "show log in binary format";
        const char *human_readable = "show log in readable format";
-       struct nvme_cmd_effects_log effects;
+       const char *csi = "";
+       struct list_head log_pages;
+       nvme_effects_log_node_t *node;
+
+       void *bar = NULL;
 
        int err = -1, fd;
        enum nvme_print_flags flags;
 
        struct config {
-               int   raw_binary;
-               int   human_readable;
-               char *output_format;
+               int      raw_binary;
+               int      human_readable;
+               char    *output_format;
+               int      csi;
        };
 
        struct config cfg = {
                .output_format = "normal",
+               .csi = -1,
        };
 
        OPT_ARGS(opts) = {
                OPT_FMT("output-format",  'o', &cfg.output_format,  output_format),
                OPT_FLAG("human-readable",'H', &cfg.human_readable, human_readable),
                OPT_FLAG("raw-binary",    'b', &cfg.raw_binary,     raw),
+               OPT_INT("csi",            'c', &cfg.csi,            csi),
                OPT_END()
        };
 
@@ -528,14 +561,49 @@ static int get_effects_log(int argc, char **argv, struct command *cmd, struct pl
        if (cfg.human_readable)
                flags |= VERBOSE;
 
-       err = nvme_get_log_cmd_effects(fd, NVME_CSI_NVM, &effects);
-       if (!err)
-               nvme_show_effects_log(&effects, flags);
-       else if (err > 0)
-               nvme_show_status(err);
-       else
-               perror("effects log page");
+       list_head_init(&log_pages);
+
+       if (cfg.csi < 0) {
+               nvme_root_t nvme_root;
+               uint64_t cap_value;
+               int nvme_command_set_supported;
+               int other_command_sets_supported;
+               nvme_root = nvme_scan(NULL);
+               bar = mmap_registers(nvme_root, devicename);
+               nvme_free_tree(nvme_root);
+
+               if (!bar) {
+                       goto close_fd;
+               }
+               cap_value = nvme_mmio_read64(bar + NVME_REG_CAP);
+               munmap(bar, getpagesize());
+
+               nvme_command_set_supported = (cap_value & (1UL << 37)) != 0;
+               other_command_sets_supported = (cap_value & (1UL << (37+6))) != 0;
+
+
+               if (nvme_command_set_supported) {
+                       collect_effects_log(fd, NVME_CSI_NVM, &log_pages, flags);
+               }
+
+               if (other_command_sets_supported) {
+                       collect_effects_log(fd, NVME_CSI_ZNS, &log_pages, flags);
+               }
+
+               nvme_print_effects_log_pages(&log_pages, flags);
+
+       }
+       else {
+               collect_effects_log(fd, cfg.csi, &log_pages, flags);
+               nvme_print_effects_log_pages(&log_pages, flags);
+       }
+
+
 close_fd:
+       while ((node = list_pop(&log_pages, nvme_effects_log_node_t, node))) {
+               free(node);
+       }
+
        close(fd);
 ret:
        return nvme_status_to_errno(err, false);