u32 threads_length;
};
+#define CHECK_BB 0
+
struct apanic_data {
struct mtd_info *mtd;
struct panic_header curr;
static struct work_struct proc_removal_work;
static DEFINE_MUTEX(drv_mutex);
-static unsigned int *apanic_bbt;
-static unsigned int apanic_erase_blocks;
-static unsigned int apanic_good_blocks;
-
-static void set_bb(unsigned int block, unsigned int *bbt)
-{
- unsigned int flag = 1;
-
- BUG_ON(block >= apanic_erase_blocks);
-
- flag = flag << (block%32);
- apanic_bbt[block/32] |= flag;
- apanic_good_blocks--;
-}
-
-static unsigned int get_bb(unsigned int block, unsigned int *bbt)
-{
- unsigned int flag;
-
- BUG_ON(block >= apanic_erase_blocks);
-
- flag = 1 << (block%32);
- return apanic_bbt[block/32] & flag;
-}
-
-static void alloc_bbt(struct mtd_info *mtd, unsigned int *bbt)
-{
- int bbt_size;
- apanic_erase_blocks = (mtd->size)>>(mtd->erasesize_shift);
- bbt_size = (apanic_erase_blocks+32)/32;
-
- apanic_bbt = kmalloc(bbt_size*4, GFP_KERNEL);
- memset(apanic_bbt, 0, bbt_size*4);
- apanic_good_blocks = apanic_erase_blocks;
-}
-static void scan_bbt(struct mtd_info *mtd, unsigned int *bbt)
-{
- int i;
-
- for (i = 0; i < apanic_erase_blocks; i++) {
- if (mtd->block_isbad(mtd, i*mtd->erasesize))
- set_bb(i, apanic_bbt);
- }
-}
-
-#define APANIC_INVALID_OFFSET 0xFFFFFFFF
-
-static unsigned int phy_offset(struct mtd_info *mtd, unsigned int offset)
-{
- unsigned int logic_block = offset>>(mtd->erasesize_shift);
- unsigned int phy_block;
- unsigned good_block = 0;
-
- for (phy_block = 0; phy_block < apanic_erase_blocks; phy_block++) {
- if (!get_bb(phy_block, apanic_bbt))
- good_block++;
- if (good_block == (logic_block + 1))
- break;
- }
-
- if (good_block != (logic_block + 1))
- return APANIC_INVALID_OFFSET;
-
- return offset + ((phy_block-logic_block)<<mtd->erasesize_shift);
-}
-
static void apanic_erase_callback(struct erase_info *done)
{
wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv;
page_no = (file_offset + offset) / ctx->mtd->writesize;
page_offset = (file_offset + offset) % ctx->mtd->writesize;
-
- if (phy_offset(ctx->mtd, (page_no * ctx->mtd->writesize))
- == APANIC_INVALID_OFFSET) {
- pr_err("apanic: reading an invalid address\n");
- mutex_unlock(&drv_mutex);
- return -EINVAL;
- }
rc = ctx->mtd->read(ctx->mtd,
- phy_offset(ctx->mtd, (page_no * ctx->mtd->writesize)),
- ctx->mtd->writesize,
- &len, ctx->bounce);
+ (page_no * ctx->mtd->writesize),
+ ctx->mtd->writesize,
+ &len, ctx->bounce);
if (page_offset)
count -= page_offset;
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&wait_q, &wait);
- if (get_bb(erase.addr>>ctx->mtd->erasesize_shift, apanic_bbt)) {
+ rc = ctx->mtd->block_isbad(ctx->mtd, erase.addr);
+ if (rc < 0) {
+ printk(KERN_ERR
+ "apanic: Bad block check "
+ "failed (%d)\n", rc);
+ goto out;
+ }
+ if (rc) {
printk(KERN_WARNING
"apanic: Skipping erase of bad "
"block @%llx\n", erase.addr);
printk(KERN_INFO
"apanic: Marked a bad block"
" @%llx\n", erase.addr);
- set_bb(erase.addr>>ctx->mtd->erasesize_shift,
- apanic_bbt);
continue;
}
goto out;
ctx->mtd = mtd;
- alloc_bbt(mtd, apanic_bbt);
- scan_bbt(mtd, apanic_bbt);
-
- if (apanic_good_blocks == 0) {
- printk(KERN_ERR "apanic: no any good blocks?!\n");
+ if (mtd->block_isbad(mtd, 0)) {
+ printk(KERN_ERR "apanic: Offset 0 bad block. Boourns!\n");
goto out_err;
}
- rc = mtd->read(mtd, phy_offset(mtd, 0), mtd->writesize,
- &len, ctx->bounce);
+ rc = mtd->read(mtd, 0, mtd->writesize, &len, ctx->bounce);
if (rc && rc == -EBADMSG) {
printk(KERN_WARNING
"apanic: Bad ECC on block 0 (ignored)\n");
return 0;
}
- to = phy_offset(mtd, to);
- if (to == APANIC_INVALID_OFFSET) {
- printk(KERN_EMERG "apanic: write to invalid address\n");
- return 0;
- }
-
if (panic)
rc = mtd->panic_write(mtd, to, mtd->writesize, &wlen, buf);
else
break;
if (rc != mtd->writesize)
memset(ctx->bounce + rc, 0, mtd->writesize - rc);
+#if CHECK_BB
+check_badblock:
+ rc = mtd->block_isbad(mtd, off);
+ if (rc < 0) {
+ printk(KERN_ERR
+ "apanic: Bad block check "
+ "failed (%d)\n", rc);
+ }
+ if (rc) {
+ printk(KERN_WARNING
+ "apanic: Skipping over bad "
+ "block @%x\n", off);
+ off += mtd->erasesize;
+ printk("chk %u %llu\n", off, mtd->size);
+ if (off >= mtd->size) {
+ printk(KERN_EMERG
+ "apanic: Too many bad blocks!\n");
+ return -EIO;
+ }
+ goto check_badblock;
+ }
+#endif
rc2 = apanic_writeflashpage(mtd, off, ctx->bounce);
if (rc2 <= 0) {
printk(KERN_EMERG
"apanic: Flash write failed (%d)\n", rc2);
- return idx;
+ return rc2;
}
if (!last_chunk)
idx += rc2;
/* Ensure that cond_resched() won't try to preempt anybody */
add_preempt_count(PREEMPT_ACTIVE);
#endif
- touch_softlockup_watchdog();
if (!ctx->mtd)
goto out;