/* NOTE: enable the keyboard port but disable the keyboard * interrupt before calling "reset_kbd()". */ int reset_kbd(KBDC p) { int retry = KBD_MAXRETRY; int again = KBD_MAXWAIT; int c = KBD_RESEND; /* keep the compiler happy */ while (retry-- > 0) { empty_both_buffers(p, 10); if (!write_kbd_command(p, KBDC_RESET_KBD)) continue; emptyq(&kbdcp(p)->kbd); c = read_controller_data(p); if (verbose || bootverbose) log(LOG_DEBUG, "kbdc: RESET_KBD return code:%04x\n", c); if (c == KBD_ACK) /* keyboard has agreed to reset itself... */ break; } if (retry < 0) return FALSE; while (again-- > 0) { /* wait awhile, well, in fact we must wait quite loooooooooooong */ DELAY(KBD_RESETDELAY*1000); c = read_controller_data(p); /* RESET_DONE/RESET_FAIL */ if (c != -1) /* wait again if the controller is not ready */ break; } if (verbose || bootverbose) log(LOG_DEBUG, "kbdc: RESET_KBD status:%04x\n", c); if (c != KBD_RESET_DONE) return FALSE; return TRUE; }
int test_aux_port(KBDC p) { int retry = KBD_MAXRETRY; int again = KBD_MAXWAIT; int c = -1; while (retry-- > 0) { empty_both_buffers(p, 10); if (write_controller_command(p, KBDC_TEST_AUX_PORT)) break; } if (retry < 0) return FALSE; emptyq(&kbdcp(p)->kbd); while (again-- > 0) { c = read_controller_data(p); if (c != -1) /* try again if the controller is not ready */ break; } if (verbose || bootverbose) log(LOG_DEBUG, "kbdc: TEST_AUX_PORT status:%04x\n", c); return c; }
int test_controller(KBDC p) { int retry = KBD_MAXRETRY; int again = KBD_MAXWAIT; int c = KBD_DIAG_FAIL; while (retry-- > 0) { empty_both_buffers(p, 10); if (write_controller_command(p, KBDC_DIAGNOSE)) break; } if (retry < 0) return FALSE; emptyq(&kbdcp(p)->kbd); while (again-- > 0) { /* wait awhile */ DELAY(KBD_RESETDELAY*1000); c = read_controller_data(p); /* DIAG_DONE/DIAG_FAIL */ if (c != -1) /* wait again if the controller is not ready */ break; } if (verbose || bootverbose) log(LOG_DEBUG, "kbdc: DIAGNOSE status:%04x\n", c); return (c == KBD_DIAG_DONE); }
static void devlist(int argc, char *argv[]) { struct nvme_controller_data cdata; struct nvme_namespace_data nsdata; struct stat devstat; char name[64], path[64]; uint32_t i; int ch, ctrlr, exit_code, fd, found; exit_code = EX_OK; while ((ch = getopt(argc, argv, "")) != -1) { switch ((char)ch) { default: usage(); } } ctrlr = -1; found = 0; while (1) { ctrlr++; sprintf(name, "nvme%d", ctrlr); sprintf(path, "/dev/%s", name); if (stat(path, &devstat) != 0) break; found++; fd = open(path, O_RDWR); if (fd < 0) { printf("Could not open %s. errno=%d (%s)\n", path, errno, strerror(errno)); exit_code = EX_NOPERM; continue; } read_controller_data(fd, &cdata); printf("%6s: %s\n", name, cdata.mn); for (i = 0; i < cdata.nn; i++) { sprintf(name, "nvme%dns%d", ctrlr, i+1); read_namespace_data(fd, i+1, &nsdata); printf(" %10s (%lldGB)\n", name, nsdata.nsze * (long long)ns_get_sector_size(&nsdata) / 1024 / 1024 / 1024); } } if (found == 0) printf("No NVMe controllers found.\n"); exit(exit_code); }
void devlist(int argc, char *argv[]) { struct nvm_identify_controller cdata; struct nvm_identify_namespace nsdata; char name[64]; uint8_t mn[64]; uint32_t i; int ch, ctrlr, fd, found, ret; while ((ch = getopt(argc, argv, "")) != -1) { switch (ch) { default: devlist_usage(); } } ctrlr = -1; found = 0; while (1) { ctrlr++; sprintf(name, "%s%d", NVME_CTRLR_PREFIX, ctrlr); ret = open_dev(name, &fd, 0, 0); if (ret != 0) { if (ret == EACCES) { warnx("could not open "_PATH_DEV"%s\n", name); continue; } else break; } found++; read_controller_data(fd, &cdata); nvme_strvis(mn, sizeof(mn), cdata.mn, sizeof(cdata.mn)); printf("%6s: %s\n", name, mn); for (i = 0; i < cdata.nn; i++) { sprintf(name, "%s%d%s%d", NVME_CTRLR_PREFIX, ctrlr, NVME_NS_PREFIX, i+1); read_namespace_data(fd, i+1, &nsdata); printf(" %10s (%lldMB)\n", name, nsdata.nsze * (long long)ns_get_sector_size(&nsdata) / 1024 / 1024); } close(fd); } if (found == 0) printf("No NVMe controllers found.\n"); exit(1); }
static void identify_ctrlr(int argc, char *argv[]) { struct nvme_controller_data cdata; struct stat devstat; char path[64]; int ch, fd, hexflag = 0, hexlength; int verboseflag = 0; while ((ch = getopt(argc, argv, "vx")) != -1) { switch ((char)ch) { case 'v': verboseflag = 1; break; case 'x': hexflag = 1; break; default: usage(); } } sprintf(path, "/dev/%s", argv[optind]); if (stat(path, &devstat) < 0) { printf("Invalid device node %s. errno=%d (%s)\n", path, errno, strerror(errno)); exit(EX_IOERR); } fd = open(path, O_RDWR); if (fd < 0) { printf("Could not open %s. errno=%d (%s)\n", path, errno, strerror(errno)); exit(EX_NOPERM); } read_controller_data(fd, &cdata); if (hexflag == 1) { if (verboseflag == 1) hexlength = sizeof(struct nvme_controller_data); else hexlength = offsetof(struct nvme_controller_data, reserved5); print_controller_hex(&cdata, hexlength); exit(EX_OK); } if (verboseflag == 1) { printf("-v not currently supported without -x.\n"); usage(); } print_controller(&cdata); exit(EX_OK); }
int get_controller_command_byte(KBDC p) { if (kbdcp(p)->command_byte != -1) return kbdcp(p)->command_byte; if (!write_controller_command(p, KBDC_GET_COMMAND_BYTE)) return -1; emptyq(&kbdcp(p)->kbd); kbdcp(p)->command_byte = read_controller_data(p); return kbdcp(p)->command_byte; }
static void identify_ctrlr(int argc, char *argv[]) { struct nvme_controller_data cdata; int ch, fd, hexflag = 0, hexlength; int verboseflag = 0; while ((ch = getopt(argc, argv, "vx")) != -1) { switch ((char)ch) { case 'v': verboseflag = 1; break; case 'x': hexflag = 1; break; default: identify_usage(); } } /* Check that a controller was specified. */ if (optind >= argc) identify_usage(); open_dev(argv[optind], &fd, 1, 1); read_controller_data(fd, &cdata); close(fd); if (hexflag == 1) { if (verboseflag == 1) hexlength = sizeof(struct nvme_controller_data); else hexlength = offsetof(struct nvme_controller_data, reserved5); print_hex(&cdata, hexlength); exit(0); } if (verboseflag == 1) { fprintf(stderr, "-v not currently supported without -x\n"); identify_usage(); } print_controller(&cdata); 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; 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, 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); }
void firmware(int argc, char *argv[]) { int fd = -1, slot = 0; int a_flag, s_flag, f_flag; int activate_action, reboot_required; char ch, *p, *image = NULL; char *controller = NULL, prompt[64]; void *buf = NULL; int32_t size = 0; struct nvme_controller_data cdata; a_flag = s_flag = f_flag = false; while ((ch = getopt(argc, argv, "af:s:")) != -1) { switch (ch) { case 'a': a_flag = true; break; case 's': slot = strtol(optarg, &p, 0); if (p != NULL && *p != '\0') { fprintf(stderr, "\"%s\" not valid slot.\n", optarg); firmware_usage(); } else if (slot == 0) { fprintf(stderr, "0 is not a valid slot number. " "Slot numbers start at 1.\n"); firmware_usage(); } else if (slot > 7) { fprintf(stderr, "Slot number %s specified which is " "greater than max allowed slot number of " "7.\n", optarg); firmware_usage(); } s_flag = true; break; case 'f': image = optarg; f_flag = true; break; } } /* Check that a controller (and not a namespace) was specified. */ if (optind >= argc || strstr(argv[optind], NVME_NS_PREFIX) != NULL) firmware_usage(); if (!f_flag && !a_flag) { fprintf(stderr, "Neither a replace ([-f path_to_firmware]) nor " "activate ([-a]) firmware image action\n" "was specified.\n"); firmware_usage(); } if (!f_flag && a_flag && slot == 0) { fprintf(stderr, "Slot number to activate not specified.\n"); firmware_usage(); } controller = argv[optind]; open_dev(controller, &fd, 1, 1); read_controller_data(fd, &cdata); if (cdata.oacs.firmware == 0) errx(1, "controller does not support firmware activate/download"); if (f_flag && slot == 1 && cdata.frmw.slot1_ro) errx(1, "slot %d is marked as read only", slot); if (slot > cdata.frmw.num_slots) errx(1, "slot %d specified but controller only supports %d slots", slot, cdata.frmw.num_slots); if (a_flag && !f_flag && !slot_has_valid_firmware(fd, slot)) errx(1, "slot %d does not contain valid firmware,\n" "try 'nvmecontrol logpage -p 3 %s' to get a list " "of available images\n", slot, controller); if (f_flag) read_image_file(image, &buf, &size); if (f_flag && a_flag) printf("You are about to download and activate " "firmware image (%s) to controller %s.\n" "This may damage your controller and/or " "overwrite an existing firmware image.\n", image, controller); else if (a_flag) printf("You are about to activate a new firmware " "image on controller %s.\n" "This may damage your controller.\n", controller); else if (f_flag) printf("You are about to download firmware image " "(%s) to controller %s.\n" "This may damage your controller and/or " "overwrite an existing firmware image.\n", image, controller); printf("Are you sure you want to continue? (yes/no) "); while (1) { fgets(prompt, sizeof(prompt), stdin); if (strncasecmp(prompt, "yes", 3) == 0) break; if (strncasecmp(prompt, "no", 2) == 0) exit(1); printf("Please answer \"yes\" or \"no\". "); } if (f_flag) { update_firmware(fd, buf, size); if (a_flag) activate_action = NVME_AA_REPLACE_ACTIVATE; else activate_action = NVME_AA_REPLACE_NO_ACTIVATE; } else { activate_action = NVME_AA_ACTIVATE; } reboot_required = activate_firmware(fd, slot, activate_action); if (a_flag) { if (reboot_required) { printf("New firmware image activated but requires " "conventional reset (i.e. reboot) to " "complete activation.\n"); } else { printf("New firmware image activated and will take " "effect after next controller reset.\n" "Controller reset can be initiated via " "'nvmecontrol reset %s'\n", controller); } } close(fd); exit(0); }