xref: /spdk/lib/ftl/ftl_p2l_log.c (revision f0748d19ce49404c4b41a13eac6f13b78b62b608)
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