smartmontools/SOURCES/smartmontools-7.4-r5471.patch

313 lines
14 KiB
Diff

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)