xref: /spdk/lib/ftl/mngt/ftl_mngt_md.c (revision f8abbede89d30584d2a4f8427b13896f8591b873)
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 	sb->upgrade_ready = false;
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 	sb->upgrade_ready = dev->conf.prep_upgrade_on_shutdown;
389 	dev->sb_shm->shm_clean = false;
390 	sb->header.crc = get_sb_crc(sb);
391 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
392 
393 	dev->sb_shm->shm_ready = false;
394 }
395 
396 void
397 ftl_mngt_set_shm_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
398 {
399 	struct ftl_superblock *sb = dev->sb;
400 
401 	sb->clean = 1;
402 	dev->sb_shm->shm_clean = true;
403 	sb->header.crc = get_sb_crc(sb);
404 	ftl_mngt_next_step(mngt);
405 }
406 
407 void
408 ftl_mngt_load_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
409 {
410 	FTL_NOTICELOG(dev, "SHM: clean %"PRIu64", shm_clean %d\n", dev->sb->clean, dev->sb_shm->shm_clean);
411 
412 	if (!ftl_fast_startup(dev)) {
413 		restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
414 		return;
415 	}
416 
417 	FTL_DEBUGLOG(dev, "SHM: found SB\n");
418 	if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_SB)) {
419 		ftl_mngt_fail_step(mngt);
420 		return;
421 	}
422 	ftl_mngt_next_step(mngt);
423 }
424 
425 void
426 ftl_mngt_validate_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
427 {
428 	struct ftl_superblock *sb = dev->sb;
429 
430 	if (!ftl_superblock_check_magic(sb)) {
431 		FTL_ERRLOG(dev, "Invalid FTL superblock magic\n");
432 		ftl_mngt_fail_step(mngt);
433 		return;
434 	}
435 
436 	if (sb->header.crc != get_sb_crc(sb)) {
437 		FTL_ERRLOG(dev, "Invalid FTL superblock CRC\n");
438 		ftl_mngt_fail_step(mngt);
439 		return;
440 	}
441 
442 	if (ftl_superblock_upgrade(dev)) {
443 		FTL_ERRLOG(dev, "FTL superblock dirty or invalid version\n");
444 		ftl_mngt_fail_step(mngt);
445 		return;
446 	}
447 
448 	if (spdk_uuid_compare(&sb->uuid, &dev->conf.uuid) != 0) {
449 		FTL_ERRLOG(dev, "Invalid FTL superblock UUID\n");
450 		ftl_mngt_fail_step(mngt);
451 		return;
452 	}
453 
454 	if (sb->lba_cnt == 0) {
455 		FTL_ERRLOG(dev, "Invalid FTL superblock lba_cnt\n");
456 		ftl_mngt_fail_step(mngt);
457 		return;
458 	}
459 	dev->num_lbas = sb->lba_cnt;
460 
461 	/* The sb has just been read. Validate and update the conf */
462 	if (sb->overprovisioning == 0 || sb->overprovisioning >= 100) {
463 		FTL_ERRLOG(dev, "Invalid FTL superblock lba_rsvd\n");
464 		ftl_mngt_fail_step(mngt);
465 		return;
466 	}
467 	dev->conf.overprovisioning = sb->overprovisioning;
468 
469 	ftl_mngt_next_step(mngt);
470 }
471 
472 /*
473  * Loads and verifies superblock contents - utilized during the load of an FTL
474  * instance (both from a clean and dirty shutdown).
475  */
476 static const struct ftl_mngt_process_desc desc_restore_sb = {
477 	.name = "SB restore",
478 	.steps = {
479 		{
480 			.name = "Load super block",
481 			.action = ftl_mngt_load_sb
482 		},
483 		{
484 			.name = "Validate super block",
485 			.action = ftl_mngt_validate_sb
486 		},
487 		{}
488 	}
489 };
490 
491 /*
492  * Initializes the superblock fields during first startup of FTL
493  */
494 static const struct ftl_mngt_process_desc desc_init_sb = {
495 	.name = "SB initialize",
496 	.steps = {
497 		{
498 			.name = "Default-initialize superblock",
499 			.action = ftl_mngt_init_default_sb,
500 		},
501 		{}
502 	}
503 };
504 
505 void
506 ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
507 {
508 	struct ftl_layout *layout = &dev->layout;
509 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
510 	char uuid[SPDK_UUID_STRING_LEN];
511 	int md_create_flags = ftl_md_create_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB);
512 
513 	/* Must generate UUID before MD create on SHM for the SB */
514 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
515 		spdk_uuid_generate(&dev->conf.uuid);
516 		spdk_uuid_fmt_lower(uuid, sizeof(uuid), &dev->conf.uuid);
517 		FTL_NOTICELOG(dev, "Create new FTL, UUID %s\n", uuid);
518 	}
519 
520 shm_retry:
521 	/* Allocate md buf */
522 	dev->sb_shm = NULL;
523 	dev->sb_shm_md = ftl_md_create(dev, spdk_divide_round_up(sizeof(*dev->sb_shm), FTL_BLOCK_SIZE),
524 				       0, "sb_shm",
525 				       md_create_flags, NULL);
526 	if (dev->sb_shm_md == NULL) {
527 		/* The first attempt may fail when trying to open SHM - try to create new */
528 		if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
529 			md_create_flags |= FTL_MD_CREATE_SHM_NEW;
530 			goto shm_retry;
531 		}
532 		if (dev->sb_shm_md == NULL) {
533 			ftl_mngt_fail_step(mngt);
534 			return;
535 		}
536 	}
537 
538 	dev->sb_shm = ftl_md_get_buffer(dev->sb_shm_md);
539 
540 	/* Setup the layout of a superblock */
541 	if (ftl_layout_setup_superblock(dev)) {
542 		ftl_mngt_fail_step(mngt);
543 		return;
544 	}
545 
546 	/* Allocate md buf */
547 	layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks,
548 						region->vss_blksz, region->name,
549 						md_create_flags, region);
550 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
551 		/* The first attempt may fail when trying to open SHM - try to create new */
552 		if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
553 			md_create_flags |= FTL_MD_CREATE_SHM_NEW;
554 			ftl_md_destroy(dev->sb_shm_md, 0);
555 			dev->sb_shm_md = NULL;
556 			goto shm_retry;
557 		}
558 		ftl_mngt_fail_step(mngt);
559 		return;
560 	}
561 
562 	/* Link the md buf to the device */
563 	dev->sb = ftl_md_get_buffer(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
564 
565 	/* Setup superblock mirror to QLC */
566 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
567 	layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks,
568 			region->vss_blksz, NULL, FTL_MD_CREATE_HEAP, region);
569 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
570 		ftl_mngt_fail_step(mngt);
571 		return;
572 	}
573 
574 	/* Initialize the superblock */
575 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
576 		ftl_mngt_call_process(mngt, &desc_init_sb);
577 	} else {
578 		ftl_mngt_call_process(mngt, &desc_restore_sb);
579 	}
580 }
581 
582 void
583 ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
584 {
585 	struct ftl_layout *layout = &dev->layout;
586 
587 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
588 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB],
589 			       ftl_md_destroy_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB));
590 		layout->md[FTL_LAYOUT_REGION_TYPE_SB] = NULL;
591 	}
592 
593 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
594 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE], 0);
595 		layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = NULL;
596 	}
597 
598 	ftl_md_destroy(dev->sb_shm_md, ftl_md_destroy_shm_flags(dev));
599 	dev->sb_shm_md = NULL;
600 	dev->sb_shm = NULL;
601 
602 	ftl_mngt_next_step(mngt);
603 }
604 
605 static void
606 ftl_mngt_restore_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
607 {
608 	if (ftl_fast_startup(dev)) {
609 		FTL_DEBUGLOG(dev, "SHM: found nv cache md\n");
610 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD)) {
611 			ftl_mngt_fail_step(mngt);
612 			return;
613 		}
614 		ftl_mngt_next_step(mngt);
615 		return;
616 	}
617 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
618 }
619 
620 static void
621 ftl_mngt_restore_vld_map_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
622 {
623 	if (ftl_fast_startup(dev)) {
624 		FTL_DEBUGLOG(dev, "SHM: found vldmap\n");
625 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP)) {
626 			ftl_mngt_fail_step(mngt);
627 			return;
628 		}
629 		ftl_mngt_next_step(mngt);
630 		return;
631 	}
632 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_VALID_MAP);
633 }
634 
635 static void
636 ftl_mngt_restore_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
637 {
638 	if (ftl_fast_startup(dev)) {
639 		FTL_DEBUGLOG(dev, "SHM: found band md\n");
640 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD)) {
641 			ftl_mngt_fail_step(mngt);
642 			return;
643 		}
644 		ftl_mngt_next_step(mngt);
645 		return;
646 	}
647 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
648 }
649 
650 static void
651 ftl_mngt_restore_trim_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
652 {
653 	if (ftl_fast_startup(dev)) {
654 		FTL_DEBUGLOG(dev, "SHM: found trim md\n");
655 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD)) {
656 			ftl_mngt_fail_step(mngt);
657 			return;
658 		}
659 		ftl_mngt_next_step(mngt);
660 		return;
661 	}
662 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_TRIM_MD);
663 }
664 
665 /*
666  * Loads metadata after a clean shutdown.
667  */
668 static const struct ftl_mngt_process_desc desc_restore = {
669 	.name = "Restore metadata",
670 	.steps = {
671 		{
672 			.name = "Restore NV cache metadata",
673 			.action = ftl_mngt_restore_nv_cache_metadata,
674 		},
675 		{
676 			.name = "Restore valid map metadata",
677 			.action = ftl_mngt_restore_vld_map_metadata,
678 		},
679 		{
680 			.name = "Restore band info metadata",
681 			.action = ftl_mngt_restore_band_info_metadata,
682 		},
683 		{
684 			.name = "Restore trim metadata",
685 			.action = ftl_mngt_restore_trim_metadata,
686 		},
687 		{}
688 	}
689 };
690 
691 void
692 ftl_mngt_restore_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
693 {
694 	ftl_mngt_call_process(mngt, &desc_restore);
695 }
696 
697 void
698 ftl_mngt_persist_superblock(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
699 {
700 	dev->sb->header.crc = get_sb_crc(dev->sb);
701 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
702 }
703