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