Module Name:    src
Committed By:   jdolecek
Date:           Tue Sep 19 21:06:25 UTC 2017

Modified Files:
        src/sys/dev/ata [jdolecek-ncq]: TODO.ncq ata.c atavar.h sata_subr.c
            satapmp_subr.c satapmpvar.h
        src/sys/dev/ic [jdolecek-ncq]: ahcisata_core.c mvsata.c siisata.c wdc.c

Log Message:
replace all remaining tsleep()/wakeup() calls with condition variables, or
calls to ata_delay(), as appropriate; change ata_delay() to require the
channel lock on entry, and pass the lock to kpause() for unlocking while
sleeping


To generate a diff of this commit:
cvs rdiff -u -r1.1.2.41 -r1.1.2.42 src/sys/dev/ata/TODO.ncq
cvs rdiff -u -r1.132.8.32 -r1.132.8.33 src/sys/dev/ata/ata.c
cvs rdiff -u -r1.92.8.25 -r1.92.8.26 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.21 -r1.21.24.1 src/sys/dev/ata/sata_subr.c
cvs rdiff -u -r1.12.24.5 -r1.12.24.6 src/sys/dev/ata/satapmp_subr.c
cvs rdiff -u -r1.3 -r1.3.30.1 src/sys/dev/ata/satapmpvar.h
cvs rdiff -u -r1.57.6.28 -r1.57.6.29 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.35.6.25 -r1.35.6.26 src/sys/dev/ic/mvsata.c
cvs rdiff -u -r1.30.4.37 -r1.30.4.38 src/sys/dev/ic/siisata.c
cvs rdiff -u -r1.283.2.15 -r1.283.2.16 src/sys/dev/ic/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/TODO.ncq
diff -u src/sys/dev/ata/TODO.ncq:1.1.2.41 src/sys/dev/ata/TODO.ncq:1.1.2.42
--- src/sys/dev/ata/TODO.ncq:1.1.2.41	Wed Sep 13 19:55:12 2017
+++ src/sys/dev/ata/TODO.ncq	Tue Sep 19 21:06:25 2017
@@ -4,10 +4,6 @@ test wd* at umass?, confirm the ata_chan
 
 mvsata - resest MVSATA_WITHOUTDMA
 
-the changes to lock channel lock cause now mi_switch() with spinlock held
-when invoking ata_delay() (which calls kpause()) or on tsleep, need
-to refactor
-
 Other random notes (do outside the NCQ branch):
 -----------------------------------------------------
 do biodone() in wddone() starting the dump to not leak bufs when dumping from

Index: src/sys/dev/ata/ata.c
diff -u src/sys/dev/ata/ata.c:1.132.8.32 src/sys/dev/ata/ata.c:1.132.8.33
--- src/sys/dev/ata/ata.c:1.132.8.32	Mon Sep 11 22:16:18 2017
+++ src/sys/dev/ata/ata.c	Tue Sep 19 21:06:25 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata.c,v 1.132.8.32 2017/09/11 22:16:18 jdolecek Exp $	*/
+/*	$NetBSD: ata.c,v 1.132.8.33 2017/09/19 21:06:25 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.32 2017/09/11 22:16:18 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.33 2017/09/19 21:06:25 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -279,6 +279,7 @@ ata_xfer_init(struct ata_xfer *xfer, uin
 	xfer->c_slot = slot;
 
 	cv_init(&xfer->c_active, "ataact");
+	cv_init(&xfer->c_finish, "atafin");
 	callout_init(&xfer->c_timo_callout, 0); 	/* XXX MPSAFE */
 	callout_init(&xfer->c_retry_callout, 0); 	/* XXX MPSAFE */
 }
@@ -291,6 +292,7 @@ ata_xfer_destroy(struct ata_xfer *xfer)
 	callout_halt(&xfer->c_retry_callout, NULL);	/* XXX MPSAFE */
 	callout_destroy(&xfer->c_retry_callout);
 	cv_destroy(&xfer->c_active);
+	cv_destroy(&xfer->c_finish);
 }
 
 struct ata_queue *
@@ -310,6 +312,7 @@ ata_queue_alloc(uint8_t openings)
 
 	cv_init(&chq->queue_busy, "ataqbusy");
 	cv_init(&chq->queue_drain, "atdrn");
+	cv_init(&chq->queue_idle, "qidl");
 
 	for (uint8_t i = 0; i < openings; i++)
 		ata_xfer_init(&chq->queue_xfers[i], i);
@@ -1194,13 +1197,13 @@ ata_dmaerr(struct ata_drive_datas *drvp,
 static void
 ata_channel_idle(struct ata_channel *chp)
 {
-	int s = splbio();
-	ata_channel_freeze(chp);
+	ata_channel_lock(chp);
+	ata_channel_freeze_locked(chp);
 	while (chp->ch_queue->queue_active > 0) {
 		chp->ch_queue->queue_flags |= QF_IDLE_WAIT;
-		tsleep(&chp->ch_queue->queue_flags, PRIBIO, "qidl", 0);
+		cv_timedwait(&chp->ch_queue->queue_idle, &chp->ch_lock, 1);
 	}
-	splx(s);
+	ata_channel_unlock(chp);
 }
 
 /*
@@ -1246,6 +1249,8 @@ ata_exec_xfer(struct ata_channel *chp, s
 			 * while we were waiting.
 			 */
 			if ((xfer->c_flags & (C_FREE|C_WAITTIMO)) == C_FREE) {
+				ata_channel_unlock(chp);
+
 				ata_free_xfer(chp, xfer);
 				return;
 			}
@@ -1305,7 +1310,7 @@ again:
 	if (__predict_false(!recovery && chq->queue_freeze > 0)) {
 		if (chq->queue_flags & QF_IDLE_WAIT) {
 			chq->queue_flags &= ~QF_IDLE_WAIT;
-			wakeup(&chq->queue_flags);
+			cv_signal(&chp->ch_queue->queue_idle);
 		}
 		goto out; /* queue frozen */
 	}
@@ -1673,7 +1678,7 @@ out:
 /*
  * Kill off all active xfers for a ata_channel.
  *
- * Must be called at splbio().
+ * Must be called with channel lock held.
  */
 void
 ata_kill_active(struct ata_channel *chp, int reason, int flags)
@@ -1681,6 +1686,8 @@ ata_kill_active(struct ata_channel *chp,
 	struct ata_queue * const chq = chp->ch_queue;
 	struct ata_xfer *xfer, *xfernext;
 
+	KASSERT(mutex_owned(&chp->ch_lock));
+
 	TAILQ_FOREACH_SAFE(xfer, &chq->active_xfers, c_activechain, xfernext) {
 		(*xfer->c_kill_xfer)(xfer->c_chp, xfer, reason);
 	}
@@ -2000,7 +2007,7 @@ ata_probe_caps(struct ata_drive_datas *d
 	struct ata_channel *chp = drvp->chnl_softc;
 	struct atac_softc *atac = chp->ch_atac;
 	device_t drv_dev = drvp->drv_softc;
-	int i, printed = 0, s;
+	int i, printed = 0;
 	const char *sep = "";
 	int cf_flags;
 
@@ -2015,15 +2022,15 @@ ata_probe_caps(struct ata_drive_datas *d
 		 * Re-do an IDENTIFY with 32-bit transfers,
 		 * and compare results.
 		 */
-		s = splbio();
+		ata_channel_lock(chp);
 		drvp->drive_flags |= ATA_DRIVE_CAP32;
-		splx(s);
+		ata_channel_unlock(chp);
 		ata_get_params(drvp, AT_WAIT, &params2);
 		if (memcmp(&params, &params2, sizeof(struct ataparams)) != 0) {
 			/* Not good. fall back to 16bits */
-			s = splbio();
+			ata_channel_lock(chp);
 			drvp->drive_flags &= ~ATA_DRIVE_CAP32;
-			splx(s);
+			ata_channel_unlock(chp);
 		} else {
 			aprint_verbose_dev(drv_dev, "32-bit data port\n");
 		}
@@ -2101,9 +2108,9 @@ ata_probe_caps(struct ata_drive_datas *d
 			 */
 			return;
 		}
-		s = splbio();
+		ata_channel_lock(chp);
 		drvp->drive_flags |= ATA_DRIVE_MODE;
-		splx(s);
+		ata_channel_unlock(chp);
 		printed = 0;
 		for (i = 7; i >= 0; i--) {
 			if ((params.atap_dmamode_supp & (1 << i)) == 0)
@@ -2127,9 +2134,9 @@ ata_probe_caps(struct ata_drive_datas *d
 					continue;
 				drvp->DMA_mode = i;
 				drvp->DMA_cap = i;
-				s = splbio();
+				ata_channel_lock(chp);
 				drvp->drive_flags |= ATA_DRIVE_DMA;
-				splx(s);
+				ata_channel_unlock(chp);
 			}
 #endif
 			break;
@@ -2168,9 +2175,9 @@ ata_probe_caps(struct ata_drive_datas *d
 						continue;
 					drvp->UDMA_mode = i;
 					drvp->UDMA_cap = i;
-					s = splbio();
+					ata_channel_lock(chp);
 					drvp->drive_flags |= ATA_DRIVE_UDMA;
-					splx(s);
+					ata_channel_unlock(chp);
 				}
 #endif
 				break;
@@ -2178,7 +2185,7 @@ ata_probe_caps(struct ata_drive_datas *d
 		}
 	}
 
-	s = splbio();
+	ata_channel_lock(chp);
 	drvp->drive_flags &= ~ATA_DRIVE_NOSTREAM;
 	if (drvp->drive_type == ATA_DRIVET_ATAPI) {
 		if (atac->atac_cap & ATAC_CAP_ATAPI_NOSTREAM)
@@ -2187,7 +2194,7 @@ ata_probe_caps(struct ata_drive_datas *d
 		if (atac->atac_cap & ATAC_CAP_ATA_NOSTREAM)
 			drvp->drive_flags |= ATA_DRIVE_NOSTREAM;
 	}
-	splx(s);
+	ata_channel_unlock(chp);
 
 	/* Try to guess ATA version here, if it didn't get reported */
 	if (drvp->ata_vers == 0) {
@@ -2201,11 +2208,11 @@ ata_probe_caps(struct ata_drive_datas *d
 	}
 	cf_flags = device_cfdata(drv_dev)->cf_flags;
 	if (cf_flags & ATA_CONFIG_PIO_SET) {
-		s = splbio();
+		ata_channel_lock(chp);
 		drvp->PIO_mode =
 		    (cf_flags & ATA_CONFIG_PIO_MODES) >> ATA_CONFIG_PIO_OFF;
 		drvp->drive_flags |= ATA_DRIVE_MODE;
-		splx(s);
+		ata_channel_unlock(chp);
 	}
 #if NATA_DMA
 	if ((atac->atac_cap & ATAC_CAP_DMA) == 0) {
@@ -2213,7 +2220,7 @@ ata_probe_caps(struct ata_drive_datas *d
 		return;
 	}
 	if (cf_flags & ATA_CONFIG_DMA_SET) {
-		s = splbio();
+		ata_channel_lock(chp);
 		if ((cf_flags & ATA_CONFIG_DMA_MODES) ==
 		    ATA_CONFIG_DMA_DISABLE) {
 			drvp->drive_flags &= ~ATA_DRIVE_DMA;
@@ -2222,7 +2229,7 @@ ata_probe_caps(struct ata_drive_datas *d
 			    ATA_CONFIG_DMA_OFF;
 			drvp->drive_flags |= ATA_DRIVE_DMA | ATA_DRIVE_MODE;
 		}
-		splx(s);
+		ata_channel_unlock(chp);
 	}
 
 	/*
@@ -2239,7 +2246,7 @@ ata_probe_caps(struct ata_drive_datas *d
 	}
 
 	/* Probe NCQ support - READ/WRITE FPDMA QUEUED command support */
-	s = splbio();
+	ata_channel_lock(chp);
 	drvp->drv_openings = 1;
 	if (params.atap_sata_caps & SATA_NATIVE_CMDQ) {
 		if (atac->atac_cap & ATAC_CAP_NCQ)
@@ -2254,7 +2261,7 @@ ata_probe_caps(struct ata_drive_datas *d
 			aprint_verbose(" w/PRIO");
 		}
 	}
-	splx(s);
+	ata_channel_unlock(chp);
 
 	if (printed)
 		aprint_verbose("\n");
@@ -2265,7 +2272,7 @@ ata_probe_caps(struct ata_drive_datas *d
 		return;
 	}
 	if (cf_flags & ATA_CONFIG_UDMA_SET) {
-		s = splbio();
+		ata_channel_lock(chp);
 		if ((cf_flags & ATA_CONFIG_UDMA_MODES) ==
 		    ATA_CONFIG_UDMA_DISABLE) {
 			drvp->drive_flags &= ~ATA_DRIVE_UDMA;
@@ -2274,7 +2281,7 @@ ata_probe_caps(struct ata_drive_datas *d
 			    ATA_CONFIG_UDMA_OFF;
 			drvp->drive_flags |= ATA_DRIVE_UDMA | ATA_DRIVE_MODE;
 		}
-		splx(s);
+		ata_channel_unlock(chp);
 	}
 #endif	/* NATA_UDMA */
 #endif	/* NATA_DMA */
@@ -2472,8 +2479,10 @@ atabus_rescan(device_t self, const char 
 }
 
 void
-ata_delay(int ms, const char *msg, int flags)
+ata_delay(struct ata_channel *chp, int ms, const char *msg, int flags)
 {
+	KASSERT(mutex_owned(&chp->ch_lock));
+
 	if ((flags & (AT_WAIT | AT_POLL)) == AT_POLL) {
 		/*
 		 * can't use kpause(), we may be in interrupt context
@@ -2482,7 +2491,7 @@ ata_delay(int ms, const char *msg, int f
 		delay(ms * 1000);
 	} else {
 		int pause = mstohz(ms);
-		kpause(msg, false, pause > 0 ? pause : 1, NULL);
+		kpause(msg, false, pause > 0 ? pause : 1, &chp->ch_lock);
 	}
 }
 
@@ -2580,3 +2589,19 @@ ata_channel_lock_owned(struct ata_channe
 {
 	KASSERT(mutex_owned(&chp->ch_lock));
 }
+
+void
+ata_wait_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+	KASSERT(mutex_owned(&chp->ch_lock));
+
+	cv_wait(&xfer->c_finish, &chp->ch_lock);
+}
+
+void
+ata_wake_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
+{
+	KASSERT(mutex_owned(&chp->ch_lock));
+
+	cv_signal(&xfer->c_finish);
+}

Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.92.8.25 src/sys/dev/ata/atavar.h:1.92.8.26
--- src/sys/dev/ata/atavar.h:1.92.8.25	Sun Sep 10 19:31:15 2017
+++ src/sys/dev/ata/atavar.h	Tue Sep 19 21:06:25 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: atavar.h,v 1.92.8.25 2017/09/10 19:31:15 jdolecek Exp $	*/
+/*	$NetBSD: atavar.h,v 1.92.8.26 2017/09/19 21:06:25 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -134,6 +134,7 @@ struct ata_xfer {
 	struct callout c_timo_callout;	/* timeout callout handle */
 	struct callout c_retry_callout;	/* retry callout handle */
 	kcondvar_t c_active;		/* somebody actively waiting for xfer */
+	kcondvar_t c_finish;		/* somebody waiting for xfer finish */
 	int8_t c_slot;			/* queue slot # */
 
 #define c_startzero	c_chp
@@ -182,7 +183,7 @@ struct ata_xfer {
 #define	C_TIMEOU	0x0002		/* xfer processing timed out */
 #define	C_POLL		0x0004		/* command is polled */
 #define	C_DMA		0x0008		/* command uses DMA */
-#define C_WAIT		0x0010		/* can use tsleep */
+#define C_WAIT		0x0010		/* can use kpause */
 #define C_WAITACT	0x0020		/* wakeup when active */
 #define C_FREE		0x0040		/* call ata_free_xfer() asap */
 #define C_PIOBM		0x0080		/* command uses busmastering PIO */
@@ -220,6 +221,7 @@ struct ata_queue {
 	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 */
 	uint32_t active_xfers_used;		/* mask of active commands */
 	uint32_t queue_xfers_avail;		/* available xfers mask */
@@ -515,6 +517,8 @@ void	ata_free_xfer(struct ata_channel *,
 void	ata_deactivate_xfer(struct ata_channel *, struct ata_xfer *);
 void	ata_exec_xfer(struct ata_channel *, struct ata_xfer *);
 int	ata_xfer_start(struct ata_xfer *xfer);
+void	ata_wait_xfer(struct ata_channel *, struct ata_xfer *xfer);
+void	ata_wake_xfer(struct ata_channel *, struct ata_xfer *xfer);
 
 void	ata_timeout(void *);
 bool	ata_timo_xfer_check(struct ata_xfer *);
@@ -550,7 +554,7 @@ struct ata_xfer *
 struct ata_xfer *
 	ata_queue_drive_active_xfer(struct ata_channel *, int);
 
-void	ata_delay(int, const char *, int);
+void	ata_delay(struct ata_channel *, int, const char *, int);
 
 bool	ata_waitdrain_xfer_check(struct ata_channel *, struct ata_xfer *);
 

Index: src/sys/dev/ata/sata_subr.c
diff -u src/sys/dev/ata/sata_subr.c:1.21 src/sys/dev/ata/sata_subr.c:1.21.24.1
--- src/sys/dev/ata/sata_subr.c:1.21	Wed Apr  3 17:15:07 2013
+++ src/sys/dev/ata/sata_subr.c	Tue Sep 19 21:06:25 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: sata_subr.c,v 1.21 2013/04/03 17:15:07 bouyer Exp $	*/
+/*	$NetBSD: sata_subr.c,v 1.21.24.1 2017/09/19 21:06:25 jdolecek Exp $	*/
 
 /*-
  * Copyright (c) 2004 The NetBSD Foundation, Inc.
@@ -33,7 +33,7 @@
  * Common functions for Serial ATA.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sata_subr.c,v 1.21 2013/04/03 17:15:07 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sata_subr.c,v 1.21.24.1 2017/09/19 21:06:25 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -85,6 +85,8 @@ sata_reset_interface(struct ata_channel 
 	uint32_t scontrol, sstatus;
 	int i;
 
+	ata_channel_lock_owned(chp);
+
 	/* bring the PHYs online.
 	 * The work-around for errata #1 of the Intel GD31244 says that we must
 	 * write 0 to the port first to be sure of correctly initializing
@@ -92,19 +94,19 @@ sata_reset_interface(struct ata_channel 
 	 */
 	bus_space_write_4(sata_t, scontrol_r, 0, 0);
 	scontrol = SControl_IPM_NONE | SControl_SPD_ANY | SControl_DET_INIT;
-	bus_space_write_4 (sata_t, scontrol_r, 0, scontrol);
+	bus_space_write_4(sata_t, scontrol_r, 0, scontrol);
 
-	ata_delay(50, "sataup", flags);
+	ata_delay(chp, 50, "sataup", flags);
 	scontrol &= ~SControl_DET_INIT;
 	bus_space_write_4(sata_t, scontrol_r, 0, scontrol);
 
-	ata_delay(50, "sataup", flags);
+	ata_delay(chp, 50, "sataup", flags);
 	/* wait up to 1s for device to come up */
 	for (i = 0; i < 100; i++) {
 		sstatus = bus_space_read_4(sata_t, sstatus_r, 0);
 		if ((sstatus & SStatus_DET_mask) == SStatus_DET_DEV)
 			break;
-		ata_delay(10, "sataup", flags);
+		ata_delay(chp, 10, "sataup", flags);
 	}
 	/*
 	 * if we have a link up without device, wait a few more seconds
@@ -112,7 +114,7 @@ sata_reset_interface(struct ata_channel 
 	 */
 	if ((sstatus & SStatus_DET_mask) == SStatus_DET_DEV_NE) {
 		for (i = 0; i < 500; i++) {
-			ata_delay(10, "sataup", flags);
+			ata_delay(chp, 10, "sataup", flags);
 			sstatus = bus_space_read_4(sata_t, sstatus_r, 0);
 			if ((sstatus & SStatus_DET_mask) == SStatus_DET_DEV)
 				break;
@@ -152,7 +154,8 @@ void
 sata_interpret_sig(struct ata_channel *chp, int port, uint32_t sig)
 {
 	int err;
-	int s;
+
+	ata_channel_lock_owned(chp);
 
 	/* some ATAPI devices have bogus lower two bytes, sigh */
 	if ((sig & 0xffff0000) == 0xeb140000) {
@@ -169,7 +172,6 @@ sata_interpret_sig(struct ata_channel *c
 	}
 	KASSERT(port < chp->ch_ndrives);
 
-	s = splbio();
 	switch(sig) {
 	case 0x96690101:
 		KASSERT(port == 0 || port == PMP_PORT_CTL);
@@ -195,5 +197,4 @@ sata_interpret_sig(struct ata_channel *c
 		    "Assuming it's a disk.\n", sig, port);
 		break;
 	}
-	splx(s);
 }

Index: src/sys/dev/ata/satapmp_subr.c
diff -u src/sys/dev/ata/satapmp_subr.c:1.12.24.5 src/sys/dev/ata/satapmp_subr.c:1.12.24.6
--- src/sys/dev/ata/satapmp_subr.c:1.12.24.5	Wed Jul 26 18:12:12 2017
+++ src/sys/dev/ata/satapmp_subr.c	Tue Sep 19 21:06:25 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: satapmp_subr.c,v 1.12.24.5 2017/07/26 18:12:12 jdolecek Exp $	*/
+/*	$NetBSD: satapmp_subr.c,v 1.12.24.6 2017/09/19 21:06:25 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.5 2017/07/26 18:12:12 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: satapmp_subr.c,v 1.12.24.6 2017/09/19 21:06:25 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -48,9 +48,9 @@ __KERNEL_RCSID(0, "$NetBSD: satapmp_subr
 #include <dev/ata/satareg.h>
 
 static int
-satapmp_read_8(struct ata_channel *chp, int port, int reg, uint64_t *value)
+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;
@@ -60,10 +60,7 @@ satapmp_read_8(struct ata_channel *chp, 
 	KASSERT(chp->ch_ndrives >= PMP_MAX_DRIVES);
 	drvp = &chp->ch_drive[PMP_PORT_CTL];
 	KASSERT(drvp->drive == PMP_PORT_CTL);
-
-	xfer = ata_get_xfer(chp);
-	if (xfer == NULL)
-		return EINTR;
+	ata_channel_lock_owned(chp);
 
 	xfer->c_ata_c.r_command = PMPC_READ_PORT;
 	xfer->c_ata_c.r_features = reg;
@@ -73,6 +70,7 @@ satapmp_read_8(struct ata_channel *chp, 
 	xfer->c_ata_c.r_st_pmask = WDCS_DRDY;
 	xfer->c_ata_c.flags = AT_LBA48 | AT_READREG | AT_WAIT;
 
+	ata_channel_unlock(chp);
 	if ((*atac->atac_bustype_ata->ata_exec_command)(drvp,
 	    xfer) != ATACMD_COMPLETE) {
 		aprint_error_dev(chp->atabus,
@@ -101,17 +99,18 @@ satapmp_read_8(struct ata_channel *chp, 
 		((uint64_t)((xfer->c_ata_c.r_count >> 0) & 0xff) << 0);
 
 out:
-	ata_free_xfer(chp, xfer);
+	ata_channel_lock(chp);
 	return error;
 }
 
 static inline int
-satapmp_read(struct ata_channel *chp, int port, int reg, uint32_t *value)
+satapmp_read(struct ata_channel *chp, int port, int reg, uint32_t *value,
+    struct ata_xfer *xfer)
 {
 	uint64_t value64;
 	int ret;
 
-	ret = satapmp_read_8(chp, port, reg, &value64);
+	ret = satapmp_read_8(chp, port, reg, &value64, xfer);
 	if (ret)
 		return ret;
 
@@ -120,9 +119,9 @@ satapmp_read(struct ata_channel *chp, in
 }
 
 static int
-satapmp_write_8(struct ata_channel *chp, int port, int reg, uint64_t value)
+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;
@@ -132,10 +131,7 @@ satapmp_write_8(struct ata_channel *chp,
 	KASSERT(chp->ch_ndrives >= PMP_MAX_DRIVES);
 	drvp = &chp->ch_drive[PMP_PORT_CTL];
 	KASSERT(drvp->drive == PMP_PORT_CTL);
-
-	xfer = ata_get_xfer(chp);
-	if (xfer == NULL)
-		return EINTR;
+	ata_channel_lock_owned(chp);
 
 	xfer->c_ata_c.r_command = PMPC_WRITE_PORT;
 	xfer->c_ata_c.r_features = reg;
@@ -149,6 +145,7 @@ satapmp_write_8(struct ata_channel *chp,
 	xfer->c_ata_c.r_st_pmask = WDCS_DRDY;
 	xfer->c_ata_c.flags = AT_LBA48 | AT_WAIT;
 
+	ata_channel_unlock(chp);
 	if ((*atac->atac_bustype_ata->ata_exec_command)(drvp,
 	    xfer) != ATACMD_COMPLETE) {
 		aprint_error_dev(chp->atabus,
@@ -172,14 +169,15 @@ satapmp_write_8(struct ata_channel *chp,
 	}
 
 out:
-	ata_free_xfer(chp, xfer);
+	ata_channel_lock(chp);
 	return error;
 }
 
 static inline int
-satapmp_write(struct ata_channel *chp, int port, int reg, uint32_t value)
+satapmp_write(struct ata_channel *chp, int port, int reg, uint32_t value,
+    struct ata_xfer *xfer)
 {
-	return satapmp_write_8(chp, port, reg, value);
+	return satapmp_write_8(chp, port, reg, value, xfer);
 }
 
 /*
@@ -187,30 +185,34 @@ satapmp_write(struct ata_channel *chp, i
  * XXX duplicate of sata_reset_interface()
  */
 static uint32_t
-satapmp_reset_device_port(struct ata_channel *chp, int port)
+satapmp_reset_device_port(struct ata_channel *chp, int port,
+    struct ata_xfer *xfer)
 {
 	uint32_t scontrol, sstatus;
 	int i;
 
+	ata_channel_lock_owned(chp);
+
 	/* bring the PHY online */
 	scontrol = SControl_IPM_NONE | SControl_SPD_ANY | SControl_DET_INIT;
-	if (satapmp_write(chp, port, PMP_PSCR_SControl, scontrol) != 0)
+	if (satapmp_write(chp, port, PMP_PSCR_SControl, scontrol, xfer) != 0)
 		return 0;
 
-	tsleep(chp, PRIBIO, "sataup", mstohz(50));
+	ata_delay(chp, 50, "sataup", AT_WAIT);
 	scontrol &= ~SControl_DET_INIT;
-	if (satapmp_write(chp, port, PMP_PSCR_SControl, scontrol) != 0)
+	if (satapmp_write(chp, port, PMP_PSCR_SControl, scontrol, xfer) != 0)
 		return 0;
-	tsleep(chp, PRIBIO, "sataup", mstohz(50));
+	ata_delay(chp, 50, "sataup", AT_WAIT);
 
 	/* wait up to 1s for device to come up */
 	for (i = 0; i < 100; i++) {
 		
-		if (satapmp_read(chp, port, PMP_PSCR_SStatus, &sstatus) != 0)
+		if (satapmp_read(chp, port, PMP_PSCR_SStatus, &sstatus,
+		    xfer) != 0)
 			return 0;
 		if ((sstatus & SStatus_DET_mask) == SStatus_DET_DEV)
 			break;
-		tsleep(chp, PRIBIO, "sataup", mstohz(10));
+		ata_delay(chp, 10, "sataup", AT_WAIT);
 	}
 
 	switch (sstatus & SStatus_DET_mask) {
@@ -238,25 +240,31 @@ satapmp_reset_device_port(struct ata_cha
 }
 
 void
-satapmp_rescan(struct ata_channel *chp) {
+satapmp_rescan(struct ata_channel *chp, struct ata_xfer *xfer)
+{
 	int i;
 	uint32_t sig;
 
 	KASSERT(chp->ch_satapmp_nports <= PMP_PORT_CTL);
 	KASSERT(chp->ch_satapmp_nports <= chp->ch_ndrives);
+	ata_channel_lock_owned(chp);
 
 	for (i = 0; i < chp->ch_satapmp_nports; i++) {
 		if (chp->ch_drive[i].drive_type != ATA_DRIVET_NONE ||
-		    satapmp_reset_device_port(chp, i) != SStatus_DET_DEV) {
+		    satapmp_reset_device_port(chp, i, xfer)
+		    != SStatus_DET_DEV) {
 			continue;
 		}
-		if (satapmp_write(chp, i, PMP_PSCR_SError, 0xffffffff) != 0) {
+		if (satapmp_write(chp, i, PMP_PSCR_SError, 0xffffffff, xfer)
+		    != 0) {
 			aprint_error("%s PMP port %d: can't write SError\n",
 			    device_xname(chp->atabus), i);
 			continue;
 		}
+		ata_channel_unlock(chp);
 		chp->ch_atac->atac_bustype_ata->ata_reset_drive(
 		    &chp->ch_drive[i], AT_WAIT, &sig);
+		ata_channel_lock(chp);
 
 		sata_interpret_sig(chp, i, sig);
 	}
@@ -266,14 +274,23 @@ void
 satapmp_attach(struct ata_channel *chp)
 {
 	uint32_t id, rev, inf;
+	struct ata_xfer *xfer;
 
-	if (satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_ID, &id) != 0 ||
-	    satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_REV, &rev) != 0 ||
-	    satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_INF, &inf) != 0) {
-		aprint_normal_dev(chp->atabus, "can't read PMP registers\n");
+	xfer = ata_get_xfer(chp);
+	if (xfer == NULL) {
+		aprint_normal_dev(chp->atabus, "no available xfer\n");
 		return;
 	}
 
+	ata_channel_lock(chp);
+
+	if (satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_ID, &id, xfer) != 0 ||
+	    satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_REV, &rev, xfer) != 0 ||
+	    satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_INF, &inf, xfer) != 0) {
+		aprint_normal_dev(chp->atabus, "can't read PMP registers\n");
+		goto out;
+	}
+
 	aprint_normal("%s at %s channel %d: SATA port multiplier, %d ports\n",
 	    device_xname(chp->atabus),
 	    device_xname(chp->ch_atac->atac_dev), chp->ch_channel,
@@ -293,5 +310,9 @@ satapmp_attach(struct ata_channel *chp)
 	chp->ch_satapmp_nports = PMP_INF_NPORTS(inf);
 
 	/* reset and bring up PHYs */
-	satapmp_rescan(chp);
+	satapmp_rescan(chp, xfer);
+
+out:
+	ata_channel_unlock(chp);
+	ata_free_xfer(chp, xfer);
 }

Index: src/sys/dev/ata/satapmpvar.h
diff -u src/sys/dev/ata/satapmpvar.h:1.3 src/sys/dev/ata/satapmpvar.h:1.3.30.1
--- src/sys/dev/ata/satapmpvar.h:1.3	Wed Aug  1 09:02:03 2012
+++ src/sys/dev/ata/satapmpvar.h	Tue Sep 19 21:06:25 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: satapmpvar.h,v 1.3 2012/08/01 09:02:03 bouyer Exp $	*/
+/*	$NetBSD: satapmpvar.h,v 1.3.30.1 2017/09/19 21:06:25 jdolecek Exp $	*/
 
 
 /*
@@ -29,7 +29,7 @@
 #define	_DEV_ATA_SATAPMPVAR_H_
 
 void satapmp_attach(struct ata_channel *);
-void satapmp_rescan(struct ata_channel *);
+void satapmp_rescan(struct ata_channel *, struct ata_xfer *);
 
 #endif	/* _DEV_ATA_SATAPMPVAR_H_ */
 

Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.57.6.28 src/sys/dev/ic/ahcisata_core.c:1.57.6.29
--- src/sys/dev/ic/ahcisata_core.c:1.57.6.28	Tue Sep 19 17:52:52 2017
+++ src/sys/dev/ic/ahcisata_core.c	Tue Sep 19 21:06:25 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisata_core.c,v 1.57.6.28 2017/09/19 17:52:52 jdolecek Exp $	*/
+/*	$NetBSD: ahcisata_core.c,v 1.57.6.29 2017/09/19 21:06:25 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.28 2017/09/19 17:52:52 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.29 2017/09/19 21:06:25 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -58,7 +58,8 @@ static void ahci_probe_drive(struct ata_
 static void ahci_setup_channel(struct ata_channel *);
 
 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 *);
+static int  ahci_do_reset_drive(struct ata_channel *, int, int, uint32_t *,
+	struct ata_xfer *xfer);
 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 *);
@@ -678,12 +679,23 @@ 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);
+
+	ata_channel_lock(chp);
+
 	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) != 0)
+	if (ahci_do_reset_drive(chp, drvp->drive, flags, sigp, xfer) != 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);
+
 	return;
 }
 
@@ -731,7 +743,7 @@ ahci_exec_fis(struct ata_channel *chp, i
 			    AHCINAME(sc), chp->ch_channel, is);
 			return ERR_DF;
 		}
-		ata_delay(10, "ahcifis", flags);
+		ata_delay(chp, 10, "ahcifis", flags);
 	}
 
 	aprint_debug("%s channel %d: timeout sending FIS\n",
@@ -741,7 +753,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)
+    uint32_t *sigp, struct ata_xfer *xfer)
 {
 	struct ahci_channel *achp = (struct ahci_channel *)chp;
 	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
@@ -749,9 +761,10 @@ ahci_do_reset_drive(struct ata_channel *
 	struct ahci_cmd_header *cmd_h;
 	int i;
 	uint32_t sig;
-	struct ata_xfer *xfer = NULL;
 
 	KASSERT((AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) & AHCI_P_CMD_CR) == 0);
+	ata_channel_lock_owned(chp);
+
 again:
 	/* clear port interrupt register */
 	AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);
@@ -774,8 +787,6 @@ again:
 		goto skip_reset;
 
 	/* polled command, assume interrupts are disabled */
-	/* use available slot to send reset, if none available fail */
-	xfer = ata_get_xfer_ext(chp, C_RECOVERY, 0);
 
 	cmd_h = &achp->ahcic_cmdh[xfer->c_slot];
 	cmd_tbl = achp->ahcic_cmd_tbl[xfer->c_slot];
@@ -837,7 +848,7 @@ skip_reset:
 		sig = AHCI_READ(sc, AHCI_P_TFD(chp->ch_channel));
 		if ((__SHIFTOUT(sig, AHCI_P_TFD_ST) & WDCS_BSY) == 0)
 			break;
-		ata_delay(10, "ahcid2h", flags);
+		ata_delay(chp, 10, "ahcid2h", flags);
 	}
 	if (i == AHCI_RST_WAIT) {
 		aprint_error("%s: BSY never cleared, TD 0x%x\n",
@@ -855,10 +866,8 @@ skip_reset:
 	    AHCINAME(sc), chp->ch_channel, sig,
 	    AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel))), DEBUG_PROBE);
 end:
-	if (xfer != NULL)
-		ata_free_xfer(chp, xfer);
 	ahci_channel_stop(sc, chp, flags);
-	ata_delay(500, "ahcirst", flags);
+	ata_delay(chp, 500, "ahcirst", flags);
 	/* clear port interrupt register */
 	AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);
 	ahci_channel_start(sc, chp, flags,
@@ -873,6 +882,8 @@ ahci_reset_channel(struct ata_channel *c
 	struct ahci_channel *achp = (struct ahci_channel *)chp;
 	int i, tfd;
 
+	ata_channel_lock(chp);
+
 	ahci_channel_stop(sc, chp, flags);
 	if (sata_reset_interface(chp, sc->sc_ahcit, achp->ahcic_scontrol,
 	    achp->ahcic_sstatus, flags) != SStatus_DET_DEV) {
@@ -880,7 +891,7 @@ ahci_reset_channel(struct ata_channel *c
 		/* XXX and then ? */
 	}
 	ata_kill_active(chp, KILL_RESET, flags);
-	ata_delay(500, "ahcirst", flags);
+	ata_delay(chp, 500, "ahcirst", flags);
 	/* clear port interrupt register */
 	AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);
 	/* clear SErrors and start operations */
@@ -891,7 +902,7 @@ ahci_reset_channel(struct ata_channel *c
 		tfd = AHCI_READ(sc, AHCI_P_TFD(chp->ch_channel));
 		if ((AHCI_TFD_ST(tfd) & WDCS_BSY) == 0)
 			break;
-		ata_delay(10, "ahcid2h", flags);
+		ata_delay(chp, 10, "ahcid2h", flags);
 	}
 	if ((AHCI_TFD_ST(tfd) & WDCS_BSY) != 0)
 		aprint_error("%s: BSY never cleared, TD 0x%x\n",
@@ -901,6 +912,8 @@ ahci_reset_channel(struct ata_channel *c
 	/* clear port interrupt register */
 	AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);
 
+	ata_channel_unlock(chp);
+
 	return;
 }
 
@@ -928,6 +941,17 @@ 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;
+
+	xfer = ata_get_xfer_ext(chp, 0, 0);
+	if (xfer == NULL) {
+		aprint_error_dev(sc->sc_atac.atac_dev,
+		    "%s: failed to get xfer port %d\n",
+		    __func__, chp->ch_channel);
+		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),
@@ -937,11 +961,12 @@ ahci_probe_drive(struct ata_channel *chp
 	switch (sata_reset_interface(chp, sc->sc_ahcit, achp->ahcic_scontrol,
 	    achp->ahcic_sstatus, AT_WAIT)) {
 	case SStatus_DET_DEV:
-		tsleep(&sc, PRIBIO, "ahcidv", mstohz(500));
+		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);
+			ahci_do_reset_drive(chp, PMP_PORT_CTL, AT_WAIT, &sig,
+			    xfer);
 		} else {
-			ahci_do_reset_drive(chp, 0, AT_WAIT, &sig);
+			ahci_do_reset_drive(chp, 0, AT_WAIT, &sig, xfer);
 		}
 		sata_interpret_sig(chp, 0, sig);
 		/* if we have a PMP attached, inform the controller */
@@ -961,12 +986,13 @@ ahci_probe_drive(struct ata_channel *chp
 		    AHCI_P_IX_OFS | AHCI_P_IX_DPS | AHCI_P_IX_UFS |
 		    AHCI_P_IX_PSS | AHCI_P_IX_DHRS | AHCI_P_IX_SDBS);
 		/* wait 500ms before actually starting operations */
-		tsleep(&sc, PRIBIO, "ahciprb", mstohz(500));
+		ata_delay(chp, 500, "ahciprb", AT_WAIT);
 		break;
 
 	default:
 		break;
 	}
+	ata_channel_unlock(chp);
 }
 
 static void
@@ -1010,9 +1036,12 @@ ahci_exec_command(struct ata_drive_datas
 		ret = ATACMD_COMPLETE;
 	} else {
 		if (ata_c->flags & AT_WAIT) {
-			while ((ata_c->flags & AT_DONE) == 0) {
-				tsleep(ata_c, PRIBIO, "ahcicmd", 0);
+			ata_channel_lock(chp);
+			if ((ata_c->flags & AT_DONE) == 0) {
+				ata_wait_xfer(chp, xfer);
+				KASSERT((ata_c->flags & AT_DONE) != 0);
 			}
+			ata_channel_unlock(chp);
 			ret = ATACMD_COMPLETE;
 		} else {
 			ret = ATACMD_QUEUED;
@@ -1089,14 +1118,18 @@ ahci_cmd_poll(struct ata_channel *chp, s
 	struct ahci_softc *sc = AHCI_CH2SC(chp);
 	struct ahci_channel *achp = (struct ahci_channel *)chp;
 
+	ata_channel_lock(chp);
+
 	/*
 	 * Polled command. 
 	 */
 	for (int i = 0; i < xfer->c_ata_c.timeout / 10; i++) {
 		if (xfer->c_ata_c.flags & AT_DONE)
 			break;
+		ata_channel_unlock(chp);
 		ahci_intr_port(sc, achp);
-		ata_delay(10, "ahcipl", xfer->c_ata_c.flags);
+		ata_channel_lock(chp);
+		ata_delay(chp, 10, "ahcipl", xfer->c_ata_c.flags);
 	}
 	AHCIDEBUG_PRINT(("%s port %d poll end GHC 0x%x IS 0x%x list 0x%x%x fis 0x%x%x CMD 0x%x CI 0x%x\n", AHCINAME(sc), chp->ch_channel, 
 	    AHCI_READ(sc, AHCI_GHC), AHCI_READ(sc, AHCI_IS),
@@ -1107,6 +1140,9 @@ ahci_cmd_poll(struct ata_channel *chp, s
 	    AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)),
 	    AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))),
 	    DEBUG_XFERS);
+
+	ata_channel_unlock(chp);
+
 	if ((xfer->c_ata_c.flags & AT_DONE) == 0) {
 		xfer->c_ata_c.flags |= AT_TIMEOU;
 		xfer->c_intr(chp, xfer, 0);
@@ -1239,11 +1275,15 @@ static void
 ahci_cmd_done_end(struct ata_channel *chp, struct ata_xfer *xfer)
 {
 	struct ata_command *ata_c = &xfer->c_ata_c;
-	
+
+	ata_channel_lock(chp);
+
 	ata_c->flags |= AT_DONE;
 
 	if (ata_c->flags & AT_WAIT)
-		wakeup(ata_c);
+		ata_wake_xfer(chp, xfer);
+
+	ata_channel_unlock(chp);
 	return;
 }
 
@@ -1482,7 +1522,7 @@ ahci_channel_stop(struct ahci_softc *sc,
 		if ((AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) & AHCI_P_CMD_CR)
 		    == 0)
 			break;
-		ata_delay(10, "ahcistop", flags);
+		ata_delay(chp, 10, "ahcistop", flags);
 	}
 	if (AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) & AHCI_P_CMD_CR) {
 		printf("%s: channel wouldn't stop\n", AHCINAME(sc));
@@ -1514,7 +1554,7 @@ ahci_channel_start(struct ahci_softc *sc
 			if ((AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) &
 			    AHCI_P_CMD_CLO) == 0)
 				break;
-			ata_delay(10, "ahciclo", flags);
+			ata_delay(chp, 10, "ahciclo", flags);
 		}
 		if (AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel)) & AHCI_P_CMD_CLO) {
 			printf("%s: channel wouldn't CLO\n", AHCINAME(sc));

Index: src/sys/dev/ic/mvsata.c
diff -u src/sys/dev/ic/mvsata.c:1.35.6.25 src/sys/dev/ic/mvsata.c:1.35.6.26
--- src/sys/dev/ic/mvsata.c:1.35.6.25	Sun Sep 10 19:31:15 2017
+++ src/sys/dev/ic/mvsata.c	Tue Sep 19 21:06:25 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: mvsata.c,v 1.35.6.25 2017/09/10 19:31:15 jdolecek Exp $	*/
+/*	$NetBSD: mvsata.c,v 1.35.6.26 2017/09/19 21:06:25 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.25 2017/09/10 19:31:15 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.26 2017/09/19 21:06:25 jdolecek Exp $");
 
 #include "opt_mvsata.h"
 
@@ -677,6 +677,8 @@ mvsata_probe_drive(struct ata_channel *c
 	struct mvsata_port * const mvport = (struct mvsata_port *)chp;
 	uint32_t sstat, sig;
 
+	ata_channel_lock(chp);
+
 	sstat = sata_reset_interface(chp, mvport->port_iot,
 	    mvport->port_sata_scontrol, mvport->port_sata_sstatus, AT_WAIT);
 	switch (sstat) {
@@ -688,6 +690,8 @@ mvsata_probe_drive(struct ata_channel *c
 	default:
 		break;
 	}
+
+	ata_channel_unlock(chp);
 }
 
 #ifndef MVSATA_WITHOUTDMA
@@ -699,6 +703,8 @@ mvsata_reset_drive(struct ata_drive_data
 	uint32_t edma_c;
 	uint32_t sig;
 
+	ata_channel_lock(chp);
+
 	edma_c = MVSATA_EDMA_READ_4(mvport, EDMA_CMD);
 
 	DPRINTF(DEBUG_FUNCS,
@@ -720,6 +726,9 @@ mvsata_reset_drive(struct ata_drive_data
 		mvsata_edma_reset_qptr(mvport);
 		mvsata_edma_enable(mvport);
 	}
+
+	ata_channel_unlock(chp);
+
 	return;
 }
 
@@ -733,6 +742,8 @@ mvsata_reset_channel(struct ata_channel 
 	DPRINTF(DEBUG_FUNCS, ("%s: mvsata_reset_channel: channel=%d\n",
 	    device_xname(MVSATA_DEV2(mvport)), chp->ch_channel));
 
+	ata_channel_lock(chp);
+
 	mvsata_hreset_port(mvport);
 	sstat = sata_reset_interface(chp, mvport->port_iot,
 	    mvport->port_sata_scontrol, mvport->port_sata_sstatus, flags);
@@ -760,6 +771,9 @@ mvsata_reset_channel(struct ata_channel 
 	mvsata_edma_config(mvport, mvport->port_edmamode_curr);
 	mvsata_edma_reset_qptr(mvport);
 	mvsata_edma_enable(mvport);
+
+	ata_channel_unlock(chp);
+
 	return;
 }
 
@@ -1689,8 +1703,12 @@ mvsata_exec_command(struct ata_drive_dat
 		rv = ATACMD_COMPLETE;
 	else {
 		if (ata_c->flags & AT_WAIT) {
-			while ((ata_c->flags & AT_DONE) == 0)
-				tsleep(ata_c, PRIBIO, "mvsatacmd", 0);
+			ata_channel_lock(chp);
+			if ((ata_c->flags & AT_DONE) == 0) {
+				ata_wait_xfer(chp, xfer);
+				KASSERT((ata_c->flags & AT_DONE) != 0);
+			}
+			ata_channel_unlock(chp);
 			rv = ATACMD_COMPLETE;
 		} else
 			rv = ATACMD_QUEUED;
@@ -1801,7 +1819,7 @@ mvsata_wdc_cmd_intr(struct ata_channel *
 		drive_flags = chp->ch_drive[xfer->c_drive].drive_flags;
 
 	if ((ata_c->flags & (AT_WAIT | AT_POLL)) == (AT_WAIT | AT_POLL))
-		/* both wait and poll, we can tsleep here */
+		/* both wait and poll, we can kpause here */
 		wflags = AT_WAIT | AT_POLL;
 	else
 		wflags = AT_POLL;
@@ -2009,9 +2027,11 @@ mvsata_wdc_cmd_done_end(struct ata_chann
 		mvsata_edma_enable(mvport);
 	}
 
+	ata_channel_lock(chp);
 	ata_c->flags |= AT_DONE;
 	if (ata_c->flags & AT_WAIT)
-		wakeup(ata_c);
+		ata_wake_xfer(chp, xfer);
+	ata_channel_unlock(chp);
 }
 
 #if NATAPIBUS > 0
@@ -3481,10 +3501,13 @@ mvsata_reset_hc(struct mvsata_hc *mvhc)
 static uint32_t
 mvsata_softreset(struct mvsata_port *mvport, int flags)
 {
+	struct ata_channel *chp = &mvport->port_ata_channel;
 	uint32_t sig0 = ~0;
 	int timeout;
 	uint8_t st0;
 
+	ata_channel_lock_owned(chp);
+
 	MVSATA_WDC_WRITE_1(mvport, SRB_CAS, WDCTL_RST | WDCTL_IDS | WDCTL_4BIT);
 	delay(10);
 	(void) MVSATA_WDC_READ_1(mvport, SRB_FE);
@@ -3502,7 +3525,7 @@ mvsata_softreset(struct mvsata_port *mvp
 			sig0 |= MVSATA_WDC_READ_1(mvport, SRB_LBAH) << 24;
 			goto out;
 		}
-		ata_delay(10, "atarst", flags);
+		ata_delay(chp, 10, "atarst", flags);
 	}
 
 	aprint_error("%s:%d:%d: %s: timeout\n",
@@ -3541,6 +3564,7 @@ mvsata_edma_enable(struct mvsata_port *m
 static int
 mvsata_edma_disable(struct mvsata_port *mvport, int timeout, int wflags)
 {
+	struct ata_channel *chp = &mvport->port_ata_channel;
 	uint32_t status, command;
 	int ms;
 
@@ -3549,7 +3573,7 @@ mvsata_edma_disable(struct mvsata_port *
 			status = MVSATA_EDMA_READ_4(mvport, EDMA_S);
 			if (status & EDMA_S_EDMAIDLE)
 				break;
-			ata_delay(1, "mvsata_edma1", wflags);
+			ata_delay(chp, 1, "mvsata_edma1", wflags);
 		}
 		if (ms == timeout) {
 			aprint_error("%s:%d:%d: unable to disable EDMA\n",
@@ -3565,7 +3589,7 @@ mvsata_edma_disable(struct mvsata_port *
 			command = MVSATA_EDMA_READ_4(mvport, EDMA_CMD);
 			if (!(command & EDMA_CMD_EENEDMA))
 				break;
-			ata_delay(1, "mvsata_edma2", wflags);
+			ata_delay(chp, 1, "mvsata_edma2", wflags);
 		}
 		if (ms == timeout) {
 			aprint_error("%s:%d:%d: unable to re-enable EDMA\n",

Index: src/sys/dev/ic/siisata.c
diff -u src/sys/dev/ic/siisata.c:1.30.4.37 src/sys/dev/ic/siisata.c:1.30.4.38
--- src/sys/dev/ic/siisata.c:1.30.4.37	Sun Sep 10 19:31:15 2017
+++ src/sys/dev/ic/siisata.c	Tue Sep 19 21:06:25 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.30.4.37 2017/09/10 19:31:15 jdolecek Exp $ */
+/* $NetBSD: siisata.c,v 1.30.4.38 2017/09/19 21:06:25 jdolecek Exp $ */
 
 /* from ahcisata_core.c */
 
@@ -79,7 +79,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.37 2017/09/10 19:31:15 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.38 2017/09/19 21:06:25 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -743,6 +743,8 @@ siisata_reset_drive(struct ata_drive_dat
 	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);
@@ -756,7 +758,7 @@ siisata_reset_drive(struct ata_drive_dat
 		}
 		if (pss & PR_PSS_ATTENTION)
 			break;
-		ata_delay(10, "siiprb", flags);
+		ata_delay(chp, 10, "siiprb", flags);
 	}
 
 	siisata_deactivate_prb(schp, xfer->c_slot);
@@ -777,6 +779,8 @@ siisata_reset_drive(struct ata_drive_dat
 
 	siisata_enable_port_interrupt(chp);
 
+	ata_channel_unlock(chp);
+
 	if (timed_out) {
 		/* timeout */
 		siisata_device_reset(chp);	/* XXX is this right? */
@@ -857,11 +861,13 @@ siisata_probe_drive(struct ata_channel *
 	xfer = ata_get_xfer_ext(chp, 0, 0);
 	if (xfer == NULL) {
 		aprint_error_dev(sc->sc_atac.atac_dev,
-		    "failed to get xfer port %d\n",
-		    chp->ch_channel);
+		    "%s: failed to get xfer port %d\n",
+		    __func__, chp->ch_channel);
 		return;
 	}
 
+	ata_channel_lock(chp);
+
 	/*
 	 * disable port interrupt as we're polling for PHY up and
 	 * prb completion
@@ -884,7 +890,7 @@ siisata_probe_drive(struct ata_channel *
 				break;
 			}
 
-			ata_delay(10, "siiprbrd", AT_WAIT);
+			ata_delay(chp, 10, "siiprbrd", AT_WAIT);
 		}
 		if (timed_out) {
 			aprint_error_dev(sc->sc_atac.atac_dev,
@@ -914,7 +920,7 @@ siisata_probe_drive(struct ata_channel *
 				break;
 			}
 
-			ata_delay(10, "siiprb", AT_WAIT);
+			ata_delay(chp, 10, "siiprb", AT_WAIT);
 		}
 
 		siisata_deactivate_prb(schp, xfer->c_slot);
@@ -951,6 +957,8 @@ siisata_probe_drive(struct ata_channel *
 
 	siisata_enable_port_interrupt(chp);
 
+	ata_channel_unlock(chp);
+
 	ata_free_xfer(chp, xfer);
 
 	SIISATA_DEBUG_PRINT(("%s: %s: port %d done\n", SIISATANAME(sc),
@@ -999,13 +1007,16 @@ siisata_exec_command(struct ata_drive_da
 		ret = ATACMD_COMPLETE;
 	} else {
 		if (ata_c->flags & AT_WAIT) {
-			while ((ata_c->flags & AT_DONE) == 0) {
+			ata_channel_lock(chp);
+			if ((ata_c->flags & AT_DONE) == 0) {
 				SIISATA_DEBUG_PRINT(("%s: %s: sleeping\n",
 				    SIISATANAME(
 				    (struct siisata_softc *)chp->ch_atac),
 				    __func__), DEBUG_FUNCS);
-				tsleep(ata_c, PRIBIO, "siicmd", 0);
+				ata_wait_xfer(chp, xfer);
+				KASSERT((ata_c->flags & AT_DONE) != 0);
 			}
+			ata_channel_unlock(chp);
 			ret = ATACMD_COMPLETE;
 		} else {
 			ret = ATACMD_QUEUED;
@@ -1213,8 +1224,6 @@ siisata_cmd_done(struct ata_channel *chp
 		ata_c->flags |= AT_XFDONE;
 
 	siisata_cmd_done_end(chp, xfer);
-	if ((ATACH_ST(tfd) & WDCS_ERR) == 0)
-		atastart(chp);
 }
 
 static void
@@ -1222,10 +1231,14 @@ siisata_cmd_done_end(struct ata_channel 
 {
 	struct ata_command *ata_c = &xfer->c_ata_c;
 
+	ata_channel_lock(chp);
+
 	ata_c->flags |= AT_DONE;
 
 	if (ata_c->flags & AT_WAIT)
-		wakeup(ata_c);
+		ata_wake_xfer(chp, xfer);
+
+	ata_channel_unlock(chp);
 	return;
 }
 

Index: src/sys/dev/ic/wdc.c
diff -u src/sys/dev/ic/wdc.c:1.283.2.15 src/sys/dev/ic/wdc.c:1.283.2.16
--- src/sys/dev/ic/wdc.c:1.283.2.15	Mon Sep 11 22:19:23 2017
+++ src/sys/dev/ic/wdc.c	Tue Sep 19 21:06:25 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdc.c,v 1.283.2.15 2017/09/11 22:19:23 jdolecek Exp $ */
+/*	$NetBSD: wdc.c,v 1.283.2.16 2017/09/19 21:06:25 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.15 2017/09/11 22:19:23 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.283.2.16 2017/09/19 21:06:25 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wdc.h"
@@ -107,7 +107,7 @@ __KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.28
 #define WDCNDELAY_DEBUG	50
 #endif
 
-/* When polling wait that much and then tsleep for 1/hz seconds */
+/* When polling wait that much and then kpause for 1/hz seconds */
 #define WDCDELAY_POLL 1 /* ms */
 
 /* timeout for the control commands */
@@ -140,7 +140,7 @@ const struct ata_bustype wdc_ata_bustype
 
 /* Flags to wdcreset(). */
 #define	RESET_POLL	1
-#define	RESET_SLEEP	0	/* wdcreset() will use tsleep() */
+#define	RESET_SLEEP	0	/* wdcreset() will use kpause() */
 
 static int	wdcprobe1(struct ata_channel *, int);
 static int	wdcreset(struct ata_channel *, int);
@@ -206,10 +206,14 @@ wdc_sataprobe(struct ata_channel *chp)
 {
 	struct wdc_regs *wdr = CHAN_TO_WDC_REGS(chp);
 	uint8_t st = 0, sc __unused, sn __unused, cl, ch;
-	int i, s;
+	int i;
 
 	KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
 
+	/* do this before we take lock */
+
+	ata_channel_lock(chp);
+
 	/* reset the PHY and bring online */
 	switch (sata_reset_interface(chp, wdr->sata_iot, wdr->sata_control,
 	    wdr->sata_status, AT_WAIT)) {
@@ -223,7 +227,7 @@ wdc_sataprobe(struct ata_channel *chp)
 			    wdr->cmd_iohs[wd_status], 0);
 			if ((st & WDCS_BSY) == 0)
 				break;
-			tsleep(&chp, PRIBIO, "sataprb", 1);
+			ata_delay(chp, 1, "sataprb", AT_WAIT);
 		}
 		if (i == WDC_PROBE_WAIT * hz)
 			aprint_error_dev(chp->ch_atac->atac_dev,
@@ -246,12 +250,10 @@ wdc_sataprobe(struct ata_channel *chp)
 		 * sc and sn are supposed to be 0x1 for ATAPI, but in some
 		 * cases we get wrong values here, so ignore it.
 		 */
-		s = splbio();
 		if (cl == 0x14 && ch == 0xeb)
 			chp->ch_drive[0].drive_type = ATA_DRIVET_ATAPI;
 		else
 			chp->ch_drive[0].drive_type = ATA_DRIVET_ATA;
-		splx(s);
 
 		/*
 		 * issue a reset in case only the interface part of the drive
@@ -264,6 +266,8 @@ wdc_sataprobe(struct ata_channel *chp)
 	default:
 		break;
 	}
+
+	ata_channel_unlock(chp);
 }
 #endif /* NSATA > 0 */
 
@@ -290,7 +294,7 @@ wdc_drvprobe(struct ata_channel *chp)
 	struct wdc_softc *wdc = CHAN_TO_WDC(chp);
 	struct wdc_regs *wdr = &wdc->regs[chp->ch_channel];
 	u_int8_t st0 = 0, st1 = 0;
-	int i, j, error, s, tfd;
+	int i, j, error, tfd;
 
 	if (atabus_alloc_drives(chp, wdc->wdc_maxdrives) != 0)
 		return;
@@ -300,7 +304,7 @@ wdc_drvprobe(struct ata_channel *chp)
 		return;
 	}
 
-	s = splbio();
+	ata_channel_lock(chp);
 	/* for ATA/OLD drives, wait for DRDY, 3s timeout */
 	for (i = 0; i < mstohz(3000); i++) {
 		/*
@@ -335,12 +339,12 @@ wdc_drvprobe(struct ata_channel *chp)
 		     (st1 & WDCS_DRDY)))
 			break;
 #ifdef WDC_NO_IDS
-		/* cannot tsleep here (can't enable IPL_BIO interrups),
+		/* cannot kpause here (can't enable IPL_BIO interrups),
 		 * delay instead
 		 */
 		delay(1000000 / hz);
 #else
-		tsleep(&params, PRIBIO, "atadrdy", 1);
+		ata_delay(chp, 1, "atadrdy", AT_WAIT);
 #endif
 	}
 	if ((st0 & WDCS_DRDY) == 0 &&
@@ -349,7 +353,7 @@ wdc_drvprobe(struct ata_channel *chp)
 	if (chp->ch_ndrives > 1 && (st1 & WDCS_DRDY) == 0 &&
 	    chp->ch_drive[1].drive_type != ATA_DRIVET_ATAPI)
 		chp->ch_drive[1].drive_type = ATA_DRIVET_NONE;
-	splx(s);
+	ata_channel_unlock(chp);
 
 	ATADEBUG_PRINT(("%s:%d: wait DRDY st0 0x%x st1 0x%x\n",
 	    device_xname(atac->atac_dev),
@@ -370,9 +374,9 @@ wdc_drvprobe(struct ata_channel *chp)
 		/* If controller can't do 16bit flag the drives as 32bit */
 		if ((atac->atac_cap &
 		    (ATAC_CAP_DATA16 | ATAC_CAP_DATA32)) == ATAC_CAP_DATA32) {
-			s = splbio();
+			ata_channel_lock(chp);
 			chp->ch_drive[i].drive_flags |= ATA_DRIVE_CAP32;
-			splx(s);
+			ata_channel_unlock(chp);
 		}
 		if (chp->ch_drive[i].drive_type == ATA_DRIVET_NONE)
 			continue;
@@ -390,7 +394,9 @@ wdc_drvprobe(struct ata_channel *chp)
 		error = ata_get_params(&chp->ch_drive[i],
 		    AT_WAIT | AT_POLL, &params);
 		if (error != CMD_OK) {
-			tsleep(&params, PRIBIO, "atacnf", mstohz(1000));
+			ata_channel_lock(chp);
+			ata_delay(chp, 1000, "atacnf", AT_WAIT);
+			ata_channel_unlock(chp);
 
 			/* Shortcut in case we've been shutdown */
 			if (chp->ch_flags & ATACH_SHUTDOWN)
@@ -403,14 +409,13 @@ wdc_drvprobe(struct ata_channel *chp)
 			ATADEBUG_PRINT(("%s:%d:%d: IDENTIFY failed (%d)\n",
 			    device_xname(atac->atac_dev),
 			    chp->ch_channel, i, error), DEBUG_PROBE);
-			s = splbio();
+			ata_channel_lock(chp);
 			if (chp->ch_drive[i].drive_type != ATA_DRIVET_ATA ||
 			    (wdc->cap & WDC_CAPABILITY_PREATA) == 0) {
 				chp->ch_drive[i].drive_type = ATA_DRIVET_NONE;
-				splx(s);
+				ata_channel_unlock(chp);
 				continue;
 			}
-			splx(s);
 			/*
 			 * Pre-ATA drive ?
 			 * Test registers writability (Error register not
@@ -433,9 +438,8 @@ wdc_drvprobe(struct ata_channel *chp)
 				    "writability failed\n",
 				    device_xname(atac->atac_dev),
 				    chp->ch_channel, i), DEBUG_PROBE);
-				    s = splbio();
 				    chp->ch_drive[i].drive_type = ATA_DRIVET_NONE;
-				    splx(s);
+				    ata_channel_unlock(chp);
 				    continue;
 			}
 			if (wdc_wait_for_ready(chp, 10000, 0, &tfd) ==
@@ -443,9 +447,8 @@ wdc_drvprobe(struct ata_channel *chp)
 				ATADEBUG_PRINT(("%s:%d:%d: not ready\n",
 				    device_xname(atac->atac_dev),
 				    chp->ch_channel, i), DEBUG_PROBE);
-				s = splbio();
 				chp->ch_drive[i].drive_type = ATA_DRIVET_NONE;
-				splx(s);
+				ata_channel_unlock(chp);
 				continue;
 			}
 			bus_space_write_1(wdr->cmd_iot,
@@ -456,11 +459,9 @@ wdc_drvprobe(struct ata_channel *chp)
 				ATADEBUG_PRINT(("%s:%d:%d: WDCC_RECAL failed\n",
 				    device_xname(atac->atac_dev),
 				    chp->ch_channel, i), DEBUG_PROBE);
-				s = splbio();
 				chp->ch_drive[i].drive_type = ATA_DRIVET_NONE;
-				splx(s);
+				ata_channel_unlock(chp);
 			} else {
-				s = splbio();
 				for (j = 0; j < chp->ch_ndrives; j++) {
 					if (chp->ch_drive[i].drive_type !=
 					    ATA_DRIVET_NONE) {
@@ -468,7 +469,7 @@ wdc_drvprobe(struct ata_channel *chp)
 						    ATA_DRIVET_OLD;
 					}
 				}
-				splx(s);
+				ata_channel_unlock(chp);
 			}
 		}
 	}
@@ -493,7 +494,6 @@ wdcprobe1(struct ata_channel *chp, int p
 	u_int8_t st0 = 0, st1 = 0, sc __unused, sn __unused, cl, ch;
 	u_int8_t ret_value = 0x03;
 	u_int8_t drive;
-	int s;
 	/* XXX if poll, wdc_probe_count is 0. */
 	int wdc_probe_count =
 	    poll ? (WDC_PROBE_WAIT / WDCDELAY)
@@ -503,7 +503,7 @@ wdcprobe1(struct ata_channel *chp, int p
 	 * Sanity check to see if the wdc channel responds at all.
 	 */
 
-	s = splbio();
+	ata_channel_lock(chp);
 	if ((wdc->cap & WDC_CAPABILITY_NO_EXTRA_RESETS) == 0) {
 		while (wdc_probe_count-- > 0) {
 			if (wdc->select)
@@ -656,7 +656,7 @@ wdcprobe1(struct ata_channel *chp, int p
 		}
 
 		if (ret_value == 0) {
-			splx(s);
+			ata_channel_unlock(chp);
 			return 0;
 		}
 	}
@@ -697,16 +697,14 @@ wdcprobe1(struct ata_channel *chp, int p
 #ifdef WDC_NO_IDS
 	ret_value = __wdcwait_reset(chp, ret_value, RESET_POLL);
 #else
-	splx(s);
 	ret_value = __wdcwait_reset(chp, ret_value, poll);
-	s = splbio();
 #endif
 	ATADEBUG_PRINT(("%s:%d: after reset, ret_value=%#x\n",
 	    __func__, chp->ch_channel, ret_value), DEBUG_PROBE);
 
 	/* if reset failed, there's nothing here */
 	if (ret_value == 0) {
-		splx(s);
+		ata_channel_unlock(chp);
 		return 0;
 	}
 
@@ -759,7 +757,7 @@ wdcprobe1(struct ata_channel *chp, int p
 		(void)bus_space_read_1(wdr->cmd_iot,
 		    wdr->cmd_iohs[wd_status], 0);
 	}
-	splx(s);
+	ata_channel_unlock(chp);
 	return (ret_value);
 }
 
@@ -925,12 +923,12 @@ wdc_reset_channel(struct ata_channel *ch
 	 * ATAPI_SOFT_RESET
 	 */
 	xfer = ata_queue_get_active_xfer(chp);
+
+	ata_channel_lock(chp);
+
 	if (xfer && xfer->c_chp == chp && (xfer->c_flags & C_ATAPI)) {
 		wdccommandshort(chp, xfer->c_drive, ATAPI_SOFT_RESET);
-		if (flags & AT_WAIT)
-			tsleep(&flags, PRIBIO, "atardl", mstohz(1) + 1);
-		else
-			delay(1000);
+		ata_delay(chp, 1000, "atardl", flags);
 	}
 
 	/* reset the channel */
@@ -943,10 +941,7 @@ wdc_reset_channel(struct ata_channel *ch
 	 * wait a bit after reset; in case the DMA engines needs some time
 	 * to recover.
 	 */
-	if (flags & AT_WAIT)
-		tsleep(&flags, PRIBIO, "atardl", mstohz(1) + 1);
-	else
-		delay(1000);
+	ata_delay(chp, 1000, "atardl", flags);
 
 	/*
 	 * Look for pending xfers. If we have a shared queue, we'll also reset
@@ -955,9 +950,11 @@ wdc_reset_channel(struct ata_channel *ch
 	 * it is queued for retry immediatelly without waiting for I/O timeout.
 	 */
 	if (xfer) {
-		if (xfer->c_chp != chp)
+		if (xfer->c_chp != chp) {
+			ata_channel_unlock(chp);
 			ata_reset_channel(xfer->c_chp, flags);
-		else {
+			ata_channel_lock(chp);
+		} else {
 #if NATA_DMA || NATA_PIOBM
 			/*
 			 * If we're waiting for DMA, stop the
@@ -974,6 +971,8 @@ wdc_reset_channel(struct ata_channel *ch
 	}
 
 	ata_kill_active(chp, KILL_RESET, flags);
+
+	ata_channel_unlock(chp);
 }
 
 static int
@@ -984,6 +983,8 @@ wdcreset(struct ata_channel *chp, int po
 	struct wdc_regs *wdr = &wdc->regs[chp->ch_channel];
 	int drv_mask1, drv_mask2;
 
+	ata_channel_lock_owned(chp);
+
 #ifdef WDC_NO_IDS
 	poll = RESET_POLL;
 #endif
@@ -1051,6 +1052,7 @@ __wdcwait_reset(struct ata_channel *chp,
 	struct wdc_softc *wdc = CHAN_TO_WDC(chp);
 	struct wdc_regs *wdr = &wdc->regs[chp->ch_channel];
 	int timeout, nloop;
+	int wflags = poll ? AT_POLL : AT_WAIT;
 	u_int8_t st0 = 0, st1 = 0;
 #ifdef ATADEBUG
 	u_int8_t sc0 = 0, sn0 = 0, cl0 = 0, ch0 = 0;
@@ -1123,10 +1125,7 @@ __wdcwait_reset(struct ata_channel *chp,
 				goto end;
 			}
 		}
-		if (poll)
-			delay(WDCDELAY);
-		else
-			tsleep(&nloop, PRIBIO, "atarst", 1);
+		ata_delay(chp, WDCDELAY, "atarst", wflags);
 	}
 	/* Reset timed out. Maybe it's because drv_mask was not right */
 	if (st0 & WDCS_BSY)
@@ -1219,7 +1218,7 @@ out:
 }
 
 /*
- * Call __wdcwait(), polling using tsleep() or waking up the kernel
+ * Call __wdcwait(), polling using kpause() or waking up the kernel
  * thread if possible
  */
 int
@@ -1376,9 +1375,12 @@ wdc_exec_command(struct ata_drive_datas 
 		ret = ATACMD_COMPLETE;
 	} else {
 		if (ata_c->flags & AT_WAIT) {
-			while ((ata_c->flags & AT_DONE) == 0) {
-				tsleep(ata_c, PRIBIO, "wdccmd", 0);
+			ata_channel_lock(chp);
+			if ((ata_c->flags & AT_DONE) == 0) {
+				ata_wait_xfer(chp, xfer);
+				KASSERT((ata_c->flags & AT_DONE) != 0);
 			}
+			ata_channel_unlock(chp);
 			ret = ATACMD_COMPLETE;
 		} else {
 			ret = ATACMD_QUEUED;
@@ -1490,7 +1492,7 @@ __wdccommand_intr(struct ata_channel *ch
 	wflags = AT_POLL;
 #else
 	if ((ata_c->flags & (AT_WAIT | AT_POLL)) == (AT_WAIT | AT_POLL)) {
-		/* both wait and poll, we can tsleep here */
+		/* both wait and poll, we can kpause here */
 		wflags = AT_WAIT | AT_POLL;
 	} else {
 		wflags = AT_POLL;
@@ -1676,10 +1678,11 @@ __wdccommand_done_end(struct ata_channel
 {
 	struct ata_command *ata_c = &xfer->c_ata_c;
 
+	ata_channel_lock(chp);
 	ata_c->flags |= AT_DONE;
 	if (ata_c->flags & AT_WAIT)
-		wakeup(ata_c);
-	return;
+		ata_wake_xfer(chp, xfer);
+	ata_channel_unlock(chp);
 }
 
 static void

Reply via email to