// countBits is a quick way of counting the number of bits in a byte.\r
// ie. countBits[n] holds the number of 1 bits in a byte with the value n.\r
\r
-static const char yaffs_countBits[256] =\r
+static const char yaffs_countBitsTable[256] =\r
{\r
0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,\r
1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,\r
4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8\r
};\r
\r
+static int yaffs_CountBits(__u8 x)\r
+{\r
+ int retVal;\r
+ retVal = yaffs_countBitsTable[x];\r
+ return retVal;\r
+}\r
+\r
\r
\r
// Device info\r
static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);\r
static int yaffs_CheckStructures(void);\r
\r
+// Robustification\r
+static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND);\r
+static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND);\r
+static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND);\r
+static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare);\r
+static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare);\r
+\r
+static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND);\r
+\r
+\r
+\r
+static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1);\r
+\r
+\r
+\r
loff_t yaffs_GetFileSize(yaffs_Object *obj);\r
\r
static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags, int *chunkDeleted);\r
return dev->writeChunkToNAND(dev,chunkInNAND,data,spare);\r
}\r
\r
-int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)\r
+\r
+int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare,int doErrorCorrection)\r
{\r
int retVal;\r
__u8 calcEcc[3];\r
}\r
\r
retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);\r
- if(data)\r
+ if(data && doErrorCorrection)\r
{\r
// Do ECC correction\r
//Todo handle any errors\r
{\r
T((TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));\r
}\r
+ \r
+ if(eccResult1 || eccResult2)\r
+ {\r
+ // Hoosterman, we had a data problem on this page\r
+ yaffs_HandleReadDataError(dev,chunkInNAND);\r
+ }\r
}\r
return retVal;\r
}\r
\r
-#ifdef YAFFS_PARANOID\r
\r
static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND)\r
{\r
+#if 1\r
+\r
static int init = 0;\r
static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];\r
static __u8 data[YAFFS_BYTES_PER_CHUNK];\r
static __u8 spare[16];\r
\r
- int retVal;\r
- \r
- retVal = YAFFS_OK;\r
\r
dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare);\r
\r
init = 1;\r
}\r
\r
- if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) retVal = YAFFS_FAIL;\r
- if(memcmp(cmpbuf,spare,16)) retVal = YAFFS_FAIL;\r
+ if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) return YAFFS_FAIL;\r
+ if(memcmp(cmpbuf,spare,16)) return YAFFS_FAIL;\r
+\r
+#endif\r
\r
- return retVal;\r
+ return YAFFS_OK;\r
\r
}\r
\r
-#endif\r
\r
\r
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)\r
{\r
int chunk;\r
\r
- int writeOk = 0;\r
+ int writeOk = 1;\r
int attempts = 0;\r
\r
unsigned char rbData[YAFFS_BYTES_PER_CHUNK];\r
\r
if(chunk >= 0)\r
{\r
- writeOk = yaffs_WriteChunkToNAND(dev,chunk,data,spare);\r
+\r
+ // First check this chunk is erased...\r
+ writeOk = yaffs_CheckChunkErased(dev,chunk);\r
+ \r
+ if(writeOk)\r
+ {\r
+ writeOk = yaffs_WriteChunkToNAND(dev,chunk,data,spare);\r
+ }\r
attempts++;\r
if(writeOk)\r
{\r
// If verify fails, then delete this chunk and try again\r
// To verify we compare everything except the block and \r
// page status bytes.\r
- yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare);\r
+ // NB We check a raw read without ECC correction applied\r
+ yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare,0);\r
\r
- if(memcmp(data,rbData,YAFFS_BYTES_PER_CHUNK) != 0 ||\r
- spare->tagByte0 != rbSpare.tagByte0 ||\r
- spare->tagByte1 != rbSpare.tagByte1 ||\r
- spare->tagByte2 != rbSpare.tagByte2 ||\r
- spare->tagByte3 != rbSpare.tagByte3 ||\r
- spare->tagByte4 != rbSpare.tagByte4 ||\r
- spare->tagByte5 != rbSpare.tagByte5 ||\r
- spare->tagByte6 != rbSpare.tagByte6 ||\r
- spare->tagByte7 != rbSpare.tagByte7 ||\r
- spare->ecc1[0] != rbSpare.ecc1[0] ||\r
- spare->ecc1[1] != rbSpare.ecc1[1] ||\r
- spare->ecc1[2] != rbSpare.ecc1[2] ||\r
- spare->ecc2[0] != rbSpare.ecc2[0] ||\r
- spare->ecc2[1] != rbSpare.ecc2[1] ||\r
- spare->ecc2[2] != rbSpare.ecc2[2] )\r
- {\r
+ if(!yaffs_VerifyCompare(data,rbData,spare,&rbSpare))\r
+ {\r
// Didn't verify\r
- yaffs_DeleteChunk(dev,chunk);\r
T((TSTR("**>> yaffs write failed on chunk %d" TENDSTR), chunk));\r
+ // yaffs_DeleteChunk(dev,chunk);\r
\r
writeOk = 0;\r
} \r
\r
}\r
+ if(writeOk)\r
+ {\r
+ // Copy the data into the write buffer.\r
+ // NB We do this at the end to prevent duplicates in the case of a write error.\r
+ //Todo\r
+ yaffs_HandleWriteChunkOk(dev,chunk,data,spare);\r
+ }\r
+ else\r
+ {\r
+ yaffs_HandleWriteChunkError(dev,chunk);\r
+ }\r
}\r
+ \r
} while(chunk >= 0 && ! writeOk);\r
\r
if(attempts > 1)\r
return chunk;\r
}\r
\r
+///\r
+// Functions for robustisizing\r
+//\r
+//\r
+\r
+static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)\r
+{\r
+ // Ding the blockStatus in the first two pages of the block.\r
+ \r
+ yaffs_Spare spare;\r
+\r
+ memset(&spare, 0xff,sizeof(yaffs_Spare));\r
+\r
+ spare.blockStatus = 0;\r
+ \r
+ yaffs_WriteChunkToNAND(dev, blockInNAND * YAFFS_CHUNKS_PER_BLOCK, NULL , &spare);\r
+ yaffs_WriteChunkToNAND(dev, blockInNAND * YAFFS_CHUNKS_PER_BLOCK + 1, NULL , &spare);\r
+ \r
+ dev->blockInfo[blockInNAND].blockState = YAFFS_BLOCK_STATE_DEAD;\r
+ dev->nRetiredBlocks++;\r
+}\r
+\r
\r
\r
+static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)\r
+{\r
+ dev->doingBufferedBlockRewrite = 1;\r
+ //\r
+ // Remove erased chunks\r
+ // Rewrite existing chunks to a new block\r
+ // Set current write block to the new block\r
+ \r
+ dev->doingBufferedBlockRewrite = 0;\r
+}\r
+\r
+\r
+static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)\r
+{\r
+ \r
+ // Just do a garbage collection on the affected block then retire the block\r
+ // NB recursion\r
+}\r
+\r
+\r
+static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND)\r
+{\r
+}\r
+\r
+static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare)\r
+{\r
+}\r
+\r
+static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare)\r
+{\r
+}\r
+\r
+static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)\r
+{\r
+}\r
+\r
+\r
+\r
+\r
+static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1)\r
+{\r
+\r
+ if( memcmp(d0,d1,YAFFS_BYTES_PER_CHUNK) != 0 ||\r
+ s0->tagByte0 != s1->tagByte0 ||\r
+ s0->tagByte1 != s1->tagByte1 ||\r
+ s0->tagByte2 != s1->tagByte2 ||\r
+ s0->tagByte3 != s1->tagByte3 ||\r
+ s0->tagByte4 != s1->tagByte4 ||\r
+ s0->tagByte5 != s1->tagByte5 ||\r
+ s0->tagByte6 != s1->tagByte6 ||\r
+ s0->tagByte7 != s1->tagByte7 ||\r
+ s0->ecc1[0] != s1->ecc1[0] ||\r
+ s0->ecc1[1] != s1->ecc1[1] ||\r
+ s0->ecc1[2] != s1->ecc1[2] ||\r
+ s0->ecc2[0] != s1->ecc2[0] ||\r
+ s0->ecc2[1] != s1->ecc2[1] ||\r
+ s0->ecc2[2] != s1->ecc2[2] )\r
+ {\r
+ return 0;\r
+ }\r
+ \r
+ return 1;\r
+}\r
+\r
\r
///////////////////////// Object management //////////////////\r
// List of spare objects\r
break;\r
}\r
\r
- yaffs_UpdateObjectHeader(in,name);\r
+ if(yaffs_UpdateObjectHeader(in,name) < 0)\r
+ {\r
+ // Could not create the object header, fail the creation\r
+ yaffs_UnlinkWorker(in);\r
+ in = NULL;\r
+ }\r
\r
}\r
\r
\r
static void yaffs_InitialiseBlocks(yaffs_Device *dev)\r
{\r
+ //Todo we're assuming the malloc will pass.\r
dev->blockInfo = YMALLOC(dev->nBlocks * sizeof(yaffs_BlockInfo));\r
memset(dev->blockInfo,0,dev->nBlocks * sizeof(yaffs_BlockInfo));\r
dev->allocationBlock = -1; // force it to get a new one\r
{\r
yaffs_BlockInfo *bi = &dev->blockInfo[blockNo];\r
\r
- // Mark as dirty, erase it and mark as clean.\r
+ // Mark as dirty.\r
+ // If the block is still healthy erase it and mark as clean.\r
+ // If the block has had a data failure, then retire it.\r
bi->blockState = YAFFS_BLOCK_STATE_DIRTY;\r
- yaffs_EraseBlockInNAND(dev,blockNo);\r
- bi->blockState = YAFFS_BLOCK_STATE_EMPTY;\r
- dev->nErasedBlocks++;\r
- bi->pagesInUse = 0;\r
- bi->pageBits = 0;\r
\r
- T((TSTR("Erased block %d" TENDSTR),blockNo));\r
+ if(!bi->needsRetiring && yaffs_EraseBlockInNAND(dev,blockNo))\r
+ {\r
+ bi->blockState = YAFFS_BLOCK_STATE_EMPTY;\r
+ dev->nErasedBlocks++;\r
+ bi->pagesInUse = 0;\r
+ bi->pageBits = 0;\r
+ \r
+ T((TSTR("Erased block %d" TENDSTR),blockNo));\r
+ }\r
+ else\r
+ {\r
+ yaffs_RetireBlock(dev,blockNo);\r
+ T((TSTR("**>> Block %d retired" TENDSTR),blockNo));\r
+ }\r
}\r
\r
\r
\r
//T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));\r
\r
- yaffs_ReadChunkFromNAND(dev,oldChunk,buffer, &spare);\r
+ yaffs_ReadChunkFromNAND(dev,oldChunk,buffer, &spare,1);\r
\r
yaffs_GetTagsFromSpare(&spare,&tags);\r
tags.serialNumber++;\r
if(dev->garbageCollectionRequired)\r
{\r
dev->garbageCollectionRequired = 0;\r
- block = yaffs_FindDirtiestBlock(dev);\r
+ if(dev->blockSelectedForGC >= 0)\r
+ {\r
+ block = dev->blockSelectedForGC;\r
+ }\r
+ else\r
+ {\r
+ block = yaffs_FindDirtiestBlock(dev);\r
+ }\r
+ \r
if(block >= 0)\r
{\r
return yaffs_GarbageCollectBlock(dev,block);\r
if(tags)\r
{\r
yaffs_Spare spare;\r
- if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,NULL,&spare) == YAFFS_OK)\r
+ if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,NULL,&spare,1) == YAFFS_OK)\r
{\r
- *chunkDeleted = (yaffs_countBits[spare.pageStatus] < 7) ? 1 : 0;\r
+ *chunkDeleted = (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;\r
yaffs_GetTagsFromSpare(&spare,tags);\r
return YAFFS_OK;\r
}\r
\r
if(chunkInNAND >= 0)\r
{\r
- return yaffs_ReadChunkFromNAND(in->myDev,chunkInNAND,buffer,NULL);\r
+ return yaffs_ReadChunkFromNAND(in->myDev,chunkInNAND,buffer,NULL,1);\r
}\r
else\r
{\r
\r
static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId)\r
{\r
- int block = chunkId / YAFFS_CHUNKS_PER_BLOCK;\r
- int page = chunkId % YAFFS_CHUNKS_PER_BLOCK;\r
+ int block;\r
+ int page;\r
yaffs_Spare spare;\r
+ \r
+ if(chunkId <= 0) return; \r
\r
+ block = chunkId / YAFFS_CHUNKS_PER_BLOCK;\r
+ page = chunkId % YAFFS_CHUNKS_PER_BLOCK;\r
yaffs_SpareInitialise(&spare);\r
\r
spare.pageStatus = 0; // To mark it as deleted.\r
\r
\r
yaffs_WriteChunkToNAND(dev,chunkId,NULL,&spare);\r
+ yaffs_HandleUpdateChunk(dev,chunkId,&spare);\r
\r
\r
// Pull out of the management area.\r
\r
if(prevChunkId >= 0)\r
{\r
- yaffs_ReadChunkFromNAND(dev,prevChunkId,bufferOld,NULL); \r
+ yaffs_ReadChunkFromNAND(dev,prevChunkId,bufferOld,NULL,1); \r
}\r
\r
// Header data\r
{\r
yaffs_Spare spare;\r
\r
- yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK,NULL,&spare);\r
+ yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK,NULL,&spare,1);\r
+#if 1\r
+ if(yaffs_CountBits(spare.blockStatus) < 7)\r
+ {\r
+ return 1;\r
+ }\r
+#else\r
if(spare.blockStatus != 0xFF)\r
{\r
return 1;\r
}\r
- yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK + 1,NULL,&spare);\r
+#endif\r
+ yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK + 1,NULL,&spare,1);\r
+\r
+#if 1\r
+ if(yaffs_CountBits(spare.blockStatus) < 7)\r
+ {\r
+ return 1;\r
+ }\r
+#else\r
if(spare.blockStatus != 0xFF)\r
{\r
return 1;\r
}\r
+#endif\r
\r
return 0;\r
\r
// Read the spare area and decide what to do\r
chunk = blk * YAFFS_CHUNKS_PER_BLOCK + c;\r
\r
- yaffs_ReadChunkFromNAND(dev,chunk,NULL,&spare);\r
+ yaffs_ReadChunkFromNAND(dev,chunk,NULL,&spare,1);\r
\r
\r
// This block looks ok, now what's in this chunk?\r
yaffs_GetTagsFromSpare(&spare,&tags);\r
\r
- if(yaffs_countBits[spare.pageStatus] < 6)\r
+ if(yaffs_CountBits(spare.pageStatus) < 6)\r
{\r
// A deleted chunk\r
deleted++;\r
dev->blockInfo[blk].pageBits |= (1 << c);\r
dev->blockInfo[blk].pagesInUse++;\r
\r
- yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL);\r
+ yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL,1);\r
\r
oh = (yaffs_ObjectHeader *)chunkData;\r
\r
\r
if(obj->chunkId >= 0)\r
{\r
- yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);\r
+ yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL,1);\r
}\r
strncpy(name,oh->name,buffSize - 1);\r
}\r
int bits;\r
\r
\r
- dev = dev;\r
\r
if(!yaffs_CheckStructures())\r
{\r
else\r
{\r
dev->chunkGroupBits = bits - 16;\r
- dev->chunkGroupSize = nChunks/0x10000;\r
+ dev->chunkGroupSize = nChunks>> 16;\r
}\r
\r
// More device initialisation\r
dev->garbageCollectionRequired = 0;\r
dev->currentDirtyChecker = 0;\r
+ dev->bufferedBlock = -1;\r
+ dev->doingBufferedBlockRewrite = 0;\r
+ dev->blockSelectedForGC = -1;\r
\r
yaffs_InitialiseBlocks(dev);\r
\r
dev->nBlockErasures = 0;\r
dev->nGCCopies = 0;\r
dev->nRetriedWrites = 0;\r
+ dev->nRetiredBlocks = 0;\r
\r
\r
return YAFFS_OK;\r