1 /* Linux driver for NAND Flash Translation Layer      */
 
   2 /* (c) 1999 Machine Vision Holdings, Inc.             */
 
   3 /* Author: David Woodhouse <dwmw2@infradead.org>      */
 
   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.
 
  13 #include <linux/kernel.h>
 
  14 #include <linux/module.h>
 
  15 #include <asm/errno.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>
 
  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>
 
  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 */
 
  34 #define MAX_LOOPS 10000
 
  37 static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 
  39         struct NFTLrecord *nftl;
 
  42         if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX)
 
  44         /* OK, this is moderately ugly.  But probably safe.  Alternatives? */
 
  45         if (memcmp(mtd->name, "DiskOnChip", 10))
 
  48         if (!mtd->block_isbad) {
 
  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");
 
  55         DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name);
 
  57         nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
 
  60                 printk(KERN_WARNING "NFTL: out of memory for data structures\n");
 
  65         nftl->mbd.devnum = -1;
 
  69         if (NFTL_mount(nftl) < 0) {
 
  70                 printk(KERN_WARNING "NFTL: could not mount device\n");
 
  75         /* OK, it's a new one. Set up all the data structures. */
 
  77         /* Calculate geometry */
 
  78         nftl->cylinders = 1024;
 
  81         temp = nftl->cylinders * nftl->heads;
 
  82         nftl->sectors = nftl->mbd.size / temp;
 
  83         if (nftl->mbd.size % temp) {
 
  85                 temp = nftl->cylinders * nftl->sectors;
 
  86                 nftl->heads = nftl->mbd.size / temp;
 
  88                 if (nftl->mbd.size % temp) {
 
  90                         temp = nftl->heads * nftl->sectors;
 
  91                         nftl->cylinders = nftl->mbd.size / temp;
 
  95         if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) {
 
  98                    mbd.size == heads * cylinders * sectors
 
 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 );
 
 109         if (add_mtd_blktrans_dev(&nftl->mbd)) {
 
 110                 kfree(nftl->ReplUnitTable);
 
 111                 kfree(nftl->EUNtable);
 
 116         printk(KERN_INFO "NFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
 
 120 static void nftl_remove_dev(struct mtd_blktrans_dev *dev)
 
 122         struct NFTLrecord *nftl = (void *)dev;
 
 124         DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum);
 
 126         del_mtd_blktrans_dev(dev);
 
 127         kfree(nftl->ReplUnitTable);
 
 128         kfree(nftl->EUNtable);
 
 133  * Read oob data from flash
 
 135 int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
 
 136                   size_t *retlen, uint8_t *buf)
 
 138         struct mtd_oob_ops ops;
 
 141         ops.mode = MTD_OOB_PLACE;
 
 142         ops.ooboffs = offs & (mtd->writesize - 1);
 
 147         res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
 
 148         *retlen = ops.oobretlen;
 
 153  * Write oob data to flash
 
 155 int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
 
 156                    size_t *retlen, uint8_t *buf)
 
 158         struct mtd_oob_ops ops;
 
 161         ops.mode = MTD_OOB_PLACE;
 
 162         ops.ooboffs = offs & (mtd->writesize - 1);
 
 167         res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
 
 168         *retlen = ops.oobretlen;
 
 172 #ifdef CONFIG_NFTL_RW
 
 175  * Write data and oob to flash
 
 177 static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
 
 178                       size_t *retlen, uint8_t *buf, uint8_t *oob)
 
 180         struct mtd_oob_ops ops;
 
 183         ops.mode = MTD_OOB_PLACE;
 
 185         ops.ooblen = mtd->oobsize;
 
 190         res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
 
 191         *retlen = ops.retlen;
 
 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
 
 199 static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate )
 
 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;
 
 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");
 
 214         /* Scan for a free block */
 
 216                 if (nftl->ReplUnitTable[pot] == BLOCK_FREE) {
 
 217                         nftl->LastFreeEUN = pot;
 
 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);
 
 230                         printk("Argh! No free blocks found! LastFreeEUN = %d, "
 
 231                                "FirstEUN = %d\n", nftl->LastFreeEUN,
 
 232                                le16_to_cpu(nftl->MediaHdr.FirstPhysicalEUN));
 
 235         } while (pot != nftl->LastFreeEUN);
 
 240 static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned pendingblock )
 
 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;
 
 249         unsigned int targetEUN;
 
 254         memset(BlockMap, 0xff, sizeof(BlockMap));
 
 255         memset(BlockFreeFound, 0, sizeof(BlockFreeFound));
 
 257         thisEUN = nftl->EUNtable[thisVUC];
 
 259         if (thisEUN == BLOCK_NIL) {
 
 260                 printk(KERN_WARNING "Trying to fold non-existent "
 
 261                        "Virtual Unit Chain %d!\n", thisVUC);
 
 265         /* Scan to find the Erase Unit which holds the actual data for each
 
 266            512-byte block within the Chain.
 
 269         targetEUN = BLOCK_NIL;
 
 270         while (thisEUN <= nftl->lastEUN ) {
 
 271                 unsigned int status, foldmark;
 
 274                 for (block = 0; block < nftl->EraseSize / 512; block ++) {
 
 275                         nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
 
 276                                       (block * 512), 16 , &retlen,
 
 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);
 
 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 */
 
 291                         status = oob.b.Status | oob.b.Status1;
 
 292                         BlockLastState[block] = status;
 
 296                                 BlockFreeFound[block] = 1;
 
 300                                 if (!BlockFreeFound[block])
 
 301                                         BlockMap[block] = thisEUN;
 
 304                                                "SECTOR_USED found after SECTOR_FREE "
 
 305                                                "in Virtual Unit Chain %d for block %d\n",
 
 309                                 if (!BlockFreeFound[block])
 
 310                                         BlockMap[block] = BLOCK_NIL;
 
 313                                                "SECTOR_DELETED found after SECTOR_FREE "
 
 314                                                "in Virtual Unit Chain %d for block %d\n",
 
 321                                 printk("Unknown status for block %d in EUN %d: %x\n",
 
 322                                        block, thisEUN, status);
 
 327                         printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n",
 
 332                 thisEUN = nftl->ReplUnitTable[thisEUN];
 
 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
 
 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],
 
 352                                       BlockMap[block]== targetEUN ? "==" : "!=",
 
 359                 if (pendingblock >= (thisVUC * (nftl->EraseSize / 512)) &&
 
 360                     pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) &&
 
 361                     BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] !=
 
 363                         DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. "
 
 364                               "Folding out of place.\n", targetEUN);
 
 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.
 
 382                                "NFTL_findfreeblock(desperate) returns 0xffff.\n");
 
 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
 
 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);
 
 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.
 
 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];
 
 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))) {
 
 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)
 
 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,
 
 423                                 printk("Error went away on retry.\n");
 
 425                 memset(&oob, 0xff, sizeof(struct nftl_oob));
 
 426                 oob.b.Status = oob.b.Status1 = SECTOR_USED;
 
 428                 nftl_write(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) +
 
 429                            (block * 512), 512, &retlen, movebuf, (char *)&oob);
 
 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;
 
 436         nftl_write_oob(mtd, (nftl->EraseSize * targetEUN) + 8,
 
 437                        8, &retlen, (char *)&oob.u);
 
 439         /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */
 
 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.
 
 446         thisEUN = nftl->EUNtable[thisVUC];
 
 447         DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n");
 
 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) {
 
 454                 EUNtmp = nftl->ReplUnitTable[thisEUN];
 
 456                 if (NFTL_formatblock(nftl, thisEUN) < 0) {
 
 457                         /* could not erase : mark block as reserved
 
 459                         nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
 
 461                         /* correctly erased : mark it as free */
 
 462                         nftl->ReplUnitTable[thisEUN] = BLOCK_FREE;
 
 468         /* Make this the new start of chain for thisVUC */
 
 469         nftl->ReplUnitTable[targetEUN] = BLOCK_NIL;
 
 470         nftl->EUNtable[thisVUC] = targetEUN;
 
 475 static u16 NFTL_makefreeblock( struct NFTLrecord *nftl , unsigned pendingblock)
 
 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.
 
 484         u16 LongestChain = 0;
 
 485         u16 ChainLength = 0, thislen;
 
 488         for (chain = 0; chain < le32_to_cpu(nftl->MediaHdr.FormattedSize) / nftl->EraseSize; chain++) {
 
 489                 EUN = nftl->EUNtable[chain];
 
 492                 while (EUN <= nftl->lastEUN) {
 
 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",
 
 500                         if (thislen > 0xff10) {
 
 501                                 /* Actually, don't return failure. Just ignore this chain and
 
 508                 if (thislen > ChainLength) {
 
 509                         //printk("New longest chain is %d with length %d\n", chain, thislen);
 
 510                         ChainLength = thislen;
 
 511                         LongestChain = chain;
 
 515         if (ChainLength < 2) {
 
 516                 printk(KERN_WARNING "No Virtual Unit Chains available for folding. "
 
 517                        "Failing request\n");
 
 521         return NFTL_foldchain (nftl, LongestChain, pendingblock);
 
 524 /* NFTL_findwriteunit: Return the unit number into which we can write
 
 525                        for this block. Make it available if it isn't already
 
 527 static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block)
 
 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);
 
 535         int silly, silly2 = 3;
 
 539                 /* Scan the media to find a unit in the VUC which has
 
 540                    a free space for the block in question.
 
 543                 /* This condition catches the 0x[7f]fff cases, as well as
 
 544                    being a sanity check for past-end-of-media access
 
 547                 writeEUN = nftl->EUNtable[thisVUC];
 
 549                 while (writeEUN <= nftl->lastEUN) {
 
 557                                       (writeEUN * nftl->EraseSize) + blockofs,
 
 558                                       8, &retlen, (char *)&bci);
 
 560                         DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n",
 
 561                               block , writeEUN, le16_to_cpu(bci.Status));
 
 563                         status = bci.Status | bci.Status1;
 
 573                                 // Invalid block. Don't use it any more. Must implement.
 
 579                                        "Infinite loop in Virtual Unit Chain 0x%x\n",
 
 584                         /* Skip to next block in chain */
 
 585                         writeEUN = nftl->ReplUnitTable[writeEUN];
 
 588                 /* OK. We didn't find one in the existing chain, or there
 
 589                    is no existing chain. */
 
 591                 /* Try to find an already-free block */
 
 592                 writeEUN = NFTL_findfreeblock(nftl, 0);
 
 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.
 
 600                         /* First remember the start of this chain */
 
 601                         //u16 startEUN = nftl->EUNtable[thisVUC];
 
 603                         //printk("Write to VirtualUnitChain %d, calling makefreeblock()\n", thisVUC);
 
 604                         writeEUN = NFTL_makefreeblock(nftl, 0xffff);
 
 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.
 
 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);
 
 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.
 
 623                                 printk(KERN_WARNING "Cannot make free space.\n");
 
 626                         //printk("Restarting scan\n");
 
 631                 /* We've found a free block. Insert it into the chain. */
 
 633                 if (lastEUN != BLOCK_NIL) {
 
 634                         thisVUC |= 0x8000; /* It's a replacement block */
 
 636                         /* The first block in a new chain */
 
 637                         nftl->EUNtable[thisVUC] = writeEUN;
 
 640                 /* set up the actual EUN we're writing into */
 
 641                 /* Both in our cache... */
 
 642                 nftl->ReplUnitTable[writeEUN] = BLOCK_NIL;
 
 644                 /* ... and on the flash itself */
 
 645                 nftl_read_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
 
 646                               &retlen, (char *)&oob.u);
 
 648                 oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC);
 
 650                 nftl_write_oob(mtd, writeEUN * nftl->EraseSize + 8, 8,
 
 651                                &retlen, (char *)&oob.u);
 
 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);
 
 663                         oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum
 
 664                                 = cpu_to_le16(writeEUN);
 
 666                         nftl_write_oob(mtd, (lastEUN * nftl->EraseSize) + 8,
 
 667                                        8, &retlen, (char *)&oob.u);
 
 674         printk(KERN_WARNING "Error folding to make room for Virtual Unit Chain 0x%x\n",
 
 679 static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
 
 682         struct NFTLrecord *nftl = (void *)mbd;
 
 684         unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
 
 688         writeEUN = NFTL_findwriteunit(nftl, block);
 
 690         if (writeEUN == BLOCK_NIL) {
 
 692                        "NFTL_writeblock(): Cannot find block to write to\n");
 
 693                 /* If we _still_ haven't got a block to use, we're screwed */
 
 697         memset(&oob, 0xff, sizeof(struct nftl_oob));
 
 698         oob.b.Status = oob.b.Status1 = SECTOR_USED;
 
 700         nftl_write(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
 
 701                    512, &retlen, (char *)buffer, (char *)&oob);
 
 704 #endif /* CONFIG_NFTL_RW */
 
 706 static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
 
 709         struct NFTLrecord *nftl = (void *)mbd;
 
 710         struct mtd_info *mtd = nftl->mbd.mtd;
 
 712         u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)];
 
 713         unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
 
 715         int silly = MAX_LOOPS;
 
 719         lastgoodEUN = BLOCK_NIL;
 
 721         if (thisEUN != BLOCK_NIL) {
 
 722                 while (thisEUN < nftl->nb_blocks) {
 
 723                         if (nftl_read_oob(mtd, (thisEUN * nftl->EraseSize) +
 
 724                                           blockofs, 8, &retlen,
 
 726                                 status = SECTOR_IGNORE;
 
 728                                 status = bci.Status | bci.Status1;
 
 732                                 /* no modification of a sector should follow a free sector */
 
 735                                 lastgoodEUN = BLOCK_NIL;
 
 738                                 lastgoodEUN = thisEUN;
 
 743                                 printk("Unknown status for block %ld in EUN %d: %x\n",
 
 744                                        block, thisEUN, status);
 
 749                                 printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n",
 
 750                                        block / (nftl->EraseSize / 512));
 
 753                         thisEUN = nftl->ReplUnitTable[thisEUN];
 
 758         if (lastgoodEUN == BLOCK_NIL) {
 
 759                 /* the requested block is not on the media, return all 0x00 */
 
 760                 memset(buffer, 0, 512);
 
 762                 loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
 
 764                 int res = mtd->read(mtd, ptr, 512, &retlen, buffer);
 
 766                 if (res < 0 && res != -EUCLEAN)
 
 772 static int nftl_getgeo(struct mtd_blktrans_dev *dev,  struct hd_geometry *geo)
 
 774         struct NFTLrecord *nftl = (void *)dev;
 
 776         geo->heads = nftl->heads;
 
 777         geo->sectors = nftl->sectors;
 
 778         geo->cylinders = nftl->cylinders;
 
 783 /****************************************************************************
 
 787  ****************************************************************************/
 
 790 static struct mtd_blktrans_ops nftl_tr = {
 
 793         .part_bits      = NFTL_PARTN_BITS,
 
 795         .getgeo         = nftl_getgeo,
 
 796         .readsect       = nftl_readblock,
 
 797 #ifdef CONFIG_NFTL_RW
 
 798         .writesect      = nftl_writeblock,
 
 800         .add_mtd        = nftl_add_mtd,
 
 801         .remove_dev     = nftl_remove_dev,
 
 802         .owner          = THIS_MODULE,
 
 805 static int __init init_nftl(void)
 
 807         return register_mtd_blktrans(&nftl_tr);
 
 810 static void __exit cleanup_nftl(void)
 
 812         deregister_mtd_blktrans(&nftl_tr);
 
 815 module_init(init_nftl);
 
 816 module_exit(cleanup_nftl);
 
 818 MODULE_LICENSE("GPL");
 
 819 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al.");
 
 820 MODULE_DESCRIPTION("Support code for NAND Flash Translation Layer, used on M-Systems DiskOnChip 2000 and Millennium");