Module Name:    src
Committed By:   jdolecek
Date:           Mon Apr 10 22:57:03 UTC 2017

Modified Files:
        src/sys/dev/ata [jdolecek-ncq]: ata.c ata_wdc.c atavar.h
        src/sys/dev/ic [jdolecek-ncq]: ahcisata_core.c mvsata.c siisata.c wdc.c
        src/sys/dev/pci [jdolecek-ncq]: artsata.c cmdide.c cypide.c
            pciide_common.c pdcsata.c satalink.c viaide.c
        src/sys/dev/scsipi [jdolecek-ncq]: atapi_wdc.c

Log Message:
ATA infrastructure improvements to eventually support more outstanding
commands

patch by Matt Thomas


To generate a diff of this commit:
cvs rdiff -u -r1.132 -r1.132.8.1 src/sys/dev/ata/ata.c
cvs rdiff -u -r1.105 -r1.105.6.1 src/sys/dev/ata/ata_wdc.c
cvs rdiff -u -r1.92 -r1.92.8.1 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.57 -r1.57.6.1 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.35 -r1.35.6.1 src/sys/dev/ic/mvsata.c
cvs rdiff -u -r1.30 -r1.30.4.1 src/sys/dev/ic/siisata.c
cvs rdiff -u -r1.283 -r1.283.2.1 src/sys/dev/ic/wdc.c
cvs rdiff -u -r1.26 -r1.26.18.1 src/sys/dev/pci/artsata.c
cvs rdiff -u -r1.38 -r1.38.28.1 src/sys/dev/pci/cmdide.c
cvs rdiff -u -r1.30 -r1.30.18.1 src/sys/dev/pci/cypide.c
cvs rdiff -u -r1.62 -r1.62.4.1 src/sys/dev/pci/pciide_common.c
cvs rdiff -u -r1.27 -r1.27.18.1 src/sys/dev/pci/pdcsata.c
cvs rdiff -u -r1.53 -r1.53.4.1 src/sys/dev/pci/satalink.c
cvs rdiff -u -r1.84 -r1.84.18.1 src/sys/dev/pci/viaide.c
cvs rdiff -u -r1.123 -r1.123.4.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.132 src/sys/dev/ata/ata.c:1.132.8.1
--- src/sys/dev/ata/ata.c:1.132	Wed Sep 10 07:04:48 2014
+++ src/sys/dev/ata/ata.c	Mon Apr 10 22:57:02 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata.c,v 1.132 2014/09/10 07:04:48 matt Exp $	*/
+/*	$NetBSD: ata.c,v 1.132.8.1 2017/04/10 22:57:02 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.132 2014/09/10 07:04:48 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.1 2017/04/10 22:57:02 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -180,6 +180,56 @@ ataprint(void *aux, const char *pnp)
 	return (UNCONF);
 }
 
+static void
+ata_queue_reset(struct ata_queue *chq)
+{
+	/* make sure that we can use polled commands */
+	TAILQ_INIT(&chq->queue_xfer);
+	chq->queue_freeze = 0;
+	chq->queue_active = 0;
+	for (u_int i = 0; i < chq->queue_openings; i++) {
+		chq->active_xfers[0] = NULL;
+	}
+}
+
+struct ata_xfer *
+ata_queue_hwslot_to_xfer(struct ata_queue *chq, int hwslot)
+{
+	KASSERT(hwslot < chq->queue_openings);
+	if (chq->queue_openings == 1) {
+		struct ata_xfer *xfer = chq->active_xfers[0];
+		KASSERT(xfer == NULL || xfer->c_hwslot == hwslot);
+		return xfer;
+	}
+	for (u_int i = 0; i < chq->queue_openings; i++) {
+		struct ata_xfer *xfer = chq->active_xfers[i];
+		if (xfer != NULL && xfer->c_hwslot == hwslot) {
+			return xfer;
+		}
+	}
+	return NULL;
+}
+
+struct ata_queue *
+ata_queue_alloc(int openings)
+{
+	if (openings == 0)
+		openings = 1;
+	struct ata_queue *chq = malloc(offsetof(struct ata_queue, active_xfers[openings]),
+	    M_DEVBUF, M_WAITOK);
+	if (chq != NULL) {
+		chq->queue_openings = openings;
+		ata_queue_reset(chq);
+	}
+	return chq;
+}
+
+void
+ata_queue_free(struct ata_queue *chq)
+{
+	free(chq, M_DEVBUF);
+}
+
 /*
  * ata_channel_attach:
  *
@@ -188,6 +238,7 @@ ataprint(void *aux, const char *pnp)
 void
 ata_channel_attach(struct ata_channel *chp)
 {
+	struct ata_queue * const chq = chp->ch_queue;
 
 	if (chp->ch_flags & ATACH_DISABLED)
 		return;
@@ -195,10 +246,9 @@ ata_channel_attach(struct ata_channel *c
 	/* XXX callout_destroy */
 	callout_init(&chp->ch_callout, 0);
 
-	TAILQ_INIT(&chp->ch_queue->queue_xfer);
-	chp->ch_queue->queue_freeze = 0;
-	chp->ch_queue->queue_flags = 0;
-	chp->ch_queue->active_xfer = NULL;
+	chq->queue_openings = 1;	/* XXX */
+
+	ata_queue_reset(chq);
 
 	chp->atabus = config_found_ia(chp->ch_atac->atac_dev, "ata", chp,
 		atabusprint);
@@ -350,7 +400,7 @@ atabusconfig_thread(void *arg)
 		memset(&adev, 0, sizeof(struct ata_device));
 		adev.adev_bustype = atac->atac_bustype_ata;
 		adev.adev_channel = chp->ch_channel;
-		adev.adev_openings = 1;
+		adev.adev_openings = chp->ch_queue->queue_openings;
 		adev.adev_drv_data = &chp->ch_drive[i];
 		chp->ch_drive[i].drv_softc = config_found_ia(atabus_sc->sc_dev,
 		    "ata_hl", &adev, ataprint);
@@ -418,6 +468,7 @@ atabus_thread(void *arg)
 {
 	struct atabus_softc *sc = arg;
 	struct ata_channel *chp = sc->sc_chan;
+	struct ata_queue *chq = chp->ch_queue;
 	struct ata_xfer *xfer;
 	int i, s;
 
@@ -442,8 +493,7 @@ atabus_thread(void *arg)
 	s = splbio();
 	for (;;) {
 		if ((chp->ch_flags & (ATACH_TH_RESET | ATACH_SHUTDOWN)) == 0 &&
-		    (chp->ch_queue->active_xfer == NULL ||
-		     chp->ch_queue->queue_freeze == 0)) {
+		    (chq->queue_active == 0 || chq->queue_freeze == 0)) {
 			chp->ch_flags &= ~ATACH_TH_RUN;
 			(void) tsleep(&chp->ch_thread, PRIBIO, "atath", 0);
 			chp->ch_flags |= ATACH_TH_RUN;
@@ -460,18 +510,22 @@ atabus_thread(void *arg)
 			 * ata_reset_channel() will freeze 2 times, so
 			 * unfreeze one time. Not a problem as we're at splbio
 			 */
-			chp->ch_queue->queue_freeze--;
+			chq->queue_freeze--;
 			ata_reset_channel(chp, AT_WAIT | chp->ch_reset_flags);
-		} else if (chp->ch_queue->active_xfer != NULL &&
-			   chp->ch_queue->queue_freeze == 1) {
+		} else if (chq->queue_active > 0 && chq->queue_freeze == 1) {
 			/*
 			 * Caller has bumped queue_freeze, decrease it.
 			 */
-			chp->ch_queue->queue_freeze--;
-			xfer = chp->ch_queue->active_xfer;
-			KASSERT(xfer != NULL);
-			(*xfer->c_start)(xfer->c_chp, xfer);
-		} else if (chp->ch_queue->queue_freeze > 1)
+			chq->queue_freeze--;
+			u_int active __diagused = 0;
+			for (i = 0; i < chq->queue_openings; i++) {
+				if ((xfer = chq->active_xfers[i]) != NULL) {
+					(*xfer->c_start)(xfer->c_chp, xfer);
+					active++;
+				}
+			}
+			KASSERT(active == chq->queue_active);
+		} else if (chq->queue_freeze > 1)
 			panic("ata_thread: queue_freeze");
 	}
 	splx(s);
@@ -884,7 +938,7 @@ ata_queue_idle(struct ata_queue *queue)
 {
 	int s = splbio();
 	queue->queue_freeze++;
-	while (queue->active_xfer != NULL) {
+	while (queue->queue_active > 0) {
 		queue->queue_flags |= QF_IDLE_WAIT;
 		tsleep(&queue->queue_flags, PRIBIO, "qidl", 0);
 	}
@@ -905,16 +959,18 @@ ata_exec_xfer(struct ata_channel *chp, s
 
 	/* complete xfer setup */
 	xfer->c_chp = chp;
+	xfer->c_slot = 0;
 
 	/* insert at the end of command list */
 	TAILQ_INSERT_TAIL(&chp->ch_queue->queue_xfer, xfer, c_xferchain);
 	ATADEBUG_PRINT(("atastart from ata_exec_xfer, flags 0x%x\n",
 	    chp->ch_flags), DEBUG_XFERS);
+
 	/*
 	 * if polling and can sleep, wait for the xfer to be at head of queue
 	 */
 	if ((xfer->c_flags & (C_POLL | C_WAIT)) ==  (C_POLL | C_WAIT)) {
-		while (chp->ch_queue->active_xfer != NULL ||
+		while (chp->ch_queue->queue_active > 0 ||
 		    TAILQ_FIRST(&chp->ch_queue->queue_xfer) != xfer) {
 			xfer->c_flags |= C_WAITACT;
 			tsleep(xfer, PRIBIO, "ataact", 0);
@@ -939,6 +995,7 @@ void
 atastart(struct ata_channel *chp)
 {
 	struct atac_softc *atac = chp->ch_atac;
+	struct ata_queue *chq = chp->ch_queue;
 	struct ata_xfer *xfer;
 
 #ifdef ATA_DEBUG
@@ -954,23 +1011,31 @@ atastart(struct ata_channel *chp)
 	splx(spl1);
 #endif /* ATA_DEBUG */
 
+	if (chq->queue_active == chq->queue_openings) {
+		return; /* channel completely busy */
+	}
+
+	/* is the queue frozen? */
+	if (__predict_false(chq->queue_freeze > 0)) {
+		if (chq->queue_flags & QF_IDLE_WAIT) {
+			chq->queue_flags &= ~QF_IDLE_WAIT;
+			wakeup(&chq->queue_flags);
+		}
+		return; /* queue frozen */
+	}
+
 	/* is there a xfer ? */
 	if ((xfer = TAILQ_FIRST(&chp->ch_queue->queue_xfer)) == NULL)
 		return;
 
+	KASSERT(chp->ch_ndrives == 1 || chq->queue_openings == 1);
+
 	/* adjust chp, in case we have a shared queue */
 	chp = xfer->c_chp;
+	KASSERT(chp->ch_queue == chq);
+
+	struct ata_drive_datas * const drvp = &chp->ch_drive[xfer->c_drive];
 
-	if (chp->ch_queue->active_xfer != NULL) {
-		return; /* channel aleady active */
-	}
-	if (__predict_false(chp->ch_queue->queue_freeze > 0)) {
-		if (chp->ch_queue->queue_flags & QF_IDLE_WAIT) {
-			chp->ch_queue->queue_flags &= ~QF_IDLE_WAIT;
-			wakeup(&chp->ch_queue->queue_flags);
-		}
-		return; /* queue frozen */
-	}
 	/*
 	 * if someone is waiting for the command to be active, wake it up
 	 * and let it process the command
@@ -986,18 +1051,31 @@ atastart(struct ata_channel *chp)
 	if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0)
 		panic("atastart: channel waiting for irq");
 #endif
-	if (atac->atac_claim_hw)
+	if (atac->atac_claim_hw) {
 		if (!(*atac->atac_claim_hw)(chp, 0))
 			return;
+	}
 
 	ATADEBUG_PRINT(("atastart: xfer %p channel %d drive %d\n", xfer,
 	    chp->ch_channel, xfer->c_drive), DEBUG_XFERS);
-	if (chp->ch_drive[xfer->c_drive].drive_flags & ATA_DRIVE_RESET) {
-		chp->ch_drive[xfer->c_drive].drive_flags &= ~ATA_DRIVE_RESET;
-		chp->ch_drive[xfer->c_drive].state = 0;
+	if (drvp->drive_flags & ATA_DRIVE_RESET) {
+		drvp->drive_flags &= ~ATA_DRIVE_RESET;
+		drvp->state = 0;
+	}
+
+	if (chq->queue_openings == 1) {
+		xfer->c_slot = 0;
+		xfer->c_hwslot = 0;
+	} else {
+		for (u_int slot = 0; slot < chq->queue_openings; slot++) {
+			if (chq->active_xfers[slot] == NULL) {
+				xfer->c_slot = slot;
+				xfer->c_hwslot = slot;
+				break;
+			}
+		}
 	}
-	chp->ch_queue->active_xfer = xfer;
-	TAILQ_REMOVE(&chp->ch_queue->queue_xfer, xfer, c_xferchain);
+	ata_activate_xfer(chp, xfer);
 
 	if (atac->atac_cap & ATAC_CAP_NOIRQ)
 		KASSERT(xfer->c_flags & C_POLL);
@@ -1018,6 +1096,7 @@ ata_get_xfer(int flags)
 	if (xfer != NULL) {
 		memset(xfer, 0, sizeof(struct ata_xfer));
 	}
+	xfer->c_slot = -1;
 	return xfer;
 }
 
@@ -1052,6 +1131,82 @@ ata_free_xfer(struct ata_channel *chp, s
 	splx(s);
 }
 
+void
+ata_activate_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+	struct ata_queue * const chq = chp->ch_queue;
+
+	KASSERT(xfer->c_slot >= 0);
+	KASSERT(chq->queue_active < chq->queue_openings);
+	KASSERT(chq->active_xfers[xfer->c_slot] == NULL);
+
+	TAILQ_REMOVE(&chq->queue_xfer, xfer, c_xferchain);
+
+	chq->active_xfers[xfer->c_slot] = xfer;
+	chq->queue_active++;
+}
+
+void
+ata_deactivate_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+	struct ata_queue * const chq = chp->ch_queue;
+
+	KASSERT(xfer->c_slot >= 0);
+	KASSERT(chq->queue_active > 0);
+	KASSERT(chq->active_xfers[xfer->c_slot] == xfer);
+
+	//if ((xfer->c_flags & C_TIMEOU) == 0)
+	callout_stop(&chp->ch_callout);
+
+	chq->active_xfers[xfer->c_slot] = NULL;
+	chq->queue_active--;
+
+	xfer->c_slot = -1;
+}
+
+
+bool
+ata_waitdrain_check(struct ata_channel *chp, int drive)
+{
+	if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
+		chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
+		wakeup(chp->ch_queue->active_xfers);
+		return true;
+	}
+	return false;
+}
+
+bool
+ata_waitdrain_xfer_check(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+	int drive = xfer->c_drive;
+	if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
+		(*xfer->c_kill_xfer)(chp, xfer, KILL_GONE);
+		chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
+		wakeup(chp->ch_queue->active_xfers);
+		return true;
+	}
+	return false;
+}
+
+/*
+ * Kill off all active xfers for a ata_channel.
+ *
+ * Must be called at splbio().
+ */
+void
+ata_kill_active(struct ata_channel *chp, int reason)
+{
+	struct ata_queue * const chq = chp->ch_queue;
+	for (u_int i = 0;
+	     chq->queue_active > 0 && i < chq->queue_openings; i++) {
+		struct ata_xfer *xfer = chq->active_xfers[i];
+		if (xfer != NULL) {
+			(*xfer->c_kill_xfer)(xfer->c_chp, xfer, reason);
+		}
+	}
+}
+
 /*
  * Kill off all pending xfers for a ata_channel.
  *
@@ -1060,28 +1215,28 @@ ata_free_xfer(struct ata_channel *chp, s
 void
 ata_kill_pending(struct ata_drive_datas *drvp)
 {
-	struct ata_channel *chp = drvp->chnl_softc;
+	struct ata_channel * const chp = drvp->chnl_softc;
+	struct ata_queue * const chq = chp->ch_queue;
 	struct ata_xfer *xfer, *next_xfer;
 	int s = splbio();
 
-	for (xfer = TAILQ_FIRST(&chp->ch_queue->queue_xfer);
+	for (xfer = TAILQ_FIRST(&chq->queue_xfer);
 	    xfer != NULL; xfer = next_xfer) {
 		next_xfer = TAILQ_NEXT(xfer, c_xferchain);
 		if (xfer->c_chp != chp || xfer->c_drive != drvp->drive)
 			continue;
-		TAILQ_REMOVE(&chp->ch_queue->queue_xfer, xfer, c_xferchain);
+		TAILQ_REMOVE(&chq->queue_xfer, xfer, c_xferchain);
 		(*xfer->c_kill_xfer)(chp, xfer, KILL_GONE);
 	}
 
-	while ((xfer = chp->ch_queue->active_xfer) != NULL) {
-		if (xfer->c_chp == chp && xfer->c_drive == drvp->drive) {
-			drvp->drive_flags |= ATA_DRIVE_WAITDRAIN;
-			(void) tsleep(&chp->ch_queue->active_xfer,
-			    PRIBIO, "atdrn", 0);
-		} else {
-			/* no more xfer for us */
-			break;
+	while (chq->queue_active > 0) {
+		if (chq->queue_openings == 1 && chp->ch_ndrives > 1) {
+			xfer = chq->active_xfers[0];
+			if (xfer->c_chp != chp || xfer->c_drive != drvp->drive)
+				break;
 		}
+		drvp->drive_flags |= ATA_DRIVE_WAITDRAIN;
+		(void) tsleep(&chq->active_xfers[0], PRIBIO, "atdrn", 0);
 	}
 	splx(s);
 }
@@ -1144,9 +1299,7 @@ ata_reset_channel(struct ata_channel *ch
 		atastart(chp);
 	} else {
 		/* make sure that we can use polled commands */
-		TAILQ_INIT(&chp->ch_queue->queue_xfer);
-		chp->ch_queue->queue_freeze = 0;
-		chp->ch_queue->active_xfer = NULL;
+		ata_queue_reset(chp->ch_queue);
 	}
 }
 

Index: src/sys/dev/ata/ata_wdc.c
diff -u src/sys/dev/ata/ata_wdc.c:1.105 src/sys/dev/ata/ata_wdc.c:1.105.6.1
--- src/sys/dev/ata/ata_wdc.c:1.105	Fri Jan  2 19:42:06 2015
+++ src/sys/dev/ata/ata_wdc.c	Mon Apr 10 22:57:02 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata_wdc.c,v 1.105 2015/01/02 19:42:06 christos Exp $	*/
+/*	$NetBSD: ata_wdc.c,v 1.105.6.1 2017/04/10 22:57:02 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.105 2015/01/02 19:42:06 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.105.6.1 2017/04/10 22:57:02 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wdc.h"
@@ -808,13 +808,11 @@ wdc_ata_bio_done(struct ata_channel *chp
 	ata_bio->bcount = xfer->c_bcount;
 
 	/* mark controller inactive and free xfer */
-	chp->ch_queue->active_xfer = NULL;
+	ata_deactivate_xfer(chp, xfer);
 	ata_free_xfer(chp, xfer);
 
-	if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
+	if (ata_waitdrain_check(chp, drive)) {
 		ata_bio->error = ERR_NODEV;
-		chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(&chp->ch_queue->active_xfer);
 	}
 	ata_bio->flags |= ATA_ITSDONE;
 	ATADEBUG_PRINT(("wdc_ata_done: drv_done\n"), DEBUG_XFERS);

Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.92 src/sys/dev/ata/atavar.h:1.92.8.1
--- src/sys/dev/ata/atavar.h:1.92	Wed Sep 10 07:04:48 2014
+++ src/sys/dev/ata/atavar.h	Mon Apr 10 22:57:02 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: atavar.h,v 1.92 2014/09/10 07:04:48 matt Exp $	*/
+/*	$NetBSD: atavar.h,v 1.92.8.1 2017/04/10 22:57:02 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -45,7 +45,9 @@ struct ata_xfer {
 
 	/* Channel and drive that are to process the request. */
 	struct ata_channel *c_chp;
-	int	c_drive;
+	uint16_t c_drive;
+	int8_t c_slot;			/* queue slot # */
+	uint8_t c_hwslot;		/* hardware slot # */
 
 	void	*c_cmd;			/* private request structure pointer */
 	void	*c_databuf;		/* pointer to data buffer */
@@ -81,9 +83,12 @@ struct ata_xfer {
 struct ata_queue {
 	TAILQ_HEAD(, ata_xfer) queue_xfer; /* queue of pending commands */
 	int queue_freeze; /* freeze count for the queue */
-	struct ata_xfer *active_xfer; /* active command */
 	int queue_flags;	/* flags for this queue */
-#define QF_IDLE_WAIT   0x01    /* someone is wants the controller idle */
+#define QF_IDLE_WAIT	0x01    /* someone is wants the controller idle */
+#define QF_SHARED	0x02	/* this queue is shared */
+	int queue_active; /* number of active transfers */
+	int queue_openings; /* max number of active transfers */
+	struct ata_xfer *active_xfers[1]; /* active command */
 };
 
 /* ATA bus instance state information. */
@@ -447,8 +452,12 @@ void	ata_free_xfer(struct ata_channel *,
 #define	ATAXF_CANSLEEP	0x00
 #define	ATAXF_NOSLEEP	0x01
 
+void	ata_activate_xfer(struct ata_channel *, struct ata_xfer *);
+void	ata_deactivate_xfer(struct ata_channel *, struct ata_xfer *);
+
 void	ata_exec_xfer(struct ata_channel *, struct ata_xfer *);
 void	ata_kill_pending(struct ata_drive_datas *);
+void	ata_kill_active(struct ata_channel *, int);
 void	ata_reset_channel(struct ata_channel *, int);
 
 int	ata_addref(struct ata_channel *);
@@ -464,7 +473,16 @@ void	ata_probe_caps(struct ata_drive_dat
 void	ata_dmaerr(struct ata_drive_datas *, int);
 #endif
 void	ata_queue_idle(struct ata_queue *);
+struct ata_queue *
+	ata_queue_alloc(int openings);
+void	ata_queue_free(struct ata_queue *);
+struct ata_xfer *
+	ata_queue_hwslot_to_xfer(struct ata_queue *, int);
+
 void	ata_delay(int, const char *, int);
+
+bool	ata_waitdrain_check(struct ata_channel *, int);
+bool	ata_waitdrain_xfer_check(struct ata_channel *, struct ata_xfer *);
 #endif /* _KERNEL */
 
 #endif /* _DEV_ATA_ATAVAR_H_ */

Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.57 src/sys/dev/ic/ahcisata_core.c:1.57.6.1
--- src/sys/dev/ic/ahcisata_core.c:1.57	Fri Jun  3 10:34:03 2016
+++ src/sys/dev/ic/ahcisata_core.c	Mon Apr 10 22:57:02 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisata_core.c,v 1.57 2016/06/03 10:34:03 jmcneill Exp $	*/
+/*	$NetBSD: ahcisata_core.c,v 1.57.6.1 2017/04/10 22:57:02 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -26,7 +26,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57 2016/06/03 10:34:03 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.1 2017/04/10 22:57:02 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -365,8 +365,7 @@ ahci_attach(struct ahci_softc *sc)
 		sc->sc_chanarray[i] = chp;
 		chp->ch_channel = i;
 		chp->ch_atac = &sc->sc_atac;
-		chp->ch_queue = malloc(sizeof(struct ata_queue),
-		    M_DEVBUF, M_NOWAIT|M_ZERO);
+		chp->ch_queue = ata_queue_alloc(1); // XXX
 		if (chp->ch_queue == NULL) {
 			aprint_error("%s port %d: can't allocate memory for "
 			    "command queue", AHCINAME(sc), i);
@@ -508,7 +507,8 @@ ahci_detach(struct ahci_softc *sc, int f
 		bus_dmamem_free(sc->sc_dmat, &achp->ahcic_cmd_tbl_seg,
 		    achp->ahcic_cmd_tbl_nseg);
 
-		free(chp->ch_queue, M_DEVBUF);
+		ata_queue_free(chp->ch_queue);
+		chp->ch_queue = NULL;
 		chp->atabus = NULL;
 	}
 
@@ -557,7 +557,7 @@ ahci_intr_port(struct ahci_softc *sc, st
 {
 	uint32_t is, tfd;
 	struct ata_channel *chp = &achp->ata_channel;
-	struct ata_xfer *xfer = chp->ch_queue->active_xfer;
+	struct ata_xfer *xfer;
 	int slot;
 
 	is = AHCI_READ(sc, AHCI_P_IS(chp->ch_channel));
@@ -578,6 +578,7 @@ ahci_intr_port(struct ahci_softc *sc, st
 			printf("ahci_intr_port: slot %d\n", slot);
 			panic("ahci_intr_port");
 		}
+		xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, slot);
 		if (is & AHCI_P_IX_TFES) {
 			tfd = AHCI_READ(sc, AHCI_P_TFD(chp->ch_channel));
 			chp->ch_error =
@@ -600,6 +601,7 @@ ahci_intr_port(struct ahci_softc *sc, st
 			ahci_channel_start(sc, chp, 0, 0);
 	} else {
 		slot = 0; /* XXX */
+		xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, slot);
 		is = AHCI_READ(sc, AHCI_P_IS(chp->ch_channel));
 		AHCIDEBUG_PRINT(("ahci_intr_port port %d is 0x%x act 0x%x CI 0x%x\n",
 		    chp->ch_channel, is, achp->ahcic_cmds_active,
@@ -820,10 +822,7 @@ ahci_reset_channel(struct ata_channel *c
 		printf("%s: port %d reset failed\n", AHCINAME(sc), chp->ch_channel);
 		/* XXX and then ? */
 	}
-	if (chp->ch_queue->active_xfer) {
-		chp->ch_queue->active_xfer->c_kill_xfer(chp,
-		    chp->ch_queue->active_xfer, KILL_RESET);
-	}
+	ata_kill_active(chp, KILL_RESET);
 	ata_delay(500, "ahcirst", flags);
 	/* clear port interrupt register */
 	AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);
@@ -976,16 +975,18 @@ ahci_cmd_start(struct ata_channel *chp, 
 	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
 	struct ahci_channel *achp = (struct ahci_channel *)chp;
 	struct ata_command *ata_c = xfer->c_cmd;
-	int slot = 0 /* XXX slot */;
+	int slot = xfer->c_slot;
 	struct ahci_cmd_tbl *cmd_tbl;
 	struct ahci_cmd_header *cmd_h;
 	int i;
 	int channel = chp->ch_channel;
 
-	AHCIDEBUG_PRINT(("ahci_cmd_start CI 0x%x timo %d\n",
-	    AHCI_READ(sc, AHCI_P_CI(chp->ch_channel)), ata_c->timeout),
+	AHCIDEBUG_PRINT(("ahci_cmd_start CI 0x%x timo %d\n slot %d",
+	    AHCI_READ(sc, AHCI_P_CI(chp->ch_channel)), ata_c->timeout, slot),
 	    DEBUG_XFERS);
 
+	KASSERT((achp->ahcic_cmds_active & (1 << slot)) == 0);
+
 	cmd_tbl = achp->ahcic_cmd_tbl[slot];
 	AHCIDEBUG_PRINT(("%s port %d tbl %p\n", AHCINAME(sc), chp->ch_channel,
 	      cmd_tbl), DEBUG_XFERS);
@@ -1092,15 +1093,11 @@ ahci_cmd_complete(struct ata_channel *ch
 	chp->ch_flags &= ~ATACH_IRQ_WAIT;
 	if (xfer->c_flags & C_TIMEOU) {
 		ata_c->flags |= AT_TIMEOU;
-	} else
-		callout_stop(&chp->ch_callout);
+	}
 
-	chp->ch_queue->active_xfer = NULL;
+	ata_deactivate_xfer(chp, xfer);
 
-	if (chp->ch_drive[xfer->c_drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
-		ahci_cmd_kill_xfer(chp, xfer, KILL_GONE);
-		chp->ch_drive[xfer->c_drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(&chp->ch_queue->active_xfer);
+	if (ata_waitdrain_xfer_check(chp, xfer)) {
 		return 0;
 	}
 
@@ -1318,21 +1315,18 @@ ahci_bio_complete(struct ata_channel *ch
 	if (xfer->c_flags & C_TIMEOU) {
 		ata_bio->error = TIMEOUT;
 	} else {
-		callout_stop(&chp->ch_callout);
 		ata_bio->error = NOERROR;
 	}
 
-	chp->ch_queue->active_xfer = NULL;
+	ata_deactivate_xfer(chp, xfer);
+
 	bus_dmamap_sync(sc->sc_dmat, achp->ahcic_datad[slot], 0,
 	    achp->ahcic_datad[slot]->dm_mapsize,
 	    (ata_bio->flags & ATA_READ) ? BUS_DMASYNC_POSTREAD :
 	    BUS_DMASYNC_POSTWRITE);
 	bus_dmamap_unload(sc->sc_dmat, achp->ahcic_datad[slot]);
 
-	if (chp->ch_drive[xfer->c_drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
-		ahci_bio_kill_xfer(chp, xfer, KILL_GONE);
-		chp->ch_drive[xfer->c_drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(&chp->ch_queue->active_xfer);
+	if (ata_waitdrain_xfer_check(chp, xfer)) {
 		return 0;
 	}
 	ata_free_xfer(chp, xfer);
@@ -1439,7 +1433,7 @@ static void
 ahci_timeout(void *v)
 {
 	struct ata_channel *chp = (struct ata_channel *)v;
-	struct ata_xfer *xfer = chp->ch_queue->active_xfer;
+	struct ata_xfer *xfer = chp->ch_queue->active_xfers[0];
 #ifdef AHCI_DEBUG
 	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
 #endif
@@ -1696,9 +1690,8 @@ ahci_atapi_start(struct ata_channel *chp
 static int
 ahci_atapi_complete(struct ata_channel *chp, struct ata_xfer *xfer, int irq)
 {
-	int slot = 0; /* XXX slot */
+	int slot = xfer->c_slot; /* XXX slot */
 	struct scsipi_xfer *sc_xfer = xfer->c_cmd;
-	int drive = xfer->c_drive;
 	struct ahci_channel *achp = (struct ahci_channel *)chp;
 	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
 
@@ -1710,11 +1703,11 @@ ahci_atapi_complete(struct ata_channel *
 	if (xfer->c_flags & C_TIMEOU) {
 		sc_xfer->error = XS_TIMEOUT;
 	} else {
-		callout_stop(&chp->ch_callout);
 		sc_xfer->error = 0;
 	}
 
-	chp->ch_queue->active_xfer = NULL;
+	ata_deactivate_xfer(chp, xfer);
+
 	if (xfer->c_bcount > 0) {
 		bus_dmamap_sync(sc->sc_dmat, achp->ahcic_datad[slot], 0,
 		    achp->ahcic_datad[slot]->dm_mapsize,
@@ -1723,10 +1716,8 @@ ahci_atapi_complete(struct ata_channel *
 		bus_dmamap_unload(sc->sc_dmat, achp->ahcic_datad[slot]);
 	}
 
-	if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
-		ahci_atapi_kill_xfer(chp, xfer, KILL_GONE);
-		chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(&chp->ch_queue->active_xfer);
+	if (ata_waitdrain_xfer_check(chp, xfer)) {
+		sc_xfer->error = XS_DRIVER_STUFFUP;
 		return 0;
 	}
 	ata_free_xfer(chp, xfer);

Index: src/sys/dev/ic/mvsata.c
diff -u src/sys/dev/ic/mvsata.c:1.35 src/sys/dev/ic/mvsata.c:1.35.6.1
--- src/sys/dev/ic/mvsata.c:1.35	Mon May  2 19:18:29 2016
+++ src/sys/dev/ic/mvsata.c	Mon Apr 10 22:57:02 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: mvsata.c,v 1.35 2016/05/02 19:18:29 christos Exp $	*/
+/*	$NetBSD: mvsata.c,v 1.35.6.1 2017/04/10 22:57:02 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.35 2016/05/02 19:18:29 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.1 2017/04/10 22:57:02 jdolecek Exp $");
 
 #include "opt_mvsata.h"
 
@@ -630,7 +630,7 @@ mvsata_reset_channel(struct ata_channel 
 		xfer = mvport->port_reqtbl[i].xfer;
 		if (xfer == NULL)
 			continue;
-		chp->ch_queue->active_xfer = xfer;
+		chp->ch_queue->active_xfers[0] = xfer;
 		xfer->c_kill_xfer(chp, xfer, KILL_RESET);
 	}
 
@@ -1447,14 +1447,14 @@ mvsata_bio_done(struct ata_channel *chp,
 	ata_bio->bcount = xfer->c_bcount;
 
 	/* mark controller inactive and free xfer */
-	KASSERT(chp->ch_queue->active_xfer != NULL);
-	chp->ch_queue->active_xfer = NULL;
+	KASSERT(chp->ch_queue->active_xfers[0] != NULL);
+	ata_deactivate_xfer(chp, xfer);
 	ata_free_xfer(chp, xfer);
 
 	if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
 		ata_bio->error = ERR_NODEV;
 		chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(&chp->ch_queue->active_xfer);
+		wakeup(chp->ch_queue->active_xfers);
 	}
 	ata_bio->flags |= ATA_ITSDONE;
 	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
@@ -1812,8 +1812,9 @@ mvsata_wdc_cmd_done(struct ata_channel *
 			    (uint64_t)(ata_c->r_device & 0x0f) << 24;
 		}
 	}
-	callout_stop(&chp->ch_callout);
-	chp->ch_queue->active_xfer = NULL;
+
+	ata_deactivate_xfer(chp, xfer);
+
 	if (ata_c->flags & AT_POLL) {
 		/* enable interrupts */
 		MVSATA_WDC_WRITE_1(mvport, SRB_CAS, WDCTL_4BIT);
@@ -1822,7 +1823,7 @@ mvsata_wdc_cmd_done(struct ata_channel *
 	if (chp->ch_drive[xfer->c_drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
 		mvsata_wdc_cmd_kill_xfer(chp, xfer, KILL_GONE);
 		chp->ch_drive[xfer->c_drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(&chp->ch_queue->active_xfer);
+		wakeup(chp->ch_queue->active_xfers);
 	} else
 		mvsata_wdc_cmd_done_end(chp, xfer);
 }
@@ -2390,15 +2391,16 @@ mvsata_atapi_done(struct ata_channel *ch
 	DPRINTFN(1, ("%s:%d:%d: mvsata_atapi_done: flags 0x%x\n",
 	    device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive,
 	    (u_int)xfer->c_flags));
-	callout_stop(&chp->ch_callout);
+
 	/* mark controller inactive and free the command */
-	chp->ch_queue->active_xfer = NULL;
+
+	ata_deactivate_xfer(chp, xfer);
 	ata_free_xfer(chp, xfer);
 
 	if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
 		sc_xfer->error = XS_DRIVER_STUFFUP;
 		chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(&chp->ch_queue->active_xfer);
+		wakeup(chp->ch_queue->active_xfers);
 	}
 
 	DPRINTFN(1, ("%s:%d: mvsata_atapi_done: scsipi_done\n",
@@ -2460,8 +2462,8 @@ mvsata_edma_enqueue(struct mvsata_port *
 		return rv;
 
 	KASSERT(mvport->port_reqtbl[quetag].xfer == NULL);
-	KASSERT(chp->ch_queue->active_xfer != NULL);
-	mvport->port_reqtbl[quetag].xfer = chp->ch_queue->active_xfer;
+	KASSERT(chp->ch_queue->active_xfers[0] != NULL);
+	mvport->port_reqtbl[quetag].xfer = chp->ch_queue->active_xfers[0];
 
 	/* setup EDMA Physical Region Descriptors (ePRD) Table Data */
 	data_dmamap = mvport->port_reqtbl[quetag].data_dmamap;
@@ -2574,8 +2576,8 @@ mvsata_edma_handle(struct mvsata_port *m
 #endif
 		crpb = mvport->port_crpb + erpqop;
 		quetag = CRPB_CHOSTQUETAG(le16toh(crpb->id));
-		KASSERT(chp->ch_queue->active_xfer != NULL);
-		xfer = chp->ch_queue->active_xfer;
+		KASSERT(chp->ch_queue->active_xfers[0] != NULL);
+		xfer = chp->ch_queue->active_xfers[0];
 		KASSERT(xfer == mvport->port_reqtbl[quetag].xfer);
 #ifdef DIAGNOSTIC
 		if (xfer == NULL)
@@ -2763,9 +2765,9 @@ mvsata_bdma_init(struct mvsata_port *mvp
 	if (rv != 0)
 		return rv;
 
-	KASSERT(chp->ch_queue->active_xfer != NULL);
+	KASSERT(chp->ch_queue->active_xfers[0] != NULL);
 	KASSERT(mvport->port_reqtbl[quetag].xfer == NULL);
-	mvport->port_reqtbl[quetag].xfer = chp->ch_queue->active_xfer;
+	mvport->port_reqtbl[quetag].xfer = chp->ch_queue->active_xfers[0];
 
 	/* setup EDMA Physical Region Descriptors (ePRD) Table Data */
 	data_dmamap = mvport->port_reqtbl[quetag].data_dmamap;
@@ -2886,6 +2888,7 @@ mvsata_port_init(struct mvsata_hc *mvhc,
 	chp->ch_channel = channel;
 	chp->ch_atac = &sc->sc_wdcdev.sc_atac;
 	chp->ch_queue = &mvport->port_ata_queue;
+	chp->ch_queue->queue_openings = 1;	// XXX
 	sc->sc_ata_channels[channel] = chp;
 
 	rv = mvsata_wdc_reg_init(mvport, sc->sc_wdcdev.regs + channel);
@@ -3449,7 +3452,7 @@ mvsata_edma_setup_crqb(struct mvsata_por
 	uint8_t cmd, head;
 	int i;
 	const int drive =
-	    mvport->port_ata_channel.ch_queue->active_xfer->c_drive;
+	    mvport->port_ata_channel.ch_queue->active_xfers[0]->c_drive;
 
 	eprd_addr = mvport->port_eprd_dmamap->dm_segs[0].ds_addr +
 	    mvport->port_reqtbl[quetag].eprd_offset;
@@ -3697,7 +3700,7 @@ mvsata_edma_setup_crqb_gen2e(struct mvsa
 	uint32_t ctrlflg, rw;
 	uint8_t cmd, head;
 	const int drive =
-	    mvport->port_ata_channel.ch_queue->active_xfer->c_drive;
+	    mvport->port_ata_channel.ch_queue->active_xfers[0]->c_drive;
 
 	eprd_addr = mvport->port_eprd_dmamap->dm_segs[0].ds_addr +
 	    mvport->port_reqtbl[quetag].eprd_offset;

Index: src/sys/dev/ic/siisata.c
diff -u src/sys/dev/ic/siisata.c:1.30 src/sys/dev/ic/siisata.c:1.30.4.1
--- src/sys/dev/ic/siisata.c:1.30	Tue Jan  3 01:30:15 2017
+++ src/sys/dev/ic/siisata.c	Mon Apr 10 22:57:02 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.30 2017/01/03 01:30:15 jakllsch Exp $ */
+/* $NetBSD: siisata.c,v 1.30.4.1 2017/04/10 22:57:02 jdolecek Exp $ */
 
 /* from ahcisata_core.c */
 
@@ -79,12 +79,12 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30 2017/01/03 01:30:15 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.1 2017/04/10 22:57:02 jdolecek Exp $");
 
 #include <sys/types.h>
-#include <sys/malloc.h>
 #include <sys/param.h>
 #include <sys/kernel.h>
+#include <sys/malloc.h>
 #include <sys/systm.h>
 #include <sys/syslog.h>
 #include <sys/disklabel.h>
@@ -290,8 +290,7 @@ siisata_attach_port(struct siisata_softc
 	sc->sc_chanarray[port] = chp;
 	chp->ch_channel = port;
 	chp->ch_atac = &sc->sc_atac;
-	chp->ch_queue = malloc(sizeof(struct ata_queue),
-			       M_DEVBUF, M_NOWAIT|M_ZERO);
+	chp->ch_queue = ata_queue_alloc(1);	// XXX
 	if (chp->ch_queue == NULL) {
 		aprint_error_dev(sc->sc_atac.atac_dev,
 		    "port %d: can't allocate memory "
@@ -481,7 +480,7 @@ siisata_intr_port(struct siisata_channel
 
 	sc = (struct siisata_softc *)schp->ata_channel.ch_atac;
 	chp = &schp->ata_channel;
-	xfer = chp->ch_queue->active_xfer;
+	xfer = chp->ch_queue->active_xfers[0];
 	slot = SIISATA_NON_NCQ_SLOT;
 
 	pis = PRREAD(sc, PRX(chp->ch_channel, PRO_PIS));
@@ -625,6 +624,7 @@ siisata_reset_channel(struct ata_channel
 {
 	struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac;
 	struct siisata_channel *schp = (struct siisata_channel *)chp;
+	struct ata_xfer *xfer;
 
 	SIISATA_DEBUG_PRINT(("%s: %s\n", SIISATANAME(sc), __func__),
 	    DEBUG_FUNCS);
@@ -640,9 +640,8 @@ siisata_reset_channel(struct ata_channel
 		DELAY(10);
 	PRWRITE(sc, PRX(chp->ch_channel, PRO_SERROR),
 	    PRREAD(sc, PRX(chp->ch_channel, PRO_SERROR)));
-	if (chp->ch_queue->active_xfer) {
-		chp->ch_queue->active_xfer->c_kill_xfer(chp,
-		    chp->ch_queue->active_xfer, KILL_RESET);
+	if ((xfer = chp->ch_queue->active_xfers[0]) != NULL) {
+		(*xfer->c_kill_xfer)(chp, xfer, KILL_RESET);
 	}
 
 	return;
@@ -943,13 +942,11 @@ siisata_cmd_complete(struct ata_channel 
 		ata_c->flags |= AT_ERROR;
 	}
 
-	if (chp->ch_drive[xfer->c_drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
-		siisata_cmd_kill_xfer(chp, xfer, KILL_GONE);
-		chp->ch_drive[xfer->c_drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(&chp->ch_queue->active_xfer);
-		return 0;
-	} else
+	ata_deactivate_xfer(chp, xfer);
+
+	if (!ata_waitdrain_xfer_check(chp, xfer)) {
 		siisata_cmd_done(chp, xfer, slot);
+	}
 
 	return 0;
 }
@@ -998,8 +995,8 @@ siisata_cmd_done(struct ata_channel *chp
 	if (PRREAD(sc, PRSX(chp->ch_channel, slot, PRSO_RTC)))
 		ata_c->flags |= AT_XFDONE;
 
-	chp->ch_queue->active_xfer = NULL;
 	ata_free_xfer(chp, xfer);
+
 	if (ata_c->flags & AT_WAIT)
 		wakeup(ata_c);
 	else if (ata_c->callback)
@@ -1156,15 +1153,14 @@ siisata_bio_complete(struct ata_channel 
 	    BUS_DMASYNC_POSTWRITE);
 	bus_dmamap_unload(sc->sc_dmat, schp->sch_datad[slot]);
 
-	if (chp->ch_drive[xfer->c_drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
-		siisata_bio_kill_xfer(chp, xfer, KILL_GONE);
-		chp->ch_drive[xfer->c_drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(&chp->ch_queue->active_xfer);
+	ata_deactivate_xfer(chp, xfer);
+
+	if (ata_waitdrain_xfer_check(chp, xfer)) {
 		return 0;
 	}
 
-	chp->ch_queue->active_xfer = NULL;
 	ata_free_xfer(chp, xfer);
+
 	ata_bio->flags |= ATA_ITSDONE;
 	if (chp->ch_status & WDCS_DWF) {
 		ata_bio->error = ERR_DF;
@@ -1195,7 +1191,7 @@ void
 siisata_timeout(void *v)
 {
 	struct ata_channel *chp = (struct ata_channel *)v;
-	struct ata_xfer *xfer = chp->ch_queue->active_xfer;
+	struct ata_xfer *xfer = chp->ch_queue->active_xfers[0];
 	int slot = SIISATA_NON_NCQ_SLOT;
 	int s = splbio();
 	SIISATA_DEBUG_PRINT(("%s: %p\n", __func__, xfer), DEBUG_INTR);
@@ -1680,14 +1676,13 @@ siisata_atapi_complete(struct ata_channe
 	    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
 	bus_dmamap_unload(sc->sc_dmat, schp->sch_datad[slot]);
 
-	if (chp->ch_drive[xfer->c_drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
-		siisata_atapi_kill_xfer(chp, xfer, KILL_GONE);
-		chp->ch_drive[xfer->c_drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(&chp->ch_queue->active_xfer);
+	ata_deactivate_xfer(chp, xfer);
+
+	if (!ata_waitdrain_xfer_check(chp, xfer)) {
+		sc_xfer->error = XS_DRIVER_STUFFUP;
 		return 0; /* XXX verify */
 	}
 
-	chp->ch_queue->active_xfer = NULL;
 	ata_free_xfer(chp, xfer);
 	sc_xfer->resid = sc_xfer->datalen;
 	sc_xfer->resid -= PRREAD(sc, PRSX(chp->ch_channel, slot, PRSO_RTC));

Index: src/sys/dev/ic/wdc.c
diff -u src/sys/dev/ic/wdc.c:1.283 src/sys/dev/ic/wdc.c:1.283.2.1
--- src/sys/dev/ic/wdc.c:1.283	Wed Mar 29 09:04:35 2017
+++ src/sys/dev/ic/wdc.c	Mon Apr 10 22:57:02 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdc.c,v 1.283 2017/03/29 09:04:35 msaitoh Exp $ */
+/*	$NetBSD: wdc.c,v 1.283.2.1 2017/04/10 22:57:02 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.283 2017/03/29 09:04:35 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.283.2.1 2017/04/10 22:57:02 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wdc.h"
@@ -872,7 +872,8 @@ wdcintr(void *arg)
 	}
 
 	ATADEBUG_PRINT(("wdcintr\n"), DEBUG_INTR);
-	xfer = chp->ch_queue->active_xfer;
+	KASSERT(chp->ch_queue->queue_openings == 1);
+	xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, 0);
 #ifdef DIAGNOSTIC
 	if (xfer == NULL)
 		panic("wdcintr: no xfer");
@@ -933,7 +934,8 @@ wdc_reset_channel(struct ata_channel *ch
 	 * if the current command if on an ATAPI device, issue a
 	 * ATAPI_SOFT_RESET
 	 */
-	xfer = chp->ch_queue->active_xfer;
+	KASSERT(chp->ch_queue->queue_openings == 1);
+	xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, 0);
 	if (xfer && xfer->c_chp == chp && (xfer->c_flags & C_ATAPI)) {
 		wdccommandshort(chp, xfer->c_drive, ATAPI_SOFT_RESET);
 		if (flags & AT_WAIT)
@@ -977,12 +979,11 @@ wdc_reset_channel(struct ata_channel *ch
 			    xfer, c_xferchain);
 			TAILQ_INSERT_TAIL(&reset_xfer, xfer, c_xferchain);
 		}
-		xfer = chp->ch_queue->active_xfer;
+		xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, 0);
 		if (xfer) {
 			if (xfer->c_chp != chp)
 				ata_reset_channel(xfer->c_chp, flags);
 			else {
-				callout_stop(&chp->ch_callout);
 #if NATA_DMA || NATA_PIOBM
 				/*
 				 * If we're waiting for DMA, stop the
@@ -995,7 +996,7 @@ wdc_reset_channel(struct ata_channel *ch
 					chp->ch_flags &= ~ATACH_DMA_WAIT;
 				}
 #endif
-				chp->ch_queue->active_xfer = NULL;
+				ata_deactivate_xfer(chp, xfer);
 				if ((flags & AT_RST_EMERG) == 0)
 					xfer->c_kill_xfer(
 					    chp, xfer, KILL_RESET);
@@ -1231,7 +1232,7 @@ __wdcwait(struct ata_channel *chp, int m
 #ifdef WDCNDELAY_DEBUG
 	/* After autoconfig, there should be no long delays. */
 	if (!cold && xtime > WDCNDELAY_DEBUG) {
-		struct ata_xfer *xfer = chp->ch_queue->active_xfer;
+		struct ata_xfer *xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, 0);
 		if (xfer == NULL)
 			printf("%s channel %d: warning: busy-wait took %dus\n",
 			    device_xname(chp->ch_atac->atac_dev),
@@ -1326,12 +1327,13 @@ wdctimeout(void *arg)
 #if NATA_DMA || NATA_PIOBM
 	struct wdc_softc *wdc = CHAN_TO_WDC(chp);
 #endif
-	struct ata_xfer *xfer = chp->ch_queue->active_xfer;
 	int s;
 
 	ATADEBUG_PRINT(("wdctimeout\n"), DEBUG_FUNCS);
 
 	s = splbio();
+	struct ata_xfer *xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, 0);
+	KASSERT(xfer != NULL);
 	if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0) {
 		__wdcerror(chp, "lost interrupt");
 		printf("\ttype: %s tc_bcount: %d tc_skip: %d\n",
@@ -1663,8 +1665,9 @@ __wdccommand_done(struct ata_channel *ch
 		}
 		ata_c->r_device &= 0xf0;
 	}
-	callout_stop(&chp->ch_callout);
-	chp->ch_queue->active_xfer = NULL;
+
+	ata_deactivate_xfer(chp, xfer);
+
 	if (ata_c->flags & AT_POLL) {
 		/* enable interrupts */
 		if (! (wdc->cap & WDC_CAPABILITY_NO_AUXCTL)) 
@@ -1672,12 +1675,10 @@ __wdccommand_done(struct ata_channel *ch
 			    wd_aux_ctlr, WDCTL_4BIT);
 		delay(10); /* some drives need a little delay here */
 	}
-	if (chp->ch_drive[xfer->c_drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
-		__wdccommand_kill_xfer(chp, xfer, KILL_GONE);
-		chp->ch_drive[xfer->c_drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(&chp->ch_queue->active_xfer);
-	} else
+
+	if (!ata_waitdrain_xfer_check(chp, xfer)) {
 		__wdccommand_done_end(chp, xfer);
+	}
 }
 
 static void
@@ -1849,7 +1850,7 @@ static void
 __wdcerror(struct ata_channel *chp, const char *msg)
 {
 	struct atac_softc *atac = chp->ch_atac;
-	struct ata_xfer *xfer = chp->ch_queue->active_xfer;
+	struct ata_xfer *xfer = ata_queue_hwslot_to_xfer(chp->ch_queue, 0);
 
 	if (xfer == NULL)
 		aprint_error("%s:%d: %s\n", device_xname(atac->atac_dev),

Index: src/sys/dev/pci/artsata.c
diff -u src/sys/dev/pci/artsata.c:1.26 src/sys/dev/pci/artsata.c:1.26.18.1
--- src/sys/dev/pci/artsata.c:1.26	Sat Mar 29 19:28:24 2014
+++ src/sys/dev/pci/artsata.c	Mon Apr 10 22:57:02 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: artsata.c,v 1.26 2014/03/29 19:28:24 christos Exp $	*/
+/*	$NetBSD: artsata.c,v 1.26.18.1 2017/04/10 22:57:02 jdolecek Exp $	*/
 
 /*-
  * Copyright (c) 2003 The NetBSD Foundation, Inc.
@@ -30,13 +30,12 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: artsata.c,v 1.26 2014/03/29 19:28:24 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: artsata.c,v 1.26.18.1 2017/04/10 22:57:02 jdolecek Exp $");
 
 #include "opt_pciide.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/malloc.h>
 
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcidevs.h>
@@ -232,8 +231,7 @@ artisea_chansetup(struct pciide_softc *s
 	cp->name = PCIIDE_CHANNEL_NAME(channel);
 	cp->ata_channel.ch_channel = channel;
 	cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
-	cp->ata_channel.ch_queue =
-	    malloc(sizeof(struct ata_queue), M_DEVBUF, M_NOWAIT);
+	cp->ata_channel.ch_queue = ata_queue_alloc(1);
 	if (cp->ata_channel.ch_queue == NULL) {
 		aprint_error("%s %s channel: "
 		    "can't allocate memory for command queue",

Index: src/sys/dev/pci/cmdide.c
diff -u src/sys/dev/pci/cmdide.c:1.38 src/sys/dev/pci/cmdide.c:1.38.28.1
--- src/sys/dev/pci/cmdide.c:1.38	Mon Sep  3 15:38:17 2012
+++ src/sys/dev/pci/cmdide.c	Mon Apr 10 22:57:02 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: cmdide.c,v 1.38 2012/09/03 15:38:17 kiyohara Exp $	*/
+/*	$NetBSD: cmdide.c,v 1.38.28.1 2017/04/10 22:57:02 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1999, 2000, 2001 Manuel Bouyer.
@@ -25,11 +25,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cmdide.c,v 1.38 2012/09/03 15:38:17 kiyohara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cmdide.c,v 1.38.28.1 2017/04/10 22:57:02 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/malloc.h>
 
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcidevs.h>
@@ -165,8 +164,7 @@ cmd_channel_map(const struct pci_attach_
 		cp->ata_channel.ch_queue =
 		    sc->pciide_channels[0].ata_channel.ch_queue;
 	} else {
-		cp->ata_channel.ch_queue =
-		    malloc(sizeof(struct ata_queue), M_DEVBUF, M_NOWAIT);
+		cp->ata_channel.ch_queue = ata_queue_alloc(1);
 	}
 	if (cp->ata_channel.ch_queue == NULL) {
 		aprint_error("%s %s channel: "
@@ -521,8 +519,7 @@ cmd680_channel_map(const struct pci_atta
 	cp->ata_channel.ch_channel = channel;
 	cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
 
-	cp->ata_channel.ch_queue =
-	    malloc(sizeof(struct ata_queue), M_DEVBUF, M_NOWAIT);
+	cp->ata_channel.ch_queue = ata_queue_alloc(1);
 	if (cp->ata_channel.ch_queue == NULL) {
 		aprint_error("%s %s channel: "
 		    "can't allocate memory for command queue",

Index: src/sys/dev/pci/cypide.c
diff -u src/sys/dev/pci/cypide.c:1.30 src/sys/dev/pci/cypide.c:1.30.18.1
--- src/sys/dev/pci/cypide.c:1.30	Mon Oct  7 19:51:55 2013
+++ src/sys/dev/pci/cypide.c	Mon Apr 10 22:57:03 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: cypide.c,v 1.30 2013/10/07 19:51:55 jakllsch Exp $	*/
+/*	$NetBSD: cypide.c,v 1.30.18.1 2017/04/10 22:57:03 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1999, 2000, 2001 Manuel Bouyer.
@@ -26,11 +26,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cypide.c,v 1.30 2013/10/07 19:51:55 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cypide.c,v 1.30.18.1 2017/04/10 22:57:03 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/malloc.h>
 
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcidevs.h>
@@ -149,8 +148,7 @@ cy693_chip_map(struct pciide_softc *sc, 
 	cp->name = PCIIDE_CHANNEL_NAME(0);
 	cp->ata_channel.ch_channel = 0;
 	cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
-	cp->ata_channel.ch_queue =
-	    malloc(sizeof(struct ata_queue), M_DEVBUF, M_NOWAIT);
+	cp->ata_channel.ch_queue = ata_queue_alloc(1);
 	if (cp->ata_channel.ch_queue == NULL) {
 		aprint_error("%s primary channel: "
 		    "can't allocate memory for command queue",

Index: src/sys/dev/pci/pciide_common.c
diff -u src/sys/dev/pci/pciide_common.c:1.62 src/sys/dev/pci/pciide_common.c:1.62.4.1
--- src/sys/dev/pci/pciide_common.c:1.62	Thu Oct 13 17:11:09 2016
+++ src/sys/dev/pci/pciide_common.c	Mon Apr 10 22:57:03 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: pciide_common.c,v 1.62 2016/10/13 17:11:09 jdolecek Exp $	*/
+/*	$NetBSD: pciide_common.c,v 1.62.4.1 2017/04/10 22:57:03 jdolecek Exp $	*/
 
 
 /*
@@ -70,10 +70,9 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pciide_common.c,v 1.62 2016/10/13 17:11:09 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pciide_common.c,v 1.62.4.1 2017/04/10 22:57:03 jdolecek Exp $");
 
 #include <sys/param.h>
-#include <sys/malloc.h>
 
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
@@ -210,7 +209,7 @@ pciide_common_detach(struct pciide_softc
 #endif
 		}
 
-		free(cp->ata_channel.ch_queue, M_DEVBUF);
+		ata_queue_free(cp->ata_channel.ch_queue);
 		cp->ata_channel.atabus = NULL;
 	}
 
@@ -877,8 +876,7 @@ pciide_chansetup(struct pciide_softc *sc
 	cp->name = PCIIDE_CHANNEL_NAME(channel);
 	cp->ata_channel.ch_channel = channel;
 	cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
-	cp->ata_channel.ch_queue =
-	    malloc(sizeof(struct ata_queue), M_DEVBUF, M_NOWAIT|M_ZERO);
+	cp->ata_channel.ch_queue = ata_queue_alloc(1);
 	if (cp->ata_channel.ch_queue == NULL) {
 		aprint_error("%s %s channel: "
 		    "can't allocate memory for command queue",

Index: src/sys/dev/pci/pdcsata.c
diff -u src/sys/dev/pci/pdcsata.c:1.27 src/sys/dev/pci/pdcsata.c:1.27.18.1
--- src/sys/dev/pci/pdcsata.c:1.27	Sat Mar 29 19:28:25 2014
+++ src/sys/dev/pci/pdcsata.c	Mon Apr 10 22:57:03 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: pdcsata.c,v 1.27 2014/03/29 19:28:25 christos Exp $	*/
+/*	$NetBSD: pdcsata.c,v 1.27.18.1 2017/04/10 22:57:03 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 2004, Manuel Bouyer.
@@ -25,10 +25,9 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pdcsata.c,v 1.27 2014/03/29 19:28:25 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pdcsata.c,v 1.27.18.1 2017/04/10 22:57:03 jdolecek Exp $");
 
 #include <sys/types.h>
-#include <sys/malloc.h>
 #include <sys/param.h>
 #include <sys/systm.h>
 
@@ -375,8 +374,7 @@ pdcsata_chip_map(struct pciide_softc *sc
 		cp->name = NULL;
 		cp->ata_channel.ch_channel = channel;
 		cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
-		cp->ata_channel.ch_queue =
-		    malloc(sizeof(struct ata_queue), M_DEVBUF, M_NOWAIT);
+		cp->ata_channel.ch_queue = ata_queue_alloc(1);
 		if (cp->ata_channel.ch_queue == NULL) {
 			aprint_error("%s channel %d: "
 			    "can't allocate memory for command queue\n",

Index: src/sys/dev/pci/satalink.c
diff -u src/sys/dev/pci/satalink.c:1.53 src/sys/dev/pci/satalink.c:1.53.4.1
--- src/sys/dev/pci/satalink.c:1.53	Tue Aug 23 09:46:45 2016
+++ src/sys/dev/pci/satalink.c	Mon Apr 10 22:57:03 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: satalink.c,v 1.53 2016/08/23 09:46:45 msaitoh Exp $	*/
+/*	$NetBSD: satalink.c,v 1.53.4.1 2017/04/10 22:57:03 jdolecek Exp $	*/
 
 /*-
  * Copyright (c) 2003 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: satalink.c,v 1.53 2016/08/23 09:46:45 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: satalink.c,v 1.53.4.1 2017/04/10 22:57:03 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -600,8 +600,7 @@ sii3114_chansetup(struct pciide_softc *s
 	cp->name = channel_names[channel];
 	cp->ata_channel.ch_channel = channel;
 	cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
-	cp->ata_channel.ch_queue =
-	    malloc(sizeof(struct ata_queue), M_DEVBUF, M_NOWAIT);
+	cp->ata_channel.ch_queue = ata_queue_alloc(1);
 	if (cp->ata_channel.ch_queue == NULL) {
 		aprint_error("%s %s channel: "
 		    "can't allocate memory for command queue",

Index: src/sys/dev/pci/viaide.c
diff -u src/sys/dev/pci/viaide.c:1.84 src/sys/dev/pci/viaide.c:1.84.18.1
--- src/sys/dev/pci/viaide.c:1.84	Sat Mar 29 19:28:25 2014
+++ src/sys/dev/pci/viaide.c	Mon Apr 10 22:57:03 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: viaide.c,v 1.84 2014/03/29 19:28:25 christos Exp $	*/
+/*	$NetBSD: viaide.c,v 1.84.18.1 2017/04/10 22:57:03 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1999, 2000, 2001 Manuel Bouyer.
@@ -26,11 +26,10 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: viaide.c,v 1.84 2014/03/29 19:28:25 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: viaide.c,v 1.84.18.1 2017/04/10 22:57:03 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
-#include <sys/malloc.h>
 
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pcidevs.h>
@@ -1071,8 +1070,7 @@ via_vt6421_chansetup(struct pciide_softc
 
 	cp->ata_channel.ch_channel = channel;
 	cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
-	cp->ata_channel.ch_queue =
-	    malloc(sizeof(struct ata_queue), M_DEVBUF, M_NOWAIT);
+	cp->ata_channel.ch_queue = ata_queue_alloc(1);
 	if (cp->ata_channel.ch_queue == NULL) {
 		aprint_error("%s channel %d: "
 		    "can't allocate memory for command queue",

Index: src/sys/dev/scsipi/atapi_wdc.c
diff -u src/sys/dev/scsipi/atapi_wdc.c:1.123 src/sys/dev/scsipi/atapi_wdc.c:1.123.4.1
--- src/sys/dev/scsipi/atapi_wdc.c:1.123	Sun Nov 20 15:37:19 2016
+++ src/sys/dev/scsipi/atapi_wdc.c	Mon Apr 10 22:57:03 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: atapi_wdc.c,v 1.123 2016/11/20 15:37:19 mlelstv Exp $	*/
+/*	$NetBSD: atapi_wdc.c,v 1.123.4.1 2017/04/10 22:57: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.123 2016/11/20 15:37:19 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.123.4.1 2017/04/10 22:57:03 jdolecek Exp $");
 
 #ifndef ATADEBUG
 #define ATADEBUG
@@ -1083,16 +1083,12 @@ wdc_atapi_done(struct ata_channel *chp, 
 	ATADEBUG_PRINT(("wdc_atapi_done %s:%d:%d: flags 0x%x\n",
 	    device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive,
 	    (u_int)xfer->c_flags), DEBUG_XFERS);
-	callout_stop(&chp->ch_callout);
-	/* mark controller inactive and free the command */
-	chp->ch_queue->active_xfer = NULL;
+
+	ata_deactivate_xfer(chp, xfer);
 	ata_free_xfer(chp, xfer);
 
-	if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
+	if (ata_waitdrain_check(chp, drive))
 		sc_xfer->error = XS_DRIVER_STUFFUP;
-		chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(&chp->ch_queue->active_xfer);
-	}
 
 	ATADEBUG_PRINT(("wdc_atapi_done: scsipi_done\n"), DEBUG_XFERS);
 	scsipi_done(sc_xfer);

Reply via email to