diff options
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c | 470 | ||||
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c | 204 | ||||
-rw-r--r-- | firmware/target/arm/s5l8700/ipodnano2g/nand-target.h | 7 |
3 files changed, 555 insertions, 126 deletions
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c index 0cc7841cd5..b4cdaebf99 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c +++ b/firmware/target/arm/s5l8700/ipodnano2g/ftl-nano2g.c | |||
@@ -372,7 +372,7 @@ struct ftl_cxt_type ftl_cxt; | |||
372 | uint8_t ftl_buffer[0x800] __attribute__((aligned(16))); | 372 | uint8_t ftl_buffer[0x800] __attribute__((aligned(16))); |
373 | 373 | ||
374 | /* Temporary spare byte buffer for internal use by the FTL */ | 374 | /* Temporary spare byte buffer for internal use by the FTL */ |
375 | union ftl_spare_data_type ftl_sparebuffer __attribute__((aligned(16))); | 375 | union ftl_spare_data_type ftl_sparebuffer[4] __attribute__((aligned(16))); |
376 | 376 | ||
377 | 377 | ||
378 | #ifndef FTL_READONLY | 378 | #ifndef FTL_READONLY |
@@ -402,7 +402,8 @@ uint8_t ftl_erasectr_dirt[8]; | |||
402 | /* Buffer needed for copying pages around while moving or committing blocks. | 402 | /* Buffer needed for copying pages around while moving or committing blocks. |
403 | This can't be shared with ftl_buffer, because this one could be overwritten | 403 | This can't be shared with ftl_buffer, because this one could be overwritten |
404 | during the copying operation in order to e.g. commit a CXT. */ | 404 | during the copying operation in order to e.g. commit a CXT. */ |
405 | uint8_t ftl_copybuffer[0x800] __attribute__((aligned(16))); | 405 | uint8_t ftl_copybuffer[4][0x800] __attribute__((aligned(16))); |
406 | union ftl_spare_data_type ftl_copyspare[4] __attribute__((aligned(16))); | ||
406 | 407 | ||
407 | /* Needed to store the old scattered page offsets in order to be able to roll | 408 | /* Needed to store the old scattered page offsets in order to be able to roll |
408 | back if something fails while compacting a scattered page block. */ | 409 | back if something fails while compacting a scattered page block. */ |
@@ -430,7 +431,7 @@ uint32_t ftl_find_devinfo(uint32_t bank) | |||
430 | { | 431 | { |
431 | pagenum = block * (*ftl_nand_type).pagesperblock + page; | 432 | pagenum = block * (*ftl_nand_type).pagesperblock + page; |
432 | if ((nand_read_page(bank, pagenum, ftl_buffer, | 433 | if ((nand_read_page(bank, pagenum, ftl_buffer, |
433 | &ftl_sparebuffer, 1, 0) & 0x11F) != 0) | 434 | &ftl_sparebuffer[0], 1, 0) & 0x11F) != 0) |
434 | continue; | 435 | continue; |
435 | if (memcmp(ftl_buffer, "DEVICEINFOSIGN\0", 0x10) == 0) | 436 | if (memcmp(ftl_buffer, "DEVICEINFOSIGN\0", 0x10) == 0) |
436 | return pagenum; | 437 | return pagenum; |
@@ -534,34 +535,34 @@ uint32_t ftl_vfl_store_cxt(uint32_t bank) | |||
534 | ftl_vfl_cxt[bank].usn = ++ftl_vfl_usn; | 535 | ftl_vfl_cxt[bank].usn = ++ftl_vfl_usn; |
535 | ftl_vfl_cxt[bank].nextcxtpage += 8; | 536 | ftl_vfl_cxt[bank].nextcxtpage += 8; |
536 | ftl_vfl_update_checksum(bank); | 537 | ftl_vfl_update_checksum(bank); |
537 | memset(&ftl_sparebuffer, 0xFF, 0x40); | 538 | memset(&ftl_sparebuffer[0], 0xFF, 0x40); |
538 | ftl_sparebuffer.meta.usn = ftl_vfl_cxt[bank].updatecount; | 539 | ftl_sparebuffer[0].meta.usn = ftl_vfl_cxt[bank].updatecount; |
539 | ftl_sparebuffer.meta.field_8 = 0; | 540 | ftl_sparebuffer[0].meta.field_8 = 0; |
540 | ftl_sparebuffer.meta.type = 0x80; | 541 | ftl_sparebuffer[0].meta.type = 0x80; |
541 | for (i = 1; i <= 8; i++) | 542 | for (i = 1; i <= 8; i++) |
542 | { | 543 | { |
543 | uint32_t index = ftl_vfl_cxt[bank].activecxtblock; | 544 | uint32_t index = ftl_vfl_cxt[bank].activecxtblock; |
544 | uint32_t block = ftl_vfl_cxt[bank].vflcxtblocks[index]; | 545 | uint32_t block = ftl_vfl_cxt[bank].vflcxtblocks[index]; |
545 | uint32_t page = block * (*ftl_nand_type).pagesperblock; | 546 | uint32_t page = block * (*ftl_nand_type).pagesperblock; |
546 | page += ftl_vfl_cxt[bank].nextcxtpage - i; | 547 | page += ftl_vfl_cxt[bank].nextcxtpage - i; |
547 | nand_write_page(bank, page, &ftl_vfl_cxt[bank], &ftl_sparebuffer, 1); | 548 | nand_write_page(bank, page, &ftl_vfl_cxt[bank], &ftl_sparebuffer[0], 1); |
548 | } | 549 | } |
549 | uint32_t good = 0; | 550 | uint32_t good = 0; |
550 | for (i = 0; i < 8; i++) | 551 | for (i = 1; i <= 8; i++) |
551 | { | 552 | { |
552 | uint32_t index = ftl_vfl_cxt[bank].activecxtblock; | 553 | uint32_t index = ftl_vfl_cxt[bank].activecxtblock; |
553 | uint32_t block = ftl_vfl_cxt[bank].vflcxtblocks[index]; | 554 | uint32_t block = ftl_vfl_cxt[bank].vflcxtblocks[index]; |
554 | uint32_t page = block * (*ftl_nand_type).pagesperblock; | 555 | uint32_t page = block * (*ftl_nand_type).pagesperblock; |
555 | page += ftl_vfl_cxt[bank].nextcxtpage - i; | 556 | page += ftl_vfl_cxt[bank].nextcxtpage - i; |
556 | if ((nand_read_page(bank, page, ftl_buffer, | 557 | if ((nand_read_page(bank, page, ftl_buffer, |
557 | &ftl_sparebuffer, 1, 0) & 0x11F) != 0) | 558 | &ftl_sparebuffer[0], 1, 0) & 0x11F) != 0) |
558 | continue; | 559 | continue; |
559 | if (memcmp(ftl_buffer, &ftl_vfl_cxt[bank], 0x7AC) != 0) | 560 | if (memcmp(ftl_buffer, &ftl_vfl_cxt[bank], 0x7AC) != 0) |
560 | continue; | 561 | continue; |
561 | if (ftl_sparebuffer.meta.usn != ftl_vfl_cxt[bank].updatecount) | 562 | if (ftl_sparebuffer[0].meta.usn != ftl_vfl_cxt[bank].updatecount) |
562 | continue; | 563 | continue; |
563 | if (ftl_sparebuffer.meta.field_8 == 0 | 564 | if (ftl_sparebuffer[0].meta.field_8 == 0 |
564 | && ftl_sparebuffer.meta.type == 0x80) good++; | 565 | && ftl_sparebuffer[0].meta.type == 0x80) good++; |
565 | } | 566 | } |
566 | return good > 3 ? 0 : 1; | 567 | return good > 3 ? 0 : 1; |
567 | } | 568 | } |
@@ -847,6 +848,72 @@ uint32_t ftl_vfl_read(uint32_t vpage, void* buffer, void* sparebuffer, | |||
847 | } | 848 | } |
848 | 849 | ||
849 | 850 | ||
851 | /* Multi-bank version of ftl_vfl_read, will read ftl_banks pages in parallel */ | ||
852 | uint32_t ftl_vfl_read_fast(uint32_t vpage, void* buffer, void* sparebuffer, | ||
853 | uint32_t checkempty, uint32_t remaponfail) | ||
854 | { | ||
855 | uint32_t i, rc = 0; | ||
856 | uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; | ||
857 | uint32_t syshyperblocks = (*ftl_nand_type).blocks | ||
858 | - (*ftl_nand_type).userblocks - 0x17; | ||
859 | uint32_t abspage = vpage + ppb * syshyperblocks; | ||
860 | if (abspage + ftl_banks - 1 >= (*ftl_nand_type).blocks * ppb || abspage < ppb) | ||
861 | panicf("FTL: Trying to read out-of-bounds vPage %u", (unsigned)vpage); | ||
862 | //return 4; | ||
863 | |||
864 | uint32_t bank = abspage % ftl_banks; | ||
865 | uint32_t block = abspage / ((*ftl_nand_type).pagesperblock * ftl_banks); | ||
866 | uint32_t page = (abspage / ftl_banks) % (*ftl_nand_type).pagesperblock; | ||
867 | if (bank) | ||
868 | { | ||
869 | for (i = 0; i < ftl_banks; i++) | ||
870 | { | ||
871 | void* databuf = (void*)0; | ||
872 | void* sparebuf = (void*)0; | ||
873 | if (buffer) databuf = (void*)((uint32_t)buffer + 0x800 * i); | ||
874 | if (sparebuffer) sparebuf = (void*)((uint32_t)sparebuffer + 0x40 * i); | ||
875 | uint32_t ret = ftl_vfl_read(vpage + i, databuf, sparebuf, checkempty, remaponfail); | ||
876 | if (ret & 1) rc |= 1 << (i << 2); | ||
877 | if (ret & 2) rc |= 2 << (i << 2); | ||
878 | if (ret & 0x10) rc |= 4 << (i << 2); | ||
879 | if (ret & 0x100) rc |= 8 << (i << 2); | ||
880 | } | ||
881 | return rc; | ||
882 | } | ||
883 | uint32_t physblock = ftl_vfl_get_physical_block(bank, block); | ||
884 | uint32_t physpage = physblock * (*ftl_nand_type).pagesperblock + page; | ||
885 | |||
886 | rc = nand_read_page_fast(physpage, buffer, sparebuffer, 1, checkempty); | ||
887 | if (!(rc & 0xdddd)) return rc; | ||
888 | |||
889 | for (i = 0; i < ftl_banks; i++) | ||
890 | { | ||
891 | if ((rc >> (i << 2)) & 0x2) continue; | ||
892 | if ((rc >> (i << 2)) & 0xf) | ||
893 | { | ||
894 | rc &= ~(0xf << (i << 2)); | ||
895 | nand_reset(i); | ||
896 | uint32_t ret = nand_read_page(i, physpage, | ||
897 | (void*)((uint32_t)buffer + 0x800 * i), | ||
898 | (void*)((uint32_t)sparebuffer + 0x40 * i), | ||
899 | 1, checkempty); | ||
900 | #ifdef FTL_READONLY | ||
901 | (void)remaponfail; | ||
902 | #else | ||
903 | if (remaponfail == 1 && (ret & 0x11D) != 0 && (ret & 2) == 0) | ||
904 | ftl_vfl_schedule_block_for_remap(i, block); | ||
905 | #endif | ||
906 | if (ret & 1) rc |= 1 << (i << 2); | ||
907 | if (ret & 2) rc |= 2 << (i << 2); | ||
908 | if (ret & 0x10) rc |= 4 << (i << 2); | ||
909 | if (ret & 0x100) rc |= 8 << (i << 2); | ||
910 | } | ||
911 | } | ||
912 | |||
913 | return rc; | ||
914 | } | ||
915 | |||
916 | |||
850 | #ifndef FTL_READONLY | 917 | #ifndef FTL_READONLY |
851 | /* Writes the specified vPage, dealing with all kinds of trouble */ | 918 | /* Writes the specified vPage, dealing with all kinds of trouble */ |
852 | uint32_t ftl_vfl_write(uint32_t vpage, void* buffer, void* sparebuffer) | 919 | uint32_t ftl_vfl_write(uint32_t vpage, void* buffer, void* sparebuffer) |
@@ -870,7 +937,7 @@ uint32_t ftl_vfl_write(uint32_t vpage, void* buffer, void* sparebuffer) | |||
870 | return 0; | 937 | return 0; |
871 | 938 | ||
872 | if ((nand_read_page(bank, physpage, ftl_buffer, | 939 | if ((nand_read_page(bank, physpage, ftl_buffer, |
873 | &ftl_sparebuffer, 1, 1) & 0x11F) == 0) | 940 | &ftl_sparebuffer[0], 1, 1) & 0x11F) == 0) |
874 | return 0; | 941 | return 0; |
875 | 942 | ||
876 | panicf("FTL: write error on vPage %u, bank %u, pPage %u", | 943 | panicf("FTL: write error on vPage %u, bank %u, pPage %u", |
@@ -881,6 +948,57 @@ uint32_t ftl_vfl_write(uint32_t vpage, void* buffer, void* sparebuffer) | |||
881 | #endif | 948 | #endif |
882 | 949 | ||
883 | 950 | ||
951 | #ifndef FTL_READONLY | ||
952 | /* Multi-bank version of ftl_vfl_write, will write ftl_banks pages in parallel */ | ||
953 | uint32_t ftl_vfl_write_fast(uint32_t vpage, void* buffer, void* sparebuffer) | ||
954 | { | ||
955 | uint32_t i, rc = 0; | ||
956 | uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; | ||
957 | uint32_t syshyperblocks = (*ftl_nand_type).blocks | ||
958 | - (*ftl_nand_type).userblocks - 0x17; | ||
959 | uint32_t abspage = vpage + ppb * syshyperblocks; | ||
960 | if (abspage + ftl_banks - 1 >= (*ftl_nand_type).blocks * ppb || abspage < ppb) | ||
961 | panicf("FTL: Trying to write out-of-bounds vPage %u", | ||
962 | (unsigned)vpage); | ||
963 | //return 4; | ||
964 | |||
965 | uint32_t bank = abspage % ftl_banks; | ||
966 | uint32_t block = abspage / ((*ftl_nand_type).pagesperblock * ftl_banks); | ||
967 | uint32_t page = (abspage / ftl_banks) % (*ftl_nand_type).pagesperblock; | ||
968 | if (bank) | ||
969 | { | ||
970 | for (i = 0; i < ftl_banks; i++) | ||
971 | { | ||
972 | void* databuf = (void*)0; | ||
973 | void* sparebuf = (void*)0; | ||
974 | if (buffer) databuf = (void*)((uint32_t)buffer + 0x800 * i); | ||
975 | if (sparebuffer) sparebuf = (void*)((uint32_t)sparebuffer + 0x40 * i); | ||
976 | rc |= ftl_vfl_write(vpage + i, databuf, sparebuf) << i; | ||
977 | } | ||
978 | return rc; | ||
979 | } | ||
980 | uint32_t physblock = ftl_vfl_get_physical_block(bank, block); | ||
981 | uint32_t physpage = physblock * (*ftl_nand_type).pagesperblock + page; | ||
982 | |||
983 | rc = nand_write_page_fast(physpage, buffer, sparebuffer, 1); | ||
984 | if (!rc) return 0; | ||
985 | |||
986 | for (i = 0; i < ftl_banks; i++) | ||
987 | if (rc & (1 << i)) | ||
988 | { | ||
989 | if (!(nand_read_page(i, physpage, ftl_buffer, | ||
990 | &ftl_sparebuffer[i], 1, 1) & 0x11F)) | ||
991 | rc &= ~(1 << i); | ||
992 | |||
993 | panicf("FTL: write error on vPage %u, bank %u, pPage %u", | ||
994 | (unsigned)(vpage + i), (unsigned)i, (unsigned)physpage); | ||
995 | ftl_vfl_log_trouble(i, block); | ||
996 | } | ||
997 | return rc; | ||
998 | } | ||
999 | #endif | ||
1000 | |||
1001 | |||
884 | /* Mounts the VFL on all banks */ | 1002 | /* Mounts the VFL on all banks */ |
885 | uint32_t ftl_vfl_open(void) | 1003 | uint32_t ftl_vfl_open(void) |
886 | { | 1004 | { |
@@ -913,7 +1031,7 @@ uint32_t ftl_vfl_open(void) | |||
913 | if (ftl_is_good_block(bbt, j) != 0) | 1031 | if (ftl_is_good_block(bbt, j) != 0) |
914 | #endif | 1032 | #endif |
915 | if (ftl_vfl_read_page(i, j, 0, ftl_buffer, | 1033 | if (ftl_vfl_read_page(i, j, 0, ftl_buffer, |
916 | &ftl_sparebuffer) == 0) | 1034 | &ftl_sparebuffer[0]) == 0) |
917 | { | 1035 | { |
918 | struct ftl_vfl_cxt_type* cxt; | 1036 | struct ftl_vfl_cxt_type* cxt; |
919 | cxt = (struct ftl_vfl_cxt_type*)ftl_buffer; | 1037 | cxt = (struct ftl_vfl_cxt_type*)ftl_buffer; |
@@ -924,11 +1042,11 @@ uint32_t ftl_vfl_open(void) | |||
924 | if (vflcxtblock[k] != 0xFFFF) | 1042 | if (vflcxtblock[k] != 0xFFFF) |
925 | if (ftl_vfl_read_page(i, vflcxtblock[k], 0, | 1043 | if (ftl_vfl_read_page(i, vflcxtblock[k], 0, |
926 | ftl_buffer, | 1044 | ftl_buffer, |
927 | &ftl_sparebuffer) == 0) | 1045 | &ftl_sparebuffer[0]) == 0) |
928 | if (ftl_sparebuffer.meta.usn > 0 | 1046 | if (ftl_sparebuffer[0].meta.usn > 0 |
929 | && ftl_sparebuffer.meta.usn <= minusn) | 1047 | && ftl_sparebuffer[0].meta.usn <= minusn) |
930 | { | 1048 | { |
931 | minusn = ftl_sparebuffer.meta.usn; | 1049 | minusn = ftl_sparebuffer[0].meta.usn; |
932 | vflcxtidx = k; | 1050 | vflcxtidx = k; |
933 | } | 1051 | } |
934 | if (vflcxtidx == 4) //return 1; | 1052 | if (vflcxtidx == 4) //return 1; |
@@ -940,13 +1058,13 @@ uint32_t ftl_vfl_open(void) | |||
940 | { | 1058 | { |
941 | if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx], | 1059 | if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx], |
942 | k, ftl_buffer, | 1060 | k, ftl_buffer, |
943 | &ftl_sparebuffer) != 0) | 1061 | &ftl_sparebuffer[0]) != 0) |
944 | break; | 1062 | break; |
945 | last = k; | 1063 | last = k; |
946 | } | 1064 | } |
947 | if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx], | 1065 | if (ftl_vfl_read_page(i, vflcxtblock[vflcxtidx], |
948 | last, ftl_buffer, | 1066 | last, ftl_buffer, |
949 | &ftl_sparebuffer) != 0) | 1067 | &ftl_sparebuffer[0]) != 0) |
950 | panicf("FTL: Re-reading VFL CXT block " | 1068 | panicf("FTL: Re-reading VFL CXT block " |
951 | "on bank %u failed!?", (unsigned)i); | 1069 | "on bank %u failed!?", (unsigned)i); |
952 | //return 1; | 1070 | //return 1; |
@@ -981,12 +1099,12 @@ uint32_t ftl_open(void) | |||
981 | for (i = 0; i < 3; i++) | 1099 | for (i = 0; i < 3; i++) |
982 | { | 1100 | { |
983 | ret = ftl_vfl_read(ppb * (*cxt).ftlctrlblocks[i], | 1101 | ret = ftl_vfl_read(ppb * (*cxt).ftlctrlblocks[i], |
984 | ftl_buffer, &ftl_sparebuffer, 1, 0); | 1102 | ftl_buffer, &ftl_sparebuffer[0], 1, 0); |
985 | if ((ret &= 0x11F) != 0) continue; | 1103 | if ((ret &= 0x11F) != 0) continue; |
986 | if (ftl_sparebuffer.meta.type - 0x43 > 4) continue; | 1104 | if (ftl_sparebuffer[0].meta.type - 0x43 > 4) continue; |
987 | if (ftlcxtblock != 0xffffffff && ftl_sparebuffer.meta.usn >= minusn) | 1105 | if (ftlcxtblock != 0xffffffff && ftl_sparebuffer[0].meta.usn >= minusn) |
988 | continue; | 1106 | continue; |
989 | minusn = ftl_sparebuffer.meta.usn; | 1107 | minusn = ftl_sparebuffer[0].meta.usn; |
990 | ftlcxtblock = (*cxt).ftlctrlblocks[i]; | 1108 | ftlcxtblock = (*cxt).ftlctrlblocks[i]; |
991 | } | 1109 | } |
992 | 1110 | ||
@@ -997,9 +1115,9 @@ uint32_t ftl_open(void) | |||
997 | for (i = (*ftl_nand_type).pagesperblock * ftl_banks - 1; i > 0; i--) | 1115 | for (i = (*ftl_nand_type).pagesperblock * ftl_banks - 1; i > 0; i--) |
998 | { | 1116 | { |
999 | ret = ftl_vfl_read(ppb * ftlcxtblock + i, | 1117 | ret = ftl_vfl_read(ppb * ftlcxtblock + i, |
1000 | ftl_buffer, &ftl_sparebuffer, 1, 0); | 1118 | ftl_buffer, &ftl_sparebuffer[0], 1, 0); |
1001 | if ((ret & 0x11F) != 0) continue; | 1119 | if ((ret & 0x11F) != 0) continue; |
1002 | else if (ftl_sparebuffer.meta.type == 0x43) | 1120 | else if (ftl_sparebuffer[0].meta.type == 0x43) |
1003 | { | 1121 | { |
1004 | memcpy(&ftl_cxt, ftl_buffer, 0x28C); | 1122 | memcpy(&ftl_cxt, ftl_buffer, 0x28C); |
1005 | ftlcxtfound = 1; | 1123 | ftlcxtfound = 1; |
@@ -1024,7 +1142,7 @@ uint32_t ftl_open(void) | |||
1024 | for (i = 0; i < pagestoread; i++) | 1142 | for (i = 0; i < pagestoread; i++) |
1025 | { | 1143 | { |
1026 | if ((ftl_vfl_read(ftl_cxt.ftl_map_pages[i], | 1144 | if ((ftl_vfl_read(ftl_cxt.ftl_map_pages[i], |
1027 | ftl_buffer, &ftl_sparebuffer, 1, 1) & 0x11F) != 0) | 1145 | ftl_buffer, &ftl_sparebuffer[0], 1, 1) & 0x11F) != 0) |
1028 | panicf("FTL: Failed to read block map page %u", (unsigned)i); | 1146 | panicf("FTL: Failed to read block map page %u", (unsigned)i); |
1029 | //return 1; | 1147 | //return 1; |
1030 | 1148 | ||
@@ -1042,7 +1160,7 @@ uint32_t ftl_open(void) | |||
1042 | for (i = 0; i < pagestoread; i++) | 1160 | for (i = 0; i < pagestoread; i++) |
1043 | { | 1161 | { |
1044 | if ((ftl_vfl_read(ftl_cxt.ftl_erasectr_pages[i], | 1162 | if ((ftl_vfl_read(ftl_cxt.ftl_erasectr_pages[i], |
1045 | ftl_buffer, &ftl_sparebuffer, 1, 1) & 0x11F) != 0) | 1163 | ftl_buffer, &ftl_sparebuffer[0], 1, 1) & 0x11F) != 0) |
1046 | panicf("FTL: Failed to read erase counter page %u", (unsigned)i); | 1164 | panicf("FTL: Failed to read erase counter page %u", (unsigned)i); |
1047 | //return 1; | 1165 | //return 1; |
1048 | 1166 | ||
@@ -1086,7 +1204,7 @@ struct ftl_log_type* ftl_get_log_entry(uint32_t block) | |||
1086 | /* Exposed function: Read highlevel sectors */ | 1204 | /* Exposed function: Read highlevel sectors */ |
1087 | uint32_t ftl_read(uint32_t sector, uint32_t count, void* buffer) | 1205 | uint32_t ftl_read(uint32_t sector, uint32_t count, void* buffer) |
1088 | { | 1206 | { |
1089 | uint32_t i; | 1207 | uint32_t i, j; |
1090 | uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; | 1208 | uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; |
1091 | uint32_t error = 0; | 1209 | uint32_t error = 0; |
1092 | 1210 | ||
@@ -1112,13 +1230,31 @@ uint32_t ftl_read(uint32_t sector, uint32_t count, void* buffer) | |||
1112 | + (*logentry).pageoffsets[page]; | 1230 | + (*logentry).pageoffsets[page]; |
1113 | #endif | 1231 | #endif |
1114 | 1232 | ||
1115 | uint32_t ret = ftl_vfl_read(abspage, &((uint8_t*)buffer)[i << 11], | 1233 | if (count >= i + ftl_banks && !(page & (ftl_banks - 1)) |
1116 | &ftl_sparebuffer, 1, 1); | 1234 | && logentry == (struct ftl_log_type*)0) |
1117 | if ((ret & 2) != 0) memset(&((uint8_t*)buffer)[i << 11], 0, 0x800); | ||
1118 | else if ((ret & 0x11D) != 0 || ftl_sparebuffer.user.eccmark != 0xFF) | ||
1119 | { | 1235 | { |
1120 | error = 1; | 1236 | uint32_t ret = ftl_vfl_read_fast(abspage, &((uint8_t*)buffer)[i << 11], |
1121 | memset(&((uint8_t*)buffer)[i << 11], 0, 0x800); | 1237 | &ftl_sparebuffer[0], 1, 1); |
1238 | for (j = 0; j < ftl_banks; j++) | ||
1239 | if (ret & (2 << (j << 2))) | ||
1240 | memset(&((uint8_t*)buffer)[(i + j) << 11], 0, 0x800); | ||
1241 | else if ((ret & (0xd << (j << 2))) || ftl_sparebuffer[j].user.eccmark != 0xFF) | ||
1242 | { | ||
1243 | error = 1; | ||
1244 | memset(&((uint8_t*)buffer)[(i + j) << 11], 0, 0x800); | ||
1245 | } | ||
1246 | i += ftl_banks - 1; | ||
1247 | } | ||
1248 | else | ||
1249 | { | ||
1250 | uint32_t ret = ftl_vfl_read(abspage, &((uint8_t*)buffer)[i << 11], | ||
1251 | &ftl_sparebuffer[0], 1, 1); | ||
1252 | if (ret & 2) memset(&((uint8_t*)buffer)[i << 11], 0, 0x800); | ||
1253 | else if ((ret & 0x11D) != 0 || ftl_sparebuffer[0].user.eccmark != 0xFF) | ||
1254 | { | ||
1255 | error = 1; | ||
1256 | memset(&((uint8_t*)buffer)[i << 11], 0, 0x800); | ||
1257 | } | ||
1122 | } | 1258 | } |
1123 | } | 1259 | } |
1124 | 1260 | ||
@@ -1137,6 +1273,8 @@ uint32_t ftl_erase_block_internal(uint32_t block) | |||
1137 | block = block + (*ftl_nand_type).blocks | 1273 | block = block + (*ftl_nand_type).blocks |
1138 | - (*ftl_nand_type).userblocks - 0x17; | 1274 | - (*ftl_nand_type).userblocks - 0x17; |
1139 | if (block == 0 || block >= (*ftl_nand_type).blocks) return 1; | 1275 | if (block == 0 || block >= (*ftl_nand_type).blocks) return 1; |
1276 | uint32_t pblock[4]; | ||
1277 | uint32_t differs = 0; | ||
1140 | for (i = 0; i < ftl_banks; i++) | 1278 | for (i = 0; i < ftl_banks; i++) |
1141 | { | 1279 | { |
1142 | if (ftl_vfl_check_remap_scheduled(i, block) == 1) | 1280 | if (ftl_vfl_check_remap_scheduled(i, block) == 1) |
@@ -1145,29 +1283,38 @@ uint32_t ftl_erase_block_internal(uint32_t block) | |||
1145 | ftl_vfl_mark_remap_done(i, block); | 1283 | ftl_vfl_mark_remap_done(i, block); |
1146 | } | 1284 | } |
1147 | ftl_vfl_log_success(i, block); | 1285 | ftl_vfl_log_success(i, block); |
1148 | uint32_t pblock = ftl_vfl_get_physical_block(i, block); | 1286 | pblock[i] = ftl_vfl_get_physical_block(i, block); |
1149 | uint32_t rc; | 1287 | if (pblock[i] != pblock[0]) differs = 1; |
1150 | for (j = 0; j < 3; j++) | 1288 | } |
1151 | { | 1289 | uint32_t res = 0xf; |
1152 | rc = nand_block_erase(i, pblock * (*ftl_nand_type).pagesperblock); | 1290 | if (!differs) |
1153 | if (rc == 0) break; | 1291 | res = nand_block_erase_fast(pblock[0] * (*ftl_nand_type).pagesperblock); |
1154 | } | 1292 | if (!res) return 0; |
1155 | if (rc != 0) | 1293 | for (i = 0; i < ftl_banks; i++) |
1294 | if (res & (1 << i)) | ||
1156 | { | 1295 | { |
1157 | panicf("FTL: Block erase failed on bank %u block %u", | 1296 | uint32_t rc; |
1158 | (unsigned)i, (unsigned)block); | 1297 | for (j = 0; j < 3; j++) |
1159 | if (pblock != block) | ||
1160 | { | 1298 | { |
1161 | uint32_t spareindex = pblock - ftl_vfl_cxt[i].firstspare; | 1299 | rc = nand_block_erase(i, pblock[i] * (*ftl_nand_type).pagesperblock); |
1162 | ftl_vfl_cxt[i].remaptable[spareindex] = 0xFFFF; | 1300 | if (rc == 0) break; |
1301 | } | ||
1302 | if (rc != 0) | ||
1303 | { | ||
1304 | panicf("FTL: Block erase failed on bank %u block %u", | ||
1305 | (unsigned)i, (unsigned)block); | ||
1306 | if (pblock[i] != block) | ||
1307 | { | ||
1308 | uint32_t spareindex = pblock[i] - ftl_vfl_cxt[i].firstspare; | ||
1309 | ftl_vfl_cxt[i].remaptable[spareindex] = 0xFFFF; | ||
1310 | } | ||
1311 | ftl_vfl_cxt[i].field_18++; | ||
1312 | if (ftl_vfl_remap_block(i, block) == 0) return 1; | ||
1313 | if (ftl_vfl_commit_cxt(i) != 0) return 1; | ||
1314 | memset(&ftl_sparebuffer[i], 0, 0x40); | ||
1315 | nand_write_page(i, pblock[i], &ftl_vfl_cxt[0], &ftl_sparebuffer[i], 1); | ||
1163 | } | 1316 | } |
1164 | ftl_vfl_cxt[i].field_18++; | ||
1165 | if (ftl_vfl_remap_block(i, block) == 0) return 1; | ||
1166 | if (ftl_vfl_commit_cxt(i) != 0) return 1; | ||
1167 | memset(&ftl_sparebuffer, 0, 0x40); | ||
1168 | nand_write_page(i, pblock, &ftl_vfl_cxt[0], &ftl_sparebuffer, 1); | ||
1169 | } | 1317 | } |
1170 | } | ||
1171 | return 0; | 1318 | return 0; |
1172 | } | 1319 | } |
1173 | #endif | 1320 | #endif |
@@ -1251,20 +1398,20 @@ uint32_t ftl_store_ctrl_block_list(void) | |||
1251 | because it is too dirty or needs to be moved. */ | 1398 | because it is too dirty or needs to be moved. */ |
1252 | uint32_t ftl_save_erasectr_page(uint32_t index) | 1399 | uint32_t ftl_save_erasectr_page(uint32_t index) |
1253 | { | 1400 | { |
1254 | memset(&ftl_sparebuffer, 0xFF, 0x40); | 1401 | memset(&ftl_sparebuffer[0], 0xFF, 0x40); |
1255 | ftl_sparebuffer.meta.usn = ftl_cxt.usn; | 1402 | ftl_sparebuffer[0].meta.usn = ftl_cxt.usn; |
1256 | ftl_sparebuffer.meta.idx = index; | 1403 | ftl_sparebuffer[0].meta.idx = index; |
1257 | ftl_sparebuffer.meta.type = 0x46; | 1404 | ftl_sparebuffer[0].meta.type = 0x46; |
1258 | if (ftl_vfl_write(ftl_cxt.ftlctrlpage, &ftl_erasectr[index << 10], | 1405 | if (ftl_vfl_write(ftl_cxt.ftlctrlpage, &ftl_erasectr[index << 10], |
1259 | &ftl_sparebuffer) != 0) | 1406 | &ftl_sparebuffer[0]) != 0) |
1260 | return 1; | 1407 | return 1; |
1261 | if ((ftl_vfl_read(ftl_cxt.ftlctrlpage, ftl_buffer, | 1408 | if ((ftl_vfl_read(ftl_cxt.ftlctrlpage, ftl_buffer, |
1262 | &ftl_sparebuffer, 1, 1) & 0x11F) != 0) | 1409 | &ftl_sparebuffer[0], 1, 1) & 0x11F) != 0) |
1263 | return 1; | 1410 | return 1; |
1264 | if (memcmp(ftl_buffer, &ftl_erasectr[index << 10], 0x800) != 0) return 1; | 1411 | if (memcmp(ftl_buffer, &ftl_erasectr[index << 10], 0x800) != 0) return 1; |
1265 | if (ftl_sparebuffer.meta.type != 0x46) return 1; | 1412 | if (ftl_sparebuffer[0].meta.type != 0x46) return 1; |
1266 | if (ftl_sparebuffer.meta.idx != index) return 1; | 1413 | if (ftl_sparebuffer[0].meta.idx != index) return 1; |
1267 | if (ftl_sparebuffer.meta.usn != ftl_cxt.usn) return 1; | 1414 | if (ftl_sparebuffer[0].meta.usn != ftl_cxt.usn) return 1; |
1268 | ftl_cxt.ftl_erasectr_pages[index] = ftl_cxt.ftlctrlpage; | 1415 | ftl_cxt.ftl_erasectr_pages[index] = ftl_cxt.ftlctrlpage; |
1269 | ftl_erasectr_dirt[index] = 0; | 1416 | ftl_erasectr_dirt[index] = 0; |
1270 | return 0; | 1417 | return 0; |
@@ -1317,17 +1464,17 @@ uint32_t ftl_copy_page(uint32_t source, uint32_t destination, | |||
1317 | uint32_t lpn, uint32_t type) | 1464 | uint32_t lpn, uint32_t type) |
1318 | { | 1465 | { |
1319 | uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; | 1466 | uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; |
1320 | uint32_t rc = ftl_vfl_read(source, ftl_copybuffer, | 1467 | uint32_t rc = ftl_vfl_read(source, ftl_copybuffer[0], |
1321 | &ftl_sparebuffer, 1, 1) & 0x11F; | 1468 | &ftl_copyspare[0], 1, 1) & 0x11F; |
1322 | memset(&ftl_sparebuffer, 0xFF, 0x40); | 1469 | memset(&ftl_copyspare[0], 0xFF, 0x40); |
1323 | ftl_sparebuffer.user.lpn = lpn; | 1470 | ftl_copyspare[0].user.lpn = lpn; |
1324 | ftl_sparebuffer.user.usn = ++ftl_cxt.nextblockusn; | 1471 | ftl_copyspare[0].user.usn = ++ftl_cxt.nextblockusn; |
1325 | ftl_sparebuffer.user.type = 0x40; | 1472 | ftl_copyspare[0].user.type = 0x40; |
1326 | if ((rc & 2) != 0) memset(ftl_copybuffer, 0, 0x800); | 1473 | if ((rc & 2) != 0) memset(ftl_copybuffer[0], 0, 0x800); |
1327 | else if (rc != 0) ftl_sparebuffer.user.eccmark = 0x55; | 1474 | else if (rc != 0) ftl_copyspare[0].user.eccmark = 0x55; |
1328 | if (type == 1 && destination % ppb == ppb - 1) | 1475 | if (type == 1 && destination % ppb == ppb - 1) |
1329 | ftl_sparebuffer.user.type = 0x41; | 1476 | ftl_copyspare[0].user.type = 0x41; |
1330 | return ftl_vfl_write(destination, ftl_copybuffer, &ftl_sparebuffer); | 1477 | return ftl_vfl_write(destination, ftl_copybuffer[0], &ftl_copyspare[0]); |
1331 | } | 1478 | } |
1332 | #endif | 1479 | #endif |
1333 | 1480 | ||
@@ -1336,21 +1483,28 @@ uint32_t ftl_copy_page(uint32_t source, uint32_t destination, | |||
1336 | /* Copies a pBlock to a vBlock */ | 1483 | /* Copies a pBlock to a vBlock */ |
1337 | uint32_t ftl_copy_block(uint32_t source, uint32_t destination) | 1484 | uint32_t ftl_copy_block(uint32_t source, uint32_t destination) |
1338 | { | 1485 | { |
1339 | uint32_t i; | 1486 | uint32_t i, j; |
1340 | uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; | 1487 | uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; |
1341 | uint32_t error = 0; | 1488 | uint32_t error = 0; |
1342 | ftl_cxt.nextblockusn++; | 1489 | ftl_cxt.nextblockusn++; |
1343 | for (i = 0; i < ppb; i++) | 1490 | for (i = 0; i < (*ftl_nand_type).pagesperblock; i ++) |
1344 | { | 1491 | { |
1345 | uint32_t rc = ftl_read(source * ppb + i, 1, ftl_copybuffer); | 1492 | uint32_t rc = ftl_read(source * ppb + i * ftl_banks, ftl_banks, ftl_copybuffer[0]); |
1346 | memset(&ftl_sparebuffer, 0xFF, 0x40); | 1493 | memset(&ftl_copyspare[0], 0xFF, 0x100); |
1347 | ftl_sparebuffer.user.lpn = source * ppb + i; | 1494 | for (j = 0; j < ftl_banks; j++) |
1348 | ftl_sparebuffer.user.usn = ftl_cxt.nextblockusn; | 1495 | { |
1349 | ftl_sparebuffer.user.type = 0x40; | 1496 | ftl_copyspare[j].user.lpn = source * ppb + i * ftl_banks + j; |
1350 | if (rc != 0) ftl_sparebuffer.user.eccmark = 0x55; | 1497 | ftl_copyspare[j].user.usn = ftl_cxt.nextblockusn; |
1351 | if (i == ppb - 1) ftl_sparebuffer.user.type = 0x41; | 1498 | ftl_copyspare[j].user.type = 0x40; |
1352 | if (ftl_vfl_write(destination * ppb + i, | 1499 | if (rc) |
1353 | ftl_copybuffer, &ftl_sparebuffer) != 0) | 1500 | { |
1501 | if (ftl_read(source * ppb + i * ftl_banks + j, 1, ftl_copybuffer[j])) | ||
1502 | ftl_copyspare[j].user.eccmark = 0x55; | ||
1503 | } | ||
1504 | if (i + j == ppb - 1) ftl_copyspare[j].user.type = 0x41; | ||
1505 | } | ||
1506 | if (ftl_vfl_write_fast(destination * ppb + i * ftl_banks, | ||
1507 | ftl_copybuffer[0], &ftl_copyspare[0])) | ||
1354 | { | 1508 | { |
1355 | error = 1; | 1509 | error = 1; |
1356 | break; | 1510 | break; |
@@ -1471,6 +1625,7 @@ uint32_t ftl_commit_scattered(struct ftl_log_type* entry) | |||
1471 | If this fails for whichever reason, it will be committed the usual way. */ | 1625 | If this fails for whichever reason, it will be committed the usual way. */ |
1472 | uint32_t ftl_commit_sequential(struct ftl_log_type* entry) | 1626 | uint32_t ftl_commit_sequential(struct ftl_log_type* entry) |
1473 | { | 1627 | { |
1628 | uint32_t i; | ||
1474 | uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; | 1629 | uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; |
1475 | 1630 | ||
1476 | if ((*entry).issequential != 1 | 1631 | if ((*entry).issequential != 1 |
@@ -1484,8 +1639,29 @@ uint32_t ftl_commit_sequential(struct ftl_log_type* entry) | |||
1484 | + (*entry).pagesused; | 1639 | + (*entry).pagesused; |
1485 | uint32_t oldpage = ftl_map[(*entry).logicalvblock] * ppb | 1640 | uint32_t oldpage = ftl_map[(*entry).logicalvblock] * ppb |
1486 | + (*entry).pagesused; | 1641 | + (*entry).pagesused; |
1487 | if ((*entry).pageoffsets[(*entry).pagesused] != 0xFFFF | 1642 | if ((*entry).pageoffsets[(*entry).pagesused] != 0xFFFF) |
1488 | || ftl_copy_page(oldpage, newpage, lpn, 1) != 0) | 1643 | return ftl_commit_scattered(entry); |
1644 | if (!((*entry).pagesused & (ftl_banks - 1))) | ||
1645 | { | ||
1646 | uint32_t rc = ftl_vfl_read_fast(oldpage, ftl_copybuffer[0], | ||
1647 | &ftl_copyspare[0], 1, 1); | ||
1648 | memset(&ftl_copyspare[0], 0xFF, 0x100); | ||
1649 | for (i = 0; i < ftl_banks; i++) | ||
1650 | { | ||
1651 | ftl_copyspare[i].user.lpn = lpn + i; | ||
1652 | ftl_copyspare[i].user.usn = ++ftl_cxt.nextblockusn; | ||
1653 | ftl_copyspare[i].user.type = 0x40; | ||
1654 | if (rc & (2 << (i << 2))) memset(ftl_copybuffer[i], 0, 0x800); | ||
1655 | else if (rc & (0xd << (i << 2))) | ||
1656 | ftl_copyspare[i].user.eccmark = 0x55; | ||
1657 | if ((*entry).pagesused + i == ppb - 1) | ||
1658 | ftl_copyspare[i].user.type = 0x41; | ||
1659 | } | ||
1660 | if (ftl_vfl_write_fast(newpage, ftl_copybuffer[0], &ftl_copyspare[0])) | ||
1661 | return ftl_commit_scattered(entry); | ||
1662 | (*entry).pagesused += ftl_banks - 1; | ||
1663 | } | ||
1664 | else if (ftl_copy_page(oldpage, newpage, lpn, 1)) | ||
1489 | return ftl_commit_scattered(entry); | 1665 | return ftl_commit_scattered(entry); |
1490 | } | 1666 | } |
1491 | ftl_release_pool_block(ftl_map[(*entry).logicalvblock]); | 1667 | ftl_release_pool_block(ftl_map[(*entry).logicalvblock]); |
@@ -1606,21 +1782,21 @@ uint32_t ftl_commit_cxt(void) | |||
1606 | for (i = 0; i < mappages; i++) | 1782 | for (i = 0; i < mappages; i++) |
1607 | { | 1783 | { |
1608 | if (ftl_next_ctrl_pool_page() != 0) return 1; | 1784 | if (ftl_next_ctrl_pool_page() != 0) return 1; |
1609 | memset(&ftl_sparebuffer, 0xFF, 0x40); | 1785 | memset(&ftl_sparebuffer[0], 0xFF, 0x40); |
1610 | ftl_sparebuffer.meta.usn = ftl_cxt.usn; | 1786 | ftl_sparebuffer[0].meta.usn = ftl_cxt.usn; |
1611 | ftl_sparebuffer.meta.idx = i; | 1787 | ftl_sparebuffer[0].meta.idx = i; |
1612 | ftl_sparebuffer.meta.type = 0x44; | 1788 | ftl_sparebuffer[0].meta.type = 0x44; |
1613 | if (ftl_vfl_write(ftl_cxt.ftlctrlpage, &ftl_map[i << 10], | 1789 | if (ftl_vfl_write(ftl_cxt.ftlctrlpage, &ftl_map[i << 10], |
1614 | &ftl_sparebuffer) != 0) | 1790 | &ftl_sparebuffer[0]) != 0) |
1615 | return 1; | 1791 | return 1; |
1616 | ftl_cxt.ftl_map_pages[i] = ftl_cxt.ftlctrlpage; | 1792 | ftl_cxt.ftl_map_pages[i] = ftl_cxt.ftlctrlpage; |
1617 | } | 1793 | } |
1618 | if (ftl_next_ctrl_pool_page() != 0) return 1; | 1794 | if (ftl_next_ctrl_pool_page() != 0) return 1; |
1619 | ftl_cxt.clean_flag = 1; | 1795 | ftl_cxt.clean_flag = 1; |
1620 | memset(&ftl_sparebuffer, 0xFF, 0x40); | 1796 | memset(&ftl_sparebuffer[0], 0xFF, 0x40); |
1621 | ftl_sparebuffer.meta.usn = ftl_cxt.usn; | 1797 | ftl_sparebuffer[0].meta.usn = ftl_cxt.usn; |
1622 | ftl_sparebuffer.meta.type = 0x43; | 1798 | ftl_sparebuffer[0].meta.type = 0x43; |
1623 | if (ftl_vfl_write(ftl_cxt.ftlctrlpage, &ftl_cxt, &ftl_sparebuffer) != 0) | 1799 | if (ftl_vfl_write(ftl_cxt.ftlctrlpage, &ftl_cxt, &ftl_sparebuffer[0]) != 0) |
1624 | return 1; | 1800 | return 1; |
1625 | return 0; | 1801 | return 0; |
1626 | } | 1802 | } |
@@ -1674,7 +1850,7 @@ uint32_t ftl_swap_blocks(void) | |||
1674 | /* Exposed function: Write highlevel sectors */ | 1850 | /* Exposed function: Write highlevel sectors */ |
1675 | uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) | 1851 | uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) |
1676 | { | 1852 | { |
1677 | uint32_t i, j; | 1853 | uint32_t i, j, k; |
1678 | uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; | 1854 | uint32_t ppb = (*ftl_nand_type).pagesperblock * ftl_banks; |
1679 | 1855 | ||
1680 | if (sector + count > (*ftl_nand_type).userblocks * ppb) | 1856 | if (sector + count > (*ftl_nand_type).userblocks * ppb) |
@@ -1694,11 +1870,11 @@ uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) | |||
1694 | return 1; | 1870 | return 1; |
1695 | } | 1871 | } |
1696 | memset(ftl_buffer, 0xFF, 0x800); | 1872 | memset(ftl_buffer, 0xFF, 0x800); |
1697 | memset(&ftl_sparebuffer, 0xFF, 0x40); | 1873 | memset(&ftl_sparebuffer[0], 0xFF, 0x40); |
1698 | ftl_sparebuffer.meta.usn = ftl_cxt.usn; | 1874 | ftl_sparebuffer[0].meta.usn = ftl_cxt.usn; |
1699 | ftl_sparebuffer.meta.type = 0x47; | 1875 | ftl_sparebuffer[0].meta.type = 0x47; |
1700 | if (ftl_vfl_write(ftl_cxt.ftlctrlpage, ftl_buffer, | 1876 | if (ftl_vfl_write(ftl_cxt.ftlctrlpage, ftl_buffer, |
1701 | &ftl_sparebuffer) == 0) | 1877 | &ftl_sparebuffer[0]) == 0) |
1702 | break; | 1878 | break; |
1703 | } | 1879 | } |
1704 | if (i == 3) | 1880 | if (i == 3) |
@@ -1735,16 +1911,27 @@ uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) | |||
1735 | } | 1911 | } |
1736 | } | 1912 | } |
1737 | ftl_cxt.nextblockusn++; | 1913 | ftl_cxt.nextblockusn++; |
1738 | for (j = 0; j < ppb; j++) | 1914 | for (j = 0; j < ppb; j += ftl_banks) |
1739 | { | 1915 | { |
1740 | memset(&ftl_sparebuffer, 0xFF, 0x40); | 1916 | memset(&ftl_sparebuffer[0], 0xFF, 0x100); |
1741 | ftl_sparebuffer.user.lpn = sector + i + j; | 1917 | for (k = 0; k < ftl_banks; k++) |
1742 | ftl_sparebuffer.user.usn = ftl_cxt.nextblockusn; | 1918 | { |
1743 | ftl_sparebuffer.user.type = 0x40; | 1919 | ftl_sparebuffer[k].user.lpn = sector + i + j + k; |
1744 | if (j == ppb - 1) ftl_sparebuffer.user.type = 0x41; | 1920 | ftl_sparebuffer[k].user.usn = ftl_cxt.nextblockusn; |
1745 | while (ftl_vfl_write(vblock * ppb + j, | 1921 | ftl_sparebuffer[k].user.type = 0x40; |
1746 | &((uint8_t*)buffer)[(i + j) << 11], | 1922 | if (j == ppb - 1) ftl_sparebuffer[k].user.type = 0x41; |
1747 | &ftl_sparebuffer) != 0); | 1923 | } |
1924 | uint32_t rc = ftl_vfl_write_fast(vblock * ppb + j, | ||
1925 | &((uint8_t*)buffer)[(i + j) << 11], | ||
1926 | &ftl_sparebuffer[0]); | ||
1927 | if (rc) | ||
1928 | for (k = 0; k < ftl_banks; k++) | ||
1929 | if (rc & (1 << k)) | ||
1930 | { | ||
1931 | while (ftl_vfl_write(vblock * ppb + j + k, | ||
1932 | &((uint8_t*)buffer)[(i + j + k) << 11], | ||
1933 | &ftl_sparebuffer[k])); | ||
1934 | } | ||
1748 | } | 1935 | } |
1749 | ftl_release_pool_block(ftl_map[block]); | 1936 | ftl_release_pool_block(ftl_map[block]); |
1750 | ftl_map[block] = vblock; | 1937 | ftl_map[block] = vblock; |
@@ -1762,20 +1949,57 @@ uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer) | |||
1762 | return 1; | 1949 | return 1; |
1763 | } | 1950 | } |
1764 | } | 1951 | } |
1765 | memset(&ftl_sparebuffer, 0xFF, 0x40); | 1952 | if ((unsigned)((*logentry).pagesused + ftl_banks) <= ppb |
1766 | ftl_sparebuffer.user.lpn = sector + i; | 1953 | && i + ftl_banks <= count |
1767 | ftl_sparebuffer.user.usn = ++ftl_cxt.nextblockusn; | 1954 | && !((*logentry).pagesused & (ftl_banks - 1)) |
1768 | ftl_sparebuffer.user.type = 0x40; | 1955 | && page + ftl_banks <= ppb) |
1769 | uint32_t abspage = (*logentry).scatteredvblock * ppb | ||
1770 | + (*logentry).pagesused++; | ||
1771 | if (ftl_vfl_write(abspage, &((uint8_t*)buffer)[i << 11], | ||
1772 | &ftl_sparebuffer) == 0) | ||
1773 | { | 1956 | { |
1774 | if ((*logentry).pageoffsets[page] == 0xFFFF) | 1957 | memset(&ftl_sparebuffer[0], 0xFF, 0x100); |
1775 | (*logentry).pagescurrent++; | 1958 | for (j = 0; j < ftl_banks; j++) |
1776 | (*logentry).pageoffsets[page] = (*logentry).pagesused - 1; | 1959 | { |
1777 | ftl_check_still_sequential(logentry, page); | 1960 | ftl_sparebuffer[j].user.lpn = sector + i + j; |
1778 | i++; | 1961 | ftl_sparebuffer[j].user.usn = ++ftl_cxt.nextblockusn; |
1962 | ftl_sparebuffer[j].user.type = 0x40; | ||
1963 | if ((*logentry).pagesused + j == ppb - 1 && (*logentry).issequential) | ||
1964 | ftl_sparebuffer[j].user.type = 0x41; | ||
1965 | } | ||
1966 | uint32_t abspage = (*logentry).scatteredvblock * ppb | ||
1967 | + (*logentry).pagesused; | ||
1968 | (*logentry).pagesused += ftl_banks; | ||
1969 | if (ftl_vfl_write_fast(abspage, &((uint8_t*)buffer)[i << 11], | ||
1970 | &ftl_sparebuffer[0]) == 0) | ||
1971 | { | ||
1972 | for (j = 0; j < ftl_banks; j++) | ||
1973 | { | ||
1974 | if ((*logentry).pageoffsets[page + j] == 0xFFFF) | ||
1975 | (*logentry).pagescurrent++; | ||
1976 | (*logentry).pageoffsets[page + j] = (*logentry).pagesused - ftl_banks + j; | ||
1977 | if ((*logentry).pagesused - ftl_banks + j + 1 != (*logentry).pagescurrent | ||
1978 | || (*logentry).pageoffsets[page + j] != page + j) | ||
1979 | (*logentry).issequential = 0; | ||
1980 | } | ||
1981 | i += ftl_banks; | ||
1982 | } | ||
1983 | } | ||
1984 | else | ||
1985 | { | ||
1986 | memset(&ftl_sparebuffer[0], 0xFF, 0x40); | ||
1987 | ftl_sparebuffer[0].user.lpn = sector + i; | ||
1988 | ftl_sparebuffer[0].user.usn = ++ftl_cxt.nextblockusn; | ||
1989 | ftl_sparebuffer[0].user.type = 0x40; | ||
1990 | if ((*logentry).pagesused == ppb - 1 && (*logentry).issequential) | ||
1991 | ftl_sparebuffer[0].user.type = 0x41; | ||
1992 | uint32_t abspage = (*logentry).scatteredvblock * ppb | ||
1993 | + (*logentry).pagesused++; | ||
1994 | if (ftl_vfl_write(abspage, &((uint8_t*)buffer)[i << 11], | ||
1995 | &ftl_sparebuffer[0]) == 0) | ||
1996 | { | ||
1997 | if ((*logentry).pageoffsets[page] == 0xFFFF) | ||
1998 | (*logentry).pagescurrent++; | ||
1999 | (*logentry).pageoffsets[page] = (*logentry).pagesused - 1; | ||
2000 | ftl_check_still_sequential(logentry, page); | ||
2001 | i++; | ||
2002 | } | ||
1779 | } | 2003 | } |
1780 | } | 2004 | } |
1781 | } | 2005 | } |
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c index 3b5f88d3c2..84bf0e6bb8 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c +++ b/firmware/target/arm/s5l8700/ipodnano2g/nand-nano2g.c | |||
@@ -99,13 +99,14 @@ static struct wakeup ecc_wakeup; | |||
99 | 99 | ||
100 | static uint8_t nand_data[0x800] __attribute__((aligned(16))); | 100 | static uint8_t nand_data[0x800] __attribute__((aligned(16))); |
101 | static uint8_t nand_ctrl[0x200] __attribute__((aligned(16))); | 101 | static uint8_t nand_ctrl[0x200] __attribute__((aligned(16))); |
102 | static uint8_t nand_spare[0x40] __attribute__((aligned(16))); | 102 | static uint8_t nand_spare[4][0x40] __attribute__((aligned(16))); |
103 | static uint8_t nand_ecc[0x30] __attribute__((aligned(16))); | 103 | static uint8_t nand_ecc[0x30] __attribute__((aligned(16))); |
104 | 104 | ||
105 | 105 | ||
106 | uint32_t nand_unlock(uint32_t rc) | 106 | uint32_t nand_unlock(uint32_t rc) |
107 | { | 107 | { |
108 | led(false); | 108 | led(false); |
109 | nand_last_activity_value = current_tick; | ||
109 | mutex_unlock(&nand_mtx); | 110 | mutex_unlock(&nand_mtx); |
110 | return rc; | 111 | return rc; |
111 | } | 112 | } |
@@ -371,7 +372,7 @@ uint32_t nand_read_page(uint32_t bank, uint32_t page, void* databuffer, | |||
371 | uint32_t checkempty) | 372 | uint32_t checkempty) |
372 | { | 373 | { |
373 | uint8_t* data = nand_data; | 374 | uint8_t* data = nand_data; |
374 | uint8_t* spare = nand_spare; | 375 | uint8_t* spare = nand_spare[0]; |
375 | if (databuffer && !((uint32_t)databuffer & 0xf)) | 376 | if (databuffer && !((uint32_t)databuffer & 0xf)) |
376 | data = (uint8_t*)databuffer; | 377 | data = (uint8_t*)databuffer; |
377 | if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) | 378 | if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) |
@@ -432,7 +433,7 @@ uint32_t nand_write_page(uint32_t bank, uint32_t page, void* databuffer, | |||
432 | void* sparebuffer, uint32_t doecc) | 433 | void* sparebuffer, uint32_t doecc) |
433 | { | 434 | { |
434 | uint8_t* data = nand_data; | 435 | uint8_t* data = nand_data; |
435 | uint8_t* spare = nand_spare; | 436 | uint8_t* spare = nand_spare[0]; |
436 | if (databuffer && !((uint32_t)databuffer & 0xf)) | 437 | if (databuffer && !((uint32_t)databuffer & 0xf)) |
437 | data = (uint8_t*)databuffer; | 438 | data = (uint8_t*)databuffer; |
438 | if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) | 439 | if (sparebuffer && !((uint32_t)sparebuffer & 0xf)) |
@@ -487,6 +488,203 @@ uint32_t nand_block_erase(uint32_t bank, uint32_t page) | |||
487 | return nand_unlock(0); | 488 | return nand_unlock(0); |
488 | } | 489 | } |
489 | 490 | ||
491 | uint32_t nand_read_page_fast(uint32_t page, void* databuffer, | ||
492 | void* sparebuffer, uint32_t doecc, | ||
493 | uint32_t checkempty) | ||
494 | { | ||
495 | uint32_t i, rc = 0; | ||
496 | if (((uint32_t)databuffer & 0xf) || ((uint32_t)sparebuffer & 0xf) | ||
497 | || !databuffer || !sparebuffer || !doecc) | ||
498 | { | ||
499 | for (i = 0; i < 4; i++) | ||
500 | { | ||
501 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
502 | void* databuf = (void*)0; | ||
503 | void* sparebuf = (void*)0; | ||
504 | if (databuffer) databuf = (void*)((uint32_t)databuffer + 0x800 * i); | ||
505 | if (sparebuffer) sparebuf = (void*)((uint32_t)sparebuffer + 0x40 * i); | ||
506 | uint32_t ret = nand_read_page(i, page, databuf, sparebuf, doecc, checkempty); | ||
507 | if (ret & 1) rc |= 1 << (i << 2); | ||
508 | if (ret & 2) rc |= 2 << (i << 2); | ||
509 | if (ret & 0x10) rc |= 4 << (i << 2); | ||
510 | if (ret & 0x100) rc |= 8 << (i << 2); | ||
511 | } | ||
512 | return rc; | ||
513 | } | ||
514 | mutex_lock(&nand_mtx); | ||
515 | nand_last_activity_value = current_tick; | ||
516 | led(true); | ||
517 | if (!nand_powered) nand_power_up(); | ||
518 | for (i = 0; i < 4; i++) | ||
519 | { | ||
520 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
521 | nand_set_fmctrl0(i, FMCTRL0_ENABLEDMA); | ||
522 | if (nand_send_cmd(NAND_CMD_READ)) | ||
523 | { | ||
524 | rc |= 1 << (i << 2); | ||
525 | continue; | ||
526 | } | ||
527 | if (nand_send_address(page, databuffer ? 0 : 0x800)) | ||
528 | { | ||
529 | rc |= 1 << (i << 2); | ||
530 | continue; | ||
531 | } | ||
532 | if (nand_send_cmd(NAND_CMD_READ2)) | ||
533 | { | ||
534 | rc |= 1 << (i << 2); | ||
535 | continue; | ||
536 | } | ||
537 | } | ||
538 | for (i = 0; i < 4; i++) | ||
539 | { | ||
540 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
541 | if (nand_wait_status_ready(i)) | ||
542 | { | ||
543 | rc |= 1 << (i << 2); | ||
544 | continue; | ||
545 | } | ||
546 | if (nand_transfer_data(i, 0, (void*)((uint32_t)databuffer | ||
547 | + 0x800 * i), 0x800)) | ||
548 | { | ||
549 | rc |= 1 << (i << 2); | ||
550 | continue; | ||
551 | } | ||
552 | if (nand_transfer_data(i, 0, (void*)((uint32_t)sparebuffer | ||
553 | + 0x40 * i), 0x40)) | ||
554 | { | ||
555 | rc |= 1 << (i << 2); | ||
556 | continue; | ||
557 | } | ||
558 | memcpy(nand_ecc, (void*)((uint32_t)sparebuffer + 0x40 * i + 0xC), 0x28); | ||
559 | if (ecc_decode(3, (void*)((uint32_t)databuffer + 0x800 * i), nand_ecc) & 1) | ||
560 | rc |= 4 << (i << 2); | ||
561 | memset(nand_ctrl, 0xFF, 0x200); | ||
562 | memcpy(nand_ctrl, (void*)((uint32_t)sparebuffer + 0x40 * i), 0xC); | ||
563 | memcpy(nand_ecc, (void*)((uint32_t)sparebuffer + 0x40 * i + 0x34), 0xC); | ||
564 | if (ecc_decode(0, nand_ctrl, nand_ecc)) | ||
565 | { | ||
566 | rc |= 8 << (i << 2); | ||
567 | memset((void*)((uint32_t)sparebuffer + 0x40 * i), 0xFF, 0xC); | ||
568 | } | ||
569 | else memcpy((void*)((uint32_t)sparebuffer + 0x40 * i), nand_ctrl, 0xC); | ||
570 | if (checkempty) | ||
571 | rc |= nand_check_empty((void*)((uint32_t)sparebuffer | ||
572 | + 0x40 * i)) << ((i << 2) + 1); | ||
573 | } | ||
574 | return nand_unlock(rc); | ||
575 | } | ||
576 | |||
577 | uint32_t nand_write_page_fast(uint32_t page, void* databuffer, | ||
578 | void* sparebuffer, uint32_t doecc) | ||
579 | { | ||
580 | uint32_t i, rc = 0; | ||
581 | if (((uint32_t)databuffer & 0xf) || ((uint32_t)sparebuffer & 0xf) | ||
582 | || !databuffer || !sparebuffer || !doecc) | ||
583 | { | ||
584 | for (i = 0; i < 4; i++) | ||
585 | { | ||
586 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
587 | void* databuf = (void*)0; | ||
588 | void* sparebuf = (void*)0; | ||
589 | if (databuffer) databuf = (void*)((uint32_t)databuffer + 0x800 * i); | ||
590 | if (sparebuffer) sparebuf = (void*)((uint32_t)sparebuffer + 0x40 * i); | ||
591 | rc |= nand_write_page(i, page, databuf, sparebuf, doecc) << i; | ||
592 | } | ||
593 | return rc; | ||
594 | } | ||
595 | mutex_lock(&nand_mtx); | ||
596 | nand_last_activity_value = current_tick; | ||
597 | led(true); | ||
598 | if (!nand_powered) nand_power_up(); | ||
599 | for (i = 0; i < 4; i++) | ||
600 | { | ||
601 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
602 | if (ecc_encode(3, (void*)((uint32_t)databuffer + 0x800 * i), nand_ecc)) | ||
603 | { | ||
604 | rc |= 1 << i; | ||
605 | continue; | ||
606 | } | ||
607 | memcpy((void*)((uint32_t)sparebuffer + 0x40 * i + 0xC), nand_ecc, 0x28); | ||
608 | memset(nand_ctrl, 0xFF, 0x200); | ||
609 | memcpy(nand_ctrl, (void*)((uint32_t)sparebuffer + 0x40 * i), 0xC); | ||
610 | if (ecc_encode(0, nand_ctrl, nand_ecc)) | ||
611 | { | ||
612 | rc |= 1 << i; | ||
613 | continue; | ||
614 | } | ||
615 | memcpy((void*)((uint32_t)sparebuffer + 0x40 * i + 0x34), nand_ecc, 0xC); | ||
616 | nand_set_fmctrl0(i, FMCTRL0_ENABLEDMA); | ||
617 | if (nand_send_cmd(NAND_CMD_PROGRAM)) | ||
618 | { | ||
619 | rc |= 1 << i; | ||
620 | continue; | ||
621 | } | ||
622 | if (nand_send_address(page, databuffer ? 0 : 0x800)) | ||
623 | { | ||
624 | rc |= 1 << i; | ||
625 | continue; | ||
626 | } | ||
627 | if (nand_transfer_data(i, 1, (void*)((uint32_t)databuffer | ||
628 | + 0x800 * i), 0x800)) | ||
629 | { | ||
630 | rc |= 1 << i; | ||
631 | continue; | ||
632 | } | ||
633 | if (nand_transfer_data(i, 1, (void*)((uint32_t)sparebuffer | ||
634 | + 0x40 * i), 0x40)) | ||
635 | { | ||
636 | rc |= 1 << i; | ||
637 | continue; | ||
638 | } | ||
639 | if (nand_send_cmd(NAND_CMD_PROGCNFRM)) | ||
640 | { | ||
641 | rc |= 1 << i; | ||
642 | continue; | ||
643 | } | ||
644 | } | ||
645 | for (i = 0; i < 4; i++) | ||
646 | { | ||
647 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
648 | rc |= nand_wait_status_ready(i) << i; | ||
649 | } | ||
650 | return nand_unlock(rc); | ||
651 | } | ||
652 | |||
653 | uint32_t nand_block_erase_fast(uint32_t page) | ||
654 | { | ||
655 | uint32_t i, rc = 0; | ||
656 | mutex_lock(&nand_mtx); | ||
657 | nand_last_activity_value = current_tick; | ||
658 | led(true); | ||
659 | if (!nand_powered) nand_power_up(); | ||
660 | for (i = 0; i < 4; i++) | ||
661 | { | ||
662 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
663 | nand_set_fmctrl0(i, 0); | ||
664 | if (nand_send_cmd(NAND_CMD_BLOCKERASE)) | ||
665 | { | ||
666 | rc |= 1 << i; | ||
667 | continue; | ||
668 | } | ||
669 | FMANUM = 2; | ||
670 | FMADDR0 = page; | ||
671 | FMCTRL1 = FMCTRL1_DOTRANSADDR; | ||
672 | if (nand_wait_cmddone()) | ||
673 | { | ||
674 | rc |= 1 << i; | ||
675 | continue; | ||
676 | } | ||
677 | if (nand_send_cmd(NAND_CMD_ERASECNFRM)) rc |= 1 << i; | ||
678 | } | ||
679 | for (i = 0; i < 4; i++) | ||
680 | { | ||
681 | if (nand_type[i] == 0xFFFFFFFF) continue; | ||
682 | if (rc & (1 << i)) continue; | ||
683 | if (nand_wait_status_ready(i)) rc |= 1 << i; | ||
684 | } | ||
685 | return nand_unlock(rc); | ||
686 | } | ||
687 | |||
490 | const struct nand_device_info_type* nand_get_device_type(uint32_t bank) | 688 | const struct nand_device_info_type* nand_get_device_type(uint32_t bank) |
491 | { | 689 | { |
492 | if (nand_type[bank] == 0xFFFFFFFF) | 690 | if (nand_type[bank] == 0xFFFFFFFF) |
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/nand-target.h b/firmware/target/arm/s5l8700/ipodnano2g/nand-target.h index dee690e5e6..000373fff1 100644 --- a/firmware/target/arm/s5l8700/ipodnano2g/nand-target.h +++ b/firmware/target/arm/s5l8700/ipodnano2g/nand-target.h | |||
@@ -46,6 +46,13 @@ uint32_t nand_write_page(uint32_t bank, uint32_t page, void* databuffer, | |||
46 | void* sparebuffer, uint32_t doecc); | 46 | void* sparebuffer, uint32_t doecc); |
47 | uint32_t nand_block_erase(uint32_t bank, uint32_t page); | 47 | uint32_t nand_block_erase(uint32_t bank, uint32_t page); |
48 | 48 | ||
49 | uint32_t nand_read_page_fast(uint32_t page, void* databuffer, | ||
50 | void* sparebuffer, uint32_t doecc, | ||
51 | uint32_t checkempty); | ||
52 | uint32_t nand_write_page_fast(uint32_t page, void* databuffer, | ||
53 | void* sparebuffer, uint32_t doecc); | ||
54 | uint32_t nand_block_erase_fast(uint32_t page); | ||
55 | |||
49 | const struct nand_device_info_type* nand_get_device_type(uint32_t bank); | 56 | const struct nand_device_info_type* nand_get_device_type(uint32_t bank); |
50 | uint32_t nand_reset(uint32_t bank); | 57 | uint32_t nand_reset(uint32_t bank); |
51 | uint32_t nand_device_init(void); | 58 | uint32_t nand_device_init(void); |