Merge git://git.infradead.org/mtd-2.6
[powerpc.git] / drivers / ata / libata-eh.c
index 2c476ee..56cf59b 100644 (file)
@@ -32,7 +32,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
@@ -200,7 +199,7 @@ void ata_scsi_error(struct Scsi_Host *host)
        /* synchronize with port task */
        ata_port_flush_task(ap);
 
-       /* synchronize with host_set lock and sort out timeouts */
+       /* synchronize with host lock and sort out timeouts */
 
        /* For new EH, all qcs are finished in one of three ways -
         * normal completion, error completion, and SCSI timeout.
@@ -333,7 +332,7 @@ void ata_scsi_error(struct Scsi_Host *host)
        if (ap->pflags & ATA_PFLAG_LOADING)
                ap->pflags &= ~ATA_PFLAG_LOADING;
        else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
-               queue_work(ata_aux_wq, &ap->hotplug_task);
+               queue_delayed_work(ata_aux_wq, &ap->hotplug_task, 0);
 
        if (ap->pflags & ATA_PFLAG_RECOVERED)
                ata_port_printk(ap, KERN_INFO, "EH complete\n");
@@ -377,7 +376,7 @@ void ata_port_wait_eh(struct ata_port *ap)
        spin_unlock_irqrestore(ap->lock, flags);
 
        /* make sure SCSI EH is complete */
-       if (scsi_host_in_recovery(ap->host)) {
+       if (scsi_host_in_recovery(ap->scsi_host)) {
                msleep(10);
                goto retry;
        }
@@ -486,7 +485,7 @@ void ata_eng_timeout(struct ata_port *ap)
  *     other commands are drained.
  *
  *     LOCKING:
- *     spin_lock_irqsave(host_set lock)
+ *     spin_lock_irqsave(host lock)
  */
 void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
 {
@@ -513,14 +512,14 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
  *     all commands are drained.
  *
  *     LOCKING:
- *     spin_lock_irqsave(host_set lock)
+ *     spin_lock_irqsave(host lock)
  */
 void ata_port_schedule_eh(struct ata_port *ap)
 {
        WARN_ON(!ap->ops->error_handler);
 
        ap->pflags |= ATA_PFLAG_EH_PENDING;
-       scsi_schedule_eh(ap->host);
+       scsi_schedule_eh(ap->scsi_host);
 
        DPRINTK("port EH scheduled\n");
 }
@@ -532,7 +531,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
  *     Abort all active qc's of @ap and schedule EH.
  *
  *     LOCKING:
- *     spin_lock_irqsave(host_set lock)
+ *     spin_lock_irqsave(host lock)
  *
  *     RETURNS:
  *     Number of aborted qc's.
@@ -575,7 +574,7 @@ int ata_port_abort(struct ata_port *ap)
  *     is frozen.
  *
  *     LOCKING:
- *     spin_lock_irqsave(host_set lock)
+ *     spin_lock_irqsave(host lock)
  */
 static void __ata_port_freeze(struct ata_port *ap)
 {
@@ -596,7 +595,7 @@ static void __ata_port_freeze(struct ata_port *ap)
  *     Abort and freeze @ap.
  *
  *     LOCKING:
- *     spin_lock_irqsave(host_set lock)
+ *     spin_lock_irqsave(host lock)
  *
  *     RETURNS:
  *     Number of aborted commands.
@@ -1137,19 +1136,21 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc,
                break;
 
        case ATA_DEV_ATAPI:
-               tmp = atapi_eh_request_sense(qc->dev,
-                                            qc->scsicmd->sense_buffer);
-               if (!tmp) {
-                       /* ATA_QCFLAG_SENSE_VALID is used to tell
-                        * atapi_qc_complete() that sense data is
-                        * already valid.
-                        *
-                        * TODO: interpret sense data and set
-                        * appropriate err_mask.
-                        */
-                       qc->flags |= ATA_QCFLAG_SENSE_VALID;
-               } else
-                       qc->err_mask |= tmp;
+               if (!(qc->ap->pflags & ATA_PFLAG_FROZEN)) {
+                       tmp = atapi_eh_request_sense(qc->dev,
+                                                    qc->scsicmd->sense_buffer);
+                       if (!tmp) {
+                               /* ATA_QCFLAG_SENSE_VALID is used to
+                                * tell atapi_qc_complete() that sense
+                                * data is already valid.
+                                *
+                                * TODO: interpret sense data and set
+                                * appropriate err_mask.
+                                */
+                               qc->flags |= ATA_QCFLAG_SENSE_VALID;
+                       } else
+                               qc->err_mask |= tmp;
+               }
        }
 
        if (qc->err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT | AC_ERR_ATA_BUS))
@@ -1434,16 +1435,39 @@ static void ata_eh_report(struct ata_port *ap)
        }
 
        for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
+               static const char *dma_str[] = {
+                       [DMA_BIDIRECTIONAL]     = "bidi",
+                       [DMA_TO_DEVICE]         = "out",
+                       [DMA_FROM_DEVICE]       = "in",
+                       [DMA_NONE]              = "",
+               };
                struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
+               struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf;
+               unsigned int nbytes;
 
                if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
                        continue;
 
-               ata_dev_printk(qc->dev, KERN_ERR, "tag %d cmd 0x%x "
-                              "Emask 0x%x stat 0x%x err 0x%x (%s)\n",
-                              qc->tag, qc->tf.command, qc->err_mask,
-                              qc->result_tf.command, qc->result_tf.feature,
-                              ata_err_string(qc->err_mask));
+               nbytes = qc->nbytes;
+               if (!nbytes)
+                       nbytes = qc->nsect << 9;
+
+               ata_dev_printk(qc->dev, KERN_ERR,
+                       "cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
+                       "tag %d cdb 0x%x data %u %s\n         "
+                       "res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
+                       "Emask 0x%x (%s)\n",
+                       cmd->command, cmd->feature, cmd->nsect,
+                       cmd->lbal, cmd->lbam, cmd->lbah,
+                       cmd->hob_feature, cmd->hob_nsect,
+                       cmd->hob_lbal, cmd->hob_lbam, cmd->hob_lbah,
+                       cmd->device, qc->tag, qc->cdb[0], nbytes,
+                       dma_str[qc->dma_dir],
+                       res->command, res->feature, res->nsect,
+                       res->lbal, res->lbam, res->lbah,
+                       res->hob_feature, res->hob_nsect,
+                       res->hob_lbal, res->hob_lbam, res->hob_lbah,
+                       res->device, qc->err_mask, ata_err_string(qc->err_mask));
        }
 }
 
@@ -1516,7 +1540,11 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
        if (prereset) {
                rc = prereset(ap);
                if (rc) {
-                       ata_port_printk(ap, KERN_ERR,
+                       if (rc == -ENOENT) {
+                               ata_port_printk(ap, KERN_DEBUG, "port disabled. ignoring.\n");
+                               ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
+                       } else
+                               ata_port_printk(ap, KERN_ERR,
                                        "prereset failed (errno=%d)\n", rc);
                        return rc;
                }
@@ -1631,11 +1659,14 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
        DPRINTK("ENTER\n");
 
        for (i = 0; i < ATA_MAX_DEVICES; i++) {
-               unsigned int action;
+               unsigned int action, readid_flags = 0;
 
                dev = &ap->device[i];
                action = ata_eh_dev_action(dev);
 
+               if (ehc->i.flags & ATA_EHI_DID_RESET)
+                       readid_flags |= ATA_READID_POSTRESET;
+
                if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
                        if (ata_port_offline(ap)) {
                                rc = -EIO;
@@ -1643,13 +1674,17 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
                        }
 
                        ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE);
-                       rc = ata_dev_revalidate(dev,
-                                       ehc->i.flags & ATA_EHI_DID_RESET);
+                       rc = ata_dev_revalidate(dev, readid_flags);
                        if (rc)
                                break;
 
                        ata_eh_done(ap, dev, ATA_EH_REVALIDATE);
 
+                       /* Configuration may have changed, reconfigure
+                        * transfer mode.
+                        */
+                       ehc->i.flags |= ATA_EHI_SETMODE;
+
                        /* schedule the scsi_rescan_device() here */
                        queue_work(ata_aux_wq, &(ap->scsi_rescan_task));
                } else if (dev->class == ATA_DEV_UNKNOWN &&
@@ -1657,18 +1692,35 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
                           ata_class_enabled(ehc->classes[dev->devno])) {
                        dev->class = ehc->classes[dev->devno];
 
-                       rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
-                       if (rc == 0)
-                               rc = ata_dev_configure(dev, 1);
+                       rc = ata_dev_read_id(dev, &dev->class, readid_flags,
+                                            dev->id);
+                       if (rc == 0) {
+                               ehc->i.flags |= ATA_EHI_PRINTINFO;
+                               rc = ata_dev_configure(dev);
+                               ehc->i.flags &= ~ATA_EHI_PRINTINFO;
+                       } else if (rc == -ENOENT) {
+                               /* IDENTIFY was issued to non-existent
+                                * device.  No need to reset.  Just
+                                * thaw and kill the device.
+                                */
+                               ata_eh_thaw_port(ap);
+                               dev->class = ATA_DEV_UNKNOWN;
+                               rc = 0;
+                       }
 
                        if (rc) {
                                dev->class = ATA_DEV_UNKNOWN;
                                break;
                        }
 
-                       spin_lock_irqsave(ap->lock, flags);
-                       ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
-                       spin_unlock_irqrestore(ap->lock, flags);
+                       if (ata_dev_enabled(dev)) {
+                               spin_lock_irqsave(ap->lock, flags);
+                               ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
+                               spin_unlock_irqrestore(ap->lock, flags);
+
+                               /* new device discovered, configure xfermode */
+                               ehc->i.flags |= ATA_EHI_SETMODE;
+                       }
                }
        }
 
@@ -1927,6 +1979,10 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
 
                ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
 
+               /* collect port action mask recorded in dev actions */
+               ehc->i.action |= ehc->i.dev_action[i] & ~ATA_EH_PERDEV_MASK;
+               ehc->i.dev_action[i] &= ATA_EH_PERDEV_MASK;
+
                /* process hotplug request */
                if (dev->flags & ATA_DFLAG_DETACH)
                        ata_eh_detach_dev(dev);
@@ -1984,13 +2040,14 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
        if (rc)
                goto dev_fail;
 
-       /* configure transfer mode if the port has been reset */
-       if (ehc->i.flags & ATA_EHI_DID_RESET) {
+       /* configure transfer mode if necessary */
+       if (ehc->i.flags & ATA_EHI_SETMODE) {
                rc = ata_set_mode(ap, &dev);
                if (rc) {
                        down_xfermask = 1;
                        goto dev_fail;
                }
+               ehc->i.flags &= ~ATA_EHI_SETMODE;
        }
 
        /* suspend devices */