2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright 2016 Nexenta Systems, Inc.
17 * nvmeadm -- NVMe administration utility
19 * nvmeadm [-v] [-d] [-h] <command> [<ctl>[/<ns>][,...]] [args]
22 * get-logpage <logpage name>
23 * get-features <feature>[,...]
31 * activate-firmware ...
32 * write-uncorrectable ...
34 * compare-and-write ...
42 #include <sys/sunddi.h>
43 #include <libdevinfo.h>
49 typedef struct nvme_process_arg nvme_process_arg_t
;
50 typedef struct nvme_feature nvme_feature_t
;
51 typedef struct nvmeadm_cmd nvmeadm_cmd_t
;
53 struct nvme_process_arg
{
59 const nvmeadm_cmd_t
*npa_cmd
;
64 nvme_identify_ctrl_t
*npa_idctl
;
65 nvme_identify_nsid_t
*npa_idns
;
66 nvme_version_t
*npa_version
;
75 int (*f_get
)(int, const nvme_feature_t
*, nvme_identify_ctrl_t
*);
76 void (*f_print
)(uint64_t, void *, size_t, nvme_identify_ctrl_t
*);
79 #define NVMEADM_CTRL 1
81 #define NVMEADM_BOTH (NVMEADM_CTRL | NVMEADM_NS)
87 int (*c_func
)(int, const nvme_process_arg_t
*);
88 void (*c_usage
)(const char *);
93 static void usage(const nvmeadm_cmd_t
*);
94 static void nvme_walk(nvme_process_arg_t
*, di_node_t
);
95 static boolean_t
nvme_match(nvme_process_arg_t
*);
97 static int nvme_process(di_node_t
, di_minor_t
, void *);
99 static int do_list(int, const nvme_process_arg_t
*);
100 static int do_identify(int, const nvme_process_arg_t
*);
101 static int do_get_logpage_error(int, const nvme_process_arg_t
*);
102 static int do_get_logpage_health(int, const nvme_process_arg_t
*);
103 static int do_get_logpage_fwslot(int, const nvme_process_arg_t
*);
104 static int do_get_logpage(int, const nvme_process_arg_t
*);
105 static int do_get_feat_common(int, const nvme_feature_t
*,
106 nvme_identify_ctrl_t
*);
107 static int do_get_feat_intr_vect(int, const nvme_feature_t
*,
108 nvme_identify_ctrl_t
*);
109 static int do_get_features(int, const nvme_process_arg_t
*);
110 static int do_format(int, const nvme_process_arg_t
*);
111 static int do_secure_erase(int, const nvme_process_arg_t
*);
112 static int do_attach_detach(int, const nvme_process_arg_t
*);
114 static void usage_list(const char *);
115 static void usage_identify(const char *);
116 static void usage_get_logpage(const char *);
117 static void usage_get_features(const char *);
118 static void usage_format(const char *);
119 static void usage_secure_erase(const char *);
120 static void usage_attach_detach(const char *);
127 static const nvmeadm_cmd_t nvmeadm_cmds
[] = {
130 "list controllers and namespaces",
132 do_list
, usage_list
, B_TRUE
136 "identify controllers and/or namespaces",
138 do_identify
, usage_identify
, B_TRUE
142 "get a log page from controllers and/or namespaces",
144 do_get_logpage
, usage_get_logpage
, B_TRUE
148 "get features from controllers and/or namespaces",
150 do_get_features
, usage_get_features
, B_TRUE
154 "format namespace(s) of a controller",
156 do_format
, usage_format
, B_FALSE
160 "secure erase namespace(s) of a controller",
161 " -c Do a cryptographic erase.",
162 do_secure_erase
, usage_secure_erase
, B_FALSE
166 "detach blkdev(7d) from namespace(s) of a controller",
168 do_attach_detach
, usage_attach_detach
, B_FALSE
172 "attach blkdev(7d) to namespace(s) of a controller",
174 do_attach_detach
, usage_attach_detach
, B_FALSE
182 static const nvme_feature_t features
[] = {
184 NVME_FEAT_ARBITRATION
, 0, NVMEADM_CTRL
,
185 do_get_feat_common
, nvme_print_feat_arbitration
},
186 { "Power Management", "",
187 NVME_FEAT_POWER_MGMT
, 0, NVMEADM_CTRL
,
188 do_get_feat_common
, nvme_print_feat_power_mgmt
},
189 { "LBA Range Type", "range",
190 NVME_FEAT_LBA_RANGE
, NVME_LBA_RANGE_BUFSIZE
, NVMEADM_NS
,
191 do_get_feat_common
, nvme_print_feat_lba_range
},
192 { "Temperature Threshold", "",
193 NVME_FEAT_TEMPERATURE
, 0, NVMEADM_CTRL
,
194 do_get_feat_common
, nvme_print_feat_temperature
},
195 { "Error Recovery", "",
196 NVME_FEAT_ERROR
, 0, NVMEADM_CTRL
,
197 do_get_feat_common
, nvme_print_feat_error
},
198 { "Volatile Write Cache", "cache",
199 NVME_FEAT_WRITE_CACHE
, 0, NVMEADM_CTRL
,
200 do_get_feat_common
, nvme_print_feat_write_cache
},
201 { "Number of Queues", "queues",
202 NVME_FEAT_NQUEUES
, 0, NVMEADM_CTRL
,
203 do_get_feat_common
, nvme_print_feat_nqueues
},
204 { "Interrupt Coalescing", "coalescing",
205 NVME_FEAT_INTR_COAL
, 0, NVMEADM_CTRL
,
206 do_get_feat_common
, nvme_print_feat_intr_coal
},
207 { "Interrupt Vector Configuration", "vector",
208 NVME_FEAT_INTR_VECT
, 0, NVMEADM_CTRL
,
209 do_get_feat_intr_vect
, nvme_print_feat_intr_vect
},
210 { "Write Atomicity", "atomicity",
211 NVME_FEAT_WRITE_ATOM
, 0, NVMEADM_CTRL
,
212 do_get_feat_common
, nvme_print_feat_write_atom
},
213 { "Asynchronous Event Configuration", "event",
214 NVME_FEAT_ASYNC_EVENT
, 0, NVMEADM_CTRL
,
215 do_get_feat_common
, nvme_print_feat_async_event
},
216 { "Autonomous Power State Transition", "",
217 NVME_FEAT_AUTO_PST
, NVME_AUTO_PST_BUFSIZE
, NVMEADM_CTRL
,
218 do_get_feat_common
, nvme_print_feat_auto_pst
},
219 { "Software Progress Marker", "progress",
220 NVME_FEAT_PROGRESS
, 0, NVMEADM_CTRL
,
221 do_get_feat_common
, nvme_print_feat_progress
},
222 { NULL
, NULL
, 0, 0, B_FALSE
, NULL
}
227 main(int argc
, char **argv
)
231 const nvmeadm_cmd_t
*cmd
;
233 nvme_process_arg_t npa
= { 0 };
235 char *tmp
, *lasts
= NULL
;
237 while ((c
= getopt(argc
, argv
, "dhv")) != -1) {
254 if (optind
== argc
) {
262 /* Look up the specified command in the command table. */
263 for (cmd
= &nvmeadm_cmds
[0]; cmd
->c_name
!= NULL
; cmd
++)
264 if (strcmp(cmd
->c_name
, argv
[optind
]) == 0)
267 if (cmd
->c_name
== NULL
) {
282 * All commands but "list" require a ctl/ns argument.
284 if ((optind
== argc
|| (strncmp(argv
[optind
], "nvme", 4) != 0)) &&
285 cmd
->c_func
!= do_list
) {
286 warnx("missing controller/namespace name");
292 /* Store the remaining arguments for use by the command. */
293 npa
.npa_argc
= argc
- optind
- 1;
294 npa
.npa_argv
= &argv
[optind
+ 1];
297 * Make sure we're not running commands on multiple controllers that
298 * aren't allowed to do that.
300 if (argv
[optind
] != NULL
&& strchr(argv
[optind
], ',') != NULL
&&
301 cmd
->c_multi
== B_FALSE
) {
302 warnx("%s not allowed on multiple controllers",
309 * Get controller/namespace arguments and run command.
311 npa
.npa_name
= strtok_r(argv
[optind
], ",", &lasts
);
313 if (npa
.npa_name
!= NULL
) {
314 tmp
= strchr(npa
.npa_name
, '/');
319 nsid
= strtoul(tmp
, NULL
, 10);
320 if (nsid
>= UINT32_MAX
|| errno
!= 0) {
321 warn("invalid namespace %s", tmp
);
326 warnx("invalid namespace %s", tmp
);
331 npa
.npa_isns
= B_TRUE
;
335 if ((node
= di_init("/", DINFOSUBTREE
| DINFOMINOR
)) == NULL
)
336 err(-1, "failed to initialize libdevinfo");
337 nvme_walk(&npa
, node
);
341 if (npa
.npa_name
!= NULL
) {
342 warnx("%s%.*s%.*d: no such controller or "
343 "namespace", npa
.npa_name
,
344 npa
.npa_nsid
> 0 ? -1 : 0, "/",
345 npa
.npa_nsid
> 0 ? -1 : 0, npa
.npa_nsid
);
347 warnx("no controllers found");
352 npa
.npa_name
= strtok_r(NULL
, ",", &lasts
);
353 } while (npa
.npa_name
!= NULL
);
359 usage(const nvmeadm_cmd_t
*cmd
)
361 (void) fprintf(stderr
, "usage:\n");
362 (void) fprintf(stderr
, " %s -h %s\n", getprogname(),
363 cmd
!= NULL
? cmd
->c_name
: "[<command>]");
364 (void) fprintf(stderr
, " %s [-dv] ", getprogname());
367 cmd
->c_usage(cmd
->c_name
);
369 (void) fprintf(stderr
,
370 "<command> <ctl>[/<ns>][,...] [<args>]\n");
371 (void) fprintf(stderr
,
372 "\n Manage NVMe controllers and namespaces.\n");
373 (void) fprintf(stderr
, "\ncommands:\n");
375 for (cmd
= &nvmeadm_cmds
[0]; cmd
->c_name
!= NULL
; cmd
++)
376 (void) fprintf(stderr
, " %-15s - %s\n",
377 cmd
->c_name
, cmd
->c_desc
);
379 (void) fprintf(stderr
, "\nflags:\n"
380 " -h print usage information\n"
381 " -d print information useful for debugging %s\n"
382 " -v print verbose information\n", getprogname());
383 if (cmd
!= NULL
&& cmd
->c_flagdesc
!= NULL
)
384 (void) fprintf(stderr
, "%s\n", cmd
->c_flagdesc
);
388 nvme_match(nvme_process_arg_t
*npa
)
393 if (npa
->npa_name
== NULL
)
396 if (asprintf(&name
, "%s%d", di_driver_name(npa
->npa_node
),
397 di_instance(npa
->npa_node
)) < 0)
398 err(-1, "nvme_match()");
400 if (strcmp(name
, npa
->npa_name
) != 0) {
408 if (npa
->npa_nsid
== 0)
410 nsid
= strtoul(di_minor_name(npa
->npa_minor
), NULL
, 10);
413 if (npa
->npa_isns
&& npa
->npa_nsid
!= nsid
)
420 nvme_dskname(const nvme_process_arg_t
*npa
)
429 for (child
= di_child_node(npa
->npa_node
);
430 child
!= DI_NODE_NIL
;
431 child
= di_sibling_node(child
)) {
432 addr
= di_bus_addr(child
);
439 if (strncasecmp(addr
, di_minor_name(npa
->npa_minor
),
440 strchrnul(addr
, ',') - addr
) != 0)
443 path
= di_dim_path_dev(dim
, di_driver_name(child
),
444 di_instance(child
), "c");
447 path
[strlen(path
) - 2] = '\0';
448 path
= strrchr(path
, '/') + 1;
452 err(-1, "nvme_dskname");
464 nvme_process(di_node_t node
, di_minor_t minor
, void *arg
)
466 nvme_process_arg_t
*npa
= arg
;
469 npa
->npa_node
= node
;
470 npa
->npa_minor
= minor
;
472 if (!nvme_match(npa
))
473 return (DI_WALK_CONTINUE
);
475 if ((fd
= nvme_open(minor
)) < 0)
476 return (DI_WALK_CONTINUE
);
480 npa
->npa_path
= di_devfs_path(node
);
481 if (npa
->npa_path
== NULL
)
484 npa
->npa_version
= nvme_version(fd
);
485 if (npa
->npa_version
== NULL
)
488 npa
->npa_idctl
= nvme_identify_ctrl(fd
);
489 if (npa
->npa_idctl
== NULL
)
492 npa
->npa_idns
= nvme_identify_nsid(fd
);
493 if (npa
->npa_idns
== NULL
)
497 npa
->npa_dsk
= nvme_dskname(npa
);
499 exitcode
+= npa
->npa_cmd
->c_func(fd
, npa
);
502 di_devfs_path_free(npa
->npa_path
);
504 free(npa
->npa_version
);
505 free(npa
->npa_idctl
);
508 npa
->npa_version
= NULL
;
509 npa
->npa_idctl
= NULL
;
510 npa
->npa_idns
= NULL
;
514 return (DI_WALK_CONTINUE
);
518 nvme_walk(nvme_process_arg_t
*npa
, di_node_t node
)
520 char *minor_nodetype
= DDI_NT_NVME_NEXUS
;
523 minor_nodetype
= DDI_NT_NVME_ATTACHMENT_POINT
;
525 (void) di_walk_minor(node
, minor_nodetype
, 0, npa
, nvme_process
);
529 usage_list(const char *c_name
)
531 (void) fprintf(stderr
, "%s [<ctl>[/<ns>][,...]\n\n"
532 " List NVMe controllers and their namespaces. If no "
533 "controllers and/or name-\n spaces are specified, all "
534 "controllers and namespaces in the system will be\n "
535 "listed.\n", c_name
);
539 do_list_nsid(int fd
, const nvme_process_arg_t
*npa
)
541 _NOTE(ARGUNUSED(fd
));
543 (void) printf(" %s/%s (%s): ", npa
->npa_name
,
544 di_minor_name(npa
->npa_minor
),
545 npa
->npa_dsk
!= NULL
? npa
->npa_dsk
: "unattached");
546 nvme_print_nsid_summary(npa
->npa_idns
);
552 do_list(int fd
, const nvme_process_arg_t
*npa
)
554 _NOTE(ARGUNUSED(fd
));
556 nvme_process_arg_t ns_npa
= { 0 };
557 nvmeadm_cmd_t cmd
= { 0 };
560 if (asprintf(&name
, "%s%d", di_driver_name(npa
->npa_node
),
561 di_instance(npa
->npa_node
)) < 0)
562 err(-1, "do_list()");
564 (void) printf("%s: ", name
);
565 nvme_print_ctrl_summary(npa
->npa_idctl
, npa
->npa_version
);
567 ns_npa
.npa_name
= name
;
568 ns_npa
.npa_isns
= B_TRUE
;
569 ns_npa
.npa_nsid
= npa
->npa_nsid
;
570 cmd
= *(npa
->npa_cmd
);
571 cmd
.c_func
= do_list_nsid
;
572 ns_npa
.npa_cmd
= &cmd
;
574 nvme_walk(&ns_npa
, npa
->npa_node
);
582 usage_identify(const char *c_name
)
584 (void) fprintf(stderr
, "%s <ctl>[/<ns>][,...]\n\n"
585 " Print detailed information about the specified NVMe "
586 "controllers and/or name-\n spaces.\n", c_name
);
590 do_identify(int fd
, const nvme_process_arg_t
*npa
)
592 if (npa
->npa_nsid
== 0) {
593 nvme_capabilities_t
*cap
;
595 cap
= nvme_capabilities(fd
);
599 (void) printf("%s: ", npa
->npa_name
);
600 nvme_print_identify_ctrl(npa
->npa_idctl
, cap
,
605 (void) printf("%s/%s: ", npa
->npa_name
,
606 di_minor_name(npa
->npa_minor
));
607 nvme_print_identify_nsid(npa
->npa_idns
,
615 usage_get_logpage(const char *c_name
)
617 (void) fprintf(stderr
, "%s <ctl>[/<ns>][,...] <logpage>\n\n"
618 " Print the specified log page of the specified NVMe "
619 "controllers and/or name-\n spaces. Supported log pages "
620 "are error, health, and firmware.\n", c_name
);
624 do_get_logpage_error(int fd
, const nvme_process_arg_t
*npa
)
626 int nlog
= npa
->npa_idctl
->id_elpe
+ 1;
627 size_t bufsize
= sizeof (nvme_error_log_entry_t
) * nlog
;
628 nvme_error_log_entry_t
*elog
;
630 if (npa
->npa_nsid
!= 0)
631 errx(-1, "Error Log not available on a per-namespace basis");
633 elog
= nvme_get_logpage(fd
, NVME_LOGPAGE_ERROR
, &bufsize
);
638 nlog
= bufsize
/ sizeof (nvme_error_log_entry_t
);
640 (void) printf("%s: ", npa
->npa_name
);
641 nvme_print_error_log(nlog
, elog
);
649 do_get_logpage_health(int fd
, const nvme_process_arg_t
*npa
)
651 size_t bufsize
= sizeof (nvme_health_log_t
);
652 nvme_health_log_t
*hlog
;
654 if (npa
->npa_nsid
!= 0) {
655 if (npa
->npa_idctl
->id_lpa
.lp_smart
== 0)
656 errx(-1, "SMART/Health information not available "
657 "on a per-namespace basis on this controller");
660 hlog
= nvme_get_logpage(fd
, NVME_LOGPAGE_HEALTH
, &bufsize
);
665 (void) printf("%s: ", npa
->npa_name
);
666 nvme_print_health_log(hlog
, npa
->npa_idctl
);
674 do_get_logpage_fwslot(int fd
, const nvme_process_arg_t
*npa
)
676 size_t bufsize
= sizeof (nvme_fwslot_log_t
);
677 nvme_fwslot_log_t
*fwlog
;
679 if (npa
->npa_nsid
!= 0)
680 errx(-1, "Firmware Slot information not available on a "
681 "per-namespace basis");
683 fwlog
= nvme_get_logpage(fd
, NVME_LOGPAGE_FWSLOT
, &bufsize
);
688 (void) printf("%s: ", npa
->npa_name
);
689 nvme_print_fwslot_log(fwlog
);
697 do_get_logpage(int fd
, const nvme_process_arg_t
*npa
)
700 int (*func
)(int, const nvme_process_arg_t
*);
702 if (npa
->npa_argc
< 1) {
703 warnx("missing logpage name");
708 if (strcmp(npa
->npa_argv
[0], "error") == 0)
709 func
= do_get_logpage_error
;
710 else if (strcmp(npa
->npa_argv
[0], "health") == 0)
711 func
= do_get_logpage_health
;
712 else if (strcmp(npa
->npa_argv
[0], "firmware") == 0)
713 func
= do_get_logpage_fwslot
;
715 errx(-1, "invalid log page: %s", npa
->npa_argv
[0]);
722 usage_get_features(const char *c_name
)
724 const nvme_feature_t
*feat
;
726 (void) fprintf(stderr
, "%s <ctl>[/<ns>][,...] [<feature>[,...]]\n\n"
727 " Print the specified features of the specified NVMe controllers "
728 "and/or\n namespaces. Supported features are:\n\n", c_name
);
729 (void) fprintf(stderr
, " %-35s %-14s %s\n",
730 "FEATURE NAME", "SHORT NAME", "CONTROLLER/NAMESPACE");
731 for (feat
= &features
[0]; feat
->f_feature
!= 0; feat
++) {
734 if ((feat
->f_getflags
& NVMEADM_BOTH
) == NVMEADM_BOTH
)
736 else if ((feat
->f_getflags
& NVMEADM_CTRL
) != 0)
737 type
= "controller only";
739 type
= "namespace only";
741 (void) fprintf(stderr
, " %-35s %-14s %s\n",
742 feat
->f_name
, feat
->f_short
, type
);
748 do_get_feat_common(int fd
, const nvme_feature_t
*feat
,
749 nvme_identify_ctrl_t
*idctl
)
752 size_t bufsize
= feat
->f_bufsize
;
755 if (nvme_get_feature(fd
, feat
->f_feature
, 0, &res
, &bufsize
, &buf
)
759 nvme_print(2, feat
->f_name
, -1, NULL
);
760 feat
->f_print(res
, buf
, bufsize
, idctl
);
767 do_get_feat_intr_vect(int fd
, const nvme_feature_t
*feat
,
768 nvme_identify_ctrl_t
*idctl
)
774 intr_cnt
= nvme_intr_cnt(fd
);
779 nvme_print(2, feat
->f_name
, -1, NULL
);
781 for (arg
= 0; arg
< intr_cnt
; arg
++) {
782 if (nvme_get_feature(fd
, feat
->f_feature
, arg
, &res
, NULL
, NULL
)
786 feat
->f_print(res
, NULL
, 0, idctl
);
793 do_get_features(int fd
, const nvme_process_arg_t
*npa
)
795 const nvme_feature_t
*feat
;
796 char *f
, *flist
, *lasts
;
797 boolean_t header_printed
= B_FALSE
;
799 if (npa
->npa_argc
> 1)
800 errx(-1, "unexpected arguments");
803 * No feature list given, print all supported features.
805 if (npa
->npa_argc
== 0) {
806 (void) printf("%s: Get Features\n", npa
->npa_name
);
807 for (feat
= &features
[0]; feat
->f_feature
!= 0; feat
++) {
808 if ((npa
->npa_nsid
!= 0 &&
809 (feat
->f_getflags
& NVMEADM_NS
) == 0) ||
810 (npa
->npa_nsid
== 0 &&
811 (feat
->f_getflags
& NVMEADM_CTRL
) == 0))
814 (void) feat
->f_get(fd
, feat
, npa
->npa_idctl
);
821 * Process feature list.
823 flist
= strdup(npa
->npa_argv
[0]);
825 err(-1, "do_get_features");
827 for (f
= strtok_r(flist
, ",", &lasts
);
829 f
= strtok_r(NULL
, ",", &lasts
)) {
833 for (feat
= &features
[0]; feat
->f_feature
!= 0; feat
++) {
834 if (strncasecmp(feat
->f_name
, f
, strlen(f
)) == 0 ||
835 strncasecmp(feat
->f_short
, f
, strlen(f
)) == 0)
839 if (feat
->f_feature
== 0) {
840 warnx("unknown feature %s", f
);
844 if ((npa
->npa_nsid
!= 0 &&
845 (feat
->f_getflags
& NVMEADM_NS
) == 0) ||
846 (npa
->npa_nsid
== 0 &&
847 (feat
->f_getflags
& NVMEADM_CTRL
) == 0)) {
848 warnx("feature %s %s supported for namespaces",
849 feat
->f_name
, (feat
->f_getflags
& NVMEADM_NS
) != 0 ?
854 if (!header_printed
) {
855 (void) printf("%s: Get Features\n", npa
->npa_name
);
856 header_printed
= B_TRUE
;
859 if (feat
->f_get(fd
, feat
, npa
->npa_idctl
) != 0) {
860 warnx("unsupported feature: %s", feat
->f_name
);
870 do_format_common(int fd
, const nvme_process_arg_t
*npa
, unsigned long lbaf
,
873 nvme_process_arg_t ns_npa
= { 0 };
874 nvmeadm_cmd_t cmd
= { 0 };
876 cmd
= *(npa
->npa_cmd
);
877 cmd
.c_func
= do_attach_detach
;
878 cmd
.c_name
= "detach";
880 ns_npa
.npa_cmd
= &cmd
;
882 if (do_attach_detach(fd
, &ns_npa
) != 0)
884 if (nvme_format_nvm(fd
, lbaf
, ses
) == B_FALSE
) {
885 warn("%s failed", npa
->npa_cmd
->c_name
);
888 cmd
.c_name
= "attach";
889 exitcode
+= do_attach_detach(fd
, &ns_npa
);
895 usage_format(const char *c_name
)
897 (void) fprintf(stderr
, "%s <ctl>[/<ns>] [<lba-format>]\n\n"
898 " Format one or all namespaces of the specified NVMe "
899 "controller. Supported LBA\n formats can be queried with "
900 "the \"%s identify\" command on the namespace\n to be "
901 "formatted.\n", c_name
, getprogname());
905 do_format(int fd
, const nvme_process_arg_t
*npa
)
909 if (npa
->npa_idctl
->id_oacs
.oa_format
== 0)
910 errx(-1, "%s not supported", npa
->npa_cmd
->c_name
);
912 if (npa
->npa_isns
&& npa
->npa_idctl
->id_fna
.fn_format
!= 0)
913 errx(-1, "%s not supported on individual namespace",
914 npa
->npa_cmd
->c_name
);
917 if (npa
->npa_argc
> 0) {
919 lbaf
= strtoul(npa
->npa_argv
[0], NULL
, 10);
921 if (errno
!= 0 || lbaf
> NVME_FRMT_MAX_LBAF
)
922 errx(-1, "invalid LBA format %d", lbaf
+ 1);
924 if (npa
->npa_idns
->id_lbaf
[lbaf
].lbaf_ms
!= 0)
925 errx(-1, "LBA formats with metadata not supported");
927 lbaf
= npa
->npa_idns
->id_flbas
.lba_format
;
930 return (do_format_common(fd
, npa
, lbaf
, 0));
934 usage_secure_erase(const char *c_name
)
936 (void) fprintf(stderr
, "%s <ctl>[/<ns>] [-c]\n\n"
937 " Secure-Erase one or all namespaces of the specified "
938 "NVMe controller.\n", c_name
);
942 do_secure_erase(int fd
, const nvme_process_arg_t
*npa
)
945 uint8_t ses
= NVME_FRMT_SES_USER
;
947 if (npa
->npa_idctl
->id_oacs
.oa_format
== 0)
948 errx(-1, "%s not supported", npa
->npa_cmd
->c_name
);
950 if (npa
->npa_isns
&& npa
->npa_idctl
->id_fna
.fn_sec_erase
!= 0)
951 errx(-1, "%s not supported on individual namespace",
952 npa
->npa_cmd
->c_name
);
954 if (npa
->npa_argc
> 0) {
955 if (strcmp(npa
->npa_argv
[0], "-c") == 0)
956 ses
= NVME_FRMT_SES_CRYPTO
;
961 if (ses
== NVME_FRMT_SES_CRYPTO
&&
962 npa
->npa_idctl
->id_fna
.fn_crypt_erase
== 0)
963 errx(-1, "cryptographic %s not supported",
964 npa
->npa_cmd
->c_name
);
966 lbaf
= npa
->npa_idns
->id_flbas
.lba_format
;
968 return (do_format_common(fd
, npa
, lbaf
, ses
));
972 usage_attach_detach(const char *c_name
)
974 (void) fprintf(stderr
, "%s <ctl>[/<ns>]\n\n"
975 " %c%s blkdev(7d) %s one or all namespaces of the "
976 "specified NVMe controller.\n",
977 c_name
, toupper(c_name
[0]), &c_name
[1],
978 c_name
[0] == 'd' ? "from" : "to");
982 do_attach_detach(int fd
, const nvme_process_arg_t
*npa
)
984 char *c_name
= npa
->npa_cmd
->c_name
;
986 if (!npa
->npa_isns
) {
987 nvme_process_arg_t ns_npa
= { 0 };
989 ns_npa
.npa_name
= npa
->npa_name
;
990 ns_npa
.npa_isns
= B_TRUE
;
991 ns_npa
.npa_cmd
= npa
->npa_cmd
;
993 nvme_walk(&ns_npa
, npa
->npa_node
);
997 if ((c_name
[0] == 'd' ? nvme_detach
: nvme_attach
)(fd
)
999 warn("%s failed", c_name
);