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_sb.h" 8 #include "ftl_core.h" 9 #include "ftl_layout.h" 10 #include "upgrade/ftl_sb_upgrade.h" 11 #include "upgrade/ftl_sb_v3.h" 12 #include "upgrade/ftl_sb_v5.h" 13 14 static bool ftl_superblock_v2_check_magic(union ftl_superblock_ver *sb_ver); 15 16 struct sb_ops { 17 bool (*check_magic)(union ftl_superblock_ver *sb_ver); 18 19 bool (*blob_is_empty)(union ftl_superblock_ver *sb_ver); 20 bool (*blob_validate)(struct spdk_ftl_dev *dev); 21 int (*blob_store)(struct spdk_ftl_dev *dev); 22 int (*blob_load)(struct spdk_ftl_dev *dev); 23 24 int (*upgrade_region)(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg, 25 uint32_t new_version); 26 27 int (*layout_apply)(struct spdk_ftl_dev *dev); 28 void (*layout_dump)(struct spdk_ftl_dev *dev); 29 }; 30 31 static struct sb_ops * 32 sb_get_ops(uint64_t version) 33 { 34 static struct sb_ops ops[] = { 35 [FTL_SB_VERSION_0] = { 36 .check_magic = ftl_superblock_v2_check_magic, 37 }, 38 [FTL_SB_VERSION_1] = { 39 .check_magic = ftl_superblock_v2_check_magic, 40 }, 41 [FTL_SB_VERSION_2] = { 42 .check_magic = ftl_superblock_v2_check_magic, 43 }, 44 [FTL_SB_VERSION_3] = { 45 .check_magic = ftl_superblock_v3_check_magic, 46 .blob_is_empty = ftl_superblock_v3_md_layout_is_empty, 47 .blob_load = ftl_superblock_v3_md_layout_load_all, 48 .layout_dump = ftl_superblock_v3_md_layout_dump, 49 }, 50 [FTL_SB_VERSION_4] = { 51 .check_magic = ftl_superblock_v3_check_magic, 52 .blob_is_empty = ftl_superblock_v3_md_layout_is_empty, 53 .blob_load = ftl_superblock_v3_md_layout_load_all, 54 .layout_dump = ftl_superblock_v3_md_layout_dump, 55 }, 56 [FTL_SB_VERSION_5] = { 57 .check_magic = ftl_superblock_v3_check_magic, 58 .blob_is_empty = ftl_superblock_v5_is_blob_area_empty, 59 .blob_validate = ftl_superblock_v5_validate_blob_area, 60 .blob_store = ftl_superblock_v5_store_blob_area, 61 .blob_load = ftl_superblock_v5_load_blob_area, 62 .upgrade_region = ftl_superblock_v5_md_layout_upgrade_region, 63 .layout_apply = ftl_superblock_v5_md_layout_apply, 64 .layout_dump = ftl_superblock_v5_md_layout_dump, 65 }, 66 }; 67 68 if (version >= SPDK_COUNTOF(ops)) { 69 return NULL; 70 } 71 72 return &ops[version]; 73 } 74 75 static bool 76 ftl_superblock_v2_check_magic(union ftl_superblock_ver *sb_ver) 77 { 78 return sb_ver->header.magic == FTL_SUPERBLOCK_MAGIC_V2; 79 } 80 81 bool 82 ftl_superblock_check_magic(struct ftl_superblock *sb) 83 { 84 union ftl_superblock_ver *sb_ver = (union ftl_superblock_ver *)sb; 85 struct sb_ops *ops = sb_get_ops(sb_ver->header.version); 86 87 if (!ops || !ops->check_magic) { 88 ftl_abort(); 89 return false; 90 } 91 return ops->check_magic(sb_ver); 92 } 93 94 bool 95 ftl_superblock_is_blob_area_empty(struct ftl_superblock *sb) 96 { 97 union ftl_superblock_ver *sb_ver = (union ftl_superblock_ver *)sb; 98 struct sb_ops *ops = sb_get_ops(sb_ver->header.version); 99 100 if (!ops || !ops->blob_is_empty) { 101 ftl_abort(); 102 return false; 103 } 104 return ops->blob_is_empty(sb_ver); 105 } 106 107 bool 108 ftl_superblock_validate_blob_area(struct spdk_ftl_dev *dev) 109 { 110 struct sb_ops *ops = sb_get_ops(dev->sb->header.version); 111 112 if (!ops || !ops->blob_validate) { 113 return true; 114 } 115 return ops->blob_validate(dev); 116 } 117 118 int 119 ftl_superblock_store_blob_area(struct spdk_ftl_dev *dev) 120 { 121 struct sb_ops *ops = sb_get_ops(dev->sb->header.version); 122 123 if (!ops || !ops->blob_store) { 124 ftl_abort(); 125 return -1; 126 } 127 return ops->blob_store(dev); 128 } 129 130 int 131 ftl_superblock_load_blob_area(struct spdk_ftl_dev *dev) 132 { 133 struct sb_ops *ops = sb_get_ops(dev->sb->header.version); 134 135 if (!ops || !ops->blob_load) { 136 ftl_abort(); 137 return -1; 138 } 139 return ops->blob_load(dev); 140 } 141 142 int 143 ftl_superblock_md_layout_upgrade_region(struct spdk_ftl_dev *dev, 144 struct ftl_layout_region *reg, uint32_t new_version) 145 { 146 struct sb_ops *ops = sb_get_ops(dev->sb->header.version); 147 148 if (!ops || !ops->upgrade_region) { 149 ftl_abort(); 150 return -1; 151 } 152 return ops->upgrade_region(dev, reg, new_version); 153 } 154 155 int 156 ftl_superblock_md_layout_apply(struct spdk_ftl_dev *dev) 157 { 158 struct sb_ops *ops = sb_get_ops(dev->sb->header.version); 159 160 if (!ops || !ops->layout_apply) { 161 return 0; 162 } 163 return ops->layout_apply(dev); 164 } 165 166 void 167 ftl_superblock_md_layout_dump(struct spdk_ftl_dev *dev) 168 { 169 struct sb_ops *ops = sb_get_ops(dev->sb->header.version); 170 171 if (!ops || !ops->layout_dump) { 172 ftl_abort(); 173 return; 174 } 175 return ops->layout_dump(dev); 176 } 177