Branch data Line data Source code
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 : 52 : 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 : 52 : return (1ULL << 30) / FTL_BLOCK_SIZE;
34 : : #endif
35 : : }
36 : :
37 : : static void
38 : 0 : base_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
39 : : {
40 [ # # ]: 0 : switch (type) {
41 : 0 : case SPDK_BDEV_EVENT_REMOVE:
42 : 0 : assert(0);
43 : : break;
44 : 0 : default:
45 : 0 : break;
46 : : }
47 : 0 : }
48 : :
49 : : void
50 : 22 : 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 : 22 : const char *bdev_name = dev->conf.base_bdev;
55 : : struct spdk_bdev *bdev;
56 : :
57 [ - + ]: 22 : if (spdk_bdev_open_ext(bdev_name, true, base_bdev_event_cb,
58 : : dev, &dev->base_bdev_desc)) {
59 [ # # ]: 0 : FTL_ERRLOG(dev, "Unable to open bdev: %s\n", bdev_name);
60 : 0 : goto error;
61 : : }
62 : :
63 : 22 : bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
64 : :
65 [ - + ]: 22 : 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 : 0 : spdk_bdev_close(dev->base_bdev_desc);
68 : 0 : dev->base_bdev_desc = NULL;
69 [ # # ]: 0 : FTL_ERRLOG(dev, "Unable to claim bdev %s\n", bdev_name);
70 : 0 : goto error;
71 : : }
72 : :
73 : 22 : block_size = spdk_bdev_get_block_size(bdev);
74 [ - + ]: 22 : if (block_size != FTL_BLOCK_SIZE) {
75 [ # # ]: 0 : FTL_ERRLOG(dev, "Unsupported block size (%"PRIu32")\n", block_size);
76 : 0 : goto error;
77 : : }
78 : :
79 : 22 : num_blocks = spdk_bdev_get_num_blocks(bdev);
80 : :
81 [ - + ]: 22 : if (num_blocks * block_size < MINIMUM_BASE_SIZE_GIB * GiB) {
82 [ # # ]: 0 : 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 : 0 : goto error;
85 : : }
86 : :
87 : 22 : dev->base_ioch = spdk_bdev_get_io_channel(dev->base_bdev_desc);
88 [ - + ]: 22 : if (!dev->base_ioch) {
89 [ # # ]: 0 : FTL_ERRLOG(dev, "Failed to create base bdev IO channel\n");
90 : 0 : goto error;
91 : : }
92 : :
93 : 22 : dev->xfer_size = ftl_get_write_unit_size(bdev);
94 [ - + ]: 22 : if (dev->xfer_size != FTL_NUM_LBA_IN_BLOCK) {
95 [ # # ]: 0 : FTL_ERRLOG(dev, "Unsupported xfer_size (%"PRIu64")\n", dev->xfer_size);
96 : 0 : goto error;
97 : : }
98 : :
99 : 22 : dev->base_type = ftl_base_device_get_type_by_bdev(dev, bdev);
100 [ - + ]: 22 : if (!dev->base_type) {
101 [ # # ]: 0 : FTL_ERRLOG(dev, "Failed to get base device type\n");
102 : 0 : goto error;
103 : : }
104 : : /* TODO: validate size when base device VSS usage gets added */
105 : 22 : dev->md_size = spdk_bdev_get_md_size(bdev);
106 : :
107 [ - + ]: 22 : if (!dev->base_type->ops.md_layout_ops.region_create) {
108 [ # # ]: 0 : FTL_ERRLOG(dev, "Base device doesn't implement md_layout_ops\n");
109 : 0 : goto error;
110 : : }
111 : :
112 : : /* Cache frequently used values */
113 : 22 : dev->num_blocks_in_band = ftl_calculate_num_blocks_in_band(dev->base_bdev_desc);
114 : 22 : dev->is_zoned = spdk_bdev_is_zoned(spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
115 : :
116 [ - + - + ]: 22 : if (dev->is_zoned) {
117 : : /* TODO - current FTL code isn't fully compatible with ZNS drives */
118 [ # # ]: 0 : FTL_ERRLOG(dev, "Creating FTL on Zoned devices is not supported\n");
119 : 0 : goto error;
120 : : }
121 : :
122 : 22 : dev->base_layout_tracker = ftl_layout_tracker_bdev_init(spdk_bdev_get_num_blocks(bdev));
123 [ - + ]: 22 : if (!dev->base_layout_tracker) {
124 [ # # ]: 0 : FTL_ERRLOG(dev, "Failed to instantiate layout tracker for base device\n");
125 : 0 : goto error;
126 : : }
127 : :
128 : 22 : ftl_mngt_next_step(mngt);
129 : 22 : return;
130 : 0 : error:
131 : 0 : ftl_mngt_fail_step(mngt);
132 : : }
133 : :
134 : : void
135 : 22 : ftl_mngt_close_base_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
136 : : {
137 [ + - ]: 22 : if (dev->base_ioch) {
138 : 22 : spdk_put_io_channel(dev->base_ioch);
139 : 22 : dev->base_ioch = NULL;
140 : : }
141 : :
142 [ + - ]: 22 : if (dev->base_bdev_desc) {
143 : 22 : struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
144 : :
145 : 22 : spdk_bdev_module_release_bdev(bdev);
146 : 22 : spdk_bdev_close(dev->base_bdev_desc);
147 : :
148 : 22 : dev->base_bdev_desc = NULL;
149 : : }
150 : :
151 [ + - ]: 22 : if (dev->base_layout_tracker) {
152 : 22 : ftl_layout_tracker_bdev_fini(dev->base_layout_tracker);
153 : 22 : dev->base_layout_tracker = NULL;
154 : : }
155 : :
156 : 22 : ftl_mngt_next_step(mngt);
157 : 22 : }
158 : :
159 : : static void
160 : 0 : nv_cache_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
161 : : {
162 [ # # ]: 0 : switch (type) {
163 : 0 : case SPDK_BDEV_EVENT_REMOVE:
164 : 0 : assert(0);
165 : : break;
166 : 0 : default:
167 : 0 : break;
168 : : }
169 : 0 : }
170 : :
171 : : void
172 : 22 : ftl_mngt_open_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
173 : : {
174 : : struct spdk_bdev *bdev;
175 : 22 : struct ftl_nv_cache *nv_cache = &dev->nv_cache;
176 : 22 : const char *bdev_name = dev->conf.cache_bdev;
177 : : const struct ftl_md_layout_ops *md_ops;
178 : :
179 [ - + ]: 22 : if (spdk_bdev_open_ext(bdev_name, true, nv_cache_bdev_event_cb, dev,
180 : : &nv_cache->bdev_desc)) {
181 [ # # ]: 0 : FTL_ERRLOG(dev, "Unable to open bdev: %s\n", bdev_name);
182 : 0 : goto error;
183 : : }
184 : :
185 : 22 : bdev = spdk_bdev_desc_get_bdev(nv_cache->bdev_desc);
186 : :
187 [ - + ]: 22 : 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 : 0 : spdk_bdev_close(nv_cache->bdev_desc);
190 : 0 : nv_cache->bdev_desc = NULL;
191 [ # # ]: 0 : FTL_ERRLOG(dev, "Unable to claim bdev %s\n", bdev_name);
192 : 0 : goto error;
193 : : }
194 : :
195 [ + - ]: 22 : FTL_NOTICELOG(dev, "Using %s as write buffer cache\n", spdk_bdev_get_name(bdev));
196 : :
197 [ - + ]: 22 : if (spdk_bdev_get_block_size(bdev) != FTL_BLOCK_SIZE) {
198 [ # # ]: 0 : FTL_ERRLOG(dev, "Unsupported block size (%d)\n",
199 : : spdk_bdev_get_block_size(bdev));
200 : 0 : goto error;
201 : : }
202 : :
203 : 22 : nv_cache->cache_ioch = spdk_bdev_get_io_channel(nv_cache->bdev_desc);
204 [ - + ]: 22 : if (!nv_cache->cache_ioch) {
205 [ # # ]: 0 : FTL_ERRLOG(dev, "Failed to create cache IO channel for NV Cache\n");
206 : 0 : goto error;
207 : : }
208 : :
209 [ - + ]: 22 : if (bdev->blockcnt * bdev->blocklen < MINIMUM_CACHE_SIZE_GIB * GiB) {
210 [ # # ]: 0 : 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 : 0 : goto error;
213 : : }
214 : 22 : nv_cache->md_size = spdk_bdev_get_md_size(bdev);
215 : :
216 : : /* Get FTL NVC bdev descriptor */
217 : 22 : nv_cache->nvc_desc = ftl_nv_cache_device_get_desc_by_bdev(dev, bdev);
218 [ - + ]: 22 : if (!nv_cache->nvc_desc) {
219 [ # # ]: 0 : FTL_ERRLOG(dev, "Failed to get NV Cache device descriptor\n");
220 : 0 : goto error;
221 : : }
222 : 22 : nv_cache->md_size = sizeof(union ftl_md_vss);
223 : :
224 : 22 : md_ops = &nv_cache->nvc_desc->ops.md_layout_ops;
225 [ - + ]: 22 : if (!md_ops->region_create) {
226 [ # # ]: 0 : FTL_ERRLOG(dev, "NV Cache device doesn't implement md_layout_ops\n");
227 : 0 : goto error;
228 : : }
229 : :
230 : 22 : dev->nvc_layout_tracker = ftl_layout_tracker_bdev_init(spdk_bdev_get_num_blocks(bdev));
231 [ - + ]: 22 : if (!dev->nvc_layout_tracker) {
232 [ # # ]: 0 : FTL_ERRLOG(dev, "Failed to instantiate layout tracker for nvc device\n");
233 : 0 : goto error;
234 : : }
235 : :
236 [ + - ]: 22 : FTL_NOTICELOG(dev, "Using %s as NV Cache device\n", nv_cache->nvc_desc->name);
237 : 22 : ftl_mngt_next_step(mngt);
238 : 22 : return;
239 : 0 : error:
240 : 0 : ftl_mngt_fail_step(mngt);
241 : : }
242 : :
243 : : void
244 : 22 : ftl_mngt_close_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
245 : : {
246 [ + - ]: 22 : if (dev->nv_cache.cache_ioch) {
247 : 22 : spdk_put_io_channel(dev->nv_cache.cache_ioch);
248 : 22 : dev->nv_cache.cache_ioch = NULL;
249 : : }
250 : :
251 [ + - ]: 22 : if (dev->nv_cache.bdev_desc) {
252 : 22 : struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
253 : :
254 : 22 : spdk_bdev_module_release_bdev(bdev);
255 : 22 : spdk_bdev_close(dev->nv_cache.bdev_desc);
256 : :
257 : 22 : dev->nv_cache.bdev_desc = NULL;
258 : : }
259 : :
260 [ + - ]: 22 : if (dev->nvc_layout_tracker) {
261 : 22 : ftl_layout_tracker_bdev_fini(dev->nvc_layout_tracker);
262 : 22 : dev->nvc_layout_tracker = NULL;
263 : : }
264 : :
265 : 22 : ftl_mngt_next_step(mngt);
266 : 22 : }
|