Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2023 Solidigm All Rights Reserved
3 : : */
4 : :
5 : : #include "ftl_nvc_dev.h"
6 : : #include "ftl_core.h"
7 : : #include "ftl_layout.h"
8 : : #include "ftl_nv_cache.h"
9 : : #include "mngt/ftl_mngt.h"
10 : : #include "ftl_nvc_bdev_common.h"
11 : :
12 : : static void write_io(struct ftl_io *io);
13 : : static void p2l_log_cb(struct ftl_io *io);
14 : :
15 : : static int
16 : 0 : init(struct spdk_ftl_dev *dev)
17 : : {
18 : : int rc;
19 : :
20 : 0 : rc = ftl_p2l_log_init(dev);
21 [ # # ]: 0 : if (rc) {
22 : 0 : return 0;
23 : : }
24 : :
25 : 0 : return 0;
26 : 0 : }
27 : :
28 : : static void
29 : 0 : deinit(struct spdk_ftl_dev *dev)
30 : : {
31 : 0 : ftl_p2l_log_deinit(dev);
32 : 0 : }
33 : :
34 : : static bool
35 : 0 : is_bdev_compatible(struct spdk_ftl_dev *dev, struct spdk_bdev *bdev)
36 : : {
37 [ # # ]: 0 : if (spdk_bdev_get_md_size(bdev) != 0) {
38 : : /* Bdev's metadata is invalid size */
39 : 0 : return false;
40 : : }
41 : :
42 : 0 : return true;
43 : 0 : }
44 : :
45 : : static void
46 : 0 : on_chunk_open(struct spdk_ftl_dev *dev, struct ftl_nv_cache_chunk *chunk)
47 : : {
48 [ # # # # : 0 : assert(NULL == chunk->p2l_log);
# # # # ]
49 [ # # # # : 0 : chunk->p2l_log = ftl_p2l_log_acquire(dev, chunk->md->seq_id, p2l_log_cb);
# # # # #
# # # ]
50 [ # # # # : 0 : chunk->md->p2l_log_type = ftl_p2l_log_type(chunk->p2l_log);
# # # # #
# # # ]
51 : 0 : }
52 : :
53 : : static void
54 : 0 : on_chunk_closed(struct spdk_ftl_dev *dev, struct ftl_nv_cache_chunk *chunk)
55 : : {
56 [ # # # # : 0 : assert(chunk->p2l_log);
# # # # ]
57 [ # # # # ]: 0 : ftl_p2l_log_release(dev, chunk->p2l_log);
58 [ # # # # ]: 0 : chunk->p2l_log = NULL;
59 : 0 : }
60 : :
61 : : static void
62 : 0 : p2l_log_cb(struct ftl_io *io)
63 : : {
64 : 0 : ftl_nv_cache_write_complete(io, true);
65 : 0 : }
66 : :
67 : : static void
68 : 0 : write_io_cb(struct spdk_bdev_io *bdev_io, bool success, void *ctx)
69 : : {
70 : 0 : struct ftl_io *io = ctx;
71 : :
72 [ # # # # ]: 0 : ftl_stats_bdev_io_completed(io->dev, FTL_STATS_TYPE_USER, bdev_io);
73 : 0 : spdk_bdev_free_io(bdev_io);
74 : :
75 [ # # # # ]: 0 : if (spdk_likely(success)) {
76 [ # # # # : 0 : struct ftl_p2l_log *log = io->nv_cache_chunk->p2l_log;
# # # # ]
77 : 0 : ftl_p2l_log_io(log, io);
78 : 0 : } else {
79 : 0 : ftl_nv_cache_write_complete(io, false);
80 : : }
81 : 0 : }
82 : :
83 : : static void
84 : 0 : write_io_retry(void *ctx)
85 : : {
86 : 0 : struct ftl_io *io = ctx;
87 : :
88 : 0 : write_io(io);
89 : 0 : }
90 : :
91 : : static void
92 : 0 : write_io(struct ftl_io *io)
93 : : {
94 [ # # # # ]: 0 : struct spdk_ftl_dev *dev = io->dev;
95 [ # # ]: 0 : struct ftl_nv_cache *nv_cache = &dev->nv_cache;
96 : : int rc;
97 : :
98 [ # # # # : 0 : rc = spdk_bdev_writev_blocks(nv_cache->bdev_desc, nv_cache->cache_ioch,
# # # # ]
99 [ # # # # : 0 : io->iov, io->iov_cnt,
# # # # ]
100 [ # # # # : 0 : ftl_addr_to_nvc_offset(dev, io->addr), io->num_blocks,
# # # # ]
101 : 0 : write_io_cb, io);
102 [ # # ]: 0 : if (spdk_unlikely(rc)) {
103 [ # # ]: 0 : if (rc == -ENOMEM) {
104 [ # # # # ]: 0 : struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(nv_cache->bdev_desc);
105 [ # # # # : 0 : io->bdev_io_wait.bdev = bdev;
# # ]
106 [ # # # # : 0 : io->bdev_io_wait.cb_fn = write_io_retry;
# # ]
107 [ # # # # : 0 : io->bdev_io_wait.cb_arg = io;
# # ]
108 [ # # # # : 0 : spdk_bdev_queue_io_wait(bdev, nv_cache->cache_ioch, &io->bdev_io_wait);
# # ]
109 : 0 : } else {
110 [ # # ]: 0 : ftl_abort();
111 : : }
112 : 0 : }
113 : 0 : }
114 : :
115 : : static void
116 : 0 : process(struct spdk_ftl_dev *dev)
117 : : {
118 : 0 : ftl_p2l_log_flush(dev);
119 : 0 : }
120 : :
121 : : struct recovery_chunk_ctx {
122 : : struct ftl_nv_cache_chunk *chunk;
123 : : };
124 : :
125 : : static void
126 : 0 : recovery_chunk_recover_p2l_map_cb(void *cb_arg, int status)
127 : : {
128 : 0 : struct ftl_mngt_process *mngt = cb_arg;
129 : :
130 [ # # ]: 0 : if (status) {
131 : 0 : ftl_mngt_fail_step(mngt);
132 : 0 : } else {
133 : 0 : ftl_mngt_next_step(mngt);
134 : : }
135 : 0 : }
136 : :
137 : : static int
138 : 0 : recovery_chunk_recover_p2l_map_read_cb(struct spdk_ftl_dev *dev, void *cb_arg,
139 : : uint64_t lba, ftl_addr addr, uint64_t seq_id)
140 : : {
141 : 0 : struct ftl_mngt_process *mngt = cb_arg;
142 : 0 : struct recovery_chunk_ctx *ctx = ftl_mngt_get_process_ctx(mngt);
143 [ # # # # ]: 0 : struct ftl_nv_cache_chunk *chunk = ctx->chunk;
144 : :
145 : 0 : ftl_nv_cache_chunk_set_addr(chunk, lba, addr);
146 : :
147 : : /* TODO We could stop scanning when getting all LBA within the chunk */
148 : 0 : return 0;
149 : : }
150 : :
151 : :
152 : : static void
153 : 0 : recovery_chunk_recover_p2l_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
154 : : {
155 : 0 : struct recovery_chunk_ctx *ctx = ftl_mngt_get_process_ctx(mngt);
156 [ # # # # ]: 0 : struct ftl_nv_cache_chunk *chunk = ctx->chunk;
157 : : int rc;
158 : :
159 [ # # # # : 0 : rc = ftl_p2l_log_read(dev, chunk->md->p2l_log_type, chunk->md->seq_id,
# # # # #
# # # # #
# # ]
160 : 0 : recovery_chunk_recover_p2l_map_cb, mngt,
161 : : recovery_chunk_recover_p2l_map_read_cb);
162 : :
163 [ # # ]: 0 : if (rc) {
164 : 0 : ftl_mngt_fail_step(mngt);
165 : 0 : }
166 : 0 : }
167 : :
168 : : static int
169 : 0 : recovery_chunk_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
170 : : void *init_ctx)
171 : : {
172 : 0 : struct recovery_chunk_ctx *ctx = ftl_mngt_get_process_ctx(mngt);
173 : :
174 [ # # # # ]: 0 : ctx->chunk = init_ctx;
175 : 0 : return 0;
176 : : }
177 : :
178 : : static const struct ftl_mngt_process_desc desc_chunk_recovery = {
179 : : .name = "Recover open chunk",
180 : : .ctx_size = sizeof(struct recovery_chunk_ctx),
181 : : .init_handler = recovery_chunk_init,
182 : : .steps = {
183 : : {
184 : : .name = "Recover chunk P2L map",
185 : : .action = recovery_chunk_recover_p2l_map,
186 : : },
187 : : {}
188 : : }
189 : : };
190 : :
191 : : static void
192 : 0 : recover_open_chunk(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
193 : : struct ftl_nv_cache_chunk *chunk)
194 : : {
195 : 0 : ftl_mngt_call_process(mngt, &desc_chunk_recovery, chunk);
196 : 0 : }
197 : :
198 : : static int
199 : 0 : setup_layout(struct spdk_ftl_dev *dev)
200 : : {
201 [ # # # # : 0 : const struct ftl_md_layout_ops *md_ops = &dev->nv_cache.nvc_type->ops.md_layout_ops;
# # # # #
# ]
202 : 0 : const uint64_t blocks = ftl_p2l_log_get_md_blocks_required(dev, 1, ftl_get_num_blocks_in_band(dev));
203 : : enum ftl_layout_region_type region_type;
204 : :
205 [ # # ]: 0 : for (region_type = FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN;
206 [ # # ]: 0 : region_type <= FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX;
207 : 0 : region_type++) {
208 [ # # # # : 0 : if (md_ops->region_create(dev, region_type, FTL_P2L_LOG_VERSION_CURRENT, blocks)) {
# # # # #
# ]
209 : 0 : return -1;
210 : : }
211 : :
212 [ # # # # : 0 : if (md_ops->region_open(dev, region_type, FTL_P2L_LOG_VERSION_CURRENT,
# # # # #
# ]
213 : 0 : FTL_BLOCK_SIZE, blocks,
214 [ # # # # : 0 : &dev->layout.region[region_type])) {
# # # # ]
215 : 0 : return -1;
216 : : }
217 : 0 : }
218 : :
219 : 0 : return 0;
220 : 0 : }
221 : :
222 : : struct ftl_nv_cache_device_type nvc_bdev_non_vss = {
223 : : .name = "bdev-non-vss",
224 : : .features = {
225 : : },
226 : : .ops = {
227 : : .init = init,
228 : : .deinit = deinit,
229 : : .on_chunk_open = on_chunk_open,
230 : : .on_chunk_closed = on_chunk_closed,
231 : : .is_bdev_compatible = is_bdev_compatible,
232 : : .is_chunk_active = ftl_nvc_bdev_common_is_chunk_active,
233 : : .setup_layout = setup_layout,
234 : : .md_layout_ops = {
235 : : .region_create = ftl_nvc_bdev_common_region_create,
236 : : .region_open = ftl_nvc_bdev_common_region_open,
237 : : },
238 : : .process = process,
239 : : .write = write_io,
240 : : .recover_open_chunk = recover_open_chunk
241 : : }
242 : : };
243 : 1994 : FTL_NV_CACHE_DEVICE_TYPE_REGISTER(nvc_bdev_non_vss)
|