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 static struct spdk_ocssd_geometry_data g_geo = { 47 .num_grp = 4, 48 .num_pu = 3, 49 .num_chk = 1500, 50 .clba = 100, 51 .ws_opt = 16, 52 .ws_min = 4, 53 }; 54 55 static struct spdk_ftl_punit_range g_range = { 56 .begin = 2, 57 .end = 9, 58 }; 59 60 static struct spdk_ftl_dev *g_dev; 61 static struct ftl_band *g_band; 62 63 static void 64 setup_band(void) 65 { 66 int rc; 67 68 g_dev = test_init_ftl_dev(&g_geo, &g_range); 69 g_band = test_init_ftl_band(g_dev, TEST_BAND_IDX); 70 rc = ftl_band_alloc_md(g_band); 71 CU_ASSERT_EQUAL_FATAL(rc, 0); 72 } 73 74 static void 75 cleanup_band(void) 76 { 77 test_free_ftl_band(g_band); 78 test_free_ftl_dev(g_dev); 79 } 80 81 static struct ftl_ppa 82 ppa_from_punit(uint64_t punit) 83 { 84 struct ftl_ppa ppa = {}; 85 86 ppa.grp = punit % g_geo.num_grp; 87 ppa.pu = punit / g_geo.num_grp; 88 return ppa; 89 } 90 91 static void 92 test_band_lbkoff_from_ppa_base(void) 93 { 94 struct ftl_ppa ppa; 95 uint64_t offset, i, flat_lun = 0; 96 97 setup_band(); 98 for (i = g_range.begin; i < g_range.end; ++i) { 99 ppa = ppa_from_punit(i); 100 ppa.chk = TEST_BAND_IDX; 101 102 offset = ftl_band_lbkoff_from_ppa(g_band, ppa); 103 CU_ASSERT_EQUAL(offset, flat_lun * ftl_dev_lbks_in_chunk(g_dev)); 104 flat_lun++; 105 } 106 cleanup_band(); 107 } 108 109 static void 110 test_band_lbkoff_from_ppa_lbk(void) 111 { 112 struct ftl_ppa ppa; 113 uint64_t offset, expect, i, j; 114 115 setup_band(); 116 for (i = g_range.begin; i < g_range.end; ++i) { 117 for (j = 0; j < g_geo.clba; ++j) { 118 ppa = ppa_from_punit(i); 119 ppa.chk = TEST_BAND_IDX; 120 ppa.lbk = j; 121 122 offset = ftl_band_lbkoff_from_ppa(g_band, ppa); 123 124 expect = test_offset_from_ppa(ppa, g_band); 125 CU_ASSERT_EQUAL(offset, expect); 126 } 127 } 128 cleanup_band(); 129 } 130 131 static void 132 test_band_ppa_from_lbkoff(void) 133 { 134 struct ftl_ppa ppa, expect; 135 uint64_t offset, i, j; 136 137 setup_band(); 138 for (i = g_range.begin; i < g_range.end; ++i) { 139 for (j = 0; j < g_geo.clba; ++j) { 140 expect = ppa_from_punit(i); 141 expect.chk = TEST_BAND_IDX; 142 expect.lbk = j; 143 144 offset = ftl_band_lbkoff_from_ppa(g_band, expect); 145 ppa = ftl_band_ppa_from_lbkoff(g_band, offset); 146 147 CU_ASSERT_EQUAL(ppa.ppa, expect.ppa); 148 } 149 } 150 cleanup_band(); 151 } 152 153 static void 154 test_band_set_addr(void) 155 { 156 struct ftl_md *md; 157 struct ftl_ppa ppa; 158 uint64_t offset = 0; 159 160 setup_band(); 161 md = &g_band->md; 162 ppa = ppa_from_punit(g_range.begin); 163 ppa.chk = TEST_BAND_IDX; 164 165 CU_ASSERT_EQUAL(md->num_vld, 0); 166 167 offset = test_offset_from_ppa(ppa, g_band); 168 169 ftl_band_set_addr(g_band, TEST_LBA, ppa); 170 CU_ASSERT_EQUAL(md->num_vld, 1); 171 CU_ASSERT_EQUAL(md->lba_map[offset], TEST_LBA); 172 CU_ASSERT_TRUE(spdk_bit_array_get(md->vld_map, offset)); 173 174 ppa.pu++; 175 offset = test_offset_from_ppa(ppa, g_band); 176 ftl_band_set_addr(g_band, TEST_LBA + 1, ppa); 177 CU_ASSERT_EQUAL(md->num_vld, 2); 178 CU_ASSERT_EQUAL(md->lba_map[offset], TEST_LBA + 1); 179 CU_ASSERT_TRUE(spdk_bit_array_get(md->vld_map, offset)); 180 ppa.pu--; 181 offset = test_offset_from_ppa(ppa, g_band); 182 CU_ASSERT_TRUE(spdk_bit_array_get(md->vld_map, offset)); 183 cleanup_band(); 184 } 185 186 static void 187 test_invalidate_addr(void) 188 { 189 struct ftl_md *md; 190 struct ftl_ppa ppa; 191 uint64_t offset[2]; 192 193 setup_band(); 194 md = &g_band->md; 195 ppa = ppa_from_punit(g_range.begin); 196 ppa.chk = TEST_BAND_IDX; 197 offset[0] = test_offset_from_ppa(ppa, g_band); 198 199 ftl_band_set_addr(g_band, TEST_LBA, ppa); 200 CU_ASSERT_EQUAL(md->num_vld, 1); 201 CU_ASSERT_TRUE(spdk_bit_array_get(md->vld_map, offset[0])); 202 ftl_invalidate_addr(g_band->dev, ppa); 203 CU_ASSERT_EQUAL(md->num_vld, 0); 204 CU_ASSERT_FALSE(spdk_bit_array_get(md->vld_map, offset[0])); 205 206 offset[0] = test_offset_from_ppa(ppa, g_band); 207 ftl_band_set_addr(g_band, TEST_LBA, ppa); 208 ppa.pu++; 209 offset[1] = test_offset_from_ppa(ppa, g_band); 210 ftl_band_set_addr(g_band, TEST_LBA + 1, ppa); 211 CU_ASSERT_EQUAL(md->num_vld, 2); 212 CU_ASSERT_TRUE(spdk_bit_array_get(md->vld_map, offset[0])); 213 CU_ASSERT_TRUE(spdk_bit_array_get(md->vld_map, offset[1])); 214 ftl_invalidate_addr(g_band->dev, ppa); 215 CU_ASSERT_EQUAL(md->num_vld, 1); 216 CU_ASSERT_TRUE(spdk_bit_array_get(md->vld_map, offset[0])); 217 CU_ASSERT_FALSE(spdk_bit_array_get(md->vld_map, offset[1])); 218 cleanup_band(); 219 } 220 221 static void 222 test_next_xfer_ppa(void) 223 { 224 struct ftl_ppa ppa, result, expect; 225 226 setup_band(); 227 /* Verify simple one lbk incremention */ 228 ppa = ppa_from_punit(g_range.begin); 229 ppa.chk = TEST_BAND_IDX; 230 ppa.lbk = 0; 231 expect = ppa; 232 expect.lbk = 1; 233 234 result = ftl_band_next_xfer_ppa(g_band, ppa, 1); 235 CU_ASSERT_EQUAL(result.ppa, expect.ppa); 236 237 /* Verify jumping between chunks */ 238 expect = ppa_from_punit(g_range.begin + 1); 239 expect.chk = TEST_BAND_IDX; 240 result = ftl_band_next_xfer_ppa(g_band, ppa, g_dev->xfer_size); 241 CU_ASSERT_EQUAL(result.ppa, expect.ppa); 242 243 /* Verify jumping works with unaligned offsets */ 244 expect = ppa_from_punit(g_range.begin + 1); 245 expect.chk = TEST_BAND_IDX; 246 expect.lbk = 3; 247 result = ftl_band_next_xfer_ppa(g_band, ppa, g_dev->xfer_size + 3); 248 CU_ASSERT_EQUAL(result.ppa, expect.ppa); 249 250 /* Verify jumping from last chunk to the first one */ 251 expect = ppa_from_punit(g_range.begin); 252 expect.chk = TEST_BAND_IDX; 253 expect.lbk = g_dev->xfer_size; 254 ppa = ppa_from_punit(g_range.end); 255 ppa.chk = TEST_BAND_IDX; 256 result = ftl_band_next_xfer_ppa(g_band, ppa, g_dev->xfer_size); 257 CU_ASSERT_EQUAL(result.ppa, expect.ppa); 258 259 /* Verify jumping from last chunk to the first one with unaligned offset */ 260 expect = ppa_from_punit(g_range.begin); 261 expect.chk = TEST_BAND_IDX; 262 expect.lbk = g_dev->xfer_size + 2; 263 ppa = ppa_from_punit(g_range.end); 264 ppa.chk = TEST_BAND_IDX; 265 result = ftl_band_next_xfer_ppa(g_band, ppa, g_dev->xfer_size + 2); 266 CU_ASSERT_EQUAL(result.ppa, expect.ppa); 267 268 /* Verify large offset spanning across the whole band multiple times */ 269 expect = ppa_from_punit(g_range.begin); 270 expect.chk = TEST_BAND_IDX; 271 expect.lbk = g_dev->xfer_size * 5 + 4; 272 ppa = ppa_from_punit(g_range.begin); 273 ppa.chk = TEST_BAND_IDX; 274 ppa.lbk = g_dev->xfer_size * 2 + 1; 275 result = ftl_band_next_xfer_ppa(g_band, ppa, 3 * g_dev->xfer_size * 276 ftl_dev_num_punits(g_dev) + 3); 277 CU_ASSERT_EQUAL(result.ppa, expect.ppa); 278 279 /* Remove one chunk and verify it's skipped properly */ 280 g_band->chunk_buf[1].state = FTL_CHUNK_STATE_BAD; 281 CIRCLEQ_REMOVE(&g_band->chunks, &g_band->chunk_buf[1], circleq); 282 g_band->num_chunks--; 283 expect = ppa_from_punit(g_range.begin + 2); 284 expect.chk = TEST_BAND_IDX; 285 expect.lbk = g_dev->xfer_size * 5 + 4; 286 ppa = ppa_from_punit(g_range.begin); 287 ppa.chk = TEST_BAND_IDX; 288 ppa.lbk = g_dev->xfer_size * 2 + 1; 289 result = ftl_band_next_xfer_ppa(g_band, ppa, 3 * g_dev->xfer_size * 290 (ftl_dev_num_punits(g_dev) - 1) + g_dev->xfer_size + 3); 291 CU_ASSERT_EQUAL(result.ppa, expect.ppa); 292 cleanup_band(); 293 } 294 295 int 296 main(int argc, char **argv) 297 { 298 CU_pSuite suite = NULL; 299 unsigned int num_failures; 300 301 if (CU_initialize_registry() != CUE_SUCCESS) { 302 return CU_get_error(); 303 } 304 305 suite = CU_add_suite("ftl_band_suite", NULL, NULL); 306 if (!suite) { 307 CU_cleanup_registry(); 308 return CU_get_error(); 309 } 310 311 if ( 312 CU_add_test(suite, "test_band_lbkoff_from_ppa_base", 313 test_band_lbkoff_from_ppa_base) == NULL 314 || CU_add_test(suite, "test_band_lbkoff_from_ppa_lbk", 315 test_band_lbkoff_from_ppa_lbk) == NULL 316 || CU_add_test(suite, "test_band_ppa_from_lbkoff", 317 test_band_ppa_from_lbkoff) == NULL 318 || CU_add_test(suite, "test_band_set_addr", 319 test_band_set_addr) == NULL 320 || CU_add_test(suite, "test_invalidate_addr", 321 test_invalidate_addr) == NULL 322 || CU_add_test(suite, "test_next_xfer_ppa", 323 test_next_xfer_ppa) == NULL 324 ) { 325 CU_cleanup_registry(); 326 return CU_get_error(); 327 } 328 329 CU_basic_set_mode(CU_BRM_VERBOSE); 330 CU_basic_run_tests(); 331 num_failures = CU_get_number_of_failures(); 332 CU_cleanup_registry(); 333 334 return num_failures; 335 } 336