1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/lffs/tf_suspend.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,526 @@
1.4 +// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// Tests erasing of Flash while forcing suspend-resume cycles
1.18 +//
1.19 +//
1.20 +
1.21 +#include <e32std.h>
1.22 +#include <e32std_private.h>
1.23 +#include <e32svr.h>
1.24 +#include <e32test.h>
1.25 +#include "user_config.h"
1.26 +
1.27 +RTest test( _L("TF_SUSPEND") );
1.28 +
1.29 +
1.30 +
1.31 +class CEraser
1.32 + {
1.33 + public:
1.34 + enum TFunction
1.35 + {
1.36 + EEraseBlock
1.37 + };
1.38 +
1.39 + public:
1.40 + ~CEraser();
1.41 + void CreateL();
1.42 + void Stop();
1.43 + void WaitForReady();
1.44 +
1.45 + inline void WaitForDone()
1.46 + {
1.47 + WaitForReady();
1.48 + iWaitingSignal.Signal(); // resignal, ready for next Start()
1.49 + };
1.50 +
1.51 + void EraseBlock( TUint32 aOffset, TUint aLength );
1.52 +
1.53 + private:
1.54 + void Panic( TInt aPanicNum );
1.55 + void Start( TFunction aFunction );
1.56 +
1.57 + static TInt EraserThread( TAny* aParam );
1.58 +
1.59 + void DoEraseBlock();
1.60 +
1.61 + private:
1.62 + RThread iThread;
1.63 +
1.64 + //
1.65 + // Shared between main & eraser thread
1.66 + //
1.67 + TFunction iRequestedFunction;
1.68 + RSemaphore iGoSignal;
1.69 + RSemaphore iWaitingSignal;
1.70 + TBool iStop;
1.71 +
1.72 + //
1.73 + // These are local to the eraser thread
1.74 + //
1.75 + TUint iOffset;
1.76 + TUint iLength;
1.77 + TBusLocalDrive iDrive;
1.78 + };
1.79 +
1.80 +
1.81 +
1.82 +CEraser::~CEraser()
1.83 + {
1.84 + iThread.Terminate( KErrNone );
1.85 + iThread.Close();
1.86 + iGoSignal.Close();
1.87 + iWaitingSignal.Close();
1.88 + }
1.89 +
1.90 +void CEraser::Panic( TInt aPanicNum )
1.91 + {
1.92 + _LIT( KPanicCat, "ERASE-T" );
1.93 + User::Panic( KPanicCat, aPanicNum );
1.94 + RProcess().Panic( KPanicCat, aPanicNum );
1.95 + }
1.96 +
1.97 +
1.98 +void CEraser::CreateL()
1.99 + //
1.100 + // Create new thread and wait for it to become ready
1.101 + //
1.102 + {
1.103 + iGoSignal.CreateLocal( 0 ); // initially blocked
1.104 + iWaitingSignal.CreateLocal( 0 ); // initially blocked
1.105 + iStop = EFalse;
1.106 + User::LeaveIfError( iThread.Create( _L("ERASER"), EraserThread, 2048, 2048, 65536, this ) );
1.107 + test.Printf( _L("Eraser thread created\n") );
1.108 +
1.109 + iThread.Resume();
1.110 +
1.111 + test.Printf( _L("Waiting for thread to become ready\n") );
1.112 + WaitForReady();
1.113 + iWaitingSignal.Signal();
1.114 + }
1.115 +
1.116 +void CEraser::Start( TFunction aFunction )
1.117 + //
1.118 + // Start the suspender thread executing function aFunction
1.119 + //
1.120 + {
1.121 + iStop = EFalse;
1.122 + WaitForReady();
1.123 + iRequestedFunction = aFunction;
1.124 + iGoSignal.Signal();
1.125 + }
1.126 +
1.127 +void CEraser::Stop()
1.128 + //
1.129 + // Stop the thread
1.130 + //
1.131 + {
1.132 + iStop = ETrue;
1.133 + }
1.134 +
1.135 +void CEraser::WaitForReady()
1.136 + {
1.137 + iWaitingSignal.Wait();
1.138 + }
1.139 +
1.140 +void CEraser::EraseBlock( TUint32 aOffset, TUint aLength )
1.141 + //
1.142 + // Execute a block erase
1.143 + //
1.144 + {
1.145 + iOffset = aOffset;
1.146 + iLength = aLength;
1.147 + Start( EEraseBlock );
1.148 + }
1.149 +
1.150 +
1.151 +TInt CEraser::EraserThread( TAny* aParam )
1.152 + //
1.153 + // The thread which executes suspend functions
1.154 + //
1.155 + {
1.156 + RDebug::Print( _L("Eraser thread starts") );
1.157 +
1.158 + CEraser& self = *reinterpret_cast<CEraser*>(aParam);
1.159 +
1.160 + //
1.161 + // Open our own TBusLogicalDevice channel
1.162 + //
1.163 + TBool changedFlag;
1.164 + if( KErrNone != self.iDrive.Connect( KDriveNumber, changedFlag ) )
1.165 + {
1.166 + self.Panic( 1 );
1.167 + }
1.168 +
1.169 + RDebug::Print( _L("Eraser thread connected to drive") );
1.170 +
1.171 + while( !self.iStop )
1.172 + {
1.173 + //
1.174 + // Signal that we are ready for a request
1.175 + //
1.176 + RDebug::Print( _L("Eraser thread waiting...") );
1.177 + self.iWaitingSignal.Signal();
1.178 +
1.179 + //
1.180 + // Wait for a request
1.181 + //
1.182 + self.iGoSignal.Wait();
1.183 + RDebug::Print( _L("Eraser thread go (%d)"), self.iRequestedFunction );
1.184 +
1.185 + switch( self.iRequestedFunction )
1.186 + {
1.187 + case EEraseBlock:
1.188 + self.DoEraseBlock();
1.189 + break;
1.190 +
1.191 + default:
1.192 + self.Panic( 0 );
1.193 + }
1.194 +
1.195 + }
1.196 +
1.197 + self.iDrive.Disconnect();
1.198 + return KErrNone;
1.199 + }
1.200 +
1.201 +void CEraser::DoEraseBlock()
1.202 + //
1.203 + // Issue an erase
1.204 + //
1.205 + {
1.206 + RDebug::Print( _L("Eraser starting erase...") );
1.207 +
1.208 + TInt64 offs( iOffset );
1.209 + TInt r = iDrive.Format( offs, iLength );
1.210 +
1.211 + if( KErrNone != r )
1.212 + {
1.213 + RDebug::Print( _L("Eraser: FAIL: erase request returns %d"), r );
1.214 + Panic( 2 );
1.215 + }
1.216 + }
1.217 +
1.218 +
1.219 +
1.220 +class CSuspendTest : public CBase
1.221 + {
1.222 + public:
1.223 + ~CSuspendTest();
1.224 +
1.225 + void CreateL();
1.226 +
1.227 + void DoTest();
1.228 +
1.229 + private:
1.230 +
1.231 + TInt EraseOneBlock( TInt aBlockNumber );
1.232 + TInt ZeroFillBlock( TInt aBlockNumber );
1.233 + TBool ValidateBlock( TInt aBlockNumber, TUint32 aFillWord );
1.234 + TInt ZeroAllBlocks();
1.235 + TBool ValidateAllBlocks( TUint32 aFillWord );
1.236 +
1.237 + void DoImmediateSuspendTest();
1.238 +
1.239 + private:
1.240 + TBusLocalDrive iDrive;
1.241 + TBool iDriveOpened;
1.242 +
1.243 + CEraser* iEraser;
1.244 +
1.245 + TInt iFlashSize;
1.246 + TInt iBlockSize;
1.247 + TInt iBlockCount;
1.248 +
1.249 + TBuf8<512> iReadBuffer;
1.250 + };
1.251 +
1.252 +
1.253 +CSuspendTest::~CSuspendTest()
1.254 + {
1.255 + if( iDriveOpened )
1.256 + {
1.257 + iDrive.Disconnect();
1.258 + }
1.259 +
1.260 + delete iEraser;
1.261 + }
1.262 +
1.263 +
1.264 +
1.265 +void CSuspendTest::CreateL()
1.266 + {
1.267 + //
1.268 + // Create the eraser thread
1.269 + //
1.270 + iEraser = new(ELeave) CEraser;
1.271 + iEraser->CreateL();
1.272 +
1.273 + //
1.274 + // Load the device drivers
1.275 + //
1.276 + TInt r;
1.277 +#ifndef SKIP_PDD_LOAD
1.278 + test.Printf( _L("Loading %S\n"), &KLfsDriverName );
1.279 + r = User::LoadPhysicalDevice( KLfsDriverName );
1.280 + test( KErrNone == r || KErrAlreadyExists == r );
1.281 +#endif
1.282 +
1.283 +#ifdef UNMOUNT_DRIVE
1.284 + RFs fs;
1.285 + test( KErrNone == fs.Connect() );
1.286 +#if 0
1.287 + // XXX - not EKA2
1.288 + test( KErrNone == fs.SetDefaultPath( _L("Z:\\") ) );
1.289 +#endif
1.290 + TFullName name;
1.291 + fs.FileSystemName( name, KLffsLogicalDriveNumber );
1.292 + if( name.Length() > 0 )
1.293 + {
1.294 + test.Printf( _L("Unmounting drive") );
1.295 + test( KErrNone == fs.DismountFileSystem( _L("Lffs"), KLffsLogicalDriveNumber) );
1.296 + User::After( 2000000 );
1.297 + test.Printf( _L("Drive unmounted") );
1.298 + }
1.299 + fs.Close();
1.300 +#endif
1.301 +
1.302 + //
1.303 + // Open a TBusLogicalDevice to the driver
1.304 + //
1.305 + test.Printf( _L("Opening media channel\n") );
1.306 + TBool changedFlag = EFalse;
1.307 + r = iDrive.Connect( KDriveNumber, changedFlag );
1.308 + User::LeaveIfError( r );
1.309 + iDriveOpened = ETrue;
1.310 +
1.311 + //
1.312 + // Get size of Flash drive, block size, block count
1.313 + //
1.314 + TLocalDriveCapsV2Buf info;
1.315 + iDrive.Caps(info);
1.316 + iFlashSize = I64LOW(info().iSize);
1.317 + iBlockSize = info().iEraseBlockSize;
1.318 + iBlockCount = iFlashSize / iBlockSize;
1.319 +
1.320 + test.Printf( _L("Flash size is 0x%x bytes\n"), iFlashSize );
1.321 + test.Printf( _L("Block size is 0x%x bytes\n"), iBlockSize );
1.322 + test.Printf( _L("Block count is %d\n"), iBlockCount );
1.323 +
1.324 + test.Printf( _L("CreateL complete\n") );
1.325 + }
1.326 +
1.327 +
1.328 +void CSuspendTest::DoTest()
1.329 + //
1.330 + // Main test dispatcher
1.331 + //
1.332 + {
1.333 + DoImmediateSuspendTest();
1.334 + }
1.335 +
1.336 +
1.337 +TInt CSuspendTest::EraseOneBlock( TInt aBlockNumber )
1.338 + //
1.339 + // Erases block aBlockNumber on Flash
1.340 + //
1.341 + {
1.342 + TInt blockBaseOffset = aBlockNumber * iBlockSize;
1.343 +
1.344 + test.Printf( _L("Erasing block %d (offs=0x%x)\n"), aBlockNumber, blockBaseOffset );
1.345 +
1.346 + TInt r = iDrive.Format( blockBaseOffset, iBlockSize );
1.347 +
1.348 + test.Printf( _L("... block erased, rv=%d\n"), r );
1.349 + return r;
1.350 + }
1.351 +
1.352 +
1.353 +TBool CSuspendTest::ValidateBlock( TInt aBlockNumber, TUint32 aFillWord )
1.354 + //
1.355 + // Checks that every word in block aBlockNumber has the value aFillWord
1.356 + //
1.357 + {
1.358 + TUint offset = aBlockNumber * iBlockSize;
1.359 + test.Printf( _L("Validating block %d (offs=0x%x)\n"), aBlockNumber, offset );
1.360 +
1.361 + TBool failed = EFalse;
1.362 + const TInt readBufLen = iReadBuffer.MaxLength();
1.363 +
1.364 + for( TInt len = iBlockSize; len > 0 && !failed ;)
1.365 + {
1.366 + TInt r = iDrive.Read( offset, readBufLen, iReadBuffer );
1.367 + if( r != KErrNone )
1.368 + {
1.369 + test.Printf( _L("... FAIL: read failed (%d) at offset 0x%x\n"), r, offset );
1.370 + test( KErrNone == r );
1.371 + }
1.372 + test( iReadBuffer.Length() == readBufLen );
1.373 +
1.374 + TUint32* p = (TUint32*)iReadBuffer.Ptr();
1.375 + for( TInt i = 0; i < readBufLen; i += 4 )
1.376 + {
1.377 + if( aFillWord != *p )
1.378 + {
1.379 + failed = ETrue;
1.380 + test.Printf( _L("... FAILED: word @ offs=0x%x, read=0x%x, expected=0x%x\n"),
1.381 + offset+i, p[0], aFillWord );
1.382 + break;
1.383 + }
1.384 + ++p;
1.385 + }
1.386 + offset += readBufLen;
1.387 + len -= readBufLen;
1.388 + }
1.389 +
1.390 + return !failed;
1.391 + }
1.392 +
1.393 +
1.394 +TInt CSuspendTest::ZeroFillBlock( TInt aBlockNumber )
1.395 + //
1.396 + // Zero-fills and entire block
1.397 + // The requires that writing works
1.398 + //
1.399 + {
1.400 + test.Printf( _L("Zero-filling block %d\n"), aBlockNumber );
1.401 +
1.402 + //
1.403 + // Create a buffer full of zeros
1.404 + //
1.405 + const TInt KZeroBufSize = 512;
1.406 +
1.407 + TBuf8<KZeroBufSize> buf;
1.408 + buf.FillZ( buf.MaxLength() );
1.409 +
1.410 + //
1.411 + // Write the data out to the Flash
1.412 + //
1.413 + TInt writeCount = iBlockSize / KZeroBufSize;
1.414 + TInt r = KErrNone;
1.415 + TInt blockBaseOffset = aBlockNumber * iBlockSize;
1.416 + for( ; (writeCount > 0) && (KErrNone == r); writeCount-- )
1.417 + {
1.418 + r = iDrive.Write( blockBaseOffset, buf );
1.419 + if( r != KErrNone )
1.420 + {
1.421 + test.Printf( _L("... FAIL: write failed (%d) at offset 0x%x\n"), blockBaseOffset );
1.422 + }
1.423 + blockBaseOffset += KZeroBufSize;
1.424 + }
1.425 +
1.426 + return r;
1.427 + }
1.428 +
1.429 +
1.430 +TInt CSuspendTest::ZeroAllBlocks()
1.431 + //
1.432 + // Writes zeros to all blocks
1.433 + //
1.434 + {
1.435 + test.Printf( _L("Zeroing all blocks\n") );
1.436 +
1.437 + TInt r = KErrNone;
1.438 + for( TInt i = 0; (i < iBlockCount) && (KErrNone == r); i++ )
1.439 + {
1.440 + r = ZeroFillBlock( i );
1.441 + }
1.442 +
1.443 + return r;
1.444 + }
1.445 +
1.446 +TBool CSuspendTest::ValidateAllBlocks( TUint32 aFillWord )
1.447 + //
1.448 + // Checks that all blocks contain aFillWord
1.449 + //
1.450 + {
1.451 + test.Printf( _L("Validating all blocks\n") );
1.452 +
1.453 + TBool failed = EFalse;
1.454 + for( TInt i = 0; (i < iBlockCount) && (!failed); i++ )
1.455 + {
1.456 + failed = !ValidateBlock( i, aFillWord );
1.457 + }
1.458 +
1.459 + return !failed;
1.460 + }
1.461 +
1.462 +
1.463 +void CSuspendTest::DoImmediateSuspendTest()
1.464 + //
1.465 + // For each block issues an erase and then immediately
1.466 + // requests a read on another block. Waits for erase to
1.467 + // finish and validates it
1.468 + //
1.469 + {
1.470 + test.Next( _L("Immediate suspend test") );
1.471 + test( KErrNone == ZeroAllBlocks() );
1.472 + test( ValidateAllBlocks( 0 ) );
1.473 +
1.474 + //
1.475 + // We repeat the test for each block, erasing block n and reading from
1.476 + // block (n+1) modulo iBlockCount
1.477 + //
1.478 + for( TInt eraseBlock = 0; eraseBlock < iBlockCount; eraseBlock++ )
1.479 + {
1.480 + TUint32 readBlock = (eraseBlock + 1) % iBlockCount;
1.481 + TUint32 erasePos = eraseBlock * iBlockSize;
1.482 + TInt readPos = readBlock * iBlockSize;
1.483 +
1.484 + TBuf8<32> buf;
1.485 +
1.486 + //
1.487 + // Start the erase
1.488 + //
1.489 + iEraser->EraseBlock( erasePos, iBlockSize );
1.490 +
1.491 + //
1.492 + // Do a read immediately
1.493 + //
1.494 + test.Printf( _L("main thread requesting read") );
1.495 + test( KErrNone == iDrive.Read( readPos, buf.MaxLength(), buf ) );
1.496 +
1.497 + //
1.498 + // Wait for erase to finish
1.499 + //
1.500 + test.Printf( _L("main thread waiting for erase to finish...") );
1.501 + iEraser->WaitForDone();
1.502 +
1.503 + //
1.504 + // Now check that the block was erased
1.505 + //
1.506 + test( ValidateBlock( eraseBlock, 0xFFFFFFFF ) );
1.507 +
1.508 + }
1.509 +
1.510 + }
1.511 +
1.512 +
1.513 +
1.514 +
1.515 +TInt E32Main()
1.516 + {
1.517 + test.Title();
1.518 + test.Start(_L("Testing media erase+suspend operations"));
1.519 +
1.520 + CSuspendTest suspendTest;
1.521 + TRAPD( ret, suspendTest.CreateL() );
1.522 + if( KErrNone == ret )
1.523 + {
1.524 + suspendTest.DoTest();
1.525 + }
1.526 +
1.527 + test.End();
1.528 + return KErrNone;
1.529 + }