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.c128
1 files changed, 41 insertions, 87 deletions
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 487b18b3ebae..bf4fb9d8d176 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,24 +98,12 @@ 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;
118 default: 104 default:
119 if (drive->using_dma == 0 || dma_ops->dma_setup(drive)) 105 if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0 ||
106 dma_ops->dma_setup(drive))
120 return ide_stopped; 107 return ide_stopped;
121 dma_ops->dma_exec_cmd(drive, tf->command); 108 dma_ops->dma_exec_cmd(drive, tf->command);
122 dma_ops->dma_start(drive); 109 dma_ops->dma_start(drive);
@@ -126,33 +113,15 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
126EXPORT_SYMBOL_GPL(do_rw_taskfile); 113EXPORT_SYMBOL_GPL(do_rw_taskfile);
127 114
128/* 115/*
129 * set_multmode_intr() is invoked on completion of a ATA_CMD_SET_MULTI cmd. 116 * Handler for commands without a data phase
130 */
131static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
132{
133 ide_hwif_t *hwif = drive->hwif;
134 u8 stat;
135
136 local_irq_enable_in_hardirq();
137 stat = hwif->tp_ops->read_status(hwif);
138
139 if (OK_STAT(stat, ATA_DRDY, BAD_STAT))
140 drive->mult_count = drive->mult_req;
141 else {
142 drive->mult_req = drive->mult_count = 0;
143 drive->special.b.recalibrate = 1;
144 (void) ide_dump_status(drive, "set_multmode", stat);
145 }
146 return ide_stopped;
147}
148
149/*
150 * set_geometry_intr() is invoked on completion of a ATA_CMD_INIT_DEV_PARAMS cmd.
151 */ 117 */
152static ide_startstop_t set_geometry_intr(ide_drive_t *drive) 118static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
153{ 119{
154 ide_hwif_t *hwif = drive->hwif; 120 ide_hwif_t *hwif = drive->hwif;
155 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;
156 u8 stat; 125 u8 stat;
157 126
158 local_irq_enable_in_hardirq(); 127 local_irq_enable_in_hardirq();
@@ -164,50 +133,36 @@ static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
164 udelay(10); 133 udelay(10);
165 }; 134 };
166 135
167 if (OK_STAT(stat, ATA_DRDY, BAD_STAT)) 136 if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
168 return ide_stopped; 137 if (custom && tf->command == ATA_CMD_SET_MULTI) {
169 138 drive->mult_req = drive->mult_count = 0;
170 if (stat & (ATA_ERR | ATA_DRQ)) 139 drive->special.b.recalibrate = 1;
171 return ide_error(drive, "set_geometry_intr", stat); 140 (void)ide_dump_status(drive, __func__, stat);
172 141 return ide_stopped;
173 ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL); 142 } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) {
174 return ide_started; 143 if ((stat & (ATA_ERR | ATA_DRQ)) == 0) {
175} 144 ide_set_handler(drive, &task_no_data_intr,
176 145 WAIT_WORSTCASE, NULL);
177/* 146 return ide_started;
178 * recal_intr() is invoked on completion of a ATA_CMD_RESTORE (recalibrate) cmd. 147 }
179 */ 148 }
180static ide_startstop_t recal_intr(ide_drive_t *drive)
181{
182 ide_hwif_t *hwif = drive->hwif;
183 u8 stat;
184
185 local_irq_enable_in_hardirq();
186 stat = hwif->tp_ops->read_status(hwif);
187
188 if (!OK_STAT(stat, ATA_DRDY, BAD_STAT))
189 return ide_error(drive, "recal_intr", stat);
190 return ide_stopped;
191}
192
193/*
194 * Handler for commands without a data phase
195 */
196static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
197{
198 ide_hwif_t *hwif = drive->hwif;
199 ide_task_t *args = hwif->hwgroup->rq->special;
200 u8 stat;
201
202 local_irq_enable_in_hardirq();
203 stat = hwif->tp_ops->read_status(hwif);
204
205 if (!OK_STAT(stat, ATA_DRDY, BAD_STAT))
206 return ide_error(drive, "task_no_data_intr", stat); 149 return ide_error(drive, "task_no_data_intr", stat);
207 /* calls ide_end_drive_cmd */ 150 /* calls ide_end_drive_cmd */
151 }
208 152
209 if (args) 153 if (!custom)
154 ide_end_drive_cmd(drive, stat, ide_read_error(drive));
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;
210 ide_end_drive_cmd(drive, stat, ide_read_error(drive)); 163 ide_end_drive_cmd(drive, stat, ide_read_error(drive));
164 } else if (tf->command == ATA_CMD_SET_MULTI)
165 drive->mult_count = drive->mult_req;
211 166
212 return ide_stopped; 167 return ide_stopped;
213} 168}
@@ -469,13 +424,12 @@ static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
469 if (ide_wait_stat(&startstop, drive, ATA_DRQ, 424 if (ide_wait_stat(&startstop, drive, ATA_DRQ,
470 drive->bad_wstat, WAIT_DRQ)) { 425 drive->bad_wstat, WAIT_DRQ)) {
471 printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n", 426 printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
472 drive->name, 427 drive->name, drive->hwif->data_phase ? "MULT" : "",
473 drive->hwif->data_phase ? "MULT" : "", 428 (drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : "");
474 drive->addressing ? "_EXT" : "");
475 return startstop; 429 return startstop;
476 } 430 }
477 431
478 if (!drive->unmask) 432 if ((drive->dev_flags & IDE_DFLAG_UNMASK) == 0)
479 local_irq_disable(); 433 local_irq_disable();
480 434
481 ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); 435 ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
@@ -591,7 +545,7 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
591 545
592 args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE | 546 args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE |
593 IDE_TFLAG_IN_TF; 547 IDE_TFLAG_IN_TF;
594 if (drive->addressing == 1) 548 if (drive->dev_flags & IDE_DFLAG_LBA48)
595 args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB); 549 args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB);
596 550
597 if (req_task->out_flags.all) { 551 if (req_task->out_flags.all) {
@@ -694,7 +648,7 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
694 if ((args.tf_flags & IDE_TFLAG_FLAGGED_SET_IN_FLAGS) && 648 if ((args.tf_flags & IDE_TFLAG_FLAGGED_SET_IN_FLAGS) &&
695 req_task->in_flags.all == 0) { 649 req_task->in_flags.all == 0) {
696 req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; 650 req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
697 if (drive->addressing == 1) 651 if (drive->dev_flags & IDE_DFLAG_LBA48)
698 req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8); 652 req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
699 } 653 }
700 654