[PATCH] jffs2 on DOC

Dan Brown brown at osdsun1.nrl.navy.mil
Mon Dec 3 09:28:09 EST 2001


I have jffs2 working on DOC in a preliminary fashion.  The included patch
incorporates the following changes (if people object to inline patches, I
apologize -- let me know and I'll use attachments instead):
 - Modify doc2k driver to allow reads/writes that cross 512-byte boundaries
(btw, thanks for the reply, David :)
 - Modify doc2k driver to optionally use a 'fake' partitioning scheme in
which the device is arbitrarily broken into two subdevices.  This is
controlled by kernel config options, and can be disabled.
 - Modify mtdpart.c to pass the read_ecc(), write_ecc(), read_oob(), and
write_oob() functions to the master device.
 - Modify eraseall.c to add a -oob option which writes 0xFF to every oob
location on a device after erasing it.  I found myself getting into a state
where the M-systems tools (dformat) refused to work with my device anymore,
even refusing to do a complete reformat.  Using eraseall with the -oob
option seems to fix this, and convince dformat we have a 'truly' virgin
device.

I now have a bootable DOC Millenium 8M, with a roughly 1M bootable nftl
partition, and the rest as a raw jffs2 partition.  I use the following
procedure:
 - make sure the M-systems firmware is loaded on the device (using dformat,
for instance).  grub would work, but not on the Millenium, yet (as I
understand it.)
 - in linux, load the DOC modules which have been compiled to split the
device into a 1M boot partition and a remainder.
 - nftl_format /dev/mtd0 0xa000
 - eraseall /dev/mtd1
 - cp jffs2.img /dev/mtd1
 - modprobe nftl
 - fdisk /dev/nftla
 - make a filesystem on /dev/nftla1 (I used msdos, and syslinux to make it
boot the kernel, but there are many methods.)
 - mount -t msdos /dev/nftla1 /flashboot
 - stick the kernel image in /flashboot
 - modprobe jffs2
 - modprobe mtdblock
 - mount -t jffs2 /dev/mtdblock1 /flash
 - enjoy

The linux image I put in the boot partition has the mtd stuff compiled in,
rather than as modules, and uses /dev/mtdblock1 as its root partition
(jffs2).  Everything works great.

A few caveats:
 - Not tested on DOC2k yet, only on Millenium. (Shouldn't matter).
 - Doesn't do ECC properly.  In fact, I suppressed the warning message in
doc2000.c about non-block-aligned writes, because it was popping up
continuously.  Given what David said about jffs2 with NAND devices, I think
the thing to do is fix this from the jffs2 end, not the doc2k end.
 - Boot partition size is currently chosen at kernel compile time, rather
than runtime.  This is not ideal.

Comments appreciated.

    -Dan Brown


------------------------------------------ patch
follows ---------------------------------------------
diff -u -r mtd-20011126/drivers/mtd/devices/Config.in
mtd/drivers/mtd/devices/Config.in
--- mtd-20011126/drivers/mtd/devices/Config.in Sun Sep 23 18:00:03 2001
+++ mtd/drivers/mtd/devices/Config.in Mon Dec  3 08:28:27 2001
@@ -27,6 +27,11 @@
 comment 'Disk-On-Chip Device Drivers'
    dep_tristate '  M-Systems Disk-On-Chip 1000' CONFIG_MTD_DOC1000
$CONFIG_MTD
    dep_tristate '  M-Systems Disk-On-Chip 2000 and Millennium'
CONFIG_MTD_DOC2000 $CONFIG_MTD
+   dep_mbool '    Fake partition support for DOC2000'
CONFIG_MTD_DOC2K_FAKEPART $CONFIG_MTD_DOC2000 $CONFIG_MTD_PARTITIONS
+   if [ "$CONFIG_MTD_DOC2K_FAKEPART" = "y" ]; then
+      hex '      Size of first partition' CONFIG_MTD_DOC2K_PARTLEN 0x10a000
+      bool '      Create full (unpartitioned) device also'
CONFIG_MTD_DOC2K_FULLDEV
+   fi
    dep_tristate '  M-Systems Disk-On-Chip Millennium-only alternative
driver (see help)' CONFIG_MTD_DOC2001 $CONFIG_MTD
    if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then
       define_bool CONFIG_MTD_DOCPROBE y
diff -u -r mtd-20011126/drivers/mtd/devices/doc2000.c
mtd/drivers/mtd/devices/doc2000.c
--- mtd-20011126/drivers/mtd/devices/doc2000.c Tue Oct  2 18:00:19 2001
+++ mtd/drivers/mtd/devices/doc2000.c Mon Dec  3 08:37:56 2001
@@ -24,6 +24,9 @@
 #include <linux/mtd/nand.h>
 #include <linux/mtd/nand_ids.h>
 #include <linux/mtd/doc2000.h>
+#ifdef CONFIG_MTD_DOC2K_FAKEPART
+#include <linux/mtd/partitions.h>
+#endif

 #define DOC_SUPPORT_2000
 #define DOC_SUPPORT_MILLENNIUM
@@ -503,6 +506,24 @@
  return retval;
 }

+#ifdef CONFIG_MTD_DOC2K_FAKEPART
+static struct mtd_partition doc_partitions[] =
+{
+ {
+  name: "boot",
+  offset: 0,
+  size: CONFIG_MTD_DOC2K_PARTLEN,
+  mask_flags: 0
+ },
+ {
+  name: "data",
+  offset: MTDPART_OFS_NXTBLK,
+  size: MTDPART_SIZ_FULL,
+  mask_flags: 0
+ }
+};
+#endif
+
 static const char im_name[] = "DoC2k_init";

 /* This routine is made available to other mtd code via
@@ -580,7 +601,11 @@
  /* Ident all the chips present. */
  DoC_ScanChips(this);

+#ifdef CONFIG_MTD_DOC2K_FAKEPART
+ if (!this->totlen || (CONFIG_MTD_DOC2K_PARTLEN >= this->totlen)) {
+#else
  if (!this->totlen) {
+#endif
   kfree(mtd);
   iounmap((void *) this->virtadr);
  } else {
@@ -588,7 +613,12 @@
   doc2klist = mtd;
   mtd->size = this->totlen;
   mtd->erasesize = this->erasesize;
+#if (!defined(CONFIG_MTD_DOC2K_FAKEPART) ||
defined(CONFIG_MTD_DOC2K_FULLDEV))
   add_mtd_device(mtd);
+#endif
+#ifdef CONFIG_MTD_DOC2K_FAKEPART
+  add_mtd_partitions(mtd, doc_partitions, 2);
+#endif
   return;
  }
 }
@@ -609,6 +639,7 @@
  unsigned char syndrome[6];
  volatile char dummy;
  int i, len256 = 0, ret=0;
+ size_t left = len;

  docptr = this->virtadr;

@@ -618,122 +649,131 @@

  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);
+ *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;

- /* printk("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len); */
+  /* 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); */

- /* Find the chip which is to be used and select it */
- mychip = &this->chips[from >> (this->chipshift)];

- 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[from >> (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);
+  }

- 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);
- }
+  this->curfloor = mychip->floor;
+  this->curchip = mychip->chip;

- /* 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);
+  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);

-  DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
-  DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
-       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);
+  }

- DoC_ReadBuf(this, &buf[len256], len - len256);
+  /* 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);
+
+   DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP);
+   DoC_Address(this, ADDR_COLUMN_PAGE, from + len256,
+        CDSN_CTRL_WP, CDSN_CTRL_ECC_IO);
+  }

- /* Let the caller know we completed it */
- *retlen = len;
+  DoC_ReadBuf(this, &buf[len256], len - len256);

- 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);
-  }
+  /* 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 */
+   /* 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);
@@ -758,6 +798,7 @@
  volatile char dummy;
  int len256 = 0;
  struct Nand *mychip;
+ size_t left = len;

  docptr = this->virtadr;

@@ -767,55 +808,114 @@

  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;
-
- /* 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);
+ *retlen = 0;
+ while (left) {
+  len = left;
+
+  /* Don't allow a single write to cross a 512-byte block boundary */
+  if (to + len > ((to | 0x1ff) + 1))
+   len = ((to | 0x1ff) + 1) - to;
+
+  /* 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 */

- /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */
+  /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */

- /* Find the chip which is to be used and select it */
- mychip = &this->chips[to >> (this->chipshift)];
+  /* Find the chip which is to be used and select it */
+  mychip = &this->chips[to >> (this->chipshift)];

- 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);
- }
+  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);
+  }

- this->curfloor = mychip->floor;
- this->curchip = mychip->chip;
+  this->curfloor = mychip->floor;
+  this->curchip = 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);
+  /* 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);

- DoC_Command(this, NAND_CMD_SEQIN, 0);
- DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
+  DoC_Command(this, NAND_CMD_SEQIN, 0);
+  DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);

- 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);
- }
+  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);
+  /* 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);
+   }
+
+   /* 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);

@@ -833,78 +933,33 @@
    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);
-  }
-
-  /* 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 (ReadDOC_(docptr, this->ioreg) & 1) {
-  printk(KERN_ERR "Error programming flash\n");
-  /* Error in programming */
-  *retlen = 0;
-  up(&this->lock);
-  return -EIO;
- }
-
- /* Let the caller know we completed it */
- *retlen = len;
+  /* 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];
+  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;
+   x[6]=0x55;
+   x[7]=0x55;

-  ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
-  up(&this->lock);
-  return ret;
+   ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x);
+   if (ret) {
+    up(&this->lock);
+    return ret;
+   }
+  }
+
+  to += len;
+  left -= len;
+  buf += len;
  }
+
  up(&this->lock);
  return 0;
 }
@@ -1156,7 +1211,12 @@
   this = (struct DiskOnChip *) mtd->priv;
   doc2klist = this->nextdoc;

+#ifdef CONFIG_MTD_DOC2K_FAKEPART
+  del_mtd_partitions(mtd);
+#endif
+#if (!defined(CONFIG_MTD_DOC2K_FAKEPART) ||
defined(CONFIG_MTD_DOC2K_FULLDEV))
   del_mtd_device(mtd);
+#endif

   iounmap((void *) this->virtadr);
   kfree(this->chips);
diff -u -r mtd-20011126/drivers/mtd/mtdpart.c mtd/drivers/mtd/mtdpart.c
--- mtd-20011126/drivers/mtd/mtdpart.c Wed Nov  7 18:00:21 2001
+++ mtd/drivers/mtd/mtdpart.c Mon Dec  3 08:39:50 2001
@@ -86,6 +86,58 @@
      from + part->offset, retlen);
 }

+static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
+   size_t *retlen, u_char *buf)
+{
+ struct mtd_part *part = PART(mtd);
+ if (from >= mtd->size)
+  len = 0;
+ else if (from + len > mtd->size)
+  len = mtd->size - from;
+ return part->master->read_oob (part->master, from + part->offset,
+     len, retlen, buf);
+}
+
+static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len,
+   size_t *retlen, const u_char *buf)
+{
+ struct mtd_part *part = PART(mtd);
+ if (!(mtd->flags & MTD_WRITEABLE))
+  return -EROFS;
+ if (to >= mtd->size)
+  len = 0;
+ else if (to + len > mtd->size)
+  len = mtd->size - to;
+ return part->master->write_oob (part->master, to + part->offset,
+     len, retlen, buf);
+}
+
+static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+   size_t *retlen, u_char *buf, u_char *eccbuf)
+{
+ struct mtd_part *part = PART(mtd);
+ if (from >= mtd->size)
+  len = 0;
+ else if (from + len > mtd->size)
+  len = mtd->size - from;
+ return part->master->read_ecc (part->master, from + part->offset,
+     len, retlen, buf, eccbuf);
+}
+
+static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
+   size_t *retlen, const u_char *buf, u_char *eccbuf)
+{
+ struct mtd_part *part = PART(mtd);
+ if (!(mtd->flags & MTD_WRITEABLE))
+  return -EROFS;
+ if (to >= mtd->size)
+  len = 0;
+ else if (to + len > mtd->size)
+  len = mtd->size - to;
+ return part->master->write_ecc (part->master, to + part->offset,
+     len, retlen, buf, eccbuf);
+}
+
 static int part_erase (struct mtd_info *mtd, struct erase_info *instr)
 {
  struct mtd_part *part = PART(mtd);
@@ -209,6 +261,14 @@
     slave->mtd.suspend = part_suspend;
     slave->mtd.resume = part_resume;
   }
+  if (master->read_oob)
+   slave->mtd.read_oob = part_read_oob;
+  if (master->write_oob)
+   slave->mtd.write_oob = part_write_oob;
+  if (master->read_ecc)
+   slave->mtd.read_ecc = part_read_ecc;
+  if (master->write_ecc)
+   slave->mtd.write_ecc = part_write_ecc;

   if (master->writev)
    slave->mtd.writev = part_writev;
diff -u -r mtd-20011126/util/eraseall.c mtd/util/eraseall.c
--- mtd-20011126/util/eraseall.c Fri Apr 27 18:00:06 2001
+++ mtd/util/eraseall.c Mon Dec  3 08:43:04 2001
@@ -37,6 +37,8 @@
 static const char *exe_name;
 static const char *mtd_device;
 static int quiet; /* true -- don't output progress */
+static int do_oob;
+#define OOBVAL 0xff

 static void process_options( int argc, char *argv[] );
 static void display_help();
@@ -47,6 +49,8 @@
     mtd_info_t meminfo;
     int fd;
     erase_info_t erase;
+    struct mtd_oob_buf oob;
+    unsigned char *oobbuf;

     process_options( argc, argv );

@@ -85,6 +89,35 @@
        printf( "\rErased %ld Kibyte @ %lx -- 100%% complete.       \n",
         meminfo.size/1024, 0L );
    }
+
+   if (!do_oob) return 0;
+
+   if (!(oobbuf = (unsigned char *) malloc(meminfo.oobsize))) {
+       fprintf( stderr, "%s: unable to malloc oob buffer\n", exe_name);
+       exit( 1 );
+   }
+   oob.length = meminfo.oobsize;
+   oob.ptr = oobbuf;
+   memset(oobbuf, OOBVAL, meminfo.oobsize);
+
+   for (oob.start = 0; oob.start < meminfo.size;
+        oob.start += meminfo.oobblock) {
+       if( !quiet ) {
+    printf( "\rSetting %d bytes of oob @ %lx to %02X -- %2ld %% complete.",
+            meminfo.oobsize, oob.start, OOBVAL,
+     oob.start*100/meminfo.size );
+       }
+       fflush( stdout );
+
+       if(ioctl( fd, MEMWRITEOOB, &oob) != 0)
+       {
+        fprintf( stderr, "\n%s: %s: OOB write failure: %s\n", exe_name,
+   mtd_device, strerror( errno) );
+       }
+   }
+   if( !quiet ) {
+       printf( "\nDone.\n" );
+   }

    return 0;
 }
@@ -98,13 +131,13 @@

     for(;;) {
         int option_index = 0;
-        static const char* short_options="q";
+        static const char* short_options="oq";
         static const struct option long_options[] = {
             {"help", no_argument, 0, 0},
             {"version", no_argument, 0, 0},
      {"quiet", no_argument, 0, 'q'},
      {"silent", no_argument, 0, 'q'},
-
+     {"oob", no_argument, 0, 'o'},
             {0, 0, 0, 0},
         };

@@ -128,6 +161,9 @@
  case 'q' :
      quiet=1;
      break;
+ case 'o' :
+     do_oob=1;
+     break;
         case '?' :
             error=1;
             break;
@@ -152,10 +188,11 @@
             "Erases all of the specified MTD device.\n"
             "\n"
             "  -q, --quiet    don't display progress messages\n"
+     "  -o, --oob      set all oob data to %02X\n"
      "      --silent   same as --quiet\n"
             "      --help     display this help and exit\n"
             "      --version  output version information and exit\n"
-            , exe_name);
+            , exe_name, OOBVAL);
     exit( 0 );
 }







More information about the linux-mtd mailing list