]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/ide/ide-taskfile.c
ide: add 'config' field to hw_regs_t
[mirror_ubuntu-artful-kernel.git] / drivers / ide / ide-taskfile.c
CommitLineData
1da177e4 1/*
59bca8cc
BZ
2 * Copyright (C) 2000-2002 Michael Cornwell <cornwell@acm.org>
3 * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
4 * Copyright (C) 2001-2002 Klaus Smolin
1da177e4 5 * IBM Storage Technology Division
59bca8cc 6 * Copyright (C) 2003-2004, 2007 Bartlomiej Zolnierkiewicz
1da177e4
LT
7 *
8 * The big the bad and the ugly.
1da177e4
LT
9 */
10
1da177e4
LT
11#include <linux/types.h>
12#include <linux/string.h>
13#include <linux/kernel.h>
651c29a1 14#include <linux/sched.h>
1da177e4 15#include <linux/interrupt.h>
1da177e4 16#include <linux/errno.h>
1da177e4 17#include <linux/slab.h>
1da177e4
LT
18#include <linux/delay.h>
19#include <linux/hdreg.h>
20#include <linux/ide.h>
55c16a70 21#include <linux/scatterlist.h>
1da177e4 22
1da177e4
LT
23#include <asm/uaccess.h>
24#include <asm/io.h>
25
089c5c7e 26void ide_tf_dump(const char *s, struct ide_taskfile *tf)
9e42237f 27{
807e35d6
BZ
28#ifdef DEBUG
29 printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x "
30 "lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n",
089c5c7e 31 s, tf->feature, tf->nsect, tf->lbal,
807e35d6 32 tf->lbam, tf->lbah, tf->device, tf->command);
6dd9b837
BZ
33 printk("%s: hob: nsect 0x%02x lbal 0x%02x "
34 "lbam 0x%02x lbah 0x%02x\n",
089c5c7e 35 s, tf->hob_nsect, tf->hob_lbal,
6dd9b837 36 tf->hob_lbam, tf->hob_lbah);
807e35d6 37#endif
089c5c7e
BZ
38}
39
1da177e4
LT
40int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
41{
42 ide_task_t args;
650d841d 43
1da177e4 44 memset(&args, 0, sizeof(ide_task_t));
650d841d 45 args.tf.nsect = 0x01;
1da177e4 46 if (drive->media == ide_disk)
650d841d 47 args.tf.command = WIN_IDENTIFY;
1da177e4 48 else
650d841d 49 args.tf.command = WIN_PIDENTIFY;
657cc1a8 50 args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
ac026ff2 51 args.data_phase = TASKFILE_IN;
ac026ff2 52 return ide_raw_taskfile(drive, &args, buf, 1);
1da177e4
LT
53}
54
1192e528 55static ide_startstop_t task_no_data_intr(ide_drive_t *);
57d7366b
BZ
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 *);
f6e29e35
BZ
59static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
60static ide_startstop_t task_in_intr(ide_drive_t *);
1192e528 61
1da177e4
LT
62ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
63{
64 ide_hwif_t *hwif = HWIF(drive);
650d841d 65 struct ide_taskfile *tf = &task->tf;
57d7366b 66 ide_handler_t *handler = NULL;
f37afdac 67 const struct ide_dma_ops *dma_ops = hwif->dma_ops;
1da177e4 68
1edee60e
BZ
69 if (task->data_phase == TASKFILE_MULTI_IN ||
70 task->data_phase == TASKFILE_MULTI_OUT) {
71 if (!drive->mult_count) {
72 printk(KERN_ERR "%s: multimode not set!\n",
73 drive->name);
74 return ide_stopped;
75 }
76 }
77
78 if (task->tf_flags & IDE_TFLAG_FLAGGED)
79 task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS;
80
089c5c7e
BZ
81 if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
82 ide_tf_dump(drive->name, tf);
6e6afb3b 83 hwif->set_irq(hwif, 1);
ed4af48f 84 SELECT_MASK(drive, 0);
94cd5b62 85 hwif->tf_load(drive, task);
089c5c7e 86 }
1da177e4 87
10d90157
BZ
88 switch (task->data_phase) {
89 case TASKFILE_MULTI_OUT:
90 case TASKFILE_OUT:
c6dfa867 91 hwif->exec_command(hwif, tf->command);
10d90157
BZ
92 ndelay(400); /* FIXME */
93 return pre_task_out_intr(drive, task->rq);
94 case TASKFILE_MULTI_IN:
95 case TASKFILE_IN:
57d7366b 96 handler = task_in_intr;
1192e528 97 /* fall-through */
10d90157 98 case TASKFILE_NO_DATA:
57d7366b
BZ
99 if (handler == NULL)
100 handler = task_no_data_intr;
1192e528 101 /* WIN_{SPECIFY,RESTORE,SETMULT} use custom handlers */
57d7366b
BZ
102 if (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) {
103 switch (tf->command) {
104 case WIN_SPECIFY: handler = set_geometry_intr; break;
105 case WIN_RESTORE: handler = recal_intr; break;
106 case WIN_SETMULT: handler = set_multmode_intr; break;
107 }
108 }
109 ide_execute_command(drive, tf->command, handler,
110 WAIT_WORSTCASE, NULL);
1da177e4 111 return ide_started;
10d90157 112 default:
07fe69d5 113 if (drive->using_dma == 0 || dma_ops->dma_setup(drive))
10d90157 114 return ide_stopped;
5e37bdc0
BZ
115 dma_ops->dma_exec_cmd(drive, tf->command);
116 dma_ops->dma_start(drive);
74095a91 117 return ide_started;
1da177e4 118 }
1da177e4 119}
f6e29e35 120EXPORT_SYMBOL_GPL(do_rw_taskfile);
1da177e4 121
1da177e4
LT
122/*
123 * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
124 */
57d7366b 125static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
1da177e4 126{
b73c7ee2
BZ
127 ide_hwif_t *hwif = drive->hwif;
128 u8 stat = hwif->read_status(hwif);
1da177e4 129
c47137a9 130 if (OK_STAT(stat, READY_STAT, BAD_STAT))
1da177e4 131 drive->mult_count = drive->mult_req;
c47137a9 132 else {
1da177e4
LT
133 drive->mult_req = drive->mult_count = 0;
134 drive->special.b.recalibrate = 1;
135 (void) ide_dump_status(drive, "set_multmode", stat);
136 }
137 return ide_stopped;
138}
139
140/*
141 * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
142 */
57d7366b 143static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
1da177e4 144{
b73c7ee2 145 ide_hwif_t *hwif = drive->hwif;
1da177e4
LT
146 int retries = 5;
147 u8 stat;
148
b73c7ee2 149 while (((stat = hwif->read_status(hwif)) & BUSY_STAT) && retries--)
1da177e4
LT
150 udelay(10);
151
152 if (OK_STAT(stat, READY_STAT, BAD_STAT))
153 return ide_stopped;
154
155 if (stat & (ERR_STAT|DRQ_STAT))
156 return ide_error(drive, "set_geometry_intr", stat);
157
1da177e4
LT
158 ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL);
159 return ide_started;
160}
161
162/*
163 * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
164 */
57d7366b 165static ide_startstop_t recal_intr(ide_drive_t *drive)
1da177e4 166{
b73c7ee2
BZ
167 ide_hwif_t *hwif = drive->hwif;
168 u8 stat = hwif->read_status(hwif);
1da177e4 169
c47137a9 170 if (!OK_STAT(stat, READY_STAT, BAD_STAT))
1da177e4
LT
171 return ide_error(drive, "recal_intr", stat);
172 return ide_stopped;
173}
174
175/*
176 * Handler for commands without a data phase
177 */
1192e528 178static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
1da177e4 179{
b73c7ee2
BZ
180 ide_hwif_t *hwif = drive->hwif;
181 ide_task_t *args = hwif->hwgroup->rq->special;
1da177e4
LT
182 u8 stat;
183
366c7f55 184 local_irq_enable_in_hardirq();
b73c7ee2 185 stat = hwif->read_status(hwif);
c47137a9
BZ
186
187 if (!OK_STAT(stat, READY_STAT, BAD_STAT))
1da177e4
LT
188 return ide_error(drive, "task_no_data_intr", stat);
189 /* calls ide_end_drive_cmd */
c47137a9 190
1da177e4 191 if (args)
64a57fe4 192 ide_end_drive_cmd(drive, stat, ide_read_error(drive));
1da177e4
LT
193
194 return ide_stopped;
195}
196
da6f4c7f 197static u8 wait_drive_not_busy(ide_drive_t *drive)
1da177e4 198{
b73c7ee2 199 ide_hwif_t *hwif = drive->hwif;
b42fa133 200 int retries;
1da177e4
LT
201 u8 stat;
202
203 /*
f54feafa
BZ
204 * Last sector was transfered, wait until device is ready. This can
205 * take up to 6 ms on some ATAPI devices, so we will wait max 10 ms.
1da177e4 206 */
f54feafa 207 for (retries = 0; retries < 1000; retries++) {
b73c7ee2 208 stat = hwif->read_status(hwif);
c47137a9
BZ
209
210 if (stat & BUSY_STAT)
b42fa133
MY
211 udelay(10);
212 else
213 break;
214 }
1da177e4 215
b42fa133 216 if (stat & BUSY_STAT)
1da177e4
LT
217 printk(KERN_ERR "%s: drive still BUSY!\n", drive->name);
218
219 return stat;
220}
221
92d3ab27
BZ
222static void ide_pio_sector(ide_drive_t *drive, struct request *rq,
223 unsigned int write)
1da177e4
LT
224{
225 ide_hwif_t *hwif = drive->hwif;
226 struct scatterlist *sg = hwif->sg_table;
55c16a70 227 struct scatterlist *cursg = hwif->cursg;
1da177e4
LT
228 struct page *page;
229#ifdef CONFIG_HIGHMEM
230 unsigned long flags;
231#endif
232 unsigned int offset;
233 u8 *buf;
234
55c16a70
JA
235 cursg = hwif->cursg;
236 if (!cursg) {
237 cursg = sg;
238 hwif->cursg = sg;
239 }
240
45711f1a 241 page = sg_page(cursg);
55c16a70 242 offset = cursg->offset + hwif->cursg_ofs * SECTOR_SIZE;
1da177e4
LT
243
244 /* get the current page and offset */
245 page = nth_page(page, (offset >> PAGE_SHIFT));
246 offset %= PAGE_SIZE;
247
248#ifdef CONFIG_HIGHMEM
249 local_irq_save(flags);
250#endif
251 buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
252
253 hwif->nleft--;
254 hwif->cursg_ofs++;
255
55c16a70
JA
256 if ((hwif->cursg_ofs * SECTOR_SIZE) == cursg->length) {
257 hwif->cursg = sg_next(hwif->cursg);
1da177e4
LT
258 hwif->cursg_ofs = 0;
259 }
260
261 /* do the actual data transfer */
262 if (write)
9567b349 263 hwif->output_data(drive, rq, buf, SECTOR_SIZE);
1da177e4 264 else
9567b349 265 hwif->input_data(drive, rq, buf, SECTOR_SIZE);
1da177e4
LT
266
267 kunmap_atomic(buf, KM_BIO_SRC_IRQ);
268#ifdef CONFIG_HIGHMEM
269 local_irq_restore(flags);
270#endif
271}
272
92d3ab27
BZ
273static void ide_pio_multi(ide_drive_t *drive, struct request *rq,
274 unsigned int write)
1da177e4
LT
275{
276 unsigned int nsect;
277
278 nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count);
279 while (nsect--)
92d3ab27 280 ide_pio_sector(drive, rq, write);
1da177e4
LT
281}
282
858119e1 283static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
1da177e4
LT
284 unsigned int write)
285{
35cf2b94
TH
286 u8 saved_io_32bit = drive->io_32bit;
287
1da177e4
LT
288 if (rq->bio) /* fs request */
289 rq->errors = 0;
290
35cf2b94
TH
291 if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
292 ide_task_t *task = rq->special;
293
294 if (task->tf_flags & IDE_TFLAG_IO_16BIT)
295 drive->io_32bit = 0;
296 }
297
651c29a1
AM
298 touch_softlockup_watchdog();
299
1da177e4
LT
300 switch (drive->hwif->data_phase) {
301 case TASKFILE_MULTI_IN:
302 case TASKFILE_MULTI_OUT:
92d3ab27 303 ide_pio_multi(drive, rq, write);
1da177e4
LT
304 break;
305 default:
92d3ab27 306 ide_pio_sector(drive, rq, write);
1da177e4
LT
307 break;
308 }
35cf2b94
TH
309
310 drive->io_32bit = saved_io_32bit;
1da177e4
LT
311}
312
313static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
314 const char *s, u8 stat)
315{
316 if (rq->bio) {
317 ide_hwif_t *hwif = drive->hwif;
318 int sectors = hwif->nsect - hwif->nleft;
319
320 switch (hwif->data_phase) {
321 case TASKFILE_IN:
322 if (hwif->nleft)
323 break;
324 /* fall through */
325 case TASKFILE_OUT:
326 sectors--;
327 break;
328 case TASKFILE_MULTI_IN:
329 if (hwif->nleft)
330 break;
331 /* fall through */
332 case TASKFILE_MULTI_OUT:
333 sectors -= drive->mult_count;
334 default:
335 break;
336 }
337
338 if (sectors > 0) {
339 ide_driver_t *drv;
340
341 drv = *(ide_driver_t **)rq->rq_disk->private_data;
342 drv->end_request(drive, 1, sectors);
343 }
344 }
345 return ide_error(drive, s, stat);
346}
347
4d7a984b 348void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
1da177e4 349{
4aff5e23 350 if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
64a57fe4 351 u8 err = ide_read_error(drive);
1da177e4 352
4d7a984b
TH
353 ide_end_drive_cmd(drive, stat, err);
354 return;
1da177e4
LT
355 }
356
03731fbd
RP
357 if (rq->rq_disk) {
358 ide_driver_t *drv;
359
360 drv = *(ide_driver_t **)rq->rq_disk->private_data;;
79f21b84 361 drv->end_request(drive, 1, rq->nr_sectors);
03731fbd 362 } else
79f21b84 363 ide_end_request(drive, 1, rq->nr_sectors);
1da177e4
LT
364}
365
6c3c3158
LT
366/*
367 * We got an interrupt on a task_in case, but no errors and no DRQ.
368 *
369 * It might be a spurious irq (shared irq), but it might be a
370 * command that had no output.
371 */
372static ide_startstop_t task_in_unexpected(ide_drive_t *drive, struct request *rq, u8 stat)
373{
374 /* Command all done? */
375 if (OK_STAT(stat, READY_STAT, BUSY_STAT)) {
376 task_end_request(drive, rq, stat);
377 return ide_stopped;
378 }
379
380 /* Assume it was a spurious irq */
381 ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
382 return ide_started;
383}
384
1da177e4
LT
385/*
386 * Handler for command with PIO data-in phase (Read/Read Multiple).
387 */
f6e29e35 388static ide_startstop_t task_in_intr(ide_drive_t *drive)
1da177e4
LT
389{
390 ide_hwif_t *hwif = drive->hwif;
b73c7ee2
BZ
391 struct request *rq = hwif->hwgroup->rq;
392 u8 stat = hwif->read_status(hwif);
1da177e4 393
6c3c3158
LT
394 /* Error? */
395 if (stat & ERR_STAT)
eb63963a 396 return task_error(drive, rq, __func__, stat);
6c3c3158
LT
397
398 /* Didn't want any data? Odd. */
399 if (!(stat & DRQ_STAT))
400 return task_in_unexpected(drive, rq, stat);
1da177e4
LT
401
402 ide_pio_datablock(drive, rq, 0);
403
6c3c3158 404 /* Are we done? Check status and finish transfer. */
1da177e4
LT
405 if (!hwif->nleft) {
406 stat = wait_drive_not_busy(drive);
73d7de0c 407 if (!OK_STAT(stat, 0, BAD_STAT))
eb63963a 408 return task_error(drive, rq, __func__, stat);
1da177e4
LT
409 task_end_request(drive, rq, stat);
410 return ide_stopped;
411 }
412
413 /* Still data left to transfer. */
414 ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
415
416 return ide_started;
417}
1da177e4
LT
418
419/*
420 * Handler for command with PIO data-out phase (Write/Write Multiple).
421 */
422static ide_startstop_t task_out_intr (ide_drive_t *drive)
423{
424 ide_hwif_t *hwif = drive->hwif;
425 struct request *rq = HWGROUP(drive)->rq;
b73c7ee2 426 u8 stat = hwif->read_status(hwif);
1da177e4
LT
427
428 if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
eb63963a 429 return task_error(drive, rq, __func__, stat);
1da177e4
LT
430
431 /* Deal with unexpected ATA data phase. */
432 if (((stat & DRQ_STAT) == 0) ^ !hwif->nleft)
eb63963a 433 return task_error(drive, rq, __func__, stat);
1da177e4
LT
434
435 if (!hwif->nleft) {
436 task_end_request(drive, rq, stat);
437 return ide_stopped;
438 }
439
440 /* Still data left to transfer. */
441 ide_pio_datablock(drive, rq, 1);
442 ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
443
444 return ide_started;
445}
446
f6e29e35 447static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
1da177e4
LT
448{
449 ide_startstop_t startstop;
450
4906f3b4 451 if (ide_wait_stat(&startstop, drive, DRQ_STAT,
1da177e4
LT
452 drive->bad_wstat, WAIT_DRQ)) {
453 printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
454 drive->name,
455 drive->hwif->data_phase ? "MULT" : "",
456 drive->addressing ? "_EXT" : "");
457 return startstop;
458 }
459
460 if (!drive->unmask)
461 local_irq_disable();
462
463 ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
464 ide_pio_datablock(drive, rq, 1);
465
466 return ide_started;
467}
1da177e4 468
ac026ff2 469int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect)
1da177e4 470{
154ed280
FT
471 struct request *rq;
472 int error;
1da177e4 473
154ed280
FT
474 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
475 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
476 rq->buffer = buf;
1da177e4
LT
477
478 /*
479 * (ks) We transfer currently only whole sectors.
480 * This is suffient for now. But, it would be great,
481 * if we would find a solution to transfer any size.
482 * To support special commands like READ LONG.
483 */
154ed280
FT
484 rq->hard_nr_sectors = rq->nr_sectors = nsect;
485 rq->hard_cur_sectors = rq->current_nr_sectors = nsect;
1da177e4 486
ac026ff2 487 if (task->tf_flags & IDE_TFLAG_WRITE)
154ed280 488 rq->cmd_flags |= REQ_RW;
1da177e4 489
154ed280
FT
490 rq->special = task;
491 task->rq = rq;
1da177e4 492
154ed280
FT
493 error = blk_execute_rq(drive->queue, NULL, rq, 0);
494 blk_put_request(rq);
495
496 return error;
1da177e4
LT
497}
498
1da177e4
LT
499EXPORT_SYMBOL(ide_raw_taskfile);
500
9a3c49be
BZ
501int ide_no_data_taskfile(ide_drive_t *drive, ide_task_t *task)
502{
ac026ff2 503 task->data_phase = TASKFILE_NO_DATA;
9a3c49be 504
ac026ff2 505 return ide_raw_taskfile(drive, task, NULL, 0);
9a3c49be
BZ
506}
507EXPORT_SYMBOL_GPL(ide_no_data_taskfile);
508
26a5b040 509#ifdef CONFIG_IDE_TASK_IOCTL
1da177e4
LT
510int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
511{
512 ide_task_request_t *req_task;
513 ide_task_t args;
514 u8 *outbuf = NULL;
515 u8 *inbuf = NULL;
ac026ff2 516 u8 *data_buf = NULL;
1da177e4
LT
517 int err = 0;
518 int tasksize = sizeof(struct ide_task_request_s);
3a42bb22
AC
519 unsigned int taskin = 0;
520 unsigned int taskout = 0;
ac026ff2 521 u16 nsect = 0;
1da177e4
LT
522 char __user *buf = (char __user *)arg;
523
524// printk("IDE Taskfile ...\n");
525
f5e3c2fa 526 req_task = kzalloc(tasksize, GFP_KERNEL);
1da177e4 527 if (req_task == NULL) return -ENOMEM;
1da177e4
LT
528 if (copy_from_user(req_task, buf, tasksize)) {
529 kfree(req_task);
530 return -EFAULT;
531 }
532
3a42bb22
AC
533 taskout = req_task->out_size;
534 taskin = req_task->in_size;
535
536 if (taskin > 65536 || taskout > 65536) {
537 err = -EINVAL;
538 goto abort;
539 }
1da177e4
LT
540
541 if (taskout) {
542 int outtotal = tasksize;
f5e3c2fa 543 outbuf = kzalloc(taskout, GFP_KERNEL);
1da177e4
LT
544 if (outbuf == NULL) {
545 err = -ENOMEM;
546 goto abort;
547 }
1da177e4
LT
548 if (copy_from_user(outbuf, buf + outtotal, taskout)) {
549 err = -EFAULT;
550 goto abort;
551 }
552 }
553
554 if (taskin) {
555 int intotal = tasksize + taskout;
f5e3c2fa 556 inbuf = kzalloc(taskin, GFP_KERNEL);
1da177e4
LT
557 if (inbuf == NULL) {
558 err = -ENOMEM;
559 goto abort;
560 }
1da177e4
LT
561 if (copy_from_user(inbuf, buf + intotal, taskin)) {
562 err = -EFAULT;
563 goto abort;
564 }
565 }
566
567 memset(&args, 0, sizeof(ide_task_t));
1da177e4 568
650d841d
BZ
569 memcpy(&args.tf_array[0], req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2);
570 memcpy(&args.tf_array[6], req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
866e2ec9
BZ
571
572 args.data_phase = req_task->data_phase;
1da177e4 573
657cc1a8
BZ
574 args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE |
575 IDE_TFLAG_IN_TF;
a3bbb9d8 576 if (drive->addressing == 1)
657cc1a8 577 args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB);
a3bbb9d8 578
74095a91
BZ
579 if (req_task->out_flags.all) {
580 args.tf_flags |= IDE_TFLAG_FLAGGED;
581
582 if (req_task->out_flags.b.data)
583 args.tf_flags |= IDE_TFLAG_OUT_DATA;
584
585 if (req_task->out_flags.b.nsector_hob)
586 args.tf_flags |= IDE_TFLAG_OUT_HOB_NSECT;
587 if (req_task->out_flags.b.sector_hob)
588 args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAL;
589 if (req_task->out_flags.b.lcyl_hob)
590 args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAM;
591 if (req_task->out_flags.b.hcyl_hob)
592 args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAH;
593
594 if (req_task->out_flags.b.error_feature)
595 args.tf_flags |= IDE_TFLAG_OUT_FEATURE;
596 if (req_task->out_flags.b.nsector)
597 args.tf_flags |= IDE_TFLAG_OUT_NSECT;
598 if (req_task->out_flags.b.sector)
599 args.tf_flags |= IDE_TFLAG_OUT_LBAL;
600 if (req_task->out_flags.b.lcyl)
601 args.tf_flags |= IDE_TFLAG_OUT_LBAM;
602 if (req_task->out_flags.b.hcyl)
603 args.tf_flags |= IDE_TFLAG_OUT_LBAH;
a3bbb9d8
BZ
604 } else {
605 args.tf_flags |= IDE_TFLAG_OUT_TF;
606 if (args.tf_flags & IDE_TFLAG_LBA48)
607 args.tf_flags |= IDE_TFLAG_OUT_HOB;
74095a91
BZ
608 }
609
866e2ec9
BZ
610 if (req_task->in_flags.b.data)
611 args.tf_flags |= IDE_TFLAG_IN_DATA;
612
1da177e4 613 switch(req_task->data_phase) {
1da177e4
LT
614 case TASKFILE_MULTI_OUT:
615 if (!drive->mult_count) {
616 /* (hs): give up if multcount is not set */
617 printk(KERN_ERR "%s: %s Multimode Write " \
618 "multcount is not set\n",
eb63963a 619 drive->name, __func__);
1da177e4
LT
620 err = -EPERM;
621 goto abort;
622 }
623 /* fall through */
624 case TASKFILE_OUT:
ac026ff2
BZ
625 /* fall through */
626 case TASKFILE_OUT_DMAQ:
627 case TASKFILE_OUT_DMA:
628 nsect = taskout / SECTOR_SIZE;
629 data_buf = outbuf;
1da177e4
LT
630 break;
631 case TASKFILE_MULTI_IN:
632 if (!drive->mult_count) {
633 /* (hs): give up if multcount is not set */
634 printk(KERN_ERR "%s: %s Multimode Read failure " \
635 "multcount is not set\n",
eb63963a 636 drive->name, __func__);
1da177e4
LT
637 err = -EPERM;
638 goto abort;
639 }
640 /* fall through */
641 case TASKFILE_IN:
ac026ff2
BZ
642 /* fall through */
643 case TASKFILE_IN_DMAQ:
644 case TASKFILE_IN_DMA:
645 nsect = taskin / SECTOR_SIZE;
646 data_buf = inbuf;
1da177e4
LT
647 break;
648 case TASKFILE_NO_DATA:
1da177e4
LT
649 break;
650 default:
651 err = -EFAULT;
652 goto abort;
653 }
654
ac026ff2
BZ
655 if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA)
656 nsect = 0;
657 else if (!nsect) {
658 nsect = (args.tf.hob_nsect << 8) | args.tf.nsect;
659
660 if (!nsect) {
661 printk(KERN_ERR "%s: in/out command without data\n",
662 drive->name);
663 err = -EFAULT;
664 goto abort;
665 }
666 }
667
668 if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE)
669 args.tf_flags |= IDE_TFLAG_WRITE;
670
671 err = ide_raw_taskfile(drive, &args, data_buf, nsect);
672
650d841d
BZ
673 memcpy(req_task->hob_ports, &args.tf_array[0], HDIO_DRIVE_HOB_HDR_SIZE - 2);
674 memcpy(req_task->io_ports, &args.tf_array[6], HDIO_DRIVE_TASK_HDR_SIZE);
866e2ec9
BZ
675
676 if ((args.tf_flags & IDE_TFLAG_FLAGGED_SET_IN_FLAGS) &&
677 req_task->in_flags.all == 0) {
678 req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
679 if (drive->addressing == 1)
680 req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
681 }
1da177e4
LT
682
683 if (copy_to_user(buf, req_task, tasksize)) {
684 err = -EFAULT;
685 goto abort;
686 }
687 if (taskout) {
688 int outtotal = tasksize;
689 if (copy_to_user(buf + outtotal, outbuf, taskout)) {
690 err = -EFAULT;
691 goto abort;
692 }
693 }
694 if (taskin) {
695 int intotal = tasksize + taskout;
696 if (copy_to_user(buf + intotal, inbuf, taskin)) {
697 err = -EFAULT;
698 goto abort;
699 }
700 }
701abort:
702 kfree(req_task);
6044ec88
JJ
703 kfree(outbuf);
704 kfree(inbuf);
1da177e4
LT
705
706// printk("IDE Taskfile ioctl ended. rc = %i\n", err);
707
1da177e4
LT
708 return err;
709}
26a5b040 710#endif
1da177e4 711
1da177e4
LT
712int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
713{
5a9e77af
BZ
714 u8 *buf = NULL;
715 int bufsize = 0, err = 0;
716 u8 args[4], xfer_rate = 0;
1da177e4 717 ide_task_t tfargs;
650d841d 718 struct ide_taskfile *tf = &tfargs.tf;
5efe7c54 719 struct hd_driveid *id = drive->id;
1da177e4
LT
720
721 if (NULL == (void *) arg) {
154ed280 722 struct request *rq;
145b75e9 723
154ed280
FT
724 rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
725 rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
726 err = blk_execute_rq(drive->queue, NULL, rq, 0);
727 blk_put_request(rq);
145b75e9 728
154ed280 729 return err;
1da177e4
LT
730 }
731
732 if (copy_from_user(args, (void __user *)arg, 4))
733 return -EFAULT;
734
735 memset(&tfargs, 0, sizeof(ide_task_t));
650d841d 736 tf->feature = args[2];
5a9e77af
BZ
737 if (args[0] == WIN_SMART) {
738 tf->nsect = args[3];
739 tf->lbal = args[1];
740 tf->lbam = 0x4f;
741 tf->lbah = 0xc2;
742 tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
743 } else {
744 tf->nsect = args[1];
745 tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE |
746 IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT;
747 }
650d841d 748 tf->command = args[0];
5a9e77af 749 tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA;
1da177e4
LT
750
751 if (args[3]) {
5a9e77af
BZ
752 tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
753 bufsize = SECTOR_WORDS * 4 * args[3];
754 buf = kzalloc(bufsize, GFP_KERNEL);
755 if (buf == NULL)
1da177e4 756 return -ENOMEM;
1da177e4 757 }
5a9e77af 758
5efe7c54
BZ
759 if (tf->command == WIN_SETFEATURES &&
760 tf->feature == SETFEATURES_XFER &&
761 tf->nsect >= XFER_SW_DMA_0 &&
762 (id->dma_ultra || id->dma_mword || id->dma_1word)) {
1da177e4 763 xfer_rate = args[1];
af10f773
BZ
764 if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) {
765 printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
766 "be set\n", drive->name);
1da177e4 767 goto abort;
af10f773 768 }
1da177e4
LT
769 }
770
5a9e77af
BZ
771 err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
772
773 args[0] = tf->status;
774 args[1] = tf->error;
775 args[2] = tf->nsect;
1da177e4
LT
776
777 if (!err && xfer_rate) {
778 /* active-retuning-calls future */
779 ide_set_xfer_rate(drive, xfer_rate);
780 ide_driveid_update(drive);
781 }
782abort:
5a9e77af 783 if (copy_to_user((void __user *)arg, &args, 4))
1da177e4 784 err = -EFAULT;
5a9e77af
BZ
785 if (buf) {
786 if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
787 err = -EFAULT;
788 kfree(buf);
789 }
1da177e4
LT
790 return err;
791}
792
1da177e4
LT
793int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
794{
795 void __user *p = (void __user *)arg;
796 int err = 0;
14b89ef9
BZ
797 u8 args[7];
798 ide_task_t task;
1da177e4
LT
799
800 if (copy_from_user(args, p, 7))
801 return -EFAULT;
14b89ef9
BZ
802
803 memset(&task, 0, sizeof(task));
804 memcpy(&task.tf_array[7], &args[1], 6);
805 task.tf.command = args[0];
657cc1a8 806 task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
14b89ef9
BZ
807
808 err = ide_no_data_taskfile(drive, &task);
809
810 args[0] = task.tf.command;
811 memcpy(&args[1], &task.tf_array[7], 6);
812
813 if (copy_to_user(p, args, 7))
1da177e4 814 err = -EFAULT;
14b89ef9 815
1da177e4
LT
816 return err;
817}