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