xref: /spdk/lib/ftl/base/ftl_base_bdev.c (revision cec5ba284b55d19c90359936d77b707e398829f7)
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