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