X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_tagscompat.c;h=d594d6193245ff7ae2f09c5ea063906c56bf7225;hp=98b7b0420a89b1d072ab7d163cdcf92ae7161eb1;hb=e1ac494e05a5dc7ab61d799af815d103a11d318c;hpb=dccf947cb075996a9f2d833c55760af7d5e42be9 diff --git a/yaffs_tagscompat.c b/yaffs_tagscompat.c index 98b7b04..d594d61 100644 --- a/yaffs_tagscompat.c +++ b/yaffs_tagscompat.c @@ -1,48 +1,48 @@ /* - * YAFFS: Yet another FFS. A NAND-flash specific file system. - * yaffs_tagscompat.h: Tags compatability layer to use YAFFS1 formatted NAND. + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. * - * Copyright (C) 2002 Aleph One Ltd. + * Copyright (C) 2002-2007 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering * * Created by Charles Manning * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. - * - * $Id: yaffs_tagscompat.c,v 1.2 2005-03-16 04:00:36 charles Exp $ */ #include "yaffs_guts.h" #include "yaffs_tagscompat.h" #include "yaffs_ecc.h" -static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND); -static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND); -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare); -static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare); -static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND); - - +static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND); +#ifdef NOTYET +static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND); +static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, + const __u8 * data, + const yaffs_Spare * spare); +static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND, + const yaffs_Spare * spare); +static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND); +#endif -static const char yaffs_countBitsTable[256] = -{ -0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4, -1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, -1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, -2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, -1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, -2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, -2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, -3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, -1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5, -2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, -2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, -3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, -2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6, -3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, -3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7, -4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 +static const char yaffs_countBitsTable[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 }; static int yaffs_CountBits(__u8 x) @@ -52,33 +52,29 @@ static int yaffs_CountBits(__u8 x) return retVal; } +/********** Tags ECC calculations *********/ -/////////////// Tags ECC calculations /////////////////// - -void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) +void yaffs_CalcECC(const __u8 * data, yaffs_Spare * spare) { - yaffs_ECCCalculate(data , spare->ecc1); - yaffs_ECCCalculate(&data[256] , spare->ecc2); + yaffs_ECCCalculate(data, spare->ecc1); + yaffs_ECCCalculate(&data[256], spare->ecc2); } -void yaffs_CalcTagsECC(yaffs_Tags *tags) +void yaffs_CalcTagsECC(yaffs_Tags * tags) { - // Calculate an ecc + /* Calculate an ecc */ - unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes; - unsigned i,j; - unsigned ecc = 0; + unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes; + unsigned i, j; + unsigned ecc = 0; unsigned bit = 0; tags->ecc = 0; - for(i = 0; i < 8; i++) - { - for(j = 1; j &0xff; j<<=1) - { + for (i = 0; i < 8; i++) { + for (j = 1; j & 0xff; j <<= 1) { bit++; - if(b[i] & j) - { + if (b[i] & j) { ecc ^= bit; } } @@ -86,49 +82,46 @@ void yaffs_CalcTagsECC(yaffs_Tags *tags) tags->ecc = ecc; - } -int yaffs_CheckECCOnTags(yaffs_Tags *tags) +int yaffs_CheckECCOnTags(yaffs_Tags * tags) { unsigned ecc = tags->ecc; yaffs_CalcTagsECC(tags); ecc ^= tags->ecc; - - if(ecc && ecc <= 64) - { - // TODO: Handle the failure better. Retire? - unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes; + + if (ecc && ecc <= 64) { + /* TODO: Handle the failure better. Retire? */ + unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes; ecc--; b[ecc / 8] ^= (1 << (ecc & 7)); - // Now recvalc the ecc + /* Now recvalc the ecc */ yaffs_CalcTagsECC(tags); - return 1; // recovered error - } - else if(ecc) - { - // Wierd ecc failure value - // TODO Need to do somethiong here - return -1; //unrecovered error + return 1; /* recovered error */ + } else if (ecc) { + /* Wierd ecc failure value */ + /* TODO Need to do somethiong here */ + return -1; /* unrecovered error */ } return 0; } -//////////////////////////// Tags /////////////////////////////////////// +/********** Tags **********/ -static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr) +static void yaffs_LoadTagsIntoSpare(yaffs_Spare * sparePtr, + yaffs_Tags * tagsPtr) { - yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr; + yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr; yaffs_CalcTagsECC(tagsPtr); - + sparePtr->tagByte0 = tu->asBytes[0]; sparePtr->tagByte1 = tu->asBytes[1]; sparePtr->tagByte2 = tu->asBytes[2]; @@ -139,558 +132,399 @@ static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr) sparePtr->tagByte7 = tu->asBytes[7]; } -static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr) +static void yaffs_GetTagsFromSpare(yaffs_Device * dev, yaffs_Spare * sparePtr, + yaffs_Tags * tagsPtr) { - yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr; + yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr; int result; - tu->asBytes[0]= sparePtr->tagByte0; - tu->asBytes[1]= sparePtr->tagByte1; - tu->asBytes[2]= sparePtr->tagByte2; - tu->asBytes[3]= sparePtr->tagByte3; - tu->asBytes[4]= sparePtr->tagByte4; - tu->asBytes[5]= sparePtr->tagByte5; - tu->asBytes[6]= sparePtr->tagByte6; - tu->asBytes[7]= sparePtr->tagByte7; - - result = yaffs_CheckECCOnTags(tagsPtr); - if(result> 0) - { + tu->asBytes[0] = sparePtr->tagByte0; + tu->asBytes[1] = sparePtr->tagByte1; + tu->asBytes[2] = sparePtr->tagByte2; + tu->asBytes[3] = sparePtr->tagByte3; + tu->asBytes[4] = sparePtr->tagByte4; + tu->asBytes[5] = sparePtr->tagByte5; + tu->asBytes[6] = sparePtr->tagByte6; + tu->asBytes[7] = sparePtr->tagByte7; + + result = yaffs_CheckECCOnTags(tagsPtr); + if (result > 0) { dev->tagsEccFixed++; - } - else if(result <0) - { + } else if (result < 0) { dev->tagsEccUnfixed++; } } -static void yaffs_SpareInitialise(yaffs_Spare *spare) +static void yaffs_SpareInitialise(yaffs_Spare * spare) { - memset(spare,0xFF,sizeof(yaffs_Spare)); + memset(spare, 0xFF, sizeof(yaffs_Spare)); } - - - -static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare) +static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev, + int chunkInNAND, const __u8 * data, + yaffs_Spare * spare) { - if(chunkInNAND < dev->startBlock * dev->nChunksPerBlock) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),chunkInNAND)); + if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) { + T(YAFFS_TRACE_ERROR, + (TSTR("**>> yaffs chunk %d is not valid" TENDSTR), + chunkInNAND)); return YAFFS_FAIL; } dev->nPageWrites++; - return dev->writeChunkToNAND(dev,chunkInNAND,data,spare); + return dev->writeChunkToNAND(dev, chunkInNAND, data, spare); } - - static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, - int chunkInNAND, - __u8 *data, - yaffs_Spare *spare, - yaffs_ECCResult *eccResult, - int doErrorCorrection) + int chunkInNAND, + __u8 * data, + yaffs_Spare * spare, + yaffs_ECCResult * eccResult, + int doErrorCorrection) { int retVal; yaffs_Spare localSpare; dev->nPageReads++; - - - - - if(!spare && data) - { - // If we don't have a real spare, then we use a local one. - // Need this for the calculation of the ecc + + if (!spare && data) { + /* If we don't have a real spare, then we use a local one. */ + /* Need this for the calculation of the ecc */ spare = &localSpare; } - - - if(!dev->useNANDECC) - { - retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,spare); - if(data && doErrorCorrection) - { - // Do ECC correction - //Todo handle any errors - int eccResult1,eccResult2; - __u8 calcEcc[3]; - - yaffs_ECCCalculate(data,calcEcc); - eccResult1 = yaffs_ECCCorrect (data,spare->ecc1, calcEcc); - yaffs_ECCCalculate(&data[256],calcEcc); - eccResult2 = yaffs_ECCCorrect(&data[256],spare->ecc2, calcEcc); - - if(eccResult1>0) - { - T(YAFFS_TRACE_ERROR, (TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND)); + + if (!dev->useNANDECC) { + retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare); + if (data && doErrorCorrection) { + /* Do ECC correction */ + /* Todo handle any errors */ + int eccResult1, eccResult2; + __u8 calcEcc[3]; + + yaffs_ECCCalculate(data, calcEcc); + eccResult1 = + yaffs_ECCCorrect(data, spare->ecc1, calcEcc); + yaffs_ECCCalculate(&data[256], calcEcc); + eccResult2 = + yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc); + + if (eccResult1 > 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>yaffs ecc error fix performed on chunk %d:0" + TENDSTR), chunkInNAND)); dev->eccFixed++; - } - else if(eccResult1<0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND)); + } else if (eccResult1 < 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>yaffs ecc error unfixed on chunk %d:0" + TENDSTR), chunkInNAND)); dev->eccUnfixed++; } - if(eccResult2>0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND)); + if (eccResult2 > 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>yaffs ecc error fix performed on chunk %d:1" + TENDSTR), chunkInNAND)); dev->eccFixed++; - } - else if(eccResult2<0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND)); + } else if (eccResult2 < 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>yaffs ecc error unfixed on chunk %d:1" + TENDSTR), chunkInNAND)); dev->eccUnfixed++; } - if(eccResult1 || eccResult2) - { - // Hoosterman, we had a data problem on this page - yaffs_HandleReadDataError(dev,chunkInNAND); + if (eccResult1 || eccResult2) { + /* We had a data problem on this page */ + yaffs_HandleReadDataError(dev, chunkInNAND); } - - if(eccResult1 < 0 || eccResult2 < 0) + + if (eccResult1 < 0 || eccResult2 < 0) *eccResult = YAFFS_ECC_RESULT_UNFIXED; - else if(eccResult1 > 0 || eccResult2 > 0) + else if (eccResult1 > 0 || eccResult2 > 0) *eccResult = YAFFS_ECC_RESULT_FIXED; else *eccResult = YAFFS_ECC_RESULT_NO_ERROR; } - } - else - { - // Must allocate enough memory for spare+2*sizeof(int) for ecc results from device. - struct yaffs_NANDSpare nspare; - retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare*)&nspare); - memcpy (spare, &nspare, sizeof(yaffs_Spare)); - if(data && doErrorCorrection) - { - if(nspare.eccres1>0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND)); - } - else if(nspare.eccres1<0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND)); + } else { + /* Must allocate enough memory for spare+2*sizeof(int) */ + /* for ecc results from device. */ + struct yaffs_NANDSpare nspare; + retVal = + dev->readChunkFromNAND(dev, chunkInNAND, data, + (yaffs_Spare *) & nspare); + memcpy(spare, &nspare, sizeof(yaffs_Spare)); + if (data && doErrorCorrection) { + if (nspare.eccres1 > 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>mtd ecc error fix performed on chunk %d:0" + TENDSTR), chunkInNAND)); + } else if (nspare.eccres1 < 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>mtd ecc error unfixed on chunk %d:0" + TENDSTR), chunkInNAND)); } - if(nspare.eccres2>0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND)); - } - else if(nspare.eccres2<0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND)); + if (nspare.eccres2 > 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>mtd ecc error fix performed on chunk %d:1" + TENDSTR), chunkInNAND)); + } else if (nspare.eccres2 < 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>mtd ecc error unfixed on chunk %d:1" + TENDSTR), chunkInNAND)); } - if(nspare.eccres1 || nspare.eccres2) - { - // Hoosterman, we had a data problem on this page - yaffs_HandleReadDataError(dev,chunkInNAND); + if (nspare.eccres1 || nspare.eccres2) { + /* We had a data problem on this page */ + yaffs_HandleReadDataError(dev, chunkInNAND); } - - if(nspare.eccres1 < 0 || nspare.eccres2 < 0) + + if (nspare.eccres1 < 0 || nspare.eccres2 < 0) *eccResult = YAFFS_ECC_RESULT_UNFIXED; - else if(nspare.eccres1 > 0 || nspare.eccres2 > 0) + else if (nspare.eccres1 > 0 || nspare.eccres2 > 0) *eccResult = YAFFS_ECC_RESULT_FIXED; else *eccResult = YAFFS_ECC_RESULT_NO_ERROR; - } } return retVal; } - - -static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND) +#ifdef NOTYET +static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev, + int chunkInNAND) { static int init = 0; static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK]; static __u8 data[YAFFS_BYTES_PER_CHUNK]; - // Might as well always allocate the larger size for dev->useNANDECC == true; + /* Might as well always allocate the larger size for */ + /* dev->useNANDECC == true; */ static __u8 spare[sizeof(struct yaffs_NANDSpare)]; - dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare); + dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare); - if(!init) - { - memset(cmpbuf,0xff,YAFFS_BYTES_PER_CHUNK); + if (!init) { + memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK); init = 1; } - if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) return YAFFS_FAIL; - if(memcmp(cmpbuf,spare,16)) return YAFFS_FAIL; - + if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK)) + return YAFFS_FAIL; + if (memcmp(cmpbuf, spare, 16)) + return YAFFS_FAIL; return YAFFS_OK; } +#endif +/* + * Functions for robustisizing + */ -#if 0 -int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND) +static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND) { - dev->nBlockErasures++; - return dev->eraseBlockInNAND(dev,blockInNAND); + int blockInNAND = chunkInNAND / dev->nChunksPerBlock; + + /* Mark the block for retirement */ + yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1; + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, + (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND)); + + /* TODO: + * Just do a garbage collection on the affected block + * then retire the block + * NB recursion + */ } -int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev) +#ifdef NOTYET +static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND) { - return dev->initialiseNAND(dev); } -#endif - -#if 0 -static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_Spare *spare,int useReserve) +static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND, + const __u8 * data, + const yaffs_Spare * spare) { - int chunk; - - int writeOk = 1; - int attempts = 0; - - unsigned char rbData[YAFFS_BYTES_PER_CHUNK]; - yaffs_Spare rbSpare; - - do{ - chunk = yaffs_AllocateChunk(dev,useReserve); - - if(chunk >= 0) - { - - // First check this chunk is erased... -#ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK - writeOk = yaffs_CheckChunkErased(dev,chunk); -#endif - if(!writeOk) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk)); - } - else - { - writeOk = yaffs_WriteChunkToNAND(dev,chunk,data,spare); - } - attempts++; - if(writeOk) - { - // Readback & verify - // If verify fails, then delete this chunk and try again - // To verify we compare everything except the block and - // page status bytes. - // NB We check a raw read without ECC correction applied - yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare,0); - -#ifndef CONFIG_YAFFS_DISABLE_WRITE_VERIFY - if(!yaffs_VerifyCompare(data,rbData,spare,&rbSpare)) - { - // Didn't verify - T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write verify failed on chunk %d" TENDSTR), chunk)); - - writeOk = 0; - } -#endif - - } - if(writeOk) - { - // Copy the data into the write buffer. - // NB We do this at the end to prevent duplicates in the case of a write error. - //Todo - yaffs_HandleWriteChunkOk(dev,chunk,data,spare); - } - else - { - yaffs_HandleWriteChunkError(dev,chunk); - } - } - - } while(chunk >= 0 && ! writeOk); - - if(attempts > 1) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts)); - dev->nRetriedWrites+= (attempts - 1); - } - - return chunk; } -#endif - -/// -// Functions for robustisizing -// -// -#if 0 - -static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND) +static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND, + const yaffs_Spare * spare) { - // Ding the blockStatus in the first two pages of the block. - - yaffs_Spare spare; - - memset(&spare, 0xff,sizeof(yaffs_Spare)); - - spare.blockStatus = 0; +} - // TODO change this retirement marking for other NAND types - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL , &spare); - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, NULL , &spare); +static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND) +{ + int blockInNAND = chunkInNAND / dev->nChunksPerBlock; - yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD; - dev->nRetiredBlocks++; + /* Mark the block for retirement */ + yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1; + /* Delete the chunk */ + yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__); } -#endif - -#if 0 -static int yaffs_RewriteBufferedBlock(yaffs_Device *dev) +static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1, + const yaffs_Spare * s0, const yaffs_Spare * s1) { - dev->doingBufferedBlockRewrite = 1; - // - // Remove erased chunks - // Rewrite existing chunks to a new block - // Set current write block to the new block - dev->doingBufferedBlockRewrite = 0; + if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 || + s0->tagByte0 != s1->tagByte0 || + s0->tagByte1 != s1->tagByte1 || + s0->tagByte2 != s1->tagByte2 || + s0->tagByte3 != s1->tagByte3 || + s0->tagByte4 != s1->tagByte4 || + s0->tagByte5 != s1->tagByte5 || + s0->tagByte6 != s1->tagByte6 || + s0->tagByte7 != s1->tagByte7 || + s0->ecc1[0] != s1->ecc1[0] || + s0->ecc1[1] != s1->ecc1[1] || + s0->ecc1[2] != s1->ecc1[2] || + s0->ecc2[0] != s1->ecc2[0] || + s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) { + return 0; + } return 1; } +#endif /* NOTYET */ -#endif - -static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND) +int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev, + int chunkInNAND, + const __u8 * data, + const yaffs_ExtendedTags * + eTags) { - int blockInNAND = chunkInNAND/dev->nChunksPerBlock; - - // Mark the block for retirement - yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1; - T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>>Block %d marked for retirement" TENDSTR),blockInNAND)); + yaffs_Spare spare; + yaffs_Tags tags; + yaffs_SpareInitialise(&spare); - //TODO - // Just do a garbage collection on the affected block then retire the block - // NB recursion -} + if (eTags->chunkDeleted) { + spare.pageStatus = 0; + } else { + tags.objectId = eTags->objectId; + tags.chunkId = eTags->chunkId; + tags.byteCount = eTags->byteCount; + tags.serialNumber = eTags->serialNumber; + if (!dev->useNANDECC && data) { + yaffs_CalcECC(data, &spare); + } + yaffs_LoadTagsIntoSpare(&spare, &tags); -static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND) -{ -} + } -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare) -{ + return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare); } -static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare) +int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev, + int chunkInNAND, + __u8 * data, + yaffs_ExtendedTags * eTags) { -} -static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND) -{ - int blockInNAND = chunkInNAND/dev->nChunksPerBlock; + yaffs_Spare spare; + yaffs_Tags tags; + yaffs_ECCResult eccResult; - // Mark the block for retirement - yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1; - // Delete the chunk - yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__); -} + static yaffs_Spare spareFF; + static int init; + if (!init) { + memset(&spareFF, 0xFF, sizeof(spareFF)); + init = 1; + } + if (yaffs_ReadChunkFromNAND + (dev, chunkInNAND, data, &spare, &eccResult, 1)) { + /* eTags may be NULL */ + if (eTags) { + int deleted = + (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0; -static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1) -{ + eTags->chunkDeleted = deleted; + eTags->eccResult = eccResult; + eTags->blockBad = 0; /* We're reading it */ + /* therefore it is not a bad block */ + eTags->chunkUsed = + (memcmp(&spareFF, &spare, sizeof(spareFF)) != + 0) ? 1 : 0; + if (eTags->chunkUsed) { + yaffs_GetTagsFromSpare(dev, &spare, &tags); - if( memcmp(d0,d1,YAFFS_BYTES_PER_CHUNK) != 0 || - s0->tagByte0 != s1->tagByte0 || - s0->tagByte1 != s1->tagByte1 || - s0->tagByte2 != s1->tagByte2 || - s0->tagByte3 != s1->tagByte3 || - s0->tagByte4 != s1->tagByte4 || - s0->tagByte5 != s1->tagByte5 || - s0->tagByte6 != s1->tagByte6 || - s0->tagByte7 != s1->tagByte7 || - s0->ecc1[0] != s1->ecc1[0] || - s0->ecc1[1] != s1->ecc1[1] || - s0->ecc1[2] != s1->ecc1[2] || - s0->ecc2[0] != s1->ecc2[0] || - s0->ecc2[1] != s1->ecc2[1] || - s0->ecc2[2] != s1->ecc2[2] ) - { - return 0; + eTags->objectId = tags.objectId; + eTags->chunkId = tags.chunkId; + eTags->byteCount = tags.byteCount; + eTags->serialNumber = tags.serialNumber; + } } - return 1; + return YAFFS_OK; + } else { + return YAFFS_FAIL; + } } -#if 0 -typedef struct +int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, + int blockInNAND) { - unsigned validMarker0; - unsigned chunkUsed; // Status of the chunk: used or unused - unsigned objectId; // If 0 then this is not part of an object (unused) - unsigned chunkId; // If 0 then this is a header - unsigned byteCount; // Only valid for data chunks - // The following stuff only has meaning when we read - yaffs_ECCResult eccResult; // Only valid when we read. - unsigned blockBad; // Only valid on reading - - // YAFFS 1 stuff - unsigned chunkDeleted; // The chunk is marked deleted - unsigned serialNumber; // Yaffs1 2-bit serial number - - // YAFFS2 stuff - unsigned sequenceNumber; // The sequence number of this block - - unsigned validMarker1; - -} yaffs_ExtendedTags; + yaffs_Spare spare; + memset(&spare, 0xff, sizeof(yaffs_Spare)); -typedef struct -{ - unsigned chunkId:20; - unsigned serialNumber:2; - unsigned byteCount:10; - unsigned objectId:18; - unsigned ecc:12; - unsigned unusedStuff:2; -} yaffs_Tags; + spare.blockStatus = 'Y'; + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL, + &spare); + yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, + NULL, &spare); -#endif - -int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *eTags) -{ - yaffs_Spare spare; - yaffs_Tags tags; - - yaffs_SpareInitialise(&spare); - - if(eTags->chunkDeleted) - { - spare.pageStatus = 0; - } - else - { - tags.objectId = eTags->objectId; - tags.chunkId = eTags->chunkId; - tags.byteCount = eTags->byteCount; - tags.serialNumber = eTags->serialNumber; - -// NCB - if (!dev->useNANDECC && data) - { - yaffs_CalcECC(data,&spare); - } + return YAFFS_OK; -// /NCB - yaffs_LoadTagsIntoSpare(&spare,&tags); - - } - - return yaffs_WriteChunkToNAND(dev,chunkInNAND,data,&spare); } - -int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *eTags) +int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, + int blockNo, yaffs_BlockState * + state, + int *sequenceNumber) { - yaffs_Spare spare; - yaffs_Tags tags; - yaffs_ECCResult eccResult; - -// NCB - static yaffs_Spare spareFF; - static int init; - - if(!init) - { - memset(&spareFF,0xFF,sizeof(spareFF)); - init = 1; - } -// /NCB - if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,data,&spare,&eccResult,1)) - { -// added NCB - eTags may be NULL - if (eTags) { + yaffs_Spare spare0, spare1; + static yaffs_Spare spareFF; + static int init; + yaffs_ECCResult dummy; - int deleted = (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0; - - yaffs_GetTagsFromSpare(dev,&spare,&tags); - - eTags->chunkDeleted = deleted; - eTags->objectId = tags.objectId; - eTags->chunkId = tags.chunkId; - eTags->byteCount = tags.byteCount; - eTags->serialNumber = tags.serialNumber; - eTags->eccResult = eccResult; - eTags->blockBad = 0; // We're reading it therefore it is not a bad block - -// NCB added 18/2/2005 - eTags->chunkUsed = (memcmp(&spareFF,&spare,sizeof(spareFF)) != 0) ? 1:0; - } - - return YAFFS_OK; - } - else - { - return YAFFS_FAIL; + if (!init) { + memset(&spareFF, 0xFF, sizeof(spareFF)); + init = 1; } -} -int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockInNAND) -{ + *sequenceNumber = 0; - yaffs_Spare spare; - - memset(&spare, 0xff,sizeof(yaffs_Spare)); + yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL, + &spare0, &dummy, 1); + yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL, + &spare1, &dummy, 1); - spare.blockStatus = 0; + if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7) + *state = YAFFS_BLOCK_STATE_DEAD; + else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0) + *state = YAFFS_BLOCK_STATE_EMPTY; + else + *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL , &spare); - yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1, NULL , &spare); - return YAFFS_OK; - -} - - -int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo, yaffs_BlockState *state, int *sequenceNumber) -{ - - yaffs_Spare spare0,spare1; - static yaffs_Spare spareFF; - static int init; - yaffs_ECCResult dummy; - - if(!init) - { - memset(&spareFF,0xFF,sizeof(spareFF)); - init = 1; - } - - *sequenceNumber = 0; - - yaffs_ReadChunkFromNAND(dev,blockNo * dev->nChunksPerBlock,NULL,&spare0,&dummy,1); - yaffs_ReadChunkFromNAND(dev,blockNo * dev->nChunksPerBlock + 1,NULL,&spare1,&dummy,1); - - if(yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7) - *state = YAFFS_BLOCK_STATE_DEAD; - else if(memcmp(&spareFF,&spare0,sizeof(spareFF)) == 0) - *state = YAFFS_BLOCK_STATE_EMPTY; - else - *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; - - return YAFFS_OK; } -