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 : }
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 : }
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 : } 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 : ftl_addr_to_nvc_offset(dev, io->addr), io->num_blocks,
101 : 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 : } else {
110 0 : ftl_abort();
111 : }
112 : }
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 : } 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 : 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 : }
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 : FTL_BLOCK_SIZE, blocks,
214 : &dev->layout.region[region_type])) {
215 0 : return -1;
216 : }
217 : }
218 :
219 0 : return 0;
220 : }
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 0 : FTL_NV_CACHE_DEVICE_TYPE_REGISTER(nvc_bdev_non_vss)
|