kerneltest/e32test/lffs/tf_erase.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:26:05 +0100
branchRCL_3
changeset 29 743008598095
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 2003-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:
// Tests erasing of Flash. Does not test suspending (see TF_SUSPEND)
// 
//

#include <e32std.h>
#include <e32std_private.h>
#include <e32svr.h>
#include <e32test.h>
#include "randgen.h"
#include "user_config.h"

RTest test( _L("TF_ERASE") );


class CEraseTest : public CBase
	{
	public:
		~CEraseTest();

		void CreateL();

		void DoTest();

	private:
		void DoSimpleTest();
		void DoSimpleTest2();
		void DoPseudoRandomTest();
		void DoRangeTest();

		TInt EraseOneBlock( TInt aBlockNumber );
		TInt ZeroFillBlock( TInt aBlockNumber );
		TBool ValidateBlock( TInt aBlockNumber, TUint32 aFillWord );


	private:
		TBusLocalDrive	iDrive;
		TBool			iDriveOpened;

		TInt			iFlashSize;
		TInt			iBlockSize;
		TInt			iBlockCount;

		TBuf8<512>		iReadBuffer;

	};


CEraseTest::~CEraseTest()
	{
	if( iDriveOpened )
		{
		iDrive.Disconnect();
		}
	}



void CEraseTest::CreateL()
	{
	//
	// Load the device drivers
	//
#ifndef SKIP_PDD_LOAD
	test.Printf( _L("Loading %S\n"), &KLfsDriverName );
	r = User::LoadPhysicalDevice( KLfsDriverName );
	test( KErrNone == r || KErrAlreadyExists == r );
#endif

#ifdef UNMOUNT_DRIVE
	RFs fs;
	test( KErrNone == fs.Connect() );
#if 0
	// XXX - not eka2
	test( KErrNone == fs.SetDefaultPath( _L("Z:\\") ) );
#endif
	TFullName name;
	fs.FileSystemName( name, KLffsLogicalDriveNumber );
	if( name.Length() > 0 )
		{
		test.Printf( _L("Unmounting drive") );
		test( KErrNone == fs.DismountFileSystem( _L("Lffs"), KLffsLogicalDriveNumber) );
		User::After( 2000000 );
		test.Printf( _L("Drive unmounted") );
		}
	fs.Close();
#endif

	//
	// Open a TBusLogicalDevice to drive
	//
	test.Printf( _L("Opening media channel\n") );
	static TBool changedFlag = EFalse;
	User::LeaveIfError( iDrive.Connect( KDriveNumber, changedFlag ) );
	iDriveOpened = ETrue;

	//
	// Get size of Flash drive, block size, block count
	//
	TLocalDriveCapsV2Buf info;
    iDrive.Caps(info);
	iFlashSize = I64LOW(info().iSize);
	iBlockSize = info().iEraseBlockSize;
	iBlockCount = iFlashSize / iBlockSize;

	test.Printf( _L("Flash size is 0x%x bytes\n"), iFlashSize );
	test.Printf( _L("Block size is 0x%x bytes\n"), iBlockSize );
	test.Printf( _L("Block count is %d\n"), iBlockCount );

	test.Printf( _L("CreateL complete\n") );
	}


void CEraseTest::DoTest()
	//
	// Main test dispatcher
	//
	{
	test.Next( _L("Starting tests...") );
	DoSimpleTest();
	DoSimpleTest2();
	DoPseudoRandomTest();
	DoRangeTest();
	}


TInt CEraseTest::EraseOneBlock( TInt aBlockNumber )
	//
	// Erases block aBlockNumber on Flash
	//
	{
	TInt blockBaseOffset = aBlockNumber * iBlockSize;

	test.Printf( _L("Erasing block %d (offs=0x%x)\n"), aBlockNumber, blockBaseOffset );
	
	TInt r = iDrive.Format( blockBaseOffset, iBlockSize );

	test.Printf( _L("... Format returned %d\n"), r );
	return r;
	}


TBool CEraseTest::ValidateBlock( TInt aBlockNumber, TUint32 aFillWord )
	//
	// Checks that every word in block aBlockNumber has the value aFillWord
	//
	{
	TUint offset = aBlockNumber * iBlockSize;
	test.Printf( _L("Validating block %d (offs=0x%x)\n"), aBlockNumber, offset );
	
	TBool failed = EFalse;
	const TInt readBufLen = iReadBuffer.MaxLength();

	for( TInt len = iBlockSize; len > 0 && !failed ;)
		{
		TInt r = iDrive.Read( offset, readBufLen, iReadBuffer );
		if( r != KErrNone )
			{
			test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset );
			test( KErrNone == r );
			}
		test( iReadBuffer.Length() == readBufLen );

		TUint32* p = (TUint32*)iReadBuffer.Ptr();
		for( TInt i = 0; i < readBufLen; i += 4 )
			{
			if( aFillWord != *p )
				{
				failed = ETrue;
				test.Printf( _L("... FAILED: word @ offs=0x%x, read=0x%x, expected=0x%x\n"), 
								offset+i, p[0], aFillWord );
				break;
				}
			++p;
			}
		offset += readBufLen;
		len -= readBufLen;
		}
	
	return !failed;
	}


TInt CEraseTest::ZeroFillBlock( TInt aBlockNumber )
	//
	// Zero-fills an entire block
	// The requires that writing works (so as a side-effect performs a
	// very basic test of writing)
	//
	{
	test.Printf( _L("Zero-filling block %d\n"), aBlockNumber );

	//
	// Create a buffer full of zeros
	//
	const TInt KZeroBufSize = 512;

	TBuf8<KZeroBufSize> buf;
	buf.FillZ( buf.MaxLength() );

	//
	// Write the data out to the Flash
	//
	TInt writeCount = iBlockSize / KZeroBufSize;
	TInt r = KErrNone;
	TInt blockBaseOffset = aBlockNumber * iBlockSize;
	for( ; (writeCount > 0) && (KErrNone == r); writeCount-- )
		{
		r = iDrive.Write( blockBaseOffset, buf );
		if( r != KErrNone )
			{
			test.Printf( _L("... FAIL: write failed (%d) at offset 0x%x\n"), r, blockBaseOffset );
			}
		blockBaseOffset += KZeroBufSize;
		}

	return r;
	}


void CEraseTest::DoSimpleTest()
	//
	// Simple erase test. This just zero-fills and then erases each block in turn
	//
	{
	test.Next( _L("Simple test: erases each block in turn\n") );

	for( TInt block = 0; block < iBlockCount; block++ )
		{
		test( KErrNone == ZeroFillBlock( block ) );
		test( ValidateBlock( block, 0 ) );
		test( KErrNone == EraseOneBlock( block ) );
		test( ValidateBlock( block, 0xFFFFFFFF ) );
		}
	}

void CEraseTest::DoSimpleTest2()
	//
	// Another simple erase test.
	// This time we zero-fill all blocks first, then erase them all
	//
	{
	test.Next( _L("Simple test2 : zero-fills whole Flash, then erases all blocks\n") );

	for( TInt block = 0; block < iBlockCount; block++ )
		{
		test( KErrNone == ZeroFillBlock( block ) );
		test( ValidateBlock( block, 0 ) );
		}

	for( TInt block = 0; block < iBlockCount; block++ )
		{
		test( KErrNone == EraseOneBlock( block ) );
		test( ValidateBlock( block, 0xFFFFFFFF ) );
		}
	}



void CEraseTest::DoPseudoRandomTest()
	//
	// Erases the blocks in pseudo-random order, zero-filling first
	//
	{
	test.Next( _L("Test random erase order\n") );

	TRandomGenerator random;
#if 0
	random.SetSeed( TInt64(0x1020466E, 0x3F9C0C00) );
#else
	random.SetSeed( 0x1020466E );
#endif

	for( TInt count = 0; count < 50; count++ )
		{
		TUint block = random.Next() % iBlockCount;
		test( KErrNone == ZeroFillBlock( block ) );

		test( ValidateBlock( block, 0 ) );

		test( KErrNone == EraseOneBlock( block ) );

		test( ValidateBlock( block, 0xFFFFFFFF ) );
		}
	}

void CEraseTest::DoRangeTest()
	//
	// Simple erase test. This just zero-fills and then erases each block in turn
	//
	{
	test.Next( _L("Range test: check that erase only affects erased block\n") );

	//
	// Pre-fill all blocks with zero
	//
	test.Printf( _L("Pre-zeroing blocks\n") );
	for( TInt block = 0; block < iBlockCount; block++ )
		{
		test( KErrNone == ZeroFillBlock( block ) );
		test( ValidateBlock( block, 0 ) );
		}

	//
	// The test is to erase a block. Check it is erased and all
	// other blocks are still zeros. Then we re-zero the block just
	// erased and repeat test with next block
	//
	test.Printf( _L("Now testing erase...\n") );
	for( TInt eraseBlock = 0; eraseBlock < iBlockCount; eraseBlock++ )
		{
		test( KErrNone == EraseOneBlock( eraseBlock ) );
		test( ValidateBlock( eraseBlock, 0xFFFFFFFF ) );
		
		// check all other blocks are still zero
		for( TInt j = 0; j < iBlockCount; j++ )
			{
			if( j != eraseBlock )
				{
				// test if not the one we just erased
				test( ValidateBlock( j, 0 ) );
				}
			}

		// Now zero-fill the block we just erased and move to next block
		test( KErrNone == ZeroFillBlock( eraseBlock ) );
		test( ValidateBlock( eraseBlock, 0 ) );
		}

	}


TInt E32Main()
	{
	test.Title();
	test.Start(_L("Testing media erase operations"));

	CEraseTest eraseTest;
	TRAPD( ret, eraseTest.CreateL() );
	if( KErrNone == ret )
		{
		eraseTest.DoTest();
		}

	test.End();
	return KErrNone;
	}