xref: /spdk/lib/ftl/mngt/ftl_mngt_md.c (revision fa09c9ac9b0ce66dcacb64b02aae778014b6c2b3)
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_internal.h"
14 #include "ftl_sb.h"
15 
16 void
17 ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
18 {
19 	if (ftl_layout_setup(dev)) {
20 		ftl_mngt_fail_step(mngt);
21 	} else {
22 		ftl_mngt_next_step(mngt);
23 	}
24 }
25 
26 static bool
27 is_buffer_needed(enum ftl_layout_region_type type)
28 {
29 	switch (type) {
30 #ifdef SPDK_FTL_VSS_EMU
31 	case FTL_LAYOUT_REGION_TYPE_VSS:
32 #endif
33 	case FTL_LAYOUT_REGION_TYPE_SB:
34 	case FTL_LAYOUT_REGION_TYPE_SB_BASE:
35 	case FTL_LAYOUT_REGION_TYPE_DATA_NVC:
36 	case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
37 		return false;
38 
39 	default:
40 		return true;
41 	}
42 }
43 
44 void
45 ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
46 {
47 	struct ftl_layout *layout = &dev->layout;
48 	struct ftl_layout_region *region = layout->region;
49 	uint64_t i;
50 
51 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) {
52 		if (layout->md[i]) {
53 			/*
54 			 * Some metadata objects are initialized by other FTL
55 			 * components. At the moment it's only used by superblock (and its mirror) -
56 			 * during load time we need to read it earlier in order to get the layout for the
57 			 * other regions.
58 			 */
59 			continue;
60 		}
61 		layout->md[i] = ftl_md_create(dev, region->current.blocks, region->vss_blksz, region->name,
62 					      !is_buffer_needed(i), region);
63 		if (NULL == layout->md[i]) {
64 			ftl_mngt_fail_step(mngt);
65 			return;
66 		}
67 	}
68 
69 	ftl_mngt_next_step(mngt);
70 }
71 
72 void
73 ftl_mngt_deinit_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
74 {
75 	struct ftl_layout *layout = &dev->layout;
76 	struct ftl_layout_region *region = layout->region;
77 	uint64_t i;
78 
79 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++, region++) {
80 		if (layout->md[i]) {
81 			ftl_md_destroy(layout->md[i]);
82 			layout->md[i] = NULL;
83 		}
84 	}
85 
86 	ftl_mngt_next_step(mngt);
87 }
88 
89 static void
90 persist_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
91 {
92 	struct ftl_mngt_process *mngt = md->owner.cb_ctx;
93 
94 	if (status) {
95 		ftl_mngt_fail_step(mngt);
96 	} else {
97 		ftl_mngt_next_step(mngt);
98 	}
99 }
100 
101 static void
102 persist(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
103 	enum ftl_layout_region_type type)
104 {
105 	struct ftl_layout *layout = &dev->layout;
106 	struct ftl_md *md = layout->md[type];
107 
108 	assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
109 
110 	if (!md) {
111 		ftl_mngt_fail_step(mngt);
112 		return;
113 	}
114 
115 	md->owner.cb_ctx = mngt;
116 	md->cb = persist_cb;
117 	ftl_md_persist(md);
118 }
119 
120 static uint32_t
121 get_sb_crc(struct ftl_superblock *sb)
122 {
123 	uint32_t crc = 0;
124 
125 	/* Calculate CRC excluding CRC field in superblock */
126 	void *buffer = sb;
127 	size_t offset = offsetof(struct ftl_superblock, header.crc);
128 	size_t size = offset;
129 	crc = spdk_crc32c_update(buffer, size, crc);
130 
131 	buffer += offset + sizeof(sb->header.crc);
132 	size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc);
133 	crc = spdk_crc32c_update(buffer, size, crc);
134 
135 	return crc;
136 }
137 
138 void
139 ftl_mngt_init_default_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
140 {
141 	struct ftl_superblock *sb = dev->sb;
142 
143 	sb->header.magic = FTL_SUPERBLOCK_MAGIC;
144 	sb->header.version = FTL_METADATA_VERSION_CURRENT;
145 	sb->uuid = dev->conf.uuid;
146 	sb->clean = 0;
147 
148 	/* Max 16 IO depth per band relocate */
149 	sb->max_reloc_qdepth = 16;
150 
151 	sb->overprovisioning = dev->conf.overprovisioning;
152 
153 	/* md layout isn't initialized yet.
154 	 * empty region list => all regions in the default location */
155 	sb->md_layout_head.type = FTL_LAYOUT_REGION_TYPE_INVALID;
156 
157 	sb->header.crc = get_sb_crc(sb);
158 
159 	ftl_mngt_next_step(mngt);
160 }
161 
162 void
163 ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
164 {
165 	struct ftl_superblock *sb = dev->sb;
166 
167 	sb->clean = 0;
168 	sb->header.crc = get_sb_crc(sb);
169 	persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
170 }
171 
172 /*
173  * Initializes the superblock fields during first startup of FTL
174  */
175 static const struct ftl_mngt_process_desc desc_init_sb = {
176 	.name = "SB initialize",
177 	.steps = {
178 		{
179 			.name = "Default-initialize superblock",
180 			.action = ftl_mngt_init_default_sb,
181 		},
182 		{}
183 	}
184 };
185 
186 #ifdef SPDK_FTL_VSS_EMU
187 void
188 ftl_mngt_md_init_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
189 {
190 	struct ftl_layout *layout = &dev->layout;
191 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_VSS];
192 
193 	/* Initialize VSS layout */
194 	ftl_layout_setup_vss_emu(dev);
195 
196 	/* Allocate md buf */
197 	layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = ftl_md_create(dev, region->current.blocks,
198 			region->vss_blksz, NULL, 0, region);
199 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
200 		ftl_mngt_fail_step(mngt);
201 		return;
202 	}
203 	ftl_mngt_next_step(mngt);
204 }
205 
206 void
207 ftl_mngt_md_deinit_vss_emu(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
208 {
209 	struct ftl_layout *layout = &dev->layout;
210 
211 	if (layout->md[FTL_LAYOUT_REGION_TYPE_VSS]) {
212 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_VSS]);
213 		layout->md[FTL_LAYOUT_REGION_TYPE_VSS] = NULL;
214 	}
215 
216 	ftl_mngt_next_step(mngt);
217 }
218 #endif
219 
220 void
221 ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
222 {
223 	struct ftl_layout *layout = &dev->layout;
224 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
225 	char uuid[SPDK_UUID_STRING_LEN];
226 
227 	/* Must generate UUID before MD create on SHM for the SB */
228 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
229 		spdk_uuid_generate(&dev->conf.uuid);
230 		spdk_uuid_fmt_lower(uuid, sizeof(uuid), &dev->conf.uuid);
231 		FTL_NOTICELOG(dev, "Create new FTL, UUID %s\n", uuid);
232 	}
233 
234 	/* Setup the layout of a superblock */
235 	if (ftl_layout_setup_superblock(dev)) {
236 		ftl_mngt_fail_step(mngt);
237 		return;
238 	}
239 
240 	/* Allocate md buf */
241 	layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks,
242 						region->vss_blksz, region->name, false, region);
243 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
244 		ftl_mngt_fail_step(mngt);
245 		return;
246 	}
247 
248 	/* Link the md buf to the device */
249 	dev->sb = ftl_md_get_buffer(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
250 
251 	/* Setup superblock mirror to QLC */
252 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
253 	layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks,
254 			region->vss_blksz, NULL, false, region);
255 	if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
256 		ftl_mngt_fail_step(mngt);
257 		return;
258 	}
259 
260 	/* Initialize the superblock */
261 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
262 		ftl_mngt_call_process(mngt, &desc_init_sb);
263 	} else {
264 		ftl_mngt_fail_step(mngt);
265 	}
266 }
267 
268 void
269 ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
270 {
271 	struct ftl_layout *layout = &dev->layout;
272 
273 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
274 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
275 		layout->md[FTL_LAYOUT_REGION_TYPE_SB] = NULL;
276 	}
277 
278 	if (layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
279 		ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]);
280 		layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = NULL;
281 	}
282 
283 	ftl_mngt_next_step(mngt);
284 }
285