ide-taskfile.c 19.6 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2 3 4
 *  Copyright (C) 2000-2002	   Michael Cornwell <cornwell@acm.org>
 *  Copyright (C) 2000-2002	   Andre Hedrick <andre@linux-ide.org>
 *  Copyright (C) 2001-2002	   Klaus Smolin
L
Linus Torvalds 已提交
5
 *					IBM Storage Technology Division
6
 *  Copyright (C) 2003-2004, 2007  Bartlomiej Zolnierkiewicz
L
Linus Torvalds 已提交
7 8 9 10 11 12 13
 *
 *  The big the bad and the ugly.
 */

#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
14
#include <linux/sched.h>
L
Linus Torvalds 已提交
15 16 17 18 19 20
#include <linux/interrupt.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
J
Jens Axboe 已提交
21
#include <linux/scatterlist.h>
L
Linus Torvalds 已提交
22 23 24 25

#include <asm/uaccess.h>
#include <asm/io.h>

26
void ide_tf_dump(const char *s, struct ide_taskfile *tf)
27
{
28 29 30
#ifdef DEBUG
	printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x "
		"lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n",
31
		s, tf->feature, tf->nsect, tf->lbal,
32
		tf->lbam, tf->lbah, tf->device, tf->command);
33 34
	printk("%s: hob: nsect 0x%02x lbal 0x%02x "
		"lbam 0x%02x lbah 0x%02x\n",
35
		s, tf->hob_nsect, tf->hob_lbal,
36
		tf->hob_lbam, tf->hob_lbah);
37
#endif
38 39
}

L
Linus Torvalds 已提交
40 41 42
int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf)
{
	ide_task_t args;
43

L
Linus Torvalds 已提交
44
	memset(&args, 0, sizeof(ide_task_t));
45
	args.tf.nsect = 0x01;
L
Linus Torvalds 已提交
46
	if (drive->media == ide_disk)
47
		args.tf.command = WIN_IDENTIFY;
L
Linus Torvalds 已提交
48
	else
49
		args.tf.command = WIN_PIDENTIFY;
50
	args.tf_flags	= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
51 52
	args.data_phase	= TASKFILE_IN;
	return ide_raw_taskfile(drive, &args, buf, 1);
L
Linus Torvalds 已提交
53 54
}

55
static ide_startstop_t task_no_data_intr(ide_drive_t *);
56 57 58
static ide_startstop_t set_geometry_intr(ide_drive_t *);
static ide_startstop_t recal_intr(ide_drive_t *);
static ide_startstop_t set_multmode_intr(ide_drive_t *);
59 60
static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct request *);
static ide_startstop_t task_in_intr(ide_drive_t *);
61

L
Linus Torvalds 已提交
62 63 64
ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
{
	ide_hwif_t *hwif	= HWIF(drive);
65
	struct ide_taskfile *tf = &task->tf;
66
	ide_handler_t *handler = NULL;
67
	const struct ide_dma_ops *dma_ops = hwif->dma_ops;
L
Linus Torvalds 已提交
68

69 70 71 72 73 74 75 76 77 78 79 80
	if (task->data_phase == TASKFILE_MULTI_IN ||
	    task->data_phase == TASKFILE_MULTI_OUT) {
		if (!drive->mult_count) {
			printk(KERN_ERR "%s: multimode not set!\n",
					drive->name);
			return ide_stopped;
		}
	}

	if (task->tf_flags & IDE_TFLAG_FLAGGED)
		task->tf_flags |= IDE_TFLAG_FLAGGED_SET_IN_FLAGS;

81 82
	if ((task->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
		ide_tf_dump(drive->name, tf);
83
		hwif->set_irq(hwif, 1);
84
		SELECT_MASK(drive, 0);
85
		hwif->tf_load(drive, task);
86
	}
L
Linus Torvalds 已提交
87

88 89 90
	switch (task->data_phase) {
	case TASKFILE_MULTI_OUT:
	case TASKFILE_OUT:
91
		hwif->exec_command(hwif, tf->command);
92 93 94 95
		ndelay(400);	/* FIXME */
		return pre_task_out_intr(drive, task->rq);
	case TASKFILE_MULTI_IN:
	case TASKFILE_IN:
96
		handler = task_in_intr;
97
		/* fall-through */
98
	case TASKFILE_NO_DATA:
99 100
		if (handler == NULL)
			handler = task_no_data_intr;
101
		/* WIN_{SPECIFY,RESTORE,SETMULT} use custom handlers */
102 103 104 105 106 107 108 109 110
		if (task->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) {
			switch (tf->command) {
			case WIN_SPECIFY: handler = set_geometry_intr;	break;
			case WIN_RESTORE: handler = recal_intr;		break;
			case WIN_SETMULT: handler = set_multmode_intr;	break;
			}
		}
		ide_execute_command(drive, tf->command, handler,
				    WAIT_WORSTCASE, NULL);
L
Linus Torvalds 已提交
111
		return ide_started;
112
	default:
113
		if (drive->using_dma == 0 || dma_ops->dma_setup(drive))
114
			return ide_stopped;
115 116
		dma_ops->dma_exec_cmd(drive, tf->command);
		dma_ops->dma_start(drive);
117
		return ide_started;
L
Linus Torvalds 已提交
118 119
	}
}
120
EXPORT_SYMBOL_GPL(do_rw_taskfile);
L
Linus Torvalds 已提交
121 122 123 124

/*
 * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
 */
125
static ide_startstop_t set_multmode_intr(ide_drive_t *drive)
L
Linus Torvalds 已提交
126
{
127 128
	ide_hwif_t *hwif = drive->hwif;
	u8 stat = hwif->read_status(hwif);
L
Linus Torvalds 已提交
129

130
	if (OK_STAT(stat, READY_STAT, BAD_STAT))
L
Linus Torvalds 已提交
131
		drive->mult_count = drive->mult_req;
132
	else {
L
Linus Torvalds 已提交
133 134 135 136 137 138 139 140 141 142
		drive->mult_req = drive->mult_count = 0;
		drive->special.b.recalibrate = 1;
		(void) ide_dump_status(drive, "set_multmode", stat);
	}
	return ide_stopped;
}

/*
 * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd.
 */
143
static ide_startstop_t set_geometry_intr(ide_drive_t *drive)
L
Linus Torvalds 已提交
144
{
145
	ide_hwif_t *hwif = drive->hwif;
L
Linus Torvalds 已提交
146 147 148
	int retries = 5;
	u8 stat;

149
	while (((stat = hwif->read_status(hwif)) & BUSY_STAT) && retries--)
L
Linus Torvalds 已提交
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
		udelay(10);

	if (OK_STAT(stat, READY_STAT, BAD_STAT))
		return ide_stopped;

	if (stat & (ERR_STAT|DRQ_STAT))
		return ide_error(drive, "set_geometry_intr", stat);

	ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL);
	return ide_started;
}

/*
 * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
 */
165
static ide_startstop_t recal_intr(ide_drive_t *drive)
L
Linus Torvalds 已提交
166
{
167 168
	ide_hwif_t *hwif = drive->hwif;
	u8 stat = hwif->read_status(hwif);
L
Linus Torvalds 已提交
169

170
	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
L
Linus Torvalds 已提交
171 172 173 174 175 176 177
		return ide_error(drive, "recal_intr", stat);
	return ide_stopped;
}

/*
 * Handler for commands without a data phase
 */
178
static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
L
Linus Torvalds 已提交
179
{
180 181
	ide_hwif_t *hwif = drive->hwif;
	ide_task_t *args = hwif->hwgroup->rq->special;
L
Linus Torvalds 已提交
182 183
	u8 stat;

184
	local_irq_enable_in_hardirq();
185
	stat = hwif->read_status(hwif);
186 187

	if (!OK_STAT(stat, READY_STAT, BAD_STAT))
L
Linus Torvalds 已提交
188 189
		return ide_error(drive, "task_no_data_intr", stat);
		/* calls ide_end_drive_cmd */
190

L
Linus Torvalds 已提交
191
	if (args)
192
		ide_end_drive_cmd(drive, stat, ide_read_error(drive));
L
Linus Torvalds 已提交
193 194 195 196

	return ide_stopped;
}

197
static u8 wait_drive_not_busy(ide_drive_t *drive)
L
Linus Torvalds 已提交
198
{
199
	ide_hwif_t *hwif = drive->hwif;
200
	int retries;
L
Linus Torvalds 已提交
201 202 203
	u8 stat;

	/*
204 205
	 * Last sector was transfered, wait until device is ready.  This can
	 * take up to 6 ms on some ATAPI devices, so we will wait max 10 ms.
L
Linus Torvalds 已提交
206
	 */
207
	for (retries = 0; retries < 1000; retries++) {
208
		stat = hwif->read_status(hwif);
209 210

		if (stat & BUSY_STAT)
211 212 213 214
			udelay(10);
		else
			break;
	}
L
Linus Torvalds 已提交
215

216
	if (stat & BUSY_STAT)
L
Linus Torvalds 已提交
217 218 219 220 221
		printk(KERN_ERR "%s: drive still BUSY!\n", drive->name);

	return stat;
}

222 223
static void ide_pio_sector(ide_drive_t *drive, struct request *rq,
			   unsigned int write)
L
Linus Torvalds 已提交
224 225 226
{
	ide_hwif_t *hwif = drive->hwif;
	struct scatterlist *sg = hwif->sg_table;
J
Jens Axboe 已提交
227
	struct scatterlist *cursg = hwif->cursg;
L
Linus Torvalds 已提交
228 229 230 231 232 233 234
	struct page *page;
#ifdef CONFIG_HIGHMEM
	unsigned long flags;
#endif
	unsigned int offset;
	u8 *buf;

J
Jens Axboe 已提交
235 236 237 238 239 240
	cursg = hwif->cursg;
	if (!cursg) {
		cursg = sg;
		hwif->cursg = sg;
	}

J
Jens Axboe 已提交
241
	page = sg_page(cursg);
J
Jens Axboe 已提交
242
	offset = cursg->offset + hwif->cursg_ofs * SECTOR_SIZE;
L
Linus Torvalds 已提交
243 244 245 246 247 248 249 250 251 252 253 254 255

	/* get the current page and offset */
	page = nth_page(page, (offset >> PAGE_SHIFT));
	offset %= PAGE_SIZE;

#ifdef CONFIG_HIGHMEM
	local_irq_save(flags);
#endif
	buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;

	hwif->nleft--;
	hwif->cursg_ofs++;

J
Jens Axboe 已提交
256 257
	if ((hwif->cursg_ofs * SECTOR_SIZE) == cursg->length) {
		hwif->cursg = sg_next(hwif->cursg);
L
Linus Torvalds 已提交
258 259 260 261 262
		hwif->cursg_ofs = 0;
	}

	/* do the actual data transfer */
	if (write)
263
		hwif->output_data(drive, rq, buf, SECTOR_SIZE);
L
Linus Torvalds 已提交
264
	else
265
		hwif->input_data(drive, rq, buf, SECTOR_SIZE);
L
Linus Torvalds 已提交
266 267 268 269 270 271 272

	kunmap_atomic(buf, KM_BIO_SRC_IRQ);
#ifdef CONFIG_HIGHMEM
	local_irq_restore(flags);
#endif
}

273 274
static void ide_pio_multi(ide_drive_t *drive, struct request *rq,
			  unsigned int write)
L
Linus Torvalds 已提交
275 276 277 278 279
{
	unsigned int nsect;

	nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count);
	while (nsect--)
280
		ide_pio_sector(drive, rq, write);
L
Linus Torvalds 已提交
281 282
}

283
static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
L
Linus Torvalds 已提交
284 285
				     unsigned int write)
{
286 287
	u8 saved_io_32bit = drive->io_32bit;

L
Linus Torvalds 已提交
288 289 290
	if (rq->bio)	/* fs request */
		rq->errors = 0;

291 292 293 294 295 296 297
	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
		ide_task_t *task = rq->special;

		if (task->tf_flags & IDE_TFLAG_IO_16BIT)
			drive->io_32bit = 0;
	}

298 299
	touch_softlockup_watchdog();

L
Linus Torvalds 已提交
300 301 302
	switch (drive->hwif->data_phase) {
	case TASKFILE_MULTI_IN:
	case TASKFILE_MULTI_OUT:
303
		ide_pio_multi(drive, rq, write);
L
Linus Torvalds 已提交
304 305
		break;
	default:
306
		ide_pio_sector(drive, rq, write);
L
Linus Torvalds 已提交
307 308
		break;
	}
309 310

	drive->io_32bit = saved_io_32bit;
L
Linus Torvalds 已提交
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
}

static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
				  const char *s, u8 stat)
{
	if (rq->bio) {
		ide_hwif_t *hwif = drive->hwif;
		int sectors = hwif->nsect - hwif->nleft;

		switch (hwif->data_phase) {
		case TASKFILE_IN:
			if (hwif->nleft)
				break;
			/* fall through */
		case TASKFILE_OUT:
			sectors--;
			break;
		case TASKFILE_MULTI_IN:
			if (hwif->nleft)
				break;
			/* fall through */
		case TASKFILE_MULTI_OUT:
			sectors -= drive->mult_count;
		default:
			break;
		}

		if (sectors > 0) {
			ide_driver_t *drv;

			drv = *(ide_driver_t **)rq->rq_disk->private_data;
			drv->end_request(drive, 1, sectors);
		}
	}
	return ide_error(drive, s, stat);
}

T
Tejun Heo 已提交
348
void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
L
Linus Torvalds 已提交
349
{
350
	if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
351
		u8 err = ide_read_error(drive);
L
Linus Torvalds 已提交
352

T
Tejun Heo 已提交
353 354
		ide_end_drive_cmd(drive, stat, err);
		return;
L
Linus Torvalds 已提交
355 356
	}

357 358 359 360
	if (rq->rq_disk) {
		ide_driver_t *drv;

		drv = *(ide_driver_t **)rq->rq_disk->private_data;;
361
		drv->end_request(drive, 1, rq->nr_sectors);
362
	} else
363
		ide_end_request(drive, 1, rq->nr_sectors);
L
Linus Torvalds 已提交
364 365
}

366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
/*
 * We got an interrupt on a task_in case, but no errors and no DRQ.
 *
 * It might be a spurious irq (shared irq), but it might be a
 * command that had no output.
 */
static ide_startstop_t task_in_unexpected(ide_drive_t *drive, struct request *rq, u8 stat)
{
	/* Command all done? */
	if (OK_STAT(stat, READY_STAT, BUSY_STAT)) {
		task_end_request(drive, rq, stat);
		return ide_stopped;
	}

	/* Assume it was a spurious irq */
	ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
	return ide_started;
}

L
Linus Torvalds 已提交
385 386 387
/*
 * Handler for command with PIO data-in phase (Read/Read Multiple).
 */
388
static ide_startstop_t task_in_intr(ide_drive_t *drive)
L
Linus Torvalds 已提交
389 390
{
	ide_hwif_t *hwif = drive->hwif;
391 392
	struct request *rq = hwif->hwgroup->rq;
	u8 stat = hwif->read_status(hwif);
L
Linus Torvalds 已提交
393

394 395
	/* Error? */
	if (stat & ERR_STAT)
396
		return task_error(drive, rq, __func__, stat);
397 398 399 400

	/* Didn't want any data? Odd. */
	if (!(stat & DRQ_STAT))
		return task_in_unexpected(drive, rq, stat);
L
Linus Torvalds 已提交
401 402 403

	ide_pio_datablock(drive, rq, 0);

404
	/* Are we done? Check status and finish transfer. */
L
Linus Torvalds 已提交
405 406
	if (!hwif->nleft) {
		stat = wait_drive_not_busy(drive);
407
		if (!OK_STAT(stat, 0, BAD_STAT))
408
			return task_error(drive, rq, __func__, stat);
L
Linus Torvalds 已提交
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
		task_end_request(drive, rq, stat);
		return ide_stopped;
	}

	/* Still data left to transfer. */
	ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);

	return ide_started;
}

/*
 * Handler for command with PIO data-out phase (Write/Write Multiple).
 */
static ide_startstop_t task_out_intr (ide_drive_t *drive)
{
	ide_hwif_t *hwif = drive->hwif;
	struct request *rq = HWGROUP(drive)->rq;
426
	u8 stat = hwif->read_status(hwif);
L
Linus Torvalds 已提交
427 428

	if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
429
		return task_error(drive, rq, __func__, stat);
L
Linus Torvalds 已提交
430 431 432

	/* Deal with unexpected ATA data phase. */
	if (((stat & DRQ_STAT) == 0) ^ !hwif->nleft)
433
		return task_error(drive, rq, __func__, stat);
L
Linus Torvalds 已提交
434 435 436 437 438 439 440 441 442 443 444 445 446

	if (!hwif->nleft) {
		task_end_request(drive, rq, stat);
		return ide_stopped;
	}

	/* Still data left to transfer. */
	ide_pio_datablock(drive, rq, 1);
	ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);

	return ide_started;
}

447
static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
L
Linus Torvalds 已提交
448 449 450
{
	ide_startstop_t startstop;

451
	if (ide_wait_stat(&startstop, drive, DRQ_STAT,
L
Linus Torvalds 已提交
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
			  drive->bad_wstat, WAIT_DRQ)) {
		printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
				drive->name,
				drive->hwif->data_phase ? "MULT" : "",
				drive->addressing ? "_EXT" : "");
		return startstop;
	}

	if (!drive->unmask)
		local_irq_disable();

	ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
	ide_pio_datablock(drive, rq, 1);

	return ide_started;
}

469
int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect)
L
Linus Torvalds 已提交
470
{
471 472
	struct request *rq;
	int error;
L
Linus Torvalds 已提交
473

474 475 476
	rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
	rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
	rq->buffer = buf;
L
Linus Torvalds 已提交
477 478 479 480 481 482 483

	/*
	 * (ks) We transfer currently only whole sectors.
	 * This is suffient for now.  But, it would be great,
	 * if we would find a solution to transfer any size.
	 * To support special commands like READ LONG.
	 */
484 485
	rq->hard_nr_sectors = rq->nr_sectors = nsect;
	rq->hard_cur_sectors = rq->current_nr_sectors = nsect;
L
Linus Torvalds 已提交
486

487
	if (task->tf_flags & IDE_TFLAG_WRITE)
488
		rq->cmd_flags |= REQ_RW;
L
Linus Torvalds 已提交
489

490 491
	rq->special = task;
	task->rq = rq;
L
Linus Torvalds 已提交
492

493 494 495 496
	error = blk_execute_rq(drive->queue, NULL, rq, 0);
	blk_put_request(rq);

	return error;
L
Linus Torvalds 已提交
497 498 499 500
}

EXPORT_SYMBOL(ide_raw_taskfile);

501 502
int ide_no_data_taskfile(ide_drive_t *drive, ide_task_t *task)
{
503
	task->data_phase = TASKFILE_NO_DATA;
504

505
	return ide_raw_taskfile(drive, task, NULL, 0);
506 507 508
}
EXPORT_SYMBOL_GPL(ide_no_data_taskfile);

509
#ifdef CONFIG_IDE_TASK_IOCTL
L
Linus Torvalds 已提交
510 511 512 513 514 515
int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
{
	ide_task_request_t	*req_task;
	ide_task_t		args;
	u8 *outbuf		= NULL;
	u8 *inbuf		= NULL;
516
	u8 *data_buf		= NULL;
L
Linus Torvalds 已提交
517 518
	int err			= 0;
	int tasksize		= sizeof(struct ide_task_request_s);
519 520
	unsigned int taskin	= 0;
	unsigned int taskout	= 0;
521
	u16 nsect		= 0;
L
Linus Torvalds 已提交
522 523 524 525
	char __user *buf = (char __user *)arg;

//	printk("IDE Taskfile ...\n");

526
	req_task = kzalloc(tasksize, GFP_KERNEL);
L
Linus Torvalds 已提交
527 528 529 530 531 532
	if (req_task == NULL) return -ENOMEM;
	if (copy_from_user(req_task, buf, tasksize)) {
		kfree(req_task);
		return -EFAULT;
	}

533 534 535 536 537 538 539
	taskout = req_task->out_size;
	taskin  = req_task->in_size;
	
	if (taskin > 65536 || taskout > 65536) {
		err = -EINVAL;
		goto abort;
	}
L
Linus Torvalds 已提交
540 541 542

	if (taskout) {
		int outtotal = tasksize;
543
		outbuf = kzalloc(taskout, GFP_KERNEL);
L
Linus Torvalds 已提交
544 545 546 547 548 549 550 551 552 553 554 555
		if (outbuf == NULL) {
			err = -ENOMEM;
			goto abort;
		}
		if (copy_from_user(outbuf, buf + outtotal, taskout)) {
			err = -EFAULT;
			goto abort;
		}
	}

	if (taskin) {
		int intotal = tasksize + taskout;
556
		inbuf = kzalloc(taskin, GFP_KERNEL);
L
Linus Torvalds 已提交
557 558 559 560 561 562 563 564 565 566 567 568
		if (inbuf == NULL) {
			err = -ENOMEM;
			goto abort;
		}
		if (copy_from_user(inbuf, buf + intotal, taskin)) {
			err = -EFAULT;
			goto abort;
		}
	}

	memset(&args, 0, sizeof(ide_task_t));

569 570
	memcpy(&args.tf_array[0], req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2);
	memcpy(&args.tf_array[6], req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);
571 572

	args.data_phase = req_task->data_phase;
L
Linus Torvalds 已提交
573

574 575
	args.tf_flags = IDE_TFLAG_IO_16BIT | IDE_TFLAG_DEVICE |
			IDE_TFLAG_IN_TF;
576
	if (drive->addressing == 1)
577
		args.tf_flags |= (IDE_TFLAG_LBA48 | IDE_TFLAG_IN_HOB);
578

579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
	if (req_task->out_flags.all) {
		args.tf_flags |= IDE_TFLAG_FLAGGED;

		if (req_task->out_flags.b.data)
			args.tf_flags |= IDE_TFLAG_OUT_DATA;

		if (req_task->out_flags.b.nsector_hob)
			args.tf_flags |= IDE_TFLAG_OUT_HOB_NSECT;
		if (req_task->out_flags.b.sector_hob)
			args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAL;
		if (req_task->out_flags.b.lcyl_hob)
			args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAM;
		if (req_task->out_flags.b.hcyl_hob)
			args.tf_flags |= IDE_TFLAG_OUT_HOB_LBAH;

		if (req_task->out_flags.b.error_feature)
			args.tf_flags |= IDE_TFLAG_OUT_FEATURE;
		if (req_task->out_flags.b.nsector)
			args.tf_flags |= IDE_TFLAG_OUT_NSECT;
		if (req_task->out_flags.b.sector)
			args.tf_flags |= IDE_TFLAG_OUT_LBAL;
		if (req_task->out_flags.b.lcyl)
			args.tf_flags |= IDE_TFLAG_OUT_LBAM;
		if (req_task->out_flags.b.hcyl)
			args.tf_flags |= IDE_TFLAG_OUT_LBAH;
604 605 606 607
	} else {
		args.tf_flags |= IDE_TFLAG_OUT_TF;
		if (args.tf_flags & IDE_TFLAG_LBA48)
			args.tf_flags |= IDE_TFLAG_OUT_HOB;
608 609
	}

610 611 612
	if (req_task->in_flags.b.data)
		args.tf_flags |= IDE_TFLAG_IN_DATA;

L
Linus Torvalds 已提交
613 614 615 616 617 618
	switch(req_task->data_phase) {
		case TASKFILE_MULTI_OUT:
			if (!drive->mult_count) {
				/* (hs): give up if multcount is not set */
				printk(KERN_ERR "%s: %s Multimode Write " \
					"multcount is not set\n",
619
					drive->name, __func__);
L
Linus Torvalds 已提交
620 621 622 623 624
				err = -EPERM;
				goto abort;
			}
			/* fall through */
		case TASKFILE_OUT:
625 626 627 628 629
			/* fall through */
		case TASKFILE_OUT_DMAQ:
		case TASKFILE_OUT_DMA:
			nsect = taskout / SECTOR_SIZE;
			data_buf = outbuf;
L
Linus Torvalds 已提交
630 631 632 633 634 635
			break;
		case TASKFILE_MULTI_IN:
			if (!drive->mult_count) {
				/* (hs): give up if multcount is not set */
				printk(KERN_ERR "%s: %s Multimode Read failure " \
					"multcount is not set\n",
636
					drive->name, __func__);
L
Linus Torvalds 已提交
637 638 639 640 641
				err = -EPERM;
				goto abort;
			}
			/* fall through */
		case TASKFILE_IN:
642 643 644 645 646
			/* fall through */
		case TASKFILE_IN_DMAQ:
		case TASKFILE_IN_DMA:
			nsect = taskin / SECTOR_SIZE;
			data_buf = inbuf;
L
Linus Torvalds 已提交
647 648 649 650 651 652 653 654
			break;
		case TASKFILE_NO_DATA:
			break;
		default:
			err = -EFAULT;
			goto abort;
	}

655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
	if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA)
		nsect = 0;
	else if (!nsect) {
		nsect = (args.tf.hob_nsect << 8) | args.tf.nsect;

		if (!nsect) {
			printk(KERN_ERR "%s: in/out command without data\n",
					drive->name);
			err = -EFAULT;
			goto abort;
		}
	}

	if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE)
		args.tf_flags |= IDE_TFLAG_WRITE;

	err = ide_raw_taskfile(drive, &args, data_buf, nsect);

673 674
	memcpy(req_task->hob_ports, &args.tf_array[0], HDIO_DRIVE_HOB_HDR_SIZE - 2);
	memcpy(req_task->io_ports, &args.tf_array[6], HDIO_DRIVE_TASK_HDR_SIZE);
675 676 677 678 679 680 681

	if ((args.tf_flags & IDE_TFLAG_FLAGGED_SET_IN_FLAGS) &&
	    req_task->in_flags.all == 0) {
		req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
		if (drive->addressing == 1)
			req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
	}
L
Linus Torvalds 已提交
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702

	if (copy_to_user(buf, req_task, tasksize)) {
		err = -EFAULT;
		goto abort;
	}
	if (taskout) {
		int outtotal = tasksize;
		if (copy_to_user(buf + outtotal, outbuf, taskout)) {
			err = -EFAULT;
			goto abort;
		}
	}
	if (taskin) {
		int intotal = tasksize + taskout;
		if (copy_to_user(buf + intotal, inbuf, taskin)) {
			err = -EFAULT;
			goto abort;
		}
	}
abort:
	kfree(req_task);
703 704
	kfree(outbuf);
	kfree(inbuf);
L
Linus Torvalds 已提交
705 706 707 708 709

//	printk("IDE Taskfile ioctl ended. rc = %i\n", err);

	return err;
}
710
#endif
L
Linus Torvalds 已提交
711 712 713

int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
{
714 715 716
	u8 *buf = NULL;
	int bufsize = 0, err = 0;
	u8 args[4], xfer_rate = 0;
L
Linus Torvalds 已提交
717
	ide_task_t tfargs;
718
	struct ide_taskfile *tf = &tfargs.tf;
719
	struct hd_driveid *id = drive->id;
L
Linus Torvalds 已提交
720 721

	if (NULL == (void *) arg) {
722
		struct request *rq;
723

724 725 726 727
		rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
		rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
		err = blk_execute_rq(drive->queue, NULL, rq, 0);
		blk_put_request(rq);
728

729
		return err;
L
Linus Torvalds 已提交
730 731 732 733 734 735
	}

	if (copy_from_user(args, (void __user *)arg, 4))
		return -EFAULT;

	memset(&tfargs, 0, sizeof(ide_task_t));
736
	tf->feature = args[2];
737 738 739 740 741 742 743 744 745 746 747
	if (args[0] == WIN_SMART) {
		tf->nsect = args[3];
		tf->lbal  = args[1];
		tf->lbam  = 0x4f;
		tf->lbah  = 0xc2;
		tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
	} else {
		tf->nsect = args[1];
		tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE |
				  IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT;
	}
748
	tf->command = args[0];
749
	tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA;
L
Linus Torvalds 已提交
750 751

	if (args[3]) {
752 753 754 755
		tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
		bufsize = SECTOR_WORDS * 4 * args[3];
		buf = kzalloc(bufsize, GFP_KERNEL);
		if (buf == NULL)
L
Linus Torvalds 已提交
756 757
			return -ENOMEM;
	}
758

759 760 761 762
	if (tf->command == WIN_SETFEATURES &&
	    tf->feature == SETFEATURES_XFER &&
	    tf->nsect >= XFER_SW_DMA_0 &&
	    (id->dma_ultra || id->dma_mword || id->dma_1word)) {
L
Linus Torvalds 已提交
763
		xfer_rate = args[1];
764 765 766
		if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) {
			printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
					    "be set\n", drive->name);
L
Linus Torvalds 已提交
767
			goto abort;
768
		}
L
Linus Torvalds 已提交
769 770
	}

771 772 773 774 775
	err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);

	args[0] = tf->status;
	args[1] = tf->error;
	args[2] = tf->nsect;
L
Linus Torvalds 已提交
776 777 778 779 780 781 782

	if (!err && xfer_rate) {
		/* active-retuning-calls future */
		ide_set_xfer_rate(drive, xfer_rate);
		ide_driveid_update(drive);
	}
abort:
783
	if (copy_to_user((void __user *)arg, &args, 4))
L
Linus Torvalds 已提交
784
		err = -EFAULT;
785 786 787 788 789
	if (buf) {
		if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
			err = -EFAULT;
		kfree(buf);
	}
L
Linus Torvalds 已提交
790 791 792 793 794 795 796
	return err;
}

int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
{
	void __user *p = (void __user *)arg;
	int err = 0;
797 798
	u8 args[7];
	ide_task_t task;
L
Linus Torvalds 已提交
799 800 801

	if (copy_from_user(args, p, 7))
		return -EFAULT;
802 803 804 805

	memset(&task, 0, sizeof(task));
	memcpy(&task.tf_array[7], &args[1], 6);
	task.tf.command = args[0];
806
	task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
807 808 809 810 811 812 813

	err = ide_no_data_taskfile(drive, &task);

	args[0] = task.tf.command;
	memcpy(&args[1], &task.tf_array[7], 6);

	if (copy_to_user(p, args, 7))
L
Linus Torvalds 已提交
814
		err = -EFAULT;
815

L
Linus Torvalds 已提交
816 817
	return err;
}