VSCSILunMmc.cpp revision a9205f11b268f45a18a89049148ff266bcf687a3
083dd76e9fd7a829b1ed67ffc9003276643e7db1vboxsync * Virtual SCSI driver: MMC LUN implementation (CD/DVD-ROM)
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2006-2011 Oracle Corporation
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * available from http://www.virtualbox.org. This file is free software;
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * you can redistribute it and/or modify it under the terms of the GNU
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * General Public License (GPL) as published by the Free Software
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
bd8e360cd1db83dcb2694ea9122ce3bc5bae678avboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync/*******************************************************************************
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync* Header Files *
85c594c1140f082dd862abde9dc7825137a3d51avboxsync*******************************************************************************/
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync * MMC LUN instance
87b2fb3f8283472ba7010aedbf2b4dc12302155cvboxsynctypedef struct VSCSILUNMMC
11a862be79fe123488bccca60c06e92cdbfec6e8vboxsync /** Core LUN structure */
e38719852d98638514dba23fbacf53ad11361d6avboxsync /** Size of the virtual disk. */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync /** Sector size. */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync /** Medium locked indicator. */
3598f07e0e71a448a04d478320a9ca6314160ff6vboxsyncDECLINLINE(void) mmcLBA2MSF(uint8_t *pbBuf, uint32_t iLBA)
8ab60c04baaf509b2aaae2a260adaf1281aaac03vboxsyncDECLINLINE(uint32_t) mmcMSF2LBA(const uint8_t *pbBuf)
85c594c1140f082dd862abde9dc7825137a3d51avboxsync/* Fabricate normal TOC information. */
85c594c1140f082dd862abde9dc7825137a3d51avboxsyncstatic int mmcReadTOCNormal(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq, uint16_t cbMaxTransfer, bool fMSF)
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync return vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync *q++ = 0; /* reserved */
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync *q++ = 0; /* reserved */
98da2c2cca8786e117ad93a31c6b2c6c1c3cdc78vboxsync *q++ = 0; /* reserved */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync /* sector 0 */
fde449f361029c75f9bf28f145bd1ba7b36a9c77vboxsync /* lead out track */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync *q++ = 0; /* reserved */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync *q++ = 0; /* reserved */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync *q++ = 0; /* reserved */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, cbMaxTransfer);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync return vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync/* Fabricate session information. */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsyncstatic int mmcReadTOCMulti(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq, uint16_t cbMaxTransfer, bool fMSF)
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync /* multi session: only a single session defined */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pbBuf[2] = 0x01; /* first complete session number */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pbBuf[3] = 0x01; /* last complete session number */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pbBuf[6] = 1; /* first track in last complete session */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync /* sector 0 */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync return vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pVScsiLunMmc->cbSector = 2048; /* Default to 2K sectors. */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pVScsiLunMmc->cSectors = cbDisk / pVScsiLunMmc->cbSector;
85c594c1140f082dd862abde9dc7825137a3d51avboxsyncstatic int vscsiLunMmcDestroy(PVSCSILUNINT pVScsiLun)
85c594c1140f082dd862abde9dc7825137a3d51avboxsync PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
85c594c1140f082dd862abde9dc7825137a3d51avboxsyncstatic int vscsiLunMmcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync VSCSIIOREQTXDIR enmTxDir = VSCSIIOREQTXDIR_INVALID;
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync * GET CONFIGURATION, GET EVENT/STATUS NOTIFICATION, INQUIRY, and REQUEST SENSE commands
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync * operate even when a unit attention condition exists for initiator; every other command
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync * needs to report CHECK CONDITION in that case.
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync if (!pVScsiLunMmc->Core.fReady && uCmd != SCSI_INQUIRY)
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync * A note on media changes: As long as a medium is not present, the unit remains in
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync * the 'not ready' state. Technically the unit becomes 'ready' soon after a medium
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync * is inserted; however, we internally keep the 'not ready' state until we've had
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync * a chance to report the UNIT ATTENTION status indicating a media change.
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_UNIT_ATTENTION,
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_NOT_READY,
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync Assert(!pVScsiLunMmc->Core.fReady); /* Only should get here if LUN isn't ready. */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT, 0x00);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
85c594c1140f082dd862abde9dc7825137a3d51avboxsync ScsiInquiryReply.u5PeripheralDeviceType = SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_CD_DVD;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync ScsiInquiryReply.u3PeripheralQualifier = SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED;
e38719852d98638514dba23fbacf53ad11361d6avboxsync ScsiInquiryReply.u3AnsiVersion = 0x05; /* MMC-?? compliant */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync ScsiInquiryReply.fCmdQue = 1; /* Command queuing supported. */
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync vscsiPadStr(ScsiInquiryReply.achVendorId, "VBOX", 8);
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync vscsiPadStr(ScsiInquiryReply.achProductId, "CD-ROM", 16);
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync vscsiPadStr(ScsiInquiryReply.achProductLevel, "1.0", 4);
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * If sector size exceeds the maximum value that is
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * able to be stored in 4 bytes return 0xffffffff in this field
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync /* @todo: implement!! */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync cSectorTransfer = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync cSectorTransfer = vscsiBE2HU32(&pVScsiReq->pbCDB[6]);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync cSectorTransfer = vscsiBE2HU32(&pVScsiReq->pbCDB[10]);
11a862be79fe123488bccca60c06e92cdbfec6e8vboxsync /* We do not implement an echo buffer. */
11a862be79fe123488bccca60c06e92cdbfec6e8vboxsync RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
1c8130d3c423590046a8ed4f3059de38ac5dcc14vboxsync rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync uint16_t cbMax = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
if (uSubPageCode == 0)
aReply[0] = 0;
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00); /* Don't know if this is correct */
case SCSI_READ_TOC_PMA_ATIP:
bool fMSF;
switch (format)
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
//AssertMsgFailed(("Command %#x [%s] not implemented\n", pVScsiReq->pbCDB[0], SCSICmdText(pVScsiReq->pbCDB[0])));
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE, 0x00);
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR, 0x00);
else if (!cSectorTransfer)
return rc;
sizeof(VSCSILUNMMC),