From 9e1db51d4b5fce8a1ea7271018970760e396500c Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Mon, 4 Nov 2024 20:28:40 -0500 Subject: [PATCH] nvmecontrol: Use active nslist to enumerate namespaces Rather than probing all namespace IDs up to cdata.nn for the devlist command, fetch the active namespace list and iterate over that. This can be much quicker on Fabrics controllers which often advertise a large cdata.nn value to support adding additional namespaces at runtime. Reviewed by: chuck Reported by: Neven Z Sponsored by: Chelsio Communications Differential Revision: https://reviews.freebsd.org/D47355 --- sbin/nvmecontrol/devlist.c | 19 ++++++++++++++++--- sbin/nvmecontrol/nvmecontrol.c | 24 ++++++++++++++++++++++++ sbin/nvmecontrol/nvmecontrol.h | 1 + 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/sbin/nvmecontrol/devlist.c b/sbin/nvmecontrol/devlist.c index b2816339bc80..d2386e7ea800 100644 --- a/sbin/nvmecontrol/devlist.c +++ b/sbin/nvmecontrol/devlist.c @@ -116,9 +116,10 @@ static bool 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 @@ scan_controller(int ctrlr) 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.c b/sbin/nvmecontrol/nvmecontrol.c index 8ad9703de9f6..b38fb8038fc3 100644 --- a/sbin/nvmecontrol/nvmecontrol.c +++ b/sbin/nvmecontrol/nvmecontrol.c @@ -142,6 +142,30 @@ read_namespace_data(int fd, uint32_t nsid, struct nvme_namespace_data *nsdata) 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) { diff --git a/sbin/nvmecontrol/nvmecontrol.h b/sbin/nvmecontrol/nvmecontrol.h index 394a88608692..968e9c20160e 100644 --- a/sbin/nvmecontrol/nvmecontrol.h +++ b/sbin/nvmecontrol/nvmecontrol.h @@ -81,6 +81,7 @@ int open_dev(const char *str, int *fd, int write, int exit_on_error); 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,