Changeset 64360 in vbox for trunk/src/VBox/Devices/Storage
- Timestamp:
- Oct 22, 2016 2:47:10 PM (8 years ago)
- svn:sync-xref-src-repo-rev:
- 111465
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DrvHostDVD.cpp
r64320 r64360 36 36 #include "ATAPIPassthrough.h" 37 37 38 /** ATAPI sense info size. */ 39 #define ATAPI_SENSE_SIZE 64 40 /** Size of an ATAPI packet. */ 41 #define ATAPI_PACKET_SIZE 12 42 38 43 /** 39 44 * Host DVD driver instance data. … … 45 50 /** The current tracklist of the loaded medium if passthrough is used. */ 46 51 PTRACKLIST pTrackList; 52 /** ATAPI sense data. */ 53 uint8_t abATAPISense[ATAPI_SENSE_SIZE]; 47 54 } DRVHOSTDVD; 48 55 /** Pointer to the host DVD driver instance data. */ … … 53 60 *********************************************************************************************************************************/ 54 61 55 56 static PDMMEDIATXDIR drvHostDvdGetTxDirFromCmd(uint8_t bCdb) 57 { 62 DECLINLINE(void) drvHostDvdH2BE_U16(uint8_t *pbBuf, uint16_t val) 63 { 64 pbBuf[0] = val >> 8; 65 pbBuf[1] = val; 66 } 67 68 69 DECLINLINE(void) drvHostDvdH2BE_U24(uint8_t *pbBuf, uint32_t val) 70 { 71 pbBuf[0] = val >> 16; 72 pbBuf[1] = val >> 8; 73 pbBuf[2] = val; 74 } 75 76 77 DECLINLINE(void) drvHostDvdH2BE_U32(uint8_t *pbBuf, uint32_t val) 78 { 79 pbBuf[0] = val >> 24; 80 pbBuf[1] = val >> 16; 81 pbBuf[2] = val >> 8; 82 pbBuf[3] = val; 83 } 84 85 86 DECLINLINE(uint16_t) drvHostDvdBE2H_U16(const uint8_t *pbBuf) 87 { 88 return (pbBuf[0] << 8) | pbBuf[1]; 89 } 90 91 92 DECLINLINE(uint32_t) drvHostDvdBE2H_U24(const uint8_t *pbBuf) 93 { 94 return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2]; 95 } 96 97 98 DECLINLINE(uint32_t) drvHostDvdBE2H_U32(const uint8_t *pbBuf) 99 { 100 return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3]; 101 } 102 103 104 DECLINLINE(void) drvHostDvdLBA2MSF(uint8_t *pbBuf, uint32_t iATAPILBA) 105 { 106 iATAPILBA += 150; 107 pbBuf[0] = (iATAPILBA / 75) / 60; 108 pbBuf[1] = (iATAPILBA / 75) % 60; 109 pbBuf[2] = iATAPILBA % 75; 110 } 111 112 113 DECLINLINE(uint32_t) drvHostDvdMSF2LBA(const uint8_t *pbBuf) 114 { 115 return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2]; 116 } 117 118 static void drvHostDvdCmdOK(PDRVHOSTDVD pThis) 119 { 120 memset(pThis->abATAPISense, '\0', sizeof(pThis->abATAPISense)); 121 pThis->abATAPISense[0] = 0x70; 122 pThis->abATAPISense[7] = 10; 123 } 124 125 static void drvHostDvdCmdError(PDRVHOSTDVD pThis, const uint8_t *pabATAPISense, size_t cbATAPISense) 126 { 127 Log(("%s: sense=%#x (%s) asc=%#x ascq=%#x (%s)\n", __FUNCTION__, pabATAPISense[2] & 0x0f, SCSISenseText(pabATAPISense[2] & 0x0f), 128 pabATAPISense[12], pabATAPISense[13], SCSISenseExtText(pabATAPISense[12], pabATAPISense[13]))); 129 memset(pThis->abATAPISense, '\0', sizeof(pThis->abATAPISense)); 130 memcpy(pThis->abATAPISense, pabATAPISense, RT_MIN(cbATAPISense, sizeof(pThis->abATAPISense))); 131 } 132 133 /** @todo deprecated function - doesn't provide enough info. Replace by direct 134 * calls to drvHostDvdCmdError() with full data. */ 135 static void drvHostDvdCmdErrorSimple(PDRVHOSTDVD pThis, uint8_t uATAPISenseKey, uint8_t uATAPIASC) 136 { 137 uint8_t abATAPISense[ATAPI_SENSE_SIZE]; 138 memset(abATAPISense, '\0', sizeof(abATAPISense)); 139 abATAPISense[0] = 0x70 | (1 << 7); 140 abATAPISense[2] = uATAPISenseKey & 0x0f; 141 abATAPISense[7] = 10; 142 abATAPISense[12] = uATAPIASC; 143 drvHostDvdCmdError(pThis, abATAPISense, sizeof(abATAPISense)); 144 } 145 146 static void drvHostDvdSCSIPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize) 147 { 148 for (uint32_t i = 0; i < cbSize; i++) 149 { 150 if (*pbSrc) 151 pbDst[i] = *pbSrc++; 152 else 153 pbDst[i] = ' '; 154 } 155 } 156 157 158 static bool drvHostDvdParseCdb(PDRVHOSTDVD pThis, PDRVHOSTBASEREQ pReq, 159 const uint8_t *pbCdb, size_t cbCdb, size_t cbBuf, 160 PDMMEDIATXDIR *penmTxDir, size_t *pcbXfer, 161 size_t *pcbSector, uint8_t *pu8ScsiSts) 162 { 163 uint32_t uLba = 0; 164 uint32_t cSectors = 0; 165 size_t cbSector = 0; 166 size_t cbXfer = 0; 167 bool fPassthrough = false; 58 168 PDMMEDIATXDIR enmTxDir = PDMMEDIATXDIR_NONE; 59 169 60 switch (bCdb) 170 RT_NOREF(cbCdb); 171 172 switch (pbCdb[0]) 61 173 { 174 /* First the commands we can pass through without further processing. */ 62 175 case SCSI_BLANK: 63 176 case SCSI_CLOSE_TRACK_SESSION: … … 68 181 case SCSI_PLAY_AUDIO_MSF: 69 182 case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL: 183 case SCSI_REPAIR_TRACK: 70 184 case SCSI_RESERVE_TRACK: 71 185 case SCSI_SCAN: 72 186 case SCSI_SEEK_10: 73 case SCSI_REPAIR_TRACK:74 187 case SCSI_SET_CD_SPEED: 75 188 case SCSI_SET_READ_AHEAD: … … 79 192 case SCSI_TEST_UNIT_READY: 80 193 case SCSI_VERIFY_10: 81 enmTxDir = PDMMEDIATXDIR_NONE; 194 fPassthrough = true; 195 break; 196 case SCSI_ERASE_10: 197 uLba = drvHostDvdBE2H_U32(pbCdb + 2); 198 cbXfer = drvHostDvdBE2H_U16(pbCdb + 7); 199 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 200 fPassthrough = true; 201 break; 202 case SCSI_FORMAT_UNIT: 203 cbXfer = cbBuf; 204 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 205 fPassthrough = true; 206 break; 207 case SCSI_GET_CONFIGURATION: 208 cbXfer = drvHostDvdBE2H_U16(pbCdb + 7); 209 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 210 fPassthrough = true; 211 break; 212 case SCSI_GET_EVENT_STATUS_NOTIFICATION: 213 cbXfer = drvHostDvdBE2H_U16(pbCdb + 7); 214 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 215 fPassthrough = true; 216 break; 217 case SCSI_GET_PERFORMANCE: 218 cbXfer = cbBuf; 219 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 220 fPassthrough = true; 221 break; 222 case SCSI_INQUIRY: 223 cbXfer = drvHostDvdBE2H_U16(pbCdb + 3); 224 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 225 fPassthrough = true; 226 break; 227 case SCSI_MECHANISM_STATUS: 228 cbXfer = drvHostDvdBE2H_U16(pbCdb + 8); 229 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 230 fPassthrough = true; 231 break; 232 case SCSI_MODE_SELECT_10: 233 cbXfer = drvHostDvdBE2H_U16(pbCdb + 7); 234 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 235 fPassthrough = true; 236 break; 237 case SCSI_MODE_SENSE_10: 238 cbXfer = drvHostDvdBE2H_U16(pbCdb + 7); 239 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 240 fPassthrough = true; 241 break; 242 case SCSI_READ_10: 243 uLba = drvHostDvdBE2H_U32(pbCdb + 2); 244 cSectors = drvHostDvdBE2H_U16(pbCdb + 7); 245 cbSector = 2048; 246 cbXfer = cSectors * cbSector; 247 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 248 fPassthrough = true; 249 break; 250 case SCSI_READ_12: 251 uLba = drvHostDvdBE2H_U32(pbCdb + 2); 252 cSectors = drvHostDvdBE2H_U32(pbCdb + 6); 253 cbSector = 2048; 254 cbXfer = cSectors * cbSector; 255 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 256 fPassthrough = true; 257 break; 258 case SCSI_READ_BUFFER: 259 cbXfer = drvHostDvdBE2H_U24(pbCdb + 6); 260 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 261 fPassthrough = true; 262 break; 263 case SCSI_READ_BUFFER_CAPACITY: 264 cbXfer = drvHostDvdBE2H_U16(pbCdb + 7); 265 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 266 fPassthrough = true; 267 break; 268 case SCSI_READ_CAPACITY: 269 cbXfer = 8; 270 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 271 fPassthrough = true; 272 break; 273 case SCSI_READ_CD: 274 case SCSI_READ_CD_MSF: 275 { 276 /* Get sector size based on the expected sector type field. */ 277 switch ((pbCdb[1] >> 2) & 0x7) 278 { 279 case 0x0: /* All types. */ 280 { 281 uint32_t iLbaStart; 282 283 if (pbCdb[0] == SCSI_READ_CD) 284 iLbaStart = drvHostDvdBE2H_U32(&pbCdb[2]); 285 else 286 iLbaStart = drvHostDvdMSF2LBA(&pbCdb[3]); 287 288 if (pThis->pTrackList) 289 cbSector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pThis->pTrackList, iLbaStart); 290 else 291 cbSector = 2048; /* Might be incorrect if we couldn't determine the type. */ 292 break; 293 } 294 case 0x1: /* CD-DA */ 295 cbSector = 2352; 296 break; 297 case 0x2: /* Mode 1 */ 298 cbSector = 2048; 299 break; 300 case 0x3: /* Mode 2 formless */ 301 cbSector = 2336; 302 break; 303 case 0x4: /* Mode 2 form 1 */ 304 cbSector = 2048; 305 break; 306 case 0x5: /* Mode 2 form 2 */ 307 cbSector = 2324; 308 break; 309 default: /* Reserved */ 310 AssertMsgFailed(("Unknown sector type\n")); 311 cbSector = 0; /** @todo we should probably fail the command here already. */ 312 } 313 314 if (pbCdb[0] == SCSI_READ_CD) 315 cbXfer = drvHostDvdBE2H_U24(pbCdb + 6) * cbSector; 316 else /* SCSI_READ_MSF */ 317 { 318 cSectors = drvHostDvdMSF2LBA(pbCdb + 6) - drvHostDvdMSF2LBA(pbCdb + 3); 319 if (cSectors > 32) 320 cSectors = 32; /* Limit transfer size to 64~74K. Safety first. In any case this can only harm software doing CDDA extraction. */ 321 cbXfer = cSectors * cbSector; 322 } 323 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 324 fPassthrough = true; 325 break; 326 } 327 case SCSI_READ_DISC_INFORMATION: 328 cbXfer = drvHostDvdBE2H_U16(pbCdb + 7); 329 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 330 fPassthrough = true; 331 break; 332 case SCSI_READ_DVD_STRUCTURE: 333 cbXfer = drvHostDvdBE2H_U16(pbCdb + 8); 334 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 335 fPassthrough = true; 336 break; 337 case SCSI_READ_FORMAT_CAPACITIES: 338 cbXfer = drvHostDvdBE2H_U16(pbCdb + 7); 339 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 340 fPassthrough = true; 341 break; 342 case SCSI_READ_SUBCHANNEL: 343 cbXfer = drvHostDvdBE2H_U16(pbCdb + 7); 344 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 345 fPassthrough = true; 346 break; 347 case SCSI_READ_TOC_PMA_ATIP: 348 cbXfer = drvHostDvdBE2H_U16(pbCdb + 7); 349 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 350 fPassthrough = true; 351 break; 352 case SCSI_READ_TRACK_INFORMATION: 353 cbXfer = drvHostDvdBE2H_U16(pbCdb + 7); 354 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 355 fPassthrough = true; 356 break; 357 case SCSI_REPORT_KEY: 358 cbXfer = drvHostDvdBE2H_U16(pbCdb + 8); 359 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 360 fPassthrough = true; 361 break; 362 case SCSI_REQUEST_SENSE: 363 cbXfer = pbCdb[4]; 364 if ((pThis->abATAPISense[2] & 0x0f) != SCSI_SENSE_NONE) 365 { 366 /* Copy sense data over. */ 367 void *pvBuf = NULL; 368 int rc = drvHostBaseBufferRetain(&pThis->Core, pReq, cbBuf, false /*fWrite*/, &pvBuf); 369 if (RT_SUCCESS(rc)) 370 { 371 memcpy(pvBuf, &pThis->abATAPISense[0], RT_MIN(sizeof(pThis->abATAPISense), cbBuf)); 372 rc = drvHostBaseBufferRelease(&pThis->Core, pReq, cbBuf, false /* fWrite */, pvBuf); 373 AssertRC(rc); 374 drvHostDvdCmdOK(pThis); 375 *pu8ScsiSts = SCSI_STATUS_OK; 376 } 377 break; 378 } 379 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 380 fPassthrough = true; 381 break; 382 case SCSI_SEND_CUE_SHEET: 383 cbXfer = drvHostDvdBE2H_U24(pbCdb + 6); 384 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 385 fPassthrough = true; 386 break; 387 case SCSI_SEND_DVD_STRUCTURE: 388 cbXfer = drvHostDvdBE2H_U16(pbCdb + 8); 389 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 390 fPassthrough = true; 391 break; 392 case SCSI_SEND_EVENT: 393 cbXfer = drvHostDvdBE2H_U16(pbCdb + 8); 394 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 395 fPassthrough = true; 396 break; 397 case SCSI_SEND_KEY: 398 cbXfer = drvHostDvdBE2H_U16(pbCdb + 8); 399 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 400 fPassthrough = true; 401 break; 402 case SCSI_SEND_OPC_INFORMATION: 403 cbXfer = drvHostDvdBE2H_U16(pbCdb + 7); 404 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 405 fPassthrough = true; 82 406 break; 83 407 case SCSI_SET_STREAMING: 84 case SCSI_ERASE_10: 85 case SCSI_FORMAT_UNIT: 86 case SCSI_MODE_SELECT_10: 87 case SCSI_SEND_CUE_SHEET: 88 case SCSI_SEND_DVD_STRUCTURE: 89 case SCSI_SEND_EVENT: 90 case SCSI_SEND_KEY: 91 case SCSI_SEND_OPC_INFORMATION: 408 cbXfer = drvHostDvdBE2H_U16(pbCdb + 9); 409 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 410 fPassthrough = true; 411 break; 92 412 case SCSI_WRITE_10: 93 413 case SCSI_WRITE_AND_VERIFY_10: 414 uLba = drvHostDvdBE2H_U32(pbCdb + 2); 415 cSectors = drvHostDvdBE2H_U16(pbCdb + 7); 416 if (pThis->pTrackList) 417 cbSector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pThis->pTrackList, uLba); 418 else 419 cbSector = 2048; 420 cbXfer = cSectors * cbSector; 421 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 422 fPassthrough = true; 423 break; 94 424 case SCSI_WRITE_12: 95 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 96 break; 97 case SCSI_GET_CONFIGURATION: 98 case SCSI_GET_EVENT_STATUS_NOTIFICATION: 99 case SCSI_GET_PERFORMANCE: 100 case SCSI_INQUIRY: 101 case SCSI_MECHANISM_STATUS: 102 case SCSI_MODE_SENSE_10: 103 case SCSI_READ_10: 104 case SCSI_READ_12: 105 case SCSI_READ_BUFFER: 106 case SCSI_READ_BUFFER_CAPACITY: 107 case SCSI_READ_CAPACITY: 108 case SCSI_READ_CD: 109 case SCSI_READ_CD_MSF: 110 case SCSI_READ_DISC_INFORMATION: 111 case SCSI_READ_DVD_STRUCTURE: 112 case SCSI_READ_FORMAT_CAPACITIES: 113 case SCSI_READ_SUBCHANNEL: 114 case SCSI_READ_TOC_PMA_ATIP: 115 case SCSI_READ_TRACK_INFORMATION: 116 case SCSI_REPORT_KEY: 117 case SCSI_REQUEST_SENSE: 118 case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */ 119 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 120 break; 121 425 uLba = drvHostDvdBE2H_U32(pbCdb + 2); 426 cSectors = drvHostDvdBE2H_U32(pbCdb + 6); 427 if (pThis->pTrackList) 428 cbSector = ATAPIPassthroughTrackListGetSectorSizeFromLba(pThis->pTrackList, uLba); 429 else 430 cbSector = 2048; 431 cbXfer = cSectors * cbSector; 432 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 433 fPassthrough = true; 434 break; 122 435 case SCSI_WRITE_BUFFER: 123 #if 0 124 switch (pbPacket[1] & 0x1f) 436 switch (pbCdb[1] & 0x1f) 125 437 { 126 438 case 0x04: /* download microcode */ … … 130 442 case 0x0e: /* download microcode with offsets and defer activation */ 131 443 case 0x0f: /* activate deferred microcode */ 132 LogRel(("PIIX3 ATA: LUN#%d: CD-ROM passthrough command attempted to update firmware, blocked\n", s->iLUN)); 133 atapiR3CmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET); 444 LogRel(("HostDVD#%u: CD-ROM passthrough command attempted to update firmware, blocked\n", pThis->Core.pDrvIns->iInstance)); 445 drvHostDvdCmdErrorSimple(pThis, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET); 446 *pu8ScsiSts = SCSI_STATUS_CHECK_CONDITION; 134 447 break; 135 448 default: 449 cbXfer = drvHostDvdBE2H_U16(pbCdb + 6); 136 450 enmTxDir = PDMMEDIATXDIR_TO_DEVICE; 451 fPassthrough = true; 137 452 break; 138 453 } 139 #endif 454 break; 455 case SCSI_REPORT_LUNS: /* Not part of MMC-3, but used by Windows. */ 456 cbXfer = drvHostDvdBE2H_U32(pbCdb + 6); 457 enmTxDir = PDMMEDIATXDIR_FROM_DEVICE; 458 fPassthrough = true; 140 459 break; 141 460 case SCSI_REZERO_UNIT: … … 145 464 * opcode 0x01" in syslog) and replies with a sense code of 0, 146 465 * which sends cdrecord to an endless loop. */ 147 //atapiR3CmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE); 466 drvHostDvdCmdErrorSimple(pThis, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE); 467 *pu8ScsiSts = SCSI_STATUS_CHECK_CONDITION; 148 468 break; 149 469 default: 150 LogRel(("HostDVD: passthrough unimplemented for command %#x\n", bCdb)); 151 //atapiR3CmdErrorSimple(s, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE); 470 LogRel(("HostDVD#%u: Passthrough unimplemented for command %#x\n", pThis->Core.pDrvIns->iInstance, pbCdb[0])); 471 drvHostDvdCmdErrorSimple(pThis, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE); 472 *pu8ScsiSts = SCSI_STATUS_CHECK_CONDITION; 152 473 break; 153 474 } 154 475 155 return enmTxDir; 476 if (fPassthrough) 477 { 478 *penmTxDir = enmTxDir; 479 *pcbXfer = cbXfer; 480 *pcbSector = cbSector; 481 } 482 483 return fPassthrough; 156 484 } 157 485 … … 215 543 RT_NOREF2(uLun, cTimeoutMillies); 216 544 217 PDRVHOST BASE pThis = RT_FROM_MEMBER(pInterface, DRVHOSTBASE,IMediaEx);545 PDRVHOSTDVD pThis = RT_FROM_MEMBER(pInterface, DRVHOSTDVD, Core.IMediaEx); 218 546 PDRVHOSTBASEREQ pReq = (PDRVHOSTBASEREQ)hIoReq; 219 547 int rc = VINF_SUCCESS; 220 void *pvBuf = NULL; 221 222 LogFlow(("%s: pbCdb[0]=%#04x enmTxDir=%d cbBuf=%zu timeout=%u\n", __FUNCTION__, pbCdb[0], enmTxDir, cbBuf, cTimeoutMillies)); 223 224 RTCritSectEnter(&pThis->CritSect); 225 if (cbBuf) 548 549 LogFlow(("%s: pbCdb[0]=%#04x{%s} enmTxDir=%d cbBuf=%zu timeout=%u\n", 550 __FUNCTION__, pbCdb[0], SCSICmdText(pbCdb[0]), enmTxDir, cbBuf, cTimeoutMillies)); 551 552 RTCritSectEnter(&pThis->Core.CritSect); 553 554 /* 555 * Parse the command first to fend off any illegal or dangeroups commands we don't want the guest 556 * to execute on the host drive. 557 */ 558 PDMMEDIATXDIR enmXferDir = PDMMEDIATXDIR_NONE; 559 size_t cbXfer = 0; 560 size_t cbSector = 0; 561 bool fPassthrough = drvHostDvdParseCdb(pThis, pReq, pbCdb, cbCdb, cbBuf, 562 &enmXferDir, &cbXfer, &cbSector, pu8ScsiSts); 563 if (fPassthrough) 226 564 { 227 bool fWrite = (enmTxDir == PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN || enmTxDir == PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE); 228 rc = drvHostBaseBufferRetain(pThis, pReq, cbBuf, fWrite, &pvBuf); 229 } 230 231 if (RT_SUCCESS(rc)) 232 { 233 uint32_t cbBufTmp = (uint32_t)cbBuf; 234 PDMMEDIATXDIR enmMediaTxDir = PDMMEDIATXDIR_NONE; 235 /* 236 * Pass the request on to the internal scsi command interface. 237 * The command seems to be 12 bytes long, the docs a bit copy&pasty on the command length point... 238 */ 239 if (enmTxDir == PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN || enmTxDir == PDMMEDIAEXIOREQSCSITXDIR_FROM_DEVICE) 240 memset(pvBuf, '\0', cbBuf); /* we got read size, but zero it anyway. */ 241 242 if (cbBuf) 565 void *pvBuf = NULL; 566 size_t cbXferCur = cbXfer; 567 568 if (cbXfer) 569 rc = drvHostBaseBufferRetain(&pThis->Core, pReq, cbXfer, enmXferDir == PDMMEDIATXDIR_TO_DEVICE, &pvBuf); 570 571 if (cbXfer > SCSI_MAX_BUFFER_SIZE) 243 572 { 244 switch (enmTxDir) 573 /* Linux accepts commands with up to 100KB of data, but expects 574 * us to handle commands with up to 128KB of data. The usual 575 * imbalance of powers. */ 576 uint8_t aATAPICmd[ATAPI_PACKET_SIZE]; 577 uint32_t iATAPILBA, cSectors; 578 uint8_t *pbBuf = (uint8_t *)pvBuf; 579 580 switch (pbCdb[0]) 245 581 { 246 case PDMMEDIAEXIOREQSCSITXDIR_FROM_DEVICE: 247 enmMediaTxDir = PDMMEDIATXDIR_FROM_DEVICE; 248 break; 249 case PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE: 250 enmMediaTxDir = PDMMEDIATXDIR_TO_DEVICE; 251 break; 252 case PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN: 253 enmMediaTxDir = drvHostDvdGetTxDirFromCmd(pbCdb[0]); 254 break; 255 case PDMMEDIAEXIOREQSCSITXDIR_NONE: 582 case SCSI_READ_10: 583 case SCSI_WRITE_10: 584 case SCSI_WRITE_AND_VERIFY_10: 585 iATAPILBA = drvHostDvdBE2H_U32(pbCdb + 2); 586 cSectors = drvHostDvdBE2H_U16(pbCdb + 7); 587 break; 588 case SCSI_READ_12: 589 case SCSI_WRITE_12: 590 iATAPILBA = drvHostDvdBE2H_U32(pbCdb + 2); 591 cSectors = drvHostDvdBE2H_U32(pbCdb + 6); 592 break; 593 case SCSI_READ_CD: 594 iATAPILBA = drvHostDvdBE2H_U32(pbCdb + 2); 595 cSectors = drvHostDvdBE2H_U24(pbCdb + 6); 596 break; 597 case SCSI_READ_CD_MSF: 598 iATAPILBA = drvHostDvdMSF2LBA(pbCdb + 3); 599 cSectors = drvHostDvdMSF2LBA(pbCdb + 6) - iATAPILBA; 600 break; 256 601 default: 257 enmMediaTxDir = PDMMEDIATXDIR_NONE; 258 break; 602 AssertMsgFailed(("Don't know how to split command %#04x\n", pbCdb[0])); 603 LogRelMax(10, ("HostDVD#%u: CD-ROM passthrough split error\n", pThis->Core.pDrvIns->iInstance)); 604 drvHostDvdCmdErrorSimple(pThis, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE); 605 *pu8ScsiSts = SCSI_STATUS_CHECK_CONDITION; 606 rc = drvHostBaseBufferRelease(&pThis->Core, pReq, cbBuf, enmXferDir == PDMMEDIATXDIR_TO_DEVICE, pvBuf); 607 RTCritSectLeave(&pThis->Core.CritSect); 608 return VINF_SUCCESS; 609 } 610 memcpy(aATAPICmd, pbCdb, RT_MIN(cbCdb, ATAPI_PACKET_SIZE)); 611 uint32_t cReqSectors = 0; 612 for (uint32_t i = cSectors; i > 0; i -= cReqSectors) 613 { 614 if (i * cbSector > SCSI_MAX_BUFFER_SIZE) 615 cReqSectors = SCSI_MAX_BUFFER_SIZE / cbSector; 616 else 617 cReqSectors = i; 618 uint32_t cbCurrTX = cbSector * cReqSectors; 619 switch (pbCdb[0]) 620 { 621 case SCSI_READ_10: 622 case SCSI_WRITE_10: 623 case SCSI_WRITE_AND_VERIFY_10: 624 drvHostDvdH2BE_U32(aATAPICmd + 2, iATAPILBA); 625 drvHostDvdH2BE_U16(aATAPICmd + 7, cReqSectors); 626 break; 627 case SCSI_READ_12: 628 case SCSI_WRITE_12: 629 drvHostDvdH2BE_U32(aATAPICmd + 2, iATAPILBA); 630 drvHostDvdH2BE_U32(aATAPICmd + 6, cReqSectors); 631 break; 632 case SCSI_READ_CD: 633 drvHostDvdH2BE_U32(aATAPICmd + 2, iATAPILBA); 634 drvHostDvdH2BE_U24(aATAPICmd + 6, cReqSectors); 635 break; 636 case SCSI_READ_CD_MSF: 637 drvHostDvdLBA2MSF(aATAPICmd + 3, iATAPILBA); 638 drvHostDvdLBA2MSF(aATAPICmd + 6, iATAPILBA + cReqSectors); 639 break; 640 } 641 rc = drvHostBaseScsiCmdOs(&pThis->Core, aATAPICmd, sizeof(aATAPICmd), 642 enmXferDir, pbBuf, &cbCurrTX, 643 &pThis->abATAPISense[0], sizeof(pThis->abATAPISense), 644 cTimeoutMillies /**< @todo timeout */); 645 if (rc != VINF_SUCCESS) 646 break; 647 iATAPILBA += cReqSectors; 648 pbBuf += cbSector * cReqSectors; 259 649 } 260 650 } 261 262 rc = drvHostBaseScsiCmdOs(pThis, pbCdb, cbCdb, enmMediaTxDir, pvBuf, &cbBufTmp, pabSense, cbSense, cTimeoutMillies); 263 if (rc == VERR_UNRESOLVED_ERROR) 651 else 264 652 { 265 /* sense information set */ 266 rc = VERR_DEV_IO_ERROR; 653 uint32_t cbXferTmp = (uint32_t)cbXferCur; 654 rc = drvHostBaseScsiCmdOs(&pThis->Core, pbCdb, cbCdb, enmXferDir, pvBuf, &cbXferTmp, 655 &pThis->abATAPISense[0], sizeof(pThis->abATAPISense), cTimeoutMillies); 656 } 657 658 if (RT_SUCCESS(rc)) 659 { 660 /* Do post processing for certain commands. */ 661 switch (pbCdb[0]) 662 { 663 case SCSI_SEND_CUE_SHEET: 664 case SCSI_READ_TOC_PMA_ATIP: 665 { 666 if (!pThis->pTrackList) 667 rc = ATAPIPassthroughTrackListCreateEmpty(&pThis->pTrackList); 668 669 if (RT_SUCCESS(rc)) 670 rc = ATAPIPassthroughTrackListUpdate(pThis->pTrackList, pbCdb, pvBuf); 671 672 if (RT_FAILURE(rc)) 673 LogRelMax(10, ("HostDVD#%u: Error (%Rrc) while updating the tracklist during %s, burning the disc might fail\n", 674 pThis->Core.pDrvIns->iInstance, rc, 675 pbCdb[0] == SCSI_SEND_CUE_SHEET ? "SEND CUE SHEET" : "READ TOC/PMA/ATIP")); 676 break; 677 } 678 case SCSI_SYNCHRONIZE_CACHE: 679 { 680 if (pThis->pTrackList) 681 ATAPIPassthroughTrackListClear(pThis->pTrackList); 682 break; 683 } 684 } 685 686 if (enmXferDir == PDMMEDIATXDIR_FROM_DEVICE) 687 { 688 Assert(cbXferCur <= cbXfer); 689 690 if (pbCdb[0] == SCSI_INQUIRY) 691 { 692 /* Make sure that the real drive cannot be identified. 693 * Motivation: changing the VM configuration should be as 694 * invisible as possible to the guest. */ 695 if (cbXferCur >= 8 + 8) 696 drvHostDvdSCSIPadStr((uint8_t *)pvBuf + 8, "VBOX", 8); 697 if (cbXferCur >= 16 + 16) 698 drvHostDvdSCSIPadStr((uint8_t *)pvBuf + 16, "CD-ROM", 16); 699 if (cbXferCur >= 32 + 4) 700 drvHostDvdSCSIPadStr((uint8_t *)pvBuf + 32, "1.0", 4); 701 } 702 703 if (cbXferCur) 704 Log3(("ATAPI PT data read (%d): %.*Rhxs\n", cbXferCur, cbXferCur, (uint8_t *)pvBuf)); 705 } 706 707 drvHostDvdCmdOK(pThis); 708 *pu8ScsiSts = SCSI_STATUS_OK; 709 } 710 else 711 { 712 do 713 { 714 /* don't log superfluous errors */ 715 if ( rc == VERR_DEV_IO_ERROR 716 && ( pbCdb[0] == SCSI_TEST_UNIT_READY 717 || pbCdb[0] == SCSI_READ_CAPACITY 718 || pbCdb[0] == SCSI_READ_DVD_STRUCTURE 719 || pbCdb[0] == SCSI_READ_TOC_PMA_ATIP)) 720 break; 721 LogRelMax(10, ("HostDVD#%u: CD-ROM passthrough cmd=%#04x sense=%d ASC=%#02x ASCQ=%#02x %Rrc\n", 722 pThis->Core.pDrvIns->iInstance, pbCdb[0], pThis->abATAPISense[2] & 0x0f, 723 pThis->abATAPISense[12], pThis->abATAPISense[13], rc)); 724 } while (0); 725 drvHostDvdCmdError(pThis, &pThis->abATAPISense[0], sizeof(pThis->abATAPISense)); 267 726 *pu8ScsiSts = SCSI_STATUS_CHECK_CONDITION; 727 rc = VINF_SUCCESS; 268 728 } 269 729 270 if (pbCdb[0] == SCSI_GET_EVENT_STATUS_NOTIFICATION) 271 { 272 uint8_t *pbBuf = (uint8_t*)pvBuf; 273 Log2(("Event Status Notification class=%#02x supported classes=%#02x\n", pbBuf[2], pbBuf[3])); 274 if (RT_BE2H_U16(*(uint16_t*)pbBuf) >= 6) 275 Log2((" event %#02x %#02x %#02x %#02x\n", pbBuf[4], pbBuf[5], pbBuf[6], pbBuf[7])); 276 } 277 278 if (cbBuf) 279 { 280 bool fWrite = (enmTxDir == PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN || enmTxDir == PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE); 281 rc = drvHostBaseBufferRelease(pThis, pReq, cbBuf, fWrite, pvBuf); 282 } 730 if (cbXfer) 731 rc = drvHostBaseBufferRelease(&pThis->Core, pReq, cbXfer, enmXferDir == PDMMEDIATXDIR_TO_DEVICE, pvBuf); 283 732 } 284 RTCritSectLeave(&pThis->CritSect); 733 734 /* 735 * We handled the command, check the status code and copy over the sense data if 736 * it is CHECK CONDITION. 737 */ 738 if ( *pu8ScsiSts == SCSI_STATUS_CHECK_CONDITION 739 && VALID_PTR(pabSense) 740 && cbSense > 0) 741 memcpy(pabSense, &pThis->abATAPISense[0], RT_MIN(cbSense, sizeof(pThis->abATAPISense))); 742 743 RTCritSectLeave(&pThis->Core.CritSect); 285 744 286 745 LogFlow(("%s: rc=%Rrc\n", __FUNCTION__, rc));
Note:
See TracChangeset
for help on using the changeset viewer.