xref: /freebsd-14.2/sbin/nvmecontrol/ns.c (revision 37109ba0)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2017 Netflix, Inc.
5  * Copyright (C) 2018-2019 Alexander Motin <[email protected]>
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 *
get_res_str(uint16_t res)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
nsactive(const struct cmd * f,int argc,char * argv[])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 (NVMEV(NVME_CTRLR_DATA_OACS_NSMGMT, cd.oacs) == 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
nsallocated(const struct cmd * f,int argc,char * argv[])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 (NVMEV(NVME_CTRLR_DATA_OACS_NSMGMT, cd.oacs) == 0)
466 		errx(EX_UNAVAILABLE, "controller does not support namespace management");
467 
468 	memset(&pt, 0, sizeof(pt));
469 	pt.cmd.opc = NVME_OPC_IDENTIFY;
470 	pt.cmd.nsid = htole32(0);
471 	pt.cmd.cdw10 = htole32(0x10);
472 	pt.buf = list;
473 	pt.len = sizeof(list);
474 	pt.is_read = 1;
475 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
476 		err(EX_IOERR, "identify request failed");
477 	if (nvme_completion_is_error(&pt.cpl))
478 		errx(EX_IOERR, "identify request returned error");
479 
480 	printf("Allocated namespaces:\n");
481 	for (i = 0; list[i] != 0; i++)
482 		printf("%10d\n", le32toh(list[i]));
483 
484 	exit(0);
485 }
486 
487 static void
nscontrollers(const struct cmd * f,int argc,char * argv[])488 nscontrollers(const struct cmd *f, int argc, char *argv[])
489 {
490 	struct nvme_pt_command	pt;
491 	struct nvme_controller_data cd;
492 	int	fd, i, n;
493 	char	*path;
494 	uint32_t nsid;
495 	uint16_t clist[2048];
496 
497 	if (arg_parse(argc, argv, f))
498 		return;
499 	open_dev(controllers_opt.dev, &fd, 0, 1);
500 	get_nsid(fd, &path, &nsid);
501 	if (nsid != 0) {
502 		close(fd);
503 		open_dev(path, &fd, 0, 1);
504 	}
505 	free(path);
506 	if (read_controller_data(fd, &cd))
507 		errx(EX_IOERR, "Identify request failed");
508 
509 	/* Check that controller can execute this command. */
510 	if (NVMEV(NVME_CTRLR_DATA_OACS_NSMGMT, cd.oacs) == 0)
511 		errx(EX_UNAVAILABLE, "controller does not support namespace management");
512 
513 	memset(&pt, 0, sizeof(pt));
514 	pt.cmd.opc = NVME_OPC_IDENTIFY;
515 	pt.cmd.cdw10 = htole32(0x13);
516 	pt.buf = clist;
517 	pt.len = sizeof(clist);
518 	pt.is_read = 1;
519 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
520 		err(EX_IOERR, "identify request failed");
521 	if (nvme_completion_is_error(&pt.cpl))
522 		errx(EX_IOERR, "identify request returned error");
523 
524 	n = le16toh(clist[0]);
525 	printf("NVM subsystem includes %d controller(s):\n", n);
526 	for (i = 0; i < n; i++)
527 		printf("  0x%04x\n", le16toh(clist[i + 1]));
528 
529 	exit(0);
530 }
531 
532 /*
533  * NS MGMT Command specific status values:
534  * 0xa = Invalid Format
535  * 0x15 = Namespace Insufficient capacity
536  * 0x16 = Namespace ID  unavailable (number namespaces exceeded)
537  * 0xb = Thin Provisioning Not supported
538  */
539 static void
nscreate(const struct cmd * f,int argc,char * argv[])540 nscreate(const struct cmd *f, int argc, char *argv[])
541 {
542 	struct nvme_pt_command	pt;
543 	struct nvme_controller_data cd;
544 	struct nvme_namespace_data nsdata;
545 	int	fd, result;
546 	char	*path;
547 	uint32_t nsid;
548 
549 	if (arg_parse(argc, argv, f))
550 		return;
551 
552 	if (create_opt.cap == NONE64)
553 		create_opt.cap = create_opt.nsze;
554 	if (create_opt.nsze == NONE64) {
555 		fprintf(stderr,
556 		    "Size not specified\n");
557 		arg_help(argc, argv, f);
558 	}
559 
560 	open_dev(create_opt.dev, &fd, 1, 1);
561 	get_nsid(fd, &path, &nsid);
562 	if (nsid != 0) {
563 		close(fd);
564 		open_dev(path, &fd, 1, 1);
565 	}
566 	free(path);
567 	if (read_controller_data(fd, &cd))
568 		errx(EX_IOERR, "Identify request failed");
569 
570 	/* Check that controller can execute this command. */
571 	if (NVMEV(NVME_CTRLR_DATA_OACS_NSMGMT, cd.oacs) == 0)
572 		errx(EX_UNAVAILABLE, "controller does not support namespace management");
573 
574 	memset(&nsdata, 0, sizeof(nsdata));
575 	nsdata.nsze = create_opt.nsze;
576 	nsdata.ncap = create_opt.cap;
577 	if (create_opt.flbas != NONE) {
578 		nsdata.flbas = create_opt.flbas;
579 	} else {
580 		/* Default to the first format, whatever it is. */
581 		nsdata.flbas = 0;
582 		if (create_opt.lbaf != NONE) {
583 			nsdata.flbas |= NVMEF(NVME_NS_DATA_FLBAS_FORMAT,
584 			    create_opt.lbaf);
585 		}
586 		if (create_opt.mset != NONE) {
587 			nsdata.flbas |= NVMEF(NVME_NS_DATA_FLBAS_EXTENDED,
588 			    create_opt.mset);
589 		}
590 	}
591 	if (create_opt.dps != NONE) {
592 		nsdata.dps = create_opt.dps;
593 	} else {
594 		/* Default to protection disabled. */
595 		nsdata.dps = 0;
596 		if (create_opt.pi != NONE) {
597 			nsdata.dps |= NVMEF(NVME_NS_DATA_DPS_MD_START,
598 			    create_opt.pi);
599 		}
600 		if (create_opt.pil != NONE) {
601 			nsdata.dps |= NVMEF(NVME_NS_DATA_DPS_PIT,
602 			    create_opt.pil);
603 		}
604 	}
605 	if (create_opt.nmic != NONE) {
606 		nsdata.nmic = create_opt.nmic;
607 	} else {
608 		/* Allow namespaces sharing if Multi-Path I/O is supported. */
609 		nsdata.nmic = NVMEF(NVME_NS_DATA_NMIC_MAY_BE_SHARED, !!cd.mic);
610 	}
611 	nvme_namespace_data_swapbytes(&nsdata);
612 
613 	memset(&pt, 0, sizeof(pt));
614 	pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
615 	pt.cmd.cdw10 = htole32(0); /* create */
616 	pt.buf = &nsdata;
617 	pt.len = sizeof(struct nvme_namespace_data);
618 	pt.is_read = 0; /* passthrough writes data to ctrlr */
619 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
620 		errx(EX_IOERR, "ioctl request to %s failed: %d", create_opt.dev, result);
621 
622 	if (nvme_completion_is_error(&pt.cpl)) {
623 		errx(EX_IOERR, "namespace creation failed: %s",
624 		    get_res_str(NVMEV(NVME_STATUS_SC, pt.cpl.status)));
625 	}
626 	printf("namespace %d created\n", pt.cpl.cdw0);
627 	exit(0);
628 }
629 
630 static void
nsdelete(const struct cmd * f,int argc,char * argv[])631 nsdelete(const struct cmd *f, int argc, char *argv[])
632 {
633 	struct nvme_pt_command	pt;
634 	struct nvme_controller_data cd;
635 	int	fd, result;
636 	char	*path;
637 	uint32_t nsid;
638 	char buf[2];
639 
640 	if (arg_parse(argc, argv, f))
641 		return;
642 
643 	open_dev(delete_opt.dev, &fd, 1, 1);
644 	get_nsid(fd, &path, &nsid);
645 	if (nsid != 0) {
646 		close(fd);
647 		open_dev(path, &fd, 1, 1);
648 	} else if (delete_opt.nsid == NONE - 1) {
649 		close(fd);
650 		fprintf(stderr, "No NSID specified\n");
651 		arg_help(argc, argv, f);
652 	}
653 	if (delete_opt.nsid != NONE - 1)
654 		nsid = delete_opt.nsid;
655 	free(path);
656 	if (read_controller_data(fd, &cd))
657 		errx(EX_IOERR, "Identify request failed");
658 
659 	/* Check that controller can execute this command. */
660 	if (NVMEV(NVME_CTRLR_DATA_OACS_NSMGMT, cd.oacs) == 0)
661 		errx(EX_UNAVAILABLE, "controller does not support namespace management");
662 
663 	memset(&pt, 0, sizeof(pt));
664 	pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
665 	pt.cmd.cdw10 = htole32(1); /* delete */
666 	pt.buf = buf;
667 	pt.len = sizeof(buf);
668 	pt.is_read = 1;
669 	pt.cmd.nsid = nsid;
670 
671 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
672 		errx(EX_IOERR, "ioctl request to %s failed: %d", delete_opt.dev, result);
673 
674 	if (nvme_completion_is_error(&pt.cpl)) {
675 		errx(EX_IOERR, "namespace deletion failed: %s",
676 		    get_res_str(NVMEV(NVME_STATUS_SC, pt.cpl.status)));
677 	}
678 	printf("namespace %d deleted\n", nsid);
679 	exit(0);
680 }
681 
682 /*
683  * Attach and Detach use Dword 10, and a controller list (section 4.9)
684  * This struct is 4096 bytes in size.
685  * 0h = attach
686  * 1h = detach
687  *
688  * Result values for both attach/detach:
689  *
690  * Completion 18h = Already attached
691  *            19h = NS is private and already attached to a controller
692  *            1Ah = Not attached, request could not be completed
693  *            1Ch = Controller list invalid.
694  *
695  * 0x2 Invalid Field can occur if ctrlrid d.n.e in system.
696  */
697 static void
nsattach(const struct cmd * f,int argc,char * argv[])698 nsattach(const struct cmd *f, int argc, char *argv[])
699 {
700 	struct nvme_pt_command	pt;
701 	struct nvme_controller_data cd;
702 	int	fd, result;
703 	char	*path;
704 	uint32_t nsid;
705 	uint16_t clist[2048];
706 
707 	if (arg_parse(argc, argv, f))
708 		return;
709 	open_dev(attach_opt.dev, &fd, 1, 1);
710 	get_nsid(fd, &path, &nsid);
711 	if (nsid != 0) {
712 		close(fd);
713 		open_dev(path, &fd, 1, 1);
714 	} else if (attach_opt.nsid == NONE) {
715 		close(fd);
716 		fprintf(stderr, "No NSID specified\n");
717 		arg_help(argc, argv, f);
718 	}
719 	if (attach_opt.nsid != NONE)
720 		nsid = attach_opt.nsid;
721 	if (read_controller_data(fd, &cd))
722 		errx(EX_IOERR, "Identify request failed");
723 
724 	/* Check that controller can execute this command. */
725 	if (NVMEV(NVME_CTRLR_DATA_OACS_NSMGMT, cd.oacs) == 0)
726 		errx(EX_UNAVAILABLE, "controller does not support namespace management");
727 
728 	if (attach_opt.ctrlrid == NONE) {
729 		/* Get full list of controllers to attach to. */
730 		memset(&pt, 0, sizeof(pt));
731 		pt.cmd.opc = NVME_OPC_IDENTIFY;
732 		pt.cmd.cdw10 = htole32(0x13);
733 		pt.buf = clist;
734 		pt.len = sizeof(clist);
735 		pt.is_read = 1;
736 		if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
737 			err(EX_IOERR, "identify request failed");
738 		if (nvme_completion_is_error(&pt.cpl))
739 			errx(EX_IOERR, "identify request returned error");
740 	} else {
741 		/* By default attach to this controller. */
742 		if (attach_opt.ctrlrid == NONE - 1)
743 			attach_opt.ctrlrid = cd.ctrlr_id;
744 		memset(&clist, 0, sizeof(clist));
745 		clist[0] = htole16(1);
746 		clist[1] = htole16(attach_opt.ctrlrid);
747 	}
748 
749 	memset(&pt, 0, sizeof(pt));
750 	pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
751 	pt.cmd.cdw10 = htole32(0); /* attach */
752 	pt.cmd.nsid = nsid;
753 	pt.buf = &clist;
754 	pt.len = sizeof(clist);
755 
756 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
757 		errx(EX_IOERR, "ioctl request to %s failed: %d", attach_opt.dev, result);
758 
759 	if (nvme_completion_is_error(&pt.cpl)) {
760 		errx(EX_IOERR, "namespace attach failed: %s",
761 		    get_res_str(NVMEV(NVME_STATUS_SC, pt.cpl.status)));
762 	}
763 	printf("namespace %d attached\n", nsid);
764 	exit(0);
765 }
766 
767 static void
nsdetach(const struct cmd * f,int argc,char * argv[])768 nsdetach(const struct cmd *f, int argc, char *argv[])
769 {
770 	struct nvme_pt_command	pt;
771 	struct nvme_controller_data cd;
772 	int	fd, result;
773 	char	*path;
774 	uint32_t nsid;
775 	uint16_t clist[2048];
776 
777 	if (arg_parse(argc, argv, f))
778 		return;
779 	open_dev(detach_opt.dev, &fd, 1, 1);
780 	get_nsid(fd, &path, &nsid);
781 	if (nsid != 0) {
782 		close(fd);
783 		open_dev(path, &fd, 1, 1);
784 	} else if (detach_opt.nsid == NONE) {
785 		close(fd);
786 		fprintf(stderr, "No NSID specified\n");
787 		arg_help(argc, argv, f);
788 	}
789 	if (detach_opt.nsid != NONE)
790 		nsid = detach_opt.nsid;
791 	if (read_controller_data(fd, &cd))
792 		errx(EX_IOERR, "Identify request failed");
793 
794 	/* Check that controller can execute this command. */
795 	if (NVMEV(NVME_CTRLR_DATA_OACS_NSMGMT, cd.oacs) == 0)
796 		errx(EX_UNAVAILABLE, "controller does not support namespace management");
797 
798 	if (detach_opt.ctrlrid == NONE) {
799 		/* Get list of controllers this namespace attached to. */
800 		memset(&pt, 0, sizeof(pt));
801 		pt.cmd.opc = NVME_OPC_IDENTIFY;
802 		pt.cmd.nsid = htole32(nsid);
803 		pt.cmd.cdw10 = htole32(0x12);
804 		pt.buf = clist;
805 		pt.len = sizeof(clist);
806 		pt.is_read = 1;
807 		if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
808 			err(EX_IOERR, "identify request failed");
809 		if (nvme_completion_is_error(&pt.cpl))
810 			errx(EX_IOERR, "identify request returned error");
811 		if (clist[0] == 0) {
812 			detach_opt.ctrlrid = cd.ctrlr_id;
813 			memset(&clist, 0, sizeof(clist));
814 			clist[0] = htole16(1);
815 			clist[1] = htole16(detach_opt.ctrlrid);
816 		}
817 	} else {
818 		/* By default detach from this controller. */
819 		if (detach_opt.ctrlrid == NONE - 1)
820 			detach_opt.ctrlrid = cd.ctrlr_id;
821 		memset(&clist, 0, sizeof(clist));
822 		clist[0] = htole16(1);
823 		clist[1] = htole16(detach_opt.ctrlrid);
824 	}
825 
826 	memset(&pt, 0, sizeof(pt));
827 	pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
828 	pt.cmd.cdw10 = htole32(1); /* detach */
829 	pt.cmd.nsid = nsid;
830 	pt.buf = &clist;
831 	pt.len = sizeof(clist);
832 
833 	if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
834 		errx(EX_IOERR, "ioctl request to %s failed: %d", detach_opt.dev, result);
835 
836 	if (nvme_completion_is_error(&pt.cpl)) {
837 		errx(EX_IOERR, "namespace detach failed: %s",
838 		    get_res_str(NVMEV(NVME_STATUS_SC, pt.cpl.status)));
839 	}
840 	printf("namespace %d detached\n", nsid);
841 	exit(0);
842 }
843 
844 static void
nsattached(const struct cmd * f,int argc,char * argv[])845 nsattached(const struct cmd *f, int argc, char *argv[])
846 {
847 	struct nvme_pt_command	pt;
848 	struct nvme_controller_data cd;
849 	int	fd, i, n;
850 	char	*path;
851 	uint32_t nsid;
852 	uint16_t clist[2048];
853 
854 	if (arg_parse(argc, argv, f))
855 		return;
856 	open_dev(attached_opt.dev, &fd, 0, 1);
857 	get_nsid(fd, &path, &nsid);
858 	if (nsid != 0) {
859 		close(fd);
860 		open_dev(path, &fd, 1, 1);
861 	} else if (attached_opt.nsid == NONE) {
862 		close(fd);
863 		fprintf(stderr, "No NSID specified\n");
864 		arg_help(argc, argv, f);
865 	}
866 	if (attached_opt.nsid != NONE)
867 		nsid = attached_opt.nsid;
868 	if (read_controller_data(fd, &cd))
869 		errx(EX_IOERR, "Identify request failed");
870 
871 	/* Check that controller can execute this command. */
872 	if (NVMEV(NVME_CTRLR_DATA_OACS_NSMGMT, cd.oacs) == 0)
873 		errx(EX_UNAVAILABLE, "controller does not support namespace management");
874 
875 	memset(&pt, 0, sizeof(pt));
876 	pt.cmd.opc = NVME_OPC_IDENTIFY;
877 	pt.cmd.nsid = htole32(nsid);
878 	pt.cmd.cdw10 = htole32(0x12);
879 	pt.buf = clist;
880 	pt.len = sizeof(clist);
881 	pt.is_read = 1;
882 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
883 		err(EX_IOERR, "identify request failed");
884 	if (nvme_completion_is_error(&pt.cpl))
885 		errx(EX_IOERR, "identify request returned error");
886 
887 	n = le16toh(clist[0]);
888 	printf("Attached %d controller(s):\n", n);
889 	for (i = 0; i < n; i++)
890 		printf("  0x%04x\n", le16toh(clist[i + 1]));
891 
892 	exit(0);
893 }
894 
895 static void
nsidentify(const struct cmd * f,int argc,char * argv[])896 nsidentify(const struct cmd *f, int argc, char *argv[])
897 {
898 	struct nvme_pt_command	pt;
899 	struct nvme_controller_data cd;
900 	struct nvme_namespace_data nsdata;
901 	uint8_t	*data;
902 	int	fd;
903 	char	*path;
904 	uint32_t nsid;
905 	u_int	i;
906 
907 	if (arg_parse(argc, argv, f))
908 		return;
909 	open_dev(identify_opt.dev, &fd, 0, 1);
910 	get_nsid(fd, &path, &nsid);
911 	if (nsid != 0) {
912 		close(fd);
913 		open_dev(path, &fd, 1, 1);
914 	} else if (identify_opt.nsid == NONE) {
915 		close(fd);
916 		fprintf(stderr, "No NSID specified\n");
917 		arg_help(argc, argv, f);
918 	}
919 	if (identify_opt.nsid != NONE)
920 		nsid = identify_opt.nsid;
921 	if (read_controller_data(fd, &cd))
922 		errx(EX_IOERR, "Identify request failed");
923 
924 	/* Check that controller can execute this command. */
925 	if (NVMEV(NVME_CTRLR_DATA_OACS_NSMGMT, cd.oacs) == 0)
926 		errx(EX_UNAVAILABLE, "controller does not support namespace management");
927 
928 	memset(&pt, 0, sizeof(pt));
929 	pt.cmd.opc = NVME_OPC_IDENTIFY;
930 	pt.cmd.nsid = htole32(nsid);
931 	pt.cmd.cdw10 = htole32(0x11);
932 	pt.buf = &nsdata;
933 	pt.len = sizeof(nsdata);
934 	pt.is_read = 1;
935 
936 	if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
937 		err(EX_IOERR, "identify request failed");
938 
939 	if (nvme_completion_is_error(&pt.cpl))
940 		errx(EX_IOERR, "identify request returned error");
941 
942 	close(fd);
943 
944 	data = (uint8_t *)&nsdata;
945 	for (i = 0; i < sizeof(nsdata); i++) {
946 		if (data[i] != 0)
947 			break;
948 	}
949 	if (i == sizeof(nsdata))
950 		errx(EX_UNAVAILABLE, "namespace %d is not allocated", nsid);
951 
952 	/* Convert data to host endian */
953 	nvme_namespace_data_swapbytes(&nsdata);
954 
955 	if (identify_opt.hex) {
956 		i = sizeof(struct nvme_namespace_data);
957 		if (!identify_opt.verbose) {
958 			for (; i > 384; i--) {
959 				if (data[i - 1] != 0)
960 					break;
961 			}
962 		}
963 		print_hex(&nsdata, i);
964 		exit(0);
965 	}
966 
967 	print_namespace(&nsdata);
968 	exit(0);
969 }
970 
971 static void
ns(const struct cmd * nf __unused,int argc,char * argv[])972 ns(const struct cmd *nf __unused, int argc, char *argv[])
973 {
974 
975 	cmd_dispatch(argc, argv, &ns_cmd);
976 }
977