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_sb.h"
8 #include "ftl_core.h"
9 #include "ftl_layout.h"
10 #include "upgrade/ftl_sb_upgrade.h"
11 #include "upgrade/ftl_sb_v3.h"
12 #include "upgrade/ftl_sb_v5.h"
13
14 static bool ftl_superblock_v2_check_magic(union ftl_superblock_ver *sb_ver);
15
16 struct sb_ops {
17 bool (*check_magic)(union ftl_superblock_ver *sb_ver);
18
19 bool (*blob_is_empty)(union ftl_superblock_ver *sb_ver);
20 bool (*blob_validate)(struct spdk_ftl_dev *dev);
21 int (*blob_store)(struct spdk_ftl_dev *dev);
22 int (*blob_load)(struct spdk_ftl_dev *dev);
23
24 int (*upgrade_region)(struct spdk_ftl_dev *dev, struct ftl_layout_region *reg,
25 uint32_t new_version);
26
27 int (*layout_apply)(struct spdk_ftl_dev *dev);
28 void (*layout_dump)(struct spdk_ftl_dev *dev);
29 };
30
31 static struct sb_ops *
sb_get_ops(uint64_t version)32 sb_get_ops(uint64_t version)
33 {
34 static struct sb_ops ops[] = {
35 [FTL_SB_VERSION_0] = {
36 .check_magic = ftl_superblock_v2_check_magic,
37 },
38 [FTL_SB_VERSION_1] = {
39 .check_magic = ftl_superblock_v2_check_magic,
40 },
41 [FTL_SB_VERSION_2] = {
42 .check_magic = ftl_superblock_v2_check_magic,
43 },
44 [FTL_SB_VERSION_3] = {
45 .check_magic = ftl_superblock_v3_check_magic,
46 .blob_is_empty = ftl_superblock_v3_md_layout_is_empty,
47 .blob_load = ftl_superblock_v3_md_layout_load_all,
48 .layout_dump = ftl_superblock_v3_md_layout_dump,
49 },
50 [FTL_SB_VERSION_4] = {
51 .check_magic = ftl_superblock_v3_check_magic,
52 .blob_is_empty = ftl_superblock_v3_md_layout_is_empty,
53 .blob_load = ftl_superblock_v3_md_layout_load_all,
54 .layout_dump = ftl_superblock_v3_md_layout_dump,
55 },
56 [FTL_SB_VERSION_5] = {
57 .check_magic = ftl_superblock_v3_check_magic,
58 .blob_is_empty = ftl_superblock_v5_is_blob_area_empty,
59 .blob_validate = ftl_superblock_v5_validate_blob_area,
60 .blob_store = ftl_superblock_v5_store_blob_area,
61 .blob_load = ftl_superblock_v5_load_blob_area,
62 .upgrade_region = ftl_superblock_v5_md_layout_upgrade_region,
63 .layout_apply = ftl_superblock_v5_md_layout_apply,
64 .layout_dump = ftl_superblock_v5_md_layout_dump,
65 },
66 };
67
68 if (version >= SPDK_COUNTOF(ops)) {
69 return NULL;
70 }
71
72 return &ops[version];
73 }
74
75 static bool
ftl_superblock_v2_check_magic(union ftl_superblock_ver * sb_ver)76 ftl_superblock_v2_check_magic(union ftl_superblock_ver *sb_ver)
77 {
78 return sb_ver->header.magic == FTL_SUPERBLOCK_MAGIC_V2;
79 }
80
81 bool
ftl_superblock_check_magic(struct ftl_superblock * sb)82 ftl_superblock_check_magic(struct ftl_superblock *sb)
83 {
84 union ftl_superblock_ver *sb_ver = (union ftl_superblock_ver *)sb;
85 struct sb_ops *ops = sb_get_ops(sb_ver->header.version);
86
87 if (!ops || !ops->check_magic) {
88 ftl_abort();
89 return false;
90 }
91 return ops->check_magic(sb_ver);
92 }
93
94 bool
ftl_superblock_is_blob_area_empty(struct ftl_superblock * sb)95 ftl_superblock_is_blob_area_empty(struct ftl_superblock *sb)
96 {
97 union ftl_superblock_ver *sb_ver = (union ftl_superblock_ver *)sb;
98 struct sb_ops *ops = sb_get_ops(sb_ver->header.version);
99
100 if (!ops || !ops->blob_is_empty) {
101 ftl_abort();
102 return false;
103 }
104 return ops->blob_is_empty(sb_ver);
105 }
106
107 bool
ftl_superblock_validate_blob_area(struct spdk_ftl_dev * dev)108 ftl_superblock_validate_blob_area(struct spdk_ftl_dev *dev)
109 {
110 struct sb_ops *ops = sb_get_ops(dev->sb->header.version);
111
112 if (!ops || !ops->blob_validate) {
113 return true;
114 }
115 return ops->blob_validate(dev);
116 }
117
118 int
ftl_superblock_store_blob_area(struct spdk_ftl_dev * dev)119 ftl_superblock_store_blob_area(struct spdk_ftl_dev *dev)
120 {
121 struct sb_ops *ops = sb_get_ops(dev->sb->header.version);
122
123 if (!ops || !ops->blob_store) {
124 ftl_abort();
125 return -1;
126 }
127 return ops->blob_store(dev);
128 }
129
130 int
ftl_superblock_load_blob_area(struct spdk_ftl_dev * dev)131 ftl_superblock_load_blob_area(struct spdk_ftl_dev *dev)
132 {
133 struct sb_ops *ops = sb_get_ops(dev->sb->header.version);
134
135 if (!ops || !ops->blob_load) {
136 ftl_abort();
137 return -1;
138 }
139 return ops->blob_load(dev);
140 }
141
142 int
ftl_superblock_md_layout_upgrade_region(struct spdk_ftl_dev * dev,struct ftl_layout_region * reg,uint32_t new_version)143 ftl_superblock_md_layout_upgrade_region(struct spdk_ftl_dev *dev,
144 struct ftl_layout_region *reg, uint32_t new_version)
145 {
146 struct sb_ops *ops = sb_get_ops(dev->sb->header.version);
147
148 if (!ops || !ops->upgrade_region) {
149 ftl_abort();
150 return -1;
151 }
152 return ops->upgrade_region(dev, reg, new_version);
153 }
154
155 int
ftl_superblock_md_layout_apply(struct spdk_ftl_dev * dev)156 ftl_superblock_md_layout_apply(struct spdk_ftl_dev *dev)
157 {
158 struct sb_ops *ops = sb_get_ops(dev->sb->header.version);
159
160 if (!ops || !ops->layout_apply) {
161 return 0;
162 }
163 return ops->layout_apply(dev);
164 }
165
166 void
ftl_superblock_md_layout_dump(struct spdk_ftl_dev * dev)167 ftl_superblock_md_layout_dump(struct spdk_ftl_dev *dev)
168 {
169 struct sb_ops *ops = sb_get_ops(dev->sb->header.version);
170
171 if (!ops || !ops->layout_dump) {
172 ftl_abort();
173 return;
174 }
175 return ops->layout_dump(dev);
176 }
177