diff options
-rw-r--r-- | drivers/ide/ide-io.c | 23 | ||||
-rw-r--r-- | drivers/ide/ide-iops.c | 18 | ||||
-rw-r--r-- | drivers/ide/ide.c | 41 | ||||
-rw-r--r-- | include/linux/ide.h | 6 |
4 files changed, 56 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 | ||
769 | static 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 | |||
769 | static void ide_check_pm_state(ide_drive_t *drive, struct request *rq) | 781 | static 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 | } |
906 | EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd); | 906 | EXPORT_SYMBOL_GPL(ide_execute_pkt_cmd); |
907 | 907 | ||
908 | static 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 */ |
909 | static ide_startstop_t do_reset1 (ide_drive_t *, int); | 917 | static 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 */ | 1015 | out: |
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 | ||
532 | static 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 | |||
532 | int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device *bdev, | 545 | int 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; |
diff --git a/include/linux/ide.h b/include/linux/ide.h index f9cbe9350cad..021710cc1b1c 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h | |||
@@ -139,6 +139,12 @@ struct ide_io_ports { | |||
139 | #define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */ | 139 | #define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */ |
140 | 140 | ||
141 | /* | 141 | /* |
142 | * Op codes for special requests to be handled by ide_special_rq(). | ||
143 | * Values should be in the range of 0x20 to 0x3f. | ||
144 | */ | ||
145 | #define REQ_DRIVE_RESET 0x20 | ||
146 | |||
147 | /* | ||
142 | * Check for an interrupt and acknowledge the interrupt status | 148 | * Check for an interrupt and acknowledge the interrupt status |
143 | */ | 149 | */ |
144 | struct hwif_s; | 150 | struct hwif_s; |