VSCSILunSbc.cpp revision 9eca783c14ba1d857aff787799d612ade35e2d03
/* $Id$ */
/** @file
* Virtual SCSI driver: SBC LUN implementation (hard disks)
*/
/*
* 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 *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_VSCSI
#include "VSCSIInternal.h"
/** Maximum of amount of LBAs to unmap with one command. */
/**
* SBC LUN instance
*/
typedef struct VSCSILUNSBC
{
/** Core LUN structure */
/** Size of the virtual disk. */
/** VPD page pool. */
} VSCSILUNSBC;
/** Pointer to a SBC LUN instance */
typedef VSCSILUNSBC *PVSCSILUNSBC;
{
int rc = VINF_SUCCESS;
int cVpdPages = 0;
if (RT_SUCCESS(rc))
if (RT_SUCCESS(rc))
/* Create device identification page - mandatory. */
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
/** @todo: Not conforming to the SPC spec but Solaris needs at least a stub to work. */
cVpdPages++;
}
}
if ( RT_SUCCESS(rc)
{
/* Create the page and fill it. */
if (RT_SUCCESS(rc))
{
pBlkPage->u8MaxCmpWriteLength = 0;
pBlkPage->u16OptTrfLengthGran = 0;
pBlkPage->u32MaxTrfLength = 0;
pBlkPage->u32OptTrfLength = 0;
pBlkPage->u32MaxPreXdTrfLength = 0;
cVpdPages++;
}
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
pBlkProvPage->fLBPU = true;
cVpdPages++;
}
}
}
if ( RT_SUCCESS(rc)
{
/* Create the page and fill it. */
rc = vscsiVpdPagePoolAllocNewPage(&pVScsiLunSbc->VpdPagePool, VSCSI_VPD_BLOCK_CHARACTERISTICS_NUMBER,
if (RT_SUCCESS(rc))
{
pBlkPage->u16MediumRotationRate = RT_H2BE_U16(VSCSI_VPD_BLOCK_CHARACT_MEDIUM_ROTATION_RATE_NON_ROTATING);
cVpdPages++;
}
}
if ( RT_SUCCESS(rc)
&& cVpdPages)
{
if (RT_SUCCESS(rc))
{
unsigned idxVpdPage = 0;
{
}
}
}
/* For SBC LUNs, there will be no ready state transitions. */
return rc;
}
{
return VINF_SUCCESS;
}
{
int rc = VINF_SUCCESS;
int rcReq = SCSI_STATUS_OK;
uint32_t cSectorTransfer = 0;
{
case SCSI_INQUIRY:
{
/* Check for EVPD bit. */
{
{
SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
rc = VINF_SUCCESS;
}
else
}
SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
else
{
}
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:
{
{
}
break;
}
case SCSI_MODE_SELECT_6:
{
/* Copy the parameters. */
/* Handle short LOGICAL BLOCK LENGTH parameter. */
&& cbList >= 12
{
{
break;
}
}
/* Fail any other requests. */
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
break;
}
case SCSI_READ_6:
{
break;
}
case SCSI_READ_10:
{
break;
}
case SCSI_READ_12:
{
break;
}
case SCSI_READ_16:
{
break;
}
case SCSI_WRITE_6:
{
break;
}
case SCSI_WRITE_10:
{
break;
}
case SCSI_WRITE_12:
{
break;
}
case SCSI_WRITE_16:
{
break;
}
case SCSI_SYNCHRONIZE_CACHE:
{
break; /* Handled below */
}
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;
}
case SCSI_UNMAP:
{
{
/* Copy the header. */
/* Using the anchor bit is not supported. */
&& cbList >= 8)
{
if (cBlkDesc)
{
if (paRanges)
{
for (unsigned i = 0; i < cBlkDesc; i++)
{
{
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
break;
}
}
if (rcReq == SCSI_STATUS_OK)
}
else /* Out of memory. */
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_HARDWARE_ERROR, SCSI_ASC_SYSTEM_RESOURCE_FAILURE,
}
else /* No block descriptors is not an error condition. */
}
else /* Invalid CDB. */
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
}
else
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_ILLEGAL_OPCODE, 0x00);
break;
}
default:
//AssertMsgFailed(("Command %#x [%s] not implemented\n", pRequest->pbCDB[0], SCSICmdText(pRequest->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 */
if ( ( enmTxDir == VSCSIIOREQTXDIR_WRITE
|| enmTxDir == VSCSIIOREQTXDIR_FLUSH)
rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_DATA_PROTECT, SCSI_ASC_WRITE_PROTECTED, 0x00);
else
}
}
{
/* Enqueue flush */
}
return rc;
}
{
/** enmLunType */
/** pcszDescName */
"SBC",
/** cbLun */
sizeof(VSCSILUNSBC),
/** pfnVScsiLunInit */
/** pfnVScsiLunDestroy */
/** pfnVScsiLunReqProcess */
};