]> err.no Git - linux-2.6/commitdiff
sata_mv: ensure empty request queue for FBS-NCQ EH
authorMark Lord <liml@rtr.ca>
Mon, 19 May 2008 13:01:24 +0000 (09:01 -0400)
committerJeff Garzik <jgarzik@redhat.com>
Mon, 19 May 2008 21:30:28 +0000 (17:30 -0400)
Check for an empty request queue before stopping EDMA after a FBS-NCQ error,
as per recommendation from the Marvell datasheet.

This ensures that the EDMA won't suddenly become active again
just after our subsequent check of the empty/idle bits.

Also bump DRV_VERSION.

Signed-off-by: Mark Lord <mlord@pobox.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
drivers/ata/sata_mv.c

index 2d8a7e894b7b0b1ebec61b0c370bf004f1d4eff8..fb81f0c7a8c2555d6e015c930a3373563f24cabc 100644 (file)
@@ -72,7 +72,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME       "sata_mv"
-#define DRV_VERSION    "1.20"
+#define DRV_VERSION    "1.21"
 
 enum {
        /* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -1695,6 +1695,18 @@ static void mv_pmp_eh_prep(struct ata_port *ap, unsigned int pmp_map)
        }
 }
 
+static int mv_req_q_empty(struct ata_port *ap)
+{
+       void __iomem *port_mmio = mv_ap_base(ap);
+       u32 in_ptr, out_ptr;
+
+       in_ptr  = (readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS)
+                       >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+       out_ptr = (readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
+                       >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK;
+       return (in_ptr == out_ptr);     /* 1 == queue_is_empty */
+}
+
 static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap)
 {
        struct mv_port_priv *pp = ap->private_data;
@@ -1728,7 +1740,7 @@ static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap)
                        ap->qc_active, failed_links,
                        ap->nr_active_links);
 
-       if (ap->nr_active_links <= failed_links) {
+       if (ap->nr_active_links <= failed_links && mv_req_q_empty(ap)) {
                mv_process_crpb_entries(ap, pp);
                mv_stop_edma(ap);
                mv_eh_freeze(ap);