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