linux-old/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/* $Id: nftlcore.c,v 1.87 2002/09/13 14:35:33 dwmw2 Exp $ */
   5
   6/*
   7  The contents of this file are distributed under the GNU General
   8  Public License version 2. The author places no additional
   9  restrictions of any kind on it.
  10 */
  11
  12#define PRERELEASE
  13
  14#include <linux/config.h>
  15#include <linux/kernel.h>
  16#include <linux/module.h>
  17#include <asm/errno.h>
  18#include <asm/io.h>
  19#include <asm/uaccess.h>
  20#include <linux/miscdevice.h>
  21#include <linux/pci.h>
  22#include <linux/delay.h>
  23#include <linux/slab.h>
  24#include <linux/sched.h>
  25#include <linux/init.h>
  26#include <linux/blkpg.h>
  27
  28#ifdef CONFIG_KMOD
  29#include <linux/kmod.h>
  30#endif
  31#include <linux/mtd/mtd.h>
  32#include <linux/mtd/nand.h>
  33#include <linux/mtd/nftl.h>
  34#include <linux/mtd/compatmac.h>
  35
  36/* maximum number of loops while examining next block, to have a
  37   chance to detect consistency problems (they should never happen
  38   because of the checks done in the mounting */
  39
  40#define MAX_LOOPS 10000
  41
  42/* NFTL block device stuff */
  43#define MAJOR_NR NFTL_MAJOR
  44#define DEVICE_REQUEST nftl_request
  45#define DEVICE_OFF(device)
  46
  47
  48#include <linux/blk.h>
  49#include <linux/hdreg.h>
  50
  51/* Linux-specific block device functions */
  52
  53/* I _HATE_ the Linux block device setup more than anything else I've ever
  54 *  encountered, except ...
  55 */
  56
  57static int nftl_sizes[256];
  58static int nftl_blocksizes[256];
  59
  60/* .. for the Linux partition table handling. */
  61struct hd_struct part_table[256];
  62
  63#if LINUX_VERSION_CODE < 0x20328
  64static void dummy_init (struct gendisk *crap)
  65{}
  66#endif
  67
  68static struct gendisk nftl_gendisk = {
  69        major:          MAJOR_NR,
  70        major_name:     "nftl",
  71        minor_shift:    NFTL_PARTN_BITS,        /* Bits to shift to get real from partition */
  72        max_p:          (1<<NFTL_PARTN_BITS)-1, /* Number of partitions per real */
  73#if LINUX_VERSION_CODE < 0x20328
  74        max_nr:         MAX_NFTLS,      /* maximum number of real */
  75        init:           dummy_init,     /* init function */
  76#endif
  77        part:           part_table,     /* hd struct */
  78        sizes:          nftl_sizes,     /* block sizes */
  79};
  80
  81#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
  82#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
  83#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
  84#else
  85#define BLK_INC_USE_COUNT do {} while(0)
  86#define BLK_DEC_USE_COUNT do {} while(0)
  87#endif
  88
  89struct NFTLrecord *NFTLs[MAX_NFTLS];
  90
  91static void NFTL_setup(struct mtd_info *mtd)
  92{
  93        int i;
  94        struct NFTLrecord *nftl;
  95        unsigned long temp;
  96        int firstfree = -1;
  97
  98        DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n");
  99
 100        for (i = 0; i < MAX_NFTLS; i++) {
 101                if (!NFTLs[i] && firstfree == -1)
 102                        firstfree = i;
 103                else if (NFTLs[i] && NFTLs[i]->mtd == mtd) {
 104                        /* This is a Spare Media Header for an NFTL we've already found */
 105                        DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n");
 106                        return;
 107                }
 108        }
 109        if (firstfree == -1) {
 110                printk(KERN_WARNING "No more NFTL slot available\n");
 111                return;
 112        }
 113
 114        nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
 115        if (!nftl) {
 116                printk(KERN_WARNING "Out of memory for NFTL data structures\n");
 117                return;
 118        }
 119
 120        init_MUTEX(&nftl->mutex);
 121
 122        nftl->mtd = mtd;
 123
 124        if (NFTL_mount(nftl) < 0) {
 125                printk(KERN_WARNING "Could not mount NFTL device\n");
 126                kfree(nftl);
 127                return;
 128        }
 129
 130        /* OK, it's a new one. Set up all the data structures. */
 131#ifdef PSYCHO_DEBUG
 132        printk("Found new NFTL nftl%c\n", firstfree + 'a');
 133#endif
 134
 135        /* linux stuff */
 136        nftl->usecount = 0;
 137        nftl->cylinders = 1024;
 138        nftl->heads = 16;
 139
 140        temp = nftl->cylinders * nftl->heads;
 141        nftl->sectors = nftl->nr_sects / temp;
 142        if (nftl->nr_sects % temp) {
 143                nftl->sectors++;
 144                temp = nftl->cylinders * nftl->sectors;
 145                nftl->heads = nftl->nr_sects / temp;
 146
 147                if (nftl->nr_sects % temp) {
 148                        nftl->heads++;
 149                        temp = nftl->heads * nftl->sectors;
 150                        nftl->cylinders = nftl->nr_sects / temp;
 151                }
 152        }
 153
 154        if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) {
 155                printk(KERN_WARNING "Cannot calculate an NFTL geometry to "
 156                       "match size of 0x%x.\n", nftl->nr_sects);
 157                printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n", 
 158                       nftl->cylinders, nftl->heads , nftl->sectors, 
 159                       (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors );
 160
 161                /* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */
 162        }
 163        NFTLs[firstfree] = nftl;
 164        /* Finally, set up the block device sizes */
 165        nftl_sizes[firstfree * 16] = nftl->nr_sects;
 166        //nftl_blocksizes[firstfree*16] = 512;
 167        part_table[firstfree * 16].nr_sects = nftl->nr_sects;
 168
 169        nftl_gendisk.nr_real++;
 170
 171        /* partition check ... */
 172#if LINUX_VERSION_CODE < 0x20328
 173        resetup_one_dev(&nftl_gendisk, firstfree);
 174#else
 175        grok_partitions(&nftl_gendisk, firstfree, 1<<NFTL_PARTN_BITS, nftl->nr_sects);
 176#endif
 177}
 178
 179static void NFTL_unsetup(int i)
 180{
 181        struct NFTLrecord *nftl = NFTLs[i];
 182
 183        DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i);
 184        
 185        NFTLs[i] = NULL;
 186        
 187        if (nftl->ReplUnitTable)
 188                kfree(nftl->ReplUnitTable);
 189        if (nftl->EUNtable)
 190                kfree(nftl->EUNtable);
 191                      
 192        nftl_gendisk.nr_real--;
 193        kfree(nftl);
 194}
 195
 196/* Search the MTD device for NFTL partitions */
 197static void NFTL_notify_add(struct mtd_info *mtd)
 198{
 199        DEBUG(MTD_DEBUG_LEVEL1, "NFTL_notify_add for %s\n", mtd->name);
 200
 201        if (mtd) {
 202                if (!mtd->read_oob) {
 203                        /* If this MTD doesn't have out-of-band data,
 204                           then there's no point continuing */
 205                        DEBUG(MTD_DEBUG_LEVEL1, "No OOB data, quitting\n");
 206                        return;
 207                }
 208                DEBUG(MTD_DEBUG_LEVEL3, "mtd->read = %p, size = %d, erasesize = %d\n", 
 209                      mtd->read, mtd->size, mtd->erasesize);
 210
 211                NFTL_setup(mtd);
 212        }
 213}
 214
 215static void NFTL_notify_remove(struct mtd_info *mtd)
 216{
 217        int i;
 218
 219        for (i = 0; i < MAX_NFTLS; i++) {
 220                if (NFTLs[i] && NFTLs[i]->mtd == mtd)
 221                        NFTL_unsetup(i);
 222        }
 223}
 224
 225#ifdef CONFIG_NFTL_RW
 226
 227/* Actual NFTL access routines */
 228/* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
 229 *      when the give Virtual Unit Chain
 230 */
 231static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
 232{
 233        /* For a given Virtual Unit Chain: find or create a free block and
 234           add it to the chain */
 235        /* We're passed the number of the last EUN in the chain, to save us from
 236           having to look it up again */
 237        u16 pot = nftl->LastFreeEUN;
 238        int silly = nftl->nb_blocks;
 239
 240        /* Normally, we force a fold to happen before we run out of free blocks completely */
 241        if (!desperate && nftl->numfreeEUNs < 2) {
 242                DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n");
 243                return 0xffff;
 244        }
 245
 246        /* Scan for a free block */
 247        do {
 248                if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
 249                        nftl->LastFreeEUN = pot;
 250                        nftl->numfreeEUNs--;
 251                        return pot;
 252                }
 253
 254                /* This will probably point to the MediaHdr unit itself,
 255                   right at the beginning of the partition. But that unit
 256                   (and the backup unit too) should have the UCI set
 257                   up so that it's not selected for overwriting */
 258                if (++pot > nftl->lastEUN)
 259                        pot = le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN);
 260
 261                if (!silly--) {
 262                        printk("Argh! No free blocks found! LastFreeEUN = %d, "
 263                               "FirstEUN = %d\n", nftl->LastFreeEUN, 
 264                               le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
 265                        return 0xffff;
 266                }
 267        } while (pot != nftl->LastFreeEUN);
 268
 269        return 0xffff;
 270}
 271
 272static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
 273{
 274        u16 BlockMap[MAX_SECTORS_PER_UNIT];
 275        unsigned char BlockLastState[MAX_SECTORS_PER_UNIT];
 276        unsigned char BlockFreeFound[MAX_SECTORS_PER_UNIT];
 277        unsigned int thisEUN;
 278        int block;
 279        int silly;
 280        unsigned int targetEUN;
 281        struct nftl_oob oob;
 282        int inplace = 1;
 283        size_t retlen;
 284
 285        memset(BlockMap, 0xff, sizeof(BlockMap));
 286        memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
 287
 288        thisEUN = nftl->EUNtable[thisVUC];
 289
 290        if (thisEUN == BLOCK_NIL) {
 291                printk(KERN_WARNING "Trying to fold non-existent "
 292                       "Virtual Unit Chain %d!\n", thisVUC);
 293                return BLOCK_NIL;
 294        }
 295        
 296        /* Scan to find the Erase Unit which holds the actual data for each
 297           512-byte block within the Chain.
 298        */
 299        silly = MAX_LOOPS;
 300        targetEUN = BLOCK_NIL;
 301        while (thisEUN <= nftl->lastEUN ) {
 302                unsigned int status, foldmark;
 303
 304                targetEUN = thisEUN;
 305                for (block = 0; block < nftl->EraseSize / 512; block ++) {
 306                        MTD_READOOB(nftl->mtd,
 307                                    (thisEUN * nftl->EraseSize) + (block * 512),
 308                                    16 , &retlen, (char *)&oob);
 309                        if (block == 2) {
 310                                foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1;
 311                                if (foldmark == FOLD_MARK_IN_PROGRESS) {
 312                                        DEBUG(MTD_DEBUG_LEVEL1, 
 313                                              "Write Inhibited on EUN %d\n", thisEUN);
 314                                        inplace = 0;
 315                                } else {
 316                                        /* There's no other reason not to do inplace,
 317                                           except ones that come later. So we don't need
 318                                           to preserve inplace */
 319                                        inplace = 1;
 320                                }
 321                        }
 322                        status = oob.b.Status | oob.b.Status1;
 323                        BlockLastState[block] = status;
 324
 325                        switch(status) {
 326                        case SECTOR_FREE:
 327                                BlockFreeFound[block] = 1;
 328                                break;
 329
 330                        case SECTOR_USED:
 331                                if (!BlockFreeFound[block])
 332                                        BlockMap[block] = thisEUN;
 333                                else
 334                                        printk(KERN_WARNING 
 335                                               "SECTOR_USED found after SECTOR_FREE "
 336                                               "in Virtual Unit Chain %d for block %d\n",
 337                                               thisVUC, block);
 338                                break;
 339                        case SECTOR_DELETED:
 340                                if (!BlockFreeFound[block])
 341                                        BlockMap[block] = BLOCK_NIL;
 342                                else
 343                                        printk(KERN_WARNING 
 344                                               "SECTOR_DELETED found after SECTOR_FREE "
 345                                               "in Virtual Unit Chain %d for block %d\n",
 346                                               thisVUC, block);
 347                                break;
 348
 349                        case SECTOR_IGNORE:
 350                                break;
 351                        default:
 352                                printk("Unknown status for block %d in EUN %d: %x\n",
 353                                       block, thisEUN, status);
 354                        }
 355                }
 356
 357                if (!silly--) {
 358                        printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
 359                               thisVUC);
 360                        return BLOCK_NIL;
 361                }
 362                
 363                thisEUN = nftl->ReplUnitTable[thisEUN];
 364        }
 365
 366        if (inplace) {
 367                /* We're being asked to be a fold-in-place. Check
 368                   that all blocks which actually have data associated
 369                   with them (i.e. BlockMap[block] != BLOCK_NIL) are 
 370                   either already present or SECTOR_FREE in the target
 371                   block. If not, we're going to have to fold out-of-place
 372                   anyway.
 373                */
 374                for (block = 0; block < nftl->EraseSize / 512 ; block++) {
 375                        if (BlockLastState[block] != SECTOR_FREE &&
 376                            BlockMap[block] != BLOCK_NIL &&
 377                            BlockMap[block] != targetEUN) {
 378                                DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, "
 379                                      "block %d was %x lastEUN, "
 380                                      "and is in EUN %d (%s) %d\n",
 381                                      thisVUC, block, BlockLastState[block],
 382                                      BlockMap[block], 
 383                                      BlockMap[block]== targetEUN ? "==" : "!=",
 384                                      targetEUN);
 385                                inplace = 0;
 386                                break;
 387                        }
 388                }
 389
 390                if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
 391                    pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
 392                    BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
 393                    SECTOR_FREE) {
 394                        DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. "
 395                              "Folding out of place.\n", targetEUN);
 396                        inplace = 0;
 397                }
 398        }
 399        
 400        if (!inplace) {
 401                DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. "
 402                      "Trying out-of-place\n", thisVUC);
 403                /* We need to find a targetEUN to fold into. */
 404                targetEUN = NFTL_findfreeblock(nftl, 1);
 405                if (targetEUN == BLOCK_NIL) {
 406                        /* Ouch. Now we're screwed. We need to do a 
 407                           fold-in-place of another chain to make room
 408                           for this one. We need a better way of selecting
 409                           which chain to fold, because makefreeblock will 
 410                           only ask us to fold the same one again.
 411                        */
 412                        printk(KERN_WARNING
 413                               "NFTL_findfreeblock(desperate) returns 0xffff.\n");
 414                        return BLOCK_NIL;
 415                }
 416        } else {
 417            /* We put a fold mark in the chain we are folding only if
 418               we fold in place to help the mount check code. If we do
 419               not fold in place, it is possible to find the valid
 420               chain by selecting the longer one */
 421            oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS);
 422            oob.u.c.unused = 0xffffffff;
 423            MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, 
 424                         8, &retlen, (char *)&oob.u);
 425        }
 426
 427        /* OK. We now know the location of every block in the Virtual Unit Chain,
 428           and the Erase Unit into which we are supposed to be copying.
 429           Go for it.
 430        */
 431        DEBUG(MTD_DEBUG_LEVEL1,"Folding chain %d into unit %d\n", thisVUC, targetEUN);
 432        for (block = 0; block < nftl->EraseSize / 512 ; block++) {
 433                unsigned char movebuf[512];
 434                int ret;
 435
 436                /* If it's in the target EUN already, or if it's pending write, do nothing */
 437                if (BlockMap[block] == targetEUN ||
 438                    (pendingblock == (thisVUC * (nftl->EraseSize / 512) + block))) {
 439                        continue;
 440                }
 441
 442                /* copy only in non free block (free blocks can only
 443                   happen in case of media errors or deleted blocks) */
 444                if (BlockMap[block] == BLOCK_NIL)
 445                        continue;
 446                
 447                ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
 448                                  512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
 449                if (ret < 0) {
 450                    ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block])
 451                                      + (block * 512), 512, &retlen,
 452                                      movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
 453                    if (ret != -EIO) 
 454                        printk("Error went away on retry.\n");
 455                }
 456                MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512),
 457                             512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
 458        }
 459        
 460        /* add the header so that it is now a valid chain */
 461        oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum
 462                = cpu_to_le16(thisVUC);
 463        oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff;
 464        
 465        MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 8, 
 466                     8, &retlen, (char *)&oob.u);
 467
 468        /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
 469
 470        /* At this point, we have two different chains for this Virtual Unit, and no way to tell 
 471           them apart. If we crash now, we get confused. However, both contain the same data, so we
 472           shouldn't actually lose data in this case. It's just that when we load up on a medium which
 473           has duplicate chains, we need to free one of the chains because it's not necessary any more.
 474        */
 475        thisEUN = nftl->EUNtable[thisVUC];
 476        DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
 477
 478        /* For each block in the old chain (except the targetEUN of course), 
 479           free it and make it available for future use */
 480        while (thisEUN <= nftl->lastEUN && thisEUN != targetEUN) {
 481                unsigned int EUNtmp;
 482
 483                EUNtmp = nftl->ReplUnitTable[thisEUN];
 484
 485                if (NFTL_formatblock(nftl, thisEUN) < 0) {
 486                        /* could not erase : mark block as reserved
 487                         * FixMe: Update Bad Unit Table on disk
 488                         */
 489                        nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
 490                } else {
 491                        /* correctly erased : mark it as free */
 492                        nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
 493                        nftl->numfreeEUNs++;
 494                }
 495                thisEUN = EUNtmp;
 496        }
 497        
 498        /* Make this the new start of chain for thisVUC */
 499        nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
 500        nftl->EUNtable[thisVUC] = targetEUN;
 501
 502        return targetEUN;
 503}
 504
 505u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
 506{
 507        /* This is the part that needs some cleverness applied. 
 508           For now, I'm doing the minimum applicable to actually
 509           get the thing to work.
 510           Wear-levelling and other clever stuff needs to be implemented
 511           and we also need to do some assessment of the results when
 512           the system loses power half-way through the routine.
 513        */
 514        u16 LongestChain = 0;
 515        u16 ChainLength = 0, thislen;
 516        u16 chain, EUN;
 517
 518        for (chain = 0; chain < le32_to_cpu(nftl->MediaHdr.FormattedSize) / nftl->EraseSize; chain++) {
 519                EUN = nftl->EUNtable[chain];
 520                thislen = 0;
 521
 522                while (EUN <= nftl->lastEUN) {
 523                        thislen++;
 524                        //printk("VUC %d reaches len %d with EUN %d\n", chain, thislen, EUN);
 525                        EUN = nftl->ReplUnitTable[EUN] & 0x7fff;
 526                        if (thislen > 0xff00) {
 527                                printk("Endless loop in Virtual Chain %d: Unit %x\n",
 528                                       chain, EUN);
 529                        }
 530                        if (thislen > 0xff10) {
 531                                /* Actually, don't return failure. Just ignore this chain and
 532                                   get on with it. */
 533                                thislen = 0;
 534                                break;
 535                        }
 536                }
 537
 538                if (thislen > ChainLength) {
 539                        //printk("New longest chain is %d with length %d\n", chain, thislen);
 540                        ChainLength = thislen;
 541                        LongestChain = chain;
 542                }
 543        }
 544
 545        if (ChainLength < 2) {
 546                printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
 547                       "Failing request\n");
 548                return 0xffff;
 549        }
 550
 551        return NFTL_foldchain (nftl, LongestChain, pendingblock);
 552}
 553
 554/* NFTL_findwriteunit: Return the unit number into which we can write 
 555                       for this block. Make it available if it isn't already
 556*/
 557static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
 558{
 559        u16 lastEUN;
 560        u16 thisVUC = block / (nftl->EraseSize / 512);
 561        unsigned int writeEUN;
 562        unsigned long blockofs = (block * 512) & (nftl->EraseSize -1);
 563        size_t retlen;
 564        int silly, silly2 = 3;
 565        struct nftl_oob oob;
 566
 567        do {
 568                /* Scan the media to find a unit in the VUC which has
 569                   a free space for the block in question.
 570                */
 571
 572                /* This condition catches the 0x[7f]fff cases, as well as 
 573                   being a sanity check for past-end-of-media access
 574                */
 575                lastEUN = BLOCK_NIL;
 576                writeEUN = nftl->EUNtable[thisVUC];
 577                silly = MAX_LOOPS;
 578                while (writeEUN <= nftl->lastEUN) {
 579                        struct nftl_bci bci;
 580                        size_t retlen;
 581                        unsigned int status;
 582
 583                        lastEUN = writeEUN;
 584
 585                        MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
 586                                    8, &retlen, (char *)&bci);
 587                        
 588                        DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
 589                              block , writeEUN, le16_to_cpu(bci.Status));
 590
 591                        status = bci.Status | bci.Status1;
 592                        switch(status) {
 593                        case SECTOR_FREE:
 594                                return writeEUN;
 595
 596                        case SECTOR_DELETED:
 597                        case SECTOR_USED:
 598                        case SECTOR_IGNORE:
 599                                break;
 600                        default:
 601                                // Invalid block. Don't use it any more. Must implement.
 602                                break;                  
 603                        }
 604                        
 605                        if (!silly--) { 
 606                                printk(KERN_WARNING
 607                                       "Infinite loop in Virtual Unit Chain 0x%x\n",
 608                                       thisVUC);
 609                                return 0xffff;
 610                        }
 611
 612                        /* Skip to next block in chain */
 613                        writeEUN = nftl->ReplUnitTable[writeEUN];
 614                }
 615
 616                /* OK. We didn't find one in the existing chain, or there 
 617                   is no existing chain. */
 618
 619                /* Try to find an already-free block */
 620                writeEUN = NFTL_findfreeblock(nftl, 0);
 621
 622                if (writeEUN == BLOCK_NIL) {
 623                        /* That didn't work - there were no free blocks just
 624                           waiting to be picked up. We're going to have to fold
 625                           a chain to make room.
 626                        */
 627
 628                        /* First remember the start of this chain */
 629                        //u16 startEUN = nftl->EUNtable[thisVUC];
 630                        
 631                        //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
 632                        writeEUN = NFTL_makefreeblock(nftl, 0xffff);
 633
 634                        if (writeEUN == BLOCK_NIL) {
 635                                /* OK, we accept that the above comment is 
 636                                   lying - there may have been free blocks
 637                                   last time we called NFTL_findfreeblock(),
 638                                   but they are reserved for when we're
 639                                   desperate. Well, now we're desperate.
 640                                */
 641                                DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC);
 642                                writeEUN = NFTL_findfreeblock(nftl, 1);
 643                        }
 644                        if (writeEUN == BLOCK_NIL) {
 645                                /* Ouch. This should never happen - we should
 646                                   always be able to make some room somehow. 
 647                                   If we get here, we've allocated more storage 
 648                                   space than actual media, or our makefreeblock
 649                                   routine is missing something.
 650                                */
 651                                printk(KERN_WARNING "Cannot make free space.\n");
 652                                return BLOCK_NIL;
 653                        }                       
 654                        //printk("Restarting scan\n");
 655                        lastEUN = BLOCK_NIL;
 656                        continue;
 657                }
 658
 659                /* We've found a free block. Insert it into the chain. */
 660                
 661                if (lastEUN != BLOCK_NIL) {
 662                    thisVUC |= 0x8000; /* It's a replacement block */
 663                } else {
 664                    /* The first block in a new chain */
 665                    nftl->EUNtable[thisVUC] = writeEUN;
 666                }
 667
 668                /* set up the actual EUN we're writing into */
 669                /* Both in our cache... */
 670                nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
 671
 672                /* ... and on the flash itself */
 673                MTD_READOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
 674                            &retlen, (char *)&oob.u);
 675
 676                oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
 677
 678                MTD_WRITEOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8,
 679                             &retlen, (char *)&oob.u);
 680
 681                /* we link the new block to the chain only after the
 682                   block is ready. It avoids the case where the chain
 683                   could point to a free block */
 684                if (lastEUN != BLOCK_NIL) {
 685                        /* Both in our cache... */
 686                        nftl->ReplUnitTable[lastEUN] = writeEUN;
 687                        /* ... and on the flash itself */
 688                        MTD_READOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
 689                                    8, &retlen, (char *)&oob.u);
 690
 691                        oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
 692                                = cpu_to_le16(writeEUN);
 693
 694                        MTD_WRITEOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8,
 695                                     8, &retlen, (char *)&oob.u);
 696                }
 697
 698                return writeEUN;
 699
 700        } while (silly2--);
 701
 702        printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
 703               thisVUC);
 704        return 0xffff;
 705}
 706
 707static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
 708{
 709        u16 writeEUN;
 710        unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
 711        size_t retlen;
 712        u8 eccbuf[6];
 713
 714        writeEUN = NFTL_findwriteunit(nftl, block);
 715
 716        if (writeEUN == BLOCK_NIL) {
 717                printk(KERN_WARNING
 718                       "NFTL_writeblock(): Cannot find block to write to\n");
 719                /* If we _still_ haven't got a block to use, we're screwed */
 720                return 1;
 721        }
 722
 723        MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs,
 724                     512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP);
 725        /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
 726
 727        return 0;
 728}
 729#endif /* CONFIG_NFTL_RW */
 730
 731static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer)
 732{
 733        u16 lastgoodEUN;
 734        u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
 735        unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
 736        unsigned int status;
 737        int silly = MAX_LOOPS;
 738        size_t retlen;
 739        struct nftl_bci bci;
 740
 741        lastgoodEUN = BLOCK_NIL;
 742
 743        if (thisEUN != BLOCK_NIL) {
 744                while (thisEUN < nftl->nb_blocks) {
 745                        if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs,
 746                                        8, &retlen, (char *)&bci) < 0)
 747                                status = SECTOR_IGNORE;
 748                        else
 749                                status = bci.Status | bci.Status1;
 750
 751                        switch (status) {
 752                        case SECTOR_FREE:
 753                                /* no modification of a sector should follow a free sector */
 754                                goto the_end;
 755                        case SECTOR_DELETED:
 756                                lastgoodEUN = BLOCK_NIL;
 757                                break;
 758                        case SECTOR_USED:
 759                                lastgoodEUN = thisEUN;
 760                                break;
 761                        case SECTOR_IGNORE:
 762                                break;
 763                        default:
 764                                printk("Unknown status for block %d in EUN %d: %x\n",
 765                                       block, thisEUN, status);
 766                                break;
 767                        }
 768
 769                        if (!silly--) {
 770                                printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
 771                                       block / (nftl->EraseSize / 512));
 772                                return 1;
 773                        }
 774                        thisEUN = nftl->ReplUnitTable[thisEUN];
 775                }
 776        }
 777
 778 the_end:
 779        if (lastgoodEUN == BLOCK_NIL) {
 780                /* the requested block is not on the media, return all 0x00 */
 781                memset(buffer, 0, 512);
 782        } else {
 783                loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
 784                size_t retlen;
 785                u_char eccbuf[6];
 786                if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP))
 787                        return -EIO;
 788        }
 789        return 0;
 790}
 791
 792static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
 793{
 794        struct NFTLrecord *nftl;
 795        int p;
 796
 797        nftl = NFTLs[MINOR(inode->i_rdev) >> NFTL_PARTN_BITS];
 798
 799        if (!nftl) return -EINVAL;
 800
 801        switch (cmd) {
 802        case HDIO_GETGEO: {
 803                struct hd_geometry g;
 804
 805                g.heads = nftl->heads;
 806                g.sectors = nftl->sectors;
 807                g.cylinders = nftl->cylinders;
 808                g.start = part_table[MINOR(inode->i_rdev)].start_sect;
 809                return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
 810        }
 811        case BLKGETSIZE:   /* Return device size */
 812                return put_user(part_table[MINOR(inode->i_rdev)].nr_sects,
 813                                (unsigned long *) arg);
 814
 815#ifdef BLKGETSIZE64
 816        case BLKGETSIZE64:
 817                return put_user((u64)part_table[MINOR(inode->i_rdev)].nr_sects << 9,
 818                                (u64 *)arg);
 819#endif
 820
 821        case BLKFLSBUF:
 822                if (!capable(CAP_SYS_ADMIN)) return -EACCES;
 823                fsync_dev(inode->i_rdev);
 824                invalidate_buffers(inode->i_rdev);
 825                if (nftl->mtd->sync)
 826                        nftl->mtd->sync(nftl->mtd);
 827                return 0;
 828
 829        case BLKRRPART:
 830                if (!capable(CAP_SYS_ADMIN)) return -EACCES;
 831                if (nftl->usecount > 1) return -EBUSY;
 832                /* 
 833                 * We have to flush all buffers and invalidate caches,
 834                 * or we won't be able to re-use the partitions,
 835                 * if there was a change and we don't want to reboot
 836                 */
 837                p = (1<<NFTL_PARTN_BITS) - 1;
 838                while (p-- > 0) {
 839                        kdev_t devp = MKDEV(MAJOR(inode->i_dev), MINOR(inode->i_dev)+p);
 840                        if (part_table[p].nr_sects > 0)
 841                                invalidate_device (devp, 1);
 842
 843                        part_table[MINOR(inode->i_dev)+p].start_sect = 0;
 844                        part_table[MINOR(inode->i_dev)+p].nr_sects = 0;
 845                }
 846                
 847#if LINUX_VERSION_CODE < 0x20328
 848                resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS);
 849#else
 850                grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS,
 851                                1<<NFTL_PARTN_BITS, nftl->nr_sects);
 852#endif
 853                return 0;
 854
 855#if (LINUX_VERSION_CODE < 0x20303)              
 856        RO_IOCTLS(inode->i_rdev, arg);  /* ref. linux/blk.h */
 857#else
 858        case BLKROSET:
 859        case BLKROGET:
 860        case BLKSSZGET:
 861                return blk_ioctl(inode->i_rdev, cmd, arg);
 862#endif
 863
 864        default:
 865                return -EINVAL;
 866        }
 867}
 868
 869void nftl_request(RQFUNC_ARG)
 870{
 871        unsigned int dev, block, nsect;
 872        struct NFTLrecord *nftl;
 873        char *buffer;
 874        struct request *req;
 875        int res;
 876
 877        while (1) {
 878                INIT_REQUEST;   /* blk.h */
 879                req = CURRENT;
 880                
 881                /* We can do this because the generic code knows not to
 882                   touch the request at the head of the queue */
 883                spin_unlock_irq(&io_request_lock);
 884
 885                DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n");
 886                DEBUG(MTD_DEBUG_LEVEL3, "NFTL %s request, from sector 0x%04lx for 0x%04lx sectors\n",
 887                      (req->cmd == READ) ? "Read " : "Write",
 888                      req->sector, req->current_nr_sectors);
 889
 890                dev = MINOR(req->rq_dev);
 891                block = req->sector;
 892                nsect = req->current_nr_sectors;
 893                buffer = req->buffer;
 894                res = 1; /* succeed */
 895
 896                if (dev >= MAX_NFTLS * (1<<NFTL_PARTN_BITS)) {
 897                        /* there is no such partition */
 898                        printk("nftl: bad minor number: device = %s\n",
 899                               kdevname(req->rq_dev));
 900                        res = 0; /* fail */
 901                        goto repeat;
 902                }
 903                
 904                nftl = NFTLs[dev / (1<<NFTL_PARTN_BITS)];
 905                DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n");
 906                down(&nftl->mutex);
 907                DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n");
 908
 909                if (block + nsect > part_table[dev].nr_sects) {
 910                        /* access past the end of device */
 911                        printk("nftl%c%d: bad access: block = %d, count = %d\n",
 912                               (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect);
 913                        up(&nftl->mutex);
 914                        res = 0; /* fail */
 915                        goto repeat;
 916                }
 917                
 918                block += part_table[dev].start_sect;
 919                
 920                if (req->cmd == READ) {
 921                        DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x "
 922                              "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors);
 923        
 924                        for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
 925                                /* Read a single sector to req->buffer + (512 * i) */
 926                                if (NFTL_readblock(nftl, block, buffer)) {
 927                                        DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n");
 928                                        up(&nftl->mutex);
 929                                        res = 0;
 930                                        goto repeat;
 931                                }
 932                        }
 933
 934                        DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n");
 935                        up(&nftl->mutex);
 936                        goto repeat;
 937                } else if (req->cmd == WRITE) {
 938                        DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x "
 939                              "(req->nr_sectors == %lx)\n", nsect, block,
 940                              req->nr_sectors);
 941#ifdef CONFIG_NFTL_RW
 942                        for ( ; nsect > 0; nsect-- , block++, buffer += 512) {
 943                                /* Read a single sector to req->buffer + (512 * i) */
 944                                if (NFTL_writeblock(nftl, block, buffer)) {
 945                                        DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n");
 946                                        up(&nftl->mutex);
 947                                        res = 0;
 948                                        goto repeat;
 949                                }
 950                        }
 951                        DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n");
 952#else
 953                        res = 0; /* Writes always fail */
 954#endif /* CONFIG_NFTL_RW */
 955                        up(&nftl->mutex);
 956                        goto repeat;
 957                } else {
 958                        DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n");
 959                        up(&nftl->mutex);
 960                        res = 0;
 961                        goto repeat;
 962                }
 963        repeat: 
 964                DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res);
 965                spin_lock_irq(&io_request_lock);
 966                end_request(res);
 967        }
 968}
 969
 970static int nftl_open(struct inode *ip, struct file *fp)
 971{
 972        int nftlnum = MINOR(ip->i_rdev) >> NFTL_PARTN_BITS;
 973        struct NFTLrecord *thisNFTL;
 974        thisNFTL = NFTLs[nftlnum];
 975
 976        DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n");
 977
 978#ifdef CONFIG_KMOD
 979        if (!thisNFTL && nftlnum == 0) {
 980                request_module("docprobe");
 981                thisNFTL = NFTLs[nftlnum];
 982        }
 983#endif
 984        if (!thisNFTL) {
 985                DEBUG(MTD_DEBUG_LEVEL2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n", 
 986                      nftlnum, ip->i_rdev, ip, fp);
 987                return -ENODEV;
 988        }
 989
 990#ifndef CONFIG_NFTL_RW
 991        if (fp->f_mode & FMODE_WRITE)
 992                return -EROFS;
 993#endif /* !CONFIG_NFTL_RW */
 994
 995        thisNFTL->usecount++;
 996        BLK_INC_USE_COUNT;
 997        if (!get_mtd_device(thisNFTL->mtd, -1)) {
 998                BLK_DEC_USE_COUNT;
 999                return -ENXIO;
1000        }
1001
1002        return 0;
1003}
1004
1005static int nftl_release(struct inode *inode, struct file *fp)
1006{
1007        struct NFTLrecord *thisNFTL;
1008
1009        thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16];
1010
1011        DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n");
1012
1013        if (thisNFTL->mtd->sync)
1014                thisNFTL->mtd->sync(thisNFTL->mtd);
1015        thisNFTL->usecount--;
1016        BLK_DEC_USE_COUNT;
1017
1018        put_mtd_device(thisNFTL->mtd);
1019
1020        return 0;
1021}
1022#if LINUX_VERSION_CODE < 0x20326
1023static struct file_operations nftl_fops = {
1024        read:           block_read,
1025        write:          block_write,
1026        ioctl:          nftl_ioctl,
1027        open:           nftl_open,
1028        release:        nftl_release,
1029        fsync:          block_fsync,
1030};
1031#else
1032static struct block_device_operations nftl_fops = 
1033{
1034#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
1035        owner:          THIS_MODULE,
1036#endif
1037        open:           nftl_open,
1038        release:        nftl_release,
1039        ioctl:          nftl_ioctl
1040};
1041#endif
1042
1043
1044
1045/****************************************************************************
1046 *
1047 * Module stuff
1048 *
1049 ****************************************************************************/
1050
1051static struct mtd_notifier nftl_notifier = {
1052        add:    NFTL_notify_add,
1053        remove: NFTL_notify_remove
1054};
1055
1056extern char nftlmountrev[];
1057
1058int __init init_nftl(void)
1059{
1060        int i;
1061
1062#ifdef PRERELEASE 
1063        printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.87 $, nftlmount.c %s\n", nftlmountrev);
1064#endif
1065
1066        if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){
1067                printk("unable to register NFTL block device on major %d\n", MAJOR_NR);
1068                return -EBUSY;
1069        } else {
1070                blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request);
1071
1072                /* set block size to 1kB each */
1073                for (i = 0; i < 256; i++) {
1074                        nftl_blocksizes[i] = 1024;
1075                }
1076                blksize_size[MAJOR_NR] = nftl_blocksizes;
1077
1078                add_gendisk(&nftl_gendisk);
1079        }
1080        
1081        register_mtd_user(&nftl_notifier);
1082
1083        return 0;
1084}
1085
1086static void __exit cleanup_nftl(void)
1087{
1088        unregister_mtd_user(&nftl_notifier);
1089        unregister_blkdev(MAJOR_NR, "nftl");
1090        
1091        blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
1092
1093        del_gendisk(&nftl_gendisk);
1094}
1095
1096module_init(init_nftl);
1097module_exit(cleanup_nftl);
1098
1099MODULE_LICENSE("GPL");
1100MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
1101MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");
1102