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