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