diff options
author | Javier González <javier@cnexlabs.com> | 2016-11-28 16:39:14 -0500 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-11-29 14:12:51 -0500 |
commit | 333ba053d145d6f9152f6b0311a345b876f0fed1 (patch) | |
tree | 5fe4cb83b1422aaa40a7ce5ff6a824fd3d323046 | |
parent | da2d7cb828ce2714c603827ac5a6e1c98a02e861 (diff) |
lightnvm: transform target get/set bad block
Since targets are given a virtual target device, it is necessary to
translate all communication between targets and the backend device.
Implement the translation layer for get/set bad block table.
Signed-off-by: Javier González <javier@cnexlabs.com>
Signed-off-by: Matias Bjørling <m@bjorling.me>
Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r-- | drivers/lightnvm/core.c | 58 | ||||
-rw-r--r-- | drivers/lightnvm/gennvm.c | 19 | ||||
-rw-r--r-- | drivers/lightnvm/rrpc.c | 4 | ||||
-rw-r--r-- | include/linux/lightnvm.h | 15 |
4 files changed, 85 insertions, 11 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 07bf989d2f77..7622e3dc5d82 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c | |||
@@ -175,6 +175,26 @@ static struct nvm_dev *nvm_find_nvm_dev(const char *name) | |||
175 | return NULL; | 175 | return NULL; |
176 | } | 176 | } |
177 | 177 | ||
178 | static void nvm_tgt_generic_to_addr_mode(struct nvm_tgt_dev *tgt_dev, | ||
179 | struct nvm_rq *rqd) | ||
180 | { | ||
181 | struct nvm_dev *dev = tgt_dev->parent; | ||
182 | int i; | ||
183 | |||
184 | if (rqd->nr_ppas > 1) { | ||
185 | for (i = 0; i < rqd->nr_ppas; i++) { | ||
186 | rqd->ppa_list[i] = dev->mt->trans_ppa(tgt_dev, | ||
187 | rqd->ppa_list[i], TRANS_TGT_TO_DEV); | ||
188 | rqd->ppa_list[i] = generic_to_dev_addr(dev, | ||
189 | rqd->ppa_list[i]); | ||
190 | } | ||
191 | } else { | ||
192 | rqd->ppa_addr = dev->mt->trans_ppa(tgt_dev, rqd->ppa_addr, | ||
193 | TRANS_TGT_TO_DEV); | ||
194 | rqd->ppa_addr = generic_to_dev_addr(dev, rqd->ppa_addr); | ||
195 | } | ||
196 | } | ||
197 | |||
178 | int nvm_set_bb_tbl(struct nvm_dev *dev, struct ppa_addr *ppas, int nr_ppas, | 198 | int nvm_set_bb_tbl(struct nvm_dev *dev, struct ppa_addr *ppas, int nr_ppas, |
179 | int type) | 199 | int type) |
180 | { | 200 | { |
@@ -202,6 +222,34 @@ int nvm_set_bb_tbl(struct nvm_dev *dev, struct ppa_addr *ppas, int nr_ppas, | |||
202 | } | 222 | } |
203 | EXPORT_SYMBOL(nvm_set_bb_tbl); | 223 | EXPORT_SYMBOL(nvm_set_bb_tbl); |
204 | 224 | ||
225 | int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas, | ||
226 | int nr_ppas, int type) | ||
227 | { | ||
228 | struct nvm_dev *dev = tgt_dev->parent; | ||
229 | struct nvm_rq rqd; | ||
230 | int ret; | ||
231 | |||
232 | if (nr_ppas > dev->ops->max_phys_sect) { | ||
233 | pr_err("nvm: unable to update all blocks atomically\n"); | ||
234 | return -EINVAL; | ||
235 | } | ||
236 | |||
237 | memset(&rqd, 0, sizeof(struct nvm_rq)); | ||
238 | |||
239 | nvm_set_rqd_ppalist(dev, &rqd, ppas, nr_ppas, 1); | ||
240 | nvm_tgt_generic_to_addr_mode(tgt_dev, &rqd); | ||
241 | |||
242 | ret = dev->ops->set_bb_tbl(dev, &rqd.ppa_addr, rqd.nr_ppas, type); | ||
243 | nvm_free_rqd_ppalist(dev, &rqd); | ||
244 | if (ret) { | ||
245 | pr_err("nvm: sysblk failed bb mark\n"); | ||
246 | return -EINVAL; | ||
247 | } | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | EXPORT_SYMBOL(nvm_set_tgt_bb_tbl); | ||
252 | |||
205 | int nvm_max_phys_sects(struct nvm_tgt_dev *tgt_dev) | 253 | int nvm_max_phys_sects(struct nvm_tgt_dev *tgt_dev) |
206 | { | 254 | { |
207 | struct nvm_dev *dev = tgt_dev->parent; | 255 | struct nvm_dev *dev = tgt_dev->parent; |
@@ -519,6 +567,16 @@ int nvm_get_bb_tbl(struct nvm_dev *dev, struct ppa_addr ppa, u8 *blks) | |||
519 | } | 567 | } |
520 | EXPORT_SYMBOL(nvm_get_bb_tbl); | 568 | EXPORT_SYMBOL(nvm_get_bb_tbl); |
521 | 569 | ||
570 | int nvm_get_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr ppa, | ||
571 | u8 *blks) | ||
572 | { | ||
573 | struct nvm_dev *dev = tgt_dev->parent; | ||
574 | |||
575 | ppa = dev->mt->trans_ppa(tgt_dev, ppa, TRANS_TGT_TO_DEV); | ||
576 | return nvm_get_bb_tbl(dev, ppa, blks); | ||
577 | } | ||
578 | EXPORT_SYMBOL(nvm_get_tgt_bb_tbl); | ||
579 | |||
522 | static int nvm_init_slc_tbl(struct nvm_dev *dev, struct nvm_id_group *grp) | 580 | static int nvm_init_slc_tbl(struct nvm_dev *dev, struct nvm_id_group *grp) |
523 | { | 581 | { |
524 | struct nvm_geo *geo = &dev->geo; | 582 | struct nvm_geo *geo = &dev->geo; |
diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c index befa8281ab3f..ca7880082d80 100644 --- a/drivers/lightnvm/gennvm.c +++ b/drivers/lightnvm/gennvm.c | |||
@@ -482,12 +482,6 @@ static void gen_unregister(struct nvm_dev *dev) | |||
482 | module_put(THIS_MODULE); | 482 | module_put(THIS_MODULE); |
483 | } | 483 | } |
484 | 484 | ||
485 | enum { | ||
486 | TRANS_TGT_TO_DEV = 0x0, | ||
487 | TRANS_DEV_TO_TGT = 0x1, | ||
488 | }; | ||
489 | |||
490 | |||
491 | static int gen_map_to_dev(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p) | 485 | static int gen_map_to_dev(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p) |
492 | { | 486 | { |
493 | struct gen_dev_map *dev_map = tgt_dev->map; | 487 | struct gen_dev_map *dev_map = tgt_dev->map; |
@@ -584,6 +578,18 @@ static int gen_erase_blk(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p, | |||
584 | return nvm_erase_ppa(tgt_dev->parent, p, 1, flags); | 578 | return nvm_erase_ppa(tgt_dev->parent, p, 1, flags); |
585 | } | 579 | } |
586 | 580 | ||
581 | static struct ppa_addr gen_trans_ppa(struct nvm_tgt_dev *tgt_dev, | ||
582 | struct ppa_addr p, int direction) | ||
583 | { | ||
584 | gen_trans_fn *f; | ||
585 | struct ppa_addr ppa = p; | ||
586 | |||
587 | f = (direction == TRANS_TGT_TO_DEV) ? gen_map_to_dev : gen_map_to_tgt; | ||
588 | f(tgt_dev, &ppa); | ||
589 | |||
590 | return ppa; | ||
591 | } | ||
592 | |||
587 | static void gen_part_to_tgt(struct nvm_dev *dev, sector_t *entries, | 593 | static void gen_part_to_tgt(struct nvm_dev *dev, sector_t *entries, |
588 | int len) | 594 | int len) |
589 | { | 595 | { |
@@ -631,6 +637,7 @@ static struct nvmm_type gen = { | |||
631 | .get_area = gen_get_area, | 637 | .get_area = gen_get_area, |
632 | .put_area = gen_put_area, | 638 | .put_area = gen_put_area, |
633 | 639 | ||
640 | .trans_ppa = gen_trans_ppa, | ||
634 | .part_to_tgt = gen_part_to_tgt, | 641 | .part_to_tgt = gen_part_to_tgt, |
635 | }; | 642 | }; |
636 | 643 | ||
diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index 8a27bcc62f23..9fb7de395915 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c | |||
@@ -735,7 +735,7 @@ static void __rrpc_mark_bad_block(struct rrpc *rrpc, struct ppa_addr ppa) | |||
735 | rblk = &rlun->blocks[ppa.g.blk]; | 735 | rblk = &rlun->blocks[ppa.g.blk]; |
736 | rblk->state = NVM_BLK_ST_BAD; | 736 | rblk->state = NVM_BLK_ST_BAD; |
737 | 737 | ||
738 | nvm_set_bb_tbl(dev->parent, &ppa, 1, NVM_BLK_T_GRWN_BAD); | 738 | nvm_set_tgt_bb_tbl(dev, &ppa, 1, NVM_BLK_T_GRWN_BAD); |
739 | } | 739 | } |
740 | 740 | ||
741 | static void rrpc_mark_bad_block(struct rrpc *rrpc, struct nvm_rq *rqd) | 741 | static void rrpc_mark_bad_block(struct rrpc *rrpc, struct nvm_rq *rqd) |
@@ -1267,7 +1267,7 @@ static int rrpc_bb_discovery(struct nvm_tgt_dev *dev, struct rrpc_lun *rlun) | |||
1267 | ppa.g.ch = rlun->bppa.g.ch; | 1267 | ppa.g.ch = rlun->bppa.g.ch; |
1268 | ppa.g.lun = rlun->bppa.g.lun; | 1268 | ppa.g.lun = rlun->bppa.g.lun; |
1269 | 1269 | ||
1270 | ret = nvm_get_bb_tbl(dev->parent, ppa, blks); | 1270 | ret = nvm_get_tgt_bb_tbl(dev, ppa, blks); |
1271 | if (ret) { | 1271 | if (ret) { |
1272 | pr_err("rrpc: could not get BB table\n"); | 1272 | pr_err("rrpc: could not get BB table\n"); |
1273 | goto out; | 1273 | goto out; |
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h index e76f9c4aa49b..7c273bbc5351 100644 --- a/include/linux/lightnvm.h +++ b/include/linux/lightnvm.h | |||
@@ -496,8 +496,15 @@ typedef int (nvmm_submit_io_fn)(struct nvm_tgt_dev *, struct nvm_rq *); | |||
496 | typedef int (nvmm_erase_blk_fn)(struct nvm_tgt_dev *, struct ppa_addr *, int); | 496 | typedef int (nvmm_erase_blk_fn)(struct nvm_tgt_dev *, struct ppa_addr *, int); |
497 | typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t); | 497 | typedef int (nvmm_get_area_fn)(struct nvm_dev *, sector_t *, sector_t); |
498 | typedef void (nvmm_put_area_fn)(struct nvm_dev *, sector_t); | 498 | typedef void (nvmm_put_area_fn)(struct nvm_dev *, sector_t); |
499 | typedef struct ppa_addr (nvmm_trans_ppa_fn)(struct nvm_tgt_dev *, | ||
500 | struct ppa_addr, int); | ||
499 | typedef void (nvmm_part_to_tgt_fn)(struct nvm_dev *, sector_t*, int); | 501 | typedef void (nvmm_part_to_tgt_fn)(struct nvm_dev *, sector_t*, int); |
500 | 502 | ||
503 | enum { | ||
504 | TRANS_TGT_TO_DEV = 0x0, | ||
505 | TRANS_DEV_TO_TGT = 0x1, | ||
506 | }; | ||
507 | |||
501 | struct nvmm_type { | 508 | struct nvmm_type { |
502 | const char *name; | 509 | const char *name; |
503 | unsigned int version[3]; | 510 | unsigned int version[3]; |
@@ -514,6 +521,7 @@ struct nvmm_type { | |||
514 | nvmm_get_area_fn *get_area; | 521 | nvmm_get_area_fn *get_area; |
515 | nvmm_put_area_fn *put_area; | 522 | nvmm_put_area_fn *put_area; |
516 | 523 | ||
524 | nvmm_trans_ppa_fn *trans_ppa; | ||
517 | nvmm_part_to_tgt_fn *part_to_tgt; | 525 | nvmm_part_to_tgt_fn *part_to_tgt; |
518 | 526 | ||
519 | struct list_head list; | 527 | struct list_head list; |
@@ -526,9 +534,9 @@ extern struct nvm_dev *nvm_alloc_dev(int); | |||
526 | extern int nvm_register(struct nvm_dev *); | 534 | extern int nvm_register(struct nvm_dev *); |
527 | extern void nvm_unregister(struct nvm_dev *); | 535 | extern void nvm_unregister(struct nvm_dev *); |
528 | 536 | ||
529 | extern int nvm_set_bb_tbl(struct nvm_dev *dev, struct ppa_addr *ppas, | 537 | extern int nvm_set_bb_tbl(struct nvm_dev *, struct ppa_addr *, int, int); |
530 | int nr_ppas, int type); | 538 | extern int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *, struct ppa_addr *, |
531 | 539 | int, int); | |
532 | extern int nvm_max_phys_sects(struct nvm_tgt_dev *); | 540 | extern int nvm_max_phys_sects(struct nvm_tgt_dev *); |
533 | extern int nvm_submit_io(struct nvm_tgt_dev *, struct nvm_rq *); | 541 | extern int nvm_submit_io(struct nvm_tgt_dev *, struct nvm_rq *); |
534 | extern void nvm_generic_to_addr_mode(struct nvm_dev *, struct nvm_rq *); | 542 | extern void nvm_generic_to_addr_mode(struct nvm_dev *, struct nvm_rq *); |
@@ -549,6 +557,7 @@ extern int nvm_submit_ppa_list(struct nvm_dev *, struct ppa_addr *, int, int, | |||
549 | int, void *, int); | 557 | int, void *, int); |
550 | extern int nvm_bb_tbl_fold(struct nvm_dev *, u8 *, int); | 558 | extern int nvm_bb_tbl_fold(struct nvm_dev *, u8 *, int); |
551 | extern int nvm_get_bb_tbl(struct nvm_dev *, struct ppa_addr, u8 *); | 559 | extern int nvm_get_bb_tbl(struct nvm_dev *, struct ppa_addr, u8 *); |
560 | extern int nvm_get_tgt_bb_tbl(struct nvm_tgt_dev *, struct ppa_addr, u8 *); | ||
552 | 561 | ||
553 | /* sysblk.c */ | 562 | /* sysblk.c */ |
554 | #define NVM_SYSBLK_MAGIC 0x4E564D53 /* "NVMS" */ | 563 | #define NVM_SYSBLK_MAGIC 0x4E564D53 /* "NVMS" */ |