Subversion Repositories freemyipod

Rev

Details | Last modification | View Log | RSS feed

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