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 c4b0101c18..e9d49f1703 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h @@ -76,6 +76,19 @@ enum { INT_DHR = (1 << 0), // Device to Host Register FIS Interrupt/Enable }; +typedef struct { + uint16 reserved : 12; + uint8 pmp : 4; // Port Multiplier Port: Not used by AHCI + uint8 spm : 4; // Select Power Management: Not used by AHCI + uint8 ipm : 4; // Interface Power Management Transitions Allowed + uint8 spd : 4; // Speed Allowed + uint8 det : 4; // Device Detection Initialization +} _PACKED scontrol; + +#define TRANSITIONS_TO_PARTIAL_SLUMBER_DISABLED 0x300 +#define NO_INITIALIZATION 0 +#define INITIALIZATION 1 + typedef struct { uint32 clb; // Command List Base Address (alignment 1024 byte) @@ -89,7 +102,7 @@ typedef struct { uint32 tfd; // Task File Data uint32 sig; // Signature uint32 ssts; // Serial ATA Status (SCR0: SStatus) - uint32 sctl; // Serial ATA Control (SCR2: SControl) + scontrol sctl; // Serial ATA Control (SCR2: SControl) uint32 serr; // Serial ATA Error (SCR1: SError) **RWC** uint32 sact; // Serial ATA Active (SCR3: SActive) **RW1** uint32 ci; // Command Issue **RW1** 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 a045771926..ed71461694 100644 --- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp +++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp @@ -110,7 +110,7 @@ AHCIPort::Init1() // prdt follows after command table // disable transitions to partial or slumber state - fRegs->sctl |= 0x300; + fRegs->sctl.ipm |= TRANSITIONS_TO_PARTIAL_SLUMBER_DISABLED; /*TODO Why "|= and not "=" ??*/ // clear IRQ status bits fRegs->is = fRegs->is; @@ -156,7 +156,12 @@ AHCIPort::Init2() TRACE("is 0x%08" B_PRIx32 "\n", fRegs->is); TRACE("cmd 0x%08" B_PRIx32 "\n", fRegs->cmd); TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts); - TRACE("sctl 0x%08" B_PRIx32 "\n", fRegs->sctl); + TRACE("sctl.reserved 0x%04" B_PRIx16 "\n", fRegs->sctl.reserved); + TRACE("sctl.pmp 0x%02" B_PRIx8 "\n", fRegs->sctl.pmp); + TRACE("sctl.spm 0x%02" B_PRIx8 "\n", fRegs->sctl.spm); + TRACE("sctl.ipm 0x%02" B_PRIx8 "\n", fRegs->sctl.ipm); + TRACE("sctl.spd 0x%02" B_PRIx8 "\n", fRegs->sctl.spd); + TRACE("sctl.det 0x%02" B_PRIx8 "\n", fRegs->sctl.det); TRACE("serr 0x%08" B_PRIx32 "\n", fRegs->serr); TRACE("sact 0x%08" B_PRIx32 "\n", fRegs->sact); TRACE("tfd 0x%08" B_PRIx32 "\n", fRegs->tfd); @@ -212,10 +217,10 @@ AHCIPort::ResetDevice() TRACE("AHCIPort::ResetDevice PORT_CMD_ST set, behaviour undefined\n"); // perform a hard reset - fRegs->sctl = (fRegs->sctl & ~0xf) | 1; + fRegs->sctl.det |= INITIALIZATION; //TODO Why "|=" instead of "=" ? FlushPostedWrites(); spin(1100); - fRegs->sctl &= ~0xf; + fRegs->sctl.det = NO_INITIALIZATION; FlushPostedWrites(); if (wait_until_set(&fRegs->ssts, 0x1, 100000) < B_OK) { @@ -364,10 +369,15 @@ AHCIPort::InterruptErrorHandler(uint32 is) TRACE("AHCIPort::InterruptErrorHandler port %d, fCommandsActive 0x%08" B_PRIx32 ", is 0x%08" B_PRIx32 ", ci 0x%08" B_PRIx32 "\n", fIndex, fCommandsActive, is, ci); - - TRACE("ssts 0x%08" B_PRIx32 ", sctl 0x%08" B_PRIx32 ", serr 0x%08" - B_PRIx32 ", sact 0x%08" B_PRIx32 "\n", - fRegs->ssts, fRegs->sctl, fRegs->serr, fRegs->sact); + TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts); + TRACE("sctl.reserved 0x%04" B_PRIx16 "\n", fRegs->sctl.reserved); + TRACE("sctl.pmp 0x%02" B_PRIx8 "\n", fRegs->sctl.pmp); + TRACE("sctl.spm 0x%02" B_PRIx8 "\n", fRegs->sctl.spm); + TRACE("sctl.ipm 0x%02" B_PRIx8 "\n", fRegs->sctl.ipm); + TRACE("sctl.spd 0x%02" B_PRIx8 "\n", fRegs->sctl.spd); + TRACE("sctl.det 0x%02" B_PRIx8 "\n", fRegs->sctl.det); + TRACE("serr 0x%08" B_PRIx32 "\n", fRegs->serr); + TRACE("sact 0x%08" B_PRIx32 "\n", fRegs->sact); } // read and clear SError @@ -413,6 +423,19 @@ AHCIPort::InterruptErrorHandler(uint32 is) } if (is & PORT_INT_PC) { TRACE("Port Connect Change\n"); + /* spec v1.3, ยง6.2.2.3 Recovery of Unsolicited COMINIT (a COMINIT that is + * not received as a consequence of issuing a COMRESET to the device) */ + + // perform a hard reset + fRegs->sctl.det |= INITIALIZATION; //TODO Why "|=" instead of "=" ? + FlushPostedWrites(); + spin(1100); // specification says you must wait 1ms + fRegs->sctl.det = NO_INITIALIZATION; + FlushPostedWrites(); + + // clear error bits to clear PxSERR.DIAG.X + fRegs->serr = fRegs->serr; + FlushPostedWrites(); // fResetPort = true; } if (is & PORT_INT_UF) {