summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier González <javier@cnexlabs.com>2018-03-29 18:05:17 -0400
committerJens Axboe <axboe@kernel.dk>2018-03-29 19:29:09 -0400
commita294c199455187d124b0760fa8f86c13cdaa4b25 (patch)
tree15df9cbb23f8fd0286db1f2671498f73914233ab
parent7100d50a7e58a6884368001e2b1a32b7169c072c (diff)
lightnvm: implement get log report chunk helpers
The 2.0 spec provides a report chunk log page that can be retrieved using the stangard nvme get log page. This replaces the dedicated get/put bad block table in 1.2. This patch implements the helper functions to allow targets retrieve the chunk metadata using get log page. It makes nvme_get_log_ext available outside of nvme core so that we can use it form lightnvm. Signed-off-by: Javier González <javier@cnexlabs.com> Signed-off-by: Matias Bjørling <mb@lightnvm.io> Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--drivers/lightnvm/core.c11
-rw-r--r--drivers/nvme/host/core.c4
-rw-r--r--drivers/nvme/host/lightnvm.c74
-rw-r--r--include/linux/lightnvm.h24
4 files changed, 111 insertions, 2 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 77901bf17416..63171cdce270 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -712,6 +712,17 @@ static void nvm_free_rqd_ppalist(struct nvm_tgt_dev *tgt_dev,
712 nvm_dev_dma_free(tgt_dev->parent, rqd->ppa_list, rqd->dma_ppa_list); 712 nvm_dev_dma_free(tgt_dev->parent, rqd->ppa_list, rqd->dma_ppa_list);
713} 713}
714 714
715int nvm_get_chunk_meta(struct nvm_tgt_dev *tgt_dev, struct nvm_chk_meta *meta,
716 struct ppa_addr ppa, int nchks)
717{
718 struct nvm_dev *dev = tgt_dev->parent;
719
720 nvm_ppa_tgt_to_dev(tgt_dev, &ppa, 1);
721
722 return dev->ops->get_chk_meta(tgt_dev->parent, meta,
723 (sector_t)ppa.ppa, nchks);
724}
725EXPORT_SYMBOL(nvm_get_chunk_meta);
715 726
716int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas, 727int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas,
717 int nr_ppas, int type) 728 int nr_ppas, int type)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index e7ec2fb5c59a..f81e3b323366 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2219,8 +2219,8 @@ out_unlock:
2219} 2219}
2220 2220
2221int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns, 2221int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
2222 u8 log_page, void *log, 2222 u8 log_page, void *log,
2223 size_t size, size_t offset) 2223 size_t size, size_t offset)
2224{ 2224{
2225 struct nvme_command c = { }; 2225 struct nvme_command c = { };
2226 unsigned long dwlen = size / 4 - 1; 2226 unsigned long dwlen = size / 4 - 1;
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index 08f0f6b5bc06..ffd64a83c8c3 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -35,6 +35,10 @@ enum nvme_nvm_admin_opcode {
35 nvme_nvm_admin_set_bb_tbl = 0xf1, 35 nvme_nvm_admin_set_bb_tbl = 0xf1,
36}; 36};
37 37
38enum nvme_nvm_log_page {
39 NVME_NVM_LOG_REPORT_CHUNK = 0xca,
40};
41
38struct nvme_nvm_ph_rw { 42struct nvme_nvm_ph_rw {
39 __u8 opcode; 43 __u8 opcode;
40 __u8 flags; 44 __u8 flags;
@@ -236,6 +240,16 @@ struct nvme_nvm_id20 {
236 __u8 vs[1024]; 240 __u8 vs[1024];
237}; 241};
238 242
243struct nvme_nvm_chk_meta {
244 __u8 state;
245 __u8 type;
246 __u8 wi;
247 __u8 rsvd[5];
248 __le64 slba;
249 __le64 cnlb;
250 __le64 wp;
251};
252
239/* 253/*
240 * Check we didn't inadvertently grow the command struct 254 * Check we didn't inadvertently grow the command struct
241 */ 255 */
@@ -252,6 +266,9 @@ static inline void _nvme_nvm_check_size(void)
252 BUILD_BUG_ON(sizeof(struct nvme_nvm_bb_tbl) != 64); 266 BUILD_BUG_ON(sizeof(struct nvme_nvm_bb_tbl) != 64);
253 BUILD_BUG_ON(sizeof(struct nvme_nvm_id20_addrf) != 8); 267 BUILD_BUG_ON(sizeof(struct nvme_nvm_id20_addrf) != 8);
254 BUILD_BUG_ON(sizeof(struct nvme_nvm_id20) != NVME_IDENTIFY_DATA_SIZE); 268 BUILD_BUG_ON(sizeof(struct nvme_nvm_id20) != NVME_IDENTIFY_DATA_SIZE);
269 BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) != 32);
270 BUILD_BUG_ON(sizeof(struct nvme_nvm_chk_meta) !=
271 sizeof(struct nvm_chk_meta));
255} 272}
256 273
257static void nvme_nvm_set_addr_12(struct nvm_addrf_12 *dst, 274static void nvme_nvm_set_addr_12(struct nvm_addrf_12 *dst,
@@ -552,6 +569,61 @@ static int nvme_nvm_set_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr *ppas,
552 return ret; 569 return ret;
553} 570}
554 571
572/*
573 * Expect the lba in device format
574 */
575static int nvme_nvm_get_chk_meta(struct nvm_dev *ndev,
576 struct nvm_chk_meta *meta,
577 sector_t slba, int nchks)
578{
579 struct nvm_geo *geo = &ndev->geo;
580 struct nvme_ns *ns = ndev->q->queuedata;
581 struct nvme_ctrl *ctrl = ns->ctrl;
582 struct nvme_nvm_chk_meta *dev_meta = (struct nvme_nvm_chk_meta *)meta;
583 struct ppa_addr ppa;
584 size_t left = nchks * sizeof(struct nvme_nvm_chk_meta);
585 size_t log_pos, offset, len;
586 int ret, i;
587
588 /* Normalize lba address space to obtain log offset */
589 ppa.ppa = slba;
590 ppa = dev_to_generic_addr(ndev, ppa);
591
592 log_pos = ppa.m.chk;
593 log_pos += ppa.m.pu * geo->num_chk;
594 log_pos += ppa.m.grp * geo->num_lun * geo->num_chk;
595
596 offset = log_pos * sizeof(struct nvme_nvm_chk_meta);
597
598 while (left) {
599 len = min_t(unsigned int, left, ctrl->max_hw_sectors << 9);
600
601 ret = nvme_get_log_ext(ctrl, ns, NVME_NVM_LOG_REPORT_CHUNK,
602 dev_meta, len, offset);
603 if (ret) {
604 dev_err(ctrl->device, "Get REPORT CHUNK log error\n");
605 break;
606 }
607
608 for (i = 0; i < len; i += sizeof(struct nvme_nvm_chk_meta)) {
609 meta->state = dev_meta->state;
610 meta->type = dev_meta->type;
611 meta->wi = dev_meta->wi;
612 meta->slba = le64_to_cpu(dev_meta->slba);
613 meta->cnlb = le64_to_cpu(dev_meta->cnlb);
614 meta->wp = le64_to_cpu(dev_meta->wp);
615
616 meta++;
617 dev_meta++;
618 }
619
620 offset += len;
621 left -= len;
622 }
623
624 return ret;
625}
626
555static inline void nvme_nvm_rqtocmd(struct nvm_rq *rqd, struct nvme_ns *ns, 627static inline void nvme_nvm_rqtocmd(struct nvm_rq *rqd, struct nvme_ns *ns,
556 struct nvme_nvm_command *c) 628 struct nvme_nvm_command *c)
557{ 629{
@@ -683,6 +755,8 @@ static struct nvm_dev_ops nvme_nvm_dev_ops = {
683 .get_bb_tbl = nvme_nvm_get_bb_tbl, 755 .get_bb_tbl = nvme_nvm_get_bb_tbl,
684 .set_bb_tbl = nvme_nvm_set_bb_tbl, 756 .set_bb_tbl = nvme_nvm_set_bb_tbl,
685 757
758 .get_chk_meta = nvme_nvm_get_chk_meta,
759
686 .submit_io = nvme_nvm_submit_io, 760 .submit_io = nvme_nvm_submit_io,
687 .submit_io_sync = nvme_nvm_submit_io_sync, 761 .submit_io_sync = nvme_nvm_submit_io_sync,
688 762
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index f3b273e543c3..da45efa09bb2 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -81,10 +81,13 @@ struct nvm_rq;
81struct nvm_id; 81struct nvm_id;
82struct nvm_dev; 82struct nvm_dev;
83struct nvm_tgt_dev; 83struct nvm_tgt_dev;
84struct nvm_chk_meta;
84 85
85typedef int (nvm_id_fn)(struct nvm_dev *); 86typedef int (nvm_id_fn)(struct nvm_dev *);
86typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, u8 *); 87typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, u8 *);
87typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct ppa_addr *, int, int); 88typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct ppa_addr *, int, int);
89typedef int (nvm_get_chk_meta_fn)(struct nvm_dev *, struct nvm_chk_meta *,
90 sector_t, int);
88typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *); 91typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
89typedef int (nvm_submit_io_sync_fn)(struct nvm_dev *, struct nvm_rq *); 92typedef int (nvm_submit_io_sync_fn)(struct nvm_dev *, struct nvm_rq *);
90typedef void *(nvm_create_dma_pool_fn)(struct nvm_dev *, char *); 93typedef void *(nvm_create_dma_pool_fn)(struct nvm_dev *, char *);
@@ -98,6 +101,8 @@ struct nvm_dev_ops {
98 nvm_op_bb_tbl_fn *get_bb_tbl; 101 nvm_op_bb_tbl_fn *get_bb_tbl;
99 nvm_op_set_bb_fn *set_bb_tbl; 102 nvm_op_set_bb_fn *set_bb_tbl;
100 103
104 nvm_get_chk_meta_fn *get_chk_meta;
105
101 nvm_submit_io_fn *submit_io; 106 nvm_submit_io_fn *submit_io;
102 nvm_submit_io_sync_fn *submit_io_sync; 107 nvm_submit_io_sync_fn *submit_io_sync;
103 108
@@ -227,6 +232,20 @@ struct nvm_addrf {
227 u64 rsv_mask[2]; 232 u64 rsv_mask[2];
228}; 233};
229 234
235/*
236 * Note: The structure size is linked to nvme_nvm_chk_meta such that the same
237 * buffer can be used when converting from little endian to cpu addressing.
238 */
239struct nvm_chk_meta {
240 u8 state;
241 u8 type;
242 u8 wi;
243 u8 rsvd[5];
244 u64 slba;
245 u64 cnlb;
246 u64 wp;
247};
248
230struct nvm_target { 249struct nvm_target {
231 struct list_head list; 250 struct list_head list;
232 struct nvm_tgt_dev *dev; 251 struct nvm_tgt_dev *dev;
@@ -492,6 +511,11 @@ extern struct nvm_dev *nvm_alloc_dev(int);
492extern int nvm_register(struct nvm_dev *); 511extern int nvm_register(struct nvm_dev *);
493extern void nvm_unregister(struct nvm_dev *); 512extern void nvm_unregister(struct nvm_dev *);
494 513
514
515extern int nvm_get_chunk_meta(struct nvm_tgt_dev *tgt_dev,
516 struct nvm_chk_meta *meta, struct ppa_addr ppa,
517 int nchks);
518
495extern int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *, struct ppa_addr *, 519extern int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *, struct ppa_addr *,
496 int, int); 520 int, int);
497extern int nvm_submit_io(struct nvm_tgt_dev *, struct nvm_rq *); 521extern int nvm_submit_io(struct nvm_tgt_dev *, struct nvm_rq *);