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