xref: /spdk/lib/ftl/base/ftl_base_bdev.c (revision e56f1618f346c3e5894207ab4da401c8a36e200b)
1498c39beSLukasz Lasek /*   SPDX-License-Identifier: BSD-3-Clause
2498c39beSLukasz Lasek  *   Copyright 2023 Solidigm All Rights Reserved
3498c39beSLukasz Lasek  */
4498c39beSLukasz Lasek 
5498c39beSLukasz Lasek #include "ftl_base_dev.h"
6498c39beSLukasz Lasek #include "ftl_core.h"
7498c39beSLukasz Lasek #include "ftl_layout.h"
89f42898aSLukasz Lasek #include "ftl_band.h"
993036282SLukasz Lasek #include "utils/ftl_layout_tracker_bdev.h"
10498c39beSLukasz Lasek 
11498c39beSLukasz Lasek static bool
12498c39beSLukasz Lasek is_bdev_compatible(struct spdk_ftl_dev *dev, struct spdk_bdev *bdev)
13498c39beSLukasz Lasek {
14*e56f1618SMateusz Kozlowski 	uint64_t write_unit_size = spdk_bdev_get_write_unit_size(bdev);
15*e56f1618SMateusz Kozlowski 
16*e56f1618SMateusz Kozlowski 	if (spdk_bdev_get_block_size(bdev) != FTL_BLOCK_SIZE) {
17*e56f1618SMateusz Kozlowski 		FTL_ERRLOG(dev, "Unsupported block size, only 4096 is supprted.\nn");
18*e56f1618SMateusz Kozlowski 		return false;
19*e56f1618SMateusz Kozlowski 	}
20*e56f1618SMateusz Kozlowski 
21*e56f1618SMateusz Kozlowski 	if (spdk_bdev_get_md_size(bdev) != 0) {
22*e56f1618SMateusz Kozlowski 		/* Bdev's metadata is unsupported */
23*e56f1618SMateusz Kozlowski 		FTL_ERRLOG(dev, "Unsupported metadata size, sector metadata isn't supported.\n");
24*e56f1618SMateusz Kozlowski 		return false;
25*e56f1618SMateusz Kozlowski 	}
26*e56f1618SMateusz Kozlowski 
27*e56f1618SMateusz Kozlowski 	if (write_unit_size == 1) {
28*e56f1618SMateusz Kozlowski 		/* No write unit size, all alignments will work out fine */
29*e56f1618SMateusz Kozlowski 		return true;
30*e56f1618SMateusz Kozlowski 	}
31*e56f1618SMateusz Kozlowski 
32*e56f1618SMateusz Kozlowski 	if (!spdk_u32_is_pow2(write_unit_size) || write_unit_size > (MiB / FTL_BLOCK_SIZE)) {
33*e56f1618SMateusz Kozlowski 		/* Needs to be a power of 2 for current band size (1GiB) restrictions.
34*e56f1618SMateusz Kozlowski 		 * Current buffers are allocated in 1MiB sizes (256 blocks), so it can't be larger than that.
35*e56f1618SMateusz Kozlowski 		 * In the future, if the restriction is relaxed, the ftl_bitmap_buffer_alignment (64 blocks)
36*e56f1618SMateusz Kozlowski 		 * will need to be taken into consideration as well.
37*e56f1618SMateusz Kozlowski 		 */
38*e56f1618SMateusz Kozlowski 		FTL_ERRLOG(dev,
39*e56f1618SMateusz Kozlowski 			   "Unsupported write unit size (%lu), must be a power of 2 (in blocks). Can't be larger than 256 (1MiB)\n",
40*e56f1618SMateusz Kozlowski 			   write_unit_size);
41*e56f1618SMateusz Kozlowski 		return false;
42*e56f1618SMateusz Kozlowski 	}
43*e56f1618SMateusz Kozlowski 
44*e56f1618SMateusz Kozlowski 	return true;
45498c39beSLukasz Lasek }
46498c39beSLukasz Lasek 
47424a88a4SMateusz Kozlowski static void
48424a88a4SMateusz Kozlowski md_region_setup(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
49424a88a4SMateusz Kozlowski 		struct ftl_layout_region *region)
50424a88a4SMateusz Kozlowski {
51424a88a4SMateusz Kozlowski 	assert(region);
52424a88a4SMateusz Kozlowski 	region->type = reg_type;
53424a88a4SMateusz Kozlowski 	region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
54424a88a4SMateusz Kozlowski 	region->name = ftl_md_region_name(reg_type);
55424a88a4SMateusz Kozlowski 
56424a88a4SMateusz Kozlowski 	region->bdev_desc = dev->base_bdev_desc;
57424a88a4SMateusz Kozlowski 	region->ioch = dev->base_ioch;
58424a88a4SMateusz Kozlowski 	region->vss_blksz = 0;
59424a88a4SMateusz Kozlowski }
60424a88a4SMateusz Kozlowski 
619f42898aSLukasz Lasek static int
62498c39beSLukasz Lasek md_region_create(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
639f42898aSLukasz Lasek 		 uint32_t reg_version, size_t reg_blks)
64498c39beSLukasz Lasek {
6593036282SLukasz Lasek 	const struct ftl_layout_tracker_bdev_region_props *reg_props;
669f42898aSLukasz Lasek 	uint64_t data_base_alignment;
67498c39beSLukasz Lasek 
68498c39beSLukasz Lasek 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
699f42898aSLukasz Lasek 	reg_blks = ftl_md_region_align_blocks(dev, reg_blks);
70498c39beSLukasz Lasek 
71498c39beSLukasz Lasek 	/* Allocating a ftl_bitmap requires a 8B input buffer alignment, since we're reusing the global valid map md buffer
72498c39beSLukasz Lasek 	 * this means that each band starting address needs to be aligned too - each device sector takes 1b in the valid map,
73498c39beSLukasz Lasek 	 * so 64 sectors (8*8) is the needed alignment
74498c39beSLukasz Lasek 	 */
7593036282SLukasz Lasek 	data_base_alignment = 8 * ftl_bitmap_buffer_alignment;
7693036282SLukasz Lasek 	reg_props = ftl_layout_tracker_bdev_add_region(dev->base_layout_tracker, reg_type, reg_version,
7793036282SLukasz Lasek 			reg_blks, data_base_alignment);
7893036282SLukasz Lasek 	if (!reg_props) {
799f42898aSLukasz Lasek 		return -1;
8093036282SLukasz Lasek 	}
8193036282SLukasz Lasek 	assert(reg_props->type == reg_type);
8293036282SLukasz Lasek 	assert(reg_props->ver == reg_version);
8393036282SLukasz Lasek 	assert(reg_props->blk_sz == reg_blks);
8493036282SLukasz Lasek 	assert(reg_props->blk_offs + reg_blks <= dev->layout.base.total_blocks);
859f42898aSLukasz Lasek 	return 0;
869f42898aSLukasz Lasek }
87498c39beSLukasz Lasek 
889f42898aSLukasz Lasek static int
899f42898aSLukasz Lasek md_region_open(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, uint32_t reg_version,
909f42898aSLukasz Lasek 	       size_t entry_size, size_t entry_count, struct ftl_layout_region *region)
919f42898aSLukasz Lasek {
929f42898aSLukasz Lasek 	const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
939f42898aSLukasz Lasek 	uint64_t reg_blks = ftl_md_region_blocks(dev, entry_size * entry_count);
949f42898aSLukasz Lasek 
959f42898aSLukasz Lasek 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
969f42898aSLukasz Lasek 
979f42898aSLukasz Lasek 	while (true) {
989f42898aSLukasz Lasek 		ftl_layout_tracker_bdev_find_next_region(dev->base_layout_tracker, reg_type, &reg_search_ctx);
999f42898aSLukasz Lasek 		if (!reg_search_ctx || reg_search_ctx->ver == reg_version) {
1009f42898aSLukasz Lasek 			break;
1019f42898aSLukasz Lasek 		}
1029f42898aSLukasz Lasek 	}
1039f42898aSLukasz Lasek 
1049f42898aSLukasz Lasek 	if (!reg_search_ctx || reg_search_ctx->blk_sz < reg_blks) {
1059f42898aSLukasz Lasek 		/* Region not found or insufficient space */
1069f42898aSLukasz Lasek 		return -1;
1079f42898aSLukasz Lasek 	}
1089f42898aSLukasz Lasek 
1099f42898aSLukasz Lasek 	if (!region) {
1109f42898aSLukasz Lasek 		return 0;
1119f42898aSLukasz Lasek 	}
1129f42898aSLukasz Lasek 
113424a88a4SMateusz Kozlowski 	md_region_setup(dev, reg_type, region);
114424a88a4SMateusz Kozlowski 
115498c39beSLukasz Lasek 	region->entry_size = entry_size / FTL_BLOCK_SIZE;
116498c39beSLukasz Lasek 	region->num_entries = entry_count;
117498c39beSLukasz Lasek 
1188fc78fd8SMateusz Kozlowski 	region->current.version = reg_version;
1199f42898aSLukasz Lasek 	region->current.offset = reg_search_ctx->blk_offs;
1209f42898aSLukasz Lasek 	region->current.blocks = reg_search_ctx->blk_sz;
1219f42898aSLukasz Lasek 
1229f42898aSLukasz Lasek 	return 0;
123498c39beSLukasz Lasek }
124498c39beSLukasz Lasek 
125498c39beSLukasz Lasek struct ftl_base_device_type base_bdev = {
126498c39beSLukasz Lasek 	.name = "base_bdev",
127498c39beSLukasz Lasek 	.ops = {
128498c39beSLukasz Lasek 		.is_bdev_compatible = is_bdev_compatible,
1299f42898aSLukasz Lasek 
130498c39beSLukasz Lasek 		.md_layout_ops = {
131498c39beSLukasz Lasek 			.region_create = md_region_create,
1329f42898aSLukasz Lasek 			.region_open = md_region_open,
133498c39beSLukasz Lasek 		},
134498c39beSLukasz Lasek 	}
135498c39beSLukasz Lasek };
136498c39beSLukasz Lasek FTL_BASE_DEVICE_TYPE_REGISTER(base_bdev)
137