Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

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