Merge bouyer-ide

This commit is contained in:
bouyer 1998-10-12 16:09:10 +00:00
parent 5e62d8161d
commit 19fddaeeb5
37 changed files with 5668 additions and 3477 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdc_pioc.c,v 1.6 1998/09/22 00:40:37 mark Exp $ */
/* $NetBSD: wdc_pioc.c,v 1.7 1998/10/12 16:09:10 bouyer Exp $ */
/*
* Copyright (c) 1997-1998 Mark Brinicombe.
@ -36,12 +36,14 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/bus.h>
#include <machine/irqhandler.h>
#include <arm32/mainbus/piocvar.h>
#include <dev/ata/atavar.h>
#include <dev/ic/wdcvar.h>
#include "locators.h"
@ -51,8 +53,8 @@
#define WDC_PIOC_AUXREG_NPORTS 1
struct wdc_pioc_softc {
struct wdc_softc sc_wdcdev;
struct wdc_attachment_data sc_ad;
struct wdc_softc sc_wdcdev;
struct channel_softc wdc_channel;
void *sc_ih;
};
@ -79,7 +81,7 @@ wdc_pioc_probe(parent, cf, aux)
void *aux;
{
struct pioc_attach_args *pa = aux;
struct wdc_attachment_data ad;
struct channel_softc ch = { 0 };
int res;
u_int iobase;
@ -91,22 +93,22 @@ wdc_pioc_probe(parent, cf, aux)
return(0);
iobase = pa->pa_iobase + pa->pa_offset;
memset(&ad, 0, sizeof(ad));
ad.iot = pa->pa_iot;
ad.auxiot = pa->pa_iot;
ch.cmd_iot = pa->pa_iot;
ch.ctl_iot = pa->pa_iot;
if (bus_space_map(ad.iot, iobase, WDC_PIOC_REG_NPORTS, 0, &ad.ioh))
if (bus_space_map(ch.cmd_iot, iobase, WDC_PIOC_REG_NPORTS, 0,
&ch.cmd_ioh))
return(0);
if (bus_space_map(ad.auxiot, iobase + WDC_PIOC_AUXREG_OFFSET,
WDC_PIOC_AUXREG_NPORTS, 0, &ad.auxioh)) {
bus_space_unmap(ad.iot, ad.ioh, WDC_PIOC_REG_NPORTS);
if (bus_space_map(ch.ctl_iot, iobase + WDC_PIOC_AUXREG_OFFSET,
WDC_PIOC_AUXREG_NPORTS, 0, &ch.ctl_ioh)) {
bus_space_unmap(ch.cmd_iot, ch.cmd_ioh, WDC_PIOC_REG_NPORTS);
return(0);
}
res = wdcprobe(&ad);
res = wdcprobe(&ch);
bus_space_unmap(ad.auxiot, ad.auxioh, WDC_PIOC_AUXREG_NPORTS);
bus_space_unmap(ad.iot, ad.ioh, WDC_PIOC_REG_NPORTS);
bus_space_unmap(ch.ctl_iot, ch.ctl_ioh, WDC_PIOC_AUXREG_NPORTS);
bus_space_unmap(ch.cmd_iot, ch.cmd_ioh, WDC_PIOC_REG_NPORTS);
if (res)
pa->pa_iosize = WDC_PIOC_REG_NPORTS;
@ -131,21 +133,33 @@ wdc_pioc_attach(parent, self, aux)
printf("\n");
iobase = pa->pa_iobase + pa->pa_offset;
sc->sc_ad.iot = pa->pa_iot;
sc->sc_ad.auxiot = pa->pa_iot;
if (bus_space_map(sc->sc_ad.iot, iobase, WDC_PIOC_REG_NPORTS, 0,
&sc->sc_ad.ioh))
sc->wdc_channel.cmd_iot = pa->pa_iot;
sc->wdc_channel.ctl_iot = pa->pa_iot;
if (bus_space_map(sc->wdc_channel.cmd_iot, iobase,
WDC_PIOC_REG_NPORTS, 0, &sc->wdc_channel.cmd_ioh))
panic("%s: couldn't map drive registers\n", self->dv_xname);
if (bus_space_map(sc->sc_ad.auxiot, iobase + WDC_PIOC_AUXREG_OFFSET,
WDC_PIOC_AUXREG_NPORTS, 0, &sc->sc_ad.auxioh))
if (bus_space_map(sc->wdc_channel.ctl_iot,
iobase + WDC_PIOC_AUXREG_OFFSET, WDC_PIOC_AUXREG_NPORTS, 0,
&sc->wdc_channel.ctl_ioh))
panic("%s: couldn't map aux registers\n", self->dv_xname);
sc->sc_ih = intr_claim(pa->pa_irq, IPL_BIO, "wdc", wdcintr, sc);
if (!sc->sc_ih)
panic("%s: Cannot claim IRQ %d\n", self->dv_xname, pa->pa_irq);
wdcattach(&sc->sc_wdcdev, &sc->sc_ad);
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16;
sc->sc_wdcdev.pio_mode = 0;
sc->sc_wdcdev.channels = &sc->wdc_channel;
sc->sc_wdcdev.nchannels = 1;
sc->wdc_channel.channel = 0;
sc->wdc_channel.ch_queue = malloc(sizeof(struct channel_queue),
M_DEVBUF, M_NOWAIT);
if (sc->wdc_channel.ch_queue == NULL) {
printf("%s: can't allocate memory for command queue",
sc->sc_wdcdev.sc_dev.dv_xname);
return;
}
wdcattach(&sc->wdc_channel);
}
/* End of wdc_pioc.c */

View File

@ -1,4 +1,4 @@
/* $NetBSD: icside.c,v 1.8 1998/09/22 00:40:37 mark Exp $ */
/* $NetBSD: icside.c,v 1.9 1998/10/12 16:09:11 bouyer Exp $ */
/*
* Copyright (c) 1997-1998 Mark Brinicombe
@ -44,6 +44,7 @@
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/irqhandler.h>
#include <machine/io.h>
@ -52,6 +53,7 @@
#include <arm32/podulebus/podules.h>
#include <arm32/podulebus/icsidereg.h>
#include <dev/ata/atavar.h>
#include <dev/ic/wdcvar.h>
/*
@ -69,35 +71,26 @@
*/
struct icside_softc {
struct device sc_dev;
struct wdc_softc sc_wdcdev; /* common wdc definitions */
podule_t *sc_podule; /* Our podule */
int sc_podule_number; /* Our podule number */
struct bus_space sc_tag; /* custom tag */
struct podule_attach_args *sc_pa; /* podule info */
struct icside_channel {
irqhandler_t ic_ih; /* interrupt handler */
bus_space_tag_t ic_irqiot; /* Bus space tag */
bus_space_handle_t ic_irqioh; /* handle for IRQ */
} *icside_channels;
};
int icside_probe __P((struct device *, struct cfdata *, void *));
void icside_attach __P((struct device *, struct device *, void *));
int icside_intr __P((void *));
struct cfattach icside_ca = {
sizeof(struct icside_softc), icside_probe, icside_attach
};
/*
* Attach arguments for child devices.
* Pass the podule details, the parent softc and the channel
*/
struct icside_attach_args {
struct podule_attach_args *ia_pa; /* podule info */
struct icside_softc *ia_softc; /* parent softc */
int ia_channel; /* IDE channel */
bus_space_tag_t ia_iot; /* bus space tag */
bus_space_handle_t ia_ioh; /* IDE drive regs */
bus_space_handle_t ia_auxioh; /* Aux status regs */
bus_space_handle_t ia_irqioh; /* IRQ regs */
u_int ia_irqstatus; /* IRQ status address */
};
/*
* Define prototypes for custom bus space functions.
*/
@ -140,21 +133,6 @@ struct ide_version {
}
};
/* Print function used during child config */
int
icside_print(aux, name)
void *aux;
const char *name;
{
struct icside_attach_args *ia = aux;
if (!name)
printf(": %s channel", (ia->ia_channel == 0) ? "primary" : "secondary");
return(QUIET);
}
/*
* Card probe function
*
@ -187,12 +165,13 @@ icside_attach(parent, self, aux)
{
struct icside_softc *sc = (void *)self;
struct podule_attach_args *pa = (void *)aux;
struct icside_attach_args ia;
bus_space_tag_t iot;
bus_space_handle_t ioh;
irqhandler_t *ihp;
struct ide_version *ide = NULL;
u_int iobase;
int channel;
struct channel_softc *cp;
int loop;
int id;
@ -251,157 +230,97 @@ icside_attach(parent, self, aux)
sc->sc_tag.bs_rm_2 = icside_bs_rm_2;
sc->sc_tag.bs_wm_2 = icside_bs_wm_2;
/* Configure the children */
ia.ia_softc = sc;
ia.ia_pa = pa;
ia.ia_iot = &sc->sc_tag;
/* Initialize wdc struct */
sc->sc_wdcdev.channels = malloc(
sizeof(struct channel_softc) * ide->channels, M_DEVBUF, M_NOWAIT);
sc->icside_channels = malloc(
sizeof(struct icside_channel) * ide->channels, M_DEVBUF, M_NOWAIT);
if (sc->sc_wdcdev.channels == NULL || sc->icside_channels == NULL) {
printf("%s: can't allocate channel infos\n",
sc->sc_wdcdev.sc_dev.dv_xname);
return;
}
sc->sc_wdcdev.nchannels = ide->channels;
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16;
sc->sc_wdcdev.pio_mode = 0;
sc->sc_pa = pa;
for (channel = 0; channel < ide->channels; ++channel) {
cp = &sc->sc_wdcdev.channels[channel];
cp->channel = channel;
cp->wdc = &sc->sc_wdcdev;
cp->ch_queue = malloc(sizeof(struct channel_queue), M_DEVBUF,
M_NOWAIT);
if (cp->ch_queue == NULL) {
printf("%s %s channel: "
"can't allocate memory for command queue",
sc->sc_wdcdev.sc_dev.dv_xname,
(channel == 0) ? "primary" : "secondary");
continue;
}
cp->cmd_iot = &sc->sc_tag;
cp->ctl_iot = &sc->sc_tag;
if (ide->modspace)
iobase = pa->pa_podule->mod_base;
else
iobase = pa->pa_podule->fast_base;
ia.ia_channel = channel;
if (bus_space_map(iot, iobase + ide->ideregs[channel],
IDE_REGISTER_SPACE, 0, &ia.ia_ioh))
IDE_REGISTER_SPACE, 0, &cp->cmd_ioh))
return;
if (bus_space_map(iot, iobase + ide->auxregs[channel],
AUX_REGISTER_SPACE, 0, &ia.ia_auxioh))
AUX_REGISTER_SPACE, 0, &cp->ctl_ioh))
return;
sc->icside_channels[channel].ic_irqiot = iot;
if (bus_space_map(iot, iobase + ide->irqregs[channel],
IRQ_REGISTER_SPACE, 0, &ia.ia_irqioh))
IRQ_REGISTER_SPACE, 0,
&sc->icside_channels[channel].ic_irqioh))
return;
ia.ia_irqstatus = iobase + ide->irqstatregs[channel];
config_found_sm(self, &ia, icside_print, NULL);
/* Disable interrupts */
(void)bus_space_read_1(iot,
sc->icside_channels[channel].ic_irqioh, 0);
/* Call common attach routines */
wdcattach(cp);
/* Disable interrupts */
(void)bus_space_read_1(iot,
sc->icside_channels[channel].ic_irqioh, 0);
pa->pa_podule->irq_addr = iobase + ide->irqstatregs[channel];
pa->pa_podule->irq_mask = IRQ_STATUS_REGISTER_MASK;
ihp = &sc->icside_channels[channel].ic_ih;
ihp->ih_func = icside_intr;
ihp->ih_arg = cp;
ihp->ih_level = IPL_BIO;
ihp->ih_name = "icside";
ihp->ih_maskaddr = pa->pa_podule->irq_addr;
ihp->ih_maskbits = pa->pa_podule->irq_mask;
if (irq_claim(pa->pa_podule->interrupt, ihp)) {
printf("%s: Cannot claim interrupt %d\n",
sc->sc_wdcdev.sc_dev.dv_xname,
pa->pa_podule->interrupt);
continue;
}
/* Enable interrupts */
bus_space_write_1(iot, sc->icside_channels[channel].ic_irqioh,
0, 0);
}
}
/*
* ICS IDE probe and attach code for the wdc device.
*
* This provides a different pair of probe and attach functions
* for attaching the wdc device (mainbus/wd.c) to the ICS IDE card.
*/
struct wdc_ics_softc {
struct wdc_softc sc_wdcdev; /* Device node */
struct wdc_attachment_data sc_ad; /* Attachment data */
irqhandler_t sc_ih; /* interrupt handler */
bus_space_tag_t sc_irqiot; /* Bus space tag */
bus_space_handle_t sc_irqioh; /* handle for IRQ */
};
int wdc_ics_probe __P((struct device *, struct cfdata *, void *));
void wdc_ics_attach __P((struct device *, struct device *, void *));
int wdc_ics_intr __P((void *));
void wdc_ics_intcontrol __P((void *wdc, int enable));
struct cfattach wdc_ics_ca = {
sizeof(struct wdc_ics_softc), wdc_ics_probe, wdc_ics_attach
};
/*
* Controller probe function
*
* Map all the required I/O space for this channel, make sure interrupts
* are disabled and probe the bus.
*/
int
wdc_ics_probe(parent, cf, aux)
struct device *parent;
struct cfdata *cf;
void *aux;
{
struct icside_attach_args *ia = aux;
struct wdc_attachment_data ad;
int result;
bzero(&ad, sizeof ad);
ad.iot = ia->ia_iot;
ad.ioh = ia->ia_ioh;
ad.auxiot = ia->ia_iot;
ad.auxioh = ia->ia_auxioh;
/* Disable interrupts */
(void)bus_space_read_1(ia->ia_iot, ia->ia_irqioh, 0);
result = wdcprobe(&ad);
/* Disable interrupts */
(void)bus_space_read_1(ia->ia_iot, ia->ia_irqioh, 0);
return(result);
}
/*
* Controller attach function
*
* Map all the required I/O space for this channel, disble interrupts
* and attach the controller. The generic attach will probe and attach
* any devices.
* Install an interrupt handler and we are ready to rock.
*/
void
wdc_ics_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct wdc_ics_softc *wdc = (void *)self;
struct icside_attach_args *ia = (void *)aux;
struct podule_attach_args *pa = ia->ia_pa;
printf("\n");
wdc->sc_irqiot = ia->ia_iot;
wdc->sc_irqioh = ia->ia_irqioh;
wdc->sc_ad.iot = ia->ia_iot;
wdc->sc_ad.ioh = ia->ia_ioh;
wdc->sc_ad.auxiot = ia->ia_iot;
wdc->sc_ad.auxioh = ia->ia_auxioh;
/* Disable interrupts */
(void)bus_space_read_1(wdc->sc_irqiot, wdc->sc_irqioh, 0);
wdcattach(&wdc->sc_wdcdev, &wdc->sc_ad);
pa->pa_podule->irq_addr = ia->ia_irqstatus;
pa->pa_podule->irq_mask = IRQ_STATUS_REGISTER_MASK;
wdc->sc_ih.ih_func = wdc_ics_intr;
wdc->sc_ih.ih_arg = wdc;
wdc->sc_ih.ih_level = IPL_BIO;
wdc->sc_ih.ih_name = "icside";
wdc->sc_ih.ih_maskaddr = pa->pa_podule->irq_addr;
wdc->sc_ih.ih_maskbits = pa->pa_podule->irq_mask;
if (irq_claim(pa->pa_podule->interrupt, &wdc->sc_ih))
printf("%s: Cannot claim interrupt %d\n", self->dv_xname,
pa->pa_podule->interrupt);
/* Enable interrupts */
bus_space_write_1(wdc->sc_irqiot, wdc->sc_irqioh, 0, 0);
}
/*
* Podule interrupt handler
*
* If the interrupt was from our card pass it on to the wdc interrupt handler
*/
int
wdc_ics_intr(arg)
icside_intr(arg)
void *arg;
{
struct wdc_ics_softc *wdc = arg;
volatile u_char *intraddr = (volatile u_char *)wdc->sc_ih.ih_maskaddr;
struct channel_softc *chp = arg;
struct icside_softc *sc = (struct icside_softc*)chp->wdc;
irqhandler_t *ihp = &sc->icside_channels[chp->channel].ic_ih;
volatile u_char *intraddr = (volatile u_char *)ihp->ih_maskaddr;
/* XXX - not bus space yet - should really be handled by podulebus */
if ((*intraddr) & wdc->sc_ih.ih_maskbits)
wdcintr(arg);
if ((*intraddr) & ihp->ih_maskbits)
wdcintr(chp);
return(0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: rapide.c,v 1.9 1998/09/22 00:40:37 mark Exp $ */
/* $NetBSD: rapide.c,v 1.10 1998/10/12 16:09:11 bouyer Exp $ */
/*
* Copyright (c) 1997-1998 Mark Brinicombe
@ -71,6 +71,7 @@
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/irqhandler.h>
#include <machine/io.h>
@ -81,6 +82,7 @@
#include <arm32/podulebus/podules.h>
#include <arm32/podulebus/rapidereg.h>
#include <dev/ata/atavar.h>
#include <dev/ic/wdcvar.h>
@ -102,36 +104,29 @@
*/
struct rapide_softc {
struct device sc_dev; /* device node */
struct wdc_softc sc_wdcdev; /* common wdc definitions */
struct channel_softc wdc_channel[2]; /* channels definition */
podule_t *sc_podule; /* Our podule info */
int sc_podule_number; /* Our podule number */
int sc_intr_enable_mask; /* Global intr mask */
int sc_version; /* Card version */
bus_space_tag_t sc_ctliot; /* Bus tag */
bus_space_handle_t sc_ctlioh; /* control handler */
struct rapide_channel {
irqhandler_t rc_ih; /* interrupt handler */
int rc_irqmask; /* IRQ mask for this channel */
} rapide_channels[2];
};
int rapide_probe __P((struct device *, struct cfdata *, void *));
void rapide_attach __P((struct device *, struct device *, void *));
void rapide_shutdown __P((void *arg));
int rapide_intr __P((void *));
struct cfattach rapide_ca = {
sizeof(struct rapide_softc), rapide_probe, rapide_attach
};
/*
* Attach arguments for child devices.
* Pass the podule details, the parent softc and the channel
*/
struct rapide_attach_args {
struct podule_attach_args *ra_pa; /* podule info */
struct rapide_softc *ra_softc; /* parent softc */
bus_space_tag_t ra_iot; /* bus space tag */
u_int ra_iobase; /* I/O base address */
int ra_channel; /* IDE channel */
};
/*
* We have a private bus space tag.
* This is created by copying the podulebus tag and then replacing
@ -143,20 +138,25 @@ static struct bus_space rapide_bs_tag;
bs_rm_4_proto(rapide);
bs_wm_4_proto(rapide);
/* Print function used during child config */
/*
* Create an array of address structures. These define the addresses and
* masks needed for the different channels for the card.
*
* XXX - Needs some work for issue 1 cards.
*/
int
rapide_print(aux, name)
void *aux;
const char *name;
{
struct rapide_attach_args *ra = aux;
struct {
u_int registers;
u_int aux_register;
u_int data_register;
u_int irq_mask;
} rapide_info[] = {
{ PRIMARY_DRIVE_REGISTERS_OFFSET, PRIMARY_AUX_REGISTER_OFFSET,
PRIMARY_DATA_REGISTER_OFFSET, PRIMARY_IRQ_MASK },
{ SECONDARY_DRIVE_REGISTERS_OFFSET, SECONDARY_AUX_REGISTER_OFFSET,
SECONDARY_DATA_REGISTER_OFFSET, SECONDARY_IRQ_MASK }
};
if (!name)
printf(": %s channel", (ra->ra_channel == 0) ? "primary" : "secondary");
return(QUIET);
}
/*
* Card probe function
@ -191,9 +191,12 @@ rapide_attach(parent, self, aux)
{
struct rapide_softc *sc = (void *)self;
struct podule_attach_args *pa = (void *)aux;
struct rapide_attach_args ra;
bus_space_tag_t iot;
bus_space_handle_t ctlioh;
u_int iobase;
int channel;
struct channel_softc *cp;
irqhandler_t *ihp;
/* Note the podule number and validate */
if (pa->pa_podule_number == -1)
@ -235,18 +238,71 @@ rapide_attach(parent, self, aux)
+ CONTROL_REGISTERS_OFFSET + IRQ_REQUEST_REGISTER_BYTE_OFFSET;
sc->sc_podule->irq_mask = IRQ_MASK;
/* Configure the children */
sc->sc_intr_enable_mask = 0;
ra.ra_softc = sc;
ra.ra_pa = pa;
ra.ra_iot = iot;
ra.ra_iobase = pa->pa_podule->easi_base;
iobase = pa->pa_podule->easi_base;
ra.ra_channel = 0;
config_found_sm(self, &ra, rapide_print, NULL);
/* Fill in wdc and channel infos */
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA32;
sc->sc_wdcdev.pio_mode = 0;
sc->sc_wdcdev.channels = sc->wdc_channel;
sc->sc_wdcdev.nchannels = 2;
for (channel = 0 ; channel < 2; channel++) {
cp = &sc->wdc_channel[channel];
cp->channel = channel;
cp->wdc = &sc->sc_wdcdev;
cp->ch_queue = malloc(sizeof(struct channel_queue),
M_DEVBUF, M_NOWAIT);
if (cp->ch_queue == NULL) {
printf("%s %s channel: can't allocate memory for "
"command queue", self->dv_xname,
(channel == 0) ? "primary" : "secondary");
continue;
}
cp->cmd_iot = iot;
cp->ctl_iot = iot;
cp->data32iot = iot;
ra.ra_channel = 1;
config_found_sm(self, &ra, rapide_print, NULL);
if (bus_space_map(iot, iobase + rapide_info[channel].registers,
DRIVE_REGISTERS_SPACE, 0, &cp->cmd_ioh))
continue;
if (bus_space_map(iot, iobase +
rapide_info[channel].aux_register, 4, 0, &cp->ctl_ioh)) {
bus_space_unmap(iot, cp->cmd_ioh,
DRIVE_REGISTERS_SPACE);
continue;
}
if (bus_space_map(iot, iobase +
rapide_info[channel].data_register, 4, 0, &cp->data32ioh)) {
bus_space_unmap(iot, cp->cmd_ioh,
DRIVE_REGISTERS_SPACE);
bus_space_unmap(iot, cp->ctl_ioh, 4);
continue;
}
/* Disable interrupts and clear any pending interrupts */
sc->rapide_channels[channel].rc_irqmask =
rapide_info[channel].irq_mask;
sc->sc_intr_enable_mask &=
~sc->rapide_channels[channel].rc_irqmask;
bus_space_write_1(iot, sc->sc_ctlioh, IRQ_MASK_REGISTER_OFFSET,
sc->sc_intr_enable_mask);
/* XXX - Issue 1 cards will need to clear any pending interrupts */
wdcattach(cp);
ihp = &sc->rapide_channels[channel].rc_ih;
ihp->ih_func = rapide_intr;
ihp->ih_arg = cp;
ihp->ih_level = IPL_BIO;
ihp->ih_name = "rapide";
ihp->ih_maskaddr = pa->pa_podule->irq_addr;
ihp->ih_maskbits = sc->rapide_channels[channel].rc_irqmask;
if (irq_claim(sc->sc_podule->interrupt, ihp))
panic("%s: Cannot claim interrupt %d\n",
self->dv_xname, sc->sc_podule->interrupt);
/* clear any pending interrupts and enable interrupts */
sc->sc_intr_enable_mask |=
sc->rapide_channels[channel].rc_irqmask;
bus_space_write_1(iot, sc->sc_ctlioh,
IRQ_MASK_REGISTER_OFFSET, sc->sc_intr_enable_mask);
/* XXX - Issue 1 cards will need to clear any pending interrupts */
}
}
/*
@ -267,185 +323,6 @@ rapide_shutdown(arg)
IRQ_MASK_REGISTER_OFFSET, 0);
}
/*
* RapIDE probe and attach code for the wdc device.
*
* This provides a different pair of probe and attach functions
* for attaching the wdc device (mainbus/wd.c) to the RapIDE card.
*/
struct wdc_rapide_softc {
struct wdc_softc sc_wdcdev; /* Device node */
struct wdc_attachment_data sc_ad; /* Attachment data */
irqhandler_t sc_ih; /* interrupt handler */
int sc_irqmask; /* IRQ mask for this channel */
int sc_channel; /* channel number */
int sc_pio_mode[2]; /* PIO mode */
struct rapide_softc *sc_softc; /* pointer to parent */
};
int wdc_rapide_probe __P((struct device *, struct cfdata *, void *));
void wdc_rapide_attach __P((struct device *, struct device *, void *));
int wdc_rapide_intr __P((void *));
struct cfattach wdc_rapide_ca = {
sizeof(struct wdc_rapide_softc), wdc_rapide_probe, wdc_rapide_attach
};
/*
* Create an array of address structures. These define the addresses and
* masks needed for the different channels for the card.
*
* XXX - Needs some work for issue 1 cards.
*/
struct {
u_int registers;
u_int aux_register;
u_int data_register;
u_int irq_mask;
} rapide_info[] = {
{ PRIMARY_DRIVE_REGISTERS_OFFSET, PRIMARY_AUX_REGISTER_OFFSET,
PRIMARY_DATA_REGISTER_OFFSET, PRIMARY_IRQ_MASK },
{ SECONDARY_DRIVE_REGISTERS_OFFSET, SECONDARY_AUX_REGISTER_OFFSET,
SECONDARY_DATA_REGISTER_OFFSET, SECONDARY_IRQ_MASK }
};
/*
* Controller probe function
*
* Map all the required I/O space for this channel, make sure interrupts
* are disabled and probe the bus.
*/
int
wdc_rapide_probe(parent, cf, aux)
struct device *parent;
struct cfdata *cf;
void *aux;
{
struct rapide_attach_args *ra = (void *)aux;
struct rapide_softc *sc;
struct wdc_attachment_data ad;
int result = 0;
bzero(&ad, sizeof ad);
sc = ra->ra_softc;
#ifdef DIAGNOSTIC
if (ra->ra_channel < 0 || ra->ra_channel > 1)
return(0);
#endif /* DIAGNOSTIC */
ad.iot = ra->ra_iot;
if (bus_space_map(ad.iot, ra->ra_iobase +
rapide_info[ra->ra_channel].registers, DRIVE_REGISTERS_SPACE,
0, &ad.ioh))
return(0);
ad.auxiot = ra->ra_iot;
if (bus_space_map(ad.auxiot, ra->ra_iobase +
rapide_info[ra->ra_channel].aux_register, 4, 0, &ad.auxioh)) {
bus_space_unmap(ad.iot, ad.ioh, DRIVE_REGISTERS_SPACE);
return(0);
}
ad.data32iot = ra->ra_iot;
ad.cap |= WDC_CAPABILITY_DATA32;
if (bus_space_map(ad.data32iot, ra->ra_iobase +
rapide_info[ra->ra_channel].data_register, 4, 0, &ad.data32ioh)) {
bus_space_unmap(ad.iot, ad.ioh, DRIVE_REGISTERS_SPACE);
bus_space_unmap(ad.auxiot, ad.auxioh, 4);
return(0);
}
/* Disable interrupts and clear any pending interrupts */
sc->sc_intr_enable_mask &= ~rapide_info[ra->ra_channel].irq_mask;
bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh, IRQ_MASK_REGISTER_OFFSET,
sc->sc_intr_enable_mask);
/* XXX - Issue 1 cards will need to clear any pending interrupts */
result = wdcprobe(&ad);
bus_space_unmap(ad.iot, ad.ioh, DRIVE_REGISTERS_SPACE);
bus_space_unmap(ad.auxiot, ad.auxioh, 4);
bus_space_unmap(ad.data32iot, ad.data32ioh, 4);
return(result);
}
/*
* Controller attach function
*
* Map all the required I/O space for this channel, disble interrupts
* and attach the controller. The generic attach will probe and attach
* any devices.
* Install an interrupt handler and we are ready to rock.
*/
void
wdc_rapide_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct wdc_rapide_softc *wdc = (void *)self;
struct rapide_attach_args *ra = (void *)aux;
struct podule_attach_args *pa = ra->ra_pa;
struct rapide_softc *sc;
printf("\n");
wdc->sc_channel = ra->ra_channel;
wdc->sc_irqmask = rapide_info[ra->ra_channel].irq_mask;
wdc->sc_ad.iot = ra->ra_iot;
wdc->sc_ad.auxiot = ra->ra_iot;
wdc->sc_ad.data32iot = ra->ra_iot;
wdc->sc_ad.cap |= WDC_CAPABILITY_DATA32;
sc = ra->ra_softc;
if (bus_space_map(wdc->sc_ad.iot, ra->ra_iobase
+ rapide_info[ra->ra_channel].registers,
DRIVE_REGISTERS_SPACE, 0, &wdc->sc_ad.ioh))
panic("%s: Cannot map drive registers\n", self->dv_xname);
if (bus_space_map(wdc->sc_ad.auxiot, ra->ra_iobase +
rapide_info[ra->ra_channel].aux_register, 4, 0, &wdc->sc_ad.auxioh))
panic("%s: Cannot map auxilary register\n", self->dv_xname);
if (bus_space_map(wdc->sc_ad.data32iot, ra->ra_iobase +
rapide_info[ra->ra_channel].data_register, 4, 0, &wdc->sc_ad.data32ioh))
panic("%s: Cannot map data register\n", self->dv_xname);
/* Disable interrupts and clear any pending interrupts */
sc->sc_intr_enable_mask &= ~wdc->sc_irqmask;
bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
IRQ_MASK_REGISTER_OFFSET, sc->sc_intr_enable_mask);
/* XXX - Issue 1 cards will need to clear any pending interrupts */
wdcattach(&wdc->sc_wdcdev, &wdc->sc_ad);
wdc->sc_ih.ih_func = wdc_rapide_intr;
wdc->sc_ih.ih_arg = wdc;
wdc->sc_ih.ih_level = IPL_BIO;
wdc->sc_ih.ih_name = "rapide";
wdc->sc_ih.ih_maskaddr = pa->pa_podule->irq_addr;
wdc->sc_ih.ih_maskbits = wdc->sc_irqmask;
if (irq_claim(sc->sc_podule->interrupt, &wdc->sc_ih))
panic("%s: Cannot claim interrupt %d\n", self->dv_xname,
sc->sc_podule->interrupt);
/* clear any pending interrupts and enable interrupts */
sc->sc_intr_enable_mask |= wdc->sc_irqmask;
bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
IRQ_MASK_REGISTER_OFFSET, sc->sc_intr_enable_mask);
/* XXX - Issue 1 cards will need to clear any pending interrupts */
}
/*
* Podule interrupt handler
*
@ -453,17 +330,19 @@ wdc_rapide_attach(parent, self, aux)
*/
int
wdc_rapide_intr(arg)
rapide_intr(arg)
void *arg;
{
struct wdc_rapide_softc *wdc = arg;
volatile u_char *intraddr = (volatile u_char *)wdc->sc_ih.ih_maskaddr;
struct channel_softc *chp = arg;
struct rapide_softc *sc = (struct rapide_softc *)chp->wdc;
irqhandler_t *ihp = &sc->rapide_channels[chp->channel].rc_ih;
volatile u_char *intraddr = (volatile u_char *)ihp->ih_maskaddr;
/* XXX - Issue 1 cards will need to clear the interrupt */
/* XXX - not bus space yet - should really be handled by podulebus */
if ((*intraddr) & wdc->sc_ih.ih_maskbits)
wdcintr(arg);
if ((*intraddr) & ihp->ih_maskbits)
wdcintr(chp);
return(0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: simide.c,v 1.7 1998/09/22 00:40:38 mark Exp $ */
/* $NetBSD: simide.c,v 1.8 1998/10/12 16:09:11 bouyer Exp $ */
/*
* Copyright (c) 1997-1998 Mark Brinicombe
@ -43,6 +43,7 @@
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/irqhandler.h>
#include <machine/io.h>
@ -51,6 +52,7 @@
#include <arm32/podulebus/podules.h>
#include <arm32/podulebus/simidereg.h>
#include <dev/ata/atavar.h>
#include <dev/ic/wdcvar.h>
@ -72,7 +74,8 @@
*/
struct simide_softc {
struct device sc_dev; /* device node */
struct wdc_softc sc_wdcdev; /* common wdc definitions */
struct channel_softc wdc_channel[2]; /* channels definition */
podule_t *sc_podule; /* Our podule info */
int sc_podule_number; /* Our podule number */
int sc_ctl_reg; /* Global ctl reg */
@ -80,28 +83,21 @@ struct simide_softc {
bus_space_tag_t sc_ctliot; /* Bus tag */
bus_space_handle_t sc_ctlioh; /* control handle */
struct bus_space sc_tag; /* custom tag */
struct simide_channel {
irqhandler_t sc_ih; /* interrupt handler */
int sc_irqmask; /* IRQ mask for this channel */
} simide_channels[2];
};
int simide_probe __P((struct device *, struct cfdata *, void *));
void simide_attach __P((struct device *, struct device *, void *));
void simide_shutdown __P((void *arg));
int simide_intr __P((void *arg));
struct cfattach simide_ca = {
sizeof(struct simide_softc), simide_probe, simide_attach
};
/*
* Attach arguments for child devices.
* Pass the podule details, the parent softc and the channel
*/
struct simide_attach_args {
struct podule_attach_args *sa_pa; /* podule info */
struct simide_softc *sa_softc; /* parent softc */
bus_space_tag_t sa_iot; /* bus space tag */
u_int sa_iobase; /* I/O base address */
int sa_channel; /* IDE channel */
};
/*
* Define prototypes for custom bus space functions.
@ -110,20 +106,23 @@ struct simide_attach_args {
bs_rm_2_proto(simide);
bs_wm_2_proto(simide);
/* Print function used during child config */
/*
* Create an array of address structures. These define the addresses and
* masks needed for the different channels.
*
* index = channel
*/
int
simide_print(aux, name)
void *aux;
const char *name;
{
struct simide_attach_args *sa = aux;
if (!name)
printf(": %s channel", (sa->sa_channel == 0) ? "primary" : "secondary");
return(QUIET);
}
struct {
u_int drive_registers;
u_int aux_register;
u_int irq_mask;
} simide_info[] = {
{ PRIMARY_DRIVE_REGISTERS_POFFSET, PRIMARY_AUX_REGISTER_POFFSET,
CONTROL_PRIMARY_IRQ },
{ SECONDARY_DRIVE_REGISTERS_POFFSET, SECONDARY_AUX_REGISTER_POFFSET,
CONTROL_SECONDARY_IRQ }
};
/*
* Card probe function
@ -158,8 +157,11 @@ simide_attach(parent, self, aux)
{
struct simide_softc *sc = (void *)self;
struct podule_attach_args *pa = (void *)aux;
struct simide_attach_args sa;
int status;
u_int iobase;
int channel;
struct channel_softc *cp;
irqhandler_t *ihp;
/* Note the podule number and validate */
if (pa->pa_podule_number == -1)
@ -236,17 +238,58 @@ simide_attach(parent, self, aux)
bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
/* Configure the children */
sa.sa_softc = sc;
sa.sa_pa = pa;
sa.sa_iot = &sc->sc_tag;
sa.sa_iobase = pa->pa_podule->mod_base;
/* Fill in wdc and channel infos */
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16;
sc->sc_wdcdev.pio_mode = 0;
sc->sc_wdcdev.channels = sc->wdc_channel;
sc->sc_wdcdev.nchannels = 2;
for (channel = 0 ; channel < 2; channel++) {
cp = &sc->wdc_channel[channel];
cp->channel = channel;
cp->wdc = &sc->sc_wdcdev;
cp->ch_queue = malloc(sizeof(struct channel_queue),
M_DEVBUF, M_NOWAIT);
if (cp->ch_queue == NULL) {
printf("%s %s channel: can't allocate memory for "
"command queue", self->dv_xname,
(channel == 0) ? "primary" : "secondary");
continue;
}
cp->cmd_iot = cp->ctl_iot = &sc->sc_tag;
iobase = pa->pa_podule->mod_base;
if (bus_space_map(cp->cmd_iot, iobase +
simide_info[channel].drive_registers,
DRIVE_REGISTERS_SPACE, 0, &cp->cmd_ioh))
continue;
if (bus_space_map(cp->ctl_iot, iobase +
simide_info[channel].aux_register, 4, 0, &cp->ctl_ioh)) {
bus_space_unmap(cp->cmd_iot, cp->cmd_ioh,
DRIVE_REGISTERS_SPACE);
continue;
}
/* Disable interrupts and clear any pending interrupts */
sc->simide_channels[channel].sc_irqmask =
simide_info[channel].irq_mask;
sc->sc_ctl_reg &= ~sc->simide_channels[channel].sc_irqmask;
bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
wdcattach(cp);
ihp = &sc->simide_channels[channel].sc_ih;
ihp->ih_func = simide_intr;
ihp->ih_arg = cp;
ihp->ih_level = IPL_BIO;
ihp->ih_name = "simide";
ihp->ih_maskaddr = pa->pa_podule->irq_addr;
ihp->ih_maskbits = sc->simide_channels[channel].sc_irqmask;
if (irq_claim(sc->sc_podule->interrupt, ihp))
panic("%s: Cannot claim interrupt %d\n",
self->dv_xname, sc->sc_podule->interrupt);
/* clear any pending interrupts and enable interrupts */
sc->sc_ctl_reg |= sc->simide_channels[channel].sc_irqmask;
bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
}
sa.sa_channel = 0;
config_found_sm(self, &sa, simide_print, NULL);
sa.sa_channel = 1;
config_found_sm(self, &sa, simide_print, NULL);
}
/*
@ -269,179 +312,23 @@ simide_shutdown(arg)
CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
}
/*
* Simtec IDE probe and attach code for the wdc device.
*
* This provides a different pair of probe and attach functions
* for attaching the wdc device to the Simtec IDE card.
*/
struct wdc_simide_softc {
struct wdc_softc sc_wdcdev; /* Device node */
struct wdc_attachment_data sc_ad; /* Attachment data */
irqhandler_t sc_ih; /* interrupt handler */
int sc_irqmask; /* IRQ mask for this channel */
int sc_channel; /* channel number */
struct simide_softc *sc_psoftc; /* pointer to parent */
};
int wdc_simide_probe __P((struct device *, struct cfdata *, void *));
void wdc_simide_attach __P((struct device *, struct device *, void *));
int wdc_simide_intr __P((void *));
struct cfattach wdc_sim_ca = {
sizeof(struct wdc_simide_softc), wdc_simide_probe, wdc_simide_attach
};
/*
* Create an array of address structures. These define the addresses and
* masks needed for the different channels.
*
* index = channel
*/
struct {
u_int drive_registers;
u_int aux_register;
u_int irq_mask;
} simide_info[] = {
{ PRIMARY_DRIVE_REGISTERS_POFFSET, PRIMARY_AUX_REGISTER_POFFSET,
CONTROL_PRIMARY_IRQ },
{ SECONDARY_DRIVE_REGISTERS_POFFSET, SECONDARY_AUX_REGISTER_POFFSET,
CONTROL_SECONDARY_IRQ }
};
/*
* Controller probe function
*
* Map all the required I/O space for this channel, make sure interrupts
* are disabled and probe the bus.
*/
int
wdc_simide_probe(parent, cf, aux)
struct device *parent;
struct cfdata *cf;
void *aux;
{
struct simide_attach_args *sa = (void *)aux;
struct wdc_attachment_data ad;
struct simide_softc *sc;
int result = 0;
bzero(&ad, sizeof ad);
sc = sa->sa_softc;
#ifdef DIAGNOSTIC
if (sa->sa_channel < 0 || sa->sa_channel > 1)
return(0);
#endif /* DIAGNOSTIC */
ad.iot = sa->sa_iot;
if (bus_space_map(ad.iot, sa->sa_iobase +
simide_info[sa->sa_channel].drive_registers, DRIVE_REGISTERS_SPACE,
0, &ad.ioh))
return(0);
ad.auxiot = sa->sa_iot;
if (bus_space_map(ad.auxiot, sa->sa_iobase +
simide_info[sa->sa_channel].aux_register, 4, 0, &ad.auxioh)) {
bus_space_unmap(ad.iot, ad.ioh, DRIVE_REGISTERS_SPACE);
return(0);
}
/* Disable interrupts and clear any pending interrupts */
sc->sc_ctl_reg &= ~simide_info[sa->sa_channel].irq_mask;
bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
result = wdcprobe(&ad);
bus_space_unmap(ad.auxiot, ad.auxioh, DRIVE_REGISTERS_SPACE);
bus_space_unmap(ad.iot, ad.ioh, 4);
return(result);
}
/*
* Controller attach function
*
* Map all the required I/O space for this channel, disble interrupts
* and attach the controller. The generic attach will probe and attach
* any devices.
* Install an interrupt handler and we are ready to rock.
*/
void
wdc_simide_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct wdc_simide_softc *wdc = (void *)self;
struct simide_attach_args *sa = (void *)aux;
struct podule_attach_args *pa = sa->sa_pa;
struct simide_softc *sc;
printf("\n");
wdc->sc_psoftc = sc = sa->sa_softc;
wdc->sc_channel = sa->sa_channel;
wdc->sc_irqmask = simide_info[wdc->sc_channel].irq_mask;
bzero(&wdc->sc_ad, sizeof wdc->sc_ad);
wdc->sc_ad.iot = sa->sa_iot;
wdc->sc_ad.auxiot = sa->sa_iot;
if (bus_space_map(wdc->sc_ad.iot, sa->sa_iobase +
simide_info[wdc->sc_channel].drive_registers,
DRIVE_REGISTERS_SPACE, 0, &wdc->sc_ad.ioh))
panic("%s: Cannot map drive registers\n", self->dv_xname);
if (bus_space_map(wdc->sc_ad.auxiot, sa->sa_iobase +
simide_info[wdc->sc_channel].aux_register, 4, 0, &wdc->sc_ad.auxioh))
panic("%s: Cannot map auxilary register\n", self->dv_xname);
/* Disable interrupts and clear any pending interrupts */
sc->sc_ctl_reg &= ~wdc->sc_irqmask;
bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
wdcattach(&wdc->sc_wdcdev, &wdc->sc_ad);
wdc->sc_ih.ih_func = wdc_simide_intr;
wdc->sc_ih.ih_arg = wdc;
wdc->sc_ih.ih_level = IPL_BIO;
wdc->sc_ih.ih_name = "simide";
wdc->sc_ih.ih_maskaddr = pa->pa_podule->irq_addr;
wdc->sc_ih.ih_maskbits = wdc->sc_irqmask;
if (irq_claim(pa->pa_podule->interrupt, &wdc->sc_ih))
panic("%s: Cannot claim interrupt %d\n", self->dv_xname,
pa->pa_podule->interrupt);
/* clear any pending interrupts and enable interrupts */
sc->sc_ctl_reg |= wdc->sc_irqmask;
bus_space_write_1(sc->sc_ctliot, sc->sc_ctlioh,
CONTROL_REGISTER_OFFSET, sc->sc_ctl_reg);
}
/*
* Podule interrupt handler
*
* If the interrupt was from our card pass it on to the wdc interrupt handler
*/
int
wdc_simide_intr(arg)
simide_intr(arg)
void *arg;
{
struct wdc_simide_softc *wdc = arg;
volatile u_char *intraddr = (volatile u_char *)wdc->sc_ih.ih_maskaddr;
struct channel_softc *chp = arg;
struct simide_softc *sc = (struct simide_softc *)chp->wdc;
irqhandler_t *ihp = &sc->simide_channels[chp->channel].sc_ih;
volatile u_char *intraddr = (volatile u_char *)ihp->ih_maskaddr;
/* XXX - not bus space yet - should really be handled by podulebus */
if ((*intraddr) & wdc->sc_ih.ih_maskbits)
wdcintr(arg);
if ((*intraddr) & ihp->ih_maskbits)
wdcintr(chp);
return(0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdc_mb.c,v 1.2 1998/08/15 10:11:01 mycroft Exp $ */
/* $NetBSD: wdc_mb.c,v 1.3 1998/10/12 16:09:12 bouyer Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -39,6 +39,7 @@
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <machine/cpu.h>
@ -47,6 +48,7 @@
#include <machine/mfp.h>
#include <machine/dma.h>
#include <dev/ata/atavar.h>
#include <dev/ic/wdcvar.h>
#include <m68k/asm_single.h>
@ -59,10 +61,14 @@
*/
static int claim_hw __P((void *, int));
static void free_hw __P((void *));
static void read_multi_2_swap __P((bus_space_tag_t, bus_space_handle_t,
bus_size_t, u_int16_t *, bus_size_t));
static void write_multi_2_swap __P((bus_space_tag_t, bus_space_handle_t,
bus_size_t, const u_int16_t *, bus_size_t));
struct wdc_mb_softc {
struct wdc_softc sc_wdcdev;
struct wdc_attachment_data sc_ad;
struct channel_softc wdc_channel;
void *sc_ih;
};
@ -79,33 +85,24 @@ wdc_mb_probe(parent, cfp, aux)
struct cfdata *cfp;
void *aux;
{
#if 0 /* XXX memset */
struct wdc_attachment_data ad = { 0 };
#else /* XXX memset */
struct wdc_attachment_data ad;
#endif /* XXX memset */
struct channel_softc ch = { 0 };
int result = 0;
u_char sv_ierb;
#if 0 /* XXX memset */
#else /* XXX memset */
bzero(&ad, sizeof ad);
#endif /* XXX memset */
if ((machineid & ATARI_TT) || strcmp("wdc", aux) || cfp->cf_unit != 0)
return 0;
if (!atari_realconfig)
return 0;
ad.iot = ad.auxiot = mb_alloc_bus_space_tag();
if (ad.iot == NULL)
ch.cmd_iot = ch.ctl_iot = mb_alloc_bus_space_tag();
if (ch.cmd_iot == NULL)
return 0;
ad.iot->stride = 2;
ad.iot->wo_1 = 1;
ch.cmd_iot->stride = 2;
ch.cmd_iot->wo_1 = 1;
if (bus_space_map(ad.iot, 0xfff00000, 0x40, 0, &ad.ioh))
if (bus_space_map(ch.cmd_iot, 0xfff00000, 0x40, 0, &ch.cmd_ioh))
return 0;
if (bus_space_subregion(ad.iot, ad.ioh, 0x38, 1, &ad.auxioh))
if (bus_space_subregion(ch.cmd_iot, ch.cmd_ioh, 0x38, 1, &ch.ctl_ioh))
return 0;
/*
@ -120,12 +117,12 @@ wdc_mb_probe(parent, cfp, aux)
if (machineid & ATARI_FALCON)
ym2149_ser2(0);
result = wdcprobe(&ad);
result = wdcprobe(&ch);
MFP->mf_ierb = sv_ierb;
bus_space_unmap(ad.iot, ad.ioh, 0x40);
mb_free_bus_space_tag(ad.iot);
bus_space_unmap(ch.cmd_iot, ch.cmd_ioh, 0x40);
mb_free_bus_space_tag(ch.cmd_iot);
return (result);
}
@ -139,17 +136,20 @@ wdc_mb_attach(parent, self, aux)
printf("\n");
sc->sc_ad.iot = sc->sc_ad.auxiot = mb_alloc_bus_space_tag();
sc->sc_ad.iot->stride = 2;
sc->sc_ad.iot->wo_1 = 1;
if (bus_space_map(sc->sc_ad.iot, 0xfff00000, 0x40, 0,
&sc->sc_ad.ioh)) {
sc->wdc_channel.cmd_iot = sc->wdc_channel.ctl_iot =
mb_alloc_bus_space_tag();
sc->wdc_channel.cmd_iot->stride = 2;
sc->wdc_channel.cmd_iot->wo_1 = 1;
sc->wdc_channel.cmd_iot->abs_rms_2 = read_multi_2_swap;
sc->wdc_channel.cmd_iot->abs_wms_2 = write_multi_2_swap;
if (bus_space_map(sc->wdc_channel.cmd_iot, 0xfff00000, 0x40, 0,
&sc->wdc_channel.cmd_ioh)) {
printf("%s: couldn't map registers\n",
sc->sc_wdcdev.sc_dev.dv_xname);
return;
}
if (bus_space_subregion(sc->sc_ad.iot, sc->sc_ad.ioh, 0x38, 1,
&sc->sc_ad.auxioh))
if (bus_space_subregion(sc->wdc_channel.cmd_iot,
sc->wdc_channel.cmd_ioh, 0x38, 1, &sc->wdc_channel.ctl_ioh))
return;
/*
@ -159,16 +159,23 @@ wdc_mb_attach(parent, self, aux)
*/
MFP->mf_ierb &= ~IB_DINT;
/*
* XXX: Is this true on all atari's??
*/
sc->sc_wdcdev.sc_flags |= WDCF_SINGLE;
sc->sc_ad.cap |= WDC_CAPABILITY_HWLOCK;
sc->sc_ad.claim_hw = &claim_hw;
sc->sc_ad.free_hw = &free_hw;
wdcattach(&sc->sc_wdcdev, &sc->sc_ad);
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_HWLOCK |
WDC_CAPABILITY_ATA_NOSTREAM;
sc->sc_wdcdev.pio_mode = 0;
sc->sc_wdcdev.claim_hw = &claim_hw;
sc->sc_wdcdev.free_hw = &free_hw;
sc->sc_wdcdev.channels = &sc->wdc_channel;
sc->sc_wdcdev.nchannels = 1;
sc->wdc_channel.channel = 0;
sc->wdc_channel.wdc = &sc->sc_wdcdev;
sc->wdc_channel.ch_queue = malloc(sizeof(struct channel_queue),
M_DEVBUF, M_NOWAIT);
if (sc->wdc_channel.ch_queue == NULL) {
printf("%s: can't allocate memory for command queue",
sc->sc_wdcdev.sc_dev.dv_xname);
return;
}
wdcattach(&sc->wdc_channel);
/*
* Setup & enable disk related interrupts.
@ -188,8 +195,6 @@ claim_hw(softc, maysleep)
void *softc;
int maysleep;
{
void wdcrestart __P((void *));
if (wd_lock != DMA_LOCK_GRANT) {
if (wd_lock == DMA_LOCK_REQ) {
/*
@ -220,3 +225,40 @@ void *softc;
/* if (machineid & ATARI_FALCON) */
st_dmafree(softc, &wd_lock);
}
/*
* XXX
* This piece of uglyness is caused by the fact that the byte lanes of
* the data-register are swapped on the atari. This works OK for an IDE
* disk, but turns into a nightmare when used on atapi devices.
*/
#define calc_addr(base, off, stride, wm) \
((u_long)(base) + ((off) << (stride)) + (wm))
static void
read_multi_2_swap(t, h, o, a, c)
bus_space_tag_t t;
bus_space_handle_t h;
bus_size_t o, c;
u_int16_t *a;
{
u_int16_t *ba;
ba = (u_int16_t *)calc_addr(h, o, t->stride, t->wo_2);
for (; c; a++, c--)
*a = bswap16(*ba);
}
static void
write_multi_2_swap(t, h, o, a, c)
bus_space_tag_t t;
bus_space_handle_t h;
bus_size_t o, c;
const u_int16_t *a;
{
u_int16_t *ba;
ba = (u_int16_t *)calc_addr(h, o, t->stride, t->wo_2);
for (; c; a++, c--)
*ba = bswap16(*a);
}

View File

@ -1,4 +1,4 @@
# $NetBSD: GENERIC,v 1.188 1998/10/10 21:58:22 thorpej Exp $
# $NetBSD: GENERIC,v 1.189 1998/10/12 16:09:13 bouyer Exp $
#
# GENERIC -- everything that's currently supported
#
@ -309,22 +309,26 @@ uk* at scsibus? target ? lun ? # SCSI unknown
# IDE and Related Devices
# PCI IDE controllers (CMD tech's PCI0640, Intel's PIIx).
#pciide* at pci ? dev ? function ?
# ISA Plug-and-Play IDE controllers
wdc* at isapnp?
wdc* at isapnp? flags 0x0000
# PCMCIA IDE controllers
wdc* at pcmcia? function ?
wdc* at pcmcia? function ?
# ISA IDE controllers
wdc0 at isa? port 0x1f0 irq 14 # ST506, ESDI, and IDE controllers
# ISA ST506, ESDI, and IDE controllers
wdc0 at isa? port 0x1f0 irq 14
wdc1 at isa? port 0x170 irq 15
# IDE drives
wd* at wdc? drive ? # the drives themselves
wd* at wdc? channel ? drive ?
#wd* at pciide? channel ? drive ?
# ATAPI bus support
atapibus* at wdc?
atapibus* at wdc? channel ?
#atapibus* at pciide? channel ?
# ATAPI devices
cd* at atapibus? drive ? # ATAPI CD-ROM drives

View File

@ -1,4 +1,4 @@
# $NetBSD: files.i386,v 1.122 1998/10/03 23:17:03 fvdl Exp $
# $NetBSD: files.i386,v 1.123 1998/10/12 16:09:13 bouyer Exp $
#
# new style config file for i386 architecture
#
@ -129,17 +129,6 @@ major {wt = 3}
attach lpt at puc with lpt_puc
file dev/pci/lpt_puc.c lpt_puc
# XXX THE FOLLOWING BLOCK SHOULD GO INTO dev/pci/files.pci, BUT CANNOT
# XXX BECAUSE NOT ALL PORTS USE THE MI DRIVER YET. (when the conf/files
# XXX and files.isa bogons are fixed, this can be fixed as well.)
# PCI IDE controllers
device pciide {[channel = -1]}
attach pciide at pci
file dev/pci/pciide.c pciide
attach wdc at pciide with wdc_pciide
file dev/pci/wdc_pciide.c wdc_pciide
file arch/i386/isa/isa_machdep.c isa
# PC clock

View File

@ -1,4 +1,4 @@
# $NetBSD: files,v 1.248 1998/09/26 16:28:16 dante Exp $
# $NetBSD: files,v 1.249 1998/10/12 16:09:14 bouyer Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@ -103,9 +103,10 @@ devclass tty
define audio { }
define midibus { }
define midisyn
define wdc_base
define scsi {[channel = -1]}
define ata {[drive = -1]}
define atapi { }
define ata {[channel = -1], [drive = -1]}
define atapi {[channel = -1]}
define mii {[phy = -1]}
# audio device attributes
@ -303,10 +304,9 @@ file dev/ic/lsi64854.c lsi64854
# XXX THE FOLLOWING BLOCK SHOULD BE UNCOMMENTED, BUT CANNOT
# XXX BECAUSE NOT ALL PORTS USE THE MI wdc DRIVER YET.
#
# # ESDI/IDE/etc. controllers
# device wdc: ata, atapi
# file dev/ic/wdc.c
# wdc & (wd | !wd) needs-flag # XXX
# device wdc: ata, atapi, wdc_base
# # Common code for ESDI/IDE/etc. controllers
file dev/ic/wdc.c wdc_base
# Definitions for wscons
# device attributes: display, display with emulator, keyboard, and mouse

151
sys/dev/ata/ata.c Normal file
View File

@ -0,0 +1,151 @@
/* $NetBSD: ata.c,v 1.2 1998/10/12 16:09:14 bouyer Exp $ */
/*
* Copyright (c) 1998 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Manuel Bouyer.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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.
*/
#define WDCDEBUG
#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 <dev/ic/wdcreg.h>
#include <dev/ata/atareg.h>
#include <dev/ata/atavar.h>
#define DEBUG_FUNCS 0x08
#define DEBUG_PROBE 0x10
#ifdef WDCDEBUG
extern int wdcdebug_mask; /* init'ed in wdc.c */
#define WDCDEBUG_PRINT(args, level) \
if (wdcdebug_mask & (level)) \
printf args
#else
#define WDCDEBUG_PRINT(args, level)
#endif
/* Get the disk's parameters */
int
ata_get_params(drvp, flags, prms)
struct ata_drive_datas *drvp;
u_int8_t flags;
struct ataparams *prms;
{
char tb[DEV_BSIZE];
struct wdc_command wdc_c;
#if BYTE_ORDER == LITTLE_ENDIAN
int i;
u_int16_t *p;
#endif
WDCDEBUG_PRINT(("wdc_ata_get_parms\n"), DEBUG_FUNCS);
memset(tb, 0, DEV_BSIZE);
memset(prms, 0, sizeof(struct ataparams));
memset(&wdc_c, 0, sizeof(struct wdc_command));
if (drvp->drive_flags & DRIVE_ATA) {
wdc_c.r_command = WDCC_IDENTIFY;
wdc_c.r_st_bmask = WDCS_DRDY | WDCS_DSC;
wdc_c.r_st_pmask = WDCS_DRDY | WDCS_DSC | WDCS_DRQ;
} else {
wdc_c.r_command = ATAPI_IDENTIFY_DEVICE;
wdc_c.r_st_bmask = 0;
wdc_c.r_st_pmask = WDCS_DRDY | WDCS_DRQ;
}
wdc_c.flags = AT_READ | flags;
wdc_c.timeout = 1000; /* 1s */
wdc_c.data = tb;
wdc_c.bcount = DEV_BSIZE;
if (wdc_exec_command(drvp, &wdc_c) != WDC_COMPLETE)
return CMD_AGAIN;
if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
return CMD_ERR;
} else {
/* Read in parameter block. */
memcpy(prms, tb, sizeof(struct ataparams));
#if BYTE_ORDER == LITTLE_ENDIAN
/*
* Shuffle string byte order.
* ATAPI Mitsumi and NEC drives don't need this.
*/
if ((prms->atap_config & WDC_CFG_ATAPI_MASK) ==
WDC_CFG_ATAPI &&
((prms->atap_model[0] == 'N' &&
prms->atap_model[1] == 'E') ||
(prms->atap_model[0] == 'F' &&
prms->atap_model[1] == 'X')))
return 0;
for (i = 0; i < sizeof(prms->atap_model); i += 2) {
p = (u_short *)(prms->atap_model + i);
*p = ntohs(*p);
}
for (i = 0; i < sizeof(prms->atap_serial); i += 2) {
p = (u_short *)(prms->atap_serial + i);
*p = ntohs(*p);
}
for (i = 0; i < sizeof(prms->atap_revision); i += 2) {
p = (u_short *)(prms->atap_revision + i);
*p = ntohs(*p);
}
#endif
return CMD_OK;
}
}
int
ata_set_mode(drvp, mode, flags)
struct ata_drive_datas *drvp;
u_int8_t mode;
u_int8_t flags;
{
struct wdc_command wdc_c;
WDCDEBUG_PRINT(("wdc_ata_set_mode=0x%x\n", mode), DEBUG_FUNCS);
memset(&wdc_c, 0, sizeof(struct wdc_command));
wdc_c.r_command = SET_FEATURES;
wdc_c.r_st_bmask = 0;
wdc_c.r_st_pmask = 0;
wdc_c.r_precomp = WDSF_SET_MODE;
wdc_c.r_count = mode;
wdc_c.flags = AT_READ | flags;
wdc_c.timeout = 1000; /* 1s */
if (wdc_exec_command(drvp, &wdc_c) != WDC_COMPLETE)
return CMD_AGAIN;
if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
return CMD_ERR;
}
return CMD_OK;
}

731
sys/dev/ata/ata_wdc.c Normal file
View File

@ -0,0 +1,731 @@
/* $NetBSD: ata_wdc.c,v 1.2 1998/10/12 16:09:15 bouyer Exp $ */
/*
* Copyright (c) 1998 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
*/
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Charles M. Hannum, by Onno van der Linden and by 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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.
*/
#define WDCDEBUG
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/buf.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/syslog.h>
#include <sys/proc.h>
#include <machine/intr.h>
#include <machine/bus.h>
#ifndef __BUS_SPACE_HAS_STREAM_METHODS
#define bus_space_write_multi_stream_2 bus_space_write_multi_2
#define bus_space_write_multi_stream_4 bus_space_write_multi_4
#define bus_space_read_multi_stream_2 bus_space_read_multi_2
#define bus_space_read_multi_stream_4 bus_space_read_multi_4
#endif /* __BUS_SPACE_HAS_STREAM_METHODS */
#include <dev/ata/atareg.h>
#include <dev/ata/atavar.h>
#include <dev/ic/wdcreg.h>
#include <dev/ic/wdcvar.h>
#include <dev/ata/wdvar.h>
#define DEBUG_INTR 0x01
#define DEBUG_XFERS 0x02
#define DEBUG_STATUS 0x04
#define DEBUG_FUNCS 0x08
#define DEBUG_PROBE 0x10
#ifdef WDCDEBUG
int wdcdebug_wd_mask = DEBUG_PROBE;
#define WDCDEBUG_PRINT(args, level) \
if (wdcdebug_wd_mask & (level)) \
printf args
#else
#define WDCDEBUG_PRINT(args, level)
#endif
#define ATA_DELAY 10000 /* 10s for a drive I/O */
void wdc_ata_bio_start __P((struct channel_softc *,struct wdc_xfer *));
int wdc_ata_bio_intr __P((struct channel_softc *, struct wdc_xfer *));
void wdc_ata_bio_done __P((struct channel_softc *, struct wdc_xfer *));
int wdc_ata_ctrl_intr __P((struct channel_softc *, struct wdc_xfer *));
int wdc_ata_err __P((struct channel_softc *, struct ata_bio *));
#define WDC_ATA_NOERR 0x00 /* Drive doesn't report an error */
#define WDC_ATA_RECOV 0x01 /* There was a recovered error */
#define WDC_ATA_ERR 0x02 /* Drive reports an error */
/*
* Handle block I/O operation. Return WDC_COMPLETE, WDC_QUEUED, or
* WDC_TRY_AGAIN. Must be called at splio().
*/
int
wdc_ata_bio(drvp, ata_bio)
struct ata_drive_datas *drvp;
struct ata_bio *ata_bio;
{
struct wdc_xfer *xfer;
struct channel_softc *chp = drvp->chnl_softc;
xfer = wdc_get_xfer(WDC_NOSLEEP);
if (xfer == NULL)
return WDC_TRY_AGAIN;
if (ata_bio->flags & ATA_POLL)
xfer->c_flags |= C_POLL;
if ((drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) &&
(ata_bio->flags & ATA_SINGLE) == 0)
xfer->c_flags |= C_DMA;
xfer->drive = drvp->drive;
xfer->cmd = ata_bio;
xfer->databuf = ata_bio->databuf;
xfer->c_bcount = ata_bio->bcount;
xfer->c_start = wdc_ata_bio_start;
xfer->c_intr = wdc_ata_bio_intr;
wdc_exec_xfer(chp, xfer);
return (ata_bio->flags & ATA_ITSDONE) ? WDC_COMPLETE : WDC_QUEUED;
}
void
wdc_ata_bio_start(chp, xfer)
struct channel_softc *chp;
struct wdc_xfer *xfer;
{
struct ata_bio *ata_bio = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
u_int16_t cyl;
u_int8_t head, sect, cmd = 0;
int nblks;
int dma_flags = 0;
WDCDEBUG_PRINT(("wdc_ata_bio_start %s:%d:%d\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive),
DEBUG_FUNCS | DEBUG_XFERS);
/* Do control operations specially. */
if (drvp->state < READY) {
/*
* Actually, we want to be careful not to mess with the control
* state if the device is currently busy, but we can assume
* that we never get to this point if that's the case.
*/
/* at this point, we should only be in RECAL state */
if (drvp->state != RECAL) {
printf("%s:%d:%d: bad state %d in wdc_ata_bio_start\n",
chp->wdc->sc_dev.dv_xname, chp->channel,
xfer->drive, drvp->state);
panic("wdc_ata_bio_start: bad state");
}
xfer->c_intr = wdc_ata_ctrl_intr;
bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
WDSD_IBM | (xfer->drive << 4));
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY) != 0)
goto timeout;
wdccommandshort(chp, xfer->drive, WDCC_RECAL);
drvp->state = RECAL_WAIT;
if ((ata_bio->flags & ATA_POLL) == 0) {
chp->ch_flags |= WDCF_IRQ_WAIT;
timeout(wdctimeout, chp, ATA_DELAY / 1000 * hz);
} else {
/* Wait for at last 400ns for status bit to be valid */
delay(1);
wdc_ata_ctrl_intr(chp, xfer);
}
return;
}
if (xfer->c_flags & C_DMA) {
dma_flags = (ata_bio->flags & ATA_READ) ? WDC_DMA_READ : 0;
dma_flags |= (ata_bio->flags & ATA_POLL) ? WDC_DMA_POLL : 0;
}
again:
/*
*
* When starting a multi-sector transfer, or doing single-sector
* transfers...
*/
if (xfer->c_skip == 0 || (ata_bio->flags & ATA_SINGLE) != 0) {
if (ata_bio->flags & ATA_SINGLE)
nblks = 1;
else
nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
/* Check for bad sectors and adjust transfer, if necessary. */
if ((ata_bio->lp->d_flags & D_BADSECT) != 0) {
long blkdiff;
int i;
for (i = 0; (blkdiff = ata_bio->badsect[i]) != -1;
i++) {
blkdiff -= ata_bio->blkno;
if (blkdiff < 0)
continue;
if (blkdiff == 0) {
/* Replace current block of transfer. */
ata_bio->blkno =
ata_bio->lp->d_secperunit -
ata_bio->lp->d_nsectors - i - 1;
}
if (blkdiff < nblks) {
/* Bad block inside transfer. */
ata_bio->flags |= ATA_SINGLE;
nblks = 1;
}
break;
}
/* Transfer is okay now. */
}
if (ata_bio->flags & ATA_LBA) {
sect = (ata_bio->blkno >> 0) & 0xff;
cyl = (ata_bio->blkno >> 8) & 0xffff;
head = (ata_bio->blkno >> 24) & 0x0f;
head |= WDSD_LBA;
} else {
int blkno = ata_bio->blkno;
sect = blkno % ata_bio->lp->d_nsectors;
sect++; /* Sectors begin with 1, not 0. */
blkno /= ata_bio->lp->d_nsectors;
head = blkno % ata_bio->lp->d_ntracks;
blkno /= ata_bio->lp->d_ntracks;
cyl = blkno;
head |= WDSD_CHS;
}
if (xfer->c_flags & C_DMA) {
ata_bio->nblks = nblks;
ata_bio->nbytes = xfer->c_bcount;
cmd = (ata_bio->flags & ATA_READ) ?
WDCC_READDMA : WDCC_WRITEDMA;
nblks = ata_bio->nblks;
/* Init the DMA channel. */
if ((*chp->wdc->dma_init)(chp->wdc->dma_arg,
chp->channel, xfer->drive,
xfer->databuf + xfer->c_skip, ata_bio->nbytes,
dma_flags) != 0) {
ata_bio->error = ERR_DMA;
ata_bio->r_error = 0;
wdc_ata_bio_done(chp, xfer);
return;
}
/* Initiate command */
bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
WDSD_IBM | (xfer->drive << 4));
if (wait_for_ready(chp, ATA_DELAY) < 0)
goto timeout;
wdccommand(chp, xfer->drive, cmd, cyl,
head, sect, nblks, 0);
/* start the DMA channel */
(*chp->wdc->dma_start)(chp->wdc->dma_arg,
chp->channel, xfer->drive, dma_flags);
/* wait for irq */
goto intr;
} /* else not DMA */
ata_bio->nblks = min(nblks, ata_bio->multi);
ata_bio->nbytes = ata_bio->nblks * ata_bio->lp->d_secsize;
if (ata_bio->nblks > 1 && (ata_bio->flags & ATA_SINGLE) == 0) {
cmd = (ata_bio->flags & ATA_READ) ?
WDCC_READMULTI : WDCC_WRITEMULTI;
} else {
cmd = (ata_bio->flags & ATA_READ) ?
WDCC_READ : WDCC_WRITE;
}
/* Initiate command! */
bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
WDSD_IBM | (xfer->drive << 4));
if (wait_for_ready(chp, ATA_DELAY) < 0)
goto timeout;
wdccommand(chp, xfer->drive, cmd, cyl,
head, sect, nblks,
(ata_bio->lp->d_type == DTYPE_ST506) ?
ata_bio->lp->d_precompcyl / 4 : 0);
} else if (ata_bio->nblks > 1) {
/* The number of blocks in the last stretch may be smaller. */
nblks = xfer->c_bcount / ata_bio->lp->d_secsize;
if (ata_bio->nblks > nblks) {
ata_bio->nblks = nblks;
ata_bio->nbytes = xfer->c_bcount;
}
}
/* If this was a write and not using DMA, push the data. */
if ((ata_bio->flags & ATA_READ) == 0) {
if (wait_for_drq(chp, ATA_DELAY) != 0) {
printf("%s:%d:%d: timeout waiting for DRQ, "
"st=0x%02x, err=0x%02x\n",
chp->wdc->sc_dev.dv_xname, chp->channel,
xfer->drive, chp->ch_status, chp->ch_error);
if (wdc_ata_err(chp, ata_bio) != WDC_ATA_ERR)
ata_bio->error = TIMEOUT;
wdc_ata_bio_done(chp, xfer);
return;
}
if (wdc_ata_err(chp, ata_bio) == WDC_ATA_ERR) {
wdc_ata_bio_done(chp, xfer);
return;
}
if ((chp->wdc->cap & WDC_CAPABILITY_ATA_NOSTREAM)) {
if (drvp->drive_flags & DRIVE_CAP32) {
bus_space_write_multi_4(chp->data32iot,
chp->data32ioh, 0,
xfer->databuf + xfer->c_skip,
ata_bio->nbytes >> 2);
} else {
bus_space_write_multi_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip,
ata_bio->nbytes >> 1);
}
} else {
if (drvp->drive_flags & DRIVE_CAP32) {
bus_space_write_multi_stream_4(chp->data32iot,
chp->data32ioh, 0,
xfer->databuf + xfer->c_skip,
ata_bio->nbytes >> 2);
} else {
bus_space_write_multi_stream_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip,
ata_bio->nbytes >> 1);
}
}
}
intr: /* Wait for IRQ (either real or polled) */
if ((ata_bio->flags & ATA_POLL) == 0) {
chp->ch_flags |= WDCF_IRQ_WAIT;
timeout(wdctimeout, chp, ATA_DELAY / 1000 * hz);
} else {
/* Wait for at last 400ns for status bit to be valid */
delay(1);
wdc_ata_bio_intr(chp, xfer);
if ((ata_bio->flags & ATA_ITSDONE) == 0)
goto again;
}
return;
timeout:
printf("%s:%d:%d: not ready, st=0x%02x, err=0x%02x\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
chp->ch_status, chp->ch_error);
if (wdc_ata_err(chp, ata_bio) != WDC_ATA_ERR)
ata_bio->error = TIMEOUT;
wdc_ata_bio_done(chp, xfer);
return;
}
int
wdc_ata_bio_intr(chp, xfer)
struct channel_softc *chp;
struct wdc_xfer *xfer;
{
struct ata_bio *ata_bio = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
int drv_err;
int dma_flags = 0;
WDCDEBUG_PRINT(("wdc_ata_bio_intr %s:%d:%d\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive),
DEBUG_INTR | DEBUG_XFERS);
/* Is it not a transfer, but a control operation? */
if (drvp->state < READY) {
printf("%s:%d:%d: bad state %d in wdc_ata_bio_intr\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
drvp->state);
panic("wdc_ata_bio_intr: bad state\n");
}
if (xfer->c_flags & C_DMA) {
dma_flags = (ata_bio->flags & ATA_READ) ? WDC_DMA_READ : 0;
dma_flags |= (ata_bio->flags & ATA_POLL) ? WDC_DMA_POLL : 0;
}
/* Ack interrupt done by wait_for_unbusy */
if (wait_for_unbusy(chp, ATA_DELAY) < 0) {
printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip%d\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
xfer->c_bcount, xfer->c_skip);
/* if we were using DMA, turn off DMA channel */
if (xfer->c_flags & C_DMA)
(*chp->wdc->dma_finish)(chp->wdc->dma_arg,
chp->channel, xfer->drive, dma_flags);
ata_bio->error = TIMEOUT;
wdc_ata_bio_done(chp, xfer);
return 1;
}
drv_err = wdc_ata_err(chp, ata_bio);
/* If we were using DMA, Turn off the DMA channel and check for error */
if (xfer->c_flags & C_DMA) {
if (ata_bio->flags & ATA_POLL) {
/*
* IDE drives deassert WDCS_BSY before trasfert is
* complete when using DMA. Polling for DRQ to deassert
* is not enouth DRQ is not required to be
* asserted for DMA transferts, so poll for DRDY.
*/
if (wdcwait(chp, WDCS_DRDY | WDCS_DRQ, WDCS_DRDY,
ATA_DELAY) < 0) {
printf("%s:%d:%d: polled transfert timed out "
"(st=0x%x)\n", chp->wdc->sc_dev.dv_xname,
chp->channel, xfer->drive, chp->ch_status);
ata_bio->error = TIMEOUT;
wdc_ata_bio_done(chp, xfer);
return 1;
}
}
if (chp->ch_status & WDCS_DRQ) {
if (drv_err != WDC_ATA_ERR) {
printf("%s:%d:%d: intr with DRQ (st=0x%x)\n",
chp->wdc->sc_dev.dv_xname, chp->channel,
xfer->drive, chp->ch_status);
ata_bio->error = TIMEOUT;
drv_err = WDC_ATA_ERR;
}
}
if ((*chp->wdc->dma_finish)(chp->wdc->dma_arg,
chp->channel, xfer->drive, dma_flags) != 0) {
if (drv_err != WDC_ATA_ERR) {
ata_bio->error = ERR_DMA;
drv_err = WDC_ATA_ERR;
}
}
if (drv_err != WDC_ATA_ERR)
goto end;
}
/* if we had an error, end */
if (drv_err == WDC_ATA_ERR) {
wdc_ata_bio_done(chp, xfer);
return 1;
}
/* If this was a read and not using DMA, fetch the data. */
if ((ata_bio->flags & ATA_READ) != 0) {
if ((chp->ch_status & (WDCS_DRDY | WDCS_DSC | WDCS_DRQ)) !=
(WDCS_DRDY | WDCS_DSC | WDCS_DRQ)) {
printf("%s:%d:%d: read intr before drq\n",
chp->wdc->sc_dev.dv_xname, chp->channel,
xfer->drive);
ata_bio->error = TIMEOUT;
wdc_ata_bio_done(chp, xfer);
return 1;
}
if ((chp->wdc->cap & WDC_CAPABILITY_ATA_NOSTREAM)) {
if (drvp->drive_flags & DRIVE_CAP32) {
bus_space_read_multi_4(chp->data32iot,
chp->data32ioh, 0,
xfer->databuf + xfer->c_skip,
ata_bio->nbytes >> 2);
} else {
bus_space_read_multi_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip,
ata_bio->nbytes >> 1);
}
} else {
if (drvp->drive_flags & DRIVE_CAP32) {
bus_space_read_multi_stream_4(chp->data32iot,
chp->data32ioh, 0,
xfer->databuf + xfer->c_skip,
ata_bio->nbytes >> 2);
} else {
bus_space_read_multi_stream_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip,
ata_bio->nbytes >> 1);
}
}
}
end:
ata_bio->blkno += ata_bio->nblks;
ata_bio->blkdone += ata_bio->nblks;
xfer->c_skip += ata_bio->nbytes;
xfer->c_bcount -= ata_bio->nbytes;
/* See if this transfer is complete. */
if (xfer->c_bcount > 0) {
if ((ata_bio->flags & ATA_POLL) == 0) {
/* Start the next operation */
wdc_ata_bio_start(chp, xfer);
} else {
/* Let wdc_ata_bio_start do the loop */
return 1;
}
} else { /* Done with this transfer */
ata_bio->error = NOERROR;
wdc_ata_bio_done(chp, xfer);
}
return 1;
}
void
wdc_ata_bio_done(chp, xfer)
struct channel_softc *chp;
struct wdc_xfer *xfer;
{
struct ata_bio *ata_bio = xfer->cmd;
int need_done = xfer->c_flags & C_NEEDDONE;
int drive = xfer->drive;
WDCDEBUG_PRINT(("wdc_ata_bio_done: flags 0x%x\n", (u_int)xfer->c_flags),
DEBUG_FUNCS);
/* feed back residual bcount to our caller */
ata_bio->bcount = xfer->c_bcount;
/* remove this command from xfer queue */
wdc_free_xfer(chp, xfer);
ata_bio->flags |= ATA_ITSDONE;
if (need_done) {
WDCDEBUG_PRINT(("wdc_ata_done: wddone\n"), DEBUG_FUNCS);
wddone(chp->ch_drive[drive].drv_softc);
}
WDCDEBUG_PRINT(("wdcstart from wdc_ata_done, flags 0x%x\n",
chp->ch_flags), DEBUG_FUNCS);
wdcstart(chp->wdc, chp->channel);
}
/*
* Implement operations needed before read/write.
*/
int
wdc_ata_ctrl_intr(chp, xfer)
struct channel_softc *chp;
struct wdc_xfer *xfer;
{
struct ata_bio *ata_bio = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
char *errstring = NULL;
WDCDEBUG_PRINT(("wdc_ata_ctrl_intr: state %d\n", drvp->state),
DEBUG_FUNCS);
again:
switch (drvp->state) {
case RECAL: /* Should not be in this state here */
panic("wdc_ata_ctrl_intr: state==RECAL");
break;
case RECAL_WAIT:
errstring = "recal";
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY))
goto timeout;
if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
goto error;
/* fall through */
case PIOMODE:
/* Don't try to set modes if controller can't be adjusted */
if ((chp->wdc->cap & WDC_CAPABILITY_MODE) == 0)
goto geometry;
wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
0x08 | drvp->PIO_mode, WDSF_SET_MODE);
drvp->state = PIOMODE_WAIT;
break;
case PIOMODE_WAIT:
errstring = "piomode";
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY))
goto timeout;
if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
goto error;
/* fall through */
case DMAMODE:
if (drvp->drive_flags & DRIVE_UDMA) {
wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
} else if (drvp->drive_flags & DRIVE_DMA) {
wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
0x20 | drvp->DMA_mode, WDSF_SET_MODE);
} else {
goto geometry;
}
drvp->state = DMAMODE_WAIT;
break;
case DMAMODE_WAIT:
errstring = "dmamode";
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY))
goto timeout;
if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
goto error;
/* fall through */
case GEOMETRY:
geometry:
if (ata_bio->flags & ATA_LBA)
goto multimode;
wdccommand(chp, xfer->drive, WDCC_IDP,
ata_bio->lp->d_ncylinders,
ata_bio->lp->d_ntracks - 1, 0, ata_bio->lp->d_nsectors,
(ata_bio->lp->d_type == DTYPE_ST506) ?
ata_bio->lp->d_precompcyl / 4 : 0);
drvp->state = GEOMETRY_WAIT;
break;
case GEOMETRY_WAIT:
errstring = "geometry";
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY))
goto timeout;
if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
goto error;
/* fall through */
case MULTIMODE:
multimode:
if (ata_bio->multi == 1)
goto ready;
wdccommand(chp, xfer->drive, WDCC_SETMULTI, 0, 0, 0,
ata_bio->multi, 0);
drvp->state = MULTIMODE_WAIT;
break;
case MULTIMODE_WAIT:
errstring = "setmulti";
if (wdcwait(chp, WDCS_DRDY, WDCS_DRDY, ATA_DELAY))
goto timeout;
if (chp->ch_status & (WDCS_ERR | WDCS_DWF))
goto error;
/* fall through */
case READY:
ready:
drvp->state = READY;
/*
* The drive is usable now
*/
xfer->c_intr = wdc_ata_bio_intr;
wdc_ata_bio_start(chp, xfer);
return 1;
}
if ((ata_bio->flags & ATA_POLL) == 0) {
chp->ch_flags |= WDCF_IRQ_WAIT;
timeout(wdctimeout, chp, ATA_DELAY / 1000 * hz);
} else {
goto again;
}
return 1;
timeout:
if ((xfer->c_flags & C_TIMEOU) == 0 ) {
return 0; /* IRQ was not for us */
}
printf("%s:%d:%d: %s timed out\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, errstring);
ata_bio->error = TIMEOUT;
drvp->state = 0;
wdc_ata_bio_done(chp, xfer);
return 0;
error:
printf("%s:%d:%d: %s ",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
errstring);
if (chp->ch_status & WDCS_DWF) {
printf("drive fault\n");
ata_bio->error = ERR_DF;
} else {
printf("error (%x)\n", chp->ch_error);
ata_bio->r_error = chp->ch_error;
ata_bio->error = ERROR;
}
drvp->state = 0;
wdc_ata_bio_done(chp, xfer);
return 1;
}
int
wdc_ata_err(chp, ata_bio)
struct channel_softc *chp;
struct ata_bio *ata_bio;
{
ata_bio->error = 0;
if (chp->ch_status & WDCS_BSY) {
ata_bio->error = TIMEOUT;
return WDC_ATA_ERR;
}
if (chp->ch_status & WDCS_DWF) {
ata_bio->error = ERR_DF;
return WDC_ATA_ERR;
}
if (chp->ch_status & WDCS_ERR) {
ata_bio->error = ERROR;
ata_bio->r_error = chp->ch_error;
if (ata_bio->r_error & (WDCE_BBK | WDCE_UNC | WDCE_IDNF |
WDCE_ABRT | WDCE_TK0NF | WDCE_AMNF))
return WDC_ATA_ERR;
return WDC_ATA_NOERR;
}
if (chp->ch_status & WDCS_CORR)
ata_bio->flags |= ATA_CORR;
return WDC_ATA_NOERR;
}

139
sys/dev/ata/atareg.h Normal file
View File

@ -0,0 +1,139 @@
/* $NetBSD: atareg.h,v 1.2 1998/10/12 16:09:15 bouyer Exp $ */
#ifdef _KERNEL
/*
* Drive parameter structure for ATA/ATAPI.
* Bit fields: WDC_* : common to ATA/ATAPI
* ATA_* : ATA only
* ATAPI_* : ATAPI only.
*/
struct ataparams {
/* drive info */
u_int16_t atap_config; /* 0: general configuration */
#define WDC_CFG_ATAPI_MASK 0xc000
#define WDC_CFG_ATAPI 0x8000
#define ATA_CFG_REMOVABLE 0x0080
#define ATA_CFG_FIXED 0x0040
#define ATAPI_CFG_TYPE_MASK 0x1f00
#define ATAPI_CFG_TYPE(x) (((x) & ATAPI_CFG_TYPE_MASK) >> 8)
#define ATAPI_CFG_REMOV 0x0080
#define ATAPI_CFG_DRQ_MASK 0x0060
#define ATAPI_CFG_STD_DRQ 0x0000
#define ATAPI_CFG_IRQ_DRQ 0x0020
#define ATAPI_CFG_ACCEL_DRQ 0x0040
#define ATAPI_CFG_CMD_MASK 0x0003
#define ATAPI_CFG_CMD_12 0x0000
#define ATAPI_CFG_CMD_16 0x0001
/* words 1-9 are ATA only */
u_int16_t atap_cylinders; /* 1: # of non-removable cylinders */
u_int16_t __reserved1;
u_int16_t atap_heads; /* 3: # of heads */
u_int16_t __retired1[2]; /* 4-5: # of unform. bytes/track */
u_int16_t atap_sectors; /* 6: # of sectors */
u_int16_t __retired2[3];
u_int8_t atap_serial[20]; /* 10-19: serial number */
u_int16_t __retired3[2];
u_int16_t __obsolete1;
u_int8_t atap_revision[8]; /* 23-26: firmware revision */
u_int8_t atap_model[40]; /* 27-46: model number */
u_int16_t atap_multi; /* 47: maximum sectors per irq (ATA) */
u_int16_t __reserved2;
u_int16_t atap_capabilities1; /* 49: capability flags */
#define WDC_CAP_IORDY 0x0800
#define WDC_CAP_IORDY_DSBL 0x0400
#define WDC_CAP_LBA 0x0200
#define WDC_CAP_DMA 0x0100
#define ATA_CAP_STBY 0x2000
#define ATAPI_CAP_INTERL_DMA 0x8000
#define ATAPI_CAP_CMD_QUEUE 0x4000
#define ATAPI_CAP_OVERLP 0X2000
#define ATAPI_CAP_ATA_RST 0x1000
u_int16_t atap_capabilities2; /* 50: capability flags (ATA) */
u_int8_t __junk2;
u_int8_t atap_oldpiotiming; /* 51: old PIO timing mode */
u_int8_t __junk3;
u_int8_t atap_olddmatiming; /* 52: old DMA timing mode (ATA) */
u_int16_t atap_extensions; /* 53: extentions supported */
#define WDC_EXT_UDMA_MODES 0x0004
#define WDC_EXT_MODES 0x0002
#define WDC_EXT_GEOM 0x0001
/* words 54-62 are ATA only */
u_int16_t atap_curcylinders; /* 54: current logical cyliners */
u_int16_t atap_curheads; /* 55: current logical heads */
u_int16_t atap_cursectors; /* 56: current logical sectors/tracks */
u_int16_t atap_curcapacity[2]; /* 57-58: current capacity */
u_int16_t atap_curmulti; /* 59: current multi-sector setting */
#define WDC_MULTI_VALID 0x0100
#define WDC_MULTI_MASK 0x00ff
u_int16_t atap_capacity[2]; /* 60-61: total capacity (LBA only) */
u_int16_t __retired4;
u_int8_t atap_dmamode_supp; /* 63: multiword DMA mode supported */
u_int8_t atap_dmamode_act; /* multiword DMA mode active */
u_int8_t atap_piomode_supp; /* 64: PIO mode supported */
u_int8_t __junk4;
u_int16_t atap_dmatiming_mimi; /* 65: minimum DMA cycle time */
u_int16_t atap_dmatiming_recom; /* 66: recomended DMA cycle time */
u_int16_t atap_piotiming; /* 67: mini PIO cycle time without FC */
u_int16_t atap_piotiming_iordy; /* 68: mini PIO cycle time with IORDY FC */
u_int16_t __reserved3[2];
/* words 71-72 are ATAPI only */
u_int16_t atap_pkt_br; /* 71: time (ns) to bus release */
u_int16_t atap_pkt_bsyclr; /* 72: tme to clear BSY after service */
u_int16_t __reserved4[2];
u_int16_t atap_queuedepth; /* 75: */
#define WDC_QUEUE_DEPTH_MASK 0x0F
u_int16_t __reserved5[4];
u_int16_t atap_ata_major; /* 80: Major version number */
#define WDC_VER_ATA1 0x0002
#define WDC_VER_ATA2 0x0004
#define WDC_VER_ATA3 0x0008
#define WDC_VER_ATA4 0x0010
u_int16_t atap_ata_minor; /* 81: Minor version number */
u_int16_t atap_cmd_set1; /* 82: command set suported */
#define WDC_CMD1_NOP 0x4000
#define WDC_CMD1_RB 0x2000
#define WDC_CMD1_WB 0x1000
#define WDC_CMD1_HPA 0x0400
#define WDC_CMD1_DVRST 0x0200
#define WDC_CMD1_SRV 0x0100
#define WDC_CMD1_RLSE 0x0080
#define WDC_CMD1_AHEAD 0x0040
#define WDC_CMD1_CACHE 0x0020
#define WDC_CMD1_PKT 0x0010
#define WDC_CMD1_PM 0x0008
#define WDC_CMD1_REMOV 0x0004
#define WDC_CMD1_SEC 0x0002
#define WDC_CMD1_SMART 0x0001
u_int16_t atap_cmd_set2; /* 83: command set suported */
#define WDC_CMD2_RMSN 0x0010
#define WDC_CMD2_DM 0x0001
#define ATA_CMD2_APM 0x0008
#define ATA_CMD2_CFA 0x0004
#define ATA_CMD2_RWQ 0x0002
u_int16_t atap_cmd_ext; /* 84: command/features supp. ext. */
u_int16_t atap_cmd1_en; /* 85: cmd/features enabled */
/* bits are the same as atap_cmd_set1 */
u_int16_t atap_cmd2_en; /* 86: cmd/features enabled */
/* bits are the same as atap_cmd_set2 */
u_int16_t atap_cmd_def; /* 87: cmd/features default */
u_int8_t atap_udmamode_supp; /* 88: Ultra-DMA mode supported */
u_int8_t atap_udmamode_act; /* Ultra-DMA mode active */
/* 89-92 are ATA-only */
u_int16_t atap_seu_time; /* 89: Sec. Erase Unit compl. time */
u_int16_t atap_eseu_time; /* 90: Enhanced SEU compl. time */
u_int16_t atap_apm_val; /* 91: current APM value */
u_int16_t __reserved6[35]; /* 92-126: reserved */
u_int16_t atap_rmsn_supp; /* 127: remov. media status notif. */
#define WDC_RMSN_SUPP_MASK 0x0003
#define WDC_RMSN_SUPP 0x0001
u_int16_t atap_sec_st; /* 128: security status */
#define WDC_SEC_LEV_MAX 0x0100
#define WDC_SEC_ESE_SUPP 0x0020
#define WDC_SEC_EXP 0x0010
#define WDC_SEC_FROZEN 0x0008
#define WDC_SEC_LOCKED 0x0004
#define WDC_SEC_EN 0x0002
#define WDC_SEC_SUPP 0x0001
};
#endif /* _KERNEL */

135
sys/dev/ata/atavar.h Normal file
View File

@ -0,0 +1,135 @@
/* $NetBSD: atavar.h,v 1.2 1998/10/12 16:09:15 bouyer Exp $ */
/*
* Copyright (c) 1998 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
*/
/* Hight-level functions and structures used by both ATA and ATAPI devices */
/* Datas common to drives and controller drivers */
struct ata_drive_datas {
u_int8_t drive; /* drive number */
u_int8_t drive_flags; /* bitmask for drives present/absent and cap */
#define DRIVE_ATA 0x01
#define DRIVE_ATAPI 0x02
#define DRIVE (DRIVE_ATA|DRIVE_ATAPI)
#define DRIVE_CAP32 0x04
#define DRIVE_DMA 0x08
#define DRIVE_UDMA 0x10
/*
* Current setting of drive's PIO, DMA and UDMA modes.
* Is initialised by the disks drivers at attach time, and may be
* changed later by the controller's code if needed
*/
u_int8_t PIO_mode; /* Current setting of drive's PIO mode */
u_int8_t DMA_mode; /* Current setting of drive's DMA mode */
u_int8_t UDMA_mode; /* Current setting of drive's UDMA mode */
/*
* Drive state. This is drive-type (ATA or ATAPI) dependant
* This is reset to 0 after a channel reset.
*/
u_int8_t state;
struct device *drv_softc; /* ATA drives softc, if any */
void* chnl_softc; /* channel softc */
};
/* ATA/ATAPI common attachement datas */
struct ata_atapi_attach {
u_int8_t aa_type; /* Type of device */
#define T_ATA 0
#define T_ATAPI 1
u_int8_t aa_channel; /* controller's channel */
u_int8_t aa_openings; /* Number of simultaneous commands possible */
struct ata_drive_datas *aa_drv_data;
void *aa_bus_private; /* infos specifics to this bus */
};
/*
* ATA/ATAPI commands description
*
* This structure defines the interface between the ATA/ATAPI device driver
* and the controller for short commands. It contains the command's parameter,
* the len of data's to read/write (if any), and a function to call upon
* completion.
* If no sleep is allowed, the driver can poll for command completion.
* Once the command completed, if the error registed is valid, the flag
* AT_ERROR is set and the error register value is copied to r_error .
* A separate interface is needed for read/write or ATAPI packet commands
* (which need multiple interrupts per commands).
*/
struct wdc_command {
u_int8_t r_command; /* Parameters to upload to registers */
u_int8_t r_head;
u_int16_t r_cyl;
u_int8_t r_sector;
u_int8_t r_count;
u_int8_t r_precomp;
u_int8_t r_st_bmask; /* status register mask to wait for before command */
u_int8_t r_st_pmask; /* status register mask to wait for after command */
u_int8_t r_error; /* error register after command done */
volatile u_int16_t flags;
#define AT_READ 0x0001 /* There is data to read */
#define AT_WRITE 0x0002 /* There is data to write (excl. with AT_READ) */
#define AT_WAIT 0x0008 /* wait in controller code for command completion */
#define AT_POLL 0x0010 /* poll for command completion (no interrupts) */
#define AT_DONE 0x0020 /* command is done */
#define AT_ERROR 0x0040 /* command is done with error */
#define AT_TIMEOU 0x0040 /* command timed out */
#define AT_DF 0x0080 /* Drive fault */
int timeout; /* timeout (in ms) */
void *data; /* Data buffer address */
int bcount; /* number of bytes to transfer */
void (*callback) __P((void*)); /* command to call once command completed */
void *callback_arg; /* argument passed to *callback() */
};
int wdc_exec_command __P((struct ata_drive_datas *, struct wdc_command*));
#define WDC_COMPLETE 0x01
#define WDC_QUEUED 0x02
#define WDC_TRY_AGAIN 0x03
void wdc_probe_caps __P((struct ata_drive_datas*));
void wdc_reset_channel __P((struct ata_drive_datas *));
struct ataparams;
int ata_get_params __P((struct ata_drive_datas*, u_int8_t,
struct ataparams *));
int ata_set_mode __P((struct ata_drive_datas*, u_int8_t, u_int8_t));
/* return code for these cmds */
#define CMD_OK 0
#define CMD_ERR 1
#define CMD_AGAIN 2

View File

@ -1,4 +1,4 @@
# $NetBSD: files.ata,v 1.2 1998/02/16 22:12:50 thorpej Exp $
# $NetBSD: files.ata,v 1.3 1998/10/12 16:09:16 bouyer Exp $
#
# Config file and device description for machine-independent devices
# which attach to ATA busses. Included by ports that need it. Ports
@ -9,3 +9,6 @@
device wd: disk
attach wd at ata
file dev/ata/wd.c wd needs-flag
file dev/ata/ata_wdc.c wd & wdc_base
file dev/ata/ata.c ata | atapi

File diff suppressed because it is too large Load Diff

View File

@ -1,134 +0,0 @@
/* $NetBSD: wdlink.h,v 1.8 1998/08/15 10:10:48 mycroft Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Charles M. Hannum and by Onno van der Linden.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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.
*/
/*
* XXX THIS FILE NEEDS TO BE GUTTED, AND TURNED INTO A REAL 'ATA'/'ATAPI'
* XXX INTERFACE FILE.
*/
#undef WDDEBUG
/* #undef DIAGNOSTIC */
struct wd_link {
u_int8_t type;
#define ATA 0
#define ATAPI 1
u_int8_t channel;
u_int8_t drive;
caddr_t wdc_softc;
caddr_t wd_softc;
struct wdparams sc_params;
/* Long-term state: */
u_int8_t openings;
int sc_state; /* control state */
#define RECAL 0 /* recalibrate */
#define RECAL_WAIT 1 /* done recalibrating */
#define GEOMETRY 2 /* upload geometry */
#define GEOMETRY_WAIT 3 /* done uploading geometry */
#define MULTIMODE 4 /* set multiple mode */
#define MULTIMODE_WAIT 5 /* done setting multiple mode */
#define READY 6 /* done with open */
int sc_mode; /* transfer mode */
#define WDM_PIOSINGLE 0 /* single-sector PIO */
#define WDM_PIOMULTI 1 /* multi-sector PIO */
#define WDM_DMA 2 /* DMA */
int sc_multiple; /* multiple for WDM_PIOMULTI */
int sc_flags; /* drive characteistics found */
#define WDF_LOCKED 0x01
#define WDF_WANTED 0x02
#define WDF_WLABEL 0x04 /* label is writable */
#define WDF_LABELLING 0x08 /* writing label */
/*
* XXX Nothing resets this yet, but disk change sensing will when ATA-4 is
* more fully implemented.
*/
#define WDF_LOADED 0x10 /* parameters loaded */
#define WDF_WAIT 0x20 /* waiting for resources */
#define WDF_LBA 0x40 /* using LBA mode */
int sc_capacity;
daddr_t sc_badsect[127]; /* 126 plus trailing -1 marker */
struct disklabel *sc_lp; /* label info for this disk */
};
struct wdc_xfer {
struct wd_link *d_link; /* drive/bus structure info */
volatile long c_flags; /* handle: scsi flags (0x0000ffff)
b_read/b_write (0x00f00000)
controllers flags (0x000f0000) */
#define C_INUSE 0x010000
#define C_ATAPI 0x020000
#define C_ERROR 0x040000
#define C_NEEDDONE 0x080000
/* Information about the current transfer */
struct buf *c_bp;
void *atapi_cmd;
void *databuf;
daddr_t c_blkno; /* starting block number */
int c_bcount; /* byte count left */
int c_skip; /* bytes already transferred */
int c_nblks; /* number of blocks currently transferring */
int c_nbytes; /* number of bytes currently transferring */
TAILQ_ENTRY(wdc_xfer) c_xferchain;
LIST_ENTRY(wdc_xfer) free_list;
};
void wdc_exec_xfer __P((struct wdc_softc *, struct wd_link *,
struct wdc_xfer *));
struct wdc_xfer *wdc_get_xfer __P((int));
int wdc_get_parms __P((struct wdc_softc *, struct wd_link *));
void wdstart __P((void*));
void wderror __P((struct wd_link* , struct buf *, char *));
void wddone __P((struct wd_link*, struct buf*));
int wdccommand __P((struct wdc_softc *, struct wd_link *, int, int,
int, int, int, int));
int wdccommandshort __P((struct wdc_softc *, int, int));
int wdcwait __P((struct wdc_softc *, int));
/*
* ST506 spec says that if READY or SEEKCMPLT go off, then the read or write
* command is aborted.
*/
#define wait_for_drq(d) wdcwait(d, WDCS_DRDY | WDCS_DSC | WDCS_DRQ)
#define wait_for_unbusy(d) wdcwait(d, 0)
#define wait_for_ready(d) wdcwait(d, WDCS_DRDY | WDCS_DSC)
#define atapi_ready(d) wdcwait(d, WDCS_DRQ)
#define IDE_NOSLEEP 0x01

79
sys/dev/ata/wdvar.h Normal file
View File

@ -0,0 +1,79 @@
/* $NetBSD: wdvar.h,v 1.2 1998/10/12 16:09:17 bouyer Exp $ */
/*
* Copyright (c) 1998 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
*/
/* Params needed by the controller to perform an ATA bio */
struct ata_bio {
volatile u_int16_t flags; /* cmd flags */
#define ATA_NOSLEEP 0x0001 /* Can't sleep */
#define ATA_POLL 0x0002 /* poll for completion */
#define ATA_ITSDONE 0x0004 /* the transfer is as done as it gets */
#define ATA_SINGLE 0x0008 /* transfer has to be done in single-sector mode */
#define ATA_LBA 0x0010 /* tranfert uses LBA adressing */
#define ATA_READ 0x0020 /* tranfert is a read (otherwise a write) */
#define ATA_CORR 0x0040 /* transfert had a corrected error */
int multi; /* number of blocks to transfert in multi-mode */
struct disklabel *lp; /* pointer to drive's label info */
daddr_t blkno; /* block addr */
daddr_t blkdone; /* number of blks transfered */
daddr_t nblks; /* number of block currently transfering */
int nbytes; /* number of bytes currently transfering */
long bcount; /* total number of bytes */
char* databuf; /* data buffer adress */
volatile int error;
#define NOERROR 0 /* There was no error (r_error invalid) */
#define ERROR 1 /* check r_error */
#define ERR_DF 2 /* Drive fault */
#define ERR_DMA 3 /* DMA error */
#define TIMEOUT 4 /* device timed out */
u_int8_t r_error; /* copy of error register */
daddr_t badsect[127]; /* 126 plus trailing -1 marker */
};
/* drive states stored in ata_drive_datas */
#define RECAL 0
#define RECAL_WAIT 1
#define PIOMODE 2
#define PIOMODE_WAIT 3
#define DMAMODE 4
#define DMAMODE_WAIT 5
#define GEOMETRY 6
#define GEOMETRY_WAIT 7
#define MULTIMODE 8
#define MULTIMODE_WAIT 9
#define READY 10
int wdc_ata_bio __P((struct ata_drive_datas*, struct ata_bio*));
void wddone __P((void *));

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdcreg.h,v 1.17 1998/04/26 05:28:24 mycroft Exp $ */
/* $NetBSD: wdcreg.h,v 1.18 1998/10/12 16:09:18 bouyer Exp $ */
/*-
* Copyright (c) 1991 The Regents of the University of California.
@ -46,7 +46,7 @@
#define wd_data 0 /* data register (R/W - 16 bits) */
#define wd_error 1 /* error register (R) */
#define wd_precomp 1 /* write precompensation (W) */
#define wd_features 1 /* features (W) */
#define wd_features 1 /* features (W), same as wd_precomp */
#define wd_seccnt 2 /* sector count (R/W) */
#define wd_ireason 2 /* interrupt reason (R/W) (for atapi) */
#define wd_sector 3 /* first sector number (R/W) */
@ -95,6 +95,7 @@
/*
* Commands for Disk Controller.
*/
#define WDCC_NOP 0x00 /* NOP - Always fail with "aborted command" */
#define WDCC_RECAL 0x10 /* disk restore code -- resets cntlr */
#define WDCC_READ 0x20 /* disk read code */
@ -118,23 +119,45 @@
#define WDCC_UNLOCK 0xdf /* unlock drawer */
#define WDCC_IDENTIFY 0xec /* read parameters from controller */
#define WDCC_CACHEC 0xef /* cache control */
#define SET_FEATURES 0xef /* set features */
/* Subcommands for SET_FEATURES (features register ) */
#define WDSF_EN_WR_CACHE 0x02
#define WDSF_SET_MODE 0x03
#define WDSF_REASSIGN_EN 0x04
#define WDSF_RETRY_DS 0x33
#define WDSF_SET_CACHE_SGMT 0x54
#define WDSF_READAHEAD_DS 0x55
#define WDSF_POD_DS 0x66
#define WDSF_ECC_DS 0x77
#define WDSF_WRITE_CACHE_DS 0x82
#define WDSF_REASSIGN_DS 0x84
#define WDSF_ECC_EN 0x88
#define WDSF_RETRY_EN 0x99
#define WDSF_SET_CURRENT 0x9A
#define WDSF_READAHEAD_EN 0xAA
#define WDSF_PREFETCH_SET 0xAB
#define WDSF_POD_EN 0xCC
/* parameters uploaded to device/heads register */
#define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */
#define WDSD_CHS 0x00 /* cylinder/head/sector addressing */
#define WDSD_LBA 0x40 /* logical block addressing */
/* Commands for ATAPI devices */
#define ATAPI_CHECK_POWER_MODE 0xe5
#define ATAPI_EXEC_DRIVE_DIAGS 0x90
#define ATAPI_IDLE_IMMEDIATE 0xe1
#define ATAPI_NOP 0x00
#define ATAPI_PACKET_COMMAND 0xa0
#define ATAPI_IDENTIFY_DEVICE 0xa1
#define ATAPI_SOFT_RESET 0x08
#define ATAPI_SET_FEATURES 0xef
#define ATAPI_SLEEP 0xe6
#define ATAPI_STANDBY_IMMEDIATE 0xe0
#define ATAPI_CHECK_POWER_MODE 0xe5
#define ATAPI_EXEC_DRIVE_DIAGS 0x90
#define ATAPI_IDLE_IMMEDIATE 0xe1
#define ATAPI_NOP 0x00
#define ATAPI_PKT_CMD 0xa0
#define ATAPI_IDENTIFY_DEVICE 0xa1
#define ATAPI_SOFT_RESET 0x08
#define ATAPI_SLEEP 0xe6
#define ATAPI_STANDBY_IMMEDIATE 0xe0
/* Bytes used by ATAPI_PACKET_COMMAND ( feature register) */
#define ATAPI_PKT_CMD_FTRE_DMA 0x01
#define ATAPI_PKT_CMD_FTRE_OVL 0x02
/* ireason */
#define WDCI_CMD 0x01 /* command(1) or data(0) */
@ -147,56 +170,3 @@
#define PHASE_COMPLETED (WDCI_IN | WDCI_CMD)
#define PHASE_ABORTED 0
#ifdef _KERNEL
/*
* read parameters command returns this:
*/
struct wdparams {
/* drive info */
u_short wdp_config; /* general configuration */
#define WD_CFG_REMOVABLE 0x0080
#define WD_CFG_FIXED 0x0040
u_short wdp_cylinders; /* number of non-removable cylinders */
u_short __reserved1;
u_short wdp_heads; /* number of heads */
u_short __retired1[2]; /* number of unformatted bytes/track */
u_short wdp_sectors; /* number of sectors */
u_short __retired2[3];
char wdp_serial[20]; /* serial number */
u_short __retired3[2];
u_short __obsolete1;
char wdp_revision[8]; /* firmware revision */
char wdp_model[40]; /* model name */
u_short wdp_multi; /* maximum sectors per interrupt */
u_short __reserved2;
u_short wdp_capabilities1; /* capability flags */
#define WD_CAP_LBA 0x0200
#define WD_CAP_DMA 0x0100
u_short wdp_capabilities2;
char __junk2;
char wdp_oldpiotiming; /* PIO timing mode */
char __junk3;
char wdp_olddmatiming; /* DMA timing mode */
u_short wdp_extensions;
u_short wdp_curcylinders;
u_short wdp_curheads;
u_short wdp_cursectors;
u_short wdp_curcapacity[2];
u_short wdp_curmulti;
u_short wdp_capacity[2];
u_short __retired4;
u_short wdp_dmamode;
u_short wdp_piomode;
u_short wdp_dmatiming[2];
u_short wdp_piotiming[2];
u_short __reserved3[6];
u_short wdp_queuedepth;
u_short __reserved4[4];
u_short wdp_ataversion;
#define WD_VER_ATA1 0x0002
#define WD_VER_ATA2 0x0004
#define WD_VER_ATA3 0x0008
#define WD_VER_ATA4 0x0010
};
#endif /* _KERNEL */

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdcvar.h,v 1.5 1998/09/22 00:21:16 mark Exp $ */
/* $NetBSD: wdcvar.h,v 1.6 1998/10/12 16:09:18 bouyer Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -11,10 +11,10 @@
* 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.
* 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.
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
@ -36,74 +36,141 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
struct wdc_attachment_data {
/* manadatory fields */
int cap;
int flags;
bus_space_tag_t iot;
bus_space_handle_t ioh;
bus_space_tag_t auxiot;
bus_space_handle_t auxioh;
#define WAITTIME (10 * hz) /* time to wait for a completion */
/* this is a lot for hard drives, but not for cdroms */
struct channel_queue { /* per channel queue (may be shared) */
TAILQ_HEAD(xferhead, wdc_xfer) sc_xfer;
};
struct channel_softc { /* Per channel data */
/* Our location */
int channel;
/* Our controller's softc */
struct wdc_softc *wdc;
/* Our registers */
bus_space_tag_t cmd_iot;
bus_space_handle_t cmd_ioh;
bus_space_tag_t ctl_iot;
bus_space_handle_t ctl_ioh;
/* data32{iot,ioh} are only used for 32 bit xfers */
bus_space_tag_t data32iot;
bus_space_handle_t data32ioh;
bus_space_tag_t data32iot;
bus_space_handle_t data32ioh;
/* Our state */
int ch_flags;
#define WDCF_ACTIVE 0x01 /* channel is active */
#define WDCF_IRQ_WAIT 0x10 /* controller is waiting for irq */
u_int8_t ch_status; /* copy of status register */
u_int8_t ch_error; /* copy of error register */
/* per-drive infos */
struct ata_drive_datas ch_drive[2];
/*
* channel queues. May be the same for all channels, if hw channels
* are not independants
*/
struct channel_queue *ch_queue;
};
struct wdc_softc { /* Per controller state */
struct device sc_dev;
/* mandatory fields */
int cap;
/* Capabilities supported by the controller */
#define WDC_CAPABILITY_DATA16 0x0001 /* can do 16-bit data access */
#define WDC_CAPABILITY_DATA32 0x0002 /* can do 32-bit data access */
#define WDC_CAPABILITY_MODE 0x0004 /* controller knows its PIO/DMA modes */
#define WDC_CAPABILITY_DMA 0x0008 /* DMA */
#define WDC_CAPABILITY_UDMA 0x0010 /* Ultra-DMA/33 */
#define WDC_CAPABILITY_HWLOCK 0x0020 /* Needs to lock HW */
#define WDC_CAPABILITY_ATA_NOSTREAM 0x0040 /* Don't use stream funcs on ATA */
#define WDC_CAPABILITY_ATAPI_NOSTREAM 0x0080 /* Don't use stream f on ATAPI */
#define WDC_CAPABILITY_NO_EXTRA_RESETS 0x0100 /* only reset once */
u_int8_t pio_mode; /* highest PIO mode supported */
u_int8_t dma_mode; /* highest DMA mode supported */
int nchannels; /* Number of channels on this controller */
struct channel_softc *channels; /* channels-specific datas (array) */
/* if WDC_CAPABILITY_DMA set in 'cap' */
void *dma_arg;
void (*dma_setup) __P((void *));
void (*dma_start) __P((void *, void *, size_t,
int));
void (*dma_finish) __P((void *));
void *dma_arg;
int (*dma_init) __P((void *, int, int, void *, size_t,
int));
void (*dma_start) __P((void *, int, int, int));
int (*dma_finish) __P((void *, int, int, int));
/* flags passed to DMA functions */
#define WDC_DMA_READ 0x01
#define WDC_DMA_POLL 0x02
/* if WDC_CAPABILITY_HWLOCK set in 'cap' */
int (*claim_hw) __P((void *, int));
void (*free_hw) __P((void *));
int (*claim_hw) __P((void *, int));
void (*free_hw) __P((void *));
};
/* Capabilities supported by the controller */
#define WDC_CAPABILITY_DATA32 0x01 /* 32-bit data access */
#define WDC_CAPABILITY_DMA 0x02 /* DMA */
#define WDC_CAPABILITY_HWLOCK 0x04 /* Needs to lock HW */
/*
* Description of a command to be handled by a controller.
* These commands are queued in a list.
*/
struct wdc_xfer {
volatile u_int c_flags;
#define C_INUSE 0x0001 /* xfer struct is in use */
#define C_ATAPI 0x0002 /* xfer is ATAPI request */
#define C_TIMEOU 0x0004 /* xfer processing timed out */
#define C_NEEDDONE 0x0010 /* need to call upper-level done */
#define C_POLL 0x0020 /* cmd is polled */
#define C_DMA 0x0040 /* cmd uses DMA */
/* Flags passed from the attach routine to the wdc driver */
#define WDC_NO_EXTRA_RESETS 0x01 /* Only reset once at attach */
/* Information about our location */
u_int8_t drive;
u_int8_t channel;
struct wdc_softc {
struct device sc_dev;
const struct wdc_attachment_data *sc_adp;
struct wd_link *d_link[2];
struct scsipi_link *ab_link;
TAILQ_HEAD(xferhead, wdc_xfer) sc_xfer;
int sc_flags;
#define WDCF_ACTIVE 0x01 /* controller is active */
#define WDCF_SINGLE 0x02 /* sector at a time mode */
#define WDCF_ERROR 0x04 /* processing a disk error */
#define WDCF_WANTED 0x08 /* XXX locking for wd_get_parms() */
#define WDCF_IRQ_WAIT 0x10 /* controller is waiting for irq */
#define WDCF_ONESLAVE 0x20 /* ctrl. has one ATAPI slave attached */
int sc_errors; /* errors during current transfer */
u_char sc_status; /* copy of status register */
u_char sc_error; /* copy of error register */
u_char sc_drives_mask; /* bitmask for drives present/absent */
/* Information about the current transfer */
void *cmd; /* wdc, ata or scsipi command structure */
void *databuf;
int c_bcount; /* byte count left */
int c_skip; /* bytes already transferred */
TAILQ_ENTRY(wdc_xfer) c_xferchain;
LIST_ENTRY(wdc_xfer) free_list;
void (*c_start) __P((struct channel_softc *, struct wdc_xfer *));
int (*c_intr) __P((struct channel_softc *, struct wdc_xfer *));
};
#define sc_cap sc_adp->cap
#define sc_iot sc_adp->iot
#define sc_ioh sc_adp->ioh
#define sc_auxiot sc_adp->auxiot
#define sc_auxioh sc_adp->auxioh
#define sc_data32iot sc_adp->data32iot
#define sc_data32ioh sc_adp->data32ioh
#define sc_dma_arg sc_adp->dma_arg
#define sc_dma_setup sc_adp->dma_setup
#define sc_dma_start sc_adp->dma_start
#define sc_dma_finish sc_adp->dma_finish
#define sc_claim_hw sc_adp->claim_hw
#define sc_free_hw sc_adp->free_hw
/*
* Public functions which can be called by ATA or ATAPI specific parts,
* or bus-specific backends.
*/
void wdcattach(struct wdc_softc *, const struct wdc_attachment_data *);
int wdcintr(void *);
int wdcprobe(const struct wdc_attachment_data *);
int wdcprobe __P((struct channel_softc *));
void wdcattach __P((struct channel_softc *));
int wdcintr __P((void *));
void wdc_exec_xfer __P((struct channel_softc *, struct wdc_xfer *));
struct wdc_xfer *wdc_get_xfer __P((int)); /* int = WDC_NOSLEEP/CANSLEEP */
#define WDC_CANSLEEP 0x00
#define WDC_NOSLEEP 0x01
void wdc_free_xfer __P((struct channel_softc *, struct wdc_xfer *));
void wdcstart __P((struct wdc_softc *, int));
void wdcrestart __P((void*));
int wdcreset __P((struct channel_softc *, int));
#define VERBOSE 1
#define SILENT 0 /* wdcreset will not print errors */
int wdcwait __P((struct channel_softc *, int, int, int));
void wdcbit_bucket __P(( struct channel_softc *, int));
void wdccommand __P((struct channel_softc *, u_int8_t, u_int8_t, u_int16_t,
u_int8_t, u_int8_t, u_int8_t, u_int8_t));
void wdccommandshort __P((struct channel_softc *, int, int));
void wdctimeout __P((void *arg));
/*
* ST506 spec says that if READY or SEEKCMPLT go off, then the read or write
* command is aborted.
*/
#define wait_for_drq(chp, timeout) wdcwait((chp), \
WDCS_DRDY | WDCS_DSC | WDCS_DRQ, \
WDCS_DRDY | WDCS_DSC | WDCS_DRQ, (timeout))
#define wait_for_unbusy(chp, timeout) wdcwait((chp), 0, 0, (timeout))
#define wait_for_ready(chp, timeout) wdcwait((chp), WDCS_DRDY | WDCS_DSC, \
WDCS_DRDY | WDCS_DSC, (timeout))
/* ATA/ATAPI specs says a device can take 31s to reset */
#define WDC_RESET_WAIT 31000
void wdc_atapibus_attach __P((struct channel_softc *));
int atapi_print __P((void *, const char *));

View File

@ -1,4 +1,4 @@
# $NetBSD: files.isa,v 1.76 1998/08/26 13:33:59 augustss Exp $
# $NetBSD: files.isa,v 1.77 1998/10/12 16:09:19 bouyer Exp $
#
# Config file and device description for machine-independent ISA code.
# Included by ports that need it. Requires that the SCSI files be
@ -121,9 +121,7 @@ file dev/isa/scd.c scd needs-flag
# XXX BECAUSE NOT ALL PORTS USE THE MI DRIVER YET.
# ESDI/IDE/etc. controllers
device wdc: ata, atapi
file dev/ic/wdc.c
wdc & (wd | !wd) needs-flag # XXX
device wdc: ata, atapi, wdc_base
attach wdc at isa with wdc_isa: isadma
file dev/isa/wdc_isa.c wdc_isa

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdc_isa.c,v 1.9 1998/08/15 10:10:52 mycroft Exp $ */
/* $NetBSD: wdc_isa.c,v 1.10 1998/10/12 16:09:19 bouyer Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -40,6 +40,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/bus.h>
#include <machine/intr.h>
@ -47,6 +48,7 @@
#include <dev/isa/isavar.h>
#include <dev/isa/isadmavar.h>
#include <dev/ata/atavar.h>
#include <dev/ic/wdcvar.h>
#define WDC_ISA_REG_NPORTS 8
@ -58,8 +60,8 @@
*/
struct wdc_isa_softc {
struct wdc_softc sc_wdcdev;
struct wdc_attachment_data sc_ad;
struct wdc_softc sc_wdcdev;
struct channel_softc wdc_channel;
isa_chipset_tag_t sc_ic;
void *sc_ih;
int sc_drq;
@ -72,9 +74,10 @@ struct cfattach wdc_isa_ca = {
sizeof(struct wdc_isa_softc), wdc_isa_probe, wdc_isa_attach
};
static void wdc_isa_dma_setup __P((void *));
static void wdc_isa_dma_start __P((void *, void *, size_t, int));
static void wdc_isa_dma_finish __P((void *));
static void wdc_isa_dma_setup __P((struct wdc_isa_softc *));
static int wdc_isa_dma_init __P((void*, int, int, void *, size_t, int));
static void wdc_isa_dma_start __P((void*, int, int, int));
static int wdc_isa_dma_finish __P((void*, int, int, int));
int
wdc_isa_probe(parent, match, aux)
@ -82,37 +85,29 @@ wdc_isa_probe(parent, match, aux)
struct cfdata *match;
void *aux;
{
#if 0 /* XXX memset */
struct wdc_attachment_data ad = { 0 };
#else /* XXX memset */
struct wdc_attachment_data ad;
#endif /* XXX memset */
struct channel_softc ch = { 0 };
struct isa_attach_args *ia = aux;
int result = 0;
#if 0 /* XXX memset */
#else /* XXX memset */
bzero(&ad, sizeof ad);
#endif /* XXX memset */
ad.iot = ia->ia_iot;
if (bus_space_map(ad.iot, ia->ia_iobase, WDC_ISA_REG_NPORTS, 0,
&ad.ioh))
ch.cmd_iot = ia->ia_iot;
if (bus_space_map(ch.cmd_iot, ia->ia_iobase, WDC_ISA_REG_NPORTS, 0,
&ch.cmd_ioh))
goto out;
ad.auxiot = ia->ia_iot;
if (bus_space_map(ad.auxiot, ia->ia_iobase + WDC_ISA_AUXREG_OFFSET,
WDC_ISA_AUXREG_NPORTS, 0, &ad.auxioh))
ch.ctl_iot = ia->ia_iot;
if (bus_space_map(ch.ctl_iot, ia->ia_iobase + WDC_ISA_AUXREG_OFFSET,
WDC_ISA_AUXREG_NPORTS, 0, &ch.ctl_ioh))
goto outunmap;
result = wdcprobe(&ad);
result = wdcprobe(&ch);
if (result) {
ia->ia_iosize = WDC_ISA_REG_NPORTS;
ia->ia_msize = 0;
}
bus_space_unmap(ad.auxiot, ad.auxioh, WDC_ISA_AUXREG_NPORTS);
bus_space_unmap(ch.ctl_iot, ch.ctl_ioh, WDC_ISA_AUXREG_NPORTS);
outunmap:
bus_space_unmap(ad.iot, ad.ioh, WDC_ISA_REG_NPORTS);
bus_space_unmap(ch.cmd_iot, ch.cmd_ioh, WDC_ISA_REG_NPORTS);
out:
return (result);
}
@ -127,66 +122,92 @@ wdc_isa_attach(parent, self, aux)
printf("\n");
sc->sc_ad.iot = ia->ia_iot;
sc->sc_ad.auxiot = ia->ia_iot;
sc->wdc_channel.cmd_iot = ia->ia_iot;
sc->wdc_channel.ctl_iot = ia->ia_iot;
sc->sc_ic = ia->ia_ic;
if (bus_space_map(sc->sc_ad.iot, ia->ia_iobase, WDC_ISA_REG_NPORTS, 0,
&sc->sc_ad.ioh) ||
bus_space_map(sc->sc_ad.auxiot,
if (bus_space_map(sc->wdc_channel.cmd_iot, ia->ia_iobase,
WDC_ISA_REG_NPORTS, 0, &sc->wdc_channel.cmd_ioh) ||
bus_space_map(sc->wdc_channel.ctl_iot,
ia->ia_iobase + WDC_ISA_AUXREG_OFFSET, WDC_ISA_AUXREG_NPORTS,
0, &sc->sc_ad.auxioh)) {
0, &sc->wdc_channel.ctl_ioh)) {
printf("%s: couldn't map registers\n",
sc->sc_wdcdev.sc_dev.dv_xname);
}
sc->wdc_channel.data32iot = sc->wdc_channel.cmd_iot;
sc->wdc_channel.data32ioh = sc->wdc_channel.cmd_ioh;
sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
IPL_BIO, wdcintr, sc);
IPL_BIO, wdcintr, &sc->wdc_channel);
if (ia->ia_drq != DRQUNK) {
sc->sc_drq = ia->ia_drq;
sc->sc_ad.cap |= WDC_CAPABILITY_DMA;
sc->sc_ad.dma_arg = sc;
sc->sc_ad.dma_setup = &wdc_isa_dma_setup;
sc->sc_ad.dma_start = &wdc_isa_dma_start;
sc->sc_ad.dma_finish = &wdc_isa_dma_finish;
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DMA;
sc->sc_wdcdev.dma_arg = sc;
sc->sc_wdcdev.dma_init = wdc_isa_dma_init;
sc->sc_wdcdev.dma_start = wdc_isa_dma_start;
sc->sc_wdcdev.dma_finish = wdc_isa_dma_finish;
wdc_isa_dma_setup(sc);
}
wdcattach(&sc->sc_wdcdev, &sc->sc_ad);
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32;
sc->sc_wdcdev.pio_mode = 0;
sc->sc_wdcdev.channels = &sc->wdc_channel;
sc->sc_wdcdev.nchannels = 1;
sc->wdc_channel.channel = 0;
sc->wdc_channel.wdc = &sc->sc_wdcdev;
sc->wdc_channel.ch_queue = malloc(sizeof(struct channel_queue),
M_DEVBUF, M_NOWAIT);
if (sc->wdc_channel.ch_queue == NULL) {
printf("%s: can't allocate memory for command queue",
sc->sc_wdcdev.sc_dev.dv_xname);
return;
}
wdcattach(&sc->wdc_channel);
}
static void
wdc_isa_dma_setup(scv)
void *scv;
wdc_isa_dma_setup(sc)
struct wdc_isa_softc *sc;
{
struct wdc_isa_softc *sc = scv;
if (isa_dmamap_create(sc->sc_ic, sc->sc_drq,
MAXPHYS, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
printf("%s: can't create map for drq %d\n",
sc->sc_wdcdev.sc_dev.dv_xname, sc->sc_drq);
sc->sc_ad.cap &= ~WDC_CAPABILITY_DMA;
sc->sc_wdcdev.cap &= ~WDC_CAPABILITY_DMA;
}
}
static void
wdc_isa_dma_start(scv, buf, size, read)
void *scv, *buf;
size_t size;
static int
wdc_isa_dma_init(v, channel, drive, databuf, datalen, read)
void *v;
void *databuf;
size_t datalen;
int read;
{
struct wdc_isa_softc *sc = scv;
struct wdc_isa_softc *sc = v;
isa_dmastart(sc->sc_ic, sc->sc_drq, buf,
size, NULL, read ? DMAMODE_READ : DMAMODE_WRITE,
isa_dmastart(sc->sc_ic, sc->sc_drq, databuf,
datalen, NULL, read ? DMAMODE_READ : DMAMODE_WRITE,
BUS_DMA_NOWAIT);
return 0;
}
static void
wdc_isa_dma_finish(scv)
void *scv;
wdc_isa_dma_start(v, channel, drive, read)
void *v;
int channel, drive;
{
struct wdc_isa_softc *sc = scv;
/* nothing to do */
}
static int
wdc_isa_dma_finish(v, channel, drive, read)
void *v;
int channel, drive;
int read;
{
struct wdc_isa_softc *sc = v;
isa_dmadone(sc->sc_ic, sc->sc_drq);
return 0;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdc_isapnp.c,v 1.7 1998/09/12 21:40:22 wrstuden Exp $ */
/* $NetBSD: wdc_isapnp.c,v 1.8 1998/10/12 16:09:19 bouyer Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -40,6 +40,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <machine/bus.h>
#include <machine/intr.h>
@ -51,12 +52,13 @@
#include <dev/isapnp/isapnpvar.h>
#include <dev/isapnp/isapnpdevs.h>
#include <dev/ata/atavar.h>
#include <dev/ic/wdcreg.h>
#include <dev/ic/wdcvar.h>
struct wdc_isapnp_softc {
struct wdc_softc sc_wdcdev;
struct wdc_attachment_data sc_ad;
struct channel_softc wdc_channel;
isa_chipset_tag_t sc_ic;
void *sc_ih;
int sc_drq;
@ -70,7 +72,7 @@ struct cfattach wdc_isapnp_ca = {
};
#ifdef notyet
static void wdc_isapnp_dma_setup __P((void *));
static void wdc_isapnp_dma_setup __P((struct wdc_isapnp_softc *));
static void wdc_isapnp_dma_start __P((void *, void *, size_t, int));
static void wdc_isapnp_dma_finish __P((void *));
#endif
@ -113,51 +115,64 @@ wdc_isapnp_attach(parent, self, aux)
printf("%s: %s %s\n", sc->sc_wdcdev.sc_dev.dv_xname, ipa->ipa_devident,
ipa->ipa_devclass);
sc->sc_ad.iot = ipa->ipa_iot;
sc->sc_ad.auxiot = ipa->ipa_iot;
sc->wdc_channel.cmd_iot = ipa->ipa_iot;
sc->wdc_channel.ctl_iot = ipa->ipa_iot;
/*
* An IDE controller can feed us the regions in any order. Pass
* them along with the 8-byte region in sc_ad.ioh, and the other
* (2 byte) region in auxioh.
*/
if (ipa->ipa_io[0].length == 8) {
sc->sc_ad.ioh = ipa->ipa_io[0].h;
sc->sc_ad.auxioh = ipa->ipa_io[1].h;
sc->wdc_channel.cmd_ioh = ipa->ipa_io[0].h;
sc->wdc_channel.ctl_ioh = ipa->ipa_io[1].h;
} else {
sc->sc_ad.ioh = ipa->ipa_io[1].h;
sc->sc_ad.auxioh = ipa->ipa_io[0].h;
sc->wdc_channel.cmd_ioh = ipa->ipa_io[1].h;
sc->wdc_channel.ctl_ioh = ipa->ipa_io[0].h;
}
sc->sc_ic = ipa->ipa_ic;
sc->wdc_channel.data32iot = sc->wdc_channel.cmd_iot;
sc->wdc_channel.data32ioh = sc->wdc_channel.cmd_ioh;
sc->sc_ic = ipa->ipa_ic;
sc->sc_ih = isa_intr_establish(ipa->ipa_ic, ipa->ipa_irq[0].num,
ipa->ipa_irq[0].type, IPL_BIO, wdcintr, sc);
ipa->ipa_irq[0].type, IPL_BIO, wdcintr, &sc->wdc_channel);
#ifdef notyet
if (ipa->ipa_ndrq > 0) {
sc->sc_drq = ipa->ipa_drq[0].num;
sc->sc_ad.cap |= WDC_CAPABILITY_DMA;
sc->sc_ad.dma_setup = &wdc_isapnp_dma_setup;
sc->sc_ad.dma_start = &wdc_isapnp_dma_start;
sc->sc_ad.dma_finish = &wdc_isapnp_dma_finish;
wdc_isapnp_dma_setup(sc);
}
#endif
wdcattach(&sc->sc_wdcdev, &sc->sc_ad);
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32;
sc->sc_wdcdev.pio_mode = 0;
sc->sc_wdcdev.channels = &sc->wdc_channel;
sc->sc_wdcdev.nchannels = 1;
sc->wdc_channel.channel = 0;
sc->wdc_channel.wdc = &sc->sc_wdcdev;
sc->wdc_channel.ch_queue = malloc(sizeof(struct channel_queue),
M_DEVBUF, M_NOWAIT);
if (sc->wdc_channel.ch_queue == NULL) {
printf("%s: can't allocate memory for command queue",
sc->sc_wdcdev.sc_dev.dv_xname);
return;
}
wdcattach(&sc->wdc_channel);
}
#ifdef notyet
static void
wdc_isapnp_dma_setup(scv)
void *scv;
wdc_isapnp_dma_setup(sc)
struct wdc_isapnp_softc *sc;
{
struct wdc_isapnp_softc *sc = scv;
if (isa_dmamap_create(sc->sc_ic, sc->sc_drq,
MAXPHYS, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW)) {
printf("%s: can't create map for drq %d\n",
sc->sc_wdcdev.sc_dev.dv_xname, sc->sc_drq);
sc->sc_ad.cap &= ~WDC_CAPABILITY_DMA;
sc->sc_wdcdev.cap &= ~WDC_CAPABILITY_DMA;
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdc_ofisa.c,v 1.2 1998/03/21 02:06:17 cgd Exp $ */
/* $NetBSD: wdc_ofisa.c,v 1.3 1998/10/12 16:09:20 bouyer Exp $ */
/*
* Copyright 1997, 1998
@ -41,6 +41,7 @@
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/tty.h>
#include <sys/malloc.h>
#include <machine/intr.h>
#include <machine/bus.h>
@ -50,12 +51,12 @@
#include <dev/ofisa/ofisavar.h>
#include <dev/ic/wdcreg.h> /* ??? */
#include <dev/ata/atavar.h>
#include <dev/ic/wdcvar.h>
struct wdc_ofisa_softc {
struct wdc_softc sc_wdc;
struct wdc_attachment_data sc_ad;
struct wdc_softc sc_wdcdev;
struct channel_softc wdc_channel;
void *sc_ih;
};
@ -90,8 +91,7 @@ wdc_ofisa_attach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct wdc_ofisa_softc *osc = (void *)self;
struct wdc_softc *sc = &osc->sc_wdc;
struct wdc_ofisa_softc *sc = (void *)self;
struct ofisa_attach_args *aa = aux;
struct ofisa_reg_desc reg[2];
struct ofisa_intr_desc intr;
@ -127,25 +127,35 @@ wdc_ofisa_attach(parent, self, aux)
return;
}
bzero(&osc->sc_ad, sizeof osc->sc_ad);
osc->sc_ad.iot =
sc->wdc_channel.cmd_iot =
(reg[0].type == OFISA_REG_TYPE_IO) ? aa->iot : aa->memt;
osc->sc_ad.auxiot =
sc->wdc_channel.ctl_iot =
(reg[1].type == OFISA_REG_TYPE_IO) ? aa->iot : aa->memt;
if (bus_space_map(osc->sc_ad.iot, reg[0].addr, 8, 0,
&osc->sc_ad.ioh) ||
bus_space_map(osc->sc_ad.auxiot, reg[1].addr, 1, 0,
&osc->sc_ad.auxioh)) {
if (bus_space_map(sc->wdc_channel.cmd_iot, reg[0].addr, 8, 0,
&sc->wdc_channel.cmd_ioh) ||
bus_space_map(sc->wdc_channel.ctl_iot, reg[1].addr, 1, 0,
&sc->wdc_channel.ctl_ioh)) {
printf(": can't map register spaces\n");
return;
}
osc->sc_ih = isa_intr_establish(aa->ic, intr.irq, intr.share,
sc->sc_ih = isa_intr_establish(aa->ic, intr.irq, intr.share,
IPL_BIO, wdcintr, sc);
printf("\n");
wdcattach(sc, &osc->sc_ad);
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16;
sc->sc_wdcdev.channels = &sc->wdc_channel;
sc->sc_wdcdev.nchannels = 1;
sc->wdc_channel.channel = 0;
sc->wdc_channel.wdc = &sc->sc_wdcdev;
sc->wdc_channel.ch_queue = malloc(sizeof(struct channel_queue),
M_DEVBUF, M_NOWAIT);
if (sc->wdc_channel.ch_queue == NULL) {
printf("%s: can't allocate memory for command queue",
sc->sc_wdcdev.sc_dev.dv_xname);
return;
}
wdcattach(&sc->wdc_channel);
#if 0
printf("%s: registers: ", sc->sc_dev.dv_xname);

View File

@ -1,4 +1,4 @@
# $NetBSD: files.pci,v 1.46 1998/09/26 16:20:31 dante Exp $
# $NetBSD: files.pci,v 1.47 1998/10/12 16:09:20 bouyer Exp $
#
# Config file and device description for machine-independent PCI code.
# Included by ports that need it. Requires that the SCSI files be
@ -73,16 +73,10 @@ device ncr: scsi
attach ncr at pci
file dev/pci/ncr.c ncr
# XXX THE FOLLOWING BLOCK SHOULD GO INTO dev/pci/files.pci, BUT CANNOT
# XXX BECAUSE NOT ALL PORTS USE THE MI DRIVER YET. (when the conf/files
# XXX and files.isa bogons are fixed, this can be fixed as well.)
# # PCI IDE controllers
# device pciide {[channel = -1]}
# attach pciide at pci
# file dev/pci/pciide.c pciide
# attach wdc at pciide with wdc_pciide
# file dev/pci/wdc_pciide.c wdc_pciide
# PCI IDE controllers
device pciide {[channel = -1]}: wdc_base, ata, atapi
attach pciide at pci
file dev/pci/pciide.c pciide
# PCI-PCI bridge chips
device ppb: pcibus

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,92 @@
/* $NetBSD: pciide_apollo_reg.h,v 1.2 1998/10/12 16:09:21 bouyer Exp $ */
/*
* Copyright (c) 1998 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
*/
/*
* Registers definitions for VIA technologies's Apollo controllers (VT82V580VO,
* VT82C586A and VT82C586B). Available from http://www.via.com.br/
*/
/* misc. configuration registers */
#define APO_IDECONF 0x40
#define APO_IDECONF_EN(channel) (0x00000001 << (1 - (channel)))
#define APO_IDECONF_SERR_EN 0x00000100 /* 580 only */
#define APO_IDECONF_DS_SOURCE 0x00000200 /* 580 only */
#define APO_IDECONF_ALT_INTR_EN 0x00000400 /* 580 only */
#define APO_IDECONF_PERR_EN 0x00000800 /* 580 only */
#define APO_IDECONF_WR_BUFF_EN(channel) (0x00001000 << ((1 - (channel)) << 1))
#define APO_IDECONF_RD_PREF_EN(channel) (0x00002000 << ((1 - (channel)) << 1))
#define APO_IDECONF_DEVSEL_TME 0x00010000 /* 580 only */
#define APO_IDECONF_MAS_CMD_MON 0x00020000 /* 580 only */
#define APO_IDECONF_IO_NAT(channel) \
(0x00400000 << (1 - (channel))) /* 580 only */
#define APO_IDECONF_FIFO_TRSH(channel, x) \
((x) & 0x3) << ((1 - (channel)) << 1 + 24)
#define APO_IDECONF_FIFO_CONF_MASK 0x60000000
/* Misc. controls register */
#define APO_CTLMISC 0x44
#define APO_CTLMISC_BM_STS_RTY 0x00000008
#define APO_CTLMISC_FIFO_HWS 0x00000010
#define APO_CTLMISC_WR_IRDY_WS 0x00000020
#define APO_CTLMISC_RD_IRDY_WS 0x00000040
#define APO_CTLMISC_INTR_SWP 0x00004000
#define APO_CTLMISC_DRDY_TIME_MASK 0x00030000
#define APO_CTLMISC_FIFO_FLSH_RD(channel) (0x00100000 << (1 - (channel)))
#define APO_CTLMISC_FIFO_FLSH_DMA(channel) (0x00400000 << (1 - (channel)))
/* data port timings controls */
#define APO_DATATIM 0x48
#define APO_DATATIM_RECOV(channel, drive, x) (((x) & 0xf) << \
(((1 - (channel)) << 4) + ((1 - (drive)) << 3)))
#define APO_DATATIM_PULSE(channel, drive, x) (((x) & 0xf) << \
(((1 - (channel)) << 4) + ((1 - (drive)) << 3) + 4))
/* misc timings control */
#define APO_MISCTIM 0x4c
/* Ultra-DMA/33 control (586A/B only) XXX check */
#define APO_UDMA 0x50
#define APO_UDMA_TIME(channel, drive, x) (((x) & 0x3) << \
(((1 - (channel)) << 4) + ((1 - (drive)) << 3)))
#define APO_UDMA_PIO_MODE(channel, drive) (0x20 << \
(((1 - (channel)) << 4) + ((1 - (drive)) << 3)))
#define APO_UDMA_EN(channel, drive) (0x40 << \
(((1 - (channel)) << 4) + ((1 - (drive)) << 3)))
#define APO_UDMA_EN_MTH(channel, drive) (0x80 << \
(((1 - (channel)) << 4) + ((1 - (drive)) << 3)))
static int8_t apollo_udma_tim[] = {0x03, 0x02, 0x00};
static int8_t apollo_pio_set[] = {0x0a, 0x0a, 0x0a, 0x02, 0x02};
static int8_t apollo_pio_rec[] = {0x08, 0x08, 0x08, 0x02, 0x00};

View File

@ -0,0 +1,64 @@
/* $NetBSD: pciide_cmd_reg.h,v 1.2 1998/10/12 16:09:21 bouyer Exp $ */
/*
* Copyright (c) 1998 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
*/
/*
* Registers definitions for CMD Technologies's PCI 064x IDE controllers.
* Available from http://www.cmd.com/
*/
/* Configuration and drive 0 setup */
#define CMD_CONF_CTRL0 0x50
#define CMD_CONF_REV_MASK 0x00000003
#define CMD_CONF_DRV0_INTR 0x00000004
#define CMD_CONF_DEVID 0x00000018
#define CMD_CONF_VESAPRT 0x00000020
#define CMD_CONF_DSA1 0x00000040
#define CMD_CONF_DSA0 0x00000080
#define CMD_CONF_HR_FIFO 0x00000100
#define CMD_CONF_HW_FIFO 0x00000200
#define CMD_CONF_DEVSEL 0x00000400
#define CMD_CONF_2PORT 0x00000800
#define CMD_CONF_PAR 0x00001000
#define CMD_CONF_HW_HLD 0x00002000
#define CMD_CONF_DRV0_RAHEAD 0x00004000
#define CMD_CONF_DRV1_RAHEAD 0x00008000
#define CMD_CONF_CB_TIM_OFF 16
#define CMD_CONF_CB_REC_OFF 20
#define CMD_DRV0_ADDRSET_OFF 30

View File

@ -0,0 +1,109 @@
/* $NetBSD: pciide_piix_reg.h,v 1.2 1998/10/12 16:09:21 bouyer Exp $ */
/*
* Copyright (c) 1998 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
*/
/*
* Registers definitions for Intel's PIIX serie PCI IDE controllers.
* See Intel's
* "82371FB (PIIX) and 82371SB (PIIX3) PCI ISA IDE XCELERATOR" and
* "82371AB PCI-TO-ISA / IDE XCELERATOR (PIIX4)"
* available from http://www.intel.com/
*/
/*
* Bus master interface base address register
*/
#define PIIX_BMIBA 0x20
#define PIIX_BMIBA_ADDR(x) (x & 0x0000FFFF0)
#define PIIX_BMIBA_RTE(x) (x & 0x000000001)
#define PIIX_BMIBA_RTE_IO 0x000000001 /* base addr maps to I/O space */
/*
* IDE timing register
* 0x40/0x41 is for primary, 0x42/0x43 for secondary channel
*/
#define PIIX_IDETIM 0x40
#define PIIX_IDETIM_READ(x, channel) (((x) >> (16 * (channel))) & 0x0000FFFF)
#define PIIX_IDETIM_SET(x, bytes, channel) \
((x) | ((bytes) << (16 * (channel))))
#define PIIX_IDETIM_CLEAR(x, bytes, channel) \
((x) & ~((bytes) << (16 * (channel))))
#define PIIX_IDETIM_IDE 0x8000 /* PIIX decode IDE registers */
#define PIIX_IDETIM_SITRE 0x4000 /* slaves IDE timing registers
enabled (PIIX3/4 only) */
#define PIIX_IDETIM_ISP_MASK 0x3000 /* IOrdy sample point */
#define PIIX_IDETIM_ISP_SHIFT 12
#define PIIX_IDETIM_ISP_SET(x) ((x) << PIIX_IDETIM_ISP_SHIFT)
#define PIIX_IDETIM_RTC_MASK 0x0300 /* recovery time */
#define PIIX_IDETIM_RTC_SHIFT 8
#define PIIX_IDETIM_RTC_SET(x) ((x) << PIIX_IDETIM_RTC_SHIFT)
#define PIIX_IDETIM_DTE(d) (0x0008 << (4 * (d))) /* DMA timing only */
#define PIIX_IDETIM_PPE(d) (0x0004 << (4 * (d))) /* prefetch/posting */
#define PIIX_IDETIM_IE(d) (0x0002 << (4 * (d))) /* IORDY enable */
#define PIIX_IDETIM_TIME(d) (0x0001 << (4 * (d))) /* Fast timing enable */
/*
* Slave IDE timing register (PIIX3/4 only)
* This register must be enabled via the PIIX_IDETIM_SITRE bit
*/
#define PIIX_SIDETIM 0x44
#define PIIX_SIDETIM_ISP_MASK(channel) (0x0c << ((channel) * 4))
#define PIIX_SIDETIM_ISP_SHIFT 2
#define PIIX_SIDETIM_ISP_SET(x, channel) \
(x << (PIIX_SIDETIM_ISP_SHIFT + ((channel) * 4)))
#define PIIX_SIDETIM_RTC_MASK(channel) (0x03 << ((channel) * 4))
#define PIIX_SIDETIM_RTC_SHIFT 0
#define PIIX_SIDETIM_RTC_SET(x, channel) \
(x << (PIIX_SIDETIM_RTC_SHIFT + ((channel) * 4)))
/*
* Ultra DMA/33 register (PIIX4 only)
*/
#define PIIX_UDMAREG 0x48
/* Control register */
#define PIIX_UDMACTL_DRV_EN(channel, drive) (0x01 << ((channel) * 2 + (drive)))
/* Ultra DMA/33 timing register (PIIX4 only) */
#define PIIX_UDMATIM_SHIFT 16
#define PIIX_UDMATIM_SET(x, channel, drive) \
(((x) << ((channel * 8) + (drive * 4))) << PIIX_UDMATIM_SHIFT)
/*
* these tables define the differents values to upload to the
* ISP and RTC registers for the various PIO and DMA mode
* (from the PIIX4 doc).
*/
static int8_t piix_isp_pio[] = {0x00, 0x00, 0x01, 0x02, 0x02};
static int8_t piix_rtc_pio[] = {0x00, 0x00, 0x00, 0x01, 0x03};
static int8_t piix_isp_dma[] = {0x00, 0x02, 0x02};
static int8_t piix_rtc_dma[] = {0x00, 0x02, 0x03};
static int8_t piix4_sct_udma[] = {0x00, 0x01, 0x02};

View File

@ -1,4 +1,4 @@
/* $NetBSD: pciidereg.h,v 1.2 1998/03/04 19:17:10 cgd Exp $ */
/* $NetBSD: pciidereg.h,v 1.3 1998/10/12 16:09:22 bouyer Exp $ */
/*
* Copyright (c) 1998 Christopher G. Demetriou. All rights reserved.
@ -68,3 +68,42 @@
#define PCIIDE_COMPAT_CTL_BASE(chan) ((chan) == 0 ? 0x3f6 : 0x376)
#define PCIIDE_COMPAT_CTL_SIZE 1
#define PCIIDE_COMPAT_IRQ(chan) ((chan) == 0 ? 14 : 15)
/*
* definitions for IDE DMA
* XXX maybe this should go elsewhere
*/
/* secondary channel registers offset */
#define IDEDMA_SCH_OFFSET 0x08
/* Bus master command register */
#define IDEDMA_CMD 0x00
#define IDEDMA_CMD_WRITE 0x08
#define IDEDMA_CMD_START 0x01
/* Bus master status register */
#define IDEDMA_CTL 0x02
#define IDEDMA_CTL_DRV_DMA(d) (0x20 << (d))
#define IDEDMA_CTL_INTR 0x04
#define IDEDMA_CTL_ERR 0x02
#define IDEDMA_CTL_ACT 0x01
/* Bus master table pointer register */
#define IDEDMA_TBL 0x04
#define IDEDMA_TBL_MASK 0xfffffffc
#define IDEDMA_TBL_ALIGN 0x00010000
/* bus master table descriptor */
struct idedma_table {
u_int32_t base_addr; /* physical base addr of memory region */
u_int32_t byte_count; /* memory region length */
#define IDEDMA_BYTE_COUNT_MASK 0x0000FFFF
#define IDEDMA_BYTE_COUNT_EOT 0x80000000
};
#define IDEDMA_BYTE_COUNT_MAX 0x00010000 /* Max I/O per table */
#define IDEDMA_BYTE_COUNT_ALIGN 0x00010000
/* Number of idedma table needed */
#define NIDEDMA_TABLES (MAXPHYS/NBPG + 1)

View File

@ -1,4 +1,4 @@
/* $NetBSD: pciidevar.h,v 1.1 1998/03/04 06:35:11 cgd Exp $ */
/* $NetBSD: pciidevar.h,v 1.2 1998/10/12 16:09:22 bouyer Exp $ */
/*
* Copyright (c) 1998 Christopher G. Demetriou. All rights reserved.
@ -37,18 +37,6 @@
*/
struct device;
struct pci_attach_args;
/*
* Attach args for devices that attach to pciide. Really, that's just wdc.
*/
struct pciide_attach_args {
int channel;
bus_space_tag_t cmd_iot, ctl_iot;
bus_space_handle_t cmd_ioh, ctl_ioh;
int (**ihandp) __P((void *));
void **ihandargp;
};
/*
* Functions defined by machine-dependent code.

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdc_pcmcia.c,v 1.11 1998/10/10 22:01:24 thorpej Exp $ */
/* $NetBSD: wdc_pcmcia.c,v 1.12 1998/10/12 16:09:22 bouyer Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -62,6 +62,7 @@
#include <dev/pcmcia/pcmciadevs.h>
#include <dev/isa/isavar.h>
#include <dev/ata/atavar.h>
#include <dev/ic/wdcvar.h>
#define WDC_PCMCIA_REG_NPORTS 8
@ -70,7 +71,7 @@
struct wdc_pcmcia_softc {
struct wdc_softc sc_wdcdev;
struct wdc_attachment_data sc_ad;
struct channel_softc wdc_channel;
struct pcmcia_io_handle sc_pioh;
struct pcmcia_io_handle sc_auxpioh;
int sc_iowindow;
@ -208,11 +209,6 @@ wdc_pcmcia_attach(parent, self, aux)
return;
}
sc->sc_ad.iot = sc->sc_pioh.iot;
sc->sc_ad.ioh = sc->sc_pioh.ioh;
sc->sc_ad.auxiot = sc->sc_auxpioh.iot;
sc->sc_ad.auxioh = sc->sc_auxpioh.ioh;
/* Enable the card. */
pcmcia_function_init(pa->pf, cfe);
if (pcmcia_function_enable(pa->pf)) {
@ -252,15 +248,33 @@ wdc_pcmcia_attach(parent, self, aux)
}
printf("\n");
sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_BIO, wdcintr, sc);
sc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_BIO, wdcintr,
&sc->wdc_channel);
if (sc->sc_ih == NULL) {
printf("%s: couldn't establish interrupt\n", self->dv_xname);
return;
}
sc->wdc_channel.cmd_iot = sc->sc_pioh.iot;
sc->wdc_channel.cmd_ioh = sc->sc_pioh.ioh;
sc->wdc_channel.ctl_iot = sc->sc_auxpioh.iot;
sc->wdc_channel.ctl_ioh = sc->sc_auxpioh.ioh;
sc->wdc_channel.data32iot = sc->wdc_channel.cmd_iot;
sc->wdc_channel.data32ioh = sc->wdc_channel.cmd_ioh;
sc->sc_wdcdev.cap |= WDC_CAPABILITY_DATA16 | WDC_CAPABILITY_DATA32;
sc->sc_wdcdev.pio_mode = 0;
sc->sc_wdcdev.channels = &sc->wdc_channel;
sc->sc_wdcdev.nchannels = 1;
sc->wdc_channel.channel = 0;
sc->wdc_channel.wdc = &sc->sc_wdcdev;
sc->wdc_channel.ch_queue = malloc(sizeof(struct channel_queue),
M_DEVBUF, M_NOWAIT);
if (sc->wdc_channel.ch_queue == NULL) {
printf("%s: can't allocate memory for command queue",
sc->sc_wdcdev.sc_dev.dv_xname);
return;
}
if (wpp->wpp_quirk_flag & WDC_PCMCIA_NO_EXTRA_RESETS)
sc->sc_ad.flags |= WDC_NO_EXTRA_RESETS;
wdcattach(&sc->sc_wdcdev, &sc->sc_ad);
sc->sc_wdcdev.cap |= WDC_CAPABILITY_NO_EXTRA_RESETS;
wdcattach(&sc->wdc_channel);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: atapi_base.c,v 1.9 1998/08/15 10:10:55 mycroft Exp $ */
/* $NetBSD: atapi_base.c,v 1.10 1998/10/12 16:09:23 bouyer Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -183,11 +183,11 @@ atapi_print_addr(sc_link)
struct scsipi_link *sc_link;
{
printf("%s(%s:%d): ",
printf("%s(%s:%d:%d): ",
sc_link->device_softc ?
((struct device *)sc_link->device_softc)->dv_xname : "probe",
((struct device *)sc_link->adapter_softc)->dv_xname,
sc_link->scsipi_atapi.drive);
sc_link->scsipi_atapi.channel, sc_link->scsipi_atapi.drive);
}
/*

713
sys/dev/scsipi/atapi_wdc.c Normal file
View File

@ -0,0 +1,713 @@
/* $NetBSD: atapi_wdc.c,v 1.2 1998/10/12 16:09:23 bouyer Exp $ */
/*
* Copyright (c) 1998 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
*/
#define WDCDEBUG
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/buf.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/syslog.h>
#include <sys/proc.h>
#include <vm/vm.h>
#include <machine/intr.h>
#include <machine/bus.h>
#ifndef __BUS_SPACE_HAS_STREAM_METHODS
#define bus_space_write_multi_stream_2 bus_space_write_multi_2
#define bus_space_write_multi_stream_4 bus_space_write_multi_4
#define bus_space_read_multi_stream_2 bus_space_read_multi_2
#define bus_space_read_multi_stream_4 bus_space_read_multi_4
#endif /* __BUS_SPACE_HAS_STREAM_METHODS */
#include <dev/ata/atareg.h>
#include <dev/ata/atavar.h>
#include <dev/ic/wdcreg.h>
#include <dev/ic/wdcvar.h>
#include <dev/scsipi/scsipi_all.h>
#include <dev/scsipi/scsipiconf.h>
#include <dev/scsipi/atapiconf.h>
#define DEBUG_INTR 0x01
#define DEBUG_XFERS 0x02
#define DEBUG_STATUS 0x04
#define DEBUG_FUNCS 0x08
#define DEBUG_PROBE 0x10
#ifdef WDCDEBUG
int wdcdebug_atapi_mask = DEBUG_PROBE;
#define WDCDEBUG_PRINT(args, level) \
if (wdcdebug_atapi_mask & (level)) \
printf args
#else
#define WDCDEBUG_PRINT(args, level)
#endif
#define ATAPI_DELAY 10 /* 10 ms, this is used only before sending a cmd */
void wdc_atapi_minphys __P((struct buf *bp));
void wdc_atapi_start __P((struct channel_softc *,struct wdc_xfer *));
int wdc_atapi_intr __P((struct channel_softc *, struct wdc_xfer *));
int wdc_atapi_ctrl __P((struct channel_softc *, struct wdc_xfer *));
void wdc_atapi_done __P((struct channel_softc *, struct wdc_xfer *));
void wdc_atapi_reset __P((struct channel_softc *, struct wdc_xfer *));
int wdc_atapi_send_cmd __P((struct scsipi_xfer *sc_xfer));
#define MAX_SIZE MAXPHYS
static struct scsipi_adapter wdc_switch = {
wdc_atapi_send_cmd,
wdc_atapi_minphys,
NULL, /* scsipi_ioctl */
};
void
wdc_atapibus_attach(chp)
struct channel_softc *chp;
{
struct wdc_softc *wdc = chp->wdc;
int channel = chp->channel;
struct ata_atapi_attach aa_link;
memset(&aa_link, 0, sizeof(struct ata_atapi_attach));
aa_link.aa_type = T_ATAPI;
aa_link.aa_channel = channel;
aa_link.aa_openings = 1;
aa_link.aa_drv_data = chp->ch_drive; /* pass the whole array */
aa_link.aa_bus_private = &wdc_switch;
(void)config_found(&wdc->sc_dev, (void *)&aa_link, atapi_print);
}
void
wdc_atapi_minphys (struct buf *bp)
{
if(bp->b_bcount > MAX_SIZE)
bp->b_bcount = MAX_SIZE;
minphys(bp);
}
int
wdc_atapi_get_params(ab_link, drive, flags, id)
struct scsipi_link *ab_link;
u_int8_t drive;
int flags;
struct ataparams *id;
{
struct wdc_softc *wdc = (void*)ab_link->adapter_softc;
struct channel_softc *chp =
&wdc->channels[ab_link->scsipi_atapi.channel];
struct wdc_command wdc_c;
/* if no ATAPI device detected at wdc attach time, skip */
/*
* XXX this will break scsireprobe if this is of any interest for
* ATAPI devices one day.
*/
if ((chp->ch_drive[drive].drive_flags & DRIVE_ATAPI) == 0) {
WDCDEBUG_PRINT(("wdc_atapi_get_params: drive %d not present\n",
drive), DEBUG_PROBE);
return -1;
}
memset(&wdc_c, 0, sizeof(struct wdc_command));
wdc_c.r_command = ATAPI_SOFT_RESET;
wdc_c.r_st_bmask = 0;
wdc_c.r_st_pmask = 0;
wdc_c.flags = AT_POLL;
wdc_c.timeout = WDC_RESET_WAIT;
if (wdc_exec_command(&chp->ch_drive[drive], &wdc_c) != WDC_COMPLETE) {
printf("wdc_atapi_get_params: ATAPI_SOFT_RESET failed for"
" drive %s:%d:%d: driver failed\n",
chp->wdc->sc_dev.dv_xname, chp->channel, drive);
panic("wdc_atapi_get_params");
}
if (wdc_c.flags & (AT_ERROR | AT_TIMEOU | AT_DF)) {
WDCDEBUG_PRINT(("wdc_atapi_get_params: ATAPI_SOFT_RESET "
"failed for drive %s:%d:%d: error 0x%x\n",
chp->wdc->sc_dev.dv_xname, chp->channel, drive,
wdc_c.r_error), DEBUG_PROBE);
return -1;
}
chp->ch_drive[drive].state = 0;
bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_status);
/* Some ATAPI devices need a bit more time after software reset. */
delay(5000);
if (ata_get_params(&chp->ch_drive[drive], AT_POLL, id) != 0) {
WDCDEBUG_PRINT(("wdc_atapi_get_params: ATAPI_IDENTIFY_DEVICE "
"failed for drive %s:%d:%d: error 0x%x\n",
chp->wdc->sc_dev.dv_xname, chp->channel, drive,
wdc_c.r_error), DEBUG_PROBE);
return -1;
}
return COMPLETE;
}
int
wdc_atapi_send_cmd(sc_xfer)
struct scsipi_xfer *sc_xfer;
{
struct scsipi_link *sc_link = sc_xfer->sc_link;
struct wdc_softc *wdc = (void*)sc_link->adapter_softc;
struct wdc_xfer *xfer;
struct ata_drive_datas *drvp;
int flags = sc_xfer->flags;
int channel = sc_xfer->sc_link->scsipi_atapi.channel;
int drive = sc_xfer->sc_link->scsipi_atapi.drive;
int s, ret;
WDCDEBUG_PRINT(("wdc_atapi_send_cmd\n"), DEBUG_FUNCS);
xfer = wdc_get_xfer(flags & SCSI_NOSLEEP ? WDC_NOSLEEP : WDC_CANSLEEP);
if (xfer == NULL) {
return TRY_AGAIN_LATER;
}
if (sc_xfer->flags & SCSI_POLL)
xfer->c_flags |= C_POLL;
drvp = &wdc->channels[channel].ch_drive[drive];
if ((drvp->drive_flags & (DRIVE_DMA | DRIVE_UDMA)) &&
sc_xfer->datalen > 0)
xfer->c_flags |= C_DMA;
xfer->drive = drive;
xfer->c_flags |= C_ATAPI;
xfer->cmd = sc_xfer;
xfer->databuf = sc_xfer->data;
xfer->c_bcount = sc_xfer->datalen;
xfer->c_start = wdc_atapi_start;
xfer->c_intr = wdc_atapi_intr;
s = splbio();
wdc_exec_xfer(&wdc->channels[channel], xfer);
#ifdef DIAGNOSTIC
if ((sc_xfer->flags & SCSI_POLL) != 0 &&
(sc_xfer->flags & ITSDONE) == 0)
panic("wdc_atapi_send_cmd: polled command not done");
#endif
ret = (sc_xfer->flags & ITSDONE) ? COMPLETE : SUCCESSFULLY_QUEUED;
splx(s);
return ret;
}
void
wdc_atapi_start(chp, xfer)
struct channel_softc *chp;
struct wdc_xfer *xfer;
{
struct scsipi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
WDCDEBUG_PRINT(("wdc_atapi_start, scsi flags 0x%x \n",sc_xfer->flags),
DEBUG_FUNCS);
/* Do control operations specially. */
if (drvp->state < READY) {
if (drvp->state != PIOMODE) {
printf("%s:%d:%d: bad state %d in wdc_atapi_start\n",
chp->wdc->sc_dev.dv_xname, chp->channel,
xfer->drive, drvp->state);
panic("wdc_atapi_start: bad state");
}
wdc_atapi_ctrl(chp, xfer);
return;
}
bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
WDSD_IBM | (xfer->drive << 4));
if (wait_for_unbusy(chp, ATAPI_DELAY) < 0) {
printf("wdc_atapi_start: not ready, st = %02x\n",
chp->ch_status);
wdc_atapi_reset(chp, xfer);
return;
}
/*
* Even with WDCS_ERR, the device should accept a command packet
* Limit length to what can be stuffed into the cylinder register
* (16 bits). Some CD-ROMs seem to interpret '0' as 65536,
* but not all devices do that and it's not obvious from the
* ATAPI spec that that behaviour should be expected. If more
* data is necessary, multiple data transfer phases will be done.
*/
wdccommand(chp, xfer->drive, ATAPI_PKT_CMD,
sc_xfer->datalen <= 0xffff ? sc_xfer->datalen : 0xffff,
0, 0, 0,
(xfer->c_flags & C_DMA) ? ATAPI_PKT_CMD_FTRE_DMA : 0);
/*
* If there is no interrupt for CMD input, busy-wait for it (done in
* the interrupt routine. If it is a polled command, call the interrupt
* routine until command is done.
*/
if ((sc_xfer->sc_link->scsipi_atapi.cap & 0x0300) != ACAP_DRQ_INTR ||
sc_xfer->flags & SCSI_POLL) {
/* Wait for at last 400ns for status bit to be valid */
delay(1);
if (wdc_atapi_intr(chp, xfer) == 0) {
wdc_atapi_reset(chp, xfer);
return;
}
}
if (sc_xfer->flags & SCSI_POLL) {
while ((sc_xfer->flags & ITSDONE) == 0) {
/* Wait for at last 400ns for status bit to be valid */
delay(1);
if (wdc_atapi_intr(chp, xfer) == 0) {
sc_xfer->error = XS_SELTIMEOUT;
/* do we know more ? */
wdc_atapi_done(chp, xfer);
return;
}
}
}
}
int
wdc_atapi_intr(chp, xfer)
struct channel_softc *chp;
struct wdc_xfer *xfer;
{
struct scsipi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
int len, phase, i, retries=0;
int ire, dma_err = 0;
int dma_flags = 0;
WDCDEBUG_PRINT(("wdc_atapi_intr\n"), DEBUG_INTR);
/* Is it not a transfer, but a control operation? */
if (drvp->state < READY) {
printf("%s:%d:%d: bad state %d in wdc_atapi_intr\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
drvp->state);
panic("wdc_atapi_intr: bad state\n");
}
/* Ack interrupt done in wait_for_unbusy */
bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
WDSD_IBM | (xfer->drive << 4));
if (wait_for_unbusy(chp, sc_xfer->timeout) != 0) {
printf("%s:%d:%d: device timeout, c_bcount=%d, c_skip%d\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
xfer->c_bcount, xfer->c_skip);
wdc_atapi_reset(chp, xfer);
return 1;
}
/* Error here only if the command is aborted */
if ((chp->ch_status & WDCS_ERR) != 0 &&
(chp->ch_error & WDCE_ABRT) != 0) {
sc_xfer->error = XS_SENSE;
sc_xfer->sense.atapi_sense = chp->ch_error;
WDCDEBUG_PRINT(("wdc_atapi_intr: wdc_atapi_done(), "
"sense 0x%x\n", sc_xfer->sense.atapi_sense), DEBUG_INTR);
wdc_atapi_done(chp, xfer);
return 1;
}
if (xfer->c_flags & C_DMA) {
dma_flags = (sc_xfer->flags & SCSI_DATA_IN) ?
WDC_DMA_READ : 0;
dma_flags |= sc_xfer->flags & SCSI_POLL ? WDC_DMA_POLL : 0;
}
again:
len = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_lo) +
256 * bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_cyl_hi);
ire = bus_space_read_1(chp->cmd_iot, chp->cmd_ioh, wd_ireason);
phase = (ire & (WDCI_CMD | WDCI_IN)) | (chp->ch_status & WDCS_DRQ);
WDCDEBUG_PRINT(("wdc_atapi_intr: c_bcount %d len %d st 0x%x err 0x%x "
"ire 0x%x :", xfer->c_bcount,
len, chp->ch_status, chp->ch_error, ire), DEBUG_INTR);
switch (phase) {
case PHASE_CMDOUT:
WDCDEBUG_PRINT(("PHASE_CMDOUT\n"), DEBUG_INTR);
/* Init the DMA channel if necessary */
if (xfer->c_flags & C_DMA) {
if ((*chp->wdc->dma_init)(chp->wdc->dma_arg,
chp->channel, xfer->drive,
xfer->databuf, sc_xfer->datalen, dma_flags) != 0) {
sc_xfer->error = XS_DRIVER_STUFFUP;
break;
}
}
/* send packet command */
/* Commands are 12 or 16 bytes long. It's 32-bit aligned */
if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM)) {
if (drvp->drive_flags & DRIVE_CAP32) {
bus_space_write_multi_4(chp->data32iot,
chp->data32ioh, 0,
(u_int32_t *)sc_xfer->cmd,
sc_xfer->cmdlen >> 2);
} else {
bus_space_write_multi_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
(u_int16_t *)sc_xfer->cmd,
sc_xfer->cmdlen >> 1);
}
} else {
if (drvp->drive_flags & DRIVE_CAP32) {
bus_space_write_multi_stream_4(chp->data32iot,
chp->data32ioh, 0,
(u_int32_t *)sc_xfer->cmd,
sc_xfer->cmdlen >> 2);
} else {
bus_space_write_multi_stream_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
(u_int16_t *)sc_xfer->cmd,
sc_xfer->cmdlen >> 1);
}
}
/* Start the DMA channel if necessary */
if (xfer->c_flags & C_DMA) {
(*chp->wdc->dma_start)(chp->wdc->dma_arg,
chp->channel, xfer->drive, dma_flags);
}
if ((sc_xfer->flags & SCSI_POLL) == 0) {
chp->ch_flags |= WDCF_IRQ_WAIT;
timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000);
}
return 1;
case PHASE_DATAOUT:
/* write data */
WDCDEBUG_PRINT(("PHASE_DATAOUT\n"), DEBUG_INTR);
if ((sc_xfer->flags & SCSI_DATA_OUT) == 0 ||
(xfer->c_flags & C_DMA) != 0) {
printf("wdc_atapi_intr: bad data phase DATAOUT");
if (xfer->c_flags & C_DMA) {
printf(", falling back to PIO\n");
drvp->drive_flags &= ~(DRIVE_DMA | DRIVE_UDMA);
}
wdc_atapi_reset(chp, xfer);
return 1;
}
if (xfer->c_bcount < len) {
printf("wdc_atapi_intr: warning: write only "
"%d of %d requested bytes\n", xfer->c_bcount, len);
if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM)) {
bus_space_write_multi_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip,
xfer->c_bcount >> 1);
} else {
bus_space_write_multi_stream_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip,
xfer->c_bcount >> 1);
}
for (i = xfer->c_bcount; i < len; i += 2)
bus_space_write_2(chp->cmd_iot, chp->cmd_ioh,
wd_data, 0);
xfer->c_skip += xfer->c_bcount;
xfer->c_bcount = 0;
} else {
if (drvp->drive_flags & DRIVE_CAP32) {
if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM))
bus_space_write_multi_4(chp->data32iot,
chp->data32ioh, 0,
xfer->databuf + xfer->c_skip, len >> 2);
else
bus_space_write_multi_stream_4(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip, len >> 2);
xfer->c_skip += len & 0xfffffffc;
xfer->c_bcount -= len & 0xfffffffc;
len = len & 0x03;
}
if (len > 0) {
if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM))
bus_space_write_multi_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip, len >> 1);
else
bus_space_write_multi_stream_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip, len >> 1);
xfer->c_skip += len;
xfer->c_bcount -= len;
}
}
if ((sc_xfer->flags & SCSI_POLL) == 0) {
chp->ch_flags |= WDCF_IRQ_WAIT;
timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000);
}
return 1;
case PHASE_DATAIN:
/* Read data */
WDCDEBUG_PRINT(("PHASE_DATAIN\n"), DEBUG_INTR);
if ((sc_xfer->flags & SCSI_DATA_IN) == 0 ||
(xfer->c_flags & C_DMA) != 0) {
printf("wdc_atapi_intr: bad data phase DATAIN");
if (xfer->c_flags & C_DMA) {
printf(", falling back to PIO\n");
drvp->drive_flags &= ~(DRIVE_DMA | DRIVE_UDMA);
}
wdc_atapi_reset(chp, xfer);
return 1;
}
if (xfer->c_bcount < len) {
printf("wdc_atapi_intr: warning: reading only "
"%d of %d bytes\n", xfer->c_bcount, len);
if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM)) {
bus_space_read_multi_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip, xfer->c_bcount >> 1);
} else {
bus_space_read_multi_stream_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip, xfer->c_bcount >> 1);
}
wdcbit_bucket(chp, len - xfer->c_bcount);
xfer->c_skip += xfer->c_bcount;
xfer->c_bcount = 0;
} else {
if (drvp->drive_flags & DRIVE_CAP32) {
if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM))
bus_space_read_multi_4(chp->data32iot,
chp->data32ioh, 0,
xfer->databuf + xfer->c_skip, len >> 2);
else
bus_space_read_multi_stream_4(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip, len >> 2);
xfer->c_skip += len & 0xfffffffc;
xfer->c_bcount -= len & 0xfffffffc;
len = len & 0x03;
}
if (len > 0) {
if ((chp->wdc->cap & WDC_CAPABILITY_ATAPI_NOSTREAM))
bus_space_read_multi_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip, len >> 1);
else
bus_space_read_multi_stream_2(chp->cmd_iot,
chp->cmd_ioh, wd_data,
xfer->databuf + xfer->c_skip, len >> 1);
xfer->c_skip += len;
xfer->c_bcount -=len;
}
}
if ((sc_xfer->flags & SCSI_POLL) == 0) {
chp->ch_flags |= WDCF_IRQ_WAIT;
timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000);
}
return 1;
case PHASE_ABORTED:
case PHASE_COMPLETED:
WDCDEBUG_PRINT(("PHASE_COMPLETED\n"), DEBUG_INTR);
/* turn off DMA channel */
if (xfer->c_flags & C_DMA) {
dma_err = (*chp->wdc->dma_finish)(chp->wdc->dma_arg,
chp->channel, xfer->drive, dma_flags);
xfer->c_bcount -= sc_xfer->datalen;
}
if (chp->ch_status & WDCS_ERR) {
sc_xfer->error = XS_SENSE;
sc_xfer->sense.atapi_sense = chp->ch_error;
} else if (dma_err < 0) {
sc_xfer->error = XS_DRIVER_STUFFUP;
}
#ifdef DIAGNOSTIC
if (xfer->c_bcount != 0) {
printf("wdc_atapi_intr warning: bcount value "
"is %d after io\n", xfer->c_bcount);
}
#endif
break;
default:
if (++retries<500) {
DELAY(100);
chp->ch_status = bus_space_read_1(chp->cmd_iot,
chp->cmd_ioh, wd_status);
chp->ch_error = bus_space_read_1(chp->cmd_iot,
chp->cmd_ioh, wd_error);
goto again;
}
printf("wdc_atapi_intr: unknown phase 0x%x\n", phase);
if (chp->ch_status & WDCS_ERR) {
sc_xfer->error = XS_SENSE;
sc_xfer->sense.atapi_sense = chp->ch_error;
} else {
sc_xfer->error = XS_DRIVER_STUFFUP;
}
}
WDCDEBUG_PRINT(("wdc_atapi_intr: wdc_atapi_done() (end), error 0x%x "
"sense 0x%x\n", sc_xfer->error, sc_xfer->sense.atapi_sense),
DEBUG_INTR);
wdc_atapi_done(chp, xfer);
return (1);
}
int
wdc_atapi_ctrl(chp, xfer)
struct channel_softc *chp;
struct wdc_xfer *xfer;
{
struct scsipi_xfer *sc_xfer = xfer->cmd;
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
char *errstring = NULL;
WDCDEBUG_PRINT(("wdc_atapi_ctrl state %d\n", drvp->state), DEBUG_INTR);
/* Ack interrupt done in wait_for_unbusy */
again:
bus_space_write_1(chp->cmd_iot, chp->cmd_ioh, wd_sdh,
WDSD_IBM | (xfer->drive << 4));
switch (drvp->state) {
case PIOMODE:
/* Don't try to set mode if controller can't be adjusted */
if ((chp->wdc->cap & WDC_CAPABILITY_MODE) == 0)
goto ready;
wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
0x08 | drvp->PIO_mode, WDSF_SET_MODE);
drvp->state = PIOMODE_WAIT;
break;
case PIOMODE_WAIT:
errstring = "piomode";
if (wait_for_unbusy(chp, ATAPI_DELAY))
goto timeout;
if (chp->ch_status & WDCS_ERR)
goto error;
/* fall through */
case DMAMODE:
if (drvp->drive_flags & DRIVE_UDMA) {
wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
0x40 | drvp->UDMA_mode, WDSF_SET_MODE);
} else if (drvp->drive_flags & DRIVE_DMA) {
wdccommand(chp, drvp->drive, SET_FEATURES, 0, 0, 0,
0x20 | drvp->DMA_mode, WDSF_SET_MODE);
} else {
goto ready;
}
drvp->state = DMAMODE_WAIT;
break;
case DMAMODE_WAIT:
errstring = "dmamode";
if (wait_for_unbusy(chp, ATAPI_DELAY))
goto timeout;
if (chp->ch_status & WDCS_ERR)
goto error;
/* fall through */
case READY:
ready:
drvp->state = READY;
xfer->c_intr = wdc_atapi_intr;
wdc_atapi_start(chp, xfer);
return 1;
}
if ((sc_xfer->flags & SCSI_POLL) == 0) {
chp->ch_flags |= WDCF_IRQ_WAIT;
xfer->c_intr = wdc_atapi_ctrl;
timeout(wdctimeout, chp, sc_xfer->timeout * hz / 1000);
} else {
goto again;
}
return 1;
timeout:
if ((xfer->c_flags & C_TIMEOU) == 0 ) {
return 0; /* IRQ was not for us */
}
printf("%s:%d:%d: %s timed out\n",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive, errstring);
wdc_atapi_reset(chp, xfer);
return 1;
error:
printf("%s:%d:%d: %s ",
chp->wdc->sc_dev.dv_xname, chp->channel, xfer->drive,
errstring);
printf("error (%x)\n", chp->ch_error);
sc_xfer->error = XS_SENSE;
sc_xfer->sense.atapi_sense = chp->ch_error;
drvp->state = 0;
wdc_atapi_done(chp, xfer);
return 1;
}
void
wdc_atapi_done(chp, xfer)
struct channel_softc *chp;
struct wdc_xfer *xfer;
{
struct scsipi_xfer *sc_xfer = xfer->cmd;
struct wdc_softc *wdc = chp->wdc;
int need_done = xfer->c_flags & C_NEEDDONE;
WDCDEBUG_PRINT(("wdc_atapi_done: flags 0x%x\n", (u_int)xfer->c_flags),
DEBUG_FUNCS);
sc_xfer->resid = xfer->c_bcount;
/* remove this command from xfer queue */
xfer->c_skip = 0;
wdc_free_xfer(chp, xfer);
sc_xfer->flags |= ITSDONE;
if (need_done) {
WDCDEBUG_PRINT(("wdc_atapi_done: scsipi_done\n"), DEBUG_FUNCS);
scsipi_done(sc_xfer);
}
WDCDEBUG_PRINT(("wdcstart from wdc_atapi_done, flags 0x%x\n",
chp->ch_flags), DEBUG_FUNCS);
wdcstart(wdc, chp->channel);
}
void
wdc_atapi_reset(chp, xfer)
struct channel_softc *chp;
struct wdc_xfer *xfer;
{
struct ata_drive_datas *drvp = &chp->ch_drive[xfer->drive];
struct scsipi_xfer *sc_xfer = xfer->cmd;
wdccommandshort(chp, xfer->drive, ATAPI_SOFT_RESET);
drvp->state = 0;
if (wait_for_unbusy(chp, WDC_RESET_WAIT) != 0) {
printf("%s:%d:%d: reset failed\n",
chp->wdc->sc_dev.dv_xname, chp->channel,
xfer->drive);
sc_xfer->error = XS_SELTIMEOUT;
wdc_atapi_done(chp, xfer);
return;
}
sc_xfer->error = XS_TIMEOUT;
wdc_atapi_done(chp, xfer);
return;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: atapiconf.c,v 1.12 1998/08/31 22:28:06 cgd Exp $ */
/* $NetBSD: atapiconf.c,v 1.13 1998/10/12 16:09:24 bouyer Exp $ */
/*
* Copyright (c) 1996 Manuel Bouyer. All rights reserved.
@ -37,6 +37,8 @@
#include <sys/buf.h>
#include <sys/proc.h>
#include <dev/ata/atareg.h>
#include <dev/ata/atavar.h>
#include <dev/scsipi/scsipi_all.h>
#include <dev/scsipi/atapi_all.h>
#include <dev/scsipi/scsipiconf.h>
@ -50,6 +52,7 @@ struct atapibus_softc {
struct device sc_dev;
struct scsipi_link *adapter_link; /* proto supplied by adapter */
struct scsipi_link **sc_link; /* dynamically allocated */
struct ata_drive_datas *sc_drvs; /* array supplied by adapter */
};
int atapibusmatch __P((struct device *, struct cfdata *, void *));
@ -99,12 +102,15 @@ atapibusmatch(parent, cf, aux)
struct cfdata *cf;
void *aux;
{
struct scsipi_link *sc_link = aux;
struct ata_atapi_attach *aa_link = aux;
if (sc_link == NULL)
if (aa_link == NULL)
return (0);
if (sc_link->type != BUS_ATAPI)
if (aa_link->aa_type != T_ATAPI)
return (0);
if (cf->cf_loc[ATAPICF_CHANNEL] != aa_link->aa_channel &&
cf->cf_loc[ATAPICF_CHANNEL] != ATAPICF_CHANNEL_DEFAULT)
return 0;
return (1);
}
@ -128,7 +134,7 @@ void
atapi_fixquirk(sc_link)
struct scsipi_link *ad_link;
{
struct atapi_identify *id = &ad_link->id;
struct ataparams *id = &ad_link->id;
struct atapi_quirk_inquiry_pattern *quirk;
/*
@ -145,8 +151,9 @@ atapibusattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
struct atapibus_softc *ab = (struct atapibus_softc *)self;
struct scsipi_link *sc_link_proto = aux;
struct atapibus_softc *sc_ab = (struct atapibus_softc *)self;
struct ata_atapi_attach *aa_link = aux;
struct scsipi_link *sc_link_proto;
int nbytes;
printf("\n");
@ -154,20 +161,33 @@ atapibusattach(parent, self, aux)
/* Initialize shared data. */
scsipi_init();
sc_link_proto->scsipi_atapi.atapibus = ab->sc_dev.dv_unit;
sc_link_proto = malloc(sizeof(struct scsipi_link),
M_DEVBUF, M_NOWAIT);
if (sc_link_proto == NULL)
printf("atapibusattach : can't allocate scsipi link proto\n");
memset(sc_link_proto, 0, sizeof(struct scsipi_link));
sc_link_proto->type = BUS_ATAPI;
sc_link_proto->openings = aa_link->aa_openings;
sc_link_proto->scsipi_atapi.channel = aa_link->aa_channel;
sc_link_proto->adapter_softc = parent;
sc_link_proto->adapter = aa_link->aa_bus_private;
sc_link_proto->scsipi_atapi.atapibus = sc_ab->sc_dev.dv_unit;
sc_link_proto->scsipi_cmd = atapi_scsipi_cmd;
sc_link_proto->scsipi_interpret_sense = atapi_interpret_sense;
sc_link_proto->sc_print_addr = atapi_print_addr;
ab->adapter_link = sc_link_proto;
sc_ab->adapter_link = sc_link_proto;
sc_ab->sc_drvs = aa_link->aa_drv_data;
nbytes = 2 * sizeof(struct scsipi_link **);
ab->sc_link = (struct scsipi_link **)malloc(nbytes, M_DEVBUF,
sc_ab->sc_link = (struct scsipi_link **)malloc(nbytes, M_DEVBUF,
M_NOWAIT);
if (ab->sc_link == NULL)
if (sc_ab->sc_link == NULL)
panic("scsibusattach: can't allocate target links");
bzero(ab->sc_link, nbytes);
atapi_probe_bus(ab->sc_dev.dv_unit, -1);
memset(sc_ab->sc_link, 0, nbytes);
atapi_probe_bus(sc_ab->sc_dev.dv_unit, -1);
}
int
@ -203,8 +223,9 @@ atapi_probedev(atapi, target)
{
struct scsipi_link *sc_link;
struct scsipibus_attach_args sa;
struct atapi_identify ids;
struct atapi_identify *id = &ids;
struct ataparams ids;
struct ataparams *id = &ids;
struct ata_drive_datas *drvp = &atapi->sc_drvs[target];
struct cfdata *cf;
struct scsi_quirk_inquiry_pattern *finger;
int priority;
@ -214,23 +235,14 @@ atapi_probedev(atapi, target)
if (atapi->sc_link[target])
return;
if (wdc_atapi_get_params(atapi->adapter_link, target, id)) {
if (wdc_atapi_get_params(atapi->adapter_link, target,
SCSI_POLL|SCSI_NOSLEEP, id) == COMPLETE) {
#ifdef ATAPI_DEBUG_PROBE
printf("%s drive %d: cmdsz 0x%x drqtype 0x%x\n",
atapi->sc_dev.dv_xname, target,
id->config.cmd_drq_rem & ATAPI_PACKET_SIZE_MASK,
id->config.cmd_drq_rem & ATAPI_DRQ_MASK);
#endif
/*
* Shuffle string byte order.
* Mitsumi and NEC drives don't need this.
*/
if (((id->model[0] == 'N' && id->model[1] == 'E') ||
(id->model[0] == 'F' && id->model[1] == 'X')) == 0)
bswap(id->model, sizeof(id->model));
bswap(id->serial_number, sizeof(id->serial_number));
bswap(id->firmware_revision, sizeof(id->firmware_revision));
/*
* Allocate a device link and try and attach
* a driver to this device. If we fail, free
@ -250,25 +262,19 @@ atapi_probedev(atapi, target)
if (DEBUGTARGET == -1 || target == DEBUGTARGET)
sc_link->flags |= DEBUGLEVEL;
#endif /* SCSIDEBUG */
if (id->config.cmd_drq_rem & ATAPI_PACKET_SIZE_16)
if ((id->atap_config & ATAPI_CFG_CMD_MASK) == ATAPI_CFG_CMD_16)
sc_link->scsipi_atapi.cap |= ACAP_LEN;
sc_link->scsipi_atapi.cap |=
(id->config.cmd_drq_rem & ATAPI_DRQ_MASK) << 3;
#if 0
bcopy(id, &ad_link->id, sizeof(*id));
/* Fix strings and look through the quirk table. */
atapi_fixquirk(ad_link, id);
#endif
(id->atap_config & ATAPI_CFG_DRQ_MASK);
sa.sa_sc_link = sc_link;
sa.sa_inqbuf.type = id->config.device_type & SID_TYPE;
sa.sa_inqbuf.type = ATAPI_CFG_TYPE(id->atap_config);
sa.sa_inqbuf.removable =
id->config.cmd_drq_rem & ATAPI_REMOVABLE ?
T_REMOV : T_FIXED;
id->atap_config & ATAPI_CFG_REMOV ? T_REMOV : T_FIXED;
if (sa.sa_inqbuf.removable)
sc_link->flags |= SDEV_REMOVABLE;
scsipi_strvis(model, 40, id->model, 40);
scsipi_strvis(serial_number, 20, id->serial_number, 20);
scsipi_strvis(firmware_revision, 8, id->firmware_revision, 8);
scsipi_strvis(model, 40, id->atap_model, 40);
scsipi_strvis(serial_number, 20, id->atap_serial, 20);
scsipi_strvis(firmware_revision, 8, id->atap_revision, 8);
sa.sa_inqbuf.vendor = model;
sa.sa_inqbuf.product = serial_number;
sa.sa_inqbuf.revision = firmware_revision;
@ -284,7 +290,9 @@ atapi_probedev(atapi, target)
if ((cf = config_search(atapibussubmatch, &atapi->sc_dev,
&sa)) != 0) {
atapi->sc_link[target] = sc_link;
config_attach(&atapi->sc_dev, cf, &sa, atapibusprint);
drvp->drv_softc = config_attach(&atapi->sc_dev, cf,
&sa, atapibusprint);
wdc_probe_caps(drvp);
return;
} else {
atapibusprint(&sa, atapi->sc_dev.dv_xname);
@ -292,12 +300,6 @@ atapi_probedev(atapi, target)
free(sc_link, M_DEVBUF);
return;
}
#if 0 /* WAS: */
/* Try to find a match. */
if (config_found(self, ad_link, atapiprint) == NULL)
free(ad_link, M_DEVBUF);
#endif
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: atapiconf.h,v 1.6 1998/02/13 08:28:23 enami Exp $ */
/* $NetBSD: atapiconf.h,v 1.7 1998/10/12 16:09:24 bouyer Exp $ */
/*
* Copyright (c) 1996 Manuel Bouyer. All rights reserved.
@ -31,104 +31,18 @@
#include <dev/scsipi/scsipiconf.h>
struct atapi_identify {
struct config_s {
u_int8_t cmd_drq_rem;
#define ATAPI_PACKET_SIZE_MASK 0x03
#define ATAPI_PACKET_SIZE_12 0x00
#define ATAPI_PACKET_SIZE_16 0x01
/* drive states stored in ata_drive_datas */
#define PIOMODE 0
#define PIOMODE_WAIT 1
#define DMAMODE 2
#define DMAMODE_WAIT 3
#define READY 4
#define ATAPI_DRQ_MASK 0x60
#define ATAPI_MICROPROCESSOR_DRQ 0x00
#define ATAPI_INTERRUPT_DRQ 0x20
#define ATAPI_ACCELERATED_DRQ 0x40
struct atapi_mode_header;
struct ataparams;
#define ATAPI_REMOVABLE 0x80
u_int8_t device_type;
#define ATAPI_DEVICE_TYPE_MASK 0x1f
#define ATAPI_DEVICE_TYPE_DAD 0x00 /* direct access device */
/* 0x1-0x4 reserved */
#define ATAPI_DEVICE_TYPE_CD 0x05 /* CD-ROM */
/* 0x6 reserved */
#define ATAPI_DEVICE_TYPE_OMD 0x07 /* optical memory device */
/* 0x8-0x1e reserved */
#define ATAPI_DEVICE_TYPE_UNKNOWN 0x1f
#define ATAPI_GC_PROTOCOL_MASK 0xc0 /* mask of protocol bits */
/* 0x00 and 0x01 are ATA */
#define ATAPI_GC_PROTO_TYPE_ATAPI 0x80
#define ATAPI_GC_PROTO_TYPE_RESERVED 0xc0
} config; /* general configuration */
u_int8_t cylinders[2];
u_int8_t reserved1[2];
u_int8_t heads[2];
u_int8_t unf_bytes_per_track[2];
u_int8_t unf_bytes_per_sector[2];
u_int8_t sectors_per_track[2];
u_int8_t reserved2[6];
char serial_number[20];
u_int8_t buffer_type[2];
u_int8_t buffer_size[2];
u_int8_t ECC_bytes_available[2];
char firmware_revision[8];
char model[40];
u_int8_t sector_count[2];
u_int8_t double_word[2]; /* == 0 for CD-ROMs */
struct capabilities_s {
u_int8_t vendor;
u_int8_t capflags;
#define ATAPI_CAP_DMA 0x01 /* DMA supported */
#define ATAPI_CAP_LBA 0x02 /* LBA supported */
#define ATAPI_IORDY_DISABLE 0x04 /* IORDY can be disabled */
#define ATAPI_IORDY 0x08 /* IORDY supported */
} capabilities;
u_int8_t reserved3[2];
u_int8_t PIO_cycle_timing[2];
u_int8_t DMA_cycle_timing[2];
u_int8_t validity[2]; /* of words 54-58, 64-70 in this table */
#define ATAPI_VALID_FIRST 0x0 /* == 1 => words 54-58 are valid */
#define ATAPI_VALID_SECOND 0x1 /* == 1 => words 64-70 are valid */
u_int8_t current_chs[6]; /* cylinder/head/sector */
u_int8_t current_capacity[4];
u_int8_t reserved4[2];
u_int8_t user_addressable_sectors[4];
u_int8_t singleword_DMA_mode[2];
#define ATAPI_SW_DMA_MODE_AVAIL 0x00ff /* Mode 0 is supported */
#define ATAPI_SW_DMA_MODE_ACTIVE 0xff00 /* which mode is active */
u_int8_t multiword_DMA_mode[2];
#define ATAPI_MW_DMA_MODE_AVAIL 0x00ff /* Mode 0 is supported */
#define ATAPI_MW_DMA_MODE_ACTIVE 0xff00 /* which mode is active */
u_int8_t enhanced_PIO_mode[2];
#define ATAPI_ENHANCED_PIO_AVAIL 0x0001 /* PIO Mode 3 is supported */
u_int8_t blind_PIO_minimum_cycles[2];
u_int8_t mw_dma_tct[2]; /* multi-word DMA transfer cycle time */
u_int8_t min_PIO_tct_no_flow_control[2];
u_int8_t min_PIO_tct_with_flow_control[2];
u_int8_t reserved5[4];
u_int8_t reserved6[114];
u_int8_t vendor[64]; /* vendor unique */
u_int8_t reserved7[192];
};
struct atapibus_attach_args {
struct scsipi_link *sa_sc_link;
struct atapi_identify *sa_inqbuf;
};
int wdc_atapi_get_params __P((struct scsipi_link *, u_int8_t,
struct atapi_identify *));
int wdc_atapi_get_params __P((struct scsipi_link *, u_int8_t, int,
struct ataparams *));
void atapi_print_addr __P((struct scsipi_link *));
int atapi_interpret_sense __P((struct scsipi_xfer *));
int atapi_scsipi_cmd __P((struct scsipi_link *, struct scsipi_generic *,

View File

@ -1,4 +1,4 @@
# $NetBSD: files.scsipi,v 1.16 1998/07/30 00:49:19 mjacob Exp $
# $NetBSD: files.scsipi,v 1.17 1998/10/12 16:09:24 bouyer Exp $
#
# Config file and device description for machine-independent SCSI code.
# Included by ports that need it. Ports that use it must provide
@ -12,6 +12,7 @@ file dev/scsipi/scsipi_ioctl.c scsi | atapi
file dev/scsipi/scsi_base.c scsi
file dev/scsipi/scsi_verbose.c scsi & scsiverbose
file dev/scsipi/atapi_base.c atapi
file dev/scsipi/atapi_wdc.c atapi & wdc_base
device scsibus {target = -1, lun = -1}
attach scsibus at scsi

View File

@ -1,4 +1,4 @@
/* $NetBSD: scsipiconf.h,v 1.19 1998/10/10 00:36:13 thorpej Exp $ */
/* $NetBSD: scsipiconf.h,v 1.20 1998/10/12 16:09:25 bouyer Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -216,19 +216,17 @@ struct scsipi_link {
int max_target; /* XXX max target supported
by adapter */
} scsipi_scsi;
struct atapi_link { /* XXX this must be in sync
with wd_link */
u_int8_t type; /* 0 = ATA, 1 = ATAPI, from
wdlink.h */
struct atapi_link {
u_int8_t drive; /* drive number on the bus */
u_int8_t channel; /* channel, i.e. bus # on
controller */
u_int8_t drive; /* drive number on the bus */
u_int8_t atapibus;
u_int8_t cap; /* drive capability */
#define ACAP_DRQ_MPROC 0x0000 /* microprocessor DRQ */
#define ACAP_DRQ_INTR 0x0100 /* interrupt DRQ */
#define ACAP_DRQ_ACCEL 0x0200 /* accelerated DRQ */
#define ACAP_LEN 0x0400 /* 16 bit commands */
#define ACAP_DRQ_INTR 0x0200 /* interrupt DRQ */
#define ACAP_DRQ_ACCEL 0x0400 /* accelerated DRQ */
#define ACAP_DRQ_MASK 0x0600 /* same as in ataparams */
#define ACAP_LEN 0x0100 /* 16 bit commands */
} scsipi_atapi;
} _scsipi_link;
int (*scsipi_cmd) __P((struct scsipi_link *, struct scsipi_generic *,