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.
14 * Copyright 2017 Joyent, Inc.
18 * nvmeadm -- NVMe administration utility
20 * nvmeadm [-v] [-d] [-h] <command> [<ctl>[/<ns>][,...]] [args]
23 * get-logpage <logpage name>
24 * get-features <feature>[,...]
32 * activate-firmware ...
33 * write-uncorrectable ...
35 * compare-and-write ...
43 #include <sys/sunddi.h>
44 #include <libdevinfo.h>
50 typedef struct nvme_process_arg nvme_process_arg_t
;
51 typedef struct nvme_feature nvme_feature_t
;
52 typedef struct nvmeadm_cmd nvmeadm_cmd_t
;
54 struct nvme_process_arg
{
61 const nvmeadm_cmd_t
*npa_cmd
;
66 nvme_identify_ctrl_t
*npa_idctl
;
67 nvme_identify_nsid_t
*npa_idns
;
68 nvme_version_t
*npa_version
;
77 int (*f_get
)(int, const nvme_feature_t
*, nvme_identify_ctrl_t
*);
78 void (*f_print
)(uint64_t, void *, size_t, nvme_identify_ctrl_t
*);
81 #define NVMEADM_CTRL 1
83 #define NVMEADM_BOTH (NVMEADM_CTRL | NVMEADM_NS)
89 int (*c_func
)(int, const nvme_process_arg_t
*);
90 void (*c_usage
)(const char *);
95 static void usage(const nvmeadm_cmd_t
*);
96 static void nvme_walk(nvme_process_arg_t
*, di_node_t
);
97 static boolean_t
nvme_match(nvme_process_arg_t
*);
99 static int nvme_process(di_node_t
, di_minor_t
, void *);
101 static int do_list(int, const nvme_process_arg_t
*);
102 static int do_identify(int, const nvme_process_arg_t
*);
103 static int do_get_logpage_error(int, const nvme_process_arg_t
*);
104 static int do_get_logpage_health(int, const nvme_process_arg_t
*);
105 static int do_get_logpage_fwslot(int, const nvme_process_arg_t
*);
106 static int do_get_logpage(int, const nvme_process_arg_t
*);
107 static int do_get_feat_common(int, const nvme_feature_t
*,
108 nvme_identify_ctrl_t
*);
109 static int do_get_feat_intr_vect(int, const nvme_feature_t
*,
110 nvme_identify_ctrl_t
*);
111 static int do_get_features(int, const nvme_process_arg_t
*);
112 static int do_format(int, const nvme_process_arg_t
*);
113 static int do_secure_erase(int, const nvme_process_arg_t
*);
114 static int do_attach_detach(int, const nvme_process_arg_t
*);
116 static void usage_list(const char *);
117 static void usage_identify(const char *);
118 static void usage_get_logpage(const char *);
119 static void usage_get_features(const char *);
120 static void usage_format(const char *);
121 static void usage_secure_erase(const char *);
122 static void usage_attach_detach(const char *);
128 static const nvmeadm_cmd_t nvmeadm_cmds
[] = {
131 "list controllers and namespaces",
133 do_list
, usage_list
, B_TRUE
137 "identify controllers and/or namespaces",
139 do_identify
, usage_identify
, B_TRUE
143 "get a log page from controllers and/or namespaces",
145 do_get_logpage
, usage_get_logpage
, B_TRUE
149 "get features from controllers and/or namespaces",
151 do_get_features
, usage_get_features
, B_TRUE
155 "format namespace(s) of a controller",
157 do_format
, usage_format
, B_FALSE
161 "secure erase namespace(s) of a controller",
162 " -c Do a cryptographic erase.",
163 do_secure_erase
, usage_secure_erase
, B_FALSE
167 "detach blkdev(7d) from namespace(s) of a controller",
169 do_attach_detach
, usage_attach_detach
, B_FALSE
173 "attach blkdev(7d) to namespace(s) of a controller",
175 do_attach_detach
, usage_attach_detach
, B_FALSE
183 static const nvme_feature_t features
[] = {
185 NVME_FEAT_ARBITRATION
, 0, NVMEADM_CTRL
,
186 do_get_feat_common
, nvme_print_feat_arbitration
},
187 { "Power Management", "",
188 NVME_FEAT_POWER_MGMT
, 0, NVMEADM_CTRL
,
189 do_get_feat_common
, nvme_print_feat_power_mgmt
},
190 { "LBA Range Type", "range",
191 NVME_FEAT_LBA_RANGE
, NVME_LBA_RANGE_BUFSIZE
, NVMEADM_NS
,
192 do_get_feat_common
, nvme_print_feat_lba_range
},
193 { "Temperature Threshold", "",
194 NVME_FEAT_TEMPERATURE
, 0, NVMEADM_CTRL
,
195 do_get_feat_common
, nvme_print_feat_temperature
},
196 { "Error Recovery", "",
197 NVME_FEAT_ERROR
, 0, NVMEADM_CTRL
,
198 do_get_feat_common
, nvme_print_feat_error
},
199 { "Volatile Write Cache", "cache",
200 NVME_FEAT_WRITE_CACHE
, 0, NVMEADM_CTRL
,
201 do_get_feat_common
, nvme_print_feat_write_cache
},
202 { "Number of Queues", "queues",
203 NVME_FEAT_NQUEUES
, 0, NVMEADM_CTRL
,
204 do_get_feat_common
, nvme_print_feat_nqueues
},
205 { "Interrupt Coalescing", "coalescing",
206 NVME_FEAT_INTR_COAL
, 0, NVMEADM_CTRL
,
207 do_get_feat_common
, nvme_print_feat_intr_coal
},
208 { "Interrupt Vector Configuration", "vector",
209 NVME_FEAT_INTR_VECT
, 0, NVMEADM_CTRL
,
210 do_get_feat_intr_vect
, nvme_print_feat_intr_vect
},
211 { "Write Atomicity", "atomicity",
212 NVME_FEAT_WRITE_ATOM
, 0, NVMEADM_CTRL
,
213 do_get_feat_common
, nvme_print_feat_write_atom
},
214 { "Asynchronous Event Configuration", "event",
215 NVME_FEAT_ASYNC_EVENT
, 0, NVMEADM_CTRL
,
216 do_get_feat_common
, nvme_print_feat_async_event
},
217 { "Autonomous Power State Transition", "",
218 NVME_FEAT_AUTO_PST
, NVME_AUTO_PST_BUFSIZE
, NVMEADM_CTRL
,
219 do_get_feat_common
, nvme_print_feat_auto_pst
},
220 { "Software Progress Marker", "progress",
221 NVME_FEAT_PROGRESS
, 0, NVMEADM_CTRL
,
222 do_get_feat_common
, nvme_print_feat_progress
},
223 { NULL
, NULL
, 0, 0, B_FALSE
, NULL
}
228 main(int argc
, char **argv
)
232 const nvmeadm_cmd_t
*cmd
;
234 nvme_process_arg_t npa
= { 0 };
236 char *tmp
, *lasts
= NULL
;
238 while ((c
= getopt(argc
, argv
, "dhv")) != -1) {
255 if (optind
== argc
) {
263 /* Look up the specified command in the command table. */
264 for (cmd
= &nvmeadm_cmds
[0]; cmd
->c_name
!= NULL
; cmd
++)
265 if (strcmp(cmd
->c_name
, argv
[optind
]) == 0)
268 if (cmd
->c_name
== NULL
) {
283 * All commands but "list" require a ctl/ns argument.
285 if ((optind
== argc
|| (strncmp(argv
[optind
], "nvme", 4) != 0)) &&
286 cmd
->c_func
!= do_list
) {
287 warnx("missing controller/namespace name");
293 /* Store the remaining arguments for use by the command. */
294 npa
.npa_argc
= argc
- optind
- 1;
295 npa
.npa_argv
= &argv
[optind
+ 1];
298 * Make sure we're not running commands on multiple controllers that
299 * aren't allowed to do that.
301 if (argv
[optind
] != NULL
&& strchr(argv
[optind
], ',') != NULL
&&
302 cmd
->c_multi
== B_FALSE
) {
303 warnx("%s not allowed on multiple controllers",
310 * Get controller/namespace arguments and run command.
312 npa
.npa_name
= strtok_r(argv
[optind
], ",", &lasts
);
314 if (npa
.npa_name
!= NULL
) {
315 tmp
= strchr(npa
.npa_name
, '/');
319 npa
.npa_isns
= B_TRUE
;
323 if ((node
= di_init("/", DINFOSUBTREE
| DINFOMINOR
)) == NULL
)
324 err(-1, "failed to initialize libdevinfo");
325 nvme_walk(&npa
, node
);
328 if (npa
.npa_found
== 0) {
329 if (npa
.npa_name
!= NULL
) {
330 warnx("%s%.*s%.*s: no such controller or "
331 "namespace", npa
.npa_name
,
332 npa
.npa_isns
? -1 : 0, "/",
333 npa
.npa_isns
? -1 : 0, npa
.npa_nsid
);
335 warnx("no controllers found");
340 npa
.npa_name
= strtok_r(NULL
, ",", &lasts
);
341 } while (npa
.npa_name
!= NULL
);
347 usage(const nvmeadm_cmd_t
*cmd
)
349 (void) fprintf(stderr
, "usage:\n");
350 (void) fprintf(stderr
, " %s -h %s\n", getprogname(),
351 cmd
!= NULL
? cmd
->c_name
: "[<command>]");
352 (void) fprintf(stderr
, " %s [-dv] ", getprogname());
355 cmd
->c_usage(cmd
->c_name
);
357 (void) fprintf(stderr
,
358 "<command> <ctl>[/<ns>][,...] [<args>]\n");
359 (void) fprintf(stderr
,
360 "\n Manage NVMe controllers and namespaces.\n");
361 (void) fprintf(stderr
, "\ncommands:\n");
363 for (cmd
= &nvmeadm_cmds
[0]; cmd
->c_name
!= NULL
; cmd
++)
364 (void) fprintf(stderr
, " %-15s - %s\n",
365 cmd
->c_name
, cmd
->c_desc
);
367 (void) fprintf(stderr
, "\nflags:\n"
368 " -h print usage information\n"
369 " -d print information useful for debugging %s\n"
370 " -v print verbose information\n", getprogname());
371 if (cmd
!= NULL
&& cmd
->c_flagdesc
!= NULL
)
372 (void) fprintf(stderr
, "%s\n", cmd
->c_flagdesc
);
376 nvme_match(nvme_process_arg_t
*npa
)
381 if (npa
->npa_name
== NULL
)
384 if (asprintf(&name
, "%s%d", di_driver_name(npa
->npa_node
),
385 di_instance(npa
->npa_node
)) < 0)
386 err(-1, "nvme_match()");
388 if (strcmp(name
, npa
->npa_name
) != 0) {
396 if (npa
->npa_nsid
== NULL
)
399 nsid
= di_minor_name(npa
->npa_minor
);
401 if (nsid
== NULL
|| strcmp(npa
->npa_nsid
, nsid
) != 0)
409 nvme_dskname(const nvme_process_arg_t
*npa
)
418 for (child
= di_child_node(npa
->npa_node
);
419 child
!= DI_NODE_NIL
;
420 child
= di_sibling_node(child
)) {
421 addr
= di_bus_addr(child
);
428 if (strncasecmp(addr
, di_minor_name(npa
->npa_minor
),
429 strchrnul(addr
, ',') - addr
) != 0)
432 path
= di_dim_path_dev(dim
, di_driver_name(child
),
433 di_instance(child
), "c");
436 * Error out if we didn't get a path, or if it's too short for
437 * the following operations to be safe.
439 if (path
== NULL
|| strlen(path
) < 2)
442 /* Chop off 's0' and get everything past the last '/' */
443 path
[strlen(path
) - 2] = '\0';
444 path
= strrchr(path
, '/');
457 err(-1, "nvme_dskname");
461 nvme_process(di_node_t node
, di_minor_t minor
, void *arg
)
463 nvme_process_arg_t
*npa
= arg
;
466 npa
->npa_node
= node
;
467 npa
->npa_minor
= minor
;
469 if (!nvme_match(npa
))
470 return (DI_WALK_CONTINUE
);
472 if ((fd
= nvme_open(minor
)) < 0)
473 return (DI_WALK_CONTINUE
);
477 npa
->npa_path
= di_devfs_path(node
);
478 if (npa
->npa_path
== NULL
)
481 npa
->npa_version
= nvme_version(fd
);
482 if (npa
->npa_version
== NULL
)
485 npa
->npa_idctl
= nvme_identify_ctrl(fd
);
486 if (npa
->npa_idctl
== NULL
)
489 npa
->npa_idns
= nvme_identify_nsid(fd
);
490 if (npa
->npa_idns
== NULL
)
494 npa
->npa_dsk
= nvme_dskname(npa
);
496 exitcode
+= npa
->npa_cmd
->c_func(fd
, npa
);
499 di_devfs_path_free(npa
->npa_path
);
501 free(npa
->npa_version
);
502 free(npa
->npa_idctl
);
505 npa
->npa_version
= NULL
;
506 npa
->npa_idctl
= NULL
;
507 npa
->npa_idns
= NULL
;
511 return (DI_WALK_CONTINUE
);
515 nvme_walk(nvme_process_arg_t
*npa
, di_node_t node
)
517 char *minor_nodetype
= DDI_NT_NVME_NEXUS
;
520 minor_nodetype
= DDI_NT_NVME_ATTACHMENT_POINT
;
522 (void) di_walk_minor(node
, minor_nodetype
, 0, npa
, nvme_process
);
526 usage_list(const char *c_name
)
528 (void) fprintf(stderr
, "%s [<ctl>[/<ns>][,...]\n\n"
529 " List NVMe controllers and their namespaces. If no "
530 "controllers and/or name-\n spaces are specified, all "
531 "controllers and namespaces in the system will be\n "
532 "listed.\n", c_name
);
536 do_list_nsid(int fd
, const nvme_process_arg_t
*npa
)
538 _NOTE(ARGUNUSED(fd
));
539 const uint_t format
= npa
->npa_idns
->id_flbas
.lba_format
;
540 const uint_t bshift
= npa
->npa_idns
->id_lbaf
[format
].lbaf_lbads
;
543 * Some devices have extra namespaces with illegal block sizes and
544 * zero blocks. Don't list them when verbose operation isn't requested.
546 if ((bshift
< 9 || npa
->npa_idns
->id_nsize
== 0) && verbose
== 0)
549 (void) printf(" %s/%s (%s): ", npa
->npa_name
,
550 di_minor_name(npa
->npa_minor
),
551 npa
->npa_dsk
!= NULL
? npa
->npa_dsk
: "unattached");
552 nvme_print_nsid_summary(npa
->npa_idns
);
558 do_list(int fd
, const nvme_process_arg_t
*npa
)
560 _NOTE(ARGUNUSED(fd
));
562 nvme_process_arg_t ns_npa
= { 0 };
563 nvmeadm_cmd_t cmd
= { 0 };
566 if (asprintf(&name
, "%s%d", di_driver_name(npa
->npa_node
),
567 di_instance(npa
->npa_node
)) < 0)
568 err(-1, "do_list()");
570 (void) printf("%s: ", name
);
571 nvme_print_ctrl_summary(npa
->npa_idctl
, npa
->npa_version
);
573 ns_npa
.npa_name
= name
;
574 ns_npa
.npa_isns
= B_TRUE
;
575 ns_npa
.npa_nsid
= npa
->npa_nsid
;
576 cmd
= *(npa
->npa_cmd
);
577 cmd
.c_func
= do_list_nsid
;
578 ns_npa
.npa_cmd
= &cmd
;
580 nvme_walk(&ns_npa
, npa
->npa_node
);
588 usage_identify(const char *c_name
)
590 (void) fprintf(stderr
, "%s <ctl>[/<ns>][,...]\n\n"
591 " Print detailed information about the specified NVMe "
592 "controllers and/or name-\n spaces.\n", c_name
);
596 do_identify(int fd
, const nvme_process_arg_t
*npa
)
598 if (!npa
->npa_isns
) {
599 nvme_capabilities_t
*cap
;
601 cap
= nvme_capabilities(fd
);
605 (void) printf("%s: ", npa
->npa_name
);
606 nvme_print_identify_ctrl(npa
->npa_idctl
, cap
,
611 (void) printf("%s/%s: ", npa
->npa_name
,
612 di_minor_name(npa
->npa_minor
));
613 nvme_print_identify_nsid(npa
->npa_idns
,
621 usage_get_logpage(const char *c_name
)
623 (void) fprintf(stderr
, "%s <ctl>[/<ns>][,...] <logpage>\n\n"
624 " Print the specified log page of the specified NVMe "
625 "controllers and/or name-\n spaces. Supported log pages "
626 "are error, health, and firmware.\n", c_name
);
630 do_get_logpage_error(int fd
, const nvme_process_arg_t
*npa
)
632 int nlog
= npa
->npa_idctl
->id_elpe
+ 1;
633 size_t bufsize
= sizeof (nvme_error_log_entry_t
) * nlog
;
634 nvme_error_log_entry_t
*elog
;
637 errx(-1, "Error Log not available on a per-namespace basis");
639 elog
= nvme_get_logpage(fd
, NVME_LOGPAGE_ERROR
, &bufsize
);
644 nlog
= bufsize
/ sizeof (nvme_error_log_entry_t
);
646 (void) printf("%s: ", npa
->npa_name
);
647 nvme_print_error_log(nlog
, elog
);
655 do_get_logpage_health(int fd
, const nvme_process_arg_t
*npa
)
657 size_t bufsize
= sizeof (nvme_health_log_t
);
658 nvme_health_log_t
*hlog
;
661 if (npa
->npa_idctl
->id_lpa
.lp_smart
== 0)
662 errx(-1, "SMART/Health information not available "
663 "on a per-namespace basis on this controller");
666 hlog
= nvme_get_logpage(fd
, NVME_LOGPAGE_HEALTH
, &bufsize
);
671 (void) printf("%s: ", npa
->npa_name
);
672 nvme_print_health_log(hlog
, npa
->npa_idctl
);
680 do_get_logpage_fwslot(int fd
, const nvme_process_arg_t
*npa
)
682 size_t bufsize
= sizeof (nvme_fwslot_log_t
);
683 nvme_fwslot_log_t
*fwlog
;
686 errx(-1, "Firmware Slot information not available on a "
687 "per-namespace basis");
689 fwlog
= nvme_get_logpage(fd
, NVME_LOGPAGE_FWSLOT
, &bufsize
);
694 (void) printf("%s: ", npa
->npa_name
);
695 nvme_print_fwslot_log(fwlog
);
703 do_get_logpage(int fd
, const nvme_process_arg_t
*npa
)
706 int (*func
)(int, const nvme_process_arg_t
*);
708 if (npa
->npa_argc
< 1) {
709 warnx("missing logpage name");
714 if (strcmp(npa
->npa_argv
[0], "error") == 0)
715 func
= do_get_logpage_error
;
716 else if (strcmp(npa
->npa_argv
[0], "health") == 0)
717 func
= do_get_logpage_health
;
718 else if (strcmp(npa
->npa_argv
[0], "firmware") == 0)
719 func
= do_get_logpage_fwslot
;
721 errx(-1, "invalid log page: %s", npa
->npa_argv
[0]);
728 usage_get_features(const char *c_name
)
730 const nvme_feature_t
*feat
;
732 (void) fprintf(stderr
, "%s <ctl>[/<ns>][,...] [<feature>[,...]]\n\n"
733 " Print the specified features of the specified NVMe controllers "
734 "and/or\n namespaces. Supported features are:\n\n", c_name
);
735 (void) fprintf(stderr
, " %-35s %-14s %s\n",
736 "FEATURE NAME", "SHORT NAME", "CONTROLLER/NAMESPACE");
737 for (feat
= &features
[0]; feat
->f_feature
!= 0; feat
++) {
740 if ((feat
->f_getflags
& NVMEADM_BOTH
) == NVMEADM_BOTH
)
742 else if ((feat
->f_getflags
& NVMEADM_CTRL
) != 0)
743 type
= "controller only";
745 type
= "namespace only";
747 (void) fprintf(stderr
, " %-35s %-14s %s\n",
748 feat
->f_name
, feat
->f_short
, type
);
754 do_get_feat_common(int fd
, const nvme_feature_t
*feat
,
755 nvme_identify_ctrl_t
*idctl
)
758 size_t bufsize
= feat
->f_bufsize
;
761 if (nvme_get_feature(fd
, feat
->f_feature
, 0, &res
, &bufsize
, &buf
)
765 nvme_print(2, feat
->f_name
, -1, NULL
);
766 feat
->f_print(res
, buf
, bufsize
, idctl
);
773 do_get_feat_intr_vect(int fd
, const nvme_feature_t
*feat
,
774 nvme_identify_ctrl_t
*idctl
)
780 intr_cnt
= nvme_intr_cnt(fd
);
785 nvme_print(2, feat
->f_name
, -1, NULL
);
787 for (arg
= 0; arg
< intr_cnt
; arg
++) {
788 if (nvme_get_feature(fd
, feat
->f_feature
, arg
, &res
, NULL
, NULL
)
792 feat
->f_print(res
, NULL
, 0, idctl
);
799 do_get_features(int fd
, const nvme_process_arg_t
*npa
)
801 const nvme_feature_t
*feat
;
802 char *f
, *flist
, *lasts
;
803 boolean_t header_printed
= B_FALSE
;
805 if (npa
->npa_argc
> 1)
806 errx(-1, "unexpected arguments");
809 * No feature list given, print all supported features.
811 if (npa
->npa_argc
== 0) {
812 (void) printf("%s: Get Features\n", npa
->npa_name
);
813 for (feat
= &features
[0]; feat
->f_feature
!= 0; feat
++) {
814 if ((npa
->npa_isns
&&
815 (feat
->f_getflags
& NVMEADM_NS
) == 0) ||
817 (feat
->f_getflags
& NVMEADM_CTRL
) == 0))
820 (void) feat
->f_get(fd
, feat
, npa
->npa_idctl
);
827 * Process feature list.
829 flist
= strdup(npa
->npa_argv
[0]);
831 err(-1, "do_get_features");
833 for (f
= strtok_r(flist
, ",", &lasts
);
835 f
= strtok_r(NULL
, ",", &lasts
)) {
839 for (feat
= &features
[0]; feat
->f_feature
!= 0; feat
++) {
840 if (strncasecmp(feat
->f_name
, f
, strlen(f
)) == 0 ||
841 strncasecmp(feat
->f_short
, f
, strlen(f
)) == 0)
845 if (feat
->f_feature
== 0) {
846 warnx("unknown feature %s", f
);
850 if ((npa
->npa_isns
&&
851 (feat
->f_getflags
& NVMEADM_NS
) == 0) ||
853 (feat
->f_getflags
& NVMEADM_CTRL
) == 0)) {
854 warnx("feature %s %s supported for namespaces",
855 feat
->f_name
, (feat
->f_getflags
& NVMEADM_NS
) != 0 ?
860 if (!header_printed
) {
861 (void) printf("%s: Get Features\n", npa
->npa_name
);
862 header_printed
= B_TRUE
;
865 if (feat
->f_get(fd
, feat
, npa
->npa_idctl
) != 0) {
866 warnx("unsupported feature: %s", feat
->f_name
);
876 do_format_common(int fd
, const nvme_process_arg_t
*npa
, unsigned long lbaf
,
879 nvme_process_arg_t ns_npa
= { 0 };
880 nvmeadm_cmd_t cmd
= { 0 };
882 cmd
= *(npa
->npa_cmd
);
883 cmd
.c_func
= do_attach_detach
;
884 cmd
.c_name
= "detach";
886 ns_npa
.npa_cmd
= &cmd
;
888 if (do_attach_detach(fd
, &ns_npa
) != 0)
890 if (nvme_format_nvm(fd
, lbaf
, ses
) == B_FALSE
) {
891 warn("%s failed", npa
->npa_cmd
->c_name
);
894 cmd
.c_name
= "attach";
895 exitcode
+= do_attach_detach(fd
, &ns_npa
);
901 usage_format(const char *c_name
)
903 (void) fprintf(stderr
, "%s <ctl>[/<ns>] [<lba-format>]\n\n"
904 " Format one or all namespaces of the specified NVMe "
905 "controller. Supported LBA\n formats can be queried with "
906 "the \"%s identify\" command on the namespace\n to be "
907 "formatted.\n", c_name
, getprogname());
911 do_format(int fd
, const nvme_process_arg_t
*npa
)
915 if (npa
->npa_idctl
->id_oacs
.oa_format
== 0)
916 errx(-1, "%s not supported", npa
->npa_cmd
->c_name
);
918 if (npa
->npa_isns
&& npa
->npa_idctl
->id_fna
.fn_format
!= 0)
919 errx(-1, "%s not supported on individual namespace",
920 npa
->npa_cmd
->c_name
);
923 if (npa
->npa_argc
> 0) {
925 lbaf
= strtoul(npa
->npa_argv
[0], NULL
, 10);
927 if (errno
!= 0 || lbaf
> NVME_FRMT_MAX_LBAF
)
928 errx(-1, "invalid LBA format %d", lbaf
+ 1);
930 if (npa
->npa_idns
->id_lbaf
[lbaf
].lbaf_ms
!= 0)
931 errx(-1, "LBA formats with metadata not supported");
933 lbaf
= npa
->npa_idns
->id_flbas
.lba_format
;
936 return (do_format_common(fd
, npa
, lbaf
, 0));
940 usage_secure_erase(const char *c_name
)
942 (void) fprintf(stderr
, "%s <ctl>[/<ns>] [-c]\n\n"
943 " Secure-Erase one or all namespaces of the specified "
944 "NVMe controller.\n", c_name
);
948 do_secure_erase(int fd
, const nvme_process_arg_t
*npa
)
951 uint8_t ses
= NVME_FRMT_SES_USER
;
953 if (npa
->npa_idctl
->id_oacs
.oa_format
== 0)
954 errx(-1, "%s not supported", npa
->npa_cmd
->c_name
);
956 if (npa
->npa_isns
&& npa
->npa_idctl
->id_fna
.fn_sec_erase
!= 0)
957 errx(-1, "%s not supported on individual namespace",
958 npa
->npa_cmd
->c_name
);
960 if (npa
->npa_argc
> 0) {
961 if (strcmp(npa
->npa_argv
[0], "-c") == 0)
962 ses
= NVME_FRMT_SES_CRYPTO
;
967 if (ses
== NVME_FRMT_SES_CRYPTO
&&
968 npa
->npa_idctl
->id_fna
.fn_crypt_erase
== 0)
969 errx(-1, "cryptographic %s not supported",
970 npa
->npa_cmd
->c_name
);
972 lbaf
= npa
->npa_idns
->id_flbas
.lba_format
;
974 return (do_format_common(fd
, npa
, lbaf
, ses
));
978 usage_attach_detach(const char *c_name
)
980 (void) fprintf(stderr
, "%s <ctl>[/<ns>]\n\n"
981 " %c%s blkdev(7d) %s one or all namespaces of the "
982 "specified NVMe controller.\n",
983 c_name
, toupper(c_name
[0]), &c_name
[1],
984 c_name
[0] == 'd' ? "from" : "to");
988 do_attach_detach(int fd
, const nvme_process_arg_t
*npa
)
990 char *c_name
= npa
->npa_cmd
->c_name
;
992 if (!npa
->npa_isns
) {
993 nvme_process_arg_t ns_npa
= { 0 };
995 ns_npa
.npa_name
= npa
->npa_name
;
996 ns_npa
.npa_isns
= B_TRUE
;
997 ns_npa
.npa_cmd
= npa
->npa_cmd
;
999 nvme_walk(&ns_npa
, npa
->npa_node
);
1003 if ((c_name
[0] == 'd' ? nvme_detach
: nvme_attach
)(fd
)
1005 warn("%s failed", c_name
);