sl@0: // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // Tests erasing of Flash. Does not test suspending (see TF_SUSPEND) sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "randgen.h" sl@0: #include "user_config.h" sl@0: sl@0: RTest test( _L("TF_ERASE") ); sl@0: sl@0: sl@0: class CEraseTest : public CBase sl@0: { sl@0: public: sl@0: ~CEraseTest(); sl@0: sl@0: void CreateL(); sl@0: sl@0: void DoTest(); sl@0: sl@0: private: sl@0: void DoSimpleTest(); sl@0: void DoSimpleTest2(); sl@0: void DoPseudoRandomTest(); sl@0: void DoRangeTest(); sl@0: sl@0: TInt EraseOneBlock( TInt aBlockNumber ); sl@0: TInt ZeroFillBlock( TInt aBlockNumber ); sl@0: TBool ValidateBlock( TInt aBlockNumber, TUint32 aFillWord ); sl@0: sl@0: sl@0: private: sl@0: TBusLocalDrive iDrive; sl@0: TBool iDriveOpened; sl@0: sl@0: TInt iFlashSize; sl@0: TInt iBlockSize; sl@0: TInt iBlockCount; sl@0: sl@0: TBuf8<512> iReadBuffer; sl@0: sl@0: }; sl@0: sl@0: sl@0: CEraseTest::~CEraseTest() sl@0: { sl@0: if( iDriveOpened ) sl@0: { sl@0: iDrive.Disconnect(); sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: void CEraseTest::CreateL() sl@0: { sl@0: // sl@0: // Load the device drivers sl@0: // sl@0: #ifndef SKIP_PDD_LOAD sl@0: test.Printf( _L("Loading %S\n"), &KLfsDriverName ); sl@0: r = User::LoadPhysicalDevice( KLfsDriverName ); sl@0: test( KErrNone == r || KErrAlreadyExists == r ); sl@0: #endif sl@0: sl@0: #ifdef UNMOUNT_DRIVE sl@0: RFs fs; sl@0: test( KErrNone == fs.Connect() ); sl@0: #if 0 sl@0: // XXX - not eka2 sl@0: test( KErrNone == fs.SetDefaultPath( _L("Z:\\") ) ); sl@0: #endif sl@0: TFullName name; sl@0: fs.FileSystemName( name, KLffsLogicalDriveNumber ); sl@0: if( name.Length() > 0 ) sl@0: { sl@0: test.Printf( _L("Unmounting drive") ); sl@0: test( KErrNone == fs.DismountFileSystem( _L("Lffs"), KLffsLogicalDriveNumber) ); sl@0: User::After( 2000000 ); sl@0: test.Printf( _L("Drive unmounted") ); sl@0: } sl@0: fs.Close(); sl@0: #endif sl@0: sl@0: // sl@0: // Open a TBusLogicalDevice to drive sl@0: // sl@0: test.Printf( _L("Opening media channel\n") ); sl@0: static TBool changedFlag = EFalse; sl@0: User::LeaveIfError( iDrive.Connect( KDriveNumber, changedFlag ) ); sl@0: iDriveOpened = ETrue; sl@0: sl@0: // sl@0: // Get size of Flash drive, block size, block count sl@0: // sl@0: TLocalDriveCapsV2Buf info; sl@0: iDrive.Caps(info); sl@0: iFlashSize = I64LOW(info().iSize); sl@0: iBlockSize = info().iEraseBlockSize; sl@0: iBlockCount = iFlashSize / iBlockSize; sl@0: sl@0: test.Printf( _L("Flash size is 0x%x bytes\n"), iFlashSize ); sl@0: test.Printf( _L("Block size is 0x%x bytes\n"), iBlockSize ); sl@0: test.Printf( _L("Block count is %d\n"), iBlockCount ); sl@0: sl@0: test.Printf( _L("CreateL complete\n") ); sl@0: } sl@0: sl@0: sl@0: void CEraseTest::DoTest() sl@0: // sl@0: // Main test dispatcher sl@0: // sl@0: { sl@0: test.Next( _L("Starting tests...") ); sl@0: DoSimpleTest(); sl@0: DoSimpleTest2(); sl@0: DoPseudoRandomTest(); sl@0: DoRangeTest(); sl@0: } sl@0: sl@0: sl@0: TInt CEraseTest::EraseOneBlock( TInt aBlockNumber ) sl@0: // sl@0: // Erases block aBlockNumber on Flash sl@0: // sl@0: { sl@0: TInt blockBaseOffset = aBlockNumber * iBlockSize; sl@0: sl@0: test.Printf( _L("Erasing block %d (offs=0x%x)\n"), aBlockNumber, blockBaseOffset ); sl@0: sl@0: TInt r = iDrive.Format( blockBaseOffset, iBlockSize ); sl@0: sl@0: test.Printf( _L("... Format returned %d\n"), r ); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: TBool CEraseTest::ValidateBlock( TInt aBlockNumber, TUint32 aFillWord ) sl@0: // sl@0: // Checks that every word in block aBlockNumber has the value aFillWord sl@0: // sl@0: { sl@0: TUint offset = aBlockNumber * iBlockSize; sl@0: test.Printf( _L("Validating block %d (offs=0x%x)\n"), aBlockNumber, offset ); sl@0: sl@0: TBool failed = EFalse; sl@0: const TInt readBufLen = iReadBuffer.MaxLength(); sl@0: sl@0: for( TInt len = iBlockSize; len > 0 && !failed ;) sl@0: { sl@0: TInt r = iDrive.Read( offset, readBufLen, iReadBuffer ); sl@0: if( r != KErrNone ) sl@0: { sl@0: test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset ); sl@0: test( KErrNone == r ); sl@0: } sl@0: test( iReadBuffer.Length() == readBufLen ); sl@0: sl@0: TUint32* p = (TUint32*)iReadBuffer.Ptr(); sl@0: for( TInt i = 0; i < readBufLen; i += 4 ) sl@0: { sl@0: if( aFillWord != *p ) sl@0: { sl@0: failed = ETrue; sl@0: test.Printf( _L("... FAILED: word @ offs=0x%x, read=0x%x, expected=0x%x\n"), sl@0: offset+i, p[0], aFillWord ); sl@0: break; sl@0: } sl@0: ++p; sl@0: } sl@0: offset += readBufLen; sl@0: len -= readBufLen; sl@0: } sl@0: sl@0: return !failed; sl@0: } sl@0: sl@0: sl@0: TInt CEraseTest::ZeroFillBlock( TInt aBlockNumber ) sl@0: // sl@0: // Zero-fills an entire block sl@0: // The requires that writing works (so as a side-effect performs a sl@0: // very basic test of writing) sl@0: // sl@0: { sl@0: test.Printf( _L("Zero-filling block %d\n"), aBlockNumber ); sl@0: sl@0: // sl@0: // Create a buffer full of zeros sl@0: // sl@0: const TInt KZeroBufSize = 512; sl@0: sl@0: TBuf8 buf; sl@0: buf.FillZ( buf.MaxLength() ); sl@0: sl@0: // sl@0: // Write the data out to the Flash sl@0: // sl@0: TInt writeCount = iBlockSize / KZeroBufSize; sl@0: TInt r = KErrNone; sl@0: TInt blockBaseOffset = aBlockNumber * iBlockSize; sl@0: for( ; (writeCount > 0) && (KErrNone == r); writeCount-- ) sl@0: { sl@0: r = iDrive.Write( blockBaseOffset, buf ); sl@0: if( r != KErrNone ) sl@0: { sl@0: test.Printf( _L("... FAIL: write failed (%d) at offset 0x%x\n"), r, blockBaseOffset ); sl@0: } sl@0: blockBaseOffset += KZeroBufSize; sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: sl@0: sl@0: void CEraseTest::DoSimpleTest() sl@0: // sl@0: // Simple erase test. This just zero-fills and then erases each block in turn sl@0: // sl@0: { sl@0: test.Next( _L("Simple test: erases each block in turn\n") ); sl@0: sl@0: for( TInt block = 0; block < iBlockCount; block++ ) sl@0: { sl@0: test( KErrNone == ZeroFillBlock( block ) ); sl@0: test( ValidateBlock( block, 0 ) ); sl@0: test( KErrNone == EraseOneBlock( block ) ); sl@0: test( ValidateBlock( block, 0xFFFFFFFF ) ); sl@0: } sl@0: } sl@0: sl@0: void CEraseTest::DoSimpleTest2() sl@0: // sl@0: // Another simple erase test. sl@0: // This time we zero-fill all blocks first, then erase them all sl@0: // sl@0: { sl@0: test.Next( _L("Simple test2 : zero-fills whole Flash, then erases all blocks\n") ); sl@0: sl@0: for( TInt block = 0; block < iBlockCount; block++ ) sl@0: { sl@0: test( KErrNone == ZeroFillBlock( block ) ); sl@0: test( ValidateBlock( block, 0 ) ); sl@0: } sl@0: sl@0: for( TInt block = 0; block < iBlockCount; block++ ) sl@0: { sl@0: test( KErrNone == EraseOneBlock( block ) ); sl@0: test( ValidateBlock( block, 0xFFFFFFFF ) ); sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: void CEraseTest::DoPseudoRandomTest() sl@0: // sl@0: // Erases the blocks in pseudo-random order, zero-filling first sl@0: // sl@0: { sl@0: test.Next( _L("Test random erase order\n") ); sl@0: sl@0: TRandomGenerator random; sl@0: #if 0 sl@0: random.SetSeed( TInt64(0x1020466E, 0x3F9C0C00) ); sl@0: #else sl@0: random.SetSeed( 0x1020466E ); sl@0: #endif sl@0: sl@0: for( TInt count = 0; count < 50; count++ ) sl@0: { sl@0: TUint block = random.Next() % iBlockCount; sl@0: test( KErrNone == ZeroFillBlock( block ) ); sl@0: sl@0: test( ValidateBlock( block, 0 ) ); sl@0: sl@0: test( KErrNone == EraseOneBlock( block ) ); sl@0: sl@0: test( ValidateBlock( block, 0xFFFFFFFF ) ); sl@0: } sl@0: } sl@0: sl@0: void CEraseTest::DoRangeTest() sl@0: // sl@0: // Simple erase test. This just zero-fills and then erases each block in turn sl@0: // sl@0: { sl@0: test.Next( _L("Range test: check that erase only affects erased block\n") ); sl@0: sl@0: // sl@0: // Pre-fill all blocks with zero sl@0: // sl@0: test.Printf( _L("Pre-zeroing blocks\n") ); sl@0: for( TInt block = 0; block < iBlockCount; block++ ) sl@0: { sl@0: test( KErrNone == ZeroFillBlock( block ) ); sl@0: test( ValidateBlock( block, 0 ) ); sl@0: } sl@0: sl@0: // sl@0: // The test is to erase a block. Check it is erased and all sl@0: // other blocks are still zeros. Then we re-zero the block just sl@0: // erased and repeat test with next block sl@0: // sl@0: test.Printf( _L("Now testing erase...\n") ); sl@0: for( TInt eraseBlock = 0; eraseBlock < iBlockCount; eraseBlock++ ) sl@0: { sl@0: test( KErrNone == EraseOneBlock( eraseBlock ) ); sl@0: test( ValidateBlock( eraseBlock, 0xFFFFFFFF ) ); sl@0: sl@0: // check all other blocks are still zero sl@0: for( TInt j = 0; j < iBlockCount; j++ ) sl@0: { sl@0: if( j != eraseBlock ) sl@0: { sl@0: // test if not the one we just erased sl@0: test( ValidateBlock( j, 0 ) ); sl@0: } sl@0: } sl@0: sl@0: // Now zero-fill the block we just erased and move to next block sl@0: test( KErrNone == ZeroFillBlock( eraseBlock ) ); sl@0: test( ValidateBlock( eraseBlock, 0 ) ); sl@0: } sl@0: sl@0: } sl@0: sl@0: sl@0: TInt E32Main() sl@0: { sl@0: test.Title(); sl@0: test.Start(_L("Testing media erase operations")); sl@0: sl@0: CEraseTest eraseTest; sl@0: TRAPD( ret, eraseTest.CreateL() ); sl@0: if( KErrNone == ret ) sl@0: { sl@0: eraseTest.DoTest(); sl@0: } sl@0: sl@0: test.End(); sl@0: return KErrNone; sl@0: }