X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_tagscompat.c;h=092430beccb7780311d1f148870a83a443fa0164;hp=ace4b28af49dea04c39df9c1dbc7dfbd36e32684;hb=6076b3bffffb8c1b26b41674cd9e6c5b7eeb1293;hpb=217abc9126befc676ccf0c82ffe07caf584db4c0 diff --git a/yaffs_tagscompat.c b/yaffs_tagscompat.c index ace4b28..092430b 100644 --- a/yaffs_tagscompat.c +++ b/yaffs_tagscompat.c @@ -1,537 +1,381 @@ /* - * 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-2011 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.5 2005-08-10 20:34:40 charles Exp $ */ #include "yaffs_guts.h" #include "yaffs_tagscompat.h" #include "yaffs_ecc.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_trace.h" -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 int yaffs_CountBits(__u8 x) -{ - int retVal; - retVal = yaffs_countBitsTable[x]; - return retVal; -} +static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); -/////////////// Tags ECC calculations /////////////////// +/********** Tags ECC calculations *********/ -void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare) -{ - yaffs_ECCCalculate(data , spare->ecc1); - yaffs_ECCCalculate(&data[256] , spare->ecc2); -} -void yaffs_CalcTagsECC(yaffs_Tags *tags) +void yaffs_calc_tags_ecc(struct yaffs_tags *tags) { - // Calculate an ecc - - unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes; - unsigned i,j; - unsigned ecc = 0; + /* Calculate an ecc */ + 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 + return 1; /* recovered error */ + } else if (ecc) { + /* Wierd ecc failure value */ + /* TODO Need to do somethiong here */ + return -1; /* unrecovered 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)); - return YAFFS_FAIL; - } + int data_size = dev->data_bytes_per_chunk; - dev->nPageWrites++; - return dev->writeChunkToNAND(dev,chunkInNAND,data,spare); + return dev->drv.drv_write_chunk_fn(dev, nand_chunk, + data, data_size, + (u8 *) spare, sizeof(*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; + int data_size; + int spare_size; + int ecc_result1, ecc_result2; + u8 calc_ecc[3]; + + if (!spare) { + /* 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++; - } - else if(eccResult2<0) - { - T(YAFFS_TRACE_ERROR,(TSTR("**>>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 < 0 || eccResult2 < 0) - *eccResult = YAFFS_ECC_RESULT_UNFIXED; - else if(eccResult1 > 0 || eccResult2 > 0) - *eccResult = YAFFS_ECC_RESULT_FIXED; - else - *eccResult = YAFFS_ECC_RESULT_NO_ERROR; - } + data_size = dev->data_bytes_per_chunk; + spare_size = sizeof(struct yaffs_spare); + + if (dev->param.use_nand_ecc) + return dev->drv.drv_read_chunk_fn(dev, nand_chunk, + data, data_size, + (u8 *) spare, spare_size, + ecc_result); + + + /* Handle the ECC at this level. */ + + ret_val = dev->drv.drv_read_chunk_fn(dev, nand_chunk, + data, data_size, + (u8 *)spare, spare_size, + NULL); + if (!data || !correct_errors) + return ret_val; + + /* Do ECC correction if needed. */ + yaffs_ecc_calc(data, calc_ecc); + ecc_result1 = yaffs_ecc_correct(data, spare->ecc1, calc_ecc); + yaffs_ecc_calc(&data[256], calc_ecc); + ecc_result2 = yaffs_ecc_correct(&data[256], spare->ecc2, calc_ecc); + + if (ecc_result1 > 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>yaffs ecc error fix performed on chunk %d:0", + nand_chunk); + dev->n_ecc_fixed++; + } else if (ecc_result1 < 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>yaffs ecc error unfixed on chunk %d:0", + nand_chunk); + dev->n_ecc_unfixed++; } - 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)); - } - - 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.eccres1 || nspare.eccres2) - { - // Hoosterman, we had a data problem on this page - yaffs_HandleReadDataError(dev,chunkInNAND); - } - - 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 (ecc_result2 > 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>yaffs ecc error fix performed on chunk %d:1", + nand_chunk); + dev->n_ecc_fixed++; + } else if (ecc_result2 < 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>yaffs ecc error unfixed on chunk %d:1", + nand_chunk); + dev->n_ecc_unfixed++; } - return retVal; -} - -#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; - 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 (ecc_result1 || ecc_result2) { + /* We had a data problem on this page */ + yaffs_handle_rd_data_error(dev, nand_chunk); } - if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) return YAFFS_FAIL; - if(memcmp(cmpbuf,spare,16)) return YAFFS_FAIL; - - - return YAFFS_OK; + 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 + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; + return ret_val; } -#endif - +/* + * Functions for robustisizing + */ -/// -// Functions for robustisizing -// -// +static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk) +{ + 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; + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, + "**>>Block %d marked for retirement", + flash_block); + + /* TODO: + * Just do a garbage collection on the affected block + * then retire the block + * NB recursion + */ +} -static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND) +static int yaffs_tags_compat_wr(struct yaffs_dev *dev, + int nand_chunk, + const u8 *data, const struct yaffs_ext_tags *ext_tags) { - int blockInNAND = chunkInNAND/dev->nChunksPerBlock; + struct yaffs_spare spare; + struct yaffs_tags tags; - // 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_init(&spare); + if (ext_tags->is_deleted) + spare.page_status = 0; + else { + tags.obj_id = ext_tags->obj_id; + tags.chunk_id = ext_tags->chunk_id; - //TODO - // Just do a garbage collection on the affected block then retire the block - // NB recursion -} + tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1); + if (dev->data_bytes_per_chunk >= 1024) + tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3; + else + tags.n_bytes_msb = 3; -#ifdef NOTYET -static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND) -{ -} + tags.serial_number = ext_tags->serial_number; -static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare) -{ -} + if (!dev->param.use_nand_ecc && data) { + yaffs_ecc_calc(data, spare.ecc1); + yaffs_ecc_calc(&data[256], spare.ecc2); + } -static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare) -{ + yaffs_load_tags_to_spare(&spare, &tags); + } + return yaffs_wr_nand(dev, nand_chunk, data, &spare); } -static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND) +static int yaffs_tags_compat_rd(struct yaffs_dev *dev, + int nand_chunk, + u8 *data, struct yaffs_ext_tags *ext_tags) { - int blockInNAND = chunkInNAND/dev->nChunksPerBlock; + struct yaffs_spare spare; + struct yaffs_tags tags; + enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN; + static struct yaffs_spare spare_ff; + static int init; + int deleted; + + if (!init) { + memset(&spare_ff, 0xff, sizeof(spare_ff)); + init = 1; + } - // Mark the block for retirement - yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1; - // Delete the chunk - yaffs_DeleteChunk(dev,chunkInNAND,1,__LINE__); -} + if (!yaffs_rd_chunk_nand(dev, nand_chunk, + data, &spare, &ecc_result, 1)) + return YAFFS_FAIL; + /* ext_tags may be NULL */ + if (!ext_tags) + return YAFFS_OK; + deleted = (hweight8(spare.page_status) < 7) ? 1 : 0; + 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)) ? 1 : 0; -static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1) -{ + if (ext_tags->chunk_used) { + yaffs_get_tags_from_spare(dev, &spare, &tags); + 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); - 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; - } + ext_tags->serial_number = tags.serial_number; + } - return 1; + return YAFFS_OK; } -#endif /* NOTYET */ - - -int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *eTags) +static int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block) { - 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); - } + struct yaffs_spare spare; -// /NCB - yaffs_LoadTagsIntoSpare(&spare,&tags); - - } - - return yaffs_WriteChunkToNAND(dev,chunkInNAND,data,&spare); -} + memset(&spare, 0xff, sizeof(struct yaffs_spare)); + spare.block_status = 'Y'; -int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,int chunkInNAND, __u8 *data, yaffs_ExtendedTags *eTags) -{ + 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); - 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) { - - 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; - } + return YAFFS_OK; } -int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockInNAND) +static int yaffs_tags_compat_query_block(struct yaffs_dev *dev, + int block_no, + enum yaffs_block_state *state, + u32 *seq_number) { + struct yaffs_spare spare0, spare1; + static struct yaffs_spare spare_ff; + static int init; + enum yaffs_ecc_result dummy; - yaffs_Spare spare; + if (!init) { + memset(&spare_ff, 0xff, sizeof(spare_ff)); + init = 1; + } - memset(&spare, 0xff,sizeof(yaffs_Spare)); + *seq_number = 0; - spare.blockStatus = 'Y'; + /* Look for bad block markers in the first two chunks */ + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, + NULL, &spare0, &dummy, 0); + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, + NULL, &spare1, &dummy, 0); + + if (hweight8(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 + *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; - 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) +void yaffs_tags_compat_install(struct yaffs_dev *dev) { - - 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; + if(dev->param.is_yaffs2) + return; + if(!dev->tagger.write_chunk_tags_fn) + dev->tagger.write_chunk_tags_fn = yaffs_tags_compat_wr; + if(!dev->tagger.read_chunk_tags_fn) + dev->tagger.read_chunk_tags_fn = yaffs_tags_compat_rd; + if(!dev->tagger.query_block_fn) + dev->tagger.query_block_fn = yaffs_tags_compat_query_block; + if(!dev->tagger.mark_bad_fn) + dev->tagger.mark_bad_fn = yaffs_tags_compat_mark_bad; } -