libata: improve probe failure handling
[powerpc.git] / drivers / ata / libata-eh.c
index 3771eb8..1abfdba 100644 (file)
@@ -332,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");
@@ -1136,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))
@@ -1274,7 +1276,7 @@ static int ata_eh_speed_down(struct ata_device *dev, int is_io,
                return ATA_EH_HARDRESET;
 
        /* lower transfer mode */
-       if (ata_down_xfermask_limit(dev, 0) == 0)
+       if (ata_down_xfermask_limit(dev, ATA_DNXFER_ANY) == 0)
                return ATA_EH_SOFTRESET;
 
        ata_dev_printk(dev, KERN_ERR,
@@ -1441,25 +1443,21 @@ static void ata_eh_report(struct ata_port *ap)
                };
                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;
 
-               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 data %u %s\n         "
+                       "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, nbytes, dma_str[qc->dma_dir],
+                       cmd->device, qc->tag, qc->cdb[0], qc->nbytes,
+                       dma_str[qc->dma_dir],
                        res->command, res->feature, res->nsect,
                        res->lbal, res->lbam, res->lbah,
                        res->hob_feature, res->hob_nsect,
@@ -1689,9 +1687,6 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
                           ata_class_enabled(ehc->classes[dev->devno])) {
                        dev->class = ehc->classes[dev->devno];
 
-                       if (ap->flags & ATA_FLAG_DETECT_POLLING)
-                               readid_flags |= ATA_READID_DETECT;
-
                        rc = ata_dev_read_id(dev, &dev->class, readid_flags,
                                             dev->id);
                        if (rc == 0) {
@@ -1796,7 +1791,7 @@ static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
                *r_failed_dev = dev;
 
        DPRINTK("EXIT\n");
-       return 0;
+       return rc;
 }
 
 /**
@@ -1969,7 +1964,7 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
 {
        struct ata_eh_context *ehc = &ap->eh_context;
        struct ata_device *dev;
-       int down_xfermask, i, rc;
+       int i, rc;
 
        DPRINTK("ENTER\n");
 
@@ -1979,6 +1974,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);
@@ -1994,7 +1993,6 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
        }
 
  retry:
-       down_xfermask = 0;
        rc = 0;
 
        /* if UNLOADING, finish immediately */
@@ -2039,10 +2037,8 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
        /* configure transfer mode if necessary */
        if (ehc->i.flags & ATA_EHI_SETMODE) {
                rc = ata_set_mode(ap, &dev);
-               if (rc) {
-                       down_xfermask = 1;
+               if (rc)
                        goto dev_fail;
-               }
                ehc->i.flags &= ~ATA_EHI_SETMODE;
        }
 
@@ -2054,20 +2050,27 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
        goto out;
 
  dev_fail:
+       ehc->tries[dev->devno]--;
+
        switch (rc) {
-       case -ENODEV:
-               /* device missing, schedule probing */
-               ehc->i.probe_mask |= (1 << dev->devno);
        case -EINVAL:
+               /* eeek, something went very wrong, give up */
                ehc->tries[dev->devno] = 0;
                break;
+
+       case -ENODEV:
+               /* device missing or wrong IDENTIFY data, schedule probing */
+               ehc->i.probe_mask |= (1 << dev->devno);
+               /* give it just one more chance */
+               ehc->tries[dev->devno] = min(ehc->tries[dev->devno], 1);
        case -EIO:
-               sata_down_spd_limit(ap);
-       default:
-               ehc->tries[dev->devno]--;
-               if (down_xfermask &&
-                   ata_down_xfermask_limit(dev, ehc->tries[dev->devno] == 1))
-                       ehc->tries[dev->devno] = 0;
+               if (ehc->tries[dev->devno] == 1) {
+                       /* This is the last chance, better to slow
+                        * down than lose it.
+                        */
+                       sata_down_spd_limit(ap);
+                       ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
+               }
        }
 
        if (ata_dev_enabled(dev) && !ehc->tries[dev->devno]) {