diff options
author | Matias Bjørling <m@bjorling.me> | 2016-05-06 20:02:56 +0200 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-05-06 20:51:10 +0200 |
commit | 1145e6351a9fefe0965df4c6dba2a04156dc47d2 (patch) | |
tree | 4c92d803aea93a7f85de048de36e1981550add98 | |
parent | lightnvm: handle submit_io failure (diff) | |
download | linux-1145e6351a9fefe0965df4c6dba2a04156dc47d2.tar.xz linux-1145e6351a9fefe0965df4c6dba2a04156dc47d2.zip |
lightnvm: implement nvm_submit_ppa_list
The nvm_submit_ppa function assumes that users manage all plane
blocks as a single block. Extend the API with nvm_submit_ppa_list
to allow the user to send its own ppa list. If the user submits more
than a single PPA, the user must take care to allocate and free
the corresponding ppa list.
Reviewed by: Johannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: Matias Bjørling <m@bjorling.me>
Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r-- | drivers/lightnvm/core.c | 88 | ||||
-rw-r--r-- | include/linux/lightnvm.h | 2 |
2 files changed, 71 insertions, 19 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index c2ef53a0d7f8..f4e04a505859 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -322,11 +322,10 @@ static void nvm_end_io_sync(struct nvm_rq *rqd) complete(waiting); } -int nvm_submit_ppa(struct nvm_dev *dev, struct ppa_addr *ppa, int nr_ppas, - int opcode, int flags, void *buf, int len) +int __nvm_submit_ppa(struct nvm_dev *dev, struct nvm_rq *rqd, int opcode, + int flags, void *buf, int len) { DECLARE_COMPLETION_ONSTACK(wait); - struct nvm_rq rqd; struct bio *bio; int ret; unsigned long hang_check; @@ -335,24 +334,17 @@ int nvm_submit_ppa(struct nvm_dev *dev, struct ppa_addr *ppa, int nr_ppas, if (IS_ERR_OR_NULL(bio)) return -ENOMEM; - memset(&rqd, 0, sizeof(struct nvm_rq)); - ret = nvm_set_rqd_ppalist(dev, &rqd, ppa, nr_ppas); - if (ret) { - bio_put(bio); - return ret; - } + nvm_generic_to_addr_mode(dev, rqd); - rqd.opcode = opcode; - rqd.bio = bio; - rqd.wait = &wait; - rqd.dev = dev; - rqd.end_io = nvm_end_io_sync; - rqd.flags = flags; - nvm_generic_to_addr_mode(dev, &rqd); + rqd->dev = dev; + rqd->opcode = opcode; + rqd->flags = flags; + rqd->bio = bio; + rqd->wait = &wait; + rqd->end_io = nvm_end_io_sync; - ret = dev->ops->submit_io(dev, &rqd); + ret = dev->ops->submit_io(dev, rqd); if (ret) { - nvm_free_rqd_ppalist(dev, &rqd); bio_put(bio); return ret; } @@ -364,9 +356,67 @@ int nvm_submit_ppa(struct nvm_dev *dev, struct ppa_addr *ppa, int nr_ppas, else wait_for_completion_io(&wait); + return rqd->error; +} + +/** + * nvm_submit_ppa_list - submit user-defined ppa list to device. The user must + * take to free ppa list if necessary. + * @dev: device + * @ppa_list: user created ppa_list + * @nr_ppas: length of ppa_list + * @opcode: device opcode + * @flags: device flags + * @buf: data buffer + * @len: data buffer length + */ +int nvm_submit_ppa_list(struct nvm_dev *dev, struct ppa_addr *ppa_list, + int nr_ppas, int opcode, int flags, void *buf, int len) +{ + struct nvm_rq rqd; + + if (dev->ops->max_phys_sect < nr_ppas) + return -EINVAL; + + memset(&rqd, 0, sizeof(struct nvm_rq)); + + rqd.nr_pages = nr_ppas; + if (nr_ppas > 1) + rqd.ppa_list = ppa_list; + else + rqd.ppa_addr = ppa_list[0]; + + return __nvm_submit_ppa(dev, &rqd, opcode, flags, buf, len); +} +EXPORT_SYMBOL(nvm_submit_ppa_list); + +/** + * nvm_submit_ppa - submit PPAs to device. PPAs will automatically be unfolded + * as single, dual, quad plane PPAs depending on device type. + * @dev: device + * @ppa: user created ppa_list + * @nr_ppas: length of ppa_list + * @opcode: device opcode + * @flags: device flags + * @buf: data buffer + * @len: data buffer length + */ +int nvm_submit_ppa(struct nvm_dev *dev, struct ppa_addr *ppa, int nr_ppas, + int opcode, int flags, void *buf, int len) +{ + struct nvm_rq rqd; + int ret; + + memset(&rqd, 0, sizeof(struct nvm_rq)); + ret = nvm_set_rqd_ppalist(dev, &rqd, ppa, nr_ppas); + if (ret) + return ret; + + ret = __nvm_submit_ppa(dev, &rqd, opcode, flags, buf, len); + nvm_free_rqd_ppalist(dev, &rqd); - return rqd.error; + return ret; } EXPORT_SYMBOL(nvm_submit_ppa); diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index cdcb2ccbefa8..38814e262872 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h @@ -534,6 +534,8 @@ extern int nvm_erase_blk(struct nvm_dev *, struct nvm_block *); extern void nvm_end_io(struct nvm_rq *, int); extern int nvm_submit_ppa(struct nvm_dev *, struct ppa_addr *, int, int, int, void *, int); +extern int nvm_submit_ppa_list(struct nvm_dev *, struct ppa_addr *, int, int, + int, void *, int); /* sysblk.c */ #define NVM_SYSBLK_MAGIC 0x4E564D53 /* "NVMS" */ |