/* * $Log: V:/Flite/archives/TrueFFS5/Src/INFTLDBG.C_V $ * * Rev 1.0 Nov 16 2001 00:44:12 oris * Initial revision. * */ /***********************************************************************************/ /* M-Systems Confidential */ /* Copyright (C) M-Systems Flash Disk Pioneers Ltd. 1995-2001 */ /* All Rights Reserved */ /***********************************************************************************/ /* NOTICE OF M-SYSTEMS OEM */ /* SOFTWARE LICENSE AGREEMENT */ /* */ /* THE USE OF THIS SOFTWARE IS GOVERNED BY A SEPARATE LICENSE */ /* AGREEMENT BETWEEN THE OEM AND M-SYSTEMS. REFER TO THAT AGREEMENT */ /* FOR THE SPECIFIC TERMS AND CONDITIONS OF USE, */ /* OR CONTACT M-SYSTEMS FOR LICENSE ASSISTANCE: */ /* E-MAIL = info@m-sys.com */ /***********************************************************************************/ /*************************************************/ /* T r u e F F S 5.0 S o u r c e F i l e s */ /* --------------------------------------------- */ /*************************************************/ /***************************************************************************** * File Header * * ----------- * * Name : inftldbg.c * * * * Description : Implementation of INFTL debug routine. * * * *****************************************************************************/ /*********************************************************/ /* The following routine are for debuging INFTL chains. */ /* They should not be compiled as part of TrueFFS based */ /* drivers and application. */ /*********************************************************/ /* function prototype */ static FLStatus getUnitData(Bnand vol, ANANDUnitNo unitNo, ANANDUnitNo *virtualUnitNo, ANANDUnitNo *prevUnitNo, byte *ANAC, byte *NAC, byte *validFields); static byte getSectorFlags(Bnand vol, CardAddress sectorAddress); #ifdef CHECK_MOUNT extern FILE* tl_out; /* Macroes */ #define TL_DEBUG_PRINT fprintf #define STATUS_DEBUG_PRINT printf #define SET_EXIT(x) vol.debugState |= x /* Add INFTL debug warnnings */ #define DID_MOUNT_FAIL vol.debugState & INFTL_FAILED_MOUNT #endif /* CHECK_MOUNT */ #ifdef CHAINS_DEBUG byte * fileNameBuf1 = "Chains00.txt"; byte * fileNameBuf2 = "report.txt"; /*------------------------------------------------------------------------*/ /* g e t F i l e H a n d l e */ /* */ /* Get file handle for debug print output file. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* type : File name identifier */ /* */ /* Returns: */ /* File handle to ourput file. */ /*------------------------------------------------------------------------*/ #include FILE* getFileHandle(Bnand vol,byte type) { char *fileName; char *logFileExt; switch (type) { case 0: fileName = fileNameBuf1; break; case 1: fileName = fileNameBuf2; break; default: return NULL; } logFileExt = strchr(fileName,'.'); if (logFileExt == NULL) { return NULL; } else { (*(logFileExt-1))++; } if (DID_MOUNT_FAIL) { return (FILE *)FL_FOPEN(fileName,"a"); } else { return NULL; } } /*------------------------------------------------------------------------*/ /* g o A l o n g V i r t u a l U n i t */ /* */ /* Print the following info for a specified virtual chain: */ /* */ /* Virtual unit number : "Chain #XX :" */ /* Physical unit number : "#XX " */ /* Physical unit ANAC : "(%XX)" */ /* Physical unit NAC : "[%XX]" */ /* Previous unit : "==>:" or "endofchain" */ /* */ /* The virtual unit state can have several comments: */ /* */ /* "FREE" - Legal state where irtual unit has */ /* no physical unit assigned */ /* "Chain XX is too long" - The chains has 2 times the maxium */ /* legal chains length */ /* "Something wrong with chain #XX" - There is a problem with the chain: */ /* a) "this unit should be the last in chain " */ /* The ram convertin table does not have the first in chain mark */ /* for this unit although we know it is the last of its chain. */ /* b) "this unit points to the unit with the different vu no %XX" */ /* The virtual unit field of the current physical unit does not */ /* match the virtual unit number of the chain being inspected. The */ /* new virtual unit is XX */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* virtualUnit : Number of the virtual unit to scan */ /* physUnits : Physical unit table indicating the number of */ /* virtual units each physical unit bellongs to. */ /* out : File pointer for ouput */ /* */ /* Returns: */ /* None */ /*------------------------------------------------------------------------*/ void goAlongVirtualUnit(Bnand vol,word virtualUnit,byte *physUnits,FILE* out) { int i; ANANDUnitNo virtualUnitNo, prevUnitNo,unitNo; byte ANAC,NAC,parityPerField; unitNo=vol.virtualUnits[virtualUnit]; FL_FPRINTF(out,"Chain #%d :", virtualUnit); if(unitNo==ANAND_NO_UNIT) { FL_FPRINTF(out,"FREE\n"); return; } for(i=0;i<2*MAX_UNIT_CHAIN;i++) { if (physUnits != NULL) physUnits[unitNo]++; getUnitData(&vol,unitNo,&virtualUnitNo, &prevUnitNo,&ANAC,&NAC,&parityPerField); FL_FPRINTF(out,"#%d (%d)[%d]==>:",unitNo,ANAC,NAC); if(vol.physicalUnits[unitNo]&FIRST_IN_CHAIN) { FL_FPRINTF(out,"endofchain\n"); return; } unitNo=prevUnitNo; if((prevUnitNo==ANAND_NO_UNIT)||(virtualUnitNo!=virtualUnit)) { FL_FPRINTF(out,"\nSomething wrong with chain #%d\n",virtualUnit); TL_DEBUG_PRINT(tl_out,"\nSomething wrong with chain #%d\n",virtualUnit); SET_EXIT(INFTL_FAILED_MOUNT); if(prevUnitNo==ANAND_NO_UNIT) { FL_FPRINTF(out,"this unit should be the last in chain\n"); TL_DEBUG_PRINT(tl_out,"this unit should be the last in chain (length %d)\n",i); } else { FL_FPRINTF(out,"this unit points to the unit with the different vu no %d\n",virtualUnitNo); TL_DEBUG_PRINT(tl_out,"this unit points to the unit with the different vu no %d\n",virtualUnitNo); } return; } } FL_FPRINTF(out,"Chain %d is too long \n",virtualUnit); TL_DEBUG_PRINT(tl_out,"Chain %d is too long \n",virtualUnit); SET_EXIT(INFTL_FAILED_MOUNT); } /*------------------------------------------------------------------------*/ /* c h e c k V i r t u a l C h a i n s */ /* */ /* Print the physical units in each virtual unit of the media */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* out : File pointer to print the result */ /* */ /* Returns: */ /* None */ /*------------------------------------------------------------------------*/ void checkVirtualChains(Bnand vol, FILE* out) { word i; #ifdef FL_MALLOC byte* physUnits; #else byte physUnits[MAX_SUPPORTED_UNITS]; #endif /* FL_MALLOC */ if (vol.noOfVirtualUnits == 0) /* Not format */ { FL_FPRINTF(out,"\nThis is a format routine since no virtual unit are reported\n"); return; } #ifdef FL_MALLOC physUnits = (byte *)FL_MALLOC(vol.noOfUnits); if (physUnits == NULL) #else if (MAX_SUPPORTED_UNITS < vol.noOfUnits) #endif /* FL_MALLOC */ { FL_FPRINTF(out,"\nCheck virtual chains will not check cross links due to lack of memory\n"); TL_DEBUG_PRINT(tl_out,"\nCheck virtual chains will not check cross links due to lack of memory (no of units %d\n",vol.noOfUnits); SET_EXIT(INFTL_FAILED_MOUNT); return; } if (physUnits != NULL) tffsset(physUnits,0,vol.noOfUnits); /* Go along each of the virtual units */ FL_FPRINTF(out,"Chains are :\n"); for(i=0;i1) { FL_FPRINTF(out,"Phys unit #%d were used more than once %d\n",i,physUnits[i]); TL_DEBUG_PRINT(tl_out,"Phys unit #%d were used more than once.\n",i); TL_DEBUG_PRINT(tl_out,"It was used %d times.\n",physUnits[i]); SET_EXIT(INFTL_FAILED_MOUNT); } } else { FL_FPRINTF(out,"\nCould not check due to lack of memory\n"); } /* Free memory */ #ifdef FL_MALLOC FL_FREE(physUnits); #endif /* FL_MALLOC */ } /*------------------------------------------------------------------------*/ /* c h e c k V o l u m e S t a t i s t i c s */ /* */ /* Print the volume statistics. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* out : File pointer to print the result */ /* */ /* Returns: */ /* None */ /*------------------------------------------------------------------------*/ void checkVolumeStatistics(Bnand vol , FILE* out) { FL_FPRINTF(out,"\nThe volume statistics are:\n"); FL_FPRINTF(out,"Socket nomber ----------------------------------- %d\n",vol.socketNo); FL_FPRINTF(out,"The volume internal flags ----------------------- %d\n",vol.flags); FL_FPRINTF(out,"Number of free units ---------------------------- %d\n",vol.freeUnits); TL_DEBUG_PRINT(tl_out,"Number of free units ---------------------------- %d\n",vol.freeUnits); FL_FPRINTF(out,"Number of boot unit ----------------------------- %d\n",vol.bootUnits); FL_FPRINTF(out,"Number of media units --------------------------- %d\n",vol.noOfUnits); FL_FPRINTF(out,"Number of virtual units ------------------------- %d\n",vol.noOfVirtualUnits); FL_FPRINTF(out,"Number of virtual sector on the volume ---------- %ld\n",vol.virtualSectors); FL_FPRINTF(out,"The media rover unit ---------------------------- %d\n",vol.roverUnit); FL_FPRINTF(out,"Physical first unit number of the volume -------- %d\n",vol.firstUnit); #ifdef NFTL_CACHE FL_FPRINTF(out,"Physical first unit address --------------------- %d\n",vol.firstUnitAddress); #endif /* NFTL_CACHE */ #ifdef QUICK_MOUNT_FEATURE FL_FPRINTF(out,"First quick mount unit -------------------------- %d\n",vol.firstQuickMountUnit); #endif /* QUICK_MOUNT_FEATURE */ FL_FPRINTF(out,"Number of unit with a valid sector count -------- %d\n",vol.countsValid); FL_FPRINTF(out,"The currently mapped sector number -------------- %ld\n",vol.mappedSectorNo); FL_FPRINTF(out,"The currently mapped sector address ------------- %ld\n",vol.mappedSectorAddress); FL_FPRINTF(out,"Number of sectors per unit ---------------------- %d\n",vol.sectorsPerUnit); FL_FPRINTF(out,"Number of bits needed to shift from block to unit %d\n",vol.blockMultiplierBits); FL_FPRINTF(out,"Number of bits used to represent a flash block -- %d\n",vol.erasableBlockSizeBits); FL_FPRINTF(out,"Number of bits used to represent a media unit --- %d\n",vol.unitSizeBits); FL_FPRINTF(out,"Number of sectors read -------------------------- %ld\n",vol.sectorsRead); FL_FPRINTF(out,"Number of sectors written ----------------------- %ld\n",vol.sectorsWritten); FL_FPRINTF(out,"Number of sectors deleted ----------------------- %ld\n",vol.sectorsDeleted); FL_FPRINTF(out,"Number of parasite write ------------------------ %ld\n",vol.parasiteWrites); FL_FPRINTF(out,"Number of units folded -------------------------- %ld\n",vol.unitsFolded); FL_FPRINTF(out,"The total erase counter ------------------------- %ld\n",vol.eraseSum); FL_FPRINTF(out,"Wear leveling counter limit---------------------- %ld\n",vol.wearLevel.alarm); FL_FPRINTF(out,"Wear leveling current unit ---------------------- %d\n",vol.wearLevel.currUnit); FL_FCLOSE(out); } #endif /* CHAINS_DEBUG */ #ifdef CHECK_MOUNT /*------------------------------------------------------------------------*/ /* c h e c k M o u n t I N F T L */ /* */ /* Print Low level errors in INFTL format. */ /* */ /* Parameters: */ /* vol : Pointer identifying drive */ /* */ /* Returns: */ /* flOK on success */ /*------------------------------------------------------------------------*/ FLStatus checkMountINFTL(Bnand vol) { ANANDUnitNo erCount=0,freeUnits=0,iUnit; ANANDUnitNo virtualUnitNo,prevUnitNo; FLStatus status; byte pattern[SECTOR_SIZE],tempbuf[SECTOR_SIZE]; byte sectorFlags,ANAC, NAC, prevANAC, parityPerField; word *erasePatt1; word *erasePatt2; word i,temp; dword sectorAddress; tffsset(pattern,0xff,SECTOR_SIZE); for (iUnit = 0; iUnit < vol.noOfUnits; iUnit++) { STATUS_DEBUG_PRINT("Checking unit %d\r",iUnit); if (vol.physicalUnits[iUnit] != UNIT_BAD) { /*Read unit header*/ status=getUnitData(&vol,iUnit,&virtualUnitNo, &prevUnitNo,&ANAC,&NAC,&parityPerField); if((status!=flOK)||(!isValidParityResult(parityPerField))) { TL_DEBUG_PRINT(tl_out,"Error going along INFTL chains - could not get unit data of %d.\n",iUnit); TL_DEBUG_PRINT(tl_out,"Status = %d and parityPerField is %d.\n",status,parityPerField); SET_EXIT(INFTL_FAILED_MOUNT); continue; } /* FREE unit test that it's all erased and it has erase mark */ if((virtualUnitNo==ANAND_NO_UNIT)&& (prevUnitNo==ANAND_NO_UNIT) && (ANAC==ANAND_UNIT_FREE) && (NAC==ANAND_UNIT_FREE)) { freeUnits++; for(i=0;i<(1<<(vol.unitSizeBits - SECTOR_SIZE_BITS));i++) { /* Extra area */ if(i!=2) /* skip erase mark at - UNIT_TAILER_OFFSET */ { checkStatus(vol.flash.read(&vol.flash, unitBaseAddress(vol,iUnit)+i*SECTOR_SIZE, tempbuf,16,EXTRA)); if(tffscmp(tempbuf,pattern,16)!=0) { TL_DEBUG_PRINT(tl_out,"Extra area of FREE unit is not FF's in %d unit %d sector, it is\n",iUnit,i); for(temp=0;temp<16;temp++) TL_DEBUG_PRINT(tl_out,"%x ",tempbuf[temp]); TL_DEBUG_PRINT(tl_out,"\n\n"); SET_EXIT(INFTL_FAILED_MOUNT); } } else /* Erase mark sector offset */ { checkStatus(vol.flash.read(&vol.flash, unitBaseAddress(vol,iUnit)+i*SECTOR_SIZE, tempbuf,16,EXTRA)); if(tffscmp(tempbuf,pattern,8)!=0) { TL_DEBUG_PRINT(tl_out,"Extra area of FREE unit is not FF's in %d unit %d sector, it is\n",iUnit,i); for(temp=0;temp<16;temp++) TL_DEBUG_PRINT(tl_out,"%x ",tempbuf[temp]); TL_DEBUG_PRINT(tl_out,"\n\n"); SET_EXIT(INFTL_FAILED_MOUNT); } erasePatt1=(unsigned short*)(&(tempbuf[12])); erasePatt2=(unsigned short*)(&(tempbuf[14])); if(*erasePatt1!=ERASE_MARK) { TL_DEBUG_PRINT(tl_out,"First Erase mark of FREE unit is not written well in Unit %d it is %x\n",iUnit,*erasePatt1); } if(*erasePatt2!=ERASE_MARK) { TL_DEBUG_PRINT(tl_out,"Second Erase mark of FREE unit is not written well in Unit %d it is %x\n",iUnit,*erasePatt2); } if ((*erasePatt1!=ERASE_MARK)||(*erasePatt2!=ERASE_MARK)) erCount++; } /* Data area */ checkStatus(vol.flash.read(&vol.flash, unitBaseAddress(vol,iUnit)+i*SECTOR_SIZE, tempbuf,SECTOR_SIZE,0)); if(tffscmp(tempbuf,pattern,SECTOR_SIZE)!=0) { TL_DEBUG_PRINT(tl_out,"Data area of FREE unit is not FF's in %d unit %d sector it is.\n",iUnit,i); for(temp=0;temp