123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- /*
- * 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 <getopt.h>
- #include <asm/types.h>
- #include <mtd/mtd-user.h>
- #include <mtd/nftl-user.h>
- #include <mtd/inftl-user.h>
- #include <mtd_swab.h>
- #include "common.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 const struct option long_opts[] = {
- {"version", no_argument, 0, 'V'},
- {"help", no_argument, 0, 'h'},
- {0, 0, 0, 0},
- };
- 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_nocheck(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_nocheck(fd, writebuf[1], 512, blockofs + ofs);
- pread_nocheck(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_nocheck(fd, writebuf[2], 512, blockofs + ofs);
- pread_nocheck(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_nocheck(fd, writebuf[3], 512, blockofs + ofs);
- pread_nocheck(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_nocheck(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);
- }
- static NORETURN void usage(int rc)
- {
- fprintf(stderr, "Usage: %s [-ib] <mtddevice> [<start offset> [<size>]]\n", PROGRAM_NAME);
- exit(rc);
- }
- static void display_version(void)
- {
- common_print_version();
- printf("Copyright (C) 2005 Thomas Gleixner \n"
- "\n"
- "%1$s comes with NO WARRANTY\n"
- "to the extent permitted by law.\n"
- "\n"
- "You may redistribute copies of %1$s\n"
- "under the terms of the GNU General Public Licence.\n"
- "See the file `COPYING' for more information.\n",
- PROGRAM_NAME);
- exit(EXIT_SUCCESS);
- }
- 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;
- int idx = 0;
- if (argc < 2)
- usage(EXIT_FAILURE);
- nftl = "NFTL";
- while ((c = getopt_long(argc, argv, "?hibV", long_opts, &idx)) != -1) {
- switch (c) {
- case 'i':
- nftl = "INFTL";
- do_inftl = 1;
- break;
- case 'b':
- do_bbt = 1;
- break;
- case 'h':
- case '?':
- usage(EXIT_SUCCESS);
- case 'V':
- display_version();
- break;
- default:
- usage(EXIT_FAILURE);
- }
- }
- 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_nocheck(fd, writebuf[0], 512, MediaUnit1 * meminfo.erasesize + MediaUnitOff1);
- for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
- pwrite_nocheck(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_nocheck(fd, writebuf[0], 512, MediaUnit2 * meminfo.erasesize + MediaUnitOff2);
- for (ezone = 0; ezone < (meminfo.size / meminfo.erasesize); ezone += 512) {
- pwrite_nocheck(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);
- }
|