1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2022 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "ftl_core.h" 7 #include "ftl_mngt.h" 8 #include "ftl_mngt_steps.h" 9 10 static const struct ftl_mngt_process_desc desc_startup; 11 static const struct ftl_mngt_process_desc desc_first_start; 12 static const struct ftl_mngt_process_desc desc_restore; 13 static const struct ftl_mngt_process_desc desc_clean_start; 14 15 static void 16 ftl_mngt_select_startup_mode(struct spdk_ftl_dev *dev, 17 struct ftl_mngt_process *mngt) 18 { 19 if (dev->conf.mode & SPDK_FTL_MODE_CREATE) { 20 ftl_mngt_call_process(mngt, &desc_first_start); 21 } else { 22 ftl_mngt_call_process(mngt, &desc_restore); 23 } 24 } 25 26 static void 27 ftl_mngt_select_restore_mode(struct spdk_ftl_dev *dev, 28 struct ftl_mngt_process *mngt) 29 { 30 if (dev->sb->clean) { 31 ftl_mngt_call_process(mngt, &desc_clean_start); 32 } else { 33 ftl_mngt_recover(dev, mngt); 34 } 35 } 36 37 /* 38 * Common startup steps required by FTL in all cases (creation, load, dirty shutdown recovery). 39 * Includes actions like opening the devices, calculating the expected size and version of metadata, etc. 40 */ 41 static const struct ftl_mngt_process_desc desc_startup = { 42 .name = "FTL startup", 43 .steps = { 44 { 45 .name = "Check configuration", 46 .action = ftl_mngt_check_conf, 47 }, 48 { 49 .name = "Open base bdev", 50 .action = ftl_mngt_open_base_bdev, 51 .cleanup = ftl_mngt_close_base_bdev 52 }, 53 { 54 .name = "Open cache bdev", 55 .action = ftl_mngt_open_cache_bdev, 56 .cleanup = ftl_mngt_close_cache_bdev 57 }, 58 #ifdef SPDK_FTL_VSS_EMU 59 { 60 .name = "Initialize VSS emu", 61 .action = ftl_mngt_md_init_vss_emu, 62 .cleanup = ftl_mngt_md_deinit_vss_emu 63 }, 64 #endif 65 { 66 .name = "Initialize superblock", 67 .action = ftl_mngt_superblock_init, 68 .cleanup = ftl_mngt_superblock_deinit 69 }, 70 { 71 .name = "Initialize memory pools", 72 .action = ftl_mngt_init_mem_pools, 73 .cleanup = ftl_mngt_deinit_mem_pools 74 }, 75 { 76 .name = "Initialize bands", 77 .action = ftl_mngt_init_bands, 78 .cleanup = ftl_mngt_deinit_bands 79 }, 80 { 81 .name = "Register IO device", 82 .action = ftl_mngt_register_io_device, 83 .cleanup = ftl_mngt_unregister_io_device 84 }, 85 { 86 .name = "Initialize core IO channel", 87 .action = ftl_mngt_init_io_channel, 88 .cleanup = ftl_mngt_deinit_io_channel 89 }, 90 { 91 .name = "Decorate bands", 92 .action = ftl_mngt_decorate_bands 93 }, 94 { 95 .name = "Initialize layout", 96 .action = ftl_mngt_init_layout 97 }, 98 { 99 .name = "Verify layout", 100 .action = ftl_mngt_layout_verify, 101 }, 102 { 103 .name = "Initialize metadata", 104 .action = ftl_mngt_init_md, 105 .cleanup = ftl_mngt_deinit_md 106 }, 107 { 108 .name = "Initialize band addresses", 109 .action = ftl_mngt_initialize_band_address 110 }, 111 { 112 .name = "Initialize NV cache", 113 .action = ftl_mngt_init_nv_cache, 114 .cleanup = ftl_mngt_deinit_nv_cache 115 }, 116 { 117 .name = "Upgrade layout", 118 .action = ftl_mngt_layout_upgrade, 119 }, 120 { 121 .name = "Initialize valid map", 122 .action = ftl_mngt_init_vld_map, 123 .cleanup = ftl_mngt_deinit_vld_map 124 }, 125 { 126 .name = "Initialize trim map", 127 .action = ftl_mngt_init_unmap_map, 128 .cleanup = ftl_mngt_deinit_unmap_map 129 }, 130 { 131 .name = "Initialize bands metadata", 132 .action = ftl_mngt_init_bands_md, 133 .cleanup = ftl_mngt_deinit_bands_md 134 }, 135 { 136 .name = "Initialize reloc", 137 .action = ftl_mngt_init_reloc, 138 .cleanup = ftl_mngt_deinit_reloc 139 }, 140 { 141 .name = "Select startup mode", 142 .action = ftl_mngt_select_startup_mode 143 }, 144 {} 145 } 146 }; 147 148 /* 149 * Steps executed when creating FTL for the first time - most important being scrubbing 150 * old data/metadata (so it's not leaked during dirty shutdown recovery) and laying out 151 * regions for the new metadata (initializing band states, etc). 152 */ 153 static const struct ftl_mngt_process_desc desc_first_start = { 154 .name = "FTL first start", 155 .steps = { 156 { 157 .name = "Initialize L2P", 158 .action = ftl_mngt_init_l2p, 159 .cleanup = ftl_mngt_deinit_l2p 160 }, 161 { 162 .name = "Clear L2P", 163 .action = ftl_mngt_clear_l2p, 164 .cleanup = ftl_mngt_clear_l2p 165 }, 166 { 167 .name = "Scrub NV cache", 168 .action = ftl_mngt_scrub_nv_cache, 169 }, 170 { 171 .name = "Finalize band initialization", 172 .action = ftl_mngt_finalize_init_bands, 173 }, 174 { 175 .name = "Save initial band info metadata", 176 .action = ftl_mngt_persist_band_info_metadata, 177 }, 178 { 179 .name = "Save initial chunk info metadata", 180 .action = ftl_mngt_persist_nv_cache_metadata, 181 }, 182 { 183 .name = "Initialize P2L checkpointing", 184 .action = ftl_mngt_p2l_init_ckpt, 185 .cleanup = ftl_mngt_p2l_deinit_ckpt 186 }, 187 { 188 .name = "Wipe P2L region", 189 .action = ftl_mngt_p2l_wipe, 190 }, 191 { 192 .name = "Clear trim map", 193 .action = ftl_mngt_unmap_clear, 194 }, 195 { 196 .name = "Free P2L region bufs", 197 .action = ftl_mngt_p2l_free_bufs, 198 }, 199 { 200 .name = "Set FTL dirty state", 201 .action = ftl_mngt_set_dirty, 202 }, 203 { 204 .name = "Start core poller", 205 .action = ftl_mngt_start_core_poller, 206 .cleanup = ftl_mngt_stop_core_poller 207 }, 208 { 209 .name = "Finalize initialization", 210 .action = ftl_mngt_finalize_startup, 211 }, 212 {} 213 } 214 }; 215 216 /* 217 * Step utilized on loading of an FTL instance - decides on dirty/clean shutdown path. 218 */ 219 static const struct ftl_mngt_process_desc desc_restore = { 220 .name = "FTL restore", 221 .steps = { 222 { 223 .name = "Select recovery mode", 224 .action = ftl_mngt_select_restore_mode, 225 }, 226 {} 227 } 228 }; 229 230 /* 231 * Loading of FTL after clean shutdown. 232 */ 233 static const struct ftl_mngt_process_desc desc_clean_start = { 234 .name = "Clean startup", 235 .steps = { 236 { 237 .name = "Restore metadata", 238 .action = ftl_mngt_restore_md 239 }, 240 { 241 .name = "Initialize P2L checkpointing", 242 .action = ftl_mngt_p2l_init_ckpt, 243 .cleanup = ftl_mngt_p2l_deinit_ckpt 244 }, 245 { 246 .name = "Restore P2L checkpoints", 247 .action = ftl_mngt_p2l_restore_ckpt 248 }, 249 { 250 .name = "Initialize L2P", 251 .action = ftl_mngt_init_l2p, 252 .cleanup = ftl_mngt_deinit_l2p 253 }, 254 { 255 .name = "Restore L2P", 256 .action = ftl_mngt_restore_l2p, 257 }, 258 { 259 .name = "Finalize band initialization", 260 .action = ftl_mngt_finalize_init_bands, 261 }, 262 { 263 .name = "Free P2L region bufs", 264 .action = ftl_mngt_p2l_free_bufs, 265 }, 266 { 267 .name = "Start core poller", 268 .action = ftl_mngt_start_core_poller, 269 .cleanup = ftl_mngt_stop_core_poller 270 }, 271 { 272 .name = "Self test on startup", 273 .action = ftl_mngt_self_test, 274 }, 275 { 276 .name = "Set FTL dirty state", 277 .action = ftl_mngt_set_dirty, 278 }, 279 { 280 .name = "Finalize initialization", 281 .action = ftl_mngt_finalize_startup, 282 }, 283 {} 284 } 285 }; 286 287 int 288 ftl_mngt_call_dev_startup(struct spdk_ftl_dev *dev, ftl_mngt_completion cb, void *cb_cntx) 289 { 290 return ftl_mngt_process_execute(dev, &desc_startup, cb, cb_cntx); 291 } 292 293 struct ftl_unmap_ctx { 294 uint64_t lba; 295 uint64_t num_blocks; 296 spdk_ftl_fn cb_fn; 297 void *cb_arg; 298 struct spdk_thread *thread; 299 int status; 300 }; 301 302 static void 303 ftl_mngt_process_unmap_cb(void *ctx, int status) 304 { 305 struct ftl_mngt_process *mngt = ctx; 306 307 if (status) { 308 ftl_mngt_fail_step(ctx); 309 } else { 310 ftl_mngt_next_step(mngt); 311 } 312 } 313 314 static void 315 ftl_mngt_process_unmap(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 316 { 317 struct ftl_io *io = ftl_mngt_get_process_ctx(mngt); 318 struct ftl_unmap_ctx *ctx = ftl_mngt_get_caller_ctx(mngt); 319 int rc; 320 321 if (!dev->ioch) { 322 ftl_mngt_fail_step(mngt); 323 return; 324 } 325 326 rc = spdk_ftl_unmap(dev, io, dev->ioch, ctx->lba, ctx->num_blocks, ftl_mngt_process_unmap_cb, mngt); 327 if (rc == -EAGAIN) { 328 ftl_mngt_continue_step(mngt); 329 } 330 } 331 332 /* 333 * RPC unmap path. 334 */ 335 static const struct ftl_mngt_process_desc g_desc_unmap = { 336 .name = "FTL unmap", 337 .ctx_size = sizeof(struct ftl_io), 338 .steps = { 339 { 340 .name = "Process unmap", 341 .action = ftl_mngt_process_unmap, 342 }, 343 {} 344 } 345 }; 346 347 static void 348 unmap_user_cb(void *_ctx) 349 { 350 struct ftl_unmap_ctx *ctx = _ctx; 351 352 ctx->cb_fn(ctx->cb_arg, ctx->status); 353 free(ctx); 354 } 355 356 static void 357 ftl_mngt_unmap_cb(struct spdk_ftl_dev *dev, void *_ctx, int status) 358 { 359 struct ftl_unmap_ctx *ctx = _ctx; 360 ctx->status = status; 361 362 if (spdk_thread_send_msg(ctx->thread, unmap_user_cb, ctx)) { 363 ftl_abort(); 364 } 365 } 366 367 int 368 ftl_mngt_unmap(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t num_blocks, spdk_ftl_fn cb, 369 void *cb_cntx) 370 { 371 struct ftl_unmap_ctx *ctx; 372 373 ctx = calloc(1, sizeof(*ctx)); 374 if (ctx == NULL) { 375 return -EAGAIN; 376 } 377 378 ctx->lba = lba; 379 ctx->num_blocks = num_blocks; 380 ctx->cb_fn = cb; 381 ctx->cb_arg = cb_cntx; 382 ctx->thread = spdk_get_thread(); 383 384 return ftl_mngt_process_execute(dev, &g_desc_unmap, ftl_mngt_unmap_cb, ctx); 385 } 386 387 void 388 ftl_mngt_rollback_device(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 389 { 390 ftl_mngt_call_process_rollback(mngt, &desc_startup); 391 } 392