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 "spdk/thread.h"
8 : #include "spdk/crc32.h"
9 : #include "spdk/string.h"
10 :
11 : #include "ftl_core.h"
12 : #include "ftl_mngt.h"
13 : #include "ftl_mngt_steps.h"
14 : #include "ftl_utils.h"
15 : #include "ftl_band.h"
16 : #include "ftl_internal.h"
17 : #include "ftl_sb.h"
18 : #include "base/ftl_base_dev.h"
19 : #include "nvc/ftl_nvc_dev.h"
20 : #include "upgrade/ftl_layout_upgrade.h"
21 : #include "upgrade/ftl_sb_upgrade.h"
22 :
23 : void
24 0 : ftl_mngt_init_layout(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
25 : {
26 0 : if (ftl_layout_setup(dev)) {
27 0 : ftl_mngt_fail_step(mngt);
28 : } else {
29 0 : ftl_mngt_next_step(mngt);
30 : }
31 0 : }
32 :
33 : static bool
34 0 : is_buffer_needed(enum ftl_layout_region_type type)
35 : {
36 0 : switch (type) {
37 0 : case FTL_LAYOUT_REGION_TYPE_SB:
38 : case FTL_LAYOUT_REGION_TYPE_SB_BASE:
39 : case FTL_LAYOUT_REGION_TYPE_DATA_NVC:
40 : case FTL_LAYOUT_REGION_TYPE_DATA_BASE:
41 : case FTL_LAYOUT_REGION_TYPE_NVC_MD_MIRROR:
42 : case FTL_LAYOUT_REGION_TYPE_BAND_MD_MIRROR:
43 : #ifndef SPDK_FTL_L2P_FLAT
44 : case FTL_LAYOUT_REGION_TYPE_L2P:
45 : #endif
46 : case FTL_LAYOUT_REGION_TYPE_TRIM_MD_MIRROR:
47 : case FTL_LAYOUT_REGION_TYPE_TRIM_LOG_MIRROR:
48 : case FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MIN:
49 : case FTL_LAYOUT_REGION_TYPE_P2L_LOG_IO_MAX:
50 0 : return false;
51 :
52 0 : default:
53 0 : return true;
54 : }
55 : }
56 :
57 : void
58 0 : ftl_mngt_init_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
59 : {
60 0 : struct ftl_layout *layout = &dev->layout;
61 : struct ftl_layout_region *region;
62 : struct ftl_md *md, *md_mirror;
63 : enum ftl_layout_region_type i;
64 : int md_flags;
65 :
66 0 : for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
67 0 : region = ftl_layout_region_get(dev, i);
68 0 : if (!region) {
69 0 : continue;
70 : }
71 0 : assert(i == region->type);
72 0 : if (layout->md[i]) {
73 : /*
74 : * Some metadata objects are initialized by other FTL
75 : * components. At the moment it's only used by superblock (and its mirror) -
76 : * during load time we need to read it earlier in order to get the layout for the
77 : * other regions.
78 : */
79 0 : continue;
80 : }
81 0 : md_flags = is_buffer_needed(i) ? ftl_md_create_region_flags(dev,
82 0 : region->type) : FTL_MD_CREATE_NO_MEM;
83 0 : layout->md[i] = ftl_md_create(dev, region->current.blocks, region->vss_blksz, region->name,
84 : md_flags, region);
85 0 : if (NULL == layout->md[i]) {
86 0 : ftl_mngt_fail_step(mngt);
87 0 : return;
88 : }
89 : }
90 :
91 : /* Initialize mirror regions */
92 0 : for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
93 0 : region = ftl_layout_region_get(dev, i);
94 0 : if (!region) {
95 0 : continue;
96 : }
97 0 : assert(i == region->type);
98 0 : if (region->mirror_type != FTL_LAYOUT_REGION_TYPE_INVALID &&
99 0 : !is_buffer_needed(region->mirror_type)) {
100 0 : md = layout->md[i];
101 0 : md_mirror = layout->md[region->mirror_type];
102 :
103 0 : md_mirror->dev = md->dev;
104 0 : md_mirror->data_blocks = md->data_blocks;
105 0 : md_mirror->data = md->data;
106 0 : if (md_mirror->region->vss_blksz == md->region->vss_blksz) {
107 0 : md_mirror->vss_data = md->vss_data;
108 : }
109 0 : md_mirror->region = ftl_layout_region_get(dev, region->mirror_type);
110 0 : ftl_bug(md_mirror->region == NULL);
111 0 : md_mirror->is_mirror = true;
112 : }
113 : }
114 :
115 0 : ftl_mngt_next_step(mngt);
116 : }
117 :
118 : void
119 0 : ftl_mngt_deinit_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
120 : {
121 0 : struct ftl_layout *layout = &dev->layout;
122 : struct ftl_layout_region *region;
123 : enum ftl_layout_region_type i;
124 :
125 0 : for (i = 0; i < FTL_LAYOUT_REGION_TYPE_MAX; i++) {
126 0 : region = ftl_layout_region_get(dev, i);
127 0 : if (!region) {
128 0 : continue;
129 : }
130 0 : if (layout->md[i]) {
131 0 : ftl_md_destroy(layout->md[i], ftl_md_destroy_region_flags(dev, region->type));
132 0 : layout->md[i] = NULL;
133 : }
134 : }
135 :
136 0 : ftl_mngt_next_step(mngt);
137 0 : }
138 :
139 : static void
140 0 : persist_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
141 : {
142 0 : struct ftl_mngt_process *mngt = md->owner.cb_ctx;
143 :
144 0 : if (status) {
145 0 : ftl_mngt_fail_step(mngt);
146 : } else {
147 0 : ftl_mngt_next_step(mngt);
148 : }
149 0 : }
150 :
151 : static void
152 0 : persist(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
153 : enum ftl_layout_region_type type)
154 : {
155 0 : struct ftl_layout *layout = &dev->layout;
156 : struct ftl_md *md;
157 :
158 0 : assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
159 :
160 0 : md = layout->md[type];
161 0 : if (!md) {
162 0 : ftl_mngt_fail_step(mngt);
163 0 : return;
164 : }
165 :
166 0 : md->owner.cb_ctx = mngt;
167 0 : md->cb = persist_cb;
168 0 : ftl_md_persist(md);
169 : }
170 :
171 : static int
172 0 : ftl_md_restore_region(struct spdk_ftl_dev *dev, int region_type)
173 : {
174 0 : int status = 0;
175 0 : switch (region_type) {
176 0 : case FTL_LAYOUT_REGION_TYPE_NVC_MD:
177 0 : status = ftl_nv_cache_load_state(&dev->nv_cache);
178 0 : break;
179 0 : case FTL_LAYOUT_REGION_TYPE_VALID_MAP:
180 0 : ftl_valid_map_load_state(dev);
181 0 : break;
182 0 : case FTL_LAYOUT_REGION_TYPE_BAND_MD:
183 0 : status = ftl_bands_load_state(dev);
184 0 : break;
185 0 : default:
186 0 : break;
187 : }
188 0 : return status;
189 : }
190 :
191 : static void
192 0 : restore_cb(struct spdk_ftl_dev *dev, struct ftl_md *md, int status)
193 : {
194 0 : struct ftl_mngt_process *mngt = md->owner.cb_ctx;
195 0 : const struct ftl_layout_region *region = ftl_md_get_region(md);
196 :
197 0 : if (status) {
198 : /* Restore error, end step */
199 0 : ftl_mngt_fail_step(mngt);
200 0 : return;
201 : }
202 :
203 0 : assert(region);
204 0 : status = ftl_md_restore_region(dev, region->type);
205 :
206 0 : if (status) {
207 0 : ftl_mngt_fail_step(mngt);
208 : } else {
209 0 : ftl_mngt_next_step(mngt);
210 : }
211 : }
212 :
213 : static void
214 0 : restore(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt, enum ftl_layout_region_type type)
215 : {
216 0 : struct ftl_layout *layout = &dev->layout;
217 0 : assert(type < FTL_LAYOUT_REGION_TYPE_MAX);
218 0 : struct ftl_md *md = layout->md[type];
219 :
220 0 : if (!md) {
221 0 : ftl_mngt_fail_step(mngt);
222 0 : return;
223 : }
224 :
225 0 : md->owner.cb_ctx = mngt;
226 0 : md->cb = restore_cb;
227 0 : ftl_md_restore(md);
228 : }
229 :
230 : void
231 0 : ftl_mngt_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
232 : {
233 0 : if (ftl_nv_cache_save_state(&dev->nv_cache)) {
234 0 : ftl_mngt_fail_step(mngt);
235 0 : return;
236 : }
237 :
238 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
239 : }
240 :
241 : static void
242 0 : ftl_mngt_fast_persist_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
243 : {
244 0 : if (ftl_nv_cache_save_state(&dev->nv_cache)) {
245 0 : ftl_mngt_fail_step(mngt);
246 0 : return;
247 : }
248 0 : ftl_mngt_next_step(mngt);
249 : }
250 :
251 : static void
252 0 : ftl_mngt_persist_vld_map_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
253 : {
254 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_VALID_MAP);
255 0 : }
256 :
257 : static void
258 0 : ftl_mngt_persist_p2l_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
259 : {
260 : /* Sync runtime P2L to persist any invalidation that may have happened */
261 :
262 0 : struct ftl_p2l_sync_ctx *ctx = ftl_mngt_get_step_ctx(mngt);
263 :
264 : /*
265 : * ftl_mngt_persist_bands_p2l will increment the md_region before the step_continue for next regions
266 : */
267 0 : if (ctx->md_region <= FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN) {
268 0 : ctx->md_region = FTL_LAYOUT_REGION_TYPE_P2L_CKPT_MIN;
269 : }
270 0 : ftl_mngt_persist_bands_p2l(mngt);
271 0 : }
272 :
273 : void
274 0 : ftl_mngt_persist_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
275 : {
276 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
277 0 : }
278 :
279 : static void
280 0 : ftl_mngt_persist_trim_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
281 : {
282 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_TRIM_MD);
283 0 : }
284 :
285 : static uint32_t
286 16 : get_sb_crc(struct ftl_superblock *sb)
287 : {
288 16 : uint32_t crc = 0;
289 :
290 : /* Calculate CRC excluding CRC field in superblock */
291 16 : void *buffer = sb;
292 16 : size_t offset = offsetof(struct ftl_superblock, header.crc);
293 16 : size_t size = offset;
294 16 : crc = spdk_crc32c_update(buffer, size, crc);
295 :
296 16 : buffer += offset + sizeof(sb->header.crc);
297 16 : if (sb->header.version > FTL_SB_VERSION_2) {
298 : /* whole buf for v3 and on: */
299 12 : size = FTL_SUPERBLOCK_SIZE - offset - sizeof(sb->header.crc);
300 12 : crc = spdk_crc32c_update(buffer, size, crc);
301 : } else {
302 : /* special for sb v2 only: */
303 4 : size = sizeof(struct ftl_superblock_v2) - offset - sizeof(sb->header.crc);
304 4 : sb->header.crc = spdk_crc32c_update(buffer, size, crc);
305 : }
306 :
307 16 : return crc;
308 : }
309 :
310 : static void
311 0 : ftl_mngt_persist_super_block(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
312 : {
313 0 : dev->sb->overprovisioning = dev->conf.overprovisioning;
314 0 : dev->sb->gc_info = dev->sb_shm->gc_info;
315 0 : dev->sb->header.crc = get_sb_crc(dev->sb);
316 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
317 0 : }
318 :
319 : /*
320 : * Persists all necessary metadata (band state, P2L, etc) during FTL's clean shutdown.
321 : */
322 : static const struct ftl_mngt_process_desc desc_persist = {
323 : .name = "Persist metadata",
324 : .steps = {
325 : {
326 : .name = "Persist NV cache metadata",
327 : .action = ftl_mngt_persist_nv_cache_metadata,
328 : },
329 : {
330 : .name = "Persist valid map metadata",
331 : .action = ftl_mngt_persist_vld_map_metadata,
332 : },
333 : {
334 : .name = "Persist P2L metadata",
335 : .action = ftl_mngt_persist_p2l_metadata,
336 : .ctx_size = sizeof(struct ftl_p2l_sync_ctx),
337 : },
338 : {
339 : .name = "Persist band info metadata",
340 : .action = ftl_mngt_persist_band_info_metadata,
341 : },
342 : {
343 : .name = "Persist trim metadata",
344 : .action = ftl_mngt_persist_trim_metadata,
345 : },
346 : {
347 : .name = "Persist superblock",
348 : .action = ftl_mngt_persist_super_block,
349 : },
350 : {}
351 : }
352 : };
353 :
354 : void
355 0 : ftl_mngt_persist_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
356 : {
357 0 : ftl_mngt_call_process(mngt, &desc_persist, NULL);
358 0 : }
359 :
360 : /*
361 : * Fast clean shutdown path - skips the persistence of most metadata regions and
362 : * relies on their shared memory state instead.
363 : */
364 : static const struct ftl_mngt_process_desc desc_fast_persist = {
365 : .name = "Fast persist metadata",
366 : .steps = {
367 : {
368 : .name = "Fast persist NV cache metadata",
369 : .action = ftl_mngt_fast_persist_nv_cache_metadata,
370 : },
371 : {}
372 : }
373 : };
374 :
375 : void
376 0 : ftl_mngt_fast_persist_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
377 : {
378 0 : ftl_mngt_call_process(mngt, &desc_fast_persist, NULL);
379 0 : }
380 :
381 : void
382 5 : ftl_mngt_init_default_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
383 : {
384 5 : struct ftl_superblock *sb = dev->sb;
385 :
386 5 : sb->header.magic = FTL_SUPERBLOCK_MAGIC;
387 5 : sb->header.version = FTL_SB_VERSION_CURRENT;
388 5 : sb->uuid = dev->conf.uuid;
389 5 : sb->clean = 0;
390 5 : dev->sb_shm->shm_clean = false;
391 5 : sb->ckpt_seq_id = 0;
392 :
393 : /* Max 16 IO depth per band relocate */
394 5 : sb->max_reloc_qdepth = 16;
395 :
396 5 : sb->overprovisioning = dev->conf.overprovisioning;
397 :
398 5 : ftl_band_init_gc_iter(dev);
399 :
400 : /* md layout isn't initialized yet.
401 : * empty region list => all regions in the default location */
402 5 : spdk_strcpy_pad(sb->base_dev_name, dev->base_type->name,
403 : SPDK_COUNTOF(sb->base_dev_name), '\0');
404 5 : sb->md_layout_base.df_id = FTL_DF_OBJ_ID_INVALID;
405 :
406 5 : spdk_strcpy_pad(sb->nvc_dev_name, dev->nv_cache.nvc_type->name,
407 : SPDK_COUNTOF(sb->nvc_dev_name), '\0');
408 5 : sb->md_layout_nvc.df_id = FTL_DF_OBJ_ID_INVALID;
409 :
410 5 : sb->header.crc = get_sb_crc(sb);
411 :
412 5 : ftl_mngt_next_step(mngt);
413 5 : }
414 :
415 : void
416 0 : ftl_mngt_set_dirty(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
417 : {
418 0 : struct ftl_superblock *sb = dev->sb;
419 :
420 0 : sb->clean = 0;
421 0 : sb->upgrade_ready = false;
422 0 : dev->sb_shm->shm_clean = false;
423 0 : sb->header.crc = get_sb_crc(sb);
424 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
425 0 : }
426 :
427 : void
428 0 : ftl_mngt_set_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
429 : {
430 0 : struct ftl_superblock *sb = dev->sb;
431 :
432 0 : sb->clean = 1;
433 0 : sb->upgrade_ready = dev->conf.prep_upgrade_on_shutdown;
434 0 : dev->sb_shm->shm_clean = false;
435 0 : sb->header.crc = get_sb_crc(sb);
436 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
437 :
438 0 : dev->sb_shm->shm_ready = false;
439 0 : }
440 :
441 : void
442 0 : ftl_mngt_set_shm_clean(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
443 : {
444 0 : struct ftl_superblock *sb = dev->sb;
445 :
446 0 : sb->clean = 1;
447 0 : dev->sb_shm->shm_clean = true;
448 0 : sb->header.crc = get_sb_crc(sb);
449 0 : ftl_mngt_next_step(mngt);
450 0 : }
451 :
452 : void
453 0 : ftl_mngt_load_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
454 : {
455 0 : FTL_NOTICELOG(dev, "SHM: clean %"PRIu64", shm_clean %d\n", dev->sb->clean, dev->sb_shm->shm_clean);
456 :
457 0 : if (!ftl_fast_startup(dev)) {
458 0 : restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
459 0 : return;
460 : }
461 :
462 0 : FTL_DEBUGLOG(dev, "SHM: found SB\n");
463 0 : if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_SB)) {
464 0 : ftl_mngt_fail_step(mngt);
465 0 : return;
466 : }
467 0 : ftl_mngt_next_step(mngt);
468 : }
469 :
470 : void
471 0 : ftl_mngt_validate_sb(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
472 : {
473 0 : struct ftl_superblock *sb = dev->sb;
474 :
475 0 : if (!ftl_superblock_check_magic(sb)) {
476 0 : FTL_ERRLOG(dev, "Invalid FTL superblock magic\n");
477 0 : ftl_mngt_fail_step(mngt);
478 0 : return;
479 : }
480 :
481 0 : if (sb->header.crc != get_sb_crc(sb)) {
482 0 : FTL_ERRLOG(dev, "Invalid FTL superblock CRC\n");
483 0 : ftl_mngt_fail_step(mngt);
484 0 : return;
485 : }
486 :
487 0 : if (ftl_superblock_upgrade(dev)) {
488 0 : FTL_ERRLOG(dev, "FTL superblock dirty or invalid version\n");
489 0 : ftl_mngt_fail_step(mngt);
490 0 : return;
491 : }
492 :
493 0 : if (spdk_uuid_compare(&sb->uuid, &dev->conf.uuid) != 0) {
494 0 : FTL_ERRLOG(dev, "Invalid FTL superblock UUID\n");
495 0 : ftl_mngt_fail_step(mngt);
496 0 : return;
497 : }
498 :
499 0 : if (sb->lba_cnt == 0) {
500 0 : FTL_ERRLOG(dev, "Invalid FTL superblock lba_cnt\n");
501 0 : ftl_mngt_fail_step(mngt);
502 0 : return;
503 : }
504 0 : dev->num_lbas = sb->lba_cnt;
505 :
506 : /* The sb has just been read. Validate and update the conf */
507 0 : if (sb->overprovisioning == 0 || sb->overprovisioning >= 100) {
508 0 : FTL_ERRLOG(dev, "Invalid FTL superblock lba_rsvd\n");
509 0 : ftl_mngt_fail_step(mngt);
510 0 : return;
511 : }
512 0 : dev->conf.overprovisioning = sb->overprovisioning;
513 :
514 0 : if (!ftl_superblock_validate_blob_area(dev)) {
515 0 : FTL_ERRLOG(dev, "Corrupted FTL superblock blob area\n");
516 0 : ftl_mngt_fail_step(mngt);
517 0 : return;
518 : }
519 :
520 0 : ftl_mngt_next_step(mngt);
521 : }
522 :
523 : /*
524 : * Loads and verifies superblock contents - utilized during the load of an FTL
525 : * instance (both from a clean and dirty shutdown).
526 : */
527 : static const struct ftl_mngt_process_desc desc_restore_sb = {
528 : .name = "SB restore",
529 : .steps = {
530 : {
531 : .name = "Load super block",
532 : .action = ftl_mngt_load_sb
533 : },
534 : {
535 : .name = "Validate super block",
536 : .action = ftl_mngt_validate_sb
537 : },
538 : {}
539 : }
540 : };
541 :
542 : /*
543 : * Initializes the superblock fields during first startup of FTL
544 : */
545 : static const struct ftl_mngt_process_desc desc_init_sb = {
546 : .name = "SB initialize",
547 : .steps = {
548 : {
549 : .name = "Default-initialize superblock",
550 : .action = ftl_mngt_init_default_sb,
551 : },
552 : {}
553 : }
554 : };
555 :
556 : void
557 0 : ftl_mngt_superblock_init(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
558 : {
559 : struct ftl_md *md;
560 : struct ftl_md *md_mirror;
561 0 : struct ftl_layout *layout = &dev->layout;
562 0 : struct ftl_layout_region *region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB];
563 0 : char uuid[SPDK_UUID_STRING_LEN];
564 0 : int md_create_flags = ftl_md_create_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB);
565 :
566 : /* Must generate UUID before MD create on SHM for the SB */
567 0 : if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
568 0 : spdk_uuid_generate(&dev->conf.uuid);
569 0 : spdk_uuid_fmt_lower(uuid, sizeof(uuid), &dev->conf.uuid);
570 0 : FTL_NOTICELOG(dev, "Create new FTL, UUID %s\n", uuid);
571 : }
572 :
573 0 : shm_retry:
574 : /* Allocate md buf */
575 0 : dev->sb_shm = NULL;
576 0 : dev->sb_shm_md = ftl_md_create(dev, spdk_divide_round_up(sizeof(*dev->sb_shm), FTL_BLOCK_SIZE),
577 : 0, "sb_shm",
578 : md_create_flags, NULL);
579 0 : if (dev->sb_shm_md == NULL) {
580 : /* The first attempt may fail when trying to open SHM - try to create new */
581 0 : if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
582 0 : md_create_flags |= FTL_MD_CREATE_SHM_NEW;
583 0 : goto shm_retry;
584 : }
585 0 : if (dev->sb_shm_md == NULL) {
586 0 : ftl_mngt_fail_step(mngt);
587 0 : return;
588 : }
589 : }
590 :
591 0 : dev->sb_shm = ftl_md_get_buffer(dev->sb_shm_md);
592 :
593 : /* Setup the layout of a superblock */
594 0 : if (ftl_layout_setup_superblock(dev)) {
595 0 : ftl_mngt_fail_step(mngt);
596 0 : return;
597 : }
598 :
599 : /* Allocate md buf */
600 0 : layout->md[FTL_LAYOUT_REGION_TYPE_SB] = ftl_md_create(dev, region->current.blocks,
601 : region->vss_blksz, region->name,
602 : md_create_flags, region);
603 0 : if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
604 : /* The first attempt may fail when trying to open SHM - try to create new */
605 0 : if ((md_create_flags & FTL_MD_CREATE_SHM_NEW) == 0) {
606 0 : md_create_flags |= FTL_MD_CREATE_SHM_NEW;
607 0 : ftl_md_destroy(dev->sb_shm_md, 0);
608 0 : dev->sb_shm_md = NULL;
609 0 : if (ftl_layout_clear_superblock(dev)) {
610 0 : ftl_mngt_fail_step(mngt);
611 0 : return;
612 : }
613 0 : goto shm_retry;
614 : }
615 0 : ftl_mngt_fail_step(mngt);
616 0 : return;
617 : }
618 :
619 : /* Link the md buf to the device */
620 0 : dev->sb = ftl_md_get_buffer(layout->md[FTL_LAYOUT_REGION_TYPE_SB]);
621 :
622 : /* Setup superblock mirror to QLC */
623 0 : region = &layout->region[FTL_LAYOUT_REGION_TYPE_SB_BASE];
624 0 : layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = ftl_md_create(dev, region->current.blocks,
625 : region->vss_blksz, NULL, FTL_MD_CREATE_NO_MEM, region);
626 0 : if (NULL == layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
627 0 : ftl_mngt_fail_step(mngt);
628 0 : return;
629 : }
630 :
631 : /* Initialize mirror region buffer */
632 0 : md = layout->md[FTL_LAYOUT_REGION_TYPE_SB];
633 0 : md_mirror = layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE];
634 :
635 0 : md_mirror->dev = md->dev;
636 0 : md_mirror->data_blocks = md->data_blocks;
637 0 : md_mirror->data = md->data;
638 0 : md_mirror->is_mirror = true;
639 :
640 : /* Initialize the superblock */
641 0 : if (dev->conf.mode & SPDK_FTL_MODE_CREATE) {
642 0 : ftl_mngt_call_process(mngt, &desc_init_sb, NULL);
643 : } else {
644 0 : ftl_mngt_call_process(mngt, &desc_restore_sb, NULL);
645 : }
646 : }
647 :
648 : void
649 0 : ftl_mngt_superblock_deinit(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
650 : {
651 0 : struct ftl_layout *layout = &dev->layout;
652 :
653 0 : if (layout->md[FTL_LAYOUT_REGION_TYPE_SB]) {
654 0 : ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB],
655 : ftl_md_destroy_region_flags(dev, FTL_LAYOUT_REGION_TYPE_SB));
656 0 : layout->md[FTL_LAYOUT_REGION_TYPE_SB] = NULL;
657 : }
658 :
659 0 : if (layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE]) {
660 0 : ftl_md_destroy(layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE], 0);
661 0 : layout->md[FTL_LAYOUT_REGION_TYPE_SB_BASE] = NULL;
662 : }
663 :
664 0 : ftl_md_destroy(dev->sb_shm_md, ftl_md_destroy_shm_flags(dev));
665 0 : dev->sb_shm_md = NULL;
666 0 : dev->sb_shm = NULL;
667 :
668 0 : ftl_mngt_next_step(mngt);
669 0 : }
670 :
671 : static void
672 0 : ftl_mngt_restore_nv_cache_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
673 : {
674 0 : if (ftl_fast_startup(dev)) {
675 0 : FTL_DEBUGLOG(dev, "SHM: found nv cache md\n");
676 0 : if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_NVC_MD)) {
677 0 : ftl_mngt_fail_step(mngt);
678 0 : return;
679 : }
680 0 : ftl_mngt_next_step(mngt);
681 0 : return;
682 : }
683 0 : restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_NVC_MD);
684 : }
685 :
686 : static void
687 0 : ftl_mngt_restore_vld_map_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
688 : {
689 0 : if (ftl_fast_startup(dev)) {
690 0 : FTL_DEBUGLOG(dev, "SHM: found vldmap\n");
691 0 : if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_VALID_MAP)) {
692 0 : ftl_mngt_fail_step(mngt);
693 0 : return;
694 : }
695 0 : ftl_mngt_next_step(mngt);
696 0 : return;
697 : }
698 0 : restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_VALID_MAP);
699 : }
700 :
701 : static void
702 0 : ftl_mngt_restore_band_info_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
703 : {
704 0 : if (ftl_fast_startup(dev)) {
705 0 : FTL_DEBUGLOG(dev, "SHM: found band md\n");
706 0 : if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_BAND_MD)) {
707 0 : ftl_mngt_fail_step(mngt);
708 0 : return;
709 : }
710 0 : ftl_mngt_next_step(mngt);
711 0 : return;
712 : }
713 0 : restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_BAND_MD);
714 : }
715 :
716 : static void
717 0 : ftl_mngt_restore_trim_metadata(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
718 : {
719 0 : if (ftl_fast_startup(dev)) {
720 0 : FTL_DEBUGLOG(dev, "SHM: found trim md\n");
721 0 : if (ftl_md_restore_region(dev, FTL_LAYOUT_REGION_TYPE_TRIM_MD)) {
722 0 : ftl_mngt_fail_step(mngt);
723 0 : return;
724 : }
725 0 : ftl_mngt_next_step(mngt);
726 0 : return;
727 : }
728 0 : restore(dev, mngt, FTL_LAYOUT_REGION_TYPE_TRIM_MD);
729 : }
730 :
731 : /*
732 : * Loads metadata after a clean shutdown.
733 : */
734 : static const struct ftl_mngt_process_desc desc_restore = {
735 : .name = "Restore metadata",
736 : .steps = {
737 : {
738 : .name = "Restore NV cache metadata",
739 : .action = ftl_mngt_restore_nv_cache_metadata,
740 : },
741 : {
742 : .name = "Restore valid map metadata",
743 : .action = ftl_mngt_restore_vld_map_metadata,
744 : },
745 : {
746 : .name = "Restore band info metadata",
747 : .action = ftl_mngt_restore_band_info_metadata,
748 : },
749 : {
750 : .name = "Restore trim metadata",
751 : .action = ftl_mngt_restore_trim_metadata,
752 : },
753 : {}
754 : }
755 : };
756 :
757 : void
758 0 : ftl_mngt_restore_md(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
759 : {
760 0 : ftl_mngt_call_process(mngt, &desc_restore, NULL);
761 0 : }
762 :
763 : void
764 0 : ftl_mngt_persist_superblock(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
765 : {
766 0 : dev->sb->header.crc = get_sb_crc(dev->sb);
767 0 : persist(dev, mngt, FTL_LAYOUT_REGION_TYPE_SB);
768 0 : }
|