aboutsummaryrefslogtreecommitdiff
path: root/drivers/ide
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt2005-10-09 10:37:47 +1000
committerLinus Torvalds2005-10-10 08:40:47 -0700
commit867f8b4e47a17c5d68c98dc6eee12739c4490056 (patch)
tree67391ec05e7fa70496767c8dddc525eae3a38bb4 /drivers/ide
parent1cc956e12aedfdc6baf6312bc36a6b5a71af3c9d (diff)
[PATCH] ide: Workaround PM problem
The logic in ide_do_request() doesn't guarantee that both drives will be serviced after a call. It may "forget" to service one in some circumstances, including when one of the drive is suspended (it will eventually fail to service the slave when the master is suspended for example). This prevents the wakeup requests that gets queued on wakeup from sleep from beeing serviced in some cases when 2 drives are sharing an IDE bus. The problem is deep enough in the way this code works (and there are probably a few other problematic but rare corner cases) and fixing it would require some major rethinking of the way IDE decides which channel to service. This is not 2.6.14 material. However, in the meantime, Bart has accepted this simple workaround that will fix the crash on wakeup from sleep since this specific corner case is actually hitting users to get into 2.6.14. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/ide')
-rw-r--r--drivers/ide/ide-io.c8
1 files changed, 8 insertions, 0 deletions
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 9e9cf1407311..5275cbb1afe9 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -1101,6 +1101,7 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
ide_hwif_t *hwif;
struct request *rq;
ide_startstop_t startstop;
+ int loops = 0;
/* for atari only: POSSIBLY BROKEN HERE(?) */
ide_get_lock(ide_intr, hwgroup);
@@ -1153,6 +1154,7 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
/* no more work for this hwgroup (for now) */
return;
}
+ again:
hwif = HWIF(drive);
if (hwgroup->hwif->sharing_irq &&
hwif != hwgroup->hwif &&
@@ -1192,8 +1194,14 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
* though. I hope that doesn't happen too much, hopefully not
* unless the subdriver triggers such a thing in its own PM
* state machine.
+ *
+ * We count how many times we loop here to make sure we service
+ * all drives in the hwgroup without looping for ever
*/
if (drive->blocked && !blk_pm_request(rq) && !(rq->flags & REQ_PREEMPT)) {
+ drive = drive->next ? drive->next : hwgroup->drive;
+ if (loops++ < 4 && !blk_queue_plugged(drive->queue))
+ goto again;
/* We clear busy, there should be no pending ATA command at this point. */
hwgroup->busy = 0;
break;