size_t * retlen, u_char * buf)
{
struct mtd_concat *concat = CONCAT(mtd);
- int err = -EINVAL;
+ int ret = 0, err;
int i;
*retlen = 0;
err = subdev->read(subdev, from, size, &retsize, buf);
- if (err)
- break;
+ /* Save information about bitflips! */
+ if (unlikely(err)) {
+ if (err == -EBADMSG) {
+ mtd->ecc_stats.failed++;
+ ret = err;
+ } else if (err == -EUCLEAN) {
+ mtd->ecc_stats.corrected++;
+ /* Do not overwrite -EBADMSG !! */
+ if (!ret)
+ ret = err;
+ } else
+ return err;
+ }
*retlen += retsize;
len -= size;
if (len == 0)
- break;
+ return ret;
- err = -EINVAL;
buf += size;
from = 0;
}
- return err;
+ return -EINVAL;
}
static int
{
struct mtd_concat *concat = CONCAT(mtd);
struct mtd_oob_ops devops = *ops;
- int i, err;
+ int i, err, ret = 0;
- ops->retlen = 0;
+ ops->retlen = ops->oobretlen = 0;
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
err = subdev->read_oob(subdev, from, &devops);
ops->retlen += devops.retlen;
- if (err)
- return err;
-
- devops.len = ops->len - ops->retlen;
- if (!devops.len)
- return 0;
+ ops->oobretlen += devops.oobretlen;
+
+ /* Save information about bitflips! */
+ if (unlikely(err)) {
+ if (err == -EBADMSG) {
+ mtd->ecc_stats.failed++;
+ ret = err;
+ } else if (err == -EUCLEAN) {
+ mtd->ecc_stats.corrected++;
+ /* Do not overwrite -EBADMSG !! */
+ if (!ret)
+ ret = err;
+ } else
+ return err;
+ }
- if (devops.datbuf)
+ if (devops.datbuf) {
+ devops.len = ops->len - ops->retlen;
+ if (!devops.len)
+ return ret;
devops.datbuf += devops.retlen;
- if (devops.oobbuf)
- devops.oobbuf += devops.ooblen;
+ }
+ if (devops.oobbuf) {
+ devops.ooblen = ops->ooblen - ops->oobretlen;
+ if (!devops.ooblen)
+ return ret;
+ devops.oobbuf += ops->oobretlen;
+ }
from = 0;
}
if (err)
return err;
- devops.len = ops->len - ops->retlen;
- if (!devops.len)
- return 0;
-
- if (devops.datbuf)
+ if (devops.datbuf) {
+ devops.len = ops->len - ops->retlen;
+ if (!devops.len)
+ return 0;
devops.datbuf += devops.retlen;
- if (devops.oobbuf)
- devops.oobbuf += devops.ooblen;
+ }
+ if (devops.oobbuf) {
+ devops.ooblen = ops->ooblen - ops->oobretlen;
+ if (!devops.ooblen)
+ return 0;
+ devops.oobbuf += devops.oobretlen;
+ }
to = 0;
}
return -EINVAL;
}
err = subdev->block_markbad(subdev, ofs);
+ if (!err)
+ mtd->ecc_stats.badblocks++;
break;
}
/* allocate the device structure */
size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
- concat = kmalloc(size, GFP_KERNEL);
+ concat = kzalloc(size, GFP_KERNEL);
if (!concat) {
printk
("memory allocation error while creating concatenated device \"%s\"\n",
name);
return NULL;
}
- memset(concat, 0, size);
concat->subdev = (struct mtd_info **) (concat + 1);
/*
concat->mtd.erasesize = subdev[0]->erasesize;
concat->mtd.writesize = subdev[0]->writesize;
concat->mtd.oobsize = subdev[0]->oobsize;
- concat->mtd.ecctype = subdev[0]->ecctype;
- concat->mtd.eccsize = subdev[0]->eccsize;
if (subdev[0]->writev)
concat->mtd.writev = concat_writev;
if (subdev[0]->read_oob)
if (subdev[0]->block_markbad)
concat->mtd.block_markbad = concat_block_markbad;
+ concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
+
concat->subdev[0] = subdev[0];
for (i = 1; i < num_devs; i++) {
subdev[i]->flags & MTD_WRITEABLE;
}
concat->mtd.size += subdev[i]->size;
+ concat->mtd.ecc_stats.badblocks +=
+ subdev[i]->ecc_stats.badblocks;
if (concat->mtd.writesize != subdev[i]->writesize ||
+ concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
concat->mtd.oobsize != subdev[i]->oobsize ||
- concat->mtd.ecctype != subdev[i]->ecctype ||
- concat->mtd.eccsize != subdev[i]->eccsize ||
!concat->mtd.read_oob != !subdev[i]->read_oob ||
!concat->mtd.write_oob != !subdev[i]->write_oob) {
kfree(concat);