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