Index: /trunk/src/VBox/Devices/Storage/DevATA.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DevATA.cpp	(revision 16707)
+++ /trunk/src/VBox/Devices/Storage/DevATA.cpp	(revision 16708)
@@ -1352,5 +1352,84 @@
 
 
-static int ataReadSectors(ATADevState *s, uint64_t u64Sector, void *pvBuf, uint32_t cSectors)
+static void ataWarningDiskFull(PPDMDEVINS pDevIns)
+{
+    int rc;
+    LogRel(("PIIX3 ATA: Host disk full\n"));
+    rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
+                           false, "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(("PIIX3 ATA: File too big\n"));
+    rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
+                           false, "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(("PIIX3 ATA: iSCSI target unavailable\n"));
+    rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
+                           false, "DevATA_ISCSIDOWN",
+                           N_("The iSCSI target has stopped responding. VM execution is suspended. You can resume when it is available again"));
+    AssertRC(rc);
+}
+
+/**
+ * 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(PATACONTROLLER pCtl)
+{
+    PPDMDEVINS  pDevIns = CONTROLLER_2_DEVINS(pCtl);
+    PVMREQ      pReq;
+    int         rc;
+
+    pCtl->fRedoIdle = true;
+    rc = VMR3ReqCall(PDMDevHlpGetVM(pDevIns), VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT,
+                     (PFNRT)PDMDevHlpVMSuspend, 1, pDevIns);
+    AssertReleaseRC(rc);
+    VMR3ReqFree(pReq);
+}
+
+bool ataIsRedoSetWarning(ATADevState *s, int rc)
+{
+    PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
+    Assert(!PDMCritSectIsOwner(&pCtl->lock));
+    if (rc == VERR_DISK_FULL)
+    {
+        ataWarningDiskFull(ATADEVSTATE_2_DEVINS(s));
+        ataSuspendRedo(pCtl);
+        return true;
+    }
+    if (rc == VERR_FILE_TOO_BIG)
+    {
+        ataWarningFileTooBig(ATADEVSTATE_2_DEVINS(s));
+        ataSuspendRedo(pCtl);
+        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));
+        ataSuspendRedo(pCtl);
+        return true;
+    }
+    return false;
+}
+
+
+static int ataReadSectors(ATADevState *s, uint64_t u64Sector, void *pvBuf, uint32_t cSectors, bool *fRedo)
 {
     PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
@@ -1367,4 +1446,9 @@
     STAM_REL_COUNTER_ADD(&s->StatBytesRead, cSectors * 512);
 
+    if (RT_SUCCESS(rc))
+        *fRedo = false;
+    else
+        *fRedo = ataIsRedoSetWarning(s, rc);
+
     STAM_PROFILE_START(&pCtl->StatLockWait, a);
     PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
@@ -1374,5 +1458,5 @@
 
 
-static int ataWriteSectors(ATADevState *s, uint64_t u64Sector, const void *pvBuf, uint32_t cSectors)
+static int ataWriteSectors(ATADevState *s, uint64_t u64Sector, const void *pvBuf, uint32_t cSectors, bool *fRedo)
 {
     PATACONTROLLER pCtl = ATADEVSTATE_2_CONTROLLER(s);
@@ -1397,4 +1481,9 @@
     STAM_REL_COUNTER_ADD(&s->StatBytesWritten, cSectors * 512);
 
+    if (RT_SUCCESS(rc))
+        *fRedo = false;
+    else
+        *fRedo = ataIsRedoSetWarning(s, rc);
+
     STAM_PROFILE_START(&pCtl->StatLockWait, a);
     PDMCritSectEnter(&pCtl->lock, VINF_SUCCESS);
@@ -1418,37 +1507,4 @@
 
 
-static void ataWarningDiskFull(PPDMDEVINS pDevIns)
-{
-    int rc;
-    LogRel(("PIIX3 ATA: Host disk full\n"));
-    rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
-                           false, "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(("PIIX3 ATA: File too big\n"));
-    rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
-                           false, "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(("PIIX3 ATA: iSCSI target unavailable\n"));
-    rc = VMSetRuntimeError(PDMDevHlpGetVM(pDevIns),
-                           false, "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(ATADevState *s)
 {
@@ -1456,4 +1512,5 @@
     uint32_t cSectors;
     uint64_t iLBA;
+    bool fRedo;
 
     cSectors = s->cbElementaryTransfer / 512;
@@ -1461,5 +1518,5 @@
     iLBA = ataGetSector(s);
     Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iLBA));
-    rc = ataReadSectors(s, iLBA, s->CTX_SUFF(pbIOBuffer), cSectors);
+    rc = ataReadSectors(s, iLBA, s->CTX_SUFF(pbIOBuffer), cSectors, &fRedo);
     if (RT_SUCCESS(rc))
     {
@@ -1471,21 +1528,6 @@
     else
     {
-        if (rc == VERR_DISK_FULL)
-        {
-            ataWarningDiskFull(ATADEVSTATE_2_DEVINS(s));
-            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 (fRedo)
+            return fRedo;
         if (s->cErrors++ < MAX_LOG_REL_ERRORS)
             LogRel(("PIIX3 ATA: LUN#%d: disk read error (rc=%Rrc iSector=%#RX64 cSectors=%#RX32)\n",
@@ -1499,5 +1541,4 @@
             ataCmdError(s, ID_ERR);
     }
-    /** @todo implement redo for iSCSI */
     return false;
 }
@@ -1509,4 +1550,5 @@
     uint32_t cSectors;
     uint64_t iLBA;
+    bool fRedo;
 
     cSectors = s->cbElementaryTransfer / 512;
@@ -1514,5 +1556,5 @@
     iLBA = ataGetSector(s);
     Log(("%s: %d sectors at LBA %d\n", __FUNCTION__, cSectors, iLBA));
-    rc = ataWriteSectors(s, iLBA, s->CTX_SUFF(pbIOBuffer), cSectors);
+    rc = ataWriteSectors(s, iLBA, s->CTX_SUFF(pbIOBuffer), cSectors, &fRedo);
     if (RT_SUCCESS(rc))
     {
@@ -1524,21 +1566,6 @@
     else
     {
-        if (rc == VERR_DISK_FULL)
-        {
-            ataWarningDiskFull(ATADEVSTATE_2_DEVINS(s));
-            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 (fRedo)
+            return fRedo;
         if (s->cErrors++ < MAX_LOG_REL_ERRORS)
             LogRel(("PIIX3 ATA: LUN#%d: disk write error (rc=%Rrc iSector=%#RX64 cSectors=%#RX32)\n",
@@ -1552,5 +1579,4 @@
             ataCmdError(s, ID_ERR);
     }
-    /** @todo implement redo for iSCSI */
     return false;
 }
@@ -4278,25 +4304,4 @@
 
 
-/**
- * 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(PATACONTROLLER pCtl)
-{
-    PPDMDEVINS  pDevIns = CONTROLLER_2_DEVINS(pCtl);
-    PVMREQ      pReq;
-    int         rc;
-
-    pCtl->fRedoIdle = true;
-    rc = VMR3ReqCall(PDMDevHlpGetVM(pDevIns), VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT,
-                     (PFNRT)PDMDevHlpVMSuspend, 1, pDevIns);
-    AssertReleaseRC(rc);
-    VMR3ReqFree(pReq);
-}
-
 /** Asynch I/O thread for an interface. Once upon a time this was readable
  * code with several loops and a different semaphore for each purpose. But
@@ -4453,5 +4458,4 @@
                             LogRel(("%s: Ctl#%d: redo entire operation\n", __FUNCTION__, ATACONTROLLER_IDX(pCtl)));
                             ataAsyncIOPutRequest(pCtl, pReq);
-                            ataSuspendRedo(pCtl);
                             break;
                         }
@@ -4558,5 +4562,4 @@
                     LogRel(("PIIX3 ATA: Ctl#%d: redo DMA operation\n", ATACONTROLLER_IDX(pCtl)));
                     ataAsyncIOPutRequest(pCtl, &ataDMARequest);
-                    ataSuspendRedo(pCtl);
                     break;
                 }
