Line data Source code
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 "spdk/thread.h"
8 : #include "spdk/crc32.h"
9 : #include "spdk/string.h"
10 :
11 : #include "ftl_core.h"
12 : #include "ftl_mngt.h"
13 : #include "ftl_mngt_steps.h"
14 : #include "ftl_utils.h"
15 : #include "ftl_band.h"
16 : #include "ftl_internal.h"
17 : #include "ftl_sb.h"
18 : #include "base/ftl_base_dev.h"
19 : #include "nvc/ftl_nvc_dev.h"
20 : #include "upgrade/ftl_layout_upgrade.h"
21 : #include "upgrade/ftl_sb_upgrade.h"
22 :
23 : void
24 0 : ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
25 : {
26 0 : if (ftl_layout_setup(dev)) {
27 0 : ftl_mngt_fail_step(mngt);
28 : } else {
29 0 : ftl_mngt_next_step(mngt);
30 : }
31 0 : }
32 :
33 : static bool
34 0 : is_buffer_needed(enum ftl_layout_region_type type)
35 : {
36 0 : switch (type) {
37 0 : case FTL_LAYOUT_REGION_TYPE_SB:
38 : case FTL_LAYOUT_REGION_TYPE_SB_BASE:
39 : case FTL_LAYOUT_REGION_TYPE_DATA_NVC:
40 : case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
41 : case FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR:
42 : case FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR:
43 : #ifndef SPDK_FTL_L2P_FLAT
44 : case FTL_LAYOUT_REGION_TYPE_L2P:
45 : #endif
46 : case FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR:
47 0 : return false;
48 :
49 0 : default:
50 0 : return true;
51 : }
52 : }
53 :
54 : void
55 0 : ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
56 : {
57 0 : struct ftl_layout *layout = &dev->layout;
58 : struct ftl_layout_region *region;
59 : struct ftl_md *md, *md_mirror;
60 : enum ftl_layout_region_type i;
61 : int md_flags;
62 :
63 0 : for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
64 0 : region = ftl_layout_region_get(dev, i);
65 0 : if (!region) {
66 0 : continue;
67 : }
68 0 : assert(i == region->type);
69 0 : if (layout->md[i]) {
70 : /*
71 : * Some metadata objects are initialized by other FTL
72 : * components. At the moment it's only used by superblock (and its mirror) -
73 : * during load time we need to read it earlier in order to get the layout for the
74 : * other regions.
75 : */
76 0 : continue;
77 : }
78 0 : md_flags = is_buffer_needed(i) ? ftl_md_create_region_flags(dev,
79 0 : region->type) : FTL_MD_CREATE_NO_MEM;
80 0 : layout->md[i] = ftl_md_create(dev, region->current.blocks, region->vss_blksz, region->name,
81 : md_flags, region);
82 0 : if (NULL == layout->md[i]) {
83 0 : ftl_mngt_fail_step(mngt);
84 0 : return;
85 : }
86 : }
87 :
88 : /* Initialize mirror regions */
89 0 : for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
90 0 : region = ftl_layout_region_get(dev, i);
91 0 : if (!region) {
92 0 : continue;
93 : }
94 0 : assert(i == region->type);
95 0 : if (region->mirror_type != FTL_LAYOUT_REGION_TYPE_INVALID &&
96 0 : !is_buffer_needed(region->mirror_type)) {
97 0 : md = layout->md[i];
98 0 : md_mirror = layout->md[region->mirror_type];
99 :
100 0 : md_mirror->dev = md->dev;
101 0 : md_mirror->data_blocks = md->data_blocks;
102 0 : md_mirror->data = md->data;
103 0 : if (md_mirror->region->vss_blksz == md->region->vss_blksz) {
104 0 : md_mirror->vss_data = md->vss_data;
105 : }
106 0 : md_mirror->region = ftl_layout_region_get(dev, region->mirror_type);
107 0 : ftl_bug(md_mirror->region == NULL);
108 0 : md_mirror->is_mirror = true;
109 : }
110 : }
111 :
112 0 : ftl_mngt_next_step(mngt);
113 : }
114 :
115 : void
116 0 : ftl_mngt_deinit_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
117 : {
118 0 : struct ftl_layout *layout = &dev->layout;
119 : struct ftl_layout_region *region;
120 : enum ftl_layout_region_type i;
121 :
122 0 : for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
123 0 : region = ftl_layout_region_get(dev, i);
124 0 : if (!region) {
125 0 : continue;
126 : }
127 0 : if (layout->md[i]) {
128 0 : ftl_md_destroy(layout->md[i], ftl_md_destroy_region_flags(dev, region->type));
129 0 : layout->md[i] = NULL;
130 : }
131 : }
132 :
133 0 : ftl_mngt_next_step(mngt);
134 0 : }
135 :
136 : static void
137 0 : persist_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
138 : {
139 0 : struct ftl_mngt_process *mngt = md->owner.cb_ctx;
140 :
141 0 : if (status) {
142 0 : ftl_mngt_fail_step(mngt);
143 : } else {
144 0 : ftl_mngt_next_step(mngt);
145 : }
146 0 : }
147 :
148 : static void
149 0 : persist(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
150 : enum ftl_layout_region_type type)
151 : {
152 0 : struct ftl_layout *layout = &dev->layout;
153 : struct ftl_md *md;
154 :
155 0 : assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
156 :
157 0 : md = layout->md[type];
158 0 : if (!md) {
159 0 : ftl_mngt_fail_step(mngt);
160 0 : return;
161 : }
162 :
163 0 : md->owner.cb_ctx = mngt;
164 0 : md->cb = persist_cb;
165 0 : ftl_md_persist(md);
166 : }
167 :
168 : static int
169 0 : ftl_md_restore_region(struct spdk_ftl_dev *dev, int region_type)
170 : {
171 0 : int status = 0;
172 0 : switch (region_type) {
173 0 : case FTL_LAYOUT_REGION_TYPE_NVC_MD:
174 0 : status = ftl_nv_cache_load_state(&dev->nv_cache);
175 0 : break;
176 0 : case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
177 0 : ftl_valid_map_load_state(dev);
178 0 : break;
179 0 : case FTL_LAYOUT_REGION_TYPE_BAND_MD:
180 0 : ftl_bands_load_state(dev);
181 0 : break;
182 0 : default:
183 0 : break;
184 : }
185 0 : return status;
186 : }
187 :
188 : static void
189 0 : restore_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
190 : {
191 0 : struct ftl_mngt_process *mngt = md->owner.cb_ctx;
192 0 : const struct ftl_layout_region *region = ftl_md_get_region(md);
193 :
194 0 : if (status) {
195 : /* Restore error, end step */
196 0 : ftl_mngt_fail_step(mngt);
197 0 : return;
198 : }
199 :
200 0 : assert(region);
201 0 : status = ftl_md_restore_region(dev, region->type);
202 :
203 0 : if (status) {
204 0 : ftl_mngt_fail_step(mngt);
205 : } else {
206 0 : ftl_mngt_next_step(mngt);
207 : }
208 : }
209 :
210 : static void
211 0 : restore(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt, enum ftl_layout_region_type type)
212 : {
213 0 : struct ftl_layout *layout = &dev->layout;
214 0 : assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
215 0 : struct ftl_md *md = layout->md[type];
216 :
217 0 : if (!md) {
218 0 : ftl_mngt_fail_step(mngt);
219 0 : return;
220 : }
221 :
222 0 : md->owner.cb_ctx = mngt;
223 0 : md->cb = restore_cb;
224 0 : ftl_md_restore(md);
225 : }
226 :
227 : void
228 0 : ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
229 : {
230 0 : if (ftl_nv_cache_save_state(&dev->nv_cache)) {
231 0 : ftl_mngt_fail_step(mngt);
232 0 : return;
233 : }
234 :
235 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
236 : }
237 :
238 : static void
239 0 : ftl_mngt_fast_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
240 : {
241 0 : if (ftl_nv_cache_save_state(&dev->nv_cache)) {
242 0 : ftl_mngt_fail_step(mngt);
243 0 : return;
244 : }
245 0 : ftl_mngt_next_step(mngt);
246 : }
247 :
248 : static void
249 0 : ftl_mngt_persist_vld_map_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
250 : {
251 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_VALID_MAP);
252 0 : }
253 :
254 : static void
255 0 : ftl_mngt_persist_p2l_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
256 : {
257 : /* Sync runtime P2L to persist any invalidation that may have happened */
258 :
259 0 : struct ftl_p2l_sync_ctx *ctx = ftl_mngt_get_step_ctx(mngt);
260 :
261 : /*
262 : * ftl_mngt_persist_bands_p2l will increment the md_region before the step_continue for next regions
263 : */
264 0 : if (ctx->md_region <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN) {
265 0 : ctx->md_region = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
266 : }
267 0 : ftl_mngt_persist_bands_p2l(mngt);
268 0 : }
269 :
270 : void
271 0 : ftl_mngt_persist_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
272 : {
273 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
274 0 : }
275 :
276 : static void
277 0 : ftl_mngt_persist_trim_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
278 : {
279 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_TRIM_MD);
280 0 : }
281 :
282 : static uint32_t
283 16 : get_sb_crc(struct ftl_superblock *sb)
284 : {
285 16 : uint32_t crc = 0;
286 :
287 : /* Calculate CRC excluding CRC field in superblock */
288 16 : void *buffer = sb;
289 16 : size_t offset = offsetof(struct ftl_superblock, header.crc);
290 16 : size_t size = offset;
291 16 : crc = spdk_crc32c_update(buffer, size, crc);
292 :
293 16 : buffer += offset + sizeof(sb->header.crc);
294 16 : if (sb->header.version > FTL_SB_VERSION_2) {
295 : /* whole buf for v3 and on: */
296 12 : size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc);
297 12 : crc = spdk_crc32c_update(buffer, size, crc);
298 : } else {
299 : /* special for sb v2 only: */
300 4 : size = sizeof(struct ftl_superblock_v2) - offset - sizeof(sb->header.crc);
301 4 : sb->header.crc = spdk_crc32c_update(buffer, size, crc);
302 : }
303 :
304 16 : return crc;
305 : }
306 :
307 : static void
308 0 : ftl_mngt_persist_super_block(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
309 : {
310 0 : dev->sb->overprovisioning = dev->conf.overprovisioning;
311 0 : dev->sb->gc_info = dev->sb_shm->gc_info;
312 0 : dev->sb->header.crc = get_sb_crc(dev->sb);
313 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
314 0 : }
315 :
316 : /*
317 : * Persists all necessary metadata (band state, P2L, etc) during FTL's clean shutdown.
318 : */
319 : static const struct ftl_mngt_process_desc desc_persist = {
320 : .name = "Persist metadata",
321 : .steps = {
322 : {
323 : .name = "Persist NV cache metadata",
324 : .action = ftl_mngt_persist_nv_cache_metadata,
325 : },
326 : {
327 : .name = "Persist valid map metadata",
328 : .action = ftl_mngt_persist_vld_map_metadata,
329 : },
330 : {
331 : .name = "Persist P2L metadata",
332 : .action = ftl_mngt_persist_p2l_metadata,
333 : .ctx_size = sizeof(struct ftl_p2l_sync_ctx),
334 : },
335 : {
336 : .name = "persist band info metadata",
337 : .action = ftl_mngt_persist_band_info_metadata,
338 : },
339 : {
340 : .name = "persist trim metadata",
341 : .action = ftl_mngt_persist_trim_metadata,
342 : },
343 : {
344 : .name = "Persist superblock",
345 : .action = ftl_mngt_persist_super_block,
346 : },
347 : {}
348 : }
349 : };
350 :
351 : void
352 0 : ftl_mngt_persist_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
353 : {
354 0 : ftl_mngt_call_process(mngt, &desc_persist);
355 0 : }
356 :
357 : /*
358 : * Fast clean shutdown path - skips the persistence of most metadata regions and
359 : * relies on their shared memory state instead.
360 : */
361 : static const struct ftl_mngt_process_desc desc_fast_persist = {
362 : .name = "Fast persist metadata",
363 : .steps = {
364 : {
365 : .name = "Fast persist NV cache metadata",
366 : .action = ftl_mngt_fast_persist_nv_cache_metadata,
367 : },
368 : {}
369 : }
370 : };
371 :
372 : void
373 0 : ftl_mngt_fast_persist_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
374 : {
375 0 : ftl_mngt_call_process(mngt, &desc_fast_persist);
376 0 : }
377 :
378 : void
379 5 : ftl_mngt_init_default_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
380 : {
381 5 : struct ftl_superblock *sb = dev->sb;
382 :
383 5 : sb->header.magic = FTL_SUPERBLOCK_MAGIC;
384 5 : sb->header.version = FTL_SB_VERSION_CURRENT;
385 5 : sb->uuid = dev->conf.uuid;
386 5 : sb->clean = 0;
387 5 : dev->sb_shm->shm_clean = false;
388 5 : sb->ckpt_seq_id = 0;
389 :
390 : /* Max 16 IO depth per band relocate */
391 5 : sb->max_reloc_qdepth = 16;
392 :
393 5 : sb->overprovisioning = dev->conf.overprovisioning;
394 :
395 5 : ftl_band_init_gc_iter(dev);
396 :
397 : /* md layout isn't initialized yet.
398 : * empty region list => all regions in the default location */
399 5 : spdk_strcpy_pad(sb->base_dev_name, dev->base_type->name,
400 : SPDK_COUNTOF(sb->base_dev_name), '\0');
401 5 : sb->md_layout_base.df_id = FTL_DF_OBJ_ID_INVALID;
402 :
403 5 : spdk_strcpy_pad(sb->nvc_dev_name, dev->nv_cache.nvc_desc->name,
404 : SPDK_COUNTOF(sb->nvc_dev_name), '\0');
405 5 : sb->md_layout_nvc.df_id = FTL_DF_OBJ_ID_INVALID;
406 :
407 5 : sb->header.crc = get_sb_crc(sb);
408 :
409 5 : ftl_mngt_next_step(mngt);
410 5 : }
411 :
412 : void
413 0 : ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
414 : {
415 0 : struct ftl_superblock *sb = dev->sb;
416 :
417 0 : sb->clean = 0;
418 0 : sb->upgrade_ready = false;
419 0 : dev->sb_shm->shm_clean = false;
420 0 : sb->header.crc = get_sb_crc(sb);
421 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
422 0 : }
423 :
424 : void
425 0 : ftl_mngt_set_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
426 : {
427 0 : struct ftl_superblock *sb = dev->sb;
428 :
429 0 : sb->clean = 1;
430 0 : sb->upgrade_ready = dev->conf.prep_upgrade_on_shutdown;
431 0 : dev->sb_shm->shm_clean = false;
432 0 : sb->header.crc = get_sb_crc(sb);
433 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
434 :
435 0 : dev->sb_shm->shm_ready = false;
436 0 : }
437 :
438 : void
439 0 : ftl_mngt_set_shm_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
440 : {
441 0 : struct ftl_superblock *sb = dev->sb;
442 :
443 0 : sb->clean = 1;
444 0 : dev->sb_shm->shm_clean = true;
445 0 : sb->header.crc = get_sb_crc(sb);
446 0 : ftl_mngt_next_step(mngt);
447 0 : }
448 :
449 : void
450 0 : ftl_mngt_load_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
451 : {
452 0 : FTL_NOTICELOG(dev, "SHM: clean %"PRIu64", shm_clean %d\n", dev->sb->clean, dev->sb_shm->shm_clean);
453 :
454 0 : if (!ftl_fast_startup(dev)) {
455 0 : restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
456 0 : return;
457 : }
458 :
459 0 : FTL_DEBUGLOG(dev, "SHM: found SB\n");
460 0 : if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_SB)) {
461 0 : ftl_mngt_fail_step(mngt);
462 0 : return;
463 : }
464 0 : ftl_mngt_next_step(mngt);
465 : }
466 :
467 : void
468 0 : ftl_mngt_validate_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
469 : {
470 0 : struct ftl_superblock *sb = dev->sb;
471 :
472 0 : if (!ftl_superblock_check_magic(sb)) {
473 0 : FTL_ERRLOG(dev, "Invalid FTL superblock magic\n");
474 0 : ftl_mngt_fail_step(mngt);
475 0 : return;
476 : }
477 :
478 0 : if (sb->header.crc != get_sb_crc(sb)) {
479 0 : FTL_ERRLOG(dev, "Invalid FTL superblock CRC\n");
480 0 : ftl_mngt_fail_step(mngt);
481 0 : return;
482 : }
483 :
484 0 : if (ftl_superblock_upgrade(dev)) {
485 0 : FTL_ERRLOG(dev, "FTL superblock dirty or invalid version\n");
486 0 : ftl_mngt_fail_step(mngt);
487 0 : return;
488 : }
489 :
490 0 : if (spdk_uuid_compare(&sb->uuid, &dev->conf.uuid) != 0) {
491 0 : FTL_ERRLOG(dev, "Invalid FTL superblock UUID\n");
492 0 : ftl_mngt_fail_step(mngt);
493 0 : return;
494 : }
495 :
496 0 : if (sb->lba_cnt == 0) {
497 0 : FTL_ERRLOG(dev, "Invalid FTL superblock lba_cnt\n");
498 0 : ftl_mngt_fail_step(mngt);
499 0 : return;
500 : }
501 0 : dev->num_lbas = sb->lba_cnt;
502 :
503 : /* The sb has just been read. Validate and update the conf */
504 0 : if (sb->overprovisioning == 0 || sb->overprovisioning >= 100) {
505 0 : FTL_ERRLOG(dev, "Invalid FTL superblock lba_rsvd\n");
506 0 : ftl_mngt_fail_step(mngt);
507 0 : return;
508 : }
509 0 : dev->conf.overprovisioning = sb->overprovisioning;
510 :
511 0 : if (!ftl_superblock_validate_blob_area(dev)) {
512 0 : FTL_ERRLOG(dev, "Corrupted FTL superblock blob area\n");
513 0 : ftl_mngt_fail_step(mngt);
514 0 : return;
515 : }
516 :
517 0 : ftl_mngt_next_step(mngt);
518 : }
519 :
520 : /*
521 : * Loads and verifies superblock contents - utilized during the load of an FTL
522 : * instance (both from a clean and dirty shutdown).
523 : */
524 : static const struct ftl_mngt_process_desc desc_restore_sb = {
525 : .name = "SB restore",
526 : .steps = {
527 : {
528 : .name = "Load super block",
529 : .action = ftl_mngt_load_sb
530 : },
531 : {
532 : .name = "Validate super block",
533 : .action = ftl_mngt_validate_sb
534 : },
535 : {}
536 : }
537 : };
538 :
539 : /*
540 : * Initializes the superblock fields during first startup of FTL
541 : */
542 : static const struct ftl_mngt_process_desc desc_init_sb = {
543 : .name = "SB initialize",
544 : .steps = {
545 : {
546 : .name = "Default-initialize superblock",
547 : .action = ftl_mngt_init_default_sb,
548 : },
549 : {}
550 : }
551 : };
552 :
553 : void
554 0 : ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
555 : {
556 : struct ftl_md *md;
557 : struct ftl_md *md_mirror;
558 0 : struct ftl_layout *layout = &dev->layout;
559 0 : struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
560 0 : char uuid[SPDK_UUID_STRING_LEN];
561 0 : int md_create_flags = ftl_md_create_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB);
562 :
563 : /* Must generate UUID before MD create on SHM for the SB */
564 0 : if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
565 0 : spdk_uuid_generate(&dev->conf.uuid);
566 0 : spdk_uuid_fmt_lower(uuid, sizeof(uuid), &dev->conf.uuid);
567 0 : FTL_NOTICELOG(dev, "Create new FTL, UUID %s\n", uuid);
568 : }
569 :
570 0 : shm_retry:
571 : /* Allocate md buf */
572 0 : dev->sb_shm = NULL;
573 0 : dev->sb_shm_md = ftl_md_create(dev, spdk_divide_round_up(sizeof(*dev->sb_shm), FTL_BLOCK_SIZE),
574 : 0, "sb_shm",
575 : md_create_flags, NULL);
576 0 : if (dev->sb_shm_md == NULL) {
577 : /* The first attempt may fail when trying to open SHM - try to create new */
578 0 : if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
579 0 : md_create_flags |= FTL_MD_CREATE_SHM_NEW;
580 0 : goto shm_retry;
581 : }
582 0 : if (dev->sb_shm_md == NULL) {
583 0 : ftl_mngt_fail_step(mngt);
584 0 : return;
585 : }
586 : }
587 :
588 0 : dev->sb_shm = ftl_md_get_buffer(dev->sb_shm_md);
589 :
590 : /* Setup the layout of a superblock */
591 0 : if (ftl_layout_setup_superblock(dev)) {
592 0 : ftl_mngt_fail_step(mngt);
593 0 : return;
594 : }
595 :
596 : /* Allocate md buf */
597 0 : layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks,
598 : region->vss_blksz, region->name,
599 : md_create_flags, region);
600 0 : if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
601 : /* The first attempt may fail when trying to open SHM - try to create new */
602 0 : if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
603 0 : md_create_flags |= FTL_MD_CREATE_SHM_NEW;
604 0 : ftl_md_destroy(dev->sb_shm_md, 0);
605 0 : dev->sb_shm_md = NULL;
606 0 : if (ftl_layout_clear_superblock(dev)) {
607 0 : ftl_mngt_fail_step(mngt);
608 0 : return;
609 : }
610 0 : goto shm_retry;
611 : }
612 0 : ftl_mngt_fail_step(mngt);
613 0 : return;
614 : }
615 :
616 : /* Link the md buf to the device */
617 0 : dev->sb = ftl_md_get_buffer(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
618 :
619 : /* Setup superblock mirror to QLC */
620 0 : region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
621 0 : layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks,
622 : region->vss_blksz, NULL, FTL_MD_CREATE_NO_MEM, region);
623 0 : if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
624 0 : ftl_mngt_fail_step(mngt);
625 0 : return;
626 : }
627 :
628 : /* Initialize mirror region buffer */
629 0 : md = layout->md[FTL_LAYOUT_REGION_TYPE_SB];
630 0 : md_mirror = layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE];
631 :
632 0 : md_mirror->dev = md->dev;
633 0 : md_mirror->data_blocks = md->data_blocks;
634 0 : md_mirror->data = md->data;
635 0 : md_mirror->is_mirror = true;
636 :
637 : /* Initialize the superblock */
638 0 : if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
639 0 : ftl_mngt_call_process(mngt, &desc_init_sb);
640 : } else {
641 0 : ftl_mngt_call_process(mngt, &desc_restore_sb);
642 : }
643 : }
644 :
645 : void
646 0 : ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
647 : {
648 0 : struct ftl_layout *layout = &dev->layout;
649 :
650 0 : if (layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
651 0 : ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB],
652 : ftl_md_destroy_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB));
653 0 : layout->md[FTL_LAYOUT_REGION_TYPE_SB] = NULL;
654 : }
655 :
656 0 : if (layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
657 0 : ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE], 0);
658 0 : layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = NULL;
659 : }
660 :
661 0 : ftl_md_destroy(dev->sb_shm_md, ftl_md_destroy_shm_flags(dev));
662 0 : dev->sb_shm_md = NULL;
663 0 : dev->sb_shm = NULL;
664 :
665 0 : ftl_mngt_next_step(mngt);
666 0 : }
667 :
668 : static void
669 0 : ftl_mngt_restore_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
670 : {
671 0 : if (ftl_fast_startup(dev)) {
672 0 : FTL_DEBUGLOG(dev, "SHM: found nv cache md\n");
673 0 : if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD)) {
674 0 : ftl_mngt_fail_step(mngt);
675 0 : return;
676 : }
677 0 : ftl_mngt_next_step(mngt);
678 0 : return;
679 : }
680 0 : restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
681 : }
682 :
683 : static void
684 0 : ftl_mngt_restore_vld_map_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
685 : {
686 0 : if (ftl_fast_startup(dev)) {
687 0 : FTL_DEBUGLOG(dev, "SHM: found vldmap\n");
688 0 : if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP)) {
689 0 : ftl_mngt_fail_step(mngt);
690 0 : return;
691 : }
692 0 : ftl_mngt_next_step(mngt);
693 0 : return;
694 : }
695 0 : restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_VALID_MAP);
696 : }
697 :
698 : static void
699 0 : ftl_mngt_restore_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
700 : {
701 0 : if (ftl_fast_startup(dev)) {
702 0 : FTL_DEBUGLOG(dev, "SHM: found band md\n");
703 0 : if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD)) {
704 0 : ftl_mngt_fail_step(mngt);
705 0 : return;
706 : }
707 0 : ftl_mngt_next_step(mngt);
708 0 : return;
709 : }
710 0 : restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
711 : }
712 :
713 : static void
714 0 : ftl_mngt_restore_trim_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
715 : {
716 0 : if (ftl_fast_startup(dev)) {
717 0 : FTL_DEBUGLOG(dev, "SHM: found trim md\n");
718 0 : if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD)) {
719 0 : ftl_mngt_fail_step(mngt);
720 0 : return;
721 : }
722 0 : ftl_mngt_next_step(mngt);
723 0 : return;
724 : }
725 0 : restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_TRIM_MD);
726 : }
727 :
728 : /*
729 : * Loads metadata after a clean shutdown.
730 : */
731 : static const struct ftl_mngt_process_desc desc_restore = {
732 : .name = "Restore metadata",
733 : .steps = {
734 : {
735 : .name = "Restore NV cache metadata",
736 : .action = ftl_mngt_restore_nv_cache_metadata,
737 : },
738 : {
739 : .name = "Restore valid map metadata",
740 : .action = ftl_mngt_restore_vld_map_metadata,
741 : },
742 : {
743 : .name = "Restore band info metadata",
744 : .action = ftl_mngt_restore_band_info_metadata,
745 : },
746 : {
747 : .name = "Restore trim metadata",
748 : .action = ftl_mngt_restore_trim_metadata,
749 : },
750 : {}
751 : }
752 : };
753 :
754 : void
755 0 : ftl_mngt_restore_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
756 : {
757 0 : ftl_mngt_call_process(mngt, &desc_restore);
758 0 : }
759 :
760 : void
761 0 : ftl_mngt_persist_superblock(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
762 : {
763 0 : dev->sb->header.crc = get_sb_crc(dev->sb);
764 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
765 0 : }
|