uboot/fs/yaffs2/yaffs_tagscompat.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
  17#include "yaffs_guts.h"
  18#include "yaffs_tagscompat.h"
  19#include "yaffs_ecc.h"
  20
  21static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND);
  22#ifdef NOTYET
  23static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND);
  24static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
  25                                     const __u8 * data,
  26                                     const yaffs_Spare * spare);
  27static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
  28                                    const yaffs_Spare * spare);
  29static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND);
  30#endif
  31
  32static const char yaffs_countBitsTable[256] = {
  33        0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
  34        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  35        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  36        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  37        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  38        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  39        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  40        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  41        1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  42        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  43        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  44        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  45        2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  46        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  47        3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  48        4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
  49};
  50
  51int yaffs_CountBits(__u8 x)
  52{
  53        int retVal;
  54        retVal = yaffs_countBitsTable[x];
  55        return retVal;
  56}
  57
  58/********** Tags ECC calculations  *********/
  59
  60void yaffs_CalcECC(const __u8 * data, yaffs_Spare * spare)
  61{
  62        yaffs_ECCCalculate(data, spare->ecc1);
  63        yaffs_ECCCalculate(&data[256], spare->ecc2);
  64}
  65
  66void yaffs_CalcTagsECC(yaffs_Tags * tags)
  67{
  68        /* Calculate an ecc */
  69
  70        unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
  71        unsigned i, j;
  72        unsigned ecc = 0;
  73        unsigned bit = 0;
  74
  75        tags->ecc = 0;
  76
  77        for (i = 0; i < 8; i++) {
  78                for (j = 1; j & 0xff; j <<= 1) {
  79                        bit++;
  80                        if (b[i] & j) {
  81                                ecc ^= bit;
  82                        }
  83                }
  84        }
  85
  86        tags->ecc = ecc;
  87
  88}
  89
  90int yaffs_CheckECCOnTags(yaffs_Tags * tags)
  91{
  92        unsigned ecc = tags->ecc;
  93
  94        yaffs_CalcTagsECC(tags);
  95
  96        ecc ^= tags->ecc;
  97
  98        if (ecc && ecc <= 64) {
  99                /* TODO: Handle the failure better. Retire? */
 100                unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
 101
 102                ecc--;
 103
 104                b[ecc / 8] ^= (1 << (ecc & 7));
 105
 106                /* Now recvalc the ecc */
 107                yaffs_CalcTagsECC(tags);
 108
 109                return 1;       /* recovered error */
 110        } else if (ecc) {
 111                /* Wierd ecc failure value */
 112                /* TODO Need to do somethiong here */
 113                return -1;      /* unrecovered error */
 114        }
 115
 116        return 0;
 117}
 118
 119/********** Tags **********/
 120
 121static void yaffs_LoadTagsIntoSpare(yaffs_Spare * sparePtr,
 122                                    yaffs_Tags * tagsPtr)
 123{
 124        yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
 125
 126        yaffs_CalcTagsECC(tagsPtr);
 127
 128        sparePtr->tagByte0 = tu->asBytes[0];
 129        sparePtr->tagByte1 = tu->asBytes[1];
 130        sparePtr->tagByte2 = tu->asBytes[2];
 131        sparePtr->tagByte3 = tu->asBytes[3];
 132        sparePtr->tagByte4 = tu->asBytes[4];
 133        sparePtr->tagByte5 = tu->asBytes[5];
 134        sparePtr->tagByte6 = tu->asBytes[6];
 135        sparePtr->tagByte7 = tu->asBytes[7];
 136}
 137
 138static void yaffs_GetTagsFromSpare(yaffs_Device * dev, yaffs_Spare * sparePtr,
 139                                   yaffs_Tags * tagsPtr)
 140{
 141        yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
 142        int result;
 143
 144        tu->asBytes[0] = sparePtr->tagByte0;
 145        tu->asBytes[1] = sparePtr->tagByte1;
 146        tu->asBytes[2] = sparePtr->tagByte2;
 147        tu->asBytes[3] = sparePtr->tagByte3;
 148        tu->asBytes[4] = sparePtr->tagByte4;
 149        tu->asBytes[5] = sparePtr->tagByte5;
 150        tu->asBytes[6] = sparePtr->tagByte6;
 151        tu->asBytes[7] = sparePtr->tagByte7;
 152
 153        result = yaffs_CheckECCOnTags(tagsPtr);
 154        if (result > 0) {
 155                dev->tagsEccFixed++;
 156        } else if (result < 0) {
 157                dev->tagsEccUnfixed++;
 158        }
 159}
 160
 161static void yaffs_SpareInitialise(yaffs_Spare * spare)
 162{
 163        memset(spare, 0xFF, sizeof(yaffs_Spare));
 164}
 165
 166static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
 167                                  int chunkInNAND, const __u8 * data,
 168                                  yaffs_Spare * spare)
 169{
 170        if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
 171                T(YAFFS_TRACE_ERROR,
 172                  (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
 173                   chunkInNAND));
 174                return YAFFS_FAIL;
 175        }
 176
 177        dev->nPageWrites++;
 178        return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
 179}
 180
 181static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
 182                                   int chunkInNAND,
 183                                   __u8 * data,
 184                                   yaffs_Spare * spare,
 185                                   yaffs_ECCResult * eccResult,
 186                                   int doErrorCorrection)
 187{
 188        int retVal;
 189        yaffs_Spare localSpare;
 190
 191        dev->nPageReads++;
 192
 193        if (!spare && data) {
 194                /* If we don't have a real spare, then we use a local one. */
 195                /* Need this for the calculation of the ecc */
 196                spare = &localSpare;
 197        }
 198
 199        if (!dev->useNANDECC) {
 200                retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
 201                if (data && doErrorCorrection) {
 202                        /* Do ECC correction */
 203                        /* Todo handle any errors */
 204                        int eccResult1, eccResult2;
 205                        __u8 calcEcc[3];
 206
 207                        yaffs_ECCCalculate(data, calcEcc);
 208                        eccResult1 =
 209                            yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
 210                        yaffs_ECCCalculate(&data[256], calcEcc);
 211                        eccResult2 =
 212                            yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
 213
 214                        if (eccResult1 > 0) {
 215                                T(YAFFS_TRACE_ERROR,
 216                                  (TSTR
 217                                   ("**>>yaffs ecc error fix performed on chunk %d:0"
 218                                    TENDSTR), chunkInNAND));
 219                                dev->eccFixed++;
 220                        } else if (eccResult1 < 0) {
 221                                T(YAFFS_TRACE_ERROR,
 222                                  (TSTR
 223                                   ("**>>yaffs ecc error unfixed on chunk %d:0"
 224                                    TENDSTR), chunkInNAND));
 225                                dev->eccUnfixed++;
 226                        }
 227
 228                        if (eccResult2 > 0) {
 229                                T(YAFFS_TRACE_ERROR,
 230                                  (TSTR
 231                                   ("**>>yaffs ecc error fix performed on chunk %d:1"
 232                                    TENDSTR), chunkInNAND));
 233                                dev->eccFixed++;
 234                        } else if (eccResult2 < 0) {
 235                                T(YAFFS_TRACE_ERROR,
 236                                  (TSTR
 237                                   ("**>>yaffs ecc error unfixed on chunk %d:1"
 238                                    TENDSTR), chunkInNAND));
 239                                dev->eccUnfixed++;
 240                        }
 241
 242                        if (eccResult1 || eccResult2) {
 243                                /* We had a data problem on this page */
 244                                yaffs_HandleReadDataError(dev, chunkInNAND);
 245                        }
 246
 247                        if (eccResult1 < 0 || eccResult2 < 0)
 248                                *eccResult = YAFFS_ECC_RESULT_UNFIXED;
 249                        else if (eccResult1 > 0 || eccResult2 > 0)
 250                                *eccResult = YAFFS_ECC_RESULT_FIXED;
 251                        else
 252                                *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
 253                }
 254        } else {
 255                /* Must allocate enough memory for spare+2*sizeof(int) */
 256                /* for ecc results from device. */
 257                struct yaffs_NANDSpare nspare;
 258                retVal =
 259                    dev->readChunkFromNAND(dev, chunkInNAND, data,
 260                                           (yaffs_Spare *) & nspare);
 261                memcpy(spare, &nspare, sizeof(yaffs_Spare));
 262                if (data && doErrorCorrection) {
 263                        if (nspare.eccres1 > 0) {
 264                                T(YAFFS_TRACE_ERROR,
 265                                  (TSTR
 266                                   ("**>>mtd ecc error fix performed on chunk %d:0"
 267                                    TENDSTR), chunkInNAND));
 268                        } else if (nspare.eccres1 < 0) {
 269                                T(YAFFS_TRACE_ERROR,
 270                                  (TSTR
 271                                   ("**>>mtd ecc error unfixed on chunk %d:0"
 272                                    TENDSTR), chunkInNAND));
 273                        }
 274
 275                        if (nspare.eccres2 > 0) {
 276                                T(YAFFS_TRACE_ERROR,
 277                                  (TSTR
 278                                   ("**>>mtd ecc error fix performed on chunk %d:1"
 279                                    TENDSTR), chunkInNAND));
 280                        } else if (nspare.eccres2 < 0) {
 281                                T(YAFFS_TRACE_ERROR,
 282                                  (TSTR
 283                                   ("**>>mtd ecc error unfixed on chunk %d:1"
 284                                    TENDSTR), chunkInNAND));
 285                        }
 286
 287                        if (nspare.eccres1 || nspare.eccres2) {
 288                                /* We had a data problem on this page */
 289                                yaffs_HandleReadDataError(dev, chunkInNAND);
 290                        }
 291
 292                        if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
 293                                *eccResult = YAFFS_ECC_RESULT_UNFIXED;
 294                        else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
 295                                *eccResult = YAFFS_ECC_RESULT_FIXED;
 296                        else
 297                                *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
 298
 299                }
 300        }
 301        return retVal;
 302}
 303
 304#ifdef NOTYET
 305static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
 306                                  int chunkInNAND)
 307{
 308
 309        static int init = 0;
 310        static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
 311        static __u8 data[YAFFS_BYTES_PER_CHUNK];
 312        /* Might as well always allocate the larger size for */
 313        /* dev->useNANDECC == true; */
 314        static __u8 spare[sizeof(struct yaffs_NANDSpare)];
 315
 316        dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
 317
 318        if (!init) {
 319                memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
 320                init = 1;
 321        }
 322
 323        if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
 324                return YAFFS_FAIL;
 325        if (memcmp(cmpbuf, spare, 16))
 326                return YAFFS_FAIL;
 327
 328        return YAFFS_OK;
 329
 330}
 331#endif
 332
 333/*
 334 * Functions for robustisizing
 335 */
 336
 337static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND)
 338{
 339        int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
 340
 341        /* Mark the block for retirement */
 342        yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
 343        T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
 344          (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
 345
 346        /* TODO:
 347         * Just do a garbage collection on the affected block
 348         * then retire the block
 349         * NB recursion
 350         */
 351}
 352
 353#ifdef NOTYET
 354static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND)
 355{
 356}
 357
 358static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
 359                                     const __u8 * data,
 360                                     const yaffs_Spare * spare)
 361{
 362}
 363
 364static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
 365                                    const yaffs_Spare * spare)
 366{
 367}
 368
 369static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
 370{
 371        int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
 372
 373        /* Mark the block for retirement */
 374        yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
 375        /* Delete the chunk */
 376        yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
 377}
 378
 379static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1,
 380                               const yaffs_Spare * s0, const yaffs_Spare * s1)
 381{
 382
 383        if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
 384            s0->tagByte0 != s1->tagByte0 ||
 385            s0->tagByte1 != s1->tagByte1 ||
 386            s0->tagByte2 != s1->tagByte2 ||
 387            s0->tagByte3 != s1->tagByte3 ||
 388            s0->tagByte4 != s1->tagByte4 ||
 389            s0->tagByte5 != s1->tagByte5 ||
 390            s0->tagByte6 != s1->tagByte6 ||
 391            s0->tagByte7 != s1->tagByte7 ||
 392            s0->ecc1[0] != s1->ecc1[0] ||
 393            s0->ecc1[1] != s1->ecc1[1] ||
 394            s0->ecc1[2] != s1->ecc1[2] ||
 395            s0->ecc2[0] != s1->ecc2[0] ||
 396            s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
 397                return 0;
 398        }
 399
 400        return 1;
 401}
 402#endif                          /* NOTYET */
 403
 404int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
 405                                                    int chunkInNAND,
 406                                                    const __u8 * data,
 407                                                    const yaffs_ExtendedTags *
 408                                                    eTags)
 409{
 410        yaffs_Spare spare;
 411        yaffs_Tags tags;
 412
 413        yaffs_SpareInitialise(&spare);
 414
 415        if (eTags->chunkDeleted) {
 416                spare.pageStatus = 0;
 417        } else {
 418                tags.objectId = eTags->objectId;
 419                tags.chunkId = eTags->chunkId;
 420                tags.byteCount = eTags->byteCount;
 421                tags.serialNumber = eTags->serialNumber;
 422
 423                if (!dev->useNANDECC && data) {
 424                        yaffs_CalcECC(data, &spare);
 425                }
 426                yaffs_LoadTagsIntoSpare(&spare, &tags);
 427
 428        }
 429
 430        return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
 431}
 432
 433int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
 434                                                     int chunkInNAND,
 435                                                     __u8 * data,
 436                                                     yaffs_ExtendedTags * eTags)
 437{
 438
 439        yaffs_Spare spare;
 440        yaffs_Tags tags;
 441        yaffs_ECCResult eccResult;
 442
 443        static yaffs_Spare spareFF;
 444        static int init;
 445
 446        if (!init) {
 447                memset(&spareFF, 0xFF, sizeof(spareFF));
 448                init = 1;
 449        }
 450
 451        if (yaffs_ReadChunkFromNAND
 452            (dev, chunkInNAND, data, &spare, &eccResult, 1)) {
 453                /* eTags may be NULL */
 454                if (eTags) {
 455
 456                        int deleted =
 457                            (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
 458
 459                        eTags->chunkDeleted = deleted;
 460                        eTags->eccResult = eccResult;
 461                        eTags->blockBad = 0;    /* We're reading it */
 462                        /* therefore it is not a bad block */
 463                        eTags->chunkUsed =
 464                            (memcmp(&spareFF, &spare, sizeof(spareFF)) !=
 465                             0) ? 1 : 0;
 466
 467                        if (eTags->chunkUsed) {
 468                                yaffs_GetTagsFromSpare(dev, &spare, &tags);
 469
 470                                eTags->objectId = tags.objectId;
 471                                eTags->chunkId = tags.chunkId;
 472                                eTags->byteCount = tags.byteCount;
 473                                eTags->serialNumber = tags.serialNumber;
 474                        }
 475                }
 476
 477                return YAFFS_OK;
 478        } else {
 479                return YAFFS_FAIL;
 480        }
 481}
 482
 483int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
 484                                            int blockInNAND)
 485{
 486
 487        yaffs_Spare spare;
 488
 489        memset(&spare, 0xff, sizeof(yaffs_Spare));
 490
 491        spare.blockStatus = 'Y';
 492
 493        yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
 494                               &spare);
 495        yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
 496                               NULL, &spare);
 497
 498        return YAFFS_OK;
 499
 500}
 501
 502int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
 503                                          int blockNo, yaffs_BlockState *
 504                                          state,
 505                                          int *sequenceNumber)
 506{
 507
 508        yaffs_Spare spare0, spare1;
 509        static yaffs_Spare spareFF;
 510        static int init;
 511        yaffs_ECCResult dummy;
 512
 513        if (!init) {
 514                memset(&spareFF, 0xFF, sizeof(spareFF));
 515                init = 1;
 516        }
 517
 518        *sequenceNumber = 0;
 519
 520        yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
 521                                &spare0, &dummy, 1);
 522        yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
 523                                &spare1, &dummy, 1);
 524
 525        if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
 526                *state = YAFFS_BLOCK_STATE_DEAD;
 527        else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
 528                *state = YAFFS_BLOCK_STATE_EMPTY;
 529        else
 530                *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
 531
 532        return YAFFS_OK;
 533}
 534