You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
313 lines
14 KiB
313 lines
14 KiB
8 months ago
|
diff -up smartmontools-7.1/dev_interface.cpp.r5471 smartmontools-7.1/dev_interface.cpp
|
||
|
--- smartmontools-7.1/dev_interface.cpp.r5471 2019-11-24 19:19:24.000000000 +0100
|
||
|
+++ smartmontools-7.1/dev_interface.cpp 2023-11-22 14:07:37.647756091 +0100
|
||
|
@@ -15,6 +15,7 @@
|
||
|
#include "dev_tunnelled.h"
|
||
|
#include "atacmds.h" // ATA_SMART_CMD/STATUS
|
||
|
#include "scsicmds.h" // scsi_cmnd_io
|
||
|
+#include "nvmecmds.h" // nvme_status_*()
|
||
|
#include "utility.h"
|
||
|
|
||
|
#include <errno.h>
|
||
|
@@ -235,12 +236,11 @@ bool scsi_device::scsi_pass_through_and_
|
||
|
|
||
|
bool nvme_device::set_nvme_err(nvme_cmd_out & out, unsigned status, const char * msg /* = 0 */)
|
||
|
{
|
||
|
- if (!status)
|
||
|
- throw std::logic_error("nvme_device: set_nvme_err() called with status=0");
|
||
|
-
|
||
|
out.status = status;
|
||
|
out.status_valid = true;
|
||
|
- return set_err(EIO, "%sNVMe Status 0x%02x", (msg ? msg : ""), status);
|
||
|
+ char buf[64];
|
||
|
+ return set_err(nvme_status_to_errno(status), "%s%s (0x%03x)", (msg ? msg : ""),
|
||
|
+ nvme_status_to_info_str(buf, status), status);
|
||
|
}
|
||
|
|
||
|
|
||
|
diff -up smartmontools-7.1/nvmecmds.cpp.r5471 smartmontools-7.1/nvmecmds.cpp
|
||
|
--- smartmontools-7.1/nvmecmds.cpp.r5471 2023-11-22 14:07:37.646756079 +0100
|
||
|
+++ smartmontools-7.1/nvmecmds.cpp 2023-11-22 14:07:37.648756102 +0100
|
||
|
@@ -258,3 +258,221 @@ bool nvme_read_smart_log(nvme_device * d
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
+
|
||
|
+// Return flagged error message for NVMe status SCT/SC fields or nullptr if unknown.
|
||
|
+// If message starts with '-', the status indicates an invalid command (EINVAL).
|
||
|
+static const char * nvme_status_to_flagged_str(uint16_t status)
|
||
|
+{
|
||
|
+ // Section 3.3.3.2.1 of NVM Express Base Specification Revision 2.0c, October 4, 2022
|
||
|
+ uint8_t sc = (uint8_t)status;
|
||
|
+ switch ((status >> 8) & 0x7) {
|
||
|
+ case 0x0: // Generic Command Status
|
||
|
+ if (sc < 0x80) switch (sc) {
|
||
|
+ case 0x00: return "Successful Completion";
|
||
|
+ case 0x01: return "-Invalid Command Opcode";
|
||
|
+ case 0x02: return "-Invalid Field in Command";
|
||
|
+ case 0x03: return "Command ID Conflict";
|
||
|
+ case 0x04: return "Data Transfer Error";
|
||
|
+ case 0x05: return "Commands Aborted due to Power Loss Notification";
|
||
|
+ case 0x06: return "Internal Error";
|
||
|
+ case 0x07: return "Command Abort Requested";
|
||
|
+ case 0x08: return "Command Aborted due to SQ Deletion";
|
||
|
+ case 0x09: return "Command Aborted due to Failed Fused Command";
|
||
|
+ case 0x0a: return "Command Aborted due to Missing Fused Command";
|
||
|
+ case 0x0b: return "-Invalid Namespace or Format";
|
||
|
+ case 0x0c: return "Command Sequence Error";
|
||
|
+ case 0x0d: return "-Invalid SGL Segment Descriptor";
|
||
|
+ case 0x0e: return "-Invalid Number of SGL Descriptors";
|
||
|
+ case 0x0f: return "-Data SGL Length Invalid";
|
||
|
+ case 0x10: return "-Metadata SGL Length Invalid";
|
||
|
+ case 0x11: return "-SGL Descriptor Type Invalid";
|
||
|
+ case 0x12: return "-Invalid Use of Controller Memory Buffer";
|
||
|
+ case 0x13: return "-PRP Offset Invalid";
|
||
|
+ case 0x14: return "Atomic Write Unit Exceeded";
|
||
|
+ case 0x15: return "Operation Denied";
|
||
|
+ case 0x16: return "-SGL Offset Invalid";
|
||
|
+ case 0x18: return "Host Identifier Inconsistent Format";
|
||
|
+ case 0x19: return "Keep Alive Timer Expired";
|
||
|
+ case 0x1a: return "-Keep Alive Timeout Invalid";
|
||
|
+ case 0x1b: return "Command Aborted due to Preempt and Abort";
|
||
|
+ case 0x1c: return "Sanitize Failed";
|
||
|
+ case 0x1d: return "Sanitize In Progress";
|
||
|
+ case 0x1e: return "SGL Data Block Granularity Invalid";
|
||
|
+ case 0x1f: return "Command Not Supported for Queue in CMB";
|
||
|
+ case 0x20: return "Namespace is Write Protected";
|
||
|
+ case 0x21: return "Command Interrupted";
|
||
|
+ case 0x22: return "Transient Transport Error";
|
||
|
+ case 0x23: return "Command Prohibited by Command and Feature Lockdown";
|
||
|
+ case 0x24: return "Admin Command Media Not Ready";
|
||
|
+ // 0x25-0x7f: Reserved
|
||
|
+ }
|
||
|
+ else switch (sc) {
|
||
|
+ // 0x80-0xbf: I/O Command Set Specific
|
||
|
+ case 0x80: return "LBA Out of Range";
|
||
|
+ case 0x81: return "Capacity Exceeded";
|
||
|
+ case 0x82: return "Namespace Not Ready";
|
||
|
+ case 0x83: return "Reservation Conflict";
|
||
|
+ case 0x84: return "Format In Progress";
|
||
|
+ case 0x85: return "-Invalid Value Size";
|
||
|
+ case 0x86: return "-Invalid Key Size";
|
||
|
+ case 0x87: return "KV Key Does Not Exist";
|
||
|
+ case 0x88: return "Unrecovered Error";
|
||
|
+ case 0x89: return "Key Exists";
|
||
|
+ // 0x90-0xbf: Reserved
|
||
|
+ // 0xc0-0xff: Vendor Specific
|
||
|
+ }
|
||
|
+ break;
|
||
|
+
|
||
|
+ case 0x1: // Command Specific Status
|
||
|
+ if (sc < 0x80) switch (sc) {
|
||
|
+ case 0x00: return "-Completion Queue Invalid";
|
||
|
+ case 0x01: return "-Invalid Queue Identifier";
|
||
|
+ case 0x02: return "-Invalid Queue Size";
|
||
|
+ case 0x03: return "Abort Command Limit Exceeded";
|
||
|
+ case 0x04: return "Abort Command Is Missing";
|
||
|
+ case 0x05: return "Asynchronous Event Request Limit Exceeded";
|
||
|
+ case 0x06: return "-Invalid Firmware Slot";
|
||
|
+ case 0x07: return "-Invalid Firmware Image";
|
||
|
+ case 0x08: return "-Invalid Interrupt Vector";
|
||
|
+ case 0x09: return "-Invalid Log Page";
|
||
|
+ case 0x0a: return "-Invalid Format";
|
||
|
+ case 0x0b: return "Firmware Activation Requires Conventional Reset";
|
||
|
+ case 0x0c: return "-Invalid Queue Deletion";
|
||
|
+ case 0x0d: return "Feature Identifier Not Saveable";
|
||
|
+ case 0x0e: return "Feature Not Changeable";
|
||
|
+ case 0x0f: return "Feature Not Namespace Specific";
|
||
|
+ case 0x10: return "Firmware Activation Requires NVM Subsystem Reset";
|
||
|
+ case 0x11: return "Firmware Activation Requires Controller Level Reset";
|
||
|
+ case 0x12: return "Firmware Activation Requires Maximum Time Violation";
|
||
|
+ case 0x13: return "Firmware Activation Prohibited";
|
||
|
+ case 0x14: return "Overlapping Range";
|
||
|
+ case 0x15: return "Namespace Insufficient Capacity";
|
||
|
+ case 0x16: return "-Namespace Identifier Unavailable";
|
||
|
+ case 0x18: return "Namespace Already Attached";
|
||
|
+ case 0x19: return "Namespace Is Private";
|
||
|
+ case 0x1a: return "Namespace Not Attached";
|
||
|
+ case 0x1b: return "Thin Provisioning Not Supported";
|
||
|
+ case 0x1c: return "-Controller List Invalid";
|
||
|
+ case 0x1d: return "Device Self-test In Progress";
|
||
|
+ case 0x1e: return "Boot Partition Write Prohibited";
|
||
|
+ case 0x1f: return "Invalid Controller Identifier";
|
||
|
+ case 0x20: return "-Invalid Secondary Controller State";
|
||
|
+ case 0x21: return "-Invalid Number of Controller Resources";
|
||
|
+ case 0x22: return "-Invalid Resource Identifier";
|
||
|
+ case 0x23: return "Sanitize Prohibited While Persistent Memory Region is Enabled";
|
||
|
+ case 0x24: return "-ANA Group Identifier Invalid";
|
||
|
+ case 0x25: return "ANA Attach Failed";
|
||
|
+ case 0x26: return "Insufficient Capacity";
|
||
|
+ case 0x27: return "Namespace Attachment Limit Exceeded";
|
||
|
+ case 0x28: return "Prohibition of Command Execution Not Supported";
|
||
|
+ case 0x29: return "I/O Command Set Not Supported";
|
||
|
+ case 0x2a: return "I/O Command Set Not Enabled";
|
||
|
+ case 0x2b: return "I/O Command Set Combination Rejected";
|
||
|
+ case 0x2c: return "-Invalid I/O Command Set";
|
||
|
+ case 0x2d: return "-Identifier Unavailable";
|
||
|
+ // 0x2e-0x6f: Reserved
|
||
|
+ // 0x70-0x7f: Directive Specific
|
||
|
+ }
|
||
|
+ else if (sc < 0xb8) switch (sc) {
|
||
|
+ // 0x80-0xbf: I/O Command Set Specific (overlap with Fabrics Command Set)
|
||
|
+ case 0x80: return "-Conflicting Attributes";
|
||
|
+ case 0x81: return "-Invalid Protection Information";
|
||
|
+ case 0x82: return "Attempted Write to Read Only Range";
|
||
|
+ case 0x83: return "Command Size Limit Exceeded";
|
||
|
+ // 0x84-0xb7: Reserved
|
||
|
+ }
|
||
|
+ else switch (sc) {
|
||
|
+ case 0xb8: return "Zoned Boundary Error";
|
||
|
+ case 0xb9: return "Zone Is Full";
|
||
|
+ case 0xba: return "Zone Is Read Only";
|
||
|
+ case 0xbb: return "Zone Is Offline";
|
||
|
+ case 0xbc: return "Zone Invalid Write";
|
||
|
+ case 0xbd: return "Too Many Active Zones";
|
||
|
+ case 0xbe: return "Too Many Open Zones";
|
||
|
+ case 0xbf: return "Invalid Zone State Transition";
|
||
|
+ // 0xc0-0xff: Vendor Specific
|
||
|
+ }
|
||
|
+ break;
|
||
|
+
|
||
|
+ case 0x2: // Media and Data Integrity Errors
|
||
|
+ switch (sc) {
|
||
|
+ // 0x00-0x7f: Reserved
|
||
|
+ case 0x80: return "Write Fault";
|
||
|
+ case 0x81: return "Unrecovered Read Error";
|
||
|
+ case 0x82: return "End-to-end Guard Check Error";
|
||
|
+ case 0x83: return "End-to-end Application Tag Check Error";
|
||
|
+ case 0x84: return "End-to-end Reference Tag Check Error";
|
||
|
+ case 0x85: return "Compare Failure";
|
||
|
+ case 0x86: return "Access Denied";
|
||
|
+ case 0x87: return "Deallocated or Unwritten Logical Block";
|
||
|
+ case 0x88: return "End-to-End Storage Tag Check Error";
|
||
|
+ // 0x89-0xbf: Reserved
|
||
|
+ // 0xc0-0xff: Vendor Specific
|
||
|
+ }
|
||
|
+ break;
|
||
|
+
|
||
|
+ case 0x3: // Path Related Status
|
||
|
+ switch (sc) {
|
||
|
+ case 0x00: return "Internal Path Error";
|
||
|
+ case 0x01: return "Asymmetric Access Persistent Loss";
|
||
|
+ case 0x02: return "Asymmetric Access Inaccessible";
|
||
|
+ case 0x03: return "Asymmetric Access Transition";
|
||
|
+ // 0x04-0x5f: Reserved
|
||
|
+ // 0x60-0x6f: Controller Detected Pathing Errors
|
||
|
+ case 0x60: return "Controller Pathing Error";
|
||
|
+ // 0x61-0x6f: Reserved
|
||
|
+ // 0x70-0x7f: Host Detected Pathing Errors
|
||
|
+ case 0x70: return "Host Pathing Error";
|
||
|
+ case 0x71: return "Command Aborted By Host";
|
||
|
+ // 0x72-0x7f: Reserved
|
||
|
+ // 0x80-0xbf: I/O Command Set Specific
|
||
|
+ // 0xc0-0xff: Vendor Specific
|
||
|
+ }
|
||
|
+ break;
|
||
|
+
|
||
|
+ // 0x4-0x6: Reserved
|
||
|
+ // 0x7: Vendor Specific
|
||
|
+ }
|
||
|
+ return nullptr;
|
||
|
+}
|
||
|
+
|
||
|
+// Return errno for NVMe status SCT/SC fields: 0, EINVAL or EIO.
|
||
|
+int nvme_status_to_errno(uint16_t status)
|
||
|
+{
|
||
|
+ if (!nvme_status_is_error(status))
|
||
|
+ return 0;
|
||
|
+ const char * s = nvme_status_to_flagged_str(status);
|
||
|
+ if (s && *s == '-')
|
||
|
+ return EINVAL;
|
||
|
+ return EIO;
|
||
|
+}
|
||
|
+
|
||
|
+// Return error message for NVMe status SCT/SC fields or nullptr if unknown.
|
||
|
+const char * nvme_status_to_str(uint16_t status)
|
||
|
+{
|
||
|
+ const char * s = nvme_status_to_flagged_str(status);
|
||
|
+ return (s && *s == '-' ? s + 1 : s);
|
||
|
+}
|
||
|
+
|
||
|
+// Return error message for NVMe status SCT/SC fields or explanatory message if unknown.
|
||
|
+const char * nvme_status_to_info_str(char * buf, size_t bufsize, uint16_t status)
|
||
|
+{
|
||
|
+ const char * s = nvme_status_to_str(status);
|
||
|
+ if (s)
|
||
|
+ return s;
|
||
|
+
|
||
|
+ uint8_t sct = (status >> 8) & 0x7, sc = (uint8_t)status;
|
||
|
+ const char * pfx = (sc >= 0xc0 ? "Vendor Specific " : "Unknown ");
|
||
|
+ switch (sct) {
|
||
|
+ case 0x0: s = "Generic Command Status"; break;
|
||
|
+ case 0x1: s = "Command Specific Status"; break;
|
||
|
+ case 0x2: s = "Media and Data Integrity Error"; break;
|
||
|
+ case 0x3: s = "Path Related Status"; break;
|
||
|
+ case 0x7: s = "Vendor Specific Status"; pfx = ""; break;
|
||
|
+ }
|
||
|
+ if (s)
|
||
|
+ snprintf(buf, bufsize, "%s%s 0x%02x", pfx, s, sc);
|
||
|
+ else
|
||
|
+ snprintf(buf, bufsize, "Unknown Status 0x%x/0x%02x", sct, sc);
|
||
|
+ return buf;
|
||
|
+}
|
||
|
diff -up smartmontools-7.1/nvmecmds.h.r5471 smartmontools-7.1/nvmecmds.h
|
||
|
--- smartmontools-7.1/nvmecmds.h.r5471 2023-11-22 14:07:37.646756079 +0100
|
||
|
+++ smartmontools-7.1/nvmecmds.h 2023-11-22 14:09:29.911084240 +0100
|
||
|
@@ -18,6 +18,8 @@
|
||
|
|
||
|
#include "static_assert.h"
|
||
|
|
||
|
+#include <errno.h>
|
||
|
+#include <stddef.h>
|
||
|
#include <stdint.h>
|
||
|
|
||
|
// The code below was originally imported from <linux/nvme.h> include file from
|
||
|
@@ -246,4 +248,22 @@ unsigned nvme_read_error_log(nvme_device
|
||
|
// Read NVMe SMART/Health Information log.
|
||
|
bool nvme_read_smart_log(nvme_device * device, smartmontools::nvme_smart_log & smart_log);
|
||
|
|
||
|
+// Return true if NVMe status indicates an error.
|
||
|
+constexpr bool nvme_status_is_error(uint16_t status)
|
||
|
+ { return !!(status & 0x07ff); }
|
||
|
+
|
||
|
+// Return errno for NVMe status SCT/SC fields: 0, EINVAL or EIO.
|
||
|
+int nvme_status_to_errno(uint16_t status);
|
||
|
+
|
||
|
+// Return error message for NVMe status SCT/SC fields or nullptr if unknown.
|
||
|
+const char * nvme_status_to_str(uint16_t status);
|
||
|
+
|
||
|
+// Return error message for NVMe status SCT/SC fields or explanatory message if unknown.
|
||
|
+const char * nvme_status_to_info_str(char * buf, size_t bufsize, uint16_t status);
|
||
|
+
|
||
|
+// Version of above for fixed size buffers.
|
||
|
+template <size_t SIZE>
|
||
|
+inline const char * nvme_status_to_info_str(char (& buf)[SIZE], unsigned status)
|
||
|
+ { return nvme_status_to_info_str(buf, SIZE, status); }
|
||
|
+
|
||
|
#endif // NVMECMDS_H
|
||
|
diff -up smartmontools-7.1/nvmeprint.cpp.r5471 smartmontools-7.1/nvmeprint.cpp
|
||
|
--- smartmontools-7.1/nvmeprint.cpp.r5471 2023-11-22 14:07:37.648756102 +0100
|
||
|
+++ smartmontools-7.1/nvmeprint.cpp 2023-11-22 14:11:35.899574762 +0100
|
||
|
@@ -420,7 +420,7 @@ static void print_error_log(const nvme_e
|
||
|
continue;
|
||
|
|
||
|
if (cnt == 1)
|
||
|
- pout("Num ErrCount SQId CmdId Status PELoc LBA NSID VS\n");
|
||
|
+ pout("Num ErrCount SQId CmdId Status PELoc LBA NSID VS Message\n");
|
||
|
|
||
|
char sq[16] = "-", cm[16] = "-", st[16] = "-", pe[16] = "-";
|
||
|
char lb[32] = "-", ns[16] = "-", vs[8] = "-";
|
||
|
@@ -439,8 +439,10 @@ static void print_error_log(const nvme_e
|
||
|
if (e.vs != 0x00)
|
||
|
snprintf(vs, sizeof(vs), "0x%02x", e.vs);
|
||
|
|
||
|
- pout("%3u %10" PRIu64 " %5s %7s %7s %6s %12s %5s %5s\n",
|
||
|
- i, e.error_count, sq, cm, st, pe, lb, ns, vs);
|
||
|
+ char buf[64];
|
||
|
+ pout("%3u %10" PRIu64 " %5s %7s %7s %6s %12s %5s %5s %s\n",
|
||
|
+ i, e.error_count, sq, cm, st, pe, lb, ns, vs,
|
||
|
+ nvme_status_to_info_str(buf, e.status_field >> 1));
|
||
|
}
|
||
|
|
||
|
if (!cnt)
|