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