linux/drivers/mtd/nftlcore.c
<<
>>
Prefs
   1/* Linux driver for NAND Flash Translation Layer      */
   2/* (c) 1999 Machine Vision Holdings, Inc.             */
   3/* Author: David Woodhouse <dwmw2@infradead.org>      */
   4
   5/*
   6  The contents of this file are distributed under the GNU General
   7  Public License version 2. The author places no additional
   8  restrictions of any kind on it.
   9 */
  10
  11#define PRERELEASE
  12
  13#include <linux/kernel.h>
  14#include <linux/module.h>
  15#include <asm/errno.h>
  16#include <asm/io.h>
  17#include <asm/uaccess.h>
  18#include <linux/miscdevice.h>
  19#include <linux/delay.h>
  20#include <linux/slab.h>
  21#include <linux/init.h>
  22#include <linux/hdreg.h>
  23
  24#include <linux/kmod.h>
  25#include <linux/mtd/mtd.h>
  26#include <linux/mtd/nand.h>
  27#include <linux/mtd/nftl.h>
  28#include <linux/mtd/blktrans.h>
  29
  30/* maximum number of loops while examining next block, to have a
  31   chance to detect consistency problems (they should never happen
  32   because of the checks done in the mounting */
  33
  34#define MAX_LOOPS 10000
  35
  36
  37static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
  38{
  39        struct NFTLrecord *nftl;
  40        unsigned long temp;
  41
  42        if (mtd->type != MTD_NANDFLASH)
  43                return;
  44        /* OK, this is moderately ugly.  But probably safe.  Alternatives? */
  45        if (memcmp(mtd->name, "DiskOnChip", 10))
  46                return;
  47
  48        if (!mtd->block_isbad) {
  49                printk(KERN_ERR
  50"NFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
  51"Please use the new diskonchip driver under the NAND subsystem.\n");
  52                return;
  53        }
  54
  55        DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name);
  56
  57        nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
  58
  59        if (!nftl) {
  60                printk(KERN_WARNING "NFTL: out of memory for data structures\n");
  61                return;
  62        }
  63
  64        nftl->mbd.mtd = mtd;
  65        nftl->mbd.devnum = -1;
  66
  67        nftl->mbd.tr = tr;
  68
  69        if (NFTL_mount(nftl) < 0) {
  70                printk(KERN_WARNING "NFTL: could not mount device\n");
  71                kfree(nftl);
  72                return;
  73        }
  74
  75        /* OK, it's a new one. Set up all the data structures. */
  76
  77        /* Calculate geometry */
  78        nftl->cylinders = 1024;
  79        nftl->heads = 16;
  80
  81        temp = nftl->cylinders * nftl->heads;
  82        nftl->sectors = nftl->mbd.size / temp;
  83        if (nftl->mbd.size % temp) {
  84                nftl->sectors++;
  85                temp = nftl->cylinders * nftl->sectors;
  86                nftl->heads = nftl->mbd.size / temp;
  87
  88                if (nftl->mbd.size % temp) {
  89                        nftl->heads++;
  90                        temp = nftl->heads * nftl->sectors;
  91                        nftl->cylinders = nftl->mbd.size / temp;
  92                }
  93        }
  94
  95        if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
  96                /*
  97                  Oh no we don't have
  98                   mbd.size == heads * cylinders * sectors
  99                */
 100                printk(KERN_WARNING "NFTL: cannot calculate a geometry to "
 101                       "match size of 0x%lx.\n", nftl->mbd.size);
 102                printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d "
 103                        "(== 0x%lx sects)\n",
 104                        nftl->cylinders, nftl->heads , nftl->sectors,
 105                        (long)nftl->cylinders * (long)nftl->heads *
 106                        (long)nftl->sectors );
 107        }
 108
 109        if (add_mtd_blktrans_dev(&nftl->mbd)) {
 110                kfree(nftl->ReplUnitTable);
 111                kfree(nftl->EUNtable);
 112                kfree(nftl);
 113                return;
 114        }
 115#ifdef PSYCHO_DEBUG
 116        printk(KERN_INFO "NFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
 117#endif
 118}
 119
 120static void nftl_remove_dev(struct mtd_blktrans_dev *dev)
 121{
 122        struct NFTLrecord *nftl = (void *)dev;
 123
 124        DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum);
 125
 126        del_mtd_blktrans_dev(dev);
 127        kfree(nftl->ReplUnitTable);
 128        kfree(nftl->EUNtable);
 129        kfree(nftl);
 130}
 131
 132/*
 133 * Read oob data from flash
 134 */
 135int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
 136                  size_t *retlen, uint8_t *buf)
 137{
 138        struct mtd_oob_ops ops;
 139        int res;
 140
 141        ops.mode = MTD_OOB_PLACE;
 142        ops.ooboffs = offs & (mtd->writesize - 1);
 143        ops.ooblen = len;
 144        ops.oobbuf = buf;
 145        ops.datbuf = NULL;
 146
 147        res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
 148        *retlen = ops.oobretlen;
 149        return res;
 150}
 151
 152/*
 153 * Write oob data to flash
 154 */
 155int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
 156                   size_t *retlen, uint8_t *buf)
 157{
 158        struct mtd_oob_ops ops;
 159        int res;
 160
 161        ops.mode = MTD_OOB_PLACE;
 162        ops.ooboffs = offs & (mtd->writesize - 1);
 163        ops.ooblen = len;
 164        ops.oobbuf = buf;
 165        ops.datbuf = NULL;
 166
 167        res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
 168        *retlen = ops.oobretlen;
 169        return res;
 170}
 171
 172#ifdef CONFIG_NFTL_RW
 173
 174/*
 175 * Write data and oob to flash
 176 */
 177static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
 178                      size_t *retlen, uint8_t *buf, uint8_t *oob)
 179{
 180        struct mtd_oob_ops ops;
 181        int res;
 182
 183        ops.mode = MTD_OOB_PLACE;
 184        ops.ooboffs = offs;
 185        ops.ooblen = mtd->oobsize;
 186        ops.oobbuf = oob;
 187        ops.datbuf = buf;
 188        ops.len = len;
 189
 190        res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
 191        *retlen = ops.retlen;
 192        return res;
 193}
 194
 195/* Actual NFTL access routines */
 196/* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
 197 *      when the give Virtual Unit Chain
 198 */
 199static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
 200{
 201        /* For a given Virtual Unit Chain: find or create a free block and
 202           add it to the chain */
 203        /* We're passed the number of the last EUN in the chain, to save us from
 204           having to look it up again */
 205        u16 pot = nftl->LastFreeEUN;
 206        int silly = nftl->nb_blocks;
 207
 208        /* Normally, we force a fold to happen before we run out of free blocks completely */
 209        if (!desperate && nftl->numfreeEUNs < 2) {
 210                DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
 211                return 0xffff;
 212        }
 213
 214        /* Scan for a free block */
 215        do {
 216                if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
 217                        nftl->LastFreeEUN = pot;
 218                        nftl->numfreeEUNs--;
 219                        return pot;
 220                }
 221
 222                /* This will probably point to the MediaHdr unit itself,
 223                   right at the beginning of the partition. But that unit
 224                   (and the backup unit too) should have the UCI set
 225                   up so that it's not selected for overwriting */
 226                if (++pot > nftl->lastEUN)
 227                        pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);
 228
 229                if (!silly--) {
 230                        printk("Argh! No free blocks found! LastFreeEUN = %d, "
 231                               "FirstEUN = %d\n", nftl->LastFreeEUN,
 232                               le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
 233                        return 0xffff;
 234                }
 235        } while (pot != nftl->LastFreeEUN);
 236
 237        return 0xffff;
 238}
 239
 240static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
 241{
 242        struct mtd_info *mtd = nftl->mbd.mtd;
 243        u16 BlockMap[MAX_SECTORS_PER_UNIT];
 244        unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
 245        unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
 246        unsigned int thisEUN;
 247        int block;
 248        int silly;
 249        unsigned int targetEUN;
 250        struct nftl_oob oob;
 251        int inplace = 1;
 252        size_t retlen;
 253
 254        memset(BlockMap, 0xff, sizeof(BlockMap));
 255        memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
 256
 257        thisEUN = nftl->EUNtable[thisVUC];
 258
 259        if (thisEUN == BLOCK_NIL) {
 260                printk(KERN_WARNING "Trying to fold non-existent "
 261                       "Virtual Unit Chain %d!\n", thisVUC);
 262                return BLOCK_NIL;
 263        }
 264
 265        /* Scan to find the Erase Unit which holds the actual data for each
 266           512-byte block within the Chain.
 267        */
 268        silly = MAX_LOOPS;
 269        targetEUN = BLOCK_NIL;
 270        while (thisEUN <= nftl->lastEUN ) {
 271                unsigned int status, foldmark;
 272
 273                targetEUN = thisEUN;
 274                for (block = 0; block < nftl->EraseSize / 512; block ++) {
 275                        nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
 276                                      (block * 512), 16 , &retlen,
 277                                      (char *)&oob);
 278                        if (block == 2) {
 279                                foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
 280                                if (foldmark == FOLD_MARK_IN_PROGRESS) {
 281                                        DEBUG(MTD_DEBUG_LEVEL1,
 282                                              "Write Inhibited on EUN %d\n", thisEUN);
 283                                        inplace = 0;
 284                                } else {
 285                                        /* There's no other reason not to do inplace,
 286                                           except ones that come later. So we don't need
 287                                           to preserve inplace */
 288                                        inplace = 1;
 289                                }
 290                        }
 291                        status = oob.b.Status | oob.b.Status1;
 292                        BlockLastState[block] = status;
 293
 294                        switch(status) {
 295                        case SECTOR_FREE:
 296                                BlockFreeFound[block] = 1;
 297                                break;
 298
 299                        case SECTOR_USED:
 300                                if (!BlockFreeFound[block])
 301                                        BlockMap[block] = thisEUN;
 302                                else
 303                                        printk(KERN_WARNING
 304                                               "SECTOR_USED found after SECTOR_FREE "
 305                                               "in Virtual Unit Chain %d for block %d\n",
 306                                               thisVUC, block);
 307                                break;
 308                        case SECTOR_DELETED:
 309                                if (!BlockFreeFound[block])
 310                                        BlockMap[block] = BLOCK_NIL;
 311                                else
 312                                        printk(KERN_WARNING
 313                                               "SECTOR_DELETED found after SECTOR_FREE "
 314                                               "in Virtual Unit Chain %d for block %d\n",
 315                                               thisVUC, block);
 316                                break;
 317
 318                        case SECTOR_IGNORE:
 319                                break;
 320                        default:
 321                                printk("Unknown status for block %d in EUN %d: %x\n",
 322                                       block, thisEUN, status);
 323                        }
 324                }
 325
 326                if (!silly--) {
 327                        printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
 328                               thisVUC);
 329                        return BLOCK_NIL;
 330                }
 331
 332                thisEUN = nftl->ReplUnitTable[thisEUN];
 333        }
 334
 335        if (inplace) {
 336                /* We're being asked to be a fold-in-place. Check
 337                   that all blocks which actually have data associated
 338                   with them (i.e. BlockMap[block] != BLOCK_NIL) are
 339                   either already present or SECTOR_FREE in the target
 340                   block. If not, we're going to have to fold out-of-place
 341                   anyway.
 342                */
 343                for (block = 0; block < nftl->EraseSize / 512 ; block++) {
 344                        if (BlockLastState[block] != SECTOR_FREE &&
 345                            BlockMap[block] != BLOCK_NIL &&
 346                            BlockMap[block] != targetEUN) {
 347                                DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, "
 348                                      "block %d was %x lastEUN, "
 349                                      "and is in EUN %d (%s) %d\n",
 350                                      thisVUC, block, BlockLastState[block],
 351                                      BlockMap[block],
 352                                      BlockMap[block]== targetEUN ? "==" : "!=",
 353                                      targetEUN);
 354                                inplace = 0;
 355                                break;
 356                        }
 357                }
 358
 359                if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
 360                    pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
 361                    BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
 362                    SECTOR_FREE) {
 363                        DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. "
 364                              "Folding out of place.\n", targetEUN);
 365                        inplace = 0;
 366                }
 367        }
 368
 369        if (!inplace) {
 370                DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
 371                      "Trying out-of-place\n", thisVUC);
 372                /* We need to find a targetEUN to fold into. */
 373                targetEUN = NFTL_findfreeblock(nftl, 1);
 374                if (targetEUN == BLOCK_NIL) {
 375                        /* Ouch. Now we're screwed. We need to do a
 376                           fold-in-place of another chain to make room
 377                           for this one. We need a better way of selecting
 378                           which chain to fold, because makefreeblock will
 379                           only ask us to fold the same one again.
 380                        */
 381                        printk(KERN_WARNING
 382                               "NFTL_findfreeblock(desperate) returns 0xffff.\n");
 383                        return BLOCK_NIL;
 384                }
 385        } else {
 386                /* We put a fold mark in the chain we are folding only if we
 387               fold in place to help the mount check code. If we do not fold in
 388               place, it is possible to find the valid chain by selecting the
 389               longer one */
 390                oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
 391                oob.u.c.unused = 0xffffffff;
 392                nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8,
 393                               8, &retlen, (char *)&oob.u);
 394        }
 395
 396        /* OK. We now know the location of every block in the Virtual Unit Chain,
 397           and the Erase Unit into which we are supposed to be copying.
 398           Go for it.
 399        */
 400        DEBUG(MTD_DEBUG_LEVEL1,"Folding chain %d into unit %d\n", thisVUC, targetEUN);
 401        for (block = 0; block < nftl->EraseSize / 512 ; block++) {
 402                unsigned char movebuf[512];
 403                int ret;
 404
 405                /* If it's in the target EUN already, or if it's pending write, do nothing */
 406                if (BlockMap[block] == targetEUN ||
 407                    (pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) {
 408                        continue;
 409                }
 410
 411                /* copy only in non free block (free blocks can only
 412                   happen in case of media errors or deleted blocks) */
 413                if (BlockMap[block] == BLOCK_NIL)
 414                        continue;
 415
 416                ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
 417                                512, &retlen, movebuf);
 418                if (ret < 0 && ret != -EUCLEAN) {
 419                        ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block])
 420                                        + (block * 512), 512, &retlen,
 421                                        movebuf);
 422                        if (ret != -EIO)
 423                                printk("Error went away on retry.\n");
 424                }
 425                memset(&oob, 0xff, sizeof(struct nftl_oob));
 426                oob.b.Status = oob.b.Status1 = SECTOR_USED;
 427
 428                nftl_write(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) +
 429                           (block * 512), 512, &retlen, movebuf, (char *)&oob);
 430        }
 431
 432        /* add the header so that it is now a valid chain */
 433        oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
 434        oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
 435
 436        nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8,
 437                       8, &retlen, (char *)&oob.u);
 438
 439        /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
 440
 441        /* At this point, we have two different chains for this Virtual Unit, and no way to tell
 442           them apart. If we crash now, we get confused. However, both contain the same data, so we
 443           shouldn't actually lose data in this case. It's just that when we load up on a medium which
 444           has duplicate chains, we need to free one of the chains because it's not necessary any more.
 445        */
 446        thisEUN = nftl->EUNtable[thisVUC];
 447        DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
 448
 449        /* For each block in the old chain (except the targetEUN of course),
 450           free it and make it available for future use */
 451        while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
 452                unsigned int EUNtmp;
 453
 454                EUNtmp = nftl->ReplUnitTable[thisEUN];
 455
 456                if (NFTL_formatblock(nftl, thisEUN) < 0) {
 457                        /* could not erase : mark block as reserved
 458                         */
 459                        nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
 460                } else {
 461                        /* correctly erased : mark it as free */
 462                        nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
 463                        nftl->numfreeEUNs++;
 464                }
 465                thisEUN = EUNtmp;
 466        }
 467
 468        /* Make this the new start of chain for thisVUC */
 469        nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
 470        nftl->EUNtable[thisVUC] = targetEUN;
 471
 472        return targetEUN;
 473}
 474
 475static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
 476{
 477        /* This is the part that needs some cleverness applied.
 478           For now, I'm doing the minimum applicable to actually
 479           get the thing to work.
 480           Wear-levelling and other clever stuff needs to be implemented
 481           and we also need to do some assessment of the results when
 482           the system loses power half-way through the routine.
 483        */
 484        u16 LongestChain = 0;
 485        u16 ChainLength = 0, thislen;
 486        u16 chain, EUN;
 487
 488        for (chain = 0; chain < le32_to_cpu(nftl->MediaHdr.FormattedSize) / nftl->EraseSize; chain++) {
 489                EUN = nftl->EUNtable[chain];
 490                thislen = 0;
 491
 492                while (EUN <= nftl->lastEUN) {
 493                        thislen++;
 494                        //printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
 495                        EUN = nftl->ReplUnitTable[EUN] & 0x7fff;
 496                        if (thislen > 0xff00) {
 497                                printk("Endless loop in Virtual Chain %d: Unit %x\n",
 498                                       chain, EUN);
 499                        }
 500                        if (thislen > 0xff10) {
 501                                /* Actually, don't return failure. Just ignore this chain and
 502                                   get on with it. */
 503                                thislen = 0;
 504                                break;
 505                        }
 506                }
 507
 508                if (thislen > ChainLength) {
 509                        //printk("New longest chain is %d with length %d\n", chain, thislen);
 510                        ChainLength = thislen;
 511                        LongestChain = chain;
 512                }
 513        }
 514
 515        if (ChainLength < 2) {
 516                printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
 517                       "Failing request\n");
 518                return 0xffff;
 519        }
 520
 521        return NFTL_foldchain (nftl, LongestChain, pendingblock);
 522}
 523
 524/* NFTL_findwriteunit: Return the unit number into which we can write
 525                       for this block. Make it available if it isn't already
 526*/
 527static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
 528{
 529        u16 lastEUN;
 530        u16 thisVUC = block / (nftl->EraseSize / 512);
 531        struct mtd_info *mtd = nftl->mbd.mtd;
 532        unsigned int writeEUN;
 533        unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
 534        size_t retlen;
 535        int silly, silly2 = 3;
 536        struct nftl_oob oob;
 537
 538        do {
 539                /* Scan the media to find a unit in the VUC which has
 540                   a free space for the block in question.
 541                */
 542
 543                /* This condition catches the 0x[7f]fff cases, as well as
 544                   being a sanity check for past-end-of-media access
 545                */
 546                lastEUN = BLOCK_NIL;
 547                writeEUN = nftl->EUNtable[thisVUC];
 548                silly = MAX_LOOPS;
 549                while (writeEUN <= nftl->lastEUN) {
 550                        struct nftl_bci bci;
 551                        size_t retlen;
 552                        unsigned int status;
 553
 554                        lastEUN = writeEUN;
 555
 556                        nftl_read_oob(mtd,
 557                                      (writeEUN * nftl->EraseSize) + blockofs,
 558                                      8, &retlen, (char *)&bci);
 559
 560                        DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
 561                              block , writeEUN, le16_to_cpu(bci.Status));
 562
 563                        status = bci.Status | bci.Status1;
 564                        switch(status) {
 565                        case SECTOR_FREE:
 566                                return writeEUN;
 567
 568                        case SECTOR_DELETED:
 569                        case SECTOR_USED:
 570                        case SECTOR_IGNORE:
 571                                break;
 572                        default:
 573                                // Invalid block. Don't use it any more. Must implement.
 574                                break;
 575                        }
 576
 577                        if (!silly--) {
 578                                printk(KERN_WARNING
 579                                       "Infinite loop in Virtual Unit Chain 0x%x\n",
 580                                       thisVUC);
 581                                return 0xffff;
 582                        }
 583
 584                        /* Skip to next block in chain */
 585                        writeEUN = nftl->ReplUnitTable[writeEUN];
 586                }
 587
 588                /* OK. We didn't find one in the existing chain, or there
 589                   is no existing chain. */
 590
 591                /* Try to find an already-free block */
 592                writeEUN = NFTL_findfreeblock(nftl, 0);
 593
 594                if (writeEUN == BLOCK_NIL) {
 595                        /* That didn't work - there were no free blocks just
 596                           waiting to be picked up. We're going to have to fold
 597                           a chain to make room.
 598                        */
 599
 600                        /* First remember the start of this chain */
 601                        //u16 startEUN = nftl->EUNtable[thisVUC];
 602
 603                        //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
 604                        writeEUN = NFTL_makefreeblock(nftl, 0xffff);
 605
 606                        if (writeEUN == BLOCK_NIL) {
 607                                /* OK, we accept that the above comment is
 608                                   lying - there may have been free blocks
 609                                   last time we called NFTL_findfreeblock(),
 610                                   but they are reserved for when we're
 611                                   desperate. Well, now we're desperate.
 612                                */
 613                                DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC);
 614                                writeEUN = NFTL_findfreeblock(nftl, 1);
 615                        }
 616                        if (writeEUN == BLOCK_NIL) {
 617                                /* Ouch. This should never happen - we should
 618                                   always be able to make some room somehow.
 619                                   If we get here, we've allocated more storage
 620                                   space than actual media, or our makefreeblock
 621                                   routine is missing something.
 622                                */
 623                                printk(KERN_WARNING "Cannot make free space.\n");
 624                                return BLOCK_NIL;
 625                        }
 626                        //printk("Restarting scan\n");
 627                        lastEUN = BLOCK_NIL;
 628                        continue;
 629                }
 630
 631                /* We've found a free block. Insert it into the chain. */
 632
 633                if (lastEUN != BLOCK_NIL) {
 634                        thisVUC |= 0x8000; /* It's a replacement block */
 635                } else {
 636                        /* The first block in a new chain */
 637                        nftl->EUNtable[thisVUC] = writeEUN;
 638                }
 639
 640                /* set up the actual EUN we're writing into */
 641                /* Both in our cache... */
 642                nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
 643
 644                /* ... and on the flash itself */
 645                nftl_read_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
 646                              &retlen, (char *)&oob.u);
 647
 648                oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
 649
 650                nftl_write_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
 651                               &retlen, (char *)&oob.u);
 652
 653                /* we link the new block to the chain only after the
 654                   block is ready. It avoids the case where the chain
 655                   could point to a free block */
 656                if (lastEUN != BLOCK_NIL) {
 657                        /* Both in our cache... */
 658                        nftl->ReplUnitTable[lastEUN] = writeEUN;
 659                        /* ... and on the flash itself */
 660                        nftl_read_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
 661                                      8, &retlen, (char *)&oob.u);
 662
 663                        oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
 664                                = cpu_to_le16(writeEUN);
 665
 666                        nftl_write_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
 667                                       8, &retlen, (char *)&oob.u);
 668                }
 669
 670                return writeEUN;
 671
 672        } while (silly2--);
 673
 674        printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
 675               thisVUC);
 676        return 0xffff;
 677}
 678
 679static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
 680                           char *buffer)
 681{
 682        struct NFTLrecord *nftl = (void *)mbd;
 683        u16 writeEUN;
 684        unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
 685        size_t retlen;
 686        struct nftl_oob oob;
 687
 688        writeEUN = NFTL_findwriteunit(nftl, block);
 689
 690        if (writeEUN == BLOCK_NIL) {
 691                printk(KERN_WARNING
 692                       "NFTL_writeblock(): Cannot find block to write to\n");
 693                /* If we _still_ haven't got a block to use, we're screwed */
 694                return 1;
 695        }
 696
 697        memset(&oob, 0xff, sizeof(struct nftl_oob));
 698        oob.b.Status = oob.b.Status1 = SECTOR_USED;
 699
 700        nftl_write(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
 701                   512, &retlen, (char *)buffer, (char *)&oob);
 702        return 0;
 703}
 704#endif /* CONFIG_NFTL_RW */
 705
 706static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
 707                          char *buffer)
 708{
 709        struct NFTLrecord *nftl = (void *)mbd;
 710        struct mtd_info *mtd = nftl->mbd.mtd;
 711        u16 lastgoodEUN;
 712        u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
 713        unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
 714        unsigned int status;
 715        int silly = MAX_LOOPS;
 716        size_t retlen;
 717        struct nftl_bci bci;
 718
 719        lastgoodEUN = BLOCK_NIL;
 720
 721        if (thisEUN != BLOCK_NIL) {
 722                while (thisEUN < nftl->nb_blocks) {
 723                        if (nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
 724                                          blockofs, 8, &retlen,
 725                                          (char *)&bci) < 0)
 726                                status = SECTOR_IGNORE;
 727                        else
 728                                status = bci.Status | bci.Status1;
 729
 730                        switch (status) {
 731                        case SECTOR_FREE:
 732                                /* no modification of a sector should follow a free sector */
 733                                goto the_end;
 734                        case SECTOR_DELETED:
 735                                lastgoodEUN = BLOCK_NIL;
 736                                break;
 737                        case SECTOR_USED:
 738                                lastgoodEUN = thisEUN;
 739                                break;
 740                        case SECTOR_IGNORE:
 741                                break;
 742                        default:
 743                                printk("Unknown status for block %ld in EUN %d: %x\n",
 744                                       block, thisEUN, status);
 745                                break;
 746                        }
 747
 748                        if (!silly--) {
 749                                printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n",
 750                                       block / (nftl->EraseSize / 512));
 751                                return 1;
 752                        }
 753                        thisEUN = nftl->ReplUnitTable[thisEUN];
 754                }
 755        }
 756
 757 the_end:
 758        if (lastgoodEUN == BLOCK_NIL) {
 759                /* the requested block is not on the media, return all 0x00 */
 760                memset(buffer, 0, 512);
 761        } else {
 762                loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
 763                size_t retlen;
 764                int res = mtd->read(mtd, ptr, 512, &retlen, buffer);
 765
 766                if (res < 0 && res != -EUCLEAN)
 767                        return -EIO;
 768        }
 769        return 0;
 770}
 771
 772static int nftl_getgeo(struct mtd_blktrans_dev *dev,  struct hd_geometry *geo)
 773{
 774        struct NFTLrecord *nftl = (void *)dev;
 775
 776        geo->heads = nftl->heads;
 777        geo->sectors = nftl->sectors;
 778        geo->cylinders = nftl->cylinders;
 779
 780        return 0;
 781}
 782
 783/****************************************************************************
 784 *
 785 * Module stuff
 786 *
 787 ****************************************************************************/
 788
 789
 790static struct mtd_blktrans_ops nftl_tr = {
 791        .name           = "nftl",
 792        .major          = NFTL_MAJOR,
 793        .part_bits      = NFTL_PARTN_BITS,
 794        .blksize        = 512,
 795        .getgeo         = nftl_getgeo,
 796        .readsect       = nftl_readblock,
 797#ifdef CONFIG_NFTL_RW
 798        .writesect      = nftl_writeblock,
 799#endif
 800        .add_mtd        = nftl_add_mtd,
 801        .remove_dev     = nftl_remove_dev,
 802        .owner          = THIS_MODULE,
 803};
 804
 805static int __init init_nftl(void)
 806{
 807        return register_mtd_blktrans(&nftl_tr);
 808}
 809
 810static void __exit cleanup_nftl(void)
 811{
 812        deregister_mtd_blktrans(&nftl_tr);
 813}
 814
 815module_init(init_nftl);
 816module_exit(cleanup_nftl);
 817
 818MODULE_LICENSE("GPL");
 819MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
 820MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");
 821