diff options
author | Javier González <javier@cnexlabs.com> | 2018-03-29 18:05:17 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2018-03-29 19:29:09 -0400 |
commit | a294c199455187d124b0760fa8f86c13cdaa4b25 (patch) | |
tree | 15df9cbb23f8fd0286db1f2671498f73914233ab | |
parent | 7100d50a7e58a6884368001e2b1a32b7169c072c (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.c | 11 | ||||
-rw-r--r-- | drivers/nvme/host/core.c | 4 | ||||
-rw-r--r-- | drivers/nvme/host/lightnvm.c | 74 | ||||
-rw-r--r-- | include/linux/lightnvm.h | 24 |
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 | ||
715 | int 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 | } | ||
725 | EXPORT_SYMBOL(nvm_get_chunk_meta); | ||
715 | 726 | ||
716 | int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas, | 727 | int 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 | ||
2221 | int nvme_get_log_ext(struct nvme_ctrl *ctrl, struct nvme_ns *ns, | 2221 | int 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 | ||
38 | enum nvme_nvm_log_page { | ||
39 | NVME_NVM_LOG_REPORT_CHUNK = 0xca, | ||
40 | }; | ||
41 | |||
38 | struct nvme_nvm_ph_rw { | 42 | struct 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 | ||
243 | struct 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 | ||
257 | static void nvme_nvm_set_addr_12(struct nvm_addrf_12 *dst, | 274 | static 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 | */ | ||
575 | static 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 | |||
555 | static inline void nvme_nvm_rqtocmd(struct nvm_rq *rqd, struct nvme_ns *ns, | 627 | static 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; | |||
81 | struct nvm_id; | 81 | struct nvm_id; |
82 | struct nvm_dev; | 82 | struct nvm_dev; |
83 | struct nvm_tgt_dev; | 83 | struct nvm_tgt_dev; |
84 | struct nvm_chk_meta; | ||
84 | 85 | ||
85 | typedef int (nvm_id_fn)(struct nvm_dev *); | 86 | typedef int (nvm_id_fn)(struct nvm_dev *); |
86 | typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, u8 *); | 87 | typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, u8 *); |
87 | typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct ppa_addr *, int, int); | 88 | typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct ppa_addr *, int, int); |
89 | typedef int (nvm_get_chk_meta_fn)(struct nvm_dev *, struct nvm_chk_meta *, | ||
90 | sector_t, int); | ||
88 | typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *); | 91 | typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *); |
89 | typedef int (nvm_submit_io_sync_fn)(struct nvm_dev *, struct nvm_rq *); | 92 | typedef int (nvm_submit_io_sync_fn)(struct nvm_dev *, struct nvm_rq *); |
90 | typedef void *(nvm_create_dma_pool_fn)(struct nvm_dev *, char *); | 93 | typedef 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 | */ | ||
239 | struct 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 | |||
230 | struct nvm_target { | 249 | struct 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); | |||
492 | extern int nvm_register(struct nvm_dev *); | 511 | extern int nvm_register(struct nvm_dev *); |
493 | extern void nvm_unregister(struct nvm_dev *); | 512 | extern void nvm_unregister(struct nvm_dev *); |
494 | 513 | ||
514 | |||
515 | extern 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 | |||
495 | extern int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *, struct ppa_addr *, | 519 | extern int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *, struct ppa_addr *, |
496 | int, int); | 520 | int, int); |
497 | extern int nvm_submit_io(struct nvm_tgt_dev *, struct nvm_rq *); | 521 | extern int nvm_submit_io(struct nvm_tgt_dev *, struct nvm_rq *); |