Ticket #12357: ahci-rework-v2.diff

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

version 2. Rebased. Doesn't solve the ATAPI issues yet.

  • 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..456bdaf 100644
    a b enum {  
    9797#define IPM_TRANSITIONS_TO_PARTIAL_DISABLED 0x1
    9898#define IPM_TRANSITIONS_TO_SLUMBER_DISABLED 0x2
    9999
     100// Device signatures
     101#define SATA_SIG_ATA            0x00000101 // SATA drive
     102#define SATA_SIG_ATAPI          0xEB140101 // ATAPI drive
     103#define SATA_SIG_SEMB           0xC33C0101 // Enclosure management bridge
     104#define SATA_SIG_PM             0x96690101 // Port multiplier
    100105
    101106typedef struct {
    102107    uint32      clb;            // Command List Base Address
    enum {  
    130135    PORT_CMD_ATAPI  = (1 << 24),    // Device is ATAPI
    131136    PORT_CMD_CR     = (1 << 15),    // Command List Running (DMA active)
    132137    PORT_CMD_FR     = (1 << 14),    // FIS Receive Running
    133     PORT_CMD_FER    = (1 << 4),     // FIS Receive Enable
     138    PORT_CMD_FRE    = (1 << 4),     // FIS Receive Enable
    134139    PORT_CMD_CLO    = (1 << 3),     // Command List Override
    135140    PORT_CMD_POD    = (1 << 2),     // Power On Device
    136141    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 94a0034..e18e126 100644
    a b AHCIPort::Init1()  
    120120    fRegs->is = fRegs->is;
    121121
    122122    // clear error bits
    123     fRegs->serr = fRegs->serr;
     123    _ClearErrorRegister();
    124124
    125125    // power up device
    126126    fRegs->cmd |= PORT_CMD_POD;
    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::Init1()  
    144144status_t
    145145AHCIPort::Init2()
    146146{
    147     TRACE("AHCIPort::Init2 port %d\n", fIndex);
     147    TRACE("%s: port %d\n", __func__, fIndex);
    148148
    149     // start DMA engine
    150     fRegs->cmd |= PORT_CMD_ST;
     149    // enable port
     150    Enable();
    151151
    152152    // enable interrupts
    153153    fRegs->ie = PORT_INT_MASK;
    154154
    155155    FlushPostedWrites();
    156156
     157    // reset port and probe info
    157158    ResetPort(true);
    158159
    159160    TRACE("ie   0x%08" B_PRIx32 "\n", fRegs->ie);
    AHCIPort::Init2()  
    172173
    173174    fDevicePresent = (fRegs->ssts & 0xf) == 0x3;
    174175
     176    TRACE("%s: port %d, device %s\n", __func__, fIndex,
     177        fDevicePresent ? "present" : "absent");
     178
    175179    return B_OK;
    176180}
    177181
    AHCIPort::Init2()  
    179183void
    180184AHCIPort::Uninit()
    181185{
    182     TRACE("AHCIPort::Uninit port %d\n", fIndex);
    183 
    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     }
     186    TRACE("%s: port %d\n", __func__, fIndex);
    191187
    192     // stop DMA engine
    193     fRegs->cmd &= ~PORT_CMD_ST;
     188    // Clear FRE and wait for completion
     189    fRegs->cmd &= ~PORT_CMD_FRE;
     190    if (wait_until_clear(&fRegs->cmd, PORT_CMD_FR, 500000) < B_OK)
     191        TRACE("%s: port %d error FIS rx still running\n", __func__, fIndex);
    194192
    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     }
     193    // shutdown the port
     194    Disable();
    200195
    201196    // disable interrupts
    202197    fRegs->ie = 0;
    void  
    218213AHCIPort::ResetDevice()
    219214{
    220215    // perform a hard reset
    221     if (!_HardReset())
     216    if (!_HardReset()) {
     217        ERROR("%s: port %d unable to hard reset device\n", __func__, fIndex);
    222218        return;
     219    }
    223220
    224221    if (wait_until_set(&fRegs->ssts, 0x1, 100000) < B_OK)
    225         TRACE("AHCIPort::ResetDevice port %d no device detected\n", fIndex);
     222        TRACE("%s: port %d no device detected\n", __func__, fIndex);
    226223
    227224    _ClearErrorRegister();
    228225
    229226    if (fRegs->ssts & 1) {
    230227        if (wait_until_set(&fRegs->ssts, 0x3, 500000) < B_OK) {
    231             TRACE("AHCIPort::ResetDevice port %d device present but no phy "
    232                 "communication\n", fIndex);
     228            TRACE("%s: port %d device present but no phy "
     229                "communication\n", __func__, fIndex);
    233230        }
    234231    }
    235232
    status_t  
    241238AHCIPort::ResetPort(bool forceDeviceReset)
    242239{
    243240    if (!fTestUnitReadyActive)
    244         TRACE("AHCIPort::ResetPort port %d\n", fIndex);
     241        TRACE("%s: port %d\n", __func__, fIndex);
    245242
    246     // stop DMA engine
    247     fRegs->cmd &= ~PORT_CMD_ST;
    248     FlushPostedWrites();
    249 
    250     if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) {
    251         TRACE("AHCIPort::ResetPort port %d error DMA engine doesn't stop\n",
    252             fIndex);
    253     }
     243    // stop port, flush transactions
     244    Disable();
    254245
    255246    bool deviceBusy = fRegs->tfd & (ATA_BSY | ATA_DRQ);
    256247
    257248    if (!fTestUnitReadyActive) {
    258         TRACE("AHCIPort::ResetPort port %d, deviceBusy %d, "
    259             "forceDeviceReset %d\n", fIndex, deviceBusy, forceDeviceReset);
     249        TRACE("%s: port %d, deviceBusy %d, forceDeviceReset %d\n", __func__,
     250            fIndex, deviceBusy, forceDeviceReset);
    260251    }
    261252
    262253    if (deviceBusy || forceDeviceReset)
    263254        ResetDevice();
    264255
    265     // start DMA engine
    266     fRegs->cmd |= PORT_CMD_ST;
    267     FlushPostedWrites();
     256    // start port
     257    Enable();
    268258
    269259    return PostReset();
    270260}
    status_t  
    274264AHCIPort::PostReset()
    275265{
    276266    if (!fTestUnitReadyActive)
    277         TRACE("AHCIPort::PostReset port %d\n", fIndex);
     267        TRACE("%s: port %d\n", __func__, fIndex);
    278268
    279269    if ((fRegs->ssts & 0xf) != 0x3 || (fRegs->tfd & 0xff) == 0x7f) {
    280         TRACE("AHCIPort::PostReset port %d: no device\n", fIndex);
     270        TRACE("%s: port %d: no device\n", __func__, fIndex);
    281271        return B_OK;
    282272    }
    283273
    AHCIPort::PostReset()  
    285275        snooze(200000);
    286276
    287277    if ((fRegs->tfd & 0xff) == 0xff) {
    288         TRACE("AHCIPort::PostReset port %d: invalid task file status 0xff\n",
     278        TRACE("%s: port %d: invalid task file status 0xff\n", __func__,
    289279            fIndex);
    290280        return B_ERROR;
    291281    }
    292282
    293283    wait_until_clear(&fRegs->tfd, ATA_BSY, 31000000);
    294284
    295     fIsATAPI = fRegs->sig == 0xeb140101;
    296 
     285    fIsATAPI = fRegs->sig == SATA_SIG_ATAPI;
    297286    if (fIsATAPI)
    298287        fRegs->cmd |= PORT_CMD_ATAPI;
    299288    else
    AHCIPort::PostReset()  
    302291
    303292    if (!fTestUnitReadyActive) {
    304293        TRACE("device signature 0x%08" B_PRIx32 " (%s)\n", fRegs->sig,
    305             fRegs->sig == 0xeb140101 ? "ATAPI" : fRegs->sig == 0x00000101
     294            fRegs->sig == SATA_SIG_ATAPI ? "ATAPI" : fRegs->sig == SATA_SIG_ATA
    306295                ? "ATA" : "unknown");
    307296    }
    308297
    AHCIPort::InterruptErrorHandler(uint32 is)  
    374363    }
    375364
    376365    // read and clear SError
    377     uint32 serr = fRegs->serr;
    378     fRegs->serr = serr;
     366    _ClearErrorRegister();
    379367
    380368    if (is & PORT_INT_TFE) {
    381369        if (!fTestUnitReadyActive)
    AHCIPort::InterruptErrorHandler(uint32 is)  
    417405    if (is & PORT_INT_PC) {
    418406        TRACE("Port Connect Change\n");
    419407        // Spec v1.3, §6.2.2.3 Recovery of Unsolicited COMINIT
    420 
    421         // perform a hard reset
    422         if (!_HardReset())
    423             return;
    424 
    425         // clear error bits to clear PxSERR.DIAG.X
     408        // Spec v1.3.1, §7.4 Interaction of command list and port change status
     409        ResetPort(true);
    426410        _ClearErrorRegister();
    427411    }
    428412    if (is & PORT_INT_UF) {
    AHCIPort::FillPrdTable(volatile prd* prdTable, int* prdCount, int prdMax,  
    452436    status_t status = get_memory_map_etc(B_CURRENT_TEAM, data, dataSize,
    453437        entries, &entriesUsed);
    454438    if (status != B_OK) {
    455         TRACE("AHCIPort::FillPrdTable get_memory_map() failed: %s\n",
    456             strerror(status));
     439        TRACE("%s: get_memory_map() failed: %s\n", __func__, strerror(status));
    457440        return B_ERROR;
    458441    }
    459442
    AHCIPort::FillPrdTable(volatile prd* prdTable, int* prdCount, int prdMax,  
    474457        FLOW("FillPrdTable: sg-entry addr %#" B_PRIxPHYSADDR ", size %lu\n",
    475458            address, size);
    476459        if (address & 1) {
    477             TRACE("AHCIPort::FillPrdTable: data alignment error\n");
     460            TRACE("%s: data alignment error\n", __func__);
    478461            return B_ERROR;
    479462        }
    480463        dataSize -= size;
    AHCIPort::FillPrdTable(volatile prd* prdTable, int* prdCount, int prdMax,  
    500483        sgCount--;
    501484    }
    502485    if (*prdCount == 0) {
    503         TRACE("AHCIPort::FillPrdTable: count is 0\n");
     486        TRACE("%s: count is 0\n", __func__);
    504487        return B_ERROR;
    505488    }
    506489    if (dataSize > 0) {
    507         TRACE("AHCIPort::FillPrdTable: sg table %ld bytes too small\n",
    508             dataSize);
     490        TRACE("%s: sg table %ld bytes too small\n", __func__, dataSize);
    509491        return B_ERROR;
    510492    }
    511493    return B_OK;
    AHCIPort::ScsiGetRestrictions(bool* isATAPI, bool* noAutoSense,  
    13221304
    13231305
    13241306bool
     1307AHCIPort::Enable()
     1308{
     1309    TRACE("%s: port %d\n", __func__, fIndex);
     1310    if ((fRegs->cmd & PORT_CMD_ST) != 0) {
     1311        TRACE("%s: Starting port already running!\n", __func__);
     1312        return false;
     1313    }
     1314    // Start port
     1315    fRegs->cmd |= PORT_CMD_ST;
     1316    FlushPostedWrites();
     1317    return true;
     1318}
     1319
     1320
     1321bool
     1322AHCIPort::Disable()
     1323{
     1324    TRACE("%s: port %d\n", __func__, fIndex);
     1325
     1326    if ((fRegs->cmd & PORT_CMD_ST) == 0) {
     1327        TRACE("%s: port %d attempting to disable stopped port.\n",
     1328            __func__, fIndex);
     1329    }
     1330
     1331    // Disable port
     1332    fRegs->cmd &= ~PORT_CMD_ST;
     1333    FlushPostedWrites();
     1334
     1335    // Clear DMA engine and wait for completion
     1336    if (wait_until_clear(&fRegs->cmd, PORT_CMD_CR, 500000) < B_OK) {
     1337        TRACE("%s: port %d error DMA engine still running\n", __func__,
     1338            fIndex);
     1339        return false;
     1340    }
     1341
     1342    return true;
     1343}
     1344
     1345
     1346bool
    13251347AHCIPort::_HardReset()
    13261348{
    13271349    if ((fRegs->cmd & PORT_CMD_ST) != 0) {
    13281350        // We shouldn't perform a reset, but at least document it
    1329         TRACE("AHCIPort::_HardReset() PORT_CMD_ST set, behaviour undefined\n");
     1351        TRACE("%s: port %d warning: ST set, bypassing hard reset\n", __func__,
     1352            fIndex);
    13301353        return false;
    13311354    }
    13321355
  • 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 0bc4e67..2127478 100644
    a b private:  
    5050    void        ResetDevice();
    5151    status_t    ResetPort(bool forceDeviceReset = false);
    5252    status_t    PostReset();
     53    bool        Enable();
     54    bool        Disable();
     55
    5356    void        FlushPostedWrites();
    5457    void        DumpD2HFis();
    5558