37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <strings.h>
40 #include <ctype.h>
41 #include <err.h>
42 #include <sys/sunddi.h>
43 #include <libdevinfo.h>
44
45 #include <sys/nvme.h>
46
47 #include "nvmeadm.h"
48
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;
52
53 struct nvme_process_arg {
54 int npa_argc;
55 char **npa_argv;
56 char *npa_name;
57 uint32_t npa_nsid;
58 boolean_t npa_isns;
59 const nvmeadm_cmd_t *npa_cmd;
60 di_node_t npa_node;
61 di_minor_t npa_minor;
62 char *npa_path;
63 char *npa_dsk;
64 nvme_identify_ctrl_t *npa_idctl;
65 nvme_identify_nsid_t *npa_idns;
66 nvme_version_t *npa_version;
67 };
68
69 struct nvme_feature {
70 char *f_name;
71 char *f_short;
72 uint8_t f_feature;
73 size_t f_bufsize;
74 uint_t f_getflags;
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 *);
77 };
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 *);
113
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 *);
121
122 int verbose;
123 int debug;
124 int found;
125 static int exitcode;
126
127 static const nvmeadm_cmd_t nvmeadm_cmds[] = {
128 {
129 "list",
130 "list controllers and namespaces",
131 NULL,
132 do_list, usage_list, B_TRUE
133 },
134 {
135 "identify",
136 "identify controllers and/or namespaces",
137 NULL,
138 do_identify, usage_identify, B_TRUE
139 },
140 {
141 "get-logpage",
142 "get a log page from controllers and/or namespaces",
143 NULL,
144 do_get_logpage, usage_get_logpage, B_TRUE
296 /*
297 * Make sure we're not running commands on multiple controllers that
298 * aren't allowed to do that.
299 */
300 if (argv[optind] != NULL && strchr(argv[optind], ',') != NULL &&
301 cmd->c_multi == B_FALSE) {
302 warnx("%s not allowed on multiple controllers",
303 cmd->c_name);
304 usage(cmd);
305 exit(-1);
306 }
307
308 /*
309 * Get controller/namespace arguments and run command.
310 */
311 npa.npa_name = strtok_r(argv[optind], ",", &lasts);
312 do {
313 if (npa.npa_name != NULL) {
314 tmp = strchr(npa.npa_name, '/');
315 if (tmp != NULL) {
316 unsigned long nsid;
317 *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;
331 npa.npa_isns = B_TRUE;
332 }
333 }
334
335 if ((node = di_init("/", DINFOSUBTREE | DINFOMINOR)) == NULL)
336 err(-1, "failed to initialize libdevinfo");
337 nvme_walk(&npa, node);
338 di_fini(node);
339
340 if (found == 0) {
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);
346 } else {
347 warnx("no controllers found");
348 }
349 exitcode--;
350 }
351 found = 0;
352 npa.npa_name = strtok_r(NULL, ",", &lasts);
353 } while (npa.npa_name != NULL);
354
355 exit(exitcode);
356 }
357
358 static void
359 usage(const nvmeadm_cmd_t *cmd)
360 {
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());
365
366 if (cmd != NULL) {
367 cmd->c_usage(cmd->c_name);
368 } else {
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");
374
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);
378 }
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);
385 }
386
387 static boolean_t
388 nvme_match(nvme_process_arg_t *npa)
389 {
390 char *name;
391 uint32_t nsid = 0;
392
393 if (npa->npa_name == NULL)
394 return (B_TRUE);
395
396 if (asprintf(&name, "%s%d", di_driver_name(npa->npa_node),
397 di_instance(npa->npa_node)) < 0)
398 err(-1, "nvme_match()");
399
400 if (strcmp(name, npa->npa_name) != 0) {
401 free(name);
402 return (B_FALSE);
403 }
404
405 free(name);
406
407 if (npa->npa_isns) {
408 if (npa->npa_nsid == 0)
409 return (B_TRUE);
410 nsid = strtoul(di_minor_name(npa->npa_minor), NULL, 10);
411 }
412
413 if (npa->npa_isns && npa->npa_nsid != nsid)
414 return (B_FALSE);
415
416 return (B_TRUE);
417 }
418
419 char *
420 nvme_dskname(const nvme_process_arg_t *npa)
421 {
422 char *path = NULL;
423 di_node_t child;
424 di_dim_t dim;
425 char *addr;
426
427 dim = di_dim_init();
428
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);
433 if (addr == NULL)
434 continue;
458
459 di_dim_fini(dim);
460 return (path);
461 }
462
463 static int
464 nvme_process(di_node_t node, di_minor_t minor, void *arg)
465 {
466 nvme_process_arg_t *npa = arg;
467 int fd;
468
469 npa->npa_node = node;
470 npa->npa_minor = minor;
471
472 if (!nvme_match(npa))
473 return (DI_WALK_CONTINUE);
474
475 if ((fd = nvme_open(minor)) < 0)
476 return (DI_WALK_CONTINUE);
477
478 found++;
479
480 npa->npa_path = di_devfs_path(node);
481 if (npa->npa_path == NULL)
482 goto out;
483
484 npa->npa_version = nvme_version(fd);
485 if (npa->npa_version == NULL)
486 goto out;
487
488 npa->npa_idctl = nvme_identify_ctrl(fd);
489 if (npa->npa_idctl == NULL)
490 goto out;
491
492 npa->npa_idns = nvme_identify_nsid(fd);
493 if (npa->npa_idns == NULL)
494 goto out;
495
496 if (npa->npa_isns)
497 npa->npa_dsk = nvme_dskname(npa);
498
572 ns_npa.npa_cmd = &cmd;
573
574 nvme_walk(&ns_npa, npa->npa_node);
575
576 free(name);
577
578 return (exitcode);
579 }
580
581 static void
582 usage_identify(const char *c_name)
583 {
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);
587 }
588
589 static int
590 do_identify(int fd, const nvme_process_arg_t *npa)
591 {
592 if (npa->npa_nsid == 0) {
593 nvme_capabilities_t *cap;
594
595 cap = nvme_capabilities(fd);
596 if (cap == NULL)
597 return (-1);
598
599 (void) printf("%s: ", npa->npa_name);
600 nvme_print_identify_ctrl(npa->npa_idctl, cap,
601 npa->npa_version);
602
603 free(cap);
604 } else {
605 (void) printf("%s/%s: ", npa->npa_name,
606 di_minor_name(npa->npa_minor));
607 nvme_print_identify_nsid(npa->npa_idns,
608 npa->npa_version);
609 }
610
611 return (0);
612 }
613
614 static void
615 usage_get_logpage(const char *c_name)
616 {
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);
621 }
622
623 static int
624 do_get_logpage_error(int fd, const nvme_process_arg_t *npa)
625 {
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;
629
630 if (npa->npa_nsid != 0)
631 errx(-1, "Error Log not available on a per-namespace basis");
632
633 elog = nvme_get_logpage(fd, NVME_LOGPAGE_ERROR, &bufsize);
634
635 if (elog == NULL)
636 return (-1);
637
638 nlog = bufsize / sizeof (nvme_error_log_entry_t);
639
640 (void) printf("%s: ", npa->npa_name);
641 nvme_print_error_log(nlog, elog);
642
643 free(elog);
644
645 return (0);
646 }
647
648 static int
649 do_get_logpage_health(int fd, const nvme_process_arg_t *npa)
650 {
651 size_t bufsize = sizeof (nvme_health_log_t);
652 nvme_health_log_t *hlog;
653
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");
658 }
659
660 hlog = nvme_get_logpage(fd, NVME_LOGPAGE_HEALTH, &bufsize);
661
662 if (hlog == NULL)
663 return (-1);
664
665 (void) printf("%s: ", npa->npa_name);
666 nvme_print_health_log(hlog, npa->npa_idctl);
667
668 free(hlog);
669
670 return (0);
671 }
672
673 static int
674 do_get_logpage_fwslot(int fd, const nvme_process_arg_t *npa)
675 {
676 size_t bufsize = sizeof (nvme_fwslot_log_t);
677 nvme_fwslot_log_t *fwlog;
678
679 if (npa->npa_nsid != 0)
680 errx(-1, "Firmware Slot information not available on a "
681 "per-namespace basis");
682
683 fwlog = nvme_get_logpage(fd, NVME_LOGPAGE_FWSLOT, &bufsize);
684
685 if (fwlog == NULL)
686 return (-1);
687
688 (void) printf("%s: ", npa->npa_name);
689 nvme_print_fwslot_log(fwlog);
690
691 free(fwlog);
692
693 return (0);
694 }
695
696 static int
697 do_get_logpage(int fd, const nvme_process_arg_t *npa)
698 {
699 int ret = 0;
788
789 return (0);
790 }
791
792 static int
793 do_get_features(int fd, const nvme_process_arg_t *npa)
794 {
795 const nvme_feature_t *feat;
796 char *f, *flist, *lasts;
797 boolean_t header_printed = B_FALSE;
798
799 if (npa->npa_argc > 1)
800 errx(-1, "unexpected arguments");
801
802 /*
803 * No feature list given, print all supported features.
804 */
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))
812 continue;
813
814 (void) feat->f_get(fd, feat, npa->npa_idctl);
815 }
816
817 return (0);
818 }
819
820 /*
821 * Process feature list.
822 */
823 flist = strdup(npa->npa_argv[0]);
824 if (flist == NULL)
825 err(-1, "do_get_features");
826
827 for (f = strtok_r(flist, ",", &lasts);
828 f != NULL;
829 f = strtok_r(NULL, ",", &lasts)) {
830 while (isspace(*f))
831 f++;
832
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)
836 break;
837 }
838
839 if (feat->f_feature == 0) {
840 warnx("unknown feature %s", f);
841 continue;
842 }
843
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 ?
850 "only" : "not");
851 continue;
852 }
853
854 if (!header_printed) {
855 (void) printf("%s: Get Features\n", npa->npa_name);
856 header_printed = B_TRUE;
857 }
858
859 if (feat->f_get(fd, feat, npa->npa_idctl) != 0) {
860 warnx("unsupported feature: %s", feat->f_name);
861 continue;
862 }
863 }
864
865 free(flist);
866 return (0);
|
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <strings.h>
40 #include <ctype.h>
41 #include <err.h>
42 #include <sys/sunddi.h>
43 #include <libdevinfo.h>
44
45 #include <sys/nvme.h>
46
47 #include "nvmeadm.h"
48
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;
52
53 struct nvme_process_arg {
54 int npa_argc;
55 char **npa_argv;
56 char *npa_name;
57 char *npa_nsid;
58 int npa_found;
59 boolean_t npa_isns;
60 const nvmeadm_cmd_t *npa_cmd;
61 di_node_t npa_node;
62 di_minor_t npa_minor;
63 char *npa_path;
64 char *npa_dsk;
65 nvme_identify_ctrl_t *npa_idctl;
66 nvme_identify_nsid_t *npa_idns;
67 nvme_version_t *npa_version;
68 };
69
70 struct nvme_feature {
71 char *f_name;
72 char *f_short;
73 uint8_t f_feature;
74 size_t f_bufsize;
75 uint_t f_getflags;
76 int (*f_get)(int, const nvme_feature_t *, nvme_identify_ctrl_t *);
77 void (*f_print)(uint64_t, void *, size_t, nvme_identify_ctrl_t *);
78 };
105 static int do_get_logpage(int, const nvme_process_arg_t *);
106 static int do_get_feat_common(int, const nvme_feature_t *,
107 nvme_identify_ctrl_t *);
108 static int do_get_feat_intr_vect(int, const nvme_feature_t *,
109 nvme_identify_ctrl_t *);
110 static int do_get_features(int, const nvme_process_arg_t *);
111 static int do_format(int, const nvme_process_arg_t *);
112 static int do_secure_erase(int, const nvme_process_arg_t *);
113 static int do_attach_detach(int, const nvme_process_arg_t *);
114
115 static void usage_list(const char *);
116 static void usage_identify(const char *);
117 static void usage_get_logpage(const char *);
118 static void usage_get_features(const char *);
119 static void usage_format(const char *);
120 static void usage_secure_erase(const char *);
121 static void usage_attach_detach(const char *);
122
123 int verbose;
124 int debug;
125 static int exitcode;
126
127 static const nvmeadm_cmd_t nvmeadm_cmds[] = {
128 {
129 "list",
130 "list controllers and namespaces",
131 NULL,
132 do_list, usage_list, B_TRUE
133 },
134 {
135 "identify",
136 "identify controllers and/or namespaces",
137 NULL,
138 do_identify, usage_identify, B_TRUE
139 },
140 {
141 "get-logpage",
142 "get a log page from controllers and/or namespaces",
143 NULL,
144 do_get_logpage, usage_get_logpage, B_TRUE
296 /*
297 * Make sure we're not running commands on multiple controllers that
298 * aren't allowed to do that.
299 */
300 if (argv[optind] != NULL && strchr(argv[optind], ',') != NULL &&
301 cmd->c_multi == B_FALSE) {
302 warnx("%s not allowed on multiple controllers",
303 cmd->c_name);
304 usage(cmd);
305 exit(-1);
306 }
307
308 /*
309 * Get controller/namespace arguments and run command.
310 */
311 npa.npa_name = strtok_r(argv[optind], ",", &lasts);
312 do {
313 if (npa.npa_name != NULL) {
314 tmp = strchr(npa.npa_name, '/');
315 if (tmp != NULL) {
316 *tmp++ = '\0';
317 npa.npa_nsid = tmp;
318 npa.npa_isns = B_TRUE;
319 }
320 }
321
322 if ((node = di_init("/", DINFOSUBTREE | DINFOMINOR)) == NULL)
323 err(-1, "failed to initialize libdevinfo");
324 nvme_walk(&npa, node);
325 di_fini(node);
326
327 if (npa.npa_found == 0) {
328 if (npa.npa_name != NULL) {
329 warnx("%s%.*s%.*s: no such controller or "
330 "namespace", npa.npa_name,
331 npa.npa_isns ? -1 : 0, "/",
332 npa.npa_isns ? -1 : 0, npa.npa_nsid);
333 } else {
334 warnx("no controllers found");
335 }
336 exitcode--;
337 }
338 npa.npa_found = 0;
339 npa.npa_name = strtok_r(NULL, ",", &lasts);
340 } while (npa.npa_name != NULL);
341
342 exit(exitcode);
343 }
344
345 static void
346 usage(const nvmeadm_cmd_t *cmd)
347 {
348 (void) fprintf(stderr, "usage:\n");
349 (void) fprintf(stderr, " %s -h %s\n", getprogname(),
350 cmd != NULL ? cmd->c_name : "[<command>]");
351 (void) fprintf(stderr, " %s [-dv] ", getprogname());
352
353 if (cmd != NULL) {
354 cmd->c_usage(cmd->c_name);
355 } else {
356 (void) fprintf(stderr,
357 "<command> <ctl>[/<ns>][,...] [<args>]\n");
358 (void) fprintf(stderr,
359 "\n Manage NVMe controllers and namespaces.\n");
360 (void) fprintf(stderr, "\ncommands:\n");
361
362 for (cmd = &nvmeadm_cmds[0]; cmd->c_name != NULL; cmd++)
363 (void) fprintf(stderr, " %-15s - %s\n",
364 cmd->c_name, cmd->c_desc);
365 }
366 (void) fprintf(stderr, "\nflags:\n"
367 " -h print usage information\n"
368 " -d print information useful for debugging %s\n"
369 " -v print verbose information\n", getprogname());
370 if (cmd != NULL && cmd->c_flagdesc != NULL)
371 (void) fprintf(stderr, "%s\n", cmd->c_flagdesc);
372 }
373
374 static boolean_t
375 nvme_match(nvme_process_arg_t *npa)
376 {
377 char *name;
378 char *nsid = NULL;
379
380 if (npa->npa_name == NULL)
381 return (B_TRUE);
382
383 if (asprintf(&name, "%s%d", di_driver_name(npa->npa_node),
384 di_instance(npa->npa_node)) < 0)
385 err(-1, "nvme_match()");
386
387 if (strcmp(name, npa->npa_name) != 0) {
388 free(name);
389 return (B_FALSE);
390 }
391
392 free(name);
393
394 if (npa->npa_isns) {
395 if (npa->npa_nsid == NULL)
396 return (B_TRUE);
397
398 nsid = di_minor_name(npa->npa_minor);
399
400 if (nsid == NULL || strcmp(npa->npa_nsid, nsid) != 0)
401 return (B_FALSE);
402 }
403
404 return (B_TRUE);
405 }
406
407 char *
408 nvme_dskname(const nvme_process_arg_t *npa)
409 {
410 char *path = NULL;
411 di_node_t child;
412 di_dim_t dim;
413 char *addr;
414
415 dim = di_dim_init();
416
417 for (child = di_child_node(npa->npa_node);
418 child != DI_NODE_NIL;
419 child = di_sibling_node(child)) {
420 addr = di_bus_addr(child);
421 if (addr == NULL)
422 continue;
446
447 di_dim_fini(dim);
448 return (path);
449 }
450
451 static int
452 nvme_process(di_node_t node, di_minor_t minor, void *arg)
453 {
454 nvme_process_arg_t *npa = arg;
455 int fd;
456
457 npa->npa_node = node;
458 npa->npa_minor = minor;
459
460 if (!nvme_match(npa))
461 return (DI_WALK_CONTINUE);
462
463 if ((fd = nvme_open(minor)) < 0)
464 return (DI_WALK_CONTINUE);
465
466 npa->npa_found++;
467
468 npa->npa_path = di_devfs_path(node);
469 if (npa->npa_path == NULL)
470 goto out;
471
472 npa->npa_version = nvme_version(fd);
473 if (npa->npa_version == NULL)
474 goto out;
475
476 npa->npa_idctl = nvme_identify_ctrl(fd);
477 if (npa->npa_idctl == NULL)
478 goto out;
479
480 npa->npa_idns = nvme_identify_nsid(fd);
481 if (npa->npa_idns == NULL)
482 goto out;
483
484 if (npa->npa_isns)
485 npa->npa_dsk = nvme_dskname(npa);
486
560 ns_npa.npa_cmd = &cmd;
561
562 nvme_walk(&ns_npa, npa->npa_node);
563
564 free(name);
565
566 return (exitcode);
567 }
568
569 static void
570 usage_identify(const char *c_name)
571 {
572 (void) fprintf(stderr, "%s <ctl>[/<ns>][,...]\n\n"
573 " Print detailed information about the specified NVMe "
574 "controllers and/or name-\n spaces.\n", c_name);
575 }
576
577 static int
578 do_identify(int fd, const nvme_process_arg_t *npa)
579 {
580 if (!npa->npa_isns) {
581 nvme_capabilities_t *cap;
582
583 cap = nvme_capabilities(fd);
584 if (cap == NULL)
585 return (-1);
586
587 (void) printf("%s: ", npa->npa_name);
588 nvme_print_identify_ctrl(npa->npa_idctl, cap,
589 npa->npa_version);
590
591 free(cap);
592 } else {
593 (void) printf("%s/%s: ", npa->npa_name,
594 di_minor_name(npa->npa_minor));
595 nvme_print_identify_nsid(npa->npa_idns,
596 npa->npa_version);
597 }
598
599 return (0);
600 }
601
602 static void
603 usage_get_logpage(const char *c_name)
604 {
605 (void) fprintf(stderr, "%s <ctl>[/<ns>][,...] <logpage>\n\n"
606 " Print the specified log page of the specified NVMe "
607 "controllers and/or name-\n spaces. Supported log pages "
608 "are error, health, and firmware.\n", c_name);
609 }
610
611 static int
612 do_get_logpage_error(int fd, const nvme_process_arg_t *npa)
613 {
614 int nlog = npa->npa_idctl->id_elpe + 1;
615 size_t bufsize = sizeof (nvme_error_log_entry_t) * nlog;
616 nvme_error_log_entry_t *elog;
617
618 if (npa->npa_isns)
619 errx(-1, "Error Log not available on a per-namespace basis");
620
621 elog = nvme_get_logpage(fd, NVME_LOGPAGE_ERROR, &bufsize);
622
623 if (elog == NULL)
624 return (-1);
625
626 nlog = bufsize / sizeof (nvme_error_log_entry_t);
627
628 (void) printf("%s: ", npa->npa_name);
629 nvme_print_error_log(nlog, elog);
630
631 free(elog);
632
633 return (0);
634 }
635
636 static int
637 do_get_logpage_health(int fd, const nvme_process_arg_t *npa)
638 {
639 size_t bufsize = sizeof (nvme_health_log_t);
640 nvme_health_log_t *hlog;
641
642 if (npa->npa_isns) {
643 if (npa->npa_idctl->id_lpa.lp_smart == 0)
644 errx(-1, "SMART/Health information not available "
645 "on a per-namespace basis on this controller");
646 }
647
648 hlog = nvme_get_logpage(fd, NVME_LOGPAGE_HEALTH, &bufsize);
649
650 if (hlog == NULL)
651 return (-1);
652
653 (void) printf("%s: ", npa->npa_name);
654 nvme_print_health_log(hlog, npa->npa_idctl);
655
656 free(hlog);
657
658 return (0);
659 }
660
661 static int
662 do_get_logpage_fwslot(int fd, const nvme_process_arg_t *npa)
663 {
664 size_t bufsize = sizeof (nvme_fwslot_log_t);
665 nvme_fwslot_log_t *fwlog;
666
667 if (npa->npa_isns)
668 errx(-1, "Firmware Slot information not available on a "
669 "per-namespace basis");
670
671 fwlog = nvme_get_logpage(fd, NVME_LOGPAGE_FWSLOT, &bufsize);
672
673 if (fwlog == NULL)
674 return (-1);
675
676 (void) printf("%s: ", npa->npa_name);
677 nvme_print_fwslot_log(fwlog);
678
679 free(fwlog);
680
681 return (0);
682 }
683
684 static int
685 do_get_logpage(int fd, const nvme_process_arg_t *npa)
686 {
687 int ret = 0;
776
777 return (0);
778 }
779
780 static int
781 do_get_features(int fd, const nvme_process_arg_t *npa)
782 {
783 const nvme_feature_t *feat;
784 char *f, *flist, *lasts;
785 boolean_t header_printed = B_FALSE;
786
787 if (npa->npa_argc > 1)
788 errx(-1, "unexpected arguments");
789
790 /*
791 * No feature list given, print all supported features.
792 */
793 if (npa->npa_argc == 0) {
794 (void) printf("%s: Get Features\n", npa->npa_name);
795 for (feat = &features[0]; feat->f_feature != 0; feat++) {
796 if ((npa->npa_isns &&
797 (feat->f_getflags & NVMEADM_NS) == 0) ||
798 (!npa->npa_isns &&
799 (feat->f_getflags & NVMEADM_CTRL) == 0))
800 continue;
801
802 (void) feat->f_get(fd, feat, npa->npa_idctl);
803 }
804
805 return (0);
806 }
807
808 /*
809 * Process feature list.
810 */
811 flist = strdup(npa->npa_argv[0]);
812 if (flist == NULL)
813 err(-1, "do_get_features");
814
815 for (f = strtok_r(flist, ",", &lasts);
816 f != NULL;
817 f = strtok_r(NULL, ",", &lasts)) {
818 while (isspace(*f))
819 f++;
820
821 for (feat = &features[0]; feat->f_feature != 0; feat++) {
822 if (strncasecmp(feat->f_name, f, strlen(f)) == 0 ||
823 strncasecmp(feat->f_short, f, strlen(f)) == 0)
824 break;
825 }
826
827 if (feat->f_feature == 0) {
828 warnx("unknown feature %s", f);
829 continue;
830 }
831
832 if ((npa->npa_isns &&
833 (feat->f_getflags & NVMEADM_NS) == 0) ||
834 (!npa->npa_isns &&
835 (feat->f_getflags & NVMEADM_CTRL) == 0)) {
836 warnx("feature %s %s supported for namespaces",
837 feat->f_name, (feat->f_getflags & NVMEADM_NS) != 0 ?
838 "only" : "not");
839 continue;
840 }
841
842 if (!header_printed) {
843 (void) printf("%s: Get Features\n", npa->npa_name);
844 header_printed = B_TRUE;
845 }
846
847 if (feat->f_get(fd, feat, npa->npa_idctl) != 0) {
848 warnx("unsupported feature: %s", feat->f_name);
849 continue;
850 }
851 }
852
853 free(flist);
854 return (0);
|