xref: /spdk/lib/ftl/mngt/ftl_mngt_bdev.c (revision 4061ed111c296d0f508ddfd75d09052b9acd6d72)
1e49ccfc8SArtur Paszkiewicz /*   SPDX-License-Identifier: BSD-3-Clause
220c3c166SMateusz Kozlowski  *   Copyright 2023 Solidigm All Rights Reserved
3a6dbe372Spaul luse  *   Copyright (C) 2022 Intel Corporation.
4e49ccfc8SArtur Paszkiewicz  *   All rights reserved.
5e49ccfc8SArtur Paszkiewicz  */
6e49ccfc8SArtur Paszkiewicz 
7e49ccfc8SArtur Paszkiewicz #include "spdk/bdev_module.h"
8e49ccfc8SArtur Paszkiewicz #include "spdk/ftl.h"
9e49ccfc8SArtur Paszkiewicz 
10a68a12a4SKozlowski Mateusz #include "ftl_nv_cache.h"
11e49ccfc8SArtur Paszkiewicz #include "ftl_internal.h"
12e49ccfc8SArtur Paszkiewicz #include "ftl_mngt_steps.h"
13e49ccfc8SArtur Paszkiewicz #include "ftl_core.h"
14e49ccfc8SArtur Paszkiewicz #include "utils/ftl_defs.h"
1593036282SLukasz Lasek #include "utils/ftl_layout_tracker_bdev.h"
16e49ccfc8SArtur Paszkiewicz 
17e49ccfc8SArtur Paszkiewicz #define MINIMUM_CACHE_SIZE_GIB 5
18e49ccfc8SArtur Paszkiewicz #define MINIMUM_BASE_SIZE_GIB 20
19e49ccfc8SArtur Paszkiewicz 
20e49ccfc8SArtur Paszkiewicz /*  Dummy bdev module used to to claim bdevs. */
21e49ccfc8SArtur Paszkiewicz static struct spdk_bdev_module g_ftl_bdev_module = {
22e49ccfc8SArtur Paszkiewicz 	.name   = "ftl_lib",
23e49ccfc8SArtur Paszkiewicz };
24e49ccfc8SArtur Paszkiewicz 
251bbefed6SKozlowski Mateusz static inline uint64_t
ftl_calculate_num_blocks_in_band(struct spdk_bdev_desc * desc)261bbefed6SKozlowski Mateusz ftl_calculate_num_blocks_in_band(struct spdk_bdev_desc *desc)
27e49ccfc8SArtur Paszkiewicz {
28e49ccfc8SArtur Paszkiewicz 	/* TODO: this should be passed via input parameter */
29e49ccfc8SArtur Paszkiewicz #ifdef SPDK_FTL_ZONE_EMU_BLOCKS
30e49ccfc8SArtur Paszkiewicz 	return SPDK_FTL_ZONE_EMU_BLOCKS;
31e49ccfc8SArtur Paszkiewicz #else
32e49ccfc8SArtur Paszkiewicz 	return (1ULL << 30) / FTL_BLOCK_SIZE;
33e49ccfc8SArtur Paszkiewicz #endif
34e49ccfc8SArtur Paszkiewicz }
35e49ccfc8SArtur Paszkiewicz 
36e49ccfc8SArtur Paszkiewicz static void
base_bdev_event_cb(enum spdk_bdev_event_type type,struct spdk_bdev * bdev,void * event_ctx)37e49ccfc8SArtur Paszkiewicz base_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
38e49ccfc8SArtur Paszkiewicz {
39e49ccfc8SArtur Paszkiewicz 	switch (type) {
40e49ccfc8SArtur Paszkiewicz 	case SPDK_BDEV_EVENT_REMOVE:
41e49ccfc8SArtur Paszkiewicz 		assert(0);
42e49ccfc8SArtur Paszkiewicz 		break;
43e49ccfc8SArtur Paszkiewicz 	default:
44e49ccfc8SArtur Paszkiewicz 		break;
45e49ccfc8SArtur Paszkiewicz 	}
46e49ccfc8SArtur Paszkiewicz }
47e49ccfc8SArtur Paszkiewicz 
48e49ccfc8SArtur Paszkiewicz void
ftl_mngt_open_base_bdev(struct spdk_ftl_dev * dev,struct ftl_mngt_process * mngt)49e49ccfc8SArtur Paszkiewicz ftl_mngt_open_base_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
50e49ccfc8SArtur Paszkiewicz {
51e49ccfc8SArtur Paszkiewicz 	uint32_t block_size;
52e49ccfc8SArtur Paszkiewicz 	uint64_t num_blocks;
53e49ccfc8SArtur Paszkiewicz 	const char *bdev_name = dev->conf.base_bdev;
54e49ccfc8SArtur Paszkiewicz 	struct spdk_bdev *bdev;
55e49ccfc8SArtur Paszkiewicz 
56e49ccfc8SArtur Paszkiewicz 	if (spdk_bdev_open_ext(bdev_name, true, base_bdev_event_cb,
57e49ccfc8SArtur Paszkiewicz 			       dev, &dev->base_bdev_desc)) {
58e49ccfc8SArtur Paszkiewicz 		FTL_ERRLOG(dev, "Unable to open bdev: %s\n", bdev_name);
59e49ccfc8SArtur Paszkiewicz 		goto error;
60e49ccfc8SArtur Paszkiewicz 	}
61e49ccfc8SArtur Paszkiewicz 
62e49ccfc8SArtur Paszkiewicz 	bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
63e49ccfc8SArtur Paszkiewicz 
64e49ccfc8SArtur Paszkiewicz 	if (spdk_bdev_module_claim_bdev(bdev, dev->base_bdev_desc, &g_ftl_bdev_module)) {
65e49ccfc8SArtur Paszkiewicz 		/* clear the desc so that we don't try to release the claim on cleanup */
66e49ccfc8SArtur Paszkiewicz 		spdk_bdev_close(dev->base_bdev_desc);
67e49ccfc8SArtur Paszkiewicz 		dev->base_bdev_desc = NULL;
68e49ccfc8SArtur Paszkiewicz 		FTL_ERRLOG(dev, "Unable to claim bdev %s\n", bdev_name);
69e49ccfc8SArtur Paszkiewicz 		goto error;
70e49ccfc8SArtur Paszkiewicz 	}
71e49ccfc8SArtur Paszkiewicz 
72e49ccfc8SArtur Paszkiewicz 	block_size = spdk_bdev_get_block_size(bdev);
73e49ccfc8SArtur Paszkiewicz 	if (block_size != FTL_BLOCK_SIZE) {
74e49ccfc8SArtur Paszkiewicz 		FTL_ERRLOG(dev, "Unsupported block size (%"PRIu32")\n", block_size);
75e49ccfc8SArtur Paszkiewicz 		goto error;
76e49ccfc8SArtur Paszkiewicz 	}
77e49ccfc8SArtur Paszkiewicz 
78e49ccfc8SArtur Paszkiewicz 	num_blocks = spdk_bdev_get_num_blocks(bdev);
79e49ccfc8SArtur Paszkiewicz 
80e49ccfc8SArtur Paszkiewicz 	if (num_blocks * block_size < MINIMUM_BASE_SIZE_GIB * GiB) {
81e49ccfc8SArtur Paszkiewicz 		FTL_ERRLOG(dev, "Bdev %s is too small, requires, at least %uGiB capacity\n",
82e49ccfc8SArtur Paszkiewicz 			   spdk_bdev_get_name(bdev), MINIMUM_BASE_SIZE_GIB);
83e49ccfc8SArtur Paszkiewicz 		goto error;
84e49ccfc8SArtur Paszkiewicz 	}
85e49ccfc8SArtur Paszkiewicz 
86e49ccfc8SArtur Paszkiewicz 	dev->base_ioch = spdk_bdev_get_io_channel(dev->base_bdev_desc);
87e49ccfc8SArtur Paszkiewicz 	if (!dev->base_ioch) {
88e49ccfc8SArtur Paszkiewicz 		FTL_ERRLOG(dev, "Failed to create base bdev IO channel\n");
89e49ccfc8SArtur Paszkiewicz 		goto error;
90e49ccfc8SArtur Paszkiewicz 	}
91e49ccfc8SArtur Paszkiewicz 
92e49ccfc8SArtur Paszkiewicz 	dev->xfer_size = ftl_get_write_unit_size(bdev);
93*4061ed11SMateusz Kozlowski 	if (!spdk_u32_is_pow2(dev->xfer_size)) {
94*4061ed11SMateusz Kozlowski 		FTL_ERRLOG(dev,
95*4061ed11SMateusz Kozlowski 			   "Unsupported xfer_size (%"PRIu64") - only power of 2 blocks xfer_size is supported\n",
96*4061ed11SMateusz Kozlowski 			   dev->xfer_size);
971738488eSArtur Paszkiewicz 		goto error;
981738488eSArtur Paszkiewicz 	}
99e49ccfc8SArtur Paszkiewicz 
100498c39beSLukasz Lasek 	dev->base_type = ftl_base_device_get_type_by_bdev(dev, bdev);
101498c39beSLukasz Lasek 	if (!dev->base_type) {
102498c39beSLukasz Lasek 		FTL_ERRLOG(dev, "Failed to get base device type\n");
103498c39beSLukasz Lasek 		goto error;
104498c39beSLukasz Lasek 	}
105e49ccfc8SArtur Paszkiewicz 	/* TODO: validate size when base device VSS usage gets added */
106e49ccfc8SArtur Paszkiewicz 	dev->md_size = spdk_bdev_get_md_size(bdev);
107e49ccfc8SArtur Paszkiewicz 
108498c39beSLukasz Lasek 	if (!dev->base_type->ops.md_layout_ops.region_create) {
109498c39beSLukasz Lasek 		FTL_ERRLOG(dev, "Base device doesn't implement md_layout_ops\n");
110498c39beSLukasz Lasek 		goto error;
111498c39beSLukasz Lasek 	}
112498c39beSLukasz Lasek 
113e49ccfc8SArtur Paszkiewicz 	/* Cache frequently used values */
114e49ccfc8SArtur Paszkiewicz 	dev->num_blocks_in_band = ftl_calculate_num_blocks_in_band(dev->base_bdev_desc);
115e49ccfc8SArtur Paszkiewicz 	dev->is_zoned = spdk_bdev_is_zoned(spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
116e49ccfc8SArtur Paszkiewicz 
117e49ccfc8SArtur Paszkiewicz 	if (dev->is_zoned) {
118e49ccfc8SArtur Paszkiewicz 		/* TODO - current FTL code isn't fully compatible with ZNS drives */
119e49ccfc8SArtur Paszkiewicz 		FTL_ERRLOG(dev, "Creating FTL on Zoned devices is not supported\n");
120e49ccfc8SArtur Paszkiewicz 		goto error;
121e49ccfc8SArtur Paszkiewicz 	}
122e49ccfc8SArtur Paszkiewicz 
12393036282SLukasz Lasek 	dev->base_layout_tracker = ftl_layout_tracker_bdev_init(spdk_bdev_get_num_blocks(bdev));
12493036282SLukasz Lasek 	if (!dev->base_layout_tracker) {
12593036282SLukasz Lasek 		FTL_ERRLOG(dev, "Failed to instantiate layout tracker for base device\n");
12693036282SLukasz Lasek 		goto error;
12793036282SLukasz Lasek 	}
12893036282SLukasz Lasek 
129e49ccfc8SArtur Paszkiewicz 	ftl_mngt_next_step(mngt);
130e49ccfc8SArtur Paszkiewicz 	return;
131e49ccfc8SArtur Paszkiewicz error:
132e49ccfc8SArtur Paszkiewicz 	ftl_mngt_fail_step(mngt);
133e49ccfc8SArtur Paszkiewicz }
134e49ccfc8SArtur Paszkiewicz 
135e49ccfc8SArtur Paszkiewicz void
ftl_mngt_close_base_bdev(struct spdk_ftl_dev * dev,struct ftl_mngt_process * mngt)136e49ccfc8SArtur Paszkiewicz ftl_mngt_close_base_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
137e49ccfc8SArtur Paszkiewicz {
138e49ccfc8SArtur Paszkiewicz 	if (dev->base_ioch) {
139e49ccfc8SArtur Paszkiewicz 		spdk_put_io_channel(dev->base_ioch);
140e49ccfc8SArtur Paszkiewicz 		dev->base_ioch = NULL;
141e49ccfc8SArtur Paszkiewicz 	}
142e49ccfc8SArtur Paszkiewicz 
143e49ccfc8SArtur Paszkiewicz 	if (dev->base_bdev_desc) {
144e49ccfc8SArtur Paszkiewicz 		struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
145e49ccfc8SArtur Paszkiewicz 
146e49ccfc8SArtur Paszkiewicz 		spdk_bdev_module_release_bdev(bdev);
147e49ccfc8SArtur Paszkiewicz 		spdk_bdev_close(dev->base_bdev_desc);
148e49ccfc8SArtur Paszkiewicz 
149e49ccfc8SArtur Paszkiewicz 		dev->base_bdev_desc = NULL;
150e49ccfc8SArtur Paszkiewicz 	}
151e49ccfc8SArtur Paszkiewicz 
15293036282SLukasz Lasek 	if (dev->base_layout_tracker) {
15393036282SLukasz Lasek 		ftl_layout_tracker_bdev_fini(dev->base_layout_tracker);
15493036282SLukasz Lasek 		dev->base_layout_tracker = NULL;
15593036282SLukasz Lasek 	}
15693036282SLukasz Lasek 
157e49ccfc8SArtur Paszkiewicz 	ftl_mngt_next_step(mngt);
158e49ccfc8SArtur Paszkiewicz }
159e49ccfc8SArtur Paszkiewicz 
160e49ccfc8SArtur Paszkiewicz static void
nv_cache_bdev_event_cb(enum spdk_bdev_event_type type,struct spdk_bdev * bdev,void * event_ctx)161e49ccfc8SArtur Paszkiewicz nv_cache_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
162e49ccfc8SArtur Paszkiewicz {
163e49ccfc8SArtur Paszkiewicz 	switch (type) {
164e49ccfc8SArtur Paszkiewicz 	case SPDK_BDEV_EVENT_REMOVE:
165e49ccfc8SArtur Paszkiewicz 		assert(0);
166e49ccfc8SArtur Paszkiewicz 		break;
167e49ccfc8SArtur Paszkiewicz 	default:
168e49ccfc8SArtur Paszkiewicz 		break;
169e49ccfc8SArtur Paszkiewicz 	}
170e49ccfc8SArtur Paszkiewicz }
171e49ccfc8SArtur Paszkiewicz 
172e49ccfc8SArtur Paszkiewicz void
ftl_mngt_open_cache_bdev(struct spdk_ftl_dev * dev,struct ftl_mngt_process * mngt)173e49ccfc8SArtur Paszkiewicz ftl_mngt_open_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
174e49ccfc8SArtur Paszkiewicz {
175e49ccfc8SArtur Paszkiewicz 	struct spdk_bdev *bdev;
176a68a12a4SKozlowski Mateusz 	struct ftl_nv_cache *nv_cache = &dev->nv_cache;
177e49ccfc8SArtur Paszkiewicz 	const char *bdev_name = dev->conf.cache_bdev;
178b0556d4aSLukasz Lasek 	const struct ftl_md_layout_ops *md_ops;
179e49ccfc8SArtur Paszkiewicz 
180e49ccfc8SArtur Paszkiewicz 	if (spdk_bdev_open_ext(bdev_name, true, nv_cache_bdev_event_cb, dev,
181a68a12a4SKozlowski Mateusz 			       &nv_cache->bdev_desc)) {
182e49ccfc8SArtur Paszkiewicz 		FTL_ERRLOG(dev, "Unable to open bdev: %s\n", bdev_name);
183e49ccfc8SArtur Paszkiewicz 		goto error;
184e49ccfc8SArtur Paszkiewicz 	}
185e49ccfc8SArtur Paszkiewicz 
186a68a12a4SKozlowski Mateusz 	bdev = spdk_bdev_desc_get_bdev(nv_cache->bdev_desc);
187e49ccfc8SArtur Paszkiewicz 
188a68a12a4SKozlowski Mateusz 	if (spdk_bdev_module_claim_bdev(bdev, nv_cache->bdev_desc, &g_ftl_bdev_module)) {
189e49ccfc8SArtur Paszkiewicz 		/* clear the desc so that we don't try to release the claim on cleanup */
190a68a12a4SKozlowski Mateusz 		spdk_bdev_close(nv_cache->bdev_desc);
191a68a12a4SKozlowski Mateusz 		nv_cache->bdev_desc = NULL;
192e49ccfc8SArtur Paszkiewicz 		FTL_ERRLOG(dev, "Unable to claim bdev %s\n", bdev_name);
193e49ccfc8SArtur Paszkiewicz 		goto error;
194e49ccfc8SArtur Paszkiewicz 	}
195e49ccfc8SArtur Paszkiewicz 
196e49ccfc8SArtur Paszkiewicz 	FTL_NOTICELOG(dev, "Using %s as write buffer cache\n", spdk_bdev_get_name(bdev));
197e49ccfc8SArtur Paszkiewicz 
198e49ccfc8SArtur Paszkiewicz 	if (spdk_bdev_get_block_size(bdev) != FTL_BLOCK_SIZE) {
199e49ccfc8SArtur Paszkiewicz 		FTL_ERRLOG(dev, "Unsupported block size (%d)\n",
200e49ccfc8SArtur Paszkiewicz 			   spdk_bdev_get_block_size(bdev));
201e49ccfc8SArtur Paszkiewicz 		goto error;
202e49ccfc8SArtur Paszkiewicz 	}
203e49ccfc8SArtur Paszkiewicz 
204a68a12a4SKozlowski Mateusz 	nv_cache->cache_ioch = spdk_bdev_get_io_channel(nv_cache->bdev_desc);
205a68a12a4SKozlowski Mateusz 	if (!nv_cache->cache_ioch) {
206e49ccfc8SArtur Paszkiewicz 		FTL_ERRLOG(dev, "Failed to create cache IO channel for NV Cache\n");
207e49ccfc8SArtur Paszkiewicz 		goto error;
208e49ccfc8SArtur Paszkiewicz 	}
209e49ccfc8SArtur Paszkiewicz 
210e49ccfc8SArtur Paszkiewicz 	if (bdev->blockcnt * bdev->blocklen < MINIMUM_CACHE_SIZE_GIB * GiB) {
211e49ccfc8SArtur Paszkiewicz 		FTL_ERRLOG(dev, "Bdev %s is too small, requires, at least %uGiB capacity\n",
212e49ccfc8SArtur Paszkiewicz 			   spdk_bdev_get_name(bdev), MINIMUM_CACHE_SIZE_GIB);
213e49ccfc8SArtur Paszkiewicz 		goto error;
214e49ccfc8SArtur Paszkiewicz 	}
21520c3c166SMateusz Kozlowski 	nv_cache->md_size = spdk_bdev_get_md_size(bdev);
216e49ccfc8SArtur Paszkiewicz 
21726f3b551SMateusz Kozlowski 	nv_cache->nvc_type = ftl_nv_cache_device_get_type_by_bdev(dev, bdev);
21826f3b551SMateusz Kozlowski 	if (!nv_cache->nvc_type) {
21926f3b551SMateusz Kozlowski 		FTL_ERRLOG(dev, "Failed to get NV Cache device type\n");
220884980d0SArtur Paszkiewicz 		goto error;
221884980d0SArtur Paszkiewicz 	}
22220c3c166SMateusz Kozlowski 	nv_cache->md_size = sizeof(union ftl_md_vss);
223f725ca81SArtur Paszkiewicz 
22426f3b551SMateusz Kozlowski 	md_ops = &nv_cache->nvc_type->ops.md_layout_ops;
225b0556d4aSLukasz Lasek 	if (!md_ops->region_create) {
226b0556d4aSLukasz Lasek 		FTL_ERRLOG(dev, "NV Cache device doesn't implement md_layout_ops\n");
227b0556d4aSLukasz Lasek 		goto error;
228b0556d4aSLukasz Lasek 	}
229b0556d4aSLukasz Lasek 
23093036282SLukasz Lasek 	dev->nvc_layout_tracker = ftl_layout_tracker_bdev_init(spdk_bdev_get_num_blocks(bdev));
23193036282SLukasz Lasek 	if (!dev->nvc_layout_tracker) {
23293036282SLukasz Lasek 		FTL_ERRLOG(dev, "Failed to instantiate layout tracker for nvc device\n");
23393036282SLukasz Lasek 		goto error;
23493036282SLukasz Lasek 	}
23593036282SLukasz Lasek 
23626f3b551SMateusz Kozlowski 	FTL_NOTICELOG(dev, "Using %s as NV Cache device\n", nv_cache->nvc_type->name);
237e49ccfc8SArtur Paszkiewicz 	ftl_mngt_next_step(mngt);
238e49ccfc8SArtur Paszkiewicz 	return;
239e49ccfc8SArtur Paszkiewicz error:
240e49ccfc8SArtur Paszkiewicz 	ftl_mngt_fail_step(mngt);
241e49ccfc8SArtur Paszkiewicz }
242e49ccfc8SArtur Paszkiewicz 
243e49ccfc8SArtur Paszkiewicz void
ftl_mngt_close_cache_bdev(struct spdk_ftl_dev * dev,struct ftl_mngt_process * mngt)244e49ccfc8SArtur Paszkiewicz ftl_mngt_close_cache_bdev(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
245e49ccfc8SArtur Paszkiewicz {
246a68a12a4SKozlowski Mateusz 	if (dev->nv_cache.cache_ioch) {
247a68a12a4SKozlowski Mateusz 		spdk_put_io_channel(dev->nv_cache.cache_ioch);
248a68a12a4SKozlowski Mateusz 		dev->nv_cache.cache_ioch = NULL;
249e49ccfc8SArtur Paszkiewicz 	}
250e49ccfc8SArtur Paszkiewicz 
251a68a12a4SKozlowski Mateusz 	if (dev->nv_cache.bdev_desc) {
252a68a12a4SKozlowski Mateusz 		struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
253e49ccfc8SArtur Paszkiewicz 
254e49ccfc8SArtur Paszkiewicz 		spdk_bdev_module_release_bdev(bdev);
255a68a12a4SKozlowski Mateusz 		spdk_bdev_close(dev->nv_cache.bdev_desc);
256e49ccfc8SArtur Paszkiewicz 
257a68a12a4SKozlowski Mateusz 		dev->nv_cache.bdev_desc = NULL;
258e49ccfc8SArtur Paszkiewicz 	}
259e49ccfc8SArtur Paszkiewicz 
26093036282SLukasz Lasek 	if (dev->nvc_layout_tracker) {
26193036282SLukasz Lasek 		ftl_layout_tracker_bdev_fini(dev->nvc_layout_tracker);
26293036282SLukasz Lasek 		dev->nvc_layout_tracker = NULL;
26393036282SLukasz Lasek 	}
26493036282SLukasz Lasek 
265e49ccfc8SArtur Paszkiewicz 	ftl_mngt_next_step(mngt);
266e49ccfc8SArtur Paszkiewicz }
267