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