aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ide/Makefile2
-rw-r--r--drivers/ide/ide-io.c29
-rw-r--r--drivers/ide/ide-iops.c29
-rw-r--r--drivers/ide/ide-park.c121
-rw-r--r--drivers/ide/ide-probe.c5
-rw-r--r--drivers/ide/ide-taskfile.c11
-rw-r--r--drivers/ide/ide.c1
7 files changed, 193 insertions, 5 deletions
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 0c30adb115c8..ceaf779054ea 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -5,7 +5,7 @@
5EXTRA_CFLAGS += -Idrivers/ide 5EXTRA_CFLAGS += -Idrivers/ide
6 6
7ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \ 7ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
8 ide-taskfile.o ide-pio-blacklist.o 8 ide-taskfile.o ide-park.o ide-pio-blacklist.o
9 9
10# core IDE code 10# core IDE code
11ide-core-$(CONFIG_IDE_TIMINGS) += ide-timings.o 11ide-core-$(CONFIG_IDE_TIMINGS) += ide-timings.o
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index e205f46c3c7a..77c6eaeacefa 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -672,7 +672,32 @@ EXPORT_SYMBOL_GPL(ide_devset_execute);
672 672
673static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq) 673static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
674{ 674{
675 switch (rq->cmd[0]) { 675 u8 cmd = rq->cmd[0];
676
677 if (cmd == REQ_PARK_HEADS || cmd == REQ_UNPARK_HEADS) {
678 ide_task_t task;
679 struct ide_taskfile *tf = &task.tf;
680
681 memset(&task, 0, sizeof(task));
682 if (cmd == REQ_PARK_HEADS) {
683 drive->sleep = *(unsigned long *)rq->special;
684 drive->dev_flags |= IDE_DFLAG_SLEEPING;
685 tf->command = ATA_CMD_IDLEIMMEDIATE;
686 tf->feature = 0x44;
687 tf->lbal = 0x4c;
688 tf->lbam = 0x4e;
689 tf->lbah = 0x55;
690 task.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER;
691 } else /* cmd == REQ_UNPARK_HEADS */
692 tf->command = ATA_CMD_CHK_POWER;
693
694 task.tf_flags |= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
695 task.rq = rq;
696 drive->hwif->data_phase = task.data_phase = TASKFILE_NO_DATA;
697 return do_rw_taskfile(drive, &task);
698 }
699
700 switch (cmd) {
676 case REQ_DEVSET_EXEC: 701 case REQ_DEVSET_EXEC:
677 { 702 {
678 int err, (*setfunc)(ide_drive_t *, int) = rq->special; 703 int err, (*setfunc)(ide_drive_t *, int) = rq->special;
@@ -1008,7 +1033,7 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
1008 } 1033 }
1009 hwgroup->hwif = hwif; 1034 hwgroup->hwif = hwif;
1010 hwgroup->drive = drive; 1035 hwgroup->drive = drive;
1011 drive->dev_flags &= ~IDE_DFLAG_SLEEPING; 1036 drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
1012 drive->service_start = jiffies; 1037 drive->service_start = jiffies;
1013 1038
1014 if (blk_queue_plugged(drive->queue)) { 1039 if (blk_queue_plugged(drive->queue)) {
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 91182ebed468..b762deb2dacb 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -1020,6 +1020,7 @@ static void ide_disk_pre_reset(ide_drive_t *drive)
1020 drive->special.b.recalibrate = legacy; 1020 drive->special.b.recalibrate = legacy;
1021 1021
1022 drive->mult_count = 0; 1022 drive->mult_count = 0;
1023 drive->dev_flags &= ~IDE_DFLAG_PARKED;
1023 1024
1024 if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0 && 1025 if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0 &&
1025 (drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) 1026 (drive->dev_flags & IDE_DFLAG_USING_DMA) == 0)
@@ -1079,12 +1080,13 @@ static void pre_reset(ide_drive_t *drive)
1079static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi) 1080static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
1080{ 1081{
1081 unsigned int unit; 1082 unsigned int unit;
1082 unsigned long flags; 1083 unsigned long flags, timeout;
1083 ide_hwif_t *hwif; 1084 ide_hwif_t *hwif;
1084 ide_hwgroup_t *hwgroup; 1085 ide_hwgroup_t *hwgroup;
1085 struct ide_io_ports *io_ports; 1086 struct ide_io_ports *io_ports;
1086 const struct ide_tp_ops *tp_ops; 1087 const struct ide_tp_ops *tp_ops;
1087 const struct ide_port_ops *port_ops; 1088 const struct ide_port_ops *port_ops;
1089 DEFINE_WAIT(wait);
1088 1090
1089 spin_lock_irqsave(&ide_lock, flags); 1091 spin_lock_irqsave(&ide_lock, flags);
1090 hwif = HWIF(drive); 1092 hwif = HWIF(drive);
@@ -1111,6 +1113,31 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
1111 return ide_started; 1113 return ide_started;
1112 } 1114 }
1113 1115
1116 /* We must not disturb devices in the IDE_DFLAG_PARKED state. */
1117 do {
1118 unsigned long now;
1119
1120 prepare_to_wait(&ide_park_wq, &wait, TASK_UNINTERRUPTIBLE);
1121 timeout = jiffies;
1122 for (unit = 0; unit < MAX_DRIVES; unit++) {
1123 ide_drive_t *tdrive = &hwif->drives[unit];
1124
1125 if (tdrive->dev_flags & IDE_DFLAG_PRESENT &&
1126 tdrive->dev_flags & IDE_DFLAG_PARKED &&
1127 time_after(tdrive->sleep, timeout))
1128 timeout = tdrive->sleep;
1129 }
1130
1131 now = jiffies;
1132 if (time_before_eq(timeout, now))
1133 break;
1134
1135 spin_unlock_irqrestore(&ide_lock, flags);
1136 timeout = schedule_timeout_uninterruptible(timeout - now);
1137 spin_lock_irqsave(&ide_lock, flags);
1138 } while (timeout);
1139 finish_wait(&ide_park_wq, &wait);
1140
1114 /* 1141 /*
1115 * First, reset any device state data we were maintaining 1142 * First, reset any device state data we were maintaining
1116 * for any of the drives on this interface. 1143 * for any of the drives on this interface.
diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c
new file mode 100644
index 000000000000..03b00e57e93f
--- /dev/null
+++ b/drivers/ide/ide-park.c
@@ -0,0 +1,121 @@
1#include <linux/kernel.h>
2#include <linux/ide.h>
3#include <linux/jiffies.h>
4#include <linux/blkdev.h>
5
6DECLARE_WAIT_QUEUE_HEAD(ide_park_wq);
7
8static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
9{
10 struct request_queue *q = drive->queue;
11 struct request *rq;
12 int rc;
13
14 timeout += jiffies;
15 spin_lock_irq(&ide_lock);
16 if (drive->dev_flags & IDE_DFLAG_PARKED) {
17 ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;
18 int reset_timer;
19
20 reset_timer = time_before(timeout, drive->sleep);
21 drive->sleep = timeout;
22 wake_up_all(&ide_park_wq);
23 if (reset_timer && hwgroup->sleeping &&
24 del_timer(&hwgroup->timer)) {
25 hwgroup->sleeping = 0;
26 hwgroup->busy = 0;
27 blk_start_queueing(q);
28 }
29 spin_unlock_irq(&ide_lock);
30 return;
31 }
32 spin_unlock_irq(&ide_lock);
33
34 rq = blk_get_request(q, READ, __GFP_WAIT);
35 rq->cmd[0] = REQ_PARK_HEADS;
36 rq->cmd_len = 1;
37 rq->cmd_type = REQ_TYPE_SPECIAL;
38 rq->special = &timeout;
39 rc = blk_execute_rq(q, NULL, rq, 1);
40 blk_put_request(rq);
41 if (rc)
42 goto out;
43
44 /*
45 * Make sure that *some* command is sent to the drive after the
46 * timeout has expired, so power management will be reenabled.
47 */
48 rq = blk_get_request(q, READ, GFP_NOWAIT);
49 if (unlikely(!rq))
50 goto out;
51
52 rq->cmd[0] = REQ_UNPARK_HEADS;
53 rq->cmd_len = 1;
54 rq->cmd_type = REQ_TYPE_SPECIAL;
55 elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1);
56
57out:
58 return;
59}
60
61ssize_t ide_park_show(struct device *dev, struct device_attribute *attr,
62 char *buf)
63{
64 ide_drive_t *drive = to_ide_device(dev);
65 unsigned long now;
66 unsigned int msecs;
67
68 if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
69 return -EOPNOTSUPP;
70
71 spin_lock_irq(&ide_lock);
72 now = jiffies;
73 if (drive->dev_flags & IDE_DFLAG_PARKED &&
74 time_after(drive->sleep, now))
75 msecs = jiffies_to_msecs(drive->sleep - now);
76 else
77 msecs = 0;
78 spin_unlock_irq(&ide_lock);
79
80 return snprintf(buf, 20, "%u\n", msecs);
81}
82
83ssize_t ide_park_store(struct device *dev, struct device_attribute *attr,
84 const char *buf, size_t len)
85{
86#define MAX_PARK_TIMEOUT 30000
87 ide_drive_t *drive = to_ide_device(dev);
88 long int input;
89 int rc;
90
91 rc = strict_strtol(buf, 10, &input);
92 if (rc || input < -2)
93 return -EINVAL;
94 if (input > MAX_PARK_TIMEOUT) {
95 input = MAX_PARK_TIMEOUT;
96 rc = -EOVERFLOW;
97 }
98
99 mutex_lock(&ide_setting_mtx);
100 if (input >= 0) {
101 if (drive->dev_flags & IDE_DFLAG_NO_UNLOAD)
102 rc = -EOPNOTSUPP;
103 else if (input || drive->dev_flags & IDE_DFLAG_PARKED)
104 issue_park_cmd(drive, msecs_to_jiffies(input));
105 } else {
106 if (drive->media == ide_disk)
107 switch (input) {
108 case -1:
109 drive->dev_flags &= ~IDE_DFLAG_NO_UNLOAD;
110 break;
111 case -2:
112 drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
113 break;
114 }
115 else
116 rc = -EOPNOTSUPP;
117 }
118 mutex_unlock(&ide_setting_mtx);
119
120 return rc ? rc : len;
121}
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index de8edd306c79..f27baa5f140e 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -208,6 +208,8 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
208 drive->ready_stat = 0; 208 drive->ready_stat = 0;
209 if (ata_id_cdb_intr(id)) 209 if (ata_id_cdb_intr(id))
210 drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT; 210 drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
211 /* we don't do head unloading on ATAPI devices */
212 drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
211 return; 213 return;
212 } 214 }
213 215
@@ -223,6 +225,9 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
223 225
224 drive->media = ide_disk; 226 drive->media = ide_disk;
225 227
228 if (!ata_id_has_unload(drive->id))
229 drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
230
226 printk(KERN_CONT "%s DISK drive\n", is_cfa ? "CFA" : "ATA"); 231 printk(KERN_CONT "%s DISK drive\n", is_cfa ? "CFA" : "ATA");
227 232
228 return; 233 return;
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index a4c2d91179b3..bf4fb9d8d176 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -152,7 +152,16 @@ static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
152 152
153 if (!custom) 153 if (!custom)
154 ide_end_drive_cmd(drive, stat, ide_read_error(drive)); 154 ide_end_drive_cmd(drive, stat, ide_read_error(drive));
155 else if (tf->command == ATA_CMD_SET_MULTI) 155 else if (tf->command == ATA_CMD_IDLEIMMEDIATE) {
156 hwif->tp_ops->tf_read(drive, task);
157 if (tf->lbal != 0xc4) {
158 printk(KERN_ERR "%s: head unload failed!\n",
159 drive->name);
160 ide_tf_dump(drive->name, tf);
161 } else
162 drive->dev_flags |= IDE_DFLAG_PARKED;
163 ide_end_drive_cmd(drive, stat, ide_read_error(drive));
164 } else if (tf->command == ATA_CMD_SET_MULTI)
156 drive->mult_count = drive->mult_req; 165 drive->mult_count = drive->mult_req;
157 166
158 return ide_stopped; 167 return ide_stopped;
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 083783e851d1..04f8f13cb9d7 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -587,6 +587,7 @@ static struct device_attribute ide_dev_attrs[] = {
587 __ATTR_RO(model), 587 __ATTR_RO(model),
588 __ATTR_RO(firmware), 588 __ATTR_RO(firmware),
589 __ATTR(serial, 0400, serial_show, NULL), 589 __ATTR(serial, 0400, serial_show, NULL),
590 __ATTR(unload_heads, 0644, ide_park_show, ide_park_store),
590 __ATTR_NULL 591 __ATTR_NULL
591}; 592};
592 593