/* $Id$ */
/** @file
*/
/*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include "VSCSIInternal.h"
/**
* MMC LUN instance
*/
typedef struct VSCSILUNMMC
{
/** Core LUN structure */
/** Size of the virtual disk. */
/** Sector size. */
/** Medium locked indicator. */
bool fLocked;
{
iLBA += 150;
}
{
}
/* Fabricate normal TOC information. */
static int mmcReadTOCNormal(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq, uint16_t cbMaxTransfer, bool fMSF)
{
uint8_t *q;
{
return vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
}
q = pbBuf + 2;
*q++ = 1; /* first session */
*q++ = 1; /* last session */
if (iStartTrack <= 1)
{
*q++ = 0; /* reserved */
*q++ = 0x14; /* ADR, CONTROL */
*q++ = 1; /* track number */
*q++ = 0; /* reserved */
if (fMSF)
{
*q++ = 0; /* reserved */
mmcLBA2MSF(q, 0);
q += 3;
}
else
{
/* sector 0 */
vscsiH2BEU32(q, 0);
q += 4;
}
}
/* lead out track */
*q++ = 0; /* reserved */
*q++ = 0x14; /* ADR, CONTROL */
*q++ = 0xaa; /* track number */
*q++ = 0; /* reserved */
if (fMSF)
{
*q++ = 0; /* reserved */
q += 3;
}
else
{
q += 4;
}
if (cbSize < cbMaxTransfer)
}
/* Fabricate session information. */
static int mmcReadTOCMulti(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq, uint16_t cbMaxTransfer, bool fMSF)
{
/* multi session: only a single session defined */
if (fMSF)
{
}
else
{
/* sector 0 */
}
}
{
if (RT_SUCCESS(rc))
return rc;
}
{
return VINF_SUCCESS;
}
{
/*
* operate even when a unit attention condition exists for initiator; every other command
* needs to report CHECK CONDITION in that case.
*/
{
/*
* A note on media changes: As long as a medium is not present, the unit remains in
* the 'not ready' state. Technically the unit becomes 'ready' soon after a medium
* is inserted; however, we internally keep the 'not ready' state until we've had
* a chance to report the UNIT ATTENTION status indicating a media change.
*/
{
SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED, 0x00);
}
else
SCSI_ASC_MEDIUM_NOT_PRESENT, 0x00);
}
else
{
switch (uCmd)
{
case SCSI_TEST_UNIT_READY:
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT, 0x00);
break;
case SCSI_INQUIRY:
{
break;
}
case SCSI_READ_CAPACITY:
{
/*
* If sector size exceeds the maximum value that is
* able to be stored in 4 bytes return 0xffffffff in this field
*/
else
break;
}
case SCSI_MODE_SENSE_6:
{
bool fValid = false;
{
fValid = true;
} else if (uModePage == 0) {
fValid = true;
}
/* Querying unknown pages must fail. */
if (fValid) {
} else {
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
}
break;
}
case SCSI_MODE_SELECT_6:
{
/* @todo: implement!! */
break;
}
case SCSI_READ_6:
{
break;
}
case SCSI_READ_10:
{
break;
}
case SCSI_READ_12:
{
break;
}
case SCSI_READ_16:
{
break;
}
case SCSI_READ_BUFFER:
{
switch (uDataMode)
{
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x0a:
break;
case 0x0b:
{
/* We do not implement an echo buffer. */
break;
}
case 0x1a:
case 0x1c:
break;
default:
AssertMsgFailed(("Invalid data mode\n"));
}
break;
}
case SCSI_VERIFY_10:
case SCSI_START_STOP_UNIT:
{
break;
}
case SCSI_LOG_SENSE:
{
switch (uPageCode)
{
case 0x00:
{
if (uSubPageCode == 0)
{
aReply[0] = 0;
aReply[1] = 0;
aReply[2] = 0;
aReply[3] = 0;
break;
}
}
default:
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
}
break;
}
{
{
{
/* Leave the rest 0 */
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;
}
{
break;
}
case SCSI_READ_TOC_PMA_ATIP:
{
bool fMSF;
switch (format)
{
case 0x00:
break;
case 0x01:
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",
{
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_LOGICAL_BLOCK_OOR, 0x00);
}
else if (!cSectorTransfer)
{
/* A 0 transfer length is not an error. */
}
else
{
/* Enqueue new I/O request */
}
}
else /* Request completed */
return rc;
}
{
/** enmLunType */
/** pcszDescName */
"MMC",
/** cbLun */
sizeof(VSCSILUNMMC),
/** pfnVScsiLunInit */
/** pfnVScsiLunDestroy */
/** pfnVScsiLunReqProcess */
};