#define T(x)
#endif
+// External functions for ECC on data
+void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
+int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+
// countBits is a quick way of counting the number of bits in a byte.
// ie. countBits[n] holds the number of 1 bits in a byte with the value n.
static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr);
static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);
-static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND);
+static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);
static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
{
- return dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
+ int retVal;
+ __u8 calcEcc[3];
+ yaffs_Spare localSpare;
+
+ 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;
+ }
+
+ retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
+ if(data)
+ {
+ // Do ECC correction
+ //Todo handle any errors
+ nand_calculate_ecc(data,calcEcc);
+ nand_correct_data (data,spare->ecc1, calcEcc);
+ nand_calculate_ecc(&data[256],calcEcc);
+ nand_correct_data (&data[256],spare->ecc2, calcEcc);
+ }
+ return retVal;
}
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
int writeOk = 0;
+ unsigned char rbData[YAFFS_BYTES_PER_CHUNK];
+ yaffs_Spare rbSpare;
+
do{
chunk = yaffs_AllocateChunk(dev,useReserve);
writeOk = yaffs_WriteChunkToNAND(dev,chunk,data,spare);
if(writeOk)
{
- //Todo read-back and verify
+ // Readback & verify
// If verify fails, then delete this chunk and try again
+ // To verify we compare everything except the block and
+ // page status bytes.
+ yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare);
+
+ if(memcmp(data,rbData,YAFFS_BYTES_PER_CHUNK) != 0 ||
+ spare->tagByte0 != rbSpare.tagByte0 ||
+ spare->tagByte1 != rbSpare.tagByte1 ||
+ spare->tagByte2 != rbSpare.tagByte2 ||
+ spare->tagByte3 != rbSpare.tagByte3 ||
+ spare->tagByte4 != rbSpare.tagByte4 ||
+ spare->tagByte5 != rbSpare.tagByte5 ||
+ spare->tagByte6 != rbSpare.tagByte6 ||
+ spare->tagByte7 != rbSpare.tagByte7 ||
+ spare->ecc1[0] != rbSpare.ecc1[0] ||
+ spare->ecc1[1] != rbSpare.ecc1[1] ||
+ spare->ecc1[2] != rbSpare.ecc1[2] ||
+ spare->ecc2[0] != rbSpare.ecc2[0] ||
+ spare->ecc2[1] != rbSpare.ecc2[1] ||
+ spare->ecc2[2] != rbSpare.ecc2[2] )
+ {
+ // Didn't verify
+ yaffs_DeleteChunk(dev,chunk);
+ writeOk = 0;
+ }
+
}
}
} while(chunk >= 0 && ! writeOk);
}
-void yaffs_CalcECC(const __u8 *buffer, yaffs_Spare *spare)
+void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
{
-
- // Todo do nothing now. Need to put in ecc
- spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xFF;
- spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xFF;
+ nand_calculate_ecc (data , spare->ecc1);
+ nand_calculate_ecc (&data[256] , spare->ecc2);
}
void yaffs_CalcTagsECC(yaffs_Tags *tags)
{
// Todo don't do anything yet. Need to calculate ecc
- tags->ecc = 0xFFFFFFFF;
+ 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 &0x7f; j<<=1)
+ {
+ bit++;
+ if(b[i] & j)
+ {
+ ecc ^= bit;
+ }
+ }
+ }
+
+ tags->ecc = ecc;
+
+
}
+void yaffs_CheckECCOnTags(yaffs_Tags *tags)
+{
+ unsigned ecc = tags->ecc;
+
+ yaffs_CalcTagsECC(tags);
+
+ ecc ^= tags->ecc;
+
+ if(ecc)
+ {
+ // Needs fixing
+ unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
+
+ ecc--;
+
+ b[ecc / 8] ^= (1 << (ecc & 7));
+
+ // Now recvalc the ecc
+ yaffs_CalcTagsECC(tags);
+ }
+}
///////////////////////// TNODES ///////////////////////
INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
+ // No action required
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
+ // No action required
break;
case YAFFS_OBJECT_TYPE_UNKNOWN:
// todo this should not happen
else
{
// It's a data chunk
- yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk);
+ yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
}
tu->asBytes[6]= sparePtr->tagByte6;
tu->asBytes[7]= sparePtr->tagByte7;
- // Todo Check ECC on tags
+ yaffs_CheckECCOnTags(tagsPtr);
}
static void yaffs_SpareInitialise(yaffs_Spare *spare)
#endif
-static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND)
+static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan)
{
yaffs_Tnode *tn;
yaffs_Device *dev = in->myDev;
+ int existingChunk;
+ yaffs_Tags existingTags;
+ yaffs_Tags newTags;
+ unsigned existingSerial, newSerial;
+
tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
+
+ if(inScan)
+ {
+ // If we're scanning then we need to test for duplicates
+ // NB This does not need to be efficient since it should only ever
+ // happen when the power fails during a write, then only one
+ // chunk should ever be affected.
+
+ existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];
+
+ if(existingChunk != 0)
+ {
+ // We have a duplicate now we need to decide which one to use
+ // To do this we get both sets of tags and compare serial numbers.
+ yaffs_ReadChunkTagsFromNAND(dev,chunkInInode, &newTags);
+ yaffs_ReadChunkTagsFromNAND(dev,existingChunk, &existingTags);
+ newSerial = newTags.serialNumber;
+ existingSerial = existingTags.serialNumber;
+ if(((existingSerial+1) & 3) == newSerial)
+ {
+ // Use new
+ // Delete the old one and drop through to update the tnode
+ yaffs_DeleteChunk(dev,existingChunk);
+ }
+ else
+ {
+ // Use existing.
+ // Delete the new one and return early so that the tnode isn't changed
+ yaffs_DeleteChunk(dev,chunkInInode);
+ return YAFFS_OK;
+ }
+ }
+ }
+
tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = chunkInNAND;
+
return YAFFS_OK;
}
}
else
{
- T(("Bad news deteing chunk %d\n",chunkId));
+ T(("Bad news deleting chunk %d\n",chunkId));
}
}
newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
if(newChunkId >= 0)
{
- yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId);
+ yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId,0);
if(prevChunkId >= 0)
switch(in->variantType)
{
- case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ // Should not happen
break;
case YAFFS_OBJECT_TYPE_FILE:
oh->fileSize = in->variant.fileVariant.fileSize;
case YAFFS_OBJECT_TYPE_HARDLINK:
oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
break;
- case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ // Do nothing
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
inuse++;
pageBits |= ( 1 <<c);
in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
- // todo check for a clash (two data chunks with
+ // PutChuunkIntoFIle checks for a clash (two data chunks with
// the same chunkId).
- yaffs_PutChunkIntoFile(in,tags.chunkId,chunk);
+ yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1);
T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));
}
else