diff options
| author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-03-26 19:21:20 +0000 |
|---|---|---|
| committer | <> | 2014-05-08 15:03:54 +0000 |
| commit | fb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch) | |
| tree | c2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Devices/Storage/VSCSI | |
| parent | 58ed4748338f9466599adfc8a9171280ed99e23f (diff) | |
| download | VirtualBox-master.tar.gz | |
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Devices/Storage/VSCSI')
| -rw-r--r-- | src/VBox/Devices/Storage/VSCSI/VSCSIDevice.cpp | 10 | ||||
| -rw-r--r-- | src/VBox/Devices/Storage/VSCSI/VSCSIInternal.h | 34 | ||||
| -rw-r--r-- | src/VBox/Devices/Storage/VSCSI/VSCSILun.cpp | 44 | ||||
| -rw-r--r-- | src/VBox/Devices/Storage/VSCSI/VSCSILunMmc.cpp | 186 | ||||
| -rw-r--r-- | src/VBox/Devices/Storage/VSCSI/VSCSILunSbc.cpp | 65 | ||||
| -rw-r--r-- | src/VBox/Devices/Storage/VSCSI/VSCSISense.cpp | 8 |
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) |
