Subversion Repositories freemyipod

Rev

Rev 624 | Details | Compare with Previous | Last modification | View Log | RSS feed

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