diff -r 000000000000 -r 96e5fb8b040d kerneltest/e32test/lffs/t_lfsdrv2.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/lffs/t_lfsdrv2.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,1177 @@ +// Copyright (c) 1996-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: +// e32test\lffs\t_lfsdrv2.cpp +// Test the LFFS Flash media driver +// +// + +#include +#include +#include +#include +#include +#include "u32std.h" +#include "..\misc\prbs.h" + +_LIT(KTestName,"T_LFSDRV"); +_LIT(KMediaDriverName,"MEDLFS"); +_LIT(KDot,"."); +_LIT(KSemiColon,";"); + +RTest test(KTestName); +TBusLocalDrive Drive; +TInt DriveNumber; +TLocalDriveCapsV7 DriveCaps; // Required for M18 devices +TBool ChangedFlag; +TUint32 EbSz; +TUint32 Size; + +const TInt KBufferSize=4096; +const TInt KBigBufferSize=4096*4; +TUint8 Buffer[KBigBufferSize]; + +#ifdef _DEBUG +/*************************************************** + * ControlIO command types - for debug builds, only + ***************************************************/ +enum TCtrlIoTypes + { + ECtrlIoRww=0, + ECtrlIoTimeout=1 + }; +// Used only for the ControlIO tests +#define TYAX_PARTITION_SIZE 0x00200000 // Partition size for TYAX is 1MB; 2 devices in parallel +#endif + + +/****************************************************************************** + * Extra thread for background erase + ******************************************************************************/ +struct SEraseInfo + { + TInt iFirstBlock; + TInt iNumBlocks; + }; + +volatile TInt Block; +TInt EraseThreadFn(TAny* aPtr) + { + SEraseInfo& e=*(SEraseInfo*)aPtr; + TInt r=KErrNone; + for (Block=e.iFirstBlock; Block exitCat=EraseThread.ExitCategory(); + if((exitType!= EExitKill)||(exitReason!=KErrNone)) + { + test.Printf(_L("Async erase error: %d, block %d\n"),EraseStatus.Int(),Block); + test.Printf(_L("Thread exit reason: %d,%d,%S\n"),exitType,exitReason,&exitCat); + test(0); + } + EraseThread.Close(); + + TUint32 pos=EraseInfo.iFirstBlock*EbSz; + TUint32 endpos=pos+EraseInfo.iNumBlocks*EbSz; + test.Printf(_L("\nAsync erase completed; verifying...\n")); + for (; pos exitCat=WriteThread.ExitCategory(); + if((exitType!= EExitKill)||(exitReason!=KErrNone)) + { + test.Printf(_L("Async Write error: %d, block %d\n"),WriteStatus.Int(),Block); + test.Printf(_L("Thread exit reason: %d,%d,%S\n"),exitType,exitReason,&exitCat); + test(0); + } + WriteThread.Close(); + // No verification performed + test.Printf(_L("\n")); + return KErrNone; + } + +/****************************************************************************** + * Control mode and Object mode test functions + ******************************************************************************/ +TInt DoControlModeWriteAndVerify(TUint32 aPattern, TUint32 aStartOffset) + { + // Writes 4K bytes of a given pattern to the "A" half of programming regions, + // starting at the specified offset, then reads the data back to verify it + + TUint32* pB=(TUint32*)(Buffer); + TUint32* pE=(TUint32*)(Buffer + KBufferSize); + TInt r=KErrNone; + + // Fill the entire buffer with an initial value + while (pBDriveCaps.iObjectModeSize) + { + test.Printf(_L("ERROR: DoObjectModeWriteAndVerify - aSize=%x is greater than max (%x)\n"),aSize,DriveCaps.iObjectModeSize); + return KErrArgument; + } + // write the data + TUint seed[2]; + seed[0]=0xb17217f8; + seed[1]=0; + TInt64 pos64 = MAKE_TINT64(0, aOffset); + TPtrC8 ptr(Buffer,aSize); + TUint32* pB=(TUint32*)Buffer; + TUint32* pE=(TUint32*)(Buffer+aSize); + while (pB>>\r\n")); + FOREVER + { + TChar c=(TUint)test.Getch(); + c.UpperCase(); + DriveNumber=((TUint)c)-'C'; + if (DriveNumber>=0&&DriveNumber<='C'+ 8) + break; + } + + test.Next(_L("Load media driver")); + TInt r=User::LoadPhysicalDevice(KMediaDriverName); + test(r==KErrNone || r==KErrAlreadyExists); + + test.Next(_L("Connect to drive")); + r=Drive.Connect(DriveNumber,ChangedFlag); + test(r==KErrNone); + test.Next(_L("Get capabilities")); + + DriveCaps.iControlModeSize=0; // If test invoked for a chip other than Sibley then this element will not be updated + DriveCaps.iObjectModeSize=0; // If test invoked for a chip other than Sibley then this element will not be updated + TPckg capsPckg(DriveCaps); + r=Drive.Caps(capsPckg); + + test(r==KErrNone); + test.Printf(_L("Size : %08x\n"),I64LOW(DriveCaps.iSize)); + test.Printf(_L("Type : %d\n"),DriveCaps.iType); + test.Printf(_L("BatState : %d\n"),DriveCaps.iBattery); + test.Printf(_L("DriveAtt : %02x\n"),DriveCaps.iDriveAtt); + test.Printf(_L("MediaAtt : %02x\n"),DriveCaps.iMediaAtt); + test.Printf(_L("BaseAddress : %08x\n"),DriveCaps.iBaseAddress); + test.Printf(_L("FileSysID : %d\n"),DriveCaps.iFileSystemId); + test.Printf(_L("Hidden sectors : %d\n"),DriveCaps.iHiddenSectors); + test.Printf(_L("Erase block size: %d\n"),DriveCaps.iEraseBlockSize); + + test.Printf(_L("Partition size: %d\n"),DriveCaps.iPartitionSize); + test.Printf(_L("Control Mode size: %d\n"),DriveCaps.iControlModeSize); + test.Printf(_L("Object Mode size: %d\n"),DriveCaps.iObjectModeSize); + test.Printf(_L("Press any key...\n\n")); + test.Getch(); + + test(DriveCaps.iDriveAtt==(KDriveAttLocal|KDriveAttInternal)); + test((DriveCaps.iMediaAtt&KMediaAttFormattable)==(KMediaAttFormattable)); // Apply mask since other flags may be set + +#if defined(_DEBUG) && defined(_WINS) +/****************************************************************************** + * Simulate device timeout + ******************************************************************************/ + test.Next(_L("Timeout")); + EbSz=DriveCaps.iEraseBlockSize; + r=Drive.Format(0,EbSz); + test(r==KErrNone); + r=Drive.ControlIO(ECtrlIoTimeout, NULL, NULL); + + if(r!=KErrNotSupported) + { + if(r==KErrNone) + { + // Test timeout behaviour for Write operation + TPtrC8 ptr(Buffer,1); + r=Drive.Write(0,ptr); + test(r==KErrNotReady); + // Test condition now cleared, ensure normal operation is OK + r=Drive.Write(0,ptr); + test(r==KErrNone); + // Test timeout behaviour for Format operation + r=Drive.ControlIO(ECtrlIoTimeout, NULL, NULL); + test(r==KErrNone); + r=Drive.Format(0,EbSz); + test(r==KErrNotReady); + // Cleanup + r=Drive.Format(0,EbSz); + test(r==KErrNone); + } + else + { + test.Printf(_L("Timeout ControlIO failed initialisation\n")); + test(0); // Cannot proceed with this test + } + } + else + { + test.Printf(_L("Timeout ControlIO not supported\n")); + } + + test.Printf(_L("Press any key...\n")); + test.Getch(); +#endif + + /****************************************************************************** + * Formatting + ******************************************************************************/ + test.Next(_L("Format")); + TUint32 pos; + EbSz=DriveCaps.iEraseBlockSize; + Size=I64LOW(DriveCaps.iSize); +// Reduce size so test doesn't take forever + if (Size>8*EbSz) + Size=8*EbSz; + + for (pos=0; pos 0) + { + pB=(TUint32*)Buffer; + for(i=0; i< KBufferSize; i+=(DriveCaps.iControlModeSize*2)) + { + pB = (TUint32 *)((TUint32)pB + DriveCaps.iControlModeSize); + for (b=0; b < DriveCaps.iControlModeSize; b+=4) + { + *pB = 0xFFFFFFFF; + pB++; + } + } + } + +#if 0 + // Debug - print content of buffer + test.Printf(_L("Content of buffer after inserting 0xFFFFFFFFs follows\n")); + i=0; + TUint32* verifyPtr=(TUint32*)Buffer; + while(i 0) + { + pB=(TUint32*)Buffer; + for(i=0; i< KBufferSize; i+=(DriveCaps.iControlModeSize*2)) + { + for (b=0; b< DriveCaps.iControlModeSize; b+=4) + { + ex=Random(seed); + if(*pB++ != ex) + { + test.Printf(_L("ERROR: addr %08x data %08x expected %08x\n"),pB,*pB,ex); + break; + } + } + for (b=0; b< DriveCaps.iControlModeSize; b+=4) + { + ex=Random(seed); + if(*pB++ != 0xFFFFFFFF) + { + test.Printf(_L("ERROR: addr %08x data %08x expected 0xFF\n"),pB,*pB); + break; + } + } + if (!((i+1)%64)) + test.Printf(KDot); + + } + } + else + { + while (pBremain) + l=remain; + TInt pos=0; + if(DriveCaps.iObjectModeSize == 0) + { + pos=KBigBufferSize-remain; + } + + TPtrC8 ptr(Buffer+(KBigBufferSize-remain),l); + TInt64 pos64(pos+objectModeOffset); // Start writes in a new programming region if object mode supported + r=Drive.Write(pos64,ptr); + test(r==KErrNone); + objectModeOffset+=DriveCaps.iObjectModeSize; + remain-=l; + test.Printf(KDot); + } + test.Printf(_L("\n")); + test.Next(_L("Verify")); + Mem::FillZ(Buffer,KBigBufferSize); + new (&buf) TPtr8(Buffer,0,KBigBufferSize); + if(DriveCaps.iObjectModeSize==0) + { + r=Drive.Read(0,KBigBufferSize,buf); + test(r==KErrNone); + + } + else + { + remain=KBigBufferSize; + objectModeOffset=0; + + while(remain && writeCount) + { + TInt totalLength=0; + TInt l=1+(Random(seed)&255); // random length between 1 and 256 + if (l>remain) + l=remain; + TPtr8 ptr(Buffer+(totalLength),l); + r=Drive.Read(objectModeOffset,l,ptr); + test(r==KErrNone); + totalLength +=l; + remain-=l; + writeCount--; + test.Printf(KDot); + } + } + + seed[0]=0xdeadbeef; + seed[1]=0; + pB=(TUint32*)Buffer; + ex=0; + if(DriveCaps.iObjectModeSize==0) + { + while (pB>2); i++) + { + test.Printf(_L("%d Buffer Content %08x %08x Flash Content\n"),i, pB[i], pE[i]); + } + } +#endif + test (r==KErrNone); + test.Printf(KSemiColon); + } + + r=WaitForAsyncErase(); + test(r==KErrNone); + + r=Drive.Format(0,EbSz); + r=Drive.Format(DriveCaps.iEraseBlockSize,EbSz); + test.Printf(_L("Press any key...\n\n")); + test.Getch(); + +// Perform the following tests for debug builds, only + +#ifdef _DEBUG + +/****************************************************************************** + * Concurrent operations to exercise TYAX Read-While-Write capability + * First, show read while write denied when attempting to read from a partition + * that is being written to + * Second, show read while write proceeding when reading from a partition other + * than that which is being written to + ******************************************************************************/ + + // Do not perform these tests unless read-while-write is supported + if(DriveCaps.iMediaAtt&KMediaAttReadWhileWrite) + { + test.Next(_L("Denied read while write")); + r=Drive.ControlIO(ECtrlIoRww, NULL, NULL); + if(r!=KErrNone) + { + test.Printf(_L("ControlIO not ready, returned %d\n"), r); + test(0); // Cannot proceed with this test + } + test.Printf(_L("Press any key...\n")); + test.Getch(); + + test.Printf(_L("Starting async write for the first RWE/RWW test")); + r=StartAsyncWrite(1,3); // Write to the first three blocks, only, to limit duration + test(r==KErrNone); + + // Allow the write thread to be created and ready to run + // This will ensure that the driver will have received a write request before the second of the read + // requests, below. Following the issue of the ControlIO command, above, the driver will not instigate + // the write request until the next (second) read request is received. This is done so that the high priority + // driver thread recognises the existence of a read request (from a lower priority test / user thread) + // before it executes a sequence of writes to the FLASH device. This is necessary because, although + // each write takes a finite amount of time, the poll timer expires so quickly that the driver thread + // would not be blocked for a sufficiently long period to allow the read request to be processed. Adopting + // the contrived, and artificial, approach of using ControlIO to 'stage' the write allows the read-while-write + // capability of the device to be execrised. + User::After(1000); + + test.Printf(_L("Starting concurrent loop for background write\n")); + { + // First read - this will be performed before the write thread is run, so does + // not exercise read while write. + TInt64 pos64 = MAKE_TINT64(0,0); + TPtr8 rptr(Buffer+KBufferSize,0,KBufferSize); + test.Printf(_L("Issuing Drive.Read 1\n")); + r=Drive.Read(pos64,KBufferSize,rptr); + test(r==KErrNone); + test.Printf(KSemiColon); + } + { + // Second read - to same partition (and block) as the active write + // This read should be deferred by the driver + TInt64 pos64 = MAKE_TINT64(0, 2*EbSz); + TPtr8 rptr(Buffer+KBufferSize,0,KBufferSize); + test.Printf(_L("Issuing Drive.Read 2\n")); + r=Drive.Read(pos64,KBufferSize,rptr); // Should collide with second write + test(r==KErrNone); + test.Printf(KSemiColon); + } + { + // Third read - due to the tight poll timer period, this will not be scheduled + // until the write request has completed - so does not exercise read while write. + TInt64 pos64 = MAKE_TINT64(0, DriveCaps.iPartitionSize); + TPtr8 rptr(Buffer+KBufferSize,0,KBufferSize); + test.Printf(_L("Issuing Drive.Read 3\n")); + r=Drive.Read(pos64,KBufferSize,rptr); + test(r==KErrNone); + test.Printf(KSemiColon); + } + + r=WaitForAsyncWrite(); + test(r==KErrNone); + + /////////////////////////////////////////////////////////////////////////////// + r=Drive.Format(0,EbSz); + r=Drive.Format(DriveCaps.iEraseBlockSize,EbSz); + r=Drive.Format((DriveCaps.iEraseBlockSize*2),EbSz); + r=Drive.Format((DriveCaps.iEraseBlockSize*3),EbSz); + test.Printf(_L("Press any key...\n")); + test.Getch(); + test.Next(_L("Supported read while write")); + r=Drive.ControlIO(ECtrlIoRww, NULL, NULL); + if(r!=KErrNone) + { + test.Printf(_L("ControlIO not ready\n")); + return r; + } + test.Printf(_L("Press any key...\n")); + test.Getch(); + + test.Printf(_L("Starting async write for the second RWE/RWW test")); + r=StartAsyncWrite(1,3); // Write to the first three blocks, only, to limit duration + test(r==KErrNone); + + // Allow the write thread to be created and ready to run + User::After(1000); + + test.Printf(_L("Starting concurrent loop for background write\n")); + { + // First read - this will be performed before the write thread is run, so does + // not exercise read while write. + TInt64 pos64 = MAKE_TINT64(0, DriveCaps.iPartitionSize); + TPtr8 rptr(Buffer+KBufferSize,0,KBufferSize); + test.Printf(_L("Issuing Drive.Read 1\n")); + r=Drive.Read(pos64,KBufferSize,rptr); + test(r==KErrNone); + test.Printf(KSemiColon); + } + { + // Second read - to different partition than that targeted by the active write + // This read should check the overlap and proceed without being deferred + TInt64 pos64 = MAKE_TINT64(0, DriveCaps.iPartitionSize); + TPtr8 rptr(Buffer+KBufferSize,0,KBufferSize); + test.Printf(_L("Issuing Drive.Read 2\n")); + r=Drive.Read(pos64,KBufferSize,rptr); // Should collide with second write + test(r==KErrNone); + test.Printf(KSemiColon); + } + { + // Third read - due to the tight poll timer period, this will not be scheduled + // until the write request has completed - so does not exercise read while write. + TInt64 pos64 = MAKE_TINT64(0, DriveCaps.iPartitionSize); + TPtr8 rptr(Buffer+KBufferSize,0,KBufferSize); + test.Printf(_L("Issuing Drive.Read 3\n")); + r=Drive.Read(pos64,KBufferSize,rptr); + test(r==KErrNone); + test.Printf(KSemiColon); + } + + test.Printf(_L("\nForeground Read OK\n")); + r=WaitForAsyncWrite(); + test(r==KErrNone); + } +#endif + + // Clean up + r=Drive.Format(0,EbSz); + r=Drive.Format(DriveCaps.iEraseBlockSize,EbSz); + r=Drive.Format((DriveCaps.iEraseBlockSize*2),EbSz); + r=Drive.Format((DriveCaps.iEraseBlockSize*3),EbSz); + +/***************************************************************************************************** + Tests for M18 NOR Flash devices + + These tests assume that object mode and control mode is supported + *****************************************************************************************************/ + if((DriveCaps.iControlModeSize !=0) && (DriveCaps.iObjectModeSize != 0)) + { + // Control mode writes + // Prove that control mode writes are supported + // This requires that data is formatted such that areas coinciding with the "B" Half of a + // programming region are set to all 0xFFs + // Write to programming region zero + test.Next(_L("\nControl mode writes")); + + r=DoControlModeWriteAndVerify(0xa5a5a5a5, 0); + test(r==KErrNone); + // Now verify that data written in control mode can be further modified + // Do this by ANDing the read-back pattern with a mask that clears particular bits + // then write the resulting pattern back to the region + r=DoControlModeWriteAndVerify(0x84848484, 0); + test(r==KErrNone); + // Now verify that data written in control mode can be further modified to all 0x00s + // Do this by ANDing the read-back pattern with a mask that clears the remaining bits + // then write the resulting pattern back to the region + r=DoControlModeWriteAndVerify(0x00000000, 0); + test(r==KErrNone); + // Erase the block before attempting to re-use the programming region for object mode writing + test.Printf(_L("\nErase block 0 before object mode write")); + r=Drive.Format(0,EbSz); + test(r==KErrNone); + + test.Next(_L("\n(Subsequent) Object mode writes")); + + // Control mode writes + // Prove that object mode writes are allowd to an erased block that was previously + // used in control mode + // Use offset zero and length equal to one-quarter of the allowed object mode size (i.e. one- + // quarter of the lengh of the programming region) (The write test, above, wrote an entire region + // in object mode) + test.Printf(_L("\nObject mode write, object mode size=%d"),DriveCaps.iObjectModeSize); + r=DoObjectModeWriteAndVerify(0, (DriveCaps.iObjectModeSize>>2)); + test(r==KErrNone); + // Prove that an attempt to append data to an object mode region fails + test.Printf(_L("\nAttempt append to object mode region")); + r=DoObjectModeWriteAndVerify((DriveCaps.iObjectModeSize>>2),(DriveCaps.iObjectModeSize>>2)); + test(r==KErrGeneral); + // Erase the block after a failed write and before attempting to re-use for programming + test.Printf(_L("\nErase block 0 after failed object mode write")); + r=Drive.Format(0,EbSz); + test(r==KErrNone); + + test.Next(_L("\n(Subsequent) Object mode writes following an error")); + + // write to a new object mode region after a failed write and before attempting to erase the block + // Prove that erase block can be re-written to + test.Printf(_L("\nObject mode write following failed write and erase")); + r=DoObjectModeWriteAndVerify(0, (DriveCaps.iObjectModeSize>>2)); + test(r==KErrNone); + // Cause a failed object mode write + r=DoObjectModeWriteAndVerify(0, (DriveCaps.iObjectModeSize>>2)); + test(r==KErrGeneral); + // the status register has an error. Attempt to write in a new region and ensure that it succeeds + r=DoObjectModeWriteAndVerify(DriveCaps.iObjectModeSize, DriveCaps.iObjectModeSize); + test(r==KErrNone); + + test.Next(_L("\n(Subsequent) Control mode writes following previous use in object mode")); + + // Re-use a former object mode region for control mode writes + // Erase the block after a failed write and before attempting to re-use for programming + r=Drive.Format(0,EbSz); + test(r==KErrNone); + r=DoControlModeWriteAndVerify(0xa5a5a5a5, 0); + test(r==KErrNone); + // Verify that data written in control mode can be further modified + r=DoControlModeWriteAndVerify(0x84848484, 0); + test(r==KErrNone); + + test.Next(_L("\n(Subsequent) Control mode writes following an error")); + + // Test that a control mode write can succeed after a previous error + // Use a failed object mode write attempt to the "B" half of a control mode region + // to cause the error + r=DoObjectModeWriteAndVerify(DriveCaps.iControlModeSize,(DriveCaps.iObjectModeSize>>2)); + test(r==KErrGeneral); + r=DoControlModeWriteAndVerify(0x00000000, 0); + test(r==KErrNone); + + test.Next(_L("\nControl mode boundary write test")); + + r=DoControlModeBoundaryWriteAndVerify(); + test(r==KErrNone); + + } + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + test.Printf(_L("Press any key...\n")); + test.Getch(); + test.End(); + return KErrNone; + }