VirtualBox

Changeset 33209 in vbox


Ignore:
Timestamp:
Oct 18, 2010 3:39:29 PM (14 years ago)
Author:
vboxsync
Message:

AHCI: Some cleanup

Until now there were two different methods to forward new requests from GC to R3.
For sync I/O a FIFO and a PDM queue to kick the I/O thread was used.
For async I/O every task was passed through the PDM queue and processed by the consumer.
This is messy and requires too much hyper heap.

The new method is the same for sync and async I/O. Because a port can only have 32 active requests
at a time it is enough to use a bitmap which is processed in R3 to get the slots of the new tasks.
Requires a PDM queue with much less items then before and saves us almost 20KB of hyper heap on a 64bit host.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DevAHCI.cpp

    r33175 r33209  
    320320    /** The core part owned by the queue manager. */
    321321    PDMQUEUEITEMCORE    Core;
    322     /** On which port the async io thread should be put into action. */
     322    /** The port to process. */
    323323    uint8_t             iPort;
    324     /** Which task to process. */
    325     uint8_t             iTask;
    326     /** Flag whether the task is queued. */
    327     uint8_t             fQueued;
    328324} DEVPORTNOTIFIERQUEUEITEM, *PDEVPORTNOTIFIERQUEUEITEM;
    329325
     
    354350    /** Pointer to the parent AHCI structure - RC ptr. */
    355351    RCPTRTYPE(struct AHCI *)        pAhciRC;
     352
    356353    /** Command List Base Address. */
    357354    uint32_t                        regCLB;
     
    379376    uint32_t                        regSERR;
    380377    /** Serial ATA Active. */
    381     uint32_t                        regSACT;
     378    volatile uint32_t               regSACT;
    382379    /** Command Issue. */
    383380    uint32_t                        regCI;
     
    391388    /** FIS Base Address */
    392389    volatile RTGCPHYS               GCPhysAddrFb;
    393 
    394     /** If we use the new async interface. */
    395     bool                            fAsyncInterface;
    396 
    397 #if HC_ARCH_BITS == 64
    398     uint32_t                        Alignment2;
    399 #endif
    400 
    401     /** Async IO Thread. */
    402     PPDMTHREAD                      pAsyncIOThread;
    403     /** Request semaphore. */
    404     RTSEMEVENT                      AsyncIORequestSem;
    405 
    406     /** Task queue. */
    407     volatile uint8_t                ahciIOTasks[2*AHCI_NR_COMMAND_SLOTS];
    408     /** Actual write position. */
    409     uint8_t                         uActWritePos;
    410     /** Actual read position. */
    411     uint8_t                         uActReadPos;
    412     /** Actual number of active tasks. */
    413     volatile uint32_t               uActTasksActive;
     390    /** Current number of active tasks. */
     391    volatile uint32_t               cTasksActive;
    414392
    415393    /** Device is powered on. */
     
    423401    /** Passthrough SCSI commands. */
    424402    bool                            fATAPIPassthrough;
    425 
    426     /** Device specific settings. */
     403    /** Flag whether this port is in a reset state. */
     404    volatile bool                   fPortReset;
     405    /** If we use the new async interface. */
     406    bool                            fAsyncInterface;
     407    /** Flag if we are in a device reset. */
     408    bool                            fResetDevice;
     409    /** Flag whether the I/O thread idles. */
     410    volatile bool                   fAsyncIOThreadIdle;
     411    /** Flag whether the port is in redo task mode. */
     412    volatile bool                   fRedo;
     413
     414#if HC_ARCH_BITS == 64
     415    bool                            fAlignment2;
     416#endif
     417
     418    /** Number of total sectors. */
     419    uint64_t                        cTotalSectors;
     420    /** Currently configured number of sectors in a multi-sector transfer. */
     421    uint32_t                        cMultSectors;
     422    /** Currently active transfer mode (MDMA/UDMA) and speed. */
     423    uint8_t                         uATATransferMode;
     424    /** ATAPI sense data. */
     425    uint8_t                         abATAPISense[ATAPI_SENSE_SIZE];
     426    /** HACK: Countdown till we report a newly unmounted drive as mounted. */
     427    uint8_t                         cNotifiedMediaChange;
     428    /** The same for GET_EVENT_STATUS for mechanism */
     429    volatile uint32_t               MediaEventStatus;
     430    /** Media type if known. */
     431    volatile uint32_t               MediaTrackType;
     432    /** The LUN. */
     433    RTUINT                          iLUN;
     434
     435    /** Bitmap for finished tasks (R3 -> Guest). */
     436    volatile uint32_t               u32TasksFinished;
     437    /** Bitmap for finished queued tasks (R3 -> Guest). */
     438    volatile uint32_t               u32QueuedTasksFinished;
     439    /** Bitmap for new queued tasks (Guest -> R3). */
     440    volatile uint32_t               u32TasksNew;
     441
     442    /** Device specific settings (R3 only stuff). */
    427443    /** Pointer to the attached driver's base interface. */
    428444    R3PTRTYPE(PPDMIBASE)            pDrvBase;
     
    449465
    450466#if HC_ARCH_BITS == 64
    451     uint32_t                        Alignment4;
     467    uint32_t                        u32Alignment3;
    452468#endif
    453469
    454     /** Number of total sectors. */
    455     uint64_t                        cTotalSectors;
    456     /** Currently configured number of sectors in a multi-sector transfer. */
    457     uint32_t                        cMultSectors;
    458     /** Currently active transfer mode (MDMA/UDMA) and speed. */
    459     uint8_t                         uATATransferMode;
    460     /** ATAPI sense data. */
    461     uint8_t                         abATAPISense[ATAPI_SENSE_SIZE];
    462     /** HACK: Countdown till we report a newly unmounted drive as mounted. */
    463     uint8_t                         cNotifiedMediaChange;
    464     /** The same for GET_EVENT_STATUS for mechanism */
    465     volatile uint32_t               MediaEventStatus;
    466     /** Media type if known. */
    467     volatile uint32_t               MediaTrackType;
    468 
    469     /** The LUN. */
    470     RTUINT                          iLUN;
    471     /** Flag if we are in a device reset. */
    472     bool                            fResetDevice;
    473 
    474     /** Bitmask for finished tasks. */
    475     volatile uint32_t               u32TasksFinished;
    476     /** Bitmask for finished queued tasks. */
    477     volatile uint32_t               u32QueuedTasksFinished;
    478 
     470    /** Async IO Thread. */
     471    R3PTRTYPE(PPDMTHREAD)           pAsyncIOThread;
     472    /** Request semaphore. */
     473    RTSEMEVENT                      AsyncIORequestSem;
    479474    /**
    480475     * Array of cached tasks. The tag number is the index value.
     
    484479    /** First task throwing an error. */
    485480    R3PTRTYPE(volatile PAHCIPORTTASKSTATE) pTaskErr;
    486 
    487 #if HC_ARCH_BITS == 32
    488     uint32_t                        u32Alignment7;
    489 #endif
    490481
    491482    /** Release statistics: number of DMA commands. */
     
    507498    STAMPROFILE                     StatProfileDestroyScatterGatherList;
    508499#endif /* VBOX_WITH_STATISTICS */
    509     /** Flag whether a notification was already send to R3. */
    510     volatile bool                   fNotificationSend;
    511     /** Flag whether this port is in a reset state. */
    512     volatile bool                   fPortReset;
    513     /** Flag whether the I/O thread idles. */
    514     volatile bool                   fAsyncIOThreadIdle;
    515500
    516501    /** The serial numnber to use for IDENTIFY DEVICE commands. */
     
    529514    uint32_t                        cErrors;
    530515
    531     /** Tasks to process */
    532     uint32_t                        cTasksToProcess;
    533     /** Flag whether we need to redo a task. */
    534     bool                            fRedo;
    535 
     516#if HC_ARCH_BITS == 64
     517    uint32_t                        u32Alignment4;
     518#endif
    536519} AHCIPort;
    537520/** Pointer to the state of an AHCI port. */
     
    640623
    641624    /** Bitmask of ports which asserted an interrupt. */
    642     uint32_t                        u32PortsInterrupted;
     625    volatile uint32_t               u32PortsInterrupted;
    643626    /** Device is in a reset state. */
    644627    bool                            fReset;
     
    665648    /** Flag whether we have written the first 4bytes in an 8byte MMIO write successfully. */
    666649    volatile bool                   f8ByteMMIO4BytesWrittenSuccessfully;
    667     /** At which number of I/O requests per second we consider having high I/O load. */
    668     uint32_t                        cHighIOThreshold;
    669     /** How many milliseconds to sleep. */
    670     uint32_t                        cMillisToSleep;
    671650
    672651} AHCI;
     
    863842#define AHCI_RECFIS_UFIS_OFFSET   0x60 /* Unknown FIS type */
    864843
    865 #define AHCI_TASK_IS_QUEUED(x) ((x) & 0x1)
    866 #define AHCI_TASK_GET_TAG(x)   ((x) >> 1)
    867 #define AHCI_TASK_SET(tag, queued) (((tag) << 1) | (queued))
    868 
    869844/**
    870845 * AHCI register operator.
     
    10351010    pAhciPort->regCI &= ~uCIValue;
    10361011
    1037 
    1038     if ((pAhciPort->regCMD & AHCI_PORT_CMD_ST) && (u32Value > 0))
    1039     {
    1040         PDEVPORTNOTIFIERQUEUEITEM pItem;
    1041 
    1042         /* Mark the tasks set in the value as used. */
    1043         for (uint8_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
    1044         {
    1045             /* Queue task if bit is set in written value and not already in progress. */
    1046             if (((u32Value >> i) & 0x01) && !(pAhciPort->regCI & (1 << i)))
    1047             {
    1048                 if (!pAhciPort->fAsyncInterface)
    1049                 {
    1050                     /* Put the tag number of the task into the FIFO. */
    1051                     uint8_t uTag = AHCI_TASK_SET(i, ((pAhciPort->regSACT & (1 << i)) ? 1 : 0));
    1052                     ASMAtomicWriteU8(&pAhciPort->ahciIOTasks[pAhciPort->uActWritePos], uTag);
    1053                     ahciLog(("%s: Before uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
    1054                     pAhciPort->uActWritePos++;
    1055                     pAhciPort->uActWritePos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
    1056                     ahciLog(("%s: After uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
    1057 
    1058                     ASMAtomicIncU32(&pAhciPort->uActTasksActive);
    1059 
    1060                     bool fNotificationSend = ASMAtomicXchgBool(&pAhciPort->fNotificationSend, true);
    1061                     if (!fNotificationSend)
    1062                     {
    1063                         /* Send new notification. */
    1064                         pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
    1065                         AssertMsg(pItem, ("Allocating item for queue failed\n"));
    1066 
    1067                         pItem->iPort = pAhciPort->iLUN;
    1068                         PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
    1069                     }
    1070                 }
    1071                 else
    1072                 {
    1073                     pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
    1074                     AssertMsg(pItem, ("Allocating item for queue failed\n"));
    1075 
    1076                     pItem->iPort = pAhciPort->iLUN;
    1077                     pItem->iTask = i;
    1078                     pItem->fQueued = !!(pAhciPort->regSACT & (1 << i)); /* Mark if the task is queued. */
    1079                     PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
    1080                 }
    1081             }
     1012    if (   (pAhciPort->regCMD & AHCI_PORT_CMD_ST)
     1013        && u32Value > 0)
     1014    {
     1015        uint32_t u32Tasks;
     1016
     1017        /*
     1018         * Clear all tasks which are already marked as busy. The guest
     1019         * shouldn't write already busy tasks actually.
     1020         */
     1021        u32Value &= ~pAhciPort->regCI;
     1022
     1023        ASMAtomicOrU32(&pAhciPort->u32TasksNew, u32Value);
     1024        u32Tasks = ASMAtomicReadU32(&pAhciPort->u32TasksNew);
     1025
     1026        /* Send a notification to R3 if u32TasksNew was before our write. */
     1027        if (!(u32Tasks ^ u32Value))
     1028        {
     1029            PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(ahci->CTX_SUFF(pNotifierQueue));
     1030            AssertMsg(VALID_PTR(pItem), ("Allocating item for queue failed\n"));
     1031
     1032            pItem->iPort = pAhciPort->iLUN;
     1033            PDMQueueInsert(ahci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
    10821034        }
    10831035    }
     
    11721124        if (pAhciPort->pDrvBase)
    11731125        {
    1174             /* Reset queue. */
    1175             pAhciPort->uActWritePos = 0;
    1176             pAhciPort->uActReadPos = 0;
    11771126            ASMAtomicXchgBool(&pAhciPort->fPortReset, false);
    11781127
     
    16121561        ahci->regHbaIs &= ~(u32Value);
    16131562
    1614         fClear = (!ahci->u32PortsInterrupted) && (!ahci->regHbaIs);
     1563        fClear = !ahci->u32PortsInterrupted && !ahci->regHbaIs;
    16151564        if (fClear)
    16161565        {
     
    19061855    pAhciPort->fPoweredOn        = true;
    19071856    pAhciPort->fSpunUp           = true;
    1908     pAhciPort->fNotificationSend = false;
    19091857    pAhciPort->cMultSectors = ATA_MAX_MULT_SECTORS;
    19101858    pAhciPort->uATATransferMode = ATA_MODE_UDMA | 6;
    19111859
     1860    pAhciPort->u32TasksNew = 0;
    19121861    pAhciPort->u32TasksFinished = 0;
    19131862    pAhciPort->u32QueuedTasksFinished = 0;
    19141863
    1915     pAhciPort->uActWritePos = 0;
    1916     pAhciPort->uActReadPos = 0;
    1917     pAhciPort->uActTasksActive = 0;
     1864    pAhciPort->cTasksActive = 0;
    19181865
    19191866    ASMAtomicWriteU32(&pAhciPort->MediaEventStatus, ATA_EVENT_STATUS_UNCHANGED);
     
    45324479     * and it is possible to finish the reset now.
    45334480     */
    4534     Assert(ASMAtomicReadU32(&pAhciPort->uActTasksActive) == 0);
     4481    Assert(ASMAtomicReadU32(&pAhciPort->cTasksActive) == 0);
    45354482    ahciFinishStorageDeviceReset(pAhciPort, pAhciPortTaskState);
    45364483}
     
    56915638            ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciPortTaskState, NULL);
    56925639        }
     5640        else
     5641            ASMAtomicOrU32(&pAhciPort->u32TasksNew, (1 << pAhciPortTaskState->uTag));
    56935642    }
    56945643    else
     
    57115660    /* Add the task to the cache. */
    57125661    ASMAtomicWritePtr(&pAhciPort->aCachedTasks[pAhciPortTaskState->uTag], pAhciPortTaskState);
    5713     ASMAtomicDecU32(&pAhciPort->uActTasksActive);
     5662    ASMAtomicDecU32(&pAhciPort->cTasksActive);
    57145663
    57155664    if (!fRedo)
     
    57525701    int rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, rcReq);
    57535702
    5754     if (pAhciPort->uActTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
     5703    if (pAhciPort->cTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
    57555704        PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
    57565705    return rc;
     
    61546103    else
    61556104    {
    6156         AHCITXDIR          enmTxDir;
    6157         PAHCIPORTTASKSTATE pAhciPortTaskState;
    6158 
    6159         ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, pNotifierItem->iTask));
    6160 
    6161         /*
    6162          * Check if there is already an allocated task struct in the cache.
    6163          * Allocate a new task otherwise.
    6164          */
    6165         if (!pAhciPort->aCachedTasks[pNotifierItem->iTask])
    6166         {
    6167             pAhciPortTaskState = (PAHCIPORTTASKSTATE)RTMemAllocZ(sizeof(AHCIPORTTASKSTATE));
    6168             AssertMsg(pAhciPortTaskState, ("%s: Cannot allocate task state memory!\n"));
    6169         }
    6170         else
    6171         {
    6172             pAhciPortTaskState = pAhciPort->aCachedTasks[pNotifierItem->iTask];
    6173         }
     6105        unsigned idx = 0;
     6106        uint32_t u32Tasks = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
     6107
     6108        idx = ASMBitFirstSetU32(u32Tasks);
     6109        while (idx)
     6110        {
     6111            AHCITXDIR          enmTxDir;
     6112            PAHCIPORTTASKSTATE pAhciPortTaskState;
     6113
     6114            /* Decrement to get the slot number. */
     6115            idx--;
     6116            ahciLog(("%s: Processing command at slot %d\n", __FUNCTION__, idx));
     6117
     6118            /*
     6119             * Check if there is already an allocated task struct in the cache.
     6120             * Allocate a new task otherwise.
     6121             */
     6122            if (!pAhciPort->aCachedTasks[idx])
     6123            {
     6124                pAhciPortTaskState = (PAHCIPORTTASKSTATE)RTMemAllocZ(sizeof(AHCIPORTTASKSTATE));
     6125                AssertMsg(pAhciPortTaskState, ("%s: Cannot allocate task state memory!\n"));
     6126            }
     6127            else
     6128                pAhciPortTaskState = pAhciPort->aCachedTasks[idx];
    61746129
    61756130#ifdef RT_STRICT
    6176         bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, true, false);
    6177         AssertMsg(fXchg, ("Task is already active\n"));
     6131            bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, true, false);
     6132            AssertMsg(fXchg, ("Task is already active\n"));
    61786133#endif
    61796134
    6180         pAhciPortTaskState->uATARegStatus = 0;
    6181         pAhciPortTaskState->uATARegError  = 0;
    6182 
    6183         /** Set current command slot */
    6184         pAhciPortTaskState->uTag = pNotifierItem->iTask;
    6185         pAhciPort->regCMD |= (AHCI_PORT_CMD_CCS_SHIFT(pAhciPortTaskState->uTag));
    6186 
    6187         ahciPortTaskGetCommandFis(pAhciPort, pAhciPortTaskState);
    6188 
    6189         /* Mark the task as processed by the HBA if this is a queued task so that it doesn't occur in the CI register anymore. */
    6190         if (pNotifierItem->fQueued)
    6191         {
    6192             pAhciPortTaskState->fQueued = true;
    6193             ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
    6194         }
    6195         else
    6196             pAhciPortTaskState->fQueued = false;
    6197 
    6198         if (!(pAhciPortTaskState->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
    6199         {
    6200             /* If the reset bit is set put the device into reset state. */
    6201             if (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
     6135            pAhciPortTaskState->uATARegStatus = 0;
     6136            pAhciPortTaskState->uATARegError  = 0;
     6137
     6138            /* Set current command slot */
     6139            pAhciPortTaskState->uTag = idx;
     6140            pAhciPort->regCMD |= (AHCI_PORT_CMD_CCS_SHIFT(pAhciPortTaskState->uTag));
     6141
     6142            ahciPortTaskGetCommandFis(pAhciPort, pAhciPortTaskState);
     6143
     6144            /* Mark the task as processed by the HBA if this is a queued task so that it doesn't occur in the CI register anymore. */
     6145            if (pAhciPort->regSACT & (1 << idx))
    62026146            {
    6203                 ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
    6204                 pAhciPort->fResetDevice = true;
    6205                 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
    6206                 pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
     6147                pAhciPortTaskState->fQueued = true;
     6148                ASMAtomicOrU32(&pAhciPort->u32TasksFinished, (1 << pAhciPortTaskState->uTag));
     6149            }
     6150            else
     6151                pAhciPortTaskState->fQueued = false;
     6152
     6153            if (!(pAhciPortTaskState->cmdFis[AHCI_CMDFIS_BITS] & AHCI_CMDFIS_C))
     6154            {
     6155                /* If the reset bit is set put the device into reset state. */
     6156                if (pAhciPortTaskState->cmdFis[AHCI_CMDFIS_CTL] & AHCI_CMDFIS_CTL_SRST)
     6157                {
     6158                    ahciLog(("%s: Setting device into reset state\n", __FUNCTION__));
     6159                    pAhciPort->fResetDevice = true;
     6160                    ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
     6161                    pAhciPort->aCachedTasks[idx] = pAhciPortTaskState;
    62076162#ifdef RT_STRICT
    6208                 fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
    6209                 AssertMsg(fXchg, ("Task is not active\n"));
     6163                    fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
     6164                    AssertMsg(fXchg, ("Task is not active\n"));
    62106165#endif
    6211                 return true;
     6166                    return true;
     6167                }
     6168                else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
     6169                {
     6170                    ahciFinishStorageDeviceReset(pAhciPort, pAhciPortTaskState);
     6171                    pAhciPort->aCachedTasks[idx] = pAhciPortTaskState;
     6172#ifdef RT_STRICT
     6173                    fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
     6174                    AssertMsg(fXchg, ("Task is not active\n"));
     6175#endif
     6176                    return true;
     6177                }
     6178                else /* We are not in a reset state update the control registers. */
     6179                    AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
    62126180            }
    6213             else if (pAhciPort->fResetDevice) /* The bit is not set and we are in a reset state. */
     6181            else
    62146182            {
    6215                 ahciFinishStorageDeviceReset(pAhciPort, pAhciPortTaskState);
    6216                 pAhciPort->aCachedTasks[pNotifierItem->iTask] = pAhciPortTaskState;
    6217 #ifdef RT_STRICT
    6218                 fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
    6219                 AssertMsg(fXchg, ("Task is not active\n"));
    6220 #endif
    6221                 return true;
    6222             }
    6223             else /* We are not in a reset state update the control registers. */
    6224             {
    6225                 AssertMsgFailed(("%s: Update the control register\n", __FUNCTION__));
    6226             }
    6227         }
    6228         else
    6229         {
    6230             enmTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis);
    6231 
    6232             if (enmTxDir != AHCITXDIR_NONE)
    6233             {
    6234                 pAhciPortTaskState->enmTxDir = enmTxDir;
    6235 
    6236                 ahciLog(("%s: Before increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
    6237                 ASMAtomicIncU32(&pAhciPort->uActTasksActive);
    6238                 ahciLog(("%s: After increment uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
    6239 
    6240                 if (enmTxDir != AHCITXDIR_FLUSH)
     6183                enmTxDir = ahciProcessCmd(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis);
     6184
     6185                if (enmTxDir != AHCITXDIR_NONE)
    62416186                {
    6242                     STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
    6243 
    6244                     rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (enmTxDir == AHCITXDIR_READ) ? false : true);
    6245                     if (RT_FAILURE(rc))
    6246                         AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
    6247                 }
    6248 
    6249                 if (enmTxDir == AHCITXDIR_FLUSH)
    6250                 {
    6251                     rc = pAhciPort->pDrvBlockAsync->pfnStartFlush(pAhciPort->pDrvBlockAsync,
    6252                                                                   pAhciPortTaskState);
    6253                 }
    6254                 else if (enmTxDir == AHCITXDIR_READ)
    6255                 {
    6256                     pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
    6257                     rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
    6258                                                                  pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGListUsed,
    6259                                                                  pAhciPortTaskState->cbTransfer,
    6260                                                                  pAhciPortTaskState);
     6187                    pAhciPortTaskState->enmTxDir = enmTxDir;
     6188
     6189                    ASMAtomicIncU32(&pAhciPort->cTasksActive);
     6190
     6191                    if (enmTxDir != AHCITXDIR_FLUSH)
     6192                    {
     6193                        STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
     6194
     6195                        rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (enmTxDir == AHCITXDIR_READ) ? false : true);
     6196                        if (RT_FAILURE(rc))
     6197                            AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
     6198                    }
     6199
     6200                    if (enmTxDir == AHCITXDIR_FLUSH)
     6201                    {
     6202                        rc = pAhciPort->pDrvBlockAsync->pfnStartFlush(pAhciPort->pDrvBlockAsync,
     6203                                                                      pAhciPortTaskState);
     6204                    }
     6205                    else if (enmTxDir == AHCITXDIR_READ)
     6206                    {
     6207                        pAhciPort->Led.Asserted.s.fReading = pAhciPort->Led.Actual.s.fReading = 1;
     6208                        rc = pAhciPort->pDrvBlockAsync->pfnStartRead(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
     6209                                                                     pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGListUsed,
     6210                                                                     pAhciPortTaskState->cbTransfer,
     6211                                                                     pAhciPortTaskState);
     6212                    }
     6213                    else
     6214                    {
     6215                        pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
     6216                        rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
     6217                                                                      pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGListUsed,
     6218                                                                      pAhciPortTaskState->cbTransfer,
     6219                                                                      pAhciPortTaskState);
     6220                    }
     6221                    if (rc == VINF_VD_ASYNC_IO_FINISHED)
     6222                        rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, VINF_SUCCESS);
     6223                    else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
     6224                        rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, rc);
    62616225                }
    62626226                else
    62636227                {
    6264                     pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
    6265                     rc = pAhciPort->pDrvBlockAsync->pfnStartWrite(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->uOffset,
    6266                                                                   pAhciPortTaskState->pSGListHead, pAhciPortTaskState->cSGListUsed,
    6267                                                                   pAhciPortTaskState->cbTransfer,
    6268                                                                   pAhciPortTaskState);
     6228#ifdef RT_STRICT
     6229                    fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
     6230                    AssertMsg(fXchg, ("Task is not active\n"));
     6231#endif
     6232
     6233                    /* There is nothing left to do. Notify the guest. */
     6234                    ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
     6235                    /* Add the task to the cache. */
     6236                    pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState;
    62696237                }
    6270                 if (rc == VINF_VD_ASYNC_IO_FINISHED)
    6271                     rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, VINF_SUCCESS);
    6272 
    6273                 if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
    6274                     rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, rc);
    6275             }
    6276             else
    6277             {
    6278 #ifdef RT_STRICT
    6279                 fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
    6280                 AssertMsg(fXchg, ("Task is not active\n"));
    6281 #endif
    6282 
    6283                 /* There is nothing left to do. Notify the guest. */
    6284                 ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
    6285                 /* Add the task to the cache. */
    6286                 pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState;
    6287             }
    6288         }
    6289     }
     6238            } /* Command */
     6239
     6240            u32Tasks &= ~(1 << idx); /* Clear task bit. */
     6241            idx = ASMBitFirstSetU32(u32Tasks);
     6242        } /* while tasks available */
     6243    } /* fUseAsyncInterface */
    62906244
    62916245    return true;
     
    63036257    uint32_t uIORequestsProcessed = 0;
    63046258    uint32_t uIOsPerSec = 0;
    6305     uint32_t cTasksToProcess = 0;
    6306     bool fRedoDontWait = false;
     6259    uint32_t fTasksToProcess = 0;
     6260    unsigned idx = 0;
    63076261
    63086262    ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
     
    63106264    if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
    63116265        return VINF_SUCCESS;
    6312 
    6313     if (pAhciPort->fRedo)
    6314     {
    6315         /*
    6316          * We entered again after the VM was suspended due to a task failing.
    6317          * Use that task and try to process it again.
    6318          */
    6319         ahciLog(("%s: Port %d redo task\n", __FUNCTION__, pAhciPort->iLUN));
    6320         cTasksToProcess = pAhciPort->cTasksToProcess;
    6321         pAhciPort->cTasksToProcess = 0;
    6322         fRedoDontWait = true;
    6323     }
    63246266
    63256267    /* We use only one task structure. */
     
    63336275    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
    63346276    {
    6335 
    6336         if (!fRedoDontWait)
    6337         {
    6338             /* New run to get number of I/O requests per second?. */
    6339             if (!u64StartTime)
    6340                 u64StartTime = RTTimeMilliTS();
    6341 
    6342             ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, true);
    6343             if (pAhci->fSignalIdle)
    6344                 PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
    6345 
    6346             rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, 1000);
    6347             if (rc == VERR_TIMEOUT)
    6348             {
    6349                 /* No I/O requests inbetween. Reset statistics and wait again. */
    6350                 pAhciPort->StatIORequestsPerSecond.c = 0;
    6351                 rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, RT_INDEFINITE_WAIT);
    6352             }
    6353 
    6354             if (RT_FAILURE(rc) || (pThread->enmState != PDMTHREADSTATE_RUNNING))
    6355                 break;
    6356 
    6357             /*
    6358              * Don't process further tasks if the redo flag is set but wait again
    6359              * until we got suspended.
    6360              */
    6361             if (pAhciPort->fRedo)
    6362                 continue;
    6363 
    6364             AssertMsg(pAhciPort->pDrvBase, ("I/O thread without attached device?!\n"));
     6277        /* New run to get number of I/O requests per second?. */
     6278        if (!u64StartTime)
     6279            u64StartTime = RTTimeMilliTS();
     6280
     6281        ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, true);
     6282        if (pAhci->fSignalIdle)
     6283            PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
     6284
     6285        rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, 1000);
     6286        if (rc == VERR_TIMEOUT)
     6287        {
     6288            /* No I/O requests inbetween. Reset statistics and wait again. */
     6289            pAhciPort->StatIORequestsPerSecond.c = 0;
     6290            rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, RT_INDEFINITE_WAIT);
    63656291        }
    6366         else
    6367             fRedoDontWait = false;
     6292
     6293        if (RT_FAILURE(rc) || (pThread->enmState != PDMTHREADSTATE_RUNNING))
     6294            break;
     6295
     6296        /* Go to sleep again if we are in redo mode. */
     6297        if (RT_UNLIKELY(pAhciPort->fRedo))
     6298            continue;
     6299
     6300        AssertMsg(pAhciPort->pDrvBase, ("I/O thread without attached device?!\n"));
    63686301
    63696302        ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, false);
    6370 
    6371         if (!pAhciPort->fRedo)
    6372         {
    6373             /*
    6374              * To maximize the throughput of the controller we try to minimize the
    6375              * number of world switches during interrupts by grouping as many
    6376              * I/O requests together as possible.
    6377              * On the other side we want to get minimal latency if the I/O load is low.
    6378              * Thatswhy the number of I/O requests per second is measured and if it is over
    6379              * a threshold the thread waits for other requests from the guest.
    6380              */
    6381             if (uIOsPerSec >= pAhci->cHighIOThreshold)
    6382             {
    6383                 uint8_t uActWritePosPrev = pAhciPort->uActWritePos;
    6384 
    6385                 Log(("%s: Waiting for more tasks to get queued\n", __FUNCTION__));
    6386 
    6387                 do
    6388                 {
    6389                     /* Sleep some time. */
    6390                     RTThreadSleep(pAhci->cMillisToSleep);
    6391                     /* Check if we got some new requests inbetween. */
    6392                     if (uActWritePosPrev != pAhciPort->uActWritePos)
    6393                     {
    6394                         uActWritePosPrev = pAhciPort->uActWritePos;
    6395                         /*
    6396                          * Check if the queue is full. If that is the case
    6397                          * there is no point waiting another round.
    6398                          */
    6399                         if (   (   (pAhciPort->uActReadPos < uActWritePosPrev)
    6400                                 && (uActWritePosPrev - pAhciPort->uActReadPos) == AHCI_NR_COMMAND_SLOTS)
    6401                             || (   (pAhciPort->uActReadPos > uActWritePosPrev)
    6402                                 && (RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev) == AHCI_NR_COMMAND_SLOTS)  )
    6403                         {
    6404                             Log(("%s: Queue full -> leaving\n", __FUNCTION__));
    6405                             break;
    6406                         }
    6407                         Log(("%s: Another round\n", __FUNCTION__));
    6408                     }
    6409                     else /* No change break out of the loop. */
    6410                     {
    6411 #ifdef DEBUG
    6412                         uint8_t uQueuedTasks;
    6413                         if (pAhciPort->uActReadPos < uActWritePosPrev)
    6414                             uQueuedTasks = uActWritePosPrev - pAhciPort->uActReadPos;
    6415                         else
    6416                             uQueuedTasks = RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev;
    6417 
    6418                         Log(("%s: %u Tasks are queued\n", __FUNCTION__, uQueuedTasks));
    6419 #endif
    6420                         break;
    6421                     }
    6422                 } while (true);
    6423             }
    6424 
    6425             cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
    6426 
    6427             ahciLog(("%s: Processing %u requests\n", __FUNCTION__, cTasksToProcess));
    6428         } /* fRedo */
    6429         else
    6430             pAhciPort->fRedo = false;
    6431 
    6432         ASMAtomicXchgBool(&pAhciPort->fNotificationSend, false);
     6303        fTasksToProcess = ASMAtomicXchgU32(&pAhciPort->u32TasksNew, 0);
     6304
     6305        idx = ASMBitFirstSetU32(fTasksToProcess);
    64336306
    64346307        /* Process commands. */
    6435         while (   (cTasksToProcess > 0)
    6436                && RT_LIKELY(!pAhciPort->fRedo)
     6308        while (   idx
    64376309               && RT_LIKELY(!pAhciPort->fPortReset))
    64386310        {
    64396311            AHCITXDIR enmTxDir;
    6440             uint8_t   uActTag;
    6441 
     6312
     6313            idx--;
    64426314            STAM_PROFILE_START(&pAhciPort->StatProfileProcessTime, a);
    6443 
    6444             ahciLog(("%s: uActWritePos=%u\n", __FUNCTION__, pAhciPort->uActWritePos));
    6445             ahciLog(("%s: Before uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
    64466315
    64476316            pAhciPortTaskState->uATARegStatus = 0;
    64486317            pAhciPortTaskState->uATARegError  = 0;
    6449             uActTag = pAhciPort->ahciIOTasks[pAhciPort->uActReadPos];
    6450 
    6451             pAhciPortTaskState->uTag = AHCI_TASK_GET_TAG(uActTag);
     6318            pAhciPortTaskState->uTag          = idx;
    64526319            AssertMsg(pAhciPortTaskState->uTag < AHCI_NR_COMMAND_SLOTS, ("%s: Invalid Tag number %u!!\n", __FUNCTION__, pAhciPortTaskState->uTag));
    64536320
    6454             /** Set current command slot */
     6321            /* Set current command slot */
    64556322            pAhciPort->regCMD |= (AHCI_PORT_CMD_CCS_SHIFT(pAhciPortTaskState->uTag));
    64566323
    64576324            /* Mark the task as processed by the HBA if this is a queued task so that it doesn't occur in the CI register anymore. */
    6458             if (AHCI_TASK_IS_QUEUED(uActTag))
     6325            if (pAhciPort->regSACT & (1 << idx))
    64596326            {
    64606327                pAhciPortTaskState->fQueued = true;
     
    64626329            }
    64636330            else
    6464             {
    64656331                pAhciPortTaskState->fQueued = false;
    6466             }
    64676332
    64686333            ahciPortTaskGetCommandFis(pAhciPort, pAhciPortTaskState);
     
    65096374                        }
    65106375                        else
    6511                             pAhciPort->cTasksToProcess = cTasksToProcess;
     6376                        {
     6377                            /* Add the task to the mask again. */
     6378                            ASMAtomicOrU32(&pAhciPort->u32TasksNew, (1 << pAhciPortTaskState->uTag));
     6379                        }
    65126380                    }
    65136381                    else
     
    66186486                            else
    66196487                            {
    6620                                 pAhciPort->cTasksToProcess = cTasksToProcess;
    6621                                 pAhciPort->fRedo = true;
     6488                                /* Add the task to the mask again. */
     6489                                ASMAtomicOrU32(&pAhciPort->u32TasksNew, (1 << pAhciPortTaskState->uTag));
    66226490                            }
    66236491                        }
     
    66646532                pAhciPortTaskState->uOffset = 0;
    66656533                pAhciPortTaskState->cbTransfer = 0;
    6666                 /* Make the port number invalid making it easier to track down bugs. */
    6667                 pAhciPort->ahciIOTasks[pAhciPort->uActReadPos] = 0xff;
    66686534#endif
    6669 
    6670                 pAhciPort->uActReadPos++;
    6671                 pAhciPort->uActReadPos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
    6672                 ahciLog(("%s: After uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
    6673                 cTasksToProcess--;
    66746535
    66756536                /* If we encountered an error notify the guest and continue with the next task. */
     
    66806541                        ahciSendSDBFis(pAhciPort, 0, true);
    66816542                }
    6682                 else if (!cTasksToProcess)
    6683                     cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
    66846543            }
    6685         }
     6544            fTasksToProcess &= ~(1 << idx);
     6545            idx = ASMBitFirstSetU32(fTasksToProcess);
     6546        } /* while tasks to process */
    66866547
    66876548        if (   ASMAtomicReadU32(&pAhciPort->u32QueuedTasksFinished) != 0
     
    67956656        pHlp->pfnPrintf(pHlp, "PortPhysClb=%RGp\n", pThisPort->GCPhysAddrClb);
    67966657        pHlp->pfnPrintf(pHlp, "PortPhysFb=%RGp\n", pThisPort->GCPhysAddrFb);
    6797         pHlp->pfnPrintf(pHlp, "PortActWritePos=%u\n", pThisPort->uActWritePos);
    6798         pHlp->pfnPrintf(pHlp, "PortActReadPos=%u\n", pThisPort->uActReadPos);
    6799         pHlp->pfnPrintf(pHlp, "PortActTasksActive=%u\n", pThisPort->uActTasksActive);
     6658        pHlp->pfnPrintf(pHlp, "PortActTasksActive=%u\n", pThisPort->cTasksActive);
    68006659        pHlp->pfnPrintf(pHlp, "PortPoweredOn=%RTbool\n", pThisPort->fPoweredOn);
    68016660        pHlp->pfnPrintf(pHlp, "PortSpunUp=%RTbool\n", pThisPort->fSpunUp);
     
    68046663        pHlp->pfnPrintf(pHlp, "PortTasksFinished=%#x\n", pThisPort->u32TasksFinished);
    68056664        pHlp->pfnPrintf(pHlp, "PortQueuedTasksFinished=%#x\n", pThisPort->u32QueuedTasksFinished);
    6806         pHlp->pfnPrintf(pHlp, "PortNotificationSend=%RTbool\n", pThisPort->fNotificationSend);
    68076665        pHlp->pfnPrintf(pHlp, "PortAsyncIoThreadIdle=%RTbool\n", pThisPort->fAsyncIOThreadIdle);
    68086666        pHlp->pfnPrintf(pHlp, "\n");
     
    68326690            bool fFinished;
    68336691            if (pThisPort->fAsyncInterface)
    6834                 fFinished = (pThisPort->uActTasksActive == 0);
     6692                fFinished = (pThisPort->cTasksActive == 0);
    68356693            else
    6836                 fFinished = ((pThisPort->uActTasksActive == 0 || pThisPort->fRedo) && (pThisPort->fAsyncIOThreadIdle));
     6694                fFinished = ((pThisPort->cTasksActive == 0) && (pThisPort->fAsyncIOThreadIdle));
    68376695            if (!fFinished)
    68386696               return false;
     
    69326790    for (i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
    69336791    {
    6934         Assert(pThis->ahciPort[i].uActTasksActive == 0);
     6792        Assert(pThis->ahciPort[i].cTasksActive == 0);
    69356793        SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLB);
    69366794        SSMR3PutU32(pSSM, pThis->ahciPort[i].regCLBU);
     
    69576815        SSMR3PutBool(pSSM, pThis->ahciPort[i].fResetDevice);
    69586816
    6959         /* No need to save */
    6960         SSMR3PutU8(pSSM, pThis->ahciPort[i].uActWritePos);
    6961         SSMR3PutU8(pSSM, pThis->ahciPort[i].uActReadPos);
     6817        /* No need to save but to avoid changing the SSM format they are still written. */
     6818        SSMR3PutU8(pSSM, 0); /* Prev: Write position in the FIFO. */
     6819        SSMR3PutU8(pSSM, 0); /* Prev: Read position in the FIFO. */
     6820
    69626821        SSMR3PutBool(pSSM, pThis->ahciPort[i].fPoweredOn);
    69636822        SSMR3PutBool(pSSM, pThis->ahciPort[i].fSpunUp);
     
    70836942        SSMR3GetU32(pSSM, &pThis->uCccCurrentNr);
    70846943
    7085         SSMR3GetU32(pSSM, &pThis->u32PortsInterrupted);
     6944        SSMR3GetU32(pSSM, (uint32_t *)&pThis->u32PortsInterrupted);
    70866945        SSMR3GetBool(pSSM, &pThis->fReset);
    70876946        SSMR3GetBool(pSSM, &pThis->f64BitAddr);
     
    70926951        for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
    70936952        {
     6953            uint8_t u8;
    70946954            PAHCIPort pAhciPort = &pThis->ahciPort[i];
    70956955
     
    71216981                SSMR3Skip(pSSM, AHCI_NR_COMMAND_SLOTS * sizeof(uint8_t)); /* no active data here */
    71226982
    7123             SSMR3GetU8(pSSM, &pThis->ahciPort[i].uActWritePos);
    7124             SSMR3GetU8(pSSM, &pThis->ahciPort[i].uActReadPos);
     6983            SSMR3GetU8(pSSM, &u8);
     6984            SSMR3GetU8(pSSM, &u8);
    71256985            SSMR3GetBool(pSSM, &pThis->ahciPort[i].fPoweredOn);
    71266986            SSMR3GetBool(pSSM, &pThis->ahciPort[i].fSpunUp);
     
    71427002            uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
    71437003
    7144             if (fTasksOutstanding || fQueuedTasksOutstanding)
     7004            pAhciPort->u32TasksNew = fTasksOutstanding | fQueuedTasksOutstanding;
     7005
     7006            if (pAhciPort->u32TasksNew)
    71457007            {
    71467008                /*
    71477009                 * There are tasks pending. The VM was saved after a task failed
    7148                  * because of non-fatal error. Set the redo flag
    7149                  * and the correct cTasksToProcess number based on the difference
    7150                  * of the FIFO counters.
     7010                 * because of non-fatal error. Set the redo flag.
    71517011                 */
    7152 
    7153                 if (!pAhciPort->fAsyncInterface)
    7154                 {
    7155                     /*
    7156                      * Because we don't save the task FIFO we have to reconstruct it by using the
    7157                      * SACT and CI registers along with the shadowed variables containing the
    7158                      * completed tasks and placing them in the FIFO again.
    7159                      */
    7160                     pAhciPort->fRedo = true;
    7161 
    7162                     pAhciPort->uActWritePos = 0;
    7163                     pAhciPort->uActReadPos  = 0;
    7164 
    7165                     for (unsigned uTag = 0; uTag < AHCI_NR_COMMAND_SLOTS; uTag++)
    7166                     {
    7167                         if (   fTasksOutstanding & (1 << uTag)
    7168                             || fQueuedTasksOutstanding & (1 << uTag))
    7169                         {
    7170                             pAhciPort->ahciIOTasks[pAhciPort->uActWritePos] = AHCI_TASK_SET(uTag, (fQueuedTasksOutstanding & (1 << uTag)) ? 1 : 0);
    7171                             pAhciPort->uActWritePos++;
    7172                             pAhciPort->uActWritePos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
    7173                             pAhciPort->cTasksToProcess++;
    7174                         }
    7175                     }
    7176                 }
    7177                 else
    7178                 {
    7179                     /* Use the PDM queue. */
    7180                     for (unsigned uTag = 0; uTag < AHCI_NR_COMMAND_SLOTS; uTag++)
    7181                     {
    7182                         if (   fTasksOutstanding & (1 << uTag)
    7183                             || fQueuedTasksOutstanding & (1 << uTag))
    7184                         {
    7185                             PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pThis->CTX_SUFF(pNotifierQueue));
    7186                             AssertMsg(pItem, ("Allocating item for queue failed\n"));
    7187 
    7188                             pItem->iPort = pThis->ahciPort[i].iLUN;
    7189                             pItem->iTask = uTag;
    7190                             pItem->fQueued = !!(fQueuedTasksOutstanding & (1 << uTag)); /* Mark if the task is queued. */
    7191                             PDMQueueInsert(pThis->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
    7192                         }
    7193                     }
    7194                 }
     7012                pAhciPort->fRedo = true;
    71957013            }
    71967014        }
     
    75697387
    75707388    /*
    7571      * Check if one of the ports has the redo flag set
    7572      * and queue all pending tasks again.
     7389     * Check if one of the ports has pending tasks.
     7390     * Queue a notification item again in this case.
    75737391     */
    75747392    for (unsigned i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
     
    75767394        PAHCIPort pAhciPort = &pAhci->ahciPort[i];
    75777395
    7578         if (   pAhciPort->fRedo
    7579             && pAhciPort->fAsyncInterface)
    7580         {
    7581             uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished;
    7582             uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
    7583 
     7396        if (pAhciPort->u32TasksNew)
     7397        {
     7398            PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
     7399            AssertMsg(pItem, ("Allocating item for queue failed\n"));
     7400
     7401            Assert(pAhciPort->fRedo);
    75847402            pAhciPort->fRedo = false;
    75857403
    7586             /* Use the PDM queue. */
    7587             for (unsigned uTag = 0; uTag < AHCI_NR_COMMAND_SLOTS; uTag++)
    7588             {
    7589                 if (   fTasksOutstanding & (1 << uTag)
    7590                     || fQueuedTasksOutstanding & (1 << uTag))
    7591                 {
    7592                     PDEVPORTNOTIFIERQUEUEITEM pItem = (PDEVPORTNOTIFIERQUEUEITEM)PDMQueueAlloc(pAhci->CTX_SUFF(pNotifierQueue));
    7593                     AssertMsg(pItem, ("Allocating item for queue failed\n"));
    7594 
    7595                     pItem->iPort = pAhci->ahciPort[i].iLUN;
    7596                     pItem->iTask = uTag;
    7597                     pItem->fQueued = !!(fQueuedTasksOutstanding & (1 << uTag)); /* Mark if the task is queued. */
    7598                     PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
    7599                 }
    7600             }
     7404            pItem->iPort = pAhci->ahciPort[i].iLUN;
     7405            PDMQueueInsert(pAhci->CTX_SUFF(pNotifierQueue), (PPDMQUEUEITEMCORE)pItem);
    76017406        }
    76027407    }
     
    78677672                                          "SecondarySlave\0"
    78687673                                          "PortCount\0"
    7869                                           "UseAsyncInterfaceIfAvailable\0"
    7870                                           "HighIOThreshold\0"
    7871                                           "MillisToSleep\0"))
     7674                                          "UseAsyncInterfaceIfAvailable\0"))
    78727675        return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
    78737676                                N_("AHCI configuration error: unknown option specified"));
     
    79037706        return PDMDEV_SET_ERROR(pDevIns, rc,
    79047707                                N_("AHCI configuration error: failed to read UseAsyncInterfaceIfAvailable as boolean"));
    7905     rc = CFGMR3QueryU32Def(pCfg, "HighIOThreshold", &pThis->cHighIOThreshold, ~0);
    7906     if (RT_FAILURE(rc))
    7907         return PDMDEV_SET_ERROR(pDevIns, rc,
    7908                                 N_("AHCI configuration error: failed to read HighIOThreshold as integer"));
    7909     rc = CFGMR3QueryU32Def(pCfg, "MillisToSleep", &pThis->cMillisToSleep, 0);
    7910     if (RT_FAILURE(rc))
    7911         return PDMDEV_SET_ERROR(pDevIns, rc,
    7912                                 N_("AHCI configuration error: failed to read MillisToSleep as integer"));
    79137708
    79147709    pThis->fR0Enabled = fR0Enabled;
     
    80337828
    80347829    /*
    8035      * Create the transmit queue.
     7830     * Create the notification queue.
     7831     *
     7832     * We need 2 items for every port because of SMP races.
    80367833     */
    8037     rc = PDMDevHlpQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), 30*32 /*Maximum of 30 ports multiplied with 32 tasks each port*/, 0,
     7834    rc = PDMDevHlpQueueCreate(pDevIns, sizeof(DEVPORTNOTIFIERQUEUEITEM), AHCI_MAX_NR_PORTS_IMPL*2, 0,
    80387835                              ahciNotifyQueueConsumer, true, "AHCI-Xmit", &pThis->pNotifierQueueR3);
    80397836    if (RT_FAILURE(rc))
     
    82408037            return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
    82418038                                       N_("AHCI: Failed to attach drive to %s"), szName);
    8242 
    8243 #ifdef DEBUG
    8244         for (uint32_t j = 0; j < AHCI_NR_COMMAND_SLOTS; j++)
    8245             pAhciPort->ahciIOTasks[j] = 0xff;
    8246 #endif
    82478039    }
    82488040
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette