1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (C) 2022 Intel Corporation.
3 * All rights reserved.
4 */
5
6 #include "ftl_mngt.h"
7 #include "ftl_mngt_steps.h"
8 #include "ftl_internal.h"
9 #include "ftl_core.h"
10 #include "ftl_band.h"
11
12 struct ftl_validate_ctx {
13 struct {
14 struct ftl_bitmap *bitmap;
15 void *buffer;
16 uint64_t buffer_size;
17 uint64_t bit_count;
18 uint64_t base_valid_count;
19 uint64_t cache_valid_count;
20 } valid_map;
21
22 int status;
23 };
24
25 static void
ftl_mngt_test_prepare(struct spdk_ftl_dev * dev,struct ftl_mngt_process * mngt)26 ftl_mngt_test_prepare(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
27 {
28 struct ftl_validate_ctx *cntx = ftl_mngt_get_process_ctx(mngt);
29
30 cntx->valid_map.bit_count = dev->layout.base.total_blocks +
31 dev->layout.nvc.total_blocks;
32 cntx->valid_map.buffer_size = spdk_divide_round_up(cntx->valid_map.bit_count, 8);
33 cntx->valid_map.buffer_size = SPDK_ALIGN_CEIL(cntx->valid_map.buffer_size,
34 ftl_bitmap_buffer_alignment);
35
36 cntx->valid_map.buffer = calloc(cntx->valid_map.buffer_size, 1);
37 if (!cntx->valid_map.buffer) {
38 ftl_mngt_fail_step(mngt);
39 return;
40 }
41
42 cntx->valid_map.bitmap = ftl_bitmap_create(cntx->valid_map.buffer,
43 cntx->valid_map.buffer_size);
44 if (!cntx->valid_map.bitmap) {
45 ftl_mngt_fail_step(mngt);
46 return;
47 }
48
49 ftl_mngt_next_step(mngt);
50 }
51
52 static void
ftl_mngt_test_cleanup(struct spdk_ftl_dev * dev,struct ftl_mngt_process * mngt)53 ftl_mngt_test_cleanup(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
54 {
55 struct ftl_validate_ctx *cntx = ftl_mngt_get_process_ctx(mngt);
56
57 ftl_bitmap_destroy(cntx->valid_map.bitmap);
58 cntx->valid_map.bitmap = NULL;
59
60 free(cntx->valid_map.buffer);
61 cntx->valid_map.buffer = NULL;
62
63 ftl_mngt_next_step(mngt);
64 }
65
66 static void
test_valid_map_pin_cb(struct spdk_ftl_dev * dev,int status,struct ftl_l2p_pin_ctx * pin_ctx)67 test_valid_map_pin_cb(struct spdk_ftl_dev *dev, int status,
68 struct ftl_l2p_pin_ctx *pin_ctx)
69 {
70 struct ftl_mngt_process *mngt = pin_ctx->cb_ctx;
71 struct ftl_validate_ctx *ctx = ftl_mngt_get_process_ctx(mngt);
72 uint64_t lba, end;
73
74 if (status) {
75 FTL_ERRLOG(dev, "L2P pin ERROR when testing valid map\n");
76 ftl_mngt_fail_step(mngt);
77 return;
78 }
79
80 lba = pin_ctx->lba;
81 end = pin_ctx->lba + pin_ctx->count;
82
83 for (; lba < end; ++lba) {
84 ftl_addr addr = ftl_l2p_get(dev, lba);
85 bool valid;
86
87 if (FTL_ADDR_INVALID == addr) {
88 continue;
89 }
90
91 if (ftl_bitmap_get(ctx->valid_map.bitmap, addr)) {
92 status = -EINVAL;
93 FTL_ERRLOG(dev, "L2P mapping ERROR, double reference, "
94 "address 0x%.16"PRIX64"\n", addr);
95 break;
96 } else {
97 ftl_bitmap_set(ctx->valid_map.bitmap, addr);
98 }
99
100 if (ftl_addr_in_nvc(dev, addr)) {
101 ctx->valid_map.cache_valid_count++;
102 } else {
103 ctx->valid_map.base_valid_count++;
104 }
105
106 valid = ftl_bitmap_get(dev->valid_map, addr);
107 if (!valid) {
108 status = -EINVAL;
109 FTL_ERRLOG(dev, "L2P and valid map mismatch"
110 ", LBA 0x%.16"PRIX64
111 ", address 0x%.16"PRIX64" unset\n",
112 lba, addr);
113 break;
114 }
115 }
116
117 ftl_l2p_unpin(dev, pin_ctx->lba, pin_ctx->count);
118 pin_ctx->lba += pin_ctx->count;
119
120 if (!status) {
121 ftl_mngt_continue_step(mngt);
122 } else {
123 ftl_mngt_fail_step(mngt);
124 }
125 }
126
127 static void
ftl_mngt_test_valid_map(struct spdk_ftl_dev * dev,struct ftl_mngt_process * mngt)128 ftl_mngt_test_valid_map(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
129 {
130 struct ftl_l2p_pin_ctx *pin_ctx;
131 struct ftl_validate_ctx *ctx = ftl_mngt_get_process_ctx(mngt);
132 uint64_t left;
133
134 pin_ctx = ftl_mngt_get_step_ctx(mngt);
135 if (!pin_ctx) {
136 if (ftl_mngt_alloc_step_ctx(mngt, sizeof(*pin_ctx))) {
137 ftl_mngt_fail_step(mngt);
138 return;
139 }
140 pin_ctx = ftl_mngt_get_step_ctx(mngt);
141 assert(pin_ctx);
142
143 pin_ctx->lba = 0;
144 memset(ctx->valid_map.buffer, 0, ctx->valid_map.buffer_size);
145 }
146
147 left = dev->num_lbas - pin_ctx->lba;
148 pin_ctx->count = spdk_min(left, 4096);
149
150 if (pin_ctx->count) {
151 ftl_l2p_pin(dev, pin_ctx->lba, pin_ctx->count,
152 test_valid_map_pin_cb, mngt, pin_ctx);
153 } else {
154 if (!ctx->status) {
155 uint64_t valid = ctx->valid_map.base_valid_count +
156 ctx->valid_map.cache_valid_count;
157
158 if (ftl_bitmap_count_set(dev->valid_map) != valid) {
159 ctx->status = -EINVAL;
160 }
161 }
162
163 /* All done */
164 if (ctx->status) {
165 ftl_mngt_fail_step(mngt);
166 } else {
167 ftl_mngt_next_step(mngt);
168 }
169 }
170 }
171
172 /*
173 * Verifies the contents of L2P versus valid map. Makes sure any physical addresses in the L2P
174 * have their corresponding valid bits set and that two different logical addresses don't point
175 * to the same physical address.
176 *
177 * For debugging purposes only, directed via environment variable - whole L2P needs to be loaded in
178 * and checked.
179 */
180 static const struct ftl_mngt_process_desc desc_self_test = {
181 .name = "[Test] Startup Test",
182 .ctx_size = sizeof(struct ftl_validate_ctx),
183 .steps = {
184 {
185 .name = "[TEST] Initialize selftest",
186
187 .action = ftl_mngt_test_prepare,
188 .cleanup = ftl_mngt_test_cleanup
189 },
190 {
191 .name = "[TEST] Validate map and L2P consistency",
192 .action = ftl_mngt_test_valid_map
193 },
194 {
195 .name = "[TEST] Deinitialize cleanup",
196 .action = ftl_mngt_test_cleanup
197 },
198 {}
199 }
200 };
201
202 void
ftl_mngt_self_test(struct spdk_ftl_dev * dev,struct ftl_mngt_process * mngt)203 ftl_mngt_self_test(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt)
204 {
205 if (getenv("FTL_SELF_TEST")) {
206 ftl_mngt_call_process(mngt, &desc_self_test, NULL);
207 } else {
208 FTL_NOTICELOG(dev, "Self test skipped\n");
209 ftl_mngt_next_step(mngt);
210 }
211 }
212