]> err.no Git - linux-2.6/blobdiff - drivers/ide/ide-taskfile.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/pci-2.6
[linux-2.6] / drivers / ide / ide-taskfile.c
index 3bbb438f4f9288dce3847930f26c67d02423793c..4e1da1c78cb51299ce359729a78b460e2c1d8c36 100644 (file)
@@ -1,11 +1,9 @@
 /*
- * linux/drivers/ide/ide-taskfile.c    Version 0.38    March 05, 2003
- *
- *  Copyright (C) 2000-2002    Michael Cornwell <cornwell@acm.org>
- *  Copyright (C) 2000-2002    Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2001-2002    Klaus Smolin
+ *  Copyright (C) 2000-2002       Michael Cornwell <cornwell@acm.org>
+ *  Copyright (C) 2000-2002       Andre Hedrick <andre@linux-ide.org>
+ *  Copyright (C) 2001-2002       Klaus Smolin
  *                                     IBM Storage Technology Division
- *  Copyright (C) 2003-2004    Bartlomiej Zolnierkiewicz
+ *  Copyright (C) 2003-2004, 2007  Bartlomiej Zolnierkiewicz
  *
  *  The big the bad and the ugly.
  */
@@ -268,8 +266,7 @@ static u8 wait_drive_not_busy(ide_drive_t *drive)
 
        /*
         * Last sector was transfered, wait until drive is ready.
-        * This can take up to 10 usec, but we will wait max 1 ms
-        * (drive_cmd_intr() waits that long).
+        * This can take up to 10 usec, but we will wait max 1 ms.
         */
        for (retries = 0; retries < 100; retries++) {
                if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT)
@@ -408,16 +405,13 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
        return ide_error(drive, s, stat);
 }
 
-static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
+void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
 {
        if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
-               ide_task_t *task = rq->special;
+               u8 err = drive->hwif->INB(IDE_ERROR_REG);
 
-               if (task->tf_flags & IDE_TFLAG_FLAGGED) {
-                       u8 err = drive->hwif->INB(IDE_ERROR_REG);
-                       ide_end_drive_cmd(drive, stat, err);
-                       return;
-               }
+               ide_end_drive_cmd(drive, stat, err);
+               return;
        }
 
        if (rq->rq_disk) {
@@ -439,7 +433,7 @@ static ide_startstop_t task_in_intr(ide_drive_t *drive)
        u8 stat = hwif->INB(IDE_STATUS_REG);
 
        /* new way for dealing with premature shared PCI interrupts */
-       if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) {
+       if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) {
                if (stat & (ERR_STAT | DRQ_STAT))
                        return task_error(drive, rq, __FUNCTION__, stat);
                /* No data yet, so wait for another IRQ. */
@@ -496,7 +490,7 @@ static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct request *rq)
 {
        ide_startstop_t startstop;
 
-       if (ide_wait_stat(&startstop, drive, DATA_READY,
+       if (ide_wait_stat(&startstop, drive, DRQ_STAT,
                          drive->bad_wstat, WAIT_DRQ)) {
                printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",
                                drive->name,
@@ -754,35 +748,21 @@ abort:
 }
 #endif
 
-int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf)
-{
-       struct request rq;
-       u8 buffer[4];
-
-       if (!buf)
-               buf = buffer;
-       memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);
-       ide_init_drive_cmd(&rq);
-       rq.buffer = buf;
-       *buf++ = cmd;
-       *buf++ = nsect;
-       *buf++ = feature;
-       *buf++ = sectors;
-       return ide_do_drive_cmd(drive, &rq, ide_wait);
-}
-
 int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 {
-       int err = 0;
-       u8 args[4], *argbuf = args;
-       u8 xfer_rate = 0;
-       int argsize = 4;
+       u8 *buf = NULL;
+       int bufsize = 0, err = 0;
+       u8 args[4], xfer_rate = 0;
        ide_task_t tfargs;
        struct ide_taskfile *tf = &tfargs.tf;
+       struct hd_driveid *id = drive->id;
 
        if (NULL == (void *) arg) {
                struct request rq;
+
                ide_init_drive_cmd(&rq);
+               rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
+
                return ide_do_drive_cmd(drive, &rq, ide_wait);
        }
 
@@ -791,23 +771,45 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 
        memset(&tfargs, 0, sizeof(ide_task_t));
        tf->feature = args[2];
-       tf->nsect   = args[3];
-       tf->lbal    = args[1];
+       if (args[0] == WIN_SMART) {
+               tf->nsect = args[3];
+               tf->lbal  = args[1];
+               tf->lbam  = 0x4f;
+               tf->lbah  = 0xc2;
+               tfargs.tf_flags = IDE_TFLAG_OUT_TF | IDE_TFLAG_IN_NSECT;
+       } else {
+               tf->nsect = args[1];
+               tfargs.tf_flags = IDE_TFLAG_OUT_FEATURE |
+                                 IDE_TFLAG_OUT_NSECT | IDE_TFLAG_IN_NSECT;
+       }
        tf->command = args[0];
+       tfargs.data_phase = args[3] ? TASKFILE_IN : TASKFILE_NO_DATA;
 
        if (args[3]) {
-               argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
-               argbuf = kzalloc(argsize, GFP_KERNEL);
-               if (argbuf == NULL)
+               tfargs.tf_flags |= IDE_TFLAG_IO_16BIT;
+               bufsize = SECTOR_WORDS * 4 * args[3];
+               buf = kzalloc(bufsize, GFP_KERNEL);
+               if (buf == NULL)
                        return -ENOMEM;
        }
-       if (set_transfer(drive, &tfargs)) {
+
+       if (tf->command == WIN_SETFEATURES &&
+           tf->feature == SETFEATURES_XFER &&
+           tf->nsect >= XFER_SW_DMA_0 &&
+           (id->dma_ultra || id->dma_mword || id->dma_1word)) {
                xfer_rate = args[1];
-               if (ide_ata66_check(drive, &tfargs))
+               if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) {
+                       printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot "
+                                           "be set\n", drive->name);
                        goto abort;
+               }
        }
 
-       err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);
+       err = ide_raw_taskfile(drive, &tfargs, buf, args[3]);
+
+       args[0] = tf->status;
+       args[1] = tf->error;
+       args[2] = tf->nsect;
 
        if (!err && xfer_rate) {
                /* active-retuning-calls future */
@@ -815,10 +817,13 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
                ide_driveid_update(drive);
        }
 abort:
-       if (copy_to_user((void __user *)arg, argbuf, argsize))
+       if (copy_to_user((void __user *)arg, &args, 4))
                err = -EFAULT;
-       if (argsize > 4)
-               kfree(argbuf);
+       if (buf) {
+               if (copy_to_user((void __user *)(arg + 4), buf, bufsize))
+                       err = -EFAULT;
+               kfree(buf);
+       }
        return err;
 }