2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2017 Netflix, Inc.
5 * Copyright (C) 2018-2019 Alexander Motin <mav@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/ioccom.h>
44 #include "nvmecontrol.h"
46 /* Tables for command line parsing */
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;
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 }
64 static struct cmd ns_cmd = {
67 .descr = "Namespace management commands",
75 static struct active_options {
81 static const struct args active_args[] = {
82 { arg_string, &active_opt.dev, "controller-id|namespace-id" },
83 { arg_none, NULL, NULL },
86 static struct cmd active_cmd = {
89 .descr = "List active (attached) namespaces",
90 .ctx_size = sizeof(active_opt),
95 CMD_SUBCOMMAND(ns_cmd, active_cmd);
97 static struct cmd allocated_cmd = {
100 .descr = "List allocated (created) namespaces",
101 .ctx_size = sizeof(active_opt),
106 CMD_SUBCOMMAND(ns_cmd, allocated_cmd);
108 static struct controllers_options {
110 } controllers_opt = {
114 static const struct args controllers_args[] = {
115 { arg_string, &controllers_opt.dev, "controller-id|namespace-id" },
116 { arg_none, NULL, NULL },
119 static struct cmd controllers_cmd = {
120 .name = "controllers",
122 .descr = "List all controllers in NVM subsystem",
123 .ctx_size = sizeof(controllers_opt),
125 .args = controllers_args,
128 CMD_SUBCOMMAND(ns_cmd, controllers_cmd);
130 static struct create_options {
140 // uint32_t block_size;
153 // .block_size = NONE,
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"),
180 static const struct args create_args[] = {
181 { arg_string, &create_opt.dev, "controller-id|namespace-id" },
182 { arg_none, NULL, NULL },
185 static struct cmd create_cmd = {
188 .descr = "Create a namespace",
189 .ctx_size = sizeof(create_opt),
194 CMD_SUBCOMMAND(ns_cmd, create_cmd);
196 static struct delete_options {
204 static const struct opts delete_opts[] = {
205 OPT("namespace-id", 'n', arg_uint32, delete_opt, nsid,
206 "The namespace ID to delete"),
210 static const struct args delete_args[] = {
211 { arg_string, &delete_opt.dev, "controller-id|namespace-id" },
212 { arg_none, NULL, NULL },
215 static struct cmd delete_cmd = {
218 .descr = "Delete a namespace",
219 .ctx_size = sizeof(delete_opt),
224 CMD_SUBCOMMAND(ns_cmd, delete_cmd);
226 static struct attach_options {
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"),
244 static const struct args attach_args[] = {
245 { arg_string, &attach_opt.dev, "controller-id|namespace-id" },
246 { arg_none, NULL, NULL },
249 static struct cmd attach_cmd = {
252 .descr = "Attach a controller to a namespace",
253 .ctx_size = sizeof(attach_opt),
258 CMD_SUBCOMMAND(ns_cmd, attach_cmd);
260 static struct attached_options {
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"),
274 static const struct args attached_args[] = {
275 { arg_string, &attached_opt.dev, "controller-id|namespace-id" },
276 { arg_none, NULL, NULL },
279 static struct cmd attached_cmd = {
282 .descr = "List controllers attached to a namespace",
283 .ctx_size = sizeof(attached_opt),
284 .opts = attached_opts,
285 .args = attached_args,
288 CMD_SUBCOMMAND(ns_cmd, attached_cmd);
290 static struct detach_options {
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"),
308 static const struct args detach_args[] = {
309 { arg_string, &detach_opt.dev, "controller-id|namespace-id" },
310 { arg_none, NULL, NULL },
313 static struct cmd detach_cmd = {
316 .descr = "Detach a controller from a namespace",
317 .ctx_size = sizeof(detach_opt),
322 CMD_SUBCOMMAND(ns_cmd, detach_cmd);
324 static struct identify_options {
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 }
346 static const struct args identify_args[] = {
347 { arg_string, &identify_opt.dev, "controller-id|namespace-id" },
348 { arg_none, NULL, NULL },
351 static struct cmd identify_cmd = {
354 .descr = "Print IDENTIFY for allocated namespace",
355 .ctx_size = sizeof(identify_opt),
356 .opts = identify_opts,
357 .args = identify_args,
360 CMD_SUBCOMMAND(ns_cmd, identify_cmd);
362 /* handles NVME_OPC_NAMESPACE_MANAGEMENT and ATTACHMENT admin cmds */
364 struct ns_result_str {
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"},
386 get_res_str(uint16_t res)
388 struct ns_result_str *t = ns_result;
390 while (t->res != 0xFFFF) {
399 nsactive(const struct cmd *f, int argc, char *argv[])
401 struct nvme_pt_command pt;
402 struct nvme_controller_data cd;
408 if (arg_parse(argc, argv, f))
410 open_dev(active_opt.dev, &fd, 0, 1);
411 get_nsid(fd, &path, &nsid);
414 open_dev(path, &fd, 0, 1);
417 read_controller_data(fd, &cd);
419 /* Check that controller can execute this command. */
420 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
421 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
422 errx(1, "controller does not support namespace management");
424 memset(&pt, 0, sizeof(pt));
425 pt.cmd.opc = NVME_OPC_IDENTIFY;
426 pt.cmd.nsid = htole32(0);
427 pt.cmd.cdw10 = htole32(0x02);
429 pt.len = sizeof(list);
431 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
432 err(1, "identify request failed");
433 if (nvme_completion_is_error(&pt.cpl))
434 errx(1, "identify request returned error");
436 printf("Active namespaces:\n");
437 for (i = 0; list[i] != 0; i++)
438 printf("%10d\n", le32toh(list[i]));
444 nsallocated(const struct cmd *f, int argc, char *argv[])
446 struct nvme_pt_command pt;
447 struct nvme_controller_data cd;
453 if (arg_parse(argc, argv, f))
455 open_dev(active_opt.dev, &fd, 0, 1);
456 get_nsid(fd, &path, &nsid);
459 open_dev(path, &fd, 0, 1);
462 read_controller_data(fd, &cd);
464 /* Check that controller can execute this command. */
465 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
466 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
467 errx(1, "controller does not support namespace management");
469 memset(&pt, 0, sizeof(pt));
470 pt.cmd.opc = NVME_OPC_IDENTIFY;
471 pt.cmd.nsid = htole32(0);
472 pt.cmd.cdw10 = htole32(0x10);
474 pt.len = sizeof(list);
476 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
477 err(1, "identify request failed");
478 if (nvme_completion_is_error(&pt.cpl))
479 errx(1, "identify request returned error");
481 printf("Allocated namespaces:\n");
482 for (i = 0; list[i] != 0; i++)
483 printf("%10d\n", le32toh(list[i]));
489 nscontrollers(const struct cmd *f, int argc, char *argv[])
491 struct nvme_pt_command pt;
492 struct nvme_controller_data cd;
496 uint16_t clist[2048];
498 if (arg_parse(argc, argv, f))
500 open_dev(controllers_opt.dev, &fd, 0, 1);
501 get_nsid(fd, &path, &nsid);
504 open_dev(path, &fd, 0, 1);
507 read_controller_data(fd, &cd);
509 /* Check that controller can execute this command. */
510 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
511 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
512 errx(1, "controller does not support namespace management");
514 memset(&pt, 0, sizeof(pt));
515 pt.cmd.opc = NVME_OPC_IDENTIFY;
516 pt.cmd.cdw10 = htole32(0x13);
518 pt.len = sizeof(clist);
520 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
521 err(1, "identify request failed");
522 if (nvme_completion_is_error(&pt.cpl))
523 errx(1, "identify request returned error");
525 n = le16toh(clist[0]);
526 printf("NVM subsystem includes %d controller(s):\n", n);
527 for (i = 0; i < n; i++)
528 printf(" 0x%04x\n", le16toh(clist[i + 1]));
534 * NS MGMT Command specific status values:
535 * 0xa = Invalid Format
536 * 0x15 = Namespace Insuffience capacity
537 * 0x16 = Namespace ID unavailable (number namespaces exceeded)
538 * 0xb = Thin Provisioning Not supported
541 nscreate(const struct cmd *f, int argc, char *argv[])
543 struct nvme_pt_command pt;
544 struct nvme_controller_data cd;
545 struct nvme_namespace_data nsdata;
550 if (arg_parse(argc, argv, f))
553 if (create_opt.cap == NONE64)
554 create_opt.cap = create_opt.nsze;
555 if (create_opt.nsze == NONE64) {
557 "Size not specified\n");
558 arg_help(argc, argv, f);
561 open_dev(create_opt.dev, &fd, 1, 1);
562 get_nsid(fd, &path, &nsid);
565 open_dev(path, &fd, 1, 1);
568 read_controller_data(fd, &cd);
570 /* Check that controller can execute this command. */
571 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
572 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
573 errx(1, "controller does not support namespace management");
575 /* Allow namespaces sharing if Multi-Path I/O is supported. */
576 if (create_opt.nmic == NONE) {
577 create_opt.nmic = cd.mic ? (NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK <<
578 NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT) : 0;
581 memset(&nsdata, 0, sizeof(nsdata));
582 nsdata.nsze = create_opt.nsze;
583 nsdata.ncap = create_opt.cap;
584 if (create_opt.flbas == NONE)
585 nsdata.flbas = ((create_opt.lbaf & NVME_NS_DATA_FLBAS_FORMAT_MASK)
586 << NVME_NS_DATA_FLBAS_FORMAT_SHIFT) |
587 ((create_opt.mset & NVME_NS_DATA_FLBAS_EXTENDED_MASK)
588 << NVME_NS_DATA_FLBAS_EXTENDED_SHIFT);
590 nsdata.flbas = create_opt.flbas;
591 if (create_opt.dps == NONE)
592 nsdata.dps = ((create_opt.pi & NVME_NS_DATA_DPS_MD_START_MASK)
593 << NVME_NS_DATA_DPS_MD_START_SHIFT) |
594 ((create_opt.pil & NVME_NS_DATA_DPS_PIT_MASK)
595 << NVME_NS_DATA_DPS_PIT_SHIFT);
597 nsdata.dps = create_opt.dps;
598 nsdata.nmic = create_opt.nmic;
599 nvme_namespace_data_swapbytes(&nsdata);
601 memset(&pt, 0, sizeof(pt));
602 pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
603 pt.cmd.cdw10 = htole32(0); /* create */
605 pt.len = sizeof(struct nvme_namespace_data);
606 pt.is_read = 0; /* passthrough writes data to ctrlr */
607 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
608 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
610 if (nvme_completion_is_error(&pt.cpl)) {
611 errx(1, "namespace creation failed: %s",
612 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
613 NVME_STATUS_SC_MASK));
615 printf("namespace %d created\n", pt.cpl.cdw0);
620 nsdelete(const struct cmd *f, int argc, char *argv[])
622 struct nvme_pt_command pt;
623 struct nvme_controller_data cd;
629 if (arg_parse(argc, argv, f))
632 open_dev(delete_opt.dev, &fd, 1, 1);
633 get_nsid(fd, &path, &nsid);
636 open_dev(path, &fd, 1, 1);
637 } else if (delete_opt.nsid == NONE) {
639 fprintf(stderr, "No NSID specified");
640 arg_help(argc, argv, f);
642 if (delete_opt.nsid != NONE)
643 nsid = delete_opt.nsid;
645 read_controller_data(fd, &cd);
647 /* Check that controller can execute this command. */
648 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
649 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
650 errx(1, "controller does not support namespace management");
652 memset(&pt, 0, sizeof(pt));
653 pt.cmd.opc = NVME_OPC_NAMESPACE_MANAGEMENT;
654 pt.cmd.cdw10 = htole32(1); /* delete */
656 pt.len = sizeof(buf);
660 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
661 errx(1, "ioctl request to %s failed: %d", delete_opt.dev, result);
663 if (nvme_completion_is_error(&pt.cpl)) {
664 errx(1, "namespace deletion failed: %s",
665 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
666 NVME_STATUS_SC_MASK));
668 printf("namespace %d deleted\n", nsid);
673 * Attach and Detach use Dword 10, and a controller list (section 4.9)
674 * This struct is 4096 bytes in size.
678 * Result values for both attach/detach:
680 * Completion 18h = Already attached
681 * 19h = NS is private and already attached to a controller
682 * 1Ah = Not attached, request could not be completed
683 * 1Ch = Controller list invalid.
685 * 0x2 Invalid Field can occur if ctrlrid d.n.e in system.
688 nsattach(const struct cmd *f, int argc, char *argv[])
690 struct nvme_pt_command pt;
691 struct nvme_controller_data cd;
695 uint16_t clist[2048];
697 if (arg_parse(argc, argv, f))
699 open_dev(attach_opt.dev, &fd, 1, 1);
700 get_nsid(fd, &path, &nsid);
703 open_dev(path, &fd, 1, 1);
704 } else if (attach_opt.nsid == NONE) {
706 fprintf(stderr, "No NSID specified");
707 arg_help(argc, argv, f);
709 if (attach_opt.nsid != NONE)
710 nsid = attach_opt.nsid;
711 read_controller_data(fd, &cd);
713 /* Check that controller can execute this command. */
714 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
715 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
716 errx(1, "controller does not support namespace management");
718 if (attach_opt.ctrlrid == NONE) {
719 /* Get full list of controllers to attach to. */
720 memset(&pt, 0, sizeof(pt));
721 pt.cmd.opc = NVME_OPC_IDENTIFY;
722 pt.cmd.cdw10 = htole32(0x13);
724 pt.len = sizeof(clist);
726 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
727 err(1, "identify request failed");
728 if (nvme_completion_is_error(&pt.cpl))
729 errx(1, "identify request returned error");
731 /* By default attach to this controller. */
732 if (attach_opt.ctrlrid == NONE - 1)
733 attach_opt.ctrlrid = cd.ctrlr_id;
734 memset(&clist, 0, sizeof(clist));
735 clist[0] = htole16(1);
736 clist[1] = htole16(attach_opt.ctrlrid);
739 memset(&pt, 0, sizeof(pt));
740 pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
741 pt.cmd.cdw10 = htole32(0); /* attach */
744 pt.len = sizeof(clist);
746 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
747 errx(1, "ioctl request to %s failed: %d", attach_opt.dev, result);
749 if (nvme_completion_is_error(&pt.cpl)) {
750 errx(1, "namespace attach failed: %s",
751 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
752 NVME_STATUS_SC_MASK));
754 printf("namespace %d attached\n", nsid);
759 nsdetach(const struct cmd *f, int argc, char *argv[])
761 struct nvme_pt_command pt;
762 struct nvme_controller_data cd;
766 uint16_t clist[2048];
768 if (arg_parse(argc, argv, f))
770 open_dev(detach_opt.dev, &fd, 1, 1);
771 get_nsid(fd, &path, &nsid);
774 open_dev(path, &fd, 1, 1);
775 } else if (detach_opt.nsid == NONE) {
777 fprintf(stderr, "No NSID specified");
778 arg_help(argc, argv, f);
780 if (detach_opt.nsid != NONE)
781 nsid = detach_opt.nsid;
782 read_controller_data(fd, &cd);
784 /* Check that controller can execute this command. */
785 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
786 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
787 errx(1, "controller does not support namespace management");
789 if (detach_opt.ctrlrid == NONE) {
790 /* Get list of controllers this namespace attached to. */
791 memset(&pt, 0, sizeof(pt));
792 pt.cmd.opc = NVME_OPC_IDENTIFY;
793 pt.cmd.nsid = htole32(nsid);
794 pt.cmd.cdw10 = htole32(0x12);
796 pt.len = sizeof(clist);
798 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
799 err(1, "identify request failed");
800 if (nvme_completion_is_error(&pt.cpl))
801 errx(1, "identify request returned error");
803 detach_opt.ctrlrid = cd.ctrlr_id;
804 memset(&clist, 0, sizeof(clist));
805 clist[0] = htole16(1);
806 clist[1] = htole16(detach_opt.ctrlrid);
809 /* By default detach from this controller. */
810 if (detach_opt.ctrlrid == NONE - 1)
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);
817 memset(&pt, 0, sizeof(pt));
818 pt.cmd.opc = NVME_OPC_NAMESPACE_ATTACHMENT;
819 pt.cmd.cdw10 = htole32(1); /* detach */
822 pt.len = sizeof(clist);
824 if ((result = ioctl(fd, NVME_PASSTHROUGH_CMD, &pt)) < 0)
825 errx(1, "ioctl request to %s failed: %d", argv[optind], result);
827 if (nvme_completion_is_error(&pt.cpl)) {
828 errx(1, "namespace detach failed: %s",
829 get_res_str((pt.cpl.status >> NVME_STATUS_SC_SHIFT) &
830 NVME_STATUS_SC_MASK));
832 printf("namespace %d detached\n", nsid);
837 nsattached(const struct cmd *f, int argc, char *argv[])
839 struct nvme_pt_command pt;
840 struct nvme_controller_data cd;
844 uint16_t clist[2048];
846 if (arg_parse(argc, argv, f))
848 open_dev(attached_opt.dev, &fd, 0, 1);
849 get_nsid(fd, &path, &nsid);
852 open_dev(path, &fd, 1, 1);
853 } else if (attached_opt.nsid == NONE) {
855 fprintf(stderr, "No NSID specified");
856 arg_help(argc, argv, f);
858 if (attached_opt.nsid != NONE)
859 nsid = attached_opt.nsid;
860 read_controller_data(fd, &cd);
862 /* Check that controller can execute this command. */
863 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
864 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
865 errx(1, "controller does not support namespace management");
867 memset(&pt, 0, sizeof(pt));
868 pt.cmd.opc = NVME_OPC_IDENTIFY;
869 pt.cmd.nsid = htole32(nsid);
870 pt.cmd.cdw10 = htole32(0x12);
872 pt.len = sizeof(clist);
874 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
875 err(1, "identify request failed");
876 if (nvme_completion_is_error(&pt.cpl))
877 errx(1, "identify request returned error");
879 n = le16toh(clist[0]);
880 printf("Attached %d controller(s):\n", n);
881 for (i = 0; i < n; i++)
882 printf(" 0x%04x\n", le16toh(clist[i + 1]));
888 nsidentify(const struct cmd *f, int argc, char *argv[])
890 struct nvme_pt_command pt;
891 struct nvme_controller_data cd;
892 struct nvme_namespace_data nsdata;
899 if (arg_parse(argc, argv, f))
901 open_dev(identify_opt.dev, &fd, 0, 1);
902 get_nsid(fd, &path, &nsid);
905 open_dev(path, &fd, 1, 1);
906 } else if (identify_opt.nsid == NONE) {
908 fprintf(stderr, "No NSID specified");
909 arg_help(argc, argv, f);
911 if (identify_opt.nsid != NONE)
912 nsid = identify_opt.nsid;
913 read_controller_data(fd, &cd);
915 /* Check that controller can execute this command. */
916 if (((cd.oacs >> NVME_CTRLR_DATA_OACS_NSMGMT_SHIFT) &
917 NVME_CTRLR_DATA_OACS_NSMGMT_MASK) == 0)
918 errx(1, "controller does not support namespace management");
920 memset(&pt, 0, sizeof(pt));
921 pt.cmd.opc = NVME_OPC_IDENTIFY;
922 pt.cmd.nsid = htole32(nsid);
923 pt.cmd.cdw10 = htole32(0x11);
925 pt.len = sizeof(nsdata);
928 if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
929 err(1, "identify request failed");
931 if (nvme_completion_is_error(&pt.cpl))
932 errx(1, "identify request returned error");
936 data = (uint8_t *)&nsdata;
937 for (i = 0; i < sizeof(nsdata); i++) {
941 if (i == sizeof(nsdata))
942 errx(1, "namespace %d is not allocated", nsid);
944 /* Convert data to host endian */
945 nvme_namespace_data_swapbytes(&nsdata);
947 if (identify_opt.hex) {
948 i = sizeof(struct nvme_namespace_data);
949 if (!identify_opt.verbose) {
950 for (; i > 384; i--) {
951 if (data[i - 1] != 0)
955 print_hex(&nsdata, i);
959 print_namespace(&nsdata);
964 ns(const struct cmd *nf __unused, int argc, char *argv[])
967 cmd_dispatch(argc, argv, &ns_cmd);