Subversion Repositories freemyipod

Rev

Rev 61 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 61 Rev 66
Line 360... Line 360...
360
 
360
 
361
/* Number of banks we detected a chip on */
361
/* Number of banks we detected a chip on */
362
uint32_t ftl_banks;
362
uint32_t ftl_banks;
363
 
363
 
364
/* Block map, used vor pBlock to vBlock mapping */
364
/* Block map, used vor pBlock to vBlock mapping */
365
uint16_t ftl_map[0x2000];
365
static uint16_t ftl_map[0x2000];
366
 
366
 
367
/* VFL context for each bank */
367
/* VFL context for each bank */
368
struct ftl_vfl_cxt_type ftl_vfl_cxt[4];
368
static struct ftl_vfl_cxt_type ftl_vfl_cxt[4];
369
 
369
 
370
/* FTL context */
370
/* FTL context */
371
struct ftl_cxt_type ftl_cxt;
371
static struct ftl_cxt_type ftl_cxt;
372
 
372
 
373
/* Temporary data buffers for internal use by the FTL */
373
/* Temporary data buffers for internal use by the FTL */
374
uint8_t ftl_buffer[0x800] CACHEALIGN_ATTR;
374
static uint8_t ftl_buffer[0x800] CACHEALIGN_ATTR;
375
 
375
 
376
/* Temporary spare byte buffer for internal use by the FTL */
376
/* Temporary spare byte buffer for internal use by the FTL */
377
union ftl_spare_data_type ftl_sparebuffer[FTL_WRITESPARE_SIZE] CACHEALIGN_ATTR;
377
static union ftl_spare_data_type ftl_sparebuffer[FTL_WRITESPARE_SIZE] CACHEALIGN_ATTR;
378
 
378
 
379
 
379
 
380
#ifndef FTL_READONLY
380
#ifndef FTL_READONLY
381
 
381
 
382
/* Lowlevel BBT for each bank */
382
/* Lowlevel BBT for each bank */
383
uint8_t ftl_bbt[4][0x410];
383
static uint8_t ftl_bbt[4][0x410];
384
 
384
 
385
/* Erase counters for the vBlocks */
385
/* Erase counters for the vBlocks */
386
uint16_t ftl_erasectr[0x2000];
386
static uint16_t ftl_erasectr[0x2000];
387
 
387
 
388
/* Used by ftl_log */
388
/* Used by ftl_log */
389
uint16_t ftl_offsets[0x11][0x200];
389
static uint16_t ftl_offsets[0x11][0x200];
390
 
390
 
391
/* Structs keeping record of scattered page blocks */
391
/* Structs keeping record of scattered page blocks */
392
struct ftl_log_type ftl_log[0x11];
392
static struct ftl_log_type ftl_log[0x11];
393
 
393
 
394
/* Global cross-bank update sequence number of the VFL context */
394
/* Global cross-bank update sequence number of the VFL context */
395
uint32_t ftl_vfl_usn;
395
static uint32_t ftl_vfl_usn;
396
 
396
 
397
/* Keeps track (temporarily) of troublesome blocks */
397
/* Keeps track (temporarily) of troublesome blocks */
398
struct ftl_trouble_type ftl_troublelog[5];
398
static struct ftl_trouble_type ftl_troublelog[5];
399
 
399
 
400
/* Counts erase counter page changes, after 100 of them the affected
400
/* Counts erase counter page changes, after 100 of them the affected
401
   page will be committed to the flash. */
401
   page will be committed to the flash. */
402
uint8_t ftl_erasectr_dirt[8];
402
static uint8_t ftl_erasectr_dirt[8];
403
 
403
 
404
/* Buffer needed for copying pages around while moving or committing blocks.
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
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. */
406
   during the copying operation in order to e.g. commit a CXT. */
407
uint8_t ftl_copybuffer[FTL_COPYBUF_SIZE][0x800] CACHEALIGN_ATTR;
407
static uint8_t ftl_copybuffer[FTL_COPYBUF_SIZE][0x800] CACHEALIGN_ATTR;
408
union ftl_spare_data_type ftl_copyspare[FTL_COPYBUF_SIZE] CACHEALIGN_ATTR;
408
static union ftl_spare_data_type ftl_copyspare[FTL_COPYBUF_SIZE] CACHEALIGN_ATTR;
409
 
409
 
410
/* Needed to store the old scattered page offsets in order to be able to roll
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. */
411
   back if something fails while compacting a scattered page block. */
412
uint16_t ftl_offsets_backup[0x200] CACHEALIGN_ATTR;
412
static uint16_t ftl_offsets_backup[0x200] CACHEALIGN_ATTR;
413
 
413
 
414
#endif
414
#endif
415
 
415
 
416
 
416
 
417
static struct mutex ftl_mtx;
417
static struct mutex ftl_mtx;
418
 
418
 
419
 
419
 
420
 
420
 
421
/* Finds a device info page for the specified bank and returns its number.
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. */
422
   Used to check if one is present, and to read the lowlevel BBT. */
423
uint32_t ftl_find_devinfo(uint32_t bank)
423
static uint32_t ftl_find_devinfo(uint32_t bank)
424
{
424
{
425
    /* Scan the last 10% of the flash for device info pages */
425
    /* Scan the last 10% of the flash for device info pages */
426
    uint32_t lowestBlock = ftl_nand_type->blocks
426
    uint32_t lowestBlock = ftl_nand_type->blocks
427
                         - (ftl_nand_type->blocks / 10);
427
                         - (ftl_nand_type->blocks / 10);
428
    uint32_t block, page, pagenum;
428
    uint32_t block, page, pagenum;
Line 442... Line 442...
442
    return 0;
442
    return 0;
443
}
443
}
444
 
444
 
445
 
445
 
446
/* Checks if all banks have proper device info pages */
446
/* Checks if all banks have proper device info pages */
447
uint32_t ftl_has_devinfo(void)
447
static uint32_t ftl_has_devinfo(void)
448
{
448
{
449
    uint32_t i;
449
    uint32_t i;
450
    for (i = 0; i < ftl_banks; i++) if (ftl_find_devinfo(i) == 0) return 0;
450
    for (i = 0; i < ftl_banks; i++) if (ftl_find_devinfo(i) == 0) return 0;
451
    return 1;
451
    return 1;
452
}
452
}
453
 
453
 
454
 
454
 
455
/* Loads the lowlevel BBT for a bank to the specified buffer.
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. */
456
   This is based on some cryptic disassembly and not fully understood yet. */
457
uint32_t ftl_load_bbt(uint32_t bank, uint8_t* bbt)
457
static uint32_t ftl_load_bbt(uint32_t bank, uint8_t* bbt)
458
{
458
{
459
    uint32_t i, j;
459
    uint32_t i, j;
460
    uint32_t pagebase, page = ftl_find_devinfo(bank), page2;
460
    uint32_t pagebase, page = ftl_find_devinfo(bank), page2;
461
    uint32_t unk1, unk2, unk3;
461
    uint32_t unk1, unk2, unk3;
462
    if (page == 0) return 1;
462
    if (page == 0) return 1;
Line 486... Line 486...
486
    return 1;
486
    return 1;
487
}
487
}
488
 
488
 
489
 
489
 
490
/* Calculates the checksums for the VFL context page of the specified bank */
490
/* Calculates the checksums for the VFL context page of the specified bank */
491
void ftl_vfl_calculate_checksum(uint32_t bank,
491
static void ftl_vfl_calculate_checksum(uint32_t bank,
492
                                uint32_t* checksum1, uint32_t* checksum2)
492
                                       uint32_t* checksum1, uint32_t* checksum2)
493
{
493
{
494
    uint32_t i;
494
    uint32_t i;
495
    *checksum1 = 0xAABBCCDD;
495
    *checksum1 = 0xAABBCCDD;
496
    *checksum2 = 0xAABBCCDD;
496
    *checksum2 = 0xAABBCCDD;
497
    for (i = 0; i < 0x1FE; i++)
497
    for (i = 0; i < 0x1FE; i++)
Line 502... Line 502...
502
}
502
}
503
 
503
 
504
 
504
 
505
/* Checks if the checksums of the VFL context
505
/* Checks if the checksums of the VFL context
506
   of the specified bank are correct */
506
   of the specified bank are correct */
507
uint32_t ftl_vfl_verify_checksum(uint32_t bank)
507
static uint32_t ftl_vfl_verify_checksum(uint32_t bank)
508
{
508
{
509
    uint32_t checksum1, checksum2;
509
    uint32_t checksum1, checksum2;
510
    ftl_vfl_calculate_checksum(bank, &checksum1, &checksum2);
510
    ftl_vfl_calculate_checksum(bank, &checksum1, &checksum2);
511
    if (checksum1 == ftl_vfl_cxt[bank].checksum1) return 0;
511
    if (checksum1 == ftl_vfl_cxt[bank].checksum1) return 0;
512
    /* The following line is pretty obviously a bug in Whimory,
512
    /* The following line is pretty obviously a bug in Whimory,
Line 517... Line 517...
517
}
517
}
518
 
518
 
519
 
519
 
520
#ifndef FTL_READONLY
520
#ifndef FTL_READONLY
521
/* Updates the checksums of the VFL context of the specified bank */
521
/* Updates the checksums of the VFL context of the specified bank */
522
void ftl_vfl_update_checksum(uint32_t bank)
522
static void ftl_vfl_update_checksum(uint32_t bank)
523
{
523
{
524
    ftl_vfl_calculate_checksum(bank, &ftl_vfl_cxt[bank].checksum1,
524
    ftl_vfl_calculate_checksum(bank, &ftl_vfl_cxt[bank].checksum1,
525
                               &ftl_vfl_cxt[bank].checksum2);
525
                               &ftl_vfl_cxt[bank].checksum2);
526
}
526
}
527
#endif
527
#endif
528
 
528
 
529
 
529
 
530
#ifndef FTL_READONLY
530
#ifndef FTL_READONLY
531
/* Writes 8 copies of the VFL context of the specified bank to flash,
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. */
532
   and succeeds if at least 4 can be read back properly. */
533
uint32_t ftl_vfl_store_cxt(uint32_t bank)
533
static uint32_t ftl_vfl_store_cxt(uint32_t bank)
534
{
534
{
535
    uint32_t i;
535
    uint32_t i;
536
    ftl_vfl_cxt[bank].updatecount--;
536
    ftl_vfl_cxt[bank].updatecount--;
537
    ftl_vfl_cxt[bank].usn = ++ftl_vfl_usn;
537
    ftl_vfl_cxt[bank].usn = ++ftl_vfl_usn;
538
    ftl_vfl_cxt[bank].nextcxtpage += 8;
538
    ftl_vfl_cxt[bank].nextcxtpage += 8;
Line 572... Line 572...
572
 
572
 
573
 
573
 
574
#ifndef FTL_READONLY
574
#ifndef FTL_READONLY
575
/* Commits the VFL context of the specified bank to flash,
575
/* Commits the VFL context of the specified bank to flash,
576
   retries until it works or all available pages have been tried */
576
   retries until it works or all available pages have been tried */
577
uint32_t ftl_vfl_commit_cxt(uint32_t bank)
577
static uint32_t ftl_vfl_commit_cxt(uint32_t bank)
578
{
578
{
579
    DEBUGF("FTL: VFL: Committing context on bank %d", bank);
579
    DEBUGF("FTL: VFL: Committing context on bank %d", bank);
580
    if (ftl_vfl_cxt[bank].nextcxtpage + 8 <= ftl_nand_type->pagesperblock)
580
    if (ftl_vfl_cxt[bank].nextcxtpage + 8 <= ftl_nand_type->pagesperblock)
581
        if (ftl_vfl_store_cxt(bank) == 0) return 0;
581
        if (ftl_vfl_store_cxt(bank) == 0) return 0;
582
    uint32_t current = ftl_vfl_cxt[bank].activecxtblock;
582
    uint32_t current = ftl_vfl_cxt[bank].activecxtblock;
Line 602... Line 602...
602
 
602
 
603
 
603
 
604
/* Returns a pointer to the most recently updated VFL context,
604
/* Returns a pointer to the most recently updated VFL context,
605
   used to find out the current FTL context vBlock numbers
605
   used to find out the current FTL context vBlock numbers
606
   (planetbeing's "maxthing") */
606
   (planetbeing's "maxthing") */
607
struct ftl_vfl_cxt_type* ftl_vfl_get_newest_cxt(void)
607
static struct ftl_vfl_cxt_type* ftl_vfl_get_newest_cxt(void)
608
{
608
{
609
    uint32_t i, maxusn;
609
    uint32_t i, maxusn;
610
    struct ftl_vfl_cxt_type* cxt = (struct ftl_vfl_cxt_type*)0;
610
    struct ftl_vfl_cxt_type* cxt = (struct ftl_vfl_cxt_type*)0;
611
    maxusn = 0;
611
    maxusn = 0;
612
    for (i = 0; i < ftl_banks; i++)
612
    for (i = 0; i < ftl_banks; i++)
Line 619... Line 619...
619
}
619
}
620
 
620
 
621
 
621
 
622
/* Checks if the specified pBlock is marked bad in the supplied lowlevel BBT.
622
/* Checks if the specified pBlock is marked bad in the supplied lowlevel BBT.
623
   Only used while mounting the VFL. */
623
   Only used while mounting the VFL. */
624
uint32_t ftl_is_good_block(uint8_t* bbt, uint32_t block)
624
static uint32_t ftl_is_good_block(uint8_t* bbt, uint32_t block)
625
{
625
{
626
    if ((bbt[block >> 3] & (1 << (block & 7))) == 0) return 0;
626
    if ((bbt[block >> 3] & (1 << (block & 7))) == 0) return 0;
627
    else return 1;
627
    else return 1;
628
}
628
}
629
 
629
 
630
 
630
 
631
/* Checks if the specified vBlock could be remapped */
631
/* Checks if the specified vBlock could be remapped */
632
uint32_t ftl_vfl_is_good_block(uint32_t bank, uint32_t block)
632
static uint32_t ftl_vfl_is_good_block(uint32_t bank, uint32_t block)
633
{
633
{
634
    uint8_t bbtentry = ftl_vfl_cxt[bank].bbt[block >> 6];
634
    uint8_t bbtentry = ftl_vfl_cxt[bank].bbt[block >> 6];
635
    if ((bbtentry & (1 << ((7 - (block >> 3)) & 7))) == 0) return 0;
635
    if ((bbtentry & (1 << ((7 - (block >> 3)) & 7))) == 0) return 0;
636
    else return 1;
636
    else return 1;
637
}
637
}
638
 
638
 
639
 
639
 
640
#ifndef FTL_READONLY
640
#ifndef FTL_READONLY
641
/* Sets or unsets the bad bit of the specified vBlock
641
/* Sets or unsets the bad bit of the specified vBlock
642
   in the specified bank's VFL context */
642
   in the specified bank's VFL context */
643
void ftl_vfl_set_good_block(uint32_t bank, uint32_t block, uint32_t isgood)
643
static void ftl_vfl_set_good_block(uint32_t bank, uint32_t block, uint32_t isgood)
644
{
644
{
645
    uint8_t bit = (1 << ((7 - (block >> 3)) & 7));
645
    uint8_t bit = (1 << ((7 - (block >> 3)) & 7));
646
    if (isgood == 1) ftl_vfl_cxt[bank].bbt[block >> 6] |= bit;
646
    if (isgood == 1) ftl_vfl_cxt[bank].bbt[block >> 6] |= bit;
647
    else ftl_vfl_cxt[bank].bbt[block >> 6] &= ~bit;
647
    else ftl_vfl_cxt[bank].bbt[block >> 6] &= ~bit;
648
}
648
}
649
#endif
649
#endif
650
 
650
 
651
 
651
 
652
/* Tries to read a VFL context from the specified bank, pBlock and page */
652
/* Tries to read a VFL context from the specified bank, pBlock and page */
653
uint32_t ftl_vfl_read_page(uint32_t bank, uint32_t block,
653
static uint32_t ftl_vfl_read_page(uint32_t bank, uint32_t block,
654
                           uint32_t startpage, void* databuffer,
654
                                  uint32_t startpage, void* databuffer,
655
                           union ftl_spare_data_type* sparebuffer)
655
                                  union ftl_spare_data_type* sparebuffer)
656
{
656
{
657
    uint32_t i;
657
    uint32_t i;
658
    for (i = 0; i < 8; i++)
658
    for (i = 0; i < 8; i++)
659
    {
659
    {
660
        uint32_t page = block * ftl_nand_type->pagesperblock
660
        uint32_t page = block * ftl_nand_type->pagesperblock
Line 668... Line 668...
668
    return 1;
668
    return 1;
669
}
669
}
670
 
670
 
671
 
671
 
672
/* Translates a bank and vBlock to a pBlock, following remaps */
672
/* Translates a bank and vBlock to a pBlock, following remaps */
673
uint32_t ftl_vfl_get_physical_block(uint32_t bank, uint32_t block)
673
static uint32_t ftl_vfl_get_physical_block(uint32_t bank, uint32_t block)
674
{
674
{
675
    if (ftl_vfl_is_good_block(bank, block) == 1) return block;
675
    if (ftl_vfl_is_good_block(bank, block) == 1) return block;
676
 
676
 
677
    uint32_t spareindex;
677
    uint32_t spareindex;
678
    uint32_t spareused = ftl_vfl_cxt[bank].spareused;
678
    uint32_t spareused = ftl_vfl_cxt[bank].spareused;
Line 687... Line 687...
687
}
687
}
688
 
688
 
689
 
689
 
690
#ifndef FTL_READONLY
690
#ifndef FTL_READONLY
691
/* Checks if remapping is scheduled for the specified bank and vBlock */
691
/* Checks if remapping is scheduled for the specified bank and vBlock */
692
uint32_t ftl_vfl_check_remap_scheduled(uint32_t bank, uint32_t block)
692
static uint32_t ftl_vfl_check_remap_scheduled(uint32_t bank, uint32_t block)
693
{
693
{
694
    uint32_t i;
694
    uint32_t i;
695
    for (i = 0x333; i > 0 && i > ftl_vfl_cxt[bank].scheduledstart; 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;
696
        if (ftl_vfl_cxt[bank].remaptable[i] == block) return 1;
697
    return 0;
697
    return 0;
Line 699... Line 699...
699
#endif
699
#endif
700
 
700
 
701
 
701
 
702
#ifndef FTL_READONLY
702
#ifndef FTL_READONLY
703
/* Schedules remapping for the specified bank and vBlock */
703
/* Schedules remapping for the specified bank and vBlock */
704
void ftl_vfl_schedule_block_for_remap(uint32_t bank, uint32_t block)
704
static void ftl_vfl_schedule_block_for_remap(uint32_t bank, uint32_t block)
705
{
705
{
706
    if (ftl_vfl_check_remap_scheduled(bank, block) == 1) return;
706
    if (ftl_vfl_check_remap_scheduled(bank, block) == 1) return;
707
    panicf(PANIC_FATAL, "FTL: Scheduling bank %u block %u for remap!",
707
    panicf(PANIC_FATAL, "FTL: Scheduling bank %u block %u for remap!",
708
	       (unsigned)bank, (unsigned)block);
708
	       (unsigned)bank, (unsigned)block);
709
    if (ftl_vfl_cxt[bank].scheduledstart == ftl_vfl_cxt[bank].spareused)
709
    if (ftl_vfl_cxt[bank].scheduledstart == ftl_vfl_cxt[bank].spareused)
Line 715... Line 715...
715
 
715
 
716
 
716
 
717
#ifndef FTL_READONLY
717
#ifndef FTL_READONLY
718
/* Removes the specified bank and vBlock combination
718
/* Removes the specified bank and vBlock combination
719
   from the remap scheduled list */
719
   from the remap scheduled list */
720
void ftl_vfl_mark_remap_done(uint32_t bank, uint32_t block)
720
static void ftl_vfl_mark_remap_done(uint32_t bank, uint32_t block)
721
{
721
{
722
    uint32_t i;
722
    uint32_t i;
723
    uint32_t start = ftl_vfl_cxt[bank].scheduledstart;
723
    uint32_t start = ftl_vfl_cxt[bank].scheduledstart;
724
    uint32_t lastscheduled = ftl_vfl_cxt[bank].remaptable[start];
724
    uint32_t lastscheduled = ftl_vfl_cxt[bank].remaptable[start];
725
    for (i = 0x333; i > 0 && i > start; i--)
725
    for (i = 0x333; i > 0 && i > start; i--)
Line 736... Line 736...
736
 
736
 
737
#ifndef FTL_READONLY
737
#ifndef FTL_READONLY
738
/* Logs that there is trouble for the specified vBlock on the specified bank.
738
/* Logs that there is trouble for the specified vBlock on the specified bank.
739
   The vBlock will be scheduled for remap
739
   The vBlock will be scheduled for remap
740
   if there is too much trouble with it. */
740
   if there is too much trouble with it. */
741
void ftl_vfl_log_trouble(uint32_t bank, uint32_t vblock)
741
static void ftl_vfl_log_trouble(uint32_t bank, uint32_t vblock)
742
{
742
{
743
    uint32_t i;
743
    uint32_t i;
744
    for (i = 0; i < 5; i++)
744
    for (i = 0; i < 5; i++)
745
        if (ftl_troublelog[i].block == vblock
745
        if (ftl_troublelog[i].block == vblock
746
         && ftl_troublelog[i].bank == bank)
746
         && ftl_troublelog[i].bank == bank)
Line 765... Line 765...
765
#endif
765
#endif
766
 
766
 
767
 
767
 
768
#ifndef FTL_READONLY
768
#ifndef FTL_READONLY
769
/* Logs a successful erase for the specified vBlock on the specified bank */
769
/* Logs a successful erase for the specified vBlock on the specified bank */
770
void ftl_vfl_log_success(uint32_t bank, uint32_t vblock)
770
static void ftl_vfl_log_success(uint32_t bank, uint32_t vblock)
771
{
771
{
772
    uint32_t i;
772
    uint32_t i;
773
    for (i = 0; i < 5; i++)
773
    for (i = 0; i < 5; i++)
774
        if (ftl_troublelog[i].block == vblock
774
        if (ftl_troublelog[i].block == vblock
775
         && ftl_troublelog[i].bank == bank)
775
         && ftl_troublelog[i].bank == bank)
Line 785... Line 785...
785
#ifndef FTL_READONLY
785
#ifndef FTL_READONLY
786
/* Tries to remap the specified vBlock on the specified bank,
786
/* Tries to remap the specified vBlock on the specified bank,
787
   not caring about data in there.
787
   not caring about data in there.
788
   If it worked, it will return the new pBlock number,
788
   If it worked, it will return the new pBlock number,
789
   if not (no more spare blocks available), it will return zero. */
789
   if not (no more spare blocks available), it will return zero. */
790
uint32_t ftl_vfl_remap_block(uint32_t bank, uint32_t block)
790
static uint32_t ftl_vfl_remap_block(uint32_t bank, uint32_t block)
791
{
791
{
792
    uint32_t i;
792
    uint32_t i;
793
    uint32_t newblock = 0, newidx;
793
    uint32_t newblock = 0, newidx;
794
    panicf(PANIC_FATAL, "FTL: Remapping bank %u block %u!",
794
    panicf(PANIC_FATAL, "FTL: Remapping bank %u block %u!",
795
	       (unsigned)bank, (unsigned)block);
795
	       (unsigned)bank, (unsigned)block);
Line 816... Line 816...
816
}
816
}
817
#endif
817
#endif
818
 
818
 
819
 
819
 
820
/* Reads the specified vPage, dealing with all kinds of trouble */
820
/* Reads the specified vPage, dealing with all kinds of trouble */
821
uint32_t ftl_vfl_read(uint32_t vpage, void* buffer, void* sparebuffer,
821
static uint32_t ftl_vfl_read(uint32_t vpage, void* buffer, void* sparebuffer,
822
                      uint32_t checkempty, uint32_t remaponfail)
822
                             uint32_t checkempty, uint32_t remaponfail)
823
{
823
{
824
#ifdef VFL_TRACE
824
#ifdef VFL_TRACE
825
    DEBUGF("FTL: VFL: Reading page %d", vpage);
825
    DEBUGF("FTL: VFL: Reading page %d", vpage);
826
#endif
826
#endif
827
 
827
 
Line 864... Line 864...
864
    return ret;
864
    return ret;
865
}
865
}
866
 
866
 
867
 
867
 
868
/* Multi-bank version of ftl_vfl_read, will read ftl_banks pages in parallel */
868
/* Multi-bank version of ftl_vfl_read, will read ftl_banks pages in parallel */
869
uint32_t ftl_vfl_read_fast(uint32_t vpage, void* buffer, void* sparebuffer,
869
static uint32_t ftl_vfl_read_fast(uint32_t vpage, void* buffer, void* sparebuffer,
870
                           uint32_t checkempty, uint32_t remaponfail)
870
                                  uint32_t checkempty, uint32_t remaponfail)
871
{
871
{
872
#ifdef VFL_TRACE
872
#ifdef VFL_TRACE
873
    DEBUGF("FTL: VFL: Fast reading page %d on all banks", vpage);
873
    DEBUGF("FTL: VFL: Fast reading page %d on all banks", vpage);
874
#endif
874
#endif
875
 
875
 
Line 940... Line 940...
940
}
940
}
941
 
941
 
942
 
942
 
943
#ifndef FTL_READONLY
943
#ifndef FTL_READONLY
944
/* Writes the specified vPage, dealing with all kinds of trouble */
944
/* Writes the specified vPage, dealing with all kinds of trouble */
945
uint32_t ftl_vfl_write(uint32_t vpage, uint32_t count,
945
static uint32_t ftl_vfl_write(uint32_t vpage, uint32_t count,
946
                       void* buffer, void* sparebuffer)
946
                              void* buffer, void* sparebuffer)
947
{
947
{
948
    uint32_t i, j;
948
    uint32_t i, j;
949
#ifdef VFL_TRACE
949
#ifdef VFL_TRACE
950
    DEBUGF("FTL: VFL: Writing page %d", vpage);
950
    DEBUGF("FTL: VFL: Writing page %d", vpage);
951
#endif
951
#endif
Line 1017... Line 1017...
1017
}
1017
}
1018
#endif
1018
#endif
1019
 
1019
 
1020
 
1020
 
1021
/* Mounts the VFL on all banks */
1021
/* Mounts the VFL on all banks */
1022
uint32_t ftl_vfl_open(void)
1022
static uint32_t ftl_vfl_open(void)
1023
{
1023
{
1024
    uint32_t i, j, k;
1024
    uint32_t i, j, k;
1025
    uint32_t minusn, vflcxtidx, last;
1025
    uint32_t minusn, vflcxtidx, last;
1026
    struct ftl_vfl_cxt_type* cxt;
1026
    struct ftl_vfl_cxt_type* cxt;
1027
    uint16_t vflcxtblock[4];
1027
    uint16_t vflcxtblock[4];
Line 1110... Line 1110...
1110
    return 0;
1110
    return 0;
1111
}
1111
}
1112
 
1112
 
1113
 
1113
 
1114
/* Mounts the actual FTL */
1114
/* Mounts the actual FTL */
1115
uint32_t ftl_open(void)
1115
static uint32_t ftl_open(void)
1116
{
1116
{
1117
    uint32_t i;
1117
    uint32_t i;
1118
    uint32_t ret;
1118
    uint32_t ret;
1119
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1119
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1120
    struct ftl_vfl_cxt_type* cxt = ftl_vfl_get_newest_cxt();
1120
    struct ftl_vfl_cxt_type* cxt = ftl_vfl_get_newest_cxt();
Line 1262... Line 1262...
1262
 
1262
 
1263
 
1263
 
1264
#ifndef FTL_READONLY
1264
#ifndef FTL_READONLY
1265
/* Returns a pointer to the ftl_log entry for the specified vBlock,
1265
/* Returns a pointer to the ftl_log entry for the specified vBlock,
1266
   or null, if there is none */
1266
   or null, if there is none */
1267
struct ftl_log_type* ftl_get_log_entry(uint32_t block)
1267
static struct ftl_log_type* ftl_get_log_entry(uint32_t block)
1268
{
1268
{
1269
    uint32_t i;
1269
    uint32_t i;
1270
    for (i = 0; i < 0x11; i++)
1270
    for (i = 0; i < 0x11; i++)
1271
    {
1271
    {
1272
        if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
1272
        if (ftl_log[i].scatteredvblock == 0xFFFF) continue;
Line 1363... Line 1363...
1363
 
1363
 
1364
 
1364
 
1365
#ifndef FTL_READONLY
1365
#ifndef FTL_READONLY
1366
/* Performs a vBlock erase, dealing with hardware,
1366
/* Performs a vBlock erase, dealing with hardware,
1367
   remapping and all kinds of trouble */
1367
   remapping and all kinds of trouble */
1368
uint32_t ftl_erase_block_internal(uint32_t block)
1368
static uint32_t ftl_erase_block_internal(uint32_t block)
1369
{
1369
{
1370
    uint32_t i, j;
1370
    uint32_t i, j;
1371
    block = block + ftl_nand_type->blocks
1371
    block = block + ftl_nand_type->blocks
1372
          - ftl_nand_type->userblocks - 0x17;
1372
          - ftl_nand_type->userblocks - 0x17;
1373
    if (block == 0 || block >= ftl_nand_type->blocks) return 1;
1373
    if (block == 0 || block >= ftl_nand_type->blocks) return 1;
Line 1407... Line 1407...
1407
#endif
1407
#endif
1408
 
1408
 
1409
 
1409
 
1410
#ifndef FTL_READONLY
1410
#ifndef FTL_READONLY
1411
/* Highlevel vBlock erase, that increments the erase counter for the block */
1411
/* Highlevel vBlock erase, that increments the erase counter for the block */
1412
uint32_t ftl_erase_block(uint32_t block)
1412
static uint32_t ftl_erase_block(uint32_t block)
1413
{
1413
{
1414
    ftl_erasectr[block]++;
1414
    ftl_erasectr[block]++;
1415
    if (ftl_erasectr_dirt[block >> 10] == 100) ftl_cxt.erasedirty = 1;
1415
    if (ftl_erasectr_dirt[block >> 10] == 100) ftl_cxt.erasedirty = 1;
1416
    else ftl_erasectr_dirt[block >> 10]++;
1416
    else ftl_erasectr_dirt[block >> 10]++;
1417
    return ftl_erase_block_internal(block);
1417
    return ftl_erase_block_internal(block);
Line 1420... Line 1420...
1420
 
1420
 
1421
 
1421
 
1422
#ifndef FTL_READONLY
1422
#ifndef FTL_READONLY
1423
/* Allocates a block from the pool,
1423
/* Allocates a block from the pool,
1424
   returning its vBlock number, or 0xFFFFFFFF on error */
1424
   returning its vBlock number, or 0xFFFFFFFF on error */
1425
uint32_t ftl_allocate_pool_block(void)
1425
static uint32_t ftl_allocate_pool_block(void)
1426
{
1426
{
1427
    uint32_t i;
1427
    uint32_t i;
1428
    uint32_t erasectr = 0xFFFFFFFF, bestidx = 0xFFFFFFFF, block;
1428
    uint32_t erasectr = 0xFFFFFFFF, bestidx = 0xFFFFFFFF, block;
1429
    for (i = 0; i < ftl_cxt.freecount; i++)
1429
    for (i = 0; i < ftl_cxt.freecount; i++)
1430
    {
1430
    {
Line 1454... Line 1454...
1454
#endif
1454
#endif
1455
 
1455
 
1456
 
1456
 
1457
#ifndef FTL_READONLY
1457
#ifndef FTL_READONLY
1458
/* Releases a vBlock back into the pool */
1458
/* Releases a vBlock back into the pool */
1459
void ftl_release_pool_block(uint32_t block)
1459
static void ftl_release_pool_block(uint32_t block)
1460
{
1460
{
1461
    if (block >= (uint32_t)ftl_nand_type->userblocks + 0x17)
1461
    if (block >= (uint32_t)ftl_nand_type->userblocks + 0x17)
1462
        panicf(PANIC_FATAL, "FTL: Tried to release block %u", (unsigned)block);
1462
        panicf(PANIC_FATAL, "FTL: Tried to release block %u", (unsigned)block);
1463
    uint32_t idx = ftl_cxt.nextfreeidx + ftl_cxt.freecount++;
1463
    uint32_t idx = ftl_cxt.nextfreeidx + ftl_cxt.freecount++;
1464
    if (idx >= 0x14) idx -= 0x14;
1464
    if (idx >= 0x14) idx -= 0x14;
Line 1468... Line 1468...
1468
 
1468
 
1469
 
1469
 
1470
#ifndef FTL_READONLY
1470
#ifndef FTL_READONLY
1471
/* Commits the location of the FTL context blocks
1471
/* Commits the location of the FTL context blocks
1472
   to a semi-randomly chosen VFL context */
1472
   to a semi-randomly chosen VFL context */
1473
uint32_t ftl_store_ctrl_block_list(void)
1473
static uint32_t ftl_store_ctrl_block_list(void)
1474
{
1474
{
1475
    uint32_t i;
1475
    uint32_t i;
1476
    for (i = 0; i < ftl_banks; i++)
1476
    for (i = 0; i < ftl_banks; i++)
1477
        memcpy(ftl_vfl_cxt[i].ftlctrlblocks, ftl_cxt.ftlctrlblocks, 6);
1477
        memcpy(ftl_vfl_cxt[i].ftlctrlblocks, ftl_cxt.ftlctrlblocks, 6);
1478
    return ftl_vfl_commit_cxt(ftl_vfl_usn % ftl_banks);
1478
    return ftl_vfl_commit_cxt(ftl_vfl_usn % ftl_banks);
Line 1481... Line 1481...
1481
 
1481
 
1482
 
1482
 
1483
#ifndef FTL_READONLY
1483
#ifndef FTL_READONLY
1484
/* Saves the n-th erase counter page to the flash,
1484
/* Saves the n-th erase counter page to the flash,
1485
   because it is too dirty or needs to be moved. */
1485
   because it is too dirty or needs to be moved. */
1486
uint32_t ftl_save_erasectr_page(uint32_t index)
1486
static uint32_t ftl_save_erasectr_page(uint32_t index)
1487
{
1487
{
1488
    memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1488
    memset(&ftl_sparebuffer[0], 0xFF, 0x40);
1489
    ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1489
    ftl_sparebuffer[0].meta.usn = ftl_cxt.usn;
1490
    ftl_sparebuffer[0].meta.idx = index;
1490
    ftl_sparebuffer[0].meta.idx = index;
1491
    ftl_sparebuffer[0].meta.type = 0x46;
1491
    ftl_sparebuffer[0].meta.type = 0x46;
Line 1507... Line 1507...
1507
 
1507
 
1508
 
1508
 
1509
#ifndef FTL_READONLY
1509
#ifndef FTL_READONLY
1510
/* Increments ftl_cxt.ftlctrlpage to the next available FTL context page,
1510
/* Increments ftl_cxt.ftlctrlpage to the next available FTL context page,
1511
   allocating a new context block if neccessary. */
1511
   allocating a new context block if neccessary. */
1512
uint32_t ftl_next_ctrl_pool_page(void)
1512
static uint32_t ftl_next_ctrl_pool_page(void)
1513
{
1513
{
1514
    uint32_t i;
1514
    uint32_t i;
1515
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1515
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1516
    if (++ftl_cxt.ftlctrlpage % ppb != 0) return 0;
1516
    if (++ftl_cxt.ftlctrlpage % ppb != 0) return 0;
1517
    for (i = 0; i < 3; i++)
1517
    for (i = 0; i < 3; i++)
Line 1546... Line 1546...
1546
#endif
1546
#endif
1547
 
1547
 
1548
 
1548
 
1549
#ifndef FTL_READONLY
1549
#ifndef FTL_READONLY
1550
/* Copies a vPage from one location to another */
1550
/* Copies a vPage from one location to another */
1551
uint32_t ftl_copy_page(uint32_t source, uint32_t destination,
1551
static uint32_t ftl_copy_page(uint32_t source, uint32_t destination,
1552
                       uint32_t lpn, uint32_t type)
1552
                              uint32_t lpn, uint32_t type)
1553
{
1553
{
1554
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1554
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1555
    uint32_t rc = ftl_vfl_read(source, ftl_copybuffer[0],
1555
    uint32_t rc = ftl_vfl_read(source, ftl_copybuffer[0],
1556
                               &ftl_copyspare[0], 1, 1) & 0x11F;
1556
                               &ftl_copyspare[0], 1, 1) & 0x11F;
1557
    memset(&ftl_copyspare[0], 0xFF, 0x40);
1557
    memset(&ftl_copyspare[0], 0xFF, 0x40);
Line 1567... Line 1567...
1567
#endif
1567
#endif
1568
 
1568
 
1569
 
1569
 
1570
#ifndef FTL_READONLY
1570
#ifndef FTL_READONLY
1571
/* Copies a pBlock to a vBlock */
1571
/* Copies a pBlock to a vBlock */
1572
uint32_t ftl_copy_block(uint32_t source, uint32_t destination)
1572
static uint32_t ftl_copy_block(uint32_t source, uint32_t destination)
1573
{
1573
{
1574
    uint32_t i, j;
1574
    uint32_t i, j;
1575
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1575
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1576
    uint32_t error = 0;
1576
    uint32_t error = 0;
1577
    ftl_cxt.nextblockusn++;
1577
    ftl_cxt.nextblockusn++;
Line 1609... Line 1609...
1609
#endif
1609
#endif
1610
 
1610
 
1611
 
1611
 
1612
#ifndef FTL_READONLY
1612
#ifndef FTL_READONLY
1613
/* Clears ftl_log.issequential, if something violating that is written. */
1613
/* Clears ftl_log.issequential, if something violating that is written. */
1614
void ftl_check_still_sequential(struct ftl_log_type* entry, uint32_t page)
1614
static void ftl_check_still_sequential(struct ftl_log_type* entry, uint32_t page)
1615
{
1615
{
1616
    if (entry->pagesused != entry->pagescurrent
1616
    if (entry->pagesused != entry->pagescurrent
1617
     || entry->pageoffsets[page] != page)
1617
     || entry->pageoffsets[page] != page)
1618
        entry->issequential = 0;
1618
        entry->issequential = 0;
1619
}
1619
}
Line 1626... Line 1626...
1626
   the old one.
1626
   the old one.
1627
   In other words: It kicks the pages containing old garbage out of it to make
1627
   In other words: It kicks the pages containing old garbage out of it to make
1628
   space again. This is usually done when a scattered page block is being
1628
   space again. This is usually done when a scattered page block is being
1629
   removed because it is full, but less than half of the pages in there are
1629
   removed because it is full, but less than half of the pages in there are
1630
   still in use and rest is just filled with old crap. */
1630
   still in use and rest is just filled with old crap. */
1631
uint32_t ftl_compact_scattered(struct ftl_log_type* entry)
1631
static uint32_t ftl_compact_scattered(struct ftl_log_type* entry)
1632
{
1632
{
1633
    uint32_t i, j;
1633
    uint32_t i, j;
1634
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1634
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1635
    uint32_t error;
1635
    uint32_t error;
1636
    struct ftl_log_type backup;
1636
    struct ftl_log_type backup;
Line 1682... Line 1682...
1682
#endif
1682
#endif
1683
 
1683
 
1684
 
1684
 
1685
#ifndef FTL_READONLY
1685
#ifndef FTL_READONLY
1686
/* Commits an ftl_log entry to proper blocks, no matter what's in there. */
1686
/* Commits an ftl_log entry to proper blocks, no matter what's in there. */
1687
uint32_t ftl_commit_scattered(struct ftl_log_type* entry)
1687
static uint32_t ftl_commit_scattered(struct ftl_log_type* entry)
1688
{
1688
{
1689
    uint32_t i;
1689
    uint32_t i;
1690
    uint32_t error;
1690
    uint32_t error;
1691
    uint32_t block;
1691
    uint32_t block;
1692
    for (i = 0; i < 4; i++)
1692
    for (i = 0; i < 4; i++)
Line 1710... Line 1710...
1710
#ifndef FTL_READONLY
1710
#ifndef FTL_READONLY
1711
/* Fills the rest of a scattered page block that was actually written
1711
/* Fills the rest of a scattered page block that was actually written
1712
   sequentially until now, in order to be able to save a block erase by
1712
   sequentially until now, in order to be able to save a block erase by
1713
   committing it without needing to copy it again.
1713
   committing it without needing to copy it again.
1714
   If this fails for whichever reason, it will be committed the usual way. */
1714
   If this fails for whichever reason, it will be committed the usual way. */
1715
uint32_t ftl_commit_sequential(struct ftl_log_type* entry)
1715
static uint32_t ftl_commit_sequential(struct ftl_log_type* entry)
1716
{
1716
{
1717
    uint32_t i;
1717
    uint32_t i;
1718
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1718
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1719
 
1719
 
1720
    if (entry->issequential != 1
1720
    if (entry->issequential != 1
Line 1756... Line 1756...
1756
 
1756
 
1757
#ifndef FTL_READONLY
1757
#ifndef FTL_READONLY
1758
/* If a log entry is supplied, its scattered page block will be removed in
1758
/* If a log entry is supplied, its scattered page block will be removed in
1759
   whatever way seems most appropriate. Else, the oldest scattered page block
1759
   whatever way seems most appropriate. Else, the oldest scattered page block
1760
   will be freed by committing it. */
1760
   will be freed by committing it. */
1761
uint32_t ftl_remove_scattered_block(struct ftl_log_type* entry)
1761
static uint32_t ftl_remove_scattered_block(struct ftl_log_type* entry)
1762
{
1762
{
1763
    uint32_t i;
1763
    uint32_t i;
1764
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1764
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1765
    uint32_t age = 0xFFFFFFFF, used = 0;
1765
    uint32_t age = 0xFFFFFFFF, used = 0;
1766
    if (entry == (struct ftl_log_type*)0)
1766
    if (entry == (struct ftl_log_type*)0)
Line 1792... Line 1792...
1792
#endif
1792
#endif
1793
 
1793
 
1794
 
1794
 
1795
#ifndef FTL_READONLY
1795
#ifndef FTL_READONLY
1796
/* Initialize a log entry to the values for an empty scattered page block */
1796
/* Initialize a log entry to the values for an empty scattered page block */
1797
void ftl_init_log_entry(struct ftl_log_type* entry)
1797
static void ftl_init_log_entry(struct ftl_log_type* entry)
1798
{
1798
{
1799
    entry->issequential = 1;
1799
    entry->issequential = 1;
1800
    entry->pagescurrent = 0;
1800
    entry->pagescurrent = 0;
1801
    entry->pagesused = 0;
1801
    entry->pagesused = 0;
1802
    memset(entry->pageoffsets, 0xFF, 0x400);
1802
    memset(entry->pageoffsets, 0xFF, 0x400);
Line 1805... Line 1805...
1805
 
1805
 
1806
 
1806
 
1807
#ifndef FTL_READONLY
1807
#ifndef FTL_READONLY
1808
/* Allocates a log entry for the specified vBlock,
1808
/* Allocates a log entry for the specified vBlock,
1809
   first making space, if neccessary. */
1809
   first making space, if neccessary. */
1810
struct ftl_log_type* ftl_allocate_log_entry(uint32_t block)
1810
static struct ftl_log_type* ftl_allocate_log_entry(uint32_t block)
1811
{
1811
{
1812
    uint32_t i;
1812
    uint32_t i;
1813
    struct ftl_log_type* entry = ftl_get_log_entry(block);
1813
    struct ftl_log_type* entry = ftl_get_log_entry(block);
1814
    entry->usn = ftl_cxt.nextblockusn - 1;
1814
    entry->usn = ftl_cxt.nextblockusn - 1;
1815
    if (entry != (struct ftl_log_type*)0) return entry;
1815
    if (entry != (struct ftl_log_type*)0) return entry;
Line 1846... Line 1846...
1846
#endif
1846
#endif
1847
 
1847
 
1848
 
1848
 
1849
#ifndef FTL_READONLY
1849
#ifndef FTL_READONLY
1850
/* Commits the FTL block map, erase counters, and context to flash */
1850
/* Commits the FTL block map, erase counters, and context to flash */
1851
uint32_t ftl_commit_cxt(void)
1851
static uint32_t ftl_commit_cxt(void)
1852
{
1852
{
1853
    uint32_t i;
1853
    uint32_t i;
1854
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1854
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
1855
    uint32_t mappages = (ftl_nand_type->userblocks + 0x3ff) >> 10;
1855
    uint32_t mappages = (ftl_nand_type->userblocks + 0x3ff) >> 10;
1856
    uint32_t ctrpages = (ftl_nand_type->userblocks + 23 + 0x3ff) >> 10;
1856
    uint32_t ctrpages = (ftl_nand_type->userblocks + 23 + 0x3ff) >> 10;
Line 1890... Line 1890...
1890
 
1890
 
1891
#ifndef FTL_READONLY
1891
#ifndef FTL_READONLY
1892
/* Swaps the most and least worn block on the flash,
1892
/* Swaps the most and least worn block on the flash,
1893
   to better distribute wear. It will refuse to do anything
1893
   to better distribute wear. It will refuse to do anything
1894
   if the wear spread is lower than 5 erases. */
1894
   if the wear spread is lower than 5 erases. */
1895
uint32_t ftl_swap_blocks(void)
1895
static uint32_t ftl_swap_blocks(void)
1896
{
1896
{
1897
    uint32_t i;
1897
    uint32_t i;
1898
    uint32_t min = 0xFFFFFFFF, max = 0, maxidx = 0x14;
1898
    uint32_t min = 0xFFFFFFFF, max = 0, maxidx = 0x14;
1899
    uint32_t minidx = 0, minvb = 0, maxvb = 0;
1899
    uint32_t minidx = 0, minvb = 0, maxvb = 0;
1900
    for (i = 0; i < ftl_cxt.freecount; i++)
1900
    for (i = 0; i < ftl_cxt.freecount; i++)
Line 2116... Line 2116...
2116
    uint32_t i;
2116
    uint32_t i;
2117
    uint32_t rc = 0;
2117
    uint32_t rc = 0;
2118
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2118
    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks;
2119
    if (ftl_cxt.clean_flag == 1) return 0;
2119
    if (ftl_cxt.clean_flag == 1) return 0;
2120
 
2120
 
-
 
2121
    mutex_lock(&ftl_mtx, TIMEOUT_BLOCK);
-
 
2122
	
2121
#ifdef FTL_TRACE
2123
#ifdef FTL_TRACE
2122
    DEBUGF("FTL: Syncing");
2124
    DEBUGF("FTL: Syncing");
2123
#endif
2125
#endif
2124
 
2126
 
2125
    if (ftl_cxt.swapcounter >= 20)
2127
    if (ftl_cxt.swapcounter >= 20)