From 7276511833e6594784e56592585bf8fdf381f398 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 15 Mar 2021 07:29:39 +0000 Subject: Kernel/Storage: Add SATA error disambiguation --- Kernel/Storage/AHCI.h | 20 +++++++++++++++ Kernel/Storage/AHCIPort.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++-- Kernel/Storage/AHCIPort.h | 1 + 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(); -- cgit v1.2.3