1f968b954SMateusz Kozlowski /* SPDX-License-Identifier: BSD-3-Clause 2f968b954SMateusz Kozlowski * Copyright 2023 Solidigm All Rights Reserved 3f968b954SMateusz Kozlowski * All rights reserved. 4f968b954SMateusz Kozlowski */ 5f968b954SMateusz Kozlowski 6f968b954SMateusz Kozlowski #include "spdk/string.h" 7f968b954SMateusz Kozlowski 8f968b954SMateusz Kozlowski #include "ftl_sb_v5.h" 9f968b954SMateusz Kozlowski #include "ftl_core.h" 10f968b954SMateusz Kozlowski #include "ftl_layout.h" 11f968b954SMateusz Kozlowski #include "ftl_band.h" 12f968b954SMateusz Kozlowski #include "upgrade/ftl_sb_prev.h" 13f968b954SMateusz Kozlowski #include "upgrade/ftl_sb_upgrade.h" 14f968b954SMateusz Kozlowski #include "upgrade/ftl_layout_upgrade.h" 15f968b954SMateusz Kozlowski #include "utils/ftl_layout_tracker_bdev.h" 16f968b954SMateusz Kozlowski 17f968b954SMateusz Kozlowski typedef size_t (*blob_store_fn)(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz); 18f968b954SMateusz Kozlowski typedef int (*blob_load_fn)(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz); 19f968b954SMateusz Kozlowski 20f968b954SMateusz Kozlowski bool 21f968b954SMateusz Kozlowski ftl_superblock_v5_is_blob_area_empty(union ftl_superblock_ver *sb_ver) 22f968b954SMateusz Kozlowski { 23f968b954SMateusz Kozlowski return sb_ver->v5.blob_area_end == 0; 24f968b954SMateusz Kozlowski } 25f968b954SMateusz Kozlowski 26f968b954SMateusz Kozlowski static bool 27f968b954SMateusz Kozlowski validate_blob_area(struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr, 28f968b954SMateusz Kozlowski ftl_df_obj_id sb_blob_area_end) 29f968b954SMateusz Kozlowski { 30f968b954SMateusz Kozlowski return sb_blob_hdr->df_id <= sb_blob_area_end && 31f968b954SMateusz Kozlowski (sb_blob_hdr->df_id + sb_blob_hdr->blob_sz) <= sb_blob_area_end; 32f968b954SMateusz Kozlowski } 33f968b954SMateusz Kozlowski 34f968b954SMateusz Kozlowski bool 35f968b954SMateusz Kozlowski ftl_superblock_v5_validate_blob_area(struct spdk_ftl_dev *dev) 36f968b954SMateusz Kozlowski { 37f968b954SMateusz Kozlowski union ftl_superblock_ver *sb_ver = (union ftl_superblock_ver *)dev->sb; 38f968b954SMateusz Kozlowski 39f968b954SMateusz Kozlowski return validate_blob_area(&sb_ver->v5.md_layout_nvc, sb_ver->v5.blob_area_end) && 40f968b954SMateusz Kozlowski validate_blob_area(&sb_ver->v5.md_layout_base, sb_ver->v5.blob_area_end) && 41f968b954SMateusz Kozlowski validate_blob_area(&sb_ver->v5.layout_params, sb_ver->v5.blob_area_end); 42f968b954SMateusz Kozlowski } 43f968b954SMateusz Kozlowski 44f968b954SMateusz Kozlowski static size_t 45f968b954SMateusz Kozlowski sb_blob_store(struct spdk_ftl_dev *dev, struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr, 46f968b954SMateusz Kozlowski blob_store_fn blob_store, void *sb_blob_area) 47f968b954SMateusz Kozlowski { 48f968b954SMateusz Kozlowski struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb; 49f968b954SMateusz Kozlowski uintptr_t sb_end = ((uintptr_t)sb) + FTL_SUPERBLOCK_SIZE; 50f968b954SMateusz Kozlowski size_t blob_sz = sb_end - (uintptr_t)sb_blob_area; 51f968b954SMateusz Kozlowski 52f968b954SMateusz Kozlowski /* Test SB blob area overflow */ 53f968b954SMateusz Kozlowski if ((uintptr_t)sb_blob_area < (uintptr_t)sb->blob_area) { 54f968b954SMateusz Kozlowski ftl_bug(true); 55f968b954SMateusz Kozlowski return 0; 56f968b954SMateusz Kozlowski } 57f968b954SMateusz Kozlowski if ((uintptr_t)sb_blob_area >= sb_end) { 58f968b954SMateusz Kozlowski ftl_bug(true); 59f968b954SMateusz Kozlowski return 0; 60f968b954SMateusz Kozlowski } 61f968b954SMateusz Kozlowski 62f968b954SMateusz Kozlowski blob_sz = blob_store(dev, sb_blob_area, blob_sz); 63f968b954SMateusz Kozlowski sb_blob_hdr->blob_sz = blob_sz; 64f968b954SMateusz Kozlowski sb_blob_hdr->df_id = ftl_df_get_obj_id(sb->blob_area, sb_blob_area); 65f968b954SMateusz Kozlowski return blob_sz; 66f968b954SMateusz Kozlowski } 67f968b954SMateusz Kozlowski 68f968b954SMateusz Kozlowski static size_t 69f968b954SMateusz Kozlowski base_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz) 70f968b954SMateusz Kozlowski { 71f968b954SMateusz Kozlowski return ftl_layout_tracker_bdev_blob_store(dev->base_layout_tracker, blob_buf, blob_buf_sz); 72f968b954SMateusz Kozlowski } 73f968b954SMateusz Kozlowski 74f968b954SMateusz Kozlowski static size_t 75f968b954SMateusz Kozlowski nvc_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz) 76f968b954SMateusz Kozlowski { 77f968b954SMateusz Kozlowski return ftl_layout_tracker_bdev_blob_store(dev->nvc_layout_tracker, blob_buf, blob_buf_sz); 78f968b954SMateusz Kozlowski } 79f968b954SMateusz Kozlowski 80f968b954SMateusz Kozlowski int 81f968b954SMateusz Kozlowski ftl_superblock_v5_store_blob_area(struct spdk_ftl_dev *dev) 82f968b954SMateusz Kozlowski { 83f968b954SMateusz Kozlowski struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb; 84f968b954SMateusz Kozlowski void *sb_blob_area; 85f968b954SMateusz Kozlowski size_t blob_sz; 86f968b954SMateusz Kozlowski 87f968b954SMateusz Kozlowski /* Store the NVC-backed FTL MD layout info */ 88f968b954SMateusz Kozlowski sb_blob_area = ftl_df_get_obj_ptr(sb->blob_area, 0); 8926f3b551SMateusz Kozlowski spdk_strcpy_pad(sb->nvc_dev_name, dev->nv_cache.nvc_type->name, 90f968b954SMateusz Kozlowski SPDK_COUNTOF(sb->nvc_dev_name), '\0'); 91f968b954SMateusz Kozlowski blob_sz = sb_blob_store(dev, &sb->md_layout_nvc, nvc_blob_store, sb_blob_area); 92f968b954SMateusz Kozlowski FTL_NOTICELOG(dev, "nvc layout blob store 0x%"PRIx64" bytes\n", blob_sz); 93f968b954SMateusz Kozlowski if (!blob_sz) { 94f968b954SMateusz Kozlowski return -1; 95f968b954SMateusz Kozlowski } 96f968b954SMateusz Kozlowski 97f968b954SMateusz Kozlowski /* Store the base dev-backed FTL MD layout info */ 98f968b954SMateusz Kozlowski sb_blob_area += blob_sz; 99f968b954SMateusz Kozlowski spdk_strcpy_pad(sb->base_dev_name, dev->base_type->name, SPDK_COUNTOF(sb->base_dev_name), '\0'); 100f968b954SMateusz Kozlowski blob_sz = sb_blob_store(dev, &sb->md_layout_base, base_blob_store, sb_blob_area); 101f968b954SMateusz Kozlowski FTL_NOTICELOG(dev, "base layout blob store 0x%"PRIx64" bytes\n", blob_sz); 102f968b954SMateusz Kozlowski if (!blob_sz) { 103f968b954SMateusz Kozlowski return -1; 104f968b954SMateusz Kozlowski } 105f968b954SMateusz Kozlowski 106f968b954SMateusz Kozlowski /* Store the region props */ 107f968b954SMateusz Kozlowski sb_blob_area += blob_sz; 108f968b954SMateusz Kozlowski blob_sz = sb_blob_store(dev, &sb->layout_params, ftl_layout_blob_store, sb_blob_area); 109f968b954SMateusz Kozlowski FTL_NOTICELOG(dev, "layout blob store 0x%"PRIx64" bytes\n", blob_sz); 110f968b954SMateusz Kozlowski if (!blob_sz) { 111f968b954SMateusz Kozlowski return -1; 112f968b954SMateusz Kozlowski } 113f968b954SMateusz Kozlowski 114f968b954SMateusz Kozlowski /* Update the blob area end */ 115f968b954SMateusz Kozlowski sb_blob_area += blob_sz; 116f968b954SMateusz Kozlowski sb->blob_area_end = ftl_df_get_obj_id(sb->blob_area, sb_blob_area); 117f968b954SMateusz Kozlowski 118f968b954SMateusz Kozlowski return 0; 119f968b954SMateusz Kozlowski } 120f968b954SMateusz Kozlowski 1218fc78fd8SMateusz Kozlowski static const struct ftl_layout_tracker_bdev_region_props * 1228fc78fd8SMateusz Kozlowski sb_md_layout_find_oldest_region(struct spdk_ftl_dev *dev, 1238fc78fd8SMateusz Kozlowski struct ftl_layout_tracker_bdev *layout_tracker, 1248fc78fd8SMateusz Kozlowski enum ftl_layout_region_type reg_type, void *find_filter) 1258fc78fd8SMateusz Kozlowski { 1268fc78fd8SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 1278fc78fd8SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_oldest = NULL; 1288fc78fd8SMateusz Kozlowski uint32_t ver_oldest; 1298fc78fd8SMateusz Kozlowski 1308fc78fd8SMateusz Kozlowski while (true) { 1318fc78fd8SMateusz Kozlowski ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 1328fc78fd8SMateusz Kozlowski if (!reg_search_ctx) { 1338fc78fd8SMateusz Kozlowski break; 1348fc78fd8SMateusz Kozlowski } 1358fc78fd8SMateusz Kozlowski 1368fc78fd8SMateusz Kozlowski if (!reg_oldest) { 1378fc78fd8SMateusz Kozlowski reg_oldest = reg_search_ctx; 1388fc78fd8SMateusz Kozlowski ver_oldest = reg_search_ctx->ver; 1398fc78fd8SMateusz Kozlowski continue; 1408fc78fd8SMateusz Kozlowski } 1418fc78fd8SMateusz Kozlowski 1428fc78fd8SMateusz Kozlowski ftl_bug(ver_oldest == reg_search_ctx->ver); 1438fc78fd8SMateusz Kozlowski if (ver_oldest > reg_search_ctx->ver) { 1448fc78fd8SMateusz Kozlowski reg_oldest = reg_search_ctx; 1458fc78fd8SMateusz Kozlowski ver_oldest = reg_search_ctx->ver; 1468fc78fd8SMateusz Kozlowski } 1478fc78fd8SMateusz Kozlowski } 1488fc78fd8SMateusz Kozlowski 1498fc78fd8SMateusz Kozlowski return reg_oldest; 1508fc78fd8SMateusz Kozlowski } 1518fc78fd8SMateusz Kozlowski 1528fc78fd8SMateusz Kozlowski static const struct ftl_layout_tracker_bdev_region_props * 1538fc78fd8SMateusz Kozlowski sb_md_layout_find_latest_region(struct spdk_ftl_dev *dev, 1548fc78fd8SMateusz Kozlowski struct ftl_layout_tracker_bdev *layout_tracker, enum ftl_layout_region_type reg_type, 1558fc78fd8SMateusz Kozlowski void *find_filter) 1568fc78fd8SMateusz Kozlowski { 1578fc78fd8SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 1588fc78fd8SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_latest = NULL; 1598fc78fd8SMateusz Kozlowski uint32_t ver_latest; 1608fc78fd8SMateusz Kozlowski 1618fc78fd8SMateusz Kozlowski while (true) { 1628fc78fd8SMateusz Kozlowski ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 1638fc78fd8SMateusz Kozlowski if (!reg_search_ctx) { 1648fc78fd8SMateusz Kozlowski break; 1658fc78fd8SMateusz Kozlowski } 1668fc78fd8SMateusz Kozlowski 1678fc78fd8SMateusz Kozlowski if (!reg_latest) { 1688fc78fd8SMateusz Kozlowski reg_latest = reg_search_ctx; 1698fc78fd8SMateusz Kozlowski ver_latest = reg_search_ctx->ver; 1708fc78fd8SMateusz Kozlowski continue; 1718fc78fd8SMateusz Kozlowski } 1728fc78fd8SMateusz Kozlowski 1738fc78fd8SMateusz Kozlowski ftl_bug(ver_latest == reg_search_ctx->ver); 1748fc78fd8SMateusz Kozlowski if (ver_latest < reg_search_ctx->ver) { 1758fc78fd8SMateusz Kozlowski reg_latest = reg_search_ctx; 1768fc78fd8SMateusz Kozlowski ver_latest = reg_search_ctx->ver; 1778fc78fd8SMateusz Kozlowski } 1788fc78fd8SMateusz Kozlowski } 1798fc78fd8SMateusz Kozlowski 1808fc78fd8SMateusz Kozlowski return reg_latest; 1818fc78fd8SMateusz Kozlowski } 1828fc78fd8SMateusz Kozlowski 1838fc78fd8SMateusz Kozlowski static const struct ftl_layout_tracker_bdev_region_props * 1848fc78fd8SMateusz Kozlowski sb_md_layout_find_region_version(struct spdk_ftl_dev *dev, 1858fc78fd8SMateusz Kozlowski struct ftl_layout_tracker_bdev *layout_tracker, enum ftl_layout_region_type reg_type, 1868fc78fd8SMateusz Kozlowski void *find_filter) 1878fc78fd8SMateusz Kozlowski { 1888fc78fd8SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 1898fc78fd8SMateusz Kozlowski uint32_t *reg_ver = find_filter; 1908fc78fd8SMateusz Kozlowski 1918fc78fd8SMateusz Kozlowski assert(reg_ver); 1928fc78fd8SMateusz Kozlowski 1938fc78fd8SMateusz Kozlowski while (true) { 1948fc78fd8SMateusz Kozlowski ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 1958fc78fd8SMateusz Kozlowski if (!reg_search_ctx) { 1968fc78fd8SMateusz Kozlowski break; 1978fc78fd8SMateusz Kozlowski } 1988fc78fd8SMateusz Kozlowski 1998fc78fd8SMateusz Kozlowski if (reg_search_ctx->ver == *reg_ver) { 2008fc78fd8SMateusz Kozlowski break; 2018fc78fd8SMateusz Kozlowski } 2028fc78fd8SMateusz Kozlowski } 2038fc78fd8SMateusz Kozlowski 2048fc78fd8SMateusz Kozlowski return reg_search_ctx; 2058fc78fd8SMateusz Kozlowski } 2068fc78fd8SMateusz Kozlowski 207f968b954SMateusz Kozlowski typedef const struct ftl_layout_tracker_bdev_region_props *(*sb_md_layout_find_fn)( 208f968b954SMateusz Kozlowski struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker, 209f968b954SMateusz Kozlowski enum ftl_layout_region_type reg_type, void *find_filter); 210f968b954SMateusz Kozlowski 2118fc78fd8SMateusz Kozlowski static const struct ftl_layout_tracker_bdev_region_props * 2128fc78fd8SMateusz Kozlowski sb_md_layout_find_region(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 2138fc78fd8SMateusz Kozlowski sb_md_layout_find_fn find_fn, void *find_filter) 2148fc78fd8SMateusz Kozlowski { 2158fc78fd8SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx; 2168fc78fd8SMateusz Kozlowski struct ftl_layout_tracker_bdev *nvc_layout_tracker = dev->nvc_layout_tracker; 2178fc78fd8SMateusz Kozlowski struct ftl_layout_tracker_bdev *base_layout_tracker = dev->base_layout_tracker; 2188fc78fd8SMateusz Kozlowski 2198fc78fd8SMateusz Kozlowski reg_search_ctx = find_fn(dev, nvc_layout_tracker, reg_type, find_filter); 2208fc78fd8SMateusz Kozlowski if (reg_search_ctx) { 2218fc78fd8SMateusz Kozlowski assert(find_fn(dev, base_layout_tracker, reg_type, find_filter) == NULL); 2228fc78fd8SMateusz Kozlowski return reg_search_ctx; 2238fc78fd8SMateusz Kozlowski } 2248fc78fd8SMateusz Kozlowski 2258fc78fd8SMateusz Kozlowski reg_search_ctx = find_fn(dev, base_layout_tracker, reg_type, find_filter); 2268fc78fd8SMateusz Kozlowski return reg_search_ctx; 2278fc78fd8SMateusz Kozlowski } 2288fc78fd8SMateusz Kozlowski 229f968b954SMateusz Kozlowski static int 230f968b954SMateusz Kozlowski sb_blob_load(struct spdk_ftl_dev *dev, struct ftl_superblock_v5_md_blob_hdr *sb_blob_hdr, 231f968b954SMateusz Kozlowski blob_load_fn blob_load) 232f968b954SMateusz Kozlowski { 233f968b954SMateusz Kozlowski struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb; 234f968b954SMateusz Kozlowski uintptr_t sb_end = ((uintptr_t)sb) + FTL_SUPERBLOCK_SIZE; 235f968b954SMateusz Kozlowski void *blob_area; 236f968b954SMateusz Kozlowski 237f968b954SMateusz Kozlowski if (sb_blob_hdr->df_id == FTL_DF_OBJ_ID_INVALID) { 238f968b954SMateusz Kozlowski /* Uninitialized blob */ 239f968b954SMateusz Kozlowski return -1; 240f968b954SMateusz Kozlowski } 241f968b954SMateusz Kozlowski 242f968b954SMateusz Kozlowski blob_area = ftl_df_get_obj_ptr(sb->blob_area, sb_blob_hdr->df_id); 243f968b954SMateusz Kozlowski 244f968b954SMateusz Kozlowski /* Test SB blob area overflow */ 245f968b954SMateusz Kozlowski if ((uintptr_t)blob_area < (uintptr_t)sb->blob_area) { 246f968b954SMateusz Kozlowski ftl_bug(true); 247f968b954SMateusz Kozlowski return -1; 248f968b954SMateusz Kozlowski } 249f968b954SMateusz Kozlowski if ((uintptr_t)blob_area + sb_blob_hdr->blob_sz >= sb_end) { 250f968b954SMateusz Kozlowski ftl_bug(true); 251f968b954SMateusz Kozlowski return -1; 252f968b954SMateusz Kozlowski } 253f968b954SMateusz Kozlowski 254f968b954SMateusz Kozlowski return blob_load(dev, blob_area, sb_blob_hdr->blob_sz); 255f968b954SMateusz Kozlowski } 256f968b954SMateusz Kozlowski 257f968b954SMateusz Kozlowski static int 258f968b954SMateusz Kozlowski base_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz) 259f968b954SMateusz Kozlowski { 260f968b954SMateusz Kozlowski return ftl_layout_tracker_bdev_blob_load(dev->base_layout_tracker, blob_buf, blob_sz); 261f968b954SMateusz Kozlowski } 262f968b954SMateusz Kozlowski 263f968b954SMateusz Kozlowski static int 264f968b954SMateusz Kozlowski nvc_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz) 265f968b954SMateusz Kozlowski { 266f968b954SMateusz Kozlowski return ftl_layout_tracker_bdev_blob_load(dev->nvc_layout_tracker, blob_buf, blob_sz); 267f968b954SMateusz Kozlowski } 268f968b954SMateusz Kozlowski 269f968b954SMateusz Kozlowski int 270f968b954SMateusz Kozlowski ftl_superblock_v5_load_blob_area(struct spdk_ftl_dev *dev) 271f968b954SMateusz Kozlowski { 272f968b954SMateusz Kozlowski struct ftl_superblock_v5 *sb = (struct ftl_superblock_v5 *)dev->sb; 273f968b954SMateusz Kozlowski 274f968b954SMateusz Kozlowski /* Load the NVC-backed FTL MD layout info */ 27526f3b551SMateusz Kozlowski if (strncmp(sb->nvc_dev_name, dev->nv_cache.nvc_type->name, SPDK_COUNTOF(sb->nvc_dev_name))) { 276f968b954SMateusz Kozlowski return -1; 277f968b954SMateusz Kozlowski } 278f968b954SMateusz Kozlowski FTL_NOTICELOG(dev, "nvc layout blob load 0x%"PRIx64" bytes\n", (uint64_t)sb->md_layout_nvc.blob_sz); 279f968b954SMateusz Kozlowski if (sb_blob_load(dev, &sb->md_layout_nvc, nvc_blob_load)) { 280f968b954SMateusz Kozlowski return -1; 281f968b954SMateusz Kozlowski } 282f968b954SMateusz Kozlowski 283f968b954SMateusz Kozlowski /* Load the base dev-backed FTL MD layout info */ 284f968b954SMateusz Kozlowski if (strncmp(sb->base_dev_name, dev->base_type->name, SPDK_COUNTOF(sb->base_dev_name))) { 285f968b954SMateusz Kozlowski return -1; 286f968b954SMateusz Kozlowski } 287f968b954SMateusz Kozlowski FTL_NOTICELOG(dev, "base layout blob load 0x%"PRIx64" bytes\n", 288f968b954SMateusz Kozlowski (uint64_t)sb->md_layout_base.blob_sz); 289f968b954SMateusz Kozlowski if (sb_blob_load(dev, &sb->md_layout_base, base_blob_load)) { 290f968b954SMateusz Kozlowski return -1; 291f968b954SMateusz Kozlowski } 292f968b954SMateusz Kozlowski 293f968b954SMateusz Kozlowski /* Load the region props */ 294f968b954SMateusz Kozlowski FTL_NOTICELOG(dev, "layout blob load 0x%"PRIx64" bytes\n", (uint64_t)sb->layout_params.blob_sz); 295f968b954SMateusz Kozlowski if (sb_blob_load(dev, &sb->layout_params, ftl_layout_blob_load)) { 296f968b954SMateusz Kozlowski return -1; 297f968b954SMateusz Kozlowski } 298f968b954SMateusz Kozlowski 299f968b954SMateusz Kozlowski return 0; 300f968b954SMateusz Kozlowski } 301f968b954SMateusz Kozlowski 3028fc78fd8SMateusz Kozlowski static struct ftl_layout_tracker_bdev * 3038fc78fd8SMateusz Kozlowski sb_get_md_layout_tracker(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg) 3048fc78fd8SMateusz Kozlowski { 3058fc78fd8SMateusz Kozlowski return (reg->bdev_desc == dev->base_bdev_desc) ? dev->base_layout_tracker : dev->nvc_layout_tracker; 3068fc78fd8SMateusz Kozlowski } 3078fc78fd8SMateusz Kozlowski 3088fc78fd8SMateusz Kozlowski static void 3098fc78fd8SMateusz Kozlowski sb_md_layout_delete_prev_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg) 3108fc78fd8SMateusz Kozlowski { 3118fc78fd8SMateusz Kozlowski int rc; 3128fc78fd8SMateusz Kozlowski struct ftl_layout_tracker_bdev *layout_tracker = sb_get_md_layout_tracker(dev, reg); 3138fc78fd8SMateusz Kozlowski 3148fc78fd8SMateusz Kozlowski rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg->type, reg->current.version); 3155555d51cSLukasz Lasek /* Version 0 indicates a placeholder for creation of a new region */ 3165555d51cSLukasz Lasek ftl_bug(reg->current.version != 0 && rc != 0); 3178fc78fd8SMateusz Kozlowski } 3188fc78fd8SMateusz Kozlowski 3198fc78fd8SMateusz Kozlowski static void 3208fc78fd8SMateusz Kozlowski sb_md_layout_update_prev_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg, 3218fc78fd8SMateusz Kozlowski uint32_t new_version) 3228fc78fd8SMateusz Kozlowski { 3238fc78fd8SMateusz Kozlowski int rc; 3248fc78fd8SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 3258fc78fd8SMateusz Kozlowski struct ftl_layout_tracker_bdev *layout_tracker = sb_get_md_layout_tracker(dev, reg); 3268fc78fd8SMateusz Kozlowski struct ftl_layout_tracker_bdev_region_props reg_props; 3278fc78fd8SMateusz Kozlowski 3288fc78fd8SMateusz Kozlowski /* Get region properties */ 3298fc78fd8SMateusz Kozlowski ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg->type, ®_search_ctx); 3308fc78fd8SMateusz Kozlowski ftl_bug(reg_search_ctx == NULL); 3318fc78fd8SMateusz Kozlowski reg_props = *reg_search_ctx; 3328fc78fd8SMateusz Kozlowski 3338fc78fd8SMateusz Kozlowski /* Delete the region */ 3348fc78fd8SMateusz Kozlowski rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg_props.type, reg_props.ver); 3358fc78fd8SMateusz Kozlowski ftl_bug(rc != 0); 3368fc78fd8SMateusz Kozlowski 3378fc78fd8SMateusz Kozlowski /* Insert the same region with new version */ 3388fc78fd8SMateusz Kozlowski reg_search_ctx = ftl_layout_tracker_bdev_insert_region(layout_tracker, reg_props.type, new_version, 3398fc78fd8SMateusz Kozlowski reg_props.blk_offs, reg_props.blk_sz); 3408fc78fd8SMateusz Kozlowski ftl_bug(reg_search_ctx == NULL); 3418fc78fd8SMateusz Kozlowski 3428fc78fd8SMateusz Kozlowski /* Verify the oldest region version stored in the SB is the new_version */ 3438fc78fd8SMateusz Kozlowski reg_search_ctx = sb_md_layout_find_region(dev, reg_props.type, sb_md_layout_find_oldest_region, 3448fc78fd8SMateusz Kozlowski NULL); 3458fc78fd8SMateusz Kozlowski ftl_bug(reg_search_ctx == NULL); 3468fc78fd8SMateusz Kozlowski ftl_bug(reg_search_ctx->ver != new_version); 3478fc78fd8SMateusz Kozlowski } 3488fc78fd8SMateusz Kozlowski 3498fc78fd8SMateusz Kozlowski int 3508fc78fd8SMateusz Kozlowski ftl_superblock_v5_md_layout_upgrade_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg, 3518fc78fd8SMateusz Kozlowski uint32_t new_version) 3528fc78fd8SMateusz Kozlowski { 3538fc78fd8SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_next = NULL; 3548fc78fd8SMateusz Kozlowski uint64_t latest_ver; 3558fc78fd8SMateusz Kozlowski 3568fc78fd8SMateusz Kozlowski ftl_bug(reg->current.version >= new_version); 3578fc78fd8SMateusz Kozlowski 3588fc78fd8SMateusz Kozlowski reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_region_version, &new_version); 3598fc78fd8SMateusz Kozlowski if (reg_next) { 3608fc78fd8SMateusz Kozlowski /** 3618fc78fd8SMateusz Kozlowski * Major upgrade. 3628fc78fd8SMateusz Kozlowski * Found a new MD region allocated for upgrade to the next version. 3638fc78fd8SMateusz Kozlowski * Destroy the previous version now that the upgrade is completed. 3648fc78fd8SMateusz Kozlowski */ 3658fc78fd8SMateusz Kozlowski ftl_bug(reg_next->ver != new_version); 3668fc78fd8SMateusz Kozlowski ftl_bug(reg_next->type != reg->type); 3678fc78fd8SMateusz Kozlowski sb_md_layout_delete_prev_region(dev, reg); 3688fc78fd8SMateusz Kozlowski reg->current.offset = reg_next->blk_offs; 3698fc78fd8SMateusz Kozlowski reg->current.blocks = reg_next->blk_sz; 3708fc78fd8SMateusz Kozlowski } else { 3718fc78fd8SMateusz Kozlowski /** 3728fc78fd8SMateusz Kozlowski * Minor upgrade. 3738fc78fd8SMateusz Kozlowski * Upgraded the MD region in place. 3748fc78fd8SMateusz Kozlowski * Update the version in place. 3758fc78fd8SMateusz Kozlowski */ 3768fc78fd8SMateusz Kozlowski sb_md_layout_update_prev_region(dev, reg, new_version); 3778fc78fd8SMateusz Kozlowski } 3788fc78fd8SMateusz Kozlowski 3798fc78fd8SMateusz Kozlowski reg->current.version = new_version; 3808fc78fd8SMateusz Kozlowski latest_ver = ftl_layout_upgrade_region_get_latest_version(reg->type); 3818fc78fd8SMateusz Kozlowski if (new_version == latest_ver) { 3828fc78fd8SMateusz Kozlowski /* Audit the only region version stored in the SB */ 3838fc78fd8SMateusz Kozlowski reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_latest_region, NULL); 3848fc78fd8SMateusz Kozlowski ftl_bug(reg_next == NULL); 3858fc78fd8SMateusz Kozlowski ftl_bug(reg_next->ver != new_version); 3868fc78fd8SMateusz Kozlowski 3878fc78fd8SMateusz Kozlowski reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_oldest_region, NULL); 3888fc78fd8SMateusz Kozlowski ftl_bug(reg_next == NULL); 3898fc78fd8SMateusz Kozlowski ftl_bug(reg_next->ver != new_version); 3908fc78fd8SMateusz Kozlowski 3918fc78fd8SMateusz Kozlowski reg_next = sb_md_layout_find_region(dev, reg->type, sb_md_layout_find_region_version, &new_version); 3928fc78fd8SMateusz Kozlowski ftl_bug(reg->type != reg_next->type); 3938fc78fd8SMateusz Kozlowski ftl_bug(reg->current.version != reg_next->ver); 3948fc78fd8SMateusz Kozlowski ftl_bug(reg->current.offset != reg_next->blk_offs); 3958fc78fd8SMateusz Kozlowski ftl_bug(reg->current.blocks != reg_next->blk_sz); 3968fc78fd8SMateusz Kozlowski } 3978fc78fd8SMateusz Kozlowski 3988fc78fd8SMateusz Kozlowski return 0; 3998fc78fd8SMateusz Kozlowski } 4008fc78fd8SMateusz Kozlowski 401f968b954SMateusz Kozlowski void 402f968b954SMateusz Kozlowski ftl_superblock_v5_md_layout_dump(struct spdk_ftl_dev *dev) 403f968b954SMateusz Kozlowski { 404f968b954SMateusz Kozlowski struct ftl_layout_tracker_bdev *nvc_layout_tracker = dev->nvc_layout_tracker; 405f968b954SMateusz Kozlowski struct ftl_layout_tracker_bdev *base_layout_tracker = dev->base_layout_tracker; 406f968b954SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 407f968b954SMateusz Kozlowski 408f968b954SMateusz Kozlowski FTL_NOTICELOG(dev, "SB metadata layout - nvc:\n"); 409f968b954SMateusz Kozlowski while (true) { 410f968b954SMateusz Kozlowski ftl_layout_tracker_bdev_find_next_region(nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID, 411f968b954SMateusz Kozlowski ®_search_ctx); 412f968b954SMateusz Kozlowski if (!reg_search_ctx) { 413f968b954SMateusz Kozlowski break; 414f968b954SMateusz Kozlowski } 415f968b954SMateusz Kozlowski 416f968b954SMateusz Kozlowski FTL_NOTICELOG(dev, 417f968b954SMateusz Kozlowski "Region type:0x%"PRIx32" ver:%"PRIu32" blk_offs:0x%"PRIx64" blk_sz:0x%"PRIx64"\n", 418f968b954SMateusz Kozlowski reg_search_ctx->type, reg_search_ctx->ver, reg_search_ctx->blk_offs, reg_search_ctx->blk_sz); 419f968b954SMateusz Kozlowski } 420f968b954SMateusz Kozlowski 421f968b954SMateusz Kozlowski reg_search_ctx = NULL; 422f968b954SMateusz Kozlowski FTL_NOTICELOG(dev, "SB metadata layout - base dev:\n"); 423f968b954SMateusz Kozlowski while (true) { 424f968b954SMateusz Kozlowski ftl_layout_tracker_bdev_find_next_region(base_layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID, 425f968b954SMateusz Kozlowski ®_search_ctx); 426f968b954SMateusz Kozlowski if (!reg_search_ctx) { 427f968b954SMateusz Kozlowski break; 428f968b954SMateusz Kozlowski } 429f968b954SMateusz Kozlowski 430f968b954SMateusz Kozlowski FTL_NOTICELOG(dev, 431f968b954SMateusz Kozlowski "Region type:0x%"PRIx32" ver:%"PRIu32" blk_offs:0x%"PRIx64" blk_sz:0x%"PRIx64"\n", 432f968b954SMateusz Kozlowski reg_search_ctx->type, reg_search_ctx->ver, reg_search_ctx->blk_offs, reg_search_ctx->blk_sz); 433f968b954SMateusz Kozlowski } 434f968b954SMateusz Kozlowski } 435f968b954SMateusz Kozlowski 436f968b954SMateusz Kozlowski static int 437f968b954SMateusz Kozlowski layout_apply_from_sb_blob(struct spdk_ftl_dev *dev, struct ftl_layout_tracker_bdev *layout_tracker, 438f968b954SMateusz Kozlowski int (*filter_region_type_fn)(enum ftl_layout_region_type)) 439f968b954SMateusz Kozlowski { 440f968b954SMateusz Kozlowski struct ftl_layout_region *reg; 441f968b954SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 442f968b954SMateusz Kozlowski 443f968b954SMateusz Kozlowski while (true) { 444f968b954SMateusz Kozlowski ftl_layout_tracker_bdev_find_next_region(layout_tracker, FTL_LAYOUT_REGION_TYPE_INVALID, 445f968b954SMateusz Kozlowski ®_search_ctx); 446f968b954SMateusz Kozlowski if (!reg_search_ctx) { 447f968b954SMateusz Kozlowski break; 448f968b954SMateusz Kozlowski } 449f968b954SMateusz Kozlowski if (reg_search_ctx->type == FTL_LAYOUT_REGION_TYPE_FREE) { 450f968b954SMateusz Kozlowski continue; 451f968b954SMateusz Kozlowski } 452f968b954SMateusz Kozlowski if (filter_region_type_fn(reg_search_ctx->type)) { 453f968b954SMateusz Kozlowski FTL_ERRLOG(dev, "Unknown region found in layout blob: type 0x%"PRIx32"\n", reg_search_ctx->type); 454f968b954SMateusz Kozlowski return -1; 455f968b954SMateusz Kozlowski } 456f968b954SMateusz Kozlowski 457f968b954SMateusz Kozlowski reg = &dev->layout.region[reg_search_ctx->type]; 458f968b954SMateusz Kozlowski 459f968b954SMateusz Kozlowski /* First region of a given type found */ 460f968b954SMateusz Kozlowski if (reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) { 461f968b954SMateusz Kozlowski reg->type = reg_search_ctx->type; 462f968b954SMateusz Kozlowski reg->current.version = reg_search_ctx->ver; 463f968b954SMateusz Kozlowski reg->current.offset = reg_search_ctx->blk_offs; 464f968b954SMateusz Kozlowski reg->current.blocks = reg_search_ctx->blk_sz; 465f968b954SMateusz Kozlowski continue; 466f968b954SMateusz Kozlowski } 467f968b954SMateusz Kozlowski 468f968b954SMateusz Kozlowski /* Update to the oldest region version found */ 469f968b954SMateusz Kozlowski if (reg_search_ctx->ver < reg->current.version) { 470f968b954SMateusz Kozlowski reg->current.version = reg_search_ctx->ver; 471f968b954SMateusz Kozlowski reg->current.offset = reg_search_ctx->blk_offs; 472f968b954SMateusz Kozlowski reg->current.blocks = reg_search_ctx->blk_sz; 473f968b954SMateusz Kozlowski continue; 474f968b954SMateusz Kozlowski } 475f968b954SMateusz Kozlowski 476f968b954SMateusz Kozlowski /* Skip newer region versions */ 477f968b954SMateusz Kozlowski if (reg_search_ctx->ver > reg->current.version) { 478f968b954SMateusz Kozlowski continue; 479f968b954SMateusz Kozlowski } 480f968b954SMateusz Kozlowski 481f968b954SMateusz Kozlowski /* Current region version already found */ 482f968b954SMateusz Kozlowski assert(reg_search_ctx->ver == reg->current.version); 483f968b954SMateusz Kozlowski if (reg->current.offset != reg_search_ctx->blk_offs || 484f968b954SMateusz Kozlowski reg->current.blocks != reg_search_ctx->blk_sz) { 485f968b954SMateusz Kozlowski FTL_ERRLOG(dev, "Corrupted layout blob: reg type 0x%"PRIx32"\n", reg_search_ctx->type); 486f968b954SMateusz Kozlowski return -1; 487f968b954SMateusz Kozlowski } 488f968b954SMateusz Kozlowski } 489f968b954SMateusz Kozlowski return 0; 490f968b954SMateusz Kozlowski } 491f968b954SMateusz Kozlowski 492f968b954SMateusz Kozlowski static int 4935555d51cSLukasz Lasek layout_region_verify(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type) 494f968b954SMateusz Kozlowski { 495f968b954SMateusz Kozlowski struct ftl_layout_region *reg = ftl_layout_region_get(dev, reg_type); 496f968b954SMateusz Kozlowski if (!reg) { 4975555d51cSLukasz Lasek return -ENOENT; 498f968b954SMateusz Kozlowski } 499f968b954SMateusz Kozlowski 500f968b954SMateusz Kozlowski /* Unknown version found in the blob */ 5015555d51cSLukasz Lasek if (reg->current.version > ftl_layout_upgrade_get_latest_version(reg_type)) { 502f968b954SMateusz Kozlowski FTL_ERRLOG(dev, "Unknown region version found in layout blob: reg type 0x%"PRIx32"\n", 503f968b954SMateusz Kozlowski reg_type); 5045555d51cSLukasz Lasek return -EINVAL; 505f968b954SMateusz Kozlowski } 506f968b954SMateusz Kozlowski 507f968b954SMateusz Kozlowski return 0; 508f968b954SMateusz Kozlowski } 509f968b954SMateusz Kozlowski 510f968b954SMateusz Kozlowski static int 5119f42898aSLukasz Lasek layout_fixup_reg_data_base(struct spdk_ftl_dev *dev) 5129f42898aSLukasz Lasek { 5139f42898aSLukasz Lasek const struct ftl_md_layout_ops *base_md_ops = &dev->base_type->ops.md_layout_ops; 5149f42898aSLukasz Lasek struct ftl_layout_region *reg = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_DATA_BASE]; 5159f42898aSLukasz Lasek const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 5169f42898aSLukasz Lasek 5179f42898aSLukasz Lasek assert(reg->type == FTL_LAYOUT_REGION_TYPE_INVALID); 5189f42898aSLukasz Lasek 5199f42898aSLukasz Lasek FTL_NOTICELOG(dev, "Adding a region\n"); 5209f42898aSLukasz Lasek 5219f42898aSLukasz Lasek /* Add the region */ 5229f42898aSLukasz Lasek if (base_md_ops->region_create(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, 5239f42898aSLukasz Lasek ftl_layout_base_offset(dev))) { 5249f42898aSLukasz Lasek return -1; 5259f42898aSLukasz Lasek } 5269f42898aSLukasz Lasek if (base_md_ops->region_open(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE, 5279f42898aSLukasz Lasek ftl_layout_base_offset(dev), reg)) { 5289f42898aSLukasz Lasek return -1; 5299f42898aSLukasz Lasek } 5309f42898aSLukasz Lasek 5319f42898aSLukasz Lasek ftl_layout_tracker_bdev_find_next_region(dev->base_layout_tracker, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 5329f42898aSLukasz Lasek ®_search_ctx); 5339f42898aSLukasz Lasek assert(reg_search_ctx); 5349f42898aSLukasz Lasek return 0; 5359f42898aSLukasz Lasek } 5369f42898aSLukasz Lasek 5379f42898aSLukasz Lasek static int 538f968b954SMateusz Kozlowski layout_fixup_base(struct spdk_ftl_dev *dev) 539f968b954SMateusz Kozlowski { 540f968b954SMateusz Kozlowski struct ftl_layout_region_descr { 541f968b954SMateusz Kozlowski enum ftl_layout_region_type type; 542f968b954SMateusz Kozlowski uint32_t ver; 543f968b954SMateusz Kozlowski int (*on_reg_miss)(struct spdk_ftl_dev *dev); 544f968b954SMateusz Kozlowski }; 545f968b954SMateusz Kozlowski struct ftl_layout_region_descr *reg_descr; 546f968b954SMateusz Kozlowski static struct ftl_layout_region_descr nvc_regs[] = { 547f968b954SMateusz Kozlowski { .type = FTL_LAYOUT_REGION_TYPE_SB_BASE, .ver = FTL_SB_VERSION_CURRENT }, 5489f42898aSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_DATA_BASE, .ver = 0, .on_reg_miss = layout_fixup_reg_data_base }, 549f968b954SMateusz Kozlowski { .type = FTL_LAYOUT_REGION_TYPE_VALID_MAP, .ver = 0 }, 550f968b954SMateusz Kozlowski { .type = FTL_LAYOUT_REGION_TYPE_INVALID, .ver = 0 }, 551f968b954SMateusz Kozlowski }; 552f968b954SMateusz Kozlowski 553f968b954SMateusz Kozlowski for (reg_descr = nvc_regs; reg_descr->type != FTL_LAYOUT_REGION_TYPE_INVALID; reg_descr++) { 554f968b954SMateusz Kozlowski struct ftl_layout_region *region; 555f968b954SMateusz Kozlowski 5565555d51cSLukasz Lasek if (layout_region_verify(dev, reg_descr->type) && 557f968b954SMateusz Kozlowski reg_descr->on_reg_miss && reg_descr->on_reg_miss(dev)) { 558f968b954SMateusz Kozlowski return -1; 559f968b954SMateusz Kozlowski } 560f968b954SMateusz Kozlowski 561f968b954SMateusz Kozlowski region = &dev->layout.region[reg_descr->type]; 562f968b954SMateusz Kozlowski region->type = reg_descr->type; 563f968b954SMateusz Kozlowski region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID; 564f968b954SMateusz Kozlowski region->name = ftl_md_region_name(reg_descr->type); 565f968b954SMateusz Kozlowski 566f968b954SMateusz Kozlowski region->bdev_desc = dev->base_bdev_desc; 567f968b954SMateusz Kozlowski region->ioch = dev->base_ioch; 568f968b954SMateusz Kozlowski region->vss_blksz = 0; 569f968b954SMateusz Kozlowski } 570f968b954SMateusz Kozlowski 571f968b954SMateusz Kozlowski return 0; 572f968b954SMateusz Kozlowski } 573f968b954SMateusz Kozlowski 574f968b954SMateusz Kozlowski static int 575f968b954SMateusz Kozlowski layout_fixup_nvc(struct spdk_ftl_dev *dev) 576f968b954SMateusz Kozlowski { 5775555d51cSLukasz Lasek int rc; 578f968b954SMateusz Kozlowski struct ftl_layout_region_descr { 579f968b954SMateusz Kozlowski enum ftl_layout_region_type type; 5805555d51cSLukasz Lasek bool deprecated; 581f968b954SMateusz Kozlowski enum ftl_layout_region_type mirror_type; 582f968b954SMateusz Kozlowski }; 583f968b954SMateusz Kozlowski struct ftl_layout_region_descr *reg_descr; 584f968b954SMateusz Kozlowski static struct ftl_layout_region_descr nvc_regs[] = { 5855555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_SB, .mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE }, 5865555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_L2P }, 5875555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_BAND_MD, .mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR }, 5885555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR }, 5895555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_TRIM_MD, .mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR }, 5905555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR }, 5912d613454SMateusz Kozlowski { .type = FTL_LAYOUT_REGION_TYPE_TRIM_LOG, .mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR }, 5922d613454SMateusz Kozlowski { .type = FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR }, 5935555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_NVC_MD, .mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR }, 5945555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR }, 5955555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_DATA_NVC, .deprecated = true }, 5965555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC }, 5975555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT }, 5985555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP }, 5995555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT }, 600*6d6179ffSMateusz Kozlowski { .type = FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN }, 601*6d6179ffSMateusz Kozlowski { .type = FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX }, 6025555d51cSLukasz Lasek { .type = FTL_LAYOUT_REGION_TYPE_INVALID }, 603f968b954SMateusz Kozlowski }; 604f968b954SMateusz Kozlowski 605f968b954SMateusz Kozlowski for (reg_descr = nvc_regs; reg_descr->type != FTL_LAYOUT_REGION_TYPE_INVALID; reg_descr++) { 606f968b954SMateusz Kozlowski struct ftl_layout_region *region; 607f968b954SMateusz Kozlowski 6085555d51cSLukasz Lasek rc = layout_region_verify(dev, reg_descr->type); 6095555d51cSLukasz Lasek if (rc == -ENOENT) { 6105555d51cSLukasz Lasek if (reg_descr->deprecated) { 6115555d51cSLukasz Lasek continue; 6125555d51cSLukasz Lasek } 6135555d51cSLukasz Lasek 6145555d51cSLukasz Lasek ftl_layout_upgrade_add_region_placeholder(dev, dev->nvc_layout_tracker, reg_descr->type); 6155555d51cSLukasz Lasek } else if (rc) { 616f968b954SMateusz Kozlowski return -1; 617f968b954SMateusz Kozlowski } 618f968b954SMateusz Kozlowski 6195555d51cSLukasz Lasek if (reg_descr->deprecated) { 6205555d51cSLukasz Lasek rc = ftl_layout_upgrade_drop_region(dev, dev->nvc_layout_tracker, reg_descr->type, 6215555d51cSLukasz Lasek dev->layout.region[reg_descr->type].current.version); 6225555d51cSLukasz Lasek if (rc) { 6235555d51cSLukasz Lasek return rc; 6245555d51cSLukasz Lasek } 6255555d51cSLukasz Lasek continue; 6265555d51cSLukasz Lasek } 6275555d51cSLukasz Lasek 628f968b954SMateusz Kozlowski region = &dev->layout.region[reg_descr->type]; 629f968b954SMateusz Kozlowski region->type = reg_descr->type; 6305555d51cSLukasz Lasek region->mirror_type = (reg_descr->mirror_type) ? reg_descr->mirror_type : 6315555d51cSLukasz Lasek FTL_LAYOUT_REGION_TYPE_INVALID; 632f968b954SMateusz Kozlowski region->name = ftl_md_region_name(reg_descr->type); 633f968b954SMateusz Kozlowski 634f968b954SMateusz Kozlowski region->bdev_desc = dev->nv_cache.bdev_desc; 635f968b954SMateusz Kozlowski region->ioch = dev->nv_cache.cache_ioch; 636f968b954SMateusz Kozlowski region->vss_blksz = dev->nv_cache.md_size; 637f968b954SMateusz Kozlowski } 638f968b954SMateusz Kozlowski 639f968b954SMateusz Kozlowski return 0; 640f968b954SMateusz Kozlowski } 641f968b954SMateusz Kozlowski 642f968b954SMateusz Kozlowski static int 643f968b954SMateusz Kozlowski filter_region_type_base(enum ftl_layout_region_type reg_type) 644f968b954SMateusz Kozlowski { 645f968b954SMateusz Kozlowski switch (reg_type) { 646f968b954SMateusz Kozlowski case FTL_LAYOUT_REGION_TYPE_SB_BASE: 647f968b954SMateusz Kozlowski case FTL_LAYOUT_REGION_TYPE_DATA_BASE: 648f968b954SMateusz Kozlowski case FTL_LAYOUT_REGION_TYPE_VALID_MAP: 649f968b954SMateusz Kozlowski return 0; 650f968b954SMateusz Kozlowski 651f968b954SMateusz Kozlowski default: 652f968b954SMateusz Kozlowski return 1; 653f968b954SMateusz Kozlowski } 654f968b954SMateusz Kozlowski } 655f968b954SMateusz Kozlowski 656f968b954SMateusz Kozlowski static int 657f968b954SMateusz Kozlowski filter_region_type_nvc(enum ftl_layout_region_type reg_type) 658f968b954SMateusz Kozlowski { 659f968b954SMateusz Kozlowski return filter_region_type_base(reg_type) ? 0 : 1; 660f968b954SMateusz Kozlowski } 661f968b954SMateusz Kozlowski 662f968b954SMateusz Kozlowski static int 663f968b954SMateusz Kozlowski layout_apply_nvc(struct spdk_ftl_dev *dev) 664f968b954SMateusz Kozlowski { 665f968b954SMateusz Kozlowski if (layout_apply_from_sb_blob(dev, dev->nvc_layout_tracker, filter_region_type_nvc) || 666f968b954SMateusz Kozlowski layout_fixup_nvc(dev)) { 667f968b954SMateusz Kozlowski return -1; 668f968b954SMateusz Kozlowski } 669f968b954SMateusz Kozlowski return 0; 670f968b954SMateusz Kozlowski } 671f968b954SMateusz Kozlowski 672f968b954SMateusz Kozlowski static int 673f968b954SMateusz Kozlowski layout_apply_base(struct spdk_ftl_dev *dev) 674f968b954SMateusz Kozlowski { 675f968b954SMateusz Kozlowski if (layout_apply_from_sb_blob(dev, dev->base_layout_tracker, filter_region_type_base) || 676f968b954SMateusz Kozlowski layout_fixup_base(dev)) { 677f968b954SMateusz Kozlowski return -1; 678f968b954SMateusz Kozlowski } 679f968b954SMateusz Kozlowski return 0; 680f968b954SMateusz Kozlowski } 681f968b954SMateusz Kozlowski 682f968b954SMateusz Kozlowski int 683f968b954SMateusz Kozlowski ftl_superblock_v5_md_layout_apply(struct spdk_ftl_dev *dev) 684f968b954SMateusz Kozlowski { 685f968b954SMateusz Kozlowski if (layout_apply_nvc(dev) || layout_apply_base(dev)) { 686f968b954SMateusz Kozlowski return -1; 687f968b954SMateusz Kozlowski } 688f968b954SMateusz Kozlowski return 0; 689f968b954SMateusz Kozlowski } 690