All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pantelis Antoniou <panto@intracom.gr>
To: linux-mtd@lists.infradead.org
Subject: [PATCH] Error free RO mtdblock device for NAND chips
Date: Thu, 12 Jun 2003 15:57:09 +0300	[thread overview]
Message-ID: <3EE878A5.8040400@intracom.gr> (raw)

[-- 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");

             reply	other threads:[~2003-06-12 12:57 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-06-12 12:57 Pantelis Antoniou [this message]
2003-06-13  8:26 ` [PATCH] Error free RO mtdblock device for NAND chips Pantelis Antoniou

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3EE878A5.8040400@intracom.gr \
    --to=panto@intracom.gr \
    --cc=linux-mtd@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.