diff options
Diffstat (limited to 'nftl_format.c')
-rw-r--r-- | nftl_format.c | 422 |
1 files changed, 0 insertions, 422 deletions
diff --git a/nftl_format.c b/nftl_format.c deleted file mode 100644 index 1fc3b36..0000000 --- a/nftl_format.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * nftl_format.c: Creating a NFTL/INFTL partition on an MTD device - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * ToDo: - * 1. UnitSizeFactor != 0xFF cases - * 2. test, test, and test !!! - */ - -#define PROGRAM_NAME "nftl_format" - -#define _XOPEN_SOURCE 500 /* for pread/pwrite */ -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <fcntl.h> -#include <time.h> -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <sys/mount.h> -#include <errno.h> -#include <string.h> - -#include <asm/types.h> -#include <mtd/mtd-user.h> -#include <mtd/nftl-user.h> -#include <mtd/inftl-user.h> -#include <mtd_swab.h> - -unsigned char BadUnitTable[MAX_ERASE_ZONES]; -unsigned char *readbuf; -unsigned char *writebuf[4]; - -mtd_info_t meminfo; -erase_info_t erase; -int fd; -struct NFTLMediaHeader *NFTLhdr; -struct INFTLMediaHeader *INFTLhdr; - -static int do_oobcheck = 1; -static int do_rwecheck = 1; - -static unsigned char check_block_1(unsigned long block) -{ - unsigned char oobbuf[16]; - struct mtd_oob_buf oob = { 0, 16, oobbuf }; - - oob.start = block * meminfo.erasesize; - if (ioctl(fd, MEMREADOOB, &oob)) - return ZONE_BAD_ORIGINAL; - - if(oobbuf[5] == 0) - return ZONE_BAD_ORIGINAL; - - oob.start = block * meminfo.erasesize + 512 /* FIXME */; - if (ioctl(fd, MEMREADOOB, &oob)) - return ZONE_BAD_ORIGINAL; - - if(oobbuf[5] == 0) - return ZONE_BAD_ORIGINAL; - - return ZONE_GOOD; -} - -static unsigned char check_block_2(unsigned long block) -{ - unsigned long ofs = block * meminfo.erasesize; - unsigned long blockofs; - - /* Erase test */ - erase.start = ofs; - - for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) { - pread(fd, readbuf, 512, ofs + blockofs); - if (memcmp(readbuf, writebuf[0], 512)) { - /* Block wasn't 0xff after erase */ - printf(": Block not 0xff after erase\n"); - return ZONE_BAD_ORIGINAL; - } - - pwrite(fd, writebuf[1], 512, blockofs + ofs); - pread(fd, readbuf, 512, blockofs + ofs); - if (memcmp(readbuf, writebuf[1], 512)) { - printf(": Block not zero after clearing\n"); - return ZONE_BAD_ORIGINAL; - } - } - - /* Write test */ - if (ioctl(fd, MEMERASE, &erase) != 0) { - printf(": Second erase failed (%s)\n", strerror(errno)); - return ZONE_BAD_ORIGINAL; - } - for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) { - pwrite(fd, writebuf[2], 512, blockofs + ofs); - pread(fd, readbuf, 512, blockofs + ofs); - if (memcmp(readbuf, writebuf[2], 512)) { - printf(": Block not 0x5a after writing\n"); - return ZONE_BAD_ORIGINAL; - } - } - - if (ioctl(fd, MEMERASE, &erase) != 0) { - printf(": Third erase failed (%s)\n", strerror(errno)); - return ZONE_BAD_ORIGINAL; - } - for (blockofs = 0; blockofs < meminfo.erasesize; blockofs += 512) { - pwrite(fd, writebuf[3], 512, blockofs + ofs); - pread(fd, readbuf, 512, blockofs + ofs); - if (memcmp(readbuf, writebuf[3], 512)) { - printf(": Block not 0xa5 after writing\n"); - return ZONE_BAD_ORIGINAL; - } - } - if (ioctl(fd, MEMERASE, &erase) != 0) { - printf(": Fourth erase failed (%s)\n", strerror(errno)); - return ZONE_BAD_ORIGINAL; - } - return ZONE_GOOD; -} - -static unsigned char erase_block(unsigned long block) -{ - unsigned char status; - int ret; - - status = (do_oobcheck) ? check_block_1(block) : ZONE_GOOD; - erase.start = block * meminfo.erasesize; - - if (status != ZONE_GOOD) { - printf("\rSkipping bad zone (factory marked) #%ld @ 0x%x\n", block, erase.start); - fflush(stdout); - return status; - } - - printf("\r\t Erasing Zone #%ld @ 0x%x", block, erase.start); - fflush(stdout); - - if ((ret=ioctl(fd, MEMERASE, &erase)) != 0) { - printf(": Erase failed (%s)\n", strerror(errno)); - return ZONE_BAD_ORIGINAL; - } - - if (do_rwecheck) { - printf("\r\tChecking Zone #%ld @ 0x%x", block, erase.start); - fflush(stdout); - status = check_block_2(block); - if (status != ZONE_GOOD) { - printf("\rSkipping bad zone (RWE test failed) #%ld @ 0x%x\n", block, erase.start); - fflush(stdout); - } - } - return status; -} - -static int checkbbt(void) -{ - unsigned char bbt[512]; - unsigned char bits; - int i, addr; - - if (pread(fd, bbt, 512, 0x800) < 0) { - printf("%s: failed to read BBT, errno=%d\n", PROGRAM_NAME, errno); - return (-1); - } - - - for (i = 0; (i < 512); i++) { - addr = i / 4; - bits = 0x3 << ((i % 4) * 2); - if ((bbt[addr] & bits) == 0) { - BadUnitTable[i] = ZONE_BAD_ORIGINAL; - } - } - - return (0); -} - -void usage(int rc) -{ - fprintf(stderr, "Usage: %s [-ib] <mtddevice> [<start offset> [<size>]]\n", PROGRAM_NAME); - exit(rc); -} - -int main(int argc, char **argv) -{ - unsigned long startofs = 0, part_size = 0; - unsigned long ezones = 0, ezone = 0, bad_zones = 0; - unsigned char unit_factor = 0xFF; - long MediaUnit1 = -1, MediaUnit2 = -1; - long MediaUnitOff1 = 0, MediaUnitOff2 = 0; - unsigned char oobbuf[16]; - struct mtd_oob_buf oob = {0, 16, oobbuf}; - char *mtddevice; - const char *nftl; - int c, do_inftl = 0, do_bbt = 0; - - - printf("version 1.24 2005/11/07 11:15:13 gleixner\n"); - - if (argc < 2) - usage(1); - - nftl = "NFTL"; - - while ((c = getopt(argc, argv, "?hib")) > 0) { - switch (c) { - case 'i': - nftl = "INFTL"; - do_inftl = 1; - break; - case 'b': - do_bbt = 1; - break; - case 'h': - case '?': - usage(0); - break; - default: - usage(1); - break; - } - } - - mtddevice = argv[optind++]; - if (argc > optind) { - startofs = strtoul(argv[optind++], NULL, 0); - } - if (argc > optind) { - part_size = strtoul(argv[optind++], NULL, 0); - } - - // Open and size the device - if ((fd = open(mtddevice, O_RDWR)) < 0) { - perror("Open flash device"); - return 1; - } - - if (ioctl(fd, MEMGETINFO, &meminfo) != 0) { - perror("ioctl(MEMGETINFO)"); - close(fd); - return 1; - } - - switch (meminfo.erasesize) { - case 0x1000: - case 0x2000: - case 0x4000: - case 0x8000: - break; - default: - printf("Unrecognized Erase size, 0x%x - I'm confused\n", - meminfo.erasesize); - close(fd); - return 1; - } - writebuf[0] = malloc(meminfo.erasesize * 5); - if (!writebuf[0]) { - printf("Malloc failed\n"); - close(fd); - return 1; - } - writebuf[1] = writebuf[0] + meminfo.erasesize; - writebuf[2] = writebuf[1] + meminfo.erasesize; - writebuf[3] = writebuf[2] + meminfo.erasesize; - readbuf = writebuf[3] + meminfo.erasesize; - memset(writebuf[0], 0xff, meminfo.erasesize); - memset(writebuf[1], 0x00, meminfo.erasesize); - memset(writebuf[2], 0x5a, meminfo.erasesize); - memset(writebuf[3], 0xa5, meminfo.erasesize); - memset(BadUnitTable, ZONE_GOOD, MAX_ERASE_ZONES); - - if (part_size == 0 || (part_size > meminfo.size - startofs)) - /* the user doest not or incorrectly specify NFTL partition size */ - part_size = meminfo.size - startofs; - - erase.length = meminfo.erasesize; - ezones = part_size / meminfo.erasesize; - - if (ezones > MAX_ERASE_ZONES) { - /* Ought to change the UnitSizeFactor. But later. */ - part_size = meminfo.erasesize * MAX_ERASE_ZONES; - ezones = MAX_ERASE_ZONES; - unit_factor = 0xFF; - } - - /* If using device BBT then parse that now */ - if (do_bbt) { - checkbbt(); - do_oobcheck = 0; - do_rwecheck = 0; - } - - /* Phase 1. Erasing and checking each erase zones in the NFTL partition. - N.B. Erase Zones not used by the NFTL partition are untouched and marked ZONE_GOOD */ - printf("Phase 1. Checking and erasing Erase Zones from 0x%08lx to 0x%08lx\n", - startofs, startofs + part_size); - for (ezone = startofs / meminfo.erasesize; - ezone < (ezones + startofs / meminfo.erasesize); ezone++) { - if (BadUnitTable[ezone] != ZONE_GOOD) - continue; - if ((BadUnitTable[ezone] = erase_block(ezone)) == ZONE_GOOD) { - if (MediaUnit1 == -1) { - MediaUnit1 = ezone; - } else if (MediaUnit2 == -1) { - MediaUnit2 = ezone; - } - } else { - bad_zones++; - } - } - printf("\n"); - - /* N.B. from dump of M-System original chips, NumEraseUnits counts the 2 Erase Unit used - by MediaHeader and the FirstPhysicalEUN starts from the MediaHeader */ - if (do_inftl) { - unsigned long maxzones, pezstart, pezend, numvunits; - - INFTLhdr = (struct INFTLMediaHeader *) (writebuf[0]); - strcpy(INFTLhdr->bootRecordID, "BNAND"); - INFTLhdr->NoOfBootImageBlocks = cpu_to_le32(0); - INFTLhdr->NoOfBinaryPartitions = cpu_to_le32(0); - INFTLhdr->NoOfBDTLPartitions = cpu_to_le32(1); - INFTLhdr->BlockMultiplierBits = cpu_to_le32(0); - INFTLhdr->FormatFlags = cpu_to_le32(0); - INFTLhdr->OsakVersion = cpu_to_le32(OSAK_VERSION); - INFTLhdr->PercentUsed = cpu_to_le32(PERCENTUSED); - /* - * Calculate number of virtual units we will have to work - * with. I am calculating out the known bad units here, not - * sure if that is what M-Systems do... - */ - MediaUnit2 = MediaUnit1; - MediaUnitOff2 = 4096; - maxzones = meminfo.size / meminfo.erasesize; - pezstart = startofs / meminfo.erasesize + 1; - pezend = startofs / meminfo.erasesize + ezones - 1; - numvunits = (ezones - 2) * PERCENTUSED / 100; - for (ezone = pezstart; ezone < maxzones; ezone++) { - if (BadUnitTable[ezone] != ZONE_GOOD) { - if (numvunits > 1) - numvunits--; - } - } - - INFTLhdr->Partitions[0].virtualUnits = cpu_to_le32(numvunits); - INFTLhdr->Partitions[0].firstUnit = cpu_to_le32(pezstart); - INFTLhdr->Partitions[0].lastUnit = cpu_to_le32(pezend); - INFTLhdr->Partitions[0].flags = cpu_to_le32(INFTL_BDTL); - INFTLhdr->Partitions[0].spareUnits = cpu_to_le32(0); - INFTLhdr->Partitions[0].Reserved0 = INFTLhdr->Partitions[0].firstUnit; - INFTLhdr->Partitions[0].Reserved1 = cpu_to_le32(0); - - } else { - - NFTLhdr = (struct NFTLMediaHeader *) (writebuf[0]); - strcpy(NFTLhdr->DataOrgID, "ANAND"); - NFTLhdr->NumEraseUnits = cpu_to_le16(part_size / meminfo.erasesize); - NFTLhdr->FirstPhysicalEUN = cpu_to_le16(MediaUnit1); - /* N.B. we reserve 2 more Erase Units for "folding" of Virtual Unit Chain */ - NFTLhdr->FormattedSize = cpu_to_le32(part_size - ( (5+bad_zones) * meminfo.erasesize)); - NFTLhdr->UnitSizeFactor = unit_factor; - } - - /* Phase 2. Writing NFTL Media Headers and Bad Unit Table */ - printf("Phase 2.a Writing %s Media Header and Bad Unit Table\n", nftl); - pwrite(fd, writebuf[0], 512, MediaUnit1 * meminfo.erasesize + MediaUnitOff1); - for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) { - pwrite(fd, BadUnitTable + ezone, 512, - (MediaUnit1 * meminfo.erasesize) + 512 * (1 + ezone / 512)); - } - -#if 0 - printf(" MediaHeader contents:\n"); - printf(" NumEraseUnits: %d\n", le16_to_cpu(NFTLhdr->NumEraseUnits)); - printf(" FirstPhysicalEUN: %d\n", le16_to_cpu(NFTLhdr->FirstPhysicalEUN)); - printf(" FormattedSize: %d (%d sectors)\n", le32_to_cpu(NFTLhdr->FormattedSize), - le32_to_cpu(NFTLhdr->FormattedSize)/512); -#endif - printf("Phase 2.b Writing Spare %s Media Header and Spare Bad Unit Table\n", nftl); - pwrite(fd, writebuf[0], 512, MediaUnit2 * meminfo.erasesize + MediaUnitOff2); - for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) { - pwrite(fd, BadUnitTable + ezone, 512, - (MediaUnit2 * meminfo.erasesize + MediaUnitOff2) + 512 * (1 + ezone / 512)); - } - - /* UCI #1 for newly erased Erase Unit */ - memset(oobbuf, 0xff, 16); - oobbuf[11] = oobbuf[10] = oobbuf[9] = 0; - oobbuf[8] = (do_inftl) ? 0x00 : 0x03; - oobbuf[12] = oobbuf[14] = 0x69; - oobbuf[13] = oobbuf[15] = 0x3c; - - /* N.B. The Media Header and Bad Erase Unit Table are considered as Free Erase Unit - by M-System i.e. their Virtual Unit Number == 0xFFFF in the Unit Control Information #0, - but their Block Status is BLOCK_USED (0x5555) in their Block Control Information */ - /* Phase 3. Writing Unit Control Information for each Erase Unit */ - printf("Phase 3. Writing Unit Control Information to each Erase Unit\n"); - for (ezone = MediaUnit1; ezone < (ezones + startofs / meminfo.erasesize); ezone++) { - /* write UCI #1 to each Erase Unit */ - if (BadUnitTable[ezone] != ZONE_GOOD) - continue; - oob.start = (ezone * meminfo.erasesize) + 512 + (do_inftl * 512); - if (ioctl(fd, MEMWRITEOOB, &oob)) - printf("MEMWRITEOOB at %lx: %s\n", (unsigned long)oob.start, strerror(errno)); - } - - exit(0); -} |