git: bf3726998fc7 - main - nvmecontrol: Use admin device for admin-passthru

From: Warner Losh <imp_at_FreeBSD.org>
Date: Mon, 19 Oct 2026 06:24:44 UTC
The branch main has been updated by imp:

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

commit bf3726998fc7655fa116dd99be24842407d8263b
Author:     Warner Losh <imp@FreeBSD.org>
AuthorDate: 2026-10-19 04:43:09 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2026-10-19 06:22:51 +0000

    nvmecontrol: Use admin device for admin-passthru
    
    When we're doing admin-passhtru, we need to use the admin device, not
    the namespace device. So when we're passed in ndaX or nvdX, we need to
    translate that to nvmeY for this command for the admin-passthru command,
    but not the io-passthru command. Note namespace nuance in man page.
    
    Differential Revision:  https://reviews.freebsd.org/D59878
---
 sbin/nvmecontrol/nvmecontrol.8 |  4 ++--
 sbin/nvmecontrol/passthru.c    | 33 +++++++++++++++++++++++++--------
 2 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/sbin/nvmecontrol/nvmecontrol.8 b/sbin/nvmecontrol/nvmecontrol.8
index 19015a8c90df..76646a578e3b 100644
--- a/sbin/nvmecontrol/nvmecontrol.8
+++ b/sbin/nvmecontrol/nvmecontrol.8
@@ -33,7 +33,7 @@
 .\"
 .\" Author: Jim Harris <jimharris@FreeBSD.org>
 .\"
-.Dd September 10, 2026
+.Dd September 21, 2026
 .Dt NVMECONTROL 8
 .Os
 .Sh NAME
@@ -766,7 +766,7 @@ This is ignored and not implemented in
 .It Fl f -flags
 Nvme command flags.
 .It Fl n -namespace-id
-Namespace ID for command (Ignored).
+Namespace ID for command (ignored for admin, defaults to device's namespace for io).
 .It Fl p -prefill
 Value to prefill payload with.
 .It Fl b -raw-binary
diff --git a/sbin/nvmecontrol/passthru.c b/sbin/nvmecontrol/passthru.c
index cf38e185a582..45c8e8c914c3 100644
--- a/sbin/nvmecontrol/passthru.c
+++ b/sbin/nvmecontrol/passthru.c
@@ -41,6 +41,8 @@
 #include "nvmecontrol.h"
 #include "comnd.h"
 
+#define NONE 0xfffffffeu
+
 static struct options {
 	uint8_t		opcode;
 	uint8_t		flags;
@@ -80,7 +82,7 @@ static struct options {
 	.flags = 0,
 	.ifn = "",
 	.metadata_len = 0,
-	.nsid = 0,
+	.nsid = NONE,
 	.opcode = 0,
 	.prefill = 0,
 	.read = false,
@@ -152,8 +154,10 @@ static const struct args args[] = {
 };
 
 static void
-passthru(const struct cmd *f, int argc, char *argv[])
+passthru(const struct cmd *f, int argc, char *argv[], bool admin)
 {
+	char		*path;
+	uint32_t	nsid;
 	int	fd = -1, ifd = -1;
 	size_t	bytes_read;
 	void	*data = NULL, *metadata = NULL;
@@ -161,7 +165,22 @@ passthru(const struct cmd *f, int argc, char *argv[])
 
 	if (arg_parse(argc, argv, f))
 		return;
+	/*
+	 * Open the specified device. Get the namespace ID for that device, and
+	 * use that if one isn't on the command line.
+	 */
 	open_dev(opt.dev, &fd, 1, 1);
+	get_nsid(fd, &path, &nsid);
+	if (admin && nsid != 0) {
+		/*
+		 * We got namespace device, but we need the admin device.
+		 */
+		close(fd);
+		open_dev(path, &fd, 0, 1);
+	}
+	free(path);
+	if (opt.nsid != NONE)
+		nsid = opt.nsid;
 
 	if (opt.read && opt.write)
 		errx(EX_USAGE, "need exactly one of --read or --write");
@@ -201,7 +220,7 @@ passthru(const struct cmd *f, int argc, char *argv[])
 		fprintf(stderr, "opcode       : %#02x\n", opt.opcode);
 		fprintf(stderr, "flags        : %#02x\n", opt.flags);
 		fprintf(stderr, "rsvd1        : %#04x\n", opt.rsvd);
-		fprintf(stderr, "nsid         : %#04x\n", opt.nsid);
+		fprintf(stderr, "nsid         : %#04x\n", nsid);
 		fprintf(stderr, "cdw2         : %#08x\n", opt.cdw2);
 		fprintf(stderr, "cdw3         : %#08x\n", opt.cdw3);
 		fprintf(stderr, "data_len     : %#08x\n", opt.data_len);
@@ -226,7 +245,7 @@ passthru(const struct cmd *f, int argc, char *argv[])
 	pt.cmd.opc = opt.opcode;
 	pt.cmd.fuse = opt.flags;
 	pt.cmd.cid = htole16(opt.rsvd);
-	pt.cmd.nsid = opt.nsid;				/* XXX note: kernel overrides this */
+	pt.cmd.nsid = htole32(nsid);
 	pt.cmd.rsvd2 = htole32(opt.cdw2);
 	pt.cmd.rsvd3 = htole32(opt.cdw3);
 	pt.cmd.cdw10 = htole32(opt.cdw10);
@@ -264,15 +283,13 @@ cleanup:
 static void
 admin_passthru(const struct cmd *nf, int argc, char *argv[])
 {
-
-	passthru(nf, argc, argv);
+	passthru(nf, argc, argv, true);
 }
 
 static void
 io_passthru(const struct cmd *nf, int argc, char *argv[])
 {
-
-	passthru(nf, argc, argv);
+	passthru(nf, argc, argv, false);
 }
 
 static struct cmd admin_pass_cmd = {