18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 CNEX Labs 48c2ecf20Sopenharmony_ci * Initial release: Javier Gonzalez <javier@cnexlabs.com> 58c2ecf20Sopenharmony_ci * Matias Bjorling <matias@cnexlabs.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 88c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License version 98c2ecf20Sopenharmony_ci * 2 as published by the Free Software Foundation. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but 128c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 138c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 148c2ecf20Sopenharmony_ci * General Public License for more details. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * pblk-map.c - pblk's lba-ppa mapping strategy 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "pblk.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic int pblk_map_page_data(struct pblk *pblk, unsigned int sentry, 238c2ecf20Sopenharmony_ci struct ppa_addr *ppa_list, 248c2ecf20Sopenharmony_ci unsigned long *lun_bitmap, 258c2ecf20Sopenharmony_ci void *meta_list, 268c2ecf20Sopenharmony_ci unsigned int valid_secs) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct pblk_line *line = pblk_line_get_data(pblk); 298c2ecf20Sopenharmony_ci struct pblk_emeta *emeta; 308c2ecf20Sopenharmony_ci struct pblk_w_ctx *w_ctx; 318c2ecf20Sopenharmony_ci __le64 *lba_list; 328c2ecf20Sopenharmony_ci u64 paddr; 338c2ecf20Sopenharmony_ci int nr_secs = pblk->min_write_pgs; 348c2ecf20Sopenharmony_ci int i; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (!line) 378c2ecf20Sopenharmony_ci return -ENOSPC; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (pblk_line_is_full(line)) { 408c2ecf20Sopenharmony_ci struct pblk_line *prev_line = line; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci /* If we cannot allocate a new line, make sure to store metadata 438c2ecf20Sopenharmony_ci * on current line and then fail 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci line = pblk_line_replace_data(pblk); 468c2ecf20Sopenharmony_ci pblk_line_close_meta(pblk, prev_line); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (!line) { 498c2ecf20Sopenharmony_ci pblk_pipeline_stop(pblk); 508c2ecf20Sopenharmony_ci return -ENOSPC; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci emeta = line->emeta; 568c2ecf20Sopenharmony_ci lba_list = emeta_to_lbas(pblk, emeta->buf); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci paddr = pblk_alloc_page(pblk, line, nr_secs); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci for (i = 0; i < nr_secs; i++, paddr++) { 618c2ecf20Sopenharmony_ci struct pblk_sec_meta *meta = pblk_get_meta(pblk, meta_list, i); 628c2ecf20Sopenharmony_ci __le64 addr_empty = cpu_to_le64(ADDR_EMPTY); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* ppa to be sent to the device */ 658c2ecf20Sopenharmony_ci ppa_list[i] = addr_to_gen_ppa(pblk, paddr, line->id); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* Write context for target bio completion on write buffer. Note 688c2ecf20Sopenharmony_ci * that the write buffer is protected by the sync backpointer, 698c2ecf20Sopenharmony_ci * and a single writer thread have access to each specific entry 708c2ecf20Sopenharmony_ci * at a time. Thus, it is safe to modify the context for the 718c2ecf20Sopenharmony_ci * entry we are setting up for submission without taking any 728c2ecf20Sopenharmony_ci * lock or memory barrier. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci if (i < valid_secs) { 758c2ecf20Sopenharmony_ci kref_get(&line->ref); 768c2ecf20Sopenharmony_ci atomic_inc(&line->sec_to_update); 778c2ecf20Sopenharmony_ci w_ctx = pblk_rb_w_ctx(&pblk->rwb, sentry + i); 788c2ecf20Sopenharmony_ci w_ctx->ppa = ppa_list[i]; 798c2ecf20Sopenharmony_ci meta->lba = cpu_to_le64(w_ctx->lba); 808c2ecf20Sopenharmony_ci lba_list[paddr] = cpu_to_le64(w_ctx->lba); 818c2ecf20Sopenharmony_ci if (lba_list[paddr] != addr_empty) 828c2ecf20Sopenharmony_ci line->nr_valid_lbas++; 838c2ecf20Sopenharmony_ci else 848c2ecf20Sopenharmony_ci atomic64_inc(&pblk->pad_wa); 858c2ecf20Sopenharmony_ci } else { 868c2ecf20Sopenharmony_ci lba_list[paddr] = addr_empty; 878c2ecf20Sopenharmony_ci meta->lba = addr_empty; 888c2ecf20Sopenharmony_ci __pblk_map_invalidate(pblk, line, paddr); 898c2ecf20Sopenharmony_ci } 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci pblk_down_rq(pblk, ppa_list[0], lun_bitmap); 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciint pblk_map_rq(struct pblk *pblk, struct nvm_rq *rqd, unsigned int sentry, 978c2ecf20Sopenharmony_ci unsigned long *lun_bitmap, unsigned int valid_secs, 988c2ecf20Sopenharmony_ci unsigned int off) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci void *meta_list = pblk_get_meta_for_writes(pblk, rqd); 1018c2ecf20Sopenharmony_ci void *meta_buffer; 1028c2ecf20Sopenharmony_ci struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); 1038c2ecf20Sopenharmony_ci unsigned int map_secs; 1048c2ecf20Sopenharmony_ci int min = pblk->min_write_pgs; 1058c2ecf20Sopenharmony_ci int i; 1068c2ecf20Sopenharmony_ci int ret; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci for (i = off; i < rqd->nr_ppas; i += min) { 1098c2ecf20Sopenharmony_ci map_secs = (i + min > valid_secs) ? (valid_secs % min) : min; 1108c2ecf20Sopenharmony_ci meta_buffer = pblk_get_meta(pblk, meta_list, i); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci ret = pblk_map_page_data(pblk, sentry + i, &ppa_list[i], 1138c2ecf20Sopenharmony_ci lun_bitmap, meta_buffer, map_secs); 1148c2ecf20Sopenharmony_ci if (ret) 1158c2ecf20Sopenharmony_ci return ret; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci return 0; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* only if erase_ppa is set, acquire erase semaphore */ 1228c2ecf20Sopenharmony_ciint pblk_map_erase_rq(struct pblk *pblk, struct nvm_rq *rqd, 1238c2ecf20Sopenharmony_ci unsigned int sentry, unsigned long *lun_bitmap, 1248c2ecf20Sopenharmony_ci unsigned int valid_secs, struct ppa_addr *erase_ppa) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct nvm_tgt_dev *dev = pblk->dev; 1278c2ecf20Sopenharmony_ci struct nvm_geo *geo = &dev->geo; 1288c2ecf20Sopenharmony_ci struct pblk_line_meta *lm = &pblk->lm; 1298c2ecf20Sopenharmony_ci void *meta_list = pblk_get_meta_for_writes(pblk, rqd); 1308c2ecf20Sopenharmony_ci void *meta_buffer; 1318c2ecf20Sopenharmony_ci struct ppa_addr *ppa_list = nvm_rq_to_ppa_list(rqd); 1328c2ecf20Sopenharmony_ci struct pblk_line *e_line, *d_line; 1338c2ecf20Sopenharmony_ci unsigned int map_secs; 1348c2ecf20Sopenharmony_ci int min = pblk->min_write_pgs; 1358c2ecf20Sopenharmony_ci int i, erase_lun; 1368c2ecf20Sopenharmony_ci int ret; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci for (i = 0; i < rqd->nr_ppas; i += min) { 1408c2ecf20Sopenharmony_ci map_secs = (i + min > valid_secs) ? (valid_secs % min) : min; 1418c2ecf20Sopenharmony_ci meta_buffer = pblk_get_meta(pblk, meta_list, i); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci ret = pblk_map_page_data(pblk, sentry + i, &ppa_list[i], 1448c2ecf20Sopenharmony_ci lun_bitmap, meta_buffer, map_secs); 1458c2ecf20Sopenharmony_ci if (ret) 1468c2ecf20Sopenharmony_ci return ret; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci erase_lun = pblk_ppa_to_pos(geo, ppa_list[i]); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* line can change after page map. We might also be writing the 1518c2ecf20Sopenharmony_ci * last line. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci e_line = pblk_line_get_erase(pblk); 1548c2ecf20Sopenharmony_ci if (!e_line) 1558c2ecf20Sopenharmony_ci return pblk_map_rq(pblk, rqd, sentry, lun_bitmap, 1568c2ecf20Sopenharmony_ci valid_secs, i + min); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci spin_lock(&e_line->lock); 1598c2ecf20Sopenharmony_ci if (!test_bit(erase_lun, e_line->erase_bitmap)) { 1608c2ecf20Sopenharmony_ci set_bit(erase_lun, e_line->erase_bitmap); 1618c2ecf20Sopenharmony_ci atomic_dec(&e_line->left_eblks); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci *erase_ppa = ppa_list[i]; 1648c2ecf20Sopenharmony_ci erase_ppa->a.blk = e_line->id; 1658c2ecf20Sopenharmony_ci erase_ppa->a.reserved = 0; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci spin_unlock(&e_line->lock); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci /* Avoid evaluating e_line->left_eblks */ 1708c2ecf20Sopenharmony_ci return pblk_map_rq(pblk, rqd, sentry, lun_bitmap, 1718c2ecf20Sopenharmony_ci valid_secs, i + min); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci spin_unlock(&e_line->lock); 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci d_line = pblk_line_get_data(pblk); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* line can change after page map. We might also be writing the 1798c2ecf20Sopenharmony_ci * last line. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci e_line = pblk_line_get_erase(pblk); 1828c2ecf20Sopenharmony_ci if (!e_line) 1838c2ecf20Sopenharmony_ci return -ENOSPC; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* Erase blocks that are bad in this line but might not be in next */ 1868c2ecf20Sopenharmony_ci if (unlikely(pblk_ppa_empty(*erase_ppa)) && 1878c2ecf20Sopenharmony_ci bitmap_weight(d_line->blk_bitmap, lm->blk_per_line)) { 1888c2ecf20Sopenharmony_ci int bit = -1; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ciretry: 1918c2ecf20Sopenharmony_ci bit = find_next_bit(d_line->blk_bitmap, 1928c2ecf20Sopenharmony_ci lm->blk_per_line, bit + 1); 1938c2ecf20Sopenharmony_ci if (bit >= lm->blk_per_line) 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci spin_lock(&e_line->lock); 1978c2ecf20Sopenharmony_ci if (test_bit(bit, e_line->erase_bitmap)) { 1988c2ecf20Sopenharmony_ci spin_unlock(&e_line->lock); 1998c2ecf20Sopenharmony_ci goto retry; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci spin_unlock(&e_line->lock); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci set_bit(bit, e_line->erase_bitmap); 2048c2ecf20Sopenharmony_ci atomic_dec(&e_line->left_eblks); 2058c2ecf20Sopenharmony_ci *erase_ppa = pblk->luns[bit].bppa; /* set ch and lun */ 2068c2ecf20Sopenharmony_ci erase_ppa->a.blk = e_line->id; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return 0; 2108c2ecf20Sopenharmony_ci} 211