Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / mtd / inftlcore.c
index 2417fba..a3b9247 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL)
  *
  * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
@@ -7,7 +7,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * Author: David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: inftlcore.c,v 1.14 2003/06/26 08:28:26 dwmw2 Exp $
+ * $Id: inftlcore.c,v 1.19 2005/11/07 11:14:20 gleixner Exp $
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  */
 #define MAX_LOOPS 10000
 
-extern void INFTL_dumptables(struct INFTLrecord *inftl);
-extern void INFTL_dumpVUchains(struct INFTLrecord *inftl);
-
 static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 {
        struct INFTLrecord *inftl;
        unsigned long temp;
 
-       if (mtd->ecctype != MTD_ECC_RS_DiskOnChip)
+       if (mtd->type != MTD_NANDFLASH)
+               return;
+       /* OK, this is moderately ugly.  But probably safe.  Alternatives? */
+       if (memcmp(mtd->name, "DiskOnChip", 10))
+               return;
+
+       if (!mtd->block_isbad) {
+               printk(KERN_ERR
+"INFTL no longer supports the old DiskOnChip drivers loaded via docprobe.\n"
+"Please use the new diskonchip driver under the NAND subsystem.\n");
                return;
+       }
 
        DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name);
 
@@ -72,6 +79,8 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
        inftl->mbd.devnum = -1;
        inftl->mbd.blksize = 512;
        inftl->mbd.tr = tr;
+       memcpy(&inftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
+       inftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
 
         if (INFTL_mount(inftl) < 0) {
                printk(KERN_WARNING "INFTL: could not mount device\n");
@@ -101,28 +110,26 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
 
        if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) {
                /*
-                 Oh no we don't have 
+                 Oh no we don't have
                   mbd.size == heads * cylinders * sectors
                */
                printk(KERN_WARNING "INFTL: cannot calculate a geometry to "
                       "match size of 0x%lx.\n", inftl->mbd.size);
                printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d "
                        "(== 0x%lx sects)\n",
-                       inftl->cylinders, inftl->heads , inftl->sectors, 
+                       inftl->cylinders, inftl->heads , inftl->sectors,
                        (long)inftl->cylinders * (long)inftl->heads *
                        (long)inftl->sectors );
        }
 
        if (add_mtd_blktrans_dev(&inftl->mbd)) {
-               if (inftl->PUtable)
-                       kfree(inftl->PUtable);
-               if (inftl->VUtable)
-                       kfree(inftl->VUtable);
+               kfree(inftl->PUtable);
+               kfree(inftl->VUtable);
                kfree(inftl);
                return;
        }
 #ifdef PSYCHO_DEBUG
-       printk(KERN_INFO "INFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a');
+       printk(KERN_INFO "INFTL: Found new inftl%c\n", inftl->mbd.devnum + 'a');
 #endif
        return;
 }
@@ -135,10 +142,8 @@ static void inftl_remove_dev(struct mtd_blktrans_dev *dev)
 
        del_mtd_blktrans_dev(dev);
 
-       if (inftl->PUtable)
-               kfree(inftl->PUtable);
-       if (inftl->VUtable)
-               kfree(inftl->VUtable);
+       kfree(inftl->PUtable);
+       kfree(inftl->VUtable);
        kfree(inftl);
 }
 
@@ -155,8 +160,8 @@ static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate)
        u16 pot = inftl->LastFreeEUN;
        int silly = inftl->nb_blocks;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=0x%x,"
-               "desperate=%d)\n", (int)inftl, desperate);
+       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=%p,"
+               "desperate=%d)\n", inftl, desperate);
 
        /*
         * Normally, we force a fold to happen before we run out of free
@@ -198,8 +203,8 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
        struct inftl_oob oob;
         size_t retlen;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=0x%x,thisVUC=%d,"
-               "pending=%d)\n", (int)inftl, thisVUC, pendingblock);
+       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d,"
+               "pending=%d)\n", inftl, thisVUC, pendingblock);
 
        memset(BlockMap, 0xff, sizeof(BlockMap));
        memset(BlockDeleted, 0, sizeof(BlockDeleted));
@@ -211,7 +216,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
                       "Virtual Unit Chain %d!\n", thisVUC);
                return BLOCK_NIL;
        }
-       
+
        /*
         * Scan to find the Erase Unit which holds the actual data for each
         * 512-byte block within the Chain.
@@ -252,7 +257,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
                                "Unit Chain 0x%x\n", thisVUC);
                        return BLOCK_NIL;
                }
-               
+
                thisEUN = inftl->PUtable[thisEUN];
        }
 
@@ -283,22 +288,23 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
                 */
                 if (BlockMap[block] == BLOCK_NIL)
                         continue;
-                
-                ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize *
+
+                ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
                        BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE,
-                       &retlen, movebuf, (char *)&oob, NULL); 
+                       &retlen, movebuf);
                 if (ret < 0) {
-                       ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize *
+                       ret = MTD_READ(inftl->mbd.mtd, (inftl->EraseSize *
                                BlockMap[block]) + (block * SECTORSIZE),
-                               SECTORSIZE, &retlen, movebuf, (char *)&oob,
-                               NULL); 
-                       if (ret != -EIO) 
+                               SECTORSIZE, &retlen, movebuf);
+                       if (ret != -EIO)
                                DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went "
                                        "away on retry?\n");
                 }
+                memset(&oob, 0xff, sizeof(struct inftl_oob));
+                oob.b.Status = oob.b.Status1 = SECTOR_USED;
                 MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) +
                        (block * SECTORSIZE), SECTORSIZE, &retlen,
-                       movebuf, (char *)&oob, NULL);
+                       movebuf, (char *)&oob, &inftl->oobinfo);
        }
 
        /*
@@ -326,7 +332,6 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
                 if (INFTL_formatblock(inftl, thisEUN) < 0) {
                        /*
                         * Could not erase : mark block as reserved.
-                        * FixMe: Update Bad Unit Table on disk.
                         */
                        inftl->PUtable[thisEUN] = BLOCK_RESERVED;
                 } else {
@@ -340,10 +345,10 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned
        return targetEUN;
 }
 
-u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock)
+static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock)
 {
        /*
-        * This is the part that needs some cleverness applied. 
+        * This is the part that needs some cleverness applied.
         * For now, I'm doing the minimum applicable to actually
         * get the thing to work.
         * Wear-levelling and other clever stuff needs to be implemented
@@ -354,8 +359,8 @@ u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock)
        u16 ChainLength = 0, thislen;
        u16 chain, EUN;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=0x%x,"
-               "pending=%d)\n", (int)inftl, pendingblock);
+       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=%p,"
+               "pending=%d)\n", inftl, pendingblock);
 
        for (chain = 0; chain < inftl->nb_blocks; chain++) {
                EUN = inftl->VUtable[chain];
@@ -402,7 +407,7 @@ static int nrbits(unsigned int val, int bitcount)
 }
 
 /*
- * INFTL_findwriteunit: Return the unit number into which we can write 
+ * INFTL_findwriteunit: Return the unit number into which we can write
  *                      for this block. Make it available if it isn't already.
  */
 static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
@@ -416,8 +421,8 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
        size_t retlen;
        int silly, silly2 = 3;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=0x%x,"
-               "block=%d)\n", (int)inftl, block);
+       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=%p,"
+               "block=%d)\n", inftl, block);
 
        do {
                /*
@@ -451,10 +456,10 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block)
                                 * Invalid block. Don't use it any more.
                                 * Must implement.
                                 */
-                               break;                  
+                               break;
                        }
-                       
-                       if (!silly--) { 
+
+                       if (!silly--) {
                                printk(KERN_WARNING "INFTL: infinite loop in "
                                        "Virtual Unit Chain 0x%x\n", thisVUC);
                                return 0xffff;
@@ -470,7 +475,7 @@ hitused:
 
 
                /*
-                * OK. We didn't find one in the existing chain, or there 
+                * OK. We didn't find one in the existing chain, or there
                 * is no existing chain. Allocate a new one.
                 */
                writeEUN = INFTL_findfreeblock(inftl, 0);
@@ -494,8 +499,8 @@ hitused:
                        if (writeEUN == BLOCK_NIL) {
                                /*
                                 * Ouch. This should never happen - we should
-                                * always be able to make some room somehow. 
-                                * If we get here, we've allocated more storage 
+                                * always be able to make some room somehow.
+                                * If we get here, we've allocated more storage
                                 * space than actual media, or our makefreeblock
                                 * routine is missing something.
                                 */
@@ -506,7 +511,7 @@ hitused:
                                INFTL_dumpVUchains(inftl);
 #endif
                                return BLOCK_NIL;
-                       }                       
+                       }
                }
 
                /*
@@ -531,7 +536,7 @@ hitused:
                parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0;
                parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0;
                parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0;
+
                oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC);
                oob.u.a.prevUnitNo = cpu_to_le16(prev_block);
                oob.u.a.ANAC = anac;
@@ -550,7 +555,7 @@ hitused:
                oob.u.b.parityPerField = parity;
                oob.u.b.discarded = 0xaa;
 
-               MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + 
+               MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize +
                        SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u);
 
                inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC];
@@ -578,8 +583,8 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
        struct inftl_bci bci;
        size_t retlen;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=0x%x,"
-               "thisVUC=%d)\n", (int)inftl, thisVUC);
+       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=%p,"
+               "thisVUC=%d)\n", inftl, thisVUC);
 
        memset(BlockUsed, 0, sizeof(BlockUsed));
        memset(BlockDeleted, 0, sizeof(BlockDeleted));
@@ -590,7 +595,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
                       "Virtual Unit Chain %d!\n", thisVUC);
                return;
        }
-       
+
        /*
         * Scan through the Erase Units to determine whether any data is in
         * each of the 512-byte blocks within the Chain.
@@ -630,7 +635,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
                                "Unit Chain 0x%x\n", thisVUC);
                        return;
                }
-               
+
                thisEUN = inftl->PUtable[thisEUN];
        }
 
@@ -668,7 +673,6 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC)
                 if (INFTL_formatblock(inftl, thisEUN) < 0) {
                        /*
                         * Could not erase : mark block as reserved.
-                        * FixMe: Update Bad Unit Table on medium.
                         */
                        inftl->PUtable[thisEUN] = BLOCK_RESERVED;
                 } else {
@@ -698,8 +702,8 @@ static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block)
        size_t retlen;
        struct inftl_bci bci;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=0x%x,"
-               "block=%d)\n", (int)inftl, block);
+       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=%p,"
+               "block=%d)\n", inftl, block);
 
        while (thisEUN < inftl->nb_blocks) {
                if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
@@ -747,18 +751,18 @@ foundit:
        return 0;
 }
 
-static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, 
+static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
                            char *buffer)
 {
        struct INFTLrecord *inftl = (void *)mbd;
        unsigned int writeEUN;
        unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1);
        size_t retlen;
-       u8 eccbuf[6];
+       struct inftl_oob oob;
        char *p, *pend;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=0x%x,block=%ld,"
-               "buffer=0x%x)\n", (int)inftl, block, (int)buffer);
+       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=%p,block=%ld,"
+               "buffer=%p)\n", inftl, block, buffer);
 
        /* Is block all zero? */
        pend = buffer + SECTORSIZE;
@@ -778,11 +782,13 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
                        return 1;
                }
 
+               memset(&oob, 0xff, sizeof(struct inftl_oob));
+               oob.b.Status = oob.b.Status1 = SECTOR_USED;
                MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) +
                        blockofs, SECTORSIZE, &retlen, (char *)buffer,
-                       (char *)eccbuf, NULL);
+                       (char *)&oob, &inftl->oobinfo);
                /*
-                * No need to write SECTOR_USED flags since they are written
+                * need to write SECTOR_USED flags since they are not written
                 * in mtd_writeecc
                 */
        } else {
@@ -803,8 +809,8 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
         struct inftl_bci bci;
        size_t retlen;
 
-       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=0x%x,block=%ld,"
-               "buffer=0x%x)\n", (int)inftl, block, (int)buffer);
+       DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld,"
+               "buffer=%p)\n", inftl, block, buffer);
 
        while (thisEUN < inftl->nb_blocks) {
                if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) +
@@ -846,9 +852,8 @@ foundit:
        } else {
                size_t retlen;
                loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs;
-               u_char eccbuf[6];
-               if (MTD_READECC(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
-                   buffer, eccbuf, NULL))
+               if (MTD_READ(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen,
+                   buffer))
                        return -EIO;
        }
        return 0;
@@ -865,7 +870,7 @@ static int inftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
        return 0;
 }
 
-struct mtd_blktrans_ops inftl_tr = {
+static struct mtd_blktrans_ops inftl_tr = {
        .name           = "inftl",
        .major          = INFTL_MAJOR,
        .part_bits      = INFTL_PARTN_BITS,
@@ -877,11 +882,9 @@ struct mtd_blktrans_ops inftl_tr = {
        .owner          = THIS_MODULE,
 };
 
-extern char inftlmountrev[];
-
-int __init init_inftl(void)
+static int __init init_inftl(void)
 {
-       printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.14 $, "
+       printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.19 $, "
                "inftlmount.c %s\n", inftlmountrev);
 
        return register_mtd_blktrans(&inftl_tr);