From 1cdf60d569383248aa03275555a7474f9e2b9f42 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sat, 18 Jun 2016 10:27:43 -0700 Subject: [PATCH] nvme - Fix composite temperature in nvmectl * Fix composite temperature reporting in nvmectl. There are two byte fields making up a 16-word, not two separate byte fields. The confusion stemmed from the fact that the 16-bit word is not word-aligned (possibly the only field in the entire spec that isn't aligned!). * Add 'errors' directive to dump error logs. --- sbin/nvmectl/nvmectl.c | 76 ++++++++++++++- sbin/nvmectl/nvmectl.h | 1 + sbin/nvmectl/subs.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 318 insertions(+), 3 deletions(-) diff --git a/sbin/nvmectl/nvmectl.c b/sbin/nvmectl/nvmectl.c index 6859a99a43..4329b1c08d 100644 --- a/sbin/nvmectl/nvmectl.c +++ b/sbin/nvmectl/nvmectl.c @@ -38,6 +38,7 @@ typedef int (*cmd_t)(int ac, char **av, const char *id, int fd); static cmd_t parsecmd(int ac, char **av, int *globokp); static int cmd_info(int ac, char **av, const char *id, int fd); +static int cmd_errors(int ac, char **av, const char *id, int fd); static void usage(int rc); int VerboseOpt; @@ -129,6 +130,10 @@ parsecmd(int ac, char **av, int *globokp) *globokp = 1; return cmd_info; } + if (strcmp(av[0], "errors") == 0) { + *globokp = 1; + return cmd_errors; + } fprintf(stderr, "Command %s not recognized\n", av[0]); usage(1); @@ -183,9 +188,8 @@ cmd_info(int ac __unused, char **av __unused, const char *id, int fd) } else { printf("none\n"); } - printf("\tcomp_temp:\t%dC %dC\n", - smart->comp_temp1 - 273, - smart->comp_temp2 - 273); + printf("\tcomp_temp:\t%dC\n", + (int)(smart->comp_temp1 + (smart->comp_temp2 << 8)) - 273); printf("\tLIFE_LEFT:\t%d%% (%d%% used)\n", 100 - (int)smart->rated_life, (int)smart->rated_life); @@ -235,12 +239,78 @@ cmd_info(int ac __unused, char **av __unused, const char *id, int fd) } static +int +cmd_errors(int ac __unused, char **av __unused, const char *id, int fd) +{ + nvme_getlog_ioctl_t ioc; + nvme_log_error_data_t *errs; + int i; + + bzero(&ioc, sizeof(ioc)); + ioc.lid = NVME_LID_ERROR; + ioc.ret_size = sizeof(ioc.info.logsmart); + + if (ioctl(fd, NVMEIOCGETLOG, &ioc) < 0) { + fprintf(stderr, "ioctl failed: %s\n", strerror(errno)); + return 1; + } + if (NVME_COMQ_STATUS_CODE_GET(ioc.status)) { + fprintf(stderr, "%s: type %d code 0x%02x\n", + id, + NVME_COMQ_STATUS_TYPE_GET(ioc.status), + NVME_COMQ_STATUS_CODE_GET(ioc.status)); + return 1; + } + printf("%s:\n", id); + errs = &ioc.info.logerr[0]; + + for (i = 0; i < 64; ++i) { + if (errs->error_count == 0 && errs->subq_id == 0 && + errs->cmd_id == 0 && errs->status == 0 && + errs->param == 0 && errs->nsid == 0 && + errs->vendor == 0 && errs->csi == 0 && errs->lba == 0) + continue; + + if (errs->param || errs->vendor || errs->csi) { + printf("\t%2d cnt=%-3ld subq=%-2d cmdi=%-3d " + "status=%d,0x%02x parm=%04x nsid=%-3d vend=%d " + "csi=0x%lx lba=%ld", + i, errs->error_count, + (int16_t)errs->subq_id, + (int16_t)errs->cmd_id, + NVME_COMQ_STATUS_TYPE_GET(errs->status), + NVME_COMQ_STATUS_CODE_GET(errs->status), + errs->param, errs->nsid, + errs->vendor, + errs->csi, errs->lba); + } else { + printf("\t%2d cnt=%-3ld subq=%-2d cmdi=%-3d " + "status=%d,0x%02x nsid=%-3d lba=%ld", + i, errs->error_count, + (int16_t)errs->subq_id, + (int16_t)errs->cmd_id, + NVME_COMQ_STATUS_TYPE_GET(errs->status), + NVME_COMQ_STATUS_CODE_GET(errs->status), + errs->nsid, + errs->lba); + } + if (errs->status & NVME_COMQ_STATUS_DNR) + printf(" DNR"); + printf(" %s\n", status_to_str(errs->status)); + ++errs; + } + + return 0; +} + +static void usage(int rc) { fprintf(stderr, "nvmectl [-v] cmd [nvme0,1,2...]\n" "\tinfo\n" + "\terrors\n" ); exit(rc); } diff --git a/sbin/nvmectl/nvmectl.h b/sbin/nvmectl/nvmectl.h index a66bf693e8..bf7a39d76b 100644 --- a/sbin/nvmectl/nvmectl.h +++ b/sbin/nvmectl/nvmectl.h @@ -49,3 +49,4 @@ #include const char *format_number(uint64_t value); +const char *status_to_str(uint16_t status); diff --git a/sbin/nvmectl/subs.c b/sbin/nvmectl/subs.c index 02a4913efe..7341c5df76 100644 --- a/sbin/nvmectl/subs.c +++ b/sbin/nvmectl/subs.c @@ -44,3 +44,247 @@ format_number(uint64_t value) return buf; } + +const char * +status_to_str(uint16_t status) +{ + static char buf[64]; + int code = NVME_COMQ_STATUS_CODE_GET(status); + const char *msg = NULL; + + switch(NVME_COMQ_STATUS_TYPE_GET(status)) { + case NVME_STATUS_TYPE_GENERIC: + switch(code) { + case NVME_CODE_SUCCESS: + msg = "SUCCESS"; + break; + case NVME_CODE_BADOP: + msg = "Bad Op"; + break; + case NVME_CODE_BADFIELD: + msg = "Bad Field"; + break; + case NVME_CODE_IDCONFLICT: + msg = "ID Conflict"; + break; + case NVME_CODE_BADXFER: + msg = "Bad XFer"; + break; + case NVME_CODE_ABORTED_PWRLOSS: + msg = "Abort on Power Loss"; + break; + case NVME_CODE_INTERNAL: + msg = "Internal Error"; + break; + case NVME_CODE_ABORTED_ONREQ: + msg = "Abort on Request"; + break; + case NVME_CODE_ABORTED_SQDEL: + msg = "Abort on SubQ Deletion"; + break; + case NVME_CODE_ABORTED_FUSEFAIL: + msg = "Abort on Fuse Failed"; + break; + case NVME_CODE_ABORTED_FUSEMISSING: + msg = "Abort on Fuse Missing"; + break; + case NVME_CODE_BADNAMESPACE: + msg = "Bad Namespace"; + break; + case NVME_CODE_SEQERROR: + msg = "Seq Error"; + break; + case NVME_CODE_BADSGLSEG: + msg = "Bad SGL Segment"; + break; + case NVME_CODE_BADSGLCNT: + msg = "Bad SGL Count"; + break; + case NVME_CODE_BADSGLLEN: + msg = "Bad SGL Length"; + break; + case NVME_CODE_BADSGLMLEN: + msg = "Bad SGL MLength"; + break; + case NVME_CODE_BADSGLTYPE: + msg = "Bad SGL Type"; + break; + case NVME_CODE_BADMEMBUFUSE: + msg = "Bad Memory Buffer Usage"; + break; + case NVME_CODE_BADPRPOFF: + msg = "Bad PRP Offset"; + break; + case NVME_CODE_ATOMICWUOVFL: + msg = "Atomic Write Overflow"; + break; + case NVME_CODE_LBA_RANGE: + msg = "LBA Out of Range"; + break; + case NVME_CODE_CAP_EXCEEDED: + msg = "Capacity Exceeded"; + break; + case NVME_CODE_NAM_NOT_READY: + msg = "Namespace not Ready"; + break; + case NVME_CODE_RSV_CONFLICT: + msg = "Reservation Conflict"; + break; + case NVME_CODE_FMT_IN_PROG: + msg = "Format in Progress"; + break; + default: + snprintf(buf, sizeof(buf), "generic(0x%02x)", code); + break; + } + break; + case NVME_STATUS_TYPE_SPECIFIC: + switch(code) { + case NVME_CSSCODE_BADCOMQ: + msg = "Bad Completion Queue"; + break; + case NVME_CSSCODE_BADQID: + msg = "Bad Queue ID"; + break; + case NVME_CSSCODE_BADQSIZE: + msg = "Bad Queue Size"; + break; + case NVME_CSSCODE_ABORTLIM: + msg = "Too many Aborts"; + break; + case NVME_CSSCODE_RESERVED04: + msg = "reserved04"; + break; + case NVME_CSSCODE_ASYNCEVENTLIM: + msg = "Too many Async Events"; + break; + case NVME_CSSCODE_BADFWSLOT: + msg = "Bad Firmware Slot"; + break; + case NVME_CSSCODE_BADFWIMAGE: + msg = "Bad Firmware Image"; + break; + case NVME_CSSCODE_BADINTRVECT: + msg = "Bad Interrupt Vector"; + break; + case NVME_CSSCODE_BADLOGPAGE: + msg = "Unsupported Log Page"; + break; + case NVME_CSSCODE_BADFORMAT: + msg = "Bad Format Command"; + break; + case NVME_CSSCODE_FW_NEEDSCONVRESET: + msg = "Firmware Activation Needs Conventional Reset"; + break; + case NVME_CSSCODE_BADQDELETE: + msg = "Bad Queue Delete"; + break; + case NVME_CSSCODE_FEAT_NOT_SAVEABLE: + msg = "Feature not Saveable"; + break; + case NVME_CSSCODE_FEAT_NOT_CHGABLE: + msg = "Feature not Changeable"; + break; + case NVME_CSSCODE_FEAT_NOT_NSSPEC: + msg = "Feature not Namespace-Specific"; + break; + case NVME_CSSCODE_FW_NEEDSSUBRESET: + msg = "Firmware Activation Needs Subsystem Reset"; + break; + case NVME_CSSCODE_FW_NEEDSRESET: + msg = "Firmware Activation Needs Reset"; + break; + case NVME_CSSCODE_FW_NEEDSMAXTVIOLATE: + msg = "Firmware Activation Requires " + "Maximum Time Violation"; + break; + case NVME_CSSCODE_FW_PROHIBITED: + msg = "Firmware Activation Prohibited"; + break; + case NVME_CSSCODE_RANGE_OVERLAP: + msg = "Overlapping Range"; + break; + case NVME_CSSCODE_NAM_INSUFF_CAP: + msg = "Insufficient Capacity"; + break; + case NVME_CSSCODE_NAM_ID_UNAVAIL: + msg = "NSID is not Available"; + break; + case NVME_CSSCODE_RESERVED17: + msg = "reserved17"; + break; + case NVME_CSSCODE_NAM_ALREADY_ATT: + msg = "NSID Already Attached"; + break; + case NVME_CSSCODE_NAM_IS_PRIVATE: + msg = "NSID is Private"; + break; + case NVME_CSSCODE_NAM_NOT_ATT: + msg = "NSID Not Attached"; + break; + case NVME_CSSCODE_NO_THIN_PROVISION: + msg = "This Provisioning not Supported"; + break; + case NVME_CSSCODE_CTLR_LIST_INVALID: + msg = "Controller List Invalid"; + break; + case NVME_CSSCODE_ATTR_CONFLICT: + msg = "Conflicting Attributes"; + break; + case NVME_CSSCODE_BADPROTINFO: + msg = "Invalid Prortection Information"; + break; + case NVME_CSSCODE_WRITE_TO_RDONLY: + msg = "Attempted Write to Read Only Range"; + break; + default: + snprintf(buf, sizeof(buf), "specific(0x%02x)", code); + break; + } + break; + case NVME_STATUS_TYPE_MEDIA: + switch(code) { + case NVME_MEDCODE_WRITE_FAULT: + msg = "Write Fault"; + break; + case NVME_MEDCODE_UNRECOV_READ_ERROR: + msg = "Unrecoverable Read Error"; + break; + case NVME_MEDCODE_ETOE_GUARD_CHK: + msg = "End-to-End Guard Check Fail"; + break; + case NVME_MEDCODE_ETOE_APPTAG_CHK: + msg = "End-to-End Application Tag Check Error"; + break; + case NVME_MEDCODE_ETOE_REFTAG_CHK: + msg = "End-to-End Reference Tag Check Error"; + break; + case NVME_MEDCODE_COMPARE_FAILURE: + msg = "Compare Failure"; + break; + case NVME_MEDCODE_ACCESS_DENIED: + msg = "Access Denied"; + break; + case NVME_MEDCODE_UNALLOCATED: + msg = "Deallocated or Unwritten Logical Block"; + break; + default: + snprintf(buf, sizeof(buf), "media(0x%02x)", code); + break; + } + break; + case NVME_STATUS_TYPE_3: + case NVME_STATUS_TYPE_4: + case NVME_STATUS_TYPE_5: + case NVME_STATUS_TYPE_6: + buf[0] = 0; + break; + case NVME_STATUS_TYPE_VENDOR: + snprintf(buf, sizeof(buf), "vendor(0x%02x)", code); + break; + } + if (msg) + snprintf(buf, sizeof(buf), "%s", msg); + + return buf; +} -- 2.11.4.GIT