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