--- /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<TUint32>((x[3] << 24) | (x[4] << 16) | (x[5] << 8) | x[6])
+#define LEN(x) static_cast<TUint16>((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<TUint8>(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<TUint8>(aSenseCode);
+ iAdditional = static_cast<TUint8>(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<TUint8>(aSenseCode);
+ iAdditional = static_cast<TUint8>(aAdditional);
+ iQualifier = static_cast<TUint8>(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<TUint8>(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<TUint8>((numBlocks & 0xFF000000) >> 24); // Number of blocks
+ iCommandBuf[1] = static_cast<TUint8>((numBlocks & 0x00FF0000) >> 16);
+ iCommandBuf[2] = static_cast<TUint8>((numBlocks & 0x0000FF00) >> 8);
+ iCommandBuf[3] = static_cast<TUint8>((numBlocks & 0x000000FF));
+ }
+ else
+ {
+ iCommandBuf[0] = iCommandBuf[1] = iCommandBuf[2] = iCommandBuf[3] = 0xFF; // indicate that size more then )0xFFFFFFFF
+ }
+
+ iCommandBuf[4] = static_cast<TUint8>((KDefaultBlockSize & 0xFF000000) >> 24); // Block Size
+ iCommandBuf[5] = static_cast<TUint8>((KDefaultBlockSize & 0x00FF0000) >> 16);
+ iCommandBuf[6] = static_cast<TUint8>((KDefaultBlockSize & 0x0000FF00) >> 8);
+ iCommandBuf[7] = static_cast<TUint8>((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<TUint32>((aData[3] << 24) | (aData[4] << 16) | (aData[5] << 8) | aData[6]);
+ const TUint32 len = static_cast<TUint32>((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<TUint8>(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<TUint8>(aData[3] >>6);
+
+ iCommandBuf.FillZ(KMaxModeRespLen);
+
+ TBool allPages = EFalse;
+ TUint16 len = static_cast<TUint16>((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<TUint16>((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<TUint16>((aData[3] << 8) | aData[4]);
+ TUint16 len = static_cast<TUint16>((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<TUint8>((blockSize & 0xFF000000) >> 24);
+ iCommandBuf[i++] = static_cast<TUint8>((blockSize & 0x00FF0000) >> 16);
+ iCommandBuf[i++] = static_cast<TUint8>((blockSize & 0x0000FF00) >> 8);
+ iCommandBuf[i++] = static_cast<TUint8>((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());
+ }
+