lightnvm: implement nvm_submit_ppa_list
authorMatias Bjørling <m@bjorling.me>
Fri, 6 May 2016 18:02:56 +0000 (20:02 +0200)
committerJens Axboe <axboe@fb.com>
Fri, 6 May 2016 18:51:10 +0000 (12:51 -0600)
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>
drivers/lightnvm/core.c
include/linux/lightnvm.h

index c2ef53a0d7f8bca461a73c13356c8a288ddaf727..f4e04a5058598a4de31c415db7edd8b56482a9cc 100644 (file)
@@ -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);
 
index cdcb2ccbefa8337f728c19dc0846ac2821b11ae7..38814e262872308d3fbe93b09448962e88d81500 100644 (file)
@@ -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" */