Index: trunk/src/VBox/Devices/Storage/DevAHCI.cpp
===================================================================
--- trunk/src/VBox/Devices/Storage/DevAHCI.cpp	(revision 24757)
+++ trunk/src/VBox/Devices/Storage/DevAHCI.cpp	(revision 24760)
@@ -2269,5 +2269,5 @@
 #ifdef IN_RING3
 
-static DECLCALLBACK(int) ahciMMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) ahciR3MMIOMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
 {
     PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
@@ -2309,5 +2309,5 @@
  * Map the legacy I/O port ranges to make Solaris work with the controller.
  */
-static DECLCALLBACK(int) ahciLegacyFakeIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
+static DECLCALLBACK(int) ahciR3LegacyFakeIORangeMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
 {
     PAHCI pThis = PCIDEV_2_PAHCI(pPciDev);
@@ -2354,5 +2354,5 @@
  * @param   ppLed           Where to store the LED pointer.
  */
-static DECLCALLBACK(int) ahciStatus_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
+static DECLCALLBACK(int) ahciR3Status_QueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
 {
     PAHCI pAhci = PDMILEDPORTS_2_PAHCI(pInterface);
@@ -2374,5 +2374,5 @@
  * @param   enmInterface        The requested interface identification.
  */
-static DECLCALLBACK(void *) ahciStatus_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
+static DECLCALLBACK(void *) ahciR3Status_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
 {
     PAHCI pAhci = PDMIBASE_2_PAHCI(pInterface);
@@ -2391,5 +2391,5 @@
  * Query interface method for the AHCI port.
  */
-static DECLCALLBACK(void *) ahciPortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
+static DECLCALLBACK(void *) ahciR3PortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
 {
     PAHCIPort pAhciPort = PDMIBASE_2_PAHCIPORT(pInterface);
@@ -2407,26 +2407,4 @@
             return NULL;
     }
-}
-
-static DECLCALLBACK(void) ahciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
-{
-    uint32_t i;
-    PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
-
-    pAhci->pDevInsRC += offDelta;
-    pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
-    pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
-
-    /* Relocate every port. */
-    for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
-    {
-        PAHCIPort pAhciPort = &pAhci->ahciPort[i];
-        pAhciPort->pAhciRC += offDelta;
-        pAhciPort->pDevInsRC += offDelta;
-    }
-
-    /* Relocate emulated ATA controllers. */
-    for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
-        ataControllerRelocate(&pAhci->aCts[i], offDelta);
 }
 
@@ -5722,170 +5700,11 @@
 }
 
-/**
- * Destroy a driver instance.
+/* -=-=-=-=- Helper -=-=-=-=- */
+
+/**
+ * Checks if all asynchronous I/O is finished.
  *
- * Most VM resources are freed by the VM. This callback is provided so that any non-VM
- * resources can be freed correctly.
- *
- * @param   pDevIns     The device instance data.
- */
-static DECLCALLBACK(int) ahciDestruct(PPDMDEVINS pDevIns)
-{
-    PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
-    int rc = VINF_SUCCESS;
-    unsigned iActPort = 0;
-
-    /*
-     * At this point the async I/O thread is suspended and will not enter
-     * this module again. So, no coordination is needed here and PDM
-     * will take care of terminating and cleaning up the thread.
-     */
-    if (PDMCritSectIsInitialized(&pAhci->lock))
-    {
-        TMR3TimerDestroy(pAhci->CTX_SUFF(pHbaCccTimer));
-
-        Log(("%s: Destruct every port\n", __FUNCTION__));
-        for (iActPort = 0; iActPort < pAhci->cPortsImpl; iActPort++)
-        {
-            PAHCIPort pAhciPort = &pAhci->ahciPort[iActPort];
-
-            if (pAhciPort->pAsyncIOThread)
-            {
-                /* Destroy the event semaphore. */
-                rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
-                if (RT_FAILURE(rc))
-                {
-                    Log(("%s: Destroying event semaphore for port %d failed rc=%Rrc\n", __FUNCTION__, iActPort, rc));
-                }
-            }
-
-            /* Free all cached tasks. */
-            for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
-            {
-                if (pAhciPort->aCachedTasks[i])
-                {
-                    if (pAhciPort->aCachedTasks[i]->pSGListHead)
-                        RTMemFree(pAhciPort->aCachedTasks[i]->pSGListHead);
-                    if (pAhciPort->aCachedTasks[i]->paSGEntries)
-                        RTMemFree(pAhciPort->aCachedTasks[i]->paSGEntries);
-
-                    RTMemFree(pAhciPort->aCachedTasks[i]);
-                }
-            }
-        }
-
-        /* Destroy emulated ATA controllers. */
-        for (unsigned i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
-            ataControllerDestroy(&pAhci->aCts[i]);
-
-        PDMR3CritSectDelete(&pAhci->lock);
-    }
-
-    return rc;
-}
-
-/**
- * Configure the attached device for a port.
- *
- * @returns VBox status code
- * @param   pDevIns     The device instance data.
- * @param   pAhciPort   The port for which the device is to be configured.
- */
-static int ahciConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
-{
-    int          rc = VINF_SUCCESS;
-    PDMBLOCKTYPE enmType;
-
-    /*
-     * Query the block and blockbios interfaces.
-     */
-    pAhciPort->pDrvBlock = (PDMIBLOCK *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK);
-    if (!pAhciPort->pDrvBlock)
-    {
-        AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
-        return VERR_PDM_MISSING_INTERFACE;
-    }
-    pAhciPort->pDrvBlockBios = (PDMIBLOCKBIOS *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_BIOS);
-    if (!pAhciPort->pDrvBlockBios)
-    {
-        AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pAhciPort->iLUN));
-        return VERR_PDM_MISSING_INTERFACE;
-    }
-
-    pAhciPort->pDrvMount = (PDMIMOUNT *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_MOUNT);
-
-    /* Try to get the optional async block interface. */
-    pAhciPort->pDrvBlockAsync = (PDMIBLOCKASYNC *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_ASYNC);
-
-    /*
-     * Validate type.
-     */
-    enmType = pAhciPort->pDrvBlock->pfnGetType(pAhciPort->pDrvBlock);
-
-    if (   enmType != PDMBLOCKTYPE_HARD_DISK
-        && enmType != PDMBLOCKTYPE_CDROM
-        && enmType != PDMBLOCKTYPE_DVD)
-    {
-        AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
-        return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
-    }
-
-    if (   (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD)
-        && !pAhciPort->pDrvMount)
-    {
-        AssertMsgFailed(("Internal error: CD/DVD-ROM without a mountable interface\n"));
-        return VERR_INTERNAL_ERROR;
-    }
-    pAhciPort->fATAPI = (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD);
-
-    if (pAhciPort->fATAPI)
-    {
-        pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
-        pAhciPort->PCHSGeometry.cCylinders = 0;
-        pAhciPort->PCHSGeometry.cHeads     = 0;
-        pAhciPort->PCHSGeometry.cSectors   = 0;
-        LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
-    }
-    else
-    {
-        pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
-        rc = pAhciPort->pDrvBlockBios->pfnGetPCHSGeometry(pAhciPort->pDrvBlockBios,
-                                                          &pAhciPort->PCHSGeometry);
-        if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
-        {
-            pAhciPort->PCHSGeometry.cCylinders = 0;
-            pAhciPort->PCHSGeometry.cHeads     = 16; /*??*/
-            pAhciPort->PCHSGeometry.cSectors   = 63; /*??*/
-        }
-        else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
-        {
-            pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
-            rc = VINF_SUCCESS;
-        }
-        AssertRC(rc);
-
-        if (   pAhciPort->PCHSGeometry.cCylinders == 0
-            || pAhciPort->PCHSGeometry.cHeads == 0
-            || pAhciPort->PCHSGeometry.cSectors == 0)
-        {
-            uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
-            pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
-            pAhciPort->PCHSGeometry.cHeads = 16;
-            pAhciPort->PCHSGeometry.cSectors = 63;
-            /* Set the disk geometry information. Ignore errors. */
-            pAhciPort->pDrvBlockBios->pfnSetPCHSGeometry(pAhciPort->pDrvBlockBios,
-                                                         &pAhciPort->PCHSGeometry);
-            rc = VINF_SUCCESS;
-        }
-        LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
-                 pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
-                 pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
-                 pAhciPort->cTotalSectors));
-    }
-    return rc;
-}
-
-/**
- * Checks if all asynchronous I/O is finished.
+ * Used by ahciR3Reset, ahciR3Suspend and ahciR3PowerOff. ahciR3SavePrep makes
+ * use of it in strict builds (which is why it's up here).
  *
  * @returns true if quiesced, false if busy.
@@ -5913,5 +5732,10 @@
 }
 
-static DECLCALLBACK(int) ahciSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
+/* -=-=-=-=- Saved State -=-=-=-=- */
+
+/**
+ * @copydoc FNDEVSSMSAVEPREP
+ */
+static DECLCALLBACK(int) ahciR3SavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
 {
     PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
@@ -5931,5 +5755,8 @@
 }
 
-static DECLCALLBACK(int) ahciLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
+/**
+ * @copydoc FNDEVSSMLOADPREP
+ */
+static DECLCALLBACK(int) ahciR3LoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
 {
     PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
@@ -5948,69 +5775,7 @@
 
 /**
- * Callback employed by ahciSuspend and ahciPowerOff..
- *
- * @returns true if we've quiesced, false if we're still working.
- * @param   pDevIns     The device instance.
- */
-static DECLCALLBACK(bool) ahciR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
-{
-    if (!ahciR3AllAsyncIOIsFinished(pDevIns))
-        return false;
-
-    PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
-    ASMAtomicWriteBool(&pThis->fSignalIdle, false);
-    return true;
-}
-
-/**
- * Common worker for ahciSuspend and ahciPowerOff.
- */
-static void ahciR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
-{
-    PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
-
-    ASMAtomicWriteBool(&pThis->fSignalIdle, true);
-    if (!ahciR3AllAsyncIOIsFinished(pDevIns))
-        PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncSuspendOrPowerOffDone);
-    else
-        ASMAtomicWriteBool(&pThis->fSignalIdle, false);
-}
-
-/**
- * Suspend notification.
- *
- * @returns VBox status.
- * @param   pDevIns     The device instance data.
- */
-static DECLCALLBACK(void) ahciSuspend(PPDMDEVINS pDevIns)
-{
-    PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
-    Log(("%s:\n", __FUNCTION__));
-
-    ahciR3SuspendOrPowerOff(pDevIns);
-
-    for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
-        ataControllerSuspend(&pAhci->aCts[i]);
-}
-
-/**
- * Resume notification.
- *
- * @param   pDevIns     The device instance data.
- */
-static DECLCALLBACK(void) ahciResume(PPDMDEVINS pDevIns)
-{
-    PAHCI    pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
-
-    Log(("%s:\n", __FUNCTION__));
-    for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
-        ataControllerResume(&pAhci->aCts[i]);
-    return;
-}
-
-/**
  * @copydoc FNDEVSSMLIVEEXEC
  */
-static DECLCALLBACK(int) ahciLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
+static DECLCALLBACK(int) ahciR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
 {
     PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
@@ -6041,5 +5806,5 @@
  * @copydoc FNDEVSSMSAVEEXEC
  */
-static DECLCALLBACK(int) ahciSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
+static DECLCALLBACK(int) ahciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
 {
     PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
@@ -6050,5 +5815,5 @@
 
     /* The config */
-    rc = ahciLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
+    rc = ahciR3LiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
     AssertRCReturn(rc, rc);
 
@@ -6128,5 +5893,5 @@
  * @param   uPass           The data pass.
  */
-static DECLCALLBACK(int) ahciLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
+static DECLCALLBACK(int) ahciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
 {
     PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
@@ -6280,4 +6045,256 @@
 }
 
+/* -=-=-=-=- device PDM interface -=-=-=-=- */
+
+static DECLCALLBACK(void) ahciR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
+{
+    uint32_t i;
+    PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
+
+    pAhci->pDevInsRC += offDelta;
+    pAhci->pHbaCccTimerRC = TMTimerRCPtr(pAhci->pHbaCccTimerR3);
+    pAhci->pNotifierQueueRC = PDMQueueRCPtr(pAhci->pNotifierQueueR3);
+
+    /* Relocate every port. */
+    for (i = 0; i < RT_ELEMENTS(pAhci->ahciPort); i++)
+    {
+        PAHCIPort pAhciPort = &pAhci->ahciPort[i];
+        pAhciPort->pAhciRC += offDelta;
+        pAhciPort->pDevInsRC += offDelta;
+    }
+
+    /* Relocate emulated ATA controllers. */
+    for (i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
+        ataControllerRelocate(&pAhci->aCts[i], offDelta);
+}
+
+/**
+ * Destroy 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   pDevIns     The device instance data.
+ */
+static DECLCALLBACK(int) ahciR3Destruct(PPDMDEVINS pDevIns)
+{
+    PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
+    int rc = VINF_SUCCESS;
+    unsigned iActPort = 0;
+
+    /*
+     * At this point the async I/O thread is suspended and will not enter
+     * this module again. So, no coordination is needed here and PDM
+     * will take care of terminating and cleaning up the thread.
+     */
+    if (PDMCritSectIsInitialized(&pAhci->lock))
+    {
+        TMR3TimerDestroy(pAhci->CTX_SUFF(pHbaCccTimer));
+
+        Log(("%s: Destruct every port\n", __FUNCTION__));
+        for (iActPort = 0; iActPort < pAhci->cPortsImpl; iActPort++)
+        {
+            PAHCIPort pAhciPort = &pAhci->ahciPort[iActPort];
+
+            if (pAhciPort->pAsyncIOThread)
+            {
+                /* Destroy the event semaphore. */
+                rc = RTSemEventDestroy(pAhciPort->AsyncIORequestSem);
+                if (RT_FAILURE(rc))
+                {
+                    Log(("%s: Destroying event semaphore for port %d failed rc=%Rrc\n", __FUNCTION__, iActPort, rc));
+                }
+            }
+
+            /* Free all cached tasks. */
+            for (uint32_t i = 0; i < AHCI_NR_COMMAND_SLOTS; i++)
+            {
+                if (pAhciPort->aCachedTasks[i])
+                {
+                    if (pAhciPort->aCachedTasks[i]->pSGListHead)
+                        RTMemFree(pAhciPort->aCachedTasks[i]->pSGListHead);
+                    if (pAhciPort->aCachedTasks[i]->paSGEntries)
+                        RTMemFree(pAhciPort->aCachedTasks[i]->paSGEntries);
+
+                    RTMemFree(pAhciPort->aCachedTasks[i]);
+                }
+            }
+        }
+
+        /* Destroy emulated ATA controllers. */
+        for (unsigned i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
+            ataControllerDestroy(&pAhci->aCts[i]);
+
+        PDMR3CritSectDelete(&pAhci->lock);
+    }
+
+    return rc;
+}
+
+/**
+ * Configure the attached device for a port.
+ *
+ * Used by ahciR3Construct and ahciR3Attach.
+ *
+ * @returns VBox status code
+ * @param   pDevIns     The device instance data.
+ * @param   pAhciPort   The port for which the device is to be configured.
+ */
+static int ahciR3ConfigureLUN(PPDMDEVINS pDevIns, PAHCIPort pAhciPort)
+{
+    int          rc = VINF_SUCCESS;
+    PDMBLOCKTYPE enmType;
+
+    /*
+     * Query the block and blockbios interfaces.
+     */
+    pAhciPort->pDrvBlock = (PDMIBLOCK *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK);
+    if (!pAhciPort->pDrvBlock)
+    {
+        AssertMsgFailed(("Configuration error: LUN#%d hasn't a block interface!\n", pAhciPort->iLUN));
+        return VERR_PDM_MISSING_INTERFACE;
+    }
+    pAhciPort->pDrvBlockBios = (PDMIBLOCKBIOS *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_BIOS);
+    if (!pAhciPort->pDrvBlockBios)
+    {
+        AssertMsgFailed(("Configuration error: LUN#%d hasn't a block BIOS interface!\n", pAhciPort->iLUN));
+        return VERR_PDM_MISSING_INTERFACE;
+    }
+
+    pAhciPort->pDrvMount = (PDMIMOUNT *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_MOUNT);
+
+    /* Try to get the optional async block interface. */
+    pAhciPort->pDrvBlockAsync = (PDMIBLOCKASYNC *)pAhciPort->pDrvBase->pfnQueryInterface(pAhciPort->pDrvBase, PDMINTERFACE_BLOCK_ASYNC);
+
+    /*
+     * Validate type.
+     */
+    enmType = pAhciPort->pDrvBlock->pfnGetType(pAhciPort->pDrvBlock);
+
+    if (   enmType != PDMBLOCKTYPE_HARD_DISK
+        && enmType != PDMBLOCKTYPE_CDROM
+        && enmType != PDMBLOCKTYPE_DVD)
+    {
+        AssertMsgFailed(("Configuration error: LUN#%d isn't a disk or cd/dvd. enmType=%d\n", pAhciPort->iLUN, enmType));
+        return VERR_PDM_UNSUPPORTED_BLOCK_TYPE;
+    }
+
+    if (   (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD)
+        && !pAhciPort->pDrvMount)
+    {
+        AssertMsgFailed(("Internal error: CD/DVD-ROM without a mountable interface\n"));
+        return VERR_INTERNAL_ERROR;
+    }
+    pAhciPort->fATAPI = (enmType == PDMBLOCKTYPE_CDROM || enmType == PDMBLOCKTYPE_DVD);
+
+    if (pAhciPort->fATAPI)
+    {
+        pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 2048;
+        pAhciPort->PCHSGeometry.cCylinders = 0;
+        pAhciPort->PCHSGeometry.cHeads     = 0;
+        pAhciPort->PCHSGeometry.cSectors   = 0;
+        LogRel(("AHCI LUN#%d: CD/DVD, total number of sectors %Ld\n", pAhciPort->iLUN, pAhciPort->cTotalSectors));
+    }
+    else
+    {
+        pAhciPort->cTotalSectors = pAhciPort->pDrvBlock->pfnGetSize(pAhciPort->pDrvBlock) / 512;
+        rc = pAhciPort->pDrvBlockBios->pfnGetPCHSGeometry(pAhciPort->pDrvBlockBios,
+                                                          &pAhciPort->PCHSGeometry);
+        if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
+        {
+            pAhciPort->PCHSGeometry.cCylinders = 0;
+            pAhciPort->PCHSGeometry.cHeads     = 16; /*??*/
+            pAhciPort->PCHSGeometry.cSectors   = 63; /*??*/
+        }
+        else if (rc == VERR_PDM_GEOMETRY_NOT_SET)
+        {
+            pAhciPort->PCHSGeometry.cCylinders = 0; /* autodetect marker */
+            rc = VINF_SUCCESS;
+        }
+        AssertRC(rc);
+
+        if (   pAhciPort->PCHSGeometry.cCylinders == 0
+            || pAhciPort->PCHSGeometry.cHeads == 0
+            || pAhciPort->PCHSGeometry.cSectors == 0)
+        {
+            uint64_t cCylinders = pAhciPort->cTotalSectors / (16 * 63);
+            pAhciPort->PCHSGeometry.cCylinders = RT_MAX(RT_MIN(cCylinders, 16383), 1);
+            pAhciPort->PCHSGeometry.cHeads = 16;
+            pAhciPort->PCHSGeometry.cSectors = 63;
+            /* Set the disk geometry information. Ignore errors. */
+            pAhciPort->pDrvBlockBios->pfnSetPCHSGeometry(pAhciPort->pDrvBlockBios,
+                                                         &pAhciPort->PCHSGeometry);
+            rc = VINF_SUCCESS;
+        }
+        LogRel(("AHCI: LUN#%d: disk, PCHS=%u/%u/%u, total number of sectors %Ld\n",
+                 pAhciPort->iLUN, pAhciPort->PCHSGeometry.cCylinders,
+                 pAhciPort->PCHSGeometry.cHeads, pAhciPort->PCHSGeometry.cSectors,
+                 pAhciPort->cTotalSectors));
+    }
+    return rc;
+}
+
+/**
+ * Callback employed by ahciR3Suspend and ahciR3PowerOff..
+ *
+ * @returns true if we've quiesced, false if we're still working.
+ * @param   pDevIns     The device instance.
+ */
+static DECLCALLBACK(bool) ahciR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
+{
+    if (!ahciR3AllAsyncIOIsFinished(pDevIns))
+        return false;
+
+    PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
+    ASMAtomicWriteBool(&pThis->fSignalIdle, false);
+    return true;
+}
+
+/**
+ * Common worker for ahciR3Suspend and ahciR3PowerOff.
+ */
+static void ahciR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
+{
+    PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
+
+    ASMAtomicWriteBool(&pThis->fSignalIdle, true);
+    if (!ahciR3AllAsyncIOIsFinished(pDevIns))
+        PDMDevHlpSetAsyncNotification(pDevIns, ahciR3IsAsyncSuspendOrPowerOffDone);
+    else
+        ASMAtomicWriteBool(&pThis->fSignalIdle, false);
+}
+
+/**
+ * Suspend notification.
+ *
+ * @returns VBox status.
+ * @param   pDevIns     The device instance data.
+ */
+static DECLCALLBACK(void) ahciR3Suspend(PPDMDEVINS pDevIns)
+{
+    PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
+    Log(("%s:\n", __FUNCTION__));
+
+    ahciR3SuspendOrPowerOff(pDevIns);
+
+    for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
+        ataControllerSuspend(&pAhci->aCts[i]);
+}
+
+/**
+ * Resume notification.
+ *
+ * @param   pDevIns     The device instance data.
+ */
+static DECLCALLBACK(void) ahciR3Resume(PPDMDEVINS pDevIns)
+{
+    PAHCI    pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
+
+    Log(("%s:\n", __FUNCTION__));
+    for (uint32_t i = 0; i < RT_ELEMENTS(pAhci->aCts); i++)
+        ataControllerResume(&pAhci->aCts[i]);
+    return;
+}
+
 /**
  * Detach notification.
@@ -6290,5 +6307,5 @@
  * @param   fFlags      Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
  */
-static DECLCALLBACK(void) ahciDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
+static DECLCALLBACK(void) ahciR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
 {
     PAHCI           pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
@@ -6333,5 +6350,5 @@
  * @param   fFlags      Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
  */
-static DECLCALLBACK(int)  ahciAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
+static DECLCALLBACK(int)  ahciR3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
 {
     PAHCI       pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
@@ -6354,5 +6371,5 @@
     rc = PDMDevHlpDriverAttach(pDevIns, pAhciPort->iLUN, &pAhciPort->IBase, &pAhciPort->pDrvBase, NULL);
     if (RT_SUCCESS(rc))
-        rc = ahciConfigureLUN(pDevIns, pAhciPort);
+        rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
     else
         AssertMsgFailed(("Failed to attach LUN#%d. rc=%Rrc\n", pAhciPort->iLUN, rc));
@@ -6419,5 +6436,5 @@
 
 /**
- * Callback employed by ahciReset.
+ * Callback employed by ahciR3Reset.
  *
  * @returns true if we've quiesced, false if we're still working.
@@ -6441,5 +6458,5 @@
  * @param   pDevIns     The device instance data.
  */
-static DECLCALLBACK(void) ahciReset(PPDMDEVINS pDevIns)
+static DECLCALLBACK(void) ahciR3Reset(PPDMDEVINS pDevIns)
 {
     PAHCI pThis = PDMINS_2_DATA(pDevIns, PAHCI);
@@ -6461,5 +6478,5 @@
  * @param   pDevIns Pointer to the device instance
  */
-static DECLCALLBACK(void) ahciPowerOff(PPDMDEVINS pDevIns)
+static DECLCALLBACK(void) ahciR3PowerOff(PPDMDEVINS pDevIns)
 {
     PAHCI pAhci = PDMINS_2_DATA(pDevIns, PAHCI);
@@ -6484,5 +6501,5 @@
  *                      iInstance it's expected to be used a bit in this function.
  */
-static DECLCALLBACK(int) ahciConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
+static DECLCALLBACK(int) ahciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
 {
     PAHCI      pThis = PDMINS_2_DATA(pDevIns, PAHCI);
@@ -6598,30 +6615,30 @@
      * to switch to it which also changes device Id and other things in the PCI configuration space).
      */
-    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
+    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("AHCI cannot register PCI I/O region"));
 
-    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
+    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("AHCI cannot register PCI I/O region"));
 
-    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
+    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, 8, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("AHCI cannot register PCI I/O region"));
 
-    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
+    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 3, 1, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("AHCI cannot register PCI I/O region"));
 
-    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciLegacyFakeIORangeMap);
+    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 4, 0x10, PCI_ADDRESS_SPACE_IO, ahciR3LegacyFakeIORangeMap);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc,
                                 N_("AHCI cannot register PCI I/O region for BMDMA"));
 
-    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciMMIOMap);
+    rc = PDMDevHlpPCIIORegionRegister(pDevIns, 5, 4352, PCI_ADDRESS_SPACE_MEM, ahciR3MMIOMap);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc,
@@ -6647,6 +6664,6 @@
 
     /* Status LUN. */
-    pThis->IBase.pfnQueryInterface = ahciStatus_QueryInterface;
-    pThis->ILeds.pfnQueryStatusLed = ahciStatus_QueryStatusLed;
+    pThis->IBase.pfnQueryInterface = ahciR3Status_QueryInterface;
+    pThis->ILeds.pfnQueryStatusLed = ahciR3Status_QueryStatusLed;
 
     /*
@@ -6710,5 +6727,5 @@
          * Init interfaces.
          */
-        pAhciPort->IBase.pfnQueryInterface           = ahciPortQueryInterface;
+        pAhciPort->IBase.pfnQueryInterface           = ahciR3PortQueryInterface;
         pAhciPort->IPortAsync.pfnTransferCompleteNotify  = ahciTransferCompleteNotify;
         pAhciPort->IMountNotify.pfnMountNotify       = ahciMountNotify;
@@ -6722,5 +6739,5 @@
         if (RT_SUCCESS(rc))
         {
-            rc = ahciConfigureLUN(pDevIns, pAhciPort);
+            rc = ahciR3ConfigureLUN(pDevIns, pAhciPort);
             if (RT_FAILURE(rc))
             {
@@ -6972,7 +6989,7 @@
 
     rc = PDMDevHlpSSMRegisterEx(pDevIns, AHCI_SAVED_STATE_VERSION, sizeof(*pThis)+cbTotalBufferSize, NULL,
-                                NULL,         ahciLiveExec, NULL,
-                                ahciSavePrep, ahciSaveExec, NULL,
-                                ahciLoadPrep, ahciLoadExec, NULL);
+                                NULL,           ahciR3LiveExec, NULL,
+                                ahciR3SavePrep, ahciR3SaveExec, NULL,
+                                ahciR3LoadPrep, ahciR3LoadExec, NULL);
     if (RT_FAILURE(rc))
         return rc;
@@ -7006,9 +7023,9 @@
     sizeof(AHCI),
     /* pfnConstruct */
-    ahciConstruct,
+    ahciR3Construct,
     /* pfnDestruct */
-    ahciDestruct,
+    ahciR3Destruct,
     /* pfnRelocate */
-    ahciRelocate,
+    ahciR3Relocate,
     /* pfnIOCtl */
     NULL,
@@ -7016,13 +7033,13 @@
     NULL,
     /* pfnReset */
-    ahciReset,
+    ahciR3Reset,
     /* pfnSuspend */
-    ahciSuspend,
+    ahciR3Suspend,
     /* pfnResume */
-    ahciResume,
+    ahciR3Resume,
     /* pfnAttach */
-    ahciAttach,
+    ahciR3Attach,
     /* pfnDetach */
-    ahciDetach,
+    ahciR3Detach,
     /* pfnQueryInterface. */
     NULL,
@@ -7030,5 +7047,5 @@
     NULL,
     /* pfnPowerOff */
-    ahciPowerOff,
+    ahciR3PowerOff,
     /* pfnSoftReset */
     NULL,
