aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lightnvm/pblk-init.c
diff options
context:
space:
mode:
authorMatias Bjørling <mb@lightnvm.io>2018-10-09 07:11:36 -0400
committerJens Axboe <axboe@kernel.dk>2018-10-09 10:25:06 -0400
commitaff3fb18f957de93e629c7d3d2c4ef1f360aa511 (patch)
tree9a4d00e5ebdbad312cf5dc4ce3379097010ecb03 /drivers/lightnvm/pblk-init.c
parentd8adaa3b86324c6186d0adf74bc256bdacfffdb6 (diff)
lightnvm: move bad block and chunk state logic to core
pblk implements two data paths for recovery line state. One for 1.2 and another for 2.0, instead of having pblk implement these, combine them in the core to reduce complexity and make available to other targets. The new interface will adhere to the 2.0 chunk definition, including managing open chunks with an active write pointer. To provide this interface, a 1.2 device recovers the state of the chunks by manually detecting if a chunk is either free/open/close/offline, and if open, scanning the flash pages sequentially to find the next writeable page. This process takes on average ~10 seconds on a device with 64 dies, 1024 blocks and 60us read access time. The process can be parallelized but is left out for maintenance simplicity, as the 1.2 specification is deprecated. For 2.0 devices, the logic is maintained internally in the drive and retrieved through the 2.0 interface. Signed-off-by: Matias Bjørling <mb@lightnvm.io> Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/lightnvm/pblk-init.c')
-rw-r--r--drivers/lightnvm/pblk-init.c116
1 files changed, 3 insertions, 113 deletions
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index 039f62d05e84..53bd52114aee 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -540,67 +540,6 @@ static void pblk_lines_free(struct pblk *pblk)
540 kfree(pblk->lines); 540 kfree(pblk->lines);
541} 541}
542 542
543static int pblk_bb_get_tbl(struct nvm_tgt_dev *dev, struct pblk_lun *rlun,
544 u8 *blks, int nr_blks)
545{
546 struct ppa_addr ppa;
547 int ret;
548
549 ppa.ppa = 0;
550 ppa.g.ch = rlun->bppa.g.ch;
551 ppa.g.lun = rlun->bppa.g.lun;
552
553 ret = nvm_get_tgt_bb_tbl(dev, ppa, blks);
554 if (ret)
555 return ret;
556
557 nr_blks = nvm_bb_tbl_fold(dev->parent, blks, nr_blks);
558 if (nr_blks < 0)
559 return -EIO;
560
561 return 0;
562}
563
564static void *pblk_bb_get_meta(struct pblk *pblk)
565{
566 struct nvm_tgt_dev *dev = pblk->dev;
567 struct nvm_geo *geo = &dev->geo;
568 u8 *meta;
569 int i, nr_blks, blk_per_lun;
570 int ret;
571
572 blk_per_lun = geo->num_chk * geo->pln_mode;
573 nr_blks = blk_per_lun * geo->all_luns;
574
575 meta = kmalloc(nr_blks, GFP_KERNEL);
576 if (!meta)
577 return ERR_PTR(-ENOMEM);
578
579 for (i = 0; i < geo->all_luns; i++) {
580 struct pblk_lun *rlun = &pblk->luns[i];
581 u8 *meta_pos = meta + i * blk_per_lun;
582
583 ret = pblk_bb_get_tbl(dev, rlun, meta_pos, blk_per_lun);
584 if (ret) {
585 kfree(meta);
586 return ERR_PTR(-EIO);
587 }
588 }
589
590 return meta;
591}
592
593static void *pblk_chunk_get_meta(struct pblk *pblk)
594{
595 struct nvm_tgt_dev *dev = pblk->dev;
596 struct nvm_geo *geo = &dev->geo;
597
598 if (geo->version == NVM_OCSSD_SPEC_12)
599 return pblk_bb_get_meta(pblk);
600 else
601 return pblk_chunk_get_info(pblk);
602}
603
604static int pblk_luns_init(struct pblk *pblk) 543static int pblk_luns_init(struct pblk *pblk)
605{ 544{
606 struct nvm_tgt_dev *dev = pblk->dev; 545 struct nvm_tgt_dev *dev = pblk->dev;
@@ -699,51 +638,7 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks)
699 atomic_set(&pblk->rl.free_user_blocks, nr_free_blks); 638 atomic_set(&pblk->rl.free_user_blocks, nr_free_blks);
700} 639}
701 640
702static int pblk_setup_line_meta_12(struct pblk *pblk, struct pblk_line *line, 641static int pblk_setup_line_meta_chk(struct pblk *pblk, struct pblk_line *line,
703 void *chunk_meta)
704{
705 struct nvm_tgt_dev *dev = pblk->dev;
706 struct nvm_geo *geo = &dev->geo;
707 struct pblk_line_meta *lm = &pblk->lm;
708 int i, chk_per_lun, nr_bad_chks = 0;
709
710 chk_per_lun = geo->num_chk * geo->pln_mode;
711
712 for (i = 0; i < lm->blk_per_line; i++) {
713 struct pblk_lun *rlun = &pblk->luns[i];
714 struct nvm_chk_meta *chunk;
715 int pos = pblk_ppa_to_pos(geo, rlun->bppa);
716 u8 *lun_bb_meta = chunk_meta + pos * chk_per_lun;
717
718 chunk = &line->chks[pos];
719
720 /*
721 * In 1.2 spec. chunk state is not persisted by the device. Thus
722 * some of the values are reset each time pblk is instantiated,
723 * so we have to assume that the block is closed.
724 */
725 if (lun_bb_meta[line->id] == NVM_BLK_T_FREE)
726 chunk->state = NVM_CHK_ST_CLOSED;
727 else
728 chunk->state = NVM_CHK_ST_OFFLINE;
729
730 chunk->type = NVM_CHK_TP_W_SEQ;
731 chunk->wi = 0;
732 chunk->slba = -1;
733 chunk->cnlb = geo->clba;
734 chunk->wp = 0;
735
736 if (!(chunk->state & NVM_CHK_ST_OFFLINE))
737 continue;
738
739 set_bit(pos, line->blk_bitmap);
740 nr_bad_chks++;
741 }
742
743 return nr_bad_chks;
744}
745
746static int pblk_setup_line_meta_20(struct pblk *pblk, struct pblk_line *line,
747 struct nvm_chk_meta *meta) 642 struct nvm_chk_meta *meta)
748{ 643{
749 struct nvm_tgt_dev *dev = pblk->dev; 644 struct nvm_tgt_dev *dev = pblk->dev;
@@ -790,8 +685,6 @@ static int pblk_setup_line_meta_20(struct pblk *pblk, struct pblk_line *line,
790static long pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line, 685static long pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
791 void *chunk_meta, int line_id) 686 void *chunk_meta, int line_id)
792{ 687{
793 struct nvm_tgt_dev *dev = pblk->dev;
794 struct nvm_geo *geo = &dev->geo;
795 struct pblk_line_mgmt *l_mg = &pblk->l_mg; 688 struct pblk_line_mgmt *l_mg = &pblk->l_mg;
796 struct pblk_line_meta *lm = &pblk->lm; 689 struct pblk_line_meta *lm = &pblk->lm;
797 long nr_bad_chks, chk_in_line; 690 long nr_bad_chks, chk_in_line;
@@ -804,10 +697,7 @@ static long pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
804 line->vsc = &l_mg->vsc_list[line_id]; 697 line->vsc = &l_mg->vsc_list[line_id];
805 spin_lock_init(&line->lock); 698 spin_lock_init(&line->lock);
806 699
807 if (geo->version == NVM_OCSSD_SPEC_12) 700 nr_bad_chks = pblk_setup_line_meta_chk(pblk, line, chunk_meta);
808 nr_bad_chks = pblk_setup_line_meta_12(pblk, line, chunk_meta);
809 else
810 nr_bad_chks = pblk_setup_line_meta_20(pblk, line, chunk_meta);
811 701
812 chk_in_line = lm->blk_per_line - nr_bad_chks; 702 chk_in_line = lm->blk_per_line - nr_bad_chks;
813 if (nr_bad_chks < 0 || nr_bad_chks > lm->blk_per_line || 703 if (nr_bad_chks < 0 || nr_bad_chks > lm->blk_per_line ||
@@ -1058,7 +948,7 @@ static int pblk_lines_init(struct pblk *pblk)
1058 if (ret) 948 if (ret)
1059 goto fail_free_meta; 949 goto fail_free_meta;
1060 950
1061 chunk_meta = pblk_chunk_get_meta(pblk); 951 chunk_meta = pblk_get_chunk_meta(pblk);
1062 if (IS_ERR(chunk_meta)) { 952 if (IS_ERR(chunk_meta)) {
1063 ret = PTR_ERR(chunk_meta); 953 ret = PTR_ERR(chunk_meta);
1064 goto fail_free_luns; 954 goto fail_free_luns;