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