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
This commit is contained in:
John Baldwin 2024-11-04 20:28:40 -05:00
parent 326e20fc12
commit 9e1db51d4b
3 changed files with 41 additions and 3 deletions

View File

@ -116,9 +116,10 @@ static bool
scan_controller(int ctrlr) scan_controller(int ctrlr)
{ {
struct nvme_controller_data cdata; struct nvme_controller_data cdata;
struct nvme_ns_list nslist;
char name[64]; char name[64];
uint8_t mn[64]; uint8_t mn[64];
uint32_t i; uint32_t nsid;
int fd, ret; int fd, ret;
snprintf(name, sizeof(name), "%s%d", NVME_CTRLR_PREFIX, ctrlr); 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); nvme_strvis(mn, cdata.mn, sizeof(mn), NVME_MODEL_NUMBER_LENGTH);
printf("%6s: %s\n", name, mn); printf("%6s: %s\n", name, mn);
for (i = 0; i < cdata.nn; i++) { nsid = 0;
scan_namespace(fd, ctrlr, i + 1); 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); close(fd);

View File

@ -142,6 +142,30 @@ read_namespace_data(int fd, uint32_t nsid, struct nvme_namespace_data *nsdata)
return (0); 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 int
open_dev(const char *str, int *fd, int write, int exit_on_error) open_dev(const char *str, int *fd, int write, int exit_on_error)
{ {

View File

@ -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); void get_nsid(int fd, char **ctrlr_str, uint32_t *nsid);
int read_controller_data(int fd, struct nvme_controller_data *cdata); 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_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_hex(void *data, uint32_t length);
void print_namespace(struct nvme_namespace_data *nsdata); void print_namespace(struct nvme_namespace_data *nsdata);
void read_logpage(int fd, uint8_t log_page, uint32_t nsid, uint8_t lsp, void read_logpage(int fd, uint8_t log_page, uint32_t nsid, uint8_t lsp,