Use ide_wait_cmd() in ide_config_drive_speed() if the drive has been
initialized and we're not in an interrupt, to avoid changing the
xfer speed while requests are in flight.
An easy way to trigger the problem is to dd the disk while doing
while :; do hdparm -d 1 /dev/hdc> /dev/null; done
While there, remove some commented-out code.
Signed-off-by: Suleiman Souhlal <[email protected]>
---
drivers/ide/ide-iops.c | 35 ++++++++++++++++++++---------------
1 files changed, 20 insertions(+), 15 deletions(-)
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index c67b3b1..35ab3af 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -748,32 +748,36 @@ int ide_config_drive_speed (ide_drive_t
int i, error = 1;
u8 stat;
-// while (HWGROUP(drive)->busy)
-// msleep(50);
+ /*
+ * Just use ide_wait_cmd() if the drive has been initialized and we
+ * aren't in an interrupt handler, to avoid changing the xfer speed
+ * while requests are in flight.
+ *
+ * If we are in an interrupt, it should be safe to issue
+ * SETFEATURES manually, since there shouldn't be any requests in
+ * flight.
+ */
+ if (drive->queue != NULL && !in_interrupt()) {
+ error = ide_wait_cmd(drive, WIN_SETFEATURES, speed,
+ SETFEATURES_XFER, 0, NULL);
+ if (error) {
+ stat = hwif->INB(IDE_STATUS_REG);
+ ide_dump_status(drive, "set_drive_speed_status", stat);
+ return (error);
+ }
+ goto done;
+ }
#ifdef CONFIG_BLK_DEV_IDEDMA
if (hwif->ide_dma_check) /* check if host supports DMA */
hwif->dma_host_off(drive);
#endif
- /*
- * Don't use ide_wait_cmd here - it will
- * attempt to set_geometry and recalibrate,
- * but for some reason these don't work at
- * this point (lost interrupt).
- */
/*
* Select the drive, and issue the SETFEATURES command
*/
disable_irq_nosync(hwif->irq);
- /*
- * FIXME: we race against the running IRQ here if
- * this is called from non IRQ context. If we use
- * disable_irq() we hang on the error path. Work
- * is needed.
- */
-
udelay(1);
SELECT_DRIVE(drive);
SELECT_MASK(drive, 0);
@@ -835,6 +839,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA
hwif->dma_off_quietly(drive);
#endif
+done:
switch(speed) {
case XFER_UDMA_7: drive->id->dma_ultra |= 0x8080; break;
case XFER_UDMA_6: drive->id->dma_ultra |= 0x4040; break;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]