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