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, NULL); 22 } else { 23 ftl_mngt_call_process(mngt, &desc_restore, NULL); 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, NULL); 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 = "Scrub NV cache", 102 .action = ftl_mngt_scrub_nv_cache, 103 }, 104 { 105 .name = "Initialize metadata", 106 .action = ftl_mngt_init_md, 107 .cleanup = ftl_mngt_deinit_md 108 }, 109 { 110 .name = "Initialize band addresses", 111 .action = ftl_mngt_initialize_band_address 112 }, 113 { 114 .name = "Initialize NV cache", 115 .action = ftl_mngt_init_nv_cache, 116 .cleanup = ftl_mngt_deinit_nv_cache 117 }, 118 { 119 .name = "Initialize valid map", 120 .action = ftl_mngt_init_vld_map, 121 .cleanup = ftl_mngt_deinit_vld_map 122 }, 123 { 124 .name = "Initialize trim map", 125 .action = ftl_mngt_init_trim_map, 126 .cleanup = ftl_mngt_deinit_trim_map 127 }, 128 { 129 .name = "Initialize bands metadata", 130 .action = ftl_mngt_init_bands_md, 131 .cleanup = ftl_mngt_deinit_bands_md 132 }, 133 { 134 .name = "Initialize reloc", 135 .action = ftl_mngt_init_reloc, 136 .cleanup = ftl_mngt_deinit_reloc 137 }, 138 { 139 .name = "Select startup mode", 140 .action = ftl_mngt_select_startup_mode 141 }, 142 {} 143 } 144 }; 145 146 /* 147 * Steps executed when creating FTL for the first time - most important being scrubbing 148 * old data/metadata (so it's not leaked during dirty shutdown recovery) and laying out 149 * regions for the new metadata (initializing band states, etc). 150 */ 151 static const struct ftl_mngt_process_desc desc_first_start = { 152 .name = "FTL first start", 153 .steps = { 154 { 155 .name = "Initialize L2P", 156 .action = ftl_mngt_init_l2p, 157 .cleanup = ftl_mngt_deinit_l2p 158 }, 159 { 160 .name = "Clear L2P", 161 .action = ftl_mngt_clear_l2p, 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_trim_metadata_clear, 187 }, 188 { 189 .name = "Clear trim log", 190 .action = ftl_mngt_trim_log_clear, 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 = "Start core poller", 257 .action = ftl_mngt_start_core_poller, 258 .cleanup = ftl_mngt_stop_core_poller 259 }, 260 { 261 .name = "Self test on startup", 262 .action = ftl_mngt_self_test, 263 }, 264 { 265 .name = "Set FTL dirty state", 266 .action = ftl_mngt_set_dirty, 267 }, 268 { 269 .name = "Finalize initialization", 270 .action = ftl_mngt_finalize_startup, 271 }, 272 {} 273 } 274 }; 275 276 int 277 ftl_mngt_call_dev_startup(struct spdk_ftl_dev *dev, ftl_mngt_completion cb, void *cb_cntx) 278 { 279 return ftl_mngt_process_execute(dev, &desc_startup, cb, cb_cntx); 280 } 281 282 struct ftl_trim_ctx { 283 uint64_t lba; 284 uint64_t num_blocks; 285 spdk_ftl_fn cb_fn; 286 void *cb_arg; 287 struct spdk_thread *thread; 288 int status; 289 }; 290 291 static void 292 ftl_mngt_process_trim_cb(void *ctx, int status) 293 { 294 struct ftl_mngt_process *mngt = ctx; 295 296 if (status) { 297 ftl_mngt_fail_step(ctx); 298 } else { 299 ftl_mngt_next_step(mngt); 300 } 301 } 302 303 static void 304 ftl_mngt_process_trim(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 305 { 306 struct ftl_io *io = ftl_mngt_get_process_ctx(mngt); 307 struct ftl_trim_ctx *ctx = ftl_mngt_get_caller_ctx(mngt); 308 int rc; 309 310 if (!dev->ioch) { 311 ftl_mngt_fail_step(mngt); 312 return; 313 } 314 315 rc = spdk_ftl_unmap(dev, io, dev->ioch, ctx->lba, ctx->num_blocks, ftl_mngt_process_trim_cb, mngt); 316 if (rc == -EAGAIN) { 317 ftl_mngt_continue_step(mngt); 318 } 319 } 320 321 /* 322 * RPC trim path. 323 */ 324 static const struct ftl_mngt_process_desc g_desc_trim = { 325 .name = "FTL trim", 326 .ctx_size = sizeof(struct ftl_io), 327 .steps = { 328 { 329 .name = "Process trim", 330 .action = ftl_mngt_process_trim, 331 }, 332 {} 333 } 334 }; 335 336 static void 337 trim_user_cb(void *_ctx) 338 { 339 struct ftl_trim_ctx *ctx = _ctx; 340 341 ctx->cb_fn(ctx->cb_arg, ctx->status); 342 free(ctx); 343 } 344 345 static void 346 ftl_mngt_trim_cb(struct spdk_ftl_dev *dev, void *_ctx, int status) 347 { 348 struct ftl_trim_ctx *ctx = _ctx; 349 ctx->status = status; 350 351 if (spdk_thread_send_msg(ctx->thread, trim_user_cb, ctx)) { 352 ftl_abort(); 353 } 354 } 355 356 int 357 ftl_mngt_trim(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t num_blocks, spdk_ftl_fn cb, 358 void *cb_cntx) 359 { 360 struct ftl_trim_ctx *ctx; 361 362 ctx = calloc(1, sizeof(*ctx)); 363 if (ctx == NULL) { 364 return -EAGAIN; 365 } 366 367 ctx->lba = lba; 368 ctx->num_blocks = num_blocks; 369 ctx->cb_fn = cb; 370 ctx->cb_arg = cb_cntx; 371 ctx->thread = spdk_get_thread(); 372 373 return ftl_mngt_process_execute(dev, &g_desc_trim, ftl_mngt_trim_cb, ctx); 374 } 375 376 void 377 ftl_mngt_rollback_device(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 378 { 379 ftl_mngt_call_process_rollback(mngt, &desc_startup); 380 } 381