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