1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2023 Solidigm All Rights Reserved 3 */ 4 5 #include "ftl_base_dev.h" 6 #include "ftl_core.h" 7 #include "ftl_layout.h" 8 #include "ftl_band.h" 9 #include "utils/ftl_layout_tracker_bdev.h" 10 11 static bool 12 is_bdev_compatible(struct spdk_ftl_dev *dev, struct spdk_bdev *bdev) 13 { 14 uint64_t write_unit_size = spdk_bdev_get_write_unit_size(bdev); 15 16 if (spdk_bdev_get_block_size(bdev) != FTL_BLOCK_SIZE) { 17 FTL_ERRLOG(dev, "Unsupported block size, only 4096 is supprted.\nn"); 18 return false; 19 } 20 21 if (spdk_bdev_get_md_size(bdev) != 0) { 22 /* Bdev's metadata is unsupported */ 23 FTL_ERRLOG(dev, "Unsupported metadata size, sector metadata isn't supported.\n"); 24 return false; 25 } 26 27 if (write_unit_size == 1) { 28 /* No write unit size, all alignments will work out fine */ 29 return true; 30 } 31 32 if (!spdk_u32_is_pow2(write_unit_size) || write_unit_size > (MiB / FTL_BLOCK_SIZE)) { 33 /* Needs to be a power of 2 for current band size (1GiB) restrictions. 34 * Current buffers are allocated in 1MiB sizes (256 blocks), so it can't be larger than that. 35 * In the future, if the restriction is relaxed, the ftl_bitmap_buffer_alignment (64 blocks) 36 * will need to be taken into consideration as well. 37 */ 38 FTL_ERRLOG(dev, 39 "Unsupported write unit size (%lu), must be a power of 2 (in blocks). Can't be larger than 256 (1MiB)\n", 40 write_unit_size); 41 return false; 42 } 43 44 return true; 45 } 46 47 static void 48 md_region_setup(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 49 struct ftl_layout_region *region) 50 { 51 assert(region); 52 region->type = reg_type; 53 region->mirror_type = FTL_LAYOUT_REGION_TYPE_INVALID; 54 region->name = ftl_md_region_name(reg_type); 55 56 region->bdev_desc = dev->base_bdev_desc; 57 region->ioch = dev->base_ioch; 58 region->vss_blksz = 0; 59 } 60 61 static int 62 md_region_create(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, 63 uint32_t reg_version, size_t reg_blks) 64 { 65 const struct ftl_layout_tracker_bdev_region_props *reg_props; 66 uint64_t data_base_alignment; 67 68 assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX); 69 reg_blks = ftl_md_region_align_blocks(dev, reg_blks); 70 71 /* Allocating a ftl_bitmap requires a 8B input buffer alignment, since we're reusing the global valid map md buffer 72 * this means that each band starting address needs to be aligned too - each device sector takes 1b in the valid map, 73 * so 64 sectors (8*8) is the needed alignment 74 */ 75 data_base_alignment = 8 * ftl_bitmap_buffer_alignment; 76 reg_props = ftl_layout_tracker_bdev_add_region(dev->base_layout_tracker, reg_type, reg_version, 77 reg_blks, data_base_alignment); 78 if (!reg_props) { 79 return -1; 80 } 81 assert(reg_props->type == reg_type); 82 assert(reg_props->ver == reg_version); 83 assert(reg_props->blk_sz == reg_blks); 84 assert(reg_props->blk_offs + reg_blks <= dev->layout.base.total_blocks); 85 return 0; 86 } 87 88 static int 89 md_region_open(struct spdk_ftl_dev *dev, enum ftl_layout_region_type reg_type, uint32_t reg_version, 90 size_t entry_size, size_t entry_count, struct ftl_layout_region *region) 91 { 92 const struct ftl_layout_tracker_bdev_region_props *reg_search_ctx = NULL; 93 uint64_t reg_blks = ftl_md_region_blocks(dev, entry_size * entry_count); 94 95 assert(reg_type < FTL_LAYOUT_REGION_TYPE_MAX); 96 97 while (true) { 98 ftl_layout_tracker_bdev_find_next_region(dev->base_layout_tracker, reg_type, ®_search_ctx); 99 if (!reg_search_ctx || reg_search_ctx->ver == reg_version) { 100 break; 101 } 102 } 103 104 if (!reg_search_ctx || reg_search_ctx->blk_sz < reg_blks) { 105 /* Region not found or insufficient space */ 106 return -1; 107 } 108 109 if (!region) { 110 return 0; 111 } 112 113 md_region_setup(dev, reg_type, region); 114 115 region->entry_size = entry_size / FTL_BLOCK_SIZE; 116 region->num_entries = entry_count; 117 118 region->current.version = reg_version; 119 region->current.offset = reg_search_ctx->blk_offs; 120 region->current.blocks = reg_search_ctx->blk_sz; 121 122 return 0; 123 } 124 125 struct ftl_base_device_type base_bdev = { 126 .name = "base_bdev", 127 .ops = { 128 .is_bdev_compatible = is_bdev_compatible, 129 130 .md_layout_ops = { 131 .region_create = md_region_create, 132 .region_open = md_region_open, 133 }, 134 } 135 }; 136 FTL_BASE_DEVICE_TYPE_REGISTER(base_bdev) 137