VirtualBox

Changeset 65965 in vbox


Ignore:
Timestamp:
Mar 7, 2017 10:45:04 AM (8 years ago)
Author:
vboxsync
Message:

Devices/Storage/DrvHostDVD: Make use of the CDB parse method in the common ATAPI passthrough code

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp

    r65113 r65965  
    9393
    9494
     95/**
     96 * Parse the CDB and check whether it can be passed through safely.
     97 *
     98 * @returns Flag whether to passthrough to the device is considered safe.
     99 * @param   pThis         The host DVD driver instance.
     100 * @param   pReq          The request.
     101 * @param   pbCdb         The CDB to parse.
     102 * @param   cbCdb         Size of the CDB in bytes.
     103 * @param   cbBuf         Size of the guest buffer.
     104 * @param   penmTxDir     Where to store the transfer direction (guest to host or vice versa).
     105 * @param   pcbXfer       Where to store the transfer size encoded in the CDB.
     106 * @param   pcbSector     Where to store the sector size used for the transfer.
     107 * @param   pu8ScsiSts    Where to store the SCSI status code.
     108 */
    95109static bool drvHostDvdParseCdb(PDRVHOSTDVD pThis, PDRVHOSTBASEREQ pReq,
    96110                               const uint8_t *pbCdb, size_t cbCdb, size_t cbBuf,
     
    98112                               size_t *pcbSector, uint8_t *pu8ScsiSts)
    99113{
    100     uint32_t uLba = 0;
    101     uint32_t cSectors = 0;
    102     size_t cbSector = 0;
    103     size_t cbXfer = 0;
    104114    bool fPassthrough = false;
    105     PDMMEDIATXDIR enmTxDir = PDMMEDIATXDIR_NONE;
    106 
    107     RT_NOREF(cbCdb);
    108 
    109     switch (pbCdb[0])
     115
     116    if (   pbCdb[0] == SCSI_REQUEST_SENSE
     117        && (pThis->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE)
    110118    {
    111         /* First the commands we can pass through without further processing. */
    112         case SCSI_BLANK:
    113         case SCSI_CLOSE_TRACK_SESSION:
    114         case SCSI_LOAD_UNLOAD_MEDIUM:
    115         case SCSI_PAUSE_RESUME:
    116         case SCSI_PLAY_AUDIO_10:
    117         case SCSI_PLAY_AUDIO_12:
    118         case SCSI_PLAY_AUDIO_MSF:
    119         case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
    120         case SCSI_REPAIR_TRACK:
    121         case SCSI_RESERVE_TRACK:
    122         case SCSI_SCAN:
    123         case SCSI_SEEK_10:
    124         case SCSI_SET_CD_SPEED:
    125         case SCSI_SET_READ_AHEAD:
    126         case SCSI_START_STOP_UNIT:
    127         case SCSI_STOP_PLAY_SCAN:
    128         case SCSI_SYNCHRONIZE_CACHE:
    129         case SCSI_TEST_UNIT_READY:
    130         case SCSI_VERIFY_10:
    131             fPassthrough = true;
    132             break;
    133         case SCSI_ERASE_10:
    134             uLba = scsiBE2H_U32(pbCdb + 2);
    135             cbXfer = scsiBE2H_U16(pbCdb + 7);
    136             enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
    137             fPassthrough = true;
    138             break;
    139         case SCSI_FORMAT_UNIT:
    140             cbXfer = cbBuf;
    141             enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
    142             fPassthrough = true;
    143             break;
    144         case SCSI_GET_CONFIGURATION:
    145             cbXfer = scsiBE2H_U16(pbCdb + 7);
    146             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    147             fPassthrough = true;
    148             break;
    149         case SCSI_GET_EVENT_STATUS_NOTIFICATION:
    150             cbXfer = scsiBE2H_U16(pbCdb + 7);
    151             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    152             fPassthrough = true;
    153             break;
    154         case SCSI_GET_PERFORMANCE:
    155             cbXfer = cbBuf;
    156             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    157             fPassthrough = true;
    158             break;
    159         case SCSI_INQUIRY:
    160             cbXfer = scsiBE2H_U16(pbCdb + 3);
    161             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    162             fPassthrough = true;
    163             break;
    164         case SCSI_MECHANISM_STATUS:
    165             cbXfer = scsiBE2H_U16(pbCdb + 8);
    166             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    167             fPassthrough = true;
    168             break;
    169         case SCSI_MODE_SELECT_10:
    170             cbXfer = scsiBE2H_U16(pbCdb + 7);
    171             enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
    172             fPassthrough = true;
    173             break;
    174         case SCSI_MODE_SENSE_10:
    175             cbXfer = scsiBE2H_U16(pbCdb + 7);
    176             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    177             fPassthrough = true;
    178             break;
    179         case SCSI_READ_10:
    180             uLba = scsiBE2H_U32(pbCdb + 2);
    181             cSectors = scsiBE2H_U16(pbCdb + 7);
    182             cbSector = 2048;
    183             cbXfer = cSectors * cbSector;
    184             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    185             fPassthrough = true;
    186             break;
    187         case SCSI_READ_12:
    188             uLba = scsiBE2H_U32(pbCdb + 2);
    189             cSectors = scsiBE2H_U32(pbCdb + 6);
    190             cbSector = 2048;
    191             cbXfer = cSectors * cbSector;
    192             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    193             fPassthrough = true;
    194             break;
    195         case SCSI_READ_BUFFER:
    196             cbXfer = scsiBE2H_U24(pbCdb + 6);
    197             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    198             fPassthrough = true;
    199             break;
    200         case SCSI_READ_BUFFER_CAPACITY:
    201             cbXfer = scsiBE2H_U16(pbCdb + 7);
    202             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    203             fPassthrough = true;
    204             break;
    205         case SCSI_READ_CAPACITY:
    206             cbXfer = 8;
    207             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    208             fPassthrough = true;
    209             break;
    210         case SCSI_READ_CD:
    211         case SCSI_READ_CD_MSF:
     119        /* Handle the command here and copy sense data over. */
     120        void *pvBuf = NULL;
     121        int rc = drvHostBaseBufferRetain(&pThis->Core, pReq, cbBuf, false /*fWrite*/, &pvBuf);
     122        if (RT_SUCCESS(rc))
    212123        {
    213             /* Get sector size based on the expected sector type field. */
    214             switch ((pbCdb[1] >> 2) & 0x7)
    215             {
    216                 case 0x0: /* All types. */
    217                 {
    218                     uint32_t iLbaStart;
    219 
    220                     if (pbCdb[0] == SCSI_READ_CD)
    221                         iLbaStart = scsiBE2H_U32(&pbCdb[2]);
    222                     else
    223                         iLbaStart = scsiMSF2LBA(&pbCdb[3]);
    224 
    225                     if (pThis->pTrackList)
    226                         cbSector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pThis->pTrackList, iLbaStart);
    227                     else
    228                         cbSector = 2048; /* Might be incorrect if we couldn't determine the type. */
    229                     break;
    230                 }
    231                 case 0x1: /* CD-DA */
    232                     cbSector = 2352;
    233                     break;
    234                 case 0x2: /* Mode 1 */
    235                     cbSector = 2048;
    236                     break;
    237                 case 0x3: /* Mode 2 formless */
    238                     cbSector = 2336;
    239                     break;
    240                 case 0x4: /* Mode 2 form 1 */
    241                     cbSector = 2048;
    242                     break;
    243                 case 0x5: /* Mode 2 form 2 */
    244                     cbSector = 2324;
    245                     break;
    246                 default: /* Reserved */
    247                     AssertMsgFailed(("Unknown sector type\n"));
    248                     cbSector = 0; /** @todo we should probably fail the command here already. */
    249             }
    250 
    251             if (pbCdb[0] == SCSI_READ_CD)
    252                 cbXfer = scsiBE2H_U24(pbCdb + 6) * cbSector;
    253             else /* SCSI_READ_MSF */
    254             {
    255                 cSectors = scsiMSF2LBA(pbCdb + 6) - scsiMSF2LBA(pbCdb + 3);
    256                 if (cSectors > 32)
    257                     cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */
    258                 cbXfer = cSectors * cbSector;
    259             }
    260             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    261             fPassthrough = true;
    262             break;
     124            memcpy(pvBuf, &pThis->abATAPISense[0], RT_MIN(sizeof(pThis->abATAPISense), cbBuf));
     125            rc = drvHostBaseBufferRelease(&pThis->Core, pReq, cbBuf, false /* fWrite */, pvBuf);
     126            AssertRC(rc);
     127            drvHostDvdCmdOK(pThis);
     128            *pu8ScsiSts = SCSI_STATUS_OK;
    263129        }
    264         case SCSI_READ_DISC_INFORMATION:
    265             cbXfer = scsiBE2H_U16(pbCdb + 7);
    266             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    267             fPassthrough = true;
    268             break;
    269         case SCSI_READ_DVD_STRUCTURE:
    270             cbXfer = scsiBE2H_U16(pbCdb + 8);
    271             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    272             fPassthrough = true;
    273             break;
    274         case SCSI_READ_FORMAT_CAPACITIES:
    275             cbXfer = scsiBE2H_U16(pbCdb + 7);
    276             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    277             fPassthrough = true;
    278             break;
    279         case SCSI_READ_SUBCHANNEL:
    280             cbXfer = scsiBE2H_U16(pbCdb + 7);
    281             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    282             fPassthrough = true;
    283             break;
    284         case SCSI_READ_TOC_PMA_ATIP:
    285             cbXfer = scsiBE2H_U16(pbCdb + 7);
    286             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    287             fPassthrough = true;
    288             break;
    289         case SCSI_READ_TRACK_INFORMATION:
    290             cbXfer = scsiBE2H_U16(pbCdb + 7);
    291             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    292             fPassthrough = true;
    293             break;
    294         case SCSI_REPORT_KEY:
    295             cbXfer = scsiBE2H_U16(pbCdb + 8);
    296             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    297             fPassthrough = true;
    298             break;
    299         case SCSI_REQUEST_SENSE:
    300             cbXfer = pbCdb[4];
    301             if ((pThis->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE)
    302             {
    303                 /* Copy sense data over. */
    304                 void *pvBuf = NULL;
    305                 int rc = drvHostBaseBufferRetain(&pThis->Core, pReq, cbBuf, false /*fWrite*/, &pvBuf);
    306                 if (RT_SUCCESS(rc))
    307                 {
    308                     memcpy(pvBuf, &pThis->abATAPISense[0], RT_MIN(sizeof(pThis->abATAPISense), cbBuf));
    309                     rc = drvHostBaseBufferRelease(&pThis->Core, pReq, cbBuf, false /* fWrite */, pvBuf);
    310                     AssertRC(rc);
    311                     drvHostDvdCmdOK(pThis);
    312                     *pu8ScsiSts = SCSI_STATUS_OK;
    313                 }
    314                 break;
    315             }
    316             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    317             fPassthrough = true;
    318             break;
    319         case SCSI_SEND_CUE_SHEET:
    320             cbXfer = scsiBE2H_U24(pbCdb + 6);
    321             enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
    322             fPassthrough = true;
    323             break;
    324         case SCSI_SEND_DVD_STRUCTURE:
    325             cbXfer = scsiBE2H_U16(pbCdb + 8);
    326             enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
    327             fPassthrough = true;
    328             break;
    329         case SCSI_SEND_EVENT:
    330             cbXfer = scsiBE2H_U16(pbCdb + 8);
    331             enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
    332             fPassthrough = true;
    333             break;
    334         case SCSI_SEND_KEY:
    335             cbXfer = scsiBE2H_U16(pbCdb + 8);
    336             enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
    337             fPassthrough = true;
    338             break;
    339         case SCSI_SEND_OPC_INFORMATION:
    340             cbXfer = scsiBE2H_U16(pbCdb + 7);
    341             enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
    342             fPassthrough = true;
    343             break;
    344         case SCSI_SET_STREAMING:
    345             cbXfer = scsiBE2H_U16(pbCdb + 9);
    346             enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
    347             fPassthrough = true;
    348             break;
    349         case SCSI_WRITE_10:
    350         case SCSI_WRITE_AND_VERIFY_10:
    351             uLba = scsiBE2H_U32(pbCdb + 2);
    352             cSectors = scsiBE2H_U16(pbCdb + 7);
    353             if (pThis->pTrackList)
    354                 cbSector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pThis->pTrackList, uLba);
    355             else
    356                 cbSector = 2048;
    357             cbXfer = cSectors * cbSector;
    358             enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
    359             fPassthrough = true;
    360             break;
    361         case SCSI_WRITE_12:
    362             uLba = scsiBE2H_U32(pbCdb + 2);
    363             cSectors = scsiBE2H_U32(pbCdb + 6);
    364             if (pThis->pTrackList)
    365                 cbSector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pThis->pTrackList, uLba);
    366             else
    367                 cbSector = 2048;
    368             cbXfer = cSectors * cbSector;
    369             enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
    370             fPassthrough = true;
    371             break;
    372         case SCSI_WRITE_BUFFER:
    373             switch (pbCdb[1] & 0x1f)
    374             {
    375                 case 0x04: /* download microcode */
    376                 case 0x05: /* download microcode and save */
    377                 case 0x06: /* download microcode with offsets */
    378                 case 0x07: /* download microcode with offsets and save */
    379                 case 0x0e: /* download microcode with offsets and defer activation */
    380                 case 0x0f: /* activate deferred microcode */
    381                     LogRel(("HostDVD#%u: CD-ROM passthrough command attempted to update firmware, blocked\n", pThis->Core.pDrvIns->iInstance));
    382                     *pu8ScsiSts = drvHostDvdCmdErrorSimple(pThis, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET);
    383                     break;
    384                 default:
    385                     cbXfer = scsiBE2H_U16(pbCdb + 6);
    386                     enmTxDir = PDMMEDIATXDIR_TO_DEVICE;
    387                     fPassthrough = true;
    388                     break;
    389             }
    390             break;
    391         case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */
    392             cbXfer = scsiBE2H_U32(pbCdb + 6);
    393             enmTxDir = PDMMEDIATXDIR_FROM_DEVICE;
    394             fPassthrough = true;
    395             break;
    396         case SCSI_REZERO_UNIT:
    397             /* Obsolete command used by cdrecord. What else would one expect?
    398              * This command is not sent to the drive, it is handled internally,
    399              * as the Linux kernel doesn't like it (message "scsi: unknown
    400              * opcode 0x01" in syslog) and replies with a sense code of 0,
    401              * which sends cdrecord to an endless loop. */
    402             *pu8ScsiSts = drvHostDvdCmdErrorSimple(pThis, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
    403             break;
    404         default:
    405             LogRel(("HostDVD#%u: Passthrough unimplemented for command %#x\n", pThis->Core.pDrvIns->iInstance, pbCdb[0]));
    406             *pu8ScsiSts = drvHostDvdCmdErrorSimple(pThis, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE);
    407             break;
    408130    }
    409 
    410     if (fPassthrough)
    411     {
    412         *penmTxDir = enmTxDir;
    413         *pcbXfer   = cbXfer;
    414         *pcbSector = cbSector;
    415     }
     131    else
     132        fPassthrough = ATAPIPassthroughParseCdb(pbCdb, cbCdb, cbBuf, pThis->pTrackList,
     133                                                &pThis->abATAPISense[0], sizeof(pThis->abATAPISense),
     134                                                penmTxDir, pcbXfer, pcbSector, pu8ScsiSts);
    416135
    417136    return fPassthrough;
    418137}
     138
    419139
    420140/**
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette