X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=drivers%2Fmtd%2Fmtdconcat.c;h=1fea631b58520aef095c356730709722f6b38248;hb=cd529a46e17b43976d05c1e2ece2676ec7941cc8;hp=6d52137988faf3e5fe29e628294044a145d37a00;hpb=0305c8659ff9cebabf469d5cd0ab8dc384857e10;p=powerpc.git diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 6d52137988..1fea631b58 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, size_t * retlen, u_char * buf) { struct mtd_concat *concat = CONCAT(mtd); - int err = -EINVAL; + int ret = 0, err; int i; *retlen = 0; @@ -80,19 +80,29 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len, 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 @@ -231,101 +241,97 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs, } static int -concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len, - size_t * retlen, u_char * buf) +concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { struct mtd_concat *concat = CONCAT(mtd); - int err = -EINVAL; - int i; + struct mtd_oob_ops devops = *ops; + int i, err, ret = 0; - *retlen = 0; + ops->retlen = 0; for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - size_t size, retsize; if (from >= subdev->size) { - /* Not destined for this subdev */ - size = 0; from -= subdev->size; continue; } - if (from + len > subdev->size) - /* First part goes into this subdev */ - size = subdev->size - from; - else - /* Entire transaction goes into this subdev */ - size = len; - if (subdev->read_oob) - err = subdev->read_oob(subdev, from, size, - &retsize, buf); - else - err = -EINVAL; + /* partial read ? */ + if (from + devops.len > subdev->size) + devops.len = subdev->size - from; + + err = subdev->read_oob(subdev, from, &devops); + ops->retlen += devops.retlen; + + /* 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 (err) - break; + devops.len = ops->len - ops->retlen; + if (!devops.len) + return ret; - *retlen += retsize; - len -= size; - if (len == 0) - break; + if (devops.datbuf) + devops.datbuf += devops.retlen; + if (devops.oobbuf) + devops.oobbuf += devops.ooblen; - err = -EINVAL; - buf += size; from = 0; } - return err; + return -EINVAL; } static int -concat_write_oob(struct mtd_info *mtd, loff_t to, size_t len, - size_t * retlen, const u_char * buf) +concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) { struct mtd_concat *concat = CONCAT(mtd); - int err = -EINVAL; - int i; + struct mtd_oob_ops devops = *ops; + int i, err; if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; - *retlen = 0; + ops->retlen = 0; for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - size_t size, retsize; if (to >= subdev->size) { - size = 0; to -= subdev->size; continue; } - if (to + len > subdev->size) - size = subdev->size - to; - else - size = len; - if (!(subdev->flags & MTD_WRITEABLE)) - err = -EROFS; - else if (subdev->write_oob) - err = subdev->write_oob(subdev, to, size, &retsize, - buf); - else - err = -EINVAL; + /* partial write ? */ + if (to + devops.len > subdev->size) + devops.len = subdev->size - to; + err = subdev->write_oob(subdev, to, &devops); + ops->retlen += devops.retlen; if (err) - break; + return err; - *retlen += retsize; - len -= size; - if (len == 0) - break; + devops.len = ops->len - ops->retlen; + if (!devops.len) + return 0; - err = -EINVAL; - buf += size; + if (devops.datbuf) + devops.datbuf += devops.retlen; + if (devops.oobbuf) + devops.oobbuf += devops.ooblen; to = 0; } - return err; + return -EINVAL; } static void concat_erase_callback(struct erase_info *instr) @@ -662,6 +668,8 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs) } err = subdev->block_markbad(subdev, ofs); + if (!err) + mtd->ecc_stats.badblocks++; break; } @@ -724,6 +732,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c 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++) { @@ -751,6 +761,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c 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.oobsize != subdev[i]->oobsize || concat->mtd.ecctype != subdev[i]->ecctype || @@ -766,9 +778,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c } - if(concat->mtd.type == MTD_NANDFLASH) - memcpy(&concat->mtd.oobinfo, &subdev[0]->oobinfo, - sizeof(struct nand_oobinfo)); + concat->mtd.ecclayout = subdev[0]->ecclayout; concat->num_subdev = num_devs; concat->mtd.name = name;