Print this page
8479 nvmeadm doesn't handle namespaces with EUI64
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/nvmeadm/nvmeadm.c
+++ new/usr/src/cmd/nvmeadm/nvmeadm.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright 2016 Nexenta Systems, Inc.
14 14 */
15 15
16 16 /*
17 17 * nvmeadm -- NVMe administration utility
18 18 *
19 19 * nvmeadm [-v] [-d] [-h] <command> [<ctl>[/<ns>][,...]] [args]
20 20 * commands: list
21 21 * identify
22 22 * get-logpage <logpage name>
23 23 * get-features <feature>[,...]
24 24 * format ...
25 25 * secure-erase ...
26 26 * detach ...
27 27 * attach ...
28 28 * get-param ...
29 29 * set-param ...
30 30 * load-firmware ...
31 31 * activate-firmware ...
32 32 * write-uncorrectable ...
33 33 * compare ...
34 34 * compare-and-write ...
35 35 */
36 36
37 37 #include <stdio.h>
38 38 #include <stdlib.h>
39 39 #include <strings.h>
40 40 #include <ctype.h>
41 41 #include <err.h>
42 42 #include <sys/sunddi.h>
43 43 #include <libdevinfo.h>
44 44
45 45 #include <sys/nvme.h>
46 46
↓ open down ↓ |
46 lines elided |
↑ open up ↑ |
47 47 #include "nvmeadm.h"
48 48
49 49 typedef struct nvme_process_arg nvme_process_arg_t;
50 50 typedef struct nvme_feature nvme_feature_t;
51 51 typedef struct nvmeadm_cmd nvmeadm_cmd_t;
52 52
53 53 struct nvme_process_arg {
54 54 int npa_argc;
55 55 char **npa_argv;
56 56 char *npa_name;
57 - uint32_t npa_nsid;
57 + char *npa_nsid;
58 + int npa_found;
58 59 boolean_t npa_isns;
59 60 const nvmeadm_cmd_t *npa_cmd;
60 61 di_node_t npa_node;
61 62 di_minor_t npa_minor;
62 63 char *npa_path;
63 64 char *npa_dsk;
64 65 nvme_identify_ctrl_t *npa_idctl;
65 66 nvme_identify_nsid_t *npa_idns;
66 67 nvme_version_t *npa_version;
67 68 };
68 69
69 70 struct nvme_feature {
70 71 char *f_name;
71 72 char *f_short;
72 73 uint8_t f_feature;
73 74 size_t f_bufsize;
74 75 uint_t f_getflags;
75 76 int (*f_get)(int, const nvme_feature_t *, nvme_identify_ctrl_t *);
76 77 void (*f_print)(uint64_t, void *, size_t, nvme_identify_ctrl_t *);
77 78 };
78 79
79 80 #define NVMEADM_CTRL 1
80 81 #define NVMEADM_NS 2
81 82 #define NVMEADM_BOTH (NVMEADM_CTRL | NVMEADM_NS)
82 83
83 84 struct nvmeadm_cmd {
84 85 char *c_name;
85 86 char *c_desc;
86 87 char *c_flagdesc;
87 88 int (*c_func)(int, const nvme_process_arg_t *);
88 89 void (*c_usage)(const char *);
89 90 boolean_t c_multi;
90 91 };
91 92
92 93
93 94 static void usage(const nvmeadm_cmd_t *);
94 95 static void nvme_walk(nvme_process_arg_t *, di_node_t);
95 96 static boolean_t nvme_match(nvme_process_arg_t *);
96 97
97 98 static int nvme_process(di_node_t, di_minor_t, void *);
98 99
99 100 static int do_list(int, const nvme_process_arg_t *);
100 101 static int do_identify(int, const nvme_process_arg_t *);
101 102 static int do_get_logpage_error(int, const nvme_process_arg_t *);
102 103 static int do_get_logpage_health(int, const nvme_process_arg_t *);
103 104 static int do_get_logpage_fwslot(int, const nvme_process_arg_t *);
104 105 static int do_get_logpage(int, const nvme_process_arg_t *);
105 106 static int do_get_feat_common(int, const nvme_feature_t *,
106 107 nvme_identify_ctrl_t *);
107 108 static int do_get_feat_intr_vect(int, const nvme_feature_t *,
108 109 nvme_identify_ctrl_t *);
109 110 static int do_get_features(int, const nvme_process_arg_t *);
110 111 static int do_format(int, const nvme_process_arg_t *);
111 112 static int do_secure_erase(int, const nvme_process_arg_t *);
112 113 static int do_attach_detach(int, const nvme_process_arg_t *);
113 114
↓ open down ↓ |
46 lines elided |
↑ open up ↑ |
114 115 static void usage_list(const char *);
115 116 static void usage_identify(const char *);
116 117 static void usage_get_logpage(const char *);
117 118 static void usage_get_features(const char *);
118 119 static void usage_format(const char *);
119 120 static void usage_secure_erase(const char *);
120 121 static void usage_attach_detach(const char *);
121 122
122 123 int verbose;
123 124 int debug;
124 -int found;
125 125 static int exitcode;
126 126
127 127 static const nvmeadm_cmd_t nvmeadm_cmds[] = {
128 128 {
129 129 "list",
130 130 "list controllers and namespaces",
131 131 NULL,
132 132 do_list, usage_list, B_TRUE
133 133 },
134 134 {
135 135 "identify",
136 136 "identify controllers and/or namespaces",
137 137 NULL,
138 138 do_identify, usage_identify, B_TRUE
139 139 },
140 140 {
141 141 "get-logpage",
142 142 "get a log page from controllers and/or namespaces",
143 143 NULL,
144 144 do_get_logpage, usage_get_logpage, B_TRUE
145 145 },
146 146 {
147 147 "get-features",
148 148 "get features from controllers and/or namespaces",
149 149 NULL,
150 150 do_get_features, usage_get_features, B_TRUE
151 151 },
152 152 {
153 153 "format",
154 154 "format namespace(s) of a controller",
155 155 NULL,
156 156 do_format, usage_format, B_FALSE
157 157 },
158 158 {
159 159 "secure-erase",
160 160 "secure erase namespace(s) of a controller",
161 161 " -c Do a cryptographic erase.",
162 162 do_secure_erase, usage_secure_erase, B_FALSE
163 163 },
164 164 {
165 165 "detach",
166 166 "detach blkdev(7d) from namespace(s) of a controller",
167 167 NULL,
168 168 do_attach_detach, usage_attach_detach, B_FALSE
169 169 },
170 170 {
171 171 "attach",
172 172 "attach blkdev(7d) to namespace(s) of a controller",
173 173 NULL,
174 174 do_attach_detach, usage_attach_detach, B_FALSE
175 175 },
176 176 {
177 177 NULL, NULL, NULL,
178 178 NULL, NULL, B_FALSE
179 179 }
180 180 };
181 181
182 182 static const nvme_feature_t features[] = {
183 183 { "Arbitration", "",
184 184 NVME_FEAT_ARBITRATION, 0, NVMEADM_CTRL,
185 185 do_get_feat_common, nvme_print_feat_arbitration },
186 186 { "Power Management", "",
187 187 NVME_FEAT_POWER_MGMT, 0, NVMEADM_CTRL,
188 188 do_get_feat_common, nvme_print_feat_power_mgmt },
189 189 { "LBA Range Type", "range",
190 190 NVME_FEAT_LBA_RANGE, NVME_LBA_RANGE_BUFSIZE, NVMEADM_NS,
191 191 do_get_feat_common, nvme_print_feat_lba_range },
192 192 { "Temperature Threshold", "",
193 193 NVME_FEAT_TEMPERATURE, 0, NVMEADM_CTRL,
194 194 do_get_feat_common, nvme_print_feat_temperature },
195 195 { "Error Recovery", "",
196 196 NVME_FEAT_ERROR, 0, NVMEADM_CTRL,
197 197 do_get_feat_common, nvme_print_feat_error },
198 198 { "Volatile Write Cache", "cache",
199 199 NVME_FEAT_WRITE_CACHE, 0, NVMEADM_CTRL,
200 200 do_get_feat_common, nvme_print_feat_write_cache },
201 201 { "Number of Queues", "queues",
202 202 NVME_FEAT_NQUEUES, 0, NVMEADM_CTRL,
203 203 do_get_feat_common, nvme_print_feat_nqueues },
204 204 { "Interrupt Coalescing", "coalescing",
205 205 NVME_FEAT_INTR_COAL, 0, NVMEADM_CTRL,
206 206 do_get_feat_common, nvme_print_feat_intr_coal },
207 207 { "Interrupt Vector Configuration", "vector",
208 208 NVME_FEAT_INTR_VECT, 0, NVMEADM_CTRL,
209 209 do_get_feat_intr_vect, nvme_print_feat_intr_vect },
210 210 { "Write Atomicity", "atomicity",
211 211 NVME_FEAT_WRITE_ATOM, 0, NVMEADM_CTRL,
212 212 do_get_feat_common, nvme_print_feat_write_atom },
213 213 { "Asynchronous Event Configuration", "event",
214 214 NVME_FEAT_ASYNC_EVENT, 0, NVMEADM_CTRL,
215 215 do_get_feat_common, nvme_print_feat_async_event },
216 216 { "Autonomous Power State Transition", "",
217 217 NVME_FEAT_AUTO_PST, NVME_AUTO_PST_BUFSIZE, NVMEADM_CTRL,
218 218 do_get_feat_common, nvme_print_feat_auto_pst },
219 219 { "Software Progress Marker", "progress",
220 220 NVME_FEAT_PROGRESS, 0, NVMEADM_CTRL,
221 221 do_get_feat_common, nvme_print_feat_progress },
222 222 { NULL, NULL, 0, 0, B_FALSE, NULL }
223 223 };
224 224
225 225
226 226 int
227 227 main(int argc, char **argv)
228 228 {
229 229 int c;
230 230 extern int optind;
231 231 const nvmeadm_cmd_t *cmd;
232 232 di_node_t node;
233 233 nvme_process_arg_t npa = { 0 };
234 234 int help = 0;
235 235 char *tmp, *lasts = NULL;
236 236
237 237 while ((c = getopt(argc, argv, "dhv")) != -1) {
238 238 switch (c) {
239 239 case 'd':
240 240 debug++;
241 241 break;
242 242 case 'v':
243 243 verbose++;
244 244 break;
245 245 case 'h':
246 246 help++;
247 247 break;
248 248 case '?':
249 249 usage(NULL);
250 250 exit(-1);
251 251 }
252 252 }
253 253
254 254 if (optind == argc) {
255 255 usage(NULL);
256 256 if (help)
257 257 exit(0);
258 258 else
259 259 exit(-1);
260 260 }
261 261
262 262 /* Look up the specified command in the command table. */
263 263 for (cmd = &nvmeadm_cmds[0]; cmd->c_name != NULL; cmd++)
264 264 if (strcmp(cmd->c_name, argv[optind]) == 0)
265 265 break;
266 266
267 267 if (cmd->c_name == NULL) {
268 268 usage(NULL);
269 269 exit(-1);
270 270 }
271 271
272 272 if (help) {
273 273 usage(cmd);
274 274 exit(0);
275 275 }
276 276
277 277 npa.npa_cmd = cmd;
278 278
279 279 optind++;
280 280
281 281 /*
282 282 * All commands but "list" require a ctl/ns argument.
283 283 */
284 284 if ((optind == argc || (strncmp(argv[optind], "nvme", 4) != 0)) &&
285 285 cmd->c_func != do_list) {
286 286 warnx("missing controller/namespace name");
287 287 usage(cmd);
288 288 exit(-1);
289 289 }
290 290
291 291
292 292 /* Store the remaining arguments for use by the command. */
293 293 npa.npa_argc = argc - optind - 1;
294 294 npa.npa_argv = &argv[optind + 1];
295 295
296 296 /*
297 297 * Make sure we're not running commands on multiple controllers that
298 298 * aren't allowed to do that.
299 299 */
300 300 if (argv[optind] != NULL && strchr(argv[optind], ',') != NULL &&
301 301 cmd->c_multi == B_FALSE) {
302 302 warnx("%s not allowed on multiple controllers",
303 303 cmd->c_name);
304 304 usage(cmd);
305 305 exit(-1);
↓ open down ↓ |
171 lines elided |
↑ open up ↑ |
306 306 }
307 307
308 308 /*
309 309 * Get controller/namespace arguments and run command.
310 310 */
311 311 npa.npa_name = strtok_r(argv[optind], ",", &lasts);
312 312 do {
313 313 if (npa.npa_name != NULL) {
314 314 tmp = strchr(npa.npa_name, '/');
315 315 if (tmp != NULL) {
316 - unsigned long nsid;
317 316 *tmp++ = '\0';
318 - errno = 0;
319 - nsid = strtoul(tmp, NULL, 10);
320 - if (nsid >= UINT32_MAX || errno != 0) {
321 - warn("invalid namespace %s", tmp);
322 - exitcode--;
323 - continue;
324 - }
325 - if (nsid == 0) {
326 - warnx("invalid namespace %s", tmp);
327 - exitcode--;
328 - continue;
329 - }
330 - npa.npa_nsid = nsid;
317 + npa.npa_nsid = tmp;
331 318 npa.npa_isns = B_TRUE;
332 319 }
333 320 }
334 321
335 322 if ((node = di_init("/", DINFOSUBTREE | DINFOMINOR)) == NULL)
336 323 err(-1, "failed to initialize libdevinfo");
337 324 nvme_walk(&npa, node);
338 325 di_fini(node);
339 326
340 - if (found == 0) {
327 + if (npa.npa_found == 0) {
341 328 if (npa.npa_name != NULL) {
342 - warnx("%s%.*s%.*d: no such controller or "
329 + warnx("%s%.*s%.*s: no such controller or "
343 330 "namespace", npa.npa_name,
344 - npa.npa_nsid > 0 ? -1 : 0, "/",
345 - npa.npa_nsid > 0 ? -1 : 0, npa.npa_nsid);
331 + npa.npa_isns ? -1 : 0, "/",
332 + npa.npa_isns ? -1 : 0, npa.npa_nsid);
346 333 } else {
347 334 warnx("no controllers found");
348 335 }
349 336 exitcode--;
350 337 }
351 - found = 0;
338 + npa.npa_found = 0;
352 339 npa.npa_name = strtok_r(NULL, ",", &lasts);
353 340 } while (npa.npa_name != NULL);
354 341
355 342 exit(exitcode);
356 343 }
357 344
358 345 static void
359 346 usage(const nvmeadm_cmd_t *cmd)
360 347 {
361 348 (void) fprintf(stderr, "usage:\n");
362 349 (void) fprintf(stderr, " %s -h %s\n", getprogname(),
363 350 cmd != NULL ? cmd->c_name : "[<command>]");
364 351 (void) fprintf(stderr, " %s [-dv] ", getprogname());
365 352
366 353 if (cmd != NULL) {
367 354 cmd->c_usage(cmd->c_name);
368 355 } else {
369 356 (void) fprintf(stderr,
370 357 "<command> <ctl>[/<ns>][,...] [<args>]\n");
371 358 (void) fprintf(stderr,
372 359 "\n Manage NVMe controllers and namespaces.\n");
373 360 (void) fprintf(stderr, "\ncommands:\n");
374 361
375 362 for (cmd = &nvmeadm_cmds[0]; cmd->c_name != NULL; cmd++)
376 363 (void) fprintf(stderr, " %-15s - %s\n",
377 364 cmd->c_name, cmd->c_desc);
378 365 }
379 366 (void) fprintf(stderr, "\nflags:\n"
380 367 " -h print usage information\n"
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
381 368 " -d print information useful for debugging %s\n"
382 369 " -v print verbose information\n", getprogname());
383 370 if (cmd != NULL && cmd->c_flagdesc != NULL)
384 371 (void) fprintf(stderr, "%s\n", cmd->c_flagdesc);
385 372 }
386 373
387 374 static boolean_t
388 375 nvme_match(nvme_process_arg_t *npa)
389 376 {
390 377 char *name;
391 - uint32_t nsid = 0;
378 + char *nsid = NULL;
392 379
393 380 if (npa->npa_name == NULL)
394 381 return (B_TRUE);
395 382
396 383 if (asprintf(&name, "%s%d", di_driver_name(npa->npa_node),
397 384 di_instance(npa->npa_node)) < 0)
398 385 err(-1, "nvme_match()");
399 386
400 387 if (strcmp(name, npa->npa_name) != 0) {
401 388 free(name);
402 389 return (B_FALSE);
403 390 }
404 391
405 392 free(name);
406 393
407 394 if (npa->npa_isns) {
408 - if (npa->npa_nsid == 0)
395 + if (npa->npa_nsid == NULL)
409 396 return (B_TRUE);
410 - nsid = strtoul(di_minor_name(npa->npa_minor), NULL, 10);
411 - }
412 397
413 - if (npa->npa_isns && npa->npa_nsid != nsid)
414 - return (B_FALSE);
398 + nsid = di_minor_name(npa->npa_minor);
415 399
400 + if (nsid == NULL || strcmp(npa->npa_nsid, nsid) != 0)
401 + return (B_FALSE);
402 + }
403 +
416 404 return (B_TRUE);
417 405 }
418 406
419 407 char *
420 408 nvme_dskname(const nvme_process_arg_t *npa)
421 409 {
422 410 char *path = NULL;
423 411 di_node_t child;
424 412 di_dim_t dim;
425 413 char *addr;
426 414
427 415 dim = di_dim_init();
428 416
429 417 for (child = di_child_node(npa->npa_node);
430 418 child != DI_NODE_NIL;
431 419 child = di_sibling_node(child)) {
432 420 addr = di_bus_addr(child);
433 421 if (addr == NULL)
434 422 continue;
435 423
436 424 if (addr[0] == 'w')
437 425 addr++;
438 426
439 427 if (strncasecmp(addr, di_minor_name(npa->npa_minor),
440 428 strchrnul(addr, ',') - addr) != 0)
441 429 continue;
442 430
443 431 path = di_dim_path_dev(dim, di_driver_name(child),
444 432 di_instance(child), "c");
445 433
446 434 if (path != NULL) {
447 435 path[strlen(path) - 2] = '\0';
448 436 path = strrchr(path, '/') + 1;
449 437 if (path != NULL) {
450 438 path = strdup(path);
451 439 if (path == NULL)
452 440 err(-1, "nvme_dskname");
453 441 }
454 442 }
455 443
456 444 break;
457 445 }
458 446
459 447 di_dim_fini(dim);
460 448 return (path);
461 449 }
462 450
463 451 static int
464 452 nvme_process(di_node_t node, di_minor_t minor, void *arg)
465 453 {
466 454 nvme_process_arg_t *npa = arg;
467 455 int fd;
↓ open down ↓ |
42 lines elided |
↑ open up ↑ |
468 456
469 457 npa->npa_node = node;
470 458 npa->npa_minor = minor;
471 459
472 460 if (!nvme_match(npa))
473 461 return (DI_WALK_CONTINUE);
474 462
475 463 if ((fd = nvme_open(minor)) < 0)
476 464 return (DI_WALK_CONTINUE);
477 465
478 - found++;
466 + npa->npa_found++;
479 467
480 468 npa->npa_path = di_devfs_path(node);
481 469 if (npa->npa_path == NULL)
482 470 goto out;
483 471
484 472 npa->npa_version = nvme_version(fd);
485 473 if (npa->npa_version == NULL)
486 474 goto out;
487 475
488 476 npa->npa_idctl = nvme_identify_ctrl(fd);
489 477 if (npa->npa_idctl == NULL)
490 478 goto out;
491 479
492 480 npa->npa_idns = nvme_identify_nsid(fd);
493 481 if (npa->npa_idns == NULL)
494 482 goto out;
495 483
496 484 if (npa->npa_isns)
497 485 npa->npa_dsk = nvme_dskname(npa);
498 486
499 487 exitcode += npa->npa_cmd->c_func(fd, npa);
500 488
501 489 out:
502 490 di_devfs_path_free(npa->npa_path);
503 491 free(npa->npa_dsk);
504 492 free(npa->npa_version);
505 493 free(npa->npa_idctl);
506 494 free(npa->npa_idns);
507 495
508 496 npa->npa_version = NULL;
509 497 npa->npa_idctl = NULL;
510 498 npa->npa_idns = NULL;
511 499
512 500 nvme_close(fd);
513 501
514 502 return (DI_WALK_CONTINUE);
515 503 }
516 504
517 505 static void
518 506 nvme_walk(nvme_process_arg_t *npa, di_node_t node)
519 507 {
520 508 char *minor_nodetype = DDI_NT_NVME_NEXUS;
521 509
522 510 if (npa->npa_isns)
523 511 minor_nodetype = DDI_NT_NVME_ATTACHMENT_POINT;
524 512
525 513 (void) di_walk_minor(node, minor_nodetype, 0, npa, nvme_process);
526 514 }
527 515
528 516 static void
529 517 usage_list(const char *c_name)
530 518 {
531 519 (void) fprintf(stderr, "%s [<ctl>[/<ns>][,...]\n\n"
532 520 " List NVMe controllers and their namespaces. If no "
533 521 "controllers and/or name-\n spaces are specified, all "
534 522 "controllers and namespaces in the system will be\n "
535 523 "listed.\n", c_name);
536 524 }
537 525
538 526 static int
539 527 do_list_nsid(int fd, const nvme_process_arg_t *npa)
540 528 {
541 529 _NOTE(ARGUNUSED(fd));
542 530
543 531 (void) printf(" %s/%s (%s): ", npa->npa_name,
544 532 di_minor_name(npa->npa_minor),
545 533 npa->npa_dsk != NULL ? npa->npa_dsk : "unattached");
546 534 nvme_print_nsid_summary(npa->npa_idns);
547 535
548 536 return (0);
549 537 }
550 538
551 539 static int
552 540 do_list(int fd, const nvme_process_arg_t *npa)
553 541 {
554 542 _NOTE(ARGUNUSED(fd));
555 543
556 544 nvme_process_arg_t ns_npa = { 0 };
557 545 nvmeadm_cmd_t cmd = { 0 };
558 546 char *name;
559 547
560 548 if (asprintf(&name, "%s%d", di_driver_name(npa->npa_node),
561 549 di_instance(npa->npa_node)) < 0)
562 550 err(-1, "do_list()");
563 551
564 552 (void) printf("%s: ", name);
565 553 nvme_print_ctrl_summary(npa->npa_idctl, npa->npa_version);
566 554
567 555 ns_npa.npa_name = name;
568 556 ns_npa.npa_isns = B_TRUE;
569 557 ns_npa.npa_nsid = npa->npa_nsid;
570 558 cmd = *(npa->npa_cmd);
571 559 cmd.c_func = do_list_nsid;
572 560 ns_npa.npa_cmd = &cmd;
573 561
574 562 nvme_walk(&ns_npa, npa->npa_node);
575 563
576 564 free(name);
577 565
578 566 return (exitcode);
579 567 }
580 568
581 569 static void
↓ open down ↓ |
93 lines elided |
↑ open up ↑ |
582 570 usage_identify(const char *c_name)
583 571 {
584 572 (void) fprintf(stderr, "%s <ctl>[/<ns>][,...]\n\n"
585 573 " Print detailed information about the specified NVMe "
586 574 "controllers and/or name-\n spaces.\n", c_name);
587 575 }
588 576
589 577 static int
590 578 do_identify(int fd, const nvme_process_arg_t *npa)
591 579 {
592 - if (npa->npa_nsid == 0) {
580 + if (!npa->npa_isns) {
593 581 nvme_capabilities_t *cap;
594 582
595 583 cap = nvme_capabilities(fd);
596 584 if (cap == NULL)
597 585 return (-1);
598 586
599 587 (void) printf("%s: ", npa->npa_name);
600 588 nvme_print_identify_ctrl(npa->npa_idctl, cap,
601 589 npa->npa_version);
602 590
603 591 free(cap);
604 592 } else {
605 593 (void) printf("%s/%s: ", npa->npa_name,
606 594 di_minor_name(npa->npa_minor));
607 595 nvme_print_identify_nsid(npa->npa_idns,
608 596 npa->npa_version);
609 597 }
610 598
611 599 return (0);
612 600 }
613 601
614 602 static void
615 603 usage_get_logpage(const char *c_name)
616 604 {
617 605 (void) fprintf(stderr, "%s <ctl>[/<ns>][,...] <logpage>\n\n"
618 606 " Print the specified log page of the specified NVMe "
619 607 "controllers and/or name-\n spaces. Supported log pages "
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
620 608 "are error, health, and firmware.\n", c_name);
621 609 }
622 610
623 611 static int
624 612 do_get_logpage_error(int fd, const nvme_process_arg_t *npa)
625 613 {
626 614 int nlog = npa->npa_idctl->id_elpe + 1;
627 615 size_t bufsize = sizeof (nvme_error_log_entry_t) * nlog;
628 616 nvme_error_log_entry_t *elog;
629 617
630 - if (npa->npa_nsid != 0)
618 + if (npa->npa_isns)
631 619 errx(-1, "Error Log not available on a per-namespace basis");
632 620
633 621 elog = nvme_get_logpage(fd, NVME_LOGPAGE_ERROR, &bufsize);
634 622
635 623 if (elog == NULL)
636 624 return (-1);
637 625
638 626 nlog = bufsize / sizeof (nvme_error_log_entry_t);
639 627
640 628 (void) printf("%s: ", npa->npa_name);
641 629 nvme_print_error_log(nlog, elog);
642 630
643 631 free(elog);
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
644 632
645 633 return (0);
646 634 }
647 635
648 636 static int
649 637 do_get_logpage_health(int fd, const nvme_process_arg_t *npa)
650 638 {
651 639 size_t bufsize = sizeof (nvme_health_log_t);
652 640 nvme_health_log_t *hlog;
653 641
654 - if (npa->npa_nsid != 0) {
642 + if (npa->npa_isns) {
655 643 if (npa->npa_idctl->id_lpa.lp_smart == 0)
656 644 errx(-1, "SMART/Health information not available "
657 645 "on a per-namespace basis on this controller");
658 646 }
659 647
660 648 hlog = nvme_get_logpage(fd, NVME_LOGPAGE_HEALTH, &bufsize);
661 649
662 650 if (hlog == NULL)
663 651 return (-1);
664 652
665 653 (void) printf("%s: ", npa->npa_name);
666 654 nvme_print_health_log(hlog, npa->npa_idctl);
667 655
668 656 free(hlog);
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
669 657
670 658 return (0);
671 659 }
672 660
673 661 static int
674 662 do_get_logpage_fwslot(int fd, const nvme_process_arg_t *npa)
675 663 {
676 664 size_t bufsize = sizeof (nvme_fwslot_log_t);
677 665 nvme_fwslot_log_t *fwlog;
678 666
679 - if (npa->npa_nsid != 0)
667 + if (npa->npa_isns)
680 668 errx(-1, "Firmware Slot information not available on a "
681 669 "per-namespace basis");
682 670
683 671 fwlog = nvme_get_logpage(fd, NVME_LOGPAGE_FWSLOT, &bufsize);
684 672
685 673 if (fwlog == NULL)
686 674 return (-1);
687 675
688 676 (void) printf("%s: ", npa->npa_name);
689 677 nvme_print_fwslot_log(fwlog);
690 678
691 679 free(fwlog);
692 680
693 681 return (0);
694 682 }
695 683
696 684 static int
697 685 do_get_logpage(int fd, const nvme_process_arg_t *npa)
698 686 {
699 687 int ret = 0;
700 688 int (*func)(int, const nvme_process_arg_t *);
701 689
702 690 if (npa->npa_argc < 1) {
703 691 warnx("missing logpage name");
704 692 usage(npa->npa_cmd);
705 693 exit(-1);
706 694 }
707 695
708 696 if (strcmp(npa->npa_argv[0], "error") == 0)
709 697 func = do_get_logpage_error;
710 698 else if (strcmp(npa->npa_argv[0], "health") == 0)
711 699 func = do_get_logpage_health;
712 700 else if (strcmp(npa->npa_argv[0], "firmware") == 0)
713 701 func = do_get_logpage_fwslot;
714 702 else
715 703 errx(-1, "invalid log page: %s", npa->npa_argv[0]);
716 704
717 705 ret = func(fd, npa);
718 706 return (ret);
719 707 }
720 708
721 709 static void
722 710 usage_get_features(const char *c_name)
723 711 {
724 712 const nvme_feature_t *feat;
725 713
726 714 (void) fprintf(stderr, "%s <ctl>[/<ns>][,...] [<feature>[,...]]\n\n"
727 715 " Print the specified features of the specified NVMe controllers "
728 716 "and/or\n namespaces. Supported features are:\n\n", c_name);
729 717 (void) fprintf(stderr, " %-35s %-14s %s\n",
730 718 "FEATURE NAME", "SHORT NAME", "CONTROLLER/NAMESPACE");
731 719 for (feat = &features[0]; feat->f_feature != 0; feat++) {
732 720 char *type;
733 721
734 722 if ((feat->f_getflags & NVMEADM_BOTH) == NVMEADM_BOTH)
735 723 type = "both";
736 724 else if ((feat->f_getflags & NVMEADM_CTRL) != 0)
737 725 type = "controller only";
738 726 else
739 727 type = "namespace only";
740 728
741 729 (void) fprintf(stderr, " %-35s %-14s %s\n",
742 730 feat->f_name, feat->f_short, type);
743 731 }
744 732
745 733 }
746 734
747 735 static int
748 736 do_get_feat_common(int fd, const nvme_feature_t *feat,
749 737 nvme_identify_ctrl_t *idctl)
750 738 {
751 739 void *buf = NULL;
752 740 size_t bufsize = feat->f_bufsize;
753 741 uint64_t res;
754 742
755 743 if (nvme_get_feature(fd, feat->f_feature, 0, &res, &bufsize, &buf)
756 744 == B_FALSE)
757 745 return (EINVAL);
758 746
759 747 nvme_print(2, feat->f_name, -1, NULL);
760 748 feat->f_print(res, buf, bufsize, idctl);
761 749 free(buf);
762 750
763 751 return (0);
764 752 }
765 753
766 754 static int
767 755 do_get_feat_intr_vect(int fd, const nvme_feature_t *feat,
768 756 nvme_identify_ctrl_t *idctl)
769 757 {
770 758 uint64_t res;
771 759 uint64_t arg;
772 760 int intr_cnt;
773 761
774 762 intr_cnt = nvme_intr_cnt(fd);
775 763
776 764 if (intr_cnt == -1)
777 765 return (EINVAL);
778 766
779 767 nvme_print(2, feat->f_name, -1, NULL);
780 768
781 769 for (arg = 0; arg < intr_cnt; arg++) {
782 770 if (nvme_get_feature(fd, feat->f_feature, arg, &res, NULL, NULL)
783 771 == B_FALSE)
784 772 return (EINVAL);
785 773
786 774 feat->f_print(res, NULL, 0, idctl);
787 775 }
788 776
789 777 return (0);
790 778 }
791 779
792 780 static int
793 781 do_get_features(int fd, const nvme_process_arg_t *npa)
794 782 {
795 783 const nvme_feature_t *feat;
796 784 char *f, *flist, *lasts;
797 785 boolean_t header_printed = B_FALSE;
↓ open down ↓ |
108 lines elided |
↑ open up ↑ |
798 786
799 787 if (npa->npa_argc > 1)
800 788 errx(-1, "unexpected arguments");
801 789
802 790 /*
803 791 * No feature list given, print all supported features.
804 792 */
805 793 if (npa->npa_argc == 0) {
806 794 (void) printf("%s: Get Features\n", npa->npa_name);
807 795 for (feat = &features[0]; feat->f_feature != 0; feat++) {
808 - if ((npa->npa_nsid != 0 &&
796 + if ((npa->npa_isns &&
809 797 (feat->f_getflags & NVMEADM_NS) == 0) ||
810 - (npa->npa_nsid == 0 &&
798 + (!npa->npa_isns &&
811 799 (feat->f_getflags & NVMEADM_CTRL) == 0))
812 800 continue;
813 801
814 802 (void) feat->f_get(fd, feat, npa->npa_idctl);
815 803 }
816 804
817 805 return (0);
818 806 }
819 807
820 808 /*
821 809 * Process feature list.
822 810 */
823 811 flist = strdup(npa->npa_argv[0]);
824 812 if (flist == NULL)
825 813 err(-1, "do_get_features");
826 814
827 815 for (f = strtok_r(flist, ",", &lasts);
828 816 f != NULL;
829 817 f = strtok_r(NULL, ",", &lasts)) {
830 818 while (isspace(*f))
831 819 f++;
832 820
833 821 for (feat = &features[0]; feat->f_feature != 0; feat++) {
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
834 822 if (strncasecmp(feat->f_name, f, strlen(f)) == 0 ||
835 823 strncasecmp(feat->f_short, f, strlen(f)) == 0)
836 824 break;
837 825 }
838 826
839 827 if (feat->f_feature == 0) {
840 828 warnx("unknown feature %s", f);
841 829 continue;
842 830 }
843 831
844 - if ((npa->npa_nsid != 0 &&
832 + if ((npa->npa_isns &&
845 833 (feat->f_getflags & NVMEADM_NS) == 0) ||
846 - (npa->npa_nsid == 0 &&
834 + (!npa->npa_isns &&
847 835 (feat->f_getflags & NVMEADM_CTRL) == 0)) {
848 836 warnx("feature %s %s supported for namespaces",
849 837 feat->f_name, (feat->f_getflags & NVMEADM_NS) != 0 ?
850 838 "only" : "not");
851 839 continue;
852 840 }
853 841
854 842 if (!header_printed) {
855 843 (void) printf("%s: Get Features\n", npa->npa_name);
856 844 header_printed = B_TRUE;
857 845 }
858 846
859 847 if (feat->f_get(fd, feat, npa->npa_idctl) != 0) {
860 848 warnx("unsupported feature: %s", feat->f_name);
861 849 continue;
862 850 }
863 851 }
864 852
865 853 free(flist);
866 854 return (0);
867 855 }
868 856
869 857 static int
870 858 do_format_common(int fd, const nvme_process_arg_t *npa, unsigned long lbaf,
871 859 unsigned long ses)
872 860 {
873 861 nvme_process_arg_t ns_npa = { 0 };
874 862 nvmeadm_cmd_t cmd = { 0 };
875 863
876 864 cmd = *(npa->npa_cmd);
877 865 cmd.c_func = do_attach_detach;
878 866 cmd.c_name = "detach";
879 867 ns_npa = *npa;
880 868 ns_npa.npa_cmd = &cmd;
881 869
882 870 if (do_attach_detach(fd, &ns_npa) != 0)
883 871 return (exitcode);
884 872 if (nvme_format_nvm(fd, lbaf, ses) == B_FALSE) {
885 873 warn("%s failed", npa->npa_cmd->c_name);
886 874 exitcode += -1;
887 875 }
888 876 cmd.c_name = "attach";
889 877 exitcode += do_attach_detach(fd, &ns_npa);
890 878
891 879 return (exitcode);
892 880 }
893 881
894 882 static void
895 883 usage_format(const char *c_name)
896 884 {
897 885 (void) fprintf(stderr, "%s <ctl>[/<ns>] [<lba-format>]\n\n"
898 886 " Format one or all namespaces of the specified NVMe "
899 887 "controller. Supported LBA\n formats can be queried with "
900 888 "the \"%s identify\" command on the namespace\n to be "
901 889 "formatted.\n", c_name, getprogname());
902 890 }
903 891
904 892 static int
905 893 do_format(int fd, const nvme_process_arg_t *npa)
906 894 {
907 895 unsigned long lbaf;
908 896
909 897 if (npa->npa_idctl->id_oacs.oa_format == 0)
910 898 errx(-1, "%s not supported", npa->npa_cmd->c_name);
911 899
912 900 if (npa->npa_isns && npa->npa_idctl->id_fna.fn_format != 0)
913 901 errx(-1, "%s not supported on individual namespace",
914 902 npa->npa_cmd->c_name);
915 903
916 904
917 905 if (npa->npa_argc > 0) {
918 906 errno = 0;
919 907 lbaf = strtoul(npa->npa_argv[0], NULL, 10);
920 908
921 909 if (errno != 0 || lbaf > NVME_FRMT_MAX_LBAF)
922 910 errx(-1, "invalid LBA format %d", lbaf + 1);
923 911
924 912 if (npa->npa_idns->id_lbaf[lbaf].lbaf_ms != 0)
925 913 errx(-1, "LBA formats with metadata not supported");
926 914 } else {
927 915 lbaf = npa->npa_idns->id_flbas.lba_format;
928 916 }
929 917
930 918 return (do_format_common(fd, npa, lbaf, 0));
931 919 }
932 920
933 921 static void
934 922 usage_secure_erase(const char *c_name)
935 923 {
936 924 (void) fprintf(stderr, "%s <ctl>[/<ns>] [-c]\n\n"
937 925 " Secure-Erase one or all namespaces of the specified "
938 926 "NVMe controller.\n", c_name);
939 927 }
940 928
941 929 static int
942 930 do_secure_erase(int fd, const nvme_process_arg_t *npa)
943 931 {
944 932 unsigned long lbaf;
945 933 uint8_t ses = NVME_FRMT_SES_USER;
946 934
947 935 if (npa->npa_idctl->id_oacs.oa_format == 0)
948 936 errx(-1, "%s not supported", npa->npa_cmd->c_name);
949 937
950 938 if (npa->npa_isns && npa->npa_idctl->id_fna.fn_sec_erase != 0)
951 939 errx(-1, "%s not supported on individual namespace",
952 940 npa->npa_cmd->c_name);
953 941
954 942 if (npa->npa_argc > 0) {
955 943 if (strcmp(npa->npa_argv[0], "-c") == 0)
956 944 ses = NVME_FRMT_SES_CRYPTO;
957 945 else
958 946 usage(npa->npa_cmd);
959 947 }
960 948
961 949 if (ses == NVME_FRMT_SES_CRYPTO &&
962 950 npa->npa_idctl->id_fna.fn_crypt_erase == 0)
963 951 errx(-1, "cryptographic %s not supported",
964 952 npa->npa_cmd->c_name);
965 953
966 954 lbaf = npa->npa_idns->id_flbas.lba_format;
967 955
968 956 return (do_format_common(fd, npa, lbaf, ses));
969 957 }
970 958
971 959 static void
972 960 usage_attach_detach(const char *c_name)
973 961 {
974 962 (void) fprintf(stderr, "%s <ctl>[/<ns>]\n\n"
975 963 " %c%s blkdev(7d) %s one or all namespaces of the "
976 964 "specified NVMe controller.\n",
977 965 c_name, toupper(c_name[0]), &c_name[1],
978 966 c_name[0] == 'd' ? "from" : "to");
979 967 }
980 968
981 969 static int
982 970 do_attach_detach(int fd, const nvme_process_arg_t *npa)
983 971 {
984 972 char *c_name = npa->npa_cmd->c_name;
985 973
986 974 if (!npa->npa_isns) {
987 975 nvme_process_arg_t ns_npa = { 0 };
988 976
989 977 ns_npa.npa_name = npa->npa_name;
990 978 ns_npa.npa_isns = B_TRUE;
991 979 ns_npa.npa_cmd = npa->npa_cmd;
992 980
993 981 nvme_walk(&ns_npa, npa->npa_node);
994 982
995 983 return (exitcode);
996 984 } else {
997 985 if ((c_name[0] == 'd' ? nvme_detach : nvme_attach)(fd)
998 986 == B_FALSE) {
999 987 warn("%s failed", c_name);
1000 988 return (-1);
1001 989 }
1002 990 }
1003 991
1004 992 return (0);
1005 993 }
↓ open down ↓ |
149 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX