diff options
Diffstat (limited to 'drivers/mtd/mtdconcat.c')
| -rw-r--r-- | drivers/mtd/mtdconcat.c | 170 |
1 files changed, 55 insertions, 115 deletions
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index bf8de094310..b9000563b9f 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -72,8 +72,6 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len, int ret = 0, err; int i; - *retlen = 0; - for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; size_t size, retsize; @@ -91,14 +89,14 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len, /* Entire transaction goes into this subdev */ size = len; - err = subdev->read(subdev, from, size, &retsize, buf); + err = mtd_read(subdev, from, size, &retsize, buf); /* Save information about bitflips! */ if (unlikely(err)) { - if (err == -EBADMSG) { + if (mtd_is_eccerr(err)) { mtd->ecc_stats.failed++; ret = err; - } else if (err == -EUCLEAN) { + } else if (mtd_is_bitflip(err)) { mtd->ecc_stats.corrected++; /* Do not overwrite -EBADMSG !! */ if (!ret) @@ -126,11 +124,6 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len, int err = -EINVAL; int i; - if (!(mtd->flags & MTD_WRITEABLE)) - return -EROFS; - - *retlen = 0; - for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; size_t size, retsize; @@ -145,11 +138,7 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len, else size = len; - if (!(subdev->flags & MTD_WRITEABLE)) - err = -EROFS; - else - err = subdev->write(subdev, to, size, &retsize, buf); - + err = mtd_write(subdev, to, size, &retsize, buf); if (err) break; @@ -176,19 +165,10 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs, 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 device */ - if ((to + total_len) > mtd->size) - return -EINVAL; - /* Check alignment */ if (mtd->writesize > 1) { uint64_t __to = to; @@ -224,11 +204,8 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs, old_iov_len = vecs_copy[entry_high].iov_len; vecs_copy[entry_high].iov_len = size; - if (!(subdev->flags & MTD_WRITEABLE)) - err = -EROFS; - else - err = subdev->writev(subdev, &vecs_copy[entry_low], - entry_high - entry_low + 1, to, &retsize); + err = mtd_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 += size; @@ -273,16 +250,16 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) if (from + devops.len > subdev->size) devops.len = subdev->size - from; - err = subdev->read_oob(subdev, from, &devops); + err = mtd_read_oob(subdev, from, &devops); ops->retlen += devops.retlen; ops->oobretlen += devops.oobretlen; /* Save information about bitflips! */ if (unlikely(err)) { - if (err == -EBADMSG) { + if (mtd_is_eccerr(err)) { mtd->ecc_stats.failed++; ret = err; - } else if (err == -EUCLEAN) { + } else if (mtd_is_bitflip(err)) { mtd->ecc_stats.corrected++; /* Do not overwrite -EBADMSG !! */ if (!ret) @@ -319,7 +296,7 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; - ops->retlen = 0; + ops->retlen = ops->oobretlen = 0; for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; @@ -333,8 +310,8 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) if (to + devops.len > subdev->size) devops.len = subdev->size - to; - err = subdev->write_oob(subdev, to, &devops); - ops->retlen += devops.retlen; + err = mtd_write_oob(subdev, to, &devops); + ops->retlen += devops.oobretlen; if (err) return err; @@ -379,7 +356,7 @@ static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase) * FIXME: Allow INTERRUPTIBLE. Which means * not having the wait_queue head on the stack. */ - err = mtd->erase(mtd, erase); + err = mtd_erase(mtd, erase); if (!err) { set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&waitq, &wait); @@ -402,15 +379,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) uint64_t length, offset = 0; struct erase_info *erase; - if (!(mtd->flags & MTD_WRITEABLE)) - return -EROFS; - - if (instr->addr > concat->mtd.size) - return -EINVAL; - - if (instr->len + instr->addr > concat->mtd.size) - return -EINVAL; - /* * Check for proper erase block alignment of the to-be-erased area. * It is easier to do this based on the super device's erase @@ -458,8 +426,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) return -EINVAL; } - instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; - /* make a local copy of instr to avoid modifying the caller's struct */ erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL); @@ -498,10 +464,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) else erase->len = length; - if (!(subdev->flags & MTD_WRITEABLE)) { - err = -EROFS; - break; - } length -= erase->len; if ((err = concat_dev_erase(subdev, erase))) { /* sanity check: should never happen since @@ -537,9 +499,6 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) struct mtd_concat *concat = CONCAT(mtd); int i, err = -EINVAL; - if ((len + ofs) > mtd->size) - return -EINVAL; - for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; uint64_t size; @@ -554,12 +513,9 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) else size = len; - if (subdev->lock) { - err = subdev->lock(subdev, ofs, size); - if (err) - break; - } else - err = -EOPNOTSUPP; + err = mtd_lock(subdev, ofs, size); + if (err) + break; len -= size; if (len == 0) @@ -577,9 +533,6 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) struct mtd_concat *concat = CONCAT(mtd); int i, err = 0; - if ((len + ofs) > mtd->size) - return -EINVAL; - for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; uint64_t size; @@ -594,12 +547,9 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) else size = len; - if (subdev->unlock) { - err = subdev->unlock(subdev, ofs, size); - if (err) - break; - } else - err = -EOPNOTSUPP; + err = mtd_unlock(subdev, ofs, size); + if (err) + break; len -= size; if (len == 0) @@ -619,7 +569,7 @@ static void concat_sync(struct mtd_info *mtd) for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - subdev->sync(subdev); + mtd_sync(subdev); } } @@ -630,7 +580,7 @@ static int concat_suspend(struct mtd_info *mtd) for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - if ((rc = subdev->suspend(subdev)) < 0) + if ((rc = mtd_suspend(subdev)) < 0) return rc; } return rc; @@ -643,7 +593,7 @@ static void concat_resume(struct mtd_info *mtd) for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - subdev->resume(subdev); + mtd_resume(subdev); } } @@ -652,12 +602,9 @@ 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) + if (!mtd_can_have_bb(concat->subdev[0])) return res; - if (ofs > mtd->size) - return -EINVAL; - for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; @@ -666,7 +613,7 @@ static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs) continue; } - res = subdev->block_isbad(subdev, ofs); + res = mtd_block_isbad(subdev, ofs); break; } @@ -678,12 +625,6 @@ 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]; @@ -692,7 +633,7 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs) continue; } - err = subdev->block_markbad(subdev, ofs); + err = mtd_block_markbad(subdev, ofs); if (!err) mtd->ecc_stats.badblocks++; break; @@ -721,15 +662,7 @@ static unsigned long concat_get_unmapped_area(struct mtd_info *mtd, continue; } - /* we've found the subdev over which the mapping will reside */ - if (offset + len > subdev->size) - return (unsigned long) -EINVAL; - - if (subdev->get_unmapped_area) - return subdev->get_unmapped_area(subdev, len, offset, - flags); - - break; + return mtd_get_unmapped_area(subdev, len, offset, flags); } return (unsigned long) -ENOSYS; @@ -750,6 +683,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c struct mtd_concat *concat; uint32_t max_erasesize, curr_erasesize; int num_erase_region; + int max_writebufsize = 0; printk(KERN_NOTICE "Concatenating MTD devices:\n"); for (i = 0; i < num_devs; i++) @@ -769,26 +703,32 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c /* * Set up the new "super" device's MTD object structure, check for - * incompatibilites between the subdevices. + * incompatibilities between the subdevices. */ concat->mtd.type = subdev[0]->type; concat->mtd.flags = subdev[0]->flags; concat->mtd.size = subdev[0]->size; concat->mtd.erasesize = subdev[0]->erasesize; concat->mtd.writesize = subdev[0]->writesize; + + for (i = 0; i < num_devs; i++) + if (max_writebufsize < subdev[i]->writebufsize) + max_writebufsize = subdev[i]->writebufsize; + concat->mtd.writebufsize = max_writebufsize; + concat->mtd.subpage_sft = subdev[0]->subpage_sft; concat->mtd.oobsize = subdev[0]->oobsize; concat->mtd.oobavail = subdev[0]->oobavail; - if (subdev[0]->writev) - concat->mtd.writev = concat_writev; - 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; + if (subdev[0]->_writev) + concat->mtd._writev = concat_writev; + 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->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks; @@ -835,8 +775,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c if (concat->mtd.writesize != subdev[i]->writesize || concat->mtd.subpage_sft != subdev[i]->subpage_sft || concat->mtd.oobsize != subdev[i]->oobsize || - !concat->mtd.read_oob != !subdev[i]->read_oob || - !concat->mtd.write_oob != !subdev[i]->write_oob) { + !concat->mtd._read_oob != !subdev[i]->_read_oob || + !concat->mtd._write_oob != !subdev[i]->_write_oob) { kfree(concat); printk("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name); @@ -851,15 +791,15 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->num_subdev = num_devs; concat->mtd.name = name; - concat->mtd.erase = concat_erase; - concat->mtd.read = concat_read; - concat->mtd.write = concat_write; - concat->mtd.sync = concat_sync; - concat->mtd.lock = concat_lock; - concat->mtd.unlock = concat_unlock; - concat->mtd.suspend = concat_suspend; - concat->mtd.resume = concat_resume; - concat->mtd.get_unmapped_area = concat_get_unmapped_area; + concat->mtd._erase = concat_erase; + concat->mtd._read = concat_read; + concat->mtd._write = concat_write; + concat->mtd._sync = concat_sync; + concat->mtd._lock = concat_lock; + concat->mtd._unlock = concat_unlock; + concat->mtd._suspend = concat_suspend; + concat->mtd._resume = concat_resume; + concat->mtd._get_unmapped_area = concat_get_unmapped_area; /* * Combine the erase block size info of the subdevices: |
