[PATCH 2/3] Don't change transfer speed while requests are in flight

From: Suleiman Souhlal
Date: Tue Feb 20 2007 - 20:44:42 EST


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 <suleiman@xxxxxxxxxx>

---
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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/