summaryrefslogtreecommitdiff
path: root/drivers/ide/ide-iops.c
diff options
context:
space:
mode:
authorElias Oltmanns <eo@nebensachen.de>2008-07-16 20:33:48 +0200
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2008-07-16 20:33:48 +0200
commit79e36a9f54aaf4a52eb2d9520953aa3960e99294 (patch)
tree70fae17d64a1facde8541184d7139c4bc12d03bf /drivers/ide/ide-iops.c
parent72a3d651b2fe341a8ae2ca164c395aa3007350cd (diff)
downloadlwn-79e36a9f54aaf4a52eb2d9520953aa3960e99294.tar.gz
lwn-79e36a9f54aaf4a52eb2d9520953aa3960e99294.zip
IDE: Fix HDIO_DRIVE_RESET handling
Currently, the code path executing an HDIO_DRIVE_RESET ioctl is broken in various ways. Most importantly, it is treated as an out of band request in an illegal way which may very likely lead to system lock ups. Use the drive's request queue to avoid this problem (and fix a locking issue for free along the way). Signed-off-by: Elias Oltmanns <eo@nebensachen.de> Cc: "Alan Cox" <alan@lxorguk.ukuu.org.uk> Cc: "Randy Dunlap" <randy.dunlap@oracle.com> Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers/ide/ide-iops.c')
-rw-r--r--drivers/ide/ide-iops.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 80ad4f234f3f..96f63eb12092 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -905,6 +905,14 @@ void ide_execute_pkt_cmd(ide_drive_t *drive)
}
EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd);
+static inline void ide_complete_drive_reset(ide_drive_t *drive)
+{
+ struct request *rq = drive->hwif->hwgroup->rq;
+
+ if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET)
+ ide_end_request(drive, 1, 0);
+}
+
/* needed below */
static ide_startstop_t do_reset1 (ide_drive_t *, int);
@@ -940,7 +948,7 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
}
/* done polling */
hwgroup->polling = 0;
- hwgroup->resetting = 0;
+ ide_complete_drive_reset(drive);
return ide_stopped;
}
@@ -961,7 +969,7 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
if (port_ops->reset_poll(drive)) {
printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
hwif->name, drive->name);
- return ide_stopped;
+ goto out;
}
}
@@ -1004,7 +1012,8 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
}
}
hwgroup->polling = 0; /* done polling */
- hwgroup->resetting = 0; /* done reset attempt */
+out:
+ ide_complete_drive_reset(drive);
return ide_stopped;
}
@@ -1090,7 +1099,6 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
/* For an ATAPI device, first try an ATAPI SRST. */
if (drive->media != ide_disk && !do_not_try_atapi) {
- hwgroup->resetting = 1;
pre_reset(drive);
SELECT_DRIVE(drive);
udelay (20);
@@ -1112,10 +1120,10 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
if (io_ports->ctl_addr == 0) {
spin_unlock_irqrestore(&ide_lock, flags);
+ ide_complete_drive_reset(drive);
return ide_stopped;
}
- hwgroup->resetting = 1;
/*
* Note that we also set nIEN while resetting the device,
* to mask unwanted interrupts from the interface during the reset.