summaryrefslogtreecommitdiff
path: root/src/VBox/Devices/Storage/VSCSI
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/Storage/VSCSI')
-rw-r--r--src/VBox/Devices/Storage/VSCSI/VSCSIDevice.cpp10
-rw-r--r--src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h34
-rw-r--r--src/VBox/Devices/Storage/VSCSI/VSCSILun.cpp44
-rw-r--r--src/VBox/Devices/Storage/VSCSI/VSCSILunMmc.cpp186
-rw-r--r--src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp65
-rw-r--r--src/VBox/Devices/Storage/VSCSI/VSCSISense.cpp8
6 files changed, 326 insertions, 21 deletions
diff --git a/src/VBox/Devices/Storage/VSCSI/VSCSIDevice.cpp b/src/VBox/Devices/Storage/VSCSI/VSCSIDevice.cpp
index 4f300716..75f1b491 100644
--- a/src/VBox/Devices/Storage/VSCSI/VSCSIDevice.cpp
+++ b/src/VBox/Devices/Storage/VSCSI/VSCSIDevice.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * 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;
@@ -101,7 +101,11 @@ static bool vscsiDeviceReqProcess(PVSCSIDEVICEINT pVScsiDevice, PVSCSIREQINT pVS
}
case SCSI_TEST_UNIT_READY:
{
- *prcReq = vscsiReqSenseOkSet(&pVScsiDevice->VScsiSense, pVScsiReq);
+ if ( vscsiDeviceLunIsPresent(pVScsiDevice, pVScsiReq->iLun)
+ && pVScsiDevice->papVScsiLun[pVScsiReq->iLun]->fReady)
+ *prcReq = vscsiReqSenseOkSet(&pVScsiDevice->VScsiSense, pVScsiReq);
+ else
+ fProcessed = false; /* The LUN (if present) will provide details. */
break;
}
case SCSI_REQUEST_SENSE:
@@ -111,6 +115,7 @@ static bool vscsiDeviceReqProcess(PVSCSIDEVICEINT pVScsiDevice, PVSCSIREQINT pVS
*prcReq = vscsiReqSenseErrorSet(&pVScsiDevice->VScsiSense, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
else
*prcReq = vscsiReqSenseCmd(&pVScsiDevice->VScsiSense, pVScsiReq);
+ break;
}
default:
fProcessed = false;
@@ -343,4 +348,3 @@ VBOXDDU_DECL(int) VSCSIDeviceReqCreate(VSCSIDEVICE hVScsiDevice, PVSCSIREQ phVSc
return VINF_SUCCESS;
}
-
diff --git a/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h b/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h
index 4fd696b0..8e086573 100644
--- a/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h
+++ b/src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * 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;
@@ -85,6 +85,10 @@ typedef struct VSCSILUNINT
PVSCSILUNIOCALLBACKS pVScsiLunIoCallbacks;
/** Pointer to the LUN type descriptor. */
PVSCSILUNDESC pVScsiLunDesc;
+ /** Flag indicating whether LUN is ready. */
+ bool fReady;
+ /** Flag indicating media presence in LUN. */
+ bool fMediaPresent;
/** Flags of supported features. */
uint64_t fFeatures;
/** I/O request processing data */
@@ -359,6 +363,34 @@ DECLINLINE(int) vscsiLunMediumGetSize(PVSCSILUNINT pVScsiLun, uint64_t *pcbSize)
}
/**
+ * Wrapper for the get medium sector size I/O callback.
+ *
+ * @returns VBox status code.
+ * @param pVScsiLun The LUN.
+ * @param pcbSectorSize Where to store the sector size on success.
+ */
+DECLINLINE(int) vscsiLunMediumGetSectorSize(PVSCSILUNINT pVScsiLun, uint32_t *pcbSectorSize)
+{
+ return pVScsiLun->pVScsiLunIoCallbacks->pfnVScsiLunMediumGetSectorSize(pVScsiLun,
+ pVScsiLun->pvVScsiLunUser,
+ pcbSectorSize);
+}
+
+/**
+ * Wrapper for the get medium lock/unlock I/O callback.
+ *
+ * @returns VBox status code.
+ * @param pVScsiLun The LUN.
+ * @param bool The new medium lock state.
+ */
+DECLINLINE(int) vscsiLunMediumSetLock(PVSCSILUNINT pVScsiLun, bool fLocked)
+{
+ return pVScsiLun->pVScsiLunIoCallbacks->pfnVScsiLunMediumSetLock(pVScsiLun,
+ pVScsiLun->pvVScsiLunUser,
+ fLocked);
+}
+
+/**
* Wrapper for the I/O request enqueue I/O callback.
*
* @returns VBox status code.
diff --git a/src/VBox/Devices/Storage/VSCSI/VSCSILun.cpp b/src/VBox/Devices/Storage/VSCSI/VSCSILun.cpp
index 9a2f1f7c..24462db0 100644
--- a/src/VBox/Devices/Storage/VSCSI/VSCSILun.cpp
+++ b/src/VBox/Devices/Storage/VSCSI/VSCSILun.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2010 Oracle Corporation
+ * 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;
@@ -115,3 +115,45 @@ VBOXDDU_DECL(int) VSCSILunDestroy(VSCSILUN hVScsiLun)
return VINF_SUCCESS;
}
+/**
+ * Notify virtual SCSI LUN of media being mounted.
+ *
+ * @returns VBox status code.
+ * @param hVScsiLun The virtual SCSI LUN
+ * mounting the medium.
+ */
+VBOXDDU_DECL(int) VSCSILunMountNotify(VSCSILUN hVScsiLun)
+{
+ PVSCSILUNINT pVScsiLun = (PVSCSILUNINT)hVScsiLun;
+
+ LogFlowFunc(("hVScsiLun=%p\n", hVScsiLun));
+ AssertPtrReturn(pVScsiLun, VERR_INVALID_HANDLE);
+ AssertReturn(vscsiIoReqOutstandingCountGet(pVScsiLun) == 0, VERR_VSCSI_LUN_BUSY);
+
+ /* Mark the LUN as not ready so that LUN specific code can do its job. */
+ pVScsiLun->fReady = false;
+ pVScsiLun->fMediaPresent = true;
+
+ return VINF_SUCCESS;
+}
+
+/**
+ * Notify virtual SCSI LUN of media being unmounted.
+ *
+ * @returns VBox status code.
+ * @param hVScsiLun The virtual SCSI LUN
+ * mounting the medium.
+ */
+VBOXDDU_DECL(int) VSCSILunUnmountNotify(VSCSILUN hVScsiLun)
+{
+ PVSCSILUNINT pVScsiLun = (PVSCSILUNINT)hVScsiLun;
+
+ LogFlowFunc(("hVScsiLun=%p\n", hVScsiLun));
+ AssertPtrReturn(pVScsiLun, VERR_INVALID_HANDLE);
+ AssertReturn(vscsiIoReqOutstandingCountGet(pVScsiLun) == 0, VERR_VSCSI_LUN_BUSY);
+
+ pVScsiLun->fReady = false;
+ pVScsiLun->fMediaPresent = false;
+
+ return VINF_SUCCESS;
+}
diff --git a/src/VBox/Devices/Storage/VSCSI/VSCSILunMmc.cpp b/src/VBox/Devices/Storage/VSCSI/VSCSILunMmc.cpp
index 6da3833b..10330cdf 100644
--- a/src/VBox/Devices/Storage/VSCSI/VSCSILunMmc.cpp
+++ b/src/VBox/Devices/Storage/VSCSI/VSCSILunMmc.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * 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;
@@ -44,6 +44,116 @@ typedef struct VSCSILUNMMC
bool fLocked;
} VSCSILUNMMC, *PVSCSILUNMMC;
+
+DECLINLINE(void) mmcLBA2MSF(uint8_t *pbBuf, uint32_t iLBA)
+{
+ iLBA += 150;
+ pbBuf[0] = (iLBA / 75) / 60;
+ pbBuf[1] = (iLBA / 75) % 60;
+ pbBuf[2] = iLBA % 75;
+}
+
+DECLINLINE(uint32_t) mmcMSF2LBA(const uint8_t *pbBuf)
+{
+ return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2];
+}
+
+
+/* Fabricate normal TOC information. */
+static int mmcReadTOCNormal(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq, uint16_t cbMaxTransfer, bool fMSF)
+{
+ PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
+ uint8_t aReply[32];
+ uint8_t *pbBuf = aReply;
+ uint8_t *q;
+ uint8_t iStartTrack;
+ uint32_t cbSize;
+
+ iStartTrack = pVScsiReq->pbCDB[6];
+ if (iStartTrack > 1 && iStartTrack != 0xaa)
+ {
+ 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 */
+ mmcLBA2MSF(q, pVScsiLunMmc->cSectors);
+ q += 3;
+ }
+ else
+ {
+ vscsiH2BEU32(q, pVScsiLunMmc->cSectors);
+ q += 4;
+ }
+ cbSize = q - pbBuf;
+ Assert(cbSize <= sizeof(aReply));
+ vscsiH2BEU16(pbBuf, cbSize - 2);
+ if (cbSize < cbMaxTransfer)
+ cbMaxTransfer = cbSize;
+
+ RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, cbMaxTransfer);
+
+ return vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
+}
+
+/* Fabricate session information. */
+static int mmcReadTOCMulti(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq, uint16_t cbMaxTransfer, bool fMSF)
+{
+ PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
+ uint8_t aReply[32];
+ uint8_t *pbBuf = aReply;
+
+ /* multi session: only a single session defined */
+ memset(pbBuf, 0, 12);
+ pbBuf[1] = 0x0a;
+ pbBuf[2] = 0x01; /* first complete session number */
+ pbBuf[3] = 0x01; /* last complete session number */
+ pbBuf[5] = 0x14; /* ADR, CONTROL */
+ pbBuf[6] = 1; /* first track in last complete session */
+
+ if (fMSF)
+ {
+ pbBuf[8] = 0; /* reserved */
+ mmcLBA2MSF(pbBuf + 8, 0);
+ }
+ else
+ {
+ /* sector 0 */
+ vscsiH2BEU32(pbBuf + 8, 0);
+ }
+
+ RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, 12);
+
+ return vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
+}
+
static int vscsiLunMmcInit(PVSCSILUNINT pVScsiLun)
{
PVSCSILUNMMC pVScsiLunMmc = (PVSCSILUNMMC)pVScsiLun;
@@ -73,9 +183,40 @@ static int vscsiLunMmcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
uint32_t cSectorTransfer = 0;
int rc = VINF_SUCCESS;
int rcReq = SCSI_STATUS_OK;
+ unsigned uCmd = pVScsiReq->pbCDB[0];
- switch(pVScsiReq->pbCDB[0])
+ /*
+ * GET CONFIGURATION, GET EVENT/STATUS NOTIFICATION, INQUIRY, and REQUEST SENSE commands
+ * operate even when a unit attention condition exists for initiator; every other command
+ * needs to report CHECK CONDITION in that case.
+ */
+ if (!pVScsiLunMmc->Core.fReady && uCmd != SCSI_INQUIRY)
{
+ /*
+ * 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.
+ */
+ if (pVScsiLunMmc->Core.fMediaPresent)
+ {
+ rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_UNIT_ATTENTION,
+ SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED, 0x00);
+ pVScsiLunMmc->Core.fReady = true;
+ }
+ else
+ rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_NOT_READY,
+ SCSI_ASC_MEDIUM_NOT_PRESENT, 0x00);
+ }
+ else
+ {
+ switch (uCmd)
+ {
+ case SCSI_TEST_UNIT_READY:
+ Assert(!pVScsiLunMmc->Core.fReady); /* Only should get here if LUN isn't ready. */
+ rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_NOT_READY, SCSI_ASC_MEDIUM_NOT_PRESENT, 0x00);
+ break;
+
case SCSI_INQUIRY:
{
SCSIINQUIRYDATA ScsiInquiryReply;
@@ -120,6 +261,7 @@ static int vscsiLunMmcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
uint8_t uModePage = pVScsiReq->pbCDB[2] & 0x3f;
uint8_t aReply[24];
uint8_t *pu8ReplyPos;
+ bool fValid = false;
memset(aReply, 0, sizeof(aReply));
aReply[0] = 4; /* Reply length 4. */
@@ -135,10 +277,18 @@ static int vscsiLunMmcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
*pu8ReplyPos++ = 0x08; /* Page code. */
*pu8ReplyPos++ = 0x12; /* Size of the page. */
*pu8ReplyPos++ = 0x4; /* Write cache enabled. */
+ fValid = true;
+ } else if (uModePage == 0) {
+ fValid = true;
}
- RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
- rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
+ /* Querying unknown pages must fail. */
+ if (fValid) {
+ RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
+ rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
+ } else {
+ rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
+ }
break;
}
case SCSI_MODE_SELECT_6:
@@ -267,13 +417,37 @@ static int vscsiLunMmcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL:
{
pVScsiLunMmc->fLocked = pVScsiReq->pbCDB[4] & 1;
+ vscsiLunMediumSetLock(pVScsiLun, pVScsiLunMmc->fLocked);
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", pRequest->pbCDB[0], SCSICmdText(pRequest->pbCDB[0])));
+ //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)
@@ -286,7 +460,7 @@ static int vscsiLunMmcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
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)
+ else if (!cSectorTransfer)
{
/* A 0 transfer length is not an error. */
rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
diff --git a/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp b/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp
index 81b8ce25..d5a3e68f 100644
--- a/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp
+++ b/src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * 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;
@@ -32,7 +32,7 @@
#include "VSCSIInternal.h"
/** Maximum of amount of LBAs to unmap with one command. */
-#define VSCSI_UNMAP_LBAS_MAX ((10*_1M) / 512)
+#define VSCSI_UNMAP_LBAS_MAX(a_cbSector) ((10*_1M) / a_cbSector)
/**
* SBC LUN instance
@@ -41,6 +41,8 @@ typedef struct VSCSILUNSBC
{
/** Core LUN structure */
VSCSILUNINT Core;
+ /** Sector size of the medium. */
+ uint32_t cbSector;
/** Size of the virtual disk. */
uint64_t cSectors;
/** VPD page pool. */
@@ -56,9 +58,13 @@ static int vscsiLunSbcInit(PVSCSILUNINT pVScsiLun)
int rc = VINF_SUCCESS;
int cVpdPages = 0;
- rc = vscsiLunMediumGetSize(pVScsiLun, &cbDisk);
+ rc = vscsiLunMediumGetSectorSize(pVScsiLun, &pVScsiLunSbc->cbSector);
if (RT_SUCCESS(rc))
- pVScsiLunSbc->cSectors = cbDisk / 512; /* Fixed sector size */
+ {
+ rc = vscsiLunMediumGetSize(pVScsiLun, &cbDisk);
+ if (RT_SUCCESS(rc))
+ pVScsiLunSbc->cSectors = cbDisk / pVScsiLunSbc->cbSector;
+ }
if (RT_SUCCESS(rc))
rc = vscsiVpdPagePoolInit(&pVScsiLunSbc->VpdPagePool);
@@ -99,7 +105,7 @@ static int vscsiLunSbcInit(PVSCSILUNINT pVScsiLun)
pBlkPage->u32MaxTrfLength = 0;
pBlkPage->u32OptTrfLength = 0;
pBlkPage->u32MaxPreXdTrfLength = 0;
- pBlkPage->u32MaxUnmapLbaCount = RT_H2BE_U32(VSCSI_UNMAP_LBAS_MAX);
+ pBlkPage->u32MaxUnmapLbaCount = RT_H2BE_U32(VSCSI_UNMAP_LBAS_MAX(pVScsiLunSbc->cbSector));
pBlkPage->u32MaxUnmapBlkDescCount = UINT32_C(0xffffffff);
pBlkPage->u32OptUnmapGranularity = 0;
pBlkPage->u32UnmapGranularityAlignment = 0;
@@ -167,6 +173,9 @@ static int vscsiLunSbcInit(PVSCSILUNINT pVScsiLun)
}
}
+ /* For SBC LUNs, there will be no ready state transitions. */
+ pVScsiLunSbc->Core.fReady = true;
+
return rc;
}
@@ -242,7 +251,7 @@ static int vscsiLunSbcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
vscsiH2BEU32(aReply, UINT32_C(0xffffffff));
else
vscsiH2BEU32(aReply, pVScsiLunSbc->cSectors - 1);
- vscsiH2BEU32(&aReply[4], 512);
+ vscsiH2BEU32(&aReply[4], pVScsiLunSbc->cbSector);
RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
break;
@@ -252,6 +261,7 @@ static int vscsiLunSbcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
uint8_t uModePage = pVScsiReq->pbCDB[2] & 0x3f;
uint8_t aReply[24];
uint8_t *pu8ReplyPos;
+ bool fValid = false;
memset(aReply, 0, sizeof(aReply));
aReply[0] = 4; /* Reply length 4. */
@@ -270,10 +280,47 @@ static int vscsiLunSbcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
*pu8ReplyPos++ = 0x08; /* Page code. */
*pu8ReplyPos++ = 0x12; /* Size of the page. */
*pu8ReplyPos++ = 0x4; /* Write cache enabled. */
+ fValid = true;
+ } else if (uModePage == 0) {
+ fValid = true;
}
- RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
- rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
+ /* Querying unknown pages must fail. */
+ if (fValid) {
+ RTSgBufCopyFromBuf(&pVScsiReq->SgBuf, aReply, sizeof(aReply));
+ rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
+ } else {
+ rcReq = vscsiLunReqSenseErrorSet(pVScsiLun, pVScsiReq, SCSI_SENSE_ILLEGAL_REQUEST, SCSI_ASC_INV_FIELD_IN_CMD_PACKET, 0x00);
+ }
+ break;
+ }
+ case SCSI_MODE_SELECT_6:
+ {
+ uint8_t abParms[12];
+ size_t cbCopied;
+ size_t cbList = pVScsiReq->pbCDB[4];
+
+ /* Copy the parameters. */
+ cbCopied = RTSgBufCopyToBuf(&pVScsiReq->SgBuf, &abParms[0], sizeof(abParms));
+
+ /* Handle short LOGICAL BLOCK LENGTH parameter. */
+ if ( !(pVScsiReq->pbCDB[1] & 0x01)
+ && cbCopied == sizeof(abParms)
+ && cbList >= 12
+ && abParms[3] == 8)
+ {
+ uint32_t cbBlock;
+
+ cbBlock = vscsiBE2HU24(&abParms[4 + 5]);
+ Log2(("SBC: set LOGICAL BLOCK LENGTH to %u\n", cbBlock));
+ if (cbBlock == 512) /* Fixed block size. */
+ {
+ rcReq = vscsiLunReqSenseOkSet(pVScsiLun, pVScsiReq);
+ 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:
@@ -445,7 +492,7 @@ static int vscsiLunSbcReqProcess(PVSCSILUNINT pVScsiLun, PVSCSIREQINT pVScsiReq)
&& cbCopied == sizeof(abHdr)
&& cbList >= 8)
{
- size_t cBlkDesc = vscsiBE2HU16(&abHdr[2]) / 16;
+ uint32_t cBlkDesc = vscsiBE2HU16(&abHdr[2]) / 16;
if (cBlkDesc)
{
diff --git a/src/VBox/Devices/Storage/VSCSI/VSCSISense.cpp b/src/VBox/Devices/Storage/VSCSI/VSCSISense.cpp
index c90cd673..673ee0b8 100644
--- a/src/VBox/Devices/Storage/VSCSI/VSCSISense.cpp
+++ b/src/VBox/Devices/Storage/VSCSI/VSCSISense.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2011 Oracle Corporation
+ * 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;
@@ -24,6 +24,12 @@
void vscsiSenseInit(PVSCSISENSE pVScsiSense)
{
memset(pVScsiSense->abSenseBuf, 0, sizeof(pVScsiSense->abSenseBuf));
+
+ /* Fill in valid sense information (can't be just zeros). */
+ pVScsiSense->abSenseBuf[0] = (1 << 7) | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED; /* Fixed format */
+ pVScsiSense->abSenseBuf[2] = SCSI_SENSE_NONE;
+ pVScsiSense->abSenseBuf[7] = 10;
+ pVScsiSense->abSenseBuf[12] = SCSI_ASC_NONE;
}
int vscsiReqSenseOkSet(PVSCSISENSE pVScsiSense, PVSCSIREQINT pVScsiReq)