aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ide
diff options
context:
space:
mode:
authorElias Oltmanns <eo@nebensachen.de>2008-07-16 14:33:48 -0400
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2008-07-16 14:33:48 -0400
commit79e36a9f54aaf4a52eb2d9520953aa3960e99294 (patch)
tree70fae17d64a1facde8541184d7139c4bc12d03bf /drivers/ide
parent72a3d651b2fe341a8ae2ca164c395aa3007350cd (diff)
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')
-rw-r--r--drivers/ide/ide-io.c23
-rw-r--r--drivers/ide/ide-iops.c18
-rw-r--r--drivers/ide/ide.c41
3 files changed, 50 insertions, 32 deletions
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 28057747c1f8..2b33c129740b 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -766,6 +766,18 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
766 return ide_stopped; 766 return ide_stopped;
767} 767}
768 768
769static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
770{
771 switch (rq->cmd[0]) {
772 case REQ_DRIVE_RESET:
773 return ide_do_reset(drive);
774 default:
775 blk_dump_rq_flags(rq, "ide_special_rq - bad request");
776 ide_end_request(drive, 0, 0);
777 return ide_stopped;
778 }
779}
780
769static void ide_check_pm_state(ide_drive_t *drive, struct request *rq) 781static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
770{ 782{
771 struct request_pm_state *pm = rq->data; 783 struct request_pm_state *pm = rq->data;
@@ -869,7 +881,16 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
869 pm->pm_step == ide_pm_state_completed) 881 pm->pm_step == ide_pm_state_completed)
870 ide_complete_pm_request(drive, rq); 882 ide_complete_pm_request(drive, rq);
871 return startstop; 883 return startstop;
872 } 884 } else if (!rq->rq_disk && blk_special_request(rq))
885 /*
886 * TODO: Once all ULDs have been modified to
887 * check for specific op codes rather than
888 * blindly accepting any special request, the
889 * check for ->rq_disk above may be replaced
890 * by a more suitable mechanism or even
891 * dropped entirely.
892 */
893 return ide_special_rq(drive, rq);
873 894
874 drv = *(ide_driver_t **)rq->rq_disk->private_data; 895 drv = *(ide_driver_t **)rq->rq_disk->private_data;
875 return drv->do_request(drive, rq, block); 896 return drv->do_request(drive, rq, block);
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)
905} 905}
906EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd); 906EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd);
907 907
908static inline void ide_complete_drive_reset(ide_drive_t *drive)
909{
910 struct request *rq = drive->hwif->hwgroup->rq;
911
912 if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET)
913 ide_end_request(drive, 1, 0);
914}
915
908/* needed below */ 916/* needed below */
909static ide_startstop_t do_reset1 (ide_drive_t *, int); 917static ide_startstop_t do_reset1 (ide_drive_t *, int);
910 918
@@ -940,7 +948,7 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
940 } 948 }
941 /* done polling */ 949 /* done polling */
942 hwgroup->polling = 0; 950 hwgroup->polling = 0;
943 hwgroup->resetting = 0; 951 ide_complete_drive_reset(drive);
944 return ide_stopped; 952 return ide_stopped;
945} 953}
946 954
@@ -961,7 +969,7 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
961 if (port_ops->reset_poll(drive)) { 969 if (port_ops->reset_poll(drive)) {
962 printk(KERN_ERR "%s: host reset_poll failure for %s.\n", 970 printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
963 hwif->name, drive->name); 971 hwif->name, drive->name);
964 return ide_stopped; 972 goto out;
965 } 973 }
966 } 974 }
967 975
@@ -1004,7 +1012,8 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
1004 } 1012 }
1005 } 1013 }
1006 hwgroup->polling = 0; /* done polling */ 1014 hwgroup->polling = 0; /* done polling */
1007 hwgroup->resetting = 0; /* done reset attempt */ 1015out:
1016 ide_complete_drive_reset(drive);
1008 return ide_stopped; 1017 return ide_stopped;
1009} 1018}
1010 1019
@@ -1090,7 +1099,6 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
1090 1099
1091 /* For an ATAPI device, first try an ATAPI SRST. */ 1100 /* For an ATAPI device, first try an ATAPI SRST. */
1092 if (drive->media != ide_disk && !do_not_try_atapi) { 1101 if (drive->media != ide_disk && !do_not_try_atapi) {
1093 hwgroup->resetting = 1;
1094 pre_reset(drive); 1102 pre_reset(drive);
1095 SELECT_DRIVE(drive); 1103 SELECT_DRIVE(drive);
1096 udelay (20); 1104 udelay (20);
@@ -1112,10 +1120,10 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
1112 1120
1113 if (io_ports->ctl_addr == 0) { 1121 if (io_ports->ctl_addr == 0) {
1114 spin_unlock_irqrestore(&ide_lock, flags); 1122 spin_unlock_irqrestore(&ide_lock, flags);
1123 ide_complete_drive_reset(drive);
1115 return ide_stopped; 1124 return ide_stopped;
1116 } 1125 }
1117 1126
1118 hwgroup->resetting = 1;
1119 /* 1127 /*
1120 * Note that we also set nIEN while resetting the device, 1128 * Note that we also set nIEN while resetting the device,
1121 * to mask unwanted interrupts from the interface during the reset. 1129 * to mask unwanted interrupts from the interface during the reset.
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 90ae00d4aaf5..1ec983b00511 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -529,6 +529,19 @@ static int generic_ide_resume(struct device *dev)
529 return err; 529 return err;
530} 530}
531 531
532static void generic_drive_reset(ide_drive_t *drive)
533{
534 struct request *rq;
535
536 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
537 rq->cmd_type = REQ_TYPE_SPECIAL;
538 rq->cmd_len = 1;
539 rq->cmd[0] = REQ_DRIVE_RESET;
540 rq->cmd_flags |= REQ_SOFTBARRIER;
541 blk_execute_rq(drive->queue, NULL, rq, 1);
542 blk_put_request(rq);
543}
544
532int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev, 545int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev,
533 unsigned int cmd, unsigned long arg) 546 unsigned int cmd, unsigned long arg)
534{ 547{
@@ -603,33 +616,9 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
603 if (!capable(CAP_SYS_ADMIN)) 616 if (!capable(CAP_SYS_ADMIN))
604 return -EACCES; 617 return -EACCES;
605 618
606 /* 619 generic_drive_reset(drive);
607 * Abort the current command on the
608 * group if there is one, taking
609 * care not to allow anything else
610 * to be queued and to die on the
611 * spot if we miss one somehow
612 */
613
614 spin_lock_irqsave(&ide_lock, flags);
615
616 if (HWGROUP(drive)->resetting) {
617 spin_unlock_irqrestore(&ide_lock, flags);
618 return -EBUSY;
619 }
620
621 ide_abort(drive, "drive reset");
622
623 BUG_ON(HWGROUP(drive)->handler);
624
625 /* Ensure nothing gets queued after we
626 drop the lock. Reset will clear the busy */
627
628 HWGROUP(drive)->busy = 1;
629 spin_unlock_irqrestore(&ide_lock, flags);
630 (void) ide_do_reset(drive);
631
632 return 0; 620 return 0;
621
633 case HDIO_GET_BUSSTATE: 622 case HDIO_GET_BUSSTATE:
634 if (!capable(CAP_SYS_ADMIN)) 623 if (!capable(CAP_SYS_ADMIN))
635 return -EACCES; 624 return -EACCES;