xref: /spdk/lib/ftl/mngt/ftl_mngt_md.c (revision 6d6179ff420a322c5161a49a5af5bfd30e78674e)
12b5bba56SArtur Paszkiewicz /*   SPDX-License-Identifier: BSD-3-Clause
217cf101bSMateusz Kozlowski  *   Copyright 2023 Solidigm All Rights Reserved
3a6dbe372Spaul luse  *   Copyright (C) 2022 Intel Corporation.
42b5bba56SArtur Paszkiewicz  *   All rights reserved.
52b5bba56SArtur Paszkiewicz  */
62b5bba56SArtur Paszkiewicz 
72b5bba56SArtur Paszkiewicz #include "spdk/thread.h"
82b5bba56SArtur Paszkiewicz #include "spdk/crc32.h"
99f42898aSLukasz Lasek #include "spdk/string.h"
102b5bba56SArtur Paszkiewicz 
112b5bba56SArtur Paszkiewicz #include "ftl_core.h"
122b5bba56SArtur Paszkiewicz #include "ftl_mngt.h"
132b5bba56SArtur Paszkiewicz #include "ftl_mngt_steps.h"
142b5bba56SArtur Paszkiewicz #include "ftl_utils.h"
156448f336SArtur Paszkiewicz #include "ftl_band.h"
162b5bba56SArtur Paszkiewicz #include "ftl_internal.h"
17c6880a39SArtur Paszkiewicz #include "ftl_sb.h"
189f42898aSLukasz Lasek #include "base/ftl_base_dev.h"
199f42898aSLukasz Lasek #include "nvc/ftl_nvc_dev.h"
207ff28519SKozlowski Mateusz #include "upgrade/ftl_layout_upgrade.h"
21c8ab874dSKozlowski Mateusz #include "upgrade/ftl_sb_upgrade.h"
222b5bba56SArtur Paszkiewicz 
232b5bba56SArtur Paszkiewicz void
242b5bba56SArtur Paszkiewicz ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
252b5bba56SArtur Paszkiewicz {
262b5bba56SArtur Paszkiewicz 	if (ftl_layout_setup(dev)) {
272b5bba56SArtur Paszkiewicz 		ftl_mngt_fail_step(mngt);
282b5bba56SArtur Paszkiewicz 	} else {
292b5bba56SArtur Paszkiewicz 		ftl_mngt_next_step(mngt);
302b5bba56SArtur Paszkiewicz 	}
312b5bba56SArtur Paszkiewicz }
327a7ac2afSArtur Paszkiewicz 
337a7ac2afSArtur Paszkiewicz static bool
347a7ac2afSArtur Paszkiewicz is_buffer_needed(enum ftl_layout_region_type type)
357a7ac2afSArtur Paszkiewicz {
367a7ac2afSArtur Paszkiewicz 	switch (type) {
37c6880a39SArtur Paszkiewicz 	case FTL_LAYOUT_REGION_TYPE_SB:
38c6880a39SArtur Paszkiewicz 	case FTL_LAYOUT_REGION_TYPE_SB_BASE:
397a7ac2afSArtur Paszkiewicz 	case FTL_LAYOUT_REGION_TYPE_DATA_NVC:
407a7ac2afSArtur Paszkiewicz 	case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
41a68a12a4SKozlowski Mateusz 	case FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR:
426448f336SArtur Paszkiewicz 	case FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR:
43b4b70e83SKozlowski Mateusz #ifndef SPDK_FTL_L2P_FLAT
44b4b70e83SKozlowski Mateusz 	case FTL_LAYOUT_REGION_TYPE_L2P:
45b4b70e83SKozlowski Mateusz #endif
4678c3cbf4SArtur Paszkiewicz 	case FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR:
472d613454SMateusz Kozlowski 	case FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR:
48*6d6179ffSMateusz Kozlowski 	case FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN:
49*6d6179ffSMateusz Kozlowski 	case FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX:
507a7ac2afSArtur Paszkiewicz 		return false;
517a7ac2afSArtur Paszkiewicz 
527a7ac2afSArtur Paszkiewicz 	default:
537a7ac2afSArtur Paszkiewicz 		return true;
547a7ac2afSArtur Paszkiewicz 	}
557a7ac2afSArtur Paszkiewicz }
567a7ac2afSArtur Paszkiewicz 
577a7ac2afSArtur Paszkiewicz void
587a7ac2afSArtur Paszkiewicz ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
597a7ac2afSArtur Paszkiewicz {
607a7ac2afSArtur Paszkiewicz 	struct ftl_layout *layout = &dev->layout;
619f42898aSLukasz Lasek 	struct ftl_layout_region *region;
62522a0c82SLukasz Lasek 	struct ftl_md *md, *md_mirror;
639f42898aSLukasz Lasek 	enum ftl_layout_region_type i;
64818b9c05SArtur Paszkiewicz 	int md_flags;
657a7ac2afSArtur Paszkiewicz 
669f42898aSLukasz Lasek 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
679f42898aSLukasz Lasek 		region = ftl_layout_region_get(dev, i);
689f42898aSLukasz Lasek 		if (!region) {
699f42898aSLukasz Lasek 			continue;
709f42898aSLukasz Lasek 		}
71522a0c82SLukasz Lasek 		assert(i == region->type);
727a7ac2afSArtur Paszkiewicz 		if (layout->md[i]) {
737a7ac2afSArtur Paszkiewicz 			/*
747a7ac2afSArtur Paszkiewicz 			 * Some metadata objects are initialized by other FTL
757a7ac2afSArtur Paszkiewicz 			 * components. At the moment it's only used by superblock (and its mirror) -
767a7ac2afSArtur Paszkiewicz 			 * during load time we need to read it earlier in order to get the layout for the
777a7ac2afSArtur Paszkiewicz 			 * other regions.
787a7ac2afSArtur Paszkiewicz 			 */
797a7ac2afSArtur Paszkiewicz 			continue;
807a7ac2afSArtur Paszkiewicz 		}
81811a027eSKozlowski Mateusz 		md_flags = is_buffer_needed(i) ? ftl_md_create_region_flags(dev,
82811a027eSKozlowski Mateusz 				region->type) : FTL_MD_CREATE_NO_MEM;
837a7ac2afSArtur Paszkiewicz 		layout->md[i] = ftl_md_create(dev, region->current.blocks, region->vss_blksz, region->name,
84818b9c05SArtur Paszkiewicz 					      md_flags, region);
857a7ac2afSArtur Paszkiewicz 		if (NULL == layout->md[i]) {
867a7ac2afSArtur Paszkiewicz 			ftl_mngt_fail_step(mngt);
877a7ac2afSArtur Paszkiewicz 			return;
887a7ac2afSArtur Paszkiewicz 		}
897a7ac2afSArtur Paszkiewicz 	}
907a7ac2afSArtur Paszkiewicz 
91522a0c82SLukasz Lasek 	/* Initialize mirror regions */
929f42898aSLukasz Lasek 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
939f42898aSLukasz Lasek 		region = ftl_layout_region_get(dev, i);
949f42898aSLukasz Lasek 		if (!region) {
959f42898aSLukasz Lasek 			continue;
969f42898aSLukasz Lasek 		}
97522a0c82SLukasz Lasek 		assert(i == region->type);
98522a0c82SLukasz Lasek 		if (region->mirror_type != FTL_LAYOUT_REGION_TYPE_INVALID &&
99522a0c82SLukasz Lasek 		    !is_buffer_needed(region->mirror_type)) {
100522a0c82SLukasz Lasek 			md = layout->md[i];
101522a0c82SLukasz Lasek 			md_mirror = layout->md[region->mirror_type];
102522a0c82SLukasz Lasek 
103522a0c82SLukasz Lasek 			md_mirror->dev = md->dev;
104522a0c82SLukasz Lasek 			md_mirror->data_blocks = md->data_blocks;
105522a0c82SLukasz Lasek 			md_mirror->data = md->data;
106522a0c82SLukasz Lasek 			if (md_mirror->region->vss_blksz == md->region->vss_blksz) {
107522a0c82SLukasz Lasek 				md_mirror->vss_data = md->vss_data;
108522a0c82SLukasz Lasek 			}
1099f42898aSLukasz Lasek 			md_mirror->region = ftl_layout_region_get(dev, region->mirror_type);
1109f42898aSLukasz Lasek 			ftl_bug(md_mirror->region == NULL);
111522a0c82SLukasz Lasek 			md_mirror->is_mirror = true;
112522a0c82SLukasz Lasek 		}
113522a0c82SLukasz Lasek 	}
114522a0c82SLukasz Lasek 
1157a7ac2afSArtur Paszkiewicz 	ftl_mngt_next_step(mngt);
1167a7ac2afSArtur Paszkiewicz }
1177a7ac2afSArtur Paszkiewicz 
1187a7ac2afSArtur Paszkiewicz void
1197a7ac2afSArtur Paszkiewicz ftl_mngt_deinit_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
1207a7ac2afSArtur Paszkiewicz {
1217a7ac2afSArtur Paszkiewicz 	struct ftl_layout *layout = &dev->layout;
1229f42898aSLukasz Lasek 	struct ftl_layout_region *region;
1239f42898aSLukasz Lasek 	enum ftl_layout_region_type i;
1247a7ac2afSArtur Paszkiewicz 
1259f42898aSLukasz Lasek 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
1269f42898aSLukasz Lasek 		region = ftl_layout_region_get(dev, i);
1279f42898aSLukasz Lasek 		if (!region) {
1289f42898aSLukasz Lasek 			continue;
1299f42898aSLukasz Lasek 		}
1307a7ac2afSArtur Paszkiewicz 		if (layout->md[i]) {
1319f42898aSLukasz Lasek 			ftl_md_destroy(layout->md[i], ftl_md_destroy_region_flags(dev, region->type));
1327a7ac2afSArtur Paszkiewicz 			layout->md[i] = NULL;
1337a7ac2afSArtur Paszkiewicz 		}
1347a7ac2afSArtur Paszkiewicz 	}
1357a7ac2afSArtur Paszkiewicz 
1367a7ac2afSArtur Paszkiewicz 	ftl_mngt_next_step(mngt);
1377a7ac2afSArtur Paszkiewicz }
138f725ca81SArtur Paszkiewicz 
139c6880a39SArtur Paszkiewicz static void
140c6880a39SArtur Paszkiewicz persist_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
141c6880a39SArtur Paszkiewicz {
142c6880a39SArtur Paszkiewicz 	struct ftl_mngt_process *mngt = md->owner.cb_ctx;
143c6880a39SArtur Paszkiewicz 
144c6880a39SArtur Paszkiewicz 	if (status) {
145c6880a39SArtur Paszkiewicz 		ftl_mngt_fail_step(mngt);
146c6880a39SArtur Paszkiewicz 	} else {
147c6880a39SArtur Paszkiewicz 		ftl_mngt_next_step(mngt);
148c6880a39SArtur Paszkiewicz 	}
149c6880a39SArtur Paszkiewicz }
150c6880a39SArtur Paszkiewicz 
151c6880a39SArtur Paszkiewicz static void
152c6880a39SArtur Paszkiewicz persist(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
153c6880a39SArtur Paszkiewicz 	enum ftl_layout_region_type type)
154c6880a39SArtur Paszkiewicz {
155c6880a39SArtur Paszkiewicz 	struct ftl_layout *layout = &dev->layout;
1560c980660SGangCao 	struct ftl_md *md;
157c6880a39SArtur Paszkiewicz 
158c6880a39SArtur Paszkiewicz 	assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
159c6880a39SArtur Paszkiewicz 
1600c980660SGangCao 	md = layout->md[type];
161c6880a39SArtur Paszkiewicz 	if (!md) {
162c6880a39SArtur Paszkiewicz 		ftl_mngt_fail_step(mngt);
163c6880a39SArtur Paszkiewicz 		return;
164c6880a39SArtur Paszkiewicz 	}
165c6880a39SArtur Paszkiewicz 
166c6880a39SArtur Paszkiewicz 	md->owner.cb_ctx = mngt;
167c6880a39SArtur Paszkiewicz 	md->cb = persist_cb;
168c6880a39SArtur Paszkiewicz 	ftl_md_persist(md);
169c6880a39SArtur Paszkiewicz }
170c6880a39SArtur Paszkiewicz 
171cbd7ae6dSKozlowski Mateusz static int
172cbd7ae6dSKozlowski Mateusz ftl_md_restore_region(struct spdk_ftl_dev *dev, int region_type)
173cbd7ae6dSKozlowski Mateusz {
174cbd7ae6dSKozlowski Mateusz 	int status = 0;
175cbd7ae6dSKozlowski Mateusz 	switch (region_type) {
176cbd7ae6dSKozlowski Mateusz 	case FTL_LAYOUT_REGION_TYPE_NVC_MD:
177cbd7ae6dSKozlowski Mateusz 		status = ftl_nv_cache_load_state(&dev->nv_cache);
178cbd7ae6dSKozlowski Mateusz 		break;
179cbd7ae6dSKozlowski Mateusz 	case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
180cbd7ae6dSKozlowski Mateusz 		ftl_valid_map_load_state(dev);
181cbd7ae6dSKozlowski Mateusz 		break;
182cbd7ae6dSKozlowski Mateusz 	case FTL_LAYOUT_REGION_TYPE_BAND_MD:
183cb00e90aSMateusz Kozlowski 		status = ftl_bands_load_state(dev);
184cbd7ae6dSKozlowski Mateusz 		break;
185cbd7ae6dSKozlowski Mateusz 	default:
186cbd7ae6dSKozlowski Mateusz 		break;
187cbd7ae6dSKozlowski Mateusz 	}
188cbd7ae6dSKozlowski Mateusz 	return status;
189cbd7ae6dSKozlowski Mateusz }
190cbd7ae6dSKozlowski Mateusz 
191cbd7ae6dSKozlowski Mateusz static void
192cbd7ae6dSKozlowski Mateusz restore_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
193cbd7ae6dSKozlowski Mateusz {
194cbd7ae6dSKozlowski Mateusz 	struct ftl_mngt_process *mngt = md->owner.cb_ctx;
195cbd7ae6dSKozlowski Mateusz 	const struct ftl_layout_region *region = ftl_md_get_region(md);
196cbd7ae6dSKozlowski Mateusz 
197cbd7ae6dSKozlowski Mateusz 	if (status) {
198cbd7ae6dSKozlowski Mateusz 		/* Restore error, end step */
199cbd7ae6dSKozlowski Mateusz 		ftl_mngt_fail_step(mngt);
200cbd7ae6dSKozlowski Mateusz 		return;
201cbd7ae6dSKozlowski Mateusz 	}
202cbd7ae6dSKozlowski Mateusz 
203cbd7ae6dSKozlowski Mateusz 	assert(region);
204cbd7ae6dSKozlowski Mateusz 	status = ftl_md_restore_region(dev, region->type);
205cbd7ae6dSKozlowski Mateusz 
206cbd7ae6dSKozlowski Mateusz 	if (status) {
207cbd7ae6dSKozlowski Mateusz 		ftl_mngt_fail_step(mngt);
208cbd7ae6dSKozlowski Mateusz 	} else {
209cbd7ae6dSKozlowski Mateusz 		ftl_mngt_next_step(mngt);
210cbd7ae6dSKozlowski Mateusz 	}
211cbd7ae6dSKozlowski Mateusz }
212cbd7ae6dSKozlowski Mateusz 
213cbd7ae6dSKozlowski Mateusz static void
214cbd7ae6dSKozlowski Mateusz restore(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt, enum ftl_layout_region_type type)
215cbd7ae6dSKozlowski Mateusz {
216cbd7ae6dSKozlowski Mateusz 	struct ftl_layout *layout = &dev->layout;
217cbd7ae6dSKozlowski Mateusz 	assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
218cbd7ae6dSKozlowski Mateusz 	struct ftl_md *md = layout->md[type];
219cbd7ae6dSKozlowski Mateusz 
220cbd7ae6dSKozlowski Mateusz 	if (!md) {
221cbd7ae6dSKozlowski Mateusz 		ftl_mngt_fail_step(mngt);
222cbd7ae6dSKozlowski Mateusz 		return;
223cbd7ae6dSKozlowski Mateusz 	}
224cbd7ae6dSKozlowski Mateusz 
225cbd7ae6dSKozlowski Mateusz 	md->owner.cb_ctx = mngt;
226cbd7ae6dSKozlowski Mateusz 	md->cb = restore_cb;
227cbd7ae6dSKozlowski Mateusz 	ftl_md_restore(md);
228cbd7ae6dSKozlowski Mateusz }
229cbd7ae6dSKozlowski Mateusz 
230506315a6SKozlowski Mateusz void
231506315a6SKozlowski Mateusz ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
232506315a6SKozlowski Mateusz {
233506315a6SKozlowski Mateusz 	if (ftl_nv_cache_save_state(&dev->nv_cache)) {
234506315a6SKozlowski Mateusz 		ftl_mngt_fail_step(mngt);
235506315a6SKozlowski Mateusz 		return;
236506315a6SKozlowski Mateusz 	}
237506315a6SKozlowski Mateusz 
238506315a6SKozlowski Mateusz 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
239506315a6SKozlowski Mateusz }
240506315a6SKozlowski Mateusz 
241ef93cc38SKozlowski Mateusz static void
242b5e2c59aSKozlowski Mateusz ftl_mngt_fast_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
243b5e2c59aSKozlowski Mateusz {
244b5e2c59aSKozlowski Mateusz 	if (ftl_nv_cache_save_state(&dev->nv_cache)) {
245b5e2c59aSKozlowski Mateusz 		ftl_mngt_fail_step(mngt);
246b5e2c59aSKozlowski Mateusz 		return;
247b5e2c59aSKozlowski Mateusz 	}
248b5e2c59aSKozlowski Mateusz 	ftl_mngt_next_step(mngt);
249b5e2c59aSKozlowski Mateusz }
250b5e2c59aSKozlowski Mateusz 
251b5e2c59aSKozlowski Mateusz static void
252ef93cc38SKozlowski Mateusz ftl_mngt_persist_vld_map_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
253ef93cc38SKozlowski Mateusz {
254ef93cc38SKozlowski Mateusz 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_VALID_MAP);
255ef93cc38SKozlowski Mateusz }
256ef93cc38SKozlowski Mateusz 
2571738488eSArtur Paszkiewicz static void
2581738488eSArtur Paszkiewicz ftl_mngt_persist_p2l_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
2591738488eSArtur Paszkiewicz {
2601738488eSArtur Paszkiewicz 	/* Sync runtime P2L to persist any invalidation that may have happened */
2611738488eSArtur Paszkiewicz 
2621738488eSArtur Paszkiewicz 	struct ftl_p2l_sync_ctx *ctx = ftl_mngt_get_step_ctx(mngt);
2631738488eSArtur Paszkiewicz 
2641738488eSArtur Paszkiewicz 	/*
2651738488eSArtur Paszkiewicz 	 * ftl_mngt_persist_bands_p2l will increment the md_region before the step_continue for next regions
2661738488eSArtur Paszkiewicz 	 */
2671738488eSArtur Paszkiewicz 	if (ctx->md_region <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN) {
2681738488eSArtur Paszkiewicz 		ctx->md_region = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
2691738488eSArtur Paszkiewicz 	}
2701738488eSArtur Paszkiewicz 	ftl_mngt_persist_bands_p2l(mngt);
2711738488eSArtur Paszkiewicz }
2721738488eSArtur Paszkiewicz 
2739dbdb029SKozlowski Mateusz void
274ef93cc38SKozlowski Mateusz ftl_mngt_persist_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
2759dbdb029SKozlowski Mateusz {
2769dbdb029SKozlowski Mateusz 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
2779dbdb029SKozlowski Mateusz }
2789dbdb029SKozlowski Mateusz 
279b3e5d8a7SKozlowski Mateusz static void
280b3e5d8a7SKozlowski Mateusz ftl_mngt_persist_trim_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
281b3e5d8a7SKozlowski Mateusz {
282b3e5d8a7SKozlowski Mateusz 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_TRIM_MD);
283b3e5d8a7SKozlowski Mateusz }
284b3e5d8a7SKozlowski Mateusz 
285c6880a39SArtur Paszkiewicz static uint32_t
286c6880a39SArtur Paszkiewicz get_sb_crc(struct ftl_superblock *sb)
287c6880a39SArtur Paszkiewicz {
288c6880a39SArtur Paszkiewicz 	uint32_t crc = 0;
289c6880a39SArtur Paszkiewicz 
290c6880a39SArtur Paszkiewicz 	/* Calculate CRC excluding CRC field in superblock */
291c6880a39SArtur Paszkiewicz 	void *buffer = sb;
292c6880a39SArtur Paszkiewicz 	size_t offset = offsetof(struct ftl_superblock, header.crc);
293c6880a39SArtur Paszkiewicz 	size_t size = offset;
294c6880a39SArtur Paszkiewicz 	crc = spdk_crc32c_update(buffer, size, crc);
295c6880a39SArtur Paszkiewicz 
296c6880a39SArtur Paszkiewicz 	buffer += offset + sizeof(sb->header.crc);
297c8ab874dSKozlowski Mateusz 	if (sb->header.version > FTL_SB_VERSION_2) {
298c8ab874dSKozlowski Mateusz 		/* whole buf for v3 and on: */
299c6880a39SArtur Paszkiewicz 		size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc);
300c6880a39SArtur Paszkiewicz 		crc = spdk_crc32c_update(buffer, size, crc);
301c8ab874dSKozlowski Mateusz 	} else {
302c8ab874dSKozlowski Mateusz 		/* special for sb v2 only: */
303c8ab874dSKozlowski Mateusz 		size = sizeof(struct ftl_superblock_v2) - offset - sizeof(sb->header.crc);
304c8ab874dSKozlowski Mateusz 		sb->header.crc = spdk_crc32c_update(buffer, size, crc);
305c8ab874dSKozlowski Mateusz 	}
306c6880a39SArtur Paszkiewicz 
307c6880a39SArtur Paszkiewicz 	return crc;
308c6880a39SArtur Paszkiewicz }
309c6880a39SArtur Paszkiewicz 
310ef93cc38SKozlowski Mateusz static void
311ef93cc38SKozlowski Mateusz ftl_mngt_persist_super_block(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
312ef93cc38SKozlowski Mateusz {
313ef93cc38SKozlowski Mateusz 	dev->sb->overprovisioning = dev->conf.overprovisioning;
314ef93cc38SKozlowski Mateusz 	dev->sb->gc_info = dev->sb_shm->gc_info;
315ef93cc38SKozlowski Mateusz 	dev->sb->header.crc = get_sb_crc(dev->sb);
316ef93cc38SKozlowski Mateusz 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
317ef93cc38SKozlowski Mateusz }
318ef93cc38SKozlowski Mateusz 
319ef93cc38SKozlowski Mateusz /*
320ef93cc38SKozlowski Mateusz  * Persists all necessary metadata (band state, P2L, etc) during FTL's clean shutdown.
321ef93cc38SKozlowski Mateusz  */
322ef93cc38SKozlowski Mateusz static const struct ftl_mngt_process_desc desc_persist = {
323ef93cc38SKozlowski Mateusz 	.name = "Persist metadata",
324ef93cc38SKozlowski Mateusz 	.steps = {
325ef93cc38SKozlowski Mateusz 		{
326ef93cc38SKozlowski Mateusz 			.name = "Persist NV cache metadata",
327ef93cc38SKozlowski Mateusz 			.action = ftl_mngt_persist_nv_cache_metadata,
328ef93cc38SKozlowski Mateusz 		},
329ef93cc38SKozlowski Mateusz 		{
330ef93cc38SKozlowski Mateusz 			.name = "Persist valid map metadata",
331ef93cc38SKozlowski Mateusz 			.action = ftl_mngt_persist_vld_map_metadata,
332ef93cc38SKozlowski Mateusz 		},
333ef93cc38SKozlowski Mateusz 		{
3341738488eSArtur Paszkiewicz 			.name = "Persist P2L metadata",
3351738488eSArtur Paszkiewicz 			.action = ftl_mngt_persist_p2l_metadata,
3361738488eSArtur Paszkiewicz 			.ctx_size = sizeof(struct ftl_p2l_sync_ctx),
3371738488eSArtur Paszkiewicz 		},
3381738488eSArtur Paszkiewicz 		{
3391c73a5c3SMateusz Kozlowski 			.name = "Persist band info metadata",
340ef93cc38SKozlowski Mateusz 			.action = ftl_mngt_persist_band_info_metadata,
341ef93cc38SKozlowski Mateusz 		},
342ef93cc38SKozlowski Mateusz 		{
3431c73a5c3SMateusz Kozlowski 			.name = "Persist trim metadata",
344b3e5d8a7SKozlowski Mateusz 			.action = ftl_mngt_persist_trim_metadata,
345b3e5d8a7SKozlowski Mateusz 		},
346b3e5d8a7SKozlowski Mateusz 		{
347ef93cc38SKozlowski Mateusz 			.name = "Persist superblock",
348ef93cc38SKozlowski Mateusz 			.action = ftl_mngt_persist_super_block,
349ef93cc38SKozlowski Mateusz 		},
350ef93cc38SKozlowski Mateusz 		{}
351ef93cc38SKozlowski Mateusz 	}
352ef93cc38SKozlowski Mateusz };
353ef93cc38SKozlowski Mateusz 
354ef93cc38SKozlowski Mateusz void
355ef93cc38SKozlowski Mateusz ftl_mngt_persist_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
356ef93cc38SKozlowski Mateusz {
3579452abe6SMateusz Kozlowski 	ftl_mngt_call_process(mngt, &desc_persist, NULL);
358ef93cc38SKozlowski Mateusz }
359ef93cc38SKozlowski Mateusz 
360b5e2c59aSKozlowski Mateusz /*
3613f912cf0SMichal Berger  * Fast clean shutdown path - skips the persistence of most metadata regions and
362b5e2c59aSKozlowski Mateusz  * relies on their shared memory state instead.
363b5e2c59aSKozlowski Mateusz  */
364b5e2c59aSKozlowski Mateusz static const struct ftl_mngt_process_desc desc_fast_persist = {
365b5e2c59aSKozlowski Mateusz 	.name = "Fast persist metadata",
366b5e2c59aSKozlowski Mateusz 	.steps = {
367b5e2c59aSKozlowski Mateusz 		{
368b5e2c59aSKozlowski Mateusz 			.name = "Fast persist NV cache metadata",
369b5e2c59aSKozlowski Mateusz 			.action = ftl_mngt_fast_persist_nv_cache_metadata,
370b5e2c59aSKozlowski Mateusz 		},
371b5e2c59aSKozlowski Mateusz 		{}
372b5e2c59aSKozlowski Mateusz 	}
373b5e2c59aSKozlowski Mateusz };
374b5e2c59aSKozlowski Mateusz 
375b5e2c59aSKozlowski Mateusz void
376b5e2c59aSKozlowski Mateusz ftl_mngt_fast_persist_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
377b5e2c59aSKozlowski Mateusz {
3789452abe6SMateusz Kozlowski 	ftl_mngt_call_process(mngt, &desc_fast_persist, NULL);
379b5e2c59aSKozlowski Mateusz }
380b5e2c59aSKozlowski Mateusz 
381c6880a39SArtur Paszkiewicz void
382c6880a39SArtur Paszkiewicz ftl_mngt_init_default_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
383c6880a39SArtur Paszkiewicz {
384c6880a39SArtur Paszkiewicz 	struct ftl_superblock *sb = dev->sb;
385c6880a39SArtur Paszkiewicz 
386c6880a39SArtur Paszkiewicz 	sb->header.magic = FTL_SUPERBLOCK_MAGIC;
387c8ab874dSKozlowski Mateusz 	sb->header.version = FTL_SB_VERSION_CURRENT;
388c6880a39SArtur Paszkiewicz 	sb->uuid = dev->conf.uuid;
389c6880a39SArtur Paszkiewicz 	sb->clean = 0;
390f45c0075SArtur Paszkiewicz 	dev->sb_shm->shm_clean = false;
3911738488eSArtur Paszkiewicz 	sb->ckpt_seq_id = 0;
392c6880a39SArtur Paszkiewicz 
393c6880a39SArtur Paszkiewicz 	/* Max 16 IO depth per band relocate */
394c6880a39SArtur Paszkiewicz 	sb->max_reloc_qdepth = 16;
395c6880a39SArtur Paszkiewicz 
396c6880a39SArtur Paszkiewicz 	sb->overprovisioning = dev->conf.overprovisioning;
397c6880a39SArtur Paszkiewicz 
398711759a0SKozlowski Mateusz 	ftl_band_init_gc_iter(dev);
399711759a0SKozlowski Mateusz 
400c6880a39SArtur Paszkiewicz 	/* md layout isn't initialized yet.
401c6880a39SArtur Paszkiewicz 	 * empty region list => all regions in the default location */
4029f42898aSLukasz Lasek 	spdk_strcpy_pad(sb->base_dev_name, dev->base_type->name,
4039f42898aSLukasz Lasek 			SPDK_COUNTOF(sb->base_dev_name), '\0');
4049f42898aSLukasz Lasek 	sb->md_layout_base.df_id = FTL_DF_OBJ_ID_INVALID;
4059f42898aSLukasz Lasek 
40626f3b551SMateusz Kozlowski 	spdk_strcpy_pad(sb->nvc_dev_name, dev->nv_cache.nvc_type->name,
4079f42898aSLukasz Lasek 			SPDK_COUNTOF(sb->nvc_dev_name), '\0');
4089f42898aSLukasz Lasek 	sb->md_layout_nvc.df_id = FTL_DF_OBJ_ID_INVALID;
409c6880a39SArtur Paszkiewicz 
410c6880a39SArtur Paszkiewicz 	sb->header.crc = get_sb_crc(sb);
411c6880a39SArtur Paszkiewicz 
412c6880a39SArtur Paszkiewicz 	ftl_mngt_next_step(mngt);
413c6880a39SArtur Paszkiewicz }
414c6880a39SArtur Paszkiewicz 
415c6880a39SArtur Paszkiewicz void
416c6880a39SArtur Paszkiewicz ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
417c6880a39SArtur Paszkiewicz {
418c6880a39SArtur Paszkiewicz 	struct ftl_superblock *sb = dev->sb;
419c6880a39SArtur Paszkiewicz 
420c6880a39SArtur Paszkiewicz 	sb->clean = 0;
421d4a2d28dSMateusz Kozlowski 	sb->upgrade_ready = false;
422f45c0075SArtur Paszkiewicz 	dev->sb_shm->shm_clean = false;
423c6880a39SArtur Paszkiewicz 	sb->header.crc = get_sb_crc(sb);
424c6880a39SArtur Paszkiewicz 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
425c6880a39SArtur Paszkiewicz }
426c6880a39SArtur Paszkiewicz 
427ef93cc38SKozlowski Mateusz void
428ef93cc38SKozlowski Mateusz ftl_mngt_set_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
429ef93cc38SKozlowski Mateusz {
430ef93cc38SKozlowski Mateusz 	struct ftl_superblock *sb = dev->sb;
431ef93cc38SKozlowski Mateusz 
432ef93cc38SKozlowski Mateusz 	sb->clean = 1;
433d4a2d28dSMateusz Kozlowski 	sb->upgrade_ready = dev->conf.prep_upgrade_on_shutdown;
434ef93cc38SKozlowski Mateusz 	dev->sb_shm->shm_clean = false;
435ef93cc38SKozlowski Mateusz 	sb->header.crc = get_sb_crc(sb);
436ef93cc38SKozlowski Mateusz 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
437ef93cc38SKozlowski Mateusz 
438ef93cc38SKozlowski Mateusz 	dev->sb_shm->shm_ready = false;
439ef93cc38SKozlowski Mateusz }
440ef93cc38SKozlowski Mateusz 
441b5e2c59aSKozlowski Mateusz void
442b5e2c59aSKozlowski Mateusz ftl_mngt_set_shm_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
443b5e2c59aSKozlowski Mateusz {
444b5e2c59aSKozlowski Mateusz 	struct ftl_superblock *sb = dev->sb;
445b5e2c59aSKozlowski Mateusz 
446b5e2c59aSKozlowski Mateusz 	sb->clean = 1;
447b5e2c59aSKozlowski Mateusz 	dev->sb_shm->shm_clean = true;
448b5e2c59aSKozlowski Mateusz 	sb->header.crc = get_sb_crc(sb);
449b5e2c59aSKozlowski Mateusz 	ftl_mngt_next_step(mngt);
450b5e2c59aSKozlowski Mateusz }
451b5e2c59aSKozlowski Mateusz 
452cbd7ae6dSKozlowski Mateusz void
453cbd7ae6dSKozlowski Mateusz ftl_mngt_load_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
454cbd7ae6dSKozlowski Mateusz {
455cbd7ae6dSKozlowski Mateusz 	FTL_NOTICELOG(dev, "SHM: clean %"PRIu64", shm_clean %d\n", dev->sb->clean, dev->sb_shm->shm_clean);
456cbd7ae6dSKozlowski Mateusz 
457cbd7ae6dSKozlowski Mateusz 	if (!ftl_fast_startup(dev)) {
458cbd7ae6dSKozlowski Mateusz 		restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
459cbd7ae6dSKozlowski Mateusz 		return;
460cbd7ae6dSKozlowski Mateusz 	}
461cbd7ae6dSKozlowski Mateusz 
462cbd7ae6dSKozlowski Mateusz 	FTL_DEBUGLOG(dev, "SHM: found SB\n");
463cbd7ae6dSKozlowski Mateusz 	if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_SB)) {
464cbd7ae6dSKozlowski Mateusz 		ftl_mngt_fail_step(mngt);
465cbd7ae6dSKozlowski Mateusz 		return;
466cbd7ae6dSKozlowski Mateusz 	}
467cbd7ae6dSKozlowski Mateusz 	ftl_mngt_next_step(mngt);
468cbd7ae6dSKozlowski Mateusz }
469cbd7ae6dSKozlowski Mateusz 
470cbd7ae6dSKozlowski Mateusz void
471cbd7ae6dSKozlowski Mateusz ftl_mngt_validate_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
472cbd7ae6dSKozlowski Mateusz {
473cbd7ae6dSKozlowski Mateusz 	struct ftl_superblock *sb = dev->sb;
474cbd7ae6dSKozlowski Mateusz 
475cbd7ae6dSKozlowski Mateusz 	if (!ftl_superblock_check_magic(sb)) {
476cbd7ae6dSKozlowski Mateusz 		FTL_ERRLOG(dev, "Invalid FTL superblock magic\n");
477cbd7ae6dSKozlowski Mateusz 		ftl_mngt_fail_step(mngt);
478cbd7ae6dSKozlowski Mateusz 		return;
479cbd7ae6dSKozlowski Mateusz 	}
480cbd7ae6dSKozlowski Mateusz 
481cbd7ae6dSKozlowski Mateusz 	if (sb->header.crc != get_sb_crc(sb)) {
482cbd7ae6dSKozlowski Mateusz 		FTL_ERRLOG(dev, "Invalid FTL superblock CRC\n");
483cbd7ae6dSKozlowski Mateusz 		ftl_mngt_fail_step(mngt);
484cbd7ae6dSKozlowski Mateusz 		return;
485cbd7ae6dSKozlowski Mateusz 	}
486cbd7ae6dSKozlowski Mateusz 
487d748bc41SKozlowski Mateusz 	if (ftl_superblock_upgrade(dev)) {
488d748bc41SKozlowski Mateusz 		FTL_ERRLOG(dev, "FTL superblock dirty or invalid version\n");
489d748bc41SKozlowski Mateusz 		ftl_mngt_fail_step(mngt);
490d748bc41SKozlowski Mateusz 		return;
491d748bc41SKozlowski Mateusz 	}
492d748bc41SKozlowski Mateusz 
493cbd7ae6dSKozlowski Mateusz 	if (spdk_uuid_compare(&sb->uuid, &dev->conf.uuid) != 0) {
494cbd7ae6dSKozlowski Mateusz 		FTL_ERRLOG(dev, "Invalid FTL superblock UUID\n");
495cbd7ae6dSKozlowski Mateusz 		ftl_mngt_fail_step(mngt);
496cbd7ae6dSKozlowski Mateusz 		return;
497cbd7ae6dSKozlowski Mateusz 	}
498cbd7ae6dSKozlowski Mateusz 
499cbd7ae6dSKozlowski Mateusz 	if (sb->lba_cnt == 0) {
500cbd7ae6dSKozlowski Mateusz 		FTL_ERRLOG(dev, "Invalid FTL superblock lba_cnt\n");
501cbd7ae6dSKozlowski Mateusz 		ftl_mngt_fail_step(mngt);
502cbd7ae6dSKozlowski Mateusz 		return;
503cbd7ae6dSKozlowski Mateusz 	}
504cbd7ae6dSKozlowski Mateusz 	dev->num_lbas = sb->lba_cnt;
505cbd7ae6dSKozlowski Mateusz 
506cbd7ae6dSKozlowski Mateusz 	/* The sb has just been read. Validate and update the conf */
507cbd7ae6dSKozlowski Mateusz 	if (sb->overprovisioning == 0 || sb->overprovisioning >= 100) {
508cbd7ae6dSKozlowski Mateusz 		FTL_ERRLOG(dev, "Invalid FTL superblock lba_rsvd\n");
509cbd7ae6dSKozlowski Mateusz 		ftl_mngt_fail_step(mngt);
510cbd7ae6dSKozlowski Mateusz 		return;
511cbd7ae6dSKozlowski Mateusz 	}
512cbd7ae6dSKozlowski Mateusz 	dev->conf.overprovisioning = sb->overprovisioning;
513cbd7ae6dSKozlowski Mateusz 
5149f42898aSLukasz Lasek 	if (!ftl_superblock_validate_blob_area(dev)) {
5159f42898aSLukasz Lasek 		FTL_ERRLOG(dev, "Corrupted FTL superblock blob area\n");
5169f42898aSLukasz Lasek 		ftl_mngt_fail_step(mngt);
5179f42898aSLukasz Lasek 		return;
5189f42898aSLukasz Lasek 	}
5199f42898aSLukasz Lasek 
520cbd7ae6dSKozlowski Mateusz 	ftl_mngt_next_step(mngt);
521cbd7ae6dSKozlowski Mateusz }
522cbd7ae6dSKozlowski Mateusz 
523cbd7ae6dSKozlowski Mateusz /*
524cbd7ae6dSKozlowski Mateusz  * Loads and verifies superblock contents - utilized during the load of an FTL
525cbd7ae6dSKozlowski Mateusz  * instance (both from a clean and dirty shutdown).
526cbd7ae6dSKozlowski Mateusz  */
527cbd7ae6dSKozlowski Mateusz static const struct ftl_mngt_process_desc desc_restore_sb = {
528cbd7ae6dSKozlowski Mateusz 	.name = "SB restore",
529cbd7ae6dSKozlowski Mateusz 	.steps = {
530cbd7ae6dSKozlowski Mateusz 		{
531cbd7ae6dSKozlowski Mateusz 			.name = "Load super block",
532cbd7ae6dSKozlowski Mateusz 			.action = ftl_mngt_load_sb
533cbd7ae6dSKozlowski Mateusz 		},
534cbd7ae6dSKozlowski Mateusz 		{
535cbd7ae6dSKozlowski Mateusz 			.name = "Validate super block",
536cbd7ae6dSKozlowski Mateusz 			.action = ftl_mngt_validate_sb
537cbd7ae6dSKozlowski Mateusz 		},
538cbd7ae6dSKozlowski Mateusz 		{}
539cbd7ae6dSKozlowski Mateusz 	}
540cbd7ae6dSKozlowski Mateusz };
541cbd7ae6dSKozlowski Mateusz 
542c6880a39SArtur Paszkiewicz /*
543c6880a39SArtur Paszkiewicz  * Initializes the superblock fields during first startup of FTL
544c6880a39SArtur Paszkiewicz  */
545c6880a39SArtur Paszkiewicz static const struct ftl_mngt_process_desc desc_init_sb = {
546c6880a39SArtur Paszkiewicz 	.name = "SB initialize",
547c6880a39SArtur Paszkiewicz 	.steps = {
548c6880a39SArtur Paszkiewicz 		{
549c6880a39SArtur Paszkiewicz 			.name = "Default-initialize superblock",
550c6880a39SArtur Paszkiewicz 			.action = ftl_mngt_init_default_sb,
551c6880a39SArtur Paszkiewicz 		},
552c6880a39SArtur Paszkiewicz 		{}
553c6880a39SArtur Paszkiewicz 	}
554c6880a39SArtur Paszkiewicz };
555c6880a39SArtur Paszkiewicz 
556c6880a39SArtur Paszkiewicz void
557c6880a39SArtur Paszkiewicz ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
558c6880a39SArtur Paszkiewicz {
559522a0c82SLukasz Lasek 	struct ftl_md *md;
560522a0c82SLukasz Lasek 	struct ftl_md *md_mirror;
561c6880a39SArtur Paszkiewicz 	struct ftl_layout *layout = &dev->layout;
562c6880a39SArtur Paszkiewicz 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
563c6880a39SArtur Paszkiewicz 	char uuid[SPDK_UUID_STRING_LEN];
5641e904e2bSArtur Paszkiewicz 	int md_create_flags = ftl_md_create_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB);
565c6880a39SArtur Paszkiewicz 
566c6880a39SArtur Paszkiewicz 	/* Must generate UUID before MD create on SHM for the SB */
567c6880a39SArtur Paszkiewicz 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
568c6880a39SArtur Paszkiewicz 		spdk_uuid_generate(&dev->conf.uuid);
569c6880a39SArtur Paszkiewicz 		spdk_uuid_fmt_lower(uuid, sizeof(uuid), &dev->conf.uuid);
570c6880a39SArtur Paszkiewicz 		FTL_NOTICELOG(dev, "Create new FTL, UUID %s\n", uuid);
571c6880a39SArtur Paszkiewicz 	}
572c6880a39SArtur Paszkiewicz 
5731e904e2bSArtur Paszkiewicz shm_retry:
574f45c0075SArtur Paszkiewicz 	/* Allocate md buf */
575f45c0075SArtur Paszkiewicz 	dev->sb_shm = NULL;
576f45c0075SArtur Paszkiewicz 	dev->sb_shm_md = ftl_md_create(dev, spdk_divide_round_up(sizeof(*dev->sb_shm), FTL_BLOCK_SIZE),
577f45c0075SArtur Paszkiewicz 				       0, "sb_shm",
578f45c0075SArtur Paszkiewicz 				       md_create_flags, NULL);
579f45c0075SArtur Paszkiewicz 	if (dev->sb_shm_md == NULL) {
5801e904e2bSArtur Paszkiewicz 		/* The first attempt may fail when trying to open SHM - try to create new */
5811e904e2bSArtur Paszkiewicz 		if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
5821e904e2bSArtur Paszkiewicz 			md_create_flags |= FTL_MD_CREATE_SHM_NEW;
5831e904e2bSArtur Paszkiewicz 			goto shm_retry;
5841e904e2bSArtur Paszkiewicz 		}
5851e904e2bSArtur Paszkiewicz 		if (dev->sb_shm_md == NULL) {
586f45c0075SArtur Paszkiewicz 			ftl_mngt_fail_step(mngt);
587f45c0075SArtur Paszkiewicz 			return;
588f45c0075SArtur Paszkiewicz 		}
5891e904e2bSArtur Paszkiewicz 	}
590f45c0075SArtur Paszkiewicz 
591f45c0075SArtur Paszkiewicz 	dev->sb_shm = ftl_md_get_buffer(dev->sb_shm_md);
592f45c0075SArtur Paszkiewicz 
593c6880a39SArtur Paszkiewicz 	/* Setup the layout of a superblock */
594c6880a39SArtur Paszkiewicz 	if (ftl_layout_setup_superblock(dev)) {
595c6880a39SArtur Paszkiewicz 		ftl_mngt_fail_step(mngt);
596c6880a39SArtur Paszkiewicz 		return;
597c6880a39SArtur Paszkiewicz 	}
598c6880a39SArtur Paszkiewicz 
599c6880a39SArtur Paszkiewicz 	/* Allocate md buf */
600c6880a39SArtur Paszkiewicz 	layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks,
601818b9c05SArtur Paszkiewicz 						region->vss_blksz, region->name,
602818b9c05SArtur Paszkiewicz 						md_create_flags, region);
603c6880a39SArtur Paszkiewicz 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
6041e904e2bSArtur Paszkiewicz 		/* The first attempt may fail when trying to open SHM - try to create new */
6051e904e2bSArtur Paszkiewicz 		if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
6061e904e2bSArtur Paszkiewicz 			md_create_flags |= FTL_MD_CREATE_SHM_NEW;
6071e904e2bSArtur Paszkiewicz 			ftl_md_destroy(dev->sb_shm_md, 0);
6086a26cb60SKozlowski Mateusz 			dev->sb_shm_md = NULL;
6099f42898aSLukasz Lasek 			if (ftl_layout_clear_superblock(dev)) {
6109f42898aSLukasz Lasek 				ftl_mngt_fail_step(mngt);
6119f42898aSLukasz Lasek 				return;
6129f42898aSLukasz Lasek 			}
6131e904e2bSArtur Paszkiewicz 			goto shm_retry;
6141e904e2bSArtur Paszkiewicz 		}
615c6880a39SArtur Paszkiewicz 		ftl_mngt_fail_step(mngt);
616c6880a39SArtur Paszkiewicz 		return;
617c6880a39SArtur Paszkiewicz 	}
618c6880a39SArtur Paszkiewicz 
619c6880a39SArtur Paszkiewicz 	/* Link the md buf to the device */
620c6880a39SArtur Paszkiewicz 	dev->sb = ftl_md_get_buffer(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
621c6880a39SArtur Paszkiewicz 
622c6880a39SArtur Paszkiewicz 	/* Setup superblock mirror to QLC */
623c6880a39SArtur Paszkiewicz 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
624c6880a39SArtur Paszkiewicz 	layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks,
625522a0c82SLukasz Lasek 			region->vss_blksz, NULL, FTL_MD_CREATE_NO_MEM, region);
626c6880a39SArtur Paszkiewicz 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
627c6880a39SArtur Paszkiewicz 		ftl_mngt_fail_step(mngt);
628c6880a39SArtur Paszkiewicz 		return;
629c6880a39SArtur Paszkiewicz 	}
630c6880a39SArtur Paszkiewicz 
631522a0c82SLukasz Lasek 	/* Initialize mirror region buffer */
632522a0c82SLukasz Lasek 	md = layout->md[FTL_LAYOUT_REGION_TYPE_SB];
633522a0c82SLukasz Lasek 	md_mirror = layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE];
634522a0c82SLukasz Lasek 
635522a0c82SLukasz Lasek 	md_mirror->dev = md->dev;
636522a0c82SLukasz Lasek 	md_mirror->data_blocks = md->data_blocks;
637522a0c82SLukasz Lasek 	md_mirror->data = md->data;
638522a0c82SLukasz Lasek 	md_mirror->is_mirror = true;
639522a0c82SLukasz Lasek 
640c6880a39SArtur Paszkiewicz 	/* Initialize the superblock */
641c6880a39SArtur Paszkiewicz 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
6429452abe6SMateusz Kozlowski 		ftl_mngt_call_process(mngt, &desc_init_sb, NULL);
643c6880a39SArtur Paszkiewicz 	} else {
6449452abe6SMateusz Kozlowski 		ftl_mngt_call_process(mngt, &desc_restore_sb, NULL);
645c6880a39SArtur Paszkiewicz 	}
646c6880a39SArtur Paszkiewicz }
647c6880a39SArtur Paszkiewicz 
648c6880a39SArtur Paszkiewicz void
649c6880a39SArtur Paszkiewicz ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
650c6880a39SArtur Paszkiewicz {
651c6880a39SArtur Paszkiewicz 	struct ftl_layout *layout = &dev->layout;
652c6880a39SArtur Paszkiewicz 
653c6880a39SArtur Paszkiewicz 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
6540e33da49SKozlowski Mateusz 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB],
6550e33da49SKozlowski Mateusz 			       ftl_md_destroy_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB));
656c6880a39SArtur Paszkiewicz 		layout->md[FTL_LAYOUT_REGION_TYPE_SB] = NULL;
657c6880a39SArtur Paszkiewicz 	}
658c6880a39SArtur Paszkiewicz 
659c6880a39SArtur Paszkiewicz 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
6600e33da49SKozlowski Mateusz 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE], 0);
661c6880a39SArtur Paszkiewicz 		layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = NULL;
662c6880a39SArtur Paszkiewicz 	}
663c6880a39SArtur Paszkiewicz 
6640e33da49SKozlowski Mateusz 	ftl_md_destroy(dev->sb_shm_md, ftl_md_destroy_shm_flags(dev));
665f45c0075SArtur Paszkiewicz 	dev->sb_shm_md = NULL;
666f45c0075SArtur Paszkiewicz 	dev->sb_shm = NULL;
667f45c0075SArtur Paszkiewicz 
668c6880a39SArtur Paszkiewicz 	ftl_mngt_next_step(mngt);
669c6880a39SArtur Paszkiewicz }
670cbd7ae6dSKozlowski Mateusz 
671cbd7ae6dSKozlowski Mateusz static void
672cbd7ae6dSKozlowski Mateusz ftl_mngt_restore_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
673cbd7ae6dSKozlowski Mateusz {
674cbd7ae6dSKozlowski Mateusz 	if (ftl_fast_startup(dev)) {
675cbd7ae6dSKozlowski Mateusz 		FTL_DEBUGLOG(dev, "SHM: found nv cache md\n");
676cbd7ae6dSKozlowski Mateusz 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD)) {
677cbd7ae6dSKozlowski Mateusz 			ftl_mngt_fail_step(mngt);
678cbd7ae6dSKozlowski Mateusz 			return;
679cbd7ae6dSKozlowski Mateusz 		}
680cbd7ae6dSKozlowski Mateusz 		ftl_mngt_next_step(mngt);
681cbd7ae6dSKozlowski Mateusz 		return;
682cbd7ae6dSKozlowski Mateusz 	}
683cbd7ae6dSKozlowski Mateusz 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
684cbd7ae6dSKozlowski Mateusz }
685cbd7ae6dSKozlowski Mateusz 
686cbd7ae6dSKozlowski Mateusz static void
687cbd7ae6dSKozlowski Mateusz ftl_mngt_restore_vld_map_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
688cbd7ae6dSKozlowski Mateusz {
689cbd7ae6dSKozlowski Mateusz 	if (ftl_fast_startup(dev)) {
690cbd7ae6dSKozlowski Mateusz 		FTL_DEBUGLOG(dev, "SHM: found vldmap\n");
691cbd7ae6dSKozlowski Mateusz 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP)) {
692cbd7ae6dSKozlowski Mateusz 			ftl_mngt_fail_step(mngt);
693cbd7ae6dSKozlowski Mateusz 			return;
694cbd7ae6dSKozlowski Mateusz 		}
695cbd7ae6dSKozlowski Mateusz 		ftl_mngt_next_step(mngt);
696cbd7ae6dSKozlowski Mateusz 		return;
697cbd7ae6dSKozlowski Mateusz 	}
698cbd7ae6dSKozlowski Mateusz 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_VALID_MAP);
699cbd7ae6dSKozlowski Mateusz }
700cbd7ae6dSKozlowski Mateusz 
701cbd7ae6dSKozlowski Mateusz static void
702cbd7ae6dSKozlowski Mateusz ftl_mngt_restore_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
703cbd7ae6dSKozlowski Mateusz {
704cbd7ae6dSKozlowski Mateusz 	if (ftl_fast_startup(dev)) {
705cbd7ae6dSKozlowski Mateusz 		FTL_DEBUGLOG(dev, "SHM: found band md\n");
706cbd7ae6dSKozlowski Mateusz 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD)) {
707cbd7ae6dSKozlowski Mateusz 			ftl_mngt_fail_step(mngt);
708cbd7ae6dSKozlowski Mateusz 			return;
709cbd7ae6dSKozlowski Mateusz 		}
710cbd7ae6dSKozlowski Mateusz 		ftl_mngt_next_step(mngt);
711cbd7ae6dSKozlowski Mateusz 		return;
712cbd7ae6dSKozlowski Mateusz 	}
713cbd7ae6dSKozlowski Mateusz 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
714cbd7ae6dSKozlowski Mateusz }
715cbd7ae6dSKozlowski Mateusz 
716b3e5d8a7SKozlowski Mateusz static void
717b3e5d8a7SKozlowski Mateusz ftl_mngt_restore_trim_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
718b3e5d8a7SKozlowski Mateusz {
719b3e5d8a7SKozlowski Mateusz 	if (ftl_fast_startup(dev)) {
720b3e5d8a7SKozlowski Mateusz 		FTL_DEBUGLOG(dev, "SHM: found trim md\n");
721b3e5d8a7SKozlowski Mateusz 		if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD)) {
722b3e5d8a7SKozlowski Mateusz 			ftl_mngt_fail_step(mngt);
723b3e5d8a7SKozlowski Mateusz 			return;
724b3e5d8a7SKozlowski Mateusz 		}
725b3e5d8a7SKozlowski Mateusz 		ftl_mngt_next_step(mngt);
726b3e5d8a7SKozlowski Mateusz 		return;
727b3e5d8a7SKozlowski Mateusz 	}
728b3e5d8a7SKozlowski Mateusz 	restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_TRIM_MD);
729b3e5d8a7SKozlowski Mateusz }
730b3e5d8a7SKozlowski Mateusz 
731cbd7ae6dSKozlowski Mateusz /*
732cbd7ae6dSKozlowski Mateusz  * Loads metadata after a clean shutdown.
733cbd7ae6dSKozlowski Mateusz  */
734cbd7ae6dSKozlowski Mateusz static const struct ftl_mngt_process_desc desc_restore = {
735cbd7ae6dSKozlowski Mateusz 	.name = "Restore metadata",
736cbd7ae6dSKozlowski Mateusz 	.steps = {
737cbd7ae6dSKozlowski Mateusz 		{
738cbd7ae6dSKozlowski Mateusz 			.name = "Restore NV cache metadata",
739cbd7ae6dSKozlowski Mateusz 			.action = ftl_mngt_restore_nv_cache_metadata,
740cbd7ae6dSKozlowski Mateusz 		},
741cbd7ae6dSKozlowski Mateusz 		{
742cbd7ae6dSKozlowski Mateusz 			.name = "Restore valid map metadata",
743cbd7ae6dSKozlowski Mateusz 			.action = ftl_mngt_restore_vld_map_metadata,
744cbd7ae6dSKozlowski Mateusz 		},
745cbd7ae6dSKozlowski Mateusz 		{
746cbd7ae6dSKozlowski Mateusz 			.name = "Restore band info metadata",
747cbd7ae6dSKozlowski Mateusz 			.action = ftl_mngt_restore_band_info_metadata,
748cbd7ae6dSKozlowski Mateusz 		},
749b3e5d8a7SKozlowski Mateusz 		{
750b3e5d8a7SKozlowski Mateusz 			.name = "Restore trim metadata",
751b3e5d8a7SKozlowski Mateusz 			.action = ftl_mngt_restore_trim_metadata,
752b3e5d8a7SKozlowski Mateusz 		},
753cbd7ae6dSKozlowski Mateusz 		{}
754cbd7ae6dSKozlowski Mateusz 	}
755cbd7ae6dSKozlowski Mateusz };
756cbd7ae6dSKozlowski Mateusz 
757cbd7ae6dSKozlowski Mateusz void
758cbd7ae6dSKozlowski Mateusz ftl_mngt_restore_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
759cbd7ae6dSKozlowski Mateusz {
7609452abe6SMateusz Kozlowski 	ftl_mngt_call_process(mngt, &desc_restore, NULL);
761cbd7ae6dSKozlowski Mateusz }
7627ff28519SKozlowski Mateusz 
7637ff28519SKozlowski Mateusz void
7647ff28519SKozlowski Mateusz ftl_mngt_persist_superblock(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
7657ff28519SKozlowski Mateusz {
7667ff28519SKozlowski Mateusz 	dev->sb->header.crc = get_sb_crc(dev->sb);
7677ff28519SKozlowski Mateusz 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
7687ff28519SKozlowski Mateusz }
769