ipod nano 2g: make functions/variables static where possible, add missing #includes
[kugel-rb.git] / firmware / target / arm / s5l8700 / ipodnano2g / ftl-nano2g.c
blob69fac62289a66838c34028346cb7ea6119e957e7
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2009 by Michael Sparmann
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
24 #include <config.h>
25 #include <cpu.h>
26 #include <nand-target.h>
27 #include <ftl-target.h>
28 #include <string.h>
29 #include "system.h"
30 #include "kernel.h"
31 #include "panic.h"
35 #define FTL_COPYBUF_SIZE 32
36 #define FTL_WRITESPARE_SIZE 32
37 //#define FTL_FORCEMOUNT
41 #ifdef FTL_FORCEMOUNT
42 #ifndef FTL_READONLY
43 #define FTL_READONLY
44 #endif
45 #endif
48 #ifdef FTL_READONLY
49 uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer)
51 (void)sector;
52 (void)count;
53 (void)buffer;
54 return -1;
56 uint32_t ftl_sync(void)
58 return 0;
60 #endif
64 /* Keeps the state of a scattered page block.
65 This structure is used in memory only, not on flash,
66 but it equals the one the OFW uses. */
67 struct ftl_log_type
70 /* The ftl_cxt.nextblockusn at the time the block was allocated,
71 needed in order to be able to remove the oldest ones first. */
72 uint32_t usn;
74 /* The vBlock number at which the scattered pages are stored */
75 uint16_t scatteredvblock;
77 /* the lBlock number for which those pages are */
78 uint16_t logicalvblock;
80 /* Pointer to ftl_offsets, contains the mapping which lPage is
81 currently stored at which scattered vPage. */
82 uint16_t* pageoffsets;
84 /* Pages used in the vBlock, i.e. next page number to be written */
85 uint16_t pagesused;
87 /* Pages that are still up to date in this block, i.e. need to be
88 moved when this vBlock is deallocated. */
89 uint16_t pagescurrent;
91 /* A flag whether all pages are still sequential in this block.
92 Initialized to 1 on allocation, zeroed as soon as anything is
93 written out of sequence, so that the block will need copying
94 when committing to get the pages back into the right order.
95 This is used to half the number of block erases needed when
96 writing huge amounts of sequential data. */
97 uint32_t issequential;
99 } __attribute__((packed));
102 /* Keeps the state of the FTL, both on flash and in memory */
103 struct ftl_cxt_type
106 /* Update sequence number of the FTL context, decremented
107 every time a new revision of FTL meta data is written. */
108 uint32_t usn;
110 /* Update sequence number for user data blocks. Incremented
111 every time a portion of user pages is written, so that
112 a consistency check can determine which copy of a user
113 page is the most recent one. */
114 uint32_t nextblockusn;
116 /* Count of currently free pages in the block pool */
117 uint16_t freecount;
119 /* Index to the first free hyperblock in the blockpool ring buffer */
120 uint16_t nextfreeidx;
122 /* This is a counter that is used to better distribute block
123 wear. It is incremented on every block erase, and if it
124 gets too high (300 on writes, 20 on sync), the most and
125 least worn hyperblock will be swapped (causing an additional
126 block write) and the counter will be decreased by 20. */
127 uint16_t swapcounter;
129 /* Ring buffer of currently free hyperblocks. nextfreeidx is the
130 index to freecount free ones, the other ones are currently
131 allocated for scattered page hyperblocks. */
132 uint16_t blockpool[0x14];
134 /* Alignment to 32 bits */
135 uint16_t field_36;
137 /* vPages where the block map is stored */
138 uint32_t ftl_map_pages[8];
140 /* Probably additional map page number space for bigger chips */
141 uint8_t field_58[0x28];
143 /* vPages where the erase counters are stored */
144 uint32_t ftl_erasectr_pages[8];
146 /* Seems to be padding */
147 uint8_t field_A0[0x70];
149 /* Pointer to ftl_map used by Whimory, not used by us */
150 uint32_t ftl_map_ptr;
152 /* Pointer to ftl_erasectr used by Whimory, not used by us */
153 uint32_t ftl_erasectr_ptr;
155 /* Pointer to ftl_log used by Whimory, not used by us */
156 uint32_t ftl_log_ptr;
158 /* Flag used to indicate that some erase counter pages should be committed
159 because they were changed more than 100 times since the last commit. */
160 uint32_t erasedirty;
162 /* Seems to be unused */
163 uint16_t field_120;
165 /* vBlocks used to store the FTL context, map, and erase
166 counter pages. This is also a ring buffer, and the oldest
167 page gets swapped with the least used page from the block
168 pool ring buffer when a new one is allocated. */
169 uint16_t ftlctrlblocks[3];
171 /* The last used vPage number from ftlctrlblocks */
172 uint32_t ftlctrlpage;
174 /* Set on context sync, reset on write, so obviously never
175 zero in the context written to the flash */
176 uint32_t clean_flag;
178 /* Seems to be unused, but gets loaded from flash by Whimory. */
179 uint8_t field_130[0x15C];
181 } __attribute__((packed));
184 /* Keeps the state of the bank's VFL, both on flash and in memory.
185 There is one of these per bank. */
186 typedef struct ftl_vfl_cxt_type
189 /* Cross-bank update sequence number, incremented on every VFL
190 context commit on any bank. */
191 uint32_t usn;
193 /* See ftl_cxt.ftlctrlblocks. This is stored to the VFL contexts
194 in order to be able to find the most recent FTL context copy
195 when mounting the FTL. The VFL context number this will be
196 written to on an FTL context commit is chosen semi-randomly. */
197 uint16_t ftlctrlblocks[3];
199 /* Alignment to 32 bits */
200 uint8_t field_A[2];
202 /* Decrementing update counter for VFL context commits per bank */
203 uint32_t updatecount;
205 /* Number of the currently active VFL context block, it's an index
206 into vflcxtblocks. */
207 uint16_t activecxtblock;
209 /* Number of the first free page in the active VFL context block */
210 uint16_t nextcxtpage;
212 /* Seems to be unused */
213 uint8_t field_14[4];
215 /* Incremented every time a block erase error leads to a remap,
216 but doesn't seem to be read anywhere. */
217 uint16_t field_18;
219 /* Number of spare blocks used */
220 uint16_t spareused;
222 /* pBlock number of the first spare block */
223 uint16_t firstspare;
225 /* Total number of spare blocks */
226 uint16_t sparecount;
228 /* Block remap table. Contains the vBlock number the n-th spare
229 block is used as a replacement for. 0 = unused, 0xFFFF = bad. */
230 uint16_t remaptable[0x334];
232 /* Bad block table. Each bit represents 8 blocks. 1 = OK, 0 = Bad.
233 If the entry is zero, you should look at the remap table to see
234 if the block is remapped, and if yes, where the replacement is. */
235 uint8_t bbt[0x11A];
237 /* pBlock numbers used to store the VFL context. This is a ring
238 buffer. On a VFL context write, always 8 pages are written,
239 and it passes if at least 4 of them can be read back. */
240 uint16_t vflcxtblocks[4];
242 /* Blocks scheduled for remapping are stored at the end of the
243 remap table. This is the first index used for them. */
244 uint16_t scheduledstart;
246 /* Probably padding */
247 uint8_t field_7AC[0x4C];
249 /* First checksum (addition) */
250 uint32_t checksum1;
252 /* Second checksum (XOR), there is a bug in whimory regarding this. */
253 uint32_t checksum2;
255 } __attribute__((packed)) FTLVFLCxtType;
258 /* Layout of the spare bytes of each page on the flash */
259 union ftl_spare_data_type
262 /* The layout used for actual user data (types 0x40 and 0x41) */
263 struct ftl_spare_data_user_type
266 /* The lPage, i.e. Sector, number */
267 uint32_t lpn;
269 /* The update sequence number of that page,
270 copied from ftl_cxt.nextblockusn on write */
271 uint32_t usn;
273 /* Seems to be unused */
274 uint8_t field_8;
276 /* Type field, 0x40 (data page) or 0x41
277 (last data page of hyperblock) */
278 uint8_t type;
280 /* ECC mark, usually 0xFF. If an error occurred while reading the
281 page during a copying operation earlier, this will be 0x55. */
282 uint8_t eccmark;
284 /* Seems to be unused */
285 uint8_t field_B;
287 /* ECC data for the user data */
288 uint8_t dataecc[0x28];
290 /* ECC data for the first 0xC bytes above */
291 uint8_t spareecc[0xC];
293 } __attribute__((packed)) user;
295 /* The layout used for meta data (other types) */
296 struct ftl_spare_data_meta_type
299 /* ftl_cxt.usn for FTL stuff, ftl_vfl_cxt.updatecount for VFL stuff */
300 uint32_t usn;
302 /* Index of the thing inside the page,
303 for example number / index of the map or erase counter page */
304 uint16_t idx;
306 /* Seems to be unused */
307 uint8_t field_6;
309 /* Seems to be unused */
310 uint8_t field_7;
312 /* Seems to be unused */
313 uint8_t field_8;
315 /* Type field:
316 0x43: FTL context page
317 0x44: Block map page
318 0x46: Erase counter page
319 0x47: "FTL is currently mounted", i.e. unclean shutdown, mark
320 0x80: VFL context page */
321 uint8_t type;
323 /* ECC mark, usually 0xFF. If an error occurred while reading the
324 page during a copying operation earlier, this will be 0x55. */
325 uint8_t eccmark;
327 /* Seems to be unused */
328 uint8_t field_B;
330 /* ECC data for the user data */
331 uint8_t dataecc[0x28];
333 /* ECC data for the first 0xC bytes above */
334 uint8_t spareecc[0xC];
336 } __attribute__((packed)) meta;
341 /* Keeps track of troublesome blocks, only in memory, lost on unmount. */
342 struct ftl_trouble_type
345 /* vBlock number of the block giving trouble */
346 uint16_t block;
348 /* Bank of the block giving trouble */
349 uint8_t bank;
351 /* Error counter, incremented by 3 on error, decremented by 1 on erase,
352 remaping will be done when it reaches 6. */
353 uint8_t errors;
355 } __attribute__((packed));
359 /* Pointer to an info structure regarding the flash type used */
360 const struct nand_device_info_type* ftl_nand_type;
362 /* Number of banks we detected a chip on */
363 uint32_t ftl_banks;
365 /* Block map, used vor pBlock to vBlock mapping */
366 static uint16_t ftl_map[0x2000];
368 /* VFL context for each bank */
369 static struct ftl_vfl_cxt_type ftl_vfl_cxt[4];
371 /* FTL context */
372 static struct ftl_cxt_type ftl_cxt;
374 /* Temporary data buffers for internal use by the FTL */
375 static uint8_t ftl_buffer[0x800] STORAGE_ALIGN_ATTR;
377 /* Temporary spare byte buffer for internal use by the FTL */
378 static union ftl_spare_data_type ftl_sparebuffer[FTL_WRITESPARE_SIZE] STORAGE_ALIGN_ATTR;
381 #ifndef FTL_READONLY
383 /* Lowlevel BBT for each bank */
384 static uint8_t ftl_bbt[4][0x410];
386 /* Erase counters for the vBlocks */
387 static uint16_t ftl_erasectr[0x2000];
389 /* Used by ftl_log */
390 static uint16_t ftl_offsets[0x11][0x200];
392 /* Structs keeping record of scattered page blocks */
393 static struct ftl_log_type ftl_log[0x11];
395 /* Global cross-bank update sequence number of the VFL context */
396 static uint32_t ftl_vfl_usn;
398 /* Keeps track (temporarily) of troublesome blocks */
399 static struct ftl_trouble_type ftl_troublelog[5];
401 /* Counts erase counter page changes, after 100 of them the affected
402 page will be committed to the flash. */
403 static uint8_t ftl_erasectr_dirt[8];
405 /* Buffer needed for copying pages around while moving or committing blocks.
406 This can't be shared with ftl_buffer, because this one could be overwritten
407 during the copying operation in order to e.g. commit a CXT. */
408 static uint8_t ftl_copybuffer[FTL_COPYBUF_SIZE][0x800] STORAGE_ALIGN_ATTR;
409 static union ftl_spare_data_type ftl_copyspare[FTL_COPYBUF_SIZE] STORAGE_ALIGN_ATTR;
411 /* Needed to store the old scattered page offsets in order to be able to roll
412 back if something fails while compacting a scattered page block. */
413 static uint16_t ftl_offsets_backup[0x200] STORAGE_ALIGN_ATTR;
415 #endif
418 static struct mutex ftl_mtx;
422 /* Finds a device info page for the specified bank and returns its number.
423 Used to check if one is present, and to read the lowlevel BBT. */
424 static uint32_t ftl_find_devinfo(uint32_t bank)
426 /* Scan the last 10% of the flash for device info pages */
427 uint32_t lowestBlock = ftl_nand_type->blocks
428 - (ftl_nand_type->blocks / 10);
429 uint32_t block, page, pagenum;
430 for (block = ftl_nand_type->blocks - 1; block >= lowestBlock; block--)
432 page = ftl_nand_type->pagesperblock - 8;
433 for (; page < ftl_nand_type->pagesperblock; page++)
435 pagenum = block * ftl_nand_type->pagesperblock + page;
436 if ((nand_read_page(bank, pagenum, ftl_buffer,
437 &ftl_sparebuffer[0], 1, 0) & 0x11F) != 0)
438 continue;
439 if (memcmp(ftl_buffer, "DEVICEINFOSIGN\0", 0x10) == 0)
440 return pagenum;
443 return 0;
447 /* Checks if all banks have proper device info pages */
448 static uint32_t ftl_has_devinfo(void)
450 uint32_t i;
451 for (i = 0; i < ftl_banks; i++) if (ftl_find_devinfo(i) == 0) return 0;
452 return 1;
456 /* Loads the lowlevel BBT for a bank to the specified buffer.
457 This is based on some cryptic disassembly and not fully understood yet. */
458 static uint32_t ftl_load_bbt(uint32_t bank, uint8_t* bbt)
460 uint32_t i, j;
461 uint32_t pagebase, page = ftl_find_devinfo(bank), page2;
462 uint32_t unk1, unk2, unk3;
463 if (page == 0) return 1;
464 pagebase = page & ~(ftl_nand_type->pagesperblock - 1);
465 if ((nand_read_page(bank, page, ftl_buffer,
466 (uint32_t*)0, 1, 0) & 0x11F) != 0) return 1;
467 if (memcmp(&ftl_buffer[0x18], "BBT", 4) != 0) return 1;
468 unk1 = ((uint16_t*)ftl_buffer)[0x10];
469 unk2 = ((uint16_t*)ftl_buffer)[0x11];
470 unk3 = ((uint16_t*)ftl_buffer)[((uint32_t*)ftl_buffer)[4] * 6 + 10]
471 + ((uint16_t*)ftl_buffer)[((uint32_t*)ftl_buffer)[4] * 6 + 11];
472 for (i = 0; i < unk1; i++)
474 for (j = 0; ; j++)
476 page2 = unk2 + i + unk3 * j;
477 if (page2 >= (uint32_t)(ftl_nand_type->pagesperblock - 8))
478 break;
479 if ((nand_read_page(bank, pagebase + page2, ftl_buffer,
480 (void*)0, 1, 0) & 0x11F) == 0)
482 memcpy(bbt, ftl_buffer, 0x410);
483 return 0;
487 return 1;
491 /* Calculates the checksums for the VFL context page of the specified bank */
492 static void ftl_vfl_calculate_checksum(uint32_t bank,
493 uint32_t* checksum1, uint32_t* checksum2)
495 uint32_t i;
496 *checksum1 = 0xAABBCCDD;
497 *checksum2 = 0xAABBCCDD;
498 for (i = 0; i < 0x1FE; i++)
500 *checksum1 += ((uint32_t*)(&ftl_vfl_cxt[bank]))[i];
501 *checksum2 ^= ((uint32_t*)(&ftl_vfl_cxt[bank]))[i];
506 /* Checks if the checksums of the VFL context
507 of the specified bank are correct */
508 static uint32_t ftl_vfl_verify_checksum(uint32_t bank)
510 uint32_t checksum1, checksum2;
511 ftl_vfl_calculate_checksum(bank, &checksum1, &checksum2);
512 if (checksum1 == ftl_vfl_cxt[bank].checksum1) return 0;
513 /* The following line is pretty obviously a bug in Whimory,
514 but we do it the same way for compatibility. */
515 if (checksum2 != ftl_vfl_cxt[bank].checksum2) return 0;
516 panicf("FTL: Bad VFL CXT checksum!");
517 return 1;
521 #ifndef FTL_READONLY
522 /* Updates the checksums of the VFL context of the specified bank */
523 static void ftl_vfl_update_checksum(uint32_t bank)
525 ftl_vfl_calculate_checksum(bank, &ftl_vfl_cxt[bank].checksum1,
526 &ftl_vfl_cxt[bank].checksum2);
528 #endif
531 #ifndef FTL_READONLY
532 /* Writes 8 copies of the VFL context of the specified bank to flash,
533 and succeeds if at least 4 can be read back properly. */
534 static uint32_t ftl_vfl_store_cxt(uint32_t bank)
536 uint32_t i;
537 ftl_vfl_cxt[bank].updatecount--;
538 ftl_vfl_cxt[bank].usn = ++ftl_vfl_usn;
539 ftl_vfl_cxt[bank].nextcxtpage += 8;
540 ftl_vfl_update_checksum(bank);
541 memset(&ftl_sparebuffer[0], 0xFF, 0x40);
542 ftl_sparebuffer[0].meta.usn = ftl_vfl_cxt[bank].updatecount;
543 ftl_sparebuffer[0].meta.field_8 = 0;
544 ftl_sparebuffer[0].meta.type = 0x80;
545 for (i = 1; i <= 8; i++)
547 uint32_t index = ftl_vfl_cxt[bank].activecxtblock;
548 uint32_t block = ftl_vfl_cxt[bank].vflcxtblocks[index];
549 uint32_t page = block * ftl_nand_type->pagesperblock;
550 page += ftl_vfl_cxt[bank].nextcxtpage - i;
551 nand_write_page(bank, page, &ftl_vfl_cxt[bank], &ftl_sparebuffer[0], 1);
553 uint32_t good = 0;
554 for (i = 1; i <= 8; i++)
556 uint32_t index = ftl_vfl_cxt[bank].activecxtblock;
557 uint32_t block = ftl_vfl_cxt[bank].vflcxtblocks[index];
558 uint32_t page = block * ftl_nand_type->pagesperblock;
559 page += ftl_vfl_cxt[bank].nextcxtpage - i;
560 if ((nand_read_page(bank, page, ftl_buffer,
561 &ftl_sparebuffer[0], 1, 0) & 0x11F) != 0)
562 continue;
563 if (memcmp(ftl_buffer, &ftl_vfl_cxt[bank], 0x7AC) != 0)
564 continue;
565 if (ftl_sparebuffer[0].meta.usn != ftl_vfl_cxt[bank].updatecount)
566 continue;
567 if (ftl_sparebuffer[0].meta.field_8 == 0
568 && ftl_sparebuffer[0].meta.type == 0x80) good++;
570 return good > 3 ? 0 : 1;
572 #endif
575 #ifndef FTL_READONLY
576 /* Commits the VFL context of the specified bank to flash,
577 retries until it works or all available pages have been tried */
578 static uint32_t ftl_vfl_commit_cxt(uint32_t bank)
580 if (ftl_vfl_cxt[bank].nextcxtpage + 8 <= ftl_nand_type->pagesperblock)
581 if (ftl_vfl_store_cxt(bank) == 0) return 0;
582 uint32_t current = ftl_vfl_cxt[bank].activecxtblock;
583 uint32_t i = current, j;
584 while (1)
586 i = (i + 1) & 3;
587 if (i == current) break;
588 if (ftl_vfl_cxt[bank].vflcxtblocks[i] == 0xFFFF) continue;
589 for (j = 0; j < 4; j++)
590 if (nand_block_erase(bank, ftl_vfl_cxt[bank].vflcxtblocks[i]
591 * ftl_nand_type->pagesperblock) == 0)
592 break;
593 if (j == 4) continue;
594 ftl_vfl_cxt[bank].activecxtblock = i;
595 ftl_vfl_cxt[bank].nextcxtpage = 0;
596 if (ftl_vfl_store_cxt(bank) == 0) return 0;
598 panicf("FTL: Failed to commit VFL CXT!");
599 return 1;
601 #endif
604 /* Returns a pointer to the most recently updated VFL context,
605 used to find out the current FTL context vBlock numbers
606 (planetbeing's "maxthing") */
607 static struct ftl_vfl_cxt_type* ftl_vfl_get_newest_cxt(void)
609 uint32_t i, maxusn;
610 struct ftl_vfl_cxt_type* cxt = (struct ftl_vfl_cxt_type*)0;
611 maxusn = 0;
612 for (i = 0; i < ftl_banks; i++)
613 if (ftl_vfl_cxt[i].usn >= maxusn)
615 cxt = &ftl_vfl_cxt[i];
616 maxusn = ftl_vfl_cxt[i].usn;
618 return cxt;
622 /* Checks if the specified pBlock is marked bad in the supplied lowlevel BBT.
623 Only used while mounting the VFL. */
624 static uint32_t ftl_is_good_block(uint8_t* bbt, uint32_t block)
626 if ((bbt[block >> 3] & (1 << (block & 7))) == 0) return 0;
627 else return 1;
631 /* Checks if the specified vBlock could be remapped */
632 static uint32_t ftl_vfl_is_good_block(uint32_t bank, uint32_t block)
634 uint8_t bbtentry = ftl_vfl_cxt[bank].bbt[block >> 6];
635 if ((bbtentry & (1 << ((7 - (block >> 3)) & 7))) == 0) return 0;
636 else return 1;
640 #ifndef FTL_READONLY
641 /* Sets or unsets the bad bit of the specified vBlock
642 in the specified bank's VFL context */
643 static void ftl_vfl_set_good_block(uint32_t bank, uint32_t block, uint32_t isgood)
645 uint8_t bit = (1 << ((7 - (block >> 3)) & 7));
646 if (isgood == 1) ftl_vfl_cxt[bank].bbt[block >> 6] |= bit;
647 else ftl_vfl_cxt[bank].bbt[block >> 6] &= ~bit;
649 #endif
652 /* Tries to read a VFL context from the specified bank, pBlock and page */
653 static uint32_t ftl_vfl_read_page(uint32_t bank, uint32_t block,
654 uint32_t startpage, void* databuffer,
655 union ftl_spare_data_type* sparebuffer)
657 uint32_t i;
658 for (i = 0; i < 8; i++)
660 uint32_t page = block * ftl_nand_type->pagesperblock
661 + startpage + i;
662 if ((nand_read_page(bank, page, databuffer,
663 sparebuffer, 1, 1) & 0x11F) == 0)
664 if (sparebuffer->meta.field_8 == 0
665 && sparebuffer->meta.type == 0x80)
666 return 0;
668 return 1;
672 /* Translates a bank and vBlock to a pBlock, following remaps */
673 static uint32_t ftl_vfl_get_physical_block(uint32_t bank, uint32_t block)
675 if (ftl_vfl_is_good_block(bank, block) == 1) return block;
677 uint32_t spareindex;
678 uint32_t spareused = ftl_vfl_cxt[bank].spareused;
679 for (spareindex = 0; spareindex < spareused; spareindex++)
680 if (ftl_vfl_cxt[bank].remaptable[spareindex] == block)
681 return ftl_vfl_cxt[bank].firstspare + spareindex;
682 return block;
686 #ifndef FTL_READONLY
687 /* Checks if remapping is scheduled for the specified bank and vBlock */
688 static uint32_t ftl_vfl_check_remap_scheduled(uint32_t bank, uint32_t block)
690 uint32_t i;
691 for (i = 0x333; i > 0 && i > ftl_vfl_cxt[bank].scheduledstart; i--)
692 if (ftl_vfl_cxt[bank].remaptable[i] == block) return 1;
693 return 0;
695 #endif
698 #ifndef FTL_READONLY
699 /* Schedules remapping for the specified bank and vBlock */
700 static void ftl_vfl_schedule_block_for_remap(uint32_t bank, uint32_t block)
702 if (ftl_vfl_check_remap_scheduled(bank, block) == 1)
703 return;
704 panicf("FTL: Scheduling bank %u block %u for remap!", (unsigned)bank, (unsigned)block);
705 if (ftl_vfl_cxt[bank].scheduledstart == ftl_vfl_cxt[bank].spareused)
706 return;
707 ftl_vfl_cxt[bank].remaptable[--ftl_vfl_cxt[bank].scheduledstart] = block;
708 ftl_vfl_commit_cxt(bank);
710 #endif
713 #ifndef FTL_READONLY
714 /* Removes the specified bank and vBlock combination
715 from the remap scheduled list */
716 static void ftl_vfl_mark_remap_done(uint32_t bank, uint32_t block)
718 uint32_t i;
719 uint32_t start = ftl_vfl_cxt[bank].scheduledstart;
720 uint32_t lastscheduled = ftl_vfl_cxt[bank].remaptable[start];
721 for (i = 0x333; i > 0 && i > start; i--)
722 if (ftl_vfl_cxt[bank].remaptable[i] == block)
724 if (i != start && i != 0x333)
725 ftl_vfl_cxt[bank].remaptable[i] = lastscheduled;
726 ftl_vfl_cxt[bank].scheduledstart++;
727 return;
730 #endif
733 #ifndef FTL_READONLY
734 /* Logs that there is trouble for the specified vBlock on the specified bank.
735 The vBlock will be scheduled for remap
736 if there is too much trouble with it. */
737 static void ftl_vfl_log_trouble(uint32_t bank, uint32_t vblock)
739 uint32_t i;
740 for (i = 0; i < 5; i++)
741 if (ftl_troublelog[i].block == vblock
742 && ftl_troublelog[i].bank == bank)
744 ftl_troublelog[i].errors += 3;
745 if (ftl_troublelog[i].errors > 5)
747 ftl_vfl_schedule_block_for_remap(bank, vblock);
748 ftl_troublelog[i].block = 0xFFFF;
750 return;
752 for (i = 0; i < 5; i++)
753 if (ftl_troublelog[i].block == 0xFFFF)
755 ftl_troublelog[i].block = vblock;
756 ftl_troublelog[i].bank = bank;
757 ftl_troublelog[i].errors = 3;
758 return;
761 #endif
764 #ifndef FTL_READONLY
765 /* Logs a successful erase for the specified vBlock on the specified bank */
766 static void ftl_vfl_log_success(uint32_t bank, uint32_t vblock)
768 uint32_t i;
769 for (i = 0; i < 5; i++)
770 if (ftl_troublelog[i].block == vblock
771 && ftl_troublelog[i].bank == bank)
773 if (--ftl_troublelog[i].errors == 0)
774 ftl_troublelog[i].block = 0xFFFF;
775 return;
778 #endif
781 #ifndef FTL_READONLY
782 /* Tries to remap the specified vBlock on the specified bank,
783 not caring about data in there.
784 If it worked, it will return the new pBlock number,
785 if not (no more spare blocks available), it will return zero. */
786 static uint32_t ftl_vfl_remap_block(uint32_t bank, uint32_t block)
788 uint32_t i;
789 uint32_t newblock = 0, newidx;
790 panicf("FTL: Remapping bank %u block %u!", (unsigned)bank, (unsigned)block);
791 if (bank >= ftl_banks || block >= ftl_nand_type->blocks) return 0;
792 for (i = 0; i < ftl_vfl_cxt[bank].sparecount; i++)
793 if (ftl_vfl_cxt[bank].remaptable[i] == 0)
795 newblock = ftl_vfl_cxt[bank].firstspare + i;
796 newidx = i;
797 break;
799 if (newblock == 0) return 0;
800 for (i = 0; i < 9; i++)
801 if (nand_block_erase(bank,
802 newblock * ftl_nand_type->pagesperblock) == 0)
803 break;
804 for (i = 0; i < newidx; i++)
805 if (ftl_vfl_cxt[bank].remaptable[i] == block)
806 ftl_vfl_cxt[bank].remaptable[i] = 0xFFFF;
807 ftl_vfl_cxt[bank].remaptable[newidx] = block;
808 ftl_vfl_cxt[bank].spareused++;
809 ftl_vfl_set_good_block(bank, block, 0);
810 return newblock;
812 #endif
815 /* Reads the specified vPage, dealing with all kinds of trouble */
816 static uint32_t ftl_vfl_read(uint32_t vpage, void* buffer, void* sparebuffer,
817 uint32_t checkempty, uint32_t remaponfail)
819 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
820 uint32_t syshyperblocks = ftl_nand_type->blocks
821 - ftl_nand_type->userblocks - 0x17;
822 uint32_t abspage = vpage + ppb * syshyperblocks;
823 if (abspage >= ftl_nand_type->blocks * ppb || abspage < ppb)
824 panicf("FTL: Trying to read out-of-bounds vPage %u", (unsigned)vpage);
825 //return 4;
827 uint32_t bank = abspage % ftl_banks;
828 uint32_t block = abspage / (ftl_nand_type->pagesperblock * ftl_banks);
829 uint32_t page = (abspage / ftl_banks) % ftl_nand_type->pagesperblock;
830 uint32_t physblock = ftl_vfl_get_physical_block(bank, block);
831 uint32_t physpage = physblock * ftl_nand_type->pagesperblock + page;
833 uint32_t ret = nand_read_page(bank, physpage, buffer,
834 sparebuffer, 1, checkempty);
836 if ((ret & 0x11D) != 0 && (ret & 2) == 0)
838 nand_reset(bank);
839 ret = nand_read_page(bank, physpage, buffer,
840 sparebuffer, 1, checkempty);
841 #ifdef FTL_READONLY
842 (void)remaponfail;
843 #else
844 if (remaponfail == 1 &&(ret & 0x11D) != 0 && (ret & 2) == 0)
845 ftl_vfl_schedule_block_for_remap(bank, block);
846 #endif
847 return ret;
850 return ret;
854 /* Multi-bank version of ftl_vfl_read, will read ftl_banks pages in parallel */
855 static uint32_t ftl_vfl_read_fast(uint32_t vpage, void* buffer, void* sparebuffer,
856 uint32_t checkempty, uint32_t remaponfail)
858 uint32_t i, rc = 0;
859 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
860 uint32_t syshyperblocks = ftl_nand_type->blocks
861 - ftl_nand_type->userblocks - 0x17;
862 uint32_t abspage = vpage + ppb * syshyperblocks;
863 if (abspage + ftl_banks - 1 >= ftl_nand_type->blocks * ppb || abspage < ppb)
864 panicf("FTL: Trying to read out-of-bounds vPage %u", (unsigned)vpage);
865 //return 4;
867 uint32_t bank = abspage % ftl_banks;
868 uint32_t block = abspage / (ftl_nand_type->pagesperblock * ftl_banks);
869 uint32_t page = (abspage / ftl_banks) % ftl_nand_type->pagesperblock;
870 uint32_t remapped = 0;
871 for (i = 0; i < ftl_banks; i++)
872 if (ftl_vfl_get_physical_block(i, block) != block)
873 remapped = 1;
874 if (bank || remapped)
876 for (i = 0; i < ftl_banks; i++)
878 void* databuf = (void*)0;
879 void* sparebuf = (void*)0;
880 if (buffer) databuf = (void*)((uint32_t)buffer + 0x800 * i);
881 if (sparebuffer) sparebuf = (void*)((uint32_t)sparebuffer + 0x40 * i);
882 uint32_t ret = ftl_vfl_read(vpage + i, databuf, sparebuf, checkempty, remaponfail);
883 if (ret & 1) rc |= 1 << (i << 2);
884 if (ret & 2) rc |= 2 << (i << 2);
885 if (ret & 0x10) rc |= 4 << (i << 2);
886 if (ret & 0x100) rc |= 8 << (i << 2);
888 return rc;
890 uint32_t physpage = block * ftl_nand_type->pagesperblock + page;
892 rc = nand_read_page_fast(physpage, buffer, sparebuffer, 1, checkempty);
893 if (!(rc & 0xdddd)) return rc;
895 for (i = 0; i < ftl_banks; i++)
897 if ((rc >> (i << 2)) & 0x2) continue;
898 if ((rc >> (i << 2)) & 0xd)
900 rc &= ~(0xf << (i << 2));
901 nand_reset(i);
902 uint32_t ret = nand_read_page(i, physpage,
903 (void*)((uint32_t)buffer + 0x800 * i),
904 (void*)((uint32_t)sparebuffer + 0x40 * i),
905 1, checkempty);
906 #ifdef FTL_READONLY
907 (void)remaponfail;
908 #else
909 if (remaponfail == 1 && (ret & 0x11D) != 0 && (ret & 2) == 0)
910 ftl_vfl_schedule_block_for_remap(i, block);
911 #endif
912 if (ret & 1) rc |= 1 << (i << 2);
913 if (ret & 2) rc |= 2 << (i << 2);
914 if (ret & 0x10) rc |= 4 << (i << 2);
915 if (ret & 0x100) rc |= 8 << (i << 2);
919 return rc;
923 #ifndef FTL_READONLY
924 /* Writes the specified vPage, dealing with all kinds of trouble */
925 static uint32_t ftl_vfl_write(uint32_t vpage, uint32_t count,
926 void* buffer, void* sparebuffer)
928 uint32_t i, j;
929 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
930 uint32_t syshyperblocks = ftl_nand_type->blocks
931 - ftl_nand_type->userblocks - 0x17;
932 uint32_t abspage = vpage + ppb * syshyperblocks;
933 if (abspage + count > ftl_nand_type->blocks * ppb || abspage < ppb)
934 panicf("FTL: Trying to write out-of-bounds vPage %u",
935 (unsigned)vpage);
936 //return 4;
938 uint32_t bank[5];
939 uint32_t block[5];
940 uint32_t physpage[5];
942 for (i = 0; i < count; i++, abspage++)
944 for (j = ftl_banks; j > 0; j--)
946 bank[j] = bank[j - 1];
947 block[j] = block[j - 1];
948 physpage[j] = physpage[j - 1];
950 bank[0] = abspage % ftl_banks;
951 block[0] = abspage / (ftl_nand_type->pagesperblock * ftl_banks);
952 uint32_t page = (abspage / ftl_banks) % ftl_nand_type->pagesperblock;
953 uint32_t physblock = ftl_vfl_get_physical_block(bank[0], block[0]);
954 physpage[0] = physblock * ftl_nand_type->pagesperblock + page;
956 if (i >= ftl_banks)
957 if (nand_write_page_collect(bank[ftl_banks]))
958 if (nand_read_page(bank[ftl_banks], physpage[ftl_banks],
959 ftl_buffer, &ftl_sparebuffer[0], 1, 1) & 0x11F)
961 panicf("FTL: write error (2) on vPage %u, bank %u, pPage %u",
962 (unsigned)(vpage + i - ftl_banks),
963 (unsigned)bank[ftl_banks],
964 (unsigned)physpage[ftl_banks]);
965 ftl_vfl_log_trouble(bank[ftl_banks], block[ftl_banks]);
967 if (nand_write_page_start(bank[0], physpage[0],
968 (void*)((uint32_t)buffer + 0x800 * i),
969 (void*)((uint32_t)sparebuffer + 0x40 * i), 1))
970 if (nand_read_page(bank[0], physpage[0], ftl_buffer,
971 &ftl_sparebuffer[0], 1, 1) & 0x11F)
973 panicf("FTL: write error (1) on vPage %u, bank %u, pPage %u",
974 (unsigned)(vpage + i), (unsigned)bank[0], (unsigned)physpage[0]);
975 ftl_vfl_log_trouble(bank[0], block[0]);
979 for (i = count < ftl_banks ? count : ftl_banks; i > 0; i--)
980 if (nand_write_page_collect(bank[i - 1]))
981 if (nand_read_page(bank[i - 1], physpage[i - 1],
982 ftl_buffer, &ftl_sparebuffer[0], 1, 1) & 0x11F)
984 panicf("FTL: write error (2) on vPage %u, bank %u, pPage %u",
985 (unsigned)(vpage + count - i),
986 (unsigned)bank[i - 1], (unsigned)physpage[i - 1]);
987 ftl_vfl_log_trouble(bank[i - 1], block[i - 1]);
990 return 0;
992 #endif
995 /* Mounts the VFL on all banks */
996 static uint32_t ftl_vfl_open(void)
998 uint32_t i, j, k;
999 uint32_t minusn, vflcxtidx, last;
1000 FTLVFLCxtType* cxt;
1001 uint16_t vflcxtblock[4];
1002 #ifndef FTL_READONLY
1003 ftl_vfl_usn = 0;
1004 #else
1005 /* Temporary BBT buffer if we're readonly,
1006 as we won't need it again after mounting */
1007 uint8_t bbt[0x410];
1008 #endif
1010 uint32_t syshyperblocks = ftl_nand_type->blocks
1011 - ftl_nand_type->userblocks - 0x18;
1013 for (i = 0; i < ftl_banks; i++)
1014 #ifndef FTL_READONLY
1015 if (ftl_load_bbt(i, ftl_bbt[i]) == 0)
1016 #else
1017 if (ftl_load_bbt(i, bbt) == 0)
1018 #endif
1020 for (j = 1; j <= syshyperblocks; j++)
1021 #ifndef FTL_READONLY
1022 if (ftl_is_good_block(ftl_bbt[i], j) != 0)
1023 #else
1024 if (ftl_is_good_block(bbt, j) != 0)
1025 #endif
1026 if (ftl_vfl_read_page(i, j, 0, ftl_buffer,
1027 &ftl_sparebuffer[0]) == 0)
1029 struct ftl_vfl_cxt_type* cxt;
1030 cxt = (struct ftl_vfl_cxt_type*)ftl_buffer;
1031 memcpy(vflcxtblock, &cxt->vflcxtblocks, 8);
1032 minusn = 0xFFFFFFFF;
1033 vflcxtidx = 4;
1034 for (k = 0; k < 4; k++)
1035 if (vflcxtblock[k] != 0xFFFF)
1036 if (ftl_vfl_read_page(i, vflcxtblock[k], 0,
1037 ftl_buffer,
1038 &ftl_sparebuffer[0]) == 0)
1039 if (ftl_sparebuffer[0].meta.usn > 0
1040 && ftl_sparebuffer[0].meta.usn <= minusn)
1042 minusn = ftl_sparebuffer[0].meta.usn;
1043 vflcxtidx = k;
1045 if (vflcxtidx == 4) //return 1;
1046 panicf("FTL: No VFL CXT block found on bank %u!",
1047 (unsigned)i);
1048 last = 0;
1049 uint32_t max = ftl_nand_type->pagesperblock;
1050 for (k = 8; k < max; k += 8)
1052 if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx],
1053 k, ftl_buffer,
1054 &ftl_sparebuffer[0]) != 0)
1055 break;
1056 last = k;
1058 if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx],
1059 last, ftl_buffer,
1060 &ftl_sparebuffer[0]) != 0)
1061 panicf("FTL: Re-reading VFL CXT block "
1062 "on bank %u failed!?", (unsigned)i);
1063 //return 1;
1064 memcpy(&ftl_vfl_cxt[i], ftl_buffer, 0x800);
1065 if (ftl_vfl_verify_checksum(i) != 0) return 1;
1066 #ifndef FTL_READONLY
1067 if (ftl_vfl_usn < ftl_vfl_cxt[i].usn)
1068 ftl_vfl_usn = ftl_vfl_cxt[i].usn;
1069 #endif
1070 break;
1073 else //return 1;
1074 panicf("FTL: Couldn't load bank %u lowlevel BBT!", (unsigned)i);
1075 cxt = ftl_vfl_get_newest_cxt();
1076 for (i = 0; i < ftl_banks; i++)
1077 memcpy(ftl_vfl_cxt[i].ftlctrlblocks, cxt->ftlctrlblocks, 6);
1078 return 0;
1082 /* Mounts the actual FTL */
1083 static uint32_t ftl_open(void)
1085 uint32_t i;
1086 uint32_t ret;
1087 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1088 struct ftl_vfl_cxt_type* cxt = ftl_vfl_get_newest_cxt();
1090 uint32_t ftlcxtblock = 0xffffffff;
1091 uint32_t minusn = 0xffffffff;
1092 for (i = 0; i < 3; i++)
1094 ret = ftl_vfl_read(ppb * cxt->ftlctrlblocks[i],
1095 ftl_buffer, &ftl_sparebuffer[0], 1, 0);
1096 if ((ret &= 0x11F) != 0) continue;
1097 if (ftl_sparebuffer[0].meta.type - 0x43 > 4) continue;
1098 if (ftlcxtblock != 0xffffffff && ftl_sparebuffer[0].meta.usn >= minusn)
1099 continue;
1100 minusn = ftl_sparebuffer[0].meta.usn;
1101 ftlcxtblock = cxt->ftlctrlblocks[i];
1104 if (ftlcxtblock == 0xffffffff) //return 1;
1105 panicf("FTL: Couldn't find readable FTL CXT block!");
1107 uint32_t ftlcxtfound = 0;
1108 for (i = ftl_nand_type->pagesperblock * ftl_banks - 1; i > 0; i--)
1110 ret = ftl_vfl_read(ppb * ftlcxtblock + i,
1111 ftl_buffer, &ftl_sparebuffer[0], 1, 0);
1112 if ((ret & 0x11F) != 0) continue;
1113 else if (ftl_sparebuffer[0].meta.type == 0x43)
1115 memcpy(&ftl_cxt, ftl_buffer, 0x28C);
1116 ftlcxtfound = 1;
1117 break;
1119 else
1121 /* This will trip if there was an unclean unmount before. */
1122 #ifndef FTL_FORCEMOUNT
1123 panicf("FTL: Unclean shutdown before!");
1124 break;
1125 #endif
1129 if (ftlcxtfound == 0) //return 1;
1130 panicf("FTL: Couldn't find FTL CXT page!");
1132 uint32_t pagestoread = ftl_nand_type->userblocks >> 10;
1133 if ((ftl_nand_type->userblocks & 0x1FF) != 0) pagestoread++;
1135 for (i = 0; i < pagestoread; i++)
1137 if ((ftl_vfl_read(ftl_cxt.ftl_map_pages[i],
1138 ftl_buffer, &ftl_sparebuffer[0], 1, 1) & 0x11F) != 0)
1139 panicf("FTL: Failed to read block map page %u", (unsigned)i);
1140 //return 1;
1142 uint32_t toread = 2048;
1143 if (toread > (ftl_nand_type->userblocks << 1) - (i << 11))
1144 toread = (ftl_nand_type->userblocks << 1) - (i << 11);
1146 memcpy(&ftl_map[i << 10], ftl_buffer, toread);
1149 #ifndef FTL_READONLY
1150 pagestoread = (ftl_nand_type->userblocks + 23) >> 10;
1151 if (((ftl_nand_type->userblocks + 23) & 0x1FF) != 0) pagestoread++;
1153 for (i = 0; i < pagestoread; i++)
1155 if ((ftl_vfl_read(ftl_cxt.ftl_erasectr_pages[i],
1156 ftl_buffer, &ftl_sparebuffer[0], 1, 1) & 0x11F) != 0)
1157 panicf("FTL: Failed to read erase counter page %u", (unsigned)i);
1158 //return 1;
1160 uint32_t toread = 2048;
1161 if (toread > ((ftl_nand_type->userblocks + 23) << 1) - (i << 11))
1162 toread = ((ftl_nand_type->userblocks + 23) << 1) - (i << 11);
1164 memcpy(&ftl_erasectr[i << 10], ftl_buffer, toread);
1167 for (i = 0; i < 0x11; i++)
1169 ftl_log[i].scatteredvblock = 0xFFFF;
1170 ftl_log[i].logicalvblock = 0xFFFF;
1171 ftl_log[i].pageoffsets = ftl_offsets[i];
1174 memset(ftl_troublelog, 0xFF, 20);
1175 memset(ftl_erasectr_dirt, 0, 8);
1176 #endif
1178 return 0;
1182 #ifndef FTL_READONLY
1183 /* Returns a pointer to the ftl_log entry for the specified vBlock,
1184 or null, if there is none */
1185 static struct ftl_log_type* ftl_get_log_entry(uint32_t block)
1187 uint32_t i;
1188 for (i = 0; i < 0x11; i++)
1190 if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
1191 if (ftl_log[i].logicalvblock == block) return &ftl_log[i];
1193 return (struct ftl_log_type*)0;
1195 #endif
1197 /* Exposed function: Read highlevel sectors */
1198 uint32_t ftl_read(uint32_t sector, uint32_t count, void* buffer)
1200 uint32_t i, j;
1201 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1202 uint32_t error = 0;
1204 if (sector + count > ftl_nand_type->userblocks * ppb)
1205 return 1;
1207 if (count == 0) return 0;
1209 mutex_lock(&ftl_mtx);
1211 for (i = 0; i < count; i++)
1213 uint32_t block = (sector + i) / ppb;
1214 uint32_t page = (sector + i) % ppb;
1216 uint32_t abspage = ftl_map[block] * ppb + page;
1217 #ifndef FTL_READONLY
1218 struct ftl_log_type* logentry = ftl_get_log_entry(block);
1219 if (logentry != (struct ftl_log_type*)0)
1220 if (logentry->scatteredvblock != 0xFFFF
1221 && logentry->pageoffsets[page] != 0xFFFF)
1222 abspage = logentry->scatteredvblock * ppb
1223 + logentry->pageoffsets[page];
1224 #endif
1226 #ifndef FTL_READONLY
1227 if (count >= i + ftl_banks && !(page & (ftl_banks - 1))
1228 && logentry == (struct ftl_log_type*)0)
1229 #else
1230 if (count >= i + ftl_banks && !(page & (ftl_banks - 1)))
1231 #endif
1233 uint32_t ret = ftl_vfl_read_fast(abspage, &((uint8_t*)buffer)[i << 11],
1234 &ftl_sparebuffer[0], 1, 1);
1235 for (j = 0; j < ftl_banks; j++)
1236 if (ret & (2 << (j << 2)))
1237 memset(&((uint8_t*)buffer)[(i + j) << 11], 0, 0x800);
1238 else if ((ret & (0xd << (j << 2))) || ftl_sparebuffer[j].user.eccmark != 0xFF)
1240 error = 1;
1241 memset(&((uint8_t*)buffer)[(i + j) << 11], 0, 0x800);
1243 i += ftl_banks - 1;
1245 else
1247 uint32_t ret = ftl_vfl_read(abspage, &((uint8_t*)buffer)[i << 11],
1248 &ftl_sparebuffer[0], 1, 1);
1249 if (ret & 2) memset(&((uint8_t*)buffer)[i << 11], 0, 0x800);
1250 else if ((ret & 0x11D) != 0 || ftl_sparebuffer[0].user.eccmark != 0xFF)
1252 error = 1;
1253 memset(&((uint8_t*)buffer)[i << 11], 0, 0x800);
1258 mutex_unlock(&ftl_mtx);
1260 return error;
1264 #ifndef FTL_READONLY
1265 /* Performs a vBlock erase, dealing with hardware,
1266 remapping and all kinds of trouble */
1267 static uint32_t ftl_erase_block_internal(uint32_t block)
1269 uint32_t i, j;
1270 block = block + ftl_nand_type->blocks
1271 - ftl_nand_type->userblocks - 0x17;
1272 if (block == 0 || block >= ftl_nand_type->blocks) return 1;
1273 for (i = 0; i < ftl_banks; i++)
1275 if (ftl_vfl_check_remap_scheduled(i, block) == 1)
1277 ftl_vfl_remap_block(i, block);
1278 ftl_vfl_mark_remap_done(i, block);
1280 ftl_vfl_log_success(i, block);
1281 uint32_t pblock = ftl_vfl_get_physical_block(i, block);
1282 uint32_t rc;
1283 for (j = 0; j < 3; j++)
1285 rc = nand_block_erase(i, pblock * ftl_nand_type->pagesperblock);
1286 if (rc == 0) break;
1288 if (rc != 0)
1290 panicf("FTL: Block erase failed on bank %u block %u",
1291 (unsigned)i, (unsigned)block);
1292 if (pblock != block)
1294 uint32_t spareindex = pblock - ftl_vfl_cxt[i].firstspare;
1295 ftl_vfl_cxt[i].remaptable[spareindex] = 0xFFFF;
1297 ftl_vfl_cxt[i].field_18++;
1298 if (ftl_vfl_remap_block(i, block) == 0) return 1;
1299 if (ftl_vfl_commit_cxt(i) != 0) return 1;
1300 memset(&ftl_sparebuffer, 0, 0x40);
1301 nand_write_page(i, pblock, &ftl_vfl_cxt[0], &ftl_sparebuffer, 1);
1304 return 0;
1306 #endif
1309 #ifndef FTL_READONLY
1310 /* Highlevel vBlock erase, that increments the erase counter for the block */
1311 static uint32_t ftl_erase_block(uint32_t block)
1313 ftl_erasectr[block]++;
1314 if (ftl_erasectr_dirt[block >> 10] == 100) ftl_cxt.erasedirty = 1;
1315 else ftl_erasectr_dirt[block >> 10]++;
1316 return ftl_erase_block_internal(block);
1318 #endif
1321 #ifndef FTL_READONLY
1322 /* Allocates a block from the pool,
1323 returning its vBlock number, or 0xFFFFFFFF on error */
1324 static uint32_t ftl_allocate_pool_block(void)
1326 uint32_t i;
1327 uint32_t erasectr = 0xFFFFFFFF, bestidx = 0xFFFFFFFF, block;
1328 for (i = 0; i < ftl_cxt.freecount; i++)
1330 uint32_t idx = ftl_cxt.nextfreeidx + i;
1331 if (idx >= 0x14) idx -= 0x14;
1332 if (!ftl_cxt.blockpool[idx]) continue;
1333 if (ftl_erasectr[ftl_cxt.blockpool[idx]] < erasectr)
1335 erasectr = ftl_erasectr[ftl_cxt.blockpool[idx]];
1336 bestidx = idx;
1339 if (bestidx == 0xFFFFFFFF) panicf("Out of pool blocks!");
1340 block = ftl_cxt.blockpool[bestidx];
1341 if (bestidx != ftl_cxt.nextfreeidx)
1343 ftl_cxt.blockpool[bestidx] = ftl_cxt.blockpool[ftl_cxt.nextfreeidx];
1344 ftl_cxt.blockpool[ftl_cxt.nextfreeidx] = block;
1346 if (block > (uint32_t)ftl_nand_type->userblocks + 0x17)
1347 panicf("FTL: Bad block number in pool: %u", (unsigned)block);
1348 if (ftl_erase_block(block) != 0) return 0xFFFFFFFF;
1349 if (++ftl_cxt.nextfreeidx == 0x14) ftl_cxt.nextfreeidx = 0;
1350 ftl_cxt.freecount--;
1351 return block;
1353 #endif
1356 #ifndef FTL_READONLY
1357 /* Releases a vBlock back into the pool */
1358 static void ftl_release_pool_block(uint32_t block)
1360 if (block >= (uint32_t)ftl_nand_type->userblocks + 0x17)
1361 panicf("FTL: Tried to release block %u", (unsigned)block);
1362 uint32_t idx = ftl_cxt.nextfreeidx + ftl_cxt.freecount++;
1363 if (idx >= 0x14) idx -= 0x14;
1364 ftl_cxt.blockpool[idx] = block;
1366 #endif
1369 #ifndef FTL_READONLY
1370 /* Commits the location of the FTL context blocks
1371 to a semi-randomly chosen VFL context */
1372 static uint32_t ftl_store_ctrl_block_list(void)
1374 uint32_t i;
1375 for (i = 0; i < ftl_banks; i++)
1376 memcpy(ftl_vfl_cxt[i].ftlctrlblocks, ftl_cxt.ftlctrlblocks, 6);
1377 return ftl_vfl_commit_cxt(ftl_vfl_usn % ftl_banks);
1379 #endif
1382 #ifndef FTL_READONLY
1383 /* Saves the n-th erase counter page to the flash,
1384 because it is too dirty or needs to be moved. */
1385 static uint32_t ftl_save_erasectr_page(uint32_t index)
1387 memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1388 ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1389 ftl_sparebuffer[0].meta.idx = index;
1390 ftl_sparebuffer[0].meta.type = 0x46;
1391 if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, &ftl_erasectr[index << 10],
1392 &ftl_sparebuffer[0]) != 0)
1393 return 1;
1394 if ((ftl_vfl_read(ftl_cxt.ftlctrlpage, ftl_buffer,
1395 &ftl_sparebuffer[0], 1, 1) & 0x11F) != 0)
1396 return 1;
1397 if (memcmp(ftl_buffer, &ftl_erasectr[index << 10], 0x800) != 0) return 1;
1398 if (ftl_sparebuffer[0].meta.type != 0x46) return 1;
1399 if (ftl_sparebuffer[0].meta.idx != index) return 1;
1400 if (ftl_sparebuffer[0].meta.usn != ftl_cxt.usn) return 1;
1401 ftl_cxt.ftl_erasectr_pages[index] = ftl_cxt.ftlctrlpage;
1402 ftl_erasectr_dirt[index] = 0;
1403 return 0;
1405 #endif
1408 #ifndef FTL_READONLY
1409 /* Increments ftl_cxt.ftlctrlpage to the next available FTL context page,
1410 allocating a new context block if neccessary. */
1411 static uint32_t ftl_next_ctrl_pool_page(void)
1413 uint32_t i;
1414 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1415 if (++ftl_cxt.ftlctrlpage % ppb != 0) return 0;
1416 for (i = 0; i < 3; i++)
1417 if ((ftl_cxt.ftlctrlblocks[i] + 1) * ppb == ftl_cxt.ftlctrlpage)
1418 break;
1419 i = (i + 1) % 3;
1420 uint32_t oldblock = ftl_cxt.ftlctrlblocks[i];
1421 uint32_t newblock = ftl_allocate_pool_block();
1422 if (newblock == 0xFFFFFFFF) return 1;
1423 ftl_cxt.ftlctrlblocks[i] = newblock;
1424 ftl_cxt.ftlctrlpage = newblock * ppb;
1425 uint32_t pagestoread = (ftl_nand_type->userblocks + 23) >> 10;
1426 if (((ftl_nand_type->userblocks + 23) & 0x1FF) != 0) pagestoread++;
1427 for (i = 0; i < pagestoread; i++)
1428 if (oldblock * ppb <= ftl_cxt.ftl_erasectr_pages[i]
1429 && (oldblock + 1) * ppb > ftl_cxt.ftl_erasectr_pages[i])
1431 ftl_cxt.usn--;
1432 if (ftl_save_erasectr_page(i) != 0)
1434 ftl_cxt.ftlctrlblocks[i] = oldblock;
1435 ftl_cxt.ftlctrlpage = oldblock * (ppb + 1) - 1;
1436 ftl_release_pool_block(newblock);
1437 return 1;
1439 ftl_cxt.ftlctrlpage++;
1441 ftl_release_pool_block(oldblock);
1442 return ftl_store_ctrl_block_list();
1444 #endif
1447 #ifndef FTL_READONLY
1448 /* Copies a vPage from one location to another */
1449 static uint32_t ftl_copy_page(uint32_t source, uint32_t destination,
1450 uint32_t lpn, uint32_t type)
1452 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1453 uint32_t rc = ftl_vfl_read(source, ftl_copybuffer[0],
1454 &ftl_copyspare[0], 1, 1) & 0x11F;
1455 memset(&ftl_copyspare[0], 0xFF, 0x40);
1456 ftl_copyspare[0].user.lpn = lpn;
1457 ftl_copyspare[0].user.usn = ++ftl_cxt.nextblockusn;
1458 ftl_copyspare[0].user.type = 0x40;
1459 if ((rc & 2) != 0) memset(ftl_copybuffer[0], 0, 0x800);
1460 else if (rc != 0) ftl_copyspare[0].user.eccmark = 0x55;
1461 if (type == 1 && destination % ppb == ppb - 1)
1462 ftl_copyspare[0].user.type = 0x41;
1463 return ftl_vfl_write(destination, 1, ftl_copybuffer[0], &ftl_copyspare[0]);
1465 #endif
1468 #ifndef FTL_READONLY
1469 /* Copies a pBlock to a vBlock */
1470 static uint32_t ftl_copy_block(uint32_t source, uint32_t destination)
1472 uint32_t i, j;
1473 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1474 uint32_t error = 0;
1475 ftl_cxt.nextblockusn++;
1476 for (i = 0; i < ppb; i += FTL_COPYBUF_SIZE)
1478 uint32_t rc = ftl_read(source * ppb + i,
1479 FTL_COPYBUF_SIZE, ftl_copybuffer[0]);
1480 memset(&ftl_copyspare[0], 0xFF, 0x40 * FTL_COPYBUF_SIZE);
1481 for (j = 0; j < FTL_COPYBUF_SIZE; j++)
1483 ftl_copyspare[j].user.lpn = source * ppb + i + j;
1484 ftl_copyspare[j].user.usn = ftl_cxt.nextblockusn;
1485 ftl_copyspare[j].user.type = 0x40;
1486 if (rc)
1488 if (ftl_read(source * ppb + i + j, 1, ftl_copybuffer[j]))
1489 ftl_copyspare[j].user.eccmark = 0x55;
1491 if (i + j == ppb - 1) ftl_copyspare[j].user.type = 0x41;
1493 if (ftl_vfl_write(destination * ppb + i, FTL_COPYBUF_SIZE,
1494 ftl_copybuffer[0], &ftl_copyspare[0]))
1496 error = 1;
1497 break;
1500 if (error != 0)
1502 ftl_erase_block(destination);
1503 return 1;
1505 return 0;
1507 #endif
1510 #ifndef FTL_READONLY
1511 /* Clears ftl_log.issequential, if something violating that is written. */
1512 static void ftl_check_still_sequential(struct ftl_log_type* entry, uint32_t page)
1514 if (entry->pagesused != entry->pagescurrent
1515 || entry->pageoffsets[page] != page)
1516 entry->issequential = 0;
1518 #endif
1521 #ifndef FTL_READONLY
1522 /* Copies all pages that are currently used from the scattered page block in
1523 use by the supplied ftl_log entry to a newly-allocated one, and releases
1524 the old one.
1525 In other words: It kicks the pages containing old garbage out of it to make
1526 space again. This is usually done when a scattered page block is being
1527 removed because it is full, but less than half of the pages in there are
1528 still in use and rest is just filled with old crap. */
1529 static uint32_t ftl_compact_scattered(struct ftl_log_type* entry)
1531 uint32_t i, j;
1532 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1533 uint32_t error;
1534 struct ftl_log_type backup;
1535 if (entry->pagescurrent == 0)
1537 ftl_release_pool_block(entry->scatteredvblock);
1538 entry->scatteredvblock = 0xFFFF;
1539 return 0;
1541 backup = *entry;
1542 memcpy(ftl_offsets_backup, entry->pageoffsets, 0x400);
1543 for (i = 0; i < 4; i++)
1545 uint32_t block = ftl_allocate_pool_block();
1546 if (block == 0xFFFFFFFF) return 1;
1547 entry->pagesused = 0;
1548 entry->pagescurrent = 0;
1549 entry->issequential = 1;
1550 entry->scatteredvblock = block;
1551 error = 0;
1552 for (j = 0; j < ppb; j++)
1553 if (entry->pageoffsets[j] != 0xFFFF)
1555 uint32_t lpn = entry->logicalvblock * ppb + j;
1556 uint32_t newpage = block * ppb + entry->pagesused;
1557 uint32_t oldpage = backup.scatteredvblock * ppb
1558 + entry->pageoffsets[j];
1559 if (ftl_copy_page(oldpage, newpage, lpn,
1560 entry->issequential) != 0)
1562 error = 1;
1563 break;
1565 entry->pageoffsets[j] = entry->pagesused++;
1566 entry->pagescurrent++;
1567 ftl_check_still_sequential(entry, j);
1569 if (backup.pagescurrent != entry->pagescurrent) error = 1;
1570 if (error == 0)
1572 ftl_release_pool_block(backup.scatteredvblock);
1573 break;
1575 *entry = backup;
1576 memcpy(entry->pageoffsets, ftl_offsets_backup, 0x400);
1578 return error;
1580 #endif
1583 #ifndef FTL_READONLY
1584 /* Commits an ftl_log entry to proper blocks, no matter what's in there. */
1585 static uint32_t ftl_commit_scattered(struct ftl_log_type* entry)
1587 uint32_t i;
1588 uint32_t error;
1589 uint32_t block;
1590 for (i = 0; i < 4; i++)
1592 block = ftl_allocate_pool_block();
1593 if (block == 0xFFFFFFFF) return 1;
1594 error = ftl_copy_block(entry->logicalvblock, block);
1595 if (error == 0) break;
1596 ftl_release_pool_block(block);
1598 if (error != 0) return 1;
1599 ftl_release_pool_block(entry->scatteredvblock);
1600 entry->scatteredvblock = 0xFFFF;
1601 ftl_release_pool_block(ftl_map[entry->logicalvblock]);
1602 ftl_map[entry->logicalvblock] = block;
1603 return 0;
1605 #endif
1608 #ifndef FTL_READONLY
1609 /* Fills the rest of a scattered page block that was actually written
1610 sequentially until now, in order to be able to save a block erase by
1611 committing it without needing to copy it again.
1612 If this fails for whichever reason, it will be committed the usual way. */
1613 static uint32_t ftl_commit_sequential(struct ftl_log_type* entry)
1615 uint32_t i;
1616 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1618 if (entry->issequential != 1
1619 || entry->pagescurrent != entry->pagesused)
1620 return 1;
1622 for (; entry->pagesused < ppb; )
1624 uint32_t lpn = entry->logicalvblock * ppb + entry->pagesused;
1625 uint32_t newpage = entry->scatteredvblock * ppb
1626 + entry->pagesused;
1627 uint32_t count = FTL_COPYBUF_SIZE < ppb - entry->pagesused
1628 ? FTL_COPYBUF_SIZE : ppb - entry->pagesused;
1629 for (i = 0; i < count; i++)
1630 if (entry->pageoffsets[entry->pagesused + i] != 0xFFFF)
1631 return ftl_commit_scattered(entry);
1632 uint32_t rc = ftl_read(lpn, count, ftl_copybuffer[0]);
1633 memset(&ftl_copyspare[0], 0xFF, 0x40 * FTL_COPYBUF_SIZE);
1634 for (i = 0; i < count; i++)
1636 ftl_copyspare[i].user.lpn = lpn + i;
1637 ftl_copyspare[i].user.usn = ++ftl_cxt.nextblockusn;
1638 ftl_copyspare[i].user.type = 0x40;
1639 if (rc) ftl_copyspare[i].user.eccmark = 0x55;
1640 if (entry->pagesused + i == ppb - 1)
1641 ftl_copyspare[i].user.type = 0x41;
1643 if (ftl_vfl_write(newpage, count, ftl_copybuffer[0], &ftl_copyspare[0]))
1644 return ftl_commit_scattered(entry);
1645 entry->pagesused += count;
1647 ftl_release_pool_block(ftl_map[entry->logicalvblock]);
1648 ftl_map[entry->logicalvblock] = entry->scatteredvblock;
1649 entry->scatteredvblock = 0xFFFF;
1650 return 0;
1652 #endif
1655 #ifndef FTL_READONLY
1656 /* If a log entry is supplied, its scattered page block will be removed in
1657 whatever way seems most appropriate. Else, the oldest scattered page block
1658 will be freed by committing it. */
1659 static uint32_t ftl_remove_scattered_block(struct ftl_log_type* entry)
1661 uint32_t i;
1662 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1663 uint32_t age = 0xFFFFFFFF, used = 0;
1664 if (entry == (struct ftl_log_type*)0)
1666 for (i = 0; i < 0x11; i++)
1668 if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
1669 if (ftl_log[i].pagesused == 0 || ftl_log[i].pagescurrent == 0)
1670 return 1;
1671 if (ftl_log[i].usn < age
1672 || (ftl_log[i].usn == age && ftl_log[i].pagescurrent > used))
1674 age = ftl_log[i].usn;
1675 used = ftl_log[i].pagescurrent;
1676 entry = &ftl_log[i];
1679 if (entry == (struct ftl_log_type*)0) return 1;
1681 else if (entry->pagescurrent < ppb / 2)
1683 ftl_cxt.swapcounter++;
1684 return ftl_compact_scattered(entry);
1686 ftl_cxt.swapcounter++;
1687 if (entry->issequential == 1) return ftl_commit_sequential(entry);
1688 else return ftl_commit_scattered(entry);
1690 #endif
1693 #ifndef FTL_READONLY
1694 /* Initialize a log entry to the values for an empty scattered page block */
1695 static void ftl_init_log_entry(struct ftl_log_type* entry)
1697 entry->issequential = 1;
1698 entry->pagescurrent = 0;
1699 entry->pagesused = 0;
1700 memset(entry->pageoffsets, 0xFF, 0x400);
1702 #endif
1705 #ifndef FTL_READONLY
1706 /* Allocates a log entry for the specified vBlock,
1707 first making space, if neccessary. */
1708 static struct ftl_log_type* ftl_allocate_log_entry(uint32_t block)
1710 uint32_t i;
1711 struct ftl_log_type* entry = ftl_get_log_entry(block);
1712 entry->usn = ftl_cxt.nextblockusn - 1;
1713 if (entry != (struct ftl_log_type*)0) return entry;
1715 for (i = 0; i < 0x11; i++)
1717 if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
1718 if (ftl_log[i].pagesused == 0)
1720 entry = &ftl_log[i];
1721 break;
1725 if (entry == (struct ftl_log_type*)0)
1727 if (ftl_cxt.freecount < 3) panicf("FTL: Detected a pool block leak!");
1728 else if (ftl_cxt.freecount == 3)
1729 if (ftl_remove_scattered_block((struct ftl_log_type*)0) != 0)
1730 return (struct ftl_log_type*)0;
1731 entry = ftl_log;
1732 while (entry->scatteredvblock != 0xFFFF) entry = &entry[1];
1733 entry->scatteredvblock = ftl_allocate_pool_block();
1734 if (entry->scatteredvblock == 0xFFFF)
1735 return (struct ftl_log_type*)0;
1738 ftl_init_log_entry(entry);
1739 entry->logicalvblock = block;
1740 entry->usn = ftl_cxt.nextblockusn - 1;
1742 return entry;
1744 #endif
1747 #ifndef FTL_READONLY
1748 /* Commits the FTL block map, erase counters, and context to flash */
1749 static uint32_t ftl_commit_cxt(void)
1751 uint32_t i;
1752 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1753 uint32_t mappages = (ftl_nand_type->userblocks + 0x3ff) >> 10;
1754 uint32_t ctrpages = (ftl_nand_type->userblocks + 23 + 0x3ff) >> 10;
1755 uint32_t endpage = ftl_cxt.ftlctrlpage + mappages + ctrpages + 1;
1756 if (endpage >= (ftl_cxt.ftlctrlpage / ppb + 1) * ppb)
1757 ftl_cxt.ftlctrlpage |= ppb - 1;
1758 for (i = 0; i < ctrpages; i++)
1760 if (ftl_next_ctrl_pool_page() != 0) return 1;
1761 if (ftl_save_erasectr_page(i) != 0) return 1;
1763 for (i = 0; i < mappages; i++)
1765 if (ftl_next_ctrl_pool_page() != 0) return 1;
1766 memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1767 ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1768 ftl_sparebuffer[0].meta.idx = i;
1769 ftl_sparebuffer[0].meta.type = 0x44;
1770 if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, &ftl_map[i << 10],
1771 &ftl_sparebuffer[0]) != 0)
1772 return 1;
1773 ftl_cxt.ftl_map_pages[i] = ftl_cxt.ftlctrlpage;
1775 if (ftl_next_ctrl_pool_page() != 0) return 1;
1776 ftl_cxt.clean_flag = 1;
1777 memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1778 ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1779 ftl_sparebuffer[0].meta.type = 0x43;
1780 if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, &ftl_cxt, &ftl_sparebuffer[0]) != 0)
1781 return 1;
1782 return 0;
1784 #endif
1787 #ifndef FTL_READONLY
1788 /* Swaps the most and least worn block on the flash,
1789 to better distribute wear. It will refuse to do anything
1790 if the wear spread is lower than 5 erases. */
1791 static uint32_t ftl_swap_blocks(void)
1793 uint32_t i;
1794 uint32_t min = 0xFFFFFFFF, max = 0, maxidx = 0x14;
1795 uint32_t minidx = 0, minvb = 0, maxvb = 0;
1796 for (i = 0; i < ftl_cxt.freecount; i++)
1798 uint32_t idx = ftl_cxt.nextfreeidx + i;
1799 if (idx >= 0x14) idx -= 0x14;
1800 if (ftl_erasectr[ftl_cxt.blockpool[idx]] > max)
1802 maxidx = idx;
1803 maxvb = ftl_cxt.blockpool[idx];
1804 max = ftl_erasectr[maxidx];
1807 if (maxidx == 0x14) return 0;
1808 for (i = 0; i < ftl_nand_type->userblocks; i++)
1810 if (ftl_erasectr[ftl_map[i]] > max) max = ftl_erasectr[ftl_map[i]];
1811 if (ftl_get_log_entry(i) != (struct ftl_log_type*)0) continue;
1812 if (ftl_erasectr[ftl_map[i]] < min)
1814 minidx = i;
1815 minvb = ftl_map[i];
1816 min = ftl_erasectr[minidx];
1819 if (max - min < 5) return 0;
1820 if (minvb == maxvb) return 0;
1821 if (ftl_erase_block(maxvb) != 0) return 1;
1822 if (ftl_copy_block(minidx, maxvb) != 0) return 1;
1823 ftl_cxt.blockpool[maxidx] = minvb;
1824 ftl_map[minidx] = maxvb;
1825 return 0;
1827 #endif
1830 #ifndef FTL_READONLY
1831 /* Exposed function: Write highlevel sectors */
1832 uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer)
1834 uint32_t i, j, k;
1835 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1837 if (sector + count > ftl_nand_type->userblocks * ppb)
1838 return 1;
1840 if (count == 0) return 0;
1842 mutex_lock(&ftl_mtx);
1844 if (ftl_cxt.clean_flag == 1)
1846 for (i = 0; i < 3; i++)
1848 if (ftl_next_ctrl_pool_page() != 0)
1850 mutex_unlock(&ftl_mtx);
1851 return 1;
1853 memset(ftl_buffer, 0xFF, 0x800);
1854 memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1855 ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1856 ftl_sparebuffer[0].meta.type = 0x47;
1857 if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, ftl_buffer,
1858 &ftl_sparebuffer[0]) == 0)
1859 break;
1861 if (i == 3)
1863 mutex_unlock(&ftl_mtx);
1864 return 1;
1866 ftl_cxt.clean_flag = 0;
1869 for (i = 0; i < count; )
1871 uint32_t block = (sector + i) / ppb;
1872 uint32_t page = (sector + i) % ppb;
1874 struct ftl_log_type* logentry = ftl_allocate_log_entry(block);
1875 if (logentry == (struct ftl_log_type*)0)
1877 mutex_unlock(&ftl_mtx);
1878 return 1;
1880 if (page == 0 && count - i >= ppb)
1882 uint32_t vblock = logentry->scatteredvblock;
1883 logentry->scatteredvblock = 0xFFFF;
1884 if (logentry->pagesused != 0)
1886 ftl_release_pool_block(vblock);
1887 vblock = ftl_allocate_pool_block();
1888 if (vblock == 0xFFFFFFFF)
1890 mutex_unlock(&ftl_mtx);
1891 return 1;
1894 ftl_cxt.nextblockusn++;
1895 for (j = 0; j < ppb; j += FTL_WRITESPARE_SIZE)
1897 memset(&ftl_sparebuffer[0], 0xFF, 0x40 * FTL_WRITESPARE_SIZE);
1898 for (k = 0; k < FTL_WRITESPARE_SIZE; k++)
1900 ftl_sparebuffer[k].user.lpn = sector + i + j + k;
1901 ftl_sparebuffer[k].user.usn = ftl_cxt.nextblockusn;
1902 ftl_sparebuffer[k].user.type = 0x40;
1903 if (j == ppb - 1) ftl_sparebuffer[k].user.type = 0x41;
1905 uint32_t rc = ftl_vfl_write(vblock * ppb + j, FTL_WRITESPARE_SIZE,
1906 &((uint8_t*)buffer)[(i + j) << 11],
1907 &ftl_sparebuffer[0]);
1908 if (rc)
1909 for (k = 0; k < ftl_banks; k++)
1910 if (rc & (1 << k))
1912 while (ftl_vfl_write(vblock * ppb + j + k, 1,
1913 &((uint8_t*)buffer)[(i + j + k) << 11],
1914 &ftl_sparebuffer[k]));
1917 ftl_release_pool_block(ftl_map[block]);
1918 ftl_map[block] = vblock;
1919 i += ppb;
1921 else
1923 if (logentry->pagesused == ppb)
1925 ftl_remove_scattered_block(logentry);
1926 logentry = ftl_allocate_log_entry(block);
1927 if (logentry == (struct ftl_log_type*)0)
1929 mutex_unlock(&ftl_mtx);
1930 return 1;
1933 uint32_t cnt = FTL_WRITESPARE_SIZE;
1934 if (cnt > count - i) cnt = count - i;
1935 if (cnt > ppb - logentry->pagesused) cnt = ppb - logentry->pagesused;
1936 if (cnt > ppb - page) cnt = ppb - page;
1937 memset(&ftl_sparebuffer[0], 0xFF, 0x40 * cnt);
1938 for (j = 0; j < cnt; j++)
1940 ftl_sparebuffer[j].user.lpn = sector + i + j;
1941 ftl_sparebuffer[j].user.usn = ++ftl_cxt.nextblockusn;
1942 ftl_sparebuffer[j].user.type = 0x40;
1943 if (logentry->pagesused + j == ppb - 1 && logentry->issequential)
1944 ftl_sparebuffer[j].user.type = 0x41;
1946 uint32_t abspage = logentry->scatteredvblock * ppb
1947 + logentry->pagesused;
1948 logentry->pagesused += cnt;
1949 if (ftl_vfl_write(abspage, cnt, &((uint8_t*)buffer)[i << 11],
1950 &ftl_sparebuffer[0]) == 0)
1952 for (j = 0; j < cnt; j++)
1954 if (logentry->pageoffsets[page + j] == 0xFFFF)
1955 logentry->pagescurrent++;
1956 logentry->pageoffsets[page + j] = logentry->pagesused - cnt + j;
1957 if (logentry->pagesused - cnt + j + 1 != logentry->pagescurrent
1958 || logentry->pageoffsets[page + j] != page + j)
1959 logentry->issequential = 0;
1961 i += cnt;
1963 else panicf("FTL: Write error: %u %u %u!",
1964 (unsigned)sector, (unsigned)count, (unsigned)i);
1966 if (logentry->pagesused == ppb) ftl_remove_scattered_block(logentry);
1968 if (ftl_cxt.swapcounter >= 300)
1970 ftl_cxt.swapcounter -= 20;
1971 for (i = 0; i < 4; i++) if (ftl_swap_blocks() == 0) break;
1973 if (ftl_cxt.erasedirty == 1)
1975 ftl_cxt.erasedirty = 0;
1976 for (i = 0; i < 8; i++)
1977 if (ftl_erasectr_dirt[i] >= 100)
1979 ftl_next_ctrl_pool_page();
1980 ftl_save_erasectr_page(i);
1983 mutex_unlock(&ftl_mtx);
1984 return 0;
1986 #endif
1989 #ifndef FTL_READONLY
1990 /* Exposed function: Performes a sync / unmount,
1991 i.e. commits all scattered page blocks,
1992 distributes wear, and commits the FTL context. */
1993 uint32_t ftl_sync(void)
1995 uint32_t i;
1996 uint32_t rc = 0;
1997 uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1998 if (ftl_cxt.clean_flag == 1) return 0;
2000 mutex_lock(&ftl_mtx);
2002 if (ftl_cxt.swapcounter >= 20)
2003 for (i = 0; i < 4; i++)
2004 if (ftl_swap_blocks() == 0)
2006 ftl_cxt.swapcounter -= 20;
2007 break;
2009 for (i = 0; i < 0x11; i++)
2011 if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
2012 ftl_cxt.nextblockusn++;
2013 if (ftl_log[i].issequential == 1)
2014 rc |= ftl_commit_sequential(&ftl_log[i]);
2015 else rc |= ftl_commit_scattered(&ftl_log[i]);
2017 if (rc != 0)
2019 mutex_unlock(&ftl_mtx);
2020 return 1;
2022 for (i = 0; i < 5; i++)
2023 if (ftl_commit_cxt() == 0)
2025 mutex_unlock(&ftl_mtx);
2026 return 0;
2028 else ftl_cxt.ftlctrlpage |= ppb - 1;
2029 mutex_unlock(&ftl_mtx);
2030 return 1;
2032 #endif
2035 /* Initializes and mounts the FTL.
2036 As long as nothing was written, you won't need to unmount it.
2037 Before shutting down after writing something, call ftl_sync(),
2038 which will just do nothing if everything was already clean. */
2039 uint32_t ftl_init(void)
2041 mutex_init(&ftl_mtx);
2042 uint32_t i;
2043 uint32_t result = 0;
2044 uint32_t foundsignature, founddevinfo, blockwiped, repaired, skip;
2045 if (nand_device_init() != 0) //return 1;
2046 panicf("FTL: Lowlevel NAND driver init failed!");
2047 ftl_banks = 0;
2048 for (i = 0; i < 4; i++)
2049 if (nand_get_device_type(i) != 0) ftl_banks = i + 1;
2050 ftl_nand_type = nand_get_device_type(0);
2051 foundsignature = 0;
2052 blockwiped = 1;
2053 mutex_unlock(&ftl_mtx);
2054 for (i = 0; i < ftl_nand_type->pagesperblock; i++)
2056 result = nand_read_page(0, i, ftl_buffer, (uint32_t*)0, 1, 1);
2057 if ((result & 0x11F) == 0)
2059 blockwiped = 0;
2060 if (((uint32_t*)ftl_buffer)[0] != 0x41303034) continue;
2061 foundsignature = 1;
2062 break;
2064 else if ((result & 2) != 2) blockwiped = 0;
2067 founddevinfo = ftl_has_devinfo();
2069 repaired = 0;
2070 skip = 0;
2071 if (founddevinfo == 0)
2073 mutex_unlock(&ftl_mtx);
2074 panicf("FTL: No DEVICEINFO found!");
2075 //return 1;
2077 if (foundsignature != 0 && (result & 0x11F) != 0)
2079 mutex_unlock(&ftl_mtx);
2080 panicf("FTL: Problem with the signature!");
2081 //return 1;
2083 if (ftl_vfl_open() == 0)
2084 if (ftl_open() == 0)
2086 mutex_unlock(&ftl_mtx);
2087 return 0;
2090 panicf("FTL: Initialization failed!");
2092 /* Something went terribly wrong. We may want to allow the user to erase
2093 block zero in that condition, to make norboot reinitialize the FTL.
2094 (However there is curently no point in this, as iLoader would already
2095 fail if this would be the case.)
2097 nand_block_erase(0, 0);
2101 mutex_unlock(&ftl_mtx);
2102 return 1;