summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke <luke.wilde@live.co.uk>2021-03-15 07:29:39 +0000
committerAndreas Kling <kling@serenityos.org>2021-03-15 09:57:27 +0100
commit7276511833e6594784e56592585bf8fdf381f398 (patch)
treed8406a7f67c46be641a86ea93c00a858791a4691
parenta166a65eff40ae69f21b491897054d9526a05275 (diff)
downloadserenity-7276511833e6594784e56592585bf8fdf381f398.zip
Kernel/Storage: Add SATA error disambiguation
-rw-r--r--Kernel/Storage/AHCI.h20
-rw-r--r--Kernel/Storage/AHCIPort.cpp60
-rw-r--r--Kernel/Storage/AHCIPort.h1
3 files changed, 79 insertions, 2 deletions
diff --git a/Kernel/Storage/AHCI.h b/Kernel/Storage/AHCI.h
index 5be8fc3054..61c45e95bd 100644
--- a/Kernel/Storage/AHCI.h
+++ b/Kernel/Storage/AHCI.h
@@ -418,6 +418,26 @@ enum PortInterruptFlag : u32 {
DHR = 1 << 0 /* Device to Host Register FIS */
};
+enum SErr : u32 {
+ DIAG_X = 1 << 26, /* Exchanged */
+ DIAG_F = 1 << 25, /* Unknown FIS Type */
+ DIAG_T = 1 << 24, /* Transport state transition error */
+ DIAG_S = 1 << 23, /* Link sequence error */
+ DIAG_H = 1 << 22, /* Handshake error */
+ DIAG_C = 1 << 21, /* CRC error */
+ DIAG_D = 1 << 20, /* Disparity error */
+ DIAG_B = 1 << 19, /* 10B to 8B decode error */
+ DIAG_W = 1 << 18, /* Comm Wake */
+ DIAG_I = 1 << 17, /* Phy Internal Error */
+ DIAG_N = 1 << 16, /* PhyRdy Change */
+ ERR_E = 1 << 11, /* Internal error */
+ ERR_P = 1 << 10, /* Protocol error */
+ ERR_C = 1 << 9, /* Persistent communication or data integrity error */
+ ERR_T = 1 << 8, /* Transient data integrity error */
+ ERR_M = 1 << 1, /* Received communications error */
+ ERR_I = 1 << 0, /* Recovered data integrity error */
+};
+
class PortInterruptStatusBitField {
public:
diff --git a/Kernel/Storage/AHCIPort.cpp b/Kernel/Storage/AHCIPort.cpp
index b3f1f464bf..8383f7b998 100644
--- a/Kernel/Storage/AHCIPort.cpp
+++ b/Kernel/Storage/AHCIPort.cpp
@@ -181,7 +181,8 @@ void AHCIPort::eject()
while (1) {
if (m_port_registers.serr != 0) {
- dbgln_if(AHCI_DEBUG, "AHCI Port {}: Eject Drive failed, SError {}", representative_port_index(), (u32)m_port_registers.serr);
+ dbgln_if(AHCI_DEBUG, "AHCI Port {}: Eject Drive failed, SError 0x{:08x}", representative_port_index(), (u32)m_port_registers.serr);
+ try_disambiguate_sata_error();
VERIFY_NOT_REACHED();
}
if ((m_port_registers.ci & (1 << unused_command_header.value())) == 0)
@@ -290,6 +291,60 @@ const char* AHCIPort::try_disambiguate_sata_status()
VERIFY_NOT_REACHED();
}
+void AHCIPort::try_disambiguate_sata_error()
+{
+ dmesgln("AHCI Port {}: SErr breakdown:", representative_port_index());
+ dmesgln("AHCI Port {}: Diagnostics:", representative_port_index());
+
+ constexpr u32 diagnostics_bitfield = 0xFFFF0000;
+ if ((m_port_registers.serr & diagnostics_bitfield) > 0) {
+ if (m_port_registers.serr & AHCI::SErr::DIAG_X)
+ dmesgln("AHCI Port {}: - Exchanged", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::DIAG_F)
+ dmesgln("AHCI Port {}: - Unknown FIS Type", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::DIAG_T)
+ dmesgln("AHCI Port {}: - Transport state transition error", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::DIAG_S)
+ dmesgln("AHCI Port {}: - Link sequence error", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::DIAG_H)
+ dmesgln("AHCI Port {}: - Handshake error", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::DIAG_C)
+ dmesgln("AHCI Port {}: - CRC error", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::DIAG_D)
+ dmesgln("AHCI Port {}: - Disparity error", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::DIAG_B)
+ dmesgln("AHCI Port {}: - 10B to 8B decode error", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::DIAG_W)
+ dmesgln("AHCI Port {}: - Comm Wake", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::DIAG_I)
+ dmesgln("AHCI Port {}: - Phy Internal Error", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::DIAG_N)
+ dmesgln("AHCI Port {}: - PhyRdy Change", representative_port_index());
+ } else {
+ dmesgln("AHCI Port {}: - No diagnostic information provided.", representative_port_index());
+ }
+
+ dmesgln("AHCI Port {}: Error(s):", representative_port_index());
+
+ constexpr u32 error_bitfield = 0xFFFF;
+ if ((m_port_registers.serr & error_bitfield) > 0) {
+ if (m_port_registers.serr & AHCI::SErr::ERR_E)
+ dmesgln("AHCI Port {}: - Internal error", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::ERR_P)
+ dmesgln("AHCI Port {}: - Protocol error", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::ERR_C)
+ dmesgln("AHCI Port {}: - Persistent communication or data integrity error", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::ERR_T)
+ dmesgln("AHCI Port {}: - Transient data integrity error", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::ERR_M)
+ dmesgln("AHCI Port {}: - Received communications error", representative_port_index());
+ if (m_port_registers.serr & AHCI::SErr::ERR_I)
+ dmesgln("AHCI Port {}: - Recovered data integrity error", representative_port_index());
+ } else {
+ dmesgln("AHCI Port {}: - No error information provided.", representative_port_index());
+ }
+}
+
void AHCIPort::rebase()
{
VERIFY(m_lock.is_locked());
@@ -535,7 +590,8 @@ bool AHCIPort::identify_device()
while (1) {
if (m_port_registers.serr != 0) {
- dbgln("AHCI Port {}: Identify failed, SError {}", representative_port_index(), (u32)m_port_registers.serr);
+ dbgln("AHCI Port {}: Identify failed, SError 0x{:08x}", representative_port_index(), (u32)m_port_registers.serr);
+ try_disambiguate_sata_error();
return false;
}
if ((m_port_registers.ci & (1 << unused_command_header.value())) == 0)
diff --git a/Kernel/Storage/AHCIPort.h b/Kernel/Storage/AHCIPort.h
index db7aaefc98..929e1640f7 100644
--- a/Kernel/Storage/AHCIPort.h
+++ b/Kernel/Storage/AHCIPort.h
@@ -92,6 +92,7 @@ private:
void eject();
const char* try_disambiguate_sata_status();
+ void try_disambiguate_sata_error();
bool initiate_sata_reset();
void rebase();