Module Name:    src
Committed By:   jdolecek
Date:           Sat Sep 22 09:23:00 UTC 2018

Modified Files:
        src/sys/dev/ata [jdolecek-ncqfixes]: TODO.ncq ata.c ata_subr.c atavar.h
            satapmp_subr.c wd.c wdvar.h
        src/sys/dev/ic [jdolecek-ncqfixes]: ahcisata_core.c mvsata.c siisata.c
        src/sys/dev/scsipi [jdolecek-ncqfixes]: atapi_wdc.c
        src/sys/dev/usb [jdolecek-ncqfixes]: umass_isdata.c

Log Message:
separate ata_xfer slot allocation and the memory allocation, so that
there can be more queued xfers than number of supported slots by controller,
and use a pool instead of custom pre-allocation

primarily to help PR kern/52614

remove no longer needed custom wd(4) logic for flush cache

switch also wd(4) trim/suspend/setcache/wdioctlstrategy to sleep waiting
for the memory, they are all called from process context and this
avoids spurious failures


To generate a diff of this commit:
cvs rdiff -u -r1.4.2.3 -r1.4.2.4 src/sys/dev/ata/TODO.ncq
cvs rdiff -u -r1.141.6.5 -r1.141.6.6 src/sys/dev/ata/ata.c
cvs rdiff -u -r1.6.2.4 -r1.6.2.5 src/sys/dev/ata/ata_subr.c
cvs rdiff -u -r1.99.2.4 -r1.99.2.5 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.14 -r1.14.2.1 src/sys/dev/ata/satapmp_subr.c
cvs rdiff -u -r1.441.2.3 -r1.441.2.4 src/sys/dev/ata/wd.c
cvs rdiff -u -r1.46.6.1 -r1.46.6.2 src/sys/dev/ata/wdvar.h
cvs rdiff -u -r1.62.2.4 -r1.62.2.5 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.41.2.3 -r1.41.2.4 src/sys/dev/ic/mvsata.c
cvs rdiff -u -r1.35.6.4 -r1.35.6.5 src/sys/dev/ic/siisata.c
cvs rdiff -u -r1.129.6.3 -r1.129.6.4 src/sys/dev/scsipi/atapi_wdc.c
cvs rdiff -u -r1.36 -r1.36.6.1 src/sys/dev/usb/umass_isdata.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/TODO.ncq
diff -u src/sys/dev/ata/TODO.ncq:1.4.2.3 src/sys/dev/ata/TODO.ncq:1.4.2.4
--- src/sys/dev/ata/TODO.ncq:1.4.2.3	Mon Sep 17 20:54:41 2018
+++ src/sys/dev/ata/TODO.ncq	Sat Sep 22 09:22:59 2018
@@ -1,16 +1,13 @@
 jdolecek-ncqfixes goals:
-- make ata_xfer dynamically allocated using a pool
-  - will fix: queue is allocated regardless if there are any drives, fix? 
-  - malloc() -> kmem_zalloc() in ata_queue_alloc() once this is done
-- remove limit of queued ata_xfers, allow any number of pending xfers;
-  this should fix kern/52614 AKA wdc-attached ATAPI cd(4)
-- remove the wd(4) flush condition, just allocate a dynamic ata_xfer
-- change wd(4) dump code to use on-stack ata_xfer to not rely on pool having
-  memory
+- add to wd(4) a callout to restart buf queue processing when ata_get_xfer()
+  call fails and remove ata_channel_start()
+- change wd(4) dump code to use preallocated or on-stack ata_xfer to not rely
+  on pool having memory
 - re-fix QEMU ahci(4) bug workaround (no READ LOG EXT support) - now it
   triggers KASSERT()
 - fix ahci(4) error handling under paralles - invalid bio via WD_CHAOS_MONKEY
   ends up being handled as NOERROR, triggering KASSERT() in wd(4)
+- weed out remaining KM_NOSLEEP
 
 Bugs
 ----

Index: src/sys/dev/ata/ata.c
diff -u src/sys/dev/ata/ata.c:1.141.6.5 src/sys/dev/ata/ata.c:1.141.6.6
--- src/sys/dev/ata/ata.c:1.141.6.5	Mon Sep 17 20:54:41 2018
+++ src/sys/dev/ata/ata.c	Sat Sep 22 09:22:59 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata.c,v 1.141.6.5 2018/09/17 20:54:41 jdolecek Exp $	*/
+/*	$NetBSD: ata.c,v 1.141.6.6 2018/09/22 09:22:59 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.6.5 2018/09/17 20:54:41 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.141.6.6 2018/09/22 09:22:59 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -84,6 +84,7 @@ int atadebug_mask = ATADEBUG_MASK;
 #endif
 
 static ONCE_DECL(ata_init_ctrl);
+static struct pool ata_xfer_pool;
 
 /*
  * A queue of atabus instances, used to ensure the same bus probe order
@@ -142,6 +143,8 @@ static int
 atabus_init(void)
 {
 
+	pool_init(&ata_xfer_pool, sizeof(struct ata_xfer), 0, 0, 0,
+	    "ataspl", NULL, IPL_BIO);
 	TAILQ_INIT(&atabus_initq_head);
 	mutex_init(&atabus_qlock, MUTEX_DEFAULT, IPL_NONE);
 	cv_init(&atabus_qcv, "atainitq");
@@ -779,7 +782,7 @@ ata_get_params(struct ata_drive_datas *d
 
 	ATADEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS);
 
-	xfer = ata_get_xfer(chp);
+	xfer = ata_get_xfer(chp, false);
 	if (xfer == NULL) {
 		ATADEBUG_PRINT(("%s: no xfer\n", __func__),
 		    DEBUG_FUNCS|DEBUG_PROBE);
@@ -884,7 +887,7 @@ ata_set_mode(struct ata_drive_datas *drv
 
 	ATADEBUG_PRINT(("ata_set_mode=0x%x\n", mode), DEBUG_FUNCS);
 
-	xfer = ata_get_xfer(chp);
+	xfer = ata_get_xfer(chp, false);
 	if (xfer == NULL) {
 		ATADEBUG_PRINT(("%s: no xfer\n", __func__),
 		    DEBUG_FUNCS|DEBUG_PROBE);
@@ -919,7 +922,7 @@ int
 ata_read_log_ext_ncq(struct ata_drive_datas *drvp, uint8_t flags,
     uint8_t *slot, uint8_t *status, uint8_t *err)
 {
-	struct ata_xfer *xfer;
+	struct ata_xfer *xfer = &drvp->recovery_xfer;
 	int rv;
 	struct ata_channel *chp = drvp->chnl_softc;
 	struct atac_softc *atac = chp->ch_atac;
@@ -932,7 +935,7 @@ ata_read_log_ext_ncq(struct ata_drive_da
 	    (drvp->drive_flags & ATA_DRIVE_NCQ) == 0)
 		return EOPNOTSUPP;
 
-	xfer = ata_get_xfer_ext(chp, C_RECOVERY, 0);
+	memset(xfer, 0, sizeof(*xfer));
 
 	tb = drvp->recovery_blk;
 	memset(tb, 0, sizeof(drvp->recovery_blk));
@@ -994,7 +997,6 @@ ata_read_log_ext_ncq(struct ata_drive_da
 	rv = 0;
 
 out:
-	ata_free_xfer(chp, xfer);
 	return rv;
 }
 
@@ -1128,13 +1130,6 @@ atastart(struct ata_channel *chp)
 	ata_channel_lock(chp);
 
 again:
-	KASSERT(chq->queue_active <= chq->queue_openings);
-	if (chq->queue_active == chq->queue_openings) {
-		ATADEBUG_PRINT(("%s(chp=%p): channel %d completely busy\n",
-		    __func__, chp, chp->ch_channel), DEBUG_XFERS);
-		goto out;
-	}
-
 	/* is there a xfer ? */
 	if ((xfer = SIMPLEQ_FIRST(&chp->ch_queue->queue_xfer)) == NULL) {
 		ATADEBUG_PRINT(("%s(chp=%p): channel %d queue_xfer is empty\n",
@@ -1142,6 +1137,18 @@ again:
 		goto out;
 	}
 
+	/*
+	 * if someone is waiting for the command to be active, wake it up
+	 * and let it process the command
+	 */
+	if (__predict_false(xfer->c_flags & C_WAITACT)) {
+		ATADEBUG_PRINT(("atastart: xfer %p channel %d drive %d "
+		    "wait active\n", xfer, chp->ch_channel, xfer->c_drive),
+		    DEBUG_XFERS);
+		cv_broadcast(&chp->ch_queue->c_active);
+		goto out;
+	}
+
 	recovery = ISSET(xfer->c_flags, C_RECOVERY);
 
 	/* is the queue frozen? */
@@ -1179,20 +1186,37 @@ again:
 	struct ata_drive_datas * const drvp = &chp->ch_drive[xfer->c_drive];
 
 	/*
-	 * if someone is waiting for the command to be active, wake it up
-	 * and let it process the command
+	 * Are we on limit of active xfers ?
+	 * For recovery, we must leave one slot available at all times.
 	 */
-	if (xfer->c_flags & C_WAITACT) {
-		ATADEBUG_PRINT(("atastart: xfer %p channel %d drive %d "
-		    "wait active\n", xfer, chp->ch_channel, xfer->c_drive),
-		    DEBUG_XFERS);
-		cv_broadcast(&chp->ch_queue->c_active);
+	KASSERT(chq->queue_active <= chq->queue_openings);
+	const uint8_t chq_openings = (!recovery && chq->queue_openings > 1)
+	    ? (chq->queue_openings - 1) : chq->queue_openings;
+	const uint8_t drv_openings = ISSET(xfer->c_flags, C_NCQ)
+	    ? drvp->drv_openings : ATA_MAX_OPENINGS;
+	if (chq->queue_active >= MIN(chq_openings, drv_openings)) {
+		if (recovery) {
+			panic("%s: channel %d busy, recovery not possible",
+			    __func__, chp->ch_channel);
+		}
+
+		ATADEBUG_PRINT(("%s(chp=%p): channel %d completely busy\n",
+		    __func__, chp, chp->ch_channel), DEBUG_XFERS);
 		goto out;
 	}
 
-	if (atac->atac_claim_hw)
-		if (!atac->atac_claim_hw(chp, 0))
+	/* Slot allocation can fail if drv_openings < ch_openings */
+	if (!ata_queue_alloc_slot(chp, &xfer->c_slot, drv_openings))
+		goto out;
+
+	if (__predict_false(atac->atac_claim_hw)) {
+		if (!atac->atac_claim_hw(chp, 0)) {
+			ata_queue_free_slot(chp, xfer->c_slot);
 			goto out;
+		}
+	}
+
+	/* Now committed to start the xfer */
 
 	ATADEBUG_PRINT(("%s(chp=%p): xfer %p channel %d drive %d\n",
 	    __func__, chp, xfer, chp->ch_channel, xfer->c_drive), DEBUG_XFERS);
@@ -1273,7 +1297,13 @@ ata_activate_xfer_locked(struct ata_chan
 
 	KASSERT(mutex_owned(&chp->ch_lock));
 
-	KASSERT(chq->queue_active < chq->queue_openings);
+	/*
+	 * When openings is just 1, can't reserve anything for
+	 * recovery. KASSERT() here is to catch code which naively
+	 * relies on C_RECOVERY to work under this condition.
+	 */
+	KASSERT((xfer->c_flags & C_RECOVERY) == 0 || chq->queue_openings > 1);
+
 	KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0);
 
 	if ((xfer->c_flags & C_RECOVERY) == 0)
@@ -1290,6 +1320,64 @@ ata_activate_xfer_locked(struct ata_chan
 	chq->queue_active++;
 }
 
+/*
+ * Does it's own locking, does not require splbio().
+ * flags - whether to block waiting for free xfer
+ */
+struct ata_xfer *
+ata_get_xfer(struct ata_channel *chp, bool waitok)
+{
+	struct ata_xfer *xfer;
+
+	xfer = pool_get(&ata_xfer_pool, waitok ? PR_WAITOK : PR_NOWAIT);
+	KASSERT(!waitok || xfer != NULL);
+
+	if (xfer != NULL) {
+		/* zero everything */
+		memset(xfer, 0, sizeof(*xfer));
+	}
+
+	return xfer;
+}
+
+/*
+ * ata_deactivate_xfer() must be always called prior to ata_free_xfer()
+ */
+void
+ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+	struct ata_queue *chq = chp->ch_queue;
+
+	ata_channel_lock(chp);
+
+	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_broadcast(&chq->c_active);
+		ata_channel_unlock(chp);
+		return;
+	}
+
+	/* XXX move PIOBM and free_gw to deactivate? */
+#if NATA_PIOBM		/* XXX wdc dependent code */
+	if (xfer->c_flags & C_PIOBM) {
+		struct wdc_softc *wdc = CHAN_TO_WDC(chp);
+
+		/* finish the busmastering PIO */
+		(*wdc->piobm_done)(wdc->dma_arg,
+		    chp->ch_channel, xfer->c_drive);
+		chp->ch_flags &= ~(ATACH_DMA_WAIT | ATACH_PIOBM_WAIT | ATACH_IRQ_WAIT);
+	}
+#endif
+
+	if (__predict_false(chp->ch_atac->atac_free_hw))
+		chp->ch_atac->atac_free_hw(chp);
+ 
+	ata_channel_unlock(chp);
+
+	pool_put(&ata_xfer_pool, xfer);
+}
+
 void
 ata_deactivate_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
 {
@@ -1311,6 +1399,8 @@ ata_deactivate_xfer(struct ata_channel *
 	chq->active_xfers_used &= ~__BIT(xfer->c_slot);
 	chq->queue_active--;
 
+	ata_queue_free_slot(chp, xfer->c_slot);
+
 	if (xfer->c_flags & C_WAIT)
 		cv_broadcast(&chq->c_cmd_finish);
 

Index: src/sys/dev/ata/ata_subr.c
diff -u src/sys/dev/ata/ata_subr.c:1.6.2.4 src/sys/dev/ata/ata_subr.c:1.6.2.5
--- src/sys/dev/ata/ata_subr.c:1.6.2.4	Mon Sep 17 20:54:41 2018
+++ src/sys/dev/ata/ata_subr.c	Sat Sep 22 09:22:59 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata_subr.c,v 1.6.2.4 2018/09/17 20:54:41 jdolecek Exp $	*/
+/*	$NetBSD: ata_subr.c,v 1.6.2.5 2018/09/22 09:22:59 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -25,14 +25,13 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.6.2.4 2018/09/17 20:54:41 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.6.2.5 2018/09/22 09:22:59 jdolecek Exp $");
 
 #include "opt_ata.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
-#include <sys/malloc.h>
 #include <sys/device.h>
 #include <sys/conf.h>
 #include <sys/fcntl.h>
@@ -167,37 +166,30 @@ ata_queue_alloc(uint8_t openings)
 	if (openings > ATA_MAX_OPENINGS)
 		openings = ATA_MAX_OPENINGS;
 
-	/* XXX convert to kmem_zalloc() once ata_xfer is moved to pool */
-	struct ata_queue *chq = malloc(offsetof(struct ata_queue, queue_xfers[openings]),
-	    M_DEVBUF, M_WAITOK | M_ZERO);
+	struct ata_queue *chq = kmem_zalloc(sizeof(*chq), KM_SLEEP);
 
 	chq->queue_openings = openings;
 	ata_queue_reset(chq);
 
-	cv_init(&chq->queue_busy, "ataqbusy");
 	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++)
-		chq->queue_xfers[i].c_slot = i;
-
 	return chq;
 }
 
 void
 ata_queue_free(struct ata_queue *chq)
 {
-	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);
+	kmem_free(chq, sizeof(*chq));
 }
 
 void
@@ -231,135 +223,6 @@ ata_channel_destroy(struct ata_channel *
 	cv_destroy(&chp->ch_thr_idle);
 }
 
-/*
- * Does it's own locking, does not require splbio().
- * flags - whether to block waiting for free xfer
- * openings - limit of openings supported by device, <= 0 means tag not
- *     relevant, and any available xfer can be returned
- */
-struct ata_xfer *
-ata_get_xfer_ext(struct ata_channel *chp, int flags, uint8_t openings)
-{
-	struct ata_queue *chq = chp->ch_queue;
-	struct ata_xfer *xfer = NULL;
-	uint32_t avail, slot, mask;
-	int error;
-
-	ATADEBUG_PRINT(("%s: channel %d fl 0x%x op %d qavail 0x%x qact %d",
-	    __func__, chp->ch_channel, flags, openings,
-	    chq->queue_xfers_avail, chq->queue_active),
-	    DEBUG_XFERS);
-
-	ata_channel_lock(chp);
-
-	/*
-	 * When openings is just 1, can't reserve anything for
-	 * recovery. KASSERT() here is to catch code which naively
-	 * relies on C_RECOVERY to work under this condition.
-	 */
-	KASSERT((flags & C_RECOVERY) == 0 || chq->queue_openings > 1);
-
-	if (flags & C_RECOVERY) {
-		mask = UINT32_MAX;
-	} else {
-		if (openings <= 0 || openings > chq->queue_openings)
-			openings = chq->queue_openings;
-
-		if (openings > 1) {
-			mask = __BIT(openings - 1) - 1;
-		} else {
-			mask = UINT32_MAX;
-		}
-	}
-
-retry:
-	avail = ffs32(chq->queue_xfers_avail & mask);
-	if (avail == 0) {
-		/*
-		 * Catch code which tries to get another recovery xfer while
-		 * already holding one (wrong recursion).
-		 */
-		KASSERTMSG((flags & C_RECOVERY) == 0,
-		    "recovery xfer busy openings %d mask %x avail %x",
-		    openings, mask, chq->queue_xfers_avail);
-
-		if (flags & C_WAIT) {
-			chq->queue_flags |= QF_NEED_XFER;
-			error = cv_wait_sig(&chq->queue_busy, &chp->ch_lock);
-			if (error == 0)
-				goto retry;
-		}
-
-		goto out;
-	}
-
-	slot = avail - 1;
-	xfer = &chq->queue_xfers[slot];
-	chq->queue_xfers_avail &= ~__BIT(slot);
-
-	KASSERT((chq->active_xfers_used & __BIT(slot)) == 0);
-
-	/* zero everything after the callout member */
-	memset(&xfer->c_startzero, 0,
-	    sizeof(struct ata_xfer) - offsetof(struct ata_xfer, c_startzero));
-
-out:
-	ata_channel_unlock(chp);
-
-	ATADEBUG_PRINT((" xfer %p\n", xfer), DEBUG_XFERS);
-	return xfer;
-}
-
-/*
- * ata_deactivate_xfer() must be always called prior to ata_free_xfer()
- */
-void
-ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
-{
-	struct ata_queue *chq = chp->ch_queue;
-
-	ata_channel_lock(chp);
-
-	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_broadcast(&chq->c_active);
-		goto out;
-	}
-
-	/* XXX move PIOBM and free_gw to deactivate? */
-#if NATA_PIOBM		/* XXX wdc dependent code */
-	if (xfer->c_flags & C_PIOBM) {
-		struct wdc_softc *wdc = CHAN_TO_WDC(chp);
-
-		/* finish the busmastering PIO */
-		(*wdc->piobm_done)(wdc->dma_arg,
-		    chp->ch_channel, xfer->c_drive);
-		chp->ch_flags &= ~(ATACH_DMA_WAIT | ATACH_PIOBM_WAIT | ATACH_IRQ_WAIT);
-	}
-#endif
-
-	if (chp->ch_atac->atac_free_hw)
-		chp->ch_atac->atac_free_hw(chp);
- 
-	KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0);
-	KASSERT((chq->queue_xfers_avail & __BIT(xfer->c_slot)) == 0);
-	chq->queue_xfers_avail |= __BIT(xfer->c_slot);
-
-out:
-	if (chq->queue_flags & QF_NEED_XFER) {
-		chq->queue_flags &= ~QF_NEED_XFER;
-		cv_broadcast(&chq->queue_busy);
-	}
-
-	ata_channel_unlock(chp);
-
-	ATADEBUG_PRINT(("%s: channel %d xfer %p qavail 0x%x qact %d\n",
-	    __func__, chp->ch_channel, xfer, chq->queue_xfers_avail,
-	    chq->queue_active),
-	    DEBUG_XFERS);
-}
-
 void
 ata_timeout(void *v)
 {
@@ -472,18 +335,49 @@ atachannel_debug(struct ata_channel *chp
 	    chq->queue_flags, chq->queue_xfers_avail, chq->active_xfers_used);
 	printf("        act %d freez %d open %u\n",
 	    chq->queue_active, chq->queue_freeze, chq->queue_openings);
-
-#if 0
-	printf("  xfers:\n");
-	for(int i=0; i < chq->queue_openings; i++) {
-		struct ata_xfer *xfer = &chq->queue_xfers[i];
-
-		printf("    #%d sl %d drv %d retr %d fl %x",
-		    i, xfer->c_slot, xfer->c_drive, xfer->c_retries,
-		    xfer->c_flags);
-		printf(" data %p bcount %d skip %d\n",
-		    xfer->c_databuf, xfer->c_bcount, xfer->c_skip);
-	}
-#endif
 }
 #endif /* ATADEBUG */
+
+bool
+ata_queue_alloc_slot(struct ata_channel *chp, uint8_t *c_slot,
+    uint8_t drv_openings)
+{
+	struct ata_queue *chq = chp->ch_queue;
+	uint32_t avail, mask;
+
+	KASSERT(mutex_owned(&chp->ch_lock));
+	KASSERT(chq->queue_active < chq->queue_openings);
+
+	ATADEBUG_PRINT(("%s: channel %d qavail 0x%x qact %d",
+	    __func__, chp->ch_channel,
+	    chq->queue_xfers_avail, chq->queue_active),
+	    DEBUG_XFERS);
+
+	mask = __BIT(MIN(chq->queue_openings, drv_openings)) - 1;
+
+	avail = ffs32(chq->queue_xfers_avail & mask);
+	if (avail == 0)
+		return false;
+
+	KASSERT(avail > 0);
+	KASSERT(avail <= drv_openings);
+
+	*c_slot = avail - 1;
+	chq->queue_xfers_avail &= ~__BIT(*c_slot);
+
+	KASSERT((chq->active_xfers_used & __BIT(*c_slot)) == 0);
+	return true;
+}
+
+void
+ata_queue_free_slot(struct ata_channel *chp, uint8_t c_slot)
+{
+	struct ata_queue *chq = chp->ch_queue;
+
+	KASSERT(mutex_owned(&chp->ch_lock));
+
+	KASSERT((chq->active_xfers_used & __BIT(c_slot)) == 0);
+	KASSERT((chq->queue_xfers_avail & __BIT(c_slot)) == 0);
+
+	chq->queue_xfers_avail |= __BIT(c_slot);
+}

Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.99.2.4 src/sys/dev/ata/atavar.h:1.99.2.5
--- src/sys/dev/ata/atavar.h:1.99.2.4	Mon Sep 17 19:30:25 2018
+++ src/sys/dev/ata/atavar.h	Sat Sep 22 09:22:59 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: atavar.h,v 1.99.2.4 2018/09/17 19:30:25 jdolecek Exp $	*/
+/*	$NetBSD: atavar.h,v 1.99.2.5 2018/09/22 09:22:59 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -134,7 +134,6 @@ struct ata_xfer_ops;
 struct ata_xfer {
 	int8_t c_slot;			/* queue slot # */
 
-#define c_startzero	c_chp
 	/* Channel and drive that are to process the request. */
 	struct ata_channel *c_chp;
 	uint16_t	c_drive;
@@ -228,7 +227,6 @@ struct ata_queue {
 	uint8_t queue_openings;			/* max number of active xfers */
 	SIMPLEQ_HEAD(, ata_xfer) queue_xfer; 	/* queue of pending commands */
 	int queue_freeze; 			/* freeze count for the queue */
-	kcondvar_t queue_busy;			/* c: waiting of xfer */
 	kcondvar_t queue_drain;			/* c: waiting of queue drain */
 	kcondvar_t queue_idle;			/* c: waiting of queue idle */
 	TAILQ_HEAD(, ata_xfer) active_xfers; 	/* active commands */
@@ -236,7 +234,6 @@ struct ata_queue {
 	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
 
@@ -340,6 +337,7 @@ struct ata_drive_datas {
 	daddr_t	badsect[127];	/* 126 plus trailing -1 marker */
 
 	/* Recovery buffer */
+	struct ata_xfer recovery_xfer;
 	uint8_t recovery_blk[ATA_BSIZE];
 };
 
@@ -534,8 +532,7 @@ int	ata_read_log_ext_ncq(struct ata_driv
 #define CMD_ERR   1
 #define CMD_AGAIN 2
 
-struct ata_xfer *ata_get_xfer_ext(struct ata_channel *, int, uint8_t);
-#define ata_get_xfer(chp) ata_get_xfer_ext((chp), C_WAIT, 0)
+struct ata_xfer *ata_get_xfer(struct ata_channel *, bool);
 void	ata_free_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 *);
@@ -578,6 +575,8 @@ struct ata_xfer *
 	ata_queue_get_active_xfer_locked(struct ata_channel *);
 struct ata_xfer *
 	ata_queue_drive_active_xfer(struct ata_channel *, int);
+bool	ata_queue_alloc_slot(struct ata_channel *, uint8_t *, uint8_t);
+void	ata_queue_free_slot(struct ata_channel *, uint8_t);
 
 void	ata_delay(struct ata_channel *, int, const char *, int);
 

Index: src/sys/dev/ata/satapmp_subr.c
diff -u src/sys/dev/ata/satapmp_subr.c:1.14 src/sys/dev/ata/satapmp_subr.c:1.14.2.1
--- src/sys/dev/ata/satapmp_subr.c:1.14	Sun Jul 29 14:11:30 2018
+++ src/sys/dev/ata/satapmp_subr.c	Sat Sep 22 09:22:59 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: satapmp_subr.c,v 1.14 2018/07/29 14:11:30 jdolecek Exp $	*/
+/*	$NetBSD: satapmp_subr.c,v 1.14.2.1 2018/09/22 09:22:59 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 2012 Manuel Bouyer.  All rights reserved.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: satapmp_subr.c,v 1.14 2018/07/29 14:11:30 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: satapmp_subr.c,v 1.14.2.1 2018/09/22 09:22:59 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -276,7 +276,7 @@ satapmp_attach(struct ata_channel *chp)
 	uint32_t id, rev, inf;
 	struct ata_xfer *xfer;
 
-	xfer = ata_get_xfer(chp);
+	xfer = ata_get_xfer(chp, false);
 	if (xfer == NULL) {
 		aprint_normal_dev(chp->atabus, "no available xfer\n");
 		return;

Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.441.2.3 src/sys/dev/ata/wd.c:1.441.2.4
--- src/sys/dev/ata/wd.c:1.441.2.3	Mon Sep 17 20:54:41 2018
+++ src/sys/dev/ata/wd.c	Sat Sep 22 09:22:59 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: wd.c,v 1.441.2.3 2018/09/17 20:54:41 jdolecek Exp $ */
+/*	$NetBSD: wd.c,v 1.441.2.4 2018/09/22 09:22:59 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.2.3 2018/09/17 20:54:41 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.441.2.4 2018/09/22 09:22:59 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wd.h"
@@ -745,8 +745,7 @@ wd_diskstart(device_t dev, struct buf *b
 
 	mutex_enter(&wd->sc_lock);
 
-	xfer = ata_get_xfer_ext(wd->drvp->chnl_softc, 0,
-	    WD_USE_NCQ(wd) ? WD_MAX_OPENINGS(wd) : 0);
+	xfer = ata_get_xfer(wd->drvp->chnl_softc, false);
 	if (xfer == NULL) {
 		ATADEBUG_PRINT(("wd_diskstart %s no xfer\n",
 		    dksc->sc_xname), DEBUG_XFERS);
@@ -776,22 +775,6 @@ wdstart(device_t self)
 	if (!device_is_active(dksc->sc_dev))
 		return;
 
-	mutex_enter(&wd->sc_lock);
-
-	/*
-	 * Do not queue any transfers until flush is finished, so that
-	 * once flush is pending, it will get handled as soon as xfer
-	 * is available.
-	 */
-	if (ISSET(wd->sc_flags, WDF_FLUSH_PEND)) {
-		ATADEBUG_PRINT(("wdstart %s flush pend\n",
-		    dksc->sc_xname), DEBUG_XFERS);
-		mutex_exit(&wd->sc_lock);
-		return;
-	}
-
-	mutex_exit(&wd->sc_lock);
-
 	dk_start(dksc, NULL);
 }
 
@@ -1486,7 +1469,7 @@ wd_dumpblocks(device_t dev, void *va, da
 		wd->drvp->state = RESET;
 	}
 
-	xfer = ata_get_xfer_ext(wd->drvp->chnl_softc, 0, 0);
+	xfer = ata_get_xfer(wd->drvp->chnl_softc, false);
 	if (xfer == NULL) {
 		printf("%s: no xfer\n", __func__);
 		return EAGAIN;
@@ -1677,9 +1660,7 @@ wd_setcache(struct wd_softc *wd, int bit
 	    (bits & DKCACHE_SAVE) != 0)
 		return EOPNOTSUPP;
 
-	xfer = ata_get_xfer(wd->drvp->chnl_softc);
-	if (xfer == NULL)
-		return EINTR;
+	xfer = ata_get_xfer(wd->drvp->chnl_softc, true);
 
 	xfer->c_ata_c.r_command = SET_FEATURES;
 	xfer->c_ata_c.r_st_bmask = 0;
@@ -1720,9 +1701,7 @@ wd_standby(struct wd_softc *wd, int flag
 	struct ata_xfer *xfer;
 	int error;
 
-	xfer = ata_get_xfer(wd->drvp->chnl_softc);
-	if (xfer == NULL)
-		return EINTR;
+	xfer = ata_get_xfer(wd->drvp->chnl_softc, true);
 
 	xfer->c_ata_c.r_command = WDCC_STANDBY_IMMED;
 	xfer->c_ata_c.r_st_bmask = WDCS_DRDY;
@@ -1779,20 +1758,7 @@ wd_flushcache(struct wd_softc *wd, int f
 	    wd->sc_params.atap_cmd_set2 == 0xffff))
 		return ENODEV;
 
-	mutex_enter(&wd->sc_lock);
-	SET(wd->sc_flags, WDF_FLUSH_PEND);
-	mutex_exit(&wd->sc_lock);
-
-	xfer = ata_get_xfer(wd->drvp->chnl_softc);
-
-	mutex_enter(&wd->sc_lock);
-	CLR(wd->sc_flags, WDF_FLUSH_PEND);
-	mutex_exit(&wd->sc_lock);
-
-	if (xfer == NULL) {
-		error = EINTR;
-		goto out;
-	}
+	xfer = ata_get_xfer(wd->drvp->chnl_softc, true);
 
 	if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0 &&
 	    (wd->sc_params.atap_cmd2_en & ATA_CMD2_FCE) != 0) {
@@ -1830,7 +1796,6 @@ wd_flushcache(struct wd_softc *wd, int f
 out_xfer:
 	ata_free_xfer(wd->drvp->chnl_softc, xfer);
 
-out:
 	/* start again I/O processing possibly stopped due to no xfer */
 	ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive, start_self);
 
@@ -1845,9 +1810,7 @@ wd_trim(struct wd_softc *wd, daddr_t bno
 	int error;
 	unsigned char *req;
 
-	xfer = ata_get_xfer(wd->drvp->chnl_softc);
-	if (xfer == NULL)
-		return EINTR;
+	xfer = ata_get_xfer(wd->drvp->chnl_softc, true);
 
 	req = kmem_zalloc(512, KM_SLEEP);
 	req[0] = bno & 0xff;
@@ -2012,11 +1975,7 @@ wdioctlstrategy(struct buf *bp)
 		goto out2;
 	}
 
-	xfer = ata_get_xfer(wi->wi_softc->drvp->chnl_softc);
-	if (xfer == NULL) {
-		error = EINTR;
-		goto out2;
-	}
+	xfer = ata_get_xfer(wi->wi_softc->drvp->chnl_softc, true);
 
 	/*
 	 * Abort if physio broke up the transfer
@@ -2134,19 +2093,6 @@ wd_sysctl_attach(struct wd_softc *wd)
 		return;
 	}
 
-	wd->drv_max_tags = ATA_MAX_OPENINGS;
-	if ((error = sysctl_createv(&wd->nodelog, 0, NULL, NULL,
-				CTLFLAG_READWRITE, CTLTYPE_INT, "max_tags",
-				SYSCTL_DESCR("max number of NCQ tags to use"),
-				NULL, 0, &wd->drv_max_tags, 0,
-				CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL))
-				!= 0) {
-		aprint_error_dev(dksc->sc_dev,
-		    "could not create %s.%s.max_tags sysctl - error %d\n",
-		    "hw", dksc->sc_xname, error);
-		return;
-	}
-
 	wd->drv_ncq = true;
 	if ((error = sysctl_createv(&wd->nodelog, 0, NULL, NULL,
 				CTLFLAG_READWRITE, CTLTYPE_BOOL, "use_ncq",

Index: src/sys/dev/ata/wdvar.h
diff -u src/sys/dev/ata/wdvar.h:1.46.6.1 src/sys/dev/ata/wdvar.h:1.46.6.2
--- src/sys/dev/ata/wdvar.h:1.46.6.1	Fri Aug 31 19:08:03 2018
+++ src/sys/dev/ata/wdvar.h	Sat Sep 22 09:22:59 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdvar.h,v 1.46.6.1 2018/08/31 19:08:03 jdolecek Exp $	*/
+/*	$NetBSD: wdvar.h,v 1.46.6.2 2018/09/22 09:22:59 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -53,7 +53,6 @@ struct wd_softc {
 #define WDF_WAIT	0x020 /* waiting for resources */
 #define WDF_LBA		0x040 /* using LBA mode */
 #define WDF_LBA48	0x100 /* using 48-bit LBA mode */
-#define WDF_FLUSH_PEND	0x200 /* cache flush waits for free xfer */
 #define WDF_OPEN	0x400 /* device is open */
 	uint64_t sc_capacity; /* full capacity of the device */
 	uint64_t sc_capacity512; /* ... in DEV_BSIZE blocks */
@@ -74,9 +73,6 @@ struct wd_softc {
 
 	/* Sysctl nodes specific for the disk */
 	struct sysctllog *nodelog;
-	int drv_max_tags;
-#define WD_MAX_OPENINGS(wd)	\
-	(MAX(1, MIN((wd)->drvp->drv_openings, (wd)->drv_max_tags)))
 	bool drv_ncq;
 #define WD_USE_NCQ(wd)	\
 	((wd)->drv_ncq && ((wd)->drvp->drive_flags & ATA_DRIVE_NCQ))

Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.62.2.4 src/sys/dev/ic/ahcisata_core.c:1.62.2.5
--- src/sys/dev/ic/ahcisata_core.c:1.62.2.4	Mon Sep 17 19:30:25 2018
+++ src/sys/dev/ic/ahcisata_core.c	Sat Sep 22 09:22:59 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisata_core.c,v 1.62.2.4 2018/09/17 19:30:25 jdolecek Exp $	*/
+/*	$NetBSD: ahcisata_core.c,v 1.62.2.5 2018/09/22 09:22:59 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.2.4 2018/09/17 19:30:25 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.62.2.5 2018/09/22 09:22:59 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -59,7 +59,7 @@ static void ahci_setup_channel(struct at
 
 static int  ahci_ata_bio(struct ata_drive_datas *, struct ata_xfer *);
 static int  ahci_do_reset_drive(struct ata_channel *, int, int, uint32_t *,
-	struct ata_xfer *xfer);
+	uint8_t);
 static void ahci_reset_drive(struct ata_drive_datas *, int, uint32_t *);
 static void ahci_reset_channel(struct ata_channel *, int);
 static int  ahci_exec_command(struct ata_drive_datas *, struct ata_xfer *);
@@ -681,24 +681,28 @@ ahci_reset_drive(struct ata_drive_datas 
 {
 	struct ata_channel *chp = drvp->chnl_softc;
 	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
-	struct ata_xfer *xfer;
-
-	xfer = ata_get_xfer_ext(chp, C_RECOVERY, 0);
+	uint8_t c_slot;
 
 	ata_channel_lock(chp);
 
+	/* get a slot for running the command on */
+	if (!ata_queue_alloc_slot(chp, &c_slot, ATA_MAX_OPENINGS)) {
+		panic("%s: %s: failed to get xfer for reset, port %d\n",
+		    device_xname(sc->sc_atac.atac_dev),
+		    __func__, chp->ch_channel);
+		/* NOTREACHED */
+	}
+
 	AHCI_WRITE(sc, AHCI_GHC,
 	    AHCI_READ(sc, AHCI_GHC) & ~AHCI_GHC_IE);
 	ahci_channel_stop(sc, chp, flags);
-	if (ahci_do_reset_drive(chp, drvp->drive, flags, sigp, xfer) != 0)
+	if (ahci_do_reset_drive(chp, drvp->drive, flags, sigp, c_slot) != 0)
 		ata_reset_channel(chp, flags);
 	AHCI_WRITE(sc, AHCI_GHC, AHCI_READ(sc, AHCI_GHC) | AHCI_GHC_IE);
 
-	ata_channel_unlock(chp);
-
-	ata_free_xfer(chp, xfer);
+	ata_queue_free_slot(chp, c_slot);
 
-	return;
+	ata_channel_unlock(chp);
 }
 
 /* return error code from ata_bio */
@@ -755,7 +759,7 @@ ahci_exec_fis(struct ata_channel *chp, i
 
 static int
 ahci_do_reset_drive(struct ata_channel *chp, int drive, int flags,
-    uint32_t *sigp, struct ata_xfer *xfer)
+    uint32_t *sigp, uint8_t c_slot)
 {
 	struct ahci_channel *achp = (struct ahci_channel *)chp;
 	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
@@ -790,8 +794,8 @@ again:
 
 	/* polled command, assume interrupts are disabled */
 
-	cmd_h = &achp->ahcic_cmdh[xfer->c_slot];
-	cmd_tbl = achp->ahcic_cmd_tbl[xfer->c_slot];
+	cmd_h = &achp->ahcic_cmdh[c_slot];
+	cmd_tbl = achp->ahcic_cmd_tbl[c_slot];
 	cmd_h->cmdh_flags = htole16(AHCI_CMDH_F_RST | AHCI_CMDH_F_CBSY |
 	    RHD_FISLEN / 4 | (drive << AHCI_CMDH_F_PMP_SHIFT));
 	cmd_h->cmdh_prdbc = 0;
@@ -799,7 +803,7 @@ again:
 	cmd_tbl->cmdt_cfis[fis_type] = RHD_FISTYPE;
 	cmd_tbl->cmdt_cfis[rhd_c] = drive;
 	cmd_tbl->cmdt_cfis[rhd_control] = WDCTL_RST;
-	switch(ahci_exec_fis(chp, 100, flags, xfer->c_slot)) {
+	switch(ahci_exec_fis(chp, 100, flags, c_slot)) {
 	case ERR_DF:
 	case TIMEOUT:
 		aprint_error("%s channel %d: setting WDCTL_RST failed "
@@ -817,7 +821,7 @@ again:
 	cmd_tbl->cmdt_cfis[fis_type] = RHD_FISTYPE;
 	cmd_tbl->cmdt_cfis[rhd_c] = drive;
 	cmd_tbl->cmdt_cfis[rhd_control] = 0;
-	switch(ahci_exec_fis(chp, 310, flags, xfer->c_slot)) {
+	switch(ahci_exec_fis(chp, 310, flags, c_slot)) {
 	case ERR_DF:
 	case TIMEOUT:
 		if ((sc->sc_ahci_quirks & AHCI_QUIRK_BADPMPRESET) != 0 &&
@@ -943,17 +947,18 @@ ahci_probe_drive(struct ata_channel *chp
 	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
 	struct ahci_channel *achp = (struct ahci_channel *)chp;
 	uint32_t sig;
-	struct ata_xfer *xfer;
+	uint8_t c_slot;
+
+	ata_channel_lock(chp);
 
-	xfer = ata_get_xfer_ext(chp, 0, 0);
-	if (xfer == NULL) {
+	/* get a slot for running the command on */
+	if (!ata_queue_alloc_slot(chp, &c_slot, ATA_MAX_OPENINGS)) {
 		aprint_error_dev(sc->sc_atac.atac_dev,
 		    "%s: failed to get xfer port %d\n",
 		    __func__, chp->ch_channel);
+		ata_channel_unlock(chp);
 		return;
-        }
-
-	ata_channel_lock(chp);
+	}
 
 	/* bring interface up, accept FISs, power up and spin up device */
 	AHCI_WRITE(sc, AHCI_P_CMD(chp->ch_channel),
@@ -966,9 +971,9 @@ ahci_probe_drive(struct ata_channel *chp
 		ata_delay(chp, 500, "ahcidv", AT_WAIT);
 		if (sc->sc_ahci_cap & AHCI_CAP_SPM) {
 			ahci_do_reset_drive(chp, PMP_PORT_CTL, AT_WAIT, &sig,
-			    xfer);
+			    c_slot);
 		} else {
-			ahci_do_reset_drive(chp, 0, AT_WAIT, &sig, xfer);
+			ahci_do_reset_drive(chp, 0, AT_WAIT, &sig, c_slot);
 		}
 		sata_interpret_sig(chp, 0, sig);
 		/* if we have a PMP attached, inform the controller */
@@ -980,7 +985,7 @@ ahci_probe_drive(struct ata_channel *chp
 		}
 		/* clear port interrupt register */
 		AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);
-		
+
 		/* and enable interrupts */
 		AHCI_WRITE(sc, AHCI_P_IE(chp->ch_channel),
 		    AHCI_P_IX_TFES | AHCI_P_IX_HBFS | AHCI_P_IX_HBDS |
@@ -994,6 +999,9 @@ ahci_probe_drive(struct ata_channel *chp
 	default:
 		break;
 	}
+
+	ata_queue_free_slot(chp, c_slot);
+
 	ata_channel_unlock(chp);
 }
 
@@ -1866,7 +1874,7 @@ ahci_atapi_scsipi_request(struct scsipi_
 			scsipi_done(sc_xfer);
 			return;
 		}
-		xfer = ata_get_xfer_ext(atac->atac_channels[channel], 0, 0);
+		xfer = ata_get_xfer(atac->atac_channels[channel], false);
 		if (xfer == NULL) {
 			sc_xfer->error = XS_RESOURCE_SHORTAGE;
 			scsipi_done(sc_xfer);

Index: src/sys/dev/ic/mvsata.c
diff -u src/sys/dev/ic/mvsata.c:1.41.2.3 src/sys/dev/ic/mvsata.c:1.41.2.4
--- src/sys/dev/ic/mvsata.c:1.41.2.3	Mon Sep 17 19:30:25 2018
+++ src/sys/dev/ic/mvsata.c	Sat Sep 22 09:22:59 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: mvsata.c,v 1.41.2.3 2018/09/17 19:30:25 jdolecek Exp $	*/
+/*	$NetBSD: mvsata.c,v 1.41.2.4 2018/09/22 09:22:59 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.2.3 2018/09/17 19:30:25 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.41.2.4 2018/09/22 09:22:59 jdolecek Exp $");
 
 #include "opt_mvsata.h"
 
@@ -2081,7 +2081,7 @@ mvsata_atapi_scsipi_request(struct scsip
 			scsipi_done(sc_xfer);
 			return;
 		}
-		xfer = ata_get_xfer_ext(chp, false, 0);
+		xfer = ata_get_xfer(chp, false);
 		if (xfer == NULL) {
 			sc_xfer->error = XS_RESOURCE_SHORTAGE;
 			scsipi_done(sc_xfer);

Index: src/sys/dev/ic/siisata.c
diff -u src/sys/dev/ic/siisata.c:1.35.6.4 src/sys/dev/ic/siisata.c:1.35.6.5
--- src/sys/dev/ic/siisata.c:1.35.6.4	Mon Sep 17 19:30:26 2018
+++ src/sys/dev/ic/siisata.c	Sat Sep 22 09:22:59 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.35.6.4 2018/09/17 19:30:26 jdolecek Exp $ */
+/* $NetBSD: siisata.c,v 1.35.6.5 2018/09/22 09:22:59 jdolecek Exp $ */
 
 /* from ahcisata_core.c */
 
@@ -79,7 +79,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.35.6.4 2018/09/17 19:30:26 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.35.6.5 2018/09/22 09:22:59 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -725,32 +725,38 @@ siisata_reset_drive(struct ata_drive_dat
 	struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac;
 	struct siisata_channel *schp = (struct siisata_channel *)chp;
 	struct siisata_prb *prb;
-	struct ata_xfer *xfer;
+	uint8_t c_slot;
 	uint32_t pss, pis;
 	int i;
 	bool timed_out;
 
 	siisata_reinit_port(chp, drvp->drive);
 
-	xfer = ata_get_xfer_ext(chp, C_RECOVERY, 0);
+	ata_channel_lock(chp);
 
-	prb = schp->sch_prb[xfer->c_slot];
+	/* get a slot for running the command on */
+	if (!ata_queue_alloc_slot(chp, &c_slot, ATA_MAX_OPENINGS)) {
+		panic("%s: %s: failed to get xfer for reset, port %d\n",
+		    device_xname(sc->sc_atac.atac_dev),
+		    __func__, chp->ch_channel);
+		/* NOTREACHED */
+	}
+
+	prb = schp->sch_prb[c_slot];
 	memset(prb, 0, SIISATA_CMD_SIZE);
 	prb->prb_control =
 	    htole16(PRB_CF_SOFT_RESET | PRB_CF_INTERRUPT_MASK);
 	KASSERT(drvp->drive <= PMP_PORT_CTL);
 	prb->prb_fis[rhd_c] = drvp->drive;
 
-	ata_channel_lock(chp);
-
 	siisata_disable_port_interrupt(chp);
 
-	siisata_activate_prb(schp, xfer->c_slot);
+	siisata_activate_prb(schp, c_slot);
 
 	timed_out = true;
 	for(i = 0; i < WDC_RESET_WAIT / 10; i++) {
 		pss = PRREAD(sc, PRX(chp->ch_channel, PRO_PSS));
-		if ((pss & PR_PXSS(xfer->c_slot)) == 0) {
+		if ((pss & PR_PXSS(c_slot)) == 0) {
 			timed_out = false;
 			break;
 		}
@@ -759,17 +765,17 @@ siisata_reset_drive(struct ata_drive_dat
 		ata_delay(chp, 10, "siiprb", flags);
 	}
 
-	siisata_deactivate_prb(schp, xfer->c_slot);
+	siisata_deactivate_prb(schp, c_slot);
 
 	if ((pss & PR_PSS_ATTENTION) != 0) {
 		pis = PRREAD(sc, PRX(chp->ch_channel, PRO_PIS));
 		const uint32_t ps = PRREAD(sc, PRX(chp->ch_channel, PRO_PS));
 		const u_int slot = PR_PS_ACTIVE_SLOT(ps);
 
-		if (slot != xfer->c_slot)
+		if (slot != c_slot)
 			device_printf(sc->sc_atac.atac_dev, "%s port %d "
 			    "drive %d slot %d c_slot %d", __func__,
-			    chp->ch_channel, drvp->drive, slot, xfer->c_slot);
+			    chp->ch_channel, drvp->drive, slot, c_slot);
 
 		PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS), pis &
 		    PR_PIS_CMDERRR);
@@ -788,14 +794,16 @@ siisata_reset_drive(struct ata_drive_dat
 		/* read the signature out of the FIS */
 		if (sigp) {
 			*sigp = 0;
-			*sigp |= (PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot,
+			*sigp |= (PRREAD(sc, PRSX(chp->ch_channel, c_slot,
 			    PRSO_FIS+0x4)) & 0x00ffffff) << 8;
-			*sigp |= PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot,
+			*sigp |= PRREAD(sc, PRSX(chp->ch_channel, c_slot,
 			    PRSO_FIS+0xc)) & 0xff;
 		}
 	}
 
-	ata_free_xfer(chp, xfer);
+	ata_channel_lock(chp);
+	ata_queue_free_slot(chp, c_slot);
+	ata_channel_unlock(chp);
 
 	return;
 }
@@ -851,21 +859,22 @@ siisata_probe_drive(struct ata_channel *
 	uint32_t sig;
 	struct siisata_prb *prb;
 	bool timed_out;
-	struct ata_xfer *xfer;
+	uint8_t c_slot;
 
 	SIISATA_DEBUG_PRINT(("%s: %s: port %d start\n", SIISATANAME(sc),
 	    __func__, chp->ch_channel), DEBUG_FUNCS);
 
-	xfer = ata_get_xfer_ext(chp, 0, 0);
-	if (xfer == NULL) {
+	ata_channel_lock(chp);
+
+	/* get a slot for running the command on */
+	if (!ata_queue_alloc_slot(chp, &c_slot, ATA_MAX_OPENINGS)) {
 		aprint_error_dev(sc->sc_atac.atac_dev,
 		    "%s: failed to get xfer port %d\n",
 		    __func__, chp->ch_channel);
+		ata_channel_unlock(chp);
 		return;
 	}
 
-	ata_channel_lock(chp);
-
 	/*
 	 * disable port interrupt as we're polling for PHY up and
 	 * prb completion
@@ -897,17 +906,17 @@ siisata_probe_drive(struct ata_channel *
 			siisata_reinit_port(chp, -1);
 		}
 
-		prb = schp->sch_prb[xfer->c_slot];
+		prb = schp->sch_prb[c_slot];
 		memset(prb, 0, SIISATA_CMD_SIZE);
 		prb->prb_control = htole16(PRB_CF_SOFT_RESET);
 		prb->prb_fis[rhd_c] = PMP_PORT_CTL;
 
-		siisata_activate_prb(schp, xfer->c_slot);
+		siisata_activate_prb(schp, c_slot);
 
 		timed_out = 1;
 		for(i = 0; i < WDC_RESET_WAIT / 10; i++) {
 			if ((PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)) &
-			    PR_PXSS(xfer->c_slot)) == 0) {
+			    PR_PXSS(c_slot)) == 0) {
 				/* prb completed */
 				timed_out = 0;
 				break;
@@ -921,7 +930,7 @@ siisata_probe_drive(struct ata_channel *
 			ata_delay(chp, 10, "siiprb", AT_WAIT);
 		}
 
-		siisata_deactivate_prb(schp, xfer->c_slot);
+		siisata_deactivate_prb(schp, c_slot);
 
 		if (timed_out) {
 			aprint_error_dev(sc->sc_atac.atac_dev,
@@ -936,9 +945,9 @@ siisata_probe_drive(struct ata_channel *
 
 		/* read the signature out of the FIS */
 		sig = 0;
-		sig |= (PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot,
+		sig |= (PRREAD(sc, PRSX(chp->ch_channel, c_slot,
 		    PRSO_FIS+0x4)) & 0x00ffffff) << 8;
-		sig |= PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot,
+		sig |= PRREAD(sc, PRSX(chp->ch_channel, c_slot,
 		    PRSO_FIS+0xc)) & 0xff;
 
 		SIISATA_DEBUG_PRINT(("%s: %s: sig=0x%08x\n", SIISATANAME(sc),
@@ -955,9 +964,9 @@ siisata_probe_drive(struct ata_channel *
 
 	siisata_enable_port_interrupt(chp);
 
-	ata_channel_unlock(chp);
+	ata_queue_free_slot(chp, c_slot);
 
-	ata_free_xfer(chp, xfer);
+	ata_channel_unlock(chp);
 
 	SIISATA_DEBUG_PRINT(("%s: %s: port %d done\n", SIISATANAME(sc),
 	    __func__, chp->ch_channel), DEBUG_PROBE);
@@ -1826,7 +1835,7 @@ siisata_atapi_scsipi_request(struct scsi
 			scsipi_done(sc_xfer);
 			return;
 		}
-		xfer = ata_get_xfer_ext(atac->atac_channels[channel], 0, 0);
+		xfer = ata_get_xfer(atac->atac_channels[channel], false);
 		if (xfer == NULL) {
 			sc_xfer->error = XS_RESOURCE_SHORTAGE;
 			scsipi_done(sc_xfer);

Index: src/sys/dev/scsipi/atapi_wdc.c
diff -u src/sys/dev/scsipi/atapi_wdc.c:1.129.6.3 src/sys/dev/scsipi/atapi_wdc.c:1.129.6.4
--- src/sys/dev/scsipi/atapi_wdc.c:1.129.6.3	Mon Sep 17 19:30:26 2018
+++ src/sys/dev/scsipi/atapi_wdc.c	Sat Sep 22 09:22:59 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: atapi_wdc.c,v 1.129.6.3 2018/09/17 19:30:26 jdolecek Exp $	*/
+/*	$NetBSD: atapi_wdc.c,v 1.129.6.4 2018/09/22 09:22:59 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.6.3 2018/09/17 19:30:26 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.129.6.4 2018/09/22 09:22:59 jdolecek Exp $");
 
 #ifndef ATADEBUG
 #define ATADEBUG
@@ -208,7 +208,7 @@ wdc_atapi_get_params(struct scsipi_chann
 	struct ata_xfer *xfer;
 	int rv;
 
-	xfer = ata_get_xfer(chp);
+	xfer = ata_get_xfer(chp, false);
 	if (xfer == NULL) {
 		printf("wdc_atapi_get_params: no xfer\n");
 		return EBUSY;
@@ -395,7 +395,7 @@ wdc_atapi_scsipi_request(struct scsipi_c
 			return;
 		}
 
-		xfer = ata_get_xfer_ext(atac->atac_channels[channel], false, 0);
+		xfer = ata_get_xfer(atac->atac_channels[channel], false);
 		if (xfer == NULL) {
 			sc_xfer->error = XS_RESOURCE_SHORTAGE;
 			scsipi_done(sc_xfer);

Index: src/sys/dev/usb/umass_isdata.c
diff -u src/sys/dev/usb/umass_isdata.c:1.36 src/sys/dev/usb/umass_isdata.c:1.36.6.1
--- src/sys/dev/usb/umass_isdata.c:1.36	Fri Oct 20 07:06:08 2017
+++ src/sys/dev/usb/umass_isdata.c	Sat Sep 22 09:23:00 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: umass_isdata.c,v 1.36 2017/10/20 07:06:08 jdolecek Exp $	*/
+/*	$NetBSD: umass_isdata.c,v 1.36.6.1 2018/09/22 09:23:00 jdolecek Exp $	*/
 
 /*
  * TODO:
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.36 2017/10/20 07:06:08 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.36.6.1 2018/09/22 09:23:00 jdolecek Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -540,7 +540,7 @@ uisdata_get_params(struct ata_drive_data
 	memset(tb, 0, DEV_BSIZE);
 	memset(prms, 0, sizeof(struct ataparams));
 
-	xfer = ata_get_xfer(drvp->chnl_softc);
+	xfer = ata_get_xfer(drvp->chnl_softc, false);
 	if (!xfer) {
 		rv = CMD_AGAIN;
 		goto out;

Reply via email to