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