1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk/stdinc.h" 35 36 #include "spdk_cunit.h" 37 #include "common/lib/test_env.c" 38 39 #include "ftl/ftl_core.c" 40 #include "ftl/ftl_band.c" 41 #include "../common/utils.c" 42 43 #define TEST_BAND_IDX 68 44 #define TEST_LBA 0x68676564 45 46 struct base_bdev_geometry g_geo = { 47 .write_unit_size = 16, 48 .optimal_open_zones = 9, 49 .zone_size = 100, 50 .blockcnt = 1500 * 100 * 8, 51 }; 52 53 static struct spdk_ftl_dev *g_dev; 54 static struct ftl_band *g_band; 55 56 static void 57 setup_band(void) 58 { 59 int rc; 60 61 g_dev = test_init_ftl_dev(&g_geo); 62 g_band = test_init_ftl_band(g_dev, TEST_BAND_IDX, g_geo.zone_size); 63 rc = ftl_band_alloc_lba_map(g_band); 64 CU_ASSERT_EQUAL_FATAL(rc, 0); 65 } 66 67 static void 68 cleanup_band(void) 69 { 70 test_free_ftl_band(g_band); 71 test_free_ftl_dev(g_dev); 72 } 73 74 static struct ftl_addr 75 addr_from_punit(uint64_t punit) 76 { 77 struct ftl_addr addr = {}; 78 79 addr.offset = punit * g_geo.zone_size; 80 return addr; 81 } 82 83 static void 84 test_band_block_offset_from_addr_base(void) 85 { 86 struct ftl_addr addr; 87 uint64_t offset, i, flat_lun = 0; 88 89 setup_band(); 90 for (i = 0; i < ftl_get_num_punits(g_dev); ++i) { 91 addr = addr_from_punit(i); 92 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 93 94 offset = ftl_band_block_offset_from_addr(g_band, addr); 95 CU_ASSERT_EQUAL(offset, flat_lun * ftl_get_num_blocks_in_zone(g_dev)); 96 flat_lun++; 97 } 98 cleanup_band(); 99 } 100 101 static void 102 test_band_block_offset_from_addr_offset(void) 103 { 104 struct ftl_addr addr; 105 uint64_t offset, expect, i, j; 106 107 setup_band(); 108 for (i = 0; i < ftl_get_num_punits(g_dev); ++i) { 109 for (j = 0; j < g_geo.zone_size; ++j) { 110 addr = addr_from_punit(i); 111 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev) + j; 112 113 offset = ftl_band_block_offset_from_addr(g_band, addr); 114 115 expect = test_offset_from_addr(addr, g_band); 116 CU_ASSERT_EQUAL(offset, expect); 117 } 118 } 119 cleanup_band(); 120 } 121 122 static void 123 test_band_addr_from_block_offset(void) 124 { 125 struct ftl_addr addr, expect; 126 uint64_t offset, i, j; 127 128 setup_band(); 129 for (i = 0; i < ftl_get_num_punits(g_dev); ++i) { 130 for (j = 0; j < g_geo.zone_size; ++j) { 131 expect = addr_from_punit(i); 132 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev) + j; 133 134 offset = ftl_band_block_offset_from_addr(g_band, expect); 135 addr = ftl_band_addr_from_block_offset(g_band, offset); 136 137 CU_ASSERT_EQUAL(addr.offset, expect.offset); 138 } 139 } 140 cleanup_band(); 141 } 142 143 static void 144 test_band_set_addr(void) 145 { 146 struct ftl_lba_map *lba_map; 147 struct ftl_addr addr; 148 uint64_t offset = 0; 149 150 setup_band(); 151 lba_map = &g_band->lba_map; 152 addr = addr_from_punit(0); 153 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 154 155 CU_ASSERT_EQUAL(lba_map->num_vld, 0); 156 157 offset = test_offset_from_addr(addr, g_band); 158 159 ftl_band_set_addr(g_band, TEST_LBA, addr); 160 CU_ASSERT_EQUAL(lba_map->num_vld, 1); 161 CU_ASSERT_EQUAL(lba_map->map[offset], TEST_LBA); 162 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset)); 163 164 addr.offset += g_geo.zone_size; 165 offset = test_offset_from_addr(addr, g_band); 166 ftl_band_set_addr(g_band, TEST_LBA + 1, addr); 167 CU_ASSERT_EQUAL(lba_map->num_vld, 2); 168 CU_ASSERT_EQUAL(lba_map->map[offset], TEST_LBA + 1); 169 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset)); 170 addr.offset -= g_geo.zone_size; 171 offset = test_offset_from_addr(addr, g_band); 172 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset)); 173 cleanup_band(); 174 } 175 176 static void 177 test_invalidate_addr(void) 178 { 179 struct ftl_lba_map *lba_map; 180 struct ftl_addr addr; 181 uint64_t offset[2]; 182 183 setup_band(); 184 lba_map = &g_band->lba_map; 185 addr = addr_from_punit(0); 186 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 187 offset[0] = test_offset_from_addr(addr, g_band); 188 189 ftl_band_set_addr(g_band, TEST_LBA, addr); 190 CU_ASSERT_EQUAL(lba_map->num_vld, 1); 191 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset[0])); 192 ftl_invalidate_addr(g_band->dev, addr); 193 CU_ASSERT_EQUAL(lba_map->num_vld, 0); 194 CU_ASSERT_FALSE(spdk_bit_array_get(lba_map->vld, offset[0])); 195 196 offset[0] = test_offset_from_addr(addr, g_band); 197 ftl_band_set_addr(g_band, TEST_LBA, addr); 198 addr.offset += g_geo.zone_size; 199 offset[1] = test_offset_from_addr(addr, g_band); 200 ftl_band_set_addr(g_band, TEST_LBA + 1, addr); 201 CU_ASSERT_EQUAL(lba_map->num_vld, 2); 202 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset[0])); 203 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset[1])); 204 ftl_invalidate_addr(g_band->dev, addr); 205 CU_ASSERT_EQUAL(lba_map->num_vld, 1); 206 CU_ASSERT_TRUE(spdk_bit_array_get(lba_map->vld, offset[0])); 207 CU_ASSERT_FALSE(spdk_bit_array_get(lba_map->vld, offset[1])); 208 cleanup_band(); 209 } 210 211 static void 212 test_next_xfer_addr(void) 213 { 214 struct ftl_addr addr, result, expect; 215 216 setup_band(); 217 /* Verify simple one block incremention */ 218 addr = addr_from_punit(0); 219 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 220 expect = addr; 221 expect.offset += 1; 222 223 result = ftl_band_next_xfer_addr(g_band, addr, 1); 224 CU_ASSERT_EQUAL(result.offset, expect.offset); 225 226 /* Verify jumping between zones */ 227 expect = addr_from_punit(1); 228 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 229 result = ftl_band_next_xfer_addr(g_band, addr, g_dev->xfer_size); 230 CU_ASSERT_EQUAL(result.offset, expect.offset); 231 232 /* Verify jumping works with unaligned offsets */ 233 expect = addr_from_punit(1); 234 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev) + 3; 235 result = ftl_band_next_xfer_addr(g_band, addr, g_dev->xfer_size + 3); 236 CU_ASSERT_EQUAL(result.offset, expect.offset); 237 238 /* Verify jumping from last zone to the first one */ 239 expect = addr_from_punit(0); 240 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev) + g_dev->xfer_size; 241 addr = addr_from_punit(ftl_get_num_punits(g_dev) - 1); 242 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 243 result = ftl_band_next_xfer_addr(g_band, addr, g_dev->xfer_size); 244 CU_ASSERT_EQUAL(result.offset, expect.offset); 245 246 /* Verify jumping from last zone to the first one with unaligned offset */ 247 expect = addr_from_punit(0); 248 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 249 expect.offset += g_dev->xfer_size + 2; 250 addr = addr_from_punit(ftl_get_num_punits(g_dev) - 1); 251 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 252 result = ftl_band_next_xfer_addr(g_band, addr, g_dev->xfer_size + 2); 253 CU_ASSERT_EQUAL(result.offset, expect.offset); 254 255 /* Verify large offset spanning across the whole band multiple times */ 256 expect = addr_from_punit(0); 257 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 258 expect.offset += g_dev->xfer_size * 5 + 4; 259 addr = addr_from_punit(0); 260 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 261 addr.offset += g_dev->xfer_size * 2 + 1; 262 result = ftl_band_next_xfer_addr(g_band, addr, 3 * g_dev->xfer_size * 263 ftl_get_num_punits(g_dev) + 3); 264 CU_ASSERT_EQUAL(result.offset, expect.offset); 265 266 /* Remove one zone and verify it's skipped properly */ 267 g_band->zone_buf[1].info.state = SPDK_BDEV_ZONE_STATE_OFFLINE; 268 CIRCLEQ_REMOVE(&g_band->zones, &g_band->zone_buf[1], circleq); 269 g_band->num_zones--; 270 expect = addr_from_punit(2); 271 expect.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 272 expect.offset += g_dev->xfer_size * 5 + 4; 273 addr = addr_from_punit(0); 274 addr.offset += TEST_BAND_IDX * ftl_get_num_blocks_in_band(g_dev); 275 addr.offset += g_dev->xfer_size * 2 + 1; 276 result = ftl_band_next_xfer_addr(g_band, addr, 3 * g_dev->xfer_size * 277 (ftl_get_num_punits(g_dev) - 1) + g_dev->xfer_size + 3); 278 CU_ASSERT_EQUAL(result.offset, expect.offset); 279 cleanup_band(); 280 } 281 282 int 283 main(int argc, char **argv) 284 { 285 CU_pSuite suite = NULL; 286 unsigned int num_failures; 287 288 CU_set_error_action(CUEA_ABORT); 289 CU_initialize_registry(); 290 291 suite = CU_add_suite("ftl_band_suite", NULL, NULL); 292 293 294 CU_ADD_TEST(suite, test_band_block_offset_from_addr_base); 295 CU_ADD_TEST(suite, test_band_block_offset_from_addr_offset); 296 CU_ADD_TEST(suite, test_band_addr_from_block_offset); 297 CU_ADD_TEST(suite, test_band_set_addr); 298 CU_ADD_TEST(suite, test_invalidate_addr); 299 CU_ADD_TEST(suite, test_next_xfer_addr); 300 301 CU_basic_set_mode(CU_BRM_VERBOSE); 302 CU_basic_run_tests(); 303 num_failures = CU_get_number_of_failures(); 304 CU_cleanup_registry(); 305 306 return num_failures; 307 } 308