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/bdev.h" 82b5bba56SArtur Paszkiewicz 92b5bba56SArtur Paszkiewicz #include "ftl_core.h" 102b5bba56SArtur Paszkiewicz #include "ftl_utils.h" 116448f336SArtur Paszkiewicz #include "ftl_band.h" 122b5bba56SArtur Paszkiewicz #include "ftl_layout.h" 13a68a12a4SKozlowski Mateusz #include "ftl_nv_cache.h" 14c6880a39SArtur Paszkiewicz #include "ftl_sb.h" 15b0556d4aSLukasz Lasek #include "nvc/ftl_nvc_dev.h" 1693036282SLukasz Lasek #include "utils/ftl_layout_tracker_bdev.h" 17a5c04e6dSMateusz Kozlowski #include "upgrade/ftl_layout_upgrade.h" 182b5bba56SArtur Paszkiewicz 199f42898aSLukasz Lasek enum ftl_layout_setup_mode { 209f42898aSLukasz Lasek FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT = 0, 219f42898aSLukasz Lasek FTL_LAYOUT_SETUP_MODE_NO_RESTRICT, 22845c9ae2SMateusz Kozlowski FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT, 239f42898aSLukasz Lasek }; 24a68a12a4SKozlowski Mateusz 252b5bba56SArtur Paszkiewicz static inline float 262b5bba56SArtur Paszkiewicz blocks2mib(uint64_t blocks) 272b5bba56SArtur Paszkiewicz { 282b5bba56SArtur Paszkiewicz float result; 292b5bba56SArtur Paszkiewicz 302b5bba56SArtur Paszkiewicz result = blocks; 312b5bba56SArtur Paszkiewicz result *= FTL_BLOCK_SIZE; 322b5bba56SArtur Paszkiewicz result /= 1024UL; 332b5bba56SArtur Paszkiewicz result /= 1024UL; 342b5bba56SArtur Paszkiewicz 352b5bba56SArtur Paszkiewicz return result; 362b5bba56SArtur Paszkiewicz } 37102d266dSKozlowski Mateusz 38102d266dSKozlowski Mateusz static uint64_t 39102d266dSKozlowski Mateusz superblock_region_size(struct spdk_ftl_dev *dev) 40102d266dSKozlowski Mateusz { 41102d266dSKozlowski Mateusz const struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc); 42102d266dSKozlowski Mateusz uint64_t wus = spdk_bdev_get_write_unit_size(bdev) * FTL_BLOCK_SIZE; 43102d266dSKozlowski Mateusz 44102d266dSKozlowski Mateusz if (wus > FTL_SUPERBLOCK_SIZE) { 45102d266dSKozlowski Mateusz return wus; 46102d266dSKozlowski Mateusz } else { 47102d266dSKozlowski Mateusz return wus * spdk_divide_round_up(FTL_SUPERBLOCK_SIZE, wus); 48102d266dSKozlowski Mateusz } 49102d266dSKozlowski Mateusz } 50102d266dSKozlowski Mateusz 51102d266dSKozlowski Mateusz static uint64_t 52102d266dSKozlowski Mateusz superblock_region_blocks(struct spdk_ftl_dev *dev) 53102d266dSKozlowski Mateusz { 54102d266dSKozlowski Mateusz return superblock_region_size(dev) / FTL_BLOCK_SIZE; 55102d266dSKozlowski Mateusz } 562b5bba56SArtur Paszkiewicz 57b0556d4aSLukasz Lasek uint64_t 58b0556d4aSLukasz Lasek ftl_md_region_blocks(struct spdk_ftl_dev *dev, uint64_t bytes) 59f725ca81SArtur Paszkiewicz { 60102d266dSKozlowski Mateusz const uint64_t alignment = superblock_region_size(dev); 61f725ca81SArtur Paszkiewicz uint64_t result; 62f725ca81SArtur Paszkiewicz 63f725ca81SArtur Paszkiewicz result = spdk_divide_round_up(bytes, alignment); 64f725ca81SArtur Paszkiewicz result *= alignment; 65f725ca81SArtur Paszkiewicz result /= FTL_BLOCK_SIZE; 66f725ca81SArtur Paszkiewicz 67f725ca81SArtur Paszkiewicz return result; 68f725ca81SArtur Paszkiewicz } 69f725ca81SArtur Paszkiewicz 708fcffebaSMateusz Kozlowski uint64_t 718fcffebaSMateusz Kozlowski ftl_md_region_align_blocks(struct spdk_ftl_dev *dev, uint64_t blocks) 728fcffebaSMateusz Kozlowski { 738fcffebaSMateusz Kozlowski const uint64_t alignment = superblock_region_blocks(dev); 748fcffebaSMateusz Kozlowski uint64_t result; 758fcffebaSMateusz Kozlowski 768fcffebaSMateusz Kozlowski result = spdk_divide_round_up(blocks, alignment); 778fcffebaSMateusz Kozlowski result *= alignment; 788fcffebaSMateusz Kozlowski 798fcffebaSMateusz Kozlowski return result; 808fcffebaSMateusz Kozlowski } 818fcffebaSMateusz Kozlowski 82b0556d4aSLukasz Lasek const char * 83b0556d4aSLukasz Lasek ftl_md_region_name(enum ftl_layout_region_type reg_type) 84b0556d4aSLukasz Lasek { 85b0556d4aSLukasz Lasek static const char *md_region_name[FTL_LAYOUT_REGION_TYPE_MAX] = { 86b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_SB] = "sb", 87b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_SB_BASE] = "sb_mirror", 88b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_L2P] = "l2p", 89b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_BAND_MD] = "band_md", 90b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR] = "band_md_mirror", 91b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_VALID_MAP] = "vmap", 92b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_NVC_MD] = "nvc_md", 93b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR] = "nvc_md_mirror", 94b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_DATA_NVC] = "data_nvc", 95b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_DATA_BASE] = "data_btm", 96b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC] = "p2l0", 97b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_GC_NEXT] = "p2l1", 98b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP] = "p2l2", 99b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_P2L_CKPT_COMP_NEXT] = "p2l3", 100b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_TRIM_MD] = "trim_md", 101b0556d4aSLukasz Lasek [FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR] = "trim_md_mirror", 1022d613454SMateusz Kozlowski [FTL_LAYOUT_REGION_TYPE_TRIM_LOG] = "trim_log", 103*6d6179ffSMateusz Kozlowski [FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR] = "trim_log_mirror", 104*6d6179ffSMateusz Kozlowski [FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN] = "p2l_log_io1", 105*6d6179ffSMateusz Kozlowski [FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX] = "p2l_log_io2", 106b0556d4aSLukasz Lasek }; 107b0556d4aSLukasz Lasek const char *reg_name = md_region_name[reg_type]; 108b0556d4aSLukasz Lasek 109b0556d4aSLukasz Lasek assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX); 110b0556d4aSLukasz Lasek assert(reg_name != NULL); 111b0556d4aSLukasz Lasek return reg_name; 112b0556d4aSLukasz Lasek } 113b0556d4aSLukasz Lasek 114*6d6179ffSMateusz Kozlowski static bool 115*6d6179ffSMateusz Kozlowski is_region_disabled(struct ftl_layout_region *region) 116*6d6179ffSMateusz Kozlowski { 117*6d6179ffSMateusz Kozlowski return region->current.blocks == 0 && region->current.offset == FTL_ADDR_INVALID; 118*6d6179ffSMateusz Kozlowski } 119*6d6179ffSMateusz Kozlowski 1202b5bba56SArtur Paszkiewicz static void 1212b5bba56SArtur Paszkiewicz dump_region(struct spdk_ftl_dev *dev, struct ftl_layout_region *region) 1222b5bba56SArtur Paszkiewicz { 123*6d6179ffSMateusz Kozlowski if (is_region_disabled(region)) { 124*6d6179ffSMateusz Kozlowski return; 125*6d6179ffSMateusz Kozlowski } 126*6d6179ffSMateusz Kozlowski 127102d266dSKozlowski Mateusz assert(!(region->current.offset % superblock_region_blocks(dev))); 128102d266dSKozlowski Mateusz assert(!(region->current.blocks % superblock_region_blocks(dev))); 1292b5bba56SArtur Paszkiewicz 1302b5bba56SArtur Paszkiewicz FTL_NOTICELOG(dev, "Region %s\n", region->name); 1312b5bba56SArtur Paszkiewicz FTL_NOTICELOG(dev, " offset: %.2f MiB\n", 1322b5bba56SArtur Paszkiewicz blocks2mib(region->current.offset)); 1332b5bba56SArtur Paszkiewicz FTL_NOTICELOG(dev, " blocks: %.2f MiB\n", 1342b5bba56SArtur Paszkiewicz blocks2mib(region->current.blocks)); 1352b5bba56SArtur Paszkiewicz } 1362b5bba56SArtur Paszkiewicz 1372b5bba56SArtur Paszkiewicz int 1382b5bba56SArtur Paszkiewicz ftl_validate_regions(struct spdk_ftl_dev *dev, struct ftl_layout *layout) 1392b5bba56SArtur Paszkiewicz { 14030ef80cdSMateusz Kozlowski enum ftl_layout_region_type i, j; 1412b5bba56SArtur Paszkiewicz 1422b5bba56SArtur Paszkiewicz /* Validate if regions doesn't overlap each other */ 1432b5bba56SArtur Paszkiewicz for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) { 14430ef80cdSMateusz Kozlowski struct ftl_layout_region *r1 = ftl_layout_region_get(dev, i); 1452b5bba56SArtur Paszkiewicz 1462d613454SMateusz Kozlowski if (!r1 || is_region_disabled(r1)) { 1478fc78fd8SMateusz Kozlowski continue; 1488fc78fd8SMateusz Kozlowski } 1498fc78fd8SMateusz Kozlowski 1502b5bba56SArtur Paszkiewicz for (j = 0; j < FTL_LAYOUT_REGION_TYPE_MAX; j++) { 15130ef80cdSMateusz Kozlowski struct ftl_layout_region *r2 = ftl_layout_region_get(dev, j); 1522b5bba56SArtur Paszkiewicz 1532d613454SMateusz Kozlowski if (!r2 || is_region_disabled(r2)) { 1548fc78fd8SMateusz Kozlowski continue; 1558fc78fd8SMateusz Kozlowski } 1568fc78fd8SMateusz Kozlowski 1572b5bba56SArtur Paszkiewicz if (r1->bdev_desc != r2->bdev_desc) { 1582b5bba56SArtur Paszkiewicz continue; 1592b5bba56SArtur Paszkiewicz } 1602b5bba56SArtur Paszkiewicz 1612b5bba56SArtur Paszkiewicz if (i == j) { 1622b5bba56SArtur Paszkiewicz continue; 1632b5bba56SArtur Paszkiewicz } 1642b5bba56SArtur Paszkiewicz 1652b5bba56SArtur Paszkiewicz uint64_t r1_begin = r1->current.offset; 1662b5bba56SArtur Paszkiewicz uint64_t r1_end = r1->current.offset + r1->current.blocks - 1; 1672b5bba56SArtur Paszkiewicz uint64_t r2_begin = r2->current.offset; 1682b5bba56SArtur Paszkiewicz uint64_t r2_end = r2->current.offset + r2->current.blocks - 1; 1692b5bba56SArtur Paszkiewicz 1702b5bba56SArtur Paszkiewicz if (spdk_max(r1_begin, r2_begin) <= spdk_min(r1_end, r2_end)) { 1712b5bba56SArtur Paszkiewicz FTL_ERRLOG(dev, "Layout initialization ERROR, two regions overlap, " 1722b5bba56SArtur Paszkiewicz "%s and %s\n", r1->name, r2->name); 1732b5bba56SArtur Paszkiewicz return -1; 1742b5bba56SArtur Paszkiewicz } 1752b5bba56SArtur Paszkiewicz } 1762b5bba56SArtur Paszkiewicz } 1772b5bba56SArtur Paszkiewicz 1782b5bba56SArtur Paszkiewicz return 0; 1792b5bba56SArtur Paszkiewicz } 1802b5bba56SArtur Paszkiewicz 1812b5bba56SArtur Paszkiewicz static uint64_t 1822b5bba56SArtur Paszkiewicz get_num_user_lbas(struct spdk_ftl_dev *dev) 1832b5bba56SArtur Paszkiewicz { 18481dfe157SKozlowski Mateusz uint64_t blocks; 1852b5bba56SArtur Paszkiewicz 18681dfe157SKozlowski Mateusz blocks = dev->num_bands * ftl_get_num_blocks_in_band(dev); 1872b5bba56SArtur Paszkiewicz blocks = (blocks * (100 - dev->conf.overprovisioning)) / 100; 1882b5bba56SArtur Paszkiewicz 1892b5bba56SArtur Paszkiewicz return blocks; 1902b5bba56SArtur Paszkiewicz } 1912b5bba56SArtur Paszkiewicz 19230ef80cdSMateusz Kozlowski struct ftl_layout_region * 19330ef80cdSMateusz Kozlowski ftl_layout_region_get(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type) 19430ef80cdSMateusz Kozlowski { 19530ef80cdSMateusz Kozlowski struct ftl_layout_region *reg = &dev->layout.region[reg_type]; 19630ef80cdSMateusz Kozlowski 19730ef80cdSMateusz Kozlowski assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX); 19830ef80cdSMateusz Kozlowski return reg->type == reg_type ? reg : NULL; 19930ef80cdSMateusz Kozlowski } 20030ef80cdSMateusz Kozlowski 2018fcffebaSMateusz Kozlowski uint64_t 2028fcffebaSMateusz Kozlowski ftl_layout_base_offset(struct spdk_ftl_dev *dev) 2038fcffebaSMateusz Kozlowski { 2048fcffebaSMateusz Kozlowski return dev->num_bands * ftl_get_num_blocks_in_band(dev); 2058fcffebaSMateusz Kozlowski } 2068fcffebaSMateusz Kozlowski 2072b5bba56SArtur Paszkiewicz static int 208d55b9f29SMateusz Kozlowski layout_region_create_nvc(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 209d55b9f29SMateusz Kozlowski uint32_t reg_version, size_t entry_size, size_t entry_count) 210d55b9f29SMateusz Kozlowski { 21126f3b551SMateusz Kozlowski const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops; 2129f42898aSLukasz Lasek size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size); 213d55b9f29SMateusz Kozlowski 2149f42898aSLukasz Lasek if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) { 2159f42898aSLukasz Lasek return -1; 2169f42898aSLukasz Lasek } 2179f42898aSLukasz Lasek if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, 2189f42898aSLukasz Lasek &dev->layout.region[reg_type])) { 219d55b9f29SMateusz Kozlowski return -1; 220d55b9f29SMateusz Kozlowski } 221d55b9f29SMateusz Kozlowski return 0; 222d55b9f29SMateusz Kozlowski } 223d55b9f29SMateusz Kozlowski 224d55b9f29SMateusz Kozlowski static int 225d55b9f29SMateusz Kozlowski layout_region_create_base(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 226d55b9f29SMateusz Kozlowski uint32_t reg_version, size_t entry_size, size_t entry_count) 227d55b9f29SMateusz Kozlowski { 228d55b9f29SMateusz Kozlowski const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops; 2299f42898aSLukasz Lasek size_t reg_blks = ftl_md_region_blocks(dev, entry_count * entry_size); 230d55b9f29SMateusz Kozlowski 2319f42898aSLukasz Lasek if (md_ops->region_create(dev, reg_type, reg_version, reg_blks)) { 2329f42898aSLukasz Lasek return -1; 2339f42898aSLukasz Lasek } 2349f42898aSLukasz Lasek if (md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, 2359f42898aSLukasz Lasek &dev->layout.region[reg_type])) { 236d55b9f29SMateusz Kozlowski return -1; 237d55b9f29SMateusz Kozlowski } 238d55b9f29SMateusz Kozlowski return 0; 239d55b9f29SMateusz Kozlowski } 240d55b9f29SMateusz Kozlowski 241845c9ae2SMateusz Kozlowski static void 242845c9ae2SMateusz Kozlowski legacy_layout_verify_region(struct ftl_layout_tracker_bdev *layout_tracker, 243845c9ae2SMateusz Kozlowski enum ftl_layout_region_type reg_type, uint32_t reg_version) 244845c9ae2SMateusz Kozlowski { 245845c9ae2SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 246845c9ae2SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_found = NULL; 247845c9ae2SMateusz Kozlowski 248845c9ae2SMateusz Kozlowski while (true) { 249845c9ae2SMateusz Kozlowski ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 250845c9ae2SMateusz Kozlowski if (!reg_search_ctx) { 251845c9ae2SMateusz Kozlowski break; 252845c9ae2SMateusz Kozlowski } 253845c9ae2SMateusz Kozlowski 254845c9ae2SMateusz Kozlowski /* Only a single region version is present in upgrade from the legacy layout */ 255845c9ae2SMateusz Kozlowski ftl_bug(reg_search_ctx->ver != reg_version); 256845c9ae2SMateusz Kozlowski ftl_bug(reg_found != NULL); 257845c9ae2SMateusz Kozlowski 258845c9ae2SMateusz Kozlowski reg_found = reg_search_ctx; 259845c9ae2SMateusz Kozlowski } 260845c9ae2SMateusz Kozlowski } 261845c9ae2SMateusz Kozlowski 262845c9ae2SMateusz Kozlowski static int 263845c9ae2SMateusz Kozlowski legacy_layout_region_open_nvc(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 264845c9ae2SMateusz Kozlowski uint32_t reg_version, size_t entry_size, size_t entry_count) 265845c9ae2SMateusz Kozlowski { 266845c9ae2SMateusz Kozlowski struct ftl_layout_region *reg = &dev->layout.region[reg_type]; 26726f3b551SMateusz Kozlowski const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops; 268845c9ae2SMateusz Kozlowski 269845c9ae2SMateusz Kozlowski legacy_layout_verify_region(dev->nvc_layout_tracker, reg_type, reg_version); 270845c9ae2SMateusz Kozlowski return md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, reg); 271845c9ae2SMateusz Kozlowski } 272845c9ae2SMateusz Kozlowski 273845c9ae2SMateusz Kozlowski static int 274845c9ae2SMateusz Kozlowski legacy_layout_region_open_base(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 275845c9ae2SMateusz Kozlowski uint32_t reg_version, size_t entry_size, size_t entry_count) 276845c9ae2SMateusz Kozlowski { 277845c9ae2SMateusz Kozlowski struct ftl_layout_region *reg = &dev->layout.region[reg_type]; 278845c9ae2SMateusz Kozlowski const struct ftl_md_layout_ops *md_ops = &dev->base_type->ops.md_layout_ops; 279845c9ae2SMateusz Kozlowski 280845c9ae2SMateusz Kozlowski legacy_layout_verify_region(dev->nvc_layout_tracker, reg_type, reg_version); 281845c9ae2SMateusz Kozlowski return md_ops->region_open(dev, reg_type, reg_version, entry_size, entry_count, reg); 282845c9ae2SMateusz Kozlowski } 283845c9ae2SMateusz Kozlowski 284845c9ae2SMateusz Kozlowski static int 285845c9ae2SMateusz Kozlowski layout_setup_legacy_default_nvc(struct spdk_ftl_dev *dev) 286845c9ae2SMateusz Kozlowski { 287845c9ae2SMateusz Kozlowski int region_type; 288845c9ae2SMateusz Kozlowski uint64_t blocks, chunk_count; 289845c9ae2SMateusz Kozlowski struct ftl_layout *layout = &dev->layout; 290845c9ae2SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 291845c9ae2SMateusz Kozlowski 292845c9ae2SMateusz Kozlowski /* Initialize L2P region */ 293845c9ae2SMateusz Kozlowski blocks = ftl_md_region_blocks(dev, layout->l2p.addr_size * dev->num_lbas); 294845c9ae2SMateusz Kozlowski if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_L2P, 0, FTL_BLOCK_SIZE, 295845c9ae2SMateusz Kozlowski blocks)) { 296845c9ae2SMateusz Kozlowski goto error; 297845c9ae2SMateusz Kozlowski } 298845c9ae2SMateusz Kozlowski 299845c9ae2SMateusz Kozlowski /* Initialize band info metadata */ 300845c9ae2SMateusz Kozlowski if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD, FTL_BAND_VERSION_1, 301845c9ae2SMateusz Kozlowski sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) { 302845c9ae2SMateusz Kozlowski goto error; 303845c9ae2SMateusz Kozlowski } 304845c9ae2SMateusz Kozlowski 305845c9ae2SMateusz Kozlowski /* Initialize band info metadata mirror */ 306845c9ae2SMateusz Kozlowski if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, FTL_BAND_VERSION_1, 307845c9ae2SMateusz Kozlowski sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) { 308845c9ae2SMateusz Kozlowski goto error; 309845c9ae2SMateusz Kozlowski } 310845c9ae2SMateusz Kozlowski layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR; 311845c9ae2SMateusz Kozlowski 312845c9ae2SMateusz Kozlowski /* 313845c9ae2SMateusz Kozlowski * Initialize P2L checkpointing regions 314845c9ae2SMateusz Kozlowski */ 315845c9ae2SMateusz Kozlowski for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN; 316845c9ae2SMateusz Kozlowski region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX; 317845c9ae2SMateusz Kozlowski region_type++) { 318845c9ae2SMateusz Kozlowski const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 319845c9ae2SMateusz Kozlowski 320845c9ae2SMateusz Kozlowski /* Get legacy number of blocks */ 321845c9ae2SMateusz Kozlowski ftl_layout_tracker_bdev_find_next_region(dev->nvc_layout_tracker, region_type, ®_search_ctx); 322845c9ae2SMateusz Kozlowski if (!reg_search_ctx || reg_search_ctx->ver != FTL_P2L_VERSION_1) { 323845c9ae2SMateusz Kozlowski goto error; 324845c9ae2SMateusz Kozlowski } 325845c9ae2SMateusz Kozlowski blocks = reg_search_ctx->blk_sz; 326845c9ae2SMateusz Kozlowski 327845c9ae2SMateusz Kozlowski if (legacy_layout_region_open_nvc(dev, region_type, FTL_P2L_VERSION_1, FTL_BLOCK_SIZE, blocks)) { 328845c9ae2SMateusz Kozlowski goto error; 329845c9ae2SMateusz Kozlowski } 330845c9ae2SMateusz Kozlowski } 331845c9ae2SMateusz Kozlowski 332845c9ae2SMateusz Kozlowski /* 333845c9ae2SMateusz Kozlowski * Initialize trim metadata region 334845c9ae2SMateusz Kozlowski */ 335845c9ae2SMateusz Kozlowski blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks; 336845c9ae2SMateusz Kozlowski if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD, 0, sizeof(uint64_t), 337845c9ae2SMateusz Kozlowski blocks)) { 338845c9ae2SMateusz Kozlowski goto error; 339845c9ae2SMateusz Kozlowski } 340845c9ae2SMateusz Kozlowski 341845c9ae2SMateusz Kozlowski /* Initialize trim metadata mirror region */ 342845c9ae2SMateusz Kozlowski if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, 0, sizeof(uint64_t), 343845c9ae2SMateusz Kozlowski blocks)) { 344845c9ae2SMateusz Kozlowski goto error; 345845c9ae2SMateusz Kozlowski } 346845c9ae2SMateusz Kozlowski layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR; 347845c9ae2SMateusz Kozlowski 348845c9ae2SMateusz Kozlowski /* Restore chunk count */ 349845c9ae2SMateusz Kozlowski ftl_layout_tracker_bdev_find_next_region(dev->nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_DATA_NVC, 350845c9ae2SMateusz Kozlowski ®_search_ctx); 351845c9ae2SMateusz Kozlowski if (!reg_search_ctx || reg_search_ctx->ver != 0) { 352845c9ae2SMateusz Kozlowski goto error; 353845c9ae2SMateusz Kozlowski } 354845c9ae2SMateusz Kozlowski blocks = reg_search_ctx->blk_sz; 355845c9ae2SMateusz Kozlowski chunk_count = blocks / ftl_get_num_blocks_in_band(dev); 356845c9ae2SMateusz Kozlowski if (0 == chunk_count) { 357845c9ae2SMateusz Kozlowski goto error; 358845c9ae2SMateusz Kozlowski } 359845c9ae2SMateusz Kozlowski 360845c9ae2SMateusz Kozlowski /* 361845c9ae2SMateusz Kozlowski * Initialize NV Cache metadata 362845c9ae2SMateusz Kozlowski */ 363845c9ae2SMateusz Kozlowski if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD, FTL_NVC_VERSION_1, 364845c9ae2SMateusz Kozlowski sizeof(struct ftl_nv_cache_chunk_md), chunk_count)) { 365845c9ae2SMateusz Kozlowski goto error; 366845c9ae2SMateusz Kozlowski } 367845c9ae2SMateusz Kozlowski 368845c9ae2SMateusz Kozlowski /* 369845c9ae2SMateusz Kozlowski * Initialize NV Cache metadata mirror 370845c9ae2SMateusz Kozlowski */ 371845c9ae2SMateusz Kozlowski if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, FTL_NVC_VERSION_1, 372845c9ae2SMateusz Kozlowski sizeof(struct ftl_nv_cache_chunk_md), chunk_count)) { 373845c9ae2SMateusz Kozlowski goto error; 374845c9ae2SMateusz Kozlowski } 375845c9ae2SMateusz Kozlowski layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR; 376845c9ae2SMateusz Kozlowski 377845c9ae2SMateusz Kozlowski /* 378845c9ae2SMateusz Kozlowski * Initialize data region on NV cache 379845c9ae2SMateusz Kozlowski */ 380845c9ae2SMateusz Kozlowski if (legacy_layout_region_open_nvc(dev, FTL_LAYOUT_REGION_TYPE_DATA_NVC, 0, 381845c9ae2SMateusz Kozlowski layout->nvc.chunk_data_blocks * FTL_BLOCK_SIZE, chunk_count)) { 382845c9ae2SMateusz Kozlowski goto error; 383845c9ae2SMateusz Kozlowski } 384845c9ae2SMateusz Kozlowski 3855555d51cSLukasz Lasek /* Here is the place to add necessary region placeholders for the creation of new regions */ 3862d613454SMateusz Kozlowski ftl_layout_upgrade_add_region_placeholder(dev, dev->nvc_layout_tracker, 3872d613454SMateusz Kozlowski FTL_LAYOUT_REGION_TYPE_TRIM_LOG); 3882d613454SMateusz Kozlowski ftl_layout_upgrade_add_region_placeholder(dev, dev->nvc_layout_tracker, 3892d613454SMateusz Kozlowski FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR); 3905555d51cSLukasz Lasek 391845c9ae2SMateusz Kozlowski return 0; 392845c9ae2SMateusz Kozlowski 393845c9ae2SMateusz Kozlowski error: 394845c9ae2SMateusz Kozlowski FTL_ERRLOG(dev, "Invalid legacy NV Cache metadata layout\n"); 395845c9ae2SMateusz Kozlowski return -1; 396845c9ae2SMateusz Kozlowski } 397845c9ae2SMateusz Kozlowski 398845c9ae2SMateusz Kozlowski static int 399845c9ae2SMateusz Kozlowski layout_setup_legacy_default_base(struct spdk_ftl_dev *dev) 400845c9ae2SMateusz Kozlowski { 401845c9ae2SMateusz Kozlowski struct ftl_layout *layout = &dev->layout; 402845c9ae2SMateusz Kozlowski 403845c9ae2SMateusz Kozlowski /* Base device layout is as follows: 404845c9ae2SMateusz Kozlowski * - superblock 405845c9ae2SMateusz Kozlowski * - data 406845c9ae2SMateusz Kozlowski * - valid map 407845c9ae2SMateusz Kozlowski */ 408845c9ae2SMateusz Kozlowski if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE, 409845c9ae2SMateusz Kozlowski ftl_layout_base_offset(dev))) { 410845c9ae2SMateusz Kozlowski return -1; 411845c9ae2SMateusz Kozlowski } 412845c9ae2SMateusz Kozlowski 413845c9ae2SMateusz Kozlowski if (legacy_layout_region_open_base(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP, 0, FTL_BLOCK_SIZE, 414845c9ae2SMateusz Kozlowski ftl_md_region_blocks(dev, spdk_divide_round_up(layout->base.total_blocks + layout->nvc.total_blocks, 415845c9ae2SMateusz Kozlowski 8)))) { 416845c9ae2SMateusz Kozlowski return -1; 417845c9ae2SMateusz Kozlowski } 418845c9ae2SMateusz Kozlowski 419845c9ae2SMateusz Kozlowski return 0; 420845c9ae2SMateusz Kozlowski } 421845c9ae2SMateusz Kozlowski 422845c9ae2SMateusz Kozlowski static int 423845c9ae2SMateusz Kozlowski layout_setup_legacy_default(struct spdk_ftl_dev *dev) 424845c9ae2SMateusz Kozlowski { 425845c9ae2SMateusz Kozlowski if (layout_setup_legacy_default_nvc(dev) || layout_setup_legacy_default_base(dev)) { 426845c9ae2SMateusz Kozlowski return -1; 427845c9ae2SMateusz Kozlowski } 428845c9ae2SMateusz Kozlowski return 0; 429845c9ae2SMateusz Kozlowski } 430845c9ae2SMateusz Kozlowski 431d55b9f29SMateusz Kozlowski static int 4329f42898aSLukasz Lasek layout_setup_default_nvc(struct spdk_ftl_dev *dev) 4332b5bba56SArtur Paszkiewicz { 4341738488eSArtur Paszkiewicz int region_type; 4352d613454SMateusz Kozlowski uint64_t blocks; 4362b5bba56SArtur Paszkiewicz struct ftl_layout *layout = &dev->layout; 437c6880a39SArtur Paszkiewicz 438b16bdc6dSArtur Paszkiewicz /* Initialize L2P region */ 4392d613454SMateusz Kozlowski blocks = ftl_md_region_blocks(dev, layout->l2p.addr_size * dev->num_lbas); 4402d613454SMateusz Kozlowski if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_L2P, 0, FTL_BLOCK_SIZE, blocks)) { 441b16bdc6dSArtur Paszkiewicz goto error; 442b16bdc6dSArtur Paszkiewicz } 443b16bdc6dSArtur Paszkiewicz 4446448f336SArtur Paszkiewicz /* Initialize band info metadata */ 445d55b9f29SMateusz Kozlowski if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD, FTL_BAND_VERSION_CURRENT, 446b0556d4aSLukasz Lasek sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) { 4476448f336SArtur Paszkiewicz goto error; 4486448f336SArtur Paszkiewicz } 4496448f336SArtur Paszkiewicz 4506448f336SArtur Paszkiewicz /* Initialize band info metadata mirror */ 451d55b9f29SMateusz Kozlowski if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR, FTL_BAND_VERSION_CURRENT, 452b0556d4aSLukasz Lasek sizeof(struct ftl_band_md), ftl_get_num_bands(dev))) { 4536448f336SArtur Paszkiewicz goto error; 4546448f336SArtur Paszkiewicz } 455b0556d4aSLukasz Lasek layout->region[FTL_LAYOUT_REGION_TYPE_BAND_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR; 456c6880a39SArtur Paszkiewicz 457a68a12a4SKozlowski Mateusz /* 4581738488eSArtur Paszkiewicz * Initialize P2L checkpointing regions 4591738488eSArtur Paszkiewicz */ 4601738488eSArtur Paszkiewicz for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN; 4611738488eSArtur Paszkiewicz region_type <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MAX; 4621738488eSArtur Paszkiewicz region_type++) { 463d55b9f29SMateusz Kozlowski if (layout_region_create_nvc(dev, region_type, FTL_P2L_VERSION_CURRENT, FTL_BLOCK_SIZE, 464b0556d4aSLukasz Lasek layout->p2l.ckpt_pages)) { 4651738488eSArtur Paszkiewicz goto error; 4661738488eSArtur Paszkiewicz } 4671738488eSArtur Paszkiewicz } 4681738488eSArtur Paszkiewicz 4691738488eSArtur Paszkiewicz /* 47078c3cbf4SArtur Paszkiewicz * Initialize trim metadata region 47178c3cbf4SArtur Paszkiewicz */ 4722d613454SMateusz Kozlowski blocks = layout->region[FTL_LAYOUT_REGION_TYPE_L2P].current.blocks; 4732d613454SMateusz Kozlowski blocks = spdk_divide_round_up(blocks * sizeof(uint64_t), FTL_BLOCK_SIZE); 4742d613454SMateusz Kozlowski if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD, 0, FTL_BLOCK_SIZE, blocks)) { 47578c3cbf4SArtur Paszkiewicz goto error; 47678c3cbf4SArtur Paszkiewicz } 47778c3cbf4SArtur Paszkiewicz 47878c3cbf4SArtur Paszkiewicz /* Initialize trim metadata mirror region */ 4792d613454SMateusz Kozlowski if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR, 0, FTL_BLOCK_SIZE, 4802d613454SMateusz Kozlowski blocks)) { 48178c3cbf4SArtur Paszkiewicz goto error; 48278c3cbf4SArtur Paszkiewicz } 483b0556d4aSLukasz Lasek layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR; 48478c3cbf4SArtur Paszkiewicz 48578c3cbf4SArtur Paszkiewicz /* 4862d613454SMateusz Kozlowski * Initialize trim log region 4872d613454SMateusz Kozlowski */ 4882d613454SMateusz Kozlowski if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_LOG, FTL_TRIM_LOG_VERSION_CURRENT, 4892d613454SMateusz Kozlowski sizeof(struct ftl_trim_log), 1)) { 4902d613454SMateusz Kozlowski goto error; 4912d613454SMateusz Kozlowski } 4922d613454SMateusz Kozlowski 4932d613454SMateusz Kozlowski /* Initialize trim log mirror region */ 4942d613454SMateusz Kozlowski if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR, 4952d613454SMateusz Kozlowski FTL_TRIM_LOG_VERSION_CURRENT, 4962d613454SMateusz Kozlowski sizeof(struct ftl_trim_log), 1)) { 4972d613454SMateusz Kozlowski goto error; 4982d613454SMateusz Kozlowski } 4992d613454SMateusz Kozlowski layout->region[FTL_LAYOUT_REGION_TYPE_TRIM_LOG].mirror_type = 5002d613454SMateusz Kozlowski FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR; 5012d613454SMateusz Kozlowski 5022d613454SMateusz Kozlowski /* 503a68a12a4SKozlowski Mateusz * Initialize NV Cache metadata 504a68a12a4SKozlowski Mateusz */ 505a68a12a4SKozlowski Mateusz if (0 == layout->nvc.chunk_count) { 506a68a12a4SKozlowski Mateusz goto error; 507a68a12a4SKozlowski Mateusz } 508d55b9f29SMateusz Kozlowski if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD, FTL_NVC_VERSION_CURRENT, 509b0556d4aSLukasz Lasek sizeof(struct ftl_nv_cache_chunk_md), layout->nvc.chunk_count)) { 510b0556d4aSLukasz Lasek goto error; 511b0556d4aSLukasz Lasek } 512a68a12a4SKozlowski Mateusz 513a68a12a4SKozlowski Mateusz /* 514a68a12a4SKozlowski Mateusz * Initialize NV Cache metadata mirror 515a68a12a4SKozlowski Mateusz */ 516d55b9f29SMateusz Kozlowski if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR, FTL_NVC_VERSION_CURRENT, 517b0556d4aSLukasz Lasek sizeof(struct ftl_nv_cache_chunk_md), layout->nvc.chunk_count)) { 518b0556d4aSLukasz Lasek goto error; 519b0556d4aSLukasz Lasek } 520b0556d4aSLukasz Lasek layout->region[FTL_LAYOUT_REGION_TYPE_NVC_MD].mirror_type = FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR; 521a68a12a4SKozlowski Mateusz 522*6d6179ffSMateusz Kozlowski if (dev->nv_cache.nvc_type->ops.setup_layout) { 523*6d6179ffSMateusz Kozlowski return dev->nv_cache.nvc_type->ops.setup_layout(dev); 524*6d6179ffSMateusz Kozlowski } 525*6d6179ffSMateusz Kozlowski 5262b5bba56SArtur Paszkiewicz return 0; 5272b5bba56SArtur Paszkiewicz 5282b5bba56SArtur Paszkiewicz error: 5292b5bba56SArtur Paszkiewicz FTL_ERRLOG(dev, "Insufficient NV Cache capacity to preserve metadata\n"); 5302b5bba56SArtur Paszkiewicz return -1; 5312b5bba56SArtur Paszkiewicz } 5322b5bba56SArtur Paszkiewicz 5332b5bba56SArtur Paszkiewicz static int 5349f42898aSLukasz Lasek layout_setup_default_base(struct spdk_ftl_dev *dev) 5352b5bba56SArtur Paszkiewicz { 5362b5bba56SArtur Paszkiewicz struct ftl_layout *layout = &dev->layout; 537498c39beSLukasz Lasek uint64_t valid_map_size; 5382b5bba56SArtur Paszkiewicz 539498c39beSLukasz Lasek /* Base device layout is as follows: 540c6880a39SArtur Paszkiewicz * - superblock 541c3321813SKozlowski Mateusz * - data 542c6880a39SArtur Paszkiewicz * - valid map 543c6880a39SArtur Paszkiewicz */ 544d55b9f29SMateusz Kozlowski if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_DATA_BASE, 0, FTL_BLOCK_SIZE, 545d55b9f29SMateusz Kozlowski ftl_layout_base_offset(dev))) { 546c6880a39SArtur Paszkiewicz return -1; 547c6880a39SArtur Paszkiewicz } 548c6880a39SArtur Paszkiewicz 549498c39beSLukasz Lasek valid_map_size = spdk_divide_round_up(layout->base.total_blocks + layout->nvc.total_blocks, 8); 550d55b9f29SMateusz Kozlowski if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP, 0, FTL_BLOCK_SIZE, 551498c39beSLukasz Lasek ftl_md_region_blocks(dev, valid_map_size))) { 552c6880a39SArtur Paszkiewicz return -1; 553c6880a39SArtur Paszkiewicz } 554c6880a39SArtur Paszkiewicz 5552b5bba56SArtur Paszkiewicz return 0; 5562b5bba56SArtur Paszkiewicz } 5572b5bba56SArtur Paszkiewicz 5589f42898aSLukasz Lasek static int 5599f42898aSLukasz Lasek layout_setup_default(struct spdk_ftl_dev *dev) 5609f42898aSLukasz Lasek { 5619f42898aSLukasz Lasek if (layout_setup_default_nvc(dev) || layout_setup_default_base(dev)) { 5629f42898aSLukasz Lasek return -1; 5639f42898aSLukasz Lasek } 5649f42898aSLukasz Lasek return 0; 5659f42898aSLukasz Lasek } 5669f42898aSLukasz Lasek 5679f42898aSLukasz Lasek static int 5689f42898aSLukasz Lasek layout_load(struct spdk_ftl_dev *dev) 5699f42898aSLukasz Lasek { 5709f42898aSLukasz Lasek if (ftl_superblock_load_blob_area(dev)) { 5719f42898aSLukasz Lasek return -1; 5729f42898aSLukasz Lasek } 5739f42898aSLukasz Lasek if (ftl_superblock_md_layout_apply(dev)) { 5749f42898aSLukasz Lasek return -1; 5759f42898aSLukasz Lasek } 5769f42898aSLukasz Lasek return 0; 5779f42898aSLukasz Lasek } 5789f42898aSLukasz Lasek 5792b5bba56SArtur Paszkiewicz int 5802b5bba56SArtur Paszkiewicz ftl_layout_setup(struct spdk_ftl_dev *dev) 5812b5bba56SArtur Paszkiewicz { 5822b5bba56SArtur Paszkiewicz struct ftl_layout *layout = &dev->layout; 5832b5bba56SArtur Paszkiewicz uint64_t i; 5842b5bba56SArtur Paszkiewicz uint64_t num_lbas; 5859f42898aSLukasz Lasek enum ftl_layout_setup_mode setup_mode; 5869f42898aSLukasz Lasek int rc; 5872b5bba56SArtur Paszkiewicz 5889f42898aSLukasz Lasek /* 5899f42898aSLukasz Lasek * SB v5 adds the ability to create MD regions dynamically, i.e. depending on the underlying device type. 5909f42898aSLukasz Lasek * For compatibility reasons: 5919f42898aSLukasz Lasek * 1. When upgrading from pre-v5 SB, only the legacy default layout is created. 5929f42898aSLukasz Lasek * Pre-v5: some regions were static and not stored in the SB layout. These must be created to match 5939f42898aSLukasz Lasek * the legacy default layout. 5949f42898aSLukasz Lasek * v5: all regions are stored in the SB layout. Upon the SB upgrade, the legacy default layout 5959f42898aSLukasz Lasek * is updated with pre-v5 layout stored in the SB. The whole layout is then stored in v5 SB. 5969f42898aSLukasz Lasek * 5979f42898aSLukasz Lasek * 2. When SB v5 or later was loaded, the layout is instantiated from the nvc and base layout blobs. 5989f42898aSLukasz Lasek * No default layout is created. 5999f42898aSLukasz Lasek * 6009f42898aSLukasz Lasek * 3. When the FTL layout is being created for the first time, there are no restrictions. 6019f42898aSLukasz Lasek * 6029f42898aSLukasz Lasek * Any new regions to be created in cases (1) and (2) can only be placed in the unallocated area 6039f42898aSLukasz Lasek * of the underlying device. 6049f42898aSLukasz Lasek */ 6059f42898aSLukasz Lasek 6069f42898aSLukasz Lasek if (dev->conf.mode & SPDK_FTL_MODE_CREATE) { 6079f42898aSLukasz Lasek setup_mode = FTL_LAYOUT_SETUP_MODE_NO_RESTRICT; 608845c9ae2SMateusz Kozlowski } else if (ftl_superblock_is_blob_area_empty(dev->sb)) { 609845c9ae2SMateusz Kozlowski setup_mode = FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT; 6109f42898aSLukasz Lasek } else { 6119f42898aSLukasz Lasek setup_mode = FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT; 6129f42898aSLukasz Lasek } 6139f42898aSLukasz Lasek FTL_NOTICELOG(dev, "FTL layout setup mode %d\n", (int)setup_mode); 6149f42898aSLukasz Lasek 6159f42898aSLukasz Lasek /* Invalidate all regions */ 6162b5bba56SArtur Paszkiewicz for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) { 6179f42898aSLukasz Lasek if (i == FTL_LAYOUT_REGION_TYPE_SB || i == FTL_LAYOUT_REGION_TYPE_SB_BASE) { 618c6880a39SArtur Paszkiewicz /* Super block has been already initialized */ 619c6880a39SArtur Paszkiewicz continue; 620c6880a39SArtur Paszkiewicz } 621c6880a39SArtur Paszkiewicz 6222b5bba56SArtur Paszkiewicz layout->region[i].mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID; 6239f42898aSLukasz Lasek /* Mark the region inactive */ 6249f42898aSLukasz Lasek layout->region[i].type = FTL_LAYOUT_REGION_TYPE_INVALID; 6252b5bba56SArtur Paszkiewicz } 6262b5bba56SArtur Paszkiewicz 6272b5bba56SArtur Paszkiewicz /* 6282b5bba56SArtur Paszkiewicz * Initialize L2P information 6292b5bba56SArtur Paszkiewicz */ 6302b5bba56SArtur Paszkiewicz num_lbas = get_num_user_lbas(dev); 6312b5bba56SArtur Paszkiewicz if (dev->num_lbas == 0) { 6322b5bba56SArtur Paszkiewicz assert(dev->conf.mode & SPDK_FTL_MODE_CREATE); 6332b5bba56SArtur Paszkiewicz dev->num_lbas = num_lbas; 634c6880a39SArtur Paszkiewicz dev->sb->lba_cnt = num_lbas; 6352b5bba56SArtur Paszkiewicz } else if (dev->num_lbas != num_lbas) { 6362b5bba56SArtur Paszkiewicz FTL_ERRLOG(dev, "Mismatched FTL num_lbas\n"); 6372b5bba56SArtur Paszkiewicz return -EINVAL; 6382b5bba56SArtur Paszkiewicz } 6392b5bba56SArtur Paszkiewicz layout->l2p.addr_length = spdk_u64log2(layout->base.total_blocks + layout->nvc.total_blocks) + 1; 6402b5bba56SArtur Paszkiewicz layout->l2p.addr_size = layout->l2p.addr_length > 32 ? 8 : 4; 6412b5bba56SArtur Paszkiewicz layout->l2p.lbas_in_page = FTL_BLOCK_SIZE / layout->l2p.addr_size; 6422b5bba56SArtur Paszkiewicz 6431738488eSArtur Paszkiewicz /* Setup P2L ckpt */ 6444061ed11SMateusz Kozlowski layout->p2l.pages_per_xfer = spdk_divide_round_up(dev->xfer_size, FTL_NUM_P2L_ENTRIES_NO_VSS); 6454061ed11SMateusz Kozlowski layout->p2l.ckpt_pages = spdk_divide_round_up(ftl_get_num_blocks_in_band(dev), 6464061ed11SMateusz Kozlowski dev->xfer_size) * layout->p2l.pages_per_xfer; 6471738488eSArtur Paszkiewicz 648a5c04e6dSMateusz Kozlowski layout->nvc.chunk_data_blocks = ftl_get_num_blocks_in_band(dev); 649a5c04e6dSMateusz Kozlowski layout->nvc.chunk_count = layout->nvc.total_blocks / ftl_get_num_blocks_in_band(dev); 6509f42898aSLukasz Lasek layout->nvc.chunk_tail_md_num_blocks = ftl_nv_cache_chunk_tail_md_num_blocks(&dev->nv_cache); 6519f42898aSLukasz Lasek 6529f42898aSLukasz Lasek layout->base.num_usable_blocks = ftl_get_num_blocks_in_band(dev); 6539f42898aSLukasz Lasek layout->base.user_blocks = ftl_band_user_blocks(dev->bands); 6549f42898aSLukasz Lasek 6559f42898aSLukasz Lasek switch (setup_mode) { 656845c9ae2SMateusz Kozlowski case FTL_LAYOUT_SETUP_MODE_LEGACY_DEFAULT: 657845c9ae2SMateusz Kozlowski if (layout_setup_legacy_default(dev)) { 658845c9ae2SMateusz Kozlowski return -EINVAL; 659845c9ae2SMateusz Kozlowski } 660845c9ae2SMateusz Kozlowski break; 661845c9ae2SMateusz Kozlowski 6629f42898aSLukasz Lasek case FTL_LAYOUT_SETUP_MODE_LOAD_CURRENT: 6639f42898aSLukasz Lasek if (layout_load(dev)) { 6642b5bba56SArtur Paszkiewicz return -EINVAL; 6652b5bba56SArtur Paszkiewicz } 6669f42898aSLukasz Lasek break; 6672b5bba56SArtur Paszkiewicz 6689f42898aSLukasz Lasek case FTL_LAYOUT_SETUP_MODE_NO_RESTRICT: 6699f42898aSLukasz Lasek if (layout_setup_default(dev)) { 6702b5bba56SArtur Paszkiewicz return -EINVAL; 6712b5bba56SArtur Paszkiewicz } 6729f42898aSLukasz Lasek break; 6739f42898aSLukasz Lasek 6749f42898aSLukasz Lasek default: 6759f42898aSLukasz Lasek ftl_abort(); 6769f42898aSLukasz Lasek break; 6779f42898aSLukasz Lasek } 6782b5bba56SArtur Paszkiewicz 6792b5bba56SArtur Paszkiewicz if (ftl_validate_regions(dev, layout)) { 6802b5bba56SArtur Paszkiewicz return -EINVAL; 6812b5bba56SArtur Paszkiewicz } 6822b5bba56SArtur Paszkiewicz 6839f42898aSLukasz Lasek rc = ftl_superblock_store_blob_area(dev); 6849f42898aSLukasz Lasek 6852b5bba56SArtur Paszkiewicz FTL_NOTICELOG(dev, "Base device capacity: %.2f MiB\n", 6862b5bba56SArtur Paszkiewicz blocks2mib(layout->base.total_blocks)); 6872b5bba56SArtur Paszkiewicz FTL_NOTICELOG(dev, "NV cache device capacity: %.2f MiB\n", 6882b5bba56SArtur Paszkiewicz blocks2mib(layout->nvc.total_blocks)); 6891738488eSArtur Paszkiewicz FTL_NOTICELOG(dev, "L2P entries: %"PRIu64"\n", dev->num_lbas); 6901738488eSArtur Paszkiewicz FTL_NOTICELOG(dev, "L2P address size: %"PRIu64"\n", layout->l2p.addr_size); 6911738488eSArtur Paszkiewicz FTL_NOTICELOG(dev, "P2L checkpoint pages: %"PRIu64"\n", layout->p2l.ckpt_pages); 6929f42898aSLukasz Lasek FTL_NOTICELOG(dev, "NV cache chunk count %"PRIu64"\n", dev->layout.nvc.chunk_count); 6932b5bba56SArtur Paszkiewicz 6949f42898aSLukasz Lasek return rc; 6952b5bba56SArtur Paszkiewicz } 6962b5bba56SArtur Paszkiewicz 697c6880a39SArtur Paszkiewicz int 698c6880a39SArtur Paszkiewicz ftl_layout_setup_superblock(struct spdk_ftl_dev *dev) 699c6880a39SArtur Paszkiewicz { 700b0556d4aSLukasz Lasek const struct spdk_bdev *bdev; 701c6880a39SArtur Paszkiewicz struct ftl_layout *layout = &dev->layout; 702c6880a39SArtur Paszkiewicz struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB]; 703c6880a39SArtur Paszkiewicz uint64_t total_blocks, offset, left; 704c6880a39SArtur Paszkiewicz 705c6880a39SArtur Paszkiewicz assert(layout->md[FTL_LAYOUT_REGION_TYPE_SB] == NULL); 706c6880a39SArtur Paszkiewicz 707b0556d4aSLukasz Lasek bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc); 708b0556d4aSLukasz Lasek layout->base.total_blocks = spdk_bdev_get_num_blocks(bdev); 709c6880a39SArtur Paszkiewicz 710b0556d4aSLukasz Lasek bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc); 711b0556d4aSLukasz Lasek layout->nvc.total_blocks = spdk_bdev_get_num_blocks(bdev); 712b0556d4aSLukasz Lasek 713b0556d4aSLukasz Lasek /* Initialize superblock region */ 7149f42898aSLukasz Lasek if (layout_region_create_nvc(dev, FTL_LAYOUT_REGION_TYPE_SB, FTL_SB_VERSION_CURRENT, 715b0556d4aSLukasz Lasek superblock_region_size(dev), 1)) { 716b0556d4aSLukasz Lasek FTL_ERRLOG(dev, "Error when setting up primary super block\n"); 717b0556d4aSLukasz Lasek return -1; 718b0556d4aSLukasz Lasek } 719c6880a39SArtur Paszkiewicz 720c6880a39SArtur Paszkiewicz assert(region->bdev_desc != NULL); 721c6880a39SArtur Paszkiewicz assert(region->ioch != NULL); 722498c39beSLukasz Lasek assert(region->current.offset == 0); 723c6880a39SArtur Paszkiewicz 7249f42898aSLukasz Lasek if (layout_region_create_base(dev, FTL_LAYOUT_REGION_TYPE_SB_BASE, FTL_SB_VERSION_CURRENT, 725498c39beSLukasz Lasek superblock_region_size(dev), 1)) { 726498c39beSLukasz Lasek FTL_ERRLOG(dev, "Error when setting up secondary super block\n"); 727498c39beSLukasz Lasek return -1; 728498c39beSLukasz Lasek } 7296394849aSMateusz Kozlowski layout->region[FTL_LAYOUT_REGION_TYPE_SB].mirror_type = FTL_LAYOUT_REGION_TYPE_SB_BASE; 7306394849aSMateusz Kozlowski 731c6880a39SArtur Paszkiewicz region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE]; 732498c39beSLukasz Lasek assert(region->current.offset == 0); 733c6880a39SArtur Paszkiewicz 734c6880a39SArtur Paszkiewicz /* Check if SB can be stored at the end of base device */ 735c6880a39SArtur Paszkiewicz total_blocks = spdk_bdev_get_num_blocks( 736c6880a39SArtur Paszkiewicz spdk_bdev_desc_get_bdev(dev->base_bdev_desc)); 737c6880a39SArtur Paszkiewicz offset = region->current.offset + region->current.blocks; 738c6880a39SArtur Paszkiewicz left = total_blocks - offset; 739c6880a39SArtur Paszkiewicz if ((left > total_blocks) || (offset > total_blocks)) { 740c6880a39SArtur Paszkiewicz FTL_ERRLOG(dev, "Error when setup base device super block\n"); 741c6880a39SArtur Paszkiewicz return -1; 742c6880a39SArtur Paszkiewicz } 743c6880a39SArtur Paszkiewicz 744c6880a39SArtur Paszkiewicz return 0; 745c6880a39SArtur Paszkiewicz } 746f725ca81SArtur Paszkiewicz 7479f42898aSLukasz Lasek int 7489f42898aSLukasz Lasek ftl_layout_clear_superblock(struct spdk_ftl_dev *dev) 7499f42898aSLukasz Lasek { 7509f42898aSLukasz Lasek int rc; 7519f42898aSLukasz Lasek 7529f42898aSLukasz Lasek rc = ftl_layout_tracker_bdev_rm_region(dev->nvc_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB, 7539f42898aSLukasz Lasek FTL_SB_VERSION_CURRENT); 7549f42898aSLukasz Lasek if (rc) { 7559f42898aSLukasz Lasek return rc; 7569f42898aSLukasz Lasek } 7579f42898aSLukasz Lasek 7589f42898aSLukasz Lasek return ftl_layout_tracker_bdev_rm_region(dev->base_layout_tracker, FTL_LAYOUT_REGION_TYPE_SB_BASE, 7599f42898aSLukasz Lasek FTL_SB_VERSION_CURRENT); 7609f42898aSLukasz Lasek } 7619f42898aSLukasz Lasek 7622b5bba56SArtur Paszkiewicz void 7632b5bba56SArtur Paszkiewicz ftl_layout_dump(struct spdk_ftl_dev *dev) 7642b5bba56SArtur Paszkiewicz { 76530ef80cdSMateusz Kozlowski struct ftl_layout_region *reg; 76630ef80cdSMateusz Kozlowski enum ftl_layout_region_type i; 767102d266dSKozlowski Mateusz 7682b5bba56SArtur Paszkiewicz FTL_NOTICELOG(dev, "NV cache layout:\n"); 7692b5bba56SArtur Paszkiewicz for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) { 77030ef80cdSMateusz Kozlowski reg = ftl_layout_region_get(dev, i); 77130ef80cdSMateusz Kozlowski if (reg && reg->bdev_desc == dev->nv_cache.bdev_desc) { 77230ef80cdSMateusz Kozlowski dump_region(dev, reg); 7732b5bba56SArtur Paszkiewicz } 7742b5bba56SArtur Paszkiewicz } 775102d266dSKozlowski Mateusz FTL_NOTICELOG(dev, "Base device layout:\n"); 7762b5bba56SArtur Paszkiewicz for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; ++i) { 77730ef80cdSMateusz Kozlowski reg = ftl_layout_region_get(dev, i); 77830ef80cdSMateusz Kozlowski if (reg && reg->bdev_desc == dev->base_bdev_desc) { 77930ef80cdSMateusz Kozlowski dump_region(dev, reg); 7802b5bba56SArtur Paszkiewicz } 7812b5bba56SArtur Paszkiewicz } 7822b5bba56SArtur Paszkiewicz } 783102d266dSKozlowski Mateusz 784102d266dSKozlowski Mateusz uint64_t 785102d266dSKozlowski Mateusz ftl_layout_base_md_blocks(struct spdk_ftl_dev *dev) 786102d266dSKozlowski Mateusz { 787102d266dSKozlowski Mateusz const struct spdk_bdev *bdev; 788102d266dSKozlowski Mateusz uint64_t md_blocks = 0, total_blocks = 0; 789102d266dSKozlowski Mateusz 790102d266dSKozlowski Mateusz bdev = spdk_bdev_desc_get_bdev(dev->base_bdev_desc); 791102d266dSKozlowski Mateusz total_blocks += spdk_bdev_get_num_blocks(bdev); 792102d266dSKozlowski Mateusz 793102d266dSKozlowski Mateusz bdev = spdk_bdev_desc_get_bdev(dev->nv_cache.bdev_desc); 794102d266dSKozlowski Mateusz total_blocks += spdk_bdev_get_num_blocks(bdev); 795102d266dSKozlowski Mateusz 796102d266dSKozlowski Mateusz /* Count space needed for validity map */ 797b0556d4aSLukasz Lasek md_blocks += ftl_md_region_blocks(dev, spdk_divide_round_up(total_blocks, 8)); 798102d266dSKozlowski Mateusz 799102d266dSKozlowski Mateusz /* Count space needed for superblock */ 800102d266dSKozlowski Mateusz md_blocks += superblock_region_blocks(dev); 801102d266dSKozlowski Mateusz return md_blocks; 802102d266dSKozlowski Mateusz } 803e8cbab9eSMateusz Kozlowski 804e8cbab9eSMateusz Kozlowski struct layout_blob_entry { 805e8cbab9eSMateusz Kozlowski uint32_t type; 806e8cbab9eSMateusz Kozlowski uint64_t entry_size; 807e8cbab9eSMateusz Kozlowski uint64_t num_entries; 808e8cbab9eSMateusz Kozlowski } __attribute__((packed)); 809e8cbab9eSMateusz Kozlowski 810e8cbab9eSMateusz Kozlowski size_t 811e8cbab9eSMateusz Kozlowski ftl_layout_blob_store(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_buf_sz) 812e8cbab9eSMateusz Kozlowski { 813e8cbab9eSMateusz Kozlowski struct layout_blob_entry *blob_entry = blob_buf; 814e8cbab9eSMateusz Kozlowski struct ftl_layout_region *reg; 815e8cbab9eSMateusz Kozlowski enum ftl_layout_region_type reg_type; 816e8cbab9eSMateusz Kozlowski size_t blob_sz = 0; 817e8cbab9eSMateusz Kozlowski 818e8cbab9eSMateusz Kozlowski for (reg_type = 0; reg_type < FTL_LAYOUT_REGION_TYPE_MAX; reg_type++) { 819e8cbab9eSMateusz Kozlowski if (blob_sz + sizeof(*blob_entry) > blob_buf_sz) { 820e8cbab9eSMateusz Kozlowski return 0; 821e8cbab9eSMateusz Kozlowski } 822e8cbab9eSMateusz Kozlowski 823e8cbab9eSMateusz Kozlowski reg = &dev->layout.region[reg_type]; 824e8cbab9eSMateusz Kozlowski blob_entry->type = reg_type; 825e8cbab9eSMateusz Kozlowski blob_entry->entry_size = reg->entry_size; 826e8cbab9eSMateusz Kozlowski blob_entry->num_entries = reg->num_entries; 827e8cbab9eSMateusz Kozlowski 828e8cbab9eSMateusz Kozlowski blob_entry++; 829e8cbab9eSMateusz Kozlowski blob_sz += sizeof(*blob_entry); 830e8cbab9eSMateusz Kozlowski } 831e8cbab9eSMateusz Kozlowski 832e8cbab9eSMateusz Kozlowski return blob_sz; 833e8cbab9eSMateusz Kozlowski } 834e8cbab9eSMateusz Kozlowski 835e8cbab9eSMateusz Kozlowski int 836e8cbab9eSMateusz Kozlowski ftl_layout_blob_load(struct spdk_ftl_dev *dev, void *blob_buf, size_t blob_sz) 837e8cbab9eSMateusz Kozlowski { 838e8cbab9eSMateusz Kozlowski struct layout_blob_entry *blob_entry = blob_buf; 839e8cbab9eSMateusz Kozlowski size_t blob_entry_num = blob_sz / sizeof(*blob_entry); 840e8cbab9eSMateusz Kozlowski struct layout_blob_entry *blob_entry_end = blob_entry + blob_entry_num; 841e8cbab9eSMateusz Kozlowski struct ftl_layout_region *reg; 842e8cbab9eSMateusz Kozlowski 843e8cbab9eSMateusz Kozlowski if (blob_sz % sizeof(*blob_entry) != 0) { 844e8cbab9eSMateusz Kozlowski /* Invalid blob size */ 845e8cbab9eSMateusz Kozlowski return -1; 846e8cbab9eSMateusz Kozlowski } 847e8cbab9eSMateusz Kozlowski 848e8cbab9eSMateusz Kozlowski for (; blob_entry < blob_entry_end; blob_entry++) { 849e8cbab9eSMateusz Kozlowski /* Verify the type */ 850e8cbab9eSMateusz Kozlowski if (blob_entry->type >= FTL_LAYOUT_REGION_TYPE_MAX) { 851e8cbab9eSMateusz Kozlowski return -1; 852e8cbab9eSMateusz Kozlowski } 853e8cbab9eSMateusz Kozlowski 854e8cbab9eSMateusz Kozlowski /* Load the entry */ 855e8cbab9eSMateusz Kozlowski reg = &dev->layout.region[blob_entry->type]; 856e8cbab9eSMateusz Kozlowski reg->entry_size = blob_entry->entry_size; 857e8cbab9eSMateusz Kozlowski reg->num_entries = blob_entry->num_entries; 858e8cbab9eSMateusz Kozlowski } 859e8cbab9eSMateusz Kozlowski 860e8cbab9eSMateusz Kozlowski return 0; 861e8cbab9eSMateusz Kozlowski } 8625555d51cSLukasz Lasek 8635555d51cSLukasz Lasek void 8645555d51cSLukasz Lasek ftl_layout_upgrade_add_region_placeholder(struct spdk_ftl_dev *dev, 8655555d51cSLukasz Lasek struct ftl_layout_tracker_bdev *layout_tracker, enum ftl_layout_region_type reg_type) 8665555d51cSLukasz Lasek { 8675555d51cSLukasz Lasek const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 8685555d51cSLukasz Lasek 8695555d51cSLukasz Lasek ftl_layout_tracker_bdev_find_next_region(layout_tracker, reg_type, ®_search_ctx); 8705555d51cSLukasz Lasek if (reg_search_ctx) { 8715555d51cSLukasz Lasek return; 8725555d51cSLukasz Lasek } 8735555d51cSLukasz Lasek 8745555d51cSLukasz Lasek dev->layout.region[reg_type].type = reg_type; 8755555d51cSLukasz Lasek dev->layout.region[reg_type].current.version = 0; 8765555d51cSLukasz Lasek dev->layout.region[reg_type].current.offset = UINT64_MAX; 8775555d51cSLukasz Lasek dev->layout.region[reg_type].current.blocks = 0; 8785555d51cSLukasz Lasek } 879