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.h" 8 9 #include "ftl_core.h" 10 #include "ftl_utils.h" 11 #include "ftl_band.h" 12 #include "ftl_layout.h" 13 #include "ftl_nv_cache.h" 14 #include "ftl_sb.h" 15 #include "nvc/ftl_nvc_dev.h" 16 #include "utils/ftl_layout_tracker_bdev.h" 17 18 enum ftl_layout_setup_mode { 19 FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT = 0, 20 FTL_LAYOUT_SETUP_MODE_NO_RESTRICT, 21 FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT, 22 }; 23 24 static inline float 25 blocks2mib(uint64_t blocks) 26 { 27 float result; 28 29 result = blocks; 30 result *= FTL_BLOCK_SIZE; 31 result /= 1024UL; 32 result /= 1024UL; 33 34 return result; 35 } 36 37 static uint64_t 38 superblock_region_size(struct spdk_ftl_dev *dev) 39 { 40 const struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc); 41 uint64_t wus = spdk_bdev_get_write_unit_size(bdev) * FTL_BLOCK_SIZE; 42 43 if (wus > FTL_SUPERBLOCK_SIZE) { 44 return wus; 45 } else { 46 return wus * spdk_divide_round_up(FTL_SUPERBLOCK_SIZE, wus); 47 } 48 } 49 50 static uint64_t 51 superblock_region_blocks(struct spdk_ftl_dev *dev) 52 { 53 return superblock_region_size(dev) / FTL_BLOCK_SIZE; 54 } 55 56 uint64_t 57 ftl_md_region_blocks(struct spdk_ftl_dev *dev, uint64_t bytes) 58 { 59 const uint64_t alignment = superblock_region_size(dev); 60 uint64_t result; 61 62 result = spdk_divide_round_up(bytes, alignment); 63 result *= alignment; 64 result /= FTL_BLOCK_SIZE; 65 66 return result; 67 } 68 69 uint64_t 70 ftl_md_region_align_blocks(struct spdk_ftl_dev *dev, uint64_t blocks) 71 { 72 const uint64_t alignment = superblock_region_blocks(dev); 73 uint64_t result; 74 75 result = spdk_divide_round_up(blocks, alignment); 76 result *= alignment; 77 78 return result; 79 } 80 81 const char * 82 ftl_md_region_name(enum ftl_layout_region_type reg_type) 83 { 84 static const char *md_region_name[FTL_LAYOUT_REGION_TYPE_MAX] = { 85 [FTL_LAYOUT_REGION_TYPE_SB] = "sb", 86 [FTL_LAYOUT_REGION_TYPE_SB_BASE] = "sb_mirror", 87 [FTL_LAYOUT_REGION_TYPE_L2P] = "l2p", 88 [FTL_LAYOUT_REGION_TYPE_BAND_MD] = "band_md", 89 [FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = "band_md_mirror", 90 [FTL_LAYOUT_REGION_TYPE_VALID_MAP] = "vmap", 91 [FTL_LAYOUT_REGION_TYPE_NVC_MD] = "nvc_md", 92 [FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = "nvc_md_mirror", 93 [FTL_LAYOUT_REGION_TYPE_DATA_NVC] = "data_nvc", 94 [FTL_LAYOUT_REGION_TYPE_DATA_BASE] = "data_btm", 95 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = "p2l0", 96 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = "p2l1", 97 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = "p2l2", 98 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = "p2l3", 99 [FTL_LAYOUT_REGION_TYPE_TRIM_MD] = "trim_md", 100 [FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = "trim_md_mirror", 101 }; 102 const char *reg_name = md_region_name[reg_type]; 103 104 assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX); 105 assert(reg_name != NULL); 106 return reg_name; 107 } 108 109 static void 110 dump_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *region) 111 { 112 assert(!(region->current.offset % superblock_region_blocks(dev))); 113 assert(!(region->current.blocks % superblock_region_blocks(dev))); 114 115 FTL_NOTICELOG(dev, "Region %s\n", region->name); 116 FTL_NOTICELOG(dev, " offset: %.2f MiB\n", 117 blocks2mib(region->current.offset)); 118 FTL_NOTICELOG(dev, " blocks: %.2f MiB\n", 119 blocks2mib(region->current.blocks)); 120 } 121 122 int 123 ftl_validate_regions(struct spdk_ftl_dev *dev, struct ftl_layout *layout) 124 { 125 enum ftl_layout_region_type i, j; 126 127 /* Validate if regions doesn't overlap each other */ 128 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) { 129 struct ftl_layout_region *r1 = ftl_layout_region_get(dev, i); 130 131 if (!r1) { 132 continue; 133 } 134 135 for (j = 0; j < FTL_LAYOUT_REGION_TYPE_MAX; j++) { 136 struct ftl_layout_region *r2 = ftl_layout_region_get(dev, j); 137 138 if (!r2) { 139 continue; 140 } 141 142 if (r1->bdev_desc != r2->bdev_desc) { 143 continue; 144 } 145 146 if (i == j) { 147 continue; 148 } 149 150 uint64_t r1_begin = r1->current.offset; 151 uint64_t r1_end = r1->current.offset + r1->current.blocks - 1; 152 uint64_t r2_begin = r2->current.offset; 153 uint64_t r2_end = r2->current.offset + r2->current.blocks - 1; 154 155 if (spdk_max(r1_begin, r2_begin) <= spdk_min(r1_end, r2_end)) { 156 FTL_ERRLOG(dev, "Layout initialization ERROR, two regions overlap, " 157 "%s and %s\n", r1->name, r2->name); 158 return -1; 159 } 160 } 161 } 162 163 return 0; 164 } 165 166 static uint64_t 167 get_num_user_lbas(struct spdk_ftl_dev *dev) 168 { 169 uint64_t blocks; 170 171 blocks = dev->num_bands * ftl_get_num_blocks_in_band(dev); 172 blocks = (blocks * (100 - dev->conf.overprovisioning)) / 100; 173 174 return blocks; 175 } 176 177 static uint64_t 178 layout_blocks_left(struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker) 179 { 180 uint64_t max_reg_size = 0; 181 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 182 183 while (true) { 184 ftl_layout_tracker_bdev_find_next_region(layout_tracker, FTL_LAYOUT_REGION_TYPE_FREE, 185 ®_search_ctx); 186 if (!reg_search_ctx) { 187 break; 188 } 189 max_reg_size = spdk_max(max_reg_size, reg_search_ctx->blk_sz); 190 } 191 return max_reg_size; 192 } 193 194 struct ftl_layout_region * 195 ftl_layout_region_get(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type) 196 { 197 struct ftl_layout_region *reg = &dev->layout.region[reg_type]; 198 199 assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX); 200 return reg->type == reg_type ? reg : NULL; 201 } 202 203 uint64_t 204 ftl_layout_base_offset(struct spdk_ftl_dev *dev) 205 { 206 return dev->num_bands * ftl_get_num_blocks_in_band(dev); 207 } 208 209 static int 210 layout_region_create_nvc(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 211 uint32_t reg_version, size_t entry_size, size_t entry_count) 212 { 213 const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_desc->ops.md_layout_ops; 214 size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size); 215 216 if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) { 217 return -1; 218 } 219 if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, 220 &dev->layout.region[reg_type])) { 221 return -1; 222 } 223 return 0; 224 } 225 226 static int 227 layout_region_create_base(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 228 uint32_t reg_version, size_t entry_size, size_t entry_count) 229 { 230 const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops; 231 size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size); 232 233 if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) { 234 return -1; 235 } 236 if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, 237 &dev->layout.region[reg_type])) { 238 return -1; 239 } 240 return 0; 241 } 242 243 static void 244 legacy_layout_verify_region(struct ftl_layout_tracker_bdev *layout_tracker, 245 enum ftl_layout_region_type reg_type, uint32_t reg_version) 246 { 247 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 248 const struct ftl_layout_tracker_bdev_region_props *reg_found = NULL; 249 250 while (true) { 251 ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 252 if (!reg_search_ctx) { 253 break; 254 } 255 256 /* Only a single region version is present in upgrade from the legacy layout */ 257 ftl_bug(reg_search_ctx->ver != reg_version); 258 ftl_bug(reg_found != NULL); 259 260 reg_found = reg_search_ctx; 261 } 262 } 263 264 static int 265 legacy_layout_region_open_nvc(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 266 uint32_t reg_version, size_t entry_size, size_t entry_count) 267 { 268 struct ftl_layout_region *reg = &dev->layout.region[reg_type]; 269 const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_desc->ops.md_layout_ops; 270 271 legacy_layout_verify_region(dev->nvc_layout_tracker, reg_type, reg_version); 272 return md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, reg); 273 } 274 275 static int 276 legacy_layout_region_open_base(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 277 uint32_t reg_version, size_t entry_size, size_t entry_count) 278 { 279 struct ftl_layout_region *reg = &dev->layout.region[reg_type]; 280 const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops; 281 282 legacy_layout_verify_region(dev->nvc_layout_tracker, reg_type, reg_version); 283 return md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, reg); 284 } 285 286 static int 287 layout_setup_legacy_default_nvc(struct spdk_ftl_dev *dev) 288 { 289 int region_type; 290 uint64_t blocks, chunk_count; 291 struct ftl_layout *layout = &dev->layout; 292 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 293 294 /* Initialize L2P region */ 295 blocks = ftl_md_region_blocks(dev, layout->l2p.addr_size * dev->num_lbas); 296 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_L2P, 0, FTL_BLOCK_SIZE, 297 blocks)) { 298 goto error; 299 } 300 301 /* Initialize band info metadata */ 302 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD, FTL_BAND_VERSION_1, 303 sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) { 304 goto error; 305 } 306 307 /* Initialize band info metadata mirror */ 308 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, FTL_BAND_VERSION_1, 309 sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) { 310 goto error; 311 } 312 layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR; 313 314 /* 315 * Initialize P2L checkpointing regions 316 */ 317 for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN; 318 region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX; 319 region_type++) { 320 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 321 322 /* Get legacy number of blocks */ 323 ftl_layout_tracker_bdev_find_next_region(dev->nvc_layout_tracker, region_type, ®_search_ctx); 324 if (!reg_search_ctx || reg_search_ctx->ver != FTL_P2L_VERSION_1) { 325 goto error; 326 } 327 blocks = reg_search_ctx->blk_sz; 328 329 if (legacy_layout_region_open_nvc(dev, region_type, FTL_P2L_VERSION_1, FTL_BLOCK_SIZE, blocks)) { 330 goto error; 331 } 332 } 333 334 /* 335 * Initialize trim metadata region 336 */ 337 blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks; 338 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD, 0, sizeof(uint64_t), 339 blocks)) { 340 goto error; 341 } 342 343 /* Initialize trim metadata mirror region */ 344 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, 0, sizeof(uint64_t), 345 blocks)) { 346 goto error; 347 } 348 layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR; 349 350 /* Restore chunk count */ 351 ftl_layout_tracker_bdev_find_next_region(dev->nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_DATA_NVC, 352 ®_search_ctx); 353 if (!reg_search_ctx || reg_search_ctx->ver != 0) { 354 goto error; 355 } 356 blocks = reg_search_ctx->blk_sz; 357 chunk_count = blocks / ftl_get_num_blocks_in_band(dev); 358 if (0 == chunk_count) { 359 goto error; 360 } 361 362 /* 363 * Initialize NV Cache metadata 364 */ 365 if (0 == chunk_count) { 366 goto error; 367 } 368 layout->nvc.chunk_count = chunk_count; 369 370 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD, FTL_NVC_VERSION_1, 371 sizeof(struct ftl_nv_cache_chunk_md), chunk_count)) { 372 goto error; 373 } 374 375 /* 376 * Initialize NV Cache metadata mirror 377 */ 378 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, FTL_NVC_VERSION_1, 379 sizeof(struct ftl_nv_cache_chunk_md), chunk_count)) { 380 goto error; 381 } 382 layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR; 383 384 /* 385 * Initialize data region on NV cache 386 */ 387 if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_DATA_NVC, 0, 388 layout->nvc.chunk_data_blocks * FTL_BLOCK_SIZE, chunk_count)) { 389 goto error; 390 } 391 392 return 0; 393 394 error: 395 FTL_ERRLOG(dev, "Invalid legacy NV Cache metadata layout\n"); 396 return -1; 397 } 398 399 static int 400 layout_setup_legacy_default_base(struct spdk_ftl_dev *dev) 401 { 402 struct ftl_layout *layout = &dev->layout; 403 404 /* Base device layout is as follows: 405 * - superblock 406 * - data 407 * - valid map 408 */ 409 if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE, 410 ftl_layout_base_offset(dev))) { 411 return -1; 412 } 413 414 if (legacy_layout_region_open_base(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP, 0, FTL_BLOCK_SIZE, 415 ftl_md_region_blocks(dev, spdk_divide_round_up(layout->base.total_blocks + layout->nvc.total_blocks, 416 8)))) { 417 return -1; 418 } 419 420 return 0; 421 } 422 423 static int 424 layout_setup_legacy_default(struct spdk_ftl_dev *dev) 425 { 426 if (layout_setup_legacy_default_nvc(dev) || layout_setup_legacy_default_base(dev)) { 427 return -1; 428 } 429 return 0; 430 } 431 432 static int 433 layout_setup_default_nvc(struct spdk_ftl_dev *dev) 434 { 435 int region_type; 436 uint64_t left, l2p_blocks; 437 struct ftl_layout *layout = &dev->layout; 438 439 /* Initialize L2P region */ 440 l2p_blocks = ftl_md_region_blocks(dev, layout->l2p.addr_size * dev->num_lbas); 441 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_L2P, 0, FTL_BLOCK_SIZE, l2p_blocks)) { 442 goto error; 443 } 444 445 /* Initialize band info metadata */ 446 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD, FTL_BAND_VERSION_CURRENT, 447 sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) { 448 goto error; 449 } 450 451 /* Initialize band info metadata mirror */ 452 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, FTL_BAND_VERSION_CURRENT, 453 sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) { 454 goto error; 455 } 456 layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR; 457 458 /* 459 * Initialize P2L checkpointing regions 460 */ 461 for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN; 462 region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX; 463 region_type++) { 464 if (layout_region_create_nvc(dev, region_type, FTL_P2L_VERSION_CURRENT, FTL_BLOCK_SIZE, 465 layout->p2l.ckpt_pages)) { 466 goto error; 467 } 468 } 469 470 /* 471 * Initialize trim metadata region 472 */ 473 l2p_blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks; 474 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD, 0, sizeof(uint64_t), 475 l2p_blocks)) { 476 goto error; 477 } 478 479 /* Initialize trim metadata mirror region */ 480 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, 0, sizeof(uint64_t), 481 l2p_blocks)) { 482 goto error; 483 } 484 layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR; 485 486 /* 487 * Initialize NV Cache metadata 488 */ 489 left = layout_blocks_left(dev, dev->nvc_layout_tracker); 490 layout->nvc.chunk_count = (left * FTL_BLOCK_SIZE) / 491 FTL_NV_CACHE_CHUNK_SIZE(ftl_get_num_blocks_in_band(dev)); 492 if (0 == layout->nvc.chunk_count) { 493 goto error; 494 } 495 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD, FTL_NVC_VERSION_CURRENT, 496 sizeof(struct ftl_nv_cache_chunk_md), layout->nvc.chunk_count)) { 497 goto error; 498 } 499 500 /* 501 * Initialize NV Cache metadata mirror 502 */ 503 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, FTL_NVC_VERSION_CURRENT, 504 sizeof(struct ftl_nv_cache_chunk_md), layout->nvc.chunk_count)) { 505 goto error; 506 } 507 layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR; 508 509 /* 510 * Initialize data region on NV cache 511 */ 512 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_DATA_NVC, 0, 513 layout->nvc.chunk_data_blocks * FTL_BLOCK_SIZE, layout->nvc.chunk_count)) { 514 goto error; 515 } 516 517 return 0; 518 519 error: 520 FTL_ERRLOG(dev, "Insufficient NV Cache capacity to preserve metadata\n"); 521 return -1; 522 } 523 524 static int 525 layout_setup_default_base(struct spdk_ftl_dev *dev) 526 { 527 struct ftl_layout *layout = &dev->layout; 528 uint64_t valid_map_size; 529 530 /* Base device layout is as follows: 531 * - superblock 532 * - data 533 * - valid map 534 */ 535 if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE, 536 ftl_layout_base_offset(dev))) { 537 return -1; 538 } 539 540 valid_map_size = spdk_divide_round_up(layout->base.total_blocks + layout->nvc.total_blocks, 8); 541 if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP, 0, FTL_BLOCK_SIZE, 542 ftl_md_region_blocks(dev, valid_map_size))) { 543 return -1; 544 } 545 546 return 0; 547 } 548 549 static int 550 layout_setup_default(struct spdk_ftl_dev *dev) 551 { 552 if (layout_setup_default_nvc(dev) || layout_setup_default_base(dev)) { 553 return -1; 554 } 555 return 0; 556 } 557 558 static int 559 layout_load(struct spdk_ftl_dev *dev) 560 { 561 if (ftl_superblock_load_blob_area(dev)) { 562 return -1; 563 } 564 dev->layout.nvc.chunk_count = dev->layout.region[FTL_LAYOUT_REGION_TYPE_DATA_NVC].num_entries; 565 if (ftl_superblock_md_layout_apply(dev)) { 566 return -1; 567 } 568 return 0; 569 } 570 571 int 572 ftl_layout_setup(struct spdk_ftl_dev *dev) 573 { 574 struct ftl_layout *layout = &dev->layout; 575 uint64_t i; 576 uint64_t num_lbas; 577 enum ftl_layout_setup_mode setup_mode; 578 int rc; 579 580 /* 581 * SB v5 adds the ability to create MD regions dynamically, i.e. depending on the underlying device type. 582 * For compatibility reasons: 583 * 1. When upgrading from pre-v5 SB, only the legacy default layout is created. 584 * Pre-v5: some regions were static and not stored in the SB layout. These must be created to match 585 * the legacy default layout. 586 * v5: all regions are stored in the SB layout. Upon the SB upgrade, the legacy default layout 587 * is updated with pre-v5 layout stored in the SB. The whole layout is then stored in v5 SB. 588 * 589 * 2. When SB v5 or later was loaded, the layout is instantiated from the nvc and base layout blobs. 590 * No default layout is created. 591 * 592 * 3. When the FTL layout is being created for the first time, there are no restrictions. 593 * 594 * Any new regions to be created in cases (1) and (2) can only be placed in the unallocated area 595 * of the underlying device. 596 */ 597 598 if (dev->conf.mode & SPDK_FTL_MODE_CREATE) { 599 setup_mode = FTL_LAYOUT_SETUP_MODE_NO_RESTRICT; 600 } else if (ftl_superblock_is_blob_area_empty(dev->sb)) { 601 setup_mode = FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT; 602 } else { 603 setup_mode = FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT; 604 } 605 FTL_NOTICELOG(dev, "FTL layout setup mode %d\n", (int)setup_mode); 606 607 /* Invalidate all regions */ 608 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) { 609 if (i == FTL_LAYOUT_REGION_TYPE_SB || i == FTL_LAYOUT_REGION_TYPE_SB_BASE) { 610 /* Super block has been already initialized */ 611 continue; 612 } 613 614 layout->region[i].mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID; 615 /* Mark the region inactive */ 616 layout->region[i].type = FTL_LAYOUT_REGION_TYPE_INVALID; 617 } 618 619 /* 620 * Initialize L2P information 621 */ 622 num_lbas = get_num_user_lbas(dev); 623 if (dev->num_lbas == 0) { 624 assert(dev->conf.mode & SPDK_FTL_MODE_CREATE); 625 dev->num_lbas = num_lbas; 626 dev->sb->lba_cnt = num_lbas; 627 } else if (dev->num_lbas != num_lbas) { 628 FTL_ERRLOG(dev, "Mismatched FTL num_lbas\n"); 629 return -EINVAL; 630 } 631 layout->l2p.addr_length = spdk_u64log2(layout->base.total_blocks + layout->nvc.total_blocks) + 1; 632 layout->l2p.addr_size = layout->l2p.addr_length > 32 ? 8 : 4; 633 layout->l2p.lbas_in_page = FTL_BLOCK_SIZE / layout->l2p.addr_size; 634 635 /* Setup P2L ckpt */ 636 layout->p2l.ckpt_pages = spdk_divide_round_up(ftl_get_num_blocks_in_band(dev), dev->xfer_size); 637 638 layout->nvc.chunk_data_blocks = 639 FTL_NV_CACHE_CHUNK_DATA_SIZE(ftl_get_num_blocks_in_band(dev)) / FTL_BLOCK_SIZE; 640 layout->nvc.chunk_meta_size = FTL_NV_CACHE_CHUNK_MD_SIZE; 641 layout->nvc.chunk_tail_md_num_blocks = ftl_nv_cache_chunk_tail_md_num_blocks(&dev->nv_cache); 642 643 layout->base.num_usable_blocks = ftl_get_num_blocks_in_band(dev); 644 layout->base.user_blocks = ftl_band_user_blocks(dev->bands); 645 646 switch (setup_mode) { 647 case FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT: 648 if (layout_setup_legacy_default(dev)) { 649 return -EINVAL; 650 } 651 break; 652 653 case FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT: 654 if (layout_load(dev)) { 655 return -EINVAL; 656 } 657 break; 658 659 case FTL_LAYOUT_SETUP_MODE_NO_RESTRICT: 660 if (layout_setup_default(dev)) { 661 return -EINVAL; 662 } 663 break; 664 665 default: 666 ftl_abort(); 667 break; 668 } 669 670 if (ftl_validate_regions(dev, layout)) { 671 return -EINVAL; 672 } 673 674 rc = ftl_superblock_store_blob_area(dev); 675 676 FTL_NOTICELOG(dev, "Base device capacity: %.2f MiB\n", 677 blocks2mib(layout->base.total_blocks)); 678 FTL_NOTICELOG(dev, "NV cache device capacity: %.2f MiB\n", 679 blocks2mib(layout->nvc.total_blocks)); 680 FTL_NOTICELOG(dev, "L2P entries: %"PRIu64"\n", dev->num_lbas); 681 FTL_NOTICELOG(dev, "L2P address size: %"PRIu64"\n", layout->l2p.addr_size); 682 FTL_NOTICELOG(dev, "P2L checkpoint pages: %"PRIu64"\n", layout->p2l.ckpt_pages); 683 FTL_NOTICELOG(dev, "NV cache chunk count %"PRIu64"\n", dev->layout.nvc.chunk_count); 684 685 return rc; 686 } 687 688 int 689 ftl_layout_setup_superblock(struct spdk_ftl_dev *dev) 690 { 691 const struct spdk_bdev *bdev; 692 struct ftl_layout *layout = &dev->layout; 693 struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB]; 694 uint64_t total_blocks, offset, left; 695 696 assert(layout->md[FTL_LAYOUT_REGION_TYPE_SB] == NULL); 697 698 bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc); 699 layout->base.total_blocks = spdk_bdev_get_num_blocks(bdev); 700 701 bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc); 702 layout->nvc.total_blocks = spdk_bdev_get_num_blocks(bdev); 703 704 /* Initialize superblock region */ 705 if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_SB, FTL_SB_VERSION_CURRENT, 706 superblock_region_size(dev), 1)) { 707 FTL_ERRLOG(dev, "Error when setting up primary super block\n"); 708 return -1; 709 } 710 711 assert(region->bdev_desc != NULL); 712 assert(region->ioch != NULL); 713 assert(region->current.offset == 0); 714 715 if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_SB_BASE, FTL_SB_VERSION_CURRENT, 716 superblock_region_size(dev), 1)) { 717 FTL_ERRLOG(dev, "Error when setting up secondary super block\n"); 718 return -1; 719 } 720 layout->region[FTL_LAYOUT_REGION_TYPE_SB].mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE; 721 722 region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE]; 723 assert(region->current.offset == 0); 724 725 /* Check if SB can be stored at the end of base device */ 726 total_blocks = spdk_bdev_get_num_blocks( 727 spdk_bdev_desc_get_bdev(dev->base_bdev_desc)); 728 offset = region->current.offset + region->current.blocks; 729 left = total_blocks - offset; 730 if ((left > total_blocks) || (offset > total_blocks)) { 731 FTL_ERRLOG(dev, "Error when setup base device super block\n"); 732 return -1; 733 } 734 735 return 0; 736 } 737 738 int 739 ftl_layout_clear_superblock(struct spdk_ftl_dev *dev) 740 { 741 int rc; 742 743 rc = ftl_layout_tracker_bdev_rm_region(dev->nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB, 744 FTL_SB_VERSION_CURRENT); 745 if (rc) { 746 return rc; 747 } 748 749 return ftl_layout_tracker_bdev_rm_region(dev->base_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB_BASE, 750 FTL_SB_VERSION_CURRENT); 751 } 752 753 void 754 ftl_layout_dump(struct spdk_ftl_dev *dev) 755 { 756 struct ftl_layout_region *reg; 757 enum ftl_layout_region_type i; 758 759 FTL_NOTICELOG(dev, "NV cache layout:\n"); 760 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) { 761 reg = ftl_layout_region_get(dev, i); 762 if (reg && reg->bdev_desc == dev->nv_cache.bdev_desc) { 763 dump_region(dev, reg); 764 } 765 } 766 FTL_NOTICELOG(dev, "Base device layout:\n"); 767 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) { 768 reg = ftl_layout_region_get(dev, i); 769 if (reg && reg->bdev_desc == dev->base_bdev_desc) { 770 dump_region(dev, reg); 771 } 772 } 773 } 774 775 uint64_t 776 ftl_layout_base_md_blocks(struct spdk_ftl_dev *dev) 777 { 778 const struct spdk_bdev *bdev; 779 uint64_t md_blocks = 0, total_blocks = 0; 780 781 bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc); 782 total_blocks += spdk_bdev_get_num_blocks(bdev); 783 784 bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc); 785 total_blocks += spdk_bdev_get_num_blocks(bdev); 786 787 /* Count space needed for validity map */ 788 md_blocks += ftl_md_region_blocks(dev, spdk_divide_round_up(total_blocks, 8)); 789 790 /* Count space needed for superblock */ 791 md_blocks += superblock_region_blocks(dev); 792 return md_blocks; 793 } 794 795 struct layout_blob_entry { 796 uint32_t type; 797 uint64_t entry_size; 798 uint64_t num_entries; 799 } __attribute__((packed)); 800 801 size_t 802 ftl_layout_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz) 803 { 804 struct layout_blob_entry *blob_entry = blob_buf; 805 struct ftl_layout_region *reg; 806 enum ftl_layout_region_type reg_type; 807 size_t blob_sz = 0; 808 809 for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) { 810 if (blob_sz + sizeof(*blob_entry) > blob_buf_sz) { 811 return 0; 812 } 813 814 reg = &dev->layout.region[reg_type]; 815 blob_entry->type = reg_type; 816 blob_entry->entry_size = reg->entry_size; 817 blob_entry->num_entries = reg->num_entries; 818 819 blob_entry++; 820 blob_sz += sizeof(*blob_entry); 821 } 822 823 return blob_sz; 824 } 825 826 int 827 ftl_layout_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz) 828 { 829 struct layout_blob_entry *blob_entry = blob_buf; 830 size_t blob_entry_num = blob_sz / sizeof(*blob_entry); 831 struct layout_blob_entry *blob_entry_end = blob_entry + blob_entry_num; 832 struct ftl_layout_region *reg; 833 834 if (blob_sz % sizeof(*blob_entry) != 0) { 835 /* Invalid blob size */ 836 return -1; 837 } 838 839 for (; blob_entry < blob_entry_end; blob_entry++) { 840 /* Verify the type */ 841 if (blob_entry->type >= FTL_LAYOUT_REGION_TYPE_MAX) { 842 return -1; 843 } 844 845 /* Load the entry */ 846 reg = &dev->layout.region[blob_entry->type]; 847 reg->entry_size = blob_entry->entry_size; 848 reg->num_entries = blob_entry->num_entries; 849 } 850 851 return 0; 852 } 853