aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMark Lord <liml@rtr.ca>2006-05-19 16:21:03 -0400
committerJeff Garzik <jeff@garzik.org>2006-05-20 00:31:45 -0400
commit9b358e305c1d783c8a4ebf00344e95deb9e38f3d (patch)
treeb1cfece40d968befb1df17661282471ddf59a9dc /drivers
parent2f880b65fdbc2d4915bddc59d75a176329570fdd (diff)
[PATCH] sata_mv: prevent unnecessary double-resets
The mv_err_intr() function is invoked from the driver's interrupt handler, as well as from the timeout function. This patch prevents it from triggering a one-after-the-other double reset of the controller when invoked from the timeout function. This also adds a check for a timeout race condition that has been observed to occur with this driver in earlier kernels. This should not be needed, in theory, but in practice it has caught bugs. Maybe nuke it at a later date. Signed-off-by: Mark Lord <liml@rtr.ca> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/sata_mv.c17
1 files changed, 10 insertions, 7 deletions
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index d5fdcb9a8842..87f26cd60fae 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -1291,6 +1291,7 @@ static u8 mv_get_crpb_status(struct ata_port *ap)
1291/** 1291/**
1292 * mv_err_intr - Handle error interrupts on the port 1292 * mv_err_intr - Handle error interrupts on the port
1293 * @ap: ATA channel to manipulate 1293 * @ap: ATA channel to manipulate
1294 * @reset_allowed: bool: 0 == don't trigger from reset here
1294 * 1295 *
1295 * In most cases, just clear the interrupt and move on. However, 1296 * In most cases, just clear the interrupt and move on. However,
1296 * some cases require an eDMA reset, which is done right before 1297 * some cases require an eDMA reset, which is done right before
@@ -1301,7 +1302,7 @@ static u8 mv_get_crpb_status(struct ata_port *ap)
1301 * LOCKING: 1302 * LOCKING:
1302 * Inherited from caller. 1303 * Inherited from caller.
1303 */ 1304 */
1304static void mv_err_intr(struct ata_port *ap) 1305static void mv_err_intr(struct ata_port *ap, int reset_allowed)
1305{ 1306{
1306 void __iomem *port_mmio = mv_ap_base(ap); 1307 void __iomem *port_mmio = mv_ap_base(ap);
1307 u32 edma_err_cause, serr = 0; 1308 u32 edma_err_cause, serr = 0;
@@ -1323,9 +1324,8 @@ static void mv_err_intr(struct ata_port *ap)
1323 writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS); 1324 writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
1324 1325
1325 /* check for fatal here and recover if needed */ 1326 /* check for fatal here and recover if needed */
1326 if (EDMA_ERR_FATAL & edma_err_cause) { 1327 if (reset_allowed && (EDMA_ERR_FATAL & edma_err_cause))
1327 mv_stop_and_reset(ap); 1328 mv_stop_and_reset(ap);
1328 }
1329} 1329}
1330 1330
1331/** 1331/**
@@ -1406,7 +1406,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
1406 shift++; /* skip bit 8 in the HC Main IRQ reg */ 1406 shift++; /* skip bit 8 in the HC Main IRQ reg */
1407 } 1407 }
1408 if ((PORT0_ERR << shift) & relevant) { 1408 if ((PORT0_ERR << shift) & relevant) {
1409 mv_err_intr(ap); 1409 mv_err_intr(ap, 1);
1410 err_mask |= AC_ERR_OTHER; 1410 err_mask |= AC_ERR_OTHER;
1411 handled = 1; 1411 handled = 1;
1412 } 1412 }
@@ -2031,11 +2031,14 @@ static void mv_eng_timeout(struct ata_port *ap)
2031 ap->host_set->mmio_base, ap, qc, qc->scsicmd, 2031 ap->host_set->mmio_base, ap, qc, qc->scsicmd,
2032 &qc->scsicmd->cmnd); 2032 &qc->scsicmd->cmnd);
2033 2033
2034 mv_err_intr(ap); 2034 mv_err_intr(ap, 0);
2035 mv_stop_and_reset(ap); 2035 mv_stop_and_reset(ap);
2036 2036
2037 qc->err_mask |= AC_ERR_TIMEOUT; 2037 WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
2038 ata_eh_qc_complete(qc); 2038 if (qc->flags & ATA_QCFLAG_ACTIVE) {
2039 qc->err_mask |= AC_ERR_TIMEOUT;
2040 ata_eh_qc_complete(qc);
2041 }
2039} 2042}
2040 2043
2041/** 2044/**