Module Name:    src
Committed By:   jdolecek
Date:           Fri Aug 31 19:08:03 UTC 2018

Modified Files:
        src/sys/dev/ata [jdolecek-ncqfixes]: ata.c ata_subr.c ata_wdc.c
            atavar.h wd.c wdvar.h
        src/sys/dev/ic [jdolecek-ncqfixes]: ahcisata_core.c mvsata.c siisata.c
            wdc.c
        src/sys/dev/scsipi [jdolecek-ncqfixes]: atapi_wdc.c

Log Message:
refactor ata_xfer to be just dumb structure; move all callouts/condvars out

retry callout to wd(4); reset callout and the active/cmd finish condvars
to channel queue; change code using the condvars so it works if there
are multiple waiters

simplify the async wait code for cmds, replace ata_wait_xfer()/ata_wake_xfer()
with ata_wait_cmd()

fix the callout_invoking/ack race handling code for timeouts to
actually have chance to work; change mvsata(4) to use generic timeout func

towards resolution of kern/52614


To generate a diff of this commit:
cvs rdiff -u -r1.141 -r1.141.6.1 src/sys/dev/ata/ata.c
cvs rdiff -u -r1.6 -r1.6.2.1 src/sys/dev/ata/ata_subr.c
cvs rdiff -u -r1.110 -r1.110.4.1 src/sys/dev/ata/ata_wdc.c
cvs rdiff -u -r1.99 -r1.99.2.1 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.441 -r1.441.2.1 src/sys/dev/ata/wd.c
cvs rdiff -u -r1.46 -r1.46.6.1 src/sys/dev/ata/wdvar.h
cvs rdiff -u -r1.62 -r1.62.2.1 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.41 -r1.41.2.1 src/sys/dev/ic/mvsata.c
cvs rdiff -u -r1.35 -r1.35.6.1 src/sys/dev/ic/siisata.c
cvs rdiff -u -r1.288 -r1.288.6.1 src/sys/dev/ic/wdc.c
cvs rdiff -u -r1.129 -r1.129.6.1 src/sys/dev/scsipi/atapi_wdc.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ata/ata.c
diff -u src/sys/dev/ata/ata.c:1.141 src/sys/dev/ata/ata.c:1.141.6.1
--- src/sys/dev/ata/ata.c:1.141	Sat Oct 28 04:53:54 2017
+++ src/sys/dev/ata/ata.c	Fri Aug 31 19:08:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata.c,v 1.141 2017/10/28 04:53:54 riastradh Exp $	*/
+/*	$NetBSD: ata.c,v 1.141.6.1 2018/08/31 19:08:03 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.141 2017/10/28 04:53:54 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.141.6.1 2018/08/31 19:08:03 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -1075,19 +1075,19 @@ ata_exec_xfer(struct ata_channel *chp, s
 		while (chp->ch_queue->queue_active > 0 ||
 		    TAILQ_FIRST(&chp->ch_queue->queue_xfer) != xfer) {
 			xfer->c_flags |= C_WAITACT;
-			cv_wait(&xfer->c_active, &chp->ch_lock);
+			cv_wait(&chp->ch_queue->c_active, &chp->ch_lock);
 			xfer->c_flags &= ~C_WAITACT;
+		}
 
-			/*
-			 * Free xfer now if it there was attempt to free it
-			 * while we were waiting.
-			 */
-			if ((xfer->c_flags & (C_FREE|C_WAITTIMO)) == C_FREE) {
-				ata_channel_unlock(chp);
+		/*
+		 * Free xfer now if it there was attempt to free it
+		 * while we were waiting.
+		 */
+		if ((xfer->c_flags & (C_FREE|C_WAITTIMO)) == C_FREE) {
+			ata_channel_unlock(chp);
 
-				ata_free_xfer(chp, xfer);
-				return;
-			}
+			ata_free_xfer(chp, xfer);
+			return;
 		}
 	}
 
@@ -1187,7 +1187,7 @@ again:
 		ATADEBUG_PRINT(("atastart: xfer %p channel %d drive %d "
 		    "wait active\n", xfer, chp->ch_channel, xfer->c_drive),
 		    DEBUG_XFERS);
-		cv_signal(&xfer->c_active);
+		cv_broadcast(&chp->ch_queue->c_active);
 		goto out;
 	}
 
@@ -1300,15 +1300,20 @@ ata_deactivate_xfer(struct ata_channel *
 	KASSERT(chq->queue_active > 0);
 	KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) != 0);
 
-	callout_stop(&xfer->c_timo_callout);
+	/* Stop only when this is last active xfer */
+	if (chq->queue_active == 1)
+		callout_stop(&chp->c_timo_callout);
 
-	if (callout_invoking(&xfer->c_timo_callout))
+	if (callout_invoking(&chp->c_timo_callout))
 		xfer->c_flags |= C_WAITTIMO;
 
 	TAILQ_REMOVE(&chq->active_xfers, xfer, c_activechain);
 	chq->active_xfers_used &= ~__BIT(xfer->c_slot);
 	chq->queue_active--;
 
+	if (xfer->c_flags & C_WAIT)
+		cv_broadcast(&chq->c_cmd_finish);
+
 	ata_channel_unlock(chp);
 }
 
@@ -1356,8 +1361,6 @@ ata_timo_xfer_check(struct ata_xfer *xfe
 
 	ata_channel_lock(chp);
 
-	callout_ack(&xfer->c_timo_callout);
-
 	if (xfer->c_flags & C_WAITTIMO) {
 		xfer->c_flags &= ~C_WAITTIMO;
 
@@ -1389,30 +1392,6 @@ ata_timo_xfer_check(struct ata_xfer *xfe
 	return false;
 }
 
-void
-ata_timeout(void *v)
-{
-	struct ata_xfer *xfer = v;
-	int s;
-
-	ATADEBUG_PRINT(("%s: slot %d\n", __func__, xfer->c_slot),
-	    DEBUG_FUNCS|DEBUG_XFERS);
-
-	s = splbio();				/* XXX MPSAFE */
-
-	if (ata_timo_xfer_check(xfer)) {
-		/* Already logged */
-		goto out;
-	}
-
-	/* Mark as timed out. Do not print anything, wd(4) will. */
-	xfer->c_flags |= C_TIMEOU;
-	xfer->c_intr(xfer->c_chp, xfer, 0);
-
-out:
-	splx(s);
-}
-
 /*
  * Kill off all active xfers for a ata_channel.
  *
@@ -2304,17 +2283,17 @@ atacmd_toncq(struct ata_xfer *xfer, uint
 }
 
 void
-ata_wait_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
+ata_wait_cmd(struct ata_channel *chp, struct ata_xfer *xfer)
 {
-	KASSERT(mutex_owned(&chp->ch_lock));
+	struct ata_queue *chq = chp->ch_queue;
+	struct ata_command *ata_c = &xfer->c_ata_c;
 
-	cv_wait(&xfer->c_finish, &chp->ch_lock);
-}
+	ata_channel_lock(chp);
 
-void
-ata_wake_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
-{
-	KASSERT(mutex_owned(&chp->ch_lock));
+	while ((ata_c->flags & AT_DONE) == 0)
+		cv_wait(&chq->c_cmd_finish, &chp->ch_lock);
+
+	ata_channel_unlock(chp);
 
-	cv_signal(&xfer->c_finish);
+	KASSERT((ata_c->flags & AT_DONE) != 0);
 }

Index: src/sys/dev/ata/ata_subr.c
diff -u src/sys/dev/ata/ata_subr.c:1.6 src/sys/dev/ata/ata_subr.c:1.6.2.1
--- src/sys/dev/ata/ata_subr.c:1.6	Fri Aug 10 22:43:22 2018
+++ src/sys/dev/ata/ata_subr.c	Fri Aug 31 19:08:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata_subr.c,v 1.6 2018/08/10 22:43:22 jdolecek Exp $	*/
+/*	$NetBSD: ata_subr.c,v 1.6.2.1 2018/08/31 19:08:03 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.6 2018/08/10 22:43:22 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.6.2.1 2018/08/31 19:08:03 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -158,30 +158,6 @@ ata_queue_drive_active_xfer(struct ata_c
 	return xfer;
 }
 
-static void
-ata_xfer_init(struct ata_xfer *xfer, uint8_t slot)
-{
-	memset(xfer, 0, sizeof(*xfer));
-
-	xfer->c_slot = slot;
-
-	cv_init(&xfer->c_active, "ataact");
-	cv_init(&xfer->c_finish, "atafin");
-	callout_init(&xfer->c_timo_callout, 0); 	/* XXX MPSAFE */
-	callout_init(&xfer->c_retry_callout, 0); 	/* XXX MPSAFE */
-}
-
-static void
-ata_xfer_destroy(struct ata_xfer *xfer)
-{
-	callout_halt(&xfer->c_timo_callout, NULL);	/* XXX MPSAFE */
-	callout_destroy(&xfer->c_timo_callout);
-	callout_halt(&xfer->c_retry_callout, NULL);	/* XXX MPSAFE */
-	callout_destroy(&xfer->c_retry_callout);
-	cv_destroy(&xfer->c_active);
-	cv_destroy(&xfer->c_finish);
-}
-
 struct ata_queue *
 ata_queue_alloc(uint8_t openings)
 {
@@ -201,8 +177,11 @@ ata_queue_alloc(uint8_t openings)
 	cv_init(&chq->queue_drain, "atdrn");
 	cv_init(&chq->queue_idle, "qidl");
 
+	cv_init(&chq->c_active, "ataact");
+	cv_init(&chq->c_cmd_finish, "atafin");
+
 	for (uint8_t i = 0; i < openings; i++)
-		ata_xfer_init(&chq->queue_xfers[i], i);
+		chq->queue_xfers[i].c_slot = i;
 
 	return chq;
 }
@@ -210,13 +189,13 @@ ata_queue_alloc(uint8_t openings)
 void
 ata_queue_free(struct ata_queue *chq)
 {
-	for (uint8_t i = 0; i < chq->queue_openings; i++)
-		ata_xfer_destroy(&chq->queue_xfers[i]);
-
 	cv_destroy(&chq->queue_busy);
 	cv_destroy(&chq->queue_drain);
 	cv_destroy(&chq->queue_idle);
 
+	cv_destroy(&chq->c_active);
+	cv_destroy(&chq->c_cmd_finish);
+
 	free(chq, M_DEVBUF);
 }
 
@@ -226,6 +205,8 @@ ata_channel_init(struct ata_channel *chp
 	mutex_init(&chp->ch_lock, MUTEX_DEFAULT, IPL_BIO);
 	cv_init(&chp->ch_thr_idle, "atath");
 
+	callout_init(&chp->c_timo_callout, 0); 	/* XXX MPSAFE */
+
 	/* Optionally setup the queue, too */
 	if (chp->ch_queue == NULL) {
 		chp->ch_queue = ata_queue_alloc(1);
@@ -240,6 +221,11 @@ ata_channel_destroy(struct ata_channel *
 		chp->ch_queue = NULL;
 	}
 
+	mutex_enter(&chp->ch_lock);
+	callout_halt(&chp->c_timo_callout, &chp->ch_lock);
+	callout_destroy(&chp->c_timo_callout);
+	mutex_exit(&chp->ch_lock);
+
 	mutex_destroy(&chp->ch_lock);
 	cv_destroy(&chp->ch_thr_idle);
 }
@@ -336,7 +322,7 @@ ata_free_xfer(struct ata_channel *chp, s
 	if (xfer->c_flags & (C_WAITACT|C_WAITTIMO)) {
 		/* Someone is waiting for this xfer, so we can't free now */
 		xfer->c_flags |= C_FREE;
-		cv_signal(&xfer->c_active);
+		cv_broadcast(&chq->c_active);
 		goto out;
 	}
 
@@ -372,6 +358,40 @@ out:
 	    DEBUG_XFERS);
 }
 
+void
+ata_timeout(void *v)
+{
+	struct ata_channel *chp = v;
+	struct ata_queue *chq = chp->ch_queue;
+	struct ata_xfer *xfer, *nxfer;
+	int s;
+
+	s = splbio();				/* XXX MPSAFE */
+
+	callout_ack(&chp->c_timo_callout);
+
+	/*
+	 * If there is a timeout, means the last enqueued command
+	 * timed out, and thus all commands timed out.
+	 * XXX locking 
+	 */
+	TAILQ_FOREACH_SAFE(xfer, &chq->active_xfers, c_activechain, nxfer) {
+		ATADEBUG_PRINT(("%s: slot %d\n", __func__, xfer->c_slot),
+		    DEBUG_FUNCS|DEBUG_XFERS);
+
+		if (ata_timo_xfer_check(xfer)) {
+			/* Already logged */
+			continue;
+		}
+
+		/* Mark as timed out. Do not print anything, wd(4) will. */
+		xfer->c_flags |= C_TIMEOU;
+		xfer->c_intr(xfer->c_chp, xfer, 0);
+	}
+
+	splx(s);
+}
+
 /*
  * Must be called without any locks, i.e. with both drive and channel locks
  * released.

Index: src/sys/dev/ata/ata_wdc.c
diff -u src/sys/dev/ata/ata_wdc.c:1.110 src/sys/dev/ata/ata_wdc.c:1.110.4.1
--- src/sys/dev/ata/ata_wdc.c:1.110	Fri Jun  1 18:13:30 2018
+++ src/sys/dev/ata/ata_wdc.c	Fri Aug 31 19:08:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata_wdc.c,v 1.110 2018/06/01 18:13:30 macallan Exp $	*/
+/*	$NetBSD: ata_wdc.c,v 1.110.4.1 2018/08/31 19:08:03 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001, 2003 Manuel Bouyer.
@@ -54,7 +54,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.110 2018/06/01 18:13:30 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.110.4.1 2018/08/31 19:08:03 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wdc.h"
@@ -479,8 +479,8 @@ _wdc_ata_bio_start(struct ata_channel *c
 			chp->ch_flags |= ATACH_DMA_WAIT;
 			/* start timeout machinery */
 			if ((xfer->c_flags & C_POLL) == 0)
-				callout_reset(&xfer->c_timo_callout,
-				    ATA_DELAY / 1000 * hz, wdctimeout, xfer);
+				callout_reset(&chp->c_timo_callout,
+				    ATA_DELAY / 1000 * hz, wdctimeout, chp);
 			/* wait for irq */
 			goto intr;
 		} /* else not DMA */
@@ -550,8 +550,8 @@ _wdc_ata_bio_start(struct ata_channel *c
 		}
 		/* start timeout machinery */
 		if ((xfer->c_flags & C_POLL) == 0)
-			callout_reset(&xfer->c_timo_callout,
-			    ATA_DELAY / 1000 * hz, wdctimeout, xfer);
+			callout_reset(&chp->c_timo_callout,
+			    ATA_DELAY / 1000 * hz, wdctimeout, chp);
 	} else if (ata_bio->nblks > 1) {
 		/* The number of blocks in the last stretch may be smaller. */
 		nblks = xfer->c_bcount / drvp->lp->d_secsize;

Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.99 src/sys/dev/ata/atavar.h:1.99.2.1
--- src/sys/dev/ata/atavar.h:1.99	Fri Aug 10 22:43:22 2018
+++ src/sys/dev/ata/atavar.h	Fri Aug 31 19:08:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: atavar.h,v 1.99 2018/08/10 22:43:22 jdolecek Exp $	*/
+/*	$NetBSD: atavar.h,v 1.99.2.1 2018/08/31 19:08:03 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -131,10 +131,6 @@ struct scsipi_xfer;
  * commands are queued in a list.
  */
 struct ata_xfer {
-	struct callout c_timo_callout;	/* timeout callout handle */
-	struct callout c_retry_callout;	/* retry callout handle */
-	kcondvar_t c_active;		/* somebody actively waiting for xfer */
-	kcondvar_t c_finish;		/* somebody waiting for xfer finish */
 	int8_t c_slot;			/* queue slot # */
 
 #define c_startzero	c_chp
@@ -166,6 +162,9 @@ struct ata_xfer {
 	TAILQ_ENTRY(ata_xfer) c_xferchain;
 	TAILQ_ENTRY(ata_xfer) c_activechain;
 
+	/* Links for error handling */
+	SLIST_ENTRY(ata_xfer) c_retrychain;
+
 	/* Low-level protocol handlers. */
 	int	(*c_start)(struct ata_channel *, struct ata_xfer *);
 #define ATASTART_STARTED	0	/* xfer started, waiting for intr */
@@ -227,6 +226,8 @@ struct ata_queue {
 	TAILQ_HEAD(, ata_xfer) active_xfers; 	/* active commands */
 	uint32_t active_xfers_used;		/* mask of active commands */
 	uint32_t queue_xfers_avail;		/* available xfers mask */
+	kcondvar_t c_active;		/* somebody actively waiting for xfer */
+	kcondvar_t c_cmd_finish;	/* somebody waiting for cmd finish */
 	struct ata_xfer queue_xfers[0];		/* xfers */
 };
 #endif
@@ -412,6 +413,9 @@ struct ata_channel {
 	/* for the reset callback */
 	int ch_reset_flags;
 
+	/* for the timeout callout */
+	struct callout c_timo_callout;	/* timeout callout handle */
+
 	/* per-drive info */
 	int ch_ndrives; /* number of entries in ch_drive[] */
 	struct ata_drive_datas *ch_drive; /* array of ata_drive_datas */
@@ -528,8 +532,7 @@ void	ata_free_xfer(struct ata_channel *,
 void	ata_deactivate_xfer(struct ata_channel *, struct ata_xfer *);
 void	ata_exec_xfer(struct ata_channel *, struct ata_xfer *);
 int	ata_xfer_start(struct ata_xfer *xfer);
-void	ata_wait_xfer(struct ata_channel *, struct ata_xfer *xfer);
-void	ata_wake_xfer(struct ata_channel *, struct ata_xfer *xfer);
+void	ata_wait_cmd(struct ata_channel *, struct ata_xfer *xfer);
 
 void	ata_timeout(void *);
 bool	ata_timo_xfer_check(struct ata_xfer *);

Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.441 src/sys/dev/ata/wd.c:1.441.2.1
--- src/sys/dev/ata/wd.c:1.441	Fri Aug 10 22:43:22 2018
+++ src/sys/dev/ata/wd.c	Fri Aug 31 19:08:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: wd.c,v 1.441 2018/08/10 22:43:22 jdolecek Exp $ */
+/*	$NetBSD: wd.c,v 1.441.2.1 2018/08/31 19:08:03 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.441 2018/08/10 22:43:22 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.441.2.1 2018/08/31 19:08:03 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wd.h"
@@ -199,7 +199,8 @@ static int	wd_diskstart(device_t, struct
 static int	wd_dumpblocks(device_t, void *, daddr_t, int);
 static void	wd_iosize(device_t, int *);
 static int	wd_discard(device_t, off_t, off_t);
-static void	wdbiorestart(void *);
+static void	wdbioretry(void *);
+static void	wdbiorequeue(void *);
 static void	wddone(device_t, struct ata_xfer *);
 static int	wd_get_params(struct wd_softc *, uint8_t, struct ataparams *);
 static void	wd_set_geometry(struct wd_softc *);
@@ -329,6 +330,11 @@ wdattach(device_t parent, device_t self,
 	wd->drvp->drv_softc = dksc->sc_dev; /* done in atabusconfig_thread()
 					     but too late */
 
+	SLIST_INIT(&wd->sc_retry_list);
+	SLIST_INIT(&wd->sc_requeue_list);
+	callout_init(&wd->sc_retry_callout, 0);		/* XXX MPSAFE */
+	callout_init(&wd->sc_requeue_callout, 0);	/* XXX MPSAFE */
+
 	aprint_naive("\n");
 	aprint_normal("\n");
 
@@ -517,6 +523,12 @@ wddetach(device_t self, int flags)
 	/* Kill off any pending commands. */
 	mutex_enter(&wd->sc_lock);
 	wd->atabus->ata_killpending(wd->drvp);
+
+	callout_halt(&wd->sc_retry_callout, &wd->sc_lock);
+	callout_destroy(&wd->sc_retry_callout);
+	callout_halt(&wd->sc_requeue_callout, &wd->sc_lock);
+	callout_destroy(&wd->sc_requeue_callout);
+
 	mutex_exit(&wd->sc_lock);
 
 	bufq_free(dksc->sc_bufq);
@@ -850,9 +862,17 @@ retry2:
 			xfer->c_retries++;
 
 			/* Rerun ASAP if just requeued */
-			callout_reset(&xfer->c_retry_callout,
-			    (xfer->c_bio.error == REQUEUE) ? 1 : RECOVERYTIME,
-			    wdbiorestart, xfer);
+			if (xfer->c_bio.error == REQUEUE) {
+				SLIST_INSERT_HEAD(&wd->sc_requeue_list, xfer,
+				    c_retrychain);
+				callout_reset(&wd->sc_requeue_callout,
+				    1, wdbiorequeue, wd);
+			} else {
+				SLIST_INSERT_HEAD(&wd->sc_retry_list, xfer,
+				    c_retrychain);
+				callout_reset(&wd->sc_retry_callout,
+				    RECOVERYTIME, wdbioretry, wd);
+			}
 
 			mutex_exit(&wd->sc_lock);
 			return;
@@ -921,20 +941,36 @@ noerror:	if ((xfer->c_bio.flags & ATA_CO
 }
 
 static void
-wdbiorestart(void *v)
+wdbioretry(void *v)
 {
-	struct ata_xfer *xfer = v;
-	struct buf *bp = xfer->c_bio.bp;
-	struct wd_softc *wd = device_lookup_private(&wd_cd, WDUNIT(bp->b_dev));
-#ifdef ATADEBUG
-	struct dk_softc *dksc = &wd->sc_dksc;
-#endif
+	struct wd_softc *wd = v;
+	struct ata_xfer *xfer;
 
-	ATADEBUG_PRINT(("wdbiorestart %s\n", dksc->sc_xname),
+	ATADEBUG_PRINT(("%s %s\n", __func__, wd->sc_dksc.sc_xname),
 	    DEBUG_XFERS);
 
 	mutex_enter(&wd->sc_lock);
-	wdstart1(wd, bp, xfer);
+	while ((xfer = SLIST_FIRST(&wd->sc_retry_list))) {
+		SLIST_REMOVE_HEAD(&wd->sc_retry_list, c_retrychain);
+		wdstart1(wd, xfer->c_bio.bp, xfer);
+	}
+	mutex_exit(&wd->sc_lock);
+}
+
+static void
+wdbiorequeue(void *v)
+{
+	struct wd_softc *wd = v;
+	struct ata_xfer *xfer;
+
+	ATADEBUG_PRINT(("%s %s\n", __func__, wd->sc_dksc.sc_xname),
+	    DEBUG_XFERS);
+
+	mutex_enter(&wd->sc_lock);
+	while ((xfer = SLIST_FIRST(&wd->sc_requeue_list))) {
+		SLIST_REMOVE_HEAD(&wd->sc_requeue_list, c_retrychain);
+		wdstart1(wd, xfer->c_bio.bp, xfer);
+	}
 	mutex_exit(&wd->sc_lock);
 }
 

Index: src/sys/dev/ata/wdvar.h
diff -u src/sys/dev/ata/wdvar.h:1.46 src/sys/dev/ata/wdvar.h:1.46.6.1
--- src/sys/dev/ata/wdvar.h:1.46	Fri Nov  3 13:01:26 2017
+++ src/sys/dev/ata/wdvar.h	Fri Aug 31 19:08:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdvar.h,v 1.46 2017/11/03 13:01:26 mlelstv Exp $	*/
+/*	$NetBSD: wdvar.h,v 1.46.6.1 2018/08/31 19:08:03 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -65,6 +65,13 @@ struct wd_softc {
 	u_int sc_bscount;
 #endif
 
+	/* Retry/requeue failed transfers */
+	SLIST_HEAD(, ata_xfer) sc_retry_list;
+	struct callout sc_retry_callout;	/* retry callout handle */
+
+	SLIST_HEAD(, ata_xfer) sc_requeue_list;
+	struct callout sc_requeue_callout;	/* requeue callout handle */
+
 	/* Sysctl nodes specific for the disk */
 	struct sysctllog *nodelog;
 	int drv_max_tags;

Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.62 src/sys/dev/ic/ahcisata_core.c:1.62.2.1
--- src/sys/dev/ic/ahcisata_core.c:1.62	Mon Jul  9 10:44:44 2018
+++ src/sys/dev/ic/ahcisata_core.c	Fri Aug 31 19:08:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisata_core.c,v 1.62 2018/07/09 10:44:44 kamil Exp $	*/
+/*	$NetBSD: ahcisata_core.c,v 1.62.2.1 2018/08/31 19:08:03 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.62 2018/07/09 10:44:44 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.62.2.1 2018/08/31 19:08:03 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -1038,12 +1038,7 @@ ahci_exec_command(struct ata_drive_datas
 		ret = ATACMD_COMPLETE;
 	} else {
 		if (ata_c->flags & AT_WAIT) {
-			ata_channel_lock(chp);
-			if ((ata_c->flags & AT_DONE) == 0) {
-				ata_wait_xfer(chp, xfer);
-				KASSERT((ata_c->flags & AT_DONE) != 0);
-			}
-			ata_channel_unlock(chp);
+			ata_wait_cmd(chp, xfer);
 			ret = ATACMD_COMPLETE;
 		} else {
 			ret = ATACMD_QUEUED;
@@ -1107,8 +1102,8 @@ ahci_cmd_start(struct ata_channel *chp, 
 	achp->ahcic_cmds_active |= 1U << slot;
 
 	if ((ata_c->flags & AT_POLL) == 0) {
-		callout_reset(&xfer->c_timo_callout, mstohz(ata_c->timeout),
-		    ata_timeout, xfer);
+		callout_reset(&chp->c_timo_callout, mstohz(ata_c->timeout),
+		    ata_timeout, chp);
 		return ATASTART_STARTED;
 	} else
 		return ATASTART_POLL;
@@ -1187,13 +1182,13 @@ ahci_cmd_kill_xfer(struct ata_channel *c
 		panic("ahci_cmd_kill_xfer");
 	}
 
+	ahci_cmd_done_end(chp, xfer);
+
 	if (deactivate) {
 		KASSERT((achp->ahcic_cmds_active & (1U << xfer->c_slot)) != 0);
 		achp->ahcic_cmds_active &= ~(1U << xfer->c_slot);
 		ata_deactivate_xfer(chp, xfer);
 	}
-
-	ahci_cmd_done_end(chp, xfer);
 }
 
 static int
@@ -1213,7 +1208,6 @@ ahci_cmd_complete(struct ata_channel *ch
 
 	KASSERT((achp->ahcic_cmds_active & (1U << xfer->c_slot)) != 0);
 	achp->ahcic_cmds_active &= ~(1U << xfer->c_slot);
-	ata_deactivate_xfer(chp, xfer);
 
 	if (xfer->c_flags & C_TIMEOU) {
 		ata_c->flags |= AT_TIMEOU;
@@ -1230,6 +1224,9 @@ ahci_cmd_complete(struct ata_channel *ch
 		satafis_rdh_cmd_readreg(ata_c, achp->ahcic_rfis->rfis_rfis);
 
 	ahci_cmd_done(chp, xfer);
+
+	ata_deactivate_xfer(chp, xfer);
+
 	return 0;
 }
 
@@ -1268,7 +1265,9 @@ ahci_cmd_done(struct ata_channel *chp, s
 
 	if (achp->ahcic_cmdh[xfer->c_slot].cmdh_prdbc)
 		ata_c->flags |= AT_XFDONE;
+
 	ahci_cmd_done_end(chp, xfer);
+
 	if ((flags & (AT_TIMEOU|AT_ERROR)) == 0)
 		atastart(chp);
 }
@@ -1278,15 +1277,7 @@ ahci_cmd_done_end(struct ata_channel *ch
 {
 	struct ata_command *ata_c = &xfer->c_ata_c;
 
-	ata_channel_lock(chp);
-
 	ata_c->flags |= AT_DONE;
-
-	if (ata_c->flags & AT_WAIT)
-		ata_wake_xfer(chp, xfer);
-
-	ata_channel_unlock(chp);
-	return;
 }
 
 static int
@@ -1363,8 +1354,8 @@ ahci_bio_start(struct ata_channel *chp, 
 	achp->ahcic_cmds_active |= 1U << xfer->c_slot;
 
 	if ((xfer->c_flags & C_POLL) == 0) {
-		callout_reset(&xfer->c_timo_callout, mstohz(ATA_DELAY),
-		    ata_timeout, xfer);
+		callout_reset(&chp->c_timo_callout, mstohz(ATA_DELAY),
+		    ata_timeout, chp);
 		return ATASTART_STARTED;
 	} else
 		return ATASTART_POLL;
@@ -1948,8 +1939,8 @@ ahci_atapi_start(struct ata_channel *chp
 	achp->ahcic_cmds_active |= 1U << xfer->c_slot;
 
 	if ((xfer->c_flags & C_POLL) == 0) {
-		callout_reset(&xfer->c_timo_callout, mstohz(sc_xfer->timeout),
-		    ata_timeout, xfer);
+		callout_reset(&chp->c_timo_callout, mstohz(sc_xfer->timeout),
+		    ata_timeout, chp);
 		return ATASTART_STARTED;
 	} else
 		return ATASTART_POLL;

Index: src/sys/dev/ic/mvsata.c
diff -u src/sys/dev/ic/mvsata.c:1.41 src/sys/dev/ic/mvsata.c:1.41.2.1
--- src/sys/dev/ic/mvsata.c:1.41	Fri Aug 31 18:43:29 2018
+++ src/sys/dev/ic/mvsata.c	Fri Aug 31 19:08:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: mvsata.c,v 1.41 2018/08/31 18:43:29 jdolecek Exp $	*/
+/*	$NetBSD: mvsata.c,v 1.41.2.1 2018/08/31 19:08:03 jdolecek Exp $	*/
 /*
  * Copyright (c) 2008 KIYOHARA Takashi
  * All rights reserved.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.41 2018/08/31 18:43:29 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.41.2.1 2018/08/31 19:08:03 jdolecek Exp $");
 
 #include "opt_mvsata.h"
 
@@ -159,7 +159,6 @@ static void mvsata_atapi_polldsc(void *)
 static int mvsata_edma_enqueue(struct mvsata_port *, struct ata_xfer *);
 static int mvsata_edma_handle(struct mvsata_port *, struct ata_xfer *);
 static int mvsata_edma_wait(struct mvsata_port *, struct ata_xfer *, int);
-static void mvsata_edma_timeout(void *);
 static void mvsata_edma_rqq_remove(struct mvsata_port *, struct ata_xfer *);
 #if NATAPIBUS > 0
 static int mvsata_bdma_init(struct mvsata_port *, struct ata_xfer *);
@@ -1214,9 +1213,8 @@ mvsata_bio_start(struct ata_channel *chp
 			chp->ch_flags |= ATACH_DMA_WAIT;
 			/* start timeout machinery */
 			if ((xfer->c_flags & C_POLL) == 0)
-				callout_reset(&xfer->c_timo_callout,
-				    mstohz(ATA_DELAY),
-				    mvsata_edma_timeout, xfer);
+				callout_reset(&chp->c_timo_callout,
+				    mstohz(ATA_DELAY), ata_timeout, chp);
 			/* wait for irq */
 			goto intr;
 		} /* else not DMA */
@@ -1300,8 +1298,8 @@ do_pio:
 
 		/* start timeout machinery */
 		if ((xfer->c_flags & C_POLL) == 0)
-			callout_reset(&xfer->c_timo_callout,
-			    mstohz(ATA_DELAY), wdctimeout, xfer);
+			callout_reset(&chp->c_timo_callout,
+			    mstohz(ATA_DELAY), wdctimeout, chp);
 	} else if (ata_bio->nblks > 1) {
 		/* The number of blocks in the last stretch may be smaller. */
 		nblks = xfer->c_bcount / drvp->lp->d_secsize;
@@ -1382,6 +1380,11 @@ mvsata_bio_intr(struct ata_channel *chp,
 	    device_xname(atac->atac_dev), chp->ch_channel, __func__,
 	    xfer->c_drive));
 
+	if (xfer->c_flags & C_TIMEOU && !irq) {
+		/* Cleanup EDMA if invoked from timeout handler */
+		mvsata_edma_rqq_remove((struct mvsata_port *)chp, xfer);
+	}
+
 	ata_channel_lock(chp);
 
 	chp->ch_flags &= ~(ATACH_DMA_WAIT);
@@ -1712,12 +1715,7 @@ mvsata_exec_command(struct ata_drive_dat
 		rv = ATACMD_COMPLETE;
 	else {
 		if (ata_c->flags & AT_WAIT) {
-			ata_channel_lock(chp);
-			if ((ata_c->flags & AT_DONE) == 0) {
-				ata_wait_xfer(chp, xfer);
-				KASSERT((ata_c->flags & AT_DONE) != 0);
-			}
-			ata_channel_unlock(chp);
+			ata_wait_cmd(chp, xfer);
 			rv = ATACMD_COMPLETE;
 		} else
 			rv = ATACMD_QUEUED;
@@ -1779,8 +1777,8 @@ mvsata_wdc_cmd_start(struct ata_channel 
 	}
 
 	if ((ata_c->flags & AT_POLL) == 0) {
-		callout_reset(&xfer->c_timo_callout, ata_c->timeout / 1000 * hz,
-		    wdctimeout, xfer);
+		callout_reset(&chp->c_timo_callout, ata_c->timeout / 1000 * hz,
+		    wdctimeout, chp);
 		return ATASTART_STARTED;
 	}
 
@@ -1895,8 +1893,8 @@ again:
 		wdc->dataout_pio(chp, drive_flags, data, bcount);
 		ata_c->flags |= AT_XFDONE;
 		if ((ata_c->flags & AT_POLL) == 0) {
-			callout_reset(&xfer->c_timo_callout,
-			    mstohz(ata_c->timeout), wdctimeout, xfer);
+			callout_reset(&chp->c_timo_callout,
+			    mstohz(ata_c->timeout), wdctimeout, chp);
 			ata_channel_unlock(chp);
 			return 1;
 		} else
@@ -1949,12 +1947,12 @@ mvsata_wdc_cmd_kill_xfer(struct ata_chan
 		panic("mvsata_cmd_kill_xfer");
 	}
 
+	mvsata_wdc_cmd_done_end(chp, xfer);
+
 	if (deactivate) {
 		mvsata_quetag_put(mvport, xfer->c_slot);
 		ata_deactivate_xfer(chp, xfer);
 	}
-
-	mvsata_wdc_cmd_done_end(chp, xfer);
 }
 
 static void
@@ -2015,7 +2013,6 @@ mvsata_wdc_cmd_done(struct ata_channel *
 	}
 
 	mvsata_quetag_put(mvport, xfer->c_slot);
-	ata_deactivate_xfer(chp, xfer);
 
 	if (ata_c->flags & AT_POLL) {
 		/* enable interrupts */
@@ -2024,6 +2021,8 @@ mvsata_wdc_cmd_done(struct ata_channel *
 	}
 
 	mvsata_wdc_cmd_done_end(chp, xfer);
+
+	ata_deactivate_xfer(chp, xfer);
 }
 
 static void
@@ -2038,11 +2037,7 @@ mvsata_wdc_cmd_done_end(struct ata_chann
 		mvsata_edma_enable(mvport);
 	}
 
-	ata_channel_lock(chp);
 	ata_c->flags |= AT_DONE;
-	if (ata_c->flags & AT_WAIT)
-		ata_wake_xfer(chp, xfer);
-	ata_channel_unlock(chp);
 }
 
 #if NATAPIBUS > 0
@@ -2224,8 +2219,8 @@ ready:
 	}
 	/* start timeout machinery */
 	if ((sc_xfer->xs_control & XS_CTL_POLL) == 0)
-		callout_reset(&xfer->c_timo_callout, mstohz(sc_xfer->timeout),
-		    wdctimeout, xfer);
+		callout_reset(&chp->c_timo_callout, mstohz(sc_xfer->timeout),
+		    wdctimeout, chp);
 
 	MVSATA_WDC_WRITE_1(mvport, SRB_H, WDSD_IBM);
 	if (wdc_wait_for_unbusy(chp, ATAPI_DELAY, wait_flags, &tfd) != 0) {
@@ -2633,8 +2628,8 @@ mvsata_atapi_phase_complete(struct ata_x
 				sc_xfer->error = XS_TIMEOUT;
 				mvsata_atapi_reset(chp, xfer);
 			} else {
-				callout_reset(&xfer->c_timo_callout, 1,
-				    mvsata_atapi_polldsc, xfer);
+				callout_reset(&chp->c_timo_callout, 1,
+				    mvsata_atapi_polldsc, chp);
 				ata_channel_unlock(chp);
 			}
 			return;
@@ -2727,8 +2722,10 @@ mvsata_atapi_done(struct ata_channel *ch
 static void
 mvsata_atapi_polldsc(void *arg)
 {
-	struct ata_xfer *xfer = arg;
-	struct ata_channel *chp = xfer->c_chp;
+	struct ata_channel *chp = arg;
+	struct ata_xfer *xfer = ata_queue_get_active_xfer(chp);
+
+	KASSERT(xfer != NULL);
 
 	ata_channel_lock(chp);
 
@@ -2967,30 +2964,6 @@ mvsata_edma_wait(struct mvsata_port *mvp
 }
 
 static void
-mvsata_edma_timeout(void *arg)
-{
-	struct ata_xfer *xfer = (struct ata_xfer *)arg;
-	struct ata_channel *chp = xfer->c_chp;
-	struct mvsata_port *mvport = (struct mvsata_port *)chp;
-	int s;
-
-	s = splbio();
-	DPRINTF(DEBUG_FUNCS, ("%s: %p\n", __func__, xfer));
-
-	if (ata_timo_xfer_check(xfer)) {
-		/* Already logged */
-		goto out;
-	}
-
-	mvsata_edma_rqq_remove(mvport, xfer);
-	xfer->c_flags |= C_TIMEOU;
-	mvsata_bio_intr(chp, xfer, 0);
-
-out:
-	splx(s);
-}
-
-static void
 mvsata_edma_rqq_remove(struct mvsata_port *mvport, struct ata_xfer *xfer)
 {
 	struct ata_channel *chp = &mvport->port_ata_channel;

Index: src/sys/dev/ic/siisata.c
diff -u src/sys/dev/ic/siisata.c:1.35 src/sys/dev/ic/siisata.c:1.35.6.1
--- src/sys/dev/ic/siisata.c:1.35	Fri Oct 20 07:06:07 2017
+++ src/sys/dev/ic/siisata.c	Fri Aug 31 19:08:03 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.35 2017/10/20 07:06:07 jdolecek Exp $ */
+/* $NetBSD: siisata.c,v 1.35.6.1 2018/08/31 19:08:03 jdolecek Exp $ */
 
 /* from ahcisata_core.c */
 
@@ -79,7 +79,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.35 2017/10/20 07:06:07 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.35.6.1 2018/08/31 19:08:03 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -1005,16 +1005,7 @@ siisata_exec_command(struct ata_drive_da
 		ret = ATACMD_COMPLETE;
 	} else {
 		if (ata_c->flags & AT_WAIT) {
-			ata_channel_lock(chp);
-			if ((ata_c->flags & AT_DONE) == 0) {
-				SIISATA_DEBUG_PRINT(("%s: %s: sleeping\n",
-				    SIISATANAME(
-				    (struct siisata_softc *)chp->ch_atac),
-				    __func__), DEBUG_FUNCS);
-				ata_wait_xfer(chp, xfer);
-				KASSERT((ata_c->flags & AT_DONE) != 0);
-			}
-			ata_channel_unlock(chp);
+			ata_wait_cmd(chp, xfer);
 			ret = ATACMD_COMPLETE;
 		} else {
 			ret = ATACMD_QUEUED;
@@ -1071,8 +1062,8 @@ siisata_cmd_start(struct ata_channel *ch
 	siisata_activate_prb(schp, xfer->c_slot);
 
 	if ((ata_c->flags & AT_POLL) == 0) {
-		callout_reset(&xfer->c_timo_callout, mstohz(ata_c->timeout),
-		    ata_timeout, xfer);
+		callout_reset(&chp->c_timo_callout, mstohz(ata_c->timeout),
+		    ata_timeout, chp);
 		return ATASTART_STARTED;
 	} else
 		return ATASTART_POLL;
@@ -1137,12 +1128,12 @@ siisata_cmd_kill_xfer(struct ata_channel
 		   __func__, chp->ch_channel, reason);
 	}
 
+	siisata_cmd_done_end(chp, xfer);
+
 	if (deactivate) {
 		siisata_deactivate_prb(schp, xfer->c_slot);
 		ata_deactivate_xfer(chp, xfer);
 	}
-	
-	siisata_cmd_done_end(chp, xfer);
 }
 
 int
@@ -1164,7 +1155,6 @@ siisata_cmd_complete(struct ata_channel 
 		return 0;
 
 	siisata_deactivate_prb(schp, xfer->c_slot);
-	ata_deactivate_xfer(chp, xfer);
 
 	if (xfer->c_flags & C_TIMEOU)
 		ata_c->flags |= AT_TIMEOU;
@@ -1178,6 +1168,8 @@ siisata_cmd_complete(struct ata_channel 
 
 	siisata_cmd_done(chp, xfer, tfd);
 
+	ata_deactivate_xfer(chp, xfer);
+
 	return 0;
 }
 
@@ -1229,15 +1221,7 @@ siisata_cmd_done_end(struct ata_channel 
 {
 	struct ata_command *ata_c = &xfer->c_ata_c;
 
-	ata_channel_lock(chp);
-
 	ata_c->flags |= AT_DONE;
-
-	if (ata_c->flags & AT_WAIT)
-		ata_wake_xfer(chp, xfer);
-
-	ata_channel_unlock(chp);
-	return;
 }
 
 int
@@ -1303,8 +1287,8 @@ siisata_bio_start(struct ata_channel *ch
 	siisata_activate_prb(schp, xfer->c_slot);
 
 	if ((ata_bio->flags & ATA_POLL) == 0) {
-		callout_reset(&xfer->c_timo_callout, mstohz(ATA_DELAY),
-		    ata_timeout, xfer);
+		callout_reset(&chp->c_timo_callout, mstohz(ATA_DELAY),
+		    ata_timeout, chp);
 		return ATASTART_STARTED;
 	} else
 		return ATASTART_POLL;
@@ -1913,8 +1897,8 @@ siisata_atapi_start(struct ata_channel *
 	siisata_activate_prb(schp, xfer->c_slot);
 
 	if ((xfer->c_flags & C_POLL) == 0) {
-		callout_reset(&xfer->c_timo_callout, mstohz(sc_xfer->timeout),
-		    ata_timeout, xfer);
+		callout_reset(&chp->c_timo_callout, mstohz(sc_xfer->timeout),
+		    ata_timeout, chp);
 		return ATASTART_STARTED;
 	} else
 		return ATASTART_POLL;

Index: src/sys/dev/ic/wdc.c
diff -u src/sys/dev/ic/wdc.c:1.288 src/sys/dev/ic/wdc.c:1.288.6.1
--- src/sys/dev/ic/wdc.c:1.288	Fri Oct 20 07:06:07 2017
+++ src/sys/dev/ic/wdc.c	Fri Aug 31 19:08:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdc.c,v 1.288 2017/10/20 07:06:07 jdolecek Exp $ */
+/*	$NetBSD: wdc.c,v 1.288.6.1 2018/08/31 19:08:03 jdolecek Exp $ */
 
 /*
  * Copyright (c) 1998, 2001, 2003 Manuel Bouyer.  All rights reserved.
@@ -58,7 +58,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.288 2017/10/20 07:06:07 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.288.6.1 2018/08/31 19:08:03 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wdc.h"
@@ -1324,8 +1324,8 @@ wdc_dmawait(struct ata_channel *chp, str
 void
 wdctimeout(void *arg)
 {
-	struct ata_xfer *xfer = arg;
-	struct ata_channel *chp = xfer->c_chp;
+	struct ata_xfer *xfer;
+	struct ata_channel *chp = arg;
 #if NATA_DMA || NATA_PIOBM
 	struct wdc_softc *wdc = CHAN_TO_WDC(chp);
 #endif
@@ -1334,6 +1334,10 @@ wdctimeout(void *arg)
 	ATADEBUG_PRINT(("wdctimeout\n"), DEBUG_FUNCS);
 
 	s = splbio();
+
+	callout_ack(&chp->c_timo_callout);
+
+	xfer = ata_queue_get_active_xfer(chp);
 	KASSERT(xfer != NULL);
 
 	if (ata_timo_xfer_check(xfer)) {
@@ -1361,7 +1365,7 @@ wdctimeout(void *arg)
 	 * in case it will miss another irq while in this transfer
 	 * We arbitray chose it to be 1s
 	 */
-	callout_reset(&xfer->c_timo_callout, hz, wdctimeout, xfer);
+	callout_reset(&chp->c_timo_callout, hz, wdctimeout, chp);
 	xfer->c_flags |= C_TIMEOU;
 	KASSERT(xfer->c_intr != NULL);
 	xfer->c_intr(chp, xfer, 1);
@@ -1408,12 +1412,7 @@ wdc_exec_command(struct ata_drive_datas 
 		ret = ATACMD_COMPLETE;
 	} else {
 		if (ata_c->flags & AT_WAIT) {
-			ata_channel_lock(chp);
-			if ((ata_c->flags & AT_DONE) == 0) {
-				ata_wait_xfer(chp, xfer);
-				KASSERT((ata_c->flags & AT_DONE) != 0);
-			}
-			ata_channel_unlock(chp);
+			ata_wait_cmd(chp, xfer);
 			ret = ATACMD_COMPLETE;
 		} else {
 			ret = ATACMD_QUEUED;
@@ -1474,8 +1473,8 @@ __wdccommand_start(struct ata_channel *c
 
 	if ((ata_c->flags & AT_POLL) == 0) {
 		chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
-		callout_reset(&xfer->c_timo_callout, ata_c->timeout / 1000 * hz,
-		    wdctimeout, xfer);
+		callout_reset(&chp->c_timo_callout, ata_c->timeout / 1000 * hz,
+		    wdctimeout, chp);
 		return ATASTART_STARTED;
 	}
 
@@ -1597,8 +1596,8 @@ again:
 		ata_c->flags |= AT_XFDONE;
 		if ((ata_c->flags & AT_POLL) == 0) {
 			chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */
-			callout_reset(&xfer->c_timo_callout,
-			    mstohz(ata_c->timeout), wdctimeout, xfer);
+			callout_reset(&chp->c_timo_callout,
+			    mstohz(ata_c->timeout), wdctimeout, chp);
 			ata_channel_unlock(chp);
 			return 1;
 		} else {
@@ -1691,10 +1690,10 @@ __wdccommand_done(struct ata_channel *ch
 		ata_c->r_device &= 0xf0;
 	}
 
-	ata_deactivate_xfer(chp, xfer);
-
 	__wdccommand_done_end(chp, xfer);
 
+	ata_deactivate_xfer(chp, xfer);
+
 out:
 	if (ata_c->flags & AT_POLL) {
 		/* enable interrupts */
@@ -1713,11 +1712,7 @@ __wdccommand_done_end(struct ata_channel
 {
 	struct ata_command *ata_c = &xfer->c_ata_c;
 
-	ata_channel_lock(chp);
 	ata_c->flags |= AT_DONE;
-	if (ata_c->flags & AT_WAIT)
-		ata_wake_xfer(chp, xfer);
-	ata_channel_unlock(chp);
 }
 
 static void
@@ -1743,10 +1738,10 @@ __wdccommand_kill_xfer(struct ata_channe
 		panic("__wdccommand_kill_xfer");
 	}
 
+	__wdccommand_done_end(chp, xfer);
+
 	if (deactivate)
 		ata_deactivate_xfer(chp, xfer);
-
-	__wdccommand_done_end(chp, xfer);
 }
 
 /*

Index: src/sys/dev/scsipi/atapi_wdc.c
diff -u src/sys/dev/scsipi/atapi_wdc.c:1.129 src/sys/dev/scsipi/atapi_wdc.c:1.129.6.1
--- src/sys/dev/scsipi/atapi_wdc.c:1.129	Tue Oct 17 18:52:51 2017
+++ src/sys/dev/scsipi/atapi_wdc.c	Fri Aug 31 19:08:03 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: atapi_wdc.c,v 1.129 2017/10/17 18:52:51 jdolecek Exp $	*/
+/*	$NetBSD: atapi_wdc.c,v 1.129.6.1 2018/08/31 19:08:03 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.129 2017/10/17 18:52:51 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.129.6.1 2018/08/31 19:08:03 jdolecek Exp $");
 
 #ifndef ATADEBUG
 #define ATADEBUG
@@ -595,8 +595,8 @@ ready:
 	}
 	/* start timeout machinery */
 	if ((sc_xfer->xs_control & XS_CTL_POLL) == 0)
-		callout_reset(&xfer->c_timo_callout, mstohz(sc_xfer->timeout),
-		    wdctimeout, xfer);
+		callout_reset(&chp->c_timo_callout, mstohz(sc_xfer->timeout),
+		    wdctimeout, chp);
 
 	if (wdc->select)
 		wdc->select(chp, xfer->c_drive);
@@ -1087,8 +1087,8 @@ wdc_atapi_phase_complete(struct ata_xfer
 				sc_xfer->error = XS_TIMEOUT;
 				wdc_atapi_reset(chp, xfer);
 			} else {
-				callout_reset(&xfer->c_timo_callout, 1,
-				    wdc_atapi_polldsc, xfer);
+				callout_reset(&chp->c_timo_callout, 1,
+				    wdc_atapi_polldsc, chp);
 				ata_channel_unlock(chp);
 			}
 			return;
@@ -1192,8 +1192,10 @@ wdc_atapi_reset(struct ata_channel *chp,
 static void
 wdc_atapi_polldsc(void *arg)
 {
-	struct ata_xfer *xfer = arg;
-	struct ata_channel *chp = xfer->c_chp;
+	struct ata_channel *chp = arg;
+	struct ata_xfer *xfer = ata_queue_get_active_xfer(chp);
+
+	KASSERT(xfer != NULL);
 
 	ata_channel_lock(chp);
 

Reply via email to