void logpage(int argc, char *argv[]) { int fd, nsid; int log_page = 0, pageflag = false; int hexflag = false, ns_specified; int ch; char *p; char cname[64]; uint32_t size; void *buf; struct logpage_function *f; struct nvm_identify_controller cdata; print_fn_t print_fn; while ((ch = getopt(argc, argv, "p:x")) != -1) { switch (ch) { case 'p': /* TODO: Add human-readable ASCII page IDs */ log_page = strtol(optarg, &p, 0); if (p != NULL && *p != '\0') { fprintf(stderr, "\"%s\" not valid log page id.\n", optarg); logpage_usage(); /* TODO: Define valid log page id ranges in nvme.h? */ } else if (log_page == 0 || (log_page >= 0x04 && log_page <= 0x7F) || (log_page >= 0x80 && log_page <= 0xBF)) { fprintf(stderr, "\"%s\" not valid log page id.\n", optarg); logpage_usage(); } pageflag = true; break; case 'x': hexflag = true; break; } } if (!pageflag) { printf("Missing page_id (-p).\n"); logpage_usage(); } /* Check that a controller and/or namespace was specified. */ if (optind >= argc) logpage_usage(); if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) { ns_specified = true; parse_ns_str(argv[optind], cname, &nsid); open_dev(cname, &fd, 1, 1); } else { ns_specified = false; nsid = 0xffffffff; open_dev(argv[optind], &fd, 1, 1); } read_controller_data(fd, &cdata); /* * The log page attribtues indicate whether or not the controller * supports the SMART/Health information log page on a per * namespace basis. */ if (ns_specified) { if (log_page != NVME_LOG_HEALTH_INFORMATION) errx(1, "log page %d valid only at controller level", log_page); if (!(cdata.lpa & NVME_ID_CTRLR_LPA_NS_SMART)) errx(1, "controller does not support per namespace " "smart/health information"); } print_fn = print_hex; if (!hexflag) { /* * See if there is a pretty print function for the * specified log page. If one isn't found, we * just revert to the default (print_hex). */ f = logfuncs; while (f->log_page > 0) { if (log_page == f->log_page) { print_fn = f->fn; break; } f++; } } /* Read the log page */ switch (log_page) { case NVME_LOG_ERROR: size = sizeof(struct nvme_error_information_entry); size *= (cdata.elpe + 1); break; case NVME_LOG_HEALTH_INFORMATION: size = sizeof(struct nvme_health_information_page); break; case NVME_LOG_FIRMWARE_SLOT: size = sizeof(struct nvme_firmware_page); break; default: size = DEFAULT_SIZE; break; } buf = get_log_buffer(size); read_logpage(fd, log_page, nsid, buf, size); print_fn(buf, size); close(fd); exit(0); }
void logpage(int argc, char *argv[]) { int fd, nsid; int log_page = 0, pageflag = false; int hexflag = false, ns_specified; char ch, *p; char cname[64]; uint32_t size; void *buf; const char *vendor = NULL; struct logpage_function *f; struct nvme_controller_data cdata; print_fn_t print_fn; while ((ch = getopt(argc, argv, "p:xv:")) != -1) { switch (ch) { case 'p': /* TODO: Add human-readable ASCII page IDs */ log_page = strtol(optarg, &p, 0); if (p != NULL && *p != '\0') { fprintf(stderr, "\"%s\" not valid log page id.\n", optarg); logpage_usage(); } pageflag = true; break; case 'x': hexflag = true; break; case 'v': vendor = optarg; break; } } if (!pageflag) { printf("Missing page_id (-p).\n"); logpage_usage(); } /* Check that a controller and/or namespace was specified. */ if (optind >= argc) logpage_usage(); if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) { ns_specified = true; parse_ns_str(argv[optind], cname, &nsid); open_dev(cname, &fd, 1, 1); } else { ns_specified = false; nsid = NVME_GLOBAL_NAMESPACE_TAG; open_dev(argv[optind], &fd, 1, 1); } read_controller_data(fd, &cdata); /* * The log page attribtues indicate whether or not the controller * supports the SMART/Health information log page on a per * namespace basis. */ if (ns_specified) { if (log_page != NVME_LOG_HEALTH_INFORMATION) errx(1, "log page %d valid only at controller level", log_page); if (cdata.lpa.ns_smart == 0) errx(1, "controller does not support per namespace " "smart/health information"); } print_fn = print_hex; size = DEFAULT_SIZE; if (!hexflag) { /* * See if there is a pretty print function for the specified log * page. If one isn't found, we just revert to the default * (print_hex). If there was a vendor specified bt the user, and * the page is vendor specific, don't match the print function * unless the vendors match. */ for (f = logfuncs; f->log_page > 0; f++) { if (f->vendor != NULL && vendor != NULL && strcmp(f->vendor, vendor) != 0) continue; if (log_page != f->log_page) continue; print_fn = f->print_fn; size = f->size; break; } } if (log_page == NVME_LOG_ERROR) { size = sizeof(struct nvme_error_information_entry); size *= (cdata.elpe + 1); } /* Read the log page */ buf = get_log_buffer(size); read_logpage(fd, log_page, nsid, buf, size); print_fn(buf, size); close(fd); exit(0); }
void logpage(int argc, char *argv[]) { int fd, nsid, len; int log_page = 0, pageflag = false; int hexflag = false; int allow_ns = false; char ch, *p, *nsloc = NULL; char *cname = NULL; size_t size; void *buf; struct logpage_function *f; struct nvme_controller_data cdata; print_fn_t print_fn; while ((ch = getopt(argc, argv, "p:x")) != -1) { switch (ch) { case 'p': /* TODO: Add human-readable ASCII page IDs */ log_page = strtol(optarg, &p, 0); if (p != NULL && *p != '\0') { fprintf(stderr, "\"%s\" not valid log page id.\n", optarg); logpage_usage(); /* TODO: Define valid log page id ranges in nvme.h? */ } else if (log_page == 0 || (log_page >= 0x04 && log_page <= 0x7F) || (log_page >= 0x80 && log_page <= 0xBF)) { fprintf(stderr, "\"%s\" not valid log page id.\n", optarg); logpage_usage(); } pageflag = true; break; case 'x': hexflag = true; break; } } if (!pageflag) { printf("Missing page_id (-p).\n"); logpage_usage(); } /* Check that a controller and/or namespace was specified. */ if (optind >= argc) logpage_usage(); /* * The log page attribtues indicate whether or not the controller * supports the SMART/Health information log page on a per * namespace basis. */ cname = malloc(strlen(NVME_CTRLR_PREFIX) + 2); len = strlen(NVME_CTRLR_PREFIX) + 1; cname = strncpy(cname, argv[optind], len); open_dev(cname, &fd, 1, 1); read_controller_data(fd, &cdata); if (log_page == NVME_LOG_HEALTH_INFORMATION && cdata.lpa.ns_smart != 0) allow_ns = true; /* If a namespace id was specified, validate it's use */ if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) { if (!allow_ns) { if (log_page != NVME_LOG_HEALTH_INFORMATION) { fprintf(stderr, "Namespace ID not valid for log page %d.\n", log_page); } else if (cdata.lpa.ns_smart == 0) { fprintf(stderr, "Controller does not support per " "namespace SMART/Health information.\n"); } close(fd); exit(EX_IOERR); } nsloc = strnstr(argv[optind], NVME_NS_PREFIX, 10); if (nsloc != NULL) nsid = strtol(nsloc + 2, NULL, 10); if (nsloc == NULL || (nsid == 0 && errno != 0)) { fprintf(stderr, "Invalid namespace ID %s.\n", argv[optind]); close(fd); exit(EX_IOERR); } /* * User is asking for per namespace log page information * so close the controller and open up the namespace. */ close(fd); open_dev(argv[optind], &fd, 1, 1); } else nsid = NVME_GLOBAL_NAMESPACE_TAG; print_fn = print_hex; if (!hexflag) { /* * See if there is a pretty print function for the * specified log page. If one isn't found, we * just revert to the default (print_hex). */ f = logfuncs; while (f->log_page > 0) { if (log_page == f->log_page) { print_fn = f->fn; break; } f++; } } /* Read the log page */ switch (log_page) { case NVME_LOG_ERROR: size = sizeof(struct nvme_error_information_entry); size *= (cdata.elpe + 1); break; case NVME_LOG_HEALTH_INFORMATION: size = sizeof(struct nvme_health_information_page); break; case NVME_LOG_FIRMWARE_SLOT: size = sizeof(struct nvme_firmware_page); break; default: size = DEFAULT_SIZE; break; } buf = get_log_buffer(size); read_logpage(fd, log_page, nsid, buf, size); print_fn(buf, size); close(fd); exit(EX_OK); }