usbclasses/usbphoneasmodem/classimplementation/mscfileserver/src/scsiprot.cpp
changeset 35 9d8b04ca6939
child 63 ef2686f7597e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbclasses/usbphoneasmodem/classimplementation/mscfileserver/src/scsiprot.cpp	Fri Jun 04 10:27:39 2010 +0100
@@ -0,0 +1,1084 @@
+// 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: 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());
+    }
+