1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/thread.h" 7 #include "spdk/crc32.h" 8 9 #include "ftl_core.h" 10 #include "ftl_mngt.h" 11 #include "ftl_mngt_steps.h" 12 #include "ftl_utils.h" 13 #include "ftl_internal.h" 14 #include "ftl_sb.h" 15 16 void 17 ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 18 { 19 if (ftl_layout_setup(dev)) { 20 ftl_mngt_fail_step(mngt); 21 } else { 22 ftl_mngt_next_step(mngt); 23 } 24 } 25 26 static bool 27 is_buffer_needed(enum ftl_layout_region_type type) 28 { 29 switch (type) { 30 #ifdef SPDK_FTL_VSS_EMU 31 case FTL_LAYOUT_REGION_TYPE_VSS: 32 #endif 33 34 case FTL_LAYOUT_REGION_TYPE_SB: 35 case FTL_LAYOUT_REGION_TYPE_SB_BASE: 36 case FTL_LAYOUT_REGION_TYPE_DATA_NVC: 37 case FTL_LAYOUT_REGION_TYPE_DATA_BASE: 38 case FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR: 39 return false; 40 41 default: 42 return true; 43 } 44 } 45 46 void 47 ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 48 { 49 struct ftl_layout *layout = &dev->layout; 50 struct ftl_layout_region *region = layout->region; 51 uint64_t i; 52 53 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) { 54 if (layout->md[i]) { 55 /* 56 * Some metadata objects are initialized by other FTL 57 * components. At the moment it's only used by superblock (and its mirror) - 58 * during load time we need to read it earlier in order to get the layout for the 59 * other regions. 60 */ 61 continue; 62 } 63 layout->md[i] = ftl_md_create(dev, region->current.blocks, region->vss_blksz, region->name, 64 !is_buffer_needed(i), region); 65 if (NULL == layout->md[i]) { 66 ftl_mngt_fail_step(mngt); 67 return; 68 } 69 } 70 71 ftl_mngt_next_step(mngt); 72 } 73 74 void 75 ftl_mngt_deinit_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 76 { 77 struct ftl_layout *layout = &dev->layout; 78 struct ftl_layout_region *region = layout->region; 79 uint64_t i; 80 81 for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) { 82 if (layout->md[i]) { 83 ftl_md_destroy(layout->md[i]); 84 layout->md[i] = NULL; 85 } 86 } 87 88 ftl_mngt_next_step(mngt); 89 } 90 91 static void 92 persist_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status) 93 { 94 struct ftl_mngt_process *mngt = md->owner.cb_ctx; 95 96 if (status) { 97 ftl_mngt_fail_step(mngt); 98 } else { 99 ftl_mngt_next_step(mngt); 100 } 101 } 102 103 static void 104 persist(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt, 105 enum ftl_layout_region_type type) 106 { 107 struct ftl_layout *layout = &dev->layout; 108 struct ftl_md *md; 109 110 assert(type < FTL_LAYOUT_REGION_TYPE_MAX); 111 112 md = layout->md[type]; 113 if (!md) { 114 ftl_mngt_fail_step(mngt); 115 return; 116 } 117 118 md->owner.cb_ctx = mngt; 119 md->cb = persist_cb; 120 ftl_md_persist(md); 121 } 122 123 static uint32_t 124 get_sb_crc(struct ftl_superblock *sb) 125 { 126 uint32_t crc = 0; 127 128 /* Calculate CRC excluding CRC field in superblock */ 129 void *buffer = sb; 130 size_t offset = offsetof(struct ftl_superblock, header.crc); 131 size_t size = offset; 132 crc = spdk_crc32c_update(buffer, size, crc); 133 134 buffer += offset + sizeof(sb->header.crc); 135 size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc); 136 crc = spdk_crc32c_update(buffer, size, crc); 137 138 return crc; 139 } 140 141 void 142 ftl_mngt_init_default_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 143 { 144 struct ftl_superblock *sb = dev->sb; 145 146 sb->header.magic = FTL_SUPERBLOCK_MAGIC; 147 sb->header.version = FTL_METADATA_VERSION_CURRENT; 148 sb->uuid = dev->conf.uuid; 149 sb->clean = 0; 150 151 /* Max 16 IO depth per band relocate */ 152 sb->max_reloc_qdepth = 16; 153 154 sb->overprovisioning = dev->conf.overprovisioning; 155 156 /* md layout isn't initialized yet. 157 * empty region list => all regions in the default location */ 158 sb->md_layout_head.type = FTL_LAYOUT_REGION_TYPE_INVALID; 159 160 sb->header.crc = get_sb_crc(sb); 161 162 ftl_mngt_next_step(mngt); 163 } 164 165 void 166 ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 167 { 168 struct ftl_superblock *sb = dev->sb; 169 170 sb->clean = 0; 171 sb->header.crc = get_sb_crc(sb); 172 persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB); 173 } 174 175 /* 176 * Initializes the superblock fields during first startup of FTL 177 */ 178 static const struct ftl_mngt_process_desc desc_init_sb = { 179 .name = "SB initialize", 180 .steps = { 181 { 182 .name = "Default-initialize superblock", 183 .action = ftl_mngt_init_default_sb, 184 }, 185 {} 186 } 187 }; 188 189 #ifdef SPDK_FTL_VSS_EMU 190 void 191 ftl_mngt_md_init_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 192 { 193 struct ftl_layout *layout = &dev->layout; 194 struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS]; 195 196 /* Initialize VSS layout */ 197 ftl_layout_setup_vss_emu(dev); 198 199 /* Allocate md buf */ 200 layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = ftl_md_create(dev, region->current.blocks, 201 region->vss_blksz, NULL, 0, region); 202 if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) { 203 ftl_mngt_fail_step(mngt); 204 return; 205 } 206 ftl_mngt_next_step(mngt); 207 } 208 209 void 210 ftl_mngt_md_deinit_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 211 { 212 struct ftl_layout *layout = &dev->layout; 213 214 if (layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) { 215 ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_VSS]); 216 layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = NULL; 217 } 218 219 ftl_mngt_next_step(mngt); 220 } 221 #endif 222 223 void 224 ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 225 { 226 struct ftl_layout *layout = &dev->layout; 227 struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB]; 228 char uuid[SPDK_UUID_STRING_LEN]; 229 230 /* Must generate UUID before MD create on SHM for the SB */ 231 if (dev->conf.mode & SPDK_FTL_MODE_CREATE) { 232 spdk_uuid_generate(&dev->conf.uuid); 233 spdk_uuid_fmt_lower(uuid, sizeof(uuid), &dev->conf.uuid); 234 FTL_NOTICELOG(dev, "Create new FTL, UUID %s\n", uuid); 235 } 236 237 /* Setup the layout of a superblock */ 238 if (ftl_layout_setup_superblock(dev)) { 239 ftl_mngt_fail_step(mngt); 240 return; 241 } 242 243 /* Allocate md buf */ 244 layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks, 245 region->vss_blksz, region->name, false, region); 246 if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) { 247 ftl_mngt_fail_step(mngt); 248 return; 249 } 250 251 /* Link the md buf to the device */ 252 dev->sb = ftl_md_get_buffer(layout->md[FTL_LAYOUT_REGION_TYPE_SB]); 253 254 /* Setup superblock mirror to QLC */ 255 region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE]; 256 layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks, 257 region->vss_blksz, NULL, false, region); 258 if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) { 259 ftl_mngt_fail_step(mngt); 260 return; 261 } 262 263 /* Initialize the superblock */ 264 if (dev->conf.mode & SPDK_FTL_MODE_CREATE) { 265 ftl_mngt_call_process(mngt, &desc_init_sb); 266 } else { 267 ftl_mngt_fail_step(mngt); 268 } 269 } 270 271 void 272 ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt) 273 { 274 struct ftl_layout *layout = &dev->layout; 275 276 if (layout->md[FTL_LAYOUT_REGION_TYPE_SB]) { 277 ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB]); 278 layout->md[FTL_LAYOUT_REGION_TYPE_SB] = NULL; 279 } 280 281 if (layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) { 282 ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]); 283 layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = NULL; 284 } 285 286 ftl_mngt_next_step(mngt); 287 } 288