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