summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2025-05-10 00:35:07 -0400
committerIan Moffett <ian@osmora.org>2025-05-10 00:35:07 -0400
commitc827321fb287e4c122a8986e8edd1d355838ca18 (patch)
treed9362a55acd88bbbbbb4f72c5eb0ede169725be6
parent822b5927a5072283ef787ea13186038ec0f46524 (diff)
kernel: ahci: Handle AHCI interface/HBA errors
Signed-off-by: Ian Moffett <ian@osmora.org>
-rw-r--r--sys/dev/ic/ahci.c52
-rw-r--r--sys/include/dev/ic/ahciregs.h20
2 files changed, 71 insertions, 1 deletions
diff --git a/sys/dev/ic/ahci.c b/sys/dev/ic/ahci.c
index d6428c9..9482c77 100644
--- a/sys/dev/ic/ahci.c
+++ b/sys/dev/ic/ahci.c
@@ -251,6 +251,56 @@ hba_port_start(struct hba_port *port)
}
/*
+ * Check for interface errors, returns
+ * 0 on success (i.e., no errors), otherwise
+ * the "ERR" word of PxSERR.
+ */
+static int
+hba_port_chkerr(struct hba_port *port)
+{
+ uint32_t serr;
+ uint16_t err;
+ uint8_t critical = 0;
+
+ serr = mmio_read32(&port->serr);
+ err = serr & 0xFFFF;
+ if (err == 0) {
+ return 0;
+ }
+
+ if (ISSET(err, AHCI_SERR_I)) {
+ pr_error("recovered data integrity error\n");
+ }
+ if (ISSET(err, AHCI_SERR_M)) {
+ pr_error("recovered comms error\n");
+ }
+ if (ISSET(err, AHCI_SERR_T)) {
+ pr_error("transient data integrity error\n");
+ }
+ if (ISSET(err, AHCI_SERR_C)) {
+ pr_error("persistent comms error\n");
+ critical = 1;
+ }
+ if (ISSET(err, AHCI_SERR_P)) {
+ pr_error("protocol error\n");
+ critical = 1;
+ }
+ if (ISSET(err, AHCI_SERR_E)) {
+ pr_error("internal hba error\n");
+ critical = 1;
+ }
+ if (critical) {
+ pr_error("CRITICAL - DISABLING PORT **\n");
+ hba_port_stop(port);
+ return err;
+ }
+
+ mmio_write32(&port->serr, 0xFFFFFFFF);
+ return err;
+
+}
+
+/*
* Reset a port on the HBA
*
* XXX: This function stops the port once the
@@ -352,7 +402,7 @@ ahci_submit_cmd(struct ahci_hba *hba, struct hba_port *port, uint8_t slot)
return status;
}
- return 0;
+ return hba_port_chkerr(port);
}
/*
diff --git a/sys/include/dev/ic/ahciregs.h b/sys/include/dev/ic/ahciregs.h
index f73e587..f959a1e 100644
--- a/sys/include/dev/ic/ahciregs.h
+++ b/sys/include/dev/ic/ahciregs.h
@@ -139,6 +139,26 @@ struct hba_memspace {
#define AHCI_IPM_ACTIVE 1
/*
+ * PxSERR bits
+ * See section 3.3.12 of the AHCI spec
+ */
+#define AHCI_SERR_I BIT(0) /* Recovered data integrity error */
+#define AHCI_SERR_M BIT(1) /* Recovered comms error */
+#define AHCI_SERR_T BIT(8) /* Transient data integrity error */
+#define AHCI_SERR_C BIT(9) /* Persistent comms error */
+#define AHCI_SERR_P BIT(10) /* Protocol error ("oh fuck!" bit) */
+#define AHCI_SERR_E BIT(11) /* Internal error (only God knows, just pray) */
+#define AHCI_DIAG_N BIT(16) /* PhyRdy change */
+#define AHCI_DIAG_I BIT(17) /* PHY internal error */
+#define AHCI_DIAG_W BIT(18) /* Comm wake */
+#define AHCI_DIAG_B BIT(19) /* 10B to 8B decode error */
+#define AHCI_DIAG_C BIT(21) /* CRC error */
+#define AHCI_DIAG_H BIT(22) /* Handshake error */
+#define AHCI_DIAG_S BIT(23) /* Link sequence error */
+#define AHCI_DIAG_T BIT(24) /* Transport state transition error */
+#define AHCI_DIAG_F BIT(25) /* Unknown FIS type */
+
+/*
* Device detection initialization values
* See section 3.3.11 of the AHCI spec.
*/