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 [FTL_LAYOUT_REGION_TYPE_TRIM_LOG] = { 113 .latest_ver = FTL_TRIM_LOG_VERSION_CURRENT, 114 .count = FTL_TRIM_LOG_VERSION_CURRENT, 115 .desc = trim_log_upgrade_desc, 116 }, 117 [FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR] = { 118 .latest_ver = FTL_TRIM_LOG_VERSION_CURRENT, 119 .count = FTL_TRIM_LOG_VERSION_CURRENT, 120 .desc = trim_log_upgrade_desc, 121 }, 122 [FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN] = {}, 123 [FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX] = {}, 124 }; 125 126 SPDK_STATIC_ASSERT(sizeof(layout_upgrade_desc) / sizeof(*layout_upgrade_desc) == 127 FTL_LAYOUT_REGION_TYPE_MAX, 128 "Missing layout upgrade descriptors"); 129 #endif 130 131 uint64_t 132 ftl_layout_upgrade_get_latest_version(enum ftl_layout_region_type reg_type) 133 { 134 assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX); 135 return layout_upgrade_desc[reg_type].latest_ver; 136 } 137 138 static int 139 region_verify(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 140 { 141 uint64_t ver; 142 143 assert(ctx->reg); 144 ver = ctx->reg->current.version; 145 if (ver > ctx->upgrade->latest_ver) { 146 FTL_ERRLOG(dev, "Unknown region version\n"); 147 return -1; 148 } 149 150 while (ver < ctx->upgrade->latest_ver) { 151 int rc = ctx->upgrade->desc[ver].verify(dev, ctx->reg); 152 if (rc) { 153 return rc; 154 } 155 ftl_bug(ver > ctx->upgrade->desc[ver].new_version); 156 ftl_bug(ctx->upgrade->desc[ver].new_version > ctx->upgrade->latest_ver); 157 ver = ctx->upgrade->desc[ver].new_version; 158 } 159 return 0; 160 } 161 162 int 163 ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 164 { 165 int rc = 0; 166 uint64_t ver; 167 168 assert(ctx->reg); 169 assert(ctx->reg->current.version <= ctx->upgrade->latest_ver); 170 ver = ctx->reg->current.version; 171 if (ver < ctx->upgrade->latest_ver) { 172 ctx->next_reg_ver = ctx->upgrade->desc[ver].new_version; 173 rc = ctx->upgrade->desc[ver].upgrade(dev, ctx); 174 } 175 return rc; 176 } 177 178 void 179 ftl_region_upgrade_completed(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx, 180 uint64_t entry_size, uint64_t num_entries, int status) 181 { 182 int rc; 183 184 assert(ctx->reg); 185 assert(ctx->reg->current.version < ctx->next_reg_ver); 186 assert(ctx->next_reg_ver <= ctx->upgrade->latest_ver); 187 188 if (!status) { 189 if (ctx->reg->type != FTL_LAYOUT_REGION_TYPE_SB) { 190 /* Superblock region is always default-created in the latest version - see ftl_layout_setup_superblock() */ 191 rc = ftl_superblock_md_layout_upgrade_region(dev, ctx->reg, ctx->next_reg_ver); 192 if (entry_size && num_entries) { 193 dev->layout.region[ctx->reg->type].entry_size = entry_size; 194 dev->layout.region[ctx->reg->type].num_entries = num_entries; 195 } 196 197 ftl_bug(rc != 0); 198 } 199 200 ctx->reg->current.version = ctx->next_reg_ver; 201 } 202 203 if (ctx->cb) { 204 ctx->cb(dev, ctx->cb_ctx, status); 205 } 206 } 207 208 int 209 ftl_layout_verify(struct spdk_ftl_dev *dev) 210 { 211 struct ftl_layout *layout = &dev->layout; 212 struct ftl_layout_upgrade_ctx ctx = {0}; 213 enum ftl_layout_region_type reg_type; 214 215 /** 216 * 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. 217 * The regions couldn't have be added in the SB upgrade path, as the FTL layout wasn't initialized at that point. 218 * Now that the FTL layout is initialized, add the missing regions and store the MD layout blob again. 219 */ 220 221 if (ftl_validate_regions(dev, layout)) { 222 return -1; 223 } 224 225 for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) { 226 ctx.reg = ftl_layout_region_get(dev, reg_type); 227 ctx.upgrade = &layout_upgrade_desc[reg_type]; 228 if (!ctx.reg) { 229 continue; 230 } 231 232 if (region_verify(dev, &ctx)) { 233 return -1; 234 } 235 } 236 237 return 0; 238 } 239 240 int 241 ftl_upgrade_layout_dump(struct spdk_ftl_dev *dev) 242 { 243 if (ftl_validate_regions(dev, &dev->layout)) { 244 return -1; 245 } 246 247 ftl_layout_dump(dev); 248 ftl_superblock_md_layout_dump(dev); 249 return 0; 250 } 251 252 int 253 ftl_superblock_upgrade(struct spdk_ftl_dev *dev) 254 { 255 struct ftl_layout_upgrade_ctx ctx = {0}; 256 struct ftl_layout_region *reg = ftl_layout_region_get(dev, FTL_LAYOUT_REGION_TYPE_SB); 257 int rc; 258 259 ctx.reg = reg; 260 ctx.upgrade = &layout_upgrade_desc[FTL_LAYOUT_REGION_TYPE_SB]; 261 reg->current.version = dev->sb->header.version; 262 263 rc = region_verify(dev, &ctx); 264 if (rc) { 265 return rc; 266 } 267 268 while (reg->current.version < ctx.upgrade->latest_ver) { 269 rc = ftl_region_upgrade(dev, &ctx); 270 if (rc) { 271 return rc; 272 } 273 /* SB upgrades are all synchronous */ 274 ftl_region_upgrade_completed(dev, &ctx, 0, 0, rc); 275 } 276 277 /* The mirror shares the same DMA buf, so it is automatically updated upon SB store */ 278 dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB_BASE].current.version = reg->current.version; 279 return 0; 280 } 281 282 static int 283 layout_upgrade_select_next_region(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 284 { 285 struct ftl_layout_region *reg; 286 uint64_t reg_ver, reg_latest_ver; 287 uint32_t reg_type = ctx->reg->type; 288 289 while (reg_type != FTL_LAYOUT_REGION_TYPE_MAX) { 290 assert(ctx->reg); 291 assert(ctx->upgrade); 292 reg = ctx->reg; 293 reg_latest_ver = ctx->upgrade->latest_ver; 294 reg_ver = reg->current.version; 295 296 if (reg_ver == reg_latest_ver || reg->type == FTL_LAYOUT_REGION_TYPE_INVALID) { 297 /* select the next region to upgrade */ 298 reg_type++; 299 if (reg_type == FTL_LAYOUT_REGION_TYPE_MAX) { 300 break; 301 } 302 ctx->reg++; 303 ctx->upgrade++; 304 } else if (reg_ver < reg_latest_ver) { 305 /* qualify region version to upgrade */ 306 return FTL_LAYOUT_UPGRADE_CONTINUE; 307 } else { 308 /* unknown version */ 309 assert(reg_ver <= reg_latest_ver); 310 FTL_ERRLOG(dev, "Region %d upgrade fault: version %"PRIu64"/%"PRIu64"\n", reg_type, reg_ver, 311 reg_latest_ver); 312 return FTL_LAYOUT_UPGRADE_FAULT; 313 } 314 } 315 316 return FTL_LAYOUT_UPGRADE_DONE; 317 } 318 319 int 320 ftl_layout_upgrade_init_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 321 { 322 if (!ctx->reg) { 323 ctx->reg = ftl_layout_region_get(dev, 0); 324 ctx->upgrade = &layout_upgrade_desc[0]; 325 SPDK_STATIC_ASSERT(FTL_LAYOUT_REGION_TYPE_SB == 0, "Invalid SB region type"); 326 } 327 328 return layout_upgrade_select_next_region(dev, ctx); 329 } 330 331 uint64_t 332 ftl_layout_upgrade_region_get_latest_version(enum ftl_layout_region_type reg_type) 333 { 334 assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX); 335 return layout_upgrade_desc[reg_type].latest_ver; 336 } 337 338 int 339 ftl_layout_upgrade_drop_region(struct spdk_ftl_dev *dev, 340 struct ftl_layout_tracker_bdev *layout_tracker, 341 enum ftl_layout_region_type reg_type, uint32_t reg_ver) 342 { 343 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 344 int rc = ftl_layout_tracker_bdev_rm_region(layout_tracker, reg_type, reg_ver); 345 346 ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 347 if (reg_search_ctx) { 348 FTL_ERRLOG(dev, 349 "Error when dropping region type %"PRId32", ver %"PRIu32": rc:%"PRId32" but found reg ver %"PRIu32"\n", 350 reg_type, reg_ver, rc, reg_search_ctx->ver); 351 return -1; 352 } 353 dev->layout.region[reg_type].type = FTL_LAYOUT_REGION_TYPE_INVALID; 354 return 0; 355 } 356