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 = "Clear trim map",
186 : .action = ftl_mngt_trim_metadata_clear,
187 : },
188 : {
189 : .name = "Clear trim log",
190 : .action = ftl_mngt_trim_log_clear,
191 : },
192 : {
193 : .name = "Set FTL dirty state",
194 : .action = ftl_mngt_set_dirty,
195 : },
196 : {
197 : .name = "Start core poller",
198 : .action = ftl_mngt_start_core_poller,
199 : .cleanup = ftl_mngt_stop_core_poller
200 : },
201 : {
202 : .name = "Finalize initialization",
203 : .action = ftl_mngt_finalize_startup,
204 : },
205 : {}
206 : }
207 : };
208 :
209 : /*
210 : * Step utilized on loading of an FTL instance - decides on dirty/clean shutdown path.
211 : */
212 : static const struct ftl_mngt_process_desc desc_restore = {
213 : .name = "FTL restore",
214 : .steps = {
215 : {
216 : .name = "Select recovery mode",
217 : .action = ftl_mngt_select_restore_mode,
218 : },
219 : {}
220 : }
221 : };
222 :
223 : /*
224 : * Loading of FTL after clean shutdown.
225 : */
226 : static const struct ftl_mngt_process_desc desc_clean_start = {
227 : .name = "Clean startup",
228 : .steps = {
229 : {
230 : .name = "Restore metadata",
231 : .action = ftl_mngt_restore_md
232 : },
233 : {
234 : .name = "Initialize P2L checkpointing",
235 : .action = ftl_mngt_p2l_init_ckpt,
236 : .cleanup = ftl_mngt_p2l_deinit_ckpt
237 : },
238 : {
239 : .name = "Restore P2L checkpoints",
240 : .action = ftl_mngt_p2l_restore_ckpt
241 : },
242 : {
243 : .name = "Initialize L2P",
244 : .action = ftl_mngt_init_l2p,
245 : .cleanup = ftl_mngt_deinit_l2p
246 : },
247 : {
248 : .name = "Restore L2P",
249 : .action = ftl_mngt_restore_l2p,
250 : },
251 : {
252 : .name = "Finalize band initialization",
253 : .action = ftl_mngt_finalize_init_bands,
254 : },
255 : {
256 : .name = "Start core poller",
257 : .action = ftl_mngt_start_core_poller,
258 : .cleanup = ftl_mngt_stop_core_poller
259 : },
260 : {
261 : .name = "Self test on startup",
262 : .action = ftl_mngt_self_test,
263 : },
264 : {
265 : .name = "Set FTL dirty state",
266 : .action = ftl_mngt_set_dirty,
267 : },
268 : {
269 : .name = "Finalize initialization",
270 : .action = ftl_mngt_finalize_startup,
271 : },
272 : {}
273 : }
274 : };
275 :
276 : int
277 0 : ftl_mngt_call_dev_startup(struct spdk_ftl_dev *dev, ftl_mngt_completion cb, void *cb_cntx)
278 : {
279 0 : return ftl_mngt_process_execute(dev, &desc_startup, cb, cb_cntx);
280 : }
281 :
282 : struct ftl_trim_ctx {
283 : uint64_t lba;
284 : uint64_t num_blocks;
285 : spdk_ftl_fn cb_fn;
286 : void *cb_arg;
287 : struct spdk_thread *thread;
288 : int status;
289 : };
290 :
291 : static void
292 0 : ftl_mngt_process_trim_cb(void *ctx, int status)
293 : {
294 0 : struct ftl_mngt_process *mngt = ctx;
295 :
296 0 : if (status) {
297 0 : ftl_mngt_fail_step(ctx);
298 : } else {
299 0 : ftl_mngt_next_step(mngt);
300 : }
301 0 : }
302 :
303 : static void
304 0 : ftl_mngt_process_trim(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
305 : {
306 0 : struct ftl_io *io = ftl_mngt_get_process_ctx(mngt);
307 0 : struct ftl_trim_ctx *ctx = ftl_mngt_get_caller_ctx(mngt);
308 : int rc;
309 :
310 0 : if (!dev->ioch) {
311 0 : ftl_mngt_fail_step(mngt);
312 0 : return;
313 : }
314 :
315 0 : rc = spdk_ftl_unmap(dev, io, dev->ioch, ctx->lba, ctx->num_blocks, ftl_mngt_process_trim_cb, mngt);
316 0 : if (rc == -EAGAIN) {
317 0 : ftl_mngt_continue_step(mngt);
318 : }
319 : }
320 :
321 : /*
322 : * RPC trim path.
323 : */
324 : static const struct ftl_mngt_process_desc g_desc_trim = {
325 : .name = "FTL trim",
326 : .ctx_size = sizeof(struct ftl_io),
327 : .steps = {
328 : {
329 : .name = "Process trim",
330 : .action = ftl_mngt_process_trim,
331 : },
332 : {}
333 : }
334 : };
335 :
336 : static void
337 0 : trim_user_cb(void *_ctx)
338 : {
339 0 : struct ftl_trim_ctx *ctx = _ctx;
340 :
341 0 : ctx->cb_fn(ctx->cb_arg, ctx->status);
342 0 : free(ctx);
343 0 : }
344 :
345 : static void
346 0 : ftl_mngt_trim_cb(struct spdk_ftl_dev *dev, void *_ctx, int status)
347 : {
348 0 : struct ftl_trim_ctx *ctx = _ctx;
349 0 : ctx->status = status;
350 :
351 0 : if (spdk_thread_send_msg(ctx->thread, trim_user_cb, ctx)) {
352 0 : ftl_abort();
353 : }
354 0 : }
355 :
356 : int
357 0 : ftl_mngt_trim(struct spdk_ftl_dev *dev, uint64_t lba, uint64_t num_blocks, spdk_ftl_fn cb,
358 : void *cb_cntx)
359 : {
360 : struct ftl_trim_ctx *ctx;
361 :
362 0 : ctx = calloc(1, sizeof(*ctx));
363 0 : if (ctx == NULL) {
364 0 : return -EAGAIN;
365 : }
366 :
367 0 : ctx->lba = lba;
368 0 : ctx->num_blocks = num_blocks;
369 0 : ctx->cb_fn = cb;
370 0 : ctx->cb_arg = cb_cntx;
371 0 : ctx->thread = spdk_get_thread();
372 :
373 0 : return ftl_mngt_process_execute(dev, &g_desc_trim, ftl_mngt_trim_cb, ctx);
374 : }
375 :
376 : void
377 0 : ftl_mngt_rollback_device(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
378 : {
379 0 : ftl_mngt_call_process_rollback(mngt, &desc_startup);
380 0 : }
|