11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
259bca8cc995428c34d8cdfadfa87c8e3f01c4340Bartlomiej Zolnierkiewicz *  Copyright (C) 2000-2002	   Michael Cornwell <cornwell@acm.org>
359bca8cc995428c34d8cdfadfa87c8e3f01c4340Bartlomiej Zolnierkiewicz *  Copyright (C) 2000-2002	   Andre Hedrick <andre@linux-ide.org>
459bca8cc995428c34d8cdfadfa87c8e3f01c4340Bartlomiej Zolnierkiewicz *  Copyright (C) 2001-2002	   Klaus Smolin
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					IBM Storage Technology Division
659bca8cc995428c34d8cdfadfa87c8e3f01c4340Bartlomiej Zolnierkiewicz *  Copyright (C) 2003-2004, 2007  Bartlomiej Zolnierkiewicz
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  The big the bad and the ugly.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
1438789fda295689689d064c0157bc363b1837b5e6Paul Gortmaker#include <linux/export.h>
15651c29a17f7ea0204dacbc2a5042d57b1c9e2e37Andrew Morton#include <linux/sched.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/hdreg.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ide.h>
2255c16a70041ba55e235c5944dccb9c1de0dd3ca6Jens Axboe#include <linux/scatterlist.h>
232d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput#include <linux/uaccess.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
273153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyovvoid ide_tf_readback(ide_drive_t *drive, struct ide_cmd *cmd)
283153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov{
293153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov	ide_hwif_t *hwif = drive->hwif;
303153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov	const struct ide_tp_ops *tp_ops = hwif->tp_ops;
313153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov
323153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov	/* Be sure we're looking at the low order bytes */
333153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov	tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
343153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov
353153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov	tp_ops->tf_read(drive, &cmd->tf, cmd->valid.in.tf);
363153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov
373153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov	if (cmd->tf_flags & IDE_TFLAG_LBA48) {
383153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov		tp_ops->write_devctl(hwif, ATA_HOB | ATA_DEVCTL_OBS);
393153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov
403153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov		tp_ops->tf_read(drive, &cmd->hob, cmd->valid.in.hob);
413153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov	}
423153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov}
433153c26b54230d025c6d536e8d3015def4524906Sergei Shtylyov
44745483f10c6cefb303007c6873e2bfce54efa8edSergei Shtylyovvoid ide_tf_dump(const char *s, struct ide_cmd *cmd)
459e42237f26cf517a3f682505f03a3a8d89b3b35dBartlomiej Zolnierkiewicz{
46807e35d695690011faa1ce3ad67dfc23c1e39bdcBartlomiej Zolnierkiewicz#ifdef DEBUG
47807e35d695690011faa1ce3ad67dfc23c1e39bdcBartlomiej Zolnierkiewicz	printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x "
48807e35d695690011faa1ce3ad67dfc23c1e39bdcBartlomiej Zolnierkiewicz		"lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x\n",
49745483f10c6cefb303007c6873e2bfce54efa8edSergei Shtylyov	       s, cmd->tf.feature, cmd->tf.nsect,
50745483f10c6cefb303007c6873e2bfce54efa8edSergei Shtylyov	       cmd->tf.lbal, cmd->tf.lbam, cmd->tf.lbah,
51745483f10c6cefb303007c6873e2bfce54efa8edSergei Shtylyov	       cmd->tf.device, cmd->tf.command);
52745483f10c6cefb303007c6873e2bfce54efa8edSergei Shtylyov	printk("%s: hob: nsect 0x%02x lbal 0x%02x lbam 0x%02x lbah 0x%02x\n",
53745483f10c6cefb303007c6873e2bfce54efa8edSergei Shtylyov	       s, cmd->hob.nsect, cmd->hob.lbal, cmd->hob.lbam, cmd->hob.lbah);
54807e35d695690011faa1ce3ad67dfc23c1e39bdcBartlomiej Zolnierkiewicz#endif
55089c5c7e0089c3461545be936bcd236cbf16b79aBartlomiej Zolnierkiewicz}
56089c5c7e0089c3461545be936bcd236cbf16b79aBartlomiej Zolnierkiewicz
572d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajputint taskfile_lib_get_identify(ide_drive_t *drive, u8 *buf)
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
5922aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	struct ide_cmd cmd;
60650d841d9e053a618dd8ce753422f91b493cf2f6Bartlomiej Zolnierkiewicz
6122aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	memset(&cmd, 0, sizeof(cmd));
6222aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	cmd.tf.nsect = 0x01;
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (drive->media == ide_disk)
6422aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz		cmd.tf.command = ATA_CMD_ID_ATA;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
6622aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz		cmd.tf.command = ATA_CMD_ID_ATAPI;
6760f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov	cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
6860f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov	cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
690dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz	cmd.protocol = ATA_PROT_PIO;
7022aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz
7122aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	return ide_raw_taskfile(drive, &cmd, buf, 1);
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741192e528e064ebb9a578219731d2b0f78ca3c1ecBartlomiej Zolnierkiewiczstatic ide_startstop_t task_no_data_intr(ide_drive_t *);
75adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewiczstatic ide_startstop_t pre_task_out_intr(ide_drive_t *, struct ide_cmd *);
76901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewiczstatic ide_startstop_t task_pio_intr(ide_drive_t *);
771192e528e064ebb9a578219731d2b0f78ca3c1ecBartlomiej Zolnierkiewicz
78adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewiczide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd)
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
80898ec223fea2a2df88035e58dbf50f493577e225Bartlomiej Zolnierkiewicz	ide_hwif_t *hwif = drive->hwif;
81adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewicz	struct ide_cmd *cmd = &hwif->cmd;
8222aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	struct ide_taskfile *tf = &cmd->tf;
8357d7366b78b74a9eef873e8212c03d8c2033a764Bartlomiej Zolnierkiewicz	ide_handler_t *handler = NULL;
84374e042c3e767ac2e5a40b78529220e0b3de793cBartlomiej Zolnierkiewicz	const struct ide_tp_ops *tp_ops = hwif->tp_ops;
85f37afdaca711838b50ecd89b9c15fc745270d77cBartlomiej Zolnierkiewicz	const struct ide_dma_ops *dma_ops = hwif->dma_ops;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
870dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz	if (orig_cmd->protocol == ATA_PROT_PIO &&
880dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz	    (orig_cmd->tf_flags & IDE_TFLAG_MULTI_PIO) &&
890dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz	    drive->mult_count == 0) {
902d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		pr_err("%s: multimode not set!\n", drive->name);
910dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz		return ide_stopped;
921edee60e9d994f2b9a79b1333be39790683541feBartlomiej Zolnierkiewicz	}
931edee60e9d994f2b9a79b1333be39790683541feBartlomiej Zolnierkiewicz
94adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewicz	if (orig_cmd->ftf_flags & IDE_FTFLAG_FLAGGED)
95adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewicz		orig_cmd->ftf_flags |= IDE_FTFLAG_SET_IN_FLAGS;
961edee60e9d994f2b9a79b1333be39790683541feBartlomiej Zolnierkiewicz
97adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewicz	memcpy(cmd, orig_cmd, sizeof(*cmd));
98d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz
9922aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) {
100745483f10c6cefb303007c6873e2bfce54efa8edSergei Shtylyov		ide_tf_dump(drive->name, cmd);
101ecf3a31d2a08a419bdf919456f1724f5b72bde2cSergei Shtylyov		tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS);
10235218d1ca808ed19b8c6f079ce91872b3deb2219Sergei Shtylyov
10335218d1ca808ed19b8c6f079ce91872b3deb2219Sergei Shtylyov		if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) {
104745483f10c6cefb303007c6873e2bfce54efa8edSergei Shtylyov			u8 data[2] = { cmd->tf.data, cmd->hob.data };
10535218d1ca808ed19b8c6f079ce91872b3deb2219Sergei Shtylyov
10635218d1ca808ed19b8c6f079ce91872b3deb2219Sergei Shtylyov			tp_ops->output_data(drive, cmd, data, 2);
10735218d1ca808ed19b8c6f079ce91872b3deb2219Sergei Shtylyov		}
1084109d19af73826aa6fee1a1b951670381be88f8bSergei Shtylyov
1094109d19af73826aa6fee1a1b951670381be88f8bSergei Shtylyov		if (cmd->valid.out.tf & IDE_VALID_DEVICE) {
1104109d19af73826aa6fee1a1b951670381be88f8bSergei Shtylyov			u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ?
1114109d19af73826aa6fee1a1b951670381be88f8bSergei Shtylyov				  0xE0 : 0xEF;
1124109d19af73826aa6fee1a1b951670381be88f8bSergei Shtylyov
1134109d19af73826aa6fee1a1b951670381be88f8bSergei Shtylyov			if (!(cmd->ftf_flags & IDE_FTFLAG_FLAGGED))
1144109d19af73826aa6fee1a1b951670381be88f8bSergei Shtylyov				cmd->tf.device &= HIHI;
1154109d19af73826aa6fee1a1b951670381be88f8bSergei Shtylyov			cmd->tf.device |= drive->select;
1164109d19af73826aa6fee1a1b951670381be88f8bSergei Shtylyov		}
1174109d19af73826aa6fee1a1b951670381be88f8bSergei Shtylyov
118c9ff9e7b64138d87023b733e618f29a1d58543f7Sergei Shtylyov		tp_ops->tf_load(drive, &cmd->hob, cmd->valid.out.hob);
119c9ff9e7b64138d87023b733e618f29a1d58543f7Sergei Shtylyov		tp_ops->tf_load(drive, &cmd->tf,  cmd->valid.out.tf);
120089c5c7e0089c3461545be936bcd236cbf16b79aBartlomiej Zolnierkiewicz	}
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1220dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz	switch (cmd->protocol) {
1230dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz	case ATA_PROT_PIO:
1240dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz		if (cmd->tf_flags & IDE_TFLAG_WRITE) {
1250dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz			tp_ops->exec_command(hwif, tf->command);
1260dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz			ndelay(400);	/* FIXME */
1270dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz			return pre_task_out_intr(drive, cmd);
1280dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz		}
129901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz		handler = task_pio_intr;
1301192e528e064ebb9a578219731d2b0f78ca3c1ecBartlomiej Zolnierkiewicz		/* fall-through */
1310dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz	case ATA_PROT_NODATA:
13257d7366b78b74a9eef873e8212c03d8c2033a764Bartlomiej Zolnierkiewicz		if (handler == NULL)
13357d7366b78b74a9eef873e8212c03d8c2033a764Bartlomiej Zolnierkiewicz			handler = task_no_data_intr;
13435b5d0be3d8de9a5ac51471c12029fb115200cdcBartlomiej Zolnierkiewicz		ide_execute_command(drive, cmd, handler, WAIT_WORSTCASE);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ide_started;
136b788ee9c6561fd9219a503216284d61036a0dc0bBartlomiej Zolnierkiewicz	case ATA_PROT_DMA:
1375ae5412d9a23b05ab08461b202bad21ad8f6b66dBartlomiej Zolnierkiewicz		if (ide_dma_prepare(drive, cmd))
13810d90157c83d4b6743c9063c36f9e7f27aa254b6Bartlomiej Zolnierkiewicz			return ide_stopped;
13922117d6eaac50d366d9013c88318a869ea4d8739Bartlomiej Zolnierkiewicz		hwif->expiry = dma_ops->dma_timer_expiry;
14035b5d0be3d8de9a5ac51471c12029fb115200cdcBartlomiej Zolnierkiewicz		ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD);
1415e37bdc081a980dd0d669e6387bcf15ca9666f81Bartlomiej Zolnierkiewicz		dma_ops->dma_start(drive);
142b788ee9c6561fd9219a503216284d61036a0dc0bBartlomiej Zolnierkiewicz	default:
14374095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz		return ide_started;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
146f6e29e35cc0f9facf2eb0b0454f9b09021b5aa6fBartlomiej ZolnierkiewiczEXPORT_SYMBOL_GPL(do_rw_taskfile);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
148d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewiczstatic ide_startstop_t task_no_data_intr(ide_drive_t *drive)
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
150b73c7ee25da6133f97f47ffd3557288417da7c76Bartlomiej Zolnierkiewicz	ide_hwif_t *hwif = drive->hwif;
15122aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	struct ide_cmd *cmd = &hwif->cmd;
15222aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	struct ide_taskfile *tf = &cmd->tf;
15322aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	int custom = (cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0;
154d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz	int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 stat;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
15790d2c6bc68745d67cdbf00bab43818d90aa0dfb6Bartlomiej Zolnierkiewicz	local_irq_enable_in_hardirq();
15890d2c6bc68745d67cdbf00bab43818d90aa0dfb6Bartlomiej Zolnierkiewicz
159374e042c3e767ac2e5a40b78529220e0b3de793cBartlomiej Zolnierkiewicz	while (1) {
160374e042c3e767ac2e5a40b78529220e0b3de793cBartlomiej Zolnierkiewicz		stat = hwif->tp_ops->read_status(hwif);
1613a7d24841ad794ae64c90d7d00d62a83741912aaBartlomiej Zolnierkiewicz		if ((stat & ATA_BUSY) == 0 || retries-- == 0)
162374e042c3e767ac2e5a40b78529220e0b3de793cBartlomiej Zolnierkiewicz			break;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(10);
164374e042c3e767ac2e5a40b78529220e0b3de793cBartlomiej Zolnierkiewicz	};
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
166d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz	if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
167d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz		if (custom && tf->command == ATA_CMD_SET_MULTI) {
168d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz			drive->mult_req = drive->mult_count = 0;
169ca1b96e00ab5d1b0838965834469a0284c81a517Bartlomiej Zolnierkiewicz			drive->special_flags |= IDE_SFLAG_RECALIBRATE;
170d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz			(void)ide_dump_status(drive, __func__, stat);
171d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz			return ide_stopped;
172d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz		} else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) {
173d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz			if ((stat & (ATA_ERR | ATA_DRQ)) == 0) {
174d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz				ide_set_handler(drive, &task_no_data_intr,
17560c0cd02b254805691cdc61101ada6af7bd56fdeBartlomiej Zolnierkiewicz						WAIT_WORSTCASE);
176d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz				return ide_started;
177d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz			}
178d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz		}
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ide_error(drive, "task_no_data_intr", stat);
180d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz	}
181c47137a99c597330b69057158b26061a360c0e09Bartlomiej Zolnierkiewicz
182e7fedc3ca0b8fcd3350a40c42a7100a9539e6c4aBartlomiej Zolnierkiewicz	if (custom && tf->command == ATA_CMD_SET_MULTI)
183d6ff9f64e68d23feab44efa07cc6aee01f3ef32bBartlomiej Zolnierkiewicz		drive->mult_count = drive->mult_req;
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
185d364c7f50b3bb6dc77259974038567b821e2cf0aBartlomiej Zolnierkiewicz	if (custom == 0 || tf->command == ATA_CMD_IDLEIMMEDIATE ||
186d364c7f50b3bb6dc77259974038567b821e2cf0aBartlomiej Zolnierkiewicz	    tf->command == ATA_CMD_CHK_POWER) {
187a09485df9cda49fbde2766c86eb18a9cae585162Bartlomiej Zolnierkiewicz		struct request *rq = hwif->rq;
188a09485df9cda49fbde2766c86eb18a9cae585162Bartlomiej Zolnierkiewicz
189a09485df9cda49fbde2766c86eb18a9cae585162Bartlomiej Zolnierkiewicz		if (blk_pm_request(rq))
190a09485df9cda49fbde2766c86eb18a9cae585162Bartlomiej Zolnierkiewicz			ide_complete_pm_rq(drive, rq);
1912230d90dd889e35da2728b6f6ebf25fb5a6499bdBartlomiej Zolnierkiewicz		else
1922230d90dd889e35da2728b6f6ebf25fb5a6499bdBartlomiej Zolnierkiewicz			ide_finish_cmd(drive, cmd, stat);
193a09485df9cda49fbde2766c86eb18a9cae585162Bartlomiej Zolnierkiewicz	}
194a09485df9cda49fbde2766c86eb18a9cae585162Bartlomiej Zolnierkiewicz
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ide_stopped;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
198da6f4c7f6fe02f92aff72071ed541f59e5880398Adrian Bunkstatic u8 wait_drive_not_busy(ide_drive_t *drive)
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
200b73c7ee25da6133f97f47ffd3557288417da7c76Bartlomiej Zolnierkiewicz	ide_hwif_t *hwif = drive->hwif;
201b42fa133110fa952299fa76cbe91226c14838261Masatake YAMATO	int retries;
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 stat;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
20525985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	 * Last sector was transferred, wait until device is ready.  This can
206f54feafa6d47d0aa1a96adefdc763b708b02f94fBartlomiej Zolnierkiewicz	 * take up to 6 ms on some ATAPI devices, so we will wait max 10 ms.
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
208f54feafa6d47d0aa1a96adefdc763b708b02f94fBartlomiej Zolnierkiewicz	for (retries = 0; retries < 1000; retries++) {
209374e042c3e767ac2e5a40b78529220e0b3de793cBartlomiej Zolnierkiewicz		stat = hwif->tp_ops->read_status(hwif);
210c47137a99c597330b69057158b26061a360c0e09Bartlomiej Zolnierkiewicz
2113a7d24841ad794ae64c90d7d00d62a83741912aaBartlomiej Zolnierkiewicz		if (stat & ATA_BUSY)
212b42fa133110fa952299fa76cbe91226c14838261Masatake YAMATO			udelay(10);
213b42fa133110fa952299fa76cbe91226c14838261Masatake YAMATO		else
214b42fa133110fa952299fa76cbe91226c14838261Masatake YAMATO			break;
215b42fa133110fa952299fa76cbe91226c14838261Masatake YAMATO	}
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2173a7d24841ad794ae64c90d7d00d62a83741912aaBartlomiej Zolnierkiewicz	if (stat & ATA_BUSY)
2182d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		pr_err("%s: drive still BUSY!\n", drive->name);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return stat;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
223a08915ba594da66145f33a972db578a58b9135f1Bartlomiej Zolnierkiewiczvoid ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd,
224a08915ba594da66145f33a972db578a58b9135f1Bartlomiej Zolnierkiewicz		   unsigned int write, unsigned int len)
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ide_hwif_t *hwif = drive->hwif;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct scatterlist *sg = hwif->sg_table;
228b6308ee0c55acd2e943d849773c9f0a49c516317Bartlomiej Zolnierkiewicz	struct scatterlist *cursg = cmd->cursg;
2297fa350b4754cd69c8352ef3f5d23082fbdcab0bdDavid S. Miller	unsigned long uninitialized_var(flags);
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct page *page;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int offset;
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 *buf;
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
234b6308ee0c55acd2e943d849773c9f0a49c516317Bartlomiej Zolnierkiewicz	cursg = cmd->cursg;
2357a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz	if (cursg == NULL)
2367a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		cursg = cmd->cursg = sg;
2377a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz
2387a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz	while (len) {
2397a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs);
240a907905219dc83f501274d5d8c6d2aa2161ff8c3Jean Delvare		int page_is_high;
24155c16a70041ba55e235c5944dccb9c1de0dd3ca6Jens Axboe
2427a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		if (nr_bytes > PAGE_SIZE)
2437a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz			nr_bytes = PAGE_SIZE;
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2457a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		page = sg_page(cursg);
2467a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		offset = cursg->offset + cmd->cursg_ofs;
2477a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz
2487a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		/* get the current page and offset */
2497a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		page = nth_page(page, (offset >> PAGE_SHIFT));
2507a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		offset %= PAGE_SIZE;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
252a907905219dc83f501274d5d8c6d2aa2161ff8c3Jean Delvare		page_is_high = PageHighMem(page);
253a907905219dc83f501274d5d8c6d2aa2161ff8c3Jean Delvare		if (page_is_high)
254f2bc316736e69e5623443a010f9581a01429c075Bartlomiej Zolnierkiewicz			local_irq_save(flags);
255f2bc316736e69e5623443a010f9581a01429c075Bartlomiej Zolnierkiewicz
2567a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2587a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		cmd->nleft -= nr_bytes;
2597a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		cmd->cursg_ofs += nr_bytes;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2617a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		if (cmd->cursg_ofs == cursg->length) {
2627a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz			cursg = cmd->cursg = sg_next(cmd->cursg);
2637a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz			cmd->cursg_ofs = 0;
2647a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		}
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2667a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		/* do the actual data transfer */
2677a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		if (write)
2687a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz			hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes);
2697a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		else
2707a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz			hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2727a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		kunmap_atomic(buf, KM_BIO_SRC_IRQ);
273f2bc316736e69e5623443a010f9581a01429c075Bartlomiej Zolnierkiewicz
274a907905219dc83f501274d5d8c6d2aa2161ff8c3Jean Delvare		if (page_is_high)
275f2bc316736e69e5623443a010f9581a01429c075Bartlomiej Zolnierkiewicz			local_irq_restore(flags);
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2777a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		len -= nr_bytes;
2787a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz	}
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
280a08915ba594da66145f33a972db578a58b9135f1Bartlomiej ZolnierkiewiczEXPORT_SYMBOL_GPL(ide_pio_bytes);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
282adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewiczstatic void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd,
283adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewicz			      unsigned int write)
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2857a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz	unsigned int nr_bytes;
2867a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz
28735cf2b94d0ecb7034cfa05dd725721538bbb83fcTejun Heo	u8 saved_io_32bit = drive->io_32bit;
28835cf2b94d0ecb7034cfa05dd725721538bbb83fcTejun Heo
289adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewicz	if (cmd->tf_flags & IDE_TFLAG_FS)
290adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewicz		cmd->rq->errors = 0;
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29222aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	if (cmd->tf_flags & IDE_TFLAG_IO_16BIT)
293e3d9a73a83d98fc466dabdcfe4f4e7e4419e3f8eBartlomiej Zolnierkiewicz		drive->io_32bit = 0;
29435cf2b94d0ecb7034cfa05dd725721538bbb83fcTejun Heo
295651c29a17f7ea0204dacbc2a5042d57b1c9e2e37Andrew Morton	touch_softlockup_watchdog();
296651c29a17f7ea0204dacbc2a5042d57b1c9e2e37Andrew Morton
2970dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz	if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO)
2987a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		nr_bytes = min_t(unsigned, cmd->nleft, drive->mult_count << 9);
2990dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz	else
3007a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz		nr_bytes = SECTOR_SIZE;
3017a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz
3027a00798b1a7502ff31736152b23189138db0b978Bartlomiej Zolnierkiewicz	ide_pio_bytes(drive, cmd, write, nr_bytes);
30335cf2b94d0ecb7034cfa05dd725721538bbb83fcTejun Heo
30435cf2b94d0ecb7034cfa05dd725721538bbb83fcTejun Heo	drive->io_32bit = saved_io_32bit;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
307041cea10a86a25b088185d07ad15d728f503f02cBartlomiej Zolnierkiewiczstatic void ide_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd)
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
309adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewicz	if (cmd->tf_flags & IDE_TFLAG_FS) {
310bf717c0a2e18dbe82eeb28e57b0abede3cdf45d6Bartlomiej Zolnierkiewicz		int nr_bytes = cmd->nbytes - cmd->nleft;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3120dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz		if (cmd->protocol == ATA_PROT_PIO &&
3130dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz		    ((cmd->tf_flags & IDE_TFLAG_WRITE) || cmd->nleft == 0)) {
3140dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz			if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO)
315bf717c0a2e18dbe82eeb28e57b0abede3cdf45d6Bartlomiej Zolnierkiewicz				nr_bytes -= drive->mult_count << 9;
3160dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz			else
317bf717c0a2e18dbe82eeb28e57b0abede3cdf45d6Bartlomiej Zolnierkiewicz				nr_bytes -= SECTOR_SIZE;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
320bf717c0a2e18dbe82eeb28e57b0abede3cdf45d6Bartlomiej Zolnierkiewicz		if (nr_bytes > 0)
321bf717c0a2e18dbe82eeb28e57b0abede3cdf45d6Bartlomiej Zolnierkiewicz			ide_complete_rq(drive, 0, nr_bytes);
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
325adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewiczvoid ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat)
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3276902a5331256e1b9f4cef95a1e3622252113b260Bartlomiej Zolnierkiewicz	struct request *rq = drive->hwif->rq;
328665d66e8fad60a5a162c4615f27f916ad1a6d567Bartlomiej Zolnierkiewicz	u8 err = ide_read_error(drive), nsect = cmd->tf.nsect;
329665d66e8fad60a5a162c4615f27f916ad1a6d567Bartlomiej Zolnierkiewicz	u8 set_xfer = !!(cmd->tf_flags & IDE_TFLAG_SET_XFER);
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3312230d90dd889e35da2728b6f6ebf25fb5a6499bdBartlomiej Zolnierkiewicz	ide_complete_cmd(drive, cmd, stat, err);
3326902a5331256e1b9f4cef95a1e3622252113b260Bartlomiej Zolnierkiewicz	rq->errors = err;
333665d66e8fad60a5a162c4615f27f916ad1a6d567Bartlomiej Zolnierkiewicz
334665d66e8fad60a5a162c4615f27f916ad1a6d567Bartlomiej Zolnierkiewicz	if (err == 0 && set_xfer) {
335665d66e8fad60a5a162c4615f27f916ad1a6d567Bartlomiej Zolnierkiewicz		ide_set_xfer_rate(drive, nsect);
336665d66e8fad60a5a162c4615f27f916ad1a6d567Bartlomiej Zolnierkiewicz		ide_driveid_update(drive);
337665d66e8fad60a5a162c4615f27f916ad1a6d567Bartlomiej Zolnierkiewicz	}
338665d66e8fad60a5a162c4615f27f916ad1a6d567Bartlomiej Zolnierkiewicz
339f974b196f58fe042c7b2b4c0ee15d5a6112dbf40Bartlomiej Zolnierkiewicz	ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq));
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
343901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz * Handler for command with PIO data phase.
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
345901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewiczstatic ide_startstop_t task_pio_intr(ide_drive_t *drive)
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ide_hwif_t *hwif = drive->hwif;
348adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewicz	struct ide_cmd *cmd = &drive->hwif->cmd;
349374e042c3e767ac2e5a40b78529220e0b3de793cBartlomiej Zolnierkiewicz	u8 stat = hwif->tp_ops->read_status(hwif);
350901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz	u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
352901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz	if (write == 0) {
353901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz		/* Error? */
354901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz		if (stat & ATA_ERR)
3550a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewicz			goto out_err;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
357901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz		/* Didn't want any data? Odd. */
358151055ed84df7bebc77d88471302a7cd02c6e0a4Bartlomiej Zolnierkiewicz		if ((stat & ATA_DRQ) == 0) {
359151055ed84df7bebc77d88471302a7cd02c6e0a4Bartlomiej Zolnierkiewicz			/* Command all done? */
3600a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewicz			if (OK_STAT(stat, ATA_DRDY, ATA_BUSY))
3610a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewicz				goto out_end;
362151055ed84df7bebc77d88471302a7cd02c6e0a4Bartlomiej Zolnierkiewicz
363151055ed84df7bebc77d88471302a7cd02c6e0a4Bartlomiej Zolnierkiewicz			/* Assume it was a spurious irq */
3640a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewicz			goto out_wait;
365151055ed84df7bebc77d88471302a7cd02c6e0a4Bartlomiej Zolnierkiewicz		}
366901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz	} else {
367901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz		if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat))
3680a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewicz			goto out_err;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
370901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz		/* Deal with unexpected ATA data phase. */
371901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz		if (((stat & ATA_DRQ) == 0) ^ (cmd->nleft == 0))
3720a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewicz			goto out_err;
373901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz	}
374901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz
3750a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewicz	if (write && cmd->nleft == 0)
3760a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewicz		goto out_end;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Still data left to transfer. */
379901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz	ide_pio_datablock(drive, cmd, write);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz	/* Are we done? Check status and finish transfer. */
382901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz	if (write == 0 && cmd->nleft == 0) {
383901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz		stat = wait_drive_not_busy(drive);
384901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz		if (!OK_STAT(stat, 0, BAD_STAT))
3850a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewicz			goto out_err;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3870a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewicz		goto out_end;
3880a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewicz	}
3890a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewiczout_wait:
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Still data left to transfer. */
39160c0cd02b254805691cdc61101ada6af7bd56fdeBartlomiej Zolnierkiewicz	ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE);
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ide_started;
3930a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewiczout_end:
3942230d90dd889e35da2728b6f6ebf25fb5a6499bdBartlomiej Zolnierkiewicz	if ((cmd->tf_flags & IDE_TFLAG_FS) == 0)
3952230d90dd889e35da2728b6f6ebf25fb5a6499bdBartlomiej Zolnierkiewicz		ide_finish_cmd(drive, cmd, stat);
3962230d90dd889e35da2728b6f6ebf25fb5a6499bdBartlomiej Zolnierkiewicz	else
3979780e2dd8254351f6cbe11304849126b51dbd561Tejun Heo		ide_complete_rq(drive, 0, blk_rq_sectors(cmd->rq) << 9);
3980a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewicz	return ide_stopped;
3990a1248c5a754cc8dc5b10a902d2f86b40144165cBartlomiej Zolnierkiewiczout_err:
400041cea10a86a25b088185d07ad15d728f503f02cBartlomiej Zolnierkiewicz	ide_error_cmd(drive, cmd);
401041cea10a86a25b088185d07ad15d728f503f02cBartlomiej Zolnierkiewicz	return ide_error(drive, __func__, stat);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
404adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewiczstatic ide_startstop_t pre_task_out_intr(ide_drive_t *drive,
405adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewicz					 struct ide_cmd *cmd)
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ide_startstop_t startstop;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4093a7d24841ad794ae64c90d7d00d62a83741912aaBartlomiej Zolnierkiewicz	if (ide_wait_stat(&startstop, drive, ATA_DRQ,
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  drive->bad_wstat, WAIT_DRQ)) {
4112d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		pr_err("%s: no DRQ after issuing %sWRITE%s\n", drive->name,
4120dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz			(cmd->tf_flags & IDE_TFLAG_MULTI_PIO) ? "MULT" : "",
41397100fc816badbbc162644cfde7ad39ae9211fb4Bartlomiej Zolnierkiewicz			(drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : "");
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return startstop;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41797100fc816badbbc162644cfde7ad39ae9211fb4Bartlomiej Zolnierkiewicz	if ((drive->dev_flags & IDE_DFLAG_UNMASK) == 0)
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		local_irq_disable();
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42060c0cd02b254805691cdc61101ada6af7bd56fdeBartlomiej Zolnierkiewicz	ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE);
421901bd08a543eed7cbd4fd9e46df588f173417388Bartlomiej Zolnierkiewicz
422adb1af9803d167091c2cb4de14014185054bfe2cBartlomiej Zolnierkiewicz	ide_pio_datablock(drive, cmd, 1);
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ide_started;
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42722aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewiczint ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf,
42822aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz		     u16 nsect)
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
430154ed280e3f48995d0689b57f10b7063add63019FUJITA Tomonori	struct request *rq;
431154ed280e3f48995d0689b57f10b7063add63019FUJITA Tomonori	int error;
432720fc22a7af79d91ec460c80efa92c65c12d105eMikulas Patocka	int rw = !(cmd->tf_flags & IDE_TFLAG_WRITE) ? READ : WRITE;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
434720fc22a7af79d91ec460c80efa92c65c12d105eMikulas Patocka	rq = blk_get_request(drive->queue, rw, __GFP_WAIT);
435154ed280e3f48995d0689b57f10b7063add63019FUJITA Tomonori	rq->cmd_type = REQ_TYPE_ATA_TASKFILE;
436d868ca24302e99a0e8a86071ca2c66273edf97d9Tejun Heo
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * (ks) We transfer currently only whole sectors.
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * This is suffient for now.  But, it would be great,
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * if we would find a solution to transfer any size.
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * To support special commands like READ LONG.
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
443d868ca24302e99a0e8a86071ca2c66273edf97d9Tejun Heo	if (nsect) {
444d868ca24302e99a0e8a86071ca2c66273edf97d9Tejun Heo		error = blk_rq_map_kern(drive->queue, rq, buf,
445d868ca24302e99a0e8a86071ca2c66273edf97d9Tejun Heo					nsect * SECTOR_SIZE, __GFP_WAIT);
446d868ca24302e99a0e8a86071ca2c66273edf97d9Tejun Heo		if (error)
447d868ca24302e99a0e8a86071ca2c66273edf97d9Tejun Heo			goto put_req;
448d868ca24302e99a0e8a86071ca2c66273edf97d9Tejun Heo	}
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
45022aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	rq->special = cmd;
45122aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	cmd->rq = rq;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
453154ed280e3f48995d0689b57f10b7063add63019FUJITA Tomonori	error = blk_execute_rq(drive->queue, NULL, rq, 0);
454154ed280e3f48995d0689b57f10b7063add63019FUJITA Tomonori
455d868ca24302e99a0e8a86071ca2c66273edf97d9Tejun Heoput_req:
456d868ca24302e99a0e8a86071ca2c66273edf97d9Tejun Heo	blk_put_request(rq);
457154ed280e3f48995d0689b57f10b7063add63019FUJITA Tomonori	return error;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(ide_raw_taskfile);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46122aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewiczint ide_no_data_taskfile(ide_drive_t *drive, struct ide_cmd *cmd)
4629a3c49be5c5f7388eefb712be9a383904140532eBartlomiej Zolnierkiewicz{
4630dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz	cmd->protocol = ATA_PROT_NODATA;
4649a3c49be5c5f7388eefb712be9a383904140532eBartlomiej Zolnierkiewicz
46522aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	return ide_raw_taskfile(drive, cmd, NULL, 0);
4669a3c49be5c5f7388eefb712be9a383904140532eBartlomiej Zolnierkiewicz}
4679a3c49be5c5f7388eefb712be9a383904140532eBartlomiej ZolnierkiewiczEXPORT_SYMBOL_GPL(ide_no_data_taskfile);
4689a3c49be5c5f7388eefb712be9a383904140532eBartlomiej Zolnierkiewicz
46926a5b04075f6f2ccf30b22e7f0fc9127c500a698Bartlomiej Zolnierkiewicz#ifdef CONFIG_IDE_TASK_IOCTL
47022aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewiczint ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg)
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ide_task_request_t	*req_task;
47322aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	struct ide_cmd		cmd;
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 *outbuf		= NULL;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 *inbuf		= NULL;
476ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz	u8 *data_buf		= NULL;
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err			= 0;
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int tasksize		= sizeof(struct ide_task_request_s);
4793a42bb223f61fbd755d6e61b9b50b9681d68fcaeAlan Cox	unsigned int taskin	= 0;
4803a42bb223f61fbd755d6e61b9b50b9681d68fcaeAlan Cox	unsigned int taskout	= 0;
481ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz	u16 nsect		= 0;
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char __user *buf = (char __user *)arg;
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4847d543d8468348c44010c7b4e6fdd23a398779668Julia Lawall	req_task = memdup_user(buf, tasksize);
4857d543d8468348c44010c7b4e6fdd23a398779668Julia Lawall	if (IS_ERR(req_task))
4867d543d8468348c44010c7b4e6fdd23a398779668Julia Lawall		return PTR_ERR(req_task);
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4883a42bb223f61fbd755d6e61b9b50b9681d68fcaeAlan Cox	taskout = req_task->out_size;
4893a42bb223f61fbd755d6e61b9b50b9681d68fcaeAlan Cox	taskin  = req_task->in_size;
4902d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput
4913a42bb223f61fbd755d6e61b9b50b9681d68fcaeAlan Cox	if (taskin > 65536 || taskout > 65536) {
4923a42bb223f61fbd755d6e61b9b50b9681d68fcaeAlan Cox		err = -EINVAL;
4933a42bb223f61fbd755d6e61b9b50b9681d68fcaeAlan Cox		goto abort;
4943a42bb223f61fbd755d6e61b9b50b9681d68fcaeAlan Cox	}
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (taskout) {
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int outtotal = tasksize;
498f5e3c2faa20615e900ab26bd957f898400435924Deepak Saxena		outbuf = kzalloc(taskout, GFP_KERNEL);
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (outbuf == NULL) {
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -ENOMEM;
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto abort;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user(outbuf, buf + outtotal, taskout)) {
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EFAULT;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto abort;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (taskin) {
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int intotal = tasksize + taskout;
511f5e3c2faa20615e900ab26bd957f898400435924Deepak Saxena		inbuf = kzalloc(taskin, GFP_KERNEL);
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (inbuf == NULL) {
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -ENOMEM;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto abort;
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_from_user(inbuf, buf + intotal, taskin)) {
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EFAULT;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto abort;
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
52222aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	memset(&cmd, 0, sizeof(cmd));
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
524745483f10c6cefb303007c6873e2bfce54efa8edSergei Shtylyov	memcpy(&cmd.hob, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2);
525745483f10c6cefb303007c6873e2bfce54efa8edSergei Shtylyov	memcpy(&cmd.tf,  req_task->io_ports,  HDIO_DRIVE_TASK_HDR_SIZE);
526866e2ec9ce525de0e7c10d02ead8d85af27adffdBartlomiej Zolnierkiewicz
52760f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov	cmd.valid.out.tf = IDE_VALID_DEVICE;
52860f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov	cmd.valid.in.tf  = IDE_VALID_DEVICE | IDE_VALID_IN_TF;
52960f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov	cmd.tf_flags = IDE_TFLAG_IO_16BIT;
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
53160f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov	if (drive->dev_flags & IDE_DFLAG_LBA48) {
53260f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov		cmd.tf_flags |= IDE_TFLAG_LBA48;
53360f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov		cmd.valid.in.hob = IDE_VALID_IN_HOB;
53460f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov	}
535a3bbb9d882dc94fe3a1361596ab9ce55d84059eaBartlomiej Zolnierkiewicz
53674095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz	if (req_task->out_flags.all) {
53722aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz		cmd.ftf_flags |= IDE_FTFLAG_FLAGGED;
53874095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz
53974095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz		if (req_task->out_flags.b.data)
54022aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz			cmd.ftf_flags |= IDE_FTFLAG_OUT_DATA;
54174095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz
54274095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz		if (req_task->out_flags.b.nsector_hob)
54360f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov			cmd.valid.out.hob |= IDE_VALID_NSECT;
54474095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz		if (req_task->out_flags.b.sector_hob)
54560f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov			cmd.valid.out.hob |= IDE_VALID_LBAL;
54674095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz		if (req_task->out_flags.b.lcyl_hob)
54760f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov			cmd.valid.out.hob |= IDE_VALID_LBAM;
54874095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz		if (req_task->out_flags.b.hcyl_hob)
54960f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov			cmd.valid.out.hob |= IDE_VALID_LBAH;
55074095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz
55174095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz		if (req_task->out_flags.b.error_feature)
55260f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov			cmd.valid.out.tf  |= IDE_VALID_FEATURE;
55374095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz		if (req_task->out_flags.b.nsector)
55460f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov			cmd.valid.out.tf  |= IDE_VALID_NSECT;
55574095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz		if (req_task->out_flags.b.sector)
55660f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov			cmd.valid.out.tf  |= IDE_VALID_LBAL;
55774095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz		if (req_task->out_flags.b.lcyl)
55860f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov			cmd.valid.out.tf  |= IDE_VALID_LBAM;
55974095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz		if (req_task->out_flags.b.hcyl)
56060f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov			cmd.valid.out.tf  |= IDE_VALID_LBAH;
561a3bbb9d882dc94fe3a1361596ab9ce55d84059eaBartlomiej Zolnierkiewicz	} else {
56260f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov		cmd.valid.out.tf |= IDE_VALID_OUT_TF;
56322aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz		if (cmd.tf_flags & IDE_TFLAG_LBA48)
56460f85019c6c8c1aebf3485a313e0da094bc95d07Sergei Shtylyov			cmd.valid.out.hob |= IDE_VALID_OUT_HOB;
56574095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz	}
56674095a91ed02f6727b62d4416be00a041f2d7436Bartlomiej Zolnierkiewicz
567866e2ec9ce525de0e7c10d02ead8d85af27adffdBartlomiej Zolnierkiewicz	if (req_task->in_flags.b.data)
56822aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz		cmd.ftf_flags |= IDE_FTFLAG_IN_DATA;
569866e2ec9ce525de0e7c10d02ead8d85af27adffdBartlomiej Zolnierkiewicz
57004d09b0e62f2180a7e3fa8578ed778eca0c454fdBartlomiej Zolnierkiewicz	if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE) {
57104d09b0e62f2180a7e3fa8578ed778eca0c454fdBartlomiej Zolnierkiewicz		/* fixup data phase if needed */
57204d09b0e62f2180a7e3fa8578ed778eca0c454fdBartlomiej Zolnierkiewicz		if (req_task->data_phase == TASKFILE_IN_DMAQ ||
57304d09b0e62f2180a7e3fa8578ed778eca0c454fdBartlomiej Zolnierkiewicz		    req_task->data_phase == TASKFILE_IN_DMA)
5740dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz			cmd.tf_flags |= IDE_TFLAG_WRITE;
57504d09b0e62f2180a7e3fa8578ed778eca0c454fdBartlomiej Zolnierkiewicz	}
57604d09b0e62f2180a7e3fa8578ed778eca0c454fdBartlomiej Zolnierkiewicz
5770dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz	cmd.protocol = ATA_PROT_DMA;
5780dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz
5790dfb991c6943c810175376b58d1c29cfe532541bBartlomiej Zolnierkiewicz	switch (req_task->data_phase) {
5802d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput	case TASKFILE_MULTI_OUT:
5812d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		if (!drive->mult_count) {
5822d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput			/* (hs): give up if multcount is not set */
5832d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput			pr_err("%s: %s Multimode Write multcount is not set\n",
5842d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput				drive->name, __func__);
5852d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput			err = -EPERM;
5862d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput			goto abort;
5872d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		}
5882d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		cmd.tf_flags |= IDE_TFLAG_MULTI_PIO;
5892d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		/* fall through */
5902d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput	case TASKFILE_OUT:
5912d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		cmd.protocol = ATA_PROT_PIO;
5922d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		/* fall through */
5932d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput	case TASKFILE_OUT_DMAQ:
5942d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput	case TASKFILE_OUT_DMA:
5952d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		cmd.tf_flags |= IDE_TFLAG_WRITE;
5962d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		nsect = taskout / SECTOR_SIZE;
5972d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		data_buf = outbuf;
5982d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		break;
5992d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput	case TASKFILE_MULTI_IN:
6002d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		if (!drive->mult_count) {
6012d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput			/* (hs): give up if multcount is not set */
6022d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput			pr_err("%s: %s Multimode Read multcount is not set\n",
6032d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput				drive->name, __func__);
6042d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput			err = -EPERM;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto abort;
6062d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		}
6072d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		cmd.tf_flags |= IDE_TFLAG_MULTI_PIO;
6082d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		/* fall through */
6092d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput	case TASKFILE_IN:
6102d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		cmd.protocol = ATA_PROT_PIO;
6112d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		/* fall through */
6122d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput	case TASKFILE_IN_DMAQ:
6132d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput	case TASKFILE_IN_DMA:
6142d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		nsect = taskin / SECTOR_SIZE;
6152d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		data_buf = inbuf;
6162d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		break;
6172d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput	case TASKFILE_NO_DATA:
6182d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		cmd.protocol = ATA_PROT_NODATA;
6192d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		break;
6202d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput	default:
6212d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		err = -EFAULT;
6222d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput		goto abort;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
625ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz	if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA)
626ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz		nsect = 0;
627ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz	else if (!nsect) {
628745483f10c6cefb303007c6873e2bfce54efa8edSergei Shtylyov		nsect = (cmd.hob.nsect << 8) | cmd.tf.nsect;
629ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz
630ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz		if (!nsect) {
6312d5abcedeb41f4af9582c60cef70749c3ab90a3bJaswinder Singh Rajput			pr_err("%s: in/out command without data\n",
632ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz					drive->name);
633ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz			err = -EFAULT;
634ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz			goto abort;
635ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz		}
636ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz	}
637ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz
63822aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	err = ide_raw_taskfile(drive, &cmd, data_buf, nsect);
639ac026ff254b32915bb14ba97a23b4019d137f181Bartlomiej Zolnierkiewicz
640745483f10c6cefb303007c6873e2bfce54efa8edSergei Shtylyov	memcpy(req_task->hob_ports, &cmd.hob, HDIO_DRIVE_HOB_HDR_SIZE - 2);
641745483f10c6cefb303007c6873e2bfce54efa8edSergei Shtylyov	memcpy(req_task->io_ports,  &cmd.tf,  HDIO_DRIVE_TASK_HDR_SIZE);
642866e2ec9ce525de0e7c10d02ead8d85af27adffdBartlomiej Zolnierkiewicz
64322aa4b32a19b1f231d4ce7e9af6354b577a22a35Bartlomiej Zolnierkiewicz	if ((cmd.ftf_flags & IDE_FTFLAG_SET_IN_FLAGS) &&
644866e2ec9ce525de0e7c10d02ead8d85af27adffdBartlomiej Zolnierkiewicz	    req_task->in_flags.all == 0) {
645866e2ec9ce525de0e7c10d02ead8d85af27adffdBartlomiej Zolnierkiewicz		req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
64697100fc816badbbc162644cfde7ad39ae9211fb4Bartlomiej Zolnierkiewicz		if (drive->dev_flags & IDE_DFLAG_LBA48)
647866e2ec9ce525de0e7c10d02ead8d85af27adffdBartlomiej Zolnierkiewicz			req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8);
648866e2ec9ce525de0e7c10d02ead8d85af27adffdBartlomiej Zolnierkiewicz	}
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_to_user(buf, req_task, tasksize)) {
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -EFAULT;
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto abort;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (taskout) {
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int outtotal = tasksize;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(buf + outtotal, outbuf, taskout)) {
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EFAULT;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto abort;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (taskin) {
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int intotal = tasksize + taskout;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(buf + intotal, inbuf, taskin)) {
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = -EFAULT;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto abort;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsabort:
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(req_task);
6706044ec8882c726e325017bd948aa0cd94ad33abcJesper Juhl	kfree(outbuf);
6716044ec8882c726e325017bd948aa0cd94ad33abcJesper Juhl	kfree(inbuf);
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
67526a5b04075f6f2ccf30b22e7f0fc9127c500a698Bartlomiej Zolnierkiewicz#endif
676