X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_tagscompat.c;h=3a9a157e7e2470c44252cb338363347db7b04569;hp=d7c0fd1144540320fef6ce62418fa885267c9d89;hb=a6b656e2ec808ffab1b5f46babcdc5f7b49b7a46;hpb=363520161b021b7ac870c269064606e3f16feeeb diff --git a/yaffs_tagscompat.c b/yaffs_tagscompat.c index d7c0fd1..3a9a157 100644 --- a/yaffs_tagscompat.c +++ b/yaffs_tagscompat.c @@ -1,672 +1,454 @@ /* - * 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-2010 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.1 2004-11-03 08:14:07 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 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 +#include "yaffs_getblockinfo.h" +#include "yaffs_trace.h" + +static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); + +static const char yaffs_count_bits_table[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) +int yaffs_count_bits(u8 x) { - int retVal; - retVal = yaffs_countBitsTable[x]; - return retVal; + int ret_val; + ret_val = yaffs_count_bits_table[x]; + return ret_val; } +/********** Tags ECC calculations *********/ -/////////////// Tags ECC calculations /////////////////// - -void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) +void yaffs_calc_ecc(const u8 * data, struct yaffs_spare *spare) { - yaffs_ECCCalculate(data , spare->ecc1); - yaffs_ECCCalculate(&data[256] , spare->ecc2); + yaffs_ecc_cacl(data, spare->ecc1); + yaffs_ecc_cacl(&data[256], spare->ecc2); } -void yaffs_CalcTagsECC(yaffs_Tags *tags) +void yaffs_calc_tags_ecc(struct 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 = ((union yaffs_tags_union *)tags)->as_bytes; + 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; - } } } tags->ecc = ecc; - } -int yaffs_CheckECCOnTags(yaffs_Tags *tags) +int yaffs_check_tags_ecc(struct yaffs_tags *tags) { unsigned ecc = tags->ecc; - yaffs_CalcTagsECC(tags); + yaffs_calc_tags_ecc(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 = ((union yaffs_tags_union *)tags)->as_bytes; ecc--; b[ecc / 8] ^= (1 << (ecc & 7)); - // Now recvalc the ecc - yaffs_CalcTagsECC(tags); + /* Now recvalc the ecc */ + yaffs_calc_tags_ecc(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_load_tags_to_spare(struct yaffs_spare *spare_ptr, + struct yaffs_tags *tags_ptr) { - yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr; - - yaffs_CalcTagsECC(tagsPtr); - - sparePtr->tagByte0 = tu->asBytes[0]; - sparePtr->tagByte1 = tu->asBytes[1]; - sparePtr->tagByte2 = tu->asBytes[2]; - sparePtr->tagByte3 = tu->asBytes[3]; - sparePtr->tagByte4 = tu->asBytes[4]; - sparePtr->tagByte5 = tu->asBytes[5]; - sparePtr->tagByte6 = tu->asBytes[6]; - sparePtr->tagByte7 = tu->asBytes[7]; + union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; + + yaffs_calc_tags_ecc(tags_ptr); + + spare_ptr->tb0 = tu->as_bytes[0]; + spare_ptr->tb1 = tu->as_bytes[1]; + spare_ptr->tb2 = tu->as_bytes[2]; + spare_ptr->tb3 = tu->as_bytes[3]; + spare_ptr->tb4 = tu->as_bytes[4]; + spare_ptr->tb5 = tu->as_bytes[5]; + spare_ptr->tb6 = tu->as_bytes[6]; + spare_ptr->tb7 = tu->as_bytes[7]; } -static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr) +static void yaffs_get_tags_from_spare(struct yaffs_dev *dev, + struct yaffs_spare *spare_ptr, + struct yaffs_tags *tags_ptr) { - yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr; + union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; 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) - { - dev->tagsEccFixed++; - } - else if(result <0) - { - dev->tagsEccUnfixed++; - } + tu->as_bytes[0] = spare_ptr->tb0; + tu->as_bytes[1] = spare_ptr->tb1; + tu->as_bytes[2] = spare_ptr->tb2; + tu->as_bytes[3] = spare_ptr->tb3; + tu->as_bytes[4] = spare_ptr->tb4; + tu->as_bytes[5] = spare_ptr->tb5; + tu->as_bytes[6] = spare_ptr->tb6; + tu->as_bytes[7] = spare_ptr->tb7; + + result = yaffs_check_tags_ecc(tags_ptr); + if (result > 0) + dev->n_tags_ecc_fixed++; + else if (result < 0) + dev->n_tags_ecc_unfixed++; } -static void yaffs_SpareInitialise(yaffs_Spare *spare) +static void yaffs_spare_init(struct yaffs_spare *spare) { - memset(spare,0xFF,sizeof(yaffs_Spare)); + memset(spare, 0xFF, sizeof(struct yaffs_spare)); } - - - -static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare) +static int yaffs_wr_nand(struct yaffs_dev *dev, + int nand_chunk, const u8 * data, + struct yaffs_spare *spare) { - if(chunkInNAND < dev->startBlock * dev->nChunksPerBlock) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),chunkInNAND)); + if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) { + T(YAFFS_TRACE_ERROR, + (TSTR("**>> yaffs chunk %d is not valid" TENDSTR), + nand_chunk)); return YAFFS_FAIL; } - dev->nPageWrites++; - return dev->writeChunkToNAND(dev,chunkInNAND,data,spare); + return dev->param.write_chunk_fn(dev, nand_chunk, data, spare); } - - -static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev, - int chunkInNAND, - __u8 *data, - yaffs_Spare *spare, - yaffs_ECCResult *eccResult, - int doErrorCorrection) +static int yaffs_rd_chunk_nand(struct yaffs_dev *dev, + int nand_chunk, + u8 * data, + struct yaffs_spare *spare, + enum yaffs_ecc_result *ecc_result, + int correct_errors) { - 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 - spare = &localSpare; + int ret_val; + struct yaffs_spare local_spare; + + 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 = &local_spare; } - - - 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)); - dev->eccFixed++; - } - else if(eccResult1<0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>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)); - dev->eccFixed++; + if (!dev->param.use_nand_ecc) { + ret_val = + dev->param.read_chunk_fn(dev, nand_chunk, data, spare); + if (data && correct_errors) { + /* Do ECC correction */ + /* Todo handle any errors */ + int ecc_result1, ecc_result2; + u8 calc_ecc[3]; + + yaffs_ecc_cacl(data, calc_ecc); + ecc_result1 = + yaffs_ecc_correct(data, spare->ecc1, calc_ecc); + yaffs_ecc_cacl(&data[256], calc_ecc); + ecc_result2 = + yaffs_ecc_correct(&data[256], spare->ecc2, + calc_ecc); + + if (ecc_result1 > 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>yaffs ecc error fix performed on chunk %d:0" + TENDSTR), nand_chunk)); + dev->n_ecc_fixed++; + } else if (ecc_result1 < 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>yaffs ecc error unfixed on chunk %d:0" + TENDSTR), nand_chunk)); + dev->n_ecc_unfixed++; } - else if(eccResult2<0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND)); - dev->eccUnfixed++; + + if (ecc_result2 > 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>yaffs ecc error fix performed on chunk %d:1" + TENDSTR), nand_chunk)); + dev->n_ecc_fixed++; + } else if (ecc_result2 < 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>yaffs ecc error unfixed on chunk %d:1" + TENDSTR), nand_chunk)); + dev->n_ecc_unfixed++; } - if(eccResult1 || eccResult2) - { - // Hoosterman, we had a data problem on this page - yaffs_HandleReadDataError(dev,chunkInNAND); + if (ecc_result1 || ecc_result2) { + /* We had a data problem on this page */ + yaffs_handle_rd_data_error(dev, nand_chunk); } - - if(eccResult1 < 0 || eccResult2 < 0) - *eccResult = YAFFS_ECC_RESULT_UNFIXED; - else if(eccResult1 > 0 || eccResult2 > 0) - *eccResult = YAFFS_ECC_RESULT_FIXED; + + if (ecc_result1 < 0 || ecc_result2 < 0) + *ecc_result = YAFFS_ECC_RESULT_UNFIXED; + else if (ecc_result1 > 0 || ecc_result2 > 0) + *ecc_result = YAFFS_ECC_RESULT_FIXED; else - *eccResult = YAFFS_ECC_RESULT_NO_ERROR; + *ecc_result = 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_nand_spare nspare; + + memset(&nspare, 0, sizeof(nspare)); + + ret_val = dev->param.read_chunk_fn(dev, nand_chunk, data, + (struct yaffs_spare *) + &nspare); + memcpy(spare, &nspare, sizeof(struct yaffs_spare)); + if (data && correct_errors) { + if (nspare.eccres1 > 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>mtd ecc error fix performed on chunk %d:0" + TENDSTR), nand_chunk)); + } else if (nspare.eccres1 < 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>mtd ecc error unfixed on chunk %d:0" + TENDSTR), nand_chunk)); } - 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), nand_chunk)); + } else if (nspare.eccres2 < 0) { + T(YAFFS_TRACE_ERROR, + (TSTR + ("**>>mtd ecc error unfixed on chunk %d:1" + TENDSTR), nand_chunk)); } - 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_handle_rd_data_error(dev, nand_chunk); } - - if(nspare.eccres1 < 0 || nspare.eccres2 < 0) - *eccResult = YAFFS_ECC_RESULT_UNFIXED; - else if(nspare.eccres1 > 0 || nspare.eccres2 > 0) - *eccResult = YAFFS_ECC_RESULT_FIXED; - else - *eccResult = YAFFS_ECC_RESULT_NO_ERROR; + if (nspare.eccres1 < 0 || nspare.eccres2 < 0) + *ecc_result = YAFFS_ECC_RESULT_UNFIXED; + else if (nspare.eccres1 > 0 || nspare.eccres2 > 0) + *ecc_result = YAFFS_ECC_RESULT_FIXED; + else + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; } } - return retVal; + return ret_val; } +/* + * Functions for robustisizing + */ - -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; - static __u8 spare[sizeof(struct yaffs_NANDSpare)]; - - dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare); - - 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; - - - return YAFFS_OK; - -} - - -#if 0 -int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND) -{ - dev->nBlockErasures++; - return dev->eraseBlockInNAND(dev,blockInNAND); -} - -int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev) +static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk) { - return dev->initialiseNAND(dev); + int flash_block = nand_chunk / dev->param.chunks_per_block; + + /* Mark the block for retirement */ + yaffs_get_block_info(dev, + flash_block + dev->block_offset)->needs_retiring = + 1; + T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, + (TSTR("**>>Block %d marked for retirement" TENDSTR), flash_block)); + + /* TODO: + * Just do a garbage collection on the affected block + * then retire the block + * NB recursion + */ } -#endif - -#if 0 -static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_Spare *spare,int useReserve) +int yaffs_tags_compat_wr(struct yaffs_dev *dev, + int nand_chunk, + const u8 * data, const struct yaffs_ext_tags *ext_tags) { - int chunk; + struct yaffs_spare spare; + struct yaffs_tags tags; - int writeOk = 1; - int attempts = 0; + yaffs_spare_init(&spare); - unsigned char rbData[YAFFS_BYTES_PER_CHUNK]; - yaffs_Spare rbSpare; + if (ext_tags->is_deleted) + spare.page_status = 0; + else { + tags.obj_id = ext_tags->obj_id; + tags.chunk_id = ext_tags->chunk_id; - do{ - chunk = yaffs_AllocateChunk(dev,useReserve); + tags.n_bytes_lsb = ext_tags->n_bytes & 0x3ff; - if(chunk >= 0) - { + if (dev->data_bytes_per_chunk >= 1024) + tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3; + else + tags.n_bytes_msb = 3; - // 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 + tags.serial_number = ext_tags->serial_number; - } - 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); - } - } + if (!dev->param.use_nand_ecc && data) + yaffs_calc_ecc(data, &spare); - } while(chunk >= 0 && ! writeOk); + yaffs_load_tags_to_spare(&spare, &tags); - if(attempts > 1) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts)); - dev->nRetriedWrites+= (attempts - 1); } - return chunk; + return yaffs_wr_nand(dev, nand_chunk, data, &spare); } -#endif - -/// -// Functions for robustisizing -// -// -#if 0 - -static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND) +int yaffs_tags_compat_rd(struct yaffs_dev *dev, + int nand_chunk, + u8 * data, struct yaffs_ext_tags *ext_tags) { - // Ding the blockStatus in the first two pages of the block. - - yaffs_Spare spare; - - memset(&spare, 0xff,sizeof(yaffs_Spare)); - spare.blockStatus = 0; + struct yaffs_spare spare; + struct yaffs_tags tags; + enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN; - // 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 struct yaffs_spare spare_ff; + static int init; - yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD; - dev->nRetiredBlocks++; -} - -#endif - -#if 0 -static int yaffs_RewriteBufferedBlock(yaffs_Device *dev) -{ - dev->doingBufferedBlockRewrite = 1; - // - // Remove erased chunks - // Rewrite existing chunks to a new block - // Set current write block to the new block - - dev->doingBufferedBlockRewrite = 0; - - return 1; -} + if (!init) { + memset(&spare_ff, 0xFF, sizeof(spare_ff)); + init = 1; + } -#endif + if (yaffs_rd_chunk_nand(dev, nand_chunk, data, &spare, &ecc_result, 1)) { + /* ext_tags may be NULL */ + if (ext_tags) { -static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND) -{ - int blockInNAND = chunkInNAND/dev->nChunksPerBlock; + int deleted = + (yaffs_count_bits(spare.page_status) < 7) ? 1 : 0; - // 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)); + ext_tags->is_deleted = deleted; + ext_tags->ecc_result = ecc_result; + ext_tags->block_bad = 0; /* We're reading it */ + /* therefore it is not a bad block */ + ext_tags->chunk_used = + (memcmp(&spare_ff, &spare, sizeof(spare_ff)) != + 0) ? 1 : 0; + if (ext_tags->chunk_used) { + yaffs_get_tags_from_spare(dev, &spare, &tags); - //TODO - // Just do a garbage collection on the affected block then retire the block - // NB recursion -} + ext_tags->obj_id = tags.obj_id; + ext_tags->chunk_id = tags.chunk_id; + ext_tags->n_bytes = tags.n_bytes_lsb; + if (dev->data_bytes_per_chunk >= 1024) + ext_tags->n_bytes |= + (((unsigned)tags. + n_bytes_msb) << 10); -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) -{ -} + ext_tags->serial_number = tags.serial_number; + } + } -static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare) -{ + return YAFFS_OK; + } else { + return YAFFS_FAIL; + } } -static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND) +int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block) { - int blockInNAND = chunkInNAND/dev->nChunksPerBlock; - // Mark the block for retirement - yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1; - // Delete the chunk - yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__); -} + struct yaffs_spare spare; + memset(&spare, 0xff, sizeof(struct yaffs_spare)); + spare.block_status = 'Y'; + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL, + &spare); + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1, + NULL, &spare); -static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1) -{ - - - 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 YAFFS_OK; - return 1; } -#if 0 -typedef struct +int yaffs_tags_compat_query_block(struct yaffs_dev *dev, + int block_no, + enum yaffs_block_state *state, + u32 * seq_number) { - 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; - - -typedef struct -{ - unsigned chunkId:20; - unsigned serialNumber:2; - unsigned byteCount:10; - unsigned objectId:18; - unsigned ecc:12; - unsigned unusedStuff:2; -} yaffs_Tags; - + struct yaffs_spare spare0, spare1; + static struct yaffs_spare spare_ff; + static int init; + enum yaffs_ecc_result dummy; -#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; - - yaffs_LoadTagsIntoSpare(&spare,&tags); - + if (!init) { + memset(&spare_ff, 0xFF, sizeof(spare_ff)); + init = 1; } - - return yaffs_WriteChunkToNAND(dev,chunkInNAND,data,&spare); -} + *seq_number = 0; -int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *eTags) -{ + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL, + &spare0, &dummy, 1); + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, + NULL, &spare1, &dummy, 1); - yaffs_Spare spare; - yaffs_Tags tags; - yaffs_ECCResult eccResult; - - if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,data,&spare,&eccResult,1)) - { - 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 - - return YAFFS_OK; - } + if (yaffs_count_bits(spare0.block_status & spare1.block_status) < 7) + *state = YAFFS_BLOCK_STATE_DEAD; + else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0) + *state = YAFFS_BLOCK_STATE_EMPTY; else - { - return YAFFS_FAIL; - } -} - -int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockInNAND) -{ - - yaffs_Spare spare; + *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING; - memset(&spare, 0xff,sizeof(yaffs_Spare)); - - spare.blockStatus = 0; - - 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; -} -