diff options
Diffstat (limited to 'drivers/ide/ide-taskfile.c')
-rw-r--r-- | drivers/ide/ide-taskfile.c | 128 |
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 | ||
55 | static ide_startstop_t task_no_data_intr(ide_drive_t *); | 55 | static ide_startstop_t task_no_data_intr(ide_drive_t *); |
56 | static ide_startstop_t set_geometry_intr(ide_drive_t *); | ||
57 | static ide_startstop_t recal_intr(ide_drive_t *); | ||
58 | static ide_startstop_t set_multmode_intr(ide_drive_t *); | ||
59 | static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *); | 56 | static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *); |
60 | static ide_startstop_t task_in_intr(ide_drive_t *); | 57 | static 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) | |||
126 | EXPORT_SYMBOL_GPL(do_rw_taskfile); | 113 | EXPORT_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 | */ | ||
131 | static 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 | */ |
152 | static ide_startstop_t set_geometry_intr(ide_drive_t *drive) | 118 | static 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 | } |
180 | static 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 | */ | ||
196 | static 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 | ||