xref: /spdk/lib/ftl/base/ftl_base_bdev.c (revision 98eca6fa083aaf48dc253cd326ac15e635bc4141)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright 2023 Solidigm All Rights Reserved
3  */
4 
5 #include "ftl_base_dev.h"
6 #include "ftl_core.h"
7 #include "ftl_layout.h"
8 #include "ftl_band.h"
9 #include "utils/ftl_layout_tracker_bdev.h"
10 
11 static bool
12 is_bdev_compatible(struct spdk_ftl_dev *dev, struct spdk_bdev *bdev)
13 {
14 	uint64_t write_unit_size = spdk_bdev_get_write_unit_size(bdev);
15 
16 	if (spdk_bdev_get_block_size(bdev) != FTL_BLOCK_SIZE) {
17 		FTL_ERRLOG(dev, "Unsupported block size, only 4096 is supprted.\nn");
18 		return false;
19 	}
20 
21 	if (spdk_bdev_get_md_size(bdev) != 0) {
22 		/* Bdev's metadata is unsupported */
23 		FTL_ERRLOG(dev, "Unsupported metadata size, sector metadata isn't supported.\n");
24 		return false;
25 	}
26 
27 	if (write_unit_size == 1) {
28 		/* No write unit size, all alignments will work out fine */
29 		return true;
30 	}
31 
32 	if (!spdk_u32_is_pow2(write_unit_size) || write_unit_size > (MiB / FTL_BLOCK_SIZE)) {
33 		/* Needs to be a power of 2 for current band size (1GiB) restrictions.
34 		 * Current buffers are allocated in 1MiB sizes (256 blocks), so it can't be larger than that.
35 		 * In the future, if the restriction is relaxed, the ftl_bitmap_buffer_alignment (64 blocks)
36 		 * will need to be taken into consideration as well.
37 		 */
38 		FTL_ERRLOG(dev,
39 			   "Unsupported write unit size (%lu), must be a power of 2 (in blocks). Can't be larger than 256 (1MiB)\n",
40 			   write_unit_size);
41 		return false;
42 	}
43 
44 	return true;
45 }
46 
47 static void
48 md_region_setup(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
49 		struct ftl_layout_region *region)
50 {
51 	assert(region);
52 	region->type = reg_type;
53 	region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
54 	region->name = ftl_md_region_name(reg_type);
55 
56 	region->bdev_desc = dev->base_bdev_desc;
57 	region->ioch = dev->base_ioch;
58 	region->vss_blksz = 0;
59 }
60 
61 static int
62 md_region_create(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
63 		 uint32_t reg_version, size_t reg_blks)
64 {
65 	const struct ftl_layout_tracker_bdev_region_props *reg_props;
66 	uint64_t data_base_alignment;
67 
68 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
69 	reg_blks = ftl_md_region_align_blocks(dev, reg_blks);
70 
71 	/* Allocating a ftl_bitmap requires a 8B input buffer alignment, since we're reusing the global valid map md buffer
72 	 * this means that each band starting address needs to be aligned too - each device sector takes 1b in the valid map,
73 	 * so 64 sectors (8*8) is the needed alignment
74 	 */
75 	data_base_alignment = 8 * ftl_bitmap_buffer_alignment;
76 	reg_props = ftl_layout_tracker_bdev_add_region(dev->base_layout_tracker, reg_type, reg_version,
77 			reg_blks, data_base_alignment);
78 	if (!reg_props) {
79 		return -1;
80 	}
81 	assert(reg_props->type == reg_type);
82 	assert(reg_props->ver == reg_version);
83 	assert(reg_props->blk_sz == reg_blks);
84 	assert(reg_props->blk_offs + reg_blks <= dev->layout.base.total_blocks);
85 	return 0;
86 }
87 
88 static int
89 md_region_open(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, uint32_t reg_version,
90 	       size_t entry_size, size_t entry_count, struct ftl_layout_region *region)
91 {
92 	const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
93 	uint64_t reg_blks = ftl_md_region_blocks(dev, entry_size * entry_count);
94 
95 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
96 
97 	while (true) {
98 		ftl_layout_tracker_bdev_find_next_region(dev->base_layout_tracker, reg_type, &reg_search_ctx);
99 		if (!reg_search_ctx || reg_search_ctx->ver == reg_version) {
100 			break;
101 		}
102 	}
103 
104 	if (!reg_search_ctx || reg_search_ctx->blk_sz < reg_blks) {
105 		/* Region not found or insufficient space */
106 		return -1;
107 	}
108 
109 	if (!region) {
110 		return 0;
111 	}
112 
113 	md_region_setup(dev, reg_type, region);
114 
115 	region->entry_size = entry_size / FTL_BLOCK_SIZE;
116 	region->num_entries = entry_count;
117 
118 	region->current.version = reg_version;
119 	region->current.offset = reg_search_ctx->blk_offs;
120 	region->current.blocks = reg_search_ctx->blk_sz;
121 
122 	return 0;
123 }
124 
125 struct ftl_base_device_type base_bdev = {
126 	.name = "base_bdev",
127 	.ops = {
128 		.is_bdev_compatible = is_bdev_compatible,
129 
130 		.md_layout_ops = {
131 			.region_create = md_region_create,
132 			.region_open = md_region_open,
133 		},
134 	}
135 };
136 FTL_BASE_DEVICE_TYPE_REGISTER(base_bdev)
137