aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatias Bjørling <m@bjorling.me>2016-05-06 14:03:05 -0400
committerJens Axboe <axboe@fb.com>2016-05-06 14:51:10 -0400
commite11903f5dfeb4f59fe93316d47f2ee5982e91e60 (patch)
treecff5ac80004af7b45bf3785889bb4ea04780943a
parent5136061ce705210b501ed9ecd673a67b74ebe017 (diff)
lightnvm: refactor device ops->get_bb_tbl()
The device ops->get_bb_tbl() takes a callback, that allows the caller to use its own callback function to update its data structures in the returning function. This makes it difficult to send parameters to the callback, and usually is circumvented by small private structures, that both carry the callers state and any flags needed to fulfill the update. Refactor ops->get_bb_tbl() to fill a data buffer with the status of the blocks returned, and let the user call the callback function manually. That will provide the necessary flags and data structures and simplify the logic around ops->get_bb_tbl(). Signed-off-by: Matias Bjørling <m@bjorling.me> Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r--drivers/lightnvm/core.c8
-rw-r--r--drivers/lightnvm/gennvm.c29
-rw-r--r--drivers/lightnvm/sysblk.c146
-rw-r--r--drivers/nvme/host/lightnvm.c6
-rw-r--r--include/linux/lightnvm.h6
5 files changed, 111 insertions, 84 deletions
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index 0296223392f7..e6d7a98baeb2 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -467,6 +467,14 @@ int nvm_bb_tbl_fold(struct nvm_dev *dev, u8 *blks, int nr_blks)
467} 467}
468EXPORT_SYMBOL(nvm_bb_tbl_fold); 468EXPORT_SYMBOL(nvm_bb_tbl_fold);
469 469
470int nvm_get_bb_tbl(struct nvm_dev *dev, struct ppa_addr ppa, u8 *blks)
471{
472 ppa = generic_to_dev_addr(dev, ppa);
473
474 return dev->ops->get_bb_tbl(dev, ppa, blks);
475}
476EXPORT_SYMBOL(nvm_get_bb_tbl);
477
470static int nvm_init_slc_tbl(struct nvm_dev *dev, struct nvm_id_group *grp) 478static int nvm_init_slc_tbl(struct nvm_dev *dev, struct nvm_id_group *grp)
471{ 479{
472 int i; 480 int i;
diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c
index 6096077c5dde..9c6b141606e9 100644
--- a/drivers/lightnvm/gennvm.c
+++ b/drivers/lightnvm/gennvm.c
@@ -129,10 +129,10 @@ static int gennvm_luns_init(struct nvm_dev *dev, struct gen_nvm *gn)
129 return 0; 129 return 0;
130} 130}
131 131
132static int gennvm_block_bb(struct nvm_dev *dev, struct ppa_addr ppa, 132static int gennvm_block_bb(struct gen_nvm *gn, struct ppa_addr ppa,
133 u8 *blks, int nr_blks, void *private) 133 u8 *blks, int nr_blks)
134{ 134{
135 struct gen_nvm *gn = private; 135 struct nvm_dev *dev = gn->dev;
136 struct gen_lun *lun; 136 struct gen_lun *lun;
137 struct nvm_block *blk; 137 struct nvm_block *blk;
138 int i; 138 int i;
@@ -219,13 +219,21 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn)
219 struct gen_lun *lun; 219 struct gen_lun *lun;
220 struct nvm_block *block; 220 struct nvm_block *block;
221 sector_t lun_iter, blk_iter, cur_block_id = 0; 221 sector_t lun_iter, blk_iter, cur_block_id = 0;
222 int ret; 222 int ret, nr_blks;
223 u8 *blks;
224
225 nr_blks = dev->blks_per_lun * dev->plane_mode;
226 blks = kmalloc(nr_blks, GFP_KERNEL);
227 if (!blks)
228 return -ENOMEM;
223 229
224 gennvm_for_each_lun(gn, lun, lun_iter) { 230 gennvm_for_each_lun(gn, lun, lun_iter) {
225 lun->vlun.blocks = vzalloc(sizeof(struct nvm_block) * 231 lun->vlun.blocks = vzalloc(sizeof(struct nvm_block) *
226 dev->blks_per_lun); 232 dev->blks_per_lun);
227 if (!lun->vlun.blocks) 233 if (!lun->vlun.blocks) {
234 kfree(blks);
228 return -ENOMEM; 235 return -ENOMEM;
236 }
229 237
230 for (blk_iter = 0; blk_iter < dev->blks_per_lun; blk_iter++) { 238 for (blk_iter = 0; blk_iter < dev->blks_per_lun; blk_iter++) {
231 block = &lun->vlun.blocks[blk_iter]; 239 block = &lun->vlun.blocks[blk_iter];
@@ -250,12 +258,14 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn)
250 ppa.ppa = 0; 258 ppa.ppa = 0;
251 ppa.g.ch = lun->vlun.chnl_id; 259 ppa.g.ch = lun->vlun.chnl_id;
252 ppa.g.lun = lun->vlun.id; 260 ppa.g.lun = lun->vlun.id;
253 ppa = generic_to_dev_addr(dev, ppa);
254 261
255 ret = dev->ops->get_bb_tbl(dev, ppa, 262 ret = nvm_get_bb_tbl(dev, ppa, blks);
256 gennvm_block_bb, gn); 263 if (ret)
264 pr_err("gennvm: could not get BB table\n");
265
266 ret = gennvm_block_bb(gn, ppa, blks, nr_blks);
257 if (ret) 267 if (ret)
258 pr_err("gennvm: could not read BB table\n"); 268 pr_err("gennvm: BB table map failed\n");
259 } 269 }
260 } 270 }
261 271
@@ -268,6 +278,7 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn)
268 } 278 }
269 } 279 }
270 280
281 kfree(blks);
271 return 0; 282 return 0;
272} 283}
273 284
diff --git a/drivers/lightnvm/sysblk.c b/drivers/lightnvm/sysblk.c
index a48093d17fea..dc99c0ac8701 100644
--- a/drivers/lightnvm/sysblk.c
+++ b/drivers/lightnvm/sysblk.c
@@ -93,10 +93,45 @@ void nvm_setup_sysblk_scan(struct nvm_dev *dev, struct sysblk_scan *s,
93 s->nr_rows = nvm_setup_sysblks(dev, sysblk_ppas); 93 s->nr_rows = nvm_setup_sysblks(dev, sysblk_ppas);
94} 94}
95 95
96static int sysblk_get_free_blks(struct nvm_dev *dev, struct ppa_addr ppa,
97 u8 *blks, int nr_blks,
98 struct sysblk_scan *s)
99{
100 struct ppa_addr *sppa;
101 int i, blkid = 0;
102
103 nr_blks = nvm_bb_tbl_fold(dev, blks, nr_blks);
104 if (nr_blks < 0)
105 return nr_blks;
106
107 for (i = 0; i < nr_blks; i++) {
108 if (blks[i] == NVM_BLK_T_HOST)
109 return -EEXIST;
110
111 if (blks[i] != NVM_BLK_T_FREE)
112 continue;
113
114 sppa = &s->ppas[scan_ppa_idx(s->row, blkid)];
115 sppa->g.ch = ppa.g.ch;
116 sppa->g.lun = ppa.g.lun;
117 sppa->g.blk = i;
118 s->nr_ppas++;
119 blkid++;
120
121 pr_debug("nvm: use (%u %u %u) as sysblk\n",
122 sppa->g.ch, sppa->g.lun, sppa->g.blk);
123 if (blkid > MAX_BLKS_PR_SYSBLK - 1)
124 return 0;
125 }
126
127 pr_err("nvm: sysblk failed get sysblk\n");
128 return -EINVAL;
129}
130
96static int sysblk_get_host_blks(struct nvm_dev *dev, struct ppa_addr ppa, 131static int sysblk_get_host_blks(struct nvm_dev *dev, struct ppa_addr ppa,
97 u8 *blks, int nr_blks, void *private) 132 u8 *blks, int nr_blks,
133 struct sysblk_scan *s)
98{ 134{
99 struct sysblk_scan *s = private;
100 int i, nr_sysblk = 0; 135 int i, nr_sysblk = 0;
101 136
102 nr_blks = nvm_bb_tbl_fold(dev, blks, nr_blks); 137 nr_blks = nvm_bb_tbl_fold(dev, blks, nr_blks);
@@ -123,26 +158,42 @@ static int sysblk_get_host_blks(struct nvm_dev *dev, struct ppa_addr ppa,
123} 158}
124 159
125static int nvm_get_all_sysblks(struct nvm_dev *dev, struct sysblk_scan *s, 160static int nvm_get_all_sysblks(struct nvm_dev *dev, struct sysblk_scan *s,
126 struct ppa_addr *ppas, nvm_bb_update_fn *fn) 161 struct ppa_addr *ppas, int get_free)
127{ 162{
128 struct ppa_addr dppa; 163 int i, nr_blks, ret = 0;
129 int i, ret = 0; 164 u8 *blks;
130 165
131 s->nr_ppas = 0; 166 s->nr_ppas = 0;
167 nr_blks = dev->blks_per_lun * dev->plane_mode;
168
169 blks = kmalloc(nr_blks, GFP_KERNEL);
170 if (!blks)
171 return -ENOMEM;
132 172
133 for (i = 0; i < s->nr_rows; i++) { 173 for (i = 0; i < s->nr_rows; i++) {
134 dppa = generic_to_dev_addr(dev, ppas[i]);
135 s->row = i; 174 s->row = i;
136 175
137 ret = dev->ops->get_bb_tbl(dev, dppa, fn, s); 176 ret = nvm_get_bb_tbl(dev, ppas[i], blks);
138 if (ret) { 177 if (ret) {
139 pr_err("nvm: failed bb tbl for ppa (%u %u)\n", 178 pr_err("nvm: failed bb tbl for ppa (%u %u)\n",
140 ppas[i].g.ch, 179 ppas[i].g.ch,
141 ppas[i].g.blk); 180 ppas[i].g.blk);
142 return ret; 181 goto err_get;
143 } 182 }
183
184 if (get_free)
185 ret = sysblk_get_free_blks(dev, ppas[i], blks, nr_blks,
186 s);
187 else
188 ret = sysblk_get_host_blks(dev, ppas[i], blks, nr_blks,
189 s);
190
191 if (ret)
192 goto err_get;
144 } 193 }
145 194
195err_get:
196 kfree(blks);
146 return ret; 197 return ret;
147} 198}
148 199
@@ -239,41 +290,6 @@ static int nvm_set_bb_tbl(struct nvm_dev *dev, struct sysblk_scan *s, int type)
239 return 0; 290 return 0;
240} 291}
241 292
242static int sysblk_get_free_blks(struct nvm_dev *dev, struct ppa_addr ppa,
243 u8 *blks, int nr_blks, void *private)
244{
245 struct sysblk_scan *s = private;
246 struct ppa_addr *sppa;
247 int i, blkid = 0;
248
249 nr_blks = nvm_bb_tbl_fold(dev, blks, nr_blks);
250 if (nr_blks < 0)
251 return nr_blks;
252
253 for (i = 0; i < nr_blks; i++) {
254 if (blks[i] == NVM_BLK_T_HOST)
255 return -EEXIST;
256
257 if (blks[i] != NVM_BLK_T_FREE)
258 continue;
259
260 sppa = &s->ppas[scan_ppa_idx(s->row, blkid)];
261 sppa->g.ch = ppa.g.ch;
262 sppa->g.lun = ppa.g.lun;
263 sppa->g.blk = i;
264 s->nr_ppas++;
265 blkid++;
266
267 pr_debug("nvm: use (%u %u %u) as sysblk\n",
268 sppa->g.ch, sppa->g.lun, sppa->g.blk);
269 if (blkid > MAX_BLKS_PR_SYSBLK - 1)
270 return 0;
271 }
272
273 pr_err("nvm: sysblk failed get sysblk\n");
274 return -EINVAL;
275}
276
277static int nvm_write_and_verify(struct nvm_dev *dev, struct nvm_sb_info *info, 293static int nvm_write_and_verify(struct nvm_dev *dev, struct nvm_sb_info *info,
278 struct sysblk_scan *s) 294 struct sysblk_scan *s)
279{ 295{
@@ -393,7 +409,7 @@ int nvm_get_sysblock(struct nvm_dev *dev, struct nvm_sb_info *info)
393 nvm_setup_sysblk_scan(dev, &s, sysblk_ppas); 409 nvm_setup_sysblk_scan(dev, &s, sysblk_ppas);
394 410
395 mutex_lock(&dev->mlock); 411 mutex_lock(&dev->mlock);
396 ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, sysblk_get_host_blks); 412 ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, 0);
397 if (ret) 413 if (ret)
398 goto err_sysblk; 414 goto err_sysblk;
399 415
@@ -453,7 +469,7 @@ int nvm_update_sysblock(struct nvm_dev *dev, struct nvm_sb_info *new)
453 nvm_setup_sysblk_scan(dev, &s, sysblk_ppas); 469 nvm_setup_sysblk_scan(dev, &s, sysblk_ppas);
454 470
455 mutex_lock(&dev->mlock); 471 mutex_lock(&dev->mlock);
456 ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, sysblk_get_host_blks); 472 ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, 0);
457 if (ret) 473 if (ret)
458 goto err_sysblk; 474 goto err_sysblk;
459 475
@@ -551,7 +567,7 @@ int nvm_init_sysblock(struct nvm_dev *dev, struct nvm_sb_info *info)
551 nvm_setup_sysblk_scan(dev, &s, sysblk_ppas); 567 nvm_setup_sysblk_scan(dev, &s, sysblk_ppas);
552 568
553 mutex_lock(&dev->mlock); 569 mutex_lock(&dev->mlock);
554 ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, sysblk_get_free_blks); 570 ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, 1);
555 if (ret) 571 if (ret)
556 goto err_mark; 572 goto err_mark;
557 573
@@ -587,9 +603,9 @@ static unsigned int factory_blk_offset(struct nvm_dev *dev, int ch, int lun)
587} 603}
588 604
589static int nvm_factory_blks(struct nvm_dev *dev, struct ppa_addr ppa, 605static int nvm_factory_blks(struct nvm_dev *dev, struct ppa_addr ppa,
590 u8 *blks, int nr_blks, void *private) 606 u8 *blks, int nr_blks,
607 struct factory_blks *f)
591{ 608{
592 struct factory_blks *f = private;
593 int i, lunoff; 609 int i, lunoff;
594 610
595 nr_blks = nvm_bb_tbl_fold(dev, blks, nr_blks); 611 nr_blks = nvm_bb_tbl_fold(dev, blks, nr_blks);
@@ -659,32 +675,29 @@ static int nvm_fact_get_blks(struct nvm_dev *dev, struct ppa_addr *erase_list,
659 return ppa_cnt; 675 return ppa_cnt;
660} 676}
661 677
662static int nvm_fact_get_bb_tbl(struct nvm_dev *dev, struct ppa_addr ppa,
663 nvm_bb_update_fn *fn, void *priv)
664{
665 struct ppa_addr dev_ppa;
666 int ret;
667
668 dev_ppa = generic_to_dev_addr(dev, ppa);
669
670 ret = dev->ops->get_bb_tbl(dev, dev_ppa, fn, priv);
671 if (ret)
672 pr_err("nvm: failed bb tbl for ch%u lun%u\n",
673 ppa.g.ch, ppa.g.blk);
674 return ret;
675}
676
677static int nvm_fact_select_blks(struct nvm_dev *dev, struct factory_blks *f) 678static int nvm_fact_select_blks(struct nvm_dev *dev, struct factory_blks *f)
678{ 679{
679 int ch, lun, ret;
680 struct ppa_addr ppa; 680 struct ppa_addr ppa;
681 int ch, lun, nr_blks, ret;
682 u8 *blks;
683
684 nr_blks = dev->blks_per_lun * dev->plane_mode;
685 blks = kmalloc(nr_blks, GFP_KERNEL);
686 if (!blks)
687 return -ENOMEM;
681 688
682 nvm_for_each_lun_ppa(dev, ppa, ch, lun) { 689 nvm_for_each_lun_ppa(dev, ppa, ch, lun) {
683 ret = nvm_fact_get_bb_tbl(dev, ppa, nvm_factory_blks, f); 690 ret = nvm_get_bb_tbl(dev, ppa, blks);
691 if (ret)
692 pr_err("nvm: failed bb tbl for ch%u lun%u\n",
693 ppa.g.ch, ppa.g.blk);
694
695 ret = nvm_factory_blks(dev, ppa, blks, nr_blks, f);
684 if (ret) 696 if (ret)
685 return ret; 697 return ret;
686 } 698 }
687 699
700 kfree(blks);
688 return 0; 701 return 0;
689} 702}
690 703
@@ -722,8 +735,7 @@ int nvm_dev_factory(struct nvm_dev *dev, int flags)
722 if (flags & NVM_FACTORY_RESET_HOST_BLKS) { 735 if (flags & NVM_FACTORY_RESET_HOST_BLKS) {
723 nvm_setup_sysblk_scan(dev, &s, sysblk_ppas); 736 nvm_setup_sysblk_scan(dev, &s, sysblk_ppas);
724 mutex_lock(&dev->mlock); 737 mutex_lock(&dev->mlock);
725 ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, 738 ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, 0);
726 sysblk_get_host_blks);
727 if (!ret) 739 if (!ret)
728 ret = nvm_set_bb_tbl(dev, &s, NVM_BLK_T_FREE); 740 ret = nvm_set_bb_tbl(dev, &s, NVM_BLK_T_FREE);
729 mutex_unlock(&dev->mlock); 741 mutex_unlock(&dev->mlock);
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index d289980d2bc8..45e3511d5d3d 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -388,7 +388,7 @@ out:
388} 388}
389 389
390static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa, 390static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
391 nvm_bb_update_fn *update_bbtbl, void *priv) 391 u8 *blks)
392{ 392{
393 struct request_queue *q = nvmdev->q; 393 struct request_queue *q = nvmdev->q;
394 struct nvme_ns *ns = q->queuedata; 394 struct nvme_ns *ns = q->queuedata;
@@ -435,9 +435,7 @@ static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
435 goto out; 435 goto out;
436 } 436 }
437 437
438 ppa = dev_to_generic_addr(nvmdev, ppa); 438 memcpy(blks, bb_tbl->blk, nvmdev->blks_per_lun * nvmdev->plane_mode);
439 ret = update_bbtbl(nvmdev, ppa, bb_tbl->blk, nr_blks, priv);
440
441out: 439out:
442 kfree(bb_tbl); 440 kfree(bb_tbl);
443 return ret; 441 return ret;
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 3f256355b9fa..16d4f2edf5b4 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -41,13 +41,10 @@ struct nvm_id;
41struct nvm_dev; 41struct nvm_dev;
42 42
43typedef int (nvm_l2p_update_fn)(u64, u32, __le64 *, void *); 43typedef int (nvm_l2p_update_fn)(u64, u32, __le64 *, void *);
44typedef int (nvm_bb_update_fn)(struct nvm_dev *, struct ppa_addr, u8 *, int,
45 void *);
46typedef int (nvm_id_fn)(struct nvm_dev *, struct nvm_id *); 44typedef int (nvm_id_fn)(struct nvm_dev *, struct nvm_id *);
47typedef int (nvm_get_l2p_tbl_fn)(struct nvm_dev *, u64, u32, 45typedef int (nvm_get_l2p_tbl_fn)(struct nvm_dev *, u64, u32,
48 nvm_l2p_update_fn *, void *); 46 nvm_l2p_update_fn *, void *);
49typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, 47typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, u8 *);
50 nvm_bb_update_fn *, void *);
51typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct nvm_rq *, int); 48typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct nvm_rq *, int);
52typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *); 49typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
53typedef int (nvm_erase_blk_fn)(struct nvm_dev *, struct nvm_rq *); 50typedef int (nvm_erase_blk_fn)(struct nvm_dev *, struct nvm_rq *);
@@ -539,6 +536,7 @@ extern int nvm_submit_ppa(struct nvm_dev *, struct ppa_addr *, int, int, int,
539extern int nvm_submit_ppa_list(struct nvm_dev *, struct ppa_addr *, int, int, 536extern int nvm_submit_ppa_list(struct nvm_dev *, struct ppa_addr *, int, int,
540 int, void *, int); 537 int, void *, int);
541extern int nvm_bb_tbl_fold(struct nvm_dev *, u8 *, int); 538extern int nvm_bb_tbl_fold(struct nvm_dev *, u8 *, int);
539extern int nvm_get_bb_tbl(struct nvm_dev *, struct ppa_addr, u8 *);
542 540
543/* sysblk.c */ 541/* sysblk.c */
544#define NVM_SYSBLK_MAGIC 0x4E564D53 /* "NVMS" */ 542#define NVM_SYSBLK_MAGIC 0x4E564D53 /* "NVMS" */