]> err.no Git - linux-2.6/blobdiff - drivers/ata/libata-eh.c
V4L/DVB (7856): cx18/: possible cleanups
[linux-2.6] / drivers / ata / libata-eh.c
index f7cae640015528aeeb211cf28ee64ef98f685d89..62e033146bedae50c7de7126f0f3a8b2aec67b17 100644 (file)
@@ -873,9 +873,9 @@ int sata_async_notification(struct ata_port *ap)
        if (rc == 0)
                sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
 
-       if (!ap->nr_pmp_links || rc) {
+       if (!sata_pmp_attached(ap) || rc) {
                /* PMP is not attached or SNTF is not available */
-               if (!ap->nr_pmp_links) {
+               if (!sata_pmp_attached(ap)) {
                        /* PMP is not attached.  Check whether ATAPI
                         * AN is configured.  If so, notify media
                         * change.
@@ -1079,12 +1079,6 @@ void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
 
        spin_lock_irqsave(ap->lock, flags);
 
-       /* suck in and clear reset modifier */
-       if (action & ATA_EH_RESET) {
-               ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK;
-               ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
-       }
-
        ata_eh_clear_action(link, dev, ehi, action);
 
        if (!(ehc->i.flags & ATA_EHI_QUIET))
@@ -1110,10 +1104,6 @@ void ata_eh_done(struct ata_link *link, struct ata_device *dev,
 {
        struct ata_eh_context *ehc = &link->eh_context;
 
-       /* if reset is complete, clear reset modifier */
-       if (action & ATA_EH_RESET)
-               ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
-
        ata_eh_clear_action(link, dev, &ehc->i, action);
 }
 
@@ -1367,7 +1357,7 @@ static void ata_eh_analyze_serror(struct ata_link *link)
  *     LOCKING:
  *     Kernel thread context (may sleep).
  */
-static void ata_eh_analyze_ncq_error(struct ata_link *link)
+void ata_eh_analyze_ncq_error(struct ata_link *link)
 {
        struct ata_port *ap = link->ap;
        struct ata_eh_context *ehc = &link->eh_context;
@@ -1412,6 +1402,7 @@ static void ata_eh_analyze_ncq_error(struct ata_link *link)
        /* we've got the perpetrator, condemn it */
        qc = __ata_qc_from_tag(ap, tag);
        memcpy(&qc->result_tf, &tf, sizeof(tf));
+       qc->result_tf.flags = ATA_TFLAG_ISADDR | ATA_TFLAG_LBA | ATA_TFLAG_LBA48;
        qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
        ehc->i.err_mask &= ~AC_ERR_DEV;
 }
@@ -1756,7 +1747,7 @@ static void ata_eh_link_autopsy(struct ata_link *link)
                ata_eh_analyze_serror(link);
        } else if (rc != -EOPNOTSUPP) {
                /* SError read failed, force reset and probing */
-               ata_ehi_schedule_probe(&ehc->i);
+               ehc->i.probe_mask |= ATA_ALL_DEVICES;
                ehc->i.action |= ATA_EH_RESET;
                ehc->i.err_mask |= AC_ERR_OTHER;
        }
@@ -1795,6 +1786,11 @@ static void ata_eh_link_autopsy(struct ata_link *link)
                if (qc->flags & ATA_QCFLAG_SENSE_VALID)
                        qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
 
+               /* determine whether the command is worth retrying */
+               if (!(qc->err_mask & AC_ERR_INVALID) &&
+                   ((qc->flags & ATA_QCFLAG_IO) || qc->err_mask != AC_ERR_DEV))
+                       qc->flags |= ATA_QCFLAG_RETRY;
+
                /* accumulate error info */
                ehc->i.dev = qc->dev;
                all_err_mask |= qc->err_mask;
@@ -1858,7 +1854,7 @@ void ata_eh_autopsy(struct ata_port *ap)
        /* Autopsy of fanout ports can affect host link autopsy.
         * Perform host link autopsy last.
         */
-       if (ap->nr_pmp_links)
+       if (sata_pmp_attached(ap))
                ata_eh_link_autopsy(&ap->link);
 }
 
@@ -2057,41 +2053,29 @@ static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
                classes[dev->devno] = ATA_DEV_UNKNOWN;
 
        rc = reset(link, classes, deadline);
-       if (rc)
-               return rc;
 
-       /* If any class isn't ATA_DEV_UNKNOWN, consider classification
-        * is complete and convert all ATA_DEV_UNKNOWN to
-        * ATA_DEV_NONE.
-        */
+       /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
        ata_link_for_each_dev(dev, link)
-               if (classes[dev->devno] != ATA_DEV_UNKNOWN)
-                       break;
-
-       if (dev) {
-               ata_link_for_each_dev(dev, link) {
-                       if (classes[dev->devno] == ATA_DEV_UNKNOWN)
-                               classes[dev->devno] = ATA_DEV_NONE;
-               }
-       }
+               if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+                       classes[dev->devno] = ATA_DEV_NONE;
 
-       return 0;
+       return rc;
 }
 
 static int ata_eh_followup_srst_needed(struct ata_link *link,
                                       int rc, int classify,
                                       const unsigned int *classes)
 {
-       if (link->flags & ATA_LFLAG_NO_SRST)
+       if ((link->flags & ATA_LFLAG_NO_SRST) || ata_link_offline(link))
                return 0;
-       if (rc == -EAGAIN)
-               return 1;
+       if (rc == -EAGAIN) {
+               if (classify)
+                       return 1;
+               rc = 0;
+       }
        if (rc != 0)
                return 0;
-       if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link))
-               return 1;
-       if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) &&
-           classes[0] == ATA_DEV_UNKNOWN)
+       if (sata_pmp_supported(link->ap) && ata_is_host_link(link))
                return 1;
        return 0;
 }
@@ -2154,9 +2138,14 @@ int ata_eh_reset(struct ata_link *link, int classify,
        if (hardreset) {
                reset = hardreset;
                ehc->i.action = ATA_EH_HARDRESET;
-       } else {
+       } else if (softreset) {
                reset = softreset;
                ehc->i.action = ATA_EH_SOFTRESET;
+       } else {
+               ata_link_printk(link, KERN_ERR, "BUG: no reset method, "
+                               "please report to linux-ide@vger.kernel.org\n");
+               dump_stack();
+               return -EINVAL;
        }
 
        if (prereset) {
@@ -2224,21 +2213,6 @@ int ata_eh_reset(struct ata_link *link, int classify,
        if (rc && rc != -EAGAIN)
                goto fail;
 
-       /* was classification successful? */
-       if (classify && classes[0] == ATA_DEV_UNKNOWN &&
-           !(lflags & ATA_LFLAG_ASSUME_CLASS)) {
-               if (try < max_tries) {
-                       ata_link_printk(link, KERN_WARNING,
-                                       "classification failed\n");
-                       rc = -EINVAL;
-                       goto fail;
-               }
-
-               ata_link_printk(link, KERN_WARNING,
-                               "classfication failed, assuming ATA\n");
-               lflags |= ATA_LFLAG_ASSUME_ATA;
-       }
-
  done:
        ata_link_for_each_dev(dev, link) {
                /* After the reset, the device state is PIO 0 and the
@@ -2281,6 +2255,11 @@ int ata_eh_reset(struct ata_link *link, int classify,
        return rc;
 
  fail:
+       /* if SCR isn't accessible on a fan-out port, PMP needs to be reset */
+       if (!ata_is_host_link(link) &&
+           sata_scr_read(link, SCR_STATUS, &sstatus))
+               rc = -ERESTART;
+
        if (rc == -ERESTART || try >= max_tries)
                goto out;
 
@@ -2491,6 +2470,7 @@ static int ata_link_nr_vacant(struct ata_link *link)
 
 static int ata_eh_skip_recovery(struct ata_link *link)
 {
+       struct ata_port *ap = link->ap;
        struct ata_eh_context *ehc = &link->eh_context;
        struct ata_device *dev;
 
@@ -2498,9 +2478,13 @@ static int ata_eh_skip_recovery(struct ata_link *link)
        if (link->flags & ATA_LFLAG_DISABLED)
                return 1;
 
-       /* thaw frozen port, resume link and recover failed devices */
-       if ((link->ap->pflags & ATA_PFLAG_FROZEN) ||
-           (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link))
+       /* thaw frozen port and recover failed devices */
+       if ((ap->pflags & ATA_PFLAG_FROZEN) || ata_link_nr_enabled(link))
+               return 0;
+
+       /* reset at least once if reset is requested */
+       if ((ehc->i.action & ATA_EH_RESET) &&
+           !(ehc->i.flags & ATA_EHI_DID_RESET))
                return 0;
 
        /* skip if class codes for all vacant slots are ATA_DEV_NONE */
@@ -2673,7 +2657,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                /* if PMP is attached, this function only deals with
                 * downstream links, port should stay thawed.
                 */
-               if (!ap->nr_pmp_links)
+               if (!sata_pmp_attached(ap))
                        ata_eh_freeze_port(ap);
 
                ata_port_for_each_link(link, ap) {
@@ -2692,7 +2676,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                        }
                }
 
-               if (!ap->nr_pmp_links)
+               if (!sata_pmp_attached(ap))
                        ata_eh_thaw_port(ap);
        }
 
@@ -2736,7 +2720,7 @@ dev_fail:
                        /* PMP reset requires working host port.
                         * Can't retry if it's frozen.
                         */
-                       if (ap->nr_pmp_links)
+                       if (sata_pmp_attached(ap))
                                goto out;
                        break;
                }
@@ -2788,18 +2772,11 @@ void ata_eh_finish(struct ata_port *ap)
                        /* FIXME: Once EH migration is complete,
                         * generate sense data in this function,
                         * considering both err_mask and tf.
-                        *
-                        * There's no point in retrying invalid
-                        * (detected by libata) and non-IO device
-                        * errors (rejected by device).  Finish them
-                        * immediately.
                         */
-                       if ((qc->err_mask & AC_ERR_INVALID) ||
-                           (!(qc->flags & ATA_QCFLAG_IO) &&
-                            qc->err_mask == AC_ERR_DEV))
-                               ata_eh_qc_complete(qc);
-                       else
+                       if (qc->flags & ATA_QCFLAG_RETRY)
                                ata_eh_qc_retry(qc);
+                       else
+                               ata_eh_qc_complete(qc);
                } else {
                        if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
                                ata_eh_qc_complete(qc);
@@ -2819,6 +2796,7 @@ void ata_eh_finish(struct ata_port *ap)
 /**
  *     ata_do_eh - do standard error handling
  *     @ap: host port to handle error for
+ *
  *     @prereset: prereset method (can be NULL)
  *     @softreset: softreset method (can be NULL)
  *     @hardreset: hardreset method (can be NULL)
@@ -2849,6 +2827,27 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
        ata_eh_finish(ap);
 }
 
+/**
+ *     ata_std_error_handler - standard error handler
+ *     @ap: host port to handle error for
+ *
+ *     Standard error handler
+ *
+ *     LOCKING:
+ *     Kernel thread context (may sleep).
+ */
+void ata_std_error_handler(struct ata_port *ap)
+{
+       struct ata_port_operations *ops = ap->ops;
+       ata_reset_fn_t hardreset = ops->hardreset;
+
+       /* ignore built-in hardreset if SCR access is not available */
+       if (ata_is_builtin_hardreset(hardreset) && !sata_scr_valid(&ap->link))
+               hardreset = NULL;
+
+       ata_do_eh(ap, ops->prereset, ops->softreset, hardreset, ops->postreset);
+}
+
 #ifdef CONFIG_PM
 /**
  *     ata_eh_handle_port_suspend - perform port suspend operation