Ticket #12357: ahci-rework-v1.diff

File ahci-rework-v1.diff, 5.2 KB (added by kallisti5, 5 years ago)

My initial rework of the AHCI Init / Reset code. RFC. Needs testing

  • 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 b9c8c03..a465fe2 100644
    a b enum {  
    130130    PORT_CMD_ATAPI  = (1 << 24),    // Device is ATAPI
    131131    PORT_CMD_CR     = (1 << 15),    // Command List Running (DMA active)
    132132    PORT_CMD_FR     = (1 << 14),    // FIS Receive Running
    133     PORT_CMD_FER    = (1 << 4),     // FIS Receive Enable
     133    PORT_CMD_FRE    = (1 << 4),     // FIS Receive Enable
    134134    PORT_CMD_CLO    = (1 << 3),     // Command List Override
    135135    PORT_CMD_POD    = (1 << 2),     // Power On Device
    136136    PORT_CMD_SUD    = (1 << 1),     // Spin-up Device
  • 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 82efc5b..e6138a1 100644
    a b AHCIPort::Init1()  
    132132    fRegs->cmd = (fRegs->cmd & ~PORT_CMD_ICC_MASK) | PORT_CMD_ICC_ACTIVE;
    133133
    134134    // enable FIS receive
    135     fRegs->cmd |= PORT_CMD_FER;
     135    fRegs->cmd |= PORT_CMD_FRE;
    136136
    137137    FlushPostedWrites();
    138138
    AHCIPort::Init2()  
    146146{
    147147    TRACE("AHCIPort::Init2 port %d\n", fIndex);
    148148
    149     // start DMA engine
    150     fRegs->cmd |= PORT_CMD_ST;
     149    // enable port
     150    Enable(true);
    151151
    152152    // enable interrupts
    153153    fRegs->ie = PORT_INT_MASK;
    154154
    155155    FlushPostedWrites();
    156156
    157     ResetPort(true);
    158 
    159157    TRACE("ie   0x%08" B_PRIx32 "\n", fRegs->ie);
    160158    TRACE("is   0x%08" B_PRIx32 "\n", fRegs->is);
    161159    TRACE("cmd  0x%08" B_PRIx32 "\n", fRegs->cmd);
    AHCIPort::Uninit()  
    181179{
    182180    TRACE("AHCIPort::Uninit port %d\n", fIndex);
    183181
    184     // disable FIS receive
    185     fRegs->cmd &= ~PORT_CMD_FER;
    186 
    187     // wait for receive completion, up to 500ms
    188     if (wait_until_clear(&fRegs->cmd, PORT_CMD_FR, 500000) < B_OK) {
    189         TRACE("AHCIPort::Uninit port %d error FIS rx still running\n", fIndex);
    190     }
    191 
    192     // stop DMA engine
    193     fRegs->cmd &= ~PORT_CMD_ST;
    194 
    195     // wait for DMA completion
    196     if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) {
    197         TRACE("AHCIPort::Uninit port %d error DMA engine still running\n",
    198             fIndex);
    199     }
     182    // shutdown the port
     183    Enable(false);
    200184
    201185    // disable interrupts
    202186    fRegs->ie = 0;
    status_t  
    240224AHCIPort::ResetPort(bool forceDeviceReset)
    241225{
    242226    if (!fTestUnitReadyActive)
    243         TRACE("AHCIPort::ResetPort port %d\n", fIndex);
     227        TRACE("%s: port %d\n", __func__, fIndex);
    244228
    245     // stop DMA engine
    246     fRegs->cmd &= ~PORT_CMD_ST;
    247     FlushPostedWrites();
    248 
    249     if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) {
    250         TRACE("AHCIPort::ResetPort port %d error DMA engine doesn't stop\n",
    251             fIndex);
    252     }
     229    // stop port, flush transactions
     230    Enable(false);
    253231
    254232    bool deviceBusy = fRegs->tfd & (ATA_BSY | ATA_DRQ);
    255233
    AHCIPort::ResetPort(bool forceDeviceReset)  
    261239    if (deviceBusy || forceDeviceReset)
    262240        ResetDevice();
    263241
    264     // start DMA engine
    265     fRegs->cmd |= PORT_CMD_ST;
    266     FlushPostedWrites();
     242    // start port
     243    Enable(true);
    267244
    268245    return PostReset();
    269246}
    AHCIPort::InterruptErrorHandler(uint32 is)  
    417394        TRACE("Port Connect Change\n");
    418395        // Spec v1.3, §6.2.2.3 Recovery of Unsolicited COMINIT
    419396
     397        // TODO: Do we need to disable the port here? Or is ST clear?
     398
    420399        // perform a hard reset
    421400        _HardReset();
    422401
    AHCIPort::ScsiGetRestrictions(bool* isATAPI, bool* noAutoSense,  
    13201299
    13211300
    13221301void
     1302AHCIPort::Enable(bool enable)
     1303{
     1304    TRACE("%s: port %d\n", __func__, fIndex);
     1305
     1306    if ((fRegs->cmd & PORT_CMD_ST) != 0) {
     1307        if (enable) {
     1308            TRACE("%s: Starting port already running!\n", __func__);
     1309            return;
     1310        }
     1311
     1312        // wait for DMA completion if port running
     1313        if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) {
     1314            TRACE("AHCIPort::Uninit port %d error DMA engine still running\n",
     1315                fIndex);
     1316        }
     1317    }
     1318
     1319    if (enable) {
     1320        // Start port
     1321        fRegs->cmd |= PORT_CMD_FRE;
     1322        fRegs->cmd |= PORT_CMD_ST;
     1323        FlushPostedWrites();
     1324        return;
     1325    }
     1326
     1327    // Clear FRE and wait for completion
     1328    fRegs->cmd &= ~PORT_CMD_FRE;
     1329    FlushPostedWrites();
     1330    if (wait_until_clear(&fRegs->cmd, PORT_CMD_FR, 500000) < B_OK) {
     1331        TRACE("%s: port %d error FIS receive still running\n", __func__,
     1332            fIndex);
     1333    }
     1334
     1335    // Clear DMA engine and wait for completion
     1336    fRegs->cmd &= ~PORT_CMD_ST;
     1337    FlushPostedWrites();
     1338    if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) {
     1339        TRACE("%s: port %d error DMA engine still running\n", __func__,
     1340            fIndex);
     1341    }
     1342}
     1343
     1344
     1345void
    13231346AHCIPort::_HardReset()
    13241347{
     1348    TRACE("%s: Called on port %d\n", __func__, fIndex);
    13251349    if ((fRegs->cmd & PORT_CMD_ST) != 0) {
    13261350        // We shouldn't perform a reset, but at least document it
    1327         TRACE("AHCIPort::_HardReset() PORT_CMD_ST set, behaviour undefined\n");
     1351        TRACE("%s: PORT_CMD_ST set, bypassing hard reset\n", __func__);
     1352        return;
    13281353    }
    13291354
    13301355    fRegs->sctl = (fRegs->sctl & ~SATA_CONTROL_DET_MASK)
  • src/add-ons/kernel/busses/scsi/ahci/ahci_port.h

    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 34cee69..1d0ae20 100644
    a b private:  
    5050    void        ResetDevice();
    5151    status_t    ResetPort(bool forceDeviceReset = false);
    5252    status_t    PostReset();
     53    void        Enable(bool enabled);
     54
    5355    void        FlushPostedWrites();
    5456    void        DumpD2HFis();
    5557