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