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;
128 theseven 434
bool ftl_initialized;
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,
485
                        (uint32_t*)0, 1, 0) & 0x11F) != 0) return 1;
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,
499
                                (void*)0, 1, 0) & 0x11F) == 0)
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;
631
    struct ftl_vfl_cxt_type* cxt = (struct ftl_vfl_cxt_type*)0;
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)
54 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;
54 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!",
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!",
820
	       (unsigned)bank, (unsigned)block);
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)
907
	{
908
        DEBUGF("FTL: Trying to read out-of-bounds vPage %u", (unsigned)vpage);
909
        return 4;
910
	}
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
        {
923
            void* databuf = (void*)0;
924
            void* sparebuf = (void*)0;
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)
983
	{
984
        DEBUGF("FTL: Trying to write out-of-bounds vPage %u",
985
               (unsigned)vpage);
986
        return 4;
987
	}
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)
1098
						{
1099
                            DEBUGF("FTL: No VFL CXT block found on bank %u!",
1100
                                   (unsigned)i);
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
1129
		{
54 theseven 1130
            DEBUGF("FTL: Couldn't load bank %u lowlevel BBT!", (unsigned)i);
2 theseven 1131
		    return 1;
1132
		}
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)
1195
	{
1196
        DEBUGF("FTL: Couldn't find FTL CXT page!");
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)
1208
		{
1209
            DEBUGF("FTL: Failed to read block map page %u", (unsigned)i);
2 theseven 1210
            return 1;
54 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)
1228
		{
1229
            DEBUGF("FTL: Failed to read erase counter page %u", (unsigned)i);
2 theseven 1230
            return 1;
54 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
    }
1302
    return (struct ftl_log_type*)0;
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
 
128 theseven 1313
    if (!ftl_initialized) return 1;
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
 
69 theseven 1319
	if ((uint32_t)buffer & (CACHEALIGN_SIZE - 1))
68 theseven 1320
		panicf(PANIC_KILLTHREAD,
1321
		       "ftl_read: Misaligned data buffer at %08X (sector %lu, count %lu)",
1322
			   (unsigned int)buffer, sector, count);
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);
2 theseven 1327
        return 1;
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);
1341
        if (logentry != (struct ftl_log_type*)0)
1342
        {
54 theseven 1343
#ifdef FTL_TRACE
61 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
61 theseven 1350
   		     DEBUGF("FTL: Found page %d at block %d, page %d", page,
54 theseven 1351
          		    (*logentry).scatteredvblock, (*logentry).pageoffsets[page]);
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))
1361
         && logentry == (struct ftl_log_type*)0)
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
                {
61 theseven 1373
		            DEBUGF("FTL: Error while reading sector %d!", (sector + i));
54 theseven 1374
                    error = 1;
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
            {
61 theseven 1386
	            DEBUGF("FTL: Error while reading sector %d!", (sector + i));
54 theseven 1387
                error = 1;
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;
1800
    if (entry == (struct ftl_log_type*)0)
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
        }
1815
        if (entry == (struct ftl_log_type*)0) return 1;
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);
54 theseven 1848
    entry->usn = ftl_cxt.nextblockusn - 1;
2 theseven 1849
    if (entry != (struct ftl_log_type*)0) return entry;
1850
 
1851
    for (i = 0; i < 0x11; i++)
1852
    {
1853
        if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
1854
        if (ftl_log[i].pagesused == 0)
1855
        {
1856
            entry = &ftl_log[i];
1857
            break;
1858
        }
1859
    }
1860
 
1861
    if (entry == (struct ftl_log_type*)0)
1862
    {
54 theseven 1863
        if (ftl_cxt.freecount < 3) panicf(PANIC_FATAL, "FTL: Detected a pool block leak!");
1864
        else if (ftl_cxt.freecount == 3)
2 theseven 1865
            if (ftl_remove_scattered_block((struct ftl_log_type*)0) != 0)
1866
                return (struct ftl_log_type*)0;
1867
        entry = ftl_log;
54 theseven 1868
        while (entry->scatteredvblock != 0xFFFF) entry = &entry[1];
1869
        entry->scatteredvblock = ftl_allocate_pool_block();
1870
        if (entry->scatteredvblock == 0xFFFF)
2 theseven 1871
            return (struct ftl_log_type*)0;
1872
    }
1873
 
1874
    ftl_init_log_entry(entry);
54 theseven 1875
    entry->logicalvblock = block;
1876
    entry->usn = ftl_cxt.nextblockusn - 1;
2 theseven 1877
 
1878
    return entry;
1879
}
1880
#endif
1881
 
1882
 
1883
#ifndef FTL_READONLY
1884
/* Commits the FTL block map, erase counters, and context to flash */
66 theseven 1885
static uint32_t ftl_commit_cxt(void)
2 theseven 1886
{
1887
    uint32_t i;
54 theseven 1888
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1889
    uint32_t mappages = (ftl_nand_type->userblocks + 0x3ff) >> 10;
1890
    uint32_t ctrpages = (ftl_nand_type->userblocks + 23 + 0x3ff) >> 10;
2 theseven 1891
    uint32_t endpage = ftl_cxt.ftlctrlpage + mappages + ctrpages + 1;
61 theseven 1892
    DEBUGF("FTL: Committing context");
54 theseven 1893
    if (endpage >= (ftl_cxt.ftlctrlpage / ppb + 1) * ppb)
2 theseven 1894
        ftl_cxt.ftlctrlpage |= ppb - 1;
1895
    for (i = 0; i < ctrpages; i++)
1896
    {
1897
        if (ftl_next_ctrl_pool_page() != 0) return 1;
1898
        if (ftl_save_erasectr_page(i) != 0) return 1;
1899
    }
1900
    for (i = 0; i < mappages; i++)
1901
    {
1902
        if (ftl_next_ctrl_pool_page() != 0) return 1;
54 theseven 1903
        memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1904
        ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1905
        ftl_sparebuffer[0].meta.idx = i;
1906
        ftl_sparebuffer[0].meta.type = 0x44;
1907
        if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, &ftl_map[i << 10],
1908
                          &ftl_sparebuffer[0]) != 0)
2 theseven 1909
            return 1;
1910
        ftl_cxt.ftl_map_pages[i] = ftl_cxt.ftlctrlpage;
1911
    }
1912
    if (ftl_next_ctrl_pool_page() != 0) return 1;
1913
    ftl_cxt.clean_flag = 1;
54 theseven 1914
    memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1915
    ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1916
    ftl_sparebuffer[0].meta.type = 0x43;
1917
    if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, &ftl_cxt, &ftl_sparebuffer[0]) != 0)
2 theseven 1918
        return 1;
61 theseven 1919
    DEBUGF("FTL: Wrote context to page %d", ftl_cxt.ftlctrlpage);
2 theseven 1920
    return 0;
1921
}
1922
#endif
1923
 
1924
 
1925
#ifndef FTL_READONLY
1926
/* Swaps the most and least worn block on the flash,
1927
   to better distribute wear. It will refuse to do anything
1928
   if the wear spread is lower than 5 erases. */
66 theseven 1929
static uint32_t ftl_swap_blocks(void)
2 theseven 1930
{
1931
    uint32_t i;
1932
    uint32_t min = 0xFFFFFFFF, max = 0, maxidx = 0x14;
1933
    uint32_t minidx = 0, minvb = 0, maxvb = 0;
1934
    for (i = 0; i < ftl_cxt.freecount; i++)
1935
    {
1936
        uint32_t idx = ftl_cxt.nextfreeidx + i;
1937
        if (idx >= 0x14) idx -= 0x14;
1938
        if (ftl_erasectr[ftl_cxt.blockpool[idx]] > max)
1939
        {
1940
            maxidx = idx;
1941
            maxvb = ftl_cxt.blockpool[idx];
1942
            max = ftl_erasectr[maxidx];
1943
        }
1944
    }
1945
    if (maxidx == 0x14) return 0;
54 theseven 1946
    for (i = 0; i < ftl_nand_type->userblocks; i++)
2 theseven 1947
    {
1948
        if (ftl_erasectr[ftl_map[i]] > max) max = ftl_erasectr[ftl_map[i]];
1949
        if (ftl_get_log_entry(i) != (struct ftl_log_type*)0) continue;
1950
        if (ftl_erasectr[ftl_map[i]] < min)
1951
        {
1952
            minidx = i;
1953
            minvb = ftl_map[i];
1954
            min = ftl_erasectr[minidx];
1955
        }
1956
    }
1957
    if (max - min < 5) return 0;
1958
    if (minvb == maxvb) return 0;
1959
    if (ftl_erase_block(maxvb) != 0) return 1;
1960
    if (ftl_copy_block(minidx, maxvb) != 0) return 1;
1961
    ftl_cxt.blockpool[maxidx] = minvb;
1962
    ftl_map[minidx] = maxvb;
1963
    return 0;
1964
}
1965
#endif
1966
 
1967
 
1968
#ifndef FTL_READONLY
1969
/* Exposed function: Write highlevel sectors */
54 theseven 1970
uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer)
2 theseven 1971
{
54 theseven 1972
    uint32_t i, j, k;
1973
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1974
 
128 theseven 1975
    if (!ftl_initialized) return 1;
1976
 
54 theseven 1977
#ifdef FTL_TRACE
61 theseven 1978
    DEBUGF("FTL: Writing %d sectors starting at %d", count, sector);
54 theseven 1979
#endif
1980
 
69 theseven 1981
	if ((uint32_t)buffer & (CACHEALIGN_SIZE - 1))
68 theseven 1982
		panicf(PANIC_KILLTHREAD,
1983
		       "ftl_write: Misaligned data buffer at %08X (sector %lu, count %lu)",
1984
			   (unsigned int)buffer, sector, count);
1985
 
54 theseven 1986
    if (sector + count > ftl_nand_type->userblocks * ppb)
1987
    {
61 theseven 1988
        DEBUGF("FTL: Sector %d is out of range!", sector + count - 1);
2 theseven 1989
        return 1;
54 theseven 1990
    }
2 theseven 1991
    if (count == 0) return 0;
1992
 
54 theseven 1993
    mutex_lock(&ftl_mtx, TIMEOUT_BLOCK);
1994
 
2 theseven 1995
    if (ftl_cxt.clean_flag == 1)
1996
    {
1997
        for (i = 0; i < 3; i++)
1998
        {
61 theseven 1999
		    DEBUGF("FTL: Marking dirty, try %d", i);
54 theseven 2000
            if (ftl_next_ctrl_pool_page() != 0)
2001
            {
2002
                mutex_unlock(&ftl_mtx);
2003
                return 1;
2004
            }
2 theseven 2005
            memset(ftl_buffer, 0xFF, 0x800);
54 theseven 2006
            memset(&ftl_sparebuffer[0], 0xFF, 0x40);
2007
            ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
2008
            ftl_sparebuffer[0].meta.type = 0x47;
2009
            if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, ftl_buffer,
2010
                              &ftl_sparebuffer[0]) == 0)
2 theseven 2011
                break;
2012
        }
54 theseven 2013
        if (i == 3)
2014
        {
2015
            mutex_unlock(&ftl_mtx);
2016
            return 1;
2017
        }
61 theseven 2018
    	DEBUGF("FTL: Wrote dirty mark to %d", ftl_cxt.ftlctrlpage);
2 theseven 2019
        ftl_cxt.clean_flag = 0;
2020
    }
2021
 
2022
    for (i = 0; i < count; )
2023
    {
2024
        uint32_t block = (sector + i) / ppb;
2025
        uint32_t page = (sector + i) % ppb;
2026
 
2027
        struct ftl_log_type* logentry = ftl_allocate_log_entry(block);
54 theseven 2028
        if (logentry == (struct ftl_log_type*)0)
2029
        {
2030
            mutex_unlock(&ftl_mtx);
2031
            return 1;
2032
        }
2 theseven 2033
        if (page == 0 && count - i >= ppb)
2034
        {
54 theseven 2035
#ifdef FTL_TRACE
61 theseven 2036
		    DEBUGF("FTL: Going to write a full hyperblock in one shot");
54 theseven 2037
#endif
2038
            uint32_t vblock = logentry->scatteredvblock;
2039
            logentry->scatteredvblock = 0xFFFF;
2040
            if (logentry->pagesused != 0)
2 theseven 2041
            {
54 theseven 2042
#ifdef FTL_TRACE
61 theseven 2043
    			DEBUGF("FTL: Scattered block had some pages already used, committing");
54 theseven 2044
#endif
2 theseven 2045
                ftl_release_pool_block(vblock);
2046
                vblock = ftl_allocate_pool_block();
54 theseven 2047
                if (vblock == 0xFFFFFFFF)
2048
                {
2049
                    mutex_unlock(&ftl_mtx);
2050
                    return 1;
2051
                }
2 theseven 2052
            }
2053
            ftl_cxt.nextblockusn++;
54 theseven 2054
            for (j = 0; j < ppb; j += FTL_WRITESPARE_SIZE)
2 theseven 2055
            {
54 theseven 2056
                memset(&ftl_sparebuffer[0], 0xFF, 0x40 * FTL_WRITESPARE_SIZE);
2057
                for (k = 0; k < FTL_WRITESPARE_SIZE; k++)
2058
                {
2059
                    ftl_sparebuffer[k].user.lpn = sector + i + j + k;
2060
                    ftl_sparebuffer[k].user.usn = ftl_cxt.nextblockusn;
2061
                    ftl_sparebuffer[k].user.type = 0x40;
2062
                    if (j == ppb - 1) ftl_sparebuffer[k].user.type = 0x41;
2063
                }
2064
                uint32_t rc = ftl_vfl_write(vblock * ppb + j, FTL_WRITESPARE_SIZE,
2065
                                            &((uint8_t*)buffer)[(i + j) << 11],
2066
                                            &ftl_sparebuffer[0]);
2067
                if (rc)
2068
                    for (k = 0; k < ftl_banks; k++)
2069
                        if (rc & (1 << k))
2070
                        {
2071
                            while (ftl_vfl_write(vblock * ppb + j + k, 1,
2072
                                                 &((uint8_t*)buffer)[(i + j + k) << 11],
2073
                                                 &ftl_sparebuffer[k]));
2074
                        }
2 theseven 2075
            }
2076
            ftl_release_pool_block(ftl_map[block]);
2077
            ftl_map[block] = vblock;
2078
            i += ppb;
2079
        }
2080
        else
2081
        {
54 theseven 2082
            if (logentry->pagesused == ppb)
2 theseven 2083
            {
54 theseven 2084
#ifdef FTL_TRACE
61 theseven 2085
    			DEBUGF("FTL: Scattered block is full, committing");
54 theseven 2086
#endif
2 theseven 2087
                ftl_remove_scattered_block(logentry);
2088
                logentry = ftl_allocate_log_entry(block);
54 theseven 2089
                if (logentry == (struct ftl_log_type*)0)
2090
                {
2091
                    mutex_unlock(&ftl_mtx);
2092
                    return 1;
2093
                }
2 theseven 2094
            }
54 theseven 2095
            uint32_t cnt = FTL_WRITESPARE_SIZE;
2096
            if (cnt > count - i) cnt = count - i;
2097
            if (cnt > ppb - logentry->pagesused) cnt = ppb - logentry->pagesused;
2098
            if (cnt > ppb - page) cnt = ppb - page;
2099
            memset(&ftl_sparebuffer[0], 0xFF, 0x40 * cnt);
2100
            for (j = 0; j < cnt; j++)
2 theseven 2101
            {
54 theseven 2102
                ftl_sparebuffer[j].user.lpn = sector + i + j;
2103
                ftl_sparebuffer[j].user.usn = ++ftl_cxt.nextblockusn;
2104
                ftl_sparebuffer[j].user.type = 0x40;
2105
                if (logentry->pagesused + j == ppb - 1 && logentry->issequential)
2106
                    ftl_sparebuffer[j].user.type = 0x41;
2 theseven 2107
            }
54 theseven 2108
            uint32_t abspage = logentry->scatteredvblock * ppb
2109
                             + logentry->pagesused;
2110
            logentry->pagesused += cnt;
2111
            if (ftl_vfl_write(abspage, cnt, &((uint8_t*)buffer)[i << 11],
2112
                              &ftl_sparebuffer[0]) == 0)
2113
            {
2114
                for (j = 0; j < cnt; j++)
2115
                {
2116
                    if (logentry->pageoffsets[page + j] == 0xFFFF)
2117
                        logentry->pagescurrent++;
2118
                    logentry->pageoffsets[page + j] = logentry->pagesused - cnt + j;
2119
                    if (logentry->pagesused - cnt + j + 1 != logentry->pagescurrent
2120
                     || logentry->pageoffsets[page + j] != page + j)
2121
                        logentry->issequential = 0;
2122
                }
2123
                i += cnt;
2124
            }
2125
            else panicf(PANIC_FATAL, "FTL: Write error: %u %u %u!",
2126
                        (unsigned)sector, (unsigned)count, (unsigned)i);
2 theseven 2127
        }
54 theseven 2128
        if (logentry->pagesused == ppb) ftl_remove_scattered_block(logentry);
2 theseven 2129
    }
2130
    if (ftl_cxt.swapcounter >= 300)
2131
    {
2132
        ftl_cxt.swapcounter -= 20;
2133
        for (i = 0; i < 4; i++) if (ftl_swap_blocks() == 0) break;
2134
    }
2135
    if (ftl_cxt.erasedirty == 1)
2136
    {
2137
        ftl_cxt.erasedirty = 0;
2138
        for (i = 0; i < 8; i++)
2139
            if (ftl_erasectr_dirt[i] >= 100)
2140
            {
2141
                ftl_next_ctrl_pool_page();
2142
                ftl_save_erasectr_page(i);
2143
            }
2144
    }
54 theseven 2145
    mutex_unlock(&ftl_mtx);
2 theseven 2146
    return 0;
2147
}
2148
#endif
2149
 
2150
 
2151
#ifndef FTL_READONLY
54 theseven 2152
/* Exposed function: Performes a sync / unmount,
2153
   i.e. commits all scattered page blocks,
2154
   distributes wear, and commits the FTL context. */
2155
uint32_t ftl_sync(void)
2 theseven 2156
{
2157
    uint32_t i;
2158
    uint32_t rc = 0;
54 theseven 2159
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
128 theseven 2160
 
2161
    if (!ftl_initialized) return 1;
2162
 
2 theseven 2163
    if (ftl_cxt.clean_flag == 1) return 0;
2164
 
66 theseven 2165
    mutex_lock(&ftl_mtx, TIMEOUT_BLOCK);
2166
 
54 theseven 2167
#ifdef FTL_TRACE
61 theseven 2168
    DEBUGF("FTL: Syncing");
54 theseven 2169
#endif
2170
 
2 theseven 2171
    if (ftl_cxt.swapcounter >= 20)
2172
        for (i = 0; i < 4; i++)
2173
            if (ftl_swap_blocks() == 0)
2174
            {
2175
                ftl_cxt.swapcounter -= 20;
2176
                break;
2177
            }
2178
    for (i = 0; i < 0x11; i++)
2179
    {
2180
        if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
2181
        ftl_cxt.nextblockusn++;
2182
        if (ftl_log[i].issequential == 1)
2183
            rc |= ftl_commit_sequential(&ftl_log[i]);
2184
        else rc |= ftl_commit_scattered(&ftl_log[i]);
2185
    }
54 theseven 2186
    if (rc != 0)
2187
    {
2188
        mutex_unlock(&ftl_mtx);
2189
        return 1;
2190
    }
2191
    for (i = 0; i < 5; i++)
2192
        if (ftl_commit_cxt() == 0)
2193
        {
2194
            mutex_unlock(&ftl_mtx);
2195
            return 0;
2196
        }
2197
        else ftl_cxt.ftlctrlpage |= ppb - 1;
2198
    mutex_unlock(&ftl_mtx);
2 theseven 2199
    return 1;
2200
}
2201
#endif
2202
 
2203
 
124 theseven 2204
/* Block allocator for FTL recovery */
2205
static uint32_t ftl_alloc_block() INITCODE_ATTR;
2206
static uint32_t ftl_alloc_block()
2207
{
2208
    while (1)
2209
    {
2210
        for (; firstfree < ftl_nand_type->userblocks + 0x17; firstfree++)
2211
            if (!blk_type[firstfree]) break;
2212
            else if (allocmode && blk_type[firstfree] != 1)
2213
            {
2214
                if (ftl_erase_block(firstfree))
2215
                {
2216
                    cprintf(CONSOLE_BOOT, "Couldn't erase vBlock %d (pool alloc)!\n", firstfree);
2217
                    return 1;
2218
                }
2219
                break;
2220
            }
2221
        if (firstfree < ftl_nand_type->userblocks + 0x17)
2222
        {
2223
            blk_type[firstfree] = 1;
2224
            return firstfree++;
2225
        }
2226
        if (!allocmode)
2227
        {
2228
            allocmode = 1;
2229
            firstfree = 0;
2230
        }
2231
        else
2232
        {
2233
            cputs(CONSOLE_BOOT, "Out of empty blocks!\n");
2234
            return 1;
2235
        }
2236
    }
2237
}
2238
 
2239
 
2240
static uint32_t ftl_repair(void) INITCODE_ATTR;
2241
static uint32_t ftl_repair()
2242
{
2243
    uint32_t i, j, k;
2244
#ifdef HAVE_LCD
2245
    struct progressbar_state progressbar;
2246
#endif
2247
 
2248
    cputs(CONSOLE_BOOT, "Scanning flash...\n");
2249
#ifdef HAVE_LCD
2250
    lcdconsole_progressbar(&progressbar, 0, ftl_nand_type->userblocks + 0x17);
2251
#endif
2252
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2253
    memset(&ftl_cxt, 0x00, 0x800);
2254
    memset(ftl_map, 0xff, 0x4000);
2255
    memset(blk_usn, 0x00, 0x8000);
2256
    memset(blk_type, 0x00, 0x2000);
2257
    memset(ftl_erasectr, 0x00, 0x4000);
2258
    memset(erasectr_usn, 0xff, 32);
2259
    user_usn = 0;
2260
    meta_usn = 0xffffffff;
2261
    for (i = 0; i < ftl_nand_type->userblocks + 0x17; i++)
2262
    {
2263
        uint32_t ret = ftl_vfl_read((i + 1) * ppb - 1, 0, &ftl_sparebuffer[0], 1, 0);
2264
        if ((ret & 0x11F) == 0 && ftl_sparebuffer[0].meta.type == 0x41)
2265
        {
2266
            uint32_t lbn = ftl_sparebuffer[0].user.lpn / ppb;
2267
            if (ftl_sparebuffer[0].user.usn > user_usn)
2268
                user_usn = ftl_sparebuffer[0].user.usn;
2269
            if (ftl_sparebuffer[0].user.usn > blk_usn[lbn])
2270
            {
2271
                if (ftl_map[lbn] != 0xffff)
2272
                    blk_type[ftl_map[lbn]] = 5;
2273
                blk_usn[lbn] = ftl_sparebuffer[0].user.usn;
2274
                ftl_map[lbn] = i;
2275
                blk_type[i] = 1;
2276
            }
2277
            else blk_type[i] = 5;
2278
        }
2279
        else
2280
            for (j = 0; j < ppb; j++)
2281
            {
2282
                ret = ftl_vfl_read(i * ppb + j, 0, &ftl_sparebuffer[0], 1, 0);
2283
                if (ret & 2) break;
2284
                if (ret & 0x11F)
2285
                {
2286
                    blk_type[i] = 4;
2287
                    continue;
2288
                }
2289
                if (ftl_sparebuffer[0].meta.type == 0x40)
2290
                {
2291
                    blk_type[i] = 2;
2292
                    break;
2293
                }
2294
                else if (ftl_sparebuffer[0].meta.type - 0x43 <= 4)
2295
                {
2296
                    blk_type[i] = 3;
2297
                    if (ftl_sparebuffer[0].meta.type == 0x46)
2298
                    {
2299
                        uint32_t idx = ftl_sparebuffer[0].meta.idx;
2300
                        if (ftl_sparebuffer[0].meta.usn < meta_usn)
2301
                            meta_usn = ftl_sparebuffer[0].meta.usn;
2302
                        if (ftl_sparebuffer[0].meta.usn < erasectr_usn[idx])
2303
                        {
2304
                            erasectr_usn[idx] = ftl_sparebuffer[0].meta.usn;
2305
                            ret = ftl_vfl_read(i * ppb + j, &ftl_erasectr[idx << 10],
2306
                                               &ftl_sparebuffer[0], 1, 0);
2307
                            if (ret & 0x11f) memset(&ftl_erasectr[idx << 10], 0, 0x800);
2308
                        }
2309
                    }
2310
                }
2311
                else
2312
                {
2313
                    cprintf(CONSOLE_BOOT, "Invalid block type %02X while reading vPage %d\n",
2314
                            ftl_sparebuffer[0].meta.type, i * ppb + j);
2315
                    return 1;
2316
                }
2317
            }
2318
#ifdef HAVE_LCD
2319
        progressbar_setpos(&progressbar, i + 1, false);
2320
#endif
2321
    }
2322
 
2323
    uint32_t sum = 0;
2324
    uint32_t count = 0;
2325
    for (i = 0; i < 0x2000; i++)
2326
        if (ftl_erasectr[i])
2327
        {
2328
            sum += ftl_erasectr[i];
2329
            count++;
2330
        }
2331
    uint32_t average = sum / count;
2332
    for (i = 0; i < 0x2000; i++)
2333
        if (!ftl_erasectr[i])
2334
            ftl_erasectr[i] = average;
2335
 
2336
    cputs(CONSOLE_BOOT, "Committing scattered pages...\n");
2337
    count = 0;
2338
    for (i = 0; i < ftl_nand_type->userblocks + 0x17; i++)
2339
        if (blk_type[i] == 2) count++;
2340
    uint32_t block;
2341
    uint32_t dirty;
2342
    if (count)
2343
    {
2344
#ifdef HAVE_LCD
134 theseven 2345
        lcdconsole_progressbar(&progressbar, 0, count * ppb * 2);
124 theseven 2346
#endif
2347
        count = 0;
2348
        for (i = 0; i < ftl_nand_type->userblocks + 0x17; i++)
2349
            if (blk_type[i] == 2)
2350
            {
2351
                block = 0xffff;
134 theseven 2352
                for (j = 0; j < ppb; j++)
124 theseven 2353
                {
134 theseven 2354
#ifdef HAVE_LCD
2355
                    progressbar_setpos(&progressbar, count * ppb * 2 + j, false);
2356
#endif
124 theseven 2357
                    uint32_t ret = ftl_vfl_read(i * ppb + j, ftl_buffer,
2358
                                                &ftl_sparebuffer[0], 1, 0);
2359
                    if (ret & 0x11F) continue;
2360
                    if (ftl_sparebuffer[0].user.type != 0x40)
2361
                    {
2362
                        cprintf(CONSOLE_BOOT, "Invalid block type %02X while reading "
2363
                                              "vPage %d (scattered page)!\n",
2364
                                ftl_sparebuffer[0].meta.type, i * ppb + j);
2365
                        return 1;
2366
                    }
2367
                    if (block == 0xffff)
2368
                    {
2369
                        block = ftl_sparebuffer[0].user.lpn / ppb;
2370
                        memset(pageusn, 0x00, 0x800);
2371
                        memset(pagedata, 0x00, 0x100000);
2372
                        if (ftl_map[block] != 0xffff)
2373
                            for (k = 0; k < ppb; k++)
2374
                            {
2375
                                uint32_t ret = ftl_vfl_read(ftl_map[block] * ppb + k, pagedata[k],
2376
                                                            &ftl_copyspare[0], 1, 0);
2377
                                if (ret & 0x11F) continue;
2378
                                if (ftl_copyspare[0].user.type != 0x40
2379
                                 && ftl_copyspare[0].user.type != 0x41)
2380
                                {
2381
                                    cprintf(CONSOLE_BOOT, "Invalid block type %02X while reading "
2382
                                                          "vPage %d (scattered page orig)!\n",
2383
                                            ftl_sparebuffer[0].meta.type,
2384
                                            ftl_map[block] * ppb + k);
2385
                                    return 1;
2386
                                }
2387
                                if (block != ftl_copyspare[0].user.lpn / ppb)
2388
                                {
2389
                                    cprintf(CONSOLE_BOOT, "Foreign page in scattered page orig "
2390
                                                          "block (vPage %d, LPN %d)!\n",
2391
                                            ftl_map[block] * ppb + k,
2392
                                            ftl_sparebuffer[0].user.usn);
2393
                                    return 1;
2394
                                }
2395
                                pageusn[k] = ftl_copyspare[0].user.usn;
2396
                            }
2397
                        dirty = 0;
2398
                    }
2399
                    if (block != ftl_sparebuffer[0].user.lpn / ppb)
2400
                    {
2401
                        cprintf(CONSOLE_BOOT, "Foreign page in scattered page block "
2402
                                              "block (vPage %d, LPN %d)!\n",
2403
                                i * ppb + j, ftl_sparebuffer[0].user.lpn);
2404
                        return 1;
2405
                    }
2406
                    uint32_t idx = ftl_sparebuffer[0].user.lpn % ppb;
2407
                    if (ftl_sparebuffer[0].user.usn > user_usn)
2408
                        user_usn = ftl_sparebuffer[0].user.usn;
2409
                    if (ftl_sparebuffer[0].user.usn > pageusn[idx])
2410
                    {
2411
                        pageusn[idx] = ftl_sparebuffer[0].user.usn;
2412
                        memcpy(pagedata[idx], ftl_buffer, 0x800);
2413
                        dirty = 1;
2414
                    }
2415
                }
2416
                if (dirty)
2417
                {
2418
                    if (ftl_erase_block(i))
2419
                    {
2420
                        cprintf(CONSOLE_BOOT, "Couldn't erase vBlock %d "
2421
                                              "(scattered page commit)!\n", i);
2422
                        return 1;
2423
                    }
2424
                    for (j = 0; j < ppb; j++)
2425
                    {
134 theseven 2426
#ifdef HAVE_LCD
2427
                        progressbar_setpos(&progressbar, count * ppb * 2 + ppb + j, false);
2428
#endif
124 theseven 2429
                        memset(&ftl_sparebuffer[0], 0xFF, 0x40);
2430
                        ftl_sparebuffer[0].user.lpn = block * ppb + j;
2431
                        ftl_sparebuffer[0].user.usn = pageusn[j];
2432
                        ftl_sparebuffer[0].user.type = 0x40;
2433
                        if (j == ppb - 1) ftl_sparebuffer[0].user.type = 0x41;
2434
                        if (ftl_vfl_write(i * ppb + j, 1, pagedata[j], &ftl_sparebuffer[0]))
2435
                        {
2436
                            cprintf(CONSOLE_BOOT, "Couldn't write vPage %d "
2437
                                                  "(scattered page commit)!\n", i * ppb + j);
2438
                            return 1;
2439
                        }
2440
                    }
2441
                    if (ftl_map[block] != 0xffff) blk_type[ftl_map[block]] = 5;
2442
                    blk_type[i] = 1;
2443
                    ftl_map[block] = i;
2444
                }
2445
                else blk_type[i] = 5;
2446
#ifdef HAVE_LCD
134 theseven 2447
                progressbar_setpos(&progressbar, ++count * ppb * 2, false);
124 theseven 2448
#endif
2449
            }
2450
    }
2451
 
2452
    cputs(CONSOLE_BOOT, "Fixing block map...\n");
2453
    allocmode = 0;
2454
    firstfree = 0;
2455
    for (i = 0; i < 3; i++) ftl_cxt.ftlctrlblocks[i] = ftl_alloc_block();
2456
    for (i = 0; i < 20; i++) ftl_cxt.blockpool[i] = ftl_alloc_block();
2457
    for (i = 0; i < ftl_nand_type->userblocks; i++)
2458
        if (ftl_map[i] == 0xffff)
2459
            ftl_map[i] = ftl_alloc_block();
2460
    ftl_cxt.usn = meta_usn - 1;
2461
    ftl_cxt.nextblockusn = user_usn + 1;
2462
    ftl_cxt.freecount = 20;
2463
    ftl_cxt.clean_flag = 1;
2464
 
2465
    cputs(CONSOLE_BOOT, "Committing FTL context...\n");
2466
    uint32_t blockmappages = ftl_nand_type->userblocks >> 10;
2467
    if ((ftl_nand_type->userblocks & 0x1FF) != 0) blockmappages++;
2468
    uint32_t erasectrpages = (ftl_nand_type->userblocks + 23) >> 10;
2469
    if (((ftl_nand_type->userblocks + 23) & 0x1FF) != 0) erasectrpages++;
2470
    uint32_t page = ftl_cxt.ftlctrlblocks[0] * ppb;
2471
    for (i = 0; i < erasectrpages; i++)
2472
    {
2473
        memset(&ftl_sparebuffer, 0xFF, 0x40);
2474
        ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
2475
        ftl_sparebuffer[0].meta.idx = i;
2476
        ftl_sparebuffer[0].meta.type = 0x46;
2477
        if (ftl_vfl_write(page, 1, &ftl_erasectr[i << 10], &ftl_sparebuffer[0]))
2478
        {
2479
            cprintf(CONSOLE_BOOT, "Couldn't write vPage %d (save erase counters)!\n", page);
2480
            return 1;
2481
        }
2482
        ftl_cxt.ftl_erasectr_pages[i] = page++;
2483
    }
2484
    for (i = 0; i < blockmappages; i++)
2485
    {
2486
        memset(&ftl_sparebuffer[0], 0xFF, 0x40);
2487
        ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
2488
        ftl_sparebuffer[0].meta.idx = i;
2489
        ftl_sparebuffer[0].meta.type = 0x44;
2490
        if (ftl_vfl_write(page, 1, &ftl_map[i << 10], &ftl_sparebuffer[0]))
2491
        {
2492
            cprintf(CONSOLE_BOOT, "Couldn't write vPage %d (save block map)!\n", page);
2493
            return 1;
2494
        }
2495
        ftl_cxt.ftl_map_pages[i] = page++;
2496
    }
2497
    ftl_cxt.ftlctrlpage = page;
2498
    memset(&ftl_sparebuffer[0], 0xFF, 0x40);
2499
    ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
2500
    ftl_sparebuffer[0].meta.type = 0x43;
2501
    if (ftl_vfl_write(page, 1, &ftl_cxt, &ftl_sparebuffer[0]))
2502
    {
2503
        cprintf(CONSOLE_BOOT, "Couldn't write vPage %d (save FTL context)!\n", page);
2504
        return 1;
2505
    }
2506
    ftl_store_ctrl_block_list();
134 theseven 2507
    return 0;
124 theseven 2508
}
2509
 
2510
 
2 theseven 2511
/* Initializes and mounts the FTL.
2512
   As long as nothing was written, you won't need to unmount it.
54 theseven 2513
   Before shutting down after writing something, call ftl_sync(),
124 theseven 2514
   which will return immediately if everything was already clean. */
54 theseven 2515
uint32_t ftl_init(void)
2 theseven 2516
{
54 theseven 2517
    mutex_init(&ftl_mtx);
2 theseven 2518
    uint32_t i;
2519
    uint32_t result = 0;
2520
    uint32_t foundsignature, founddevinfo, blockwiped, repaired, skip;
61 theseven 2521
    int rc;
2522
    if ((rc = nand_device_init()) != 0) //return 1;
2523
        panicf(PANIC_FATAL, "FTL: Lowlevel NAND driver init failed: %d", rc);
2 theseven 2524
    ftl_banks = 0;
2525
    for (i = 0; i < 4; i++)
2526
        if (nand_get_device_type(i) != 0) ftl_banks = i + 1;
2527
    ftl_nand_type = nand_get_device_type(0);
2528
    foundsignature = 0;
2529
    blockwiped = 1;
54 theseven 2530
    for (i = 0; i < ftl_nand_type->pagesperblock; i++)
2 theseven 2531
    {
2532
        result = nand_read_page(0, i, ftl_buffer, (uint32_t*)0, 1, 1);
2533
        if ((result & 0x11F) == 0)
2534
        {
2535
            blockwiped = 0;
2536
            if (((uint32_t*)ftl_buffer)[0] != 0x41303034) continue;
2537
            foundsignature = 1;
2538
            break;
2539
        }
2540
        else if ((result & 2) != 2) blockwiped = 0;
2541
    }
54 theseven 2542
 
2 theseven 2543
    founddevinfo = ftl_has_devinfo();
2544
 
2545
    repaired = 0;
2546
    skip = 0;
54 theseven 2547
    if (founddevinfo == 0)
2548
    {
2549
	   	DEBUGF("FTL: No DEVICEINFO found!");
2550
        return 1;
2551
    }
2552
    if (foundsignature != 0 && (result & 0x11F) != 0)
2553
    {
2554
        DEBUGF("FTL: Problem with the signature!");
2555
        return 1;
2556
    }
2 theseven 2557
    if (ftl_vfl_open() == 0)
124 theseven 2558
	{
2 theseven 2559
        if (ftl_open() == 0)
128 theseven 2560
        {
2561
            ftl_initialized = true;
2 theseven 2562
            return 0;
128 theseven 2563
        }
124 theseven 2564
		cprintf(CONSOLE_BOOT, "The FTL seems to be damaged. Forcing check.\n");
2565
		if (ftl_repair() != 0)
2566
			cprintf(CONSOLE_BOOT, "FTL recovery failed. Use disk mode to recover.\n");
2567
		else
2568
		{
2569
			cprintf(CONSOLE_BOOT, "FTL recovery finished. Trying to mount again...\n");
2570
	        if (ftl_open() == 0)
128 theseven 2571
            {
134 theseven 2572
			    cprintf(CONSOLE_BOOT, "Mount succeeded.\n");
128 theseven 2573
                ftl_initialized = true;
2574
                return 0;
2575
            }
124 theseven 2576
			cprintf(CONSOLE_BOOT, "Mounting FTL failed again, use disk mode to recover.\n");
2577
		}
2578
	}
2 theseven 2579
 
54 theseven 2580
    DEBUGF("FTL: Initialization failed!");
2581
 
2 theseven 2582
    return 1;
2583
}