sl@0: // Copyright (c) 1997-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_pccdsk.cpp
sl@0: // Soak test the Compact Flash card (ATA).
sl@0: // 
sl@0: //
sl@0: 
sl@0: 
sl@0: // One of these
sl@0: #define USE_MEDIA_CHANGE
sl@0: //#define USE_POWER_OFF_ON
sl@0: 
sl@0: #include <e32test.h>
sl@0: #include <e32svr.h>
sl@0: #include <e32hal.h>
sl@0: #include <e32uid.h>
sl@0: #include <hal.h>
sl@0: 
sl@0: #define ATA_PDD_NAME _L("MEDATA")
sl@0: 
sl@0: const TInt KAtaSectorSize=512;
sl@0: const TInt KMaxSectors=16;
sl@0: const TInt KMaxRdWrBufLen=(KAtaSectorSize*KMaxSectors); // 8K
sl@0: const TInt KMaxErrPos=5;
sl@0: 
sl@0: LOCAL_D	TBusLocalDrive TheDrive;
sl@0: LOCAL_D TBool ChangedFlag;
sl@0: RTest test(_L("Local Drive Soak Test"));
sl@0: LOCAL_D TBuf8<KMaxRdWrBufLen> wrBuf1,wrBuf2,rdBuf;
sl@0: 
sl@0: class TResult
sl@0: 	{
sl@0: public:
sl@0: 	enum TResTest {EWrite,ERead,ECompare,EFormat,EReMount};
sl@0: 	TResult();
sl@0: 	void Display(CConsoleBase *aConsole, TInt aCycles);
sl@0: 	void Add(TResTest aTst,TInt anErr,TInt anErrPos);
sl@0: 	inline void SetMemStillFree(TInt aVal)
sl@0: 		{iFreeMem=aVal;}
sl@0: 	inline void WriteAborted()
sl@0: 		{iAbortedWrites++;}
sl@0: 	inline TInt WriteFails()
sl@0: 		{return(iWriteTimeoutFails+iWriteWriteFails+iWriteGeneralFails+iWriteCorruptFails+iWriteBatLowFails+iWriteOtherFails);}
sl@0: 	inline TInt ReadFails()
sl@0: 		{return(iReadTimeoutFails+iReadCorruptFails+iReadOtherFails);}
sl@0: 	inline TInt CompareFails()
sl@0: 		{return(iCompareFails);}
sl@0: 	inline TInt FormatFails()
sl@0: 		{return(iFormatTimeoutFails+iFormatEmergencyFails+iFormatBatLowFails+iFormatOtherFails);}
sl@0: 	inline TInt ReMountFails()
sl@0: 		{return(iReMountFails);}
sl@0: public:
sl@0: 	TInt iWriteTimeoutFails;
sl@0: 	TInt iWriteWriteFails;
sl@0: 	TInt iWriteGeneralFails;
sl@0: 	TInt iWriteCorruptFails;
sl@0: 	TInt iWriteBatLowFails;
sl@0: 	TInt iWriteOtherFails;
sl@0: 	TInt iReadTimeoutFails;
sl@0: 	TInt iReadCorruptFails;
sl@0: 	TInt iReadOtherFails;
sl@0: 	TInt iCompareFails;
sl@0: 	TInt iFormatTimeoutFails;
sl@0: 	TInt iFormatEmergencyFails;
sl@0: 	TInt iFormatBatLowFails;
sl@0: 	TInt iFormatOtherFails;
sl@0: 	TInt iReMountFails;
sl@0: 	TInt iLastErrorPos[KMaxErrPos];
sl@0: 	TInt iLastErrorPtr;
sl@0: 	TInt iFreeMem;
sl@0: 	TInt iAbortedWrites;
sl@0: 	};
sl@0: 
sl@0: 
sl@0: LOCAL_C void StatusBar(TInt aPos,TInt anEndPos,TInt aYPos,const TPtrC &aTitle)
sl@0: //
sl@0: // Display progress of local drive operation on screen (1-16 dots)
sl@0: //
sl@0: 	{
sl@0: 	static TInt prev;
sl@0: 	TInt curr;
sl@0: 	if ((curr=(aPos-1)/(anEndPos>>4))>prev)
sl@0: 		{ // Update progress bar
sl@0: 		test.Console()->SetPos(0,aYPos);
sl@0: 		test.Printf(_L("                              "));
sl@0: 		test.Console()->SetPos(2);
sl@0: 		test.Printf(_L("%S "),&aTitle);
sl@0: 		for (TInt i=curr;i>=0;i--)
sl@0: 			test.Printf(_L("."));
sl@0: 		}
sl@0: 	prev=curr;
sl@0: 	}
sl@0: 
sl@0: TResult::TResult()
sl@0: //
sl@0: // Constructor
sl@0: //
sl@0: 	{
sl@0: 
sl@0: 	iWriteTimeoutFails=0;
sl@0: 	iWriteWriteFails=0;
sl@0: 	iWriteGeneralFails=0;
sl@0: 	iWriteCorruptFails=0;
sl@0: 	iWriteBatLowFails=0;
sl@0: 	iWriteOtherFails=0;
sl@0: 	iReadTimeoutFails=0;
sl@0: 	iReadCorruptFails=0;
sl@0: 	iReadOtherFails=0;
sl@0: 	iCompareFails=0;
sl@0: 	iFormatTimeoutFails=0;
sl@0: 	iFormatEmergencyFails=0;
sl@0: 	iFormatBatLowFails=0;
sl@0: 	iFormatOtherFails=0;
sl@0: 	iReMountFails=0;
sl@0: 	for (TInt i=0;i<KMaxErrPos;i++)
sl@0: 		iLastErrorPos[i]=0;
sl@0: 	iLastErrorPtr=0;
sl@0: 	iFreeMem=0;
sl@0: 	iAbortedWrites=0;
sl@0: 	}
sl@0: 
sl@0: void TResult::Display(CConsoleBase *aConsole, TInt aCycles)
sl@0: //
sl@0: // Display test results
sl@0: //
sl@0: 	{
sl@0: 
sl@0: 	TInt xStartPos=3;
sl@0: 	TInt yStartPos=8;
sl@0: 
sl@0: 	aConsole->SetPos(xStartPos,yStartPos);
sl@0: 	test.Printf(_L("Cycles(%08xH) : %d"),iFreeMem,aCycles);
sl@0: 
sl@0: 	aConsole->SetPos(xStartPos,yStartPos+1);
sl@0: 	if (WriteFails())
sl@0: 		test.Printf(_L("Write Fails       : %d (TO:%d BT:%d WR:%d GE:%d CU:%d OT:%d)"),WriteFails(),iWriteTimeoutFails,\
sl@0: 					   iWriteBatLowFails,iWriteWriteFails,iWriteGeneralFails,iWriteCorruptFails,iWriteOtherFails);
sl@0: 	else
sl@0: 		test.Printf(_L("Write Fails       : 0"));
sl@0: 
sl@0: 	aConsole->SetPos(xStartPos,yStartPos+2);
sl@0: 	if (ReadFails())
sl@0: 		test.Printf(_L("Read Fails        : %d (TO:%d CU:%d OT:%d)"),ReadFails(),iReadTimeoutFails,iReadCorruptFails,iReadOtherFails);
sl@0: 	else
sl@0: 		test.Printf(_L("Read Fails        : 0"));
sl@0: 
sl@0: 	aConsole->SetPos(xStartPos,yStartPos+3);
sl@0: 	test.Printf(_L("Compare Fails     : %d"),CompareFails());
sl@0: 
sl@0: 	aConsole->SetPos(xStartPos,yStartPos+4);
sl@0: 	if (FormatFails())
sl@0: 		test.Printf(_L("Format Fails      : %d (TO:%d EM:%d BT:%d OT:%d)"),FormatFails(),iFormatTimeoutFails,iFormatEmergencyFails,iFormatBatLowFails,iFormatOtherFails);
sl@0: 	else
sl@0: 		test.Printf(_L("Format Fails      : 0"));
sl@0: 
sl@0: 	aConsole->SetPos(xStartPos,yStartPos+5);
sl@0: #if defined (USE_MEDIA_CHANGE)
sl@0: 	test.Printf(_L("MediaChange Fails : %d"),ReMountFails());
sl@0: #else
sl@0: 	test.Printf(_L("Pwr off/on Fails  : %d"),ReMountFails());
sl@0: #endif
sl@0: 
sl@0: 	aConsole->SetPos(xStartPos,yStartPos+6);
sl@0: 	test.Printf(_L("Last failures at  : "));
sl@0: 	for (TInt i=iLastErrorPtr;i>0;i--)
sl@0: 		test.Printf(_L("%xH "),iLastErrorPos[i-1]);
sl@0: 	aConsole->SetPos(xStartPos,yStartPos+7);
sl@0: 	test.Printf(_L("Writes aborted    : %d"),iAbortedWrites);
sl@0: 	test.Printf(_L("\r\n"));
sl@0: 	}
sl@0: 
sl@0: void TResult::Add(TResTest aTst,TInt anErr,TInt anErrPos)
sl@0: //
sl@0: // Add a test result
sl@0: //
sl@0: 	{
sl@0: 
sl@0: 	if (anErr!=KErrNone)
sl@0: 		{
sl@0: 		RDebug::Print(_L("%d) %d(%x)"),aTst,anErr,anErrPos);
sl@0: 		// Save start sector involved in operation which failed
sl@0: 		if (anErrPos>=0)
sl@0: 			{
sl@0: 			if (iLastErrorPtr>=KMaxErrPos)
sl@0: 				{
sl@0: 				TInt i;
sl@0: 				for (i=0;i<(KMaxErrPos-1);i++)
sl@0: 					iLastErrorPos[i]=iLastErrorPos[i+1];
sl@0: 				iLastErrorPos[i]=anErrPos;
sl@0: 				}
sl@0: 			else
sl@0: 				{
sl@0: 				iLastErrorPtr++;
sl@0: 				iLastErrorPos[iLastErrorPtr-1]=anErrPos;
sl@0: 				}
sl@0: 			}
sl@0: 
sl@0: 		// Save error type
sl@0: 		switch (aTst)
sl@0: 			{
sl@0: 			case EWrite:
sl@0: 				if (anErr==KErrTimedOut)
sl@0: 					iWriteTimeoutFails++;
sl@0: 				else if (anErr==KErrWrite)
sl@0: 					iWriteWriteFails++;
sl@0: 				else if (anErr==KErrGeneral)
sl@0: 					iWriteGeneralFails++;
sl@0: 				else if (anErr==KErrCorrupt)
sl@0: 					iWriteCorruptFails++;
sl@0: 				else if (anErr==KErrBadPower)
sl@0: 					iWriteBatLowFails++;
sl@0: 				else
sl@0: 					iWriteOtherFails++;
sl@0: 				break;
sl@0: 			case ERead:
sl@0: 				if (anErr==KErrTimedOut)
sl@0: 					iReadTimeoutFails++;
sl@0: 				else if (anErr==KErrCorrupt)
sl@0: 					iReadCorruptFails++;
sl@0: 				else
sl@0: 					iReadOtherFails++;
sl@0: 				break;
sl@0: 			case ECompare:
sl@0: 				iCompareFails++;
sl@0: 				break;
sl@0: 			case EFormat:
sl@0: 				if (anErr==KErrTimedOut)
sl@0: 					iFormatTimeoutFails++;
sl@0: 				else if (anErr==KErrAbort)
sl@0: 					iFormatEmergencyFails++;
sl@0: 				else if (anErr==KErrBadPower)
sl@0: 					iFormatBatLowFails++;
sl@0: 				else
sl@0: 					iFormatOtherFails++;
sl@0: 				break;
sl@0: 			case EReMount:
sl@0: 				iReMountFails++;
sl@0: 				break;
sl@0: 			}
sl@0: 		}
sl@0: 	}
sl@0: 
sl@0: LOCAL_C TUint GetTUintFromConsole(const TDesC &aText)
sl@0: //
sl@0: // Get a TUint value from the console
sl@0: //
sl@0:     {
sl@0: 
sl@0:     TBuf<10> buf(0);
sl@0:     TKeyCode kc;
sl@0:     TUint pos=0;
sl@0: 	test.Printf(aText);
sl@0:     TUint linePos=(aText.Length()+2);
sl@0: 	test.Console()->SetPos(linePos);
sl@0:     FOREVER
sl@0:         {
sl@0: 		switch((kc=test.Getch()))
sl@0: 			{
sl@0:             case EKeyEscape: case EKeyEnter:
sl@0: 				{
sl@0:                 TLex lex(buf);
sl@0: 	            TUint v;
sl@0:                 if (lex.Val(v,EDecimal)==KErrNone)
sl@0:                     return(v);
sl@0:                 return(0);
sl@0: 				}
sl@0:             case EKeyBackspace: case EKeyDelete:
sl@0:                 pos--;
sl@0: 				buf.Delete(pos,1);
sl@0:                 linePos--;
sl@0: 	            test.Console()->SetPos(linePos);
sl@0: 	            test.Printf(_L(" "));
sl@0: 	            test.Console()->SetPos(linePos);
sl@0: 				break;
sl@0:             default:
sl@0: 				TChar ch=(TUint)kc;
sl@0:                 if (ch.IsDigit() && pos<9)
sl@0:                     {
sl@0:                     buf.Append(ch);
sl@0: 					pos++;
sl@0: 	                test.Printf(_L("%c"),(TUint)ch);
sl@0: 					linePos++;
sl@0:                     }
sl@0:                 break;
sl@0: 			}
sl@0:         }
sl@0:     }
sl@0: 
sl@0: GLDEF_C TInt E32Main()
sl@0:     {
sl@0: 	TBuf<64> b;
sl@0: 
sl@0: 	test.Title();
sl@0: 	TDriveInfoV1Buf diBuf;
sl@0: 	UserHal::DriveInfo(diBuf);
sl@0: 	TDriveInfoV1 &di=diBuf();
sl@0: 	test.Printf(_L("Select Local Drive (C-%c): "),'C'+(di.iTotalSupportedDrives-1));
sl@0: 	TChar c;
sl@0: 	TInt drv;
sl@0: 	FOREVER
sl@0: 		{
sl@0: 		c=(TUint)test.Getch();
sl@0: 		c.UpperCase();
sl@0: 		drv=((TUint)c)-'C';
sl@0: 		if (drv>=0&&drv<di.iTotalSupportedDrives)
sl@0: 			break;
sl@0: 		}
sl@0: 	test.Printf(_L("%c:\r\n"),'C'+drv);
sl@0: 
sl@0: 	test.Printf(_L("Select Test Sequence (Sector 1-R,2-WR,3-WRF)/(SubSector 4-R,5-WR,6-WRF): "));
sl@0: 	TInt testSeq;
sl@0: 	FOREVER
sl@0: 		{
sl@0: 		c=(TUint)test.Getch();
sl@0: 		testSeq=((TUint)c)-'0';
sl@0: 		if (testSeq>=0&&testSeq<=6)
sl@0: 			break;
sl@0: 		}
sl@0: 	test.Printf(_L("%d\r\n"),testSeq);
sl@0: 
sl@0: 	TInt RdWrLen=(TInt)GetTUintFromConsole(_L("Select Buffer Size In Sectors: "));
sl@0: 	RdWrLen*=KAtaSectorSize;
sl@0: 
sl@0: 	test.Start(_L("Load Ata Media Driver"));
sl@0: 	TInt r;
sl@0: 	r=User::LoadPhysicalDevice(ATA_PDD_NAME);
sl@0: 	test(r==KErrNone || r==KErrAlreadyExists);
sl@0: #if defined (USE_POWER_OFF_ON)
sl@0: 	RTimer timer;
sl@0: 	test(timer.CreateLocal()==KErrNone);
sl@0: 	TRequestStatus prs;
sl@0: 	TTime tim;
sl@0: #endif
sl@0: 	TInt muid=0;
sl@0: 	r=HAL::Get(HAL::EMachineUid, muid);
sl@0: 	test(r==KErrNone);
sl@0: 	TBool reMountTestSupported=ETrue;
sl@0: //	if (machineName.MatchF(_L("SNOWBALL*"))>=0)	// snowball is ancient history
sl@0: //		reMountTestSupported=EFalse;
sl@0: 
sl@0: 	b.Format(_L("Connect to drive %c:"),'C'+drv);
sl@0: 	test.Next(b);
sl@0: 	ChangedFlag=EFalse;
sl@0: 	TheDrive.Connect(drv,ChangedFlag);
sl@0: 
sl@0: 	test.Next(_L("ATA drive: Capabilities"));
sl@0: 	TLocalDriveCapsV2Buf info;
sl@0: 	test(TheDrive.Caps(info)==KErrNone);
sl@0: 	test(info().iType==EMediaHardDisk);
sl@0: 	TInt diskSize=I64LOW(info().iSize);
sl@0: 
sl@0: 	wrBuf1.SetLength(RdWrLen);
sl@0: 	TInt j;
sl@0: 	for (j=0;j<RdWrLen;j++)
sl@0: 		wrBuf1[j]=(TUint8)j;
sl@0: 	wrBuf2.SetLength(RdWrLen);
sl@0: 	for (j=0;j<RdWrLen;j++)
sl@0: 		wrBuf2[j]=(TUint8)((RdWrLen-1)-j);
sl@0: 
sl@0: 	TUint *p;
sl@0: 	TDes8* wrBuf;
sl@0: 	TInt cycles=0;
sl@0: 	TResult results;
sl@0: 	TBool decendPat=EFalse;
sl@0: 
sl@0: 	TRequestStatus kStat;
sl@0: 	test.Console()->Read(kStat);
sl@0: 	FOREVER
sl@0: 		{
sl@0: 		wrBuf=(decendPat)?&wrBuf2:&wrBuf1;
sl@0: 		p=(decendPat)?(TUint*)&wrBuf2[0]:(TUint*)&wrBuf1[0];
sl@0: 		TInt i,j,len,res;
sl@0: 
sl@0: 		// Recalculate amount of free memory
sl@0:     	TMemoryInfoV1Buf membuf;
sl@0:     	UserHal::MemoryInfo(membuf);
sl@0:     	TMemoryInfoV1 &memoryInfo=membuf();
sl@0: 		results.SetMemStillFree(memoryInfo.iFreeRamInBytes);
sl@0: 		results.Display(test.Console(),cycles);
sl@0: 
sl@0: 		// Write test
sl@0: 		RDebug::Print(_L("0"));
sl@0: 		if (testSeq==2||testSeq==3||testSeq==5||testSeq==6)
sl@0: 			{
sl@0: 			for (i=0,j=0;i<diskSize;i+=len,j++)
sl@0: 				{
sl@0: 				StatusBar(i,diskSize,16,_L("WRITING   "));
sl@0: 				if (testSeq>3)
sl@0: 					len=Min(RdWrLen-3,(diskSize-i)); // Not on sector boundary
sl@0: 				else
sl@0: 					len=Min(RdWrLen,(diskSize-i));
sl@0: 				(*p)=j;
sl@0: 				wrBuf->SetLength(len);
sl@0: 				do
sl@0: 					{
sl@0: 					res=TheDrive.Write(i,*wrBuf);
sl@0: 					if (res==KErrAbort)
sl@0: 						{
sl@0: 						results.WriteAborted();
sl@0: 						results.Display(test.Console(),cycles);
sl@0: 						}
sl@0: 					} while (res==KErrNotReady||res==KErrAbort);
sl@0: 				results.Add(TResult::EWrite,res,i);
sl@0: 				if (res!=KErrNone)
sl@0: 					break;
sl@0: 				}
sl@0: 			results.Display(test.Console(),cycles);
sl@0: 			}
sl@0: 
sl@0: 		// Read test
sl@0: 		RDebug::Print(_L("1"));
sl@0: 		if (testSeq>=1)
sl@0: 			{
sl@0: 			for (i=0,j=0;i<diskSize;i+=len,j++)
sl@0: 				{
sl@0: 				StatusBar(i,diskSize,16,_L("READING   "));
sl@0: 				if (testSeq>3)
sl@0: 					len=Min(RdWrLen-3,(diskSize-i)); // Not on sector boundary
sl@0: 				else
sl@0: 					len=Min(RdWrLen,(diskSize-i));
sl@0: 				rdBuf.Fill(0,len);
sl@0: 				do
sl@0: 					{
sl@0: 					res=TheDrive.Read(i,len,rdBuf);
sl@0: 					} while (res==KErrNotReady);
sl@0: 
sl@0: 				results.Add(TResult::ERead,res,i);
sl@0: 				if (res!=KErrNone)
sl@0: 					break;
sl@0: 				if (testSeq==2||testSeq==3||testSeq==5||testSeq==6)
sl@0: 					{
sl@0: 					(*p)=j;
sl@0: 					wrBuf->SetLength(len);
sl@0: 					if (rdBuf.Compare(*wrBuf)!=0)
sl@0: 						{
sl@0: 						results.Add(TResult::ECompare,KErrGeneral,-1);
sl@0: 						break;
sl@0: 						}
sl@0: 					}
sl@0: 				}
sl@0: 			results.Display(test.Console(),cycles);
sl@0: 			}
sl@0: 
sl@0: 		// Format test
sl@0: 		RDebug::Print(_L("3"));
sl@0: 		if (testSeq==3||testSeq==6)
sl@0: 			{ 
sl@0: 			TFormatInfo fi;
sl@0: 			FOREVER
sl@0: 				{
sl@0: 				StatusBar((fi.i512ByteSectorsFormatted<<9),diskSize,16,_L("FORMATTING"));
sl@0: 				do
sl@0: 					{
sl@0: 					res=TheDrive.Format(fi);
sl@0: 					} while (res==KErrNotReady);
sl@0: 				if (res==KErrEof)
sl@0: 					break;
sl@0: 				results.Add(TResult::EFormat,res,(fi.i512ByteSectorsFormatted<<9));
sl@0: 				if (res!=KErrNone)
sl@0: 					break;
sl@0: 				}
sl@0: 			results.Display(test.Console(),cycles);
sl@0: 			}
sl@0: 
sl@0: 		RDebug::Print(_L("4"));
sl@0: 		if (reMountTestSupported)
sl@0: 			{
sl@0: 			// Media change test / power off-on test
sl@0: #if defined (USE_MEDIA_CHANGE)
sl@0: 			TheDrive.ForceMediaChange();
sl@0: 			if (ChangedFlag==EFalse)
sl@0: 				results.Add(TResult::EReMount,KErrGeneral,-1);
sl@0: #else
sl@0: 			tim.HomeTime();
sl@0: 			tim+=TTimeIntervalSeconds(8);
sl@0: 			timer.At(prs,tim);
sl@0: 			UserHal::SwitchOff();		// Switch off
sl@0: 			User::WaitForRequest(prs);	// Switch back on
sl@0: 			if (prs.Int()!=KErrNone)
sl@0: 				results.Add(TResult::EReMount,KErrGeneral,-1);
sl@0: #endif
sl@0: 			else
sl@0: 				{
sl@0: 				do
sl@0: 					{
sl@0: 					res=TheDrive.Caps(info);
sl@0: 					} while (res==KErrNotReady);
sl@0: 				if (res==KErrNone)
sl@0: 					{
sl@0: 					if (info().iType!=EMediaHardDisk)
sl@0: 						results.Add(TResult::EReMount,KErrGeneral,-1);
sl@0: 					}
sl@0: 				else
sl@0: 					results.Add(TResult::EReMount,res,-1);
sl@0: 				}
sl@0: 			ChangedFlag=EFalse;
sl@0: 			}
sl@0: 
sl@0: 		cycles++;
sl@0: 		decendPat^=0x01;
sl@0: 
sl@0: 		if (kStat!=KRequestPending)
sl@0: 			{
sl@0: 			TKeyCode c=test.Console()->KeyCode();
sl@0: 			if (c==EKeySpace)
sl@0: 				break;
sl@0: 			test.Console()->Read(kStat);
sl@0: 			}
sl@0: 		RDebug::Print(_L("<<"));
sl@0: 		}
sl@0: 
sl@0: 	b.Format(_L("Disconnect from local drive (%c:)"),'C'+drv);
sl@0: 	test.Next(b);
sl@0: 	TheDrive.Disconnect();
sl@0: 
sl@0: 	test.End();
sl@0: 	return(0);
sl@0: 	}
sl@0: