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