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