xref: /freebsd/sbin/nvmecontrol/ns.c (revision 344d411c676dc92e648be86de369c4d1dd070209)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2017 Netflix, Inc.
5  * Copyright (C) 2018-2019 Alexander Motin <mav@FreeBSD.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer,
12  *    without modification, immediately at the beginning of the file.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/ioccom.h>
34 
35 #include <err.h>
36 #include <fcntl.h>
37 #include <stdbool.h>
38 #include <stddef.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 
44 #include "nvmecontrol.h"
45 
46 /* Tables for command line parsing */
47 
48 static cmd_fn_t ns;
49 static cmd_fn_t nsactive;
50 static cmd_fn_t nsallocated;
51 static cmd_fn_t nscontrollers;
52 static cmd_fn_t nscreate;
53 static cmd_fn_t nsdelete;
54 static cmd_fn_t nsattach;
55 static cmd_fn_t nsdetach;
56 static cmd_fn_t nsattached;
57 static cmd_fn_t nsidentify;
58 
59 #define NONE 0xffffffffu
60 #define NONE64 0xffffffffffffffffull
61 #define OPT(l, s, t, opt, addr, desc) { l, s, t, &opt.addr, desc }
62 #define OPT_END	{ NULL, 0, arg_none, NULL, NULL }
63 
64 static struct cmd ns_cmd = {
65 	.name = "ns",
66 	.fn = ns,
67 	.descr = "Namespace management commands",
68 	.ctx_size = 0,
69 	.opts = NULL,
70 	.args = NULL,
71 };
72 
73 CMD_COMMAND(ns_cmd);
74 
75 static struct active_options {
76 	const char	*dev;
77 } active_opt = {
78 	.dev = NULL,
79 };
80 
81 static const struct args active_args[] = {
82 	{ arg_string, &active_opt.dev, "controller-id|namespace-id" },
83 	{ arg_none, NULL, NULL },
84 };
85 
86 static struct cmd active_cmd = {
87 	.name = "active",
88 	.fn = nsactive,
89 	.descr = "List active (attached) namespaces",
90 	.ctx_size = sizeof(active_opt),
91 	.opts = NULL,
92 	.args = active_args,
93 };
94 
95 CMD_SUBCOMMAND(ns_cmd, active_cmd);
96 
97 static struct cmd allocated_cmd = {
98 	.name = "allocated",
99 	.fn = nsallocated,
100 	.descr = "List allocated (created) namespaces",
101 	.ctx_size = sizeof(active_opt),
102 	.opts = NULL,
103 	.args = active_args,
104 };
105 
106 CMD_SUBCOMMAND(ns_cmd, allocated_cmd);
107 
108 static struct controllers_options {
109 	const char	*dev;
110 } controllers_opt = {
111 	.dev = NULL,
112 };
113 
114 static const struct args controllers_args[] = {
115 	{ arg_string, &controllers_opt.dev, "controller-id|namespace-id" },
116 	{ arg_none, NULL, NULL },
117 };
118 
119 static struct cmd controllers_cmd = {
120 	.name = "controllers",
121 	.fn = nscontrollers,
122 	.descr = "List all controllers in NVM subsystem",
123 	.ctx_size = sizeof(controllers_opt),
124 	.opts = NULL,
125 	.args = controllers_args,
126 };
127 
128 CMD_SUBCOMMAND(ns_cmd, controllers_cmd);
129 
130 static struct create_options {
131 	uint64_t nsze;
132 	uint64_t cap;
133 	uint32_t lbaf;
134 	uint32_t mset;
135 	uint32_t nmic;
136 	uint32_t pi;
137 	uint32_t pil;
138 	uint32_t flbas;
139 	uint32_t dps;
140 //	uint32_t block_size;
141 	const char *dev;
142 } create_opt = {
143 	.nsze = NONE64,
144 	.cap = NONE64,
145 	.lbaf = NONE,
146 	.mset = NONE,
147 	.nmic = NONE,
148 	.pi = NONE,
149 	.pil = NONE,
150 	.flbas = NONE,
151 	.dps = NONE,
152 	.dev = NULL,
153 //	.block_size = NONE,
154 };
155 
156 static const struct opts create_opts[] = {
157 	OPT("nsze", 's', arg_uint64, create_opt, nsze,
158 	    "The namespace size"),
159 	OPT("ncap", 'c', arg_uint64, create_opt, cap,
160 	    "The capacity of the namespace (<= ns size)"),
161 	OPT("lbaf", 'f', arg_uint32, create_opt, lbaf,
162 	    "The FMT field of the FLBAS"),
163 	OPT("mset", 'm', arg_uint32, create_opt, mset,
164 	    "The MSET field of the FLBAS"),
165 	OPT("nmic", 'n', arg_uint32, create_opt, nmic,
166 	    "Namespace multipath and sharing capabilities"),
167 	OPT("pi", 'p', arg_uint32, create_opt, pi,
168 	    "PI field of FLBAS"),
169 	OPT("pil", 'l', arg_uint32, create_opt, pil,
170 	    "PIL field of FLBAS"),
171 	OPT("flbas", 'L', arg_uint32, create_opt, flbas,
172 	    "Namespace formatted logical block size setting"),
173 	OPT("dps", 'd', arg_uint32, create_opt, dps,
174 	    "Data protection settings"),
175 //	OPT("block-size", 'b', arg_uint32, create_opt, block_size,
176 //	    "Blocksize of the namespace"),
177 	OPT_END
178 };
179 
180 static const struct args create_args[] = {
181 	{ arg_string, &create_opt.dev, "controller-id|namespace-id" },
182 	{ arg_none, NULL, NULL },
183 };
184 
185 static struct cmd create_cmd = {
186 	.name = "create",
187 	.fn = nscreate,
188 	.descr = "Create a namespace",
189 	.ctx_size = sizeof(create_opt),
190 	.opts = create_opts,
191 	.args = create_args,
192 };
193 
194 CMD_SUBCOMMAND(ns_cmd, create_cmd);
195 
196 static struct delete_options {
197 	uint32_t	nsid;
198 	const char	*dev;
199 } delete_opt = {
200 	.nsid = NONE,
201 	.dev = NULL,
202 };
203 
204 static const struct opts delete_opts[] = {
205 	OPT("namespace-id", 'n', arg_uint32, delete_opt, nsid,
206 	    "The namespace ID to delete"),
207 	OPT_END
208 };
209 
210 static const struct args delete_args[] = {
211 	{ arg_string, &delete_opt.dev, "controller-id|namespace-id" },
212 	{ arg_none, NULL, NULL },
213 };
214 
215 static struct cmd delete_cmd = {
216 	.name = "delete",
217 	.fn = nsdelete,
218 	.descr = "Delete a namespace",
219 	.ctx_size = sizeof(delete_opt),
220 	.opts = delete_opts,
221 	.args = delete_args,
222 };
223 
224 CMD_SUBCOMMAND(ns_cmd, delete_cmd);
225 
226 static struct attach_options {
227 	uint32_t	nsid;
228 	uint32_t	ctrlrid;
229 	const char	*dev;
230 } attach_opt = {
231 	.nsid = NONE,
232 	.ctrlrid = NONE - 1,
233 	.dev = NULL,
234 };
235 
236 static const struct opts attach_opts[] = {
237 	OPT("namespace-id", 'n', arg_uint32, attach_opt, nsid,
238 	    "The namespace ID to attach"),
239 	OPT("controller", 'c', arg_uint32, attach_opt, ctrlrid,
240 	    "The controller ID to attach"),
241 	OPT_END
242 };
243 
244 static const struct args attach_args[] = {
245 	{ arg_string, &attach_opt.dev, "controller-id|namespace-id" },
246 	{ arg_none, NULL, NULL },
247 };
248 
249 static struct cmd attach_cmd = {
250 	.name = "attach",
251 	.fn = nsattach,
252 	.descr = "Attach a controller to a namespace",
253 	.ctx_size = sizeof(attach_opt),
254 	.opts = attach_opts,
255 	.args = attach_args,
256 };
257 
258 CMD_SUBCOMMAND(ns_cmd, attach_cmd);
259 
260 static struct attached_options {
261 	uint32_t	nsid;
262 	const char	*dev;
263 } attached_opt = {
264 	.nsid = NONE,
265 	.dev = NULL,
266 };
267 
268 static const struct opts attached_opts[] = {
269 	OPT("namespace-id", 'n', arg_uint32, attached_opt, nsid,
270 	    "The namespace ID to request attached controllers"),
271 	OPT_END
272 };
273 
274 static const struct args attached_args[] = {
275 	{ arg_string, &attached_opt.dev, "controller-id|namespace-id" },
276 	{ arg_none, NULL, NULL },
277 };
278 
279 static struct cmd attached_cmd = {
280 	.name = "attached",
281 	.fn = nsattached,
282 	.descr = "List controllers attached to a namespace",
283 	.ctx_size = sizeof(attached_opt),
284 	.opts = attached_opts,
285 	.args = attached_args,
286 };
287 
288 CMD_SUBCOMMAND(ns_cmd, attached_cmd);
289 
290 static struct detach_options {
291 	uint32_t	nsid;
292 	uint32_t	ctrlrid;
293 	const char	*dev;
294 } detach_opt = {
295 	.nsid = NONE,
296 	.ctrlrid = NONE - 1,
297 	.dev = NULL,
298 };
299 
300 static const struct opts detach_opts[] = {
301 	OPT("namespace-id", 'n', arg_uint32, detach_opt, nsid,
302 	    "The namespace ID to detach"),
303 	OPT("controller", 'c', arg_uint32, detach_opt, ctrlrid,
304 	    "The controller ID to detach"),
305 	OPT_END
306 };
307 
308 static const struct args detach_args[] = {
309 	{ arg_string, &detach_opt.dev, "controller-id|namespace-id" },
310 	{ arg_none, NULL, NULL },
311 };
312 
313 static struct cmd detach_cmd = {
314 	.name = "detach",
315 	.fn = nsdetach,
316 	.descr = "Detach a controller from a namespace",
317 	.ctx_size = sizeof(detach_opt),
318 	.opts = detach_opts,
319 	.args = detach_args,
320 };
321 
322 CMD_SUBCOMMAND(ns_cmd, detach_cmd);
323 
324 static struct identify_options {
325 	bool		hex;
326 	bool		verbose;
327 	const char	*dev;
328 	uint32_t	nsid;
329 } identify_opt = {
330 	.hex = false,
331 	.verbose = false,
332 	.dev = NULL,
333 	.nsid = NONE,
334 };
335 
336 static const struct opts identify_opts[] = {
337 	OPT("hex", 'x', arg_none, identify_opt, hex,
338 	    "Print identiy information in hex"),
339 	OPT("verbose", 'v', arg_none, identify_opt, verbose,
340 	    "More verbosity: print entire identify table"),
341 	OPT("nsid", 'n', arg_uint32, identify_opt, nsid,
342 	    "The namespace ID to print IDENTIFY for"),
343 	{ NULL, 0, arg_none, NULL, NULL }
344 };
345 
346 static const struct args identify_args[] = {
347 	{ arg_string, &identify_opt.dev, "controller-id|namespace-id" },
348 	{ arg_none, NULL, NULL },
349 };
350 
351 static struct cmd identify_cmd = {
352 	.name = "identify",
353 	.fn = nsidentify,
354 	.descr = "Print IDENTIFY for allocated namespace",
355 	.ctx_size = sizeof(identify_opt),
356 	.opts = identify_opts,
357 	.args = identify_args,
358 };
359 
360 CMD_SUBCOMMAND(ns_cmd, identify_cmd);
361 
362 /* handles NVME_OPC_NAMESPACE_MANAGEMENT and ATTACHMENT admin cmds */
363 
364 struct ns_result_str {
365 	uint16_t res;
366 	const char * str;
367 };
368 
369 static struct ns_result_str ns_result[] = {
370 	{ 0x2,  "Invalid Field"},
371 	{ 0xa,  "Invalid Format"},
372 	{ 0xb,  "Invalid Namespace or format"},
373 	{ 0x15, "Namespace insufficent capacity"},
374 	{ 0x16, "Namespace ID unavaliable"},
375 	{ 0x18, "Namespace already attached"},
376 	{ 0x19, "Namespace is private"},
377 	{ 0x1a, "Namespace is not attached"},
378 	{ 0x1b, "Thin provisioning not supported"},
379 	{ 0x1c, "Controller list invalid"},
380 	{ 0x24, "ANA Group Identifier Invalid"},
381 	{ 0x25, "ANA Attach Failed"},
382 	{ 0xFFFF, "Unknown"}
383 };
384 
385 static const char *
386 get_res_str(uint16_t res)
387 {
388 	struct ns_result_str *t = ns_result;
389 
390 	while (t->res != 0xFFFF) {
391 		if (t->res == res)
392 			return (t->str);
393 		t++;
394 	}
395 	return t->str;
396 }
397 
398 static void
399 nsactive(const struct cmd *f, int argc, char *argv[])
400 {
401 	struct nvme_pt_command	pt;
402 	struct nvme_controller_data cd;
403 	int	fd, i;
404 	char	*path;
405 	uint32_t nsid;
406 	uint32_t list[1024];
407 
408 	if (arg_parse(argc, argv, f))
409 		return;
410 	open_dev(active_opt.dev, &fd, 0, 1);
411 	get_nsid(fd, &path, &nsid);
412 	if (nsid != 0) {
413 		close(fd);
414 		open_dev(path, &fd, 0, 1);
415 	}
416 	free(path);
417 	read_controller_data(fd, &cd);
418 
419 	/* Check that controller can execute this command. */
420 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
421 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
422 		errx(1, "controller does not support namespace management");
423 
424 	memset(&pt, 0, sizeof(pt));
425 	pt.cmd.opc = NVME_OPC_IDENTIFY;
426 	pt.cmd.nsid = htole32(0);
427 	pt.cmd.cdw10 = htole32(0x02);
428 	pt.buf = list;
429 	pt.len = sizeof(list);
430 	pt.is_read = 1;
431 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
432 		err(1, "identify request failed");
433 	if (nvme_completion_is_error(&pt.cpl))
434 		errx(1, "identify request returned error");
435 
436 	printf("Active namespaces:\n");
437 	for (i = 0; list[i] != 0; i++)
438 		printf("%10d\n", le32toh(list[i]));
439 
440 	exit(0);
441 }
442 
443 static void
444 nsallocated(const struct cmd *f, int argc, char *argv[])
445 {
446 	struct nvme_pt_command	pt;
447 	struct nvme_controller_data cd;
448 	int	fd, i;
449 	char	*path;
450 	uint32_t nsid;
451 	uint32_t list[1024];
452 
453 	if (arg_parse(argc, argv, f))
454 		return;
455 	open_dev(active_opt.dev, &fd, 0, 1);
456 	get_nsid(fd, &path, &nsid);
457 	if (nsid != 0) {
458 		close(fd);
459 		open_dev(path, &fd, 0, 1);
460 	}
461 	free(path);
462 	read_controller_data(fd, &cd);
463 
464 	/* Check that controller can execute this command. */
465 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
466 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
467 		errx(1, "controller does not support namespace management");
468 
469 	memset(&pt, 0, sizeof(pt));
470 	pt.cmd.opc = NVME_OPC_IDENTIFY;
471 	pt.cmd.nsid = htole32(0);
472 	pt.cmd.cdw10 = htole32(0x10);
473 	pt.buf = list;
474 	pt.len = sizeof(list);
475 	pt.is_read = 1;
476 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
477 		err(1, "identify request failed");
478 	if (nvme_completion_is_error(&pt.cpl))
479 		errx(1, "identify request returned error");
480 
481 	printf("Allocated namespaces:\n");
482 	for (i = 0; list[i] != 0; i++)
483 		printf("%10d\n", le32toh(list[i]));
484 
485 	exit(0);
486 }
487 
488 static void
489 nscontrollers(const struct cmd *f, int argc, char *argv[])
490 {
491 	struct nvme_pt_command	pt;
492 	struct nvme_controller_data cd;
493 	int	fd, i, n;
494 	char	*path;
495 	uint32_t nsid;
496 	uint16_t clist[2048];
497 
498 	if (arg_parse(argc, argv, f))
499 		return;
500 	open_dev(controllers_opt.dev, &fd, 0, 1);
501 	get_nsid(fd, &path, &nsid);
502 	if (nsid != 0) {
503 		close(fd);
504 		open_dev(path, &fd, 0, 1);
505 	}
506 	free(path);
507 	read_controller_data(fd, &cd);
508 
509 	/* Check that controller can execute this command. */
510 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
511 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
512 		errx(1, "controller does not support namespace management");
513 
514 	memset(&pt, 0, sizeof(pt));
515 	pt.cmd.opc = NVME_OPC_IDENTIFY;
516 	pt.cmd.cdw10 = htole32(0x13);
517 	pt.buf = clist;
518 	pt.len = sizeof(clist);
519 	pt.is_read = 1;
520 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
521 		err(1, "identify request failed");
522 	if (nvme_completion_is_error(&pt.cpl))
523 		errx(1, "identify request returned error");
524 
525 	n = le16toh(clist[0]);
526 	printf("NVM subsystem includes %d controller(s):\n", n);
527 	for (i = 0; i < n; i++)
528 		printf("  0x%04x\n", le16toh(clist[i + 1]));
529 
530 	exit(0);
531 }
532 
533 /*
534  * NS MGMT Command specific status values:
535  * 0xa = Invalid Format
536  * 0x15 = Namespace Insuffience capacity
537  * 0x16 = Namespace ID  unavailable (number namespaces exceeded)
538  * 0xb = Thin Provisioning Not supported
539  */
540 static void
541 nscreate(const struct cmd *f, int argc, char *argv[])
542 {
543 	struct nvme_pt_command	pt;
544 	struct nvme_controller_data cd;
545 	struct nvme_namespace_data nsdata;
546 	int	fd, result;
547 	char	*path;
548 	uint32_t nsid;
549 
550 	if (arg_parse(argc, argv, f))
551 		return;
552 
553 	if (create_opt.cap == NONE64)
554 		create_opt.cap = create_opt.nsze;
555 	if (create_opt.nsze == NONE64) {
556 		fprintf(stderr,
557 		    "Size not specified\n");
558 		arg_help(argc, argv, f);
559 	}
560 
561 	open_dev(create_opt.dev, &fd, 1, 1);
562 	get_nsid(fd, &path, &nsid);
563 	if (nsid != 0) {
564 		close(fd);
565 		open_dev(path, &fd, 1, 1);
566 	}
567 	free(path);
568 	read_controller_data(fd, &cd);
569 
570 	/* Check that controller can execute this command. */
571 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
572 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
573 		errx(1, "controller does not support namespace management");
574 
575 	/* Allow namespaces sharing if Multi-Path I/O is supported. */
576 	if (create_opt.nmic == NONE) {
577 		create_opt.nmic = cd.mic ? (NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK <<
578 		     NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) : 0;
579 	}
580 
581 	memset(&nsdata, 0, sizeof(nsdata));
582 	nsdata.nsze = create_opt.nsze;
583 	nsdata.ncap = create_opt.cap;
584 	if (create_opt.flbas == NONE)
585 		nsdata.flbas = ((create_opt.lbaf & NVME_NS_DATA_FLBAS_FORMAT_MASK)
586 		    << NVME_NS_DATA_FLBAS_FORMAT_SHIFT) |
587 		    ((create_opt.mset & NVME_NS_DATA_FLBAS_EXTENDED_MASK)
588 			<< NVME_NS_DATA_FLBAS_EXTENDED_SHIFT);
589 	else
590 		nsdata.flbas = create_opt.flbas;
591 	if (create_opt.dps == NONE)
592 		nsdata.dps = ((create_opt.pi & NVME_NS_DATA_DPS_MD_START_MASK)
593 		    << NVME_NS_DATA_DPS_MD_START_SHIFT) |
594 		    ((create_opt.pil & NVME_NS_DATA_DPS_PIT_MASK)
595 			<< NVME_NS_DATA_DPS_PIT_SHIFT);
596 	else
597 		nsdata.dps = create_opt.dps;
598 	nsdata.nmic = create_opt.nmic;
599 	nvme_namespace_data_swapbytes(&nsdata);
600 
601 	memset(&pt, 0, sizeof(pt));
602 	pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
603 	pt.cmd.cdw10 = htole32(0); /* create */
604 	pt.buf = &nsdata;
605 	pt.len = sizeof(struct nvme_namespace_data);
606 	pt.is_read = 0; /* passthrough writes data to ctrlr */
607 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
608 		errx(1, "ioctl request to %s failed: %d", argv[optind], result);
609 
610 	if (nvme_completion_is_error(&pt.cpl)) {
611 		errx(1, "namespace creation failed: %s",
612 		    get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
613 		    NVME_STATUS_SC_MASK));
614 	}
615 	printf("namespace %d created\n", pt.cpl.cdw0);
616 	exit(0);
617 }
618 
619 static void
620 nsdelete(const struct cmd *f, int argc, char *argv[])
621 {
622 	struct nvme_pt_command	pt;
623 	struct nvme_controller_data cd;
624 	int	fd, result;
625 	char	*path;
626 	uint32_t nsid;
627 	char buf[2];
628 
629 	if (arg_parse(argc, argv, f))
630 		return;
631 
632 	open_dev(delete_opt.dev, &fd, 1, 1);
633 	get_nsid(fd, &path, &nsid);
634 	if (nsid != 0) {
635 		close(fd);
636 		open_dev(path, &fd, 1, 1);
637 	} else if (delete_opt.nsid == NONE) {
638 		close(fd);
639 		fprintf(stderr, "No NSID specified");
640 		arg_help(argc, argv, f);
641 	}
642 	if (delete_opt.nsid != NONE)
643 		nsid = delete_opt.nsid;
644 	free(path);
645 	read_controller_data(fd, &cd);
646 
647 	/* Check that controller can execute this command. */
648 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
649 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
650 		errx(1, "controller does not support namespace management");
651 
652 	memset(&pt, 0, sizeof(pt));
653 	pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
654 	pt.cmd.cdw10 = htole32(1); /* delete */
655 	pt.buf = buf;
656 	pt.len = sizeof(buf);
657 	pt.is_read = 1;
658 	pt.cmd.nsid = nsid;
659 
660 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
661 		errx(1, "ioctl request to %s failed: %d", delete_opt.dev, result);
662 
663 	if (nvme_completion_is_error(&pt.cpl)) {
664 		errx(1, "namespace deletion failed: %s",
665 		    get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
666 		    NVME_STATUS_SC_MASK));
667 	}
668 	printf("namespace %d deleted\n", nsid);
669 	exit(0);
670 }
671 
672 /*
673  * Attach and Detach use Dword 10, and a controller list (section 4.9)
674  * This struct is 4096 bytes in size.
675  * 0h = attach
676  * 1h = detach
677  *
678  * Result values for both attach/detach:
679  *
680  * Completion 18h = Already attached
681  *            19h = NS is private and already attached to a controller
682  *            1Ah = Not attached, request could not be completed
683  *            1Ch = Controller list invalid.
684  *
685  * 0x2 Invalid Field can occur if ctrlrid d.n.e in system.
686  */
687 static void
688 nsattach(const struct cmd *f, int argc, char *argv[])
689 {
690 	struct nvme_pt_command	pt;
691 	struct nvme_controller_data cd;
692 	int	fd, result;
693 	char	*path;
694 	uint32_t nsid;
695 	uint16_t clist[2048];
696 
697 	if (arg_parse(argc, argv, f))
698 		return;
699 	open_dev(attach_opt.dev, &fd, 1, 1);
700 	get_nsid(fd, &path, &nsid);
701 	if (nsid != 0) {
702 		close(fd);
703 		open_dev(path, &fd, 1, 1);
704 	} else if (attach_opt.nsid == NONE) {
705 		close(fd);
706 		fprintf(stderr, "No NSID specified");
707 		arg_help(argc, argv, f);
708 	}
709 	if (attach_opt.nsid != NONE)
710 		nsid = attach_opt.nsid;
711 	read_controller_data(fd, &cd);
712 
713 	/* Check that controller can execute this command. */
714 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
715 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
716 		errx(1, "controller does not support namespace management");
717 
718 	if (attach_opt.ctrlrid == NONE) {
719 		/* Get full list of controllers to attach to. */
720 		memset(&pt, 0, sizeof(pt));
721 		pt.cmd.opc = NVME_OPC_IDENTIFY;
722 		pt.cmd.cdw10 = htole32(0x13);
723 		pt.buf = clist;
724 		pt.len = sizeof(clist);
725 		pt.is_read = 1;
726 		if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
727 			err(1, "identify request failed");
728 		if (nvme_completion_is_error(&pt.cpl))
729 			errx(1, "identify request returned error");
730 	} else {
731 		/* By default attach to this controller. */
732 		if (attach_opt.ctrlrid == NONE - 1)
733 			attach_opt.ctrlrid = cd.ctrlr_id;
734 		memset(&clist, 0, sizeof(clist));
735 		clist[0] = htole16(1);
736 		clist[1] = htole16(attach_opt.ctrlrid);
737 	}
738 
739 	memset(&pt, 0, sizeof(pt));
740 	pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
741 	pt.cmd.cdw10 = htole32(0); /* attach */
742 	pt.cmd.nsid = nsid;
743 	pt.buf = &clist;
744 	pt.len = sizeof(clist);
745 
746 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
747 		errx(1, "ioctl request to %s failed: %d", attach_opt.dev, result);
748 
749 	if (nvme_completion_is_error(&pt.cpl)) {
750 		errx(1, "namespace attach failed: %s",
751 		    get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
752 		    NVME_STATUS_SC_MASK));
753 	}
754 	printf("namespace %d attached\n", nsid);
755 	exit(0);
756 }
757 
758 static void
759 nsdetach(const struct cmd *f, int argc, char *argv[])
760 {
761 	struct nvme_pt_command	pt;
762 	struct nvme_controller_data cd;
763 	int	fd, result;
764 	char	*path;
765 	uint32_t nsid;
766 	uint16_t clist[2048];
767 
768 	if (arg_parse(argc, argv, f))
769 		return;
770 	open_dev(detach_opt.dev, &fd, 1, 1);
771 	get_nsid(fd, &path, &nsid);
772 	if (nsid != 0) {
773 		close(fd);
774 		open_dev(path, &fd, 1, 1);
775 	} else if (detach_opt.nsid == NONE) {
776 		close(fd);
777 		fprintf(stderr, "No NSID specified");
778 		arg_help(argc, argv, f);
779 	}
780 	if (detach_opt.nsid != NONE)
781 		nsid = detach_opt.nsid;
782 	read_controller_data(fd, &cd);
783 
784 	/* Check that controller can execute this command. */
785 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
786 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
787 		errx(1, "controller does not support namespace management");
788 
789 	if (detach_opt.ctrlrid == NONE) {
790 		/* Get list of controllers this namespace attached to. */
791 		memset(&pt, 0, sizeof(pt));
792 		pt.cmd.opc = NVME_OPC_IDENTIFY;
793 		pt.cmd.nsid = htole32(nsid);
794 		pt.cmd.cdw10 = htole32(0x12);
795 		pt.buf = clist;
796 		pt.len = sizeof(clist);
797 		pt.is_read = 1;
798 		if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
799 			err(1, "identify request failed");
800 		if (nvme_completion_is_error(&pt.cpl))
801 			errx(1, "identify request returned error");
802 		if (clist[0] == 0) {
803 			detach_opt.ctrlrid = cd.ctrlr_id;
804 			memset(&clist, 0, sizeof(clist));
805 			clist[0] = htole16(1);
806 			clist[1] = htole16(detach_opt.ctrlrid);
807 		}
808 	} else {
809 		/* By default detach from this controller. */
810 		if (detach_opt.ctrlrid == NONE - 1)
811 			detach_opt.ctrlrid = cd.ctrlr_id;
812 		memset(&clist, 0, sizeof(clist));
813 		clist[0] = htole16(1);
814 		clist[1] = htole16(detach_opt.ctrlrid);
815 	}
816 
817 	memset(&pt, 0, sizeof(pt));
818 	pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
819 	pt.cmd.cdw10 = htole32(1); /* detach */
820 	pt.cmd.nsid = nsid;
821 	pt.buf = &clist;
822 	pt.len = sizeof(clist);
823 
824 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
825 		errx(1, "ioctl request to %s failed: %d", argv[optind], result);
826 
827 	if (nvme_completion_is_error(&pt.cpl)) {
828 		errx(1, "namespace detach failed: %s",
829 		    get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
830 		    NVME_STATUS_SC_MASK));
831 	}
832 	printf("namespace %d detached\n", nsid);
833 	exit(0);
834 }
835 
836 static void
837 nsattached(const struct cmd *f, int argc, char *argv[])
838 {
839 	struct nvme_pt_command	pt;
840 	struct nvme_controller_data cd;
841 	int	fd, i, n;
842 	char	*path;
843 	uint32_t nsid;
844 	uint16_t clist[2048];
845 
846 	if (arg_parse(argc, argv, f))
847 		return;
848 	open_dev(attached_opt.dev, &fd, 0, 1);
849 	get_nsid(fd, &path, &nsid);
850 	if (nsid != 0) {
851 		close(fd);
852 		open_dev(path, &fd, 1, 1);
853 	} else if (attached_opt.nsid == NONE) {
854 		close(fd);
855 		fprintf(stderr, "No NSID specified");
856 		arg_help(argc, argv, f);
857 	}
858 	if (attached_opt.nsid != NONE)
859 		nsid = attached_opt.nsid;
860 	read_controller_data(fd, &cd);
861 
862 	/* Check that controller can execute this command. */
863 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
864 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
865 		errx(1, "controller does not support namespace management");
866 
867 	memset(&pt, 0, sizeof(pt));
868 	pt.cmd.opc = NVME_OPC_IDENTIFY;
869 	pt.cmd.nsid = htole32(nsid);
870 	pt.cmd.cdw10 = htole32(0x12);
871 	pt.buf = clist;
872 	pt.len = sizeof(clist);
873 	pt.is_read = 1;
874 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
875 		err(1, "identify request failed");
876 	if (nvme_completion_is_error(&pt.cpl))
877 		errx(1, "identify request returned error");
878 
879 	n = le16toh(clist[0]);
880 	printf("Attached %d controller(s):\n", n);
881 	for (i = 0; i < n; i++)
882 		printf("  0x%04x\n", le16toh(clist[i + 1]));
883 
884 	exit(0);
885 }
886 
887 static void
888 nsidentify(const struct cmd *f, int argc, char *argv[])
889 {
890 	struct nvme_pt_command	pt;
891 	struct nvme_controller_data cd;
892 	struct nvme_namespace_data nsdata;
893 	uint8_t	*data;
894 	int	fd;
895 	char	*path;
896 	uint32_t nsid;
897 	u_int	i;
898 
899 	if (arg_parse(argc, argv, f))
900 		return;
901 	open_dev(identify_opt.dev, &fd, 0, 1);
902 	get_nsid(fd, &path, &nsid);
903 	if (nsid != 0) {
904 		close(fd);
905 		open_dev(path, &fd, 1, 1);
906 	} else if (identify_opt.nsid == NONE) {
907 		close(fd);
908 		fprintf(stderr, "No NSID specified");
909 		arg_help(argc, argv, f);
910 	}
911 	if (identify_opt.nsid != NONE)
912 		nsid = identify_opt.nsid;
913 	read_controller_data(fd, &cd);
914 
915 	/* Check that controller can execute this command. */
916 	if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
917 	    NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
918 		errx(1, "controller does not support namespace management");
919 
920 	memset(&pt, 0, sizeof(pt));
921 	pt.cmd.opc = NVME_OPC_IDENTIFY;
922 	pt.cmd.nsid = htole32(nsid);
923 	pt.cmd.cdw10 = htole32(0x11);
924 	pt.buf = &nsdata;
925 	pt.len = sizeof(nsdata);
926 	pt.is_read = 1;
927 
928 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
929 		err(1, "identify request failed");
930 
931 	if (nvme_completion_is_error(&pt.cpl))
932 		errx(1, "identify request returned error");
933 
934 	close(fd);
935 
936 	data = (uint8_t *)&nsdata;
937 	for (i = 0; i < sizeof(nsdata); i++) {
938 		if (data[i] != 0)
939 			break;
940 	}
941 	if (i == sizeof(nsdata))
942 		errx(1, "namespace %d is not allocated", nsid);
943 
944 	/* Convert data to host endian */
945 	nvme_namespace_data_swapbytes(&nsdata);
946 
947 	if (identify_opt.hex) {
948 		i = sizeof(struct nvme_namespace_data);
949 		if (!identify_opt.verbose) {
950 			for (; i > 384; i--) {
951 				if (data[i - 1] != 0)
952 					break;
953 			}
954 		}
955 		print_hex(&nsdata, i);
956 		exit(0);
957 	}
958 
959 	print_namespace(&nsdata);
960 	exit(0);
961 }
962 
963 static void
964 ns(const struct cmd *nf __unused, int argc, char *argv[])
965 {
966 
967 	cmd_dispatch(argc, argv, &ns_cmd);
968 }
969