ahci: Simplification of reset code
* This simplifies the reset process again while keeping my original cleanups. * I think trying a software reset before a hardware reset is desireable, however lets work on base functionality first.
This commit is contained in:
@@ -59,7 +59,7 @@ AHCIPort::AHCIPort(AHCIController* controller, int index)
|
|||||||
fSectorCount(0),
|
fSectorCount(0),
|
||||||
fIsATAPI(false),
|
fIsATAPI(false),
|
||||||
fTestUnitReadyActive(false),
|
fTestUnitReadyActive(false),
|
||||||
fSoftReset(false),
|
fPortReset(false),
|
||||||
fError(false),
|
fError(false),
|
||||||
fTrimSupported(false)
|
fTrimSupported(false)
|
||||||
{
|
{
|
||||||
@@ -158,7 +158,7 @@ AHCIPort::Init2()
|
|||||||
FlushPostedWrites();
|
FlushPostedWrites();
|
||||||
|
|
||||||
// reset port and probe info
|
// reset port and probe info
|
||||||
SoftReset();
|
ResetDevice();
|
||||||
|
|
||||||
DumpHBAState();
|
DumpHBAState();
|
||||||
|
|
||||||
@@ -229,92 +229,6 @@ AHCIPort::ResetDevice()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
AHCIPort::SoftReset()
|
|
||||||
{
|
|
||||||
TRACE("AHCIPort::SoftReset port %d\n", fIndex);
|
|
||||||
|
|
||||||
// Spec v1.3.1, §10.4.1 Software Reset
|
|
||||||
// A single device on one port is reset, HBA and phy comm remain intact.
|
|
||||||
|
|
||||||
// stop port, flush transactions
|
|
||||||
if (!Disable()) {
|
|
||||||
// If the port doesn't power off, move on to a stronger reset.
|
|
||||||
ERROR("%s: port %d soft reset failed. Moving on to port reset.\n",
|
|
||||||
__func__, fIndex);
|
|
||||||
return PortReset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// start port
|
|
||||||
Enable();
|
|
||||||
|
|
||||||
if (wait_until_clear(&fRegs->tfd, ATA_STATUS_BUSY | ATA_STATUS_DATA_REQUEST,
|
|
||||||
1000000) < B_OK) {
|
|
||||||
ERROR("%s: port %d still busy. Moving on to port reset.\n",
|
|
||||||
__func__, fIndex);
|
|
||||||
return PortReset();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Just can't get AHCI software reset issued properly.
|
|
||||||
#if 0
|
|
||||||
// Spec v1.2.0, §9.3.9
|
|
||||||
// If FBS supported + enabled, disable
|
|
||||||
bool fbsDisabled = false;
|
|
||||||
if ((fRegs->cap & CAP_FBSS) != 0) {
|
|
||||||
if ((fRegs->fbs & PORT_FBS_EN) != 0) {
|
|
||||||
fbsDisabled = true;
|
|
||||||
fRegs->fbs &= ~PORT_FBS_EN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set command table soft reset bit
|
|
||||||
fCommandTable->cfis[2] |= ATA_DEVICE_CONTROL_SOFT_RESET;
|
|
||||||
|
|
||||||
// TODO: We could use a low level ahci command call (~ahci_exec_polled_cmd)
|
|
||||||
cpu_status cpu = disable_interrupts();
|
|
||||||
acquire_spinlock(&fSpinlock);
|
|
||||||
|
|
||||||
// FIS ATA set Reset + clear busy
|
|
||||||
fCommandList[0].r = 1;
|
|
||||||
fCommandList[0].c = 1;
|
|
||||||
// FIS ATA clear Reset + clear busy
|
|
||||||
fCommandList[1].r = 0;
|
|
||||||
fCommandList[1].c = 0;
|
|
||||||
|
|
||||||
// Issue Command
|
|
||||||
fRegs->ci = 1;
|
|
||||||
FlushPostedWrites();
|
|
||||||
release_spinlock(&fSpinlock);
|
|
||||||
restore_interrupts(cpu);
|
|
||||||
|
|
||||||
if (wait_until_clear(&fRegs->ci, 0, 1000000) < B_OK) {
|
|
||||||
TRACE("%s: port %d: device is busy\n", __func__, fIndex);
|
|
||||||
|
|
||||||
// Before we bail-out. Re-enable FBS if we disabled it
|
|
||||||
if (fbsDisabled)
|
|
||||||
fRegs->fbs |= PORT_FBS_EN;
|
|
||||||
return PortReset();
|
|
||||||
}
|
|
||||||
|
|
||||||
fCommandTable->cfis[2] &= ~ATA_DEVICE_CONTROL_SOFT_RESET;
|
|
||||||
|
|
||||||
if (fbsDisabled)
|
|
||||||
fRegs->fbs |= PORT_FBS_EN;
|
|
||||||
|
|
||||||
if (wait_until_clear(&fRegs->tfd, ATA_STATUS_BUSY | ATA_STATUS_DATA_REQUEST,
|
|
||||||
1000000) < B_OK) {
|
|
||||||
ERROR("%s: port %d software reset failed. Doing port reset...\n",
|
|
||||||
__func__, fIndex);
|
|
||||||
return PortReset();
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return PortReset();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return Probe();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
AHCIPort::PortReset()
|
AHCIPort::PortReset()
|
||||||
{
|
{
|
||||||
@@ -327,13 +241,21 @@ AHCIPort::PortReset()
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
fRegs->sctl |= SCTL_PORT_DET_INIT;
|
_ClearErrorRegister();
|
||||||
|
|
||||||
|
// Wait for BSY and DRQ to clear (idle port)
|
||||||
|
wait_until_clear(&fRegs->tfd, ATA_STATUS_BUSY | ATA_STATUS_DATA_REQUEST,
|
||||||
|
1000000);
|
||||||
|
|
||||||
|
// comreset. Notice we're throwing out all other control flags.
|
||||||
|
fRegs->sctl = (SSTS_PORT_IPM_ACTIVE | SSTS_PORT_IPM_PARTIAL
|
||||||
|
| SCTL_PORT_DET_INIT);
|
||||||
FlushPostedWrites();
|
FlushPostedWrites();
|
||||||
spin(1100);
|
spin(1100);
|
||||||
// You must wait 1ms at minimum
|
// You must wait 1ms at minimum
|
||||||
fRegs->sctl = (fRegs->sctl & ~HBA_PORT_DET_MASK) | SCTL_PORT_DET_NOINIT;
|
fRegs->sctl = (fRegs->sctl & ~HBA_PORT_DET_MASK) | SCTL_PORT_DET_NOINIT;
|
||||||
|
// Enable also flushes above write
|
||||||
FlushPostedWrites();
|
Enable();
|
||||||
|
|
||||||
if (wait_until_set(&fRegs->ssts, SSTS_PORT_DET_PRESENT, 500000) < B_OK) {
|
if (wait_until_set(&fRegs->ssts, SSTS_PORT_DET_PRESENT, 500000) < B_OK) {
|
||||||
TRACE("%s: port %d: no device detected\n", __func__, fIndex);
|
TRACE("%s: port %d: no device detected\n", __func__, fIndex);
|
||||||
@@ -341,8 +263,6 @@ AHCIPort::PortReset()
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Enable();
|
|
||||||
|
|
||||||
return Probe();
|
return Probe();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -391,8 +311,6 @@ AHCIPort::Probe()
|
|||||||
? "ATA" : "unknown");
|
? "ATA" : "unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
_ClearErrorRegister();
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,22 +395,22 @@ AHCIPort::InterruptErrorHandler(uint32 is)
|
|||||||
if (!fTestUnitReadyActive)
|
if (!fTestUnitReadyActive)
|
||||||
TRACE("Task File Error\n");
|
TRACE("Task File Error\n");
|
||||||
|
|
||||||
fSoftReset = true;
|
fPortReset = true;
|
||||||
fError = true;
|
fError = true;
|
||||||
}
|
}
|
||||||
if (is & PORT_INT_HBF) {
|
if (is & PORT_INT_HBF) {
|
||||||
TRACE("Host Bus Fatal Error\n");
|
TRACE("Host Bus Fatal Error\n");
|
||||||
fSoftReset = true;
|
fPortReset = true;
|
||||||
fError = true;
|
fError = true;
|
||||||
}
|
}
|
||||||
if (is & PORT_INT_HBD) {
|
if (is & PORT_INT_HBD) {
|
||||||
TRACE("Host Bus Data Error\n");
|
TRACE("Host Bus Data Error\n");
|
||||||
fSoftReset = true;
|
fPortReset = true;
|
||||||
fError = true;
|
fError = true;
|
||||||
}
|
}
|
||||||
if (is & PORT_INT_IF) {
|
if (is & PORT_INT_IF) {
|
||||||
TRACE("Interface Fatal Error\n");
|
TRACE("Interface Fatal Error\n");
|
||||||
fSoftReset = true;
|
fPortReset = true;
|
||||||
fError = true;
|
fError = true;
|
||||||
}
|
}
|
||||||
if (is & PORT_INT_INF) {
|
if (is & PORT_INT_INF) {
|
||||||
@@ -500,7 +418,7 @@ AHCIPort::InterruptErrorHandler(uint32 is)
|
|||||||
}
|
}
|
||||||
if (is & PORT_INT_OF) {
|
if (is & PORT_INT_OF) {
|
||||||
TRACE("Overflow\n");
|
TRACE("Overflow\n");
|
||||||
fSoftReset = true;
|
fPortReset = true;
|
||||||
fError = true;
|
fError = true;
|
||||||
}
|
}
|
||||||
if (is & PORT_INT_IPM) {
|
if (is & PORT_INT_IPM) {
|
||||||
@@ -508,26 +426,19 @@ AHCIPort::InterruptErrorHandler(uint32 is)
|
|||||||
}
|
}
|
||||||
if (is & PORT_INT_PRC) {
|
if (is & PORT_INT_PRC) {
|
||||||
TRACE("PhyReady Change\n");
|
TRACE("PhyReady Change\n");
|
||||||
//fSoftReset = true;
|
//fPortReset = true;
|
||||||
}
|
}
|
||||||
if (is & PORT_INT_PC) {
|
if (is & PORT_INT_PC) {
|
||||||
TRACE("Port Connect Change\n");
|
TRACE("Port Connect Change\n");
|
||||||
// Unsolicited when we had a port connect change without us requesting
|
// Unsolicited when we had a port connect change without us requesting
|
||||||
// Spec v1.3, §6.2.2.3 Recovery of Unsolicited COMINIT
|
// Spec v1.3, §6.2.2.3 Recovery of Unsolicited COMINIT
|
||||||
|
|
||||||
// TODO: This isn't enough
|
|
||||||
//if ((fRegs->sctl & SCTL_PORT_DET_INIT) == 0) {
|
|
||||||
// TRACE("%s: unsolicited port connect change\n", __func__);
|
|
||||||
// fSoftReset = true;
|
|
||||||
// fError = true;
|
|
||||||
//}
|
|
||||||
|
|
||||||
// XXX: This shouldn't be needed here... but we can loop without it
|
// XXX: This shouldn't be needed here... but we can loop without it
|
||||||
_ClearErrorRegister();
|
//_ClearErrorRegister();
|
||||||
}
|
}
|
||||||
if (is & PORT_INT_UF) {
|
if (is & PORT_INT_UF) {
|
||||||
TRACE("Unknown FIS\n");
|
TRACE("Unknown FIS\n");
|
||||||
fSoftReset = true;
|
fPortReset = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fError) {
|
if (fError) {
|
||||||
@@ -1159,7 +1070,7 @@ AHCIPort::ExecuteSataRequest(sata_request* request, bool isWrite)
|
|||||||
if (wait_until_clear(&fRegs->tfd, ATA_STATUS_BUSY | ATA_STATUS_DATA_REQUEST,
|
if (wait_until_clear(&fRegs->tfd, ATA_STATUS_BUSY | ATA_STATUS_DATA_REQUEST,
|
||||||
1000000) < B_OK) {
|
1000000) < B_OK) {
|
||||||
TRACE("ExecuteAtaRequest port %d: device is busy\n", fIndex);
|
TRACE("ExecuteAtaRequest port %d: device is busy\n", fIndex);
|
||||||
SoftReset();
|
PortReset();
|
||||||
FinishTransfer();
|
FinishTransfer();
|
||||||
request->Abort();
|
request->Abort();
|
||||||
return;
|
return;
|
||||||
@@ -1195,9 +1106,9 @@ AHCIPort::ExecuteSataRequest(sata_request* request, bool isWrite)
|
|||||||
TRACE("tfd 0x%08" B_PRIx32 "\n", fRegs->tfd);
|
TRACE("tfd 0x%08" B_PRIx32 "\n", fRegs->tfd);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (fSoftReset || status == B_TIMED_OUT) {
|
if (fPortReset || status == B_TIMED_OUT) {
|
||||||
fSoftReset = false;
|
fPortReset = false;
|
||||||
SoftReset();
|
PortReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t bytesTransfered = fCommandList->prdbc;
|
size_t bytesTransfered = fCommandList->prdbc;
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ private:
|
|||||||
void ExecuteSataRequest(sata_request *request, bool isWrite = false);
|
void ExecuteSataRequest(sata_request *request, bool isWrite = false);
|
||||||
|
|
||||||
void ResetDevice();
|
void ResetDevice();
|
||||||
status_t SoftReset();
|
|
||||||
status_t PortReset();
|
status_t PortReset();
|
||||||
status_t Probe();
|
status_t Probe();
|
||||||
|
|
||||||
@@ -84,7 +83,7 @@ private:
|
|||||||
uint64 fSectorCount;
|
uint64 fSectorCount;
|
||||||
bool fIsATAPI;
|
bool fIsATAPI;
|
||||||
bool fTestUnitReadyActive;
|
bool fTestUnitReadyActive;
|
||||||
bool fSoftReset;
|
bool fPortReset;
|
||||||
bool fError;
|
bool fError;
|
||||||
bool fTrimSupported;
|
bool fTrimSupported;
|
||||||
uint32 fMaxTrimRangeBlocks;
|
uint32 fMaxTrimRangeBlocks;
|
||||||
|
|||||||
Reference in New Issue
Block a user