1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2023 Solidigm All Rights Reserved 3 * Copyright (C) 2022 Intel Corporation. 4 * All rights reserved. 5 */ 6 7 #include "ftl_layout_upgrade.h" 8 #include "ftl_layout.h" 9 #include "ftl_sb_current.h" 10 #include "ftl_sb_prev.h" 11 #include "ftl_core.h" 12 #include "ftl_band.h" 13 14 int 15 ftl_region_upgrade_disabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region) 16 { 17 return -1; 18 } 19 20 int 21 ftl_region_upgrade_enabled(struct spdk_ftl_dev *dev, struct ftl_layout_region *region) 22 { 23 if (!(dev->sb->clean == 1 && dev->sb_shm->shm_clean == 0)) { 24 FTL_ERRLOG(dev, "FTL region upgrade: SB dirty\n"); 25 return -1; 26 } 27 return 0; 28 } 29 30 #ifndef UTEST 31 extern struct ftl_region_upgrade_desc sb_upgrade_desc[]; 32 extern struct ftl_region_upgrade_desc p2l_upgrade_desc[]; 33 extern struct ftl_region_upgrade_desc nvc_upgrade_desc[]; 34 extern struct ftl_region_upgrade_desc band_upgrade_desc[]; 35 36 static struct ftl_layout_upgrade_desc_list layout_upgrade_desc[] = { 37 [FTL_LAYOUT_REGION_TYPE_SB] = { 38 .latest_ver = FTL_SB_VERSION_CURRENT, 39 .count = FTL_SB_VERSION_CURRENT, 40 .desc = sb_upgrade_desc, 41 }, 42 [FTL_LAYOUT_REGION_TYPE_SB_BASE] = { 43 .latest_ver = FTL_SB_VERSION_CURRENT, 44 .count = FTL_SB_VERSION_CURRENT, 45 .desc = sb_upgrade_desc, 46 }, 47 [FTL_LAYOUT_REGION_TYPE_L2P] = {}, 48 [FTL_LAYOUT_REGION_TYPE_BAND_MD] = { 49 .latest_ver = FTL_BAND_VERSION_CURRENT, 50 .count = FTL_BAND_VERSION_CURRENT, 51 .desc = band_upgrade_desc, 52 }, 53 [FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = { 54 .latest_ver = FTL_BAND_VERSION_CURRENT, 55 .count = FTL_BAND_VERSION_CURRENT, 56 .desc = band_upgrade_desc, 57 }, 58 [FTL_LAYOUT_REGION_TYPE_VALID_MAP] = {}, 59 [FTL_LAYOUT_REGION_TYPE_NVC_MD] = { 60 .latest_ver = FTL_NVC_VERSION_CURRENT, 61 .count = FTL_NVC_VERSION_CURRENT, 62 .desc = nvc_upgrade_desc, 63 }, 64 [FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = { 65 .latest_ver = FTL_NVC_VERSION_CURRENT, 66 .count = FTL_NVC_VERSION_CURRENT, 67 .desc = nvc_upgrade_desc, 68 }, 69 [FTL_LAYOUT_REGION_TYPE_DATA_NVC] = {}, 70 [FTL_LAYOUT_REGION_TYPE_DATA_BASE] = {}, 71 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = { 72 .latest_ver = FTL_P2L_VERSION_CURRENT, 73 .count = FTL_P2L_VERSION_CURRENT, 74 .desc = p2l_upgrade_desc, 75 }, 76 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = { 77 .latest_ver = FTL_P2L_VERSION_CURRENT, 78 .count = FTL_P2L_VERSION_CURRENT, 79 .desc = p2l_upgrade_desc, 80 }, 81 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = { 82 .latest_ver = FTL_P2L_VERSION_CURRENT, 83 .count = FTL_P2L_VERSION_CURRENT, 84 .desc = p2l_upgrade_desc, 85 }, 86 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = { 87 .latest_ver = FTL_P2L_VERSION_CURRENT, 88 .count = FTL_P2L_VERSION_CURRENT, 89 .desc = p2l_upgrade_desc, 90 }, 91 [FTL_LAYOUT_REGION_TYPE_TRIM_MD] = {}, 92 [FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = {}, 93 }; 94 95 SPDK_STATIC_ASSERT(sizeof(layout_upgrade_desc) / sizeof(*layout_upgrade_desc) == 96 FTL_LAYOUT_REGION_TYPE_MAX, 97 "Missing layout upgrade descriptors"); 98 #endif 99 100 static int 101 region_verify(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 102 { 103 uint64_t ver; 104 105 assert(ctx->reg); 106 ver = ctx->reg->current.version; 107 if (ver > ctx->upgrade->latest_ver) { 108 FTL_ERRLOG(dev, "Unknown region version\n"); 109 return -1; 110 } 111 112 while (ver < ctx->upgrade->latest_ver) { 113 int rc = ctx->upgrade->desc[ver].verify(dev, ctx->reg); 114 if (rc) { 115 return rc; 116 } 117 ftl_bug(ver > ctx->upgrade->desc[ver].new_version); 118 ftl_bug(ctx->upgrade->desc[ver].new_version > ctx->upgrade->latest_ver); 119 ver = ctx->upgrade->desc[ver].new_version; 120 } 121 return 0; 122 } 123 124 int 125 ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 126 { 127 int rc = 0; 128 uint64_t ver; 129 130 assert(ctx->reg); 131 assert(ctx->reg->current.version <= ctx->upgrade->latest_ver); 132 ver = ctx->reg->current.version; 133 if (ver < ctx->upgrade->latest_ver) { 134 ctx->next_reg_ver = ctx->upgrade->desc[ver].new_version; 135 rc = ctx->upgrade->desc[ver].upgrade(dev, ctx); 136 } 137 return rc; 138 } 139 140 void 141 ftl_region_upgrade_completed(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx, 142 uint64_t entry_size, uint64_t num_entries, int status) 143 { 144 int rc; 145 146 assert(ctx->reg); 147 assert(ctx->reg->current.version < ctx->next_reg_ver); 148 assert(ctx->next_reg_ver <= ctx->upgrade->latest_ver); 149 150 if (!status) { 151 if (ctx->reg->type != FTL_LAYOUT_REGION_TYPE_SB) { 152 /* Superblock region is always default-created in the latest version - see ftl_layout_setup_superblock() */ 153 rc = ftl_superblock_md_layout_upgrade_region(dev, ctx->reg, ctx->next_reg_ver); 154 if (entry_size && num_entries) { 155 dev->layout.region[ctx->reg->type].entry_size = entry_size; 156 dev->layout.region[ctx->reg->type].num_entries = num_entries; 157 } 158 159 ftl_bug(rc != 0); 160 } 161 162 ctx->reg->current.version = ctx->next_reg_ver; 163 } 164 165 if (ctx->cb) { 166 ctx->cb(dev, ctx->cb_ctx, status); 167 } 168 } 169 170 int 171 ftl_layout_verify(struct spdk_ftl_dev *dev) 172 { 173 struct ftl_layout *layout = &dev->layout; 174 struct ftl_layout_upgrade_ctx ctx = {0}; 175 enum ftl_layout_region_type reg_type; 176 177 /** 178 * Upon SB upgrade some MD regions may be missing in the MD layout blob - e.g. v3 to v5, FTL_LAYOUT_REGION_TYPE_DATA_BASE. 179 * The regions couldn't have be added in the SB upgrade path, as the FTL layout wasn't initialized at that point. 180 * Now that the FTL layout is initialized, add the missing regions and store the MD layout blob again. 181 */ 182 183 if (ftl_validate_regions(dev, layout)) { 184 return -1; 185 } 186 187 for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) { 188 ctx.reg = ftl_layout_region_get(dev, reg_type); 189 ctx.upgrade = &layout_upgrade_desc[reg_type]; 190 if (!ctx.reg) { 191 continue; 192 } 193 194 if (region_verify(dev, &ctx)) { 195 return -1; 196 } 197 } 198 199 return 0; 200 } 201 202 int 203 ftl_upgrade_layout_dump(struct spdk_ftl_dev *dev) 204 { 205 if (ftl_validate_regions(dev, &dev->layout)) { 206 return -1; 207 } 208 209 ftl_layout_dump(dev); 210 ftl_superblock_md_layout_dump(dev); 211 return 0; 212 } 213 214 int 215 ftl_superblock_upgrade(struct spdk_ftl_dev *dev) 216 { 217 struct ftl_layout_upgrade_ctx ctx = {0}; 218 struct ftl_layout_region *reg = ftl_layout_region_get(dev, FTL_LAYOUT_REGION_TYPE_SB); 219 int rc; 220 221 ctx.reg = reg; 222 ctx.upgrade = &layout_upgrade_desc[FTL_LAYOUT_REGION_TYPE_SB]; 223 reg->current.version = dev->sb->header.version; 224 225 rc = region_verify(dev, &ctx); 226 if (rc) { 227 return rc; 228 } 229 230 while (reg->current.version < ctx.upgrade->latest_ver) { 231 rc = ftl_region_upgrade(dev, &ctx); 232 if (rc) { 233 return rc; 234 } 235 /* SB upgrades are all synchronous */ 236 ftl_region_upgrade_completed(dev, &ctx, 0, 0, rc); 237 } 238 239 /* The mirror shares the same DMA buf, so it is automatically updated upon SB store */ 240 dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB_BASE].current.version = reg->current.version; 241 return 0; 242 } 243 244 static int 245 layout_upgrade_select_next_region(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 246 { 247 struct ftl_layout_region *reg; 248 uint64_t reg_ver, reg_latest_ver; 249 uint32_t reg_type = ctx->reg->type; 250 251 while (reg_type != FTL_LAYOUT_REGION_TYPE_MAX) { 252 assert(ctx->reg); 253 assert(ctx->upgrade); 254 reg = ctx->reg; 255 reg_latest_ver = ctx->upgrade->latest_ver; 256 reg_ver = reg->current.version; 257 258 if (reg_ver == reg_latest_ver || reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) { 259 /* select the next region to upgrade */ 260 reg_type++; 261 if (reg_type == FTL_LAYOUT_REGION_TYPE_MAX) { 262 break; 263 } 264 ctx->reg++; 265 ctx->upgrade++; 266 } else if (reg_ver < reg_latest_ver) { 267 /* qualify region version to upgrade */ 268 return FTL_LAYOUT_UPGRADE_CONTINUE; 269 } else { 270 /* unknown version */ 271 assert(reg_ver <= reg_latest_ver); 272 FTL_ERRLOG(dev, "Region %d upgrade fault: version %"PRIu64"/%"PRIu64"\n", reg_type, reg_ver, 273 reg_latest_ver); 274 return FTL_LAYOUT_UPGRADE_FAULT; 275 } 276 } 277 278 return FTL_LAYOUT_UPGRADE_DONE; 279 } 280 281 int 282 ftl_layout_upgrade_init_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 283 { 284 if (!ctx->reg) { 285 ctx->reg = ftl_layout_region_get(dev, 0); 286 ctx->upgrade = &layout_upgrade_desc[0]; 287 static_assert(FTL_LAYOUT_REGION_TYPE_SB == 0, "Invalid SB region type"); 288 } 289 290 return layout_upgrade_select_next_region(dev, ctx); 291 } 292 293 uint64_t 294 ftl_layout_upgrade_region_get_latest_version(enum ftl_layout_region_type reg_type) 295 { 296 assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX); 297 return layout_upgrade_desc[reg_type].latest_ver; 298 } 299