1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <inc/config.h>
8 
9 #if INC_FTL_NDM
10 #include <errno.h>
11 #include <string.h>
12 #include <sys.h>
13 #include <kprivate/ftl_vc.h>
14 #include <kprivate/ndm.h>
15 #include <kprivate/ftl_mc.h>
16 
17 /***********************************************************************/
18 /* Configuration                                                       */
19 /***********************************************************************/
20 #define FTLN_LEGACY TRUE // TRUE to be backward compatible
21 #define INC_ELIST TRUE   // if true, write erased blocks list
22 #define DEBUG_ELIST FALSE
23 #ifndef FTLN_DEBUG
24 #define FTLN_DEBUG TRUE
25 #endif
26 #ifndef FTLN_DEBUG_PTR
27 #define FTLN_DEBUG_PTR FALSE
28 #endif
29 #if !FTLN_LEGACY
30 #define FTLN_3B_PN TRUE // if true, use 3B page numbers
31 #endif
32 
33 /***********************************************************************/
34 /* Symbol Definitions                                                  */
35 /***********************************************************************/
36 #define FTLN_MIN_FREE_BLKS 4
37 
38 //
39 // FTL Flag Values
40 //
41 #define FTLN_FAT_VOL (1 << 0)    // TargetFAT volume
42 #define FTLN_XFS_VOL (1 << 1)    // TargetXFS volume
43 #define FTLN_FATAL_ERR (1 << 2)  // fatal I/O error has occurred
44 #define FTLN_MOUNTED (1 << 3)    // FTL is mounted flag
45 
46 //
47 // FTL meta-page information
48 //
49 #define FTLN_META_VER0 20100427  // first metapage version
50 #define FTLN_META_VER1 20180423  // second metapage version
51 #define FTLN_META_VER_LOC 0      // version location in page
52 #define FTLN_META_TYP_LOC 4      // page type location
53 #define FTLN_META_DATA_BEG 8     // starting data offset
54 
55 //
56 // Meta-Page Types
57 //
58 #define CONT_FORMAT 0
59 #define ERASED_LIST 1
60 
61 /***********************************************************************/
62 /* Macro Definitions                                                   */
63 /***********************************************************************/
64 //
65 // Block Array Definitions
66 //
67 // A bdata entry is a 32 bit value that holds block metadata in RAM
68 // Bit 31 indicates if a block is free (1) or used (0)
69 // For free blocks:
70 //   Bit 30 indicates if a free block is erased (1) or not (0)
71 // For used blocks:
72 //   Bit 30 - indicates if a block is map (1) or volume (0) block
73 //   Bits 29 through 20 - number of used pages in block
74 //   Bits 19 through  0 - block read count
75 //
76 // 0xC0000000 - free/erased block
77 // 0x80000000 - free block
78 // 0x7XXXXXXX-0x4XXXXXXX - map block
79 // 0x3XXXXXXX-0x0XXXXXXX - used block
80 //
81 #define BLK_STATE_MASK 0xC0000000
82 #define FREE_BLK_FLAG 0x80000000
83 #define ERASED_BLK_FLAG 0x40000000  // applies only to free blocks
84 #define MAP_BLK_STATE 0x40000000
85 #define USED_MASK 0x3FF00000  // applies to map/vol blocks
86 #define RC_MASK 0x000FFFFF    // applies to map/vol blocks
87 
88 #define PGS_PER_BLK_MAX (USED_MASK >> 20)
89 
90 #define IS_FREE(b) ((b)&FREE_BLK_FLAG)
91 #define IS_ERASED(b) (((b)&BLK_STATE_MASK) == (FREE_BLK_FLAG | ERASED_BLK_FLAG))
92 #define IS_MAP_BLK(b) (((b)&BLK_STATE_MASK) == MAP_BLK_STATE)
93 #define SET_MAP_BLK(bd) (bd = MAP_BLK_STATE)
94 
95 #define NUM_USED(bd) (((bd)&USED_MASK) >> 20)
96 #define DEC_USED(bd) ((bd) -= (1 << 20))
97 #define INC_USED(bd) ((bd) += (1 << 20))
98 #define GET_RC(bd) ((bd)&RC_MASK)
99 #define SET_RC(bd, n) ((bd) = ((bd) & ~RC_MASK) | n)
100 #define INC_RC(ftl, bdp, c)               \
101     do {                                  \
102         ui32 rc = GET_RC(*bdp) + c;       \
103                                           \
104         if (rc > RC_MASK)                 \
105             rc = RC_MASK;                 \
106         *bdp = rc | (*bdp & ~RC_MASK);    \
107         if (rc >= (ftl)->max_rc)          \
108             (ftl)->max_rc_blk = (ui32)-2; \
109     } /*lint !e717*/ \
110     while (0)
111 #define SET_MAX_RC(ftl, bdp)                      \
112     do {                                          \
113         (ftl)->max_rc_blk = (ui32)-2;             \
114         *bdp = (ftl)->max_rc | (*bdp & ~RC_MASK); \
115     } /*lint !e717*/ \
116     while (0)
117 
118 
119 // Map Page Array Definitions
120 //
121 // Get/set the physical page corresponding to a VPN
122 //
123 #if FTLN_3B_PN
124 #define FTLN_PN_SZ 3
125 #define UNMAPPED_PN 0x00FFFFFF
126 #define GET_MAP_PPN(maddr) RD24_LE(maddr)
127 #define SET_MAP_PPN(maddr, pn) WR24_LE(pn, maddr)
128 #else
129 #define FTLN_PN_SZ 4
130 #define UNMAPPED_PN 0xFFFFFFFF
131 #define GET_MAP_PPN(maddr) RD32_LE(maddr)
132 #define SET_MAP_PPN(maddr, pn) WR32_LE(pn, maddr)
133 #endif
134 
135 //
136 // Spare Area Access Definitions//
137 //
138 // Layout of Spare Area (Extra Bytes)
139 //  - byte   0: bad block mark byte - unused by the FTL
140 //  - bytes  1 -  4: virtual page number
141 //  - bytes  5 -  8: block count (BC)
142 //  - bytes  9 - 11 and MSH of 12: block wear count (WC)
143 //  - bytes LSH of 12 and 13 - 14: page validity check
144 //  - byte  15: NDM control page mark byte
145 //
146 //
147 // Get/set virtual page number from spare area (bytes 1 - 4)
148 //
149 #define GET_SA_VPN(spare) RD32_LE(&spare[1])
150 #define SET_SA_VPN(vpn, spare) WR32_LE(vpn, &spare[1])
151 
152 //
153 // Get/set block count from spare area (bytes 5 - 8)
154 //
155 #define GET_SA_BC(spare) RD32_LE(&spare[5])
156 #define SET_SA_BC(bc, spare) WR32_LE(bc, &spare[5])
157 
158 //
159 // Get/set block wear count from spare area (bytes 9 - 11 and MSH of 12)
160 //
161 #define GET_SA_WC(spare) (RD24_LE(&spare[9]) | ((spare[12] & 0xF0) << 20))
162 #define SET_SA_WC(wc, spare)                                 \
163     {                                                        \
164         WR24_LE(wc, &spare[9]);                              \
165         spare[12] = (spare[12] & 0xF) | ((wc >> 20) & 0xF0); \
166     }
167 
168 /***********************************************************************/
169 /* Type Declarations                                                   */
170 /***********************************************************************/
171 //
172 // The TargetFTL-NDM volume type
173 //
174 typedef struct ftln* FTLN;
175 typedef const struct ftln* CFTLN;
176 struct ftln {
177     CircLink link; // volume list link
178 
179     // Driver Functions
180     int (*write_page)(ui32 pn, const void* data, void* spare, void* ndm);
181     int (*read_spare)(ui32 pn, void* spare, void* ndm);
182     int (*read_pages)(ui32 start_pn, ui32 count, void* data, void* spare, void* ndm);
183     int (*write_pages)(ui32 start_pn, ui32 count, const void* data, void* spare, void* ndm);
184     int (*page_check)(ui32 pn, ui8* data, ui8* spare, void* ndm);
185     int (*xfer_page)(ui32 old_pn, ui32 new_pn, ui8* data, ui8* spare, void* ndm);
186     int (*erase_block)(ui32 pn, void* ndm);
187 #if INC_FTL_NDM_MLC
188     ui32 (*pair_offset)(ui32 page_offset, void* ndm);
189 #endif
190 
191     //
192     // Callback function for freeing FTL specific resources
193     //
194     void (*free_ftl)(void* vol);
195 
196 // Virtual Volume Variables
197 #if INC_FAT_MBR
198     ui32 vol_frst_sect; // first (boot) volume sector
199 #endif
200     ui32 sect_size;      // virtual sector size in bytes
201     ui32 sects_per_page; // virtual sectors in a page
202 
203     // Driver Dependent Variables
204     ui32 num_pages;   // total number of pages
205     ui32 pgs_per_blk; // number of pages in a block
206     ui32 block_size;  // block size in bytes
207     ui32 num_blks;    // number of blocks
208     ui32 page_size;   // page size in bytes
209     ui32 start_pn;    // first page on device for volume
210     void* ndm;        // pointer to NDM this FTL belongs to
211 
212     ui32 flags; // holds various FTL flags
213 #if INC_FAT_MBR
214     ui32 frst_clust_sect; // first sector of first FAT cluster
215     ui32 clust_off;       // offset to page align cluster sectors
216 #endif
217     ui32* bdata;     // block metadata: flags and counts
218     ui8* blk_wc_lag; // amount block erase counts lag 'high_wc'
219     ui32* mpns;      // array holding phy page # of map pages
220 
221 #if INC_FTL_PAGE_CACHE
222     void* vol_cache; // handle to volume page cache
223 #endif
224     FTLMC* map_cache;      // handle to map page cache
225     ui32 free_vpn;         // next free page for volume page write
226     ui32 free_mpn;         // next free page for map page write
227     ui32 mappings_per_mpg; // number of phys page numbers per map page
228     ui32 num_vsects;       // number of volume sectors (FAT)
229     ui32 num_vpages;       // number of volume pages
230     ui32 num_free_blks;    // number of free blocks
231     ui32 num_map_pgs;      // number of pages holding map data
232     ui32 high_wc;          // highest block wear count
233     ui32 high_bc;          // highest map block write count
234     ui32 max_rc;           // per block read wear limit
235     ui32 max_rc_blk;       // if not -1, # of block w/high read cnt
236     ui32 high_bc_mblk;     // last map block
237     ui32 high_bc_mblk_po;  // used page offset on last map block
238     ui32 resume_vblk;      // vblk in interrupted recycle recovery
239     ui32 resume_tblk;      // tmp blk for interrupted recycle recovery
240     ui32 resume_po;        // resume vblk's highest used page offset
241 #if INC_ELIST
242     ui32 elist_blk; // if valid, # of block holding erased list
243 #endif
244     ftl_ndm_stats stats; // driver call counts
245 
246     ui8* main_buf; // NAND main page buffer
247 #if INC_SECT_FTL
248     ui8* swap_page; // for accessing sector in page
249 #endif
250     ui8* spare_buf; // spare buffer for single/multi-pg access
251 
252     ui32 type;          // type of NAND - SLC or MLC
253     ui8 eb_size;        // spare area size in bytes
254     ui8 copy_end_found; // vblk resume copy-end mark found
255     ui8 deferment;      // # of recycles before applying wear limit
256 #if FTLN_DEBUG
257     ui8 max_wc_lag;  // maximum observed lag below hi wear count
258     ui8 max_wc_over; // # of times max WC (0xFF) was exceeded
259 #endif
260 #if FS_ASSERT
261     ui8 assert_no_recycle; // test no recycle changes physical page #
262 #endif
263     char vol_name[FILENAME_MAX]; // volume name
264 };
265 
266 /***********************************************************************/
267 /* Variable Declarations                                               */
268 /***********************************************************************/
269 extern CircLink FtlnVols;
270 #if FTLN_DEBUG_PTR
271 extern FTLN Ftln;
272 #endif
273 
274 /***********************************************************************/
275 /* Function Prototypes                                                 */
276 /***********************************************************************/
277 void* FtlnAddVol(FtlNdmVol* ftl, int type, int sect_size, void* fs_vol);
278 int FtlnDelVol(FTLN ftl);
279 int FtlnWrSects(const void* buf, ui32 first, int count, void* vol);
280 int FtlnRdSects(void* buf, ui32 first, int count, void* vol);
281 int FtlnReport(void* vol, ui32 msg, ...);
282 ui32 FtlnGarbLvl(CFTLN ftl);
283 int FtlnVclean(FTLN ftl);
284 int FtlnMapGetPpn(CFTLN ftl, ui32 vpn, ui32* pnp);
285 int FtlnMapSetPpn(CFTLN ftl, ui32 vpn, ui32 ppn);
286 int FtlnRecCheck(FTLN ftl, int wr_cnt);
287 int FtlnRecNeeded(CFTLN ftl, int wr_cnt);
288 int FtlnRdPage(FTLN ftl, ui32 pn, void* buf);
289 
290 int FtlnMapWr(void* vol, ui32 mpn, void* buf);
291 int FtlnMapRd(void* vol, ui32 mpn, void* buf, int* unmapped);
292 int FtlnMetaWr(FTLN ftl, ui32 type);
293 
294 int FtlnVpnWr(FcEntry* c_e, int unused, void* vol);
295 int FtlnVpnRd(void* buf, ui32 vpn, void* vol);
296 
297 void FtlnDecUsed(FTLN ftl, ui32 pn, ui32 vpn);
298 int FtlnFormat(FTLN ftl, ui32 meta_block);
299 void FtlnStateRst(FTLN ftl);
300 int FtlnEraseBlk(FTLN ftl, ui32 b);
301 ui32 FtlnLoWcFreeBlk(CFTLN ftl);
302 ui32 FtlnHiWcFreeBlk(CFTLN ftl);
303 int FtlnRecycleMapBlk(FTLN ftl, ui32 recycle_b);
304 
305 int FtlnSetClustSect1(FTLN ftl, const ui8* bpb, int format_req);
306 int FtlnFatErr(FTLN ftl);
307 
308 #if INC_FTL_NDM_MLC
309 void FtlnMlcSafeFreeVpn(FTLN ftl);
310 #endif
311 
312 void FtlnBlkStats(CFTLN ftl);
313 void FtlnStats(FTLN ftl);
314 void FtlnShowBlks(void);
315 void FtlnCheckBlank(FTLN ftl, ui32 b);
316 
317 #endif // INC_FTL_NDM
318