140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project/*
240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project * YAFFS: Yet another FFS. A NAND-flash specific file system.
340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project *
440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project * Copyright (C) 2002 Aleph One Ltd.
540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project *   for Toby Churchill Ltd and Brightstar Engineering
640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project *
740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project * Created by Charles Manning <charles@aleph1.co.uk>
840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project *
940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project * This program is free software; you can redistribute it and/or modify
1040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project * it under the terms of the GNU General Public License version 2 as
1140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project * published by the Free Software Foundation.
1240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project *
1340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project */
1440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
1540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectconst char *yaffs_checkptrw_c_version =
1640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project    "$Id: yaffs_checkptrw.c,v 1.5 2006/10/03 10:13:03 charles Exp $";
1740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
1840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
1940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project#include "yaffs_checkptrw.h"
2040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
2140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
2240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectstatic int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
2340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
2440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
2540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
2640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
2740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	T(YAFFS_TRACE_CHECKPOINT,
2840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		(TSTR("checkpt blocks available = %d" TENDSTR),
2940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		blocksAvailable));
3040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
3140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
3240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	return (blocksAvailable <= 0) ? 0 : 1;
3340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
3440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
3540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
3640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
3740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectstatic int yaffs_CheckpointErase(yaffs_Device *dev)
3840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
3940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
4040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int i;
4140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
4240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
4340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(!dev->eraseBlockInNAND)
4440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return 0;
4540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
4640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->startBlock,dev->endBlock));
4740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
4840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	for(i = dev->startBlock; i <= dev->endBlock; i++) {
4940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		yaffs_BlockInfo *bi = &dev->blockInfo[i];
5040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){
5140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i));
5240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			if(dev->eraseBlockInNAND(dev,i)){
5340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
5440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->nErasedBlocks++;
5540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->nFreeChunks += dev->nChunksPerBlock;
5640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			}
5740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			else {
5840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->markNANDBlockBad(dev,i);
5940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				bi->blockState = YAFFS_BLOCK_STATE_DEAD;
6040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			}
6140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		}
6240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	}
6340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
6440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->blocksInCheckpoint = 0;
6540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
6640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	return 1;
6740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
6840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
6940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
7040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectstatic void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
7140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
7240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int  i;
7340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
7440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
7540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(dev->checkpointNextBlock >= 0 &&
7640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	   dev->checkpointNextBlock <= dev->endBlock &&
7740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	   blocksAvailable > 0){
7840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
7940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		for(i = dev->checkpointNextBlock; i <= dev->endBlock; i++){
8040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			yaffs_BlockInfo *bi = &dev->blockInfo[i];
8140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){
8240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->checkpointNextBlock = i + 1;
8340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->checkpointCurrentBlock = i;
8440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i));
8540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				return;
8640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			}
8740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		}
8840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	}
8940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
9040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
9140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->checkpointNextBlock = -1;
9240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->checkpointCurrentBlock = -1;
9340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
9440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
9540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectstatic void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
9640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
9740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int  i;
9840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	yaffs_ExtendedTags tags;
9940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
10040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
10140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		for(i = dev->checkpointNextBlock; i <= dev->endBlock; i++){
10240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			int chunk = i * dev->nChunksPerBlock;
10340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
10440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			dev->readChunkWithTagsFromNAND(dev,chunk,NULL,&tags);
10540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
10640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
10740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				/* Right kind of block */
10840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->checkpointNextBlock = tags.objectId;
10940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->checkpointCurrentBlock = i;
11040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
11140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->blocksInCheckpoint++;
11240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i));
11340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				return;
11440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			}
11540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		}
11640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
11740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
11840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
11940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->checkpointNextBlock = -1;
12040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->checkpointCurrentBlock = -1;
12140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
12240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
12340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
12440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectint yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
12540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
12640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
12740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	/* Got the functions we need? */
12840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if (!dev->writeChunkWithTagsToNAND ||
12940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	    !dev->readChunkWithTagsFromNAND ||
13040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	    !dev->eraseBlockInNAND ||
13140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	    !dev->markNANDBlockBad)
13240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return 0;
13340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
13440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(forWriting && !yaffs_CheckpointSpaceOk(dev))
13540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return 0;
13640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
13740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(!dev->checkpointBuffer)
13840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
13940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(!dev->checkpointBuffer)
14040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return 0;
14140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
14240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
14340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->checkpointPageSequence = 0;
14440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
14540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->checkpointOpenForWrite = forWriting;
14640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
14740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->checkpointByteCount = 0;
14840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->checkpointCurrentBlock = -1;
14940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->checkpointCurrentChunk = -1;
15040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->checkpointNextBlock = dev->startBlock;
15140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
15240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	/* Erase all the blocks in the checkpoint area */
15340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(forWriting){
15440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
15540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->checkpointByteOffset = 0;
15640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return yaffs_CheckpointErase(dev);
15740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
15840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
15940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	} else {
16040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		int i;
16140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		/* Set to a value that will kick off a read */
16240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->checkpointByteOffset = dev->nDataBytesPerChunk;
16340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
16440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		 * going to be way more than we need */
16540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->blocksInCheckpoint = 0;
16640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->checkpointMaxBlocks = (dev->endBlock - dev->startBlock)/16 + 2;
16740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
16840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		for(i = 0; i < dev->checkpointMaxBlocks; i++)
16940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			dev->checkpointBlockList[i] = -1;
17040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	}
17140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
17240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	return 1;
17340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
17440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
17540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectstatic int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
17640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
17740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
17840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int chunk;
17940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
18040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	yaffs_ExtendedTags tags;
18140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
18240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(dev->checkpointCurrentBlock < 0){
18340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		yaffs_CheckpointFindNextErasedBlock(dev);
18440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->checkpointCurrentChunk = 0;
18540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	}
18640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
18740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(dev->checkpointCurrentBlock < 0)
18840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return 0;
18940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
19040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	tags.chunkDeleted = 0;
19140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
19240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	tags.chunkId = dev->checkpointPageSequence + 1;
19340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	tags.sequenceNumber =  YAFFS_SEQUENCE_CHECKPOINT_DATA;
19440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	tags.byteCount = dev->nDataBytesPerChunk;
19540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(dev->checkpointCurrentChunk == 0){
19640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		/* First chunk we write for the block? Set block state to
19740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		   checkpoint */
19840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		yaffs_BlockInfo *bi = &dev->blockInfo[dev->checkpointCurrentBlock];
19940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
20040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->blocksInCheckpoint++;
20140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	}
20240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
20340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
20440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
20540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->writeChunkWithTagsToNAND(dev,chunk,dev->checkpointBuffer,&tags);
20640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->checkpointByteOffset = 0;
20740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->checkpointPageSequence++;
20840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->checkpointCurrentChunk++;
20940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){
21040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->checkpointCurrentChunk = 0;
21140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->checkpointCurrentBlock = -1;
21240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	}
21340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
21440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
21540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	return 1;
21640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
21740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
21840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
21940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectint yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
22040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
22140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int i=0;
22240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int ok = 1;
22340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
22440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
22540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	__u8 * dataBytes = (__u8 *)data;
22640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
22740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
22840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
22940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(!dev->checkpointBuffer)
23040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return 0;
23140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
23240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	while(i < nBytes && ok) {
23340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
23440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
23540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
23640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		 dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
23740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->checkpointByteOffset++;
23840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		i++;
23940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dataBytes++;
24040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->checkpointByteCount++;
24140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
24240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
24340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		if(dev->checkpointByteOffset < 0 ||
24440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		   dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
24540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			ok = yaffs_CheckpointFlushBuffer(dev);
24640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
24740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	}
24840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
24940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	return 	i;
25040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
25140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
25240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectint yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
25340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
25440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int i=0;
25540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int ok = 1;
25640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	yaffs_ExtendedTags tags;
25740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
25840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
25940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	int chunk;
26040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
26140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	__u8 *dataBytes = (__u8 *)data;
26240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
26340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(!dev->checkpointBuffer)
26440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return 0;
26540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
26640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	while(i < nBytes && ok) {
26740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
26840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
26940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		if(dev->checkpointByteOffset < 0 ||
27040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		   dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
27140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
27240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		   	if(dev->checkpointCurrentBlock < 0){
27340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				yaffs_CheckpointFindNextCheckpointBlock(dev);
27440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->checkpointCurrentChunk = 0;
27540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			}
27640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
27740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			if(dev->checkpointCurrentBlock < 0)
27840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				ok = 0;
27940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			else {
28040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
28140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
28240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				          dev->checkpointCurrentChunk;
28340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
28440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	   			/* read in the next chunk */
28540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	   			/* printf("read checkpoint page %d\n",dev->checkpointPage); */
28640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->readChunkWithTagsFromNAND(dev, chunk,
28740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project							       dev->checkpointBuffer,
28840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project							      &tags);
28940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
29040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
29140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				   tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
29240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				   ok = 0;
29340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
29440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->checkpointByteOffset = 0;
29540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->checkpointPageSequence++;
29640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				dev->checkpointCurrentChunk++;
29740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
29840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
29940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project					dev->checkpointCurrentBlock = -1;
30040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			}
30140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		}
30240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
30340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		if(ok){
30440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
30540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			dev->checkpointByteOffset++;
30640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			i++;
30740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			dataBytes++;
30840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			dev->checkpointByteCount++;
30940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		}
31040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	}
31140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
31240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	return 	i;
31340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
31440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
31540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectint yaffs_CheckpointClose(yaffs_Device *dev)
31640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
31740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
31840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(dev->checkpointOpenForWrite){
31940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		if(dev->checkpointByteOffset != 0)
32040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			yaffs_CheckpointFlushBuffer(dev);
32140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	} else {
32240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		int i;
32340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){
32440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			yaffs_BlockInfo *bi = &dev->blockInfo[dev->checkpointBlockList[i]];
32540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
32640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
32740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			else {
32840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project				// Todo this looks odd...
32940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			}
33040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		}
33140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		YFREE(dev->checkpointBlockList);
33240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->checkpointBlockList = NULL;
33340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	}
33440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
33540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
33640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	dev->nErasedBlocks -= dev->blocksInCheckpoint;
33740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
33840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
33940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
34040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project			dev->checkpointByteCount));
34140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
34240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(dev->checkpointBuffer){
34340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		/* free the buffer */
34440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		YFREE(dev->checkpointBuffer);
34540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		dev->checkpointBuffer = NULL;
34640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return 1;
34740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	}
34840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	else
34940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return 0;
35040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
35140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
35240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
35340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Projectint yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
35440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project{
35540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	/* Erase the first checksum block */
35640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
35740c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
35840c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
35940c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	if(!yaffs_CheckpointSpaceOk(dev))
36040c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project		return 0;
36140c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
36240c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project	return yaffs_CheckpointErase(dev);
36340c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project}
36440c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
36540c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
36640c4004d07a37a9b140067f893930ce4436b9346The Android Open Source Project
367