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