From 1f1337939e8ac7673310e7101ee44ed5cd2c49d9 Mon Sep 17 00:00:00 2001 From: Kenneth Heitke Date: Wed, 24 Apr 2019 17:32:20 -0600 Subject: [PATCH] nvme-cli: add identify secondary controller list Signed-off-by: Kenneth Heitke --- linux/nvme.h | 1 + nvme-builtin.h | 1 + nvme-ioctl.c | 5 ++++ nvme-ioctl.h | 1 + nvme-print.c | 64 +++++++++++++++++++++++++++++++++++++++++ nvme-print.h | 3 +- nvme.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ nvme.h | 17 +++++++++++ 8 files changed, 169 insertions(+), 1 deletion(-) diff --git a/linux/nvme.h b/linux/nvme.h index 68000eb8..a1422a77 100644 --- a/linux/nvme.h +++ b/linux/nvme.h @@ -355,6 +355,7 @@ enum { NVME_ID_CNS_NS_PRESENT = 0x11, NVME_ID_CNS_CTRL_NS_LIST = 0x12, NVME_ID_CNS_CTRL_LIST = 0x13, + NVME_ID_CNS_SCNDRY_CTRL_LIST = 0x15, }; enum { diff --git a/nvme-builtin.h b/nvme-builtin.h index 2eb34cba..a203a5c0 100644 --- a/nvme-builtin.h +++ b/nvme-builtin.h @@ -68,6 +68,7 @@ COMMAND_LIST( ENTRY("dir-receive", "Submit a Directive Receive command, return results", dir_receive) ENTRY("dir-send", "Submit a Directive Send command, return results", dir_send) ENTRY("virt-mgmt", "Manage Flexible Resources between Primary and Secondary Controller ", virtual_mgmt) + ENTRY("list-secondary", "List Secondary Controllers associated with a Primary Controller", list_secondary_ctrl) ); #endif diff --git a/nvme-ioctl.c b/nvme-ioctl.c index 75bf9fad..83740f22 100644 --- a/nvme-ioctl.c +++ b/nvme-ioctl.c @@ -370,6 +370,11 @@ int nvme_identify_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data) return nvme_identify(fd, nsid, (cntid << 16) | cns, data); } +int nvme_identify_secondary_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data) +{ + return nvme_identify(fd, nsid, (cntid << 16) | NVME_ID_CNS_SCNDRY_CTRL_LIST, data); +} + int nvme_identify_ns_descs(int fd, __u32 nsid, void *data) { diff --git a/nvme-ioctl.h b/nvme-ioctl.h index c82149c7..f4553e0b 100644 --- a/nvme-ioctl.h +++ b/nvme-ioctl.h @@ -75,6 +75,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_identify_nvmset(int fd, __u16 nvmset_id, void *data); +int nvme_identify_secondary_ctrl_list(int fd, __u32 nsid, __u16 cntid, void *data); int nvme_get_log13(int fd, __u32 nsid, __u8 log_id, __u8 lsp, __u64 lpo, __u16 group_id, bool rae, __u32 data_len, void *data); int nvme_get_log(int fd, __u32 nsid, __u8 log_id, bool rae, diff --git a/nvme-print.c b/nvme-print.c index 8b01c08a..5ef29323 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -7,6 +7,7 @@ #include "json.h" #include "nvme-models.h" #include "suffix.h" +#include "common.h" static const char *nvme_ana_state_to_string(enum nvme_ana_state state) { @@ -1144,6 +1145,69 @@ void json_nvme_id_nvmset(struct nvme_id_nvmset *nvmset, const char *devname) json_free_object(root); } +void show_nvme_list_secondary_ctrl(const struct nvme_secondary_controllers_list *sc_list, __u32 count) +{ + int i; + __u16 num = le16_to_cpu(sc_list->num); + __u32 entries = min(num, count); + + static const char * const state_desc[] = { "Offline", "Online" }; + const struct nvme_secondary_controller_entry *sc_entry = &sc_list->sc_entry[0]; + + printf("Identify Secondary Controller List:\n"); + printf(" NUMID : Number of Identifiers : %d\n", num); + + for (i = 0; i < entries; i++) { + printf(" SCEntry[%-3d]:\n", i); + printf("................\n"); + printf(" SCID : Secondary Controller Identifier : 0x%.04x\n", + le16_to_cpu(sc_entry[i].scid)); + printf(" PCID : Primary Controller Identifier : 0x%.04x\n", + le16_to_cpu(sc_entry[i].pcid)); + printf(" SCS : Secondary Controller State : 0x%.04x (%s)\n", + le16_to_cpu(sc_entry[i].scs), + state_desc[le16_to_cpu(sc_entry[i].scs) & 0x1]); + printf(" VFN : Virtual Function Number : 0x%.04x\n", + le16_to_cpu(sc_entry[i].vfn)); + printf(" NVQ : Num VQ Flex Resources Assigned : 0x%.04x\n", + le16_to_cpu(sc_entry[i].nvq)); + printf(" NVI : Num VI Flex Resources Assigned : 0x%.04x\n", + le16_to_cpu(sc_entry[i].nvi)); + } +} + +void json_nvme_list_secondary_ctrl(const struct nvme_secondary_controllers_list *sc_list, __u32 count) +{ + int i; + struct json_object *root; + struct json_array *entries; + __u32 nent = min(le16_to_cpu(sc_list->num), count); + const struct nvme_secondary_controller_entry *sc_entry = &sc_list->sc_entry[0]; + + root = json_create_object(); + + json_object_add_value_int(root, "num", nent); + + entries = json_create_array(); + for (i = 0; i < nent; i++) { + struct json_object *entry = json_create_object(); + + json_object_add_value_int(entry, "secondary-controller-identifier", le16_to_cpu(sc_entry[i].scid)); + json_object_add_value_int(entry, "primary-controller-identifier", le16_to_cpu(sc_entry[i].pcid)); + json_object_add_value_int(entry, "secondary-controller-state", le16_to_cpu(sc_entry[i].scs)); + json_object_add_value_int(entry, "virtual-function-number", le16_to_cpu(sc_entry[i].vfn)); + json_object_add_value_int(entry, "num-virtual-queues", le16_to_cpu(sc_entry[i].nvq)); + json_object_add_value_int(entry, "num-virtual-interrupts", le16_to_cpu(sc_entry[i].nvi)); + json_array_add_value_object(entries, entry); + } + + json_object_add_value_array(root, "secondary-controllers", entries); + + json_print_object(root, NULL); + printf("\n"); + json_free_object(root); +} + void show_error_log(struct nvme_error_log_page *err_log, int entries, const char *devname) { int i; diff --git a/nvme-print.h b/nvme-print.h index e4dc9187..4c2af7b5 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -38,6 +38,7 @@ void show_nvme_id_ns_descs(void *data); void show_list_items(struct list_item *list_items, unsigned len); void show_nvme_subsystem_list(struct subsys_list_item *slist, int n); void show_nvme_id_nvmset(struct nvme_id_nvmset *nvmset); +void show_nvme_list_secondary_ctrl(const struct nvme_secondary_controllers_list *sc_list, __u32 count); void nvme_feature_show_fields(__u32 fid, unsigned int result, unsigned char *buf); void nvme_directive_show_fields(__u8 dtype, __u8 doper, unsigned int result, unsigned char *buf); @@ -65,6 +66,6 @@ void json_print_nvme_subsystem_list(struct subsys_list_item *slist, int n); void json_self_test_log(struct nvme_self_test_log *self_test, const char *devname); void json_nvme_id_nvmset(struct nvme_id_nvmset *nvmset, const char *devname); void json_ctrl_registers(void *bar); - +void json_nvme_list_secondary_ctrl(const struct nvme_secondary_controllers_list *sc_list, __u32 count); #endif diff --git a/nvme.c b/nvme.c index 102d5e9f..52d50aba 100644 --- a/nvme.c +++ b/nvme.c @@ -2268,6 +2268,84 @@ static int virtual_mgmt(int argc, char **argv, struct command *cmd, struct plugi } +static int list_secondary_ctrl(int argc, char **argv, struct command *cmd, struct plugin *plugin) +{ + const char *desc = "Show secondary controller list associated with the primary controller "\ + "of the given device."; + const char *controller = "lowest controller identifier to display"; + const char *namespace_id = "optional namespace attached to controller"; + const char *num_entries = "number of entries to retrieve"; + int err, fmt, fd; + struct nvme_secondary_controllers_list *sc_list; + + _Static_assert(sizeof(struct nvme_secondary_controller_entry) != NVME_IDENTIFY_DATA_SIZE, "bad structure size"); + + struct config { + __u16 cntid; + __u32 num_entries; + __u32 namespace_id; + char *output_format; + }; + + struct config cfg = { + .cntid = 0, + .namespace_id = 0, + .output_format = "normal", + .num_entries = ARRAY_SIZE(sc_list->sc_entry), + }; + + const struct argconfig_commandline_options command_line_options[] = { + {"cntid", 'c', "NUM", CFG_SHORT, &cfg.cntid, required_argument, controller}, + {"namespace-id", 'n', "NUM", CFG_POSITIVE, &cfg.namespace_id, required_argument, namespace_id}, + {"num-entries", 'e', "NUM", CFG_POSITIVE, &cfg.num_entries, required_argument, num_entries}, + {"output-format", 'o', "FMT", CFG_STRING, &cfg.output_format, required_argument, output_format}, + {NULL} + }; + + 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) { + err = fmt; + goto close_fd; + } + + if (!cfg.num_entries) { + fprintf(stderr, "non-zero num-entries is required param\n"); + err = -EINVAL; + goto close_fd; + } + + if (posix_memalign((void *)&sc_list, getpagesize(), sizeof(*sc_list))) { + fprintf(stderr, "can not allocate controller list payload\n"); + err = -ENOMEM; + goto close_fd; + } + + err = nvme_identify_secondary_ctrl_list(fd, cfg.namespace_id, cfg.cntid, sc_list); + if (!err) { + if (fmt == BINARY) + d_raw((unsigned char *)sc_list, sizeof(*sc_list)); + else if (fmt == JSON) + json_nvme_list_secondary_ctrl(sc_list, cfg.num_entries); + else + show_nvme_list_secondary_ctrl(sc_list, cfg.num_entries); + } else if (err > 0) + fprintf(stderr, "NVMe Status:%s(%x) cntid:%d\n", + nvme_status_to_string(err), err, cfg.cntid); + else + perror("id secondary controller list"); + + free(sc_list); + +close_fd: + close(fd); + + return err; +} + static int device_self_test(int argc, char **argv, struct command *cmd, struct plugin *plugin) { const char *desc = "Implementing the device self-test feature"\ diff --git a/nvme.h b/nvme.h index 685d1799..71e2f4d2 100644 --- a/nvme.h +++ b/nvme.h @@ -87,6 +87,23 @@ struct nvme_controller_list { __le16 identifier[]; }; +struct nvme_secondary_controller_entry { + __le16 scid; /* Secondary Controller Identifier */ + __le16 pcid; /* Primary Controller Identifier */ + __u8 scs; /* Secondary Controller State */ + __u8 rsvd5[3]; + __le16 vfn; /* Virtual Function Number */ + __le16 nvq; /* Number of VQ Flexible Resources Assigned */ + __le16 nvi; /* Number of VI Flexible Resources Assigned */ + __u8 rsvd14[18]; +}; + +struct nvme_secondary_controllers_list { + __u8 num; + __u8 rsvd[31]; + struct nvme_secondary_controller_entry sc_entry[127]; +}; + struct nvme_bar_cap { __u16 mqes; __u8 ams_cqr; -- 2.50.1