VirtualBox

Changeset 24101 in vbox


Ignore:
Timestamp:
Oct 27, 2009 12:03:09 AM (15 years ago)
Author:
vboxsync
Message:

DrvSCSI,DevLsiLogic: Moved the reset request sync down to the driver where DevBusLogic can make use of it as well.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/pdmifs.h

    r24098 r24101  
    25612561     DECLR3CALLBACKMEMBER(int, pfnSCSIRequestSend, (PPDMISCSICONNECTOR pInterface, PPDMSCSIREQUEST pSCSIRequest));
    25622562
    2563     /**
    2564      * Wait for all current requests to complete.
    2565      *
    2566      * This can only be called while the VM is running.
    2567      *
    2568      * @returns VINF_SUCCESS, VERR_NO_MEMORY, VERR_INVALID_STATE or VERR_TIMEOUT.
    2569      * @param   pInterface      Pointer to this interface.
    2570      * @param   cMillies        The timeout in milliseconds or RT_INDEFINITE_WAIT.
    2571      */
    2572      DECLR3CALLBACKMEMBER(int, pfnSyncronizeRequests, (PPDMISCSICONNECTOR pInterface, uint32_t cMillies));
    2573 
    25742563} PDMISCSICONNECTOR;
    25752564
  • trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp

    r24099 r24101  
    47814781}
    47824782
    4783 /**
    4784  * Waits until all I/O operations on all devices are complete.
    4785  *
    4786  * @retruns Flag which indicates if all I/O completed in the given timeout.
    4787  * @param   pLsiLogic    Pointer to the dveice instance to check.
    4788  * @param   cMillis      Timeout in milliseconds to wait per device.
    4789  */
    4790 static bool lsilogicWaitForAsyncIOFinished(PLSILOGICSCSI pLsiLogic, unsigned cMillies)
    4791 {
    4792     uint64_t u64Start;
    4793     unsigned i;
    4794 
    4795     /*
    4796      * Wait for any pending async operation to finish
    4797      */
    4798     u64Start = RTTimeMilliTS();
    4799     for (;;)
    4800     {
    4801         /* Check every port. */
    4802         for (i = 0; i < RT_ELEMENTS(pLsiLogic->aDeviceStates); i++)
    4803             if (ASMAtomicReadU32(&pLsiLogic->aDeviceStates[i].cOutstandingRequests))
    4804                 break;
    4805         if (i >= RT_ELEMENTS(pLsiLogic->aDeviceStates))
    4806             return true;
    4807 
    4808         uint64_t cMsElapsed = RTTimeMilliTS() - u64Start;
    4809         if (cMsElapsed >= cMillies)
    4810             return false;
    4811 
    4812         /* Try synchronize the request queue for this device. */
    4813         PPDMISCSICONNECTOR pDrvSCSIConnector = pLsiLogic->aDeviceStates[i].pDrvSCSIConnector;
    4814         uint32_t cMsLeft = cMillies - (uint32_t)cMsElapsed;
    4815         pDrvSCSIConnector->pfnSyncronizeRequests(pDrvSCSIConnector, RT_MAX(cMsLeft, 100));
    4816     }
    4817 }
    4818 
    48194783static DECLCALLBACK(int) lsilogicLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
    48204784{
     
    51595123    PLSILOGICSCSI pLsiLogic = PDMINS_2_DATA(pDevIns, PLSILOGICSCSI);
    51605124    int rc;
    5161 
    5162 /** @todo r=bird: this is a deadlock trap. We're EMT(0), if there are
    5163  *        outstanding requests they may require EMT interaction because of
    5164  *        physical write backs around lsilogicDeviceSCSIRequestCompleted...
    5165  *
    5166  *        I have some more generic solution for delayed suspend, reset and
    5167  *        poweroff handling that I'm considering.  The idea is that the
    5168  *        notification callback returns a status indicating that it didn't
    5169  *        complete and needs to be called again or something.  EMT continues on
    5170  *        the next device and when it's done, it processes incoming requests and
    5171  *        does another notification round... This way we could combine the waits
    5172  *        in the I/O controllers and reduce the time it takes to suspend a VM a
    5173  *        wee bit...
    5174  *
    5175  * DrvSCSI should implement the reset notification, then we could retire this
    5176  * fun lsilogicWaitForAsyncIOFinished code.  (The drivers are reset before the
    5177  * device.)  The deadlock trap is still there though.
    5178  */
    5179     bool fIdle = lsilogicWaitForAsyncIOFinished(pLsiLogic, 20000);
    5180     Assert(fIdle);
    51815125
    51825126    rc = lsilogicHardReset(pLsiLogic);
  • trunk/src/VBox/Devices/Storage/DrvSCSI.cpp

    r24098 r24101  
    8989    /** Queue for passing the requests to the thread. */
    9090    PRTREQQUEUE             pQueueRequests;
     91    /** Request that we've left pending on wakeup or reset. */
     92    PRTREQ                  pPendingDummyReq;
    9193    /** Release statistics: number of bytes written. */
    9294    STAMCOUNTER             StatBytesWritten;
     
    671673
    672674/**
    673  * Request function to syncronize the request execution.
     675 * Dummy request function used by drvscsiReset to wait for all pending requests
     676 * to complete prior to the device reset.
    674677 *
    675678 * @returns VINF_SUCCESS.
     
    716719}
    717720
     721/**
     722 * Deals with any pending dummy request
     723 *
     724 * @returns true if no pending dummy request, false if still pending.
     725 * @param   pThis               The instance data.
     726 * @param   cMillies            The number of milliseconds to wait for any
     727 *                              pending request to finish.
     728 */
     729static bool drvscsiAsyncIOLoopNoPendingDummy(PDRVSCSI pThis, uint32_t cMillies)
     730{
     731    if (!pThis->pPendingDummyReq)
     732        return false;
     733    int rc = RTReqWait(pThis->pPendingDummyReq, cMillies);
     734    if (RT_FAILURE(rc))
     735        return false;
     736    RTReqFree(pThis->pPendingDummyReq);
     737    pThis->pPendingDummyReq = NULL;
     738    return true;
     739}
     740
    718741static int drvscsiAsyncIOLoopWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
    719742{
    720     int rc;
    721743    PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
    722744    PRTREQ pReq;
     745    int rc;
    723746
    724747    AssertMsgReturn(pThis->pQueueRequests, ("pQueueRequests is NULL\n"), VERR_INVALID_STATE);
    725748
     749    if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 10000 /* 10 sec */))
     750    {
     751        LogRel(("drvscsiAsyncIOLoopWakeup#%u: previous dummy request is still pending\n", pDrvIns->iInstance));
     752        return VERR_TIMEOUT;
     753    }
     754
    726755    rc = RTReqCall(pThis->pQueueRequests, &pReq, 10000 /* 10 sec. */, (PFNRT)drvscsiAsyncIOLoopWakeupFunc, 0);
    727     AssertMsgRC(rc, ("Inserting request into queue failed rc=%Rrc\n", rc));
    728756    if (RT_SUCCESS(rc))
    729757        RTReqFree(pReq);
    730     /*else: leak it */
     758    else
     759    {
     760        pThis->pPendingDummyReq = pReq;
     761        LogRel(("drvscsiAsyncIOLoopWakeup#%u: %Rrc pReq=%p\n", pDrvIns->iInstance, rc, pReq));
     762    }
    731763
    732764    return rc;
     
    748780
    749781    return VINF_SUCCESS;
    750 }
    751 
    752 /** @copydoc PDMISCSICONNECTOR::pfnSyncronizeRequests. */
    753 static DECLCALLBACK(int) drvscsiSyncronizeRequests(PPDMISCSICONNECTOR pInterface, uint32_t cMillies)
    754 {
    755     int rc;
    756     PDRVSCSI pThis = PDMISCSICONNECTOR_2_DRVSCSI(pInterface);
    757     PRTREQ pReq;
    758 
    759     Assert(cMillies > 100);
    760     AssertReturn(pThis->pQueueRequests, VERR_INVALID_STATE);
    761 
    762     rc = RTReqCall(pThis->pQueueRequests, &pReq, cMillies, (PFNRT)drvscsiAsyncIOLoopSyncCallback, 0);
    763     AssertMsgRC(rc, ("Inserting request into queue failed rc=%Rrc\n", rc));
    764     if (RT_SUCCESS(rc))
    765         RTReqFree(pReq);
    766     /*else: leak it */
    767 
    768     return rc;
    769782}
    770783
     
    790803
    791804/**
     805 * @copydoc FNPDMDRVRESET
     806 */
     807static DECLCALLBACK(void) drvscsiReset(PPDMDRVINS pDrvIns)
     808{
     809    PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI);
     810    int rc;
     811
     812    /*
     813     * Try make sure any pending I/O has completed now.
     814     */
     815    if (pThis->pQueueRequests)
     816    {
     817        if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 20000 /*ms*/))
     818        {
     819            LogRel(("drvscsiReset#%u: previous dummy request is still pending\n", pDrvIns->iInstance));
     820            return;
     821        }
     822
     823        if (RTReqIsBusy(pThis->pQueueRequests))
     824        {
     825            PRTREQ pReq;
     826            rc = RTReqCall(pThis->pQueueRequests, &pReq, 20000 /*ms*/, (PFNRT)drvscsiAsyncIOLoopSyncCallback, 0);
     827            if (RT_SUCCESS(rc))
     828                RTReqFree(pReq);
     829            else
     830            {
     831                pThis->pPendingDummyReq = pReq;
     832                LogRel(("drvscsiReset#%u: %Rrc pReq=%p\n", pDrvIns->iInstance, rc, pReq));
     833            }
     834        }
     835    }
     836/** @todo r=bird: this is a deadlock trap. We're EMT(0), if there are
     837 *        outstanding requests they may require EMT interaction because of
     838 *        physical write backs around lsilogicDeviceSCSIRequestCompleted...
     839 *
     840 *        I have some more generic solution for delayed suspend, reset and
     841 *        poweroff handling that I'm considering.  The idea is that the
     842 *        notification callback returns a status indicating that it didn't
     843 *        complete and needs to be called again or something.  EMT continues on
     844 *        the next device and when it's done, it processes incoming requests and
     845 *        does another notification round... This way we could combine the waits
     846 *        in the I/O controllers and reduce the time it takes to suspend a VM a
     847 *        wee bit...
     848 */
     849}
     850
     851/**
    792852 * Destruct a driver instance.
    793853 *
     
    826886    pDrvIns->IBase.pfnQueryInterface                    = drvscsiQueryInterface;
    827887    pThis->ISCSIConnector.pfnSCSIRequestSend            = drvscsiRequestSend;
    828     pThis->ISCSIConnector.pfnSyncronizeRequests         = drvscsiSyncronizeRequests;
    829888
    830889    /*
     
    929988    NULL,
    930989    /* pfnReset */
    931     NULL,
     990    drvscsiReset,
    932991    /* pfnSuspend */
    933992    NULL,
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