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