xref: /spdk/lib/ftl/ftl_internal.h (revision 2d610abe8d35ec40014b8a449b760cf732797c75)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2022 Intel Corporation.
3  *   Copyright 2023 Solidigm All Rights Reserved
4  *   All rights reserved.
5  */
6 
7 #ifndef FTL_INTERNAL_H
8 #define FTL_INTERNAL_H
9 
10 #include "spdk/stdinc.h"
11 #include "spdk/crc32.h"
12 #include "spdk/util.h"
13 #include "spdk/uuid.h"
14 
15 #include "utils/ftl_bitmap.h"
16 #include "utils/ftl_md.h"
17 
18 /* Marks address as invalid */
19 #define FTL_ADDR_INVALID	((ftl_addr)-1)
20 /* Marks LBA as invalid */
21 #define FTL_LBA_INVALID		((uint64_t)-1)
22 /* Smallest data unit size */
23 #define FTL_BLOCK_SIZE		4096ULL
24 
25 #define FTL_P2L_VERSION_0	0
26 #define FTL_P2L_VERSION_1	1
27 #define FTL_P2L_VERSION_2	2
28 
29 #define FTL_P2L_VERSION_CURRENT FTL_P2L_VERSION_2
30 
31 /*
32  * This type represents address in the ftl address space. Values from 0 to based bdev size are
33  * mapped directly to base device lbas. Values above that represent nv cache lbas.
34  */
35 typedef uint64_t ftl_addr;
36 
37 struct spdk_ftl_dev;
38 
39 enum ftl_md_type {
40 	FTL_MD_TYPE_BAND,
41 	FTL_MD_TYPE_CHUNK
42 };
43 
44 enum ftl_band_type {
45 	FTL_BAND_TYPE_GC = 1,
46 	FTL_BAND_TYPE_COMPACTION
47 };
48 
49 enum ftl_md_status {
50 	FTL_MD_SUCCESS,
51 	/* Metadata read failure */
52 	FTL_MD_IO_FAILURE,
53 	/* Invalid version */
54 	FTL_MD_INVALID_VER,
55 	/* UUID doesn't match */
56 	FTL_MD_NO_MD,
57 	/* UUID and version matches but CRC doesn't */
58 	FTL_MD_INVALID_CRC,
59 	/* Vld or p2l map size doesn't match */
60 	FTL_MD_INVALID_SIZE
61 };
62 
63 struct ftl_p2l_map_entry {
64 	uint64_t lba;
65 	uint64_t seq_id;
66 };
67 
68 /* Number of p2l entries that could be stored in a single block for bands */
69 #define FTL_NUM_LBA_IN_BLOCK	(FTL_BLOCK_SIZE / sizeof(struct ftl_p2l_map_entry))
70 
71 /*
72  * Mapping of physical (actual location on disk) to logical (user's POV) addresses. Used in two main scenarios:
73  * - during relocation FTL needs to pin L2P pages (this allows to check which pages to pin) and move still valid blocks
74  * (valid map allows for preliminary elimination of invalid physical blocks, but user data could invalidate a location
75  * during read/write operation, so actual comparison against L2P needs to be done)
76  * - After dirty shutdown the state of the L2P is unknown and needs to be rebuilt - it is done by applying all P2L, taking
77  * into account ordering of user writes
78  */
79 struct ftl_p2l_map {
80 	/* Number of valid LBAs */
81 	size_t					num_valid;
82 
83 	/* P2L map's reference count, prevents premature release of resources during dirty shutdown recovery for open bands */
84 	size_t					ref_cnt;
85 
86 	/* Bitmap of valid LBAs */
87 	struct ftl_bitmap			*valid;
88 
89 	/* P2L map (only valid for open/relocating bands) */
90 	union {
91 		struct ftl_p2l_map_entry	*band_map;
92 		void				*chunk_map;
93 	};
94 
95 	/* DMA buffer for region's metadata entry */
96 	union {
97 		struct ftl_band_md		*band_dma_md;
98 
99 		struct ftl_nv_cache_chunk_md	*chunk_dma_md;
100 	};
101 
102 	/* P2L checkpointing region */
103 	struct ftl_p2l_ckpt			*p2l_ckpt;
104 };
105 
106 struct ftl_p2l_sync_ctx {
107 	struct ftl_band *band;
108 	uint64_t	xfer_start;
109 	uint64_t	xfer_end;
110 	int		md_region;
111 };
112 
113 struct ftl_p2l_ckpt_page {
114 	struct ftl_p2l_map_entry map[FTL_NUM_LBA_IN_BLOCK];
115 };
116 
117 struct ftl_p2l_ckpt_page_no_vss {
118 	union ftl_md_vss metadata;
119 	struct ftl_p2l_map_entry map[FTL_NUM_LBA_IN_BLOCK - sizeof(union ftl_md_vss) / sizeof(
120 								  struct ftl_p2l_map_entry)];
121 } __attribute__((packed));
122 SPDK_STATIC_ASSERT(sizeof(struct ftl_p2l_ckpt_page_no_vss) == FTL_BLOCK_SIZE,
123 		   "ftl_p2l_ckpt_page_no_vss incorrect size");
124 
125 #define FTL_NUM_P2L_ENTRIES_NO_VSS (SPDK_COUNTOF_MEMBER(struct ftl_p2l_ckpt_page_no_vss, map))
126 
127 #define FTL_TRIM_LOG_VERSION_0		0
128 #define FTL_TRIM_LOG_VERSION_1		1
129 #define FTL_TRIM_LOG_VERSION_CURRENT	FTL_TRIM_LOG_VERSION_1
130 
131 struct ftl_trim_log {
132 	union ftl_md_vss hdr;
133 	char reserved[FTL_BLOCK_SIZE - sizeof(union ftl_md_vss)];
134 };
135 SPDK_STATIC_ASSERT(sizeof(struct ftl_trim_log) == FTL_BLOCK_SIZE, "Invalid trim log page size");
136 
137 struct ftl_p2l_ckpt;
138 struct ftl_band;
139 struct spdk_ftl_dev;
140 struct ftl_mngt_process;
141 struct ftl_rq;
142 
143 int ftl_p2l_ckpt_init(struct spdk_ftl_dev *dev);
144 
145 void ftl_p2l_ckpt_deinit(struct spdk_ftl_dev *dev);
146 
147 void ftl_p2l_ckpt_issue(struct ftl_rq *rq);
148 
149 struct ftl_p2l_ckpt *ftl_p2l_ckpt_acquire(struct spdk_ftl_dev *dev);
150 
151 struct ftl_p2l_ckpt *ftl_p2l_ckpt_acquire_region_type(struct spdk_ftl_dev *dev,
152 		uint32_t region_type);
153 
154 void ftl_p2l_ckpt_release(struct spdk_ftl_dev *dev, struct ftl_p2l_ckpt *ckpt);
155 
156 enum ftl_layout_region_type ftl_p2l_ckpt_region_type(const struct ftl_p2l_ckpt *ckpt);
157 
158 #if defined(DEBUG)
159 void ftl_p2l_validate_ckpt(struct ftl_band *band);
160 #else
161 static inline void
162 ftl_p2l_validate_ckpt(struct ftl_band *band)
163 {
164 }
165 #endif
166 
167 uint64_t ftl_mngt_p2l_ckpt_get_seq_id(struct spdk_ftl_dev *dev, int md_region);
168 
169 int ftl_mngt_p2l_ckpt_restore(struct ftl_band *band, uint32_t md_region, uint64_t seq_id);
170 
171 int ftl_mngt_p2l_ckpt_restore_clean(struct ftl_band *band);
172 
173 void ftl_mngt_p2l_ckpt_restore_shm_clean(struct ftl_band *band);
174 
175 void ftl_mngt_persist_bands_p2l(struct ftl_mngt_process *mngt);
176 
177 struct ftl_reloc *ftl_reloc_init(struct spdk_ftl_dev *dev);
178 
179 void ftl_reloc_free(struct ftl_reloc *reloc);
180 
181 void ftl_reloc(struct ftl_reloc *reloc);
182 
183 void ftl_reloc_halt(struct ftl_reloc *reloc);
184 
185 void ftl_reloc_resume(struct ftl_reloc *reloc);
186 
187 bool ftl_reloc_is_halted(const struct ftl_reloc *reloc);
188 
189 #endif /* FTL_INTERNAL_H */
190