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