off_t mtd_erase_blocks(MtdWriteContext *ctx, int blocks) { // Zero-pad and write any pending data to get us to a block boundary if (ctx->stored > 0) { size_t zero = ctx->partition->erase_size - ctx->stored; memset(ctx->buffer + ctx->stored, 0, zero); if (write_block(ctx, ctx->buffer)) return -1; ctx->stored = 0; } off_t pos = lseek(ctx->fd, 0, SEEK_CUR); if ((off_t) pos == (off_t) -1) return pos; const int total = (ctx->partition->size - pos) / ctx->partition->erase_size; if (blocks < 0) blocks = total; if (blocks > total) { errno = ENOSPC; return -1; } // Erase the specified number of blocks while (blocks-- > 0) { loff_t bpos = pos; if (ioctl(ctx->fd, MEMGETBADBLOCK, &bpos) > 0) { printf("mtd: not erasing bad block at 0x%08lx\n", pos); pos += ctx->partition->erase_size; continue; // Don't try to erase known factory-bad blocks. } struct erase_info_user erase_info; erase_info.start = pos; erase_info.length = ctx->partition->erase_size; #ifdef RK3066 if (rk30_zero_out(ctx->fd, pos, ctx->partition->erase_size) < 0) { fprintf(stderr, "mtd: erase failure at 0x%08lx\n", pos); } #else if (ioctl(ctx->fd, MEMERASE, &erase_info) < 0) { printf("mtd: erase failure at 0x%08lx\n", pos); } #endif pos += ctx->partition->erase_size; } return pos; }
static int write_block(MtdWriteContext *ctx, const char *data) { const MtdPartition *partition = ctx->partition; int fd = ctx->fd; off_t pos = lseek(fd, 0, SEEK_CUR); if (pos == (off_t) -1) return 1; ssize_t size = partition->erase_size; char *verify = malloc(size); if (verify == NULL) return 1; while (pos + size <= (int) partition->size) { loff_t bpos = pos; int ret = ioctl(fd, MEMGETBADBLOCK, &bpos); if (ret != 0 && !(ret == -1 && errno == EOPNOTSUPP)) { add_bad_block_offset(ctx, pos); fprintf(stderr, "mtd: not writing bad block at 0x%08lx (ret %d errno %d)\n", pos, ret, errno); pos += partition->erase_size; continue; // Don't try to erase known factory-bad blocks. } struct erase_info_user erase_info; erase_info.start = pos; erase_info.length = size; int retry; for (retry = 0; retry < 2; ++retry) { #ifdef RK3066 if (rk30_zero_out(fd, pos, size) < 0) { fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } #else if (ioctl(fd, MEMERASE, &erase_info) < 0) { printf("mtd: erase failure at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } #endif if (lseek(fd, pos, SEEK_SET) != pos || write(fd, data, size) != size) { printf("mtd: write error at 0x%08lx (%s)\n", pos, strerror(errno)); } char verify[size]; if (lseek(fd, pos, SEEK_SET) != pos || read(fd, verify, size) != size) { printf("mtd: re-read error at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } if (memcmp(data, verify, size) != 0) { printf("mtd: verification error at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } if (retry > 0) { printf("mtd: wrote block after %d retries\n", retry); } printf("mtd: successfully wrote block at %lx\n", pos); free(verify); return 0; // Success! } // Try to erase it once more as we give up on this block add_bad_block_offset(ctx, pos); printf("mtd: skipping write block at 0x%08lx\n", pos); #ifdef RK3066 rk30_zero_out(fd, pos, size); #else ioctl(fd, MEMERASE, &erase_info); #endif pos += partition->erase_size; } free(verify); // Ran out of space on the device errno = ENOSPC; return -1; }
static ssize_t bml_over_mtd_write_block(int fd, ssize_t erase_size, char* data) { off_t pos = lseek(fd, 0, SEEK_CUR); if (pos == (off_t) -1) return -1; ssize_t size = erase_size; loff_t bpos = pos; int ret = ioctl(fd, MEMGETBADBLOCK, &bpos); if (ret != 0 && !(ret == -1 && errno == EOPNOTSUPP)) { fprintf(stderr, "Mapping failure: Trying to write bad block at 0x%08lx (ret %d errno %d)\n", pos, ret, errno); return -1; } struct erase_info_user erase_info; erase_info.start = pos; erase_info.length = size; int retry; for (retry = 0; retry < 2; ++retry) { #ifdef RK3X if (rk30_zero_out(fd, pos, size) < 0) { fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } #else if (ioctl(fd, MEMERASE, &erase_info) < 0) { fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } #endif if (lseek(fd, pos, SEEK_SET) != pos || write(fd, data, size) != size) { fprintf(stderr, "mtd: write error at 0x%08lx (%s)\n", pos, strerror(errno)); } char verify[size]; if (lseek(fd, pos, SEEK_SET) != pos || read(fd, verify, size) != size) { fprintf(stderr, "mtd: re-read error at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } if (memcmp(data, verify, size) != 0) { fprintf(stderr, "mtd: verification error at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } if (retry > 0) { fprintf(stderr, "mtd: wrote block after %d retries\n", retry); } fprintf(stderr, "mtd: successfully wrote block at %llx\n", pos); return size; // Success! } fprintf(stderr, "mtd: Block at %llx could not be properly written.\n", pos); // Ran out of space on the device errno = ENOSPC; return -1; }