Index: /trunk/src/VBox/Devices/Storage/DevATA.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DevATA.cpp	(revision 24740)
+++ /trunk/src/VBox/Devices/Storage/DevATA.cpp	(revision 24741)
@@ -3746,8 +3746,12 @@
  * @returns true on success.
  * @returns false when the thread is still processing.
- * @param   pThis       Pointer to the controller data.
- * @param   cMillies    How long to wait (total).  This isn't very accurate.
+ * @param   pThis               Pointer to the controller data.
+ * @param   cMillies            How long to wait (total).  This isn't very
+ *                              accurate.
+ * @param   fLeaveSignallingOn  Leave the signalling on so that it will notifiy
+ *                              PDM about completion of the asynchronous
+ *                              notification.
  */
-static bool ataWaitForAsyncIOIsIdle(PATACONTROLLER pCtl, unsigned cMillies)
+static bool ataWaitForAsyncIOIsIdle(PATACONTROLLER pCtl, unsigned cMillies, bool fLeaveSignallingOn)
 {
     uint64_t        u64Start;
@@ -3785,5 +3789,6 @@
     }
 
-    ASMAtomicWriteBool(&pCtl->fSignalIdle, false);
+    if (fRc || !fLeaveSignallingOn)
+        ASMAtomicWriteBool(&pCtl->fSignalIdle, false);
     return fRc;
 }
@@ -3795,8 +3800,11 @@
  * @returns true on success.
  * @returns false when one or more threads is still processing.
- * @param   pThis       Pointer to the instance data.
- * @param   cMillies    How long to wait per controller.
+ * @param   pThis               Pointer to the instance data.
+ * @param   cMillies            How long to wait per controller.
+ * @param   fLeaveSignallingOn  Leave the signalling on so that it will notifiy
+ *                              PDM about completion of the asynchronous
+ *                              notification.
  */
-static bool ataWaitForAllAsyncIOIsIdle(PPDMDEVINS pDevIns, uint32_t cMillies)
+static bool ataWaitForAllAsyncIOIsIdle(PPDMDEVINS pDevIns, uint32_t cMillies, bool fLeaveSignallingOn)
 {
     PCIATAState *pThis = PDMINS_2_DATA(pDevIns, PCIATAState *);
@@ -3804,5 +3812,5 @@
     for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aCts); i++)
         if (   pThis->aCts[i].AsyncIOThread != NIL_RTTHREAD
-            && !ataWaitForAsyncIOIsIdle(&pThis->aCts[i], cMillies))
+            && !ataWaitForAsyncIOIsIdle(&pThis->aCts[i], cMillies, fLeaveSignallingOn))
         {
             LogRel(("PIIX3 ATA: Ctl#%u is still executing, DevSel=%d AIOIf=%d CmdIf0=%#04x CmdIf1=%#04x\n",
@@ -4568,5 +4576,8 @@
     if (    pCtl->fSignalIdle
         &&  ataAsyncIOIsIdle(pCtl, false /*fStrict*/))
+    {
         RTThreadUserSignal(pCtl->AsyncIOThread);
+        PDMDevHlpAsyncNotificationCompleted(pCtl->pDevInsR3);
+    }
 
     rc = RTSemMutexRelease(pCtl->AsyncIORequestMutex); AssertRC(rc);
@@ -5304,5 +5315,6 @@
         ataAsyncIOPutRequest(&pThis->aCts[i], &ataResetARequest);
         ataAsyncIOPutRequest(&pThis->aCts[i], &ataResetCRequest);
-        if (!ataWaitForAsyncIOIsIdle(&pThis->aCts[i], 30000))
+/** @todo Deadlock alert. see @bugref{4394}. */
+        if (!ataWaitForAsyncIOIsIdle(&pThis->aCts[i], 30000, false /*fLeaveSignallingOn*/))
         {
             PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "DevATA_ASYNCBUSY",
@@ -5622,4 +5634,31 @@
 
 #ifdef IN_RING3
+
+/**
+ * Callback employed by ataSuspend and ataPowerOff.
+ *
+ * @returns true if we've quiesced, false if we're still working.
+ * @param   pDevIns     The device instance.
+ */
+static DECLCALLBACK(bool) ataR3IsAsyncSuspendOrPowerOffDone(PPDMDEVINS pDevIns)
+{
+    return ataWaitForAllAsyncIOIsIdle(pDevIns, 0, true /*fLeaveSignallingOn*/);
+}
+
+
+/**
+ * Common worker for ataSuspend and ataPowerOff.
+ */
+static void ataR3SuspendOrPowerOff(PPDMDEVINS pDevIns)
+{
+#if 1
+    if (!ataWaitForAllAsyncIOIsIdle(pDevIns, 0, true /*fLeaveSignallingOn*/))
+        PDMDevHlpSetAsyncNotification(pDevIns, ataR3IsAsyncSuspendOrPowerOffDone);
+#else
+    if (!ataWaitForAllAsyncIOIsIdle(pDevIns, 20000))
+        AssertMsgFailed(("Async I/O didn't stop in ~40 seconds!\n"));
+#endif
+}
+
 
 DECLINLINE(void) ataRelocBuffer(PPDMDEVINS pDevIns, ATADevState *s)
@@ -5981,7 +6020,5 @@
 {
     Log(("%s:\n", __FUNCTION__));
-    if (!ataWaitForAllAsyncIOIsIdle(pDevIns, 20000))
-        AssertMsgFailed(("Async I/O didn't stop in ~40 seconds!\n"));
-    return;
+    ataR3SuspendOrPowerOff(pDevIns);
 }
 
@@ -6020,7 +6057,5 @@
 {
     Log(("%s:\n", __FUNCTION__));
-    if (!ataWaitForAllAsyncIOIsIdle(pDevIns, 20000))
-        AssertMsgFailed(("Async I/O didn't stop in ~40 seconds!\n"));
-    return;
+    ataR3SuspendOrPowerOff(pDevIns);
 }
 
