xref: /rk3399_rockchip-uboot/fs/yaffs2/yaffs_checkptrw.c (revision 0e8cc8bd92257da2e1df88cbc985e166e472ce61)
1*0e8cc8bdSWilliam Juul /*
2*0e8cc8bdSWilliam Juul  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3*0e8cc8bdSWilliam Juul  *
4*0e8cc8bdSWilliam Juul  * Copyright (C) 2002-2007 Aleph One Ltd.
5*0e8cc8bdSWilliam Juul  *   for Toby Churchill Ltd and Brightstar Engineering
6*0e8cc8bdSWilliam Juul  *
7*0e8cc8bdSWilliam Juul  * Created by Charles Manning <charles@aleph1.co.uk>
8*0e8cc8bdSWilliam Juul  *
9*0e8cc8bdSWilliam Juul  * This program is free software; you can redistribute it and/or modify
10*0e8cc8bdSWilliam Juul  * it under the terms of the GNU General Public License version 2 as
11*0e8cc8bdSWilliam Juul  * published by the Free Software Foundation.
12*0e8cc8bdSWilliam Juul  */
13*0e8cc8bdSWilliam Juul 
14*0e8cc8bdSWilliam Juul const char *yaffs_checkptrw_c_version =
15*0e8cc8bdSWilliam Juul     "$Id: yaffs_checkptrw.c,v 1.14 2007/05/15 20:07:40 charles Exp $";
16*0e8cc8bdSWilliam Juul 
17*0e8cc8bdSWilliam Juul 
18*0e8cc8bdSWilliam Juul #include "yaffs_checkptrw.h"
19*0e8cc8bdSWilliam Juul 
20*0e8cc8bdSWilliam Juul 
21*0e8cc8bdSWilliam Juul static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
22*0e8cc8bdSWilliam Juul {
23*0e8cc8bdSWilliam Juul 
24*0e8cc8bdSWilliam Juul 	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
25*0e8cc8bdSWilliam Juul 
26*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_CHECKPOINT,
27*0e8cc8bdSWilliam Juul 		(TSTR("checkpt blocks available = %d" TENDSTR),
28*0e8cc8bdSWilliam Juul 		blocksAvailable));
29*0e8cc8bdSWilliam Juul 
30*0e8cc8bdSWilliam Juul 
31*0e8cc8bdSWilliam Juul 	return (blocksAvailable <= 0) ? 0 : 1;
32*0e8cc8bdSWilliam Juul }
33*0e8cc8bdSWilliam Juul 
34*0e8cc8bdSWilliam Juul 
35*0e8cc8bdSWilliam Juul static int yaffs_CheckpointErase(yaffs_Device *dev)
36*0e8cc8bdSWilliam Juul {
37*0e8cc8bdSWilliam Juul 
38*0e8cc8bdSWilliam Juul 	int i;
39*0e8cc8bdSWilliam Juul 
40*0e8cc8bdSWilliam Juul 
41*0e8cc8bdSWilliam Juul 	if(!dev->eraseBlockInNAND)
42*0e8cc8bdSWilliam Juul 		return 0;
43*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
44*0e8cc8bdSWilliam Juul 		dev->internalStartBlock,dev->internalEndBlock));
45*0e8cc8bdSWilliam Juul 
46*0e8cc8bdSWilliam Juul 	for(i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
47*0e8cc8bdSWilliam Juul 		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
48*0e8cc8bdSWilliam Juul 		if(bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT){
49*0e8cc8bdSWilliam Juul 			T(YAFFS_TRACE_CHECKPOINT,(TSTR("erasing checkpt block %d"TENDSTR),i));
50*0e8cc8bdSWilliam Juul 			if(dev->eraseBlockInNAND(dev,i- dev->blockOffset /* realign */)){
51*0e8cc8bdSWilliam Juul 				bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
52*0e8cc8bdSWilliam Juul 				dev->nErasedBlocks++;
53*0e8cc8bdSWilliam Juul 				dev->nFreeChunks += dev->nChunksPerBlock;
54*0e8cc8bdSWilliam Juul 			}
55*0e8cc8bdSWilliam Juul 			else {
56*0e8cc8bdSWilliam Juul 				dev->markNANDBlockBad(dev,i);
57*0e8cc8bdSWilliam Juul 				bi->blockState = YAFFS_BLOCK_STATE_DEAD;
58*0e8cc8bdSWilliam Juul 			}
59*0e8cc8bdSWilliam Juul 		}
60*0e8cc8bdSWilliam Juul 	}
61*0e8cc8bdSWilliam Juul 
62*0e8cc8bdSWilliam Juul 	dev->blocksInCheckpoint = 0;
63*0e8cc8bdSWilliam Juul 
64*0e8cc8bdSWilliam Juul 	return 1;
65*0e8cc8bdSWilliam Juul }
66*0e8cc8bdSWilliam Juul 
67*0e8cc8bdSWilliam Juul 
68*0e8cc8bdSWilliam Juul static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
69*0e8cc8bdSWilliam Juul {
70*0e8cc8bdSWilliam Juul 	int  i;
71*0e8cc8bdSWilliam Juul 	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
72*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_CHECKPOINT,
73*0e8cc8bdSWilliam Juul 		(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
74*0e8cc8bdSWilliam Juul 		dev->nErasedBlocks,dev->nReservedBlocks,blocksAvailable,dev->checkpointNextBlock));
75*0e8cc8bdSWilliam Juul 
76*0e8cc8bdSWilliam Juul 	if(dev->checkpointNextBlock >= 0 &&
77*0e8cc8bdSWilliam Juul 	   dev->checkpointNextBlock <= dev->internalEndBlock &&
78*0e8cc8bdSWilliam Juul 	   blocksAvailable > 0){
79*0e8cc8bdSWilliam Juul 
80*0e8cc8bdSWilliam Juul 		for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
81*0e8cc8bdSWilliam Juul 			yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,i);
82*0e8cc8bdSWilliam Juul 			if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY){
83*0e8cc8bdSWilliam Juul 				dev->checkpointNextBlock = i + 1;
84*0e8cc8bdSWilliam Juul 				dev->checkpointCurrentBlock = i;
85*0e8cc8bdSWilliam Juul 				T(YAFFS_TRACE_CHECKPOINT,(TSTR("allocating checkpt block %d"TENDSTR),i));
86*0e8cc8bdSWilliam Juul 				return;
87*0e8cc8bdSWilliam Juul 			}
88*0e8cc8bdSWilliam Juul 		}
89*0e8cc8bdSWilliam Juul 	}
90*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("out of checkpt blocks"TENDSTR)));
91*0e8cc8bdSWilliam Juul 
92*0e8cc8bdSWilliam Juul 	dev->checkpointNextBlock = -1;
93*0e8cc8bdSWilliam Juul 	dev->checkpointCurrentBlock = -1;
94*0e8cc8bdSWilliam Juul }
95*0e8cc8bdSWilliam Juul 
96*0e8cc8bdSWilliam Juul static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
97*0e8cc8bdSWilliam Juul {
98*0e8cc8bdSWilliam Juul 	int  i;
99*0e8cc8bdSWilliam Juul 	yaffs_ExtendedTags tags;
100*0e8cc8bdSWilliam Juul 
101*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start:  blocks %d next %d" TENDSTR),
102*0e8cc8bdSWilliam Juul 		dev->blocksInCheckpoint, dev->checkpointNextBlock));
103*0e8cc8bdSWilliam Juul 
104*0e8cc8bdSWilliam Juul 	if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
105*0e8cc8bdSWilliam Juul 		for(i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++){
106*0e8cc8bdSWilliam Juul 			int chunk = i * dev->nChunksPerBlock;
107*0e8cc8bdSWilliam Juul 			int realignedChunk = chunk - dev->chunkOffset;
108*0e8cc8bdSWilliam Juul 
109*0e8cc8bdSWilliam Juul 			dev->readChunkWithTagsFromNAND(dev,realignedChunk,NULL,&tags);
110*0e8cc8bdSWilliam Juul 			T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
111*0e8cc8bdSWilliam Juul 				i, tags.objectId,tags.sequenceNumber,tags.eccResult));
112*0e8cc8bdSWilliam Juul 
113*0e8cc8bdSWilliam Juul 			if(tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA){
114*0e8cc8bdSWilliam Juul 				/* Right kind of block */
115*0e8cc8bdSWilliam Juul 				dev->checkpointNextBlock = tags.objectId;
116*0e8cc8bdSWilliam Juul 				dev->checkpointCurrentBlock = i;
117*0e8cc8bdSWilliam Juul 				dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
118*0e8cc8bdSWilliam Juul 				dev->blocksInCheckpoint++;
119*0e8cc8bdSWilliam Juul 				T(YAFFS_TRACE_CHECKPOINT,(TSTR("found checkpt block %d"TENDSTR),i));
120*0e8cc8bdSWilliam Juul 				return;
121*0e8cc8bdSWilliam Juul 			}
122*0e8cc8bdSWilliam Juul 		}
123*0e8cc8bdSWilliam Juul 
124*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("found no more checkpt blocks"TENDSTR)));
125*0e8cc8bdSWilliam Juul 
126*0e8cc8bdSWilliam Juul 	dev->checkpointNextBlock = -1;
127*0e8cc8bdSWilliam Juul 	dev->checkpointCurrentBlock = -1;
128*0e8cc8bdSWilliam Juul }
129*0e8cc8bdSWilliam Juul 
130*0e8cc8bdSWilliam Juul 
131*0e8cc8bdSWilliam Juul int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
132*0e8cc8bdSWilliam Juul {
133*0e8cc8bdSWilliam Juul 
134*0e8cc8bdSWilliam Juul 	/* Got the functions we need? */
135*0e8cc8bdSWilliam Juul 	if (!dev->writeChunkWithTagsToNAND ||
136*0e8cc8bdSWilliam Juul 	    !dev->readChunkWithTagsFromNAND ||
137*0e8cc8bdSWilliam Juul 	    !dev->eraseBlockInNAND ||
138*0e8cc8bdSWilliam Juul 	    !dev->markNANDBlockBad)
139*0e8cc8bdSWilliam Juul 		return 0;
140*0e8cc8bdSWilliam Juul 
141*0e8cc8bdSWilliam Juul 	if(forWriting && !yaffs_CheckpointSpaceOk(dev))
142*0e8cc8bdSWilliam Juul 		return 0;
143*0e8cc8bdSWilliam Juul 
144*0e8cc8bdSWilliam Juul 	if(!dev->checkpointBuffer)
145*0e8cc8bdSWilliam Juul 		dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
146*0e8cc8bdSWilliam Juul 	if(!dev->checkpointBuffer)
147*0e8cc8bdSWilliam Juul 		return 0;
148*0e8cc8bdSWilliam Juul 
149*0e8cc8bdSWilliam Juul 
150*0e8cc8bdSWilliam Juul 	dev->checkpointPageSequence = 0;
151*0e8cc8bdSWilliam Juul 
152*0e8cc8bdSWilliam Juul 	dev->checkpointOpenForWrite = forWriting;
153*0e8cc8bdSWilliam Juul 
154*0e8cc8bdSWilliam Juul 	dev->checkpointByteCount = 0;
155*0e8cc8bdSWilliam Juul 	dev->checkpointSum = 0;
156*0e8cc8bdSWilliam Juul 	dev->checkpointXor = 0;
157*0e8cc8bdSWilliam Juul 	dev->checkpointCurrentBlock = -1;
158*0e8cc8bdSWilliam Juul 	dev->checkpointCurrentChunk = -1;
159*0e8cc8bdSWilliam Juul 	dev->checkpointNextBlock = dev->internalStartBlock;
160*0e8cc8bdSWilliam Juul 
161*0e8cc8bdSWilliam Juul 	/* Erase all the blocks in the checkpoint area */
162*0e8cc8bdSWilliam Juul 	if(forWriting){
163*0e8cc8bdSWilliam Juul 		memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
164*0e8cc8bdSWilliam Juul 		dev->checkpointByteOffset = 0;
165*0e8cc8bdSWilliam Juul 		return yaffs_CheckpointErase(dev);
166*0e8cc8bdSWilliam Juul 
167*0e8cc8bdSWilliam Juul 
168*0e8cc8bdSWilliam Juul 	} else {
169*0e8cc8bdSWilliam Juul 		int i;
170*0e8cc8bdSWilliam Juul 		/* Set to a value that will kick off a read */
171*0e8cc8bdSWilliam Juul 		dev->checkpointByteOffset = dev->nDataBytesPerChunk;
172*0e8cc8bdSWilliam Juul 		/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
173*0e8cc8bdSWilliam Juul 		 * going to be way more than we need */
174*0e8cc8bdSWilliam Juul 		dev->blocksInCheckpoint = 0;
175*0e8cc8bdSWilliam Juul 		dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
176*0e8cc8bdSWilliam Juul 		dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
177*0e8cc8bdSWilliam Juul 		for(i = 0; i < dev->checkpointMaxBlocks; i++)
178*0e8cc8bdSWilliam Juul 			dev->checkpointBlockList[i] = -1;
179*0e8cc8bdSWilliam Juul 	}
180*0e8cc8bdSWilliam Juul 
181*0e8cc8bdSWilliam Juul 	return 1;
182*0e8cc8bdSWilliam Juul }
183*0e8cc8bdSWilliam Juul 
184*0e8cc8bdSWilliam Juul int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
185*0e8cc8bdSWilliam Juul {
186*0e8cc8bdSWilliam Juul 	__u32 compositeSum;
187*0e8cc8bdSWilliam Juul 	compositeSum =  (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
188*0e8cc8bdSWilliam Juul 	*sum = compositeSum;
189*0e8cc8bdSWilliam Juul 	return 1;
190*0e8cc8bdSWilliam Juul }
191*0e8cc8bdSWilliam Juul 
192*0e8cc8bdSWilliam Juul static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
193*0e8cc8bdSWilliam Juul {
194*0e8cc8bdSWilliam Juul 
195*0e8cc8bdSWilliam Juul 	int chunk;
196*0e8cc8bdSWilliam Juul 	int realignedChunk;
197*0e8cc8bdSWilliam Juul 
198*0e8cc8bdSWilliam Juul 	yaffs_ExtendedTags tags;
199*0e8cc8bdSWilliam Juul 
200*0e8cc8bdSWilliam Juul 	if(dev->checkpointCurrentBlock < 0){
201*0e8cc8bdSWilliam Juul 		yaffs_CheckpointFindNextErasedBlock(dev);
202*0e8cc8bdSWilliam Juul 		dev->checkpointCurrentChunk = 0;
203*0e8cc8bdSWilliam Juul 	}
204*0e8cc8bdSWilliam Juul 
205*0e8cc8bdSWilliam Juul 	if(dev->checkpointCurrentBlock < 0)
206*0e8cc8bdSWilliam Juul 		return 0;
207*0e8cc8bdSWilliam Juul 
208*0e8cc8bdSWilliam Juul 	tags.chunkDeleted = 0;
209*0e8cc8bdSWilliam Juul 	tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
210*0e8cc8bdSWilliam Juul 	tags.chunkId = dev->checkpointPageSequence + 1;
211*0e8cc8bdSWilliam Juul 	tags.sequenceNumber =  YAFFS_SEQUENCE_CHECKPOINT_DATA;
212*0e8cc8bdSWilliam Juul 	tags.byteCount = dev->nDataBytesPerChunk;
213*0e8cc8bdSWilliam Juul 	if(dev->checkpointCurrentChunk == 0){
214*0e8cc8bdSWilliam Juul 		/* First chunk we write for the block? Set block state to
215*0e8cc8bdSWilliam Juul 		   checkpoint */
216*0e8cc8bdSWilliam Juul 		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointCurrentBlock);
217*0e8cc8bdSWilliam Juul 		bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
218*0e8cc8bdSWilliam Juul 		dev->blocksInCheckpoint++;
219*0e8cc8bdSWilliam Juul 	}
220*0e8cc8bdSWilliam Juul 
221*0e8cc8bdSWilliam Juul 	chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
222*0e8cc8bdSWilliam Juul 
223*0e8cc8bdSWilliam Juul 
224*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
225*0e8cc8bdSWilliam Juul 		chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId));
226*0e8cc8bdSWilliam Juul 
227*0e8cc8bdSWilliam Juul 	realignedChunk = chunk - dev->chunkOffset;
228*0e8cc8bdSWilliam Juul 
229*0e8cc8bdSWilliam Juul 	dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags);
230*0e8cc8bdSWilliam Juul 	dev->checkpointByteOffset = 0;
231*0e8cc8bdSWilliam Juul 	dev->checkpointPageSequence++;
232*0e8cc8bdSWilliam Juul 	dev->checkpointCurrentChunk++;
233*0e8cc8bdSWilliam Juul 	if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock){
234*0e8cc8bdSWilliam Juul 		dev->checkpointCurrentChunk = 0;
235*0e8cc8bdSWilliam Juul 		dev->checkpointCurrentBlock = -1;
236*0e8cc8bdSWilliam Juul 	}
237*0e8cc8bdSWilliam Juul 	memset(dev->checkpointBuffer,0,dev->nDataBytesPerChunk);
238*0e8cc8bdSWilliam Juul 
239*0e8cc8bdSWilliam Juul 	return 1;
240*0e8cc8bdSWilliam Juul }
241*0e8cc8bdSWilliam Juul 
242*0e8cc8bdSWilliam Juul 
243*0e8cc8bdSWilliam Juul int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
244*0e8cc8bdSWilliam Juul {
245*0e8cc8bdSWilliam Juul 	int i=0;
246*0e8cc8bdSWilliam Juul 	int ok = 1;
247*0e8cc8bdSWilliam Juul 
248*0e8cc8bdSWilliam Juul 
249*0e8cc8bdSWilliam Juul 	__u8 * dataBytes = (__u8 *)data;
250*0e8cc8bdSWilliam Juul 
251*0e8cc8bdSWilliam Juul 
252*0e8cc8bdSWilliam Juul 
253*0e8cc8bdSWilliam Juul 	if(!dev->checkpointBuffer)
254*0e8cc8bdSWilliam Juul 		return 0;
255*0e8cc8bdSWilliam Juul 
256*0e8cc8bdSWilliam Juul 	if(!dev->checkpointOpenForWrite)
257*0e8cc8bdSWilliam Juul 		return -1;
258*0e8cc8bdSWilliam Juul 
259*0e8cc8bdSWilliam Juul 	while(i < nBytes && ok) {
260*0e8cc8bdSWilliam Juul 
261*0e8cc8bdSWilliam Juul 
262*0e8cc8bdSWilliam Juul 
263*0e8cc8bdSWilliam Juul 		dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
264*0e8cc8bdSWilliam Juul 		dev->checkpointSum += *dataBytes;
265*0e8cc8bdSWilliam Juul 		dev->checkpointXor ^= *dataBytes;
266*0e8cc8bdSWilliam Juul 
267*0e8cc8bdSWilliam Juul 		dev->checkpointByteOffset++;
268*0e8cc8bdSWilliam Juul 		i++;
269*0e8cc8bdSWilliam Juul 		dataBytes++;
270*0e8cc8bdSWilliam Juul 		dev->checkpointByteCount++;
271*0e8cc8bdSWilliam Juul 
272*0e8cc8bdSWilliam Juul 
273*0e8cc8bdSWilliam Juul 		if(dev->checkpointByteOffset < 0 ||
274*0e8cc8bdSWilliam Juul 		   dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
275*0e8cc8bdSWilliam Juul 			ok = yaffs_CheckpointFlushBuffer(dev);
276*0e8cc8bdSWilliam Juul 
277*0e8cc8bdSWilliam Juul 	}
278*0e8cc8bdSWilliam Juul 
279*0e8cc8bdSWilliam Juul 	return 	i;
280*0e8cc8bdSWilliam Juul }
281*0e8cc8bdSWilliam Juul 
282*0e8cc8bdSWilliam Juul int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
283*0e8cc8bdSWilliam Juul {
284*0e8cc8bdSWilliam Juul 	int i=0;
285*0e8cc8bdSWilliam Juul 	int ok = 1;
286*0e8cc8bdSWilliam Juul 	yaffs_ExtendedTags tags;
287*0e8cc8bdSWilliam Juul 
288*0e8cc8bdSWilliam Juul 
289*0e8cc8bdSWilliam Juul 	int chunk;
290*0e8cc8bdSWilliam Juul 	int realignedChunk;
291*0e8cc8bdSWilliam Juul 
292*0e8cc8bdSWilliam Juul 	__u8 *dataBytes = (__u8 *)data;
293*0e8cc8bdSWilliam Juul 
294*0e8cc8bdSWilliam Juul 	if(!dev->checkpointBuffer)
295*0e8cc8bdSWilliam Juul 		return 0;
296*0e8cc8bdSWilliam Juul 
297*0e8cc8bdSWilliam Juul 	if(dev->checkpointOpenForWrite)
298*0e8cc8bdSWilliam Juul 		return -1;
299*0e8cc8bdSWilliam Juul 
300*0e8cc8bdSWilliam Juul 	while(i < nBytes && ok) {
301*0e8cc8bdSWilliam Juul 
302*0e8cc8bdSWilliam Juul 
303*0e8cc8bdSWilliam Juul 		if(dev->checkpointByteOffset < 0 ||
304*0e8cc8bdSWilliam Juul 		   dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
305*0e8cc8bdSWilliam Juul 
306*0e8cc8bdSWilliam Juul 		   	if(dev->checkpointCurrentBlock < 0){
307*0e8cc8bdSWilliam Juul 				yaffs_CheckpointFindNextCheckpointBlock(dev);
308*0e8cc8bdSWilliam Juul 				dev->checkpointCurrentChunk = 0;
309*0e8cc8bdSWilliam Juul 			}
310*0e8cc8bdSWilliam Juul 
311*0e8cc8bdSWilliam Juul 			if(dev->checkpointCurrentBlock < 0)
312*0e8cc8bdSWilliam Juul 				ok = 0;
313*0e8cc8bdSWilliam Juul 			else {
314*0e8cc8bdSWilliam Juul 
315*0e8cc8bdSWilliam Juul 				chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
316*0e8cc8bdSWilliam Juul 				          dev->checkpointCurrentChunk;
317*0e8cc8bdSWilliam Juul 
318*0e8cc8bdSWilliam Juul 				realignedChunk = chunk - dev->chunkOffset;
319*0e8cc8bdSWilliam Juul 
320*0e8cc8bdSWilliam Juul 	   			/* read in the next chunk */
321*0e8cc8bdSWilliam Juul 	   			/* printf("read checkpoint page %d\n",dev->checkpointPage); */
322*0e8cc8bdSWilliam Juul 				dev->readChunkWithTagsFromNAND(dev, realignedChunk,
323*0e8cc8bdSWilliam Juul 							       dev->checkpointBuffer,
324*0e8cc8bdSWilliam Juul 							      &tags);
325*0e8cc8bdSWilliam Juul 
326*0e8cc8bdSWilliam Juul 				if(tags.chunkId != (dev->checkpointPageSequence + 1) ||
327*0e8cc8bdSWilliam Juul 				   tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
328*0e8cc8bdSWilliam Juul 				   ok = 0;
329*0e8cc8bdSWilliam Juul 
330*0e8cc8bdSWilliam Juul 				dev->checkpointByteOffset = 0;
331*0e8cc8bdSWilliam Juul 				dev->checkpointPageSequence++;
332*0e8cc8bdSWilliam Juul 				dev->checkpointCurrentChunk++;
333*0e8cc8bdSWilliam Juul 
334*0e8cc8bdSWilliam Juul 				if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
335*0e8cc8bdSWilliam Juul 					dev->checkpointCurrentBlock = -1;
336*0e8cc8bdSWilliam Juul 			}
337*0e8cc8bdSWilliam Juul 		}
338*0e8cc8bdSWilliam Juul 
339*0e8cc8bdSWilliam Juul 		if(ok){
340*0e8cc8bdSWilliam Juul 			*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
341*0e8cc8bdSWilliam Juul 			dev->checkpointSum += *dataBytes;
342*0e8cc8bdSWilliam Juul 			dev->checkpointXor ^= *dataBytes;
343*0e8cc8bdSWilliam Juul 			dev->checkpointByteOffset++;
344*0e8cc8bdSWilliam Juul 			i++;
345*0e8cc8bdSWilliam Juul 			dataBytes++;
346*0e8cc8bdSWilliam Juul 			dev->checkpointByteCount++;
347*0e8cc8bdSWilliam Juul 		}
348*0e8cc8bdSWilliam Juul 	}
349*0e8cc8bdSWilliam Juul 
350*0e8cc8bdSWilliam Juul 	return 	i;
351*0e8cc8bdSWilliam Juul }
352*0e8cc8bdSWilliam Juul 
353*0e8cc8bdSWilliam Juul int yaffs_CheckpointClose(yaffs_Device *dev)
354*0e8cc8bdSWilliam Juul {
355*0e8cc8bdSWilliam Juul 
356*0e8cc8bdSWilliam Juul 	if(dev->checkpointOpenForWrite){
357*0e8cc8bdSWilliam Juul 		if(dev->checkpointByteOffset != 0)
358*0e8cc8bdSWilliam Juul 			yaffs_CheckpointFlushBuffer(dev);
359*0e8cc8bdSWilliam Juul 	} else {
360*0e8cc8bdSWilliam Juul 		int i;
361*0e8cc8bdSWilliam Juul 		for(i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++){
362*0e8cc8bdSWilliam Juul 			yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,dev->checkpointBlockList[i]);
363*0e8cc8bdSWilliam Juul 			if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
364*0e8cc8bdSWilliam Juul 				bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
365*0e8cc8bdSWilliam Juul 			else {
366*0e8cc8bdSWilliam Juul 				// Todo this looks odd...
367*0e8cc8bdSWilliam Juul 			}
368*0e8cc8bdSWilliam Juul 		}
369*0e8cc8bdSWilliam Juul 		YFREE(dev->checkpointBlockList);
370*0e8cc8bdSWilliam Juul 		dev->checkpointBlockList = NULL;
371*0e8cc8bdSWilliam Juul 	}
372*0e8cc8bdSWilliam Juul 
373*0e8cc8bdSWilliam Juul 	dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
374*0e8cc8bdSWilliam Juul 	dev->nErasedBlocks -= dev->blocksInCheckpoint;
375*0e8cc8bdSWilliam Juul 
376*0e8cc8bdSWilliam Juul 
377*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
378*0e8cc8bdSWilliam Juul 			dev->checkpointByteCount));
379*0e8cc8bdSWilliam Juul 
380*0e8cc8bdSWilliam Juul 	if(dev->checkpointBuffer){
381*0e8cc8bdSWilliam Juul 		/* free the buffer */
382*0e8cc8bdSWilliam Juul 		YFREE(dev->checkpointBuffer);
383*0e8cc8bdSWilliam Juul 		dev->checkpointBuffer = NULL;
384*0e8cc8bdSWilliam Juul 		return 1;
385*0e8cc8bdSWilliam Juul 	}
386*0e8cc8bdSWilliam Juul 	else
387*0e8cc8bdSWilliam Juul 		return 0;
388*0e8cc8bdSWilliam Juul 
389*0e8cc8bdSWilliam Juul }
390*0e8cc8bdSWilliam Juul 
391*0e8cc8bdSWilliam Juul int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
392*0e8cc8bdSWilliam Juul {
393*0e8cc8bdSWilliam Juul 	/* Erase the first checksum block */
394*0e8cc8bdSWilliam Juul 
395*0e8cc8bdSWilliam Juul 	T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint invalidate"TENDSTR)));
396*0e8cc8bdSWilliam Juul 
397*0e8cc8bdSWilliam Juul 	if(!yaffs_CheckpointSpaceOk(dev))
398*0e8cc8bdSWilliam Juul 		return 0;
399*0e8cc8bdSWilliam Juul 
400*0e8cc8bdSWilliam Juul 	return yaffs_CheckpointErase(dev);
401*0e8cc8bdSWilliam Juul }
402*0e8cc8bdSWilliam Juul 
403*0e8cc8bdSWilliam Juul 
404*0e8cc8bdSWilliam Juul 
405