1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2023 Solidigm All Rights Reserved 3 */ 4 5 #include "ftl_core.h" 6 #include "ftl_io.h" 7 #include "ftl_layout.h" 8 #include "utils/ftl_defs.h" 9 10 struct ftl_pl2_log_item { 11 uint64_t lba; 12 uint64_t num_blocks; 13 uint64_t seq_id; 14 ftl_addr addr; 15 }; 16 #define FTL_P2L_LOG_ITEMS_IN_PAGE ((FTL_BLOCK_SIZE - sizeof(union ftl_md_vss)) / sizeof(struct ftl_pl2_log_item)) 17 #define FTL_P2L_LOG_PAGE_COUNT_DEFAULT 128 18 19 struct ftl_p2l_log_page { 20 union ftl_md_vss hdr; 21 struct ftl_pl2_log_item items[FTL_P2L_LOG_ITEMS_IN_PAGE]; 22 }; 23 SPDK_STATIC_ASSERT(sizeof(struct ftl_p2l_log_page) == FTL_BLOCK_SIZE, "Invalid size of P2L page"); 24 25 struct ftl_p2l_log_page_ctrl { 26 struct ftl_p2l_log_page page; 27 struct ftl_p2l_log *p2l; 28 uint64_t entry_idx; 29 TAILQ_HEAD(, ftl_io) ios; 30 struct ftl_md_io_entry_ctx md_ctx; 31 }; 32 33 struct ftl_p2l_log { 34 struct spdk_ftl_dev *dev; 35 TAILQ_ENTRY(ftl_p2l_log) link; 36 TAILQ_HEAD(, ftl_io) ios; 37 struct ftl_md *md; 38 uint64_t seq_id; 39 struct ftl_mempool *page_pool; 40 uint64_t entry_idx; 41 uint64_t entry_max; 42 ftl_p2l_log_cb cb_fn; 43 uint32_t ref_cnt; 44 bool in_use; 45 46 struct { 47 spdk_ftl_fn cb_fn; 48 void *cb_arg; 49 ftl_p2l_log_rd_cb cb_rd; 50 uint64_t qd; 51 uint64_t idx; 52 uint64_t seq_id; 53 int result; 54 } read_ctx; 55 }; 56 57 static void p2l_log_page_io(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl); 58 static void ftl_p2l_log_read_process(struct ftl_p2l_log *p2l); 59 60 static struct ftl_p2l_log * 61 p2l_log_create(struct spdk_ftl_dev *dev, uint32_t region_type) 62 { 63 struct ftl_p2l_log *p2l; 64 65 p2l = calloc(1, sizeof(struct ftl_p2l_log)); 66 if (!p2l) { 67 return NULL; 68 } 69 70 TAILQ_INIT(&p2l->ios); 71 p2l->dev = dev; 72 p2l->md = dev->layout.md[region_type]; 73 p2l->entry_max = ftl_md_get_buffer_size(p2l->md) / FTL_BLOCK_SIZE; 74 p2l->page_pool = ftl_mempool_create(FTL_P2L_LOG_PAGE_COUNT_DEFAULT, 75 sizeof(struct ftl_p2l_log_page_ctrl), 76 FTL_BLOCK_SIZE, SPDK_ENV_SOCKET_ID_ANY); 77 if (!p2l->page_pool) { 78 goto ERROR; 79 } 80 81 return p2l; 82 ERROR: 83 free(p2l); 84 return NULL; 85 } 86 87 static void 88 p2l_log_destroy(struct ftl_p2l_log *p2l) 89 { 90 if (!p2l) { 91 return; 92 } 93 94 ftl_mempool_destroy(p2l->page_pool); 95 free(p2l); 96 } 97 98 static struct ftl_p2l_log_page_ctrl * 99 p2l_log_get_page(struct ftl_p2l_log *p2l) 100 { 101 struct ftl_p2l_log_page_ctrl *ctrl; 102 103 ctrl = ftl_mempool_get(p2l->page_pool); 104 if (!ctrl) { 105 return NULL; 106 } 107 108 /* Initialize P2L header */ 109 ctrl->page.hdr.p2l_ckpt.seq_id = p2l->seq_id; 110 ctrl->page.hdr.p2l_ckpt.count = 0; 111 ctrl->page.hdr.p2l_ckpt.p2l_checksum = 0; 112 ctrl->page.hdr.p2l_ckpt.idx = ctrl->entry_idx = p2l->entry_idx; 113 114 /* Initialize the page control structure */ 115 ctrl->p2l = p2l; 116 TAILQ_INIT(&ctrl->ios); 117 118 /* Increase P2L page index */ 119 p2l->entry_idx++; 120 121 /* Check if the index exceeding the buffer size */ 122 ftl_bug(p2l->entry_idx > p2l->entry_max); 123 124 return ctrl; 125 } 126 127 static bool 128 l2p_log_page_is_full(struct ftl_p2l_log_page_ctrl *ctrl) 129 { 130 return ctrl->page.hdr.p2l_ckpt.count == FTL_P2L_LOG_ITEMS_IN_PAGE; 131 } 132 133 static void 134 p2l_log_page_free(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl) 135 { 136 ftl_mempool_put(p2l->page_pool, ctrl); 137 } 138 139 static void 140 p2l_log_handle_io_error(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl) 141 { 142 #ifdef SPDK_FTL_RETRY_ON_ERROR 143 p2l_log_page_io(p2l, ctrl); 144 #else 145 ftl_abort(); 146 #endif 147 } 148 149 static uint32_t 150 p2l_log_page_crc(struct ftl_p2l_log_page *page) 151 { 152 uint32_t crc = 0; 153 void *buffer = page; 154 size_t size = sizeof(*page); 155 size_t offset = offsetof(struct ftl_p2l_log_page, hdr.p2l_ckpt.p2l_checksum); 156 157 crc = spdk_crc32c_update(buffer, offset, crc); 158 buffer += offset + sizeof(page->hdr.p2l_ckpt.p2l_checksum); 159 size -= offset + sizeof(page->hdr.p2l_ckpt.p2l_checksum); 160 161 return spdk_crc32c_update(buffer, size, crc); 162 } 163 164 static void 165 p2l_log_page_io_cb(int status, void *arg) 166 { 167 struct ftl_p2l_log_page_ctrl *ctrl = arg; 168 struct ftl_p2l_log *p2l = ctrl->p2l; 169 struct ftl_io *io; 170 171 if (status) { 172 p2l_log_handle_io_error(p2l, ctrl); 173 return; 174 } 175 176 while ((io = TAILQ_FIRST(&ctrl->ios))) { 177 TAILQ_REMOVE(&ctrl->ios, io, queue_entry); 178 p2l->cb_fn(io); 179 } 180 181 p2l_log_page_free(p2l, ctrl); 182 } 183 184 static void 185 p2l_log_page_io(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl) 186 { 187 ctrl->page.hdr.p2l_ckpt.p2l_checksum = p2l_log_page_crc(&ctrl->page); 188 189 ftl_md_persist_entries(p2l->md, ctrl->page.hdr.p2l_ckpt.idx, 1, &ctrl->page, NULL, 190 p2l_log_page_io_cb, 191 ctrl, &ctrl->md_ctx); 192 } 193 194 static void 195 p2l_log_add_io(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl, struct ftl_io *io) 196 { 197 uint64_t i = ctrl->page.hdr.p2l_ckpt.count++; 198 199 assert(i < FTL_P2L_LOG_ITEMS_IN_PAGE); 200 ctrl->page.items[i].lba = io->lba; 201 ctrl->page.items[i].num_blocks = io->num_blocks; 202 ctrl->page.items[i].seq_id = io->nv_cache_chunk->md->seq_id; 203 ctrl->page.items[i].addr = io->addr; 204 205 /* TODO Make sure P2L map is updated respectively */ 206 207 TAILQ_REMOVE(&p2l->ios, io, queue_entry); 208 TAILQ_INSERT_TAIL(&ctrl->ios, io, queue_entry); 209 } 210 211 void 212 ftl_p2l_log_io(struct ftl_p2l_log *p2l, struct ftl_io *io) 213 { 214 TAILQ_INSERT_TAIL(&p2l->ios, io, queue_entry); 215 } 216 217 static void 218 p2l_log_flush(struct ftl_p2l_log *p2l) 219 { 220 struct ftl_p2l_log_page_ctrl *ctrl = NULL; 221 struct ftl_io *io; 222 223 while ((io = TAILQ_FIRST(&p2l->ios))) { 224 if (!ctrl) { 225 ctrl = p2l_log_get_page(p2l); 226 if (!ctrl) { 227 /* No page at the moment, try next time */ 228 break; 229 } 230 } 231 232 p2l_log_add_io(p2l, ctrl, io); 233 234 if (l2p_log_page_is_full(ctrl)) { 235 p2l_log_page_io(p2l, ctrl); 236 ctrl = NULL; 237 } 238 } 239 240 if (ctrl) { 241 p2l_log_page_io(p2l, ctrl); 242 } 243 } 244 245 void 246 ftl_p2l_log_flush(struct spdk_ftl_dev *dev) 247 { 248 struct ftl_p2l_log *p2l; 249 250 TAILQ_FOREACH(p2l, &dev->p2l_ckpt.log.inuse, link) { 251 p2l_log_flush(p2l); 252 } 253 } 254 255 uint64_t 256 ftl_p2l_log_get_md_blocks_required(struct spdk_ftl_dev *dev, uint64_t write_unit_blocks, 257 uint64_t max_user_data_blocks) 258 { 259 return spdk_divide_round_up(max_user_data_blocks, write_unit_blocks); 260 } 261 262 int 263 ftl_p2l_log_init(struct spdk_ftl_dev *dev) 264 { 265 struct ftl_p2l_log *p2l; 266 uint32_t region_type; 267 268 TAILQ_INIT(&dev->p2l_ckpt.log.free); 269 TAILQ_INIT(&dev->p2l_ckpt.log.inuse); 270 271 for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN; 272 region_type <= FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX; 273 region_type++) { 274 p2l = p2l_log_create(dev, region_type); 275 if (!p2l) { 276 return -ENOMEM; 277 } 278 279 TAILQ_INSERT_TAIL(&dev->p2l_ckpt.log.free, p2l, link); 280 } 281 282 return 0; 283 } 284 285 void 286 ftl_p2l_log_deinit(struct spdk_ftl_dev *dev) 287 { 288 struct ftl_p2l_log *p2l, *p2l_next; 289 290 TAILQ_FOREACH_SAFE(p2l, &dev->p2l_ckpt.log.free, link, p2l_next) { 291 TAILQ_REMOVE(&dev->p2l_ckpt.log.free, p2l, link); 292 p2l_log_destroy(p2l); 293 } 294 295 TAILQ_FOREACH_SAFE(p2l, &dev->p2l_ckpt.log.inuse, link, p2l_next) { 296 TAILQ_REMOVE(&dev->p2l_ckpt.log.inuse, p2l, link); 297 p2l_log_destroy(p2l); 298 } 299 } 300 301 enum ftl_layout_region_type 302 ftl_p2l_log_type(struct ftl_p2l_log *p2l) { 303 return p2l->md->region->type; 304 } 305 306 struct ftl_p2l_log * 307 ftl_p2l_log_acquire(struct spdk_ftl_dev *dev, uint64_t seq_id, ftl_p2l_log_cb cb) 308 { 309 struct ftl_p2l_log *p2l; 310 311 p2l = TAILQ_FIRST(&dev->p2l_ckpt.log.free); 312 assert(p2l); 313 TAILQ_REMOVE(&dev->p2l_ckpt.log.free, p2l, link); 314 TAILQ_INSERT_TAIL(&dev->p2l_ckpt.log.inuse, p2l, link); 315 316 p2l->entry_idx = 0; 317 p2l->seq_id = seq_id; 318 p2l->cb_fn = cb; 319 320 return p2l; 321 } 322 323 void 324 ftl_p2l_log_release(struct spdk_ftl_dev *dev, struct ftl_p2l_log *p2l) 325 { 326 assert(p2l); 327 328 /* TODO: Add assert if no ongoing IOs on the P2L log */ 329 /* TODO: Add assert if the P2L log already open */ 330 331 TAILQ_REMOVE(&dev->p2l_ckpt.log.inuse, p2l, link); 332 TAILQ_INSERT_TAIL(&dev->p2l_ckpt.log.free, p2l, link); 333 } 334 335 static struct ftl_p2l_log * 336 p2l_log_get(struct spdk_ftl_dev *dev, enum ftl_layout_region_type type) 337 { 338 struct ftl_p2l_log *p2l_Log; 339 340 TAILQ_FOREACH(p2l_Log, &dev->p2l_ckpt.log.free, link) { 341 if (type == p2l_Log->md->region->type) { 342 return p2l_Log; 343 } 344 } 345 346 TAILQ_FOREACH(p2l_Log, &dev->p2l_ckpt.log.inuse, link) { 347 if (type == p2l_Log->md->region->type) { 348 return p2l_Log; 349 } 350 } 351 352 return NULL; 353 } 354 355 static bool 356 p2l_log_read_in_progress(struct ftl_p2l_log *p2l) 357 { 358 return p2l->read_ctx.cb_fn ? true : false; 359 } 360 361 static bool 362 ftl_p2l_log_read_is_next(struct ftl_p2l_log *p2l) 363 { 364 if (p2l->read_ctx.result) { 365 return false; 366 } 367 368 return p2l->read_ctx.idx < p2l->entry_max; 369 } 370 371 static bool 372 ftl_p2l_log_read_is_qd(struct ftl_p2l_log *p2l) 373 { 374 return p2l->read_ctx.qd > 0; 375 } 376 377 static bool 378 ftl_p2l_log_read_is_finished(struct ftl_p2l_log *p2l) 379 { 380 if (ftl_p2l_log_read_is_next(p2l) || ftl_p2l_log_read_is_qd(p2l)) { 381 return false; 382 } 383 384 return true; 385 } 386 387 static void 388 ftl_p2l_log_read_finish(struct ftl_p2l_log *p2l) 389 { 390 spdk_ftl_fn cb_fn = p2l->read_ctx.cb_fn; 391 void *cb_arg = p2l->read_ctx.cb_arg; 392 int result = p2l->read_ctx.result; 393 394 memset(&p2l->read_ctx, 0, sizeof(p2l->read_ctx)); 395 cb_fn(cb_arg, result); 396 } 397 398 static void 399 ftl_p2l_log_read_visit(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl) 400 { 401 struct ftl_p2l_log_page *page = &ctrl->page; 402 struct spdk_ftl_dev *dev = p2l->dev; 403 ftl_p2l_log_rd_cb cb_rd = p2l->read_ctx.cb_rd; 404 void *cb_arg = p2l->read_ctx.cb_arg; 405 uint64_t crc = p2l_log_page_crc(&ctrl->page); 406 uint64_t i, j; 407 int rc = 0; 408 409 ftl_bug(ctrl->entry_idx > p2l->entry_max); 410 411 if (p2l->read_ctx.seq_id != page->hdr.p2l_ckpt.seq_id) { 412 /* This page contains entires older than the owner's sequence ID */ 413 return; 414 } 415 416 if (ctrl->entry_idx != page->hdr.p2l_ckpt.idx) { 417 FTL_ERRLOG(p2l->dev, "Read P2L IO Logs ERROR, invalid index, type %d\n", 418 p2l->md->region->type); 419 p2l->read_ctx.result = -EINVAL; 420 return; 421 } 422 423 if (crc != page->hdr.p2l_ckpt.p2l_checksum) { 424 FTL_ERRLOG(p2l->dev, "Read P2L IO Log ERROR, CRC problem, type %d\n", 425 p2l->md->region->type); 426 p2l->read_ctx.result = -EINVAL; 427 return; 428 } 429 430 if (page->hdr.p2l_ckpt.count > SPDK_COUNTOF(page->items)) { 431 FTL_ERRLOG(p2l->dev, "Read P2L IO Log ERROR, inconsistent format, type %d\n", 432 p2l->md->region->type); 433 p2l->read_ctx.result = -EINVAL; 434 return; 435 } 436 437 for (i = 0; i < page->hdr.p2l_ckpt.count; i++) { 438 struct ftl_pl2_log_item *item = &page->items[i]; 439 440 for (j = 0; j < item->num_blocks; j++) { 441 rc = cb_rd(dev, cb_arg, item->lba + j, item->addr + j, item->seq_id); 442 if (rc) { 443 p2l->read_ctx.result = rc; 444 break; 445 } 446 } 447 448 if (rc) { 449 break; 450 } 451 } 452 } 453 454 static void 455 ftl_p2l_log_read_cb(int status, void *arg) 456 { 457 struct ftl_p2l_log_page_ctrl *ctrl = arg; 458 struct ftl_p2l_log *p2l = ctrl->p2l; 459 460 assert(p2l->read_ctx.qd > 0); 461 p2l->read_ctx.qd--; 462 463 if (status) { 464 p2l->read_ctx.result = status; 465 } else { 466 ftl_p2l_log_read_visit(p2l, ctrl); 467 } 468 469 /* Release page control */ 470 ftl_mempool_put(p2l->page_pool, ctrl); 471 ftl_p2l_log_read_process(p2l); 472 } 473 474 static void 475 ftl_p2l_log_read_process(struct ftl_p2l_log *p2l) 476 { 477 struct ftl_p2l_log_page_ctrl *ctrl; 478 479 while (ftl_p2l_log_read_is_next(p2l)) { 480 ctrl = ftl_mempool_get(p2l->page_pool); 481 if (!ctrl) { 482 break; 483 } 484 485 ctrl->p2l = p2l; 486 ctrl->entry_idx = p2l->read_ctx.idx++; 487 488 /* Check if the index exceeding the buffer size */ 489 ftl_bug(p2l->read_ctx.idx > p2l->entry_max); 490 491 p2l->read_ctx.qd++; 492 ftl_md_read_entry(p2l->md, ctrl->entry_idx, &ctrl->page, NULL, 493 ftl_p2l_log_read_cb, ctrl, &ctrl->md_ctx); 494 } 495 496 if (ftl_p2l_log_read_is_finished(p2l)) { 497 ftl_p2l_log_read_finish(p2l); 498 } 499 } 500 501 int 502 ftl_p2l_log_read(struct spdk_ftl_dev *dev, enum ftl_layout_region_type type, uint64_t seq_id, 503 spdk_ftl_fn cb_fn, void *cb_arg, ftl_p2l_log_rd_cb cb_rd) 504 { 505 struct ftl_p2l_log *p2l_log = p2l_log_get(dev, type); 506 507 if (!p2l_log) { 508 FTL_ERRLOG(dev, "Read P2L IO Log ERROR, no such log, type %d\n", type); 509 return -ENODEV; 510 } 511 if (p2l_log_read_in_progress(p2l_log)) { 512 FTL_ERRLOG(dev, "Read P2L IO Log ERROR, read busy, type %d\n", type); 513 return -EBUSY; 514 } 515 516 memset(&p2l_log->read_ctx, 0, sizeof(p2l_log->read_ctx)); 517 p2l_log->read_ctx.cb_fn = cb_fn; 518 p2l_log->read_ctx.cb_arg = cb_arg; 519 p2l_log->read_ctx.cb_rd = cb_rd; 520 p2l_log->read_ctx.seq_id = seq_id; 521 522 ftl_p2l_log_read_process(p2l_log); 523 if (ftl_p2l_log_read_is_qd(p2l_log)) { 524 /* Read in progress */ 525 return 0; 526 } else { 527 FTL_ERRLOG(dev, "Read P2L IO Log ERROR, operation not started, type %d\n", type); 528 return -EINVAL; 529 } 530 } 531