xref: /spdk/lib/ftl/mngt/ftl_mngt_bdev.c (revision b02581a89058ebaebe03bd0e16e3b58adfe406c1)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright 2023 Solidigm All Rights Reserved
3  *   Copyright (C) 2022 Intel Corporation.
4  *   All rights reserved.
5  */
6 
7 #include "spdk/bdev_module.h"
8 #include "spdk/ftl.h"
9 
10 #include "ftl_nv_cache.h"
11 #include "ftl_internal.h"
12 #include "ftl_mngt_steps.h"
13 #include "ftl_core.h"
14 #include "utils/ftl_defs.h"
15 #include "utils/ftl_layout_tracker_bdev.h"
16 
17 #define MINIMUM_CACHE_SIZE_GIB 5
18 #define MINIMUM_BASE_SIZE_GIB 20
19 
20 /*  Dummy bdev module used to to claim bdevs. */
21 static struct spdk_bdev_module g_ftl_bdev_module = {
22 	.name   = "ftl_lib",
23 };
24 
25 static inline uint64_t
26 ftl_calculate_num_blocks_in_band(struct spdk_bdev_desc *desc)
27 {
28 	/* TODO: this should be passed via input parameter */
29 #ifdef SPDK_FTL_ZONE_EMU_BLOCKS
30 	return SPDK_FTL_ZONE_EMU_BLOCKS;
31 #else
32 	return (1ULL << 30) / FTL_BLOCK_SIZE;
33 #endif
34 }
35 
36 static void
37 base_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
38 {
39 	switch (type) {
40 	case SPDK_BDEV_EVENT_REMOVE:
41 		assert(0);
42 		break;
43 	default:
44 		break;
45 	}
46 }
47 
48 void
49 ftl_mngt_open_base_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
50 {
51 	uint32_t block_size;
52 	uint64_t num_blocks;
53 	const char *bdev_name = dev->conf.base_bdev;
54 	struct spdk_bdev *bdev;
55 
56 	if (spdk_bdev_open_ext(bdev_name, true, base_bdev_event_cb,
57 			       dev, &dev->base_bdev_desc)) {
58 		FTL_ERRLOG(dev, "Unable to open bdev: %s\n", bdev_name);
59 		goto error;
60 	}
61 
62 	bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
63 
64 	if (spdk_bdev_module_claim_bdev(bdev, dev->base_bdev_desc, &g_ftl_bdev_module)) {
65 		/* clear the desc so that we don't try to release the claim on cleanup */
66 		spdk_bdev_close(dev->base_bdev_desc);
67 		dev->base_bdev_desc = NULL;
68 		FTL_ERRLOG(dev, "Unable to claim bdev %s\n", bdev_name);
69 		goto error;
70 	}
71 
72 	block_size = spdk_bdev_get_block_size(bdev);
73 	if (block_size != FTL_BLOCK_SIZE) {
74 		FTL_ERRLOG(dev, "Unsupported block size (%"PRIu32")\n", block_size);
75 		goto error;
76 	}
77 
78 	num_blocks = spdk_bdev_get_num_blocks(bdev);
79 
80 	if (num_blocks * block_size < MINIMUM_BASE_SIZE_GIB * GiB) {
81 		FTL_ERRLOG(dev, "Bdev %s is too small, requires, at least %uGiB capacity\n",
82 			   spdk_bdev_get_name(bdev), MINIMUM_BASE_SIZE_GIB);
83 		goto error;
84 	}
85 
86 	dev->base_ioch = spdk_bdev_get_io_channel(dev->base_bdev_desc);
87 	if (!dev->base_ioch) {
88 		FTL_ERRLOG(dev, "Failed to create base bdev IO channel\n");
89 		goto error;
90 	}
91 
92 	dev->xfer_size = ftl_get_write_unit_size(bdev);
93 	if (dev->xfer_size != FTL_NUM_LBA_IN_BLOCK) {
94 		FTL_ERRLOG(dev, "Unsupported xfer_size (%"PRIu64")\n", dev->xfer_size);
95 		goto error;
96 	}
97 
98 	dev->base_type = ftl_base_device_get_type_by_bdev(dev, bdev);
99 	if (!dev->base_type) {
100 		FTL_ERRLOG(dev, "Failed to get base device type\n");
101 		goto error;
102 	}
103 	/* TODO: validate size when base device VSS usage gets added */
104 	dev->md_size = spdk_bdev_get_md_size(bdev);
105 
106 	if (!dev->base_type->ops.md_layout_ops.region_create) {
107 		FTL_ERRLOG(dev, "Base device doesn't implement md_layout_ops\n");
108 		goto error;
109 	}
110 
111 	/* Cache frequently used values */
112 	dev->num_blocks_in_band = ftl_calculate_num_blocks_in_band(dev->base_bdev_desc);
113 	dev->is_zoned = spdk_bdev_is_zoned(spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
114 
115 	if (dev->is_zoned) {
116 		/* TODO - current FTL code isn't fully compatible with ZNS drives */
117 		FTL_ERRLOG(dev, "Creating FTL on Zoned devices is not supported\n");
118 		goto error;
119 	}
120 
121 	dev->base_layout_tracker = ftl_layout_tracker_bdev_init(spdk_bdev_get_num_blocks(bdev));
122 	if (!dev->base_layout_tracker) {
123 		FTL_ERRLOG(dev, "Failed to instantiate layout tracker for base device\n");
124 		goto error;
125 	}
126 
127 	ftl_mngt_next_step(mngt);
128 	return;
129 error:
130 	ftl_mngt_fail_step(mngt);
131 }
132 
133 void
134 ftl_mngt_close_base_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
135 {
136 	if (dev->base_ioch) {
137 		spdk_put_io_channel(dev->base_ioch);
138 		dev->base_ioch = NULL;
139 	}
140 
141 	if (dev->base_bdev_desc) {
142 		struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
143 
144 		spdk_bdev_module_release_bdev(bdev);
145 		spdk_bdev_close(dev->base_bdev_desc);
146 
147 		dev->base_bdev_desc = NULL;
148 	}
149 
150 	if (dev->base_layout_tracker) {
151 		ftl_layout_tracker_bdev_fini(dev->base_layout_tracker);
152 		dev->base_layout_tracker = 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 	struct ftl_nv_cache *nv_cache = &dev->nv_cache;
175 	const char *bdev_name = dev->conf.cache_bdev;
176 	const struct ftl_md_layout_ops *md_ops;
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 	if (bdev->blockcnt * bdev->blocklen < MINIMUM_CACHE_SIZE_GIB * GiB) {
209 		FTL_ERRLOG(dev, "Bdev %s is too small, requires, at least %uGiB capacity\n",
210 			   spdk_bdev_get_name(bdev), MINIMUM_CACHE_SIZE_GIB);
211 		goto error;
212 	}
213 	nv_cache->md_size = spdk_bdev_get_md_size(bdev);
214 
215 	/* Get FTL NVC bdev descriptor */
216 	nv_cache->nvc_desc = ftl_nv_cache_device_get_desc_by_bdev(dev, bdev);
217 	if (!nv_cache->nvc_desc) {
218 		FTL_ERRLOG(dev, "Failed to get NV Cache device descriptor\n");
219 		goto error;
220 	}
221 	nv_cache->md_size = sizeof(union ftl_md_vss);
222 
223 	md_ops = &nv_cache->nvc_desc->ops.md_layout_ops;
224 	if (!md_ops->region_create) {
225 		FTL_ERRLOG(dev, "NV Cache device doesn't implement md_layout_ops\n");
226 		goto error;
227 	}
228 
229 	dev->nvc_layout_tracker = ftl_layout_tracker_bdev_init(spdk_bdev_get_num_blocks(bdev));
230 	if (!dev->nvc_layout_tracker) {
231 		FTL_ERRLOG(dev, "Failed to instantiate layout tracker for nvc device\n");
232 		goto error;
233 	}
234 
235 	FTL_NOTICELOG(dev, "Using %s as NV Cache device\n", nv_cache->nvc_desc->name);
236 	ftl_mngt_next_step(mngt);
237 	return;
238 error:
239 	ftl_mngt_fail_step(mngt);
240 }
241 
242 void
243 ftl_mngt_close_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
244 {
245 	if (dev->nv_cache.cache_ioch) {
246 		spdk_put_io_channel(dev->nv_cache.cache_ioch);
247 		dev->nv_cache.cache_ioch = NULL;
248 	}
249 
250 	if (dev->nv_cache.bdev_desc) {
251 		struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
252 
253 		spdk_bdev_module_release_bdev(bdev);
254 		spdk_bdev_close(dev->nv_cache.bdev_desc);
255 
256 		dev->nv_cache.bdev_desc = NULL;
257 	}
258 
259 	if (dev->nvc_layout_tracker) {
260 		ftl_layout_tracker_bdev_fini(dev->nvc_layout_tracker);
261 		dev->nvc_layout_tracker = NULL;
262 	}
263 
264 	ftl_mngt_next_step(mngt);
265 }
266