git: 9e1db51d4b5f - main - nvmecontrol: Use active nslist to enumerate namespaces

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Tue, 05 Nov 2024 01:29:09 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=9e1db51d4b5fce8a1ea7271018970760e396500c

commit 9e1db51d4b5fce8a1ea7271018970760e396500c
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2024-11-05 01:28:40 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2024-11-05 01:28:40 +0000

    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 <nevenzfr@gmail.com>
    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,