xref: /spdk/lib/ftl/mngt/ftl_mngt_md.c (revision b50af42b621bbd51f1fba7977706cc4e463a5c09)
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 void
217 ftl_mngt_persist_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
218 {
219 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
220 }
221 
222 static uint32_t
223 get_sb_crc(struct ftl_superblock *sb)
224 {
225 	uint32_t crc = 0;
226 
227 	/* Calculate CRC excluding CRC field in superblock */
228 	void *buffer = sb;
229 	size_t offset = offsetof(struct ftl_superblock, header.crc);
230 	size_t size = offset;
231 	crc = spdk_crc32c_update(buffer, size, crc);
232 
233 	buffer += offset + sizeof(sb->header.crc);
234 	size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc);
235 	crc = spdk_crc32c_update(buffer, size, crc);
236 
237 	return crc;
238 }
239 
240 static void
241 ftl_mngt_persist_super_block(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
242 {
243 	dev->sb->overprovisioning = dev->conf.overprovisioning;
244 	dev->sb->gc_info = dev->sb_shm->gc_info;
245 	dev->sb->header.crc = get_sb_crc(dev->sb);
246 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
247 }
248 
249 #ifdef SPDK_FTL_VSS_EMU
250 static void
251 ftl_mngt_persist_vss(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
252 {
253 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_VSS);
254 }
255 #endif
256 
257 /*
258  * Persists all necessary metadata (band state, P2L, etc) during FTL's clean shutdown.
259  */
260 static const struct ftl_mngt_process_desc desc_persist = {
261 	.name = "Persist metadata",
262 	.steps = {
263 		{
264 			.name = "Persist NV cache metadata",
265 			.action = ftl_mngt_persist_nv_cache_metadata,
266 		},
267 		{
268 			.name = "Persist valid map metadata",
269 			.action = ftl_mngt_persist_vld_map_metadata,
270 		},
271 		{
272 			.name = "persist band info metadata",
273 			.action = ftl_mngt_persist_band_info_metadata,
274 		},
275 		{
276 			.name = "Persist superblock",
277 			.action = ftl_mngt_persist_super_block,
278 		},
279 #ifdef SPDK_FTL_VSS_EMU
280 		{
281 			.name = "Persist VSS metadata",
282 			.action = ftl_mngt_persist_vss,
283 		},
284 #endif
285 		{}
286 	}
287 };
288 
289 void
290 ftl_mngt_persist_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
291 {
292 	ftl_mngt_call_process(mngt, &desc_persist);
293 }
294 
295 /*
296  * Fast clean shutdown path - skips the persistance of most metadata regions and
297  * relies on their shared memory state instead.
298  */
299 static const struct ftl_mngt_process_desc desc_fast_persist = {
300 	.name = "Fast persist metadata",
301 	.steps = {
302 		{
303 			.name = "Fast persist NV cache metadata",
304 			.action = ftl_mngt_fast_persist_nv_cache_metadata,
305 		},
306 #ifdef SPDK_FTL_VSS_EMU
307 		{
308 			.name = "Persist VSS metadata",
309 			.action = ftl_mngt_persist_vss,
310 		},
311 #endif
312 		{}
313 	}
314 };
315 
316 void
317 ftl_mngt_fast_persist_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
318 {
319 	ftl_mngt_call_process(mngt, &desc_fast_persist);
320 }
321 
322 void
323 ftl_mngt_init_default_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
324 {
325 	struct ftl_superblock *sb = dev->sb;
326 
327 	sb->header.magic = FTL_SUPERBLOCK_MAGIC;
328 	sb->header.version = FTL_METADATA_VERSION_CURRENT;
329 	sb->uuid = dev->conf.uuid;
330 	sb->clean = 0;
331 	dev->sb_shm->shm_clean = false;
332 
333 	/* Max 16 IO depth per band relocate */
334 	sb->max_reloc_qdepth = 16;
335 
336 	sb->overprovisioning = dev->conf.overprovisioning;
337 
338 	ftl_band_init_gc_iter(dev);
339 
340 	/* md layout isn't initialized yet.
341 	 * empty region list => all regions in the default location */
342 	sb->md_layout_head.type = FTL_LAYOUT_REGION_TYPE_INVALID;
343 
344 	sb->header.crc = get_sb_crc(sb);
345 
346 	ftl_mngt_next_step(mngt);
347 }
348 
349 void
350 ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
351 {
352 	struct ftl_superblock *sb = dev->sb;
353 
354 	sb->clean = 0;
355 	dev->sb_shm->shm_clean = false;
356 	sb->header.crc = get_sb_crc(sb);
357 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
358 }
359 
360 void
361 ftl_mngt_set_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
362 {
363 	struct ftl_superblock *sb = dev->sb;
364 
365 	sb->clean = 1;
366 	dev->sb_shm->shm_clean = false;
367 	sb->header.crc = get_sb_crc(sb);
368 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
369 
370 	dev->sb_shm->shm_ready = false;
371 }
372 
373 void
374 ftl_mngt_set_shm_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
375 {
376 	struct ftl_superblock *sb = dev->sb;
377 
378 	sb->clean = 1;
379 	dev->sb_shm->shm_clean = true;
380 	sb->header.crc = get_sb_crc(sb);
381 	ftl_mngt_next_step(mngt);
382 }
383 
384 void
385 ftl_mngt_load_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
386 {
387 	FTL_NOTICELOG(dev, "SHM: clean %"PRIu64", shm_clean %d\n", dev->sb->clean, dev->sb_shm->shm_clean);
388 
389 	if (!ftl_fast_startup(dev)) {
390 		restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
391 		return;
392 	}
393 
394 	FTL_DEBUGLOG(dev, "SHM: found SB\n");
395 	if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_SB)) {
396 		ftl_mngt_fail_step(mngt);
397 		return;
398 	}
399 	ftl_mngt_next_step(mngt);
400 }
401 
402 void
403 ftl_mngt_validate_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
404 {
405 	struct ftl_superblock *sb = dev->sb;
406 
407 	if (!ftl_superblock_check_magic(sb)) {
408 		FTL_ERRLOG(dev, "Invalid FTL superblock magic\n");
409 		ftl_mngt_fail_step(mngt);
410 		return;
411 	}
412 
413 	if (sb->header.crc != get_sb_crc(sb)) {
414 		FTL_ERRLOG(dev, "Invalid FTL superblock CRC\n");
415 		ftl_mngt_fail_step(mngt);
416 		return;
417 	}
418 
419 	if (spdk_uuid_compare(&sb->uuid, &dev->conf.uuid) != 0) {
420 		FTL_ERRLOG(dev, "Invalid FTL superblock UUID\n");
421 		ftl_mngt_fail_step(mngt);
422 		return;
423 	}
424 
425 	if (sb->lba_cnt == 0) {
426 		FTL_ERRLOG(dev, "Invalid FTL superblock lba_cnt\n");
427 		ftl_mngt_fail_step(mngt);
428 		return;
429 	}
430 	dev->num_lbas = sb->lba_cnt;
431 
432 	/* The sb has just been read. Validate and update the conf */
433 	if (sb->overprovisioning == 0 || sb->overprovisioning >= 100) {
434 		FTL_ERRLOG(dev, "Invalid FTL superblock lba_rsvd\n");
435 		ftl_mngt_fail_step(mngt);
436 		return;
437 	}
438 	dev->conf.overprovisioning = sb->overprovisioning;
439 
440 	ftl_mngt_next_step(mngt);
441 }
442 
443 /*
444  * Loads and verifies superblock contents - utilized during the load of an FTL
445  * instance (both from a clean and dirty shutdown).
446  */
447 static const struct ftl_mngt_process_desc desc_restore_sb = {
448 	.name = "SB restore",
449 	.steps = {
450 		{
451 			.name = "Load super block",
452 			.action = ftl_mngt_load_sb
453 		},
454 		{
455 			.name = "Validate super block",
456 			.action = ftl_mngt_validate_sb
457 		},
458 		{}
459 	}
460 };
461 
462 /*
463  * Initializes the superblock fields during first startup of FTL
464  */
465 static const struct ftl_mngt_process_desc desc_init_sb = {
466 	.name = "SB initialize",
467 	.steps = {
468 		{
469 			.name = "Default-initialize superblock",
470 			.action = ftl_mngt_init_default_sb,
471 		},
472 		{}
473 	}
474 };
475 
476 #ifdef SPDK_FTL_VSS_EMU
477 void
478 ftl_mngt_md_init_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
479 {
480 	struct ftl_layout *layout = &dev->layout;
481 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS];
482 
483 	/* Initialize VSS layout */
484 	ftl_layout_setup_vss_emu(dev);
485 
486 	/* Allocate md buf */
487 	layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = ftl_md_create(dev, region->current.blocks,
488 			region->vss_blksz, NULL, 0, region);
489 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
490 		ftl_mngt_fail_step(mngt);
491 		return;
492 	}
493 	ftl_mngt_next_step(mngt);
494 }
495 
496 void
497 ftl_mngt_md_deinit_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
498 {
499 	struct ftl_layout *layout = &dev->layout;
500 
501 	if (layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
502 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_VSS], 0);
503 		layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = NULL;
504 	}
505 
506 	ftl_mngt_next_step(mngt);
507 }
508 #endif
509 
510 void
511 ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
512 {
513 	struct ftl_layout *layout = &dev->layout;
514 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
515 	char uuid[SPDK_UUID_STRING_LEN];
516 	int md_create_flags = ftl_md_create_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB);
517 
518 	/* Must generate UUID before MD create on SHM for the SB */
519 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
520 		spdk_uuid_generate(&dev->conf.uuid);
521 		spdk_uuid_fmt_lower(uuid, sizeof(uuid), &dev->conf.uuid);
522 		FTL_NOTICELOG(dev, "Create new FTL, UUID %s\n", uuid);
523 	}
524 
525 shm_retry:
526 	/* Allocate md buf */
527 	dev->sb_shm = NULL;
528 	dev->sb_shm_md = ftl_md_create(dev, spdk_divide_round_up(sizeof(*dev->sb_shm), FTL_BLOCK_SIZE),
529 				       0, "sb_shm",
530 				       md_create_flags, NULL);
531 	if (dev->sb_shm_md == NULL) {
532 		/* The first attempt may fail when trying to open SHM - try to create new */
533 		if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
534 			md_create_flags |= FTL_MD_CREATE_SHM_NEW;
535 			goto shm_retry;
536 		}
537 		if (dev->sb_shm_md == NULL) {
538 			ftl_mngt_fail_step(mngt);
539 			return;
540 		}
541 	}
542 
543 	dev->sb_shm = ftl_md_get_buffer(dev->sb_shm_md);
544 
545 	/* Setup the layout of a superblock */
546 	if (ftl_layout_setup_superblock(dev)) {
547 		ftl_mngt_fail_step(mngt);
548 		return;
549 	}
550 
551 	/* Allocate md buf */
552 	layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks,
553 						region->vss_blksz, region->name,
554 						md_create_flags, region);
555 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
556 		/* The first attempt may fail when trying to open SHM - try to create new */
557 		if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
558 			md_create_flags |= FTL_MD_CREATE_SHM_NEW;
559 			ftl_md_destroy(dev->sb_shm_md, 0);
560 			goto shm_retry;
561 		}
562 		ftl_mngt_fail_step(mngt);
563 		return;
564 	}
565 
566 	/* Link the md buf to the device */
567 	dev->sb = ftl_md_get_buffer(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
568 
569 	/* Setup superblock mirror to QLC */
570 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
571 	layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks,
572 			region->vss_blksz, NULL, FTL_MD_CREATE_HEAP, region);
573 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
574 		ftl_mngt_fail_step(mngt);
575 		return;
576 	}
577 
578 	/* Initialize the superblock */
579 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
580 		ftl_mngt_call_process(mngt, &desc_init_sb);
581 	} else {
582 		ftl_mngt_call_process(mngt, &desc_restore_sb);
583 	}
584 }
585 
586 void
587 ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
588 {
589 	struct ftl_layout *layout = &dev->layout;
590 
591 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
592 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB],
593 			       ftl_md_destroy_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB));
594 		layout->md[FTL_LAYOUT_REGION_TYPE_SB] = NULL;
595 	}
596 
597 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
598 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE], 0);
599 		layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = NULL;
600 	}
601 
602 	ftl_md_destroy(dev->sb_shm_md, ftl_md_destroy_shm_flags(dev));
603 	dev->sb_shm_md = NULL;
604 	dev->sb_shm = NULL;
605 
606 	ftl_mngt_next_step(mngt);
607 }
608 
609 static void
610 ftl_mngt_restore_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
611 {
612 	if (ftl_fast_startup(dev)) {
613 		FTL_DEBUGLOG(dev, "SHM: found nv cache md\n");
614 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD)) {
615 			ftl_mngt_fail_step(mngt);
616 			return;
617 		}
618 		ftl_mngt_next_step(mngt);
619 		return;
620 	}
621 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
622 }
623 
624 static void
625 ftl_mngt_restore_vld_map_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
626 {
627 	if (ftl_fast_startup(dev)) {
628 		FTL_DEBUGLOG(dev, "SHM: found vldmap\n");
629 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP)) {
630 			ftl_mngt_fail_step(mngt);
631 			return;
632 		}
633 		ftl_mngt_next_step(mngt);
634 		return;
635 	}
636 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_VALID_MAP);
637 }
638 
639 static void
640 ftl_mngt_restore_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
641 {
642 	if (ftl_fast_startup(dev)) {
643 		FTL_DEBUGLOG(dev, "SHM: found band md\n");
644 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD)) {
645 			ftl_mngt_fail_step(mngt);
646 			return;
647 		}
648 		ftl_mngt_next_step(mngt);
649 		return;
650 	}
651 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
652 }
653 
654 
655 
656 #ifdef SPDK_FTL_VSS_EMU
657 static void
658 ftl_mngt_restore_vss_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
659 {
660 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_VSS);
661 }
662 #endif
663 
664 /*
665  * Loads metadata after a clean shutdown.
666  */
667 static const struct ftl_mngt_process_desc desc_restore = {
668 	.name = "Restore metadata",
669 	.steps = {
670 #ifdef SPDK_FTL_VSS_EMU
671 		{
672 			.name = "Restore VSS metadata",
673 			.action = ftl_mngt_restore_vss_metadata,
674 		},
675 #endif
676 		{
677 			.name = "Restore NV cache metadata",
678 			.action = ftl_mngt_restore_nv_cache_metadata,
679 		},
680 		{
681 			.name = "Restore valid map metadata",
682 			.action = ftl_mngt_restore_vld_map_metadata,
683 		},
684 		{
685 			.name = "Restore band info metadata",
686 			.action = ftl_mngt_restore_band_info_metadata,
687 		},
688 		{}
689 	}
690 };
691 
692 void
693 ftl_mngt_restore_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
694 {
695 	ftl_mngt_call_process(mngt, &desc_restore);
696 }
697