Ticket #12295: ahci_irq_storm.patch

File ahci_irq_storm.patch, 6.1 KB (added by Anarchos, 9 years ago)

Solving boot failures due to "Port Connect Change" IRQ storm.

  • src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h

    diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h
    index c4b0101..1a689d3 100644
    a b enum {  
    7676    INT_DHR         = (1 << 0),     // Device to Host Register FIS Interrupt/Enable
    7777};
    7878
     79/*
     80 * From Spec v1.3, §3.3.11
     81 */
     82typedef struct {
     83    uint16 reserved:12; // Reserved
     84    uint8 pmp:4; // Port Multiplier Port (PMP) : This field is not used by AHCI.
     85    uint8 spm:4; // Select Power Management (SPM) : This field is not used by AHCI
     86    uint8 ipm:4; // Interface Power Management Trnasitions Allowed (IPM)
     87    uint8 spd:4; // Speed Allowed (SPD)
     88    uint8 det:4; //Device Detection Initialization (DET)
     89} _PACKED scontrol;
     90
     91#define TRANSITIONS_TO_PARTIAL_SLUMBER_DISABLED 3
     92#define NO_INITIALIZATION 0
     93#define INITIALIZATION 1
     94
    7995
    8096typedef struct {
    8197    uint32      clb;            // Command List Base Address (alignment 1024 byte)
    typedef struct {  
    89105    uint32      tfd;            // Task File Data
    90106    uint32      sig;            // Signature
    91107    uint32      ssts;           // Serial ATA Status (SCR0: SStatus)
    92     uint32      sctl;           // Serial ATA Control (SCR2: SControl)
     108    scontrol    sctl;           // Serial ATA Control (SCR2: SControl)
    93109    uint32      serr;           // Serial ATA Error (SCR1: SError) **RWC**
    94110    uint32      sact;           // Serial ATA Active (SCR3: SActive) **RW1**
    95111    uint32      ci;             // Command Issue **RW1**
  • src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp

    diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp
    index a045771..d89294e 100644
    a b AHCIPort::Init1()  
    110110    // prdt follows after command table
    111111
    112112    // disable transitions to partial or slumber state
    113     fRegs->sctl |= 0x300;
     113    fRegs->sctl.ipm |= TRANSITIONS_TO_PARTIAL_SLUMBER_DISABLED; /*TODO Why "|= and not "=" ??*/
    114114
    115115    // clear IRQ status bits
    116116    fRegs->is = fRegs->is;
    AHCIPort::Init2()  
    156156    TRACE("is   0x%08" B_PRIx32 "\n", fRegs->is);
    157157    TRACE("cmd  0x%08" B_PRIx32 "\n", fRegs->cmd);
    158158    TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts);
    159     TRACE("sctl 0x%08" B_PRIx32 "\n", fRegs->sctl);
     159    TRACE("sctl.reserved 0x%04" B_PRIx16 "\n", fRegs->sctl.reserved);
     160    TRACE("sctl.pmp 0x%02" B_PRIx8 "\n", fRegs->sctl.pmp);
     161    TRACE("sctl.spm 0x%02" B_PRIx8 "\n", fRegs->sctl.spm);
     162    TRACE("sctl.ipm 0x%02" B_PRIx8 "\n", fRegs->sctl.ipm);
     163    TRACE("sctl.spd 0x%02" B_PRIx8 "\n", fRegs->sctl.spd);
     164    TRACE("sctl.det 0x%02" B_PRIx8 "\n", fRegs->sctl.det);
    160165    TRACE("serr 0x%08" B_PRIx32 "\n", fRegs->serr);
    161166    TRACE("sact 0x%08" B_PRIx32 "\n", fRegs->sact);
    162167    TRACE("tfd  0x%08" B_PRIx32 "\n", fRegs->tfd);
    AHCIPort::ResetDevice()  
    212217        TRACE("AHCIPort::ResetDevice PORT_CMD_ST set, behaviour undefined\n");
    213218
    214219    // perform a hard reset
    215     fRegs->sctl = (fRegs->sctl & ~0xf) | 1;
     220    fRegs->sctl.det |= INITIALIZATION; //TODO Why "|=" instead of "=" ?
    216221    FlushPostedWrites();
    217222    spin(1100);
    218     fRegs->sctl &= ~0xf;
     223    fRegs->sctl.det = NO_INITIALIZATION;
    219224    FlushPostedWrites();
    220225
    221226    if (wait_until_set(&fRegs->ssts, 0x1, 100000) < B_OK) {
    AHCIPort::InterruptErrorHandler(uint32 is)  
    364369        TRACE("AHCIPort::InterruptErrorHandler port %d, fCommandsActive 0x%08"
    365370            B_PRIx32 ", is 0x%08" B_PRIx32 ", ci 0x%08" B_PRIx32 "\n", fIndex,
    366371            fCommandsActive, is, ci);
    367 
    368         TRACE("ssts 0x%08" B_PRIx32 ", sctl 0x%08" B_PRIx32 ", serr 0x%08"
    369             B_PRIx32 ", sact 0x%08" B_PRIx32 "\n",
    370             fRegs->ssts, fRegs->sctl, fRegs->serr, fRegs->sact);
     372        TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts);
     373        TRACE("sctl.reserved 0x%04" B_PRIx16 "\n", fRegs->sctl.reserved);
     374        TRACE("sctl.pmp 0x%02" B_PRIx8 "\n", fRegs->sctl.pmp);
     375        TRACE("sctl.spm 0x%02" B_PRIx8 "\n", fRegs->sctl.spm);
     376        TRACE("sctl.ipm 0x%02" B_PRIx8 "\n", fRegs->sctl.ipm);
     377        TRACE("sctl.spd 0x%02" B_PRIx8 "\n", fRegs->sctl.spd);
     378        TRACE("sctl.det 0x%02" B_PRIx8 "\n", fRegs->sctl.det);
     379        TRACE("serr 0x%08" B_PRIx32 "\n", fRegs->serr);
     380        TRACE("sact 0x%08" B_PRIx32 "\n", fRegs->sact);
    371381    }
    372382
    373383    // read and clear SError
    AHCIPort::InterruptErrorHandler(uint32 is)  
    411421        TRACE("PhyReady Change\n");
    412422//      fResetPort = true;
    413423    }
     424    //As we are in the InterruptErrorHandler, the §6.2.2.3 of the SATA specification v1.3 applies
    414425    if (is & PORT_INT_PC) {
    415426        TRACE("Port Connect Change\n");
     427        /* spec v1.3, §6.2.2.3 Recovery of Unsolicited COMINIT
     428        An unsolicited COMINIT is a COMINIT that is not received as a consequence of issuing a COMRESET to
     429        the device (refer to Serial ATA revision 2.6). If the HBA receives an unsolicited COMINIT during normal
     430        operation, the HBA shall perform the following actions;
     431         - Respond to the device with a COMRESET
     432         - Halt execution until PxIS.PCS is cleared to '0' by software
     433
     434         To detect this condition, software should check whether PxIS.PCS is set to '1' on an interrupt. The HBA
     435         cannot guarantee that a device received a COMRESET because a COMINIT may appear to be solicited
     436         to the HBA if it happens to occur closely to an issued COMRESET. Therefore, when software detects
     437         that PxIS.PCS is set, software should first issue a COMRESET to ensure that the device receives a
     438         COMRESET. Then software should perform the appropriate actions to clear PxIS.PCS to '0'. To recover,
     439         software should perform error recovery actions for a fatal error condition (including restarting the
     440         controller). Then software should perform a re-enumeration to check whether a new device has been inserted.
     441        */
     442        /*spec v1.3
     443          §3.3.5
     444          Port Connect Change Status (PCS): 1=Change in Current Connect Status. 0=No
     445          change in Current Connect Status. This bit reflects the state of PxSERR.DIAG.X. This
     446          bit is only cleared when PxSERR.DIAG.X is cleared.
     447        */
     448        /*spec v1.3
     449        §3.3.12 DIAG is RWC (Read/Write '1' to clear)
     450        */
     451       
     452   
     453    // perform a hard reset
     454    fRegs->sctl.det |= INITIALIZATION; //TODO Why "|=" instead of "=" ?
     455    FlushPostedWrites();
     456    spin(1100);
     457    fRegs->sctl.det = NO_INITIALIZATION;
     458    FlushPostedWrites();
     459   
     460    // clear error bits to clear PxSERR.DIAG.X
     461    fRegs->serr = fRegs->serr;
     462    FlushPostedWrites();
    416463//      fResetPort = true;
    417464    }
    418465    if (is & PORT_INT_UF) {