Skip to content

Commit

Permalink
[PATCH] sata_mv: prevent unnecessary double-resets
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Jeff Garzik <[email protected]>
  • Loading branch information
Mark Lord authored and Jeff Garzik committed May 20, 2006
1 parent 2f880b6 commit 9b358e3
Showing 1 changed file with 10 additions and 7 deletions.
17 changes: 10 additions & 7 deletions drivers/scsi/sata_mv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,7 @@ static u8 mv_get_crpb_status(struct ata_port *ap)
/**
* mv_err_intr - Handle error interrupts on the port
* @ap: ATA channel to manipulate
* @reset_allowed: bool: 0 == don't trigger from reset here
*
* In most cases, just clear the interrupt and move on. However,
* some cases require an eDMA reset, which is done right before
Expand All @@ -1301,7 +1302,7 @@ static u8 mv_get_crpb_status(struct ata_port *ap)
* LOCKING:
* Inherited from caller.
*/
static void mv_err_intr(struct ata_port *ap)
static void mv_err_intr(struct ata_port *ap, int reset_allowed)
{
void __iomem *port_mmio = mv_ap_base(ap);
u32 edma_err_cause, serr = 0;
Expand All @@ -1323,9 +1324,8 @@ static void mv_err_intr(struct ata_port *ap)
writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);

/* check for fatal here and recover if needed */
if (EDMA_ERR_FATAL & edma_err_cause) {
if (reset_allowed && (EDMA_ERR_FATAL & edma_err_cause))
mv_stop_and_reset(ap);
}
}

/**
Expand Down Expand Up @@ -1406,7 +1406,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
shift++; /* skip bit 8 in the HC Main IRQ reg */
}
if ((PORT0_ERR << shift) & relevant) {
mv_err_intr(ap);
mv_err_intr(ap, 1);
err_mask |= AC_ERR_OTHER;
handled = 1;
}
Expand Down Expand Up @@ -2031,11 +2031,14 @@ static void mv_eng_timeout(struct ata_port *ap)
ap->host_set->mmio_base, ap, qc, qc->scsicmd,
&qc->scsicmd->cmnd);

mv_err_intr(ap);
mv_err_intr(ap, 0);
mv_stop_and_reset(ap);

qc->err_mask |= AC_ERR_TIMEOUT;
ata_eh_qc_complete(qc);
WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
if (qc->flags & ATA_QCFLAG_ACTIVE) {
qc->err_mask |= AC_ERR_TIMEOUT;
ata_eh_qc_complete(qc);
}
}

/**
Expand Down

0 comments on commit 9b358e3

Please sign in to comment.