diff options
author | Mark Lord <liml@rtr.ca> | 2008-05-19 09:01:24 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-05-19 17:30:28 -0400 |
commit | 06aaca3f6301d04463b1ee0eb75c0352147159f2 (patch) | |
tree | e4057424492a9237c736ed216c6df95a03da34ca /drivers/ata/sata_mv.c | |
parent | 96e2c487933e5f69e98fffdcae2c35c78a671c07 (diff) |
sata_mv: ensure empty request queue for FBS-NCQ EH
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>
Diffstat (limited to 'drivers/ata/sata_mv.c')
-rw-r--r-- | drivers/ata/sata_mv.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 2d8a7e894b7b..fb81f0c7a8c2 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c | |||
@@ -72,7 +72,7 @@ | |||
72 | #include <linux/libata.h> | 72 | #include <linux/libata.h> |
73 | 73 | ||
74 | #define DRV_NAME "sata_mv" | 74 | #define DRV_NAME "sata_mv" |
75 | #define DRV_VERSION "1.20" | 75 | #define DRV_VERSION "1.21" |
76 | 76 | ||
77 | enum { | 77 | enum { |
78 | /* BAR's are enumerated in terms of pci_resource_start() terms */ | 78 | /* 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) | |||
1695 | } | 1695 | } |
1696 | } | 1696 | } |
1697 | 1697 | ||
1698 | static int mv_req_q_empty(struct ata_port *ap) | ||
1699 | { | ||
1700 | void __iomem *port_mmio = mv_ap_base(ap); | ||
1701 | u32 in_ptr, out_ptr; | ||
1702 | |||
1703 | in_ptr = (readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS) | ||
1704 | >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK; | ||
1705 | out_ptr = (readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) | ||
1706 | >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK; | ||
1707 | return (in_ptr == out_ptr); /* 1 == queue_is_empty */ | ||
1708 | } | ||
1709 | |||
1698 | static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap) | 1710 | static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap) |
1699 | { | 1711 | { |
1700 | struct mv_port_priv *pp = ap->private_data; | 1712 | struct mv_port_priv *pp = ap->private_data; |
@@ -1728,7 +1740,7 @@ static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap) | |||
1728 | ap->qc_active, failed_links, | 1740 | ap->qc_active, failed_links, |
1729 | ap->nr_active_links); | 1741 | ap->nr_active_links); |
1730 | 1742 | ||
1731 | if (ap->nr_active_links <= failed_links) { | 1743 | if (ap->nr_active_links <= failed_links && mv_req_q_empty(ap)) { |
1732 | mv_process_crpb_entries(ap, pp); | 1744 | mv_process_crpb_entries(ap, pp); |
1733 | mv_stop_edma(ap); | 1745 | mv_stop_edma(ap); |
1734 | mv_eh_freeze(ap); | 1746 | mv_eh_freeze(ap); |