uboot/fs/yaffs2/yaffs_checkptrw.c
<<
>>
Prefs
   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
  14/* XXX U-BOOT XXX */
  15#include <common.h>
  16#include <malloc.h>
  17
  18const 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
  25static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
  26{
  27
  28        int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
  29
  30        T(YAFFS_TRACE_CHECKPOINT,
  31                (TSTR("checkpt blocks available = %d" TENDSTR),
  32                blocksAvailable));
  33
  34
  35        return (blocksAvailable <= 0) ? 0 : 1;
  36}
  37
  38
  39static int yaffs_CheckpointErase(yaffs_Device *dev)
  40{
  41
  42        int i;
  43
  44
  45        if(!dev->eraseBlockInNAND)
  46                return 0;
  47        T(YAFFS_TRACE_CHECKPOINT,(TSTR("checking blocks %d to %d"TENDSTR),
  48                dev->internalStartBlock,dev->internalEndBlock));
  49
  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        }
  65
  66        dev->blocksInCheckpoint = 0;
  67
  68        return 1;
  69}
  70
  71
  72static 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));
  79
  80        if(dev->checkpointNextBlock >= 0 &&
  81           dev->checkpointNextBlock <= dev->internalEndBlock &&
  82           blocksAvailable > 0){
  83
  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)));
  95
  96        dev->checkpointNextBlock = -1;
  97        dev->checkpointCurrentBlock = -1;
  98}
  99
 100static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
 101{
 102        int  i;
 103        yaffs_ExtendedTags tags;
 104
 105        T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: start:  blocks %d next %d" TENDSTR),
 106                dev->blocksInCheckpoint, dev->checkpointNextBlock));
 107
 108        if(dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
 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);
 114                        T(YAFFS_TRACE_CHECKPOINT,(TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
 115                                i, tags.objectId,tags.sequenceNumber,tags.eccResult));
 116
 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
 135int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
 136{
 137
 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;
 147
 148        if(!dev->checkpointBuffer)
 149                dev->checkpointBuffer = YMALLOC_DMA(dev->nDataBytesPerChunk);
 150        if(!dev->checkpointBuffer)
 151                return 0;
 152
 153
 154        dev->checkpointPageSequence = 0;
 155
 156        dev->checkpointOpenForWrite = forWriting;
 157
 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;
 164
 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);
 170
 171
 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        }
 184
 185        return 1;
 186}
 187
 188int 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
 196static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
 197{
 198
 199        int chunk;
 200        int realignedChunk;
 201
 202        yaffs_ExtendedTags tags;
 203
 204        if(dev->checkpointCurrentBlock < 0){
 205                yaffs_CheckpointFindNextErasedBlock(dev);
 206                dev->checkpointCurrentChunk = 0;
 207        }
 208
 209        if(dev->checkpointCurrentBlock < 0)
 210                return 0;
 211
 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        }
 224
 225        chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
 226
 227
 228        T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
 229                chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk,tags.objectId,tags.chunkId));
 230
 231        realignedChunk = chunk - dev->chunkOffset;
 232
 233        dev->writeChunkWithTagsToNAND(dev,realignedChunk,dev->checkpointBuffer,&tags);
 234        dev->checkpointByteOffset = 0;
 235        dev->checkpointPageSequence++;
 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);
 242
 243        return 1;
 244}
 245
 246
 247int yaffs_CheckpointWrite(yaffs_Device *dev,const void *data, int nBytes)
 248{
 249        int i=0;
 250        int ok = 1;
 251
 252
 253        __u8 * dataBytes = (__u8 *)data;
 254
 255
 256
 257        if(!dev->checkpointBuffer)
 258                return 0;
 259
 260        if(!dev->checkpointOpenForWrite)
 261                return -1;
 262
 263        while(i < nBytes && ok) {
 264
 265
 266
 267                dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes ;
 268                dev->checkpointSum += *dataBytes;
 269                dev->checkpointXor ^= *dataBytes;
 270
 271                dev->checkpointByteOffset++;
 272                i++;
 273                dataBytes++;
 274                dev->checkpointByteCount++;
 275
 276
 277                if(dev->checkpointByteOffset < 0 ||
 278                   dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
 279                        ok = yaffs_CheckpointFlushBuffer(dev);
 280
 281        }
 282
 283        return  i;
 284}
 285
 286int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
 287{
 288        int i=0;
 289        int ok = 1;
 290        yaffs_ExtendedTags tags;
 291
 292
 293        int chunk;
 294        int realignedChunk;
 295
 296        __u8 *dataBytes = (__u8 *)data;
 297
 298        if(!dev->checkpointBuffer)
 299                return 0;
 300
 301        if(dev->checkpointOpenForWrite)
 302                return -1;
 303
 304        while(i < nBytes && ok) {
 305
 306
 307                if(dev->checkpointByteOffset < 0 ||
 308                   dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
 309
 310                        if(dev->checkpointCurrentBlock < 0){
 311                                yaffs_CheckpointFindNextCheckpointBlock(dev);
 312                                dev->checkpointCurrentChunk = 0;
 313                        }
 314
 315                        if(dev->checkpointCurrentBlock < 0)
 316                                ok = 0;
 317                        else {
 318
 319                                chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock +
 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); */
 326                                dev->readChunkWithTagsFromNAND(dev, realignedChunk,
 327                                                               dev->checkpointBuffer,
 328                                                              &tags);
 329
 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++;
 337
 338                                if(dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
 339                                        dev->checkpointCurrentBlock = -1;
 340                        }
 341                }
 342
 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        }
 353
 354        return  i;
 355}
 356
 357int yaffs_CheckpointClose(yaffs_Device *dev)
 358{
 359
 360        if(dev->checkpointOpenForWrite){
 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
 380
 381        T(YAFFS_TRACE_CHECKPOINT,(TSTR("checkpoint byte count %d" TENDSTR),
 382                        dev->checkpointByteCount));
 383
 384        if(dev->checkpointBuffer){
 385                /* free the buffer */
 386                YFREE(dev->checkpointBuffer);
 387                dev->checkpointBuffer = NULL;
 388                return 1;
 389        }
 390        else
 391                return 0;
 392
 393}
 394
 395int 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}
 406