xref: /spdk/lib/ftl/upgrade/ftl_sb_v5.c (revision 6d6179ff420a322c5161a49a5af5bfd30e78674e)
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, &reg_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, &reg_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, &reg_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, &reg_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 				&reg_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 				&reg_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 				&reg_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 			&reg_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