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