Module Name:    src
Committed By:   jdolecek
Date:           Sat Apr 15 12:01:24 UTC 2017

Modified Files:
        src/sys/dev/ata [jdolecek-ncq]: ata.c ata_wdc.c atavar.h satafis_subr.c
            wd.c wdvar.h
        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:
make ata_xfer's allocated as part of ata_queue and make it include ata_bio;
they are pre-allocated on attach and ata_get_xfer() now never sleep, drop the
pool

modify wd(4) to file the bio requests using the xfers and hence
make it possible to have more than one active I/O request in flight;
ata_bio callback doesn't need to allocate any memory any more,
require it to never return ATACMD_TRY_AGAIN

move lp, badsect, multi from ata_bio to ata_drive_datas, as they are per-drive,
not per transfer

drop unused drv atac_claim_hw/atac_free_hw hooks, and also drop again ata_bio
c_hwslot


To generate a diff of this commit:
cvs rdiff -u -r1.132.8.2 -r1.132.8.3 src/sys/dev/ata/ata.c
cvs rdiff -u -r1.105.6.1 -r1.105.6.2 src/sys/dev/ata/ata_wdc.c
cvs rdiff -u -r1.92.8.2 -r1.92.8.3 src/sys/dev/ata/atavar.h
cvs rdiff -u -r1.7 -r1.7.28.1 src/sys/dev/ata/satafis_subr.c
cvs rdiff -u -r1.428.2.2 -r1.428.2.3 src/sys/dev/ata/wd.c
cvs rdiff -u -r1.43.4.1 -r1.43.4.2 src/sys/dev/ata/wdvar.h
cvs rdiff -u -r1.57.6.2 -r1.57.6.3 src/sys/dev/ic/ahcisata_core.c
cvs rdiff -u -r1.35.6.3 -r1.35.6.4 src/sys/dev/ic/mvsata.c
cvs rdiff -u -r1.30.4.2 -r1.30.4.3 src/sys/dev/ic/siisata.c
cvs rdiff -u -r1.283.2.1 -r1.283.2.2 src/sys/dev/ic/wdc.c
cvs rdiff -u -r1.123.4.1 -r1.123.4.2 src/sys/dev/scsipi/atapi_wdc.c
cvs rdiff -u -r1.33 -r1.33.4.1 src/sys/dev/usb/umass_isdata.c

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

Modified files:

Index: src/sys/dev/ata/ata.c
diff -u src/sys/dev/ata/ata.c:1.132.8.2 src/sys/dev/ata/ata.c:1.132.8.3
--- src/sys/dev/ata/ata.c:1.132.8.2	Tue Apr 11 18:15:03 2017
+++ src/sys/dev/ata/ata.c	Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata.c,v 1.132.8.2 2017/04/11 18:15:03 jdolecek Exp $	*/
+/*	$NetBSD: ata.c,v 1.132.8.3 2017/04/15 12:01:23 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.2 2017/04/11 18:15:03 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.132.8.3 2017/04/15 12:01:23 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -37,7 +37,6 @@ __KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.13
 #include <sys/conf.h>
 #include <sys/fcntl.h>
 #include <sys/proc.h>
-#include <sys/pool.h>
 #include <sys/kthread.h>
 #include <sys/errno.h>
 #include <sys/ataio.h>
@@ -45,6 +44,7 @@ __KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.13
 #include <sys/intr.h>
 #include <sys/bus.h>
 #include <sys/once.h>
+#include <sys/bitops.h>
 
 #define ATABUS_PRIVATE
 
@@ -84,7 +84,6 @@ int atadebug_mask = ATADEBUG_MASK;
 #endif
 
 static ONCE_DECL(ata_init_ctrl);
-static struct pool ata_xfer_pool;
 
 /*
  * A queue of atabus instances, used to ensure the same bus probe order
@@ -139,8 +138,6 @@ static int
 atabus_init(void)
 {
 
-	pool_init(&ata_xfer_pool, sizeof(struct ata_xfer), 0, 0, 0,
-	    "ataspl", NULL, IPL_BIO);
 	TAILQ_INIT(&atabus_initq_head);
 	mutex_init(&atabus_qlock, MUTEX_DEFAULT, IPL_NONE);
 	cv_init(&atabus_qcv, "atainitq");
@@ -187,29 +184,18 @@ ata_queue_reset(struct ata_queue *chq)
 {
 	/* make sure that we can use polled commands */
 	TAILQ_INIT(&chq->queue_xfer);
+	TAILQ_INIT(&chq->active_xfers);
 	chq->queue_freeze = 0;
 	chq->queue_active = 0;
-	for (u_int i = 0; i < chq->queue_openings; i++) {
-		chq->active_xfers[0] = NULL;
-	}
 }
 
 struct ata_xfer *
 ata_queue_hwslot_to_xfer(struct ata_queue *chq, int hwslot)
 {
 	KASSERT(hwslot < chq->queue_openings);
-	if (chq->queue_openings == 1) {
-		struct ata_xfer *xfer = chq->active_xfers[0];
-		KASSERT(xfer == NULL || xfer->c_hwslot == hwslot);
-		return xfer;
-	}
-	for (u_int i = 0; i < chq->queue_openings; i++) {
-		struct ata_xfer *xfer = chq->active_xfers[i];
-		if (xfer != NULL && xfer->c_hwslot == hwslot) {
-			return xfer;
-		}
-	}
-	return NULL;
+	KASSERT((chq->queue_xfers_avail & __BIT(hwslot)) == 0);
+
+	return &chq->queue_xfers[hwslot];
 }
 
 struct ata_queue *
@@ -217,10 +203,11 @@ ata_queue_alloc(int openings)
 {
 	if (openings == 0)
 		openings = 1;
-	struct ata_queue *chq = malloc(offsetof(struct ata_queue, active_xfers[openings]),
+	struct ata_queue *chq = malloc(offsetof(struct ata_queue, queue_xfers[openings]),
 	    M_DEVBUF, M_WAITOK);
 	if (chq != NULL) {
 		chq->queue_openings = openings;
+		chq->queue_xfers_avail = (1 << openings) - 1;
 		ata_queue_reset(chq);
 	}
 	return chq;
@@ -520,11 +507,9 @@ atabus_thread(void *arg)
 			 */
 			chq->queue_freeze--;
 			u_int active __diagused = 0;
-			for (i = 0; i < chq->queue_openings; i++) {
-				if ((xfer = chq->active_xfers[i]) != NULL) {
-					(*xfer->c_start)(xfer->c_chp, xfer);
-					active++;
-				}
+			TAILQ_FOREACH(xfer, &chq->active_xfers, c_activechain) {
+				(*xfer->c_start)(xfer->c_chp, xfer);
+				active++;
 			}
 			KASSERT(active == chq->queue_active);
 		} else if (chq->queue_freeze > 1)
@@ -961,7 +946,6 @@ ata_exec_xfer(struct ata_channel *chp, s
 
 	/* complete xfer setup */
 	xfer->c_chp = chp;
-	xfer->c_slot = 0;
 
 	/* insert at the end of command list */
 	TAILQ_INSERT_TAIL(&chp->ch_queue->queue_xfer, xfer, c_xferchain);
@@ -1053,11 +1037,6 @@ atastart(struct ata_channel *chp)
 	if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0)
 		panic("atastart: channel waiting for irq");
 #endif
-	if (atac->atac_claim_hw) {
-		if (!(*atac->atac_claim_hw)(chp, 0))
-			return;
-	}
-
 	ATADEBUG_PRINT(("atastart: xfer %p channel %d drive %d\n", xfer,
 	    chp->ch_channel, xfer->c_drive), DEBUG_XFERS);
 	if (drvp->drive_flags & ATA_DRIVE_RESET) {
@@ -1065,18 +1044,6 @@ atastart(struct ata_channel *chp)
 		drvp->state = 0;
 	}
 
-	if (chq->queue_openings == 1) {
-		xfer->c_slot = 0;
-		xfer->c_hwslot = 0;
-	} else {
-		for (u_int slot = 0; slot < chq->queue_openings; slot++) {
-			if (chq->active_xfers[slot] == NULL) {
-				xfer->c_slot = slot;
-				xfer->c_hwslot = slot;
-				break;
-			}
-		}
-	}
 	ata_activate_xfer(chp, xfer);
 
 	if (atac->atac_cap & ATAC_CAP_NOIRQ)
@@ -1086,26 +1053,34 @@ atastart(struct ata_channel *chp)
 }
 
 struct ata_xfer *
-ata_get_xfer(int flags)
+ata_get_xfer(struct ata_channel *chp)
 {
-	struct ata_xfer *xfer;
+	struct ata_queue *chq = chp->ch_queue;
+	struct ata_xfer *xfer = NULL;
 	int s;
+	uint32_t avail, slot;
 
 	s = splbio();
-	xfer = pool_get(&ata_xfer_pool,
-	    ((flags & ATAXF_NOSLEEP) != 0 ? PR_NOWAIT : PR_WAITOK));
+	avail = ffs32(chq->queue_xfers_avail);
+	if (avail == 0)
+		goto out;
+
+	slot = avail - 1;
+	xfer = &chq->queue_xfers[slot];
+	chq->queue_xfers_avail &= ~__BIT(slot);
+
+	memset(xfer, 0, sizeof(struct ata_xfer));
+	xfer->c_slot = slot;
+
+out:
 	splx(s);
-	if (xfer != NULL) {
-		memset(xfer, 0, sizeof(struct ata_xfer));
-	}
-	xfer->c_slot = -1;
 	return xfer;
 }
 
 void
 ata_free_xfer(struct ata_channel *chp, struct ata_xfer *xfer)
 {
-	struct atac_softc *atac = chp->ch_atac;
+	struct ata_queue *chq = chp->ch_queue;
 	int s;
 
 	if (xfer->c_flags & C_WAITACT) {
@@ -1126,10 +1101,9 @@ ata_free_xfer(struct ata_channel *chp, s
 	}
 #endif
 
-	if (atac->atac_free_hw)
-		(*atac->atac_free_hw)(chp);
 	s = splbio();
-	pool_put(&ata_xfer_pool, xfer);
+	KASSERT((chq->queue_xfers_avail & __BIT(xfer->c_slot)) == 0);
+	chq->queue_xfers_avail |= __BIT(xfer->c_slot);
 	splx(s);
 }
 
@@ -1138,13 +1112,12 @@ ata_activate_xfer(struct ata_channel *ch
 {
 	struct ata_queue * const chq = chp->ch_queue;
 
-	KASSERT(xfer->c_slot >= 0);
 	KASSERT(chq->queue_active < chq->queue_openings);
-	KASSERT(chq->active_xfers[xfer->c_slot] == NULL);
+	KASSERT((chq->queue_xfers_avail & __BIT(xfer->c_slot)) == 0);
 
 	TAILQ_REMOVE(&chq->queue_xfer, xfer, c_xferchain);
+	TAILQ_INSERT_TAIL(&chq->active_xfers, xfer, c_activechain);
 
-	chq->active_xfers[xfer->c_slot] = xfer;
 	chq->queue_active++;
 }
 
@@ -1153,17 +1126,14 @@ ata_deactivate_xfer(struct ata_channel *
 {
 	struct ata_queue * const chq = chp->ch_queue;
 
-	KASSERT(xfer->c_slot >= 0);
 	KASSERT(chq->queue_active > 0);
-	KASSERT(chq->active_xfers[xfer->c_slot] == xfer);
+	KASSERT((chq->queue_xfers_avail & __BIT(xfer->c_slot)) == 0);
 
 	//if ((xfer->c_flags & C_TIMEOU) == 0)
 	callout_stop(&chp->ch_callout);
 
-	chq->active_xfers[xfer->c_slot] = NULL;
+	TAILQ_REMOVE(&chq->active_xfers, xfer, c_activechain);
 	chq->queue_active--;
-
-	xfer->c_slot = -1;
 }
 
 
@@ -1172,7 +1142,7 @@ ata_waitdrain_check(struct ata_channel *
 {
 	if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
 		chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(chp->ch_queue->active_xfers);
+		wakeup(&chp->ch_queue->active_xfers);
 		return true;
 	}
 	return false;
@@ -1185,7 +1155,7 @@ ata_waitdrain_xfer_check(struct ata_chan
 	if (chp->ch_drive[drive].drive_flags & ATA_DRIVE_WAITDRAIN) {
 		(*xfer->c_kill_xfer)(chp, xfer, KILL_GONE);
 		chp->ch_drive[drive].drive_flags &= ~ATA_DRIVE_WAITDRAIN;
-		wakeup(chp->ch_queue->active_xfers);
+		wakeup(&chp->ch_queue->active_xfers);
 		return true;
 	}
 	return false;
@@ -1200,12 +1170,10 @@ void
 ata_kill_active(struct ata_channel *chp, int reason)
 {
 	struct ata_queue * const chq = chp->ch_queue;
-	for (u_int i = 0;
-	     chq->queue_active > 0 && i < chq->queue_openings; i++) {
-		struct ata_xfer *xfer = chq->active_xfers[i];
-		if (xfer != NULL) {
-			(*xfer->c_kill_xfer)(xfer->c_chp, xfer, reason);
-		}
+	struct ata_xfer *xfer, *xfernext;
+
+	TAILQ_FOREACH_SAFE(xfer, &chq->active_xfers, c_activechain, xfernext) {
+		(*xfer->c_kill_xfer)(xfer->c_chp, xfer, reason);
 	}
 }
 
@@ -1233,12 +1201,13 @@ ata_kill_pending(struct ata_drive_datas 
 
 	while (chq->queue_active > 0) {
 		if (chq->queue_openings == 1 && chp->ch_ndrives > 1) {
-			xfer = chq->active_xfers[0];
+			xfer = TAILQ_FIRST(&chq->active_xfers);
+			KASSERT(xfer != NULL);
 			if (xfer->c_chp != chp || xfer->c_drive != drvp->drive)
 				break;
 		}
 		drvp->drive_flags |= ATA_DRIVE_WAITDRAIN;
-		(void) tsleep(&chq->active_xfers[0], PRIBIO, "atdrn", 0);
+		(void) tsleep(&chq->active_xfers, PRIBIO, "atdrn", 0);
 	}
 	splx(s);
 }

Index: src/sys/dev/ata/ata_wdc.c
diff -u src/sys/dev/ata/ata_wdc.c:1.105.6.1 src/sys/dev/ata/ata_wdc.c:1.105.6.2
--- src/sys/dev/ata/ata_wdc.c:1.105.6.1	Mon Apr 10 22:57:02 2017
+++ src/sys/dev/ata/ata_wdc.c	Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata_wdc.c,v 1.105.6.1 2017/04/10 22:57:02 jdolecek Exp $	*/
+/*	$NetBSD: ata_wdc.c,v 1.105.6.2 2017/04/15 12:01:23 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001, 2003 Manuel Bouyer.
@@ -54,7 +54,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.105.6.1 2017/04/10 22:57:02 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.105.6.2 2017/04/15 12:01:23 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wdc.h"
@@ -103,7 +103,7 @@ extern int wdcdebug_wd_mask; /* inited i
 
 #define ATA_DELAY 10000 /* 10s for a drive I/O */
 
-static int	wdc_ata_bio(struct ata_drive_datas*, struct ata_bio*);
+static int	wdc_ata_bio(struct ata_drive_datas*, struct ata_xfer *);
 static void	wdc_ata_bio_start(struct ata_channel *,struct ata_xfer *);
 static void	_wdc_ata_bio_start(struct ata_channel *,struct ata_xfer *);
 static int	wdc_ata_bio_intr(struct ata_channel *, struct ata_xfer *,
@@ -135,15 +135,12 @@ const struct ata_bustype wdc_ata_bustype
  * ATACMD_TRY_AGAIN. Must be called at splbio().
  */
 static int
-wdc_ata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
+wdc_ata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer)
 {
-	struct ata_xfer *xfer;
 	struct ata_channel *chp = drvp->chnl_softc;
 	struct atac_softc *atac = chp->ch_atac;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 
-	xfer = ata_get_xfer(ATAXF_NOSLEEP);
-	if (xfer == NULL)
-		return ATACMD_TRY_AGAIN;
 	if (atac->atac_cap & ATAC_CAP_NOIRQ)
 		ata_bio->flags |= ATA_POLL;
 	if (ata_bio->flags & ATA_POLL)
@@ -161,7 +158,6 @@ wdc_ata_bio(struct ata_drive_datas *drvp
 		xfer->c_flags |= C_PIOBM;
 #endif
 	xfer->c_drive = drvp->drive;
-	xfer->c_cmd = ata_bio;
 	xfer->c_databuf = ata_bio->databuf;
 	xfer->c_bcount = ata_bio->bcount;
 	xfer->c_start = wdc_ata_bio_start;
@@ -177,7 +173,7 @@ wdc_ata_bio_start(struct ata_channel *ch
 	struct atac_softc *atac = chp->ch_atac;
 	struct wdc_softc *wdc = CHAN_TO_WDC(chp);
 	struct wdc_regs *wdr = &wdc->regs[chp->ch_channel];
-	struct ata_bio *ata_bio = xfer->c_cmd;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 	struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
 	int wait_flags;
 	const char *errstring;
@@ -266,20 +262,20 @@ geometry:
 		if (ata_bio->flags & ATA_LBA)
 			goto multimode;
 		wdccommand(chp, xfer->c_drive, WDCC_IDP,
-		    ata_bio->lp->d_ncylinders,
-		    ata_bio->lp->d_ntracks - 1, 0, ata_bio->lp->d_nsectors,
-		    (ata_bio->lp->d_type == DKTYPE_ST506) ?
-			ata_bio->lp->d_precompcyl / 4 : 0);
+		    drvp->lp->d_ncylinders,
+		    drvp->lp->d_ntracks - 1, 0, drvp->lp->d_nsectors,
+		    (drvp->lp->d_type == DKTYPE_ST506) ?
+			drvp->lp->d_precompcyl / 4 : 0);
 		errstring = "geometry";
 		if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags))
 			goto ctrltimeout;
 		if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
 			goto ctrlerror;
 multimode:
-		if (ata_bio->multi == 1)
+		if (drvp->multi == 1)
 			goto ready;
 		wdccommand(chp, xfer->c_drive, WDCC_SETMULTI, 0, 0, 0,
-		    ata_bio->multi, 0);
+		    drvp->multi, 0);
 		errstring = "setmulti";
 		if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags))
 			goto ctrltimeout;
@@ -332,7 +328,7 @@ _wdc_ata_bio_start(struct ata_channel *c
 	struct atac_softc *atac = chp->ch_atac;
 	struct wdc_softc *wdc = CHAN_TO_WDC(chp);
 	struct wdc_regs *wdr = &wdc->regs[chp->ch_channel];
-	struct ata_bio *ata_bio = xfer->c_cmd;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 	struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
 	int wait_flags = (xfer->c_flags & C_POLL) ? AT_POLL : 0;
 	uint16_t cyl;
@@ -367,12 +363,12 @@ again:
 		if (ata_bio->flags & ATA_SINGLE)
 			nblks = 1;
 		else
-			nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
+			nblks = xfer->c_bcount / drvp->lp->d_secsize;
 		/* Check for bad sectors and adjust transfer, if necessary. */
-		if ((ata_bio->lp->d_flags & D_BADSECT) != 0) {
+		if ((drvp->lp->d_flags & D_BADSECT) != 0) {
 			long blkdiff;
 			int i;
-			for (i = 0; (blkdiff = ata_bio->badsect[i]) != -1;
+			for (i = 0; (blkdiff = drvp->badsect[i]) != -1;
 			    i++) {
 				blkdiff -= ata_bio->blkno;
 				if (blkdiff < 0)
@@ -380,8 +376,8 @@ again:
 				if (blkdiff == 0) {
 					/* Replace current block of transfer. */
 					ata_bio->blkno =
-					    ata_bio->lp->d_secperunit -
-					    ata_bio->lp->d_nsectors - i - 1;
+					    drvp->lp->d_secperunit -
+					    drvp->lp->d_nsectors - i - 1;
 				}
 				if (blkdiff < nblks) {
 					/* Bad block inside transfer. */
@@ -403,11 +399,11 @@ again:
 			head |= WDSD_LBA;
 		} else {
 			int blkno = ata_bio->blkno;
-			sect = blkno % ata_bio->lp->d_nsectors;
+			sect = blkno % drvp->lp->d_nsectors;
 			sect++;    /* Sectors begin with 1, not 0. */
-			blkno /= ata_bio->lp->d_nsectors;
-			head = blkno % ata_bio->lp->d_ntracks;
-			blkno /= ata_bio->lp->d_ntracks;
+			blkno /= drvp->lp->d_nsectors;
+			head = blkno % drvp->lp->d_ntracks;
+			blkno /= drvp->lp->d_ntracks;
 			cyl = blkno;
 			head |= WDSD_CHS;
 		}
@@ -502,8 +498,8 @@ again:
 			}
 		}
 #endif
-		ata_bio->nblks = min(nblks, ata_bio->multi);
-		ata_bio->nbytes = ata_bio->nblks * ata_bio->lp->d_secsize;
+		ata_bio->nblks = min(nblks, drvp->multi);
+		ata_bio->nbytes = ata_bio->nblks * drvp->lp->d_secsize;
 		KASSERT(nblks == 1 || (ata_bio->flags & ATA_SINGLE) == 0);
 		if (ata_bio->nblks > 1) {
 			cmd = (ata_bio->flags & ATA_READ) ?
@@ -531,8 +527,8 @@ again:
 		} else {
 		    wdccommand(chp, xfer->c_drive, cmd, cyl,
 			head, sect, nblks,
-			(ata_bio->lp->d_type == DKTYPE_ST506) ?
-			ata_bio->lp->d_precompcyl / 4 : 0);
+			(drvp->lp->d_type == DKTYPE_ST506) ?
+			drvp->lp->d_precompcyl / 4 : 0);
 		}
 		/* start timeout machinery */
 		if ((xfer->c_flags & C_POLL) == 0)
@@ -540,7 +536,7 @@ again:
 			    ATA_DELAY / 1000 * hz, wdctimeout, chp);
 	} else if (ata_bio->nblks > 1) {
 		/* The number of blocks in the last stretch may be smaller. */
-		nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
+		nblks = xfer->c_bcount / drvp->lp->d_secsize;
 		if (ata_bio->nblks > nblks) {
 		ata_bio->nblks = nblks;
 		ata_bio->nbytes = xfer->c_bcount;
@@ -615,7 +611,7 @@ wdc_ata_bio_intr(struct ata_channel *chp
 {
 	struct atac_softc *atac = chp->ch_atac;
 	struct wdc_softc *wdc = CHAN_TO_WDC(chp);
-	struct ata_bio *ata_bio = xfer->c_cmd;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 	struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
 	int drv_err;
 
@@ -768,11 +764,9 @@ static void
 wdc_ata_bio_kill_xfer(struct ata_channel *chp, struct ata_xfer *xfer,
     int reason)
 {
-	struct ata_bio *ata_bio = xfer->c_cmd;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 	int drive = xfer->c_drive;
 
-	ata_free_xfer(chp, xfer);
-
 	ata_bio->flags |= ATA_ITSDONE;
 	switch (reason) {
 	case KILL_GONE:
@@ -788,13 +782,13 @@ wdc_ata_bio_kill_xfer(struct ata_channel
 	}
 	ata_bio->r_error = WDCE_ABRT;
 	ATADEBUG_PRINT(("wdc_ata_bio_kill_xfer: drv_done\n"), DEBUG_XFERS);
-	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
 }
 
 static void
 wdc_ata_bio_done(struct ata_channel *chp, struct ata_xfer *xfer)
 {
-	struct ata_bio *ata_bio = xfer->c_cmd;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 	int drive = xfer->c_drive;
 
 	ATADEBUG_PRINT(("wdc_ata_bio_done %s:%d:%d: flags 0x%x\n",
@@ -809,14 +803,13 @@ wdc_ata_bio_done(struct ata_channel *chp
 
 	/* mark controller inactive and free xfer */
 	ata_deactivate_xfer(chp, xfer);
-	ata_free_xfer(chp, xfer);
 
 	if (ata_waitdrain_check(chp, drive)) {
 		ata_bio->error = ERR_NODEV;
 	}
 	ata_bio->flags |= ATA_ITSDONE;
 	ATADEBUG_PRINT(("wdc_ata_done: drv_done\n"), DEBUG_XFERS);
-	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
 	ATADEBUG_PRINT(("atastart from wdc_ata_done, flags 0x%x\n",
 	    chp->ch_flags), DEBUG_XFERS);
 	atastart(chp);

Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.92.8.2 src/sys/dev/ata/atavar.h:1.92.8.3
--- src/sys/dev/ata/atavar.h:1.92.8.2	Tue Apr 11 18:15:03 2017
+++ src/sys/dev/ata/atavar.h	Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: atavar.h,v 1.92.8.2 2017/04/11 18:15:03 jdolecek Exp $	*/
+/*	$NetBSD: atavar.h,v 1.92.8.3 2017/04/15 12:01:23 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -37,6 +37,38 @@
 #include <dev/scsipi/atapiconf.h>
 
 /*
+ * Parameters/state needed by the controller to perform an ATA bio.
+ */
+struct ata_bio {
+	volatile uint16_t flags;/* cmd flags */
+/* 			0x0001	free, was ATA_NOSLEEP */
+#define	ATA_POLL	0x0002	/* poll for completion */
+#define	ATA_ITSDONE	0x0004	/* the transfer is as done as it gets */
+#define	ATA_SINGLE	0x0008	/* transfer must be done in singlesector mode */
+#define	ATA_LBA		0x0010	/* transfer uses LBA addressing */
+#define	ATA_READ	0x0020	/* transfer is a read (otherwise a write) */
+#define	ATA_CORR	0x0040	/* transfer had a corrected error */
+#define	ATA_LBA48	0x0080	/* transfer uses 48-bit LBA addressing */
+	daddr_t		blkno;	/* block addr */
+	daddr_t		blkdone;/* number of blks transferred */
+	daddr_t		nblks;	/* number of block currently transferring */
+	int		nbytes;	/* number of bytes currently transferring */
+	long		bcount;	/* total number of bytes */
+	char		*databuf;/* data buffer address */
+	volatile int	error;
+#define	NOERROR 	0	/* There was no error (r_error invalid) */
+#define	ERROR		1	/* check r_error */
+#define	ERR_DF		2	/* Drive fault */
+#define	ERR_DMA		3	/* DMA error */
+#define	TIMEOUT		4	/* device timed out */
+#define	ERR_NODEV	5	/* device has been gone */
+#define ERR_RESET	6	/* command was terminated by channel reset */
+	uint8_t		r_error;/* copy of error register */
+	int		retries;/* number of xfer retry */
+	struct buf	*bp;
+};
+
+/*
  * Description of a command to be handled by an ATA controller.  These
  * commands are queued in a list.
  */
@@ -47,7 +79,6 @@ struct ata_xfer {
 	struct ata_channel *c_chp;
 	uint16_t c_drive;
 	int8_t c_slot;			/* queue slot # */
-	uint8_t c_hwslot;		/* hardware slot # */
 
 	void	*c_cmd;			/* private request structure pointer */
 	void	*c_databuf;		/* pointer to data buffer */
@@ -56,8 +87,15 @@ struct ata_xfer {
 	int	c_dscpoll;		/* counter for dsc polling (ATAPI) */
 	int	c_lenoff;		/* offset to c_bcount (ATAPI) */
 
+	union {
+		struct ata_bio	c_bio;	/* block I/O context */
+	} u;
+#define c_bio	u.c_bio
+
 	/* Link on the command queue. */
 	TAILQ_ENTRY(ata_xfer) c_xferchain;
+	TAILQ_ENTRY(ata_xfer) c_activechain;
+	STAILQ_ENTRY(ata_xfer) c_restartchain;
 
 	/* Low-level protocol handlers. */
 	void	(*c_start)(struct ata_channel *, struct ata_xfer *);
@@ -79,17 +117,18 @@ struct ata_xfer {
 #define KILL_GONE 1 /* device is gone */
 #define KILL_RESET 2 /* xfer was reset */
 
-/* Per-channel queue of ata_xfers.  May be shared by multiple channels. */
+/* 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 is wants the controller idle */
-#define QF_SHARED	0x02	/* this queue is shared */
+#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 */
 #ifdef ATABUS_PRIVATE
-	struct ata_xfer *active_xfers[1]; /* active command */
+	TAILQ_HEAD(, ata_xfer) active_xfers; 	/* active commands */
+	uint32_t queue_xfers_avail;		/* available xfers mask */
+	struct ata_xfer queue_xfers[0];		/* xfers */
 #endif
 };
 
@@ -176,10 +215,15 @@ struct ata_drive_datas {
 #endif
 
 	/* Callbacks into the drive's driver. */
-	void	(*drv_done)(void *);	/* transfer is done */
+	void	(*drv_done)(void *, struct ata_xfer *);	/* transfer is done */
 
-	device_t drv_softc;	/* ATA drives softc, if any */
+	device_t drv_softc;		/* ATA drives softc, if any */
 	void *chnl_softc;		/* channel softc */
+
+	/* Context used for I/O */
+	struct disklabel *lp;	/* pointer to drive's label info */
+	uint8_t		multi;	/* # of blocks to transfer in multi-mode */
+	daddr_t	badsect[127];	/* 126 plus trailing -1 marker */
 };
 
 /* User config flags that force (or disable) the use of a mode */
@@ -196,39 +240,6 @@ struct ata_drive_datas {
 #define ATA_CONFIG_UDMA_OFF	8
 
 /*
- * Parameters/state needed by the controller to perform an ATA bio.
- */
-struct ata_bio {
-	volatile uint16_t flags;/* cmd flags */
-/* 			0x0001	free, was ATA_NOSLEEP */
-#define	ATA_POLL	0x0002	/* poll for completion */
-#define	ATA_ITSDONE	0x0004	/* the transfer is as done as it gets */
-#define	ATA_SINGLE	0x0008	/* transfer must be done in singlesector mode */
-#define	ATA_LBA		0x0010	/* transfer uses LBA addressing */
-#define	ATA_READ	0x0020	/* transfer is a read (otherwise a write) */
-#define	ATA_CORR	0x0040	/* transfer had a corrected error */
-#define	ATA_LBA48	0x0080	/* transfer uses 48-bit LBA addressing */
-	int		multi;	/* # of blocks to transfer in multi-mode */
-	struct disklabel *lp;	/* pointer to drive's label info */
-	daddr_t		blkno;	/* block addr */
-	daddr_t		blkdone;/* number of blks transferred */
-	daddr_t		nblks;	/* number of block currently transferring */
-	int		nbytes;	/* number of bytes currently transferring */
-	long		bcount;	/* total number of bytes */
-	char		*databuf;/* data buffer address */
-	volatile int	error;
-#define	NOERROR 	0	/* There was no error (r_error invalid) */
-#define	ERROR		1	/* check r_error */
-#define	ERR_DF		2	/* Drive fault */
-#define	ERR_DMA		3	/* DMA error */
-#define	TIMEOUT		4	/* device timed out */
-#define	ERR_NODEV	5	/* device has been gone */
-#define ERR_RESET	6	/* command was terminated by channel reset */
-	uint8_t		r_error;/* copy of error register */
-	daddr_t		badsect[127];/* 126 plus trailing -1 marker */
-};
-
-/*
  * ATA/ATAPI commands description
  *
  * This structure defines the interface between the ATA/ATAPI device driver
@@ -289,7 +300,7 @@ struct ata_command {
  */
 struct ata_bustype {
 	int	bustype_type;	/* symbolic name of type */
-	int	(*ata_bio)(struct ata_drive_datas *, struct ata_bio *);
+	int	(*ata_bio)(struct ata_drive_datas *, struct ata_xfer *);
 	void	(*ata_reset_drive)(struct ata_drive_datas *, int, uint32_t *);
 	void	(*ata_reset_channel)(struct ata_channel *, int);
 /* extra flags for ata_reset_*(), in addition to AT_* */
@@ -422,10 +433,6 @@ struct atac_softc {
 	/* Driver callback to probe for drives. */
 	void (*atac_probe)(struct ata_channel *);
 
-	/* Optional callbacks to lock/unlock hardware. */
-	int  (*atac_claim_hw)(struct ata_channel *, int);
-	void (*atac_free_hw)(struct ata_channel *);
-
 	/*
 	 * Optional callbacks to set drive mode.  Required for anything
 	 * but basic PIO operation.
@@ -449,7 +456,7 @@ int	ata_set_mode(struct ata_drive_datas 
 #define CMD_ERR   1
 #define CMD_AGAIN 2
 
-struct ata_xfer *ata_get_xfer(int);
+struct ata_xfer *ata_get_xfer(struct ata_channel *);
 void	ata_free_xfer(struct ata_channel *, struct ata_xfer *);
 #define	ATAXF_CANSLEEP	0x00
 #define	ATAXF_NOSLEEP	0x01

Index: src/sys/dev/ata/satafis_subr.c
diff -u src/sys/dev/ata/satafis_subr.c:1.7 src/sys/dev/ata/satafis_subr.c:1.7.28.1
--- src/sys/dev/ata/satafis_subr.c:1.7	Sun Jul 22 17:57:57 2012
+++ src/sys/dev/ata/satafis_subr.c	Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: satafis_subr.c,v 1.7 2012/07/22 17:57:57 jakllsch Exp $ */
+/* $NetBSD: satafis_subr.c,v 1.7.28.1 2017/04/15 12:01:23 jdolecek Exp $ */
 
 /*-
  * Copyright (c) 2009 Jonathan A. Kollasch.
@@ -51,7 +51,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: satafis_subr.c,v 1.7 2012/07/22 17:57:57 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: satafis_subr.c,v 1.7.28.1 2017/04/15 12:01:23 jdolecek Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -100,10 +100,11 @@ satafis_rhd_construct_cmd(struct ata_com
 void
 satafis_rhd_construct_bio(struct ata_xfer *xfer, uint8_t *fis)
 {
-	struct ata_bio *ata_bio = xfer->c_cmd;
+	struct ata_bio *ata_bio = &xfer->c_bio;
+	struct ata_drive_datas *drvp = &xfer->c_chp->ch_drive[xfer->c_drive];
 	int nblks;
 
-	nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
+	nblks = xfer->c_bcount / drvp->lp->d_secsize;
 
 	memset(fis, 0, RHD_FISLEN);
 

Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.428.2.2 src/sys/dev/ata/wd.c:1.428.2.3
--- src/sys/dev/ata/wd.c:1.428.2.2	Wed Apr 12 22:28:20 2017
+++ src/sys/dev/ata/wd.c	Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: wd.c,v 1.428.2.2 2017/04/12 22:28:20 jdolecek Exp $ */
+/*	$NetBSD: wd.c,v 1.428.2.3 2017/04/15 12:01:23 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.2 2017/04/12 22:28:20 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.3 2017/04/15 12:01:23 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -90,7 +90,7 @@ __KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428
 
 #include <prop/proplib.h>
 
-#define	WDIORETRIES_SINGLE 4	/* number of retries before single-sector */
+#define	WDIORETRIES_SINGLE 4	/* number of retries for single-sector */
 #define	WDIORETRIES	5	/* number of retries before giving up */
 #define	RECOVERYTIME hz/2	/* time to wait before retrying a cmd */
 
@@ -119,7 +119,7 @@ int	wdprobe(device_t, cfdata_t, void *);
 void	wdattach(device_t, device_t, void *);
 int	wddetach(device_t, int);
 int	wdprint(void *, char *);
-void	wdperror(const struct wd_softc *);
+void	wdperror(const struct wd_softc *, struct ata_xfer *);
 
 static void	wdminphys(struct buf *);
 
@@ -186,12 +186,17 @@ void	wi_free(struct wd_ioctl *);
 struct	wd_ioctl *wi_get(struct wd_softc *);
 void	wdioctlstrategy(struct buf *);
 
+struct wd_split_mod15_private {
+	struct buf *bp;
+	struct ata_xfer *xfer;
+};
+
 void  wdgetdefaultlabel(struct wd_softc *, struct disklabel *);
 void  wdgetdisklabel(struct wd_softc *);
-void  wdstart(void *);
-void  wdstart1(struct wd_softc*, struct buf *);
+void  wdstart(struct wd_softc *);
+void  wdstart1(struct wd_softc *, struct buf *, struct ata_xfer *);
 void  wdrestart(void *);
-void  wddone(void *);
+void  wddone(void *, struct ata_xfer *);
 static void wd_params_to_properties(struct wd_softc *);
 int   wd_get_params(struct wd_softc *, uint8_t, struct ataparams *);
 int   wd_flushcache(struct wd_softc *, int);
@@ -295,14 +300,15 @@ wdattach(device_t parent, device_t self,
 
 	ATADEBUG_PRINT(("wdattach\n"), DEBUG_FUNCS | DEBUG_PROBE);
 	callout_init(&wd->sc_restart_ch, CALLOUT_MPSAFE);
+	callout_setfunc(&wd->sc_restart_ch, wdrestart, wd);
 	mutex_init(&wd->sc_lock, MUTEX_DEFAULT, IPL_BIO);
 	bufq_alloc(&wd->sc_q, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK);
 #ifdef WD_SOFTBADSECT
 	SLIST_INIT(&wd->sc_bslist);
 #endif
 	LIST_INIT(&wd->wi_head);
+	STAILQ_INIT(&wd->xfer_restart);
 	wd->atabus = adev->adev_bustype;
-	wd->openings = adev->adev_openings;
 	wd->drvp = adev->adev_drv_data;
 
 	wd->drvp->drv_done = wddone;
@@ -347,13 +353,13 @@ wdattach(device_t parent, device_t self,
 	}
 
 	if ((wd->sc_params.atap_multi & 0xff) > 1) {
-		wd->sc_multi = wd->sc_params.atap_multi & 0xff;
+		wd->drvp->multi = wd->sc_params.atap_multi & 0xff;
 	} else {
-		wd->sc_multi = 1;
+		wd->drvp->multi = 1;
 	}
 
 	aprint_verbose_dev(self, "drive supports %d-sector PIO transfers,",
-	    wd->sc_multi);
+	    wd->drvp->multi);
 
 	/* 48-bit LBA addressing */
 	if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0)
@@ -426,7 +432,7 @@ out:
 	/* we fill in dk_info later */
 	disk_init(&wd->sc_dk, device_xname(wd->sc_dev), &wddkdriver);
 	disk_attach(&wd->sc_dk);
-	wd->sc_wdc_bio.lp = wd->sc_dk.dk_label;
+	wd->drvp->lp = wd->sc_dk.dk_label;
 	wd_params_to_properties(wd);
 	rnd_attach_source(&wd->rnd_source, device_xname(wd->sc_dev),
 			  RND_TYPE_DISK, RND_FLAG_DEFAULT);
@@ -588,18 +594,20 @@ wdstrategy(struct buf *bp)
 	 * even attempting to start a transfer up under the premis that we
 	 * will just end up doing more retries for a transfer that will end
 	 * up failing again.
-	 * XXX:SMP - mutex required to protect with DIOCBSFLUSH
 	 */
 	if (__predict_false(!SLIST_EMPTY(&wd->sc_bslist))) {
 		struct disk_badsectors *dbs;
 		daddr_t maxblk = blkno + (bp->b_bcount / wd->sc_blksize) - 1;
 
+		mutex_enter(&wd->sc_lock);
 		SLIST_FOREACH(dbs, &wd->sc_bslist, dbs_next)
 			if ((dbs->dbs_min <= blkno && blkno <= dbs->dbs_max) ||
 			    (dbs->dbs_min <= maxblk && maxblk <= dbs->dbs_max)){
 				bp->b_error = EIO;
+				mutex_exit(&wd->sc_lock);
 				goto done;
 			}
+		mutex_exit(&wd->sc_lock);
 	}
 #endif
 
@@ -607,8 +615,9 @@ wdstrategy(struct buf *bp)
 	mutex_enter(&wd->sc_lock);
 	disk_wait(&wd->sc_dk);
 	bufq_put(wd->sc_q, bp);
-	wdstart(wd);
 	mutex_exit(&wd->sc_lock);
+
+	wdstart(wd);
 	return;
 done:
 	/* Toss transfer; we're done early. */
@@ -620,10 +629,10 @@ done:
  * Queue a drive for I/O.
  */
 void
-wdstart(void *arg)
+wdstart(struct wd_softc *wd)
 {
-	struct wd_softc *wd = arg;
-	struct buf *bp = NULL;
+	struct buf *bp;
+	struct ata_xfer *xfer;
 
 	ATADEBUG_PRINT(("wdstart %s\n", device_xname(wd->sc_dev)),
 	    DEBUG_XFERS);
@@ -631,29 +640,36 @@ wdstart(void *arg)
 	if (!device_is_active(wd->sc_dev))
 		return;
 
-	while (wd->openings > 0) {
+	mutex_enter(&wd->sc_lock);
 
-		/* Is there a buf for us ? */
-		if ((bp = bufq_get(wd->sc_q)) == NULL)
-			return;
+	while (bufq_peek(wd->sc_q) != NULL) {
+		/* First try to get command */
+		xfer = ata_get_xfer(wd->drvp->chnl_softc);
+		if (!xfer) 
+			break;
 
-		/*
-		 * Make the command. First lock the device
-		 */
-		wd->openings--;
+		/* There is got to be a buf for us */
+		bp = bufq_get(wd->sc_q);
+		KASSERT(bp != NULL);
 
-		wd->retries = 0;
-		wdstart1(wd, bp);
+		wdstart1(wd, bp, xfer);
 	}
+
+	mutex_exit(&wd->sc_lock);
 }
 
 static void
 wd_split_mod15_write(struct buf *bp)
 {
-	struct buf *obp = bp->b_private;
+	struct wd_split_mod15_private *m = bp->b_private;
+	struct buf *obp = m->bp;
+	struct ata_xfer *xfer = m->xfer;
 	struct wd_softc *wd =
 	    device_lookup_private(&wd_cd, DISKUNIT(obp->b_dev));
 
+	free(m, sizeof *m);
+
+	mutex_enter(&wd->sc_lock);
 	if (__predict_false(bp->b_error != 0)) {
 		/*
 		 * Propagate the error.  If this was the first half of
@@ -673,7 +689,7 @@ wd_split_mod15_write(struct buf *bp)
 
 	/*
 	 * Advance the pointer to the second half and issue that command
-	 * using the same opening.
+	 * using the same xfer.
 	 */
 	bp->b_flags = obp->b_flags;
 	bp->b_oflags = obp->b_oflags;
@@ -681,26 +697,25 @@ wd_split_mod15_write(struct buf *bp)
 	bp->b_data = (char *)bp->b_data + bp->b_bcount;
 	bp->b_blkno += (bp->b_bcount / DEV_BSIZE);
 	bp->b_rawblkno += (bp->b_bcount / wd->sc_blksize);
-	mutex_enter(&wd->sc_lock);
-	wdstart1(wd, bp);
+	memset(xfer, 0, sizeof(*xfer));
+	wdstart1(wd, bp, xfer);
 	mutex_exit(&wd->sc_lock);
 	return;
 
  done:
 	obp->b_error = bp->b_error;
 	obp->b_resid = bp->b_resid;
-	mutex_enter(&wd->sc_lock);
+	mutex_exit(&wd->sc_lock);
+
 	putiobuf(bp);
 	biodone(obp);
-	wd->openings++;
-	mutex_exit(&wd->sc_lock);
 	/* wddone() will call wdstart() */
 }
 
 void
-wdstart1(struct wd_softc *wd, struct buf *bp)
+wdstart1(struct wd_softc *wd, struct buf *bp, struct ata_xfer *xfer)
 {
-	/* already locked */
+	/* must be locked on entry */
 	KASSERT(mutex_owned(&wd->sc_lock));
 
 	/*
@@ -716,14 +731,21 @@ wdstart1(struct wd_softc *wd, struct buf
 			    bp->b_bcount > 512 &&
 			    ((bp->b_bcount / 512) % 15) == 1)) {
 		struct buf *nbp;
+		struct wd_split_mod15_private *m;
+
+		m = malloc(sizeof *m, M_TEMP, M_NOWAIT);
+		if (m == NULL)
+			goto fail;
 
 		nbp = getiobuf(NULL, false);
 		if (__predict_false(nbp == NULL)) {
+			free(m, sizeof *m);
+fail:
 			/* No memory -- fail the iop. */
 			bp->b_error = ENOMEM;
 			bp->b_resid = bp->b_bcount;
 			biodone(bp);
-			wd->openings++;
+			ata_free_xfer(wd->drvp->chnl_softc, xfer);
 			return;
 		}
 
@@ -744,43 +766,46 @@ wdstart1(struct wd_softc *wd, struct buf
 		nbp->b_iodone = wd_split_mod15_write;
 
 		/* Put ptr to orig buf in b_private and use new buf */
-		nbp->b_private = bp;
+		m->bp = bp;
+		m->xfer = xfer;
+		nbp->b_private = m;
 
 		BIO_COPYPRIO(nbp, bp);
 
 		bp = nbp;
 	}
 
-	wd->sc_wdc_bio.blkno = bp->b_rawblkno;
-	wd->sc_wdc_bio.bcount = bp->b_bcount;
-	wd->sc_wdc_bio.databuf = bp->b_data;
-	wd->sc_wdc_bio.blkdone =0;
-	KASSERT(bp == wd->sc_bp || wd->sc_bp == NULL);
-	wd->sc_bp = bp;
+	xfer->c_bio.blkno = bp->b_rawblkno;
+	xfer->c_bio.bcount = bp->b_bcount;
+	xfer->c_bio.databuf = bp->b_data;
+	xfer->c_bio.blkdone = 0;
+	KASSERT(bp == xfer->c_bio.bp || xfer->c_bio.bp == NULL);
+	xfer->c_bio.bp = bp;
 
 	/*
 	 * If we're retrying, retry in single-sector mode. This will give us
 	 * the sector number of the problem, and will eventually allow the
 	 * transfer to succeed.
 	 */
-	if (wd->retries >= WDIORETRIES_SINGLE)
-		wd->sc_wdc_bio.flags = ATA_SINGLE;
+	if (xfer->c_bio.retries >= WDIORETRIES_SINGLE)
+		xfer->c_bio.flags = ATA_SINGLE;
 	else
-		wd->sc_wdc_bio.flags = 0;
+		xfer->c_bio.flags = 0;
 	if (wd->sc_flags & WDF_LBA48 &&
-	    (wd->sc_wdc_bio.blkno +
-	     wd->sc_wdc_bio.bcount / wd->sc_dk.dk_label->d_secsize) >
+	    (xfer->c_bio.blkno +
+	     xfer->c_bio.bcount / wd->sc_dk.dk_label->d_secsize) >
 	    wd->sc_capacity28)
-		wd->sc_wdc_bio.flags |= ATA_LBA48;
+		xfer->c_bio.flags |= ATA_LBA48;
 	if (wd->sc_flags & WDF_LBA)
-		wd->sc_wdc_bio.flags |= ATA_LBA;
+		xfer->c_bio.flags |= ATA_LBA;
 	if (bp->b_flags & B_READ)
-		wd->sc_wdc_bio.flags |= ATA_READ;
+		xfer->c_bio.flags |= ATA_READ;
+
 	/* Instrumentation. */
 	disk_busy(&wd->sc_dk);
-	switch (wd->atabus->ata_bio(wd->drvp, &wd->sc_wdc_bio)) {
+	switch (wd->atabus->ata_bio(wd->drvp, xfer)) {
 	case ATACMD_TRY_AGAIN:
-		callout_reset(&wd->sc_restart_ch, hz, wdrestart, wd);
+		panic("wdstart1: try again");
 		break;
 	case ATACMD_QUEUED:
 	case ATACMD_COMPLETE:
@@ -791,22 +816,23 @@ wdstart1(struct wd_softc *wd, struct buf
 }
 
 void
-wddone(void *v)
+wddone(void *v, struct ata_xfer *xfer)
 {
 	struct wd_softc *wd = device_private(v);
-	struct buf *bp;
 	const char *errmsg;
-	int do_perror = 0;
+	int do_perror = 0, finish;
+	struct buf *bp;
 
 	ATADEBUG_PRINT(("wddone %s\n", device_xname(wd->sc_dev)),
 	    DEBUG_XFERS);
 
 	mutex_enter(&wd->sc_lock);
-	if ((bp = wd->sc_bp) == NULL)
-		goto out;
 
-	bp->b_resid = wd->sc_wdc_bio.bcount;
-	switch (wd->sc_wdc_bio.error) {
+	bp = xfer->c_bio.bp;
+	KASSERT(bp != NULL);
+
+	bp->b_resid = xfer->c_bio.bcount;
+	switch (xfer->c_bio.error) {
 	case ERR_DMA:
 		errmsg = "DMA error";
 		goto retry;
@@ -821,8 +847,8 @@ wddone(void *v)
 		goto retry2;
 	case ERROR:
 		/* Don't care about media change bits */
-		if (wd->sc_wdc_bio.r_error != 0 &&
-		    (wd->sc_wdc_bio.r_error & ~(WDCE_MC | WDCE_MCR)) == 0)
+		if (xfer->c_bio.r_error != 0 &&
+		    (xfer->c_bio.r_error & ~(WDCE_MC | WDCE_MCR)) == 0)
 			goto noerror;
 		errmsg = "error";
 		do_perror = 1;
@@ -830,17 +856,28 @@ retry:		/* Just reset and retry. Can we 
 		(*wd->atabus->ata_reset_drive)(wd->drvp, AT_RST_NOCMD, NULL);
 retry2:
 		diskerr(bp, "wd", errmsg, LOG_PRINTF,
-		    wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label);
-		if (wd->retries < WDIORETRIES)
+		    xfer->c_bio.blkdone, wd->sc_dk.dk_label);
+		if (xfer->c_bio.retries < WDIORETRIES)
 			printf(", retrying");
 		printf("\n");
 		if (do_perror)
-			wdperror(wd);
-		if (wd->retries < WDIORETRIES) {
-			wd->retries++;
-			callout_reset(&wd->sc_restart_ch, RECOVERYTIME,
-			    wdrestart, wd);
-			goto out;
+			wdperror(wd, xfer);
+		if (xfer->c_bio.retries < WDIORETRIES) {
+			xfer->c_bio.retries++;
+			STAILQ_INSERT_TAIL(&wd->xfer_restart, xfer,
+			    c_restartchain);
+
+			/*
+			 * Only restart the timer if it's not already pending,
+			 * so that we wouldn't postpone processing beyond
+			 * original schedule.
+			 */
+			if (!callout_pending(&wd->sc_restart_ch)) {
+				callout_schedule(&wd->sc_restart_ch,
+				    RECOVERYTIME);
+			}
+			mutex_exit(&wd->sc_lock);
+			return;
 		}
 
 #ifdef WD_SOFTBADSECT
@@ -851,8 +888,8 @@ retry2:
 		 * itself, according to Manuel.
 		 */
 		if ((bp->b_flags & B_READ) &&
-		    ((wd->drvp->ata_vers >= 4 && wd->sc_wdc_bio.r_error & 64) ||
-		     (wd->drvp->ata_vers < 4 && wd->sc_wdc_bio.r_error & 192))) {
+		    ((wd->drvp->ata_vers >= 4 && xfer->c_bio.r_error & 64) ||
+		     (wd->drvp->ata_vers < 4 && xfer->c_bio.r_error & 192))) {
 			struct disk_badsectors *dbs;
 
 			dbs = malloc(sizeof *dbs, M_TEMP, M_WAITOK);
@@ -867,7 +904,7 @@ retry2:
 		bp->b_error = EIO;
 		break;
 	case NOERROR:
-noerror:	if ((wd->sc_wdc_bio.flags & ATA_CORR) || wd->retries > 0)
+noerror:	if ((xfer->c_bio.flags & ATA_CORR) || xfer->c_bio.retries > 0)
 			aprint_error_dev(wd->sc_dev,
 			    "soft error (corrected)\n");
 		break;
@@ -886,31 +923,44 @@ noerror:	if ((wd->sc_wdc_bio.flags & ATA
 	disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid),
 	    (bp->b_flags & B_READ));
 	rnd_add_uint32(&wd->rnd_source, bp->b_blkno);
-	/* XXX Yuck, but we don't want to increment openings in this case */
-	if (__predict_false(bp->b_iodone == wd_split_mod15_write))
-		biodone(bp);
-	else {
-		biodone(bp);
-		wd->openings++;
-	}
-	KASSERT(wd->sc_bp != NULL);
-	wd->sc_bp = NULL;
-	wdstart(wd);
 
-out:
+	/*
+	 * XXX Yuck, but we don't want to free the xfer in this case.
+	 * See wd_split_mod15_write() for details.
+	 */
+	finish = (bp->b_iodone != wd_split_mod15_write);
+
 	mutex_exit(&wd->sc_lock);
+
+	biodone(bp);
+
+	if (__predict_true(finish)) {
+		ata_free_xfer(wd->drvp->chnl_softc, xfer);
+		wdstart(wd);
+	}
 }
 
 void
 wdrestart(void *v)
 {
 	struct wd_softc *wd = v;
-	struct buf *bp = wd->sc_bp;
+	struct ata_xfer *xfer;
 
 	ATADEBUG_PRINT(("wdrestart %s\n", device_xname(wd->sc_dev)),
 	    DEBUG_XFERS);
+
+	/*
+	 * Resend all failed xfers out immediatelly regardless of original
+	 * schedule, so that we error out reasonably fast in case of massive
+	 * permanent errors.
+	 */
 	mutex_enter(&wd->sc_lock);
-	wdstart1(v, bp);
+	while (!STAILQ_EMPTY(&wd->xfer_restart)) {
+		xfer = STAILQ_FIRST(&wd->xfer_restart);
+		STAILQ_REMOVE_HEAD(&wd->xfer_restart, c_restartchain);
+
+		wdstart1(v, xfer->c_bio.bp, xfer);
+	}
 	mutex_exit(&wd->sc_lock);
 }
 
@@ -1138,7 +1188,7 @@ wdgetdisklabel(struct wd_softc *wd)
 
 	wdgetdefaultlabel(wd, lp);
 
-	wd->sc_badsect[0] = -1;
+	wd->drvp->badsect[0] = -1;
 
 	if (wd->drvp->state > RESET) {
 		mutex_enter(&wd->sc_lock);
@@ -1180,7 +1230,7 @@ wdgetdisklabel(struct wd_softc *wd)
 }
 
 void
-wdperror(const struct wd_softc *wd)
+wdperror(const struct wd_softc *wd, struct ata_xfer *xfer)
 {
 	static const char *const errstr0_3[] = {"address mark not found",
 	    "track 0 not found", "aborted command", "media change requested",
@@ -1197,7 +1247,7 @@ wdperror(const struct wd_softc *wd)
 
 	const char *devname = device_xname(wd->sc_dev);
 	struct ata_drive_datas *drvp = wd->drvp;
-	int errno = wd->sc_wdc_bio.r_error;
+	int errno = xfer->c_bio.r_error;
 
 	if (drvp->ata_vers >= 4)
 		errstr = errstr4_5;
@@ -1630,6 +1680,7 @@ wddump(dev_t dev, daddr_t blkno, void *v
 	struct disklabel *lp;   /* disk's disklabel */
 	int part, err;
 	int nblks;	/* total number of sectors left to write */
+	struct ata_xfer *xfer;
 
 	/* Check if recursive dump; if so, punt. */
 	if (wddoingadump)
@@ -1664,18 +1715,21 @@ wddump(dev_t dev, daddr_t blkno, void *v
 		wd->drvp->state = RESET;
 	}
 
-	wd->sc_bp = NULL;
-	wd->sc_wdc_bio.blkno = blkno;
-	wd->sc_wdc_bio.flags = ATA_POLL;
+	xfer = ata_get_xfer(wd->drvp->chnl_softc);
+	if (xfer == NULL)
+		return EAGAIN;
+
+	xfer->c_bio.blkno = blkno;
+	xfer->c_bio.flags = ATA_POLL;
 	if (wd->sc_flags & WDF_LBA48 &&
-	    (wd->sc_wdc_bio.blkno + nblks) > wd->sc_capacity28)
-		wd->sc_wdc_bio.flags |= ATA_LBA48;
+	    (xfer->c_bio.blkno + nblks) > wd->sc_capacity28)
+		xfer->c_bio.flags |= ATA_LBA48;
 	if (wd->sc_flags & WDF_LBA)
-		wd->sc_wdc_bio.flags |= ATA_LBA;
-	wd->sc_wdc_bio.bcount = nblks * lp->d_secsize;
-	wd->sc_wdc_bio.databuf = va;
+		xfer->c_bio.flags |= ATA_LBA;
+	xfer->c_bio.bcount = nblks * lp->d_secsize;
+	xfer->c_bio.databuf = va;
 #ifndef WD_DUMP_NOT_TRUSTED
-	switch (err = wd->atabus->ata_bio(wd->drvp, &wd->sc_wdc_bio)) {
+	switch (err = wd->atabus->ata_bio(wd->drvp, xfer)) {
 	case ATACMD_TRY_AGAIN:
 		panic("wddump: try again");
 		break;
@@ -1687,7 +1741,7 @@ wddump(dev_t dev, daddr_t blkno, void *v
 	default:
 		panic("wddump: unknown atacmd code %d", err);
 	}
-	switch(err = wd->sc_wdc_bio.error) {
+	switch(err = xfer->c_bio.error) {
 	case TIMEOUT:
 		printf("wddump: device timed out");
 		err = EIO;
@@ -1702,7 +1756,7 @@ wddump(dev_t dev, daddr_t blkno, void *v
 		break;
 	case ERROR:
 		printf("wddump: ");
-		wdperror(wd);
+		wdperror(wd, xfer);
 		err = EIO;
 		break;
 	case NOERROR:
@@ -1711,6 +1765,9 @@ wddump(dev_t dev, daddr_t blkno, void *v
 	default:
 		panic("wddump: unknown error type %d", err);
 	}
+
+	ata_free_xfer(wd->drvp->chnl_softc, xfer);
+
 	if (err != 0) {
 		printf("\n");
 		return err;
@@ -1742,13 +1799,13 @@ bad144intern(struct wd_softc *wd)
 	for (; i < NBT_BAD; i++) {
 		if (bt->bt_bad[i].bt_cyl == 0xffff)
 			break;
-		wd->sc_badsect[i] =
+		wd->drvp->badsect[i] =
 		    bt->bt_bad[i].bt_cyl * lp->d_secpercyl +
 		    (bt->bt_bad[i].bt_trksec >> 8) * lp->d_nsectors +
 		    (bt->bt_bad[i].bt_trksec & 0xff);
 	}
 	for (; i < NBT_BAD+1; i++)
-		wd->sc_badsect[i] = -1;
+		wd->drvp->badsect[i] = -1;
 }
 #endif
 

Index: src/sys/dev/ata/wdvar.h
diff -u src/sys/dev/ata/wdvar.h:1.43.4.1 src/sys/dev/ata/wdvar.h:1.43.4.2
--- src/sys/dev/ata/wdvar.h:1.43.4.1	Wed Apr 12 21:59:14 2017
+++ src/sys/dev/ata/wdvar.h	Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdvar.h,v 1.43.4.1 2017/04/12 21:59:14 jdolecek Exp $	*/
+/*	$NetBSD: wdvar.h,v 1.43.4.2 2017/04/15 12:01:23 jdolecek Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -43,11 +43,8 @@ struct wd_softc {
 	int sc_quirks;			/* any quirks drive might have */
 
 	/* IDE disk soft states */
-	struct ata_bio sc_wdc_bio; /* current transfer */
-	struct buf *sc_bp; /* buf being transfered */
 	struct ata_drive_datas *drvp; /* Our controller's infos */
 	const struct ata_bustype *atabus;
-	int openings;
 	struct ataparams sc_params;/* drive characteristics found */
 	int sc_flags;
 #define	WDF_WLABEL	0x004 /* label is writable */
@@ -66,8 +63,6 @@ struct wd_softc {
 	uint32_t sc_capacity28; /* capacity accessible with LBA28 commands */
 	uint32_t sc_blksize; /* logical block size, in bytes */
 
-	int retries; /* number of xfer retry */
-
 #ifdef WD_SOFTBADSECT
 	SLIST_HEAD(, disk_badsectors)	sc_bslist;
 	u_int sc_bscount;
@@ -75,11 +70,8 @@ struct wd_softc {
 	krndsource_t	rnd_source;
 
 	LIST_HEAD(, wd_ioctl) wi_head;
-};
 
-#define sc_drive sc_wdc_bio.drive
-#define sc_mode sc_wdc_bio.mode
-#define sc_multi sc_wdc_bio.multi
-#define sc_badsect sc_wdc_bio.badsect
+	STAILQ_HEAD(, ata_xfer) xfer_restart;
+};
 
 #endif /* _DEV_ATA_WDVAR_H_ */

Index: src/sys/dev/ic/ahcisata_core.c
diff -u src/sys/dev/ic/ahcisata_core.c:1.57.6.2 src/sys/dev/ic/ahcisata_core.c:1.57.6.3
--- src/sys/dev/ic/ahcisata_core.c:1.57.6.2	Tue Apr 11 18:13:17 2017
+++ src/sys/dev/ic/ahcisata_core.c	Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ahcisata_core.c,v 1.57.6.2 2017/04/11 18:13:17 jdolecek Exp $	*/
+/*	$NetBSD: ahcisata_core.c,v 1.57.6.3 2017/04/15 12:01:23 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.2 2017/04/11 18:13:17 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ahcisata_core.c,v 1.57.6.3 2017/04/15 12:01:23 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/malloc.h>
@@ -57,7 +57,7 @@ int ahcidebug_mask = 0;
 static void ahci_probe_drive(struct ata_channel *);
 static void ahci_setup_channel(struct ata_channel *);
 
-static int  ahci_ata_bio(struct ata_drive_datas *, struct ata_bio *);
+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 void ahci_reset_drive(struct ata_drive_datas *, int, uint32_t *);
 static void ahci_reset_channel(struct ata_channel *, int);
@@ -930,8 +930,7 @@ ahci_exec_command(struct ata_drive_datas
 	AHCIDEBUG_PRINT(("ahci_exec_command port %d CI 0x%x\n",
 	    chp->ch_channel, AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))),
 	    DEBUG_XFERS);
-	xfer = ata_get_xfer(ata_c->flags & AT_WAIT ? ATAXF_CANSLEEP :
-	    ATAXF_NOSLEEP);
+	xfer = ata_get_xfer(chp);
 	if (xfer == NULL) {
 		return ATACMD_TRY_AGAIN;
 	}
@@ -1164,23 +1163,18 @@ ahci_cmd_done(struct ata_channel *chp, s
 }
 
 static int
-ahci_ata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
+ahci_ata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer)
 {
 	struct ata_channel *chp = drvp->chnl_softc;
-	struct ata_xfer *xfer;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 
 	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
 	AHCIDEBUG_PRINT(("ahci_ata_bio port %d CI 0x%x\n",
 	    chp->ch_channel, AHCI_READ(sc, AHCI_P_CI(chp->ch_channel))),
 	    DEBUG_XFERS);
-	xfer = ata_get_xfer(ATAXF_NOSLEEP);
-	if (xfer == NULL) {
-		return ATACMD_TRY_AGAIN;
-	}
 	if (ata_bio->flags & ATA_POLL)
 		xfer->c_flags |= C_POLL;
 	xfer->c_drive = drvp->drive;
-	xfer->c_cmd = ata_bio;
 	xfer->c_databuf = ata_bio->databuf;
 	xfer->c_bcount = ata_bio->bcount;
 	xfer->c_start = ahci_bio_start;
@@ -1195,7 +1189,7 @@ ahci_bio_start(struct ata_channel *chp, 
 {
 	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
 	struct ahci_channel *achp = (struct ahci_channel *)chp;
-	struct ata_bio *ata_bio = xfer->c_cmd;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 	int slot = 0 /* XXX slot */;
 	struct ahci_cmd_tbl *cmd_tbl;
 	struct ahci_cmd_header *cmd_h;
@@ -1275,13 +1269,12 @@ ahci_bio_kill_xfer(struct ata_channel *c
 {
 	int slot = 0;  /* XXX slot */
 	int drive = xfer->c_drive;
-	struct ata_bio *ata_bio = xfer->c_cmd;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 	struct ahci_channel *achp = (struct ahci_channel *)chp;
 	AHCIDEBUG_PRINT(("ahci_bio_kill_xfer channel %d\n", chp->ch_channel),
 	    DEBUG_FUNCS);
 
 	achp->ahcic_cmds_active &= ~(1 << slot);
-	ata_free_xfer(chp, xfer);
 	ata_bio->flags |= ATA_ITSDONE;
 	switch (reason) {
 	case KILL_GONE:
@@ -1295,14 +1288,14 @@ ahci_bio_kill_xfer(struct ata_channel *c
 		panic("ahci_bio_kill_xfer");
 	}
 	ata_bio->r_error = WDCE_ABRT;
-	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
 }
 
 static int
 ahci_bio_complete(struct ata_channel *chp, struct ata_xfer *xfer, int is)
 {
 	int slot = 0; /* XXX slot */
-	struct ata_bio *ata_bio = xfer->c_cmd;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 	int drive = xfer->c_drive;
 	struct ahci_channel *achp = (struct ahci_channel *)chp;
 	struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
@@ -1329,7 +1322,6 @@ ahci_bio_complete(struct ata_channel *ch
 	if (ata_waitdrain_xfer_check(chp, xfer)) {
 		return 0;
 	}
-	ata_free_xfer(chp, xfer);
 	ata_bio->flags |= ATA_ITSDONE;
 	if (chp->ch_status & WDCS_DWF) { 
 		ata_bio->error = ERR_DF;
@@ -1352,7 +1344,7 @@ ahci_bio_complete(struct ata_channel *ch
 	if ((ata_bio->flags & ATA_READ) || ata_bio->error == NOERROR)
 		ata_bio->bcount -= le32toh(achp->ahcic_cmdh[slot].cmdh_prdbc);
 	AHCIDEBUG_PRINT((" now %ld\n", ata_bio->bcount), DEBUG_XFERS);
-	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
 	atastart(chp);
 	return 0;
 }
@@ -1569,7 +1561,7 @@ ahci_atapi_scsipi_request(struct scsipi_
 			scsipi_done(sc_xfer);
 			return;
 		}
-		xfer = ata_get_xfer(ATAXF_NOSLEEP);
+		xfer = ata_get_xfer(atac->atac_channels[channel]);
 		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.3 src/sys/dev/ic/mvsata.c:1.35.6.4
--- src/sys/dev/ic/mvsata.c:1.35.6.3	Tue Apr 11 18:14:47 2017
+++ src/sys/dev/ic/mvsata.c	Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: mvsata.c,v 1.35.6.3 2017/04/11 18:14:47 jdolecek Exp $	*/
+/*	$NetBSD: mvsata.c,v 1.35.6.4 2017/04/15 12:01:23 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.3 2017/04/11 18:14:47 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mvsata.c,v 1.35.6.4 2017/04/15 12:01:23 jdolecek Exp $");
 
 #include "opt_mvsata.h"
 
@@ -108,7 +108,7 @@ int	mvsata_debug = 2;
 
 static void mvsata_probe_drive(struct ata_channel *);
 #ifndef MVSATA_WITHOUTDMA
-static int mvsata_bio(struct ata_drive_datas *, struct ata_bio *);
+static int mvsata_bio(struct ata_drive_datas *, struct ata_xfer *);
 static void mvsata_reset_drive(struct ata_drive_datas *, int, uint32_t *);
 static void mvsata_reset_channel(struct ata_channel *, int);
 static int mvsata_exec_command(struct ata_drive_datas *, struct ata_command *);
@@ -530,17 +530,16 @@ mvsata_probe_drive(struct ata_channel *c
 
 #ifndef MVSATA_WITHOUTDMA
 static int
-mvsata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
+mvsata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer)
 {
 	struct ata_channel *chp = drvp->chnl_softc;
 	struct atac_softc *atac = chp->ch_atac;
-	struct ata_xfer *xfer;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 
 	DPRINTFN(1, ("%s:%d: mvsata_bio: drive=%d, blkno=%" PRId64
 	    ", bcount=%ld\n", device_xname(atac->atac_dev), chp->ch_channel,
 	    drvp->drive, ata_bio->blkno, ata_bio->bcount));
 
-	xfer = ata_get_xfer(ATAXF_NOSLEEP);
 	if (xfer == NULL)
 		return ATACMD_TRY_AGAIN;
 	if (atac->atac_cap & ATAC_CAP_NOIRQ)
@@ -661,8 +660,7 @@ mvsata_exec_command(struct ata_drive_dat
 	    drvp->drive, ata_c->bcount, ata_c->r_lba, ata_c->r_count,
 	    ata_c->r_features, ata_c->r_device, ata_c->r_command));
 
-	xfer = ata_get_xfer(ata_c->flags & AT_WAIT ? ATAXF_CANSLEEP :
-	    ATAXF_NOSLEEP);
+	xfer = ata_get_xfer(chp);
 	if (xfer == NULL)
 		return ATACMD_TRY_AGAIN;
 	if (ata_c->flags & AT_POLL)
@@ -777,7 +775,7 @@ mvsata_atapi_scsipi_request(struct scsip
 			scsipi_done(sc_xfer);
 			return;
 		}
-		xfer = ata_get_xfer(ATAXF_NOSLEEP);
+		xfer = ata_get_xfer(atac->atac_channels[channel]);
 		if (xfer == NULL) {
 			sc_xfer->error = XS_RESOURCE_SHORTAGE;
 			scsipi_done(sc_xfer);
@@ -1084,13 +1082,13 @@ again:
 		if (ata_bio->flags & ATA_SINGLE)
 			nblks = 1;
 		else
-			nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
+			nblks = xfer->c_bcount / drvp->lp->d_secsize;
 		/* Check for bad sectors and adjust transfer, if necessary. */
-		if ((ata_bio->lp->d_flags & D_BADSECT) != 0) {
+		if ((drvp->lp->d_flags & D_BADSECT) != 0) {
 			long blkdiff;
 			int i;
 
-			for (i = 0; (blkdiff = ata_bio->badsect[i]) != -1;
+			for (i = 0; (blkdiff = drvp->badsect[i]) != -1;
 			    i++) {
 				blkdiff -= ata_bio->blkno;
 				if (blkdiff < 0)
@@ -1098,8 +1096,8 @@ again:
 				if (blkdiff == 0)
 					/* Replace current block of transfer. */
 					ata_bio->blkno =
-					    ata_bio->lp->d_secperunit -
-					    ata_bio->lp->d_nsectors - i - 1;
+					    drvp->lp->d_secperunit -
+					    drvp->lp->d_nsectors - i - 1;
 				if (blkdiff < nblks) {
 					/* Bad block inside transfer. */
 					ata_bio->flags |= ATA_SINGLE;
@@ -1164,16 +1162,16 @@ do_pio:
 			head |= WDSD_LBA;
 		} else {
 			int blkno = ata_bio->blkno;
-			sect = blkno % ata_bio->lp->d_nsectors;
+			sect = blkno % drvp->lp->d_nsectors;
 			sect++;	/* Sectors begin with 1, not 0. */
-			blkno /= ata_bio->lp->d_nsectors;
-			head = blkno % ata_bio->lp->d_ntracks;
-			blkno /= ata_bio->lp->d_ntracks;
+			blkno /= drvp->lp->d_nsectors;
+			head = blkno % drvp->lp->d_ntracks;
+			blkno /= drvp->lp->d_ntracks;
 			cyl = blkno;
 			head |= WDSD_CHS;
 		}
-		ata_bio->nblks = min(nblks, ata_bio->multi);
-		ata_bio->nbytes = ata_bio->nblks * ata_bio->lp->d_secsize;
+		ata_bio->nblks = min(nblks, drvp->multi);
+		ata_bio->nbytes = ata_bio->nblks * drvp->lp->d_secsize;
 		KASSERT(nblks == 1 || (ata_bio->flags & ATA_SINGLE) == 0);
 		if (ata_bio->nblks > 1)
 			cmd = (ata_bio->flags & ATA_READ) ?
@@ -1228,8 +1226,8 @@ do_pio:
 		else
 			wdccommand(chp, 0, cmd, cyl,
 			    head, sect, nblks,
-			    (ata_bio->lp->d_type == DKTYPE_ST506) ?
-			    ata_bio->lp->d_precompcyl / 4 : 0);
+			    (drvp->lp->d_type == DKTYPE_ST506) ?
+			    drvp->lp->d_precompcyl / 4 : 0);
 
 		/* start timeout machinery */
 		if ((xfer->c_flags & C_POLL) == 0)
@@ -1237,7 +1235,7 @@ do_pio:
 			    ATA_DELAY / 1000 * hz, wdctimeout, chp);
 	} else if (ata_bio->nblks > 1) {
 		/* The number of blocks in the last stretch may be smaller. */
-		nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
+		nblks = xfer->c_bcount / drvp->lp->d_secsize;
 		if (ata_bio->nblks > nblks) {
 			ata_bio->nblks = nblks;
 			ata_bio->nbytes = xfer->c_bcount;
@@ -1408,8 +1406,6 @@ mvsata_bio_kill_xfer(struct ata_channel 
 		mvsata_edma_enable(mvport);
 	}
 
-	ata_free_xfer(chp, xfer);
-
 	ata_bio->flags |= ATA_ITSDONE;
 	switch (reason) {
 	case KILL_GONE:
@@ -1424,7 +1420,7 @@ mvsata_bio_kill_xfer(struct ata_channel 
 		panic("mvsata_bio_kill_xfer");
 	}
 	ata_bio->r_error = WDCE_ABRT;
-	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
 }
 
 static void
@@ -1451,12 +1447,11 @@ mvsata_bio_done(struct ata_channel *chp,
 
 	/* mark controller inactive and free xfer */
 	ata_deactivate_xfer(chp, xfer);
-	ata_free_xfer(chp, xfer);
 
 	if (ata_waitdrain_check(chp, drive))
 		ata_bio->error = ERR_NODEV;
 	ata_bio->flags |= ATA_ITSDONE;
-	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
 	atastart(chp);
 }
 
@@ -1518,19 +1513,19 @@ mvsata_bio_ready(struct mvsata_port *mvp
 geometry:
 	if (ata_bio->flags & ATA_LBA)
 		goto multimode;
-	wdccommand(chp, 0, WDCC_IDP, ata_bio->lp->d_ncylinders,
-	    ata_bio->lp->d_ntracks - 1, 0, ata_bio->lp->d_nsectors,
-	    (ata_bio->lp->d_type == DKTYPE_ST506) ?
-	    ata_bio->lp->d_precompcyl / 4 : 0);
+	wdccommand(chp, 0, WDCC_IDP, drvp->lp->d_ncylinders,
+	    drvp->lp->d_ntracks - 1, 0, drvp->lp->d_nsectors,
+	    (drvp->lp->d_type == DKTYPE_ST506) ?
+	    drvp->lp->d_precompcyl / 4 : 0);
 	errstring = "geometry";
 	if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags))
 		goto ctrltimeout;
 	if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
 		goto ctrlerror;
 multimode:
-	if (ata_bio->multi == 1)
+	if (drvp->multi == 1)
 		goto ready;
-	wdccommand(chp, 0, WDCC_SETMULTI, 0, 0, 0, ata_bio->multi, 0);
+	wdccommand(chp, 0, WDCC_SETMULTI, 0, 0, 0, drvp->multi, 0);
 	errstring = "setmulti";
 	if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, flags))
 		goto ctrltimeout;

Index: src/sys/dev/ic/siisata.c
diff -u src/sys/dev/ic/siisata.c:1.30.4.2 src/sys/dev/ic/siisata.c:1.30.4.3
--- src/sys/dev/ic/siisata.c:1.30.4.2	Tue Apr 11 18:13:17 2017
+++ src/sys/dev/ic/siisata.c	Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: siisata.c,v 1.30.4.2 2017/04/11 18:13:17 jdolecek Exp $ */
+/* $NetBSD: siisata.c,v 1.30.4.3 2017/04/15 12:01:23 jdolecek Exp $ */
 
 /* from ahcisata_core.c */
 
@@ -79,7 +79,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.2 2017/04/11 18:13:17 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: siisata.c,v 1.30.4.3 2017/04/15 12:01:23 jdolecek Exp $");
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -138,7 +138,7 @@ static void siisata_intr_port(struct sii
 void siisata_probe_drive(struct ata_channel *);
 void siisata_setup_channel(struct ata_channel *);
 
-int siisata_ata_bio(struct ata_drive_datas *, struct ata_bio *);
+int siisata_ata_bio(struct ata_drive_datas *, struct ata_xfer *);
 void siisata_reset_drive(struct ata_drive_datas *, int, uint32_t *);
 void siisata_reset_channel(struct ata_channel *, int);
 int siisata_ata_addref(struct ata_drive_datas *);
@@ -773,8 +773,7 @@ siisata_exec_command(struct ata_drive_da
 	    SIISATANAME((struct siisata_softc *)chp->ch_atac), __func__),
 	    DEBUG_FUNCS);
 
-	xfer = ata_get_xfer(ata_c->flags & AT_WAIT ?
-	    ATAXF_CANSLEEP : ATAXF_NOSLEEP);
+	xfer = ata_get_xfer(chp);
 	if (xfer == NULL)
 		return ATACMD_TRY_AGAIN;
 	if (ata_c->flags & AT_POLL)
@@ -1006,16 +1005,15 @@ siisata_cmd_done(struct ata_channel *chp
 }
 
 int
-siisata_ata_bio(struct ata_drive_datas *drvp, struct ata_bio *ata_bio)
+siisata_ata_bio(struct ata_drive_datas *drvp, struct ata_xfer *xfer)
 {
 	struct ata_channel *chp = drvp->chnl_softc;
-	struct ata_xfer *xfer;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 
 	SIISATA_DEBUG_PRINT( ("%s: %s.\n",
 	    SIISATANAME((struct siisata_softc *)chp->ch_atac),
 	    __func__), DEBUG_FUNCS);
 
-	xfer = ata_get_xfer(ATAXF_NOSLEEP);
 	if (xfer == NULL)
 		return ATACMD_TRY_AGAIN;
 	if (ata_bio->flags & ATA_POLL)
@@ -1113,7 +1111,6 @@ siisata_bio_kill_xfer(struct ata_channel
 
 	siisata_deactivate_prb(schp, slot);
 
-	ata_free_xfer(chp, xfer);
 	ata_bio->flags |= ATA_ITSDONE;
 	switch (reason) {
 	case KILL_GONE:
@@ -1127,7 +1124,7 @@ siisata_bio_kill_xfer(struct ata_channel
 		   __func__, chp->ch_channel, reason);
 	}
 	ata_bio->r_error = WDCE_ABRT;
-	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
 }
 
 int
@@ -1159,8 +1156,6 @@ siisata_bio_complete(struct ata_channel 
 		return 0;
 	}
 
-	ata_free_xfer(chp, xfer);
-
 	ata_bio->flags |= ATA_ITSDONE;
 	if (chp->ch_status & WDCS_DWF) {
 		ata_bio->error = ERR_DF;
@@ -1182,7 +1177,7 @@ siisata_bio_complete(struct ata_channel 
 	SIISATA_DEBUG_PRINT((" now %ld\n", ata_bio->bcount), DEBUG_XFERS); 
 	if (ata_bio->flags & ATA_POLL)
 		return 1;
-	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
+	(*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc, xfer);
 	atastart(chp);
 	return 0;
 }
@@ -1535,7 +1530,7 @@ siisata_atapi_scsipi_request(struct scsi
 			scsipi_done(sc_xfer);
 			return;
 		}
-		xfer = ata_get_xfer(ATAXF_NOSLEEP);
+		xfer = ata_get_xfer(atac->atac_channels[channel]);
 		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.1 src/sys/dev/ic/wdc.c:1.283.2.2
--- src/sys/dev/ic/wdc.c:1.283.2.1	Mon Apr 10 22:57:02 2017
+++ src/sys/dev/ic/wdc.c	Sat Apr 15 12:01:23 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: wdc.c,v 1.283.2.1 2017/04/10 22:57:02 jdolecek Exp $ */
+/*	$NetBSD: wdc.c,v 1.283.2.2 2017/04/15 12:01:23 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.1 2017/04/10 22:57:02 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.283.2.2 2017/04/15 12:01:23 jdolecek Exp $");
 
 #include "opt_ata.h"
 #include "opt_wdc.h"
@@ -1377,8 +1377,7 @@ wdc_exec_command(struct ata_drive_datas 
 	    drvp->drive), DEBUG_FUNCS);
 
 	/* set up an xfer and queue. Wait for completion */
-	xfer = ata_get_xfer(ata_c->flags & AT_WAIT ? ATAXF_CANSLEEP :
-	    ATAXF_NOSLEEP);
+	xfer = ata_get_xfer(chp);
 	if (xfer == NULL) {
 		return ATACMD_TRY_AGAIN;
 	 }

Index: src/sys/dev/scsipi/atapi_wdc.c
diff -u src/sys/dev/scsipi/atapi_wdc.c:1.123.4.1 src/sys/dev/scsipi/atapi_wdc.c:1.123.4.2
--- src/sys/dev/scsipi/atapi_wdc.c:1.123.4.1	Mon Apr 10 22:57:03 2017
+++ src/sys/dev/scsipi/atapi_wdc.c	Sat Apr 15 12:01:24 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: atapi_wdc.c,v 1.123.4.1 2017/04/10 22:57:03 jdolecek Exp $	*/
+/*	$NetBSD: atapi_wdc.c,v 1.123.4.2 2017/04/15 12:01:24 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.1 2017/04/10 22:57:03 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.123.4.2 2017/04/15 12:01:24 jdolecek Exp $");
 
 #ifndef ATADEBUG
 #define ATADEBUG
@@ -362,7 +362,7 @@ wdc_atapi_scsipi_request(struct scsipi_c
 			return;
 		}
 
-		xfer = ata_get_xfer(ATAXF_NOSLEEP);
+		xfer = ata_get_xfer(atac->atac_channels[channel]);
 		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 src/sys/dev/usb/umass_isdata.c:1.33.4.1
--- src/sys/dev/usb/umass_isdata.c:1.33	Fri Nov 25 12:56:29 2016
+++ src/sys/dev/usb/umass_isdata.c	Sat Apr 15 12:01:24 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: umass_isdata.c,v 1.33 2016/11/25 12:56:29 skrll Exp $	*/
+/*	$NetBSD: umass_isdata.c,v 1.33.4.1 2017/04/15 12:01:24 jdolecek Exp $	*/
 
 /*
  * TODO:
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.33 2016/11/25 12:56:29 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: umass_isdata.c,v 1.33.4.1 2017/04/15 12:01:24 jdolecek Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -93,7 +93,7 @@ struct uisdata_softc {
 
 	struct ata_drive_datas	sc_drv_data;
 	struct isd200_config	sc_isd_config;
-	void			*sc_ata_bio;
+	struct ata_xfer		*sc_ata_xfer;
 	u_long			sc_skip;
 };
 
@@ -108,8 +108,8 @@ int	uisdatadebug = 0;
 #define DPRINTFN(n,x)
 #endif
 
-int  uisdata_bio(struct ata_drive_datas *, struct ata_bio *);
-int  uisdata_bio1(struct ata_drive_datas *, struct ata_bio *);
+int  uisdata_bio(struct ata_drive_datas *, struct ata_xfer *);
+int  uisdata_bio1(struct ata_drive_datas *, struct ata_xfer *);
 void uisdata_reset_drive(struct ata_drive_datas *, int, uint32_t *);
 void uisdata_reset_channel(struct ata_channel *, int);
 int  uisdata_exec_command(struct ata_drive_datas *, struct ata_command *);
@@ -220,6 +220,7 @@ umass_isdata_attach(struct umass_softc *
 	adev.adev_drv_data = &scbus->sc_drv_data;
 	scbus->sc_drv_data.drive_type = ATA_DRIVET_ATA;
 	scbus->sc_drv_data.chnl_softc = sc;
+#error chnl_softc is used by ata_get_xfer() as ata_channel
 	scbus->base.sc_child = config_found(sc->sc_dev, &adev, uwdprint);
 
 	return 0;
@@ -230,13 +231,14 @@ void
 uisdata_bio_cb(struct umass_softc *sc, void *priv, int residue, int status)
 {
 	struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
-	struct ata_bio *ata_bio = priv;
+	struct ata_xfer *xfer = priv;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 	int s;
 
 	DPRINTF(("%s: residue=%d status=%d\n", __func__, residue, status));
 
 	s = splbio();
-	scbus->sc_ata_bio = NULL;
+	scbus->sc_ata_xfer = NULL;
 	if (status != STATUS_CMD_OK)
 		ata_bio->error = ERR_DF; /* ??? */
 	else
@@ -251,7 +253,7 @@ uisdata_bio_cb(struct umass_softc *sc, v
 		ata_bio->bcount += residue;
 	} else if (ata_bio->bcount > 0) {
 		DPRINTF(("%s: continue\n", __func__));
-		(void)uisdata_bio1(&scbus->sc_drv_data, ata_bio); /*XXX save drv*/
+		(void)uisdata_bio1(&scbus->sc_drv_data, xfer); /*XXX save drv*/
 		splx(s);
 		return;
 	}
@@ -260,27 +262,29 @@ uisdata_bio_cb(struct umass_softc *sc, v
 		DPRINTF(("%s: wakeup %p\n", __func__, ata_bio));
 		wakeup(ata_bio);
 	} else {
-		(*scbus->sc_drv_data.drv_done)(scbus->sc_drv_data.drv_softc);
+		(*scbus->sc_drv_data.drv_done)(scbus->sc_drv_data.drv_softc,
+		    xfer);
 	}
 	splx(s);
 }
 
 int
-uisdata_bio(struct ata_drive_datas *drv, struct ata_bio *ata_bio)
+uisdata_bio(struct ata_drive_datas *drv, struct ata_xfer *xfer)
 {
 	struct umass_softc *sc = drv->chnl_softc;
 	struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
 
 	scbus->sc_skip = 0;
-	return uisdata_bio1(drv, ata_bio);
+	return uisdata_bio1(drv, xfer);
 }
 
 int
-uisdata_bio1(struct ata_drive_datas *drv, struct ata_bio *ata_bio)
+uisdata_bio1(struct ata_drive_datas *drv, struct ata_xfer *xfer)
 {
 	struct umass_softc *sc = drv->chnl_softc;
 	struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
 	struct isd200_config *cf = &scbus->sc_isd_config;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 	struct ata_cmd ata;
 	uint16_t cyl;
 	uint8_t head, sect;
@@ -298,11 +302,11 @@ uisdata_bio1(struct ata_drive_datas *drv
 		return ATACMD_COMPLETE;
 	}
 
-	if (scbus->sc_ata_bio != NULL) {
+	if (scbus->sc_ata_xfer != NULL) {
 		printf("%s: multiple uisdata_bio\n", __func__);
 		return ATACMD_TRY_AGAIN;
 	} else
-		scbus->sc_ata_bio = ata_bio;
+		scbus->sc_ata_xfer = xfer;
 
 	if (ata_bio->flags & ATA_LBA) {
 		sect = (ata_bio->blkno >> 0) & 0xff;
@@ -311,11 +315,11 @@ uisdata_bio1(struct ata_drive_datas *drv
 		head |= WDSD_LBA;
 	} else {
 		int blkno = ata_bio->blkno;
-		sect = blkno % ata_bio->lp->d_nsectors;
+		sect = blkno % drv->lp->d_nsectors;
 		sect++;    /* Sectors begin with 1, not 0. */
-		blkno /= ata_bio->lp->d_nsectors;
-		head = blkno % ata_bio->lp->d_ntracks;
-		blkno /= ata_bio->lp->d_ntracks;
+		blkno /= drv->lp->d_nsectors;
+		head = blkno % drv->lp->d_ntracks;
+		blkno /= drv->lp->d_ntracks;
 		cyl = blkno;
 		head |= WDSD_CHS;
 	}
@@ -324,8 +328,8 @@ uisdata_bio1(struct ata_drive_datas *drv
 	if (ata_bio->flags & ATA_SINGLE)
 		nblks = 1;
 	else
-		nblks = min(ata_bio->multi, nbytes / ata_bio->lp->d_secsize);
-	nbytes = nblks * ata_bio->lp->d_secsize;
+		nblks = min(drv->multi, nbytes / drv->lp->d_secsize);
+	nbytes = nblks * drv->lp->d_secsize;
 	ata_bio->nblks = nblks;
 	ata_bio->nbytes = nbytes;
 
@@ -364,7 +368,7 @@ uisdata_bio1(struct ata_drive_datas *drv
 		 ata_bio->bcount, drv->drive));
 	sc->sc_methods->wire_xfer(sc, drv->drive, &ata, sizeof(ata),
 				  ata_bio->databuf + scbus->sc_skip, nbytes,
-				  dir, ATA_DELAY, 0, uisdata_bio_cb, ata_bio);
+				  dir, ATA_DELAY, 0, uisdata_bio_cb, xfer);
 
 	while (ata_bio->flags & ATA_POLL) {
 		DPRINTF(("%s: tsleep %p\n", __func__, ata_bio));
@@ -496,17 +500,19 @@ uisdata_kill_pending(struct ata_drive_da
 {
 	struct umass_softc *sc = drv->chnl_softc;
 	struct uisdata_softc *scbus = (struct uisdata_softc *)sc->bus;
-	struct ata_bio *ata_bio = scbus->sc_ata_bio;
+	struct ata_xfer *xfer = scbus->sc_ata_xfer;
+	struct ata_bio *ata_bio = &xfer->c_bio;
 
 	DPRINTFN(-1,("%s\n", __func__));
 
-	if (ata_bio == NULL)
+	if (xfer == NULL)
 		return;
-	scbus->sc_ata_bio = NULL;
+
+	scbus->sc_ata_xfer = NULL;
 	ata_bio->flags |= ATA_ITSDONE;
 	ata_bio->error = ERR_NODEV;
 	ata_bio->r_error = WDCE_ABRT;
-	(*scbus->sc_drv_data.drv_done)(scbus->sc_drv_data.drv_softc);
+	(*scbus->sc_drv_data.drv_done)(scbus->sc_drv_data.drv_softc, xfer);
 }
 
 int

Reply via email to