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 .count = FTL_SB_VERSION_CURRENT, 39 .desc = sb_upgrade_desc, 40 }, 41 [FTL_LAYOUT_REGION_TYPE_SB_BASE] = { 42 .count = FTL_SB_VERSION_CURRENT, 43 .desc = sb_upgrade_desc, 44 }, 45 [FTL_LAYOUT_REGION_TYPE_L2P] = {}, 46 [FTL_LAYOUT_REGION_TYPE_BAND_MD] = { 47 .count = FTL_BAND_VERSION_CURRENT, 48 .desc = band_upgrade_desc, 49 }, 50 [FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = { 51 .count = FTL_BAND_VERSION_CURRENT, 52 .desc = band_upgrade_desc, 53 }, 54 [FTL_LAYOUT_REGION_TYPE_VALID_MAP] = {}, 55 [FTL_LAYOUT_REGION_TYPE_NVC_MD] = { 56 .count = FTL_NVC_VERSION_CURRENT, 57 .desc = nvc_upgrade_desc, 58 }, 59 [FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = { 60 .count = FTL_NVC_VERSION_CURRENT, 61 .desc = nvc_upgrade_desc, 62 }, 63 [FTL_LAYOUT_REGION_TYPE_DATA_NVC] = {}, 64 [FTL_LAYOUT_REGION_TYPE_DATA_BASE] = {}, 65 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = { 66 .count = FTL_P2L_VERSION_CURRENT, 67 .desc = p2l_upgrade_desc, 68 }, 69 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = { 70 .count = FTL_P2L_VERSION_CURRENT, 71 .desc = p2l_upgrade_desc, 72 }, 73 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = { 74 .count = FTL_P2L_VERSION_CURRENT, 75 .desc = p2l_upgrade_desc, 76 }, 77 [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = { 78 .count = FTL_P2L_VERSION_CURRENT, 79 .desc = p2l_upgrade_desc, 80 }, 81 [FTL_LAYOUT_REGION_TYPE_TRIM_MD] = {}, 82 [FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = {}, 83 }; 84 85 SPDK_STATIC_ASSERT(sizeof(layout_upgrade_desc) / sizeof(*layout_upgrade_desc) == 86 FTL_LAYOUT_REGION_TYPE_MAX, 87 "Missing layout upgrade descriptors"); 88 #endif 89 90 static int 91 region_verify(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 92 { 93 uint64_t ver; 94 95 assert(ctx->reg); 96 assert(ctx->reg->current.version == ctx->upgrade->count); 97 ver = ctx->reg->prev.version; 98 if (ver > ctx->upgrade->count) { 99 FTL_ERRLOG(dev, "Unknown region version\n"); 100 return -1; 101 } 102 103 while (ver < ctx->reg->current.version) { 104 int rc = ctx->upgrade->desc[ver].verify(dev, ctx->reg); 105 if (rc) { 106 return rc; 107 } 108 ver = ctx->upgrade->desc[ver].new_version; 109 } 110 return 0; 111 } 112 113 int 114 ftl_region_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 115 { 116 int rc = 0; 117 uint64_t ver; 118 119 assert(ctx->reg); 120 assert(ctx->reg->prev.version <= ctx->reg->current.version); 121 assert(ctx->reg->current.version == ctx->upgrade->count); 122 ver = ctx->reg->prev.version; 123 if (ver < ctx->upgrade->count) { 124 ctx->next_reg_ver = ctx->upgrade->desc[ver].new_version; 125 rc = ctx->upgrade->desc[ver].upgrade(dev, ctx); 126 } 127 return rc; 128 } 129 130 void 131 ftl_region_upgrade_completed(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx, 132 int status) 133 { 134 assert(ctx->reg); 135 assert(ctx->reg->prev.version < ctx->next_reg_ver); 136 assert(ctx->next_reg_ver <= ctx->reg->current.version); 137 138 /* SB MD isn't tracked in SB MD region list */ 139 if (!status) { 140 if (ctx->reg->prev.sb_md_reg) { 141 int rc = ftl_superblock_md_layout_upgrade_region(dev, ctx->reg->prev.sb_md_reg, ctx->next_reg_ver); 142 ftl_bug(rc != 0); 143 } 144 145 ctx->reg->prev.version = ctx->next_reg_ver; 146 } 147 148 if (ctx->cb) { 149 ctx->cb(dev, ctx->cb_ctx, status); 150 } 151 } 152 153 int 154 ftl_layout_verify(struct spdk_ftl_dev *dev) 155 { 156 int rc = 0; 157 struct ftl_layout *layout = &dev->layout; 158 struct ftl_layout_upgrade_ctx ctx = {0}; 159 160 if (ftl_superblock_md_layout_is_empty(dev->sb)) { 161 rc = ftl_superblock_md_layout_build(dev); 162 goto exit; 163 } 164 165 if (ftl_superblock_md_layout_load_all(dev)) { 166 return -1; 167 } 168 169 if (ftl_validate_regions(dev, layout)) { 170 return -1; 171 } 172 173 ctx.reg = &dev->layout.region[0]; 174 ctx.upgrade = &layout_upgrade_desc[0]; 175 176 while (true) { 177 if (region_verify(dev, &ctx)) { 178 return -1; 179 } 180 181 if (ctx.reg->type == FTL_LAYOUT_REGION_TYPE_MAX - 1) { 182 break; 183 } 184 185 ctx.reg++; 186 ctx.upgrade++; 187 } 188 189 exit: 190 return rc; 191 } 192 193 int 194 ftl_upgrade_layout_dump(struct spdk_ftl_dev *dev) 195 { 196 if (ftl_validate_regions(dev, &dev->layout)) { 197 return -1; 198 } 199 200 ftl_layout_dump(dev); 201 ftl_superblock_md_layout_dump(dev); 202 return 0; 203 } 204 205 int 206 ftl_superblock_upgrade(struct spdk_ftl_dev *dev) 207 { 208 struct ftl_layout_upgrade_ctx ctx = {0}; 209 struct ftl_layout_region *reg = &dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB]; 210 int rc; 211 212 ctx.reg = reg; 213 ctx.upgrade = &layout_upgrade_desc[FTL_LAYOUT_REGION_TYPE_SB]; 214 reg->prev.version = dev->sb->header.version; 215 216 rc = region_verify(dev, &ctx); 217 if (rc) { 218 return rc; 219 } 220 221 while (reg->prev.version < reg->current.version) { 222 rc = ftl_region_upgrade(dev, &ctx); 223 if (rc) { 224 return rc; 225 } 226 /* SB upgrades are all synchronous */ 227 ftl_region_upgrade_completed(dev, &ctx, rc); 228 } 229 230 dev->layout.region[FTL_LAYOUT_REGION_TYPE_SB_BASE].prev.version = reg->prev.version; 231 return 0; 232 } 233 234 static int 235 layout_upgrade_select_next_region(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 236 { 237 struct ftl_layout_region *reg; 238 uint64_t reg_ver; 239 uint32_t reg_type = ctx->reg->type; 240 241 while (reg_type != FTL_LAYOUT_REGION_TYPE_MAX) { 242 assert(ctx->reg); 243 assert(ctx->upgrade); 244 reg = ctx->reg; 245 reg_ver = reg->prev.version; 246 247 if (reg_ver < reg->current.version) { 248 /* qualify region version to upgrade */ 249 return FTL_LAYOUT_UPGRADE_CONTINUE; 250 } else if (reg_ver == reg->current.version) { 251 /* select the next region to upgrade */ 252 reg_type++; 253 if (reg_type == FTL_LAYOUT_REGION_TYPE_MAX) { 254 break; 255 } 256 ctx->reg++; 257 ctx->upgrade++; 258 } else { 259 /* unknown version */ 260 assert(reg_ver > reg->current.version); 261 FTL_ERRLOG(dev, "Region %d upgrade fault: version %"PRIu64"/%"PRIu64"\n", reg_type, reg_ver, 262 reg->current.version); 263 return FTL_LAYOUT_UPGRADE_FAULT; 264 } 265 } 266 267 return FTL_LAYOUT_UPGRADE_DONE; 268 } 269 270 int 271 ftl_layout_upgrade_init_ctx(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 272 { 273 if (!ctx->reg) { 274 ctx->reg = &dev->layout.region[0]; 275 ctx->upgrade = &layout_upgrade_desc[0]; 276 } 277 278 return layout_upgrade_select_next_region(dev, ctx); 279 } 280