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