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