tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

SATA port multiplier support



Hello,
I've been working on support for SATA port multiplier in the siisata driver
(ahcisata should be coming soon as well, but hardware for tests is a bit
tricky to set up). This requires some changes to the atabus layer,
and I took the opportunity to cleanup some code there.

I've been considering 2 approaches for SATA PMP support:
1) add a PMP driver which attaches to atabus, and provide one atabus per
  fanout port
2) integrate PMP support to the atabus layer and support attaching more
  than 2 devices to atabus.

solution 1) has one avantage: almost no change needed to atabus.
But it has several disavantage:
- proliferation of atabus instances. On systems with lots of controller/channel
  lots of PMP, it would become tricky to find what is connected to what,
  especially as all PMP devices would have to be attached before
  atabus at pmp could start attaching.
- while it would reflect the physical topology, it is actually the controller
  which drives the devices through the PMP, the PMP acting as a simple
  switch. The controller driver needs to have a view of all attached device
  (especially with SATA NCQ in mind) and adding an intermediate driver
  doesn't help here.

So I went with 2). This requires one major change to the ata layer:
struct ata_channel's ch_drive[] can be as large as 15, so it's better to
dynamically allocate it. As struct ata_channel is allocated in the
controller driver it requires change to a lot of controller drivers.
I added helper functions atabus_alloc_drives() and atabus_free_drives()
for this.

To avoid lots of (if chp->ch_drive != NULL) in code, I enforced that
ch_ndrive (renamed to ch_ndrives while there, it allows to catch
use) be 0 when ch_drive[] is NULL. The only place where this matters is
in wdc.c, where the called passed the max number of drives in ch_ndrive.
I added a wdc_maxdrives to struct wdc_softc for this purpose.

When the PMP driver finds a port with PHY up, is has to reset the attached
device and get the signature. For this purpose I changed the
ata_reset_drive callback to take a uint32_t * pointer which, when not NULL,
will contain the signature returned by the device after reset.
Only the PMP driver uses it with a non-NULL pointer, so non-PMP-driver
aware can ignore it (I added KASSERTs for this).

While there I've done some other more cosmetic changes:
- added a drive_type enum to ata_drive_datas, and stop encoding the
  probed drive type in drive_flags (we were out of drive flags anyway).
- rename DRIVE_ATAPIST to DRIVE_ATAPIDSCW to better reflect what this
  really is
- remove ata_channel->ata_drives, it's redundant with the pointer in
  ata_drive_datas
- I factored out the interpretation of SATA signatures in sata_interpet_sig()

I build a number of kernels for different ports, I think I compile-tested
all the affected code. I tested a few pciide drivers (will test more),
ahci and sii as well as wdc(4).

Any comments before I commit this ?

-- 
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
     NetBSD: 26 ans d'experience feront toujours la difference
--
Index: arch/acorn32/eb7500atx/rside.c
===================================================================
RCS file: /cvsroot/src/sys/arch/acorn32/eb7500atx/rside.c,v
retrieving revision 1.11
diff -u -p -u -r1.11 rside.c
--- arch/acorn32/eb7500atx/rside.c      19 Jul 2011 15:59:52 -0000      1.11
+++ arch/acorn32/eb7500atx/rside.c      23 Jun 2012 13:27:34 -0000
@@ -190,6 +190,7 @@ rside_attach(device_t parent, device_t s
        sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 2;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        for (channel = 0 ; channel < 2; channel++) {
                scp = &sc->rside_channels[channel];
                sc->sc_chanarray[channel] = &scp->rc_channel;
@@ -199,7 +200,6 @@ rside_attach(device_t parent, device_t s
                cp->ch_channel = channel;
                cp->ch_atac = &sc->sc_wdcdev.sc_atac;
                cp->ch_queue = &scp->rc_chqueue;
-               cp->ch_ndrive = 2;
                wdr->cmd_iot = wdr->ctl_iot = &sc->sc_tag;
                if (bus_space_map(wdr->cmd_iot,
                    rside_info[channel].drive_registers,
Index: arch/acorn32/mainbus/wdc_pioc.c
===================================================================
RCS file: /cvsroot/src/sys/arch/acorn32/mainbus/wdc_pioc.c,v
retrieving revision 1.25
diff -u -p -u -r1.25 wdc_pioc.c
--- arch/acorn32/mainbus/wdc_pioc.c     19 Jul 2011 15:59:53 -0000      1.25
+++ arch/acorn32/mainbus/wdc_pioc.c     23 Jun 2012 13:27:34 -0000
@@ -185,9 +185,9 @@ wdc_pioc_attach(device_t parent, device_
        sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanlist;
        sc->sc_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->sc_channel.ch_channel = 0;
        sc->sc_channel.ch_queue = &sc->sc_chqueue;
-       sc->sc_channel.ch_ndrive = 2;
 
        wdc_init_shadow_regs(&sc->sc_channel);
 
Index: arch/acorn32/podulebus/icside.c
===================================================================
RCS file: /cvsroot/src/sys/arch/acorn32/podulebus/icside.c,v
retrieving revision 1.29
diff -u -p -u -r1.29 icside.c
--- arch/acorn32/podulebus/icside.c     19 Jul 2011 15:59:54 -0000      1.29
+++ arch/acorn32/podulebus/icside.c     23 Jun 2012 13:27:34 -0000
@@ -259,6 +259,7 @@ icside_attach(device_t parent, device_t 
        sc->sc_wdcdev.sc_atac.atac_nchannels = ide->channels;
        sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16;
        sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->sc_pa = pa;
 
        for (channel = 0; channel < ide->channels; ++channel) {
@@ -270,7 +271,6 @@ icside_attach(device_t parent, device_t 
                cp->ch_channel = channel;
                cp->ch_atac = &sc->sc_wdcdev.sc_atac;
                cp->ch_queue = &icp->ic_chqueue;
-               cp->ch_ndrive = 2;
                wdr->cmd_iot = &sc->sc_tag;
                wdr->ctl_iot = &sc->sc_tag;
                if (ide->modspace)
Index: arch/acorn32/podulebus/rapide.c
===================================================================
RCS file: /cvsroot/src/sys/arch/acorn32/podulebus/rapide.c,v
retrieving revision 1.27
diff -u -p -u -r1.27 rapide.c
--- arch/acorn32/podulebus/rapide.c     19 Jul 2011 15:59:54 -0000      1.27
+++ arch/acorn32/podulebus/rapide.c     23 Jun 2012 13:27:34 -0000
@@ -250,6 +250,7 @@ rapide_attach(device_t parent, device_t 
        sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 2;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        for (channel = 0 ; channel < 2; channel++) {
                rcp = &sc->rapide_channels[channel];
                sc->sc_chanarray[channel] = &rcp->rc_channel;
@@ -259,7 +260,6 @@ rapide_attach(device_t parent, device_t 
                cp->ch_channel = channel;
                cp->ch_atac = &sc->sc_wdcdev.sc_atac;
                cp->ch_queue = &rcp->rc_chqueue;
-               cp->ch_ndrive = 2;
                wdr->cmd_iot = iot;
                wdr->ctl_iot = iot;
                wdr->data32iot = iot;
Index: arch/acorn32/podulebus/simide.c
===================================================================
RCS file: /cvsroot/src/sys/arch/acorn32/podulebus/simide.c,v
retrieving revision 1.26
diff -u -p -u -r1.26 simide.c
--- arch/acorn32/podulebus/simide.c     19 Jul 2011 15:59:54 -0000      1.26
+++ arch/acorn32/podulebus/simide.c     23 Jun 2012 13:27:34 -0000
@@ -249,6 +249,7 @@ simide_attach(device_t parent, device_t 
        sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 2;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        for (channel = 0 ; channel < 2; channel++) {
                scp = &sc->simide_channels[channel];
                sc->sc_chanarray[channel] = &scp->sc_channel;
@@ -258,7 +259,6 @@ simide_attach(device_t parent, device_t 
                cp->ch_channel = channel;
                cp->ch_atac = &sc->sc_wdcdev.sc_atac;
                cp->ch_queue = &scp->sc_chqueue;
-               cp->ch_ndrive = 2;
                wdr->cmd_iot = wdr->ctl_iot = &sc->sc_tag;
                iobase = pa->pa_podule->mod_base;
                if (bus_space_map(wdr->cmd_iot, iobase +
Index: arch/amiga/dev/efa.c
===================================================================
RCS file: /cvsroot/src/sys/arch/amiga/dev/efa.c,v
retrieving revision 1.5
diff -u -p -u -r1.5 efa.c
--- arch/amiga/dev/efa.c        5 Nov 2011 17:44:25 -0000       1.5
+++ arch/amiga/dev/efa.c        23 Jun 2012 13:27:34 -0000
@@ -159,6 +159,7 @@ efa_attach(device_t parent, device_t sel
        sc->sc_wdcdev.sc_atac.atac_dev = self;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_cap = ATAC_CAP_DATA16;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        if (sc->sc_32bit_io)
                sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA32;
@@ -206,7 +207,6 @@ efa_attach_channel(struct efa_softc *sc,
        sc->sc_ports[chnum].chan.ch_channel = chnum;
        sc->sc_ports[chnum].chan.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->sc_ports[chnum].chan.ch_queue = &sc->sc_ports[chnum].queue;
-       sc->sc_ports[chnum].chan.ch_ndrive = 2;
 
        if (!sc->sc_32bit_io)
                efa_select_regset(sc, chnum, 0); /* Start in PIO0. */
@@ -485,7 +485,7 @@ efa_setup_channel(struct ata_channel *ch
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
 
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue; /* nothing to see here */
 
                if (drvp->PIO_cap < mode);
Index: arch/amiga/dev/wdc_amiga.c
===================================================================
RCS file: /cvsroot/src/sys/arch/amiga/dev/wdc_amiga.c,v
retrieving revision 1.33
diff -u -p -u -r1.33 wdc_amiga.c
--- arch/amiga/dev/wdc_amiga.c  19 Jul 2011 15:55:27 -0000      1.33
+++ arch/amiga/dev/wdc_amiga.c  23 Jun 2012 13:27:34 -0000
@@ -134,10 +134,10 @@ wdc_amiga_attach(device_t parent, device
        sc->sc_chanlist[0] = &sc->sc_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->sc_channel.ch_channel = 0;
        sc->sc_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->sc_channel.ch_queue = &sc->sc_chqueue;
-       sc->sc_channel.ch_ndrive = 2;
 
        wdc_init_shadow_regs(&sc->sc_channel);
 
Index: arch/amiga/dev/wdc_buddha.c
===================================================================
RCS file: /cvsroot/src/sys/arch/amiga/dev/wdc_buddha.c,v
retrieving revision 1.5
diff -u -p -u -r1.5 wdc_buddha.c
--- arch/amiga/dev/wdc_buddha.c 19 Jul 2011 15:55:27 -0000      1.5
+++ arch/amiga/dev/wdc_buddha.c 23 Jun 2012 13:27:34 -0000
@@ -114,6 +114,7 @@ wdc_buddha_attach(device_t parent, devic
        sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = nchannels;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
@@ -134,7 +135,6 @@ wdc_buddha_attach(device_t parent, devic
                            "can't allocate memory for command queue\n");
                        return;
                }
-               cp->ch_ndrive = 2;
 
                /*
                 * XXX According to the Buddha docs, we should use a method
Index: arch/arm/gemini/obio_wdc.c
===================================================================
RCS file: /cvsroot/src/sys/arch/arm/gemini/obio_wdc.c,v
retrieving revision 1.3
diff -u -p -u -r1.3 obio_wdc.c
--- arch/arm/gemini/obio_wdc.c  1 Jul 2011 19:32:28 -0000       1.3
+++ arch/arm/gemini/obio_wdc.c  23 Jun 2012 13:27:34 -0000
@@ -138,10 +138,10 @@ wdc_obio_attach(device_t parent, device_
        sc->wdc_chanlist[0] = &sc->ata_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->ata_channel.ch_channel = 0;
        sc->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->ata_channel.ch_queue = &sc->wdc_chqueue;
-       sc->ata_channel.ch_ndrive = 2;
        wdc_init_shadow_regs(&sc->ata_channel);
 
        aprint_normal("\n");
Index: arch/atari/dev/wdc_mb.c
===================================================================
RCS file: /cvsroot/src/sys/arch/atari/dev/wdc_mb.c,v
retrieving revision 1.35
diff -u -p -u -r1.35 wdc_mb.c
--- arch/atari/dev/wdc_mb.c     1 Jul 2011 20:34:05 -0000       1.35
+++ arch/atari/dev/wdc_mb.c     23 Jun 2012 13:27:34 -0000
@@ -204,10 +204,10 @@ wdc_mb_attach(device_t parent, device_t 
        sc->sc_chanlist[0] = &sc->sc_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->sc_channel.ch_channel = 0;
        sc->sc_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->sc_channel.ch_queue = &sc->sc_chqueue;
-       sc->sc_channel.ch_ndrive = 2;
        wdc_init_shadow_regs(&sc->sc_channel);
 
        /*
Index: arch/evbarm/iq31244/wdc_obio.c
===================================================================
RCS file: /cvsroot/src/sys/arch/evbarm/iq31244/wdc_obio.c,v
retrieving revision 1.6
diff -u -p -u -r1.6 wdc_obio.c
--- arch/evbarm/iq31244/wdc_obio.c      1 Jul 2011 20:41:16 -0000       1.6
+++ arch/evbarm/iq31244/wdc_obio.c      23 Jun 2012 13:27:35 -0000
@@ -109,10 +109,10 @@ wdc_obio_attach(device_t parent, device_
        sc->wdc_chanlist[0] = &sc->ata_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->ata_channel.ch_channel = 0;
        sc->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->ata_channel.ch_queue = &sc->wdc_chqueue;
-       sc->ata_channel.ch_ndrive = 2;
        wdc_init_shadow_regs(&sc->ata_channel);
 
        aprint_normal("\n");
Index: arch/evbarm/tsarm/wdc_ts.c
===================================================================
RCS file: /cvsroot/src/sys/arch/evbarm/tsarm/wdc_ts.c,v
retrieving revision 1.6
diff -u -p -u -r1.6 wdc_ts.c
--- arch/evbarm/tsarm/wdc_ts.c  1 Jul 2011 19:11:34 -0000       1.6
+++ arch/evbarm/tsarm/wdc_ts.c  23 Jun 2012 13:27:35 -0000
@@ -107,10 +107,10 @@ wdc_ts_attach(device_t parent, device_t 
        sc->wdc_chanlist[0] = &sc->ata_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->ata_channel.ch_channel = 0;
        sc->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->ata_channel.ch_queue = &sc->wdc_chqueue;
-       sc->ata_channel.ch_ndrive = 2;
        wdc_init_shadow_regs(&sc->ata_channel);
 
        aprint_normal("\n");
Index: arch/evbppc/mpc85xx/wdc_obio.c
===================================================================
RCS file: /cvsroot/src/sys/arch/evbppc/mpc85xx/wdc_obio.c,v
retrieving revision 1.1
diff -u -p -u -r1.1 wdc_obio.c
--- arch/evbppc/mpc85xx/wdc_obio.c      18 Jan 2011 01:10:25 -0000      1.1
+++ arch/evbppc/mpc85xx/wdc_obio.c      23 Jun 2012 13:27:35 -0000
@@ -159,10 +159,10 @@ wdc_obio_attach(device_t parent, device_
        sc->wdc_chanlist[0] = &sc->ata_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->ata_channel.ch_channel = 0;
        sc->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->ata_channel.ch_queue = &sc->wdc_chqueue;
-       sc->ata_channel.ch_ndrive = 2;
 
        wdc_init_shadow_regs(&sc->ata_channel);
 
Index: arch/i386/pci/gcscide.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/pci/gcscide.c,v
retrieving revision 1.9
diff -u -p -u -r1.9 gcscide.c
--- arch/i386/pci/gcscide.c     4 Apr 2011 20:37:51 -0000       1.9
+++ arch/i386/pci/gcscide.c     23 Jun 2012 13:27:35 -0000
@@ -198,7 +198,7 @@ gcscide_setup_channel(struct ata_channel
 
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
 
                reg = rdmsr(drive ? GCSCIDE_ATAC_CH0D1_DMA :
Index: arch/i386/pnpbios/pciide_pnpbios.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/pnpbios/pciide_pnpbios.c,v
retrieving revision 1.27
diff -u -p -u -r1.27 pciide_pnpbios.c
--- arch/i386/pnpbios/pciide_pnpbios.c  1 Jul 2011 18:14:15 -0000       1.27
+++ arch/i386/pnpbios/pciide_pnpbios.c  23 Jun 2012 13:27:35 -0000
@@ -120,7 +120,6 @@ pciide_pnpbios_attach(device_t parent, d
        cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        cp->ata_channel.ch_queue = malloc(sizeof(struct ata_queue),
                                          M_DEVBUF, M_NOWAIT);
-       cp->ata_channel.ch_ndrive = 2;
        if (cp->ata_channel.ch_queue == NULL) {
                aprint_error_dev(self, "unable to allocate memory for command "
                    "queue\n");
@@ -149,6 +148,7 @@ pciide_pnpbios_attach(device_t parent, d
        sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DMA;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16 | ATAC_CAP_DATA32;
        sc->sc_wdcdev.sc_atac.atac_pio_cap = 0;
        sc->sc_wdcdev.sc_atac.atac_dma_cap = 0;         /* XXX */
@@ -182,7 +182,7 @@ pciide_pnpbios_attach(device_t parent, d
        wdcattach(wdc_cp);
 
        idedma_ctl = 0;
-       for (drive = 0; drive < cp->ata_channel.ch_ndrive; drive++) {
+       for (drive = 0; drive < cp->ata_channel.ch_ndrives; drive++) {
                /*
                 * we have not probed the drives yet,
                 * allocate ressources for all of them.
Index: arch/landisk/dev/wdc_obio.c
===================================================================
RCS file: /cvsroot/src/sys/arch/landisk/dev/wdc_obio.c,v
retrieving revision 1.5
diff -u -p -u -r1.5 wdc_obio.c
--- arch/landisk/dev/wdc_obio.c 1 Jul 2011 19:12:53 -0000       1.5
+++ arch/landisk/dev/wdc_obio.c 23 Jun 2012 13:27:35 -0000
@@ -171,10 +171,10 @@ wdc_obio_attach(device_t parent, device_
        sc->sc_chanlist[0] = &sc->sc_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->sc_channel.ch_channel = 0;
        sc->sc_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->sc_channel.ch_queue = &sc->sc_chqueue;
-       sc->sc_channel.ch_ndrive = 2;
 
        wdc_init_shadow_regs(&sc->sc_channel);
 
Index: arch/mac68k/obio/wdc_obio.c
===================================================================
RCS file: /cvsroot/src/sys/arch/mac68k/obio/wdc_obio.c,v
retrieving revision 1.23
diff -u -p -u -r1.23 wdc_obio.c
--- arch/mac68k/obio/wdc_obio.c 18 Mar 2008 20:46:36 -0000      1.23
+++ arch/mac68k/obio/wdc_obio.c 23 Jun 2012 13:27:35 -0000
@@ -223,10 +223,10 @@ wdc_obio_attach(device_t parent, device_
        sc->sc_chanlist[0] = chp;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        chp->ch_channel = 0;
        chp->ch_atac = &sc->sc_wdcdev.sc_atac;
        chp->ch_queue = &sc->sc_chqueue;
-       chp->ch_ndrive = 2;
        wdc_init_shadow_regs(chp);
 
        aprint_normal("\n");
Index: arch/macppc/dev/kauai.c
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/dev/kauai.c,v
retrieving revision 1.28
diff -u -p -u -r1.28 kauai.c
--- arch/macppc/dev/kauai.c     1 Jul 2011 18:41:52 -0000       1.28
+++ arch/macppc/dev/kauai.c     23 Jun 2012 13:27:35 -0000
@@ -181,6 +181,7 @@ kauai_attach(device_t parent, device_t s
        sc->sc_chanptr = chp;
        sc->sc_wdcdev.sc_atac.atac_channels = &sc->sc_chanptr;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->sc_wdcdev.dma_arg = sc;
        sc->sc_wdcdev.dma_init = kauai_dma_init;
        sc->sc_wdcdev.dma_start = kauai_dma_start;
@@ -192,7 +193,6 @@ kauai_attach(device_t parent, device_t s
        chp->ch_channel = 0;
        chp->ch_atac = &sc->sc_wdcdev.sc_atac;
        chp->ch_queue = &sc->sc_queue;
-       chp->ch_ndrive = 2;
        wdc_init_shadow_regs(chp);
 
        wdcattach(chp);
@@ -208,14 +208,15 @@ kauai_set_modes(struct ata_channel *chp)
        struct ata_drive_datas *drvp;
        int drive;
 
-       if ((drvp0->drive_flags & DRIVE) && (drvp1->drive_flags & DRIVE)) {
+       if (drvp0->drive_type != DRIVET_NONE &&
+           drvp1->drive_type != DRIVET_NONE) {
                drvp0->PIO_mode = drvp1->PIO_mode =
                    min(drvp0->PIO_mode, drvp1->PIO_mode);
        }
 
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
-               if (drvp->drive_flags & DRIVE) {
+               if (drvp->drive_type !=  DRIVET_NONE) {
                        (*sc->sc_calc_timing)(sc, drive);
                        bus_space_write_4(wdr->cmd_iot, wdr->cmd_baseioh,
                            PIO_CONFIG_REG, sc->sc_piotiming_r[drive]);
Index: arch/macppc/dev/wdc_obio.c
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/dev/wdc_obio.c,v
retrieving revision 1.53
diff -u -p -u -r1.53 wdc_obio.c
--- arch/macppc/dev/wdc_obio.c  1 Jul 2011 18:41:52 -0000       1.53
+++ arch/macppc/dev/wdc_obio.c  23 Jun 2012 13:27:35 -0000
@@ -230,6 +230,7 @@ wdc_obio_attach(device_t parent, device_
        sc->sc_chanptr = chp;
        sc->sc_wdcdev.sc_atac.atac_channels = &sc->sc_chanptr;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->sc_wdcdev.dma_arg = sc;
        sc->sc_wdcdev.dma_init = wdc_obio_dma_init;
        sc->sc_wdcdev.dma_start = wdc_obio_dma_start;
@@ -237,7 +238,6 @@ wdc_obio_attach(device_t parent, device_
        chp->ch_channel = 0;
        chp->ch_atac = &sc->sc_wdcdev.sc_atac;
        chp->ch_queue = &sc->sc_chqueue;
-       chp->ch_ndrive = 2;
 
        wdc_init_shadow_regs(chp);
 
@@ -319,7 +319,7 @@ adjust_timing(struct ata_channel *chp)
                
                drvp = &chp->ch_drive[drive];
                /* set up pio mode timings */
-               if (drvp->drive_flags & DRIVE) {
+               if (drvp->drive_type != DRIVET_NONE) {
                        int piomode = drvp->PIO_mode;
                        min_cycle = pio_timing[piomode].cycle;
                        min_active = pio_timing[piomode].active;
@@ -385,7 +385,7 @@ ata4_adjust_timing(struct ata_channel *c
                drvp = &chp->ch_drive[drive];
                /* set up pio mode timings */
 
-               if (drvp->drive_flags & DRIVE) {
+               if (drvp->drive_type != DRIVET_NONE) {
                        int piomode = drvp->PIO_mode;
                        min_cycle = pio_timing[piomode].cycle;
                        min_active = pio_timing[piomode].active;
Index: arch/mips/adm5120/dev/wdc_extio.c
===================================================================
RCS file: /cvsroot/src/sys/arch/mips/adm5120/dev/wdc_extio.c,v
retrieving revision 1.5
diff -u -p -u -r1.5 wdc_extio.c
--- arch/mips/adm5120/dev/wdc_extio.c   10 Jul 2011 23:13:23 -0000      1.5
+++ arch/mips/adm5120/dev/wdc_extio.c   23 Jun 2012 13:27:35 -0000
@@ -307,10 +307,10 @@ wdc_extio_attach(device_t parent, device
        sc->sc_chanlist[0] = chp;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        chp->ch_channel = 0;
        chp->ch_atac = &sc->sc_wdcdev.sc_atac;
        chp->ch_queue = &sc->sc_chqueue;
-       chp->ch_ndrive = 2;
 
        aprint_normal("\n");
 
Index: arch/mmeye/dev/wdc_mainbus.c
===================================================================
RCS file: /cvsroot/src/sys/arch/mmeye/dev/wdc_mainbus.c,v
retrieving revision 1.1
diff -u -p -u -r1.1 wdc_mainbus.c
--- arch/mmeye/dev/wdc_mainbus.c        19 Feb 2011 10:46:28 -0000      1.1
+++ arch/mmeye/dev/wdc_mainbus.c        23 Jun 2012 13:27:35 -0000
@@ -170,10 +170,10 @@ wdc_mainbus_attach(device_t parent, devi
        sc->wdc_chanlist[0] = &sc->ata_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->ata_channel.ch_channel = 0;
        sc->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->ata_channel.ch_queue = &sc->wdc_chqueue;
-       sc->ata_channel.ch_ndrive = 2;
        wdc_init_shadow_regs(&sc->ata_channel);
 
        aprint_normal("\n");
Index: arch/prep/pnpbus/wdc_pnpbus.c
===================================================================
RCS file: /cvsroot/src/sys/arch/prep/pnpbus/wdc_pnpbus.c,v
retrieving revision 1.10
diff -u -p -u -r1.10 wdc_pnpbus.c
--- arch/prep/pnpbus/wdc_pnpbus.c       1 Jul 2011 16:55:42 -0000       1.10
+++ arch/prep/pnpbus/wdc_pnpbus.c       23 Jun 2012 13:27:35 -0000
@@ -138,10 +138,10 @@ wdc_pnpbus_attach(device_t parent, devic
        sc->sc_chanlist[0] = &sc->sc_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->sc_channel.ch_channel = 0;
        sc->sc_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->sc_channel.ch_queue = &sc->sc_chqueue;
-       sc->sc_channel.ch_ndrive = 2;
        wdc_init_shadow_regs(&sc->sc_channel);
 
        sc->sc_ih = pnpbus_intr_establish(0, IPL_BIO, IST_PNP,
Index: conf/files
===================================================================
RCS file: /cvsroot/src/sys/conf/files,v
retrieving revision 1.1050
diff -u -p -u -r1.1050 files
--- conf/files  8 May 2012 23:53:26 -0000       1.1050
+++ conf/files  23 Jun 2012 13:27:36 -0000
@@ -290,6 +290,7 @@ define      videobus        { }
 define ata             {[channel = -1]}
 define sata
 define sata_fis
+define sata_pmp
 define scsi_core
 define scsi            {[channel = -1]}: scsi_core
 define ata_hl          {[drive = -1]}
@@ -979,7 +980,7 @@ device ahcisata: ata, ata_dma, ata_udma,
 # Silicon Image SteelVine SATA-II controllers
 define siisata
 file   dev/ic/siisata.c                siisata
-device siisata: ata, ata_dma, ata_udma, sata, sata_fis, siisata
+device siisata: ata, ata_dma, ata_udma, sata, sata_fis, sata_pmp, siisata
 
 # Marvell Serial-ATA Host Controller
 define mvsata
Index: dev/ata/ata.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/ata.c,v
retrieving revision 1.116
diff -u -p -u -r1.116 ata.c
--- dev/ata/ata.c       6 Apr 2012 02:52:00 -0000       1.116
+++ dev/ata/ata.c       23 Jun 2012 13:27:36 -0000
@@ -55,10 +55,15 @@ __KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.11
 
 #include "atapibus.h"
 #include "ataraid.h"
+#include "sata_pmp.h"
 
 #if NATARAID > 0
 #include <dev/ata/ata_raidvar.h>
 #endif
+#if NSATA_PMP > 0
+#include <dev/ata/satapmpvar.h>
+#endif
+#include <dev/ata/satapmpreg.h>
 
 #define DEBUG_FUNCS  0x08
 #define DEBUG_PROBE  0x10
@@ -199,12 +204,16 @@ atabusconfig(struct atabus_softc *atabus
        chp->ch_flags |= ATACH_TH_RUN;
        splx(s);
 
-       /* Probe for the drives. */
+       /*
+        * Probe for the drives attached to controller, unless a PMP
+        * is already known
+        */
        /* XXX for SATA devices we will power up all drives at once */
-       (*atac->atac_probe)(chp);
+       if (chp->ch_satapmp_nports == 0)
+               (*atac->atac_probe)(chp);
 
-       ATADEBUG_PRINT(("atabusattach: ch_drive_flags 0x%x 0x%x\n",
-           chp->ch_drive[0].drive_flags, chp->ch_drive[1].drive_flags),
+       ATADEBUG_PRINT(("atabusattach: ch_drive_type 0x%x 0x%x\n",
+           chp->ch_drive[0].drive_type, chp->ch_drive[1].drive_type),
            DEBUG_PROBE);
 
        /* next operations will occurs in a separate thread */
@@ -223,17 +232,19 @@ atabusconfig(struct atabus_softc *atabus
        mutex_exit(&atabus_qlock);
 
        /* If no drives, abort here */
-       for (i = 0; i < chp->ch_ndrive; i++)
-               if ((chp->ch_drive[i].drive_flags & DRIVE) != 0)
+       if (chp->ch_drive == NULL)
+               goto out;
+       KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
+       for (i = 0; i < chp->ch_ndrives; i++)
+               if (chp->ch_drive[i].drive_type != DRIVET_NONE)
                        break;
-       if (i == chp->ch_ndrive)
+       if (i == chp->ch_ndrives)
                goto out;
 
        /* Shortcut in case we've been shutdown */
        if (chp->ch_flags & ATACH_SHUTDOWN)
                goto out;
 
-
        if ((error = kthread_create(PRI_NONE, 0, NULL, atabusconfig_thread,
            atabus_sc, &atabus_cfg_lwp,
            "%scnf", device_xname(atac->atac_dev))) != 0)
@@ -274,10 +285,25 @@ atabusconfig_thread(void *arg)
        mutex_exit(&atabus_qlock);
 
        /*
+        * First look for a port multiplier
+        */
+       if (chp->ch_ndrives == PMP_MAX_DRIVES &&
+           chp->ch_drive[PMP_PORT_CTL].drive_type == DRIVET_PM) {
+#if NSATA_PMP > 0
+               satapmp_attach(chp);
+#else
+               aprint_error_dev(atabus_sc->sc_dev,
+                   "SATA port multiplier not supported\n");
+               /* no problems going on, all drives are DRIVET_NONE */
+#endif
+       }
+
+       /*
         * Attach an ATAPI bus, if needed.
         */
-       for (i = 0; i < chp->ch_ndrive; i++) {
-               if (chp->ch_drive[i].drive_flags & DRIVE_ATAPI) {
+       KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
+       for (i = 0; i < chp->ch_ndrives && chp->atapibus == NULL; i++) {
+               if (chp->ch_drive[i].drive_type == DRIVET_ATAPI) {
 #if NATAPIBUS > 0
                        (*atac->atac_atapibus_attach)(atabus_sc);
 #else
@@ -288,33 +314,36 @@ atabusconfig_thread(void *arg)
                            device_xname(atac->atac_dev));
                        chp->atapibus = NULL;
                        s = splbio();
-                       for (i = 0; i < chp->ch_ndrive; i++)
-                               chp->ch_drive[i].drive_flags &= ~DRIVE_ATAPI;
+                       for (i = 0; i < chp->ch_ndrives; i++) {
+                               if (chp->ch_drive[i].drive_type == DRIVET_ATAPI)
+                                       chp->ch_drive[i].drive_type = 
DRIVET_NONE;
+                       }
                        splx(s);
 #endif
                        break;
                }
        }
 
-       for (i = 0; i < chp->ch_ndrive; i++) {
+       for (i = 0; i < chp->ch_ndrives; i++) {
                struct ata_device adev;
-               if ((chp->ch_drive[i].drive_flags &
-                   (DRIVE_ATA | DRIVE_OLD)) == 0) {
+               if (chp->ch_drive[i].drive_type != DRIVET_ATA &&
+                   chp->ch_drive[i].drive_type != DRIVET_OLD) {
                        continue;
                }
+               if (chp->ch_drive[i].drv_softc != NULL)
+                       continue;
                memset(&adev, 0, sizeof(struct ata_device));
                adev.adev_bustype = atac->atac_bustype_ata;
                adev.adev_channel = chp->ch_channel;
                adev.adev_openings = 1;
                adev.adev_drv_data = &chp->ch_drive[i];
-               chp->ata_drives[i] = config_found_ia(atabus_sc->sc_dev,
+               chp->ch_drive[i].drv_softc = config_found_ia(atabus_sc->sc_dev,
                    "ata_hl", &adev, ataprint);
-               if (chp->ata_drives[i] != NULL)
+               if (chp->ch_drive[i].drv_softc != NULL) {
                        ata_probe_caps(&chp->ch_drive[i]);
-               else {
+               } else {
                        s = splbio();
-                       chp->ch_drive[i].drive_flags &=
-                           ~(DRIVE_ATA | DRIVE_OLD);
+                       chp->ch_drive[i].drive_type = DRIVET_NONE;
                        splx(s);
                }
        }
@@ -325,10 +354,14 @@ atabusconfig_thread(void *arg)
                ata_print_modes(chp);
        }
 #if NATARAID > 0
-       if (atac->atac_cap & ATAC_CAP_RAID)
-               for (i = 0; i < chp->ch_ndrive; i++)
-                       if (chp->ata_drives[i] != NULL)
-                               ata_raid_check_component(chp->ata_drives[i]);
+       if (atac->atac_cap & ATAC_CAP_RAID) {
+               for (i = 0; i < chp->ch_ndrives; i++) {
+                       if (chp->ch_drive[i].drive_type == DRIVET_ATA) {
+                               ata_raid_check_component(
+                                   chp->ch_drive[i].drv_softc);
+                       }
+               }
+       }
 #endif /* NATARAID > 0 */
 
        /*
@@ -336,10 +369,13 @@ atabusconfig_thread(void *arg)
         * ones
         */
        s = splbio();
-       for (i = 0; i < chp->ch_ndrive; i++) {
-               if (chp->ch_drive[i].drv_softc == NULL)
+       for (i = 0; i < chp->ch_ndrives; i++) {
+               if (chp->ch_drive[i].drive_type == DRIVET_PM)
+                       continue;
+               if (chp->ch_drive[i].drv_softc == NULL) {
                        chp->ch_drive[i].drive_flags = 0;
-               else
+                       chp->ch_drive[i].drive_type = DRIVET_NONE;
+               } else
                        chp->ch_drive[i].state = 0;
        }
        splx(s);
@@ -374,13 +410,16 @@ atabus_thread(void *arg)
        chp->ch_flags |= ATACH_TH_RUN;
 
        /*
-        * Probe the drives.  Reset all flags to 0 to indicate to controllers
+        * Probe the drives.  Reset type to indicate to controllers
         * that can re-probe that all drives must be probed..
         *
-        * Note: ch_ndrive may be changed during the probe.
+        * Note: ch_ndrives may be changed during the probe.
         */
-       for (i = 0; i < ATA_MAXDRIVES; i++)
+       KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
+       for (i = 0; i < chp->ch_ndrives; i++) {
                chp->ch_drive[i].drive_flags = 0;
+               chp->ch_drive[i].drive_type = DRIVET_NONE;
+       }
        splx(s);
 
        atabusconfig(sc);
@@ -522,24 +561,28 @@ atabus_detach(device_t self, int flags)
                KASSERT(chp->atapibus == NULL);
        }
 
+       KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
+
        /*
         * Detach our other children.
         */
-       for (i = 0; i < chp->ch_ndrive; i++) {
-               if (chp->ch_drive[i].drive_flags & DRIVE_ATAPI)
+       for (i = 0; i < chp->ch_ndrives; i++) {
+               if (chp->ch_drive[i].drive_type == DRIVET_ATAPI)
                        continue;
-               if ((dev = chp->ata_drives[i]) != NULL) {
+               if (chp->ch_drive[i].drive_type == DRIVET_PM)
+                       chp->ch_drive[i].drive_type = DRIVET_NONE;
+               if ((dev = chp->ch_drive[i].drv_softc) != NULL) {
                        ATADEBUG_PRINT(("%s.%d: %s: detaching %s\n", __func__,
                            __LINE__, device_xname(self), device_xname(dev)),
                            DEBUG_DETACH);
-                       KASSERT(chp->ch_drive[i].drv_softc ==
-                               chp->ata_drives[i]);
                        error = config_detach(dev, flags);
                        if (error)
                                goto out;
-                       KASSERT(chp->ata_drives[i] == NULL);
+                       KASSERT(chp->ch_drive[i].drv_softc == NULL);
+                       KASSERT(chp->ch_drive[i].drive_type == 0);
                }
        }
+       atabus_free_drives(chp);
 
  out:
 #ifdef ATADEBUG
@@ -560,26 +603,35 @@ atabus_childdetached(device_t self, devi
        struct ata_channel *chp = sc->sc_chan;
        int i;
 
+       KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
        /*
         * atapibus detached.
         */
        if (child == chp->atapibus) {
                chp->atapibus = NULL;
                found = true;
+               for (i = 0; i < chp->ch_ndrives; i++) {
+                       if (chp->ch_drive[i].drive_type != DRIVET_ATAPI)
+                               continue;
+                       KASSERT(chp->ch_drive[i].drv_softc != NULL);
+                       chp->ch_drive[i].drv_softc = NULL;
+                       chp->ch_drive[i].drive_flags = 0;
+                       chp->ch_drive[i].drive_type = DRIVET_NONE;
+               }
        }
 
        /*
         * Detach our other children.
         */
-       for (i = 0; i < chp->ch_ndrive; i++) {
-               if (chp->ch_drive[i].drive_flags & DRIVE_ATAPI)
+       for (i = 0; i < chp->ch_ndrives; i++) {
+               if (chp->ch_drive[i].drive_type == DRIVET_ATAPI)
                        continue;
-               if (child == chp->ata_drives[i]) {
-                       KASSERT(chp->ata_drives[i] ==
-                               chp->ch_drive[i].drv_softc);
-                       chp->ata_drives[i] = NULL;
+               if (child == chp->ch_drive[i].drv_softc) {
                        chp->ch_drive[i].drv_softc = NULL;
                        chp->ch_drive[i].drive_flags = 0;
+                       if (chp->ch_drive[i].drive_type == DRIVET_PM)
+                               chp->ch_satapmp_nports = 0;
+                       chp->ch_drive[i].drive_type = DRIVET_NONE;
                        found = true;
                }
        }
@@ -597,6 +649,64 @@ CFATTACH_DECL3_NEW(atabus, sizeof(struct
  * Common ATA bus operations.
  *****************************************************************************/
 
+/* allocate/free the channel's ch_drive[] array */
+int
+atabus_alloc_drives(struct ata_channel *chp, int ndrives)
+{
+       int i;
+       if (chp->ch_ndrives != ndrives)
+               atabus_free_drives(chp);
+       if (chp->ch_drive == NULL) {
+               chp->ch_drive = malloc(
+                   sizeof(struct ata_drive_datas) * ndrives,
+                   M_DEVBUF, M_NOWAIT | M_ZERO);
+       }
+       if (chp->ch_drive == NULL) {
+           aprint_error_dev(chp->ch_atac->atac_dev,
+               "can't alloc drive array\n");
+           chp->ch_ndrives = 0;
+           return ENOMEM;
+       };
+       for (i = 0; i < ndrives; i++) {
+               chp->ch_drive[i].chnl_softc = chp;
+               chp->ch_drive[i].drive = i;
+       }
+       chp->ch_ndrives = ndrives;
+       return 0;
+}
+
+void
+atabus_free_drives(struct ata_channel *chp)
+{
+#ifdef DIAGNOSTIC
+       int i;
+       int dopanic = 0;
+       KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
+       for (i = 0; i < chp->ch_ndrives; i++) {
+               if (chp->ch_drive[i].drive_type != DRIVET_NONE) {
+                       printf("%s: ch_drive[%d] type %d != DRIVET_NONE\n",
+                           device_xname(chp->atabus), i,
+                           chp->ch_drive[i].drive_type);
+                       dopanic = 1;
+               }
+               if (chp->ch_drive[i].drv_softc != NULL) {
+                       printf("%s: ch_drive[%d] attached to %s\n",
+                           device_xname(chp->atabus), i,
+                           device_xname(chp->ch_drive[i].drv_softc));
+                       dopanic = 1;
+               }
+       }
+       if (dopanic)
+               panic("atabus_free_drives");
+#endif
+
+       if (chp->ch_drive == NULL)
+               return;
+       chp->ch_ndrives = 0;
+       free(chp->ch_drive, M_DEVBUF);
+       chp->ch_drive = NULL;
+}
+
 /* Get the disk's parameters */
 int
 ata_get_params(struct ata_drive_datas *drvp, u_int8_t flags,
@@ -615,12 +725,12 @@ ata_get_params(struct ata_drive_datas *d
        memset(prms, 0, sizeof(struct ataparams));
        memset(&ata_c, 0, sizeof(struct ata_command));
 
-       if (drvp->drive_flags & DRIVE_ATA) {
+       if (drvp->drive_type == DRIVET_ATA) {
                ata_c.r_command = WDCC_IDENTIFY;
                ata_c.r_st_bmask = WDCS_DRDY;
                ata_c.r_st_pmask = WDCS_DRQ;
                ata_c.timeout = 3000; /* 3s */
-       } else if (drvp->drive_flags & DRIVE_ATAPI) {
+       } else if (drvp->drive_type == DRIVET_ATAPI) {
                ata_c.r_command = ATAPI_IDENTIFY_DEVICE;
                ata_c.r_st_bmask = 0;
                ata_c.r_st_pmask = WDCS_DRQ;
@@ -671,7 +781,7 @@ ata_get_params(struct ata_drive_datas *d
 #if BYTE_ORDER == BIG_ENDIAN
            !
 #endif
-           ((drvp->drive_flags & DRIVE_ATAPI) ?
+           ((drvp->drive_type == DRIVET_ATAPI) ?
             ((M(0) == 'N' && M(1) == 'E') ||
              (M(0) == 'F' && M(1) == 'X') ||
              (M(0) == 'P' && M(1) == 'i')) :
@@ -1009,7 +1119,8 @@ ata_reset_channel(struct ata_channel *ch
 
        (*atac->atac_bustype_ata->ata_reset_channel)(chp, flags);
 
-       for (drive = 0; drive < chp->ch_ndrive; drive++)
+       KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
+       for (drive = 0; drive < chp->ch_ndrives; drive++)
                chp->ch_drive[drive].state = 0;
 
        chp->ch_flags &= ~ATACH_TH_RESET;
@@ -1063,9 +1174,11 @@ ata_print_modes(struct ata_channel *chp)
        int drive;
        struct ata_drive_datas *drvp;
 
-       for (drive = 0; drive < chp->ch_ndrive; drive++) {
+       KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
+       for (drive = 0; drive < chp->ch_ndrives; drive++) {
                drvp = &chp->ch_drive[drive];
-               if ((drvp->drive_flags & DRIVE) == 0 || drvp->drv_softc == NULL)
+               if (drvp->drive_type == DRIVET_NONE ||
+                   drvp->drv_softc == NULL)
                        continue;
                aprint_verbose("%s(%s:%d:%d): using PIO mode %d",
                        device_xname(drvp->drv_softc),
@@ -1215,7 +1328,7 @@ ata_probe_caps(struct ata_drive_datas *d
 #endif
 
        /* An ATAPI device is at last PIO mode 3 */
-       if (drvp->drive_flags & DRIVE_ATAPI)
+       if (drvp->drive_type == DRIVET_ATAPI)
                drvp->PIO_mode = 3;
 
        /*
@@ -1354,7 +1467,7 @@ ata_probe_caps(struct ata_drive_datas *d
 
        s = splbio();
        drvp->drive_flags &= ~DRIVE_NOSTREAM;
-       if (drvp->drive_flags & DRIVE_ATAPI) {
+       if (drvp->drive_type == DRIVET_ATAPI) {
                if (atac->atac_cap & ATAC_CAP_ATAPI_NOSTREAM)
                        drvp->drive_flags |= DRIVE_NOSTREAM;
        } else {
@@ -1490,8 +1603,8 @@ atabusioctl(dev_t dev, u_long cmd, void 
                struct atabusioscan_args *a=
                    (struct atabusioscan_args *)addr;
 #endif
-               if ((chp->ch_drive[0].drive_flags & DRIVE_OLD) ||
-                   (chp->ch_drive[1].drive_flags & DRIVE_OLD))
+               if ((chp->ch_drive[0].drive_type == DRIVET_OLD) ||
+                   (chp->ch_drive[1].drive_type == DRIVET_OLD))
                        return (EOPNOTSUPP);
                return (EOPNOTSUPP);
        }
@@ -1499,8 +1612,8 @@ atabusioctl(dev_t dev, u_long cmd, void 
        {
                struct atabusiodetach_args *a=
                    (struct atabusiodetach_args *)addr;
-               if ((chp->ch_drive[0].drive_flags & DRIVE_OLD) ||
-                   (chp->ch_drive[1].drive_flags & DRIVE_OLD))
+               if ((chp->ch_drive[0].drive_type == DRIVET_OLD) ||
+                   (chp->ch_drive[1].drive_type == DRIVET_OLD))
                        return (EOPNOTSUPP);
                switch (a->at_dev) {
                case -1:
@@ -1573,23 +1686,23 @@ atabus_rescan(device_t self, const char 
        struct ata_channel *chp = sc->sc_chan;
        struct atabus_initq *initq;
        int i;
-       int s;
 
-       if (chp->atapibus != NULL) {
-               return EBUSY;
-       }
-
-       for (i = 0; i < ATA_MAXDRIVES; i++) {
-               if (chp->ata_drives[i] != NULL) {
+       /*
+        * we can rescan a port multiplier atabus, even if some devices are
+        * still attached 
+        */
+       if (chp->ch_satapmp_nports == 0) {
+               if (chp->atapibus != NULL) {
                        return EBUSY;
                }
-       }
 
-       s = splbio();
-       for (i = 0; i < ATA_MAXDRIVES; i++) {
-               chp->ch_drive[i].drive_flags = 0;
+               KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
+               for (i = 0; i < chp->ch_ndrives; i++) {
+                       if (chp->ch_drive[i].drv_softc != NULL) {
+                               return EBUSY;
+                       }
+               }
        }
-       splx(s);
 
        initq = malloc(sizeof(*initq), M_DEVBUF, M_WAITOK);
        initq->atabus_sc = sc;
Index: dev/ata/ata_wdc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/ata_wdc.c,v
retrieving revision 1.96
diff -u -p -u -r1.96 ata_wdc.c
--- dev/ata/ata_wdc.c   9 Jan 2012 01:01:48 -0000       1.96
+++ dev/ata/ata_wdc.c   23 Jun 2012 13:27:36 -0000
@@ -187,8 +187,10 @@ wdc_ata_bio_start(struct ata_channel *ch
        wait_flags = (xfer->c_flags & C_POLL) ? AT_POLL : 0;
 #endif
 
-       ATADEBUG_PRINT(("wdc_ata_bio_start %s:%d:%d\n",
-           device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive),
+       ATADEBUG_PRINT(("wdc_ata_bio_start %s:%d:%d state %d drive_flags 0x%x "
+           "c_flags 0x%x ch_flags 0x%x\n",
+           device_xname(atac->atac_dev), chp->ch_channel, xfer->c_drive,
+           drvp->state, drvp->drive_flags, xfer->c_flags, chp->ch_flags),
            DEBUG_XFERS);
 
        /* Do control operations specially. */
@@ -780,7 +782,7 @@ wdc_ata_bio_kill_xfer(struct ata_channel
                panic("wdc_ata_bio_kill_xfer");
        }
        ata_bio->r_error = WDCE_ABRT;
-       ATADEBUG_PRINT(("wdc_ata_done: drv_done\n"), DEBUG_XFERS);
+       ATADEBUG_PRINT(("wdc_ata_bio_kill_xfer: drv_done\n"), DEBUG_XFERS);
        (*chp->ch_drive[drive].drv_done)(chp->ch_drive[drive].drv_softc);
 }
 
Index: dev/ata/atavar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/atavar.h,v
retrieving revision 1.84
diff -u -p -u -r1.84 atavar.h
--- dev/ata/atavar.h    24 Jan 2012 20:04:07 -0000      1.84
+++ dev/ata/atavar.h    23 Jun 2012 13:27:36 -0000
@@ -37,11 +37,6 @@
 #include <dev/scsipi/atapiconf.h>
 
 /*
- * Max number of drives per channel.
- */
-#define        ATA_MAXDRIVES           2
-
-/*
  * Description of a command to be handled by an ATA controller.  These
  * commands are queued in a list.
  */
@@ -113,22 +108,24 @@ struct ataparams;
 
 /* Datas common to drives and controller drivers */
 struct ata_drive_datas {
+       enum {
+               DRIVET_NONE = 0,
+               DRIVET_ATA,
+               DRIVET_ATAPI,
+               DRIVET_OLD,
+               DRIVET_PM,
+       } drive_type;
        u_int8_t drive;         /* drive number */
        int8_t ata_vers;        /* ATA version supported */
        u_int16_t drive_flags;  /* bitmask for drives present/absent and cap */
-
-#define        DRIVE_ATA       0x0001
-#define        DRIVE_ATAPI     0x0002
-#define        DRIVE_OLD       0x0004
-#define        DRIVE           (DRIVE_ATA|DRIVE_ATAPI|DRIVE_OLD)
-#define        DRIVE_CAP32     0x0008
-#define        DRIVE_DMA       0x0010
-#define        DRIVE_UDMA      0x0020
-#define        DRIVE_MODE      0x0040  /* the drive reported its mode */
-#define        DRIVE_RESET     0x0080  /* reset the drive state at next xfer */
-#define        DRIVE_WAITDRAIN 0x0100  /* device is waiting for the queue to 
drain */
-#define        DRIVE_ATAPIST   0x0200  /* device is an ATAPI tape drive */
-#define        DRIVE_NOSTREAM  0x0400  /* no stream methods on this drive */
+#define        DRIVE_CAP32     0x0001
+#define        DRIVE_DMA       0x0002
+#define        DRIVE_UDMA      0x0004
+#define        DRIVE_MODE      0x0008  /* the drive reported its mode */
+#define        DRIVE_RESET     0x0010  /* reset the drive state at next xfer */
+#define        DRIVE_WAITDRAIN 0x0020  /* device is waiting for the queue to 
drain */
+#define        DRIVE_NOSTREAM  0x0040  /* no stream methods on this drive */
+#define DRIVE_ATAPIDSCW        0x0080  /* needs to wait for DSC in 
phase_complete */
 
        /*
         * Current setting of drive's PIO, DMA and UDMA modes.
@@ -286,7 +283,7 @@ struct ata_command {
 struct ata_bustype {
        int     bustype_type;   /* symbolic name of type */
        int     (*ata_bio)(struct ata_drive_datas *, struct ata_bio *);
-       void    (*ata_reset_drive)(struct ata_drive_datas *, int);
+       void    (*ata_reset_drive)(struct ata_drive_datas *, int, uint32_t *);
        void    (*ata_reset_channel)(struct ata_channel *, int);
 /* extra flags for ata_reset_*(), in addition to AT_* */
 #define AT_RST_EMERG 0x10000 /* emergency - e.g. for a dump */
@@ -347,8 +344,8 @@ struct ata_channel {
        int ch_reset_flags;
 
        /* per-drive info */
-       int ch_ndrive;
-       struct ata_drive_datas ch_drive[ATA_MAXDRIVES];
+       int ch_ndrives; /* number of entries in ch_drive[] */
+       struct ata_drive_datas *ch_drive; /* array of ata_drive_datas */
 
        device_t atabus;        /* self */
 
@@ -356,9 +353,6 @@ struct ata_channel {
        device_t atapibus;
        struct scsipi_channel ch_atapi_channel;
 
-       /* ATA children */
-       device_t ata_drives[ATA_MAXDRIVES];
-
        /*
         * Channel queues.  May be the same for all channels, if hw
         * channels are not independent.
@@ -367,6 +361,9 @@ struct ata_channel {
 
        /* The channel kernel thread */
        struct lwp *ch_thread;
+
+       /* Number of sata PMP ports, if any */
+       int ch_satapmp_nports;
 };
 
 /*
@@ -434,6 +431,9 @@ void        ata_channel_attach(struct ata_chann
 int    atabusprint(void *aux, const char *);
 int    ataprint(void *aux, const char *);
 
+int    atabus_alloc_drives(struct ata_channel *, int);
+void   atabus_free_drives(struct ata_channel *);
+
 struct ataparams;
 int    ata_get_params(struct ata_drive_datas *, u_int8_t, struct ataparams *);
 int    ata_set_mode(struct ata_drive_datas *, u_int8_t, u_int8_t);
Index: dev/ata/files.ata
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/files.ata,v
retrieving revision 1.21
diff -u -p -u -r1.21 files.ata
--- dev/ata/files.ata   17 Jun 2009 03:07:51 -0000      1.21
+++ dev/ata/files.ata   23 Jun 2012 13:27:36 -0000
@@ -34,3 +34,6 @@ file  dev/ata/sata_subr.c             sata                    
needs-f
 
 # Common SATA FIS subroutines
 file   dev/ata/satafis_subr.c          sata_fis
+
+# SATA port multiplier support
+file   dev/ata/satapmp_subr.c          sata_pmp                needs-flag
Index: dev/ata/sata_subr.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/sata_subr.c,v
retrieving revision 1.15
diff -u -p -u -r1.15 sata_subr.c
--- dev/ata/sata_subr.c 15 May 2012 19:01:10 -0000      1.15
+++ dev/ata/sata_subr.c 23 Jun 2012 13:27:36 -0000
@@ -41,6 +41,7 @@ __KERNEL_RCSID(0, "$NetBSD: sata_subr.c,
 
 #include <dev/ata/satareg.h>
 #include <dev/ata/satavar.h>
+#include <dev/ata/satapmpreg.h>
 
 /*
  * sata_speed:
@@ -146,3 +147,53 @@ sata_reset_interface(struct ata_channel 
        }
        return(sstatus & SStatus_DET_mask);
 }
+
+void
+sata_interpet_sig(struct ata_channel *chp, int port, uint32_t sig)
+{
+       int err;
+       int s;
+
+       /* some ATAPI devices have bogus lower two bytes, sigh */
+       if ((sig & 0xffff0000) == 0xeb140000) {
+               sig &= 0xffff0000;
+               sig |= 0x00000101;
+       }
+       if (chp->ch_drive == NULL) {
+               if (sig == 0x96690101)
+                       err = atabus_alloc_drives(chp, PMP_MAX_DRIVES);
+               else
+                       err = atabus_alloc_drives(chp, 1);
+               if (err)
+                       return;
+       }
+       KASSERT(port < chp->ch_ndrives);
+
+       s = splbio();
+       switch(sig) {
+       case 0x96690101:
+               KASSERT(port == 0 || port == PMP_PORT_CTL);
+               chp->ch_drive[PMP_PORT_CTL].drive_type = DRIVET_PM;
+               break;
+       case 0xc33c0101:
+               aprint_verbose_dev(chp->atabus, "port %d is SEMB, ignored\n",
+                   port);
+               break;
+       case 0xeb140101:
+               chp->ch_drive[port].drive_type = DRIVET_ATAPI;
+               break;
+       case 0x00000101:
+               chp->ch_drive[port].drive_type = DRIVET_ATA;
+               break;
+       case 0xffffffff:
+               /* COMRESET time out */
+               break;
+       default:
+               chp->ch_drive[port].drive_type = DRIVET_ATA;
+               aprint_verbose_dev(chp->atabus,
+                   "Unrecognized signature 0x%08x on port %d. "
+                   "Assuming it's a disk.\n", sig, port);
+               break;
+       }
+       splx(s);
+}
Index: dev/ata/satapmp_subr.c
===================================================================
RCS file: dev/ata/satapmp_subr.c
diff -N dev/ata/satapmp_subr.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ dev/ata/satapmp_subr.c      23 Jun 2012 13:27:36 -0000
@@ -0,0 +1,251 @@
+/*     $NetBSD: ata.c,v 1.116 2012/04/06 02:52:00 isaki Exp $  */
+
+/*
+ * Copyright (c) 2012 Manuel Bouyer.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.116 2012/04/06 02:52:00 isaki Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/proc.h>
+#include <sys/errno.h>
+#include <sys/kmem.h>
+#include <sys/intr.h>
+
+#include <dev/ata/ataconf.h>
+#include <dev/ata/atareg.h>
+#include <dev/ata/atavar.h>
+
+#include <dev/ata/satapmpvar.h>
+#include <dev/ata/satapmpreg.h>
+#include <dev/ata/satavar.h>
+#include <dev/ata/satareg.h>
+
+static int
+satapmp_read(struct ata_channel *chp, int port, int reg, uint32_t *value)
+{
+       struct ata_command ata_c;
+       struct atac_softc *atac = chp->ch_atac;
+       struct ata_drive_datas *drvp;
+
+       KASSERT(reg < PMP_GSCR_NREGS);
+       KASSERT(chp->ch_ndrives >= PMP_MAX_DRIVES);
+       drvp = &chp->ch_drive[PMP_PORT_CTL];
+       KASSERT(drvp->drive == PMP_PORT_CTL);
+
+       memset(&ata_c, 0, sizeof(struct ata_command));
+
+       ata_c.r_command = PMPC_READ_PORT;
+       ata_c.r_features = reg;
+       ata_c.r_lba = (port & 0xf) << 24;
+       ata_c.timeout = 3000; /* 3s */
+       ata_c.r_st_bmask = WDCS_DRDY;
+       ata_c.r_st_pmask = 0;
+       ata_c.flags = AT_READREG | AT_WAIT;
+
+       if ((*atac->atac_bustype_ata->ata_exec_command)(drvp,
+           &ata_c) != ATACMD_COMPLETE) {
+               aprint_error_dev(chp->atabus,
+                   "PMP register %d read failed\n", reg);
+               return EIO;
+       }
+       if (ata_c.flags & (AT_TIMEOU | AT_DF)) {
+               aprint_error_dev(chp->atabus,
+                   "PMP register %d read failed, flags 0x%x\n",
+                   reg, ata_c.flags);
+               return EIO;
+       }
+       if (ata_c.flags & AT_ERROR) {
+               aprint_verbose_dev(chp->atabus,
+                   "PMP register %d read failed, error 0x%x\n",
+                   reg, ata_c.r_error);
+               return EIO;
+       }
+       *value = ata_c.r_lba << 8 | ata_c.r_count;
+       return 0;
+}
+
+static int satapmp_write(struct ata_channel *chp, int, int, uint32_t) __unused;
+static int
+satapmp_write(struct ata_channel *chp, int port, int reg, uint32_t value)
+{
+       struct ata_command ata_c;
+       struct atac_softc *atac = chp->ch_atac;
+       struct ata_drive_datas *drvp;
+
+       KASSERT(reg < PMP_GSCR_NREGS);
+       KASSERT(chp->ch_ndrives >= PMP_MAX_DRIVES);
+       drvp = &chp->ch_drive[PMP_PORT_CTL];
+       KASSERT(drvp->drive == PMP_PORT_CTL);
+
+
+       memset(&ata_c, 0, sizeof(struct ata_command));
+
+       ata_c.r_command = PMPC_WRITE_PORT;
+       ata_c.r_features = reg;
+       ata_c.r_lba = (port & 0xf) << 24;
+       ata_c.r_lba |= (value & 0xffffff00) >> 8;
+       ata_c.r_count = value & 0xff;
+       ata_c.timeout = 3000; /* 3s */
+       ata_c.r_st_bmask = WDCS_DRDY;
+       ata_c.r_st_pmask = 0;
+       ata_c.flags = AT_WAIT;
+
+       if ((*atac->atac_bustype_ata->ata_exec_command)(drvp,
+           &ata_c) != ATACMD_COMPLETE) {
+               aprint_error_dev(chp->atabus,
+                   "PMP register %d write failed\n", reg);
+               return EIO;
+       }
+       if (ata_c.flags & (AT_TIMEOU | AT_DF)) {
+               aprint_error_dev(chp->atabus,
+                   "PMP register %d write failed, flags 0x%x\n",
+                   reg, ata_c.flags);
+               return EIO;
+       }
+       if (ata_c.flags & AT_ERROR) {
+               aprint_verbose_dev(chp->atabus,
+                   "PMP register %d write failed, error 0x%x\n",
+                   reg, ata_c.r_error);
+               return EIO;
+       }
+       return 0;
+}
+
+/*
+ * Reset one port's PHY and bring it online
+ * XXX duplicate of sata_reset_interface()
+ */
+static uint32_t
+satapmp_reset_device_port(struct ata_channel *chp, int port)
+{
+       uint32_t scontrol, sstatus;
+       int i;
+
+       /* bring the PHY online */
+       scontrol = SControl_IPM_NONE | SControl_SPD_ANY | SControl_DET_INIT;
+       if (satapmp_write(chp, port, PMP_PSCR_SControl, scontrol) != 0)
+               return 0;
+
+       tsleep(chp, PRIBIO, "sataup", mstohz(50));
+       scontrol &= ~SControl_DET_INIT;
+       if (satapmp_write(chp, port, PMP_PSCR_SControl, scontrol) != 0)
+               return 0;
+       tsleep(chp, PRIBIO, "sataup", mstohz(50));
+
+       /* wait up to 1s for device to come up */
+       for (i = 0; i < 100; i++) {
+               
+               if (satapmp_read(chp, port, PMP_PSCR_SStatus, &sstatus) != 0)
+                       return 0;
+               if ((sstatus & SStatus_DET_mask) == SStatus_DET_DEV)
+                       break;
+               tsleep(chp, PRIBIO, "sataup", mstohz(10));
+       }
+
+       switch (sstatus & SStatus_DET_mask) {
+       case SStatus_DET_NODEV:
+               /* No Device; be silent.  */
+               break;
+       case SStatus_DET_DEV_NE:
+               aprint_error("%s PMP port %d: device connected, but "
+                   "communication not established\n",
+                   device_xname(chp->atabus), port);
+               break;
+       case SStatus_DET_OFFLINE:
+               aprint_error("%s PMP port %d: PHY offline\n",
+                   device_xname(chp->atabus), port);
+               break;
+       case SStatus_DET_DEV:
+               aprint_normal("%s PMP port %d: device present, speed: %s\n",
+                   device_xname(chp->atabus), port, sata_speed(sstatus));
+               break;
+       default:
+               aprint_error("%s PMP port %d: unknown SStatus: 0x%08x\n",
+                   device_xname(chp->atabus), port, sstatus);
+       }
+       return(sstatus & SStatus_DET_mask);
+}
+
+void
+satapmp_rescan(struct ata_channel *chp) {
+       int i;
+       uint32_t sig;
+
+       KASSERT(chp->ch_satapmp_nports <= PMP_PORT_CTL);
+       KASSERT(chp->ch_satapmp_nports <= chp->ch_ndrives);
+
+       for (i = 0; i < chp->ch_satapmp_nports; i++) {
+               if (chp->ch_drive[i].drive_type != DRIVET_NONE ||
+                   satapmp_reset_device_port(chp, i) != SStatus_DET_DEV) {
+                       continue;
+               }
+               if (satapmp_write(chp, i, PMP_PSCR_SError, 0xffffffff) != 0) {
+                       aprint_error("%s PMP port %d: can't write SError\n",
+                           device_xname(chp->atabus), i);
+                       continue;
+               }
+               chp->ch_atac->atac_bustype_ata->ata_reset_drive(
+                   &chp->ch_drive[i], AT_WAIT, &sig);
+
+               sata_interpet_sig(chp, i, sig);
+       }
+}
+
+void
+satapmp_attach(struct ata_channel *chp)
+{
+       uint32_t id, rev, inf;
+
+       if (satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_ID, &id) != 0 ||
+           satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_REV, &rev) != 0 ||
+           satapmp_read(chp, PMP_PORT_CTL, PMP_GSCR_INF, &inf) != 0) {
+               aprint_normal_dev(chp->atabus, "can't read PMP registers\n");
+               return;
+       }
+
+       aprint_normal_dev(chp->atabus,
+           "SATA port multiplier, %d ports\n", PMP_INF_NPORTS(inf));
+       aprint_verbose_dev(chp->atabus,
+           "vendor 0x%x, product 0x%x",
+           PMP_ID_VEND(id), PMP_ID_DEV(id));
+       if (rev & PMP_REV_SPEC_11) {
+               aprint_verbose(", revision 1.1");
+       } else if (rev & PMP_REV_SPEC_10) {
+               aprint_verbose(", revision 1.0");
+       } else {
+               aprint_verbose(", unknown revision 0x%x", rev & 0x0f);
+       }
+       aprint_verbose(", level %d\n", PMP_REV_LEVEL(rev));
+
+       chp->ch_satapmp_nports = PMP_INF_NPORTS(inf);
+
+       /* reset and bring up PHYs */
+       satapmp_rescan(chp);
+}
Index: dev/ata/satapmpreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/satapmpreg.h,v
retrieving revision 1.3
diff -u -p -u -r1.3 satapmpreg.h
--- dev/ata/satapmpreg.h        28 Apr 2008 20:23:47 -0000      1.3
+++ dev/ata/satapmpreg.h        23 Jun 2012 13:27:36 -0000
@@ -37,7 +37,7 @@
  */
 
 #define PMP_GSCR_ID    0x00            /* product and vendor id */
-#define        PMP_ID_DEV(x)   ((x) << 16)
+#define        PMP_ID_DEV(x)   ((x) >> 16)
 #define                PMP_ID_VEND(x)  ((x) & 0xffff)
 #define PMP_GSCR_REV   0x01            /* revision */
 #define                PMP_REV_SPEC_10         0x02
@@ -79,4 +79,7 @@
 #define PMPC_READ_PORT         0xe4
 #define PMPC_WRITE_PORT                0xe8
 
+/* max number of drives (last one being the PM itself */
+#define PMP_MAX_DRIVES         16
+
 #endif /* _DEV_ATA_SATAPMPREG_H_ */
Index: dev/ata/satapmpvar.h
===================================================================
RCS file: dev/ata/satapmpvar.h
diff -N dev/ata/satapmpvar.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ dev/ata/satapmpvar.h        23 Jun 2012 13:27:36 -0000
@@ -0,0 +1,35 @@
+/*     $NetBSD: atavar.h,v 1.84 2012/01/24 20:04:07 jakllsch Exp $     */
+
+
+/*
+ * Copyright (c) 2012 Manuel Bouyer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_ATA_SATAPMPVAR_H_
+#define        _DEV_ATA_SATAPMPVAR_H_
+
+void satapmp_attach(struct ata_channel *);
+void satapmp_rescan(struct ata_channel *);
+
+#endif /* _DEV_ATA_SATAPMPVAR_H_ */
+
Index: dev/ata/satavar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/satavar.h,v
retrieving revision 1.5
diff -u -p -u -r1.5 satavar.h
--- dev/ata/satavar.h   28 Apr 2008 20:23:47 -0000      1.5
+++ dev/ata/satavar.h   23 Jun 2012 13:27:36 -0000
@@ -42,5 +42,6 @@
 const char *sata_speed(uint32_t);
 uint32_t sata_reset_interface(struct ata_channel *, bus_space_tag_t,
     bus_space_handle_t, bus_space_handle_t);
+void   sata_interpet_sig(struct ata_channel *, int, uint32_t);
 
 #endif /* _DEV_ATA_SATAVAR_H_ */
Index: dev/ata/wd.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ata/wd.c,v
retrieving revision 1.392
diff -u -p -u -r1.392 wd.c
--- dev/ata/wd.c        2 Feb 2012 19:43:02 -0000       1.392
+++ dev/ata/wd.c        23 Jun 2012 13:27:36 -0000
@@ -283,7 +283,8 @@ wdattach(device_t parent, device_t self,
        wd->drvp = adev->adev_drv_data;
 
        wd->drvp->drv_done = wddone;
-       wd->drvp->drv_softc = wd->sc_dev;
+       wd->drvp->drv_softc = wd->sc_dev; /* done in atabusconfig_thread()
+                                            but too late */
 
        aprint_naive("\n");
        aprint_normal("\n");
@@ -291,7 +292,7 @@ wdattach(device_t parent, device_t self,
        /* read our drive info */
        if (wd_get_params(wd, AT_WAIT, &wd->sc_params) != 0) {
                aprint_error_dev(self, "IDENTIFY failed\n");
-               return;
+               goto out;
        }
 
        for (blank = 0, p = wd->sc_params.atap_model, q = tbuf, i = 0;
@@ -380,6 +381,7 @@ wdattach(device_t parent, device_t self,
        ATADEBUG_PRINT(("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n",
            device_xname(self), wd->sc_params.atap_dmatiming_mimi,
            wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE);
+out:
        /*
         * Initialize and attach the disk structure.
         */
@@ -461,7 +463,8 @@ wddetach(device_t self, int flags)
 
        callout_destroy(&sc->sc_restart_ch);
 
-       sc->drvp->drive_flags = 0; /* no drive any more here */
+       sc->drvp->drive_type = DRIVET_NONE; /* no drive any more here */
+       sc->drvp->drive_flags = 0;
 
        return (0);
 }
@@ -772,7 +775,7 @@ wddone(void *v)
                errmsg = "error";
                do_perror = 1;
 retry:         /* Just reset and retry. Can we do more ? */
-               (*wd->atabus->ata_reset_drive)(wd->drvp, AT_RST_NOCMD);
+               (*wd->atabus->ata_reset_drive)(wd->drvp, AT_RST_NOCMD, NULL);
 retry2:
                diskerr(bp, "wd", errmsg, LOG_PRINTF,
                    wd->sc_wdc_bio.blkdone, wd->sc_dk.dk_label);
@@ -888,6 +891,9 @@ wdopen(dev_t dev, int flag, int fmt, str
        if (! device_is_active(wd->sc_dev))
                return (ENODEV);
 
+       if (wd->sc_capacity == 0)
+               return (ENODEV);
+
        part = WDPART(dev);
 
        mutex_enter(&wd->sc_dk.dk_openlock);
@@ -920,11 +926,15 @@ wdopen(dev_t dev, int flag, int fmt, str
                }
        } else {
                if ((wd->sc_flags & WDF_LOADED) == 0) {
-                       wd->sc_flags |= WDF_LOADED;
 
                        /* Load the physical device parameters. */
-                       wd_get_params(wd, AT_WAIT, &wd->sc_params);
-
+                       if (wd_get_params(wd, AT_WAIT, &wd->sc_params) != 0) {
+                               aprint_error_dev(wd->sc_dev,
+                               "IDENTIFY failed\n");
+                               error = EIO;
+                               goto bad2;
+                       }
+                       wd->sc_flags |= WDF_LOADED;
                        /* Load the partition info if not already loaded. */
                        wdgetdisklabel(wd);
                }
@@ -1599,7 +1609,7 @@ wddump(dev_t dev, daddr_t blkno, void *v
        if (wddumprecalibrated == 0) {
                wddumprecalibrated = 1;
                (*wd->atabus->ata_reset_drive)(wd->drvp,
-                                              AT_POLL | AT_RST_EMERG);
+                                              AT_POLL | AT_RST_EMERG, NULL);
                wd->drvp->state = RESET;
        }
 
@@ -1754,6 +1764,8 @@ wd_get_params(struct wd_softc *wd, u_int
        case CMD_AGAIN:
                return 1;
        case CMD_ERR:
+               if (wd->drvp->drive_type != DRIVET_OLD)
+                       return 1;
                /*
                 * We `know' there's a drive here; just assume it's old.
                 * This geometry is only used to read the MBR and print a
Index: dev/ic/ahcisata_core.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/ahcisata_core.c,v
retrieving revision 1.34
diff -u -p -u -r1.34 ahcisata_core.c
--- dev/ic/ahcisata_core.c      20 Apr 2012 20:23:20 -0000      1.34
+++ dev/ic/ahcisata_core.c      23 Jun 2012 13:27:36 -0000
@@ -56,7 +56,7 @@ static void ahci_probe_drive(struct ata_
 static void ahci_setup_channel(struct ata_channel *);
 
 static int  ahci_ata_bio(struct ata_drive_datas *, struct ata_bio *);
-static void ahci_reset_drive(struct ata_drive_datas *, int);
+static void ahci_reset_drive(struct ata_drive_datas *, int, uint32_t *);
 static void ahci_reset_channel(struct ata_channel *, int);
 static int  ahci_exec_command(struct ata_drive_datas *, struct ata_command *);
 static int  ahci_ata_addref(struct ata_drive_datas *);
@@ -394,7 +394,6 @@ ahci_attach(struct ahci_softc *sc)
                        }
                }
                ahci_setup_port(sc, i);
-               chp->ch_ndrive = 1;
                if (bus_space_subregion(sc->sc_ahcit, sc->sc_ahcih,
                    AHCI_P_SSTS(i), 4,  &achp->ahcic_sstatus) != 0) {
                        aprint_error("%s: couldn't map channel %d "
@@ -563,9 +562,10 @@ ahci_intr_port(struct ahci_softc *sc, st
 }
 
 static void
-ahci_reset_drive(struct ata_drive_datas *drvp, int flags)
+ahci_reset_drive(struct ata_drive_datas *drvp, int flags, uint32_t *sigp)
 {
        struct ata_channel *chp = drvp->chnl_softc;
+       KASSERT(sigp == NULL);
        ata_reset_channel(chp, flags);
        return;
 }
@@ -634,15 +634,9 @@ ahci_probe_drive(struct ata_channel *chp
 {
        struct ahci_softc *sc = (struct ahci_softc *)chp->ch_atac;
        struct ahci_channel *achp = (struct ahci_channel *)chp;
-       int i, s;
+       int i;
        uint32_t sig;
 
-       /* XXX This should be done by other code. */
-       for (i = 0; i < chp->ch_ndrive; i++) {
-               chp->ch_drive[i].chnl_softc = chp;
-               chp->ch_drive[i].drive = i;
-       }
-
        /* bring interface up, accept FISs, power up and spin up device */
        AHCI_WRITE(sc, AHCI_P_CMD(chp->ch_channel),
            AHCI_P_CMD_ICC_AC | AHCI_P_CMD_FRE |
@@ -675,16 +669,8 @@ ahci_probe_drive(struct ata_channel *chp
                AHCIDEBUG_PRINT(("%s: port %d: sig=0x%x CMD=0x%x\n",
                    AHCINAME(sc), chp->ch_channel, sig,
                    AHCI_READ(sc, AHCI_P_CMD(chp->ch_channel))), DEBUG_PROBE);
-               /*
-                * scnt and sn are supposed to be 0x1 for ATAPI, but in some
-                * cases we get wrong values here, so ignore it.
-                */
-               s = splbio();
-               if ((sig & 0xffff0000) == 0xeb140000) {
-                       chp->ch_drive[0].drive_flags |= DRIVE_ATAPI;
-               } else
-                       chp->ch_drive[0].drive_flags |= DRIVE_ATA;
-               splx(s);
+
+               sata_interpet_sig(chp, 0, sig);
                /* clear port interrupt register */
                AHCI_WRITE(sc, AHCI_P_IS(chp->ch_channel), 0xffffffff);
                /* and enable interrupts */
@@ -1545,7 +1531,7 @@ ahci_atapi_probe_device(struct atapibus_
                return;
 
        /* if no ATAPI device detected at attach time, skip */
-       if ((drvp->drive_flags & DRIVE_ATAPI) == 0) {
+       if (drvp->drive_type != DRIVET_ATAPI) {
                AHCIDEBUG_PRINT(("ahci_atapi_probe_device: drive %d "
                    "not present\n", target), DEBUG_PROBE);
                return;
@@ -1584,7 +1570,7 @@ ahci_atapi_probe_device(struct atapibus_
                        periph->periph_flags |= PERIPH_REMOVABLE;
                if (periph->periph_type == T_SEQUENTIAL) {
                        s = splbio();
-                       drvp->drive_flags |= DRIVE_ATAPIST;
+                       drvp->drive_flags |= DRIVE_ATAPIDSCW;
                        splx(s);
                }
 
@@ -1615,7 +1601,7 @@ ahci_atapi_probe_device(struct atapibus_
                        ata_probe_caps(drvp);
                else {
                        s = splbio();
-                       drvp->drive_flags &= ~DRIVE_ATAPI;
+                       drvp->drive_type = DRIVET_NONE;
                        splx(s);
                }
        } else {
@@ -1624,7 +1610,7 @@ ahci_atapi_probe_device(struct atapibus_
                    AHCINAME(ahcic), chp->ch_channel, target,
                    chp->ch_error), DEBUG_PROBE);
                s = splbio();
-               drvp->drive_flags &= ~DRIVE_ATAPI;
+               drvp->drive_type = DRIVET_NONE;
                splx(s);
        }
 }
Index: dev/ic/mvsata.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/mvsata.c,v
retrieving revision 1.16
diff -u -p -u -r1.16 mvsata.c
--- dev/ic/mvsata.c     20 Apr 2012 20:23:20 -0000      1.16
+++ dev/ic/mvsata.c     23 Jun 2012 13:27:36 -0000
@@ -103,7 +103,7 @@ int mvsata_debug = 2;
 
 #ifndef MVSATA_WITHOUTDMA
 static int mvsata_bio(struct ata_drive_datas *, struct ata_bio *);
-static void mvsata_reset_drive(struct ata_drive_datas *, int);
+static void mvsata_reset_drive(struct ata_drive_datas *, int, uint32_t *);
 static void mvsata_reset_channel(struct ata_channel *, int);
 static int mvsata_exec_command(struct ata_drive_datas *, struct ata_command *);
 static int mvsata_addref(struct ata_drive_datas *);
@@ -304,6 +304,7 @@ mvsata_attach(struct mvsata_softc *sc, s
        sc->sc_wdcdev.sc_atac.atac_atapibus_attach = mvsata_atapibus_attach;
 #endif
 #endif
+       sc->sc_wdcdev.wdc_maxdrives = 1;        /* SATA is always 1 drive */
        sc->sc_wdcdev.sc_atac.atac_probe = wdc_sataprobe;
        sc->sc_wdcdev.sc_atac.atac_set_modes = mvsata_setup_channel;
 
@@ -519,12 +520,14 @@ mvsata_bio(struct ata_drive_datas *drvp,
 }
 
 static void
-mvsata_reset_drive(struct ata_drive_datas *drvp, int flags)
+mvsata_reset_drive(struct ata_drive_datas *drvp, int flags, uint32_t *sigp)
 {
        struct ata_channel *chp = drvp->chnl_softc;
        struct mvsata_port *mvport = (struct mvsata_port *)chp;
        uint32_t edma_c;
 
+       KASSERT(sigp == NULL);
+
        edma_c = MVSATA_EDMA_READ_4(mvport, EDMA_CMD);
 
        DPRINTF(("%s:%d: mvsata_reset_drive: drive=%d (EDMA %sactive)\n",
@@ -789,7 +792,7 @@ mvsata_atapi_probe_device(struct atapibu
                return;
 
        /* if no ATAPI device detected at attach time, skip */
-       if ((drvp->drive_flags & DRIVE_ATAPI) == 0) {
+       if ((drvp->drive_type != DRIVET_ATAPI) {
                DPRINTF(("%s:%d: mvsata_atapi_probe_device:"
                    " drive %d not present\n",
                    device_xname(atac->atac_dev), chp->ch_channel, target));
@@ -830,7 +833,7 @@ mvsata_atapi_probe_device(struct atapibu
                        periph->periph_flags |= PERIPH_REMOVABLE;
                if (periph->periph_type == T_SEQUENTIAL) {
                        s = splbio();
-                       drvp->drive_flags |= DRIVE_ATAPIST;
+                       drvp->drive_flags |= DRIVE_ATAPIDSCW;
                        splx(s);
                }
 
@@ -860,7 +863,7 @@ mvsata_atapi_probe_device(struct atapibu
                        ata_probe_caps(drvp);
                else {
                        s = splbio();
-                       drvp->drive_flags &= ~DRIVE_ATAPI;
+                       drvp->drive_type = DRIVET_NONE;
                        splx(s);
                }
        } else {
@@ -869,7 +872,7 @@ mvsata_atapi_probe_device(struct atapibu
                    device_xname(atac->atac_dev), chp->ch_channel, target,
                    chp->ch_error));
                s = splbio();
-               drvp->drive_flags &= ~DRIVE_ATAPI;
+               drvp->drive_type = DRIVET_NONE;
                splx(s);
        }
 }
@@ -918,11 +921,11 @@ mvsata_setup_channel(struct ata_channel 
            device_xname(MVSATA_DEV2(mvport)), chp->ch_channel));
 
        edma_mode = nodma;
-       for (drive = 0; drive < chp->ch_ndrive; drive++) {
+       for (drive = 0; drive < chp->ch_ndrives; drive++) {
                drvp = &chp->ch_drive[drive];
 
                /* If no drive, skip */
-               if (!(drvp->drive_flags & DRIVE))
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
 
                if (drvp->drive_flags & DRIVE_UDMA) {
@@ -933,7 +936,7 @@ mvsata_setup_channel(struct ata_channel 
                }
 
                if (drvp->drive_flags & (DRIVE_UDMA | DRIVE_DMA))
-                       if (drvp->drive_flags & DRIVE_ATA)
+                       if (drvp->drive_type == DRIVET_ATA)
                                edma_mode = dma;
        }
 
@@ -978,11 +981,11 @@ no_edma:
                aprint_error_dev(MVSATA_DEV2(mvport),
                    "channel %d: can't use EDMA\n", chp->ch_channel);
                s = splbio();
-               for (drive = 0; drive < chp->ch_ndrive; drive++) {
+               for (drive = 0; drive < chp->ch_ndrives; drive++) {
                        drvp = &chp->ch_drive[drive];
 
                        /* If no drive, skip */
-                       if (!(drvp->drive_flags & DRIVE))
+                       if (drvp->drive_type == DRIVET_NONE)
                                continue;
 
                        drvp->drive_flags &= ~(DRIVE_UDMA | DRIVE_DMA);
@@ -2248,7 +2251,7 @@ mvsata_atapi_phase_complete(struct ata_x
        struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
 
        /* wait for DSC if needed */
-       if (drvp->drive_flags & DRIVE_ATAPIST) {
+       if (drvp->drive_flags & DRIVE_ATAPIDSCW) {
                DPRINTFN(1,
                    ("%s:%d:%d: mvsata_atapi_phase_complete: polldsc %d\n",
                    device_xname(atac->atac_dev), chp->ch_channel,
@@ -2823,7 +2826,6 @@ mvsata_port_init(struct mvsata_hc *mvhc,
        chp = &mvport->port_ata_channel;
        chp->ch_channel = channel;
        chp->ch_atac = &sc->sc_wdcdev.sc_atac;
-       chp->ch_ndrive = 1;                     /* SATA is always 1 drive */
        chp->ch_queue = &mvport->port_ata_queue;
        sc->sc_ata_channels[channel] = chp;
 
Index: dev/ic/ninjaata32.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/ninjaata32.c,v
retrieving revision 1.13
diff -u -p -u -r1.13 ninjaata32.c
--- dev/ic/ninjaata32.c 21 Feb 2011 02:32:00 -0000      1.13
+++ dev/ic/ninjaata32.c 23 Jun 2012 13:27:36 -0000
@@ -192,7 +192,7 @@ njata32_attach(struct njata32_softc *sc)
        sc->sc_ch[0].ch_ata_channel.ch_channel = 0;
        sc->sc_ch[0].ch_ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->sc_ch[0].ch_ata_channel.ch_queue = &sc->sc_wdc_chqueue;
-       sc->sc_ch[0].ch_ata_channel.ch_ndrive = 2; /* max number of drives */
+       sc->sc_wdcdev.wdc_maxdrives = 2; /* max number of drives per channel */
 
        /* map ATA registers */
        for (i = 0; i < WDC_NREG; i++) {
@@ -317,16 +317,16 @@ njata32_setup_channel(struct ata_channel
        int drive;
        uint8_t mode;
 
-       KASSERT(chp->ch_ndrive != 0);
+       KASSERT(chp->ch_ndrives != 0);
 
        sc->sc_timing_pio = 0;
 #if 0  /* ATA DMA is currently unused */
        sc->sc_timing_dma = 0;
 #endif
 
-       for (drive = 0; drive < chp->ch_ndrive; drive++) {
+       for (drive = 0; drive < chp->ch_ndrives; drive++) {
                drvp = &chp->ch_drive[drive];
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;       /* no drive */
 
 #if 0  /* ATA DMA is currently unused */
Index: dev/ic/siisata.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/siisata.c,v
retrieving revision 1.17
diff -u -p -u -r1.17 siisata.c
--- dev/ic/siisata.c    15 May 2012 19:06:26 -0000      1.17
+++ dev/ic/siisata.c    23 Jun 2012 13:27:36 -0000
@@ -96,6 +96,7 @@ __KERNEL_RCSID(0, "$NetBSD: siisata.c,v 
 #include <dev/ata/satareg.h>
 #include <dev/ata/satafisvar.h>
 #include <dev/ata/satafisreg.h>
+#include <dev/ata/satapmpreg.h>
 #include <dev/ic/siisatavar.h>
 #include <dev/ic/siisatareg.h>
 
@@ -116,7 +117,7 @@ void siisata_probe_drive(struct ata_chan
 void siisata_setup_channel(struct ata_channel *);
 
 int siisata_ata_bio(struct ata_drive_datas *, struct ata_bio *);
-void siisata_reset_drive(struct ata_drive_datas *, int);
+void siisata_reset_drive(struct ata_drive_datas *, int, uint32_t *);
 void siisata_reset_channel(struct ata_channel *, int);
 int siisata_ata_addref(struct ata_drive_datas *);
 void siisata_ata_delref(struct ata_drive_datas *);
@@ -345,7 +346,6 @@ siisata_attach_port(struct siisata_softc
                }
        }
 
-       chp->ch_ndrive = 1;
        if (bus_space_subregion(sc->sc_prt, sc->sc_prh,
            PRX(chp->ch_channel, PRO_SSTATUS), 4, &schp->sch_sstatus) != 0) {
                aprint_error_dev(sc->sc_atac.atac_dev,
@@ -462,23 +462,29 @@ siisata_intr_port(struct siisata_channel
        xfer = chp->ch_queue->active_xfer;
        slot = SIISATA_NON_NCQ_SLOT;
 
-       SIISATA_DEBUG_PRINT(("%s: %s port %d\n",
-           SIISATANAME(sc), __func__, chp->ch_channel), DEBUG_INTR);
-
        pis = PRREAD(sc, PRX(chp->ch_channel, PRO_PIS));
 
+       SIISATA_DEBUG_PRINT(("%s: %s port %d, pis 0x%x ",
+           SIISATANAME(sc), __func__, chp->ch_channel, pis), DEBUG_INTR);
+
        if (pis & PR_PIS_CMDCMPL) {
                /* get slot status, clearing completion interrupt */
                pss = PRREAD(sc, PRX(chp->ch_channel, PRO_PSS));
+               SIISATA_DEBUG_PRINT(("pss 0x%x\n", pss), DEBUG_INTR);
                /* is this expected? */
                /* XXX improve */
                if ((schp->sch_active_slots & __BIT(slot)) == 0) {
-                       PRWRITE(sc, PRX(chp->ch_channel, PRO_PIS), 0xffffffff);
-                       log(LOG_WARNING, "%s: unexpected command "
+                       aprint_error( "%s: unexpected command "
                            "completion on port %d\n",
                            SIISATANAME(sc), chp->ch_channel);
                        return;
                } 
+               if ((~pss & __BIT(slot)) == 0) {
+                       aprint_error( "%s: unknown slot "
+                           "completion on port %d, pss 0x%x\n",
+                           SIISATANAME(sc), chp->ch_channel, pss);
+                       return;
+               }
        } else if (pis & PR_PIS_CMDERRR) {
                uint32_t ec;
 
@@ -487,8 +493,9 @@ siisata_intr_port(struct siisata_channel
                chp->ch_error = WDCE_CRC;
 
                ec = PRREAD(sc, PRX(chp->ch_channel, PRO_PCE));
+               SIISATA_DEBUG_PRINT(("ec %d\n", ec), DEBUG_INTR);
                if (ec <= PR_PCE_DATAFISERROR) {
-                       if (ec == PR_PCE_DEVICEERROR) {
+                       if (ec == PR_PCE_DEVICEERROR && xfer != NULL) {
                                /* read in specific information about error */
                                prbfis = bus_space_read_stream_4(
                                    sc->sc_prt, sc->sc_prh,
@@ -498,9 +505,10 @@ siisata_intr_port(struct siisata_channel
                        }
                        siisata_reinit_port(chp);
                } else {
-                       aprint_error_dev(sc->sc_atac.atac_dev,
-                           "fatal error %d on channel %d, resetting\n",
-                           ec, chp->ch_channel);
+                       aprint_error_dev(sc->sc_atac.atac_dev, "fatal error %d"
+                           " on channel %d (ctx 0x%x), resetting\n",
+                           ec, chp->ch_channel,
+                           PRREAD(sc, PRX(chp->ch_channel, PRO_PCR)));
                        /* okay, we have a "Fatal Error" */
                        siisata_device_reset(chp);
                }
@@ -515,7 +523,7 @@ siisata_intr_port(struct siisata_channel
 }
 
 void
-siisata_reset_drive(struct ata_drive_datas *drvp, int flags)
+siisata_reset_drive(struct ata_drive_datas *drvp, int flags, uint32_t *sigp)
 {
        struct ata_channel *chp = drvp->chnl_softc;
        struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac;
@@ -532,21 +540,37 @@ siisata_reset_drive(struct ata_drive_dat
        memset(prb, 0, sizeof(struct siisata_prb));
        prb->prb_control =
            htole16(PRB_CF_SOFT_RESET | PRB_CF_INTERRUPT_MASK);
+       KASSERT(drvp->drive <= PMP_PORT_CTL);
+       prb->prb_fis[rhd_c] = drvp->drive;
 
        siisata_activate_prb(schp, slot);
 
-       for(i = 0; i < 31000; i++) {
-               if (PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)) &
-                   PR_PXSS(slot))
-                       DELAY(1000);
-               else
+       for(i = 0; i < 3100; i++) {
+               if ((PRREAD(sc, PRX(chp->ch_channel, PRO_PSS)) &
+                   PR_PXSS(slot)) == 0)
                        break;
+               if (flags & AT_WAIT)
+                       tsleep(schp, PRIBIO, "siiprb", mstohz(10));
+               else
+                       DELAY(10000);
        }
 
        siisata_deactivate_prb(schp, slot);
-
-       log(LOG_DEBUG, "%s: port %d: ch_status %x ch_error %x\n",
-           __func__, chp->ch_channel, chp->ch_status, chp->ch_error);
+       if (i == 3100) {
+               /* timeout */
+               siisata_device_reset(chp);
+               if (sigp)
+                       *sigp = 0xffffffff;
+       } else {
+               /* read the signature out of the FIS */
+               if (sigp) {
+                       *sigp = 0;
+                       *sigp |= (PRREAD(sc, PRSX(chp->ch_channel, slot,
+                           PRSO_FIS+0x4)) & 0x00ffffff) << 8;
+                       *sigp |= PRREAD(sc, PRSX(chp->ch_channel, slot,
+                           PRSO_FIS+0xc)) & 0xff;
+               }
+       }
 
 #if 1
        /* attempt to downgrade signaling in event of CRC error */
@@ -571,7 +595,6 @@ siisata_reset_drive(struct ata_drive_dat
        chp->ch_status = 0;
        chp->ch_error = 0;
 #endif
-
        return;
 }
 
@@ -627,7 +650,6 @@ siisata_probe_drive(struct ata_channel *
        struct siisata_softc *sc = (struct siisata_softc *)chp->ch_atac;
        struct siisata_channel *schp = (struct siisata_channel *)chp;
        int i;
-       int s;
        uint32_t sig;
        int slot = SIISATA_NON_NCQ_SLOT;
        struct siisata_prb *prb;
@@ -636,12 +658,6 @@ siisata_probe_drive(struct ata_channel *
        SIISATA_DEBUG_PRINT(("%s: %s: port %d start\n", SIISATANAME(sc),
            __func__, chp->ch_channel), DEBUG_FUNCS);
 
-       /* XXX This should be done by other code. */
-       for (i = 0; i < chp->ch_ndrive; i++) {
-               chp->ch_drive[i].chnl_softc = chp;
-               chp->ch_drive[i].drive = i;
-       }
-
        /*
         * disable port interrupt as we're polling for PHY up and
         * prb completion
@@ -661,6 +677,7 @@ siisata_probe_drive(struct ata_channel *
                prb = schp->sch_prb[slot];
                memset(prb, 0, sizeof(struct siisata_prb));
                prb->prb_control = htole16(PRB_CF_SOFT_RESET);
+               prb->prb_fis[rhd_c] = PMP_PORT_CTL;
 
                siisata_activate_prb(schp, slot);
 
@@ -703,28 +720,10 @@ siisata_probe_drive(struct ata_channel *
                SIISATA_DEBUG_PRINT(("%s: %s: sig=0x%08x\n", SIISATANAME(sc),
                    __func__, sig), DEBUG_PROBE);
 
-               /* some ATAPI devices have bogus lower two bytes, sigh */
-               if ((sig & 0xffff0000) == 0xeb140000) {
-                       sig &= 0xffff0000;
-                       sig |= 0x00000101;
-               }
-
-               s = splbio();
-               switch (sig) {
-               case 0xeb140101:
-                       chp->ch_drive[0].drive_flags |= DRIVE_ATAPI;
-                       break;
-               case 0x00000101:
-                       chp->ch_drive[0].drive_flags |= DRIVE_ATA;
-                       break;
-               default:
-                       chp->ch_drive[0].drive_flags |= DRIVE_ATA;
-                       aprint_verbose_dev(sc->sc_atac.atac_dev,
-                           "Unrecognized signature 0x%08x on port %d. "
-                           "Assuming it's a disk.\n", sig, chp->ch_channel);
-                       break;
-               }
-               splx(s);
+               if (sig == 0x96690101)
+                       PRWRITE(sc, PRX(chp->ch_channel, PRO_PCS),
+                           PR_PC_PMP_ENABLE);
+               sata_interpet_sig(chp, 0, sig);
                break;
        default:
                break;
@@ -808,8 +807,11 @@ siisata_cmd_start(struct ata_channel *ch
        struct siisata_prb *prb;
        int i;
 
-       SIISATA_DEBUG_PRINT(("%s: %s port %d, slot %d\n",
-           SIISATANAME(sc), __func__, chp->ch_channel, slot), DEBUG_FUNCS);
+       SIISATA_DEBUG_PRINT(("%s: %s port %d drive %d command 0x%x, slot %d\n",
+           SIISATANAME((struct siisata_softc *)chp->ch_atac),
+           __func__, chp->ch_channel, xfer->c_drive,
+           ata_c->r_command, slot),
+           DEBUG_FUNCS|DEBUG_XFERS);
 
        chp->ch_status = 0;
        chp->ch_error = 0;
@@ -818,6 +820,8 @@ siisata_cmd_start(struct ata_channel *ch
        memset(prb, 0, sizeof(struct siisata_prb));
 
        satafis_rhd_construct_cmd(ata_c, prb->prb_fis);
+       KASSERT(xfer->c_drive <= PMP_PORT_CTL);
+       prb->prb_fis[rhd_c] |= xfer->c_drive;
 
        memset(prb->prb_atapi, 0, sizeof(prb->prb_atapi));
 
@@ -857,15 +861,14 @@ siisata_cmd_start(struct ata_channel *ch
        }
 
        if ((ata_c->flags & AT_DONE) == 0) {
-               ata_c->flags |= AT_TIMEOU;
-               siisata_cmd_complete(chp, xfer, slot);
+               siisata_timeout(chp);
        }
 
        /* reenable interrupts */
        siisata_enable_port_interrupt(chp);
 out:
        SIISATA_DEBUG_PRINT(
-           ("%s: %s: done\n", SIISATANAME(sc), __func__), DEBUG_FUNCS);
+           ("%s: %s: done\n", SIISATANAME((struct siisata_softc 
*)chp->ch_atac), __func__), DEBUG_FUNCS);
        return;
 }
 
@@ -899,7 +902,7 @@ siisata_cmd_complete(struct ata_channel 
 #endif
 
        SIISATA_DEBUG_PRINT(
-           ("%s: %s\n", SIISATANAME(sc), __func__), DEBUG_FUNCS);
+           ("%s: %s\n", SIISATANAME(sc), __func__), DEBUG_FUNCS|DEBUG_XFERS);
 
        chp->ch_flags &= ~ATACH_IRQ_WAIT;
        if (xfer->c_flags & C_TIMEOU)
@@ -936,7 +939,8 @@ siisata_cmd_done(struct ata_channel *chp
        int i;
 
        SIISATA_DEBUG_PRINT(
-           ("%s: %s.\n", SIISATANAME(sc), __func__), DEBUG_FUNCS);
+           ("%s: %s flags 0x%x error 0x%x\n", SIISATANAME(sc), __func__,
+               ata_c->flags, ata_c->r_error), DEBUG_FUNCS|DEBUG_XFERS);
 
        siisata_deactivate_prb(schp, slot);
 
@@ -1016,7 +1020,7 @@ siisata_bio_start(struct ata_channel *ch
 
        SIISATA_DEBUG_PRINT(
            ("%s: %s port %d, slot %d\n",
-           SIISATANAME(sc), __func__, chp->ch_channel, slot),
+           SIISATANAME((struct siisata_softc *)chp->ch_atac), __func__, 
chp->ch_channel, slot),
            DEBUG_FUNCS);
 
        chp->ch_status = 0;
@@ -1026,6 +1030,8 @@ siisata_bio_start(struct ata_channel *ch
        memset(prb, 0, sizeof(struct siisata_prb));
 
        satafis_rhd_construct_bio(xfer, prb->prb_fis);
+       KASSERT(xfer->c_drive <= PMP_PORT_CTL);
+       prb->prb_fis[rhd_c] |= xfer->c_drive;
 
        memset(prb->prb_atapi, 0, sizeof(prb->prb_atapi));
 
@@ -1065,7 +1071,7 @@ siisata_bio_start(struct ata_channel *ch
        siisata_enable_port_interrupt(chp);
 out:
        SIISATA_DEBUG_PRINT(
-           ("%s: %s: done\n", SIISATANAME(sc), __func__), DEBUG_FUNCS);
+           ("%s: %s: done\n", SIISATANAME((struct siisata_softc 
*)chp->ch_atac), __func__), DEBUG_FUNCS);
        return;
 }
 
@@ -1167,6 +1173,7 @@ siisata_timeout(void *v)
        int slot = SIISATA_NON_NCQ_SLOT;
        int s = splbio();
        SIISATA_DEBUG_PRINT(("%s: %p\n", __func__, xfer), DEBUG_INTR);
+       siisata_device_reset(chp);
        if ((chp->ch_flags & ATACH_IRQ_WAIT) != 0) {
                xfer->c_flags |= C_TIMEOU;
                xfer->c_intr(chp, xfer, slot);
@@ -1270,6 +1277,8 @@ siisata_reinit_port(struct ata_channel *
        PRWRITE(sc, PRX(chp->ch_channel, PRO_PCS), PR_PC_PORT_INITIALIZE);
        while (!(PRREAD(sc, PRX(chp->ch_channel, PRO_PS)) & PR_PS_PORT_READY))
                DELAY(10);
+       if (chp->ch_ndrives > 1)
+               PRWRITE(sc, PRX(chp->ch_channel, PRO_PCS), PR_PC_PMP_ENABLE);
 }
 
 static void
@@ -1386,7 +1395,7 @@ siisata_atapi_probe_device(struct atapib
                return;
 
        /* if no ATAPI device detected at attach time, skip */
-       if ((drvp->drive_flags & DRIVE_ATAPI) == 0) {
+       if (drvp->drive_type == DRIVET_ATAPI) {
                SIISATA_DEBUG_PRINT(("%s: drive %d "
                    "not present\n", __func__, target), DEBUG_PROBE);
                return;
@@ -1424,12 +1433,6 @@ siisata_atapi_probe_device(struct atapib
                periph->periph_type = ATAPI_CFG_TYPE(id->atap_config);
                if (id->atap_config & ATAPI_CFG_REMOV)
                        periph->periph_flags |= PERIPH_REMOVABLE;
-               if (periph->periph_type == T_SEQUENTIAL) {
-                       s = splbio();
-                       drvp->drive_flags |= DRIVE_ATAPIST;
-                       splx(s);
-               }
-
                sa.sa_periph = periph;
                sa.sa_inqbuf.type = ATAPI_CFG_TYPE(id->atap_config);
                sa.sa_inqbuf.removable = id->atap_config & ATAPI_CFG_REMOV ?
@@ -1467,7 +1470,7 @@ siisata_atapi_probe_device(struct atapib
                        ata_probe_caps(drvp);
                else {
                        s = splbio();
-                       drvp->drive_flags &= ~DRIVE_ATAPI;
+                       drvp->drive_type &= DRIVET_NONE;
                        splx(s);
                }
        } else {
@@ -1476,7 +1479,7 @@ siisata_atapi_probe_device(struct atapib
                    __func__, SIISATANAME(siic), chp->ch_channel, target,
                    chp->ch_error), DEBUG_PROBE);
                s = splbio();
-               drvp->drive_flags &= ~DRIVE_ATAPI;
+               drvp->drive_type &= DRIVET_NONE;
                splx(s);
        }
 }
@@ -1555,7 +1558,7 @@ siisata_atapi_start(struct ata_channel *
        int i;
 
        SIISATA_DEBUG_PRINT( ("%s: %s:%d:%d, scsi flags 0x%x\n", __func__,
-           SIISATANAME(sc), chp->ch_channel,
+           SIISATANAME((struct siisata_softc *)chp->ch_atac), chp->ch_channel,
            chp->ch_drive[xfer->c_drive].drive, sc_xfer->xs_control),
            DEBUG_XFERS);
 
@@ -1573,6 +1576,8 @@ siisata_atapi_start(struct ata_channel *
                prbp->prb_control |= htole16(PRB_CF_PACKET_WRITE);
 
        satafis_rhd_construct_atapi(xfer, prbp->prb_fis);
+       KASSERT(xfer->c_drive <= PMP_PORT_CTL);
+       prbp->prb_fis[rhd_c] |= xfer->c_drive;
 
        /* copy over ATAPI command */
        memcpy(prbp->prb_atapi, sc_xfer->cmd, sc_xfer->cmdlen);
@@ -1611,14 +1616,13 @@ siisata_atapi_start(struct ata_channel *
                DELAY(1000);
        }
        if ((sc_xfer->xs_status & XS_STS_DONE) == 0) {
-               sc_xfer->error = XS_TIMEOUT;
-               siisata_atapi_complete(chp, xfer, slot);
+               siisata_timeout(chp);
        }
        /* reenable interrupts */
        siisata_enable_port_interrupt(chp);
 out:
        SIISATA_DEBUG_PRINT(
-           ("%s: %s: done\n", SIISATANAME(sc), __func__), DEBUG_FUNCS);
+           ("%s: %s: done\n", SIISATANAME((struct siisata_softc 
*)chp->ch_atac), __func__), DEBUG_FUNCS);
        return;
 }
 
Index: dev/ic/wdc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wdc.c,v
retrieving revision 1.268
diff -u -p -u -r1.268 wdc.c
--- dev/ic/wdc.c        24 Jan 2012 20:04:08 -0000      1.268
+++ dev/ic/wdc.c        23 Jun 2012 13:27:36 -0000
@@ -208,11 +208,7 @@ wdc_sataprobe(struct ata_channel *chp)
        uint8_t st = 0, sc, sn, cl, ch;
        int i, s;
 
-       /* XXX This should be done by other code. */
-       for (i = 0; i < chp->ch_ndrive; i++) {
-               chp->ch_drive[i].chnl_softc = chp;
-               chp->ch_drive[i].drive = i;
-       }
+       KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
 
        /* reset the PHY and bring online */
        switch (sata_reset_interface(chp, wdr->sata_iot, wdr->sata_control,
@@ -244,15 +240,17 @@ wdc_sataprobe(struct ata_channel *chp)
                    "cl=0x%x ch=0x%x\n",
                    device_xname(chp->ch_atac->atac_dev), chp->ch_channel,
                    sc, sn, cl, ch), DEBUG_PROBE);
+               if (atabus_alloc_drives(chp, 1) != 0)
+                       return;
                /*
                 * sc and sn are supposed to be 0x1 for ATAPI, but in some
                 * cases we get wrong values here, so ignore it.
                 */
                s = splbio();
                if (cl == 0x14 && ch == 0xeb)
-                       chp->ch_drive[0].drive_flags |= DRIVE_ATAPI;
+                       chp->ch_drive[0].drive_type = DRIVET_ATAPI;
                else
-                       chp->ch_drive[0].drive_flags |= DRIVE_ATA;
+                       chp->ch_drive[0].drive_type = DRIVET_ATA;
                splx(s);
 
                /*
@@ -260,7 +258,7 @@ wdc_sataprobe(struct ata_channel *chp)
                 * is up
                 */
                if (wdcreset(chp, RESET_SLEEP) != 0)
-                       chp->ch_drive[0].drive_flags = 0;
+                       chp->ch_drive[0].drive_type = DRIVET_NONE;
                break;
 
        default:
@@ -294,8 +292,11 @@ wdc_drvprobe(struct ata_channel *chp)
        u_int8_t st0 = 0, st1 = 0;
        int i, j, error, s;
 
+       if (atabus_alloc_drives(chp, wdc->wdc_maxdrives) != 0)
+               return;
        if (wdcprobe1(chp, 0) == 0) {
                /* No drives, abort the attach here. */
+               atabus_free_drives(chp);
                return;
        }
 
@@ -306,7 +307,8 @@ wdc_drvprobe(struct ata_channel *chp)
                 * select drive 1 first, so that master is selected on
                 * exit from the loop
                 */
-               if (chp->ch_drive[1].drive_flags & (DRIVE_ATA|DRIVE_OLD)) {
+               if (chp->ch_ndrives > 1 &&
+                   chp->ch_drive[1].drive_type == DRIVET_ATA) {
                        if (wdc->select)
                                wdc->select(chp,1);
                        bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh],
@@ -315,7 +317,7 @@ wdc_drvprobe(struct ata_channel *chp)
                        st1 = bus_space_read_1(wdr->cmd_iot,
                            wdr->cmd_iohs[wd_status], 0);
                }
-               if (chp->ch_drive[0].drive_flags & (DRIVE_ATA|DRIVE_OLD)) {
+               if (chp->ch_drive[0].drive_type == DRIVET_ATA) {
                        if (wdc->select)
                                wdc->select(chp,0);
                        bus_space_write_1(wdr->cmd_iot, wdr->cmd_iohs[wd_sdh],
@@ -326,12 +328,11 @@ wdc_drvprobe(struct ata_channel *chp)
                }
 
 
-               if (((chp->ch_drive[0].drive_flags & (DRIVE_ATA|DRIVE_OLD))
-                       == 0 ||
-                   (st0 & WDCS_DRDY)) &&
-                   ((chp->ch_drive[1].drive_flags & (DRIVE_ATA|DRIVE_OLD))
-                       == 0 ||
-                   (st1 & WDCS_DRDY)))
+               if ((chp->ch_drive[0].drive_type != DRIVET_ATA ||
+                    (st0 & WDCS_DRDY)) &&
+                   (chp->ch_ndrives < 2 ||
+                    chp->ch_drive[1].drive_type != DRIVET_ATA ||
+                    (st1 & WDCS_DRDY)))
                        break;
 #ifdef WDC_NO_IDS
                /* cannot tsleep here (can't enable IPL_BIO interrups),
@@ -342,10 +343,12 @@ wdc_drvprobe(struct ata_channel *chp)
                tsleep(&params, PRIBIO, "atadrdy", 1);
 #endif
        }
-       if ((st0 & WDCS_DRDY) == 0)
-               chp->ch_drive[0].drive_flags &= ~(DRIVE_ATA|DRIVE_OLD);
-       if ((st1 & WDCS_DRDY) == 0)
-               chp->ch_drive[1].drive_flags &= ~(DRIVE_ATA|DRIVE_OLD);
+       if ((st0 & WDCS_DRDY) == 0 &&
+           chp->ch_drive[0].drive_type != DRIVET_ATAPI)
+               chp->ch_drive[0].drive_type = DRIVET_NONE;
+       if (chp->ch_ndrives > 1 && (st1 & WDCS_DRDY) == 0 &&
+           chp->ch_drive[1].drive_type != DRIVET_ATAPI)
+               chp->ch_drive[1].drive_type = DRIVET_NONE;
        splx(s);
 
        ATADEBUG_PRINT(("%s:%d: wait DRDY st0 0x%x st1 0x%x\n",
@@ -355,11 +358,7 @@ wdc_drvprobe(struct ata_channel *chp)
        /* Wait a bit, some devices are weird just after a reset. */
        delay(5000);
 
-       for (i = 0; i < chp->ch_ndrive; i++) {
-               /* XXX This should be done by other code. */
-               chp->ch_drive[i].chnl_softc = chp;
-               chp->ch_drive[i].drive = i;
-
+       for (i = 0; i < chp->ch_ndrives; i++) {
 #if NATA_DMA
                /*
                 * Init error counter so that an error withing the first xfers
@@ -375,7 +374,7 @@ wdc_drvprobe(struct ata_channel *chp)
                        chp->ch_drive[i].drive_flags |= DRIVE_CAP32;
                        splx(s);
                }
-               if ((chp->ch_drive[i].drive_flags & DRIVE) == 0)
+               if (chp->ch_drive[i].drive_type == DRIVET_NONE)
                        continue;
 
                /* Shortcut in case we've been shutdown */
@@ -400,22 +399,17 @@ wdc_drvprobe(struct ata_channel *chp)
                        error = ata_get_params(&chp->ch_drive[i],
                            AT_WAIT | AT_POLL, &params);
                }
-               if (error == CMD_OK) {
-                       /* If IDENTIFY succeeded, this is not an OLD ctrl */
-                       s = splbio();
-                       for (j = 0; j < chp->ch_ndrive; j++)
-                               chp->ch_drive[j].drive_flags &= ~DRIVE_OLD;
-                       splx(s);
-               } else {
-                       s = splbio();
-                       chp->ch_drive[i].drive_flags &=
-                           ~(DRIVE_ATA | DRIVE_ATAPI);
-                       splx(s);
+               if (error != CMD_OK) {
                        ATADEBUG_PRINT(("%s:%d:%d: IDENTIFY failed (%d)\n",
                            device_xname(atac->atac_dev),
                            chp->ch_channel, i, error), DEBUG_PROBE);
-                       if ((chp->ch_drive[i].drive_flags & DRIVE_OLD) == 0)
+                       s = splbio();
+                       if (chp->ch_drive[i].drive_type != DRIVET_ATA ||
+                           (wdc->cap & WDC_CAPABILITY_PREATA) == 0) {
+                               chp->ch_drive[i].drive_type = DRIVET_NONE;
                                continue;
+                       }
+                       splx(s);
                        /*
                         * Pre-ATA drive ?
                         * Test registers writability (Error register not
@@ -439,7 +433,7 @@ wdc_drvprobe(struct ata_channel *chp)
                                    device_xname(atac->atac_dev),
                                    chp->ch_channel, i), DEBUG_PROBE);
                                    s = splbio();
-                                   chp->ch_drive[i].drive_flags &= ~DRIVE_OLD;
+                                   chp->ch_drive[i].drive_type = DRIVET_NONE;
                                    splx(s);
                                    continue;
                        }
@@ -448,7 +442,7 @@ wdc_drvprobe(struct ata_channel *chp)
                                    device_xname(atac->atac_dev),
                                    chp->ch_channel, i), DEBUG_PROBE);
                                s = splbio();
-                               chp->ch_drive[i].drive_flags &= ~DRIVE_OLD;
+                               chp->ch_drive[i].drive_type = DRIVET_NONE;
                                splx(s);
                                continue;
                        }
@@ -460,13 +454,17 @@ wdc_drvprobe(struct ata_channel *chp)
                                    device_xname(atac->atac_dev),
                                    chp->ch_channel, i), DEBUG_PROBE);
                                s = splbio();
-                               chp->ch_drive[i].drive_flags &= ~DRIVE_OLD;
+                               chp->ch_drive[i].drive_type = DRIVET_NONE;
                                splx(s);
                        } else {
                                s = splbio();
-                               for (j = 0; j < chp->ch_ndrive; j++)
-                                       chp->ch_drive[j].drive_flags &=
-                                           ~(DRIVE_ATA | DRIVE_ATAPI);
+                               for (j = 0; j < chp->ch_ndrives; j++) {
+                                       if (chp->ch_drive[i].drive_type !=
+                                           DRIVET_NONE) {
+                                               chp->ch_drive[j].drive_type =
+                                                   DRIVET_OLD;
+                                       }
+                               }
                                splx(s);
                        }
                }
@@ -724,7 +722,7 @@ wdcprobe1(struct ata_channel *chp, int p
         * be something here assume it's ATA or OLD.  Ghost will be killed
         * later in attach routine.
         */
-       for (drive = 0; drive < chp->ch_ndrive; drive++) {
+       for (drive = 0; drive < wdc->wdc_maxdrives; drive++) {
                if ((ret_value & (0x01 << drive)) == 0)
                        continue;
                if (wdc->select)
@@ -750,12 +748,12 @@ wdcprobe1(struct ata_channel *chp, int p
                 * sc & sn are supposed 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 ((wdc->cap & WDC_CAPABILITY_PREATA) != 0)
-                               chp->ch_drive[drive].drive_flags |= DRIVE_OLD;
+               if (chp->ch_drive != NULL) {
+                       if (cl == 0x14 && ch == 0xeb) {
+                               chp->ch_drive[drive].drive_type = DRIVET_ATAPI;
+                       } else {
+                               chp->ch_drive[drive].drive_type = DRIVET_ATA;
+                       }
                }
        }
        /*
@@ -778,7 +776,7 @@ wdcattach(struct ata_channel *chp)
        struct atac_softc *atac = chp->ch_atac;
        struct wdc_softc *wdc = CHAN_TO_WDC(chp);
 
-       KASSERT(chp->ch_ndrive > 0 && chp->ch_ndrive < 3);
+       KASSERT(wdc->wdc_maxdrives > 0 && wdc->wdc_maxdrives <= WDC_MAXDRIVES);
 
        /* default data transfer methods */
        if (wdc->datain_pio == NULL)
@@ -916,10 +914,12 @@ wdcintr(void *arg)
 
 /* Put all disk in RESET state */
 void
-wdc_reset_drive(struct ata_drive_datas *drvp, int flags)
+wdc_reset_drive(struct ata_drive_datas *drvp, int flags, uint32_t *sigp)
 {
        struct ata_channel *chp = drvp->chnl_softc;
 
+       KASSERT(sigp == NULL);
+
        ATADEBUG_PRINT(("wdc_reset_drive %s:%d for drive %d\n",
            device_xname(chp->ch_atac->atac_dev), chp->ch_channel,
            drvp->drive), DEBUG_FUNCS);
@@ -1037,8 +1037,10 @@ wdcreset(struct ata_channel *chp, int po
 #endif
        wdc->reset(chp, poll);
 
-       drv_mask1 = (chp->ch_drive[0].drive_flags & DRIVE) ? 0x01:0x00;
-       drv_mask1 |= (chp->ch_drive[1].drive_flags & DRIVE) ? 0x02:0x00;
+       drv_mask1 = (chp->ch_drive[0].drive_type !=  DRIVET_NONE) ? 0x01:0x00;
+       if (chp->ch_ndrives > 1) 
+               drv_mask1 |=
+                   (chp->ch_drive[1].drive_type != DRIVET_NONE) ? 0x02:0x00;
        drv_mask2 = __wdcwait_reset(chp, drv_mask1,
            (poll == RESET_SLEEP) ? 0 : 1);
        if (drv_mask2 != drv_mask1) {
Index: dev/ic/wdc_upc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wdc_upc.c,v
retrieving revision 1.26
diff -u -p -u -r1.26 wdc_upc.c
--- dev/ic/wdc_upc.c    25 Jan 2009 14:34:14 -0000      1.26
+++ dev/ic/wdc_upc.c    23 Jun 2012 13:27:36 -0000
@@ -89,7 +89,7 @@ wdc_upc_attach(device_t parent, device_t
        sc->sc_channel.ch_channel = 0;
        sc->sc_channel.ch_atac = &sc->sc_wdc.sc_atac;
        sc->sc_channel.ch_queue = &sc->sc_chqueue;
-       sc->sc_channel.ch_ndrive = 2;
+       sc->sc_wdc.wdc_maxdrives = 2;
        for (i = 0; i < WDC_NREG; i++) {
                if (bus_space_subregion(ua->ua_iot, ua->ua_ioh, i,
                    i == 0 ? 4 : 1, &wdr->cmd_iohs[i]) != 0) {
Index: dev/ic/wdcvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/wdcvar.h,v
retrieving revision 1.92
diff -u -p -u -r1.92 wdcvar.h
--- dev/ic/wdcvar.h     9 Jan 2012 01:01:49 -0000       1.92
+++ dev/ic/wdcvar.h     23 Jun 2012 13:27:36 -0000
@@ -43,6 +43,8 @@
 #define WDC_NREG       8 /* number of command registers */
 #define        WDC_NSHADOWREG  2 /* number of command "shadow" registers */
 
+#define WDC_MAXDRIVES  2 /* absolute max number of drives per channel */
+
 struct wdc_regs {
        /* Our registers */
        bus_space_tag_t       cmd_iot;
@@ -74,7 +76,9 @@ struct wdc_softc {
 
        struct wdc_regs *regs;          /* register array (per-channel) */
 
-       int           cap;              /* controller capabilities */
+       int             wdc_maxdrives;  /* max number of drives per channel */
+
+       int             cap;            /* controller capabilities */
 #define WDC_CAPABILITY_NO_EXTRA_RESETS 0x0100 /* only reset once */
 #define WDC_CAPABILITY_PREATA  0x0200  /* ctrl can be a pre-ata one */
 #define WDC_CAPABILITY_WIDEREGS 0x0400  /* Ctrl has wide (16bit) registers  */
@@ -164,7 +168,7 @@ void        wdccommandext(struct ata_channel *,
                      u_int16_t, u_int16_t);
 void   wdccommandshort(struct ata_channel *, int, int);
 void   wdctimeout(void *arg);
-void   wdc_reset_drive(struct ata_drive_datas *, int);
+void   wdc_reset_drive(struct ata_drive_datas *, int, uint32_t *);
 void   wdc_reset_channel(struct ata_channel *, int);
 void   wdc_do_reset(struct ata_channel *, int);
 
Index: dev/isa/wdc_isa.c
===================================================================
RCS file: /cvsroot/src/sys/dev/isa/wdc_isa.c,v
retrieving revision 1.56
diff -u -p -u -r1.56 wdc_isa.c
--- dev/isa/wdc_isa.c   2 Apr 2009 00:09:33 -0000       1.56
+++ dev/isa/wdc_isa.c   23 Jun 2012 13:27:36 -0000
@@ -224,10 +224,10 @@ wdc_isa_attach(device_t parent, device_t
        sc->wdc_chanlist[0] = &sc->ata_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->ata_channel.ch_channel = 0;
        sc->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->ata_channel.ch_queue = &sc->wdc_chqueue;
-       sc->ata_channel.ch_ndrive = 2;
        wdc_init_shadow_regs(&sc->ata_channel);
 
        aprint_normal("\n");
Index: dev/isapnp/wdc_isapnp.c
===================================================================
RCS file: /cvsroot/src/sys/dev/isapnp/wdc_isapnp.c,v
retrieving revision 1.39
diff -u -p -u -r1.39 wdc_isapnp.c
--- dev/isapnp/wdc_isapnp.c     28 Apr 2008 20:23:53 -0000      1.39
+++ dev/isapnp/wdc_isapnp.c     23 Jun 2012 13:27:36 -0000
@@ -156,10 +156,10 @@ wdc_isapnp_attach(device_t parent, devic
        sc->wdc_chanlist[0] = &sc->ata_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->ata_channel.ch_channel = 0;
        sc->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->ata_channel.ch_queue = &sc->wdc_chqueue;
-       sc->ata_channel.ch_ndrive = 2;
 
        wdc_init_shadow_regs(&sc->ata_channel);
 
Index: dev/ofisa/wdc_ofisa.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ofisa/wdc_ofisa.c,v
retrieving revision 1.30
diff -u -p -u -r1.30 wdc_ofisa.c
--- dev/ofisa/wdc_ofisa.c       18 Mar 2008 20:46:36 -0000      1.30
+++ dev/ofisa/wdc_ofisa.c       23 Jun 2012 13:27:36 -0000
@@ -158,10 +158,10 @@ wdc_ofisa_attach(device_t parent, device
        sc->sc_chanlist[0] = &sc->sc_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        sc->sc_channel.ch_channel = 0;
        sc->sc_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->sc_channel.ch_queue = &sc->sc_chqueue;
-       sc->sc_channel.ch_ndrive = 2;
 
        wdc_init_shadow_regs(&sc->sc_channel);
 
Index: dev/pci/acardide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/acardide.c,v
retrieving revision 1.25
diff -u -p -u -r1.25 acardide.c
--- dev/pci/acardide.c  4 Apr 2011 20:37:56 -0000       1.25
+++ dev/pci/acardide.c  23 Jun 2012 13:27:36 -0000
@@ -159,6 +159,7 @@ acard_chip_map(struct pciide_softc *sc, 
        sc->sc_wdcdev.sc_atac.atac_set_modes = acard_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 2;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
@@ -220,7 +221,7 @@ acard_setup_channel(struct ata_channel *
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                /* add timing values, setup DMA if needed */
                if ((atac->atac_cap & ATAC_CAP_UDMA) &&
Index: dev/pci/aceride.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/aceride.c,v
retrieving revision 1.30
diff -u -p -u -r1.30 aceride.c
--- dev/pci/aceride.c   4 Apr 2011 20:37:56 -0000       1.30
+++ dev/pci/aceride.c   23 Jun 2012 13:27:36 -0000
@@ -152,6 +152,7 @@ acer_chip_map(struct pciide_softc *sc, c
        sc->sc_wdcdev.sc_atac.atac_set_modes = acer_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        pciide_pci_write(sc->sc_pc, sc->sc_tag, ACER_CDRC,
            (pciide_pci_read(sc->sc_pc, sc->sc_tag, ACER_CDRC) |
@@ -281,7 +282,7 @@ acer_setup_channel(struct ata_channel *c
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                ATADEBUG_PRINT(("acer_setup_channel: old timings reg for "
                    "channel %d drive %d 0x%x\n", chp->ch_channel, drive,
Index: dev/pci/artsata.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/artsata.c,v
retrieving revision 1.21
diff -u -p -u -r1.21 artsata.c
--- dev/pci/artsata.c   4 Apr 2011 20:37:56 -0000       1.21
+++ dev/pci/artsata.c   23 Jun 2012 13:27:36 -0000
@@ -233,7 +233,6 @@ artisea_chansetup(struct pciide_softc *s
        cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        cp->ata_channel.ch_queue =
            malloc(sizeof(struct ata_queue), M_DEVBUF, M_NOWAIT);
-       cp->ata_channel.ch_ndrive = 2;
        if (cp->ata_channel.ch_queue == NULL) {
                aprint_error("%s %s channel: "
                    "can't allocate memory for command queue",
@@ -349,6 +348,7 @@ artisea_chip_map_dpa(struct pciide_softc
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = ARTISEA_NUM_CHAN;
        sc->sc_wdcdev.sc_atac.atac_probe = wdc_sataprobe;
+       sc->sc_wdcdev.wdc_maxdrives = 1;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
Index: dev/pci/cmdide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/cmdide.c,v
retrieving revision 1.32
diff -u -p -u -r1.32 cmdide.c
--- dev/pci/cmdide.c    4 Apr 2011 20:37:56 -0000       1.32
+++ dev/pci/cmdide.c    23 Jun 2012 13:27:36 -0000
@@ -148,6 +148,7 @@ cmd_channel_map(const struct pci_attach_
        cp->name = PCIIDE_CHANNEL_NAME(channel);
        cp->ata_channel.ch_channel = channel;
        cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        /*
         * Older CMD64X doesn't have independent channels
@@ -174,7 +175,6 @@ cmd_channel_map(const struct pci_attach_
                    device_xname(sc->sc_wdcdev.sc_atac.atac_dev), cp->name);
                    return;
        }
-       cp->ata_channel.ch_ndrive = 2;
 
        aprint_normal_dev(sc->sc_wdcdev.sc_atac.atac_dev,
            "%s channel %s to %s mode\n", cp->name,
@@ -258,6 +258,7 @@ cmd_chip_map(struct pciide_softc *sc, co
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
        sc->sc_wdcdev.sc_atac.atac_cap = ATAC_CAP_DATA16;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
@@ -378,7 +379,7 @@ cmd0643_9_setup_channel(struct ata_chann
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                /* add timing values, setup DMA if needed */
                tim = cmd0643_9_data_tim_pio[drvp->PIO_mode];
@@ -527,7 +528,6 @@ cmd680_channel_map(const struct pci_atta
                    device_xname(sc->sc_wdcdev.sc_atac.atac_dev), cp->name);
                    return;
        }
-       cp->ata_channel.ch_ndrive = 2;
 
        /* XXX */
        reg = 0xa2 + channel * 16;
@@ -572,7 +572,7 @@ cmd680_setup_channel(struct ata_channel 
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                mode &= ~(0x03 << (drive * 4));
                if (drvp->drive_flags & DRIVE_UDMA) {
Index: dev/pci/cypide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/cypide.c,v
retrieving revision 1.24
diff -u -p -u -r1.24 cypide.c
--- dev/pci/cypide.c    4 Apr 2011 20:37:56 -0000       1.24
+++ dev/pci/cypide.c    23 Jun 2012 13:27:36 -0000
@@ -139,6 +139,7 @@ cy693_chip_map(struct pciide_softc *sc, 
 
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
@@ -150,7 +151,6 @@ cy693_chip_map(struct pciide_softc *sc, 
        cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        cp->ata_channel.ch_queue =
            malloc(sizeof(struct ata_queue), M_DEVBUF, M_NOWAIT);
-       cp->ata_channel.ch_ndrive = 2;
        if (cp->ata_channel.ch_queue == NULL) {
                aprint_error("%s primary channel: "
                    "can't allocate memory for command queue",
@@ -195,7 +195,7 @@ cy693_setup_channel(struct ata_channel *
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                /* add timing values, setup DMA if needed */
                if (drvp->drive_flags & DRIVE_DMA) {
Index: dev/pci/geodeide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/geodeide.c,v
retrieving revision 1.19
diff -u -p -u -r1.19 geodeide.c
--- dev/pci/geodeide.c  4 Apr 2011 20:37:56 -0000       1.19
+++ dev/pci/geodeide.c  23 Jun 2012 13:27:36 -0000
@@ -136,6 +136,7 @@ geodeide_chip_map(struct pciide_softc *s
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
        sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16 | ATAC_CAP_DATA32;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        /*
         * Soekris Engineering Issue #0003:
@@ -203,7 +204,7 @@ geodeide_setup_channel(struct ata_channe
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
 
                switch (sc->sc_pp->ide_product) {
Index: dev/pci/hptide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/hptide.c,v
retrieving revision 1.28
diff -u -p -u -r1.28 hptide.c
--- dev/pci/hptide.c    4 Apr 2011 20:37:56 -0000       1.28
+++ dev/pci/hptide.c    23 Jun 2012 13:27:36 -0000
@@ -199,6 +199,7 @@ hpt_chip_map(struct pciide_softc *sc, co
                else
                        sc->sc_wdcdev.sc_atac.atac_udma_cap = 5;
        }
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
@@ -334,10 +335,10 @@ hpt_setup_channel(struct ata_channel *ch
        }
 
        /* Per drive settings */
-       for (drive = 0; drive < chp->ch_ndrive; drive++) {
+       for (drive = 0; drive < chp->ch_ndrives; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                before = pci_conf_read(sc->sc_pc, sc->sc_tag,
                                        HPT_IDETIM(chp->ch_channel, drive));
Index: dev/pci/iteide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/iteide.c,v
retrieving revision 1.12
diff -u -p -u -r1.12 iteide.c
--- dev/pci/iteide.c    4 Apr 2011 20:37:56 -0000       1.12
+++ dev/pci/iteide.c    23 Jun 2012 13:27:36 -0000
@@ -132,6 +132,7 @@ ite_chip_map(struct pciide_softc *sc, co
        sc->sc_wdcdev.sc_atac.atac_set_modes = ite_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
@@ -188,7 +189,7 @@ ite_setup_channel(struct ata_channel *ch
                drvp = &chp->ch_drive[drive];
 
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
 
                if ((chp->ch_atac->atac_cap & ATAC_CAP_UDMA) != 0 &&
Index: dev/pci/ixpide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/ixpide.c,v
retrieving revision 1.19
diff -u -p -u -r1.19 ixpide.c
--- dev/pci/ixpide.c    4 Apr 2011 20:37:56 -0000       1.19
+++ dev/pci/ixpide.c    23 Jun 2012 13:27:36 -0000
@@ -120,6 +120,7 @@ ixp_chip_map(struct pciide_softc *sc, co
        sc->sc_wdcdev.sc_atac.atac_set_modes = ixp_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        interface = PCI_INTERFACE(pa->pa_class);
 
@@ -187,7 +188,7 @@ ixp_setup_channel(struct ata_channel *ch
 
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                if (drvp->drive_flags & DRIVE_UDMA) {
                        s = splbio();
Index: dev/pci/jmide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/jmide.c,v
retrieving revision 1.13
diff -u -p -u -r1.13 jmide.c
--- dev/pci/jmide.c     29 Mar 2012 00:02:41 -0000      1.13
+++ dev/pci/jmide.c     23 Jun 2012 13:27:36 -0000
@@ -326,6 +326,7 @@ jmpata_chip_map(struct pciide_softc *sc,
        sc->sc_wdcdev.sc_atac.atac_set_modes = jmpata_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        wdc_allocate_regs(&sc->sc_wdcdev);
        /*
          * can't rely on the PCI_CLASS_REG content if the chip was in raid
@@ -395,7 +396,7 @@ jmpata_setup_channel(struct ata_channel 
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                if (drvp->drive_flags & DRIVE_UDMA) {
                        /* use Ultra/DMA */
Index: dev/pci/nside.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/nside.c,v
retrieving revision 1.2
diff -u -p -u -r1.2 nside.c
--- dev/pci/nside.c     4 Apr 2011 20:37:56 -0000       1.2
+++ dev/pci/nside.c     23 Jun 2012 13:27:36 -0000
@@ -129,6 +129,7 @@ natsemi_chip_map(struct pciide_softc *sc
        sc->sc_wdcdev.sc_atac.atac_set_modes = natsemi_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
         interface = PCI_INTERFACE(pa->pa_class);
        interface &= ~PCIIDE_CHANSTATUS_EN;     /* Reserved on PC87415 */
@@ -172,7 +173,7 @@ natsemi_setup_channel(struct ata_channel
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
 
                ndrives++;
Index: dev/pci/optiide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/optiide.c,v
retrieving revision 1.19
diff -u -p -u -r1.19 optiide.c
--- dev/pci/optiide.c   4 Apr 2011 20:37:56 -0000       1.19
+++ dev/pci/optiide.c   23 Jun 2012 13:27:36 -0000
@@ -141,6 +141,7 @@ opti_chip_map(struct pciide_softc *sc, c
 
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        init_ctrl = pciide_pci_read(sc->sc_pc, sc->sc_tag,
            OPTI_REG_INIT_CONTROL);
@@ -197,7 +198,7 @@ opti_setup_channel(struct ata_channel *c
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0) {
+               if (drvp->drive_type == DRIVET_NONE) {
                        mode[drive] = -1;
                        continue;
                }
Index: dev/pci/pciide_common.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pciide_common.c,v
retrieving revision 1.52
diff -u -p -u -r1.52 pciide_common.c
--- dev/pci/pciide_common.c     30 Jan 2012 19:41:22 -0000      1.52
+++ dev/pci/pciide_common.c     23 Jun 2012 13:27:36 -0000
@@ -203,7 +203,7 @@ pciide_common_detach(struct pciide_softc
                                    cp->ctl_baseioh, cp->ctl_ios);
                }
 
-               for (drive = 0; drive < cp->ata_channel.ch_ndrive; drive++) {
+               for (drive = 0; drive < sc->sc_wdcdev.wdc_maxdrives; drive++) {
 #if NATA_DMA
                        pciide_dma_table_teardown(sc, channel, drive);
 #endif
@@ -568,12 +568,12 @@ pciide_channel_dma_setup(struct pciide_c
        struct pciide_softc *sc = CHAN_TO_PCIIDE(&cp->ata_channel);
        struct ata_drive_datas *drvp;
 
-       KASSERT(cp->ata_channel.ch_ndrive != 0);
+       KASSERT(cp->ata_channel.ch_ndrives != 0);
 
-       for (drive = 0; drive < cp->ata_channel.ch_ndrive; drive++) {
+       for (drive = 0; drive < cp->ata_channel.ch_ndrives; drive++) {
                drvp = &cp->ata_channel.ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                /* setup DMA if needed */
                if (((drvp->drive_flags & DRIVE_DMA) == 0 &&
@@ -875,7 +875,6 @@ pciide_chansetup(struct pciide_softc *sc
                device_xname(sc->sc_wdcdev.sc_atac.atac_dev), cp->name);
                return 0;
        }
-       cp->ata_channel.ch_ndrive = 2;
        aprint_verbose_dev(sc->sc_wdcdev.sc_atac.atac_dev,
            "%s channel %s to %s mode\n", cp->name,
            (interface & PCIIDE_INTERFACE_SETTABLE(channel)) ?
@@ -996,6 +995,7 @@ default_chip_map(struct pciide_softc *sc
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
        sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
@@ -1069,7 +1069,7 @@ next:
             channel++) {
                idedma_ctl = 0;
                cp = &sc->pciide_channels[channel];
-               for (drive = 0; drive < cp->ata_channel.ch_ndrive; drive++) {
+               for (drive = 0; drive < sc->sc_wdcdev.wdc_maxdrives; drive++) {
                        /*
                         * we have not probed the drives yet, allocate
                         * ressources for all of them.
@@ -1116,10 +1116,11 @@ sata_setup_channel(struct ata_channel *c
 
        idedma_ctl = 0;
 
-       for (drive = 0; drive < cp->ata_channel.ch_ndrive; drive++) {
+       KASSERT(cp->ata_channel.ch_ndrives != 0);
+       for (drive = 0; drive < cp->ata_channel.ch_ndrives; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
 #if NATA_UDMA
                if (drvp->drive_flags & DRIVE_UDMA) {
Index: dev/pci/pciidevar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pciidevar.h,v
retrieving revision 1.43
diff -u -p -u -r1.43 pciidevar.h
--- dev/pci/pciidevar.h 4 Apr 2011 20:37:56 -0000       1.43
+++ dev/pci/pciidevar.h 23 Jun 2012 13:27:36 -0000
@@ -142,7 +142,7 @@ struct pciide_softc {
                        struct idedma_table *dma_table;
                        bus_dmamap_t    dmamap_xfer;
                        int dma_flags;
-               } dma_maps[ATA_MAXDRIVES];
+               } dma_maps[WDC_MAXDRIVES];
                bus_space_handle_t      dma_iohs[IDEDMA_NREGS];
                /*
                 * Some controllers require certain bits to
Index: dev/pci/pdcide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pdcide.c,v
retrieving revision 1.29
diff -u -p -u -r1.29 pdcide.c
--- dev/pci/pdcide.c    4 Apr 2011 20:37:56 -0000       1.29
+++ dev/pci/pdcide.c    23 Jun 2012 13:27:36 -0000
@@ -233,6 +233,7 @@ pdc202xx_chip_map(struct pciide_softc *s
                        pdc20268_setup_channel : pdc202xx_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
@@ -372,8 +373,8 @@ pdc202xx_setup_channel(struct ata_channe
                    device_xname(sc->sc_wdcdev.sc_atac.atac_dev), channel,
                    bus_space_read_4(sc->sc_dma_iot, sc->sc_dma_ioh,
                    PDC262_ATAPI(channel))), DEBUG_PROBE);
-               if (chp->ch_drive[0].drive_flags & DRIVE_ATAPI ||
-                       chp->ch_drive[1].drive_flags & DRIVE_ATAPI) {
+               if (chp->ch_drive[0].drive_type == DRIVET_ATAPI ||
+                       chp->ch_drive[1].drive_type == DRIVET_ATAPI) {
                        if (((chp->ch_drive[0].drive_flags & DRIVE_UDMA) &&
                            !(chp->ch_drive[1].drive_flags & DRIVE_UDMA) &&
                            (chp->ch_drive[1].drive_flags & DRIVE_DMA)) ||
@@ -390,7 +391,7 @@ pdc202xx_setup_channel(struct ata_channe
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                mode = 0;
                if (drvp->drive_flags & DRIVE_UDMA) {
@@ -417,7 +418,7 @@ pdc202xx_setup_channel(struct ata_channe
                }
                mode = PDC2xx_TIM_SET_PA(mode, pdc2xx_pa[drvp->PIO_mode]);
                mode = PDC2xx_TIM_SET_PB(mode, pdc2xx_pb[drvp->PIO_mode]);
-               if (drvp->drive_flags & DRIVE_ATA)
+               if (drvp->drive_type == DRIVET_ATA)
                        mode |= PDC2xx_TIM_PRE;
                mode |= PDC2xx_TIM_SYNC | PDC2xx_TIM_ERRDY;
                if (drvp->PIO_mode >= 3) {
@@ -468,7 +469,7 @@ pdc20268_setup_channel(struct ata_channe
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                if (drvp->drive_flags & DRIVE_UDMA) {
                        /* use Ultra/DMA */
@@ -594,8 +595,8 @@ pdc20262_dma_finish(void *v, int channel
        if (dma_maps->dma_flags & WDC_DMA_LBA48) {
                chp = sc->wdc_chanarray[channel];
                atapi = 0;
-               if (chp->ch_drive[0].drive_flags & DRIVE_ATAPI ||
-                   chp->ch_drive[1].drive_flags & DRIVE_ATAPI) {
+               if (chp->ch_drive[0].drive_type == DRIVET_ATAPI ||
+                   chp->ch_drive[1].drive_type == DRIVET_ATAPI) {
                        if ((!(chp->ch_drive[0].drive_flags & DRIVE_UDMA) ||
                            (chp->ch_drive[1].drive_flags & DRIVE_UDMA) ||
                            !(chp->ch_drive[1].drive_flags & DRIVE_DMA)) &&
Index: dev/pci/pdcsata.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/pdcsata.c,v
retrieving revision 1.20
diff -u -p -u -r1.20 pdcsata.c
--- dev/pci/pdcsata.c   4 Apr 2011 20:37:56 -0000       1.20
+++ dev/pci/pdcsata.c   23 Jun 2012 13:27:36 -0000
@@ -292,6 +292,7 @@ pdcsata_chip_map(struct pciide_softc *sc
        sc->sc_wdcdev.sc_atac.atac_udma_cap = 6;
        sc->sc_wdcdev.sc_atac.atac_set_modes = pdc203xx_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        sc->sc_wdcdev.reset = pdcsata_do_reset;
 
@@ -302,6 +303,7 @@ pdcsata_chip_map(struct pciide_softc *sc
                    0x00ff0033);
                sc->sc_wdcdev.sc_atac.atac_probe = wdc_sataprobe;
                sc->sc_wdcdev.sc_atac.atac_nchannels = PDC203xx_SATA_NCHANNELS;
+               sc->sc_wdcdev.wdc_maxdrives = 1;
                break;
        case PCI_PRODUCT_PROMISE_PDC20371:
        case PCI_PRODUCT_PROMISE_PDC20375:
@@ -324,6 +326,7 @@ pdcsata_chip_map(struct pciide_softc *sc
                    0x00ff00ff);
                sc->sc_wdcdev.sc_atac.atac_nchannels = PDC40718_SATA_NCHANNELS;
                sc->sc_wdcdev.sc_atac.atac_probe = wdc_sataprobe;
+               sc->sc_wdcdev.wdc_maxdrives = 1;
                break;
 
        case PCI_PRODUCT_PROMISE_PDC20571:
@@ -373,7 +376,6 @@ pdcsata_chip_map(struct pciide_softc *sc
                cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
                cp->ata_channel.ch_queue =
                    malloc(sizeof(struct ata_queue), M_DEVBUF, M_NOWAIT);
-               cp->ata_channel.ch_ndrive = 2;
                if (cp->ata_channel.ch_queue == NULL) {
                        aprint_error("%s channel %d: "
                            "can't allocate memory for command queue\n",
@@ -496,7 +498,7 @@ pdc203xx_setup_channel(struct ata_channe
 
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                if (drvp->drive_flags & DRIVE_UDMA) {
                        s = splbio();
Index: dev/pci/piixide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/piixide.c,v
retrieving revision 1.58
diff -u -p -u -r1.58 piixide.c
--- dev/pci/piixide.c   5 Mar 2012 16:21:44 -0000       1.58
+++ dev/pci/piixide.c   23 Jun 2012 13:27:36 -0000
@@ -486,6 +486,7 @@ piix_chip_map(struct pciide_softc *sc, c
                sc->sc_wdcdev.sc_atac.atac_set_modes = piix3_4_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        ATADEBUG_PRINT(("piix_setup_chip: old idetim=0x%x",
            pci_conf_read(sc->sc_pc, sc->sc_tag, PIIX_IDETIM)),
@@ -676,7 +677,7 @@ end:        /*
         */
        for (drive = 0; drive < 2; drive++) {
                /* If no drive, skip */
-               if ((drvp[drive].drive_flags & DRIVE) == 0)
+               if (drvp[drive].drive_type == DRIVET_NONE)
                        continue;
                idetim |= piix_setup_idetim_drvs(&drvp[drive]);
                if (drvp[drive].drive_flags & DRIVE_DMA)
@@ -721,7 +722,7 @@ piix3_4_setup_channel(struct ata_channel
                    PIIX_UDMATIM_SET(0x3, channel, drive));
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                if (((drvp->drive_flags & DRIVE_DMA) == 0 &&
                    (drvp->drive_flags & DRIVE_UDMA) == 0))
@@ -943,6 +944,7 @@ piixsata_chip_map(struct pciide_softc *s
 
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        cmdsts = pci_conf_read(sc->sc_pc, sc->sc_tag, PCI_COMMAND_STATUS_REG);
        cmdsts &= ~PCI_COMMAND_INTERRUPT_DISABLE;
Index: dev/pci/rccide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/rccide.c,v
retrieving revision 1.21
diff -u -p -u -r1.21 rccide.c
--- dev/pci/rccide.c    4 Apr 2011 20:37:56 -0000       1.21
+++ dev/pci/rccide.c    23 Jun 2012 13:27:36 -0000
@@ -152,6 +152,7 @@ serverworks_chip_map(struct pciide_softc
        sc->sc_wdcdev.sc_atac.atac_set_modes = serverworks_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 2;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
@@ -211,7 +212,7 @@ serverworks_setup_channel(struct ata_cha
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                unit = drive + 2 * channel;
                /* add timing values, setup DMA if needed */
Index: dev/pci/rdcide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/rdcide.c,v
retrieving revision 1.2
diff -u -p -u -r1.2 rdcide.c
--- dev/pci/rdcide.c    4 Apr 2011 22:13:58 -0000       1.2
+++ dev/pci/rdcide.c    23 Jun 2012 13:27:36 -0000
@@ -144,6 +144,7 @@ rdcide_chip_map(struct pciide_softc *sc,
        sc->sc_wdcdev.sc_atac.atac_set_modes = rdcide_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        ATADEBUG_PRINT(("rdcide_setup_chip: old PATR=0x%x",
            pci_conf_read(sc->sc_pc, sc->sc_tag, RDCIDE_PATR)),
@@ -219,9 +220,9 @@ rdcide_setup_channel(struct ata_channel 
        }
        /* now setup modes */
        for (drive = 0; drive < 2; drive++) {
-               if ((drvp[drive].drive_flags & DRIVE) == 0)
+               if (drvp[drive].drive_type == DRIVET_NONE)
                        continue;
-               if ((drvp[drive].drive_flags & DRIVE_ATAPI) == 0)
+               if (drvp[drive].drive_type == DRIVET_ATAPI)
                        patr |= RDCIDE_PATR_ATA(chp->ch_channel, drive);
                if (drive == 0) {
                        patr |= RDCIDE_PATR_SETUP(
Index: dev/pci/satalink.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/satalink.c,v
retrieving revision 1.43
diff -u -p -u -r1.43 satalink.c
--- dev/pci/satalink.c  4 Apr 2011 20:37:56 -0000       1.43
+++ dev/pci/satalink.c  23 Jun 2012 13:27:36 -0000
@@ -505,6 +505,7 @@ sii3112_chip_map(struct pciide_softc *sc
 
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 1;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
@@ -606,7 +607,6 @@ sii3114_chansetup(struct pciide_softc *s
        cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        cp->ata_channel.ch_queue =
            malloc(sizeof(struct ata_queue), M_DEVBUF, M_NOWAIT);
-       cp->ata_channel.ch_ndrive = 2;
        if (cp->ata_channel.ch_queue == NULL) {
                aprint_error("%s %s channel: "
                    "can't allocate memory for command queue",
@@ -750,6 +750,7 @@ sii3114_chip_map(struct pciide_softc *sc
 
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 4;
+       sc->sc_wdcdev.wdc_maxdrives = 1;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
@@ -795,13 +796,7 @@ sii3112_drv_probe(struct ata_channel *ch
        struct wdc_regs *wdr = CHAN_TO_WDC_REGS(chp);
        uint32_t scontrol, sstatus;
        uint8_t scnt, sn, cl, ch;
-       int i, s;
-
-       /* XXX This should be done by other code. */
-       for (i = 0; i < 2; i++) {
-               chp->ch_drive[i].chnl_softc = chp;
-               chp->ch_drive[i].drive = i;
-       }
+       int s;
 
        /*
         * The 3112 is a 2-port part, and only has one drive per channel
@@ -875,15 +870,17 @@ sii3112_drv_probe(struct ata_channel *ch
                    device_xname(&sc->sc_wdcdev.sc_atac.atac_dev), 
chp->ch_channel,
                    scnt, sn, cl, ch);
 #endif
+               if (atabus_alloc_drives(chp, 1) != 0)
+                       return;
                /*
                 * scnt and sn are supposed to be 0x1 for ATAPI, but in some
                 * cases we get wrong values here, so ignore it.
                 */
                s = splbio();
                if (cl == 0x14 && ch == 0xeb)
-                       chp->ch_drive[0].drive_flags |= DRIVE_ATAPI;
+                       chp->ch_drive[0].drive_type = DRIVET_ATAPI;
                else
-                       chp->ch_drive[0].drive_flags |= DRIVE_ATA;
+                       chp->ch_drive[0].drive_type = DRIVET_ATA;
                splx(s);
 
                aprint_normal_dev(sc->sc_wdcdev.sc_atac.atac_dev,
@@ -917,7 +914,7 @@ sii3112_setup_channel(struct ata_channel
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                if (drvp->drive_flags & DRIVE_UDMA) {
                        /* use Ultra/DMA */
Index: dev/pci/schide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/schide.c,v
retrieving revision 1.2
diff -u -p -u -r1.2 schide.c
--- dev/pci/schide.c    4 Apr 2011 20:37:56 -0000       1.2
+++ dev/pci/schide.c    23 Jun 2012 13:27:36 -0000
@@ -140,6 +140,7 @@ sch_chip_map(struct pciide_softc *sc, co
        sc->sc_wdcdev.sc_atac.atac_set_modes = sch_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
 
        ATADEBUG_PRINT(("sch_setup_chip: old d0tim=0x%x, d1tim=0x%x\n",
@@ -184,7 +185,7 @@ sch_setup_channel(struct ata_channel *ch
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
 
                timaddr = (drive == 0) ? SCH_D0TIM : SCH_D1TIM;
Index: dev/pci/siside.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/siside.c,v
retrieving revision 1.28
diff -u -p -u -r1.28 siside.c
--- dev/pci/siside.c    24 May 2011 16:42:10 -0000      1.28
+++ dev/pci/siside.c    23 Jun 2012 13:27:36 -0000
@@ -293,6 +293,7 @@ sis_chip_map(struct pciide_softc *sc, co
 
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        switch(sc->sis_type) {
        case SIS_TYPE_NOUDMA:
        case SIS_TYPE_66:
@@ -357,7 +358,7 @@ sis96x_setup_channel(struct ata_channel 
                    chp->ch_channel, drive);
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                /* add timing values, setup DMA if needed */
                if (drvp->drive_flags & DRIVE_UDMA) {
@@ -423,7 +424,7 @@ sis_setup_channel(struct ata_channel *ch
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                /* add timing values, setup DMA if needed */
                if ((drvp->drive_flags & DRIVE_DMA) == 0 &&
@@ -544,6 +545,7 @@ sis_sata_chip_map(struct pciide_softc *s
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
        sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16 | ATAC_CAP_DATA32;
        sc->sc_wdcdev.sc_atac.atac_set_modes = sata_setup_channel;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
Index: dev/pci/slide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/slide.c,v
retrieving revision 1.23
diff -u -p -u -r1.23 slide.c
--- dev/pci/slide.c     8 Apr 2012 13:08:02 -0000       1.23
+++ dev/pci/slide.c     23 Jun 2012 13:27:36 -0000
@@ -160,6 +160,7 @@ sl82c105_chip_map(struct pciide_softc *s
 
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        idecr = pci_conf_read(sc->sc_pc, sc->sc_tag, SYMPH_IDECSR);
 
@@ -207,7 +208,7 @@ sl82c105_setup_channel(struct ata_channe
 
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip. */
-               if ((drvp->drive_flags & DRIVE) == 0) {
+               if (drvp->drive_type == DRIVET_NONE) {
                        pci_conf_write(sc->sc_pc, sc->sc_tag, pxdx_reg, pxdx);
                        continue;
                }
Index: dev/pci/stpcide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/stpcide.c,v
retrieving revision 1.21
diff -u -p -u -r1.21 stpcide.c
--- dev/pci/stpcide.c   4 Apr 2011 20:37:56 -0000       1.21
+++ dev/pci/stpcide.c   23 Jun 2012 13:27:36 -0000
@@ -109,6 +109,7 @@ stpc_chip_map(struct pciide_softc *sc, c
        sc->sc_wdcdev.sc_atac.atac_set_modes = stpc_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
@@ -158,7 +159,7 @@ stpc_setup_channel(struct ata_channel *c
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                /* add timing values, setup DMA if needed */
                if ((atac->atac_cap & ATAC_CAP_DMA) &&
Index: dev/pci/svwsata.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/svwsata.c,v
retrieving revision 1.13
diff -u -p -u -r1.13 svwsata.c
--- dev/pci/svwsata.c   4 Apr 2011 20:37:56 -0000       1.13
+++ dev/pci/svwsata.c   23 Jun 2012 13:27:36 -0000
@@ -151,6 +151,7 @@ svwsata_chip_map(struct pciide_softc *sc
 
        /* We can use SControl and SStatus to probe for drives. */
        sc->sc_wdcdev.sc_atac.atac_probe = wdc_sataprobe;
+       sc->sc_wdcdev.wdc_maxdrives = 1;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
Index: dev/pci/toshide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/toshide.c,v
retrieving revision 1.4
diff -u -p -u -r1.4 toshide.c
--- dev/pci/toshide.c   4 Apr 2011 20:37:56 -0000       1.4
+++ dev/pci/toshide.c   23 Jun 2012 13:27:36 -0000
@@ -141,6 +141,7 @@ piccolo_chip_map(struct pciide_softc *sc
 
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
        /* 
         * XXX one for now. We'll figure out how to talk to the second channel
         * later, hopefully! Second interface config is via the
@@ -183,7 +184,7 @@ piccolo_setup_channel(struct ata_channel
 
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
 
                if (drvp->drive_flags & DRIVE_UDMA) {
Index: dev/pci/viaide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/viaide.c,v
retrieving revision 1.78
diff -u -p -u -r1.78 viaide.c
--- dev/pci/viaide.c    18 Mar 2012 17:50:43 -0000      1.78
+++ dev/pci/viaide.c    23 Jun 2012 13:27:36 -0000
@@ -614,6 +614,7 @@ via_chip_map(struct pciide_softc *sc, co
        sc->sc_wdcdev.sc_atac.atac_set_modes = via_setup_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE &&
            PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_RAID)
@@ -743,7 +744,7 @@ via_setup_channel(struct ata_channel *ch
        for (drive = 0; drive < 2; drive++) {
                drvp = &chp->ch_drive[drive];
                /* If no drive, skip */
-               if ((drvp->drive_flags & DRIVE) == 0)
+               if (drvp->drive_type == DRIVET_NONE)
                        continue;
                /* add timing values, setup DMA if needed */
                if (((drvp->drive_flags & DRIVE_DMA) == 0 &&
@@ -891,6 +892,7 @@ via_sata_chip_map_common(struct pciide_s
        sc->sc_wdcdev.sc_atac.atac_nchannels = PCIIDE_NUM_CHANNELS;
        sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_DATA16 | ATAC_CAP_DATA32;
        sc->sc_wdcdev.sc_atac.atac_set_modes = sata_setup_channel;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        if (PCI_CLASS(pa->pa_class) == PCI_CLASS_MASS_STORAGE &&
            PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_MASS_STORAGE_RAID)
@@ -960,6 +962,8 @@ via_sata_chip_map(struct pciide_softc *s
                    PCIIDE_INTERFACE_PCI(0) | PCIIDE_INTERFACE_PCI(1);
        }
 
+       sc->sc_wdcdev.sc_atac.atac_probe = wdc_sataprobe;
+       sc->sc_wdcdev.wdc_maxdrives = 1;
        for (channel = 0; channel < sc->sc_wdcdev.sc_atac.atac_nchannels;
             channel++) {
                cp = &sc->pciide_channels[channel];
@@ -993,7 +997,6 @@ via_sata_chip_map(struct pciide_softc *s
                            wdc_cp->ch_channel);
                        continue;
                }
-               sc->sc_wdcdev.sc_atac.atac_probe = wdc_sataprobe;
                pciide_mapchan(pa, cp, interface, pciide_pci_intr);
        }
 }
@@ -1070,7 +1073,6 @@ via_vt6421_chansetup(struct pciide_softc
        cp->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        cp->ata_channel.ch_queue =
            malloc(sizeof(struct ata_queue), M_DEVBUF, M_NOWAIT);
-       cp->ata_channel.ch_ndrive = 2;
        if (cp->ata_channel.ch_queue == NULL) {
                aprint_error("%s channel %d: "
                    "can't allocate memory for command queue",
@@ -1120,6 +1122,7 @@ via_sata_chip_map_new(struct pciide_soft
        
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanarray;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 3;
+       sc->sc_wdcdev.wdc_maxdrives = 2;
 
        wdc_allocate_regs(&sc->sc_wdcdev);
 
@@ -1148,7 +1151,6 @@ via_sata_chip_map_new(struct pciide_soft
                cp = &sc->pciide_channels[channel];
                if (via_vt6421_chansetup(sc, channel) == 0)
                        continue;
-               cp->ata_channel.ch_ndrive = 2;
                wdc_cp = &cp->ata_channel;
                wdr = CHAN_TO_WDC_REGS(wdc_cp);
 
Index: dev/pcmcia/wdc_pcmcia.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pcmcia/wdc_pcmcia.c,v
retrieving revision 1.117
diff -u -p -u -r1.117 wdc_pcmcia.c
--- dev/pcmcia/wdc_pcmcia.c     12 Nov 2009 19:37:17 -0000      1.117
+++ dev/pcmcia/wdc_pcmcia.c     23 Jun 2012 13:27:36 -0000
@@ -294,12 +294,12 @@ wdc_pcmcia_attach(device_t parent, devic
        sc->wdc_chanlist[0] = &sc->ata_channel;
        sc->sc_wdcdev.sc_atac.atac_channels = sc->wdc_chanlist;
        sc->sc_wdcdev.sc_atac.atac_nchannels = 1;
+       sc->sc_wdcdev.wdc_maxdrives = wdcp ? wdcp->wdc_ndrive : 2;
        sc->ata_channel.ch_channel = 0;
        sc->ata_channel.ch_atac = &sc->sc_wdcdev.sc_atac;
        sc->ata_channel.ch_queue = &sc->wdc_chqueue;
        wdcp = pcmcia_product_lookup(pa, wdc_pcmcia_products,
            wdc_pcmcia_nproducts, sizeof(wdc_pcmcia_products[0]), NULL);
-       sc->ata_channel.ch_ndrive = wdcp ? wdcp->wdc_ndrive : 2;
        wdc_init_shadow_regs(&sc->ata_channel);
 
        error = wdc_pcmcia_enable(self, 1);
Index: dev/podulebus/dtide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/podulebus/dtide.c,v
retrieving revision 1.25
diff -u -p -u -r1.25 dtide.c
--- dev/podulebus/dtide.c       18 Mar 2008 20:46:37 -0000      1.25
+++ dev/podulebus/dtide.c       23 Jun 2012 13:27:36 -0000
@@ -93,6 +93,7 @@ dtide_attach(device_t parent, device_t s
        sc->sc_wdc.sc_atac.atac_pio_cap = 0; /* XXX correct? */
        sc->sc_wdc.sc_atac.atac_nchannels = DTIDE_NCHANNELS;
        sc->sc_wdc.sc_atac.atac_channels = sc->sc_chp;
+       sc->sc_wdc.wdc_maxdrives = 2;
        sc->sc_magict = pa->pa_fast_t;
        bus_space_map(pa->pa_fast_t, pa->pa_fast_base + DTIDE_MAGICBASE, 0, 1,
            &sc->sc_magich);
@@ -106,7 +107,6 @@ dtide_attach(device_t parent, device_t s
                wdr->cmd_iot = bst;
                wdr->ctl_iot = bst;
                ch->ch_queue = &sc->sc_chq[i];
-               ch->ch_ndrive = 2;
                bus_space_map(pa->pa_fast_t,
                    pa->pa_fast_base + dtide_cmdoffsets[i], 0, 8,
                    &wdr->cmd_baseioh);
Index: dev/podulebus/hcide.c
===================================================================
RCS file: /cvsroot/src/sys/dev/podulebus/hcide.c,v
retrieving revision 1.22
diff -u -p -u -r1.22 hcide.c
--- dev/podulebus/hcide.c       18 Mar 2008 20:46:37 -0000      1.22
+++ dev/podulebus/hcide.c       23 Jun 2012 13:27:36 -0000
@@ -92,6 +92,7 @@ hcide_attach(device_t parent, device_t s
        sc->sc_wdc.sc_atac.atac_pio_cap = 0; /* XXX correct? */
        sc->sc_wdc.sc_atac.atac_nchannels = HCIDE_NCHANNELS;
        sc->sc_wdc.sc_atac.atac_channels = sc->sc_chp;
+       sc->sc_wdc.wdc_maxdrives = 2;
        aprint_normal("\n");
        for (i = 0; i < HCIDE_NCHANNELS; i++) {
                ch = sc->sc_chp[i] = &sc->sc_chan[i];
@@ -101,7 +102,6 @@ hcide_attach(device_t parent, device_t s
                wdr->cmd_iot = pa->pa_mod_t;
                wdr->ctl_iot = pa->pa_mod_t;
                ch->ch_queue = &sc->sc_chq[i];
-               ch->ch_ndrive = 2;
                bus_space_map(pa->pa_fast_t,
                    pa->pa_fast_base + hcide_cmdoffsets[i], 0, 8,
                    &wdr->cmd_baseioh);
Index: dev/scsipi/atapi_wdc.c
===================================================================
RCS file: /cvsroot/src/sys/dev/scsipi/atapi_wdc.c,v
retrieving revision 1.113
diff -u -p -u -r1.113 atapi_wdc.c
--- dev/scsipi/atapi_wdc.c      20 Apr 2012 20:23:21 -0000      1.113
+++ dev/scsipi/atapi_wdc.c      23 Jun 2012 13:27:36 -0000
@@ -199,7 +199,7 @@ wdc_atapi_get_params(struct scsipi_chann
        struct ata_command ata_c;
 
        /* if no ATAPI device detected at wdc attach time, skip */
-       if ((chp->ch_drive[drive].drive_flags & DRIVE_ATAPI) == 0) {
+       if (chp->ch_drive[drive].drive_type != DRIVET_ATAPI) {
                ATADEBUG_PRINT(("wdc_atapi_get_params: drive %d not present\n",
                    drive), DEBUG_PROBE);
                return -1;
@@ -290,7 +290,7 @@ wdc_atapi_probe_device(struct atapibus_s
                        periph->periph_flags |= PERIPH_REMOVABLE;
                if (periph->periph_type == T_SEQUENTIAL) {
                        s = splbio();
-                       drvp->drive_flags |= DRIVE_ATAPIST;
+                       drvp->drive_flags |= DRIVE_ATAPIDSCW;
                        splx(s);
                }
 
@@ -321,12 +321,12 @@ wdc_atapi_probe_device(struct atapibus_s
                        ata_probe_caps(drvp);
                else {
                        s = splbio();
-                       drvp->drive_flags &= ~DRIVE_ATAPI;
+                       drvp->drive_type = DRIVET_NONE;
                        splx(s);
                }
        } else {
                s = splbio();
-               drvp->drive_flags &= ~DRIVE_ATAPI;
+               drvp->drive_type = DRIVET_NONE;
                splx(s);
        }
 }
@@ -995,7 +995,7 @@ wdc_atapi_phase_complete(struct ata_xfer
        struct ata_drive_datas *drvp = &chp->ch_drive[xfer->c_drive];
 
        /* wait for DSC if needed */
-       if (drvp->drive_flags & DRIVE_ATAPIST) {
+       if (drvp->drive_flags & DRIVE_ATAPIDSCW) {
                ATADEBUG_PRINT(("wdc_atapi_phase_complete(%s:%d:%d) "
                    "polldsc %d\n", device_xname(atac->atac_dev),
                    chp->ch_channel,
Index: dev/usb/umass_isdata.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/umass_isdata.c,v
retrieving revision 1.22
diff -u -p -u -r1.22 umass_isdata.c
--- dev/usb/umass_isdata.c      4 Mar 2012 00:21:20 -0000       1.22
+++ dev/usb/umass_isdata.c      23 Jun 2012 13:27:36 -0000
@@ -110,7 +110,7 @@ int uisdatadebug = 0;
 
 int  uisdata_bio(struct ata_drive_datas *, struct ata_bio *);
 int  uisdata_bio1(struct ata_drive_datas *, struct ata_bio *);
-void uisdata_reset_drive(struct ata_drive_datas *, int);
+void uisdata_reset_drive(struct ata_drive_datas *, int, uint32_t *);
 void uisdata_reset_channel(struct ata_channel *, int);
 int  uisdata_exec_command(struct ata_drive_datas *, struct ata_command *);
 int  uisdata_get_params(struct ata_drive_datas *, u_int8_t, struct ataparams 
*);
@@ -215,7 +215,7 @@ umass_isdata_attach(struct umass_softc *
        adev.adev_channel = 1;  /* XXX */
        adev.adev_openings = 1;
        adev.adev_drv_data = &scbus->sc_drv_data;
-       scbus->sc_drv_data.drive_flags = DRIVE_ATA;
+       scbus->sc_drv_data.drive_type = DRIVET_ATA;
        scbus->sc_drv_data.chnl_softc = sc;
        scbus->base.sc_child = config_found(sc->sc_dev, &adev, uwdprint);
 
@@ -376,9 +376,10 @@ uisdata_bio1(struct ata_drive_datas *drv
 }
 
 void
-uisdata_reset_drive(struct ata_drive_datas *drv, int flags)
+uisdata_reset_drive(struct ata_drive_datas *drv, int flags, uint32_t *sigp)
 {
        DPRINTFN(-1,("%s\n", __func__));
+       KASSERT(sigp == NULL);
        /* XXX what? */
 }
 


Home | Main Index | Thread Index | Old Index