aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/mtdconcat.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-05-29 18:37:34 -0400
committerThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-05-29 18:37:34 -0400
commitf1a28c02843efcfcc41982149880bac3ac180234 (patch)
treeb15ca1a140e463ef3cde6b9a8591e7be172ee1f1 /drivers/mtd/mtdconcat.c
parent9a1fcdfd4bee27c418424cac47abf7c049541297 (diff)
[MTD] NAND Expose the new raw mode function and status info to userspace
The raw read/write access to NAND (without ECC) has been changed in the NAND rework. Expose the new way - setting the file mode via ioctl - to userspace. Also allow to read out the ecc statistics information so userspace tools can see that bitflips happened and whether errors where correctable or not. Also expose the number of bad blocks for the partition, so nandwrite can check if the data fits into the parition before writing to it. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/mtd/mtdconcat.c')
-rw-r--r--drivers/mtd/mtdconcat.c51
1 files changed, 35 insertions, 16 deletions
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 3c8d5e6fa010..1fea631b5852 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -56,7 +56,7 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
56 size_t * retlen, u_char * buf) 56 size_t * retlen, u_char * buf)
57{ 57{
58 struct mtd_concat *concat = CONCAT(mtd); 58 struct mtd_concat *concat = CONCAT(mtd);
59 int ret = 0, err = -EINVAL; 59 int ret = 0, err;
60 int i; 60 int i;
61 61
62 *retlen = 0; 62 *retlen = 0;
@@ -80,28 +80,29 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len,
80 80
81 err = subdev->read(subdev, from, size, &retsize, buf); 81 err = subdev->read(subdev, from, size, &retsize, buf);
82 82
83 if (err && (err != -EBADMSG) && (err != -EUCLEAN))
84 break;
85
86 /* Save information about bitflips! */ 83 /* Save information about bitflips! */
87 if (err) { 84 if (unlikely(err)) {
88 if (err == -EBADMSG) 85 if (err == -EBADMSG) {
89 ret = err; 86 mtd->ecc_stats.failed++;
90 else if (!ret)
91 ret = err; 87 ret = err;
92 err = 0; 88 } else if (err == -EUCLEAN) {
89 mtd->ecc_stats.corrected++;
90 /* Do not overwrite -EBADMSG !! */
91 if (!ret)
92 ret = err;
93 } else
94 return err;
93 } 95 }
94 96
95 *retlen += retsize; 97 *retlen += retsize;
96 len -= size; 98 len -= size;
97 if (len == 0) 99 if (len == 0)
98 break; 100 return ret;
99 101
100 err = -EINVAL;
101 buf += size; 102 buf += size;
102 from = 0; 103 from = 0;
103 } 104 }
104 return err ? err : ret; 105 return -EINVAL;
105} 106}
106 107
107static int 108static int
@@ -244,7 +245,7 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
244{ 245{
245 struct mtd_concat *concat = CONCAT(mtd); 246 struct mtd_concat *concat = CONCAT(mtd);
246 struct mtd_oob_ops devops = *ops; 247 struct mtd_oob_ops devops = *ops;
247 int i, err; 248 int i, err, ret = 0;
248 249
249 ops->retlen = 0; 250 ops->retlen = 0;
250 251
@@ -262,12 +263,24 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
262 263
263 err = subdev->read_oob(subdev, from, &devops); 264 err = subdev->read_oob(subdev, from, &devops);
264 ops->retlen += devops.retlen; 265 ops->retlen += devops.retlen;
265 if (err) 266
266 return err; 267 /* Save information about bitflips! */
268 if (unlikely(err)) {
269 if (err == -EBADMSG) {
270 mtd->ecc_stats.failed++;
271 ret = err;
272 } else if (err == -EUCLEAN) {
273 mtd->ecc_stats.corrected++;
274 /* Do not overwrite -EBADMSG !! */
275 if (!ret)
276 ret = err;
277 } else
278 return err;
279 }
267 280
268 devops.len = ops->len - ops->retlen; 281 devops.len = ops->len - ops->retlen;
269 if (!devops.len) 282 if (!devops.len)
270 return 0; 283 return ret;
271 284
272 if (devops.datbuf) 285 if (devops.datbuf)
273 devops.datbuf += devops.retlen; 286 devops.datbuf += devops.retlen;
@@ -655,6 +668,8 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
655 } 668 }
656 669
657 err = subdev->block_markbad(subdev, ofs); 670 err = subdev->block_markbad(subdev, ofs);
671 if (!err)
672 mtd->ecc_stats.badblocks++;
658 break; 673 break;
659 } 674 }
660 675
@@ -717,6 +732,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
717 if (subdev[0]->block_markbad) 732 if (subdev[0]->block_markbad)
718 concat->mtd.block_markbad = concat_block_markbad; 733 concat->mtd.block_markbad = concat_block_markbad;
719 734
735 concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
736
720 concat->subdev[0] = subdev[0]; 737 concat->subdev[0] = subdev[0];
721 738
722 for (i = 1; i < num_devs; i++) { 739 for (i = 1; i < num_devs; i++) {
@@ -744,6 +761,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
744 subdev[i]->flags & MTD_WRITEABLE; 761 subdev[i]->flags & MTD_WRITEABLE;
745 } 762 }
746 concat->mtd.size += subdev[i]->size; 763 concat->mtd.size += subdev[i]->size;
764 concat->mtd.ecc_stats.badblocks +=
765 subdev[i]->ecc_stats.badblocks;
747 if (concat->mtd.writesize != subdev[i]->writesize || 766 if (concat->mtd.writesize != subdev[i]->writesize ||
748 concat->mtd.oobsize != subdev[i]->oobsize || 767 concat->mtd.oobsize != subdev[i]->oobsize ||
749 concat->mtd.ecctype != subdev[i]->ecctype || 768 concat->mtd.ecctype != subdev[i]->ecctype ||