aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ide/ide-taskfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ide/ide-taskfile.c')
-rw-r--r--drivers/ide/ide-taskfile.c105
1 files changed, 25 insertions, 80 deletions
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 8da8d26db7ed..a4c2d91179b3 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -53,9 +53,6 @@ int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
53} 53}
54 54
55static ide_startstop_t task_no_data_intr(ide_drive_t *); 55static ide_startstop_t task_no_data_intr(ide_drive_t *);
56static ide_startstop_t set_geometry_intr(ide_drive_t *);
57static ide_startstop_t recal_intr(ide_drive_t *);
58static ide_startstop_t set_multmode_intr(ide_drive_t *);
59static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *); 56static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
60static ide_startstop_t task_in_intr(ide_drive_t *); 57static ide_startstop_t task_in_intr(ide_drive_t *);
61 58
@@ -79,6 +76,8 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
79 if (task->tf_flags & IDE_TFLAG_FLAGGED) 76 if (task->tf_flags & IDE_TFLAG_FLAGGED)
80 task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS; 77 task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS;
81 78
79 memcpy(&hwif->task, task, sizeof(*task));
80
82 if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) { 81 if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
83 ide_tf_dump(drive->name, tf); 82 ide_tf_dump(drive->name, tf);
84 tp_ops->set_irq(hwif, 1); 83 tp_ops->set_irq(hwif, 1);
@@ -99,19 +98,6 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
99 case TASKFILE_NO_DATA: 98 case TASKFILE_NO_DATA:
100 if (handler == NULL) 99 if (handler == NULL)
101 handler = task_no_data_intr; 100 handler = task_no_data_intr;
102 if (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) {
103 switch (tf->command) {
104 case ATA_CMD_INIT_DEV_PARAMS:
105 handler = set_geometry_intr;
106 break;
107 case ATA_CMD_RESTORE:
108 handler = recal_intr;
109 break;
110 case ATA_CMD_SET_MULTI:
111 handler = set_multmode_intr;
112 break;
113 }
114 }
115 ide_execute_command(drive, tf->command, handler, 101 ide_execute_command(drive, tf->command, handler,
116 WAIT_WORSTCASE, NULL); 102 WAIT_WORSTCASE, NULL);
117 return ide_started; 103 return ide_started;
@@ -127,33 +113,15 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
127EXPORT_SYMBOL_GPL(do_rw_taskfile); 113EXPORT_SYMBOL_GPL(do_rw_taskfile);
128 114
129/* 115/*
130 * set_multmode_intr() is invoked on completion of a ATA_CMD_SET_MULTI cmd. 116 * Handler for commands without a data phase
131 */
132static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
133{
134 ide_hwif_t *hwif = drive->hwif;
135 u8 stat;
136
137 local_irq_enable_in_hardirq();
138 stat = hwif->tp_ops->read_status(hwif);
139
140 if (OK_STAT(stat, ATA_DRDY, BAD_STAT))
141 drive->mult_count = drive->mult_req;
142 else {
143 drive->mult_req = drive->mult_count = 0;
144 drive->special.b.recalibrate = 1;
145 (void) ide_dump_status(drive, "set_multmode", stat);
146 }
147 return ide_stopped;
148}
149
150/*
151 * set_geometry_intr() is invoked on completion of a ATA_CMD_INIT_DEV_PARAMS cmd.
152 */ 117 */
153static ide_startstop_t set_geometry_intr(ide_drive_t *drive) 118static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
154{ 119{
155 ide_hwif_t *hwif = drive->hwif; 120 ide_hwif_t *hwif = drive->hwif;
156 int retries = 5; 121 ide_task_t *task = &hwif->task;
122 struct ide_taskfile *tf = &task->tf;
123 int custom = (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0;
124 int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1;
157 u8 stat; 125 u8 stat;
158 126
159 local_irq_enable_in_hardirq(); 127 local_irq_enable_in_hardirq();
@@ -165,50 +133,27 @@ static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
165 udelay(10); 133 udelay(10);
166 }; 134 };
167 135
168 if (OK_STAT(stat, ATA_DRDY, BAD_STAT)) 136 if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
169 return ide_stopped; 137 if (custom && tf->command == ATA_CMD_SET_MULTI) {
170 138 drive->mult_req = drive->mult_count = 0;
171 if (stat & (ATA_ERR | ATA_DRQ)) 139 drive->special.b.recalibrate = 1;
172 return ide_error(drive, "set_geometry_intr", stat); 140 (void)ide_dump_status(drive, __func__, stat);
173 141 return ide_stopped;
174 ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL); 142 } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) {
175 return ide_started; 143 if ((stat & (ATA_ERR | ATA_DRQ)) == 0) {
176} 144 ide_set_handler(drive, &task_no_data_intr,
177 145 WAIT_WORSTCASE, NULL);
178/* 146 return ide_started;
179 * recal_intr() is invoked on completion of a ATA_CMD_RESTORE (recalibrate) cmd. 147 }
180 */ 148 }
181static ide_startstop_t recal_intr(ide_drive_t *drive)
182{
183 ide_hwif_t *hwif = drive->hwif;
184 u8 stat;
185
186 local_irq_enable_in_hardirq();
187 stat = hwif->tp_ops->read_status(hwif);
188
189 if (!OK_STAT(stat, ATA_DRDY, BAD_STAT))
190 return ide_error(drive, "recal_intr", stat);
191 return ide_stopped;
192}
193
194/*
195 * Handler for commands without a data phase
196 */
197static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
198{
199 ide_hwif_t *hwif = drive->hwif;
200 ide_task_t *args = hwif->hwgroup->rq->special;
201 u8 stat;
202
203 local_irq_enable_in_hardirq();
204 stat = hwif->tp_ops->read_status(hwif);
205
206 if (!OK_STAT(stat, ATA_DRDY, BAD_STAT))
207 return ide_error(drive, "task_no_data_intr", stat); 149 return ide_error(drive, "task_no_data_intr", stat);
208 /* calls ide_end_drive_cmd */ 150 /* calls ide_end_drive_cmd */
151 }
209 152
210 if (args) 153 if (!custom)
211 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)
156 drive->mult_count = drive->mult_req;
212 157
213 return ide_stopped; 158 return ide_stopped;
214} 159}