-/*
- * Access functions to useful fake objects.
- * Note that root might have a presence in NAND if permissions are set.
- */
-
-yaffs_Object *yaffs_Root(yaffs_Device *dev)
-{
- return dev->rootDir;
-}
-
-yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
-{
- return dev->lostNFoundDir;
-}
-
-
-/*
- * Erased NAND checking functions
- */
-
-int yaffs_CheckFF(__u8 *buffer, int nBytes)
-{
- /* Horrible, slow implementation */
- while (nBytes--) {
- if (*buffer != 0xFF)
- return 0;
- buffer++;
- }
- return 1;
-}
-
-static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
- int chunkInNAND)
-{
- int retval = YAFFS_OK;
- __u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
- yaffs_ExtendedTags tags;
- int result;
-
- result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
-
- if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
- retval = YAFFS_FAIL;
-
- if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
- T(YAFFS_TRACE_NANDACCESS,
- (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
- retval = YAFFS_FAIL;
- }
-
- yaffs_ReleaseTempBuffer(dev, data, __LINE__);
-
- return retval;
-
-}
-
-
-static int yaffs_VerifyChunkWritten(yaffs_Device *dev,
- int chunkInNAND,
- const __u8 *data,
- yaffs_ExtendedTags *tags)
-{
- int retval = YAFFS_OK;
- yaffs_ExtendedTags tempTags;
- __u8 *buffer = yaffs_GetTempBuffer(dev,__LINE__);
- int result;
-
- result = yaffs_ReadChunkWithTagsFromNAND(dev,chunkInNAND,buffer,&tempTags);
- if(memcmp(buffer,data,dev->nDataBytesPerChunk) ||
- tempTags.objectId != tags->objectId ||
- tempTags.chunkId != tags->chunkId ||
- tempTags.byteCount != tags->byteCount)
- retval = YAFFS_FAIL;
-
- yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
-
- return retval;
-}
-
-static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
- const __u8 *data,
- yaffs_ExtendedTags *tags,
- int useReserve)
-{
- int attempts = 0;
- int writeOk = 0;
- int chunk;
-
- yaffs2_InvalidateCheckpoint(dev);
-
- do {
- yaffs_BlockInfo *bi = 0;
- int erasedOk = 0;
-
- chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
- if (chunk < 0) {
- /* no space */
- break;
- }
-
- /* First check this chunk is erased, if it needs
- * checking. The checking policy (unless forced
- * always on) is as follows:
- *
- * Check the first page we try to write in a block.
- * If the check passes then we don't need to check any
- * more. If the check fails, we check again...
- * If the block has been erased, we don't need to check.
- *
- * However, if the block has been prioritised for gc,
- * then we think there might be something odd about
- * this block and stop using it.
- *
- * Rationale: We should only ever see chunks that have
- * not been erased if there was a partially written
- * chunk due to power loss. This checking policy should
- * catch that case with very few checks and thus save a
- * lot of checks that are most likely not needed.
- *
- * Mods to the above
- * If an erase check fails or the write fails we skip the
- * rest of the block.
- */
-
- /* let's give it a try */
- attempts++;
-
-#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
- bi->skipErasedCheck = 0;
-#endif
- if (!bi->skipErasedCheck) {
- erasedOk = yaffs_CheckChunkErased(dev, chunk);
- if (erasedOk != YAFFS_OK) {
- T(YAFFS_TRACE_ERROR,
- (TSTR("**>> yaffs chunk %d was not erased"
- TENDSTR), chunk));
-
- /* If not erased, delete this one,
- * skip rest of block and
- * try another chunk */
- yaffs_DeleteChunk(dev,chunk,1,__LINE__);
- yaffs_SkipRestOfBlock(dev);
- continue;
- }
- }
-
- writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
- data, tags);
-
- if(!bi->skipErasedCheck)
- writeOk = yaffs_VerifyChunkWritten(dev, chunk, data, tags);
-
- if (writeOk != YAFFS_OK) {
- /* Clean up aborted write, skip to next block and
- * try another chunk */
- yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
- continue;
- }
-
- bi->skipErasedCheck = 1;
-
- /* Copy the data into the robustification buffer */
- yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
-
- } while (writeOk != YAFFS_OK &&
- (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
-
- if (!writeOk)
- chunk = -1;
-
- if (attempts > 1) {
- T(YAFFS_TRACE_ERROR,
- (TSTR("**>> yaffs write required %d attempts" TENDSTR),
- attempts));
-
- dev->nRetriedWrites += (attempts - 1);
- }
-
- return chunk;
-}
-
-
-
-/*
- * Block retiring for handling a broken block.
- */
-
-static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
-{
- yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
-
- yaffs2_InvalidateCheckpoint(dev);
-
- yaffs2_ClearOldestDirtySequence(dev,bi);
-
- if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
- if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
- T(YAFFS_TRACE_ALWAYS, (TSTR(
- "yaffs: Failed to mark bad and erase block %d"
- TENDSTR), blockInNAND));
- } else {
- yaffs_ExtendedTags tags;
- int chunkId = blockInNAND * dev->param.nChunksPerBlock;
-
- __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
-
- memset(buffer, 0xff, dev->nDataBytesPerChunk);
- yaffs_InitialiseTags(&tags);
- tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
- if (dev->param.writeChunkWithTagsToNAND(dev, chunkId -
- dev->chunkOffset, buffer, &tags) != YAFFS_OK)
- T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
- TCONT("write bad block marker to block %d")
- TENDSTR), blockInNAND));
-
- yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
- }
- }
-
- bi->blockState = YAFFS_BLOCK_STATE_DEAD;
- bi->gcPrioritise = 0;
- bi->needsRetiring = 0;
-
- dev->nRetiredBlocks++;
-}
-
-/*
- * Functions for robustisizing TODO
- *
- */
-
-static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
- const __u8 *data,
- const yaffs_ExtendedTags *tags)
-{
- dev=dev;
- chunkInNAND=chunkInNAND;
- data=data;
- tags=tags;
-}
-
-static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
- const yaffs_ExtendedTags *tags)
-{
- dev=dev;
- chunkInNAND=chunkInNAND;
- tags=tags;
-}
-
-void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
-{
- if (!bi->gcPrioritise) {
- bi->gcPrioritise = 1;
- dev->hasPendingPrioritisedGCs = 1;
- bi->chunkErrorStrikes++;
-
- if (bi->chunkErrorStrikes > 3) {
- bi->needsRetiring = 1; /* Too many stikes, so retire this */
- T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
-
- }
- }
-}
-
-static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
- int erasedOk)
-{
- int blockInNAND = chunkInNAND / dev->param.nChunksPerBlock;
- yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
-
- yaffs_HandleChunkError(dev, bi);
-
- if (erasedOk) {
- /* Was an actual write failure, so mark the block for retirement */
- bi->needsRetiring = 1;
- T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
- (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
- }
-
- /* Delete the chunk */
- yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
- yaffs_SkipRestOfBlock(dev);
-}
-
-
-/*---------------- Name handling functions ------------*/
-
-static __u16 yaffs_CalcNameSum(const YCHAR *name)