Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 theseven 1
//
2
//
3
//    Copyright 2010 TheSeven
4
//
5
//
6
//    This file is part of emBIOS.
7
//
8
//    emBIOS is free software: you can redistribute it and/or
9
//    modify it under the terms of the GNU General Public License as
10
//    published by the Free Software Foundation, either version 2 of the
11
//    License, or (at your option) any later version.
12
//
13
//    emBIOS is distributed in the hope that it will be useful,
14
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
//    See the GNU General Public License for more details.
17
//
18
//    You should have received a copy of the GNU General Public License along
19
//    with emBIOS.  If not, see <http://www.gnu.org/licenses/>.
20
//
21
//
22
 
23
 
24
 
25
#include "global.h"
26
#include "nand.h"
54 theseven 27
#include "ftl.h"
2 theseven 28
#include "util.h"
54 theseven 29
#include "thread.h"
30
#include "panic.h"
31
#include "debug.h"
124 theseven 32
#include "console.h"
33
#include "progressbar.h"
34
#include "lcdconsole.h"
2 theseven 35
 
36
 
37
 
54 theseven 38
#define FTL_COPYBUF_SIZE 4
39
#define FTL_WRITESPARE_SIZE 32
2 theseven 40
//#define FTL_FORCEMOUNT
41
 
42
 
43
 
44
#ifdef FTL_FORCEMOUNT
45
#ifndef FTL_READONLY
46
#define FTL_READONLY
47
#endif
48
#endif
49
 
50
 
51
#ifdef FTL_READONLY
54 theseven 52
uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer)
2 theseven 53
{
54
    (void)sector;
55
    (void)count;
56
    (void)buffer;
57
    return -1;
58
}
54 theseven 59
uint32_t ftl_sync(void)
2 theseven 60
{
61
    return 0;
62
}
63
#endif
64
 
65
 
66
 
67
/* Keeps the state of a scattered page block.
68
   This structure is used in memory only, not on flash,
69
   but it equals the one the OFW uses. */
70
struct ftl_log_type
71
{
72
 
73
    /* The ftl_cxt.nextblockusn at the time the block was allocated,
74
       needed in order to be able to remove the oldest ones first. */
75
    uint32_t usn;
76
 
77
    /* The vBlock number at which the scattered pages are stored */
78
    uint16_t scatteredvblock;
79
 
80
    /* the lBlock number for which those pages are */
81
    uint16_t logicalvblock;
82
 
83
    /* Pointer to ftl_offsets, contains the mapping which lPage is
84
       currently stored at which scattered vPage. */
85
    uint16_t* pageoffsets;
86
 
87
    /* Pages used in the vBlock, i.e. next page number to be written */
88
    uint16_t pagesused;
89
 
90
    /* Pages that are still up to date in this block, i.e. need to be
91
       moved when this vBlock is deallocated. */
92
    uint16_t pagescurrent;
93
 
94
    /* A flag whether all pages are still sequential in this block.
95
       Initialized to 1 on allocation, zeroed as soon as anything is
96
       written out of sequence, so that the block will need copying
97
       when committing to get the pages back into the right order.
98
       This is used to half the number of block erases needed when
99
       writing huge amounts of sequential data. */
100
    uint32_t issequential;
101
 
102
} __attribute__((packed));
103
 
104
 
105
/* Keeps the state of the FTL, both on flash and in memory */
106
struct ftl_cxt_type
107
{
108
 
109
    /* Update sequence number of the FTL context, decremented
110
       every time a new revision of FTL meta data is written. */
111
    uint32_t usn;
112
 
113
    /* Update sequence number for user data blocks. Incremented
114
       every time a portion of user pages is written, so that
115
       a consistency check can determine which copy of a user
116
       page is the most recent one. */
117
    uint32_t nextblockusn;
118
 
119
    /* Count of currently free pages in the block pool */
120
    uint16_t freecount;
121
 
54 theseven 122
    /* Index to the first free hyperblock in the blockpool ring buffer */
2 theseven 123
    uint16_t nextfreeidx;
124
 
125
    /* This is a counter that is used to better distribute block
126
       wear. It is incremented on every block erase, and if it
127
       gets too high (300 on writes, 20 on sync), the most and
54 theseven 128
       least worn hyperblock will be swapped (causing an additional
2 theseven 129
       block write) and the counter will be decreased by 20. */
130
    uint16_t swapcounter;
131
 
54 theseven 132
    /* Ring buffer of currently free hyperblocks. nextfreeidx is the
2 theseven 133
       index to freecount free ones, the other ones are currently
54 theseven 134
       allocated for scattered page hyperblocks. */
2 theseven 135
    uint16_t blockpool[0x14];
136
 
137
    /* Alignment to 32 bits */
138
    uint16_t field_36;
139
 
140
    /* vPages where the block map is stored */
141
    uint32_t ftl_map_pages[8];
142
 
143
    /* Probably additional map page number space for bigger chips */
144
    uint8_t field_58[0x28];
145
 
146
    /* vPages where the erase counters are stored */
147
    uint32_t ftl_erasectr_pages[8];
148
 
149
    /* Seems to be padding */
150
    uint8_t field_A0[0x70];
151
 
152
    /* Pointer to ftl_map used by Whimory, not used by us */
153
    uint32_t ftl_map_ptr;
154
 
155
    /* Pointer to ftl_erasectr used by Whimory, not used by us */
156
    uint32_t ftl_erasectr_ptr;
157
 
158
    /* Pointer to ftl_log used by Whimory, not used by us */
159
    uint32_t ftl_log_ptr;
160
 
161
    /* Flag used to indicate that some erase counter pages should be committed
54 theseven 162
       because they were changed more than 100 times since the last commit. */
2 theseven 163
    uint32_t erasedirty;
164
 
165
    /* Seems to be unused */
166
    uint16_t field_120;
167
 
168
    /* vBlocks used to store the FTL context, map, and erase
169
       counter pages. This is also a ring buffer, and the oldest
170
       page gets swapped with the least used page from the block
171
       pool ring buffer when a new one is allocated. */
172
    uint16_t ftlctrlblocks[3];
173
 
174
    /* The last used vPage number from ftlctrlblocks */
175
    uint32_t ftlctrlpage;
176
 
177
    /* Set on context sync, reset on write, so obviously never
178
       zero in the context written to the flash */
179
    uint32_t clean_flag;
180
 
181
    /* Seems to be unused, but gets loaded from flash by Whimory. */
182
    uint8_t field_130[0x15C];
183
 
184
} __attribute__((packed));
185
 
186
 
187
/* Keeps the state of the bank's VFL, both on flash and in memory.
188
   There is one of these per bank. */
189
struct ftl_vfl_cxt_type
190
{
191
 
192
    /* Cross-bank update sequence number, incremented on every VFL
193
       context commit on any bank. */
194
    uint32_t usn;
195
 
196
    /* See ftl_cxt.ftlctrlblocks. This is stored to the VFL contexts
197
       in order to be able to find the most recent FTL context copy
198
       when mounting the FTL. The VFL context number this will be
199
       written to on an FTL context commit is chosen semi-randomly. */
200
    uint16_t ftlctrlblocks[3];
201
 
202
    /* Alignment to 32 bits */
203
    uint8_t field_A[2];
204
 
205
    /* Decrementing update counter for VFL context commits per bank */
206
    uint32_t updatecount;
207
 
208
    /* Number of the currently active VFL context block, it's an index
209
       into vflcxtblocks. */
210
    uint16_t activecxtblock;
211
 
54 theseven 212
    /* Number of the first free page in the active VFL context block */
2 theseven 213
    uint16_t nextcxtpage;
214
 
215
    /* Seems to be unused */
216
    uint8_t field_14[4];
217
 
218
    /* Incremented every time a block erase error leads to a remap,
219
       but doesn't seem to be read anywhere. */
220
    uint16_t field_18;
221
 
222
    /* Number of spare blocks used */
223
    uint16_t spareused;
224
 
225
    /* pBlock number of the first spare block */
226
    uint16_t firstspare;
227
 
228
    /* Total number of spare blocks */
229
    uint16_t sparecount;
230
 
231
    /* Block remap table. Contains the vBlock number the n-th spare
232
       block is used as a replacement for. 0 = unused, 0xFFFF = bad. */
233
    uint16_t remaptable[0x334];
234
 
235
    /* Bad block table. Each bit represents 8 blocks. 1 = OK, 0 = Bad.
236
       If the entry is zero, you should look at the remap table to see
237
       if the block is remapped, and if yes, where the replacement is. */
238
    uint8_t bbt[0x11A];
239
 
240
    /* pBlock numbers used to store the VFL context. This is a ring
241
       buffer. On a VFL context write, always 8 pages are written,
242
       and it passes if at least 4 of them can be read back. */
243
    uint16_t vflcxtblocks[4];
244
 
245
    /* Blocks scheduled for remapping are stored at the end of the
246
       remap table. This is the first index used for them. */
247
    uint16_t scheduledstart;
248
 
249
    /* Probably padding */
250
    uint8_t field_7AC[0x4C];
251
 
252
    /* First checksum (addition) */
253
    uint32_t checksum1;
254
 
255
    /* Second checksum (XOR), there is a bug in whimory regarding this. */
256
    uint32_t checksum2;
257
 
258
} __attribute__((packed));
259
 
260
 
261
/* Layout of the spare bytes of each page on the flash */
262
union ftl_spare_data_type
263
{
264
 
265
    /* The layout used for actual user data (types 0x40 and 0x41) */
266
    struct ftl_spare_data_user_type
267
    {
268
 
269
        /* The lPage, i.e. Sector, number */
270
        uint32_t lpn;
271
 
272
        /* The update sequence number of that page,
273
           copied from ftl_cxt.nextblockusn on write */
274
        uint32_t usn;
275
 
276
        /* Seems to be unused */
277
        uint8_t field_8;
278
 
279
        /* Type field, 0x40 (data page) or 0x41 (last data page of block) */
280
        uint8_t type;
281
 
282
        /* ECC mark, usually 0xFF. If an error occurred while reading the
283
           page during a copying operation earlier, this will be 0x55. */
284
        uint8_t eccmark;
285
 
286
        /* Seems to be unused */
287
        uint8_t field_B;
288
 
289
        /* ECC data for the user data */
290
        uint8_t dataecc[0x28];
291
 
292
        /* ECC data for the first 0xC bytes above */
293
        uint8_t spareecc[0xC];
294
 
295
    } __attribute__((packed)) user;
296
 
297
    /* The layout used for meta data (other types) */
298
    struct ftl_spare_data_meta_type
299
    {
300
 
301
        /* ftl_cxt.usn for FTL stuff, ftl_vfl_cxt.updatecount for VFL stuff */
302
        uint32_t usn;
303
 
304
        /* Index of the thing inside the page,
305
           for example number / index of the map or erase counter page */
306
        uint16_t idx;
307
 
308
        /* Seems to be unused */
309
        uint8_t field_6;
310
 
311
        /* Seems to be unused */
312
        uint8_t field_7;
313
 
314
        /* Seems to be unused */
315
        uint8_t field_8;
316
 
317
       /* Type field:
318
            0x43: FTL context page
319
            0x44: Block map page
320
            0x46: Erase counter page
321
            0x47: "FTL is currently mounted", i.e. unclean shutdown, mark
322
            0x80: VFL context page */
323
        uint8_t type;
324
 
325
        /* ECC mark, usually 0xFF. If an error occurred while reading the
326
           page during a copying operation earlier, this will be 0x55. */
327
        uint8_t eccmark;
328
 
329
        /* Seems to be unused */
330
        uint8_t field_B;
331
 
332
        /* ECC data for the user data */
333
        uint8_t dataecc[0x28];
334
 
335
        /* ECC data for the first 0xC bytes above */
336
        uint8_t spareecc[0xC];
337
 
338
    } __attribute__((packed)) meta;
339
 
340
};
341
 
342
 
343
/* Keeps track of troublesome blocks, only in memory, lost on unmount. */
344
struct ftl_trouble_type
345
{
346
 
347
    /* vBlock number of the block giving trouble */
348
    uint16_t block;
349
 
350
    /* Bank of the block giving trouble */
351
    uint8_t bank;
352
 
353
    /* Error counter, incremented by 3 on error, decremented by 1 on erase,
354
       remaping will be done when it reaches 6. */
355
    uint8_t errors;
356
 
357
} __attribute__((packed));
358
 
359
 
360
 
361
/* Pointer to an info structure regarding the flash type used */
362
const struct nand_device_info_type* ftl_nand_type;
363
 
364
/* Number of banks we detected a chip on */
365
uint32_t ftl_banks;
366
 
367
/* Block map, used vor pBlock to vBlock mapping */
124 theseven 368
static uint16_t ftl_map[0x2000] CACHEALIGN_ATTR;
2 theseven 369
 
370
/* VFL context for each bank */
66 theseven 371
static struct ftl_vfl_cxt_type ftl_vfl_cxt[4];
2 theseven 372
 
373
/* FTL context */
124 theseven 374
static struct ftl_cxt_type ftl_cxt CACHEALIGN_ATTR;
2 theseven 375
 
376
/* Temporary data buffers for internal use by the FTL */
66 theseven 377
static uint8_t ftl_buffer[0x800] CACHEALIGN_ATTR;
2 theseven 378
 
379
/* Temporary spare byte buffer for internal use by the FTL */
66 theseven 380
static union ftl_spare_data_type ftl_sparebuffer[FTL_WRITESPARE_SIZE] CACHEALIGN_ATTR;
2 theseven 381
 
382
 
383
#ifndef FTL_READONLY
384
 
385
/* Lowlevel BBT for each bank */
66 theseven 386
static uint8_t ftl_bbt[4][0x410];
2 theseven 387
 
54 theseven 388
/* Erase counters for the vBlocks */
124 theseven 389
static uint16_t ftl_erasectr[0x2000] CACHEALIGN_ATTR;
2 theseven 390
 
391
/* Used by ftl_log */
66 theseven 392
static uint16_t ftl_offsets[0x11][0x200];
2 theseven 393
 
394
/* Structs keeping record of scattered page blocks */
66 theseven 395
static struct ftl_log_type ftl_log[0x11];
2 theseven 396
 
397
/* Global cross-bank update sequence number of the VFL context */
66 theseven 398
static uint32_t ftl_vfl_usn;
2 theseven 399
 
400
/* Keeps track (temporarily) of troublesome blocks */
66 theseven 401
static struct ftl_trouble_type ftl_troublelog[5];
2 theseven 402
 
403
/* Counts erase counter page changes, after 100 of them the affected
404
   page will be committed to the flash. */
66 theseven 405
static uint8_t ftl_erasectr_dirt[8];
2 theseven 406
 
407
/* Buffer needed for copying pages around while moving or committing blocks.
408
   This can't be shared with ftl_buffer, because this one could be overwritten
409
   during the copying operation in order to e.g. commit a CXT. */
66 theseven 410
static uint8_t ftl_copybuffer[FTL_COPYBUF_SIZE][0x800] CACHEALIGN_ATTR;
411
static union ftl_spare_data_type ftl_copyspare[FTL_COPYBUF_SIZE] CACHEALIGN_ATTR;
2 theseven 412
 
413
/* Needed to store the old scattered page offsets in order to be able to roll
414
   back if something fails while compacting a scattered page block. */
66 theseven 415
static uint16_t ftl_offsets_backup[0x200] CACHEALIGN_ATTR;
2 theseven 416
 
124 theseven 417
/* Buffers needed for FTL recovery */
418
static uint32_t blk_usn[0x2000] INITBSS_ATTR;
419
static uint8_t blk_type[0x2000] INITBSS_ATTR;
420
static uint32_t erasectr_usn[8] INITBSS_ATTR;
421
static uint32_t pageusn[0x200] INITBSS_ATTR;
422
static uint8_t pagedata[0x200][0x800] INITBSS_ATTR CACHEALIGN_ATTR;
423
 
424
/* State information needed for FTL recovery */
425
static uint32_t meta_usn INITBSS_ATTR;
426
static uint32_t user_usn INITBSS_ATTR;
427
static uint32_t allocmode INITBSS_ATTR;
428
static uint32_t firstfree INITBSS_ATTR;
429
 
2 theseven 430
#endif
431
 
432
 
54 theseven 433
static struct mutex ftl_mtx;
210 theseven 434
bool ftl_initialized = false;
2 theseven 435
 
436
 
437
 
438
/* Finds a device info page for the specified bank and returns its number.
439
   Used to check if one is present, and to read the lowlevel BBT. */
124 theseven 440
static uint32_t ftl_find_devinfo(uint32_t bank) INITCODE_ATTR;
66 theseven 441
static uint32_t ftl_find_devinfo(uint32_t bank)
2 theseven 442
{
443
    /* Scan the last 10% of the flash for device info pages */
54 theseven 444
    uint32_t lowestBlock = ftl_nand_type->blocks
445
                         - (ftl_nand_type->blocks / 10);
2 theseven 446
    uint32_t block, page, pagenum;
54 theseven 447
    for (block = ftl_nand_type->blocks - 1; block >= lowestBlock; block--)
2 theseven 448
    {
54 theseven 449
        page = ftl_nand_type->pagesperblock - 8;
450
        for (; page < ftl_nand_type->pagesperblock; page++)
2 theseven 451
        {
54 theseven 452
            pagenum = block * ftl_nand_type->pagesperblock + page;
2 theseven 453
            if ((nand_read_page(bank, pagenum, ftl_buffer,
54 theseven 454
                                &ftl_sparebuffer[0], 1, 0) & 0x11F) != 0)
2 theseven 455
                continue;
456
            if (memcmp(ftl_buffer, "DEVICEINFOSIGN\0", 0x10) == 0)
457
                return pagenum;
458
        }
459
    }
460
    return 0;
461
}
462
 
463
 
464
/* Checks if all banks have proper device info pages */
124 theseven 465
static uint32_t ftl_has_devinfo(void) INITCODE_ATTR;
66 theseven 466
static uint32_t ftl_has_devinfo(void)
2 theseven 467
{
468
    uint32_t i;
469
    for (i = 0; i < ftl_banks; i++) if (ftl_find_devinfo(i) == 0) return 0;
470
    return 1;
471
}
472
 
473
 
474
/* Loads the lowlevel BBT for a bank to the specified buffer.
475
   This is based on some cryptic disassembly and not fully understood yet. */
124 theseven 476
static uint32_t ftl_load_bbt(uint32_t bank, uint8_t* bbt) INITCODE_ATTR;
66 theseven 477
static uint32_t ftl_load_bbt(uint32_t bank, uint8_t* bbt)
2 theseven 478
{
479
    uint32_t i, j;
480
    uint32_t pagebase, page = ftl_find_devinfo(bank), page2;
481
    uint32_t unk1, unk2, unk3;
482
    if (page == 0) return 1;
54 theseven 483
    pagebase = page & ~(ftl_nand_type->pagesperblock - 1);
2 theseven 484
    if ((nand_read_page(bank, page, ftl_buffer,
166 theseven 485
                        NULL, 1, 0) & 0x11F) != 0) return 1;
2 theseven 486
    if (memcmp(&ftl_buffer[0x18], "BBT", 4) != 0) return 1;
487
    unk1 = ((uint16_t*)ftl_buffer)[0x10];
488
    unk2 = ((uint16_t*)ftl_buffer)[0x11];
54 theseven 489
    unk3 = ((uint16_t*)ftl_buffer)[((uint32_t*)ftl_buffer)[4] * 6 + 10]
490
         + ((uint16_t*)ftl_buffer)[((uint32_t*)ftl_buffer)[4] * 6 + 11];
2 theseven 491
    for (i = 0; i < unk1; i++)
492
    {
493
        for (j = 0; ; j++)
494
        {
495
            page2 = unk2 + i + unk3 * j;
54 theseven 496
            if (page2 >= (uint32_t)(ftl_nand_type->pagesperblock - 8))
2 theseven 497
                break;
498
            if ((nand_read_page(bank, pagebase + page2, ftl_buffer,
166 theseven 499
                                NULL, 1, 0) & 0x11F) == 0)
2 theseven 500
            {
501
                memcpy(bbt, ftl_buffer, 0x410);
502
                return 0;
503
            }
504
        }
505
    }
506
    return 1;
507
}
508
 
509
 
510
/* Calculates the checksums for the VFL context page of the specified bank */
66 theseven 511
static void ftl_vfl_calculate_checksum(uint32_t bank,
512
                                       uint32_t* checksum1, uint32_t* checksum2)
2 theseven 513
{
514
    uint32_t i;
515
    *checksum1 = 0xAABBCCDD;
516
    *checksum2 = 0xAABBCCDD;
517
    for (i = 0; i < 0x1FE; i++)
518
    {
519
        *checksum1 += ((uint32_t*)(&ftl_vfl_cxt[bank]))[i];
520
        *checksum2 ^= ((uint32_t*)(&ftl_vfl_cxt[bank]))[i];
521
    }
522
}
523
 
524
 
525
/* Checks if the checksums of the VFL context
526
   of the specified bank are correct */
66 theseven 527
static uint32_t ftl_vfl_verify_checksum(uint32_t bank)
2 theseven 528
{
529
    uint32_t checksum1, checksum2;
530
    ftl_vfl_calculate_checksum(bank, &checksum1, &checksum2);
531
    if (checksum1 == ftl_vfl_cxt[bank].checksum1) return 0;
532
    /* The following line is pretty obviously a bug in Whimory,
533
       but we do it the same way for compatibility. */
534
    if (checksum2 != ftl_vfl_cxt[bank].checksum2) return 0;
54 theseven 535
    DEBUGF("FTL: Bad VFL CXT checksum on bank %d!", bank);
2 theseven 536
    return 1;
537
}
538
 
539
 
540
#ifndef FTL_READONLY
541
/* Updates the checksums of the VFL context of the specified bank */
66 theseven 542
static void ftl_vfl_update_checksum(uint32_t bank)
2 theseven 543
{
544
    ftl_vfl_calculate_checksum(bank, &ftl_vfl_cxt[bank].checksum1,
545
                               &ftl_vfl_cxt[bank].checksum2);
546
}
547
#endif
548
 
549
 
550
#ifndef FTL_READONLY
551
/* Writes 8 copies of the VFL context of the specified bank to flash,
552
   and succeeds if at least 4 can be read back properly. */
66 theseven 553
static uint32_t ftl_vfl_store_cxt(uint32_t bank)
2 theseven 554
{
555
    uint32_t i;
556
    ftl_vfl_cxt[bank].updatecount--;
557
    ftl_vfl_cxt[bank].usn = ++ftl_vfl_usn;
558
    ftl_vfl_cxt[bank].nextcxtpage += 8;
559
    ftl_vfl_update_checksum(bank);
54 theseven 560
    memset(&ftl_sparebuffer[0], 0xFF, 0x40);
561
    ftl_sparebuffer[0].meta.usn = ftl_vfl_cxt[bank].updatecount;
562
    ftl_sparebuffer[0].meta.field_8 = 0;
563
    ftl_sparebuffer[0].meta.type = 0x80;
2 theseven 564
    for (i = 1; i <= 8; i++)
565
    {
566
        uint32_t index = ftl_vfl_cxt[bank].activecxtblock;
567
        uint32_t block = ftl_vfl_cxt[bank].vflcxtblocks[index];
54 theseven 568
        uint32_t page = block * ftl_nand_type->pagesperblock;
2 theseven 569
        page += ftl_vfl_cxt[bank].nextcxtpage - i;
54 theseven 570
        nand_write_page(bank, page, &ftl_vfl_cxt[bank], &ftl_sparebuffer[0], 1);
2 theseven 571
    }
572
    uint32_t good = 0;
54 theseven 573
    for (i = 1; i <= 8; i++)
2 theseven 574
    {
575
        uint32_t index = ftl_vfl_cxt[bank].activecxtblock;
576
        uint32_t block = ftl_vfl_cxt[bank].vflcxtblocks[index];
54 theseven 577
        uint32_t page = block * ftl_nand_type->pagesperblock;
2 theseven 578
        page += ftl_vfl_cxt[bank].nextcxtpage - i;
579
        if ((nand_read_page(bank, page, ftl_buffer,
54 theseven 580
                            &ftl_sparebuffer[0], 1, 0) & 0x11F) != 0)
2 theseven 581
            continue;
582
        if (memcmp(ftl_buffer, &ftl_vfl_cxt[bank], 0x7AC) != 0)
583
            continue;
54 theseven 584
        if (ftl_sparebuffer[0].meta.usn != ftl_vfl_cxt[bank].updatecount)
2 theseven 585
            continue;
54 theseven 586
        if (ftl_sparebuffer[0].meta.field_8 == 0
587
         && ftl_sparebuffer[0].meta.type == 0x80) good++;
2 theseven 588
    }
589
    return good > 3 ? 0 : 1;
590
}
591
#endif
592
 
593
 
594
#ifndef FTL_READONLY
595
/* Commits the VFL context of the specified bank to flash,
596
   retries until it works or all available pages have been tried */
66 theseven 597
static uint32_t ftl_vfl_commit_cxt(uint32_t bank)
2 theseven 598
{
61 theseven 599
    DEBUGF("FTL: VFL: Committing context on bank %d", bank);
54 theseven 600
    if (ftl_vfl_cxt[bank].nextcxtpage + 8 <= ftl_nand_type->pagesperblock)
2 theseven 601
        if (ftl_vfl_store_cxt(bank) == 0) return 0;
602
    uint32_t current = ftl_vfl_cxt[bank].activecxtblock;
603
    uint32_t i = current, j;
604
    while (1)
605
    {
606
        i = (i + 1) & 3;
607
        if (i == current) break;
608
        if (ftl_vfl_cxt[bank].vflcxtblocks[i] == 0xFFFF) continue;
609
        for (j = 0; j < 4; j++)
610
            if (nand_block_erase(bank, ftl_vfl_cxt[bank].vflcxtblocks[i]
54 theseven 611
                                     * ftl_nand_type->pagesperblock) == 0)
2 theseven 612
                break;
613
        if (j == 4) continue;
614
        ftl_vfl_cxt[bank].activecxtblock = i;
615
        ftl_vfl_cxt[bank].nextcxtpage = 0;
616
        if (ftl_vfl_store_cxt(bank) == 0) return 0;
617
    }
61 theseven 618
    panicf(PANIC_FATAL, "VFL: Failed to commit VFL CXT!");
2 theseven 619
    return 1;
620
}
621
#endif
622
 
623
 
624
/* Returns a pointer to the most recently updated VFL context,
625
   used to find out the current FTL context vBlock numbers
626
   (planetbeing's "maxthing") */
124 theseven 627
static struct ftl_vfl_cxt_type* ftl_vfl_get_newest_cxt(void) INITCODE_ATTR;
66 theseven 628
static struct ftl_vfl_cxt_type* ftl_vfl_get_newest_cxt(void)
2 theseven 629
{
630
    uint32_t i, maxusn;
166 theseven 631
    struct ftl_vfl_cxt_type* cxt = NULL;
2 theseven 632
    maxusn = 0;
633
    for (i = 0; i < ftl_banks; i++)
634
        if (ftl_vfl_cxt[i].usn >= maxusn)
635
        {
636
            cxt = &ftl_vfl_cxt[i];
637
            maxusn = ftl_vfl_cxt[i].usn;
638
        }
639
    return cxt;
640
}
641
 
642
 
643
/* Checks if the specified pBlock is marked bad in the supplied lowlevel BBT.
644
   Only used while mounting the VFL. */
124 theseven 645
static uint32_t ftl_is_good_block(uint8_t* bbt, uint32_t block) INITCODE_ATTR;
66 theseven 646
static uint32_t ftl_is_good_block(uint8_t* bbt, uint32_t block)
2 theseven 647
{
648
    if ((bbt[block >> 3] & (1 << (block & 7))) == 0) return 0;
649
    else return 1;
650
}
651
 
652
 
653
/* Checks if the specified vBlock could be remapped */
66 theseven 654
static uint32_t ftl_vfl_is_good_block(uint32_t bank, uint32_t block)
2 theseven 655
{
656
    uint8_t bbtentry = ftl_vfl_cxt[bank].bbt[block >> 6];
657
    if ((bbtentry & (1 << ((7 - (block >> 3)) & 7))) == 0) return 0;
658
    else return 1;
659
}
660
 
661
 
662
#ifndef FTL_READONLY
663
/* Sets or unsets the bad bit of the specified vBlock
664
   in the specified bank's VFL context */
66 theseven 665
static void ftl_vfl_set_good_block(uint32_t bank, uint32_t block, uint32_t isgood)
2 theseven 666
{
667
    uint8_t bit = (1 << ((7 - (block >> 3)) & 7));
668
    if (isgood == 1) ftl_vfl_cxt[bank].bbt[block >> 6] |= bit;
669
    else ftl_vfl_cxt[bank].bbt[block >> 6] &= ~bit;
670
}
671
#endif
672
 
673
 
674
/* Tries to read a VFL context from the specified bank, pBlock and page */
66 theseven 675
static uint32_t ftl_vfl_read_page(uint32_t bank, uint32_t block,
676
                                  uint32_t startpage, void* databuffer,
124 theseven 677
                                  union ftl_spare_data_type* sparebuffer) INITCODE_ATTR;
678
static uint32_t ftl_vfl_read_page(uint32_t bank, uint32_t block,
679
                                  uint32_t startpage, void* databuffer,
66 theseven 680
                                  union ftl_spare_data_type* sparebuffer)
2 theseven 681
{
682
    uint32_t i;
683
    for (i = 0; i < 8; i++)
684
    {
54 theseven 685
        uint32_t page = block * ftl_nand_type->pagesperblock
2 theseven 686
                      + startpage + i;
687
        if ((nand_read_page(bank, page, databuffer,
688
                            sparebuffer, 1, 1) & 0x11F) == 0)
54 theseven 689
            if (sparebuffer->meta.field_8 == 0
690
             && sparebuffer->meta.type == 0x80)
2 theseven 691
                return 0;
692
    }
693
    return 1;
694
}
695
 
696
 
697
/* Translates a bank and vBlock to a pBlock, following remaps */
66 theseven 698
static uint32_t ftl_vfl_get_physical_block(uint32_t bank, uint32_t block)
2 theseven 699
{
700
    if (ftl_vfl_is_good_block(bank, block) == 1) return block;
701
 
702
    uint32_t spareindex;
703
    uint32_t spareused = ftl_vfl_cxt[bank].spareused;
704
    for (spareindex = 0; spareindex < spareused; spareindex++)
705
        if (ftl_vfl_cxt[bank].remaptable[spareindex] == block)
201 theseven 706
        {
61 theseven 707
            DEBUGF("FTL: VFL: Following remapped block: %d => %d",
54 theseven 708
                   block, ftl_vfl_cxt[bank].firstspare + spareindex);
2 theseven 709
            return ftl_vfl_cxt[bank].firstspare + spareindex;
201 theseven 710
        }
2 theseven 711
    return block;
712
}
713
 
714
 
715
#ifndef FTL_READONLY
716
/* Checks if remapping is scheduled for the specified bank and vBlock */
66 theseven 717
static uint32_t ftl_vfl_check_remap_scheduled(uint32_t bank, uint32_t block)
2 theseven 718
{
719
    uint32_t i;
720
    for (i = 0x333; i > 0 && i > ftl_vfl_cxt[bank].scheduledstart; i--)
721
        if (ftl_vfl_cxt[bank].remaptable[i] == block) return 1;
722
    return 0;
723
}
724
#endif
725
 
726
 
727
#ifndef FTL_READONLY
728
/* Schedules remapping for the specified bank and vBlock */
66 theseven 729
static void ftl_vfl_schedule_block_for_remap(uint32_t bank, uint32_t block)
2 theseven 730
{
731
    if (ftl_vfl_check_remap_scheduled(bank, block) == 1) return;
54 theseven 732
    panicf(PANIC_FATAL, "FTL: Scheduling bank %u block %u for remap!",
201 theseven 733
           (unsigned)bank, (unsigned)block);
2 theseven 734
    if (ftl_vfl_cxt[bank].scheduledstart == ftl_vfl_cxt[bank].spareused)
735
        return;
736
    ftl_vfl_cxt[bank].remaptable[--ftl_vfl_cxt[bank].scheduledstart] = block;
737
    ftl_vfl_commit_cxt(bank);
738
}
739
#endif
740
 
741
 
742
#ifndef FTL_READONLY
743
/* Removes the specified bank and vBlock combination
744
   from the remap scheduled list */
66 theseven 745
static void ftl_vfl_mark_remap_done(uint32_t bank, uint32_t block)
2 theseven 746
{
747
    uint32_t i;
748
    uint32_t start = ftl_vfl_cxt[bank].scheduledstart;
749
    uint32_t lastscheduled = ftl_vfl_cxt[bank].remaptable[start];
750
    for (i = 0x333; i > 0 && i > start; i--)
751
        if (ftl_vfl_cxt[bank].remaptable[i] == block)
752
        {
753
            if (i != start && i != 0x333)
754
                ftl_vfl_cxt[bank].remaptable[i] = lastscheduled;
755
            ftl_vfl_cxt[bank].scheduledstart++;
756
            return;
757
        }
758
}
759
#endif
760
 
761
 
762
#ifndef FTL_READONLY
763
/* Logs that there is trouble for the specified vBlock on the specified bank.
764
   The vBlock will be scheduled for remap
765
   if there is too much trouble with it. */
66 theseven 766
static void ftl_vfl_log_trouble(uint32_t bank, uint32_t vblock)
2 theseven 767
{
768
    uint32_t i;
769
    for (i = 0; i < 5; i++)
770
        if (ftl_troublelog[i].block == vblock
771
         && ftl_troublelog[i].bank == bank)
772
        {
773
            ftl_troublelog[i].errors += 3;
774
            if (ftl_troublelog[i].errors > 5)
775
            {
776
                ftl_vfl_schedule_block_for_remap(bank, vblock);
777
                ftl_troublelog[i].block = 0xFFFF;
778
            }
779
            return;
780
        }
781
    for (i = 0; i < 5; i++)
782
        if (ftl_troublelog[i].block == 0xFFFF)
783
        {
784
            ftl_troublelog[i].block = vblock;
785
            ftl_troublelog[i].bank = bank;
786
            ftl_troublelog[i].errors = 3;
787
            return;
788
        }
789
}
790
#endif
791
 
792
 
793
#ifndef FTL_READONLY
794
/* Logs a successful erase for the specified vBlock on the specified bank */
66 theseven 795
static void ftl_vfl_log_success(uint32_t bank, uint32_t vblock)
2 theseven 796
{
797
    uint32_t i;
798
    for (i = 0; i < 5; i++)
799
        if (ftl_troublelog[i].block == vblock
800
         && ftl_troublelog[i].bank == bank)
801
        {
802
            if (--ftl_troublelog[i].errors == 0)
803
                ftl_troublelog[i].block = 0xFFFF;
804
            return;
805
        }
806
}
807
#endif
808
 
809
 
810
#ifndef FTL_READONLY
811
/* Tries to remap the specified vBlock on the specified bank,
812
   not caring about data in there.
813
   If it worked, it will return the new pBlock number,
814
   if not (no more spare blocks available), it will return zero. */
66 theseven 815
static uint32_t ftl_vfl_remap_block(uint32_t bank, uint32_t block)
2 theseven 816
{
817
    uint32_t i;
818
    uint32_t newblock = 0, newidx;
54 theseven 819
    panicf(PANIC_FATAL, "FTL: Remapping bank %u block %u!",
201 theseven 820
           (unsigned)bank, (unsigned)block);
54 theseven 821
    if (bank >= ftl_banks || block >= ftl_nand_type->blocks) return 0;
2 theseven 822
    for (i = 0; i < ftl_vfl_cxt[bank].sparecount; i++)
823
        if (ftl_vfl_cxt[bank].remaptable[i] == 0)
824
        {
825
            newblock = ftl_vfl_cxt[bank].firstspare + i;
826
            newidx = i;
827
            break;
828
        }
829
    if (newblock == 0) return 0;
830
    for (i = 0; i < 9; i++)
831
        if (nand_block_erase(bank,
54 theseven 832
                             newblock * ftl_nand_type->pagesperblock) == 0)
2 theseven 833
            break;
834
    for (i = 0; i < newidx; i++)
835
        if (ftl_vfl_cxt[bank].remaptable[i] == block)
836
            ftl_vfl_cxt[bank].remaptable[i] = 0xFFFF;
837
    ftl_vfl_cxt[bank].remaptable[newidx] = block;
838
    ftl_vfl_cxt[bank].spareused++;
839
    ftl_vfl_set_good_block(bank, block, 0);
840
    return newblock;
841
}
842
#endif
843
 
844
 
54 theseven 845
/* Reads the specified vPage, dealing with all kinds of trouble */
66 theseven 846
static uint32_t ftl_vfl_read(uint32_t vpage, void* buffer, void* sparebuffer,
847
                             uint32_t checkempty, uint32_t remaponfail)
2 theseven 848
{
54 theseven 849
#ifdef VFL_TRACE
61 theseven 850
    DEBUGF("FTL: VFL: Reading page %d", vpage);
54 theseven 851
#endif
852
 
853
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
854
    uint32_t syshyperblocks = ftl_nand_type->blocks
855
                            - ftl_nand_type->userblocks - 0x17;
2 theseven 856
    uint32_t abspage = vpage + ppb * syshyperblocks;
54 theseven 857
    if (abspage >= ftl_nand_type->blocks * ppb || abspage < ppb)
2 theseven 858
    {
58 theseven 859
        DEBUGF("FTL: Trying to read out-of-bounds vPage %u", (unsigned)vpage);
2 theseven 860
        return 4;
861
    }
862
 
863
    uint32_t bank = abspage % ftl_banks;
54 theseven 864
    uint32_t block = abspage / (ftl_nand_type->pagesperblock * ftl_banks);
865
    uint32_t page = (abspage / ftl_banks) % ftl_nand_type->pagesperblock;
2 theseven 866
    uint32_t physblock = ftl_vfl_get_physical_block(bank, block);
54 theseven 867
    uint32_t physpage = physblock * ftl_nand_type->pagesperblock + page;
2 theseven 868
 
869
    uint32_t ret = nand_read_page(bank, physpage, buffer,
870
                                  sparebuffer, 1, checkempty);
871
 
872
    if ((ret & 0x11D) != 0 && (ret & 2) == 0)
873
    {
874
        nand_reset(bank);
875
        ret = nand_read_page(bank, physpage, buffer,
876
                             sparebuffer, 1, checkempty);
877
#ifdef FTL_READONLY
878
        (void)remaponfail;
879
#else
880
        if (remaponfail == 1 &&(ret & 0x11D) != 0 && (ret & 2) == 0)
881
        {
61 theseven 882
            DEBUGF("FTL: VFL: Scheduling vBlock %d for remapping!", block);
2 theseven 883
            ftl_vfl_schedule_block_for_remap(bank, block);
884
        }
885
#endif
886
        return ret;
887
    }
888
 
889
    return ret;
890
}
891
 
892
 
54 theseven 893
/* Multi-bank version of ftl_vfl_read, will read ftl_banks pages in parallel */
66 theseven 894
static uint32_t ftl_vfl_read_fast(uint32_t vpage, void* buffer, void* sparebuffer,
895
                                  uint32_t checkempty, uint32_t remaponfail)
54 theseven 896
{
897
#ifdef VFL_TRACE
61 theseven 898
    DEBUGF("FTL: VFL: Fast reading page %d on all banks", vpage);
54 theseven 899
#endif
900
 
901
    uint32_t i, rc = 0;
902
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
903
    uint32_t syshyperblocks = ftl_nand_type->blocks
904
                            - ftl_nand_type->userblocks - 0x17;
905
    uint32_t abspage = vpage + ppb * syshyperblocks;
906
    if (abspage + ftl_banks - 1 >= ftl_nand_type->blocks * ppb || abspage < ppb)
201 theseven 907
    {
54 theseven 908
        DEBUGF("FTL: Trying to read out-of-bounds vPage %u", (unsigned)vpage);
909
        return 4;
201 theseven 910
    }
54 theseven 911
 
912
    uint32_t bank = abspage % ftl_banks;
913
    uint32_t block = abspage / (ftl_nand_type->pagesperblock * ftl_banks);
914
    uint32_t page = (abspage / ftl_banks) % ftl_nand_type->pagesperblock;
915
    uint32_t remapped = 0;
916
    for (i = 0; i < ftl_banks; i++)
917
        if (ftl_vfl_get_physical_block(i, block) != block)
918
            remapped = 1;
919
    if (bank || remapped)
920
    {
921
        for (i = 0; i < ftl_banks; i++)
922
        {
166 theseven 923
            void* databuf = NULL;
924
            void* sparebuf = NULL;
54 theseven 925
            if (buffer) databuf = (void*)((uint32_t)buffer + 0x800 * i);
926
            if (sparebuffer) sparebuf = (void*)((uint32_t)sparebuffer + 0x40 * i);
927
            uint32_t ret = ftl_vfl_read(vpage + i, databuf, sparebuf, checkempty, remaponfail);
928
            if (ret & 1) rc |= 1 << (i << 2);
929
            if (ret & 2) rc |= 2 << (i << 2);
930
            if (ret & 0x10) rc |= 4 << (i << 2);
931
            if (ret & 0x100) rc |= 8 << (i << 2);
932
        }
933
        return rc;
934
    }
935
    uint32_t physpage = block * ftl_nand_type->pagesperblock + page;
936
 
937
    rc = nand_read_page_fast(physpage, buffer, sparebuffer, 1, checkempty);
938
    if (!(rc & 0xdddd)) return rc;
939
 
940
    for (i = 0; i < ftl_banks; i++)
941
    {
942
        if ((rc >> (i << 2)) & 0x2) continue;
943
        if ((rc >> (i << 2)) & 0xd)
944
        {
945
            rc &= ~(0xf << (i << 2));
946
            nand_reset(i);
947
            uint32_t ret = nand_read_page(i, physpage,
948
                                          (void*)((uint32_t)buffer + 0x800 * i),
949
                                          (void*)((uint32_t)sparebuffer + 0x40 * i),
950
                                          1, checkempty);
951
#ifdef FTL_READONLY
952
            (void)remaponfail;
953
#else
954
            if (remaponfail == 1 && (ret & 0x11D) != 0 && (ret & 2) == 0)
955
                ftl_vfl_schedule_block_for_remap(i, block);
956
#endif
957
            if (ret & 1) rc |= 1 << (i << 2);
958
            if (ret & 2) rc |= 2 << (i << 2);
959
            if (ret & 0x10) rc |= 4 << (i << 2);
960
            if (ret & 0x100) rc |= 8 << (i << 2);
961
        }
962
    }
963
 
964
    return rc;
965
}
966
 
967
 
2 theseven 968
#ifndef FTL_READONLY
969
/* Writes the specified vPage, dealing with all kinds of trouble */
66 theseven 970
static uint32_t ftl_vfl_write(uint32_t vpage, uint32_t count,
971
                              void* buffer, void* sparebuffer)
2 theseven 972
{
54 theseven 973
    uint32_t i, j;
974
#ifdef VFL_TRACE
61 theseven 975
    DEBUGF("FTL: VFL: Writing page %d", vpage);
54 theseven 976
#endif
977
 
978
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
979
    uint32_t syshyperblocks = ftl_nand_type->blocks
980
                            - ftl_nand_type->userblocks - 0x17;
2 theseven 981
    uint32_t abspage = vpage + ppb * syshyperblocks;
54 theseven 982
    if (abspage + count > ftl_nand_type->blocks * ppb || abspage < ppb)
201 theseven 983
    {
54 theseven 984
        DEBUGF("FTL: Trying to write out-of-bounds vPage %u",
985
               (unsigned)vpage);
986
        return 4;
201 theseven 987
    }
54 theseven 988
 
989
    uint32_t bank[5];
990
    uint32_t block[5];
991
    uint32_t physpage[5];
992
 
993
    for (i = 0; i < count; i++, abspage++)
2 theseven 994
    {
54 theseven 995
        for (j = ftl_banks; j > 0; j--)
996
        {
997
            bank[j] = bank[j - 1];
998
            block[j] = block[j - 1];
999
            physpage[j] = physpage[j - 1];
1000
        }
1001
        bank[0] = abspage % ftl_banks;
1002
        block[0] = abspage / (ftl_nand_type->pagesperblock * ftl_banks);
1003
        uint32_t page = (abspage / ftl_banks) % ftl_nand_type->pagesperblock;
1004
        uint32_t physblock = ftl_vfl_get_physical_block(bank[0], block[0]);
1005
        physpage[0] = physblock * ftl_nand_type->pagesperblock + page;
1006
 
1007
        if (i >= ftl_banks)
1008
            if (nand_write_page_collect(bank[ftl_banks]))
1009
                if (nand_read_page(bank[ftl_banks], physpage[ftl_banks],
1010
                                   ftl_buffer, &ftl_sparebuffer[0], 1, 1) & 0x11F)
1011
                {
1012
                    panicf(PANIC_FATAL, "FTL: write error (2) on vPage %u, bank %u, pPage %u",
1013
                           (unsigned)(vpage + i - ftl_banks),
1014
                           (unsigned)bank[ftl_banks],
1015
                           (unsigned)physpage[ftl_banks]);
1016
                    ftl_vfl_log_trouble(bank[ftl_banks], block[ftl_banks]);
1017
                }
1018
        if (nand_write_page_start(bank[0], physpage[0],
1019
                                  (void*)((uint32_t)buffer + 0x800 * i),
1020
                                  (void*)((uint32_t)sparebuffer + 0x40 * i), 1))
1021
            if (nand_read_page(bank[0], physpage[0], ftl_buffer,
1022
                               &ftl_sparebuffer[0], 1, 1) & 0x11F)
1023
            {
1024
                panicf(PANIC_FATAL, "FTL: write error (1) on vPage %u, bank %u, pPage %u",
1025
                       (unsigned)(vpage + i), (unsigned)bank[0], (unsigned)physpage[0]);
1026
                ftl_vfl_log_trouble(bank[0], block[0]);
1027
            }
2 theseven 1028
    }
1029
 
54 theseven 1030
    for (i = count < ftl_banks ? count : ftl_banks; i > 0; i--)
1031
        if (nand_write_page_collect(bank[i - 1]))
1032
            if (nand_read_page(bank[i - 1], physpage[i - 1],
1033
                               ftl_buffer, &ftl_sparebuffer[0], 1, 1) & 0x11F)
1034
            {
1035
                panicf(PANIC_FATAL, "FTL: write error (2) on vPage %u, bank %u, pPage %u",
1036
                       (unsigned)(vpage + count - i),
1037
                       (unsigned)bank[i - 1], (unsigned)physpage[i - 1]);
1038
                ftl_vfl_log_trouble(bank[i - 1], block[i - 1]);
1039
            }
2 theseven 1040
 
54 theseven 1041
    return 0;
2 theseven 1042
}
1043
#endif
1044
 
1045
 
1046
/* Mounts the VFL on all banks */
124 theseven 1047
static uint32_t ftl_vfl_open(void) INITCODE_ATTR;
1048
static uint32_t ftl_vfl_open()
2 theseven 1049
{
1050
    uint32_t i, j, k;
1051
    uint32_t minusn, vflcxtidx, last;
1052
    struct ftl_vfl_cxt_type* cxt;
1053
    uint16_t vflcxtblock[4];
1054
#ifndef FTL_READONLY
1055
    ftl_vfl_usn = 0;
1056
#else
1057
    /* Temporary BBT buffer if we're readonly,
1058
       as we won't need it again after mounting */
1059
    uint8_t bbt[0x410];
1060
#endif
1061
 
54 theseven 1062
    uint32_t syshyperblocks = ftl_nand_type->blocks
1063
                            - ftl_nand_type->userblocks - 0x18;
2 theseven 1064
 
1065
    for (i = 0; i < ftl_banks; i++)
1066
#ifndef FTL_READONLY
1067
        if (ftl_load_bbt(i, ftl_bbt[i]) == 0)
1068
#else
1069
        if (ftl_load_bbt(i, bbt) == 0)
1070
#endif
1071
        {
1072
            for (j = 1; j <= syshyperblocks; j++)
1073
#ifndef FTL_READONLY
1074
                if (ftl_is_good_block(ftl_bbt[i], j) != 0)
1075
#else
1076
                if (ftl_is_good_block(bbt, j) != 0)
1077
#endif
1078
                    if (ftl_vfl_read_page(i, j, 0, ftl_buffer,
54 theseven 1079
                                          &ftl_sparebuffer[0]) == 0)
2 theseven 1080
                    {
1081
                        struct ftl_vfl_cxt_type* cxt;
1082
                        cxt = (struct ftl_vfl_cxt_type*)ftl_buffer;
54 theseven 1083
                        memcpy(vflcxtblock, &cxt->vflcxtblocks, 8);
2 theseven 1084
                        minusn = 0xFFFFFFFF;
1085
                        vflcxtidx = 4;
1086
                        for (k = 0; k < 4; k++)
1087
                            if (vflcxtblock[k] != 0xFFFF)
1088
                                if (ftl_vfl_read_page(i, vflcxtblock[k], 0,
1089
                                                      ftl_buffer,
54 theseven 1090
                                                      &ftl_sparebuffer[0]) == 0)
1091
                                    if (ftl_sparebuffer[0].meta.usn > 0
1092
                                     && ftl_sparebuffer[0].meta.usn <= minusn)
2 theseven 1093
                                    {
54 theseven 1094
                                        minusn = ftl_sparebuffer[0].meta.usn;
2 theseven 1095
                                        vflcxtidx = k;
1096
                                    }
54 theseven 1097
                        if (vflcxtidx == 4)
201 theseven 1098
                        {
54 theseven 1099
                            DEBUGF("FTL: No VFL CXT block found on bank %u!",
1100
                                   (unsigned)i);
201 theseven 1101
                            return 1;
1102
                        }
2 theseven 1103
                        last = 0;
54 theseven 1104
                        uint32_t max = ftl_nand_type->pagesperblock;
2 theseven 1105
                        for (k = 8; k < max; k += 8)
1106
                        {
1107
                            if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx],
1108
                                                  k, ftl_buffer,
54 theseven 1109
                                                  &ftl_sparebuffer[0]) != 0)
2 theseven 1110
                                break;
1111
                            last = k;
1112
                        }
1113
                        if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx],
1114
                                              last, ftl_buffer,
54 theseven 1115
                                              &ftl_sparebuffer[0]) != 0)
1116
                            panicf(PANIC_FATAL, "FTL: Re-reading VFL CXT block "
1117
                                        "on bank %u failed!?", (unsigned)i);
1118
                            //return 1;
2 theseven 1119
                        memcpy(&ftl_vfl_cxt[i], ftl_buffer, 0x800);
1120
                        if (ftl_vfl_verify_checksum(i) != 0) return 1;
1121
#ifndef FTL_READONLY
1122
                        if (ftl_vfl_usn < ftl_vfl_cxt[i].usn)
1123
                            ftl_vfl_usn = ftl_vfl_cxt[i].usn;
1124
#endif
1125
                        break;
1126
                    }
1127
        }
1128
        else
201 theseven 1129
        {
54 theseven 1130
            DEBUGF("FTL: Couldn't load bank %u lowlevel BBT!", (unsigned)i);
201 theseven 1131
            return 1;
1132
        }
2 theseven 1133
    cxt = ftl_vfl_get_newest_cxt();
1134
    for (i = 0; i < ftl_banks; i++)
54 theseven 1135
        memcpy(ftl_vfl_cxt[i].ftlctrlblocks, cxt->ftlctrlblocks, 6);
2 theseven 1136
    return 0;
1137
}
1138
 
1139
 
1140
/* Mounts the actual FTL */
124 theseven 1141
static uint32_t ftl_open(void) INITCODE_ATTR;
1142
static uint32_t ftl_open()
2 theseven 1143
{
1144
    uint32_t i;
1145
    uint32_t ret;
54 theseven 1146
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1147
    struct ftl_vfl_cxt_type* cxt = ftl_vfl_get_newest_cxt();
1148
 
1149
    uint32_t ftlcxtblock = 0xffffffff;
54 theseven 1150
    uint32_t minusn = 0xffffffff;
2 theseven 1151
    for (i = 0; i < 3; i++)
1152
    {
54 theseven 1153
        ret = ftl_vfl_read(ppb * cxt->ftlctrlblocks[i],
1154
                           ftl_buffer, &ftl_sparebuffer[0], 1, 0);
2 theseven 1155
        if ((ret &= 0x11F) != 0) continue;
54 theseven 1156
        if (ftl_sparebuffer[0].meta.type - 0x43 > 4) continue;
1157
        if (ftlcxtblock != 0xffffffff && ftl_sparebuffer[0].meta.usn >= minusn)
2 theseven 1158
            continue;
54 theseven 1159
        minusn = ftl_sparebuffer[0].meta.usn;
1160
        ftlcxtblock = cxt->ftlctrlblocks[i];
2 theseven 1161
    }
1162
 
54 theseven 1163
    if (ftlcxtblock == 0xffffffff)
1164
    {
1165
        DEBUGF("FTL: Couldn't find readable FTL CXT block!");
1166
        return 1;
1167
    }
2 theseven 1168
 
61 theseven 1169
    DEBUGF("FTL: Found FTL context block: vBlock %d", ftlcxtblock);
2 theseven 1170
    uint32_t ftlcxtfound = 0;
54 theseven 1171
    for (i = ftl_nand_type->pagesperblock * ftl_banks - 1; i > 0; i--)
2 theseven 1172
    {
1173
        ret = ftl_vfl_read(ppb * ftlcxtblock + i,
54 theseven 1174
                           ftl_buffer, &ftl_sparebuffer[0], 1, 0);
2 theseven 1175
        if ((ret & 0x11F) != 0) continue;
54 theseven 1176
        else if (ftl_sparebuffer[0].meta.type == 0x43)
2 theseven 1177
        {
1178
            memcpy(&ftl_cxt, ftl_buffer, 0x28C);
1179
            ftlcxtfound = 1;
1180
            break;
1181
        }
1182
        else
1183
        {
54 theseven 1184
            /* This will trip if there was an unclean unmount before. */
61 theseven 1185
            DEBUGF("FTL: Unclean shutdown before!");
54 theseven 1186
#ifdef FTL_FORCEMOUNT
61 theseven 1187
            DEBUGF("FTL: Forcing mount nevertheless...");
54 theseven 1188
#else
2 theseven 1189
            break;
1190
#endif
1191
        }
1192
    }
1193
 
54 theseven 1194
    if (ftlcxtfound == 0)
201 theseven 1195
    {
54 theseven 1196
        DEBUGF("FTL: Couldn't find FTL CXT page!");
201 theseven 1197
        return 1;
1198
    }
2 theseven 1199
 
61 theseven 1200
    DEBUGF("FTL: Successfully read FTL context block");
54 theseven 1201
    uint32_t pagestoread = ftl_nand_type->userblocks >> 10;
1202
    if ((ftl_nand_type->userblocks & 0x1FF) != 0) pagestoread++;
2 theseven 1203
 
1204
    for (i = 0; i < pagestoread; i++)
1205
    {
1206
        if ((ftl_vfl_read(ftl_cxt.ftl_map_pages[i],
54 theseven 1207
                          ftl_buffer, &ftl_sparebuffer[0], 1, 1) & 0x11F) != 0)
201 theseven 1208
        {
54 theseven 1209
            DEBUGF("FTL: Failed to read block map page %u", (unsigned)i);
2 theseven 1210
            return 1;
201 theseven 1211
        }
2 theseven 1212
 
1213
        uint32_t toread = 2048;
54 theseven 1214
        if (toread > (ftl_nand_type->userblocks << 1) - (i << 11))
1215
            toread = (ftl_nand_type->userblocks << 1) - (i << 11);
2 theseven 1216
 
1217
        memcpy(&ftl_map[i << 10], ftl_buffer, toread);
1218
    }
1219
 
1220
#ifndef FTL_READONLY
54 theseven 1221
    pagestoread = (ftl_nand_type->userblocks + 23) >> 10;
1222
    if (((ftl_nand_type->userblocks + 23) & 0x1FF) != 0) pagestoread++;
2 theseven 1223
 
1224
    for (i = 0; i < pagestoread; i++)
1225
    {
1226
        if ((ftl_vfl_read(ftl_cxt.ftl_erasectr_pages[i],
54 theseven 1227
                          ftl_buffer, &ftl_sparebuffer[0], 1, 1) & 0x11F) != 0)
201 theseven 1228
        {
54 theseven 1229
            DEBUGF("FTL: Failed to read erase counter page %u", (unsigned)i);
2 theseven 1230
            return 1;
201 theseven 1231
        }
2 theseven 1232
 
1233
        uint32_t toread = 2048;
54 theseven 1234
        if (toread > ((ftl_nand_type->userblocks + 23) << 1) - (i << 11))
1235
            toread = ((ftl_nand_type->userblocks + 23) << 1) - (i << 11);
2 theseven 1236
 
1237
        memcpy(&ftl_erasectr[i << 10], ftl_buffer, toread);
1238
    }
1239
 
1240
    for (i = 0; i < 0x11; i++)
1241
    {
1242
        ftl_log[i].scatteredvblock = 0xFFFF;
1243
        ftl_log[i].logicalvblock = 0xFFFF;
1244
        ftl_log[i].pageoffsets = ftl_offsets[i];
1245
    }
1246
 
1247
    memset(ftl_troublelog, 0xFF, 20);
1248
    memset(ftl_erasectr_dirt, 0, 8);
1249
#endif
1250
 
54 theseven 1251
#ifdef FTL_DEBUG
1252
    uint32_t j, k;
1253
    for (i = 0; i < ftl_banks; i++)
1254
    {
1255
        uint32_t badblocks = 0;
1256
#ifndef FTL_READONLY
124 theseven 1257
        for (j = 0; j < ftl_nand_type->blocks >> 3; j++)
54 theseven 1258
        {
1259
            uint8_t bbtentry = ftl_bbt[i][j];
1260
            for (k = 0; k < 8; k++) if ((bbtentry & (1 << k)) == 0) badblocks++;
1261
        }
61 theseven 1262
        DEBUGF("FTL: BBT for bank %d: %d bad blocks", i, badblocks);
54 theseven 1263
        badblocks = 0;
1264
#endif
1265
        for (j = 0; j < ftl_vfl_cxt[i].sparecount; j++)
1266
            if (ftl_vfl_cxt[i].remaptable[j] == 0xFFFF) badblocks++;
61 theseven 1267
        DEBUGF("FTL: VFL: Bank %d: %d of %d spare blocks are bad",
54 theseven 1268
               i, badblocks, ftl_vfl_cxt[i].sparecount);
61 theseven 1269
        DEBUGF("FTL: VFL: Bank %d: %d blocks remapped",
54 theseven 1270
               i, ftl_vfl_cxt[i].spareused);
61 theseven 1271
        DEBUGF("FTL: VFL: Bank %d: %d blocks scheduled for remapping",
54 theseven 1272
               i, 0x334 - ftl_vfl_cxt[i].scheduledstart);
1273
    }
1274
#ifndef FTL_READONLY
1275
    uint32_t min = 0xFFFFFFFF, max = 0, total = 0;
124 theseven 1276
    for (i = 0; i < ftl_nand_type->userblocks + 23; i++)
54 theseven 1277
    {
1278
        if (ftl_erasectr[i] > max) max = ftl_erasectr[i];
1279
        if (ftl_erasectr[i] < min) min = ftl_erasectr[i];
1280
        total += ftl_erasectr[i];
1281
    }
61 theseven 1282
    DEBUGF("FTL: Erase counters: Minimum: %d, maximum %d, average: %d, total: %d",
124 theseven 1283
           min, max, total / (ftl_nand_type->userblocks + 23), total);
54 theseven 1284
#endif
1285
#endif
1286
 
2 theseven 1287
    return 0;
1288
}
1289
 
1290
 
1291
#ifndef FTL_READONLY
1292
/* Returns a pointer to the ftl_log entry for the specified vBlock,
1293
   or null, if there is none */
66 theseven 1294
static struct ftl_log_type* ftl_get_log_entry(uint32_t block)
2 theseven 1295
{
1296
    uint32_t i;
1297
    for (i = 0; i < 0x11; i++)
1298
    {
1299
        if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
1300
        if (ftl_log[i].logicalvblock == block) return &ftl_log[i];
1301
    }
166 theseven 1302
    return NULL;
2 theseven 1303
}
1304
#endif
1305
 
1306
/* Exposed function: Read highlevel sectors */
54 theseven 1307
uint32_t ftl_read(uint32_t sector, uint32_t count, void* buffer)
2 theseven 1308
{
54 theseven 1309
    uint32_t i, j;
1310
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1311
    uint32_t error = 0;
1312
 
155 theseven 1313
    if (!ftl_initialized) return -1;
128 theseven 1314
 
54 theseven 1315
#ifdef FTL_TRACE
61 theseven 1316
    DEBUGF("FTL: Reading %d sectors starting at %d", count, sector);
54 theseven 1317
#endif
1318
 
201 theseven 1319
    if ((uint32_t)buffer & (CACHEALIGN_SIZE - 1))
1320
        panicf(PANIC_KILLTHREAD,
1321
               "ftl_read: Misaligned data buffer at %08X (sector %lu, count %lu)",
1322
               (unsigned int)buffer, sector, count);
68 theseven 1323
 
54 theseven 1324
    if (sector + count > ftl_nand_type->userblocks * ppb)
1325
    {
61 theseven 1326
        DEBUGF("FTL: Sector %d is out of range!", sector + count - 1);
155 theseven 1327
        return -2;
54 theseven 1328
    }
2 theseven 1329
    if (count == 0) return 0;
1330
 
54 theseven 1331
    mutex_lock(&ftl_mtx, TIMEOUT_BLOCK);
1332
 
2 theseven 1333
    for (i = 0; i < count; i++)
1334
    {
1335
        uint32_t block = (sector + i) / ppb;
1336
        uint32_t page = (sector + i) % ppb;
1337
 
1338
        uint32_t abspage = ftl_map[block] * ppb + page;
1339
#ifndef FTL_READONLY
1340
        struct ftl_log_type* logentry = ftl_get_log_entry(block);
166 theseven 1341
        if (logentry != NULL)
2 theseven 1342
        {
54 theseven 1343
#ifdef FTL_TRACE
201 theseven 1344
            DEBUGF("FTL: Block %d has a log entry", block);
54 theseven 1345
#endif
1346
            if (logentry->scatteredvblock != 0xFFFF
1347
             && logentry->pageoffsets[page] != 0xFFFF)
2 theseven 1348
            {
54 theseven 1349
#ifdef FTL_TRACE
201 theseven 1350
                DEBUGF("FTL: Found page %d at block %d, page %d", page,
1351
                      (*logentry).scatteredvblock, (*logentry).pageoffsets[page]);
54 theseven 1352
#endif
1353
                abspage = logentry->scatteredvblock * ppb
1354
                        + logentry->pageoffsets[page];
2 theseven 1355
            }
1356
        }
1357
#endif
1358
 
54 theseven 1359
#ifndef FTL_READONLY
1360
        if (count >= i + ftl_banks && !(page & (ftl_banks - 1))
166 theseven 1361
         && logentry == NULL)
54 theseven 1362
#else
1363
        if (count >= i + ftl_banks && !(page & (ftl_banks - 1)))
1364
#endif
2 theseven 1365
        {
54 theseven 1366
            uint32_t ret = ftl_vfl_read_fast(abspage, &((uint8_t*)buffer)[i << 11],
1367
                                             &ftl_sparebuffer[0], 1, 1);
1368
            for (j = 0; j < ftl_banks; j++)
1369
                if (ret & (2 << (j << 2)))
1370
                    memset(&((uint8_t*)buffer)[(i + j) << 11], 0, 0x800);
1371
                else if ((ret & (0xd << (j << 2))) || ftl_sparebuffer[j].user.eccmark != 0xFF)
1372
                {
201 theseven 1373
                    DEBUGF("FTL: Error while reading sector %d!", (sector + i));
155 theseven 1374
                    error = -3;
54 theseven 1375
                    memset(&((uint8_t*)buffer)[(i + j) << 11], 0, 0x800);
1376
                }
1377
            i += ftl_banks - 1;
2 theseven 1378
        }
54 theseven 1379
        else
1380
        {
1381
            uint32_t ret = ftl_vfl_read(abspage, &((uint8_t*)buffer)[i << 11],
1382
                                        &ftl_sparebuffer[0], 1, 1);
1383
            if (ret & 2) memset(&((uint8_t*)buffer)[i << 11], 0, 0x800);
1384
            else if ((ret & 0x11D) != 0 || ftl_sparebuffer[0].user.eccmark != 0xFF)
1385
            {
201 theseven 1386
                DEBUGF("FTL: Error while reading sector %d!", (sector + i));
155 theseven 1387
                error = -4;
54 theseven 1388
                memset(&((uint8_t*)buffer)[i << 11], 0, 0x800);
1389
            }
1390
        }
2 theseven 1391
    }
54 theseven 1392
 
1393
    mutex_unlock(&ftl_mtx);
1394
 
2 theseven 1395
    return error;
1396
}
1397
 
1398
 
1399
#ifndef FTL_READONLY
1400
/* Performs a vBlock erase, dealing with hardware,
1401
   remapping and all kinds of trouble */
66 theseven 1402
static uint32_t ftl_erase_block_internal(uint32_t block)
2 theseven 1403
{
1404
    uint32_t i, j;
54 theseven 1405
    block = block + ftl_nand_type->blocks
1406
          - ftl_nand_type->userblocks - 0x17;
1407
    if (block == 0 || block >= ftl_nand_type->blocks) return 1;
2 theseven 1408
    for (i = 0; i < ftl_banks; i++)
1409
    {
1410
        if (ftl_vfl_check_remap_scheduled(i, block) == 1)
1411
        {
1412
            ftl_vfl_remap_block(i, block);
1413
            ftl_vfl_mark_remap_done(i, block);
1414
        }
1415
        ftl_vfl_log_success(i, block);
1416
        uint32_t pblock = ftl_vfl_get_physical_block(i, block);
1417
        uint32_t rc;
1418
        for (j = 0; j < 3; j++)
1419
        {
54 theseven 1420
            rc = nand_block_erase(i, pblock * ftl_nand_type->pagesperblock);
2 theseven 1421
            if (rc == 0) break;
1422
        }
1423
        if (rc != 0)
1424
        {
54 theseven 1425
            panicf(PANIC_FATAL, "FTL: Block erase failed on bank %u block %u",
1426
                   (unsigned)i, (unsigned)block);
2 theseven 1427
            if (pblock != block)
1428
            {
1429
                uint32_t spareindex = pblock - ftl_vfl_cxt[i].firstspare;
1430
                ftl_vfl_cxt[i].remaptable[spareindex] = 0xFFFF;
1431
            }
1432
            ftl_vfl_cxt[i].field_18++;
1433
            if (ftl_vfl_remap_block(i, block) == 0) return 1;
1434
            if (ftl_vfl_commit_cxt(i) != 0) return 1;
1435
            memset(&ftl_sparebuffer, 0, 0x40);
1436
            nand_write_page(i, pblock, &ftl_vfl_cxt[0], &ftl_sparebuffer, 1);
1437
        }
1438
    }
1439
    return 0;
1440
}
1441
#endif
1442
 
1443
 
1444
#ifndef FTL_READONLY
1445
/* Highlevel vBlock erase, that increments the erase counter for the block */
66 theseven 1446
static uint32_t ftl_erase_block(uint32_t block)
2 theseven 1447
{
1448
    ftl_erasectr[block]++;
1449
    if (ftl_erasectr_dirt[block >> 10] == 100) ftl_cxt.erasedirty = 1;
1450
    else ftl_erasectr_dirt[block >> 10]++;
1451
    return ftl_erase_block_internal(block);
1452
}
1453
#endif
1454
 
1455
 
1456
#ifndef FTL_READONLY
1457
/* Allocates a block from the pool,
1458
   returning its vBlock number, or 0xFFFFFFFF on error */
66 theseven 1459
static uint32_t ftl_allocate_pool_block(void)
2 theseven 1460
{
1461
    uint32_t i;
1462
    uint32_t erasectr = 0xFFFFFFFF, bestidx = 0xFFFFFFFF, block;
1463
    for (i = 0; i < ftl_cxt.freecount; i++)
1464
    {
1465
        uint32_t idx = ftl_cxt.nextfreeidx + i;
1466
        if (idx >= 0x14) idx -= 0x14;
1467
        if (!ftl_cxt.blockpool[idx]) continue;
1468
        if (ftl_erasectr[ftl_cxt.blockpool[idx]] < erasectr)
1469
        {
1470
            erasectr = ftl_erasectr[ftl_cxt.blockpool[idx]];
1471
            bestidx = idx;
1472
        }
1473
    }
54 theseven 1474
    if (bestidx == 0xFFFFFFFF) panicf(PANIC_FATAL, "FTL: Out of pool blocks!");
2 theseven 1475
    block = ftl_cxt.blockpool[bestidx];
1476
    if (bestidx != ftl_cxt.nextfreeidx)
1477
    {
1478
        ftl_cxt.blockpool[bestidx] = ftl_cxt.blockpool[ftl_cxt.nextfreeidx];
1479
        ftl_cxt.blockpool[ftl_cxt.nextfreeidx] = block;
1480
    }
54 theseven 1481
    if (block > (uint32_t)ftl_nand_type->userblocks + 0x17)
1482
        panicf(PANIC_FATAL, "FTL: Bad block number in pool: %u", (unsigned)block);
2 theseven 1483
    if (ftl_erase_block(block) != 0) return 0xFFFFFFFF;
1484
    if (++ftl_cxt.nextfreeidx == 0x14) ftl_cxt.nextfreeidx = 0;
1485
    ftl_cxt.freecount--;
1486
    return block;
1487
}
1488
#endif
1489
 
1490
 
1491
#ifndef FTL_READONLY
1492
/* Releases a vBlock back into the pool */
66 theseven 1493
static void ftl_release_pool_block(uint32_t block)
2 theseven 1494
{
54 theseven 1495
    if (block >= (uint32_t)ftl_nand_type->userblocks + 0x17)
1496
        panicf(PANIC_FATAL, "FTL: Tried to release block %u", (unsigned)block);
2 theseven 1497
    uint32_t idx = ftl_cxt.nextfreeidx + ftl_cxt.freecount++;
1498
    if (idx >= 0x14) idx -= 0x14;
1499
    ftl_cxt.blockpool[idx] = block;
1500
}
1501
#endif
1502
 
1503
 
1504
#ifndef FTL_READONLY
1505
/* Commits the location of the FTL context blocks
1506
   to a semi-randomly chosen VFL context */
66 theseven 1507
static uint32_t ftl_store_ctrl_block_list(void)
2 theseven 1508
{
1509
    uint32_t i;
1510
    for (i = 0; i < ftl_banks; i++)
1511
        memcpy(ftl_vfl_cxt[i].ftlctrlblocks, ftl_cxt.ftlctrlblocks, 6);
1512
    return ftl_vfl_commit_cxt(ftl_vfl_usn % ftl_banks);
1513
}
1514
#endif
1515
 
1516
 
1517
#ifndef FTL_READONLY
1518
/* Saves the n-th erase counter page to the flash,
1519
   because it is too dirty or needs to be moved. */
66 theseven 1520
static uint32_t ftl_save_erasectr_page(uint32_t index)
2 theseven 1521
{
54 theseven 1522
    memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1523
    ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1524
    ftl_sparebuffer[0].meta.idx = index;
1525
    ftl_sparebuffer[0].meta.type = 0x46;
1526
    if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, &ftl_erasectr[index << 10],
1527
                      &ftl_sparebuffer[0]) != 0)
2 theseven 1528
        return 1;
1529
    if ((ftl_vfl_read(ftl_cxt.ftlctrlpage, ftl_buffer,
54 theseven 1530
                      &ftl_sparebuffer[0], 1, 1) & 0x11F) != 0)
2 theseven 1531
        return 1;
1532
    if (memcmp(ftl_buffer, &ftl_erasectr[index << 10], 0x800) != 0) return 1;
54 theseven 1533
    if (ftl_sparebuffer[0].meta.type != 0x46) return 1;
1534
    if (ftl_sparebuffer[0].meta.idx != index) return 1;
1535
    if (ftl_sparebuffer[0].meta.usn != ftl_cxt.usn) return 1;
2 theseven 1536
    ftl_cxt.ftl_erasectr_pages[index] = ftl_cxt.ftlctrlpage;
1537
    ftl_erasectr_dirt[index] = 0;
1538
    return 0;
1539
}
1540
#endif
1541
 
1542
 
1543
#ifndef FTL_READONLY
1544
/* Increments ftl_cxt.ftlctrlpage to the next available FTL context page,
1545
   allocating a new context block if neccessary. */
66 theseven 1546
static uint32_t ftl_next_ctrl_pool_page(void)
2 theseven 1547
{
1548
    uint32_t i;
54 theseven 1549
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1550
    if (++ftl_cxt.ftlctrlpage % ppb != 0) return 0;
1551
    for (i = 0; i < 3; i++)
1552
        if ((ftl_cxt.ftlctrlblocks[i] + 1) * ppb == ftl_cxt.ftlctrlpage)
1553
            break;
1554
    i = (i + 1) % 3;
1555
    uint32_t oldblock = ftl_cxt.ftlctrlblocks[i];
1556
    uint32_t newblock = ftl_allocate_pool_block();
1557
    if (newblock == 0xFFFFFFFF) return 1;
1558
    ftl_cxt.ftlctrlblocks[i] = newblock;
1559
    ftl_cxt.ftlctrlpage = newblock * ppb;
61 theseven 1560
    DEBUGF("Starting new FTL control block at %d", ftl_cxt.ftlctrlpage);
54 theseven 1561
    uint32_t pagestoread = (ftl_nand_type->userblocks + 23) >> 10;
1562
    if (((ftl_nand_type->userblocks + 23) & 0x1FF) != 0) pagestoread++;
2 theseven 1563
    for (i = 0; i < pagestoread; i++)
1564
        if (oldblock * ppb <= ftl_cxt.ftl_erasectr_pages[i]
1565
         && (oldblock + 1) * ppb > ftl_cxt.ftl_erasectr_pages[i])
1566
         {
1567
            ftl_cxt.usn--;
1568
            if (ftl_save_erasectr_page(i) != 0)
1569
            {
1570
                ftl_cxt.ftlctrlblocks[i] = oldblock;
1571
                ftl_cxt.ftlctrlpage = oldblock * (ppb + 1) - 1;
1572
                ftl_release_pool_block(newblock);
1573
                return 1;
1574
            }
1575
            ftl_cxt.ftlctrlpage++;
1576
         }
1577
    ftl_release_pool_block(oldblock);
1578
    return ftl_store_ctrl_block_list();
1579
}
1580
#endif
1581
 
1582
 
1583
#ifndef FTL_READONLY
1584
/* Copies a vPage from one location to another */
66 theseven 1585
static uint32_t ftl_copy_page(uint32_t source, uint32_t destination,
1586
                              uint32_t lpn, uint32_t type)
2 theseven 1587
{
54 theseven 1588
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1589
    uint32_t rc = ftl_vfl_read(source, ftl_copybuffer[0],
1590
                               &ftl_copyspare[0], 1, 1) & 0x11F;
1591
    memset(&ftl_copyspare[0], 0xFF, 0x40);
1592
    ftl_copyspare[0].user.lpn = lpn;
1593
    ftl_copyspare[0].user.usn = ++ftl_cxt.nextblockusn;
1594
    ftl_copyspare[0].user.type = 0x40;
1595
    if ((rc & 2) != 0) memset(ftl_copybuffer[0], 0, 0x800);
1596
    else if (rc != 0) ftl_copyspare[0].user.eccmark = 0x55;
2 theseven 1597
    if (type == 1 && destination % ppb == ppb - 1)
54 theseven 1598
        ftl_copyspare[0].user.type = 0x41;
1599
    return ftl_vfl_write(destination, 1, ftl_copybuffer[0], &ftl_copyspare[0]);
2 theseven 1600
}
1601
#endif
1602
 
1603
 
1604
#ifndef FTL_READONLY
1605
/* Copies a pBlock to a vBlock */
66 theseven 1606
static uint32_t ftl_copy_block(uint32_t source, uint32_t destination)
2 theseven 1607
{
54 theseven 1608
    uint32_t i, j;
1609
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1610
    uint32_t error = 0;
1611
    ftl_cxt.nextblockusn++;
54 theseven 1612
    for (i = 0; i < ppb; i += FTL_COPYBUF_SIZE)
2 theseven 1613
    {
54 theseven 1614
        uint32_t rc = ftl_read(source * ppb + i,
1615
                               FTL_COPYBUF_SIZE, ftl_copybuffer[0]);
1616
        memset(&ftl_copyspare[0], 0xFF, 0x40 * FTL_COPYBUF_SIZE);
1617
        for (j = 0; j < FTL_COPYBUF_SIZE; j++)
2 theseven 1618
        {
54 theseven 1619
            ftl_copyspare[j].user.lpn = source * ppb + i + j;
1620
            ftl_copyspare[j].user.usn = ftl_cxt.nextblockusn;
1621
            ftl_copyspare[j].user.type = 0x40;
1622
            if (rc)
1623
            {
1624
                if (ftl_read(source * ppb + i + j, 1, ftl_copybuffer[j]))
1625
                    ftl_copyspare[j].user.eccmark = 0x55;
1626
            }
1627
            if (i + j == ppb - 1) ftl_copyspare[j].user.type = 0x41;
1628
        }
1629
        if (ftl_vfl_write(destination * ppb + i, FTL_COPYBUF_SIZE,
1630
                          ftl_copybuffer[0], &ftl_copyspare[0]))
1631
        {
2 theseven 1632
            error = 1;
1633
            break;
1634
        }
1635
    }
1636
    if (error != 0)
1637
    {
1638
        ftl_erase_block(destination);
1639
        return 1;
1640
    }
1641
    return 0;
1642
}
1643
#endif
1644
 
1645
 
1646
#ifndef FTL_READONLY
1647
/* Clears ftl_log.issequential, if something violating that is written. */
66 theseven 1648
static void ftl_check_still_sequential(struct ftl_log_type* entry, uint32_t page)
2 theseven 1649
{
54 theseven 1650
    if (entry->pagesused != entry->pagescurrent
1651
     || entry->pageoffsets[page] != page)
1652
        entry->issequential = 0;
2 theseven 1653
}
1654
#endif
1655
 
1656
 
1657
#ifndef FTL_READONLY
1658
/* Copies all pages that are currently used from the scattered page block in
1659
   use by the supplied ftl_log entry to a newly-allocated one, and releases
1660
   the old one.
1661
   In other words: It kicks the pages containing old garbage out of it to make
1662
   space again. This is usually done when a scattered page block is being
1663
   removed because it is full, but less than half of the pages in there are
1664
   still in use and rest is just filled with old crap. */
66 theseven 1665
static uint32_t ftl_compact_scattered(struct ftl_log_type* entry)
2 theseven 1666
{
1667
    uint32_t i, j;
54 theseven 1668
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1669
    uint32_t error;
1670
    struct ftl_log_type backup;
54 theseven 1671
    if (entry->pagescurrent == 0)
2 theseven 1672
    {
54 theseven 1673
        ftl_release_pool_block(entry->scatteredvblock);
1674
        entry->scatteredvblock = 0xFFFF;
2 theseven 1675
        return 0;
1676
    }
1677
    backup = *entry;
54 theseven 1678
    memcpy(ftl_offsets_backup, entry->pageoffsets, 0x400);
2 theseven 1679
    for (i = 0; i < 4; i++)
1680
    {
1681
        uint32_t block = ftl_allocate_pool_block();
1682
        if (block == 0xFFFFFFFF) return 1;
54 theseven 1683
        entry->pagesused = 0;
1684
        entry->pagescurrent = 0;
1685
        entry->issequential = 1;
1686
        entry->scatteredvblock = block;
2 theseven 1687
        error = 0;
1688
        for (j = 0; j < ppb; j++)
54 theseven 1689
            if (entry->pageoffsets[j] != 0xFFFF)
2 theseven 1690
            {
54 theseven 1691
                uint32_t lpn = entry->logicalvblock * ppb + j;
1692
                uint32_t newpage = block * ppb + entry->pagesused;
2 theseven 1693
                uint32_t oldpage = backup.scatteredvblock * ppb
54 theseven 1694
                                 + entry->pageoffsets[j];
2 theseven 1695
                if (ftl_copy_page(oldpage, newpage, lpn,
54 theseven 1696
                                  entry->issequential) != 0)
2 theseven 1697
                {
1698
                    error = 1;
1699
                    break;
1700
                }
54 theseven 1701
                entry->pageoffsets[j] = entry->pagesused++;
1702
                entry->pagescurrent++;
2 theseven 1703
                ftl_check_still_sequential(entry, j);
1704
            }
54 theseven 1705
        if (backup.pagescurrent != entry->pagescurrent) error = 1;
2 theseven 1706
        if (error == 0)
1707
        {
1708
            ftl_release_pool_block(backup.scatteredvblock);
1709
            break;
1710
        }
1711
        *entry = backup;
54 theseven 1712
        memcpy(entry->pageoffsets, ftl_offsets_backup, 0x400);
2 theseven 1713
    }
1714
    return error;
1715
}
1716
#endif
1717
 
1718
 
1719
#ifndef FTL_READONLY
1720
/* Commits an ftl_log entry to proper blocks, no matter what's in there. */
66 theseven 1721
static uint32_t ftl_commit_scattered(struct ftl_log_type* entry)
2 theseven 1722
{
1723
    uint32_t i;
1724
    uint32_t error;
1725
    uint32_t block;
1726
    for (i = 0; i < 4; i++)
1727
    {
1728
        block = ftl_allocate_pool_block();
1729
        if (block == 0xFFFFFFFF) return 1;
54 theseven 1730
        error = ftl_copy_block(entry->logicalvblock, block);
2 theseven 1731
        if (error == 0) break;
1732
        ftl_release_pool_block(block);
1733
    }
1734
    if (error != 0) return 1;
54 theseven 1735
    ftl_release_pool_block(entry->scatteredvblock);
1736
    entry->scatteredvblock = 0xFFFF;
1737
    ftl_release_pool_block(ftl_map[entry->logicalvblock]);
1738
    ftl_map[entry->logicalvblock] = block;
2 theseven 1739
    return 0;
1740
}
1741
#endif
1742
 
1743
 
1744
#ifndef FTL_READONLY
1745
/* Fills the rest of a scattered page block that was actually written
1746
   sequentially until now, in order to be able to save a block erase by
1747
   committing it without needing to copy it again.
1748
   If this fails for whichever reason, it will be committed the usual way. */
66 theseven 1749
static uint32_t ftl_commit_sequential(struct ftl_log_type* entry)
2 theseven 1750
{
54 theseven 1751
    uint32_t i;
1752
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1753
 
54 theseven 1754
    if (entry->issequential != 1
1755
     || entry->pagescurrent != entry->pagesused)
2 theseven 1756
        return 1;
1757
 
54 theseven 1758
    for (; entry->pagesused < ppb; )
2 theseven 1759
    {
54 theseven 1760
        uint32_t lpn = entry->logicalvblock * ppb + entry->pagesused;
1761
        uint32_t newpage = entry->scatteredvblock * ppb
1762
                         + entry->pagesused;
1763
        uint32_t count = FTL_COPYBUF_SIZE < ppb - entry->pagesused
1764
                       ? FTL_COPYBUF_SIZE : ppb - entry->pagesused;
1765
        for (i = 0; i < count; i++)
1766
            if (entry->pageoffsets[entry->pagesused + i] != 0xFFFF)
1767
                return ftl_commit_scattered(entry);
1768
        uint32_t rc = ftl_read(lpn, count, ftl_copybuffer[0]);
1769
        memset(&ftl_copyspare[0], 0xFF, 0x40 * FTL_COPYBUF_SIZE);
1770
        for (i = 0; i < count; i++)
1771
        {
1772
            ftl_copyspare[i].user.lpn = lpn + i;
1773
            ftl_copyspare[i].user.usn = ++ftl_cxt.nextblockusn;
1774
            ftl_copyspare[i].user.type = 0x40;
1775
            if (rc) ftl_copyspare[i].user.eccmark = 0x55;
1776
            if (entry->pagesused + i == ppb - 1)
1777
                ftl_copyspare[i].user.type = 0x41;
1778
        }
1779
        if (ftl_vfl_write(newpage, count, ftl_copybuffer[0], &ftl_copyspare[0]))
2 theseven 1780
            return ftl_commit_scattered(entry);
54 theseven 1781
        entry->pagesused += count;
2 theseven 1782
    }
54 theseven 1783
    ftl_release_pool_block(ftl_map[entry->logicalvblock]);
1784
    ftl_map[entry->logicalvblock] = entry->scatteredvblock;
1785
    entry->scatteredvblock = 0xFFFF;
2 theseven 1786
    return 0;
1787
}
1788
#endif
1789
 
1790
 
1791
#ifndef FTL_READONLY
1792
/* If a log entry is supplied, its scattered page block will be removed in
1793
   whatever way seems most appropriate. Else, the oldest scattered page block
1794
   will be freed by committing it. */
66 theseven 1795
static uint32_t ftl_remove_scattered_block(struct ftl_log_type* entry)
2 theseven 1796
{
1797
    uint32_t i;
54 theseven 1798
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1799
    uint32_t age = 0xFFFFFFFF, used = 0;
166 theseven 1800
    if (entry == NULL)
2 theseven 1801
    {
1802
        for (i = 0; i < 0x11; i++)
1803
        {
1804
            if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
1805
            if (ftl_log[i].pagesused == 0 || ftl_log[i].pagescurrent == 0)
1806
                return 1;
1807
            if (ftl_log[i].usn < age
1808
             || (ftl_log[i].usn == age && ftl_log[i].pagescurrent > used))
1809
            {
1810
                age = ftl_log[i].usn;
1811
                used = ftl_log[i].pagescurrent;
1812
                entry = &ftl_log[i];
1813
            }
1814
        }
166 theseven 1815
        if (entry == NULL) return 1;
2 theseven 1816
    }
54 theseven 1817
    else if (entry->pagescurrent < ppb / 2)
2 theseven 1818
    {
1819
        ftl_cxt.swapcounter++;
1820
        return ftl_compact_scattered(entry);
1821
    }
1822
    ftl_cxt.swapcounter++;
54 theseven 1823
    if (entry->issequential == 1) return ftl_commit_sequential(entry);
2 theseven 1824
    else return ftl_commit_scattered(entry);
1825
}
1826
#endif
1827
 
1828
 
1829
#ifndef FTL_READONLY
1830
/* Initialize a log entry to the values for an empty scattered page block */
66 theseven 1831
static void ftl_init_log_entry(struct ftl_log_type* entry)
2 theseven 1832
{
54 theseven 1833
    entry->issequential = 1;
1834
    entry->pagescurrent = 0;
1835
    entry->pagesused = 0;
1836
    memset(entry->pageoffsets, 0xFF, 0x400);
2 theseven 1837
}
1838
#endif
1839
 
1840
 
1841
#ifndef FTL_READONLY
1842
/* Allocates a log entry for the specified vBlock,
1843
   first making space, if neccessary. */
66 theseven 1844
static struct ftl_log_type* ftl_allocate_log_entry(uint32_t block)
2 theseven 1845
{
1846
    uint32_t i;
1847
    struct ftl_log_type* entry = ftl_get_log_entry(block);
166 theseven 1848
    if (entry != NULL)
155 theseven 1849
    {
1850
        entry->usn = ftl_cxt.nextblockusn - 1;
1851
        return entry;
1852
    }
2 theseven 1853
 
1854
    for (i = 0; i < 0x11; i++)
1855
    {
1856
        if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
1857
        if (ftl_log[i].pagesused == 0)
1858
        {
1859
            entry = &ftl_log[i];
1860
            break;
1861
        }
1862
    }
1863
 
166 theseven 1864
    if (entry == NULL)
2 theseven 1865
    {
54 theseven 1866
        if (ftl_cxt.freecount < 3) panicf(PANIC_FATAL, "FTL: Detected a pool block leak!");
1867
        else if (ftl_cxt.freecount == 3)
166 theseven 1868
            if (ftl_remove_scattered_block(NULL) != 0)
1869
                return NULL;
2 theseven 1870
        entry = ftl_log;
54 theseven 1871
        while (entry->scatteredvblock != 0xFFFF) entry = &entry[1];
1872
        entry->scatteredvblock = ftl_allocate_pool_block();
1873
        if (entry->scatteredvblock == 0xFFFF)
166 theseven 1874
            return NULL;
2 theseven 1875
    }
1876
 
1877
    ftl_init_log_entry(entry);
54 theseven 1878
    entry->logicalvblock = block;
1879
    entry->usn = ftl_cxt.nextblockusn - 1;
2 theseven 1880
 
1881
    return entry;
1882
}
1883
#endif
1884
 
1885
 
1886
#ifndef FTL_READONLY
1887
/* Commits the FTL block map, erase counters, and context to flash */
66 theseven 1888
static uint32_t ftl_commit_cxt(void)
2 theseven 1889
{
1890
    uint32_t i;
54 theseven 1891
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1892
    uint32_t mappages = (ftl_nand_type->userblocks + 0x3ff) >> 10;
1893
    uint32_t ctrpages = (ftl_nand_type->userblocks + 23 + 0x3ff) >> 10;
2 theseven 1894
    uint32_t endpage = ftl_cxt.ftlctrlpage + mappages + ctrpages + 1;
61 theseven 1895
    DEBUGF("FTL: Committing context");
54 theseven 1896
    if (endpage >= (ftl_cxt.ftlctrlpage / ppb + 1) * ppb)
2 theseven 1897
        ftl_cxt.ftlctrlpage |= ppb - 1;
1898
    for (i = 0; i < ctrpages; i++)
1899
    {
1900
        if (ftl_next_ctrl_pool_page() != 0) return 1;
1901
        if (ftl_save_erasectr_page(i) != 0) return 1;
1902
    }
1903
    for (i = 0; i < mappages; i++)
1904
    {
1905
        if (ftl_next_ctrl_pool_page() != 0) return 1;
54 theseven 1906
        memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1907
        ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1908
        ftl_sparebuffer[0].meta.idx = i;
1909
        ftl_sparebuffer[0].meta.type = 0x44;
1910
        if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, &ftl_map[i << 10],
1911
                          &ftl_sparebuffer[0]) != 0)
2 theseven 1912
            return 1;
1913
        ftl_cxt.ftl_map_pages[i] = ftl_cxt.ftlctrlpage;
1914
    }
1915
    if (ftl_next_ctrl_pool_page() != 0) return 1;
1916
    ftl_cxt.clean_flag = 1;
54 theseven 1917
    memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1918
    ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1919
    ftl_sparebuffer[0].meta.type = 0x43;
1920
    if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, &ftl_cxt, &ftl_sparebuffer[0]) != 0)
2 theseven 1921
        return 1;
61 theseven 1922
    DEBUGF("FTL: Wrote context to page %d", ftl_cxt.ftlctrlpage);
2 theseven 1923
    return 0;
1924
}
1925
#endif
1926
 
1927
 
1928
#ifndef FTL_READONLY
1929
/* Swaps the most and least worn block on the flash,
1930
   to better distribute wear. It will refuse to do anything
1931
   if the wear spread is lower than 5 erases. */
66 theseven 1932
static uint32_t ftl_swap_blocks(void)
2 theseven 1933
{
1934
    uint32_t i;
1935
    uint32_t min = 0xFFFFFFFF, max = 0, maxidx = 0x14;
1936
    uint32_t minidx = 0, minvb = 0, maxvb = 0;
1937
    for (i = 0; i < ftl_cxt.freecount; i++)
1938
    {
1939
        uint32_t idx = ftl_cxt.nextfreeidx + i;
1940
        if (idx >= 0x14) idx -= 0x14;
1941
        if (ftl_erasectr[ftl_cxt.blockpool[idx]] > max)
1942
        {
1943
            maxidx = idx;
1944
            maxvb = ftl_cxt.blockpool[idx];
1945
            max = ftl_erasectr[maxidx];
1946
        }
1947
    }
1948
    if (maxidx == 0x14) return 0;
54 theseven 1949
    for (i = 0; i < ftl_nand_type->userblocks; i++)
2 theseven 1950
    {
1951
        if (ftl_erasectr[ftl_map[i]] > max) max = ftl_erasectr[ftl_map[i]];
166 theseven 1952
        if (ftl_get_log_entry(i) != NULL) continue;
2 theseven 1953
        if (ftl_erasectr[ftl_map[i]] < min)
1954
        {
1955
            minidx = i;
1956
            minvb = ftl_map[i];
1957
            min = ftl_erasectr[minidx];
1958
        }
1959
    }
1960
    if (max - min < 5) return 0;
1961
    if (minvb == maxvb) return 0;
1962
    if (ftl_erase_block(maxvb) != 0) return 1;
1963
    if (ftl_copy_block(minidx, maxvb) != 0) return 1;
1964
    ftl_cxt.blockpool[maxidx] = minvb;
1965
    ftl_map[minidx] = maxvb;
1966
    return 0;
1967
}
1968
#endif
1969
 
1970
 
1971
#ifndef FTL_READONLY
1972
/* Exposed function: Write highlevel sectors */
54 theseven 1973
uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer)
2 theseven 1974
{
54 theseven 1975
    uint32_t i, j, k;
1976
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1977
 
155 theseven 1978
    if (!ftl_initialized) return -1;
128 theseven 1979
 
54 theseven 1980
#ifdef FTL_TRACE
61 theseven 1981
    DEBUGF("FTL: Writing %d sectors starting at %d", count, sector);
54 theseven 1982
#endif
1983
 
201 theseven 1984
    if ((uint32_t)buffer & (CACHEALIGN_SIZE - 1))
1985
        panicf(PANIC_KILLTHREAD,
1986
               "ftl_write: Misaligned data buffer at %08X (sector %lu, count %lu)",
1987
               (unsigned int)buffer, sector, count);
68 theseven 1988
 
54 theseven 1989
    if (sector + count > ftl_nand_type->userblocks * ppb)
1990
    {
61 theseven 1991
        DEBUGF("FTL: Sector %d is out of range!", sector + count - 1);
155 theseven 1992
        return -2;
54 theseven 1993
    }
2 theseven 1994
    if (count == 0) return 0;
1995
 
54 theseven 1996
    mutex_lock(&ftl_mtx, TIMEOUT_BLOCK);
1997
 
2 theseven 1998
    if (ftl_cxt.clean_flag == 1)
1999
    {
2000
        for (i = 0; i < 3; i++)
2001
        {
201 theseven 2002
            DEBUGF("FTL: Marking dirty, try %d", i);
54 theseven 2003
            if (ftl_next_ctrl_pool_page() != 0)
2004
            {
2005
                mutex_unlock(&ftl_mtx);
155 theseven 2006
                return -3;
54 theseven 2007
            }
2 theseven 2008
            memset(ftl_buffer, 0xFF, 0x800);
54 theseven 2009
            memset(&ftl_sparebuffer[0], 0xFF, 0x40);
2010
            ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
2011
            ftl_sparebuffer[0].meta.type = 0x47;
2012
            if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, ftl_buffer,
2013
                              &ftl_sparebuffer[0]) == 0)
2 theseven 2014
                break;
2015
        }
54 theseven 2016
        if (i == 3)
2017
        {
2018
            mutex_unlock(&ftl_mtx);
155 theseven 2019
            return -4;
54 theseven 2020
        }
201 theseven 2021
        DEBUGF("FTL: Wrote dirty mark to %d", ftl_cxt.ftlctrlpage);
2 theseven 2022
        ftl_cxt.clean_flag = 0;
2023
    }
2024
 
2025
    for (i = 0; i < count; )
2026
    {
2027
        uint32_t block = (sector + i) / ppb;
2028
        uint32_t page = (sector + i) % ppb;
2029
 
2030
        struct ftl_log_type* logentry = ftl_allocate_log_entry(block);
166 theseven 2031
        if (logentry == NULL)
54 theseven 2032
        {
2033
            mutex_unlock(&ftl_mtx);
155 theseven 2034
            return -5;
54 theseven 2035
        }
2 theseven 2036
        if (page == 0 && count - i >= ppb)
2037
        {
54 theseven 2038
#ifdef FTL_TRACE
201 theseven 2039
            DEBUGF("FTL: Going to write a full hyperblock in one shot");
54 theseven 2040
#endif
2041
            uint32_t vblock = logentry->scatteredvblock;
2042
            logentry->scatteredvblock = 0xFFFF;
2043
            if (logentry->pagesused != 0)
2 theseven 2044
            {
54 theseven 2045
#ifdef FTL_TRACE
201 theseven 2046
                DEBUGF("FTL: Scattered block had some pages already used, committing");
54 theseven 2047
#endif
2 theseven 2048
                ftl_release_pool_block(vblock);
2049
                vblock = ftl_allocate_pool_block();
54 theseven 2050
                if (vblock == 0xFFFFFFFF)
2051
                {
2052
                    mutex_unlock(&ftl_mtx);
155 theseven 2053
                    return -6;
54 theseven 2054
                }
2 theseven 2055
            }
2056
            ftl_cxt.nextblockusn++;
54 theseven 2057
            for (j = 0; j < ppb; j += FTL_WRITESPARE_SIZE)
2 theseven 2058
            {
54 theseven 2059
                memset(&ftl_sparebuffer[0], 0xFF, 0x40 * FTL_WRITESPARE_SIZE);
2060
                for (k = 0; k < FTL_WRITESPARE_SIZE; k++)
2061
                {
2062
                    ftl_sparebuffer[k].user.lpn = sector + i + j + k;
2063
                    ftl_sparebuffer[k].user.usn = ftl_cxt.nextblockusn;
2064
                    ftl_sparebuffer[k].user.type = 0x40;
2065
                    if (j == ppb - 1) ftl_sparebuffer[k].user.type = 0x41;
2066
                }
2067
                uint32_t rc = ftl_vfl_write(vblock * ppb + j, FTL_WRITESPARE_SIZE,
2068
                                            &((uint8_t*)buffer)[(i + j) << 11],
2069
                                            &ftl_sparebuffer[0]);
2070
                if (rc)
2071
                    for (k = 0; k < ftl_banks; k++)
2072
                        if (rc & (1 << k))
2073
                        {
2074
                            while (ftl_vfl_write(vblock * ppb + j + k, 1,
2075
                                                 &((uint8_t*)buffer)[(i + j + k) << 11],
2076
                                                 &ftl_sparebuffer[k]));
2077
                        }
2 theseven 2078
            }
2079
            ftl_release_pool_block(ftl_map[block]);
2080
            ftl_map[block] = vblock;
2081
            i += ppb;
2082
        }
2083
        else
2084
        {
54 theseven 2085
            if (logentry->pagesused == ppb)
2 theseven 2086
            {
54 theseven 2087
#ifdef FTL_TRACE
201 theseven 2088
                DEBUGF("FTL: Scattered block is full, committing");
54 theseven 2089
#endif
2 theseven 2090
                ftl_remove_scattered_block(logentry);
2091
                logentry = ftl_allocate_log_entry(block);
166 theseven 2092
                if (logentry == NULL)
54 theseven 2093
                {
2094
                    mutex_unlock(&ftl_mtx);
155 theseven 2095
                    return -7;
54 theseven 2096
                }
2 theseven 2097
            }
54 theseven 2098
            uint32_t cnt = FTL_WRITESPARE_SIZE;
2099
            if (cnt > count - i) cnt = count - i;
2100
            if (cnt > ppb - logentry->pagesused) cnt = ppb - logentry->pagesused;
2101
            if (cnt > ppb - page) cnt = ppb - page;
2102
            memset(&ftl_sparebuffer[0], 0xFF, 0x40 * cnt);
2103
            for (j = 0; j < cnt; j++)
2 theseven 2104
            {
54 theseven 2105
                ftl_sparebuffer[j].user.lpn = sector + i + j;
2106
                ftl_sparebuffer[j].user.usn = ++ftl_cxt.nextblockusn;
2107
                ftl_sparebuffer[j].user.type = 0x40;
2108
                if (logentry->pagesused + j == ppb - 1 && logentry->issequential)
2109
                    ftl_sparebuffer[j].user.type = 0x41;
2 theseven 2110
            }
54 theseven 2111
            uint32_t abspage = logentry->scatteredvblock * ppb
2112
                             + logentry->pagesused;
2113
            logentry->pagesused += cnt;
2114
            if (ftl_vfl_write(abspage, cnt, &((uint8_t*)buffer)[i << 11],
2115
                              &ftl_sparebuffer[0]) == 0)
2116
            {
2117
                for (j = 0; j < cnt; j++)
2118
                {
2119
                    if (logentry->pageoffsets[page + j] == 0xFFFF)
2120
                        logentry->pagescurrent++;
2121
                    logentry->pageoffsets[page + j] = logentry->pagesused - cnt + j;
2122
                    if (logentry->pagesused - cnt + j + 1 != logentry->pagescurrent
2123
                     || logentry->pageoffsets[page + j] != page + j)
2124
                        logentry->issequential = 0;
2125
                }
2126
                i += cnt;
2127
            }
2128
            else panicf(PANIC_FATAL, "FTL: Write error: %u %u %u!",
2129
                        (unsigned)sector, (unsigned)count, (unsigned)i);
2 theseven 2130
        }
54 theseven 2131
        if (logentry->pagesused == ppb) ftl_remove_scattered_block(logentry);
2 theseven 2132
    }
2133
    if (ftl_cxt.swapcounter >= 300)
2134
    {
2135
        ftl_cxt.swapcounter -= 20;
2136
        for (i = 0; i < 4; i++) if (ftl_swap_blocks() == 0) break;
2137
    }
2138
    if (ftl_cxt.erasedirty == 1)
2139
    {
2140
        ftl_cxt.erasedirty = 0;
2141
        for (i = 0; i < 8; i++)
2142
            if (ftl_erasectr_dirt[i] >= 100)
2143
            {
2144
                ftl_next_ctrl_pool_page();
2145
                ftl_save_erasectr_page(i);
2146
            }
2147
    }
54 theseven 2148
    mutex_unlock(&ftl_mtx);
2 theseven 2149
    return 0;
2150
}
2151
#endif
2152
 
2153
 
2154
#ifndef FTL_READONLY
54 theseven 2155
/* Exposed function: Performes a sync / unmount,
2156
   i.e. commits all scattered page blocks,
2157
   distributes wear, and commits the FTL context. */
2158
uint32_t ftl_sync(void)
2 theseven 2159
{
2160
    uint32_t i;
2161
    uint32_t rc = 0;
54 theseven 2162
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
128 theseven 2163
 
206 theseven 2164
    if (!ftl_initialized) return 0;
128 theseven 2165
 
2 theseven 2166
    if (ftl_cxt.clean_flag == 1) return 0;
2167
 
66 theseven 2168
    mutex_lock(&ftl_mtx, TIMEOUT_BLOCK);
201 theseven 2169
 
54 theseven 2170
#ifdef FTL_TRACE
61 theseven 2171
    DEBUGF("FTL: Syncing");
54 theseven 2172
#endif
2173
 
2 theseven 2174
    if (ftl_cxt.swapcounter >= 20)
2175
        for (i = 0; i < 4; i++)
2176
            if (ftl_swap_blocks() == 0)
2177
            {
2178
                ftl_cxt.swapcounter -= 20;
2179
                break;
2180
            }
2181
    for (i = 0; i < 0x11; i++)
2182
    {
2183
        if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
2184
        ftl_cxt.nextblockusn++;
2185
        if (ftl_log[i].issequential == 1)
2186
            rc |= ftl_commit_sequential(&ftl_log[i]);
2187
        else rc |= ftl_commit_scattered(&ftl_log[i]);
2188
    }
54 theseven 2189
    if (rc != 0)
2190
    {
2191
        mutex_unlock(&ftl_mtx);
155 theseven 2192
        return -1;
54 theseven 2193
    }
2194
    for (i = 0; i < 5; i++)
2195
        if (ftl_commit_cxt() == 0)
2196
        {
2197
            mutex_unlock(&ftl_mtx);
2198
            return 0;
2199
        }
2200
        else ftl_cxt.ftlctrlpage |= ppb - 1;
2201
    mutex_unlock(&ftl_mtx);
155 theseven 2202
    return -2;
2 theseven 2203
}
2204
#endif
2205
 
2206
 
124 theseven 2207
/* Block allocator for FTL recovery */
2208
static uint32_t ftl_alloc_block() INITCODE_ATTR;
2209
static uint32_t ftl_alloc_block()
2210
{
2211
    while (1)
2212
    {
2213
        for (; firstfree < ftl_nand_type->userblocks + 0x17; firstfree++)
2214
            if (!blk_type[firstfree]) break;
2215
            else if (allocmode && blk_type[firstfree] != 1)
2216
            {
2217
                if (ftl_erase_block(firstfree))
2218
                {
2219
                    cprintf(CONSOLE_BOOT, "Couldn't erase vBlock %d (pool alloc)!\n", firstfree);
2220
                    return 1;
2221
                }
2222
                break;
2223
            }
2224
        if (firstfree < ftl_nand_type->userblocks + 0x17)
2225
        {
2226
            blk_type[firstfree] = 1;
2227
            return firstfree++;
2228
        }
2229
        if (!allocmode)
2230
        {
2231
            allocmode = 1;
2232
            firstfree = 0;
2233
        }
2234
        else
2235
        {
2236
            cputs(CONSOLE_BOOT, "Out of empty blocks!\n");
2237
            return 1;
2238
        }
2239
    }
2240
}
2241
 
2242
 
2243
static uint32_t ftl_repair(void) INITCODE_ATTR;
2244
static uint32_t ftl_repair()
2245
{
2246
    uint32_t i, j, k;
2247
#ifdef HAVE_LCD
2248
    struct progressbar_state progressbar;
2249
#endif
2250
 
2251
    cputs(CONSOLE_BOOT, "Scanning flash...\n");
2252
#ifdef HAVE_LCD
2253
    lcdconsole_progressbar(&progressbar, 0, ftl_nand_type->userblocks + 0x17);
2254
#endif
2255
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
223 theseven 2256
    memset(&ftl_cxt, 0x00, sizeof(ftl_cxt));
2257
    memset(ftl_map, 0xff, sizeof(ftl_map));
2258
    memset(blk_usn, 0x00, sizeof(blk_usn));
2259
    memset(blk_type, 0x00, sizeof(blk_type));
2260
    memset(ftl_erasectr, 0x00, sizeof(ftl_erasectr));
2261
    memset(erasectr_usn, 0xff, sizeof(erasectr_usn));
124 theseven 2262
    user_usn = 0;
2263
    meta_usn = 0xffffffff;
2264
    for (i = 0; i < ftl_nand_type->userblocks + 0x17; i++)
2265
    {
2266
        uint32_t ret = ftl_vfl_read((i + 1) * ppb - 1, 0, &ftl_sparebuffer[0], 1, 0);
2267
        if ((ret & 0x11F) == 0 && ftl_sparebuffer[0].meta.type == 0x41)
2268
        {
2269
            uint32_t lbn = ftl_sparebuffer[0].user.lpn / ppb;
2270
            if (ftl_sparebuffer[0].user.usn > user_usn)
2271
                user_usn = ftl_sparebuffer[0].user.usn;
2272
            if (ftl_sparebuffer[0].user.usn > blk_usn[lbn])
2273
            {
2274
                if (ftl_map[lbn] != 0xffff)
2275
                    blk_type[ftl_map[lbn]] = 5;
2276
                blk_usn[lbn] = ftl_sparebuffer[0].user.usn;
2277
                ftl_map[lbn] = i;
2278
                blk_type[i] = 1;
2279
            }
2280
            else blk_type[i] = 5;
2281
        }
2282
        else
2283
            for (j = 0; j < ppb; j++)
2284
            {
2285
                ret = ftl_vfl_read(i * ppb + j, 0, &ftl_sparebuffer[0], 1, 0);
2286
                if (ret & 2) break;
2287
                if (ret & 0x11F)
2288
                {
2289
                    blk_type[i] = 4;
2290
                    continue;
2291
                }
2292
                if (ftl_sparebuffer[0].meta.type == 0x40)
2293
                {
2294
                    blk_type[i] = 2;
2295
                    break;
2296
                }
2297
                else if (ftl_sparebuffer[0].meta.type - 0x43 <= 4)
2298
                {
2299
                    blk_type[i] = 3;
2300
                    if (ftl_sparebuffer[0].meta.type == 0x46)
2301
                    {
2302
                        uint32_t idx = ftl_sparebuffer[0].meta.idx;
2303
                        if (ftl_sparebuffer[0].meta.usn < meta_usn)
2304
                            meta_usn = ftl_sparebuffer[0].meta.usn;
2305
                        if (ftl_sparebuffer[0].meta.usn < erasectr_usn[idx])
2306
                        {
2307
                            erasectr_usn[idx] = ftl_sparebuffer[0].meta.usn;
2308
                            ret = ftl_vfl_read(i * ppb + j, &ftl_erasectr[idx << 10],
2309
                                               &ftl_sparebuffer[0], 1, 0);
2310
                            if (ret & 0x11f) memset(&ftl_erasectr[idx << 10], 0, 0x800);
2311
                        }
2312
                    }
2313
                }
2314
                else
2315
                {
2316
                    cprintf(CONSOLE_BOOT, "Invalid block type %02X while reading vPage %d\n",
2317
                            ftl_sparebuffer[0].meta.type, i * ppb + j);
2318
                    return 1;
2319
                }
2320
            }
2321
#ifdef HAVE_LCD
2322
        progressbar_setpos(&progressbar, i + 1, false);
2323
#endif
2324
    }
2325
 
2326
    uint32_t sum = 0;
2327
    uint32_t count = 0;
2328
    for (i = 0; i < 0x2000; i++)
2329
        if (ftl_erasectr[i])
2330
        {
2331
            sum += ftl_erasectr[i];
2332
            count++;
2333
        }
213 theseven 2334
    uint32_t average = 0;
2335
    if (count) average = sum / count;
124 theseven 2336
    for (i = 0; i < 0x2000; i++)
2337
        if (!ftl_erasectr[i])
2338
            ftl_erasectr[i] = average;
2339
 
2340
    cputs(CONSOLE_BOOT, "Committing scattered pages...\n");
2341
    count = 0;
2342
    for (i = 0; i < ftl_nand_type->userblocks + 0x17; i++)
2343
        if (blk_type[i] == 2) count++;
2344
    uint32_t block;
2345
    uint32_t dirty;
2346
    if (count)
2347
    {
2348
#ifdef HAVE_LCD
134 theseven 2349
        lcdconsole_progressbar(&progressbar, 0, count * ppb * 2);
124 theseven 2350
#endif
2351
        count = 0;
2352
        for (i = 0; i < ftl_nand_type->userblocks + 0x17; i++)
2353
            if (blk_type[i] == 2)
2354
            {
2355
                block = 0xffff;
134 theseven 2356
                for (j = 0; j < ppb; j++)
124 theseven 2357
                {
134 theseven 2358
#ifdef HAVE_LCD
2359
                    progressbar_setpos(&progressbar, count * ppb * 2 + j, false);
2360
#endif
124 theseven 2361
                    uint32_t ret = ftl_vfl_read(i * ppb + j, ftl_buffer,
2362
                                                &ftl_sparebuffer[0], 1, 0);
2363
                    if (ret & 0x11F) continue;
2364
                    if (ftl_sparebuffer[0].user.type != 0x40)
2365
                    {
2366
                        cprintf(CONSOLE_BOOT, "Invalid block type %02X while reading "
2367
                                              "vPage %d (scattered page)!\n",
2368
                                ftl_sparebuffer[0].meta.type, i * ppb + j);
2369
                        return 1;
2370
                    }
2371
                    if (block == 0xffff)
2372
                    {
2373
                        block = ftl_sparebuffer[0].user.lpn / ppb;
2374
                        memset(pageusn, 0x00, 0x800);
2375
                        memset(pagedata, 0x00, 0x100000);
2376
                        if (ftl_map[block] != 0xffff)
2377
                            for (k = 0; k < ppb; k++)
2378
                            {
2379
                                uint32_t ret = ftl_vfl_read(ftl_map[block] * ppb + k, pagedata[k],
2380
                                                            &ftl_copyspare[0], 1, 0);
2381
                                if (ret & 0x11F) continue;
2382
                                if (ftl_copyspare[0].user.type != 0x40
2383
                                 && ftl_copyspare[0].user.type != 0x41)
2384
                                {
2385
                                    cprintf(CONSOLE_BOOT, "Invalid block type %02X while reading "
2386
                                                          "vPage %d (scattered page orig)!\n",
2387
                                            ftl_sparebuffer[0].meta.type,
2388
                                            ftl_map[block] * ppb + k);
2389
                                    return 1;
2390
                                }
2391
                                if (block != ftl_copyspare[0].user.lpn / ppb)
2392
                                {
2393
                                    cprintf(CONSOLE_BOOT, "Foreign page in scattered page orig "
2394
                                                          "block (vPage %d, LPN %d)!\n",
2395
                                            ftl_map[block] * ppb + k,
2396
                                            ftl_sparebuffer[0].user.usn);
2397
                                    return 1;
2398
                                }
2399
                                pageusn[k] = ftl_copyspare[0].user.usn;
2400
                            }
2401
                        dirty = 0;
2402
                    }
2403
                    if (block != ftl_sparebuffer[0].user.lpn / ppb)
2404
                    {
2405
                        cprintf(CONSOLE_BOOT, "Foreign page in scattered page block "
2406
                                              "block (vPage %d, LPN %d)!\n",
2407
                                i * ppb + j, ftl_sparebuffer[0].user.lpn);
2408
                        return 1;
2409
                    }
2410
                    uint32_t idx = ftl_sparebuffer[0].user.lpn % ppb;
2411
                    if (ftl_sparebuffer[0].user.usn > user_usn)
2412
                        user_usn = ftl_sparebuffer[0].user.usn;
2413
                    if (ftl_sparebuffer[0].user.usn > pageusn[idx])
2414
                    {
2415
                        pageusn[idx] = ftl_sparebuffer[0].user.usn;
2416
                        memcpy(pagedata[idx], ftl_buffer, 0x800);
2417
                        dirty = 1;
2418
                    }
2419
                }
2420
                if (dirty)
2421
                {
2422
                    if (ftl_erase_block(i))
2423
                    {
2424
                        cprintf(CONSOLE_BOOT, "Couldn't erase vBlock %d "
2425
                                              "(scattered page commit)!\n", i);
2426
                        return 1;
2427
                    }
2428
                    for (j = 0; j < ppb; j++)
2429
                    {
134 theseven 2430
#ifdef HAVE_LCD
2431
                        progressbar_setpos(&progressbar, count * ppb * 2 + ppb + j, false);
2432
#endif
124 theseven 2433
                        memset(&ftl_sparebuffer[0], 0xFF, 0x40);
2434
                        ftl_sparebuffer[0].user.lpn = block * ppb + j;
2435
                        ftl_sparebuffer[0].user.usn = pageusn[j];
2436
                        ftl_sparebuffer[0].user.type = 0x40;
2437
                        if (j == ppb - 1) ftl_sparebuffer[0].user.type = 0x41;
2438
                        if (ftl_vfl_write(i * ppb + j, 1, pagedata[j], &ftl_sparebuffer[0]))
2439
                        {
2440
                            cprintf(CONSOLE_BOOT, "Couldn't write vPage %d "
2441
                                                  "(scattered page commit)!\n", i * ppb + j);
2442
                            return 1;
2443
                        }
2444
                    }
2445
                    if (ftl_map[block] != 0xffff) blk_type[ftl_map[block]] = 5;
2446
                    blk_type[i] = 1;
2447
                    ftl_map[block] = i;
2448
                }
2449
                else blk_type[i] = 5;
2450
#ifdef HAVE_LCD
134 theseven 2451
                progressbar_setpos(&progressbar, ++count * ppb * 2, false);
124 theseven 2452
#endif
2453
            }
2454
    }
2455
 
2456
    cputs(CONSOLE_BOOT, "Fixing block map...\n");
2457
    allocmode = 0;
2458
    firstfree = 0;
2459
    for (i = 0; i < 3; i++) ftl_cxt.ftlctrlblocks[i] = ftl_alloc_block();
2460
    for (i = 0; i < 20; i++) ftl_cxt.blockpool[i] = ftl_alloc_block();
2461
    for (i = 0; i < ftl_nand_type->userblocks; i++)
2462
        if (ftl_map[i] == 0xffff)
2463
            ftl_map[i] = ftl_alloc_block();
2464
    ftl_cxt.usn = meta_usn - 1;
2465
    ftl_cxt.nextblockusn = user_usn + 1;
2466
    ftl_cxt.freecount = 20;
2467
    ftl_cxt.clean_flag = 1;
2468
 
2469
    cputs(CONSOLE_BOOT, "Committing FTL context...\n");
2470
    uint32_t blockmappages = ftl_nand_type->userblocks >> 10;
2471
    if ((ftl_nand_type->userblocks & 0x1FF) != 0) blockmappages++;
2472
    uint32_t erasectrpages = (ftl_nand_type->userblocks + 23) >> 10;
2473
    if (((ftl_nand_type->userblocks + 23) & 0x1FF) != 0) erasectrpages++;
2474
    uint32_t page = ftl_cxt.ftlctrlblocks[0] * ppb;
2475
    for (i = 0; i < erasectrpages; i++)
2476
    {
2477
        memset(&ftl_sparebuffer, 0xFF, 0x40);
2478
        ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
2479
        ftl_sparebuffer[0].meta.idx = i;
2480
        ftl_sparebuffer[0].meta.type = 0x46;
2481
        if (ftl_vfl_write(page, 1, &ftl_erasectr[i << 10], &ftl_sparebuffer[0]))
2482
        {
2483
            cprintf(CONSOLE_BOOT, "Couldn't write vPage %d (save erase counters)!\n", page);
2484
            return 1;
2485
        }
2486
        ftl_cxt.ftl_erasectr_pages[i] = page++;
2487
    }
2488
    for (i = 0; i < blockmappages; i++)
2489
    {
2490
        memset(&ftl_sparebuffer[0], 0xFF, 0x40);
2491
        ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
2492
        ftl_sparebuffer[0].meta.idx = i;
2493
        ftl_sparebuffer[0].meta.type = 0x44;
2494
        if (ftl_vfl_write(page, 1, &ftl_map[i << 10], &ftl_sparebuffer[0]))
2495
        {
2496
            cprintf(CONSOLE_BOOT, "Couldn't write vPage %d (save block map)!\n", page);
2497
            return 1;
2498
        }
2499
        ftl_cxt.ftl_map_pages[i] = page++;
2500
    }
2501
    ftl_cxt.ftlctrlpage = page;
2502
    memset(&ftl_sparebuffer[0], 0xFF, 0x40);
2503
    ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
2504
    ftl_sparebuffer[0].meta.type = 0x43;
2505
    if (ftl_vfl_write(page, 1, &ftl_cxt, &ftl_sparebuffer[0]))
2506
    {
2507
        cprintf(CONSOLE_BOOT, "Couldn't write vPage %d (save FTL context)!\n", page);
2508
        return 1;
2509
    }
2510
    ftl_store_ctrl_block_list();
134 theseven 2511
    return 0;
124 theseven 2512
}
2513
 
2514
 
2 theseven 2515
/* Initializes and mounts the FTL.
2516
   As long as nothing was written, you won't need to unmount it.
54 theseven 2517
   Before shutting down after writing something, call ftl_sync(),
124 theseven 2518
   which will return immediately if everything was already clean. */
54 theseven 2519
uint32_t ftl_init(void)
2 theseven 2520
{
210 theseven 2521
    if (ftl_initialized) return 0;
54 theseven 2522
    mutex_init(&ftl_mtx);
2 theseven 2523
    uint32_t i;
61 theseven 2524
    int rc;
223 theseven 2525
    if ((rc = nand_device_init()) != 0)
61 theseven 2526
        panicf(PANIC_FATAL, "FTL: Lowlevel NAND driver init failed: %d", rc);
2 theseven 2527
    ftl_banks = 0;
2528
    for (i = 0; i < 4; i++)
2529
        if (nand_get_device_type(i) != 0) ftl_banks = i + 1;
2530
    ftl_nand_type = nand_get_device_type(0);
54 theseven 2531
 
223 theseven 2532
    if (!ftl_has_devinfo())
54 theseven 2533
    {
201 theseven 2534
           DEBUGF("FTL: No DEVICEINFO found!");
155 theseven 2535
        return -1;
54 theseven 2536
    }
2 theseven 2537
    if (ftl_vfl_open() == 0)
201 theseven 2538
    {
2 theseven 2539
        if (ftl_open() == 0)
128 theseven 2540
        {
2541
            ftl_initialized = true;
2 theseven 2542
            return 0;
128 theseven 2543
        }
211 theseven 2544
        cputs(CONSOLE_BOOT, "The FTL seems to be damaged. Forcing check.\n");
201 theseven 2545
        if (ftl_repair() != 0)
211 theseven 2546
            cputs(CONSOLE_BOOT, "FTL recovery failed. Use disk mode to recover.\n");
201 theseven 2547
        else
2548
        {
211 theseven 2549
            cputs(CONSOLE_BOOT, "FTL recovery finished. Trying to mount again...\n");
201 theseven 2550
            if (ftl_open() == 0)
128 theseven 2551
            {
211 theseven 2552
                cputs(CONSOLE_BOOT, "Mount succeeded.\n");
128 theseven 2553
                ftl_initialized = true;
2554
                return 0;
2555
            }
211 theseven 2556
            cputs(CONSOLE_BOOT, "Mounting FTL failed again, use disk mode to recover.\n");
201 theseven 2557
        }
2558
    }
2 theseven 2559
 
54 theseven 2560
    DEBUGF("FTL: Initialization failed!");
2561
 
223 theseven 2562
    return -2;
2 theseven 2563
}