xref: /spdk/lib/ftl/ftl_layout.c (revision 8afdeef3becfe9409cc9e7372bd0bc10e8b7d46d)
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/bdev.h"
8 
9 #include "ftl_core.h"
10 #include "ftl_utils.h"
11 #include "ftl_band.h"
12 #include "ftl_layout.h"
13 #include "ftl_nv_cache.h"
14 #include "ftl_sb.h"
15 #include "nvc/ftl_nvc_dev.h"
16 #include "utils/ftl_layout_tracker_bdev.h"
17 #include "upgrade/ftl_layout_upgrade.h"
18 
19 enum ftl_layout_setup_mode {
20 	FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT = 0,
21 	FTL_LAYOUT_SETUP_MODE_NO_RESTRICT,
22 	FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT,
23 };
24 
25 static inline float
26 blocks2mib(uint64_t blocks)
27 {
28 	float result;
29 
30 	result = blocks;
31 	result *= FTL_BLOCK_SIZE;
32 	result /= 1024UL;
33 	result /= 1024UL;
34 
35 	return result;
36 }
37 
38 static uint64_t
39 superblock_region_size(struct spdk_ftl_dev *dev)
40 {
41 	const struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
42 	uint64_t wus = spdk_bdev_get_write_unit_size(bdev) * FTL_BLOCK_SIZE;
43 
44 	if (wus > FTL_SUPERBLOCK_SIZE) {
45 		return wus;
46 	} else {
47 		return wus * spdk_divide_round_up(FTL_SUPERBLOCK_SIZE, wus);
48 	}
49 }
50 
51 static uint64_t
52 superblock_region_blocks(struct spdk_ftl_dev *dev)
53 {
54 	return superblock_region_size(dev) / FTL_BLOCK_SIZE;
55 }
56 
57 uint64_t
58 ftl_md_region_blocks(struct spdk_ftl_dev *dev, uint64_t bytes)
59 {
60 	const uint64_t alignment = superblock_region_size(dev);
61 	uint64_t result;
62 
63 	result = spdk_divide_round_up(bytes, alignment);
64 	result *= alignment;
65 	result /= FTL_BLOCK_SIZE;
66 
67 	return result;
68 }
69 
70 uint64_t
71 ftl_md_region_align_blocks(struct spdk_ftl_dev *dev, uint64_t blocks)
72 {
73 	const uint64_t alignment = superblock_region_blocks(dev);
74 	uint64_t result;
75 
76 	result = spdk_divide_round_up(blocks, alignment);
77 	result *= alignment;
78 
79 	return result;
80 }
81 
82 const char *
83 ftl_md_region_name(enum ftl_layout_region_type reg_type)
84 {
85 	static const char *md_region_name[FTL_LAYOUT_REGION_TYPE_MAX] = {
86 		[FTL_LAYOUT_REGION_TYPE_SB] = "sb",
87 		[FTL_LAYOUT_REGION_TYPE_SB_BASE] = "sb_mirror",
88 		[FTL_LAYOUT_REGION_TYPE_L2P] = "l2p",
89 		[FTL_LAYOUT_REGION_TYPE_BAND_MD] = "band_md",
90 		[FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = "band_md_mirror",
91 		[FTL_LAYOUT_REGION_TYPE_VALID_MAP] = "vmap",
92 		[FTL_LAYOUT_REGION_TYPE_NVC_MD] = "nvc_md",
93 		[FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = "nvc_md_mirror",
94 		[FTL_LAYOUT_REGION_TYPE_DATA_NVC] = "data_nvc",
95 		[FTL_LAYOUT_REGION_TYPE_DATA_BASE] = "data_btm",
96 		[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = "p2l0",
97 		[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = "p2l1",
98 		[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = "p2l2",
99 		[FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = "p2l3",
100 		[FTL_LAYOUT_REGION_TYPE_TRIM_MD] = "trim_md",
101 		[FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = "trim_md_mirror",
102 		[FTL_LAYOUT_REGION_TYPE_TRIM_LOG] = "trim_log",
103 		[FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR] = "trim_log_mirror"
104 	};
105 	const char *reg_name = md_region_name[reg_type];
106 
107 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
108 	assert(reg_name != NULL);
109 	return reg_name;
110 }
111 
112 static void
113 dump_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *region)
114 {
115 	assert(!(region->current.offset % superblock_region_blocks(dev)));
116 	assert(!(region->current.blocks % superblock_region_blocks(dev)));
117 
118 	FTL_NOTICELOG(dev, "Region %s\n", region->name);
119 	FTL_NOTICELOG(dev, "	offset:                      %.2f MiB\n",
120 		      blocks2mib(region->current.offset));
121 	FTL_NOTICELOG(dev, "	blocks:                      %.2f MiB\n",
122 		      blocks2mib(region->current.blocks));
123 }
124 
125 static bool
126 is_region_disabled(struct ftl_layout_region *region)
127 {
128 	return region->current.blocks == 0 && region->current.offset == FTL_ADDR_INVALID;
129 }
130 
131 int
132 ftl_validate_regions(struct spdk_ftl_dev *dev, struct ftl_layout *layout)
133 {
134 	enum ftl_layout_region_type i, j;
135 
136 	/* Validate if regions doesn't overlap each other  */
137 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
138 		struct ftl_layout_region *r1 = ftl_layout_region_get(dev, i);
139 
140 		if (!r1 || is_region_disabled(r1)) {
141 			continue;
142 		}
143 
144 		for (j = 0; j < FTL_LAYOUT_REGION_TYPE_MAX; j++) {
145 			struct ftl_layout_region *r2 = ftl_layout_region_get(dev, j);
146 
147 			if (!r2 || is_region_disabled(r2)) {
148 				continue;
149 			}
150 
151 			if (r1->bdev_desc != r2->bdev_desc) {
152 				continue;
153 			}
154 
155 			if (i == j) {
156 				continue;
157 			}
158 
159 			uint64_t r1_begin = r1->current.offset;
160 			uint64_t r1_end = r1->current.offset + r1->current.blocks - 1;
161 			uint64_t r2_begin = r2->current.offset;
162 			uint64_t r2_end = r2->current.offset + r2->current.blocks - 1;
163 
164 			if (spdk_max(r1_begin, r2_begin) <= spdk_min(r1_end, r2_end)) {
165 				FTL_ERRLOG(dev, "Layout initialization ERROR, two regions overlap, "
166 					   "%s and %s\n", r1->name, r2->name);
167 				return -1;
168 			}
169 		}
170 	}
171 
172 	return 0;
173 }
174 
175 static uint64_t
176 get_num_user_lbas(struct spdk_ftl_dev *dev)
177 {
178 	uint64_t blocks;
179 
180 	blocks = dev->num_bands * ftl_get_num_blocks_in_band(dev);
181 	blocks = (blocks * (100 - dev->conf.overprovisioning)) / 100;
182 
183 	return blocks;
184 }
185 
186 struct ftl_layout_region *
187 ftl_layout_region_get(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type)
188 {
189 	struct ftl_layout_region *reg = &dev->layout.region[reg_type];
190 
191 	assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX);
192 	return reg->type == reg_type ? reg : NULL;
193 }
194 
195 uint64_t
196 ftl_layout_base_offset(struct spdk_ftl_dev *dev)
197 {
198 	return dev->num_bands * ftl_get_num_blocks_in_band(dev);
199 }
200 
201 static int
202 layout_region_create_nvc(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
203 			 uint32_t reg_version, size_t entry_size, size_t entry_count)
204 {
205 	const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
206 	size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size);
207 
208 	if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) {
209 		return -1;
210 	}
211 	if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count,
212 				&dev->layout.region[reg_type])) {
213 		return -1;
214 	}
215 	return 0;
216 }
217 
218 static int
219 layout_region_create_base(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
220 			  uint32_t reg_version, size_t entry_size, size_t entry_count)
221 {
222 	const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops;
223 	size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size);
224 
225 	if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) {
226 		return -1;
227 	}
228 	if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count,
229 				&dev->layout.region[reg_type])) {
230 		return -1;
231 	}
232 	return 0;
233 }
234 
235 static void
236 legacy_layout_verify_region(struct ftl_layout_tracker_bdev *layout_tracker,
237 			    enum ftl_layout_region_type reg_type, uint32_t reg_version)
238 {
239 	const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
240 	const struct ftl_layout_tracker_bdev_region_props *reg_found = NULL;
241 
242 	while (true) {
243 		ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, &reg_search_ctx);
244 		if (!reg_search_ctx) {
245 			break;
246 		}
247 
248 		/* Only a single region version is present in upgrade from the legacy layout */
249 		ftl_bug(reg_search_ctx->ver != reg_version);
250 		ftl_bug(reg_found != NULL);
251 
252 		reg_found = reg_search_ctx;
253 	}
254 }
255 
256 static int
257 legacy_layout_region_open_nvc(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
258 			      uint32_t reg_version, size_t entry_size, size_t entry_count)
259 {
260 	struct ftl_layout_region *reg = &dev->layout.region[reg_type];
261 	const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
262 
263 	legacy_layout_verify_region(dev->nvc_layout_tracker, reg_type, reg_version);
264 	return md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, reg);
265 }
266 
267 static int
268 legacy_layout_region_open_base(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type,
269 			       uint32_t reg_version, size_t entry_size, size_t entry_count)
270 {
271 	struct ftl_layout_region *reg = &dev->layout.region[reg_type];
272 	const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops;
273 
274 	legacy_layout_verify_region(dev->nvc_layout_tracker, reg_type, reg_version);
275 	return md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, reg);
276 }
277 
278 static int
279 layout_setup_legacy_default_nvc(struct spdk_ftl_dev *dev)
280 {
281 	int region_type;
282 	uint64_t blocks, chunk_count;
283 	struct ftl_layout *layout = &dev->layout;
284 	const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
285 
286 	/* Initialize L2P region */
287 	blocks = ftl_md_region_blocks(dev, layout->l2p.addr_size * dev->num_lbas);
288 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_L2P, 0, FTL_BLOCK_SIZE,
289 					  blocks)) {
290 		goto error;
291 	}
292 
293 	/* Initialize band info metadata */
294 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD, FTL_BAND_VERSION_1,
295 					  sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) {
296 		goto error;
297 	}
298 
299 	/* Initialize band info metadata mirror */
300 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, FTL_BAND_VERSION_1,
301 					  sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) {
302 		goto error;
303 	}
304 	layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR;
305 
306 	/*
307 	 * Initialize P2L checkpointing regions
308 	 */
309 	for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
310 	     region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX;
311 	     region_type++) {
312 		const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
313 
314 		/* Get legacy number of blocks */
315 		ftl_layout_tracker_bdev_find_next_region(dev->nvc_layout_tracker, region_type, &reg_search_ctx);
316 		if (!reg_search_ctx || reg_search_ctx->ver != FTL_P2L_VERSION_1) {
317 			goto error;
318 		}
319 		blocks = reg_search_ctx->blk_sz;
320 
321 		if (legacy_layout_region_open_nvc(dev, region_type, FTL_P2L_VERSION_1, FTL_BLOCK_SIZE, blocks)) {
322 			goto error;
323 		}
324 	}
325 
326 	/*
327 	 * Initialize trim metadata region
328 	 */
329 	blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks;
330 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD, 0, sizeof(uint64_t),
331 					  blocks)) {
332 		goto error;
333 	}
334 
335 	/* Initialize trim metadata mirror region */
336 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, 0, sizeof(uint64_t),
337 					  blocks)) {
338 		goto error;
339 	}
340 	layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR;
341 
342 	/* Restore chunk count */
343 	ftl_layout_tracker_bdev_find_next_region(dev->nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_DATA_NVC,
344 			&reg_search_ctx);
345 	if (!reg_search_ctx || reg_search_ctx->ver != 0) {
346 		goto error;
347 	}
348 	blocks = reg_search_ctx->blk_sz;
349 	chunk_count = blocks / ftl_get_num_blocks_in_band(dev);
350 	if (0 == chunk_count) {
351 		goto error;
352 	}
353 
354 	/*
355 	 * Initialize NV Cache metadata
356 	 */
357 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD, FTL_NVC_VERSION_1,
358 					  sizeof(struct ftl_nv_cache_chunk_md), chunk_count)) {
359 		goto error;
360 	}
361 
362 	/*
363 	 * Initialize NV Cache metadata mirror
364 	 */
365 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, FTL_NVC_VERSION_1,
366 					  sizeof(struct ftl_nv_cache_chunk_md), chunk_count)) {
367 		goto error;
368 	}
369 	layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR;
370 
371 	/*
372 	 * Initialize data region on NV cache
373 	 */
374 	if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_DATA_NVC, 0,
375 					  layout->nvc.chunk_data_blocks * FTL_BLOCK_SIZE, chunk_count)) {
376 		goto error;
377 	}
378 
379 	/* Here is the place to add necessary region placeholders for the creation of new regions */
380 	ftl_layout_upgrade_add_region_placeholder(dev, dev->nvc_layout_tracker,
381 			FTL_LAYOUT_REGION_TYPE_TRIM_LOG);
382 	ftl_layout_upgrade_add_region_placeholder(dev, dev->nvc_layout_tracker,
383 			FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR);
384 
385 	return 0;
386 
387 error:
388 	FTL_ERRLOG(dev, "Invalid legacy NV Cache metadata layout\n");
389 	return -1;
390 }
391 
392 static int
393 layout_setup_legacy_default_base(struct spdk_ftl_dev *dev)
394 {
395 	struct ftl_layout *layout = &dev->layout;
396 
397 	/* Base device layout is as follows:
398 	 * - superblock
399 	 * - data
400 	 * - valid map
401 	 */
402 	if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE,
403 				      ftl_layout_base_offset(dev))) {
404 		return -1;
405 	}
406 
407 	if (legacy_layout_region_open_base(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP, 0, FTL_BLOCK_SIZE,
408 					   ftl_md_region_blocks(dev, spdk_divide_round_up(layout->base.total_blocks + layout->nvc.total_blocks,
409 							   8)))) {
410 		return -1;
411 	}
412 
413 	return 0;
414 }
415 
416 static int
417 layout_setup_legacy_default(struct spdk_ftl_dev *dev)
418 {
419 	if (layout_setup_legacy_default_nvc(dev) || layout_setup_legacy_default_base(dev)) {
420 		return -1;
421 	}
422 	return 0;
423 }
424 
425 static int
426 layout_setup_default_nvc(struct spdk_ftl_dev *dev)
427 {
428 	int region_type;
429 	uint64_t blocks;
430 	struct ftl_layout *layout = &dev->layout;
431 
432 	/* Initialize L2P region */
433 	blocks = ftl_md_region_blocks(dev, layout->l2p.addr_size * dev->num_lbas);
434 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_L2P, 0, FTL_BLOCK_SIZE, blocks)) {
435 		goto error;
436 	}
437 
438 	/* Initialize band info metadata */
439 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD, FTL_BAND_VERSION_CURRENT,
440 				     sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) {
441 		goto error;
442 	}
443 
444 	/* Initialize band info metadata mirror */
445 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, FTL_BAND_VERSION_CURRENT,
446 				     sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) {
447 		goto error;
448 	}
449 	layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR;
450 
451 	/*
452 	 * Initialize P2L checkpointing regions
453 	 */
454 	for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
455 	     region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX;
456 	     region_type++) {
457 		if (layout_region_create_nvc(dev, region_type, FTL_P2L_VERSION_CURRENT, FTL_BLOCK_SIZE,
458 					     layout->p2l.ckpt_pages)) {
459 			goto error;
460 		}
461 	}
462 
463 	/*
464 	 * Initialize trim metadata region
465 	 */
466 	blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks;
467 	blocks = spdk_divide_round_up(blocks * sizeof(uint64_t), FTL_BLOCK_SIZE);
468 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD, 0, FTL_BLOCK_SIZE, blocks)) {
469 		goto error;
470 	}
471 
472 	/* Initialize trim metadata mirror region */
473 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, 0, FTL_BLOCK_SIZE,
474 				     blocks)) {
475 		goto error;
476 	}
477 	layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR;
478 
479 	/*
480 	 * Initialize trim log region
481 	 */
482 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_LOG, FTL_TRIM_LOG_VERSION_CURRENT,
483 				     sizeof(struct ftl_trim_log), 1)) {
484 		goto error;
485 	}
486 
487 	/* Initialize trim log mirror region */
488 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR,
489 				     FTL_TRIM_LOG_VERSION_CURRENT,
490 				     sizeof(struct ftl_trim_log), 1)) {
491 		goto error;
492 	}
493 	layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_LOG].mirror_type =
494 		FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR;
495 
496 	/*
497 	 * Initialize NV Cache metadata
498 	 */
499 	if (0 == layout->nvc.chunk_count) {
500 		goto error;
501 	}
502 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD, FTL_NVC_VERSION_CURRENT,
503 				     sizeof(struct ftl_nv_cache_chunk_md), layout->nvc.chunk_count)) {
504 		goto error;
505 	}
506 
507 	/*
508 	 * Initialize NV Cache metadata mirror
509 	 */
510 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, FTL_NVC_VERSION_CURRENT,
511 				     sizeof(struct ftl_nv_cache_chunk_md), layout->nvc.chunk_count)) {
512 		goto error;
513 	}
514 	layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR;
515 
516 	return 0;
517 
518 error:
519 	FTL_ERRLOG(dev, "Insufficient NV Cache capacity to preserve metadata\n");
520 	return -1;
521 }
522 
523 static int
524 layout_setup_default_base(struct spdk_ftl_dev *dev)
525 {
526 	struct ftl_layout *layout = &dev->layout;
527 	uint64_t valid_map_size;
528 
529 	/* Base device layout is as follows:
530 	 * - superblock
531 	 * - data
532 	 * - valid map
533 	 */
534 	if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE,
535 				      ftl_layout_base_offset(dev))) {
536 		return -1;
537 	}
538 
539 	valid_map_size = spdk_divide_round_up(layout->base.total_blocks + layout->nvc.total_blocks, 8);
540 	if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP, 0, FTL_BLOCK_SIZE,
541 				      ftl_md_region_blocks(dev, valid_map_size))) {
542 		return -1;
543 	}
544 
545 	return 0;
546 }
547 
548 static int
549 layout_setup_default(struct spdk_ftl_dev *dev)
550 {
551 	if (layout_setup_default_nvc(dev) || layout_setup_default_base(dev)) {
552 		return -1;
553 	}
554 	return 0;
555 }
556 
557 static int
558 layout_load(struct spdk_ftl_dev *dev)
559 {
560 	if (ftl_superblock_load_blob_area(dev)) {
561 		return -1;
562 	}
563 	if (ftl_superblock_md_layout_apply(dev)) {
564 		return -1;
565 	}
566 	return 0;
567 }
568 
569 int
570 ftl_layout_setup(struct spdk_ftl_dev *dev)
571 {
572 	struct ftl_layout *layout = &dev->layout;
573 	uint64_t i;
574 	uint64_t num_lbas;
575 	enum ftl_layout_setup_mode setup_mode;
576 	int rc;
577 
578 	/*
579 	 * SB v5 adds the ability to create MD regions dynamically, i.e. depending on the underlying device type.
580 	 * For compatibility reasons:
581 	 * 1. When upgrading from pre-v5 SB, only the legacy default layout is created.
582 	 *    Pre-v5: some regions were static and not stored in the SB layout. These must be created to match
583 	 *            the legacy default layout.
584 	 *    v5: all regions are stored in the SB layout. Upon the SB upgrade, the legacy default layout
585 	 *        is updated with pre-v5 layout stored in the SB. The whole layout is then stored in v5 SB.
586 	 *
587 	 * 2. When SB v5 or later was loaded, the layout is instantiated from the nvc and base layout blobs.
588 	 *    No default layout is created.
589 	 *
590 	 * 3. When the FTL layout is being created for the first time, there are no restrictions.
591 	 *
592 	 * Any new regions to be created in cases (1) and (2) can only be placed in the unallocated area
593 	 * of the underlying device.
594 	 */
595 
596 	if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
597 		setup_mode = FTL_LAYOUT_SETUP_MODE_NO_RESTRICT;
598 	} else if (ftl_superblock_is_blob_area_empty(dev->sb)) {
599 		setup_mode = FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT;
600 	} else {
601 		setup_mode = FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT;
602 	}
603 	FTL_NOTICELOG(dev, "FTL layout setup mode %d\n", (int)setup_mode);
604 
605 	/* Invalidate all regions */
606 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
607 		if (i == FTL_LAYOUT_REGION_TYPE_SB || i == FTL_LAYOUT_REGION_TYPE_SB_BASE) {
608 			/* Super block has been already initialized */
609 			continue;
610 		}
611 
612 		layout->region[i].mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID;
613 		/* Mark the region inactive */
614 		layout->region[i].type = FTL_LAYOUT_REGION_TYPE_INVALID;
615 	}
616 
617 	/*
618 	 * Initialize L2P information
619 	 */
620 	num_lbas = get_num_user_lbas(dev);
621 	if (dev->num_lbas == 0) {
622 		assert(dev->conf.mode & SPDK_FTL_MODE_CREATE);
623 		dev->num_lbas = num_lbas;
624 		dev->sb->lba_cnt = num_lbas;
625 	} else if (dev->num_lbas != num_lbas) {
626 		FTL_ERRLOG(dev, "Mismatched FTL num_lbas\n");
627 		return -EINVAL;
628 	}
629 	layout->l2p.addr_length = spdk_u64log2(layout->base.total_blocks + layout->nvc.total_blocks) + 1;
630 	layout->l2p.addr_size = layout->l2p.addr_length > 32 ? 8 : 4;
631 	layout->l2p.lbas_in_page = FTL_BLOCK_SIZE / layout->l2p.addr_size;
632 
633 	/* Setup P2L ckpt */
634 	layout->p2l.pages_per_xfer = spdk_divide_round_up(dev->xfer_size, FTL_NUM_P2L_ENTRIES_NO_VSS);
635 	layout->p2l.ckpt_pages = spdk_divide_round_up(ftl_get_num_blocks_in_band(dev),
636 				 dev->xfer_size) * layout->p2l.pages_per_xfer;
637 
638 	layout->nvc.chunk_data_blocks = ftl_get_num_blocks_in_band(dev);
639 	layout->nvc.chunk_count = layout->nvc.total_blocks / ftl_get_num_blocks_in_band(dev);
640 	layout->nvc.chunk_tail_md_num_blocks = ftl_nv_cache_chunk_tail_md_num_blocks(&dev->nv_cache);
641 
642 	layout->base.num_usable_blocks = ftl_get_num_blocks_in_band(dev);
643 	layout->base.user_blocks = ftl_band_user_blocks(dev->bands);
644 
645 	switch (setup_mode) {
646 	case FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT:
647 		if (layout_setup_legacy_default(dev)) {
648 			return -EINVAL;
649 		}
650 		break;
651 
652 	case FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT:
653 		if (layout_load(dev)) {
654 			return -EINVAL;
655 		}
656 		break;
657 
658 	case FTL_LAYOUT_SETUP_MODE_NO_RESTRICT:
659 		if (layout_setup_default(dev)) {
660 			return -EINVAL;
661 		}
662 		break;
663 
664 	default:
665 		ftl_abort();
666 		break;
667 	}
668 
669 	if (ftl_validate_regions(dev, layout)) {
670 		return -EINVAL;
671 	}
672 
673 	rc = ftl_superblock_store_blob_area(dev);
674 
675 	FTL_NOTICELOG(dev, "Base device capacity:         %.2f MiB\n",
676 		      blocks2mib(layout->base.total_blocks));
677 	FTL_NOTICELOG(dev, "NV cache device capacity:       %.2f MiB\n",
678 		      blocks2mib(layout->nvc.total_blocks));
679 	FTL_NOTICELOG(dev, "L2P entries:                    %"PRIu64"\n", dev->num_lbas);
680 	FTL_NOTICELOG(dev, "L2P address size:               %"PRIu64"\n", layout->l2p.addr_size);
681 	FTL_NOTICELOG(dev, "P2L checkpoint pages:           %"PRIu64"\n", layout->p2l.ckpt_pages);
682 	FTL_NOTICELOG(dev, "NV cache chunk count            %"PRIu64"\n", dev->layout.nvc.chunk_count);
683 
684 	return rc;
685 }
686 
687 int
688 ftl_layout_setup_superblock(struct spdk_ftl_dev *dev)
689 {
690 	const struct spdk_bdev *bdev;
691 	struct ftl_layout *layout = &dev->layout;
692 	struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
693 	uint64_t total_blocks, offset, left;
694 
695 	assert(layout->md[FTL_LAYOUT_REGION_TYPE_SB] == NULL);
696 
697 	bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
698 	layout->base.total_blocks = spdk_bdev_get_num_blocks(bdev);
699 
700 	bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
701 	layout->nvc.total_blocks = spdk_bdev_get_num_blocks(bdev);
702 
703 	/* Initialize superblock region */
704 	if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_SB, FTL_SB_VERSION_CURRENT,
705 				     superblock_region_size(dev), 1)) {
706 		FTL_ERRLOG(dev, "Error when setting up primary super block\n");
707 		return -1;
708 	}
709 
710 	assert(region->bdev_desc != NULL);
711 	assert(region->ioch != NULL);
712 	assert(region->current.offset == 0);
713 
714 	if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_SB_BASE, FTL_SB_VERSION_CURRENT,
715 				      superblock_region_size(dev), 1)) {
716 		FTL_ERRLOG(dev, "Error when setting up secondary super block\n");
717 		return -1;
718 	}
719 	layout->region[FTL_LAYOUT_REGION_TYPE_SB].mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE;
720 
721 	region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
722 	assert(region->current.offset == 0);
723 
724 	/* Check if SB can be stored at the end of base device */
725 	total_blocks = spdk_bdev_get_num_blocks(
726 			       spdk_bdev_desc_get_bdev(dev->base_bdev_desc));
727 	offset = region->current.offset + region->current.blocks;
728 	left = total_blocks - offset;
729 	if ((left > total_blocks) || (offset > total_blocks)) {
730 		FTL_ERRLOG(dev, "Error when setup base device super block\n");
731 		return -1;
732 	}
733 
734 	return 0;
735 }
736 
737 int
738 ftl_layout_clear_superblock(struct spdk_ftl_dev *dev)
739 {
740 	int rc;
741 
742 	rc = ftl_layout_tracker_bdev_rm_region(dev->nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB,
743 					       FTL_SB_VERSION_CURRENT);
744 	if (rc) {
745 		return rc;
746 	}
747 
748 	return ftl_layout_tracker_bdev_rm_region(dev->base_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB_BASE,
749 			FTL_SB_VERSION_CURRENT);
750 }
751 
752 void
753 ftl_layout_dump(struct spdk_ftl_dev *dev)
754 {
755 	struct ftl_layout_region *reg;
756 	enum ftl_layout_region_type i;
757 
758 	FTL_NOTICELOG(dev, "NV cache layout:\n");
759 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
760 		reg = ftl_layout_region_get(dev, i);
761 		if (reg && reg->bdev_desc == dev->nv_cache.bdev_desc) {
762 			dump_region(dev, reg);
763 		}
764 	}
765 	FTL_NOTICELOG(dev, "Base device layout:\n");
766 	for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) {
767 		reg = ftl_layout_region_get(dev, i);
768 		if (reg && reg->bdev_desc == dev->base_bdev_desc) {
769 			dump_region(dev, reg);
770 		}
771 	}
772 }
773 
774 uint64_t
775 ftl_layout_base_md_blocks(struct spdk_ftl_dev *dev)
776 {
777 	const struct spdk_bdev *bdev;
778 	uint64_t md_blocks = 0, total_blocks = 0;
779 
780 	bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc);
781 	total_blocks += spdk_bdev_get_num_blocks(bdev);
782 
783 	bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc);
784 	total_blocks += spdk_bdev_get_num_blocks(bdev);
785 
786 	/* Count space needed for validity map */
787 	md_blocks += ftl_md_region_blocks(dev, spdk_divide_round_up(total_blocks, 8));
788 
789 	/* Count space needed for superblock */
790 	md_blocks += superblock_region_blocks(dev);
791 	return md_blocks;
792 }
793 
794 struct layout_blob_entry {
795 	uint32_t type;
796 	uint64_t entry_size;
797 	uint64_t num_entries;
798 } __attribute__((packed));
799 
800 size_t
801 ftl_layout_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz)
802 {
803 	struct layout_blob_entry *blob_entry = blob_buf;
804 	struct ftl_layout_region *reg;
805 	enum ftl_layout_region_type reg_type;
806 	size_t blob_sz = 0;
807 
808 	for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) {
809 		if (blob_sz + sizeof(*blob_entry) > blob_buf_sz) {
810 			return 0;
811 		}
812 
813 		reg = &dev->layout.region[reg_type];
814 		blob_entry->type = reg_type;
815 		blob_entry->entry_size = reg->entry_size;
816 		blob_entry->num_entries = reg->num_entries;
817 
818 		blob_entry++;
819 		blob_sz += sizeof(*blob_entry);
820 	}
821 
822 	return blob_sz;
823 }
824 
825 int
826 ftl_layout_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz)
827 {
828 	struct layout_blob_entry *blob_entry = blob_buf;
829 	size_t blob_entry_num = blob_sz / sizeof(*blob_entry);
830 	struct layout_blob_entry *blob_entry_end = blob_entry + blob_entry_num;
831 	struct ftl_layout_region *reg;
832 
833 	if (blob_sz % sizeof(*blob_entry) != 0) {
834 		/* Invalid blob size */
835 		return -1;
836 	}
837 
838 	for (; blob_entry < blob_entry_end; blob_entry++) {
839 		/* Verify the type */
840 		if (blob_entry->type >= FTL_LAYOUT_REGION_TYPE_MAX) {
841 			return -1;
842 		}
843 
844 		/* Load the entry */
845 		reg = &dev->layout.region[blob_entry->type];
846 		reg->entry_size = blob_entry->entry_size;
847 		reg->num_entries = blob_entry->num_entries;
848 	}
849 
850 	return 0;
851 }
852 
853 void
854 ftl_layout_upgrade_add_region_placeholder(struct spdk_ftl_dev *dev,
855 		struct ftl_layout_tracker_bdev *layout_tracker, enum ftl_layout_region_type reg_type)
856 {
857 	const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL;
858 
859 	ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, &reg_search_ctx);
860 	if (reg_search_ctx) {
861 		return;
862 	}
863 
864 	dev->layout.region[reg_type].type = reg_type;
865 	dev->layout.region[reg_type].current.version = 0;
866 	dev->layout.region[reg_type].current.offset = UINT64_MAX;
867 	dev->layout.region[reg_type].current.blocks = 0;
868 }
869