| Index: embios/trunk/target/ipodnano2g/ftl.c | 
| — | — | @@ -29,6 +29,9 @@ | 
| 30 | 30 | #include "thread.h" | 
| 31 | 31 | #include "panic.h" | 
| 32 | 32 | #include "debug.h" | 
|  | 33 | +#include "console.h" | 
|  | 34 | +#include "progressbar.h" | 
|  | 35 | +#include "lcdconsole.h" | 
| 33 | 36 |  | 
| 34 | 37 |  | 
| 35 | 38 |  | 
| — | — | @@ -362,13 +365,13 @@ | 
| 363 | 366 | uint32_t ftl_banks; | 
| 364 | 367 |  | 
| 365 | 368 | /* Block map, used vor pBlock to vBlock mapping */ | 
| 366 |  | -static uint16_t ftl_map[0x2000];
 | 
|  | 369 | +static uint16_t ftl_map[0x2000] CACHEALIGN_ATTR; | 
| 367 | 370 |  | 
| 368 | 371 | /* VFL context for each bank */ | 
| 369 | 372 | static struct ftl_vfl_cxt_type ftl_vfl_cxt[4]; | 
| 370 | 373 |  | 
| 371 | 374 | /* FTL context */ | 
| 372 |  | -static struct ftl_cxt_type ftl_cxt;
 | 
|  | 375 | +static struct ftl_cxt_type ftl_cxt CACHEALIGN_ATTR; | 
| 373 | 376 |  | 
| 374 | 377 | /* Temporary data buffers for internal use by the FTL */ | 
| 375 | 378 | static uint8_t ftl_buffer[0x800] CACHEALIGN_ATTR; | 
| — | — | @@ -383,7 +386,7 @@ | 
| 384 | 387 | static uint8_t ftl_bbt[4][0x410]; | 
| 385 | 388 |  | 
| 386 | 389 | /* Erase counters for the vBlocks */ | 
| 387 |  | -static uint16_t ftl_erasectr[0x2000];
 | 
|  | 390 | +static uint16_t ftl_erasectr[0x2000] CACHEALIGN_ATTR; | 
| 388 | 391 |  | 
| 389 | 392 | /* Used by ftl_log */ | 
| 390 | 393 | static uint16_t ftl_offsets[0x11][0x200]; | 
| — | — | @@ -411,6 +414,19 @@ | 
| 412 | 415 | back if something fails while compacting a scattered page block. */ | 
| 413 | 416 | static uint16_t ftl_offsets_backup[0x200] CACHEALIGN_ATTR; | 
| 414 | 417 |  | 
|  | 418 | +/* Buffers needed for FTL recovery */ | 
|  | 419 | +static uint32_t blk_usn[0x2000] INITBSS_ATTR; | 
|  | 420 | +static uint8_t blk_type[0x2000] INITBSS_ATTR; | 
|  | 421 | +static uint32_t erasectr_usn[8] INITBSS_ATTR; | 
|  | 422 | +static uint32_t pageusn[0x200] INITBSS_ATTR; | 
|  | 423 | +static uint8_t pagedata[0x200][0x800] INITBSS_ATTR CACHEALIGN_ATTR; | 
|  | 424 | + | 
|  | 425 | +/* State information needed for FTL recovery */ | 
|  | 426 | +static uint32_t meta_usn INITBSS_ATTR; | 
|  | 427 | +static uint32_t user_usn INITBSS_ATTR; | 
|  | 428 | +static uint32_t allocmode INITBSS_ATTR; | 
|  | 429 | +static uint32_t firstfree INITBSS_ATTR; | 
|  | 430 | + | 
| 415 | 431 | #endif | 
| 416 | 432 |  | 
| 417 | 433 |  | 
| — | — | @@ -420,6 +436,7 @@ | 
| 421 | 437 |  | 
| 422 | 438 | /* Finds a device info page for the specified bank and returns its number. | 
| 423 | 439 | Used to check if one is present, and to read the lowlevel BBT. */ | 
|  | 440 | +static uint32_t ftl_find_devinfo(uint32_t bank) INITCODE_ATTR; | 
| 424 | 441 | static uint32_t ftl_find_devinfo(uint32_t bank) | 
| 425 | 442 | { | 
| 426 | 443 | /* Scan the last 10% of the flash for device info pages */ | 
| — | — | @@ -444,6 +461,7 @@ | 
| 445 | 462 |  | 
| 446 | 463 |  | 
| 447 | 464 | /* Checks if all banks have proper device info pages */ | 
|  | 465 | +static uint32_t ftl_has_devinfo(void) INITCODE_ATTR; | 
| 448 | 466 | static uint32_t ftl_has_devinfo(void) | 
| 449 | 467 | { | 
| 450 | 468 | uint32_t i; | 
| — | — | @@ -454,6 +472,7 @@ | 
| 455 | 473 |  | 
| 456 | 474 | /* Loads the lowlevel BBT for a bank to the specified buffer. | 
| 457 | 475 | This is based on some cryptic disassembly and not fully understood yet. */ | 
|  | 476 | +static uint32_t ftl_load_bbt(uint32_t bank, uint8_t* bbt) INITCODE_ATTR; | 
| 458 | 477 | static uint32_t ftl_load_bbt(uint32_t bank, uint8_t* bbt) | 
| 459 | 478 | { | 
| 460 | 479 | uint32_t i, j; | 
| — | — | @@ -604,6 +623,7 @@ | 
| 605 | 624 | /* Returns a pointer to the most recently updated VFL context, | 
| 606 | 625 | used to find out the current FTL context vBlock numbers | 
| 607 | 626 | (planetbeing's "maxthing") */ | 
|  | 627 | +static struct ftl_vfl_cxt_type* ftl_vfl_get_newest_cxt(void) INITCODE_ATTR; | 
| 608 | 628 | static struct ftl_vfl_cxt_type* ftl_vfl_get_newest_cxt(void) | 
| 609 | 629 | { | 
| 610 | 630 | uint32_t i, maxusn; | 
| — | — | @@ -621,6 +641,7 @@ | 
| 622 | 642 |  | 
| 623 | 643 | /* Checks if the specified pBlock is marked bad in the supplied lowlevel BBT. | 
| 624 | 644 | Only used while mounting the VFL. */ | 
|  | 645 | +static uint32_t ftl_is_good_block(uint8_t* bbt, uint32_t block) INITCODE_ATTR; | 
| 625 | 646 | static uint32_t ftl_is_good_block(uint8_t* bbt, uint32_t block) | 
| 626 | 647 | { | 
| 627 | 648 | if ((bbt[block >> 3] & (1 << (block & 7))) == 0) return 0; | 
| — | — | @@ -652,6 +673,9 @@ | 
| 653 | 674 | /* Tries to read a VFL context from the specified bank, pBlock and page */ | 
| 654 | 675 | static uint32_t ftl_vfl_read_page(uint32_t bank, uint32_t block, | 
| 655 | 676 | uint32_t startpage, void* databuffer, | 
|  | 677 | +                                  union ftl_spare_data_type* sparebuffer) INITCODE_ATTR; | 
|  | 678 | +static uint32_t ftl_vfl_read_page(uint32_t bank, uint32_t block, | 
|  | 679 | +                                  uint32_t startpage, void* databuffer, | 
| 656 | 680 | union ftl_spare_data_type* sparebuffer) | 
| 657 | 681 | { | 
| 658 | 682 | uint32_t i; | 
| — | — | @@ -1019,7 +1043,8 @@ | 
| 1020 | 1044 |  | 
| 1021 | 1045 |  | 
| 1022 | 1046 | /* Mounts the VFL on all banks */ | 
| 1023 |  | -static uint32_t ftl_vfl_open(void)
 | 
|  | 1047 | +static uint32_t ftl_vfl_open(void) INITCODE_ATTR; | 
|  | 1048 | +static uint32_t ftl_vfl_open() | 
| 1024 | 1049 | { | 
| 1025 | 1050 | uint32_t i, j, k; | 
| 1026 | 1051 | uint32_t minusn, vflcxtidx, last; | 
| — | — | @@ -1112,7 +1137,8 @@ | 
| 1113 | 1138 |  | 
| 1114 | 1139 |  | 
| 1115 | 1140 | /* Mounts the actual FTL */ | 
| 1116 |  | -static uint32_t ftl_open(void)
 | 
|  | 1141 | +static uint32_t ftl_open(void) INITCODE_ATTR; | 
|  | 1142 | +static uint32_t ftl_open() | 
| 1117 | 1143 | { | 
| 1118 | 1144 | uint32_t i; | 
| 1119 | 1145 | uint32_t ret; | 
| — | — | @@ -1227,7 +1253,7 @@ | 
| 1228 | 1254 | { | 
| 1229 | 1255 | uint32_t badblocks = 0; | 
| 1230 | 1256 | #ifndef FTL_READONLY | 
| 1231 |  | -        for (j = 0; j < (*ftl_nand_type).blocks >> 3; j++)
 | 
|  | 1257 | +        for (j = 0; j < ftl_nand_type->blocks >> 3; j++) | 
| 1232 | 1258 | { | 
| 1233 | 1259 | uint8_t bbtentry = ftl_bbt[i][j]; | 
| 1234 | 1260 | for (k = 0; k < 8; k++) if ((bbtentry & (1 << k)) == 0) badblocks++; | 
| — | — | @@ -1246,7 +1272,7 @@ | 
| 1247 | 1273 | } | 
| 1248 | 1274 | #ifndef FTL_READONLY | 
| 1249 | 1275 | uint32_t min = 0xFFFFFFFF, max = 0, total = 0; | 
| 1250 |  | -    for (i = 0; i < (*ftl_nand_type).userblocks + 23; i++)
 | 
|  | 1276 | +    for (i = 0; i < ftl_nand_type->userblocks + 23; i++) | 
| 1251 | 1277 | { | 
| 1252 | 1278 | if (ftl_erasectr[i] > max) max = ftl_erasectr[i]; | 
| 1253 | 1279 | if (ftl_erasectr[i] < min) min = ftl_erasectr[i]; | 
| — | — | @@ -1253,7 +1279,7 @@ | 
| 1254 | 1280 | total += ftl_erasectr[i]; | 
| 1255 | 1281 | } | 
| 1256 | 1282 | DEBUGF("FTL: Erase counters: Minimum: %d, maximum %d, average: %d, total: %d", | 
| 1257 |  | -           min, max, total / ((*ftl_nand_type).userblocks + 23), total);
 | 
|  | 1283 | +           min, max, total / (ftl_nand_type->userblocks + 23), total); | 
| 1258 | 1284 | #endif | 
| 1259 | 1285 | #endif | 
| 1260 | 1286 |  | 
| — | — | @@ -2167,10 +2193,313 @@ | 
| 2168 | 2194 | #endif | 
| 2169 | 2195 |  | 
| 2170 | 2196 |  | 
|  | 2197 | +/* Block allocator for FTL recovery */ | 
|  | 2198 | +static uint32_t ftl_alloc_block() INITCODE_ATTR; | 
|  | 2199 | +static uint32_t ftl_alloc_block() | 
|  | 2200 | +{ | 
|  | 2201 | +    while (1) | 
|  | 2202 | +    { | 
|  | 2203 | +        for (; firstfree < ftl_nand_type->userblocks + 0x17; firstfree++) | 
|  | 2204 | +            if (!blk_type[firstfree]) break; | 
|  | 2205 | +            else if (allocmode && blk_type[firstfree] != 1) | 
|  | 2206 | +            { | 
|  | 2207 | +                if (ftl_erase_block(firstfree)) | 
|  | 2208 | +                { | 
|  | 2209 | +                    cprintf(CONSOLE_BOOT, "Couldn't erase vBlock %d (pool alloc)!\n", firstfree); | 
|  | 2210 | +                    return 1; | 
|  | 2211 | +                } | 
|  | 2212 | +                break; | 
|  | 2213 | +            } | 
|  | 2214 | +        if (firstfree < ftl_nand_type->userblocks + 0x17) | 
|  | 2215 | +        { | 
|  | 2216 | +            blk_type[firstfree] = 1; | 
|  | 2217 | +            return firstfree++; | 
|  | 2218 | +        } | 
|  | 2219 | +        if (!allocmode) | 
|  | 2220 | +        { | 
|  | 2221 | +            allocmode = 1; | 
|  | 2222 | +            firstfree = 0; | 
|  | 2223 | +        } | 
|  | 2224 | +        else | 
|  | 2225 | +        { | 
|  | 2226 | +            cputs(CONSOLE_BOOT, "Out of empty blocks!\n"); | 
|  | 2227 | +            return 1; | 
|  | 2228 | +        } | 
|  | 2229 | +    } | 
|  | 2230 | +} | 
|  | 2231 | + | 
|  | 2232 | + | 
|  | 2233 | +static uint32_t ftl_repair(void) INITCODE_ATTR; | 
|  | 2234 | +static uint32_t ftl_repair() | 
|  | 2235 | +{ | 
|  | 2236 | +    uint32_t i, j, k; | 
|  | 2237 | +#ifdef HAVE_LCD | 
|  | 2238 | +    struct progressbar_state progressbar; | 
|  | 2239 | +#endif | 
|  | 2240 | + | 
|  | 2241 | +    cputs(CONSOLE_BOOT, "Scanning flash...\n"); | 
|  | 2242 | +#ifdef HAVE_LCD | 
|  | 2243 | +    lcdconsole_progressbar(&progressbar, 0, ftl_nand_type->userblocks + 0x17); | 
|  | 2244 | +#endif | 
|  | 2245 | +    uint32_t ppb = ftl_nand_type->pagesperblock * ftl_banks; | 
|  | 2246 | +    memset(&ftl_cxt, 0x00, 0x800); | 
|  | 2247 | +    memset(ftl_map, 0xff, 0x4000); | 
|  | 2248 | +    memset(blk_usn, 0x00, 0x8000); | 
|  | 2249 | +    memset(blk_type, 0x00, 0x2000); | 
|  | 2250 | +    memset(ftl_erasectr, 0x00, 0x4000); | 
|  | 2251 | +    memset(erasectr_usn, 0xff, 32); | 
|  | 2252 | +    user_usn = 0; | 
|  | 2253 | +    meta_usn = 0xffffffff; | 
|  | 2254 | +    for (i = 0; i < ftl_nand_type->userblocks + 0x17; i++) | 
|  | 2255 | +    { | 
|  | 2256 | +        uint32_t ret = ftl_vfl_read((i + 1) * ppb - 1, 0, &ftl_sparebuffer[0], 1, 0); | 
|  | 2257 | +        if ((ret & 0x11F) == 0 && ftl_sparebuffer[0].meta.type == 0x41) | 
|  | 2258 | +        { | 
|  | 2259 | +            uint32_t lbn = ftl_sparebuffer[0].user.lpn / ppb; | 
|  | 2260 | +            if (ftl_sparebuffer[0].user.usn > user_usn) | 
|  | 2261 | +                user_usn = ftl_sparebuffer[0].user.usn; | 
|  | 2262 | +            if (ftl_sparebuffer[0].user.usn > blk_usn[lbn]) | 
|  | 2263 | +            { | 
|  | 2264 | +                if (ftl_map[lbn] != 0xffff) | 
|  | 2265 | +                    blk_type[ftl_map[lbn]] = 5; | 
|  | 2266 | +                blk_usn[lbn] = ftl_sparebuffer[0].user.usn; | 
|  | 2267 | +                ftl_map[lbn] = i; | 
|  | 2268 | +                blk_type[i] = 1; | 
|  | 2269 | +            } | 
|  | 2270 | +            else blk_type[i] = 5; | 
|  | 2271 | +        } | 
|  | 2272 | +        else | 
|  | 2273 | +            for (j = 0; j < ppb; j++) | 
|  | 2274 | +            { | 
|  | 2275 | +                ret = ftl_vfl_read(i * ppb + j, 0, &ftl_sparebuffer[0], 1, 0); | 
|  | 2276 | +                if (ret & 2) break; | 
|  | 2277 | +                if (ret & 0x11F) | 
|  | 2278 | +                { | 
|  | 2279 | +                    blk_type[i] = 4; | 
|  | 2280 | +                    continue; | 
|  | 2281 | +                } | 
|  | 2282 | +                if (ftl_sparebuffer[0].meta.type == 0x40) | 
|  | 2283 | +                { | 
|  | 2284 | +                    blk_type[i] = 2; | 
|  | 2285 | +                    break; | 
|  | 2286 | +                } | 
|  | 2287 | +                else if (ftl_sparebuffer[0].meta.type - 0x43 <= 4) | 
|  | 2288 | +                { | 
|  | 2289 | +                    blk_type[i] = 3; | 
|  | 2290 | +                    if (ftl_sparebuffer[0].meta.type == 0x46) | 
|  | 2291 | +                    { | 
|  | 2292 | +                        uint32_t idx = ftl_sparebuffer[0].meta.idx; | 
|  | 2293 | +                        if (ftl_sparebuffer[0].meta.usn < meta_usn) | 
|  | 2294 | +                            meta_usn = ftl_sparebuffer[0].meta.usn; | 
|  | 2295 | +                        if (ftl_sparebuffer[0].meta.usn < erasectr_usn[idx]) | 
|  | 2296 | +                        { | 
|  | 2297 | +                            erasectr_usn[idx] = ftl_sparebuffer[0].meta.usn; | 
|  | 2298 | +                            ret = ftl_vfl_read(i * ppb + j, &ftl_erasectr[idx << 10], | 
|  | 2299 | +                                               &ftl_sparebuffer[0], 1, 0); | 
|  | 2300 | +                            if (ret & 0x11f) memset(&ftl_erasectr[idx << 10], 0, 0x800); | 
|  | 2301 | +                        } | 
|  | 2302 | +                    } | 
|  | 2303 | +                } | 
|  | 2304 | +                else | 
|  | 2305 | +                { | 
|  | 2306 | +                    cprintf(CONSOLE_BOOT, "Invalid block type %02X while reading vPage %d\n", | 
|  | 2307 | +                            ftl_sparebuffer[0].meta.type, i * ppb + j); | 
|  | 2308 | +                    return 1; | 
|  | 2309 | +                } | 
|  | 2310 | +            } | 
|  | 2311 | +#ifdef HAVE_LCD | 
|  | 2312 | +        progressbar_setpos(&progressbar, i + 1, false); | 
|  | 2313 | +#endif | 
|  | 2314 | +    } | 
|  | 2315 | + | 
|  | 2316 | +    uint32_t sum = 0; | 
|  | 2317 | +    uint32_t count = 0; | 
|  | 2318 | +    for (i = 0; i < 0x2000; i++) | 
|  | 2319 | +        if (ftl_erasectr[i]) | 
|  | 2320 | +        { | 
|  | 2321 | +            sum += ftl_erasectr[i]; | 
|  | 2322 | +            count++; | 
|  | 2323 | +        } | 
|  | 2324 | +    uint32_t average = sum / count; | 
|  | 2325 | +    for (i = 0; i < 0x2000; i++) | 
|  | 2326 | +        if (!ftl_erasectr[i]) | 
|  | 2327 | +            ftl_erasectr[i] = average; | 
|  | 2328 | + | 
|  | 2329 | +    cputs(CONSOLE_BOOT, "Committing scattered pages...\n"); | 
|  | 2330 | +    count = 0; | 
|  | 2331 | +    for (i = 0; i < ftl_nand_type->userblocks + 0x17; i++) | 
|  | 2332 | +        if (blk_type[i] == 2) count++; | 
|  | 2333 | +    uint32_t block; | 
|  | 2334 | +    uint32_t dirty; | 
|  | 2335 | +    if (count) | 
|  | 2336 | +    { | 
|  | 2337 | +#ifdef HAVE_LCD | 
|  | 2338 | +        lcdconsole_progressbar(&progressbar, 0, count * ppb); | 
|  | 2339 | +#endif | 
|  | 2340 | +        count = 0; | 
|  | 2341 | +        for (i = 0; i < ftl_nand_type->userblocks + 0x17; i++) | 
|  | 2342 | +            if (blk_type[i] == 2) | 
|  | 2343 | +            { | 
|  | 2344 | +                block = 0xffff; | 
|  | 2345 | +                for (j = 0; j < ftl_nand_type->pagesperblock * ftl_banks; j++) | 
|  | 2346 | +                { | 
|  | 2347 | +                    uint32_t ret = ftl_vfl_read(i * ppb + j, ftl_buffer, | 
|  | 2348 | +                                                &ftl_sparebuffer[0], 1, 0); | 
|  | 2349 | +                    if (ret & 0x11F) continue; | 
|  | 2350 | +                    if (ftl_sparebuffer[0].user.type != 0x40) | 
|  | 2351 | +                    { | 
|  | 2352 | +                        cprintf(CONSOLE_BOOT, "Invalid block type %02X while reading " | 
|  | 2353 | +                                              "vPage %d (scattered page)!\n", | 
|  | 2354 | +                                ftl_sparebuffer[0].meta.type, i * ppb + j); | 
|  | 2355 | +                        return 1; | 
|  | 2356 | +                    } | 
|  | 2357 | +                    if (block == 0xffff) | 
|  | 2358 | +                    { | 
|  | 2359 | +                        block = ftl_sparebuffer[0].user.lpn / ppb; | 
|  | 2360 | +                        memset(pageusn, 0x00, 0x800); | 
|  | 2361 | +                        memset(pagedata, 0x00, 0x100000); | 
|  | 2362 | +                        if (ftl_map[block] != 0xffff) | 
|  | 2363 | +                            for (k = 0; k < ppb; k++) | 
|  | 2364 | +                            { | 
|  | 2365 | +                                uint32_t ret = ftl_vfl_read(ftl_map[block] * ppb + k, pagedata[k], | 
|  | 2366 | +                                                            &ftl_copyspare[0], 1, 0); | 
|  | 2367 | +                                if (ret & 0x11F) continue; | 
|  | 2368 | +                                if (ftl_copyspare[0].user.type != 0x40 | 
|  | 2369 | +                                 && ftl_copyspare[0].user.type != 0x41) | 
|  | 2370 | +                                { | 
|  | 2371 | +                                    cprintf(CONSOLE_BOOT, "Invalid block type %02X while reading " | 
|  | 2372 | +                                                          "vPage %d (scattered page orig)!\n", | 
|  | 2373 | +                                            ftl_sparebuffer[0].meta.type, | 
|  | 2374 | +                                            ftl_map[block] * ppb + k); | 
|  | 2375 | +                                    return 1; | 
|  | 2376 | +                                } | 
|  | 2377 | +                                if (block != ftl_copyspare[0].user.lpn / ppb) | 
|  | 2378 | +                                { | 
|  | 2379 | +                                    cprintf(CONSOLE_BOOT, "Foreign page in scattered page orig " | 
|  | 2380 | +                                                          "block (vPage %d, LPN %d)!\n", | 
|  | 2381 | +                                            ftl_map[block] * ppb + k, | 
|  | 2382 | +                                            ftl_sparebuffer[0].user.usn); | 
|  | 2383 | +                                    return 1; | 
|  | 2384 | +                                } | 
|  | 2385 | +                                pageusn[k] = ftl_copyspare[0].user.usn; | 
|  | 2386 | +                            } | 
|  | 2387 | +                        dirty = 0; | 
|  | 2388 | +                    } | 
|  | 2389 | +                    if (block != ftl_sparebuffer[0].user.lpn / ppb) | 
|  | 2390 | +                    { | 
|  | 2391 | +                        cprintf(CONSOLE_BOOT, "Foreign page in scattered page block " | 
|  | 2392 | +                                              "block (vPage %d, LPN %d)!\n", | 
|  | 2393 | +                                i * ppb + j, ftl_sparebuffer[0].user.lpn); | 
|  | 2394 | +                        return 1; | 
|  | 2395 | +                    } | 
|  | 2396 | +                    uint32_t idx = ftl_sparebuffer[0].user.lpn % ppb; | 
|  | 2397 | +                    if (ftl_sparebuffer[0].user.usn > user_usn) | 
|  | 2398 | +                        user_usn = ftl_sparebuffer[0].user.usn; | 
|  | 2399 | +                    if (ftl_sparebuffer[0].user.usn > pageusn[idx]) | 
|  | 2400 | +                    { | 
|  | 2401 | +                        pageusn[idx] = ftl_sparebuffer[0].user.usn; | 
|  | 2402 | +                        memcpy(pagedata[idx], ftl_buffer, 0x800); | 
|  | 2403 | +                        dirty = 1; | 
|  | 2404 | +                    } | 
|  | 2405 | +                } | 
|  | 2406 | +                if (dirty) | 
|  | 2407 | +                { | 
|  | 2408 | +                    if (ftl_erase_block(i)) | 
|  | 2409 | +                    { | 
|  | 2410 | +                        cprintf(CONSOLE_BOOT, "Couldn't erase vBlock %d " | 
|  | 2411 | +                                              "(scattered page commit)!\n", i); | 
|  | 2412 | +                        return 1; | 
|  | 2413 | +                    } | 
|  | 2414 | +                    for (j = 0; j < ppb; j++) | 
|  | 2415 | +                    { | 
|  | 2416 | +                        memset(&ftl_sparebuffer[0], 0xFF, 0x40); | 
|  | 2417 | +                        ftl_sparebuffer[0].user.lpn = block * ppb + j; | 
|  | 2418 | +                        ftl_sparebuffer[0].user.usn = pageusn[j]; | 
|  | 2419 | +                        ftl_sparebuffer[0].user.type = 0x40; | 
|  | 2420 | +                        if (j == ppb - 1) ftl_sparebuffer[0].user.type = 0x41; | 
|  | 2421 | +                        if (ftl_vfl_write(i * ppb + j, 1, pagedata[j], &ftl_sparebuffer[0])) | 
|  | 2422 | +                        { | 
|  | 2423 | +                            cprintf(CONSOLE_BOOT, "Couldn't write vPage %d " | 
|  | 2424 | +                                                  "(scattered page commit)!\n", i * ppb + j); | 
|  | 2425 | +                            return 1; | 
|  | 2426 | +                        } | 
|  | 2427 | +#ifdef HAVE_LCD | 
|  | 2428 | +                        progressbar_setpos(&progressbar, count * ppb + j, false); | 
|  | 2429 | +#endif | 
|  | 2430 | +                    } | 
|  | 2431 | +                    if (ftl_map[block] != 0xffff) blk_type[ftl_map[block]] = 5; | 
|  | 2432 | +                    blk_type[i] = 1; | 
|  | 2433 | +                    ftl_map[block] = i; | 
|  | 2434 | +                } | 
|  | 2435 | +                else blk_type[i] = 5; | 
|  | 2436 | +#ifdef HAVE_LCD | 
|  | 2437 | +                progressbar_setpos(&progressbar, ++count * ppb, false); | 
|  | 2438 | +#endif | 
|  | 2439 | +            } | 
|  | 2440 | +    } | 
|  | 2441 | + | 
|  | 2442 | +    cputs(CONSOLE_BOOT, "Fixing block map...\n"); | 
|  | 2443 | +    allocmode = 0; | 
|  | 2444 | +    firstfree = 0; | 
|  | 2445 | +    for (i = 0; i < 3; i++) ftl_cxt.ftlctrlblocks[i] = ftl_alloc_block(); | 
|  | 2446 | +    for (i = 0; i < 20; i++) ftl_cxt.blockpool[i] = ftl_alloc_block(); | 
|  | 2447 | +    for (i = 0; i < ftl_nand_type->userblocks; i++) | 
|  | 2448 | +        if (ftl_map[i] == 0xffff) | 
|  | 2449 | +            ftl_map[i] = ftl_alloc_block(); | 
|  | 2450 | +    ftl_cxt.usn = meta_usn - 1; | 
|  | 2451 | +    ftl_cxt.nextblockusn = user_usn + 1; | 
|  | 2452 | +    ftl_cxt.freecount = 20; | 
|  | 2453 | +    ftl_cxt.clean_flag = 1; | 
|  | 2454 | + | 
|  | 2455 | +    cputs(CONSOLE_BOOT, "Committing FTL context...\n"); | 
|  | 2456 | +    uint32_t blockmappages = ftl_nand_type->userblocks >> 10; | 
|  | 2457 | +    if ((ftl_nand_type->userblocks & 0x1FF) != 0) blockmappages++; | 
|  | 2458 | +    uint32_t erasectrpages = (ftl_nand_type->userblocks + 23) >> 10; | 
|  | 2459 | +    if (((ftl_nand_type->userblocks + 23) & 0x1FF) != 0) erasectrpages++; | 
|  | 2460 | +    uint32_t page = ftl_cxt.ftlctrlblocks[0] * ppb; | 
|  | 2461 | +    for (i = 0; i < erasectrpages; i++) | 
|  | 2462 | +    { | 
|  | 2463 | +        memset(&ftl_sparebuffer, 0xFF, 0x40); | 
|  | 2464 | +        ftl_sparebuffer[0].meta.usn = ftl_cxt.usn; | 
|  | 2465 | +        ftl_sparebuffer[0].meta.idx = i; | 
|  | 2466 | +        ftl_sparebuffer[0].meta.type = 0x46; | 
|  | 2467 | +        if (ftl_vfl_write(page, 1, &ftl_erasectr[i << 10], &ftl_sparebuffer[0])) | 
|  | 2468 | +        { | 
|  | 2469 | +            cprintf(CONSOLE_BOOT, "Couldn't write vPage %d (save erase counters)!\n", page); | 
|  | 2470 | +            return 1; | 
|  | 2471 | +        } | 
|  | 2472 | +        ftl_cxt.ftl_erasectr_pages[i] = page++; | 
|  | 2473 | +    } | 
|  | 2474 | +    for (i = 0; i < blockmappages; i++) | 
|  | 2475 | +    { | 
|  | 2476 | +        memset(&ftl_sparebuffer[0], 0xFF, 0x40); | 
|  | 2477 | +        ftl_sparebuffer[0].meta.usn = ftl_cxt.usn; | 
|  | 2478 | +        ftl_sparebuffer[0].meta.idx = i; | 
|  | 2479 | +        ftl_sparebuffer[0].meta.type = 0x44; | 
|  | 2480 | +        if (ftl_vfl_write(page, 1, &ftl_map[i << 10], &ftl_sparebuffer[0])) | 
|  | 2481 | +        { | 
|  | 2482 | +            cprintf(CONSOLE_BOOT, "Couldn't write vPage %d (save block map)!\n", page); | 
|  | 2483 | +            return 1; | 
|  | 2484 | +        } | 
|  | 2485 | +        ftl_cxt.ftl_map_pages[i] = page++; | 
|  | 2486 | +    } | 
|  | 2487 | +    ftl_cxt.ftlctrlpage = page; | 
|  | 2488 | +    memset(&ftl_sparebuffer[0], 0xFF, 0x40); | 
|  | 2489 | +    ftl_sparebuffer[0].meta.usn = ftl_cxt.usn; | 
|  | 2490 | +    ftl_sparebuffer[0].meta.type = 0x43; | 
|  | 2491 | +    if (ftl_vfl_write(page, 1, &ftl_cxt, &ftl_sparebuffer[0])) | 
|  | 2492 | +    { | 
|  | 2493 | +        cprintf(CONSOLE_BOOT, "Couldn't write vPage %d (save FTL context)!\n", page); | 
|  | 2494 | +        return 1; | 
|  | 2495 | +    } | 
|  | 2496 | +    ftl_store_ctrl_block_list(); | 
|  | 2497 | +} | 
|  | 2498 | + | 
|  | 2499 | + | 
| 2171 | 2500 | /* Initializes and mounts the FTL. | 
| 2172 | 2501 | As long as nothing was written, you won't need to unmount it. | 
| 2173 | 2502 | Before shutting down after writing something, call ftl_sync(), | 
| 2174 |  | -   which will just do nothing if everything was already clean. */
 | 
|  | 2503 | +   which will return immediately if everything was already clean. */ | 
| 2175 | 2504 | uint32_t ftl_init(void) | 
| 2176 | 2505 | { | 
| 2177 | 2506 | mutex_init(&ftl_mtx); | 
| — | — | @@ -2214,8 +2543,20 @@ | 
| 2215 | 2544 | return 1; | 
| 2216 | 2545 | } | 
| 2217 | 2546 | if (ftl_vfl_open() == 0) | 
|  | 2547 | +	{ | 
| 2218 | 2548 | if (ftl_open() == 0) | 
| 2219 | 2549 | return 0; | 
|  | 2550 | +		cprintf(CONSOLE_BOOT, "The FTL seems to be damaged. Forcing check.\n"); | 
|  | 2551 | +		if (ftl_repair() != 0) | 
|  | 2552 | +			cprintf(CONSOLE_BOOT, "FTL recovery failed. Use disk mode to recover.\n"); | 
|  | 2553 | +		else | 
|  | 2554 | +		{ | 
|  | 2555 | +			cprintf(CONSOLE_BOOT, "FTL recovery finished. Trying to mount again...\n"); | 
|  | 2556 | +	        if (ftl_open() == 0) | 
|  | 2557 | +	            return 0; | 
|  | 2558 | +			cprintf(CONSOLE_BOOT, "Mounting FTL failed again, use disk mode to recover.\n"); | 
|  | 2559 | +		} | 
|  | 2560 | +	} | 
| 2220 | 2561 |  | 
| 2221 | 2562 | DEBUGF("FTL: Initialization failed!"); | 
| 2222 | 2563 |  | 
| Index: embios/trunk/target/ipodnano2g/ftl.h | 
| — | — | @@ -31,7 +31,7 @@ | 
| 32 | 32 | extern uint32_t ftl_banks; | 
| 33 | 33 |  | 
| 34 | 34 |  | 
| 35 |  | -uint32_t ftl_init(void);
 | 
|  | 35 | +uint32_t ftl_init(void) INITCODE_ATTR; | 
| 36 | 36 | uint32_t ftl_read(uint32_t sector, uint32_t count, void* buffer); | 
| 37 | 37 | uint32_t ftl_write(uint32_t sector, uint32_t count, const void* buffer); | 
| 38 | 38 | uint32_t ftl_sync(void); | 
| Index: embios/trunk/progressbar.c | 
| — | — | @@ -26,10 +26,10 @@ | 
| 27 | 27 | #include "lcd.h" | 
| 28 | 28 |  | 
| 29 | 29 |  | 
| 30 |  | -static void progressbar_drawborderbg(struct progressbar_state* state)
 | 
|  | 30 | +static void progressbar_drawborderbg(struct progressbar_state* state, int bgstart) | 
| 31 | 31 | { | 
| 32 | 32 | state->currentx = state->startx; | 
| 33 |  | -    displaylcd(state->startx + 1, state->endx - 1, state->starty + 1, state->endy - 1,
 | 
|  | 33 | +    displaylcd(bgstart + 1, state->endx - 1, state->starty + 1, state->endy - 1, | 
| 34 | 34 | (void*)-1, state->bgcolor); | 
| 35 | 35 | displaylcd(state->startx, state->endx, state->starty, state->starty, | 
| 36 | 36 | (void*)-1, state->bordercolor); | 
| — | — | @@ -53,7 +53,7 @@ | 
| 54 | 54 | state->fgcolor = fgcolor; | 
| 55 | 55 | state->min = min; | 
| 56 | 56 | state->max = max; | 
| 57 |  | -    progressbar_drawborderbg(state);
 | 
|  | 57 | +    progressbar_drawborderbg(state, state->startx); | 
| 58 | 58 | } | 
| 59 | 59 |  | 
| 60 | 60 | void progressbar_setpos(struct progressbar_state* state, int value, bool redraw) | 
| — | — | @@ -62,7 +62,7 @@ | 
| 63 | 63 | if (value < state->min) value = state->min; | 
| 64 | 64 | int newx = (value - state->min) * (state->endx - state->startx - 1) | 
| 65 | 65 | / (state->max - state->min) + state->startx; | 
| 66 |  | -    if (redraw || newx < state->currentx) progressbar_drawborderbg(state);
 | 
|  | 66 | +    if (redraw || newx < state->currentx) progressbar_drawborderbg(state, newx); | 
| 67 | 67 | if (newx > state->currentx) | 
| 68 | 68 | displaylcd(state->currentx + 1, newx, state->starty + 1, state->endy - 1, | 
| 69 | 69 | (void*)-1, state->fgcolor); | 
| Index: embios/trunk/export/syscallwrappers.h | 
| — | — | @@ -75,6 +75,7 @@ | 
| 76 | 76 | #define lcdconsole_get_current_y(args...) __embios_syscall->lcdconsole_get_current_y(args) | 
| 77 | 77 | #define lcdconsole_get_lineend_x(args...) __embios_syscall->lcdconsole_get_lineend_x(args) | 
| 78 | 78 | #define lcdconsole_get_lineend_y(args...) __embios_syscall->lcdconsole_get_lineend_y(args) | 
|  | 79 | +#define lcdconsole_progressbar(args...) __embios_syscall->lcdconsole_progressbar(args) | 
| 79 | 80 | #define progressbar_init(args...) __embios_syscall->progressbar_init(args) | 
| 80 | 81 | #define progressbar_setpos(args...) __embios_syscall->progressbar_setpos(args) | 
| 81 | 82 | #define shutdown(args...) __embios_syscall->shutdown(args) | 
| Index: embios/trunk/export/syscallapi.h | 
| — | — | @@ -112,6 +112,7 @@ | 
| 113 | 113 | typeof(lcdconsole_get_current_y) *lcdconsole_get_current_y; | 
| 114 | 114 | typeof(lcdconsole_get_lineend_x) *lcdconsole_get_lineend_x; | 
| 115 | 115 | typeof(lcdconsole_get_lineend_y) *lcdconsole_get_lineend_y; | 
|  | 116 | +    typeof(lcdconsole_progressbar) *lcdconsole_progressbar; | 
| 116 | 117 | typeof(progressbar_init) *progressbar_init; | 
| 117 | 118 | typeof(progressbar_setpos) *progressbar_setpos; | 
| 118 | 119 | typeof(shutdown) *shutdown; | 
| Index: embios/trunk/syscallapi.c | 
| — | — | @@ -133,6 +133,7 @@ | 
| 134 | 134 | .lcdconsole_get_current_y = lcdconsole_get_current_y, | 
| 135 | 135 | .lcdconsole_get_lineend_x = lcdconsole_get_lineend_x, | 
| 136 | 136 | .lcdconsole_get_lineend_y = lcdconsole_get_lineend_y, | 
|  | 137 | +    .lcdconsole_progressbar = lcdconsole_progressbar, | 
| 137 | 138 | .progressbar_init = progressbar_init, | 
| 138 | 139 | .progressbar_setpos = progressbar_setpos, | 
| 139 | 140 | .displaylcd = displaylcd, | 
| Index: embios/trunk/lcdconsole.c | 
| — | — | @@ -26,6 +26,7 @@ | 
| 27 | 27 | #include "drawing.h" | 
| 28 | 28 | #include "util.h" | 
| 29 | 29 | #include "contextswitch.h" | 
|  | 30 | +#include "progressbar.h" | 
| 30 | 31 |  | 
| 31 | 32 |  | 
| 32 | 33 | #define OFFSETX LCDCONSOLE_OFFSETX | 
| — | — | @@ -153,3 +154,11 @@ | 
| 154 | 155 | { | 
| 155 | 156 | return (current_row + 1) * FONT_HEIGHT + OFFSETY - 1; | 
| 156 | 157 | } | 
|  | 158 | + | 
|  | 159 | +void lcdconsole_progressbar(struct progressbar_state* progressbar, int min, int max) | 
|  | 160 | +{ | 
|  | 161 | +    progressbar_init(progressbar, lcdconsole_get_current_x(), lcdconsole_get_lineend_x(), | 
|  | 162 | +                     lcdconsole_get_current_y(), lcdconsole_get_lineend_y(), | 
|  | 163 | +                     lcd_translate_color(0, 0, 0, 0), lcd_translate_color(0, 0xcf, 0xcf, 0xcf), | 
|  | 164 | +                     lcd_translate_color(0, 0, 0, 0xef), min, max); | 
|  | 165 | +} | 
| Index: embios/trunk/lcdconsole.h | 
| — | — | @@ -28,6 +28,7 @@ | 
| 29 | 29 | #include "global.h" | 
| 30 | 30 | #include "drawing.h" | 
| 31 | 31 | #include "lcd.h" | 
|  | 32 | +#include "progressbar.h" | 
| 32 | 33 |  | 
| 33 | 34 |  | 
| 34 | 35 | #define LCDCONSOLE_COLS (LCD_WIDTH / FONT_WIDTH) | 
| — | — | @@ -49,6 +50,7 @@ | 
| 50 | 51 | int lcdconsole_get_current_y() ICODE_ATTR; | 
| 51 | 52 | int lcdconsole_get_lineend_x() ICODE_ATTR; | 
| 52 | 53 | int lcdconsole_get_lineend_y() ICODE_ATTR; | 
|  | 54 | +void lcdconsole_progressbar(struct progressbar_state* progressbar, int min, int max); | 
| 53 | 55 |  | 
| 54 | 56 |  | 
| 55 | 57 | #endif |