18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2015 IT University of Copenhagen (rrpc.c)
48c2ecf20Sopenharmony_ci * Copyright (C) 2016 CNEX Labs
58c2ecf20Sopenharmony_ci * Initial release: Javier Gonzalez <javier@cnexlabs.com>
68c2ecf20Sopenharmony_ci *                  Matias Bjorling <matias@cnexlabs.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or
98c2ecf20Sopenharmony_ci * modify it under the terms of the GNU General Public License version
108c2ecf20Sopenharmony_ci * 2 as published by the Free Software Foundation.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, but
138c2ecf20Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
148c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
158c2ecf20Sopenharmony_ci * General Public License for more details.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * Implementation of a physical block-device target for Open-channel SSDs.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * pblk-init.c - pblk's initialization.
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include "pblk.h"
238c2ecf20Sopenharmony_ci#include "pblk-trace.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic unsigned int write_buffer_size;
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cimodule_param(write_buffer_size, uint, 0644);
288c2ecf20Sopenharmony_ciMODULE_PARM_DESC(write_buffer_size, "number of entries in a write buffer");
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistruct pblk_global_caches {
318c2ecf20Sopenharmony_ci	struct kmem_cache	*ws;
328c2ecf20Sopenharmony_ci	struct kmem_cache	*rec;
338c2ecf20Sopenharmony_ci	struct kmem_cache	*g_rq;
348c2ecf20Sopenharmony_ci	struct kmem_cache	*w_rq;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	struct kref		kref;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	struct mutex		mutex; /* Ensures consistency between
398c2ecf20Sopenharmony_ci					* caches and kref
408c2ecf20Sopenharmony_ci					*/
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic struct pblk_global_caches pblk_caches = {
448c2ecf20Sopenharmony_ci	.mutex = __MUTEX_INITIALIZER(pblk_caches.mutex),
458c2ecf20Sopenharmony_ci	.kref = KREF_INIT(0),
468c2ecf20Sopenharmony_ci};
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistruct bio_set pblk_bio_set;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic blk_qc_t pblk_submit_bio(struct bio *bio)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct pblk *pblk = bio->bi_disk->queue->queuedata;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	if (bio_op(bio) == REQ_OP_DISCARD) {
558c2ecf20Sopenharmony_ci		pblk_discard(pblk, bio);
568c2ecf20Sopenharmony_ci		if (!(bio->bi_opf & REQ_PREFLUSH)) {
578c2ecf20Sopenharmony_ci			bio_endio(bio);
588c2ecf20Sopenharmony_ci			return BLK_QC_T_NONE;
598c2ecf20Sopenharmony_ci		}
608c2ecf20Sopenharmony_ci	}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* Read requests must be <= 256kb due to NVMe's 64 bit completion bitmap
638c2ecf20Sopenharmony_ci	 * constraint. Writes can be of arbitrary size.
648c2ecf20Sopenharmony_ci	 */
658c2ecf20Sopenharmony_ci	if (bio_data_dir(bio) == READ) {
668c2ecf20Sopenharmony_ci		blk_queue_split(&bio);
678c2ecf20Sopenharmony_ci		pblk_submit_read(pblk, bio);
688c2ecf20Sopenharmony_ci	} else {
698c2ecf20Sopenharmony_ci		/* Prevent deadlock in the case of a modest LUN configuration
708c2ecf20Sopenharmony_ci		 * and large user I/Os. Unless stalled, the rate limiter
718c2ecf20Sopenharmony_ci		 * leaves at least 256KB available for user I/O.
728c2ecf20Sopenharmony_ci		 */
738c2ecf20Sopenharmony_ci		if (pblk_get_secs(bio) > pblk_rl_max_io(&pblk->rl))
748c2ecf20Sopenharmony_ci			blk_queue_split(&bio);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci		pblk_write_to_cache(pblk, bio, PBLK_IOTYPE_USER);
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return BLK_QC_T_NONE;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic const struct block_device_operations pblk_bops = {
838c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
848c2ecf20Sopenharmony_ci	.submit_bio	= pblk_submit_bio,
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic size_t pblk_trans_map_size(struct pblk *pblk)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	int entry_size = 8;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (pblk->addrf_len < 32)
938c2ecf20Sopenharmony_ci		entry_size = 4;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return entry_size * pblk->capacity;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci#ifdef CONFIG_NVM_PBLK_DEBUG
998c2ecf20Sopenharmony_cistatic u32 pblk_l2p_crc(struct pblk *pblk)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	size_t map_size;
1028c2ecf20Sopenharmony_ci	u32 crc = ~(u32)0;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	map_size = pblk_trans_map_size(pblk);
1058c2ecf20Sopenharmony_ci	crc = crc32_le(crc, pblk->trans_map, map_size);
1068c2ecf20Sopenharmony_ci	return crc;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci#endif
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic void pblk_l2p_free(struct pblk *pblk)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	vfree(pblk->trans_map);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int pblk_l2p_recover(struct pblk *pblk, bool factory_init)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct pblk_line *line = NULL;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (factory_init) {
1208c2ecf20Sopenharmony_ci		guid_gen(&pblk->instance_uuid);
1218c2ecf20Sopenharmony_ci	} else {
1228c2ecf20Sopenharmony_ci		line = pblk_recov_l2p(pblk);
1238c2ecf20Sopenharmony_ci		if (IS_ERR(line)) {
1248c2ecf20Sopenharmony_ci			pblk_err(pblk, "could not recover l2p table\n");
1258c2ecf20Sopenharmony_ci			return -EFAULT;
1268c2ecf20Sopenharmony_ci		}
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci#ifdef CONFIG_NVM_PBLK_DEBUG
1308c2ecf20Sopenharmony_ci	pblk_info(pblk, "init: L2P CRC: %x\n", pblk_l2p_crc(pblk));
1318c2ecf20Sopenharmony_ci#endif
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	/* Free full lines directly as GC has not been started yet */
1348c2ecf20Sopenharmony_ci	pblk_gc_free_full_lines(pblk);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	if (!line) {
1378c2ecf20Sopenharmony_ci		/* Configure next line for user data */
1388c2ecf20Sopenharmony_ci		line = pblk_line_get_first_data(pblk);
1398c2ecf20Sopenharmony_ci		if (!line)
1408c2ecf20Sopenharmony_ci			return -EFAULT;
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	return 0;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic int pblk_l2p_init(struct pblk *pblk, bool factory_init)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	sector_t i;
1498c2ecf20Sopenharmony_ci	struct ppa_addr ppa;
1508c2ecf20Sopenharmony_ci	size_t map_size;
1518c2ecf20Sopenharmony_ci	int ret = 0;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	map_size = pblk_trans_map_size(pblk);
1548c2ecf20Sopenharmony_ci	pblk->trans_map = __vmalloc(map_size, GFP_KERNEL | __GFP_NOWARN |
1558c2ecf20Sopenharmony_ci				    __GFP_RETRY_MAYFAIL | __GFP_HIGHMEM);
1568c2ecf20Sopenharmony_ci	if (!pblk->trans_map) {
1578c2ecf20Sopenharmony_ci		pblk_err(pblk, "failed to allocate L2P (need %zu of memory)\n",
1588c2ecf20Sopenharmony_ci				map_size);
1598c2ecf20Sopenharmony_ci		return -ENOMEM;
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	pblk_ppa_set_empty(&ppa);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	for (i = 0; i < pblk->capacity; i++)
1658c2ecf20Sopenharmony_ci		pblk_trans_map_set(pblk, i, ppa);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	ret = pblk_l2p_recover(pblk, factory_init);
1688c2ecf20Sopenharmony_ci	if (ret)
1698c2ecf20Sopenharmony_ci		vfree(pblk->trans_map);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return ret;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic void pblk_rwb_free(struct pblk *pblk)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	if (pblk_rb_tear_down_check(&pblk->rwb))
1778c2ecf20Sopenharmony_ci		pblk_err(pblk, "write buffer error on tear down\n");
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	pblk_rb_free(&pblk->rwb);
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic int pblk_rwb_init(struct pblk *pblk)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	struct nvm_tgt_dev *dev = pblk->dev;
1858c2ecf20Sopenharmony_ci	struct nvm_geo *geo = &dev->geo;
1868c2ecf20Sopenharmony_ci	unsigned long buffer_size;
1878c2ecf20Sopenharmony_ci	int pgs_in_buffer, threshold;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	threshold = geo->mw_cunits * geo->all_luns;
1908c2ecf20Sopenharmony_ci	pgs_in_buffer = (max(geo->mw_cunits, geo->ws_opt) + geo->ws_opt)
1918c2ecf20Sopenharmony_ci								* geo->all_luns;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	if (write_buffer_size && (write_buffer_size > pgs_in_buffer))
1948c2ecf20Sopenharmony_ci		buffer_size = write_buffer_size;
1958c2ecf20Sopenharmony_ci	else
1968c2ecf20Sopenharmony_ci		buffer_size = pgs_in_buffer;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	return pblk_rb_init(&pblk->rwb, buffer_size, threshold, geo->csecs);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic int pblk_set_addrf_12(struct pblk *pblk, struct nvm_geo *geo,
2028c2ecf20Sopenharmony_ci			     struct nvm_addrf_12 *dst)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	struct nvm_addrf_12 *src = (struct nvm_addrf_12 *)&geo->addrf;
2058c2ecf20Sopenharmony_ci	int power_len;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/* Re-calculate channel and lun format to adapt to configuration */
2088c2ecf20Sopenharmony_ci	power_len = get_count_order(geo->num_ch);
2098c2ecf20Sopenharmony_ci	if (1 << power_len != geo->num_ch) {
2108c2ecf20Sopenharmony_ci		pblk_err(pblk, "supports only power-of-two channel config.\n");
2118c2ecf20Sopenharmony_ci		return -EINVAL;
2128c2ecf20Sopenharmony_ci	}
2138c2ecf20Sopenharmony_ci	dst->ch_len = power_len;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	power_len = get_count_order(geo->num_lun);
2168c2ecf20Sopenharmony_ci	if (1 << power_len != geo->num_lun) {
2178c2ecf20Sopenharmony_ci		pblk_err(pblk, "supports only power-of-two LUN config.\n");
2188c2ecf20Sopenharmony_ci		return -EINVAL;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci	dst->lun_len = power_len;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	dst->blk_len = src->blk_len;
2238c2ecf20Sopenharmony_ci	dst->pg_len = src->pg_len;
2248c2ecf20Sopenharmony_ci	dst->pln_len = src->pln_len;
2258c2ecf20Sopenharmony_ci	dst->sec_len = src->sec_len;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	dst->sec_offset = 0;
2288c2ecf20Sopenharmony_ci	dst->pln_offset = dst->sec_len;
2298c2ecf20Sopenharmony_ci	dst->ch_offset = dst->pln_offset + dst->pln_len;
2308c2ecf20Sopenharmony_ci	dst->lun_offset = dst->ch_offset + dst->ch_len;
2318c2ecf20Sopenharmony_ci	dst->pg_offset = dst->lun_offset + dst->lun_len;
2328c2ecf20Sopenharmony_ci	dst->blk_offset = dst->pg_offset + dst->pg_len;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	dst->sec_mask = ((1ULL << dst->sec_len) - 1) << dst->sec_offset;
2358c2ecf20Sopenharmony_ci	dst->pln_mask = ((1ULL << dst->pln_len) - 1) << dst->pln_offset;
2368c2ecf20Sopenharmony_ci	dst->ch_mask = ((1ULL << dst->ch_len) - 1) << dst->ch_offset;
2378c2ecf20Sopenharmony_ci	dst->lun_mask = ((1ULL << dst->lun_len) - 1) << dst->lun_offset;
2388c2ecf20Sopenharmony_ci	dst->pg_mask = ((1ULL << dst->pg_len) - 1) << dst->pg_offset;
2398c2ecf20Sopenharmony_ci	dst->blk_mask = ((1ULL << dst->blk_len) - 1) << dst->blk_offset;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return dst->blk_offset + src->blk_len;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic int pblk_set_addrf_20(struct nvm_geo *geo, struct nvm_addrf *adst,
2458c2ecf20Sopenharmony_ci			     struct pblk_addrf *udst)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	struct nvm_addrf *src = &geo->addrf;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	adst->ch_len = get_count_order(geo->num_ch);
2508c2ecf20Sopenharmony_ci	adst->lun_len = get_count_order(geo->num_lun);
2518c2ecf20Sopenharmony_ci	adst->chk_len = src->chk_len;
2528c2ecf20Sopenharmony_ci	adst->sec_len = src->sec_len;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	adst->sec_offset = 0;
2558c2ecf20Sopenharmony_ci	adst->ch_offset = adst->sec_len;
2568c2ecf20Sopenharmony_ci	adst->lun_offset = adst->ch_offset + adst->ch_len;
2578c2ecf20Sopenharmony_ci	adst->chk_offset = adst->lun_offset + adst->lun_len;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	adst->sec_mask = ((1ULL << adst->sec_len) - 1) << adst->sec_offset;
2608c2ecf20Sopenharmony_ci	adst->chk_mask = ((1ULL << adst->chk_len) - 1) << adst->chk_offset;
2618c2ecf20Sopenharmony_ci	adst->lun_mask = ((1ULL << adst->lun_len) - 1) << adst->lun_offset;
2628c2ecf20Sopenharmony_ci	adst->ch_mask = ((1ULL << adst->ch_len) - 1) << adst->ch_offset;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	udst->sec_stripe = geo->ws_opt;
2658c2ecf20Sopenharmony_ci	udst->ch_stripe = geo->num_ch;
2668c2ecf20Sopenharmony_ci	udst->lun_stripe = geo->num_lun;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	udst->sec_lun_stripe = udst->sec_stripe * udst->ch_stripe;
2698c2ecf20Sopenharmony_ci	udst->sec_ws_stripe = udst->sec_lun_stripe * udst->lun_stripe;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	return adst->chk_offset + adst->chk_len;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic int pblk_set_addrf(struct pblk *pblk)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	struct nvm_tgt_dev *dev = pblk->dev;
2778c2ecf20Sopenharmony_ci	struct nvm_geo *geo = &dev->geo;
2788c2ecf20Sopenharmony_ci	int mod;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	switch (geo->version) {
2818c2ecf20Sopenharmony_ci	case NVM_OCSSD_SPEC_12:
2828c2ecf20Sopenharmony_ci		div_u64_rem(geo->clba, pblk->min_write_pgs, &mod);
2838c2ecf20Sopenharmony_ci		if (mod) {
2848c2ecf20Sopenharmony_ci			pblk_err(pblk, "bad configuration of sectors/pages\n");
2858c2ecf20Sopenharmony_ci			return -EINVAL;
2868c2ecf20Sopenharmony_ci		}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci		pblk->addrf_len = pblk_set_addrf_12(pblk, geo,
2898c2ecf20Sopenharmony_ci							(void *)&pblk->addrf);
2908c2ecf20Sopenharmony_ci		break;
2918c2ecf20Sopenharmony_ci	case NVM_OCSSD_SPEC_20:
2928c2ecf20Sopenharmony_ci		pblk->addrf_len = pblk_set_addrf_20(geo, (void *)&pblk->addrf,
2938c2ecf20Sopenharmony_ci							&pblk->uaddrf);
2948c2ecf20Sopenharmony_ci		break;
2958c2ecf20Sopenharmony_ci	default:
2968c2ecf20Sopenharmony_ci		pblk_err(pblk, "OCSSD revision not supported (%d)\n",
2978c2ecf20Sopenharmony_ci								geo->version);
2988c2ecf20Sopenharmony_ci		return -EINVAL;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	return 0;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic int pblk_create_global_caches(void)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	pblk_caches.ws = kmem_cache_create("pblk_blk_ws",
3088c2ecf20Sopenharmony_ci				sizeof(struct pblk_line_ws), 0, 0, NULL);
3098c2ecf20Sopenharmony_ci	if (!pblk_caches.ws)
3108c2ecf20Sopenharmony_ci		return -ENOMEM;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	pblk_caches.rec = kmem_cache_create("pblk_rec",
3138c2ecf20Sopenharmony_ci				sizeof(struct pblk_rec_ctx), 0, 0, NULL);
3148c2ecf20Sopenharmony_ci	if (!pblk_caches.rec)
3158c2ecf20Sopenharmony_ci		goto fail_destroy_ws;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	pblk_caches.g_rq = kmem_cache_create("pblk_g_rq", pblk_g_rq_size,
3188c2ecf20Sopenharmony_ci				0, 0, NULL);
3198c2ecf20Sopenharmony_ci	if (!pblk_caches.g_rq)
3208c2ecf20Sopenharmony_ci		goto fail_destroy_rec;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	pblk_caches.w_rq = kmem_cache_create("pblk_w_rq", pblk_w_rq_size,
3238c2ecf20Sopenharmony_ci				0, 0, NULL);
3248c2ecf20Sopenharmony_ci	if (!pblk_caches.w_rq)
3258c2ecf20Sopenharmony_ci		goto fail_destroy_g_rq;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	return 0;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cifail_destroy_g_rq:
3308c2ecf20Sopenharmony_ci	kmem_cache_destroy(pblk_caches.g_rq);
3318c2ecf20Sopenharmony_cifail_destroy_rec:
3328c2ecf20Sopenharmony_ci	kmem_cache_destroy(pblk_caches.rec);
3338c2ecf20Sopenharmony_cifail_destroy_ws:
3348c2ecf20Sopenharmony_ci	kmem_cache_destroy(pblk_caches.ws);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	return -ENOMEM;
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic int pblk_get_global_caches(void)
3408c2ecf20Sopenharmony_ci{
3418c2ecf20Sopenharmony_ci	int ret = 0;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	mutex_lock(&pblk_caches.mutex);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	if (kref_get_unless_zero(&pblk_caches.kref))
3468c2ecf20Sopenharmony_ci		goto out;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	ret = pblk_create_global_caches();
3498c2ecf20Sopenharmony_ci	if (!ret)
3508c2ecf20Sopenharmony_ci		kref_init(&pblk_caches.kref);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ciout:
3538c2ecf20Sopenharmony_ci	mutex_unlock(&pblk_caches.mutex);
3548c2ecf20Sopenharmony_ci	return ret;
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic void pblk_destroy_global_caches(struct kref *ref)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	struct pblk_global_caches *c;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	c = container_of(ref, struct pblk_global_caches, kref);
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	kmem_cache_destroy(c->ws);
3648c2ecf20Sopenharmony_ci	kmem_cache_destroy(c->rec);
3658c2ecf20Sopenharmony_ci	kmem_cache_destroy(c->g_rq);
3668c2ecf20Sopenharmony_ci	kmem_cache_destroy(c->w_rq);
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic void pblk_put_global_caches(void)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	mutex_lock(&pblk_caches.mutex);
3728c2ecf20Sopenharmony_ci	kref_put(&pblk_caches.kref, pblk_destroy_global_caches);
3738c2ecf20Sopenharmony_ci	mutex_unlock(&pblk_caches.mutex);
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic int pblk_core_init(struct pblk *pblk)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	struct nvm_tgt_dev *dev = pblk->dev;
3798c2ecf20Sopenharmony_ci	struct nvm_geo *geo = &dev->geo;
3808c2ecf20Sopenharmony_ci	int ret, max_write_ppas;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	atomic64_set(&pblk->user_wa, 0);
3838c2ecf20Sopenharmony_ci	atomic64_set(&pblk->pad_wa, 0);
3848c2ecf20Sopenharmony_ci	atomic64_set(&pblk->gc_wa, 0);
3858c2ecf20Sopenharmony_ci	pblk->user_rst_wa = 0;
3868c2ecf20Sopenharmony_ci	pblk->pad_rst_wa = 0;
3878c2ecf20Sopenharmony_ci	pblk->gc_rst_wa = 0;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	atomic64_set(&pblk->nr_flush, 0);
3908c2ecf20Sopenharmony_ci	pblk->nr_flush_rst = 0;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	pblk->min_write_pgs = geo->ws_opt;
3938c2ecf20Sopenharmony_ci	pblk->min_write_pgs_data = pblk->min_write_pgs;
3948c2ecf20Sopenharmony_ci	max_write_ppas = pblk->min_write_pgs * geo->all_luns;
3958c2ecf20Sopenharmony_ci	pblk->max_write_pgs = min_t(int, max_write_ppas, NVM_MAX_VLBA);
3968c2ecf20Sopenharmony_ci	pblk->max_write_pgs = min_t(int, pblk->max_write_pgs,
3978c2ecf20Sopenharmony_ci		queue_max_hw_sectors(dev->q) / (geo->csecs >> SECTOR_SHIFT));
3988c2ecf20Sopenharmony_ci	pblk_set_sec_per_write(pblk, pblk->min_write_pgs);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	pblk->oob_meta_size = geo->sos;
4018c2ecf20Sopenharmony_ci	if (!pblk_is_oob_meta_supported(pblk)) {
4028c2ecf20Sopenharmony_ci		/* For drives which does not have OOB metadata feature
4038c2ecf20Sopenharmony_ci		 * in order to support recovery feature we need to use
4048c2ecf20Sopenharmony_ci		 * so called packed metadata. Packed metada will store
4058c2ecf20Sopenharmony_ci		 * the same information as OOB metadata (l2p table mapping,
4068c2ecf20Sopenharmony_ci		 * but in the form of the single page at the end of
4078c2ecf20Sopenharmony_ci		 * every write request.
4088c2ecf20Sopenharmony_ci		 */
4098c2ecf20Sopenharmony_ci		if (pblk->min_write_pgs
4108c2ecf20Sopenharmony_ci			* sizeof(struct pblk_sec_meta) > PAGE_SIZE) {
4118c2ecf20Sopenharmony_ci			/* We want to keep all the packed metadata on single
4128c2ecf20Sopenharmony_ci			 * page per write requests. So we need to ensure that
4138c2ecf20Sopenharmony_ci			 * it will fit.
4148c2ecf20Sopenharmony_ci			 *
4158c2ecf20Sopenharmony_ci			 * This is more like sanity check, since there is
4168c2ecf20Sopenharmony_ci			 * no device with such a big minimal write size
4178c2ecf20Sopenharmony_ci			 * (above 1 metabytes).
4188c2ecf20Sopenharmony_ci			 */
4198c2ecf20Sopenharmony_ci			pblk_err(pblk, "Not supported min write size\n");
4208c2ecf20Sopenharmony_ci			return -EINVAL;
4218c2ecf20Sopenharmony_ci		}
4228c2ecf20Sopenharmony_ci		/* For packed meta approach we do some simplification.
4238c2ecf20Sopenharmony_ci		 * On read path we always issue requests which size
4248c2ecf20Sopenharmony_ci		 * equal to max_write_pgs, with all pages filled with
4258c2ecf20Sopenharmony_ci		 * user payload except of last one page which will be
4268c2ecf20Sopenharmony_ci		 * filled with packed metadata.
4278c2ecf20Sopenharmony_ci		 */
4288c2ecf20Sopenharmony_ci		pblk->max_write_pgs = pblk->min_write_pgs;
4298c2ecf20Sopenharmony_ci		pblk->min_write_pgs_data = pblk->min_write_pgs - 1;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	pblk->pad_dist = kcalloc(pblk->min_write_pgs - 1, sizeof(atomic64_t),
4338c2ecf20Sopenharmony_ci								GFP_KERNEL);
4348c2ecf20Sopenharmony_ci	if (!pblk->pad_dist)
4358c2ecf20Sopenharmony_ci		return -ENOMEM;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	if (pblk_get_global_caches())
4388c2ecf20Sopenharmony_ci		goto fail_free_pad_dist;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	/* Internal bios can be at most the sectors signaled by the device. */
4418c2ecf20Sopenharmony_ci	ret = mempool_init_page_pool(&pblk->page_bio_pool, NVM_MAX_VLBA, 0);
4428c2ecf20Sopenharmony_ci	if (ret)
4438c2ecf20Sopenharmony_ci		goto free_global_caches;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	ret = mempool_init_slab_pool(&pblk->gen_ws_pool, PBLK_GEN_WS_POOL_SIZE,
4468c2ecf20Sopenharmony_ci				     pblk_caches.ws);
4478c2ecf20Sopenharmony_ci	if (ret)
4488c2ecf20Sopenharmony_ci		goto free_page_bio_pool;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	ret = mempool_init_slab_pool(&pblk->rec_pool, geo->all_luns,
4518c2ecf20Sopenharmony_ci				     pblk_caches.rec);
4528c2ecf20Sopenharmony_ci	if (ret)
4538c2ecf20Sopenharmony_ci		goto free_gen_ws_pool;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	ret = mempool_init_slab_pool(&pblk->r_rq_pool, geo->all_luns,
4568c2ecf20Sopenharmony_ci				     pblk_caches.g_rq);
4578c2ecf20Sopenharmony_ci	if (ret)
4588c2ecf20Sopenharmony_ci		goto free_rec_pool;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	ret = mempool_init_slab_pool(&pblk->e_rq_pool, geo->all_luns,
4618c2ecf20Sopenharmony_ci				     pblk_caches.g_rq);
4628c2ecf20Sopenharmony_ci	if (ret)
4638c2ecf20Sopenharmony_ci		goto free_r_rq_pool;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	ret = mempool_init_slab_pool(&pblk->w_rq_pool, geo->all_luns,
4668c2ecf20Sopenharmony_ci				     pblk_caches.w_rq);
4678c2ecf20Sopenharmony_ci	if (ret)
4688c2ecf20Sopenharmony_ci		goto free_e_rq_pool;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	pblk->close_wq = alloc_workqueue("pblk-close-wq",
4718c2ecf20Sopenharmony_ci			WQ_MEM_RECLAIM | WQ_UNBOUND, PBLK_NR_CLOSE_JOBS);
4728c2ecf20Sopenharmony_ci	if (!pblk->close_wq)
4738c2ecf20Sopenharmony_ci		goto free_w_rq_pool;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	pblk->bb_wq = alloc_workqueue("pblk-bb-wq",
4768c2ecf20Sopenharmony_ci			WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
4778c2ecf20Sopenharmony_ci	if (!pblk->bb_wq)
4788c2ecf20Sopenharmony_ci		goto free_close_wq;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	pblk->r_end_wq = alloc_workqueue("pblk-read-end-wq",
4818c2ecf20Sopenharmony_ci			WQ_MEM_RECLAIM | WQ_UNBOUND, 0);
4828c2ecf20Sopenharmony_ci	if (!pblk->r_end_wq)
4838c2ecf20Sopenharmony_ci		goto free_bb_wq;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	if (pblk_set_addrf(pblk))
4868c2ecf20Sopenharmony_ci		goto free_r_end_wq;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&pblk->compl_list);
4898c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&pblk->resubmit_list);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	return 0;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cifree_r_end_wq:
4948c2ecf20Sopenharmony_ci	destroy_workqueue(pblk->r_end_wq);
4958c2ecf20Sopenharmony_cifree_bb_wq:
4968c2ecf20Sopenharmony_ci	destroy_workqueue(pblk->bb_wq);
4978c2ecf20Sopenharmony_cifree_close_wq:
4988c2ecf20Sopenharmony_ci	destroy_workqueue(pblk->close_wq);
4998c2ecf20Sopenharmony_cifree_w_rq_pool:
5008c2ecf20Sopenharmony_ci	mempool_exit(&pblk->w_rq_pool);
5018c2ecf20Sopenharmony_cifree_e_rq_pool:
5028c2ecf20Sopenharmony_ci	mempool_exit(&pblk->e_rq_pool);
5038c2ecf20Sopenharmony_cifree_r_rq_pool:
5048c2ecf20Sopenharmony_ci	mempool_exit(&pblk->r_rq_pool);
5058c2ecf20Sopenharmony_cifree_rec_pool:
5068c2ecf20Sopenharmony_ci	mempool_exit(&pblk->rec_pool);
5078c2ecf20Sopenharmony_cifree_gen_ws_pool:
5088c2ecf20Sopenharmony_ci	mempool_exit(&pblk->gen_ws_pool);
5098c2ecf20Sopenharmony_cifree_page_bio_pool:
5108c2ecf20Sopenharmony_ci	mempool_exit(&pblk->page_bio_pool);
5118c2ecf20Sopenharmony_cifree_global_caches:
5128c2ecf20Sopenharmony_ci	pblk_put_global_caches();
5138c2ecf20Sopenharmony_cifail_free_pad_dist:
5148c2ecf20Sopenharmony_ci	kfree(pblk->pad_dist);
5158c2ecf20Sopenharmony_ci	return -ENOMEM;
5168c2ecf20Sopenharmony_ci}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic void pblk_core_free(struct pblk *pblk)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	if (pblk->close_wq)
5218c2ecf20Sopenharmony_ci		destroy_workqueue(pblk->close_wq);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (pblk->r_end_wq)
5248c2ecf20Sopenharmony_ci		destroy_workqueue(pblk->r_end_wq);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	if (pblk->bb_wq)
5278c2ecf20Sopenharmony_ci		destroy_workqueue(pblk->bb_wq);
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	mempool_exit(&pblk->page_bio_pool);
5308c2ecf20Sopenharmony_ci	mempool_exit(&pblk->gen_ws_pool);
5318c2ecf20Sopenharmony_ci	mempool_exit(&pblk->rec_pool);
5328c2ecf20Sopenharmony_ci	mempool_exit(&pblk->r_rq_pool);
5338c2ecf20Sopenharmony_ci	mempool_exit(&pblk->e_rq_pool);
5348c2ecf20Sopenharmony_ci	mempool_exit(&pblk->w_rq_pool);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	pblk_put_global_caches();
5378c2ecf20Sopenharmony_ci	kfree(pblk->pad_dist);
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic void pblk_line_mg_free(struct pblk *pblk)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	struct pblk_line_mgmt *l_mg = &pblk->l_mg;
5438c2ecf20Sopenharmony_ci	int i;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	kfree(l_mg->bb_template);
5468c2ecf20Sopenharmony_ci	kfree(l_mg->bb_aux);
5478c2ecf20Sopenharmony_ci	kfree(l_mg->vsc_list);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	for (i = 0; i < PBLK_DATA_LINES; i++) {
5508c2ecf20Sopenharmony_ci		kfree(l_mg->sline_meta[i]);
5518c2ecf20Sopenharmony_ci		kvfree(l_mg->eline_meta[i]->buf);
5528c2ecf20Sopenharmony_ci		kfree(l_mg->eline_meta[i]);
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	mempool_destroy(l_mg->bitmap_pool);
5568c2ecf20Sopenharmony_ci	kmem_cache_destroy(l_mg->bitmap_cache);
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_cistatic void pblk_line_meta_free(struct pblk_line_mgmt *l_mg,
5608c2ecf20Sopenharmony_ci				struct pblk_line *line)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	struct pblk_w_err_gc *w_err_gc = line->w_err_gc;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	kfree(line->blk_bitmap);
5658c2ecf20Sopenharmony_ci	kfree(line->erase_bitmap);
5668c2ecf20Sopenharmony_ci	kfree(line->chks);
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	kvfree(w_err_gc->lba_list);
5698c2ecf20Sopenharmony_ci	kfree(w_err_gc);
5708c2ecf20Sopenharmony_ci}
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_cistatic void pblk_lines_free(struct pblk *pblk)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	struct pblk_line_mgmt *l_mg = &pblk->l_mg;
5758c2ecf20Sopenharmony_ci	struct pblk_line *line;
5768c2ecf20Sopenharmony_ci	int i;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	for (i = 0; i < l_mg->nr_lines; i++) {
5798c2ecf20Sopenharmony_ci		line = &pblk->lines[i];
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci		pblk_line_free(line);
5828c2ecf20Sopenharmony_ci		pblk_line_meta_free(l_mg, line);
5838c2ecf20Sopenharmony_ci	}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	pblk_line_mg_free(pblk);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	kfree(pblk->luns);
5888c2ecf20Sopenharmony_ci	kfree(pblk->lines);
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cistatic int pblk_luns_init(struct pblk *pblk)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	struct nvm_tgt_dev *dev = pblk->dev;
5948c2ecf20Sopenharmony_ci	struct nvm_geo *geo = &dev->geo;
5958c2ecf20Sopenharmony_ci	struct pblk_lun *rlun;
5968c2ecf20Sopenharmony_ci	int i;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	/* TODO: Implement unbalanced LUN support */
5998c2ecf20Sopenharmony_ci	if (geo->num_lun < 0) {
6008c2ecf20Sopenharmony_ci		pblk_err(pblk, "unbalanced LUN config.\n");
6018c2ecf20Sopenharmony_ci		return -EINVAL;
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	pblk->luns = kcalloc(geo->all_luns, sizeof(struct pblk_lun),
6058c2ecf20Sopenharmony_ci								GFP_KERNEL);
6068c2ecf20Sopenharmony_ci	if (!pblk->luns)
6078c2ecf20Sopenharmony_ci		return -ENOMEM;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	for (i = 0; i < geo->all_luns; i++) {
6108c2ecf20Sopenharmony_ci		/* Stripe across channels */
6118c2ecf20Sopenharmony_ci		int ch = i % geo->num_ch;
6128c2ecf20Sopenharmony_ci		int lun_raw = i / geo->num_ch;
6138c2ecf20Sopenharmony_ci		int lunid = lun_raw + ch * geo->num_lun;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci		rlun = &pblk->luns[i];
6168c2ecf20Sopenharmony_ci		rlun->bppa = dev->luns[lunid];
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci		sema_init(&rlun->wr_sem, 1);
6198c2ecf20Sopenharmony_ci	}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	return 0;
6228c2ecf20Sopenharmony_ci}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci/* See comment over struct line_emeta definition */
6258c2ecf20Sopenharmony_cistatic unsigned int calc_emeta_len(struct pblk *pblk)
6268c2ecf20Sopenharmony_ci{
6278c2ecf20Sopenharmony_ci	struct pblk_line_meta *lm = &pblk->lm;
6288c2ecf20Sopenharmony_ci	struct pblk_line_mgmt *l_mg = &pblk->l_mg;
6298c2ecf20Sopenharmony_ci	struct nvm_tgt_dev *dev = pblk->dev;
6308c2ecf20Sopenharmony_ci	struct nvm_geo *geo = &dev->geo;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	/* Round to sector size so that lba_list starts on its own sector */
6338c2ecf20Sopenharmony_ci	lm->emeta_sec[1] = DIV_ROUND_UP(
6348c2ecf20Sopenharmony_ci			sizeof(struct line_emeta) + lm->blk_bitmap_len +
6358c2ecf20Sopenharmony_ci			sizeof(struct wa_counters), geo->csecs);
6368c2ecf20Sopenharmony_ci	lm->emeta_len[1] = lm->emeta_sec[1] * geo->csecs;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	/* Round to sector size so that vsc_list starts on its own sector */
6398c2ecf20Sopenharmony_ci	lm->dsec_per_line = lm->sec_per_line - lm->emeta_sec[0];
6408c2ecf20Sopenharmony_ci	lm->emeta_sec[2] = DIV_ROUND_UP(lm->dsec_per_line * sizeof(u64),
6418c2ecf20Sopenharmony_ci			geo->csecs);
6428c2ecf20Sopenharmony_ci	lm->emeta_len[2] = lm->emeta_sec[2] * geo->csecs;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	lm->emeta_sec[3] = DIV_ROUND_UP(l_mg->nr_lines * sizeof(u32),
6458c2ecf20Sopenharmony_ci			geo->csecs);
6468c2ecf20Sopenharmony_ci	lm->emeta_len[3] = lm->emeta_sec[3] * geo->csecs;
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	lm->vsc_list_len = l_mg->nr_lines * sizeof(u32);
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	return (lm->emeta_len[1] + lm->emeta_len[2] + lm->emeta_len[3]);
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_cistatic int pblk_set_provision(struct pblk *pblk, int nr_free_chks)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	struct nvm_tgt_dev *dev = pblk->dev;
6568c2ecf20Sopenharmony_ci	struct pblk_line_mgmt *l_mg = &pblk->l_mg;
6578c2ecf20Sopenharmony_ci	struct pblk_line_meta *lm = &pblk->lm;
6588c2ecf20Sopenharmony_ci	struct nvm_geo *geo = &dev->geo;
6598c2ecf20Sopenharmony_ci	sector_t provisioned;
6608c2ecf20Sopenharmony_ci	int sec_meta, blk_meta, clba;
6618c2ecf20Sopenharmony_ci	int minimum;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	if (geo->op == NVM_TARGET_DEFAULT_OP)
6648c2ecf20Sopenharmony_ci		pblk->op = PBLK_DEFAULT_OP;
6658c2ecf20Sopenharmony_ci	else
6668c2ecf20Sopenharmony_ci		pblk->op = geo->op;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	minimum = pblk_get_min_chks(pblk);
6698c2ecf20Sopenharmony_ci	provisioned = nr_free_chks;
6708c2ecf20Sopenharmony_ci	provisioned *= (100 - pblk->op);
6718c2ecf20Sopenharmony_ci	sector_div(provisioned, 100);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	if ((nr_free_chks - provisioned) < minimum) {
6748c2ecf20Sopenharmony_ci		if (geo->op != NVM_TARGET_DEFAULT_OP) {
6758c2ecf20Sopenharmony_ci			pblk_err(pblk, "OP too small to create a sane instance\n");
6768c2ecf20Sopenharmony_ci			return -EINTR;
6778c2ecf20Sopenharmony_ci		}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci		/* If the user did not specify an OP value, and PBLK_DEFAULT_OP
6808c2ecf20Sopenharmony_ci		 * is not enough, calculate and set sane value
6818c2ecf20Sopenharmony_ci		 */
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci		provisioned = nr_free_chks - minimum;
6848c2ecf20Sopenharmony_ci		pblk->op =  (100 * minimum) / nr_free_chks;
6858c2ecf20Sopenharmony_ci		pblk_info(pblk, "Default OP insufficient, adjusting OP to %d\n",
6868c2ecf20Sopenharmony_ci				pblk->op);
6878c2ecf20Sopenharmony_ci	}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	pblk->op_blks = nr_free_chks - provisioned;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	/* Internally pblk manages all free blocks, but all calculations based
6928c2ecf20Sopenharmony_ci	 * on user capacity consider only provisioned blocks
6938c2ecf20Sopenharmony_ci	 */
6948c2ecf20Sopenharmony_ci	pblk->rl.total_blocks = nr_free_chks;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	/* Consider sectors used for metadata */
6978c2ecf20Sopenharmony_ci	sec_meta = (lm->smeta_sec + lm->emeta_sec[0]) * l_mg->nr_free_lines;
6988c2ecf20Sopenharmony_ci	blk_meta = DIV_ROUND_UP(sec_meta, geo->clba);
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	clba = (geo->clba / pblk->min_write_pgs) * pblk->min_write_pgs_data;
7018c2ecf20Sopenharmony_ci	pblk->capacity = (provisioned - blk_meta) * clba;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	atomic_set(&pblk->rl.free_blocks, nr_free_chks);
7048c2ecf20Sopenharmony_ci	atomic_set(&pblk->rl.free_user_blocks, nr_free_chks);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	return 0;
7078c2ecf20Sopenharmony_ci}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_cistatic int pblk_setup_line_meta_chk(struct pblk *pblk, struct pblk_line *line,
7108c2ecf20Sopenharmony_ci				   struct nvm_chk_meta *meta)
7118c2ecf20Sopenharmony_ci{
7128c2ecf20Sopenharmony_ci	struct nvm_tgt_dev *dev = pblk->dev;
7138c2ecf20Sopenharmony_ci	struct nvm_geo *geo = &dev->geo;
7148c2ecf20Sopenharmony_ci	struct pblk_line_meta *lm = &pblk->lm;
7158c2ecf20Sopenharmony_ci	int i, nr_bad_chks = 0;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	for (i = 0; i < lm->blk_per_line; i++) {
7188c2ecf20Sopenharmony_ci		struct pblk_lun *rlun = &pblk->luns[i];
7198c2ecf20Sopenharmony_ci		struct nvm_chk_meta *chunk;
7208c2ecf20Sopenharmony_ci		struct nvm_chk_meta *chunk_meta;
7218c2ecf20Sopenharmony_ci		struct ppa_addr ppa;
7228c2ecf20Sopenharmony_ci		int pos;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci		ppa = rlun->bppa;
7258c2ecf20Sopenharmony_ci		pos = pblk_ppa_to_pos(geo, ppa);
7268c2ecf20Sopenharmony_ci		chunk = &line->chks[pos];
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci		ppa.m.chk = line->id;
7298c2ecf20Sopenharmony_ci		chunk_meta = pblk_chunk_get_off(pblk, meta, ppa);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci		chunk->state = chunk_meta->state;
7328c2ecf20Sopenharmony_ci		chunk->type = chunk_meta->type;
7338c2ecf20Sopenharmony_ci		chunk->wi = chunk_meta->wi;
7348c2ecf20Sopenharmony_ci		chunk->slba = chunk_meta->slba;
7358c2ecf20Sopenharmony_ci		chunk->cnlb = chunk_meta->cnlb;
7368c2ecf20Sopenharmony_ci		chunk->wp = chunk_meta->wp;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci		trace_pblk_chunk_state(pblk_disk_name(pblk), &ppa,
7398c2ecf20Sopenharmony_ci					chunk->state);
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci		if (chunk->type & NVM_CHK_TP_SZ_SPEC) {
7428c2ecf20Sopenharmony_ci			WARN_ONCE(1, "pblk: custom-sized chunks unsupported\n");
7438c2ecf20Sopenharmony_ci			continue;
7448c2ecf20Sopenharmony_ci		}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci		if (!(chunk->state & NVM_CHK_ST_OFFLINE))
7478c2ecf20Sopenharmony_ci			continue;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci		set_bit(pos, line->blk_bitmap);
7508c2ecf20Sopenharmony_ci		nr_bad_chks++;
7518c2ecf20Sopenharmony_ci	}
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	return nr_bad_chks;
7548c2ecf20Sopenharmony_ci}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_cistatic long pblk_setup_line_meta(struct pblk *pblk, struct pblk_line *line,
7578c2ecf20Sopenharmony_ci				 void *chunk_meta, int line_id)
7588c2ecf20Sopenharmony_ci{
7598c2ecf20Sopenharmony_ci	struct pblk_line_mgmt *l_mg = &pblk->l_mg;
7608c2ecf20Sopenharmony_ci	struct pblk_line_meta *lm = &pblk->lm;
7618c2ecf20Sopenharmony_ci	long nr_bad_chks, chk_in_line;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	line->pblk = pblk;
7648c2ecf20Sopenharmony_ci	line->id = line_id;
7658c2ecf20Sopenharmony_ci	line->type = PBLK_LINETYPE_FREE;
7668c2ecf20Sopenharmony_ci	line->state = PBLK_LINESTATE_NEW;
7678c2ecf20Sopenharmony_ci	line->gc_group = PBLK_LINEGC_NONE;
7688c2ecf20Sopenharmony_ci	line->vsc = &l_mg->vsc_list[line_id];
7698c2ecf20Sopenharmony_ci	spin_lock_init(&line->lock);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	nr_bad_chks = pblk_setup_line_meta_chk(pblk, line, chunk_meta);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	chk_in_line = lm->blk_per_line - nr_bad_chks;
7748c2ecf20Sopenharmony_ci	if (nr_bad_chks < 0 || nr_bad_chks > lm->blk_per_line ||
7758c2ecf20Sopenharmony_ci					chk_in_line < lm->min_blk_line) {
7768c2ecf20Sopenharmony_ci		line->state = PBLK_LINESTATE_BAD;
7778c2ecf20Sopenharmony_ci		list_add_tail(&line->list, &l_mg->bad_list);
7788c2ecf20Sopenharmony_ci		return 0;
7798c2ecf20Sopenharmony_ci	}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	atomic_set(&line->blk_in_line, chk_in_line);
7828c2ecf20Sopenharmony_ci	list_add_tail(&line->list, &l_mg->free_list);
7838c2ecf20Sopenharmony_ci	l_mg->nr_free_lines++;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	return chk_in_line;
7868c2ecf20Sopenharmony_ci}
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_cistatic int pblk_alloc_line_meta(struct pblk *pblk, struct pblk_line *line)
7898c2ecf20Sopenharmony_ci{
7908c2ecf20Sopenharmony_ci	struct pblk_line_meta *lm = &pblk->lm;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	line->blk_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL);
7938c2ecf20Sopenharmony_ci	if (!line->blk_bitmap)
7948c2ecf20Sopenharmony_ci		return -ENOMEM;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	line->erase_bitmap = kzalloc(lm->blk_bitmap_len, GFP_KERNEL);
7978c2ecf20Sopenharmony_ci	if (!line->erase_bitmap)
7988c2ecf20Sopenharmony_ci		goto free_blk_bitmap;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	line->chks = kmalloc_array(lm->blk_per_line,
8028c2ecf20Sopenharmony_ci				   sizeof(struct nvm_chk_meta), GFP_KERNEL);
8038c2ecf20Sopenharmony_ci	if (!line->chks)
8048c2ecf20Sopenharmony_ci		goto free_erase_bitmap;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	line->w_err_gc = kzalloc(sizeof(struct pblk_w_err_gc), GFP_KERNEL);
8078c2ecf20Sopenharmony_ci	if (!line->w_err_gc)
8088c2ecf20Sopenharmony_ci		goto free_chks;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	return 0;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_cifree_chks:
8138c2ecf20Sopenharmony_ci	kfree(line->chks);
8148c2ecf20Sopenharmony_cifree_erase_bitmap:
8158c2ecf20Sopenharmony_ci	kfree(line->erase_bitmap);
8168c2ecf20Sopenharmony_cifree_blk_bitmap:
8178c2ecf20Sopenharmony_ci	kfree(line->blk_bitmap);
8188c2ecf20Sopenharmony_ci	return -ENOMEM;
8198c2ecf20Sopenharmony_ci}
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_cistatic int pblk_line_mg_init(struct pblk *pblk)
8228c2ecf20Sopenharmony_ci{
8238c2ecf20Sopenharmony_ci	struct nvm_tgt_dev *dev = pblk->dev;
8248c2ecf20Sopenharmony_ci	struct nvm_geo *geo = &dev->geo;
8258c2ecf20Sopenharmony_ci	struct pblk_line_mgmt *l_mg = &pblk->l_mg;
8268c2ecf20Sopenharmony_ci	struct pblk_line_meta *lm = &pblk->lm;
8278c2ecf20Sopenharmony_ci	int i, bb_distance;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	l_mg->nr_lines = geo->num_chk;
8308c2ecf20Sopenharmony_ci	l_mg->log_line = l_mg->data_line = NULL;
8318c2ecf20Sopenharmony_ci	l_mg->l_seq_nr = l_mg->d_seq_nr = 0;
8328c2ecf20Sopenharmony_ci	l_mg->nr_free_lines = 0;
8338c2ecf20Sopenharmony_ci	bitmap_zero(&l_mg->meta_bitmap, PBLK_DATA_LINES);
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&l_mg->free_list);
8368c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&l_mg->corrupt_list);
8378c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&l_mg->bad_list);
8388c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&l_mg->gc_full_list);
8398c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&l_mg->gc_high_list);
8408c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&l_mg->gc_mid_list);
8418c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&l_mg->gc_low_list);
8428c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&l_mg->gc_empty_list);
8438c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&l_mg->gc_werr_list);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&l_mg->emeta_list);
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	l_mg->gc_lists[0] = &l_mg->gc_werr_list;
8488c2ecf20Sopenharmony_ci	l_mg->gc_lists[1] = &l_mg->gc_high_list;
8498c2ecf20Sopenharmony_ci	l_mg->gc_lists[2] = &l_mg->gc_mid_list;
8508c2ecf20Sopenharmony_ci	l_mg->gc_lists[3] = &l_mg->gc_low_list;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	spin_lock_init(&l_mg->free_lock);
8538c2ecf20Sopenharmony_ci	spin_lock_init(&l_mg->close_lock);
8548c2ecf20Sopenharmony_ci	spin_lock_init(&l_mg->gc_lock);
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	l_mg->vsc_list = kcalloc(l_mg->nr_lines, sizeof(__le32), GFP_KERNEL);
8578c2ecf20Sopenharmony_ci	if (!l_mg->vsc_list)
8588c2ecf20Sopenharmony_ci		goto fail;
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	l_mg->bb_template = kzalloc(lm->sec_bitmap_len, GFP_KERNEL);
8618c2ecf20Sopenharmony_ci	if (!l_mg->bb_template)
8628c2ecf20Sopenharmony_ci		goto fail_free_vsc_list;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	l_mg->bb_aux = kzalloc(lm->sec_bitmap_len, GFP_KERNEL);
8658c2ecf20Sopenharmony_ci	if (!l_mg->bb_aux)
8668c2ecf20Sopenharmony_ci		goto fail_free_bb_template;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	/* smeta is always small enough to fit on a kmalloc memory allocation,
8698c2ecf20Sopenharmony_ci	 * emeta depends on the number of LUNs allocated to the pblk instance
8708c2ecf20Sopenharmony_ci	 */
8718c2ecf20Sopenharmony_ci	for (i = 0; i < PBLK_DATA_LINES; i++) {
8728c2ecf20Sopenharmony_ci		l_mg->sline_meta[i] = kmalloc(lm->smeta_len, GFP_KERNEL);
8738c2ecf20Sopenharmony_ci		if (!l_mg->sline_meta[i])
8748c2ecf20Sopenharmony_ci			goto fail_free_smeta;
8758c2ecf20Sopenharmony_ci	}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	l_mg->bitmap_cache = kmem_cache_create("pblk_lm_bitmap",
8788c2ecf20Sopenharmony_ci			lm->sec_bitmap_len, 0, 0, NULL);
8798c2ecf20Sopenharmony_ci	if (!l_mg->bitmap_cache)
8808c2ecf20Sopenharmony_ci		goto fail_free_smeta;
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	/* the bitmap pool is used for both valid and map bitmaps */
8838c2ecf20Sopenharmony_ci	l_mg->bitmap_pool = mempool_create_slab_pool(PBLK_DATA_LINES * 2,
8848c2ecf20Sopenharmony_ci				l_mg->bitmap_cache);
8858c2ecf20Sopenharmony_ci	if (!l_mg->bitmap_pool)
8868c2ecf20Sopenharmony_ci		goto fail_destroy_bitmap_cache;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	/* emeta allocates three different buffers for managing metadata with
8898c2ecf20Sopenharmony_ci	 * in-memory and in-media layouts
8908c2ecf20Sopenharmony_ci	 */
8918c2ecf20Sopenharmony_ci	for (i = 0; i < PBLK_DATA_LINES; i++) {
8928c2ecf20Sopenharmony_ci		struct pblk_emeta *emeta;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci		emeta = kmalloc(sizeof(struct pblk_emeta), GFP_KERNEL);
8958c2ecf20Sopenharmony_ci		if (!emeta)
8968c2ecf20Sopenharmony_ci			goto fail_free_emeta;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci		emeta->buf = kvmalloc(lm->emeta_len[0], GFP_KERNEL);
8998c2ecf20Sopenharmony_ci		if (!emeta->buf) {
9008c2ecf20Sopenharmony_ci			kfree(emeta);
9018c2ecf20Sopenharmony_ci			goto fail_free_emeta;
9028c2ecf20Sopenharmony_ci		}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci		emeta->nr_entries = lm->emeta_sec[0];
9058c2ecf20Sopenharmony_ci		l_mg->eline_meta[i] = emeta;
9068c2ecf20Sopenharmony_ci	}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	for (i = 0; i < l_mg->nr_lines; i++)
9098c2ecf20Sopenharmony_ci		l_mg->vsc_list[i] = cpu_to_le32(EMPTY_ENTRY);
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	bb_distance = (geo->all_luns) * geo->ws_opt;
9128c2ecf20Sopenharmony_ci	for (i = 0; i < lm->sec_per_line; i += bb_distance)
9138c2ecf20Sopenharmony_ci		bitmap_set(l_mg->bb_template, i, geo->ws_opt);
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	return 0;
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_cifail_free_emeta:
9188c2ecf20Sopenharmony_ci	while (--i >= 0) {
9198c2ecf20Sopenharmony_ci		kvfree(l_mg->eline_meta[i]->buf);
9208c2ecf20Sopenharmony_ci		kfree(l_mg->eline_meta[i]);
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	mempool_destroy(l_mg->bitmap_pool);
9248c2ecf20Sopenharmony_cifail_destroy_bitmap_cache:
9258c2ecf20Sopenharmony_ci	kmem_cache_destroy(l_mg->bitmap_cache);
9268c2ecf20Sopenharmony_cifail_free_smeta:
9278c2ecf20Sopenharmony_ci	for (i = 0; i < PBLK_DATA_LINES; i++)
9288c2ecf20Sopenharmony_ci		kfree(l_mg->sline_meta[i]);
9298c2ecf20Sopenharmony_ci	kfree(l_mg->bb_aux);
9308c2ecf20Sopenharmony_cifail_free_bb_template:
9318c2ecf20Sopenharmony_ci	kfree(l_mg->bb_template);
9328c2ecf20Sopenharmony_cifail_free_vsc_list:
9338c2ecf20Sopenharmony_ci	kfree(l_mg->vsc_list);
9348c2ecf20Sopenharmony_cifail:
9358c2ecf20Sopenharmony_ci	return -ENOMEM;
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cistatic int pblk_line_meta_init(struct pblk *pblk)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	struct nvm_tgt_dev *dev = pblk->dev;
9418c2ecf20Sopenharmony_ci	struct nvm_geo *geo = &dev->geo;
9428c2ecf20Sopenharmony_ci	struct pblk_line_meta *lm = &pblk->lm;
9438c2ecf20Sopenharmony_ci	unsigned int smeta_len, emeta_len;
9448c2ecf20Sopenharmony_ci	int i;
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_ci	lm->sec_per_line = geo->clba * geo->all_luns;
9478c2ecf20Sopenharmony_ci	lm->blk_per_line = geo->all_luns;
9488c2ecf20Sopenharmony_ci	lm->blk_bitmap_len = BITS_TO_LONGS(geo->all_luns) * sizeof(long);
9498c2ecf20Sopenharmony_ci	lm->sec_bitmap_len = BITS_TO_LONGS(lm->sec_per_line) * sizeof(long);
9508c2ecf20Sopenharmony_ci	lm->lun_bitmap_len = BITS_TO_LONGS(geo->all_luns) * sizeof(long);
9518c2ecf20Sopenharmony_ci	lm->mid_thrs = lm->sec_per_line / 2;
9528c2ecf20Sopenharmony_ci	lm->high_thrs = lm->sec_per_line / 4;
9538c2ecf20Sopenharmony_ci	lm->meta_distance = (geo->all_luns / 2) * pblk->min_write_pgs;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	/* Calculate necessary pages for smeta. See comment over struct
9568c2ecf20Sopenharmony_ci	 * line_smeta definition
9578c2ecf20Sopenharmony_ci	 */
9588c2ecf20Sopenharmony_ci	i = 1;
9598c2ecf20Sopenharmony_ciadd_smeta_page:
9608c2ecf20Sopenharmony_ci	lm->smeta_sec = i * geo->ws_opt;
9618c2ecf20Sopenharmony_ci	lm->smeta_len = lm->smeta_sec * geo->csecs;
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	smeta_len = sizeof(struct line_smeta) + lm->lun_bitmap_len;
9648c2ecf20Sopenharmony_ci	if (smeta_len > lm->smeta_len) {
9658c2ecf20Sopenharmony_ci		i++;
9668c2ecf20Sopenharmony_ci		goto add_smeta_page;
9678c2ecf20Sopenharmony_ci	}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	/* Calculate necessary pages for emeta. See comment over struct
9708c2ecf20Sopenharmony_ci	 * line_emeta definition
9718c2ecf20Sopenharmony_ci	 */
9728c2ecf20Sopenharmony_ci	i = 1;
9738c2ecf20Sopenharmony_ciadd_emeta_page:
9748c2ecf20Sopenharmony_ci	lm->emeta_sec[0] = i * geo->ws_opt;
9758c2ecf20Sopenharmony_ci	lm->emeta_len[0] = lm->emeta_sec[0] * geo->csecs;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	emeta_len = calc_emeta_len(pblk);
9788c2ecf20Sopenharmony_ci	if (emeta_len > lm->emeta_len[0]) {
9798c2ecf20Sopenharmony_ci		i++;
9808c2ecf20Sopenharmony_ci		goto add_emeta_page;
9818c2ecf20Sopenharmony_ci	}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	lm->emeta_bb = geo->all_luns > i ? geo->all_luns - i : 0;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	lm->min_blk_line = 1;
9868c2ecf20Sopenharmony_ci	if (geo->all_luns > 1)
9878c2ecf20Sopenharmony_ci		lm->min_blk_line += DIV_ROUND_UP(lm->smeta_sec +
9888c2ecf20Sopenharmony_ci					lm->emeta_sec[0], geo->clba);
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	if (lm->min_blk_line > lm->blk_per_line) {
9918c2ecf20Sopenharmony_ci		pblk_err(pblk, "config. not supported. Min. LUN in line:%d\n",
9928c2ecf20Sopenharmony_ci							lm->blk_per_line);
9938c2ecf20Sopenharmony_ci		return -EINVAL;
9948c2ecf20Sopenharmony_ci	}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_ci	return 0;
9978c2ecf20Sopenharmony_ci}
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_cistatic int pblk_lines_init(struct pblk *pblk)
10008c2ecf20Sopenharmony_ci{
10018c2ecf20Sopenharmony_ci	struct pblk_line_mgmt *l_mg = &pblk->l_mg;
10028c2ecf20Sopenharmony_ci	struct pblk_line *line;
10038c2ecf20Sopenharmony_ci	void *chunk_meta;
10048c2ecf20Sopenharmony_ci	int nr_free_chks = 0;
10058c2ecf20Sopenharmony_ci	int i, ret;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	ret = pblk_line_meta_init(pblk);
10088c2ecf20Sopenharmony_ci	if (ret)
10098c2ecf20Sopenharmony_ci		return ret;
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	ret = pblk_line_mg_init(pblk);
10128c2ecf20Sopenharmony_ci	if (ret)
10138c2ecf20Sopenharmony_ci		return ret;
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	ret = pblk_luns_init(pblk);
10168c2ecf20Sopenharmony_ci	if (ret)
10178c2ecf20Sopenharmony_ci		goto fail_free_meta;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	chunk_meta = pblk_get_chunk_meta(pblk);
10208c2ecf20Sopenharmony_ci	if (IS_ERR(chunk_meta)) {
10218c2ecf20Sopenharmony_ci		ret = PTR_ERR(chunk_meta);
10228c2ecf20Sopenharmony_ci		goto fail_free_luns;
10238c2ecf20Sopenharmony_ci	}
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	pblk->lines = kcalloc(l_mg->nr_lines, sizeof(struct pblk_line),
10268c2ecf20Sopenharmony_ci								GFP_KERNEL);
10278c2ecf20Sopenharmony_ci	if (!pblk->lines) {
10288c2ecf20Sopenharmony_ci		ret = -ENOMEM;
10298c2ecf20Sopenharmony_ci		goto fail_free_chunk_meta;
10308c2ecf20Sopenharmony_ci	}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	for (i = 0; i < l_mg->nr_lines; i++) {
10338c2ecf20Sopenharmony_ci		line = &pblk->lines[i];
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci		ret = pblk_alloc_line_meta(pblk, line);
10368c2ecf20Sopenharmony_ci		if (ret)
10378c2ecf20Sopenharmony_ci			goto fail_free_lines;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci		nr_free_chks += pblk_setup_line_meta(pblk, line, chunk_meta, i);
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci		trace_pblk_line_state(pblk_disk_name(pblk), line->id,
10428c2ecf20Sopenharmony_ci								line->state);
10438c2ecf20Sopenharmony_ci	}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	if (!nr_free_chks) {
10468c2ecf20Sopenharmony_ci		pblk_err(pblk, "too many bad blocks prevent for sane instance\n");
10478c2ecf20Sopenharmony_ci		ret = -EINTR;
10488c2ecf20Sopenharmony_ci		goto fail_free_lines;
10498c2ecf20Sopenharmony_ci	}
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	ret = pblk_set_provision(pblk, nr_free_chks);
10528c2ecf20Sopenharmony_ci	if (ret)
10538c2ecf20Sopenharmony_ci		goto fail_free_lines;
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	vfree(chunk_meta);
10568c2ecf20Sopenharmony_ci	return 0;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_cifail_free_lines:
10598c2ecf20Sopenharmony_ci	while (--i >= 0)
10608c2ecf20Sopenharmony_ci		pblk_line_meta_free(l_mg, &pblk->lines[i]);
10618c2ecf20Sopenharmony_ci	kfree(pblk->lines);
10628c2ecf20Sopenharmony_cifail_free_chunk_meta:
10638c2ecf20Sopenharmony_ci	vfree(chunk_meta);
10648c2ecf20Sopenharmony_cifail_free_luns:
10658c2ecf20Sopenharmony_ci	kfree(pblk->luns);
10668c2ecf20Sopenharmony_cifail_free_meta:
10678c2ecf20Sopenharmony_ci	pblk_line_mg_free(pblk);
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	return ret;
10708c2ecf20Sopenharmony_ci}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_cistatic int pblk_writer_init(struct pblk *pblk)
10738c2ecf20Sopenharmony_ci{
10748c2ecf20Sopenharmony_ci	pblk->writer_ts = kthread_create(pblk_write_ts, pblk, "pblk-writer-t");
10758c2ecf20Sopenharmony_ci	if (IS_ERR(pblk->writer_ts)) {
10768c2ecf20Sopenharmony_ci		int err = PTR_ERR(pblk->writer_ts);
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci		if (err != -EINTR)
10798c2ecf20Sopenharmony_ci			pblk_err(pblk, "could not allocate writer kthread (%d)\n",
10808c2ecf20Sopenharmony_ci					err);
10818c2ecf20Sopenharmony_ci		return err;
10828c2ecf20Sopenharmony_ci	}
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	timer_setup(&pblk->wtimer, pblk_write_timer_fn, 0);
10858c2ecf20Sopenharmony_ci	mod_timer(&pblk->wtimer, jiffies + msecs_to_jiffies(100));
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	return 0;
10888c2ecf20Sopenharmony_ci}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_cistatic void pblk_writer_stop(struct pblk *pblk)
10918c2ecf20Sopenharmony_ci{
10928c2ecf20Sopenharmony_ci	/* The pipeline must be stopped and the write buffer emptied before the
10938c2ecf20Sopenharmony_ci	 * write thread is stopped
10948c2ecf20Sopenharmony_ci	 */
10958c2ecf20Sopenharmony_ci	WARN(pblk_rb_read_count(&pblk->rwb),
10968c2ecf20Sopenharmony_ci			"Stopping not fully persisted write buffer\n");
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	WARN(pblk_rb_sync_count(&pblk->rwb),
10998c2ecf20Sopenharmony_ci			"Stopping not fully synced write buffer\n");
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	del_timer_sync(&pblk->wtimer);
11028c2ecf20Sopenharmony_ci	if (pblk->writer_ts)
11038c2ecf20Sopenharmony_ci		kthread_stop(pblk->writer_ts);
11048c2ecf20Sopenharmony_ci}
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_cistatic void pblk_free(struct pblk *pblk)
11078c2ecf20Sopenharmony_ci{
11088c2ecf20Sopenharmony_ci	pblk_lines_free(pblk);
11098c2ecf20Sopenharmony_ci	pblk_l2p_free(pblk);
11108c2ecf20Sopenharmony_ci	pblk_rwb_free(pblk);
11118c2ecf20Sopenharmony_ci	pblk_core_free(pblk);
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	kfree(pblk);
11148c2ecf20Sopenharmony_ci}
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_cistatic void pblk_tear_down(struct pblk *pblk, bool graceful)
11178c2ecf20Sopenharmony_ci{
11188c2ecf20Sopenharmony_ci	if (graceful)
11198c2ecf20Sopenharmony_ci		__pblk_pipeline_flush(pblk);
11208c2ecf20Sopenharmony_ci	__pblk_pipeline_stop(pblk);
11218c2ecf20Sopenharmony_ci	pblk_writer_stop(pblk);
11228c2ecf20Sopenharmony_ci	pblk_rb_sync_l2p(&pblk->rwb);
11238c2ecf20Sopenharmony_ci	pblk_rl_free(&pblk->rl);
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	pblk_debug(pblk, "consistent tear down (graceful:%d)\n", graceful);
11268c2ecf20Sopenharmony_ci}
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_cistatic void pblk_exit(void *private, bool graceful)
11298c2ecf20Sopenharmony_ci{
11308c2ecf20Sopenharmony_ci	struct pblk *pblk = private;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	pblk_gc_exit(pblk, graceful);
11338c2ecf20Sopenharmony_ci	pblk_tear_down(pblk, graceful);
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci#ifdef CONFIG_NVM_PBLK_DEBUG
11368c2ecf20Sopenharmony_ci	pblk_info(pblk, "exit: L2P CRC: %x\n", pblk_l2p_crc(pblk));
11378c2ecf20Sopenharmony_ci#endif
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	pblk_free(pblk);
11408c2ecf20Sopenharmony_ci}
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_cistatic sector_t pblk_capacity(void *private)
11438c2ecf20Sopenharmony_ci{
11448c2ecf20Sopenharmony_ci	struct pblk *pblk = private;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	return pblk->capacity * NR_PHY_IN_LOG;
11478c2ecf20Sopenharmony_ci}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_cistatic void *pblk_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk,
11508c2ecf20Sopenharmony_ci		       int flags)
11518c2ecf20Sopenharmony_ci{
11528c2ecf20Sopenharmony_ci	struct nvm_geo *geo = &dev->geo;
11538c2ecf20Sopenharmony_ci	struct request_queue *bqueue = dev->q;
11548c2ecf20Sopenharmony_ci	struct request_queue *tqueue = tdisk->queue;
11558c2ecf20Sopenharmony_ci	struct pblk *pblk;
11568c2ecf20Sopenharmony_ci	int ret;
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	pblk = kzalloc(sizeof(struct pblk), GFP_KERNEL);
11598c2ecf20Sopenharmony_ci	if (!pblk)
11608c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	pblk->dev = dev;
11638c2ecf20Sopenharmony_ci	pblk->disk = tdisk;
11648c2ecf20Sopenharmony_ci	pblk->state = PBLK_STATE_RUNNING;
11658c2ecf20Sopenharmony_ci	trace_pblk_state(pblk_disk_name(pblk), pblk->state);
11668c2ecf20Sopenharmony_ci	pblk->gc.gc_enabled = 0;
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	if (!(geo->version == NVM_OCSSD_SPEC_12 ||
11698c2ecf20Sopenharmony_ci					geo->version == NVM_OCSSD_SPEC_20)) {
11708c2ecf20Sopenharmony_ci		pblk_err(pblk, "OCSSD version not supported (%u)\n",
11718c2ecf20Sopenharmony_ci							geo->version);
11728c2ecf20Sopenharmony_ci		kfree(pblk);
11738c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
11748c2ecf20Sopenharmony_ci	}
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	if (geo->ext) {
11778c2ecf20Sopenharmony_ci		pblk_err(pblk, "extended metadata not supported\n");
11788c2ecf20Sopenharmony_ci		kfree(pblk);
11798c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
11808c2ecf20Sopenharmony_ci	}
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	spin_lock_init(&pblk->resubmit_lock);
11838c2ecf20Sopenharmony_ci	spin_lock_init(&pblk->trans_lock);
11848c2ecf20Sopenharmony_ci	spin_lock_init(&pblk->lock);
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci#ifdef CONFIG_NVM_PBLK_DEBUG
11878c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->inflight_writes, 0);
11888c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->padded_writes, 0);
11898c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->padded_wb, 0);
11908c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->req_writes, 0);
11918c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->sub_writes, 0);
11928c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->sync_writes, 0);
11938c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->inflight_reads, 0);
11948c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->cache_reads, 0);
11958c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->sync_reads, 0);
11968c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->recov_writes, 0);
11978c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->recov_writes, 0);
11988c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->recov_gc_writes, 0);
11998c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->recov_gc_reads, 0);
12008c2ecf20Sopenharmony_ci#endif
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->read_failed, 0);
12038c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->read_empty, 0);
12048c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->read_high_ecc, 0);
12058c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->read_failed_gc, 0);
12068c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->write_failed, 0);
12078c2ecf20Sopenharmony_ci	atomic_long_set(&pblk->erase_failed, 0);
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	ret = pblk_core_init(pblk);
12108c2ecf20Sopenharmony_ci	if (ret) {
12118c2ecf20Sopenharmony_ci		pblk_err(pblk, "could not initialize core\n");
12128c2ecf20Sopenharmony_ci		goto fail;
12138c2ecf20Sopenharmony_ci	}
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	ret = pblk_lines_init(pblk);
12168c2ecf20Sopenharmony_ci	if (ret) {
12178c2ecf20Sopenharmony_ci		pblk_err(pblk, "could not initialize lines\n");
12188c2ecf20Sopenharmony_ci		goto fail_free_core;
12198c2ecf20Sopenharmony_ci	}
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	ret = pblk_rwb_init(pblk);
12228c2ecf20Sopenharmony_ci	if (ret) {
12238c2ecf20Sopenharmony_ci		pblk_err(pblk, "could not initialize write buffer\n");
12248c2ecf20Sopenharmony_ci		goto fail_free_lines;
12258c2ecf20Sopenharmony_ci	}
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	ret = pblk_l2p_init(pblk, flags & NVM_TARGET_FACTORY);
12288c2ecf20Sopenharmony_ci	if (ret) {
12298c2ecf20Sopenharmony_ci		pblk_err(pblk, "could not initialize maps\n");
12308c2ecf20Sopenharmony_ci		goto fail_free_rwb;
12318c2ecf20Sopenharmony_ci	}
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	ret = pblk_writer_init(pblk);
12348c2ecf20Sopenharmony_ci	if (ret) {
12358c2ecf20Sopenharmony_ci		if (ret != -EINTR)
12368c2ecf20Sopenharmony_ci			pblk_err(pblk, "could not initialize write thread\n");
12378c2ecf20Sopenharmony_ci		goto fail_free_l2p;
12388c2ecf20Sopenharmony_ci	}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	ret = pblk_gc_init(pblk);
12418c2ecf20Sopenharmony_ci	if (ret) {
12428c2ecf20Sopenharmony_ci		pblk_err(pblk, "could not initialize gc\n");
12438c2ecf20Sopenharmony_ci		goto fail_stop_writer;
12448c2ecf20Sopenharmony_ci	}
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	/* inherit the size from the underlying device */
12478c2ecf20Sopenharmony_ci	blk_queue_logical_block_size(tqueue, queue_physical_block_size(bqueue));
12488c2ecf20Sopenharmony_ci	blk_queue_max_hw_sectors(tqueue, queue_max_hw_sectors(bqueue));
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	blk_queue_write_cache(tqueue, true, false);
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	tqueue->limits.discard_granularity = geo->clba * geo->csecs;
12538c2ecf20Sopenharmony_ci	tqueue->limits.discard_alignment = 0;
12548c2ecf20Sopenharmony_ci	blk_queue_max_discard_sectors(tqueue, UINT_MAX >> 9);
12558c2ecf20Sopenharmony_ci	blk_queue_flag_set(QUEUE_FLAG_DISCARD, tqueue);
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	pblk_info(pblk, "luns:%u, lines:%d, secs:%llu, buf entries:%u\n",
12588c2ecf20Sopenharmony_ci			geo->all_luns, pblk->l_mg.nr_lines,
12598c2ecf20Sopenharmony_ci			(unsigned long long)pblk->capacity,
12608c2ecf20Sopenharmony_ci			pblk->rwb.nr_entries);
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	wake_up_process(pblk->writer_ts);
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	/* Check if we need to start GC */
12658c2ecf20Sopenharmony_ci	pblk_gc_should_kick(pblk);
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci	return pblk;
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_cifail_stop_writer:
12708c2ecf20Sopenharmony_ci	pblk_writer_stop(pblk);
12718c2ecf20Sopenharmony_cifail_free_l2p:
12728c2ecf20Sopenharmony_ci	pblk_l2p_free(pblk);
12738c2ecf20Sopenharmony_cifail_free_rwb:
12748c2ecf20Sopenharmony_ci	pblk_rwb_free(pblk);
12758c2ecf20Sopenharmony_cifail_free_lines:
12768c2ecf20Sopenharmony_ci	pblk_lines_free(pblk);
12778c2ecf20Sopenharmony_cifail_free_core:
12788c2ecf20Sopenharmony_ci	pblk_core_free(pblk);
12798c2ecf20Sopenharmony_cifail:
12808c2ecf20Sopenharmony_ci	kfree(pblk);
12818c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
12828c2ecf20Sopenharmony_ci}
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci/* physical block device target */
12858c2ecf20Sopenharmony_cistatic struct nvm_tgt_type tt_pblk = {
12868c2ecf20Sopenharmony_ci	.name		= "pblk",
12878c2ecf20Sopenharmony_ci	.version	= {1, 0, 0},
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	.bops		= &pblk_bops,
12908c2ecf20Sopenharmony_ci	.capacity	= pblk_capacity,
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	.init		= pblk_init,
12938c2ecf20Sopenharmony_ci	.exit		= pblk_exit,
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	.sysfs_init	= pblk_sysfs_init,
12968c2ecf20Sopenharmony_ci	.sysfs_exit	= pblk_sysfs_exit,
12978c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
12988c2ecf20Sopenharmony_ci};
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_cistatic int __init pblk_module_init(void)
13018c2ecf20Sopenharmony_ci{
13028c2ecf20Sopenharmony_ci	int ret;
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	ret = bioset_init(&pblk_bio_set, BIO_POOL_SIZE, 0, 0);
13058c2ecf20Sopenharmony_ci	if (ret)
13068c2ecf20Sopenharmony_ci		return ret;
13078c2ecf20Sopenharmony_ci	ret = nvm_register_tgt_type(&tt_pblk);
13088c2ecf20Sopenharmony_ci	if (ret)
13098c2ecf20Sopenharmony_ci		bioset_exit(&pblk_bio_set);
13108c2ecf20Sopenharmony_ci	return ret;
13118c2ecf20Sopenharmony_ci}
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_cistatic void pblk_module_exit(void)
13148c2ecf20Sopenharmony_ci{
13158c2ecf20Sopenharmony_ci	bioset_exit(&pblk_bio_set);
13168c2ecf20Sopenharmony_ci	nvm_unregister_tgt_type(&tt_pblk);
13178c2ecf20Sopenharmony_ci}
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_cimodule_init(pblk_module_init);
13208c2ecf20Sopenharmony_cimodule_exit(pblk_module_exit);
13218c2ecf20Sopenharmony_ciMODULE_AUTHOR("Javier Gonzalez <javier@cnexlabs.com>");
13228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Matias Bjorling <matias@cnexlabs.com>");
13238c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
13248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Physical Block-Device for Open-Channel SSDs");
1325