hrev50195 adds 2 changesets to branch 'master'
old head: f8df3953f4289bc7912a1fce3030d0a359eda426
new head: 037ecca315558e48d3efa4c406a2617f20c650dc
overview:
http://cgit.haiku-os.org/haiku/log/?qt=range&q=037ecca31555+%5Ef8df3953f428
----------------------------------------------------------------------------
fb75d9606cd7: 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.
037ecca31555: ahci: Reduce aggressiveness of port reset
* While no removeable media is present, ahci
ports continuously reset.
* hrev49665 made the port resets slightly more
agressive resulting in strange removeable media
behaviour.
* Lots of red herrings made this one take a while
to figure out.
* Resolves #12415
[ Alexander von Gluck IV <kallisti5@xxxxxxxxxxx> ]
----------------------------------------------------------------------------
2 files changed, 37 insertions(+), 119 deletions(-)
.../kernel/busses/scsi/ahci/ahci_port.cpp | 153 +++++--------------
src/add-ons/kernel/busses/scsi/ahci/ahci_port.h | 3 +-
############################################################################
Commit: fb75d9606cd700b933667c58f974d0835985b404
URL: http://cgit.haiku-os.org/haiku/commit/?id=fb75d9606cd7
Author: Alexander von Gluck IV <kallisti5@xxxxxxxxxxx>
Date: Fri Apr 8 19:44:14 2016 UTC
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.
----------------------------------------------------------------------------
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 8006793..d273df5 100644
--- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp
+++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp
@@ -59,7 +59,7 @@ AHCIPort::AHCIPort(AHCIController* controller, int index)
fSectorCount(0),
fIsATAPI(false),
fTestUnitReadyActive(false),
- fSoftReset(false),
+ fPortReset(false),
fError(false),
fTrimSupported(false)
{
@@ -158,7 +158,7 @@ AHCIPort::Init2()
FlushPostedWrites();
// reset port and probe info
- SoftReset();
+ ResetDevice();
DumpHBAState();
@@ -230,92 +230,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
AHCIPort::PortReset()
{
TRACE("AHCIPort::PortReset port %d\n", fIndex);
@@ -327,13 +241,21 @@ AHCIPort::PortReset()
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();
spin(1100);
// You must wait 1ms at minimum
fRegs->sctl = (fRegs->sctl & ~HBA_PORT_DET_MASK) | SCTL_PORT_DET_NOINIT;
-
- FlushPostedWrites();
+ // Enable also flushes above write
+ Enable();
if (wait_until_set(&fRegs->ssts, SSTS_PORT_DET_PRESENT, 500000) < B_OK)
{
TRACE("%s: port %d: no device detected\n", __func__, fIndex);
@@ -341,8 +263,6 @@ AHCIPort::PortReset()
return B_OK;
}
- Enable();
-
return Probe();
}
@@ -391,8 +311,6 @@ AHCIPort::Probe()
? "ATA" : "unknown");
}
- _ClearErrorRegister();
-
return B_OK;
}
@@ -477,22 +395,22 @@ AHCIPort::InterruptErrorHandler(uint32 is)
if (!fTestUnitReadyActive)
TRACE("Task File Error\n");
- fSoftReset = true;
+ fPortReset = true;
fError = true;
}
if (is & PORT_INT_HBF) {
TRACE("Host Bus Fatal Error\n");
- fSoftReset = true;
+ fPortReset = true;
fError = true;
}
if (is & PORT_INT_HBD) {
TRACE("Host Bus Data Error\n");
- fSoftReset = true;
+ fPortReset = true;
fError = true;
}
if (is & PORT_INT_IF) {
TRACE("Interface Fatal Error\n");
- fSoftReset = true;
+ fPortReset = true;
fError = true;
}
if (is & PORT_INT_INF) {
@@ -500,7 +418,7 @@ AHCIPort::InterruptErrorHandler(uint32 is)
}
if (is & PORT_INT_OF) {
TRACE("Overflow\n");
- fSoftReset = true;
+ fPortReset = true;
fError = true;
}
if (is & PORT_INT_IPM) {
@@ -508,26 +426,19 @@ AHCIPort::InterruptErrorHandler(uint32 is)
}
if (is & PORT_INT_PRC) {
TRACE("PhyReady Change\n");
- //fSoftReset = true;
+ //fPortReset = true;
}
if (is & PORT_INT_PC) {
TRACE("Port Connect Change\n");
// Unsolicited when we had a port connect change without us
requesting
// 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
- _ClearErrorRegister();
+ //_ClearErrorRegister();
}
if (is & PORT_INT_UF) {
TRACE("Unknown FIS\n");
- fSoftReset = true;
+ fPortReset = true;
}
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,
1000000) < B_OK) {
TRACE("ExecuteAtaRequest port %d: device is busy\n", fIndex);
- SoftReset();
+ PortReset();
FinishTransfer();
request->Abort();
return;
@@ -1195,9 +1106,9 @@ AHCIPort::ExecuteSataRequest(sata_request* request, bool
isWrite)
TRACE("tfd 0x%08" B_PRIx32 "\n", fRegs->tfd);
*/
- if (fSoftReset || status == B_TIMED_OUT) {
- fSoftReset = false;
- SoftReset();
+ if (fPortReset || status == B_TIMED_OUT) {
+ fPortReset = false;
+ PortReset();
}
size_t bytesTransfered = fCommandList->prdbc;
diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h
b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h
index 2f74dd1..0b8c802 100644
--- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h
+++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.h
@@ -48,7 +48,6 @@ private:
void ExecuteSataRequest(sata_request *request, bool isWrite
= false);
void ResetDevice();
- status_t SoftReset();
status_t PortReset();
status_t Probe();
@@ -84,7 +83,7 @@ private:
uint64 fSectorCount;
bool fIsATAPI;
bool
fTestUnitReadyActive;
- bool fSoftReset;
+ bool fPortReset;
bool fError;
bool fTrimSupported;
uint32
fMaxTrimRangeBlocks;
############################################################################
Revision: hrev50195
Commit: 037ecca315558e48d3efa4c406a2617f20c650dc
URL: http://cgit.haiku-os.org/haiku/commit/?id=037ecca31555
Author: Alexander von Gluck IV <kallisti5@xxxxxxxxxxx>
Date: Sat Apr 9 03:08:43 2016 UTC
Ticket: https://dev.haiku-os.org/ticket/12415
ahci: Reduce aggressiveness of port reset
* While no removeable media is present, ahci
ports continuously reset.
* hrev49665 made the port resets slightly more
agressive resulting in strange removeable media
behaviour.
* Lots of red herrings made this one take a while
to figure out.
* Resolves #12415
----------------------------------------------------------------------------
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 d273df5..06a3262 100644
--- a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp
+++ b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp
@@ -234,27 +234,32 @@ AHCIPort::PortReset()
{
TRACE("AHCIPort::PortReset port %d\n", fIndex);
- // Spec v1.3.1, §10.4.2 Port Reset
- // Physical comm between HBA and port disabled. More Intrusive
if (!Disable()) {
- ERROR("%s: port %d unable to reset!\n", __func__, fIndex);
+ ERROR("%s: port %d unable to shutdown!\n", __func__, fIndex);
return B_ERROR;
}
_ClearErrorRegister();
// Wait for BSY and DRQ to clear (idle port)
- wait_until_clear(&fRegs->tfd, ATA_STATUS_BUSY | ATA_STATUS_DATA_REQUEST,
- 1000000);
+ if (wait_until_clear(&fRegs->tfd, ATA_STATUS_BUSY |
ATA_STATUS_DATA_REQUEST,
+ 1000000) < B_OK) {
+ // If we can't clear busy, do a full comreset
- // 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();
- spin(1100);
+ // Spec v1.3.1, §10.4.2 Port Reset
+ // Physical comm between HBA and port disabled. More Intrusive
+ ERROR("%s: port %d undergoing COMRESET\n", __func__, fIndex);
+
+ // Notice we're throwing out all other control flags.
+ fRegs->sctl = (SSTS_PORT_IPM_ACTIVE | SSTS_PORT_IPM_PARTIAL
+ | SCTL_PORT_DET_INIT);
+ FlushPostedWrites();
+ spin(1100);
// You must wait 1ms at minimum
- fRegs->sctl = (fRegs->sctl & ~HBA_PORT_DET_MASK) | SCTL_PORT_DET_NOINIT;
- // Enable also flushes above write
+ fRegs->sctl = (fRegs->sctl & ~HBA_PORT_DET_MASK) |
SCTL_PORT_DET_NOINIT;
+ FlushPostedWrites();
+ }
+
Enable();
if (wait_until_set(&fRegs->ssts, SSTS_PORT_DET_PRESENT, 500000) < B_OK)
{
@@ -1053,7 +1058,10 @@ AHCIPort::ExecuteSataRequest(sata_request* request, bool
isWrite)
fCommandList->cfl = 5; // 20 bytes, length in DWORDS
memcpy((char*)fCommandTable->cfis, request->FIS(), 20);
+ // We some hide messages when the test unit ready active is clear
+ // as empty removeable media resets constantly.
fTestUnitReadyActive = request->IsTestUnitReady();
+
if (request->IsATAPI()) {
// ATAPI PACKET is a 12 or 16 byte SCSI command
memset((char*)fCommandTable->acmd, 0, 32);