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