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 /drivers | |
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>
Diffstat (limited to 'drivers')
-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 |
3 files changed, 87 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 | ||