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