Move most of the atabus layer into ata.c.

This commit is contained in:
thorpej 2003-12-30 16:28:37 +00:00
parent 90c49c51c7
commit 0ad3db4759
4 changed files with 352 additions and 307 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ata.c,v 1.22 2003/12/30 00:43:31 thorpej Exp $ */
/* $NetBSD: ata.c,v 1.23 2003/12/30 16:28:37 thorpej Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.22 2003/12/30 00:43:31 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.23 2003/12/30 16:28:37 thorpej Exp $");
#ifndef WDCDEBUG
#define WDCDEBUG
@ -39,11 +39,11 @@ __KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.22 2003/12/30 00:43:31 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/syslog.h>
#include <sys/proc.h>
#include <sys/kthread.h>
#include <sys/errno.h>
#include <machine/intr.h>
#include <machine/bus.h>
@ -53,8 +53,11 @@ __KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.22 2003/12/30 00:43:31 thorpej Exp $");
#include <dev/ic/wdcreg.h>
#include <dev/ic/wdcvar.h>
#include "locators.h"
#define DEBUG_FUNCS 0x08
#define DEBUG_PROBE 0x10
#define DEBUG_DETACH 0x20
#ifdef WDCDEBUG
extern int wdcdebug_mask; /* init'ed in wdc.c */
#define WDCDEBUG_PRINT(args, level) \
@ -64,6 +67,294 @@ extern int wdcdebug_mask; /* init'ed in wdc.c */
#define WDCDEBUG_PRINT(args, level)
#endif
/*****************************************************************************
* ATA bus layer.
*
* ATA controllers attach an atabus instance, which handles probing the bus
* for drives, etc.
*****************************************************************************/
/*
* atabusprint:
*
* Autoconfiguration print routine used by ATA controllers when
* attaching an atabus instance.
*/
int
atabusprint(void *aux, const char *pnp)
{
struct channel_softc *chan = aux;
if (pnp)
aprint_normal("atabus at %s", pnp);
aprint_normal(" channel %d", chan->channel);
return (UNCONF);
}
/*
* ataprint:
*
* Autoconfiguration print routine.
*/
int
ataprint(void *aux, const char *pnp)
{
struct ata_device *adev = aux;
if (pnp)
aprint_normal("wd at %s", pnp);
aprint_normal(" drive %d", adev->adev_drv_data->drive);
return (UNCONF);
}
/*
* atabus_thread:
*
* Worker thread for the ATA bus.
*/
static void
atabus_thread(void *arg)
{
struct atabus_softc *sc = arg;
struct channel_softc *chp = sc->sc_chan;
struct wdc_xfer *xfer;
int s;
s = splbio();
chp->ch_flags |= WDCF_TH_RUN;
splx(s);
/* Configure the devices on the bus. */
atabusconfig(sc);
for (;;) {
s = splbio();
if ((chp->ch_flags & (WDCF_TH_RESET | WDCF_SHUTDOWN)) == 0 &&
((chp->ch_flags & WDCF_ACTIVE) == 0 ||
chp->ch_queue->queue_freeze == 0)) {
chp->ch_flags &= ~WDCF_TH_RUN;
(void) tsleep(&chp->thread, PRIBIO, "atath", 0);
chp->ch_flags |= WDCF_TH_RUN;
}
splx(s);
if (chp->ch_flags & WDCF_SHUTDOWN)
break;
s = splbio();
if (chp->ch_flags & WDCF_TH_RESET) {
int drive;
(void) wdcreset(chp, RESET_SLEEP);
for (drive = 0; drive < 2; drive++)
chp->ch_drive[drive].state = 0;
chp->ch_flags &= ~WDCF_TH_RESET;
chp->ch_queue->queue_freeze--;
wdcstart(chp);
} else if ((chp->ch_flags & WDCF_ACTIVE) != 0 &&
chp->ch_queue->queue_freeze == 1) {
/*
* Caller has bumped queue_freeze, decrease it.
*/
chp->ch_queue->queue_freeze--;
xfer = TAILQ_FIRST(&chp->ch_queue->sc_xfer);
KASSERT(xfer != NULL);
(*xfer->c_start)(chp, xfer);
} else if (chp->ch_queue->queue_freeze > 1)
panic("ata_thread: queue_freeze");
splx(s);
}
chp->thread = NULL;
wakeup(&chp->ch_flags);
kthread_exit(0);
}
/*
* atabus_create_thread:
*
* Helper routine to create the ATA bus worker thread.
*/
static void
atabus_create_thread(void *arg)
{
struct atabus_softc *sc = arg;
struct channel_softc *chp = sc->sc_chan;
int error;
if ((error = kthread_create1(atabus_thread, sc, &chp->thread,
"%s", sc->sc_dev.dv_xname)) != 0)
aprint_error("%s: unable to create kernel thread: error %d\n",
sc->sc_dev.dv_xname, error);
}
/*
* atabus_match:
*
* Autoconfiguration match routine.
*/
static int
atabus_match(struct device *parent, struct cfdata *cf, void *aux)
{
struct channel_softc *chp = aux;
if (chp == NULL)
return (0);
if (cf->cf_loc[ATACF_CHANNEL] != chp->channel &&
cf->cf_loc[ATACF_CHANNEL] != ATACF_CHANNEL_DEFAULT)
return (0);
return (1);
}
/*
* atabus_attach:
*
* Autoconfiguration attach routine.
*/
static void
atabus_attach(struct device *parent, struct device *self, void *aux)
{
struct atabus_softc *sc = (void *) self;
struct channel_softc *chp = aux;
struct atabus_initq *initq;
sc->sc_chan = chp;
aprint_normal("\n");
aprint_naive("\n");
initq = malloc(sizeof(*initq), M_DEVBUF, M_WAITOK);
initq->atabus_sc = sc;
TAILQ_INSERT_TAIL(&atabus_initq_head, initq, atabus_initq);
config_pending_incr();
kthread_create(atabus_create_thread, sc);
}
/*
* atabus_activate:
*
* Autoconfiguration activation routine.
*/
static int
atabus_activate(struct device *self, enum devact act)
{
struct atabus_softc *sc = (void *) self;
struct channel_softc *chp = sc->sc_chan;
struct device *dev = NULL;
int s, i, error = 0;
s = splbio();
switch (act) {
case DVACT_ACTIVATE:
error = EOPNOTSUPP;
break;
case DVACT_DEACTIVATE:
/*
* We might deactivate the children of atapibus twice
* (once bia atapibus, once directly), but since the
* generic autoconfiguration code maintains the DVF_ACTIVE
* flag, it's safe.
*/
if ((dev = chp->atapibus) != NULL) {
error = config_deactivate(dev);
if (error)
goto out;
}
for (i = 0; i < 2; i++) {
if ((dev = chp->ch_drive[i].drv_softc) != NULL) {
WDCDEBUG_PRINT(("atabus_activate: %s: "
"deactivating %s\n", sc->sc_dev.dv_xname,
dev->dv_xname),
DEBUG_DETACH);
error = config_deactivate(dev);
if (error)
goto out;
}
}
break;
}
out:
splx(s);
#ifdef WDCDEBUG
if (dev != NULL && error != 0)
WDCDEBUG_PRINT(("atabus_activate: %s: "
"error %d deactivating %s\n", sc->sc_dev.dv_xname,
error, dev->dv_xname), DEBUG_DETACH);
#endif /* WDCDEBUG */
return (error);
}
/*
* atabus_detach:
*
* Autoconfiguration detach routine.
*/
static int
atabus_detach(struct device *self, int flags)
{
struct atabus_softc *sc = (void *) self;
struct channel_softc *chp = sc->sc_chan;
struct device *dev = NULL;
int i, error = 0;
/* Shutdown the channel. */
/* XXX NEED AN INTERLOCK HERE. */
chp->ch_flags |= WDCF_SHUTDOWN;
wakeup(&chp->thread);
while (chp->thread != NULL)
(void) tsleep(&chp->ch_flags, PRIBIO, "atadown", 0);
/*
* Detach atapibus and its children.
*/
if ((dev = chp->atapibus) != NULL) {
WDCDEBUG_PRINT(("atabus_detach: %s: detaching %s\n",
sc->sc_dev.dv_xname, dev->dv_xname), DEBUG_DETACH);
error = config_detach(dev, flags);
if (error)
goto out;
}
/*
* Detach our other children.
*/
for (i = 0; i < 2; i++) {
if (chp->ch_drive[i].drive_flags & DRIVE_ATAPI)
continue;
if ((dev = chp->ch_drive[i].drv_softc) != NULL) {
WDCDEBUG_PRINT(("atabus_detach: %s: detaching %s\n",
sc->sc_dev.dv_xname, dev->dv_xname),
DEBUG_DETACH);
error = config_detach(dev, flags);
if (error)
goto out;
}
}
wdc_kill_pending(chp);
out:
#ifdef WDCDEBUG
if (dev != NULL && error != 0)
WDCDEBUG_PRINT(("atabus_detach: %s: error %d detaching %s\n",
sc->sc_dev.dv_xname, error, dev->dv_xname),
DEBUG_DETACH);
#endif /* WDCDEBUG */
return (error);
}
CFATTACH_DECL(atabus, sizeof(struct atabus_softc),
atabus_match, atabus_attach, atabus_detach, atabus_activate);
/*****************************************************************************
* Common ATA bus operations.
*****************************************************************************/
/* Get the disk's parameters */
int
ata_get_params(struct ata_drive_datas *drvp, u_int8_t flags,

View File

@ -1,4 +1,4 @@
/* $NetBSD: atavar.h,v 1.36 2003/12/20 19:53:54 lha Exp $ */
/* $NetBSD: atavar.h,v 1.37 2003/12/30 16:28:37 thorpej Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@ -32,8 +32,31 @@
#ifndef _DEV_ATA_ATAVAR_H_
#define _DEV_ATA_ATAVAR_H_
/* High-level functions and structures used by both ATA and ATAPI devices */
#include <sys/lock.h>
#include <sys/queue.h>
/* ATA bus instance state information. */
struct atabus_softc {
struct device sc_dev;
struct channel_softc *sc_chan; /* XXXwdc */
};
/*
* A queue of atabus instances, used to ensure the same bus probe order
* for a given hardware configuration at each boot.
*/
struct atabus_initq {
TAILQ_ENTRY(atabus_initq) atabus_initq;
struct atabus_softc *atabus_sc;
};
#ifdef _KERNEL
TAILQ_HEAD(atabus_initq_head, atabus_initq);
extern struct atabus_initq_head atabus_initq_head;
extern struct simplelock atabus_interlock;
#endif /* _KERNEL */
/* High-level functions and structures used by both ATA and ATAPI devices */
struct ataparams;
/* Datas common to drives and controller drivers */
@ -292,6 +315,8 @@ struct ata_smart_selftestlog {
} __attribute__((packed));
#ifdef _KERNEL
int atabusprint(void *aux, const char *);
int ataprint(void *aux, const char *);
int wdc_downgrade_mode(struct ata_drive_datas *, int);
@ -304,7 +329,6 @@ int ata_set_mode(struct ata_drive_datas *, u_int8_t, u_int8_t);
#define CMD_AGAIN 2
void ata_dmaerr(struct ata_drive_datas *, int);
#endif /* _KERNEL */
#endif /* _DEV_ATA_ATAVAR_H_ */
#endif /* _KERNEL */

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdc.c,v 1.161 2003/12/15 00:27:13 thorpej Exp $ */
/* $NetBSD: wdc.c,v 1.162 2003/12/30 16:28:37 thorpej Exp $ */
/*
* Copyright (c) 1998, 2001, 2003 Manuel Bouyer. All rights reserved.
@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.161 2003/12/15 00:27:13 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.162 2003/12/30 16:28:37 thorpej Exp $");
#ifndef WDCDEBUG
#define WDCDEBUG
@ -79,7 +79,6 @@ __KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.161 2003/12/15 00:27:13 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/conf.h>
#include <sys/buf.h>
#include <sys/device.h>
@ -144,26 +143,6 @@ const struct ata_bustype wdc_ata_bustype = {
};
#endif
int atabusmatch __P((struct device *, struct cfdata *, void *));
void atabusattach __P((struct device *, struct device *, void *));
void atabus_create_thread __P((void *));
void atabus_thread __P((void *));
void atabusconfig __P((struct atabus_softc *));
int atabusactivate __P((struct device *, enum devact));
int atabusdetach __P((struct device *, int flags));
int atabusprint __P((void *, const char *));
CFATTACH_DECL(atabus, sizeof(struct atabus_softc),
atabusmatch, atabusattach, atabusdetach, atabusactivate);
struct atabus_initq {
struct atabus_softc *atabus_sc;
TAILQ_ENTRY(atabus_initq) atabus_initq;
};
static TAILQ_HEAD(, atabus_initq) atabus_initq_head =
TAILQ_HEAD_INITIALIZER(atabus_initq_head);
static struct simplelock atabus_interlock = SIMPLELOCK_INITIALIZER;
int wdcprobe1 __P((struct channel_softc*, int));
static void __wdcerror __P((struct channel_softc*, char *));
static int __wdcwait_reset __P((struct channel_softc *, int, int));
@ -171,7 +150,6 @@ void __wdccommand_done __P((struct channel_softc *, struct wdc_xfer *));
void __wdccommand_start __P((struct channel_softc *, struct wdc_xfer *));
int __wdccommand_intr __P((struct channel_softc *, struct wdc_xfer *, int));
int __wdcwait __P((struct channel_softc *, int, int, int));
int wdprint __P((void *, const char *));
void wdc_finish_attach __P((struct device *));
void wdc_channel_attach __P((struct channel_softc *));
@ -190,127 +168,27 @@ int wdc_nxfer = 0;
#define WDCDEBUG_PRINT(args, level)
#endif
int
atabusprint(aux, pnp)
void *aux;
const char *pnp;
{
struct channel_softc *chan = aux;
if (pnp)
aprint_normal("atabus at %s", pnp);
aprint_normal(" channel %d", chan->channel);
return (UNCONF);
}
/*
* A queue of atabus instances, used to ensure the same bus probe order
* for a given hardware configuration at each boot.
*/
struct atabus_initq_head atabus_initq_head =
TAILQ_HEAD_INITIALIZER(atabus_initq_head);
struct simplelock atabus_interlock = SIMPLELOCK_INITIALIZER;
int
atabusmatch(parent, cf, aux)
struct device *parent;
struct cfdata *cf;
void *aux;
{
struct channel_softc *chp = aux;
if (chp == NULL)
return (0);
if (cf->cf_loc[ATACF_CHANNEL] != chp->channel &&
cf->cf_loc[ATACF_CHANNEL] != ATACF_CHANNEL_DEFAULT)
return (0);
return (1);
}
void
atabusattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct atabus_softc *atabus_sc = (struct atabus_softc *)self;
struct channel_softc *chp = aux;
struct atabus_initq *atabus_initq;
atabus_sc->sc_chan = chp;
aprint_normal("\n");
aprint_naive("\n");
atabus_initq = malloc(sizeof(struct atabus_initq), M_DEVBUF, M_NOWAIT);
atabus_initq->atabus_sc = atabus_sc;
TAILQ_INSERT_TAIL(&atabus_initq_head, atabus_initq, atabus_initq);
config_pending_incr();
kthread_create(atabus_create_thread, atabus_sc);
}
void
atabus_create_thread(arg)
void *arg;
{
struct atabus_softc *atabus_sc = arg;
struct channel_softc *chp = atabus_sc->sc_chan;
int error;
if ((error = kthread_create1(atabus_thread, atabus_sc, &chp->thread,
"%s", atabus_sc->sc_dev.dv_xname)) != 0)
printf("unable to create kernel thread for %s: error %d\n",
atabus_sc->sc_dev.dv_xname, error);
}
void
atabus_thread(arg)
void *arg;
{
struct atabus_softc *atabus_sc = arg;
struct channel_softc *chp = atabus_sc->sc_chan;
struct wdc_xfer *xfer;
int s;
s = splbio();
chp->ch_flags |= WDCF_TH_RUN;
splx(s);
atabusconfig(atabus_sc);
for(;;) {
s = splbio();
if ((chp->ch_flags & (WDCF_TH_RESET | WDCF_SHUTDOWN)) == 0 &&
((chp->ch_flags & WDCF_ACTIVE) == 0 ||
chp->ch_queue->queue_freeze == 0)) {
chp->ch_flags &= ~WDCF_TH_RUN;
tsleep(&chp->thread, PRIBIO, "atath", 0);
chp->ch_flags |= WDCF_TH_RUN;
}
splx(s);
if (chp->ch_flags & WDCF_SHUTDOWN)
break;
s = splbio();
if (chp->ch_flags & WDCF_TH_RESET) {
int drive;
(void) wdcreset(chp, RESET_SLEEP);
for (drive = 0; drive < 2; drive++) {
chp->ch_drive[drive].state = 0;
}
chp->ch_flags &= ~WDCF_TH_RESET;
chp->ch_queue->queue_freeze--;
wdcstart(chp);
} else if ((chp->ch_flags & WDCF_ACTIVE) != 0 &&
chp->ch_queue->queue_freeze == 1) {
/*
* caller has bumped queue_freeze, decrease it
*/
chp->ch_queue->queue_freeze--;
xfer = chp->ch_queue->sc_xfer.tqh_first;
#ifdef DIAGNOSTIC
if (xfer == NULL)
panic("channel active with no xfer ?");
#endif
xfer->c_start(chp, xfer);
} else if (chp->ch_queue->queue_freeze > 1) {
panic("queue_freeze");
}
splx(s);
}
chp->thread = NULL;
wakeup(&chp->ch_flags);
kthread_exit(0);
}
/* Test to see controller with at last one attached drive is there.
* Returns a bit for each possible drive found (0x01 for drive 0,
* 0x02 for drive 1).
* Logic:
* - If a status register is at 0xff, assume there is no drive here
* (ISA has pull-up resistors). Similarly if the status register has
* the value we last wrote to the bus (for IDE interfaces without pullups).
* If no drive at all -> return.
* - reset the controller, wait for it to complete (may take up to 31s !).
* If timeout -> return.
* - test ATA/ATAPI signatures. If at last one drive found -> return.
* - try an ATA command on the master.
*/
void
atabusconfig(atabus_sc)
@ -524,7 +402,7 @@ atabusconfig(atabus_sc)
adev.adev_openings = 1;
adev.adev_drv_data = &chp->ch_drive[i];
chp->ata_drives[i] = config_found(&atabus_sc->sc_dev,
&adev, wdprint);
&adev, ataprint);
if (chp->ata_drives[i] != NULL)
wdc_probe_caps(&chp->ch_drive[i]);
else
@ -579,33 +457,6 @@ out:
wdc_delref(chp);
}
int
wdprint(aux, pnp)
void *aux;
const char *pnp;
{
struct ata_device *adev = aux;
if (pnp)
aprint_normal("wd at %s", pnp);
aprint_normal(" drive %d", adev->adev_drv_data->drive);
return (UNCONF);
}
/* Test to see controller with at last one attached drive is there.
* Returns a bit for each possible drive found (0x01 for drive 0,
* 0x02 for drive 1).
* Logic:
* - If a status register is at 0xff, assume there is no drive here
* (ISA has pull-up resistors). Similarly if the status register has
* the value we last wrote to the bus (for IDE interfaces without pullups).
* If no drive at all -> return.
* - reset the controller, wait for it to complete (may take up to 31s !).
* If timeout -> return.
* - test ATA/ATAPI signatures. If at last one drive found -> return.
* - try an ATA command on the master.
*/
int
wdcprobe(chp)
struct channel_softc *chp;
@ -815,67 +666,6 @@ wdcattach(chp)
chp->atabus = config_found(&chp->wdc->sc_dev, chp, atabusprint);
}
/*
* Call activate routine of underlying devices.
*/
int
atabusactivate(self, act)
struct device *self;
enum devact act;
{
struct atabus_softc *atabus_sc = (struct atabus_softc *)self;
struct channel_softc *chp = atabus_sc->sc_chan;
struct device *sc = 0;
int s, i, error = 0;
s = splbio();
switch (act) {
case DVACT_ACTIVATE:
error = EOPNOTSUPP;
break;
case DVACT_DEACTIVATE:
/*
* We might call deactivate routine for
* the children of atapibus twice (once via
* atapibus, once directly), but since
* config_deactivate maintains DVF_ACTIVE flag,
* it's safe.
*/
sc = chp->atapibus;
if (sc != NULL) {
error = config_deactivate(sc);
if (error != 0)
goto out;
}
for (i = 0; i < 2; i++) {
sc = chp->ch_drive[i].drv_softc;
WDCDEBUG_PRINT(("atabusactivate: %s:"
" deactivating %s\n", atabus_sc->sc_dev.dv_xname,
sc == NULL ? "nodrv" : sc->dv_xname),
DEBUG_DETACH);
if (sc != NULL) {
error = config_deactivate(sc);
if (error != 0)
goto out;
}
}
break;
}
out:
splx(s);
#ifdef WDCDEBUG
if (sc && error != 0)
WDCDEBUG_PRINT(("atabusactivate: %s: "
"error %d deactivating %s\n", atabus_sc->sc_dev.dv_xname,
error, sc->dv_xname), DEBUG_DETACH);
#endif
return (error);
}
int wdcactivate(self, act)
struct device *self;
enum devact act;
@ -901,65 +691,6 @@ int wdcactivate(self, act)
return (error);
}
int
atabusdetach(self, flags)
struct device *self;
int flags;
{
struct atabus_softc *atabus_sc = (struct atabus_softc *)self;
struct channel_softc *chp = atabus_sc->sc_chan;
struct device *sc = 0;
int i, error = 0;
/* shutdown channel */
chp->ch_flags |= WDCF_SHUTDOWN;
wakeup(&chp->thread);
while (chp->thread != NULL)
tsleep(&chp->ch_flags, PRIBIO, "atadown", 0);
/*
* Detach atapibus and its children.
*/
sc = chp->atapibus;
if (sc != NULL) {
WDCDEBUG_PRINT(("atabusdetach: %s: detaching %s\n",
atabus_sc->sc_dev.dv_xname, sc->dv_xname), DEBUG_DETACH);
error = config_detach(sc, flags);
if (error != 0)
goto out;
}
/*
* Detach our other children.
*/
for (i = 0; i < 2; i++) {
if (chp->ch_drive[i].drive_flags & DRIVE_ATAPI)
continue;
sc = chp->ch_drive[i].drv_softc;
WDCDEBUG_PRINT(("atabusdetach: %s: detaching %s\n",
atabus_sc->sc_dev.dv_xname,
sc == NULL ? "nodrv" : sc->dv_xname),
DEBUG_DETACH);
if (sc != NULL) {
error = config_detach(sc, flags);
if (error != 0)
goto out;
}
}
wdc_kill_pending(chp);
out:
#ifdef WDCDEBUG
if (sc && error != 0)
WDCDEBUG_PRINT(("atabusdetach: %s: error %d detaching %s\n",
atabus_sc->sc_dev.dv_xname, error, sc->dv_xname),
DEBUG_DETACH);
#endif
return (error);
}
int
wdcdetach(self, flags)
struct device *self;

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdcvar.h,v 1.46 2003/12/15 00:27:13 thorpej Exp $ */
/* $NetBSD: wdcvar.h,v 1.47 2003/12/30 16:28:37 thorpej Exp $ */
/*-
* Copyright (c) 1998, 2003 The NetBSD Foundation, Inc.
@ -97,11 +97,6 @@ struct channel_softc { /* Per channel data */
struct proc *thread;
};
struct atabus_softc { /* the atabus softc */
struct device sc_dev;
struct channel_softc *sc_chan;
};
struct wdc_softc { /* Per controller state */
struct device sc_dev;
/* mandatory fields */
@ -251,3 +246,7 @@ void wdc_probe_caps __P((struct ata_drive_datas*));
#define WDC_RESET_WAIT 31000
void wdc_atapibus_attach __P((struct atabus_softc *));
/* XXX */
struct atabus_softc;
void atabusconfig(struct atabus_softc *);