/** * Destruct a driver instance. * * Most VM resources are freed by the VM. This callback is provided so that any non-VM * resources can be freed correctly. * * @param pDrvIns The driver instance data. */ static DECLCALLBACK(void) drvscsiDestruct(PPDMDRVINS pDrvIns) { PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI); PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); if (pThis->hQueueRequests != NIL_RTREQQUEUE) { if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 100 /*ms*/)) LogRel(("drvscsiDestruct#%u: previous dummy request is still pending\n", pDrvIns->iInstance)); int rc = RTReqQueueDestroy(pThis->hQueueRequests); AssertMsgRC(rc, ("Failed to destroy queue rc=%Rrc\n", rc)); pThis->hQueueRequests = NIL_RTREQQUEUE; } /* Free the VSCSI device and LUN handle. */ if (pThis->hVScsiDevice) { VSCSILUN hVScsiLun; int rc = VSCSIDeviceLunDetach(pThis->hVScsiDevice, 0, &hVScsiLun); AssertRC(rc); Assert(hVScsiLun == pThis->hVScsiLun); rc = VSCSILunDestroy(hVScsiLun); AssertRC(rc); rc = VSCSIDeviceDestroy(pThis->hVScsiDevice); AssertRC(rc); pThis->hVScsiDevice = NULL; pThis->hVScsiLun = NULL; } }
static int drvscsiAsyncIOLoopWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) { PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI); PRTREQ pReq; int rc; AssertMsgReturn(pThis->hQueueRequests != NIL_RTREQQUEUE, ("hQueueRequests is NULL\n"), VERR_INVALID_STATE); if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 10000 /* 10 sec */)) { LogRel(("drvscsiAsyncIOLoopWakeup#%u: previous dummy request is still pending\n", pDrvIns->iInstance)); return VERR_TIMEOUT; } rc = RTReqQueueCall(pThis->hQueueRequests, &pReq, 10000 /* 10 sec. */, (PFNRT)drvscsiAsyncIOLoopWakeupFunc, 1, pThis); if (RT_SUCCESS(rc)) RTReqRelease(pReq); else { pThis->pPendingDummyReq = pReq; LogRel(("drvscsiAsyncIOLoopWakeup#%u: %Rrc pReq=%p\n", pDrvIns->iInstance, rc, pReq)); } return rc; }
/** * Callback employed by drvscsiReset. * * @returns true if we've quiesced, false if we're still working. * @param pDrvIns The driver instance. */ static DECLCALLBACK(bool) drvscsiIsAsyncResetDone(PPDMDRVINS pDrvIns) { PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI); if (pThis->pDrvBlockAsync) { if (pThis->StatIoDepth > 0) return false; else return true; } else { if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 0 /*ms*/)) return false; ASMAtomicWriteBool(&pThis->fDummySignal, false); return true; } }
/** * Callback employed by drvscsiSuspend and drvscsiPowerOff. * * @returns true if we've quiesced, false if we're still working. * @param pDrvIns The driver instance. */ static DECLCALLBACK(bool) drvscsiIsAsyncSuspendOrPowerOffDone(PPDMDRVINS pDrvIns) { PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI); if (pThis->pDrvMediaAsync) { if (pThis->StatIoDepth > 0) return false; else return true; } else { if (!drvscsiAsyncIOLoopNoPendingDummy(pThis, 0 /*ms*/)) return false; ASMAtomicWriteBool(&pThis->fDummySignal, false); PDMR3ThreadSuspend(pThis->pAsyncIOThread); return true; } }
/** * Worker for drvscsiReset, drvscsiSuspend and drvscsiPowerOff. * * @param pDrvIns The driver instance. * @param pfnAsyncNotify The async callback. */ static void drvscsiR3ResetOrSuspendOrPowerOff(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify) { PDRVSCSI pThis = PDMINS_2_DATA(pDrvIns, PDRVSCSI); if (!pThis->pDrvBlockAsync) { if (pThis->hQueueRequests != NIL_RTREQQUEUE) return; ASMAtomicWriteBool(&pThis->fDummySignal, true); if (drvscsiAsyncIOLoopNoPendingDummy(pThis, 0 /*ms*/)) { if (!RTReqQueueIsBusy(pThis->hQueueRequests)) { ASMAtomicWriteBool(&pThis->fDummySignal, false); return; } PRTREQ pReq; int rc = RTReqQueueCall(pThis->hQueueRequests, &pReq, 0 /*ms*/, (PFNRT)drvscsiAsyncIOLoopSyncCallback, 1, pThis); if (RT_SUCCESS(rc)) { ASMAtomicWriteBool(&pThis->fDummySignal, false); RTReqRelease(pReq); return; } pThis->pPendingDummyReq = pReq; } } else { if (pThis->StatIoDepth > 0) { ASMAtomicWriteBool(&pThis->fDummySignal, true); } return; } PDMDrvHlpSetAsyncNotification(pDrvIns, pfnAsyncNotify); }