xref: /spdk/lib/ftl/mngt/ftl_mngt_bdev.c (revision fa09c9ac9b0ce66dcacb64b02aae778014b6c2b3)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/bdev_module.h"
7 #include "spdk/ftl.h"
8 
9 #include "ftl_internal.h"
10 #include "ftl_mngt_steps.h"
11 #include "ftl_internal.h"
12 #include "ftl_core.h"
13 #include "utils/ftl_defs.h"
14 
15 #define MINIMUM_CACHE_SIZE_GIB 5
16 #define MINIMUM_BASE_SIZE_GIB 20
17 
18 /*  Dummy bdev module used to to claim bdevs. */
19 static struct spdk_bdev_module g_ftl_bdev_module = {
20 	.name   = "ftl_lib",
21 };
22 
23 static inline size_t
24 ftl_calculate_num_zones_in_band(struct spdk_bdev_desc *desc)
25 {
26 	if (spdk_bdev_is_zoned(spdk_bdev_desc_get_bdev(desc))) {
27 		return spdk_bdev_get_optimal_open_zones(spdk_bdev_desc_get_bdev(desc));
28 	}
29 
30 	return 1;
31 }
32 
33 static inline size_t
34 ftl_calculate_num_blocks_in_zone(struct spdk_bdev_desc *desc)
35 {
36 	if (spdk_bdev_is_zoned(spdk_bdev_desc_get_bdev(desc))) {
37 		return spdk_bdev_get_zone_size(spdk_bdev_desc_get_bdev(desc));
38 	}
39 
40 	/* TODO: this should be passed via input parameter */
41 #ifdef SPDK_FTL_ZONE_EMU_BLOCKS
42 	return SPDK_FTL_ZONE_EMU_BLOCKS;
43 #else
44 	return (1ULL << 30) / FTL_BLOCK_SIZE;
45 #endif
46 }
47 
48 static inline uint64_t
49 ftl_calculate_num_blocks_in_band(struct spdk_bdev_desc *desc)
50 {
51 	return ftl_calculate_num_zones_in_band(desc) * ftl_calculate_num_blocks_in_zone(desc);
52 }
53 
54 static void
55 base_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
56 {
57 	switch (type) {
58 	case SPDK_BDEV_EVENT_REMOVE:
59 		assert(0);
60 		break;
61 	default:
62 		break;
63 	}
64 }
65 
66 void
67 ftl_mngt_open_base_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
68 {
69 	uint32_t block_size;
70 	uint64_t num_blocks;
71 	const char *bdev_name = dev->conf.base_bdev;
72 	struct spdk_bdev *bdev;
73 
74 	if (spdk_bdev_open_ext(bdev_name, true, base_bdev_event_cb,
75 			       dev, &dev->base_bdev_desc)) {
76 		FTL_ERRLOG(dev, "Unable to open bdev: %s\n", bdev_name);
77 		goto error;
78 	}
79 
80 	bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
81 
82 	if (spdk_bdev_module_claim_bdev(bdev, dev->base_bdev_desc, &g_ftl_bdev_module)) {
83 		/* clear the desc so that we don't try to release the claim on cleanup */
84 		spdk_bdev_close(dev->base_bdev_desc);
85 		dev->base_bdev_desc = NULL;
86 		FTL_ERRLOG(dev, "Unable to claim bdev %s\n", bdev_name);
87 		goto error;
88 	}
89 
90 	block_size = spdk_bdev_get_block_size(bdev);
91 	if (block_size != FTL_BLOCK_SIZE) {
92 		FTL_ERRLOG(dev, "Unsupported block size (%"PRIu32")\n", block_size);
93 		goto error;
94 	}
95 
96 	num_blocks = spdk_bdev_get_num_blocks(bdev);
97 
98 	if (num_blocks * block_size < MINIMUM_BASE_SIZE_GIB * GiB) {
99 		FTL_ERRLOG(dev, "Bdev %s is too small, requires, at least %uGiB capacity\n",
100 			   spdk_bdev_get_name(bdev), MINIMUM_BASE_SIZE_GIB);
101 		goto error;
102 	}
103 
104 	dev->base_ioch = spdk_bdev_get_io_channel(dev->base_bdev_desc);
105 	if (!dev->base_ioch) {
106 		FTL_ERRLOG(dev, "Failed to create base bdev IO channel\n");
107 		goto error;
108 	}
109 
110 	dev->xfer_size = ftl_get_write_unit_size(bdev);
111 
112 	/* TODO: validate size when base device VSS usage gets added */
113 	dev->md_size = spdk_bdev_get_md_size(bdev);
114 
115 	/* Cache frequently used values */
116 	dev->num_blocks_in_band = ftl_calculate_num_blocks_in_band(dev->base_bdev_desc);
117 	dev->num_zones_in_band = ftl_calculate_num_zones_in_band(dev->base_bdev_desc);
118 	dev->num_blocks_in_zone = ftl_calculate_num_blocks_in_zone(dev->base_bdev_desc);
119 	dev->is_zoned = spdk_bdev_is_zoned(spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
120 
121 	if (dev->is_zoned) {
122 		/* TODO - current FTL code isn't fully compatible with ZNS drives */
123 		FTL_ERRLOG(dev, "Creating FTL on Zoned devices is not supported\n");
124 		goto error;
125 	}
126 
127 	dev->num_bands = num_blocks / ftl_get_num_blocks_in_band(dev);
128 
129 	/* Save a band worth of space for metadata */
130 	dev->num_bands--;
131 
132 	ftl_mngt_next_step(mngt);
133 	return;
134 error:
135 	ftl_mngt_fail_step(mngt);
136 }
137 
138 void
139 ftl_mngt_close_base_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
140 {
141 	if (dev->base_ioch) {
142 		spdk_put_io_channel(dev->base_ioch);
143 		dev->base_ioch = NULL;
144 	}
145 
146 	if (dev->base_bdev_desc) {
147 		struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
148 
149 		spdk_bdev_module_release_bdev(bdev);
150 		spdk_bdev_close(dev->base_bdev_desc);
151 
152 		dev->base_bdev_desc = NULL;
153 	}
154 
155 	ftl_mngt_next_step(mngt);
156 }
157 
158 static void
159 nv_cache_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
160 {
161 	switch (type) {
162 	case SPDK_BDEV_EVENT_REMOVE:
163 		assert(0);
164 		break;
165 	default:
166 		break;
167 	}
168 }
169 
170 void
171 ftl_mngt_open_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
172 {
173 	struct spdk_bdev *bdev;
174 	const char *bdev_name = dev->conf.cache_bdev;
175 
176 	if (spdk_bdev_open_ext(bdev_name, true, nv_cache_bdev_event_cb, dev,
177 			       &dev->cache_bdev_desc)) {
178 		FTL_ERRLOG(dev, "Unable to open bdev: %s\n", bdev_name);
179 		goto error;
180 	}
181 
182 	bdev = spdk_bdev_desc_get_bdev(dev->cache_bdev_desc);
183 
184 	if (spdk_bdev_module_claim_bdev(bdev, dev->cache_bdev_desc, &g_ftl_bdev_module)) {
185 		/* clear the desc so that we don't try to release the claim on cleanup */
186 		spdk_bdev_close(dev->cache_bdev_desc);
187 		dev->cache_bdev_desc = NULL;
188 		FTL_ERRLOG(dev, "Unable to claim bdev %s\n", bdev_name);
189 		goto error;
190 	}
191 
192 	FTL_NOTICELOG(dev, "Using %s as write buffer cache\n", spdk_bdev_get_name(bdev));
193 
194 	if (spdk_bdev_get_block_size(bdev) != FTL_BLOCK_SIZE) {
195 		FTL_ERRLOG(dev, "Unsupported block size (%d)\n",
196 			   spdk_bdev_get_block_size(bdev));
197 		goto error;
198 	}
199 
200 	dev->cache_ioch = spdk_bdev_get_io_channel(dev->cache_bdev_desc);
201 	if (!dev->cache_ioch) {
202 		FTL_ERRLOG(dev, "Failed to create cache IO channel for NV Cache\n");
203 		goto error;
204 	}
205 
206 #ifndef SPDK_FTL_VSS_EMU
207 	if (!spdk_bdev_is_md_separate(bdev)) {
208 		FTL_ERRLOG(dev, "Bdev %s doesn't support separate metadata buffer IO\n",
209 			   spdk_bdev_get_name(bdev));
210 		goto error;
211 	}
212 
213 	dev->cache_md_size = spdk_bdev_get_md_size(bdev);
214 	if (dev->cache_md_size != sizeof(union ftl_md_vss)) {
215 		FTL_ERRLOG(dev, "Bdev's %s metadata is invalid size (%"PRIu32")\n",
216 			   spdk_bdev_get_name(bdev), spdk_bdev_get_md_size(bdev));
217 		goto error;
218 	}
219 
220 	if (spdk_bdev_get_dif_type(bdev) != SPDK_DIF_DISABLE) {
221 		FTL_ERRLOG(dev, "Unsupported DIF type used by bdev %s\n",
222 			   spdk_bdev_get_name(bdev));
223 		goto error;
224 	}
225 
226 	if (bdev->blockcnt * bdev->blocklen < MINIMUM_CACHE_SIZE_GIB * GiB) {
227 		FTL_ERRLOG(dev, "Bdev %s is too small, requires, at least %uGiB capacity\n",
228 			   spdk_bdev_get_name(bdev), MINIMUM_CACHE_SIZE_GIB);
229 		goto error;
230 	}
231 
232 	if (ftl_md_xfer_blocks(dev) * dev->cache_md_size > FTL_ZERO_BUFFER_SIZE) {
233 		FTL_ERRLOG(dev, "Zero buffer too small for bdev %s metadata transfer\n",
234 			   spdk_bdev_get_name(bdev));
235 		goto error;
236 	}
237 #else
238 	if (spdk_bdev_is_md_separate(bdev)) {
239 		FTL_ERRLOG(dev, "FTL VSS emulation but NV cache supports VSS\n");
240 		goto error;
241 	}
242 
243 	dev->cache_md_size = 64;
244 	FTL_NOTICELOG(dev, "FTL uses VSS emulation\n");
245 #endif
246 
247 	ftl_mngt_next_step(mngt);
248 	return;
249 error:
250 	ftl_mngt_fail_step(mngt);
251 }
252 
253 void
254 ftl_mngt_close_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
255 {
256 	if (dev->cache_ioch) {
257 		spdk_put_io_channel(dev->cache_ioch);
258 		dev->cache_ioch = NULL;
259 	}
260 
261 	if (dev->cache_bdev_desc) {
262 		struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->cache_bdev_desc);
263 
264 		spdk_bdev_module_release_bdev(bdev);
265 		spdk_bdev_close(dev->cache_bdev_desc);
266 
267 		dev->cache_bdev_desc = NULL;
268 	}
269 
270 	ftl_mngt_next_step(mngt);
271 }
272