aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lightnvm/pblk-init.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/lightnvm/pblk-init.c')
-rw-r--r--drivers/lightnvm/pblk-init.c222
1 files changed, 158 insertions, 64 deletions
diff --git a/drivers/lightnvm/pblk-init.c b/drivers/lightnvm/pblk-init.c
index 5b381700ef30..27b4974930b4 100644
--- a/drivers/lightnvm/pblk-init.c
+++ b/drivers/lightnvm/pblk-init.c
@@ -451,6 +451,7 @@ static void pblk_line_meta_free(struct pblk_line *line)
451{ 451{
452 kfree(line->blk_bitmap); 452 kfree(line->blk_bitmap);
453 kfree(line->erase_bitmap); 453 kfree(line->erase_bitmap);
454 kfree(line->chks);
454} 455}
455 456
456static void pblk_lines_free(struct pblk *pblk) 457static void pblk_lines_free(struct pblk *pblk)
@@ -495,55 +496,44 @@ static int pblk_bb_get_tbl(struct nvm_tgt_dev *dev, struct pblk_lun *rlun,
495 return 0; 496 return 0;
496} 497}
497 498
498static void *pblk_bb_get_log(struct pblk *pblk) 499static void *pblk_bb_get_meta(struct pblk *pblk)
499{ 500{
500 struct nvm_tgt_dev *dev = pblk->dev; 501 struct nvm_tgt_dev *dev = pblk->dev;
501 struct nvm_geo *geo = &dev->geo; 502 struct nvm_geo *geo = &dev->geo;
502 u8 *log; 503 u8 *meta;
503 int i, nr_blks, blk_per_lun; 504 int i, nr_blks, blk_per_lun;
504 int ret; 505 int ret;
505 506
506 blk_per_lun = geo->num_chk * geo->pln_mode; 507 blk_per_lun = geo->num_chk * geo->pln_mode;
507 nr_blks = blk_per_lun * geo->all_luns; 508 nr_blks = blk_per_lun * geo->all_luns;
508 509
509 log = kmalloc(nr_blks, GFP_KERNEL); 510 meta = kmalloc(nr_blks, GFP_KERNEL);
510 if (!log) 511 if (!meta)
511 return ERR_PTR(-ENOMEM); 512 return ERR_PTR(-ENOMEM);
512 513
513 for (i = 0; i < geo->all_luns; i++) { 514 for (i = 0; i < geo->all_luns; i++) {
514 struct pblk_lun *rlun = &pblk->luns[i]; 515 struct pblk_lun *rlun = &pblk->luns[i];
515 u8 *log_pos = log + i * blk_per_lun; 516 u8 *meta_pos = meta + i * blk_per_lun;
516 517
517 ret = pblk_bb_get_tbl(dev, rlun, log_pos, blk_per_lun); 518 ret = pblk_bb_get_tbl(dev, rlun, meta_pos, blk_per_lun);
518 if (ret) { 519 if (ret) {
519 kfree(log); 520 kfree(meta);
520 return ERR_PTR(-EIO); 521 return ERR_PTR(-EIO);
521 } 522 }
522 } 523 }
523 524
524 return log; 525 return meta;
525} 526}
526 527
527static int pblk_bb_line(struct pblk *pblk, struct pblk_line *line, 528static void *pblk_chunk_get_meta(struct pblk *pblk)
528 u8 *bb_log, int blk_per_line)
529{ 529{
530 struct nvm_tgt_dev *dev = pblk->dev; 530 struct nvm_tgt_dev *dev = pblk->dev;
531 struct nvm_geo *geo = &dev->geo; 531 struct nvm_geo *geo = &dev->geo;
532 int i, bb_cnt = 0;
533 int blk_per_lun = geo->num_chk * geo->pln_mode;
534 532
535 for (i = 0; i < blk_per_line; i++) { 533 if (geo->version == NVM_OCSSD_SPEC_12)
536 struct pblk_lun *rlun = &pblk->luns[i]; 534 return pblk_bb_get_meta(pblk);
537 u8 *lun_bb_log = bb_log + i * blk_per_lun; 535 else
538 536 return pblk_chunk_get_info(pblk);
539 if (lun_bb_log[line->id] == NVM_BLK_T_FREE)
540 continue;
541
542 set_bit(pblk_ppa_to_pos(geo, rlun->bppa), line->blk_bitmap);
543 bb_cnt++;
544 }
545
546 return bb_cnt;
547} 537}
548 538
549static int pblk_luns_init(struct pblk *pblk) 539static int pblk_luns_init(struct pblk *pblk)
@@ -644,8 +634,131 @@ static void pblk_set_provision(struct pblk *pblk, long nr_free_blks)
644 atomic_set(&pblk->rl.free_user_blocks, nr_free_blks); 634 atomic_set(&pblk->rl.free_user_blocks, nr_free_blks);
645} 635}
646 636
647static int pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line, 637static int pblk_setup_line_meta_12(struct pblk *pblk, struct pblk_line *line,
648 void *chunk_log, long *nr_bad_blks) 638 void *chunk_meta)
639{
640 struct nvm_tgt_dev *dev = pblk->dev;
641 struct nvm_geo *geo = &dev->geo;
642 struct pblk_line_meta *lm = &pblk->lm;
643 int i, chk_per_lun, nr_bad_chks = 0;
644
645 chk_per_lun = geo->num_chk * geo->pln_mode;
646
647 for (i = 0; i < lm->blk_per_line; i++) {
648 struct pblk_lun *rlun = &pblk->luns[i];
649 struct nvm_chk_meta *chunk;
650 int pos = pblk_ppa_to_pos(geo, rlun->bppa);
651 u8 *lun_bb_meta = chunk_meta + pos * chk_per_lun;
652
653 chunk = &line->chks[pos];
654
655 /*
656 * In 1.2 spec. chunk state is not persisted by the device. Thus
657 * some of the values are reset each time pblk is instantiated.
658 */
659 if (lun_bb_meta[line->id] == NVM_BLK_T_FREE)
660 chunk->state = NVM_CHK_ST_FREE;
661 else
662 chunk->state = NVM_CHK_ST_OFFLINE;
663
664 chunk->type = NVM_CHK_TP_W_SEQ;
665 chunk->wi = 0;
666 chunk->slba = -1;
667 chunk->cnlb = geo->clba;
668 chunk->wp = 0;
669
670 if (!(chunk->state & NVM_CHK_ST_OFFLINE))
671 continue;
672
673 set_bit(pos, line->blk_bitmap);
674 nr_bad_chks++;
675 }
676
677 return nr_bad_chks;
678}
679
680static int pblk_setup_line_meta_20(struct pblk *pblk, struct pblk_line *line,
681 struct nvm_chk_meta *meta)
682{
683 struct nvm_tgt_dev *dev = pblk->dev;
684 struct nvm_geo *geo = &dev->geo;
685 struct pblk_line_meta *lm = &pblk->lm;
686 int i, nr_bad_chks = 0;
687
688 for (i = 0; i < lm->blk_per_line; i++) {
689 struct pblk_lun *rlun = &pblk->luns[i];
690 struct nvm_chk_meta *chunk;
691 struct nvm_chk_meta *chunk_meta;
692 struct ppa_addr ppa;
693 int pos;
694
695 ppa = rlun->bppa;
696 pos = pblk_ppa_to_pos(geo, ppa);
697 chunk = &line->chks[pos];
698
699 ppa.m.chk = line->id;
700 chunk_meta = pblk_chunk_get_off(pblk, meta, ppa);
701
702 chunk->state = chunk_meta->state;
703 chunk->type = chunk_meta->type;
704 chunk->wi = chunk_meta->wi;
705 chunk->slba = chunk_meta->slba;
706 chunk->cnlb = chunk_meta->cnlb;
707 chunk->wp = chunk_meta->wp;
708
709 if (!(chunk->state & NVM_CHK_ST_OFFLINE))
710 continue;
711
712 if (chunk->type & NVM_CHK_TP_SZ_SPEC) {
713 WARN_ONCE(1, "pblk: custom-sized chunks unsupported\n");
714 continue;
715 }
716
717 set_bit(pos, line->blk_bitmap);
718 nr_bad_chks++;
719 }
720
721 return nr_bad_chks;
722}
723
724static long pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
725 void *chunk_meta, int line_id)
726{
727 struct nvm_tgt_dev *dev = pblk->dev;
728 struct nvm_geo *geo = &dev->geo;
729 struct pblk_line_mgmt *l_mg = &pblk->l_mg;
730 struct pblk_line_meta *lm = &pblk->lm;
731 long nr_bad_chks, chk_in_line;
732
733 line->pblk = pblk;
734 line->id = line_id;
735 line->type = PBLK_LINETYPE_FREE;
736 line->state = PBLK_LINESTATE_NEW;
737 line->gc_group = PBLK_LINEGC_NONE;
738 line->vsc = &l_mg->vsc_list[line_id];
739 spin_lock_init(&line->lock);
740
741 if (geo->version == NVM_OCSSD_SPEC_12)
742 nr_bad_chks = pblk_setup_line_meta_12(pblk, line, chunk_meta);
743 else
744 nr_bad_chks = pblk_setup_line_meta_20(pblk, line, chunk_meta);
745
746 chk_in_line = lm->blk_per_line - nr_bad_chks;
747 if (nr_bad_chks < 0 || nr_bad_chks > lm->blk_per_line ||
748 chk_in_line < lm->min_blk_line) {
749 line->state = PBLK_LINESTATE_BAD;
750 list_add_tail(&line->list, &l_mg->bad_list);
751 return 0;
752 }
753
754 atomic_set(&line->blk_in_line, chk_in_line);
755 list_add_tail(&line->list, &l_mg->free_list);
756 l_mg->nr_free_lines++;
757
758 return chk_in_line;
759}
760
761static int pblk_alloc_line_meta(struct pblk *pblk, struct pblk_line *line)
649{ 762{
650 struct pblk_line_meta *lm = &pblk->lm; 763 struct pblk_line_meta *lm = &pblk->lm;
651 764
@@ -659,7 +772,13 @@ static int pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
659 return -ENOMEM; 772 return -ENOMEM;
660 } 773 }
661 774
662 *nr_bad_blks = pblk_bb_line(pblk, line, chunk_log, lm->blk_per_line); 775 line->chks = kmalloc(lm->blk_per_line * sizeof(struct nvm_chk_meta),
776 GFP_KERNEL);
777 if (!line->chks) {
778 kfree(line->erase_bitmap);
779 kfree(line->blk_bitmap);
780 return -ENOMEM;
781 }
663 782
664 return 0; 783 return 0;
665} 784}
@@ -846,10 +965,9 @@ add_emeta_page:
846static int pblk_lines_init(struct pblk *pblk) 965static int pblk_lines_init(struct pblk *pblk)
847{ 966{
848 struct pblk_line_mgmt *l_mg = &pblk->l_mg; 967 struct pblk_line_mgmt *l_mg = &pblk->l_mg;
849 struct pblk_line_meta *lm = &pblk->lm;
850 struct pblk_line *line; 968 struct pblk_line *line;
851 void *chunk_log; 969 void *chunk_meta;
852 long nr_bad_blks = 0, nr_free_blks = 0; 970 long nr_free_chks = 0;
853 int i, ret; 971 int i, ret;
854 972
855 ret = pblk_line_meta_init(pblk); 973 ret = pblk_line_meta_init(pblk);
@@ -864,11 +982,9 @@ static int pblk_lines_init(struct pblk *pblk)
864 if (ret) 982 if (ret)
865 goto fail_free_meta; 983 goto fail_free_meta;
866 984
867 chunk_log = pblk_bb_get_log(pblk); 985 chunk_meta = pblk_chunk_get_meta(pblk);
868 if (IS_ERR(chunk_log)) { 986 if (IS_ERR(chunk_meta)) {
869 pr_err("pblk: could not get bad block log (%lu)\n", 987 ret = PTR_ERR(chunk_meta);
870 PTR_ERR(chunk_log));
871 ret = PTR_ERR(chunk_log);
872 goto fail_free_luns; 988 goto fail_free_luns;
873 } 989 }
874 990
@@ -876,52 +992,30 @@ static int pblk_lines_init(struct pblk *pblk)
876 GFP_KERNEL); 992 GFP_KERNEL);
877 if (!pblk->lines) { 993 if (!pblk->lines) {
878 ret = -ENOMEM; 994 ret = -ENOMEM;
879 goto fail_free_chunk_log; 995 goto fail_free_chunk_meta;
880 } 996 }
881 997
882 for (i = 0; i < l_mg->nr_lines; i++) { 998 for (i = 0; i < l_mg->nr_lines; i++) {
883 int chk_in_line;
884
885 line = &pblk->lines[i]; 999 line = &pblk->lines[i];
886 1000
887 line->pblk = pblk; 1001 ret = pblk_alloc_line_meta(pblk, line);
888 line->id = i;
889 line->type = PBLK_LINETYPE_FREE;
890 line->state = PBLK_LINESTATE_FREE;
891 line->gc_group = PBLK_LINEGC_NONE;
892 line->vsc = &l_mg->vsc_list[i];
893 spin_lock_init(&line->lock);
894
895 ret = pblk_setup_line_meta(pblk, line, chunk_log, &nr_bad_blks);
896 if (ret) 1002 if (ret)
897 goto fail_free_lines; 1003 goto fail_free_lines;
898 1004
899 chk_in_line = lm->blk_per_line - nr_bad_blks; 1005 nr_free_chks += pblk_setup_line_meta(pblk, line, chunk_meta, i);
900 if (nr_bad_blks < 0 || nr_bad_blks > lm->blk_per_line ||
901 chk_in_line < lm->min_blk_line) {
902 line->state = PBLK_LINESTATE_BAD;
903 list_add_tail(&line->list, &l_mg->bad_list);
904 continue;
905 }
906
907 nr_free_blks += chk_in_line;
908 atomic_set(&line->blk_in_line, chk_in_line);
909
910 l_mg->nr_free_lines++;
911 list_add_tail(&line->list, &l_mg->free_list);
912 } 1006 }
913 1007
914 pblk_set_provision(pblk, nr_free_blks); 1008 pblk_set_provision(pblk, nr_free_chks);
915 1009
916 kfree(chunk_log); 1010 kfree(chunk_meta);
917 return 0; 1011 return 0;
918 1012
919fail_free_lines: 1013fail_free_lines:
920 while (--i >= 0) 1014 while (--i >= 0)
921 pblk_line_meta_free(&pblk->lines[i]); 1015 pblk_line_meta_free(&pblk->lines[i]);
922 kfree(pblk->lines); 1016 kfree(pblk->lines);
923fail_free_chunk_log: 1017fail_free_chunk_meta:
924 kfree(chunk_log); 1018 kfree(chunk_meta);
925fail_free_luns: 1019fail_free_luns:
926 kfree(pblk->luns); 1020 kfree(pblk->luns);
927fail_free_meta: 1021fail_free_meta: