VirtualBox

Changeset 33175 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Oct 16, 2010 6:32:23 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
66711
Message:

AHCI: Implement suspend on error for the async I/O path

File:
1 edited

Legend:

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

    r33125 r33175  
    55845584#define PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface)    ( (PAHCIPort)((uintptr_t)pInterface - RT_OFFSETOF(AHCIPort, IPortAsync)) )
    55855585
     5586static void ahciWarningDiskFull(PPDMDEVINS pDevIns)
     5587{
     5588    int rc;
     5589    LogRel(("AHCI: Host disk full\n"));
     5590    rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_DISKFULL",
     5591                                    N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
     5592    AssertRC(rc);
     5593}
     5594
     5595static void ahciWarningFileTooBig(PPDMDEVINS pDevIns)
     5596{
     5597    int rc;
     5598    LogRel(("AHCI: File too big\n"));
     5599    rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_FILETOOBIG",
     5600                                    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"));
     5601    AssertRC(rc);
     5602}
     5603
     5604static void ahciWarningISCSI(PPDMDEVINS pDevIns)
     5605{
     5606    int rc;
     5607    LogRel(("AHCI: iSCSI target unavailable\n"));
     5608    rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_ISCSIDOWN",
     5609                                    N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
     5610    AssertRC(rc);
     5611}
     5612
     5613bool ahciIsRedoSetWarning(PAHCIPort pAhciPort, int rc)
     5614{
     5615    if (rc == VERR_DISK_FULL)
     5616    {
     5617        if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
     5618            ahciWarningDiskFull(pAhciPort->CTX_SUFF(pDevIns));
     5619        return true;
     5620    }
     5621    if (rc == VERR_FILE_TOO_BIG)
     5622    {
     5623        if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
     5624            ahciWarningFileTooBig(pAhciPort->CTX_SUFF(pDevIns));
     5625        return true;
     5626    }
     5627    if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
     5628    {
     5629        /* iSCSI connection abort (first error) or failure to reestablish
     5630         * connection (second error). Pause VM. On resume we'll retry. */
     5631        if (ASMAtomicCmpXchgBool(&pAhciPort->fRedo, true, false))
     5632            ahciWarningISCSI(pAhciPort->CTX_SUFF(pDevIns));
     5633        return true;
     5634    }
     5635    return false;
     5636}
     5637
    55865638/**
    55875639 * Complete a data transfer task by freeing all occupied ressources
     
    55965648static int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, int rcReq)
    55975649{
     5650    bool fRedo = false;
     5651
    55985652    /* Free system resources occupied by the scatter gather list. */
    55995653    if (pAhciPortTaskState->enmTxDir != AHCITXDIR_FLUSH)
    56005654        ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
    56015655
     5656    if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)
     5657    {
     5658        STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciPortTaskState->cbTransfer);
     5659        pAhciPort->Led.Actual.s.fReading = 0;
     5660    }
     5661    else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
     5662    {
     5663        STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciPortTaskState->cbTransfer);
     5664        pAhciPort->Led.Actual.s.fWriting = 0;
     5665    }
     5666
    56025667    if (RT_FAILURE(rcReq))
    56035668    {
    5604         pAhciPortTaskState->cmdHdr.u32PRDBC = 0;
    5605         pAhciPortTaskState->uATARegError = ID_ERR;
    5606         pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
    5607 
    56085669        /* Log the error. */
    56095670        if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
     
    56215682                        pAhciPortTaskState->cbTransfer, rcReq));
    56225683        }
    5623         ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciPortTaskState, NULL);
     5684
     5685        fRedo = ahciIsRedoSetWarning(pAhciPort, rcReq);
     5686        if (!fRedo)
     5687        {
     5688            pAhciPortTaskState->cmdHdr.u32PRDBC = 0;
     5689            pAhciPortTaskState->uATARegError = ID_ERR;
     5690            pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
     5691            ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciPortTaskState, NULL);
     5692        }
    56245693    }
    56255694    else
     
    56355704    }
    56365705
    5637     if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)
    5638     {
    5639         STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciPortTaskState->cbTransfer);
    5640         pAhciPort->Led.Actual.s.fReading = 0;
    5641     }
    5642     else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
    5643     {
    5644         STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciPortTaskState->cbTransfer);
    5645         pAhciPort->Led.Actual.s.fWriting = 0;
    5646     }
    5647 
    5648     if (pAhciPortTaskState->fQueued)
    5649     {
    5650         uint32_t cOutstandingTasks;
    5651 
    5652         ahciLog(("%s: Before decrement uActTasksActive=%u\n", __FUNCTION__, pAhciPort->uActTasksActive));
    5653         cOutstandingTasks = ASMAtomicDecU32(&pAhciPort->uActTasksActive);
    5654         ahciLog(("%s: After decrement uActTasksActive=%u\n", __FUNCTION__, cOutstandingTasks));
    5655         if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIPORTTASKSTATE))
    5656             ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
    5657 
    56585706#ifdef RT_STRICT
    5659         bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
    5660         AssertMsg(fXchg, ("Task is not active\n"));
     5707    bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
     5708    AssertMsg(fXchg, ("Task is not active\n"));
    56615709#endif
    56625710
    5663         /* Always raise an interrupt after task completion; delaying
    5664          * this (interrupt coalescing) increases latency and has a significant
    5665          * impact on performance (see #5071)
    5666          */
    5667         ahciSendSDBFis(pAhciPort, 0, true);
    5668     }
    5669     else
    5670     {
    5671 #ifdef RT_STRICT
    5672         bool fXchg = ASMAtomicCmpXchgBool(&pAhciPortTaskState->fActive, false, true);
    5673         AssertMsg(fXchg, ("Task is not active\n"));
    5674 #endif
    5675 
    5676         ASMAtomicDecU32(&pAhciPort->uActTasksActive);
    5677         ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
    5678     }
    5679 
    56805711    /* Add the task to the cache. */
    5681     pAhciPort->aCachedTasks[pAhciPortTaskState->uTag] = pAhciPortTaskState;
     5712    ASMAtomicWritePtr(&pAhciPort->aCachedTasks[pAhciPortTaskState->uTag], pAhciPortTaskState);
     5713    ASMAtomicDecU32(&pAhciPort->uActTasksActive);
     5714
     5715    if (!fRedo)
     5716    {
     5717        if (pAhciPortTaskState->fQueued)
     5718        {
     5719            if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIPORTTASKSTATE))
     5720                ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
     5721
     5722            /*
     5723             * Always raise an interrupt after task completion; delaying
     5724             * this (interrupt coalescing) increases latency and has a significant
     5725             * impact on performance (see #5071)
     5726             */
     5727            ahciSendSDBFis(pAhciPort, 0, true);
     5728        }
     5729        else
     5730            ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
     5731    }
    56825732
    56835733    return VINF_SUCCESS;
     
    57055755        PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
    57065756    return rc;
    5707 }
    5708 
    5709 static void ahciWarningDiskFull(PPDMDEVINS pDevIns)
    5710 {
    5711     int rc;
    5712     LogRel(("AHCI: Host disk full\n"));
    5713     rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_DISKFULL",
    5714                                     N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
    5715     AssertRC(rc);
    5716 }
    5717 
    5718 static void ahciWarningFileTooBig(PPDMDEVINS pDevIns)
    5719 {
    5720     int rc;
    5721     LogRel(("AHCI: File too big\n"));
    5722     rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_FILETOOBIG",
    5723                                     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"));
    5724     AssertRC(rc);
    5725 }
    5726 
    5727 static void ahciWarningISCSI(PPDMDEVINS pDevIns)
    5728 {
    5729     int rc;
    5730     LogRel(("AHCI: iSCSI target unavailable\n"));
    5731     rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevAHCI_ISCSIDOWN",
    5732                                     N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
    5733     AssertRC(rc);
    5734 }
    5735 
    5736 bool ahciIsRedoSetWarning(PAHCIPort pAhciPort, int rc)
    5737 {
    5738     if (rc == VERR_DISK_FULL)
    5739     {
    5740         ahciWarningDiskFull(pAhciPort->CTX_SUFF(pDevIns));
    5741         return true;
    5742     }
    5743     if (rc == VERR_FILE_TOO_BIG)
    5744     {
    5745         ahciWarningFileTooBig(pAhciPort->CTX_SUFF(pDevIns));
    5746         return true;
    5747     }
    5748     if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
    5749     {
    5750         /* iSCSI connection abort (first error) or failure to reestablish
    5751          * connection (second error). Pause VM. On resume we'll retry. */
    5752         ahciWarningISCSI(pAhciPort->CTX_SUFF(pDevIns));
    5753         return true;
    5754     }
    5755     return false;
    57565757}
    57575758
     
    65086509                        }
    65096510                        else
    6510                         {
    6511                             pAhciPort->fRedo = true;
    65126511                            pAhciPort->cTasksToProcess = cTasksToProcess;
    6513                         }
    65146512                    }
    65156513                    else
     
    70947092        for (uint32_t i = 0; i < AHCI_MAX_NR_PORTS_IMPL; i++)
    70957093        {
     7094            PAHCIPort pAhciPort = &pThis->ahciPort[i];
     7095
    70967096            SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLB);
    70977097            SSMR3GetU32(pSSM, &pThis->ahciPort[i].regCLBU);
     
    71387138                return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch: atapi - saved=%false config=true"));
    71397139
    7140             if (   pThis->ahciPort[i].uActWritePos != pThis->ahciPort[i].uActReadPos
    7141                 && !pThis->ahciPort[i].fAsyncInterface)
     7140            /* Check if we have tasks pending. */
     7141            uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished;
     7142            uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
     7143
     7144            if (fTasksOutstanding || fQueuedTasksOutstanding)
    71427145            {
    71437146                /*
     
    71477150                 * of the FIFO counters.
    71487151                 */
    7149                 PAHCIPort pAhciPort = &pThis->ahciPort[i];
    7150 
    7151                 pAhciPort->fRedo = true;
    7152                 /*
    7153                  * Because we don't save the task FIFO we have to reconstruct it by using the
    7154                  * SACT and CI registers along with the shadowed variables containing the
    7155                  * completed tasks and placing them in the FIFO again.
    7156                  */
    7157                 uint32_t fTasksOutstanding = pAhciPort->regCI & ~pAhciPort->u32TasksFinished;
    7158                 uint32_t fQueuedTasksOutstanding = pAhciPort->regSACT & ~pAhciPort->u32QueuedTasksFinished;
    7159 
    7160                 pAhciPort->uActWritePos = 0;
    7161                 pAhciPort->uActReadPos  = 0;
    7162 
    7163                 for (unsigned uTag = 0; uTag < AHCI_NR_COMMAND_SLOTS; uTag++)
     7152
     7153                if (!pAhciPort->fAsyncInterface)
    71647154                {
    7165                     if (   fTasksOutstanding & (1 << uTag)
    7166                         || fQueuedTasksOutstanding & (1 << uTag))
     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++)
    71677166                    {
    7168                         pAhciPort->ahciIOTasks[pAhciPort->uActWritePos] = AHCI_TASK_SET(uTag, (fQueuedTasksOutstanding & (1 << uTag)) ? 1 : 0);
    7169                         pAhciPort->uActWritePos++;
    7170                         pAhciPort->uActWritePos %= RT_ELEMENTS(pAhciPort->ahciIOTasks);
    7171                         pAhciPort->cTasksToProcess++;
     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                        }
    71727193                    }
    71737194                }
     
    75467567{
    75477568    PAHCI    pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
     7569
     7570    /*
     7571     * Check if one of the ports has the redo flag set
     7572     * and queue all pending tasks again.
     7573     */
     7574    for (unsigned i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
     7575    {
     7576        PAHCIPort pAhciPort = &pAhci->ahciPort[i];
     7577
     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
     7584            pAhciPort->fRedo = false;
     7585
     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            }
     7601        }
     7602    }
    75487603
    75497604    Log(("%s:\n", __FUNCTION__));
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