Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[safe/jmp/linux-2.6] / drivers / ide / ide-io.c
index b4901b6..6415a2e 100644 (file)
@@ -73,6 +73,7 @@ EXPORT_SYMBOL_GPL(ide_end_rq);
 
 void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)
 {
+       const struct ide_tp_ops *tp_ops = drive->hwif->tp_ops;
        struct ide_taskfile *tf = &cmd->tf;
        struct request *rq = cmd->rq;
        u8 tf_cmd = tf->command;
@@ -80,23 +81,35 @@ void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)
        tf->error = err;
        tf->status = stat;
 
-       drive->hwif->tp_ops->tf_read(drive, cmd);
+       if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
+               u8 data[2];
+
+               tp_ops->input_data(drive, cmd, data, 2);
+
+               cmd->tf.data  = data[0];
+               cmd->hob.data = data[1];
+       }
+
+       ide_tf_readback(drive, cmd);
 
        if ((cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) &&
            tf_cmd == ATA_CMD_IDLEIMMEDIATE) {
                if (tf->lbal != 0xc4) {
                        printk(KERN_ERR "%s: head unload failed!\n",
                               drive->name);
-                       ide_tf_dump(drive->name, tf);
+                       ide_tf_dump(drive->name, cmd);
                } else
                        drive->dev_flags |= IDE_DFLAG_PARKED;
        }
 
-       if (rq && rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
-               memcpy(rq->special, cmd, sizeof(*cmd));
+       if (rq && rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
+               struct ide_cmd *orig_cmd = rq->special;
 
-       if (cmd->tf_flags & IDE_TFLAG_DYN)
-               kfree(cmd);
+               if (cmd->tf_flags & IDE_TFLAG_DYN)
+                       kfree(orig_cmd);
+               else
+                       memcpy(orig_cmd, cmd, sizeof(*cmd));
+       }
 }
 
 /* obsolete, blk_rq_bytes() should be used instead */
@@ -195,8 +208,9 @@ static ide_startstop_t ide_disk_special(ide_drive_t *drive)
                return ide_stopped;
        }
 
-       cmd.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE |
-                      IDE_TFLAG_CUSTOM_HANDLER;
+       cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE;
+       cmd.valid.in.tf  = IDE_VALID_IN_TF  | IDE_VALID_DEVICE;
+       cmd.tf_flags = IDE_TFLAG_CUSTOM_HANDLER;
 
        do_rw_taskfile(drive, &cmd);
 
@@ -245,9 +259,9 @@ void ide_map_sg(ide_drive_t *drive, struct ide_cmd *cmd)
 }
 EXPORT_SYMBOL_GPL(ide_map_sg);
 
-void ide_init_sg_cmd(struct ide_cmd *cmd, int nsect)
+void ide_init_sg_cmd(struct ide_cmd *cmd, unsigned int nr_bytes)
 {
-       cmd->nsect = cmd->nleft = nsect;
+       cmd->nbytes = cmd->nleft = nr_bytes;
        cmd->cursg_ofs = 0;
        cmd->cursg = NULL;
 }
@@ -272,7 +286,7 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
 
        if (cmd) {
                if (cmd->protocol == ATA_PROT_PIO) {
-                       ide_init_sg_cmd(cmd, rq->nr_sectors);
+                       ide_init_sg_cmd(cmd, rq->nr_sectors << 9);
                        ide_map_sg(drive, cmd);
                }
 
@@ -338,7 +352,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
        if (blk_pm_request(rq))
                ide_check_pm_state(drive, rq);
 
-       SELECT_DRIVE(drive);
+       drive->hwif->tp_ops->dev_select(drive);
        if (ide_wait_stat(&startstop, drive, drive->ready_stat,
                          ATA_BUSY | ATA_DRQ, WAIT_READY)) {
                printk(KERN_ERR "%s: drive not ready for command\n", drive->name);
@@ -481,11 +495,10 @@ repeat:
                prev_port = hwif->host->cur_port;
                hwif->rq = NULL;
 
-               if (drive->dev_flags & IDE_DFLAG_SLEEPING) {
-                       if (time_before(drive->sleep, jiffies)) {
-                               ide_unlock_port(hwif);
-                               goto plug_device;
-                       }
+               if (drive->dev_flags & IDE_DFLAG_SLEEPING &&
+                   time_after(drive->sleep, jiffies)) {
+                       ide_unlock_port(hwif);
+                       goto plug_device;
                }
 
                if ((hwif->host->host_flags & IDE_HFLAG_SERIALIZE) &&
@@ -495,7 +508,9 @@ repeat:
                         * quirk_list may not like intr setups/cleanups
                         */
                        if (prev_port && prev_port->cur_dev->quirk_list == 0)
-                               prev_port->tp_ops->set_irq(prev_port, 0);
+                               prev_port->tp_ops->write_devctl(prev_port,
+                                                               ATA_NIEN |
+                                                               ATA_DEVCTL_OBS);
 
                        hwif->host->cur_port = hwif;
                }
@@ -681,7 +696,7 @@ void ide_timer_expiry (unsigned long data)
                }
                spin_lock_irq(&hwif->lock);
                enable_irq(hwif->irq);
-               if (startstop == ide_stopped) {
+               if (startstop == ide_stopped && hwif->polling == 0) {
                        ide_unlock_port(hwif);
                        plug_device = 1;
                }
@@ -853,7 +868,7 @@ irqreturn_t ide_intr (int irq, void *dev_id)
         * same irq as is currently being serviced here, and Linux
         * won't allow another of the same (on any CPU) until we return.
         */
-       if (startstop == ide_stopped) {
+       if (startstop == ide_stopped && hwif->polling == 0) {
                BUG_ON(hwif->handler);
                ide_unlock_port(hwif);
                plug_device = 1;