1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2023 Solidigm All Rights Reserved 3 * All rights reserved. 4 */ 5 6 #include "spdk/string.h" 7 8 #include "ftl_sb_v5.h" 9 #include "ftl_core.h" 10 #include "ftl_layout.h" 11 #include "ftl_band.h" 12 #include "upgrade/ftl_sb_prev.h" 13 #include "upgrade/ftl_sb_upgrade.h" 14 #include "upgrade/ftl_layout_upgrade.h" 15 #include "utils/ftl_layout_tracker_bdev.h" 16 17 typedef size_t (*blob_store_fn)(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz); 18 typedef int (*blob_load_fn)(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz); 19 20 bool 21 ftl_superblock_v5_is_blob_area_empty(union ftl_superblock_ver *sb_ver) 22 { 23 return sb_ver->v5.blob_area_end == 0; 24 } 25 26 static bool 27 validate_blob_area(struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr, 28 ftl_df_obj_id sb_blob_area_end) 29 { 30 return sb_blob_hdr->df_id <= sb_blob_area_end && 31 (sb_blob_hdr->df_id + sb_blob_hdr->blob_sz) <= sb_blob_area_end; 32 } 33 34 bool 35 ftl_superblock_v5_validate_blob_area(struct spdk_ftl_dev *dev) 36 { 37 union ftl_superblock_ver *sb_ver = (union ftl_superblock_ver *)dev->sb; 38 39 return validate_blob_area(&sb_ver->v5.md_layout_nvc, sb_ver->v5.blob_area_end) && 40 validate_blob_area(&sb_ver->v5.md_layout_base, sb_ver->v5.blob_area_end) && 41 validate_blob_area(&sb_ver->v5.layout_params, sb_ver->v5.blob_area_end); 42 } 43 44 static size_t 45 sb_blob_store(struct spdk_ftl_dev *dev, struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr, 46 blob_store_fn blob_store, void *sb_blob_area) 47 { 48 struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb; 49 uintptr_t sb_end = ((uintptr_t)sb) + FTL_SUPERBLOCK_SIZE; 50 size_t blob_sz = sb_end - (uintptr_t)sb_blob_area; 51 52 /* Test SB blob area overflow */ 53 if ((uintptr_t)sb_blob_area < (uintptr_t)sb->blob_area) { 54 ftl_bug(true); 55 return 0; 56 } 57 if ((uintptr_t)sb_blob_area >= sb_end) { 58 ftl_bug(true); 59 return 0; 60 } 61 62 blob_sz = blob_store(dev, sb_blob_area, blob_sz); 63 sb_blob_hdr->blob_sz = blob_sz; 64 sb_blob_hdr->df_id = ftl_df_get_obj_id(sb->blob_area, sb_blob_area); 65 return blob_sz; 66 } 67 68 static size_t 69 base_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz) 70 { 71 return ftl_layout_tracker_bdev_blob_store(dev->base_layout_tracker, blob_buf, blob_buf_sz); 72 } 73 74 static size_t 75 nvc_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz) 76 { 77 return ftl_layout_tracker_bdev_blob_store(dev->nvc_layout_tracker, blob_buf, blob_buf_sz); 78 } 79 80 int 81 ftl_superblock_v5_store_blob_area(struct spdk_ftl_dev *dev) 82 { 83 struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb; 84 void *sb_blob_area; 85 size_t blob_sz; 86 87 /* Store the NVC-backed FTL MD layout info */ 88 sb_blob_area = ftl_df_get_obj_ptr(sb->blob_area, 0); 89 spdk_strcpy_pad(sb->nvc_dev_name, dev->nv_cache.nvc_desc->name, 90 SPDK_COUNTOF(sb->nvc_dev_name), '\0'); 91 blob_sz = sb_blob_store(dev, &sb->md_layout_nvc, nvc_blob_store, sb_blob_area); 92 FTL_NOTICELOG(dev, "nvc layout blob store 0x%"PRIx64" bytes\n", blob_sz); 93 if (!blob_sz) { 94 return -1; 95 } 96 97 /* Store the base dev-backed FTL MD layout info */ 98 sb_blob_area += blob_sz; 99 spdk_strcpy_pad(sb->base_dev_name, dev->base_type->name, SPDK_COUNTOF(sb->base_dev_name), '\0'); 100 blob_sz = sb_blob_store(dev, &sb->md_layout_base, base_blob_store, sb_blob_area); 101 FTL_NOTICELOG(dev, "base layout blob store 0x%"PRIx64" bytes\n", blob_sz); 102 if (!blob_sz) { 103 return -1; 104 } 105 106 /* Store the region props */ 107 sb_blob_area += blob_sz; 108 blob_sz = sb_blob_store(dev, &sb->layout_params, ftl_layout_blob_store, sb_blob_area); 109 FTL_NOTICELOG(dev, "layout blob store 0x%"PRIx64" bytes\n", blob_sz); 110 if (!blob_sz) { 111 return -1; 112 } 113 114 /* Update the blob area end */ 115 sb_blob_area += blob_sz; 116 sb->blob_area_end = ftl_df_get_obj_id(sb->blob_area, sb_blob_area); 117 118 return 0; 119 } 120 121 static const struct ftl_layout_tracker_bdev_region_props * 122 sb_md_layout_find_oldest_region(struct spdk_ftl_dev *dev, 123 struct ftl_layout_tracker_bdev *layout_tracker, 124 enum ftl_layout_region_type reg_type, void *find_filter) 125 { 126 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 127 const struct ftl_layout_tracker_bdev_region_props *reg_oldest = NULL; 128 uint32_t ver_oldest; 129 130 while (true) { 131 ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 132 if (!reg_search_ctx) { 133 break; 134 } 135 136 if (!reg_oldest) { 137 reg_oldest = reg_search_ctx; 138 ver_oldest = reg_search_ctx->ver; 139 continue; 140 } 141 142 ftl_bug(ver_oldest == reg_search_ctx->ver); 143 if (ver_oldest > reg_search_ctx->ver) { 144 reg_oldest = reg_search_ctx; 145 ver_oldest = reg_search_ctx->ver; 146 } 147 } 148 149 return reg_oldest; 150 } 151 152 static const struct ftl_layout_tracker_bdev_region_props * 153 sb_md_layout_find_latest_region(struct spdk_ftl_dev *dev, 154 struct ftl_layout_tracker_bdev *layout_tracker, enum ftl_layout_region_type reg_type, 155 void *find_filter) 156 { 157 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 158 const struct ftl_layout_tracker_bdev_region_props *reg_latest = NULL; 159 uint32_t ver_latest; 160 161 while (true) { 162 ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 163 if (!reg_search_ctx) { 164 break; 165 } 166 167 if (!reg_latest) { 168 reg_latest = reg_search_ctx; 169 ver_latest = reg_search_ctx->ver; 170 continue; 171 } 172 173 ftl_bug(ver_latest == reg_search_ctx->ver); 174 if (ver_latest < reg_search_ctx->ver) { 175 reg_latest = reg_search_ctx; 176 ver_latest = reg_search_ctx->ver; 177 } 178 } 179 180 return reg_latest; 181 } 182 183 static const struct ftl_layout_tracker_bdev_region_props * 184 sb_md_layout_find_region_version(struct spdk_ftl_dev *dev, 185 struct ftl_layout_tracker_bdev *layout_tracker, enum ftl_layout_region_type reg_type, 186 void *find_filter) 187 { 188 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 189 uint32_t *reg_ver = find_filter; 190 191 assert(reg_ver); 192 193 while (true) { 194 ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 195 if (!reg_search_ctx) { 196 break; 197 } 198 199 if (reg_search_ctx->ver == *reg_ver) { 200 break; 201 } 202 } 203 204 return reg_search_ctx; 205 } 206 207 typedef const struct ftl_layout_tracker_bdev_region_props *(*sb_md_layout_find_fn)( 208 struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker, 209 enum ftl_layout_region_type reg_type, void *find_filter); 210 211 static const struct ftl_layout_tracker_bdev_region_props * 212 sb_md_layout_find_region(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 213 sb_md_layout_find_fn find_fn, void *find_filter) 214 { 215 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx; 216 struct ftl_layout_tracker_bdev *nvc_layout_tracker = dev->nvc_layout_tracker; 217 struct ftl_layout_tracker_bdev *base_layout_tracker = dev->base_layout_tracker; 218 219 reg_search_ctx = find_fn(dev, nvc_layout_tracker, reg_type, find_filter); 220 if (reg_search_ctx) { 221 assert(find_fn(dev, base_layout_tracker, reg_type, find_filter) == NULL); 222 return reg_search_ctx; 223 } 224 225 reg_search_ctx = find_fn(dev, base_layout_tracker, reg_type, find_filter); 226 return reg_search_ctx; 227 } 228 229 static int 230 sb_blob_load(struct spdk_ftl_dev *dev, struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr, 231 blob_load_fn blob_load) 232 { 233 struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb; 234 uintptr_t sb_end = ((uintptr_t)sb) + FTL_SUPERBLOCK_SIZE; 235 void *blob_area; 236 237 if (sb_blob_hdr->df_id == FTL_DF_OBJ_ID_INVALID) { 238 /* Uninitialized blob */ 239 return -1; 240 } 241 242 blob_area = ftl_df_get_obj_ptr(sb->blob_area, sb_blob_hdr->df_id); 243 244 /* Test SB blob area overflow */ 245 if ((uintptr_t)blob_area < (uintptr_t)sb->blob_area) { 246 ftl_bug(true); 247 return -1; 248 } 249 if ((uintptr_t)blob_area + sb_blob_hdr->blob_sz >= sb_end) { 250 ftl_bug(true); 251 return -1; 252 } 253 254 return blob_load(dev, blob_area, sb_blob_hdr->blob_sz); 255 } 256 257 static int 258 base_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz) 259 { 260 return ftl_layout_tracker_bdev_blob_load(dev->base_layout_tracker, blob_buf, blob_sz); 261 } 262 263 static int 264 nvc_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz) 265 { 266 return ftl_layout_tracker_bdev_blob_load(dev->nvc_layout_tracker, blob_buf, blob_sz); 267 } 268 269 int 270 ftl_superblock_v5_load_blob_area(struct spdk_ftl_dev *dev) 271 { 272 struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb; 273 274 /* Load the NVC-backed FTL MD layout info */ 275 if (strncmp(sb->nvc_dev_name, dev->nv_cache.nvc_desc->name, SPDK_COUNTOF(sb->nvc_dev_name))) { 276 return -1; 277 } 278 FTL_NOTICELOG(dev, "nvc layout blob load 0x%"PRIx64" bytes\n", (uint64_t)sb->md_layout_nvc.blob_sz); 279 if (sb_blob_load(dev, &sb->md_layout_nvc, nvc_blob_load)) { 280 return -1; 281 } 282 283 /* Load the base dev-backed FTL MD layout info */ 284 if (strncmp(sb->base_dev_name, dev->base_type->name, SPDK_COUNTOF(sb->base_dev_name))) { 285 return -1; 286 } 287 FTL_NOTICELOG(dev, "base layout blob load 0x%"PRIx64" bytes\n", 288 (uint64_t)sb->md_layout_base.blob_sz); 289 if (sb_blob_load(dev, &sb->md_layout_base, base_blob_load)) { 290 return -1; 291 } 292 293 /* Load the region props */ 294 FTL_NOTICELOG(dev, "layout blob load 0x%"PRIx64" bytes\n", (uint64_t)sb->layout_params.blob_sz); 295 if (sb_blob_load(dev, &sb->layout_params, ftl_layout_blob_load)) { 296 return -1; 297 } 298 299 return 0; 300 } 301 302 static struct ftl_layout_tracker_bdev * 303 sb_get_md_layout_tracker(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg) 304 { 305 return (reg->bdev_desc == dev->base_bdev_desc) ? dev->base_layout_tracker : dev->nvc_layout_tracker; 306 } 307 308 static void 309 sb_md_layout_delete_prev_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg) 310 { 311 int rc; 312 struct ftl_layout_tracker_bdev *layout_tracker = sb_get_md_layout_tracker(dev, reg); 313 314 rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg->type, reg->current.version); 315 ftl_bug(rc != 0); 316 } 317 318 static void 319 sb_md_layout_update_prev_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg, 320 uint32_t new_version) 321 { 322 int rc; 323 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 324 struct ftl_layout_tracker_bdev *layout_tracker = sb_get_md_layout_tracker(dev, reg); 325 struct ftl_layout_tracker_bdev_region_props reg_props; 326 327 /* Get region properties */ 328 ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg->type, ®_search_ctx); 329 ftl_bug(reg_search_ctx == NULL); 330 reg_props = *reg_search_ctx; 331 332 /* Delete the region */ 333 rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg_props.type, reg_props.ver); 334 ftl_bug(rc != 0); 335 336 /* Insert the same region with new version */ 337 reg_search_ctx = ftl_layout_tracker_bdev_insert_region(layout_tracker, reg_props.type, new_version, 338 reg_props.blk_offs, reg_props.blk_sz); 339 ftl_bug(reg_search_ctx == NULL); 340 341 /* Verify the oldest region version stored in the SB is the new_version */ 342 reg_search_ctx = sb_md_layout_find_region(dev, reg_props.type, sb_md_layout_find_oldest_region, 343 NULL); 344 ftl_bug(reg_search_ctx == NULL); 345 ftl_bug(reg_search_ctx->ver != new_version); 346 } 347 348 int 349 ftl_superblock_v5_md_layout_upgrade_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg, 350 uint32_t new_version) 351 { 352 const struct ftl_layout_tracker_bdev_region_props *reg_next = NULL; 353 uint64_t latest_ver; 354 355 ftl_bug(reg->current.version >= new_version); 356 357 reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_region_version, &new_version); 358 if (reg_next) { 359 /** 360 * Major upgrade. 361 * Found a new MD region allocated for upgrade to the next version. 362 * Destroy the previous version now that the upgrade is completed. 363 */ 364 ftl_bug(reg_next->ver != new_version); 365 ftl_bug(reg_next->type != reg->type); 366 sb_md_layout_delete_prev_region(dev, reg); 367 reg->current.offset = reg_next->blk_offs; 368 reg->current.blocks = reg_next->blk_sz; 369 } else { 370 /** 371 * Minor upgrade. 372 * Upgraded the MD region in place. 373 * Update the version in place. 374 */ 375 sb_md_layout_update_prev_region(dev, reg, new_version); 376 } 377 378 reg->current.version = new_version; 379 latest_ver = ftl_layout_upgrade_region_get_latest_version(reg->type); 380 if (new_version == latest_ver) { 381 /* Audit the only region version stored in the SB */ 382 reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_latest_region, NULL); 383 ftl_bug(reg_next == NULL); 384 ftl_bug(reg_next->ver != new_version); 385 386 reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_oldest_region, NULL); 387 ftl_bug(reg_next == NULL); 388 ftl_bug(reg_next->ver != new_version); 389 390 reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_region_version, &new_version); 391 ftl_bug(reg->type != reg_next->type); 392 ftl_bug(reg->current.version != reg_next->ver); 393 ftl_bug(reg->current.offset != reg_next->blk_offs); 394 ftl_bug(reg->current.blocks != reg_next->blk_sz); 395 } 396 397 return 0; 398 } 399 400 void 401 ftl_superblock_v5_md_layout_dump(struct spdk_ftl_dev *dev) 402 { 403 struct ftl_layout_tracker_bdev *nvc_layout_tracker = dev->nvc_layout_tracker; 404 struct ftl_layout_tracker_bdev *base_layout_tracker = dev->base_layout_tracker; 405 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 406 407 FTL_NOTICELOG(dev, "SB metadata layout - nvc:\n"); 408 while (true) { 409 ftl_layout_tracker_bdev_find_next_region(nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID, 410 ®_search_ctx); 411 if (!reg_search_ctx) { 412 break; 413 } 414 415 FTL_NOTICELOG(dev, 416 "Region type:0x%"PRIx32" ver:%"PRIu32" blk_offs:0x%"PRIx64" blk_sz:0x%"PRIx64"\n", 417 reg_search_ctx->type, reg_search_ctx->ver, reg_search_ctx->blk_offs, reg_search_ctx->blk_sz); 418 } 419 420 reg_search_ctx = NULL; 421 FTL_NOTICELOG(dev, "SB metadata layout - base dev:\n"); 422 while (true) { 423 ftl_layout_tracker_bdev_find_next_region(base_layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID, 424 ®_search_ctx); 425 if (!reg_search_ctx) { 426 break; 427 } 428 429 FTL_NOTICELOG(dev, 430 "Region type:0x%"PRIx32" ver:%"PRIu32" blk_offs:0x%"PRIx64" blk_sz:0x%"PRIx64"\n", 431 reg_search_ctx->type, reg_search_ctx->ver, reg_search_ctx->blk_offs, reg_search_ctx->blk_sz); 432 } 433 } 434 435 static int 436 layout_apply_from_sb_blob(struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker, 437 int (*filter_region_type_fn)(enum ftl_layout_region_type)) 438 { 439 struct ftl_layout_region *reg; 440 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 441 442 while (true) { 443 ftl_layout_tracker_bdev_find_next_region(layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID, 444 ®_search_ctx); 445 if (!reg_search_ctx) { 446 break; 447 } 448 if (reg_search_ctx->type == FTL_LAYOUT_REGION_TYPE_FREE) { 449 continue; 450 } 451 if (filter_region_type_fn(reg_search_ctx->type)) { 452 FTL_ERRLOG(dev, "Unknown region found in layout blob: type 0x%"PRIx32"\n", reg_search_ctx->type); 453 return -1; 454 } 455 456 reg = &dev->layout.region[reg_search_ctx->type]; 457 458 /* First region of a given type found */ 459 if (reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) { 460 reg->type = reg_search_ctx->type; 461 reg->current.version = reg_search_ctx->ver; 462 reg->current.offset = reg_search_ctx->blk_offs; 463 reg->current.blocks = reg_search_ctx->blk_sz; 464 continue; 465 } 466 467 /* Update to the oldest region version found */ 468 if (reg_search_ctx->ver < reg->current.version) { 469 reg->current.version = reg_search_ctx->ver; 470 reg->current.offset = reg_search_ctx->blk_offs; 471 reg->current.blocks = reg_search_ctx->blk_sz; 472 continue; 473 } 474 475 /* Skip newer region versions */ 476 if (reg_search_ctx->ver > reg->current.version) { 477 continue; 478 } 479 480 /* Current region version already found */ 481 assert(reg_search_ctx->ver == reg->current.version); 482 if (reg->current.offset != reg_search_ctx->blk_offs || 483 reg->current.blocks != reg_search_ctx->blk_sz) { 484 FTL_ERRLOG(dev, "Corrupted layout blob: reg type 0x%"PRIx32"\n", reg_search_ctx->type); 485 return -1; 486 } 487 } 488 return 0; 489 } 490 491 static int 492 layout_region_verify(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 493 uint32_t reg_ver) 494 { 495 struct ftl_layout_region *reg = ftl_layout_region_get(dev, reg_type); 496 497 if (!reg) { 498 FTL_ERRLOG(dev, "Region not found in nvc layout blob: reg type 0x%"PRIx32"\n", reg_type); 499 return -1; 500 } 501 502 /* Unknown version found in the blob */ 503 if (reg->current.version > reg_ver) { 504 FTL_ERRLOG(dev, "Unknown region version found in layout blob: reg type 0x%"PRIx32"\n", 505 reg_type); 506 return -1; 507 } 508 509 return 0; 510 } 511 512 static int 513 layout_fixup_reg_data_base(struct spdk_ftl_dev *dev) 514 { 515 const struct ftl_md_layout_ops *base_md_ops = &dev->base_type->ops.md_layout_ops; 516 struct ftl_layout_region *reg = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_DATA_BASE]; 517 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 518 519 assert(reg->type == FTL_LAYOUT_REGION_TYPE_INVALID); 520 521 FTL_NOTICELOG(dev, "Adding a region\n"); 522 523 /* Add the region */ 524 if (base_md_ops->region_create(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, 525 ftl_layout_base_offset(dev))) { 526 return -1; 527 } 528 if (base_md_ops->region_open(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE, 529 ftl_layout_base_offset(dev), reg)) { 530 return -1; 531 } 532 533 ftl_layout_tracker_bdev_find_next_region(dev->base_layout_tracker, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 534 ®_search_ctx); 535 assert(reg_search_ctx); 536 return 0; 537 } 538 539 static int 540 layout_fixup_base(struct spdk_ftl_dev *dev) 541 { 542 struct ftl_layout_region_descr { 543 enum ftl_layout_region_type type; 544 uint32_t ver; 545 int (*on_reg_miss)(struct spdk_ftl_dev *dev); 546 }; 547 struct ftl_layout_region_descr *reg_descr; 548 static struct ftl_layout_region_descr nvc_regs[] = { 549 { .type = FTL_LAYOUT_REGION_TYPE_SB_BASE, .ver = FTL_SB_VERSION_CURRENT }, 550 { .type = FTL_LAYOUT_REGION_TYPE_DATA_BASE, .ver = 0, .on_reg_miss = layout_fixup_reg_data_base }, 551 { .type = FTL_LAYOUT_REGION_TYPE_VALID_MAP, .ver = 0 }, 552 { .type = FTL_LAYOUT_REGION_TYPE_INVALID, .ver = 0 }, 553 }; 554 555 for (reg_descr = nvc_regs; reg_descr->type != FTL_LAYOUT_REGION_TYPE_INVALID; reg_descr++) { 556 struct ftl_layout_region *region; 557 558 if (layout_region_verify(dev, reg_descr->type, reg_descr->ver) && 559 reg_descr->on_reg_miss && reg_descr->on_reg_miss(dev)) { 560 return -1; 561 } 562 563 region = &dev->layout.region[reg_descr->type]; 564 region->type = reg_descr->type; 565 region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID; 566 region->name = ftl_md_region_name(reg_descr->type); 567 568 region->bdev_desc = dev->base_bdev_desc; 569 region->ioch = dev->base_ioch; 570 region->vss_blksz = 0; 571 } 572 573 return 0; 574 } 575 576 static int 577 layout_fixup_nvc(struct spdk_ftl_dev *dev) 578 { 579 struct ftl_layout_region_descr { 580 enum ftl_layout_region_type type; 581 uint32_t ver; 582 enum ftl_layout_region_type mirror_type; 583 }; 584 struct ftl_layout_region_descr *reg_descr; 585 static struct ftl_layout_region_descr nvc_regs[] = { 586 { .type = FTL_LAYOUT_REGION_TYPE_SB, .ver = FTL_SB_VERSION_CURRENT, .mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE }, 587 { .type = FTL_LAYOUT_REGION_TYPE_L2P, .ver = 0 }, 588 { .type = FTL_LAYOUT_REGION_TYPE_BAND_MD, .ver = FTL_BAND_VERSION_CURRENT, .mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR }, 589 { .type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, .ver = FTL_BAND_VERSION_CURRENT }, 590 { .type = FTL_LAYOUT_REGION_TYPE_TRIM_MD, .ver = 0, .mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR }, 591 { .type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, .ver = 0 }, 592 { .type = FTL_LAYOUT_REGION_TYPE_NVC_MD, .ver = FTL_NVC_VERSION_CURRENT, .mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR }, 593 { .type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, .ver = FTL_NVC_VERSION_CURRENT }, 594 { .type = FTL_LAYOUT_REGION_TYPE_DATA_NVC, .ver = 0 }, 595 { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC, .ver = FTL_P2L_VERSION_CURRENT }, 596 { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT, .ver = FTL_P2L_VERSION_CURRENT }, 597 { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP, .ver = FTL_P2L_VERSION_CURRENT }, 598 { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT, .ver = FTL_P2L_VERSION_CURRENT }, 599 { .type = FTL_LAYOUT_REGION_TYPE_INVALID, .ver = 0 }, 600 }; 601 602 for (reg_descr = nvc_regs; reg_descr->type != FTL_LAYOUT_REGION_TYPE_INVALID; reg_descr++) { 603 struct ftl_layout_region *region; 604 605 if (layout_region_verify(dev, reg_descr->type, reg_descr->ver)) { 606 return -1; 607 } 608 609 region = &dev->layout.region[reg_descr->type]; 610 region->type = reg_descr->type; 611 region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID; 612 region->name = ftl_md_region_name(reg_descr->type); 613 614 region->bdev_desc = dev->nv_cache.bdev_desc; 615 region->ioch = dev->nv_cache.cache_ioch; 616 region->vss_blksz = dev->nv_cache.md_size; 617 618 if (reg_descr->mirror_type) { 619 dev->layout.region[reg_descr->type].mirror_type = reg_descr->mirror_type; 620 } 621 } 622 623 return 0; 624 } 625 626 static int 627 filter_region_type_base(enum ftl_layout_region_type reg_type) 628 { 629 switch (reg_type) { 630 case FTL_LAYOUT_REGION_TYPE_SB_BASE: 631 case FTL_LAYOUT_REGION_TYPE_DATA_BASE: 632 case FTL_LAYOUT_REGION_TYPE_VALID_MAP: 633 return 0; 634 635 default: 636 return 1; 637 } 638 } 639 640 static int 641 filter_region_type_nvc(enum ftl_layout_region_type reg_type) 642 { 643 return filter_region_type_base(reg_type) ? 0 : 1; 644 } 645 646 static int 647 layout_apply_nvc(struct spdk_ftl_dev *dev) 648 { 649 if (layout_apply_from_sb_blob(dev, dev->nvc_layout_tracker, filter_region_type_nvc) || 650 layout_fixup_nvc(dev)) { 651 return -1; 652 } 653 return 0; 654 } 655 656 static int 657 layout_apply_base(struct spdk_ftl_dev *dev) 658 { 659 if (layout_apply_from_sb_blob(dev, dev->base_layout_tracker, filter_region_type_base) || 660 layout_fixup_base(dev)) { 661 return -1; 662 } 663 return 0; 664 } 665 666 int 667 ftl_superblock_v5_md_layout_apply(struct spdk_ftl_dev *dev) 668 { 669 if (layout_apply_nvc(dev) || layout_apply_base(dev)) { 670 return -1; 671 } 672 return 0; 673 } 674