[haiku-commits] haiku: hrev50195 - src/add-ons/kernel/busses/scsi/ahci

  • From: kallisti5@xxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sat, 9 Apr 2016 05:14:09 +0200 (CEST)

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);


Other related posts:

  • » [haiku-commits] haiku: hrev50195 - src/add-ons/kernel/busses/scsi/ahci - kallisti5