1e3f76044SMateusz Kozlowski /* SPDX-License-Identifier: BSD-3-Clause 2e3f76044SMateusz Kozlowski * Copyright 2023 Solidigm All Rights Reserved 3e3f76044SMateusz Kozlowski */ 4e3f76044SMateusz Kozlowski 5e3f76044SMateusz Kozlowski #include "ftl_core.h" 6e3f76044SMateusz Kozlowski #include "ftl_io.h" 76f50be26SMateusz Kozlowski #include "ftl_layout.h" 8e3f76044SMateusz Kozlowski #include "utils/ftl_defs.h" 9e3f76044SMateusz Kozlowski 10e3f76044SMateusz Kozlowski struct ftl_pl2_log_item { 11e3f76044SMateusz Kozlowski uint64_t lba; 12e3f76044SMateusz Kozlowski uint64_t num_blocks; 13e3f76044SMateusz Kozlowski uint64_t seq_id; 146f50be26SMateusz Kozlowski ftl_addr addr; 15e3f76044SMateusz Kozlowski }; 16e3f76044SMateusz Kozlowski #define FTL_P2L_LOG_ITEMS_IN_PAGE ((FTL_BLOCK_SIZE - sizeof(union ftl_md_vss)) / sizeof(struct ftl_pl2_log_item)) 17e3f76044SMateusz Kozlowski #define FTL_P2L_LOG_PAGE_COUNT_DEFAULT 128 18e3f76044SMateusz Kozlowski 19e3f76044SMateusz Kozlowski struct ftl_p2l_log_page { 20e3f76044SMateusz Kozlowski union ftl_md_vss hdr; 21e3f76044SMateusz Kozlowski struct ftl_pl2_log_item items[FTL_P2L_LOG_ITEMS_IN_PAGE]; 22e3f76044SMateusz Kozlowski }; 23e3f76044SMateusz Kozlowski SPDK_STATIC_ASSERT(sizeof(struct ftl_p2l_log_page) == FTL_BLOCK_SIZE, "Invalid size of P2L page"); 24e3f76044SMateusz Kozlowski 25e3f76044SMateusz Kozlowski struct ftl_p2l_log_page_ctrl { 26e3f76044SMateusz Kozlowski struct ftl_p2l_log_page page; 27e3f76044SMateusz Kozlowski struct ftl_p2l_log *p2l; 28e3f76044SMateusz Kozlowski uint64_t entry_idx; 29e3f76044SMateusz Kozlowski TAILQ_HEAD(, ftl_io) ios; 30e3f76044SMateusz Kozlowski struct ftl_md_io_entry_ctx md_ctx; 31e3f76044SMateusz Kozlowski }; 32e3f76044SMateusz Kozlowski 33e3f76044SMateusz Kozlowski struct ftl_p2l_log { 34e3f76044SMateusz Kozlowski struct spdk_ftl_dev *dev; 35e3f76044SMateusz Kozlowski TAILQ_ENTRY(ftl_p2l_log) link; 36e3f76044SMateusz Kozlowski TAILQ_HEAD(, ftl_io) ios; 37e3f76044SMateusz Kozlowski struct ftl_md *md; 38e3f76044SMateusz Kozlowski uint64_t seq_id; 39e3f76044SMateusz Kozlowski struct ftl_mempool *page_pool; 40e3f76044SMateusz Kozlowski uint64_t entry_idx; 416f50be26SMateusz Kozlowski uint64_t entry_max; 42e3f76044SMateusz Kozlowski ftl_p2l_log_cb cb_fn; 436f50be26SMateusz Kozlowski uint32_t ref_cnt; 446f50be26SMateusz Kozlowski bool in_use; 456f50be26SMateusz Kozlowski 466f50be26SMateusz Kozlowski struct { 476f50be26SMateusz Kozlowski spdk_ftl_fn cb_fn; 486f50be26SMateusz Kozlowski void *cb_arg; 496f50be26SMateusz Kozlowski ftl_p2l_log_rd_cb cb_rd; 506f50be26SMateusz Kozlowski uint64_t qd; 516f50be26SMateusz Kozlowski uint64_t idx; 526f50be26SMateusz Kozlowski uint64_t seq_id; 536f50be26SMateusz Kozlowski int result; 546f50be26SMateusz Kozlowski } read_ctx; 55e3f76044SMateusz Kozlowski }; 56e3f76044SMateusz Kozlowski 57e3f76044SMateusz Kozlowski static void p2l_log_page_io(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl); 586f50be26SMateusz Kozlowski static void ftl_p2l_log_read_process(struct ftl_p2l_log *p2l); 59e3f76044SMateusz Kozlowski 60e3f76044SMateusz Kozlowski static struct ftl_p2l_log * 61e3f76044SMateusz Kozlowski p2l_log_create(struct spdk_ftl_dev *dev, uint32_t region_type) 62e3f76044SMateusz Kozlowski { 63e3f76044SMateusz Kozlowski struct ftl_p2l_log *p2l; 64e3f76044SMateusz Kozlowski 65e3f76044SMateusz Kozlowski p2l = calloc(1, sizeof(struct ftl_p2l_log)); 66e3f76044SMateusz Kozlowski if (!p2l) { 67e3f76044SMateusz Kozlowski return NULL; 68e3f76044SMateusz Kozlowski } 69e3f76044SMateusz Kozlowski 70e3f76044SMateusz Kozlowski TAILQ_INIT(&p2l->ios); 71e3f76044SMateusz Kozlowski p2l->dev = dev; 72e3f76044SMateusz Kozlowski p2l->md = dev->layout.md[region_type]; 736f50be26SMateusz Kozlowski p2l->entry_max = ftl_md_get_buffer_size(p2l->md) / FTL_BLOCK_SIZE; 74e3f76044SMateusz Kozlowski p2l->page_pool = ftl_mempool_create(FTL_P2L_LOG_PAGE_COUNT_DEFAULT, 75e3f76044SMateusz Kozlowski sizeof(struct ftl_p2l_log_page_ctrl), 76e3f76044SMateusz Kozlowski FTL_BLOCK_SIZE, SPDK_ENV_SOCKET_ID_ANY); 77e3f76044SMateusz Kozlowski if (!p2l->page_pool) { 78e3f76044SMateusz Kozlowski goto ERROR; 79e3f76044SMateusz Kozlowski } 80e3f76044SMateusz Kozlowski 81e3f76044SMateusz Kozlowski return p2l; 82e3f76044SMateusz Kozlowski ERROR: 83e3f76044SMateusz Kozlowski free(p2l); 84e3f76044SMateusz Kozlowski return NULL; 85e3f76044SMateusz Kozlowski } 86e3f76044SMateusz Kozlowski 87e3f76044SMateusz Kozlowski static void 88e3f76044SMateusz Kozlowski p2l_log_destroy(struct ftl_p2l_log *p2l) 89e3f76044SMateusz Kozlowski { 90e3f76044SMateusz Kozlowski if (!p2l) { 91e3f76044SMateusz Kozlowski return; 92e3f76044SMateusz Kozlowski } 93e3f76044SMateusz Kozlowski 94e3f76044SMateusz Kozlowski ftl_mempool_destroy(p2l->page_pool); 95e3f76044SMateusz Kozlowski free(p2l); 96e3f76044SMateusz Kozlowski } 97e3f76044SMateusz Kozlowski 98e3f76044SMateusz Kozlowski static struct ftl_p2l_log_page_ctrl * 99e3f76044SMateusz Kozlowski p2l_log_get_page(struct ftl_p2l_log *p2l) 100e3f76044SMateusz Kozlowski { 101e3f76044SMateusz Kozlowski struct ftl_p2l_log_page_ctrl *ctrl; 102e3f76044SMateusz Kozlowski 103e3f76044SMateusz Kozlowski ctrl = ftl_mempool_get(p2l->page_pool); 104e3f76044SMateusz Kozlowski if (!ctrl) { 105e3f76044SMateusz Kozlowski return NULL; 106e3f76044SMateusz Kozlowski } 107e3f76044SMateusz Kozlowski 108e3f76044SMateusz Kozlowski /* Initialize P2L header */ 109e3f76044SMateusz Kozlowski ctrl->page.hdr.p2l_ckpt.seq_id = p2l->seq_id; 110e3f76044SMateusz Kozlowski ctrl->page.hdr.p2l_ckpt.count = 0; 111e3f76044SMateusz Kozlowski ctrl->page.hdr.p2l_ckpt.p2l_checksum = 0; 112*f0748d19SMateusz Kozlowski ctrl->page.hdr.p2l_ckpt.idx = ctrl->entry_idx = p2l->entry_idx; 113e3f76044SMateusz Kozlowski 114e3f76044SMateusz Kozlowski /* Initialize the page control structure */ 115e3f76044SMateusz Kozlowski ctrl->p2l = p2l; 116e3f76044SMateusz Kozlowski TAILQ_INIT(&ctrl->ios); 117e3f76044SMateusz Kozlowski 118e3f76044SMateusz Kozlowski /* Increase P2L page index */ 119e3f76044SMateusz Kozlowski p2l->entry_idx++; 1206f50be26SMateusz Kozlowski 1216f50be26SMateusz Kozlowski /* Check if the index exceeding the buffer size */ 1226f50be26SMateusz Kozlowski ftl_bug(p2l->entry_idx > p2l->entry_max); 123e3f76044SMateusz Kozlowski 124e3f76044SMateusz Kozlowski return ctrl; 125e3f76044SMateusz Kozlowski } 126e3f76044SMateusz Kozlowski 127e3f76044SMateusz Kozlowski static bool 128e3f76044SMateusz Kozlowski l2p_log_page_is_full(struct ftl_p2l_log_page_ctrl *ctrl) 129e3f76044SMateusz Kozlowski { 130e3f76044SMateusz Kozlowski return ctrl->page.hdr.p2l_ckpt.count == FTL_P2L_LOG_ITEMS_IN_PAGE; 131e3f76044SMateusz Kozlowski } 132e3f76044SMateusz Kozlowski 133e3f76044SMateusz Kozlowski static void 134e3f76044SMateusz Kozlowski p2l_log_page_free(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl) 135e3f76044SMateusz Kozlowski { 136e3f76044SMateusz Kozlowski ftl_mempool_put(p2l->page_pool, ctrl); 137e3f76044SMateusz Kozlowski } 138e3f76044SMateusz Kozlowski 139e3f76044SMateusz Kozlowski static void 140e3f76044SMateusz Kozlowski p2l_log_handle_io_error(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl) 141e3f76044SMateusz Kozlowski { 142e3f76044SMateusz Kozlowski #ifdef SPDK_FTL_RETRY_ON_ERROR 143e3f76044SMateusz Kozlowski p2l_log_page_io(p2l, ctrl); 144e3f76044SMateusz Kozlowski #else 145e3f76044SMateusz Kozlowski ftl_abort(); 146e3f76044SMateusz Kozlowski #endif 147e3f76044SMateusz Kozlowski } 148e3f76044SMateusz Kozlowski 149e3f76044SMateusz Kozlowski static uint32_t 150e3f76044SMateusz Kozlowski p2l_log_page_crc(struct ftl_p2l_log_page *page) 151e3f76044SMateusz Kozlowski { 152e3f76044SMateusz Kozlowski uint32_t crc = 0; 153e3f76044SMateusz Kozlowski void *buffer = page; 154e3f76044SMateusz Kozlowski size_t size = sizeof(*page); 155e3f76044SMateusz Kozlowski size_t offset = offsetof(struct ftl_p2l_log_page, hdr.p2l_ckpt.p2l_checksum); 156e3f76044SMateusz Kozlowski 157e3f76044SMateusz Kozlowski crc = spdk_crc32c_update(buffer, offset, crc); 158e3f76044SMateusz Kozlowski buffer += offset + sizeof(page->hdr.p2l_ckpt.p2l_checksum); 159e3f76044SMateusz Kozlowski size -= offset + sizeof(page->hdr.p2l_ckpt.p2l_checksum); 160e3f76044SMateusz Kozlowski 161e3f76044SMateusz Kozlowski return spdk_crc32c_update(buffer, size, crc); 162e3f76044SMateusz Kozlowski } 163e3f76044SMateusz Kozlowski 164e3f76044SMateusz Kozlowski static void 165e3f76044SMateusz Kozlowski p2l_log_page_io_cb(int status, void *arg) 166e3f76044SMateusz Kozlowski { 167e3f76044SMateusz Kozlowski struct ftl_p2l_log_page_ctrl *ctrl = arg; 168e3f76044SMateusz Kozlowski struct ftl_p2l_log *p2l = ctrl->p2l; 169e3f76044SMateusz Kozlowski struct ftl_io *io; 170e3f76044SMateusz Kozlowski 171e3f76044SMateusz Kozlowski if (status) { 172e3f76044SMateusz Kozlowski p2l_log_handle_io_error(p2l, ctrl); 173e3f76044SMateusz Kozlowski return; 174e3f76044SMateusz Kozlowski } 175e3f76044SMateusz Kozlowski 176e3f76044SMateusz Kozlowski while ((io = TAILQ_FIRST(&ctrl->ios))) { 177e3f76044SMateusz Kozlowski TAILQ_REMOVE(&ctrl->ios, io, queue_entry); 178e3f76044SMateusz Kozlowski p2l->cb_fn(io); 179e3f76044SMateusz Kozlowski } 180e3f76044SMateusz Kozlowski 181e3f76044SMateusz Kozlowski p2l_log_page_free(p2l, ctrl); 182e3f76044SMateusz Kozlowski } 183e3f76044SMateusz Kozlowski 184e3f76044SMateusz Kozlowski static void 185e3f76044SMateusz Kozlowski p2l_log_page_io(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl) 186e3f76044SMateusz Kozlowski { 187e3f76044SMateusz Kozlowski ctrl->page.hdr.p2l_ckpt.p2l_checksum = p2l_log_page_crc(&ctrl->page); 188*f0748d19SMateusz Kozlowski 189*f0748d19SMateusz Kozlowski ftl_md_persist_entries(p2l->md, ctrl->page.hdr.p2l_ckpt.idx, 1, &ctrl->page, NULL, 190*f0748d19SMateusz Kozlowski p2l_log_page_io_cb, 191e3f76044SMateusz Kozlowski ctrl, &ctrl->md_ctx); 192e3f76044SMateusz Kozlowski } 193e3f76044SMateusz Kozlowski 194e3f76044SMateusz Kozlowski static void 195e3f76044SMateusz Kozlowski p2l_log_add_io(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl, struct ftl_io *io) 196e3f76044SMateusz Kozlowski { 197e3f76044SMateusz Kozlowski uint64_t i = ctrl->page.hdr.p2l_ckpt.count++; 198e3f76044SMateusz Kozlowski 199e3f76044SMateusz Kozlowski assert(i < FTL_P2L_LOG_ITEMS_IN_PAGE); 200e3f76044SMateusz Kozlowski ctrl->page.items[i].lba = io->lba; 201e3f76044SMateusz Kozlowski ctrl->page.items[i].num_blocks = io->num_blocks; 202e3f76044SMateusz Kozlowski ctrl->page.items[i].seq_id = io->nv_cache_chunk->md->seq_id; 203e3f76044SMateusz Kozlowski ctrl->page.items[i].addr = io->addr; 204e3f76044SMateusz Kozlowski 205e3f76044SMateusz Kozlowski /* TODO Make sure P2L map is updated respectively */ 206e3f76044SMateusz Kozlowski 207e3f76044SMateusz Kozlowski TAILQ_REMOVE(&p2l->ios, io, queue_entry); 208e3f76044SMateusz Kozlowski TAILQ_INSERT_TAIL(&ctrl->ios, io, queue_entry); 209e3f76044SMateusz Kozlowski } 210e3f76044SMateusz Kozlowski 211e3f76044SMateusz Kozlowski void 212e3f76044SMateusz Kozlowski ftl_p2l_log_io(struct ftl_p2l_log *p2l, struct ftl_io *io) 213e3f76044SMateusz Kozlowski { 214e3f76044SMateusz Kozlowski TAILQ_INSERT_TAIL(&p2l->ios, io, queue_entry); 215e3f76044SMateusz Kozlowski } 216e3f76044SMateusz Kozlowski 217e3f76044SMateusz Kozlowski static void 218e3f76044SMateusz Kozlowski p2l_log_flush(struct ftl_p2l_log *p2l) 219e3f76044SMateusz Kozlowski { 220e3f76044SMateusz Kozlowski struct ftl_p2l_log_page_ctrl *ctrl = NULL; 221e3f76044SMateusz Kozlowski struct ftl_io *io; 222e3f76044SMateusz Kozlowski 223e3f76044SMateusz Kozlowski while ((io = TAILQ_FIRST(&p2l->ios))) { 224e3f76044SMateusz Kozlowski if (!ctrl) { 225e3f76044SMateusz Kozlowski ctrl = p2l_log_get_page(p2l); 226e3f76044SMateusz Kozlowski if (!ctrl) { 227e3f76044SMateusz Kozlowski /* No page at the moment, try next time */ 228e3f76044SMateusz Kozlowski break; 229e3f76044SMateusz Kozlowski } 230e3f76044SMateusz Kozlowski } 231e3f76044SMateusz Kozlowski 232e3f76044SMateusz Kozlowski p2l_log_add_io(p2l, ctrl, io); 233e3f76044SMateusz Kozlowski 234e3f76044SMateusz Kozlowski if (l2p_log_page_is_full(ctrl)) { 235e3f76044SMateusz Kozlowski p2l_log_page_io(p2l, ctrl); 236e3f76044SMateusz Kozlowski ctrl = NULL; 237e3f76044SMateusz Kozlowski } 238e3f76044SMateusz Kozlowski } 239e3f76044SMateusz Kozlowski 240e3f76044SMateusz Kozlowski if (ctrl) { 241e3f76044SMateusz Kozlowski p2l_log_page_io(p2l, ctrl); 242e3f76044SMateusz Kozlowski } 243e3f76044SMateusz Kozlowski } 244e3f76044SMateusz Kozlowski 245e3f76044SMateusz Kozlowski void 246e3f76044SMateusz Kozlowski ftl_p2l_log_flush(struct spdk_ftl_dev *dev) 247e3f76044SMateusz Kozlowski { 248e3f76044SMateusz Kozlowski struct ftl_p2l_log *p2l; 249e3f76044SMateusz Kozlowski 250e3f76044SMateusz Kozlowski TAILQ_FOREACH(p2l, &dev->p2l_ckpt.log.inuse, link) { 251e3f76044SMateusz Kozlowski p2l_log_flush(p2l); 252e3f76044SMateusz Kozlowski } 253e3f76044SMateusz Kozlowski } 254e3f76044SMateusz Kozlowski 255e3f76044SMateusz Kozlowski uint64_t 256e3f76044SMateusz Kozlowski ftl_p2l_log_get_md_blocks_required(struct spdk_ftl_dev *dev, uint64_t write_unit_blocks, 257e3f76044SMateusz Kozlowski uint64_t max_user_data_blocks) 258e3f76044SMateusz Kozlowski { 259e3f76044SMateusz Kozlowski return spdk_divide_round_up(max_user_data_blocks, write_unit_blocks); 260e3f76044SMateusz Kozlowski } 261e3f76044SMateusz Kozlowski 262e3f76044SMateusz Kozlowski int 263e3f76044SMateusz Kozlowski ftl_p2l_log_init(struct spdk_ftl_dev *dev) 264e3f76044SMateusz Kozlowski { 265e3f76044SMateusz Kozlowski struct ftl_p2l_log *p2l; 266e3f76044SMateusz Kozlowski uint32_t region_type; 267e3f76044SMateusz Kozlowski 268e3f76044SMateusz Kozlowski TAILQ_INIT(&dev->p2l_ckpt.log.free); 269e3f76044SMateusz Kozlowski TAILQ_INIT(&dev->p2l_ckpt.log.inuse); 270e3f76044SMateusz Kozlowski 271e3f76044SMateusz Kozlowski for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN; 272e3f76044SMateusz Kozlowski region_type <= FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX; 273e3f76044SMateusz Kozlowski region_type++) { 274e3f76044SMateusz Kozlowski p2l = p2l_log_create(dev, region_type); 275e3f76044SMateusz Kozlowski if (!p2l) { 276e3f76044SMateusz Kozlowski return -ENOMEM; 277e3f76044SMateusz Kozlowski } 278e3f76044SMateusz Kozlowski 279e3f76044SMateusz Kozlowski TAILQ_INSERT_TAIL(&dev->p2l_ckpt.log.free, p2l, link); 280e3f76044SMateusz Kozlowski } 281e3f76044SMateusz Kozlowski 282e3f76044SMateusz Kozlowski return 0; 283e3f76044SMateusz Kozlowski } 284e3f76044SMateusz Kozlowski 285e3f76044SMateusz Kozlowski void 286e3f76044SMateusz Kozlowski ftl_p2l_log_deinit(struct spdk_ftl_dev *dev) 287e3f76044SMateusz Kozlowski { 288e3f76044SMateusz Kozlowski struct ftl_p2l_log *p2l, *p2l_next; 289e3f76044SMateusz Kozlowski 290e3f76044SMateusz Kozlowski TAILQ_FOREACH_SAFE(p2l, &dev->p2l_ckpt.log.free, link, p2l_next) { 291e3f76044SMateusz Kozlowski TAILQ_REMOVE(&dev->p2l_ckpt.log.free, p2l, link); 292e3f76044SMateusz Kozlowski p2l_log_destroy(p2l); 293e3f76044SMateusz Kozlowski } 294e3f76044SMateusz Kozlowski 295e3f76044SMateusz Kozlowski TAILQ_FOREACH_SAFE(p2l, &dev->p2l_ckpt.log.inuse, link, p2l_next) { 296e3f76044SMateusz Kozlowski TAILQ_REMOVE(&dev->p2l_ckpt.log.inuse, p2l, link); 297e3f76044SMateusz Kozlowski p2l_log_destroy(p2l); 298e3f76044SMateusz Kozlowski } 299e3f76044SMateusz Kozlowski } 300e3f76044SMateusz Kozlowski 301bdca6e74SMateusz Kozlowski enum ftl_layout_region_type 302bdca6e74SMateusz Kozlowski ftl_p2l_log_type(struct ftl_p2l_log *p2l) { 303bdca6e74SMateusz Kozlowski return p2l->md->region->type; 304bdca6e74SMateusz Kozlowski } 305e3f76044SMateusz Kozlowski 306e3f76044SMateusz Kozlowski struct ftl_p2l_log * 307e3f76044SMateusz Kozlowski ftl_p2l_log_acquire(struct spdk_ftl_dev *dev, uint64_t seq_id, ftl_p2l_log_cb cb) 308e3f76044SMateusz Kozlowski { 309e3f76044SMateusz Kozlowski struct ftl_p2l_log *p2l; 310e3f76044SMateusz Kozlowski 311e3f76044SMateusz Kozlowski p2l = TAILQ_FIRST(&dev->p2l_ckpt.log.free); 312e3f76044SMateusz Kozlowski assert(p2l); 313e3f76044SMateusz Kozlowski TAILQ_REMOVE(&dev->p2l_ckpt.log.free, p2l, link); 314e3f76044SMateusz Kozlowski TAILQ_INSERT_TAIL(&dev->p2l_ckpt.log.inuse, p2l, link); 315e3f76044SMateusz Kozlowski 316e3f76044SMateusz Kozlowski p2l->entry_idx = 0; 317e3f76044SMateusz Kozlowski p2l->seq_id = seq_id; 318e3f76044SMateusz Kozlowski p2l->cb_fn = cb; 319e3f76044SMateusz Kozlowski 320e3f76044SMateusz Kozlowski return p2l; 321e3f76044SMateusz Kozlowski } 322e3f76044SMateusz Kozlowski 323e3f76044SMateusz Kozlowski void 324e3f76044SMateusz Kozlowski ftl_p2l_log_release(struct spdk_ftl_dev *dev, struct ftl_p2l_log *p2l) 325e3f76044SMateusz Kozlowski { 326e3f76044SMateusz Kozlowski assert(p2l); 327e3f76044SMateusz Kozlowski 328e3f76044SMateusz Kozlowski /* TODO: Add assert if no ongoing IOs on the P2L log */ 329e3f76044SMateusz Kozlowski /* TODO: Add assert if the P2L log already open */ 330e3f76044SMateusz Kozlowski 331e3f76044SMateusz Kozlowski TAILQ_REMOVE(&dev->p2l_ckpt.log.inuse, p2l, link); 332e3f76044SMateusz Kozlowski TAILQ_INSERT_TAIL(&dev->p2l_ckpt.log.free, p2l, link); 333e3f76044SMateusz Kozlowski } 3346f50be26SMateusz Kozlowski 3356f50be26SMateusz Kozlowski static struct ftl_p2l_log * 3366f50be26SMateusz Kozlowski p2l_log_get(struct spdk_ftl_dev *dev, enum ftl_layout_region_type type) 3376f50be26SMateusz Kozlowski { 3386f50be26SMateusz Kozlowski struct ftl_p2l_log *p2l_Log; 3396f50be26SMateusz Kozlowski 3406f50be26SMateusz Kozlowski TAILQ_FOREACH(p2l_Log, &dev->p2l_ckpt.log.free, link) { 3416f50be26SMateusz Kozlowski if (type == p2l_Log->md->region->type) { 3426f50be26SMateusz Kozlowski return p2l_Log; 3436f50be26SMateusz Kozlowski } 3446f50be26SMateusz Kozlowski } 3456f50be26SMateusz Kozlowski 3466f50be26SMateusz Kozlowski TAILQ_FOREACH(p2l_Log, &dev->p2l_ckpt.log.inuse, link) { 3476f50be26SMateusz Kozlowski if (type == p2l_Log->md->region->type) { 3486f50be26SMateusz Kozlowski return p2l_Log; 3496f50be26SMateusz Kozlowski } 3506f50be26SMateusz Kozlowski } 3516f50be26SMateusz Kozlowski 3526f50be26SMateusz Kozlowski return NULL; 3536f50be26SMateusz Kozlowski } 3546f50be26SMateusz Kozlowski 3556f50be26SMateusz Kozlowski static bool 3566f50be26SMateusz Kozlowski p2l_log_read_in_progress(struct ftl_p2l_log *p2l) 3576f50be26SMateusz Kozlowski { 3586f50be26SMateusz Kozlowski return p2l->read_ctx.cb_fn ? true : false; 3596f50be26SMateusz Kozlowski } 3606f50be26SMateusz Kozlowski 3616f50be26SMateusz Kozlowski static bool 3626f50be26SMateusz Kozlowski ftl_p2l_log_read_is_next(struct ftl_p2l_log *p2l) 3636f50be26SMateusz Kozlowski { 3646f50be26SMateusz Kozlowski if (p2l->read_ctx.result) { 3656f50be26SMateusz Kozlowski return false; 3666f50be26SMateusz Kozlowski } 3676f50be26SMateusz Kozlowski 368*f0748d19SMateusz Kozlowski return p2l->read_ctx.idx < p2l->entry_max; 3696f50be26SMateusz Kozlowski } 3706f50be26SMateusz Kozlowski 3716f50be26SMateusz Kozlowski static bool 3726f50be26SMateusz Kozlowski ftl_p2l_log_read_is_qd(struct ftl_p2l_log *p2l) 3736f50be26SMateusz Kozlowski { 3746f50be26SMateusz Kozlowski return p2l->read_ctx.qd > 0; 3756f50be26SMateusz Kozlowski } 3766f50be26SMateusz Kozlowski 3776f50be26SMateusz Kozlowski static bool 3786f50be26SMateusz Kozlowski ftl_p2l_log_read_is_finished(struct ftl_p2l_log *p2l) 3796f50be26SMateusz Kozlowski { 3806f50be26SMateusz Kozlowski if (ftl_p2l_log_read_is_next(p2l) || ftl_p2l_log_read_is_qd(p2l)) { 3816f50be26SMateusz Kozlowski return false; 3826f50be26SMateusz Kozlowski } 3836f50be26SMateusz Kozlowski 3846f50be26SMateusz Kozlowski return true; 3856f50be26SMateusz Kozlowski } 3866f50be26SMateusz Kozlowski 3876f50be26SMateusz Kozlowski static void 3886f50be26SMateusz Kozlowski ftl_p2l_log_read_finish(struct ftl_p2l_log *p2l) 3896f50be26SMateusz Kozlowski { 3906f50be26SMateusz Kozlowski spdk_ftl_fn cb_fn = p2l->read_ctx.cb_fn; 3916f50be26SMateusz Kozlowski void *cb_arg = p2l->read_ctx.cb_arg; 3926f50be26SMateusz Kozlowski int result = p2l->read_ctx.result; 3936f50be26SMateusz Kozlowski 3946f50be26SMateusz Kozlowski memset(&p2l->read_ctx, 0, sizeof(p2l->read_ctx)); 3956f50be26SMateusz Kozlowski cb_fn(cb_arg, result); 3966f50be26SMateusz Kozlowski } 3976f50be26SMateusz Kozlowski 3986f50be26SMateusz Kozlowski static void 3996f50be26SMateusz Kozlowski ftl_p2l_log_read_visit(struct ftl_p2l_log *p2l, struct ftl_p2l_log_page_ctrl *ctrl) 4006f50be26SMateusz Kozlowski { 4016f50be26SMateusz Kozlowski struct ftl_p2l_log_page *page = &ctrl->page; 4026f50be26SMateusz Kozlowski struct spdk_ftl_dev *dev = p2l->dev; 4036f50be26SMateusz Kozlowski ftl_p2l_log_rd_cb cb_rd = p2l->read_ctx.cb_rd; 4046f50be26SMateusz Kozlowski void *cb_arg = p2l->read_ctx.cb_arg; 4056f50be26SMateusz Kozlowski uint64_t crc = p2l_log_page_crc(&ctrl->page); 4066f50be26SMateusz Kozlowski uint64_t i, j; 4076f50be26SMateusz Kozlowski int rc = 0; 4086f50be26SMateusz Kozlowski 409*f0748d19SMateusz Kozlowski ftl_bug(ctrl->entry_idx > p2l->entry_max); 410*f0748d19SMateusz Kozlowski 411*f0748d19SMateusz Kozlowski if (p2l->read_ctx.seq_id != page->hdr.p2l_ckpt.seq_id) { 412*f0748d19SMateusz Kozlowski /* This page contains entires older than the owner's sequence ID */ 413*f0748d19SMateusz Kozlowski return; 414*f0748d19SMateusz Kozlowski } 415*f0748d19SMateusz Kozlowski 416*f0748d19SMateusz Kozlowski if (ctrl->entry_idx != page->hdr.p2l_ckpt.idx) { 417*f0748d19SMateusz Kozlowski FTL_ERRLOG(p2l->dev, "Read P2L IO Logs ERROR, invalid index, type %d\n", 418*f0748d19SMateusz Kozlowski p2l->md->region->type); 419*f0748d19SMateusz Kozlowski p2l->read_ctx.result = -EINVAL; 420*f0748d19SMateusz Kozlowski return; 421*f0748d19SMateusz Kozlowski } 422*f0748d19SMateusz Kozlowski 4236f50be26SMateusz Kozlowski if (crc != page->hdr.p2l_ckpt.p2l_checksum) { 4246f50be26SMateusz Kozlowski FTL_ERRLOG(p2l->dev, "Read P2L IO Log ERROR, CRC problem, type %d\n", 4256f50be26SMateusz Kozlowski p2l->md->region->type); 4266f50be26SMateusz Kozlowski p2l->read_ctx.result = -EINVAL; 4276f50be26SMateusz Kozlowski return; 4286f50be26SMateusz Kozlowski } 4296f50be26SMateusz Kozlowski 4306f50be26SMateusz Kozlowski if (page->hdr.p2l_ckpt.count > SPDK_COUNTOF(page->items)) { 4316f50be26SMateusz Kozlowski FTL_ERRLOG(p2l->dev, "Read P2L IO Log ERROR, inconsistent format, type %d\n", 4326f50be26SMateusz Kozlowski p2l->md->region->type); 4336f50be26SMateusz Kozlowski p2l->read_ctx.result = -EINVAL; 4346f50be26SMateusz Kozlowski return; 4356f50be26SMateusz Kozlowski } 4366f50be26SMateusz Kozlowski 4376f50be26SMateusz Kozlowski for (i = 0; i < page->hdr.p2l_ckpt.count; i++) { 4386f50be26SMateusz Kozlowski struct ftl_pl2_log_item *item = &page->items[i]; 4396f50be26SMateusz Kozlowski 4406f50be26SMateusz Kozlowski for (j = 0; j < item->num_blocks; j++) { 4416f50be26SMateusz Kozlowski rc = cb_rd(dev, cb_arg, item->lba + j, item->addr + j, item->seq_id); 4426f50be26SMateusz Kozlowski if (rc) { 4436f50be26SMateusz Kozlowski p2l->read_ctx.result = rc; 4446f50be26SMateusz Kozlowski break; 4456f50be26SMateusz Kozlowski } 4466f50be26SMateusz Kozlowski } 4476f50be26SMateusz Kozlowski 4486f50be26SMateusz Kozlowski if (rc) { 4496f50be26SMateusz Kozlowski break; 4506f50be26SMateusz Kozlowski } 4516f50be26SMateusz Kozlowski } 4526f50be26SMateusz Kozlowski } 4536f50be26SMateusz Kozlowski 4546f50be26SMateusz Kozlowski static void 4556f50be26SMateusz Kozlowski ftl_p2l_log_read_cb(int status, void *arg) 4566f50be26SMateusz Kozlowski { 4576f50be26SMateusz Kozlowski struct ftl_p2l_log_page_ctrl *ctrl = arg; 4586f50be26SMateusz Kozlowski struct ftl_p2l_log *p2l = ctrl->p2l; 4596f50be26SMateusz Kozlowski 4606f50be26SMateusz Kozlowski assert(p2l->read_ctx.qd > 0); 4616f50be26SMateusz Kozlowski p2l->read_ctx.qd--; 4626f50be26SMateusz Kozlowski 4636f50be26SMateusz Kozlowski if (status) { 4646f50be26SMateusz Kozlowski p2l->read_ctx.result = status; 4656f50be26SMateusz Kozlowski } else { 4666f50be26SMateusz Kozlowski ftl_p2l_log_read_visit(p2l, ctrl); 4676f50be26SMateusz Kozlowski } 4686f50be26SMateusz Kozlowski 4696f50be26SMateusz Kozlowski /* Release page control */ 4706f50be26SMateusz Kozlowski ftl_mempool_put(p2l->page_pool, ctrl); 4716f50be26SMateusz Kozlowski ftl_p2l_log_read_process(p2l); 4726f50be26SMateusz Kozlowski } 4736f50be26SMateusz Kozlowski 4746f50be26SMateusz Kozlowski static void 4756f50be26SMateusz Kozlowski ftl_p2l_log_read_process(struct ftl_p2l_log *p2l) 4766f50be26SMateusz Kozlowski { 4776f50be26SMateusz Kozlowski struct ftl_p2l_log_page_ctrl *ctrl; 4786f50be26SMateusz Kozlowski 4796f50be26SMateusz Kozlowski while (ftl_p2l_log_read_is_next(p2l)) { 4806f50be26SMateusz Kozlowski ctrl = ftl_mempool_get(p2l->page_pool); 4816f50be26SMateusz Kozlowski if (!ctrl) { 4826f50be26SMateusz Kozlowski break; 4836f50be26SMateusz Kozlowski } 4846f50be26SMateusz Kozlowski 4856f50be26SMateusz Kozlowski ctrl->p2l = p2l; 4866f50be26SMateusz Kozlowski ctrl->entry_idx = p2l->read_ctx.idx++; 4876f50be26SMateusz Kozlowski 4886f50be26SMateusz Kozlowski /* Check if the index exceeding the buffer size */ 489*f0748d19SMateusz Kozlowski ftl_bug(p2l->read_ctx.idx > p2l->entry_max); 4906f50be26SMateusz Kozlowski 4916f50be26SMateusz Kozlowski p2l->read_ctx.qd++; 4926f50be26SMateusz Kozlowski ftl_md_read_entry(p2l->md, ctrl->entry_idx, &ctrl->page, NULL, 4936f50be26SMateusz Kozlowski ftl_p2l_log_read_cb, ctrl, &ctrl->md_ctx); 4946f50be26SMateusz Kozlowski } 4956f50be26SMateusz Kozlowski 4966f50be26SMateusz Kozlowski if (ftl_p2l_log_read_is_finished(p2l)) { 4976f50be26SMateusz Kozlowski ftl_p2l_log_read_finish(p2l); 4986f50be26SMateusz Kozlowski } 4996f50be26SMateusz Kozlowski } 5006f50be26SMateusz Kozlowski 5016f50be26SMateusz Kozlowski int 5026f50be26SMateusz Kozlowski ftl_p2l_log_read(struct spdk_ftl_dev *dev, enum ftl_layout_region_type type, uint64_t seq_id, 5036f50be26SMateusz Kozlowski spdk_ftl_fn cb_fn, void *cb_arg, ftl_p2l_log_rd_cb cb_rd) 5046f50be26SMateusz Kozlowski { 5056f50be26SMateusz Kozlowski struct ftl_p2l_log *p2l_log = p2l_log_get(dev, type); 5066f50be26SMateusz Kozlowski 5076f50be26SMateusz Kozlowski if (!p2l_log) { 5086f50be26SMateusz Kozlowski FTL_ERRLOG(dev, "Read P2L IO Log ERROR, no such log, type %d\n", type); 5096f50be26SMateusz Kozlowski return -ENODEV; 5106f50be26SMateusz Kozlowski } 5116f50be26SMateusz Kozlowski if (p2l_log_read_in_progress(p2l_log)) { 5126f50be26SMateusz Kozlowski FTL_ERRLOG(dev, "Read P2L IO Log ERROR, read busy, type %d\n", type); 5136f50be26SMateusz Kozlowski return -EBUSY; 5146f50be26SMateusz Kozlowski } 5156f50be26SMateusz Kozlowski 5166f50be26SMateusz Kozlowski memset(&p2l_log->read_ctx, 0, sizeof(p2l_log->read_ctx)); 5176f50be26SMateusz Kozlowski p2l_log->read_ctx.cb_fn = cb_fn; 5186f50be26SMateusz Kozlowski p2l_log->read_ctx.cb_arg = cb_arg; 5196f50be26SMateusz Kozlowski p2l_log->read_ctx.cb_rd = cb_rd; 520*f0748d19SMateusz Kozlowski p2l_log->read_ctx.seq_id = seq_id; 5216f50be26SMateusz Kozlowski 5226f50be26SMateusz Kozlowski ftl_p2l_log_read_process(p2l_log); 5236f50be26SMateusz Kozlowski if (ftl_p2l_log_read_is_qd(p2l_log)) { 5246f50be26SMateusz Kozlowski /* Read in progress */ 5256f50be26SMateusz Kozlowski return 0; 5266f50be26SMateusz Kozlowski } else { 5276f50be26SMateusz Kozlowski FTL_ERRLOG(dev, "Read P2L IO Log ERROR, operation not started, type %d\n", type); 5286f50be26SMateusz Kozlowski return -EINVAL; 5296f50be26SMateusz Kozlowski } 5306f50be26SMateusz Kozlowski } 531