busybox/miscutils/flash_eraseall.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * eraseall.c -- erase the whole of a MTD device
   4 *
   5 * Ported to busybox from mtd-utils.
   6 *
   7 * Copyright (C) 2000 Arcom Control System Ltd
   8 *
   9 * Renamed to flash_eraseall.c
  10 *
  11 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  12 */
  13//config:config FLASH_ERASEALL
  14//config:       bool "flash_eraseall (5.9 kb)"
  15//config:       default n  # doesn't build on Ubuntu 8.04
  16//config:       help
  17//config:       The flash_eraseall binary from mtd-utils as of git head c4c6a59eb.
  18//config:       This utility is used to erase the whole MTD device.
  19
  20//applet:IF_FLASH_ERASEALL(APPLET(flash_eraseall, BB_DIR_USR_SBIN, BB_SUID_DROP))
  21/* not NOEXEC: if flash operation stalls, use less memory in "hung" process */
  22
  23//kbuild:lib-$(CONFIG_FLASH_ERASEALL) += flash_eraseall.o
  24
  25//usage:#define flash_eraseall_trivial_usage
  26//usage:       "[-jNq] MTD_DEVICE"
  27//usage:#define flash_eraseall_full_usage "\n\n"
  28//usage:       "Erase an MTD device\n"
  29//usage:     "\n        -j      Format the device for jffs2"
  30//usage:     "\n        -N      Don't skip bad blocks"
  31//usage:     "\n        -q      Don't display progress messages"
  32
  33#include "libbb.h"
  34#include <mtd/mtd-user.h>
  35#include <linux/jffs2.h>
  36
  37#define OPTION_J  (1 << 0)
  38#define OPTION_N  (1 << 1)
  39#define OPTION_Q  (1 << 2)
  40#define IS_NAND   (1 << 3)
  41
  42/* mtd/jffs2-user.h used to have this atrocity:
  43extern int target_endian;
  44
  45#define t16(x) ({ __u16 __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); })
  46#define t32(x) ({ __u32 __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); })
  47
  48#define cpu_to_je16(x) ((jint16_t){t16(x)})
  49#define cpu_to_je32(x) ((jint32_t){t32(x)})
  50#define cpu_to_jemode(x) ((jmode_t){t32(x)})
  51
  52#define je16_to_cpu(x) (t16((x).v16))
  53#define je32_to_cpu(x) (t32((x).v32))
  54#define jemode_to_cpu(x) (t32((x).m))
  55
  56but mtd/jffs2-user.h is gone now (at least 2.6.31.6 does not have it anymore)
  57*/
  58
  59/* We always use native endianness */
  60#undef cpu_to_je16
  61#undef cpu_to_je32
  62#define cpu_to_je16(v) ((jint16_t){(v)})
  63#define cpu_to_je32(v) ((jint32_t){(v)})
  64
  65static void show_progress(mtd_info_t *meminfo, erase_info_t *erase)
  66{
  67        printf("\rErasing %u Kibyte @ %x - %2u%% complete.",
  68                (unsigned)meminfo->erasesize / 1024,
  69                erase->start,
  70                (unsigned) ((unsigned long long) erase->start * 100 / meminfo->size)
  71        );
  72        fflush_all();
  73}
  74
  75int flash_eraseall_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  76int flash_eraseall_main(int argc UNUSED_PARAM, char **argv)
  77{
  78        struct jffs2_unknown_node cleanmarker;
  79        mtd_info_t meminfo;
  80        int fd, clmpos, clmlen;
  81        erase_info_t erase;
  82        struct stat st;
  83        unsigned int flags;
  84        char *mtd_name;
  85
  86        flags = getopt32(argv, "^" "jNq" "\0" "=1");
  87
  88        mtd_name = argv[optind];
  89        fd = xopen(mtd_name, O_RDWR);
  90        fstat(fd, &st);
  91        if (!S_ISCHR(st.st_mode))
  92                bb_error_msg_and_die("%s: not a char device", mtd_name);
  93
  94        xioctl(fd, MEMGETINFO, &meminfo);
  95        erase.length = meminfo.erasesize;
  96        if (meminfo.type == MTD_NANDFLASH)
  97                flags |= IS_NAND;
  98
  99        clmpos = 0;
 100        clmlen = 8;
 101        if (flags & OPTION_J) {
 102                uint32_t *crc32_table;
 103
 104                crc32_table = crc32_new_table_le();
 105
 106                cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
 107                cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
 108                if (!(flags & IS_NAND))
 109                        cleanmarker.totlen = cpu_to_je32(sizeof(struct jffs2_unknown_node));
 110                else {
 111                        struct nand_oobinfo oobinfo;
 112
 113                        xioctl(fd, MEMGETOOBSEL, &oobinfo);
 114
 115                        /* Check for autoplacement */
 116                        if (oobinfo.useecc == MTD_NANDECC_AUTOPLACE) {
 117                                /* Get the position of the free bytes */
 118                                clmpos = oobinfo.oobfree[0][0];
 119                                clmlen = oobinfo.oobfree[0][1];
 120                                if (clmlen > 8)
 121                                        clmlen = 8;
 122                                if (clmlen == 0)
 123                                        bb_error_msg_and_die("autoplacement selected and no empty space in oob");
 124                        } else {
 125                                /* Legacy mode */
 126                                switch (meminfo.oobsize) {
 127                                case 8:
 128                                        clmpos = 6;
 129                                        clmlen = 2;
 130                                        break;
 131                                case 16:
 132                                        clmpos = 8;
 133                                        /*clmlen = 8;*/
 134                                        break;
 135                                case 64:
 136                                        clmpos = 16;
 137                                        /*clmlen = 8;*/
 138                                        break;
 139                                }
 140                        }
 141                        cleanmarker.totlen = cpu_to_je32(8);
 142                }
 143
 144                cleanmarker.hdr_crc = cpu_to_je32(
 145                        crc32_block_endian0(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, crc32_table)
 146                );
 147        }
 148
 149        /* Don't want to destroy progress indicator by bb_error_msg's */
 150        applet_name = xasprintf("\n%s: %s", applet_name, mtd_name);
 151
 152        for (erase.start = 0; erase.start < meminfo.size;
 153             erase.start += meminfo.erasesize) {
 154                if (!(flags & OPTION_N)) {
 155                        int ret;
 156                        loff_t offset = erase.start;
 157
 158                        ret = ioctl(fd, MEMGETBADBLOCK, &offset);
 159                        if (ret > 0) {
 160                                if (!(flags & OPTION_Q))
 161                                        printf("\nSkipping bad block at 0x%08x\n", erase.start);
 162                                continue;
 163                        }
 164                        if (ret < 0) {
 165                                /* Black block table is not available on certain flash
 166                                 * types e.g. NOR
 167                                 */
 168                                if (errno == EOPNOTSUPP) {
 169                                        flags |= OPTION_N;
 170                                        if (flags & IS_NAND)
 171                                                bb_error_msg_and_die("bad block check not available");
 172                                } else {
 173                                        bb_perror_msg_and_die("MEMGETBADBLOCK error");
 174                                }
 175                        }
 176                }
 177
 178                if (!(flags & OPTION_Q))
 179                        show_progress(&meminfo, &erase);
 180
 181                xioctl(fd, MEMERASE, &erase);
 182
 183                /* format for JFFS2 ? */
 184                if (!(flags & OPTION_J))
 185                        continue;
 186
 187                /* write cleanmarker */
 188                if (flags & IS_NAND) {
 189                        struct mtd_oob_buf oob;
 190
 191                        oob.ptr = (unsigned char *) &cleanmarker;
 192                        oob.start = erase.start + clmpos;
 193                        oob.length = clmlen;
 194                        xioctl(fd, MEMWRITEOOB, &oob);
 195                } else {
 196                        xlseek(fd, erase.start, SEEK_SET);
 197                        /* if (lseek(fd, erase.start, SEEK_SET) < 0) {
 198                                bb_perror_msg("MTD %s failure", "seek");
 199                                continue;
 200                        } */
 201                        xwrite(fd, &cleanmarker, sizeof(cleanmarker));
 202                        /* if (write(fd, &cleanmarker, sizeof(cleanmarker)) != sizeof(cleanmarker)) {
 203                                bb_perror_msg("MTD %s failure", "write");
 204                                continue;
 205                        } */
 206                }
 207                if (!(flags & OPTION_Q))
 208                        printf(" Cleanmarker written at %x.", erase.start);
 209        }
 210        if (!(flags & OPTION_Q)) {
 211                show_progress(&meminfo, &erase);
 212                bb_putchar('\n');
 213        }
 214
 215        if (ENABLE_FEATURE_CLEAN_UP)
 216                close(fd);
 217        return EXIT_SUCCESS;
 218}
 219