Module Name:    src
Committed By:   jdolecek
Date:           Mon Jun 19 21:00:00 UTC 2017

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

Log Message:
add ata_channel lock, use it to protect queue manipulation (only that for now);
add ata_channel_detach() to destroy the locks

change ata_get_xfer() so that it can wait for xfer, convert all on-stack
xfer code to use the blocking variant

fix siisata_reset_drive() to use polled reset and not try ata_activate_xfer(),
convert drive probe code also over from slot0 XXX to ata_get_xfer()

drive reset and PMP now works on siisata(4) too; changes tested also
on piixide(4), ahci(4), mvsata(4)


To generate a diff of this commit:
cvs rdiff -u -r1.1.2.17 -r1.1.2.18 src/sys/dev/ata/TODO.ncq
cvs rdiff -u -r1.132.8.10 -r1.132.8.11 src/sys/dev/ata/ata.c
cvs rdiff -u -r1.92.8.9 -r1.92.8.10 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.12.24.2 -r1.12.24.3 src/sys/dev/ata/satapmp_subr.c
cvs rdiff -u -r1.428.2.17 -r1.428.2.18 src/sys/dev/ata/wd.c
cvs rdiff -u -r1.57.6.13 -r1.57.6.14 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.35.6.11 -r1.35.6.12 src/sys/dev/ic/mvsata.c
cvs rdiff -u -r1.30.4.16 -r1.30.4.17 src/sys/dev/ic/siisata.c
cvs rdiff -u -r1.283.2.5 -r1.283.2.6 src/sys/dev/ic/wdc.c
cvs rdiff -u -r1.123.4.5 -r1.123.4.6 src/sys/dev/scsipi/atapi_wdc.c
cvs rdiff -u -r1.33.4.2 -r1.33.4.3 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.1.2.17 src/sys/dev/ata/TODO.ncq:1.1.2.18
--- src/sys/dev/ata/TODO.ncq:1.1.2.17	Sat Jun 17 19:24:26 2017
+++ src/sys/dev/ata/TODO.ncq	Mon Jun 19 21:00:00 2017
@@ -6,11 +6,11 @@ fix crashdump for mvsata - request times
 siisata - fix all new XXX and unmergable bits, fix PMP
 
 test crashdump with siisata
-
-reset channel and PMP doesn't work with siisata - siisata_reset_drive()
-uses ata_get_xfer() and this can clash on slot 0 with on-stack xfers
+- fails with recursive panic via pmap_kremove_local() regardless if
+  drive connected via PMP or direct
 
 test wd* at umass?, confirm the ata_channel kludge works
++ add detach code (channel detach, free queue)
 
 is ata_exec_xfer() + POLL safe wrt. more outstanding I/Os? why is it waiting
 until xfer is head of queue? also layer violation with the ata_xfer_free() call
@@ -30,6 +30,10 @@ drive rescaned after detach of non-NCQ d
   to have active or pending transfers (e.g. when non-NCQ device is attached
   while there is already NCQ device present)
 
+add mechanics to re-check queue when xfer is finished - needed on PMP
+and for IDE disks, when one drive uses up all available xfers nothing
+ever restarts queue for the other drives
+
 Other random notes (do outside the NCQ branch):
 -----------------------------------------------------
 change wd(4) to use dk_open()

Index: src/sys/dev/ata/ata.c
diff -u src/sys/dev/ata/ata.c:1.132.8.10 src/sys/dev/ata/ata.c:1.132.8.11
--- src/sys/dev/ata/ata.c:1.132.8.10	Sat Jun 17 14:01:36 2017
+++ src/sys/dev/ata/ata.c	Mon Jun 19 21:00:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata.c,v 1.132.8.10 2017/06/17 14:01:36 jdolecek Exp $	*/
+/*	$NetBSD: ata.c,v 1.132.8.11 2017/06/19 21:00:00 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.8.10 2017/06/17 14:01:36 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.11 2017/06/19 21:00:00 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -129,6 +129,9 @@ static bool atabus_resume(device_t, cons
 static bool atabus_suspend(device_t, const pmf_qual_t *);
 static void atabusconfig_thread(void *);
 
+static void ata_xfer_init(struct ata_xfer *, bool);
+static void ata_xfer_destroy(struct ata_xfer *);
+
 /*
  * atabus_init:
  *
@@ -221,7 +224,7 @@ ata_queue_active_xfer_peek(struct ata_qu
 	return TAILQ_FIRST(&chq->active_xfers);
 }
 
-void
+static void
 ata_xfer_init(struct ata_xfer *xfer, bool zero)
 {
 	if (zero)
@@ -230,7 +233,7 @@ ata_xfer_init(struct ata_xfer *xfer, boo
 	callout_init(&xfer->c_timo_callout, 0); 	/* XXX MPSAFE */
 }
 
-void
+static void
 ata_xfer_destroy(struct ata_xfer *xfer)
 {
 	callout_halt(&xfer->c_timo_callout, NULL);	/* XXX MPSAFE */
@@ -257,6 +260,8 @@ ata_queue_alloc(uint8_t openings)
 	chq->queue_openings = openings;
 	ata_queue_reset(chq);
 
+	cv_init(&chq->queue_busy, "ataqbusy");
+
 	for (uint8_t i = 0; i < openings; i++)
 		ata_xfer_init(&chq->queue_xfers[i], false);
 
@@ -283,6 +288,12 @@ ata_queue_free(struct ata_queue *chq)
 	free(chq, M_DEVBUF);
 }
 
+void
+ata_channel_init(struct ata_channel *chp)
+{
+	mutex_init(&chp->ch_lock, MUTEX_DEFAULT, IPL_BIO);
+}
+
 /*
  * ata_channel_attach:
  *
@@ -291,17 +302,37 @@ ata_queue_free(struct ata_queue *chq)
 void
 ata_channel_attach(struct ata_channel *chp)
 {
-	struct ata_queue * const chq = chp->ch_queue;
-
 	if (chp->ch_flags & ATACH_DISABLED)
 		return;
 
-	ata_queue_reset(chq);
+	KASSERT(chp->ch_queue != NULL);
+
+	ata_channel_init(chp);
 
 	chp->atabus = config_found_ia(chp->ch_atac->atac_dev, "ata", chp,
 		atabusprint);
 }
 
+void
+ata_channel_destroy(struct ata_channel *chp)
+{
+	mutex_destroy(&chp->ch_lock);
+}
+
+/*
+ * ata_channel_detach:
+ *
+ *	Common parts of detaching an atabus to an ATA controller channel.
+ */
+void
+ata_channel_detach(struct ata_channel *chp)
+{
+	if (chp->ch_flags & ATACH_DISABLED)
+		return;
+
+	ata_channel_destroy(chp);
+}
+
 static void
 atabusconfig(struct atabus_softc *atabus_sc)
 {
@@ -1130,17 +1161,27 @@ atastart(struct ata_channel *chp)
 }
 
 struct ata_xfer *
-ata_get_xfer(struct ata_channel *chp)
+ata_get_xfer(struct ata_channel *chp, bool wait)
 {
 	struct ata_queue *chq = chp->ch_queue;
 	struct ata_xfer *xfer = NULL;
-	int s;
 	uint32_t avail, slot;
+	int error;
 
-	s = splbio();
+	mutex_enter(&chp->ch_lock);
+
+retry:
 	avail = ffs32(chq->queue_xfers_avail);
-	if (avail == 0)
+	if (avail == 0) {
+		if (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];
@@ -1154,7 +1195,7 @@ ata_get_xfer(struct ata_channel *chp)
 	xfer->c_slot = slot;
 
 out:
-	splx(s);
+	mutex_exit(&chp->ch_lock);
 	return xfer;
 }
 
@@ -1165,13 +1206,14 @@ void
 ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
 {
 	struct ata_queue *chq = chp->ch_queue;
-	int s;
+
+	mutex_enter(&chp->ch_lock);
 
 	if (xfer->c_flags & C_WAITACT) {
 		/* Someone is waiting for this xfer, so we can't free now */
 		xfer->c_flags |= C_FREE;
 		wakeup(xfer);
-		return;
+		goto out;
 	}
 
 #if NATA_PIOBM		/* XXX wdc dependent code */
@@ -1185,11 +1227,17 @@ ata_free_xfer(struct ata_channel *chp, s
 	}
 #endif
 
-	s = splbio();
 	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);
-	splx(s);
+
+out:
+	if (chq->queue_flags & QF_NEED_XFER) {
+		chq->queue_flags &= ~QF_NEED_XFER;
+		cv_broadcast(&chq->queue_busy);
+	}
+
+	mutex_exit(&chp->ch_lock);
 }
 
 void
@@ -1197,6 +1245,8 @@ ata_activate_xfer(struct ata_channel *ch
 {
 	struct ata_queue * const chq = chp->ch_queue;
 
+	mutex_enter(&chp->ch_lock);
+
 	KASSERT(chq->queue_active < chq->queue_openings);
 	KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) == 0);
 
@@ -1204,6 +1254,8 @@ ata_activate_xfer(struct ata_channel *ch
 	TAILQ_INSERT_TAIL(&chq->active_xfers, xfer, c_activechain);
 	chq->active_xfers_used |= __BIT(xfer->c_slot);
 	chq->queue_active++;
+
+	mutex_exit(&chp->ch_lock);
 }
 
 void
@@ -1211,6 +1263,8 @@ ata_deactivate_xfer(struct ata_channel *
 {
 	struct ata_queue * const chq = chp->ch_queue;
 
+	mutex_enter(&chp->ch_lock);
+
 	KASSERT(chq->queue_active > 0);
 	KASSERT((chq->active_xfers_used & __BIT(xfer->c_slot)) != 0);
 
@@ -1219,6 +1273,8 @@ ata_deactivate_xfer(struct ata_channel *
 	TAILQ_REMOVE(&chq->active_xfers, xfer, c_activechain);
 	chq->active_xfers_used &= ~__BIT(xfer->c_slot);
 	chq->queue_active--;
+
+	mutex_exit(&chp->ch_lock);
 }
 
 

Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.92.8.9 src/sys/dev/ata/atavar.h:1.92.8.10
--- src/sys/dev/ata/atavar.h:1.92.8.9	Fri Jun 16 20:40:49 2017
+++ src/sys/dev/ata/atavar.h	Mon Jun 19 21:00:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: atavar.h,v 1.92.8.9 2017/06/16 20:40:49 jdolecek Exp $	*/
+/*	$NetBSD: atavar.h,v 1.92.8.10 2017/06/19 21:00:00 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -186,12 +186,14 @@ struct ata_xfer {
 /* Per-channel queue of ata_xfers */
 struct ata_queue {
 	TAILQ_HEAD(, ata_xfer) queue_xfer; 	/* queue of pending commands */
-	int queue_freeze; /* freeze count for the queue */
-	int queue_flags;	/* flags for this queue */
-#define QF_IDLE_WAIT	0x01    /* someone wants the controller idle */
-	int queue_active; /* number of active transfers */
-	int queue_openings; /* max number of active transfers */
+	int queue_freeze; 		/* freeze count for the queue */
+	int8_t queue_flags;		/* flags for this queue */
+#define QF_IDLE_WAIT	0x01    	/* someone wants the controller idle */
+#define QF_NEED_XFER	0x02    	/* someone wants xfer */
+	int8_t queue_active; 		/* number of active transfers */
+	int8_t queue_openings; 		/* max number of active transfers */
 #ifdef ATABUS_PRIVATE
+	kcondvar_t queue_busy;			/* c: waiting of xfer */
 	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 */
@@ -358,6 +360,7 @@ struct ata_device {
 struct ata_channel {
 	int ch_channel;			/* location */
 	struct atac_softc *ch_atac;	/* ATA controller softc */
+	kmutex_t ch_lock;		/* channel lock - queue */
 
 	/* Our state */
 	volatile int ch_flags;
@@ -457,6 +460,9 @@ struct atac_softc {
 
 #ifdef _KERNEL
 void	ata_channel_attach(struct ata_channel *);
+void	ata_channel_init(struct ata_channel *);
+void	ata_channel_detach(struct ata_channel *);
+void	ata_channel_destroy(struct ata_channel *);
 int	atabusprint(void *aux, const char *);
 int	ataprint(void *aux, const char *);
 
@@ -471,7 +477,7 @@ int	ata_set_mode(struct ata_drive_datas 
 #define CMD_ERR   1
 #define CMD_AGAIN 2
 
-struct ata_xfer *ata_get_xfer(struct ata_channel *);
+struct ata_xfer *ata_get_xfer(struct ata_channel *, bool);
 void	ata_free_xfer(struct ata_channel *, struct ata_xfer *);
 #define	ATAXF_CANSLEEP	0x00
 #define	ATAXF_NOSLEEP	0x01
@@ -497,8 +503,6 @@ void	ata_probe_caps(struct ata_drive_dat
 void	ata_dmaerr(struct ata_drive_datas *, int);
 #endif
 void	ata_queue_idle(struct ata_queue *);
-void	ata_xfer_init(struct ata_xfer *, bool);
-void	ata_xfer_destroy(struct ata_xfer *);
 struct ata_queue *
 	ata_queue_alloc(uint8_t openings);
 void	ata_queue_free(struct ata_queue *);

Index: src/sys/dev/ata/satapmp_subr.c
diff -u src/sys/dev/ata/satapmp_subr.c:1.12.24.2 src/sys/dev/ata/satapmp_subr.c:1.12.24.3
--- src/sys/dev/ata/satapmp_subr.c:1.12.24.2	Sat Jun 17 14:01:36 2017
+++ src/sys/dev/ata/satapmp_subr.c	Mon Jun 19 21:00:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: satapmp_subr.c,v 1.12.24.2 2017/06/17 14:01:36 jdolecek Exp $	*/
+/*	$NetBSD: satapmp_subr.c,v 1.12.24.3 2017/06/19 21:00:00 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.12.24.2 2017/06/17 14:01:36 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: satapmp_subr.c,v 1.12.24.3 2017/06/19 21:00:00 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -50,7 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: satapmp_subr
 static int
 satapmp_read_8(struct ata_channel *chp, int port, int reg, uint64_t *value)
 {
-	struct ata_xfer xfer;
+	struct ata_xfer *xfer;
 	struct atac_softc *atac = chp->ch_atac;
 	struct ata_drive_datas *drvp;
 	int error = 0;
@@ -61,45 +61,47 @@ satapmp_read_8(struct ata_channel *chp, 
 	drvp = &chp->ch_drive[PMP_PORT_CTL];
 	KASSERT(drvp->drive == PMP_PORT_CTL);
 
-	ata_xfer_init(&xfer, true);
-
-	xfer.c_ata_c.r_command = PMPC_READ_PORT;
-	xfer.c_ata_c.r_features = reg;
-	xfer.c_ata_c.r_device = port;
-	xfer.c_ata_c.timeout = 3000; /* 3s */
-	xfer.c_ata_c.r_st_bmask = 0;
-	xfer.c_ata_c.r_st_pmask = WDCS_DRDY;
-	xfer.c_ata_c.flags = AT_LBA48 | AT_READREG | AT_WAIT;
+	xfer = ata_get_xfer(chp, true);
+	if (xfer == NULL)
+		return EINTR;
+
+	xfer->c_ata_c.r_command = PMPC_READ_PORT;
+	xfer->c_ata_c.r_features = reg;
+	xfer->c_ata_c.r_device = port;
+	xfer->c_ata_c.timeout = 3000; /* 3s */
+	xfer->c_ata_c.r_st_bmask = 0;
+	xfer->c_ata_c.r_st_pmask = WDCS_DRDY;
+	xfer->c_ata_c.flags = AT_LBA48 | AT_READREG | AT_WAIT;
 
 	if ((*atac->atac_bustype_ata->ata_exec_command)(drvp,
-	    &xfer) != ATACMD_COMPLETE) {
+	    xfer) != ATACMD_COMPLETE) {
 		aprint_error_dev(chp->atabus,
 		    "PMP port %d register %d read failed\n", port, reg);
 		error = EIO;
 		goto out;
 	}
-	if (xfer.c_ata_c.flags & (AT_TIMEOU | AT_DF)) {
+	if (xfer->c_ata_c.flags & (AT_TIMEOU | AT_DF)) {
 		aprint_error_dev(chp->atabus,
 		    "PMP port %d register %d read failed, flags 0x%x\n",
-		    port, reg, xfer.c_ata_c.flags);
+		    port, reg, xfer->c_ata_c.flags);
 		error = EIO;
 		goto out;
 	}
-	if (xfer.c_ata_c.flags & AT_ERROR) {
+	if (xfer->c_ata_c.flags & AT_ERROR) {
 		aprint_verbose_dev(chp->atabus,
 		    "PMP port %d register %d read failed, error 0x%x\n",
-		    port, reg, xfer.c_ata_c.r_error);
+		    port, reg, xfer->c_ata_c.r_error);
 		error = EIO;
 		goto out;
 	}
 
-	*value = ((uint64_t)((xfer.c_ata_c.r_lba >> 24) & 0xffffff) << 40) |
-		((uint64_t)((xfer.c_ata_c.r_count >> 8) & 0xff) << 32) |
-		((uint64_t)((xfer.c_ata_c.r_lba >> 0) & 0xffffff) << 8) |
-		((uint64_t)((xfer.c_ata_c.r_count >> 0) & 0xff) << 0);
+	*value = ((uint64_t)((xfer->c_ata_c.r_lba >> 24) & 0xffffff) << 40) |
+		((uint64_t)((xfer->c_ata_c.r_count >> 8) & 0xff) << 32) |
+		((uint64_t)((xfer->c_ata_c.r_lba >> 0) & 0xffffff) << 8) |
+		((uint64_t)((xfer->c_ata_c.r_count >> 0) & 0xff) << 0);
 
 out:
-	ata_xfer_destroy(&xfer);
+	ata_free_xfer(chp, xfer);
 	return error;
 }
 
@@ -120,7 +122,7 @@ satapmp_read(struct ata_channel *chp, in
 static int
 satapmp_write_8(struct ata_channel *chp, int port, int reg, uint64_t value)
 {
-	struct ata_xfer xfer;
+	struct ata_xfer *xfer;
 	struct atac_softc *atac = chp->ch_atac;
 	struct ata_drive_datas *drvp;
 	int error = 0;
@@ -131,44 +133,46 @@ satapmp_write_8(struct ata_channel *chp,
 	drvp = &chp->ch_drive[PMP_PORT_CTL];
 	KASSERT(drvp->drive == PMP_PORT_CTL);
 
-	ata_xfer_init(&xfer, true);
-
-	xfer.c_ata_c.r_command = PMPC_WRITE_PORT;
-	xfer.c_ata_c.r_features = reg;
-	xfer.c_ata_c.r_device = port;
-	xfer.c_ata_c.r_lba = (((value >> 40) & 0xffffff) << 24) |
+	xfer = ata_get_xfer(chp, true);
+	if (xfer == NULL)
+		return EINTR;
+
+	xfer->c_ata_c.r_command = PMPC_WRITE_PORT;
+	xfer->c_ata_c.r_features = reg;
+	xfer->c_ata_c.r_device = port;
+	xfer->c_ata_c.r_lba = (((value >> 40) & 0xffffff) << 24) |
 		      (((value >>  8) & 0xffffff) <<  0);
-	xfer.c_ata_c.r_count = (((value >> 32) & 0xff) << 8) |
+	xfer->c_ata_c.r_count = (((value >> 32) & 0xff) << 8) |
 			(((value >>  0) & 0xff) << 0);
-	xfer.c_ata_c.timeout = 3000; /* 3s */
-	xfer.c_ata_c.r_st_bmask = 0;
-	xfer.c_ata_c.r_st_pmask = WDCS_DRDY;
-	xfer.c_ata_c.flags = AT_LBA48 | AT_WAIT;
+	xfer->c_ata_c.timeout = 3000; /* 3s */
+	xfer->c_ata_c.r_st_bmask = 0;
+	xfer->c_ata_c.r_st_pmask = WDCS_DRDY;
+	xfer->c_ata_c.flags = AT_LBA48 | AT_WAIT;
 
 	if ((*atac->atac_bustype_ata->ata_exec_command)(drvp,
-	    &xfer) != ATACMD_COMPLETE) {
+	    xfer) != ATACMD_COMPLETE) {
 		aprint_error_dev(chp->atabus,
 		    "PMP port %d register %d write failed\n", port, reg);
 		error = EIO;
 		goto out;
 	}
-	if (xfer.c_ata_c.flags & (AT_TIMEOU | AT_DF)) {
+	if (xfer->c_ata_c.flags & (AT_TIMEOU | AT_DF)) {
 		aprint_error_dev(chp->atabus,
 		    "PMP port %d register %d write failed, flags 0x%x\n",
-		    port, reg, xfer.c_ata_c.flags);
+		    port, reg, xfer->c_ata_c.flags);
 		error = EIO;
 		goto out;
 	}
-	if (xfer.c_ata_c.flags & AT_ERROR) {
+	if (xfer->c_ata_c.flags & AT_ERROR) {
 		aprint_verbose_dev(chp->atabus,
 		    "PMP port %d register %d write failed, error 0x%x\n",
-		    port, reg, xfer.c_ata_c.r_error);
+		    port, reg, xfer->c_ata_c.r_error);
 		error = EIO;
 		goto out;
 	}
 
 out:
-	ata_xfer_destroy(&xfer);
+	ata_free_xfer(chp, xfer);
 	return error;
 }
 

Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.428.2.17 src/sys/dev/ata/wd.c:1.428.2.18
--- src/sys/dev/ata/wd.c:1.428.2.17	Mon Jun 19 17:11:24 2017
+++ src/sys/dev/ata/wd.c	Mon Jun 19 21:00:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: wd.c,v 1.428.2.17 2017/06/19 17:11:24 jdolecek Exp $ */
+/*	$NetBSD: wd.c,v 1.428.2.18 2017/06/19 21:00:00 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.428.2.17 2017/06/19 17:11:24 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.18 2017/06/19 21:00:00 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -646,8 +646,8 @@ wdstart(struct wd_softc *wd)
 
 	while (bufq_peek(wd->sc_q) != NULL) {
 		/* First try to get command */
-		xfer = ata_get_xfer(wd->drvp->chnl_softc);
-		if (!xfer) 
+		xfer = ata_get_xfer(wd->drvp->chnl_softc, false);
+		if (xfer == NULL) 
 			break;
 
 		/* There is got to be a buf for us */
@@ -1637,7 +1637,7 @@ wddump(dev_t dev, daddr_t blkno, void *v
 		wd->drvp->state = RESET;
 	}
 
-	xfer = ata_get_xfer(wd->drvp->chnl_softc);
+	xfer = ata_get_xfer(wd->drvp->chnl_softc, false);
 	if (xfer == NULL)
 		return EAGAIN;
 
@@ -1812,7 +1812,7 @@ int
 wd_setcache(struct wd_softc *wd, int bits)
 {
 	struct ataparams params;
-	struct ata_xfer xfer;
+	struct ata_xfer *xfer;
 	int error;
 
 	if (wd_get_params(wd, AT_WAIT, &params) != 0)
@@ -1827,26 +1827,29 @@ wd_setcache(struct wd_softc *wd, int bit
 	    (bits & DKCACHE_SAVE) != 0)
 		return EOPNOTSUPP;
 
-	ata_xfer_init(&xfer, true);
-	xfer.c_ata_c.r_command = SET_FEATURES;
-	xfer.c_ata_c.r_st_bmask = 0;
-	xfer.c_ata_c.r_st_pmask = 0;
-	xfer.c_ata_c.timeout = 30000; /* 30s timeout */
-	xfer.c_ata_c.flags = AT_WAIT;
+	xfer = ata_get_xfer(wd->drvp->chnl_softc, true);
+	if (xfer == NULL)
+		return EINTR;
+
+	xfer->c_ata_c.r_command = SET_FEATURES;
+	xfer->c_ata_c.r_st_bmask = 0;
+	xfer->c_ata_c.r_st_pmask = 0;
+	xfer->c_ata_c.timeout = 30000; /* 30s timeout */
+	xfer->c_ata_c.flags = AT_WAIT;
 	if (bits & DKCACHE_WRITE)
-		xfer.c_ata_c.r_features = WDSF_WRITE_CACHE_EN;
+		xfer->c_ata_c.r_features = WDSF_WRITE_CACHE_EN;
 	else
-		xfer.c_ata_c.r_features = WDSF_WRITE_CACHE_DS;
-	if (wd->atabus->ata_exec_command(wd->drvp, &xfer) != ATACMD_COMPLETE) {
+		xfer->c_ata_c.r_features = WDSF_WRITE_CACHE_DS;
+	if (wd->atabus->ata_exec_command(wd->drvp, xfer) != ATACMD_COMPLETE) {
 		aprint_error_dev(wd->sc_dev,
 		    "wd_setcache command not complete\n");
 		error = EIO;
 		goto out;
 	}
 
-	if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
+	if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
 		char sbuf[sizeof(at_errbits) + 64];
-		snprintb(sbuf, sizeof(sbuf), at_errbits, xfer.c_ata_c.flags);
+		snprintb(sbuf, sizeof(sbuf), at_errbits, xfer->c_ata_c.flags);
 		aprint_error_dev(wd->sc_dev, "wd_setcache: status=%s\n", sbuf);
 		error = EIO;
 		goto out;
@@ -1855,38 +1858,41 @@ wd_setcache(struct wd_softc *wd, int bit
 	error = 0;
 
 out:
-	ata_xfer_destroy(&xfer);
+	ata_free_xfer(wd->drvp->chnl_softc, xfer);
 	return error;
 }
 
 static int
 wd_standby(struct wd_softc *wd, int flags)
 {
-	struct ata_xfer xfer;
+	struct ata_xfer *xfer;
 	int error;
 
-	ata_xfer_init(&xfer, true);
-	xfer.c_ata_c.r_command = WDCC_STANDBY_IMMED;
-	xfer.c_ata_c.r_st_bmask = WDCS_DRDY;
-	xfer.c_ata_c.r_st_pmask = WDCS_DRDY;
-	xfer.c_ata_c.flags = flags;
-	xfer.c_ata_c.timeout = 30000; /* 30s timeout */
-	if (wd->atabus->ata_exec_command(wd->drvp, &xfer) != ATACMD_COMPLETE) {
+	xfer = ata_get_xfer(wd->drvp->chnl_softc, true);
+	if (xfer == NULL)
+		return EINTR;
+
+	xfer->c_ata_c.r_command = WDCC_STANDBY_IMMED;
+	xfer->c_ata_c.r_st_bmask = WDCS_DRDY;
+	xfer->c_ata_c.r_st_pmask = WDCS_DRDY;
+	xfer->c_ata_c.flags = flags;
+	xfer->c_ata_c.timeout = 30000; /* 30s timeout */
+	if (wd->atabus->ata_exec_command(wd->drvp, xfer) != ATACMD_COMPLETE) {
 		aprint_error_dev(wd->sc_dev,
 		    "standby immediate command didn't complete\n");
 		error = EIO;
 		goto out;
 	}
-	if (xfer.c_ata_c.flags & AT_ERROR) {
-		if (xfer.c_ata_c.r_error == WDCE_ABRT) {
+	if (xfer->c_ata_c.flags & AT_ERROR) {
+		if (xfer->c_ata_c.r_error == WDCE_ABRT) {
 			/* command not supported */
 			error = ENODEV;
 			goto out;
 		}
 	}
-	if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
+	if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
 		char sbuf[sizeof(at_errbits) + 64];
-		snprintb(sbuf, sizeof(sbuf), at_errbits, xfer.c_ata_c.flags);
+		snprintb(sbuf, sizeof(sbuf), at_errbits, xfer->c_ata_c.flags);
 		aprint_error_dev(wd->sc_dev, "wd_standby: status=%s\n", sbuf);
 		error = EIO;
 		goto out;
@@ -1894,14 +1900,14 @@ wd_standby(struct wd_softc *wd, int flag
 	error = 0;
 
 out:
-	ata_xfer_destroy(&xfer);
+	ata_free_xfer(wd->drvp->chnl_softc, xfer);
 	return error;
 }
 
 int
 wd_flushcache(struct wd_softc *wd, int flags)
 {
-	struct ata_xfer xfer;
+	struct ata_xfer *xfer;
 	int error;
 
 	/*
@@ -1913,33 +1919,36 @@ wd_flushcache(struct wd_softc *wd, int f
 	    wd->sc_params.atap_cmd_set2 == 0xffff))
 		return ENODEV;
 
-	ata_xfer_init(&xfer, true);
+	xfer = ata_get_xfer(wd->drvp->chnl_softc, true);
+	if (xfer == NULL)
+		return EINTR;
+
 	if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0 &&
 	    (wd->sc_params.atap_cmd2_en & ATA_CMD2_FCE) != 0) {
-		xfer.c_ata_c.r_command = WDCC_FLUSHCACHE_EXT;
+		xfer->c_ata_c.r_command = WDCC_FLUSHCACHE_EXT;
 		flags |= AT_LBA48;
 	} else
-		xfer.c_ata_c.r_command = WDCC_FLUSHCACHE;
-	xfer.c_ata_c.r_st_bmask = WDCS_DRDY;
-	xfer.c_ata_c.r_st_pmask = WDCS_DRDY;
-	xfer.c_ata_c.flags = flags | AT_READREG;
-	xfer.c_ata_c.timeout = 300000; /* 5m timeout */
-	if (wd->atabus->ata_exec_command(wd->drvp, &xfer) != ATACMD_COMPLETE) {
+		xfer->c_ata_c.r_command = WDCC_FLUSHCACHE;
+	xfer->c_ata_c.r_st_bmask = WDCS_DRDY;
+	xfer->c_ata_c.r_st_pmask = WDCS_DRDY;
+	xfer->c_ata_c.flags = flags | AT_READREG;
+	xfer->c_ata_c.timeout = 300000; /* 5m timeout */
+	if (wd->atabus->ata_exec_command(wd->drvp, xfer) != ATACMD_COMPLETE) {
 		aprint_error_dev(wd->sc_dev,
 		    "flush cache command didn't complete\n");
 		error = EIO;
 		goto out;
 	}
-	if (xfer.c_ata_c.flags & AT_ERROR) {
-		if (xfer.c_ata_c.r_error == WDCE_ABRT) {
+	if (xfer->c_ata_c.flags & AT_ERROR) {
+		if (xfer->c_ata_c.r_error == WDCE_ABRT) {
 			/* command not supported */
 			error = ENODEV;
 			goto out;
 		}
 	}
-	if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
+	if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
 		char sbuf[sizeof(at_errbits) + 64];
-		snprintb(sbuf, sizeof(sbuf), at_errbits, xfer.c_ata_c.flags);
+		snprintb(sbuf, sizeof(sbuf), at_errbits, xfer->c_ata_c.flags);
 		aprint_error_dev(wd->sc_dev, "wd_flushcache: status=%s\n",
 		    sbuf);
 		error = EIO;
@@ -1948,20 +1957,24 @@ wd_flushcache(struct wd_softc *wd, int f
 	error = 0;
 
 out:
-	ata_xfer_destroy(&xfer);
+	ata_free_xfer(wd->drvp->chnl_softc, xfer);
 	return error;
 }
 
 int
 wd_trim(struct wd_softc *wd, int part, daddr_t bno, long size)
 {
-	struct ata_xfer xfer;
+	struct ata_xfer *xfer;
 	int error;
 	unsigned char *req;
 
 	if (part != RAW_PART)
 		bno += wd->sc_dk.dk_label->d_partitions[part].p_offset;;
 
+	xfer = ata_get_xfer(wd->drvp->chnl_softc, true);
+	if (xfer == NULL)
+		return EINTR;
+
 	req = kmem_zalloc(512, KM_SLEEP);
 	req[0] = bno & 0xff;
 	req[1] = (bno >> 8) & 0xff;
@@ -1972,17 +1985,16 @@ wd_trim(struct wd_softc *wd, int part, d
 	req[6] = size & 0xff;
 	req[7] = (size >> 8) & 0xff;
 
-	ata_xfer_init(&xfer, true);
-	xfer.c_ata_c.r_command = ATA_DATA_SET_MANAGEMENT;
-	xfer.c_ata_c.r_count = 1;
-	xfer.c_ata_c.r_features = ATA_SUPPORT_DSM_TRIM;
-	xfer.c_ata_c.r_st_bmask = WDCS_DRDY;
-	xfer.c_ata_c.r_st_pmask = WDCS_DRDY;
-	xfer.c_ata_c.timeout = 30000; /* 30s timeout */
-	xfer.c_ata_c.data = req;
-	xfer.c_ata_c.bcount = 512;
-	xfer.c_ata_c.flags |= AT_WRITE | AT_WAIT;
-	if (wd->atabus->ata_exec_command(wd->drvp, &xfer) != ATACMD_COMPLETE) {
+	xfer->c_ata_c.r_command = ATA_DATA_SET_MANAGEMENT;
+	xfer->c_ata_c.r_count = 1;
+	xfer->c_ata_c.r_features = ATA_SUPPORT_DSM_TRIM;
+	xfer->c_ata_c.r_st_bmask = WDCS_DRDY;
+	xfer->c_ata_c.r_st_pmask = WDCS_DRDY;
+	xfer->c_ata_c.timeout = 30000; /* 30s timeout */
+	xfer->c_ata_c.data = req;
+	xfer->c_ata_c.bcount = 512;
+	xfer->c_ata_c.flags |= AT_WRITE | AT_WAIT;
+	if (wd->atabus->ata_exec_command(wd->drvp, xfer) != ATACMD_COMPLETE) {
 		aprint_error_dev(wd->sc_dev,
 		    "trim command didn't complete\n");
 		kmem_free(req, 512);
@@ -1990,16 +2002,16 @@ wd_trim(struct wd_softc *wd, int part, d
 		goto out;
 	}
 	kmem_free(req, 512);
-	if (xfer.c_ata_c.flags & AT_ERROR) {
-		if (xfer.c_ata_c.r_error == WDCE_ABRT) {
+	if (xfer->c_ata_c.flags & AT_ERROR) {
+		if (xfer->c_ata_c.r_error == WDCE_ABRT) {
 			/* command not supported */
 			error = ENODEV;
 			goto out;
 		}
 	}
-	if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
+	if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
 		char sbuf[sizeof(at_errbits) + 64];
-		snprintb(sbuf, sizeof(sbuf), at_errbits, xfer.c_ata_c.flags);
+		snprintb(sbuf, sizeof(sbuf), at_errbits, xfer->c_ata_c.flags);
 		aprint_error_dev(wd->sc_dev, "wd_trim: status=%s\n",
 		    sbuf);
 		error = EIO;
@@ -2008,7 +2020,7 @@ wd_trim(struct wd_softc *wd, int part, d
 	error = 0;
 
 out:
-	ata_xfer_destroy(&xfer);
+	ata_free_xfer(wd->drvp->chnl_softc, xfer);
 	return error;
 }
 
@@ -2114,7 +2126,7 @@ void
 wdioctlstrategy(struct buf *bp)
 {
 	struct wd_ioctl *wi;
-	struct ata_xfer xfer;
+	struct ata_xfer *xfer;
 	int error = 0;
 
 	wi = wi_find(bp);
@@ -2125,7 +2137,11 @@ wdioctlstrategy(struct buf *bp)
 		goto out2;
 	}
 
-	ata_xfer_init(&xfer, true);
+	xfer = ata_get_xfer(wi->wi_softc->drvp->chnl_softc, true);
+	if (xfer == NULL) {
+		error = EINTR;
+		goto out2;
+	}
 
 	/*
 	 * Abort if physio broke up the transfer
@@ -2159,62 +2175,62 @@ wdioctlstrategy(struct buf *bp)
 	}
 
 	if (wi->wi_atareq.flags & ATACMD_READ)
-		xfer.c_ata_c.flags |= AT_READ;
+		xfer->c_ata_c.flags |= AT_READ;
 	else if (wi->wi_atareq.flags & ATACMD_WRITE)
-		xfer.c_ata_c.flags |= AT_WRITE;
+		xfer->c_ata_c.flags |= AT_WRITE;
 
 	if (wi->wi_atareq.flags & ATACMD_READREG)
-		xfer.c_ata_c.flags |= AT_READREG;
+		xfer->c_ata_c.flags |= AT_READREG;
 
 	if ((wi->wi_atareq.flags & ATACMD_LBA) != 0)
-		xfer.c_ata_c.flags |= AT_LBA;
+		xfer->c_ata_c.flags |= AT_LBA;
 
-	xfer.c_ata_c.flags |= AT_WAIT;
+	xfer->c_ata_c.flags |= AT_WAIT;
 
-	xfer.c_ata_c.timeout = wi->wi_atareq.timeout;
-	xfer.c_ata_c.r_command = wi->wi_atareq.command;
-	xfer.c_ata_c.r_lba = ((wi->wi_atareq.head & 0x0f) << 24) |
+	xfer->c_ata_c.timeout = wi->wi_atareq.timeout;
+	xfer->c_ata_c.r_command = wi->wi_atareq.command;
+	xfer->c_ata_c.r_lba = ((wi->wi_atareq.head & 0x0f) << 24) |
 	    (wi->wi_atareq.cylinder << 8) |
 	    wi->wi_atareq.sec_num;
-	xfer.c_ata_c.r_count = wi->wi_atareq.sec_count;
-	xfer.c_ata_c.r_features = wi->wi_atareq.features;
-	xfer.c_ata_c.r_st_bmask = WDCS_DRDY;
-	xfer.c_ata_c.r_st_pmask = WDCS_DRDY;
-	xfer.c_ata_c.data = wi->wi_bp.b_data;
-	xfer.c_ata_c.bcount = wi->wi_bp.b_bcount;
+	xfer->c_ata_c.r_count = wi->wi_atareq.sec_count;
+	xfer->c_ata_c.r_features = wi->wi_atareq.features;
+	xfer->c_ata_c.r_st_bmask = WDCS_DRDY;
+	xfer->c_ata_c.r_st_pmask = WDCS_DRDY;
+	xfer->c_ata_c.data = wi->wi_bp.b_data;
+	xfer->c_ata_c.bcount = wi->wi_bp.b_bcount;
 
-	if (wi->wi_softc->atabus->ata_exec_command(wi->wi_softc->drvp, &xfer)
+	if (wi->wi_softc->atabus->ata_exec_command(wi->wi_softc->drvp, xfer)
 	    != ATACMD_COMPLETE) {
 		wi->wi_atareq.retsts = ATACMD_ERROR;
 		error = EIO;
 		goto out;
 	}
 
-	if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
-		if (xfer.c_ata_c.flags & AT_ERROR) {
+	if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
+		if (xfer->c_ata_c.flags & AT_ERROR) {
 			wi->wi_atareq.retsts = ATACMD_ERROR;
-			wi->wi_atareq.error = xfer.c_ata_c.r_error;
-		} else if (xfer.c_ata_c.flags & AT_DF)
+			wi->wi_atareq.error = xfer->c_ata_c.r_error;
+		} else if (xfer->c_ata_c.flags & AT_DF)
 			wi->wi_atareq.retsts = ATACMD_DF;
 		else
 			wi->wi_atareq.retsts = ATACMD_TIMEOUT;
 	} else {
 		wi->wi_atareq.retsts = ATACMD_OK;
 		if (wi->wi_atareq.flags & ATACMD_READREG) {
-			wi->wi_atareq.command = xfer.c_ata_c.r_status;
-			wi->wi_atareq.features = xfer.c_ata_c.r_error;
-			wi->wi_atareq.sec_count = xfer.c_ata_c.r_count;
-			wi->wi_atareq.sec_num = xfer.c_ata_c.r_lba & 0xff;
-			wi->wi_atareq.head = (xfer.c_ata_c.r_device & 0xf0) |
-			    ((xfer.c_ata_c.r_lba >> 24) & 0x0f);
+			wi->wi_atareq.command = xfer->c_ata_c.r_status;
+			wi->wi_atareq.features = xfer->c_ata_c.r_error;
+			wi->wi_atareq.sec_count = xfer->c_ata_c.r_count;
+			wi->wi_atareq.sec_num = xfer->c_ata_c.r_lba & 0xff;
+			wi->wi_atareq.head = (xfer->c_ata_c.r_device & 0xf0) |
+			    ((xfer->c_ata_c.r_lba >> 24) & 0x0f);
 			wi->wi_atareq.cylinder =
-			    (xfer.c_ata_c.r_lba >> 8) & 0xffff;
-			wi->wi_atareq.error = xfer.c_ata_c.r_error;
+			    (xfer->c_ata_c.r_lba >> 8) & 0xffff;
+			wi->wi_atareq.error = xfer->c_ata_c.r_error;
 		}
 	}
 
 out:
-	ata_xfer_destroy(&xfer);
+	ata_free_xfer(wi->wi_softc->drvp->chnl_softc, xfer);
 out2:
 	bp->b_error = error;
 	if (error)

Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.57.6.13 src/sys/dev/ic/ahcisata_core.c:1.57.6.14
--- src/sys/dev/ic/ahcisata_core.c:1.57.6.13	Fri Jun 16 20:40:49 2017
+++ src/sys/dev/ic/ahcisata_core.c	Mon Jun 19 21:00:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisata_core.c,v 1.57.6.13 2017/06/16 20:40:49 jdolecek Exp $	*/
+/*	$NetBSD: ahcisata_core.c,v 1.57.6.14 2017/06/19 21:00:00 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.6.13 2017/06/16 20:40:49 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.14 2017/06/19 21:00:00 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -511,6 +511,8 @@ ahci_detach(struct ahci_softc *sc, int f
 		ata_queue_free(chp->ch_queue);
 		chp->ch_queue = NULL;
 		chp->atabus = NULL;
+
+		ata_channel_detach(chp);
 	}
 
 	bus_dmamap_unload(sc->sc_dmat, sc->sc_cmd_hdrd);
@@ -1567,7 +1569,7 @@ ahci_atapi_scsipi_request(struct scsipi_
 			scsipi_done(sc_xfer);
 			return;
 		}
-		xfer = ata_get_xfer(atac->atac_channels[channel]);
+		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.35.6.11 src/sys/dev/ic/mvsata.c:1.35.6.12
--- src/sys/dev/ic/mvsata.c:1.35.6.11	Fri Jun 16 20:40:49 2017
+++ src/sys/dev/ic/mvsata.c	Mon Jun 19 21:00:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: mvsata.c,v 1.35.6.11 2017/06/16 20:40:49 jdolecek Exp $	*/
+/*	$NetBSD: mvsata.c,v 1.35.6.12 2017/06/19 21:00:00 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.6.11 2017/06/16 20:40:49 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.12 2017/06/19 21:00:00 jdolecek Exp $");
 
 #include "opt_mvsata.h"
 
@@ -791,7 +791,7 @@ mvsata_atapi_scsipi_request(struct scsip
 			scsipi_done(sc_xfer);
 			return;
 		}
-		xfer = ata_get_xfer(chp);
+		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.30.4.16 src/sys/dev/ic/siisata.c:1.30.4.17
--- src/sys/dev/ic/siisata.c:1.30.4.16	Fri Jun 16 20:40:49 2017
+++ src/sys/dev/ic/siisata.c	Mon Jun 19 21:00:00 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.30.4.16 2017/06/16 20:40:49 jdolecek Exp $ */
+/* $NetBSD: siisata.c,v 1.30.4.17 2017/06/19 21:00:00 jdolecek Exp $ */
 
 /* from ahcisata_core.c */
 
@@ -79,7 +79,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.16 2017/06/16 20:40:49 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.17 2017/06/19 21:00:00 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -425,6 +425,8 @@ siisata_detach(struct siisata_softc *sc,
 
 		free(chp->ch_queue, M_DEVBUF);
 		chp->atabus = NULL;
+
+		ata_channel_detach(chp);
 	}
 
 	if (adapt->adapt_refcnt != 0)
@@ -582,22 +584,29 @@ siisata_reset_drive(struct ata_drive_dat
 	while (!(PRREAD(sc, PRX(chp->ch_channel, PRO_PS)) & PR_PS_PORT_READY))
 		DELAY(10);
 
-	xfer = ata_get_xfer(chp);  /* Is this right?  What if the slots are full? */
-	if (xfer == NULL)
+	/*
+	 * Try to get available slot. If there is none available, must
+	 * do full channel reset.
+	 */
+	xfer = ata_get_xfer(chp, false);
+	if (xfer == NULL) {
+		siisata_reset_channel(chp, flags);
 		return;
+	}
 
 	prb = schp->sch_prb[xfer->c_slot];
 	memset(prb, 0, SIISATA_CMD_SIZE);
 	prb->prb_control =
-	    htole16(PRB_CF_SOFT_RESET /* | PRB_CF_INTERRUPT_MASK */);
+	    htole16(PRB_CF_SOFT_RESET | PRB_CF_INTERRUPT_MASK);
 	KASSERT(drvp->drive <= PMP_PORT_CTL);
 	prb->prb_fis[rhd_c] = drvp->drive;
 
-	ata_activate_xfer(chp, xfer);
+	siisata_disable_port_interrupt(chp);
+
 	siisata_activate_prb(schp, xfer->c_slot);
 
 	for(i = 0; i < 3100; i++) {
-#if 0		/* XXX-jak-jd-ncq this block needs re-work... XXX */
+#if 1		/* XXX-jak-jd-ncq this block needs re-work... XXX */
 		PRWRITE(sc, PRX(chp->ch_channel, PRO_PCS), PR_PC_INCOR);
 		pss = PRREAD(sc, PRX(chp->ch_channel, PRO_PSS));
 		PRWRITE(sc, PRX(chp->ch_channel, PRO_PCC), PR_PC_INCOR);
@@ -626,6 +635,8 @@ siisata_reset_drive(struct ata_drive_dat
 		    PR_PIS_CMDERRR);
 	}
 
+	siisata_enable_port_interrupt(chp);
+
 	if (i == 3100) {
 		/* timeout */
 		siisata_device_reset(chp);	/* XXX is this right? */
@@ -642,7 +653,6 @@ siisata_reset_drive(struct ata_drive_dat
 		}
 	}
 
-	ata_deactivate_xfer(chp, xfer);
 	ata_free_xfer(chp, xfer);
 
 #if 1
@@ -723,11 +733,19 @@ siisata_probe_drive(struct ata_channel *
 	uint32_t sig;
 	struct siisata_prb *prb;
 	bool timed_out;
-	const u_int slot0 = 0; /* XXX this is a problem */
+	struct ata_xfer *xfer;
 
 	SIISATA_DEBUG_PRINT(("%s: %s: port %d start\n", SIISATANAME(sc),
 	    __func__, chp->ch_channel), DEBUG_FUNCS);
 
+	xfer = ata_get_xfer(chp, true);
+	if (xfer == NULL) {
+		aprint_error_dev(sc->sc_atac.atac_dev,
+		    "failed to get xfer port %d\n",
+		    chp->ch_channel);
+		return;
+	}
+
 	/*
 	 * disable port interrupt as we're polling for PHY up and
 	 * prb completion
@@ -747,17 +765,17 @@ siisata_probe_drive(struct ata_channel *
 		while (!(PRREAD(sc, PRX(chp->ch_channel, PRO_PS))
 		    & PR_PS_PORT_READY))
 			DELAY(10);
-		prb = schp->sch_prb[slot0];
+		prb = schp->sch_prb[xfer->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, slot0);
+		siisata_activate_prb(schp, xfer->c_slot);
 
 		timed_out = 1;
 		for(i = 0; i < 3100; i++) {
 			if ((PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)) &
-			    PR_PXSS(slot0)) == 0) {
+			    PR_PXSS(xfer->c_slot)) == 0) {
 				/* prb completed */
 				timed_out = 0;
 				break;
@@ -771,7 +789,8 @@ siisata_probe_drive(struct ata_channel *
 			tsleep(schp, PRIBIO, "siiprb", mstohz(10));
 		}
 
-		siisata_deactivate_prb(schp, slot0);
+		siisata_deactivate_prb(schp, xfer->c_slot);
+
 		if (timed_out) {
 			aprint_error_dev(sc->sc_atac.atac_dev,
 			    "SOFT_RESET failed on port %d (error %d PSS 0x%x), "
@@ -784,9 +803,9 @@ siisata_probe_drive(struct ata_channel *
 
 		/* read the signature out of the FIS */
 		sig = 0;
-		sig |= (PRREAD(sc, PRSX(chp->ch_channel, slot0,
+		sig |= (PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot,
 		    PRSO_FIS+0x4)) & 0x00ffffff) << 8;
-		sig |= PRREAD(sc, PRSX(chp->ch_channel, slot0,
+		sig |= PRREAD(sc, PRSX(chp->ch_channel, xfer->c_slot,
 		    PRSO_FIS+0xc)) & 0xff;
 
 		SIISATA_DEBUG_PRINT(("%s: %s: sig=0x%08x\n", SIISATANAME(sc),
@@ -1578,7 +1597,7 @@ siisata_atapi_scsipi_request(struct scsi
 			scsipi_done(sc_xfer);
 			return;
 		}
-		xfer = ata_get_xfer(atac->atac_channels[channel]);
+		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/wdc.c
diff -u src/sys/dev/ic/wdc.c:1.283.2.5 src/sys/dev/ic/wdc.c:1.283.2.6
--- src/sys/dev/ic/wdc.c:1.283.2.5	Fri Jun 16 20:40:49 2017
+++ src/sys/dev/ic/wdc.c	Mon Jun 19 21:00:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdc.c,v 1.283.2.5 2017/06/16 20:40:49 jdolecek Exp $ */
+/*	$NetBSD: wdc.c,v 1.283.2.6 2017/06/19 21:00:00 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.2.5 2017/06/16 20:40:49 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.283.2.6 2017/06/19 21:00:00 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wdc.h"
@@ -823,6 +823,7 @@ wdcdetach(device_t self, int flags)
 		    DEBUG_DETACH);
 		if ((error = config_detach(chp->atabus, flags)) != 0)
 			return error;
+		ata_channel_detach(chp);
 	}
 	if (adapt->adapt_refcnt != 0)
 		return EBUSY;

Index: src/sys/dev/scsipi/atapi_wdc.c
diff -u src/sys/dev/scsipi/atapi_wdc.c:1.123.4.5 src/sys/dev/scsipi/atapi_wdc.c:1.123.4.6
--- src/sys/dev/scsipi/atapi_wdc.c:1.123.4.5	Fri Jun 16 20:40:49 2017
+++ src/sys/dev/scsipi/atapi_wdc.c	Mon Jun 19 21:00:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: atapi_wdc.c,v 1.123.4.5 2017/06/16 20:40:49 jdolecek Exp $	*/
+/*	$NetBSD: atapi_wdc.c,v 1.123.4.6 2017/06/19 21:00:00 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.4.5 2017/06/16 20:40:49 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.123.4.6 2017/06/19 21:00:00 jdolecek Exp $");
 
 #ifndef ATADEBUG
 #define ATADEBUG
@@ -198,27 +198,31 @@ wdc_atapi_get_params(struct scsipi_chann
 	struct atac_softc *atac = &wdc->sc_atac;
 	struct wdc_regs *wdr = &wdc->regs[chan->chan_channel];
 	struct ata_channel *chp = atac->atac_channels[chan->chan_channel];
-	struct ata_xfer xfer;
+	struct ata_xfer *xfer;
 	int rv;
 
-	ata_xfer_init(&xfer, true);
+	xfer = ata_get_xfer(chp, true);
+	if (xfer == NULL) {
+		printf("wdc_atapi_get_params: no xfer\n");
+		return EBUSY;
+	}
 
-	xfer.c_ata_c.r_command = ATAPI_SOFT_RESET;
-	xfer.c_ata_c.r_st_bmask = 0;
-	xfer.c_ata_c.r_st_pmask = 0;
-	xfer.c_ata_c.flags = AT_WAIT | AT_POLL;
-	xfer.c_ata_c.timeout = WDC_RESET_WAIT;
-	if (wdc_exec_command(&chp->ch_drive[drive], &xfer) != ATACMD_COMPLETE) {
+	xfer->c_ata_c.r_command = ATAPI_SOFT_RESET;
+	xfer->c_ata_c.r_st_bmask = 0;
+	xfer->c_ata_c.r_st_pmask = 0;
+	xfer->c_ata_c.flags = AT_WAIT | AT_POLL;
+	xfer->c_ata_c.timeout = WDC_RESET_WAIT;
+	if (wdc_exec_command(&chp->ch_drive[drive], xfer) != ATACMD_COMPLETE) {
 		printf("wdc_atapi_get_params: ATAPI_SOFT_RESET failed for"
 		    " drive %s:%d:%d: driver failed\n",
 		    device_xname(atac->atac_dev), chp->ch_channel, drive);
 		panic("wdc_atapi_get_params");
 	}
-	if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
+	if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
 		ATADEBUG_PRINT(("wdc_atapi_get_params: ATAPI_SOFT_RESET "
 		    "failed for drive %s:%d:%d: error 0x%x\n",
 		    device_xname(atac->atac_dev), chp->ch_channel, drive,
-		    xfer.c_ata_c.r_error), DEBUG_PROBE);
+		    xfer->c_ata_c.r_error), DEBUG_PROBE);
 		rv = -1;
 		goto out;
 	}
@@ -232,14 +236,14 @@ wdc_atapi_get_params(struct scsipi_chann
 		ATADEBUG_PRINT(("wdc_atapi_get_params: ATAPI_IDENTIFY_DEVICE "
 		    "failed for drive %s:%d:%d: error 0x%x\n",
 		    device_xname(atac->atac_dev), chp->ch_channel, drive,
-		    xfer.c_ata_c.r_error), DEBUG_PROBE);
+		    xfer->c_ata_c.r_error), DEBUG_PROBE);
 		rv = -1;
 		goto out;
 	}
 	rv = 0;
 
 out:
-	ata_xfer_destroy(&xfer);
+	ata_free_xfer(chp, xfer);
 	return rv;
 }
 
@@ -372,7 +376,7 @@ wdc_atapi_scsipi_request(struct scsipi_c
 			return;
 		}
 
-		xfer = ata_get_xfer(atac->atac_channels[channel]);
+		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.33.4.2 src/sys/dev/usb/umass_isdata.c:1.33.4.3
--- src/sys/dev/usb/umass_isdata.c:1.33.4.2	Thu Apr 20 20:14:42 2017
+++ src/sys/dev/usb/umass_isdata.c	Mon Jun 19 21:00:00 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: umass_isdata.c,v 1.33.4.2 2017/04/20 20:14:42 jdolecek Exp $	*/
+/*	$NetBSD: umass_isdata.c,v 1.33.4.3 2017/06/19 21:00:00 jdolecek Exp $	*/
 
 /*
  * TODO:
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.33.4.2 2017/04/20 20:14:42 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.33.4.3 2017/06/19 21:00:00 jdolecek Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -221,6 +221,7 @@ umass_isdata_attach(struct umass_softc *
 	adev.adev_drv_data = &scbus->sc_drv_data;
 
 	/* Fake ATA channel so wd(4) ata_{get,free}_xfer() work */
+	ata_channel_init(&scbus->sc_channel);
 	scbus->sc_channel.atabus = (device_t)scbus;
 	scbus->sc_channel.ch_queue = ata_queue_alloc(1);
 
@@ -520,7 +521,7 @@ uisdata_get_params(struct ata_drive_data
 		struct ataparams *prms)
 {
 	char tb[DEV_BSIZE];
-	struct ata_xfer xfer;
+	struct ata_xfer *xfer;
 	int rv;
 
 #if BYTE_ORDER == LITTLE_ENDIAN
@@ -533,19 +534,23 @@ uisdata_get_params(struct ata_drive_data
 	memset(tb, 0, DEV_BSIZE);
 	memset(prms, 0, sizeof(struct ataparams));
 
-	ata_xfer_init(&xfer, true);
+	xfer = ata_get_xfer(drvp->chnl_softc, true);
+	if (!xfer) {
+		rv = CMD_AGAIN;
+		goto out;
+	}
 
-	xfer.c_ata_c.r_command = WDCC_IDENTIFY;
-	xfer.c_ata_c.timeout = 1000; /* 1s */
-	xfer.c_ata_c.flags = AT_READ | flags;
-	xfer.c_ata_c.data = tb;
-	xfer.c_ata_c.bcount = DEV_BSIZE;
-	if (uisdata_exec_command(drvp, &xfer) != ATACMD_COMPLETE) {
+	xfer->c_ata_c.r_command = WDCC_IDENTIFY;
+	xfer->c_ata_c.timeout = 1000; /* 1s */
+	xfer->c_ata_c.flags = AT_READ | flags;
+	xfer->c_ata_c.data = tb;
+	xfer->c_ata_c.bcount = DEV_BSIZE;
+	if (uisdata_exec_command(drvp, xfer) != ATACMD_COMPLETE) {
 		DPRINTF(("uisdata_get_parms: wdc_exec_command failed\n"));
 		rv = CMD_AGAIN;
 		goto out;
 	}
-	if (xfer.c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
+	if (xfer->c_ata_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
 		DPRINTF(("uisdata_get_parms: ata_c.flags=0x%x\n",
 			 ata_c.flags));
 		rv = CMD_ERR;
@@ -585,7 +590,7 @@ uisdata_get_params(struct ata_drive_data
 	rv = CMD_OK;
 
 out:
-	ata_xfer_destroy(&xfer);
+	ata_free_xfer(drvp->chnl_softc, xfer);
 	return rv;
 }
 

Reply via email to