Index: /trunk/include/VBox/VBoxHDD-new.h
===================================================================
--- /trunk/include/VBox/VBoxHDD-new.h	(revision 10714)
+++ /trunk/include/VBox/VBoxHDD-new.h	(revision 10715)
@@ -178,6 +178,12 @@
  * used for querying information, and nothing else. */
 #define VD_OPEN_FLAGS_INFO          RT_BIT(3)
+/** Open image for asynchronous access.
+ *  Only available if VD_CAP_ASYNC_IO is set
+ *  Check with VDIsAsynchonousIoSupported wether
+ *  asynchronous I/O is really supported for this file.
+ */
+#define VD_OPEN_FLAGS_ASYNC_IO      RT_BIT(4)
 /** Mask of valid flags. */
-#define VD_OPEN_FLAGS_MASK          (VD_OPEN_FLAGS_NORMAL | VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_HONOR_ZEROES | VD_OPEN_FLAGS_HONOR_SAME | VD_OPEN_FLAGS_INFO)
+#define VD_OPEN_FLAGS_MASK          (VD_OPEN_FLAGS_NORMAL | VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_HONOR_ZEROES | VD_OPEN_FLAGS_HONOR_SAME | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_ASYNC_IO)
 /** @}*/
 
@@ -196,9 +202,10 @@
 /** Supports being used as differencing image format backend. */
 #define VD_CAP_DIFF                 RT_BIT(4)
+/** Supports asynchronous I/O operations for at least some configurations. */
+#define VD_CAP_ASYNC                RT_BIT(5)
 /** The backend operates on files. The caller needs to know to handle the
  * location appropriately. */
 #define VD_CAP_FILE                 RT_BIT(6)
 /** @}*/
-
 
 /**
@@ -213,17 +220,340 @@
 } VDBACKENDINFO, *PVDBACKENDINFO;
 
-
-/**
- * Error message callback.
- *
- * @param   pvUser          The opaque data passed on container creation.
- * @param   rc              The VBox error code.
- * @param   RT_SRC_POS_DECL Use RT_SRC_POS.
- * @param   pszFormat       Error message format string.
- * @param   va              Error message arguments.
- */
-typedef DECLCALLBACK(void) FNVDERROR(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va);
-/** Pointer to a FNVDERROR(). */
-typedef FNVDERROR *PFNVDERROR;
+/**
+ * Supported interface types.
+ */
+typedef enum VDINTERFACETYPE
+{
+    /** First valid interface. */
+    VDINTERFACETYPE_FIRST = 0,
+    /** Interface to pass error message to upper layers. */
+    VDINTERFACETYPE_ERROR = VDINTERFACETYPE_FIRST,
+    /** Interface for asynchronous I/O operations. */
+    VDINTERFACETYPE_ASYNCIO,
+    /** Interface for progress notification. */
+    VDINTERFACETYPE_PROGRESS,
+    /** invalid interface. */
+    VDINTERFACETYPE_INVALID
+} VDINTERFACETYPE;
+
+/**
+ * Common structure for all interfaces.
+ */
+typedef struct VDINTERFACE
+{
+    /** Human readable interface name. */
+    const char         *pszInterfaceName;
+    /** The size of the struct. */
+    uint32_t            cbSize;
+    /** Pointer to the next common interface structure. */
+    struct VDINTERFACE *pNext;
+    /** Interface type. */
+    VDINTERFACETYPE     enmInterface;
+    /** Opaque user data which is passed on every call. */
+    void               *pvUser;
+    /** Pointer to the function call table of the interface. 
+     *  As this is opaque this must be casted to the right interface
+     *  struct defined below based on the interface type in enmInterface. */
+    void               *pCallbacks;
+} VDINTERFACE, *PVDINTERFACE;
+/** Pointer to a const PVDINTERFACE. */
+typedef const PVDINTERFACE PCVDINTERFACE;
+
+/**
+ * Helper functions to handle interface lists.
+ */
+
+/**
+ * Get a specific interface from a list of interfaces specified by the type.
+ *
+ * @returns Pointer to the matching interface or NULL if none was found.
+ * @param   pInterfaces     Pointer to the first interface in the list.
+ * @param   enmInterface    Interface to search for.
+ */
+DECLINLINE(PVDINTERFACE) VDGetInterfaceFromList(PVDINTERFACE pInterfaces, VDINTERFACETYPE enmInterface)
+{
+    AssertMsgReturn(   (enmInterface >= VDINTERFACETYPE_FIRST)
+                    && (enmInterface < VDINTERFACETYPE_INVALID),
+                    ("enmInterface=%u", enmInterface), NULL);
+
+    while (pInterfaces)
+    {
+        /* Sanity checks. */
+        AssertMsgBreak(pInterfaces->cbSize == sizeof(VDINTERFACE),
+                       ("cbSize=%u\n", pInterfaces->cbSize));
+                       
+        if (pInterfaces->enmInterface == enmInterface)
+            return pInterfaces;
+        pInterfaces = pInterfaces->pNext;
+    }
+
+    /* No matching interface was found. */
+    return NULL;
+}
+
+/**
+ * Initialize a common interface structure.
+ *
+ * @return VBox status code.
+ * @param  pInterface   Pointer to an unitialized common interface structure.
+ * @param  pszName      Name of the interface.
+ * @param  enmInterface Type of the interface.
+ * @param  pCallbacks   The callback table of the interface.
+ * @param  pvUser       Opaque user data passed on every function call.
+ * @param  pNext        Pointer to the next supported interface if any.
+ */
+DECLINLINE(int) VDInterfaceCreate(PVDINTERFACE pInterface, const char *pszName,
+                                  VDINTERFACETYPE enmInterface, void *pCallbacks,
+                                  void *pvUser, PVDINTERFACE pNext)
+{
+
+    /** Argument checks. */
+    AssertMsgReturn(   (enmInterface >= VDINTERFACETYPE_FIRST)
+                    && (enmInterface < VDINTERFACETYPE_INVALID),
+                    ("enmInterface=%u", enmInterface), VERR_INVALID_PARAMETER);
+
+    AssertMsgReturn(VALID_PTR(pCallbacks),
+                    ("pCallbacks=%#p", pCallbacks),
+                    VERR_INVALID_PARAMETER);
+
+    pInterface->cbSize           = sizeof(VDINTERFACE);
+    pInterface->pszInterfaceName = pszName;
+    pInterface->enmInterface     = enmInterface;
+    pInterface->pCallbacks       = pCallbacks;
+    pInterface->pvUser           = pvUser;
+    pInterface->pNext            = pNext;
+    return VINF_SUCCESS;
+}
+
+/**
+ * Interface to deliver error messages to upper layers.
+ */
+typedef struct VDINTERFACEERROR
+{
+    /**
+     * Size of the error interface.
+     */
+    uint32_t    cbSize;
+
+    /**
+     * Interface type.
+     */
+    VDINTERFACETYPE enmInterface;
+
+    /**
+     * Error message callback.
+     *
+     * @param   pvUser          The opaque data passed on container creation.
+     * @param   rc              The VBox error code.
+     * @param   RT_SRC_POS_DECL Use RT_SRC_POS.
+     * @param   pszFormat       Error message format string.
+     * @param   va              Error message arguments.
+     */
+    DECLR3CALLBACKMEMBER(void, pfnError, (void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va));
+
+} VDINTERFACEERROR, *PVDINTERFACEERROR;
+
+/**
+ * Get error interface from opaque callback table.
+ *
+ * @return Pointer to the callback table.
+ * @param  pCallbacks Opaque interface pointer.
+ */
+DECLINLINE(PVDINTERFACEERROR) VDGetInterfaceError(void *pCallbacks)
+{
+    PVDINTERFACEERROR pInterfaceError = (PVDINTERFACEERROR)pCallbacks;
+
+    /* Do basic checks. */
+    AssertMsgReturn(   (pInterfaceError->cbSize == sizeof(VDINTERFACEERROR))
+                    && (pInterfaceError->enmInterface == VDINTERFACETYPE_ERROR),
+                    ("Not an error interface\n"), NULL);
+
+    return pInterfaceError;
+}
+
+/** 
+ * Completion callback which is called by the interface owner
+ * to inform the backend that a task finished.
+ * 
+ * @returns VBox status code.
+ * @param   pvUser          Opaque user data which is passed on request submission.
+ */
+typedef DECLCALLBACK(int) FNVDCOMPLETED(void *pvUser);
+/** Pointer to FNVDCOMPLETED() */
+typedef FNVDCOMPLETED *PFNVDCOMPLETED;
+
+
+/**
+ * Support interface for asynchronous I/O
+ */
+typedef struct VDINTERFACEASYNCIO
+{
+    /**
+     * Size of the async interface.
+     */
+    uint32_t    cbSize;
+
+    /**
+     * Interface type.
+     */
+    VDINTERFACETYPE enmInterface;
+
+    /**
+     * Open callback
+     *
+     * @returns VBox status code.
+     * @param   pvUser          The opaque data passed on container creation.
+     * @param   pszLocation     Name of the location to open.
+     * @param   fReadonly       Whether to open the storage medium read only.
+     * @param   ppStorage       Where to store the opaque storage handle.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnOpen, (void *pvUser, const char *pszLocation, bool fReadonly, void **ppStorage));
+
+    /**
+     * Close callback.
+     *
+     * @returns VBox status code.
+     * @param   pvUser          The opaque data passed on container creation.
+     * @param   pStorage        The opaque storage handle to close.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnClose, (void *pvUser, void *pStorage));
+
+    /**
+     * Synchronous write callback.
+     *
+     * @returns VBox status code.
+     * @param   pvUser          The opaque data passed on container creation.
+     * @param   pStorage        The storage handle to use.
+     * @param   uOffset         The offset to start from.
+     * @þaram   cbWrite         How many bytes to write.
+     * @param   pvBuf           Pointer to the bits need to be written.
+     * @param   pcbWritten      Where to store how many bytes where actually written.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnWrite, (void *pvUser, void *pStorage, uint64_t uOffset, 
+                                         size_t cbWrite, const void *pvBuf, size_t *pcbWritten));
+
+    /**
+     * Synchronous read callback.
+     *
+     * @returns VBox status code.
+     * @param   pvUser          The opaque data passed on container creation.
+     * @param   pStorage        The storage handle to use.
+     * @param   uOffset         The offset to start from.
+     * @þaram   cbRead          How many bytes to read.
+     * @param   pvBuf           Where to store the read bits.
+     * @param   pcbRead         Where to store how many bytes where actually read.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnRead, (void *pvUser, void *pStorage, uint64_t uOffset, 
+                                        size_t cbRead, void *pvBuf, size_t *pcbRead));
+
+    /**
+     * Flush data to the storage backend.
+     *
+     * @returns VBox statis code.
+     * @param   pvUser          The opaque data passed on container creation.
+     * @param   pStorage        The storage handle to flush.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnFlush, (void *pvUser, void *pStorage));
+
+    /**
+     * Prepare an asynchronous read task.
+     *
+     * @returns VBox status code.
+     * @param   pvUser         The opqaue user data passed on container creation.
+     * @param   pStorage       The storage handle.
+     * @param   uOffset        The offset to start reading from.
+     * @param   pvBuf          Where to store read bits.
+     * @param   cbRead         How many bytes to read.
+     * @param   ppTask         Where to store the opaque task handle.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnPrepareRead, (void *pvUser, void *pStorage, uint64_t uOffset, 
+                                               void *pvBuf, size_t cbRead, void **ppTask));
+
+    /**
+     * Prepare an asynchronous write task.
+     *
+     * @returns VBox status code.
+     * @param   pvUser         The opaque user data passed on conatiner creation.
+     * @param   pStorage       The storage handle.
+     * @param   uOffset        The offset to start writing to.
+     * @param   pvBuf          Where to read the data from.
+     * @param   cbWrite        How many bytes to write.
+     * @param   ppTask         Where to store the opaque task handle.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnPrepareWrite, (void *pvUser, void *pStorage, uint64_t uOffset, 
+                                                void *pvBuf, size_t cbWrite, void **ppTask));
+
+    /**
+     * Submit an array of tasks for processing
+     *
+     * @returns VBox status code.
+     * @param   pvUser        The opaque user data passed on container creation.
+     * @param   apTasks       Array of task handles to submit.
+     * @param   cTasks        How many tasks to submit.
+     * @param   pvUser2       User data which is passed on completion.
+     * @param   pvUserCaller  Opaque user data the caller of VDAsyncWrite/Read passed.
+     * @param   pfnTasksCompleted Pointer to callback which is called on request completion.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnTasksSubmit, (void *pvUser, void *apTasks[], unsigned cTasks, void *pvUser2,
+                                               void *pvUserCaller, PFNVDCOMPLETED pfnTasksCompleted));
+
+} VDINTERFACEASYNCIO, *PVDINTERFACEASYNCIO;
+
+/**
+ * Get async I/O interface from opaque callback table.
+ *
+ * @return Pointer to the callback table.
+ * @param  pCallbacks Opaque interface pointer.
+ */
+DECLINLINE(PVDINTERFACEASYNCIO) VDGetInterfaceAsyncIO(void *pCallbacks)
+{
+    PVDINTERFACEASYNCIO pInterfaceAsyncIO = (PVDINTERFACEASYNCIO)pCallbacks;
+
+    /* Do basic checks. */
+    AssertMsgReturn(   (pInterfaceAsyncIO->cbSize == sizeof(VDINTERFACEASYNCIO))
+                    && (pInterfaceAsyncIO->enmInterface == VDINTERFACETYPE_ASYNCIO),
+                    ("Not an async I/O interface\n"), NULL);
+
+    return pInterfaceAsyncIO;
+}
+
+/**
+ * Progress notification interface
+ */
+typedef struct VDINTERFACEPROGRESS
+{
+    /**
+     * Size of the progress interface.
+     */
+    uint32_t    cbSize;
+
+    /**
+     * Interface type.
+     */
+    VDINTERFACETYPE enmInterface;
+
+    /**
+     * Progress notification callbacks.
+     */
+    PFNVMPROGRESS   pfnProgress;
+} VDINTERFACEPROGRESS, *PVDINTERFACEPROGRESS;
+
+/**
+ * Get progress interface from opaque callback table.
+ *
+ * @return Pointer to the callback table.
+ * @param  pCallbacks Opaque interface pointer.
+ */
+DECLINLINE(PVDINTERFACEPROGRESS) VDGetInterfaceProgress(void *pCallbacks)
+{
+    PVDINTERFACEPROGRESS pInterfaceProgress = (PVDINTERFACEPROGRESS)pCallbacks;
+
+    /* Do basic checks. */
+    AssertMsgReturn(   (pInterfaceProgress->cbSize == sizeof(VDINTERFACEPROGRESS))
+                    && (pInterfaceProgress->enmInterface == VDINTERFACETYPE_PROGRESS),
+                    ("Not an progress notification interface\n"), NULL);
+
+    return pInterfaceProgress;
+}
 
 
@@ -250,4 +580,13 @@
                                 unsigned *pcEntriesUsed);
 
+/**
+ * Lists the capablities of a backend indentified by its name.
+ * Free all returned names with RTStrFree() when you no longer need them.
+ *
+ * @returns VBox status code.
+ * @param   pszBackend      The backend name.
+ * @param   pEntries        Pointer to an entry.
+ */
+VBOXDDU_DECL(int) VDBackendInfoOne(const char *pszBackend, PVDBACKENDINFO pEntry);
 
 /**
@@ -256,10 +595,8 @@
  *
  * @returns VBox status code.
- * @param   pfnError        Callback for setting extended error information.
- * @param   pvErrorUser     Opaque parameter for pfnError.
+ * @param   pInterfaces     Pointer to the first supported interface.
  * @param   ppDisk          Where to store the reference to HDD container.
  */
-VBOXDDU_DECL(int) VDCreate(PFNVDERROR pfnError, void *pvErrorUser,
-                           PVBOXHDD *ppDisk);
+VBOXDDU_DECL(int) VDCreate(PVDINTERFACE pInterfaces, PVBOXHDD *ppDisk);
 
 /**
@@ -559,4 +896,16 @@
 
 /**
+ * List the capabilities of image backend in HDD container.
+ *
+ * @returns VBox status code.
+ * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
+ * @param   pDisk           Pointer to the HDD container.
+ * @param   nImage          Image number, counts from 0. 0 is always base image of container.
+ * @param   pbackendInfo    Where to store the backend information.
+ */
+VBOXDDU_DECL(int) VDBackendInfoSingle(PVBOXHDD pDisk, unsigned nImage,
+                                      PVDBACKENDINFO pBackendInfo);
+
+/**
  * Get flags of image in HDD container.
  *
@@ -714,4 +1063,49 @@
 VBOXDDU_DECL(void) VDDumpImages(PVBOXHDD pDisk);
 
+
+/**
+ * Query if asynchronous operations are supported for this disk.
+ *
+ * @returns VBox status code.
+ * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
+ * @param   pDisk           Pointer to the HDD container.
+ * @param   nImage          Image number, counts from 0. 0 is always base image of container.
+ * @param   pfAIOSupported  Where to store if async IO is supported.
+ */
+VBOXDDU_DECL(int) VDImageIsAsyncIOSupported(PVBOXHDD pDisk, unsigned nImage, bool *pfAIOSupported);
+
+
+/**
+ * Start a asynchronous read request.
+ *
+ * @returns VBox status code.
+ * @param   pDisk           Pointer to the HDD container.
+ * @param   uOffset         The offset of the virtual disk to read from.
+ * @param   cbRead          How many bytes to read.
+ * @param   paSeg           Pointer to an array of segments.
+ * @param   cSeg            Number of segments in the array.
+ * @param   pvUser          User data which is passed on completion
+ */
+VBOXDDU_DECL(int) VDAsyncRead(PVBOXHDD pDisk, uint64_t uOffset, size_t cbRead, 
+                              PPDMDATASEG paSeg, unsigned cSeg,
+                              void *pvUser);
+
+
+/**
+ * Start a asynchronous write request.
+ *
+ * @returns VBox status code.
+ * @param   pDisk           Pointer to the HDD container.
+ * @param   uOffset         The offset of the virtual disk to write to.
+ * @param   cbWrtie         How many bytes to write.
+ * @param   paSeg           Pointer to an array of segments.
+ * @param   cSeg            Number of segments in the array.
+ * @param   pvUser          User data which is passed on completion.
+ */
+VBOXDDU_DECL(int) VDAsyncWrite(PVBOXHDD pDisk, uint64_t uOffset, size_t cbWrite,
+                               PPDMDATASEG paSeg, unsigned cSeg,
+                               void *pvUser);
+
+
 __END_DECLS
 
Index: /trunk/include/VBox/err.h
===================================================================
--- /trunk/include/VBox/err.h	(revision 10714)
+++ /trunk/include/VBox/err.h	(revision 10715)
@@ -1049,4 +1049,8 @@
 /** Configuration value not found. */
 #define VERR_VDI_VALUE_NOT_FOUND                    (-3216)
+/** Asynchronous I/O request finished. */
+#define VINF_VDI_ASYNC_IO_FINISHED                  3218
+/** Asynchronous I/O is not finished yet. */
+#define VERR_VDI_ASYNC_IO_IN_PROGRESS               (-3219)
 /** @} */
 
Index: /trunk/include/VBox/pdmifs.h
===================================================================
--- /trunk/include/VBox/pdmifs.h	(revision 10714)
+++ /trunk/include/VBox/pdmifs.h	(revision 10715)
@@ -1115,20 +1115,4 @@
 
 
-/**
- * Data transport buffer (scatter/gather)
- */
-typedef struct PDMIDATATRANSPORTSEG
-{
-    /** Length of buffer in entry. */
-    size_t  cbSeg;
-    /** Pointer to the start of the buffer. */
-    void   *pvSeg;
-} PDMIDATATRANSPORTSEG;
-/** Pointer to a data transport segment. */
-typedef PDMIDATATRANSPORTSEG *PPDMIDATATRANSPORTSEG;
-/** Pointer to a const data transport segment. */
-typedef PDMIDATATRANSPORTSEG const *PCPDMIDATATRANSPORTSEG;
-
-
 /** Pointer to an asynchronous iSCSI transport driver interface. */
 typedef struct PDMIISCSITRANSPORTASYNC *PPDMIISCSITRANSPORTASYNC;
@@ -1207,30 +1191,12 @@
 {
     /**
-     * Notify completion of a read task.
-     *
-     * @returns VBox status code.
-     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
-     * @param   off             Offset the task read from.
-     * @param   pSeg            Pointer to the first element in the gather list.
-     * @param   cSeg            Number of segments in the gather list.
-     * @param   cbRead          Number of bytes read.
-     * @param   pvUser          The user argument given in pfnStartRead.
-     * @thread  Any thread.
-     */
-    DECLR3CALLBACKMEMBER(int, pfnReadCompleteNotify, (PPDMIBLOCKASYNCPORT pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser));
-
-    /**
-     * Notify completion of a write task.
-     *
-     * @returns VBox status code.
-     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
-     * @param   off             Offset the task has written to.
-     * @param   pSeg            Pointer to the first element in the scatter list.
-     * @param   cSeg            Number of segments in the scatter list.
-     * @param   cbWritten       Number of bytes actually written.
-     * @param   pvUser          The user argument given in pfnStartWrite.
-     * @thread  Any thread.
-     */
-    DECLR3CALLBACKMEMBER(int, pfnWriteCompleteNotify, (PPDMIBLOCKASYNCPORT pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbWritten, void *pvUser));
+     * Notify completion of a asynchronous transfer.
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   pvUser          The user argument given in pfnStartWrite/Read.
+     * @thread  Any thread.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnTransferCompleteNotify, (PPDMIBLOCKASYNCPORT pInterface, void *pvUser));
 } PDMIBLOCKASYNCPORT;
 
@@ -1256,5 +1222,5 @@
      * @thread  Any thread.
      */
-    DECLR3CALLBACKMEMBER(int, pfnStartRead,(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser));
+    DECLR3CALLBACKMEMBER(int, pfnStartRead,(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMDATASEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser));
 
     /**
@@ -1270,5 +1236,5 @@
      * @thread  Any thread.
      */
-    DECLR3CALLBACKMEMBER(int, pfnStartWrite,(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbWrite, void *pvUser));
+    DECLR3CALLBACKMEMBER(int, pfnStartWrite,(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMDATASEG pSeg, unsigned cSeg, size_t cbWrite, void *pvUser));
 
 } PDMIBLOCKASYNC;
@@ -1284,30 +1250,12 @@
 {
     /**
-     * Notify completion of a read task.
-     *
-     * @returns VBox status code.
-     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
-     * @param   off             Offset the task read from.
-     * @param   pSeg            Pointer to the first element in the scatter list.
-     * @param   cSeg            Number of entries in the list.
-     * @param   cbRead          Number of bytes read.
-     * @param   pvUser          The user argument given in pfnStartRead.
-     * @thread  Any thread.
-     */
-    DECLR3CALLBACKMEMBER(int, pfnReadCompleteNotify, (PPDMIMEDIAASYNCPORT pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser));
-
-    /**
-     * Notify completion of a write task.
-     *
-     * @returns VBox status code.
-     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
-     * @param   off             Offset the task has written to.
-     * @param   pSeg            Pointer to the first element in the gather list.
-     * @param   cSeg            Number of entries in the list.
-     * @param   cbWritten       Number of bytes actually written.
+     * Notify completion of a task.
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
      * @param   pvUser          The user argument given in pfnStartWrite.
      * @thread  Any thread.
      */
-    DECLR3CALLBACKMEMBER(int, pfnWriteCompleteNotify, (PPDMIMEDIAASYNCPORT pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbWritten, void *pvUser));
+    DECLR3CALLBACKMEMBER(int, pfnTransferCompleteNotify, (PPDMIMEDIAASYNCPORT pInterface, void *pvUser));
 } PDMIMEDIAASYNCPORT;
 
@@ -1333,5 +1281,5 @@
      * @thread  Any thread.
      */
-    DECLR3CALLBACKMEMBER(int, pfnStartRead,(PPDMIMEDIAASYNC pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser));
+    DECLR3CALLBACKMEMBER(int, pfnStartRead,(PPDMIMEDIAASYNC pInterface, uint64_t off, PPDMDATASEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser));
 
     /**
@@ -1347,5 +1295,5 @@
      * @thread  Any thread.
      */
-    DECLR3CALLBACKMEMBER(int, pfnStartWrite,(PPDMIMEDIAASYNC pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbWrite, void *pvUser));
+    DECLR3CALLBACKMEMBER(int, pfnStartWrite,(PPDMIMEDIAASYNC pInterface, uint64_t off, PPDMDATASEG pSeg, unsigned cSeg, size_t cbWrite, void *pvUser));
 
 } PDMIMEDIAASYNC;
@@ -1361,32 +1309,13 @@
 {
     /**
-     * Notify completion of a read task.
-     *
-     * @returns VBox status code.
-     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
-     * @param   off             Offset the task read from.
-     * @param   pSeg            Pointer to the first element in the scatter list.
-     * @param   cSeg            Number of entries in the list.
-     * @param   cbRead          Number of bytes read.
-     * @param   pvUser          The user argument given in pfnStartRead.
-     * @thread  Any thread.
-     */
-    DECLR3CALLBACKMEMBER(int, pfnReadCompleteNotify, (PPDMITRANSPORTASYNCPORT pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg,
-                                                      size_t cbRead, void *pvUser));
-
-    /**
-     * Notify completion of a write task.
-     *
-     * @returns VBox status code.
-     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
-     * @param   off             Offset the task has written to.
-     * @param   pSeg            Pointer to the first element in the gather list.
-     * @param   cSeg            Number of entries in the list.
-     * @param   cbWritten       Number of bytes actually written.
-     * @param   pvUser          The user argument given in pfnStartWrite.
-     * @thread  Any thread.
-     */
-    DECLR3CALLBACKMEMBER(int, pfnWriteCompleteNotify, (PPDMITRANSPORTASYNCPORT pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg,
-                                                       size_t cbWritten, void *pvUser));
+     * Notify completion of tasks.
+     *
+     * @returns VBox status code.
+     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
+     * @param   pvUser          The user argument given in pfnTasksSubmit.
+     * @thread  Any thread.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnTaskCompleteNotify, (PPDMITRANSPORTASYNCPORT pInterface, void *pvUser));
+
 } PDMITRANSPORTASYNCPORT;
 
@@ -1406,11 +1335,13 @@
      * @returns VBox status code.
      * @param   pInterface      Pointer to the interface structure containint the called function pointer.
+     * @param   pStorage        The storage handle to read from.
      * @param   off             Offset to start reading from.
-     * @param   pvBuf           here to store the read bits.
+     * @param   pvBuf           Where to store the read bits.
      * @param   cbRead          Number of bytes to read.
      * @param   pcbRead         Where to store the number of bytes actually read.
      * @thread  Any thread.
      */
-    DECLR3CALLBACKMEMBER(int, pfnReadSynchronous, (PPDMITRANSPORTASYNC pInterface, uint64_t off, void *pvBuf, size_t cbRead, size_t *pcbRead));
+    DECLR3CALLBACKMEMBER(int, pfnReadSynchronous, (PPDMITRANSPORTASYNC pInterface, void *pStorage,
+                                                   uint64_t off, void *pvBuf, size_t cbRead, size_t *pcbRead));
 
     /**
@@ -1420,41 +1351,13 @@
      * @returns VBox status code.
      * @param   pInterface      Pointer to the interface structure containint the called function pointer.
+     * @param   pStorage        The storage handle to write to.
      * @param   off             Offset to start reading from.
-     * @param   pvBuf           here to store the read bits.
+     * @param   pvBuf           Pointer to the buffer which contains the data to write.
      * @param   cbWrite         Number of bytes to read.
      * @param   pcbWritten      Where to store the number of bytes actually read.
      * @thread  Any thread.
      */
-    DECLR3CALLBACKMEMBER(int, pfnWriteSynchronous, (PPDMITRANSPORTASYNC pInterface, uint64_t off, void *pvBuf, size_t cbWrite, size_t *pcbWritten));
-
-    /**
-     * Start asynchronous read.
-     *
-     * @returns VBox status code.
-     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
-     * @param   off             Offset to start reading from.
-     * @param   pSeg            Pointer to the first element in the scatter list.
-     * @param   cSeg            Number of entries in the list.
-     * @param   cbRead          Number of bytes to read.
-     * @param   pvUser          User argument returned in completion callback.
-     * @thread  Any thread.
-     */
-    DECLR3CALLBACKMEMBER(int, pfnReadStartAsynchronous,(PPDMITRANSPORTASYNC pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg,
-                                                        size_t cbRead, void *pvUser));
-
-    /**
-     * Start asynchronous write.
-     *
-     * @returns VBox status code.
-     * @param   pInterface      Pointer to the interface structure containing the called function pointer.
-     * @param   off             Offset to start writing at.
-     * @param   pSeg            Pointer to the first element in the gather list.
-     * @param   cSeg            Number of entries in the list.
-     * @param   cbWrite         Number of bytes to write.
-     * @param   pvUser          User argument returned in completion callback.
-     * @thread  Any thread.
-     */
-    DECLR3CALLBACKMEMBER(int, pfnWriteStartAsynchronous,(PPDMITRANSPORTASYNC pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg,
-                                                         size_t cbWrite, void *pvUser));
+    DECLR3CALLBACKMEMBER(int, pfnWriteSynchronous, (PPDMITRANSPORTASYNC pInterface, void *pStorage,
+                                                    uint64_t off, const void *pvBuf, size_t cbWrite, size_t *pcbWritten));
 
     /**
@@ -1464,7 +1367,8 @@
      * @returns VBox status code.
      * @param   pInterface      Pointer to the interface structure containing the called function pointer.
-     * @thread  Any thread.
-     */
-    DECLR3CALLBACKMEMBER(int, pfnFlushSynchronous,(PPDMITRANSPORTASYNC pInterface));
+     * @param   pStorage        The storage handle to flush-
+     * @thread  Any thread.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnFlushSynchronous,(PPDMITRANSPORTASYNC pInterface, void *pStorage));
 
     /**
@@ -1473,7 +1377,8 @@
      * @returns Media size in bytes.
      * @param   pInterface      Pointer to the interface structure containing the called function pointer.
-     * @thread  Any thread.
-     */
-    DECLR3CALLBACKMEMBER(uint64_t, pfnGetSize,(PPDMITRANSPORTASYNC pInterface));
+     * @param   pStorage        The storage handle.
+     * @thread  Any thread.
+     */
+    DECLR3CALLBACKMEMBER(uint64_t, pfnGetSize,(PPDMITRANSPORTASYNC pInterface, void *pStorage));
 
     /**
@@ -1483,7 +1388,8 @@
      * @returns false if read/write.
      * @param   pInterface      Pointer to the interface structure containing the called function pointer.
-     * @thread  Any thread.
-     */
-    DECLR3CALLBACKMEMBER(bool, pfnIsReadOnly,(PPDMITRANSPORTASYNC pInterface));
+     * @param   pStorage        The storage handle.
+     * @thread  Any thread.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnIsReadOnly,(PPDMITRANSPORTASYNC pInterface, void *pStorage));
 
     /**
@@ -1494,7 +1400,8 @@
      * @param   pszPath         The path to open.
      * @param   fReadonly       If the target shoudl opened readonly.
-     * @thread  Any thread.
-     */
-    DECLR3CALLBACKMEMBER(int, pfnOpen, (PPDMITRANSPORTASYNC pInterface, const char *pszTargetPath, bool fReadonly));
+     * @param   ppStorage       Where to store the storage handle.
+     * @thread  Any thread.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnOpen, (PPDMITRANSPORTASYNC pInterface, const char *pszTargetPath, bool fReadonly, void **ppStorage));
 
     /**
@@ -1503,8 +1410,47 @@
      * @returns VBox status code.
      * @param   pInterface      Pointer to the interface structure containing the called function pointer.
-     * @thread  Any thread.
-     */
-    DECLR3CALLBACKMEMBER(int, pfnClose, (PPDMITRANSPORTASYNC pInterface));
-
+     * @param   pStorage        The storage handle to close.
+     * @thread  Any thread.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnClose, (PPDMITRANSPORTASYNC pInterface, void *pStorage));
+
+    /**
+     * Prepare an asynchronous read task.
+     *
+     * @returns VBox status code.
+     * @param   pInterface     Pointer to the interface structure containing the called function pointer.
+     * @param   pStorage       The storage handle.
+     * @param   uOffset        The offset to start reading from.
+     * @param   pvBuf          Where to store read bits.
+     * @param   cbRead         How many bytes to read.
+     * @param   ppTask         Where to store the opaque task handle.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnPrepareRead, (PPDMITRANSPORTASYNC pInterface, void *pStorage, uint64_t uOffset, 
+                                               void *pvBuf, size_t cbRead, void **ppTask));
+
+    /**
+     * Prepare an asynchronous write task.
+     *
+     * @returns VBox status code.
+     * @param   pInterface     Pointer to the interface structure containing the called function pointer.
+     * @param   pStorage       The storage handle.
+     * @param   uOffset        The offset to start writing to.
+     * @param   pvBuf          Where to read the data from.
+     * @param   cbWrite        How many bytes to write.
+     * @param   ppTask         Where to store the opaque task handle.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnPrepareWrite, (PPDMITRANSPORTASYNC pInterface, void *pStorage, uint64_t uOffset, 
+                                                void *pvBuf, size_t cbWrite, void **ppTask));
+
+    /**
+     * Submit an array of tasks for processing
+     *
+     * @returns VBox status code.
+     * @param   pInterface    Pointer to the interface structure containing the called function pointer.
+     * @param   apTasks       Array of task handles to submit.
+     * @param   cTasks        How many tasks to submit.
+     * @param   pvUser        User data which is passed on completion.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnTasksSubmit, (PPDMITRANSPORTASYNC pInterface, void *apTasks[], unsigned cTasks, void *pvUser));
 } PDMITRANSPORTASYNC;
 
Index: /trunk/include/VBox/types.h
===================================================================
--- /trunk/include/VBox/types.h	(revision 10714)
+++ /trunk/include/VBox/types.h	(revision 10715)
@@ -508,4 +508,18 @@
 typedef const PDMMAC *PCPDMMAC;
 
+/**
+ * Data transport buffer (scatter/gather)
+ */
+typedef struct PDMDATASEG
+{
+    /** Length of buffer in entry. */
+    size_t  cbSeg;
+    /** Pointer to the start of the buffer. */
+    void   *pvSeg;
+} PDMDATASEG;
+/** Pointer to a data transport segment. */
+typedef PDMDATASEG *PPDMDATASEG;
+/** Pointer to a const data transport segment. */
+typedef PDMDATASEG const *PCPDMDATASEG;
 
 /** @} */
Index: /trunk/src/VBox/Devices/Storage/DrvBlock.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvBlock.cpp	(revision 10714)
+++ /trunk/src/VBox/Devices/Storage/DrvBlock.cpp	(revision 10715)
@@ -260,5 +260,5 @@
 
 /** @copydoc PDMIBLOCKASYNC::pfnRead */
-static DECLCALLBACK(int) drvblockAsyncReadStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser)
+static DECLCALLBACK(int) drvblockAsyncReadStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMDATASEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser)
 {
     PDRVBLOCK pData = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
@@ -279,5 +279,5 @@
 
 /** @copydoc PDMIBLOCKASYNC::pfnWrite */
-static DECLCALLBACK(int) drvblockAsyncWriteStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbWrite, void *pvUser)
+static DECLCALLBACK(int) drvblockAsyncWriteStart(PPDMIBLOCKASYNC pInterface, uint64_t off, PPDMDATASEG pSeg, unsigned cSeg, size_t cbWrite, void *pvUser)
 {
     PDRVBLOCK pData = PDMIBLOCKASYNC_2_DRVBLOCK(pInterface);
@@ -302,29 +302,9 @@
 #define PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface)    ( (PDRVBLOCK((uintptr_t)pInterface - RT_OFFSETOF(DRVBLOCK, IMediaAsyncPort))) )
 
-
-static DECLCALLBACK(int) drvblockAsyncReadCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, uint64_t uOffset, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbRead, void *pvUser)
+static DECLCALLBACK(int) drvblockAsyncTransferCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, void *pvUser)
 {
     PDRVBLOCK pData = PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface);
 
-    return pData->pDrvBlockAsyncPort->pfnReadCompleteNotify(pData->pDrvBlockAsyncPort, uOffset, pSeg, cSeg, cbRead, pvUser);
-}
-
-static DECLCALLBACK(int) drvblockAsyncWriteCompleteNotify(PPDMIMEDIAASYNCPORT pInterface, uint64_t uOffset, PPDMIDATATRANSPORTSEG pSeg, unsigned cSeg, size_t cbWritten, void *pvUser)
-{
-    PDRVBLOCK pData = PDMIMEDIAASYNCPORT_2_DRVBLOCK(pInterface);
-
-#ifdef VBOX_PERIODIC_FLUSH
-    if (pData->cbFlushInterval)
-    {
-        pData->cbDataWritten += cbWritten;
-        if (pData->cbDataWritten > pData->cbFlushInterval)
-        {
-            pData->cbDataWritten = 0;
-            pData->pDrvMedia->pfnFlush(pData->pDrvMedia);
-        }
-    }
-#endif /* VBOX_PERIODIC_FLUSH */
-
-    return pData->pDrvBlockAsyncPort->pfnWriteCompleteNotify(pData->pDrvBlockAsyncPort, uOffset, pSeg, cSeg, cbWritten, pvUser);
+    return pData->pDrvBlockAsyncPort->pfnTransferCompleteNotify(pData->pDrvBlockAsyncPort, pvUser);
 }
 
@@ -678,5 +658,5 @@
             return pData->pDrvMediaAsync ? &pData->IBlockAsync : NULL;
         case PDMINTERFACE_MEDIA_ASYNC_PORT:
-            return &pData->IMediaAsyncPort;
+            return pData->pDrvBlockAsyncPort ? &pData->IMediaAsyncPort : NULL;
         default:
             return NULL;
@@ -771,6 +751,5 @@
 
     /* IMediaAsyncPort. */
-    pData->IMediaAsyncPort.pfnReadCompleteNotify  = drvblockAsyncReadCompleteNotify;
-    pData->IMediaAsyncPort.pfnWriteCompleteNotify = drvblockAsyncWriteCompleteNotify;
+    pData->IMediaAsyncPort.pfnTransferCompleteNotify  = drvblockAsyncTransferCompleteNotify;
 
     /*
Index: /trunk/src/VBox/Devices/Storage/DrvVD.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvVD.cpp	(revision 10714)
+++ /trunk/src/VBox/Devices/Storage/DrvVD.cpp	(revision 10715)
@@ -34,4 +34,5 @@
 #include <iprt/file.h>
 #include <iprt/string.h>
+#include <iprt/cache.h>
 
 #include "Builtins.h"
@@ -54,4 +55,24 @@
     ( PDMINS2DATA(PDMIBASE_2_DRVINS(pInterface), PVBOXDISK) )
 
+/** Converts a pointer to VBOXDISK::IMediaAsync to a PVBOXDISK. */
+#define PDMIMEDIAASYNC_2_VBOXDISK(pInterface) \
+    ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, IMediaAsync)) )
+
+/** Converts a pointer to VBOXDISK::ITransportAsyncPort to a PVBOXDISK. */
+#define PDMITRANSPORTASYNCPORT_2_VBOXDISK(pInterface) \
+    ( (PVBOXDISK)((uintptr_t)pInterface - RT_OFFSETOF(VBOXDISK, ITransportAsyncPort)) )
+
+/**
+ * Structure for an async I/O task.
+ */
+typedef struct DRVVDASYNCTASK
+{
+    /** Callback which is called on completion. */
+    PFNVDCOMPLETED pfnCompleted;
+    /** Opqaue user data which is passed on completion. */
+    void           *pvUser;
+    /** Opaque user data the caller passed on transfer initiation. */
+    void           *pvUserCaller;
+} DRVVDASYNCTASK, *PDRVVDASYNCTASK;
 
 /**
@@ -61,11 +82,31 @@
 {
     /** The VBox disk container. */
-    PVBOXHDD        pDisk;
+    PVBOXHDD           pDisk;
     /** The media interface. */
-    PDMIMEDIA       IMedia;
+    PDMIMEDIA          IMedia;
     /** Pointer to the driver instance. */
-    PPDMDRVINS      pDrvIns;
+    PPDMDRVINS         pDrvIns;
     /** Flag whether suspend has changed image open mode to read only. */
-    bool            fTempReadOnly;
+    bool               fTempReadOnly;
+    /** Common structure for the supported error interface. */
+    VDINTERFACE        VDIError;
+    /** Callback table for error interface. */
+    VDINTERFACEERROR   VDIErrorCallbacks;
+    /** Common structure for the supported async I/O interface. */
+    VDINTERFACE        VDIAsyncIO;
+    /** Callback table for async I/O interface. */
+    VDINTERFACEASYNCIO VDIAsyncIOCallbacks;
+    /** Flag whether opened disk suppports async I/O operations. */
+    bool               fAsyncIOSupported;
+    /** The async media interface. */
+    PDMIMEDIAASYNC           IMediaAsync;
+    /** The async media port interface above. */
+    PPDMIMEDIAASYNCPORT      pDrvMediaAsyncPort;
+    /** Pointer to the asynchronous media driver below. */
+    PPDMITRANSPORTASYNC      pDrvTransportAsync;
+    /** Async transport port interface. */
+    PDMITRANSPORTASYNCPORT   ITransportAsyncPort;
+    /** Our cache to reduce allocation overhead. */
+    PRTOBJCACHE              pCache;
 } VBOXDISK, *PVBOXDISK;
 
@@ -79,4 +120,96 @@
     PPDMDRVINS pDrvIns = (PPDMDRVINS)pvUser;
     pDrvIns->pDrvHlp->pfnVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va);
+}
+
+/*******************************************************************************
+*   VD Async I/O interface implementation                                      *
+*******************************************************************************/
+
+static DECLCALLBACK(int) drvvdAsyncIOOpen(void *pvUser, const char *pszLocation, bool fReadonly, void **ppStorage)
+{
+    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
+
+    return pDrvVD->pDrvTransportAsync->pfnOpen(pDrvVD->pDrvTransportAsync, pszLocation, fReadonly, ppStorage);
+}
+
+static DECLCALLBACK(int) drvvdAsyncIOClose(void *pvUser, void *pStorage)
+{
+    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
+
+    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
+
+   return pDrvVD->pDrvTransportAsync->pfnClose(pDrvVD->pDrvTransportAsync, pStorage);
+}
+
+static DECLCALLBACK(int) drvvdAsyncIORead(void *pvUser, void *pStorage, uint64_t uOffset, 
+                                          size_t cbRead, void *pvBuf, size_t *pcbRead)
+{
+    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
+
+    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
+
+    return pDrvVD->pDrvTransportAsync->pfnReadSynchronous(pDrvVD->pDrvTransportAsync,
+                                                          pStorage,
+                                                          uOffset, pvBuf, cbRead, pcbRead);
+}
+
+static DECLCALLBACK(int) drvvdAsyncIOWrite(void *pvUser, void *pStorage, uint64_t uOffset, 
+                                           size_t cbWrite, const void *pvBuf, size_t *pcbWritten)
+{
+    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
+
+    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
+
+    return pDrvVD->pDrvTransportAsync->pfnWriteSynchronous(pDrvVD->pDrvTransportAsync,
+                                                           pStorage,
+                                                           uOffset, pvBuf, cbWrite, pcbWritten);
+}
+
+static DECLCALLBACK(int) drvvdAsyncIOFlush(void *pvUser, void *pStorage)
+{
+    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
+
+    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
+
+    return pDrvVD->pDrvTransportAsync->pfnFlushSynchronous(pDrvVD->pDrvTransportAsync, pStorage);
+}
+
+static DECLCALLBACK(int) drvvdAsyncIOPrepareRead(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuf, size_t cbRead, void **ppTask)
+{
+    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
+
+    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
+
+    return pDrvVD->pDrvTransportAsync->pfnPrepareRead(pDrvVD->pDrvTransportAsync, pStorage, uOffset, pvBuf, cbRead, ppTask);
+}
+
+static DECLCALLBACK(int) drvvdAsyncIOPrepareWrite(void *pvUser, void *pStorage, uint64_t uOffset, void *pvBuf, size_t cbWrite, void **ppTask)
+{
+    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
+
+    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
+
+    return pDrvVD->pDrvTransportAsync->pfnPrepareWrite(pDrvVD->pDrvTransportAsync, pStorage, uOffset, pvBuf, cbWrite, ppTask);
+}
+
+static DECLCALLBACK(int) drvvdAsyncIOTasksSubmit(void *pvUser, void *apTasks[], unsigned cTasks, void *pvUser2,
+                                                 void *pvUserCaller, PFNVDCOMPLETED pfnTasksCompleted)
+{
+    PVBOXDISK pDrvVD = (PVBOXDISK)pvUser;
+    PDRVVDASYNCTASK pDrvVDAsyncTask;
+    int rc;
+
+    AssertMsg(pDrvVD->pDrvTransportAsync, ("Asynchronous function called but no async transport interface below\n"));
+
+    rc = RTCacheRequest(pDrvVD->pCache, (void **)&pDrvVDAsyncTask);
+
+    if (RT_FAILURE(rc))
+        return rc;
+
+    pDrvVDAsyncTask->pfnCompleted = pfnTasksCompleted;
+    pDrvVDAsyncTask->pvUser       = pvUser2;
+    pDrvVDAsyncTask->pvUserCaller = pvUserCaller;
+
+    return pDrvVD->pDrvTransportAsync->pfnTasksSubmit(pDrvVD->pDrvTransportAsync, apTasks, cTasks, pDrvVDAsyncTask);
 }
 
@@ -213,4 +346,60 @@
 }
 
+/*******************************************************************************
+*   Async Media interface methods                                              *
+*******************************************************************************/
+
+static DECLCALLBACK(int) drvvdStartRead(PPDMIMEDIAASYNC pInterface, uint64_t uOffset, 
+                                        PPDMDATASEG paSeg, unsigned cSeg,
+                                        size_t cbRead, void *pvUser)
+{
+     LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbRead=%d\n pvUser=%#p", __FUNCTION__,
+             uOffset, paSeg, cSeg, cbRead, pvUser));
+    PVBOXDISK pData = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
+    int rc = VDAsyncRead(pData->pDisk, uOffset, cbRead, paSeg, cSeg, pvUser);
+    LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
+    return rc;
+}
+
+static DECLCALLBACK(int) drvvdStartWrite(PPDMIMEDIAASYNC pInterface, uint64_t uOffset,
+                                         PPDMDATASEG paSeg, unsigned cSeg,
+                                         size_t cbWrite, void *pvUser)
+{
+     LogFlow(("%s: uOffset=%#llx paSeg=%#p cSeg=%u cbWrite=%d\n pvUser=%#p", __FUNCTION__,
+             uOffset, paSeg, cSeg, cbWrite, pvUser));
+    PVBOXDISK pData = PDMIMEDIAASYNC_2_VBOXDISK(pInterface);
+    int rc = VDAsyncWrite(pData->pDisk, uOffset, cbWrite, paSeg, cSeg, pvUser);
+    LogFlow(("%s: returns %Vrc\n", __FUNCTION__, rc));
+    return rc;
+}
+
+/*******************************************************************************
+*   Async transport port interface methods                                     *
+*******************************************************************************/
+
+static DECLCALLBACK(int) drvvdTasksCompleteNotify(PPDMITRANSPORTASYNCPORT pInterface, void *pvUser)
+{
+    PVBOXDISK pData = PDMITRANSPORTASYNCPORT_2_VBOXDISK(pInterface);
+    PDRVVDASYNCTASK pDrvVDAsyncTask = (PDRVVDASYNCTASK)pvUser;
+    int rc = VINF_VDI_ASYNC_IO_FINISHED;
+   
+    /* Having a completion callback for a task is not mandatory. */
+    if (pDrvVDAsyncTask->pfnCompleted)
+        rc = pDrvVDAsyncTask->pfnCompleted(pDrvVDAsyncTask->pvUser);
+
+    /* Check if the request is finished. */
+    if (rc == VINF_VDI_ASYNC_IO_FINISHED)
+    {
+        rc = pData->pDrvMediaAsyncPort->pfnTransferCompleteNotify(pData->pDrvMediaAsyncPort, pDrvVDAsyncTask->pvUserCaller);
+    }
+    else if (rc == VERR_VDI_ASYNC_IO_IN_PROGRESS)
+        rc = VINF_SUCCESS;
+
+    rc = RTCacheInsert(pData->pCache, pDrvVDAsyncTask);
+    AssertRC(rc);
+
+    return rc;
+}
+
 
 /*******************************************************************************
@@ -230,4 +419,8 @@
         case PDMINTERFACE_MEDIA:
             return &pData->IMedia;
+        case PDMINTERFACE_MEDIA_ASYNC:
+            return pData->fAsyncIOSupported ? &pData->IMediaAsync : NULL;
+        case PDMINTERFACE_TRANSPORT_ASYNC_PORT:
+            return &pData->ITransportAsyncPort;
         default:
             return NULL;
@@ -282,4 +475,74 @@
     pData->IMedia.pfnGetUuid            = drvvdGetUuid;
 
+    /* IMediaAsync */
+    pData->IMediaAsync.pfnStartRead       = drvvdStartRead;
+    pData->IMediaAsync.pfnStartWrite      = drvvdStartWrite;
+
+    /* ITransportAsyncPort */
+    pData->ITransportAsyncPort.pfnTaskCompleteNotify  = drvvdTasksCompleteNotify;
+
+    /* Initialize supported VD interfaces. */
+    pData->VDIErrorCallbacks.cbSize       = sizeof(VDINTERFACEERROR);
+    pData->VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
+    pData->VDIErrorCallbacks.pfnError     = drvvdErrorCallback;
+
+    rc = VDInterfaceCreate(&pData->VDIError, "DrvVD_VDIError", VDINTERFACETYPE_ERROR,
+                           &pData->VDIErrorCallbacks, pData, NULL);
+    AssertRC(rc);
+
+    pData->VDIAsyncIOCallbacks.cbSize                  = sizeof(VDINTERFACEASYNCIO);
+    pData->VDIAsyncIOCallbacks.enmInterface            = VDINTERFACETYPE_ASYNCIO;
+    pData->VDIAsyncIOCallbacks.pfnOpen                 = drvvdAsyncIOOpen;
+    pData->VDIAsyncIOCallbacks.pfnClose                = drvvdAsyncIOClose;
+    pData->VDIAsyncIOCallbacks.pfnRead                 = drvvdAsyncIORead;
+    pData->VDIAsyncIOCallbacks.pfnWrite                = drvvdAsyncIOWrite;
+    pData->VDIAsyncIOCallbacks.pfnFlush                = drvvdAsyncIOFlush;
+    pData->VDIAsyncIOCallbacks.pfnPrepareRead          = drvvdAsyncIOPrepareRead;
+    pData->VDIAsyncIOCallbacks.pfnPrepareWrite         = drvvdAsyncIOPrepareWrite;
+    pData->VDIAsyncIOCallbacks.pfnTasksSubmit          = drvvdAsyncIOTasksSubmit;
+
+    rc = VDInterfaceCreate(&pData->VDIAsyncIO, "DrvVD_AsyncIO", VDINTERFACETYPE_ASYNCIO,
+                           &pData->VDIAsyncIOCallbacks, pData, &pData->VDIError);
+    AssertRC(rc);
+
+    /* Try to attach async media port interface above.*/
+    pData->pDrvMediaAsyncPort = (PPDMIMEDIAASYNCPORT)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_MEDIA_ASYNC_PORT);
+
+    /* 
+     * Attach the async transport driver below of the device above us implements the
+     * async interface.
+     */
+    if (pData->pDrvMediaAsyncPort)
+    {
+        /* Try to attach the driver. */
+        PPDMIBASE pBase;
+
+        rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBase);
+        if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
+        {
+            /* 
+             * Though the device supports async I/O the backend seems to not support it.
+             * Revert to non async I/O.
+             */
+            pData->pDrvMediaAsyncPort = NULL;
+        }
+        else if (VBOX_FAILURE(rc))
+        {
+            AssertMsgFailed(("Failed to attach async transport driver below rc=%Vrc\n", rc));
+        }
+        else
+        {
+            /* Success query the async transport interface. */
+            pData->pDrvTransportAsync = (PPDMITRANSPORTASYNC)pBase->pfnQueryInterface(pBase, PDMINTERFACE_TRANSPORT_ASYNC);
+            if (!pData->pDrvTransportAsync)
+            {
+                /* Whoops. */
+                AssertMsgFailed(("Configuration error: No async transport interface below!\n"));
+                return VERR_PDM_MISSING_INTERFACE_ABOVE;
+
+            }
+        }
+    }
+
     /*
      * Validate configuration and find all parent images.
@@ -325,5 +588,5 @@
     if (VBOX_SUCCESS(rc))
     {
-        rc = VDCreate(drvvdErrorCallback, pDrvIns, &pData->pDisk);
+        rc = VDCreate(&pData->VDIAsyncIO, &pData->pDisk);
         /* Error message is already set correctly. */
     }
@@ -388,5 +651,16 @@
         if (fHonorZeroWrites)
             uOpenFlags |= VD_OPEN_FLAGS_HONOR_ZEROES;
+        if (pData->pDrvMediaAsyncPort)
+            uOpenFlags |= VD_OPEN_FLAGS_ASYNC_IO;
+
+        /** Try to open backend in asyc I/O mode first. */
         rc = VDOpen(pData->pDisk, pszFormat, pszName, uOpenFlags);
+        if (rc == VERR_NOT_SUPPORTED)
+        {
+            /* Seems asxnc I/O is not supported by the backend, open in normal mode. */
+            uOpenFlags &= ~VD_OPEN_FLAGS_ASYNC_IO;
+            rc = VDOpen(pData->pDisk, pszFormat, pszName, uOpenFlags);
+        }
+
         if (VBOX_SUCCESS(rc))
             Log(("%s: %d - Opened '%s' in %s mode\n", __FUNCTION__,
@@ -395,7 +669,9 @@
         else
         {
-            AssertMsgFailed(("Failed to open image '%s' rc=%Vrc\n", pszName, rc));
-            break;
-        }
+           AssertMsgFailed(("Failed to open image '%s' rc=%Vrc\n", pszName, rc));
+           break;
+        }
+
+
         MMR3HeapFree(pszName);
         pszName = NULL;
@@ -419,4 +695,47 @@
         if (VALID_PTR(pszFormat))
             MMR3HeapFree(pszFormat);
+    }
+
+    /* 
+     * Check for async I/O support. Every opened image has to support
+     * it.
+     */
+    pData->fAsyncIOSupported = true;
+    for (unsigned i = 0; i < VDGetCount(pData->pDisk); i++)
+    {
+        VDBACKENDINFO vdBackendInfo;
+
+        rc = VDBackendInfoSingle(pData->pDisk, i, &vdBackendInfo);
+        AssertRC(rc);
+
+        if (vdBackendInfo.uBackendCaps & VD_CAP_ASYNC)
+        {
+            /* 
+             * Backend indicates support for at least some files.
+             * Check if current file is supported with async I/O)
+             */
+            rc = VDImageIsAsyncIOSupported(pData->pDisk, i, &pData->fAsyncIOSupported);
+            AssertRC(rc);
+
+            /* 
+             * Check if current image is supported.
+             * If not we can stop checking because
+             * at least one does not support it.
+             */
+            if (!pData->fAsyncIOSupported)
+                break;
+        }
+        else
+        {
+            pData->fAsyncIOSupported = false;
+            break;
+        }
+    }
+
+    /* Create cache if async I/O is supported. */
+    if (pData->fAsyncIOSupported)
+    {
+        rc = RTCacheCreate(&pData->pCache, 0, sizeof(DRVVDASYNCTASK), RTOBJCACHE_PROTECT_INSERT);
+        AssertMsg(RT_SUCCESS(rc), ("Failed to create cache rc=%Vrc\n", rc));
     }
 
@@ -435,7 +754,8 @@
 static DECLCALLBACK(void) drvvdDestruct(PPDMDRVINS pDrvIns)
 {
-    LogFlow(("%s:\n", __FUNCTION__));
+    int rc;
     PVBOXDISK pData = PDMINS2DATA(pDrvIns, PVBOXDISK);
-    int rc = VDCloseAll(pData->pDisk);
+    LogFlow(("%s:\n", __FUNCTION__));
+    rc = RTCacheDestroy(pData->pCache);
     AssertRC(rc);
 }
@@ -487,5 +807,17 @@
 }
 
-
+static DECLCALLBACK(void) drvvdPowerOff(PPDMDRVINS pDrvIns)
+{
+    LogFlow(("%s:\n", __FUNCTION__));
+    PVBOXDISK pData = PDMINS2DATA(pDrvIns, PVBOXDISK);
+
+    /* 
+     * We must close the disk here to ensure that
+     * the backend closes all files before the
+     * async transport driver is destructed.
+     */
+    int rc = VDCloseAll(pData->pDisk);
+    AssertRC(rc);
+}
 
 /**
@@ -523,4 +855,6 @@
     drvvdResume,
     /* pfnDetach */
-    NULL
+    NULL,
+    /* pfnPowerOff */
+    drvvdPowerOff
 };
Index: /trunk/src/VBox/Devices/Storage/RawHDDCore.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/RawHDDCore.cpp	(revision 10714)
+++ /trunk/src/VBox/Devices/Storage/RawHDDCore.cpp	(revision 10715)
@@ -48,7 +48,7 @@
 
     /** Error callback. */
-    PFNVDERROR      pfnError;
+    PVDINTERFACE      pInterfaceError;
     /** Opaque data for error callback. */
-    void            *pvErrorUser;
+    PVDINTERFACEERROR pInterfaceErrorCallbacks;
 
     /** Open flags passed by VBoxHD layer. */
@@ -84,7 +84,7 @@
     va_list va;
     va_start(va, pszFormat);
-    if (pImage->pfnError)
-        pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS,
-                         pszFormat, va);
+    if (pImage->pInterfaceError)
+        pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
+                                                   pszFormat, va);
     va_end(va);
     return rc;
@@ -98,4 +98,7 @@
     int rc;
     RTFILE File;
+
+    if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
+        return VERR_NOT_SUPPORTED;
 
     pImage->uOpenFlags = uOpenFlags;
@@ -305,6 +308,5 @@
 /** @copydoc VBOXHDDBACKEND::pfnOpen */
 static int rawOpen(const char *pszFilename, unsigned uOpenFlags,
-                    PFNVDERROR pfnError, void *pvErrorUser,
-                    void **ppBackendData)
+                   PVDINTERFACE pInterfaces, void **ppBackendData)
 {
     LogFlowFunc(("pszFilename=\"%s\" uOpenFlags=%#x ppBackendData=%#p\n", pszFilename, uOpenFlags, ppBackendData));
@@ -336,6 +338,10 @@
     pImage->pszFilename = pszFilename;
     pImage->File = NIL_RTFILE;
-    pImage->pfnError = pfnError;
-    pImage->pvErrorUser = pvErrorUser;
+    pImage->pInterfaceError = NULL;
+    pImage->pInterfaceErrorCallbacks = NULL;
+
+    pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR);
+    if (pImage->pInterfaceError)
+        pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError->pCallbacks);
 
     rc = rawOpenImage(pImage, uOpenFlags);
@@ -356,8 +362,8 @@
                      unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
                      void *pvUser, unsigned uPercentStart,
-                     unsigned uPercentSpan, PFNVDERROR pfnError,
-                     void *pvErrorUser, void **ppBackendData)
-{
-    LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pfnError=%#p pvErrorUser=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pfnError, pvErrorUser, ppBackendData));
+                     unsigned uPercentSpan, PVDINTERFACE pInterfaces,
+                     void **ppBackendData)
+{
+    LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pInterfaces=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pInterfaces, ppBackendData));
     int rc;
     PRAWIMAGE pImage;
@@ -389,6 +395,9 @@
     pImage->pszFilename = pszFilename;
     pImage->File = NIL_RTFILE;
-    pImage->pfnError = pfnError;
-    pImage->pvErrorUser = pvErrorUser;
+
+    pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR);
+    if (pImage->pInterfaceError)
+        pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
+
 
     rc = rawCreateImage(pImage, enmType, cbSize, uImageFlags, pszComment,
@@ -987,4 +996,59 @@
 }
 
+static int rawGetTimeStamp(void *pvBackendData, PRTTIMESPEC pTimeStamp)
+{
+    int rc = VERR_NOT_IMPLEMENTED;
+    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
+    return rc;
+}
+
+static int rawGetParentTimeStamp(void *pvBackendData, PRTTIMESPEC pTimeStamp)
+{
+    int rc = VERR_NOT_IMPLEMENTED;
+    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
+    return rc;
+}
+
+static int rawSetParentTimeStamp(void *pvBackendData, PCRTTIMESPEC pTimeStamp)
+{
+    int rc = VERR_NOT_IMPLEMENTED;
+    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
+    return rc;
+}
+
+static int rawGetParentFilename(void *pvBackendData, char **ppszParentFilename)
+{
+    int rc = VERR_NOT_IMPLEMENTED;
+    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
+    return rc;
+}
+
+static int rawSetParentFilename(void *pvBackendData, const char *pszParentFilename)
+{
+    int rc = VERR_NOT_IMPLEMENTED;
+    LogFlow(("%s: returned %Vrc\n", __FUNCTION__, rc));
+    return rc;
+}
+
+static bool rawIsAsyncIOSupported(void *pvBackendData)
+{
+    return false;
+}
+
+static int rawAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead,
+                        PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
+{
+    int rc = VERR_NOT_IMPLEMENTED;
+    LogFlowFunc(("returns %Vrc\n", rc));
+    return rc;
+}
+
+static int rawAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
+                         PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
+{
+    int rc = VERR_NOT_IMPLEMENTED;
+    LogFlowFunc(("returns %Vrc\n", rc));
+    return rc;
+}
 
 VBOXHDDBACKEND g_RawBackend =
@@ -1055,4 +1119,21 @@
     rawSetParentModificationUuid,
     /* pfnDump */
-    rawDump
+    rawDump,
+    /* pfnGetTimeStamp */
+    rawGetTimeStamp,
+    /* pfnGetParentTimeStamp */
+    rawGetParentTimeStamp,
+    /* pfnSetParentTimeStamp */
+    rawSetParentTimeStamp,
+    /* pfnGetParentFilename */
+    rawGetParentFilename,
+    /* pfnSetParentFilename */
+    rawSetParentFilename,
+    /* pfnIsAsyncIOSupported */
+    rawIsAsyncIOSupported,
+    /* pfnAsyncRead */
+    rawAsyncRead,
+    /* pfnAsyncWrite */
+    rawAsyncWrite
 };
+
Index: /trunk/src/VBox/Devices/Storage/VBoxHDD-new.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/VBoxHDD-new.cpp	(revision 10714)
+++ /trunk/src/VBox/Devices/Storage/VBoxHDD-new.cpp	(revision 10715)
@@ -108,8 +108,10 @@
     PDMMEDIAGEOMETRY    LCHSGeometry;
 
-    /** Error message processing callback. */
-    PFNVDERROR          pfnError;
-    /** Opaque data for error callback. */
-    void                *pvErrorUser;
+    /** List of interfaces the caller supports. */
+    PVDINTERFACE        pInterfaces;
+    /** Pointer to the common interface structure for error reporting. */
+    PVDINTERFACE        pInterfaceError;
+    /** Pointer to the error interface we use if available. */
+    PVDINTERFACEERROR   pInterfaceErrorCallbacks;
 };
 
@@ -148,6 +150,6 @@
     va_list va;
     va_start(va, pszFormat);
-    if (pDisk->pfnError)
-        pDisk->pfnError(pDisk->pvErrorUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
+    if (pDisk->pInterfaceErrorCallbacks)
+        pDisk->pInterfaceErrorCallbacks->pfnError(pDisk->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va);
     va_end(va);
     return rc;
@@ -761,4 +763,16 @@
 }
 
+/**
+ * Lists the capablities of a backend indentified by its name.
+ * Free all returned names with RTStrFree() when you no longer need them.
+ *
+ * @returns VBox status code.
+ * @param   pszBackend      The backend name.
+ * @param   pEntries        Pointer to an entry.
+ */
+VBOXDDU_DECL(int) VDBackendInfoOne(const char *pszBackend, PVDBACKENDINFO pEntry)
+{
+    return VERR_NOT_IMPLEMENTED;
+}
 
 /**
@@ -767,21 +781,16 @@
  *
  * @returns VBox status code.
- * @param   pfnError        Callback for setting extended error information.
- * @param   pvErrorUser     Opaque parameter for pfnError.
+ * @param   pInterfaces     Pointer to the first supported interface.
  * @param   ppDisk          Where to store the reference to HDD container.
  */
-VBOXDDU_DECL(int) VDCreate(PFNVDERROR pfnError, void *pvErrorUser,
-                           PVBOXHDD *ppDisk)
+VBOXDDU_DECL(int) VDCreate(PVDINTERFACE pInterfaces, PVBOXHDD *ppDisk)
 {
     int rc = VINF_SUCCESS;
     PVBOXHDD pDisk = NULL;
 
-    LogFlowFunc(("pfnError=%#p pvErrorUser=%#p\n", pfnError, pvErrorUser));
+    LogFlowFunc(("pInterfaces=%#p\n", pInterfaces));
     do
     {
         /* Check arguments. */
-        AssertMsgBreakStmt(VALID_PTR(pfnError),
-                           ("pfnError=%#p\n", pfnError),
-                           rc = VERR_INVALID_PARAMETER);
         AssertMsgBreakStmt(VALID_PTR(ppDisk),
                            ("ppDisk=%#p\n", ppDisk),
@@ -802,6 +811,11 @@
             pDisk->LCHSGeometry.cHeads     = 0;
             pDisk->LCHSGeometry.cSectors   = 0;
-            pDisk->pfnError     = pfnError;
-            pDisk->pvErrorUser  = pvErrorUser;
+            pDisk->pInterfaces  = pInterfaces;
+            pDisk->pInterfaceError = NULL;
+            pDisk->pInterfaceErrorCallbacks = NULL;
+
+            pDisk->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR);
+            if (pDisk->pInterfaceError)
+                pDisk->pInterfaceErrorCallbacks = VDGetInterfaceError(pDisk->pInterfaceError->pCallbacks);
             *ppDisk = pDisk;
         }
@@ -1078,5 +1092,5 @@
         rc = pImage->Backend->pfnOpen(pImage->pszFilename,
                                       uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME,
-                                      pDisk->pfnError, pDisk->pvErrorUser,
+                                      pDisk->pInterfaces,
                                       &pImage->pvBackendData);
         /* If the open in read-write mode failed, retry in read-only mode. */
@@ -1092,5 +1106,5 @@
                                                 (uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME)
                                                | VD_OPEN_FLAGS_READONLY,
-                                               pDisk->pfnError, pDisk->pvErrorUser,
+                                               pDisk->pInterfaces,
                                                &pImage->pvBackendData);
             if (VBOX_FAILURE(rc))
@@ -1342,5 +1356,5 @@
                                         uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME,
                                         pfnProgress, pvUser, 0, 99,
-                                        pDisk->pfnError, pDisk->pvErrorUser,
+                                        pDisk->pInterfaces,
                                         &pImage->pvBackendData);
 
@@ -1515,5 +1529,5 @@
                                         uOpenFlags & ~VD_OPEN_FLAGS_HONOR_SAME,
                                         pfnProgress, pvUser, 0, 99,
-                                        pDisk->pfnError, pDisk->pvErrorUser,
+                                        pDisk->pInterfaces,
                                         &pImage->pvBackendData);
 
@@ -2471,5 +2485,5 @@
     } while (0);
 
-    LogFlowFunc(("%s: %Vrc (PCHS=%u/%u/%u)\n", rc,
+    LogFlowFunc(("%s: %Vrc (PCHS=%u/%u/%u)\n", __FUNCTION__, rc,
                  pDisk->PCHSGeometry.cCylinders, pDisk->PCHSGeometry.cHeads,
                  pDisk->PCHSGeometry.cSectors));
@@ -2617,5 +2631,5 @@
     } while (0);
 
-    LogFlowFunc(("%s: %Vrc (LCHS=%u/%u/%u)\n", rc,
+    LogFlowFunc((": %Vrc (LCHS=%u/%u/%u)\n", rc,
                  pDisk->LCHSGeometry.cCylinders, pDisk->LCHSGeometry.cHeads,
                  pDisk->LCHSGeometry.cSectors));
@@ -2800,4 +2814,50 @@
 }
 
+
+/**
+ * List the capabilities of image backend in HDD container.
+ *
+ * @returns VBox status code.
+ * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
+ * @param   pDisk           Pointer to the HDD container.
+ * @param   nImage          Image number, counts from 0. 0 is always base image of container.
+ * @param   pbackendInfo    Where to store the backend information.
+ */
+VBOXDDU_DECL(int) VDBackendInfoSingle(PVBOXHDD pDisk, unsigned nImage,
+                                      PVDBACKENDINFO pBackendInfo)
+{
+    int rc = VINF_SUCCESS;
+
+    LogFlowFunc(("pDisk=%#p nImage=%u penmType=%#p\n",
+                 pDisk, nImage, pBackendInfo));
+    do
+    {
+        /* sanity check */
+        AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER);
+        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
+
+        /* Check arguments. */
+        AssertMsgBreakStmt(VALID_PTR(pBackendInfo),
+                           ("pBackendInfo=%#p\n", pBackendInfo),
+                           rc = VERR_INVALID_PARAMETER);
+
+        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
+        AssertPtrBreakStmt(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
+
+        if (    pImage->enmImageType >= VD_IMAGE_TYPE_FIRST
+            &&  pImage->enmImageType <= VD_IMAGE_TYPE_DIFF)
+        {
+            pBackendInfo->pszBackend = RTStrDup(pImage->Backend->pszBackendName);
+            pBackendInfo->uBackendCaps = pImage->Backend->uBackendCaps;
+            rc = VINF_SUCCESS;
+        }
+        else
+            rc = VERR_VDI_INVALID_TYPE;
+    } while (0);
+
+    LogFlowFunc(("returns %Vrc\n", rc));
+    return rc;
+}
+
 /**
  * Get flags of image in HDD container.
@@ -3306,2 +3366,168 @@
 }
 
+/**
+ * Query if asynchronous operations are supported for this disk.
+ *
+ * @returns VBox status code.
+ * @returns VERR_VDI_IMAGE_NOT_FOUND if image with specified number was not opened.
+ * @param   pDisk           Pointer to the HDD container.
+ * @param   nImage          Image number, counts from 0. 0 is always base image of container.
+ * @param   pfAIOSupported  Where to store if async IO is supported.
+ */
+VBOXDDU_DECL(int) VDImageIsAsyncIOSupported(PVBOXHDD pDisk, unsigned nImage, bool *pfAIOSupported)
+{
+    int rc = VINF_SUCCESS;
+
+    LogFlowFunc(("pDisk=%#p nImage=%u pfAIOSupported=%#p\n", pDisk, nImage, pfAIOSupported));
+    do
+    {
+        /* sanity check */
+        AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER);
+        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
+
+        /* Check arguments. */
+        AssertMsgBreakStmt(VALID_PTR(pfAIOSupported),
+                           ("pfAIOSupported=%#p\n", pfAIOSupported),
+                           rc = VERR_INVALID_PARAMETER);
+
+        PVDIMAGE pImage = vdGetImageByNumber(pDisk, nImage);
+        AssertPtrBreakStmt(pImage, rc = VERR_VDI_IMAGE_NOT_FOUND);
+
+        if (pImage->Backend->uBackendCaps & VD_CAP_ASYNC)
+            *pfAIOSupported = pImage->Backend->pfnIsAsyncIOSupported(pImage->pvBackendData);
+        else
+            *pfAIOSupported = false;
+    } while (0);
+
+    LogFlowFunc(("returns %Vrc, fAIOSupported=%u\n", rc, *pfAIOSupported));
+    return rc;
+}
+
+/**
+ * Start a asynchronous read request.
+ *
+ * @returns VBox status code.
+ * @param   pDisk           Pointer to the HDD container.
+ * @param   uOffset         The offset of the virtual disk to read from.
+ * @param   cbRead          How many bytes to read.
+ * @param   paSeg           Pointer to an array of segments.
+ * @param   cSeg            Number of segments in the array.
+ * @param   pvUser          User data which is passed on completion
+ */
+VBOXDDU_DECL(int) VDAsyncRead(PVBOXHDD pDisk, uint64_t uOffset, size_t cbRead, 
+                              PPDMDATASEG paSeg, unsigned cSeg,
+                              void *pvUser)
+{
+    int rc = VERR_VDI_BLOCK_FREE;
+
+    LogFlowFunc(("pDisk=%#p uOffset=%llu paSeg=%p cSeg=%u cbRead=%zu\n",
+                 pDisk, uOffset, paSeg, cSeg, cbRead));
+    do
+    {
+        /* sanity check */
+        AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER);
+        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
+
+        /* Check arguments. */
+        AssertMsgBreakStmt(cbRead,
+                           ("cbRead=%zu\n", cbRead),
+                           rc = VERR_INVALID_PARAMETER);
+        AssertMsgBreakStmt(uOffset + cbRead <= pDisk->cbSize,
+                           ("uOffset=%llu cbRead=%zu pDisk->cbSize=%llu\n",
+                            uOffset, cbRead, pDisk->cbSize),
+                           rc = VERR_INVALID_PARAMETER);
+        AssertMsgBreakStmt(VALID_PTR(paSeg),
+                           ("paSeg=%#p\n", paSeg),
+                           rc = VERR_INVALID_PARAMETER);
+        AssertMsgBreakStmt(cSeg,
+                           ("cSeg=%zu\n", cSeg),
+                           rc = VERR_INVALID_PARAMETER);
+
+
+        PVDIMAGE pImage = pDisk->pLast;
+        AssertPtrBreakStmt(pImage, rc = VERR_VDI_NOT_OPENED);
+
+        /* @todo: This does not work for images which do not have all meta data in memory. */
+        for (PVDIMAGE pCurrImage = pImage;
+             pCurrImage != NULL && rc == VERR_VDI_BLOCK_FREE;
+             pCurrImage = pCurrImage->pPrev)
+        {
+            rc = pCurrImage->Backend->pfnAsyncRead(pCurrImage->pvBackendData,
+                                                   uOffset, cbRead, paSeg, cSeg,
+                                                   pvUser);
+        }
+
+        /* No image in the chain contains the data for the block. */
+        if (rc == VERR_VDI_BLOCK_FREE)
+        {
+            for (unsigned i = 0; i < cSeg && (cbRead > 0); i++)
+            {
+                memset(paSeg[i].pvSeg, '\0', paSeg[i].cbSeg);
+                cbRead -= paSeg[i].cbSeg;
+            }
+            /* Request finished without the need to enqueue a async I/O request. Tell caller. */
+            rc = VINF_VDI_ASYNC_IO_FINISHED;
+        }
+
+    } while (0);
+
+    LogFlowFunc(("returns %Vrc\n", rc));
+    return rc;
+}
+
+
+/**
+ * Start a asynchronous write request.
+ *
+ * @returns VBox status code.
+ * @param   pDisk           Pointer to the HDD container.
+ * @param   uOffset         The offset of the virtual disk to write to.
+ * @param   cbWrtie         How many bytes to write.
+ * @param   paSeg           Pointer to an array of segments.
+ * @param   cSeg            Number of segments in the array.
+ * @param   pvUser          User data which is passed on completion.
+ */
+VBOXDDU_DECL(int) VDAsyncWrite(PVBOXHDD pDisk, uint64_t uOffset, size_t cbWrite,
+                               PPDMDATASEG paSeg, unsigned cSeg,
+                               void *pvUser)
+{
+    int rc;
+
+    LogFlowFunc(("pDisk=%#p uOffset=%llu paSeg=%p cSeg=%u cbWrite=%zu\n",
+                 pDisk, uOffset, paSeg, cSeg, cbWrite));
+    do
+    {
+        /* sanity check */
+        AssertPtrBreakStmt(pDisk, rc = VERR_INVALID_PARAMETER);
+        AssertMsg(pDisk->u32Signature == VBOXHDDDISK_SIGNATURE, ("u32Signature=%08x\n", pDisk->u32Signature));
+
+        /* Check arguments. */
+        AssertMsgBreakStmt(cbWrite,
+                           ("cbWrite=%zu\n", cbWrite),
+                           rc = VERR_INVALID_PARAMETER);
+        AssertMsgBreakStmt(uOffset + cbWrite <= pDisk->cbSize,
+                           ("uOffset=%llu cbWrite=%zu pDisk->cbSize=%llu\n",
+                            uOffset, cbWrite, pDisk->cbSize),
+                           rc = VERR_INVALID_PARAMETER);
+        AssertMsgBreakStmt(VALID_PTR(paSeg),
+                           ("paSeg=%#p\n", paSeg),
+                           rc = VERR_INVALID_PARAMETER);
+        AssertMsgBreakStmt(cSeg,
+                           ("cSeg=%zu\n", cSeg),
+                           rc = VERR_INVALID_PARAMETER);
+
+
+        PVDIMAGE pImage = pDisk->pLast;
+        AssertPtrBreakStmt(pImage, rc = VERR_VDI_NOT_OPENED);
+
+        vdSetModifiedFlag(pDisk);
+        rc = pImage->Backend->pfnAsyncWrite(pImage->pvBackendData, 
+                                            uOffset, cbWrite, 
+                                            paSeg, cSeg, pvUser);
+    } while (0);
+
+    LogFlowFunc(("returns %Vrc\n", rc));
+    return rc;
+
+}
+
Index: /trunk/src/VBox/Devices/Storage/VBoxHDD-newInternal.h
===================================================================
--- /trunk/src/VBox/Devices/Storage/VBoxHDD-newInternal.h	(revision 10714)
+++ /trunk/src/VBox/Devices/Storage/VBoxHDD-newInternal.h	(revision 10715)
@@ -71,9 +71,9 @@
      *                          unchanged during the lifetime of this image.
      * @param   uOpenFlags      Image file open mode, see VD_OPEN_FLAGS_* constants.
-     * @param   pfnError        Callback for setting extended error information.
-     * @param   pvErrorUser     Opaque parameter for pfnError.
+     * @param   pInterfaces     Pointer to the first element of supported interfaces of the caller.
      * @param   ppvBackendData  Opaque state data for this image.
      */
-    DECLR3CALLBACKMEMBER(int, pfnOpen, (const char *pszFilename, unsigned uOpenFlags, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData));
+    DECLR3CALLBACKMEMBER(int, pfnOpen, (const char *pszFilename, unsigned uOpenFlags,
+                                        PVDINTERFACE pInterfaces, void **ppvBackendData));
 
     /**
@@ -94,9 +94,8 @@
      * @param   uPercentStart   Starting value for progress percentage.
      * @param   uPercentSpan    Span for varying progress percentage.
-     * @param   pfnError        Callback for setting extended error information.
-     * @param   pvErrorUser     Opaque parameter for pfnError.
+     * @param   pInterfaces     Pointer to the supported interfaces of the caller.
      * @param   ppvBackendData  Opaque state data for this image.
      */
-    DECLR3CALLBACKMEMBER(int, pfnCreate, (const char *pszFilename, VDIMAGETYPE enmType, uint64_t cbSize, unsigned uImageFlags, const char *pszComment, PCPDMMEDIAGEOMETRY pPCHSGeometry, PCPDMMEDIAGEOMETRY pLCHSGeometry, unsigned uOpenFlags, PFNVMPROGRESS pfnProgress, void *pvUser, unsigned uPercentStart, unsigned uPercentSpan, PFNVDERROR pfnError, void *pvErrorUser, void **ppvBackendData));
+    DECLR3CALLBACKMEMBER(int, pfnCreate, (const char *pszFilename, VDIMAGETYPE enmType, uint64_t cbSize, unsigned uImageFlags, const char *pszComment, PCPDMMEDIAGEOMETRY pPCHSGeometry, PCPDMMEDIAGEOMETRY pLCHSGeometry, unsigned uOpenFlags, PFNVMPROGRESS pfnProgress, void *pvUser, unsigned uPercentStart, unsigned uPercentSpan, PVDINTERFACE pInterfaces, void **ppvBackendData));
 
     /**
@@ -421,4 +420,41 @@
     DECLR3CALLBACKMEMBER(int, pfnSetParentFilename, (void *pvBackendData, const char *pszParentFilename));
 
+    /**
+     * Return whether asynchronous I/O operations are supported for this image.
+     *
+     * @returns true if asynchronous I/O is supported
+     *          false otherwise.
+     * @param   pvBackendData    Opaque state data for this image.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnIsAsyncIOSupported, (void *pvBackendData));
+
+    /**
+     * Start an asynchronous read request.
+     *
+     * @returns VBox status code.
+     * @param   pvBackendData   Opaque state data for this image.
+     * @param   uOffset         The offset of the virtual disk to read from.
+     * @param   cbRead          How many bytes to read.
+     * @param   paSeg           Pointer to the segment array.
+     * @param   cSeg            Number of segments.
+     * @param   pvUser          Opaque user data.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnAsyncRead, (void *pvBackendData, uint64_t uOffset, size_t cbRead,
+                                             PPDMDATASEG paSeg, unsigned cSeg, void *pvUser));
+
+    /**
+     * Start an asynchronous write request.
+     *
+     * @returns VBox status code.
+     * @param   pvBackendData   Opaque state data for this image.
+     * @param   uOffset         The offset of the virtual disk to write to.
+     * @param   cbWrite         How many bytes to write.
+     * @param   paSeg           Pointer to the segment array.
+     * @param   cSeg            Number of segments.
+     * @param   pvUser          Oaque user data-
+     */
+    DECLR3CALLBACKMEMBER(int, pfnAsyncWrite, (void *pvBackendData, uint64_t uOffset, size_t cbWrite,
+                                              PPDMDATASEG paSeg, unsigned cSeg, void *pvUser));
+
 } VBOXHDDBACKEND;
 
Index: /trunk/src/VBox/Devices/Storage/VDICore.h
===================================================================
--- /trunk/src/VBox/Devices/Storage/VDICore.h	(revision 10714)
+++ /trunk/src/VBox/Devices/Storage/VDICore.h	(revision 10715)
@@ -562,8 +562,8 @@
     /** Physical geometry of this image (never actually stored). */
     PDMMEDIAGEOMETRY        PCHSGeometry;
-    /** Error callback. */
-    PFNVDERROR              pfnError;
-    /** Opaque data for error callback. */
-    void                   *pvErrorUser;
+    /** Error interface. */
+    PVDINTERFACE            pInterfaceError;
+    /** Error interface callback table. */
+    PVDINTERFACEERROR       pInterfaceErrorCallbacks;
 #endif /* VBOX_VDICORE_VD */
 } VDIIMAGEDESC, *PVDIIMAGEDESC;
Index: /trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp	(revision 10714)
+++ /trunk/src/VBox/Devices/Storage/VDIHDDCore.cpp	(revision 10715)
@@ -63,7 +63,8 @@
     va_list va;
     va_start(va, pszFormat);
-    if (pImage->pfnError)
-        pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS,
-                         pszFormat, va);
+    if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks)
+        pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser,
+                                                   rc, RT_SRC_POS_ARGS,
+                                                   pszFormat, va);
     va_end(va);
     return rc;
@@ -508,4 +509,7 @@
     int rc;
     RTFILE File;
+
+    if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
+        return VERR_NOT_SUPPORTED;
 
     pImage->uOpenFlags = uOpenFlags;
@@ -731,6 +735,6 @@
     pImage->File = NIL_RTFILE;
     pImage->paBlocks = NULL;
-    pImage->pfnError = NULL;
-    pImage->pvErrorUser = NULL;
+    pImage->pInterfaceError = NULL;
+    pImage->pInterfaceErrorCallbacks = NULL;
 
     rc = vdiOpenImage(pImage, VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_READONLY);
@@ -744,5 +748,5 @@
 /** @copydoc VBOXHDDBACKEND::pfnOpen */
 static int vdiOpen(const char *pszFilename, unsigned uOpenFlags,
-                   PFNVDERROR pfnError, void *pvErrorUser,
+                   PVDINTERFACE pInterfaces,
                    void **ppBackendData)
 {
@@ -775,6 +779,10 @@
     pImage->File = NIL_RTFILE;
     pImage->paBlocks = NULL;
-    pImage->pfnError = pfnError;
-    pImage->pvErrorUser = pvErrorUser;
+    pImage->pInterfaceError = NULL;
+    pImage->pInterfaceErrorCallbacks = NULL;
+
+    pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR);
+    if (pImage->pInterfaceError)
+        pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError->pCallbacks);
 
     rc = vdiOpenImage(pImage, uOpenFlags);
@@ -795,8 +803,8 @@
                      unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
                      void *pvUser, unsigned uPercentStart,
-                     unsigned uPercentSpan, PFNVDERROR pfnError,
-                     void *pvErrorUser, void **ppBackendData)
-{
-    LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pfnError=%#p pvErrorUser=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pfnError, pvErrorUser, ppBackendData));
+                     unsigned uPercentSpan, PVDINTERFACE pInterfaces,
+                     void **ppBackendData)
+{
+    LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pInterfaces=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pInterfaces, ppBackendData));
     int rc;
     PVDIIMAGEDESC pImage;
@@ -831,6 +839,6 @@
     pImage->File = NIL_RTFILE;
     pImage->paBlocks = NULL;
-    pImage->pfnError = pfnError;
-    pImage->pvErrorUser = pvErrorUser;
+    pImage->pInterfaceError = NULL;
+    pImage->pInterfaceErrorCallbacks = NULL;
 
     rc = vdiCreateImage(pImage, enmType, cbSize, uImageFlags, pszComment,
@@ -1753,4 +1761,26 @@
     return rc;
 }
+
+static bool vdiIsAsyncIOSupported(void *pvBackendData)
+{
+    return false;
+}
+
+static int vdiAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead,
+                        PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
+{
+    int rc = VERR_NOT_IMPLEMENTED;
+    LogFlowFunc(("returns %Vrc\n", rc));
+    return rc;
+}
+
+static int vdiAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
+                         PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
+{
+    int rc = VERR_NOT_IMPLEMENTED;
+    LogFlowFunc(("returns %Vrc\n", rc));
+    return rc;
+}
+
 
 VBOXHDDBACKEND g_VDIBackend =
@@ -1832,5 +1862,11 @@
     vdiGetParentFilename,
     /* pfnSetParentFilename */
-    vdiSetParentFilename
+    vdiSetParentFilename,
+    /* pfnIsAsyncIOSupported */
+    vdiIsAsyncIOSupported,
+    /* pfnAsyncRead */
+    vdiAsyncRead,
+    /* pfnAsyncWrite */
+    vdiAsyncWrite
 };
 
Index: /trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp	(revision 10714)
+++ /trunk/src/VBox/Devices/Storage/VmdkHDDCore.cpp	(revision 10715)
@@ -179,4 +179,34 @@
 } VMDKACCESS, *PVMDKACCESS;
 
+/** Forward declaration for PVMDKIMAGE. */
+typedef struct VMDKIMAGE *PVMDKIMAGE;
+
+/**
+ * Extents files entry. Used for opening a particular file only once.
+ */
+typedef struct VMDKFILE
+{
+    /** Pointer to filename. Local copy. */
+    const char *pszFilename;
+    /** File open flags for consistency checking. */
+    unsigned    fOpen;
+    /** File handle. */
+    RTFILE      File;
+    /** Handle for asnychronous access if requested.*/
+    void       *pStorage;
+    /** Flag whether to use File or pStorage. */
+    bool        fAsyncIO;
+    /** Reference counter. */
+    unsigned    uReferences;
+    /** Flag whether the file should be deleted on last close. */
+    bool        fDelete;
+    /** Pointer to the image we belong to. */
+    PVMDKIMAGE  pImage;
+    /** Pointer to next file descriptor. */
+    struct VMDKFILE *pNext;
+    /** Pointer to the previous file descriptor. */
+    struct VMDKFILE *pPrev;
+} VMDKFILE, *PVMDKFILE;
+
 /**
  * VMDK extent data structure.
@@ -185,5 +215,5 @@
 {
     /** File handle. */
-    RTFILE      File;
+    PVMDKFILE    pFile;
     /** Base name of the image extent. */
     const char  *pszBasename;
@@ -239,23 +269,4 @@
 
 /**
- * Extents files entry. Used for opening a particular file only once.
- */
-typedef struct VMDKFILE
-{
-    /** Pointer to filename. Local copy. */
-    const char *pszFilename;
-    /** File open flags for consistency checking. */
-    unsigned    fOpen;
-    /** File handle. */
-    RTFILE      File;
-    /** Reference counter. */
-    unsigned    uReferences;
-    /** Flag whether the file should be deleted on last close. */
-    bool        fDelete;
-    /** Pointer to next file descriptor. Singly linked list is fast enough. */
-    struct VMDKFILE *pNext;
-} VMDKFILE, *PVMDKFILE;
-
-/**
  * Grain table cache size. Allocated per image.
  */
@@ -346,10 +357,24 @@
     const char      *pszFilename;
     /** Descriptor file if applicable. */
-    RTFILE          File;
-
-    /** Error callback. */
-    PFNVDERROR      pfnError;
-    /** Opaque data for error callback. */
-    void            *pvErrorUser;
+    PVMDKFILE        pFile;
+
+    /** Error interface. */
+    PVDINTERFACE      pInterfaceError;
+    /** Error interface callbacks. */
+    PVDINTERFACEERROR pInterfaceErrorCallbacks;
+
+    /** Async I/O interface. */
+    PVDINTERFACE        pInterfaceAsyncIO;
+    /** Async I/O interface callbacks. */
+    PVDINTERFACEASYNCIO pInterfaceAsyncIOCallbacks;
+    /** 
+     * Pointer to an array of task handles for task submission.
+     * This is an optimization because the task number to submit is not known
+     * and allocating/freeing an array in the read/write functions every time
+     * is too expensive.
+     */
+    void               **apTask;
+    /** Entries available in the task handle array. */
+    unsigned             cTask;
 
     /** Open flags passed by VBoxHD layer. */
@@ -382,5 +407,5 @@
     /** Parsed descriptor file content. */
     VMDKDESCRIPTOR  Descriptor;
-} VMDKIMAGE, *PVMDKIMAGE;
+} VMDKIMAGE;
 
 
@@ -408,7 +433,7 @@
     va_list va;
     va_start(va, pszFormat);
-    if (pImage->pfnError)
-        pImage->pfnError(pImage->pvErrorUser, rc, RT_SRC_POS_ARGS,
-                         pszFormat, va);
+    if (pImage->pInterfaceError && pImage->pInterfaceErrorCallbacks)
+        pImage->pInterfaceErrorCallbacks->pfnError(pImage->pInterfaceError->pvUser, rc, RT_SRC_POS_ARGS,
+                                                   pszFormat, va);
     va_end(va);
     return rc;
@@ -419,6 +444,6 @@
  * is only opened once - anything else can cause locking problems).
  */
-static int vmdkFileOpen(PVMDKIMAGE pImage, PRTFILE pFile,
-                        const char *pszFilename, unsigned fOpen)
+static int vmdkFileOpen(PVMDKIMAGE pImage, PVMDKFILE *ppVmdkFile,
+                        const char *pszFilename, unsigned fOpen, bool fAsyncIO)
 {
     int rc = VINF_SUCCESS;
@@ -433,5 +458,7 @@
             Assert(fOpen == pVmdkFile->fOpen);
             pVmdkFile->uReferences++;
-            *pFile = pVmdkFile->File;
+
+            *ppVmdkFile = pVmdkFile;
+
             return rc;
         }
@@ -442,5 +469,5 @@
     if (!VALID_PTR(pVmdkFile))
     {
-        *pFile = NIL_RTFILE;
+        *ppVmdkFile = NULL;
         return VERR_NO_MEMORY;
     }
@@ -450,15 +477,32 @@
     {
         RTMemFree(pVmdkFile);
-        *pFile = NIL_RTFILE;
+        *ppVmdkFile = NULL;
         return VERR_NO_MEMORY;
     }
     pVmdkFile->fOpen = fOpen;
-    rc = RTFileOpen(&pVmdkFile->File, pszFilename, fOpen);
+    if ((pImage->uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO) && (fAsyncIO))
+    {
+        rc = pImage->pInterfaceAsyncIOCallbacks->pfnOpen(pImage->pInterfaceAsyncIO->pvUser,
+                                                         pszFilename,
+                                                         pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY
+                                                           ? true
+                                                           : false,
+                                                         &pVmdkFile->pStorage);
+        pVmdkFile->fAsyncIO = true;
+    }
+    else
+    {
+        rc = RTFileOpen(&pVmdkFile->File, pszFilename, fOpen);
+        pVmdkFile->fAsyncIO = false;
+    }
     if (VBOX_SUCCESS(rc))
     {
         pVmdkFile->uReferences = 1;
+        pVmdkFile->pImage = pImage;
         pVmdkFile->pNext = pImage->pFiles;
+        if (pImage->pFiles)
+            pImage->pFiles->pPrev = pVmdkFile;
         pImage->pFiles = pVmdkFile;
-        *pFile = pVmdkFile->File;
+        *ppVmdkFile = pVmdkFile;
     }
     else
@@ -466,5 +510,5 @@
         RTStrFree((char *)(void *)pVmdkFile->pszFilename);
         RTMemFree(pVmdkFile);
-        *pFile = NIL_RTFILE;
+        *ppVmdkFile = NULL;
     }
 
@@ -475,44 +519,123 @@
  * Internal: close a file, updating the file descriptor cache.
  */
-static int vmdkFileClose(PVMDKIMAGE pImage, PRTFILE pFile, bool fDelete)
+static int vmdkFileClose(PVMDKIMAGE pImage, PVMDKFILE *ppVmdkFile, bool fDelete)
 {
     int rc = VINF_SUCCESS;
-    RTFILE File;
-    PVMDKFILE pVmdkFile, pPrev;
-
-    Assert(VALID_PTR(pFile) && *pFile != NIL_RTFILE);
-    File = *pFile;
-
-    pPrev = NULL;
-    for (pVmdkFile = pImage->pFiles;
-         pVmdkFile != NULL;
-         pVmdkFile = pVmdkFile->pNext)
-    {
-        if (File == pVmdkFile->File)
-        {
-            pVmdkFile->fDelete |= fDelete;
-            Assert(pVmdkFile->uReferences);
-            pVmdkFile->uReferences--;
-            if (pVmdkFile->uReferences == 0)
-            {
-                /* Unchain the element from the list. */
-                if (pPrev == NULL)
-                    pImage->pFiles = pVmdkFile->pNext;
-                else
-                    pPrev->pNext = pVmdkFile->pNext;
-                rc = RTFileClose(File);
-                *pFile = NIL_RTFILE;
-                if (VBOX_SUCCESS(rc) && pVmdkFile->fDelete)
-                    rc = RTFileDelete(pVmdkFile->pszFilename);
-                RTStrFree((char *)(void *)pVmdkFile->pszFilename);
-                RTMemFree(pVmdkFile);
-            }
-            return rc;
-        }
-        pPrev = pVmdkFile;
-    }
-
-    AssertMsgFailed(("trying to close unknown file %#p", File));
-    return VERR_INVALID_PARAMETER;
+    PVMDKFILE pVmdkFile = *ppVmdkFile;
+
+    Assert(VALID_PTR(pVmdkFile));
+
+    pVmdkFile->fDelete |= fDelete;
+    Assert(pVmdkFile->uReferences);
+    pVmdkFile->uReferences--;
+    if (pVmdkFile->uReferences == 0)
+    {
+        PVMDKFILE pPrev;
+        PVMDKFILE pNext;
+
+        /* Unchain the element from the list. */
+        pPrev = pVmdkFile->pPrev;
+        pNext = pVmdkFile->pNext;
+
+        if (pNext)
+            pNext->pPrev = pPrev;
+        if (pPrev)
+            pPrev->pNext = pNext;
+        else
+            pImage->pFiles = pNext;
+
+        if (pVmdkFile->fAsyncIO)
+        {
+            rc = pImage->pInterfaceAsyncIOCallbacks->pfnClose(pImage->pInterfaceAsyncIO->pvUser,
+                                                              pVmdkFile->pStorage);
+        }
+        else
+        {
+            rc = RTFileClose(pVmdkFile->File);
+        }
+        if (VBOX_SUCCESS(rc) && pVmdkFile->fDelete)
+            rc = RTFileDelete(pVmdkFile->pszFilename);
+        RTStrFree((char *)(void *)pVmdkFile->pszFilename);
+        RTMemFree(pVmdkFile);
+    }
+
+    *ppVmdkFile = NULL;
+    return rc;
+}
+
+/**
+ * Internal: read from a file distinguishing between async and normal operation
+ */
+DECLINLINE(int) vmdkFileReadAt(PVMDKFILE pVmdkFile, 
+                               uint64_t uOffset, void *pvBuf, 
+                               size_t cbToRead, size_t *pcbRead)
+{
+    PVMDKIMAGE pImage = pVmdkFile->pImage;
+
+    if (pVmdkFile->fAsyncIO)
+        return pImage->pInterfaceAsyncIOCallbacks->pfnRead(pImage->pInterfaceAsyncIO->pvUser,
+                                                           pVmdkFile->pStorage, uOffset,
+                                                           cbToRead, pvBuf, pcbRead);
+    else
+        return RTFileReadAt(pVmdkFile->File, uOffset, pvBuf, cbToRead, pcbRead);
+}
+
+/**
+ * Internal: write to a file distinguishing between async and normal operation
+ */
+DECLINLINE(int) vmdkFileWriteAt(PVMDKFILE pVmdkFile, 
+                                uint64_t uOffset, const void *pvBuf, 
+                                size_t cbToWrite, size_t *pcbWritten)
+{
+    PVMDKIMAGE pImage = pVmdkFile->pImage;
+
+    if (pVmdkFile->fAsyncIO)
+        return pImage->pInterfaceAsyncIOCallbacks->pfnWrite(pImage->pInterfaceAsyncIO->pvUser,
+                                                            pVmdkFile->pStorage, uOffset,
+                                                            cbToWrite, pvBuf, pcbWritten);
+    else
+        return RTFileWriteAt(pVmdkFile->File, uOffset, pvBuf, cbToWrite, pcbWritten);
+}
+
+/**
+ * Internal: get the size of a file distinguishing beween async and normal operation
+ */
+DECLINLINE(int) vmdkFileGetSize(PVMDKFILE pVmdkFile, uint64_t *pcbSize)
+{
+    if (pVmdkFile->fAsyncIO)
+    {
+        AssertMsgFailed(("TODO\n"));
+        return 0;
+    }
+    else
+        return RTFileGetSize(pVmdkFile->File, pcbSize);
+}
+
+/**
+ * Internal: set the size of a file distinguishing beween async and normal operation
+ */
+DECLINLINE(int) vmdkFileSetSize(PVMDKFILE pVmdkFile, uint64_t cbSize)
+{
+    if (pVmdkFile->fAsyncIO)
+    {
+        AssertMsgFailed(("TODO\n"));
+        return VERR_NOT_SUPPORTED;
+    }
+    else
+        return RTFileSetSize(pVmdkFile->File, cbSize);
+}
+
+/**
+ * Internal: flush a file distinguishing between async and normal operation
+ */
+DECLINLINE(int) vmdkFileFlush(PVMDKFILE pVmdkFile)
+{
+    PVMDKIMAGE pImage = pVmdkFile->pImage;
+
+    if (pVmdkFile->fAsyncIO)
+        return pImage->pInterfaceAsyncIOCallbacks->pfnFlush(pImage->pInterfaceAsyncIO->pvUser,
+                                                            pVmdkFile->pStorage);
+    else
+        return RTFileFlush(pVmdkFile->File);
 }
 
@@ -533,5 +656,11 @@
                 pVmdkFile->pszFilename));
         pImage->pFiles = pVmdkFile->pNext;
-        rc2 = RTFileClose(pVmdkFile->File);
+
+        if (pImage->uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
+            rc2 = pImage->pInterfaceAsyncIOCallbacks->pfnClose(pImage->pInterfaceAsyncIO->pvUser,
+                                                               pVmdkFile->pStorage);
+        else
+            rc2 = RTFileClose(pVmdkFile->File);
+
         if (VBOX_SUCCESS(rc) && pVmdkFile->fDelete)
             rc2 = RTFileDelete(pVmdkFile->pszFilename);
@@ -649,6 +778,6 @@
     }
     pExtent->pGD = pGD;
-    rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorGD),
-                      pGD, cbGD, NULL);
+    rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(pExtent->uSectorGD),
+                        pGD, cbGD, NULL);
     AssertRC(rc);
     if (VBOX_FAILURE(rc))
@@ -669,6 +798,6 @@
         }
         pExtent->pRGD = pRGD;
-        rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(pExtent->uSectorRGD),
-                          pRGD, cbGD, NULL);
+        rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(pExtent->uSectorRGD),
+                            pRGD, cbGD, NULL);
         AssertRC(rc);
         if (VBOX_FAILURE(rc))
@@ -714,6 +843,6 @@
                 goto out;
             }
-            rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(*pGDTmp),
-                              pTmpGT1, cbGT, NULL);
+            rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(*pGDTmp),
+                                pTmpGT1, cbGT, NULL);
             if (VBOX_FAILURE(rc))
             {
@@ -723,6 +852,6 @@
                 goto out;
             }
-            rc = RTFileReadAt(pExtent->File, VMDK_SECTOR2BYTE(*pRGDTmp),
-                              pTmpGT2, cbGT, NULL);
+            rc = vmdkFileReadAt(pExtent->pFile, VMDK_SECTOR2BYTE(*pRGDTmp),
+                                pTmpGT2, cbGT, NULL);
             if (VBOX_FAILURE(rc))
             {
@@ -782,5 +911,5 @@
 
     cbOverhead = RT_ALIGN_64(VMDK_SECTOR2BYTE(uStartSector) + 2 * (cbGDRounded + cbGTRounded), VMDK_SECTOR2BYTE(pExtent->cSectorsPerGrain));
-    rc = RTFileSetSize(pExtent->File, cbOverhead);
+    rc = vmdkFileSetSize(pExtent->pFile, cbOverhead);
     if (VBOX_FAILURE(rc))
         goto out;
@@ -799,7 +928,7 @@
             uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
             /* Write the redundant grain directory entry to disk. */
-            rc = RTFileWriteAt(pExtent->File,
-                               VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE),
-                               &uGTSectorLE, sizeof(uGTSectorLE), NULL);
+            rc = vmdkFileWriteAt(pExtent->pFile,
+                                 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + i * sizeof(uGTSectorLE),
+                                 &uGTSectorLE, sizeof(uGTSectorLE), NULL);
             if (VBOX_FAILURE(rc))
                 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new redundant grain directory entry in '%s'"), pExtent->pszFullname);
@@ -813,7 +942,7 @@
             uGTSectorLE = RT_H2LE_U64(uOffsetSectors);
             /* Write the grain directory entry to disk. */
-            rc = RTFileWriteAt(pExtent->File,
-                               VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE),
-                               &uGTSectorLE, sizeof(uGTSectorLE), NULL);
+            rc = vmdkFileWriteAt(pExtent->pFile,
+                                 VMDK_SECTOR2BYTE(pExtent->uSectorGD) + i * sizeof(uGTSectorLE),
+                                 &uGTSectorLE, sizeof(uGTSectorLE), NULL);
             if (VBOX_FAILURE(rc))
                 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write new grain directory entry in '%s'"), pExtent->pszFullname);
@@ -1819,5 +1948,5 @@
     uint64_t cbLimit;
     uint64_t uOffset;
-    RTFILE DescFile;
+    PVMDKFILE pDescFile;
 
     if (pImage->pDescData)
@@ -1826,5 +1955,5 @@
         uOffset = 0;
         cbLimit = 0;
-        DescFile = pImage->File;
+        pDescFile = pImage->pFile;
     }
     else
@@ -1834,5 +1963,5 @@
         cbLimit = VMDK_SECTOR2BYTE(pImage->pExtents[0].cDescriptorSectors);
         cbLimit += uOffset;
-        DescFile = pImage->pExtents[0].File;
+        pDescFile = pImage->pExtents[0].pFile;
     }
     for (unsigned i = 0; i < pImage->Descriptor.cLines; i++)
@@ -1843,9 +1972,9 @@
         if (cbLimit && uOffset + cb + 1 > cbLimit)
             return vmdkError(pImage, VERR_BUFFER_OVERFLOW, RT_SRC_POS, N_("VMDK: descriptor too long in '%s'"), pImage->pszFilename);
-        rc = RTFileWriteAt(DescFile, uOffset, psz, cb, NULL);
+        rc = vmdkFileWriteAt(pDescFile, uOffset, psz, cb, NULL);
         if (VBOX_FAILURE(rc))
             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
         uOffset += cb;
-        rc = RTFileWriteAt(DescFile, uOffset, "\n", 1, NULL);
+        rc = vmdkFileWriteAt(pDescFile, uOffset, "\n", 1, NULL);
         if (VBOX_FAILURE(rc))
             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
@@ -1857,5 +1986,5 @@
         while (uOffset < cbLimit)
         {
-            rc = RTFileWriteAt(DescFile, uOffset, "", 1, NULL);
+            rc = vmdkFileWriteAt(pDescFile, uOffset, "", 1, NULL);
             if (VBOX_FAILURE(rc))
                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error writing descriptor in '%s'"), pImage->pszFilename);
@@ -1865,5 +1994,5 @@
     else
     {
-        rc = RTFileSetSize(DescFile, uOffset);
+        rc = vmdkFileSetSize(pDescFile, uOffset);
         if (VBOX_FAILURE(rc))
             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: error truncating descriptor in '%s'"), pImage->pszFilename);
@@ -1881,5 +2010,5 @@
     uint64_t cbExtentSize, cSectorsPerGDE;
 
-    int rc = RTFileReadAt(pExtent->File, 0, &Header, sizeof(Header), NULL);
+    int rc = vmdkFileReadAt(pExtent->pFile, 0, &Header, sizeof(Header), NULL);
     AssertRC(rc);
     if (VBOX_FAILURE(rc))
@@ -1896,5 +2025,5 @@
     /* The image must be a multiple of a sector in size. If not, it means the
      * image is at least truncated, or even seriously garbled. */
-    rc = RTFileGetSize(pExtent->File, &cbExtentSize);
+    rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize);
     if (VBOX_FAILURE(rc))
     {
@@ -2005,5 +2134,5 @@
     Header.doubleEndLineChar2 = '\n';
 
-    int rc = RTFileWriteAt(pExtent->File, 0, &Header, sizeof(Header), NULL);
+    int rc = vmdkFileWriteAt(pExtent->pFile, 0, &Header, sizeof(Header), NULL);
     AssertRC(rc);
     if (VBOX_FAILURE(rc))
@@ -2023,5 +2152,5 @@
     uint64_t cSectorsPerGDE;
 
-    int rc = RTFileReadAt(pExtent->File, 0, &Header, sizeof(Header), NULL);
+    int rc = vmdkFileReadAt(pExtent->pFile, 0, &Header, sizeof(Header), NULL);
     AssertRC(rc);
     if (VBOX_FAILURE(rc))
@@ -2093,7 +2222,7 @@
         pExtent->pDescData = NULL;
     }
-    if (pExtent->File != NIL_RTFILE)
-    {
-        vmdkFileClose(pImage, &pExtent->File,
+    if (pExtent->pFile != NULL)
+    {
+        vmdkFileClose(pImage, &pExtent->pFile,
                          fDelete
                       && pExtent->pszFullname
@@ -2157,5 +2286,5 @@
         for (unsigned i = 0; i < cExtents; i++)
         {
-            pExtents[i].File = NIL_RTFILE;
+            pExtents[i].pFile = NULL;
             pExtents[i].pszBasename = NULL;
             pExtents[i].pszFullname = NULL;
@@ -2182,5 +2311,5 @@
     int rc;
     uint32_t u32Magic;
-    RTFILE File;
+    PVMDKFILE pFile;
     PVMDKEXTENT pExtent;
 
@@ -2189,9 +2318,12 @@
     /*
      * Open the image.
+     * We don't have to check for asynchronous access because 
+     * we only support raw access and the opened file is a description
+     * file were no data is stored.
      */
-    rc = vmdkFileOpen(pImage, &File, pImage->pszFilename,
+    rc = vmdkFileOpen(pImage, &pFile, pImage->pszFilename,
                       uOpenFlags & VD_OPEN_FLAGS_READONLY
                        ? RTFILE_O_READ      | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
-                       : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
+                       : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, false);
     if (VBOX_FAILURE(rc))
     {
@@ -2200,8 +2332,8 @@
         goto out;
     }
-    pImage->File = File;
+    pImage->pFile = pFile;
 
     /* Read magic (if present). */
-    rc = RTFileReadAt(File, 0, &u32Magic, sizeof(u32Magic), NULL);
+    rc = vmdkFileReadAt(pFile, 0, &u32Magic, sizeof(u32Magic), NULL);
     if (VBOX_FAILURE(rc))
     {
@@ -2220,6 +2352,6 @@
          * file, so no need to keep anything open for the image. */
         pExtent = &pImage->pExtents[0];
-        pExtent->File = File;
-        pImage->File = NIL_RTFILE;
+        pExtent->pFile = pFile;
+        pImage->pFile = NULL;
         pExtent->pszFullname = RTStrDup(pImage->pszFilename);
         if (!pExtent->pszFullname)
@@ -2245,8 +2377,8 @@
             goto out;
         }
-        rc = RTFileReadAt(pExtent->File,
-                          VMDK_SECTOR2BYTE(pExtent->uDescriptorSector),
-                          pExtent->pDescData,
-                          VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors), NULL);
+        rc = vmdkFileReadAt(pExtent->pFile,
+                            VMDK_SECTOR2BYTE(pExtent->uDescriptorSector),
+                            pExtent->pDescData,
+                            VMDK_SECTOR2BYTE(pExtent->cDescriptorSectors), NULL);
         AssertRC(rc);
         if (VBOX_FAILURE(rc))
@@ -2279,6 +2411,6 @@
 
         size_t cbRead;
-        rc = RTFileReadAt(pImage->File, 0, pImage->pDescData,
-                          pImage->cbDescAlloc, &cbRead);
+        rc = vmdkFileReadAt(pImage->pFile, 0, pImage->pDescData,
+                            pImage->cbDescAlloc, &cbRead);
         if (VBOX_FAILURE(rc))
         {
@@ -2298,4 +2430,29 @@
         if (VBOX_FAILURE(rc))
             goto out;
+
+        /* 
+         * We have to check for the asynchronous open flag. The
+         * extents are parsed and the type of all are known now.
+         * Check if every extent is either FLAT or ZERO.
+         */
+        if (uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO)
+        {
+            for (unsigned i = 0; i < pImage->cExtents; i++)
+            {
+                PVMDKEXTENT pExtent = &pImage->pExtents[i];
+
+                if (   (pExtent->enmType != VMDKETYPE_FLAT)
+                    && (pExtent->enmType != VMDKETYPE_ZERO))
+                {
+                    /* 
+                     * Opened image contains at least one none flat or zero extent.
+                     * Return error but don't set error message as the caller
+                     * has the chance to open in non async I/O mode.
+                     */
+                    rc = VERR_NOT_SUPPORTED;
+                    goto out;
+                }
+            }
+        }
 
         for (unsigned i = 0; i < pImage->cExtents; i++)
@@ -2344,8 +2501,8 @@
             {
                 case VMDKETYPE_HOSTED_SPARSE:
-                    rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname,
+                    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
                                       uOpenFlags & VD_OPEN_FLAGS_READONLY
                                         ? RTFILE_O_READ      | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
-                                        : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
+                                        : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, false);
                     if (VBOX_FAILURE(rc))
                     {
@@ -2367,8 +2524,8 @@
                     break;
                 case VMDKETYPE_FLAT:
-                    rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname,
+                    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
                                       uOpenFlags & VD_OPEN_FLAGS_READONLY
                                         ? RTFILE_O_READ      | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
-                                        : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
+                                        : RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, true);
                     if (VBOX_FAILURE(rc))
                     {
@@ -2469,6 +2626,7 @@
         pExtent = &pImage->pExtents[0];
         /* Create raw disk descriptor file. */
-        rc = vmdkFileOpen(pImage, &pImage->File, pImage->pszFilename,
-                          RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
+        rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename,
+                          RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED,
+                          false);
         if (VBOX_FAILURE(rc))
             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
@@ -2492,6 +2650,6 @@
 
         /* Open flat image, the raw disk. */
-        rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname,
-                          RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
+        rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
+                          RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, false);
         if (VBOX_FAILURE(rc))
             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw disk file '%s'"), pExtent->pszFullname);
@@ -2541,6 +2699,7 @@
 
         /* Create raw partition descriptor file. */
-        rc = vmdkFileOpen(pImage, &pImage->File, pImage->pszFilename,
-                          RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
+        rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename,
+                          RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED,
+                          false);
         if (VBOX_FAILURE(rc))
             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pImage->pszFilename);
@@ -2612,12 +2771,13 @@
 
                 /* Create partition table flat image. */
-                rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname,
-                                  RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
+                rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
+                                  RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED,
+                                  false);
                 if (VBOX_FAILURE(rc))
                     return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new partition data file '%s'"), pExtent->pszFullname);
-                rc = RTFileWriteAt(pExtent->File,
-                                   VMDK_SECTOR2BYTE(uPartOffset),
-                                   pPart->pvPartitionData,
-                                   pPart->cbPartitionData, NULL);
+                rc = vmdkFileWriteAt(pExtent->pFile,
+                                     VMDK_SECTOR2BYTE(uPartOffset),
+                                     pPart->pvPartitionData,
+                                     pPart->cbPartitionData, NULL);
                 if (VBOX_FAILURE(rc))
                     return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not write partition data to '%s'"), pExtent->pszFullname);
@@ -2659,6 +2819,7 @@
 
                     /* Open flat image, the raw partition. */
-                    rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname,
-                                      RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
+                    rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
+                                      RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE,
+                                      false);
                     if (VBOX_FAILURE(rc))
                         return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not open raw partition file '%s'"), pExtent->pszFullname);
@@ -2731,6 +2892,7 @@
     if (cExtents != 1 || enmType == VD_IMAGE_TYPE_FIXED)
     {
-        rc = vmdkFileOpen(pImage, &pImage->File, pImage->pszFilename,
-                          RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
+        rc = vmdkFileOpen(pImage, &pImage->pFile, pImage->pszFilename,
+                          RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED,
+                          false);
         if (VBOX_FAILURE(rc))
             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new sparse descriptor file '%s'"), pImage->pszFilename);
@@ -2738,5 +2900,5 @@
     }
     else
-        pImage->File = NIL_RTFILE;
+        pImage->pFile = NULL;
 
     /* Set up all extents. */
@@ -2801,11 +2963,12 @@
 
         /* Create file for extent. */
-        rc = vmdkFileOpen(pImage, &pExtent->File, pExtent->pszFullname,
-                          RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED);
+        rc = vmdkFileOpen(pImage, &pExtent->pFile, pExtent->pszFullname,
+                          RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE | RTFILE_O_NOT_CONTENT_INDEXED,
+                          false);
         if (VBOX_FAILURE(rc))
             return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not create new file '%s'"), pExtent->pszFullname);
         if (enmType == VD_IMAGE_TYPE_FIXED)
         {
-            rc = RTFileSetSize(pExtent->File, cbExtent);
+            rc = vmdkFileSetSize(pExtent->pFile, cbExtent);
             if (VBOX_FAILURE(rc))
                 return vmdkError(pImage, rc, RT_SRC_POS, N_("VMDK: could not set size of new file '%s'"), pExtent->pszFullname);
@@ -2830,5 +2993,5 @@
                 unsigned cbChunk = (unsigned)RT_MIN(cbExtent, cbBuf);
 
-                rc = RTFileWriteAt(pExtent->File, uOff, pvBuf, cbChunk, NULL);
+                rc = vmdkFileWriteAt(pExtent->pFile, uOff, pvBuf, cbChunk, NULL);
                 if (VBOX_FAILURE(rc))
                 {
@@ -3140,6 +3303,6 @@
         pImage->pExtents = NULL;
     }
-    if (pImage->File != NIL_RTFILE)
-        vmdkFileClose(pImage, &pImage->File, fDelete);
+    if (pImage->pFile != NULL)
+        vmdkFileClose(pImage, &pImage->pFile, fDelete);
     vmdkFileCheckAllClose(pImage);
 }
@@ -3164,5 +3327,5 @@
     {
         pExtent = &pImage->pExtents[i];
-        if (pExtent->File != NIL_RTFILE && pExtent->fMetaDirty)
+        if (pExtent->pFile != NULL && pExtent->fMetaDirty)
         {
             switch (pExtent->enmType)
@@ -3196,8 +3359,8 @@
             case VMDKETYPE_FLAT:
                 /** @todo implement proper path absolute check. */
-                if (   pExtent->File != NIL_RTFILE
+                if (   pExtent->pFile != NULL
                     && !(pImage->uOpenFlags & VD_OPEN_FLAGS_READONLY)
                     && !(pExtent->pszBasename[0] == RTPATH_SLASH))
-                    rc = RTFileFlush(pExtent->File);
+                    rc = vmdkFileFlush(pExtent->pFile);
                 break;
             case VMDKETYPE_ZERO:
@@ -3285,7 +3448,7 @@
     {
         /* Cache miss, fetch data from disk. */
-        rc = RTFileReadAt(pExtent->File,
-                          VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
-                          aGTDataTmp, sizeof(aGTDataTmp), NULL);
+        rc = vmdkFileReadAt(pExtent->pFile,
+                            VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
+                            aGTDataTmp, sizeof(aGTDataTmp), NULL);
         if (VBOX_FAILURE(rc))
             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read grain table entry in '%s'"), pExtent->pszFullname);
@@ -3334,5 +3497,5 @@
          * entry. So there is absolutely no data in this area. Allocate
          * a new grain table and put the reference to it in the GDs. */
-        rc = RTFileGetSize(pExtent->File, &cbExtentSize);
+        rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize);
         if (VBOX_FAILURE(rc))
             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
@@ -3353,7 +3516,7 @@
              i++)
         {
-            rc = RTFileWriteAt(pExtent->File,
-                               VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp),
-                               aGTDataTmp, sizeof(aGTDataTmp), NULL);
+            rc = vmdkFileWriteAt(pExtent->pFile,
+                                 VMDK_SECTOR2BYTE(uGTSector) + i * sizeof(aGTDataTmp),
+                                 aGTDataTmp, sizeof(aGTDataTmp), NULL);
             if (VBOX_FAILURE(rc))
                 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain table allocation in '%s'"), pExtent->pszFullname);
@@ -3362,5 +3525,5 @@
         {
             AssertReturn(!uRGTSector, VERR_VDI_INVALID_HEADER);
-            rc = RTFileGetSize(pExtent->File, &cbExtentSize);
+            rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize);
             if (VBOX_FAILURE(rc))
                 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
@@ -3380,7 +3543,7 @@
                  i++)
             {
-                rc = RTFileWriteAt(pExtent->File,
-                                   VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp),
-                                   aGTDataTmp, sizeof(aGTDataTmp), NULL);
+                rc = vmdkFileWriteAt(pExtent->pFile,
+                                     VMDK_SECTOR2BYTE(uRGTSector) + i * sizeof(aGTDataTmp),
+                                     aGTDataTmp, sizeof(aGTDataTmp), NULL);
                 if (VBOX_FAILURE(rc))
                     return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain table allocation in '%s'"), pExtent->pszFullname);
@@ -3393,7 +3556,7 @@
          * some unused sectors in the extent. */
         uint32_t uGTSectorLE = RT_H2LE_U64(uGTSector);
-        rc = RTFileWriteAt(pExtent->File,
-                           VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
-                           &uGTSectorLE, sizeof(uGTSectorLE), NULL);
+        rc = vmdkFileWriteAt(pExtent->pFile,
+                             VMDK_SECTOR2BYTE(pExtent->uSectorGD) + uGDIndex * sizeof(uGTSectorLE),
+                             &uGTSectorLE, sizeof(uGTSectorLE), NULL);
         if (VBOX_FAILURE(rc))
             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write grain directory entry in '%s'"), pExtent->pszFullname);
@@ -3401,7 +3564,7 @@
         {
             uint32_t uRGTSectorLE = RT_H2LE_U64(uRGTSector);
-            rc = RTFileWriteAt(pExtent->File,
-                               VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE),
-                               &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);
+            rc = vmdkFileWriteAt(pExtent->pFile,
+                                 VMDK_SECTOR2BYTE(pExtent->uSectorRGD) + uGDIndex * sizeof(uRGTSectorLE),
+                                 &uRGTSectorLE, sizeof(uRGTSectorLE), NULL);
             if (VBOX_FAILURE(rc))
                 return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write backup grain directory entry in '%s'"), pExtent->pszFullname);
@@ -3414,5 +3577,5 @@
     }
 
-    rc = RTFileGetSize(pExtent->File, &cbExtentSize);
+    rc = vmdkFileGetSize(pExtent->pFile, &cbExtentSize);
     if (VBOX_FAILURE(rc))
         return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: error getting size in '%s'"), pExtent->pszFullname);
@@ -3420,5 +3583,5 @@
 
     /* Write the data. */
-    rc = RTFileWriteAt(pExtent->File, cbExtentSize, pvBuf, cbWrite, NULL);
+    rc = vmdkFileWriteAt(pExtent->pFile, cbExtentSize, pvBuf, cbWrite, NULL);
     if (VBOX_FAILURE(rc))
         return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write allocated data block in '%s'"), pExtent->pszFullname);
@@ -3432,7 +3595,7 @@
     {
         /* Cache miss, fetch data from disk. */
-        rc = RTFileReadAt(pExtent->File,
-                          VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
-                          aGTDataTmp, sizeof(aGTDataTmp), NULL);
+        rc = vmdkFileReadAt(pExtent->pFile,
+                            VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
+                            aGTDataTmp, sizeof(aGTDataTmp), NULL);
         if (VBOX_FAILURE(rc))
             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot read allocated grain table entry in '%s'"), pExtent->pszFullname);
@@ -3453,7 +3616,7 @@
     pGTCacheEntry->aGTData[uGTBlockIndex] = VMDK_BYTE2SECTOR(cbExtentSize);
     /* Update grain table on disk. */
-    rc = RTFileWriteAt(pExtent->File,
-                       VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
-                       aGTDataTmp, sizeof(aGTDataTmp), NULL);
+    rc = vmdkFileWriteAt(pExtent->pFile,
+                         VMDK_SECTOR2BYTE(uGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
+                         aGTDataTmp, sizeof(aGTDataTmp), NULL);
     if (VBOX_FAILURE(rc))
         return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated grain table in '%s'"), pExtent->pszFullname);
@@ -3461,7 +3624,7 @@
     {
         /* Update backup grain table on disk. */
-        rc = RTFileWriteAt(pExtent->File,
-                           VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
-                           aGTDataTmp, sizeof(aGTDataTmp), NULL);
+        rc = vmdkFileWriteAt(pExtent->pFile,
+                             VMDK_SECTOR2BYTE(uRGTSector) + (uGTBlock % (pExtent->cGTEntries / VMDK_GT_CACHELINE_SIZE)) * sizeof(aGTDataTmp),
+                             aGTDataTmp, sizeof(aGTDataTmp), NULL);
         if (VBOX_FAILURE(rc))
             return vmdkError(pExtent->pImage, rc, RT_SRC_POS, N_("VMDK: cannot write updated backup grain table in '%s'"), pExtent->pszFullname);
@@ -3500,11 +3663,11 @@
     }
     pImage->pszFilename = pszFilename;
-    pImage->File = NIL_RTFILE;
+    pImage->pFile = NULL;
     pImage->pExtents = NULL;
     pImage->pFiles = NULL;
     pImage->pGTCache = NULL;
     pImage->pDescData = NULL;
-    pImage->pfnError = NULL;
-    pImage->pvErrorUser = NULL;
+    pImage->pInterfaceError = NULL;
+    pImage->pInterfaceErrorCallbacks = NULL;
     /** @todo speed up this test open (VD_OPEN_FLAGS_INFO) by skipping as
      * much as possible in vmdkOpenImage. */
@@ -3519,5 +3682,5 @@
 /** @copydoc VBOXHDDBACKEND::pfnOpen */
 static int vmdkOpen(const char *pszFilename, unsigned uOpenFlags,
-                    PFNVDERROR pfnError, void *pvErrorUser,
+                    PVDINTERFACE pInterfaces,
                     void **ppBackendData)
 {
@@ -3550,11 +3713,22 @@
     }
     pImage->pszFilename = pszFilename;
-    pImage->File = NIL_RTFILE;
+    pImage->pFile = NULL;
     pImage->pExtents = NULL;
     pImage->pFiles = NULL;
     pImage->pGTCache = NULL;
     pImage->pDescData = NULL;
-    pImage->pfnError = pfnError;
-    pImage->pvErrorUser = pvErrorUser;
+    pImage->pInterfaceError = NULL;
+    pImage->pInterfaceErrorCallbacks = NULL;
+
+    /* Try to get error interface. */
+    pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR);
+    if (pImage->pInterfaceError)
+        pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError->pCallbacks);
+
+    /* Try to get async I/O interfaec. */
+    pImage->pInterfaceAsyncIO = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ASYNCIO);
+    if (pImage->pInterfaceAsyncIO)
+        pImage->pInterfaceAsyncIOCallbacks = VDGetInterfaceAsyncIO(pImage->pInterfaceAsyncIO->pCallbacks);
+
 
     rc = vmdkOpenImage(pImage, uOpenFlags);
@@ -3575,8 +3749,8 @@
                       unsigned uOpenFlags, PFNVMPROGRESS pfnProgress,
                       void *pvUser, unsigned uPercentStart,
-                      unsigned uPercentSpan, PFNVDERROR pfnError,
-                      void *pvErrorUser, void **ppBackendData)
-{
-    LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pfnError=%#p pvErrorUser=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pfnError, pvErrorUser, ppBackendData));
+                      unsigned uPercentSpan, PVDINTERFACE pInterfaces,
+                      void **ppBackendData)
+{
+    LogFlowFunc(("pszFilename=\"%s\" enmType=%d cbSize=%llu uImageFlags=%#x pszComment=\"%s\" pPCHSGeometry=%#p pLCHSGeometry=%#p uOpenFlags=%#x pfnProgress=%#p pvUser=%#p uPercentStart=%u uPercentSpan=%u pInterfaces=%#p ppBackendData=%#p", pszFilename, enmType, cbSize, uImageFlags, pszComment, pPCHSGeometry, pLCHSGeometry, uOpenFlags, pfnProgress, pvUser, uPercentStart, uPercentSpan, pInterfaces, ppBackendData));
     int rc;
     PVMDKIMAGE pImage;
@@ -3612,11 +3786,11 @@
     }
     pImage->pszFilename = pszFilename;
-    pImage->File = NIL_RTFILE;
+    pImage->pFile = NULL;
     pImage->pExtents = NULL;
     pImage->pFiles = NULL;
     pImage->pGTCache = NULL;
     pImage->pDescData = NULL;
-    pImage->pfnError = pfnError;
-    pImage->pvErrorUser = pvErrorUser;
+    pImage->pInterfaceError = NULL;
+    pImage->pInterfaceErrorCallbacks = NULL;
     pImage->cbDescAlloc = VMDK_SECTOR2BYTE(20);
     pImage->pDescData = (char *)RTMemAllocZ(pImage->cbDescAlloc);
@@ -3626,4 +3800,9 @@
         goto out;
     }
+
+    /* Get error interface. */
+    pImage->pInterfaceError = VDGetInterfaceFromList(pInterfaces, VDINTERFACETYPE_ERROR);
+    if (pImage->pInterfaceError)
+        pImage->pInterfaceErrorCallbacks = VDGetInterfaceError(pImage->pInterfaceError);
 
     rc = vmdkCreateImage(pImage, enmType, cbSize, uImageFlags, pszComment,
@@ -3780,5 +3959,5 @@
             goto rollback;
         /* Close the extent file. */
-        vmdkFileClose(pImage, &pExtent->File, false);
+        vmdkFileClose(pImage, &pExtent->pFile, false);
         /* Rename the extent file. */
         rc = RTFileMove(pExtent->pszFullname, apszNewName[i], 0);
@@ -3846,18 +4025,18 @@
         }
         /* Restore the old descriptor. */
-        RTFILE File;
-        rrc = RTFileOpen(&File, pszOldDescName,
-            RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
+        PVMDKFILE pFile;
+        rrc = vmdkFileOpen(pImage, &pFile, pszOldDescName,
+            RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE, false);
         AssertRC(rrc);
         if (fEmbeddedDesc)
         {
-            ExtentCopy.File   = File;
+            ExtentCopy.pFile   = pFile;
             pImage->pExtents = &ExtentCopy;
         }
         else
-            pImage->File = File;
+            pImage->pFile = pFile;
         pImage->Descriptor = DescriptorCopy;
         vmdkWriteDescriptor(pImage);
-        RTFileClose(File);
+        vmdkFileClose(pImage, &pFile, false);
         RTStrFree(pszOldDescName);
         /* Re-open the image back. */
@@ -3950,12 +4129,12 @@
                 rc = VERR_VDI_BLOCK_FREE;
             else
-                rc = RTFileReadAt(pExtent->File,
-                                  VMDK_SECTOR2BYTE(uSectorExtentAbs),
-                                  pvBuf, cbToRead, NULL);
+                rc = vmdkFileReadAt(pExtent->pFile,
+                                    VMDK_SECTOR2BYTE(uSectorExtentAbs),
+                                    pvBuf, cbToRead, NULL);
             break;
         case VMDKETYPE_FLAT:
-            rc = RTFileReadAt(pExtent->File,
-                              VMDK_SECTOR2BYTE(uSectorExtentRel),
-                              pvBuf, cbToRead, NULL);
+            rc = vmdkFileReadAt(pExtent->pFile,
+                                VMDK_SECTOR2BYTE(uSectorExtentRel),
+                                pvBuf, cbToRead, NULL);
             break;
         case VMDKETYPE_ZERO:
@@ -4057,14 +4236,14 @@
             }
             else
-                rc = RTFileWriteAt(pExtent->File,
-                                   VMDK_SECTOR2BYTE(uSectorExtentAbs),
-                                   pvBuf, cbToWrite, NULL);
+                rc = vmdkFileWriteAt(pExtent->pFile,
+                                     VMDK_SECTOR2BYTE(uSectorExtentAbs),
+                                     pvBuf, cbToWrite, NULL);
             break;
         case VMDKETYPE_FLAT:
             /* Clip write range to remain in this extent. */
             cbToWrite = RT_MIN(cbToWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
-            rc = RTFileWriteAt(pExtent->File,
-                               VMDK_SECTOR2BYTE(uSectorExtentRel),
-                               pvBuf, cbToWrite, NULL);
+            rc = vmdkFileWriteAt(pExtent->pFile,
+                                 VMDK_SECTOR2BYTE(uSectorExtentRel),
+                                 pvBuf, cbToWrite, NULL);
             break;
         case VMDKETYPE_ZERO:
@@ -4154,12 +4333,12 @@
     {
         uint64_t cbFile;
-        if (pImage->File != NIL_RTFILE)
-        {
-            int rc = RTFileGetSize(pImage->File, &cbFile);
+        if (pImage->pFile != NULL)
+        {
+            int rc = vmdkFileGetSize(pImage->pFile, &cbFile);
             if (VBOX_SUCCESS(rc))
                 cb += cbFile;
             for (unsigned i = 0; i <= pImage->cExtents; i++)
             {
-                rc = RTFileGetSize(pImage->File, &cbFile);
+                rc = vmdkFileGetSize(pImage->pFile, &cbFile);
                 if (VBOX_SUCCESS(rc))
                     cb += cbFile;
@@ -4336,5 +4515,5 @@
     /* Image must be opened and the new flags must be valid. Just readonly flag
      * is supported. */
-    if (!pImage || uOpenFlags & ~VD_OPEN_FLAGS_READONLY)
+    if (!pImage || uOpenFlags & ~(VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_ASYNC_IO))
     {
         rc = VERR_INVALID_PARAMETER;
@@ -4672,4 +4851,301 @@
 }
 
+static bool vmdkIsAsyncIOSupported(void *pvBackendData)
+{
+    PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
+    bool fAsyncIOSupported = false;
+
+    if (pImage)
+    {
+        /* We only support async I/O support if the image only consists of FLAT or ZERO extents. */
+        fAsyncIOSupported = true;
+        for (unsigned i = 0; i < pImage->cExtents; i++)
+        {
+            if (   (pImage->pExtents[i].enmType != VMDKETYPE_FLAT)
+                && (pImage->pExtents[i].enmType != VMDKETYPE_ZERO))
+            {
+                fAsyncIOSupported = false;
+                break; /* Stop search */
+            }
+        }
+    }
+
+    return fAsyncIOSupported;
+}
+
+static int vmdkAsyncRead(void *pvBackendData, uint64_t uOffset, size_t cbRead,
+                         PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
+{
+    PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
+    PVMDKEXTENT pExtent;
+    int rc = VINF_SUCCESS;
+    unsigned cTasksToSubmit = 0;
+    PPDMDATASEG paSegCurrent = paSeg;
+    unsigned  cbLeftInCurrentSegment = paSegCurrent->cbSeg;
+    unsigned  uOffsetInCurrentSegment = 0;
+
+    Assert(pImage);
+    Assert(uOffset % 512 == 0);
+    Assert(cbRead % 512 == 0);
+
+    if (   uOffset + cbRead > pImage->cbSize
+        || cbRead == 0)
+    {
+        rc = VERR_INVALID_PARAMETER;
+        goto out;
+    }
+
+    while (cbRead && cSeg)
+    {
+        unsigned cbToRead;
+        uint64_t uSectorExtentRel;
+
+        rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
+                            &pExtent, &uSectorExtentRel);
+        if (VBOX_FAILURE(rc))
+            goto out;
+
+        /* Check access permissions as defined in the extent descriptor. */
+        if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
+        {
+            rc = VERR_VDI_INVALID_STATE;
+            goto out;
+        }
+
+        /* Clip read range to remain in this extent. */
+        cbToRead = RT_MIN(cbRead, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
+        /* Clip read range to remain into current data segment. */
+        cbToRead = RT_MIN(cbToRead, cbLeftInCurrentSegment);
+
+        switch (pExtent->enmType)
+        {
+            case VMDKETYPE_FLAT:
+            {
+                /* Setup new task. */
+                void *pTask;
+                rc = pImage->pInterfaceAsyncIOCallbacks->pfnPrepareRead(pImage->pInterfaceAsyncIO->pvUser, pExtent->pFile->pStorage,
+                                                                       VMDK_SECTOR2BYTE(uSectorExtentRel), 
+                                                                       (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment,
+                                                                       cbToRead, &pTask);
+                if (VBOX_FAILURE(rc))
+                {
+                    AssertMsgFailed(("Preparing read failed rc=%Vrc\n", rc));
+                    goto out;
+                }
+
+                /* Check for enough room first. */
+                if (cTasksToSubmit >= pImage->cTask)
+                {
+                    /* We reached maximum, resize array. Try to realloc memory first. */
+                    void **apTaskNew = (void **)RTMemRealloc(pImage->apTask, (cTasksToSubmit + 10)*sizeof(void *));
+
+                    if (!apTaskNew)
+                    {
+                        /* We failed. Allocate completely new. */
+                        apTaskNew = (void **)RTMemAllocZ((cTasksToSubmit + 10)* sizeof(void *));
+                        if (!apTaskNew)
+                        {
+                            /* Damn, we are out of memory. */
+                            rc = VERR_NO_MEMORY;
+                            goto out;
+                        }
+
+                        /* Copy task handles over. */
+                        for (unsigned i = 0; i < cTasksToSubmit; i++)
+                            apTaskNew[i] = pImage->apTask[i];
+
+                        /* Free old memory. */
+                        RTMemFree(pImage->apTask);
+                    }
+
+                    pImage->cTask = cTasksToSubmit + 10;
+                    pImage->apTask = apTaskNew;
+                }
+
+                pImage->apTask[cTasksToSubmit] = pTask;
+                cTasksToSubmit++;
+                break;
+            }
+            case VMDKETYPE_ZERO:
+                memset((uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment, 0, cbToRead); 
+                break;
+            default:
+                AssertMsgFailed(("Unsupported extent type %u\n", pExtent->enmType));
+        }
+
+        cbRead  -= cbToRead;
+        uOffset += cbToRead;
+        cbLeftInCurrentSegment -= cbToRead;
+        uOffsetInCurrentSegment += cbToRead;
+        /* Go to next extent if there is no space left in current one. */
+        if (!cbLeftInCurrentSegment)
+        {
+            uOffsetInCurrentSegment = 0;
+            paSegCurrent++;
+            cSeg--;
+            cbLeftInCurrentSegment = paSegCurrent->cbSeg;
+        }
+    }
+
+    AssertMsg((cSeg >= 0) && (cbRead == 0), ("No segment left but there is still data to read\n"));
+
+    if (cTasksToSubmit == 0)
+    {
+        /* The request was completely in a ZERO extent nothing to do. */
+        rc = VINF_VDI_ASYNC_IO_FINISHED;
+    }
+    else
+    {
+        /* Submit tasks. */
+        rc = pImage->pInterfaceAsyncIOCallbacks->pfnTasksSubmit(pImage->pInterfaceAsyncIO->pvUser,
+                                                                pImage->apTask, cTasksToSubmit,
+                                                                NULL, pvUser,
+                                                                NULL /* Nothing required after read. */);
+        AssertMsg(VBOX_SUCCESS(rc), ("Failed to enqueue tasks rc=%Vrc\n", rc));
+    }
+
+out:
+    LogFlowFunc(("returns %Vrc\n", rc));
+    return rc;
+}
+
+static int vmdkAsyncWrite(void *pvBackendData, uint64_t uOffset, size_t cbWrite,
+                          PPDMDATASEG paSeg, unsigned cSeg, void *pvUser)
+{
+    PVMDKIMAGE pImage = (PVMDKIMAGE)pvBackendData;
+    PVMDKEXTENT pExtent;
+    int rc = VINF_SUCCESS;
+    unsigned cTasksToSubmit = 0;
+    PPDMDATASEG paSegCurrent = paSeg;
+    unsigned  cbLeftInCurrentSegment = paSegCurrent->cbSeg;
+    unsigned  uOffsetInCurrentSegment = 0;
+
+    Assert(pImage);
+    Assert(uOffset % 512 == 0);
+    Assert(cbWrite % 512 == 0);
+
+    if (   uOffset + cbWrite > pImage->cbSize
+        || cbWrite == 0)
+    {
+        rc = VERR_INVALID_PARAMETER;
+        goto out;
+    }
+
+    while (cbWrite && cSeg)
+    {
+        unsigned cbToWrite;
+        uint64_t uSectorExtentRel;
+
+        rc = vmdkFindExtent(pImage, VMDK_BYTE2SECTOR(uOffset),
+                            &pExtent, &uSectorExtentRel);
+        if (VBOX_FAILURE(rc))
+            goto out;
+
+        /* Check access permissions as defined in the extent descriptor. */
+        if (pExtent->enmAccess == VMDKACCESS_NOACCESS)
+        {
+            rc = VERR_VDI_INVALID_STATE;
+            goto out;
+        }
+
+        /* Clip write range to remain in this extent. */
+        cbToWrite = RT_MIN(cbWrite, VMDK_SECTOR2BYTE(pExtent->uSectorOffset + pExtent->cNominalSectors - uSectorExtentRel));
+        /* Clip write range to remain into current data segment. */
+        cbToWrite = RT_MIN(cbToWrite, cbLeftInCurrentSegment);
+
+        switch (pExtent->enmType)
+        {
+            case VMDKETYPE_FLAT:
+            {
+                /* Setup new task. */
+                void *pTask;
+                rc = pImage->pInterfaceAsyncIOCallbacks->pfnPrepareWrite(pImage->pInterfaceAsyncIO->pvUser, pExtent->pFile->pStorage,
+                                                                         VMDK_SECTOR2BYTE(uSectorExtentRel), 
+                                                                         (uint8_t *)paSegCurrent->pvSeg + uOffsetInCurrentSegment,
+                                                                         cbToWrite, &pTask);
+                if (VBOX_FAILURE(rc))
+                {
+                    AssertMsgFailed(("Preparing read failed rc=%Vrc\n", rc));
+                    goto out;
+                }
+
+                /* Check for enough room first. */
+                if (cTasksToSubmit >= pImage->cTask)
+                {
+                    /* We reached maximum, resize array. Try to realloc memory first. */
+                    void **apTaskNew = (void **)RTMemRealloc(pImage->apTask, (cTasksToSubmit + 10)*sizeof(void *));
+
+                    if (!apTaskNew)
+                    {
+                        /* We failed. Allocate completely new. */
+                        apTaskNew = (void **)RTMemAllocZ((cTasksToSubmit + 10)* sizeof(void *));
+                        if (!apTaskNew)
+                        {
+                            /* Damn, we are out of memory. */
+                            rc = VERR_NO_MEMORY;
+                            goto out;
+                        }
+
+                        /* Copy task handles over. */
+                        for (unsigned i = 0; i < cTasksToSubmit; i++)
+                            apTaskNew[i] = pImage->apTask[i];
+
+                        /* Free old memory. */
+                        RTMemFree(pImage->apTask);
+                    }
+
+                    pImage->cTask = cTasksToSubmit + 10;
+                    pImage->apTask = apTaskNew;
+                }
+
+                pImage->apTask[cTasksToSubmit] = pTask;
+                cTasksToSubmit++;
+                break;
+            }
+            case VMDKETYPE_ZERO:
+                /* Nothing left to do. */
+                break;
+            default:
+                AssertMsgFailed(("Unsupported extent type %u\n", pExtent->enmType));
+        }
+
+        cbWrite  -= cbToWrite;
+        uOffset  += cbToWrite;
+        cbLeftInCurrentSegment -= cbToWrite;
+        uOffsetInCurrentSegment += cbToWrite;
+        /* Go to next extent if there is no space left in current one. */
+        if (!cbLeftInCurrentSegment)
+        {
+            uOffsetInCurrentSegment = 0;
+            paSegCurrent++;
+            cSeg--;
+            cbLeftInCurrentSegment = paSegCurrent->cbSeg;
+        }
+    }
+
+    AssertMsg((cSeg >= 0) && (cbWrite == 0), ("No segment left but there is still data to read\n"));
+
+    if (cTasksToSubmit == 0)
+    {
+        /* The request was completely in a ZERO extent nothing to do. */
+        rc = VINF_VDI_ASYNC_IO_FINISHED;
+    }
+    else
+    {
+        /* Submit tasks. */
+        rc = pImage->pInterfaceAsyncIOCallbacks->pfnTasksSubmit(pImage->pInterfaceAsyncIO->pvUser,
+                                                                pImage->apTask, cTasksToSubmit,
+                                                                NULL, pvUser, 
+                                                                NULL /* Nothing required after read. */);
+        AssertMsg(VBOX_SUCCESS(rc), ("Failed to enqueue tasks rc=%Vrc\n", rc));
+    }
+
+out:
+    LogFlowFunc(("returns %Vrc\n", rc));
+    return rc;
+
+}
+
+
 VBOXHDDBACKEND g_VmdkBackend =
 {
@@ -4680,5 +5156,5 @@
     /* uBackendCaps */
       VD_CAP_UUID | VD_CAP_CREATE_FIXED | VD_CAP_CREATE_DYNAMIC
-    | VD_CAP_CREATE_SPLIT_2G | VD_CAP_DIFF | VD_CAP_FILE,
+    | VD_CAP_CREATE_SPLIT_2G | VD_CAP_DIFF | VD_CAP_FILE |VD_CAP_ASYNC,
     /* pfnCheckIfValid */
     vmdkCheckIfValid,
@@ -4750,4 +5226,10 @@
     vmdkGetParentFilename,
     /* pfnSetParentFilename */
-    vmdkSetParentFilename
+    vmdkSetParentFilename,
+    /* pfnIsAsyncIOSupported */
+    vmdkIsAsyncIOSupported,
+    /* pfnAsyncRead */
+    vmdkAsyncRead,
+    /* pfnAsyncWrite */
+    vmdkAsyncWrite
 };
Index: /trunk/src/VBox/Devices/Storage/testcase/tstVD.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/testcase/tstVD.cpp	(revision 10714)
+++ /trunk/src/VBox/Devices/Storage/testcase/tstVD.cpp	(revision 10715)
@@ -56,4 +56,6 @@
     PDMMEDIAGEOMETRY PCHS = { 0, 0, 0 };
     PDMMEDIAGEOMETRY LCHS = { 0, 0, 0 };
+    VDINTERFACE      VDIError;
+    VDINTERFACEERROR VDIErrorCallbacks;
 
 #define CHECK(str) \
@@ -68,5 +70,14 @@
     } while (0)
 
-    rc = VDCreate(tstVDError, NULL, &pVD);
+    /* Create error interface. */
+    VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
+    VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
+    VDIErrorCallbacks.pfnError = tstVDError;
+
+    rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
+                           NULL, NULL);
+    AssertRC(rc);
+
+    rc = VDCreate(&VDIError, &pVD);
     CHECK("VDCreate()");
 
@@ -420,4 +431,6 @@
     uint64_t u64DiskSize  = 1000 * _1M;
     uint32_t u32SectorSize = 512;
+    VDINTERFACE      VDIError;
+    VDINTERFACEERROR VDIErrorCallbacks;
 
 #define CHECK(str) \
@@ -432,5 +445,15 @@
     } while (0)
 
-    rc = VDCreate(tstVDError, NULL, &pVD);
+    /* Create error interface. */
+    VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
+    VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
+    VDIErrorCallbacks.pfnError = tstVDError;
+
+    rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
+                           NULL, NULL);
+    AssertRC(rc);
+
+
+    rc = VDCreate(&VDIError, &pVD);
     CHECK("VDCreate()");
 
@@ -526,4 +549,6 @@
     uint64_t u64DiskSize  = 1000 * _1M;
     uint32_t u32SectorSize = 512;
+    VDINTERFACE      VDIError;
+    VDINTERFACEERROR VDIErrorCallbacks;
 
 #define CHECK(str) \
@@ -538,5 +563,15 @@
     } while (0)
 
-    rc = VDCreate(tstVDError, NULL, &pVD);
+    /* Create error interface. */
+    VDIErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
+    VDIErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
+    VDIErrorCallbacks.pfnError = tstVDError;
+
+    rc = VDInterfaceCreate(&VDIError, "tstVD_Error", VDINTERFACETYPE_ERROR, &VDIErrorCallbacks,
+                           NULL, NULL);
+    AssertRC(rc);
+
+
+    rc = VDCreate(&VDIError, &pVD);
     CHECK("VDCreate()");
 
Index: /trunk/src/VBox/Devices/testcase/tstDeviceStructSizeGC.cpp
===================================================================
--- /trunk/src/VBox/Devices/testcase/tstDeviceStructSizeGC.cpp	(revision 10714)
+++ /trunk/src/VBox/Devices/testcase/tstDeviceStructSizeGC.cpp	(revision 10715)
@@ -908,4 +908,8 @@
     GEN_CHECK_OFF(AHCIPort, u32TasksFinished);
     GEN_CHECK_OFF(AHCIPort, u32QueuedTasksFinished);
+    GEN_CHECK_OFF(AHCIPort, StatDMA);
+    GEN_CHECK_OFF(AHCIPort, StatBytesWritten);
+    GEN_CHECK_OFF(AHCIPort, StatBytesRead);
+    GEN_CHECK_OFF(AHCIPort, StatQueueFillRate);
 
     GEN_CHECK_SIZE(AHCI);
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp	(revision 10714)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp	(revision 10715)
@@ -1093,5 +1093,15 @@
     RTFileClose(RawFile);
 
-    vrc = VDCreate(handleVDError, NULL, &pDisk);
+    VDINTERFACE      vdInterfaceError;
+    VDINTERFACEERROR vdInterfaceErrorCallbacks;
+    vdInterfaceErrorCallbacks.cbSize       = sizeof(VDINTERFACEERROR);
+    vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
+    vdInterfaceErrorCallbacks.pfnError     = handleVDError;
+
+    vrc = VDInterfaceCreate(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
+                            &vdInterfaceErrorCallbacks, NULL, NULL);
+    AssertRC(vrc);
+
+    vrc = VDCreate(&vdInterfaceError, &pDisk);
     if (VBOX_FAILURE(vrc))
     {
@@ -1192,5 +1202,15 @@
     PVBOXHDD pDisk = NULL;
 
-    int vrc = VDCreate(handleVDError, NULL, &pDisk);
+    VDINTERFACE      vdInterfaceError;
+    VDINTERFACEERROR vdInterfaceErrorCallbacks;
+    vdInterfaceErrorCallbacks.cbSize       = sizeof(VDINTERFACEERROR);
+    vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
+    vdInterfaceErrorCallbacks.pfnError     = handleVDError;
+
+    int vrc = VDInterfaceCreate(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
+                                &vdInterfaceErrorCallbacks, NULL, NULL);
+    AssertRC(vrc);
+
+    vrc = VDCreate(&vdInterfaceError, &pDisk);
     if (VBOX_FAILURE(vrc))
     {
Index: /trunk/src/VBox/Main/ConsoleImpl2.cpp
===================================================================
--- /trunk/src/VBox/Main/ConsoleImpl2.cpp	(revision 10714)
+++ /trunk/src/VBox/Main/ConsoleImpl2.cpp	(revision 10715)
@@ -854,4 +854,13 @@
                 STR_FREE();
                 rc = CFGMR3InsertString(pCfg,   "Format",           "VMDK");                RC_CHECK();
+
+                /* 
+                 * Create cfgm nodes for async transport driver because VMDK is currently the only
+                 * one which may support async I/O. This has to be made generic based on the capabiliy flags
+                 * when the new HardDisk interface is merged.
+                 */
+                rc = CFGMR3InsertNode(pLunL1, "AttachedDriver", &pLunL2);                   RC_CHECK();
+                rc = CFGMR3InsertString(pLunL2, "Driver",      "TransportAsync");           RC_CHECK();
+                /* The async transport driver has no config options yet. */
             }
             else if (hddType == HardDiskStorageType_CustomHardDisk)
Index: /trunk/src/VBox/Main/HardDiskImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/HardDiskImpl.cpp	(revision 10714)
+++ /trunk/src/VBox/Main/HardDiskImpl.cpp	(revision 10715)
@@ -3403,6 +3403,14 @@
     mActualSize = 0;
 
+    /* Create supported error interface. */
+    mInterfaceErrorCallbacks.cbSize       = sizeof(VDINTERFACEERROR);
+    mInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
+    mInterfaceErrorCallbacks.pfnError     = VDError;
+    int vrc = VDInterfaceCreate(&mInterfaceError, "VMDK_IError", VDINTERFACETYPE_ERROR,
+                                &mInterfaceErrorCallbacks, this, NULL);
+    ComAssertRCRet (vrc, E_FAIL);
+
     /* initialize the container */
-    int vrc = VDCreate (VDError, this, &mContainer);
+    vrc = VDCreate (&mInterfaceError, &mContainer);
     ComAssertRCRet (vrc, E_FAIL);
 
@@ -4283,4 +4291,12 @@
     ComAssertRCRet (rc, E_FAIL);
 
+    /* Create supported error interface. */
+    mInterfaceErrorCallbacks.cbSize       = sizeof(VDINTERFACEERROR);
+    mInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
+    mInterfaceErrorCallbacks.pfnError     = VDError;
+    int vrc = VDInterfaceCreate(&mInterfaceError, "Custom_IError", VDINTERFACETYPE_ERROR,
+                                &mInterfaceErrorCallbacks, this, NULL);
+    ComAssertRCRet (vrc, E_FAIL);
+
     return S_OK;
 }
@@ -4344,5 +4360,5 @@
 
         /* initialize the container */
-        vrc = VDCreate (VDError, this, &mContainer);
+        vrc = VDCreate (&mInterfaceError, &mContainer);
         if (VBOX_FAILURE (vrc))
         {
@@ -4447,6 +4463,6 @@
             RTStrFree (pszFormat);
 
-            /* Create the corresponding container. */
-            vrc = VDCreate (VDError, this, &mContainer);
+            /* initialize the container */
+            vrc = VDCreate (&mInterfaceError, &mContainer);
 
             /* the format has been already checked for presence at this point */
@@ -5111,6 +5127,14 @@
     mActualSize = 0;
 
+    /* Create supported error interface. */
+    mInterfaceErrorCallbacks.cbSize       = sizeof(VDINTERFACEERROR);
+    mInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
+    mInterfaceErrorCallbacks.pfnError     = VDError;
+    int vrc = VDInterfaceCreate(&mInterfaceError, "VHD_IError", VDINTERFACETYPE_ERROR,
+                                &mInterfaceErrorCallbacks, this, NULL);
+    ComAssertRCRet (vrc, E_FAIL);
+
     /* initialize the container */
-    int vrc = VDCreate (VDError, this, &mContainer);
+    vrc = VDCreate (&mInterfaceError, &mContainer);
     ComAssertRCRet (vrc, E_FAIL);
 
Index: /trunk/src/VBox/Main/include/HardDiskImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/HardDiskImpl.h	(revision 10714)
+++ /trunk/src/VBox/Main/include/HardDiskImpl.h	(revision 10715)
@@ -539,4 +539,7 @@
     PVBOXHDD mContainer;
 
+    VDINTERFACE      mInterfaceError;
+    VDINTERFACEERROR mInterfaceErrorCallbacks;
+
     Utf8Str mLastVDError;
 
@@ -651,4 +654,7 @@
     PVBOXHDD mContainer;
 
+    VDINTERFACE      mInterfaceError;
+    VDINTERFACEERROR mInterfaceErrorCallbacks;
+
     Utf8Str mLastVDError;
 
@@ -764,4 +770,7 @@
     PVBOXHDD mContainer;
 
+    VDINTERFACE      mInterfaceError;
+    VDINTERFACEERROR mInterfaceErrorCallbacks;
+
     Utf8Str mLastVDError;
 
