kerneltest/f32test/smassstorage/scsiprot/t_ms_scsi_steps.cpp
changeset 0 a41df078684a
child 286 48e57fb1237e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/f32test/smassstorage/scsiprot/t_ms_scsi_steps.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1357 @@
+// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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: t_ms_scsi_steps.cpp
+// SCSI protocol test cases.
+// 
+//
+
+/**
+ @file
+ @internalTechnology
+*/
+
+
+#include <f32file.h>
+#include <e32test.h>
+#include <e32math.h>
+#include <f32fsys.h>
+
+#include "massstoragedebug.h"
+
+#include "t_ms_main.h"
+#include "t_ms_scsi.h"
+
+
+
+
+TInt CScsiTest::TestLun = 1;
+// see scsiprot.cpp
+LOCAL_D const TUint KDefaultBlockSize = 0x200;
+
+LOCAL_D TBool mediaChanged = EFalse;
+
+LOCAL_D const TInt KMaxLuns = 8;
+
+/**
+t_scsi_inquiry_normal case
+*/
+GLDEF_C void t_scsi_inquiry_normal()
+	{
+	test.Next(_L("t_scsi_inquiry_normal"));
+	
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+
+	TMassStorageConfig config;
+	config.iVendorId.FillZ(8);
+	config.iVendorId.Copy(_L("UnitTest"));
+	config.iVendorId.SetLength(8);
+	
+	config.iProductId.FillZ(16);
+	config.iProductId.Copy(_L("ProductTest"));
+	config.iProductId.SetLength(16);
+	
+	config.iProductRev.FillZ(4);
+	config.iProductRev.Copy(_L("Rev"));
+	config.iProductRev.SetLength(4);
+	
+	TEST_FOR_VALUE (scsiTest->iScsiProt->SetScsiParameters(config), KErrNone);
+
+	TInquiryCmd cmd;
+	TPtrC8 pBuf(cmd.iCmd);
+	
+	// CASE: media is Not connected
+	TEST_FOR_VALUE (scsiTest->DecodePacket(pBuf), ETrue);
+	{
+	TInquiryData inquiryData(scsiTest->iTransport.iBufWrite);
+
+	// test 		value					expected
+	TEST_FOR_VALUE (inquiryData.DeviceType(),	0);
+	TEST_FOR_VALUE (inquiryData.RMB(), 			1);
+	TEST_FOR_VALUE (inquiryData.Version(), 		0);
+	TEST_FOR_VALUE (inquiryData.RespDataFrmt(),	0x02);
+	TEST_FOR_VALUE (inquiryData.PeripheralQualifier(), 0);	// to be 'connected'
+	
+	TEST_FOR_VALUE ((35 <= inquiryData.Length()),ETrue);		// at least min length
+
+	// these values were set above in this function
+	TMassStorageConfig configInquiry;
+	configInquiry.iVendorId.Copy(inquiryData.VendorId());
+	configInquiry.iProductId.Copy(inquiryData.ProductId());
+	configInquiry.iProductRev.Copy(inquiryData.RevisionLevel());
+	__PRINT1 (_L("VendorId: %S\n"), &configInquiry.iVendorId);
+	__PRINT1 (_L("ProductId: %S\n"), &configInquiry.iProductId);
+	__PRINT1 (_L("ProductRev: %S\n"), &configInquiry.iProductRev);
+
+	TEST_FOR_VALUE((configInquiry.iVendorId == config.iVendorId),	ETrue);
+	TEST_FOR_VALUE((configInquiry.iProductId == config.iProductId), 	ETrue);
+	TEST_FOR_VALUE((configInquiry.iProductRev == config.iProductRev), ETrue);
+	}
+	__PRINT (_L("media not connected ===> passed OK\n"));
+
+	
+	// CASE: emulate 'mount and connect media'	
+	// set connection to physical device as Connected
+	scsiTest->MountTestDrive();
+	TEST_FOR_VALUE (scsiTest->DecodePacket(pBuf), ETrue);
+	{
+	TInquiryData inquiryData(scsiTest->iTransport.iBufWrite);
+	TEST_FOR_VALUE(inquiryData.PeripheralQualifier(), 0);	// to be 'connected'
+	}
+	__PRINT (_L("media not connected ===> passed OK\n"));
+	
+	// cleanup
+	CleanupStack::PopAndDestroy(1); // scsiTest
+
+	__PRINT (_L("t_scsi_inquiry_normal ===> passed OK\n"));
+	}
+
+
+
+/**
+t_scsi_inquiry_error case
+*/
+GLDEF_C void t_scsi_inquiry_error()
+	{
+	test.Next(_L("t_scsi_inquiry_error"));
+	
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+	
+	TInquiryCmd cmd;
+	cmd.iCmd[2] = 0x02; 	// set CmdDt = 1 (2nd bit in 2nd byte)
+	TPtrC8 pBuf(cmd.iCmd);
+	TEST_FOR_VALUE(scsiTest->DecodePacket(pBuf), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
+	
+	// cleanup
+	CleanupStack::PopAndDestroy(1); // scsiTest
+	
+	__PRINT (_L("t_scsi_inquiry_error ===> passed OK\n"));
+	}
+
+
+/**
+t_scsi_test_unit_ready case
+*/
+GLDEF_C void t_scsi_test_unit_ready()
+	{
+	test.Next(_L("t_scsi_test_unit_ready"));
+	
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+	
+	// CASE: NOT registered media
+	TTestUnitReadyCmd cmd;
+	TPtrC8 pBuf(cmd.iCmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket(pBuf), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(),
+						TSenseInfo::ENotReady,
+						TSenseInfo::EMediaNotPresent);
+
+
+	// CASE: registered media
+	scsiTest->MountTestDrive();
+	// repeat TEST UNIT READY command
+	TEST_FOR_VALUE(scsiTest->DecodePacket(pBuf), ETrue);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::ENoSense, 0);
+	
+	// cleanup
+	CleanupStack::PopAndDestroy(1); // scsiTest
+	
+	__PRINT (_L("t_scsi_test_unit_ready ===> passed OK\n"));
+	}
+
+/**
+t_scsi_prevent_allow_media_removal case
+*/
+GLDEF_C void t_scsi_prevent_allow_media_removal()
+	{
+	test.Next(_L("t_scsi_prevent_allow_media_removal"));
+	
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+	
+	// SPC-2, p. 113
+	// Notes: limitation in SCSI protocol:
+	// SCSI protocol uses the 1st bit of PREVENT field only 
+	TMediaRemovalCmd cmdAllow;
+	cmdAllow.iCmd[5] = 0x00;		// allow
+	TPtrC8 pCmdAllow(cmdAllow.iCmd);
+	
+	TMediaRemovalCmd cmdPrevent;
+	cmdPrevent.iCmd[5] = 0x01;	// prevent
+	TPtrC8 pCmdPrevent(cmdPrevent.iCmd);
+	
+	
+	// CASE: do NOT register media AND allow media removal
+	TEST_FOR_VALUE(scsiTest->DecodePacket(pCmdAllow), EFalse);
+
+	TEST_SENSE_CODE_IF_SUPPORTED(scsiTest->GetSenseCodePtr(), TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent)
+		{
+		 __PRINT(_L("NOT register media AND allow removal ===> passed OK\n"));
+
+
+		// CASE: do NOT register media AND prevent media removal
+		TEST_FOR_VALUE(scsiTest->DecodePacket(pCmdPrevent), EFalse);
+		TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
+		 __PRINT(_L("NOT register media AND prevent removal ===> passed OK\n"));
+
+
+		// CASE: Register media AND prevent removal 
+		scsiTest->MountTestDrive();
+		TEST_FOR_VALUE(scsiTest->DecodePacket(pCmdPrevent), ETrue);
+		// check setting in a Drive. the drive has to set to Active state
+		TEST_FOR_VALUE(scsiTest->TestDrive()->DriveState(),	CMassStorageDrive::EActive);
+		 __PRINT(_L("Register media AND prevent removal ===> passed OK\n"));
+
+
+		// CASE:Register media AND allow removal
+		TEST_FOR_VALUE(scsiTest->DecodePacket(pCmdAllow), ETrue);
+		// check setting in a Drive. the drive has to set to Idle state
+		TEST_FOR_VALUE(scsiTest->TestDrive()->DriveState(),	CMassStorageDrive::EIdle);
+		 __PRINT(_L("Register media AND allow removal ===> passed OK\n"));
+		}
+
+	// cleanup
+	CleanupStack::PopAndDestroy(1); // scsiTest
+	 __PRINT(_L("t_scsi_prevent_allow_media_removal ===> passed OK\n"));
+	}
+
+
+/**
+t_scsi_start_stop_unit case
+*/
+GLDEF_C void t_scsi_start_stop_unit()
+	{
+	test.Next(_L("t_scsi_start_stop_unit\n"));
+	
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+	
+	// SBC-2, p. 64 of scsi block commands spec
+	// Notes: limitation in SCSI protocol:
+	// SCSI protocol doesn't support the following fields:
+	// -- IMMED
+	// -- POWER CONDITIONS
+	// => the supported fields are
+	// -- START
+	// -- LOEJ
+	TBuf8<7> cmdStart;
+	cmdStart.FillZ(7);
+	cmdStart[0] = 0x06;		// size of a command itself
+	cmdStart[1] = 0x1B; 	// START STOP UNIT command
+	cmdStart[2] = 0x01;		// Get result immediatly
+	cmdStart[5] = 0x03;		// start: LOEJ + START
+	TPtrC8 pCmdStart(cmdStart);
+	
+	TBuf8<7> cmdStop;
+	cmdStop.FillZ(7);
+	cmdStop[0] = 0x06;		// size of a command itself
+	cmdStop[1] = 0x1B; 		// START STOP UNIT command
+	cmdStop[2] = 0x01;		// Get result immediatly
+	cmdStop[5] = 0x02;		// stop: LOEJ
+	TPtrC8 pCmdStop(cmdStop);
+	
+	
+	// CASE: do NOT register media AND Start
+	// NOT APPLICABLE as there is no such thing as 'register media' in latest implementation
+
+
+	// CASE: do NOT register media AND stop
+	// NOT APPLICABLE as there is no such thing as 'register media' in latest implementation
+
+
+	// CASE: Start unit
+	TEST_FOR_VALUE(scsiTest->DecodePacket(pCmdStart), ETrue);
+	// check setting in a Drive. the drive has to set to Connecting state
+	TEST_FOR_VALUE (scsiTest->TestDrive()->MountState(), CMassStorageDrive::EConnecting);
+	 __PRINT(_L("Registered media AND Start unit ===> passed OK\n"));
+
+
+ 	// CASE: Stop unit
+	TEST_FOR_VALUE(scsiTest->DecodePacket(pCmdStop), ETrue);
+	// check setting in a Drive. the drive has to set to Disconnecting state
+	TEST_FOR_VALUE(scsiTest->TestDrive()->MountState(),		CMassStorageDrive::EDisconnecting);
+	 __PRINT(_L("Registered media AND stop unit ===> passed OK\n"));
+	
+	// cleanup
+	CleanupStack::PopAndDestroy(1); // scsiTest
+	
+	 __PRINT(_L("t_scsi_start_stop_unit ===> passed OK\n"));
+	}
+
+
+/**
+t_scsi_request_sense case
+*/
+GLDEF_C void t_scsi_request_sense()
+	{
+	test.Next(_L("t_scsi_request_sense\n"));
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+
+	// -- check sense BEFORE any other command
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::ENoSense, 0);
+
+
+	// CASE: don't register drive and send UNIT READY
+	TTestUnitReadyCmd cmdUnitReady;
+	TPtrC8 pRequestSenseCmd (cmdUnitReady.iCmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pRequestSenseCmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
+	// check sense code right away
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::ENoSense, 0);
+
+
+	// CASE: do register media
+	scsiTest->MountTestDrive();
+	// repeat TEST UNIT READY command
+	TEST_FOR_VALUE (scsiTest->DecodePacket(pRequestSenseCmd), ETrue);
+
+
+	// CASE: deregister media
+	scsiTest->DismountTestDrive();
+	TEST_FOR_VALUE (scsiTest->DecodePacket(pRequestSenseCmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
+	// check sense code right away
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::ENoSense, 0);
+
+	
+	// cleanup
+	CleanupStack::PopAndDestroy(1); // scsiTest
+	 __PRINT(_L("t_scsi_request_sense ===> passed OK\n"));
+	}
+
+
+/**
+t_scsi_read case
+*/
+GLDEF_C void t_scsi_read()
+	{
+	test.Next (_L("t_scsi_read\n"));
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+	// and initialize proxy drive buffers
+	scsiTest->iProxyDrive.Initialise();
+
+	// SBC-2 p.50
+	// dev notes: latest implementation of scsi protocol supports only:
+	//			- Logical block address
+	//			- Transfer length
+	//			- RDPROTECT (only true or false)
+	//     all other fields are not supported
+	TReadWrite10Cmd cmd;
+	cmd.SetRead();	// setup cmd with correct header
+	TPtrC8 pRead10Cmd(cmd.iCmd);
+	// extra check for iMediaBuf
+	ASSERT (scsiTest->iProxyDrive.iMediaBuf.Length() / KDefaultBlockSize < 0x0000FFFF);
+	TUint16 maxNumBlocks = static_cast<TUint16>(scsiTest->iProxyDrive.iMediaBuf.Length() / KDefaultBlockSize);
+	TUint16 readBlocks = 1;
+	TUint32 offsetBlocks = 1;
+
+	// CASE: register drive; nothing to read
+	scsiTest->MountTestDrive();
+	TEST_FOR_VALUE(scsiTest->DecodePacket(pRead10Cmd), ETrue);
+	 __PRINT(_L("Request to read 0 bytes ===> passed OK\n"));
+
+
+	// CASE: read min (1 block) with offset = 0
+	readBlocks = 1;
+	cmd.SetTransferLength (readBlocks);
+	cmd.SetBlockAddress(0);
+	TEST_FOR_VALUE(scsiTest->DecodePacket(pRead10Cmd), ETrue);
+	{
+	TPtrC8 transportBuf = scsiTest->iTransport.iBufWrite.Left(readBlocks * KDefaultBlockSize);
+	TPtrC8 driveBuf(TPtrC8(scsiTest->iProxyDrive.iMediaBuf).Left(readBlocks * KDefaultBlockSize));
+	// data should be identical
+	TEST_FOR_VALUE(driveBuf.Compare(transportBuf), 0);
+	}
+	 __PRINT(_L("Request to read 1 block @ offset 0 ===> passed OK\n"));
+	
+	
+	// CASE: read after the end
+	readBlocks = 10;
+	cmd.SetTransferLength (readBlocks);
+	cmd.SetBlockAddress(maxNumBlocks - readBlocks/2);
+	TEST_FOR_VALUE(scsiTest->DecodePacket(pRead10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
+	 __PRINT(_L("Request to read AFTER the end of a media ===> passed OK\n"));
+	
+
+	// CASE: read from after the end
+	readBlocks = 10;
+	cmd.SetTransferLength (readBlocks);
+	cmd.SetBlockAddress(maxNumBlocks + readBlocks/2);
+	TEST_FOR_VALUE(scsiTest->DecodePacket(pRead10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
+	 __PRINT(_L("Request to start read AFTER the end of a media ===> passed OK\n"));
+	
+	
+	// CASE: check for internal buffer overflow (with offset)
+	// dev note: this check is specific to SCSI prot implementation
+	// 			 and NOT described by SBC-2 
+	offsetBlocks = 1;
+	readBlocks = static_cast<TUint16>(maxNumBlocks - offsetBlocks);
+	cmd.SetTransferLength (readBlocks);
+	cmd.SetBlockAddress(offsetBlocks);
+	TEST_FOR_VALUE(scsiTest->DecodePacket(pRead10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
+	 __PRINT(_L("Check for internal buffer overflow ===> passed OK\n"));
+
+	
+	// CASE: read max with offset (= offsetBlocks block)
+	offsetBlocks = 2;
+	//				max size in blocks supported by SCSI prot  - offsetBlocks
+	readBlocks = static_cast<TUint16>((KMaxBufSize / KDefaultBlockSize) - offsetBlocks);
+	cmd.SetTransferLength (readBlocks);
+	cmd.SetBlockAddress(offsetBlocks);
+	TEST_FOR_VALUE(scsiTest->DecodePacket(pRead10Cmd), ETrue);
+	{
+	TPtrC8 transportBuf (scsiTest->iTransport.iBufWrite.Left(readBlocks * KDefaultBlockSize));
+	TPtrC8 driveBuf(TPtrC8(scsiTest->iProxyDrive.iMediaBuf).Mid(offsetBlocks * KDefaultBlockSize, readBlocks * KDefaultBlockSize));
+	// data should be identical
+	TEST_FOR_VALUE(driveBuf.Compare(transportBuf), 0);
+	}
+	 __PRINT(_L("Check for max read ===> passed OK\n"));
+
+
+	// CASE: boundary conditions
+	offsetBlocks = 0xFFFFFFFF;
+	readBlocks = 0xFFFF;
+	cmd.SetTransferLength (readBlocks);
+	cmd.SetBlockAddress(offsetBlocks);
+	TEST_FOR_VALUE(scsiTest->DecodePacket(pRead10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
+	 __PRINT(_L("Check for boundary conditions ===> passed OK\n"));
+
+	
+	// CASE: try RDProtect
+	// dev note: scsi protocol doesn't support any value except 000b
+	cmd.SetProtect (1);
+	offsetBlocks = 1;
+	readBlocks = 1;
+	cmd.SetTransferLength (readBlocks);
+	cmd.SetBlockAddress(offsetBlocks);
+	TEST_FOR_VALUE(scsiTest->DecodePacket(pRead10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
+	 __PRINT(_L("Check for RD Protect ===> passed OK\n"));
+
+
+	// CASE: invalid CAPs
+	cmd.SetProtect (0);
+	offsetBlocks = 1;
+	readBlocks = 1;
+	cmd.SetTransferLength (readBlocks);
+	cmd.SetBlockAddress (offsetBlocks);
+	// create error conditions in drive
+	TInt error = KErrNone;
+	CMassStorageDrive* pDrive = scsiTest->iDriveManager->Drive (CScsiTest::TestLun, error);
+	ASSERT (KErrNone == error && pDrive);
+	delete pDrive->iLocalDrive;
+	pDrive->iLocalDrive = NULL;
+	
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pRead10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
+	 __PRINT(_L("Check for invalid caps ===> passed OK\n"));
+	// NOTE: be aware that CMassStorageDrive is in invalid state at this point 
+	//		as Drive->iLocalDrive was set to NULL
+	
+	// cleanup
+	CleanupStack::PopAndDestroy (1); // scsiTest
+	 __PRINT(_L("t_scsi_read ===> passed OK\n"));
+	}
+
+
+/**
+t_scsi_write case
+*/
+GLDEF_C void t_scsi_write()
+	{
+	test.Next (_L("t_scsi_write\n"));
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+	// and initialize Read/Write buffers
+	scsiTest->iProxyDrive.Initialise();
+	scsiTest->iTransport.InitialiseReadBuf();
+
+	// SBC-2 p.80
+	// dev notes: latest implementation of scsi protocol supports only:
+	//			- Logical block address
+	//			- Transfer length
+	//			- WRPROTECT (only true or false)
+	//     all other fields are not supported
+	TReadWrite10Cmd cmd;
+	cmd.SetWrite(); // setup cmd with correct header
+	TPtrC8 pWrite10Cmd(cmd.iCmd);
+	
+	TUint16 maxNumBlocks = static_cast<TUint16>(scsiTest->iProxyDrive.iMediaBuf.Length() / KDefaultBlockSize);
+	TUint16 writeBlocks = 1;
+	TUint32 offsetBlocks = 1;
+
+	// CASE: register drive; nothing to read
+	scsiTest->MountTestDrive();
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pWrite10Cmd), ETrue);
+	 __PRINT(_L("Request to write 0 bytes ===> passed OK\n"));
+
+
+	// CASE: write min
+	writeBlocks = 1;
+	cmd.SetTransferLength (writeBlocks);
+	cmd.SetBlockAddress(0);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pWrite10Cmd), ETrue);
+	// complete read
+	TEST_FOR_VALUE(scsiTest->iScsiProt->ReadComplete(KErrNone), KErrNone);
+	{
+	// note: offset == 0 in this case
+	TPtrC8 transportBuf = scsiTest->iTransport.iBufRead.Left(writeBlocks * KDefaultBlockSize);
+	TPtrC8 driveBuf(TPtrC8(scsiTest->iProxyDrive.iMediaBuf).Mid(0, writeBlocks * KDefaultBlockSize));
+	// data should be identical
+	TEST_FOR_VALUE (driveBuf.Compare(transportBuf), 0);
+	}
+	 __PRINT(_L("Request to write 1 block @ offset 0 ===> passed OK\n"));
+
+
+	// CASE: 	KMediaAttWriteProtected
+	scsiTest->iProxyDrive.iCaps.iMediaAtt = KMediaAttWriteProtected;
+	cmd.SetTransferLength (1);
+	cmd.SetBlockAddress (0);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pWrite10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EDataProtection, TSenseInfo::EWriteProtected);
+	// and CASE: KMediaAttLocked
+	scsiTest->iProxyDrive.iCaps.iMediaAtt = KMediaAttLocked;
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pWrite10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EDataProtection, TSenseInfo::EWriteProtected);
+	// restore media attributes
+	scsiTest->iProxyDrive.iCaps.iMediaAtt = 0;
+	 __PRINT(_L("Request to write to write protected media ===> passed OK\n"));
+	
+	
+	// CASE: check for ReadComplete error during transport READ
+	writeBlocks = 1;
+	cmd.SetTransferLength (writeBlocks);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pWrite10Cmd), ETrue);
+	// complete read
+	TEST_FOR_VALUE(scsiTest->iScsiProt->ReadComplete(KErrOverflow), KErrAbort);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EAbortedCommand, 0);
+	 __PRINT(_L("Case: error during transport READ ===> passed OK\n"));
+	// CASE: KUndefinedCommand in ReadComplete
+	// note: keep this test right after CASE: check for ReadComplete
+	TEST_FOR_VALUE(scsiTest->iScsiProt->ReadComplete(KErrNone), KErrAbort);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EAbortedCommand, 0);
+	 __PRINT(_L("Case: error Undefined Command in ReadComplete ===> passed OK\n"));
+
+
+	// CASE: write after the end
+	writeBlocks = 10;
+	cmd.SetTransferLength (writeBlocks);
+	cmd.SetBlockAddress(maxNumBlocks - writeBlocks/2);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pWrite10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
+	 __PRINT(_L("Request to write AFTER the end of a media ===> passed OK\n"));
+	
+
+	// CASE: write from after the end
+	writeBlocks = 10;
+	cmd.SetTransferLength (writeBlocks);
+	cmd.SetBlockAddress(maxNumBlocks + writeBlocks/2);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pWrite10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
+	 __PRINT(_L("Request to start write AFTER the end of a media ===> passed OK\n"));
+	
+	
+	// CASE: check for internal buffer overflow (with offset)
+	// dev note: this check is specific to SCSI prot implementation
+	// 			 and NOT described by SBC-2 
+	//
+	// NOTE: Contrary to the the above comment, the USB Compliance Tests require this
+	//		 test case to pass, hence the EEinvalidFieldInCdb check has been removed
+	//
+	offsetBlocks = 1;
+	writeBlocks = static_cast<TUint16>(maxNumBlocks - offsetBlocks);
+	cmd.SetTransferLength (writeBlocks);
+	cmd.SetBlockAddress(offsetBlocks);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pWrite10Cmd), ETrue);
+//	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
+	 __PRINT(_L("Check for internal buffer overflow ===> passed OK\n"));
+
+	
+	// CASE: write max with offset (= offsetBlocks block)
+	offsetBlocks = 2;
+	//				max size in blocks supported by SCSI prot  - offsetBlocks
+	writeBlocks = static_cast<TUint16>((KMaxBufSize / KDefaultBlockSize) - offsetBlocks);
+	cmd.SetTransferLength (writeBlocks);
+	cmd.SetBlockAddress(offsetBlocks);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pWrite10Cmd), ETrue);
+	// complete read
+	TInt err = KErrCompletion;
+	do
+		{
+		err = scsiTest->iScsiProt->ReadComplete(KErrNone);
+		}
+	while(err == KErrCompletion);
+
+	TEST_FOR_VALUE(err, KErrNone);
+	{
+	TPtrC8 transportBuf (scsiTest->iTransport.iBufRead.Left(writeBlocks * KDefaultBlockSize));
+	TPtrC8 driveBuf(TPtrC8(scsiTest->iProxyDrive.iMediaBuf).Mid(offsetBlocks * KDefaultBlockSize, writeBlocks * KDefaultBlockSize));
+	// data should be identical
+	TEST_FOR_VALUE(driveBuf.Compare(transportBuf), 0);
+	}
+	 __PRINT(_L("Check for max write ===> passed OK\n"));
+
+
+	// CASE: boundary conditions
+	offsetBlocks = 0xFFFFFFFF;
+	writeBlocks = 0xFFFF;
+	cmd.SetTransferLength (writeBlocks);
+	cmd.SetBlockAddress(offsetBlocks);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pWrite10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
+	 __PRINT(_L("Check for boundary conditions ===> passed OK\n"));
+
+	
+	// CASE: try WrProtect
+	// dev note: scsi protocol doesn't support any value except 000b
+	cmd.SetProtect (1);
+	offsetBlocks = 1;
+	writeBlocks = 1;
+	cmd.SetTransferLength (writeBlocks);
+	cmd.SetBlockAddress(offsetBlocks);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pWrite10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
+	 __PRINT(_L("Check for WR Protect ===> passed OK\n"));
+
+
+	// CASE: invalid CAPs
+	cmd.SetProtect (0);
+	offsetBlocks = 1;
+	writeBlocks = 1;
+	cmd.SetTransferLength (writeBlocks);
+	cmd.SetBlockAddress (offsetBlocks);
+	// create error conditions in drive
+	TInt error = KErrNone;
+	CMassStorageDrive* pDrive = scsiTest->iDriveManager->Drive (CScsiTest::TestLun, error);
+	ASSERT (KErrNone == error && pDrive);
+	delete pDrive->iLocalDrive;
+	pDrive->iLocalDrive = NULL;
+	// ATTENTION: iLocalDrive is set to NULL
+	
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pWrite10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
+	 __PRINT(_L("Check for invalid caps ===> passed OK\n"));
+
+	// CASE: drive->Write() with errors in CScsiProtocol::ReadComplete()
+	// note: this case is trivial => no test case is required
+
+	// cleanup
+	CleanupStack::PopAndDestroy (1); // scsiTest
+	 __PRINT(_L("t_scsi_write ===> passed OK\n"));
+	}
+	
+	
+/**
+t_scsi_verify case
+*/
+GLDEF_C void t_scsi_verify()
+	{
+	test.Next (_L("t_scsi_verify\n"));
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+	// initialize Read/Write buffers
+	// I need identical initialization here because of specifics of a test
+	scsiTest->iProxyDrive.iMediaBuf.FillZ(KMaxBufSize * 2);
+	scsiTest->iTransport.iBufRead.FillZ(KMaxBufSize * 2);
+	// initialize 1/2 a buffer for testing
+	for (TInt i = 0; i<(TInt)KMaxBufSize; i++)
+		{
+		scsiTest->iTransport.iBufRead[i] = scsiTest->iProxyDrive.iMediaBuf[i] = static_cast<TUint8>(i%0x10);
+		}
+
+	
+	// SBC-2 p.68
+	// dev notes: latest implementation of scsi protocol supports only:
+	//			- Logical block address
+	//			- Transfer length
+	//			- VRPROTECT (only true or false)
+	//			- BYTCHK
+	//     all other fields are not supported
+	TReadWrite10Cmd cmd;
+	cmd.SetVerify(); 		// setup cmd with correct header
+	cmd.SetBytChk (ETrue);	// set BYTCHK
+	TPtrC8 pVerify10Cmd(cmd.iCmd);
+	
+	TUint16 maxNumBlocks = static_cast<TUint16>(scsiTest->iProxyDrive.iMediaBuf.Length() / KDefaultBlockSize);
+	TUint16 verifyBlocks = 1;
+	TUint32 offsetBlocks = 0;
+
+	// CASE: register drive; nothing to verify
+	scsiTest->MountTestDrive();
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pVerify10Cmd), ETrue);
+	 __PRINT(_L("Request to verify 0 bytes ===> passed OK\n"));
+
+
+	// CASE: verify min (1 block) with offset = 0
+	// NOTE: buffers are identical as per initialisation at the beginning
+	verifyBlocks = 1;
+	cmd.SetTransferLength (verifyBlocks);
+	cmd.SetBlockAddress(0);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pVerify10Cmd), ETrue);
+	// complete cmd
+	TEST_FOR_VALUE(scsiTest->iScsiProt->ReadComplete(KErrNone), KErrNone);
+	 __PRINT(_L("Request to verify 1 block @ offset 0 ===> passed OK\n"));
+	
+	
+	// CASE: verify after the end
+	verifyBlocks = 10;
+	cmd.SetTransferLength (verifyBlocks);
+	cmd.SetBlockAddress (maxNumBlocks - verifyBlocks/2);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pVerify10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
+	 __PRINT(_L("Request to verify AFTER the end of a media ===> passed OK\n"));
+	
+
+	// CASE: verify from after the end
+	verifyBlocks = 10;
+	cmd.SetTransferLength (verifyBlocks);
+	cmd.SetBlockAddress(maxNumBlocks + verifyBlocks/2);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pVerify10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
+	 __PRINT(_L("Request to start verify AFTER the end of a media ===> passed OK\n"));
+	
+	
+	// CASE: check for internal buffer overflow (with offset)
+	// dev note: this check is specific to SCSI prot implementation
+	// 			 and NOT described by SBC-2 
+	offsetBlocks = 1;
+	verifyBlocks = static_cast<TUint16>(maxNumBlocks - offsetBlocks);
+	cmd.SetTransferLength (verifyBlocks);
+	cmd.SetBlockAddress(offsetBlocks);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pVerify10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
+	 __PRINT(_L("Check for internal buffer overflow ===> passed OK\n"));
+
+	
+	// CASE: verify max with offset (= offsetBlocks block)
+	offsetBlocks = 2;
+	//				max size in blocks supported by SCSI prot  - offsetBlocks
+	verifyBlocks = static_cast<TUint16>((KMaxBufSize / KDefaultBlockSize) - offsetBlocks);
+	cmd.SetTransferLength (verifyBlocks);
+	cmd.SetBlockAddress(offsetBlocks);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pVerify10Cmd), ETrue);
+	// complete read
+	TEST_FOR_VALUE(scsiTest->iScsiProt->ReadComplete(KErrNone), KErrNone);
+	 __PRINT(_L("Check for max verify ===> passed OK\n"));
+
+
+	// CASE: boundary conditions
+	offsetBlocks = 0xFFFFFFFF;
+	verifyBlocks = 0xFFFF;
+	cmd.SetTransferLength (verifyBlocks);
+	cmd.SetBlockAddress(offsetBlocks);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pVerify10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
+	 __PRINT(_L("Check for boundary conditions ===> passed OK\n"));
+
+	
+	// CASE: VrProtect
+	// dev note: scsi protocol doesn't support any value except 000b
+	cmd.SetProtect (1);
+	offsetBlocks = 1;
+	verifyBlocks = 1;
+	cmd.SetTransferLength (verifyBlocks);
+	cmd.SetBlockAddress(offsetBlocks);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pVerify10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
+	// restore protect
+	cmd.SetProtect (0);
+	 __PRINT(_L("Check for VR Protect ===> passed OK\n"));
+
+
+	// CASE: BYTCHK
+	cmd.SetProtect (0);
+	cmd.SetBytChk (EFalse);
+	offsetBlocks = 1;
+	verifyBlocks = 1;
+	cmd.SetTransferLength (verifyBlocks);
+	cmd.SetBlockAddress (offsetBlocks);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pVerify10Cmd), ETrue);
+	// restore bytchk
+	cmd.SetBytChk (ETrue);
+	 __PRINT(_L("Check for BYTCHK ===> passed OK\n"));
+
+
+	// CASE: different read/write buffers => has to fail in Compare()
+	scsiTest->iTransport.iBufRead[2] = 0xFF;
+	scsiTest->iProxyDrive.iMediaBuf[2] = 0x0F;
+	verifyBlocks = 1;
+	cmd.SetTransferLength (verifyBlocks);
+	cmd.SetBlockAddress (0);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pVerify10Cmd), ETrue);
+	// complete cmd
+	TEST_FOR_VALUE (scsiTest->iScsiProt->ReadComplete(KErrNone), KErrAbort);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EMisCompare, 0);
+	 __PRINT (_L("Compare different read/write buffers ===> passed OK\n"));
+
+#ifdef _DEBUG
+	// CASE: out of memory check
+	verifyBlocks = 1;
+	cmd.SetTransferLength (verifyBlocks);
+	cmd.SetBlockAddress(0);
+	__UHEAP_FAILNEXT(1);
+	TEST_FOR_VALUE(scsiTest->DecodePacket (pVerify10Cmd), ETrue);
+	// complete cmd
+	TEST_FOR_VALUE(scsiTest->iScsiProt->ReadComplete(KErrNone), KErrAbort);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EAbortedCommand, TSenseInfo::EInsufficientRes);
+	__PRINT (_L("Out of memory check ===> passed OK\n"));
+#endif
+
+	// CASE: invalid CAPs
+	// 	Attention: This case changes internal state of a drive.
+	cmd.SetProtect (0);
+	offsetBlocks = 1;
+	verifyBlocks = 1;
+	cmd.SetTransferLength (verifyBlocks);
+	cmd.SetBlockAddress (offsetBlocks);
+	// create error conditions in drive
+	TInt error = KErrNone;
+	CMassStorageDrive* pDrive = scsiTest->iDriveManager->Drive (CScsiTest::TestLun, error);
+	ASSERT (KErrNone == error && pDrive);
+	delete pDrive->iLocalDrive;
+	pDrive->iLocalDrive = NULL;
+	// ATTENTION: iLocalDrive is set to NULL
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pVerify10Cmd), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
+	 __PRINT (_L("Check for invalid caps ===> passed OK\n"));
+
+	
+	// cleanup
+	CleanupStack::PopAndDestroy (1); // scsiTest
+	 __PRINT (_L("t_scsi_verify ===> passed OK\n"));
+	}
+	
+
+/**
+t_scsi_mode_sense case
+*/
+GLDEF_C void t_scsi_mode_sense()
+	{
+	test.Next (_L("t_scsi_mode_sense\n"));
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+	
+	// SPC-2 p.100
+	// dev notes: latest implementation of scsi protocol supports only:
+	// 		- PC field
+	//			- 00b	| supported 
+	//			- 10b	| in the same
+	//			- 11b	| manner
+	//			- 01b - NOT supported
+	//		- PAGE CODE (p. 189)
+	//			- 3Fh code ONLY
+	//
+	//  OUTPUT:
+	//		- device-specific parameter, field WP only (table 147, p.189 and table 101, p.107 in SBC-2)
+	// 		NOT supported:
+	//		- block descriptors are not supported (table 146)
+	//		- pages
+	
+	TModeSenseCmd cmd;
+	TPtrC8 pCmdModeSense (cmd.iCmd);
+	// expected response length is 16 bytes
+	TBuf8<4> response;
+	response.FillZ(4);
+	scsiTest->MountTestDrive();
+	
+	// CASE: PC = 0; page code = 3Fh, media is Write protected
+	cmd.SetPC (0x00);
+	cmd.SetPageCode (0x3F);
+	scsiTest->iProxyDrive.iCaps.iMediaAtt = KMediaAttWriteProtected;
+	TEST_FOR_VALUE (scsiTest->DecodePacket(pCmdModeSense), ETrue);
+	response = scsiTest->iTransport.iBufWrite;
+	// response has to have header only
+	TEST_FOR_VALUE (response[0],		3);		// length of the response - 1, (header only = 4) (see p.190)
+	TEST_FOR_VALUE (response[1],		0); 	// medium type
+	TEST_FOR_VALUE (response[2],		0x80); 	// device-specific parameter WP flag has to be set to 1, p107 in SBC-2
+	TEST_FOR_VALUE (response[3],		0); 	// block descriptor length
+	 __PRINT (_L("CASE: Code page 3Fh ===> passed OK\n"));
+
+	// CASE: PC = 10b; page code = 3Fh, media is Write protected
+	cmd.SetPC (0x02);	// default values
+	cmd.SetPageCode (0x3F);
+	TEST_FOR_VALUE (scsiTest->DecodePacket(pCmdModeSense), ETrue);
+	// default response has to have 00h in all fields
+	TBuf8<4> responseDefault;
+	responseDefault.FillZ(4);
+	responseDefault[0] = 3;	// size of a response
+	TEST_FOR_VALUE (scsiTest->iTransport.iBufWrite.Compare(responseDefault), 0); 
+	 __PRINT (_L("CASE: Page control 10b ===> passed OK\n"));
+	// CASE: PC = 10b; page code = 3Fh; media is NOT registered
+	// 			as per SBC-2 p.102: for PC = 10b:
+	//			"default values should be accessible even if the device is not ready"
+	scsiTest->DismountTestDrive();
+	TEST_FOR_VALUE (scsiTest->DecodePacket(pCmdModeSense), ETrue);
+	// default response has to have 00h in all fields
+	TEST_FOR_VALUE (scsiTest->iTransport.iBufWrite.Compare(responseDefault), 0); 
+	// restore drive 
+	scsiTest->MountTestDrive();
+	 __PRINT (_L("CASE: Page control 10b ===> passed OK\n"));
+
+
+	// CASE: PC = 11b; page code = 3Fh, media is Write protected
+	cmd.SetPC (0x03); // saved values
+	cmd.SetPageCode (0x3F);
+	TEST_FOR_VALUE (scsiTest->DecodePacket(pCmdModeSense), ETrue);
+	// response has to be identical to the original response
+	TEST_FOR_VALUE (scsiTest->iTransport.iBufWrite.Compare(response), 0); 
+	 __PRINT (_L("CASE: Page control 11b ===> passed OK\n"));
+
+
+	// CASE: PC = 0; page code = 3Fh, media is NOT Write protected
+	scsiTest->iProxyDrive.iCaps.iMediaAtt = 0; // reset a flag
+	cmd.SetPC (0x00);
+	cmd.SetPageCode (0x3F);
+	TEST_FOR_VALUE (scsiTest->DecodePacket(pCmdModeSense), ETrue);
+	TEST_FOR_VALUE (scsiTest->iTransport.iBufWrite[2], 0);	// WP is set to 0
+	 __PRINT (_L("CASE: Write not protected ===> passed OK\n"));
+
+
+	// CASE: PC = 0; page code = 0Ah (not supported)
+	cmd.SetPC (0x00);
+	cmd.SetPageCode (0x0A);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pCmdModeSense), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
+	 __PRINT (_L("CASE: unsupported page code ===> passed OK\n"));
+
+	
+	// CASE: PC = 01b (not supported); page code = 3Fh 
+	cmd.SetPC (0x01);	// changable values
+	cmd.SetPageCode (0x3F);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pCmdModeSense), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
+	 __PRINT (_L("CASE: unsupported page control ===> passed OK\n"));
+	
+		
+	// cleanup
+	CleanupStack::PopAndDestroy (1); // scsiTest
+	 __PRINT (_L("t_scsi_mode_sense ===> passed OK\n"));
+	}
+	
+	
+/**
+t_scsi_media_change case
+*/
+GLDEF_C void t_scsi_media_change()
+	{
+	test.Next (_L("t_scsi_media_change\n"));
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+	
+	// CASE: iMediaRemoved
+	scsiTest->MountTestDrive();
+	// issue Inquiry cmd
+	TInquiryCmd cmdInquiry;
+	TPtrC8 pInquiry(cmdInquiry.iCmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket(pInquiry), ETrue);
+	// simulate media changed
+	mediaChanged = ETrue;
+	// issue TEST UNIT READY
+	TTestUnitReadyCmd cmdReady;
+	TPtrC8 pReady(cmdReady.iCmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket(pReady), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EUnitAttention, TSenseInfo::ENotReadyToReadyChange);
+
+
+	// repeat with prevent allow media removal
+	mediaChanged = ETrue;
+	TMediaRemovalCmd cmdAllow;
+	TPtrC8 pAllow(cmdAllow.iCmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket(pAllow), EFalse);
+	TEST_SENSE_CODE_IF_SUPPORTED(scsiTest->GetSenseCodePtr(), TSenseInfo::EUnitAttention,
+			TSenseInfo::ENotReadyToReadyChange)
+		{
+		// yet another test...
+		TEST_FOR_VALUE (scsiTest->DecodePacket(pAllow), ETrue);
+		}
+
+	// cleanup
+	mediaChanged = EFalse;
+	CleanupStack::PopAndDestroy (1); // scsiTest
+	 __PRINT (_L("t_scsi_media_change ===> passed OK\n"));
+	}
+	
+	
+/**
+t_scsi_read_capacity case
+*/
+GLDEF_C void t_scsi_read_capacity()
+	{
+	test.Next (_L("t_scsi_read_capacity\n"));
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+	
+	// SBC-2 p.56
+	// dev notes: LOGICAL BLOCK ADDRESS and PMI have to be set to 00h
+	//		as a limitation from scsi prot.
+
+	TReadCapacityCmd cmdReadCapacity;
+	TPtrC8 pReadCapacity(cmdReadCapacity.iCmd);
+	scsiTest->MountTestDrive();
+	// CASE: default media settigns
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pReadCapacity), ETrue);
+	// compare values
+	{
+	TReadCapacityResponse response (scsiTest->iTransport.iBufWrite);
+	TEST_FOR_VALUE (response.Length(),			8);
+	TEST_FOR_VALUE (I64HIGH(scsiTest->iProxyDrive.iCaps.MediaSizeInBytes()),	0);
+	TEST_FOR_VALUE (response.LBAddress(),		I64LOW(scsiTest->iProxyDrive.iCaps.MediaSizeInBytes()) / response.BlockLength() - 1); // number of blocks - 1
+	TEST_FOR_VALUE (response.BlockLength(),		512); // FAT
+	}
+	 __PRINT (_L("default settings ===> passed OK\n"));
+	
+	
+	// CASE: unsupported LOGICAL BLOCK ADDRESS
+	cmdReadCapacity.iCmd[6] = 0x10;	// set some value
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pReadCapacity), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
+	// reset
+	cmdReadCapacity.iCmd[6] = 0x00;	// set some value
+	__PRINT (_L("unsupported LOGICAL BLOCK ADDRESS ===> passed OK\n"));
+	
+	
+	// CASE: PMI
+	cmdReadCapacity.iCmd[9] = 0x01;	// set field
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pReadCapacity), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
+	// reset
+	cmdReadCapacity.iCmd[9] = 0x00;
+	__PRINT (_L("unsupported PMI ===> passed OK\n"));
+	
+
+	// CASE: Huge size
+	scsiTest->iProxyDrive.iCaps.iNumberOfSectors   = 0xF0F0F0F0;
+	scsiTest->iProxyDrive.iCaps.iSectorSizeInBytes = 0x200;
+	scsiTest->iProxyDrive.iCaps.iNumPagesPerBlock  = 2;
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pReadCapacity), ETrue);
+	// compare values
+	TReadCapacityResponse response (scsiTest->iTransport.iBufWrite);
+	TEST_FOR_VALUE (response.Length(),			8);
+	TEST_FOR_VALUE (response.LBAddress(),		0xFFFFFFFF);
+	TEST_FOR_VALUE (response.BlockLength(),		512);
+	// reset
+	scsiTest->iProxyDrive.iCaps.iNumberOfSectors = 0;
+	 __PRINT (_L("huge media size ===> passed OK\n"));
+
+	// cleanup
+	CleanupStack::PopAndDestroy (1); // scsiTest
+	 __PRINT (_L("t_scsi_read_capacity ===> passed OK\n"));
+	}
+	
+	
+/**
+t_scsi_bad_lun case
+ Issue ALL supported SCSI commsnds with unsupported LUN
+*/
+GLDEF_C void t_scsi_bad_lun()
+	{
+	test.Next (_L("t_scsi_bad_lun\n"));
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+	// mount a drive on different lun
+	// all DecodePacket requests will go on TestLun
+	scsiTest->MountTestDrive ();
+	// set test lun to unsupported LUN
+	// note: CScsiTest::TestLun has to be restored at the end of a test
+	CScsiTest::TestLun = 10;
+	
+	
+	// CASE: Inquiry
+	// not applicable here
+
+
+	// CASE: Request sense
+	// not applicable
+
+
+	// CASE: Mode sense
+	TModeSenseCmd cmdModeSense;
+	cmdModeSense.SetPC (0x00);
+	cmdModeSense.SetPageCode (0x3F);
+	TPtrC8 pModeSense(cmdModeSense.iCmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pModeSense), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
+
+	
+	// CASE: Read capacity
+	TReadCapacityCmd cmdReadCapacity;
+	TPtrC8 pReadCapacity(cmdReadCapacity.iCmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pReadCapacity), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
+
+	
+	// CASE: Start stop unit
+	// not applicable here
+
+
+	// CASE: Prevent allow media removal
+	TMediaRemovalCmd cmdMediaRemoval;
+	TPtrC8 pMediaRemoval (cmdMediaRemoval.iCmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pMediaRemoval), EFalse);
+	TEST_SENSE_CODE_IF_SUPPORTED(scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported) {}
+
+	
+	// CASE: Read
+	TReadWrite10Cmd cmdRead;
+	cmdRead.SetRead();
+	cmdRead.SetTransferLength(2);
+	TPtrC8 pRead (cmdRead.iCmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pRead), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
+
+	
+	// CASE: Write
+	TReadWrite10Cmd cmdWrite;
+	cmdWrite.SetWrite();
+	cmdWrite.SetTransferLength(2);
+	TPtrC8 pWrite (cmdWrite.iCmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pWrite), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
+
+	
+	// CASE: Verify
+	TReadWrite10Cmd cmdVerify;
+	cmdVerify.SetVerify();
+	cmdVerify.SetTransferLength(2);
+	TPtrC8 pVerify (cmdVerify.iCmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pVerify), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
+	
+	
+	// CASE: Test unit ready
+	// Dev. note: this case has to be last as it tries to connect the drive
+	TTestUnitReadyCmd cmdTestUnitReady;
+	TPtrC8 pTestUnitReady(cmdTestUnitReady.iCmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pTestUnitReady), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
+	
+	
+	// cleanup
+	CleanupStack::PopAndDestroy (1); // scsiTest
+	__PRINT (_L("t_scsi_bad_lun ===> passed OK\n"));
+	// restore
+	CScsiTest::TestLun = 1;
+	}
+	
+/**
+t_scsi_unsupported_commands
+ Issue several unsupported SCSI commsnds
+*/
+GLDEF_C void t_scsi_unsupported_commands()
+	{
+	test.Next (_L("t_scsi_unsupported_commands\n"));
+	CScsiTest* scsiTest = CScsiTest::NewLC();
+	scsiTest->MountTestDrive ();
+
+	
+	// CASE: format unit cmd	
+	TBuf8<7> cmd;
+	cmd.FillZ(7);
+	cmd[0] = 0x06;		// size of a command itself
+	cmd[1] = 0x04;		// FORMAT UNIT command
+	TPtrC8 pFormat(cmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pFormat), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidCmdCode);
+
+	// CASE: READ(6)
+	cmd[1] = 0x08;		// READ(6) command
+	TPtrC8 pRead(cmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pRead), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidCmdCode);
+	
+	// CASE: WRITE(6)
+	cmd[1] = 0x0A;		// WRITE(6) command
+	TPtrC8 pWrite(cmd);
+	TEST_FOR_VALUE (scsiTest->DecodePacket (pWrite), EFalse);
+	TEST_SENSE_CODE (scsiTest->GetSenseCodePtr(), TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidCmdCode);
+
+	// cleanup
+	CleanupStack::PopAndDestroy (1); // scsiTest
+	__PRINT (_L("t_scsi_unsupported_commands ===> passed OK\n"));
+	}
+
+	
+/**
+Entry point for all SCSI protocol test case
+*/
+GLDEF_C void t_scsi_prot()
+	{
+	
+	__UHEAP_MARK;
+
+	t_scsi_inquiry_normal();
+	
+	t_scsi_inquiry_error();
+	
+	t_scsi_test_unit_ready();
+	
+	t_scsi_prevent_allow_media_removal();
+	
+	t_scsi_start_stop_unit();
+	
+	t_scsi_request_sense();
+	
+	t_scsi_read();
+	
+	t_scsi_write();
+	
+	t_scsi_verify();
+	
+	t_scsi_mode_sense();
+	
+	t_scsi_media_change();
+	
+	t_scsi_read_capacity();
+	
+	t_scsi_bad_lun();
+	
+	t_scsi_unsupported_commands();
+	
+	__UHEAP_MARKEND;
+
+	__PRINT (_L("t_scsi_prot test completed O.K\n"));
+	}
+
+
+//
+// CScsiTest implementation
+//
+/**
+c'tor
+*/
+CScsiTest::CScsiTest()
+	: iDriveManager(NULL),
+	  iScsiProt(NULL)
+	{}
+	
+/**
+d'tor
+*/
+CScsiTest::~CScsiTest()
+	{
+	iDriveMap.Close();
+	delete iDriveManager;
+	delete iScsiProt;
+	}
+	
+/**
+NewLC
+@return instance of CScsiTest
+*/
+CScsiTest* CScsiTest::NewLC()
+	{
+	CScsiTest* self = new (ELeave) CScsiTest();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	
+	return self;
+	}
+
+/**
+ConstructL
+*/
+void CScsiTest::ConstructL()
+	{
+	__PRINT(_L("CScsiTest::ConstructL\n"));
+	
+	for(TInt i=0; i<KMaxLuns; i++)
+		{
+		iDriveMap.AppendL(EDriveA+i);
+		}
+	
+	iDriveManager = CDriveManager::NewL (iDriveMap);
+	iScsiProt = CScsiProtocol::NewL(*iDriveManager);
+	iScsiProt->RegisterTransport(&iTransport);
+	
+	TInt err = KErrNone;
+	CMassStorageDrive* drive = iDriveManager->Drive(TestLun, err);
+	ASSERT(!err && drive);
+	
+	// let's set proxy drive
+	drive->SetMountState(CMassStorageDrive::EDisconnected, NULL);
+	}
+
+/**
+Requests of Sense data
+@return TPtrC8 pointer to SenseData
+*/
+TPtrC8& CScsiTest::GetSenseCodePtr()
+	{
+	__PRINT(_L("CScsiTest::GetSenseCodePtr\n"));
+	
+	TBuf8<7> buf;
+	buf.FillZ(7);
+	buf[0] = 0x06;	// size of a command itself
+	buf[1] = 0x03; 	// inquiry operation code
+	// Note: SCSI protocol supprts 0x70 byte response format only
+	buf[4] = 0x70;
+	buf[5] = 18;   //expected answer's length
+	TPtrC8 pBuf(buf);
+	TEST_FOR_VALUE(iScsiProt->DecodePacket(pBuf, TestLun), ETrue);
+
+	return iTransport.iBufWrite;
+	}
+
+
+/**
+Mounts test drive, which is defined by CScsi::TestLun
+*/
+void CScsiTest::MountTestDrive ()
+	{
+	TInt error = 0;
+	CMassStorageDrive* pDrive = iDriveManager->Drive (CScsiTest::TestLun, error);
+	if(!pDrive || error)
+		{
+		__PRINT(_L("Error: Can't get test drive\n"));
+		test(EFalse);
+		return;
+		}
+	// SCSI prot checks mount and drive states
+	
+	pDrive->SetMountConnected(iProxyDrive, mediaChanged);
+	
+	pDrive->SetDriveState(CMassStorageDrive::EIdle);
+	}
+
+
+/**
+Mounts test drive, which is defined by CScsi::TestLun
+*/
+void CScsiTest::DismountTestDrive()
+	{
+	TInt error = 0;
+	CMassStorageDrive* pDrive = iDriveManager->Drive (CScsiTest::TestLun, error);
+	if(!pDrive || error)
+		{
+		__PRINT(_L("Error: Can't get test drive\n"));
+		test(EFalse);
+		return;
+		}
+	// SCSI prot checks mount and drive states
+	pDrive->SetMountDisconnected();
+	pDrive->SetDriveState(CMassStorageDrive::EMediaNotPresent);
+	}
+
+
+/**
+@return Pointer to test drive, which is defined by CScsi::TestLun
+*/
+CMassStorageDrive* CScsiTest::TestDrive()
+	{
+	TInt error = 0;
+	CMassStorageDrive* pDrive = iDriveManager->Drive(TestLun, error);
+	if(!pDrive || error)
+		{
+		__PRINT(_L("Error: Can't get test drive\n"));
+		ASSERT(EFalse);
+		return NULL;
+		}
+	return pDrive;
+	}