diff options
Diffstat (limited to 'drivers/ide/ide-disk.c')
-rw-r--r-- | drivers/ide/ide-disk.c | 85 |
1 files changed, 55 insertions, 30 deletions
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 851374ef55cf..97abc91db7d0 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c | |||
@@ -129,6 +129,50 @@ static int lba_capacity_is_ok (struct hd_driveid *id) | |||
129 | return 0; /* lba_capacity value may be bad */ | 129 | return 0; /* lba_capacity value may be bad */ |
130 | } | 130 | } |
131 | 131 | ||
132 | static const u8 ide_rw_cmds[] = { | ||
133 | WIN_MULTREAD, | ||
134 | WIN_MULTWRITE, | ||
135 | WIN_MULTREAD_EXT, | ||
136 | WIN_MULTWRITE_EXT, | ||
137 | WIN_READ, | ||
138 | WIN_WRITE, | ||
139 | WIN_READ_EXT, | ||
140 | WIN_WRITE_EXT, | ||
141 | WIN_READDMA, | ||
142 | WIN_WRITEDMA, | ||
143 | WIN_READDMA_EXT, | ||
144 | WIN_WRITEDMA_EXT, | ||
145 | }; | ||
146 | |||
147 | static const u8 ide_data_phases[] = { | ||
148 | TASKFILE_MULTI_IN, | ||
149 | TASKFILE_MULTI_OUT, | ||
150 | TASKFILE_IN, | ||
151 | TASKFILE_OUT, | ||
152 | TASKFILE_IN_DMA, | ||
153 | TASKFILE_OUT_DMA, | ||
154 | }; | ||
155 | |||
156 | static void ide_tf_set_cmd(ide_drive_t *drive, ide_task_t *task, u8 dma) | ||
157 | { | ||
158 | u8 index, lba48, write; | ||
159 | |||
160 | lba48 = (task->tf_flags & IDE_TFLAG_LBA48) ? 2 : 0; | ||
161 | write = (task->tf_flags & IDE_TFLAG_WRITE) ? 1 : 0; | ||
162 | |||
163 | if (dma) | ||
164 | index = drive->vdma ? 4 : 8; | ||
165 | else | ||
166 | index = drive->mult_count ? 0 : 4; | ||
167 | |||
168 | task->tf.command = ide_rw_cmds[index + lba48 + write]; | ||
169 | |||
170 | if (dma) | ||
171 | index = 8; /* fixup index */ | ||
172 | |||
173 | task->data_phase = ide_data_phases[index / 2 + write]; | ||
174 | } | ||
175 | |||
132 | /* | 176 | /* |
133 | * __ide_do_rw_disk() issues READ and WRITE commands to a disk, | 177 | * __ide_do_rw_disk() issues READ and WRITE commands to a disk, |
134 | * using LBA if supported, or CHS otherwise, to address sectors. | 178 | * using LBA if supported, or CHS otherwise, to address sectors. |
@@ -139,7 +183,6 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, | |||
139 | unsigned int dma = drive->using_dma; | 183 | unsigned int dma = drive->using_dma; |
140 | u16 nsectors = (u16)rq->nr_sectors; | 184 | u16 nsectors = (u16)rq->nr_sectors; |
141 | u8 lba48 = (drive->addressing == 1) ? 1 : 0; | 185 | u8 lba48 = (drive->addressing == 1) ? 1 : 0; |
142 | u8 command = WIN_NOP; | ||
143 | ide_task_t task; | 186 | ide_task_t task; |
144 | struct ide_taskfile *tf = &task.tf; | 187 | struct ide_taskfile *tf = &task.tf; |
145 | 188 | ||
@@ -205,50 +248,32 @@ static ide_startstop_t __ide_do_rw_disk(ide_drive_t *drive, struct request *rq, | |||
205 | tf->device = head; | 248 | tf->device = head; |
206 | } | 249 | } |
207 | 250 | ||
251 | if (rq_data_dir(rq)) | ||
252 | task.tf_flags |= IDE_TFLAG_WRITE; | ||
253 | |||
254 | ide_tf_set_cmd(drive, &task, dma); | ||
255 | |||
208 | ide_tf_load(drive, &task); | 256 | ide_tf_load(drive, &task); |
209 | 257 | ||
210 | if (dma) { | 258 | if (dma) { |
211 | if (!hwif->dma_setup(drive)) { | 259 | if (!hwif->dma_setup(drive)) { |
212 | if (rq_data_dir(rq)) { | 260 | hwif->dma_exec_cmd(drive, tf->command); |
213 | command = lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; | ||
214 | if (drive->vdma) | ||
215 | command = lba48 ? WIN_WRITE_EXT: WIN_WRITE; | ||
216 | } else { | ||
217 | command = lba48 ? WIN_READDMA_EXT : WIN_READDMA; | ||
218 | if (drive->vdma) | ||
219 | command = lba48 ? WIN_READ_EXT: WIN_READ; | ||
220 | } | ||
221 | hwif->dma_exec_cmd(drive, command); | ||
222 | hwif->dma_start(drive); | 261 | hwif->dma_start(drive); |
223 | return ide_started; | 262 | return ide_started; |
224 | } | 263 | } |
225 | /* fallback to PIO */ | 264 | /* fallback to PIO */ |
265 | ide_tf_set_cmd(drive, &task, 0); | ||
226 | ide_init_sg_cmd(drive, rq); | 266 | ide_init_sg_cmd(drive, rq); |
227 | } | 267 | } |
228 | 268 | ||
229 | if (rq_data_dir(rq) == READ) { | 269 | hwif->data_phase = task.data_phase; |
230 | |||
231 | if (drive->mult_count) { | ||
232 | hwif->data_phase = TASKFILE_MULTI_IN; | ||
233 | command = lba48 ? WIN_MULTREAD_EXT : WIN_MULTREAD; | ||
234 | } else { | ||
235 | hwif->data_phase = TASKFILE_IN; | ||
236 | command = lba48 ? WIN_READ_EXT : WIN_READ; | ||
237 | } | ||
238 | 270 | ||
239 | ide_execute_command(drive, command, &task_in_intr, | 271 | if (rq_data_dir(rq) == READ) { |
272 | ide_execute_command(drive, tf->command, &task_in_intr, | ||
240 | WAIT_WORSTCASE, NULL); | 273 | WAIT_WORSTCASE, NULL); |
241 | return ide_started; | 274 | return ide_started; |
242 | } else { | 275 | } else { |
243 | if (drive->mult_count) { | 276 | hwif->OUTBSYNC(drive, tf->command, IDE_COMMAND_REG); |
244 | hwif->data_phase = TASKFILE_MULTI_OUT; | ||
245 | command = lba48 ? WIN_MULTWRITE_EXT : WIN_MULTWRITE; | ||
246 | } else { | ||
247 | hwif->data_phase = TASKFILE_OUT; | ||
248 | command = lba48 ? WIN_WRITE_EXT : WIN_WRITE; | ||
249 | } | ||
250 | |||
251 | hwif->OUTBSYNC(drive, command, IDE_COMMAND_REG); | ||
252 | ndelay(400); /* FIXME */ | 277 | ndelay(400); /* FIXME */ |
253 | 278 | ||
254 | return pre_task_out_intr(drive, rq); | 279 | return pre_task_out_intr(drive, rq); |