diff options
author | Javier González <javier@cnexlabs.com> | 2016-11-28 22:39:14 +0100 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2016-11-29 12:12:51 -0700 |
commit | 333ba053d145d6f9152f6b0311a345b876f0fed1 (patch) | |
tree | 5fe4cb83b1422aaa40a7ce5ff6a824fd3d323046 /drivers/lightnvm | |
parent | da2d7cb828ce2714c603827ac5a6e1c98a02e861 (diff) | |
download | lwn-333ba053d145d6f9152f6b0311a345b876f0fed1.tar.gz lwn-333ba053d145d6f9152f6b0311a345b876f0fed1.zip |
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>
Diffstat (limited to 'drivers/lightnvm')
-rw-r--r-- | drivers/lightnvm/core.c | 58 | ||||
-rw-r--r-- | drivers/lightnvm/gennvm.c | 19 | ||||
-rw-r--r-- | drivers/lightnvm/rrpc.c | 4 |
3 files changed, 73 insertions, 8 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) return NULL; } +static void nvm_tgt_generic_to_addr_mode(struct nvm_tgt_dev *tgt_dev, + struct nvm_rq *rqd) +{ + struct nvm_dev *dev = tgt_dev->parent; + int i; + + if (rqd->nr_ppas > 1) { + for (i = 0; i < rqd->nr_ppas; i++) { + rqd->ppa_list[i] = dev->mt->trans_ppa(tgt_dev, + rqd->ppa_list[i], TRANS_TGT_TO_DEV); + rqd->ppa_list[i] = generic_to_dev_addr(dev, + rqd->ppa_list[i]); + } + } else { + rqd->ppa_addr = dev->mt->trans_ppa(tgt_dev, rqd->ppa_addr, + TRANS_TGT_TO_DEV); + rqd->ppa_addr = generic_to_dev_addr(dev, rqd->ppa_addr); + } +} + int nvm_set_bb_tbl(struct nvm_dev *dev, struct ppa_addr *ppas, int nr_ppas, int type) { @@ -202,6 +222,34 @@ int nvm_set_bb_tbl(struct nvm_dev *dev, struct ppa_addr *ppas, int nr_ppas, } EXPORT_SYMBOL(nvm_set_bb_tbl); +int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas, + int nr_ppas, int type) +{ + struct nvm_dev *dev = tgt_dev->parent; + struct nvm_rq rqd; + int ret; + + if (nr_ppas > dev->ops->max_phys_sect) { + pr_err("nvm: unable to update all blocks atomically\n"); + return -EINVAL; + } + + memset(&rqd, 0, sizeof(struct nvm_rq)); + + nvm_set_rqd_ppalist(dev, &rqd, ppas, nr_ppas, 1); + nvm_tgt_generic_to_addr_mode(tgt_dev, &rqd); + + ret = dev->ops->set_bb_tbl(dev, &rqd.ppa_addr, rqd.nr_ppas, type); + nvm_free_rqd_ppalist(dev, &rqd); + if (ret) { + pr_err("nvm: sysblk failed bb mark\n"); + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL(nvm_set_tgt_bb_tbl); + int nvm_max_phys_sects(struct nvm_tgt_dev *tgt_dev) { 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) } EXPORT_SYMBOL(nvm_get_bb_tbl); +int nvm_get_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr ppa, + u8 *blks) +{ + struct nvm_dev *dev = tgt_dev->parent; + + ppa = dev->mt->trans_ppa(tgt_dev, ppa, TRANS_TGT_TO_DEV); + return nvm_get_bb_tbl(dev, ppa, blks); +} +EXPORT_SYMBOL(nvm_get_tgt_bb_tbl); + static int nvm_init_slc_tbl(struct nvm_dev *dev, struct nvm_id_group *grp) { 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) module_put(THIS_MODULE); } -enum { - TRANS_TGT_TO_DEV = 0x0, - TRANS_DEV_TO_TGT = 0x1, -}; - - static int gen_map_to_dev(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p) { 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, return nvm_erase_ppa(tgt_dev->parent, p, 1, flags); } +static struct ppa_addr gen_trans_ppa(struct nvm_tgt_dev *tgt_dev, + struct ppa_addr p, int direction) +{ + gen_trans_fn *f; + struct ppa_addr ppa = p; + + f = (direction == TRANS_TGT_TO_DEV) ? gen_map_to_dev : gen_map_to_tgt; + f(tgt_dev, &ppa); + + return ppa; +} + static void gen_part_to_tgt(struct nvm_dev *dev, sector_t *entries, int len) { @@ -631,6 +637,7 @@ static struct nvmm_type gen = { .get_area = gen_get_area, .put_area = gen_put_area, + .trans_ppa = gen_trans_ppa, .part_to_tgt = gen_part_to_tgt, }; 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) rblk = &rlun->blocks[ppa.g.blk]; rblk->state = NVM_BLK_ST_BAD; - nvm_set_bb_tbl(dev->parent, &ppa, 1, NVM_BLK_T_GRWN_BAD); + nvm_set_tgt_bb_tbl(dev, &ppa, 1, NVM_BLK_T_GRWN_BAD); } 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) ppa.g.ch = rlun->bppa.g.ch; ppa.g.lun = rlun->bppa.g.lun; - ret = nvm_get_bb_tbl(dev->parent, ppa, blks); + ret = nvm_get_tgt_bb_tbl(dev, ppa, blks); if (ret) { pr_err("rrpc: could not get BB table\n"); goto out; |