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_TagsUnion *tu)
 140{
 141        int result;
 142
 143        tu->asBytes[0] = sparePtr->tagByte0;
 144        tu->asBytes[1] = sparePtr->tagByte1;
 145        tu->asBytes[2] = sparePtr->tagByte2;
 146        tu->asBytes[3] = sparePtr->tagByte3;
 147        tu->asBytes[4] = sparePtr->tagByte4;
 148        tu->asBytes[5] = sparePtr->tagByte5;
 149        tu->asBytes[6] = sparePtr->tagByte6;
 150        tu->asBytes[7] = sparePtr->tagByte7;
 151
 152        result = yaffs_CheckECCOnTags(&tu->asTags);
 153        if (result > 0) {
 154                dev->tagsEccFixed++;
 155        } else if (result < 0) {
 156                dev->tagsEccUnfixed++;
 157        }
 158}
 159
 160static void yaffs_SpareInitialise(yaffs_Spare * spare)
 161{
 162        memset(spare, 0xFF, sizeof(yaffs_Spare));
 163}
 164
 165static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
 166                                  int chunkInNAND, const __u8 * data,
 167                                  yaffs_Spare * spare)
 168{
 169        if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
 170                T(YAFFS_TRACE_ERROR,
 171                  (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
 172                   chunkInNAND));
 173                return YAFFS_FAIL;
 174        }
 175
 176        dev->nPageWrites++;
 177        return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
 178}
 179
 180static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
 181                                   int chunkInNAND,
 182                                   __u8 * data,
 183                                   yaffs_Spare * spare,
 184                                   yaffs_ECCResult * eccResult,
 185                                   int doErrorCorrection)
 186{
 187        int retVal;
 188        yaffs_Spare localSpare;
 189
 190        dev->nPageReads++;
 191
 192        if (!spare && data) {
 193                /* If we don't have a real spare, then we use a local one. */
 194                /* Need this for the calculation of the ecc */
 195                spare = &localSpare;
 196        }
 197
 198        if (!dev->useNANDECC) {
 199                retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
 200                if (data && doErrorCorrection) {
 201                        /* Do ECC correction */
 202                        /* Todo handle any errors */
 203                        int eccResult1, eccResult2;
 204                        __u8 calcEcc[3];
 205
 206                        yaffs_ECCCalculate(data, calcEcc);
 207                        eccResult1 =
 208                            yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
 209                        yaffs_ECCCalculate(&data[256], calcEcc);
 210                        eccResult2 =
 211                            yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
 212
 213                        if (eccResult1 > 0) {
 214                                T(YAFFS_TRACE_ERROR,
 215                                  (TSTR
 216                                   ("**>>yaffs ecc error fix performed on chunk %d:0"
 217                                    TENDSTR), chunkInNAND));
 218                                dev->eccFixed++;
 219                        } else if (eccResult1 < 0) {
 220                                T(YAFFS_TRACE_ERROR,
 221                                  (TSTR
 222                                   ("**>>yaffs ecc error unfixed on chunk %d:0"
 223                                    TENDSTR), chunkInNAND));
 224                                dev->eccUnfixed++;
 225                        }
 226
 227                        if (eccResult2 > 0) {
 228                                T(YAFFS_TRACE_ERROR,
 229                                  (TSTR
 230                                   ("**>>yaffs ecc error fix performed on chunk %d:1"
 231                                    TENDSTR), chunkInNAND));
 232                                dev->eccFixed++;
 233                        } else if (eccResult2 < 0) {
 234                                T(YAFFS_TRACE_ERROR,
 235                                  (TSTR
 236                                   ("**>>yaffs ecc error unfixed on chunk %d:1"
 237                                    TENDSTR), chunkInNAND));
 238                                dev->eccUnfixed++;
 239                        }
 240
 241                        if (eccResult1 || eccResult2) {
 242                                /* We had a data problem on this page */
 243                                yaffs_HandleReadDataError(dev, chunkInNAND);
 244                        }
 245
 246                        if (eccResult1 < 0 || eccResult2 < 0)
 247                                *eccResult = YAFFS_ECC_RESULT_UNFIXED;
 248                        else if (eccResult1 > 0 || eccResult2 > 0)
 249                                *eccResult = YAFFS_ECC_RESULT_FIXED;
 250                        else
 251                                *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
 252                }
 253        } else {
 254                /* Must allocate enough memory for spare+2*sizeof(int) */
 255                /* for ecc results from device. */
 256                struct yaffs_NANDSpare nspare;
 257                retVal =
 258                    dev->readChunkFromNAND(dev, chunkInNAND, data,
 259                                           (yaffs_Spare *) & nspare);
 260                memcpy(spare, &nspare, sizeof(yaffs_Spare));
 261                if (data && doErrorCorrection) {
 262                        if (nspare.eccres1 > 0) {
 263                                T(YAFFS_TRACE_ERROR,
 264                                  (TSTR
 265                                   ("**>>mtd ecc error fix performed on chunk %d:0"
 266                                    TENDSTR), chunkInNAND));
 267                        } else if (nspare.eccres1 < 0) {
 268                                T(YAFFS_TRACE_ERROR,
 269                                  (TSTR
 270                                   ("**>>mtd ecc error unfixed on chunk %d:0"
 271                                    TENDSTR), chunkInNAND));
 272                        }
 273
 274                        if (nspare.eccres2 > 0) {
 275                                T(YAFFS_TRACE_ERROR,
 276                                  (TSTR
 277                                   ("**>>mtd ecc error fix performed on chunk %d:1"
 278                                    TENDSTR), chunkInNAND));
 279                        } else if (nspare.eccres2 < 0) {
 280                                T(YAFFS_TRACE_ERROR,
 281                                  (TSTR
 282                                   ("**>>mtd ecc error unfixed on chunk %d:1"
 283                                    TENDSTR), chunkInNAND));
 284                        }
 285
 286                        if (nspare.eccres1 || nspare.eccres2) {
 287                                /* We had a data problem on this page */
 288                                yaffs_HandleReadDataError(dev, chunkInNAND);
 289                        }
 290
 291                        if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
 292                                *eccResult = YAFFS_ECC_RESULT_UNFIXED;
 293                        else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
 294                                *eccResult = YAFFS_ECC_RESULT_FIXED;
 295                        else
 296                                *eccResult = YAFFS_ECC_RESULT_NO_ERROR;
 297
 298                }
 299        }
 300        return retVal;
 301}
 302
 303#ifdef NOTYET
 304static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
 305                                  int chunkInNAND)
 306{
 307
 308        static int init = 0;
 309        static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
 310        static __u8 data[YAFFS_BYTES_PER_CHUNK];
 311        /* Might as well always allocate the larger size for */
 312        /* dev->useNANDECC == true; */
 313        static __u8 spare[sizeof(struct yaffs_NANDSpare)];
 314
 315        dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
 316
 317        if (!init) {
 318                memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
 319                init = 1;
 320        }
 321
 322        if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
 323                return YAFFS_FAIL;
 324        if (memcmp(cmpbuf, spare, 16))
 325                return YAFFS_FAIL;
 326
 327        return YAFFS_OK;
 328
 329}
 330#endif
 331
 332/*
 333 * Functions for robustisizing
 334 */
 335
 336static void yaffs_HandleReadDataError(yaffs_Device * dev, int chunkInNAND)
 337{
 338        int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
 339
 340        /* Mark the block for retirement */
 341        yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
 342        T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
 343          (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
 344
 345        /* TODO:
 346         * Just do a garbage collection on the affected block
 347         * then retire the block
 348         * NB recursion
 349         */
 350}
 351
 352#ifdef NOTYET
 353static void yaffs_CheckWrittenBlock(yaffs_Device * dev, int chunkInNAND)
 354{
 355}
 356
 357static void yaffs_HandleWriteChunkOk(yaffs_Device * dev, int chunkInNAND,
 358                                     const __u8 * data,
 359                                     const yaffs_Spare * spare)
 360{
 361}
 362
 363static void yaffs_HandleUpdateChunk(yaffs_Device * dev, int chunkInNAND,
 364                                    const yaffs_Spare * spare)
 365{
 366}
 367
 368static void yaffs_HandleWriteChunkError(yaffs_Device * dev, int chunkInNAND)
 369{
 370        int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
 371
 372        /* Mark the block for retirement */
 373        yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
 374        /* Delete the chunk */
 375        yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
 376}
 377
 378static int yaffs_VerifyCompare(const __u8 * d0, const __u8 * d1,
 379                               const yaffs_Spare * s0, const yaffs_Spare * s1)
 380{
 381
 382        if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
 383            s0->tagByte0 != s1->tagByte0 ||
 384            s0->tagByte1 != s1->tagByte1 ||
 385            s0->tagByte2 != s1->tagByte2 ||
 386            s0->tagByte3 != s1->tagByte3 ||
 387            s0->tagByte4 != s1->tagByte4 ||
 388            s0->tagByte5 != s1->tagByte5 ||
 389            s0->tagByte6 != s1->tagByte6 ||
 390            s0->tagByte7 != s1->tagByte7 ||
 391            s0->ecc1[0] != s1->ecc1[0] ||
 392            s0->ecc1[1] != s1->ecc1[1] ||
 393            s0->ecc1[2] != s1->ecc1[2] ||
 394            s0->ecc2[0] != s1->ecc2[0] ||
 395            s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
 396                return 0;
 397        }
 398
 399        return 1;
 400}
 401#endif                          /* NOTYET */
 402
 403int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device * dev,
 404                                                    int chunkInNAND,
 405                                                    const __u8 * data,
 406                                                    const yaffs_ExtendedTags *
 407                                                    eTags)
 408{
 409        yaffs_Spare spare;
 410        yaffs_Tags tags;
 411
 412        yaffs_SpareInitialise(&spare);
 413
 414        if (eTags->chunkDeleted) {
 415                spare.pageStatus = 0;
 416        } else {
 417                tags.objectId = eTags->objectId;
 418                tags.chunkId = eTags->chunkId;
 419                tags.byteCount = eTags->byteCount;
 420                tags.serialNumber = eTags->serialNumber;
 421
 422                if (!dev->useNANDECC && data) {
 423                        yaffs_CalcECC(data, &spare);
 424                }
 425                yaffs_LoadTagsIntoSpare(&spare, &tags);
 426
 427        }
 428
 429        return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
 430}
 431
 432int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device * dev,
 433                                                     int chunkInNAND,
 434                                                     __u8 * data,
 435                                                     yaffs_ExtendedTags * eTags)
 436{
 437
 438        yaffs_Spare spare;
 439        yaffs_TagsUnion tags;
 440        yaffs_ECCResult eccResult;
 441
 442        static yaffs_Spare spareFF;
 443        static int init;
 444
 445        if (!init) {
 446                memset(&spareFF, 0xFF, sizeof(spareFF));
 447                init = 1;
 448        }
 449
 450        if (yaffs_ReadChunkFromNAND
 451            (dev, chunkInNAND, data, &spare, &eccResult, 1)) {
 452                /* eTags may be NULL */
 453                if (eTags) {
 454
 455                        int deleted =
 456                            (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
 457
 458                        eTags->chunkDeleted = deleted;
 459                        eTags->eccResult = eccResult;
 460                        eTags->blockBad = 0;    /* We're reading it */
 461                        /* therefore it is not a bad block */
 462                        eTags->chunkUsed =
 463                            (memcmp(&spareFF, &spare, sizeof(spareFF)) !=
 464                             0) ? 1 : 0;
 465
 466                        if (eTags->chunkUsed) {
 467                                yaffs_GetTagsFromSpare(dev, &spare, &tags);
 468
 469                                eTags->objectId = tags.asTags.objectId;
 470                                eTags->chunkId = tags.asTags.chunkId;
 471                                eTags->byteCount = tags.asTags.byteCount;
 472                                eTags->serialNumber = tags.asTags.serialNumber;
 473                        }
 474                }
 475
 476                return YAFFS_OK;
 477        } else {
 478                return YAFFS_FAIL;
 479        }
 480}
 481
 482int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
 483                                            int blockInNAND)
 484{
 485
 486        yaffs_Spare spare;
 487
 488        memset(&spare, 0xff, sizeof(yaffs_Spare));
 489
 490        spare.blockStatus = 'Y';
 491
 492        yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
 493                               &spare);
 494        yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
 495                               NULL, &spare);
 496
 497        return YAFFS_OK;
 498
 499}
 500
 501int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
 502                                          int blockNo, yaffs_BlockState *
 503                                          state,
 504                                          int *sequenceNumber)
 505{
 506
 507        yaffs_Spare spare0, spare1;
 508        static yaffs_Spare spareFF;
 509        static int init;
 510        yaffs_ECCResult dummy;
 511
 512        if (!init) {
 513                memset(&spareFF, 0xFF, sizeof(spareFF));
 514                init = 1;
 515        }
 516
 517        *sequenceNumber = 0;
 518
 519        yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
 520                                &spare0, &dummy, 1);
 521        yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
 522                                &spare1, &dummy, 1);
 523
 524        if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
 525                *state = YAFFS_BLOCK_STATE_DEAD;
 526        else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
 527                *state = YAFFS_BLOCK_STATE_EMPTY;
 528        else
 529                *state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
 530
 531        return YAFFS_OK;
 532}
 533