VSCSILunMmc.cpp revision a9205f11b268f45a18a89049148ff266bcf687a3
083dd76e9fd7a829b1ed67ffc9003276643e7db1vboxsync/* $Id$ */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync/** @file
083dd76e9fd7a829b1ed67ffc9003276643e7db1vboxsync * Virtual SCSI driver: MMC LUN implementation (CD/DVD-ROM)
85c594c1140f082dd862abde9dc7825137a3d51avboxsync */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync/*
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2006-2011 Oracle Corporation
85c594c1140f082dd862abde9dc7825137a3d51avboxsync *
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
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync/*******************************************************************************
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync* Header Files *
85c594c1140f082dd862abde9dc7825137a3d51avboxsync*******************************************************************************/
85c594c1140f082dd862abde9dc7825137a3d51avboxsync#define LOG_GROUP LOG_GROUP_VSCSI
85c594c1140f082dd862abde9dc7825137a3d51avboxsync#include <VBox/log.h>
85c594c1140f082dd862abde9dc7825137a3d51avboxsync#include <VBox/err.h>
85c594c1140f082dd862abde9dc7825137a3d51avboxsync#include <VBox/types.h>
85c594c1140f082dd862abde9dc7825137a3d51avboxsync#include <VBox/vscsi.h>
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync#include <iprt/assert.h>
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync#include <iprt/mem.h>
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync#include <iprt/string.h>
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync#include "VSCSIInternal.h"
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync/**
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync * MMC LUN instance
b29e03c9044019d9c77222336e8f8616052824f5vboxsync */
87b2fb3f8283472ba7010aedbf2b4dc12302155cvboxsynctypedef struct VSCSILUNMMC
87b2fb3f8283472ba7010aedbf2b4dc12302155cvboxsync{
11a862be79fe123488bccca60c06e92cdbfec6e8vboxsync /** Core LUN structure */
87b2fb3f8283472ba7010aedbf2b4dc12302155cvboxsync VSCSILUNINT Core;
e38719852d98638514dba23fbacf53ad11361d6avboxsync /** Size of the virtual disk. */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync uint64_t cSectors;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync /** Sector size. */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync uint32_t cbSector;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync /** Medium locked indicator. */
463d00559e51c6e08ccc9f5a77d2ee6d122b6e8cvboxsync bool fLocked;
463d00559e51c6e08ccc9f5a77d2ee6d122b6e8cvboxsync} VSCSILUNMMC, *PVSCSILUNMMC;
463d00559e51c6e08ccc9f5a77d2ee6d122b6e8cvboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
3598f07e0e71a448a04d478320a9ca6314160ff6vboxsyncDECLINLINE(void) mmcLBA2MSF(uint8_t *pbBuf, uint32_t iLBA)
083dd76e9fd7a829b1ed67ffc9003276643e7db1vboxsync{
85c594c1140f082dd862abde9dc7825137a3d51avboxsync iLBA += 150;
463d00559e51c6e08ccc9f5a77d2ee6d122b6e8cvboxsync pbBuf[0] = (iLBA / 75) / 60;
463d00559e51c6e08ccc9f5a77d2ee6d122b6e8cvboxsync pbBuf[1] = (iLBA / 75) % 60;
463d00559e51c6e08ccc9f5a77d2ee6d122b6e8cvboxsync pbBuf[2] = iLBA % 75;
463d00559e51c6e08ccc9f5a77d2ee6d122b6e8cvboxsync}
463d00559e51c6e08ccc9f5a77d2ee6d122b6e8cvboxsync
8ab60c04baaf509b2aaae2a260adaf1281aaac03vboxsyncDECLINLINE(uint32_t) mmcMSF2LBA(const uint8_t *pbBuf)
8ab60c04baaf509b2aaae2a260adaf1281aaac03vboxsync{
8ab60c04baaf509b2aaae2a260adaf1281aaac03vboxsync return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2];
463d00559e51c6e08ccc9f5a77d2ee6d122b6e8cvboxsync}
6edb4183bc898fddcd0987b6c5c3903b8246fe45vboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync/* Fabricate normal TOC information. */
85c594c1140f082dd862abde9dc7825137a3d51avboxsyncstatic int mmcReadTOCNormal(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq, uint16_t cbMaxTransfer, bool fMSF)
85c594c1140f082dd862abde9dc7825137a3d51avboxsync{
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync uint8_t aReply[32];
fde449f361029c75f9bf28f145bd1ba7b36a9c77vboxsync uint8_t *pbBuf = aReply;
fde449f361029c75f9bf28f145bd1ba7b36a9c77vboxsync uint8_t *q;
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync uint8_t iStartTrack;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync uint32_t cbSize;
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync iStartTrack = pVScsiReq->pbCDB[6];
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync if (iStartTrack > 1 && iStartTrack != 0xaa)
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync {
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync return vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync }
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync q = pbBuf + 2;
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync *q++ = 1; /* first session */
4ad933b349952e43d0b6ce21b3f5e2833ca04e85vboxsync *q++ = 1; /* last session */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync if (iStartTrack <= 1)
85c594c1140f082dd862abde9dc7825137a3d51avboxsync {
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync *q++ = 0; /* reserved */
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync *q++ = 0x14; /* ADR, CONTROL */
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync *q++ = 1; /* track number */
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync *q++ = 0; /* reserved */
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync if (fMSF)
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync {
98da2c2cca8786e117ad93a31c6b2c6c1c3cdc78vboxsync *q++ = 0; /* reserved */
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync mmcLBA2MSF(q, 0);
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync q += 3;
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync }
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync else
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync {
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync /* sector 0 */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync vscsiH2BEU32(q, 0);
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync q += 4;
fde449f361029c75f9bf28f145bd1ba7b36a9c77vboxsync }
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync }
fde449f361029c75f9bf28f145bd1ba7b36a9c77vboxsync /* lead out track */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync *q++ = 0; /* reserved */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync *q++ = 0x14; /* ADR, CONTROL */
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync *q++ = 0xaa; /* track number */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync *q++ = 0; /* reserved */
fde449f361029c75f9bf28f145bd1ba7b36a9c77vboxsync if (fMSF)
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync {
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync *q++ = 0; /* reserved */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync mmcLBA2MSF(q, pVScsiLunMmc->cSectors);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync q += 3;
fde449f361029c75f9bf28f145bd1ba7b36a9c77vboxsync }
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync else
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync {
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync vscsiH2BEU32(q, pVScsiLunMmc->cSectors);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync q += 4;
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync }
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync cbSize = q - pbBuf;
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync Assert(cbSize <= sizeof(aReply));
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync vscsiH2BEU16(pbBuf, cbSize - 2);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync if (cbSize < cbMaxTransfer)
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync cbMaxTransfer = cbSize;
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, cbMaxTransfer);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync return vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync}
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync/* Fabricate session information. */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsyncstatic int mmcReadTOCMulti(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq, uint16_t cbMaxTransfer, bool fMSF)
85c594c1140f082dd862abde9dc7825137a3d51avboxsync{
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync uint8_t aReply[32];
e38719852d98638514dba23fbacf53ad11361d6avboxsync uint8_t *pbBuf = aReply;
e38719852d98638514dba23fbacf53ad11361d6avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync /* multi session: only a single session defined */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync memset(pbBuf, 0, 12);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pbBuf[1] = 0x0a;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pbBuf[2] = 0x01; /* first complete session number */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pbBuf[3] = 0x01; /* last complete session number */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pbBuf[5] = 0x14; /* ADR, CONTROL */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pbBuf[6] = 1; /* first track in last complete session */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync if (fMSF)
85c594c1140f082dd862abde9dc7825137a3d51avboxsync {
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pbBuf[8] = 0; /* reserved */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync mmcLBA2MSF(pbBuf + 8, 0);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync }
85c594c1140f082dd862abde9dc7825137a3d51avboxsync else
85c594c1140f082dd862abde9dc7825137a3d51avboxsync {
85c594c1140f082dd862abde9dc7825137a3d51avboxsync /* sector 0 */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync vscsiH2BEU32(pbBuf + 8, 0);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync }
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, 12);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync return vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync}
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsyncstatic int vscsiLunMmcInit(PVSCSILUNINT pVScsiLun)
85c594c1140f082dd862abde9dc7825137a3d51avboxsync{
85c594c1140f082dd862abde9dc7825137a3d51avboxsync PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync uint64_t cbDisk = 0;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync int rc = VINF_SUCCESS;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pVScsiLunMmc->cbSector = 2048; /* Default to 2K sectors. */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync rc = vscsiLunMediumGetSize(pVScsiLun, &cbDisk);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync if (RT_SUCCESS(rc))
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pVScsiLunMmc->cSectors = cbDisk / pVScsiLunMmc->cbSector;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync return rc;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync}
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsyncstatic int vscsiLunMmcDestroy(PVSCSILUNINT pVScsiLun)
85c594c1140f082dd862abde9dc7825137a3d51avboxsync{
85c594c1140f082dd862abde9dc7825137a3d51avboxsync PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync return VINF_SUCCESS;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync}
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsyncstatic int vscsiLunMmcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
85c594c1140f082dd862abde9dc7825137a3d51avboxsync{
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync VSCSIIOREQTXDIR enmTxDir = VSCSIIOREQTXDIR_INVALID;
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync uint64_t uLbaStart = 0;
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync uint32_t cSectorTransfer = 0;
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync int rc = VINF_SUCCESS;
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync int rcReq = SCSI_STATUS_OK;
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync unsigned uCmd = pVScsiReq->pbCDB[0];
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync /*
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 */
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync if (!pVScsiLunMmc->Core.fReady && uCmd != SCSI_INQUIRY)
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync {
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync /*
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 */
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync if (pVScsiLunMmc->Core.fMediaPresent)
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync {
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_UNIT_ATTENTION,
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED, 0x00);
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync pVScsiLunMmc->Core.fReady = true;
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync }
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync else
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_NOT_READY,
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync SCSI_ASC_MEDIUM_NOT_PRESENT, 0x00);
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync }
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync else
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync {
999b9efb1c9a95fee642550c525ca0cf7c6f07b5vboxsync switch (uCmd)
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync {
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync case SCSI_TEST_UNIT_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);
fde449f361029c75f9bf28f145bd1ba7b36a9c77vboxsync break;
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync
fde449f361029c75f9bf28f145bd1ba7b36a9c77vboxsync case SCSI_INQUIRY:
6edb4183bc898fddcd0987b6c5c3903b8246fe45vboxsync {
fde449f361029c75f9bf28f145bd1ba7b36a9c77vboxsync SCSIINQUIRYDATA ScsiInquiryReply;
fde449f361029c75f9bf28f145bd1ba7b36a9c77vboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync memset(&ScsiInquiryReply, 0, sizeof(ScsiInquiryReply));
6edb4183bc898fddcd0987b6c5c3903b8246fe45vboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync ScsiInquiryReply.cbAdditional = 31;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync ScsiInquiryReply.fRMB = 1; /* Removable. */
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 ScsiInquiryReply.fWBus16 = 1;
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync vscsiPadStr(ScsiInquiryReply.achVendorId, "VBOX", 8);
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync vscsiPadStr(ScsiInquiryReply.achProductId, "CD-ROM", 16);
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync vscsiPadStr(ScsiInquiryReply.achProductLevel, "1.0", 4);
3598f07e0e71a448a04d478320a9ca6314160ff6vboxsync
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, (uint8_t *)&ScsiInquiryReply, sizeof(SCSIINQUIRYDATA));
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync break;
3598f07e0e71a448a04d478320a9ca6314160ff6vboxsync }
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync case SCSI_READ_CAPACITY:
eb5d68001efb9346c3341aa46f2871b973b47107vboxsync {
3598f07e0e71a448a04d478320a9ca6314160ff6vboxsync uint8_t aReply[8];
85c594c1140f082dd862abde9dc7825137a3d51avboxsync memset(aReply, 0, sizeof(aReply));
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync /*
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * If sector size exceeds the maximum value that is
85c594c1140f082dd862abde9dc7825137a3d51avboxsync * able to be stored in 4 bytes return 0xffffffff in this field
85c594c1140f082dd862abde9dc7825137a3d51avboxsync */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync if (pVScsiLunMmc->cSectors > UINT32_C(0xffffffff))
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync vscsiH2BEU32(aReply, UINT32_C(0xffffffff));
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync else
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync vscsiH2BEU32(aReply, pVScsiLunMmc->cSectors - 1);
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync vscsiH2BEU32(&aReply[4], pVScsiLunMmc->cbSector);
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync break;
fde449f361029c75f9bf28f145bd1ba7b36a9c77vboxsync }
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync case SCSI_MODE_SENSE_6:
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync {
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync uint8_t uModePage = pVScsiReq->pbCDB[2] & 0x3f;
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync uint8_t aReply[24];
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync uint8_t *pu8ReplyPos;
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync memset(aReply, 0, sizeof(aReply));
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync aReply[0] = 4; /* Reply length 4. */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync aReply[1] = 0; /* Default media type. */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync aReply[2] = RT_BIT(4); /* Caching supported. */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync aReply[3] = 0; /* Block descriptor length. */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync pu8ReplyPos = aReply + 4;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync if ((uModePage == 0x08) || (uModePage == 0x3f))
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync {
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync memset(pu8ReplyPos, 0, 20);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync *pu8ReplyPos++ = 0x08; /* Page code. */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync *pu8ReplyPos++ = 0x12; /* Size of the page. */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync *pu8ReplyPos++ = 0x4; /* Write cache enabled. */
85c594c1140f082dd862abde9dc7825137a3d51avboxsync }
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync break;
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync }
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync case SCSI_MODE_SELECT_6:
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync {
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync /* @todo: implement!! */
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync break;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync }
85c594c1140f082dd862abde9dc7825137a3d51avboxsync case SCSI_READ_6:
85c594c1140f082dd862abde9dc7825137a3d51avboxsync {
85c594c1140f082dd862abde9dc7825137a3d51avboxsync enmTxDir = VSCSIIOREQTXDIR_READ;
e38719852d98638514dba23fbacf53ad11361d6avboxsync uLbaStart = ((uint64_t) pVScsiReq->pbCDB[3]
85c594c1140f082dd862abde9dc7825137a3d51avboxsync | (pVScsiReq->pbCDB[2] << 8)
85c594c1140f082dd862abde9dc7825137a3d51avboxsync | ((pVScsiReq->pbCDB[1] & 0x1f) << 16));
e38719852d98638514dba23fbacf53ad11361d6avboxsync cSectorTransfer = pVScsiReq->pbCDB[4];
85c594c1140f082dd862abde9dc7825137a3d51avboxsync break;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync }
85c594c1140f082dd862abde9dc7825137a3d51avboxsync case SCSI_READ_10:
e38719852d98638514dba23fbacf53ad11361d6avboxsync {
85c594c1140f082dd862abde9dc7825137a3d51avboxsync enmTxDir = VSCSIIOREQTXDIR_READ;
e38719852d98638514dba23fbacf53ad11361d6avboxsync uLbaStart = vscsiBE2HU32(&pVScsiReq->pbCDB[2]);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync cSectorTransfer = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync break;
0c1bdc5adae416967cb64e09f8ec81a5b77fe31dvboxsync }
85c594c1140f082dd862abde9dc7825137a3d51avboxsync case SCSI_READ_12:
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync {
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync enmTxDir = VSCSIIOREQTXDIR_READ;
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync uLbaStart = vscsiBE2HU32(&pVScsiReq->pbCDB[2]);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync cSectorTransfer = vscsiBE2HU32(&pVScsiReq->pbCDB[6]);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync break;
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync }
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync case SCSI_READ_16:
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync {
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync enmTxDir = VSCSIIOREQTXDIR_READ;
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync uLbaStart = vscsiBE2HU64(&pVScsiReq->pbCDB[2]);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync cSectorTransfer = vscsiBE2HU32(&pVScsiReq->pbCDB[10]);
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync break;
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync }
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync case SCSI_READ_BUFFER:
f6b7aa2d424718f1bf8ca45a37b219b986f1024bvboxsync {
85c594c1140f082dd862abde9dc7825137a3d51avboxsync uint8_t uDataMode = pVScsiReq->pbCDB[1] & 0x1f;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync switch (uDataMode)
e38719852d98638514dba23fbacf53ad11361d6avboxsync {
85c594c1140f082dd862abde9dc7825137a3d51avboxsync case 0x00:
85c594c1140f082dd862abde9dc7825137a3d51avboxsync case 0x01:
85c594c1140f082dd862abde9dc7825137a3d51avboxsync case 0x02:
85c594c1140f082dd862abde9dc7825137a3d51avboxsync case 0x03:
85c594c1140f082dd862abde9dc7825137a3d51avboxsync case 0x0a:
85c594c1140f082dd862abde9dc7825137a3d51avboxsync break;
b29e03c9044019d9c77222336e8f8616052824f5vboxsync case 0x0b:
1c8130d3c423590046a8ed4f3059de38ac5dcc14vboxsync {
1c8130d3c423590046a8ed4f3059de38ac5dcc14vboxsync uint8_t aReply[4];
1c8130d3c423590046a8ed4f3059de38ac5dcc14vboxsync
11a862be79fe123488bccca60c06e92cdbfec6e8vboxsync /* We do not implement an echo buffer. */
1c8130d3c423590046a8ed4f3059de38ac5dcc14vboxsync memset(aReply, 0, sizeof(aReply));
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync
11a862be79fe123488bccca60c06e92cdbfec6e8vboxsync RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
1c8130d3c423590046a8ed4f3059de38ac5dcc14vboxsync rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync break;
1c8130d3c423590046a8ed4f3059de38ac5dcc14vboxsync }
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync case 0x1a:
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync case 0x1c:
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync break;
1c8130d3c423590046a8ed4f3059de38ac5dcc14vboxsync default:
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync AssertMsgFailed(("Invalid data mode\n"));
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync }
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync break;
463d00559e51c6e08ccc9f5a77d2ee6d122b6e8cvboxsync }
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync case SCSI_VERIFY_10:
463d00559e51c6e08ccc9f5a77d2ee6d122b6e8cvboxsync case SCSI_START_STOP_UNIT:
34822e8b7d00c04a0bc98c0d1a565a00d9bb1fd9vboxsync {
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync break;
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync }
507ebf9b3b77c84000a55645867db6617b5324bcvboxsync case SCSI_LOG_SENSE:
85c594c1140f082dd862abde9dc7825137a3d51avboxsync {
85c594c1140f082dd862abde9dc7825137a3d51avboxsync uint16_t cbMax = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
85c594c1140f082dd862abde9dc7825137a3d51avboxsync uint8_t uPageCode = pVScsiReq->pbCDB[2] & 0x3f;
85c594c1140f082dd862abde9dc7825137a3d51avboxsync uint8_t uSubPageCode = pVScsiReq->pbCDB[3];
85c594c1140f082dd862abde9dc7825137a3d51avboxsync
85c594c1140f082dd862abde9dc7825137a3d51avboxsync switch (uPageCode)
85c594c1140f082dd862abde9dc7825137a3d51avboxsync {
85c594c1140f082dd862abde9dc7825137a3d51avboxsync case 0x00:
{
if (uSubPageCode == 0)
{
uint8_t aReply[4];
aReply[0] = 0;
aReply[1] = 0;
aReply[2] = 0;
aReply[3] = 0;
RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
break;
}
}
default:
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
}
break;
}
case SCSI_SERVICE_ACTION_IN_16:
{
switch (pVScsiReq->pbCDB[1] & 0x1f)
{
case SCSI_SVC_ACTION_IN_READ_CAPACITY_16:
{
uint8_t aReply[32];
memset(aReply, 0, sizeof(aReply));
vscsiH2BEU64(aReply, pVScsiLunMmc->cSectors - 1);
vscsiH2BEU32(&aReply[8], pVScsiLunMmc->cbSector);
/* Leave the rest 0 */
RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
break;
}
default:
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00); /* Don't know if this is correct */
}
break;
}
case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
{
pVScsiLunMmc->fLocked = pVScsiReq->pbCDB[4] & 1;
rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
break;
}
case SCSI_READ_TOC_PMA_ATIP:
{
uint8_t format;
uint16_t cbMax;
bool fMSF;
format = pVScsiReq->pbCDB[2] & 0x0f;
cbMax = vscsiBE2HU16(&pVScsiReq->pbCDB[7]);
fMSF = (pVScsiReq->pbCDB[1] >> 1) & 1;
switch (format)
{
case 0x00:
mmcReadTOCNormal(pVScsiLun, pVScsiReq, cbMax, fMSF);
break;
case 0x01:
mmcReadTOCMulti(pVScsiLun, pVScsiReq, cbMax, fMSF);
break;
default:
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
}
break;
}
default:
//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);
}
}
if (enmTxDir != VSCSIIOREQTXDIR_INVALID)
{
LogFlow(("%s: uLbaStart=%llu cSectorTransfer=%u\n",
__FUNCTION__, uLbaStart, cSectorTransfer));
if (RT_UNLIKELY(uLbaStart + cSectorTransfer > pVScsiLunMmc->cSectors))
{
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR, 0x00);
vscsiDeviceReqComplete(pVScsiLun->pVScsiDevice, pVScsiReq, rcReq, false, VINF_SUCCESS);
}
else if (!cSectorTransfer)
{
/* A 0 transfer length is not an error. */
rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
vscsiDeviceReqComplete(pVScsiLun->pVScsiDevice, pVScsiReq, rcReq, false, VINF_SUCCESS);
}
else
{
/* Enqueue new I/O request */
rc = vscsiIoReqTransferEnqueue(pVScsiLun, pVScsiReq, enmTxDir,
uLbaStart * pVScsiLunMmc->cbSector,
cSectorTransfer * pVScsiLunMmc->cbSector);
}
}
else /* Request completed */
vscsiDeviceReqComplete(pVScsiLun->pVScsiDevice, pVScsiReq, rcReq, false, VINF_SUCCESS);
return rc;
}
VSCSILUNDESC g_VScsiLunTypeMmc =
{
/** enmLunType */
VSCSILUNTYPE_MMC,
/** pcszDescName */
"MMC",
/** cbLun */
sizeof(VSCSILUNMMC),
/** pfnVScsiLunInit */
vscsiLunMmcInit,
/** pfnVScsiLunDestroy */
vscsiLunMmcDestroy,
/** pfnVScsiLunReqProcess */
vscsiLunMmcReqProcess
};