]> git.hungrycats.org Git - linux/commitdiff
MTD core include and device code cleanup
authorDavid Woodhouse <dwmw2@shinybook.infradead.org>
Thu, 15 Jul 2004 19:27:17 +0000 (20:27 +0100)
committerDavid Woodhouse <dwmw2@shinybook.infradead.org>
Thu, 15 Jul 2004 19:27:17 +0000 (20:27 +0100)
 - Move user-visible bits from headers to include/mtd/ directory.
 - Update old DiskOnChip drivers for newer hardware.
 - Switch NFTL and INFTL support to work with new DiskOnChip/NAND code.
 - New phram driver, reimplenting the ugly slram driver.
 - Bug fixes in partitioning code

36 files changed:
drivers/mtd/afs.c
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/Makefile
drivers/mtd/devices/blkmtd.c
drivers/mtd/devices/doc2000.c
drivers/mtd/devices/doc2001.c
drivers/mtd/devices/doc2001plus.c
drivers/mtd/devices/docprobe.c
drivers/mtd/devices/lart.c
drivers/mtd/devices/ms02-nv.c
drivers/mtd/devices/ms02-nv.h
drivers/mtd/devices/phram.c [new file with mode: 0644]
drivers/mtd/devices/pmc551.c
drivers/mtd/ftl.c
drivers/mtd/inftlcore.c
drivers/mtd/inftlmount.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdblock.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdconcat.c
drivers/mtd/mtdcore.c
drivers/mtd/nftlcore.c
drivers/mtd/nftlmount.c
drivers/mtd/redboot.c
include/linux/mtd/doc2000.h
include/linux/mtd/ftl.h
include/linux/mtd/inftl.h
include/linux/mtd/mtd.h
include/linux/mtd/nftl.h
include/linux/mtd/partitions.h
include/mtd/inftl-user.h [new file with mode: 0644]
include/mtd/jffs2-user.h [new file with mode: 0644]
include/mtd/mtd-abi.h [new file with mode: 0644]
include/mtd/mtd-user.h [new file with mode: 0644]
include/mtd/nftl-user.h [new file with mode: 0644]

index 4ea08f5e9486ad55ae1d9b09c80f1dd5dc264b6b..801e6c7d08920e4c80babcb1c23bc239f4d869ab 100644 (file)
@@ -21,7 +21,7 @@
    This is access code for flashes using ARM's flash partitioning 
    standards.
 
-   $Id: afs.c,v 1.12 2003/06/13 15:31:06 rmk Exp $
+   $Id: afs.c,v 1.13 2004/02/27 22:09:59 rmk Exp $
 
 ======================================================================*/
 
index a66e5a6654334d9b130e4140f3fc772acd65b599..4e0f1a7a0001f6d051115917cddd54b7c6b1a66e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: cmdlinepart.c,v 1.9 2003/05/16 17:08:24 dwmw2 Exp $
+ * $Id: cmdlinepart.c,v 1.14 2004/07/12 12:34:23 dwmw2 Exp $
  *
  * Read flash partition table from command line
  *
@@ -10,7 +10,7 @@
  * mtdparts=<mtddef>[;<mtddef]
  * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
  * <partdef> := <size>[@offset][<name>][ro]
- * <mtd-id>  := unique id used in mapping driver/device
+ * <mtd-id>  := unique name used in mapping driver/device (mtd->name)
  * <size>    := standard linux memsize OR "-" to denote all remaining space
  * <name>    := '(' NAME ')'
  * 
@@ -358,14 +358,7 @@ static int __init cmdline_parser_init(void)
        return register_mtd_parser(&cmdline_parser);
 }
 
-static void __exit cmdline_parser_exit(void)
-{
-       deregister_mtd_parser(&cmdline_parser);
-}
-
 module_init(cmdline_parser_init);
-module_exit(cmdline_parser_exit);
-
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
index d1df462069b14fb39ff0421637e0bba8d6a55686..6ecd5ec9e20fcd7eb6045b0b2695e407b09f32e8 100644 (file)
@@ -1,5 +1,5 @@
 # drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.4 2003/05/28 15:18:54 dwmw2 Exp $
+# $Id: Kconfig,v 1.10 2004/07/15 00:34:49 dwmw2 Exp $
 
 menu "Self-contained MTD device drivers"
        depends on MTD!=n
@@ -9,9 +9,9 @@ config MTD_PMC551
        depends on MTD && PCI
        ---help---
          This provides a MTD device driver for the Ramix PMC551 RAM PCI card
-         from Ramix Inc. <http://www.ramix.com/products/>. These devices come
-         in memory configurations from 32M - 1G.  If you have one, you
-         probably want to enable this.
+         from Ramix Inc. <http://www.ramix.com/products/memory/pmc551.html>.
+         These devices come in memory configurations from 32M - 1G.  If you
+         have one, you probably want to enable this.
 
          If this driver is compiled as a module you get the ability to select
          the size of the aperture window pointing into the devices memory.
@@ -40,9 +40,12 @@ config MTD_PMC551_DEBUG
 
 config MTD_MS02NV
        tristate "DEC MS02-NV NVRAM module support"
-       depends on CONFIG_MACH_DECSTATION
+       depends on MTD && MACH_DECSTATION
        help
-         Support for NVRAM module on DECstation.
+         This is an MTD driver for the DEC's MS02-NV (54-20948-01) battery
+         backed-up NVRAM module.  The module was originally meant as an NFS
+         accelerator.  Say Y here if you have a DECstation 5000/2x0 or a
+         DECsystem 5900 equipped with such a module.
 
 config MTD_SLRAM
        tristate "Uncached system RAM"
@@ -52,6 +55,16 @@ config MTD_SLRAM
          you can still use it for storage or swap by using this driver to
          present it to the system as a Memory Technology Device.
 
+config MTD_PHRAM
+       tristate "Physical system RAM"
+       depends on MTD
+       help
+         This is a re-implementation of the slram driver above.
+
+         Use this driver to access physical memory that the kernel proper
+         doesn't have access to, memory beyond the mem=xxx limit, nvram,
+         memory on the video card, etc...
+
 config MTD_LART
        tristate "28F160xx flash driver for LART"
        depends on SA1100_LART && MTD
@@ -161,11 +174,18 @@ config MTD_DOC2001PLUS
 
 config MTD_DOCPROBE
        tristate
-       default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MOD_DOC2001PLUS=m)
+       default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MTD_DOC2001PLUS=m)
        default y if MTD_DOC2001=y || MTD_DOC2000=y || MTD_DOC2001PLUS=y
        help
          This isn't a real config option, it's derived.
 
+config MTD_DOCECC
+       tristate
+       default m if MTD_DOCPROBE!=y && MTD_NAND_DISKONCHIP!=y && (MTD_DOCPROBE=m || MTD_NAND_DISKONCHIP=m)
+       default y if MTD_DOCPROBE=y || MTD_NAND_DISKONCHIP=y
+       help
+         This isn't a real config option, it's derived.
+
 config MTD_DOCPROBE_ADVANCED
        bool "Advanced detection options for DiskOnChip"
        depends on MTD_DOCPROBE
index 8ab580b9106604a68330b853d1182c716b718767..3bb872edac595ba15ca8f229053a63b123cd358c 100644 (file)
@@ -1,7 +1,7 @@
 #
 # linux/drivers/devices/Makefile
 #
-# $Id: Makefile.common,v 1.3 2003/05/28 10:54:23 dwmw2 Exp $
+# $Id: Makefile.common,v 1.6 2004/07/12 16:07:30 dwmw2 Exp $
 
 #                       *** BIG UGLY NOTE ***
 #
 obj-$(CONFIG_MTD_DOC2000)      += doc2000.o
 obj-$(CONFIG_MTD_DOC2001)      += doc2001.o
 obj-$(CONFIG_MTD_DOC2001PLUS)  += doc2001plus.o
-obj-$(CONFIG_MTD_DOCPROBE)     += docprobe.o docecc.o
+obj-$(CONFIG_MTD_DOCPROBE)     += docprobe.o
+obj-$(CONFIG_MTD_DOCECC)       += docecc.o
 obj-$(CONFIG_MTD_SLRAM)                += slram.o
+obj-$(CONFIG_MTD_PHRAM)                += phram.o
 obj-$(CONFIG_MTD_PMC551)       += pmc551.o
 obj-$(CONFIG_MTD_MS02NV)       += ms02-nv.o
 obj-$(CONFIG_MTD_MTDRAM)       += mtdram.o
index 4bd5d32194587e400ed617ab94ddcdeb64727ac1..a7e3a9e4be72fa854348d8a3b78ebf150e50a00a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: blkmtd-25.c,v 1.5 2003/07/16 06:48:27 spse Exp $
+ * $Id: blkmtd-25.c,v 1.6 2004/07/15 15:09:15 dwmw2 Exp $
  *
  * blkmtd.c - use a block device as a fake MTD
  *
@@ -39,7 +39,7 @@
 
 /* Default erase size in K, always make it a multiple of PAGE_SIZE */
 #define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10)        /* 128KiB */
-#define VERSION "$Revision: 1.5 $"
+#define VERSION "$Revision: 1.6 $"
 
 /* Info for the block device */
 struct blkmtd_dev {
index fe708695fae2b5aad96262918b03dc4877d7aff7..1a0c28e4eeaada608f44f89ebee85c9b96090d31 100644 (file)
@@ -4,7 +4,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2000.c,v 1.53 2003/06/11 09:45:19 dwmw2 Exp $
+ * $Id: doc2000.c,v 1.60 2004/04/07 08:30:04 gleixner Exp $
  */
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/bitops.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/doc2000.h>
 
 #define DOC_SUPPORT_2000
+#define DOC_SUPPORT_2000TSOP
 #define DOC_SUPPORT_MILLENNIUM
 
 #ifdef DOC_SUPPORT_2000
@@ -33,7 +35,7 @@
 #define DoC_is_2000(doc) (0)
 #endif
 
-#ifdef DOC_SUPPORT_MILLENNIUM
+#if defined(DOC_SUPPORT_2000TSOP) || defined(DOC_SUPPORT_MILLENNIUM)
 #define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil)
 #else
 #define DoC_is_Millennium(doc) (0)
@@ -53,11 +55,12 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
                     size_t *retlen, const u_char *buf);
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t *retlen, u_char *buf, u_char *eccbuf,
-                       struct nand_oobinfo *unused);
+                       size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-                        size_t *retlen, const u_char *buf, u_char *eccbuf,
-                       struct nand_oobinfo *unused);
+                        size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
+static int doc_writev_ecc(struct mtd_info *mtd, const struct iovec *vecs, 
+                         unsigned long count, loff_t to, size_t *retlen,
+                         u_char *eccbuf, struct nand_oobinfo *oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                        size_t *retlen, u_char *buf);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
@@ -94,6 +97,10 @@ static int _DoC_WaitReady(struct DiskOnChip *doc)
 
        /* Out-of-line routine to wait for chip response */
        while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) {
+               /* issue 2 read from NOP register after reading from CDSNControl register
+               see Software Requirement 11.4 item 2. */
+               DoC_Delay(doc, 2);
+
                if (time_after(jiffies, timeo)) {
                        DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n");
                        return -EIO;
@@ -147,6 +154,8 @@ static inline int DoC_Command(struct DiskOnChip *doc, unsigned char command,
 
        /* Send the command */
        WriteDOC_(command, docptr, doc->ioreg);
+       if (DoC_is_Millennium(doc))
+               WriteDOC(command, docptr, WritePipeTerm);
 
        /* Lower the CLE line */
        WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl);
@@ -208,6 +217,9 @@ static int DoC_Address(struct DiskOnChip *doc, int numbytes, unsigned long ofs,
                }
        }
 
+       if (DoC_is_Millennium(doc))
+               WriteDOC(ofs & 0xff, docptr, WritePipeTerm);
+
        DoC_Delay(doc, 2);      /* Needed for some slow flash chips. mf. */
        
        /* FIXME: The SlowIO's for millennium could be replaced by 
@@ -346,15 +358,25 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
 
        /* Read the manufacturer and device id codes from the device */
 
-       /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
-       dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
-       DoC_Delay(doc, 2);
-       mfr = ReadDOC_(doc->virtadr, doc->ioreg);
+       if (DoC_is_Millennium(doc)) {
+               DoC_Delay(doc, 2);
+               dummy = ReadDOC(doc->virtadr, ReadPipeInit);
+               mfr = ReadDOC(doc->virtadr, LastDataRead);
 
-       /* CDSN Slow IO register see Software Requirement 11.4 item 5. */
-       dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
-       DoC_Delay(doc, 2);
-       id = ReadDOC_(doc->virtadr, doc->ioreg);
+               DoC_Delay(doc, 2);
+               dummy = ReadDOC(doc->virtadr, ReadPipeInit);
+               id = ReadDOC(doc->virtadr, LastDataRead);
+       } else {
+               /* CDSN Slow IO register see Software Req 11.4 item 5. */
+               dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+               DoC_Delay(doc, 2);
+               mfr = ReadDOC_(doc->virtadr, doc->ioreg);
+
+               /* CDSN Slow IO register see Software Req 11.4 item 5. */
+               dummy = ReadDOC(doc->virtadr, CDSNSlowIO);
+               DoC_Delay(doc, 2);
+               id = ReadDOC_(doc->virtadr, doc->ioreg);
+       }
 
        /* No response - return failure */
        if (mfr == 0xff || mfr == 0)
@@ -388,11 +410,10 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
                        if (!doc->mfr) {
                                doc->mfr = mfr;
                                doc->id = id;
-                               doc->chipshift =
-                                   nand_flash_ids[i].chipshift;
-                               doc->page256 = nand_flash_ids[i].page256;
-                               doc->pageadrlen =
-                                   nand_flash_ids[i].chipshift > 25 ? 3 : 2;
+                               doc->chipshift = 
+                                       ffs((nand_flash_ids[i].chipsize << 20)) - 1;
+                               doc->page256 = (nand_flash_ids[i].pagesize == 256) ? 1 : 0;
+                               doc->pageadrlen = doc->chipshift > 25 ? 3 : 2;
                                doc->erasesize =
                                    nand_flash_ids[i].erasesize;
                                return 1;
@@ -412,20 +433,16 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
 
 /* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */
 
-static void DoC_ScanChips(struct DiskOnChip *this)
+static void DoC_ScanChips(struct DiskOnChip *this, int maxchips)
 {
        int floor, chip;
        int numchips[MAX_FLOORS];
-       int maxchips = MAX_CHIPS;
        int ret = 1;
 
        this->numchips = 0;
        this->mfr = 0;
        this->id = 0;
 
-       if (DoC_is_Millennium(this))
-               maxchips = MAX_CHIPS_MIL;
-
        /* For each floor, find the number of valid chips it contains */
        for (floor = 0; floor < MAX_FLOORS; floor++) {
                ret = 1;
@@ -517,6 +534,7 @@ static void DoC2k_init(struct mtd_info *mtd)
 {
        struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
        struct DiskOnChip *old = NULL;
+       int maxchips;
 
        /* We must avoid being called twice for the same device. */
 
@@ -540,14 +558,28 @@ static void DoC2k_init(struct mtd_info *mtd)
 
 
        switch (this->ChipID) {
+       case DOC_ChipID_Doc2kTSOP:
+               mtd->name = "DiskOnChip 2000 TSOP";
+               this->ioreg = DoC_Mil_CDSN_IO;
+               /* Pretend it's a Millennium */
+               this->ChipID = DOC_ChipID_DocMil;
+               maxchips = MAX_CHIPS;
+               break;
        case DOC_ChipID_Doc2k:
                mtd->name = "DiskOnChip 2000";
                this->ioreg = DoC_2k_CDSN_IO;
+               maxchips = MAX_CHIPS;
                break;
        case DOC_ChipID_DocMil:
                mtd->name = "DiskOnChip Millennium";
                this->ioreg = DoC_Mil_CDSN_IO;
+               maxchips = MAX_CHIPS_MIL;
                break;
+       default:
+               printk("Unknown ChipID 0x%02x\n", this->ChipID);
+               kfree(mtd);
+               iounmap((void *) this->virtadr);
+               return;
        }
 
        printk(KERN_NOTICE "%s found at address 0x%lX\n", mtd->name,
@@ -568,6 +600,7 @@ static void DoC2k_init(struct mtd_info *mtd)
        mtd->write = doc_write;
        mtd->read_ecc = doc_read_ecc;
        mtd->write_ecc = doc_write_ecc;
+       mtd->writev_ecc = doc_writev_ecc;
        mtd->read_oob = doc_read_oob;
        mtd->write_oob = doc_write_oob;
        mtd->sync = NULL;
@@ -580,7 +613,7 @@ static void DoC2k_init(struct mtd_info *mtd)
        init_MUTEX(&this->lock);
 
        /* Ident all the chips present. */
-       DoC_ScanChips(this);
+       DoC_ScanChips(this, maxchips);
 
        if (!this->totlen) {
                kfree(mtd);
@@ -599,12 +632,11 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
                    size_t * retlen, u_char * buf)
 {
        /* Just a special case of doc_read_ecc */
-       return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
+       return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
 }
 
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t * retlen, u_char * buf, u_char * eccbuf,
-                       struct nand_oobinfo *unused)
+                       size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
 {
        struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
        unsigned long docptr;
@@ -612,6 +644,7 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
        unsigned char syndrome[6];
        volatile char dummy;
        int i, len256 = 0, ret=0;
+       size_t left = len;
 
        docptr = this->virtadr;
 
@@ -621,122 +654,131 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
 
        down(&this->lock);
 
-       /* Don't allow a single read to cross a 512-byte block boundary */
-       if (from + len > ((from | 0x1ff) + 1))
-               len = ((from | 0x1ff) + 1) - from;
-
-       /* The ECC will not be calculated correctly if less than 512 is read */
-       if (len != 0x200 && eccbuf)
-               printk(KERN_WARNING
-                      "ECC needs a full sector read (adr: %lx size %lx)\n",
-                      (long) from, (long) len);
-
-       /* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */
+       *retlen = 0;
+       while (left) {
+               len = left;
 
+               /* Don't allow a single read to cross a 512-byte block boundary */
+               if (from + len > ((from | 0x1ff) + 1))
+                       len = ((from | 0x1ff) + 1) - from;
 
-       /* Find the chip which is to be used and select it */
-       mychip = &this->chips[from >> (this->chipshift)];
+               /* The ECC will not be calculated correctly if less than 512 is read */
+               if (len != 0x200 && eccbuf)
+                       printk(KERN_WARNING
+                              "ECC needs a full sector read (adr: %lx size %lx)\n",
+                              (long) from, (long) len);
 
-       if (this->curfloor != mychip->floor) {
-               DoC_SelectFloor(this, mychip->floor);
-               DoC_SelectChip(this, mychip->chip);
-       } else if (this->curchip != mychip->chip) {
-               DoC_SelectChip(this, mychip->chip);
-       }
+               /* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */
 
-       this->curfloor = mychip->floor;
-       this->curchip = mychip->chip;
 
-       DoC_Command(this,
-                   (!this->page256
-                    && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
-                   CDSN_CTRL_WP);
-       DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
-                   CDSN_CTRL_ECC_IO);
-
-       if (eccbuf) {
-               /* Prime the ECC engine */
-               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-               WriteDOC(DOC_ECC_EN, docptr, ECCConf);
-       } else {
-               /* disable the ECC engine */
-               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-       }
+               /* Find the chip which is to be used and select it */
+               mychip = &this->chips[from >> (this->chipshift)];
 
-       /* treat crossing 256-byte sector for 2M x 8bits devices */
-       if (this->page256 && from + len > (from | 0xff) + 1) {
-               len256 = (from | 0xff) + 1 - from;
-               DoC_ReadBuf(this, buf, len256);
+               if (this->curfloor != mychip->floor) {
+                       DoC_SelectFloor(this, mychip->floor);
+                       DoC_SelectChip(this, mychip->chip);
+               } else if (this->curchip != mychip->chip) {
+                       DoC_SelectChip(this, mychip->chip);
+               }
 
-               DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
-               DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
-                           CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
-       }
+               this->curfloor = mychip->floor;
+               this->curchip = mychip->chip;
 
-       DoC_ReadBuf(this, &buf[len256], len - len256);
+               DoC_Command(this,
+                           (!this->page256
+                            && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+                           CDSN_CTRL_WP);
+               DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
+                           CDSN_CTRL_ECC_IO);
 
-       /* Let the caller know we completed it */
-       *retlen = len;
+               if (eccbuf) {
+                       /* Prime the ECC engine */
+                       WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+                       WriteDOC(DOC_ECC_EN, docptr, ECCConf);
+               } else {
+                       /* disable the ECC engine */
+                       WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+                       WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+               }
 
-       if (eccbuf) {
-               /* Read the ECC data through the DiskOnChip ECC logic */
-               /* Note: this will work even with 2M x 8bit devices as   */
-               /*       they have 8 bytes of OOB per 256 page. mf.      */
-               DoC_ReadBuf(this, eccbuf, 6);
+               /* treat crossing 256-byte sector for 2M x 8bits devices */
+               if (this->page256 && from + len > (from | 0xff) + 1) {
+                       len256 = (from | 0xff) + 1 - from;
+                       DoC_ReadBuf(this, buf, len256);
 
-               /* Flush the pipeline */
-               if (DoC_is_Millennium(this)) {
-                       dummy = ReadDOC(docptr, ECCConf);
-                       dummy = ReadDOC(docptr, ECCConf);
-                       i = ReadDOC(docptr, ECCConf);
-               } else {
-                       dummy = ReadDOC(docptr, 2k_ECCStatus);
-                       dummy = ReadDOC(docptr, 2k_ECCStatus);
-                       i = ReadDOC(docptr, 2k_ECCStatus);
+                       DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
+                       DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
+                                   CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
                }
 
-               /* Check the ECC Status */
-               if (i & 0x80) {
-                       int nb_errors;
-                       /* There was an ECC error */
+               DoC_ReadBuf(this, &buf[len256], len - len256);
+
+               /* Let the caller know we completed it */
+               *retlen += len;
+
+               if (eccbuf) {
+                       /* Read the ECC data through the DiskOnChip ECC logic */
+                       /* Note: this will work even with 2M x 8bit devices as   */
+                       /*       they have 8 bytes of OOB per 256 page. mf.      */
+                       DoC_ReadBuf(this, eccbuf, 6);
+
+                       /* Flush the pipeline */
+                       if (DoC_is_Millennium(this)) {
+                               dummy = ReadDOC(docptr, ECCConf);
+                               dummy = ReadDOC(docptr, ECCConf);
+                               i = ReadDOC(docptr, ECCConf);
+                       } else {
+                               dummy = ReadDOC(docptr, 2k_ECCStatus);
+                               dummy = ReadDOC(docptr, 2k_ECCStatus);
+                               i = ReadDOC(docptr, 2k_ECCStatus);
+                       }
+
+                       /* Check the ECC Status */
+                       if (i & 0x80) {
+                               int nb_errors;
+                               /* There was an ECC error */
 #ifdef ECC_DEBUG
-                       printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from);
+                               printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from);
 #endif
-                       /* Read the ECC syndrom through the DiskOnChip ECC logic.
-                          These syndrome will be all ZERO when there is no error */
-                       for (i = 0; i < 6; i++) {
-                               syndrome[i] =
-                                   ReadDOC(docptr, ECCSyndrome0 + i);
-                       }
-                        nb_errors = doc_decode_ecc(buf, syndrome);
+                               /* Read the ECC syndrom through the DiskOnChip ECC logic.
+                                  These syndrome will be all ZERO when there is no error */
+                               for (i = 0; i < 6; i++) {
+                                       syndrome[i] =
+                                           ReadDOC(docptr, ECCSyndrome0 + i);
+                               }
+                               nb_errors = doc_decode_ecc(buf, syndrome);
 
 #ifdef ECC_DEBUG
-                       printk(KERN_ERR "Errors corrected: %x\n", nb_errors);
+                               printk(KERN_ERR "Errors corrected: %x\n", nb_errors);
 #endif
-                        if (nb_errors < 0) {
-                               /* We return error, but have actually done the read. Not that
-                                  this can be told to user-space, via sys_read(), but at least
-                                  MTD-aware stuff can know about it by checking *retlen */
-                               ret = -EIO;
-                        }
-               }
+                               if (nb_errors < 0) {
+                                       /* We return error, but have actually done the read. Not that
+                                          this can be told to user-space, via sys_read(), but at least
+                                          MTD-aware stuff can know about it by checking *retlen */
+                                       ret = -EIO;
+                               }
+                       }
 
 #ifdef PSYCHO_DEBUG
-               printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-                            (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
-                            eccbuf[3], eccbuf[4], eccbuf[5]);
+                       printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+                                    (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
+                                    eccbuf[3], eccbuf[4], eccbuf[5]);
 #endif
                
-               /* disable the ECC engine */
-               WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
-       }
+                       /* disable the ECC engine */
+                       WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
+               }
 
-       /* according to 11.4.1, we need to wait for the busy line 
-         * drop if we read to the end of the page.  */
-       if(0 == ((from + *retlen) & 0x1ff))
-       {
-           DoC_WaitReady(this);
+               /* according to 11.4.1, we need to wait for the busy line 
+                * drop if we read to the end of the page.  */
+               if(0 == ((from + len) & 0x1ff))
+               {
+                   DoC_WaitReady(this);
+               }
+
+               from += len;
+               left -= len;
+               buf += len;
        }
 
        up(&this->lock);
@@ -748,13 +790,12 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
                     size_t * retlen, const u_char * buf)
 {
        char eccbuf[6];
-       return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
+       return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
 }
 
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
                         size_t * retlen, const u_char * buf,
-                        u_char * eccbuf,
-                        struct nand_oobinfo *unused)
+                        u_char * eccbuf, struct nand_oobinfo *oobsel)
 {
        struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv;
        int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
@@ -762,6 +803,8 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
        volatile char dummy;
        int len256 = 0;
        struct Nand *mychip;
+       size_t left = len;
+       int status;
 
        docptr = this->virtadr;
 
@@ -771,65 +814,133 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
 
        down(&this->lock);
 
-       /* Don't allow a single write to cross a 512-byte block boundary */
-       if (to + len > ((to | 0x1ff) + 1))
-               len = ((to | 0x1ff) + 1) - to;
+       *retlen = 0;
+       while (left) {
+               len = left;
 
-       /* The ECC will not be calculated correctly if less than 512 is written */
-       if (len != 0x200 && eccbuf)
-               printk(KERN_WARNING
-                      "ECC needs a full sector write (adr: %lx size %lx)\n",
-                      (long) to, (long) len);
+               /* Don't allow a single write to cross a 512-byte block boundary */
+               if (to + len > ((to | 0x1ff) + 1))
+                       len = ((to | 0x1ff) + 1) - to;
 
-       /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
+               /* The ECC will not be calculated correctly if less than 512 is written */
+/* DBB-
+               if (len != 0x200 && eccbuf)
+                       printk(KERN_WARNING
+                              "ECC needs a full sector write (adr: %lx size %lx)\n",
+                              (long) to, (long) len);
+   -DBB */
 
-       /* Find the chip which is to be used and select it */
-       mychip = &this->chips[to >> (this->chipshift)];
+               /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
 
-       if (this->curfloor != mychip->floor) {
-               DoC_SelectFloor(this, mychip->floor);
-               DoC_SelectChip(this, mychip->chip);
-       } else if (this->curchip != mychip->chip) {
-               DoC_SelectChip(this, mychip->chip);
-       }
+               /* Find the chip which is to be used and select it */
+               mychip = &this->chips[to >> (this->chipshift)];
 
-       this->curfloor = mychip->floor;
-       this->curchip = mychip->chip;
+               if (this->curfloor != mychip->floor) {
+                       DoC_SelectFloor(this, mychip->floor);
+                       DoC_SelectChip(this, mychip->chip);
+               } else if (this->curchip != mychip->chip) {
+                       DoC_SelectChip(this, mychip->chip);
+               }
 
-       /* Set device to main plane of flash */
-       DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
-       DoC_Command(this,
-                   (!this->page256
-                    && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
-                   CDSN_CTRL_WP);
+               this->curfloor = mychip->floor;
+               this->curchip = mychip->chip;
 
-       DoC_Command(this, NAND_CMD_SEQIN, 0);
-       DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
+               /* Set device to main plane of flash */
+               DoC_Command(this, NAND_CMD_RESET, CDSN_CTRL_WP);
+               DoC_Command(this,
+                           (!this->page256
+                            && (to & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0,
+                           CDSN_CTRL_WP);
 
-       if (eccbuf) {
-               /* Prime the ECC engine */
-               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-               WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
-       } else {
-               /* disable the ECC engine */
-               WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
-               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
-       }
+               DoC_Command(this, NAND_CMD_SEQIN, 0);
+               DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
 
-       /* treat crossing 256-byte sector for 2M x 8bits devices */
-       if (this->page256 && to + len > (to | 0xff) + 1) {
-               len256 = (to | 0xff) + 1 - to;
-               DoC_WriteBuf(this, buf, len256);
+               if (eccbuf) {
+                       /* Prime the ECC engine */
+                       WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+                       WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
+               } else {
+                       /* disable the ECC engine */
+                       WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+                       WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+               }
+
+               /* treat crossing 256-byte sector for 2M x 8bits devices */
+               if (this->page256 && to + len > (to | 0xff) + 1) {
+                       len256 = (to | 0xff) + 1 - to;
+                       DoC_WriteBuf(this, buf, len256);
+
+                       DoC_Command(this, NAND_CMD_PAGEPROG, 0);
+
+                       DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
+                       /* There's an implicit DoC_WaitReady() in DoC_Command */
+
+                       dummy = ReadDOC(docptr, CDSNSlowIO);
+                       DoC_Delay(this, 2);
+
+                       if (ReadDOC_(docptr, this->ioreg) & 1) {
+                               printk(KERN_ERR "Error programming flash\n");
+                               /* Error in programming */
+                               *retlen = 0;
+                               up(&this->lock);
+                               return -EIO;
+                       }
+
+                       DoC_Command(this, NAND_CMD_SEQIN, 0);
+                       DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0,
+                                   CDSN_CTRL_ECC_IO);
+               }
+
+               DoC_WriteBuf(this, &buf[len256], len - len256);
+
+               if (eccbuf) {
+                       WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
+                                CDSNControl);
+
+                       if (DoC_is_Millennium(this)) {
+                               WriteDOC(0, docptr, NOP);
+                               WriteDOC(0, docptr, NOP);
+                               WriteDOC(0, docptr, NOP);
+                       } else {
+                               WriteDOC_(0, docptr, this->ioreg);
+                               WriteDOC_(0, docptr, this->ioreg);
+                               WriteDOC_(0, docptr, this->ioreg);
+                       }
+
+                       WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr,
+                                CDSNControl);
+
+                       /* Read the ECC data through the DiskOnChip ECC logic */
+                       for (di = 0; di < 6; di++) {
+                               eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
+                       }
+
+                       /* Reset the ECC engine */
+                       WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+
+#ifdef PSYCHO_DEBUG
+                       printk
+                           ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+                            (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+                            eccbuf[4], eccbuf[5]);
+#endif
+               }
 
                DoC_Command(this, NAND_CMD_PAGEPROG, 0);
 
                DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
                /* There's an implicit DoC_WaitReady() in DoC_Command */
 
-               dummy = ReadDOC(docptr, CDSNSlowIO);
-               DoC_Delay(this, 2);
+               if (DoC_is_Millennium(this)) {
+                       ReadDOC(docptr, ReadPipeInit);
+                       status = ReadDOC(docptr, LastDataRead);
+               } else {
+                       dummy = ReadDOC(docptr, CDSNSlowIO);
+                       DoC_Delay(this, 2);
+                       status = ReadDOC_(docptr, this->ioreg);
+               }
 
-               if (ReadDOC_(docptr, this->ioreg) & 1) {
+               if (status & 1) {
                        printk(KERN_ERR "Error programming flash\n");
                        /* Error in programming */
                        *retlen = 0;
@@ -837,82 +948,97 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
                        return -EIO;
                }
 
-               DoC_Command(this, NAND_CMD_SEQIN, 0);
-               DoC_Address(this, ADDR_COLUMN_PAGE, to + len256, 0,
-                           CDSN_CTRL_ECC_IO);
+               /* Let the caller know we completed it */
+               *retlen += len;
+               
+               if (eccbuf) {
+                       unsigned char x[8];
+                       size_t dummy;
+                       int ret;
+
+                       /* Write the ECC data to flash */
+                       for (di=0; di<6; di++)
+                               x[di] = eccbuf[di];
+               
+                       x[6]=0x55;
+                       x[7]=0x55;
+               
+                       ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
+                       if (ret) {
+                               up(&this->lock);
+                               return ret;
+                       }
+               }
+
+               to += len;
+               left -= len;
+               buf += len;
        }
 
-       DoC_WriteBuf(this, &buf[len256], len - len256);
+       up(&this->lock);
+       return 0;
+}
 
-       if (eccbuf) {
-               WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
-                        CDSNControl);
+static int doc_writev_ecc(struct mtd_info *mtd, const struct iovec *vecs, 
+                         unsigned long count, loff_t to, size_t *retlen,
+                         u_char *eccbuf, struct nand_oobinfo *oobsel)
+{
+       static char static_buf[512];
+       static DECLARE_MUTEX(writev_buf_sem);
 
-               if (DoC_is_Millennium(this)) {
-                       WriteDOC(0, docptr, NOP);
-                       WriteDOC(0, docptr, NOP);
-                       WriteDOC(0, docptr, NOP);
-               } else {
-                       WriteDOC_(0, docptr, this->ioreg);
-                       WriteDOC_(0, docptr, this->ioreg);
-                       WriteDOC_(0, docptr, this->ioreg);
-               }
+       size_t totretlen = 0;
+       size_t thisvecofs = 0;
+       int ret= 0;
 
-               /* Read the ECC data through the DiskOnChip ECC logic */
-               for (di = 0; di < 6; di++) {
-                       eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
-               }
+       down(&writev_buf_sem);
 
-               /* Reset the ECC engine */
-               WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+       while(count) {
+               size_t thislen, thisretlen;
+               unsigned char *buf;
 
-#ifdef PSYCHO_DEBUG
-               printk
-                   ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
-                    (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
-                    eccbuf[4], eccbuf[5]);
-#endif
-       }
+               buf = vecs->iov_base + thisvecofs;
+               thislen = vecs->iov_len - thisvecofs;
 
-       DoC_Command(this, NAND_CMD_PAGEPROG, 0);
 
-       DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
-       /* There's an implicit DoC_WaitReady() in DoC_Command */
+               if (thislen >= 512) {
+                       thislen = thislen & ~(512-1);
+                       thisvecofs += thislen;
+               } else {
+                       /* Not enough to fill a page. Copy into buf */
+                       memcpy(static_buf, buf, thislen);
+                       buf = &static_buf[thislen];
+
+                       while(count && thislen < 512) {
+                               vecs++;
+                               count--;
+                               thisvecofs = min((512-thislen), vecs->iov_len);
+                               memcpy(buf, vecs->iov_base, thisvecofs);
+                               thislen += thisvecofs;
+                               buf += thisvecofs;
+                       }
+                       buf = static_buf;
+               }
+               if (count && thisvecofs == vecs->iov_len) {
+                       thisvecofs = 0;
+                       vecs++;
+                       count--;
+               }
+               ret = doc_write_ecc(mtd, to, thislen, &thisretlen, buf, eccbuf, oobsel);
 
-       dummy = ReadDOC(docptr, CDSNSlowIO);
-       DoC_Delay(this, 2);
+               totretlen += thisretlen;
 
-       if (ReadDOC_(docptr, this->ioreg) & 1) {
-               printk(KERN_ERR "Error programming flash\n");
-               /* Error in programming */
-               *retlen = 0;
-               up(&this->lock);
-               return -EIO;
-       }
+               if (ret || thisretlen != thislen)
+                       break;
 
-       /* Let the caller know we completed it */
-       *retlen = len;
-               
-       if (eccbuf) {
-               unsigned char x[8];
-               size_t dummy;
-               int ret;
-
-               /* Write the ECC data to flash */
-               for (di=0; di<6; di++)
-                       x[di] = eccbuf[di];
-               
-               x[6]=0x55;
-               x[7]=0x55;
-               
-               ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
-               up(&this->lock);
-               return ret;
-       }
-       up(&this->lock);
-       return 0;
+               to += thislen;
+       }               
+
+       up(&writev_buf_sem);
+       *retlen = totretlen;
+       return ret;
 }
 
+
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                        size_t * retlen, u_char * buf)
 {
@@ -982,6 +1108,7 @@ static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
        unsigned long docptr = this->virtadr;
        struct Nand *mychip = &this->chips[ofs >> this->chipshift];
        volatile int dummy;
+       int status;
 
        //      printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len,
        //   buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]);
@@ -1030,10 +1157,16 @@ static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
                DoC_Command(this, NAND_CMD_STATUS, 0);
                /* DoC_WaitReady() is implicit in DoC_Command */
 
-               dummy = ReadDOC(docptr, CDSNSlowIO);
-               DoC_Delay(this, 2);
+               if (DoC_is_Millennium(this)) {
+                       ReadDOC(docptr, ReadPipeInit);
+                       status = ReadDOC(docptr, LastDataRead);
+               } else {
+                       dummy = ReadDOC(docptr, CDSNSlowIO);
+                       DoC_Delay(this, 2);
+                       status = ReadDOC_(docptr, this->ioreg);
+               }
 
-               if (ReadDOC_(docptr, this->ioreg) & 1) {
+               if (status & 1) {
                        printk(KERN_ERR "Error programming oob data\n");
                        /* There was an error */
                        *retlen = 0;
@@ -1049,10 +1182,16 @@ static int doc_write_oob_nolock(struct mtd_info *mtd, loff_t ofs, size_t len,
        DoC_Command(this, NAND_CMD_STATUS, 0);
        /* DoC_WaitReady() is implicit in DoC_Command */
 
-       dummy = ReadDOC(docptr, CDSNSlowIO);
-       DoC_Delay(this, 2);
+       if (DoC_is_Millennium(this)) {
+               ReadDOC(docptr, ReadPipeInit);
+               status = ReadDOC(docptr, LastDataRead);
+       } else {
+               dummy = ReadDOC(docptr, CDSNSlowIO);
+               DoC_Delay(this, 2);
+               status = ReadDOC_(docptr, this->ioreg);
+       }
 
-       if (ReadDOC_(docptr, this->ioreg) & 1) {
+       if (status & 1) {
                printk(KERN_ERR "Error programming oob data\n");
                /* There was an error */
                *retlen = 0;
@@ -1085,6 +1224,7 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
        volatile int dummy;
        unsigned long docptr;
        struct Nand *mychip;
+       int status;
 
        down(&this->lock);
 
@@ -1116,10 +1256,16 @@ static int doc_erase(struct mtd_info *mtd, struct erase_info *instr)
 
                DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
 
-               dummy = ReadDOC(docptr, CDSNSlowIO);
-               DoC_Delay(this, 2);
-               
-               if (ReadDOC_(docptr, this->ioreg) & 1) {
+               if (DoC_is_Millennium(this)) {
+                       ReadDOC(docptr, ReadPipeInit);
+                       status = ReadDOC(docptr, LastDataRead);
+               } else {
+                       dummy = ReadDOC(docptr, CDSNSlowIO);
+                       DoC_Delay(this, 2);
+                       status = ReadDOC_(docptr, this->ioreg);
+               }
+
+               if (status & 1) {
                        printk(KERN_ERR "Error erasing at 0x%x\n", ofs);
                        /* There was an error */
                        instr->state = MTD_ERASE_FAILED;
index 6d5d8218bfa53c348744ee2aff3308357bcfd1f8..77ed2c409e3a9741352bee3da9355481776c3dfc 100644 (file)
@@ -4,7 +4,7 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2001.c,v 1.41 2003/06/11 09:45:19 dwmw2 Exp $
+ * $Id: doc2001.c,v 1.42 2004/04/04 12:36:45 gleixner Exp $
  */
 
 #include <linux/kernel.h>
@@ -19,6 +19,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/bitops.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -37,12 +38,9 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
 static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
                     size_t *retlen, const u_char *buf);
 static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
-                       size_t *retlen, u_char *buf, u_char *eccbuf,
-                       struct nand_oobinfo *unused);
+                       size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
-                        size_t *retlen, const u_char *buf, u_char *eccbuf,
-                       struct nand_oobinfo *unused);
-
+                        size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel);
 static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                        size_t *retlen, u_char *buf);
 static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
@@ -229,7 +227,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
                               mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name);
                        doc->mfr = mfr;
                        doc->id = id;
-                       doc->chipshift = nand_flash_ids[i].chipshift;
+                       doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1;
                        break;
                }
        }
@@ -406,12 +404,11 @@ static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
                     size_t *retlen, u_char *buf)
 {
        /* Just a special case of doc_read_ecc */
-       return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
+       return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0);
 }
 
 static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
-                        size_t *retlen, u_char *buf, u_char *eccbuf,
-                        struct nand_oobinfo *unused)
+                        size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel)
 {
        int i, ret;
        volatile char dummy;
@@ -533,12 +530,11 @@ static int doc_write (struct mtd_info *mtd, loff_t to, size_t len,
                      size_t *retlen, const u_char *buf)
 {
        char eccbuf[6];
-       return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
+       return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0);
 }
 
 static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
-                         size_t *retlen, const u_char *buf, u_char *eccbuf,
-                         struct nand_oobinfo *unused)
+                         size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel)
 {
        int i,ret = 0;
        volatile char dummy;
index e5e5fdaeb32d01e9e5de7ee794c242b62abeac49..da4275cb73eb18100ddcbe8575f53cec6463bb63 100644 (file)
@@ -6,7 +6,9 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
- * $Id: doc2001plus.c,v 1.5 2003/06/11 09:45:19 dwmw2 Exp $
+ * $Id: doc2001plus.c,v 1.8 2004/04/04 12:36:45 gleixner Exp $
+ *
+ * Released under GPL
  */
 
 #include <linux/kernel.h>
@@ -21,6 +23,7 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/types.h>
+#include <linux/bitops.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -183,24 +186,35 @@ static int DoC_SelectFloor(unsigned long docptr, int floor)
  *  | Data 0    | ECC 0 |Flags0 |Flags1 | Data 1       |ECC 1    | OOB 1 + 2 |
  *  +-----------+-------+-------+-------+--------------+---------+-----------+
  */
+/* FIXME: This lives in INFTL not here. Other users of flash devices
+   may not want it */
 static unsigned int DoC_GetDataOffset(struct mtd_info *mtd, loff_t *from)
 {
-       unsigned int ofs = *from & 0x3ff;
-       unsigned int cmd;
+       struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv;
 
-       if (ofs < 512) {
-               cmd = NAND_CMD_READ0;
-               ofs &= 0x1ff;
-       } else if (ofs < 1014) {
-               cmd = NAND_CMD_READ1;
-               ofs = (ofs & 0x1ff) + 10;
+       if (this->interleave) {
+               unsigned int ofs = *from & 0x3ff;
+               unsigned int cmd;
+
+               if (ofs < 512) {
+                       cmd = NAND_CMD_READ0;
+                       ofs &= 0x1ff;
+               } else if (ofs < 1014) {
+                       cmd = NAND_CMD_READ1;
+                       ofs = (ofs & 0x1ff) + 10;
+               } else {
+                       cmd = NAND_CMD_READOOB;
+                       ofs = ofs - 1014;
+               }
+
+               *from = (*from & ~0x3ff) | ofs;
+               return cmd;
        } else {
-               cmd = NAND_CMD_READOOB;
-               ofs = ofs - 1014;
+               /* No interleave */
+               if ((*from) & 0x100)
+                       return NAND_CMD_READ1;
+               return NAND_CMD_READ0;
        }
-
-       *from = (*from & ~0x3ff) | ofs;
-       return cmd;
 }
 
 static unsigned int DoC_GetECCOffset(struct mtd_info *mtd, loff_t *from)
@@ -294,10 +308,12 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
        dummy = ReadDOC(docptr, Mplus_ReadPipeInit);
 
        mfr = ReadDOC(docptr, Mil_CDSN_IO);
-       dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
+       if (doc->interleave)
+               dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
 
        id  = ReadDOC(docptr, Mil_CDSN_IO);
-       dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
+       if (doc->interleave)
+               dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */
 
        dummy = ReadDOC(docptr, Mplus_LastDataRead);
        dummy = ReadDOC(docptr, Mplus_LastDataRead);
@@ -321,10 +337,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip)
                               nand_manuf_ids[j].name, nand_flash_ids[i].name);
                        doc->mfr = mfr;
                        doc->id = id;
-                       doc->interleave = 0;
-                       if (doc->ChipID == DOC_ChipID_DocMilPlus32)
-                               doc->interleave = 1;
-                       doc->chipshift = nand_flash_ids[i].chipshift;
+                       doc->chipshift = ffs((nand_flash_ids[i].chipsize << 20)) - 1;
                        doc->erasesize = nand_flash_ids[i].erasesize << doc->interleave;
                        break;
                }
@@ -346,6 +359,21 @@ static void DoC_ScanChips(struct DiskOnChip *this)
        this->mfr = 0;
        this->id = 0;
 
+       /* Work out the intended interleave setting */
+       this->interleave = 0;
+       if (this->ChipID == DOC_ChipID_DocMilPlus32)
+               this->interleave = 1;
+
+       /* Check the ASIC agrees */
+       if ( (this->interleave << 2) != 
+            (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) {
+               u_char conf = ReadDOC(this->virtadr, Mplus_Configuration);
+               printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n",
+                      this->interleave?"on (16-bit)":"off (8-bit)");
+               conf ^= 4;
+               WriteDOC(this->virtadr, conf, Mplus_Configuration);
+       }
+
        /* For each floor, find the number of valid chips it contains */
        for (floor = 0,ret = 1; floor < MAX_FLOORS_MPLUS; floor++) {
                numchips[floor] = 0;
@@ -739,7 +767,7 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
                return -EINVAL;
 
        /* Determine position of OOB flags, before or after data */
-       before = to & 0x200;
+       before = (this->interleave && (to & 0x200));
 
        DoC_CheckASIC(docptr);
 
@@ -886,7 +914,10 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                /* Figure out which region we are accessing... */
                fofs = ofs;
                base = ofs & 0xf;
-               if (base < 6) {
+               if (!this->interleave) {
+                       DoC_Command(docptr, NAND_CMD_READOOB, 0);
+                       size = 16 - base;
+               } else if (base < 6) {
                        DoC_Command(docptr, DoC_GetECCOffset(mtd, &fofs), 0);
                        size = 6 - base;
                } else if (base < 8) {
@@ -963,7 +994,10 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len,
                /* Figure out which region we are accessing... */
                fofs = ofs;
                base = ofs & 0x0f;
-               if (base < 6) {
+               if (!this->interleave) {
+                       WriteDOC(NAND_CMD_READOOB, docptr, Mplus_FlashCmd);
+                       size = 16 - base;
+               } else if (base < 6) {
                        WriteDOC(DoC_GetECCOffset(mtd, &fofs), docptr, Mplus_FlashCmd);
                        size = 6 - base;
                } else if (base < 8) {
index f7a91fa86995da572a1ab1838a5606d324e251d0..cb8b8a51ec0756834d676c4f74857e2f70f71dda 100644 (file)
@@ -4,7 +4,7 @@
 /* (C) 1999 Machine Vision Holdings, Inc.                      */
 /* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>         */
 
-/* $Id: docprobe.c,v 1.36 2003/05/23 11:29:34 dwmw2 Exp $      */
+/* $Id: docprobe.c,v 1.41 2003/12/03 10:19:57 dwmw2 Exp $      */
 
 
 
@@ -135,6 +135,9 @@ static inline int __init doccheck(unsigned long potential, unsigned long physadr
                 window, DOCControl);
 #endif /* !DOC_PASSIVE_PROBE */        
 
+       /* We need to read the ChipID register four times. For some
+          newer DiskOnChip 2000 units, the first three reads will
+          return the DiskOnChip Millennium ident. Don't ask. */
        ChipID = ReadDOC(window, ChipID);
   
        switch (ChipID) {
@@ -148,6 +151,12 @@ static inline int __init doccheck(unsigned long potential, unsigned long physadr
                break;
                
        case DOC_ChipID_DocMil:
+               /* Check for the new 2000 with Millennium ASIC */
+               ReadDOC(window, ChipID);
+               ReadDOC(window, ChipID);
+               if (ReadDOC(window, ChipID) != DOC_ChipID_DocMil)
+                       ChipID = DOC_ChipID_Doc2kTSOP;
+
                /* Check the TOGGLE bit in the ECC register */
                tmp  = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
                tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT;
@@ -191,7 +200,6 @@ static inline int __init doccheck(unsigned long potential, unsigned long physadr
                        tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT;
                        if (tmp != tmpb && tmp == tmpc)
                                        return ChipID;
-                       break;
                default:
                        break;
                }
@@ -199,8 +207,8 @@ static inline int __init doccheck(unsigned long potential, unsigned long physadr
 
        default:
 
-#ifndef CONFIG_MTD_DOCPROBE_55AA
-               printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
+#ifdef CONFIG_MTD_DOCPROBE_55AA
+               printk(KERN_DEBUG "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n",
                       ChipID, physadr);
 #endif
 #ifndef DOC_PASSIVE_PROBE
@@ -241,6 +249,12 @@ static void __init DoC_Probe(unsigned long physadr)
                return;
        
        if ((ChipID = doccheck(docptr, physadr))) {
+               if (ChipID == DOC_ChipID_Doc2kTSOP) {
+                       /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */
+                       printk(KERN_NOTICE "Refusing to drive DiskOnChip 2000 TSOP until Bad Block Table is correctly supported by INFTL\n");
+                       iounmap((void *)docptr);
+                       return;
+               }
                docfound = 1;
                mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL);
 
@@ -262,6 +276,12 @@ static void __init DoC_Probe(unsigned long physadr)
                sprintf(namebuf, "with ChipID %2.2X", ChipID);
 
                switch(ChipID) {
+               case DOC_ChipID_Doc2kTSOP:
+                       name="2000 TSOP";
+                       im_funcname = "DoC2k_init";
+                       im_modname = "doc2000";
+                       break;
+                       
                case DOC_ChipID_Doc2k:
                        name="2000";
                        im_funcname = "DoC2k_init";
index f60195ec5518e360821454e9272f3138da9389f2..d67ca4cb206f60e23ca11badc1acc0a5b8bf2be6 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART.
  *
- * $Id: lart.c,v 1.5 2003/05/20 21:03:07 dwmw2 Exp $
+ * $Id: lart.c,v 1.6 2004/07/14 17:21:38 dwmw2 Exp $
  *
  * Author: Abraham vd Merwe <abraham@2d3d.co.za>
  *
index e7f49a5ca5d3cde43d21a1571c66aca70d1d459a..3a331aa0b97479221750f4d47d2fbbe2b0dbba51 100644 (file)
@@ -1,12 +1,12 @@
 /*
- *      Copyright (c) 2001 Maciej W. Rozycki
+ *     Copyright (c) 2001 Maciej W. Rozycki
  *
- *      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 the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
+ *     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 the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
  *
- *     $Id: ms02-nv.c,v 1.4 2003/05/20 21:03:07 dwmw2 Exp $
+ *     $Id: ms02-nv.c,v 1.6 2003/08/19 09:25:36 dwmw2 Exp $
  */
 
 #include <linux/init.h>
@@ -29,7 +29,7 @@
 
 
 static char version[] __initdata =
-        "ms02-nv.c: v.1.0.0  13 Aug 2001  Maciej W. Rozycki.\n";
+       "ms02-nv.c: v.1.0.0  13 Aug 2001  Maciej W. Rozycki.\n";
 
 MODULE_AUTHOR("Maciej W. Rozycki <macro@ds2.pg.gda.pl>");
 MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver");
@@ -38,9 +38,9 @@ MODULE_LICENSE("GPL");
 
 /*
  * Addresses we probe for an MS02-NV at.  Modules may be located
- * at any 8MB boundary within a 0MB up to 112MB range or at any 32MB
- * boundary within a 0MB up to 448MB range.  We don't support a module
- * at 0MB, though.
+ * at any 8MiB boundary within a 0MiB up to 112MiB range or at any 32MiB
+ * boundary within a 0MiB up to 448MiB range.  We don't support a module
+ * at 0MiB, though.
  */
 static ulong ms02nv_addrs[] __initdata = {
        0x07000000, 0x06800000, 0x06000000, 0x05800000, 0x05000000,
@@ -130,7 +130,7 @@ static int __init ms02nv_init_one(ulong addr)
 
        int ret = -ENODEV;
 
-       /* The module decodes 8MB of address space. */
+       /* The module decodes 8MiB of address space. */
        mod_res = kmalloc(sizeof(*mod_res), GFP_KERNEL);
        if (!mod_res)
                return -ENOMEM;
@@ -233,7 +233,7 @@ static int __init ms02nv_init_one(ulong addr)
                goto err_out_csr_res;
        }
 
-       printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMB.\n",
+       printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMiB.\n",
                mtd->index, ms02nv_name, addr, size >> 20);
 
        mp->next = root_ms02nv_mtd;
@@ -293,12 +293,12 @@ static int __init ms02nv_init(void)
 
        switch (mips_machtype) {
        case MACH_DS5000_200:
-               csr = (volatile u32 *)KN02_CSR_ADDR;
+               csr = (volatile u32 *)KN02_CSR_BASE;
                if (*csr & KN02_CSR_BNK32M)
                        stride = 2;
                break;
        case MACH_DS5000_2X0:
-       case MACH_DS5000:
+       case MACH_DS5900:
                csr = (volatile u32 *)KN03_MCR_BASE;
                if (*csr & KN03_MCR_BNK32M)
                        stride = 2;
index fb1ec1056409806e5f8f4286215f48ddaf8ebfbe..8a6eef7cfee31d7bb0a8dc442b1309041f148468 100644 (file)
@@ -1,34 +1,96 @@
 /*
- *      Copyright (c) 2001 Maciej W. Rozycki
+ *     Copyright (c) 2001, 2003  Maciej W. Rozycki
  *
- *      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 the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
+ *     DEC MS02-NV (54-20948-01) battery backed-up NVRAM module for
+ *     DECstation/DECsystem 5000/2x0 and DECsystem 5900 and 5900/260
+ *     systems.
  *
- *     $Id: ms02-nv.h,v 1.1 2002/09/13 13:46:55 dwmw2 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 the Free Software Foundation; either version
+ *     2 of the License, or (at your option) any later version.
+ *
+ *     $Id: ms02-nv.h,v 1.3 2003/08/19 09:25:36 dwmw2 Exp $
  */
 
 #include <linux/ioport.h>
 #include <linux/mtd/mtd.h>
 
+/*
+ * Addresses are decoded as follows:
+ *
+ * 0x000000 - 0x3fffff SRAM
+ * 0x400000 - 0x7fffff CSR
+ *
+ * Within the SRAM area the following ranges are forced by the system
+ * firmware:
+ *
+ * 0x000000 - 0x0003ff diagnostic area, destroyed upon a reboot
+ * 0x000400 - ENDofRAM storage area, available to operating systems
+ *
+ * but we can't really use the available area right from 0x000400 as
+ * the first word is used by the firmware as a status flag passed
+ * from an operating system.  If anything but the valid data magic
+ * ID value is found, the firmware considers the SRAM clean, i.e.
+ * containing no valid data, and disables the battery resulting in
+ * data being erased as soon as power is switched off.  So the choice
+ * for the start address of the user-available is 0x001000 which is
+ * nicely page aligned.  The area between 0x000404 and 0x000fff may
+ * be used by the driver for own needs.
+ *
+ * The diagnostic area defines two status words to be read by an
+ * operating system, a magic ID to distinguish a MS02-NV board from
+ * anything else and a status information providing results of tests
+ * as well as the size of SRAM available, which can be 1MiB or 2MiB
+ * (that's what the firmware handles; no idea if 2MiB modules ever
+ * existed).
+ *
+ * The firmware only handles the MS02-NV board if installed in the
+ * last (15th) slot, so for any other location the status information
+ * stored in the SRAM cannot be relied upon.  But from the hardware
+ * point of view there is no problem using up to 14 such boards in a
+ * system -- only the 1st slot needs to be filled with a DRAM module.
+ * The MS02-NV board is ECC-protected, like other MS02 memory boards.
+ *
+ * The state of the battery as provided by the CSR is reflected on
+ * the two onboard LEDs.  When facing the battery side of the board,
+ * with the LEDs at the top left and the battery at the bottom right
+ * (i.e. looking from the back side of the system box), their meaning
+ * is as follows (the system has to be powered on):
+ *
+ * left LED            battery disable status: lit = enabled
+ * right LED           battery condition status: lit = OK
+ */
+
 /* MS02-NV iomem register offsets. */
 #define MS02NV_CSR             0x400000        /* control & status register */
 
+/* MS02-NV CSR status bits. */
+#define MS02NV_CSR_BATT_OK     0x01            /* battery OK */
+#define MS02NV_CSR_BATT_OFF    0x02            /* battery disabled */
+
+
 /* MS02-NV memory offsets. */
 #define MS02NV_DIAG            0x0003f8        /* diagnostic status */
 #define MS02NV_MAGIC           0x0003fc        /* MS02-NV magic ID */
-#define MS02NV_RAM             0x000400        /* general-purpose RAM start */
+#define MS02NV_VALID           0x000400        /* valid data magic ID */
+#define MS02NV_RAM             0x001000        /* user-exposed RAM start */
 
-/* MS02-NV diagnostic status constants. */
-#define MS02NV_DIAG_SIZE_MASK  0xf0            /* RAM size mask */
-#define MS02NV_DIAG_SIZE_SHIFT 0x10            /* RAM size shift (left) */
+/* MS02-NV diagnostic status bits. */
+#define MS02NV_DIAG_TEST       0x01            /* SRAM test done (?) */
+#define MS02NV_DIAG_RO         0x02            /* SRAM r/o test done */
+#define MS02NV_DIAG_RW         0x04            /* SRAM r/w test done */
+#define MS02NV_DIAG_FAIL       0x08            /* SRAM test failed */
+#define MS02NV_DIAG_SIZE_MASK  0xf0            /* SRAM size mask */
+#define MS02NV_DIAG_SIZE_SHIFT 0x10            /* SRAM size shift (left) */
 
 /* MS02-NV general constants. */
 #define MS02NV_ID              0x03021966      /* MS02-NV magic ID value */
+#define MS02NV_VALID_ID                0xbd100248      /* valid data magic ID value */
 #define MS02NV_SLOT_SIZE       0x800000        /* size of the address space
                                                   decoded by the module */
 
+
 typedef volatile u32 ms02nv_uint;
 
 struct ms02nv_private {
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
new file mode 100644 (file)
index 0000000..5f66e9b
--- /dev/null
@@ -0,0 +1,362 @@
+/**
+ *
+ * $Id: phram.c,v 1.1 2003/08/21 17:52:30 joern Exp $
+ *
+ * Copyright (c) Jochen Schaeuble <psionic@psionic.de>
+ * 07/2003     rewritten by Joern Engel <joern@wh.fh-wedel.de>
+ *
+ * DISCLAIMER:  This driver makes use of Rusty's excellent module code,
+ * so it will not work for 2.4 without changes and it wont work for 2.4
+ * as a module without major changes.  Oh well!
+ *
+ * Usage:
+ *
+ * one commend line parameter per device, each in the form:
+ *   phram=<name>,<start>,<len>
+ * <name> may be up to 63 characters.
+ * <start> and <len> can be octal, decimal or hexadecimal.  If followed
+ * by "k", "M" or "G", the numbers will be interpreted as kilo, mega or
+ * gigabytes.
+ *
+ */
+
+#include <asm/io.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mtd/mtd.h>
+
+#define ERROR(fmt, args...) printk(KERN_ERR "phram: " fmt , ## args)
+
+struct phram_mtd_list {
+       struct list_head list;
+       struct mtd_info *mtdinfo;
+};
+
+static LIST_HEAD(phram_list);
+
+
+
+int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+       u_char *start = (u_char *)mtd->priv;
+
+       if (instr->addr + instr->len > mtd->size)
+               return -EINVAL;
+       
+       memset(start + instr->addr, 0xff, instr->len);
+
+       /* This'll catch a few races. Free the thing before returning :) 
+        * I don't feel at all ashamed. This kind of thing is possible anyway
+        * with flash, but unlikely.
+        */
+
+       instr->state = MTD_ERASE_DONE;
+
+       if (instr->callback)
+               (*(instr->callback))(instr);
+       else
+               kfree(instr);
+
+       return 0;
+}
+
+int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
+               size_t *retlen, u_char **mtdbuf)
+{
+       u_char *start = (u_char *)mtd->priv;
+
+       if (from + len > mtd->size)
+               return -EINVAL;
+       
+       *mtdbuf = start + from;
+       *retlen = len;
+       return 0;
+}
+
+void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+{
+}
+
+int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
+               size_t *retlen, u_char *buf)
+{
+       u_char *start = (u_char *)mtd->priv;
+
+       if (from + len > mtd->size)
+               return -EINVAL;
+       
+       memcpy(buf, start + from, len);
+
+       *retlen = len;
+       return 0;
+}
+
+int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
+               size_t *retlen, const u_char *buf)
+{
+       u_char *start = (u_char *)mtd->priv;
+
+       if (to + len > mtd->size)
+               return -EINVAL;
+       
+       memcpy(start + to, buf, len);
+
+       *retlen = len;
+       return 0;
+}
+
+
+
+static void unregister_devices(void)
+{
+       struct phram_mtd_list *this;
+
+       list_for_each_entry(this, &phram_list, list) {
+               del_mtd_device(this->mtdinfo);
+               iounmap(this->mtdinfo->priv);
+               kfree(this->mtdinfo);
+               kfree(this);
+       }
+}
+
+static int register_device(char *name, unsigned long start, unsigned long len)
+{
+       struct phram_mtd_list *new;
+       int ret = -ENOMEM;
+
+       new = kmalloc(sizeof(*new), GFP_KERNEL);
+       if (!new)
+               goto out0;
+
+       new->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+       if (!new->mtdinfo)
+               goto out1;
+       
+       memset(new->mtdinfo, 0, sizeof(struct mtd_info));
+
+       ret = -EIO;
+       new->mtdinfo->priv = ioremap(start, len);
+       if (!new->mtdinfo->priv) {
+               ERROR("ioremap failed\n");
+               goto out2;
+       }
+
+
+       new->mtdinfo->name = name;
+       new->mtdinfo->size = len;
+       new->mtdinfo->flags = MTD_CAP_RAM | MTD_ERASEABLE | MTD_VOLATILE;
+        new->mtdinfo->erase = phram_erase;
+       new->mtdinfo->point = phram_point;
+       new->mtdinfo->unpoint = phram_unpoint;
+       new->mtdinfo->read = phram_read;
+       new->mtdinfo->write = phram_write;
+       new->mtdinfo->owner = THIS_MODULE;
+       new->mtdinfo->type = MTD_RAM;
+       new->mtdinfo->erasesize = 0x0;
+
+       ret = -EAGAIN;
+       if (add_mtd_device(new->mtdinfo)) {
+               ERROR("Failed to register new device\n");
+               goto out3;
+       }
+
+       list_add_tail(&new->list, &phram_list);
+       return 0;       
+
+out3:
+       iounmap(new->mtdinfo->priv);
+out2:
+       kfree(new->mtdinfo);
+out1:
+       kfree(new);
+out0:
+       return ret;
+}
+
+static int ustrtoul(const char *cp, char **endp, unsigned int base)
+{
+       unsigned long result = simple_strtoul(cp, endp, base);
+
+       switch (**endp) {
+       case 'G':
+               result *= 1024;
+       case 'M':
+               result *= 1024;
+       case 'k':
+               result *= 1024;
+               endp++;
+       }
+       return result;
+}
+
+static int parse_num32(uint32_t *num32, const char *token)
+{
+       char *endp;
+       unsigned long n;
+
+       n = ustrtoul(token, &endp, 0);
+       if (*endp)
+               return -EINVAL;
+
+       *num32 = n;
+       return 0;
+}
+
+static int parse_name(char **pname, const char *token)
+{
+       size_t len;
+       char *name;
+
+       len = strlen(token) + 1;
+       if (len > 64)
+               return -ENOSPC;
+
+       name = kmalloc(len, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+
+       strcpy(name, token);
+
+       *pname = name;
+       return 0;
+}
+
+#define parse_err(fmt, args...) do {   \
+       ERROR(fmt , ## args);   \
+       return 0;               \
+} while (0)
+
+static int phram_setup(const char *val, struct kernel_param *kp)
+{
+       char buf[64+12+12], *str = buf;
+       char *token[3];
+       char *name;
+       uint32_t start;
+       uint32_t len;
+       int i, ret;
+
+       if (strnlen(val, sizeof(str)) >= sizeof(str))
+               parse_err("parameter too long\n");
+
+       strcpy(str, val);
+
+       for (i=0; i<3; i++)
+               token[i] = strsep(&str, ",");
+
+       if (str)
+               parse_err("too many arguments\n");
+
+       if (!token[2])
+               parse_err("not enough arguments\n");
+
+       ret = parse_name(&name, token[0]);
+       if (ret == -ENOMEM)
+               parse_err("out of memory\n");
+       if (ret == -ENOSPC)
+               parse_err("name too long\n");
+       if (ret)
+               return 0;
+
+       ret = parse_num32(&start, token[1]);
+       if (ret)
+               parse_err("illegal start address\n");
+
+       ret = parse_num32(&len, token[2]);
+       if (ret)
+               parse_err("illegal device length\n");
+
+       register_device(name, start, len);
+
+       return 0;
+}
+
+module_param_call(phram, phram_setup, NULL, NULL, 000);
+MODULE_PARM_DESC(phram, "Memory region to map. \"map=<name>,<start><length>\"");
+
+/*
+ * Just for compatibility with slram, this is horrible and should go someday.
+ */
+static int __init slram_setup(const char *val, struct kernel_param *kp)
+{
+       char buf[256], *str = buf;
+
+       if (!val || !val[0])
+               parse_err("no arguments to \"slram=\"\n");
+
+       if (strnlen(val, sizeof(str)) >= sizeof(str))
+               parse_err("parameter too long\n");
+
+       strcpy(str, val);
+
+       while (str) {
+               char *token[3];
+               char *name;
+               uint32_t start;
+               uint32_t len;
+               int i, ret;
+
+               for (i=0; i<3; i++) {
+                       token[i] = strsep(&str, ",");
+                       if (token[i])
+                               continue;
+                       parse_err("wrong number of arguments to \"slram=\"\n");
+               }
+
+               /* name */
+               ret = parse_name(&name, token[0]);
+               if (ret == -ENOMEM)
+                       parse_err("of memory\n");
+               if (ret == -ENOSPC)
+                       parse_err("too long\n");
+               if (ret)
+                       return 1;
+
+               /* start */
+               ret = parse_num32(&start, token[1]);
+               if (ret)
+                       parse_err("illegal start address\n");
+
+               /* len */
+               if (token[2][0] == '+')
+                       ret = parse_num32(&len, token[2] + 1);
+               else
+                       ret = parse_num32(&len, token[2]);
+
+               if (ret)
+                       parse_err("illegal device length\n");
+
+               if (token[2][0] != '+') {
+                       if (len < start)
+                               parse_err("end < start\n");
+                       len -= start;
+               }
+
+               register_device(name, start, len);
+       }
+       return 1;
+}
+
+module_param_call(slram, slram_setup, NULL, NULL, 000);
+MODULE_PARM_DESC(slram, "List of memory regions to map. \"map=<name>,<start><length/end>\"");
+
+
+int __init init_phram(void)
+{
+       printk(KERN_ERR "phram loaded\n");
+       return 0;
+}
+
+static void __exit cleanup_phram(void)
+{
+       unregister_devices();
+}
+
+module_init(init_phram);
+module_exit(cleanup_phram);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedel.de>");
+MODULE_DESCRIPTION("MTD driver for physical RAM");
index 14308850afbf8c59fcf747395807168ec3d1a394..80d4287564553eeaa656476997d435f4f563d290 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: pmc551.c,v 1.24 2003/05/20 21:03:08 dwmw2 Exp $
+ * $Id: pmc551.c,v 1.26 2004/07/14 17:25:07 dwmw2 Exp $
  *
  * PMC551 PCI Mezzanine Ram Device
  *
index 4e2d14ce4e1e14488835cd3717f0728268b9491b..b9892acfe206663511d791e916e0e57fa506decf 100644 (file)
@@ -1,5 +1,5 @@
 /* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $
+ * $Id: ftl.c,v 1.52 2003/08/11 09:00:44 dwmw2 Exp $
  *
  * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
@@ -1093,7 +1093,7 @@ struct mtd_blktrans_ops ftl_tr = {
 
 int init_ftl(void)
 {
-       DEBUG(0, "$Id: ftl.c,v 1.51 2003/06/23 12:00:08 dwmw2 Exp $\n");
+       DEBUG(0, "$Id: ftl.c,v 1.52 2003/08/11 09:00:44 dwmw2 Exp $\n");
 
        return register_mtd_blktrans(&ftl_tr);
 }
index 2417fba1b0457a4df54025d06d558fc302b123b9..bc7e2bf56ca78bbfc192a1252688e9413e166e41 100644 (file)
@@ -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.16 2004/07/12 12:34:58 dwmw2 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
@@ -55,9 +55,19 @@ 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);
 
        inftl = kmalloc(sizeof(*inftl), GFP_KERNEL);
@@ -72,6 +82,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");
@@ -284,21 +296,22 @@ 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); 
+                               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 +339,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 {
@@ -668,7 +680,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 {
@@ -754,7 +765,7 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
        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,"
@@ -778,11 +789,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 {
@@ -846,9 +859,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;
@@ -881,7 +893,7 @@ extern char inftlmountrev[];
 
 int __init init_inftl(void)
 {
-       printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.14 $, "
+       printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.16 $, "
                "inftlmount.c %s\n", inftlmountrev);
 
        return register_mtd_blktrans(&inftl_tr);
index 042c4eeadf8ec6100b978a9e1b310fc25702306e..a7075c2a22c9e63a3c7e2de6b572914fcb20819e 100644 (file)
@@ -8,7 +8,7 @@
  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: inftlmount.c,v 1.11 2003/06/23 07:39:21 dwmw2 Exp $
+ * $Id: inftlmount.c,v 1.13 2004/06/28 16:06:36 dbrown 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
@@ -41,7 +41,7 @@
 #include <linux/mtd/inftl.h>
 #include <linux/mtd/compatmac.h>
 
-char inftlmountrev[]="$Revision: 1.11 $";
+char inftlmountrev[]="$Revision: 1.13 $";
 
 /*
  * find_boot_record: Find the INFTL Media Header and its Spare copy which
@@ -54,7 +54,7 @@ static int find_boot_record(struct INFTLrecord *inftl)
 {
        struct inftl_unittail h1;
        //struct inftl_oob oob;
-       unsigned int i, block, boot_record_count = 0;
+       unsigned int i, block;
        u8 buf[SECTORSIZE];
        struct INFTLMediaHeader *mh = &inftl->MediaHdr;
        struct INFTLPartition *ip;
@@ -72,7 +72,6 @@ static int find_boot_record(struct INFTLrecord *inftl)
         inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
 
        inftl->MediaUnit = BLOCK_NIL;
-       inftl->SpareMediaUnit = BLOCK_NIL;
 
        /* Search for a valid boot record */
        for (block = 0; block < inftl->nb_blocks; block++) {
@@ -82,8 +81,11 @@ static int find_boot_record(struct INFTLrecord *inftl)
                 * Check for BNAND header first. Then whinge if it's found
                 * but later checks fail.
                 */
-               if ((ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize,
-                   SECTORSIZE, &retlen, buf))) {
+               ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize,
+                   SECTORSIZE, &retlen, buf);
+               /* We ignore ret in case the ECC of the MediaHeader is invalid
+                  (which is apparently acceptable) */
+               if (retlen != SECTORSIZE) {
                        static int warncount = 5;
 
                        if (warncount) {
@@ -114,36 +116,28 @@ static int find_boot_record(struct INFTLrecord *inftl)
                        continue;
                }
 
-               if (boot_record_count) {
-                       /*
-                        * We've already processed one. So we just check if
-                        * this one is the same as the first one we found.
-                        */
-                       if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) {
-                               printk(KERN_WARNING "INFTL: Media Headers at "
-                                       "0x%x and 0x%x disagree.\n",
-                                       inftl->MediaUnit * inftl->EraseSize,
-                                       block * inftl->EraseSize);
-                               return -1;
-                       }
-                       if (boot_record_count == 1)
-                               inftl->SpareMediaUnit = block;
-
-                       /*
-                        * Mark this boot record (INFTL MediaHeader) block as
-                        * reserved.
-                        */
-                       inftl->PUtable[block] = BLOCK_RESERVED;
-
-                       boot_record_count++;
-                       continue;
-               }
 
                /*
                 * This is the first we've seen.
                 * Copy the media header structure into place.
                 */
                memcpy(mh, buf, sizeof(struct INFTLMediaHeader));
+
+               /* Read the spare media header at offset 4096 */
+               MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize + 4096,
+                   SECTORSIZE, &retlen, buf);
+               if (retlen != SECTORSIZE) {
+                       printk(KERN_WARNING "INFTL: Unable to read spare "
+                              "Media Header\n");
+                       return -1;
+               }
+               /* Check if this one is the same as the first one we found. */
+               if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) {
+                       printk(KERN_WARNING "INFTL: Primary and spare Media "
+                              "Headers disagree.\n");
+                       return -1;
+               }
+
                mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks);
                mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions);
                mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions);
@@ -197,8 +191,9 @@ static int find_boot_record(struct INFTLrecord *inftl)
                                "UnitSizeFactor 0x%02x is experimental\n",
                                mh->BlockMultiplierBits);
                        inftl->EraseSize = inftl->mbd.mtd->erasesize <<
-                               (0xff - mh->BlockMultiplierBits);
+                               mh->BlockMultiplierBits;
                        inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize;
+                       block >>= mh->BlockMultiplierBits;
                }
 
                /* Scan the partitions */
@@ -317,34 +312,23 @@ static int find_boot_record(struct INFTLrecord *inftl)
                /* Mark this boot record (NFTL MediaHeader) block as reserved */
                inftl->PUtable[block] = BLOCK_RESERVED;
 
-#if 0
                /* Read Bad Erase Unit Table and modify PUtable[] accordingly */
                for (i = 0; i < inftl->nb_blocks; i++) {
-                       if ((i & (SECTORSIZE - 1)) == 0) {
-                               /* read one sector for every SECTORSIZE of blocks */
-                               if ((ret = MTD_READECC(inftl->mbd.mtd,
-                                   block * inftl->EraseSize + i + SECTORSIZE,
-                                   SECTORSIZE, &retlen, buf,
-                                   (char *)&oob, NULL)) < 0) {
-                                       printk(KERN_WARNING "INFTL: read of "
-                                               "bad sector table failed "
-                                               "(err %d)\n", ret);
-                                       kfree(inftl->VUtable);
-                                       kfree(inftl->PUtable);
-                                       return -1;
-                               }
+                       int physblock;
+                       /* If any of the physical eraseblocks are bad, don't
+                          use the unit. */
+                       for (physblock = 0; physblock < inftl->EraseSize; physblock += inftl->mbd.mtd->erasesize) {
+                               if (inftl->mbd.mtd->block_isbad(inftl->mbd.mtd, i * inftl->EraseSize + physblock))
+                                       inftl->PUtable[i] = BLOCK_RESERVED;
                        }
-                       /* Mark the Bad Erase Unit as RESERVED in PUtable */
-                       if (buf[i & (SECTORSIZE - 1)] != 0xff)
-                               inftl->PUtable[i] = BLOCK_RESERVED;
                }
-#endif
 
                inftl->MediaUnit = block;
-               boot_record_count++;
+               return 0;
        }
-               
-       return boot_record_count ? 0 : -1;
+
+       /* Not found. */
+       return -1;
 }
 
 static int memcmpb(void *a, int c, int n)
@@ -365,27 +349,20 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
        int len, int check_oob)
 {
        int i, retlen;
-       u8 buf[SECTORSIZE];
+       u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize];
 
        DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=0x%x,"
                "address=0x%x,len=%d,check_oob=%d)\n", (int)inftl,
                address, len, check_oob);
 
        for (i = 0; i < len; i += SECTORSIZE) {
-               /*
-                * We want to read the sector without ECC check here since a
-                * free sector does not have ECC syndrome on it yet.
-                */
-               if (MTD_READ(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0)
+               if (MTD_READECC(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &inftl->oobinfo) < 0)
                        return -1;
                if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
                        return -1;
 
                if (check_oob) {
-                       if (MTD_READOOB(inftl->mbd.mtd, address,
-                           inftl->mbd.mtd->oobsize, &retlen, buf) < 0)
-                               return -1;
-                       if (memcmpb(buf, 0xff, inftl->mbd.mtd->oobsize) != 0)
+                       if (memcmpb(buf + SECTORSIZE, 0xff, inftl->mbd.mtd->oobsize) != 0)
                                return -1;
                }
                address += SECTORSIZE;
@@ -402,52 +379,62 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
  * Return: 0 when succeed, -1 on error.
  *
  * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? 
- *       2. UnitSizeFactor != 0xFF
  */
 int INFTL_formatblock(struct INFTLrecord *inftl, int block)
 {
        int retlen;
        struct inftl_unittail uci;
        struct erase_info *instr = &inftl->instr;
+       int physblock;
 
        DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=0x%x,"
                "block=%d)\n", (int)inftl, block);
 
        memset(instr, 0, sizeof(struct erase_info));
 
+       /* FIXME: Shouldn't we be setting the 'discarded' flag to zero
+          _first_? */
+
        /* Use async erase interface, test return code */
        instr->addr = block * inftl->EraseSize;
-       instr->len = inftl->EraseSize;
-       MTD_ERASE(inftl->mbd.mtd, instr);
+       instr->len = inftl->mbd.mtd->erasesize;
+       /* Erase one physical eraseblock at a time, even though the NAND api
+          allows us to group them.  This way we if we have a failure, we can
+          mark only the failed block in the bbt. */
+       for (physblock = 0; physblock < inftl->EraseSize; physblock += instr->len, instr->addr += instr->len) {
+               MTD_ERASE(inftl->mbd.mtd, instr);
+
+               if (instr->state == MTD_ERASE_FAILED) {
+                       printk(KERN_WARNING "INFTL: error while formatting block %d\n",
+                               block);
+                       goto fail;
+               }
 
-       if (instr->state == MTD_ERASE_FAILED) {
                /*
-                * Could not format, FixMe: We should update the BadUnitTable 
-                * both in memory and on disk.
-                */
-               printk(KERN_WARNING "INFTL: error while formatting block %d\n",
-                       block);
-               return -1;
+               * Check the "freeness" of Erase Unit before updating metadata.
+               * FixMe: is this check really necessary? Since we have check the
+               *        return code after the erase operation.
+               */
+               if (check_free_sectors(inftl, instr->addr, instr->len, 1) != 0)
+                       goto fail;
        }
 
-       /*
-        * Check the "freeness" of Erase Unit before updating metadata.
-        * FixMe: is this check really necessary? Since we have check the
-        *        return code after the erase operation.
-        */
-       if (check_free_sectors(inftl, instr->addr, inftl->EraseSize, 1) != 0)
-               return -1;
-
        uci.EraseMark = cpu_to_le16(ERASE_MARK);
        uci.EraseMark1 = cpu_to_le16(ERASE_MARK);
        uci.Reserved[0] = 0;
        uci.Reserved[1] = 0;
        uci.Reserved[2] = 0;
        uci.Reserved[3] = 0;
-       if (MTD_WRITEOOB(inftl->mbd.mtd, block * inftl->EraseSize + SECTORSIZE * 2 +
+       instr->addr = block * inftl->EraseSize + SECTORSIZE * 2;
+       if (MTD_WRITEOOB(inftl->mbd.mtd, instr->addr +
            8, 8, &retlen, (char *)&uci) < 0)
-               return -1;
+               goto fail;
        return 0;
+fail:
+       /* could not format, update the bad block table (caller is responsible
+          for setting the PUtable to BLOCK_RESERVED on failure) */
+       inftl->mbd.mtd->block_markbad(inftl->mbd.mtd, instr->addr);
+       return -1;
 }
 
 /*
@@ -472,7 +459,6 @@ static void format_chain(struct INFTLrecord *inftl, unsigned int first_block)
                if (INFTL_formatblock(inftl, block) < 0) {
                        /*
                         * Cannot format !!!! Mark it as Bad Unit,
-                        * FixMe: update the BadUnitTable on disk.
                         */
                        inftl->PUtable[block] = BLOCK_RESERVED;
                } else {
index e45b3fc99fdedd274fc37a771b797280f96597c9..b134315ab51854d4416cd677b0295ef1e4b60af3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtd_blkdevs.c,v 1.16 2003/06/23 13:34:43 dwmw2 Exp $
+ * $Id: mtd_blkdevs.c,v 1.22 2004/07/12 12:35:28 dwmw2 Exp $
  *
  * (C) 2003 David Woodhouse <dwmw2@infradead.org>
  *
@@ -295,7 +295,10 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
        snprintf(gd->devfs_name, sizeof(gd->devfs_name),
                 "%s/%c", tr->name, (tr->part_bits?'a':'0') + new->devnum);
 
-       set_capacity(gd, new->size);
+       /* 2.5 has capacity in units of 512 bytes while still
+          having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */
+       set_capacity(gd, (new->size * new->blksize) >> 9);
+
        gd->private_data = new;
        new->blkcore_priv = gd;
        gd->queue = tr->blkcore_priv->rq;
index fd096eaea9237f716b0bdf162505a5a1b11fb60b..c91d9701ef710e86a270cf29553d5a656a5466d5 100644 (file)
@@ -1,7 +1,7 @@
 /* 
  * Direct MTD block device access
  *
- * $Id: mtdblock.c,v 1.63 2003/06/23 12:00:08 dwmw2 Exp $
+ * $Id: mtdblock.c,v 1.64 2003/10/04 17:14:14 dwmw2 Exp $
  *
  * (C) 2000-2003 Nicolas Pitre <nico@cam.org>
  * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
index b1a9257b9b75d3c6b6b956a72fdd664fdd1da844..02b93f9c266b400f90ea5f1673f839476c70fe31 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdchar.c,v 1.54 2003/05/21 10:50:43 dwmw2 Exp $
+ * $Id: mtdchar.c,v 1.62 2004/07/14 13:20:42 dwmw2 Exp $
  *
  * Character-device access to raw MTD devices.
  *
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/compatmac.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 
 #ifdef CONFIG_DEVFS_FS
 #include <linux/devfs_fs_kernel.h>
-static void mtd_notify_add(struct mtd_info* mtd);
-static void mtd_notify_remove(struct mtd_info* mtd);
+
+static void mtd_notify_add(struct mtd_info* mtd)
+{
+       if (!mtd)
+               return;
+
+       devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
+                     S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index);
+               
+       devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
+                     S_IFCHR | S_IRUGO, "mtd/%dro", mtd->index);
+}
+
+static void mtd_notify_remove(struct mtd_info* mtd)
+{
+       if (!mtd)
+               return;
+       devfs_remove("mtd/%d", mtd->index);
+       devfs_remove("mtd/%dro", mtd->index);
+}
 
 static struct mtd_notifier notifier = {
        .add    = mtd_notify_add,
        .remove = mtd_notify_remove,
 };
 
+static inline void mtdchar_devfs_init(void)
+{
+       devfs_mk_dir("mtd");
+       register_mtd_user(&notifier);
+}
+
+static inline void mtdchar_devfs_exit(void)
+{
+       unregister_mtd_user(&notifier);
+       devfs_remove("mtd");
+}
+#else /* !DEVFS */
+#define mtdchar_devfs_init() do { } while(0)
+#define mtdchar_devfs_exit() do { } while(0)
 #endif
 
 static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
@@ -298,7 +331,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
 
                        memset (erase,0,sizeof(struct erase_info));
                        if (copy_from_user(&erase->addr, argp,
-                                          2 * sizeof(u_long))) {
+                                   sizeof(struct erase_info_user))) {
                                kfree(erase);
                                return -EFAULT;
                        }
@@ -366,7 +399,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
 
                ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf);
 
-               if (copy_to_user(argp + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
+               if (copy_to_user(argp + sizeof(uint32_t), &retlen, sizeof(uint32_t)))
                        ret = -EFAULT;
 
                kfree(databuf);
@@ -400,7 +433,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                
                ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);
 
-               if (copy_to_user(argp + sizeof(u_int32_t), &retlen, sizeof(u_int32_t)))
+               if (put_user(retlen, (uint32_t __user *)argp))
                        ret = -EFAULT;
                else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
                        ret = -EFAULT;
@@ -411,29 +444,29 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
 
        case MEMLOCK:
        {
-               unsigned long adrs[2];
+               struct erase_info_user info;
 
-               if (copy_from_user(adrs, argp, 2* sizeof(unsigned long)))
+               if (copy_from_user(&info, argp, sizeof(info)))
                        return -EFAULT;
 
                if (!mtd->lock)
                        ret = -EOPNOTSUPP;
                else
-                       ret = mtd->lock(mtd, adrs[0], adrs[1]);
+                       ret = mtd->lock(mtd, info.start, info.length);
                break;
        }
 
        case MEMUNLOCK:
        {
-               unsigned long adrs[2];
+               struct erase_info_user info;
 
-               if (copy_from_user(adrs, argp, 2* sizeof(unsigned long)))
+               if (copy_from_user(&info, argp, sizeof(info)))
                        return -EFAULT;
 
                if (!mtd->unlock)
                        ret = -EOPNOTSUPP;
                else
-                       ret = mtd->unlock(mtd, adrs[0], adrs[1]);
+                       ret = mtd->unlock(mtd, info.start, info.length);
                break;
        }
 
@@ -443,7 +476,40 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
                        return -EFAULT;
                break;
        }
+
+       case MEMGETOOBSEL:
+       {
+               if (copy_to_user(argp, &(mtd->oobinfo), sizeof(struct nand_oobinfo)))
+                       return -EFAULT;
+               break;
+       }
+
+       case MEMGETBADBLOCK:
+       {
+               loff_t offs;
                
+               if (copy_from_user(&offs, argp, sizeof(loff_t)))
+                       return -EFAULT;
+               if (!mtd->block_isbad)
+                       ret = -EOPNOTSUPP;
+               else
+                       return mtd->block_isbad(mtd, offs);
+               break;
+       }
+
+       case MEMSETBADBLOCK:
+       {
+               loff_t offs;
+
+               if (copy_from_user(&offs, argp, sizeof(loff_t)))
+                       return -EFAULT;
+               if (!mtd->block_markbad)
+                       ret = -EOPNOTSUPP;
+               else
+                       return mtd->block_markbad(mtd, offs);
+               break;
+       }
+
        default:
                DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO);
                ret = -ENOTTY;
@@ -462,30 +528,6 @@ static struct file_operations mtd_fops = {
        .release        = mtd_close,
 };
 
-
-#ifdef CONFIG_DEVFS_FS
-/* Notification that a new device has been added. Create the devfs entry for
- * it. */
-
-static void mtd_notify_add(struct mtd_info* mtd)
-{
-       if (!mtd)
-               return;
-       devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
-                       S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index);
-       devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
-                       S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%dro", mtd->index);
-}
-
-static void mtd_notify_remove(struct mtd_info* mtd)
-{
-       if (!mtd)
-               return;
-       devfs_remove("mtd/%d", mtd->index);
-       devfs_remove("mtd/%dro", mtd->index);
-}
-#endif
-
 static int __init init_mtdchar(void)
 {
        if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) {
@@ -494,20 +536,13 @@ static int __init init_mtdchar(void)
                return -EAGAIN;
        }
 
-#ifdef CONFIG_DEVFS_FS
-       devfs_mk_dir("mtd");
-
-       register_mtd_user(&notifier);
-#endif
+       mtdchar_devfs_init();
        return 0;
 }
 
 static void __exit cleanup_mtdchar(void)
 {
-#ifdef CONFIG_DEVFS_FS
-       unregister_mtd_user(&notifier);
-       devfs_remove("mtd");
-#endif
+       mtdchar_devfs_exit();
        unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
 }
 
index 5a4f02cc1d8581eb07ff5758ce262c1831cd9450..8f66d093c80d5b15084dc233b8cb05e718e4ac76 100644 (file)
@@ -7,7 +7,7 @@
  *
  * This code is GPL
  *
- * $Id: mtdconcat.c,v 1.8 2003/06/30 11:01:26 dwmw2 Exp $
+ * $Id: mtdconcat.c,v 1.9 2004/06/30 15:17:41 dbrown Exp $
  */
 
 #include <linux/module.h>
@@ -391,7 +391,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
        struct mtd_concat *concat = CONCAT(mtd);
        struct mtd_info *subdev;
        int i, err;
-       u_int32_t length;
+       u_int32_t length, offset = 0;
        struct erase_info *erase;
 
        if (!(mtd->flags & MTD_WRITEABLE))
@@ -450,6 +450,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
                        return -EINVAL;
        }
 
+       instr->fail_addr = 0xffffffff;
+
        /* make a local copy of instr to avoid modifying the caller's struct */
        erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
 
@@ -465,10 +467,12 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
         */
        for (i = 0; i < concat->num_subdev; i++) {
                subdev = concat->subdev[i];
-               if (subdev->size <= erase->addr)
+               if (subdev->size <= erase->addr) {
                        erase->addr -= subdev->size;
-               else
+                       offset += subdev->size;
+               } else {
                        break;
+               }
        }
 
        /* must never happen since size limit has been verified above */
@@ -497,6 +501,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
                         * block alignment has been checked above */
                        if (err == -EINVAL)
                                BUG();
+                       if (erase->fail_addr != 0xffffffff)
+                               instr->fail_addr = erase->fail_addr + offset;
                        break;
                }
                /*
@@ -508,12 +514,13 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
                 * current subdevice, i.e. at offset zero.
                 */
                erase->addr = 0;
+               offset += subdev->size;
        }
+       instr->state = erase->state;
        kfree(erase);
        if (err)
                return err;
 
-       instr->state = MTD_ERASE_DONE;
        if (instr->callback)
                instr->callback(instr);
        return 0;
index 12775563f4dfa50d8cd46f063cf16190c96981ce..9c5af1dd7cf608d89957492da590c096fb3d5f45 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: mtdcore.c,v 1.39 2003/05/21 15:15:03 dwmw2 Exp $
+ * $Id: mtdcore.c,v 1.42 2004/07/13 10:21:13 dwmw2 Exp $
  *
  * Core registration and callback routines for MTD
  * drivers and users.
@@ -334,10 +334,7 @@ static int mtd_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
 /* Support for /proc/mtd */
 
 #ifdef CONFIG_PROC_FS
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
 static struct proc_dir_entry *proc_mtd;
-#endif
 
 static inline int mtd_proc_info (char *buf, int i)
 {
@@ -350,13 +347,8 @@ static inline int mtd_proc_info (char *buf, int i)
                       this->erasesize, this->name);
 }
 
-static int mtd_read_proc ( char *page, char **start, off_t off,int count
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
-                       ,int *eof, void *data_unused
-#else
-                        ,int unused
-#endif
-                       )
+static int mtd_read_proc (char *page, char **start, off_t off, int count,
+                         int *eof, void *data_unused)
 {
        int len, l, i;
         off_t   begin = 0;
@@ -376,9 +368,7 @@ static int mtd_read_proc ( char *page, char **start, off_t off,int count
                 }
         }
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
         *eof = 1;
-#endif
 
 done:
        up(&mtd_table_mutex);
@@ -388,18 +378,6 @@ done:
         return ((count < begin+len-off) ? count : begin+len-off);
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
-struct proc_dir_entry mtd_proc_entry = {
-        0,                 /* low_ino: the inode -- dynamic */
-        3, "mtd",     /* len of name and name */
-        S_IFREG | S_IRUGO, /* mode */
-        1, 0, 0,           /* nlinks, owner, group */
-        0, NULL,           /* size - unused; operations -- use default */
-        &mtd_read_proc,   /* function used to read data */
-        /* nothing more */
-    };
-#endif
-
 #endif /* CONFIG_PROC_FS */
 
 /*====================================================================*/
@@ -408,16 +386,8 @@ struct proc_dir_entry mtd_proc_entry = {
 int __init init_mtd(void)
 {
 #ifdef CONFIG_PROC_FS
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
        if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))
-         proc_mtd->read_proc = mtd_read_proc;
-#else
-        proc_register_dynamic(&proc_root,&mtd_proc_entry);
-#endif
-#endif
-
-#if LINUX_VERSION_CODE < 0x20212
-       init_mtd_devices();
+               proc_mtd->read_proc = mtd_read_proc;
 #endif
 
 #ifdef CONFIG_PM
@@ -436,12 +406,8 @@ static void __exit cleanup_mtd(void)
 #endif
 
 #ifdef CONFIG_PROC_FS
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
         if (proc_mtd)
-          remove_proc_entry( "mtd", NULL);
-#else
-        proc_unregister(&proc_root,mtd_proc_entry.low_ino);
-#endif
+               remove_proc_entry( "mtd", NULL);
 #endif
 }
 
index ea709d7cf463926c6877e8ccf1cffc0aed42b38d..4102a67978d686b3e31ad3a1c688ecca166f48b4 100644 (file)
@@ -1,7 +1,7 @@
 /* Linux driver for NAND Flash Translation Layer      */
 /* (c) 1999 Machine Vision Holdings, Inc.             */
 /* Author: David Woodhouse <dwmw2@infradead.org>      */
-/* $Id: nftlcore.c,v 1.94 2003/06/23 12:00:08 dwmw2 Exp $ */
+/* $Id: nftlcore.c,v 1.96 2004/06/28 13:52:55 dbrown Exp $ */
 
 /*
   The contents of this file are distributed under the GNU General
@@ -43,9 +43,19 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
        struct NFTLrecord *nftl;
        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
+"NFTL 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_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name);
 
        nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
@@ -60,6 +70,8 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
        nftl->mbd.devnum = -1;
        nftl->mbd.blksize = 512;
        nftl->mbd.tr = tr;
+       memcpy(&nftl->oobinfo, &mtd->oobinfo, sizeof(struct nand_oobinfo));
+       nftl->oobinfo.useecc = MTD_NANDECC_PLACEONLY;
 
         if (NFTL_mount(nftl) < 0) {
                printk(KERN_WARNING "NFTL: could not mount device\n");
@@ -350,17 +362,19 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
                 if (BlockMap[block] == BLOCK_NIL)
                         continue;
                 
-                ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
-                                 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
+                ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512),
+                                 512, &retlen, movebuf); 
                 if (ret < 0) {
-                    ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
+                    ret = MTD_READ(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block])
                                       + (block * 512), 512, &retlen,
-                                      movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); 
+                                      movebuf); 
                     if (ret != -EIO) 
                         printk("Error went away on retry.\n");
                 }
+               memset(&oob, 0xff, sizeof(struct nftl_oob));
+               oob.b.Status = oob.b.Status1 = SECTOR_USED;
                 MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512),
-                             512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP);
+                             512, &retlen, movebuf, (char *)&oob, &nftl->oobinfo);
        }
         
         /* add the header so that it is now a valid chain */
@@ -390,7 +404,6 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p
 
                 if (NFTL_formatblock(nftl, thisEUN) < 0) {
                        /* could not erase : mark block as reserved
-                        * FixMe: Update Bad Unit Table on disk
                         */
                        nftl->ReplUnitTable[thisEUN] = BLOCK_RESERVED;
                 } else {
@@ -617,7 +630,7 @@ static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
        u16 writeEUN;
        unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1);
        size_t retlen;
-       u8 eccbuf[6];
+       struct nftl_oob oob;
 
        writeEUN = NFTL_findwriteunit(nftl, block);
 
@@ -628,9 +641,11 @@ static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block,
                return 1;
        }
 
+       memset(&oob, 0xff, sizeof(struct nftl_oob));
+       oob.b.Status = oob.b.Status1 = SECTOR_USED;
        MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs,
-                    512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP);
-        /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */
+                    512, &retlen, (char *)buffer, (char *)&oob, &nftl->oobinfo);
+        /* need to write SECTOR_USED flags since they are not written in mtd_writeecc */
 
        return 0;
 }
@@ -692,8 +707,7 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block,
        } else {
                loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs;
                size_t retlen;
-               u_char eccbuf[6];
-               if (MTD_READECC(nftl->mbd.mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP))
+               if (MTD_READ(nftl->mbd.mtd, ptr, 512, &retlen, buffer))
                        return -EIO;
        }
        return 0;
@@ -735,7 +749,7 @@ extern char nftlmountrev[];
 
 int __init init_nftl(void)
 {
-       printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.94 $, nftlmount.c %s\n", nftlmountrev);
+       printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.96 $, nftlmount.c %s\n", nftlmountrev);
 
        return register_mtd_blktrans(&nftl_tr);
 }
index 394a0a115d821df2251ac28ca8bd9ddc512e997c..a8a4e1ac843e9fac366bbe2fbe0272940544d709 100644 (file)
@@ -4,7 +4,7 @@
  * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
  * Copyright (C) 2000 Netgem S.A.
  *
- * $Id: nftlmount.c,v 1.34 2003/05/21 10:54:10 dwmw2 Exp $
+ * $Id: nftlmount.c,v 1.36 2004/06/28 13:52:55 dbrown 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
@@ -31,7 +31,7 @@
 
 #define SECTORSIZE 512
 
-char nftlmountrev[]="$Revision: 1.34 $";
+char nftlmountrev[]="$Revision: 1.36 $";
 
 /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
  *     various device information of the NFTL partition and Bad Unit Table. Update
@@ -50,6 +50,10 @@ static int find_boot_record(struct NFTLrecord *nftl)
 
         /* Assume logical EraseSize == physical erasesize for starting the scan. 
           We'll sort it out later if we find a MediaHeader which says otherwise */
+       /* Actually, we won't.  The new DiskOnChip driver has already scanned
+          the MediaHeader and adjusted the virtual erasesize it presents in
+          the mtd device accordingly.  We could even get rid of
+          nftl->EraseSize if there were any point in doing so. */
        nftl->EraseSize = nftl->mbd.mtd->erasesize;
         nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
 
@@ -62,7 +66,10 @@ static int find_boot_record(struct NFTLrecord *nftl)
 
                /* Check for ANAND header first. Then can whinge if it's found but later
                   checks fail */
-               if ((ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) {
+               ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf);
+               /* We ignore ret in case the ECC of the MediaHeader is invalid
+                  (which is apparently acceptable) */
+               if (retlen != SECTORSIZE) {
                        static int warncount = 5;
 
                        if (warncount) {
@@ -104,7 +111,7 @@ static int find_boot_record(struct NFTLrecord *nftl)
 
                /* Finally reread to check ECC */
                if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE,
-                               &retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP) < 0)) {
+                               &retlen, buf, (char *)&oob, NULL) < 0)) {
                        printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
                               block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
                        continue;
@@ -149,6 +156,10 @@ static int find_boot_record(struct NFTLrecord *nftl)
                memcpy(mh, buf, sizeof(struct NFTLMediaHeader));
 
                /* Do some sanity checks on it */
+#if 0
+The new DiskOnChip driver scans the MediaHeader itself, and presents a virtual
+erasesize based on UnitSizeFactor.  So the erasesize we read from the mtd
+device is already correct.
                if (mh->UnitSizeFactor == 0) {
                        printk(KERN_NOTICE "NFTL: UnitSizeFactor 0x00 detected. This violates the spec but we think we know what it means...\n");
                } else if (mh->UnitSizeFactor < 0xfc) {
@@ -161,6 +172,7 @@ static int find_boot_record(struct NFTLrecord *nftl)
                        nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor);
                        nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize;
                }
+#endif
                nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN);
                if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) {
                        printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n");
@@ -213,11 +225,13 @@ static int find_boot_record(struct NFTLrecord *nftl)
 
                /* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */
                for (i = 0; i < nftl->nb_blocks; i++) {
+#if 0
+The new DiskOnChip driver already scanned the bad block table.  Just query it.
                        if ((i & (SECTORSIZE - 1)) == 0) {
                                /* read one sector for every SECTORSIZE of blocks */
                                if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize +
                                                       i + SECTORSIZE, SECTORSIZE, &retlen, buf,
-                                                      (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) {
+                                                      (char *)&oob, NULL)) < 0) {
                                        printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
                                               ret);
                                        kfree(nftl->ReplUnitTable);
@@ -228,6 +242,9 @@ static int find_boot_record(struct NFTLrecord *nftl)
                        /* mark the Bad Erase Unit as RESERVED in ReplUnitTable */
                        if (buf[i & (SECTORSIZE - 1)] != 0xff)
                                nftl->ReplUnitTable[i] = BLOCK_RESERVED;
+#endif
+                       if (nftl->mbd.mtd->block_isbad(nftl->mbd.mtd, i * nftl->EraseSize))
+                               nftl->ReplUnitTable[i] = BLOCK_RESERVED;
                }
                
                nftl->MediaUnit = block;
@@ -253,21 +270,16 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int
                              int check_oob)
 {
        int i, retlen;
-       u8 buf[SECTORSIZE];
+       u8 buf[SECTORSIZE + nftl->mbd.mtd->oobsize];
 
        for (i = 0; i < len; i += SECTORSIZE) {
-               /* we want to read the sector without ECC check here since a free
-                  sector does not have ECC syndrome on it yet */
-               if (MTD_READ(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0)
+               if (MTD_READECC(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf, &buf[SECTORSIZE], &nftl->oobinfo) < 0)
                        return -1;
                if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
                        return -1;
 
                if (check_oob) {
-                       if (MTD_READOOB(nftl->mbd.mtd, address, nftl->mbd.mtd->oobsize,
-                                       &retlen, buf) < 0)
-                               return -1;
-                       if (memcmpb(buf, 0xff, nftl->mbd.mtd->oobsize) != 0)
+                       if (memcmpb(buf + SECTORSIZE, 0xff, nftl->mbd.mtd->oobsize) != 0)
                                return -1;
                }
                address += SECTORSIZE;
@@ -282,7 +294,6 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int
  * Return: 0 when succeed, -1 on error.
  *
  *  ToDo: 1. Is it neceressary to check_free_sector after erasing ?? 
- *        2. UnitSizeFactor != 0xFF
  */
 int NFTL_formatblock(struct NFTLrecord *nftl, int block)
 {
@@ -312,11 +323,10 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
        MTD_ERASE(nftl->mbd.mtd, instr);
 
        if (instr->state == MTD_ERASE_FAILED) {
-               /* could not format, FixMe: We should update the BadUnitTable 
-                  both in memory and on disk */
                printk("Error while formatting block %d\n", block);
-               return -1;
-       } else {
+               goto fail;
+       }
+
                /* increase and write Wear-Leveling info */
                nb_erases = le32_to_cpu(uci.WearInfo);
                nb_erases++;
@@ -329,14 +339,18 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
                 * FixMe:  is this check really necessary ? since we have check the
                 *         return code after the erase operation. */
                if (check_free_sectors(nftl, instr->addr, nftl->EraseSize, 1) != 0)
-                       return -1;
+                       goto fail;
 
                uci.WearInfo = le32_to_cpu(nb_erases);
                if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8,
                                 &retlen, (char *)&uci) < 0)
-                       return -1;
+                       goto fail;
                return 0;
-       }
+fail:
+       /* could not format, update the bad block table (caller is responsible
+          for setting the ReplUnitTable to BLOCK_RESERVED on failure) */
+       nftl->mbd.mtd->block_markbad(nftl->mbd.mtd, instr->addr);
+       return -1;
 }
 
 /* check_sectors_in_chain: Check that each sector of a Virtual Unit Chain is correct.
@@ -441,8 +455,7 @@ static void format_chain(struct NFTLrecord *nftl, unsigned int first_block)
 
                printk("Formatting block %d\n", block);
                if (NFTL_formatblock(nftl, block) < 0) {
-                       /* cannot format !!!! Mark it as Bad Unit,
-                          FixMe: update the BadUnitTable on disk */
+                       /* cannot format !!!! Mark it as Bad Unit */
                        nftl->ReplUnitTable[block] = BLOCK_RESERVED;
                } else {
                        nftl->ReplUnitTable[block] = BLOCK_FREE;
index 3e279992f6a90dd8efc9b82857b6c0ad512022e2..626ad368ecc2d5dc68a7b9c367d65fd61a00c931 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: redboot.c,v 1.11 2003/05/21 10:39:26 dwmw2 Exp $
+ * $Id: redboot.c,v 1.13 2004/04/01 10:17:40 gthomas Exp $
  *
  * Parse RedBoot-style Flash Image System (FIS) tables and
  * produce a Linux partition array to match.
@@ -48,21 +48,24 @@ static int parse_redboot_partitions(struct mtd_info *master,
        char *names;
        char *nullname;
        int namelen = 0;
+       int nulllen = 0;
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
        static char nullstring[] = "unallocated";
+#endif
 
-       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       buf = kmalloc(master->erasesize, GFP_KERNEL);
 
        if (!buf)
                return -ENOMEM;
 
        /* Read the start of the last erase block */
        ret = master->read(master, master->size - master->erasesize,
-                          PAGE_SIZE, &retlen, (void *)buf);
+                          master->erasesize, &retlen, (void *)buf);
 
        if (ret)
                goto out;
 
-       if (retlen != PAGE_SIZE) {
+       if (retlen != master->erasesize) {
                ret = -EIO;
                goto out;
        }
@@ -80,7 +83,7 @@ static int parse_redboot_partitions(struct mtd_info *master,
                goto out;
        }
 
-       for (i = 0; i < PAGE_SIZE / sizeof(struct fis_image_desc); i++) {
+       for (i = 0; i < master->erasesize / sizeof(struct fis_image_desc); i++) {
                struct fis_list *new_fl, **prev;
 
                if (buf[i].name[0] == 0xff)
@@ -112,48 +115,69 @@ static int parse_redboot_partitions(struct mtd_info *master,
 
                nrparts++;
        }
-       if (fl->img->flash_base)
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+       if (fl->img->flash_base) {
                nrparts++;
+               nulllen = sizeof(nullstring);
+       }
 
        for (tmp_fl = fl; tmp_fl->next; tmp_fl = tmp_fl->next) {
-               if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize < tmp_fl->next->img->flash_base)
+               if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize <= tmp_fl->next->img->flash_base) {
                        nrparts++;
+                       nulllen = sizeof(nullstring);
+               }
        }
-       parts = kmalloc(sizeof(*parts)*nrparts + sizeof(nullstring) + namelen, GFP_KERNEL);
+#endif
+       parts = kmalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
 
        if (!parts) {
                ret = -ENOMEM;
                goto out;
        }
 
-       memset(parts, 0, sizeof(*parts)*nrparts + namelen);
+       memset(parts, 0, sizeof(*parts)*nrparts + nulllen + namelen);
 
-       /* FIXME: Include nullname only if it's used */
        nullname = (char *)&parts[nrparts];
-       sprintf(nullname, nullstring);
-       names = nullname + sizeof(nullstring);
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+       if (nulllen > 0) {
+               strcpy(nullname, nullstring);
+       }
+#endif
+       names = nullname + nulllen;
 
        i=0;
 
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
        if (fl->img->flash_base) {
               parts[0].name = nullname;
               parts[0].size = fl->img->flash_base;
               parts[0].offset = 0;
+               i++;
        }
+#endif
        for ( ; i<nrparts; i++) {
                parts[i].size = fl->img->size;
                parts[i].offset = fl->img->flash_base;
                parts[i].name = names;
 
                strcpy(names, fl->img->name);
+#ifdef CONFIG_MTD_REDBOOT_PARTS_READONLY
+               if (!memcmp(names, "RedBoot", 8) ||
+                               !memcmp(names, "RedBoot config", 15) ||
+                               !memcmp(names, "FIS directory", 14)) {
+                       parts[i].mask_flags = MTD_WRITEABLE;
+               }
+#endif
                names += strlen(names)+1;
 
-               if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize < fl->next->img->flash_base) {
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+               if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
                        i++;
                        parts[i].offset = parts[i-1].size + parts[i-1].offset;
                        parts[i].size = fl->next->img->flash_base - parts[i].offset;
                        parts[i].name = nullname;
                }
+#endif
                tmp_fl = fl;
                fl = fl->next;
                kfree(tmp_fl);
index 64465a963442e368ecb6ffc646ec3cf679a3e800..0fd8f49c649b36e5fe918249cae05b7cf4f8ee68 100644 (file)
@@ -1,13 +1,21 @@
-
-/* Linux driver for Disk-On-Chip 2000       */
-/* (c) 1999 Machine Vision Holdings, Inc.   */
-/* Author: David Woodhouse <dwmw2@mvhi.com> */
-/* $Id: doc2000.h,v 1.17 2003/06/12 01:20:46 gerg Exp $ */
+/* 
+ * Linux driver for Disk-On-Chip devices
+ *
+ * Copyright (C) 1999 Machine Vision Holdings, Inc.   
+ * Copyright (C) 2001-2003 David Woodhouse <dwmw2@infradead.org>
+ * Copyright (C) 2002-2003 Greg Ungerer <gerg@snapgear.com>
+ * Copyright (C) 2002-2003 SnapGear Inc
+ *
+ * $Id: doc2000.h,v 1.22 2003/11/05 10:51:36 dwmw2 Exp $ 
+ *
+ * Released under GPL
+ */
 
 #ifndef __MTD_DOC2000_H__
 #define __MTD_DOC2000_H__
 
 #include <linux/mtd/mtd.h>
+#include <asm/semaphore.h>
 
 #define DoC_Sig1 0
 #define DoC_Sig2 1
  * Others use readb/writeb 
  */
 #if defined(__arm__)
-#define ReadDOC_(adr, reg)      ((unsigned char)(*(__u32 *)(((unsigned long)adr)+((reg)<<2))))
-#define WriteDOC_(d, adr, reg)  do{ *(__u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
+#define ReadDOC_(adr, reg)      ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2))))
+#define WriteDOC_(d, adr, reg)  do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0)
 #define DOC_IOREMAP_LEN 0x8000
 #elif defined(__ppc__)
-#define ReadDOC_(adr, reg)      ((unsigned char)(*(__u16 *)(((unsigned long)adr)+((reg)<<1))))
-#define WriteDOC_(d, adr, reg)  do{ *(__u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
+#define ReadDOC_(adr, reg)      ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1))))
+#define WriteDOC_(d, adr, reg)  do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0)
 #define DOC_IOREMAP_LEN 0x4000
 #else
 #define ReadDOC_(adr, reg)      readb(((unsigned long)adr) + (reg))
 #define DOC_MODE_MDWREN        0x04
 
 #define DOC_ChipID_Doc2k       0x20
+#define DOC_ChipID_Doc2kTSOP   0x21    /* internal number for MTD */
 #define DOC_ChipID_DocMil      0x30
 #define DOC_ChipID_DocMilPlus32        0x40
 #define DOC_ChipID_DocMilPlus16        0x41
@@ -147,10 +156,10 @@ struct Nand {
 #define MAX_FLOORS 4
 #define MAX_CHIPS 4
 
-#define MAX_FLOORS_MIL 4
+#define MAX_FLOORS_MIL 1
 #define MAX_CHIPS_MIL 1
 
-#define MAX_FLOORS_MPLUS 1
+#define MAX_FLOORS_MPLUS 2
 #define MAX_CHIPS_MPLUS 1
 
 #define ADDR_COLUMN 1
@@ -161,7 +170,7 @@ struct DiskOnChip {
        unsigned long physadr;
        unsigned long virtadr;
        unsigned long totlen;
-       char ChipID; /* Type of DiskOnChip */
+       unsigned char ChipID; /* Type of DiskOnChip */
        int ioreg;
        
        unsigned long mfr; /* Flash IDs - only one type of flash per device */
index ae017efb974ef454617119a866a39bd69d223efe..3678459b4535ec66c32c6f4981475eb004bd5f2d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ftl.h,v 1.5 2001/06/02 20:35:51 dwmw2 Exp $
+ * $Id: ftl.h,v 1.6 2003/01/24 13:20:04 dwmw2 Exp $
  * 
  * Derived from (and probably identical to):
  * ftl.h 1.7 1999/10/25 20:23:17
index 5cc052da95975fb32fd41439bd07b8689b372516..b52c8cbd235c8917fb7f29f5dfd53ab48f2db751 100644 (file)
  *
  *     (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
  *
- *     $Id: inftl.h,v 1.3 2003/05/23 11:35:34 dwmw2 Exp $
+ *     $Id: inftl.h,v 1.6 2004/06/30 14:49:00 dbrown Exp $
  */
 
 #ifndef __MTD_INFTL_H__
 #define __MTD_INFTL_H__
 
+#ifndef __KERNEL__
+#error This is a kernel header. Perhaps include nftl-user.h instead?
+#endif
+
 #include <linux/mtd/blktrans.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nftl.h>
 
-#define        OSAK_VERSION    0x5120
-#define        PERCENTUSED     98
-
-#define        SECTORSIZE      512
+#include <mtd/inftl-user.h>
 
 #ifndef INFTL_MAJOR
-#define INFTL_MAJOR 93 /* FIXME */
+#define INFTL_MAJOR 94
 #endif
 #define INFTL_PARTN_BITS 4
 
-/* Block Control Information */
-
-struct inftl_bci {
-       __u8 ECCsig[6];
-       __u8 Status;
-       __u8 Status1;
-} __attribute__((packed));
-
-struct inftl_unithead1 {
-       __u16 virtualUnitNo;
-       __u16 prevUnitNo;
-       __u8 ANAC;
-       __u8 NACs;
-       __u8 parityPerField;
-       __u8 discarded;
-} __attribute__((packed));
-
-struct inftl_unithead2 {
-       __u8 parityPerField;
-       __u8 ANAC;
-       __u16 prevUnitNo;
-       __u16 virtualUnitNo;
-       __u8 NACs;
-       __u8 discarded;
-} __attribute__((packed));
-
-struct inftl_unittail {
-       __u8 Reserved[4];
-       __u16 EraseMark;
-       __u16 EraseMark1;
-} __attribute__((packed));
-
-union inftl_uci {
-       struct inftl_unithead1 a;
-       struct inftl_unithead2 b;
-       struct inftl_unittail c;
-};
-
-struct inftl_oob {
-       struct inftl_bci b;
-       union inftl_uci u;
-};
-
-
-/* INFTL Media Header */
-
-struct INFTLPartition {
-       __u32 virtualUnits;
-       __u32 firstUnit;
-       __u32 lastUnit;
-       __u32 flags;
-       __u32 spareUnits;
-       __u32 Reserved0;
-       __u32 Reserved1;
-} __attribute__((packed));
-
-struct INFTLMediaHeader {
-       char bootRecordID[8];
-       __u32 NoOfBootImageBlocks;
-       __u32 NoOfBinaryPartitions;
-       __u32 NoOfBDTLPartitions;
-       __u32 BlockMultiplierBits;
-       __u32 FormatFlags;
-       __u32 OsakVersion;
-       __u32 PercentUsed;
-       struct INFTLPartition Partitions[4];
-} __attribute__((packed));
-
-/* Partition flag types */
-#define        INFTL_BINARY    0x20000000
-#define        INFTL_BDTL      0x40000000
-#define        INFTL_LAST      0x80000000
-
-
 #ifdef __KERNEL__
 
 struct INFTLrecord {
        struct mtd_blktrans_dev mbd;
-       __u16 MediaUnit, SpareMediaUnit;
+       __u16 MediaUnit;
        __u32 EraseSize;
        struct INFTLMediaHeader MediaHdr;
        int usecount;
@@ -119,6 +46,7 @@ struct INFTLrecord {
         unsigned int nb_blocks;                /* number of physical blocks */
         unsigned int nb_boot_blocks;   /* number of blocks used by the bios */
         struct erase_info instr;
+        struct nand_oobinfo oobinfo;
 };
 
 int INFTL_mount(struct INFTLrecord *s);
index 2f0e43db03076968e56321d486279e86ff44e95f..fd7b15d077b311586ab83c19588bcf5abe5406db 100644 (file)
@@ -1,10 +1,17 @@
-
-/* $Id: mtd.h,v 1.45 2003/05/20 21:56:40 dwmw2 Exp $ */
+/* 
+ * $Id: mtd.h,v 1.54 2004/07/15 01:13:12 dwmw2 Exp $
+ *
+ * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
+ *
+ * Released under GPL
+ */
 
 #ifndef __MTD_MTD_H__
 #define __MTD_MTD_H__
 
-#ifdef __KERNEL__
+#ifndef __KERNEL__
+#error This is a kernel header. Perhaps include mtd-user.h instead?
+#endif
 
 #include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/uio.h>
 
-#endif /* __KERNEL__ */
-
-struct erase_info_user {
-       u_int32_t start;
-       u_int32_t length;
-};
-
-struct mtd_oob_buf {
-       u_int32_t start;
-       u_int32_t length;
-       unsigned char __user *ptr;
-};
+#include <mtd/mtd-abi.h>
 
 #define MTD_CHAR_MAJOR 90
 #define MTD_BLOCK_MAJOR 31
 #define MAX_MTD_DEVICES 16
 
-
-
-#define MTD_ABSENT             0
-#define MTD_RAM                        1
-#define MTD_ROM                        2
-#define MTD_NORFLASH           3
-#define MTD_NANDFLASH          4
-#define MTD_PEROM              5
-#define MTD_OTHER              14
-#define MTD_UNKNOWN            15
-
-
-
-#define MTD_CLEAR_BITS         1       // Bits can be cleared (flash)
-#define MTD_SET_BITS           2       // Bits can be set
-#define MTD_ERASEABLE          4       // Has an erase function
-#define MTD_WRITEB_WRITEABLE   8       // Direct IO is possible
-#define MTD_VOLATILE           16      // Set for RAMs
-#define MTD_XIP                        32      // eXecute-In-Place possible
-#define MTD_OOB                        64      // Out-of-band data (NAND flash)
-#define MTD_ECC                        128     // Device capable of automatic ECC
-
-// Some common devices / combinations of capabilities
-#define MTD_CAP_ROM            0
-#define MTD_CAP_RAM            (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEB_WRITEABLE)
-#define MTD_CAP_NORFLASH        (MTD_CLEAR_BITS|MTD_ERASEABLE)
-#define MTD_CAP_NANDFLASH       (MTD_CLEAR_BITS|MTD_ERASEABLE|MTD_OOB)
-#define MTD_WRITEABLE          (MTD_CLEAR_BITS|MTD_SET_BITS)
-
-
-// Types of automatic ECC/Checksum available
-#define MTD_ECC_NONE           0       // No automatic ECC available
-#define MTD_ECC_RS_DiskOnChip  1       // Automatic ECC on DiskOnChip
-#define MTD_ECC_SW             2       // SW ECC for Toshiba & Samsung devices
-
-struct mtd_info_user {
-       u_char type;
-       u_int32_t flags;
-       u_int32_t size;  // Total size of the MTD
-       u_int32_t erasesize;
-       u_int32_t oobblock;  // Size of OOB blocks (e.g. 512)
-       u_int32_t oobsize;   // Amount of OOB data per block (e.g. 16)
-       u_int32_t ecctype;
-       u_int32_t eccsize;
-};
-
-struct region_info_user {
-       u_int32_t offset;               /* At which this region starts, 
-                                        * from the beginning of the MTD */
-       u_int32_t erasesize;            /* For this region */
-       u_int32_t numblocks;            /* Number of blocks in this region */
-       u_int32_t regionindex;
-};
-
-#define MEMGETINFO              _IOR('M', 1, struct mtd_info_user)
-#define MEMERASE                _IOW('M', 2, struct erase_info_user)
-#define MEMWRITEOOB             _IOWR('M', 3, struct mtd_oob_buf)
-#define MEMREADOOB              _IOWR('M', 4, struct mtd_oob_buf)
-#define MEMLOCK                 _IOW('M', 5, struct erase_info_user)
-#define MEMUNLOCK               _IOW('M', 6, struct erase_info_user)
-#define MEMGETREGIONCOUNT      _IOR('M', 7, int)
-#define MEMGETREGIONINFO       _IOWR('M', 8, struct region_info_user)
-#define MEMSETOOBSEL           _IOW('M', 9, struct nand_oobinfo)
-
-struct nand_oobinfo {
-       int     useecc;
-       int     eccpos[6];      
-};
-
-
-#ifndef __KERNEL__
-
-typedef struct mtd_info_user mtd_info_t;
-typedef struct erase_info_user erase_info_t;
-typedef struct region_info_user region_info_t;
-typedef struct nand_oobinfo nand_oobinfo_t;
-
-       /* User-space ioctl definitions */
-
-#else /* __KERNEL__ */
-
-
 #define MTD_ERASE_PENDING              0x01
 #define MTD_ERASING            0x02
 #define MTD_ERASE_SUSPEND      0x04
 #define MTD_ERASE_DONE          0x08
 #define MTD_ERASE_FAILED        0x10
 
+/* If the erase fails, fail_addr might indicate exactly which block failed.  If
+   fail_addr = 0xffffffff, the failure was not at the device level or was not
+   specific to any particular block. */
 struct erase_info {
        struct mtd_info *mtd;
        u_int32_t addr;
        u_int32_t len;
+       u_int32_t fail_addr;
        u_long time;
        u_long retries;
        u_int dev;
@@ -150,6 +68,7 @@ struct mtd_info {
 
        u_int32_t oobblock;  // Size of OOB blocks (e.g. 512)
        u_int32_t oobsize;   // Amount of OOB data per block (e.g. 16)
+       u_int32_t oobavail;  // Number of bytes in OOB area available for fs 
        u_int32_t ecctype;
        u_int32_t eccsize;
        
@@ -223,6 +142,10 @@ struct mtd_info {
        int (*suspend) (struct mtd_info *mtd);
        void (*resume) (struct mtd_info *mtd);
 
+       /* Bad block management functions */
+       int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
+       int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
+
        void *priv;
 
        struct module *owner;
@@ -288,6 +211,4 @@ int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs,
 
 #endif /* CONFIG_MTD_DEBUG */
 
-#endif /* __KERNEL__ */
-
 #endif /* __MTD_MTD_H__ */
index fd57ffddd69a5bf8d8428992abe2826c6850d551..d35d2c21ff3e0abd4caa594fdd31e37d506c3a53 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: nftl.h,v 1.13 2003/05/23 11:25:02 dwmw2 Exp $
+ * $Id: nftl.h,v 1.16 2004/06/30 14:49:00 dbrown Exp $
  *
  * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
  */
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/blktrans.h>
 
-/* Block Control Information */
-
-struct nftl_bci {
-       unsigned char ECCSig[6];
-       __u8 Status;
-       __u8 Status1;
-}__attribute__((packed));
-
-/* Unit Control Information */
-
-struct nftl_uci0 {
-       __u16 VirtUnitNum;
-       __u16 ReplUnitNum;
-       __u16 SpareVirtUnitNum;
-       __u16 SpareReplUnitNum;
-} __attribute__((packed));
-
-struct nftl_uci1 {
-       __u32 WearInfo;
-       __u16 EraseMark;
-       __u16 EraseMark1;
-} __attribute__((packed));
-
-struct nftl_uci2 {
-        __u16 FoldMark;
-        __u16 FoldMark1;
-       __u32 unused;
-} __attribute__((packed));
-
-union nftl_uci {
-       struct nftl_uci0 a;
-       struct nftl_uci1 b;
-       struct nftl_uci2 c;
-};
-
-struct nftl_oob {
-       struct nftl_bci b;
-       union nftl_uci u;
-};
-
-/* NFTL Media Header */
-
-struct NFTLMediaHeader {
-       char DataOrgID[6];
-       __u16 NumEraseUnits;
-       __u16 FirstPhysicalEUN;
-       __u32 FormattedSize;
-       unsigned char UnitSizeFactor;
-} __attribute__((packed));
-
-#define MAX_ERASE_ZONES (8192 - 512)
-
-#define ERASE_MARK 0x3c69
-#define SECTOR_FREE 0xff
-#define SECTOR_USED 0x55
-#define SECTOR_IGNORE 0x11
-#define SECTOR_DELETED 0x00
-
-#define FOLD_MARK_IN_PROGRESS 0x5555
-
-#define ZONE_GOOD 0xff
-#define ZONE_BAD_ORIGINAL 0
-#define ZONE_BAD_MARKED 7
-
-#ifdef __KERNEL__
+#include <mtd/nftl-user.h>
 
 /* these info are used in ReplUnitTable */
 #define BLOCK_NIL          0xffff /* last block of a chain */
@@ -101,6 +37,7 @@ struct NFTLrecord {
         unsigned int nb_blocks;                /* number of physical blocks */
         unsigned int nb_boot_blocks;   /* number of blocks used by the bios */
         struct erase_info instr;
+       struct nand_oobinfo oobinfo;
 };
 
 int NFTL_mount(struct NFTLrecord *s);
@@ -114,6 +51,4 @@ int NFTL_formatblock(struct NFTLrecord *s, int block);
 #define MAX_SECTORS_PER_UNIT 64
 #define NFTL_PARTN_BITS 4
 
-#endif /* __KERNEL__ */
-
 #endif /* __MTD_NFTL_H__ */
index 5c5f8770b86d29b9a3b4c826def31447b60b5b35..100ea79de16dd35b5848dfdeef88e650f431d555 100644 (file)
@@ -5,7 +5,7 @@
  *
  * This code is GPL
  *
- * $Id: partitions.h,v 1.14 2003/05/20 21:56:29 dwmw2 Exp $
+ * $Id: partitions.h,v 1.15 2003/07/09 11:15:43 dwmw2 Exp $
  */
 
 #ifndef MTD_PARTITIONS_H
@@ -50,7 +50,7 @@ struct mtd_partition {
 #define MTDPART_SIZ_FULL       (0)
 
 
-int add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int);
+int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
 int del_mtd_partitions(struct mtd_info *);
 
 /*
diff --git a/include/mtd/inftl-user.h b/include/mtd/inftl-user.h
new file mode 100644 (file)
index 0000000..bda4f2c
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * $Id: inftl-user.h,v 1.1 2004/05/05 15:17:00 dwmw2 Exp $
+ *
+ * Parts of INFTL headers shared with userspace 
+ *
+ */
+
+#ifndef __MTD_INFTL_USER_H__
+#define __MTD_INFTL_USER_H__
+
+#define        OSAK_VERSION    0x5120
+#define        PERCENTUSED     98
+
+#define        SECTORSIZE      512
+
+/* Block Control Information */
+
+struct inftl_bci {
+       uint8_t ECCsig[6];
+       uint8_t Status;
+       uint8_t Status1;
+} __attribute__((packed));
+
+struct inftl_unithead1 {
+       uint16_t virtualUnitNo;
+       uint16_t prevUnitNo;
+       uint8_t ANAC;
+       uint8_t NACs;
+       uint8_t parityPerField;
+       uint8_t discarded;
+} __attribute__((packed));
+
+struct inftl_unithead2 {
+       uint8_t parityPerField;
+       uint8_t ANAC;
+       uint16_t prevUnitNo;
+       uint16_t virtualUnitNo;
+       uint8_t NACs;
+       uint8_t discarded;
+} __attribute__((packed));
+
+struct inftl_unittail {
+       uint8_t Reserved[4];
+       uint16_t EraseMark;
+       uint16_t EraseMark1;
+} __attribute__((packed));
+
+union inftl_uci {
+       struct inftl_unithead1 a;
+       struct inftl_unithead2 b;
+       struct inftl_unittail c;
+};
+
+struct inftl_oob {
+       struct inftl_bci b;
+       union inftl_uci u;
+};
+
+
+/* INFTL Media Header */
+
+struct INFTLPartition {
+       __u32 virtualUnits;
+       __u32 firstUnit;
+       __u32 lastUnit;
+       __u32 flags;
+       __u32 spareUnits;
+       __u32 Reserved0;
+       __u32 Reserved1;
+} __attribute__((packed));
+
+struct INFTLMediaHeader {
+       char bootRecordID[8];
+       __u32 NoOfBootImageBlocks;
+       __u32 NoOfBinaryPartitions;
+       __u32 NoOfBDTLPartitions;
+       __u32 BlockMultiplierBits;
+       __u32 FormatFlags;
+       __u32 OsakVersion;
+       __u32 PercentUsed;
+       struct INFTLPartition Partitions[4];
+} __attribute__((packed));
+
+/* Partition flag types */
+#define        INFTL_BINARY    0x20000000
+#define        INFTL_BDTL      0x40000000
+#define        INFTL_LAST      0x80000000
+
+#endif /* __MTD_INFTL_USER_H__ */
+
+
diff --git a/include/mtd/jffs2-user.h b/include/mtd/jffs2-user.h
new file mode 100644 (file)
index 0000000..d508ef0
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * $Id: jffs2-user.h,v 1.1 2004/05/05 11:57:54 dwmw2 Exp $
+ *
+ * JFFS2 definitions for use in user space only
+ */
+
+#ifndef __JFFS2_USER_H__
+#define __JFFS2_USER_H__
+
+/* This file is blessed for inclusion by userspace */
+#include <linux/jffs2.h>
+#include <endian.h>
+#include <byteswap.h>
+
+#undef cpu_to_je16
+#undef cpu_to_je32
+#undef cpu_to_jemode
+#undef je16_to_cpu
+#undef je32_to_cpu
+#undef jemode_to_cpu
+
+extern int target_endian;
+
+#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); })
+#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); })
+
+#define cpu_to_je16(x) ((jint16_t){t16(x)})
+#define cpu_to_je32(x) ((jint32_t){t32(x)})
+#define cpu_to_jemode(x) ((jmode_t){t32(x)})
+
+#define je16_to_cpu(x) (t16((x).v16))
+#define je32_to_cpu(x) (t32((x).v32))
+#define jemode_to_cpu(x) (t32((x).m))
+
+#endif /* __JFFS2_USER_H__ */
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
new file mode 100644 (file)
index 0000000..db5fca2
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * $Id: mtd-abi.h,v 1.5 2004/06/22 09:29:35 gleixner Exp $
+ *
+ * Portions of MTD ABI definition which are shared by kernel and user space 
+ */
+
+#ifndef __MTD_ABI_H__
+#define __MTD_ABI_H__
+
+struct erase_info_user {
+       uint32_t start;
+       uint32_t length;
+};
+
+struct mtd_oob_buf {
+       uint32_t start;
+       uint32_t length;
+       unsigned char *ptr;
+};
+
+#define MTD_ABSENT             0
+#define MTD_RAM                        1
+#define MTD_ROM                        2
+#define MTD_NORFLASH           3
+#define MTD_NANDFLASH          4
+#define MTD_PEROM              5
+#define MTD_OTHER              14
+#define MTD_UNKNOWN            15
+
+#define MTD_CLEAR_BITS         1       // Bits can be cleared (flash)
+#define MTD_SET_BITS           2       // Bits can be set
+#define MTD_ERASEABLE          4       // Has an erase function
+#define MTD_WRITEB_WRITEABLE   8       // Direct IO is possible
+#define MTD_VOLATILE           16      // Set for RAMs
+#define MTD_XIP                        32      // eXecute-In-Place possible
+#define MTD_OOB                        64      // Out-of-band data (NAND flash)
+#define MTD_ECC                        128     // Device capable of automatic ECC
+
+// Some common devices / combinations of capabilities
+#define MTD_CAP_ROM            0
+#define MTD_CAP_RAM            (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEB_WRITEABLE)
+#define MTD_CAP_NORFLASH        (MTD_CLEAR_BITS|MTD_ERASEABLE)
+#define MTD_CAP_NANDFLASH       (MTD_CLEAR_BITS|MTD_ERASEABLE|MTD_OOB)
+#define MTD_WRITEABLE          (MTD_CLEAR_BITS|MTD_SET_BITS)
+
+
+// Types of automatic ECC/Checksum available
+#define MTD_ECC_NONE           0       // No automatic ECC available
+#define MTD_ECC_RS_DiskOnChip  1       // Automatic ECC on DiskOnChip
+#define MTD_ECC_SW             2       // SW ECC for Toshiba & Samsung devices
+
+/* ECC byte placement */
+#define MTD_NANDECC_OFF                0       // Switch off ECC (Not recommended)
+#define MTD_NANDECC_PLACE      1       // Use the given placement in the structure (YAFFS1 legacy mode)
+#define MTD_NANDECC_AUTOPLACE  2       // Use the default placement scheme
+#define MTD_NANDECC_PLACEONLY  3       // Use the given placement in the structure (Do not store ecc result on read)
+
+struct mtd_info_user {
+       uint8_t type;
+       uint32_t flags;
+       uint32_t size;   // Total size of the MTD
+       uint32_t erasesize;
+       uint32_t oobblock;  // Size of OOB blocks (e.g. 512)
+       uint32_t oobsize;   // Amount of OOB data per block (e.g. 16)
+       uint32_t ecctype;
+       uint32_t eccsize;
+};
+
+struct region_info_user {
+       uint32_t offset;                /* At which this region starts, 
+                                        * from the beginning of the MTD */
+       uint32_t erasesize;             /* For this region */
+       uint32_t numblocks;             /* Number of blocks in this region */
+       uint32_t regionindex;
+};
+
+#define MEMGETINFO              _IOR('M', 1, struct mtd_info_user)
+#define MEMERASE                _IOW('M', 2, struct erase_info_user)
+#define MEMWRITEOOB             _IOWR('M', 3, struct mtd_oob_buf)
+#define MEMREADOOB              _IOWR('M', 4, struct mtd_oob_buf)
+#define MEMLOCK                 _IOW('M', 5, struct erase_info_user)
+#define MEMUNLOCK               _IOW('M', 6, struct erase_info_user)
+#define MEMGETREGIONCOUNT      _IOR('M', 7, int)
+#define MEMGETREGIONINFO       _IOWR('M', 8, struct region_info_user)
+#define MEMSETOOBSEL           _IOW('M', 9, struct nand_oobinfo)
+#define MEMGETOOBSEL           _IOR('M', 10, struct nand_oobinfo)
+#define MEMGETBADBLOCK         _IOW('M', 11, loff_t)
+#define MEMSETBADBLOCK         _IOW('M', 12, loff_t)
+
+struct nand_oobinfo {
+       uint32_t useecc;
+       uint32_t eccbytes;
+       uint32_t oobfree[8][2];
+       uint32_t eccpos[32];
+};
+
+#endif /* __MTD_ABI_H__ */
diff --git a/include/mtd/mtd-user.h b/include/mtd/mtd-user.h
new file mode 100644 (file)
index 0000000..1c13fc7
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * $Id: mtd-user.h,v 1.2 2004/05/05 14:44:57 dwmw2 Exp $
+ *
+ * MTD ABI header for use by user space only.
+ */
+
+#ifndef __MTD_USER_H__
+#define __MTD_USER_H__
+
+#include <stdint.h>
+
+/* This file is blessed for inclusion by userspace */
+#include <mtd/mtd-abi.h>
+
+typedef struct mtd_info_user mtd_info_t;
+typedef struct erase_info_user erase_info_t;
+typedef struct region_info_user region_info_t;
+typedef struct nand_oobinfo nand_oobinfo_t;
+
+#endif /* __MTD_USER_H__ */
diff --git a/include/mtd/nftl-user.h b/include/mtd/nftl-user.h
new file mode 100644 (file)
index 0000000..924ec04
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * $Id: nftl-user.h,v 1.1 2004/05/05 14:44:57 dwmw2 Exp $
+ *
+ * Parts of NFTL headers shared with userspace 
+ *
+ */
+
+#ifndef __MTD_NFTL_USER_H__
+#define __MTD_NFTL_USER_H__
+
+/* Block Control Information */
+
+struct nftl_bci {
+       unsigned char ECCSig[6];
+       uint8_t Status;
+       uint8_t Status1;
+}__attribute__((packed));
+
+/* Unit Control Information */
+
+struct nftl_uci0 {
+       uint16_t VirtUnitNum;
+       uint16_t ReplUnitNum;
+       uint16_t SpareVirtUnitNum;
+       uint16_t SpareReplUnitNum;
+} __attribute__((packed));
+
+struct nftl_uci1 {
+       uint32_t WearInfo;
+       uint16_t EraseMark;
+       uint16_t EraseMark1;
+} __attribute__((packed));
+
+struct nftl_uci2 {
+        uint16_t FoldMark;
+        uint16_t FoldMark1;
+       uint32_t unused;
+} __attribute__((packed));
+
+union nftl_uci {
+       struct nftl_uci0 a;
+       struct nftl_uci1 b;
+       struct nftl_uci2 c;
+};
+
+struct nftl_oob {
+       struct nftl_bci b;
+       union nftl_uci u;
+};
+
+/* NFTL Media Header */
+
+struct NFTLMediaHeader {
+       char DataOrgID[6];
+       uint16_t NumEraseUnits;
+       uint16_t FirstPhysicalEUN;
+       uint32_t FormattedSize;
+       unsigned char UnitSizeFactor;
+} __attribute__((packed));
+
+#define MAX_ERASE_ZONES (8192 - 512)
+
+#define ERASE_MARK 0x3c69
+#define SECTOR_FREE 0xff
+#define SECTOR_USED 0x55
+#define SECTOR_IGNORE 0x11
+#define SECTOR_DELETED 0x00
+
+#define FOLD_MARK_IN_PROGRESS 0x5555
+
+#define ZONE_GOOD 0xff
+#define ZONE_BAD_ORIGINAL 0
+#define ZONE_BAD_MARKED 7
+
+
+#endif /* __MTD_NFTL_USER_H__ */