* jffs2 on DOC
@ 2001-11-27 18:26 Dan Brown
2001-12-01 9:32 ` David Woodhouse
0 siblings, 1 reply; 3+ messages in thread
From: Dan Brown @ 2001-11-27 18:26 UTC (permalink / raw)
To: linux-mtd
I'm trying to get jffs2 running on DOC. My tentative plan is to put two
partitions on the DOC; a small NFTL partition for booting and a large
partition containing a jffs2 filesystem. These "partitions" will initially
be produced by a slightly hacked version of the doc2000 driver which will
accept a new kernel configuration variable which tells it where to draw the
boundary between the two partitions. (The NFTL "partition" will of course
have its own partition table, etc, which complicates the terminology a bit,
but since it uses a different device namespace it shouldn't be too bad.) In
the long run a true on-flash partition table would be nice, but this scheme
should be quick and easy to implement, using add_mtd_partitions.
But first, I'm just trying to get jffs2 running on the entire, raw DOC
device, without an NFTL boot partition. The problem I'm having initially is
that jffs2 is getting short reads from the doc2000 driver. It seems to me I
could either:
- modify the jffs2 code to handle short reads, by issuing another read for
the remainder of the needed data, or
- modify the doc2k code to handle reads that cross 512 byte boundaries, by
issuing multiple low-level reads to the DOC.
The second option looks easier, but I'd appreciate advice.
Also, I'm a little confused about the read() vs read_ecc() and write() vs
write_ecc() routines. In some cases (NAND driver) it looks like a read() or
read_ecc() will always pull in an entire ecc block, and then return some
subportion of that to the caller if the caller didn't want an entire block.
This gives you the advantages of error correction even if you don't
explicitly call read_ecc(). In contrast, the DOC driver will never do ecc
unless called by read_ecc(), and even then will not do it properly unless
the caller gives block-aligned requests. With writes, the NAND driver will
always attempt to compute (and write) the ecc no matter which interface is
used, and it looks like there is some support for partial-block writes as
well, by reading the remainder of the block from the device before computing
the ecc. If I'm reading the code right, it won't work correctly if the
start of the write is not block-aligned. The DOC driver will do ECC on
writes no matter which interface you use (write() or write_ecc()), but again
it requires a full-block write for proper operation. This is all very
confusing.
So my question is, what is the intended semantics of read(), read_ecc(),
write(), and write_ecc()? I can't seem to find any clients of read_ecc() or
write_ecc(), so I can't figure out why a client would need access to the ecc
buffer. My personal preference, in regard to getting jffs2 working over
DOC, would be for the normal read() and write() functions to perform ecc
operations, including proper partial-block support. Can anyone shed any
light on this, or give me any pointers?
Thanks,
Dan Brown
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: jffs2 on DOC
2001-11-27 18:26 jffs2 on DOC Dan Brown
@ 2001-12-01 9:32 ` David Woodhouse
2001-12-03 14:28 ` [PATCH] " Dan Brown
0 siblings, 1 reply; 3+ messages in thread
From: David Woodhouse @ 2001-12-01 9:32 UTC (permalink / raw)
To: Dan Brown; +Cc: linux-mtd
brown@osdsun1.nrl.navy.mil said:
> But first, I'm just trying to get jffs2 running on the entire, raw DOC
> device, without an NFTL boot partition. The problem I'm having
> initially is that jffs2 is getting short reads from the doc2000
> driver.
This is just a symptom of the fact that the doc2000 driver wasn't written
to be a proper generic MTD driver, so I cut some corners. You should modify
the doc2k code to play nicely, doing longer reads/writes/erases etc.
> So my question is, what is the intended semantics of read(),
> read_ecc(), write(), and write_ecc()? I can't seem to find any
> clients of read_ecc() or write_ecc(), so I can't figure out why a
> client would need access to the ecc buffer.
The NFTL code needs it - currently, it writes the 512 byte data block, then
does a second write to write the contents of the ECC buffer, generated by
the first write.
> If I'm reading the code right, it won't work correctly if the start
> of the write is not block-aligned. The DOC driver will do ECC on
> writes no matter which interface you use (write() or write_ecc()), but
> again it requires a full-block write for proper operation. This is
> all very confusing.
NAND flash chips have restrictions on the number of times you can write to
any given 512-byte page between erases. That number can apparently be as
low as 1 write cycle to the main data area, and 2 write cycles to the spare
data area.
So you _have_ to write the whole 512 bytes at a time, because otherwise you
can't fill the rest without erasing the whole erase block and starting
again.
JFFS2 will need modification to deal with this - probably by caching the
512-byte page which is pending, then writing it out in one go. This way, we
have the added bonus that we can make use of the hardware ECC which the
DiskOnChip and some SmartMedia hardware is capable of, which is limited to
512-byte blocks.
JFFS2 will also need some other mods for operation on NAND flash, but the
above is the main task.
--
dwmw2
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH] jffs2 on DOC
2001-12-01 9:32 ` David Woodhouse
@ 2001-12-03 14:28 ` Dan Brown
0 siblings, 0 replies; 3+ messages in thread
From: Dan Brown @ 2001-12-03 14:28 UTC (permalink / raw)
To: linux-mtd
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 );
}
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2001-12-03 14:17 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2001-11-27 18:26 jffs2 on DOC Dan Brown
2001-12-01 9:32 ` David Woodhouse
2001-12-03 14:28 ` [PATCH] " Dan Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox