Index: /trunk/src/VBox/Devices/Storage/ATAController.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/ATAController.cpp	(revision 32943)
+++ /trunk/src/VBox/Devices/Storage/ATAController.cpp	(revision 32944)
@@ -7,5 +7,5 @@
 
 /*
- * Copyright (C) 2006-2009 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -308,10 +308,10 @@
     rc = RTSemMutexRequest(pCtl->AsyncIORequestMutex, RT_INDEFINITE_WAIT);
     AssertRC(rc);
-    LogRel(("ATA: Ctl: request queue dump (topmost is current):\n"));
+    LogRel(("AHCI ATA: Ctl: request queue dump (topmost is current):\n"));
     curr = pCtl->AsyncIOReqTail;
     do
     {
         if (curr == pCtl->AsyncIOReqHead)
-            LogRel(("ATA: Ctl: processed requests (topmost is oldest):\n"));
+            LogRel(("AHCI ATA: Ctl: processed requests (topmost is oldest):\n"));
         switch (pCtl->aAsyncIORequests[curr].ReqType)
         {
@@ -963,5 +963,61 @@
 
 
-static int ataReadSectors(AHCIATADevState *s, uint64_t u64Sector, void *pvBuf, uint32_t cSectors)
+static void ataWarningDiskFull(PPDMDEVINS pDevIns)
+{
+    int rc;
+    LogRel(("AHCI ATA: Host disk full\n"));
+    rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevATA_DISKFULL",
+                                    N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
+    AssertRC(rc);
+}
+
+static void ataWarningFileTooBig(PPDMDEVINS pDevIns)
+{
+    int rc;
+    LogRel(("AHCI ATA: File too big\n"));
+    rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevATA_FILETOOBIG",
+                                    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"));
+    AssertRC(rc);
+}
+
+static void ataWarningISCSI(PPDMDEVINS pDevIns)
+{
+    int rc;
+    LogRel(("AHCI ATA: iSCSI target unavailable\n"));
+    rc = PDMDevHlpVMSetRuntimeError(pDevIns, VMSETRTERR_FLAGS_SUSPEND | VMSETRTERR_FLAGS_NO_WAIT, "DevATA_ISCSIDOWN",
+                                    N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
+    AssertRC(rc);
+}
+
+static bool ataIsRedoSetWarning(AHCIATADevState *s, int rc)
+{
+    PAHCIATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
+    Assert(!PDMCritSectIsOwner(&pCtl->lock));
+    if (rc == VERR_DISK_FULL)
+    {
+        pCtl->fRedoIdle = true;
+        ataWarningDiskFull(ATADEVSTATE_2_DEVINS(s));
+        return true;
+    }
+    if (rc == VERR_FILE_TOO_BIG)
+    {
+        pCtl->fRedoIdle = true;
+        ataWarningFileTooBig(ATADEVSTATE_2_DEVINS(s));
+        return true;
+    }
+    if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
+    {
+        pCtl->fRedoIdle = true;
+        /* iSCSI connection abort (first error) or failure to reestablish
+         * connection (second error). Pause VM. On resume we'll retry. */
+        ataWarningISCSI(ATADEVSTATE_2_DEVINS(s));
+        return true;
+    }
+    return false;
+}
+
+
+static int ataReadSectors(AHCIATADevState *s, uint64_t u64Sector, void *pvBuf,
+                          uint32_t cSectors, bool *pfRedo)
 {
     PAHCIATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
@@ -978,4 +1034,9 @@
     STAM_REL_COUNTER_ADD(s->pStatBytesRead, cSectors * 512);
 
+    if (RT_SUCCESS(rc))
+        *pfRedo = false;
+    else
+        *pfRedo = ataIsRedoSetWarning(s, rc);
+
     STAM_PROFILE_START(&pCtl->StatLockWait, a);
     PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
@@ -985,5 +1046,6 @@
 
 
-static int ataWriteSectors(AHCIATADevState *s, uint64_t u64Sector, const void *pvBuf, uint32_t cSectors)
+static int ataWriteSectors(AHCIATADevState *s, uint64_t u64Sector,
+                           const void *pvBuf, uint32_t cSectors, bool *pfRedo)
 {
     PAHCIATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
@@ -999,4 +1061,9 @@
 
     STAM_REL_COUNTER_ADD(s->pStatBytesWritten, cSectors * 512);
+
+    if (RT_SUCCESS(rc))
+        *pfRedo = false;
+    else
+        *pfRedo = ataIsRedoSetWarning(s, rc);
 
     STAM_PROFILE_START(&pCtl->StatLockWait, a);
@@ -1021,34 +1088,4 @@
 
 
-static void ataWarningDiskFull(PPDMDEVINS pDevIns)
-{
-    int rc;
-    LogRel(("ATA: Host disk full\n"));
-    rc = PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "DevATA_DISKFULL",
-                                    N_("Host system reported disk full. VM execution is suspended. You can resume after freeing some space"));
-    AssertRC(rc);
-}
-
-
-static void ataWarningFileTooBig(PPDMDEVINS pDevIns)
-{
-    int rc;
-    LogRel(("ATA: File too big\n"));
-    rc = PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "DevATA_FILETOOBIG",
-                                    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"));
-    AssertRC(rc);
-}
-
-
-static void ataWarningISCSI(PPDMDEVINS pDevIns)
-{
-    int rc;
-    LogRel(("ATA: iSCSI target unavailable\n"));
-    rc = PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "DevATA_ISCSIDOWN",
-                                    N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
-    AssertRC(rc);
-}
-
-
 static bool ataReadSectorsSS(AHCIATADevState *s)
 {
@@ -1056,4 +1093,5 @@
     uint32_t cSectors;
     uint64_t iLBA;
+    bool fRedo;
 
     cSectors = s->cbElementaryTransfer / 512;
@@ -1061,5 +1099,5 @@
     iLBA = ataGetSector(s);
     Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iLBA));
-    rc = ataReadSectors(s, iLBA, s->CTXALLSUFF(pbIOBuffer), cSectors);
+    rc = ataReadSectors(s, iLBA, s->CTXALLSUFF(pbIOBuffer), cSectors, &fRedo);
     if (RT_SUCCESS(rc))
     {
@@ -1071,21 +1109,6 @@
     else
     {
-        if (rc == VERR_DISK_FULL)
-        {
-            ataWarningDiskFull(ATADEVSTATE_2_DEVINS(s));
+        if (fRedo)
             return true;
-        }
-        if (rc == VERR_FILE_TOO_BIG)
-        {
-            ataWarningFileTooBig(ATADEVSTATE_2_DEVINS(s));
-            return true;
-        }
-        if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
-        {
-            /* iSCSI connection abort (first error) or failure to reestablish
-             * connection (second error). Pause VM. On resume we'll retry. */
-            ataWarningISCSI(ATADEVSTATE_2_DEVINS(s));
-            return true;
-        }
         if (s->cErrors++ < MAX_LOG_REL_ERRORS)
             LogRel(("AHCI ATA: LUN#%d: disk read error (rc=%Rrc iSector=%#RX64 cSectors=%#RX32)\n",
@@ -1093,5 +1116,4 @@
         ataCmdError(s, ID_ERR);
     }
-    /** @todo implement redo for iSCSI */
     return false;
 }
@@ -1103,4 +1125,5 @@
     uint32_t cSectors;
     uint64_t iLBA;
+    bool fRedo;
 
     cSectors = s->cbElementaryTransfer / 512;
@@ -1108,5 +1131,5 @@
     iLBA = ataGetSector(s);
     Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iLBA));
-    rc = ataWriteSectors(s, iLBA, s->CTXALLSUFF(pbIOBuffer), cSectors);
+    rc = ataWriteSectors(s, iLBA, s->CTXALLSUFF(pbIOBuffer), cSectors, &fRedo);
     if (RT_SUCCESS(rc))
     {
@@ -1118,21 +1141,6 @@
     else
     {
-        if (rc == VERR_DISK_FULL)
-        {
-            ataWarningDiskFull(ATADEVSTATE_2_DEVINS(s));
+        if (fRedo)
             return true;
-        }
-        if (rc == VERR_FILE_TOO_BIG)
-        {
-            ataWarningFileTooBig(ATADEVSTATE_2_DEVINS(s));
-            return true;
-        }
-        if (rc == VERR_BROKEN_PIPE || rc == VERR_NET_CONNECTION_REFUSED)
-        {
-            /* iSCSI connection abort (first error) or failure to reestablish
-             * connection (second error). Pause VM. On resume we'll retry. */
-            ataWarningISCSI(ATADEVSTATE_2_DEVINS(s));
-            return true;
-        }
         if (s->cErrors++ < MAX_LOG_REL_ERRORS)
             LogRel(("AHCI ATA: LUN#%d: disk write error (rc=%Rrc iSector=%#RX64 cSectors=%#RX32)\n",
@@ -1140,5 +1148,4 @@
         ataCmdError(s, ID_ERR);
     }
-    /** @todo implement redo for iSCSI */
     return false;
 }
@@ -2767,5 +2774,5 @@
         return;
 
-    LogRel(("ATA: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pIf->iLUN, pIf->cTotalSectors));
+    LogRel(("AHCI ATA: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough unchanged\n", pIf->iLUN, pIf->cTotalSectors));
 
     if (pIf->fATAPI)
@@ -3405,5 +3412,5 @@
         if (pCtl->aIfs[1].u64CmdTS)
             uCmdWait1 = (uNow - pCtl->aIfs[1].u64CmdTS) / 1000;
-        LogRel(("ATA: Ctl: RESET, DevSel=%d AIOIf=%d CmdIf0=%#04x (%d usec ago) CmdIf1=%#04x (%d usec ago)\n",
+        LogRel(("AHCI ATA: Ctl: RESET, DevSel=%d AIOIf=%d CmdIf0=%#04x (%d usec ago) CmdIf1=%#04x (%d usec ago)\n",
                     pCtl->iSelectedIf, pCtl->iAIOIf,
                     pCtl->aIfs[0].uATARegCommand, uCmdWait0,
@@ -3823,5 +3830,5 @@
         if (!(pCtl->BmDma.u8Cmd & BM_CMD_START) || pCtl->fReset)
         {
-            LogRel(("ATA: Ctl: ABORT DMA%s\n", pCtl->fReset ? " due to RESET" : ""));
+            LogRel(("AHCI ATA: Ctl: ABORT DMA%s\n", pCtl->fReset ? " due to RESET" : ""));
             if (!pCtl->fReset)
                 ataDMATransferStop(s);
@@ -3848,24 +3855,4 @@
     s->iIOBufferCur = iIOBufferCur;
     s->iIOBufferEnd = iIOBufferEnd;
-}
-
-
-/**
- * Suspend I/O operations on a controller. Also suspends EMT, because it's
- * waiting for I/O to make progress. The next attempt to perform an I/O
- * operation will be made when EMT is resumed up again (as the resume
- * callback below restarts I/O).
- *
- * @param pCtl      Controller for which to suspend I/O.
- */
-static void ataSuspendRedo(PAHCIATACONTROLLER pCtl)
-{
-    PPDMDEVINS  pDevIns = CONTROLLER_2_DEVINS(pCtl);
-    int         rc;
-
-    pCtl->fRedoIdle = true;
-    rc = VMR3ReqCallWait(PDMDevHlpGetVM(pDevIns), VMCPUID_ANY,
-                         (PFNRT)PDMDevHlpVMSuspend, 1, pDevIns);
-    AssertReleaseRC(rc);
 }
 
@@ -4036,5 +4023,4 @@
                             LogRel(("%s: Ctl: redo entire operation\n", __FUNCTION__));
                             ataAsyncIOPutRequest(pCtl, pReq);
-                            ataSuspendRedo(pCtl);
                             break;
                         }
@@ -4139,7 +4125,6 @@
                 if (RT_UNLIKELY(pCtl->fRedo))
                 {
-                    LogRel(("ATA: Ctl: redo DMA operation\n"));
+                    LogRel(("AHCI ATA: Ctl: redo DMA operation\n"));
                     ataAsyncIOPutRequest(pCtl, &ataDMARequest);
-                    ataSuspendRedo(pCtl);
                     break;
                 }
@@ -4185,7 +4170,6 @@
                     if (RT_UNLIKELY(fRedo))
                     {
-                        LogRel(("ATA: Ctl#%d: redo PIO operation\n"));
+                        LogRel(("AHCI ATA: Ctl#%d: redo PIO operation\n"));
                         ataAsyncIOPutRequest(pCtl, &ataPIORequest);
-                        ataSuspendRedo(pCtl);
                         break;
                     }
@@ -4258,5 +4242,5 @@
                 pCtl->uAsyncIOState = AHCIATA_AIO_NEW;
                 pCtl->fReset = false;
-                LogRel(("ATA: Ctl: finished processing RESET\n"));
+                LogRel(("AHCI ATA: Ctl: finished processing RESET\n"));
                 for (uint32_t i = 0; i < RT_ELEMENTS(pCtl->aIfs); i++)
                 {
@@ -4868,5 +4852,5 @@
 
     if (!fAllIdle)
-        LogRel(("ATA: Ctl is still executing, DevSel=%d AIOIf=%d CmdIf0=%#04x CmdIf1=%#04x\n",
+        LogRel(("AHCI ATA: Ctl is still executing, DevSel=%d AIOIf=%d CmdIf0=%#04x CmdIf1=%#04x\n",
                 pCtl->iSelectedIf, pCtl->iAIOIf,
                 pCtl->aIfs[0].uATARegCommand, pCtl->aIfs[1].uATARegCommand));
@@ -4921,4 +4905,6 @@
         ASMAtomicWriteU32(&pCtl->fShutdown, true);
         rc = RTSemEventSignal(pCtl->AsyncIOSem);
+        AssertRC(rc);
+        rc = RTSemEventSignal(pCtl->SuspendIOSem);
         AssertRC(rc);
 
@@ -5083,5 +5069,5 @@
         pIf->PCHSGeometry.cHeads     = 0; /* dummy */
         pIf->PCHSGeometry.cSectors   = 0; /* dummy */
-        LogRel(("ATA: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pIf->iLUN, pIf->cTotalSectors, (pIf->fATAPIPassthrough ? "enabled" : "disabled")));
+        LogRel(("AHCI ATA: LUN#%d: CD/DVD, total number of sectors %Ld, passthrough %s\n", pIf->iLUN, pIf->cTotalSectors, (pIf->fATAPIPassthrough ? "enabled" : "disabled")));
     }
     else
@@ -5403,5 +5389,5 @@
             else
             {
-                LogRel(("ATA: No buffer for %d\n", j));
+                LogRel(("AHCI ATA: No buffer for %d\n", j));
                 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
                     return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("No buffer for %d"), j);
