diff options
author | David Woodhouse <dwmw2@shinybook.infradead.org> | 2006-04-11 19:09:16 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@shinybook.infradead.org> | 2006-04-11 19:09:16 -0400 |
commit | 72212c137c574b564723327af751c4054c7cfca6 (patch) | |
tree | 13be2da9d4be695002d6ea9c396660c986e5fa5c /ftl_format.c |
Initial commit
Diffstat (limited to 'ftl_format.c')
-rw-r--r-- | ftl_format.c | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/ftl_format.c b/ftl_format.c new file mode 100644 index 0000000..231fb3f --- /dev/null +++ b/ftl_format.c @@ -0,0 +1,343 @@ +/* Ported to MTD system. + * $Id: ftl_format.c,v 1.9 2005/11/07 11:15:12 gleixner Exp $ + * Based on: + */ +/*====================================================================== + + Utility to create an FTL partition in a memory region + + ftl_format.c 1.13 1999/10/25 20:01:35 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <time.h> +#include <sys/ioctl.h> +#include <sys/stat.h> + +#include <mtd/mtd-user.h> +#include <linux/mtd/ftl.h> + +#include <byteswap.h> +#include <endian.h> + +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define TO_LE32(x) (x) +# define TO_LE16(x) (x) +#elif __BYTE_ORDER == __BIG_ENDIAN +# define TO_LE32(x) (bswap_32(x)) +# define TO_LE16(x) (bswap_16(x)) +#else +# error cannot detect endianess +#endif + +#define FROM_LE32(x) TO_LE32(x) +#define FROM_LE16(x) TO_LE16(x) + +/*====================================================================*/ + +static void print_size(u_int s) +{ + if ((s > 0x100000) && ((s % 0x100000) == 0)) + printf("%d mb", s / 0x100000); + else if ((s > 0x400) && ((s % 0x400) == 0)) + printf("%d kb", s / 0x400); + else + printf("%d bytes", s); +} + +/*====================================================================*/ + +static const char LinkTarget[] = { + 0x13, 0x03, 'C', 'I', 'S' +}; +static const char DataOrg[] = { + 0x46, 0x39, 0x00, 'F', 'T', 'L', '1', '0', '0', 0x00 +}; + +static void build_header(erase_unit_header_t *hdr, u_int RegionSize, + u_int BlockSize, u_int Spare, int Reserve, + u_int BootSize) +{ + u_int i, BootUnits, nbam, __FormattedSize; + + /* Default everything to the erased state */ + memset(hdr, 0xff, sizeof(*hdr)); + memcpy(hdr->LinkTargetTuple, LinkTarget, 5); + memcpy(hdr->DataOrgTuple, DataOrg, 10); + hdr->EndTuple[0] = hdr->EndTuple[1] = 0xff; + BootSize = (BootSize + (BlockSize-1)) & ~(BlockSize-1); + BootUnits = BootSize / BlockSize; + + /* We only support 512-byte blocks */ + hdr->BlockSize = 9; + hdr->EraseUnitSize = 0; + for (i = BlockSize; i > 1; i >>= 1) + hdr->EraseUnitSize++; + hdr->EraseCount = TO_LE32(0); + hdr->FirstPhysicalEUN = TO_LE16(BootUnits); + hdr->NumEraseUnits = TO_LE16((RegionSize - BootSize) >> hdr->EraseUnitSize); + hdr->NumTransferUnits = Spare; + __FormattedSize = RegionSize - ((Spare + BootUnits) << hdr->EraseUnitSize); + /* Leave a little bit of space between the CIS and BAM */ + hdr->BAMOffset = TO_LE32(0x80); + /* Adjust size to account for BAM space */ + nbam = ((1 << (hdr->EraseUnitSize - hdr->BlockSize)) * sizeof(u_int) + + FROM_LE32(hdr->BAMOffset) + (1 << hdr->BlockSize) - 1) >> hdr->BlockSize; + + __FormattedSize -= + (FROM_LE16(hdr->NumEraseUnits) - Spare) * (nbam << hdr->BlockSize); + __FormattedSize -= ((__FormattedSize * Reserve / 100) & ~0xfff); + + hdr->FormattedSize = TO_LE32(__FormattedSize); + + /* hdr->FirstVMAddress defaults to erased state */ + hdr->NumVMPages = TO_LE16(0); + hdr->Flags = 0; + /* hdr->Code defaults to erased state */ + hdr->SerialNumber = TO_LE32(time(NULL)); + /* hdr->AltEUHOffset defaults to erased state */ + +} /* build_header */ + +/*====================================================================*/ + +static int format_partition(int fd, int quiet, int interrogate, + u_int spare, int reserve, u_int bootsize) +{ + mtd_info_t mtd; + erase_info_t erase; + erase_unit_header_t hdr; + u_int step, lun, i, nbam, *bam; + + /* Get partition size, block size */ + if (ioctl(fd, MEMGETINFO, &mtd) != 0) { + perror("get info failed"); + return -1; + } + +#if 0 + /* Intel Series 100 Flash: skip first block */ + if ((region.JedecMfr == 0x89) && (region.JedecInfo == 0xaa) && + (bootsize == 0)) { + if (!quiet) + printf("Skipping first block to protect CIS info...\n"); + bootsize = 1; + } +#endif + + /* Create header */ + build_header(&hdr, mtd.size, mtd.erasesize, + spare, reserve, bootsize); + + if (!quiet) { + printf("Partition size = "); + print_size(mtd.size); + printf(", erase unit size = "); + print_size(mtd.erasesize); + printf(", %d transfer units\n", spare); + if (bootsize != 0) { + print_size(FROM_LE16(hdr.FirstPhysicalEUN) << hdr.EraseUnitSize); + printf(" allocated for boot image\n"); + } + printf("Reserved %d%%, formatted size = ", reserve); + print_size(FROM_LE32(hdr.FormattedSize)); + printf("\n"); + fflush(stdout); + } + + if (interrogate) { + char str[3]; + printf("This will destroy all data on the target device. " + "Confirm (y/n): "); + if (fgets(str, 3, stdin) == NULL) + return -1; + if ((strcmp(str, "y\n") != 0) && (strcmp(str, "Y\n") != 0)) + return -1; + } + + /* Create basic block allocation table for control blocks */ + nbam = ((mtd.erasesize >> hdr.BlockSize) * sizeof(u_int) + + FROM_LE32(hdr.BAMOffset) + (1 << hdr.BlockSize) - 1) >> hdr.BlockSize; + bam = malloc(nbam * sizeof(u_int)); + for (i = 0; i < nbam; i++) + bam[i] = TO_LE32(BLOCK_CONTROL); + + /* Erase partition */ + if (!quiet) { + printf("Erasing all blocks...\n"); + fflush(stdout); + } + erase.length = mtd.erasesize; + erase.start = mtd.erasesize * FROM_LE16(hdr.FirstPhysicalEUN); + for (i = 0; i < FROM_LE16(hdr.NumEraseUnits); i++) { + if (ioctl(fd, MEMERASE, &erase) < 0) { + if (!quiet) { + putchar('\n'); + fflush(stdout); + } + perror("block erase failed"); + return -1; + } + erase.start += erase.length; + if (!quiet) { + if (mtd.size <= 0x800000) { + if (erase.start % 0x100000) { + if (!(erase.start % 0x20000)) putchar('-'); + } + else putchar('+'); + } + else { + if (erase.start % 0x800000) { + if (!(erase.start % 0x100000)) putchar('+'); + } + else putchar('*'); + } + fflush(stdout); + } + } + if (!quiet) putchar('\n'); + + /* Prepare erase units */ + if (!quiet) { + printf("Writing erase unit headers...\n"); + fflush(stdout); + } + lun = 0; + /* Distribute transfer units over the entire region */ + step = (spare) ? (FROM_LE16(hdr.NumEraseUnits)/spare) : (FROM_LE16(hdr.NumEraseUnits)+1); + for (i = 0; i < FROM_LE16(hdr.NumEraseUnits); i++) { + u_int ofs = (i + FROM_LE16(hdr.FirstPhysicalEUN)) << hdr.EraseUnitSize; + if (lseek(fd, ofs, SEEK_SET) == -1) { + perror("seek failed"); + break; + } + /* Is this a transfer unit? */ + if (((i+1) % step) == 0) + hdr.LogicalEUN = TO_LE16(0xffff); + else { + hdr.LogicalEUN = TO_LE16(lun); + lun++; + } + if (write(fd, &hdr, sizeof(hdr)) == -1) { + perror("write failed"); + break; + } + if (lseek(fd, ofs + FROM_LE32(hdr.BAMOffset), SEEK_SET) == -1) { + perror("seek failed"); + break; + } + if (write(fd, bam, nbam * sizeof(u_int)) == -1) { + perror("write failed"); + break; + } + } + if (i < FROM_LE16(hdr.NumEraseUnits)) + return -1; + else + return 0; +} /* format_partition */ + +/*====================================================================*/ + +int main(int argc, char *argv[]) +{ + int quiet, interrogate, reserve; + int optch, errflg, fd, ret; + u_int spare, bootsize; + char *s; + extern char *optarg; + struct stat buf; + + quiet = 0; + interrogate = 0; + spare = 1; + reserve = 5; + errflg = 0; + bootsize = 0; + + while ((optch = getopt(argc, argv, "qir:s:b:")) != -1) { + switch (optch) { + case 'q': + quiet = 1; break; + case 'i': + interrogate = 1; break; + case 's': + spare = strtoul(optarg, NULL, 0); break; + case 'r': + reserve = strtoul(optarg, NULL, 0); break; + case 'b': + bootsize = strtoul(optarg, &s, 0); + if ((*s == 'k') || (*s == 'K')) + bootsize *= 1024; + break; + default: + errflg = 1; break; + } + } + if (errflg || (optind != argc-1)) { + fprintf(stderr, "usage: %s [-q] [-i] [-s spare-blocks]" + " [-r reserve-percent] [-b bootsize] device\n", argv[0]); + exit(EXIT_FAILURE); + } + + if (stat(argv[optind], &buf) != 0) { + perror("status check failed"); + exit(EXIT_FAILURE); + } + if (!(buf.st_mode & S_IFCHR)) { + fprintf(stderr, "%s is not a character special device\n", + argv[optind]); + exit(EXIT_FAILURE); + } + fd = open(argv[optind], O_RDWR); + if (fd == -1) { + perror("open failed"); + exit(EXIT_FAILURE); + } + + ret = format_partition(fd, quiet, interrogate, spare, reserve, + bootsize); + if (!quiet) { + if (ret) + printf("format failed.\n"); + else + printf("format successful.\n"); + } + close(fd); + + exit((ret) ? EXIT_FAILURE : EXIT_SUCCESS); + return 0; +} |