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