When an error is reported on a write, data may have been transfered
to the device's cache anyway and so cmdh_prdbc reports a completed transfer. If we use it to update ata_bio->bcount this has 2 conseqences: - the automatic LBA48 workaround doesn't qick in because bcount is used to compute the last sector of the transfer (wd(4) part of kern/40569) - wd(4) will report a B_ERROR buffer with a b_resid of 0, which panics a DIAGNOSTIC kernel Fix by ignoring cmdh_prdbc if we had a write with errors, and in this case leave ata_bio->bcount at its initial value. While there use NOERROR instead of 0 for ata_bio->error (cosmetic). thanks to Matthias Scheler for tests.
This commit is contained in:
parent
d237abe695
commit
c54134b00b
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: ahcisata_core.c,v 1.18 2008/10/03 13:02:08 bouyer Exp $ */
|
||||
/* $NetBSD: ahcisata_core.c,v 1.19 2009/02/12 11:44:11 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006 Manuel Bouyer.
|
||||
@ -31,7 +31,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.18 2008/10/03 13:02:08 bouyer Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.19 2009/02/12 11:44:11 bouyer Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/malloc.h>
|
||||
@ -1065,7 +1065,7 @@ ahci_bio_complete(struct ata_channel *chp, struct ata_xfer *xfer, int is)
|
||||
ata_bio->error = TIMEOUT;
|
||||
} else {
|
||||
callout_stop(&chp->ch_callout);
|
||||
ata_bio->error = 0;
|
||||
ata_bio->error = NOERROR;
|
||||
}
|
||||
|
||||
chp->ch_queue->active_xfer = NULL;
|
||||
@ -1095,7 +1095,14 @@ ahci_bio_complete(struct ata_channel *chp, struct ata_xfer *xfer, int is)
|
||||
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
|
||||
AHCIDEBUG_PRINT(("ahci_bio_complete bcount %ld",
|
||||
ata_bio->bcount), DEBUG_XFERS);
|
||||
ata_bio->bcount -= le32toh(achp->ahcic_cmdh[slot].cmdh_prdbc);
|
||||
/*
|
||||
* if it was a write, complete data buffer may have been transfered
|
||||
* before error detection; in this case don't use cmdh_prdbc
|
||||
* as it won't reflect what was written to media. Assume nothing
|
||||
* was transfered and leave bcount as-is.
|
||||
*/
|
||||
if ((ata_bio->flags & ATA_READ) || ata_bio->error == NOERROR)
|
||||
ata_bio->bcount -= le32toh(achp->ahcic_cmdh[slot].cmdh_prdbc);
|
||||
AHCIDEBUG_PRINT((" now %ld\n", ata_bio->bcount), DEBUG_XFERS);
|
||||
(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
|
||||
atastart(chp);
|
||||
|
Loading…
Reference in New Issue
Block a user