fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / ide / ide-taskfile.c
index d04f62a..30175c7 100644 (file)
  *     request.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/major.h>
 #include <linux/errno.h>
@@ -51,8 +51,6 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-#define DEBUG_TASKFILE 0       /* unset when fixed */
-
 static void ata_bswap_data (void *buffer, int wcount)
 {
        u16 *p = buffer;
@@ -161,8 +159,6 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task)
        return ide_stopped;
 }
 
-EXPORT_SYMBOL(do_rw_taskfile);
-
 /*
  * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd.
  */
@@ -199,8 +195,7 @@ ide_startstop_t set_geometry_intr (ide_drive_t *drive)
        if (stat & (ERR_STAT|DRQ_STAT))
                return ide_error(drive, "set_geometry_intr", stat);
 
-       if (HWGROUP(drive)->handler != NULL)
-               BUG();
+       BUG_ON(HWGROUP(drive)->handler != NULL);
        ide_set_handler(drive, &set_geometry_intr, WAIT_WORSTCASE, NULL);
        return ide_started;
 }
@@ -227,7 +222,7 @@ ide_startstop_t task_no_data_intr (ide_drive_t *drive)
        ide_hwif_t *hwif        = HWIF(drive);
        u8 stat;
 
-       local_irq_enable();
+       local_irq_enable_in_hardirq();
        if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
                return ide_error(drive, "task_no_data_intr", stat);
                /* calls ide_end_drive_cmd */
@@ -312,12 +307,14 @@ static void ide_pio_multi(ide_drive_t *drive, unsigned int write)
                ide_pio_sector(drive, write);
 }
 
-static inline void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
+static void ide_pio_datablock(ide_drive_t *drive, struct request *rq,
                                     unsigned int write)
 {
        if (rq->bio)    /* fs request */
                rq->errors = 0;
 
+       touch_softlockup_watchdog();
+
        switch (drive->hwif->data_phase) {
        case TASKFILE_MULTI_IN:
        case TASKFILE_MULTI_OUT:
@@ -366,7 +363,7 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
 
 static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
 {
-       if (rq->flags & REQ_DRIVE_TASKFILE) {
+       if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
                ide_task_t *task = rq->special;
 
                if (task->tf_out_flags.all) {
@@ -376,7 +373,13 @@ static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
                }
        }
 
-       ide_end_request(drive, 1, rq->hard_nr_sectors);
+       if (rq->rq_disk) {
+               ide_driver_t *drv;
+
+               drv = *(ide_driver_t **)rq->rq_disk->private_data;;
+               drv->end_request(drive, 1, rq->hard_nr_sectors);
+       } else
+               ide_end_request(drive, 1, rq->hard_nr_sectors);
 }
 
 /*
@@ -471,7 +474,7 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long
        struct request rq;
 
        memset(&rq, 0, sizeof(rq));
-       rq.flags = REQ_DRIVE_TASKFILE;
+       rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
        rq.buffer = buf;
 
        /*
@@ -496,10 +499,11 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long
                rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors;
 
                if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
-                       rq.flags |= REQ_RW;
+                       rq.cmd_flags |= REQ_RW;
        }
 
        rq.special = args;
+       args->rq = &rq;
        return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
 
@@ -520,32 +524,35 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
        task_ioreg_t *hobsptr   = args.hobRegister;
        int err                 = 0;
        int tasksize            = sizeof(struct ide_task_request_s);
-       int taskin              = 0;
-       int taskout             = 0;
+       unsigned int taskin     = 0;
+       unsigned int taskout    = 0;
        u8 io_32bit             = drive->io_32bit;
        char __user *buf = (char __user *)arg;
 
 //     printk("IDE Taskfile ...\n");
 
-       req_task = kmalloc(tasksize, GFP_KERNEL);
+       req_task = kzalloc(tasksize, GFP_KERNEL);
        if (req_task == NULL) return -ENOMEM;
-       memset(req_task, 0, tasksize);
        if (copy_from_user(req_task, buf, tasksize)) {
                kfree(req_task);
                return -EFAULT;
        }
 
-       taskout = (int) req_task->out_size;
-       taskin  = (int) req_task->in_size;
+       taskout = req_task->out_size;
+       taskin  = req_task->in_size;
+       
+       if (taskin > 65536 || taskout > 65536) {
+               err = -EINVAL;
+               goto abort;
+       }
 
        if (taskout) {
                int outtotal = tasksize;
-               outbuf = kmalloc(taskout, GFP_KERNEL);
+               outbuf = kzalloc(taskout, GFP_KERNEL);
                if (outbuf == NULL) {
                        err = -ENOMEM;
                        goto abort;
                }
-               memset(outbuf, 0, taskout);
                if (copy_from_user(outbuf, buf + outtotal, taskout)) {
                        err = -EFAULT;
                        goto abort;
@@ -554,12 +561,11 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 
        if (taskin) {
                int intotal = tasksize + taskout;
-               inbuf = kmalloc(taskin, GFP_KERNEL);
+               inbuf = kzalloc(taskin, GFP_KERNEL);
                if (inbuf == NULL) {
                        err = -ENOMEM;
                        goto abort;
                }
-               memset(inbuf, 0, taskin);
                if (copy_from_user(inbuf, buf + intotal, taskin)) {
                        err = -EFAULT;
                        goto abort;
@@ -648,10 +654,8 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
        }
 abort:
        kfree(req_task);
-       if (outbuf != NULL)
-               kfree(outbuf);
-       if (inbuf != NULL)
-               kfree(inbuf);
+       kfree(outbuf);
+       kfree(inbuf);
 
 //     printk("IDE Taskfile ioctl ended. rc = %i\n", err);
 
@@ -708,10 +712,9 @@ int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
 
        if (args[3]) {
                argsize = 4 + (SECTOR_WORDS * 4 * args[3]);
-               argbuf = kmalloc(argsize, GFP_KERNEL);
+               argbuf = kzalloc(argsize, GFP_KERNEL);
                if (argbuf == NULL)
                        return -ENOMEM;
-               memcpy(argbuf, args, 4);
        }
        if (set_transfer(drive, &tfargs)) {
                xfer_rate = args[1];
@@ -739,7 +742,7 @@ static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf)
        struct request rq;
 
        ide_init_drive_cmd(&rq);
-       rq.flags = REQ_DRIVE_TASK;
+       rq.cmd_type = REQ_TYPE_ATA_TASK;
        rq.buffer = buf;
        return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
@@ -772,9 +775,6 @@ ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
        ide_hwif_t *hwif        = HWIF(drive);
        task_struct_t *taskfile = (task_struct_t *) task->tfRegister;
        hob_struct_t *hobfile   = (hob_struct_t *) task->hobRegister;
-#if DEBUG_TASKFILE
-       u8 status;
-#endif
 
        if (task->data_phase == TASKFILE_MULTI_IN ||
            task->data_phase == TASKFILE_MULTI_OUT) {
@@ -785,19 +785,13 @@ ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
        }
 
        /*
-        * (ks) Check taskfile in/out flags.
+        * (ks) Check taskfile in flags.
         * If set, then execute as it is defined.
         * If not set, then define default settings.
         * The default values are:
-        *      write and read all taskfile registers (except data) 
-        *      write and read the hob registers (sector,nsector,lcyl,hcyl)
+        *      read all taskfile registers (except data)
+        *      read the hob registers (sector, nsector, lcyl, hcyl)
         */
-       if (task->tf_out_flags.all == 0) {
-               task->tf_out_flags.all = IDE_TASKFILE_STD_OUT_FLAGS;
-               if (drive->addressing == 1)
-                       task->tf_out_flags.all |= (IDE_HOB_STD_OUT_FLAGS << 8);
-        }
-
        if (task->tf_in_flags.all == 0) {
                task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;
                if (drive->addressing == 1)
@@ -810,16 +804,6 @@ ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task)
                hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
        SELECT_MASK(drive, 0);
 
-#if DEBUG_TASKFILE
-       status = hwif->INB(IDE_STATUS_REG);
-       if (status & 0x80) {
-               printk("flagged_taskfile -> Bad status. Status = %02x. wait 100 usec ...\n", status);
-               udelay(100);
-               status = hwif->INB(IDE_STATUS_REG);
-               printk("flagged_taskfile -> Status = %02x\n", status);
-       }
-#endif
-
        if (task->tf_out_flags.b.data) {
                u16 data =  taskfile->data + (hobfile->data << 8);
                hwif->OUTW(data, IDE_DATA_REG);