summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/devices/bcm47xxsflash.c3
-rw-r--r--drivers/mtd/ftl.c51
-rw-r--r--drivers/mtd/inftlmount.c5
-rw-r--r--drivers/mtd/mtdblock.c20
-rw-r--r--drivers/mtd/mtdchar.c33
-rw-r--r--drivers/mtd/mtdconcat.c48
-rw-r--r--drivers/mtd/mtdcore.c8
-rw-r--r--drivers/mtd/mtdoops.c19
-rw-r--r--drivers/mtd/mtdpart.c2
-rw-r--r--drivers/mtd/mtdswap.c32
-rw-r--r--drivers/mtd/nftlmount.c4
-rw-r--r--drivers/mtd/rfd_ftl.c92
-rw-r--r--drivers/mtd/sm_ftl.c18
-rw-r--r--drivers/mtd/sm_ftl.h4
-rw-r--r--drivers/mtd/tests/mtd_test.c4
-rw-r--r--drivers/mtd/tests/speedtest.c6
-rw-r--r--drivers/mtd/ubi/io.c35
-rw-r--r--fs/jffs2/erase.c36
-rw-r--r--include/linux/mtd/mtd.h2
19 files changed, 52 insertions, 370 deletions
diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c
index e2bd81817df4..6b84947cfbea 100644
--- a/drivers/mtd/devices/bcm47xxsflash.c
+++ b/drivers/mtd/devices/bcm47xxsflash.c
@@ -95,9 +95,6 @@ static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase)
95 else 95 else
96 erase->state = MTD_ERASE_DONE; 96 erase->state = MTD_ERASE_DONE;
97 97
98 if (erase->callback)
99 erase->callback(erase);
100
101 return err; 98 return err;
102} 99}
103 100
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 664d206a4cbe..fcf9907e7987 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -140,12 +140,6 @@ typedef struct partition_t {
140#define XFER_PREPARED 0x03 140#define XFER_PREPARED 0x03
141#define XFER_FAILED 0x04 141#define XFER_FAILED 0x04
142 142
143/*====================================================================*/
144
145
146static void ftl_erase_callback(struct erase_info *done);
147
148
149/*====================================================================== 143/*======================================================================
150 144
151 Scan_header() checks to see if a memory region contains an FTL 145 Scan_header() checks to see if a memory region contains an FTL
@@ -349,17 +343,19 @@ static int erase_xfer(partition_t *part,
349 return -ENOMEM; 343 return -ENOMEM;
350 344
351 erase->mtd = part->mbd.mtd; 345 erase->mtd = part->mbd.mtd;
352 erase->callback = ftl_erase_callback;
353 erase->addr = xfer->Offset; 346 erase->addr = xfer->Offset;
354 erase->len = 1 << part->header.EraseUnitSize; 347 erase->len = 1 << part->header.EraseUnitSize;
355 erase->priv = (u_long)part;
356 348
357 ret = mtd_erase(part->mbd.mtd, erase); 349 ret = mtd_erase(part->mbd.mtd, erase);
350 if (!ret) {
351 xfer->state = XFER_ERASED;
352 xfer->EraseCount++;
353 } else {
354 xfer->state = XFER_FAILED;
355 pr_notice("ftl_cs: erase failed: err = %d\n", ret);
356 }
358 357
359 if (!ret) 358 kfree(erase);
360 xfer->EraseCount++;
361 else
362 kfree(erase);
363 359
364 return ret; 360 return ret;
365} /* erase_xfer */ 361} /* erase_xfer */
@@ -371,37 +367,6 @@ static int erase_xfer(partition_t *part,
371 367
372======================================================================*/ 368======================================================================*/
373 369
374static void ftl_erase_callback(struct erase_info *erase)
375{
376 partition_t *part;
377 struct xfer_info_t *xfer;
378 int i;
379
380 /* Look up the transfer unit */
381 part = (partition_t *)(erase->priv);
382
383 for (i = 0; i < part->header.NumTransferUnits; i++)
384 if (part->XferInfo[i].Offset == erase->addr) break;
385
386 if (i == part->header.NumTransferUnits) {
387 printk(KERN_NOTICE "ftl_cs: internal error: "
388 "erase lookup failed!\n");
389 return;
390 }
391
392 xfer = &part->XferInfo[i];
393 if (erase->state == MTD_ERASE_DONE)
394 xfer->state = XFER_ERASED;
395 else {
396 xfer->state = XFER_FAILED;
397 printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
398 erase->state);
399 }
400
401 kfree(erase);
402
403} /* ftl_erase_callback */
404
405static int prepare_xfer(partition_t *part, int i) 370static int prepare_xfer(partition_t *part, int i)
406{ 371{
407 erase_unit_header_t header; 372 erase_unit_header_t header;
diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c
index 8d6bb189ea8e..0f47be4834d8 100644
--- a/drivers/mtd/inftlmount.c
+++ b/drivers/mtd/inftlmount.c
@@ -393,9 +393,10 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)
393 mark only the failed block in the bbt. */ 393 mark only the failed block in the bbt. */
394 for (physblock = 0; physblock < inftl->EraseSize; 394 for (physblock = 0; physblock < inftl->EraseSize;
395 physblock += instr->len, instr->addr += instr->len) { 395 physblock += instr->len, instr->addr += instr->len) {
396 mtd_erase(inftl->mbd.mtd, instr); 396 int ret;
397 397
398 if (instr->state == MTD_ERASE_FAILED) { 398 ret = mtd_erase(inftl->mbd.mtd, instr);
399 if (ret) {
399 printk(KERN_WARNING "INFTL: error while formatting block %d\n", 400 printk(KERN_WARNING "INFTL: error while formatting block %d\n",
400 block); 401 block);
401 goto fail; 402 goto fail;
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index bb4c14f83c75..7b2b7f651181 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -55,48 +55,28 @@ struct mtdblk_dev {
55 * being written to until a different sector is required. 55 * being written to until a different sector is required.
56 */ 56 */
57 57
58static void erase_callback(struct erase_info *done)
59{
60 wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
61 wake_up(wait_q);
62}
63
64static int erase_write (struct mtd_info *mtd, unsigned long pos, 58static int erase_write (struct mtd_info *mtd, unsigned long pos,
65 int len, const char *buf) 59 int len, const char *buf)
66{ 60{
67 struct erase_info erase; 61 struct erase_info erase;
68 DECLARE_WAITQUEUE(wait, current);
69 wait_queue_head_t wait_q;
70 size_t retlen; 62 size_t retlen;
71 int ret; 63 int ret;
72 64
73 /* 65 /*
74 * First, let's erase the flash block. 66 * First, let's erase the flash block.
75 */ 67 */
76
77 init_waitqueue_head(&wait_q);
78 erase.mtd = mtd; 68 erase.mtd = mtd;
79 erase.callback = erase_callback;
80 erase.addr = pos; 69 erase.addr = pos;
81 erase.len = len; 70 erase.len = len;
82 erase.priv = (u_long)&wait_q;
83
84 set_current_state(TASK_INTERRUPTIBLE);
85 add_wait_queue(&wait_q, &wait);
86 71
87 ret = mtd_erase(mtd, &erase); 72 ret = mtd_erase(mtd, &erase);
88 if (ret) { 73 if (ret) {
89 set_current_state(TASK_RUNNING);
90 remove_wait_queue(&wait_q, &wait);
91 printk (KERN_WARNING "mtdblock: erase of region [0x%lx, 0x%x] " 74 printk (KERN_WARNING "mtdblock: erase of region [0x%lx, 0x%x] "
92 "on \"%s\" failed\n", 75 "on \"%s\" failed\n",
93 pos, len, mtd->name); 76 pos, len, mtd->name);
94 return ret; 77 return ret;
95 } 78 }
96 79
97 schedule(); /* Wait for erase to finish. */
98 remove_wait_queue(&wait_q, &wait);
99
100 /* 80 /*
101 * Next, write the data to flash. 81 * Next, write the data to flash.
102 */ 82 */
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index de8c902059b8..2beb22dd6bbb 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -324,10 +324,6 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c
324 IOCTL calls for getting device parameters. 324 IOCTL calls for getting device parameters.
325 325
326======================================================================*/ 326======================================================================*/
327static void mtdchar_erase_callback (struct erase_info *instr)
328{
329 wake_up((wait_queue_head_t *)instr->priv);
330}
331 327
332static int otp_select_filemode(struct mtd_file_info *mfi, int mode) 328static int otp_select_filemode(struct mtd_file_info *mfi, int mode)
333{ 329{
@@ -709,11 +705,6 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
709 if (!erase) 705 if (!erase)
710 ret = -ENOMEM; 706 ret = -ENOMEM;
711 else { 707 else {
712 wait_queue_head_t waitq;
713 DECLARE_WAITQUEUE(wait, current);
714
715 init_waitqueue_head(&waitq);
716
717 if (cmd == MEMERASE64) { 708 if (cmd == MEMERASE64) {
718 struct erase_info_user64 einfo64; 709 struct erase_info_user64 einfo64;
719 710
@@ -736,30 +727,8 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
736 erase->len = einfo32.length; 727 erase->len = einfo32.length;
737 } 728 }
738 erase->mtd = mtd; 729 erase->mtd = mtd;
739 erase->callback = mtdchar_erase_callback; 730
740 erase->priv = (unsigned long)&waitq;
741
742 /*
743 FIXME: Allow INTERRUPTIBLE. Which means
744 not having the wait_queue head on the stack.
745
746 If the wq_head is on the stack, and we
747 leave because we got interrupted, then the
748 wq_head is no longer there when the
749 callback routine tries to wake us up.
750 */
751 ret = mtd_erase(mtd, erase); 731 ret = mtd_erase(mtd, erase);
752 if (!ret) {
753 set_current_state(TASK_UNINTERRUPTIBLE);
754 add_wait_queue(&waitq, &wait);
755 if (erase->state != MTD_ERASE_DONE &&
756 erase->state != MTD_ERASE_FAILED)
757 schedule();
758 remove_wait_queue(&waitq, &wait);
759 set_current_state(TASK_RUNNING);
760
761 ret = (erase->state == MTD_ERASE_FAILED)?-EIO:0;
762 }
763 kfree(erase); 732 kfree(erase);
764 } 733 }
765 break; 734 break;
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index 60bf53df5454..caa09bf6e572 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -333,45 +333,6 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
333 return -EINVAL; 333 return -EINVAL;
334} 334}
335 335
336static void concat_erase_callback(struct erase_info *instr)
337{
338 wake_up((wait_queue_head_t *) instr->priv);
339}
340
341static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
342{
343 int err;
344 wait_queue_head_t waitq;
345 DECLARE_WAITQUEUE(wait, current);
346
347 /*
348 * This code was stol^H^H^H^Hinspired by mtdchar.c
349 */
350 init_waitqueue_head(&waitq);
351
352 erase->mtd = mtd;
353 erase->callback = concat_erase_callback;
354 erase->priv = (unsigned long) &waitq;
355
356 /*
357 * FIXME: Allow INTERRUPTIBLE. Which means
358 * not having the wait_queue head on the stack.
359 */
360 err = mtd_erase(mtd, erase);
361 if (!err) {
362 set_current_state(TASK_UNINTERRUPTIBLE);
363 add_wait_queue(&waitq, &wait);
364 if (erase->state != MTD_ERASE_DONE
365 && erase->state != MTD_ERASE_FAILED)
366 schedule();
367 remove_wait_queue(&waitq, &wait);
368 set_current_state(TASK_RUNNING);
369
370 err = (erase->state == MTD_ERASE_FAILED) ? -EIO : 0;
371 }
372 return err;
373}
374
375static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) 336static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
376{ 337{
377 struct mtd_concat *concat = CONCAT(mtd); 338 struct mtd_concat *concat = CONCAT(mtd);
@@ -466,7 +427,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
466 erase->len = length; 427 erase->len = length;
467 428
468 length -= erase->len; 429 length -= erase->len;
469 if ((err = concat_dev_erase(subdev, erase))) { 430 erase->mtd = subdev;
431 if ((err = mtd_erase(subdev, erase))) {
470 /* sanity check: should never happen since 432 /* sanity check: should never happen since
471 * block alignment has been checked above */ 433 * block alignment has been checked above */
472 BUG_ON(err == -EINVAL); 434 BUG_ON(err == -EINVAL);
@@ -487,12 +449,8 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
487 } 449 }
488 instr->state = erase->state; 450 instr->state = erase->state;
489 kfree(erase); 451 kfree(erase);
490 if (err)
491 return err;
492 452
493 if (instr->callback) 453 return err;
494 instr->callback(instr);
495 return 0;
496} 454}
497 455
498static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) 456static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index c87859ff338b..f92ad02959eb 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -945,11 +945,9 @@ void __put_mtd_device(struct mtd_info *mtd)
945EXPORT_SYMBOL_GPL(__put_mtd_device); 945EXPORT_SYMBOL_GPL(__put_mtd_device);
946 946
947/* 947/*
948 * Erase is an asynchronous operation. Device drivers are supposed 948 * Erase is an synchronous operation. Device drivers are epected to return a
949 * to call instr->callback() whenever the operation completes, even 949 * negative error code if the operation failed and update instr->fail_addr
950 * if it completes with a failure. 950 * to point the portion that was not properly erased.
951 * Callers are supposed to pass a callback function and wait for it
952 * to be called before writing to the block.
953 */ 951 */
954int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) 952int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
955{ 953{
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 97bb8f6304d4..028ded59297b 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -84,12 +84,6 @@ static int page_is_used(struct mtdoops_context *cxt, int page)
84 return test_bit(page, cxt->oops_page_used); 84 return test_bit(page, cxt->oops_page_used);
85} 85}
86 86
87static void mtdoops_erase_callback(struct erase_info *done)
88{
89 wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
90 wake_up(wait_q);
91}
92
93static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset) 87static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
94{ 88{
95 struct mtd_info *mtd = cxt->mtd; 89 struct mtd_info *mtd = cxt->mtd;
@@ -97,34 +91,21 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
97 u32 start_page = start_page_offset / record_size; 91 u32 start_page = start_page_offset / record_size;
98 u32 erase_pages = mtd->erasesize / record_size; 92 u32 erase_pages = mtd->erasesize / record_size;
99 struct erase_info erase; 93 struct erase_info erase;
100 DECLARE_WAITQUEUE(wait, current);
101 wait_queue_head_t wait_q;
102 int ret; 94 int ret;
103 int page; 95 int page;
104 96
105 init_waitqueue_head(&wait_q);
106 erase.mtd = mtd; 97 erase.mtd = mtd;
107 erase.callback = mtdoops_erase_callback;
108 erase.addr = offset; 98 erase.addr = offset;
109 erase.len = mtd->erasesize; 99 erase.len = mtd->erasesize;
110 erase.priv = (u_long)&wait_q;
111
112 set_current_state(TASK_INTERRUPTIBLE);
113 add_wait_queue(&wait_q, &wait);
114 100
115 ret = mtd_erase(mtd, &erase); 101 ret = mtd_erase(mtd, &erase);
116 if (ret) { 102 if (ret) {
117 set_current_state(TASK_RUNNING);
118 remove_wait_queue(&wait_q, &wait);
119 printk(KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] on \"%s\" failed\n", 103 printk(KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] on \"%s\" failed\n",
120 (unsigned long long)erase.addr, 104 (unsigned long long)erase.addr,
121 (unsigned long long)erase.len, mtddev); 105 (unsigned long long)erase.len, mtddev);
122 return ret; 106 return ret;
123 } 107 }
124 108
125 schedule(); /* Wait for erase to finish. */
126 remove_wait_queue(&wait_q, &wait);
127
128 /* Mark pages as unused */ 109 /* Mark pages as unused */
129 for (page = start_page; page < start_page + erase_pages; page++) 110 for (page = start_page; page < start_page + erase_pages; page++)
130 mark_page_unused(cxt, page); 111 mark_page_unused(cxt, page);
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 76cd21d1171b..ae1206633d9d 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -222,8 +222,6 @@ void mtd_erase_callback(struct erase_info *instr)
222 instr->fail_addr -= part->offset; 222 instr->fail_addr -= part->offset;
223 instr->addr -= part->offset; 223 instr->addr -= part->offset;
224 } 224 }
225 if (instr->callback)
226 instr->callback(instr);
227} 225}
228EXPORT_SYMBOL_GPL(mtd_erase_callback); 226EXPORT_SYMBOL_GPL(mtd_erase_callback);
229 227
diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c
index 7eb0e1f4f980..d390324d102e 100644
--- a/drivers/mtd/mtdswap.c
+++ b/drivers/mtd/mtdswap.c
@@ -536,18 +536,10 @@ static void mtdswap_store_eb(struct mtdswap_dev *d, struct swap_eb *eb)
536 mtdswap_rb_add(d, eb, MTDSWAP_HIFRAG); 536 mtdswap_rb_add(d, eb, MTDSWAP_HIFRAG);
537} 537}
538 538
539
540static void mtdswap_erase_callback(struct erase_info *done)
541{
542 wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;
543 wake_up(wait_q);
544}
545
546static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb) 539static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb)
547{ 540{
548 struct mtd_info *mtd = d->mtd; 541 struct mtd_info *mtd = d->mtd;
549 struct erase_info erase; 542 struct erase_info erase;
550 wait_queue_head_t wq;
551 unsigned int retries = 0; 543 unsigned int retries = 0;
552 int ret; 544 int ret;
553 545
@@ -556,14 +548,11 @@ static int mtdswap_erase_block(struct mtdswap_dev *d, struct swap_eb *eb)
556 d->max_erase_count = eb->erase_count; 548 d->max_erase_count = eb->erase_count;
557 549
558retry: 550retry:
559 init_waitqueue_head(&wq);
560 memset(&erase, 0, sizeof(struct erase_info)); 551 memset(&erase, 0, sizeof(struct erase_info));
561 552
562 erase.mtd = mtd; 553 erase.mtd = mtd;
563 erase.callback = mtdswap_erase_callback;
564 erase.addr = mtdswap_eb_offset(d, eb); 554 erase.addr = mtdswap_eb_offset(d, eb);
565 erase.len = mtd->erasesize; 555 erase.len = mtd->erasesize;
566 erase.priv = (u_long)&wq;
567 556
568 ret = mtd_erase(mtd, &erase); 557 ret = mtd_erase(mtd, &erase);
569 if (ret) { 558 if (ret) {
@@ -582,27 +571,6 @@ retry:
582 return -EIO; 571 return -EIO;
583 } 572 }
584 573
585 ret = wait_event_interruptible(wq, erase.state == MTD_ERASE_DONE ||
586 erase.state == MTD_ERASE_FAILED);
587 if (ret) {
588 dev_err(d->dev, "Interrupted erase block %#llx erasure on %s\n",
589 erase.addr, mtd->name);
590 return -EINTR;
591 }
592
593 if (erase.state == MTD_ERASE_FAILED) {
594 if (retries++ < MTDSWAP_ERASE_RETRIES) {
595 dev_warn(d->dev,
596 "erase of erase block %#llx on %s failed",
597 erase.addr, mtd->name);
598 yield();
599 goto retry;
600 }
601
602 mtdswap_handle_badblock(d, eb);
603 return -EIO;
604 }
605
606 return 0; 574 return 0;
607} 575}
608 576
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
index 184c8fbfe465..07e122449759 100644
--- a/drivers/mtd/nftlmount.c
+++ b/drivers/mtd/nftlmount.c
@@ -331,9 +331,7 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
331 instr->mtd = nftl->mbd.mtd; 331 instr->mtd = nftl->mbd.mtd;
332 instr->addr = block * nftl->EraseSize; 332 instr->addr = block * nftl->EraseSize;
333 instr->len = nftl->EraseSize; 333 instr->len = nftl->EraseSize;
334 mtd_erase(mtd, instr); 334 if (mtd_erase(mtd, instr)) {
335
336 if (instr->state == MTD_ERASE_FAILED) {
337 printk("Error while formatting block %d\n", block); 335 printk("Error while formatting block %d\n", block);
338 goto fail; 336 goto fail;
339 } 337 }
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index d1cbf26db2c0..4e0b55cd08e2 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -266,91 +266,55 @@ static int rfd_ftl_readsect(struct mtd_blktrans_dev *dev, u_long sector, char *b
266 return 0; 266 return 0;
267} 267}
268 268
269static void erase_callback(struct erase_info *erase)
270{
271 struct partition *part;
272 u16 magic;
273 int i, rc;
274 size_t retlen;
275
276 part = (struct partition*)erase->priv;
277
278 i = (u32)erase->addr / part->block_size;
279 if (i >= part->total_blocks || part->blocks[i].offset != erase->addr ||
280 erase->addr > UINT_MAX) {
281 printk(KERN_ERR PREFIX "erase callback for unknown offset %llx "
282 "on '%s'\n", (unsigned long long)erase->addr, part->mbd.mtd->name);
283 return;
284 }
285
286 if (erase->state != MTD_ERASE_DONE) {
287 printk(KERN_WARNING PREFIX "erase failed at 0x%llx on '%s', "
288 "state %d\n", (unsigned long long)erase->addr,
289 part->mbd.mtd->name, erase->state);
290
291 part->blocks[i].state = BLOCK_FAILED;
292 part->blocks[i].free_sectors = 0;
293 part->blocks[i].used_sectors = 0;
294
295 kfree(erase);
296
297 return;
298 }
299
300 magic = cpu_to_le16(RFD_MAGIC);
301
302 part->blocks[i].state = BLOCK_ERASED;
303 part->blocks[i].free_sectors = part->data_sectors_per_block;
304 part->blocks[i].used_sectors = 0;
305 part->blocks[i].erases++;
306
307 rc = mtd_write(part->mbd.mtd, part->blocks[i].offset, sizeof(magic),
308 &retlen, (u_char *)&magic);
309
310 if (!rc && retlen != sizeof(magic))
311 rc = -EIO;
312
313 if (rc) {
314 printk(KERN_ERR PREFIX "'%s': unable to write RFD "
315 "header at 0x%lx\n",
316 part->mbd.mtd->name,
317 part->blocks[i].offset);
318 part->blocks[i].state = BLOCK_FAILED;
319 }
320 else
321 part->blocks[i].state = BLOCK_OK;
322
323 kfree(erase);
324}
325
326static int erase_block(struct partition *part, int block) 269static int erase_block(struct partition *part, int block)
327{ 270{
328 struct erase_info *erase; 271 struct erase_info *erase;
329 int rc = -ENOMEM; 272 int rc;
330 273
331 erase = kmalloc(sizeof(struct erase_info), GFP_KERNEL); 274 erase = kmalloc(sizeof(struct erase_info), GFP_KERNEL);
332 if (!erase) 275 if (!erase)
333 goto err; 276 return -ENOMEM;
334 277
335 erase->mtd = part->mbd.mtd; 278 erase->mtd = part->mbd.mtd;
336 erase->callback = erase_callback;
337 erase->addr = part->blocks[block].offset; 279 erase->addr = part->blocks[block].offset;
338 erase->len = part->block_size; 280 erase->len = part->block_size;
339 erase->priv = (u_long)part;
340 281
341 part->blocks[block].state = BLOCK_ERASING; 282 part->blocks[block].state = BLOCK_ERASING;
342 part->blocks[block].free_sectors = 0; 283 part->blocks[block].free_sectors = 0;
343 284
344 rc = mtd_erase(part->mbd.mtd, erase); 285 rc = mtd_erase(part->mbd.mtd, erase);
345
346 if (rc) { 286 if (rc) {
347 printk(KERN_ERR PREFIX "erase of region %llx,%llx on '%s' " 287 printk(KERN_ERR PREFIX "erase of region %llx,%llx on '%s' "
348 "failed\n", (unsigned long long)erase->addr, 288 "failed\n", (unsigned long long)erase->addr,
349 (unsigned long long)erase->len, part->mbd.mtd->name); 289 (unsigned long long)erase->len, part->mbd.mtd->name);
350 kfree(erase); 290 part->blocks[block].state = BLOCK_FAILED;
291 part->blocks[block].free_sectors = 0;
292 part->blocks[block].used_sectors = 0;
293 } else {
294 u16 magic = cpu_to_le16(RFD_MAGIC);
295 size_t retlen;
296
297 part->blocks[block].state = BLOCK_ERASED;
298 part->blocks[block].free_sectors = part->data_sectors_per_block;
299 part->blocks[block].used_sectors = 0;
300 part->blocks[block].erases++;
301
302 rc = mtd_write(part->mbd.mtd, part->blocks[block].offset,
303 sizeof(magic), &retlen, (u_char *)&magic);
304 if (!rc && retlen != sizeof(magic))
305 rc = -EIO;
306
307 if (rc) {
308 pr_err(PREFIX "'%s': unable to write RFD header at 0x%lx\n",
309 part->mbd.mtd->name, part->blocks[block].offset);
310 part->blocks[block].state = BLOCK_FAILED;
311 } else {
312 part->blocks[block].state = BLOCK_OK;
313 }
351 } 314 }
352 315
353err: 316 kfree(erase);
317
354 return rc; 318 return rc;
355} 319}
356 320
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c
index 4237c7cebf02..c11156f9d96f 100644
--- a/drivers/mtd/sm_ftl.c
+++ b/drivers/mtd/sm_ftl.c
@@ -461,10 +461,8 @@ static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block,
461 struct erase_info erase; 461 struct erase_info erase;
462 462
463 erase.mtd = mtd; 463 erase.mtd = mtd;
464 erase.callback = sm_erase_callback;
465 erase.addr = sm_mkoffset(ftl, zone_num, block, 0); 464 erase.addr = sm_mkoffset(ftl, zone_num, block, 0);
466 erase.len = ftl->block_size; 465 erase.len = ftl->block_size;
467 erase.priv = (u_long)ftl;
468 466
469 if (ftl->unstable) 467 if (ftl->unstable)
470 return -EIO; 468 return -EIO;
@@ -482,15 +480,6 @@ static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block,
482 goto error; 480 goto error;
483 } 481 }
484 482
485 if (erase.state == MTD_ERASE_PENDING)
486 wait_for_completion(&ftl->erase_completion);
487
488 if (erase.state != MTD_ERASE_DONE) {
489 sm_printk("erase of block %d in zone %d failed after wait",
490 block, zone_num);
491 goto error;
492 }
493
494 if (put_free) 483 if (put_free)
495 kfifo_in(&zone->free_sectors, 484 kfifo_in(&zone->free_sectors,
496 (const unsigned char *)&block, sizeof(block)); 485 (const unsigned char *)&block, sizeof(block));
@@ -501,12 +490,6 @@ error:
501 return -EIO; 490 return -EIO;
502} 491}
503 492
504static void sm_erase_callback(struct erase_info *self)
505{
506 struct sm_ftl *ftl = (struct sm_ftl *)self->priv;
507 complete(&ftl->erase_completion);
508}
509
510/* Thoroughly test that block is valid. */ 493/* Thoroughly test that block is valid. */
511static int sm_check_block(struct sm_ftl *ftl, int zone, int block) 494static int sm_check_block(struct sm_ftl *ftl, int zone, int block)
512{ 495{
@@ -1141,7 +1124,6 @@ static void sm_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
1141 mutex_init(&ftl->mutex); 1124 mutex_init(&ftl->mutex);
1142 timer_setup(&ftl->timer, sm_cache_flush_timer, 0); 1125 timer_setup(&ftl->timer, sm_cache_flush_timer, 0);
1143 INIT_WORK(&ftl->flush_work, sm_cache_flush_work); 1126 INIT_WORK(&ftl->flush_work, sm_cache_flush_work);
1144 init_completion(&ftl->erase_completion);
1145 1127
1146 /* Read media information */ 1128 /* Read media information */
1147 if (sm_get_media_info(ftl, mtd)) { 1129 if (sm_get_media_info(ftl, mtd)) {
diff --git a/drivers/mtd/sm_ftl.h b/drivers/mtd/sm_ftl.h
index 43bb7300785b..0a46d75cdc6a 100644
--- a/drivers/mtd/sm_ftl.h
+++ b/drivers/mtd/sm_ftl.h
@@ -53,9 +53,6 @@ struct sm_ftl {
53 struct work_struct flush_work; 53 struct work_struct flush_work;
54 struct timer_list timer; 54 struct timer_list timer;
55 55
56 /* Async erase stuff */
57 struct completion erase_completion;
58
59 /* Geometry stuff */ 56 /* Geometry stuff */
60 int heads; 57 int heads;
61 int sectors; 58 int sectors;
@@ -86,7 +83,6 @@ struct chs_entry {
86 printk(KERN_DEBUG "sm_ftl" ": " format "\n", ## __VA_ARGS__) 83 printk(KERN_DEBUG "sm_ftl" ": " format "\n", ## __VA_ARGS__)
87 84
88 85
89static void sm_erase_callback(struct erase_info *self);
90static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block, 86static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block,
91 int put_free); 87 int put_free);
92static void sm_mark_block_bad(struct sm_ftl *ftl, int zone_num, int block); 88static void sm_mark_block_bad(struct sm_ftl *ftl, int zone_num, int block);
diff --git a/drivers/mtd/tests/mtd_test.c b/drivers/mtd/tests/mtd_test.c
index 3d0b8b5c1a53..0ac625e8f798 100644
--- a/drivers/mtd/tests/mtd_test.c
+++ b/drivers/mtd/tests/mtd_test.c
@@ -24,10 +24,6 @@ int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum)
24 return err; 24 return err;
25 } 25 }
26 26
27 if (ei.state == MTD_ERASE_FAILED) {
28 pr_info("some erase error occurred at EB %d\n", ebnum);
29 return -EIO;
30 }
31 return 0; 27 return 0;
32} 28}
33 29
diff --git a/drivers/mtd/tests/speedtest.c b/drivers/mtd/tests/speedtest.c
index 0b89418a0888..f8e5dc11f943 100644
--- a/drivers/mtd/tests/speedtest.c
+++ b/drivers/mtd/tests/speedtest.c
@@ -70,12 +70,6 @@ static int multiblock_erase(int ebnum, int blocks)
70 return err; 70 return err;
71 } 71 }
72 72
73 if (ei.state == MTD_ERASE_FAILED) {
74 pr_err("some erase error occurred at EB %d,"
75 "blocks %d\n", ebnum, blocks);
76 return -EIO;
77 }
78
79 return 0; 73 return 0;
80} 74}
81 75
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 8290432017ce..8843d26837b2 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -309,18 +309,6 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset,
309} 309}
310 310
311/** 311/**
312 * erase_callback - MTD erasure call-back.
313 * @ei: MTD erase information object.
314 *
315 * Note, even though MTD erase interface is asynchronous, all the current
316 * implementations are synchronous anyway.
317 */
318static void erase_callback(struct erase_info *ei)
319{
320 wake_up_interruptible((wait_queue_head_t *)ei->priv);
321}
322
323/**
324 * do_sync_erase - synchronously erase a physical eraseblock. 312 * do_sync_erase - synchronously erase a physical eraseblock.
325 * @ubi: UBI device description object 313 * @ubi: UBI device description object
326 * @pnum: the physical eraseblock number to erase 314 * @pnum: the physical eraseblock number to erase
@@ -333,7 +321,6 @@ static int do_sync_erase(struct ubi_device *ubi, int pnum)
333{ 321{
334 int err, retries = 0; 322 int err, retries = 0;
335 struct erase_info ei; 323 struct erase_info ei;
336 wait_queue_head_t wq;
337 324
338 dbg_io("erase PEB %d", pnum); 325 dbg_io("erase PEB %d", pnum);
339 ubi_assert(pnum >= 0 && pnum < ubi->peb_count); 326 ubi_assert(pnum >= 0 && pnum < ubi->peb_count);
@@ -344,14 +331,11 @@ static int do_sync_erase(struct ubi_device *ubi, int pnum)
344 } 331 }
345 332
346retry: 333retry:
347 init_waitqueue_head(&wq);
348 memset(&ei, 0, sizeof(struct erase_info)); 334 memset(&ei, 0, sizeof(struct erase_info));
349 335
350 ei.mtd = ubi->mtd; 336 ei.mtd = ubi->mtd;
351 ei.addr = (loff_t)pnum * ubi->peb_size; 337 ei.addr = (loff_t)pnum * ubi->peb_size;
352 ei.len = ubi->peb_size; 338 ei.len = ubi->peb_size;
353 ei.callback = erase_callback;
354 ei.priv = (unsigned long)&wq;
355 339
356 err = mtd_erase(ubi->mtd, &ei); 340 err = mtd_erase(ubi->mtd, &ei);
357 if (err) { 341 if (err) {
@@ -366,25 +350,6 @@ retry:
366 return err; 350 return err;
367 } 351 }
368 352
369 err = wait_event_interruptible(wq, ei.state == MTD_ERASE_DONE ||
370 ei.state == MTD_ERASE_FAILED);
371 if (err) {
372 ubi_err(ubi, "interrupted PEB %d erasure", pnum);
373 return -EINTR;
374 }
375
376 if (ei.state == MTD_ERASE_FAILED) {
377 if (retries++ < UBI_IO_RETRIES) {
378 ubi_warn(ubi, "error while erasing PEB %d, retry",
379 pnum);
380 yield();
381 goto retry;
382 }
383 ubi_err(ubi, "cannot erase PEB %d", pnum);
384 dump_stack();
385 return -EIO;
386 }
387
388 err = ubi_self_check_all_ff(ubi, pnum, 0, ubi->peb_size); 353 err = ubi_self_check_all_ff(ubi, pnum, 0, ubi->peb_size);
389 if (err) 354 if (err)
390 return err; 355 return err;
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index 4a6cf289be24..09bb6c00b869 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -21,14 +21,6 @@
21#include <linux/pagemap.h> 21#include <linux/pagemap.h>
22#include "nodelist.h" 22#include "nodelist.h"
23 23
24struct erase_priv_struct {
25 struct jffs2_eraseblock *jeb;
26 struct jffs2_sb_info *c;
27};
28
29#ifndef __ECOS
30static void jffs2_erase_callback(struct erase_info *);
31#endif
32static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset); 24static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
33static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); 25static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
34static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); 26static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb);
@@ -51,7 +43,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
51 jffs2_dbg(1, "%s(): erase block %#08x (range %#08x-%#08x)\n", 43 jffs2_dbg(1, "%s(): erase block %#08x (range %#08x-%#08x)\n",
52 __func__, 44 __func__,
53 jeb->offset, jeb->offset, jeb->offset + c->sector_size); 45 jeb->offset, jeb->offset, jeb->offset + c->sector_size);
54 instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); 46 instr = kmalloc(sizeof(struct erase_info), GFP_KERNEL);
55 if (!instr) { 47 if (!instr) {
56 pr_warn("kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); 48 pr_warn("kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
57 mutex_lock(&c->erase_free_sem); 49 mutex_lock(&c->erase_free_sem);
@@ -70,15 +62,13 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
70 instr->mtd = c->mtd; 62 instr->mtd = c->mtd;
71 instr->addr = jeb->offset; 63 instr->addr = jeb->offset;
72 instr->len = c->sector_size; 64 instr->len = c->sector_size;
73 instr->callback = jffs2_erase_callback;
74 instr->priv = (unsigned long)(&instr[1]);
75
76 ((struct erase_priv_struct *)instr->priv)->jeb = jeb;
77 ((struct erase_priv_struct *)instr->priv)->c = c;
78 65
79 ret = mtd_erase(c->mtd, instr); 66 ret = mtd_erase(c->mtd, instr);
80 if (!ret) 67 if (!ret) {
68 jffs2_erase_succeeded(c, jeb);
69 kfree(instr);
81 return; 70 return;
71 }
82 72
83 bad_offset = instr->fail_addr; 73 bad_offset = instr->fail_addr;
84 kfree(instr); 74 kfree(instr);
@@ -214,22 +204,6 @@ static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock
214 wake_up(&c->erase_wait); 204 wake_up(&c->erase_wait);
215} 205}
216 206
217#ifndef __ECOS
218static void jffs2_erase_callback(struct erase_info *instr)
219{
220 struct erase_priv_struct *priv = (void *)instr->priv;
221
222 if(instr->state != MTD_ERASE_DONE) {
223 pr_warn("Erase at 0x%08llx finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n",
224 (unsigned long long)instr->addr, instr->state);
225 jffs2_erase_failed(priv->c, priv->jeb, instr->fail_addr);
226 } else {
227 jffs2_erase_succeeded(priv->c, priv->jeb);
228 }
229 kfree(instr);
230}
231#endif /* !__ECOS */
232
233/* Hmmm. Maybe we should accept the extra space it takes and make 207/* Hmmm. Maybe we should accept the extra space it takes and make
234 this a standard doubly-linked list? */ 208 this a standard doubly-linked list? */
235static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, 209static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 2a407dc9beaa..5018437d7999 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -48,8 +48,6 @@ struct erase_info {
48 uint64_t addr; 48 uint64_t addr;
49 uint64_t len; 49 uint64_t len;
50 uint64_t fail_addr; 50 uint64_t fail_addr;
51 void (*callback) (struct erase_info *self);
52 u_long priv;
53 u_char state; 51 u_char state;
54}; 52};
55 53