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