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 */
66 theseven 365
static uint16_t ftl_map[0x2000];
2 theseven 366
 
367
/* VFL context for each bank */
66 theseven 368
static struct ftl_vfl_cxt_type ftl_vfl_cxt[4];
2 theseven 369
 
370
/* FTL context */
66 theseven 371
static struct ftl_cxt_type ftl_cxt;
2 theseven 372
 
373
/* Temporary data buffers for internal use by the FTL */
66 theseven 374
static uint8_t ftl_buffer[0x800] CACHEALIGN_ATTR;
2 theseven 375
 
376
/* Temporary spare byte buffer for internal use by the FTL */
66 theseven 377
static 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 */
66 theseven 383
static uint8_t ftl_bbt[4][0x410];
2 theseven 384
 
54 theseven 385
/* Erase counters for the vBlocks */
66 theseven 386
static uint16_t ftl_erasectr[0x2000];
2 theseven 387
 
388
/* Used by ftl_log */
66 theseven 389
static uint16_t ftl_offsets[0x11][0x200];
2 theseven 390
 
391
/* Structs keeping record of scattered page blocks */
66 theseven 392
static struct ftl_log_type ftl_log[0x11];
2 theseven 393
 
394
/* Global cross-bank update sequence number of the VFL context */
66 theseven 395
static uint32_t ftl_vfl_usn;
2 theseven 396
 
397
/* Keeps track (temporarily) of troublesome blocks */
66 theseven 398
static struct ftl_trouble_type ftl_troublelog[5];
2 theseven 399
 
400
/* Counts erase counter page changes, after 100 of them the affected
401
   page will be committed to the flash. */
66 theseven 402
static uint8_t ftl_erasectr_dirt[8];
2 theseven 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. */
66 theseven 407
static uint8_t ftl_copybuffer[FTL_COPYBUF_SIZE][0x800] CACHEALIGN_ATTR;
408
static 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. */
66 theseven 412
static 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. */
66 theseven 423
static uint32_t ftl_find_devinfo(uint32_t bank)
2 theseven 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 */
66 theseven 447
static uint32_t ftl_has_devinfo(void)
2 theseven 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. */
66 theseven 457
static uint32_t ftl_load_bbt(uint32_t bank, uint8_t* bbt)
2 theseven 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 */
66 theseven 491
static void ftl_vfl_calculate_checksum(uint32_t bank,
492
                                       uint32_t* checksum1, uint32_t* checksum2)
2 theseven 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 */
66 theseven 507
static uint32_t ftl_vfl_verify_checksum(uint32_t bank)
2 theseven 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 */
66 theseven 522
static void ftl_vfl_update_checksum(uint32_t bank)
2 theseven 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. */
66 theseven 533
static uint32_t ftl_vfl_store_cxt(uint32_t bank)
2 theseven 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 */
66 theseven 577
static uint32_t ftl_vfl_commit_cxt(uint32_t bank)
2 theseven 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") */
66 theseven 607
static struct ftl_vfl_cxt_type* ftl_vfl_get_newest_cxt(void)
2 theseven 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. */
66 theseven 624
static uint32_t ftl_is_good_block(uint8_t* bbt, uint32_t block)
2 theseven 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 */
66 theseven 632
static uint32_t ftl_vfl_is_good_block(uint32_t bank, uint32_t block)
2 theseven 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 */
66 theseven 643
static void ftl_vfl_set_good_block(uint32_t bank, uint32_t block, uint32_t isgood)
2 theseven 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 */
66 theseven 653
static 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)
2 theseven 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 */
66 theseven 673
static uint32_t ftl_vfl_get_physical_block(uint32_t bank, uint32_t block)
2 theseven 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 */
66 theseven 692
static uint32_t ftl_vfl_check_remap_scheduled(uint32_t bank, uint32_t block)
2 theseven 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 */
66 theseven 704
static void ftl_vfl_schedule_block_for_remap(uint32_t bank, uint32_t block)
2 theseven 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 */
66 theseven 720
static void ftl_vfl_mark_remap_done(uint32_t bank, uint32_t block)
2 theseven 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. */
66 theseven 741
static void ftl_vfl_log_trouble(uint32_t bank, uint32_t vblock)
2 theseven 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 */
66 theseven 770
static void ftl_vfl_log_success(uint32_t bank, uint32_t vblock)
2 theseven 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. */
66 theseven 790
static uint32_t ftl_vfl_remap_block(uint32_t bank, uint32_t block)
2 theseven 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 */
66 theseven 821
static uint32_t ftl_vfl_read(uint32_t vpage, void* buffer, void* sparebuffer,
822
                             uint32_t checkempty, uint32_t remaponfail)
2 theseven 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 */
66 theseven 869
static uint32_t ftl_vfl_read_fast(uint32_t vpage, void* buffer, void* sparebuffer,
870
                                  uint32_t checkempty, uint32_t remaponfail)
54 theseven 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 */
66 theseven 945
static 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 */
66 theseven 1022
static uint32_t ftl_vfl_open(void)
2 theseven 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 */
66 theseven 1115
static uint32_t ftl_open(void)
2 theseven 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 */
66 theseven 1267
static struct ftl_log_type* ftl_get_log_entry(uint32_t block)
2 theseven 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
 
68 theseven 1290
	if ((uint32_t)buffer & 0xf)
1291
		panicf(PANIC_KILLTHREAD,
1292
		       "ftl_read: Misaligned data buffer at %08X (sector %lu, count %lu)",
1293
			   (unsigned int)buffer, sector, count);
1294
 
54 theseven 1295
    if (sector + count > ftl_nand_type->userblocks * ppb)
1296
    {
61 theseven 1297
        DEBUGF("FTL: Sector %d is out of range!", sector + count - 1);
2 theseven 1298
        return 1;
54 theseven 1299
    }
2 theseven 1300
    if (count == 0) return 0;
1301
 
54 theseven 1302
    mutex_lock(&ftl_mtx, TIMEOUT_BLOCK);
1303
 
2 theseven 1304
    for (i = 0; i < count; i++)
1305
    {
1306
        uint32_t block = (sector + i) / ppb;
1307
        uint32_t page = (sector + i) % ppb;
1308
 
1309
        uint32_t abspage = ftl_map[block] * ppb + page;
1310
#ifndef FTL_READONLY
1311
        struct ftl_log_type* logentry = ftl_get_log_entry(block);
1312
        if (logentry != (struct ftl_log_type*)0)
1313
        {
54 theseven 1314
#ifdef FTL_TRACE
61 theseven 1315
	        DEBUGF("FTL: Block %d has a log entry", block);
54 theseven 1316
#endif
1317
            if (logentry->scatteredvblock != 0xFFFF
1318
             && logentry->pageoffsets[page] != 0xFFFF)
2 theseven 1319
            {
54 theseven 1320
#ifdef FTL_TRACE
61 theseven 1321
   		     DEBUGF("FTL: Found page %d at block %d, page %d", page,
54 theseven 1322
          		    (*logentry).scatteredvblock, (*logentry).pageoffsets[page]);
1323
#endif
1324
                abspage = logentry->scatteredvblock * ppb
1325
                        + logentry->pageoffsets[page];
2 theseven 1326
            }
1327
        }
1328
#endif
1329
 
54 theseven 1330
#ifndef FTL_READONLY
1331
        if (count >= i + ftl_banks && !(page & (ftl_banks - 1))
1332
         && logentry == (struct ftl_log_type*)0)
1333
#else
1334
        if (count >= i + ftl_banks && !(page & (ftl_banks - 1)))
1335
#endif
2 theseven 1336
        {
54 theseven 1337
            uint32_t ret = ftl_vfl_read_fast(abspage, &((uint8_t*)buffer)[i << 11],
1338
                                             &ftl_sparebuffer[0], 1, 1);
1339
            for (j = 0; j < ftl_banks; j++)
1340
                if (ret & (2 << (j << 2)))
1341
                    memset(&((uint8_t*)buffer)[(i + j) << 11], 0, 0x800);
1342
                else if ((ret & (0xd << (j << 2))) || ftl_sparebuffer[j].user.eccmark != 0xFF)
1343
                {
61 theseven 1344
		            DEBUGF("FTL: Error while reading sector %d!", (sector + i));
54 theseven 1345
                    error = 1;
1346
                    memset(&((uint8_t*)buffer)[(i + j) << 11], 0, 0x800);
1347
                }
1348
            i += ftl_banks - 1;
2 theseven 1349
        }
54 theseven 1350
        else
1351
        {
1352
            uint32_t ret = ftl_vfl_read(abspage, &((uint8_t*)buffer)[i << 11],
1353
                                        &ftl_sparebuffer[0], 1, 1);
1354
            if (ret & 2) memset(&((uint8_t*)buffer)[i << 11], 0, 0x800);
1355
            else if ((ret & 0x11D) != 0 || ftl_sparebuffer[0].user.eccmark != 0xFF)
1356
            {
61 theseven 1357
	            DEBUGF("FTL: Error while reading sector %d!", (sector + i));
54 theseven 1358
                error = 1;
1359
                memset(&((uint8_t*)buffer)[i << 11], 0, 0x800);
1360
            }
1361
        }
2 theseven 1362
    }
54 theseven 1363
 
1364
    mutex_unlock(&ftl_mtx);
1365
 
2 theseven 1366
    return error;
1367
}
1368
 
1369
 
1370
#ifndef FTL_READONLY
1371
/* Performs a vBlock erase, dealing with hardware,
1372
   remapping and all kinds of trouble */
66 theseven 1373
static uint32_t ftl_erase_block_internal(uint32_t block)
2 theseven 1374
{
1375
    uint32_t i, j;
54 theseven 1376
    block = block + ftl_nand_type->blocks
1377
          - ftl_nand_type->userblocks - 0x17;
1378
    if (block == 0 || block >= ftl_nand_type->blocks) return 1;
2 theseven 1379
    for (i = 0; i < ftl_banks; i++)
1380
    {
1381
        if (ftl_vfl_check_remap_scheduled(i, block) == 1)
1382
        {
1383
            ftl_vfl_remap_block(i, block);
1384
            ftl_vfl_mark_remap_done(i, block);
1385
        }
1386
        ftl_vfl_log_success(i, block);
1387
        uint32_t pblock = ftl_vfl_get_physical_block(i, block);
1388
        uint32_t rc;
1389
        for (j = 0; j < 3; j++)
1390
        {
54 theseven 1391
            rc = nand_block_erase(i, pblock * ftl_nand_type->pagesperblock);
2 theseven 1392
            if (rc == 0) break;
1393
        }
1394
        if (rc != 0)
1395
        {
54 theseven 1396
            panicf(PANIC_FATAL, "FTL: Block erase failed on bank %u block %u",
1397
                   (unsigned)i, (unsigned)block);
2 theseven 1398
            if (pblock != block)
1399
            {
1400
                uint32_t spareindex = pblock - ftl_vfl_cxt[i].firstspare;
1401
                ftl_vfl_cxt[i].remaptable[spareindex] = 0xFFFF;
1402
            }
1403
            ftl_vfl_cxt[i].field_18++;
1404
            if (ftl_vfl_remap_block(i, block) == 0) return 1;
1405
            if (ftl_vfl_commit_cxt(i) != 0) return 1;
1406
            memset(&ftl_sparebuffer, 0, 0x40);
1407
            nand_write_page(i, pblock, &ftl_vfl_cxt[0], &ftl_sparebuffer, 1);
1408
        }
1409
    }
1410
    return 0;
1411
}
1412
#endif
1413
 
1414
 
1415
#ifndef FTL_READONLY
1416
/* Highlevel vBlock erase, that increments the erase counter for the block */
66 theseven 1417
static uint32_t ftl_erase_block(uint32_t block)
2 theseven 1418
{
1419
    ftl_erasectr[block]++;
1420
    if (ftl_erasectr_dirt[block >> 10] == 100) ftl_cxt.erasedirty = 1;
1421
    else ftl_erasectr_dirt[block >> 10]++;
1422
    return ftl_erase_block_internal(block);
1423
}
1424
#endif
1425
 
1426
 
1427
#ifndef FTL_READONLY
1428
/* Allocates a block from the pool,
1429
   returning its vBlock number, or 0xFFFFFFFF on error */
66 theseven 1430
static uint32_t ftl_allocate_pool_block(void)
2 theseven 1431
{
1432
    uint32_t i;
1433
    uint32_t erasectr = 0xFFFFFFFF, bestidx = 0xFFFFFFFF, block;
1434
    for (i = 0; i < ftl_cxt.freecount; i++)
1435
    {
1436
        uint32_t idx = ftl_cxt.nextfreeidx + i;
1437
        if (idx >= 0x14) idx -= 0x14;
1438
        if (!ftl_cxt.blockpool[idx]) continue;
1439
        if (ftl_erasectr[ftl_cxt.blockpool[idx]] < erasectr)
1440
        {
1441
            erasectr = ftl_erasectr[ftl_cxt.blockpool[idx]];
1442
            bestidx = idx;
1443
        }
1444
    }
54 theseven 1445
    if (bestidx == 0xFFFFFFFF) panicf(PANIC_FATAL, "FTL: Out of pool blocks!");
2 theseven 1446
    block = ftl_cxt.blockpool[bestidx];
1447
    if (bestidx != ftl_cxt.nextfreeidx)
1448
    {
1449
        ftl_cxt.blockpool[bestidx] = ftl_cxt.blockpool[ftl_cxt.nextfreeidx];
1450
        ftl_cxt.blockpool[ftl_cxt.nextfreeidx] = block;
1451
    }
54 theseven 1452
    if (block > (uint32_t)ftl_nand_type->userblocks + 0x17)
1453
        panicf(PANIC_FATAL, "FTL: Bad block number in pool: %u", (unsigned)block);
2 theseven 1454
    if (ftl_erase_block(block) != 0) return 0xFFFFFFFF;
1455
    if (++ftl_cxt.nextfreeidx == 0x14) ftl_cxt.nextfreeidx = 0;
1456
    ftl_cxt.freecount--;
1457
    return block;
1458
}
1459
#endif
1460
 
1461
 
1462
#ifndef FTL_READONLY
1463
/* Releases a vBlock back into the pool */
66 theseven 1464
static void ftl_release_pool_block(uint32_t block)
2 theseven 1465
{
54 theseven 1466
    if (block >= (uint32_t)ftl_nand_type->userblocks + 0x17)
1467
        panicf(PANIC_FATAL, "FTL: Tried to release block %u", (unsigned)block);
2 theseven 1468
    uint32_t idx = ftl_cxt.nextfreeidx + ftl_cxt.freecount++;
1469
    if (idx >= 0x14) idx -= 0x14;
1470
    ftl_cxt.blockpool[idx] = block;
1471
}
1472
#endif
1473
 
1474
 
1475
#ifndef FTL_READONLY
1476
/* Commits the location of the FTL context blocks
1477
   to a semi-randomly chosen VFL context */
66 theseven 1478
static uint32_t ftl_store_ctrl_block_list(void)
2 theseven 1479
{
1480
    uint32_t i;
1481
    for (i = 0; i < ftl_banks; i++)
1482
        memcpy(ftl_vfl_cxt[i].ftlctrlblocks, ftl_cxt.ftlctrlblocks, 6);
1483
    return ftl_vfl_commit_cxt(ftl_vfl_usn % ftl_banks);
1484
}
1485
#endif
1486
 
1487
 
1488
#ifndef FTL_READONLY
1489
/* Saves the n-th erase counter page to the flash,
1490
   because it is too dirty or needs to be moved. */
66 theseven 1491
static uint32_t ftl_save_erasectr_page(uint32_t index)
2 theseven 1492
{
54 theseven 1493
    memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1494
    ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1495
    ftl_sparebuffer[0].meta.idx = index;
1496
    ftl_sparebuffer[0].meta.type = 0x46;
1497
    if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, &ftl_erasectr[index << 10],
1498
                      &ftl_sparebuffer[0]) != 0)
2 theseven 1499
        return 1;
1500
    if ((ftl_vfl_read(ftl_cxt.ftlctrlpage, ftl_buffer,
54 theseven 1501
                      &ftl_sparebuffer[0], 1, 1) & 0x11F) != 0)
2 theseven 1502
        return 1;
1503
    if (memcmp(ftl_buffer, &ftl_erasectr[index << 10], 0x800) != 0) return 1;
54 theseven 1504
    if (ftl_sparebuffer[0].meta.type != 0x46) return 1;
1505
    if (ftl_sparebuffer[0].meta.idx != index) return 1;
1506
    if (ftl_sparebuffer[0].meta.usn != ftl_cxt.usn) return 1;
2 theseven 1507
    ftl_cxt.ftl_erasectr_pages[index] = ftl_cxt.ftlctrlpage;
1508
    ftl_erasectr_dirt[index] = 0;
1509
    return 0;
1510
}
1511
#endif
1512
 
1513
 
1514
#ifndef FTL_READONLY
1515
/* Increments ftl_cxt.ftlctrlpage to the next available FTL context page,
1516
   allocating a new context block if neccessary. */
66 theseven 1517
static uint32_t ftl_next_ctrl_pool_page(void)
2 theseven 1518
{
1519
    uint32_t i;
54 theseven 1520
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1521
    if (++ftl_cxt.ftlctrlpage % ppb != 0) return 0;
1522
    for (i = 0; i < 3; i++)
1523
        if ((ftl_cxt.ftlctrlblocks[i] + 1) * ppb == ftl_cxt.ftlctrlpage)
1524
            break;
1525
    i = (i + 1) % 3;
1526
    uint32_t oldblock = ftl_cxt.ftlctrlblocks[i];
1527
    uint32_t newblock = ftl_allocate_pool_block();
1528
    if (newblock == 0xFFFFFFFF) return 1;
1529
    ftl_cxt.ftlctrlblocks[i] = newblock;
1530
    ftl_cxt.ftlctrlpage = newblock * ppb;
61 theseven 1531
    DEBUGF("Starting new FTL control block at %d", ftl_cxt.ftlctrlpage);
54 theseven 1532
    uint32_t pagestoread = (ftl_nand_type->userblocks + 23) >> 10;
1533
    if (((ftl_nand_type->userblocks + 23) & 0x1FF) != 0) pagestoread++;
2 theseven 1534
    for (i = 0; i < pagestoread; i++)
1535
        if (oldblock * ppb <= ftl_cxt.ftl_erasectr_pages[i]
1536
         && (oldblock + 1) * ppb > ftl_cxt.ftl_erasectr_pages[i])
1537
         {
1538
            ftl_cxt.usn--;
1539
            if (ftl_save_erasectr_page(i) != 0)
1540
            {
1541
                ftl_cxt.ftlctrlblocks[i] = oldblock;
1542
                ftl_cxt.ftlctrlpage = oldblock * (ppb + 1) - 1;
1543
                ftl_release_pool_block(newblock);
1544
                return 1;
1545
            }
1546
            ftl_cxt.ftlctrlpage++;
1547
         }
1548
    ftl_release_pool_block(oldblock);
1549
    return ftl_store_ctrl_block_list();
1550
}
1551
#endif
1552
 
1553
 
1554
#ifndef FTL_READONLY
1555
/* Copies a vPage from one location to another */
66 theseven 1556
static uint32_t ftl_copy_page(uint32_t source, uint32_t destination,
1557
                              uint32_t lpn, uint32_t type)
2 theseven 1558
{
54 theseven 1559
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1560
    uint32_t rc = ftl_vfl_read(source, ftl_copybuffer[0],
1561
                               &ftl_copyspare[0], 1, 1) & 0x11F;
1562
    memset(&ftl_copyspare[0], 0xFF, 0x40);
1563
    ftl_copyspare[0].user.lpn = lpn;
1564
    ftl_copyspare[0].user.usn = ++ftl_cxt.nextblockusn;
1565
    ftl_copyspare[0].user.type = 0x40;
1566
    if ((rc & 2) != 0) memset(ftl_copybuffer[0], 0, 0x800);
1567
    else if (rc != 0) ftl_copyspare[0].user.eccmark = 0x55;
2 theseven 1568
    if (type == 1 && destination % ppb == ppb - 1)
54 theseven 1569
        ftl_copyspare[0].user.type = 0x41;
1570
    return ftl_vfl_write(destination, 1, ftl_copybuffer[0], &ftl_copyspare[0]);
2 theseven 1571
}
1572
#endif
1573
 
1574
 
1575
#ifndef FTL_READONLY
1576
/* Copies a pBlock to a vBlock */
66 theseven 1577
static uint32_t ftl_copy_block(uint32_t source, uint32_t destination)
2 theseven 1578
{
54 theseven 1579
    uint32_t i, j;
1580
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1581
    uint32_t error = 0;
1582
    ftl_cxt.nextblockusn++;
54 theseven 1583
    for (i = 0; i < ppb; i += FTL_COPYBUF_SIZE)
2 theseven 1584
    {
54 theseven 1585
        uint32_t rc = ftl_read(source * ppb + i,
1586
                               FTL_COPYBUF_SIZE, ftl_copybuffer[0]);
1587
        memset(&ftl_copyspare[0], 0xFF, 0x40 * FTL_COPYBUF_SIZE);
1588
        for (j = 0; j < FTL_COPYBUF_SIZE; j++)
2 theseven 1589
        {
54 theseven 1590
            ftl_copyspare[j].user.lpn = source * ppb + i + j;
1591
            ftl_copyspare[j].user.usn = ftl_cxt.nextblockusn;
1592
            ftl_copyspare[j].user.type = 0x40;
1593
            if (rc)
1594
            {
1595
                if (ftl_read(source * ppb + i + j, 1, ftl_copybuffer[j]))
1596
                    ftl_copyspare[j].user.eccmark = 0x55;
1597
            }
1598
            if (i + j == ppb - 1) ftl_copyspare[j].user.type = 0x41;
1599
        }
1600
        if (ftl_vfl_write(destination * ppb + i, FTL_COPYBUF_SIZE,
1601
                          ftl_copybuffer[0], &ftl_copyspare[0]))
1602
        {
2 theseven 1603
            error = 1;
1604
            break;
1605
        }
1606
    }
1607
    if (error != 0)
1608
    {
1609
        ftl_erase_block(destination);
1610
        return 1;
1611
    }
1612
    return 0;
1613
}
1614
#endif
1615
 
1616
 
1617
#ifndef FTL_READONLY
1618
/* Clears ftl_log.issequential, if something violating that is written. */
66 theseven 1619
static void ftl_check_still_sequential(struct ftl_log_type* entry, uint32_t page)
2 theseven 1620
{
54 theseven 1621
    if (entry->pagesused != entry->pagescurrent
1622
     || entry->pageoffsets[page] != page)
1623
        entry->issequential = 0;
2 theseven 1624
}
1625
#endif
1626
 
1627
 
1628
#ifndef FTL_READONLY
1629
/* Copies all pages that are currently used from the scattered page block in
1630
   use by the supplied ftl_log entry to a newly-allocated one, and releases
1631
   the old one.
1632
   In other words: It kicks the pages containing old garbage out of it to make
1633
   space again. This is usually done when a scattered page block is being
1634
   removed because it is full, but less than half of the pages in there are
1635
   still in use and rest is just filled with old crap. */
66 theseven 1636
static uint32_t ftl_compact_scattered(struct ftl_log_type* entry)
2 theseven 1637
{
1638
    uint32_t i, j;
54 theseven 1639
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1640
    uint32_t error;
1641
    struct ftl_log_type backup;
54 theseven 1642
    if (entry->pagescurrent == 0)
2 theseven 1643
    {
54 theseven 1644
        ftl_release_pool_block(entry->scatteredvblock);
1645
        entry->scatteredvblock = 0xFFFF;
2 theseven 1646
        return 0;
1647
    }
1648
    backup = *entry;
54 theseven 1649
    memcpy(ftl_offsets_backup, entry->pageoffsets, 0x400);
2 theseven 1650
    for (i = 0; i < 4; i++)
1651
    {
1652
        uint32_t block = ftl_allocate_pool_block();
1653
        if (block == 0xFFFFFFFF) return 1;
54 theseven 1654
        entry->pagesused = 0;
1655
        entry->pagescurrent = 0;
1656
        entry->issequential = 1;
1657
        entry->scatteredvblock = block;
2 theseven 1658
        error = 0;
1659
        for (j = 0; j < ppb; j++)
54 theseven 1660
            if (entry->pageoffsets[j] != 0xFFFF)
2 theseven 1661
            {
54 theseven 1662
                uint32_t lpn = entry->logicalvblock * ppb + j;
1663
                uint32_t newpage = block * ppb + entry->pagesused;
2 theseven 1664
                uint32_t oldpage = backup.scatteredvblock * ppb
54 theseven 1665
                                 + entry->pageoffsets[j];
2 theseven 1666
                if (ftl_copy_page(oldpage, newpage, lpn,
54 theseven 1667
                                  entry->issequential) != 0)
2 theseven 1668
                {
1669
                    error = 1;
1670
                    break;
1671
                }
54 theseven 1672
                entry->pageoffsets[j] = entry->pagesused++;
1673
                entry->pagescurrent++;
2 theseven 1674
                ftl_check_still_sequential(entry, j);
1675
            }
54 theseven 1676
        if (backup.pagescurrent != entry->pagescurrent) error = 1;
2 theseven 1677
        if (error == 0)
1678
        {
1679
            ftl_release_pool_block(backup.scatteredvblock);
1680
            break;
1681
        }
1682
        *entry = backup;
54 theseven 1683
        memcpy(entry->pageoffsets, ftl_offsets_backup, 0x400);
2 theseven 1684
    }
1685
    return error;
1686
}
1687
#endif
1688
 
1689
 
1690
#ifndef FTL_READONLY
1691
/* Commits an ftl_log entry to proper blocks, no matter what's in there. */
66 theseven 1692
static uint32_t ftl_commit_scattered(struct ftl_log_type* entry)
2 theseven 1693
{
1694
    uint32_t i;
1695
    uint32_t error;
1696
    uint32_t block;
1697
    for (i = 0; i < 4; i++)
1698
    {
1699
        block = ftl_allocate_pool_block();
1700
        if (block == 0xFFFFFFFF) return 1;
54 theseven 1701
        error = ftl_copy_block(entry->logicalvblock, block);
2 theseven 1702
        if (error == 0) break;
1703
        ftl_release_pool_block(block);
1704
    }
1705
    if (error != 0) return 1;
54 theseven 1706
    ftl_release_pool_block(entry->scatteredvblock);
1707
    entry->scatteredvblock = 0xFFFF;
1708
    ftl_release_pool_block(ftl_map[entry->logicalvblock]);
1709
    ftl_map[entry->logicalvblock] = block;
2 theseven 1710
    return 0;
1711
}
1712
#endif
1713
 
1714
 
1715
#ifndef FTL_READONLY
1716
/* Fills the rest of a scattered page block that was actually written
1717
   sequentially until now, in order to be able to save a block erase by
1718
   committing it without needing to copy it again.
1719
   If this fails for whichever reason, it will be committed the usual way. */
66 theseven 1720
static uint32_t ftl_commit_sequential(struct ftl_log_type* entry)
2 theseven 1721
{
54 theseven 1722
    uint32_t i;
1723
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1724
 
54 theseven 1725
    if (entry->issequential != 1
1726
     || entry->pagescurrent != entry->pagesused)
2 theseven 1727
        return 1;
1728
 
54 theseven 1729
    for (; entry->pagesused < ppb; )
2 theseven 1730
    {
54 theseven 1731
        uint32_t lpn = entry->logicalvblock * ppb + entry->pagesused;
1732
        uint32_t newpage = entry->scatteredvblock * ppb
1733
                         + entry->pagesused;
1734
        uint32_t count = FTL_COPYBUF_SIZE < ppb - entry->pagesused
1735
                       ? FTL_COPYBUF_SIZE : ppb - entry->pagesused;
1736
        for (i = 0; i < count; i++)
1737
            if (entry->pageoffsets[entry->pagesused + i] != 0xFFFF)
1738
                return ftl_commit_scattered(entry);
1739
        uint32_t rc = ftl_read(lpn, count, ftl_copybuffer[0]);
1740
        memset(&ftl_copyspare[0], 0xFF, 0x40 * FTL_COPYBUF_SIZE);
1741
        for (i = 0; i < count; i++)
1742
        {
1743
            ftl_copyspare[i].user.lpn = lpn + i;
1744
            ftl_copyspare[i].user.usn = ++ftl_cxt.nextblockusn;
1745
            ftl_copyspare[i].user.type = 0x40;
1746
            if (rc) ftl_copyspare[i].user.eccmark = 0x55;
1747
            if (entry->pagesused + i == ppb - 1)
1748
                ftl_copyspare[i].user.type = 0x41;
1749
        }
1750
        if (ftl_vfl_write(newpage, count, ftl_copybuffer[0], &ftl_copyspare[0]))
2 theseven 1751
            return ftl_commit_scattered(entry);
54 theseven 1752
        entry->pagesused += count;
2 theseven 1753
    }
54 theseven 1754
    ftl_release_pool_block(ftl_map[entry->logicalvblock]);
1755
    ftl_map[entry->logicalvblock] = entry->scatteredvblock;
1756
    entry->scatteredvblock = 0xFFFF;
2 theseven 1757
    return 0;
1758
}
1759
#endif
1760
 
1761
 
1762
#ifndef FTL_READONLY
1763
/* If a log entry is supplied, its scattered page block will be removed in
1764
   whatever way seems most appropriate. Else, the oldest scattered page block
1765
   will be freed by committing it. */
66 theseven 1766
static uint32_t ftl_remove_scattered_block(struct ftl_log_type* entry)
2 theseven 1767
{
1768
    uint32_t i;
54 theseven 1769
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1770
    uint32_t age = 0xFFFFFFFF, used = 0;
1771
    if (entry == (struct ftl_log_type*)0)
1772
    {
1773
        for (i = 0; i < 0x11; i++)
1774
        {
1775
            if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
1776
            if (ftl_log[i].pagesused == 0 || ftl_log[i].pagescurrent == 0)
1777
                return 1;
1778
            if (ftl_log[i].usn < age
1779
             || (ftl_log[i].usn == age && ftl_log[i].pagescurrent > used))
1780
            {
1781
                age = ftl_log[i].usn;
1782
                used = ftl_log[i].pagescurrent;
1783
                entry = &ftl_log[i];
1784
            }
1785
        }
1786
        if (entry == (struct ftl_log_type*)0) return 1;
1787
    }
54 theseven 1788
    else if (entry->pagescurrent < ppb / 2)
2 theseven 1789
    {
1790
        ftl_cxt.swapcounter++;
1791
        return ftl_compact_scattered(entry);
1792
    }
1793
    ftl_cxt.swapcounter++;
54 theseven 1794
    if (entry->issequential == 1) return ftl_commit_sequential(entry);
2 theseven 1795
    else return ftl_commit_scattered(entry);
1796
}
1797
#endif
1798
 
1799
 
1800
#ifndef FTL_READONLY
1801
/* Initialize a log entry to the values for an empty scattered page block */
66 theseven 1802
static void ftl_init_log_entry(struct ftl_log_type* entry)
2 theseven 1803
{
54 theseven 1804
    entry->issequential = 1;
1805
    entry->pagescurrent = 0;
1806
    entry->pagesused = 0;
1807
    memset(entry->pageoffsets, 0xFF, 0x400);
2 theseven 1808
}
1809
#endif
1810
 
1811
 
1812
#ifndef FTL_READONLY
1813
/* Allocates a log entry for the specified vBlock,
1814
   first making space, if neccessary. */
66 theseven 1815
static struct ftl_log_type* ftl_allocate_log_entry(uint32_t block)
2 theseven 1816
{
1817
    uint32_t i;
1818
    struct ftl_log_type* entry = ftl_get_log_entry(block);
54 theseven 1819
    entry->usn = ftl_cxt.nextblockusn - 1;
2 theseven 1820
    if (entry != (struct ftl_log_type*)0) return entry;
1821
 
1822
    for (i = 0; i < 0x11; i++)
1823
    {
1824
        if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
1825
        if (ftl_log[i].pagesused == 0)
1826
        {
1827
            entry = &ftl_log[i];
1828
            break;
1829
        }
1830
    }
1831
 
1832
    if (entry == (struct ftl_log_type*)0)
1833
    {
54 theseven 1834
        if (ftl_cxt.freecount < 3) panicf(PANIC_FATAL, "FTL: Detected a pool block leak!");
1835
        else if (ftl_cxt.freecount == 3)
2 theseven 1836
            if (ftl_remove_scattered_block((struct ftl_log_type*)0) != 0)
1837
                return (struct ftl_log_type*)0;
1838
        entry = ftl_log;
54 theseven 1839
        while (entry->scatteredvblock != 0xFFFF) entry = &entry[1];
1840
        entry->scatteredvblock = ftl_allocate_pool_block();
1841
        if (entry->scatteredvblock == 0xFFFF)
2 theseven 1842
            return (struct ftl_log_type*)0;
1843
    }
1844
 
1845
    ftl_init_log_entry(entry);
54 theseven 1846
    entry->logicalvblock = block;
1847
    entry->usn = ftl_cxt.nextblockusn - 1;
2 theseven 1848
 
1849
    return entry;
1850
}
1851
#endif
1852
 
1853
 
1854
#ifndef FTL_READONLY
1855
/* Commits the FTL block map, erase counters, and context to flash */
66 theseven 1856
static uint32_t ftl_commit_cxt(void)
2 theseven 1857
{
1858
    uint32_t i;
54 theseven 1859
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1860
    uint32_t mappages = (ftl_nand_type->userblocks + 0x3ff) >> 10;
1861
    uint32_t ctrpages = (ftl_nand_type->userblocks + 23 + 0x3ff) >> 10;
2 theseven 1862
    uint32_t endpage = ftl_cxt.ftlctrlpage + mappages + ctrpages + 1;
61 theseven 1863
    DEBUGF("FTL: Committing context");
54 theseven 1864
    if (endpage >= (ftl_cxt.ftlctrlpage / ppb + 1) * ppb)
2 theseven 1865
        ftl_cxt.ftlctrlpage |= ppb - 1;
1866
    for (i = 0; i < ctrpages; i++)
1867
    {
1868
        if (ftl_next_ctrl_pool_page() != 0) return 1;
1869
        if (ftl_save_erasectr_page(i) != 0) return 1;
1870
    }
1871
    for (i = 0; i < mappages; i++)
1872
    {
1873
        if (ftl_next_ctrl_pool_page() != 0) return 1;
54 theseven 1874
        memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1875
        ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1876
        ftl_sparebuffer[0].meta.idx = i;
1877
        ftl_sparebuffer[0].meta.type = 0x44;
1878
        if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, &ftl_map[i << 10],
1879
                          &ftl_sparebuffer[0]) != 0)
2 theseven 1880
            return 1;
1881
        ftl_cxt.ftl_map_pages[i] = ftl_cxt.ftlctrlpage;
1882
    }
1883
    if (ftl_next_ctrl_pool_page() != 0) return 1;
1884
    ftl_cxt.clean_flag = 1;
54 theseven 1885
    memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1886
    ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1887
    ftl_sparebuffer[0].meta.type = 0x43;
1888
    if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, &ftl_cxt, &ftl_sparebuffer[0]) != 0)
2 theseven 1889
        return 1;
61 theseven 1890
    DEBUGF("FTL: Wrote context to page %d", ftl_cxt.ftlctrlpage);
2 theseven 1891
    return 0;
1892
}
1893
#endif
1894
 
1895
 
1896
#ifndef FTL_READONLY
1897
/* Swaps the most and least worn block on the flash,
1898
   to better distribute wear. It will refuse to do anything
1899
   if the wear spread is lower than 5 erases. */
66 theseven 1900
static uint32_t ftl_swap_blocks(void)
2 theseven 1901
{
1902
    uint32_t i;
1903
    uint32_t min = 0xFFFFFFFF, max = 0, maxidx = 0x14;
1904
    uint32_t minidx = 0, minvb = 0, maxvb = 0;
1905
    for (i = 0; i < ftl_cxt.freecount; i++)
1906
    {
1907
        uint32_t idx = ftl_cxt.nextfreeidx + i;
1908
        if (idx >= 0x14) idx -= 0x14;
1909
        if (ftl_erasectr[ftl_cxt.blockpool[idx]] > max)
1910
        {
1911
            maxidx = idx;
1912
            maxvb = ftl_cxt.blockpool[idx];
1913
            max = ftl_erasectr[maxidx];
1914
        }
1915
    }
1916
    if (maxidx == 0x14) return 0;
54 theseven 1917
    for (i = 0; i < ftl_nand_type->userblocks; i++)
2 theseven 1918
    {
1919
        if (ftl_erasectr[ftl_map[i]] > max) max = ftl_erasectr[ftl_map[i]];
1920
        if (ftl_get_log_entry(i) != (struct ftl_log_type*)0) continue;
1921
        if (ftl_erasectr[ftl_map[i]] < min)
1922
        {
1923
            minidx = i;
1924
            minvb = ftl_map[i];
1925
            min = ftl_erasectr[minidx];
1926
        }
1927
    }
1928
    if (max - min < 5) return 0;
1929
    if (minvb == maxvb) return 0;
1930
    if (ftl_erase_block(maxvb) != 0) return 1;
1931
    if (ftl_copy_block(minidx, maxvb) != 0) return 1;
1932
    ftl_cxt.blockpool[maxidx] = minvb;
1933
    ftl_map[minidx] = maxvb;
1934
    return 0;
1935
}
1936
#endif
1937
 
1938
 
1939
#ifndef FTL_READONLY
1940
/* Exposed function: Write highlevel sectors */
54 theseven 1941
uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer)
2 theseven 1942
{
54 theseven 1943
    uint32_t i, j, k;
1944
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 1945
 
54 theseven 1946
#ifdef FTL_TRACE
61 theseven 1947
    DEBUGF("FTL: Writing %d sectors starting at %d", count, sector);
54 theseven 1948
#endif
1949
 
68 theseven 1950
	if ((uint32_t)buffer & 0xf)
1951
		panicf(PANIC_KILLTHREAD,
1952
		       "ftl_write: Misaligned data buffer at %08X (sector %lu, count %lu)",
1953
			   (unsigned int)buffer, sector, count);
1954
 
54 theseven 1955
    if (sector + count > ftl_nand_type->userblocks * ppb)
1956
    {
61 theseven 1957
        DEBUGF("FTL: Sector %d is out of range!", sector + count - 1);
2 theseven 1958
        return 1;
54 theseven 1959
    }
2 theseven 1960
    if (count == 0) return 0;
1961
 
54 theseven 1962
    mutex_lock(&ftl_mtx, TIMEOUT_BLOCK);
1963
 
2 theseven 1964
    if (ftl_cxt.clean_flag == 1)
1965
    {
1966
        for (i = 0; i < 3; i++)
1967
        {
61 theseven 1968
		    DEBUGF("FTL: Marking dirty, try %d", i);
54 theseven 1969
            if (ftl_next_ctrl_pool_page() != 0)
1970
            {
1971
                mutex_unlock(&ftl_mtx);
1972
                return 1;
1973
            }
2 theseven 1974
            memset(ftl_buffer, 0xFF, 0x800);
54 theseven 1975
            memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1976
            ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1977
            ftl_sparebuffer[0].meta.type = 0x47;
1978
            if (ftl_vfl_write(ftl_cxt.ftlctrlpage, 1, ftl_buffer,
1979
                              &ftl_sparebuffer[0]) == 0)
2 theseven 1980
                break;
1981
        }
54 theseven 1982
        if (i == 3)
1983
        {
1984
            mutex_unlock(&ftl_mtx);
1985
            return 1;
1986
        }
61 theseven 1987
    	DEBUGF("FTL: Wrote dirty mark to %d", ftl_cxt.ftlctrlpage);
2 theseven 1988
        ftl_cxt.clean_flag = 0;
1989
    }
1990
 
1991
    for (i = 0; i < count; )
1992
    {
1993
        uint32_t block = (sector + i) / ppb;
1994
        uint32_t page = (sector + i) % ppb;
1995
 
1996
        struct ftl_log_type* logentry = ftl_allocate_log_entry(block);
54 theseven 1997
        if (logentry == (struct ftl_log_type*)0)
1998
        {
1999
            mutex_unlock(&ftl_mtx);
2000
            return 1;
2001
        }
2 theseven 2002
        if (page == 0 && count - i >= ppb)
2003
        {
54 theseven 2004
#ifdef FTL_TRACE
61 theseven 2005
		    DEBUGF("FTL: Going to write a full hyperblock in one shot");
54 theseven 2006
#endif
2007
            uint32_t vblock = logentry->scatteredvblock;
2008
            logentry->scatteredvblock = 0xFFFF;
2009
            if (logentry->pagesused != 0)
2 theseven 2010
            {
54 theseven 2011
#ifdef FTL_TRACE
61 theseven 2012
    			DEBUGF("FTL: Scattered block had some pages already used, committing");
54 theseven 2013
#endif
2 theseven 2014
                ftl_release_pool_block(vblock);
2015
                vblock = ftl_allocate_pool_block();
54 theseven 2016
                if (vblock == 0xFFFFFFFF)
2017
                {
2018
                    mutex_unlock(&ftl_mtx);
2019
                    return 1;
2020
                }
2 theseven 2021
            }
2022
            ftl_cxt.nextblockusn++;
54 theseven 2023
            for (j = 0; j < ppb; j += FTL_WRITESPARE_SIZE)
2 theseven 2024
            {
54 theseven 2025
                memset(&ftl_sparebuffer[0], 0xFF, 0x40 * FTL_WRITESPARE_SIZE);
2026
                for (k = 0; k < FTL_WRITESPARE_SIZE; k++)
2027
                {
2028
                    ftl_sparebuffer[k].user.lpn = sector + i + j + k;
2029
                    ftl_sparebuffer[k].user.usn = ftl_cxt.nextblockusn;
2030
                    ftl_sparebuffer[k].user.type = 0x40;
2031
                    if (j == ppb - 1) ftl_sparebuffer[k].user.type = 0x41;
2032
                }
2033
                uint32_t rc = ftl_vfl_write(vblock * ppb + j, FTL_WRITESPARE_SIZE,
2034
                                            &((uint8_t*)buffer)[(i + j) << 11],
2035
                                            &ftl_sparebuffer[0]);
2036
                if (rc)
2037
                    for (k = 0; k < ftl_banks; k++)
2038
                        if (rc & (1 << k))
2039
                        {
2040
                            while (ftl_vfl_write(vblock * ppb + j + k, 1,
2041
                                                 &((uint8_t*)buffer)[(i + j + k) << 11],
2042
                                                 &ftl_sparebuffer[k]));
2043
                        }
2 theseven 2044
            }
2045
            ftl_release_pool_block(ftl_map[block]);
2046
            ftl_map[block] = vblock;
2047
            i += ppb;
2048
        }
2049
        else
2050
        {
54 theseven 2051
            if (logentry->pagesused == ppb)
2 theseven 2052
            {
54 theseven 2053
#ifdef FTL_TRACE
61 theseven 2054
    			DEBUGF("FTL: Scattered block is full, committing");
54 theseven 2055
#endif
2 theseven 2056
                ftl_remove_scattered_block(logentry);
2057
                logentry = ftl_allocate_log_entry(block);
54 theseven 2058
                if (logentry == (struct ftl_log_type*)0)
2059
                {
2060
                    mutex_unlock(&ftl_mtx);
2061
                    return 1;
2062
                }
2 theseven 2063
            }
54 theseven 2064
            uint32_t cnt = FTL_WRITESPARE_SIZE;
2065
            if (cnt > count - i) cnt = count - i;
2066
            if (cnt > ppb - logentry->pagesused) cnt = ppb - logentry->pagesused;
2067
            if (cnt > ppb - page) cnt = ppb - page;
2068
            memset(&ftl_sparebuffer[0], 0xFF, 0x40 * cnt);
2069
            for (j = 0; j < cnt; j++)
2 theseven 2070
            {
54 theseven 2071
                ftl_sparebuffer[j].user.lpn = sector + i + j;
2072
                ftl_sparebuffer[j].user.usn = ++ftl_cxt.nextblockusn;
2073
                ftl_sparebuffer[j].user.type = 0x40;
2074
                if (logentry->pagesused + j == ppb - 1 && logentry->issequential)
2075
                    ftl_sparebuffer[j].user.type = 0x41;
2 theseven 2076
            }
54 theseven 2077
            uint32_t abspage = logentry->scatteredvblock * ppb
2078
                             + logentry->pagesused;
2079
            logentry->pagesused += cnt;
2080
            if (ftl_vfl_write(abspage, cnt, &((uint8_t*)buffer)[i << 11],
2081
                              &ftl_sparebuffer[0]) == 0)
2082
            {
2083
                for (j = 0; j < cnt; j++)
2084
                {
2085
                    if (logentry->pageoffsets[page + j] == 0xFFFF)
2086
                        logentry->pagescurrent++;
2087
                    logentry->pageoffsets[page + j] = logentry->pagesused - cnt + j;
2088
                    if (logentry->pagesused - cnt + j + 1 != logentry->pagescurrent
2089
                     || logentry->pageoffsets[page + j] != page + j)
2090
                        logentry->issequential = 0;
2091
                }
2092
                i += cnt;
2093
            }
2094
            else panicf(PANIC_FATAL, "FTL: Write error: %u %u %u!",
2095
                        (unsigned)sector, (unsigned)count, (unsigned)i);
2 theseven 2096
        }
54 theseven 2097
        if (logentry->pagesused == ppb) ftl_remove_scattered_block(logentry);
2 theseven 2098
    }
2099
    if (ftl_cxt.swapcounter >= 300)
2100
    {
2101
        ftl_cxt.swapcounter -= 20;
2102
        for (i = 0; i < 4; i++) if (ftl_swap_blocks() == 0) break;
2103
    }
2104
    if (ftl_cxt.erasedirty == 1)
2105
    {
2106
        ftl_cxt.erasedirty = 0;
2107
        for (i = 0; i < 8; i++)
2108
            if (ftl_erasectr_dirt[i] >= 100)
2109
            {
2110
                ftl_next_ctrl_pool_page();
2111
                ftl_save_erasectr_page(i);
2112
            }
2113
    }
54 theseven 2114
    mutex_unlock(&ftl_mtx);
2 theseven 2115
    return 0;
2116
}
2117
#endif
2118
 
2119
 
2120
#ifndef FTL_READONLY
54 theseven 2121
/* Exposed function: Performes a sync / unmount,
2122
   i.e. commits all scattered page blocks,
2123
   distributes wear, and commits the FTL context. */
2124
uint32_t ftl_sync(void)
2 theseven 2125
{
2126
    uint32_t i;
2127
    uint32_t rc = 0;
54 theseven 2128
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2 theseven 2129
    if (ftl_cxt.clean_flag == 1) return 0;
2130
 
66 theseven 2131
    mutex_lock(&ftl_mtx, TIMEOUT_BLOCK);
2132
 
54 theseven 2133
#ifdef FTL_TRACE
61 theseven 2134
    DEBUGF("FTL: Syncing");
54 theseven 2135
#endif
2136
 
2 theseven 2137
    if (ftl_cxt.swapcounter >= 20)
2138
        for (i = 0; i < 4; i++)
2139
            if (ftl_swap_blocks() == 0)
2140
            {
2141
                ftl_cxt.swapcounter -= 20;
2142
                break;
2143
            }
2144
    for (i = 0; i < 0x11; i++)
2145
    {
2146
        if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
2147
        ftl_cxt.nextblockusn++;
2148
        if (ftl_log[i].issequential == 1)
2149
            rc |= ftl_commit_sequential(&ftl_log[i]);
2150
        else rc |= ftl_commit_scattered(&ftl_log[i]);
2151
    }
54 theseven 2152
    if (rc != 0)
2153
    {
2154
        mutex_unlock(&ftl_mtx);
2155
        return 1;
2156
    }
2157
    for (i = 0; i < 5; i++)
2158
        if (ftl_commit_cxt() == 0)
2159
        {
2160
            mutex_unlock(&ftl_mtx);
2161
            return 0;
2162
        }
2163
        else ftl_cxt.ftlctrlpage |= ppb - 1;
2164
    mutex_unlock(&ftl_mtx);
2 theseven 2165
    return 1;
2166
}
2167
#endif
2168
 
2169
 
2170
/* Initializes and mounts the FTL.
2171
   As long as nothing was written, you won't need to unmount it.
54 theseven 2172
   Before shutting down after writing something, call ftl_sync(),
2 theseven 2173
   which will just do nothing if everything was already clean. */
54 theseven 2174
uint32_t ftl_init(void)
2 theseven 2175
{
54 theseven 2176
    mutex_init(&ftl_mtx);
2 theseven 2177
    uint32_t i;
2178
    uint32_t result = 0;
2179
    uint32_t foundsignature, founddevinfo, blockwiped, repaired, skip;
61 theseven 2180
    int rc;
2181
    if ((rc = nand_device_init()) != 0) //return 1;
2182
        panicf(PANIC_FATAL, "FTL: Lowlevel NAND driver init failed: %d", rc);
2 theseven 2183
    ftl_banks = 0;
2184
    for (i = 0; i < 4; i++)
2185
        if (nand_get_device_type(i) != 0) ftl_banks = i + 1;
2186
    ftl_nand_type = nand_get_device_type(0);
2187
    foundsignature = 0;
2188
    blockwiped = 1;
54 theseven 2189
    for (i = 0; i < ftl_nand_type->pagesperblock; i++)
2 theseven 2190
    {
2191
        result = nand_read_page(0, i, ftl_buffer, (uint32_t*)0, 1, 1);
2192
        if ((result & 0x11F) == 0)
2193
        {
2194
            blockwiped = 0;
2195
            if (((uint32_t*)ftl_buffer)[0] != 0x41303034) continue;
2196
            foundsignature = 1;
2197
            break;
2198
        }
2199
        else if ((result & 2) != 2) blockwiped = 0;
2200
    }
54 theseven 2201
 
2 theseven 2202
    founddevinfo = ftl_has_devinfo();
2203
 
2204
    repaired = 0;
2205
    skip = 0;
54 theseven 2206
    if (founddevinfo == 0)
2207
    {
2208
	   	DEBUGF("FTL: No DEVICEINFO found!");
2209
        return 1;
2210
    }
2211
    if (foundsignature != 0 && (result & 0x11F) != 0)
2212
    {
2213
        DEBUGF("FTL: Problem with the signature!");
2214
        return 1;
2215
    }
2 theseven 2216
    if (ftl_vfl_open() == 0)
2217
        if (ftl_open() == 0)
2218
            return 0;
2219
 
54 theseven 2220
    DEBUGF("FTL: Initialization failed!");
2221
 
2 theseven 2222
    return 1;
2223
}