diff --git a/sbin/nvmecontrol/devlist.c b/sbin/nvmecontrol/devlist.c --- a/sbin/nvmecontrol/devlist.c +++ b/sbin/nvmecontrol/devlist.c @@ -116,9 +116,10 @@ scan_controller(int ctrlr) { struct nvme_controller_data cdata; + struct nvme_ns_list nslist; char name[64]; uint8_t mn[64]; - uint32_t i; + uint32_t nsid; int fd, ret; snprintf(name, sizeof(name), "%s%d", NVME_CTRLR_PREFIX, ctrlr); @@ -139,8 +140,20 @@ nvme_strvis(mn, cdata.mn, sizeof(mn), NVME_MODEL_NUMBER_LENGTH); printf("%6s: %s\n", name, mn); - for (i = 0; i < cdata.nn; i++) { - scan_namespace(fd, ctrlr, i + 1); + nsid = 0; + for (;;) { + if (read_active_namespaces(fd, nsid, &nslist) != 0) + break; + for (u_int i = 0; i < nitems(nslist.ns); i++) { + nsid = nslist.ns[i]; + if (nsid == 0) { + break; + } + + scan_namespace(fd, ctrlr, nsid); + } + if (nsid == 0 || nsid >= NVME_GLOBAL_NAMESPACE_TAG - 1) + break; } close(fd); diff --git a/sbin/nvmecontrol/nvmecontrol.h b/sbin/nvmecontrol/nvmecontrol.h --- a/sbin/nvmecontrol/nvmecontrol.h +++ b/sbin/nvmecontrol/nvmecontrol.h @@ -81,6 +81,7 @@ void get_nsid(int fd, char **ctrlr_str, uint32_t *nsid); int read_controller_data(int fd, struct nvme_controller_data *cdata); int read_namespace_data(int fd, uint32_t nsid, struct nvme_namespace_data *nsdata); +int read_active_namespaces(int fd, uint32_t nsid, struct nvme_ns_list *nslist); void print_hex(void *data, uint32_t length); void print_namespace(struct nvme_namespace_data *nsdata); void read_logpage(int fd, uint8_t log_page, uint32_t nsid, uint8_t lsp, diff --git a/sbin/nvmecontrol/nvmecontrol.c b/sbin/nvmecontrol/nvmecontrol.c --- a/sbin/nvmecontrol/nvmecontrol.c +++ b/sbin/nvmecontrol/nvmecontrol.c @@ -142,6 +142,30 @@ return (0); } +int +read_active_namespaces(int fd, uint32_t nsid, struct nvme_ns_list *nslist) +{ + struct nvme_pt_command pt; + + memset(&pt, 0, sizeof(pt)); + pt.cmd.opc = NVME_OPC_IDENTIFY; + pt.cmd.nsid = htole32(nsid); + pt.cmd.cdw10 = htole32(2); + pt.buf = nslist; + pt.len = sizeof(*nslist); + pt.is_read = 1; + + if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) + return (errno); + + /* Convert data to host endian */ + nvme_ns_list_swapbytes(nslist); + + if (nvme_completion_is_error(&pt.cpl)) + return (EIO); + return (0); +} + int open_dev(const char *str, int *fd, int write, int exit_on_error) {