Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright 2023 Solidigm All Rights Reserved
3 : * Copyright (C) 2022 Intel Corporation.
4 : * All rights reserved.
5 : */
6 :
7 : #include "ftl_core.h"
8 : #include "ftl_mngt.h"
9 : #include "ftl_mngt_steps.h"
10 :
11 : static const struct ftl_mngt_process_desc desc_startup;
12 : static const struct ftl_mngt_process_desc desc_first_start;
13 : static const struct ftl_mngt_process_desc desc_restore;
14 : static const struct ftl_mngt_process_desc desc_clean_start;
15 :
16 : static void
17 0 : ftl_mngt_select_startup_mode(struct spdk_ftl_dev *dev,
18 : struct ftl_mngt_process *mngt)
19 : {
20 0 : if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
21 0 : ftl_mngt_call_process(mngt, &desc_first_start, NULL);
22 : } else {
23 0 : ftl_mngt_call_process(mngt, &desc_restore, NULL);
24 : }
25 0 : }
26 :
27 : static void
28 0 : ftl_mngt_select_restore_mode(struct spdk_ftl_dev *dev,
29 : struct ftl_mngt_process *mngt)
30 : {
31 0 : if (dev->sb->clean) {
32 0 : ftl_mngt_call_process(mngt, &desc_clean_start, NULL);
33 : } else {
34 0 : ftl_mngt_recover(dev, mngt);
35 : }
36 0 : }
37 :
38 : /*
39 : * Common startup steps required by FTL in all cases (creation, load, dirty shutdown recovery).
40 : * Includes actions like opening the devices, calculating the expected size and version of metadata, etc.
41 : */
42 : static const struct ftl_mngt_process_desc desc_startup = {
43 : .name = "FTL startup",
44 : .steps = {
45 : {
46 : .name = "Check configuration",
47 : .action = ftl_mngt_check_conf,
48 : },
49 : {
50 : .name = "Open base bdev",
51 : .action = ftl_mngt_open_base_bdev,
52 : .cleanup = ftl_mngt_close_base_bdev
53 : },
54 : {
55 : .name = "Open cache bdev",
56 : .action = ftl_mngt_open_cache_bdev,
57 : .cleanup = ftl_mngt_close_cache_bdev
58 : },
59 : {
60 : .name = "Initialize superblock",
61 : .action = ftl_mngt_superblock_init,
62 : .cleanup = ftl_mngt_superblock_deinit
63 : },
64 : {
65 : .name = "Initialize memory pools",
66 : .action = ftl_mngt_init_mem_pools,
67 : .cleanup = ftl_mngt_deinit_mem_pools
68 : },
69 : {
70 : .name = "Initialize bands",
71 : .action = ftl_mngt_init_bands,
72 : .cleanup = ftl_mngt_deinit_bands
73 : },
74 : {
75 : .name = "Register IO device",
76 : .action = ftl_mngt_register_io_device,
77 : .cleanup = ftl_mngt_unregister_io_device
78 : },
79 : {
80 : .name = "Initialize core IO channel",
81 : .action = ftl_mngt_init_io_channel,
82 : .cleanup = ftl_mngt_deinit_io_channel
83 : },
84 : {
85 : .name = "Decorate bands",
86 : .action = ftl_mngt_decorate_bands
87 : },
88 : {
89 : .name = "Initialize layout",
90 : .action = ftl_mngt_init_layout
91 : },
92 : {
93 : .name = "Verify layout",
94 : .action = ftl_mngt_layout_verify,
95 : },
96 : {
97 : .name = "Upgrade layout",
98 : .action = ftl_mngt_layout_upgrade,
99 : },
100 : {
101 : .name = "Scrub NV cache",
102 : .action = ftl_mngt_scrub_nv_cache,
103 : },
104 : {
105 : .name = "Initialize metadata",
106 : .action = ftl_mngt_init_md,
107 : .cleanup = ftl_mngt_deinit_md
108 : },
109 : {
110 : .name = "Initialize band addresses",
111 : .action = ftl_mngt_initialize_band_address
112 : },
113 : {
114 : .name = "Initialize NV cache",
115 : .action = ftl_mngt_init_nv_cache,
116 : .cleanup = ftl_mngt_deinit_nv_cache
117 : },
118 : {
119 : .name = "Initialize valid map",
120 : .action = ftl_mngt_init_vld_map,
121 : .cleanup = ftl_mngt_deinit_vld_map
122 : },
123 : {
124 : .name = "Initialize trim map",
125 : .action = ftl_mngt_init_trim_map,
126 : .cleanup = ftl_mngt_deinit_trim_map
127 : },
128 : {
129 : .name = "Initialize bands metadata",
130 : .action = ftl_mngt_init_bands_md,
131 : .cleanup = ftl_mngt_deinit_bands_md
132 : },
133 : {
134 : .name = "Initialize reloc",
135 : .action = ftl_mngt_init_reloc,
136 : .cleanup = ftl_mngt_deinit_reloc
137 : },
138 : {
139 : .name = "Select startup mode",
140 : .action = ftl_mngt_select_startup_mode
141 : },
142 : {}
143 : }
144 : };
145 :
146 : /*
147 : * Steps executed when creating FTL for the first time - most important being scrubbing
148 : * old data/metadata (so it's not leaked during dirty shutdown recovery) and laying out
149 : * regions for the new metadata (initializing band states, etc).
150 : */
151 : static const struct ftl_mngt_process_desc desc_first_start = {
152 : .name = "FTL first start",
153 : .steps = {
154 : {
155 : .name = "Initialize L2P",
156 : .action = ftl_mngt_init_l2p,
157 : .cleanup = ftl_mngt_deinit_l2p
158 : },
159 : {
160 : .name = "Clear L2P",
161 : .action = ftl_mngt_clear_l2p,
162 : },
163 : {
164 : .name = "Finalize band initialization",
165 : .action = ftl_mngt_finalize_init_bands,
166 : },
167 : {
168 : .name = "Save initial band info metadata",
169 : .action = ftl_mngt_persist_band_info_metadata,
170 : },
171 : {
172 : .name = "Save initial chunk info metadata",
173 : .action = ftl_mngt_persist_nv_cache_metadata,
174 : },
175 : {
176 : .name = "Initialize P2L checkpointing",
177 : .action = ftl_mngt_p2l_init_ckpt,
178 : .cleanup = ftl_mngt_p2l_deinit_ckpt
179 : },
180 : {
181 : .name = "Wipe P2L region",
182 : .action = ftl_mngt_p2l_wipe,
183 : },
184 : {
185 : .name = "Wipe P2L Log IO region",
186 : .action = ftl_mngt_p2l_log_io_wipe,
187 : },
188 : {
189 : .name = "Clear trim map",
190 : .action = ftl_mngt_trim_metadata_clear,
191 : },
192 : {
193 : .name = "Clear trim log",
194 : .action = ftl_mngt_trim_log_clear,
195 : },
196 : {
197 : .name = "Set FTL dirty state",
198 : .action = ftl_mngt_set_dirty,
199 : },
200 : {
201 : .name = "Start core poller",
202 : .action = ftl_mngt_start_core_poller,
203 : .cleanup = ftl_mngt_stop_core_poller
204 : },
205 : {
206 : .name = "Finalize initialization",
207 : .action = ftl_mngt_finalize_startup,
208 : },
209 : {}
210 : }
211 : };
212 :
213 : /*
214 : * Step utilized on loading of an FTL instance - decides on dirty/clean shutdown path.
215 : */
216 : static const struct ftl_mngt_process_desc desc_restore = {
217 : .name = "FTL restore",
218 : .steps = {
219 : {
220 : .name = "Select recovery mode",
221 : .action = ftl_mngt_select_restore_mode,
222 : },
223 : {}
224 : }
225 : };
226 :
227 : /*
228 : * Loading of FTL after clean shutdown.
229 : */
230 : static const struct ftl_mngt_process_desc desc_clean_start = {
231 : .name = "Clean startup",
232 : .steps = {
233 : {
234 : .name = "Restore metadata",
235 : .action = ftl_mngt_restore_md
236 : },
237 : {
238 : .name = "Initialize P2L checkpointing",
239 : .action = ftl_mngt_p2l_init_ckpt,
240 : .cleanup = ftl_mngt_p2l_deinit_ckpt
241 : },
242 : {
243 : .name = "Restore P2L checkpoints",
244 : .action = ftl_mngt_p2l_restore_ckpt
245 : },
246 : {
247 : .name = "Initialize L2P",
248 : .action = ftl_mngt_init_l2p,
249 : .cleanup = ftl_mngt_deinit_l2p
250 : },
251 : {
252 : .name = "Restore L2P",
253 : .action = ftl_mngt_restore_l2p,
254 : },
255 : {
256 : .name = "Finalize band initialization",
257 : .action = ftl_mngt_finalize_init_bands,
258 : },
259 : {
260 : .name = "Start core poller",
261 : .action = ftl_mngt_start_core_poller,
262 : .cleanup = ftl_mngt_stop_core_poller
263 : },
264 : {
265 : .name = "Self test on startup",
266 : .action = ftl_mngt_self_test,
267 : },
268 : {
269 : .name = "Set FTL dirty state",
270 : .action = ftl_mngt_set_dirty,
271 : },
272 : {
273 : .name = "Finalize initialization",
274 : .action = ftl_mngt_finalize_startup,
275 : },
276 : {}
277 : }
278 : };
279 :
280 : int
281 0 : ftl_mngt_call_dev_startup(struct spdk_ftl_dev *dev, ftl_mngt_completion cb, void *cb_cntx)
282 : {
283 0 : return ftl_mngt_process_execute(dev, &desc_startup, cb, cb_cntx);
284 : }
285 :
286 : struct ftl_trim_ctx {
287 : uint64_t lba;
288 : uint64_t num_blocks;
289 : spdk_ftl_fn cb_fn;
290 : void *cb_arg;
291 : struct spdk_thread *thread;
292 : int status;
293 : };
294 :
295 : static void
296 0 : ftl_mngt_process_trim_cb(void *ctx, int status)
297 : {
298 0 : struct ftl_mngt_process *mngt = ctx;
299 :
300 0 : if (status) {
301 0 : ftl_mngt_fail_step(ctx);
302 : } else {
303 0 : ftl_mngt_next_step(mngt);
304 : }
305 0 : }
306 :
307 : static void
308 0 : ftl_mngt_process_trim(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
309 : {
310 0 : struct ftl_io *io = ftl_mngt_get_process_ctx(mngt);
311 0 : struct ftl_trim_ctx *ctx = ftl_mngt_get_caller_ctx(mngt);
312 : int rc;
313 :
314 0 : if (!dev->ioch) {
315 0 : ftl_mngt_fail_step(mngt);
316 0 : return;
317 : }
318 :
319 0 : rc = spdk_ftl_unmap(dev, io, dev->ioch, ctx->lba, ctx->num_blocks, ftl_mngt_process_trim_cb, mngt);
320 0 : if (rc == -EAGAIN) {
321 0 : ftl_mngt_continue_step(mngt);
322 : }
323 : }
324 :
325 : /*
326 : * RPC trim path.
327 : */
328 : static const struct ftl_mngt_process_desc g_desc_trim = {
329 : .name = "FTL trim",
330 : .ctx_size = sizeof(struct ftl_io),
331 : .steps = {
332 : {
333 : .name = "Process trim",
334 : .action = ftl_mngt_process_trim,
335 : },
336 : {}
337 : }
338 : };
339 :
340 : static void
341 0 : trim_user_cb(void *_ctx)
342 : {
343 0 : struct ftl_trim_ctx *ctx = _ctx;
344 :
345 0 : ctx->cb_fn(ctx->cb_arg, ctx->status);
346 0 : free(ctx);
347 0 : }
348 :
349 : static void
350 0 : ftl_mngt_trim_cb(struct spdk_ftl_dev *dev, void *_ctx, int status)
351 : {
352 0 : struct ftl_trim_ctx *ctx = _ctx;
353 0 : ctx->status = status;
354 :
355 0 : if (spdk_thread_send_msg(ctx->thread, trim_user_cb, ctx)) {
356 0 : ftl_abort();
357 : }
358 0 : }
359 :
360 : int
361 0 : ftl_mngt_trim(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t num_blocks, spdk_ftl_fn cb,
362 : void *cb_cntx)
363 : {
364 : struct ftl_trim_ctx *ctx;
365 :
366 0 : ctx = calloc(1, sizeof(*ctx));
367 0 : if (ctx == NULL) {
368 0 : return -EAGAIN;
369 : }
370 :
371 0 : ctx->lba = lba;
372 0 : ctx->num_blocks = num_blocks;
373 0 : ctx->cb_fn = cb;
374 0 : ctx->cb_arg = cb_cntx;
375 0 : ctx->thread = spdk_get_thread();
376 :
377 0 : return ftl_mngt_process_execute(dev, &g_desc_trim, ftl_mngt_trim_cb, ctx);
378 : }
379 :
380 : void
381 0 : ftl_mngt_rollback_device(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
382 : {
383 0 : ftl_mngt_call_process_rollback(mngt, &desc_startup);
384 0 : }
|