diff -r 000000000000 -r 1e05558e2206 usbclasses/usbphoneasmodem/classimplementation/mscfileserver/src/scsiprot.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbclasses/usbphoneasmodem/classimplementation/mscfileserver/src/scsiprot.cpp Thu Dec 17 09:14:30 2009 +0200 @@ -0,0 +1,1089 @@ +// Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// +// + +/** + @file + SCSI protocol + */ + +#include "scsiprot.h" +#include "debug.h" +#include "mscfileserver.h" + +// Helper macros +#define LBA(x) static_cast((x[3] << 24) | (x[4] << 16) | (x[5] << 8) | x[6]) +#define LEN(x) static_cast((x[8] << 8) | x[9]) + + +LOCAL_D const TUint KDefaultBlockSize = 0x800; //default block size for MM + +LOCAL_D const TUint KUndefinedLun = 0xFFFF; + +LOCAL_D const TUint8 KAllPages = 0x3F; + +LOCAL_D const TUint8 KChangeableValues = 0x1; +LOCAL_D const TUint8 KDefaultValues = 0x2; + +/** +Default constructor for TSenseInfo +*/ +TSenseInfo::TSenseInfo() + : iSenseCode(ENoSense), + iAdditional(EAscNull), + iQualifier(EAscqNull) + {} + + +/** +Set sense with no additional info. + +@param aSenseCode sense key +*/ +void TSenseInfo::SetSense(TSenseCode aSenseCode) + { + iSenseCode = static_cast(aSenseCode); + iAdditional = EAscNull; + iQualifier = EAscqNull; + } + + +/** +Set sense with additional info. + +@param aSenseCode sense key +@param aAdditional additional sense code (ASC) +*/ +void TSenseInfo::SetSense(TSenseCode aSenseCode, TAdditionalCode aAdditional) + + { + iSenseCode = static_cast(aSenseCode); + iAdditional = static_cast(aAdditional); + iQualifier = EAscqNull; + } + + +/** +Set sense with additional info and qualifier. + +@param aSenseCode sense key +@param aAdditional additional sense code (ASC) +@param aQualifier additional sense code qualifier (ASCQ) +*/ +void TSenseInfo::SetSense(TSenseCode aSenseCode, + TAdditionalCode aAdditional, + TAdditionalSenseCodeQualifier aQualifier) + { + iSenseCode = static_cast(aSenseCode); + iAdditional = static_cast(aAdditional); + iQualifier = static_cast(aQualifier); + } + + +//----------------------------------------------- + +/** +Creates the CScsiProtocol object. Called during controller initialisation. + +@param aFsImage reference to the file system image +*/ +CScsiProtocol* CScsiProtocol::NewL(CMscFileController& aController) + { + CScsiProtocol* self = new (ELeave) CScsiProtocol(aController); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +/** +c'tor + +@param aFsImage reference to the file system image +*/ +CScsiProtocol::CScsiProtocol(CMscFileController& aController): + iController(aController), + iLastCommand(EUndefinedCommand), + iLastLun(KUndefinedLun), + iMediaWriteSize(KDefaultMediaWriteSize) + { + } + + +CScsiProtocol::~CScsiProtocol() + { + } + + +void CScsiProtocol::ConstructL() + { + TRACE_FUNC + } + + +/** +Associates the transport with the protocol. Called during initialisation of the controller. + +@param aTransport pointer to the transport object +*/ +void CScsiProtocol::RegisterTransport(MTransportBase* aTransport) + { + TRACE_FUNC + iTransport = aTransport; + } + + +/** +Called by the Transport when it detects that the USB device is either running +at High Speed or is at least capable of HS operation. The Protocol can use this +information (for instance) to select the optimal write block size to use. + +This function is preferably called before actual MS data transfer operation +starts, and usually only once. + +*/ +void CScsiProtocol::ReportHighSpeedDevice() + { + TRACE_FUNC + iMediaWriteSize = KHsMediaWriteSize; + TRACE_INFO(( _L( "HS Device reported: SCSI will use %d bytes disk write size"), + iMediaWriteSize )) + } + + +TInt CScsiProtocol::SetScsiParameters(TMassStorageConfig aConfig) + { + TRACE_FUNC + iConfig = aConfig; + return KErrNone; + } + + +/** +Called by the transport layer when a packet is available for decoding. +If an error occurs, the sense code is updated and EFalse is returned. + +@param aData + +@return ETrue if command was decoded and executed successfully +*/ +TBool CScsiProtocol::DecodePacket(TPtrC8& aData, TUint aLun) + { + TRACE_FUNC_ENTRY + + TUint8 command = aData[1]; + + if (command != ERequestSense) + { + iSenseInfo.SetSense(TSenseInfo::ENoSense); + } + + TRACE_INFO(( _L( "command = 0x%x lun=%d"), command, aLun )) + switch (command) + { + case ETestUnitReady: + HandleUnitReady(aLun); + break; + + case ERequestSense: + HandleRequestSense(aData); + break; + + case EInquiry: + HandleInquiry(aData, aLun); + break; + + case EModeSense: + HandleModeSense(aData, aLun); + break; + + case EModeSense10: + HandleModeSense10(aData, aLun); + break; + + case EStartStopUnit: + HandleStartStopUnit( aData,aLun); + break; + + case EPreventMediaRemoval: + HandlePreventMediaRemoval(aData, aLun); + break; + + case EReadCapacity: + HandleReadCapacity(aData, aLun); + break; + + case ERead10: + HandleRead10(aData, aLun); + break; + + case ERead12: + HandleRead12(aData, aLun); + break; + + case EReadTOC: + HandleReadTOC(aData, aLun); + break; + + case EGetConfiguration: + HandleGetConfiguration(aData, aLun); + break; + + default: + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidCmdCode); + } + TRACE_INFO(( _L( "result = %d" ), iSenseInfo.SenseOk() )) + TRACE_FUNC_EXIT + return ( iSenseInfo.SenseOk() ); + } + + +/** +Checks if drive ready + +@param aLun Logic unit number +@return pointer to drive correspondent to LUN if drive mounted and ready, NULL otherwise +*/ +CFileSystemImage* CScsiProtocol::GetCheckFs(TUint aLun) + { + TRACE_FUNC + TInt err = KErrNone; + CFileSystemImage* image = iController.FsImage( aLun ); + + if ( image == NULL ) + { + TRACE_ERROR(( _L( "Illegal LUN %d" ), aLun )) + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported); + return NULL; + } + + // Image exists, ensure it is opened for access + err = image->Open(); + if ( err == KErrNone ) + { + // Image is now open, if it wasn't already + TRACE_INFO(( _L( "Image opened successfully" ) )) + return image; + } + else + { + // Either file doesn't exist or was removed + TRACE_ERROR(( _L( "Error %d opening image" ), err )) + iSenseInfo.SetSense( TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent ); + } + return NULL; + } + + +/** +Command Parser for the UNIT READY command (0x00) + +@param aLun Logic unit number +@return ETrue if successful, +*/ +TBool CScsiProtocol::HandleUnitReady(TUint aLun) + { + TRACE_FUNC + return ( GetCheckFs(aLun) != NULL ); + } + + +/** +Command Parser for the REQUEST SENSE command (0x03) + +@return ETrue if successful, +*/ +TBool CScsiProtocol::HandleRequestSense(TPtrC8& aData) + { + TRACE_FUNC + TUint length = aData[5]; + TRACE_INFO(( _L( "length = %d"), length )) + iCommandBuf.FillZ(KRequestSenseCommandLength); + + TSenseInfo* senseInfo; + senseInfo = &iSenseInfo; + iCommandBuf[00] = 0x70; //(current errors) + + iCommandBuf[02] = static_cast(senseInfo->iSenseCode & 0x0F); + + iCommandBuf[12] = senseInfo->iAdditional; + iCommandBuf[13] = senseInfo->iQualifier; + if (length<18 && length >=8) + { + iCommandBuf.SetLength(length); //length of response code data + iCommandBuf[07] = TUint8(length - 8); //additional sence length + } + else if (length >= KRequestSenseCommandLength) + { + iCommandBuf[07] = KRequestSenseCommandLength - 8; // we have max 18 byte to send + } + + TRACE_INFO(( _L( "Response=0x%x Sense=0x%x, Additional=0x%x, Qualifier=0x%x\n"), + iCommandBuf[0], iCommandBuf[02], iCommandBuf[12], iCommandBuf[13] )) + + TPtrC8 writeBuf = iCommandBuf.Left(length); + iTransport->SetupWriteData(writeBuf); + + // clear the sense info + iSenseInfo.SetSense(TSenseInfo::ENoSense); + + return ETrue; + } + + +/** +Command Parser for the INQUIRY command (0x12) + +@param aLun Logic unit number +@return ETrue if successful, +*/ +TBool CScsiProtocol::HandleInquiry(TPtrC8& aData, TUint /*aLun*/ ) + { + TRACE_FUNC + + TBool cmdDt = aData[2] & 0x2; + TBool evpd = aData[2] & 0x1; + TUint8 page = aData[3]; + if (cmdDt || evpd || page /*|| aLun >= KUsbMsMaxDrives*/) + { + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); + return EFalse; + } + + iCommandBuf.FillZ(KInquiryCommandLength); + + iCommandBuf[0] = 0x05; // CD-ROM + iCommandBuf[1] = 0x80; // MSB: RMB : Removable + iCommandBuf[2] = 0x02; // Version SPC-3 + iCommandBuf[3] = 0x02; // AERC, TrmTsk, NormACA, Response Data Format + iCommandBuf[4] = 0x1F; // Additional Length + + TPtr8 vendorId(&iCommandBuf[8], 8, 8); // Vendor ID (Vendor Specific/Logged by T10) + vendorId.Fill(' ', 8); + vendorId.Copy(iConfig.iVendorId); + + TPtr8 productId(&iCommandBuf[16], 16, 16); // Product ID (Vendor Specific) + productId.Fill(' ', 16); + productId.Copy(iConfig.iProductId); + + TPtr8 productRev(&iCommandBuf[32], 4, 4); // Product Revision Level (Vendor Specific) + productRev.Fill(' ', 4); + productRev.Copy(iConfig.iProductRev); + + TUint length = aData[5]; + TPtrC8 writeBuf = iCommandBuf.Left(length); + iTransport->SetupWriteData(writeBuf); + + iSenseInfo.SetSense(TSenseInfo::ENoSense); + return ETrue; + } + + +/** + Command Parser for the START STOP UNIT command (0x1B) + + @param aData command data (started form position 1) + @param aLun Logic unit number + @return ETrue if successful, TFalse otherwise + */ +TBool CScsiProtocol::HandleStartStopUnit(TPtrC8& aData, TUint aLun) + { + TRACE_FUNC + CFileSystemImage* image = GetCheckFs(aLun); + if ( image == NULL ) + { + return EFalse; + } + + const TUint8 KStartMask = 0x01; + const TUint8 KImmedMask = 0x01; + const TUint8 KLoejMask = 0x02; + + TBool immed = aData[2] & KImmedMask ? ETrue : EFalse; + TBool start = aData[5] & KStartMask ? ETrue : EFalse; + TBool loej = aData[5] & KLoejMask ? ETrue : EFalse; + + TRACE_INFO(( _L( "Data %X %X" ), aData[2], aData[5] )) + TRACE_INFO(( _L( "IMMED = %d" ), immed )) + TRACE_INFO(( _L( "START = %d"), start )) + TRACE_INFO(( _L( "LOEJ = %d" ), loej )) + + TInt err = KErrNone; + if (loej) + { + if (start) //Start unit + { + // GetCheckFs has already opened the image file + TRACE_INFO(( _L( "Load media" ) )) + } + else //Stop unit + { + err = image->Close(); + TRACE_INFO(( _L( "Unload media" ) )) + } + } + + if (err != KErrNone) //actually we have error here only if the LUN is incorrect + { + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported); + return EFalse; + } + + return ETrue; + } + + +/** +Command Parser for the PREVENT/ALLOW MEDIA REMOVAL command (0x1E) + +@param aData command data (started form position 1) +@param aLun Logic unit number +@return ETrue if successful. +*/ +TBool CScsiProtocol::HandlePreventMediaRemoval(TPtrC8& aData, TUint aLun) + { + TRACE_FUNC + if ( GetCheckFs(aLun) == NULL ) + { + return EFalse; + } + + TInt prevent = aData[5] & 0x01; + + // locking is not supported + if (prevent) + { + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); + } + return ETrue; + } + +/** Cancel active state, Invoked by transnport when it stops */ +TInt CScsiProtocol::Cancel() + { + TRACE_FUNC + return KErrNone; + } + +/** +Command Parser for the READ CAPACITY(10) command (0x25) + +@param aData command data (started form position 1) +@param aLun Logic unit number +@return ETrue if successful. +*/ +TBool CScsiProtocol::HandleReadCapacity(TPtrC8& aData, TUint aLun) + { + TRACE_FUNC + CFileSystemImage* image = GetCheckFs(aLun); + if ( image == NULL ) + { + return EFalse; + } + + TInt pmi = aData[9] & 0x01; + TInt lba = aData[3] | aData[4] | aData[5] | aData[6]; + + if (pmi || lba) //do not support partial medium indicator + { + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); + return EFalse; + } + + TInt64 driveBlocks = image->Size() / MAKE_TINT64(0, KDefaultBlockSize) - 1; + iCommandBuf.FillZ(KReadCapacityCommandLength); + if (I64HIGH(driveBlocks) == 0) + { + TUint32 numBlocks = I64LOW(driveBlocks); + + TRACE_INFO(( _L( "Block size=%d, NumBlocks=%d" ), + KDefaultBlockSize, numBlocks )) + iCommandBuf[0] = static_cast((numBlocks & 0xFF000000) >> 24); // Number of blocks + iCommandBuf[1] = static_cast((numBlocks & 0x00FF0000) >> 16); + iCommandBuf[2] = static_cast((numBlocks & 0x0000FF00) >> 8); + iCommandBuf[3] = static_cast((numBlocks & 0x000000FF)); + } + else + { + iCommandBuf[0] = iCommandBuf[1] = iCommandBuf[2] = iCommandBuf[3] = 0xFF; // indicate that size more then )0xFFFFFFFF + } + + iCommandBuf[4] = static_cast((KDefaultBlockSize & 0xFF000000) >> 24); // Block Size + iCommandBuf[5] = static_cast((KDefaultBlockSize & 0x00FF0000) >> 16); + iCommandBuf[6] = static_cast((KDefaultBlockSize & 0x0000FF00) >> 8); + iCommandBuf[7] = static_cast((KDefaultBlockSize & 0x000000FF)); + + TPtrC8 writeBuf = iCommandBuf; + iTransport->SetupWriteData(writeBuf); + + return ETrue; + } + + +/** +Command Parser for the READ10 command (0x28) + +@param aData command data (started form position 1) +@param aLun Logic unit number +@return ETrue if successful. +*/ +TBool CScsiProtocol::HandleRead10(TPtrC8& aData, TUint aLun) + { + TRACE_FUNC + CFileSystemImage* image = GetCheckFs(aLun); + if ( image == NULL ) + { + return EFalse; + } + + TInt rdProtect = aData[2] >> 5; + if (rdProtect) + { + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); + return EFalse; + } + + const TUint32 lba = LBA(aData); + const TUint16 len = LEN(aData); + + TRACE_INFO(( _L( "READ(10) : LBA = %d, Length = %d (blocks)" ), lba, len)) + + if (!len) + { + return ETrue; // do nothing - this is not an error + } + + const TInt64 bOffset = MAKE_TINT64(0, lba) * KDefaultBlockSize; + const TInt bLength = len * KDefaultBlockSize; + const TInt64 theEnd = bOffset + MAKE_TINT64(0, bLength); + + if (theEnd > image->Size()) //check if media big enough for this request + { + TRACE_ERROR(( _L( "err - Request ends out of media" ) )) + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange); + return EFalse; + } + + // check if our buffer can hold requested data + if (iCommandBuf.MaxLength() < bLength) + { + TRACE_ERROR(( _L( "err - Buffer too small" ) )) + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); + return EFalse; + } + + TInt err = image->Read(bOffset, bLength, iCommandBuf); + if (err != KErrNone) + { + TRACE_ERROR(( _L( "Read failed, err=%d" ), err )) + iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent); + return EFalse; + } + + TPtrC8 writeBuf = iCommandBuf; + + // Set up data write to the host + iTransport->SetupWriteData(writeBuf); + + return ETrue; + } + + +/** +Command Parser for the READ12 command (0xA8) + +@param aData command data (started form position 1) +@param aLun Logic unit number +@return ETrue if successful. +*/ +TBool CScsiProtocol::HandleRead12(TPtrC8& aData, TUint aLun) + { + TRACE_FUNC + CFileSystemImage* image = GetCheckFs(aLun); + if ( image == NULL ) + { + return EFalse; + } + TInt rdProtect = aData[2] >> 5; + if (rdProtect) + { + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); + return EFalse; + } + + const TUint32 lba = static_cast((aData[3] << 24) | (aData[4] << 16) | (aData[5] << 8) | aData[6]); + const TUint32 len = static_cast((aData[7] << 24) | (aData[8] << 16) | (aData[9] << 8) | aData[10]); + + TRACE_INFO(( _L( "READ(12) : LBA = %d, Length = %d (blocks)" ), lba, len )) + + if (!len) + { + return ETrue; // do nothing - this is not an error + } + + const TInt64 bOffset = MAKE_TINT64(0, lba) * KDefaultBlockSize; + const TUint32 bLength = len * KDefaultBlockSize; + const TInt64 theEnd = bOffset + MAKE_TINT64(0, bLength); + + if (theEnd > image->Size()) //check if media big enough for this request + { + TRACE_ERROR(( _L( "err - Request ends out of media" ) )) + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange); + return EFalse; + } + + // check if our buffer can hold requested data + if (iCommandBuf.MaxLength() < bLength) + { + TRACE_ERROR(( _L( "err - Buffer too small" ) )) + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); + return EFalse; + } + + TInt err = image->Read(bOffset, bLength, iCommandBuf); + if (err != KErrNone) + { + TRACE_ERROR(( _L( "Read failed, err=%d" ), err )) + iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent); + return EFalse; + } + + TPtrC8 writeBuf = iCommandBuf; + + // Set up data write to the host + iTransport->SetupWriteData(writeBuf); + + return ETrue; + } + +/** +Called by the transport when the requested data has been read or an error has +occurred during the read. + +@param aError Indicate if an error occurs during reading data by transport. +@return KErrAbort if command processing is complete but has failed, + KErrCompletion if sufficient data is available in the buffer to process + the transfer immediately, KErrNotReady if insufficient data is + available in the buffer so the transport should wait for it to arrive, + KErrNone if command processing is complete and was successful. +*/ +TInt CScsiProtocol::ReadComplete(TInt aError) + { + TRACE_FUNC + TRACE_INFO(( _L( "Error = 0x%X" ), aError )) +// const TInt64 bOffset = iOffset; + TUint8 lastCommand = iLastCommand; + TUint lastLun = iLastLun; + + iOffset = 0; + iLastCommand = EUndefinedCommand; + iLastLun = KUndefinedLun; + + TRACE_INFO(( _L( "Last command was: %s" ), + (lastCommand == EUndefinedCommand) ? _S("Undefined") : + ((lastCommand == EWrite10) ? _S("EWrite10") : + ((lastCommand == EVerify10) ? _S("EVerify10") : + _S("Unknown"))) )) + + if (aError != KErrNone || + lastCommand == EUndefinedCommand || + lastLun == KUndefinedLun) + { + iSenseInfo.SetSense(TSenseInfo::EAbortedCommand); + return KErrAbort; + } + + CFileSystemImage* image = GetCheckFs(lastLun); + if ( image == NULL ) + { + return KErrAbort; + } + else + { + iSenseInfo.SetSense(TSenseInfo::EAbortedCommand); + } + return iSenseInfo.SenseOk() ? KErrNone : KErrAbort; + } + + +/** +Command Parser for the MODE SENSE(06) command (0x1A) + +@return ETrue if successful. +*/ +TBool CScsiProtocol::HandleModeSense(TPtrC8& aData, TUint /*aLun*/) + { + TRACE_FUNC + + TInt pageCode = aData[3] & 0x3F; + TUint8 pageControl= static_cast(aData[3] >>6); + + // reserve 4 bytes for Length, Media type, Device-specific parameter and Block descriptor length + iCommandBuf.FillZ(KModeSenseCommandLength); + + if (pageCode != KAllPages || pageControl == KChangeableValues) + { + TRACE_ERROR(( _L( "TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb"))) + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb); + return EFalse; + } + if (pageControl != KDefaultValues) + { + iCommandBuf[2] = 1<<7; // set SWP bit at the Device Specific parameters + } + + iCommandBuf[0]=3; //Sending only Mode parameter header + + TPtrC8 writeBuf = iCommandBuf; + iTransport->SetupWriteData(writeBuf); + + return (iSenseInfo.SenseOk()); + } + + +const TUint16 KMaxModeRespLen = 58; +/** +Command Parser for the MODE SENSE(10) command (0x5A) + +@return ETrue if successful. +*/ +TBool CScsiProtocol::HandleModeSense10(TPtrC8& aData, TUint /*aLun*/) + { + TRACE_FUNC + + TInt pageCode = aData[3] & 0x3F; + TUint8 pageControl= static_cast(aData[3] >>6); + + iCommandBuf.FillZ(KMaxModeRespLen); + + TBool allPages = EFalse; + TUint16 len = static_cast((aData[8] << 8) | aData[9]); + __ASSERT_DEBUG(len > 1, User::Panic(KUsbMsSvrPncCat, EMsWrongLength)); + + iCommandBuf[2] = 0x71; // medium type + + TInt i = 8; + + switch (pageCode) + { + case 0x3F: // All mode pages + allPages = ETrue; + case 0x1A: // Power condition mode page + // byte 0 + iCommandBuf[i++] = 0x1A; // page code + iCommandBuf[i++] = 0x0A; // length + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // IDLE = 0, STANDBY = 0 + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x00; // idle timer + // byte 8 + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x00; // standby timer + + if (!allPages) + { + break; + } + case 0x1D: // Timeout and protect mode page + // byte 0 + iCommandBuf[i++] = 0x1D; // page code + iCommandBuf[i++] = 0x08; // length + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // reserver + iCommandBuf[i++] = 0x00; // G3, TMOE, DISP, SWPP = 0, 0, 0, 0 + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x00; // group 1 timeout + // byte 8 + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x00; // group 2 timeout + + if (!allPages) + { + break; + } + case 0x2A: // MM capabilities and mechanical status page + // byte 0 + iCommandBuf[i++] = 0x2A; // page code + iCommandBuf[i++] = 0x1A; // length + iCommandBuf[i++] = 0x00; // !CD-R + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x30; // mode (mode 2, form 1,2) + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x29; // tray, eject, lock + iCommandBuf[i++] = 0x00; + // byte 8 + iCommandBuf[i++] = 0x00; // + iCommandBuf[i++] = 0x00; // obsolete + iCommandBuf[i++] = 0x00; // + iCommandBuf[i++] = 0x00; // volume levels + iCommandBuf[i++] = 0x00; // + iCommandBuf[i++] = 0x00; // buffer size + iCommandBuf[i++] = 0x00; // + iCommandBuf[i++] = 0x00; // obsolete + // byte 16 + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // unspecified + iCommandBuf[i++] = 0x00; // obsolete + iCommandBuf[i++] = 0x00; // obsolete + iCommandBuf[i++] = 0x00; // obsolete + iCommandBuf[i++] = 0x00; // obsolete + iCommandBuf[i++] = 0x00; // + iCommandBuf[i++] = 0x00; // copy management revision + // byte 24 + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // reserved + + break; + default: + // Unknown page code + iSenseInfo.SetSense(TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb); + return EFalse; + } + + if (i > len) + { + // don't send more data than the host will accept + i = len; + } + iCommandBuf.SetLength(i); + iCommandBuf[1] = (TUint8)(i-2); // length will not exceed 255, so LSB is enough + + TPtrC8 writeBuf = iCommandBuf; + iTransport->SetupWriteData(writeBuf); + + return (iSenseInfo.SenseOk()); + } + +/** +Command Parser for the READ TOC/PMA/ATIP command (0x43) + +@return ETrue if successful. +*/ +TBool CScsiProtocol::HandleReadTOC(TPtrC8& aData, TUint aLun) + { + TRACE_FUNC + if ( GetCheckFs(aLun) == NULL ) + { + return EFalse; + } + + TUint16 len = static_cast((aData[8] << 8) | aData[9]); + + if (len == 0) + { + return ETrue; // allocation length = 0 is not an error + } + else if (len > 20) + { + len = 20; + } + + iCommandBuf.FillZ(len); + + // TOC header + iCommandBuf[0] = 0x00; // length MSB + iCommandBuf[1] = len-2; // length LSB + iCommandBuf[2] = 0x01; // first track + iCommandBuf[3] = 0x01; // last track + if (len >= 12) + { + // Track descriptor, track 1 + iCommandBuf[5] = 0x14; // ADR | CTRL + iCommandBuf[6] = 0x01; // track + // Track start address + if (aData[2] & 0x02) + { + // TIME address = 0x00 00 02 00 + iCommandBuf[10] = 0x02; + } + } + if (len >= 20) + { + // Track descriptor, lead-out + iCommandBuf[13] = 0x14; + iCommandBuf[14] = 0xaa; + } + + TPtrC8 writeBuf = iCommandBuf; + iTransport->SetupWriteData(writeBuf); + + return (iSenseInfo.SenseOk()); + } + +const TUint16 KFeatureNums[] = { 0x0000, 0x0001, 0x0002, 0x0003, + 0x0010, 0x001E, 0x0100, 0x0105 }; +const TInt KNumFeatures = sizeof(KFeatureNums) / sizeof(TUint16); +const TInt KMaxConfRespLen = 76; + +/** +Command Parser for the GET CONFIGURATION command (0x46) + +@return ETrue if successful. +*/ +TBool CScsiProtocol::HandleGetConfiguration(TPtrC8& aData, TUint aLun) + { + TRACE_FUNC + if ( GetCheckFs(aLun) == NULL ) + { + return EFalse; + } + TUint blockSize = KDefaultBlockSize; + + TUint8 rt = aData[2] & 0x03; + TUint16 feature = static_cast((aData[3] << 8) | aData[4]); + TUint16 len = static_cast((aData[8] << 8) | aData[9]); + + if (len == 0) + { + return ETrue; // allocation length = 0 is not an error + } + + iCommandBuf.FillZ(KMaxConfRespLen); + + // Feature header + iCommandBuf[0] = 0x00; // length + iCommandBuf[1] = 0x00; // length + iCommandBuf[2] = 0x00; // length + iCommandBuf[6] = 0x00; + iCommandBuf[7] = 0x08; // CD-ROM Profile 0x0008 + + TInt i = 8; + + for (TInt f = 0; f < KNumFeatures; f++) + { + if ( ( ( rt == 2 ) && ( KFeatureNums[f] == feature ) ) || + ( ( rt != 2 ) && ( KFeatureNums[f] >= feature ) ) ) + { + switch (KFeatureNums[f]) + { + case 0x0000: + // Profile list + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x00; // feature code = 0x0000 + iCommandBuf[i++] = 0x03; // persistent = 1, current = 1 + iCommandBuf[i++] = 0x04; // additional length (1 profile desc.) + // Profile descriptor + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x08; // profile 0x0008 + iCommandBuf[i++] = 0x01; // current + iCommandBuf[i++] = 0x00; // reserved + break; + case 0x0001: + // Core feature descriptor + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x01; // feature code = 0x0001 + iCommandBuf[i++] = 0x07; // version = 0001b, persistent = 1, current = 1 + iCommandBuf[i++] = 0x08; // additional length + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x08; // physical interface = 0x00000008 (USB) + iCommandBuf[i++] = 0x01; // DBE = 1 + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // reserved + break; + case 0x0002: + // Morphing feature descriptor + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x02; // feature code = 0x0002 + iCommandBuf[i++] = 0x07; // version = 0001b, persistent = 1, current = 1 + iCommandBuf[i++] = 0x04; // additional length + iCommandBuf[i++] = 0x02; // OCEvent = 1, ASYNC = 0 + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // reserved + break; + case 0x0003: + // Removable medium feature descriptor + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x03; // feature code = 0x0003 + iCommandBuf[i++] = 0x03; // persistent = 1, current = 1 + iCommandBuf[i++] = 0x04; // additional length + iCommandBuf[i++] = 0x29; // tray, eject, lock + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // reserved + break; + case 0x0010: + // Random readable feature descriptor + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x10; // feature code = 0x0010 + iCommandBuf[i++] = 0x03; // persistent = 1, current = 1 + iCommandBuf[i++] = 0x08; // additional length + // Block Size + iCommandBuf[i++] = static_cast((blockSize & 0xFF000000) >> 24); + iCommandBuf[i++] = static_cast((blockSize & 0x00FF0000) >> 16); + iCommandBuf[i++] = static_cast((blockSize & 0x0000FF00) >> 8); + iCommandBuf[i++] = static_cast((blockSize & 0x000000FF)); + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x01; // blocking = 1 + iCommandBuf[i++] = 0x00; // PP = 0 + iCommandBuf[i++] = 0x00; // reserved + break; + case 0x001E: + // CD Read feature descriptor + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x1E; // feature code = 0x001E + iCommandBuf[i++] = 0x0B; // version = 2, persistent = 1, current = 1 + iCommandBuf[i++] = 0x04; // additional length + iCommandBuf[i++] = 0x00; // DAP = 0, C2 flags = 0, CD-Text = 0 + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; // reserved + break; + case 0x0100: + // Power management feature descriptor + iCommandBuf[i++] = 0x01; + iCommandBuf[i++] = 0x00; // feature code = 0x0100 + iCommandBuf[i++] = 0x03; // persistent = 1, current = 1 + iCommandBuf[i++] = 0x00; // additional length = 0 + break; + case 0x0105: + // Timeout feature descriptor + iCommandBuf[i++] = 0x01; + iCommandBuf[i++] = 0x05; // feature code = 0x0105 + iCommandBuf[i++] = 0x07; // version = 1, persistent = 1, current = 1 + iCommandBuf[i++] = 0x04; // additional length + iCommandBuf[i++] = 0x00; // G3 = 0 + iCommandBuf[i++] = 0x00; // reserved + iCommandBuf[i++] = 0x00; + iCommandBuf[i++] = 0x00; // unit lenght = undefined + break; + default: + break; + } + } + } + iCommandBuf[3] = (TUint8)(i-4); // length LSB + if (i > len) + { + // don't send more data than the host will accept + i = len; + } + + TPtrC8 writeBuf = iCommandBuf.Left(i); + iTransport->SetupWriteData(writeBuf); + + return (iSenseInfo.SenseOk()); + } +