only call drive reset with AT_POLL when the command itself was

polled, so that the logic for AT_POLL matches how e.g. ata_dmaerr() is
called; this was the original intent of the change in 1.428.2.25,
to make the error handling safe wrt. polled xfers

this is stopgap fix for ATA channel wedge after DMA error, as reported
by Martin Husemann in PR kern/52606, and PR kern/52605

problem happened due to ata_reset_channel() being called once in ata_dmaerr()
with flags == 0, which freezed channel and set flag to reset via thread,
then ata_reset_channel() was called via wdc_drive_reset() with AT_POLL, which
just executed the reset and cleared the flag, without clearing the extra
freeze; that logic will be refactored in separate commit
This commit is contained in:
jdolecek 2017-10-14 13:15:14 +00:00
parent 05aa47e6f6
commit fd181cba14

View File

@ -1,4 +1,4 @@
/* $NetBSD: wd.c,v 1.430 2017/10/07 16:05:32 jdolecek Exp $ */
/* $NetBSD: wd.c,v 1.431 2017/10/14 13:15:14 jdolecek Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@ -54,7 +54,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.430 2017/10/07 16:05:32 jdolecek Exp $");
__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.431 2017/10/14 13:15:14 jdolecek Exp $");
#include "opt_ata.h"
#include "opt_wd.h"
@ -829,8 +829,10 @@ wddone(device_t self, struct ata_xfer *xfer)
errmsg = "error";
do_perror = 1;
retry: /* Just reset and retry. Can we do more ? */
if ((xfer->c_flags & C_RECOVERED) == 0)
(*wd->atabus->ata_reset_drive)(wd->drvp, AT_POLL, NULL);
if ((xfer->c_flags & C_RECOVERED) == 0) {
int wflags = (xfer->c_flags & C_POLL) ? AT_POLL : 0;
(*wd->atabus->ata_reset_drive)(wd->drvp, wflags, NULL);
}
retry2:
mutex_enter(&wd->sc_lock);