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