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 #include "ftlnp.h"
6
7 #if INC_FTL_NDM
8 // Configuration
9 #define DEBUG_RESUME FALSE
10
11 // Symbol Definitions
12 #define COPY_BLK_END 0xFFFFFFFD
13 #define COPY_BLK_MARK 0xFFFFFFFE
14
15 // Global Variable Declarations
16 CircLink FtlnVols = {&FtlnVols, &FtlnVols};
17 #if FTLN_DEBUG_PTR
18 FTLN Ftln;
19 #endif
20 #ifdef FTL_RESUME_STRESS
21 extern int FtlMblkResumeCnt, FtlVblkResumeCnt;
22 #endif
23
24 // Local Function Definitions
25
26 #if INC_ELIST
27 // proc_elist: Process elist map page
28 //
29 // Input: ftl = pointer to FTL control block
30 //
31 // Returns: NDM_PAGE_VALID (1) or NDM_PAGE_INVALID (2)
32 //
proc_elist(FTLN ftl)33 static int proc_elist(FTLN ftl) {
34 ui32 b, wc, *lp = (ui32 *)(ftl->main_buf + FTLN_META_DATA_BEG);
35
36 // Loop to process each block number/wear count entry in page.
37 do {
38 // Get number of proposed erased block and its wear count.
39 b = RD32_LE(lp);
40 ++lp;
41 wc = RD32_LE(lp);
42 ++lp;
43
44 // List validly ends with -1.
45 if (b > ftl->num_blks) {
46 PfAssert(b == (ui32)-1);
47 break;
48 }
49
50 // Check block's wear count.
51 if ((wc > ftl->high_wc) || (ftl->high_wc - wc > 0xFF))
52 return NDM_PAGE_INVALID;
53
54 // Skip the elist block itself. It is definitely not erased.
55 if (b != ftl->elist_blk) {
56 #if DEBUG_ELIST
57 // Verify that this block is unwritten.
58 FtlnCheckBlank(ftl, b);
59 #endif
60
61 // Verify block is unused and not a map block.
62 if (NUM_USED(ftl->bdata[b]) || IS_MAP_BLK(ftl->bdata[b]))
63 return NDM_PAGE_INVALID;
64
65 // If not already marked free, increment free block count.
66 if (!IS_FREE(ftl->bdata[b]))
67 ++ftl->num_free_blks;
68
69 // Set block's state and wear count lag.
70 ftl->bdata[b] = FREE_BLK_FLAG | ERASED_BLK_FLAG;
71 ftl->blk_wc_lag[b] = ftl->high_wc - wc;
72 }
73 } while (lp < (ui32*)(ftl->main_buf + ftl->page_size));
74
75 // Finished and no check failed. Page is valid.
76 return NDM_PAGE_VALID;
77 }
78 #endif
79
80 // map_page_check: Check contents of map page for validity
81 //
82 // Inputs: ftl = pointer to FTL control block
83 // apn = absolute physical page number (+ ftl->start_pn)
84 // process = do stored request if map page is meta-page
85 //
86 // Returns: -1 if fatal error, else NDM_PAGE_ERASED (0),
87 // NDM_PAGE_VALID (1), or NDM_PAGE_INVALID (2)
88 //
map_page_check(FTLN ftl,ui32 apn,int process)89 static int map_page_check(FTLN ftl, ui32 apn, int process) {
90 ui32 mpn, n, *ppns = (ui32 *)ftl->main_buf;
91 int status;
92
93 // Call driver validity check. Return -1 if error.
94 ++ftl->stats.page_check;
95 status = ftl->page_check(apn, ftl->main_buf, ftl->spare_buf, ftl->ndm);
96 if (status < 0)
97 return FtlnFatErr(ftl);
98
99 // If page is erased or invalid, return its status.
100 if (status != NDM_PAGE_VALID)
101 return status;
102
103 // If MPN too big, page is invalid.
104 mpn = GET_SA_VPN(ftl->spare_buf);
105 if (mpn >= ftl->num_map_pgs)
106 return NDM_PAGE_INVALID;
107
108 // If meta-page, check version, type, and format. Process if enabled.
109 if (mpn == ftl->num_map_pgs - 1) {
110 ui32 type, vers = RD32_LE(&ppns[0]);
111
112 // Check if first metapage version number.
113 if (vers == FTLN_META_VER0) {
114 ui32 b, i;
115
116 // If recycle block wrong, page is invalid.
117 b = RD32_LE(&ppns[1]);
118 if (b >= ftl->num_blks && b != (ui32)-1)
119 return NDM_PAGE_INVALID;
120
121 // Rest of the page should be erased. If not, page is invalid.
122 for (i = 2; i < ftl->page_size / sizeof(ui32); ++i)
123 if (RD32_LE(&ppns[i]) != (ui32)-1)
124 return NDM_PAGE_INVALID;
125 }
126
127 // Else check if second metapage version.
128 else if (vers == FTLN_META_VER1) {
129 // Read the meta-page type.
130 type = RD32_LE(&ppns[1]);
131
132 // Check if 'continue format' metadata.
133 if (type == CONT_FORMAT) {
134 // Rest of meta-page should be erased.
135 for (n = 2; n < ftl->page_size / sizeof(ui32); ++n)
136 if (RD32_LE(&ppns[n]) != (ui32)-1)
137 return NDM_PAGE_INVALID;
138
139 // If enabled, resume the format.
140 if (process)
141 if (FtlnFormat(ftl, (apn - ftl->start_pn) / ftl->pgs_per_blk))
142 return -1;
143 }
144 #if INC_ELIST
145 // Check if 'erased block list' metapage.
146 else if (type == ERASED_LIST) {
147 // Just save block number if called from build_map(). Called
148 // once for each used page in the elist block.
149 if (process == FALSE)
150 ftl->elist_blk = (apn - ftl->start_pn) / ftl->pgs_per_blk;
151
152 // Else read/check/process each elist page contents if caller
153 // is meta_read(). Called once, using last elist page number.
154 else {
155 ui32 ap0 = ftl->start_pn + ftl->elist_blk * ftl->pgs_per_blk;
156
157 // Process each elist page, from last to first.
158 for (;;) {
159 //---------------------------------------------------------
160 // Verify and apply elist page. Return if page invalid.
161 //---------------------------------------------------------
162 status = proc_elist(ftl);
163 if (status != NDM_PAGE_VALID)
164 return status;
165
166 //---------------------------------------------------------
167 // If first (perhaps only) page was processed, finished!
168 //---------------------------------------------------------
169 if (apn == ap0)
170 break;
171
172 //---------------------------------------------------------
173 // Move to next written page in backwards direction. If
174 // MLC flash, move to page whose pair has higher offset.
175 //---------------------------------------------------------
176 #if INC_FTL_NDM_MLC && (INC_FTL_NDM_SLC || INC_FTL_NOR_WR1)
177 if (ftl->type == NDM_MLC)
178 #endif
179 #if INC_NDM_MLC
180 for (;;) {
181 ui32 pg_offset = --apn % ftl->pgs_per_blk;
182
183 if (pg_offset == 0)
184 break;
185 if (ftl->pair_offset(pg_offset, ftl->ndm) >= pg_offset)
186 break;
187 }
188 #endif
189 #if INC_FTL_NDM_MLC && (INC_FTL_NDM_SLC || INC_FTL_NOR_WR1)
190 else
191 #endif
192 #if INC_FTL_NDM_SLC || INC_FTL_NOR_WR1
193 --apn;
194 #endif
195
196 //---------------------------------------------------------
197 // Call driver to read/check next page. Return -1 if error.
198 //---------------------------------------------------------
199 ++ftl->stats.page_check;
200 status = ftl->page_check(apn, ftl->main_buf, ftl->spare_buf, ftl->ndm);
201 if (status < 0)
202 return FtlnFatErr(ftl);
203
204 //---------------------------------------------------------
205 // If page is erased or invalid, return its status.
206 //---------------------------------------------------------
207 if (status != NDM_PAGE_VALID)
208 return status;
209
210 //---------------------------------------------------------
211 // Verify the metadata version is correct.
212 //---------------------------------------------------------
213 if (RD32_LE(&ppns[0]) != FTLN_META_VER1)
214 return NDM_PAGE_INVALID;
215
216 //---------------------------------------------------------
217 // Verify the metadata type is correct.
218 //---------------------------------------------------------
219 if (RD32_LE(&ppns[1]) != ERASED_LIST)
220 return NDM_PAGE_INVALID;
221 }
222 }
223 }
224 #endif
225
226 // Else meta page type is invalid.
227 else
228 return NDM_PAGE_INVALID;
229 }
230
231 // Else meta page version is invalid.
232 else
233 return NDM_PAGE_INVALID;
234 }
235
236 // Else regular map page.
237 else {
238 ui32 pn;
239 ui8* maddr = ftl->main_buf;
240
241 // Check every entry for validity.
242 for (n = 0; n < ftl->mappings_per_mpg; ++n) {
243 // Read entry's mapping from map page and update entry address.
244 pn = GET_MAP_PPN(maddr);
245 maddr += FTLN_PN_SZ;
246
247 // Invalid page if entry is neither valid nor the unmapped value.
248 if (pn >= ftl->num_pages && pn != UNMAPPED_PN)
249 return NDM_PAGE_INVALID;
250 }
251 }
252
253 // All checks passed! Page is valid.
254 return NDM_PAGE_VALID;
255 }
256
257 // build_map: Scan volume blocks and for map ones, read all valid
258 // map pages to build the MPNs array
259 //
260 // Input: ftl = pointer to FTL control block
261 //
262 // Returns: 0 on success, -1 on error
263 //
build_map(FTLN ftl)264 static int build_map(FTLN ftl) {
265 int status;
266 ui32 b, bc, *bcs, mpn, n, pn, po, *b_ptr;
267
268 // Allocate space to hold block count for each map page array entry.
269 bcs = FsCalloc(ftl->num_map_pgs, sizeof(ui32));
270 if (bcs == NULL)
271 return -1;
272
273 // Loop over every block looking for map blocks. This list was made
274 // by format_status() and only has one with the highest BC, but may
275 // include old map blocks that didn't get erased after their recycle.
276 for (b = 0; b < ftl->num_blks; ++b) {
277 // Skip blocks that don't hold any map pages.
278 if (!IS_MAP_BLK(ftl->bdata[b]))
279 continue;
280
281 // Compute first page on block.
282 pn = ftl->start_pn + b * ftl->pgs_per_blk;
283
284 // For each page in map block, check if MPN array needs updating.
285 for (po = 0, bc = (ui32)-1; po < ftl->pgs_per_blk; ++po, ++pn) {
286 #if INC_FTL_NDM_MLC
287 // For MLC devices, skip pages not written by the FTL, those
288 // whose pair offset is lower than their offset.
289 if (ftl->type == NDM_MLC && ftl->pair_offset(po, ftl->ndm) < po)
290 continue;
291 #endif
292
293 // Check if page is on newest map block and not its first page.
294 // The newest map block is only one that potentially has (as its
295 // partially written last page) an invalid page. Look for that.
296 if (po && bc == ftl->high_bc) {
297 // Check if page contents are valid. Return -1 if fatal error.
298 status = map_page_check(ftl, pn, FALSE);
299 if (status < 0) {
300 FsFree(bcs);
301 return -1;
302 }
303
304 // If invalid last page, break to advance to next map block.
305 if (status == NDM_PAGE_INVALID)
306 break;
307
308 // Else erased last page, break to advance to next map block.
309 else if (status == NDM_PAGE_ERASED)
310 break;
311
312 // Remember highest valid map page on most recent map block.
313 ftl->high_bc_mblk_po = po;
314 }
315
316 // Else page on older map block or first on newest map block.
317 else {
318 // Read page's spare area.
319 ++ftl->stats.read_spare;
320 status = ftl->read_spare(pn, ftl->spare_buf, ftl->ndm);
321
322 // Return if fatal error.
323 if (status == -2) {
324 FsFree(bcs);
325 return FtlnFatErr(ftl);
326 }
327
328 // Break to skip block if uncorrectable ECC error occurred.
329 if (status < 0)
330 break;
331 }
332
333 // If first page, retrieve block count. Otherwise compare with
334 // block count of block's already-checked-valid first page.
335 if (po == 0)
336 bc = GET_SA_BC(ftl->spare_buf);
337 else if (bc != GET_SA_BC(ftl->spare_buf)) {
338 #if FTLN_DEBUG > 1
339 printf("build_ma: b = %u, po = %u, i_bc = %u vs 0_bc = %u\n", b, po,
340 GET_SA_BC(ftl->spare_buf), bc);
341 #endif
342
343 // Should not be, but page is invalid. Break to skip block.
344 break;
345 }
346
347 // Block count is retrieved by now.
348 PfAssert(bc != (ui32)-1);
349
350 // Adjust map block read count.
351 b_ptr = &ftl->bdata[b];
352 INC_RC(ftl, b_ptr, 1);
353
354 // Retrieve MPN and check that it is valid.
355 mpn = GET_SA_VPN(ftl->spare_buf);
356 if (mpn > ftl->num_map_pgs) {
357 #if FTLN_DEBUG > 1
358 printf("build_ma: b = %u, po = %u, mpn = %u, max = %u\n", b, po, mpn,
359 ftl->num_map_pgs);
360 #endif
361
362 // Should not be, but page is invalid. Break to skip block.
363 break;
364 }
365
366 // If no entry for this MPN in array OR entry in same block as
367 // current block OR entry in a block with a lower block count,
368 // update array entry with current page.
369 if (ftl->mpns[mpn] == (ui32)-1 || ftl->mpns[mpn] / ftl->pgs_per_blk == b ||
370 bcs[mpn] < bc) {
371 // If not metapage, adjust used counts of referenced blks.
372 if (mpn < ftl->num_map_pgs - 1) {
373 // If old MPN array entry already set, decrement old block's
374 // used pages count.
375 if (ftl->mpns[mpn] != (ui32)-1) {
376 uint ob = ftl->mpns[mpn] / ftl->pgs_per_blk;
377
378 PfAssert(IS_MAP_BLK(ftl->bdata[ob]));
379 DEC_USED(ftl->bdata[ob]);
380 }
381
382 // Increment used count for new block.
383 PfAssert(IS_MAP_BLK(ftl->bdata[b]));
384 INC_USED(ftl->bdata[b]);
385 }
386 #if FTLN_DEBUG > 1
387 printf("build_ma: mpn = %u, old_pn = %d, new_pn = %u\n", mpn, ftl->mpns[mpn],
388 b * ftl->pgs_per_blk + po);
389 #endif
390
391 // Save the map page number and (temporarily) the block count.
392 ftl->mpns[mpn] = b * ftl->pgs_per_blk + po;
393 bcs[mpn] = bc;
394 }
395 }
396 }
397
398 // Free temporary block counts space.
399 FsFree(bcs);
400
401 #if INC_ELIST
402 // If present, change state of elist block from map block to free.
403 if (ftl->elist_blk != (ui32)-1) {
404 ftl->bdata[ftl->elist_blk] = FREE_BLK_FLAG;
405 ++ftl->num_free_blks;
406 }
407 #endif
408
409 // Loop over map blocks to build volume block's used page counts.
410 for (mpn = 0; mpn < ftl->num_map_pgs - 1; ++mpn) {
411 ui8* maddr;
412
413 // Skip unused map pages.
414 pn = ftl->mpns[mpn];
415 if (pn == (ui32)-1)
416 continue;
417
418 #if FTLN_DEBUG > 1
419 printf(" -> MPN[%2u] = %u\n", mpn, pn);
420 #endif
421
422 // Read map page. Return -1 if error.
423 if (FtlnRdPage(ftl, pn, ftl->main_buf))
424 return -1;
425
426 // Loop over every physical page number entry on map page.
427 maddr = ftl->main_buf;
428 for (n = 0; n < ftl->mappings_per_mpg; ++n) {
429 // Read entry's mapping from map page and update entry address.
430 pn = GET_MAP_PPN(maddr);
431 maddr += FTLN_PN_SZ;
432
433 // Continue if no mapping at this entry.
434 if (pn >= ftl->num_pages)
435 continue;
436
437 // Get page's block number and verify its status.
438 b = pn / ftl->pgs_per_blk;
439 PfAssert(!IS_FREE(ftl->bdata[b]) && !IS_MAP_BLK(ftl->bdata[b]));
440 if (IS_FREE(ftl->bdata[b]) || IS_MAP_BLK(ftl->bdata[b]))
441 return -1;
442
443 // Increment the used page count for this volume block.
444 INC_USED(ftl->bdata[b]);
445
446 // Record the highest used page offset in block's read count.
447 po = pn % ftl->pgs_per_blk;
448 if (po > GET_RC(ftl->bdata[b]))
449 SET_RC(ftl->bdata[b], po);
450 }
451 }
452
453 // If not recovered from the copy-end page (after interrupted vblk
454 // resume), find the volume block with the lowest used page offset.
455 if (ftl->copy_end_found == FALSE) {
456 ftl->resume_po = ftl->pgs_per_blk;
457 for (b = 0; b < ftl->num_blks; ++b) {
458 if (NUM_USED(ftl->bdata[b]) && !IS_MAP_BLK(ftl->bdata[b])) {
459 po = GET_RC(ftl->bdata[b]);
460 if (po < ftl->resume_po) {
461 ftl->resume_vblk = b;
462 ftl->resume_po = po;
463 if (po == 0)
464 break;
465 }
466 }
467 }
468 }
469 #if FTLN_DEBUG > 1
470 printf("vol block %d has lowest used page offset (%d)\n", ftl->resume_vblk, ftl->resume_po);
471 #endif
472
473 // Clean temporary use of vol block read-wear field for page offset.
474 for (b = 0; b < ftl->num_blks; ++b)
475 if (NUM_USED(ftl->bdata[b]) && !IS_MAP_BLK(ftl->bdata[b]))
476 ftl->bdata[b] &= ~RC_MASK;
477
478 // Return success.
479 return 0;
480 }
481
482 // set_wc_lag: Set block's wear count lag and possibly adjust the
483 // highest/lowest overall wear counts
484 //
485 // Inputs: ftl = pointer to FTL control block
486 // b = block number
487 // wc = wear count for block
488 // I/O: *low_wc = lowest wear count encountered so far
489 //
set_wc_lag(FTLN ftl,ui32 b,ui32 wc,ui32 * low_wc)490 static void set_wc_lag(FTLN ftl, ui32 b, ui32 wc, ui32* low_wc) {
491 // If this block has lowest wear count, update lowest.
492 if (*low_wc > wc)
493 *low_wc = wc;
494
495 // If it has highest wear count, update highest and also update wear
496 // count offsets of all used (not free) blocks below it.
497 if (wc > ftl->high_wc) {
498 ui32 lb, increase = wc - ftl->high_wc;
499
500 // Loop over all lower numbered blocks.
501 for (lb = 0; lb < b; ++lb) {
502 // Skip blocks that don't have a valid wear count value.
503 if (GET_RC(ftl->bdata[lb]) == 100)
504 continue;
505
506 // Update previously set wear count lags, avoiding ui8 overflow.
507 if (ftl->blk_wc_lag[lb] + increase > 0xFF) {
508 ftl->blk_wc_lag[lb] = 0xFF;
509 #if FTLN_DEBUG
510 ++ftl->max_wc_over;
511 #endif
512 } else
513 ftl->blk_wc_lag[lb] += increase;
514
515 #if FTLN_DEBUG
516 // If new value, record maximum encountered wear lag.
517 if (ftl->max_wc_lag < ftl->blk_wc_lag[lb])
518 ftl->max_wc_lag = ftl->blk_wc_lag[lb];
519 #endif
520 }
521
522 // Remember new high wear count.
523 ftl->high_wc = wc;
524 }
525
526 // Set block wear count lag, avoiding ui8 overflow.
527 if (ftl->high_wc - wc > 0xFF) {
528 ftl->blk_wc_lag[b] = 0xFF;
529 #if FTLN_DEBUG
530 ++ftl->max_wc_over;
531 #endif
532 } else
533 ftl->blk_wc_lag[b] = ftl->high_wc - wc;
534
535 #if FTLN_DEBUG
536 // If new value, record maximum encountered wear lag.
537 if (ftl->max_wc_lag < ftl->blk_wc_lag[b])
538 ftl->max_wc_lag = ftl->blk_wc_lag[b];
539 #endif
540 }
541
542 // format_status: Check if FTL volume is formatted
543 //
544 // Input: ftl = pointer to FTL control block
545 //
546 // Returns: TRUE if formatted, FALSE if unformatted, -1 if error
547 //
format_status(FTLN ftl)548 static int format_status(FTLN ftl) {
549 ui32 b, n, avg_lag, pn, bc, wc, low_wc = (ui32)-1;
550 int rc, formatted = FALSE;
551
552 // Scan first page on all blocks to determine block status.
553 for (ftl->num_free_blks = b = 0; b < ftl->num_blks; ++b) {
554 // Compute page number of block's first page.
555 pn = ftl->start_pn + b * ftl->pgs_per_blk;
556
557 // Read spare area for first page. Return -1 if fatal error.
558 ++ftl->stats.read_spare;
559 rc = ftl->read_spare(pn, ftl->spare_buf, ftl->ndm);
560 if (rc == -2)
561 return FtlnFatErr(ftl);
562
563 // Read metadata from spare area.
564 bc = GET_SA_BC(ftl->spare_buf);
565 wc = GET_SA_WC(ftl->spare_buf);
566
567 // Check if the block count is 0xFFFFFFFF.
568 if (bc == 0xFFFFFFFF) {
569 // If spare data looks erased, mark block as free.
570 if (wc == 0x0FFFFFFF) {
571 ftl->bdata[b] = FREE_BLK_FLAG;
572 ++ftl->num_free_blks;
573 PfAssert(GET_RC(ftl->bdata[b]) != 100);
574 SET_RC(ftl->bdata[b], 100); // flag to use average wear count
575 }
576
577 // Else classify as volume block.
578 else {
579 // If its wear count is in expected range, record it.
580 if ((wc <= ftl->high_wc + 32) && ((wc + 32 >= low_wc) || (low_wc == (ui32)-1)))
581 set_wc_lag(ftl, b, wc, &low_wc);
582
583 // Else only use wear count if block has other non-empty pages
584 // with same BC/wear, to discard partially written counts.
585 else
586 for (n = 1;;) {
587 ui32 bc2, wc2;
588
589 // Read spare area for higher page. Return -1 if fatal error.
590 ++ftl->stats.read_spare;
591 rc = ftl->read_spare(pn + n, ftl->spare_buf, ftl->ndm);
592 if (rc == -2)
593 return FtlnFatErr(ftl);
594
595 // If read good and counts match, set block wear count lag.
596 bc2 = GET_SA_BC(ftl->spare_buf);
597 wc2 = GET_SA_WC(ftl->spare_buf);
598 if ((rc == 0) && (bc == bc2) && (wc == wc2)) {
599 set_wc_lag(ftl, b, wc, &low_wc);
600 break;
601 }
602
603 #if INC_FTL_NDM_MLC
604 // If MLC, try first next page that has no earlier pair, in
605 // case FTL skipped volume pages for sync operation.
606 if ((ftl->type == NDM_MLC) && (n == 1)) {
607 n = ndmPastPrevPair(ftl->ndm, pn + 1) - pn;
608 if (n != 1)
609 continue;
610 }
611 #endif
612
613 // Done. Mark block as needing average wear count and break.
614 PfAssert(GET_RC(ftl->bdata[b]) != 100);
615 SET_RC(ftl->bdata[b], 100);
616 break;
617 }
618 }
619 }
620
621 // Else check if this is an interrupted volume block transfer.
622 else if (bc == COPY_BLK_MARK) {
623 #if DEBUG_RESUME
624 puts("encountered copy-blk mark");
625 #endif
626 // Call driver validity check. Return -1 if error.
627 ++ftl->stats.page_check;
628 rc = ftl->page_check(pn, ftl->main_buf, ftl->spare_buf, ftl->ndm);
629 if (rc < 0)
630 return FtlnFatErr(ftl);
631
632 // If page is invalid, mark block free and continue.
633 if (rc != NDM_PAGE_VALID) {
634 ftl->bdata[b] = FREE_BLK_FLAG;
635 ++ftl->num_free_blks;
636 PfAssert(GET_RC(ftl->bdata[b]) != 100);
637 SET_RC(ftl->bdata[b], 100); // flag to use average wear count
638 continue;
639 }
640
641 // Set block wear count lag.
642 set_wc_lag(ftl, b, wc, &low_wc);
643
644 // Search for copy-end page, indicating the 'copy to' finished.
645 for (n = 1; n < ftl->pgs_per_blk; ++n) {
646 ui32 vpn;
647
648 // Read spare data. Return if fatal error. Skip if ECC error.
649 ++ftl->stats.read_spare;
650 rc = ftl->read_spare(pn + n, ftl->spare_buf, ftl->ndm);
651 if (rc == -2)
652 return FtlnFatErr(ftl);
653 if (rc)
654 continue;
655
656 // Read metadata from spare area.
657 vpn = GET_SA_VPN(ftl->spare_buf);
658 bc = GET_SA_BC(ftl->spare_buf);
659 wc = GET_SA_WC(ftl->spare_buf);
660
661 // Check if this is the copy-end page.
662 if ((vpn == COPY_BLK_END) && (bc == vpn) && (wc == 0)) {
663 #if DEBUG_RESUME
664 puts("encountered copy-blk end");
665 #endif
666 // Read and check the copy-end page. Return -1 if error.
667 ++ftl->stats.page_check;
668 rc = ftl->page_check(pn + n, ftl->main_buf, ftl->spare_buf, ftl->ndm);
669 if (rc < 0)
670 return FtlnFatErr(ftl);
671
672 // Break if page is invalid.
673 if (rc != NDM_PAGE_VALID)
674 break;
675
676 // Flag that the copy-end page has been found.
677 ftl->copy_end_found = TRUE;
678
679 // Save parameters of the interrupted vblk resume transfer.
680 ftl->resume_vblk = RD32_LE(&ftl->main_buf[0]);
681 PfAssert(ftl->resume_vblk < ftl->num_blks);
682 ftl->resume_tblk = b;
683 ftl->resume_po = n - 1;
684 #if DEBUG_RESUME
685 {
686 ui32 vb = ftl->resume_vblk;
687
688 printf("resume_vblk=%d bdata=0x%X", vb, ftl->bdata[vb]);
689 if (IS_FREE(ftl->bdata[vb]))
690 puts(" free blk");
691 else if (IS_MAP_BLK(ftl->bdata[vb]))
692 puts(" map blk");
693 else
694 putchar('\n');
695 }
696 #endif
697
698 // Mark the resume temporary block free and break.
699 ftl->bdata[b] = FREE_BLK_FLAG;
700 ++ftl->num_free_blks;
701 break;
702 }
703 }
704
705 // If copy-end not found, erase block. Return -1 if I/O error.
706 if (!ftl->copy_end_found)
707 if (FtlnEraseBlk(ftl, b))
708 return -1;
709 }
710
711 // Else this looks like a map block.
712 else {
713 // Check block's first map page for validity. Return -1 if error.
714 rc = map_page_check(ftl, pn, FALSE);
715 if (rc < 0)
716 return -1;
717
718 // If first page is invalid, whole block is invalid. Free it.
719 if (rc != NDM_PAGE_VALID) {
720 ftl->bdata[b] = FREE_BLK_FLAG;
721 ++ftl->num_free_blks;
722 PfAssert(GET_RC(ftl->bdata[b]) != 100);
723 SET_RC(ftl->bdata[b], 100); // flag to use average wear count
724 }
725
726 // Else this is a valid map page and block.
727 else {
728 // Remember that volume is formatted. Mark block as map block.
729 formatted = TRUE;
730 SET_MAP_BLK(ftl->bdata[b]); // clear used/read pages cnt
731
732 // Set block wear count lag.
733 set_wc_lag(ftl, b, wc, &low_wc);
734
735 // If this is the highest block count so far, remember it.
736 if (ftl->high_bc < bc) {
737 ftl->high_bc = bc;
738 ftl->high_bc_mblk = b;
739 }
740
741 // Else if this is the second block with highest block count,
742 // it's an interrupted map block transfer.
743 else if (ftl->high_bc == bc && ftl->high_bc_mblk != (ui32)-1) {
744 // Erase block that was destination of interrupted transfer.
745 if (ftl->blk_wc_lag[b] > ftl->blk_wc_lag[ftl->high_bc_mblk]) {
746 rc = FtlnEraseBlk(ftl, ftl->high_bc_mblk);
747 ftl->high_bc_mblk = b;
748 } else
749 rc = FtlnEraseBlk(ftl, b);
750 if (rc)
751 return -1;
752 }
753 }
754 }
755 }
756
757 // If volume is unformatted, return FALSE.
758 if (formatted == FALSE)
759 return FALSE;
760
761 // Compute the average 'high_wc' lag.
762 for (avg_lag = n = b = 0; b < ftl->num_blks; ++b)
763 if (GET_RC(ftl->bdata[b]) != 100) {
764 avg_lag += ftl->blk_wc_lag[b];
765 ++n;
766 }
767 if (n)
768 avg_lag = (avg_lag + n / 2) / n;
769
770 // Apply average wear offset to every block marked as needing it.
771 for (b = 0; b < ftl->num_blks; ++b)
772 if ((ftl->bdata[b] & RC_MASK) == 100) {
773 ftl->bdata[b] &= ~RC_MASK;
774 ftl->blk_wc_lag[b] = avg_lag;
775 }
776
777 // Depending when powerfail recovery was interrupted, at this point
778 // the volume block being resumed might look like a free block or a
779 // volume block. Need it to be a volume block.
780 if (ftl->copy_end_found) {
781 PfAssert(!IS_MAP_BLK(ftl->bdata[ftl->resume_vblk]));
782 if (IS_FREE(ftl->bdata[ftl->resume_vblk])) {
783 ftl->bdata[ftl->resume_vblk] = 0;
784 --ftl->num_free_blks;
785 }
786 }
787
788 // Volume is formatted, return TRUE.
789 PfAssert(ftl->num_free_blks < ftl->num_blks);
790 return TRUE;
791 }
792
793 #if INC_FAT_MBR
794 // read_bpb: Read the FAT boot sector to set frst_data_sect
795 //
796 // Input: ftl = pointer to FTL control block
797 //
798 // Returns: 0 for success or no boot sector, -1 on error
799 //
read_bpb(FTLN ftl)800 static int read_bpb(FTLN ftl) {
801 ui32 pn;
802 FATPartition part;
803
804 // Prepare to (potentially) write one map page.
805 if (FtlnRecCheck(ftl, -1))
806 return -1;
807
808 // Retrieve physical page number for sector 0. Return -1 if error.
809 if (FtlnMapGetPpn(ftl, 0, &pn) < 0)
810 return -1;
811
812 // Return 0 if boot sector is unmapped.
813 if (pn == (ui32)-1)
814 return 0;
815
816 // Read sector 0. Return -1 if error.
817 if (FtlnRdPage(ftl, pn, ftl->main_buf))
818 return -1;
819
820 // If one valid partition, use it to read location of boot sector.
821 if (FatGetPartitions(ftl->main_buf, &part, 1) == 1) {
822 ftl->vol_frst_sect = part.first_sect;
823 ftl->num_vsects -= ftl->vol_frst_sect;
824 }
825
826 // Read boot sector into temporary buffer. Return -1 if error.
827 if (FtlnRdSects(ftl->main_buf, ftl->vol_frst_sect, 1, ftl))
828 return -1;
829
830 // Extract frst_clust_sect from the boot information. Return status.
831 return FtlnSetClustSect1(ftl, ftl->main_buf, TRUE);
832 }
833 #endif // INC_FAT_MBR
834
835 // meta_read: Read FTL meta information page
836 //
837 // Input: ftl = pointer to FTL control block
838 //
839 // Returns: 0 if successful, else -1 for I/O error
840 //
meta_read(FTLN ftl)841 static int meta_read(FTLN ftl) {
842 ui32 pn = ftl->mpns[ftl->num_map_pgs - 1];
843
844 // If no meta page, return 0.
845 if (pn >= ftl->num_pages)
846 return 0;
847
848 // Read meta page. check/process its contents. Return -1 if error.
849 if (map_page_check(ftl, ftl->start_pn + pn, TRUE) < 0)
850 return -1;
851
852 // Mark meta page invalid since no longer needed. Return success.
853 ftl->mpns[ftl->num_map_pgs - 1] = (ui32)-1;
854 return 0;
855 }
856
857 // copy_end_mark: Write the copy-end page, marking completion of the
858 // copy from the volume block to the temporary block
859 //
860 // Inputs: ftl = pointer to FTL control block
861 // b = block number of the vblk resume temporary block
862 //
copy_end_mark(CFTLN ftl,ui32 b)863 static int copy_end_mark(CFTLN ftl, ui32 b) {
864 ui32 pn = ftl->start_pn + b * ftl->pgs_per_blk + ftl->resume_po + 1;
865
866 // Page data is number of volume block with lowest used page offset.
867 memset(ftl->main_buf, 0xFF, ftl->page_size);
868 WR32_LE(ftl->resume_vblk, &ftl->main_buf[0]);
869
870 // Initialize spare area, including VPN and block/wear counts.
871 memset(ftl->spare_buf, 0xFF, ftl->eb_size);
872 SET_SA_VPN(COPY_BLK_END, ftl->spare_buf);
873 SET_SA_BC(COPY_BLK_END, ftl->spare_buf);
874 SET_SA_WC(0, ftl->spare_buf);
875
876 // Write page that marks the end of a volume resume copy block.
877 return ftl->write_page(pn, ftl->main_buf, ftl->spare_buf, ftl->ndm);
878 }
879
880 // resume_copy: Copy one volume block
881 //
882 // Inputs: ftl = pointer to FTL control block
883 // src_b = number of block to copy from
884 // dst_b = number of block to copy to
885 // bc = block count value: 0xFFFFFFFF or COPY_BLK_MARK
886 //
887 // Returns: 0 on success, -1 on error
888 //
resume_copy(FTLN ftl,ui32 src_b,ui32 dst_b,ui32 bc)889 static int resume_copy(FTLN ftl, ui32 src_b, ui32 dst_b, ui32 bc) {
890 int rc;
891 ui32 po, vpn;
892 ui32 src_pg0 = ftl->start_pn + src_b * ftl->pgs_per_blk;
893 ui32 dst_pg0 = ftl->start_pn + dst_b * ftl->pgs_per_blk;
894 ui32 wc = ftl->high_wc - ftl->blk_wc_lag[src_b];
895
896 // Copy all used pages from selected volume block to free block.
897 for (po = 0; po <= ftl->resume_po; ++po) {
898 // Read source page's spare area.
899 ++ftl->stats.read_spare;
900 rc = ftl->read_spare(src_pg0 + po, ftl->spare_buf, ftl->ndm);
901
902 // Return -1 if fatal error, skip page if ECC error on spare read.
903 if (rc) {
904 if (rc == -2)
905 return FtlnFatErr(ftl);
906 else
907 continue;
908 }
909
910 // Get virtual page number from spare. Skip page if out of range.
911 vpn = GET_SA_VPN(ftl->spare_buf);
912 if (vpn > ftl->num_vpages)
913 continue;
914
915 // Initialize spare area, including VPN and block/wear counts.
916 memset(ftl->spare_buf, 0xFF, ftl->eb_size);
917 SET_SA_VPN(vpn, ftl->spare_buf);
918 SET_SA_BC(bc, ftl->spare_buf);
919 SET_SA_WC(wc, ftl->spare_buf);
920
921 // Invoke page transfer routine. If error, return -1.
922 ++ftl->stats.transfer_page;
923 if (ftl->xfer_page(src_pg0 + po, dst_pg0 + po, ftl->main_buf, ftl->spare_buf, ftl->ndm))
924 return FtlnFatErr(ftl);
925 }
926
927 // Return success.
928 return 0;
929 }
930
931 // init_ftln: Prepare a TargetFTL-NDM volume for use
932 //
933 // Input: ftl = pointer to FTL control block
934 //
935 // Returns: 0 on success, -1 on failure
936 //
init_ftln(FTLN ftl)937 static int init_ftln(FTLN ftl) {
938 int formatted;
939 ui32 b, n;
940
941 // Analyze volume to see if it is formatted. Return -1 if error.
942 formatted = format_status(ftl);
943 if (formatted < 0)
944 return -1;
945
946 // If unformatted, blocks are free w/zero 'high_wc' lag.
947 if (formatted == FALSE) {
948 for (b = 0; b < ftl->num_blks; ++b) {
949 ftl->blk_wc_lag[b] = 0;
950 ftl->bdata[b] = FREE_BLK_FLAG;
951 }
952 ftl->num_free_blks = ftl->num_blks;
953 ftl->high_bc = 1; // initial block count of unformatted volumes
954 return 0;
955 }
956
957 // Look for all the valid map pages on all the map blocks.
958 if (build_map(ftl))
959 return -1;
960
961 // If below limit, convert unused volume blocks to free blocks.
962 if (ftl->num_free_blks < FTLN_MIN_FREE_BLKS)
963 for (b = 0; b < ftl->num_blks; ++b) {
964 if (ftl->bdata[b] == 0) // map/free flags clear and no use counts
965 {
966 ftl->bdata[b] = FREE_BLK_FLAG;
967 ++ftl->num_free_blks;
968 }
969 }
970
971 // Read and process meta page, if any. Return -1 if error.
972 if (meta_read(ftl) < 0)
973 return -1;
974
975 // Erase unused map blocks. Return -1 if error
976 for (b = 0; b < ftl->num_blks; ++b)
977 if (IS_MAP_BLK(ftl->bdata[b]) && (NUM_USED(ftl->bdata[b]) == 0))
978 if (FtlnEraseBlk(ftl, b))
979 return -1;
980
981 // If free block count is below reserved number, a recycle has been
982 // interrupted by a power failure. Must avoid losing additional free
983 // blocks from additional power failures. Resume restores the free
984 // map and volume page lists by copying valid entries to an erased
985 // block, ensuring they don't have undetectable corruption from an
986 // interrupted page write or block erase command. If resume is
987 // interrupted by a power failure, no free blocks are lost.
988 if (ftl->num_free_blks < FTLN_MIN_FREE_BLKS) {
989 #if DEBUG_RESUME
990 printf("Resuming: %u free blocks\n", ftl->num_free_blks);
991 printf("map block %u has used page offset of %u/%u\n", ftl->high_bc_mblk,
992 ftl->high_bc_mblk_po, ftl->pgs_per_blk);
993 printf("vol block %u has used page offset of %u/%u\n", ftl->resume_vblk, ftl->resume_po,
994 ftl->pgs_per_blk);
995 #endif
996
997 // Resume needs one free block and should have it.
998 PfAssert(ftl->num_free_blks >= 1);
999 if (ftl->num_free_blks < 1)
1000 return -1;
1001
1002 // Check if low page-offset volume block has unused pages.
1003 if (ftl->resume_po < ftl->pgs_per_blk - 1) {
1004 #ifdef FTL_RESUME_STRESS
1005 ++FtlVblkResumeCnt;
1006 #endif
1007
1008 // Get the number of used pages on the volume block.
1009 n = NUM_USED(ftl->bdata[ftl->resume_vblk]);
1010
1011 // If volume block transfer was interrupted, but the 'copy to'
1012 // finished, use the discovered 'copy to' block.
1013 if (ftl->copy_end_found) {
1014 b = ftl->resume_tblk;
1015 --ftl->num_free_blks;
1016 }
1017
1018 // Else get a free block and copy the volume block to it.
1019 else {
1020 // Find free block w/highest wear count. Error if none free.
1021 b = FtlnHiWcFreeBlk(ftl);
1022 if (b == (ui32)-1)
1023 return b;
1024
1025 // If the block is unerased, erase it now. Return -1 if error.
1026 if ((ftl->bdata[b] & ERASED_BLK_FLAG) == 0)
1027 if (FtlnEraseBlk(ftl, b))
1028 return (ui32)-1;
1029
1030 // Decrement free block count.
1031 --ftl->num_free_blks;
1032
1033 // Copy used pages to temp block.
1034 if (resume_copy(ftl, ftl->resume_vblk, b, COPY_BLK_MARK))
1035 return -1;
1036
1037 // Write "end of copy" mark on next temp block page.
1038 if (copy_end_mark(ftl, b))
1039 return -1;
1040 }
1041
1042 // Erase the volume block with the lowest used page-offset.
1043 if (FtlnEraseBlk(ftl, ftl->resume_vblk))
1044 return -1;
1045
1046 // Copy the temp block's contents back to the volume block.
1047 if (resume_copy(ftl, b, ftl->resume_vblk, 0xFFFFFFFF))
1048 return -1;
1049
1050 // Mark resumed block as a volume block with 'n' used pages.
1051 ftl->bdata[ftl->resume_vblk] = n << 20; // clr free & erased flags
1052
1053 // Erase the temp copy block.
1054 if (FtlnEraseBlk(ftl, b))
1055 return -1;
1056
1057 // Assign the resumed ftl->free_vpn value.
1058 ftl->free_vpn = ftl->resume_vblk * ftl->pgs_per_blk + ftl->resume_po + 1;
1059 }
1060
1061 // Check if high-block-count map block has unused pages.
1062 if (ftl->high_bc_mblk_po < ftl->pgs_per_blk - 1) {
1063 #ifdef FTL_RESUME_STRESS
1064 ++FtlMblkResumeCnt;
1065 #endif
1066
1067 // Find free block with lowest wear count. Error if none free.
1068 b = FtlnLoWcFreeBlk(ftl);
1069 if (b == (ui32)-1)
1070 return b;
1071
1072 // If the block is unerased, erase it now. Return -1 if error.
1073 if ((ftl->bdata[b] & ERASED_BLK_FLAG) == 0)
1074 if (FtlnEraseBlk(ftl, b))
1075 return (ui32)-1;
1076
1077 // Decrement free block count.
1078 --ftl->num_free_blks;
1079
1080 // Set free MPN pointer to first page in block (wo BC increment).
1081 ftl->free_mpn = b * ftl->pgs_per_blk;
1082
1083 // Clear free block flag and read count, set map block flag.
1084 SET_MAP_BLK(ftl->bdata[b]); // clr free flag & read wear count
1085
1086 // Set wear count of copy to be one higher than source block.
1087 if (ftl->blk_wc_lag[ftl->high_bc_mblk])
1088 ftl->blk_wc_lag[b] = ftl->blk_wc_lag[ftl->high_bc_mblk] - 1;
1089 else {
1090 ftl->blk_wc_lag[ftl->high_bc_mblk] = 1;
1091 ftl->blk_wc_lag[b] = 0;
1092 }
1093
1094 // Copy the used pages to a free block, then erase the original.
1095 if (FtlnRecycleMapBlk(ftl, ftl->high_bc_mblk))
1096 return -1;
1097 }
1098 }
1099
1100 #if INC_FAT_MBR
1101 // For FAT volumes, read in boot sector, if it exists, to set
1102 // frst_clust_sect. Return -1 if error.
1103 if (FLAG_IS_SET(ftl->flags, FTLN_FAT_VOL))
1104 if (read_bpb(ftl))
1105 return -1;
1106 #endif
1107
1108 #if FTLN_DEBUG > 1
1109 printf("init_ftln: FTL formatted - hi_bc = %u, hi_wc = %u\n", ftl->high_bc, ftl->high_wc);
1110 #endif
1111
1112 // Do recycles if needed and return status.
1113 return FtlnRecCheck(ftl, 0);
1114 }
1115
1116 // free_ftl: Callback used inside FtlnFreeFTL()
1117 //
1118 // Input: vol = FTL handle
1119 //
free_ftl(void * vol)1120 static void free_ftl(void* vol) {
1121 FTLN ftl = vol;
1122
1123 #if FTLN_DEBUG > 1
1124 // Display FTL statistics.
1125 FtlnStats(ftl);
1126 #endif
1127
1128 // Free FTL memory allocations.
1129 if (ftl->bdata)
1130 FsFree(ftl->bdata);
1131 if (ftl->blk_wc_lag)
1132 FsFree(ftl->blk_wc_lag);
1133 if (ftl->mpns)
1134 FsFree(ftl->mpns);
1135 if (ftl->main_buf)
1136 FsAfreeClear(&ftl->main_buf);
1137 if (ftl->map_cache)
1138 ftlmcDelete(&ftl->map_cache);
1139 #if INC_FTL_PAGE_CACHE
1140 if (ftl->vol_cache)
1141 ftlvcDelete(ftl->vol_cache);
1142 #endif
1143 FsFree(ftl);
1144 }
1145
1146 // Global Function Definitions
1147
1148 // FtlnAddVol: Add a new TargetFTL-NDM volume
1149 //
1150 // Inputs: ftl_dvr = pointer to FTL NDM driver control block
1151 // ftl_type = FTL type (FTLN_XFS_VOL or FTLN_FAT_VOL)
1152 // sect_size = FAT or XFS sector size
1153 // fs_vol = pointer to FS driver's volume control block
1154 //
1155 // Returns: Newly created FTL handle on success, NULL on error
1156 //
FtlnAddVol(FtlNdmVol * ftl_dvr,int ftl_type,int sect_size,void * fs_vol)1157 void* FtlnAddVol(FtlNdmVol* ftl_dvr, int ftl_type, int sect_size, void* fs_vol) {
1158 ui32 n, vol_blks;
1159 ui8* buf;
1160 FTLN ftl;
1161
1162 // Ensure shared FTL vstat fields remain at same offset.
1163 PfAssert(offsetof(vstat_fat, garbage_level) == offsetof(vstat_xfs, garbage_level));
1164 PfAssert(offsetof(vstat_fat, ftl_type) == offsetof(vstat_xfs, ftl_type));
1165
1166 // If number of blocks less than 7, FTL-NDM cannot work.
1167 if (ftl_dvr->num_blocks < 7) {
1168 FsError(EINVAL);
1169 return NULL;
1170 }
1171
1172 #if CACHE_LINE_SIZE
1173 // Ensure driver page size is a multiple of the CPU cache line size.
1174 if (ftl_dvr->page_size % CACHE_LINE_SIZE) {
1175 FsError(EINVAL);
1176 return NULL;
1177 }
1178 #endif
1179
1180 // Ensure physical page size is a multiple of FAT sector size and
1181 // not bigger than the device block size.
1182 if (ftl_dvr->page_size % FAT_SECT_SZ || ftl_dvr->page_size == 0 ||
1183 ftl_dvr->page_size > ftl_dvr->block_size) {
1184 FsError(EINVAL);
1185 return NULL;
1186 }
1187
1188 #if OS_PARM_CHECK
1189 // Ensure FTL flags are valid.
1190 if (ftl_dvr->flags &
1191 ~(FSF_EXTRA_FREE
1192 #if INC_FTL_PAGE_CACHE
1193 | FSF_FTL_PAGE_CACHE
1194 #endif
1195 | FSF_READ_WEAR_LIMIT)) {
1196 FsError(EINVAL);
1197 return NULL;
1198 }
1199 #endif
1200
1201 // Ensure driver has an NDM pointer.
1202 PfAssert(ftl_dvr->ndm);
1203
1204 // Allocate memory for FTL control block. Return NULL if unable.
1205 ftl = FsCalloc(1, sizeof(struct ftln));
1206 if (ftl == NULL)
1207 return NULL;
1208 #if FTLN_DEBUG_PTR
1209 Ftln = ftl;
1210 #endif
1211
1212 // Set callback to free FTL resources from generic FTL NDM layer.
1213 ftl->free_ftl = free_ftl;
1214
1215 // Acquire exclusive access to upper file system.
1216 semPend(FileSysSem, WAIT_FOREVER);
1217
1218 // Add volume to list of FTL volumes.
1219 CIRC_LIST_APPEND(&ftl->link, &FtlnVols);
1220
1221 // Set all FTL driver dependent variables.
1222 ftl->page_size = ftl_dvr->page_size;
1223 ftl->eb_size = ftl_dvr->eb_size;
1224 ftl->block_size = ftl_dvr->block_size;
1225 ftl->num_blks = ftl_dvr->num_blocks;
1226 ftl->start_pn = ftl_dvr->start_page;
1227 ftl->ndm = ftl_dvr->ndm;
1228 ftl->type = ftl_dvr->type;
1229 SET_FLAG(ftl->flags, ftl_type);
1230 ftl->sect_size = sect_size;
1231
1232 // Derive other driver dependent variables.
1233 ftl->pgs_per_blk = ftl->block_size / ftl->page_size;
1234 if (ftl->pgs_per_blk > PGS_PER_BLK_MAX) {
1235 FsError(EINVAL);
1236 semPostBin(FileSysSem);
1237 goto FtlnAddV_err;
1238 }
1239 ftl->num_pages = ftl->pgs_per_blk * ftl->num_blks;
1240 #if !FTLN_LEGACY
1241 #if FTLN_3B_PN
1242 if (ftl->num_pages > 0x1000000) {
1243 FsError(EFBIG);
1244 semPostBin(FileSysSem);
1245 goto FtlnAddV_err;
1246 }
1247 #endif
1248 #endif // !FTLN_LEGACY
1249 ftl->sects_per_page = ftl->page_size / ftl->sect_size;
1250
1251 // Release file system exclusive access.
1252 semPostBin(FileSysSem);
1253
1254 // Copy the driver callback functions.
1255 ftl->write_page = ftl_dvr->write_data_and_spare;
1256 ftl->write_pages = ftl_dvr->write_pages;
1257 ftl->read_spare = ftl_dvr->read_spare;
1258 ftl->read_pages = ftl_dvr->read_pages;
1259 ftl->page_check = ftl_dvr->page_check;
1260 ftl->xfer_page = ftl_dvr->transfer_page;
1261 ftl->erase_block = ftl_dvr->erase_block;
1262 #if INC_FTL_NDM_MLC
1263 ftl->pair_offset = ftl_dvr->pair_offset;
1264 #endif
1265
1266 // Compute how many volume pages are mapped by a single map page.
1267 ftl->mappings_per_mpg = ftl->page_size / FTLN_PN_SZ;
1268
1269 #if !FTLN_LEGACY
1270 // Determine largest possible number of volume blocks.
1271 for (vol_blks = ftl->num_blks - FTLN_MIN_FREE_BLKS - 1;; --vol_blks) {
1272 // Determine number of map pages for given number of vol blocks.
1273 n = (vol_blks * ftl->pgs_per_blk + ftl->mappings_per_mpg - 1) / ftl->mappings_per_mpg;
1274 n = n + 1; // plus one for metapage
1275
1276 // Convert to number of map blocks.
1277 n = (n * ftl->page_size + ftl->block_size - 1) / ftl->block_size;
1278
1279 #if INC_FTL_NDM_MLC
1280 // If MLC, double the required number of map blocks because only
1281 // half their pages are used.
1282 if (ftl->type == NDM_MLC)
1283 n *= 2;
1284 #endif
1285
1286 // Break if this number of volume blocks fits into the partition.
1287 if (vol_blks + n + FTLN_MIN_FREE_BLKS <= ftl->num_blks)
1288 break;
1289 }
1290
1291 #if INC_FTL_NDM_MLC
1292 // If MLC, remove another 5% of volume space to account for having
1293 // to advance the free volume pointer to skip possible page pair
1294 // corruption anytime FTL metadata is synched to flash.
1295 if (ftl->type == NDM_MLC)
1296 vol_blks = 95 * vol_blks / 100;
1297 #endif
1298
1299 #else // FTLN_LEGACY
1300
1301 // Compute the number of volume blocks using:
1302 // VB = TB - MB - 4 (1)
1303 // where VB = # volume blocks, TB = # total blocks, MB = # map blocks
1304 // and:
1305 // MB = (4 * VB * PB + 1) / BS (2)
1306 // where PB = # pages per block and BS = block size in bytes
1307 // Combining (1) and (2) yields (with rounding):
1308 // VB = TB - (4 * (TP + PB) + 6 * BS - 2) / (BS + 4 * PB)
1309 // For MLC devices, double the number of map blocks in computation,
1310 // because we only use half the pages in MLC map blocks.
1311 #if INC_FTL_NDM_MLC && (INC_FTL_NDM_SLC || INC_FTL_NOR_WR1)
1312 if (ftl->type == NDM_SLC)
1313 #endif
1314 #if INC_FTL_NDM_SLC || INC_FTL_NOR_WR1
1315 {
1316 vol_blks = ftl->num_blks -
1317 (4 * (ftl->num_pages + ftl->pgs_per_blk) + 6 * ftl->block_size - 2) /
1318 (ftl->block_size + 4 * ftl->pgs_per_blk);
1319 }
1320 #endif
1321 #if INC_FTL_NDM_MLC && (INC_FTL_NDM_SLC || INC_FTL_NOR_WR1)
1322 else
1323 #endif
1324 #if INC_FTL_NDM_MLC
1325 {
1326 vol_blks = ftl->num_blks -
1327 (8 * (ftl->num_pages + ftl->pgs_per_blk) + 5 * ftl->block_size + 1) /
1328 (ftl->block_size + 8 * ftl->pgs_per_blk);
1329
1330 // Remove another 5% from volume space to account for the fact
1331 // that the free volume pointer must be advanced to skip page
1332 // pair corruption anytime the FTL meta information is flushed.
1333 vol_blks = 95 * vol_blks / 100;
1334 }
1335 #endif
1336 #endif // FTLN_LEGACY
1337
1338 // Compute number of volume pages and subtract extra free percentage.
1339 // If driver specifies an acceptable amount, use it. Otherwise, use
1340 // 2%. Increasing number of map pages makes recycles more efficient
1341 // because the ratio of used to dirty pages is lower in map blocks.
1342 ftl->num_vpages = vol_blks * ftl->pgs_per_blk;
1343 n = ftl_dvr->extra_free;
1344 if (FLAG_IS_CLR(ftl_dvr->flags, FSF_EXTRA_FREE) || n < 2 || n > 50)
1345 n = 2;
1346 n = (n * ftl->num_vpages) / 100;
1347 if (n == 0)
1348 n = 1;
1349 ftl->num_vpages -= n;
1350
1351 #if INC_FTL_NDM_MLC
1352 // For MLC devices, account for the fact that the last recycled
1353 // volume block cannot be fully used. To be safe, assume worst case
1354 // scenario for max pair offset - half a block.
1355 if (ftl->type == NDM_MLC)
1356 ftl->num_vpages -= ftl->pgs_per_blk / 2;
1357 #endif
1358
1359 // Compute number of map pages based on number of volume pages.
1360 ftl->num_map_pgs = 1 + (ftl->num_vpages + ftl->mappings_per_mpg - 1) / ftl->mappings_per_mpg;
1361 PfAssert(ftl->num_vpages / ftl->mappings_per_mpg < ftl->num_map_pgs);
1362
1363 #if FTLN_DEBUG > 1
1364 printf("\nVOL PAGES = %u, FTL PAGES = %u, %u%% usage\n", ftl->num_vpages, ftl->num_pages,
1365 (ftl->num_vpages * 100) / ftl->num_pages);
1366 #endif
1367
1368 // Set the number of sectors based on the number of pages.
1369 ftl->num_vsects = ftl->num_vpages * ftl->sects_per_page;
1370
1371 // Allocate one or two main data pages and spare buffers. Max spare
1372 // use is one block worth of spare areas for multi-page writes.
1373 #if INC_SECT_FTL
1374 n = 2 * ftl->page_size + ftl->eb_size * ftl->pgs_per_blk;
1375 #else
1376 n = 1 * ftl->page_size + ftl->eb_size * ftl->pgs_per_blk;
1377 #endif
1378 buf = FsAalloc(n);
1379 if (buf == NULL)
1380 goto FtlnAddV_err;
1381 ftl->main_buf = buf;
1382 buf += ftl->page_size;
1383 #if INC_SECT_FTL
1384 ftl->swap_page = buf;
1385 buf += ftl->page_size;
1386 #endif
1387 ftl->spare_buf = buf;
1388
1389 // Allocate memory for the block data and wear count lag arrays.
1390 ftl->bdata = FsCalloc(ftl->num_blks, sizeof(ui32));
1391 if (ftl->bdata == NULL)
1392 goto FtlnAddV_err;
1393 ftl->blk_wc_lag = FsCalloc(ftl->num_blks, sizeof(ui8));
1394 if (ftl->blk_wc_lag == NULL)
1395 goto FtlnAddV_err;
1396 ftl->high_wc = 0;
1397
1398 // Allocate memory for map pages array (holds physical page numbers).
1399 ftl->mpns = FsMalloc(ftl->num_map_pgs * sizeof(ui32));
1400 if (ftl->mpns == NULL)
1401 goto FtlnAddV_err;
1402
1403 // For SLC devices, adjust driver cached MPNs if too big or zero.
1404 #if INC_FTL_NDM_MLC && (INC_FTL_NDM_SLC || INC_FTL_NOR_WR1)
1405 if (ftl->type == NDM_SLC)
1406 #endif
1407 #if INC_FTL_NDM_SLC || INC_FTL_NOR_WR1
1408 {
1409 if (ftl->num_map_pgs < ftl_dvr->cached_map_pages || ftl_dvr->cached_map_pages == 0)
1410 ftl_dvr->cached_map_pages = ftl->num_map_pgs;
1411 }
1412 #endif
1413
1414 // For MLC devices, cache all map pages so that no map write occurs
1415 // due to cache preemption.
1416 #if INC_FTL_NDM_MLC && (INC_FTL_NDM_SLC || INC_FTL_NOR_WR1)
1417 else
1418 #endif
1419 #if INC_NDM_MLC
1420 ftl_dvr->cached_map_pages = ftl->num_map_pgs;
1421 #endif
1422
1423 // Allocate map page cache for new volume.
1424 ftl->map_cache = ftlmcNew(ftl, ftl_dvr->cached_map_pages, FtlnMapWr, FtlnMapRd, ftl->page_size);
1425 if (ftl->map_cache == NULL)
1426 goto FtlnAddV_err;
1427
1428 #if INC_FTL_PAGE_CACHE
1429 // If FAT volume and driver requests it, allocate volume page cache.
1430 if (FLAG_IS_SET(ftl->flags, FTLN_FAT_VOL) && FLAG_IS_SET(ftl_dvr->flags, FSF_FTL_PAGE_CACHE)) {
1431 ftl->vol_cache =
1432 ftlvcNew(ftl, ftl_dvr->cached_vol_pages, FtlnVpnWr, FtlnVpnRd, ftl->page_size);
1433 if (ftl->vol_cache == NULL)
1434 goto FtlnAddV_err;
1435 }
1436 #endif
1437
1438 // Set block read wear limit and mark no block at limit.
1439 if (FLAG_IS_SET(ftl_dvr->flags, FSF_READ_WEAR_LIMIT))
1440 ftl->max_rc = ftl_dvr->read_wear_limit;
1441 #if INC_FTL_NDM_MLC
1442 else
1443 #if INC_FTL_NDM_SLC || INC_FTL_NOR_WR1
1444 if (ftl_dvr->type == NDM_MLC)
1445 #endif
1446 ftl->max_rc = MLC_NAND_RC_LIMIT;
1447 #endif
1448 #if INC_FTL_NDM_SLC
1449 else
1450 #if INC_FTL_NOR_WR1
1451 if (ftl_dvr->type == NDM_SLC)
1452 #endif
1453 ftl->max_rc = SLC_NAND_RC_LIMIT;
1454 #endif
1455 #if INC_FTL_NOR_WR1
1456 else
1457 ftl->max_rc = NOR_RC_LIMIT;
1458 #endif
1459 if (ftl->max_rc > RC_MASK) {
1460 FsError(EINVAL);
1461 goto FtlnAddV_err;
1462 }
1463
1464 // Initialize volume state.
1465 FtlnStateRst(ftl);
1466
1467 // Initialize the NAND FTL.
1468 if (init_ftln(ftl))
1469 goto FtlnAddV_err;
1470
1471 #if FTLN_DEBUG > 1
1472 // Display FTL statistics.
1473 FtlnStats(ftl);
1474 #endif
1475
1476 #if INC_SECT_FTL
1477 // If FAT volume, prepare for registration with TargetFAT.
1478 if (ftl_type == FTLN_FAT_VOL) {
1479 FatVol* fat = (FatVol*)fs_vol;
1480
1481 // Initialize TargetFAT driver structure.
1482 #if INC_FAT_MBR
1483 fat->start_sect = ftl->vol_frst_sect;
1484 fat->num_sects = ftl->num_vsects - ftl->vol_frst_sect;
1485 #else
1486 fat->start_sect = 0;
1487 fat->num_sects = ftl->num_vsects;
1488 #endif
1489 fat->vol = ftl;
1490 fat->write_sectors = FtlnWrSects;
1491 fat->read_sectors = FtlnRdSects;
1492 fat->report = FtlnReport;
1493 fat->flags |= FSF_BLUNK_FTL;
1494
1495 #if FAT_DEBUG
1496 printf("\nFAT STATS:\n");
1497 printf(" - start_sect = %u\n", fat->start_sect);
1498 printf(" - num_sects = %u\n", fat->num_sects);
1499 printf(" - min_clust_size = %u\n", fat->min_clust_size);
1500 printf(" - flags = 0x%X\n\n", fat->flags);
1501 #endif
1502
1503 // Standard FTL-FAT settings.
1504 fat->fixed = TRUE;
1505 fat->num_heads = FAT_NUM_HEADS;
1506 fat->sects_per_trk = FAT_SECTS_PER_TRACK;
1507
1508 // Save volume name.
1509 strcpy(ftl->vol_name, fat->name);
1510 }
1511 #endif // INC_SECT_FTL
1512
1513 #if INC_PAGE_FTL
1514 // If XFS volume, prepare for registration with TargetXFS.
1515 if (ftl_type == FTLN_XFS_VOL) {
1516 XfsVol* xfs = (XfsVol*)fs_vol;
1517
1518 // Initialize TargetXFS driver structure with FTL specific fields.
1519 xfs->start_page = 0;
1520 xfs->num_pages = ftl->num_vsects;
1521 xfs->page_size = ftl->page_size;
1522 xfs->vol = ftl;
1523 xfs->write_pages = FtlnWrSects;
1524 xfs->read_pages = FtlnRdSects;
1525 xfs->report = FtlnReport;
1526
1527 #if FTLN_DEBUG > 1
1528 printf("\nXFS STATS:\n");
1529 printf(" - start_page = %u\n", xfs->start_page);
1530 printf(" - num_pages = %u\n\n", xfs->num_pages);
1531 #endif
1532
1533 // Save volume name.
1534 strcpy(ftl->vol_name, xfs->name);
1535 }
1536 #endif // INC_PAGE_FTL
1537
1538 // Return pointer to FTL control block.
1539 return ftl;
1540
1541 // Error exit.
1542 FtlnAddV_err:
1543 semPend(FileSysSem, WAIT_FOREVER);
1544 CIRC_NODE_REMOVE(&ftl->link);
1545 free_ftl(ftl);
1546 semPostBin(FileSysSem);
1547 return NULL;
1548 }
1549
1550 #if INC_SECT_FTL
1551 // FtlNdmAddFatFTL: Create a new TargetFTL-NDM FAT FTL
1552 //
1553 // Inputs: ftl_dvr = pointer to FTL NDM driver control block
1554 // fat = pointer to FAT pseudo driver control block
1555 //
1556 // Returns: Pointer to FTL control block on success, else NULL
1557 //
FtlNdmAddFatFTL(FtlNdmVol * ftl_dvr,FatVol * fat)1558 void* FtlNdmAddFatFTL(FtlNdmVol* ftl_dvr, FatVol* fat) {
1559 // Determine sector size.
1560 fat->sect_size = FatGetSectSize(fat);
1561 if (fat->sect_size == 0)
1562 return NULL;
1563
1564 // Create new FTL and return FTL handle.
1565 return FtlnAddVol(ftl_dvr, FTLN_FAT_VOL, fat->sect_size, fat);
1566 } //lint !e818
1567 #endif // INC_SECT_FTL
1568
1569 #if INC_PAGE_FTL
1570 // FtlNdmAddXfsFTL: Create a new TargetFTL-NDM XFS FTL
1571 //
1572 // Inputs: ftl_dvr = pointer to FTL NDM driver control block
1573 // xfs = pointer to XFS pseudo driver control block
1574 //
1575 // Returns: -1 if error, 0 for success
1576 //
FtlNdmAddXfsFTL(FtlNdmVol * ftl_dvr,XfsVol * xfs)1577 void* FtlNdmAddXfsFTL(FtlNdmVol* ftl_dvr, XfsVol* xfs) {
1578 // Create new FTL and return FTL handle.
1579 return FtlnAddVol(ftl_dvr, FTLN_XFS_VOL, ftl_dvr->page_size, xfs);
1580 } //lint !e818
1581 #endif // INC_PAGE_FTL
1582
1583 // FtlnFreeFTL: Free an existing FTL volume
1584 //
1585 // Input: handle = FTL handle
1586 //
FtlnFreeFTL(void * handle)1587 void FtlnFreeFTL(void* handle) {
1588 FTLN ftln = handle;
1589
1590 // Acquire exclusive access to upper file system.
1591 semPend(FileSysSem, WAIT_FOREVER);
1592
1593 // Remove FTL from list and free its memory.
1594 CIRC_NODE_REMOVE(&ftln->link);
1595 ftln->free_ftl(ftln);
1596
1597 // Release exclusive access to upper file system.
1598 semPostBin(FileSysSem);
1599 }
1600
1601 // FtlnDelVol: Delete an existing FTL NDM volume (both FTL and FS)
1602 //
1603 // Input: ftl = pointer to FTL control block
1604 //
1605 // Note: Called with exclusive file system access held
1606 //
1607 // Returns: 0 if success, -1 if error
1608 //
FtlnDelVol(FTLN ftl)1609 int FtlnDelVol(FTLN ftl) {
1610 // Remove volume from list of volumes.
1611 CIRC_NODE_REMOVE(&ftl->link);
1612
1613 // Release file system exclusive access.
1614 semPostBin(FileSysSem);
1615
1616 // Delete file system volume.
1617 #if INC_PAGE_FTL && INC_SECT_FTL
1618 if (FLAG_IS_SET(ftl->flags, FTLN_XFS_VOL))
1619 #endif
1620 #if INC_PAGE_FTL
1621 (void)XfsDelVol(ftl->vol_name);
1622 #endif
1623 #if INC_PAGE_FTL && INC_SECT_FTL
1624 else
1625 #endif
1626 #if INC_SECT_FTL
1627 (void)FatDelVol(ftl->vol_name);
1628 #endif
1629
1630 // Acquire exclusive access to upper file system.
1631 semPend(FileSysSem, WAIT_FOREVER);
1632
1633 // Delete FTL and return success.
1634 ftl->free_ftl(ftl);
1635 return 0;
1636 }
1637
1638 // FtlNdmDelVol: Delete an existing FTL NDM volume
1639 //
1640 // Input: name = name of volume to delete
1641 //
1642 // Returns: 0 on success, -1 on failure
1643 //
1644 // Note: Called with FileSysSem semaphore held
1645 //
FtlNdmDelVol(const char * name)1646 int FtlNdmDelVol(const char* name) {
1647 CircLink* circ;
1648
1649 // Acquire global file system semaphore.
1650 semPend(FileSysSem, WAIT_FOREVER);
1651
1652 // Search all TargetFTL-NDM volume for name match.
1653 for (circ = CIRC_LIST_HEAD(&FtlnVols);; circ = circ->next_bck) {
1654 FTLN ftln;
1655
1656 // Stop when end of list is reached.
1657 if (CIRC_LIST_AT_END(circ, &FtlnVols)) {
1658 // Release file system exclusive access.
1659 semPostBin(FileSysSem);
1660
1661 // Volume not found, assign errno and return -1.
1662 return FsError(ENOENT);
1663 }
1664
1665 // If volume found, delete it and return success.
1666 ftln = (FTLN)circ;
1667 if (FNameEqu(ftln->vol_name, name)) {
1668 int rc;
1669
1670 // Delete this TargetFTL-NDM volume.
1671 rc = FtlnDelVol(ftln);
1672
1673 // Release file system exclusive access and return status.
1674 semPostBin(FileSysSem);
1675 return rc;
1676 }
1677 }
1678 }
1679 #endif // INC_FTL_NDM
1680