xref: /spdk/lib/ftl/upgrade/ftl_sb_upgrade.c (revision 8fc78fd8776efac4fb3c6323030b7f57a7a3401a)
1c8ab874dSKozlowski Mateusz /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2022 Intel Corporation.
3c8ab874dSKozlowski Mateusz  *   All rights reserved.
4c8ab874dSKozlowski Mateusz  */
5c8ab874dSKozlowski Mateusz 
6c8ab874dSKozlowski Mateusz #include "ftl_sb_upgrade.h"
7c8ab874dSKozlowski Mateusz #include "ftl_layout_upgrade.h"
8c8ab874dSKozlowski Mateusz #include "ftl_layout.h"
9c8ab874dSKozlowski Mateusz #include "ftl_core.h"
10*8fc78fd8SMateusz Kozlowski #include "ftl_sb_v3.h"
11*8fc78fd8SMateusz Kozlowski #include "utils/ftl_df.h"
12*8fc78fd8SMateusz Kozlowski #include "utils/ftl_layout_tracker_bdev.h"
13*8fc78fd8SMateusz Kozlowski 
14*8fc78fd8SMateusz Kozlowski static int
sb_v4_to_v5_verify(struct spdk_ftl_dev * dev,struct ftl_layout_region * region)15*8fc78fd8SMateusz Kozlowski sb_v4_to_v5_verify(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
16*8fc78fd8SMateusz Kozlowski {
17*8fc78fd8SMateusz Kozlowski 	struct ftl_layout_region *reg;
18*8fc78fd8SMateusz Kozlowski 	uint32_t reg_no;
19*8fc78fd8SMateusz Kozlowski 	int rc = ftl_region_upgrade_enabled(dev, region);
20*8fc78fd8SMateusz Kozlowski 
21*8fc78fd8SMateusz Kozlowski 	if (rc) {
22*8fc78fd8SMateusz Kozlowski 		return rc;
23*8fc78fd8SMateusz Kozlowski 	}
24*8fc78fd8SMateusz Kozlowski 
25*8fc78fd8SMateusz Kozlowski 	/* Verify there are no pending major upgrades */
26*8fc78fd8SMateusz Kozlowski 	for (reg_no = 0; reg_no < FTL_LAYOUT_REGION_TYPE_MAX; reg_no++) {
27*8fc78fd8SMateusz Kozlowski 		reg = ftl_layout_region_get(dev, reg_no);
28*8fc78fd8SMateusz Kozlowski 		if (!reg) {
29*8fc78fd8SMateusz Kozlowski 			/* This region does not exist */
30*8fc78fd8SMateusz Kozlowski 			continue;
31*8fc78fd8SMateusz Kozlowski 		}
32*8fc78fd8SMateusz Kozlowski 
33*8fc78fd8SMateusz Kozlowski 		if (reg->current.version <= ftl_layout_upgrade_region_get_latest_version(reg->type)) {
34*8fc78fd8SMateusz Kozlowski 			/* Only latest region version found */
35*8fc78fd8SMateusz Kozlowski 			continue;
36*8fc78fd8SMateusz Kozlowski 		}
37*8fc78fd8SMateusz Kozlowski 
38*8fc78fd8SMateusz Kozlowski 		/* Previous version found, major upgrade */
39*8fc78fd8SMateusz Kozlowski 		FTL_WARNLOG(dev, "FTL superblock upgrade v4 to v5 disabled: " \
40*8fc78fd8SMateusz Kozlowski 			    "cannot upgrade region type 0x%"PRIx32" v%"PRId64" to v%"PRId64", " \
41*8fc78fd8SMateusz Kozlowski 			    "offs 0x%"PRIx64", blks 0x%"PRIx64"\n",
42*8fc78fd8SMateusz Kozlowski 			    reg->type, reg->current.version, ftl_layout_upgrade_region_get_latest_version(reg->type),
43*8fc78fd8SMateusz Kozlowski 			    reg->current.offset, reg->current.blocks);
44*8fc78fd8SMateusz Kozlowski 		return -1;
45*8fc78fd8SMateusz Kozlowski 	}
46*8fc78fd8SMateusz Kozlowski 
47*8fc78fd8SMateusz Kozlowski 	return 0;
48*8fc78fd8SMateusz Kozlowski }
49*8fc78fd8SMateusz Kozlowski 
50*8fc78fd8SMateusz Kozlowski static bool
sb_v3_md_region_is_fixed(int reg_type)51*8fc78fd8SMateusz Kozlowski sb_v3_md_region_is_fixed(int reg_type)
52*8fc78fd8SMateusz Kozlowski {
53*8fc78fd8SMateusz Kozlowski 	switch (reg_type) {
54*8fc78fd8SMateusz Kozlowski 	case FTL_LAYOUT_REGION_TYPE_SB:
55*8fc78fd8SMateusz Kozlowski 	case FTL_LAYOUT_REGION_TYPE_SB_BASE:
56*8fc78fd8SMateusz Kozlowski 	case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
57*8fc78fd8SMateusz Kozlowski 		return true;
58*8fc78fd8SMateusz Kozlowski 
59*8fc78fd8SMateusz Kozlowski 	default:
60*8fc78fd8SMateusz Kozlowski 		return false;
61*8fc78fd8SMateusz Kozlowski 	}
62*8fc78fd8SMateusz Kozlowski }
63*8fc78fd8SMateusz Kozlowski 
64*8fc78fd8SMateusz Kozlowski static bool
sb_v3_md_region_is_nvc(int reg_type)65*8fc78fd8SMateusz Kozlowski sb_v3_md_region_is_nvc(int reg_type)
66*8fc78fd8SMateusz Kozlowski {
67*8fc78fd8SMateusz Kozlowski 	switch (reg_type) {
68*8fc78fd8SMateusz Kozlowski 	case FTL_LAYOUT_REGION_TYPE_SB_BASE:
69*8fc78fd8SMateusz Kozlowski 	case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
70*8fc78fd8SMateusz Kozlowski 	case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
71*8fc78fd8SMateusz Kozlowski 		return false;
72*8fc78fd8SMateusz Kozlowski 
73*8fc78fd8SMateusz Kozlowski 	default:
74*8fc78fd8SMateusz Kozlowski 		return true;
75*8fc78fd8SMateusz Kozlowski 	}
76*8fc78fd8SMateusz Kozlowski }
77*8fc78fd8SMateusz Kozlowski 
78*8fc78fd8SMateusz Kozlowski static int
sb_v3_md_layout_convert(struct spdk_ftl_dev * dev)79*8fc78fd8SMateusz Kozlowski sb_v3_md_layout_convert(struct spdk_ftl_dev *dev)
80*8fc78fd8SMateusz Kozlowski {
81*8fc78fd8SMateusz Kozlowski 	struct ftl_superblock_v3 *sb = (struct ftl_superblock_v3 *)dev->sb;
82*8fc78fd8SMateusz Kozlowski 	struct ftl_superblock_v3_md_region *sb_reg = &sb->md_layout_head;
83*8fc78fd8SMateusz Kozlowski 	const struct ftl_layout_tracker_bdev_region_props *reg_props;
84*8fc78fd8SMateusz Kozlowski 
85*8fc78fd8SMateusz Kozlowski 	while (sb_reg->type != FTL_LAYOUT_REGION_TYPE_INVALID) {
86*8fc78fd8SMateusz Kozlowski 		if (sb_reg->type == FTL_LAYOUT_REGION_TYPE_FREE_NVC ||
87*8fc78fd8SMateusz Kozlowski 		    sb_reg->type == FTL_LAYOUT_REGION_TYPE_FREE_BASE) {
88*8fc78fd8SMateusz Kozlowski 			goto next_sb_reg;
89*8fc78fd8SMateusz Kozlowski 		}
90*8fc78fd8SMateusz Kozlowski 
91*8fc78fd8SMateusz Kozlowski 		if (sb_reg->type >= FTL_LAYOUT_REGION_TYPE_MAX) {
92*8fc78fd8SMateusz Kozlowski 			FTL_ERRLOG(dev, "Invalid MD region type found\n");
93*8fc78fd8SMateusz Kozlowski 			return -1;
94*8fc78fd8SMateusz Kozlowski 		}
95*8fc78fd8SMateusz Kozlowski 
96*8fc78fd8SMateusz Kozlowski 		if (sb_v3_md_region_is_fixed(sb_reg->type)) {
97*8fc78fd8SMateusz Kozlowski 			FTL_ERRLOG(dev, "Unsupported MD region type found\n");
98*8fc78fd8SMateusz Kozlowski 			return -1;
99*8fc78fd8SMateusz Kozlowski 		}
100*8fc78fd8SMateusz Kozlowski 
101*8fc78fd8SMateusz Kozlowski 		if (sb_v3_md_region_is_nvc(sb_reg->type)) {
102*8fc78fd8SMateusz Kozlowski 			reg_props = ftl_layout_tracker_bdev_insert_region(dev->nvc_layout_tracker, sb_reg->type,
103*8fc78fd8SMateusz Kozlowski 					sb_reg->version, sb_reg->blk_offs, sb_reg->blk_sz);
104*8fc78fd8SMateusz Kozlowski 		} else {
105*8fc78fd8SMateusz Kozlowski 			reg_props = ftl_layout_tracker_bdev_insert_region(dev->base_layout_tracker, sb_reg->type,
106*8fc78fd8SMateusz Kozlowski 					sb_reg->version, sb_reg->blk_offs, sb_reg->blk_sz);
107*8fc78fd8SMateusz Kozlowski 		}
108*8fc78fd8SMateusz Kozlowski 		if (!reg_props) {
109*8fc78fd8SMateusz Kozlowski 			FTL_ERRLOG(dev, "Cannot upgrade SB MD layout - region type 0x%"PRIx32" v%"PRId32" " \
110*8fc78fd8SMateusz Kozlowski 				   "offs 0x%"PRIx64" blks 0x%"PRIx64"\n",
111*8fc78fd8SMateusz Kozlowski 				   sb_reg->type, sb_reg->version, sb_reg->blk_offs, sb_reg->blk_sz);
112*8fc78fd8SMateusz Kozlowski 		}
113*8fc78fd8SMateusz Kozlowski 
114*8fc78fd8SMateusz Kozlowski next_sb_reg:
115*8fc78fd8SMateusz Kozlowski 		if (sb_reg->df_next == FTL_DF_OBJ_ID_INVALID) {
116*8fc78fd8SMateusz Kozlowski 			break;
117*8fc78fd8SMateusz Kozlowski 		}
118*8fc78fd8SMateusz Kozlowski 
119*8fc78fd8SMateusz Kozlowski 		if (UINT64_MAX - (uintptr_t)sb <= sb_reg->df_next) {
120*8fc78fd8SMateusz Kozlowski 			FTL_ERRLOG(dev, "Buffer overflow\n");
121*8fc78fd8SMateusz Kozlowski 			return -EOVERFLOW;
122*8fc78fd8SMateusz Kozlowski 		}
123*8fc78fd8SMateusz Kozlowski 
124*8fc78fd8SMateusz Kozlowski 		sb_reg = ftl_df_get_obj_ptr(sb, sb_reg->df_next);
125*8fc78fd8SMateusz Kozlowski 		if (ftl_superblock_v3_md_region_overflow(dev, sb_reg)) {
126*8fc78fd8SMateusz Kozlowski 			FTL_ERRLOG(dev, "Buffer overflow\n");
127*8fc78fd8SMateusz Kozlowski 			return -EOVERFLOW;
128*8fc78fd8SMateusz Kozlowski 		}
129*8fc78fd8SMateusz Kozlowski 	}
130*8fc78fd8SMateusz Kozlowski 
131*8fc78fd8SMateusz Kozlowski 	return 0;
132*8fc78fd8SMateusz Kozlowski }
133*8fc78fd8SMateusz Kozlowski 
134*8fc78fd8SMateusz Kozlowski static int
sb_v4_to_v5_upgrade(struct spdk_ftl_dev * dev,struct ftl_layout_upgrade_ctx * ctx)135*8fc78fd8SMateusz Kozlowski sb_v4_to_v5_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx)
136*8fc78fd8SMateusz Kozlowski {
137*8fc78fd8SMateusz Kozlowski 	union ftl_superblock_ver *sb = (union ftl_superblock_ver *)dev->sb;
138*8fc78fd8SMateusz Kozlowski 
139*8fc78fd8SMateusz Kozlowski 	FTL_NOTICELOG(dev, "FTL superblock upgrade v4 to v5\n");
140*8fc78fd8SMateusz Kozlowski 
141*8fc78fd8SMateusz Kozlowski 	/* Convert v3 MD layout */
142*8fc78fd8SMateusz Kozlowski 	if (ftl_superblock_is_blob_area_empty(dev->sb)) {
143*8fc78fd8SMateusz Kozlowski 		FTL_ERRLOG(dev, "SBv3 MD layout empty\n");
144*8fc78fd8SMateusz Kozlowski 		return -1;
145*8fc78fd8SMateusz Kozlowski 	}
146*8fc78fd8SMateusz Kozlowski 	if (sb_v3_md_layout_convert(dev)) {
147*8fc78fd8SMateusz Kozlowski 		FTL_ERRLOG(dev, "SBv3 MD layout load failed\n");
148*8fc78fd8SMateusz Kozlowski 		return -1;
149*8fc78fd8SMateusz Kozlowski 	}
150*8fc78fd8SMateusz Kozlowski 
151*8fc78fd8SMateusz Kozlowski 	/* Bump up the version */
152*8fc78fd8SMateusz Kozlowski 	sb->v5.header.version = FTL_SB_VERSION_5;
153*8fc78fd8SMateusz Kozlowski 	sb->v5.blob_area_end = 0;
154*8fc78fd8SMateusz Kozlowski 
155*8fc78fd8SMateusz Kozlowski 	/* Keep v5 layout empty */
156*8fc78fd8SMateusz Kozlowski 	memset(sb->v5.nvc_dev_name, 0, sizeof(sb->v5.nvc_dev_name));
157*8fc78fd8SMateusz Kozlowski 	memset(&sb->v5.md_layout_nvc, 0, sizeof(sb->v5.md_layout_nvc));
158*8fc78fd8SMateusz Kozlowski 	memset(sb->v5.base_dev_name, 0, sizeof(sb->v5.base_dev_name));
159*8fc78fd8SMateusz Kozlowski 	memset(&sb->v5.md_layout_base, 0, sizeof(sb->v5.md_layout_base));
160*8fc78fd8SMateusz Kozlowski 	memset(&sb->v5.layout_params, 0, sizeof(sb->v5.layout_params));
161*8fc78fd8SMateusz Kozlowski 
162*8fc78fd8SMateusz Kozlowski 	return 0;
163*8fc78fd8SMateusz Kozlowski }
164c8ab874dSKozlowski Mateusz 
165c8ab874dSKozlowski Mateusz struct ftl_region_upgrade_desc sb_upgrade_desc[] = {
166c8ab874dSKozlowski Mateusz 	[FTL_SB_VERSION_0] = {.verify = ftl_region_upgrade_disabled},
167c8ab874dSKozlowski Mateusz 	[FTL_SB_VERSION_1] = {.verify = ftl_region_upgrade_disabled},
168c8ab874dSKozlowski Mateusz 	[FTL_SB_VERSION_2] = {.verify = ftl_region_upgrade_disabled},
169c8ab874dSKozlowski Mateusz 	[FTL_SB_VERSION_3] = {.verify = ftl_region_upgrade_disabled},
170*8fc78fd8SMateusz Kozlowski 	[FTL_SB_VERSION_4] = {.verify = sb_v4_to_v5_verify, .upgrade = sb_v4_to_v5_upgrade, .new_version = FTL_SB_VERSION_5},
171c8ab874dSKozlowski Mateusz };
172c8ab874dSKozlowski Mateusz 
173c8ab874dSKozlowski Mateusz SPDK_STATIC_ASSERT(SPDK_COUNTOF(sb_upgrade_desc) == FTL_SB_VERSION_CURRENT,
174c8ab874dSKozlowski Mateusz 		   "Missing SB region upgrade descriptors");
175