Index: /trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp	(revision 65964)
+++ /trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp	(revision 65965)
@@ -93,4 +93,18 @@
 
 
+/**
+ * Parse the CDB and check whether it can be passed through safely.
+ *
+ * @returns Flag whether to passthrough to the device is considered safe.
+ * @param   pThis         The host DVD driver instance.
+ * @param   pReq          The request.
+ * @param   pbCdb         The CDB to parse.
+ * @param   cbCdb         Size of the CDB in bytes.
+ * @param   cbBuf         Size of the guest buffer.
+ * @param   penmTxDir     Where to store the transfer direction (guest to host or vice versa).
+ * @param   pcbXfer       Where to store the transfer size encoded in the CDB.
+ * @param   pcbSector     Where to store the sector size used for the transfer.
+ * @param   pu8ScsiSts    Where to store the SCSI status code.
+ */
 static bool drvHostDvdParseCdb(PDRVHOSTDVD pThis, PDRVHOSTBASEREQ pReq,
                                const uint8_t *pbCdb, size_t cbCdb, size_t cbBuf,
@@ -98,323 +112,29 @@
                                size_t *pcbSector, uint8_t *pu8ScsiSts)
 {
-    uint32_t uLba = 0;
-    uint32_t cSectors = 0;
-    size_t cbSector = 0;
-    size_t cbXfer = 0;
     bool fPassthrough = false;
-    PDMMEDIATXDIR enmTxDir = PDMMEDIATXDIR_NONE;
-
-    RT_NOREF(cbCdb);
-
-    switch (pbCdb[0])
+
+    if (   pbCdb[0] == SCSI_REQUEST_SENSE
+        && (pThis->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE)
     {
-        /* First the commands we can pass through without further processing. */
-        case SCSI_BLANK:
-        case SCSI_CLOSE_TRACK_SESSION:
-        case SCSI_LOAD_UNLOAD_MEDIUM:
-        case SCSI_PAUSE_RESUME:
-        case SCSI_PLAY_AUDIO_10:
-        case SCSI_PLAY_AUDIO_12:
-        case SCSI_PLAY_AUDIO_MSF:
-        case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
-        case SCSI_REPAIR_TRACK:
-        case SCSI_RESERVE_TRACK:
-        case SCSI_SCAN:
-        case SCSI_SEEK_10:
-        case SCSI_SET_CD_SPEED:
-        case SCSI_SET_READ_AHEAD:
-        case SCSI_START_STOP_UNIT:
-        case SCSI_STOP_PLAY_SCAN:
-        case SCSI_SYNCHRONIZE_CACHE:
-        case SCSI_TEST_UNIT_READY:
-        case SCSI_VERIFY_10:
-            fPassthrough = true;
-            break;
-        case SCSI_ERASE_10:
-            uLba = scsiBE2H_U32(pbCdb + 2);
-            cbXfer = scsiBE2H_U16(pbCdb + 7);
-            enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_FORMAT_UNIT:
-            cbXfer = cbBuf;
-            enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_GET_CONFIGURATION:
-            cbXfer = scsiBE2H_U16(pbCdb + 7);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_GET_EVENT_STATUS_NOTIFICATION:
-            cbXfer = scsiBE2H_U16(pbCdb + 7);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_GET_PERFORMANCE:
-            cbXfer = cbBuf;
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_INQUIRY:
-            cbXfer = scsiBE2H_U16(pbCdb + 3);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_MECHANISM_STATUS:
-            cbXfer = scsiBE2H_U16(pbCdb + 8);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_MODE_SELECT_10:
-            cbXfer = scsiBE2H_U16(pbCdb + 7);
-            enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_MODE_SENSE_10:
-            cbXfer = scsiBE2H_U16(pbCdb + 7);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_READ_10:
-            uLba = scsiBE2H_U32(pbCdb + 2);
-            cSectors = scsiBE2H_U16(pbCdb + 7);
-            cbSector = 2048;
-            cbXfer = cSectors * cbSector;
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_READ_12:
-            uLba = scsiBE2H_U32(pbCdb + 2);
-            cSectors = scsiBE2H_U32(pbCdb + 6);
-            cbSector = 2048;
-            cbXfer = cSectors * cbSector;
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_READ_BUFFER:
-            cbXfer = scsiBE2H_U24(pbCdb + 6);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_READ_BUFFER_CAPACITY:
-            cbXfer = scsiBE2H_U16(pbCdb + 7);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_READ_CAPACITY:
-            cbXfer = 8;
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_READ_CD:
-        case SCSI_READ_CD_MSF:
+        /* Handle the command here and copy sense data over. */
+        void *pvBuf = NULL;
+        int rc = drvHostBaseBufferRetain(&pThis->Core, pReq, cbBuf, false /*fWrite*/, &pvBuf);
+        if (RT_SUCCESS(rc))
         {
-            /* Get sector size based on the expected sector type field. */
-            switch ((pbCdb[1] >> 2) & 0x7)
-            {
-                case 0x0: /* All types. */
-                {
-                    uint32_t iLbaStart;
-
-                    if (pbCdb[0] == SCSI_READ_CD)
-                        iLbaStart = scsiBE2H_U32(&pbCdb[2]);
-                    else
-                        iLbaStart = scsiMSF2LBA(&pbCdb[3]);
-
-                    if (pThis->pTrackList)
-                        cbSector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pThis->pTrackList, iLbaStart);
-                    else
-                        cbSector = 2048; /* Might be incorrect if we couldn't determine the type. */
-                    break;
-                }
-                case 0x1: /* CD-DA */
-                    cbSector = 2352;
-                    break;
-                case 0x2: /* Mode 1 */
-                    cbSector = 2048;
-                    break;
-                case 0x3: /* Mode 2 formless */
-                    cbSector = 2336;
-                    break;
-                case 0x4: /* Mode 2 form 1 */
-                    cbSector = 2048;
-                    break;
-                case 0x5: /* Mode 2 form 2 */
-                    cbSector = 2324;
-                    break;
-                default: /* Reserved */
-                    AssertMsgFailed(("Unknown sector type\n"));
-                    cbSector = 0; /** @todo we should probably fail the command here already. */
-            }
-
-            if (pbCdb[0] == SCSI_READ_CD)
-                cbXfer = scsiBE2H_U24(pbCdb + 6) * cbSector;
-            else /* SCSI_READ_MSF */
-            {
-                cSectors = scsiMSF2LBA(pbCdb + 6) - scsiMSF2LBA(pbCdb + 3);
-                if (cSectors > 32)
-                    cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
-                cbXfer = cSectors * cbSector;
-            }
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
+            memcpy(pvBuf, &pThis->abATAPISense[0], RT_MIN(sizeof(pThis->abATAPISense), cbBuf));
+            rc = drvHostBaseBufferRelease(&pThis->Core, pReq, cbBuf, false /* fWrite */, pvBuf);
+            AssertRC(rc);
+            drvHostDvdCmdOK(pThis);
+            *pu8ScsiSts = SCSI_STATUS_OK;
         }
-        case SCSI_READ_DISC_INFORMATION:
-            cbXfer = scsiBE2H_U16(pbCdb + 7);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_READ_DVD_STRUCTURE:
-            cbXfer = scsiBE2H_U16(pbCdb + 8);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_READ_FORMAT_CAPACITIES:
-            cbXfer = scsiBE2H_U16(pbCdb + 7);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_READ_SUBCHANNEL:
-            cbXfer = scsiBE2H_U16(pbCdb + 7);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_READ_TOC_PMA_ATIP:
-            cbXfer = scsiBE2H_U16(pbCdb + 7);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_READ_TRACK_INFORMATION:
-            cbXfer = scsiBE2H_U16(pbCdb + 7);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_REPORT_KEY:
-            cbXfer = scsiBE2H_U16(pbCdb + 8);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_REQUEST_SENSE:
-            cbXfer = pbCdb[4];
-            if ((pThis->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE)
-            {
-                /* Copy sense data over. */
-                void *pvBuf = NULL;
-                int rc = drvHostBaseBufferRetain(&pThis->Core, pReq, cbBuf, false /*fWrite*/, &pvBuf);
-                if (RT_SUCCESS(rc))
-                {
-                    memcpy(pvBuf, &pThis->abATAPISense[0], RT_MIN(sizeof(pThis->abATAPISense), cbBuf));
-                    rc = drvHostBaseBufferRelease(&pThis->Core, pReq, cbBuf, false /* fWrite */, pvBuf);
-                    AssertRC(rc);
-                    drvHostDvdCmdOK(pThis);
-                    *pu8ScsiSts = SCSI_STATUS_OK;
-                }
-                break;
-            }
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_SEND_CUE_SHEET:
-            cbXfer = scsiBE2H_U24(pbCdb + 6);
-            enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_SEND_DVD_STRUCTURE:
-            cbXfer = scsiBE2H_U16(pbCdb + 8);
-            enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_SEND_EVENT:
-            cbXfer = scsiBE2H_U16(pbCdb + 8);
-            enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_SEND_KEY:
-            cbXfer = scsiBE2H_U16(pbCdb + 8);
-            enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_SEND_OPC_INFORMATION:
-            cbXfer = scsiBE2H_U16(pbCdb + 7);
-            enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_SET_STREAMING:
-            cbXfer = scsiBE2H_U16(pbCdb + 9);
-            enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_WRITE_10:
-        case SCSI_WRITE_AND_VERIFY_10:
-            uLba = scsiBE2H_U32(pbCdb + 2);
-            cSectors = scsiBE2H_U16(pbCdb + 7);
-            if (pThis->pTrackList)
-                cbSector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pThis->pTrackList, uLba);
-            else
-                cbSector = 2048;
-            cbXfer = cSectors * cbSector;
-            enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_WRITE_12:
-            uLba = scsiBE2H_U32(pbCdb + 2);
-            cSectors = scsiBE2H_U32(pbCdb + 6);
-            if (pThis->pTrackList)
-                cbSector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pThis->pTrackList, uLba);
-            else
-                cbSector = 2048;
-            cbXfer = cSectors * cbSector;
-            enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_WRITE_BUFFER:
-            switch (pbCdb[1] & 0x1f)
-            {
-                case 0x04: /* download microcode */
-                case 0x05: /* download microcode and save */
-                case 0x06: /* download microcode with offsets */
-                case 0x07: /* download microcode with offsets and save */
-                case 0x0e: /* download microcode with offsets and defer activation */
-                case 0x0f: /* activate deferred microcode */
-                    LogRel(("HostDVD#%u: CD-ROM passthrough command attempted to update firmware, blocked\n", pThis->Core.pDrvIns->iInstance));
-                    *pu8ScsiSts = drvHostDvdCmdErrorSimple(pThis, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
-                    break;
-                default:
-                    cbXfer = scsiBE2H_U16(pbCdb + 6);
-                    enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
-                    fPassthrough = true;
-                    break;
-            }
-            break;
-        case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */
-            cbXfer = scsiBE2H_U32(pbCdb + 6);
-            enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
-            fPassthrough = true;
-            break;
-        case SCSI_REZERO_UNIT:
-            /* Obsolete command used by cdrecord. What else would one expect?
-             * This command is not sent to the drive, it is handled internally,
-             * as the Linux kernel doesn't like it (message "scsi: unknown
-             * opcode 0x01" in syslog) and replies with a sense code of 0,
-             * which sends cdrecord to an endless loop. */
-            *pu8ScsiSts = drvHostDvdCmdErrorSimple(pThis, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
-            break;
-        default:
-            LogRel(("HostDVD#%u: Passthrough unimplemented for command %#x\n", pThis->Core.pDrvIns->iInstance, pbCdb[0]));
-            *pu8ScsiSts = drvHostDvdCmdErrorSimple(pThis, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
-            break;
     }
-
-    if (fPassthrough)
-    {
-        *penmTxDir = enmTxDir;
-        *pcbXfer   = cbXfer;
-        *pcbSector = cbSector;
-    }
+    else
+        fPassthrough = ATAPIPassthroughParseCdb(pbCdb, cbCdb, cbBuf, pThis->pTrackList,
+                                                &pThis->abATAPISense[0], sizeof(pThis->abATAPISense),
+                                                penmTxDir, pcbXfer, pcbSector, pu8ScsiSts);
 
     return fPassthrough;
 }
+
 
 /**
