Index: /trunk/include/VBox/vmm/pdmdrv.h
===================================================================
--- /trunk/include/VBox/vmm/pdmdrv.h	(revision 38877)
+++ /trunk/include/VBox/vmm/pdmdrv.h	(revision 38878)
@@ -1263,4 +1263,5 @@
                                                   PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete,
                                                   PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue,
+                                                  PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard,
                                                   const char *pcszId));
 
@@ -1720,7 +1721,8 @@
                                         PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete,
                                         PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue,
+                                        PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard,
                                         const char *pcszId)
 {
-    return pDrvIns->pHlpR3->pfnBlkCacheRetain(pDrvIns, ppBlkCache, pfnXferComplete, pfnXferEnqueue, pcszId);
+    return pDrvIns->pHlpR3->pfnBlkCacheRetain(pDrvIns, ppBlkCache, pfnXferComplete, pfnXferEnqueue, pfnXferEnqueueDiscard, pcszId);
 }
 
Index: /trunk/include/VBox/vmm/pdmifs.h
===================================================================
--- /trunk/include/VBox/vmm/pdmifs.h	(revision 38877)
+++ /trunk/include/VBox/vmm/pdmifs.h	(revision 38878)
@@ -913,18 +913,4 @@
 
 
-/**
- * PDM range.
- */
-typedef struct PDMRANGE
-{
-    /** Start offset. */
-    uint64_t    offStart;
-    /** Size. */
-    size_t      cbRange;
-} PDMRANGE;
-/** Pointer to a PDM range. */
-typedef PDMRANGE *PPDMRANGE;
-
-
 /** Pointer to a block interface. */
 typedef struct PDMIBLOCK *PPDMIBLOCK;
@@ -1043,5 +1029,5 @@
      * @thread  Any thread.
      */
-    DECLR3CALLBACKMEMBER(int, pfnDiscard,(PPDMIBLOCK pInterface, PPDMRANGE paRanges, unsigned cRanges));
+    DECLR3CALLBACKMEMBER(int, pfnDiscard,(PPDMIBLOCK pInterface, PCRTRANGE paRanges, unsigned cRanges));
 } PDMIBLOCK;
 /** PDMIBLOCK interface ID. */
@@ -1341,5 +1327,5 @@
      * @thread  Any thread.
      */
-    DECLR3CALLBACKMEMBER(int, pfnDiscard,(PPDMIMEDIA pInterface, PPDMRANGE paRanges, unsigned cRanges));
+    DECLR3CALLBACKMEMBER(int, pfnDiscard,(PPDMIMEDIA pInterface, PCRTRANGE paRanges, unsigned cRanges));
 
 } PDMIMEDIA;
@@ -1525,7 +1511,19 @@
     DECLR3CALLBACKMEMBER(int, pfnStartFlush,(PPDMIBLOCKASYNC pInterface, void *pvUser));
 
+    /**
+     * Discards the given range.
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   paRanges        Array of ranges to discard.
+     * @param   cRanges         Number of entries in the array.
+     * @param   pvUser          User argument which is returned in completion callback.
+     * @thread  Any thread.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnStartDiscard,(PPDMIBLOCKASYNC pInterface, PCRTRANGE paRanges, unsigned cRanges, void *pvUser));
+
 } PDMIBLOCKASYNC;
 /** PDMIBLOCKASYNC interface ID. */
-#define PDMIBLOCKASYNC_IID                      "78302d0d-4978-498c-be3c-8989cb5ff5c8"
+#define PDMIBLOCKASYNC_IID                      "a921dd96-1748-4ecd-941e-d5f3cd4c8fe4"
 
 
@@ -1599,7 +1597,19 @@
     DECLR3CALLBACKMEMBER(int, pfnStartFlush,(PPDMIMEDIAASYNC pInterface, void *pvUser));
 
+    /**
+     * Discards the given range.
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   paRanges        Array of ranges to discard.
+     * @param   cRanges         Number of entries in the array.
+     * @param   pvUser          User argument which is returned in completion callback.
+     * @thread  Any thread.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnStartDiscard,(PPDMIMEDIAASYNC pInterface, PCRTRANGE paRanges, unsigned cRanges, void *pvUser));
+
 } PDMIMEDIAASYNC;
 /** PDMIMEDIAASYNC interface ID. */
-#define PDMIMEDIAASYNC_IID                      "3553227d-714d-4d28-b993-59f4e671588e"
+#define PDMIMEDIAASYNC_IID                      "4be209d3-ccb5-4297-82fe-7d8018bc6ab4"
 
 
Index: /trunk/include/VBox/vscsi.h
===================================================================
--- /trunk/include/VBox/vscsi.h	(revision 38877)
+++ /trunk/include/VBox/vscsi.h	(revision 38878)
@@ -95,17 +95,4 @@
 typedef VSCSILUNTYPE *PVSCSILUNTYPE;
 
-/**
- * Range descriptor.
- */
-typedef struct VSCSIRANGE
-{
-    /** Start offset. */
-    uint64_t offStart;
-    /** Size of the range. */
-    size_t   cbRange;
-} VSCSIRANGE;
-/** Pointer to a range descriptor. */
-typedef VSCSIRANGE *PVSCSIRANGE;
-
 /** The LUN can handle the UNMAP command. */
 #define VSCSI_LUN_FEATURE_UNMAP          RT_BIT(0)
@@ -326,5 +313,5 @@
  * @param   pcRanges       Where to store the number of ranges on success.
  */
-VBOXDDU_DECL(int) VSCSIIoReqUnmapParamsGet(VSCSIIOREQ hVScsiIoReq, PVSCSIRANGE *ppaRanges,
+VBOXDDU_DECL(int) VSCSIIoReqUnmapParamsGet(VSCSIIOREQ hVScsiIoReq, PCRTRANGE *ppaRanges,
                                            unsigned *pcRanges);
 
Index: /trunk/src/VBox/Devices/Storage/DevAHCI.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DevAHCI.cpp	(revision 38877)
+++ /trunk/src/VBox/Devices/Storage/DevAHCI.cpp	(revision 38878)
@@ -329,5 +329,5 @@
     PFNAHCIPOSTPROCESS         pfnPostProcess;
     /** Pointer to the array of PDM ranges. */
-    PPDMRANGE                  paRanges;
+    PRTRANGE                   paRanges;
     /** Number of entries in the array. */
     unsigned                   cRanges;
@@ -3076,5 +3076,7 @@
     p[67] = RT_H2LE_U16(120); /* minimum PIO cycle time without flow control */
     p[68] = RT_H2LE_U16(120); /* minimum PIO cycle time with IORDY flow control */
-    if (pAhciPort->pDrvBlock->pfnDiscard)
+    if (   pAhciPort->pDrvBlock->pfnDiscard
+        || ( pAhciPort->fAsyncInterface
+            && pAhciPort->pDrvBlockAsync->pfnStartDiscard))
     {
         p[80] = RT_H2LE_U16(0x1f0); /* support everything up to ATA/ATAPI-8 ACS */
@@ -3101,5 +3103,7 @@
         p[217] = RT_H2LE_U16(1); /* Non-rotational medium */
 
-    if (pAhciPort->pDrvBlock->pfnDiscard) /** @todo: Set bit 14 in word 69 too? (Deterministic read after TRIM). */
+    if (   pAhciPort->pDrvBlock->pfnDiscard
+        || (   pAhciPort->fAsyncInterface
+            && pAhciPort->pDrvBlockAsync->pfnStartDiscard)) /** @todo: Set bit 14 in word 69 too? (Deterministic read after TRIM). */
         p[169] = RT_H2LE_U16(1); /* DATA SET MANAGEMENT command supported. */
 
@@ -5348,5 +5352,6 @@
     pAhciPortTaskState->paSGEntries[0].u.temp.pvBuf = pAhciPortTaskState->pvBufferUnaligned;
 
-    if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
+    if (   pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE
+        || pAhciPortTaskState->enmTxDir == AHCITXDIR_TRIM)
         ahciCopyFromSGListIntoBuffer(pDevIns, &pAhciPortTaskState->paSGEntries[0]);
 
@@ -6076,158 +6081,4 @@
 
 /**
- * Complete a data transfer task by freeing all occupied resources
- * and notifying the guest.
- *
- * @returns VBox status code
- *
- * @param pAhciPort             Pointer to the port where to request completed.
- * @param pAhciPortTaskState    Pointer to the task which finished.
- * @param rcReq                 IPRT status code of the completed request.
- */
-static int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, int rcReq)
-{
-    bool fXchg = false;
-    bool fRedo = false;
-
-    ASMAtomicCmpXchgSize(&pAhciPortTaskState->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
-
-    if (fXchg)
-    {
-        /* Free system resources occupied by the scatter gather list. */
-        if (pAhciPortTaskState->enmTxDir != AHCITXDIR_FLUSH)
-            ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
-
-        if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)
-        {
-            STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciPortTaskState->cbTransfer);
-            pAhciPort->Led.Actual.s.fReading = 0;
-        }
-        else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
-        {
-            STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciPortTaskState->cbTransfer);
-            pAhciPort->Led.Actual.s.fWriting = 0;
-        }
-
-        if (RT_FAILURE(rcReq))
-        {
-            /* Log the error. */
-            if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
-            {
-                if (pAhciPortTaskState->enmTxDir == AHCITXDIR_FLUSH)
-                    LogRel(("AHCI#%u: Flush returned rc=%Rrc\n",
-                            pAhciPort->iLUN, rcReq));
-                else
-                    LogRel(("AHCI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
-                            pAhciPort->iLUN,
-                            pAhciPortTaskState->enmTxDir == AHCITXDIR_READ
-                            ? "Read"
-                            : "Write",
-                            pAhciPortTaskState->uOffset,
-                            pAhciPortTaskState->cbTransfer, rcReq));
-            }
-
-            fRedo = ahciIsRedoSetWarning(pAhciPort, rcReq);
-            if (!fRedo)
-            {
-                pAhciPortTaskState->cmdHdr.u32PRDBC = 0;
-                pAhciPortTaskState->uATARegError = ID_ERR;
-                pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
-                ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciPortTaskState, NULL);
-            }
-            else
-                ASMAtomicOrU32(&pAhciPort->u32TasksNew, (1 << pAhciPortTaskState->uTag));
-        }
-        else
-        {
-            pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
-
-            pAhciPortTaskState->uATARegError = 0;
-            pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
-
-            /* Write updated command header into memory of the guest. */
-            PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
-                               &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
-        }
-
-        /* Add the task to the cache. */
-        ASMAtomicWritePtr(&pAhciPort->aCachedTasks[pAhciPortTaskState->uTag], pAhciPortTaskState);
-        ASMAtomicDecU32(&pAhciPort->cTasksActive);
-
-        if (!fRedo)
-        {
-            if (pAhciPortTaskState->fQueued)
-            {
-                if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIPORTTASKSTATE))
-                    ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
-
-                /*
-                 * Always raise an interrupt after task completion; delaying
-                 * this (interrupt coalescing) increases latency and has a significant
-                 * impact on performance (see #5071)
-                 */
-                ahciSendSDBFis(pAhciPort, 0, true);
-            }
-            else
-                ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
-        }
-    }
-    else
-    {
-        /*
-         * Task was canceled, do the cleanup but DO NOT access the guest memory!
-         * The guest might use it for other things now because it doesn't know about that task anymore.
-         */
-        AssertMsg(pAhciPortTaskState->enmTxState == AHCITXSTATE_CANCELED,
-                  ("Task is not active but wasn't canceled!\n"));
-
-        ahciScatterGatherListFree(pAhciPortTaskState);
-
-        /* Leave a log message about the canceled request. */
-        if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
-        {
-            if (pAhciPortTaskState->enmTxDir == AHCITXDIR_FLUSH)
-                LogRel(("AHCI#%u: Canceled flush returned rc=%Rrc\n",
-                        pAhciPort->iLUN, rcReq));
-            else
-                LogRel(("AHCI#%u: Canceled %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
-                        pAhciPort->iLUN,
-                        pAhciPortTaskState->enmTxDir == AHCITXDIR_READ
-                        ? "read"
-                        : "write",
-                        pAhciPortTaskState->uOffset,
-                        pAhciPortTaskState->cbTransfer, rcReq));
-         }
-
-        /* Finally free the task state structure because it is completely unused now. */
-        RTMemFree(pAhciPortTaskState);
-    }
-
-    return VINF_SUCCESS;
-}
-
-/**
- * Notification callback for a completed transfer.
- *
- * @returns VBox status code.
- * @param   pInterface   Pointer to the interface.
- * @param   pvUser       User data.
- * @param   rcReq        IPRT Status code of the completed request.
- */
-static DECLCALLBACK(int) ahciTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser, int rcReq)
-{
-    PAHCIPort pAhciPort = PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface);
-    PAHCIPORTTASKSTATE pAhciPortTaskState = (PAHCIPORTTASKSTATE)pvUser;
-
-    ahciLog(("%s: pInterface=%p pvUser=%p uTag=%u\n",
-             __FUNCTION__, pInterface, pvUser, pAhciPortTaskState->uTag));
-
-    int rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, rcReq);
-
-    if (pAhciPort->cTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
-        PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
-    return rc;
-}
-
-/**
  * Creates the array of ranges to trim.
  *
@@ -6277,5 +6128,5 @@
     AssertReturn(cRanges != 0, VERR_INVALID_PARAMETER);
 
-    pAhciPortTaskState->paRanges = (PPDMRANGE)RTMemAllocZ(sizeof(PDMRANGE) * cRanges);
+    pAhciPortTaskState->paRanges = (PRTRANGE)RTMemAllocZ(sizeof(RTRANGE) * cRanges);
     if (pAhciPortTaskState->paRanges)
     {
@@ -6309,7 +6160,175 @@
 }
 
+/**
+ * Destroy the trim range list.
+ *
+ * @returns nothing.
+ * @param   pAhciPortTaskState    The task state.
+ */
 static void ahciTrimRangesDestroy(PAHCIPORTTASKSTATE pAhciPortTaskState)
 {
     RTMemFree(pAhciPortTaskState->paRanges);
+}
+
+/**
+ * Complete a data transfer task by freeing all occupied resources
+ * and notifying the guest.
+ *
+ * @returns VBox status code
+ *
+ * @param pAhciPort             Pointer to the port where to request completed.
+ * @param pAhciPortTaskState    Pointer to the task which finished.
+ * @param rcReq                 IPRT status code of the completed request.
+ */
+static int ahciTransferComplete(PAHCIPort pAhciPort, PAHCIPORTTASKSTATE pAhciPortTaskState, int rcReq)
+{
+    bool fXchg = false;
+    bool fRedo = false;
+
+    ASMAtomicCmpXchgSize(&pAhciPortTaskState->enmTxState, AHCITXSTATE_FREE, AHCITXSTATE_ACTIVE, fXchg);
+
+    if (fXchg)
+    {
+        /* Free system resources occupied by the scatter gather list. */
+        if (pAhciPortTaskState->enmTxDir != AHCITXDIR_FLUSH)
+            ahciScatterGatherListDestroy(pAhciPort, pAhciPortTaskState);
+
+        if (pAhciPortTaskState->enmTxDir == AHCITXDIR_READ)
+        {
+            STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesRead, pAhciPortTaskState->cbTransfer);
+            pAhciPort->Led.Actual.s.fReading = 0;
+        }
+        else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_WRITE)
+        {
+            STAM_REL_COUNTER_ADD(&pAhciPort->StatBytesWritten, pAhciPortTaskState->cbTransfer);
+            pAhciPort->Led.Actual.s.fWriting = 0;
+        }
+        else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_TRIM)
+        {
+            ahciTrimRangesDestroy(pAhciPortTaskState);
+            pAhciPort->Led.Actual.s.fWriting = 0;
+        }
+
+        if (RT_FAILURE(rcReq))
+        {
+            /* Log the error. */
+            if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
+            {
+                if (pAhciPortTaskState->enmTxDir == AHCITXDIR_FLUSH)
+                    LogRel(("AHCI#%u: Flush returned rc=%Rrc\n",
+                            pAhciPort->iLUN, rcReq));
+                else if (pAhciPortTaskState->enmTxDir == AHCITXDIR_TRIM)
+                    LogRel(("AHCI#%u: Trim returned rc=%Rrc\n",
+                            pAhciPort->iLUN, rcReq));
+                else
+                    LogRel(("AHCI#%u: %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
+                            pAhciPort->iLUN,
+                            pAhciPortTaskState->enmTxDir == AHCITXDIR_READ
+                            ? "Read"
+                            : "Write",
+                            pAhciPortTaskState->uOffset,
+                            pAhciPortTaskState->cbTransfer, rcReq));
+            }
+
+            fRedo = ahciIsRedoSetWarning(pAhciPort, rcReq);
+            if (!fRedo)
+            {
+                pAhciPortTaskState->cmdHdr.u32PRDBC = 0;
+                pAhciPortTaskState->uATARegError = ID_ERR;
+                pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_ERR;
+                ASMAtomicCmpXchgPtr(&pAhciPort->pTaskErr, pAhciPortTaskState, NULL);
+            }
+            else
+                ASMAtomicOrU32(&pAhciPort->u32TasksNew, (1 << pAhciPortTaskState->uTag));
+        }
+        else
+        {
+            pAhciPortTaskState->cmdHdr.u32PRDBC = pAhciPortTaskState->cbTransfer;
+
+            pAhciPortTaskState->uATARegError = 0;
+            pAhciPortTaskState->uATARegStatus = ATA_STAT_READY | ATA_STAT_SEEK;
+
+            /* Write updated command header into memory of the guest. */
+            PDMDevHlpPhysWrite(pAhciPort->CTX_SUFF(pDevIns), pAhciPortTaskState->GCPhysCmdHdrAddr,
+                               &pAhciPortTaskState->cmdHdr, sizeof(CmdHdr));
+        }
+
+        /* Add the task to the cache. */
+        ASMAtomicWritePtr(&pAhciPort->aCachedTasks[pAhciPortTaskState->uTag], pAhciPortTaskState);
+        ASMAtomicDecU32(&pAhciPort->cTasksActive);
+
+        if (!fRedo)
+        {
+            if (pAhciPortTaskState->fQueued)
+            {
+                if (RT_SUCCESS(rcReq) && !ASMAtomicReadPtrT(&pAhciPort->pTaskErr, PAHCIPORTTASKSTATE))
+                    ASMAtomicOrU32(&pAhciPort->u32QueuedTasksFinished, (1 << pAhciPortTaskState->uTag));
+
+                /*
+                 * Always raise an interrupt after task completion; delaying
+                 * this (interrupt coalescing) increases latency and has a significant
+                 * impact on performance (see #5071)
+                 */
+                ahciSendSDBFis(pAhciPort, 0, true);
+            }
+            else
+                ahciSendD2HFis(pAhciPort, pAhciPortTaskState, pAhciPortTaskState->cmdFis, true);
+        }
+    }
+    else
+    {
+        /*
+         * Task was canceled, do the cleanup but DO NOT access the guest memory!
+         * The guest might use it for other things now because it doesn't know about that task anymore.
+         */
+        AssertMsg(pAhciPortTaskState->enmTxState == AHCITXSTATE_CANCELED,
+                  ("Task is not active but wasn't canceled!\n"));
+
+        ahciScatterGatherListFree(pAhciPortTaskState);
+
+        /* Leave a log message about the canceled request. */
+        if (pAhciPort->cErrors++ < MAX_LOG_REL_ERRORS)
+        {
+            if (pAhciPortTaskState->enmTxDir == AHCITXDIR_FLUSH)
+                LogRel(("AHCI#%u: Canceled flush returned rc=%Rrc\n",
+                        pAhciPort->iLUN, rcReq));
+            else
+                LogRel(("AHCI#%u: Canceled %s at offset %llu (%u bytes left) returned rc=%Rrc\n",
+                        pAhciPort->iLUN,
+                        pAhciPortTaskState->enmTxDir == AHCITXDIR_READ
+                        ? "read"
+                        : "write",
+                        pAhciPortTaskState->uOffset,
+                        pAhciPortTaskState->cbTransfer, rcReq));
+         }
+
+        /* Finally free the task state structure because it is completely unused now. */
+        RTMemFree(pAhciPortTaskState);
+    }
+
+    return VINF_SUCCESS;
+}
+
+/**
+ * Notification callback for a completed transfer.
+ *
+ * @returns VBox status code.
+ * @param   pInterface   Pointer to the interface.
+ * @param   pvUser       User data.
+ * @param   rcReq        IPRT Status code of the completed request.
+ */
+static DECLCALLBACK(int) ahciTransferCompleteNotify(PPDMIBLOCKASYNCPORT pInterface, void *pvUser, int rcReq)
+{
+    PAHCIPort pAhciPort = PDMIBLOCKASYNCPORT_2_PAHCIPORT(pInterface);
+    PAHCIPORTTASKSTATE pAhciPortTaskState = (PAHCIPORTTASKSTATE)pvUser;
+
+    ahciLog(("%s: pInterface=%p pvUser=%p uTag=%u\n",
+             __FUNCTION__, pInterface, pvUser, pAhciPortTaskState->uTag));
+
+    int rc = ahciTransferComplete(pAhciPort, pAhciPortTaskState, rcReq);
+
+    if (pAhciPort->cTasksActive == 0 && pAhciPort->pAhciR3->fSignalIdle)
+        PDMDevHlpAsyncNotificationCompleted(pAhciPort->pDevInsR3);
+    return rc;
 }
 
@@ -6590,5 +6609,7 @@
         case ATA_DATA_SET_MANAGEMENT:
         {
-            if (pAhciPort->pDrvBlock->pfnDiscard)
+            if (   pAhciPort->pDrvBlock->pfnDiscard
+                || (   pAhciPort->fAsyncInterface
+                    && pAhciPort->pDrvBlockAsync->pfnStartDiscard))
             {
                 rc = AHCITXDIR_TRIM;
@@ -6806,7 +6827,12 @@
                     if (enmTxDir != AHCITXDIR_FLUSH)
                     {
+                        bool fReadonly = true;
                         STAM_REL_COUNTER_INC(&pAhciPort->StatDMA);
 
-                        rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, (enmTxDir == AHCITXDIR_READ) ? false : true);
+                        if (   enmTxDir == AHCITXDIR_WRITE
+                            || enmTxDir == AHCITXDIR_TRIM)
+                            fReadonly = false;
+
+                        rc = ahciScatterGatherListCreate(pAhciPort, pAhciPortTaskState, fReadonly);
                         if (RT_FAILURE(rc))
                             AssertMsgFailed(("%s: Failed to process command %Rrc\n", __FUNCTION__, rc));
@@ -6817,4 +6843,14 @@
                         rc = pAhciPort->pDrvBlockAsync->pfnStartFlush(pAhciPort->pDrvBlockAsync,
                                                                       pAhciPortTaskState);
+                    }
+                    else if (enmTxDir == AHCITXDIR_TRIM)
+                    {
+                        rc = ahciTrimRangesCreate(pAhciPort, pAhciPortTaskState);
+                        if (RT_SUCCESS(rc))
+                        {
+                            pAhciPort->Led.Asserted.s.fWriting = pAhciPort->Led.Actual.s.fWriting = 1;
+                            rc = pAhciPort->pDrvBlockAsync->pfnStartDiscard(pAhciPort->pDrvBlockAsync, pAhciPortTaskState->paRanges,
+                                                                            pAhciPortTaskState->cRanges, pAhciPortTaskState);
+                        }
                     }
                     else if (enmTxDir == AHCITXDIR_READ)
Index: /trunk/src/VBox/Devices/Storage/DrvBlock.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvBlock.cpp	(revision 38877)
+++ /trunk/src/VBox/Devices/Storage/DrvBlock.cpp	(revision 38878)
@@ -286,5 +286,5 @@
 }
 
-static DECLCALLBACK(int) drvblockDiscard(PPDMIBLOCK pInterface, PPDMRANGE paRanges, unsigned cRanges)
+static DECLCALLBACK(int) drvblockDiscard(PPDMIBLOCK pInterface, PCRTRANGE paRanges, unsigned cRanges)
 {
     PDRVBLOCK pThis = PDMIBLOCK_2_DRVBLOCK(pInterface);
@@ -337,5 +337,5 @@
 
 
-/** @copydoc PDMIBLOCKASYNC::pfnStartFLush */
+/** @copydoc PDMIBLOCKASYNC::pfnStartFlush */
 static DECLCALLBACK(int) drvblockAsyncFlushStart(PPDMIBLOCKASYNC pInterface, void *pvUser)
 {
@@ -359,4 +359,22 @@
 
     return rc;
+}
+
+
+/** @copydoc PDMIBLOCKASYNC::pfnStartDiscard */
+static DECLCALLBACK(int) drvblockStartDiscard(PPDMIBLOCKASYNC pInterface, PCRTRANGE paRanges, unsigned cRanges, void *pvUser)
+{
+    PDRVBLOCK pThis = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
+
+    /*
+     * Check the state.
+     */
+    if (!pThis->pDrvMediaAsync)
+    {
+        AssertMsgFailed(("Invalid state! Not mounted!\n"));
+        return VERR_PDM_MEDIA_NOT_MOUNTED;
+    }
+
+    return pThis->pDrvMediaAsync->pfnStartDiscard(pThis->pDrvMediaAsync, paRanges, cRanges, pvUser);
 }
 
@@ -976,9 +994,13 @@
                                 N_("No media or async media interface below"));
 
+    /* Try to get the optional async interface. */
+    pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);
+
     if (pThis->pDrvMedia->pfnDiscard)
         pThis->IBlock.pfnDiscard = drvblockDiscard;
 
-    /* Try to get the optional async interface. */
-    pThis->pDrvMediaAsync = PDMIBASE_QUERY_INTERFACE(pBase, PDMIMEDIAASYNC);
+    if (   pThis->pDrvMediaAsync
+        && pThis->pDrvMediaAsync->pfnStartDiscard)
+        pThis->IBlockAsync.pfnStartDiscard = drvblockStartDiscard;
 
     if (RTUuidIsNull(&pThis->Uuid))
Index: /trunk/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp	(revision 38877)
+++ /trunk/src/VBox/Devices/Storage/DrvDiskIntegrity.cpp	(revision 38878)
@@ -51,5 +51,7 @@
     DRVDISKAIOTXDIR_WRITE,
     /** Flush */
-    DRVDISKAIOTXDIR_FLUSH
+    DRVDISKAIOTXDIR_FLUSH,
+    /** Discard */
+    DRVDISKAIOTXDIR_DISCARD
 } DRVDISKAIOTXDIR;
 
@@ -79,4 +81,8 @@
     /** I/O log entry if configured. */
     VDIOLOGENT      hIoLogEntry;
+    /** Ranges to discard. */
+    PCRTRANGE       paRanges;
+    /** Number of ranges. */
+    unsigned        cRanges;
 } DRVDISKAIOREQ, *PDRVDISKAIOREQ;
 
@@ -941,4 +947,40 @@
 }
 
+/** @copydoc PDMIMEDIAASYNC::pfnStartDiscard */
+static DECLCALLBACK(int) drvdiskintStartDiscard(PPDMIMEDIA pInterface, PPDMRANGE paRanges, unsigned cRanges, void *pvUser)
+{
+    int rc = VINF_SUCCESS;
+    VDIOLOGENT hIoLogEntry;
+    PDRVDISKINTEGRITY pThis = PDMIMEDIA_2_DRVDISKINTEGRITY(pInterface);
+    PDRVDISKAIOREQ pIoReq = drvdiskintIoReqAlloc(DRVDISKAIOTXDIR_DISCARD, 0, NULL, 0, 0, pvUser);
+    AssertPtr(pIoReq);
+
+    pIoReq->paRanges = paRanges;
+    pIoReq->cRanges  = cRanges;
+
+    if (pThis->hIoLogger)
+    {
+        rc = VDDbgIoLogStartDiscard(pThis->hIoLogger, true, (PVDRANGE)paRanges, cRanges, &hIoLogEntry);
+        AssertRC(rc);
+    }
+
+    rc = pThis->pDrvMedia->pfnStartDiscard(pThis->pDrvMedia, paRanges, cRanges, pIoReq);
+
+    if (rc == VINF_VD_ASYNC_IO_FINISHED)
+    {
+        if (pThis->hIoLogger)
+        {
+            int rc2 = VDDbgIoLogComplete(pThis->hIoLogger, pIoReq->hIoLogEntry, VINF_SUCCESS, NULL);
+            AssertRC(rc2);
+        }
+
+        RTMemFree(pIoReq);
+    }
+    else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
+        RTMemFree(pIoReq);
+
+    return rc;
+}
+
 /** @copydoc PDMIMEDIA::pfnFlush */
 static DECLCALLBACK(int) drvdiskintFlush(PPDMIMEDIA pInterface)
@@ -1069,4 +1111,6 @@
         else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_WRITE)
             rc = drvdiskintWriteRecord(pThis, pIoReq->paSeg, pIoReq->cSeg, pIoReq->off, pIoReq->cbTransfer);
+        else if (pIoReq->enmTxDir == DRVDISKAIOTXDIR_DISCARD)
+            rc = drvdiskintDiscardRecords(pThis, paRanges, cRanges);
         else
             AssertMsg(pIoReq->enmTxDir == DRVDISKAIOTXDIR_FLUSH, ("Huh?\n"));
@@ -1276,4 +1320,7 @@
     if (pThis->pDrvMedia->pfnDiscard)
         pThis->IMedia.pfnDiscard = drvdiskintDiscard;
+    if (   pThis->pDrvMediaAsync
+        && pThis->pDrvMediaAsync->pfnStartDiscard)
+        pThis->IMediaAsync.pfnStartDiscard = drvdiskintStartDiscard;
 
     if (pThis->fCheckConsistency)
Index: /trunk/src/VBox/Devices/Storage/DrvSCSI.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvSCSI.cpp	(revision 38877)
+++ /trunk/src/VBox/Devices/Storage/DrvSCSI.cpp	(revision 38878)
@@ -192,5 +192,5 @@
         case VSCSIIOREQTXDIR_UNMAP:
         {
-            PVSCSIRANGE paRanges;
+            PCRTRANGE paRanges;
             unsigned cRanges;
 
@@ -199,5 +199,5 @@
 
             pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1;
-            rc = pThis->pDrvBlock->pfnDiscard(pThis->pDrvBlock, (PPDMRANGE)paRanges, cRanges);
+            rc = pThis->pDrvBlock->pfnDiscard(pThis->pDrvBlock, paRanges, cRanges);
             pThis->pLed->Actual.s.fWriting = 0;
             break;
@@ -234,5 +234,6 @@
     if (enmTxDir == VSCSIIOREQTXDIR_READ)
         pThis->pLed->Actual.s.fReading = 0;
-    else if (enmTxDir == VSCSIIOREQTXDIR_WRITE)
+    else if (   enmTxDir == VSCSIIOREQTXDIR_WRITE
+             || enmTxDir == VSCSIIOREQTXDIR_UNMAP)
         pThis->pLed->Actual.s.fWriting = 0;
     else
@@ -299,4 +300,21 @@
                     && pThis->cErrors++ < MAX_LOG_REL_ERRORS)
                     LogRel(("SCSI#%u: Flush returned rc=%Rrc\n",
+                            pThis->pDrvIns->iInstance, rc));
+                break;
+            }
+            case VSCSIIOREQTXDIR_UNMAP:
+            {
+                PCRTRANGE paRanges;
+                unsigned cRanges;
+
+                rc = VSCSIIoReqUnmapParamsGet(hVScsiIoReq, &paRanges, &cRanges);
+                AssertRC(rc);
+
+                pThis->pLed->Asserted.s.fWriting = pThis->pLed->Actual.s.fWriting = 1;
+                rc = pThis->pDrvBlockAsync->pfnStartDiscard(pThis->pDrvBlockAsync, paRanges, cRanges, hVScsiIoReq);
+                if (   RT_FAILURE(rc)
+                    && rc != VERR_VD_ASYNC_IO_IN_PROGRESS
+                    && pThis->cErrors++ < MAX_LOG_REL_ERRORS)
+                    LogRel(("SCSI#%u: Discard returned rc=%Rrc\n",
                             pThis->pDrvIns->iInstance, rc));
                 break;
@@ -396,5 +414,7 @@
     *pfFeatures = 0;
 
-    if (pThis->pDrvBlock->pfnDiscard)
+    if (   pThis->pDrvBlock->pfnDiscard
+        || (   pThis->pDrvBlockAsync
+            && pThis->pDrvBlockAsync->pfnStartDiscard))
         *pfFeatures |= VSCSI_LUN_FEATURE_UNMAP;
 
@@ -886,4 +906,9 @@
     else
         LogRel(("SCSI#%d: using async I/O\n", pDrvIns->iInstance));
+
+    if (   pThis->pDrvBlock->pfnDiscard
+        || (   pThis->pDrvBlockAsync
+            && pThis->pDrvBlockAsync->pfnStartDiscard))
+        LogRel(("SCSI#%d: Enabled UNMAP support\n"));
 
     return VINF_SUCCESS;
Index: /trunk/src/VBox/Devices/Storage/DrvVD.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvVD.cpp	(revision 38877)
+++ /trunk/src/VBox/Devices/Storage/DrvVD.cpp	(revision 38878)
@@ -560,9 +560,5 @@
     PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pStorage;
 
-    int rc = drvvdAsyncIOFlushSync(pvUser, pStorage);
-    if (RT_SUCCESS(rc))
-        rc = PDMR3AsyncCompletionEpSetSize(pStorageBackend->pEndpoint, cbSize);
-
-    return rc;
+    return PDMR3AsyncCompletionEpSetSize(pStorageBackend->pEndpoint, cbSize);
 }
 
@@ -1674,11 +1670,10 @@
 }
 
-static DECLCALLBACK(int) drvvdDiscard(PPDMIMEDIA pInterface, PPDMRANGE paRanges, unsigned cRanges)
+static DECLCALLBACK(int) drvvdDiscard(PPDMIMEDIA pInterface, PCRTRANGE paRanges, unsigned cRanges)
 {
     LogFlowFunc(("\n"));
     PVBOXDISK pThis = PDMIMEDIA_2_VBOXDISK(pInterface);
 
-    /** @todo: Fix the cast properly without allocating temporary memory (maybe move the type to IPRT). */
-    int rc = VDDiscardRanges(pThis->pDisk, (PVDRANGE)paRanges, cRanges);
+    int rc = VDDiscardRanges(pThis->pDisk, paRanges, cRanges);
     LogFlowFunc(("returns %Rrc\n", rc));
     return rc;
@@ -1773,4 +1768,28 @@
     {
         rc = PDMR3BlkCacheFlush(pThis->pBlkCache, pvUser);
+        if (rc == VINF_AIO_TASK_PENDING)
+            rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
+        else if (rc == VINF_SUCCESS)
+            rc = VINF_VD_ASYNC_IO_FINISHED;
+    }
+    LogFlowFunc(("returns %Rrc\n", rc));
+    return rc;
+}
+
+static DECLCALLBACK(int) drvvdStartDiscard(PPDMIMEDIAASYNC pInterface, PCRTRANGE paRanges,
+                                           unsigned cRanges, void *pvUser)
+{
+    int rc = VINF_SUCCESS;
+    PVBOXDISK pThis = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
+
+    LogFlowFunc(("paRanges=%#p cRanges=%u pvUser=%#p\n",
+                 paRanges, cRanges, pvUser));
+
+    if (!pThis->pBlkCache)
+        rc = VDAsyncDiscardRanges(pThis->pDisk, paRanges, cRanges, drvvdAsyncReqComplete,
+                                  pThis, pvUser);
+    else
+    {
+        rc = PDMR3BlkCacheDiscard(pThis->pBlkCache, paRanges, cRanges, pvUser);
         if (rc == VINF_AIO_TASK_PENDING)
             rc = VERR_VD_ASYNC_IO_IN_PROGRESS;
@@ -1818,4 +1837,22 @@
             rc = VERR_INVALID_PARAMETER;
     }
+
+    if (rc == VINF_VD_ASYNC_IO_FINISHED)
+        PDMR3BlkCacheIoXferComplete(pThis->pBlkCache, hIoXfer, VINF_SUCCESS);
+    else if (RT_FAILURE(rc) && rc != VERR_VD_ASYNC_IO_IN_PROGRESS)
+        PDMR3BlkCacheIoXferComplete(pThis->pBlkCache, hIoXfer, rc);
+
+    return VINF_SUCCESS;
+}
+
+/** @copydoc FNPDMBLKCACHEXFERENQUEUEDISCARDDRV */
+static int drvvdBlkCacheXferEnqueueDiscard(PPDMDRVINS pDrvIns, PCRTRANGE paRanges,
+                                           unsigned cRanges, PPDMBLKCACHEIOXFER hIoXfer)
+{
+    int rc = VINF_SUCCESS;
+    PVBOXDISK pThis = PDMINS_2_DATA(pDrvIns, PVBOXDISK);
+
+    rc = VDAsyncDiscardRanges(pThis->pDisk, paRanges, cRanges,
+                              drvvdAsyncReqComplete, pThis, hIoXfer);
 
     if (rc == VINF_VD_ASYNC_IO_FINISHED)
@@ -2076,4 +2113,5 @@
     pThis->IMediaAsync.pfnStartWrite      = drvvdStartWrite;
     pThis->IMediaAsync.pfnStartFlush      = drvvdStartFlush;
+    pThis->IMediaAsync.pfnStartDiscard    = drvvdStartDiscard;
 
     /* Initialize supported VD interfaces. */
@@ -2575,5 +2613,8 @@
 
         if (!fDiscard)
+        {
             pThis->IMedia.pfnDiscard = NULL;
+            pThis->IMediaAsync.pfnStartDiscard = NULL;
+        }
 
         if (RT_SUCCESS(rc))
@@ -2666,4 +2707,5 @@
     if (   fUseBlockCache
         && !pThis->fShareable
+        && !fDiscard
         && RT_SUCCESS(rc))
     {
@@ -2695,4 +2737,5 @@
                                              drvvdBlkCacheXferComplete,
                                              drvvdBlkCacheXferEnqueue,
+                                             drvvdBlkCacheXferEnqueueDiscard,
                                              pszId);
                 if (rc == VERR_NOT_SUPPORTED)
Index: /trunk/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h
===================================================================
--- /trunk/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h	(revision 38877)
+++ /trunk/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h	(revision 38878)
@@ -149,5 +149,5 @@
         {
             /** Array of ranges to unmap. */
-            PVSCSIRANGE    paRanges;
+            PRTRANGE       paRanges;
             /** Number of ranges. */
             unsigned       cRanges;
@@ -335,5 +335,5 @@
  */
 int vscsiIoReqUnmapEnqueue(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq,
-                           PVSCSIRANGE paRanges, unsigned cRanges);
+                           PRTRANGE paRanges, unsigned cRanges);
 
 /**
Index: /trunk/src/VBox/Devices/Storage/VSCSI/VSCSIIoReq.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/VSCSI/VSCSIIoReq.cpp	(revision 38877)
+++ /trunk/src/VBox/Devices/Storage/VSCSI/VSCSIIoReq.cpp	(revision 38878)
@@ -88,5 +88,5 @@
 
 int vscsiIoReqUnmapEnqueue(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq,
-                           PVSCSIRANGE paRanges, unsigned cRanges)
+                           PRTRANGE paRanges, unsigned cRanges)
 {
     int rc = VINF_SUCCESS;
@@ -202,5 +202,5 @@
 }
 
-VBOXDDU_DECL(int) VSCSIIoReqUnmapParamsGet(VSCSIIOREQ hVScsiIoReq, PVSCSIRANGE *ppaRanges,
+VBOXDDU_DECL(int) VSCSIIoReqUnmapParamsGet(VSCSIIOREQ hVScsiIoReq, PCRTRANGE *ppaRanges,
                                            unsigned *pcRanges)
 {
Index: /trunk/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp	(revision 38877)
+++ /trunk/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp	(revision 38878)
@@ -447,7 +447,7 @@
                     if (cBlkDesc)
                     {
-                        PVSCSIRANGE paRanges;
-
-                        paRanges = (PVSCSIRANGE)RTMemAllocZ(cBlkDesc * sizeof(PVSCSIRANGE));
+                        PRTRANGE paRanges;
+
+                        paRanges = (PRTRANGE)RTMemAllocZ(cBlkDesc * sizeof(RTRANGE));
                         if (paRanges)
                         {
Index: /trunk/src/VBox/VMM/VMMR3/PDMDriver.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDMDriver.cpp	(revision 38877)
+++ /trunk/src/VBox/VMM/VMMR3/PDMDriver.cpp	(revision 38878)
@@ -1429,9 +1429,10 @@
                                                     PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete,
                                                     PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue,
+                                                    PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard,
                                                     const char *pcszId)
 {
     PDMDRV_ASSERT_DRVINS(pDrvIns);
     return PDMR3BlkCacheRetainDriver(pDrvIns->Internal.s.pVMR3, pDrvIns, ppBlkCache,
-                                     pfnXferComplete, pfnXferEnqueue, pcszId);
+                                     pfnXferComplete, pfnXferEnqueue, pfnXferEnqueueDiscard, pcszId);
 }
 
