Index: /trunk/src/VBox/Devices/Storage/UsbMsd.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/UsbMsd.cpp	(revision 64221)
+++ /trunk/src/VBox/Devices/Storage/UsbMsd.cpp	(revision 64222)
@@ -53,5 +53,7 @@
 
 /** Saved state version. */
-#define USB_MSD_SAVED_STATE_VERSION 1
+#define USB_MSD_SAVED_STATE_VERSION             2
+/** Saved state vesion before the cleanup. */
+#define USB_MSD_SAVED_STATE_VERSION_PRE_CLEANUP 1
 
 
@@ -145,4 +147,6 @@
     /** The state of the request. */
     USBMSDREQSTATE      enmState;
+    /** The I/O requesthandle .*/
+    PDMMEDIAEXIOREQ     hIoReq;
     /** The size of the data buffer. */
     uint32_t            cbBuf;
@@ -153,14 +157,6 @@
     /** The current Cbw when we're in the pending state. */
     USBCBW              Cbw;
-    /** The current SCSI request. */
-    PDMSCSIREQUEST      ScsiReq;
-    /** The scatter-gather segment used by ScsiReq for describing pbBuf. */
-    RTSGSEG             ScsiReqSeg;
-    /** The sense buffer for the current SCSI request. */
-    uint8_t             ScsiReqSense[64];
     /** The status of a completed SCSI request. */
-    int                 iScsiReqStatus;
-    /** Pointer to the USB device instance owning it. */
-    PPDMUSBINS          pUsbIns;
+    uint8_t             iScsiReqStatus;
 } USBMSDREQ;
 /** Pointer to a USB MSD request. */
@@ -208,8 +204,4 @@
      * (0 - default, 1 - the only, i.e configured.) */
     uint8_t             bConfigurationValue;
-#if 0
-    /** The state of the MSD (state machine).*/
-    USBMSDSTATE         enmState;
-#endif
     /** Endpoint 0 is the default control pipe, 1 is the host->dev bulk pipe and 2
      * is the dev->host one. */
@@ -255,11 +247,15 @@
         /** The base interface for LUN\#0. */
         PDMIBASE            IBase;
-        /** The SCSI port interface for LUN\#0  */
-        PDMISCSIPORT        IScsiPort;
+        /** The media port interface fo LUN\#0. */
+        PDMIMEDIAPORT       IMediaPort;
+        /** The extended media port interface for LUN\#0  */
+        PDMIMEDIAEXPORT     IMediaExPort;
 
         /** The base interface for the SCSI driver connected to LUN\#0. */
         PPDMIBASE           pIBase;
-        /** The SCSI connector interface for the SCSI driver connected to LUN\#0. */
-        PPDMISCSICONNECTOR  pIScsiConnector;
+        /** The media interface for th SCSI drver conected to LUN\#0. */
+        PPDMIMEDIA          pIMedia;
+        /** The extended media inerface for the SCSI driver connected to LUN\#0. */
+        PPDMIMEDIAEX        pIMediaEx;
     } Lun0;
 
@@ -818,17 +814,22 @@
  *
  * @returns Pointer to the new request.  NULL if we're out of memory.
- * @param   pUsbIns             The instance allocating it.
- */
-static PUSBMSDREQ usbMsdReqAlloc(PPDMUSBINS pUsbIns)
-{
-    PUSBMSDREQ pReq = (PUSBMSDREQ)PDMUsbHlpMMHeapAllocZ(pUsbIns, sizeof(*pReq));
-    if (pReq)
-    {
-        pReq->enmState          = USBMSDREQSTATE_READY;
-        pReq->iScsiReqStatus    = -1;
-        pReq->pUsbIns           = pUsbIns;
+ * @param   pThis               The MSD instance.
+ */
+static PUSBMSDREQ usbMsdReqAlloc(PUSBMSD pThis)
+{
+    PUSBMSDREQ pReq = NULL;
+    PDMMEDIAEXIOREQ hIoReq = NULL;
+
+    int rc = pThis->Lun0.pIMediaEx->pfnIoReqAlloc(pThis->Lun0.pIMediaEx, &hIoReq, (void **)&pReq,
+                                                  0 /* uTag */, PDMIMEDIAEX_F_DEFAULT);
+    if (RT_SUCCESS(rc))
+    {
+        pReq->hIoReq         = hIoReq;
+        pReq->enmState       = USBMSDREQSTATE_READY;
+        pReq->iScsiReqStatus = 0xff;
     }
     else
-        LogRel(("usbMsdReqAlloc: Out of memory\n"));
+        LogRel(("usbMsdReqAlloc: Out of memory (%Rrc)\n", rc));
+
     return pReq;
 }
@@ -838,7 +839,8 @@
  * Frees a request.
  *
+ * @param   pThis               The MSD instance.
  * @param   pReq                The request.
  */
-static void usbMsdReqFree(PUSBMSDREQ pReq)
+static void usbMsdReqFree(PUSBMSD pThis, PUSBMSDREQ pReq)
 {
     /*
@@ -848,5 +850,5 @@
                      &&  pReq->enmState != USBMSDREQSTATE_EXECUTING
                      &&  pReq->enmState < USBMSDREQSTATE_END);
-    PPDMUSBINS pUsbIns = pReq->pUsbIns;
+    PPDMUSBINS pUsbIns = pThis->pUsbIns;
     AssertPtrReturnVoid(pUsbIns);
     AssertReturnVoid(PDM_VERSION_ARE_COMPATIBLE(pUsbIns->u32Version, PDM_USBINS_VERSION));
@@ -855,13 +857,7 @@
      * Invalidate it and free the associated resources.
      */
-    pReq->enmState                      = USBMSDREQSTATE_INVALID;
-    pReq->cbBuf                         = 0;
-    pReq->offBuf                        = 0;
-    pReq->ScsiReq.pbCDB                 = NULL;
-    pReq->ScsiReq.paScatterGatherHead   = NULL;
-    pReq->ScsiReq.pbSenseBuffer         = NULL;
-    pReq->ScsiReq.pvUser                = NULL;
-    pReq->ScsiReqSeg.cbSeg              = 0;
-    pReq->ScsiReqSeg.pvSeg              = NULL;
+    pReq->enmState = USBMSDREQSTATE_INVALID;
+    pReq->cbBuf    = 0;
+    pReq->offBuf   = 0;
 
     if (pReq->pbBuf)
@@ -871,5 +867,6 @@
     }
 
-    PDMUsbHlpMMHeapFree(pUsbIns, pReq);
+    int rc = pThis->Lun0.pIMediaEx->pfnIoReqFree(pThis->Lun0.pIMediaEx, pReq->hIoReq);
+    AssertRC(rc);
 }
 
@@ -889,22 +886,6 @@
 
     /* Setup the SCSI request. */
-    pReq->ScsiReq.uLogicalUnit      = pReq->Cbw.bCBWLun;
-    pReq->ScsiReq.uDataDirection    = (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT
-                                    ? PDMSCSIREQUESTTXDIR_TO_DEVICE
-                                    : PDMSCSIREQUESTTXDIR_FROM_DEVICE;
-    pReq->ScsiReq.cbCDB             = pReq->Cbw.bCBWCBLength;
-
-    pReq->ScsiReq.pbCDB             = &pReq->Cbw.CBWCB[0];
-    pReq->offBuf                    = 0;
-    pReq->ScsiReqSeg.pvSeg          = pReq->pbBuf;
-    pReq->ScsiReqSeg.cbSeg          = pReq->Cbw.dCBWDataTransferLength;
-    pReq->ScsiReq.cbScatterGather   = pReq->Cbw.dCBWDataTransferLength;
-    pReq->ScsiReq.cScatterGatherEntries = 1;
-    pReq->ScsiReq.paScatterGatherHead = &pReq->ScsiReqSeg;
-    pReq->ScsiReq.cbSenseBuffer     = sizeof(pReq->ScsiReqSense);
-    pReq->ScsiReq.pbSenseBuffer     = &pReq->ScsiReqSense[0];
-    pReq->ScsiReq.pvUser            = NULL;
-    RT_ZERO(pReq->ScsiReqSense);
-    pReq->iScsiReqStatus            = -1;
+    pReq->offBuf         = 0;
+    pReq->iScsiReqStatus = 0xff;
 }
 
@@ -914,8 +895,9 @@
  *
  * @returns Success indicator (true/false)
- * @param   pReq
- * @param   cbBuf       The required buffer space.
- */
-static int usbMsdReqEnsureBuffer(PUSBMSDREQ pReq, uint32_t cbBuf)
+ * @param   pThis               The MSD instance.
+ * @param   pReq                The request.
+ * @param   cbBuf               The required buffer space.
+ */
+static int usbMsdReqEnsureBuffer(PUSBMSD pThis, PUSBMSDREQ pReq, uint32_t cbBuf)
 {
     if (RT_LIKELY(pReq->cbBuf >= cbBuf))
@@ -923,9 +905,9 @@
     else
     {
-        PDMUsbHlpMMHeapFree(pReq->pUsbIns, pReq->pbBuf);
+        PDMUsbHlpMMHeapFree(pThis->pUsbIns, pReq->pbBuf);
         pReq->cbBuf = 0;
 
         cbBuf = RT_ALIGN_Z(cbBuf, 0x1000);
-        pReq->pbBuf = (uint8_t *)PDMUsbHlpMMHeapAllocZ(pReq->pUsbIns, cbBuf);
+        pReq->pbBuf = (uint8_t *)PDMUsbHlpMMHeapAllocZ(pThis->pUsbIns, cbBuf);
         if (!pReq->pbBuf)
             return false;
@@ -1015,5 +997,5 @@
 
         /* Device reset: Wait for up to 10 ms.  If it doesn't work, ditch
-           whoe the request structure.  We'll allocate a new one when needed. */
+           whole the request structure.  We'll allocate a new one when needed. */
         Log(("usbMsdResetWorker: Waiting for completion...\n"));
         Assert(!pThis->fSignalResetSem);
@@ -1043,5 +1025,5 @@
     {
         pReq->enmState       = USBMSDREQSTATE_READY;
-        pReq->iScsiReqStatus = -1;
+        pReq->iScsiReqStatus = 0xff;
     }
 
@@ -1077,14 +1059,16 @@
 
 /**
- * @interface_method_impl{PDMISCSIPORT,pfnSCSIRequestCompleted}
- */
-static DECLCALLBACK(int) usbMsdLun0ScsiRequestCompleted(PPDMISCSIPORT pInterface, PPDMSCSIREQUEST pSCSIRequest,
-                                                        int rcCompletion, bool fRedo, int rcReq)
-{
-    RT_NOREF(fRedo, rcReq);
-    PUSBMSD     pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IScsiPort);
-    PUSBMSDREQ  pReq  = RT_FROM_MEMBER(pSCSIRequest, USBMSDREQ, ScsiReq);
-
-    Log(("usbMsdLun0ScsiRequestCompleted: pReq=%p dCBWTag=%#x iScsiReqStatus=%u \n", pReq, pReq->Cbw.dCBWTag, rcCompletion));
+ * Process a completed request.
+ *
+ * @returns nothing.
+ * @param   pThis               The MSD instance.
+ * @param   pReq                The request.
+ * @param   rcReq               The completion status.
+ */
+static void usbMsdReqComplete(PUSBMSD pThis, PUSBMSDREQ pReq, int rcReq)
+{
+    RT_NOREF1(rcReq);
+
+    Log(("usbMsdLun0IoReqCompleteNotify: pReq=%p dCBWTag=%#x iScsiReqStatus=%u \n", pReq, pReq->Cbw.dCBWTag, pReq->iScsiReqStatus));
     RTCritSectEnter(&pThis->CritSect);
 
@@ -1093,5 +1077,4 @@
         Assert(pReq->enmState == USBMSDREQSTATE_EXECUTING);
         Assert(pThis->pReq == pReq);
-        pReq->iScsiReqStatus = rcCompletion;
 
         /*
@@ -1102,10 +1085,10 @@
         {
             pReq->enmState = USBMSDREQSTATE_STATUS;
-            Log(("usbMsdLun0ScsiRequestCompleted: Entering STATUS\n"));
+            Log(("usbMsdLun0IoReqCompleteNotify: Entering STATUS\n"));
         }
         else
         {
             pReq->enmState = USBMSDREQSTATE_DATA_TO_HOST;
-            Log(("usbMsdLun0ScsiRequestCompleted: Entering DATA_TO_HOST\n"));
+            Log(("usbMsdLun0IoReqCompleteNotify: Entering DATA_TO_HOST\n"));
         }
 
@@ -1125,6 +1108,6 @@
     else
     {
-        Log(("usbMsdLun0ScsiRequestCompleted: freeing %p\n", pReq));
-        usbMsdReqFree(pReq);
+        Log(("usbMsdLun0IoReqCompleteNotify: freeing %p\n", pReq));
+        usbMsdReqFree(pThis, pReq);
     }
 
@@ -1139,4 +1122,64 @@
 
     RTCritSectLeave(&pThis->CritSect);
+}
+
+
+/**
+ * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyFromBuf}
+ */
+static DECLCALLBACK(int) usbMsdLun0IoReqCopyFromBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
+                                                    void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf,
+                                                    size_t cbCopy)
+{
+    RT_NOREF2(pInterface, hIoReq);
+    int rc = VINF_SUCCESS;
+    PUSBMSDREQ pReq = (PUSBMSDREQ)pvIoReqAlloc;
+
+    if (RT_UNLIKELY(offDst + cbCopy > pReq->cbBuf))
+        rc = VERR_PDM_MEDIAEX_IOBUF_OVERFLOW;
+    else
+    {
+        size_t cbCopied = RTSgBufCopyToBuf(pSgBuf, pReq->pbBuf + offDst, cbCopy);
+        Assert(cbCopied == cbCopy);
+    }
+
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCopyToBuf}
+ */
+static DECLCALLBACK(int) usbMsdLun0IoReqCopyToBuf(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
+                                                  void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf,
+                                                  size_t cbCopy)
+{
+    RT_NOREF2(pInterface, hIoReq);
+    int rc = VINF_SUCCESS;
+    PUSBMSDREQ pReq = (PUSBMSDREQ)pvIoReqAlloc;
+
+    if (RT_UNLIKELY(offSrc + cbCopy > pReq->cbBuf))
+        rc = VERR_PDM_MEDIAEX_IOBUF_UNDERRUN;
+    else
+    {
+        size_t cbCopied = RTSgBufCopyFromBuf(pSgBuf, pReq->pbBuf + offSrc, cbCopy);
+        Assert(cbCopied == cbCopy);
+    }
+
+    return rc;
+}
+
+
+/**
+ * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqCompleteNotify}
+ */
+static DECLCALLBACK(int) usbMsdLun0IoReqCompleteNotify(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
+                                                       void *pvIoReqAlloc, int rcReq)
+{
+    RT_NOREF1(hIoReq);
+    PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IMediaExPort);
+    PUSBMSDREQ pReq = (PUSBMSDREQ)pvIoReqAlloc;
+
+    usbMsdReqComplete(pThis, pReq, rcReq);
     return VINF_SUCCESS;
 }
@@ -1144,10 +1187,30 @@
 
 /**
+ * @interface_method_impl{PDMIMEDIAEXPORT,pfnIoReqStateChanged}
+ */
+static DECLCALLBACK(void) usbMsdLun0IoReqStateChanged(PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq,
+                                                      void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)
+{
+    RT_NOREF4(pInterface, hIoReq, pvIoReqAlloc, enmState);
+    AssertLogRelMsgFailed(("This should not be hit because I/O requests should not be suspended\n"));
+}
+
+
+/**
+ * @interface_method_impl{PDMIMEDIAEXPORT,pfnMediumEjected}
+ */
+static DECLCALLBACK(void) usbMsdLun0MediumEjected(PPDMIMEDIAEXPORT pInterface)
+{
+    RT_NOREF1(pInterface); /** @todo */
+}
+
+
+/**
  * @interface_method_impl{PDMISCSIPORT,pfnQueryDeviceLocation}
  */
-static DECLCALLBACK(int) usbMsdLun0QueryDeviceLocation(PPDMISCSIPORT pInterface, const char **ppcszController,
+static DECLCALLBACK(int) usbMsdLun0QueryDeviceLocation(PPDMIMEDIAPORT pInterface, const char **ppcszController,
                                                        uint32_t *piInstance, uint32_t *piLUN)
 {
-    PUSBMSD    pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IScsiPort);
+    PUSBMSD    pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IMediaPort);
     PPDMUSBINS pUsbIns = pThis->pUsbIns;
 
@@ -1171,5 +1234,6 @@
     PUSBMSD pThis = RT_FROM_MEMBER(pInterface, USBMSD, Lun0.IBase);
     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->Lun0.IBase);
-    PDMIBASE_RETURN_INTERFACE(pszIID, PDMISCSIPORT, &pThis->Lun0.IScsiPort);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAPORT, &pThis->Lun0.IMediaPort);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIAEXPORT, &pThis->Lun0.IMediaExPort);
     return NULL;
 }
@@ -1220,5 +1284,13 @@
         PDMUsbHlpSetAsyncNotification(pUsbIns, usbMsdIsAsyncSuspendOrPowerOffDone);
     else
+    {
         ASMAtomicWriteBool(&pThis->fSignalIdle, false);
+
+        if (pThis->pReq)
+        {
+            usbMsdReqFree(pThis, pThis->pReq);
+            pThis->pReq = NULL;
+        }
+    }
 }
 
@@ -1305,10 +1377,5 @@
         SSMR3PutU32(pSSM, pReq->offBuf);
         SSMR3PutMem(pSSM, &pReq->Cbw, sizeof(pReq->Cbw));
-        SSMR3PutU32(pSSM, pReq->ScsiReq.uLogicalUnit);
-        SSMR3PutU32(pSSM, pReq->ScsiReq.uDataDirection);
-        SSMR3PutU32(pSSM, pReq->ScsiReq.cbCDB);
-        SSMR3PutU32(pSSM, pReq->ScsiReq.cbScatterGather);
-        SSMR3PutMem(pSSM, &pReq->ScsiReqSense[0], sizeof(pReq->ScsiReqSense));
-        SSMR3PutS32(pSSM, pReq->iScsiReqStatus);
+        SSMR3PutU8(pSSM, pReq->iScsiReqStatus);
     }
 
@@ -1351,5 +1418,5 @@
         if (fReqAlloc)
         {
-            PUSBMSDREQ pReq = usbMsdReqAlloc(pUsbIns);
+            PUSBMSDREQ pReq = usbMsdReqAlloc(pThis);
             AssertReturn(pReq, VERR_NO_MEMORY);
             pThis->pReq = pReq;
@@ -1361,5 +1428,5 @@
             if (cbBuf)
             {
-                if (usbMsdReqEnsureBuffer(pReq, cbBuf))
+                if (usbMsdReqEnsureBuffer(pThis, pReq, cbBuf))
                 {
                     AssertPtr(pReq->pbBuf);
@@ -1373,22 +1440,17 @@
             SSMR3GetU32(pSSM, &pReq->offBuf);
             SSMR3GetMem(pSSM, &pReq->Cbw, sizeof(pReq->Cbw));
-            SSMR3GetU32(pSSM, &pReq->ScsiReq.uLogicalUnit);
-            SSMR3GetU32(pSSM, (uint32_t *)&pReq->ScsiReq.uDataDirection);
-            SSMR3GetU32(pSSM, &pReq->ScsiReq.cbCDB);
-            SSMR3GetU32(pSSM, &pReq->ScsiReq.cbScatterGather);
-            SSMR3GetMem(pSSM, &pReq->ScsiReqSense[0], sizeof(pReq->ScsiReqSense));
-            rc = SSMR3GetS32(pSSM, &pReq->iScsiReqStatus);
+
+            if (uVersion >= USB_MSD_SAVED_STATE_VERSION_PRE_CLEANUP)
+                rc = SSMR3GetU8(pSSM, &pReq->iScsiReqStatus);
+            else
+            {
+                int32_t iScsiReqStatus;
+
+                /* Skip old fields which are unused now or can be determined from the CBW. */
+                SSMR3Skip(pSSM, 4 * 4 + 64);
+                rc = SSMR3GetS32(pSSM, &iScsiReqStatus);
+                pReq->iScsiReqStatus = (uint8_t)iScsiReqStatus;
+            }
             AssertRCReturn(rc, rc);
-
-            /* Setup the rest of the SCSI request. */
-            pReq->ScsiReq.cbCDB             = pReq->Cbw.bCBWCBLength;
-            pReq->ScsiReq.pbCDB             = &pReq->Cbw.CBWCB[0];
-            pReq->ScsiReqSeg.pvSeg          = pReq->pbBuf;
-            pReq->ScsiReqSeg.cbSeg          = pReq->ScsiReq.cbScatterGather;
-            pReq->ScsiReq.cScatterGatherEntries = 1;
-            pReq->ScsiReq.paScatterGatherHead = &pReq->ScsiReqSeg;
-            pReq->ScsiReq.cbSenseBuffer     = sizeof(pReq->ScsiReqSense);
-            pReq->ScsiReq.pbSenseBuffer     = &pReq->ScsiReqSense[0];
-            pReq->ScsiReq.pvUser            = NULL;
         }
 
@@ -1463,83 +1525,4 @@
 
     RTCritSectLeave(&pThis->CritSect);
-    return VINF_SUCCESS;
-}
-
-
-/**
- * Fails an illegal SCSI request.
- *
- * @returns VBox status code.
- * @param   pThis               The MSD instance data.
- * @param   pReq                The MSD request.
- * @param   bAsc                The ASC for the SCSI_SENSE_ILLEGAL_REQUEST.
- * @param   bAscq               The ASC qualifier.
- * @param   pszWhy              For logging why.
- */
-static int usbMsdScsiIllegalRequest(PUSBMSD pThis, PUSBMSDREQ pReq, uint8_t bAsc, uint8_t bAscq, const char *pszWhy)
-{
-    RT_NOREF(bAsc, bAscq, pszWhy);
-    Log(("usbMsdScsiIllegalRequest: bAsc=%#x bAscq=%#x %s\n", bAsc, bAscq, pszWhy));
-
-    RT_ZERO(pReq->ScsiReqSense);
-    pReq->ScsiReqSense[0]  = 0x80 | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
-    pReq->ScsiReqSense[2]  = SCSI_SENSE_ILLEGAL_REQUEST;
-    pReq->ScsiReqSense[7]  = 10;
-    pReq->ScsiReqSense[12] = SCSI_ASC_INVALID_MESSAGE;
-    pReq->ScsiReqSense[13] = 0; /* Should be ASCQ but it has the same value for success. */
-
-    usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_CHECK_CONDITION, false, VINF_SUCCESS);
-    return VINF_SUCCESS;
-}
-
-
-/**
- * The SCSI driver doesn't handle SCSI_REQUEST_SENSE but instead
- * returns the sense info with the request.
- *
- */
-static int usbMsdHandleScsiReqestSense(PUSBMSD pThis, PUSBMSDREQ pReq, PCUSBCBW pCbw)
-{
-    Log(("usbMsdHandleScsiReqestSense: Entering EXECUTING (dCBWTag=%#x).\n", pReq->Cbw.dCBWTag));
-    Assert(pReq == pThis->pReq);
-    pReq->enmState = USBMSDREQSTATE_EXECUTING;
-
-    /* validation */
-    if ((pCbw->bmCBWFlags & USBCBW_DIR_MASK) != USBCBW_DIR_IN)
-        return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "direction");
-    if (pCbw->bCBWCBLength < 6)
-        return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "length");
-    if ((pCbw->CBWCB[1] >> 5) != pCbw->bCBWLun)
-        return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0, "lun");
-    if (pCbw->bCBWLun != 0)
-        return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INVALID_MESSAGE, 0, "lun0");
-    if (pCbw->CBWCB[4] < 6)
-        return usbMsdScsiIllegalRequest(pThis, pReq, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0, "out length");
-
-    /* If the previous command succeeded successfully, whip up some sense data. */
-    if (   pReq->iScsiReqStatus == SCSI_STATUS_OK
-        && pReq->ScsiReqSense[0] == 0)
-    {
-        RT_ZERO(pReq->ScsiReqSense);
-#if 0  /** @todo something upsets linux about this stuff. Needs investigation. */
-        pReq->ScsiReqSense[0]  = 0x80 | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
-        pReq->ScsiReqSense[0]  = SCSI_SENSE_RESPONSE_CODE_CURR_FIXED;
-        pReq->ScsiReqSense[2]  = SCSI_SENSE_NONE;
-        pReq->ScsiReqSense[7]  = 10;
-        pReq->ScsiReqSense[12] = SCSI_ASC_NONE;
-        pReq->ScsiReqSense[13] = SCSI_ASC_NONE; /* Should be ASCQ but it has the same value for success. */
-#endif
-    }
-
-    /* Copy the data into the result buffer. */
-    size_t cbCopy = RT_MIN(pCbw->dCBWDataTransferLength, sizeof(pReq->ScsiReqSense));
-    Log(("usbMsd: SCSI_REQUEST_SENSE - CBWCB[4]=%#x iOldState=%d, %u bytes, raw: %.*Rhxs\n",
-         pCbw->CBWCB[4], pReq->iScsiReqStatus, pCbw->dCBWDataTransferLength, RT_MAX(1, cbCopy), pReq->ScsiReqSense));
-    memcpy(pReq->pbBuf, &pReq->ScsiReqSense[0], cbCopy);
-
-    usbMsdReqPrepare(pReq, pCbw);
-
-    /* Do normal completion.  */
-    usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_OK, false, VINF_SUCCESS);
     return VINF_SUCCESS;
 }
@@ -1562,35 +1545,14 @@
     pReq->enmState = USBMSDREQSTATE_EXECUTING;
 
-    switch (pReq->ScsiReq.pbCDB[0])
-    {
-        case SCSI_REQUEST_SENSE:
-        {
-        }
-
-        default:
-            return pThis->Lun0.pIScsiConnector->pfnSCSIRequestSend(pThis->Lun0.pIScsiConnector, &pReq->ScsiReq);
-    }
-}
-
-/**
- * Validates a SCSI request before passing it down to the SCSI driver.
- *
- * @returns true / false.  The request will be completed on failure.
- * @param   pThis               The MSD instance data.
- * @param   pCbw                The USB command block wrapper.
- * @param   pUrb                The URB.
- */
-static bool usbMsdIsValidCommand(PUSBMSD pThis, PCUSBCBW pCbw, PVUSBURB pUrb)
-{
-    RT_NOREF(pThis, pUrb);
-    switch (pCbw->CBWCB[0])
-    {
-        case SCSI_REQUEST_SENSE:
-            /** @todo validate this. */
-            return true;
-
-        default:
-            return true;
-    }
+    PDMMEDIAEXIOREQSCSITXDIR enmTxDir = pReq->Cbw.dCBWDataTransferLength == 0
+                                      ? PDMMEDIAEXIOREQSCSITXDIR_NONE
+                                      :   (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT
+                                        ? PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE
+                                        : PDMMEDIAEXIOREQSCSITXDIR_FROM_DEVICE;
+
+    return pThis->Lun0.pIMediaEx->pfnIoReqSendScsiCmd(pThis->Lun0.pIMediaEx, pReq->hIoReq, pReq->Cbw.bCBWLun,
+                                                      &pReq->Cbw.CBWCB[0], pReq->Cbw.bCBWCBLength, enmTxDir,
+                                                      pReq->Cbw.dCBWDataTransferLength, NULL, 0,
+                                                      &pReq->iScsiReqStatus, 20 * RT_MS_1SEC);
 }
 
@@ -1667,7 +1629,4 @@
             }
 
-            if (!usbMsdIsValidCommand(pThis, pCbw, pUrb))
-                return VINF_SUCCESS;
-
             /*
              * Make sure we've got a request and a sufficient buffer space.
@@ -1679,40 +1638,33 @@
             if (!pReq)
             {
-                pReq = usbMsdReqAlloc(pThis->pUsbIns);
+                pReq = usbMsdReqAlloc(pThis);
                 if (!pReq)
                     return usbMsdCompleteStall(pThis, NULL, pUrb, "Request allocation failure");
                 pThis->pReq = pReq;
             }
-            if (!usbMsdReqEnsureBuffer(pReq, pCbw->dCBWDataTransferLength))
+            if (!usbMsdReqEnsureBuffer(pThis, pReq, pCbw->dCBWDataTransferLength))
                 return usbMsdCompleteStall(pThis, NULL, pUrb, "Buffer allocation failure");
 
             /*
-             * Special case REQUEST SENSE requests, usbMsdReqPrepare will
-             * trash the sense data otherwise.
+             * Prepare the request.  Kick it off right away if possible.
              */
-            if (pCbw->CBWCB[0] == SCSI_REQUEST_SENSE)
-                usbMsdHandleScsiReqestSense(pThis, pReq, pCbw);
+            usbMsdReqPrepare(pReq, pCbw);
+
+            if (   pReq->Cbw.dCBWDataTransferLength == 0
+                || (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_IN)
+            {
+                int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkHostToDev");
+                if (RT_SUCCESS(rc) && rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
+                    usbMsdReqComplete(pThis, pReq, rc);
+                else if (RT_FAILURE(rc))
+                {
+                    Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
+                    return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #1");
+                }
+            }
             else
             {
-                /*
-                 * Prepare the request.  Kick it off right away if possible.
-                 */
-                usbMsdReqPrepare(pReq, pCbw);
-
-                if (   pReq->Cbw.dCBWDataTransferLength == 0
-                    || (pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_IN)
-                {
-                    int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkHostToDev");
-                    if (RT_FAILURE(rc))
-                    {
-                        Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
-                        return usbMsdCompleteStall(pThis, NULL, pUrb, "SCSI Submit #1");
-                    }
-                }
-                else
-                {
-                    Log(("usbMsdHandleBulkHostToDev: Entering DATA_FROM_HOST.\n"));
-                    pReq->enmState = USBMSDREQSTATE_DATA_FROM_HOST;
-                }
+                Log(("usbMsdHandleBulkHostToDev: Entering DATA_FROM_HOST.\n"));
+                pReq->enmState = USBMSDREQSTATE_DATA_FROM_HOST;
             }
 
@@ -1739,5 +1691,7 @@
             {
                 int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkHostToDev");
-                if (RT_FAILURE(rc))
+                if (RT_SUCCESS(rc) && rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
+                    usbMsdReqComplete(pThis, pReq, rc);
+                else if (RT_FAILURE(rc))
                 {
                     Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
@@ -1825,5 +1779,5 @@
             pCsw->bCSWStatus    = pReq->iScsiReqStatus == SCSI_STATUS_OK
                                 ? USBCSW_STATUS_OK
-                                : pReq->iScsiReqStatus >= 0
+                                : pReq->iScsiReqStatus < 0xff
                                 ? USBCSW_STATUS_FAILED
                                 : USBCSW_STATUS_PHASE_ERROR;
@@ -1832,10 +1786,10 @@
             if ((pReq->Cbw.bmCBWFlags & USBCBW_DIR_MASK) == USBCBW_DIR_OUT)
                 pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
-                                      ? pReq->Cbw.dCBWDataTransferLength - pReq->ScsiReq.cbScatterGather
+                                      ? 0
                                       : pReq->Cbw.dCBWDataTransferLength;
             else
                 pCsw->dCSWDataResidue = pCsw->bCSWStatus == USBCSW_STATUS_OK
                                       ? 0
-                                      : pReq->ScsiReq.cbScatterGather;
+                                      : pReq->Cbw.dCBWDataTransferLength;
             Log(("usbMsd: CSW: dCSWTag=%#x bCSWStatus=%d dCSWDataResidue=%#x\n",
                  pCsw->dCSWTag, pCsw->bCSWStatus, pCsw->dCSWDataResidue));
@@ -1860,22 +1814,8 @@
             }
 
-            /* Adjust the request and kick it off.  Special case the no-data
-               case since the SCSI driver doesn't like that. */
-            pReq->ScsiReq.cbScatterGather = pReq->offBuf;
-            pReq->ScsiReqSeg.cbSeg        = pReq->offBuf;
-            if (!pReq->offBuf)
-            {
-                Log(("usbMsdHandleBulkDevToHost: Entering EXECUTING (offBuf=0x0).\n"));
-                pReq->enmState = USBMSDREQSTATE_EXECUTING;
-
-                usbMsdQueueAddTail(&pThis->ToHostQueue, pUrb);
-                LogFlow(("usbMsdHandleBulkDevToHost: Added %p:%s to the to-host queue\n", pUrb, pUrb->pszDesc));
-
-                usbMsdLun0ScsiRequestCompleted(&pThis->Lun0.IScsiPort, &pReq->ScsiReq, SCSI_STATUS_OK, false, VINF_SUCCESS);
-                return VINF_SUCCESS;
-            }
-
             int rc = usbMsdSubmitScsiCommand(pThis, pReq, "usbMsdHandleBulkDevToHost");
-            if (RT_FAILURE(rc))
+            if (RT_SUCCESS(rc) && rc != VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS)
+                usbMsdReqComplete(pThis, pReq, rc);
+            else if (RT_FAILURE(rc))
             {
                 Log(("usbMsd: Failed sending SCSI request to driver: %Rrc\n", rc));
@@ -2154,5 +2094,5 @@
     PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
 
-    LogFlow(("usbMsdDetach/#%u:\n", pUsbIns->iInstance));
+    LogFlow(("usbMsdDriverAttach/#%u:\n", pUsbIns->iInstance));
 
     AssertMsg(iLUN == 0, ("UsbMsd: No other LUN than 0 is supported\n"));
@@ -2162,5 +2102,6 @@
     /* the usual paranoia */
     AssertRelease(!pThis->Lun0.pIBase);
-    AssertRelease(!pThis->Lun0.pIScsiConnector);
+    AssertRelease(!pThis->Lun0.pIMedia);
+    AssertRelease(!pThis->Lun0.pIMediaEx);
 
     /*
@@ -2171,7 +2112,12 @@
     if (RT_SUCCESS(rc))
     {
-        /* Get SCSI connector interface. */
-        pThis->Lun0.pIScsiConnector = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMISCSICONNECTOR);
-        AssertMsgReturn(pThis->Lun0.pIScsiConnector, ("Missing SCSI interface below\n"), VERR_PDM_MISSING_INTERFACE);
+        /* Get media and extended media interface. */
+        pThis->Lun0.pIMedia = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMIMEDIA);
+        AssertMsgReturn(pThis->Lun0.pIMedia, ("Missing media interface below\n"), VERR_PDM_MISSING_INTERFACE);
+        pThis->Lun0.pIMediaEx = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMIMEDIAEX);
+        AssertMsgReturn(pThis->Lun0.pIMediaEx, ("Missing extended media interface below\n"), VERR_PDM_MISSING_INTERFACE);
+
+        rc = pThis->Lun0.pIMediaEx->pfnIoReqAllocSizeSet(pThis->Lun0.pIMediaEx, sizeof(USBMSDREQ));
+        AssertMsgRCReturn(rc, ("MSD failed to set I/O request size!\n"), VERR_PDM_MISSING_INTERFACE);
     }
     else
@@ -2181,19 +2127,13 @@
     {
         pThis->Lun0.pIBase = NULL;
-        pThis->Lun0.pIScsiConnector = NULL;
-    }
-
-    /*
-     * Find out what kind of device we are.
-     */
-    PDMSCSILUNTYPE enmLunType;
+        pThis->Lun0.pIMedia = NULL;
+        pThis->Lun0.pIMediaEx = NULL;
+    }
+
     pThis->fIsCdrom = false;
-    rc = pThis->Lun0.pIScsiConnector->pfnQueryLUNType(pThis->Lun0.pIScsiConnector, 0 /*iLun*/, &enmLunType);
-    if (RT_SUCCESS(rc))
-    {
-        /* Anything else will be reported as a hard disk. */
-        if (enmLunType == PDMSCSILUNTYPE_MMC)
-            pThis->fIsCdrom = true;
-    }
+    PDMMEDIATYPE enmType = pThis->Lun0.pIMedia->pfnGetType(pThis->Lun0.pIMedia);
+    /* Anything else will be reported as a hard disk. */
+    if (enmType == PDMMEDIATYPE_CDROM || enmType == PDMMEDIATYPE_DVD)
+        pThis->fIsCdrom = true;
 
     return rc;
@@ -2209,9 +2149,15 @@
     PUSBMSD pThis = PDMINS_2_DATA(pUsbIns, PUSBMSD);
 
-    LogFlow(("usbMsdDetach/#%u:\n", pUsbIns->iInstance));
+    LogFlow(("usbMsdDriverDetach/#%u:\n", pUsbIns->iInstance));
 
     AssertMsg(iLUN == 0, ("UsbMsd: No other LUN than 0 is supported\n"));
     AssertMsg(fFlags & PDM_TACH_FLAGS_NOT_HOT_PLUG,
               ("UsbMsd: Device does not support hotplugging\n"));
+
+    if (pThis->pReq)
+    {
+        usbMsdReqFree(pThis, pThis->pReq);
+        pThis->pReq = NULL;
+    }
 
     /*
@@ -2219,5 +2165,6 @@
      */
     pThis->Lun0.pIBase = NULL;
-    pThis->Lun0.pIScsiConnector = NULL;
+    pThis->Lun0.pIMedia = NULL;
+    pThis->Lun0.pIMediaEx = NULL;
 }
 
@@ -2275,10 +2222,4 @@
     }
 
-    if (pThis->pReq)
-    {
-        usbMsdReqFree(pThis->pReq);
-        pThis->pReq = NULL;
-    }
-
     if (pThis->hEvtDoneQueue != NIL_RTSEMEVENT)
     {
@@ -2309,10 +2250,15 @@
      * will not misbehave.
      */
-    pThis->pUsbIns                                  = pUsbIns;
-    pThis->hEvtDoneQueue                            = NIL_RTSEMEVENT;
-    pThis->hEvtReset                                = NIL_RTSEMEVENTMULTI;
-    pThis->Lun0.IBase.pfnQueryInterface             = usbMsdLun0QueryInterface;
-    pThis->Lun0.IScsiPort.pfnSCSIRequestCompleted   = usbMsdLun0ScsiRequestCompleted;
-    pThis->Lun0.IScsiPort.pfnQueryDeviceLocation    = usbMsdLun0QueryDeviceLocation;
+    pThis->pUsbIns                                      = pUsbIns;
+    pThis->hEvtDoneQueue                                = NIL_RTSEMEVENT;
+    pThis->hEvtReset                                    = NIL_RTSEMEVENTMULTI;
+    pThis->Lun0.IBase.pfnQueryInterface                 = usbMsdLun0QueryInterface;
+    pThis->Lun0.IMediaPort.pfnQueryDeviceLocation       = usbMsdLun0QueryDeviceLocation;
+    pThis->Lun0.IMediaExPort.pfnIoReqCompleteNotify     = usbMsdLun0IoReqCompleteNotify;
+    pThis->Lun0.IMediaExPort.pfnIoReqCopyFromBuf        = usbMsdLun0IoReqCopyFromBuf;
+    pThis->Lun0.IMediaExPort.pfnIoReqCopyToBuf          = usbMsdLun0IoReqCopyToBuf;
+    pThis->Lun0.IMediaExPort.pfnIoReqQueryDiscardRanges = NULL;
+    pThis->Lun0.IMediaExPort.pfnIoReqStateChanged       = usbMsdLun0IoReqStateChanged;
+    pThis->Lun0.IMediaExPort.pfnMediumEjected           = usbMsdLun0MediumEjected;
     usbMsdQueueInit(&pThis->ToHostQueue);
     usbMsdQueueInit(&pThis->DoneQueue);
@@ -2340,21 +2286,25 @@
     if (RT_FAILURE(rc))
         return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("MSD failed to attach SCSI driver"));
-    pThis->Lun0.pIScsiConnector = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMISCSICONNECTOR);
-    if (!pThis->Lun0.pIScsiConnector)
+    pThis->Lun0.pIMedia = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMIMEDIA);
+    if (!pThis->Lun0.pIMedia)
         return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS,
-                                   N_("MSD failed to query the PDMISCSICONNECTOR from the driver below it"));
+                                   N_("MSD failed to query the PDMIMEDIA from the driver below it"));
+    pThis->Lun0.pIMediaEx = PDMIBASE_QUERY_INTERFACE(pThis->Lun0.pIBase, PDMIMEDIAEX);
+    if (!pThis->Lun0.pIMediaEx)
+        return PDMUsbHlpVMSetError(pUsbIns, VERR_PDM_MISSING_INTERFACE_BELOW, RT_SRC_POS,
+                                   N_("MSD failed to query the PDMIMEDIAEX from the driver below it"));
 
     /*
      * Find out what kind of device we are.
      */
-    PDMSCSILUNTYPE enmLunType;
     pThis->fIsCdrom = false;
-    rc = pThis->Lun0.pIScsiConnector->pfnQueryLUNType(pThis->Lun0.pIScsiConnector, 0 /*iLun*/, &enmLunType);
-    if (RT_SUCCESS(rc))
-    {
-        /* Anything else will be reported as a hard disk. */
-        if (enmLunType == PDMSCSILUNTYPE_MMC)
-            pThis->fIsCdrom = true;
-    }
+    PDMMEDIATYPE enmType = pThis->Lun0.pIMedia->pfnGetType(pThis->Lun0.pIMedia);
+    /* Anything else will be reported as a hard disk. */
+    if (enmType == PDMMEDIATYPE_CDROM || enmType == PDMMEDIATYPE_DVD)
+        pThis->fIsCdrom = true;
+
+    rc = pThis->Lun0.pIMediaEx->pfnIoReqAllocSizeSet(pThis->Lun0.pIMediaEx, sizeof(USBMSDREQ));
+    if (RT_FAILURE(rc))
+        return PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, N_("MSD failed to set I/O request size!"));
 
     /*
