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