VirtualBox

Changeset 32957 in vbox for trunk/src/VBox/Devices/Storage


Ignore:
Timestamp:
Oct 6, 2010 4:10:48 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
66456
Message:

AHCI: Implement SuspendOnError to give the user a chance to fix certain errors like broken iSCSI connections.

File:
1 edited

Legend:

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

    r32939 r32957  
    531531    /** Error counter */
    532532    uint32_t                        cErrors;
     533
     534    /** Tasks to process */
     535    uint32_t                        cTasksToProcess;
     536    /** Flag whether we need to redo a task. */
     537    bool                            fRedo;
    533538
    534539} AHCIPort;
     
    45974602        sdbFis[1] = pAhciPort->u32QueuedTasksFinished | uFinishedTasks;
    45984603
    4599          ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
     4604        ahciPostFisIntoMemory(pAhciPort, AHCI_CMDFIS_TYPE_SETDEVBITS, (uint8_t *)sdbFis);
    46004605
    46014606        if (RT_UNLIKELY(pTaskErr))
     
    56655670        PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
    56665671    return rc;
     5672}
     5673
     5674static void ahciWarningDiskFull(PPDMDEVINS pDevIns)
     5675{
     5676    int rc;
     5677    LogRel(("AHCI: Host disk full\n"));
     5678    rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_DISKFULL",
     5679                                    N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
     5680    AssertRC(rc);
     5681}
     5682
     5683static void ahciWarningFileTooBig(PPDMDEVINS pDevIns)
     5684{
     5685    int rc;
     5686    LogRel(("AHCI: File too big\n"));
     5687    rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_FILETOOBIG",
     5688                                    N_("Host system reported that the file size limit of the host file system has been exceeded. VM execution is suspended. You need to move your virtual hard disk to a filesystem which allows bigger files"));
     5689    AssertRC(rc);
     5690}
     5691
     5692static void ahciWarningISCSI(PPDMDEVINS pDevIns)
     5693{
     5694    int rc;
     5695    LogRel(("AHCI: iSCSI target unavailable\n"));
     5696    rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_ISCSIDOWN",
     5697                                    N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
     5698    AssertRC(rc);
     5699}
     5700
     5701bool ahciIsRedoSetWarning(PAHCIPort pAhciPort, int rc)
     5702{
     5703    if (rc == VERR_DISK_FULL)
     5704    {
     5705        ahciWarningDiskFull(pAhciPort->CTX_SUFF(pDevIns));
     5706        return true;
     5707    }
     5708    if (rc == VERR_FILE_TOO_BIG)
     5709    {
     5710        ahciWarningFileTooBig(pAhciPort->CTX_SUFF(pDevIns));
     5711        return true;
     5712    }
     5713    if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
     5714    {
     5715        /* iSCSI connection abort (first error) or failure to reestablish
     5716         * connection (second error). Pause VM. On resume we'll retry. */
     5717        ahciWarningISCSI(pAhciPort->CTX_SUFF(pDevIns));
     5718        return true;
     5719    }
     5720    return false;
    56675721}
    56685722
     
    61996253    uint32_t uIORequestsProcessed = 0;
    62006254    uint32_t uIOsPerSec = 0;
     6255    uint32_t cTasksToProcess = 0;
     6256    bool fRedoDontWait = false;
    62016257
    62026258    ahciLog(("%s: Port %d entering async IO loop.\n", __FUNCTION__, pAhciPort->iLUN));
     
    62046260    if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
    62056261        return VINF_SUCCESS;
     6262
     6263    if (pAhciPort->fRedo)
     6264    {
     6265        /*
     6266         * We entered again after the VM was suspended due to a task failing.
     6267         * Use that task and try to process it again.
     6268         */
     6269        ahciLog(("%s: Port %d redo task\n", __FUNCTION__, pAhciPort->iLUN));
     6270        cTasksToProcess = pAhciPort->cTasksToProcess;
     6271        pAhciPort->cTasksToProcess = 0;
     6272        fRedoDontWait = true;
     6273    }
    62066274
    62076275    /* We use only one task structure. */
     
    62136281    }
    62146282
    6215     while(pThread->enmState == PDMTHREADSTATE_RUNNING)
    6216     {
    6217         uint32_t uQueuedTasksFinished = 0;
    6218 
    6219         /* New run to get number of I/O requests per second?. */
    6220         if (!u64StartTime)
    6221             u64StartTime = RTTimeMilliTS();
    6222 
    6223         ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, true);
    6224         if (pAhci->fSignalIdle)
    6225             PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
    6226 
    6227         rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, 1000);
    6228         if (rc == VERR_TIMEOUT)
    6229         {
    6230             /* No I/O requests inbetween. Reset statistics and wait again. */
    6231             pAhciPort->StatIORequestsPerSecond.c = 0;
    6232             rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, RT_INDEFINITE_WAIT);
     6283    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     6284    {
     6285
     6286        if (!fRedoDontWait)
     6287        {
     6288            /* New run to get number of I/O requests per second?. */
     6289            if (!u64StartTime)
     6290                u64StartTime = RTTimeMilliTS();
     6291
     6292            ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, true);
     6293            if (pAhci->fSignalIdle)
     6294                PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
     6295
     6296            rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, 1000);
     6297            if (rc == VERR_TIMEOUT)
     6298            {
     6299                /* No I/O requests inbetween. Reset statistics and wait again. */
     6300                pAhciPort->StatIORequestsPerSecond.c = 0;
     6301                rc = RTSemEventWait(pAhciPort->AsyncIORequestSem, RT_INDEFINITE_WAIT);
     6302            }
     6303
     6304            if (RT_FAILURE(rc) || (pThread->enmState != PDMTHREADSTATE_RUNNING))
     6305                break;
     6306
     6307            /*
     6308             * Don't process further tasks if the redo flag is set but wait again
     6309             * until we got suspended.
     6310             */
     6311            if (pAhciPort->fRedo)
     6312                continue;
     6313
     6314            AssertMsg(pAhciPort->pDrvBase, ("I/O thread without attached device?!\n"));
    62336315        }
    6234 
    6235         if (RT_FAILURE(rc) || (pThread->enmState != PDMTHREADSTATE_RUNNING))
    6236             break;
    6237 
    6238         AssertMsg(pAhciPort->pDrvBase, ("I/O thread without attached device?!\n"));
     6316        else
     6317            fRedoDontWait = false;
    62396318
    62406319        ASMAtomicXchgBool(&pAhciPort->fAsyncIOThreadIdle, false);
    62416320
    6242         /*
    6243          * To maximize the throughput of the controller we try to minimize the
    6244          * number of world switches during interrupts by grouping as many
    6245          * I/O requests together as possible.
    6246          * On the other side we want to get minimal latency if the I/O load is low.
    6247          * Thatswhy the number of I/O requests per second is measured and if it is over
    6248          * a threshold the thread waits for other requests from the guest.
    6249          */
    6250         if (uIOsPerSec >= pAhci->cHighIOThreshold)
    6251         {
    6252             uint8_t uActWritePosPrev = pAhciPort->uActWritePos;
    6253 
    6254             Log(("%s: Waiting for more tasks to get queued\n", __FUNCTION__));
    6255 
    6256             do
     6321        if (!pAhciPort->fRedo)
     6322        {
     6323            /*
     6324             * To maximize the throughput of the controller we try to minimize the
     6325             * number of world switches during interrupts by grouping as many
     6326             * I/O requests together as possible.
     6327             * On the other side we want to get minimal latency if the I/O load is low.
     6328             * Thatswhy the number of I/O requests per second is measured and if it is over
     6329             * a threshold the thread waits for other requests from the guest.
     6330             */
     6331            if (uIOsPerSec >= pAhci->cHighIOThreshold)
    62576332            {
    6258                 /* Sleep some time. */
    6259                 RTThreadSleep(pAhci->cMillisToSleep);
    6260                 /* Check if we got some new requests inbetween. */
    6261                 if (uActWritePosPrev != pAhciPort->uActWritePos)
     6333                uint8_t uActWritePosPrev = pAhciPort->uActWritePos;
     6334
     6335                Log(("%s: Waiting for more tasks to get queued\n", __FUNCTION__));
     6336
     6337                do
    62626338                {
    6263                     uActWritePosPrev = pAhciPort->uActWritePos;
    6264                     /*
    6265                      * Check if the queue is full. If that is the case
    6266                      * there is no point waiting another round.
    6267                      */
    6268                     if (   (   (pAhciPort->uActReadPos < uActWritePosPrev)
    6269                             && (uActWritePosPrev - pAhciPort->uActReadPos) == AHCI_NR_COMMAND_SLOTS)
    6270                         || (   (pAhciPort->uActReadPos > uActWritePosPrev)
    6271                             && (RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev) == AHCI_NR_COMMAND_SLOTS)  )
     6339                    /* Sleep some time. */
     6340                    RTThreadSleep(pAhci->cMillisToSleep);
     6341                    /* Check if we got some new requests inbetween. */
     6342                    if (uActWritePosPrev != pAhciPort->uActWritePos)
    62726343                    {
    6273                         Log(("%s: Queue full -> leaving\n", __FUNCTION__));
     6344                        uActWritePosPrev = pAhciPort->uActWritePos;
     6345                        /*
     6346                         * Check if the queue is full. If that is the case
     6347                         * there is no point waiting another round.
     6348                         */
     6349                        if (   (   (pAhciPort->uActReadPos < uActWritePosPrev)
     6350                                && (uActWritePosPrev - pAhciPort->uActReadPos) == AHCI_NR_COMMAND_SLOTS)
     6351                            || (   (pAhciPort->uActReadPos > uActWritePosPrev)
     6352                                && (RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev) == AHCI_NR_COMMAND_SLOTS)  )
     6353                        {
     6354                            Log(("%s: Queue full -> leaving\n", __FUNCTION__));
     6355                            break;
     6356                        }
     6357                        Log(("%s: Another round\n", __FUNCTION__));
     6358                    }
     6359                    else /* No change break out of the loop. */
     6360                    {
     6361#ifdef DEBUG
     6362                        uint8_t uQueuedTasks;
     6363                        if (pAhciPort->uActReadPos < uActWritePosPrev)
     6364                            uQueuedTasks = uActWritePosPrev - pAhciPort->uActReadPos;
     6365                        else
     6366                            uQueuedTasks = RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev;
     6367
     6368                        Log(("%s: %u Tasks are queued\n", __FUNCTION__, uQueuedTasks));
     6369#endif
    62746370                        break;
    62756371                    }
    6276                     Log(("%s: Another round\n", __FUNCTION__));
    6277                 }
    6278                 else /* No change break out of the loop. */
    6279                 {
    6280 #ifdef DEBUG
    6281                     uint8_t uQueuedTasks;
    6282                     if (pAhciPort->uActReadPos < uActWritePosPrev)
    6283                         uQueuedTasks = uActWritePosPrev - pAhciPort->uActReadPos;
    6284                     else
    6285                         uQueuedTasks = RT_ELEMENTS(pAhciPort->ahciIOTasks) - pAhciPort->uActReadPos + uActWritePosPrev;
    6286 
    6287                     Log(("%s: %u Tasks are queued\n", __FUNCTION__, uQueuedTasks));
    6288 #endif
    6289                     break;
    6290                 }
    6291             } while (true);
    6292         }
     6372                } while (true);
     6373            }
     6374
     6375            cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
     6376
     6377            ahciLog(("%s: Processing %u requests\n", __FUNCTION__, cTasksToProcess));
     6378        } /* fRedo */
     6379        else
     6380            pAhciPort->fRedo = false;
    62936381
    62946382        ASMAtomicXchgBool(&pAhciPort->fNotificationSend, false);
    6295 
    6296         uint32_t cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
    6297 
    6298         ahciLog(("%s: Processing %u requests\n", __FUNCTION__, cTasksToProcess));
    62996383
    63006384        /* Process commands. */
    63016385        while (   (cTasksToProcess > 0)
     6386               && RT_LIKELY(!pAhciPort->fRedo)
    63026387               && RT_LIKELY(!pAhciPort->fPortReset))
    63036388        {
     
    63686453                    if (RT_FAILURE(rc))
    63696454                    {
    6370                         pAhciPortTaskState->uATARegError = ID_ERR;
    6371                         pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
     6455                        if (!ahciIsRedoSetWarning(pAhciPort, rc))
     6456                        {
     6457                            pAhciPortTaskState->uATARegError = ID_ERR;
     6458                            pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
     6459                        }
     6460                        else
     6461                        {
     6462                            pAhciPort->fRedo = true;
     6463                            pAhciPort->cTasksToProcess = cTasksToProcess;
     6464                        }
    63726465                    }
    63736466                    else
     
    63776470                    }
    63786471
    6379                     if (pAhciPortTaskState->fQueued)
    6380                         uQueuedTasksFinished |= (1 << pAhciPortTaskState->uTag);
    6381                     else
     6472                    if (!pAhciPort->fRedo)
    63826473                    {
    6383                         /* Task is not queued send D2H FIS */
    6384                         ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
     6474                        if (pAhciPortTaskState->fQueued)
     6475                            ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
     6476                        else
     6477                        {
     6478                            /* Task is not queued send D2H FIS */
     6479                            ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
     6480                        }
    63856481                    }
    63866482                }
     
    64686564                        if (RT_FAILURE(rc))
    64696565                        {
    6470                             pAhciPortTaskState->uATARegError = ID_ERR;
    6471                             pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
     6566                            if (!ahciIsRedoSetWarning(pAhciPort, rc))
     6567                            {
     6568                                pAhciPortTaskState->uATARegError = ID_ERR;
     6569                                pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
     6570                            }
     6571                            else
     6572                            {
     6573                                pAhciPort->cTasksToProcess = cTasksToProcess;
     6574                                pAhciPort->fRedo = true;
     6575                            }
    64726576                        }
    64736577                        else
     
    64766580                            pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
    64776581                        }
    6478                         /* Write updated command header into memory of the guest. */
    6479                         PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
    6480                                            &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
    6481 
    6482                         if (pAhciPortTaskState->fQueued)
    6483                             uQueuedTasksFinished |= (1 << pAhciPortTaskState->uTag);
    6484                         else
     6582
     6583                        if (!pAhciPort->fRedo)
    64856584                        {
    6486                             /* Task is not queued send D2H FIS */
    6487                             ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
     6585                            /* Write updated command header into memory of the guest. */
     6586                            PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
     6587                                               &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
     6588
     6589                            if (pAhciPortTaskState->fQueued)
     6590                                ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
     6591                            else
     6592                            {
     6593                                /* Task is not queued send D2H FIS */
     6594                                ahciSendD2HFis(pAhciPort, pAhciPortTaskState, &pAhciPortTaskState->cmdFis[0], true);
     6595                            }
     6596
     6597                            uIORequestsProcessed++;
    64886598                        }
    6489 
    6490                         uIORequestsProcessed++;
    64916599                    }
    64926600                }
     
    65006608            }
    65016609
     6610            if (!pAhciPort->fRedo)
     6611            {
    65026612#ifdef DEBUG
    6503             /* Be paranoid. */
    6504             memset(&pAhciPortTaskState->cmdHdr, 0, sizeof(CmdHdr));
    6505             memset(&pAhciPortTaskState->cmdFis, 0, AHCI_CMDFIS_TYPE_H2D_SIZE);
    6506             pAhciPortTaskState->GCPhysCmdHdrAddr = 0;
    6507             pAhciPortTaskState->uOffset = 0;
    6508             pAhciPortTaskState->cbTransfer = 0;
    6509             /* Make the port number invalid making it easier to track down bugs. */
    6510             pAhciPort->ahciIOTasks[pAhciPort->uActReadPos] = 0xff;
     6613                /* Be paranoid. */
     6614                memset(&pAhciPortTaskState->cmdHdr, 0, sizeof(CmdHdr));
     6615                memset(&pAhciPortTaskState->cmdFis, 0, AHCI_CMDFIS_TYPE_H2D_SIZE);
     6616                pAhciPortTaskState->GCPhysCmdHdrAddr = 0;
     6617                pAhciPortTaskState->uOffset = 0;
     6618                pAhciPortTaskState->cbTransfer = 0;
     6619                /* Make the port number invalid making it easier to track down bugs. */
     6620                pAhciPort->ahciIOTasks[pAhciPort->uActReadPos] = 0xff;
    65116621#endif
    65126622
    6513             pAhciPort->uActReadPos++;
    6514             pAhciPort->uActReadPos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
    6515             ahciLog(("%s: After uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
    6516             cTasksToProcess--;
    6517 
    6518             /* If we encountered an error notify the guest and continue with the next task. */
    6519             if (RT_FAILURE(rc))
    6520             {
    6521                 if (uQueuedTasksFinished && RT_LIKELY(!pAhciPort->fPortReset))
    6522                     ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, true);
    6523 
    6524                 uQueuedTasksFinished = 0;
     6623                pAhciPort->uActReadPos++;
     6624                pAhciPort->uActReadPos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
     6625                ahciLog(("%s: After uActReadPos=%u\n", __FUNCTION__, pAhciPort->uActReadPos));
     6626                cTasksToProcess--;
     6627
     6628                /* If we encountered an error notify the guest and continue with the next task. */
     6629                if (RT_FAILURE(rc))
     6630                {
     6631                    if (   ASMAtomicReadU32(&pAhciPort->u32QueuedTasksFinished) != 0
     6632                        && RT_LIKELY(!pAhciPort->fPortReset))
     6633                        ahciSendSDBFis(pAhciPort, 0, true);
     6634                }
     6635                else if (!cTasksToProcess)
     6636                    cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
    65256637            }
    6526             else if (!cTasksToProcess)
    6527                 cTasksToProcess = ASMAtomicXchgU32(&pAhciPort->uActTasksActive, 0);
    65286638        }
    65296639
    6530         if (uQueuedTasksFinished && RT_LIKELY(!pAhciPort->fPortReset))
    6531             ahciSendSDBFis(pAhciPort, uQueuedTasksFinished, true);
    6532 
    6533         uQueuedTasksFinished = 0;
     6640        if (   ASMAtomicReadU32(&pAhciPort->u32QueuedTasksFinished) != 0
     6641            && RT_LIKELY(!pAhciPort->fPortReset)
     6642            && RT_LIKELY(!pAhciPort->fRedo))
     6643            ahciSendSDBFis(pAhciPort, 0, true);
    65346644
    65356645        u64StopTime = RTTimeMilliTS();
     
    65596669    RTMemFree(pAhciPortTaskState);
    65606670
    6561     ahciLog(("%s: Port %d async IO thread exiting rc=%Rrc\n", __FUNCTION__, pAhciPort->iLUN, rc));
    6562     return rc;
     6671    ahciLog(("%s: Port %d async IO thread exiting\n", __FUNCTION__, pAhciPort->iLUN));
     6672    return VINF_SUCCESS;
    65636673}
    65646674
     
    66776787                fFinished = (pThisPort->uActTasksActive == 0);
    66786788            else
    6679                 fFinished = ((pThisPort->uActTasksActive == 0) && (pThisPort->fAsyncIOThreadIdle));
     6789                fFinished = ((pThisPort->uActTasksActive == 0 || pThisPort->fRedo) && (pThisPort->fAsyncIOThreadIdle));
    66806790            if (!fFinished)
    66816791               return false;
     
    69787088            else if (pThis->ahciPort[i].fATAPI)
    69797089                return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: atapi - saved=%false config=true"));
     7090
     7091            if (   pThis->ahciPort[i].uActWritePos != pThis->ahciPort[i].uActReadPos
     7092                && !pThis->ahciPort[i].fAsyncInterface)
     7093            {
     7094                /*
     7095                 * There are tasks pending. The VM was saved after a task failed
     7096                 * because of non-fatal error. Set the redo flag
     7097                 * and the correct cTasksToProcess number based on the difference
     7098                 * of the FIFO counters.
     7099                 */
     7100                PAHCIPort pAhciPort = &pThis->ahciPort[i];
     7101
     7102                pAhciPort->fRedo = true;
     7103                /*
     7104                 * Because we don't save the task FIFO we have to reconstruct it by using the
     7105                 * SACT and CI registers along with the shadowed variables containing the
     7106                 * completed tasks and placing them in the FIFO again.
     7107                 */
     7108                uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished;
     7109                uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
     7110
     7111                pAhciPort->uActWritePos = 0;
     7112                pAhciPort->uActReadPos  = 0;
     7113
     7114                for (unsigned uTag = 0; uTag < AHCI_NR_COMMAND_SLOTS; uTag++)
     7115                {
     7116                    if (   fTasksOutstanding & (1 << uTag)
     7117                        || fQueuedTasksOutstanding & (1 << uTag))
     7118                    {
     7119                        pAhciPort->ahciIOTasks[pAhciPort->uActWritePos] = AHCI_TASK_SET(uTag, (fQueuedTasksOutstanding & (1 << uTag)) ? 1 : 0);
     7120                        pAhciPort->uActWritePos++;
     7121                        pAhciPort->uActWritePos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
     7122                        pAhciPort->cTasksToProcess++;
     7123                    }
     7124                }
     7125            }
    69807126        }
    69817127
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