--- /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;
+ }