From c827321fb287e4c122a8986e8edd1d355838ca18 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sat, 10 May 2025 00:35:07 -0400 Subject: kernel: ahci: Handle AHCI interface/HBA errors Signed-off-by: Ian Moffett --- sys/dev/ic/ahci.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) (limited to 'sys/dev/ic/ahci.c') 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 @@ -250,6 +250,56 @@ hba_port_start(struct hba_port *port) return 0; } +/* + * 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 * @@ -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); } /* -- cgit v1.2.3