sl@0: // Copyright (c) 1996-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: // e32test\pccd\t_atadr3.cpp sl@0: // Test the Compact Flash card (ATA) media driver sl@0: // sl@0: // sl@0: sl@0: #include <e32test.h> sl@0: #include <e32svr.h> sl@0: #include <e32hal.h> sl@0: #include "u32std.h" sl@0: #include "../misc/prbs.h" sl@0: sl@0: //#define __USE_MUTEX__ sl@0: //#define __DISABLE_KILLER__ sl@0: #define SYSTEM ETrue sl@0: sl@0: const TInt KErrVerify=-100; sl@0: sl@0: const TInt KSectorSize=512; sl@0: const TInt KSectorShift=9; sl@0: const TInt KVerifyBlockSize=8; // in sectors sl@0: sl@0: LOCAL_D TBusLocalDrive WriterDrive; sl@0: LOCAL_D RTest test(_L("T_ATADR3")); sl@0: LOCAL_D TInt DriveNumber; sl@0: LOCAL_D TInt DriveSizeInSectors; sl@0: LOCAL_D RThread TheWriterThread; sl@0: LOCAL_D RThread TheKillerThread; sl@0: LOCAL_D RSemaphore Sem; sl@0: LOCAL_D TInt CurrentSector=0; sl@0: LOCAL_D TInt MediaChanges=0; sl@0: LOCAL_D TInt PowerDowns=0; sl@0: LOCAL_D TInt Kills=0; sl@0: LOCAL_D TInt SectorsWritten=0; sl@0: LOCAL_D TInt Aborts=0; sl@0: LOCAL_D TUint WritePattern=0; sl@0: sl@0: #ifdef __USE_MUTEX__ sl@0: LOCAL_D RMutex Mutex; sl@0: #define WAIT Mutex.Wait() sl@0: #define SIGNAL Mutex.Signal() sl@0: #else sl@0: #define WAIT sl@0: #define SIGNAL sl@0: #endif sl@0: sl@0: inline TUint RoundDownToSector(TUint aPos) sl@0: { return aPos&~0x1ff; } sl@0: inline TUint RoundUpToSector(TUint aPos) sl@0: { return (aPos+0x1ff)&~0x1ff; } sl@0: sl@0: LOCAL_C TInt WriteSectors(TBusLocalDrive& aDrive, TInt aSector, TInt aCount, TUint8* aBuf) sl@0: { sl@0: WAIT; sl@0: TInt r=KErrNotReady; sl@0: TInt pos=aSector<<KSectorShift; sl@0: TPtrC8 p(aBuf,aCount*KSectorSize); sl@0: while (r==KErrNotReady || (r==KErrAbort && (++Aborts,1))) sl@0: r=aDrive.Write(pos,p); sl@0: SIGNAL; sl@0: return r; sl@0: } sl@0: sl@0: LOCAL_C TInt ReadSectors(TBusLocalDrive& aDrive, TInt aSector, TInt aCount, TUint8* aBuf) sl@0: { sl@0: WAIT; sl@0: TInt r=KErrNotReady; sl@0: TInt pos=aSector<<KSectorShift; sl@0: TInt len=aCount*KSectorSize; sl@0: TPtr8 p(aBuf,0,len); sl@0: while (r==KErrNotReady || r==KErrAbort) sl@0: r=aDrive.Read(pos,len,p); sl@0: if (r==KErrNone && p.Length()!=len) sl@0: r=KErrUnderflow; sl@0: SIGNAL; sl@0: return r; sl@0: } sl@0: sl@0: LOCAL_C void GenerateTestPattern(TInt aSector, TUint aState, TUint8* aBuf) sl@0: { sl@0: TUint seed[2]; sl@0: seed[1]=0; sl@0: seed[0]=TUint(aSector)^(aState<<16); sl@0: *aBuf++=TUint8(aState&0xff); sl@0: *aBuf++=TUint8((aState>>8)&0xff); sl@0: TInt i; sl@0: for (i=0; i<KSectorSize-2; i++) sl@0: *aBuf++=TUint8(Random(seed)); sl@0: } sl@0: sl@0: LOCAL_C void Write(TBusLocalDrive& aDrive, TInt aSector, TInt aCount, TUint8* aBuf) sl@0: { sl@0: TInt n; sl@0: for (n=0; n<aCount; n++) sl@0: GenerateTestPattern(aSector+n,WritePattern,aBuf+n*KSectorSize); sl@0: TInt r=WriteSectors(aDrive,aSector,aCount,aBuf); sl@0: if (r!=KErrNone) sl@0: User::Panic(_L("WRITE"),r); sl@0: } sl@0: sl@0: LOCAL_C void Write(TBusLocalDrive& aDrive, TInt aSector, TInt aCount) sl@0: { sl@0: const TInt KMaxLen = KSectorSize * 8; sl@0: TInt len=aCount*KSectorSize; sl@0: test (len <= KMaxLen); sl@0: TUint8 buf[KMaxLen]; sl@0: Write(aDrive,aSector,aCount,buf); sl@0: } sl@0: sl@0: LOCAL_C TInt Verify(TInt aSector, TInt aCount, TUint8* aBuf) sl@0: { sl@0: TUint32 buf[KSectorSize/4]; sl@0: TUint8* pB=(TUint8*)buf; sl@0: while(aCount--) sl@0: { sl@0: TUint state=aBuf[0]|(aBuf[1]<<8); sl@0: GenerateTestPattern(aSector,state,pB); sl@0: if (Mem::Compare(aBuf,KSectorSize,pB,KSectorSize)!=0) sl@0: return KErrVerify; sl@0: ++aSector; sl@0: aBuf+=KSectorSize; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: LOCAL_C TInt Verify(TBusLocalDrive& aDrive, TInt aSector, TInt aCount) sl@0: { sl@0: const TInt KMaxLen = KSectorSize * 8; sl@0: TInt len=aCount*KSectorSize; sl@0: test (len <= KMaxLen); sl@0: TUint8 buf[KMaxLen]; sl@0: TInt r=ReadSectors(aDrive,aSector,aCount,buf); sl@0: if (r!=KErrNone) sl@0: return r; sl@0: return Verify(aSector,aCount,buf); sl@0: } sl@0: sl@0: LOCAL_C TInt WriterThread(TAny*) sl@0: { sl@0: /* sl@0: * SetSystem() API was removed by __SECURE_API__ sl@0: * "Systemize" will be implemented later calling a LDD which will set thread's "system" flag sl@0: RThread().SetSystem(SYSTEM); sl@0: */ sl@0: TUint seed[2]; sl@0: seed[0]=User::NTickCount(); sl@0: seed[1]=0; sl@0: TUint32 buf[8*KSectorSize/4]; sl@0: TUint8* pB=(TUint8*)buf; sl@0: TBool medChg=EFalse; sl@0: WriterDrive.Close(); // close handle from previous incarnation of this thread sl@0: TInt r=WriterDrive.Connect(DriveNumber,medChg); sl@0: if (r!=KErrNone) sl@0: User::Panic(_L("WRITER-CONNECT"),r); sl@0: FOREVER sl@0: { sl@0: TInt remain=DriveSizeInSectors-CurrentSector; sl@0: TInt n=Random(seed)&15; sl@0: if (n>8 || n==0) sl@0: n=1; sl@0: if (n>remain) sl@0: n=remain; sl@0: if (n==1) sl@0: { sl@0: Write(WriterDrive,CurrentSector,1,pB); sl@0: ++WritePattern; sl@0: Write(WriterDrive,CurrentSector,1,pB+KSectorSize); sl@0: SectorsWritten+=2; sl@0: } sl@0: else sl@0: { sl@0: Write(WriterDrive,CurrentSector,n,pB); sl@0: SectorsWritten+=n; sl@0: } sl@0: CurrentSector+=n; sl@0: if (CurrentSector==DriveSizeInSectors) sl@0: { sl@0: CurrentSector=0; sl@0: ++WritePattern; sl@0: } sl@0: } sl@0: } sl@0: sl@0: LOCAL_C TInt KillerThread(TAny*) sl@0: { sl@0: /* sl@0: * SetSystem() API was removed by __SECURE_API__ sl@0: * "Systemize" will be implemented later calling a LDD which will set thread's "system" flag sl@0: RThread().SetSystem(SYSTEM); sl@0: */ sl@0: TUint seed[2]; sl@0: seed[0]=0xadf85458; sl@0: seed[1]=0; sl@0: TBusLocalDrive drive; sl@0: TBool medChg=EFalse; sl@0: TInt r=drive.Connect(DriveNumber,medChg); sl@0: if (r!=KErrNone) sl@0: User::Panic(_L("KILLER-CONNECT"),r); sl@0: RTimer timer; sl@0: r=timer.CreateLocal(); sl@0: if (r!=KErrNone) sl@0: User::Panic(_L("KILLER-TIMER"),r); sl@0: TInt action=0; sl@0: FOREVER sl@0: { sl@0: TUint x=Random(seed); sl@0: TUint ms=1000+(x&4095); sl@0: User::AfterHighRes(ms*1000); sl@0: switch (action) sl@0: { sl@0: case 0: sl@0: #ifndef __DISABLE_KILLER__ sl@0: drive.ForceMediaChange(); sl@0: #endif sl@0: ++MediaChanges; sl@0: break; sl@0: case 1: sl@0: { sl@0: #ifndef __DISABLE_KILLER__ sl@0: TTime now; sl@0: now.HomeTime(); sl@0: now+=TTimeIntervalSeconds(2); sl@0: TRequestStatus s; sl@0: timer.At(s,now); sl@0: UserHal::SwitchOff(); sl@0: User::WaitForRequest(s); sl@0: ++PowerDowns; sl@0: #endif sl@0: break; sl@0: } sl@0: case 2: sl@0: #ifndef __DISABLE_KILLER__ sl@0: TheWriterThread.Kill(0); sl@0: #endif sl@0: ++Kills; sl@0: #ifndef __DISABLE_KILLER__ sl@0: ++WritePattern; sl@0: Sem.Wait(); sl@0: TheWriterThread.SetPriority(EPriorityNormal); sl@0: #endif sl@0: break; sl@0: case 3: sl@0: #ifndef __DISABLE_KILLER__ sl@0: drive.ForceMediaChange(); sl@0: #endif sl@0: ++MediaChanges; sl@0: #ifndef __DISABLE_KILLER__ sl@0: x=Random(seed); sl@0: ms=50+(x&511); sl@0: User::AfterHighRes(ms*1000); sl@0: TheWriterThread.Kill(0); sl@0: #endif sl@0: ++Kills; sl@0: #ifndef __DISABLE_KILLER__ sl@0: ++WritePattern; sl@0: Sem.Wait(); sl@0: TheWriterThread.SetPriority(EPriorityNormal); sl@0: #endif sl@0: break; sl@0: case 4: sl@0: break; sl@0: } sl@0: if (++action==5) sl@0: action=0; sl@0: #ifndef __DISABLE_KILLER__ sl@0: TInt curr=CurrentSector; sl@0: TInt remain=DriveSizeInSectors-curr; sl@0: TInt n=(remain<8)?remain:8; sl@0: r=Verify(drive,curr,n); sl@0: if (r!=KErrNone) sl@0: User::Panic(_L("VERIFY"),r); sl@0: #endif sl@0: } sl@0: } sl@0: sl@0: LOCAL_C TInt CreateKillerThread() sl@0: { sl@0: TInt r=TheKillerThread.Create(_L("Killer"),KillerThread,0x2000,NULL,NULL); sl@0: if (r!=KErrNone) sl@0: return r; sl@0: TheKillerThread.SetPriority(EPriorityMore); sl@0: TheKillerThread.Resume(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: LOCAL_C TInt CreateWriterThread() sl@0: { sl@0: FOREVER sl@0: { sl@0: TInt r=TheWriterThread.Create(_L("Writer"),WriterThread,0x2000,NULL,NULL); sl@0: if (r==KErrNone) sl@0: break; sl@0: if (r!=KErrAlreadyExists) sl@0: return r; sl@0: test.Printf(_L("Writer thread still exists\n")); sl@0: User::After(200000); sl@0: } sl@0: TheWriterThread.SetPriority(EPriorityLess); sl@0: TheWriterThread.Resume(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: { sl@0: /* sl@0: * SetSystem() API was removed by __SECURE_API__ sl@0: * "Systemize" will be implemented later calling a LDD which will set thread's "system" flag sl@0: RThread().SetSystem(SYSTEM); sl@0: */ sl@0: WriterDrive.SetHandle(0); sl@0: test.Title(); sl@0: TInt drv=-1; sl@0: while (drv<0 || drv>=KMaxLocalDrives) sl@0: { sl@0: test.Printf(_L("\nSelect drive C-K: ")); sl@0: TChar c=(TUint)test.Getch(); sl@0: c.UpperCase(); sl@0: if (c.IsAlpha()) sl@0: drv=TUint(c)-'C'; sl@0: else sl@0: drv=-1; sl@0: } sl@0: TBuf<1> b; sl@0: b.SetLength(1); sl@0: b[0]=(TText)(drv+'C'); sl@0: test.Printf(_L("%S\n"),&b); sl@0: sl@0: TBuf<80> buf=_L("Connect to drive "); sl@0: buf+=b; sl@0: test.Start(buf); sl@0: TBusLocalDrive drive; sl@0: TBool medChg=EFalse; sl@0: TInt r=drive.Connect(drv,medChg); sl@0: test(r==KErrNone); sl@0: DriveNumber=drv; sl@0: sl@0: test.Next(_L("Get capabilities")); sl@0: TLocalDriveCapsV2 driveCaps; sl@0: TPckg<TLocalDriveCapsV2> capsPckg(driveCaps); sl@0: r=drive.Caps(capsPckg); sl@0: test(r==KErrNone); sl@0: TUint driveSize=I64LOW(driveCaps.iSize); sl@0: DriveSizeInSectors=(driveSize&~0xfff)>>KSectorShift; // round down to multiple of 8 sectors sl@0: test.Printf(_L("Drive size = %08x (%dK)\n"),driveSize,driveSize>>10); sl@0: test.Printf(_L("Media type = %d\n"),driveCaps.iType); sl@0: test.Printf(_L("Connection Bus = %d\n"),driveCaps.iConnectionBusType); sl@0: test.Printf(_L("Drive attributes = %08x\n"),driveCaps.iDriveAtt); sl@0: test.Printf(_L("Media attributes = %08x\n"),driveCaps.iMediaAtt); sl@0: test.Printf(_L("Base address = %08x\n"),driveCaps.iBaseAddress); sl@0: test.Printf(_L("File system ID = %08x\n"),driveCaps.iFileSystemId); sl@0: test.Printf(_L("Hidden sectors = %08x\n"),driveCaps.iHiddenSectors); sl@0: test.Printf(_L("Press any key...\n")); sl@0: test.Getch(); sl@0: sl@0: #ifdef __USE_MUTEX__ sl@0: test.Next(_L("Create mutex")); sl@0: r=Mutex.CreateLocal(); sl@0: test(r==KErrNone); sl@0: #endif sl@0: sl@0: test.Next(_L("Initialise drive")); sl@0: TInt sector; sl@0: for (sector=0; sector<DriveSizeInSectors; sector+=8) sl@0: { sl@0: Write(drive,sector,8); sl@0: if ((sector&127)==0) sl@0: test.Printf(_L(".")); sl@0: } sl@0: test.Printf(_L("\n")); sl@0: test.Next(_L("Verify drive")); sl@0: for (sector=0; sector<DriveSizeInSectors; sector+=8) sl@0: { sl@0: test(Verify(drive,sector,8)==KErrNone); sl@0: if ((sector&127)==0) sl@0: test.Printf(_L(".")); sl@0: } sl@0: sl@0: test.Printf(_L("\n\nPress ENTER to continue...")); sl@0: TKeyCode k=EKeyNull; sl@0: while (k!=EKeyEnter) sl@0: k=test.Getch(); sl@0: test.Printf(_L("\n")); sl@0: sl@0: test.Next(_L("Create semaphore")); sl@0: r=Sem.CreateLocal(0); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Create writer thread")); sl@0: r=CreateWriterThread(); sl@0: test(r==KErrNone); sl@0: TheWriterThread.SetPriority(EPriorityNormal); sl@0: test.Next(_L("Create killer thread")); sl@0: r=CreateKillerThread(); sl@0: test(r==KErrNone); sl@0: sl@0: TBool exit=EFalse; sl@0: sector=0; sl@0: TInt verifies=0; sl@0: TInt fails=0; sl@0: while (!exit) sl@0: { sl@0: r=Verify(drive,sector,KVerifyBlockSize); sl@0: if (r!=KErrNone) sl@0: { sl@0: ++fails; sl@0: test.Printf(_L("Sector %d Fail %d\n"),sector,r); sl@0: } sl@0: else sl@0: ++verifies; sl@0: sector+=KVerifyBlockSize; sl@0: if (sector==DriveSizeInSectors) sl@0: { sl@0: sector=0; sl@0: test.Printf(_L("W %d VER %d FAIL %d MC %d PD %d K %d A %d\n"),SectorsWritten,verifies,fails,MediaChanges,PowerDowns,Kills,Aborts); sl@0: } sl@0: if ((sector&63)==0) sl@0: { sl@0: if (TheKillerThread.ExitType()!=EExitPending) sl@0: { sl@0: const TDesC& cat=TheKillerThread.ExitCategory(); sl@0: test.Printf(_L("KillerThread exited %d,%d,%S\n"),TheKillerThread.ExitType(), sl@0: TheKillerThread.ExitReason(),&cat); sl@0: break; sl@0: } sl@0: TExitType xt=TheWriterThread.ExitType(); sl@0: if (xt==EExitPanic) sl@0: { sl@0: const TDesC& cat=TheWriterThread.ExitCategory(); sl@0: test.Printf(_L("WriterThread Panic %S %d\n"),&cat,TheWriterThread.ExitReason()); sl@0: break; sl@0: } sl@0: if (xt!=EExitPending) sl@0: { sl@0: // restart writer thread sl@0: TheWriterThread.Close(); sl@0: r=CreateWriterThread(); sl@0: if (r!=KErrNone) sl@0: { sl@0: test.Printf(_L("Restart writer thread failed %d\n"),r); sl@0: break; sl@0: } sl@0: Sem.Signal(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: buf=_L("Disconnect from drive "); sl@0: buf+=b; sl@0: test.Next(buf); sl@0: drive.Disconnect(); sl@0: test.End(); sl@0: return 0; sl@0: }