1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2022 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "ftl_sb_upgrade.h" 7 #include "ftl_layout_upgrade.h" 8 #include "ftl_layout.h" 9 #include "ftl_core.h" 10 #include "ftl_sb_v3.h" 11 #include "utils/ftl_df.h" 12 #include "utils/ftl_layout_tracker_bdev.h" 13 14 static int 15 sb_v4_to_v5_verify(struct spdk_ftl_dev *dev, struct ftl_layout_region *region) 16 { 17 struct ftl_layout_region *reg; 18 uint32_t reg_no; 19 int rc = ftl_region_upgrade_enabled(dev, region); 20 21 if (rc) { 22 return rc; 23 } 24 25 /* Verify there are no pending major upgrades */ 26 for (reg_no = 0; reg_no < FTL_LAYOUT_REGION_TYPE_MAX; reg_no++) { 27 reg = ftl_layout_region_get(dev, reg_no); 28 if (!reg) { 29 /* This region does not exist */ 30 continue; 31 } 32 33 if (reg->current.version <= ftl_layout_upgrade_region_get_latest_version(reg->type)) { 34 /* Only latest region version found */ 35 continue; 36 } 37 38 /* Previous version found, major upgrade */ 39 FTL_WARNLOG(dev, "FTL superblock upgrade v4 to v5 disabled: " \ 40 "cannot upgrade region type 0x%"PRIx32" v%"PRId64" to v%"PRId64", " \ 41 "offs 0x%"PRIx64", blks 0x%"PRIx64"\n", 42 reg->type, reg->current.version, ftl_layout_upgrade_region_get_latest_version(reg->type), 43 reg->current.offset, reg->current.blocks); 44 return -1; 45 } 46 47 return 0; 48 } 49 50 static bool 51 sb_v3_md_region_is_fixed(int reg_type) 52 { 53 switch (reg_type) { 54 case FTL_LAYOUT_REGION_TYPE_SB: 55 case FTL_LAYOUT_REGION_TYPE_SB_BASE: 56 case FTL_LAYOUT_REGION_TYPE_DATA_BASE: 57 return true; 58 59 default: 60 return false; 61 } 62 } 63 64 static bool 65 sb_v3_md_region_is_nvc(int reg_type) 66 { 67 switch (reg_type) { 68 case FTL_LAYOUT_REGION_TYPE_SB_BASE: 69 case FTL_LAYOUT_REGION_TYPE_VALID_MAP: 70 case FTL_LAYOUT_REGION_TYPE_DATA_BASE: 71 return false; 72 73 default: 74 return true; 75 } 76 } 77 78 static int 79 sb_v3_md_layout_convert(struct spdk_ftl_dev *dev) 80 { 81 struct ftl_superblock_v3 *sb = (struct ftl_superblock_v3 *)dev->sb; 82 struct ftl_superblock_v3_md_region *sb_reg = &sb->md_layout_head; 83 const struct ftl_layout_tracker_bdev_region_props *reg_props; 84 85 while (sb_reg->type != FTL_LAYOUT_REGION_TYPE_INVALID) { 86 if (sb_reg->type == FTL_LAYOUT_REGION_TYPE_FREE_NVC || 87 sb_reg->type == FTL_LAYOUT_REGION_TYPE_FREE_BASE) { 88 goto next_sb_reg; 89 } 90 91 if (sb_reg->type >= FTL_LAYOUT_REGION_TYPE_MAX) { 92 FTL_ERRLOG(dev, "Invalid MD region type found\n"); 93 return -1; 94 } 95 96 if (sb_v3_md_region_is_fixed(sb_reg->type)) { 97 FTL_ERRLOG(dev, "Unsupported MD region type found\n"); 98 return -1; 99 } 100 101 if (sb_v3_md_region_is_nvc(sb_reg->type)) { 102 reg_props = ftl_layout_tracker_bdev_insert_region(dev->nvc_layout_tracker, sb_reg->type, 103 sb_reg->version, sb_reg->blk_offs, sb_reg->blk_sz); 104 } else { 105 reg_props = ftl_layout_tracker_bdev_insert_region(dev->base_layout_tracker, sb_reg->type, 106 sb_reg->version, sb_reg->blk_offs, sb_reg->blk_sz); 107 } 108 if (!reg_props) { 109 FTL_ERRLOG(dev, "Cannot upgrade SB MD layout - region type 0x%"PRIx32" v%"PRId32" " \ 110 "offs 0x%"PRIx64" blks 0x%"PRIx64"\n", 111 sb_reg->type, sb_reg->version, sb_reg->blk_offs, sb_reg->blk_sz); 112 } 113 114 next_sb_reg: 115 if (sb_reg->df_next == FTL_DF_OBJ_ID_INVALID) { 116 break; 117 } 118 119 if (UINT64_MAX - (uintptr_t)sb <= sb_reg->df_next) { 120 FTL_ERRLOG(dev, "Buffer overflow\n"); 121 return -EOVERFLOW; 122 } 123 124 sb_reg = ftl_df_get_obj_ptr(sb, sb_reg->df_next); 125 if (ftl_superblock_v3_md_region_overflow(dev, sb_reg)) { 126 FTL_ERRLOG(dev, "Buffer overflow\n"); 127 return -EOVERFLOW; 128 } 129 } 130 131 return 0; 132 } 133 134 static int 135 sb_v4_to_v5_upgrade(struct spdk_ftl_dev *dev, struct ftl_layout_upgrade_ctx *ctx) 136 { 137 union ftl_superblock_ver *sb = (union ftl_superblock_ver *)dev->sb; 138 139 FTL_NOTICELOG(dev, "FTL superblock upgrade v4 to v5\n"); 140 141 /* Convert v3 MD layout */ 142 if (ftl_superblock_is_blob_area_empty(dev->sb)) { 143 FTL_ERRLOG(dev, "SBv3 MD layout empty\n"); 144 return -1; 145 } 146 if (sb_v3_md_layout_convert(dev)) { 147 FTL_ERRLOG(dev, "SBv3 MD layout load failed\n"); 148 return -1; 149 } 150 151 /* Bump up the version */ 152 sb->v5.header.version = FTL_SB_VERSION_5; 153 sb->v5.blob_area_end = 0; 154 155 /* Keep v5 layout empty */ 156 memset(sb->v5.nvc_dev_name, 0, sizeof(sb->v5.nvc_dev_name)); 157 memset(&sb->v5.md_layout_nvc, 0, sizeof(sb->v5.md_layout_nvc)); 158 memset(sb->v5.base_dev_name, 0, sizeof(sb->v5.base_dev_name)); 159 memset(&sb->v5.md_layout_base, 0, sizeof(sb->v5.md_layout_base)); 160 memset(&sb->v5.layout_params, 0, sizeof(sb->v5.layout_params)); 161 162 return 0; 163 } 164 165 struct ftl_region_upgrade_desc sb_upgrade_desc[] = { 166 [FTL_SB_VERSION_0] = {.verify = ftl_region_upgrade_disabled}, 167 [FTL_SB_VERSION_1] = {.verify = ftl_region_upgrade_disabled}, 168 [FTL_SB_VERSION_2] = {.verify = ftl_region_upgrade_disabled}, 169 [FTL_SB_VERSION_3] = {.verify = ftl_region_upgrade_disabled}, 170 [FTL_SB_VERSION_4] = {.verify = sb_v4_to_v5_verify, .upgrade = sb_v4_to_v5_upgrade, .new_version = FTL_SB_VERSION_5}, 171 }; 172 173 SPDK_STATIC_ASSERT(SPDK_COUNTOF(sb_upgrade_desc) == FTL_SB_VERSION_CURRENT, 174 "Missing SB region upgrade descriptors"); 175