Subject: kernel thread for IDE
To: None <tech-kern@netbsd.org>
From: Manuel Bouyer <bouyer@antioche.eu.org>
List: tech-kern
Date: 09/19/2003 23:39:11
--d6Gm4EdcadzBjdND
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi,
here are some changes I've been working on for some time. It's been tested
on i386, macppc and sparc64 for some time now.
Unfortunably I don't have any pcmcia IDE adapter to test attach/detach.

Basically I added a per-channel kernel thread for IDE, to handle most
operations the kernel has to do using polling. The most time-consuming one
is channel reset, but it can also handle the wdcwait() before sending a
command. The kernel thread also handle probing the bus at attach time.
This allows polling for the reset to complete in parrallel, which reduce
boot time significantly on boxes with multiple controllers.
I also added a atabus device which'll be used to perform channel-specific
operation reset, and hot-plug related operations (tri-state, scan).
I did it at the same time because it allows the changes related to
deffering the bus probe to be located only in MI wdc, leaving the bus
front-end mostly untouched.

More in details:
when a atabus is attached, it resets the bus and schedules creation of its
kernel thread.
The kernel thread, when created, will then poll for the reset to complete,
and probe devices. This is done in kernel thread context so we can use
interrupts and tsleep(). Once probe is done, it will loop on tsleep, waiting
for some work to do.
When the kernel thread runs, it asserts the WDCF_TH_RUN flag. This is used
in others wdc parts to know if it's safe to sleep or not. If WDCF_TH_RUN
isn't set we can then wake up the thread and return, letting the thread
handle the problem.
Once awakened the kernel thread will check, in order:
WDCF_SHUTDOWN: the thread will then exit
WDCF_TH_RESET: the thread will reset the channel (using tlseep() to poll
               for reset to complete), and will then call wdcstart()
Else, if the channel is active and the queue was froozen, unfreeze it and
restart the current xfer.

wdcwait can now return 3 different status:
WDCWAIT_OK: the device is in the state we expect
WDCWAIT_TOUT: the device timed out
WDCWAIT_THR: only if wdcwait() was not called with AT_POLL: the device
             isn't ready and we need the kernel thread to poll. Just 
	     return, the kernel thread has been waked up.

the wdcwait() users have to either call it with AT_POLL (it's a polled command,
or we're in interrupt context and we can't use the kernel thread here),
or check for the WDCWAIT_THR return value and just return. In the second case
this has to happen at the beggining of the *_start() functions.

I converted the ata and atapi control functions (setting PIO and DMA modes,
etc ...) from interrupt-driven to polled. It's much simpler, and using
interrupts here isn't critical since basically this is only called after a
channel reset.

I had to change some bits in pciide.c, because it currently assumes all devices
have been probed and attached when wdcattach() returns. 

This doens't require much MD changes (I still need to adjust the macppc machdep
so that it finds its root device again), but requires all the kenrel config
files to be changed.

Comments ?

-- 
Manuel Bouyer <bouyer@antioche.eu.org>
     NetBSD: 24 ans d'experience feront toujours la difference
--

--d6Gm4EdcadzBjdND
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="ide.diff"

Index: arch/i386/conf/GENERIC
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/conf/GENERIC,v
retrieving revision 1.570
diff -u -r1.570 GENERIC
--- arch/i386/conf/GENERIC	2003/09/06 22:39:23	1.570
+++ arch/i386/conf/GENERIC	2003/09/19 20:26:41
@@ -625,8 +625,10 @@
 # 0x0fac means 'use PIO mode 4, DMA mode 2, disable UltraDMA'.
 # (0xc=1100, 0xa=1010, 0xf=1111)
 # 0x0000 means "use whatever the drive claims to support".
-wd*	at wdc? channel ? drive ? flags 0x0000
-wd*	at pciide? channel ? drive ? flags 0x0000
+
+atabus* at pciide? channel ?
+atabus* at wdc? channel ?
+wd*	at atabus? drive ? flags 0x0000
 
 # ATA RAID configuration support, as found on some Promise controllers.
 pseudo-device	ataraid
Index: arch/macppc/conf/GENERIC
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/conf/GENERIC,v
retrieving revision 1.160
diff -u -r1.160 GENERIC
--- arch/macppc/conf/GENERIC	2003/08/22 07:52:50	1.160
+++ arch/macppc/conf/GENERIC	2003/09/19 20:26:42
@@ -327,11 +327,11 @@
 uk*	at scsibus? target ? lun ?	# SCSI unknown
 
 wdc*	at obio? flags 0x1
-wd*	at pciide? channel ? drive ?
-wd*	at wdc? channel ? drive ? flags 0x0000
+atabus* at pciide? channel ?
+atabus* at wdc? channel ? 
+wd*	at atabus? drive ? flags 0x0000
 
-atapibus* at pciide? channel ?
-atapibus* at wdc? channel ?
+atapibus* at atabus?
 
 cd*	at atapibus? drive ? flags 0x0000	# ATAPI CD-ROM drives
 sd*	at atapibus? drive ? flags 0x0000	# ATAPI disk drives
@@ -360,7 +360,7 @@
 ucom*	at umodem?
 
 umass*	at uhub? port ? configuration ? interface ?	# USB Mass Storage
-atapibus* at umass? channel ?
+atapibus* at umass?
 scsibus* at umass? channel ?
 
 uaudio*	at uhub? port ? configuration ?			# USB audio
Index: arch/sparc64/conf/GENERIC32
===================================================================
RCS file: /cvsroot/src/sys/arch/sparc64/conf/GENERIC32,v
retrieving revision 1.70
diff -u -r1.70 GENERIC32
--- arch/sparc64/conf/GENERIC32	2003/08/07 17:17:58	1.70
+++ arch/sparc64/conf/GENERIC32	2003/09/19 20:26:47
@@ -315,9 +315,9 @@
 # how to set up DMA modes for this chip. This may work, or may cause
 # a machine hang with some controllers.
 pciide* at pci? dev ? function ? flags 0x0000
+atabus* at pciide? channel ?
+atapibus* at atabus?
 
-atapibus* at atapi?
-
 # IDE drives
 # Flags are used only with controllers that support DMA operations
 # and mode settings (e.g. some pciide controllers)
@@ -332,7 +332,7 @@
 
 ## Disable UDMA 4 which causes data corruption on the Acer Labs
 ## chipset on Sun Blade 100 and Netra X1 machines.
-wd*	at pciide? channel ? drive ? flags 0x0a00 # Disable UDMA 4
+wd*     at atabus? drive ? flags 0x0000
 
 cd*	at atapibus? drive ? flags 0x0000	# ATAPI CD-ROM drives
 sd*	at atapibus? drive ? flags 0x0000	# ATAPI disk drives
Index: conf/files
===================================================================
RCS file: /cvsroot/src/sys/conf/files,v
retrieving revision 1.632
diff -u -r1.632 files
--- conf/files	2003/09/12 11:20:57	1.632
+++ conf/files	2003/09/19 20:26:53
@@ -187,11 +187,11 @@
 define	audiobus	{ }
 define	midibus		{ }
 define	midisyn
-define	wdc_base
+define	wdc_base        {[channel = -1]}
 define	scsi_core
 define	scsi		{[channel = -1]}: scsi_core
-define	ata		{[channel = -1], [drive = -1]}
-define	atapi		{[channel = -1]}
+define	ata		{[drive = -1]}
+define	atapi		{ }
 define	radiodev	{ }
 define	gpibdev		{[address = -1]}
 
@@ -712,8 +712,11 @@
 
 # Common code for ESDI/IDE/etc. controllers
 #
-device	wdc: ata, atapi, wdc_base
-file	dev/ic/wdc.c			wdc_base
+device	wdc: wdc_base
+
+device atabus: atapi,ata
+attach atabus at wdc_base
+file	dev/ic/wdc.c			atabus
 
 # CHIPS and Technologies 82C7[12][01] Universal Peripheral Controller
 # lpt attachment commented out because "device lpt" isn't in this file.
Index: dev/ata/ata.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/ata.c,v
retrieving revision 1.18
diff -u -r1.18 ata.c
--- dev/ata/ata.c	2003/01/27 21:27:52	1.18
+++ dev/ata/ata.c	2003/09/19 20:26:53
@@ -173,7 +173,7 @@
 }
 
 void
-ata_dmaerr(drvp)
+ata_dmaerr(drvp, flags)
 	struct ata_drive_datas *drvp;
 {
 	/*
@@ -185,7 +185,7 @@
 	 */
 	drvp->n_dmaerrs++;
 	if (drvp->n_dmaerrs >= NERRS_MAX && drvp->n_xfers <= NXFER) {
-		wdc_downgrade_mode(drvp);
+		wdc_downgrade_mode(drvp, flags);
 		drvp->n_dmaerrs = NERRS_MAX-1;
 		drvp->n_xfers = 0;
 		return;
Index: dev/ata/ata_wdc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/ata_wdc.c,v
retrieving revision 1.39
diff -u -r1.39 ata_wdc.c
--- dev/ata/ata_wdc.c	2003/04/28 05:20:29	1.39
+++ dev/ata/ata_wdc.c	2003/09/19 20:26:53
@@ -1,7 +1,7 @@
 /*	$NetBSD: ata_wdc.c,v 1.39 2003/04/28 05:20:29 nakayama Exp $	*/
 
 /*
- * Copyright (c) 1998, 2001 Manuel Bouyer.
+ * Copyright (c) 1998, 2001, 2003 Manuel Bouyer.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -123,7 +123,6 @@
 int   wdc_ata_bio_intr   __P((struct channel_softc *, struct wdc_xfer *, int));
 void  wdc_ata_bio_kill_xfer __P((struct channel_softc *,struct wdc_xfer *));
 void  wdc_ata_bio_done   __P((struct channel_softc *, struct wdc_xfer *)); 
-int   wdc_ata_ctrl_intr __P((struct channel_softc *, struct wdc_xfer *, int));
 int   wdc_ata_err __P((struct ata_drive_datas *, struct ata_bio *));
 #define WDC_ATA_NOERR 0x00 /* Drive doesn't report an error */
 #define WDC_ATA_RECOV 0x01 /* There was a recovered error */
@@ -207,13 +206,12 @@
 	struct channel_softc *chp;
 	struct wdc_xfer *xfer;
 {
-	struct ata_bio *ata_bio = xfer->cmd;
 	WDCDEBUG_PRINT(("wdc_ata_bio_start %s:%d:%d\n",
 	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive),
 	    DEBUG_XFERS);
 
 	/* start timeout machinery */
-	if ((ata_bio->flags & ATA_POLL) == 0)
+	if (xfer->c_flags & C_POLL)
 		callout_reset(&chp->ch_callout, ATA_DELAY / 1000 * hz,
 		    wdctimeout, chp);
 	_wdc_ata_bio_start(chp, xfer);
@@ -229,42 +227,103 @@
 	u_int16_t cyl;
 	u_int8_t head, sect, cmd = 0;
 	int nblks;
-	int ata_delay;
 	int dma_flags = 0;
+	int wait_flags = (ata_bio->flags & ATA_POLL) ? AT_POLL : 0;
+	char *errstring;
 
 	WDCDEBUG_PRINT(("_wdc_ata_bio_start %s:%d:%d\n",
 	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive),
 	    DEBUG_INTR | DEBUG_XFERS);
 	/* Do control operations specially. */
-	if (drvp->state < READY) {
+	if (__predict_false(drvp->state < READY)) {
 		/*
 		 * Actually, we want to be careful not to mess with the control
 		 * state if the device is currently busy, but we can assume
 		 * that we never get to this point if that's the case.
 		 */
-		/* at this point, we should only be in RECAL state */
-		if (drvp->state != RESET) {
-			printf("%s:%d:%d: bad state %d in _wdc_ata_bio_start\n",
-			    chp->wdc->sc_dev.dv_xname, chp->channel,
-			    xfer->drive, drvp->state);
-			panic("_wdc_ata_bio_start: bad state");
+		/* If it's not a polled command, we need the kenrel thread */
+		if ((ata_bio->flags & ATA_POLL) == 0 &&
+		    (chp->ch_flags & WDCF_TH_RUN) == 0) {
+			chp->ch_queue->queue_freese++;
+			wakeup(&chp->thread);
+			return;
 		}
-		drvp->state = RECAL;
-		xfer->c_intr = wdc_ata_ctrl_intr;
+		/*
+		 * disable interrupts, all commands here should be quick
+		 * enouth to be able to poll, and we don't go here that often
+		 */
+		bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
+		    WDCTL_4BIT | WDCTL_IDS);
 		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
 		    WDSD_IBM | (xfer->drive << 4));
-		if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY) != 0)
-			goto timeout;
+		errstring = "wait";
+		if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags))
+			goto ctrltimeout;
 		wdccommandshort(chp, xfer->drive, WDCC_RECAL);
-		drvp->state = RECAL_WAIT;
-		if ((ata_bio->flags & ATA_POLL) == 0) {
-			chp->ch_flags |= WDCF_IRQ_WAIT;
+		/* Wait for at last 400ns for status bit to be valid */
+		DELAY(1);
+		errstring = "recal";
+		if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags))
+			goto ctrltimeout;
+		if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
+			goto ctrlerror;
+		/* Don't try to set modes if controller can't be adjusted */
+		if ((chp->wdc->cap & WDC_CAPABILITY_MODE) == 0)
+			goto geometry;
+		/* Also don't try if the drive didn't report its mode */
+		if ((drvp->drive_flags & DRIVE_MODE) == 0)
+			goto geometry;
+		wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+		    0x08 | drvp->PIO_mode, WDSF_SET_MODE);
+		errstring = "piomode";
+		if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags))
+			goto ctrltimeout;
+		if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
+			goto ctrlerror;
+		if (drvp->drive_flags & DRIVE_UDMA) {
+			wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+			    0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
+		} else if (drvp->drive_flags & DRIVE_DMA) {
+			wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+			    0x20 | drvp->DMA_mode, WDSF_SET_MODE);
 		} else {
-			/* Wait for at last 400ns for status bit to be valid */
-			DELAY(1);
-			wdc_ata_ctrl_intr(chp, xfer, 0);
-		}
-		return;
+			goto geometry;
+		}	
+		errstring = "dmamode";
+		if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags))
+			goto ctrltimeout;
+		if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
+			goto ctrlerror;
+geometry:
+		if (ata_bio->flags & ATA_LBA)
+			goto multimode;
+		wdccommand(chp, xfer->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 == DTYPE_ST506) ?
+			ata_bio->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)
+			goto ready;
+		wdccommand(chp, xfer->drive, WDCC_SETMULTI, 0, 0, 0,
+		    ata_bio->multi, 0);
+		errstring = "setmulti";
+		if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY, wait_flags))
+			goto ctrltimeout;
+		if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
+			goto ctrlerror;
+ready:
+		drvp->state = READY;
+		/*
+		 * The drive is usable now
+		 */
+		bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
+		    WDCTL_4BIT);
 	}
 
 	if (xfer->c_flags & C_DMA) {
@@ -274,10 +333,6 @@
 		if (ata_bio->flags & ATA_LBA48)
 			dma_flags |= WDC_DMA_LBA48;
 	}
-	if (ata_bio->flags & ATA_SINGLE)
-		ata_delay = ATA_DELAY;
-	else
-		ata_delay = ATA_DELAY;
 again:
 	/*
 	 *
@@ -350,8 +405,14 @@
 			/* Initiate command */
 			bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
 			    WDSD_IBM | (xfer->drive << 4));
-			if (wait_for_ready(chp, ata_delay) < 0)
+			switch(wait_for_ready(chp, ATA_DELAY, wait_flags)) {
+			case WDCWAIT_OK:
+				break;	
+			case WDCWAIT_TOUT:
 				goto timeout;
+			case WDCWAIT_THR:
+				return;
+			}
 			if (ata_bio->flags & ATA_LBA48) {
 			    wdccommandext(chp, xfer->drive, to48(cmd),
 				(u_int64_t)ata_bio->blkno, nblks);
@@ -378,8 +439,14 @@
 		/* Initiate command! */
 		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
 		    WDSD_IBM | (xfer->drive << 4));
-		if (wait_for_ready(chp, ata_delay) < 0)
+		switch(wait_for_ready(chp, ATA_DELAY, wait_flags)) {
+		case WDCWAIT_OK:
+			break;
+		case WDCWAIT_TOUT:
 			goto timeout;
+		case WDCWAIT_THR:
+			return;
+		}
 		if (ata_bio->flags & ATA_LBA48) {
 		    wdccommandext(chp, xfer->drive, to48(cmd),
 			(u_int64_t) ata_bio->blkno, nblks);
@@ -399,7 +466,11 @@
 	}
 	/* If this was a write and not using DMA, push the data. */
 	if ((ata_bio->flags & ATA_READ) == 0) {
-		if (wait_for_drq(chp, ata_delay) != 0) {
+		/*
+		 * we have to busy-wait here, we can't rely on running in
+		 * thread context.
+		 */
+		if (wait_for_drq(chp, ATA_DELAY, AT_POLL) != 0) {
 			printf("%s:%d:%d: timeout waiting for DRQ, "
 			    "st=0x%02x, err=0x%02x\n",
 			    chp->wdc->sc_dev.dv_xname, chp->channel,
@@ -467,6 +538,28 @@
 		ata_bio->error = TIMEOUT;
 	wdc_ata_bio_done(chp, xfer);
 	return;
+ctrltimeout:
+	printf("%s:%d:%d: %s timed out\n",
+	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, errstring);
+	ata_bio->error = TIMEOUT;
+	goto ctrldone;
+ctrlerror:
+	printf("%s:%d:%d: %s ",
+	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
+	    errstring);
+	if (chp->ch_status & WDCS_DWF) {
+		printf("drive fault\n");
+		ata_bio->error = ERR_DF;
+	} else {
+		printf("error (%x)\n", chp->ch_error);
+		ata_bio->r_error = chp->ch_error;
+		ata_bio->error = ERROR;
+	}
+ctrldone:
+	drvp->state = 0;
+	wdc_ata_bio_done(chp, xfer);
+	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
+	return;
 }
 
 int
@@ -503,8 +596,7 @@
 	}
 
 	/* Ack interrupt done by wait_for_unbusy */
-	if (wait_for_unbusy(chp,
-	    (irq == 0) ? ATA_DELAY : 0) < 0) {
+	if (wait_for_unbusy(chp, (irq == 0) ? ATA_DELAY : 0, AT_POLL) < 0) {
 		if (irq && (xfer->c_flags & C_TIMEOU) == 0)
 			return 0; /* IRQ was not for us */
 		printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip%d\n",
@@ -512,7 +604,8 @@
 		    xfer->c_bcount, xfer->c_skip);
 		/* if we were using DMA, flag a DMA error */
 		if (xfer->c_flags & C_DMA) {
-			ata_dmaerr(drvp);
+			ata_dmaerr(drvp,
+			    (xfer->c_flags & C_POLL) ? AT_POLL : 0);
 		}
 		ata_bio->error = TIMEOUT;
 		wdc_ata_bio_done(chp, xfer);
@@ -533,7 +626,7 @@
 			 * asserted for DMA transfers, so poll for DRDY.
 			 */
 			if (wdcwait(chp, WDCS_DRDY | WDCS_DRQ, WDCS_DRDY,
-			    ATA_DELAY) < 0) {
+			    ATA_DELAY, ATA_POLL) == WDCWAIT_TOUT) {
 				printf("%s:%d:%d: polled transfer timed out "
 				    "(st=0x%x)\n", chp->wdc->sc_dev.dv_xname,
 				    chp->channel, xfer->drive, chp->ch_status);
@@ -558,7 +651,7 @@
 		}
 		if (drv_err != WDC_ATA_ERR)
 			goto end;
-		ata_dmaerr(drvp);
+		ata_dmaerr(drvp, (xfer->c_flags & C_POLL) ? AT_POLL : 0);
 	}
 
 	/* if we had an error, end */
@@ -684,169 +777,6 @@
 	WDCDEBUG_PRINT(("wdcstart from wdc_ata_done, flags 0x%x\n",
 	    chp->ch_flags), DEBUG_XFERS);
 	wdcstart(chp);
-}
-
-/*
- * Implement operations needed before read/write.
- */
-int
-wdc_ata_ctrl_intr(chp, xfer, irq)
-	struct channel_softc *chp;
-	struct wdc_xfer *xfer;
-	int irq;
-{
-	struct ata_bio *ata_bio = xfer->cmd;
-	struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
-	char *errstring = NULL;
-	int delay = (irq == 0) ? ATA_DELAY : 0;
-
-	WDCDEBUG_PRINT(("wdc_ata_ctrl_intr: state %d\n", drvp->state),
-	    DEBUG_FUNCS);
-
-again:
-	switch (drvp->state) {
-	case RECAL:    /* Should not be in this state here */
-		panic("wdc_ata_ctrl_intr: state==RECAL");
-		break;
-
-	case RECAL_WAIT:
-		errstring = "recal";
-		if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay))
-			goto timeout;
-		if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
-			chp->wdc->irqack(chp);
-		if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
-			goto error;
-	/* fall through */
-
-	case PIOMODE:
-		/* Don't try to set modes if controller can't be adjusted */
-		if ((chp->wdc->cap & WDC_CAPABILITY_MODE) == 0)
-			goto geometry;
-		/* Also don't try if the drive didn't report its mode */
-		if ((drvp->drive_flags & DRIVE_MODE) == 0)
-			goto geometry;
-		wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
-		    0x08 | drvp->PIO_mode, WDSF_SET_MODE);
-		drvp->state = PIOMODE_WAIT;
-		break;
-
-	case PIOMODE_WAIT:
-		errstring = "piomode";
-		if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay))
-			goto timeout;
-		if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
-			chp->wdc->irqack(chp);
-		if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
-			goto error;
-	/* fall through */
-
-	case DMAMODE:
-		if (drvp->drive_flags & DRIVE_UDMA) {
-			wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
-			    0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
-		} else if (drvp->drive_flags & DRIVE_DMA) {
-			wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
-			    0x20 | drvp->DMA_mode, WDSF_SET_MODE);
-		} else {
-			goto geometry;
-		}	
-		drvp->state = DMAMODE_WAIT;
-		break;
-	case DMAMODE_WAIT:
-		errstring = "dmamode";
-		if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay))
-			goto timeout;
-		if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
-			chp->wdc->irqack(chp);
-		if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
-			goto error;
-	/* fall through */
-
-	case GEOMETRY:
-	geometry:
-		if (ata_bio->flags & ATA_LBA)
-			goto multimode;
-		wdccommand(chp, xfer->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 == DTYPE_ST506) ?
-			ata_bio->lp->d_precompcyl / 4 : 0);
-		drvp->state = GEOMETRY_WAIT;
-		break;
-
-	case GEOMETRY_WAIT:
-		errstring = "geometry";
-		if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay))
-			goto timeout;
-		if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
-			chp->wdc->irqack(chp);
-		if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
-			goto error;
-		/* fall through */
-
-	case MULTIMODE:
-	multimode:
-		if (ata_bio->multi == 1)
-			goto ready;
-		wdccommand(chp, xfer->drive, WDCC_SETMULTI, 0, 0, 0,
-		    ata_bio->multi, 0);
-		drvp->state = MULTIMODE_WAIT;
-		break;
-
-	case MULTIMODE_WAIT:
-		errstring = "setmulti";
-		if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, delay))
-			goto timeout;
-		if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
-			chp->wdc->irqack(chp);
-		if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
-			goto error;
-		/* fall through */
-
-	case READY:
-	ready:
-		drvp->state = READY;
-		/*
-		 * The drive is usable now
-		 */
-		xfer->c_intr = wdc_ata_bio_intr;
-		_wdc_ata_bio_start(chp, xfer); 
-		return 1;
-	}
-
-	if ((ata_bio->flags & ATA_POLL) == 0) {
-		chp->ch_flags |= WDCF_IRQ_WAIT;
-	} else {
-		goto again;
-	}
-	return 1;
-
-timeout:
-	if (irq && (xfer->c_flags & C_TIMEOU) == 0) {
-		return 0; /* IRQ was not for us */
-	}
-	printf("%s:%d:%d: %s timed out\n",
-	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, errstring);
-	ata_bio->error = TIMEOUT;
-	drvp->state = 0;
-	wdc_ata_bio_done(chp, xfer);
-	return 0;
-error:
-	printf("%s:%d:%d: %s ",
-	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
-	    errstring);
-	if (chp->ch_status & WDCS_DWF) {
-		printf("drive fault\n");
-		ata_bio->error = ERR_DF;
-	} else {
-		printf("error (%x)\n", chp->ch_error);
-		ata_bio->r_error = chp->ch_error;
-		ata_bio->error = ERROR;
-	}
-	drvp->state = 0;
-	wdc_ata_bio_done(chp, xfer);
-	return 1;
 }
 
 int
Index: dev/ata/atavar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/atavar.h,v
retrieving revision 1.27
diff -u -r1.27 atavar.h
--- dev/ata/atavar.h	2003/07/08 10:06:28	1.27
+++ dev/ata/atavar.h	2003/09/19 20:26:53
@@ -67,17 +67,7 @@
      */
     u_int8_t state;
 #define RESET          0
-#define RECAL          1
-#define RECAL_WAIT     2
-#define PIOMODE        3
-#define PIOMODE_WAIT   4
-#define DMAMODE        5
-#define DMAMODE_WAIT   6
-#define GEOMETRY       7
-#define GEOMETRY_WAIT  8
-#define MULTIMODE      9
-#define MULTIMODE_WAIT 10
-#define READY          11
+#define READY          1
 
     /* numbers of xfers and DMA errs. Used by ata_dmaerr() */
     u_int8_t n_dmaerrs;
@@ -194,7 +184,7 @@
 	int8_t			checksum;
 } __attribute__((packed));
 
-int  wdc_downgrade_mode __P((struct ata_drive_datas *));
+int  wdc_downgrade_mode __P((struct ata_drive_datas *, int));
 
 struct ataparams;
 int ata_get_params __P((struct ata_drive_datas *, u_int8_t,
@@ -205,4 +195,4 @@
 #define CMD_ERR   1
 #define CMD_AGAIN 2
 
-void ata_dmaerr __P((struct ata_drive_datas *));
+void ata_dmaerr __P((struct ata_drive_datas *, int));
Index: dev/ata/files.ata
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/files.ata,v
retrieving revision 1.6
diff -u -r1.6 files.ata
--- dev/ata/files.ata	2003/01/27 18:21:29	1.6
+++ dev/ata/files.ata	2003/09/19 20:26:53
@@ -9,9 +9,9 @@
 device	wd: disk
 attach	wd at ata
 file	dev/ata/wd.c			wd			needs-flag
-file	dev/ata/ata_wdc.c		wd & wdc_base
+file	dev/ata/ata_wdc.c		wd & atabus
 
-file	dev/ata/ata.c			(ata | atapi) & wdc_base
+file	dev/ata/ata.c			(ata | atapi) & atabus
 
 # ATA RAID configuration support
 defpseudo ataraid {[vendtype = -1], [unit = -1]}
Index: dev/ata/wd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/wd.c,v
retrieving revision 1.260
diff -u -r1.260 wd.c
--- dev/ata/wd.c	2003/08/03 17:53:04	1.260
+++ dev/ata/wd.c	2003/09/19 20:26:53
@@ -262,10 +262,6 @@
 	if (adev->adev_bustype->bustype_type != SCSIPI_BUSTYPE_ATA)
 		return 0;
 
-	if (match->cf_loc[ATACF_CHANNEL] != ATACF_CHANNEL_DEFAULT &&
-	    match->cf_loc[ATACF_CHANNEL] != adev->adev_channel)
-		return 0;
-
 	if (match->cf_loc[ATACF_DRIVE] != ATACF_DRIVE_DEFAULT &&
 	    match->cf_loc[ATACF_DRIVE] != adev->adev_drv_data->drive)
 		return 0;
@@ -293,14 +289,13 @@
 	wd->atabus = adev->adev_bustype;
 	wd->openings = adev->adev_openings;
 	wd->drvp = adev->adev_drv_data;
-	wd->wdc_softc = parent;
 	/* give back our softc to our caller */
 	wd->drvp->drv_softc = &wd->sc_dev;
 
 	aprint_naive("\n");
 
 	/* read our drive info */
-	if (wd_get_params(wd, AT_POLL, &wd->sc_params) != 0) {
+	if (wd_get_params(wd, AT_WAIT, &wd->sc_params) != 0) {
 		aprint_error("\n%s: IDENTIFY failed\n", wd->sc_dev.dv_xname);
 		return;
 	}
@@ -755,7 +750,7 @@
 		errmsg = "error";
 		do_perror = 1;
 retry:		/* Just reset and retry. Can we do more ? */
-		wd->atabus->ata_reset_channel(wd->drvp);
+		wd->atabus->ata_reset_channel(wd->drvp, 0);
 		diskerr(bp, "wd", errmsg, LOG_PRINTF,
 		    wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label);
 		if (wd->retries < WDIORETRIES)
@@ -1067,7 +1062,7 @@
 
 	wd->sc_badsect[0] = -1;
 
-	if (wd->drvp->state > RECAL)
+	if (wd->drvp->state > RESET)
 		wd->drvp->drive_flags |= DRIVE_RESET;
 	errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit, RAW_PART),
 	    wdstrategy, lp, wd->sc_dk.dk_cpulabel);
@@ -1078,7 +1073,7 @@
 		 * assume the DOS geometry is now in the label and try
 		 * again.  XXX This is a kluge.
 		 */
-		if (wd->drvp->state > RECAL)
+		if (wd->drvp->state > RESET)
 			wd->drvp->drive_flags |= DRIVE_RESET;
 		errstring = readdisklabel(MAKEWDDEV(0, wd->sc_dev.dv_unit,
 		    RAW_PART), wdstrategy, lp, wd->sc_dk.dk_cpulabel);
@@ -1088,7 +1083,7 @@
 		return;
 	}
 
-	if (wd->drvp->state > RECAL)
+	if (wd->drvp->state > RESET)
 		wd->drvp->drive_flags |= DRIVE_RESET;
 #ifdef HAS_BAD144_HANDLING
 	if ((lp->d_flags & D_BADSECT) != 0)
@@ -1269,7 +1264,7 @@
 		    lp, /*wd->sc_dk.dk_openmask : */0,
 		    wd->sc_dk.dk_cpulabel);
 		if (error == 0) {
-			if (wd->drvp->state > RECAL)
+			if (wd->drvp->state > RESET)
 				wd->drvp->drive_flags |= DRIVE_RESET;
 			if (xfer == DIOCWDINFO
 #ifdef __HAVE_OLD_DISKLABEL
Index: dev/ata/wdvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/wdvar.h,v
retrieving revision 1.17
diff -u -r1.17 wdvar.h
--- dev/ata/wdvar.h	2003/04/15 18:27:27	1.17
+++ dev/ata/wdvar.h	2003/09/19 20:26:53
@@ -69,7 +69,7 @@
 struct ata_bustype {
 	int bustype_type;	/* symbolic name of type */
 	int (*ata_bio) __P((struct ata_drive_datas*, struct ata_bio *));
-	void (*ata_reset_channel) __P((struct ata_drive_datas *));
+	void (*ata_reset_channel) __P((struct ata_drive_datas *, int));
 	int (*ata_exec_command) __P((struct ata_drive_datas *,
 					struct wdc_command *));
 #define WDC_COMPLETE 0x01
@@ -109,7 +109,6 @@
 	/* IDE disk soft states */
 	struct ata_bio sc_wdc_bio; /* current transfer */
 	struct buf *sc_bp; /* buf being transfered */
-	void *wdc_softc;   /* pointer to our parent */
 	struct ata_drive_datas *drvp; /* Our controller's infos */
 	const struct ata_bustype *atabus;
 	int openings;
Index: dev/ic/wdc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wdc.c,v
retrieving revision 1.123
diff -u -r1.123 wdc.c
--- dev/ic/wdc.c	2003/05/17 21:52:04	1.123
+++ dev/ic/wdc.c	2003/09/19 20:26:54
@@ -1,7 +1,7 @@
 /*	$NetBSD: wdc.c,v 1.123 2003/05/17 21:52:04 thorpej Exp $ */
 
 /*
- * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
+ * Copyright (c) 1998, 2001, 2003 Manuel Bouyer.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -79,6 +79,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/kthread.h>
 #include <sys/conf.h>
 #include <sys/buf.h>
 #include <sys/device.h>
@@ -103,6 +104,8 @@
 #include <dev/ic/wdcreg.h>
 #include <dev/ic/wdcvar.h>
 
+#include "locators.h"
+
 #include "ataraid.h"
 #include "atapibus.h"
 #include "wd.h"
@@ -118,6 +121,12 @@
 #define WDCNDELAY_DEBUG	50
 #endif
 
+/* When polling wait that much and then tsleep for 1/hz seconds */
+#define WDCDELAY_POLL 1 /* ms */ 
+
+/* timeout for the control commands */
+#define WDC_CTRL_DELAY 10000 /* 10s, for the recall command */
+
 struct pool wdc_xfer_pool;
 
 #if NWD > 0
@@ -136,11 +145,33 @@
 };
 #endif
 
+int	atabusmatch __P((struct device *, struct cfdata *, void *));
+void	atabusattach __P((struct device *, struct device *, void *));
+void	atabus_create_thread __P((void *));
+void	atabus_thread __P((void *));
+void	atabusconfig __P((struct atabus_softc *));
+int	atabusactivate __P((struct device *, enum devact));
+int	atabusdetach __P((struct device *, int flags));
+int	atabusprint __P((void *, const char *));
+
+CFATTACH_DECL(atabus, sizeof(struct atabus_softc),
+    atabusmatch, atabusattach, atabusdetach, atabusactivate);
+
+struct atabus_initq {
+        struct atabus_softc *atabus_sc;
+        TAILQ_ENTRY(atabus_initq) atabus_initq;
+};    
+static TAILQ_HEAD(, atabus_initq) atabus_initq_head =
+    TAILQ_HEAD_INITIALIZER(atabus_initq_head);
+static struct simplelock atabus_interlock = SIMPLELOCK_INITIALIZER;
+
+int __wdcprobe __P((struct channel_softc*, int));
 static void  __wdcerror	  __P((struct channel_softc*, char *));
-static int   __wdcwait_reset  __P((struct channel_softc *, int));
+static int   __wdcwait_reset  __P((struct channel_softc *, int, int));
 void  __wdccommand_done __P((struct channel_softc *, struct wdc_xfer *));
 void  __wdccommand_start __P((struct channel_softc *, struct wdc_xfer *));	
 int   __wdccommand_intr __P((struct channel_softc *, struct wdc_xfer *, int));
+int   __wdcwait __P((struct channel_softc *, int, int, int));
 int   wdprint __P((void *, const char *));
 
 #define DEBUG_INTR   0x01
@@ -159,185 +190,140 @@
 #endif
 
 int
-wdprint(aux, pnp)
+atabusprint(aux, pnp)
 	void *aux;
 	const char *pnp;
 {
-	struct ata_device *adev = aux;
+	struct channel_softc *chan = aux;
 	if (pnp)
-		aprint_normal("wd at %s", pnp);
-	aprint_normal(" channel %d drive %d", adev->adev_channel,
-	    adev->adev_drv_data->drive);
+		aprint_normal("atabus at %s", pnp);
+	aprint_normal(" channel %d", chan->channel);
 	return (UNCONF);
 }
 
-/* Test to see controller with at last one attached drive is there.
- * Returns a bit for each possible drive found (0x01 for drive 0,
- * 0x02 for drive 1).
- * Logic:
- * - If a status register is at 0xff, assume there is no drive here
- *   (ISA has pull-up resistors).  Similarly if the status register has
- *   the value we last wrote to the bus (for IDE interfaces without pullups).
- *   If no drive at all -> return.
- * - reset the controller, wait for it to complete (may take up to 31s !).
- *   If timeout -> return.
- * - test ATA/ATAPI signatures. If at last one drive found -> return.
- * - try an ATA command on the master.
- */
-
 int
-wdcprobe(chp)
-	struct channel_softc *chp;
+atabusmatch(parent, cf, aux)
+	struct device *parent;
+	struct cfdata *cf;
+	void *aux;
 {
-	u_int8_t st0, st1, sc, sn, cl, ch;
-	u_int8_t ret_value = 0x03;
-	u_int8_t drive;
-	int found;
-
-	/*
-	 * Sanity check to see if the wdc channel responds at all.
-	 */
-
-	if (chp->wdc == NULL ||
-	    (chp->wdc->cap & WDC_CAPABILITY_NO_EXTRA_RESETS) == 0) {
+	struct channel_softc *chp = aux;
 
-		if (chp->wdc && (chp->wdc->cap & WDC_CAPABILITY_SELECT))
-			chp->wdc->select(chp,0);
-
-		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
-		    WDSD_IBM);
-		delay(10);
-		st0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status);
-		
-		if (chp->wdc && (chp->wdc->cap & WDC_CAPABILITY_SELECT))
-			chp->wdc->select(chp,1);
+	if (chp == NULL)
+		return (0);
 
-		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
-		    WDSD_IBM | 0x10);
-		delay(10);
-		st1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status);
+	if (cf->cf_loc[WDC_BASECF_CHANNEL] != chp->channel &&
+	    cf->cf_loc[WDC_BASECF_CHANNEL] != WDC_BASECF_CHANNEL_DEFAULT)
+		return (0);
 
-		WDCDEBUG_PRINT(("%s:%d: before reset, st0=0x%x, st1=0x%x\n",
-		    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
-		    chp->channel, st0, st1), DEBUG_PROBE);
+	return (1);
+}
 
-		if (st0 == 0xff || st0 == WDSD_IBM)
-			ret_value &= ~0x01;
-		if (st1 == 0xff || st1 == (WDSD_IBM | 0x10))
-			ret_value &= ~0x02;
-		if (ret_value == 0)
-			return 0;
-	}
+void
+atabusattach(parent, self, aux)
+	struct device *parent, *self;
+	void *aux;
+{
+	struct atabus_softc *atabus_sc = (struct atabus_softc *)self;
+	struct channel_softc *chp = aux;
+	struct atabus_initq *atabus_initq;
+
+	atabus_sc->sc_chan = chp;
+
+	printf("\n");
+	atabus_initq  = malloc(sizeof(struct atabus_initq), M_DEVBUF, M_NOWAIT);
+	atabus_initq->atabus_sc = atabus_sc;
+	TAILQ_INSERT_TAIL(&atabus_initq_head, atabus_initq, atabus_initq);
+	config_pending_incr();
+	kthread_create(atabus_create_thread, atabus_sc);
 
-	if (chp->wdc && (chp->wdc->cap & WDC_CAPABILITY_SELECT))
-		chp->wdc->select(chp,0);
-	/* assert SRST, wait for reset to complete */
-	bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
-	    WDSD_IBM);
-	delay(10);
-	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
-	    WDCTL_RST | WDCTL_IDS); 
-	DELAY(1000);
-	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
-	    WDCTL_IDS);
-	delay(1000);
-	(void) bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error);
-	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
-	delay(10);
+}
 
-	ret_value = __wdcwait_reset(chp, ret_value);
-	WDCDEBUG_PRINT(("%s:%d: after reset, ret_value=0x%d\n",
-	    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe", chp->channel,
-	    ret_value), DEBUG_PROBE);
+void
+atabus_create_thread(arg)
+	void *arg;
+{
+	struct atabus_softc *atabus_sc = arg;
+	struct channel_softc *chp = atabus_sc->sc_chan;
+	int error;
+	
+	if ((error = kthread_create1(atabus_thread, atabus_sc, &chp->thread,
+	    "%s", atabus_sc->sc_dev.dv_xname)) != 0)
+		printf("unable to create kernel thread for %s: error %d\n",
+		    atabus_sc->sc_dev.dv_xname, error);
+}
 
-	/* if reset failed, there's nothing here */
-	if (ret_value == 0)
-		return 0;
+void
+atabus_thread(arg)
+	void *arg;
+{
+	struct atabus_softc *atabus_sc = arg;
+	struct channel_softc *chp = atabus_sc->sc_chan;
+	struct wdc_xfer *xfer;
+	int s;
 
-	/*
-	 * Test presence of drives. First test register signatures looking for
-	 * ATAPI devices. If it's not an ATAPI and reset said there may be
-	 * something here assume it's ATA or OLD. Ghost will be killed later in
-	 * attach routine.
-	 */
-	found = 0;
-	for (drive = 0; drive < 2; drive++) {
-		if ((ret_value & (0x01 << drive)) == 0)
-			continue;
-		if (1 < ++found && chp->wdc != NULL &&
-		    (chp->wdc->cap & WDC_CAPABILITY_SINGLE_DRIVE)) {
+	s = splbio();
+	chp->ch_flags |= WDCF_TH_RUN;
+	splx(s);
+	atabusconfig(atabus_sc);
+	for(;;)
+	{
+		s = splbio();
+		chp->ch_flags &= ~WDCF_TH_RUN;
+		tsleep(&chp->thread, PRIBIO, "atath", 0);
+		chp->ch_flags |= WDCF_TH_RUN;
+		splx(s);
+		if (chp->ch_flags & WDCF_SHUTDOWN)
+			break;
+		s = splbio();
+		if (chp->ch_flags & WDCF_TH_RESET) {
+			int drive;
+			(void) wdcreset(chp, RESET_SLEEP);
+			for (drive = 0; drive < 2; drive++) {
+				chp->ch_drive[drive].state = 0;
+			}
+			chp->ch_flags &= ~WDCF_TH_RESET;
+			wdcstart(chp);
+		} else if ((chp->ch_flags & WDCF_ACTIVE) != 0 &&
+		    chp->ch_queue->queue_freese == 1) {
 			/*
-			 * Ignore second drive if WDC_CAPABILITY_SINGLE_DRIVE
-			 * is set.
-			 *
-			 * Some CF Card (for ex. IBM MicroDrive and SanDisk) 
-			 * doesn't seem to implement drive select command. In
-			 * this case, you can't eliminate ghost drive properly.
+			 * caller has bumped queue_freese, decrease it
 			 */
-			WDCDEBUG_PRINT(("%s:%d:%d: ignored.\n",
-			    chp->wdc->sc_dev.dv_xname,
-			    chp->channel, drive), DEBUG_PROBE);
-			break;
-		}
-		if (chp->wdc && chp->wdc->cap & WDC_CAPABILITY_SELECT)
-			chp->wdc->select(chp,drive);
-		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
-		    WDSD_IBM | (drive << 4));
-		delay(10);
-		/* Save registers contents */
-		sc = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_seccnt);
-		sn = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_sector);
-		cl = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo);
-		ch = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_hi);
-
-		WDCDEBUG_PRINT(("%s:%d:%d: after reset, sc=0x%x sn=0x%x "
-		    "cl=0x%x ch=0x%x\n",
-		    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
-	    	    chp->channel, drive, sc, sn, cl, ch), DEBUG_PROBE);
-		/*
-		 * sc & sn are supposted to be 0x1 for ATAPI but in some cases
-		 * we get wrong values here, so ignore it.
-		 */
-		if (cl == 0x14 && ch == 0xeb) {
-			chp->ch_drive[drive].drive_flags |= DRIVE_ATAPI;
-		} else {
-			chp->ch_drive[drive].drive_flags |= DRIVE_ATA;
-			if (chp->wdc == NULL ||
-			    (chp->wdc->cap & WDC_CAPABILITY_PREATA) != 0)
-				chp->ch_drive[drive].drive_flags |= DRIVE_OLD;
+			chp->ch_queue->queue_freese--;
+			xfer = chp->ch_queue->sc_xfer.tqh_first;
+#ifdef DIAGNOSTIC
+			if (xfer == NULL)
+				panic("channel active with no xfer ?");
+#endif
+			xfer->c_start(chp, xfer);
 		}
+		splx(s);
 	}
-	return (ret_value);	
+	chp->thread = NULL;
+	wakeup(&chp->ch_flags);
+	kthread_exit(0);
 }
 
 void
-wdcattach(chp)
-	struct channel_softc *chp;
+atabusconfig(atabus_sc)
+	struct atabus_softc *atabus_sc;
 {
+	struct channel_softc *chp = atabus_sc->sc_chan;
 	int ctrl_flags, i, error;
 	struct ataparams params;
-	static int inited = 0;
-
-	callout_init(&chp->ch_callout);
+	struct atabus_initq *atabus_initq = NULL;
 
 	if ((error = wdc_addref(chp)) != 0) {
 		aprint_error("%s: unable to enable controller\n",
 		    chp->wdc->sc_dev.dv_xname);
+		config_pending_decr();
 		return;
 	}
 
-	if (wdcprobe(chp) == 0)
+	if (__wdcprobe(chp, 0) == 0)
 		/* If no drives, abort attach here. */
 		goto out;
 
-	/* initialise global data */
-	if (inited == 0) {
-		/* Initialize the wdc_xfer pool. */
-		pool_init(&wdc_xfer_pool, sizeof(struct wdc_xfer), 0,
-		    0, 0, "wdcspl", NULL);
-		inited++;
-	}
-	TAILQ_INIT(&chp->ch_queue->sc_xfer);
 
 	for (i = 0; i < 2; i++) {
 		chp->ch_drive[i].chnl_softc = chp;
@@ -361,10 +347,10 @@
 		 * Then issue a IDENTIFY command, to try to detect slave ghost
 		 */
 		delay(5000);
-		error = ata_get_params(&chp->ch_drive[i], AT_POLL, &params);
+		error = ata_get_params(&chp->ch_drive[i], AT_WAIT, &params);
 		if (error != CMD_OK) {
-			delay(1000000);
-			error = ata_get_params(&chp->ch_drive[i], AT_POLL,
+			tsleep(&atabus_sc, PRIBIO, "atacnf", mstohz(1000));
+			error = ata_get_params(&chp->ch_drive[i], AT_WAIT,
 			    &params);
 		}
 		if (error == CMD_OK) {
@@ -408,7 +394,7 @@
 			bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
 			    WDSD_IBM | (i << 4));
 			delay(100);
-			if (wait_for_ready(chp, 10000) != 0) {
+			if (wait_for_ready(chp, 10000, 0) == WDCWAIT_TOUT) {
 				WDCDEBUG_PRINT(("%s:%d:%d: not ready\n",
 				    chp->wdc->sc_dev.dv_xname,
 				    chp->channel, i), DEBUG_PROBE);
@@ -417,7 +403,7 @@
 			}
 			bus_space_write_1(chp->cmd_iot, chp->cmd_ioh,
 			    wd_command, WDCC_RECAL);
-			if (wait_for_ready(chp, 10000) != 0) {
+			if (wait_for_ready(chp, 10000, 0) == WDCWAIT_TOUT) {
 				WDCDEBUG_PRINT(("%s:%d:%d: WDCC_RECAL failed\n",
 				    chp->wdc->sc_dev.dv_xname,
 				    chp->channel, i), DEBUG_PROBE);
@@ -427,7 +413,7 @@
 	}
 	ctrl_flags = chp->wdc->sc_dev.dv_cfdata->cf_flags;
 
-	WDCDEBUG_PRINT(("wdcattach: ch_drive_flags 0x%x 0x%x\n",
+	WDCDEBUG_PRINT(("atabusattach: ch_drive_flags 0x%x 0x%x\n",
 	    chp->ch_drive[0].drive_flags, chp->ch_drive[1].drive_flags),
 	    DEBUG_PROBE);
 
@@ -436,19 +422,30 @@
 	    (chp->ch_drive[1].drive_flags & DRIVE) == 0)
 		goto out;
 
+	/* Make sure the devices probe in atabus order to avoid jitter. */
+	simple_lock(&atabus_interlock);
+	while(1) {
+		atabus_initq = TAILQ_FIRST(&atabus_initq_head);
+		if (atabus_initq->atabus_sc == atabus_sc)
+			break;
+		ltsleep(&atabus_initq_head, PRIBIO, "ata_initq", 0,
+		    &atabus_interlock);
+	}
+	simple_unlock(&atabus_interlock);
+
 	/*
 	 * Attach an ATAPI bus, if needed.
 	 */
 	if ((chp->ch_drive[0].drive_flags & DRIVE_ATAPI) ||
 	    (chp->ch_drive[1].drive_flags & DRIVE_ATAPI)) {
 #if NATAPIBUS > 0
-		wdc_atapibus_attach(chp);
+		wdc_atapibus_attach(atabus_sc);
 #else
 		/*
 		 * Fake the autoconfig "not configured" message
 		 */
-		aprint_normal("atapibus at %s channel %d not configured\n",
-		    chp->wdc->sc_dev.dv_xname, chp->channel);
+		aprint_normal("atapibus at %s not configured\n",
+		    chp->wdc->sc_dev.dv_xname);
 		chp->atapibus = NULL;
 #endif
 	}
@@ -464,7 +461,7 @@
 		adev.adev_channel = chp->channel;
 		adev.adev_openings = 1;
 		adev.adev_drv_data = &chp->ch_drive[i];
-		chp->ata_drives[i] = config_found(&chp->wdc->sc_dev,
+		chp->ata_drives[i] = config_found(&atabus_sc->sc_dev,
 		    &adev, wdprint);
 		if (chp->ata_drives[i] != NULL) {
 			wdc_probe_caps(&chp->ch_drive[i]);
@@ -476,6 +473,9 @@
 		}
 	}
 
+	/* now that we know the drives, the controller can set its modes */
+	chp->wdc->set_modes(chp);
+
 	/*
 	 * reset drive_flags for unnatached devices, reset state for attached
 	 *  ones
@@ -487,47 +487,221 @@
 			chp->ch_drive[i].state = 0;
 	}
 
+out:
+	if (atabus_initq == NULL) {
+		simple_lock(&atabus_interlock);
+		while(1) {
+			atabus_initq = TAILQ_FIRST(&atabus_initq_head);
+			if (atabus_initq->atabus_sc == atabus_sc)
+				break;
+			ltsleep(&atabus_initq_head, PRIBIO, "ata_initq", 0,
+			    &atabus_interlock);
+		}
+		simple_unlock(&atabus_interlock);
+	}
+        simple_lock(&atabus_interlock);
+        TAILQ_REMOVE(&atabus_initq_head, atabus_initq, atabus_initq);
+        simple_unlock(&atabus_interlock);
+
+        free(atabus_initq, M_DEVBUF);
+        wakeup(&atabus_initq_head);
+
+	config_pending_decr();
+	wdc_delref(chp);
+}
+
+
+int
+wdprint(aux, pnp)
+	void *aux;
+	const char *pnp;
+{
+	struct ata_device *adev = aux;
+	if (pnp)
+		aprint_normal("wd at %s", pnp);
+	aprint_normal(" drive %d", adev->adev_drv_data->drive);
+	return (UNCONF);
+}
+
+/* Test to see controller with at last one attached drive is there.
+ * Returns a bit for each possible drive found (0x01 for drive 0,
+ * 0x02 for drive 1).
+ * Logic:
+ * - If a status register is at 0xff, assume there is no drive here
+ *   (ISA has pull-up resistors).  Similarly if the status register has
+ *   the value we last wrote to the bus (for IDE interfaces without pullups).
+ *   If no drive at all -> return.
+ * - reset the controller, wait for it to complete (may take up to 31s !).
+ *   If timeout -> return.
+ * - test ATA/ATAPI signatures. If at last one drive found -> return.
+ * - try an ATA command on the master.
+ */
+
+int
+wdcprobe(chp)
+	struct channel_softc *chp;
+{
+	return __wdcprobe(chp, 1);
+}
+
+int
+__wdcprobe(chp, poll)
+	struct channel_softc *chp;
+	int poll;
+{
+	u_int8_t st0, st1, sc, sn, cl, ch;
+	u_int8_t ret_value = 0x03;
+	u_int8_t drive;
+	int found;
+
 	/*
-	 * Reset channel. The probe, with some combinations of ATA/ATAPI
-	 * devices keep it in a mostly working, but strange state (with busy
-	 * led on)
+	 * Sanity check to see if the wdc channel responds at all.
 	 */
-	if ((chp->wdc->cap & WDC_CAPABILITY_NO_EXTRA_RESETS) == 0) {
-		delay(50);
-		wdcreset(chp, VERBOSE);
+
+	if (chp->wdc == NULL ||
+	    (chp->wdc->cap & WDC_CAPABILITY_NO_EXTRA_RESETS) == 0) {
+
+		if (chp->wdc && (chp->wdc->cap & WDC_CAPABILITY_SELECT))
+			chp->wdc->select(chp,0);
+
+		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
+		    WDSD_IBM);
+		delay(10);
+		st0 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status);
+		
+		if (chp->wdc && (chp->wdc->cap & WDC_CAPABILITY_SELECT))
+			chp->wdc->select(chp,1);
+
+		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
+		    WDSD_IBM | 0x10);
+		delay(10);
+		st1 = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status);
+
+		WDCDEBUG_PRINT(("%s:%d: before reset, st0=0x%x, st1=0x%x\n",
+		    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
+		    chp->channel, st0, st1), DEBUG_PROBE);
+
+		if (st0 == 0xff || st0 == WDSD_IBM)
+			ret_value &= ~0x01;
+		if (st1 == 0xff || st1 == (WDSD_IBM | 0x10))
+			ret_value &= ~0x02;
+		if (ret_value == 0)
+			return 0;
+	}
+
+	if (chp->wdc && (chp->wdc->cap & WDC_CAPABILITY_SELECT))
+		chp->wdc->select(chp,0);
+	/* assert SRST, wait for reset to complete */
+	bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
+	    WDSD_IBM);
+	delay(10);
+	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
+	    WDCTL_RST | WDCTL_IDS); 
+	DELAY(1000);
+	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
+	    WDCTL_IDS);
+	delay(1000);
+	(void) bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_error);
+	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
+	delay(10);
+
+	ret_value = __wdcwait_reset(chp, ret_value, poll);
+	WDCDEBUG_PRINT(("%s:%d: after reset, ret_value=0x%d\n",
+	    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe", chp->channel,
+	    ret_value), DEBUG_PROBE);
+
+	/* if reset failed, there's nothing here */
+	if (ret_value == 0)
+		return 0;
+
+	/*
+	 * Test presence of drives. First test register signatures looking for
+	 * ATAPI devices. If it's not an ATAPI and reset said there may be
+	 * something here assume it's ATA or OLD. Ghost will be killed later in
+	 * attach routine.
+	 */
+	found = 0;
+	for (drive = 0; drive < 2; drive++) {
+		if ((ret_value & (0x01 << drive)) == 0)
+			continue;
+		if (1 < ++found && chp->wdc != NULL &&
+		    (chp->wdc->cap & WDC_CAPABILITY_SINGLE_DRIVE)) {
+			/*
+			 * Ignore second drive if WDC_CAPABILITY_SINGLE_DRIVE
+			 * is set.
+			 *
+			 * Some CF Card (for ex. IBM MicroDrive and SanDisk) 
+			 * doesn't seem to implement drive select command. In
+			 * this case, you can't eliminate ghost drive properly.
+			 */
+			WDCDEBUG_PRINT(("%s:%d:%d: ignored.\n",
+			    chp->wdc->sc_dev.dv_xname,
+			    chp->channel, drive), DEBUG_PROBE);
+			break;
+		}
+		if (chp->wdc && chp->wdc->cap & WDC_CAPABILITY_SELECT)
+			chp->wdc->select(chp,drive);
+		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
+		    WDSD_IBM | (drive << 4));
+		delay(10);
+		/* Save registers contents */
+		sc = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_seccnt);
+		sn = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_sector);
+		cl = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo);
+		ch = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_hi);
+
+		WDCDEBUG_PRINT(("%s:%d:%d: after reset, sc=0x%x sn=0x%x "
+		    "cl=0x%x ch=0x%x\n",
+		    chp->wdc ? chp->wdc->sc_dev.dv_xname : "wdcprobe",
+	    	    chp->channel, drive, sc, sn, cl, ch), DEBUG_PROBE);
 		/*
-		 * Read status registers to avoid spurious interrupts.
+		 * sc & sn are supposted to be 0x1 for ATAPI but in some cases
+		 * we get wrong values here, so ignore it.
 		 */
-		for (i = 1; i >= 0; i--) {
-			if (chp->ch_drive[i].drive_flags & DRIVE) {
-				if (chp->wdc->cap & WDC_CAPABILITY_SELECT)
-					chp->wdc->select(chp,i);
-				bus_space_write_1(chp->cmd_iot, chp->cmd_ioh,
-				    wd_sdh, WDSD_IBM | (i << 4));
-				if (wait_for_unbusy(chp, 10000) < 0)
-					aprint_error("%s:%d:%d: device busy\n",
-					    chp->wdc->sc_dev.dv_xname,
-					    chp->channel, i);
-			}
+		if (cl == 0x14 && ch == 0xeb) {
+			chp->ch_drive[drive].drive_flags |= DRIVE_ATAPI;
+		} else {
+			chp->ch_drive[drive].drive_flags |= DRIVE_ATA;
+			if (chp->wdc == NULL ||
+			    (chp->wdc->cap & WDC_CAPABILITY_PREATA) != 0)
+				chp->ch_drive[drive].drive_flags |= DRIVE_OLD;
 		}
 	}
+	return (ret_value);	
+}
 
-out:
-	wdc_delref(chp);
+void
+wdcattach(chp)
+	struct channel_softc *chp;
+{
+	static int inited = 0;
+
+	/* initialise global data */
+	callout_init(&chp->ch_callout);
+	if (inited == 0) {
+		/* Initialize the wdc_xfer pool. */
+		pool_init(&wdc_xfer_pool, sizeof(struct wdc_xfer), 0,
+		    0, 0, "wdcspl", NULL);
+		inited++;
+	}
+	TAILQ_INIT(&chp->ch_queue->sc_xfer);
+	chp->ch_queue->queue_freese = 0;
+
+	config_found(&chp->wdc->sc_dev, chp, atabusprint);
 }
 
 /*
  * Call activate routine of underlying devices.
  */
 int
-wdcactivate(self, act)
+atabusactivate(self, act)
 	struct device *self;
 	enum devact act;
 {
-	struct wdc_softc *wdc = (struct wdc_softc *)self;
-	struct channel_softc *chp;
+	struct atabus_softc *atabus_sc = (struct atabus_softc *)self;
+	struct channel_softc *chp = atabus_sc->sc_chan;
 	struct device *sc = 0;
-	int s, i, j, error = 0;
+	int s, i, error = 0;
 
 	s = splbio();
 	switch (act) {
@@ -536,35 +710,31 @@
 		break;
 
 	case DVACT_DEACTIVATE:
-		for (i = 0; i < wdc->nchannels; i++) {
-			chp = wdc->channels[i];
+		/*
+		 * We might call deactivate routine for
+		 * the children of atapibus twice (once via
+		 * atapibus, once directly), but since
+		 * config_deactivate maintains DVF_ACTIVE flag,
+		 * it's safe.
+		 */
+		sc = chp->atapibus;
+		if (sc != NULL) {
+			error = config_deactivate(sc);
+			if (error != 0)
+				goto out;
+		}
 
-			/*
-			 * We might call deactivate routine for
-			 * the children of atapibus twice (once via
-			 * atapibus, once directly), but since
-			 * config_deactivate maintains DVF_ACTIVE flag,
-			 * it's safe.
-			 */
-			sc = chp->atapibus;
+		for (i = 0; i < 2; i++) {
+			sc = chp->ch_drive[i].drv_softc;
+			WDCDEBUG_PRINT(("atabusactivate: %s:"
+			    " deactivating %s\n", atabus_sc->sc_dev.dv_xname,
+			    sc == NULL ? "nodrv" : sc->dv_xname),
+			    DEBUG_DETACH);
 			if (sc != NULL) {
 				error = config_deactivate(sc);
 				if (error != 0)
 					goto out;
 			}
-
-			for (j = 0; j < 2; j++) {
-				sc = chp->ch_drive[j].drv_softc;
-				WDCDEBUG_PRINT(("wdcactivate: %s:"
-				    " deactivating %s\n", wdc->sc_dev.dv_xname,
-				    sc == NULL ? "nodrv" : sc->dv_xname),
-				    DEBUG_DETACH);
-				if (sc != NULL) {
-					error = config_deactivate(sc);
-					if (error != 0)
-						goto out;
-				}
-			}
 		}
 		break;
 	}
@@ -574,67 +744,117 @@
 
 #ifdef WDCDEBUG
 	if (sc && error != 0)
-		WDCDEBUG_PRINT(("wdcactivate: %s: error %d deactivating %s\n",
-		    wdc->sc_dev.dv_xname, error, sc->dv_xname), DEBUG_DETACH);
+		WDCDEBUG_PRINT(("atabusactivate: %s: "
+		    "error %d deactivating %s\n", atabus_sc->sc_dev.dv_xname,
+		    error, sc->dv_xname), DEBUG_DETACH);
 #endif
 	return (error);
 }
 
+int wdcactivate(self, act)
+	struct device *self;
+	enum devact act;
+{
+	struct wdc_softc *wdc = (struct wdc_softc *)self;
+	int s, i, error = 0;
+
+	s = splbio();
+	switch (act) {
+	case DVACT_ACTIVATE:
+		error = EOPNOTSUPP;
+		break;
+
+	case DVACT_DEACTIVATE:
+		for (i = 0; i < wdc->nchannels; i++) {
+			error = config_deactivate(wdc->channels[i]->atabus);
+			if (error)
+				break;
+		}
+		break;
+	}
+	splx(s);
+	return (error);
+}
+	
+
 int
-wdcdetach(self, flags)
+atabusdetach(self, flags)
 	struct device *self;
 	int flags;
 {
-	struct wdc_softc *wdc = (struct wdc_softc *)self;
-	struct channel_softc *chp;
+	struct atabus_softc *atabus_sc = (struct atabus_softc *)self;
+	struct channel_softc *chp = atabus_sc->sc_chan;
 	struct device *sc = 0;
-	int i, j, error = 0;
+	int i, error = 0;
 
-	for (i = 0; i < wdc->nchannels; i++) {
-		chp = wdc->channels[i];
+	/* shutdown channel */
+	chp->ch_flags |= WDCF_SHUTDOWN;
+	wakeup(&chp);
+	while (chp->thread != NULL)
+		tsleep(&chp->ch_flags, PRIBIO, "atadown", 0);
 
-		/*
-		 * Detach atapibus and its children.
-		 */
-		sc = chp->atapibus;
+	/*
+	 * Detach atapibus and its children.
+	 */
+	sc = chp->atapibus;
+	if (sc != NULL) {
+		WDCDEBUG_PRINT(("atabusdetach: %s: detaching %s\n",
+		    atabus_sc->sc_dev.dv_xname, sc->dv_xname), DEBUG_DETACH);
+		error = config_detach(sc, flags);
+		if (error != 0)
+			goto out;
+	}
+
+	/*
+	 * Detach our other children.
+	 */
+	for (i = 0; i < 2; i++) {
+		if (chp->ch_drive[i].drive_flags & DRIVE_ATAPI)
+			continue;
+		sc = chp->ch_drive[i].drv_softc;
+		WDCDEBUG_PRINT(("atabusdetach: %s: detaching %s\n",
+		    atabus_sc->sc_dev.dv_xname,
+		    sc == NULL ? "nodrv" : sc->dv_xname),
+		    DEBUG_DETACH);
 		if (sc != NULL) {
-			WDCDEBUG_PRINT(("wdcdetach: %s: detaching %s\n",
-			    wdc->sc_dev.dv_xname, sc->dv_xname), DEBUG_DETACH);
 			error = config_detach(sc, flags);
 			if (error != 0)
 				goto out;
 		}
-
-		/*
-		 * Detach our other children.
-		 */
-		for (j = 0; j < 2; j++) {
-			if (chp->ch_drive[j].drive_flags & DRIVE_ATAPI)
-				continue;
-			sc = chp->ch_drive[j].drv_softc;
-			WDCDEBUG_PRINT(("wdcdetach: %s: detaching %s\n",
-			    wdc->sc_dev.dv_xname,
-			    sc == NULL ? "nodrv" : sc->dv_xname),
-			    DEBUG_DETACH);
-			if (sc != NULL) {
-				error = config_detach(sc, flags);
-				if (error != 0)
-					goto out;
-			}
-		}
-
-		wdc_kill_pending(chp);
 	}
 
+	wdc_kill_pending(chp);
+
 out:
 #ifdef WDCDEBUG
 	if (sc && error != 0)
-		WDCDEBUG_PRINT(("wdcdetach: %s: error %d detaching %s\n",
-		    wdc->sc_dev.dv_xname, error, sc->dv_xname), DEBUG_DETACH);
+		WDCDEBUG_PRINT(("atabusdetach: %s: error %d detaching %s\n",
+		    atabus_sc->sc_dev.dv_xname, error, sc->dv_xname),
+		    DEBUG_DETACH);
 #endif
 	return (error);
 }
 
+int
+wdcdetach(self, flags)
+	struct device *self;
+	int flags;
+{
+	struct wdc_softc *wdc = (struct wdc_softc *)self;
+	struct channel_softc *chp;
+	int i, error = 0;
+
+	for (i = 0; i < wdc->nchannels; i++) {
+		chp = wdc->channels[i];
+		WDCDEBUG_PRINT(("wdcdetach: %s: detaching %s\n",
+		    wdc->sc_dev.dv_xname, chp->atabus->dv_xname), DEBUG_DETACH);
+		error = config_detach(chp->atabus, flags);
+		if (error)
+			break;
+	}
+	return (error);
+}
+
 /*
  * Start I/O on a controller, for the given channel.
  * The first xfer may be not for our channel if the channel queues
@@ -669,6 +889,9 @@
 	if ((chp->ch_flags & WDCF_ACTIVE) != 0 ) {
 		return; /* channel aleady active */
 	}
+	if ((chp->ch_flags & WDCF_TH_RESET) != 0) {
+		return; /* a channel reset is pending */
+	}
 #ifdef DIAGNOSTIC
 	if ((chp->ch_flags & WDCF_IRQ_WAIT) != 0)
 		panic("wdcstart: channel waiting for irq");
@@ -749,24 +972,31 @@
 }
 
 /* Put all disk in RESET state */
-void wdc_reset_channel(drvp)
+void wdc_reset_channel(drvp, flags)
 	struct ata_drive_datas *drvp;
+	int flags;
 {
 	struct channel_softc *chp = drvp->chnl_softc;
 	int drive;
 	WDCDEBUG_PRINT(("ata_reset_channel %s:%d for drive %d\n",
 	    chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive),
 	    DEBUG_FUNCS);
-	(void) wdcreset(chp, VERBOSE);
+	if ((chp->ch_flags & WDCF_TH_RUN) == 0 &&
+	    (flags & AT_POLL) == 0) {
+		chp->ch_flags |= WDCF_TH_RESET;
+		wakeup(&chp->thread);
+		return;
+	}
+	(void) wdcreset(chp, (flags & AT_POLL) ? RESET_POLL : RESET_SLEEP);
 	for (drive = 0; drive < 2; drive++) {
 		chp->ch_drive[drive].state = 0;
 	}
 }
 
 int
-wdcreset(chp, verb)
+wdcreset(chp, poll)
 	struct channel_softc *chp;
-	int verb;
+	int poll;
 {
 	int drv_mask1, drv_mask2;
 
@@ -786,8 +1016,9 @@
 
 	drv_mask1 = (chp->ch_drive[0].drive_flags & DRIVE) ? 0x01:0x00;
 	drv_mask1 |= (chp->ch_drive[1].drive_flags & DRIVE) ? 0x02:0x00;
-	drv_mask2 = __wdcwait_reset(chp, drv_mask1);
-	if (verb && drv_mask2 != drv_mask1) {
+	drv_mask2 = __wdcwait_reset(chp, drv_mask1,
+	    (poll == RESET_SLEEP) ? 0 : 1);
+	if (drv_mask2 != drv_mask1) {
 		printf("%s channel %d: reset failed for",
 		    chp->wdc->sc_dev.dv_xname, chp->channel);
 		if ((drv_mask1 & 0x01) != 0 && (drv_mask2 & 0x01) == 0)
@@ -800,18 +1031,23 @@
 }
 
 static int
-__wdcwait_reset(chp, drv_mask)
+__wdcwait_reset(chp, drv_mask, poll)
 	struct channel_softc *chp;
 	int drv_mask;
 {
-	int timeout;
+	int timeout, nloop;
 	u_int8_t st0, st1;
 #ifdef WDCDEBUG
 	u_int8_t sc0, sn0, cl0, ch0;
 	u_int8_t sc1, sn1, cl1, ch1;
 #endif
+
+	if (poll)
+		nloop = WDCNDELAY_RST;
+	else
+		nloop = WDC_RESET_WAIT * hz / 1000;
 	/* wait for BSY to deassert */
-	for (timeout = 0; timeout < WDCNDELAY_RST; timeout++) {
+	for (timeout = 0; timeout < nloop; timeout++) {
 		if (chp->wdc && chp->wdc->cap & WDC_CAPABILITY_SELECT)
 			chp->wdc->select(chp,0);
 		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
@@ -855,7 +1091,10 @@
 				goto end;
 			}
 		}
-		delay(WDCDELAY);
+		if (poll)
+			delay(WDCDELAY);
+		else
+			tsleep(&nloop, PRIBIO, "atarst", 1);
 	}
 	/* Reset timed out. Maybe it's because drv_mask was not right */
 	if (st0 & WDCS_BSY)
@@ -884,14 +1123,14 @@
  * return -1 for a timeout after "timeout" ms.
  */
 int
-wdcwait(chp, mask, bits, timeout)
+__wdcwait(chp, mask, bits, timeout)
 	struct channel_softc *chp;
 	int mask, bits, timeout;
 {
 	u_char status;
 	int time = 0;
 
-	WDCDEBUG_PRINT(("wdcwait %s:%d\n", chp->wdc ?chp->wdc->sc_dev.dv_xname
+	WDCDEBUG_PRINT(("__wdcwait %s:%d\n", chp->wdc ?chp->wdc->sc_dev.dv_xname
 	    :"none", chp->channel), DEBUG_STATUS);
 	chp->ch_error = 0;
 
@@ -903,19 +1142,19 @@
 		if ((status & WDCS_BSY) == 0 && (status & mask) == bits)
 			break;
 		if (++time > timeout) {
-			WDCDEBUG_PRINT(("wdcwait: timeout (time=%d), "
+			WDCDEBUG_PRINT(("__wdcwait: timeout (time=%d), "
 			    "status %x error %x (mask 0x%x bits 0x%x)\n",
 			    time, status,
 			    bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
 				wd_error), mask, bits),
 			    DEBUG_STATUS | DEBUG_PROBE | DEBUG_DELAY);
-			return -1;
+			return(WDCWAIT_TOUT);
 		}
 		delay(WDCDELAY);
 	}
 #ifdef WDCDEBUG
 	if (time > 0 && (wdcdebug_mask & DEBUG_DELAY))
-		printf("wdcwait: did busy-wait, time=%d\n", time);
+		printf("__wdcwait: did busy-wait, time=%d\n", time);
 #endif
 	if (status & WDCS_ERR)
 		chp->ch_error = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh,
@@ -935,9 +1174,52 @@
 			    WDCDELAY * time);
 	}
 #endif
-	return 0;
+	return(WDCWAIT_OK);
+}
+
+/*
+ * Call __wdcwait(), polling using tsleep() or waking up the kernel
+ * thread if possible
+ */
+int
+wdcwait(chp, mask, bits, timeout, flags)
+	struct channel_softc *chp;
+	int mask, bits, timeout, flags;
+{
+	int error, i, timwout_hz = mstohz(timeout);
+
+	if (timwout_hz == 0 || (flags & AT_POLL) != 0)
+		error = __wdcwait(chp, mask, bits, timeout);
+	else {
+		error = __wdcwait(chp, mask, bits, WDCDELAY_POLL);
+		if (error != 0) {
+			if (chp->ch_flags & WDCF_TH_RUN) {
+				/*
+				 * we're running in the channel thread context
+				 */
+				for (i = 0; i < timwout_hz; i++) {
+					if (__wdcwait(chp, mask, bits,
+					    WDCDELAY_POLL) == 0) {
+						error = 0;
+						break;
+					}
+					tsleep(&chp, PRIBIO, "atapoll", 1);
+				}
+			} else {
+				/*
+				 * we're probably in interrupt context,
+				 * ask the thread to come back here
+				 */
+				chp->ch_queue->queue_freese++;
+				wakeup(&chp->thread);
+				return(WDCWAIT_THR);
+			}
+		}
+	}
+	return(error);
 }
 
+
 /*
  * Busy-wait for DMA to complete
  */
@@ -1019,7 +1301,7 @@
 	char *sep = "";
 	int cf_flags;
 
-	if (ata_get_params(drvp, AT_POLL, &params) != CMD_OK) {
+	if (ata_get_params(drvp, AT_WAIT, &params) != CMD_OK) {
 		/* IDENTIFY failed. Can't tell more about the device */
 		return;
 	}
@@ -1031,7 +1313,7 @@
 		 * and compare results.
 		 */
 		drvp->drive_flags |= DRIVE_CAP32;
-		ata_get_params(drvp, AT_POLL, &params2);
+		ata_get_params(drvp, AT_WAIT, &params2);
 		if (memcmp(&params, &params2, sizeof(struct ataparams)) != 0) {
 			/* Not good. fall back to 16bits */
 			drvp->drive_flags &= ~DRIVE_CAP32;
@@ -1089,6 +1371,10 @@
 			 * to set it
 			 */
 			if ((wdc->cap & WDC_CAPABILITY_MODE) != 0)
+				/*
+				 * It's OK to pool here, it's fast enouth
+				 * to not bother waiting for interrupt
+				 */
 				if (ata_set_mode(drvp, 0x08 | (i + 3),
 				   AT_POLL) != CMD_OK)
 					continue;
@@ -1228,7 +1514,7 @@
  * downgrade was possible, 0 otherwise.
  */
 int
-wdc_downgrade_mode(drvp)
+wdc_downgrade_mode(drvp, flags)
 	struct ata_drive_datas *drvp;
 {
 	struct channel_softc *chp = drvp->chnl_softc;
@@ -1281,7 +1567,7 @@
 
 	wdc->set_modes(chp);
 	/* reset the channel, which will shedule all drives for setup */
-	wdc_reset_channel(drvp);
+	wdc_reset_channel(drvp, flags);
 	return 1;
 }
 
@@ -1357,11 +1643,16 @@
 
 	bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
 	    WDSD_IBM | (drive << 4));
-	if (wdcwait(chp, wdc_c->r_st_bmask | WDCS_DRQ, wdc_c->r_st_bmask,
-	    wdc_c->timeout) != 0) {
+	switch(wdcwait(chp, wdc_c->r_st_bmask | WDCS_DRQ,
+	    wdc_c->r_st_bmask, wdc_c->timeout, wdc_c->flags)) {
+	case WDCWAIT_OK:
+		break;
+	case WDCWAIT_TOUT:
 		wdc_c->flags |= AT_TIMEOU;
 		__wdccommand_done(chp, xfer);
 		return;
+	case WDCWAIT_THR:
+		return;
 	}
 	wdccommand(chp, drive, wdc_c->r_command, wdc_c->r_cyl, wdc_c->r_head,
 	    wdc_c->r_sector, wdc_c->r_count, wdc_c->r_precomp);
@@ -1392,13 +1683,22 @@
 again:
 	WDCDEBUG_PRINT(("__wdccommand_intr %s:%d:%d\n",
 	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive), DEBUG_INTR);
+	/*
+	 * after a ATAPI_SOFT_RESET, the device will have released the bus.
+	 * Reselect again, it doesn't hurt for others commands, and the time
+	 * penalty for the extra regiter write is acceptable,
+	 * wdc_exec_command() isn't called often (mosly for autoconfig)
+	 */
+	bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
+	    WDSD_IBM | (xfer->drive << 4));
 	if ((wdc_c->flags & AT_XFDONE) != 0) {
 		/*
 		 * We have completed a data xfer. The drive should now be
 		 * in its initial state
 		 */
 		if (wdcwait(chp, wdc_c->r_st_bmask | WDCS_DRQ,
-		    wdc_c->r_st_bmask, (irq == 0)  ? wdc_c->timeout : 0) != 0) {
+		    wdc_c->r_st_bmask, (irq == 0)  ? wdc_c->timeout : 0,
+		    AT_POLL) ==  WDCWAIT_TOUT) {
 			if (irq && (xfer->c_flags & C_TIMEOU) == 0) 
 				return 0; /* IRQ was not for us */
 			wdc_c->flags |= AT_TIMEOU;
@@ -1410,7 +1710,7 @@
 		return 1;
 	}
 	if (wdcwait(chp, wdc_c->r_st_pmask, wdc_c->r_st_pmask,
-	     (irq == 0)  ? wdc_c->timeout : 0)) {
+	     (irq == 0)  ? wdc_c->timeout : 0, AT_POLL) == WDCWAIT_TOUT) {
 		if (irq && (xfer->c_flags & C_TIMEOU) == 0) 
 			return 0; /* IRQ was not for us */
 		wdc_c->flags |= AT_TIMEOU;
@@ -1432,7 +1732,7 @@
 		/* at this point the drive should be in its initial state */
 		wdc_c->flags |= AT_XFDONE;
 		if (wdcwait(chp, wdc_c->r_st_bmask | WDCS_DRQ,
-		    wdc_c->r_st_bmask, 100) != 0)
+		    wdc_c->r_st_bmask, 100, AT_POLL) == WDCWAIT_TOUT)
 			wdc_c->flags |= AT_TIMEOU;
 	} else if (wdc_c->flags & AT_WRITE) {
 		if (chp->ch_drive[xfer->drive].drive_flags & DRIVE_CAP32) {
Index: dev/ic/wdcvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wdcvar.h,v
retrieving revision 1.36
diff -u -r1.36 wdcvar.h
--- dev/ic/wdcvar.h	2003/04/28 05:20:30	1.36
+++ dev/ic/wdcvar.h	2003/09/19 20:26:54
@@ -47,6 +47,7 @@
 
 struct channel_queue {  /* per channel queue (may be shared) */
 	TAILQ_HEAD(xferhead, wdc_xfer) sc_xfer;
+	int queue_freese;
 };
 
 struct channel_softc { /* Per channel data */
@@ -67,25 +68,36 @@
 	/* Our state */
 	int ch_flags;
 #define WDCF_ACTIVE   0x01	/* channel is active */
+#define WDCF_SHUTDOWN 0x02	/* channel is shutting down */
 #define WDCF_IRQ_WAIT 0x10	/* controller is waiting for irq */
 #define WDCF_DMA_WAIT 0x20	/* controller is waiting for DMA */
+#define WDCF_TH_RUN   0x100	/* the kenrel thread is working */
+#define WDCF_TH_RESET 0x200	/* someone ask the thread to reset */
 	u_int8_t ch_status;         /* copy of status register */
 	u_int8_t ch_error;          /* copy of error register */
 	/* per-drive infos */
 	struct ata_drive_datas ch_drive[2];
 
-	struct device *atapibus;
+	struct device *atabus;	/* self */
+	struct device *atapibus; /* children */
 	struct scsipi_channel ch_atapi_channel;
 
-	struct device *ata_drives[2];
+	struct device *ata_drives[2]; /* children */
 
 	/*
 	 * channel queues. May be the same for all channels, if hw channels
 	 * are not independants
 	 */
 	struct channel_queue *ch_queue;
+	/* the channel kenrel thread */
+	struct proc *thread;
 };
 
+struct atabus_softc { /* the atabus softc */
+	struct device sc_dev;
+	struct channel_softc *sc_chan;
+};
+
 struct wdc_softc { /* Per controller state */
 	struct device sc_dev;
 	/* mandatory fields */
@@ -156,8 +168,6 @@
 #define C_TIMEOU  	0x0002 /* xfer processing timed out */
 #define C_POLL		0x0004 /* cmd is polled */
 #define C_DMA		0x0008 /* cmd uses DMA */
-#define C_SENSE		0x0010 /* cmd is a internal command */
-#define	C_FORCEPIO	0x0020 /* cmd must use PIO */
 
 	/* Informations about our location */
 	struct channel_softc *chp;
@@ -193,9 +203,12 @@
 void  wdcstart __P((struct channel_softc *));
 void  wdcrestart __P((void*));
 int   wdcreset	__P((struct channel_softc *, int));
-#define VERBOSE 1 
-#define SILENT 0 /* wdcreset will not print errors */
-int   wdcwait __P((struct channel_softc *, int, int, int));
+#define RESET_POLL 1 
+#define RESET_SLEEP 0 /* wdcreset will use tsleep() */
+int   wdcwait __P((struct channel_softc *, int, int, int, int));
+#define WDCWAIT_OK	0  /* we have what we asked */
+#define WDCWAIT_TOUT	-1 /* timed out */
+#define WDCWAIT_THR	1  /* return, the kernel thread has been awakened */
 int   wdc_dmawait __P((struct channel_softc *, struct wdc_xfer *, int));
 void  wdcbit_bucket __P(( struct channel_softc *, int));
 void  wdccommand __P((struct channel_softc *, u_int8_t, u_int8_t, u_int16_t,
@@ -204,7 +217,7 @@
     u_int16_t));
 void   wdccommandshort __P((struct channel_softc *, int, int));
 void  wdctimeout	__P((void *arg));
-void wdc_reset_channel __P((struct ata_drive_datas *));
+void wdc_reset_channel __P((struct ata_drive_datas *, int));
 int wdc_exec_command __P((struct ata_drive_datas *, struct wdc_command*));
 #define WDC_COMPLETE 0x01
 #define WDC_QUEUED   0x02
@@ -221,11 +234,13 @@
  * ST506 spec says that if READY or SEEKCMPLT go off, then the read or write
  * command is aborted.
  */   
-#define wait_for_drq(chp, timeout) wdcwait((chp), WDCS_DRQ, WDCS_DRQ, (timeout))
-#define wait_for_unbusy(chp, timeout)	wdcwait((chp), 0, 0, (timeout))
-#define wait_for_ready(chp, timeout) wdcwait((chp), WDCS_DRDY, \
-	WDCS_DRDY, (timeout))
+#define wait_for_drq(chp, timeout, flags) \
+		wdcwait((chp), WDCS_DRQ, WDCS_DRQ, (timeout), (flags))
+#define wait_for_unbusy(chp, timeout, flags) \
+		wdcwait((chp), 0, 0, (timeout), (flags))
+#define wait_for_ready(chp, timeout, flags) \
+		wdcwait((chp), WDCS_DRDY, WDCS_DRDY, (timeout), (flags))
 /* ATA/ATAPI specs says a device can take 31s to reset */
 #define WDC_RESET_WAIT 31000
 
-void wdc_atapibus_attach __P((struct channel_softc *));
+void wdc_atapibus_attach __P((struct atabus_softc *));
Index: dev/pci/files.pci
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/files.pci,v
retrieving revision 1.192
diff -u -r1.192 files.pci
--- dev/pci/files.pci	2003/09/08 18:59:48	1.192
+++ dev/pci/files.pci	2003/09/19 20:26:54
@@ -191,7 +191,7 @@
 #file	dev/pci/sf64pcr.c		sf4r
 
 # PCI IDE controllers
-device	pciide {[channel = -1]}: cy82c693, wdc_base, ata, atapi
+device	pciide {[channel = -1]}: cy82c693, wdc_base
 attach	pciide at pci
 file	dev/pci/pciide.c		pciide
 
Index: dev/pci/pciide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pciide.c,v
retrieving revision 1.196
diff -u -r1.196 pciide.c
--- dev/pci/pciide.c	2003/08/17 15:52:06	1.196
+++ dev/pci/pciide.c	2003/09/19 20:26:54
@@ -719,7 +719,6 @@
 void	pciide_mapchan __P((struct pci_attach_args *,
 	    struct pciide_channel *, pcireg_t, bus_size_t *, bus_size_t *,
 	    int (*pci_intr) __P((void *))));
-int	pciide_chan_candisable __P((struct pciide_channel *));
 void	pciide_map_compat_intr __P(( struct pci_attach_args *,
 	    struct pciide_channel *, int, int));
 int	pciide_compat_intr __P((void *));
@@ -1394,27 +1393,6 @@
 }
 
 /*
- * Generic code to call to know if a channel can be disabled. Return 1
- * if channel can be disabled, 0 if not
- */
-int
-pciide_chan_candisable(cp)
-	struct pciide_channel *cp;
-{
-	struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
-	struct channel_softc *wdc_cp = &cp->wdc_channel;
-
-	if ((wdc_cp->ch_drive[0].drive_flags & DRIVE) == 0 &&
-	    (wdc_cp->ch_drive[1].drive_flags & DRIVE) == 0) {
-		aprint_normal("%s: disabling %s channel (no drives)\n",
-		    sc->sc_wdcdev.sc_dev.dv_xname, cp->name);
-		cp->hw_ok = 0;
-		return 1;
-	}
-	return 0;
-}
-
-/*
  * generic code to map the compat intr if hw_ok=1 and it is a compat channel.
  * Set hw_ok=0 on failure
  */
@@ -1517,6 +1495,15 @@
 		 * Check to see if something appears to be there.
 		 */
 		failreason = NULL;
+		/*
+		 * In native mode, always enable the controller. It's
+		 * not possible to have an ISA board using the same address
+		 * anyway.
+		 */
+#if 0
+		if (interface & PCIIDE_INTERFACE_PCI(channel))
+			goto next;
+#endif
 		if (!wdcprobe(&cp->wdc_channel)) {
 			failreason = "not responding; disabled or no drives?";
 			goto next;
@@ -1747,16 +1734,9 @@
 		pciide_mapchan(pa, cp, 0, &cmdsize, &ctlsize, pciide_pci_intr);
 		if (cp->hw_ok == 0)
 			continue;
-		if (pciide_chan_candisable(cp)) {
-			idetim = PIIX_IDETIM_CLEAR(idetim, PIIX_IDETIM_IDE,
-			    channel);
-			pci_conf_write(sc->sc_pc, sc->sc_tag, PIIX_IDETIM,
-			    idetim);
-		}
 		pciide_map_compat_intr(pa, cp, channel, 0);
 		if (cp->hw_ok == 0)
 			continue;
-		sc->sc_wdcdev.set_modes(&cp->wdc_channel);
 	}
 
 	WDCDEBUG_PRINT(("piix_setup_chip: idetim=0x%x",
@@ -2197,13 +2177,10 @@
 		pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize,
 		    pciide_pci_intr);
 
-		if (pciide_chan_candisable(cp))
-			chanenable &= ~AMD7X6_CHAN_EN(channel);
 		pciide_map_compat_intr(pa, cp, channel, interface);
 		if (cp->hw_ok == 0)
 			continue;
 
-		amd7x6_setup_channel(&cp->wdc_channel);
 	}
 	pci_conf_write(sc->sc_pc, sc->sc_tag, AMD7X6_CHANSTATUS_EN(sc),
 	    chanenable);
@@ -2431,16 +2408,10 @@
 		    pciide_pci_intr);
 		if (cp->hw_ok == 0)
 			continue;
-		if (pciide_chan_candisable(cp)) {
-			ideconf &= ~APO_IDECONF_EN(channel);
-			pci_conf_write(sc->sc_pc, sc->sc_tag, APO_IDECONF,
-			    ideconf);
-		}
 		pciide_map_compat_intr(pa, cp, channel, interface);
 
 		if (cp->hw_ok == 0)
 			continue;
-		apollo_setup_channel(&sc->pciide_channels[channel].wdc_channel);
 	}
 	WDCDEBUG_PRINT(("apollo_chip_map: APO_DATATIM=0x%x, APO_UDMA=0x%x\n",
 	    pci_conf_read(sc->sc_pc, sc->sc_tag, APO_DATATIM),
@@ -2619,13 +2590,6 @@
 	pciide_mapchan(pa, cp, interface, &cmdsize, &ctlsize, cmd_pci_intr);
 	if (cp->hw_ok == 0)
 		return;
-	if (channel == 1) {
-		if (pciide_chan_candisable(cp)) {
-			ctrl &= ~CMD_CTRL_2PORT;
-			pciide_pci_write(pa->pa_pc, pa->pa_tag,
-			    CMD_CTRL, ctrl);
-		}
-	}
 	pciide_map_compat_intr(pa, cp, channel, interface);
 }
 
@@ -2781,7 +2745,6 @@
 		cmd_channel_map(pa, sc, channel);
 		if (cp->hw_ok == 0)
 			continue;
-		cmd0643_9_setup_channel(&cp->wdc_channel);
 	}
 	/*
 	 * note - this also makes sure we clear the irq disable and reset
@@ -2931,7 +2894,6 @@
 		cmd680_channel_map(pa, sc, channel);
 		if (cp->hw_ok == 0)
 			continue;
-		cmd680_setup_channel(&cp->wdc_channel);
 	}
 }
 
@@ -3133,7 +3095,6 @@
 		if (cp->hw_ok == 0)
 			continue;
 		pciide_map_compat_intr(pa, cp, channel, interface);
-		cmd3112_setup_channel(&cp->wdc_channel);
 	}
 }
 
@@ -3274,18 +3235,9 @@
 	cp->wdc_channel.data32iot = cp->wdc_channel.cmd_iot;
 	cp->wdc_channel.data32ioh = cp->wdc_channel.cmd_ioh;
 	wdcattach(&cp->wdc_channel);
-	if (pciide_chan_candisable(cp)) {
-		pci_conf_write(sc->sc_pc, sc->sc_tag,
-		    PCI_COMMAND_STATUS_REG, 0);
-	}
 	pciide_map_compat_intr(pa, cp, sc->sc_cy_compatchan, interface);
 	if (cp->hw_ok == 0)
 		return;
-	WDCDEBUG_PRINT(("cy693_chip_map: old timings reg 0x%x\n",
-	    pci_conf_read(sc->sc_pc, sc->sc_tag, CY_CMD_CTRL)),DEBUG_PROBE);
-	cy693_setup_channel(&cp->wdc_channel);
-	WDCDEBUG_PRINT(("cy693_chip_map: new timings reg 0x%x\n",
-	    pci_conf_read(sc->sc_pc, sc->sc_tag, CY_CMD_CTRL)), DEBUG_PROBE);
 }
 
 void
@@ -3300,6 +3252,9 @@
 	struct pciide_softc *sc = (struct pciide_softc *)cp->wdc_channel.wdc;
 	int dma_mode = -1;
 
+	WDCDEBUG_PRINT(("cy693_chip_map: old timings reg 0x%x\n",
+	    pci_conf_read(sc->sc_pc, sc->sc_tag, CY_CMD_CTRL)),DEBUG_PROBE);
+
 	cy_cmd_ctrl = idedma_ctl = 0;
 
 	/* setup DMA if needed */
@@ -3347,6 +3302,8 @@
 		bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh,
 		    IDEDMA_CTL, idedma_ctl);
 	}
+	WDCDEBUG_PRINT(("cy693_chip_map: new timings reg 0x%x\n",
+	    pci_conf_read(sc->sc_pc, sc->sc_tag, CY_CMD_CTRL)), DEBUG_PROBE);
 }
 
 static struct sis_hostbr_type {
@@ -3550,18 +3507,9 @@
 		    pciide_pci_intr);
 		if (cp->hw_ok == 0)
 			continue;
-		if (pciide_chan_candisable(cp)) {
-			if (channel == 0)
-				sis_ctr0 &= ~SIS_CTRL0_CHAN0_EN;
-			else
-				sis_ctr0 &= ~SIS_CTRL0_CHAN1_EN;
-			pciide_pci_write(sc->sc_pc, sc->sc_tag, SIS_CTRL0,
-			    sis_ctr0);
-		}
 		pciide_map_compat_intr(pa, cp, channel, interface);
 		if (cp->hw_ok == 0)
 			continue;
-		sc->sc_wdcdev.set_modes(&cp->wdc_channel);
 	}
 }
 
@@ -3818,13 +3766,7 @@
 		     (rev >= 0xC2) ? pciide_pci_intr : acer_pci_intr);
 		if (cp->hw_ok == 0)
 			continue;
-		if (pciide_chan_candisable(cp)) {
-			cr &= ~(PCIIDE_CHAN_EN(channel) << PCI_INTERFACE_SHIFT);
-			pci_conf_write(sc->sc_pc, sc->sc_tag,
-			    PCI_CLASS_REG, cr);
-		}
 		pciide_map_compat_intr(pa, cp, channel, interface);
-		acer_setup_channel(&cp->wdc_channel);
 	}
 }
 
@@ -4076,7 +4018,6 @@
 		cp->wdc_channel.data32iot = cp->wdc_channel.cmd_iot;
 		cp->wdc_channel.data32ioh = cp->wdc_channel.cmd_ioh;
 		wdcattach(&cp->wdc_channel);
-		hpt_setup_channel(&cp->wdc_channel);
 	}
 	if ((sc->sc_pp->ide_product == PCI_PRODUCT_TRIONES_HPT366 &&
 	    (revision == HPT370_REV || revision == HPT370A_REV ||
@@ -4449,11 +4390,7 @@
 			    pdc202xx_pci_intr);
 		if (cp->hw_ok == 0)
 			continue;
-		if (!PDC_IS_268(sc) && pciide_chan_candisable(cp))
-			st &= ~(PDC_IS_262(sc) ?
-			    PDC262_STATE_EN(channel):PDC246_STATE_EN(channel));
 		pciide_map_compat_intr(pa, cp, channel, interface);
-		sc->sc_wdcdev.set_modes(&cp->wdc_channel);
 	}
 	if (!PDC_IS_268(sc)) {
 		WDCDEBUG_PRINT(("pdc202xx_setup_chip: new controller state "
@@ -4579,6 +4516,7 @@
 		    idedma_ctl);
 	}
 	pciide_print_modes(cp);
+	pci_conf_print(sc->sc_pc, sc->sc_tag, NULL);
 }
 
 void
@@ -4631,6 +4569,7 @@
 		    idedma_ctl);
 	}
 	pciide_print_modes(cp);
+	pci_conf_print(sc->sc_pc, sc->sc_tag, NULL);
 }
 
 int
@@ -4680,6 +4619,11 @@
 		/* If a compat channel skip. */
 		if (cp->compat)
 			continue;
+#if 0
+		bus_space_write_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CMD + 0x1 + IDEDMA_SCH_OFFSET * i, 0x0b);
+		if ((bus_space_read_1(sc->sc_dma_iot, sc->sc_dma_ioh, IDEDMA_CMD + 0x3 + IDEDMA_SCH_OFFSET * i) & 0x20) == 0)
+			continue;
+#endif
 		/*
 		 * The Ultra/100 seems to assert PDC2xx_SCR_INT * spuriously,
 		 * however it asserts INT in IDEDMA_CTL even for non-DMA ops.
@@ -4822,7 +4766,6 @@
 		pciide_map_compat_intr(pa, cp, channel, interface);
 		if (cp->hw_ok == 0)
 			continue;
-		opti_setup_channel(&cp->wdc_channel);
 	}
 }
 
@@ -4990,7 +4933,6 @@
 		cp->wdc_channel.data32iot = cp->wdc_channel.cmd_iot;
 		cp->wdc_channel.data32ioh = cp->wdc_channel.cmd_ioh;
 		wdcattach(&cp->wdc_channel);
-		acard_setup_channel(&cp->wdc_channel);
 	}
 	if (!ACARD_IS_850(sc)) {
 		u_int32_t reg;
@@ -5223,7 +5165,6 @@
 		pciide_map_compat_intr(pa, cp, channel, interface);
 		if (cp->hw_ok == 0)
 			continue;
-		sl82c105_setup_channel(&cp->wdc_channel);
 	}
 }
 
@@ -5358,7 +5299,6 @@
 		pciide_map_compat_intr(pa, cp, channel, interface);
 		if (cp->hw_ok == 0)
 			return;
-		serverworks_setup_channel(&cp->wdc_channel);
 	}
 
 	pcib_tag = pci_make_tag(pa->pa_pc, pa->pa_bus, pa->pa_device, 0);
@@ -5526,6 +5466,5 @@
 		if (cp->hw_ok == 0)
 			continue;
 		pciide_map_compat_intr(pa, cp, channel, interface);
-		sata_setup_channel(&cp->wdc_channel);
 	}
 }
Index: dev/pcmcia/wdc_pcmcia.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pcmcia/wdc_pcmcia.c,v
retrieving revision 1.55
diff -u -r1.55 wdc_pcmcia.c
--- dev/pcmcia/wdc_pcmcia.c	2003/03/30 02:06:29	1.55
+++ dev/pcmcia/wdc_pcmcia.c	2003/09/19 20:26:54
@@ -461,7 +461,7 @@
 				pcmcia_intr_disestablish(sc->sc_pf, sc->sc_ih);
 				return (EIO);
 			}
-			wdcreset(&sc->wdc_channel, VERBOSE);
+			wdcreset(&sc->wdc_channel, RESET_POLL);
 		}
 	} else {
 		pcmcia_function_disable(sc->sc_pf);
Index: dev/scsipi/atapi_wdc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/atapi_wdc.c,v
retrieving revision 1.56
diff -u -r1.56 atapi_wdc.c
--- dev/scsipi/atapi_wdc.c	2003/09/07 22:11:22	1.56
+++ dev/scsipi/atapi_wdc.c	2003/09/19 20:26:54
@@ -82,21 +82,20 @@
 #endif
 
 #define ATAPI_DELAY 10	/* 10 ms, this is used only before sending a cmd */
-int   wdc_atapi_get_params __P((struct scsipi_channel *, int, int,
+int   wdc_atapi_get_params __P((struct scsipi_channel *, int,
 				struct ataparams *));
 void  wdc_atapi_probe_device __P((struct atapibus_softc *, int));
 void  wdc_atapi_minphys  __P((struct buf *bp));
 void  wdc_atapi_start	__P((struct channel_softc *,struct wdc_xfer *));
 int   wdc_atapi_intr	 __P((struct channel_softc *, struct wdc_xfer *, int));
 void  wdc_atapi_kill_xfer __P((struct channel_softc *, struct wdc_xfer *));
-int   wdc_atapi_ctrl	 __P((struct channel_softc *, struct wdc_xfer *, int));
 void  wdc_atapi_phase_complete __P((struct wdc_xfer *));
 void  wdc_atapi_done	 __P((struct channel_softc *, struct wdc_xfer *));
 void  wdc_atapi_reset	 __P((struct channel_softc *, struct wdc_xfer *));
 void  wdc_atapi_scsipi_request __P((struct scsipi_channel *,
 	scsipi_adapter_req_t, void *));
 void  wdc_atapi_kill_pending __P((struct scsipi_periph *));
-void  wdc_atapi_polldsc __P((void *arg));
+static void  wdc_atapi_polldsc __P((void *arg));
 
 #define MAX_SIZE MAXPHYS
 
@@ -109,9 +108,10 @@
 };
 
 void
-wdc_atapibus_attach(chp)
-	struct channel_softc *chp;
+wdc_atapibus_attach(ata_sc)
+	struct atabus_softc *ata_sc;
 {
+	struct channel_softc *chp = ata_sc->sc_chan;
 	struct wdc_softc *wdc = chp->wdc;
 	struct scsipi_adapter *adapt = &wdc->sc_atapi_adapter._generic;
 	struct scsipi_channel *chan = &chp->ch_atapi_channel;
@@ -140,7 +140,7 @@
 	chan->chan_ntargets = 2;
 	chan->chan_nluns = 1;
 
-	chp->atapibus = config_found(&wdc->sc_dev, chan, atapiprint);
+	chp->atapibus = config_found(&ata_sc->sc_dev, chan, atapiprint);
 }
 
 void
@@ -185,9 +185,9 @@
 }
 
 int
-wdc_atapi_get_params(chan, drive, flags, id)
+wdc_atapi_get_params(chan, drive, id)
 	struct scsipi_channel *chan;
-	int drive, flags;
+	int drive;
 	struct ataparams *id;
 {
 	struct wdc_softc *wdc = (void *)chan->chan_adapter->adapt_dev;
@@ -195,10 +195,6 @@
 	struct wdc_command wdc_c;
 
 	/* if no ATAPI device detected at wdc attach time, skip */
-	/*
-	 * XXX this will break scsireprobe if this is of any interest for
-	 * ATAPI devices one day.
-	 */
 	if ((chp->ch_drive[drive].drive_flags & DRIVE_ATAPI) == 0) {
 		WDCDEBUG_PRINT(("wdc_atapi_get_params: drive %d not present\n",
 		    drive), DEBUG_PROBE);
@@ -229,7 +225,7 @@
 	
 	/* Some ATAPI devices need a bit more time after software reset. */
 	delay(5000);
-	if (ata_get_params(&chp->ch_drive[drive], AT_POLL, id) != 0) {
+	if (ata_get_params(&chp->ch_drive[drive], AT_WAIT, id) != 0) {
 		WDCDEBUG_PRINT(("wdc_atapi_get_params: ATAPI_IDENTIFY_DEVICE "
 		    "failed for drive %s:%d:%d: error 0x%x\n",
 		    chp->wdc->sc_dev.dv_xname, chp->channel, drive, 
@@ -258,8 +254,7 @@
 	if (scsipi_lookup_periph(chan, target, 0) != NULL)
 		return;
 
-	if (wdc_atapi_get_params(chan, target,
-	    XS_CTL_POLL|XS_CTL_NOSLEEP, id) == 0) {
+	if (wdc_atapi_get_params(chan, target, id) == 0) {
 #ifdef ATAPI_DEBUG_PROBE
 		printf("%s drive %d: cmdsz 0x%x drqtype 0x%x\n",
 		    sc->sc_dev.dv_xname, target,
@@ -353,6 +348,9 @@
 
 		if (sc_xfer->xs_control & XS_CTL_POLL)
 			xfer->c_flags |= C_POLL;
+		if ((wdc->channels[channel]->ch_drive[drive].drive_flags &
+		    (DRIVE_DMA | DRIVE_UDMA)) && sc_xfer->datalen > 0)
+			xfer->c_flags |= C_DMA;
 		xfer->drive = drive;
 		xfer->c_flags |= C_ATAPI;
 		if (sc_xfer->cmd->opcode == GPCMD_REPORT_KEY ||
@@ -362,7 +360,7 @@
 			 * DVD authentication commands must always be done in
 			 * PIO mode.
 			 */
-			xfer->c_flags |= C_FORCEPIO;
+			xfer->c_flags &= ~C_DMA;
 		}
 		/*
 		 * DMA can't deal with transfers which are not a multiple of
@@ -373,7 +371,7 @@
 		 * 4 bytes.
 		 */
 		if (sc_xfer->datalen < 4 || (sc_xfer->datalen & 0x01))
-			xfer->c_flags |= C_FORCEPIO;
+			xfer->c_flags &= ~C_DMA;
 
 		xfer->cmd = sc_xfer;
 		xfer->databuf = sc_xfer->data;
@@ -406,43 +404,101 @@
 {
 	struct scsipi_xfer *sc_xfer = xfer->cmd;
 	struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
+	int wait_flags = (sc_xfer->xs_control & XS_CTL_POLL) ? AT_POLL : 0;
+	char *errstring;
 
 	WDCDEBUG_PRINT(("wdc_atapi_start %s:%d:%d, scsi flags 0x%x \n",
 	    chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive,
 	    sc_xfer->xs_control), DEBUG_XFERS);
-	/* Adjust C_DMA, it may have changed if we are requesting sense */
-	if ((drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) &&
-	    sc_xfer->datalen > 0 && !(xfer->c_flags & C_FORCEPIO)) {
-		if (drvp->n_xfers <= NXFER)
-			drvp->n_xfers++;
-		xfer->c_flags |= C_DMA;
-	} else {
-		xfer->c_flags &= ~C_DMA;
+	if ((xfer->c_flags & C_DMA) && (drvp->n_xfers <= NXFER))
+		drvp->n_xfers++;
+	/* Do control operations specially. */
+	if (__predict_false(drvp->state < READY)) {
+		/* If it's not a polled command, we need the kenrel thread */
+		if ((sc_xfer->xs_control & XS_CTL_POLL) == 0 &&
+		    (chp->ch_flags & WDCF_TH_RUN) == 0) {
+			chp->ch_queue->queue_freese++;
+			wakeup(&chp->thread);
+			return;
+		}
+		/*
+		 * disable interrupts, all commands here should be quick
+		 * enouth to be able to poll, and we don't go here that often
+		 */
+		 bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
+		     WDCTL_4BIT | WDCTL_IDS);
+		bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
+		    WDSD_IBM | (xfer->drive << 4));
+		/* Don't try to set mode if controller can't be adjusted */
+		if ((chp->wdc->cap & WDC_CAPABILITY_MODE) == 0)
+			goto ready;
+		/* Also don't try if the drive didn't report its mode */
+		if ((drvp->drive_flags & DRIVE_MODE) == 0)
+			goto ready;
+		errstring = "unbusy";
+		if (wait_for_unbusy(chp, ATAPI_DELAY, wait_flags))
+			goto timeout;
+		wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+		    0x08 | drvp->PIO_mode, WDSF_SET_MODE);
+		errstring = "piomode";
+		if (wait_for_unbusy(chp, ATAPI_DELAY, wait_flags))
+			goto timeout;
+		if (chp->ch_status & WDCS_ERR) {
+			if (chp->ch_error == WDCE_ABRT) {
+				/*
+				 * some ATAPI drives rejects pio settings.
+				 * all we can do here is fall back to PIO 0
+				 */
+				drvp->drive_flags &= ~DRIVE_MODE;
+				drvp->drive_flags &= ~(DRIVE_DMA|DRIVE_UDMA);
+				drvp->PIO_mode = 0;
+				drvp->DMA_mode = 0;
+				printf("%s:%d:%d: pio setting rejected, "
+				    "falling back to PIO mode 0\n",
+				    chp->wdc->sc_dev.dv_xname,
+				    chp->channel, xfer->drive);
+				chp->wdc->set_modes(chp);
+				goto ready;
+			}
+			goto error;
+		}
+		if (drvp->drive_flags & DRIVE_UDMA) {
+			wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+			    0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
+		} else if (drvp->drive_flags & DRIVE_DMA) {
+			wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
+			    0x20 | drvp->DMA_mode, WDSF_SET_MODE);
+		} else {
+			goto ready;
+		}
+		errstring = "dmamode";
+		if (wait_for_unbusy(chp, ATAPI_DELAY, wait_flags))
+			goto timeout;
+		if (chp->ch_status & WDCS_ERR)
+			goto error;
+ready:
+		drvp->state = READY;
+		bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr,
+		    WDCTL_4BIT);
 	}
 	/* start timeout machinery */
 	if ((sc_xfer->xs_control & XS_CTL_POLL) == 0)
 		callout_reset(&chp->ch_callout, mstohz(sc_xfer->timeout),
 		    wdctimeout, chp);
-	/* Do control operations specially. */
-	if (drvp->state < READY) {
-		if (drvp->state != RESET) {
-			printf("%s:%d:%d: bad state %d in wdc_atapi_start\n",
-			    chp->wdc->sc_dev.dv_xname, chp->channel,
-			    xfer->drive, drvp->state);
-			panic("wdc_atapi_start: bad state");
-		}
-		drvp->state = PIOMODE;
-		wdc_atapi_ctrl(chp, xfer, 0);
-		return;
-	}
+
 	bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
 	    WDSD_IBM | (xfer->drive << 4));
-	if (wait_for_unbusy(chp, ATAPI_DELAY) < 0) {
+	switch (wait_for_unbusy(chp, ATAPI_DELAY, wait_flags)  < 0) {
+	case WDCWAIT_OK:
+		break;
+	case WDCWAIT_TOUT:
 		printf("wdc_atapi_start: not ready, st = %02x\n",
 		    chp->ch_status);
 		sc_xfer->error = XS_TIMEOUT;
 		wdc_atapi_reset(chp, xfer);
 		return;
+	case WDCWAIT_THR:
+		return;
 	}
 
 	/*
@@ -483,6 +539,24 @@
 			wdc_atapi_intr(chp, xfer, 0);
 		}
 	}
+	return;
+timeout:
+	printf("%s:%d:%d: %s timed out\n",
+	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, errstring);
+	sc_xfer->error = XS_TIMEOUT;
+	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
+	wdc_atapi_reset(chp, xfer);
+	return;
+error:
+	printf("%s:%d:%d: %s ",
+	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
+	    errstring);
+	printf("error (0x%x)\n", chp->ch_error);
+	sc_xfer->error = XS_SHORTSENSE;
+	sc_xfer->sense.atapi_sense = chp->ch_error;
+	bus_space_write_1(chp->ctl_iot, chp->ctl_ioh, wd_aux_ctlr, WDCTL_4BIT);
+	wdc_atapi_reset(chp, xfer);
+	return;
 }
 
 int
@@ -522,14 +596,15 @@
 	bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
 	    WDSD_IBM | (xfer->drive << 4));
 	if (wait_for_unbusy(chp,
-	    (irq == 0) ? sc_xfer->timeout : 0) != 0) {
+	    (irq == 0) ? sc_xfer->timeout : 0, AT_POLL) == WDCWAIT_TOUT) {
 		if (irq && (xfer->c_flags & C_TIMEOU) == 0)
 			return 0; /* IRQ was not for us */
 		printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip=%d\n",
 		    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
 		    xfer->c_bcount, xfer->c_skip);
 		if (xfer->c_flags & C_DMA) {
-			ata_dmaerr(drvp);
+			ata_dmaerr(drvp,
+			    (xfer->c_flags & C_POLL) ? AT_POLL : 0);
 		}
 		sc_xfer->error = XS_TIMEOUT;
 		wdc_atapi_reset(chp, xfer);
@@ -543,7 +618,7 @@
 	 * and reset device.
 	 */
 	if ((xfer->c_flags & C_TIMEOU) && (xfer->c_flags & C_DMA)) {
-		ata_dmaerr(drvp);
+		ata_dmaerr(drvp, (xfer->c_flags & C_POLL) ? AT_POLL : 0);
 		sc_xfer->error = XS_RESET;
 		wdc_atapi_reset(chp, xfer);
 		return (1);
@@ -624,7 +699,8 @@
 		    (xfer->c_flags & C_DMA) != 0) {
 			printf("wdc_atapi_intr: bad data phase DATAOUT\n");
 			if (xfer->c_flags & C_DMA) {
-				ata_dmaerr(drvp);
+				ata_dmaerr(drvp,
+				    (xfer->c_flags & C_POLL) ? AT_POLL : 0);
 			}
 			sc_xfer->error = XS_TIMEOUT;
 			wdc_atapi_reset(chp, xfer);
@@ -699,7 +775,8 @@
 		    (xfer->c_flags & C_DMA) != 0) {
 			printf("wdc_atapi_intr: bad data phase DATAIN\n");
 			if (xfer->c_flags & C_DMA) {
-				ata_dmaerr(drvp);
+				ata_dmaerr(drvp,
+				    (xfer->c_flags & C_POLL) ? AT_POLL : 0);
 			}
 			sc_xfer->error = XS_TIMEOUT;
 			wdc_atapi_reset(chp, xfer);
@@ -790,7 +867,8 @@
 			sc_xfer->sense.atapi_sense = chp->ch_error;
 		} else {
 			if (xfer->c_flags & C_DMA) {
-				ata_dmaerr(drvp);
+				ata_dmaerr(drvp,
+				    (xfer->c_flags & C_POLL) ? AT_POLL : 0);
 			}
 			sc_xfer->error = XS_RESET;
 			wdc_atapi_reset(chp, xfer);
@@ -804,121 +882,6 @@
 	return (1);
 }
 
-int
-wdc_atapi_ctrl(chp, xfer, irq)
-	struct channel_softc *chp;
-	struct wdc_xfer *xfer;
-	int irq;
-{
-	struct scsipi_xfer *sc_xfer = xfer->cmd;
-	struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
-	char *errstring = NULL;
-	int delay = (irq == 0) ? ATAPI_DELAY : 0;
-
-	/* Ack interrupt done in wait_for_unbusy */
-again:
-	WDCDEBUG_PRINT(("wdc_atapi_ctrl %s:%d:%d state %d\n",
-	    chp->wdc->sc_dev.dv_xname, chp->channel, drvp->drive, drvp->state),
-	    DEBUG_INTR | DEBUG_FUNCS);
-	bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
-	    WDSD_IBM | (xfer->drive << 4));
-	switch (drvp->state) {
-	case PIOMODE:
-		/* Don't try to set mode if controller can't be adjusted */
-		if ((chp->wdc->cap & WDC_CAPABILITY_MODE) == 0)
-			goto ready;
-		/* Also don't try if the drive didn't report its mode */
-		if ((drvp->drive_flags & DRIVE_MODE) == 0)
-			goto ready;
-		wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
-		    0x08 | drvp->PIO_mode, WDSF_SET_MODE);
-		drvp->state = PIOMODE_WAIT;
-		break;
-	case PIOMODE_WAIT:
-		errstring = "piomode";
-		if (wait_for_unbusy(chp, delay))
-			goto timeout;
-		if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
-			chp->wdc->irqack(chp);
-		if (chp->ch_status & WDCS_ERR) {
-			if (chp->ch_error == WDCE_ABRT) {
-				/*
-				 * some ATAPI drives rejects pio settings.
-				 * all we can do here is fall back to PIO 0
-				 */
-				drvp->drive_flags &= ~DRIVE_MODE;
-				drvp->drive_flags &= ~(DRIVE_DMA|DRIVE_UDMA);
-				drvp->PIO_mode = 0;
-				drvp->DMA_mode = 0;
-				printf("%s:%d:%d: pio setting rejected, "
-				    "falling back to PIO mode 0\n",
-				    chp->wdc->sc_dev.dv_xname,
-				    chp->channel, xfer->drive);
-				chp->wdc->set_modes(chp);
-				goto ready;
-			}
-			goto error;
-		}
-	/* fall through */
-
-	case DMAMODE:
-		if (drvp->drive_flags & DRIVE_UDMA) {
-			wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
-			    0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
-		} else if (drvp->drive_flags & DRIVE_DMA) {
-			wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
-			    0x20 | drvp->DMA_mode, WDSF_SET_MODE);
-		} else {
-			goto ready;
-		}
-		drvp->state = DMAMODE_WAIT;
-		break;
-	case DMAMODE_WAIT:
-		errstring = "dmamode";
-		if (wait_for_unbusy(chp, delay))
-			goto timeout;
-		if (chp->wdc->cap & WDC_CAPABILITY_IRQACK)
-			chp->wdc->irqack(chp);
-		if (chp->ch_status & WDCS_ERR)
-			goto error;
-	/* fall through */
-
-	case READY:
-	ready:
-		drvp->state = READY;
-		xfer->c_intr = wdc_atapi_intr;
-		callout_stop(&chp->ch_callout);
-		wdc_atapi_start(chp, xfer);
-		return 1;
-	}
-	if ((sc_xfer->xs_control & XS_CTL_POLL) == 0) {
-		chp->ch_flags |= WDCF_IRQ_WAIT;
-		xfer->c_intr = wdc_atapi_ctrl;
-	} else {
-		goto again;
-	}
-	return 1;
-
-timeout:
-	if (irq && (xfer->c_flags & C_TIMEOU) == 0) {
-		return 0; /* IRQ was not for us */
-	}
-	printf("%s:%d:%d: %s timed out\n",
-	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, errstring);
-	sc_xfer->error = XS_TIMEOUT;
-	wdc_atapi_reset(chp, xfer);
-	return 1;
-error:
-	printf("%s:%d:%d: %s ",
-	    chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
-	    errstring);
-	printf("error (0x%x)\n", chp->ch_error);
-	sc_xfer->error = XS_SHORTSENSE;
-	sc_xfer->sense.atapi_sense = chp->ch_error;
-	wdc_atapi_reset(chp, xfer);
-	return 1;
-}
-
 void
 wdc_atapi_phase_complete(xfer)
 	struct wdc_xfer *xfer;
@@ -934,7 +897,7 @@
 		    xfer->drive, xfer->c_dscpoll), DEBUG_XFERS);
 		if (cold) {
 			if (wdcwait(chp, WDCS_DSC, WDCS_DSC,
-			    sc_xfer->timeout)) {
+			    sc_xfer->timeout, AT_POLL) == WDCWAIT_TOUT) {
 				printf("%s:%d:%d: wait_for_dsc failed\n",
 				    chp->wdc->sc_dev.dv_xname, chp->channel,
 				    xfer->drive);
@@ -943,7 +906,8 @@
 				return;
 			}
 		} else {
-			if (wdcwait(chp, WDCS_DSC, WDCS_DSC, 10)) {
+			if (wdcwait(chp, WDCS_DSC, WDCS_DSC, 10,
+			    AT_POLL) == WDCWAIT_TOUT) {
 				/* 10ms not enough, try again in 1 tick */
 				if (xfer->c_dscpoll++ > 
 				    mstohz(sc_xfer->timeout)) {
@@ -981,7 +945,8 @@
 			sc_xfer->status = SCSI_CHECK;
 		} else if (chp->wdc->dma_status &
 		    (WDC_DMAST_NOIRQ | WDC_DMAST_ERR)) {
-			ata_dmaerr(drvp);
+			ata_dmaerr(drvp,
+			    (xfer->c_flags & C_POLL) ? AT_POLL : 0);
 			sc_xfer->error = XS_RESET;
 			wdc_atapi_reset(chp, xfer);
 			return;
@@ -1034,7 +999,7 @@
 
 	wdccommandshort(chp, xfer->drive, ATAPI_SOFT_RESET);
 	drvp->state = 0;
-	if (wait_for_unbusy(chp, WDC_RESET_WAIT) != 0) {
+	if (wait_for_unbusy(chp, WDC_RESET_WAIT, AT_POLL) != 0) {
 		printf("%s:%d:%d: reset failed\n",
 		    chp->wdc->sc_dev.dv_xname, chp->channel,
 		    xfer->drive);
@@ -1044,7 +1009,7 @@
 	return;
 }
 
-void
+static void
 wdc_atapi_polldsc(arg)
 	void *arg;
 {
Index: dev/scsipi/atapiconf.c
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/atapiconf.c,v
retrieving revision 1.59
diff -u -r1.59 atapiconf.c
--- dev/scsipi/atapiconf.c	2003/09/09 02:37:55	1.59
+++ dev/scsipi/atapiconf.c	2003/09/19 20:26:55
@@ -122,10 +122,8 @@
 	void *aux;
 	const char *pnp; 
 {
-	struct scsipi_channel *chan = aux;
 	if (pnp)
 		aprint_normal("atapibus at %s", pnp);
-	aprint_normal(" channel %d", chan->chan_channel);
 	return (UNCONF);
 }
 
@@ -141,10 +139,6 @@
 		return (0);
 
 	if (chan->chan_bustype->bustype_type != SCSIPI_BUSTYPE_ATAPI)
-		return (0);
-
-	if (cf->cf_loc[ATAPICF_CHANNEL] != chan->chan_channel &&
-	    cf->cf_loc[ATAPICF_CHANNEL] != ATAPICF_CHANNEL_DEFAULT)
 		return (0);
 
 	return (1);
Index: dev/scsipi/files.scsipi
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/files.scsipi,v
retrieving revision 1.35
diff -u -r1.35 files.scsipi
--- dev/scsipi/files.scsipi	2003/09/08 01:56:34	1.35
+++ dev/scsipi/files.scsipi	2003/09/19 20:26:55
@@ -20,7 +20,7 @@
 file	dev/scsipi/scsipi_verbose.c	(scsi_core | atapibus) & scsiverbose
 file	dev/scsipi/scsi_base.c		scsi_core 
 file	dev/scsipi/atapi_base.c		atapibus
-file	dev/scsipi/atapi_wdc.c		atapibus & wdc_base
+file	dev/scsipi/atapi_wdc.c		atapibus & atabus
 
 device	scsibus {target = -1, lun = -1}: scsi_core
 attach	scsibus at scsi
Index: dev/usb/umass_isdata.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/umass_isdata.c,v
retrieving revision 1.5
diff -u -r1.5 umass_isdata.c
--- dev/usb/umass_isdata.c	2003/01/27 13:06:38	1.5
+++ dev/usb/umass_isdata.c	2003/09/19 20:26:55
@@ -115,7 +115,7 @@
 
 int  uisdata_bio(struct ata_drive_datas *, struct ata_bio *);
 int  uisdata_bio1(struct ata_drive_datas *, struct ata_bio *);
-void uisdata_reset_channel(struct ata_drive_datas *);
+void uisdata_reset_channel(struct ata_drive_datas *, int);
 int  uisdata_exec_command(struct ata_drive_datas *, struct wdc_command *);
 int  uisdata_get_params(struct ata_drive_datas *, u_int8_t, struct ataparams *);
 int  uisdata_addref(struct ata_drive_datas *);
@@ -379,7 +379,7 @@
 }
 
 void
-uisdata_reset_channel(struct ata_drive_datas *drv)
+uisdata_reset_channel(struct ata_drive_datas *drv, int flags)
 {
 	DPRINTFN(-1,("%s\n", __func__));
 	/* XXX what? */

--d6Gm4EdcadzBjdND--