* [PATCH] Error free RO mtdblock device for NAND chips
@ 2003-06-12 12:57 Pantelis Antoniou
2003-06-13 8:26 ` Pantelis Antoniou
0 siblings, 1 reply; 2+ messages in thread
From: Pantelis Antoniou @ 2003-06-12 12:57 UTC (permalink / raw)
To: linux-mtd
[-- Attachment #1: Type: text/plain, Size: 626 bytes --]
Hi there
Following the discussion in the list the previous day
here is a patch that implements a very simple read-only
error free block device interface in order to allow
NAND chips to use filesystems like CRAMFS.
The theory of operation is very simple.
There is a mapping array for every block in the device
which provides the number of the physical NAND block
which it resides.
This is not the final driver. It's only a base for
discussion for the list.
I haven't done any serious tests really, but I was
able to mount a CRAMFS filesystem over it and
read files OK.
Comments and/or flames welcome.
Regards
Pantelis
[-- Attachment #2: mtdblockn.patch --]
[-- Type: text/plain, Size: 7214 bytes --]
diff -ubBrN drivers/mtd/Config.in drivers-nand/mtd/Config.in
--- drivers/mtd/Config.in Thu Jun 12 15:44:47 2003
+++ drivers-nand/mtd/Config.in Thu Jun 12 15:43:57 2003
@@ -30,6 +30,7 @@
if [ "$CONFIG_NFTL" = "y" -o "$CONFIG_NFTL" = "m" ]; then
bool ' Write support for NFTL (BETA)' CONFIG_NFTL_RW
fi
+ dep_tristate ' Read-only block device access to NAND MTD devices' CONFIG_MTD_BLOCKN $CONFIG_MTD
source drivers/mtd/chips/Config.in
diff -ubBrN drivers/mtd/Makefile drivers-nand/mtd/Makefile
--- drivers/mtd/Makefile Thu Jun 12 15:44:47 2003
+++ drivers-nand/mtd/Makefile Thu Jun 12 15:43:57 2003
@@ -48,6 +48,7 @@
obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o $(mtd_blkdevs)
obj-$(CONFIG_FTL) += ftl.o $(mtd_blkdevs)
obj-$(CONFIG_NFTL) += nftl.o $(mtd_blkdevs)
+obj-$(CONFIG_MTD_BLOCKN) += mtdblock_nro.o $(mtd_blkdevs)
ifeq ($(BELOW25),y)
obj-y += chips/chipslink.o maps/mapslink.o \
diff -ubBrN drivers/mtd/mtdblock_nro.c drivers-nand/mtd/mtdblock_nro.c
--- drivers/mtd/mtdblock_nro.c Thu Jan 1 02:00:00 1970
+++ drivers-nand/mtd/mtdblock_nro.c Thu Jun 12 15:43:57 2003
@@ -0,0 +1,272 @@
+/*
+ * $Id:$
+ *
+ * Pantelis Antoniou <panto@intracom.gr>
+ * Intracom S.A.
+ *
+ * Read-only block device for NAND devices
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/blktrans.h>
+#include <linux/mtd/nand.h>
+
+/*********************************************************/
+
+/*
+ * XXX the following are copied from fs/jffs2/wbuf.c
+ * XXX care must be taken to keep them in sync
+ */
+
+#define JFFS2_OOB_ECCPOS0 0
+#define JFFS2_OOB_ECCPOS1 1
+#define JFFS2_OOB_ECCPOS2 2
+#define JFFS2_OOB_ECCPOS3 3
+#define JFFS2_OOB_ECCPOS4 6
+#define JFFS2_OOB_ECCPOS5 7
+
+#define NAND_JFFS2_OOB8_FSDAPOS 6
+#define NAND_JFFS2_OOB16_FSDAPOS 8
+#define NAND_JFFS2_OOB8_FSDALEN 2
+#define NAND_JFFS2_OOB16_FSDALEN 8
+
+static struct nand_oobinfo jffs2_oobinfo = {
+ useecc: 1,
+ eccpos: {JFFS2_OOB_ECCPOS0, JFFS2_OOB_ECCPOS1, JFFS2_OOB_ECCPOS2, JFFS2_OOB_ECCPOS3, JFFS2_OOB_ECCPOS4, JFFS2_OOB_ECCPOS5}
+};
+
+/*********************************************************/
+
+static struct mtdblk_dev {
+ struct mtd_info *mtd;
+ int count;
+ int bad;
+ struct semaphore map_sem;
+ int *map;
+ int map_top;
+ int map_scantop;
+ int oob_per_block;
+ u_char *oobbuf;
+} *mtdblks[MAX_MTD_DEVICES];
+
+static int mtdblock_readsect(struct mtd_blktrans_dev *dev,
+ unsigned long block, char *buf)
+{
+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
+ struct mtd_info *mtd = mtdblk->mtd;
+ size_t retlen;
+ int i, ret, pos;
+
+ /* for devices with no oob do it directly */
+ pos = block * 512;
+ if (!mtdblk->map) {
+ if (mtd->read(mtd, pos, 512, &retlen, buf))
+ return 1;
+ return 0;
+ }
+
+ down(&mtdblk->map_sem);
+
+ /* scan the chip as it appropriate */
+ while (mtdblk->map_scantop < 0 || block > mtdblk->map_scantop) {
+
+ if (mtdblk->map_scantop >= 0)
+ i = mtdblk->map[mtdblk->map_scantop] + 1;
+ else
+ i = 0;
+
+ for (; i < mtdblk->map_top; i++) {
+
+ ret = mtd->read_oob(mtd, i * 512, mtd->oobsize, &retlen, mtdblk->oobbuf);
+
+ if (ret >= 0 && mtdblk->oobbuf[5] == 0xff)
+ break;
+ }
+
+ if (i >= mtdblk->map_top) {
+ up(&mtdblk->map_sem);
+ printk(KERN_WARNING "mtdblockn: too many bad blocks\n");
+ return 0;
+ }
+
+ if (mtdblk->map_scantop < 0)
+ mtdblk->map_scantop = 0;
+ else
+ mtdblk->map_scantop++;
+
+ mtdblk->map[mtdblk->map_scantop] = i;
+ }
+
+ up(&mtdblk->map_sem);
+
+ pos = mtdblk->map[block] * 512;
+
+ /* XXX we don't really expect this to fail! */
+ if (mtd->read_ecc(mtd, pos, 512, &retlen, buf, NULL, &jffs2_oobinfo))
+ return 1;
+ return 0;
+}
+
+static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
+ unsigned long block, char *buf)
+{
+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
+ size_t retlen;
+
+ /* for devices with no oob do it directly */
+ if (!mtdblk->map) {
+ if (dev->mtd->write(dev->mtd, (block * 512), 512, &retlen, buf))
+ return 1;
+ return 0;
+ }
+
+ /* We don't perform writes anyway */
+ return 0;
+}
+
+static int mtdblock_open(struct mtd_blktrans_dev *mbd, struct inode *inode, struct file *file)
+{
+ struct mtdblk_dev *mtdblk;
+ struct mtd_info *mtd = mbd->mtd;
+ int dev = mbd->devnum;
+ int err;
+ int i;
+
+ DEBUG(MTD_DEBUG_LEVEL1,"mtdblockn_open\n");
+
+ if (mtdblks[dev]) {
+ mtdblks[dev]->count++;
+ return 0;
+ }
+
+ err = 0;
+
+ /* OK, it's not open. Create cache info for it */
+ mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
+ if (!mtdblks) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ memset(mtdblk, 0, sizeof(*mtdblk));
+
+ mtdblk->count = 1;
+ mtdblk->mtd = mtd;
+
+ init_MUTEX(&mtdblk->map_sem);
+
+ if (mtd->oobblock) {
+ mtdblk->map_top = mtd->size / 512;
+ mtdblk->map = kmalloc(sizeof(int) * mtdblk->map_top + mtd->oobsize, GFP_KERNEL);
+ if (!mtdblk->map) {
+ err = -ENOMEM;
+ goto out_free;
+ }
+ mtdblk->map_scantop = -1;
+ for (i = 0; i < mtdblk->map_top; i++)
+ mtdblk->map[i] = -1; /* mark not present */
+ mtdblk->oob_per_block = 512 / mtd->oobblock;
+
+ /* buff for oob data */
+ mtdblk->oobbuf = (u_char *)(mtdblk->map + mtdblk->map_top);
+ }
+
+ mtdblks[dev] = mtdblk;
+
+ DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
+
+ return 0;
+
+out_free:
+ kfree(mtdblk);
+out:
+ return err;
+}
+
+static int mtdblock_release(struct mtd_blktrans_dev *mbd,
+ struct inode *inode, struct file *file)
+{
+ int dev;
+ struct mtdblk_dev *mtdblk;
+
+ DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
+
+ dev = minor(inode->i_rdev);
+ mtdblk = mtdblks[dev];
+
+ if (!--mtdblk->count) {
+ /* It was the last usage. Free the device */
+ mtdblks[dev] = NULL;
+ if (mtdblk->mtd->sync) /* XXX possibly redundant for a RO fs */
+ mtdblk->mtd->sync(mtdblk->mtd);
+
+ if (mtdblk->map)
+ kfree(mtdblk->map);
+
+ kfree(mtdblk);
+ }
+ DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
+
+ return 0;
+}
+
+
+static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
+{
+ struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+
+ if (!dev)
+ return;
+
+ memset(dev, 0, sizeof(*dev));
+
+ dev->mtd = mtd;
+ dev->devnum = mtd->index;
+ dev->blksize = 512;
+ dev->size = mtd->size >> 9;
+ dev->tr = tr;
+
+ /* force read-only */
+ dev->readonly = 1;
+
+ add_mtd_blktrans_dev(dev);
+}
+
+static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev)
+{
+ del_mtd_blktrans_dev(dev);
+ kfree(dev);
+}
+
+struct mtd_blktrans_ops mtdblockn_tr = {
+ .name = "mtdblockn",
+ .major = 128,
+ .part_bits = 0,
+ .open = mtdblock_open,
+ .release = mtdblock_release,
+ .readsect = mtdblock_readsect,
+ .writesect = mtdblock_writesect,
+ .add_mtd = mtdblock_add_mtd,
+ .remove_dev = mtdblock_remove_dev,
+ .owner = THIS_MODULE,
+};
+
+static int __init mtdblock_init(void)
+{
+ return register_mtd_blktrans(&mtdblockn_tr);
+}
+
+static void __exit mtdblock_exit(void)
+{
+ deregister_mtd_blktrans(&mtdblockn_tr);
+}
+
+module_init(mtdblock_init);
+module_exit(mtdblock_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>");
+MODULE_DESCRIPTION("Read-only block device emulation access to MTD devices with bad blocks");
^ permalink raw reply [flat|nested] 2+ messages in thread* Re: [PATCH] Error free RO mtdblock device for NAND chips
2003-06-12 12:57 [PATCH] Error free RO mtdblock device for NAND chips Pantelis Antoniou
@ 2003-06-13 8:26 ` Pantelis Antoniou
0 siblings, 0 replies; 2+ messages in thread
From: Pantelis Antoniou @ 2003-06-13 8:26 UTC (permalink / raw)
To: linux-mtd
Well, obviously this thing will not work since I mistakenly
use a block size of 512, instead of the erase size
of the device as supported by the nandwrite utility.
My device had no bad blocks, so everything worked by chance.
Reading the NAND documentation for the JFFS2 OOB usage
it states the the valid block marker is used for the first page
in a block.
I thought that it meant a block device block, but it appears
that it is the erase block.
So a new patch will be produced shortly.
Regards
Pantelis
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2003-06-13 8:27 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-06-12 12:57 [PATCH] Error free RO mtdblock device for NAND chips Pantelis Antoniou
2003-06-13 8:26 ` Pantelis Antoniou
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox