public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH] MTD: mtdconcat NAND/Sibley support (revised)
@ 2006-05-05 12:08 Belyakov, Alexander
  2006-05-05 13:51 ` Nicolas Pitre
  2006-05-15 12:25 ` Jörn Engel
  0 siblings, 2 replies; 9+ messages in thread
From: Belyakov, Alexander @ 2006-05-05 12:08 UTC (permalink / raw)
  To: linux-mtd

My previous message did not appear in mailing list. So I repost it.

This patch adds concat_writev(), concat_writev_ecc(),
concat_block_isbad(), concat_block_markbad() functions to make
concatenation layer compatible with Sibley and NAND chips.

The patch has been changed to use writev() functions of underlying
devices.

It has been verified on both Sibley and NAND before posting.


Signed-off-by: Alexander Belyakov <alexander.belyakov@intel.com>

-------

diff -uNr a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
--- a/drivers/mtd/mtdconcat.c	2006-04-07 20:56:47.000000000 +0400
+++ b/drivers/mtd/mtdconcat.c	2006-05-04 12:41:19.000000000 +0400
@@ -45,6 +45,13 @@
 #define CONCAT(x)  ((struct mtd_concat *)(x))
 
 /*
+ * Forward function declaration
+ */
+static int
+concat_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, 
+		loff_t to, size_t * retlen, u_char *eccbuf, struct
nand_oobinfo *oobsel);
+
+/*
  * MTD methods which look up the relevant subdevice, translate the
  * effective address and pass through to the subdevice.
  */
@@ -140,6 +147,14 @@
 	return err;
 }
 
+
+static int
+concat_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned
long count, 
+		loff_t to, size_t * retlen)
+{
+	return (concat_writev_ecc(mtd, vecs, count, to, retlen, NULL,
NULL));
+}
+
 static int
 concat_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
 		size_t * retlen, u_char * buf, u_char * eccbuf,
@@ -251,6 +266,107 @@
 }
 
 static int
+concat_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, 
+		loff_t to, size_t * retlen, u_char *eccbuf, struct
nand_oobinfo *oobsel)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	struct kvec *vecs_copy;
+	unsigned long entry_low, entry_high;
+	size_t total_len = 0;
+	int i;
+	int err = -EINVAL;
+	
+	if (!(mtd->flags & MTD_WRITEABLE))
+		return -EROFS;
+
+	*retlen = 0;
+
+	/* Calculate total length of data */
+	for (i = 0; i < count; i++)
+		total_len += vecs[i].iov_len;
+		
+	/* Do not allow write past end of page */
+	if ((to + total_len) > mtd->size) {
+		DEBUG (MTD_DEBUG_LEVEL0, "concat_writev_ecc(): Attempted
write past end of device\n");
+		return -EINVAL;
+	}
+    
+	/* Check alignment */
+	if (concat->mtd.type == MTD_NANDFLASH) {
+    		if ((to & (mtd->oobblock - 1)) || (total_len &
(mtd->oobblock - 1))) {
+			DEBUG (MTD_DEBUG_LEVEL0, "concat_writev_ecc():
Attempted write not aligned data!\n");
+			return -EINVAL;
+		}
+	}
+	
+	/* make a copy of vecs */
+	vecs_copy = kmalloc(sizeof(struct kvec) * count, GFP_KERNEL);
+	if (!vecs_copy)
+		return -ENOMEM;
+	memcpy(vecs_copy, vecs, sizeof(struct kvec) * count);
+
+	entry_low = 0;
+	for (i = 0; i < concat->num_subdev; i++) {
+		struct mtd_info *subdev = concat->subdev[i];
+		size_t size, wsize, retsize, old_iov_len;
+
+		if (to >= subdev->size) {
+			size = 0;
+			to -= subdev->size;
+			continue;
+		}
+		
+		if (to + total_len > subdev->size)
+			size = subdev->size - to;
+		else
+			size = total_len;
+		wsize = size; /* store for future use */
+
+		entry_high = entry_low;
+		while (entry_high < count) {
+			if (size > vecs_copy[entry_high].iov_len)
+				size -= vecs_copy[entry_high++].iov_len;
+			else
+				break;
+		}
+		
+		old_iov_len = vecs_copy[entry_high].iov_len;
+		vecs_copy[entry_high].iov_len = size;
+		
+		if (!(subdev->flags & MTD_WRITEABLE))
+			err = -EROFS;
+		else if (eccbuf)
+			err = subdev->writev_ecc(subdev,
&vecs_copy[entry_low],
+				entry_high - entry_low + 1, to,
&retsize, eccbuf, oobsel);
+		else
+			err = subdev->writev(subdev,
&vecs_copy[entry_low],
+				entry_high - entry_low + 1, to,
&retsize);
+
+		vecs_copy[entry_high].iov_len = old_iov_len - size;
+		vecs_copy[entry_high].iov_base = (void *)((u_char
*)vecs_copy[entry_high].iov_base + size);
+		
+		entry_low = entry_high;
+			
+		if (err)
+			break;
+
+		*retlen += retsize;
+		total_len -= wsize;
+		if (concat->mtd.type == MTD_NANDFLASH && eccbuf)
+			eccbuf += mtd->oobavail * (wsize /
mtd->oobblock);
+
+		if (total_len == 0)
+			break;
+
+		err = -EINVAL;
+		to = 0;
+	}
+	
+	kfree(vecs_copy);
+	return err;
+}
+
+static int
 concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
 		size_t * retlen, u_char * buf)
 {
@@ -638,6 +754,60 @@
 	}
 }
 
+static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int i, res = 0;
+	
+	if (!concat->subdev[0]->block_isbad)
+		return res;
+
+	if (ofs > mtd->size)
+		return -EINVAL;
+		
+	for (i = 0; i < concat->num_subdev; i++) {
+		struct mtd_info *subdev = concat->subdev[i];
+
+		if (ofs >= subdev->size) {
+			ofs -= subdev->size;
+			continue;
+		}
+		
+		res = subdev->block_isbad(subdev, ofs);
+
+		break;
+	}
+
+	return res;
+}
+
+static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+	struct mtd_concat *concat = CONCAT(mtd);
+	int i, err = -EINVAL;
+	
+	if (!concat->subdev[0]->block_markbad)
+		return 0;
+
+	if (ofs > mtd->size)
+		return -EINVAL;
+		
+	for (i = 0; i < concat->num_subdev; i++) {
+		struct mtd_info *subdev = concat->subdev[i];
+
+		if (ofs >= subdev->size) {
+			ofs -= subdev->size;
+			continue;
+		}
+		
+		err = subdev->block_markbad(subdev, ofs);
+
+		break;
+	}
+
+	return err;
+}
+
 /*
  * This function constructs a virtual MTD device by concatenating
  * num_devs MTD devices. A pointer to the new device object is
@@ -687,10 +857,18 @@
 		concat->mtd.read_ecc = concat_read_ecc;
 	if (subdev[0]->write_ecc)
 		concat->mtd.write_ecc = concat_write_ecc;
+	if (subdev[0]->writev)
+		concat->mtd.writev = concat_writev;
+	if (subdev[0]->writev_ecc)
+		concat->mtd.writev_ecc = concat_writev_ecc;
 	if (subdev[0]->read_oob)
 		concat->mtd.read_oob = concat_read_oob;
 	if (subdev[0]->write_oob)
 		concat->mtd.write_oob = concat_write_oob;
+	if (subdev[0]->block_isbad)
+		concat->mtd.block_isbad = concat_block_isbad;
+	if (subdev[0]->block_markbad)
+		concat->mtd.block_markbad = concat_block_markbad;
 
 	concat->subdev[0] = subdev[0];
 
@@ -736,14 +914,12 @@
 
 	}
 
+	if(concat->mtd.type == MTD_NANDFLASH)
+
memcpy(&concat->mtd.oobinfo,&subdev[0]->oobinfo,sizeof(struct
nand_oobinfo));
+
 	concat->num_subdev = num_devs;
 	concat->mtd.name = name;
 
-	/*
-	 * NOTE: for now, we do not provide any readv()/writev() methods
-	 *       because they are messy to implement and they are not
-	 *       used to a great extent anyway.
-	 */
 	concat->mtd.erase = concat_erase;
 	concat->mtd.read = concat_read;
 	concat->mtd.write = concat_write;



-------
The content of this message is my personal opinion only and although
I am an employee of Intel, the statements I make here
in no way represent Intel's position on the issue

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2006-05-16 12:22 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-05 12:08 [PATCH] MTD: mtdconcat NAND/Sibley support (revised) Belyakov, Alexander
2006-05-05 13:51 ` Nicolas Pitre
2006-05-15  9:30   ` Alexander Belyakov
2006-05-15 12:25 ` Jörn Engel
2006-05-16  6:34   ` Alexander Belyakov
2006-05-16  6:43     ` Jörn Engel
2006-05-16  8:33     ` Jörn Engel
2006-05-16 11:54       ` Artem B. Bityutskiy
2006-05-16 12:22         ` Jörn Engel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox