]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
1 | /*- |
2 | * BSD LICENSE | |
3 | * | |
4 | * Copyright (c) Intel Corporation. | |
5 | * All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * | |
11 | * * Redistributions of source code must retain the above copyright | |
12 | * notice, this list of conditions and the following disclaimer. | |
13 | * * Redistributions in binary form must reproduce the above copyright | |
14 | * notice, this list of conditions and the following disclaimer in | |
15 | * the documentation and/or other materials provided with the | |
16 | * distribution. | |
17 | * * Neither the name of Intel Corporation nor the names of its | |
18 | * contributors may be used to endorse or promote products derived | |
19 | * from this software without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
24 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
25 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
26 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
27 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #ifndef FTL_BAND_H | |
35 | #define FTL_BAND_H | |
36 | ||
37 | #include "spdk/stdinc.h" | |
38 | #include "spdk/bit_array.h" | |
39 | #include "spdk/queue.h" | |
f67539c2 | 40 | #include "spdk/bdev_zone.h" |
9f95a23c TL |
41 | |
42 | #include "ftl_io.h" | |
f67539c2 TL |
43 | #include "ftl_addr.h" |
44 | #include "ftl_core.h" | |
9f95a23c TL |
45 | |
46 | /* Number of LBAs that could be stored in a single block */ | |
47 | #define FTL_NUM_LBA_IN_BLOCK (FTL_BLOCK_SIZE / sizeof(uint64_t)) | |
48 | ||
49 | struct spdk_ftl_dev; | |
50 | struct ftl_lba_map_request; | |
51 | ||
f67539c2 TL |
52 | struct ftl_zone { |
53 | struct spdk_bdev_zone_info info; | |
9f95a23c TL |
54 | |
55 | /* Indicates that there is inflight write */ | |
56 | bool busy; | |
57 | ||
f67539c2 | 58 | CIRCLEQ_ENTRY(ftl_zone) circleq; |
9f95a23c TL |
59 | }; |
60 | ||
61 | enum ftl_md_status { | |
62 | FTL_MD_SUCCESS, | |
63 | /* Metadata read failure */ | |
64 | FTL_MD_IO_FAILURE, | |
65 | /* Invalid version */ | |
66 | FTL_MD_INVALID_VER, | |
67 | /* UUID doesn't match */ | |
68 | FTL_MD_NO_MD, | |
69 | /* UUID and version matches but CRC doesn't */ | |
70 | FTL_MD_INVALID_CRC, | |
71 | /* Vld or lba map size doesn't match */ | |
72 | FTL_MD_INVALID_SIZE | |
73 | }; | |
74 | ||
75 | enum ftl_lba_map_seg_state { | |
76 | FTL_LBA_MAP_SEG_CLEAR, | |
77 | FTL_LBA_MAP_SEG_PENDING, | |
78 | FTL_LBA_MAP_SEG_CACHED | |
79 | }; | |
80 | ||
81 | struct ftl_lba_map { | |
82 | /* LBA/vld map lock */ | |
83 | pthread_spinlock_t lock; | |
84 | ||
85 | /* Number of valid LBAs */ | |
86 | size_t num_vld; | |
87 | ||
88 | /* LBA map's reference count */ | |
89 | size_t ref_cnt; | |
90 | ||
91 | /* Bitmap of valid LBAs */ | |
92 | struct spdk_bit_array *vld; | |
93 | ||
94 | /* LBA map (only valid for open/relocating bands) */ | |
95 | uint64_t *map; | |
96 | ||
97 | /* LBA map segment state map (clear, pending, cached) */ | |
98 | uint8_t *segments; | |
99 | ||
100 | LIST_HEAD(, ftl_lba_map_request) request_list; | |
101 | ||
102 | /* Metadata DMA buffer (only valid for open/relocating bands) */ | |
103 | void *dma_buf; | |
104 | }; | |
105 | ||
106 | enum ftl_band_state { | |
107 | FTL_BAND_STATE_FREE, | |
108 | FTL_BAND_STATE_PREP, | |
109 | FTL_BAND_STATE_OPENING, | |
110 | FTL_BAND_STATE_OPEN, | |
111 | FTL_BAND_STATE_FULL, | |
112 | FTL_BAND_STATE_CLOSING, | |
113 | FTL_BAND_STATE_CLOSED, | |
114 | FTL_BAND_STATE_MAX | |
115 | }; | |
116 | ||
117 | struct ftl_lba_map_request { | |
118 | /* Completion callback */ | |
119 | ftl_io_fn cb; | |
120 | ||
121 | /* Completion callback context */ | |
122 | void *cb_ctx; | |
123 | ||
124 | /* Bit array of requested segments */ | |
125 | struct spdk_bit_array *segments; | |
126 | ||
127 | /* Number of pending segments to read */ | |
128 | size_t num_pending; | |
129 | ||
130 | LIST_ENTRY(ftl_lba_map_request) list_entry; | |
131 | }; | |
132 | ||
133 | struct ftl_band { | |
134 | /* Device this band belongs to */ | |
135 | struct spdk_ftl_dev *dev; | |
136 | ||
f67539c2 TL |
137 | /* Number of operational zones */ |
138 | size_t num_zones; | |
9f95a23c | 139 | |
f67539c2 TL |
140 | /* Array of zones */ |
141 | struct ftl_zone *zone_buf; | |
9f95a23c | 142 | |
f67539c2 TL |
143 | /* List of operational zones */ |
144 | CIRCLEQ_HEAD(, ftl_zone) zones; | |
9f95a23c TL |
145 | |
146 | /* LBA map */ | |
147 | struct ftl_lba_map lba_map; | |
148 | ||
149 | /* Band's state */ | |
150 | enum ftl_band_state state; | |
151 | ||
152 | /* Band's index */ | |
153 | unsigned int id; | |
154 | ||
155 | /* Latest merit calculation */ | |
156 | double merit; | |
157 | ||
158 | /* High defrag priority - means that the metadata should be copied and */ | |
159 | /* the band should be defragged immediately */ | |
160 | int high_prio; | |
161 | ||
162 | /* Sequence number */ | |
163 | uint64_t seq; | |
164 | ||
165 | /* Number of defrag cycles */ | |
166 | uint64_t wr_cnt; | |
167 | ||
f67539c2 TL |
168 | /* End metadata start addr */ |
169 | struct ftl_addr tail_md_addr; | |
170 | ||
171 | /* Bitmap of all bands that have its data moved onto this band */ | |
172 | struct spdk_bit_array *reloc_bitmap; | |
173 | /* Number of open bands containing data moved from this band */ | |
174 | size_t num_reloc_bands; | |
175 | /* Number of blocks currently being moved from this band */ | |
176 | size_t num_reloc_blocks; | |
9f95a23c TL |
177 | |
178 | /* Free/shut bands' lists */ | |
179 | LIST_ENTRY(ftl_band) list_entry; | |
180 | ||
181 | /* High priority queue link */ | |
182 | STAILQ_ENTRY(ftl_band) prio_stailq; | |
183 | }; | |
184 | ||
f67539c2 TL |
185 | uint64_t ftl_band_block_offset_from_addr(struct ftl_band *band, struct ftl_addr addr); |
186 | struct ftl_addr ftl_band_addr_from_block_offset(struct ftl_band *band, uint64_t block_off); | |
9f95a23c TL |
187 | void ftl_band_set_state(struct ftl_band *band, enum ftl_band_state state); |
188 | size_t ftl_band_age(const struct ftl_band *band); | |
189 | void ftl_band_acquire_lba_map(struct ftl_band *band); | |
190 | int ftl_band_alloc_lba_map(struct ftl_band *band); | |
191 | void ftl_band_clear_lba_map(struct ftl_band *band); | |
192 | void ftl_band_release_lba_map(struct ftl_band *band); | |
193 | int ftl_band_read_lba_map(struct ftl_band *band, | |
194 | size_t offset, size_t lba_cnt, | |
195 | ftl_io_fn cb_fn, void *cb_ctx); | |
f67539c2 TL |
196 | struct ftl_addr ftl_band_next_xfer_addr(struct ftl_band *band, struct ftl_addr addr, |
197 | size_t num_blocks); | |
198 | struct ftl_addr ftl_band_next_addr(struct ftl_band *band, struct ftl_addr addr, | |
199 | size_t offset); | |
200 | size_t ftl_band_num_usable_blocks(const struct ftl_band *band); | |
201 | size_t ftl_band_user_blocks_left(const struct ftl_band *band, size_t offset); | |
202 | size_t ftl_band_user_blocks(const struct ftl_band *band); | |
9f95a23c | 203 | void ftl_band_set_addr(struct ftl_band *band, uint64_t lba, |
f67539c2 TL |
204 | struct ftl_addr addr); |
205 | struct ftl_band *ftl_band_from_addr(struct spdk_ftl_dev *dev, struct ftl_addr addr); | |
206 | struct ftl_zone *ftl_band_zone_from_addr(struct ftl_band *band, struct ftl_addr); | |
9f95a23c | 207 | void ftl_band_md_clear(struct ftl_band *band); |
f67539c2 | 208 | int ftl_band_read_tail_md(struct ftl_band *band, struct ftl_addr, |
9f95a23c TL |
209 | ftl_io_fn cb_fn, void *cb_ctx); |
210 | int ftl_band_read_head_md(struct ftl_band *band, ftl_io_fn cb_fn, void *cb_ctx); | |
211 | int ftl_band_write_tail_md(struct ftl_band *band, ftl_io_fn cb); | |
212 | int ftl_band_write_head_md(struct ftl_band *band, ftl_io_fn cb); | |
f67539c2 TL |
213 | struct ftl_addr ftl_band_tail_md_addr(struct ftl_band *band); |
214 | struct ftl_addr ftl_band_head_md_addr(struct ftl_band *band); | |
9f95a23c TL |
215 | void ftl_band_write_failed(struct ftl_band *band); |
216 | int ftl_band_full(struct ftl_band *band, size_t offset); | |
9f95a23c | 217 | int ftl_band_write_prep(struct ftl_band *band); |
f67539c2 TL |
218 | struct ftl_zone *ftl_band_next_operational_zone(struct ftl_band *band, |
219 | struct ftl_zone *zone); | |
9f95a23c | 220 | size_t ftl_lba_map_pool_elem_size(struct spdk_ftl_dev *dev); |
f67539c2 TL |
221 | void ftl_band_remove_zone(struct ftl_band *band, struct ftl_zone *zone); |
222 | ||
9f95a23c TL |
223 | |
224 | static inline int | |
225 | ftl_band_empty(const struct ftl_band *band) | |
226 | { | |
227 | return band->lba_map.num_vld == 0; | |
228 | } | |
229 | ||
f67539c2 TL |
230 | static inline struct ftl_zone * |
231 | ftl_band_next_zone(struct ftl_band *band, struct ftl_zone *zone) | |
9f95a23c | 232 | { |
f67539c2 TL |
233 | assert(zone->info.state != SPDK_BDEV_ZONE_STATE_OFFLINE); |
234 | return CIRCLEQ_LOOP_NEXT(&band->zones, zone, circleq); | |
9f95a23c TL |
235 | } |
236 | ||
237 | static inline void | |
238 | ftl_band_set_next_state(struct ftl_band *band) | |
239 | { | |
240 | ftl_band_set_state(band, (band->state + 1) % FTL_BAND_STATE_MAX); | |
241 | } | |
242 | ||
243 | static inline int | |
244 | ftl_band_state_changing(struct ftl_band *band) | |
245 | { | |
246 | return band->state == FTL_BAND_STATE_OPENING || | |
247 | band->state == FTL_BAND_STATE_CLOSING; | |
248 | } | |
249 | ||
250 | static inline int | |
f67539c2 | 251 | ftl_band_block_offset_valid(struct ftl_band *band, size_t block_off) |
9f95a23c TL |
252 | { |
253 | struct ftl_lba_map *lba_map = &band->lba_map; | |
254 | ||
255 | pthread_spin_lock(&lba_map->lock); | |
f67539c2 | 256 | if (spdk_bit_array_get(lba_map->vld, block_off)) { |
9f95a23c TL |
257 | pthread_spin_unlock(&lba_map->lock); |
258 | return 1; | |
259 | } | |
260 | ||
261 | pthread_spin_unlock(&lba_map->lock); | |
262 | return 0; | |
263 | } | |
264 | ||
265 | static inline int | |
f67539c2 | 266 | ftl_band_zone_is_last(struct ftl_band *band, struct ftl_zone *zone) |
9f95a23c | 267 | { |
f67539c2 | 268 | return zone == CIRCLEQ_LAST(&band->zones); |
9f95a23c TL |
269 | } |
270 | ||
271 | static inline int | |
f67539c2 | 272 | ftl_band_zone_is_first(struct ftl_band *band, struct ftl_zone *zone) |
9f95a23c | 273 | { |
f67539c2 | 274 | return zone == CIRCLEQ_FIRST(&band->zones); |
9f95a23c TL |
275 | } |
276 | ||
277 | static inline int | |
f67539c2 | 278 | ftl_zone_is_writable(const struct spdk_ftl_dev *dev, const struct ftl_zone *zone) |
9f95a23c | 279 | { |
f67539c2 TL |
280 | bool busy = ftl_is_append_supported(dev) ? false : zone->busy; |
281 | ||
282 | return (zone->info.state == SPDK_BDEV_ZONE_STATE_OPEN || | |
283 | zone->info.state == SPDK_BDEV_ZONE_STATE_EMPTY) && | |
284 | !busy; | |
9f95a23c TL |
285 | } |
286 | ||
287 | #endif /* FTL_BAND_H */ |