Subversion Repositories freemyipod

Rev

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