diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-08-11 05:35:37 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-08-11 05:35:37 +0000 |
commit | e511a52691ddb2290f5d3c9ca6e9f0fc3b320289 (patch) | |
tree | f68510b774a71e2a0879cb013e3abd7a15665abc /sys/arch/sparc/dev | |
parent | fc98d7c9a0046f274410f903f952ef6224f68e10 (diff) |
netbsd port, now we merge our changes back in
Diffstat (limited to 'sys/arch/sparc/dev')
46 files changed, 5209 insertions, 3530 deletions
diff --git a/sys/arch/sparc/dev/amd7930.c b/sys/arch/sparc/dev/amd7930.c index c7a133e3eaf..d2af316243d 100644 --- a/sys/arch/sparc/dev/amd7930.c +++ b/sys/arch/sparc/dev/amd7930.c @@ -1,4 +1,4 @@ -/* $NetBSD: amd7930.c,v 1.2 1995/05/04 19:43:27 pk Exp $ */ +/* $NetBSD: amd7930.c,v 1.10 1996/03/31 22:38:29 pk Exp $ */ /* * Copyright (c) 1995 Rolf Grossmann @@ -69,7 +69,7 @@ struct amd7930_softc { int sc_open; /* single use device */ int sc_locked; /* true when transfering data */ struct mapreg sc_map; /* current contents of map registers */ - + u_char sc_rlevel; /* record level */ u_char sc_plevel; /* play level */ u_char sc_mlevel; /* monitor level */ @@ -83,7 +83,7 @@ struct amd7930_softc { /* sc_au is special in that the hardware interrupt handler uses it */ struct auio sc_au; /* recv and xmit buffers, etc */ -#define sc_intrcnt sc_au.au_intrcnt +#define sc_intrcnt sc_au.au_intrcnt /* statistics */ }; /* interrupt interfaces */ @@ -92,7 +92,6 @@ int amd7930hwintr __P((void *)); #define AUDIO_SET_SWINTR ienab_bis(IE_L4) #else struct auio *auiop; -extern void amd7930_trap(); #endif int amd7930swintr __P((void *)); @@ -101,12 +100,15 @@ void audio_setmap __P((volatile struct amd7930 *, struct mapreg *)); static void init_amd __P((volatile struct amd7930 *)); /* autoconfiguration driver */ -void amd9730attach __P((struct device *, struct device *, void *)); -int amd9730match __P((struct device *, void *, void *)); +void amd7930attach __P((struct device *, struct device *, void *)); +int amd7930match __P((struct device *, void *, void *)); + +struct cfattach audio_ca = { + sizeof(struct amd7930_softc), amd7930match, amd7930attach +}; -struct cfdriver audiocd = { - NULL, "audio", amd9730match, amd9730attach, - DV_DULL, sizeof(struct amd7930_softc) +struct cfdriver audio_cd = { + NULL, "audio", DV_DULL }; struct audio_device amd7930_device = { @@ -212,8 +214,10 @@ int amd7930_set_in_port __P((void *, int)); int amd7930_get_in_port __P((void *)); int amd7930_commit_settings __P((void *)); u_int amd7930_get_silence __P((int)); -int amd7930_start_output __P((void *, void *, int, void (*)(), void *)); -int amd7930_start_input __P((void *, void *, int, void (*)(), void *)); +int amd7930_start_output __P((void *, void *, int, void (*)(void *), + void *)); +int amd7930_start_input __P((void *, void *, int, void (*)(void *), + void *)); int amd7930_halt_output __P((void *)); int amd7930_halt_input __P((void *)); int amd7930_cont_output __P((void *)); @@ -268,7 +272,7 @@ struct audio_hw_if sa_hw_if = { /* autoconfig routines */ int -amd9730match(parent, vcf, aux) +amd7930match(parent, vcf, aux) struct device *parent; void *vcf, *aux; { @@ -276,7 +280,7 @@ amd9730match(parent, vcf, aux) register struct confargs *ca = aux; register struct romaux *ra = &ca->ca_ra; - if (cputyp==CPU_SUN4) + if (CPU_ISSUN4) return (0); return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0); } @@ -285,7 +289,7 @@ amd9730match(parent, vcf, aux) * Audio chip found. */ void -amd9730attach(parent, self, args) +amd7930attach(parent, self, args) struct device *parent, *self; void *args; { @@ -301,8 +305,9 @@ amd9730attach(parent, self, args) } pri = ra->ra_intr[0].int_pri; printf(" pri %d, softpri %d\n", pri, PIL_AUSOFT); - amd = (volatile struct amd7930 *)(ra->ra_vaddr ? ra->ra_vaddr : - mapiodev(ra->ra_reg, 0, sizeof (*amd), ca->ca_bustype)); + amd = (volatile struct amd7930 *)(ra->ra_vaddr ? + ra->ra_vaddr : mapiodev(ra->ra_reg, 0, sizeof (*amd), + ca->ca_bustype)); sc->sc_map.mr_mmr1 = AMD_MMR1_GX | AMD_MMR1_GER | AMD_MMR1_GR | AMD_MMR1_STG; @@ -312,7 +317,7 @@ amd9730attach(parent, self, args) sc->sc_plevel = 128; sc->sc_mlevel = 0; sc->sc_out_port = SUNAUDIO_SPEAKER; - + init_amd(amd); #ifndef AUDIO_C_HANDLER @@ -360,14 +365,13 @@ amd7930_open(dev, flags) int flags; { register struct amd7930_softc *sc; - register volatile struct amd7930 *amd; int unit = AUDIOUNIT(dev); DPRINTF(("sa_open: unit %d\n",unit)); - if (unit >= audiocd.cd_ndevs) + if (unit >= audio_cd.cd_ndevs) return (ENODEV); - if ((sc = audiocd.cd_devs[unit]) == NULL) + if ((sc = audio_cd.cd_devs[unit]) == NULL) return (ENXIO); if (sc->sc_open) return (EBUSY); @@ -410,7 +414,7 @@ amd7930_set_in_sr(addr, sr) { if (sr != 8000) return EINVAL; - + return(0); /* no other sampling rates supported by amd chip */ } @@ -463,7 +467,7 @@ amd7930_set_encoding(addr, enc) { if (enc != AUDIO_ENCODING_ULAW) return(EINVAL); - + return(0); /* no other encoding supported by amd chip */ } @@ -571,7 +575,7 @@ amd7930_commit_settings(addr) register struct mapreg *map; register volatile struct amd7930 *amd; register int s, level; - + DPRINTF(("sa_commit.\n")); map = &sc->sc_map; @@ -579,7 +583,7 @@ amd7930_commit_settings(addr) map->mr_gx = gx_coeff[sc->sc_rlevel]; map->mr_stgr = gx_coeff[sc->sc_mlevel]; - + level = (sc->sc_plevel * (256 + NGER)) >> 8; if (level >= 256) { map->mr_ger = ger_coeff[level - 256]; @@ -593,9 +597,9 @@ amd7930_commit_settings(addr) map->mr_mmr2 |= AMD_MMR2_LS; else map->mr_mmr2 &= ~AMD_MMR2_LS; - + s = splaudio(); - + amd->cr = AMDR_MAP_MMR1; amd->dr = map->mr_mmr1; amd->cr = AMDR_MAP_GX; @@ -625,7 +629,7 @@ amd7930_start_output(addr, p, cc, intr, arg) void *addr; void *p; int cc; - void (*intr)(); + void (*intr) __P((void *)); void *arg; { register struct amd7930_softc *sc = addr; @@ -657,7 +661,7 @@ amd7930_start_input(addr, p, cc, intr, arg) void *addr; void *p; int cc; - void (*intr)(); + void (*intr) __P((void *)); void *arg; { register struct amd7930_softc *sc = addr; @@ -760,7 +764,7 @@ amd7930_set_port(addr, cp) if (cp->type != AUDIO_MIXER_VALUE || cp->un.value.num_channels != 1) return(EINVAL); - + switch(cp->dev) { case SUNAUDIO_MIC_PORT: sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; @@ -790,7 +794,7 @@ amd7930_get_port(addr, cp) if (cp->type != AUDIO_MIXER_VALUE || cp->un.value.num_channels != 1) return(EINVAL); - + switch(cp->dev) { case SUNAUDIO_MIC_PORT: cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel; @@ -814,8 +818,6 @@ amd7930_query_devinfo(addr, dip) void *addr; register mixer_devinfo_t *dip; { - register struct amd7930_softc *sc = addr; - switch(dip->index) { case SUNAUDIO_MIC_PORT: dip->type = AUDIO_MIXER_VALUE; @@ -867,7 +869,7 @@ amd7930_query_devinfo(addr, dip) } DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name)); - + return(0); } @@ -913,7 +915,6 @@ amd7930hwintr(au0) } } - *(au->au_intrcnt)++; return (1); } #endif /* AUDIO_C_HANDLER */ diff --git a/sys/arch/sparc/dev/amd7930var.h b/sys/arch/sparc/dev/amd7930var.h index 0faaf75c41e..2d2e5f28257 100644 --- a/sys/arch/sparc/dev/amd7930var.h +++ b/sys/arch/sparc/dev/amd7930var.h @@ -1,4 +1,4 @@ -/* $NetBSD: amd7930var.h,v 1.2 1995/05/04 19:43:32 pk Exp $ */ +/* $NetBSD: amd7930var.h,v 1.3 1996/02/01 22:32:25 mycroft Exp $ */ /* * Copyright (c) 1992, 1993 @@ -44,7 +44,7 @@ * @(#)bsd_audiovar.h 8.1 (Berkeley) 6/11/93 */ -#ifndef LOCORE +#ifndef _LOCORE /* XXX I think these defines should go into some other header file */ #define SUNAUDIO_MIC_PORT 0 @@ -80,4 +80,4 @@ struct mapreg { u_char mr_mmr2; }; -#endif /* !LOCORE */ +#endif /* !_LOCORE */ diff --git a/sys/arch/sparc/dev/bt_subr.c b/sys/arch/sparc/dev/bt_subr.c index c7ba266d197..2a1df0ad71b 100644 --- a/sys/arch/sparc/dev/bt_subr.c +++ b/sys/arch/sparc/dev/bt_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: bt_subr.c,v 1.4 1994/11/20 20:51:54 deraadt Exp $ */ +/* $NetBSD: bt_subr.c,v 1.5 1996/03/14 19:44:32 christos Exp $ */ /* * Copyright (c) 1993 @@ -45,9 +45,12 @@ */ #include <sys/param.h> +#include <sys/systm.h> #include <sys/buf.h> #include <sys/errno.h> +#include <vm/vm.h> + #include <machine/fbio.h> #include <sparc/dev/btreg.h> diff --git a/sys/arch/sparc/dev/btreg.h b/sys/arch/sparc/dev/btreg.h index a1f4692da60..aa3f5fbc0db 100644 --- a/sys/arch/sparc/dev/btreg.h +++ b/sys/arch/sparc/dev/btreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: btreg.h,v 1.2 1994/11/20 20:51:55 deraadt Exp $ */ +/* $NetBSD: btreg.h,v 1.4 1996/02/27 22:09:21 thorpej Exp $ */ /* * Copyright (c) 1993 @@ -78,3 +78,63 @@ struct bt_regs { u_int bt_ctrl; /* control register */ u_int bt_omap; /* overlay (cursor) map register */ }; +#define BT_INIT(bt, shift) do { /* whatever this means.. */ \ + (bt)->bt_addr = 0x06 << (shift); /* command reg */ \ + (bt)->bt_ctrl = 0x73 << (shift); /* overlay plane */ \ + (bt)->bt_addr = 0x04 << (shift); /* read mask */ \ + (bt)->bt_ctrl = 0xff << (shift); /* color planes */ \ +} while(0) +#define BT_UNBLANK(bt, x, shift) do { \ + /* restore color 0 (and R of color 1) */ \ + (bt)->bt_addr = 0 << (shift); \ + (bt)->bt_cmap = (x); \ + if ((shift)) { \ + (bt)->bt_cmap = (x) << 8; \ + (bt)->bt_cmap = (x) << 16; \ + /* restore read mask */ \ + BT_INIT((bt), (shift)); \ +} while(0) +#define BT_BLANK(bt, shift) do { \ + (bt)->bt_addr = 0x06 << (shift); /* command reg */ \ + (bt)->bt_ctrl = 0x70 << (shift); /* overlay plane */ \ + (bt)->bt_addr = 0x04 << (shift); /* read mask */ \ + (bt)->bt_ctrl = 0x00 << (shift); /* color planes */ \ + /* Set color 0 to black -- note that this overwrites R of color 1. */\ + (bt)->bt_addr = 0 << (shift); \ + (bt)->bt_cmap = 0 << (shift); \ + /* restore read mask */ \ + BT_INIT((bt), (shift)); \ +} while(0) + + +/* + * Sbus framebuffer control look like this (usually at offset 0x400000). + */ +struct fbcontrol { + struct bt_regs fbc_dac; + u_char fbc_ctrl; + u_char fbc_status; + u_char fbc_cursor_start; + u_char fbc_cursor_end; + u_char fbc_vcontrol[12]; /* 12 bytes of video timing goo */ +}; +/* fbc_ctrl bits: */ +#define FBC_IENAB 0x80 /* Interrupt enable */ +#define FBC_VENAB 0x40 /* Video enable */ +#define FBC_TIMING 0x20 /* Master timing enable */ +#define FBC_CURSOR 0x10 /* Cursor compare enable */ +#define FBC_XTALMSK 0x0c /* Xtal select (0,1,2,test) */ +#define FBC_DIVMSK 0x03 /* Divisor (1,2,3,4) */ + +/* fbc_status bits: */ +#define FBS_INTR 0x80 /* Interrupt pending */ +#define FBS_MSENSE 0x70 /* Monitor sense mask */ +#define FBS_1024X768 0x10 +#define FBS_1152X900 0x30 +#define FBS_1280X1024 0x40 +#define FBS_1600X1280 0x50 +#define FBS_ID_MASK 0x0f /* ID mask */ +#define FBS_ID_COLOR 0x01 +#define FBS_ID_MONO 0x02 +#define FBS_ID_MONO_ECL 0x03 /* ? */ + diff --git a/sys/arch/sparc/dev/bwtwo.c b/sys/arch/sparc/dev/bwtwo.c index b024a82640a..78be5d0b885 100644 --- a/sys/arch/sparc/dev/bwtwo.c +++ b/sys/arch/sparc/dev/bwtwo.c @@ -1,35 +1,7 @@ -/* $NetBSD: bwtwo.c,v 1.15 1995/10/09 15:39:34 pk Exp $ */ +/* $NetBSD: bwtwo.c,v 1.26 1996/04/01 17:30:15 christos Exp $ */ /* - * Copyright (c) 1995 Theo de Raadt - * - * 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 under OpenBSD by - * Theo de Raadt. - * 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. - * + * Copyright (c) 1996 Jason R. Thorpe. All rights reserved. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * @@ -77,14 +49,19 @@ * black&white display (bwtwo) driver. * * Does not handle interrupts, even though they can occur. + * + * P4 and overlay plane support by Jason R. Thorpe <thorpej@NetBSD.ORG>. + * Overlay plane handling hints and ideas provided by Brad Spencer. */ #include <sys/param.h> +#include <sys/systm.h> #include <sys/device.h> #include <sys/ioctl.h> #include <sys/malloc.h> #include <sys/mman.h> #include <sys/tty.h> +#include <sys/conf.h> #include <vm/vm.h> @@ -92,25 +69,36 @@ #include <machine/autoconf.h> #include <machine/pmap.h> #include <machine/fbvar.h> -#if defined(SUN4) #include <machine/eeprom.h> #include <machine/ctlreg.h> +#include <machine/conf.h> #include <sparc/sparc/asm.h> -#endif +#include <sparc/dev/btreg.h> #include <sparc/dev/bwtworeg.h> -#include <sparc/dev/pfourreg.h> #include <sparc/dev/sbusvar.h> -#include "pfour.h" +#if defined(SUN4) +#include <sparc/dev/pfourreg.h> +#endif /* per-display variables */ struct bwtwo_softc { struct device sc_dev; /* base device */ struct sbusdev sc_sd; /* sbus device */ struct fbdevice sc_fb; /* frame buffer device */ - volatile struct bwtworeg *sc_reg;/* control registers */ - struct rom_reg sc_phys; /* display RAM (phys addr) */ - int sc_bustype; + volatile struct fbcontrol *sc_reg;/* control registers */ + struct rom_reg sc_phys; /* phys address description */ + int sc_bustype; /* type of bus we live on */ + int sc_pixeloffset; /* offset to framebuffer */ +#if defined(SUN4) + /* + * Additional overlay plane goo. + */ + int sc_ovtype; /* what kind of color fb? */ +#define BWO_NONE 0x00 +#define BWO_CGFOUR 0x01 +#define BWO_CGEIGHT 0x02 +#endif }; /* autoconfiguration driver */ @@ -121,20 +109,24 @@ int bwtwoclose __P((dev_t, int, int, struct proc *)); int bwtwoioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); int bwtwommap __P((dev_t, int, int)); static void bwtwounblank __P((struct device *)); +static void bwtwo_set_video __P((struct bwtwo_softc *, int)); +static int bwtwo_get_video __P((struct bwtwo_softc *)); + +struct cfattach bwtwo_ca = { + sizeof(struct bwtwo_softc), bwtwomatch, bwtwoattach +}; -struct cfdriver bwtwocd = { - NULL, "bwtwo", bwtwomatch, bwtwoattach, - DV_DULL, sizeof(struct bwtwo_softc) +struct cfdriver bwtwo_cd = { + NULL, "bwtwo", DV_DULL }; +/* XXX we do not handle frame buffer interrupts (do not know how) */ + /* frame buffer generic driver */ static struct fbdriver bwtwofbdriver = { bwtwounblank, bwtwoopen, bwtwoclose, bwtwoioctl, bwtwommap }; -static void bwtwoenable __P((struct bwtwo_softc *, int)); -static int bwtwostatus __P((struct bwtwo_softc *)); - extern int fbnode; extern struct tty *fbconstty; @@ -150,18 +142,48 @@ bwtwomatch(parent, vcf, aux) struct confargs *ca = aux; struct romaux *ra = &ca->ca_ra; + if (CPU_ISSUN4 && cf->cf_unit != 0) + return (0); + if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); + + /* + * Mask out invalid flags from the user. + */ + cf->cf_flags &= FB_USERMASK; + if (ca->ca_bustype == BUS_SBUS) return(1); -#if NPFOUR > 0 - if (ca->ca_bustype == BUS_PFOUR) { - if (PFOUR_ID(ra->ra_pfour) == PFOUR_ID_BW) - return (1); + + /* + * Make sure there's hardware there. + */ + if (probeget(ra->ra_vaddr, 4) == -1) return (0); + +#if defined(SUN4) + if (CPU_ISSUN4 && (ca->ca_bustype == BUS_OBIO)) { + /* + * Check for a pfour framebuffer. + */ + switch (fb_pfour_id(ra->ra_vaddr)) { + case PFOUR_ID_BW: + case PFOUR_ID_COLOR8P1: /* bwtwo in ... */ + case PFOUR_ID_COLOR24: /* ...overlay plane */ + cf->cf_flags |= FB_PFOUR; + /* FALLTHROUGH */ + + case PFOUR_NOTPFOUR: + return (1); + + default: + return (0); + } } #endif - return (probeget(ra->ra_vaddr, 4) != -1); + + return (0); } /* @@ -175,107 +197,180 @@ bwtwoattach(parent, self, args) register struct bwtwo_softc *sc = (struct bwtwo_softc *)self; register struct confargs *ca = args; register int node = ca->ca_ra.ra_node, ramsize; - int isconsole; - char *nam; + struct fbdevice *fb = &sc->sc_fb; + int isconsole = 0; + int sbus = 1; + char *nam = NULL; - sc->sc_fb.fb_driver = &bwtwofbdriver; - sc->sc_fb.fb_device = &sc->sc_dev; - sc->sc_fb.fb_type.fb_type = FBTYPE_SUN2BW; + fb->fb_driver = &bwtwofbdriver; + fb->fb_device = &sc->sc_dev; + fb->fb_type.fb_type = FBTYPE_SUN2BW; + fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags; + + /* + * Map the control register. + */ + if (fb->fb_flags & FB_PFOUR) { + fb->fb_pfour = + (volatile u_int32_t *)mapiodev(ca->ca_ra.ra_reg, 0, + sizeof(u_int32_t), ca->ca_bustype); + sc->sc_reg = NULL; + } else { + sc->sc_reg = + (volatile struct fbcontrol *)mapiodev(ca->ca_ra.ra_reg, + BWREG_REG, sizeof(struct fbcontrol), ca->ca_bustype); + fb->fb_pfour = NULL; + } + + /* Set up default pixel offset. May be changed below. */ + sc->sc_pixeloffset = BWREG_MEM; - sc->sc_bustype = ca->ca_bustype; switch (ca->ca_bustype) { -#if defined(SUN4) -#if NPFOUR > 0 - case BUS_PFOUR: - node = 0; - pfour_reset(); - pfour_videosize(ca->ca_ra.ra_pfour, - &sc->sc_fb.fb_type.fb_width, - &sc->sc_fb.fb_type.fb_height); - sc->sc_fb.fb_linebytes = sc->sc_fb.fb_type.fb_width / 8; - nam = "bwtwo"; - break; -#endif -#endif case BUS_OBIO: -#if defined(SUN4M) - if (cputyp == CPU_SUN4M) { /* 4m has framebuffer on obio */ - nam = getpropstring(node, "model"); - break; - } -#endif + if (CPU_ISSUN4M) /* 4m has framebuffer on obio */ + goto obp_name; + + sbus = node = 0; #if defined(SUN4) - node = 0; + if (fb->fb_flags & FB_PFOUR) { + nam = "bwtwo/p4"; + /* + * Notice if this is an overlay plane on a color + * framebuffer. Note that PFOUR_COLOR_OFF_OVERLAY + * is the same as PFOUR_BW_OFF, but we use the + * different names anyway. + */ + switch (PFOUR_ID(*fb->fb_pfour)) { + case PFOUR_ID_COLOR8P1: + sc->sc_ovtype = BWO_CGFOUR; + sc->sc_pixeloffset = PFOUR_COLOR_OFF_OVERLAY; + break; + + case PFOUR_ID_COLOR24: + sc->sc_ovtype = BWO_CGEIGHT; + sc->sc_pixeloffset = PFOUR_COLOR_OFF_OVERLAY; + break; + + default: + sc->sc_ovtype = BWO_NONE; + sc->sc_pixeloffset = PFOUR_BW_OFF; + break; + } + } else +#endif + nam = "bwtwo"; + break; + + case BUS_VME32: + case BUS_VME16: + sbus = node = 0; nam = "bwtwo"; break; -#endif + case BUS_SBUS: + obp_name: #if defined(SUN4C) || defined(SUN4M) nam = getpropstring(node, "model"); - break; #endif + break; } + sc->sc_phys = ca->ca_ra.ra_reg[0]; sc->sc_bustype = ca->ca_bustype; - sc->sc_fb.fb_type.fb_depth = 1; - fb_setsize(&sc->sc_fb, sc->sc_fb.fb_type.fb_depth, - 1152, 900, node, ca->ca_bustype); + fb->fb_type.fb_depth = 1; + fb_setsize(fb, fb->fb_type.fb_depth, 1152, 900, node, ca->ca_bustype); - ramsize = sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes; - sc->sc_fb.fb_type.fb_cmsize = 0; - sc->sc_fb.fb_type.fb_size = ramsize; + ramsize = fb->fb_type.fb_height * fb->fb_linebytes; + fb->fb_type.fb_cmsize = 0; + fb->fb_type.fb_size = ramsize; printf(": %s, %d x %d", nam, - sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height); + fb->fb_type.fb_width, fb->fb_type.fb_height); #if defined(SUN4) - if (cputyp == CPU_SUN4) { + if (CPU_ISSUN4) { struct eeprom *eep = (struct eeprom *)eeprom_va; + int constype = (fb->fb_flags & FB_PFOUR) ? EE_CONS_P4OPT : + EE_CONS_BW; /* * Assume this is the console if there's no eeprom info * to be found. */ - if (eep == NULL || eep->ee_diag.eed_console == EED_CONS_BW) + if (eep == NULL || eep->eeConsole == constype) isconsole = (fbconstty != NULL); else isconsole = 0; } #endif -#if defined(SUN4C) || defined(SUN4M) - if (cputyp == CPU_SUN4C || cputyp == CPU_SUN4M) + + if (CPU_ISSUN4COR4M) isconsole = node == fbnode && fbconstty != NULL; -#endif + /* * When the ROM has mapped in a bwtwo display, the address - * maps only the video RAM, so in any case we have to map the + * maps only the video RAM, hence we always map the control * registers ourselves. We only need the video RAM if we are * going to print characters via rconsole. */ - if ((sc->sc_fb.fb_pixels = ca->ca_ra.ra_vaddr) == NULL && isconsole) { + if ((fb->fb_pixels = ca->ca_ra.ra_vaddr) == NULL && isconsole) { /* this probably cannot happen (on sun4c), but what the heck */ - sc->sc_fb.fb_pixels = mapiodev(ca->ca_ra.ra_reg, BWREG_MEM, + fb->fb_pixels = + mapiodev(ca->ca_ra.ra_reg, sc->sc_pixeloffset, ramsize, ca->ca_bustype); } - sc->sc_reg = (volatile struct bwtworeg *)mapiodev(ca->ca_ra.ra_reg, - BWREG_REG, sizeof(struct bwtworeg), ca->ca_bustype); /* Insure video is enabled */ - bwtwoenable(sc, 1); + bwtwo_set_video(sc, 1); if (isconsole) { printf(" (console)\n"); #ifdef RASTERCONSOLE - fbrcons_init(&sc->sc_fb); + fbrcons_init(fb); #endif } else printf("\n"); + #if defined(SUN4C) || defined(SUN4M) - if (ca->ca_bustype == BUS_SBUS) + if (sbus) sbus_establish(&sc->sc_sd, &sc->sc_dev); #endif - if ((node == fbnode && cputyp != CPU_SUN4) || - (isconsole && cputyp == CPU_SUN4)) - fb_attach(&sc->sc_fb); + +#if defined(SUN4) + if ((fb->fb_flags & FB_PFOUR) && (sc->sc_ovtype != BWO_NONE)) { + char *ovnam; + + switch (sc->sc_ovtype) { + case BWO_CGFOUR: + ovnam = "cgfour"; + break; + + case BWO_CGEIGHT: + ovnam = "cgeight"; + break; + + default: + ovnam = "unknown"; + break; + } + printf("%s: %s overlay plane\n", sc->sc_dev.dv_xname, ovnam); + } +#endif + + if (CPU_ISSUN4 || node == fbnode) { +#if defined(SUN4) + /* + * If we're on an overlay plane of a color framebuffer, + * then we don't force the issue in fb_attach() because + * we'd like the color framebuffer to actually be the + * "console framebuffer". We're only around to speed + * up rconsole. + */ + if ((fb->fb_flags & FB_PFOUR) && (sc->sc_ovtype != BWO_NONE )) + fb_attach(fb, 0); + else +#endif + fb_attach(fb, isconsole); + } } int @@ -286,8 +381,9 @@ bwtwoopen(dev, flags, mode, p) { int unit = minor(dev); - if (unit >= bwtwocd.cd_ndevs || bwtwocd.cd_devs[unit] == NULL) + if (unit >= bwtwo_cd.cd_ndevs || bwtwo_cd.cd_devs[unit] == NULL) return (ENXIO); + return (0); } @@ -309,7 +405,7 @@ bwtwoioctl(dev, cmd, data, flags, p) int flags; struct proc *p; { - struct bwtwo_softc *sc = bwtwocd.cd_devs[minor(dev)]; + struct bwtwo_softc *sc = bwtwo_cd.cd_devs[minor(dev)]; switch (cmd) { @@ -318,11 +414,11 @@ bwtwoioctl(dev, cmd, data, flags, p) break; case FBIOGVIDEO: - bwtwostatus(sc); + *(int *)data = bwtwo_get_video(sc); break; case FBIOSVIDEO: - bwtwoenable(sc, *(int *)data); + bwtwo_set_video(sc, (*(int *)data)); break; default: @@ -337,7 +433,7 @@ bwtwounblank(dev) { struct bwtwo_softc *sc = (struct bwtwo_softc *)dev; - bwtwoenable(sc, 1); + bwtwo_set_video(sc, 1); } /* @@ -349,7 +445,7 @@ bwtwommap(dev, off, prot) dev_t dev; int off, prot; { - register struct bwtwo_softc *sc = bwtwocd.cd_devs[minor(dev)]; + register struct bwtwo_softc *sc = bwtwo_cd.cd_devs[minor(dev)]; if (off & PGOFSET) panic("bwtwommap"); @@ -359,55 +455,59 @@ bwtwommap(dev, off, prot) * I turned on PMAP_NC here to disable the cache as I was * getting horribly broken behaviour with it on. */ - return (REG2PHYS(&sc->sc_phys, BWREG_MEM+off, sc->sc_bustype) | PMAP_NC); + return (REG2PHYS(&sc->sc_phys, sc->sc_pixeloffset + off, + sc->sc_bustype) | PMAP_NC); } - -int -bwtwostatus(sc) +static int +bwtwo_get_video(sc) struct bwtwo_softc *sc; { -#ifdef SUN4 -#if NPFOUR > 0 - if (sc->sc_bustype == BUS_PFOUR) - return pfourstatus(); -#endif - if (sc->sc_bustype == BUS_OBIO) - return (lduba(AC_SYSENABLE, ASI_CONTROL) & SYSEN_VIDEO); -#endif -#if defined(SUN4C) || defined(SUN4M) - return (sc->sc_reg->bw_ctl & CTL_VE); + +#if defined(SUN4) + if (CPU_ISSUN4 && (sc->sc_bustype == BUS_OBIO)) { + if (sc->sc_fb.fb_flags & FB_PFOUR) { + /* + * This handles the overlay plane case, too. + */ + return (fb_pfour_get_video(&sc->sc_fb)); + } else + return ((lduba(AC_SYSENABLE, + ASI_CONTROL) & SYSEN_VIDEO) != 0); + } #endif + + return ((sc->sc_reg->fbc_ctrl & FBC_VENAB) != 0); } -void -bwtwoenable(sc, on) +static void +bwtwo_set_video(sc, enable) struct bwtwo_softc *sc; - int on; + int enable; { -#if NPFOUR > 0 - if (sc->sc_bustype == BUS_PFOUR) { - pfourenable(on); + +#if defined(SUN4) + if (CPU_ISSUN4 && (sc->sc_bustype == BUS_OBIO)) { + if (sc->sc_fb.fb_flags & FB_PFOUR) { + /* + * This handles the overlay plane case, too. + */ + fb_pfour_set_video(&sc->sc_fb, enable); return; } -#endif - if (on) { -#ifdef SUN4 - if (sc->sc_bustype == BUS_OBIO) { + if (enable) stba(AC_SYSENABLE, ASI_CONTROL, lduba(AC_SYSENABLE, ASI_CONTROL) | SYSEN_VIDEO); - return; - } -#endif - sc->sc_reg->bw_ctl |= CTL_VE; - } else { -#ifdef SUN4 - if (sc->sc_bustype == BUS_OBIO) { + else stba(AC_SYSENABLE, ASI_CONTROL, lduba(AC_SYSENABLE, ASI_CONTROL) & ~SYSEN_VIDEO); - return; - } -#endif - sc->sc_reg->bw_ctl &= ~CTL_VE; + + return; } +#endif + + if (enable) + sc->sc_reg->fbc_ctrl |= FBC_VENAB; + else + sc->sc_reg->fbc_ctrl &= ~FBC_VENAB; } diff --git a/sys/arch/sparc/dev/bwtworeg.h b/sys/arch/sparc/dev/bwtworeg.h index cae902991a8..236f4a44929 100644 --- a/sys/arch/sparc/dev/bwtworeg.h +++ b/sys/arch/sparc/dev/bwtworeg.h @@ -1,4 +1,4 @@ -/* $NetBSD: bwtworeg.h,v 1.2 1994/11/20 20:51:58 deraadt Exp $ */ +/* $NetBSD: bwtworeg.h,v 1.3 1996/02/27 00:32:39 pk Exp $ */ /* * Copyright (c) 1992, 1993 @@ -53,20 +53,9 @@ * the sparc addressing modes work well. */ struct bwtworeg { - /* - * The xxx0 range is all 0xff on my IPC but causes a screen glitch - * on my SS1+, so it must do *some*thing... the xxx1 range is full - * of values but I do not know what they are. bw_ctl changes for - * a blanked screen. - */ - char bw_xxx0[16]; - u_char bw_ctl; /* contains video enable */ - char bw_xxx1[15]; + struct fbcontrol bw_fbc; }; -/* bits in bw_ctl */ -#define CTL_VE 0x40 /* video enable */ - /* offsets */ #define BWREG_ID 0 #define BWREG_REG 0x400000 @@ -76,7 +65,7 @@ struct bwtworeg { struct bwtwo_all { long ba_id; /* ID = 0xfe010104 on my IPC */ char ba_xxx0[0x400000-4]; - struct bwtworeg ba_reg; /* control registers */ + struct fbcontrol ba_reg; /* control registers */ char ba_xxx1[0x400000-32]; char ba_ram[4096]; /* actually larger */ }; diff --git a/sys/arch/sparc/dev/cgeight.c b/sys/arch/sparc/dev/cgeight.c index 546a6992797..aea11563608 100644 --- a/sys/arch/sparc/dev/cgeight.c +++ b/sys/arch/sparc/dev/cgeight.c @@ -1,6 +1,7 @@ -/* $NetBSD: cgeight.c,v 1.12 1994/11/23 07:02:07 deraadt Exp $ */ +/* $NetBSD: cgeight.c,v 1.7 1996/04/01 17:29:57 christos Exp $ */ /* + * Copyright (c) 1996 Jason R. Thorpe. All rights reserved. * Copyright (c) 1995 Theo de Raadt * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. @@ -54,12 +55,14 @@ */ #include <sys/param.h> +#include <sys/systm.h> #include <sys/buf.h> #include <sys/device.h> #include <sys/ioctl.h> #include <sys/malloc.h> #include <sys/mman.h> #include <sys/tty.h> +#include <sys/conf.h> #include <vm/vm.h> @@ -67,20 +70,20 @@ #include <machine/autoconf.h> #include <machine/pmap.h> #include <machine/fbvar.h> +#include <machine/eeprom.h> +#include <machine/conf.h> #include <sparc/dev/btreg.h> #include <sparc/dev/btvar.h> -#include <sparc/dev/cgeightreg.h> #include <sparc/dev/pfourreg.h> /* per-display variables */ struct cgeight_softc { struct device sc_dev; /* base device */ struct fbdevice sc_fb; /* frame buffer device */ - volatile struct bt_regs *sc_bt; /* Brooktree registers */ struct rom_reg sc_phys; /* display RAM (phys addr) */ + volatile struct fbcontrol *sc_fbc; /* Brooktree registers */ int sc_bustype; /* type of bus we live on */ - int sc_blanked; /* true if blanked */ union bt_cmap sc_cmap; /* Brooktree color map */ }; @@ -91,13 +94,19 @@ int cgeightopen __P((dev_t, int, int, struct proc *)); int cgeightclose __P((dev_t, int, int, struct proc *)); int cgeightioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); int cgeightmmap __P((dev_t, int, int)); +#if defined(SUN4) static void cgeightunblank __P((struct device *)); +#endif + +struct cfattach cgeight_ca = { + sizeof(struct cgeight_softc), cgeightmatch, cgeightattach +}; -struct cfdriver cgeightcd = { - NULL, "cgeight", cgeightmatch, cgeightattach, - DV_DULL, sizeof(struct cgeight_softc) +struct cfdriver cgeight_cd = { + NULL, "cgeight", DV_DULL }; +#if defined(SUN4) /* frame buffer generic driver */ static struct fbdriver cgeightfbdriver = { cgeightunblank, cgeightopen, cgeightclose, cgeightioctl, cgeightmmap @@ -107,6 +116,9 @@ extern int fbnode; extern struct tty *fbconstty; static void cgeightloadcmap __P((struct cgeight_softc *, int, int)); +static int cgeight_get_video __P((struct cgeight_softc *)); +static void cgeight_set_video __P((struct cgeight_softc *, int)); +#endif /* * Match a cgeight. @@ -122,8 +134,40 @@ cgeightmatch(parent, vcf, aux) if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); - if (PFOUR_ID(ra->ra_pfour) == PFOUR_ID_COLOR24) + + /* + * Mask out invalid flags from the user. + */ + cf->cf_flags &= FB_USERMASK; + + /* + * Only exists on a sun4. + */ + if (!CPU_ISSUN4) + return (0); + + /* + * Only exists on obio. + */ + if (ca->ca_bustype != BUS_OBIO) + return (0); + + /* + * Make sure there's hardware there. + */ + if (probeget(ra->ra_vaddr, 4) == -1) + return (0); + +#if defined(SUN4) + /* + * Check the pfour register. + */ + if (fb_pfour_id(ra->ra_vaddr) == PFOUR_ID_COLOR24) { + cf->cf_flags |= FB_PFOUR; return (1); + } +#endif + return (0); } @@ -135,99 +179,115 @@ cgeightattach(parent, self, args) struct device *parent, *self; void *args; { +#if defined(SUN4) register struct cgeight_softc *sc = (struct cgeight_softc *)self; register struct confargs *ca = args; register int node = 0, ramsize, i; register volatile struct bt_regs *bt; - register struct cgeight_all *p; + struct fbdevice *fb = &sc->sc_fb; int isconsole; -#ifdef RASTERCONSOLE - struct fbdevice fbd; -#endif - sc->sc_fb.fb_driver = &cgeightfbdriver; - sc->sc_fb.fb_device = &sc->sc_dev; - sc->sc_fb.fb_type.fb_type = FBTYPE_MEMCOLOR; + fb->fb_driver = &cgeightfbdriver; + fb->fb_device = &sc->sc_dev; + fb->fb_type.fb_type = FBTYPE_MEMCOLOR; + fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags; + + /* + * Only pfour cgfours, thank you... + */ + if ((ca->ca_bustype != BUS_OBIO) || + ((fb->fb_flags & FB_PFOUR) == 0)) { + printf("%s: ignoring; not a pfour\n", sc->sc_dev.dv_xname); + return; + } - pfour_reset(); - pfour_videosize(ca->ca_ra.ra_pfour, &sc->sc_fb.fb_type.fb_width, - &sc->sc_fb.fb_type.fb_height); + /* Map the pfour register. */ + fb->fb_pfour = (volatile u_int32_t *)mapiodev(ca->ca_ra.ra_reg, 0, + sizeof(u_int32_t), ca->ca_bustype); - sc->sc_fb.fb_linebytes = sc->sc_fb.fb_type.fb_width * 4; + ramsize = PFOUR_COLOR_OFF_END - PFOUR_COLOR_OFF_OVERLAY; + + fb->fb_type.fb_depth = 24; + fb_setsize(fb, fb->fb_type.fb_depth, 1152, 900, node, ca->ca_bustype); - ramsize = CG8REG_END - CG8REG_OVERLAY; - sc->sc_fb.fb_type.fb_depth = 24; sc->sc_fb.fb_type.fb_cmsize = 256; sc->sc_fb.fb_type.fb_size = ramsize; - printf(": %d x %d", sc->sc_fb.fb_type.fb_width, - sc->sc_fb.fb_type.fb_height); + printf(": cgeight/p4, %d x %d", fb->fb_type.fb_width, + fb->fb_type.fb_height); + + isconsole = 0; + + if (cputyp == CPU_SUN4) { + struct eeprom *eep = (struct eeprom *)eeprom_va; + + /* + * Assume this is the console if there's no eeprom info + * to be found. + */ + if (eep == NULL || eep->eeConsole == EE_CONS_P4OPT) + isconsole = (fbconstty != NULL); + } + +#if 0 + /* + * We don't do any of the console handling here. Instead, + * we let the bwtwo driver pick up the overlay plane and + * use it instead. Rconsole should have better performance + * with the 1-bit depth. + * -- Jason R. Thorpe <thorpej@NetBSD.ORG> + */ /* - * When the ROM has mapped in a cgeight display, the address + * When the ROM has mapped in a cgfour display, the address * maps only the video RAM, so in any case we have to map the * registers ourselves. We only need the video RAM if we are * going to print characters via rconsole. - * - * XXX: it is insane to map the full 0x800000 space, when - * the mmap code down below doesn't want it that way. - * Ridiculous! */ - isconsole = node == fbnode && fbconstty != NULL; - if (ca->ca_ra.ra_vaddr == NULL) { - /* this probably cannot happen, but what the heck */ - ca->ca_ra.ra_vaddr = mapiodev(ca->ca_ra.ra_reg, 0, - ramsize, ca->ca_bustype); + + if (isconsole) { + /* XXX this is kind of a waste */ + fb->fb_pixels = mapiodev(ca->ca_ra.ra_reg, + PFOUR_COLOR_OFF_OVERLAY, ramsize, ca->ca_bustype); } - sc->sc_fb.fb_pixels = (char *)((int)ca->ca_ra.ra_vaddr + - CG8REG_COLOUR - CG8REG_OVERLAY); +#endif + + /* Map the Brooktree. */ + sc->sc_fbc = (volatile struct fbcontrol *)mapiodev(ca->ca_ra.ra_reg, + PFOUR_COLOR_OFF_CMAP, sizeof(struct fbcontrol), ca->ca_bustype); -#define O(memb) ((u_int)(&((struct cgeight_all *)0)->memb)) - sc->sc_bt = bt = (volatile struct bt_regs *)mapiodev(ca->ca_ra.ra_reg, - O(ba_btreg), sizeof(struct bt_regs), ca->ca_bustype); sc->sc_phys = ca->ca_ra.ra_reg[0]; sc->sc_bustype = ca->ca_bustype; +#if 0 /* XXX thorpej ??? */ /* tell the enable plane to look at the mono image */ memset(ca->ca_ra.ra_vaddr, 0xff, sc->sc_fb.fb_type.fb_width * sc->sc_fb.fb_type.fb_height / 8); -#if 0 - memset((caddr_t)((int)ca->ca_ra.ra_vaddr + - CG8REG_ENABLE - CG8REG_OVERLAY), 0x00, - sc->sc_fb.fb_type.fb_width * sc->sc_fb.fb_type.fb_height / 8); #endif /* grab initial (current) color map */ + bt = &sc->sc_fbc->fbc_dac; bt->bt_addr = 0; for (i = 0; i < 256 * 3 / 4; i++) sc->sc_cmap.cm_chip[i] = bt->bt_cmap; - /* make sure we are not blanked (see cgeightunblank) */ - bt->bt_addr = 0x06; /* command reg */ - bt->bt_ctrl = 0x73; /* overlay plane */ - bt->bt_addr = 0x04; /* read mask */ - bt->bt_ctrl = 0xff; /* color planes */ + BT_INIT(bt, 0); + +#if 0 /* see above */ if (isconsole) { printf(" (console)\n"); -#ifdef RASTERCONSOLE - /* - * Like SunOS and the bootrom, we want to do full-screen - * text on the overlay plane. But rcons_init() requires - * our fbdevice pointer to remain the same; so we hack - * the fbdevice, pass it in, and then restore it's - * values. Ugly -- should change rcons_init()'s interface. - */ - bcopy(&sc->sc_fb, &fbd, sizeof fbd); - sc->sc_fb.fb_type.fb_depth = 1; - sc->sc_fb.fb_linebytes = sc->sc_fb.fb_type.fb_width / 8; - sc->sc_fb.fb_pixels = ca->ca_ra.ra_vaddr; - rcons_init(&fbd); - bcopy(&fbd, &sc->sc_fb, sizeof fbd); +#if defined(RASTERCONSOLE) && 0 /* XXX been told it doesn't work well. */ + fbrcons_init(fb); #endif } else +#endif /* 0 */ printf("\n"); - if ((node == fbnode && cputyp != CPU_SUN4) || - (isconsole && cputyp == CPU_SUN4)) - fb_attach(&sc->sc_fb); + + /* + * Even though we're not using rconsole, we'd still like + * to notice if we're the console framebuffer. + */ + fb_attach(&sc->sc_fb, isconsole); +#endif } int @@ -238,7 +298,7 @@ cgeightopen(dev, flags, mode, p) { int unit = minor(dev); - if (unit >= cgeightcd.cd_ndevs || cgeightcd.cd_devs[unit] == NULL) + if (unit >= cgeight_cd.cd_ndevs || cgeight_cd.cd_devs[unit] == NULL) return (ENXIO); return (0); } @@ -261,7 +321,8 @@ cgeightioctl(dev, cmd, data, flags, p) int flags; struct proc *p; { - register struct cgeight_softc *sc = cgeightcd.cd_devs[minor(dev)]; +#if defined(SUN4) + register struct cgeight_softc *sc = cgeight_cd.cd_devs[minor(dev)]; register struct fbgattr *fba; int error; @@ -299,83 +360,21 @@ cgeightioctl(dev, cmd, data, flags, p) break; case FBIOGVIDEO: - *(int *)data = sc->sc_blanked; + *(int *)data = cgeight_get_video(sc); break; case FBIOSVIDEO: - if (*(int *)data) - cgeightunblank(&sc->sc_dev); - else if (!sc->sc_blanked) { - register volatile struct bt_regs *bt; - - bt = sc->sc_bt; - bt->bt_addr = 0x06; /* command reg */ - bt->bt_ctrl = 0x70; /* overlay plane */ - bt->bt_addr = 0x04; /* read mask */ - bt->bt_ctrl = 0x00; /* color planes */ - /* - * Set color 0 to black -- note that this overwrites - * R of color 1. - */ - bt->bt_addr = 0; - bt->bt_cmap = 0; - - sc->sc_blanked = 1; - } + cgeight_set_video(sc, *(int *)data); break; default: return (ENOTTY); } +#endif return (0); } /* - * Undo the effect of an FBIOSVIDEO that turns the video off. - */ -static void -cgeightunblank(dev) - struct device *dev; -{ - struct cgeight_softc *sc = (struct cgeight_softc *)dev; - register volatile struct bt_regs *bt; - - if (sc->sc_blanked) { - sc->sc_blanked = 0; - bt = sc->sc_bt; - /* restore color 0 (and R of color 1) */ - bt->bt_addr = 0; - bt->bt_cmap = sc->sc_cmap.cm_chip[0]; - - /* restore read mask */ - bt->bt_addr = 0x06; /* command reg */ - bt->bt_ctrl = 0x73; /* overlay plane */ - bt->bt_addr = 0x04; /* read mask */ - bt->bt_ctrl = 0xff; /* color planes */ - } -} - -/* - * Load a subset of the current (new) colormap into the Brooktree DAC. - */ -static void -cgeightloadcmap(sc, start, ncolors) - register struct cgeight_softc *sc; - register int start, ncolors; -{ - register volatile struct bt_regs *bt; - register u_int *ip; - register int count; - - ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ - count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; - bt = sc->sc_bt; - bt->bt_addr = BT_D4M4(start); - while (--count >= 0) - bt->bt_cmap = *ip++; -} - -/* * Return the address that would map the given device at the given * offset, allowing for the given protection, or return -1 for error. * @@ -389,14 +388,14 @@ cgeightmmap(dev, off, prot) dev_t dev; int off, prot; { - register struct cgeight_softc *sc = cgeightcd.cd_devs[minor(dev)]; + register struct cgeight_softc *sc = cgeight_cd.cd_devs[minor(dev)]; int poff; #define START_ENABLE (128*1024) -#define START_COLOUR (128*1024 + 128*1024) -#define COLOUR_SIZE (sc->sc_fb.fb_type.fb_width * \ - sc->sc_fb.fb_type.fb_height * 4) -#define END_COLOUR (START_COLOUR + COLOUR_SIZE) +#define START_COLOR ((128*1024) + (128*1024)) +#define COLOR_SIZE (sc->sc_fb.fb_type.fb_width * \ + sc->sc_fb.fb_type.fb_height * 3) +#define END_COLOR (START_COLOR + COLOR_SIZE) #define START_SPECIAL 0x800000 #define PROMSIZE 0x40000 #define NOOVERLAY (0x04000000) @@ -405,36 +404,108 @@ cgeightmmap(dev, off, prot) panic("cgeightmap"); if ((u_int)off >= NOOVERLAY) { - off = off - NOOVERLAY; + off =- NOOVERLAY; /* * X11 maps a huge chunk of the frame buffer; far more than * there really is. We compensate by double-mapping the * first page for as many other pages as it wants */ - while (off >= COLOUR_SIZE) - off = 0; - poff = off + (CG8REG_COLOUR - CG8REG_OVERLAY); - } else if ((u_int)off < START_ENABLE) /* in overlay plane */ - poff = off; - else if ((u_int)off < START_COLOUR) /* in enable plane */ - poff = off + (CG8REG_ENABLE - CG8REG_OVERLAY) - START_ENABLE; - else if ((u_int)off < END_COLOUR) /* in colour plane */ - poff = off + (CG8REG_COLOUR - CG8REG_OVERLAY) - START_COLOUR; - else if ((u_int)off < START_SPECIAL) /* hole */ + while (off >= COLOR_SIZE) + off -= COLOR_SIZE; /* XXX thorpej ??? */ + + poff = off + PFOUR_COLOR_OFF_COLOR; + } else if ((u_int)off < START_ENABLE) { + /* + * in overlay plane + */ + poff = PFOUR_COLOR_OFF_OVERLAY + off; + } else if ((u_int)off < START_COLOR) { + /* + * in enable plane + */ + poff = (off - START_ENABLE) + PFOUR_COLOR_OFF_ENABLE; + } else if ((u_int)off < END_COLOR) { + /* + * in colour plane + */ + poff = (off - START_COLOR) + PFOUR_COLOR_OFF_COLOR; + } else if ((u_int)off < START_SPECIAL) { + /* + * hole + */ + poff = 0; /* XXX */ + } else if ((u_int)off == START_SPECIAL) { + /* + * colour map (Brooktree) + */ + poff = PFOUR_COLOR_OFF_CMAP; + } else if ((u_int)off == START_SPECIAL + NBPG) { + /* + * p4 register + */ poff = 0; - else if ((u_int)off == START_SPECIAL) /* colour map */ - poff = CG8REG_CMAP; - else if ((u_int)off == START_SPECIAL + NBPG) /* p4 register */ - poff = PFOUR_REG; - else if ((u_int)off > START_SPECIAL + NBPG*2 && - (u_int) off < START_SPECIAL + NBPG*2 + PROMSIZE) /* rom */ - poff = CG8REG_P4REG + 0x8000 + off - START_SPECIAL + NBPG*2; - else + } else if ((u_int)off > (START_SPECIAL + (NBPG * 2)) && + (u_int) off < (START_SPECIAL + (NBPG * 2) + PROMSIZE)) { + /* + * rom + */ + poff = 0x8000 + (off - (START_SPECIAL + (NBPG * 2))); + } else return (-1); /* * I turned on PMAP_NC here to disable the cache as I was * getting horribly broken behaviour with it on. */ - return (REG2PHYS(&sc->sc_phys, off, sc->sc_bustype) | PMAP_NC); + return (REG2PHYS(&sc->sc_phys, poff, sc->sc_bustype) | PMAP_NC); +} + +#if defined(SUN4) +/* + * Undo the effect of an FBIOSVIDEO that turns the video off. + */ +static void +cgeightunblank(dev) + struct device *dev; +{ + + cgeight_set_video((struct cgeight_softc *)dev, 1); +} + +static int +cgeight_get_video(sc) + struct cgeight_softc *sc; +{ + + return (fb_pfour_get_video(&sc->sc_fb)); } + +static void +cgeight_set_video(sc, enable) + struct cgeight_softc *sc; + int enable; +{ + + fb_pfour_set_video(&sc->sc_fb, enable); +} + +/* + * Load a subset of the current (new) colormap into the Brooktree DAC. + */ +static void +cgeightloadcmap(sc, start, ncolors) + register struct cgeight_softc *sc; + register int start, ncolors; +{ + register volatile struct bt_regs *bt; + register u_int *ip; + register int count; + + ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ + count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; + bt = &sc->sc_fbc->fbc_dac; + bt->bt_addr = BT_D4M4(start); + while (--count >= 0) + bt->bt_cmap = *ip++; +} +#endif diff --git a/sys/arch/sparc/dev/cgfour.c b/sys/arch/sparc/dev/cgfour.c index ebd6b1fecd7..d5dde467a9c 100644 --- a/sys/arch/sparc/dev/cgfour.c +++ b/sys/arch/sparc/dev/cgfour.c @@ -1,6 +1,7 @@ -/* $NetBSD: cgfour.c,v 1.12 1994/11/23 07:02:07 deraadt Exp $ */ +/* $NetBSD: cgfour.c,v 1.7 1996/04/01 17:29:58 christos Exp $ */ /* + * Copyright (c) 1996 Jason R. Thorpe. All rights reserved. * Copyright (c) 1995 Theo de Raadt. All rights reserved. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. @@ -58,12 +59,14 @@ */ #include <sys/param.h> +#include <sys/systm.h> #include <sys/buf.h> #include <sys/device.h> #include <sys/ioctl.h> #include <sys/malloc.h> #include <sys/mman.h> #include <sys/tty.h> +#include <sys/conf.h> #include <vm/vm.h> @@ -71,20 +74,20 @@ #include <machine/autoconf.h> #include <machine/pmap.h> #include <machine/fbvar.h> +#include <machine/eeprom.h> +#include <machine/conf.h> #include <sparc/dev/btreg.h> #include <sparc/dev/btvar.h> -#include <sparc/dev/cgfourreg.h> #include <sparc/dev/pfourreg.h> /* per-display variables */ struct cgfour_softc { struct device sc_dev; /* base device */ struct fbdevice sc_fb; /* frame buffer device */ - volatile struct bt_regs *sc_bt; /* Brooktree registers */ struct rom_reg sc_phys; /* display RAM (phys addr) */ + volatile struct fbcontrol *sc_fbc; /* Brooktree registers */ int sc_bustype; /* type of bus we live on */ - int sc_blanked; /* true if blanked */ union bt_cmap sc_cmap; /* Brooktree color map */ }; @@ -95,13 +98,19 @@ int cgfouropen __P((dev_t, int, int, struct proc *)); int cgfourclose __P((dev_t, int, int, struct proc *)); int cgfourioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); int cgfourmmap __P((dev_t, int, int)); +#if defined(SUN4) static void cgfourunblank __P((struct device *)); +#endif + +struct cfattach cgfour_ca = { + sizeof(struct cgfour_softc), cgfourmatch, cgfourattach +}; -struct cfdriver cgfourcd = { - NULL, "cgfour", cgfourmatch, cgfourattach, - DV_DULL, sizeof(struct cgfour_softc) +struct cfdriver cgfour_cd = { + NULL, "cgfour", DV_DULL }; +#if defined(SUN4) /* frame buffer generic driver */ static struct fbdriver cgfourfbdriver = { cgfourunblank, cgfouropen, cgfourclose, cgfourioctl, cgfourmmap @@ -111,6 +120,9 @@ extern int fbnode; extern struct tty *fbconstty; static void cgfourloadcmap __P((struct cgfour_softc *, int, int)); +static int cgfour_get_video __P((struct cgfour_softc *)); +static void cgfour_set_video __P((struct cgfour_softc *, int)); +#endif /* * Match a cgfour. @@ -126,8 +138,40 @@ cgfourmatch(parent, vcf, aux) if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); - if (PFOUR_ID(ra->ra_pfour) == PFOUR_ID_COLOR8P1) + + /* + * Mask out invalid flags from the user. + */ + cf->cf_flags &= FB_USERMASK; + + /* + * Only exists on a sun4. + */ + if (!CPU_ISSUN4) + return (0); + + /* + * Only exists on obio. + */ + if (ca->ca_bustype != BUS_OBIO) + return (0); + + /* + * Make sure there's hardware there. + */ + if (probeget(ra->ra_vaddr, 4) == -1) + return (0); + +#if defined(SUN4) + /* + * Check the pfour register. + */ + if (fb_pfour_id(ra->ra_vaddr) == PFOUR_ID_COLOR8P1) { + cf->cf_flags |= FB_PFOUR; return (1); + } +#endif + return (0); } @@ -139,74 +183,109 @@ cgfourattach(parent, self, args) struct device *parent, *self; void *args; { +#if defined(SUN4) register struct cgfour_softc *sc = (struct cgfour_softc *)self; register struct confargs *ca = args; register int node = 0, ramsize, i; register volatile struct bt_regs *bt; + struct fbdevice *fb = &sc->sc_fb; int isconsole; - sc->sc_fb.fb_driver = &cgfourfbdriver; - sc->sc_fb.fb_device = &sc->sc_dev; - sc->sc_fb.fb_type.fb_type = FBTYPE_SUN4COLOR; + fb->fb_driver = &cgfourfbdriver; + fb->fb_device = &sc->sc_dev; + fb->fb_type.fb_type = FBTYPE_SUN4COLOR; + fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags; + + /* + * Only pfour cgfours, thank you... + */ + if ((ca->ca_bustype != BUS_OBIO) || + ((fb->fb_flags & FB_PFOUR) == 0)) { + printf("%s: ignoring; not a pfour\n", sc->sc_dev.dv_xname); + return; + } + + /* Map the pfour register. */ + fb->fb_pfour = (volatile u_int32_t *)mapiodev(ca->ca_ra.ra_reg, 0, + sizeof(u_int32_t), ca->ca_bustype); + + ramsize = PFOUR_COLOR_OFF_END - PFOUR_COLOR_OFF_OVERLAY; + + fb->fb_type.fb_depth = 8; + fb_setsize(fb, fb->fb_type.fb_depth, 1152, 900, node, ca->ca_bustype); + + fb->fb_type.fb_cmsize = 256; + fb->fb_type.fb_size = ramsize; + printf(": cgfour/p4, %d x %d", fb->fb_type.fb_width, + fb->fb_type.fb_height); + + isconsole = 0; - pfour_reset(); - pfour_videosize(ca->ca_ra.ra_pfour, &sc->sc_fb.fb_type.fb_width, - &sc->sc_fb.fb_type.fb_height); + if (CPU_ISSUN4) { + struct eeprom *eep = (struct eeprom *)eeprom_va; - sc->sc_fb.fb_linebytes = sc->sc_fb.fb_type.fb_width; + /* + * Assume this is the console if there's no eeprom info + * to be found. + */ + if (eep == NULL || eep->eeConsole == EE_CONS_P4OPT) + isconsole = (fbconstty != NULL); + } - ramsize = CG4REG_END - CG4REG_OVERLAY; - sc->sc_fb.fb_type.fb_depth = 8; - sc->sc_fb.fb_type.fb_cmsize = 256; - sc->sc_fb.fb_type.fb_size = ramsize; - printf(": %d x %d", sc->sc_fb.fb_type.fb_width, - sc->sc_fb.fb_type.fb_height); +#if 0 + /* + * We don't do any of the console handling here. Instead, + * we let the bwtwo driver pick up the overlay plane and + * use it instead. Rconsole should have better performance + * with the 1-bit depth. + * -- Jason R. Thorpe <thorpej@NetBSD.ORG> + */ /* * When the ROM has mapped in a cgfour display, the address * maps only the video RAM, so in any case we have to map the * registers ourselves. We only need the video RAM if we are * going to print characters via rconsole. - * - * XXX: it is insane to map the full 0x800000 space, when - * the mmap code down below doesn't use it all. Ridiculous! */ - isconsole = node == fbnode && fbconstty != NULL; - if (ca->ca_ra.ra_vaddr == NULL) { - /* this probably cannot happen, but what the heck */ - ca->ca_ra.ra_vaddr = mapiodev(ca->ca_ra.ra_reg, 0, - ramsize, ca->ca_bustype); + + if (isconsole) { + /* XXX this is kind of a waste */ + fb->fb_pixels = mapiodev(ca->ca_ra.ra_reg, + PFOUR_COLOR_OFF_OVERLAY, ramsize, ca->ca_bustype); } - sc->sc_fb.fb_pixels = (char *)((int)ca->ca_ra.ra_vaddr + - CG4REG_COLOUR - CG4REG_OVERLAY); +#endif + + /* Map the Brooktree. */ + sc->sc_fbc = (volatile struct fbcontrol *)mapiodev(ca->ca_ra.ra_reg, + PFOUR_COLOR_OFF_CMAP, sizeof(struct fbcontrol), ca->ca_bustype); -#define O(memb) ((u_int)(&((struct cgfour_all *)0)->memb)) - sc->sc_bt = bt = (volatile struct bt_regs *)mapiodev(ca->ca_ra.ra_reg, - O(ba_btreg), sizeof(struct bt_regs), ca->ca_bustype); sc->sc_phys = ca->ca_ra.ra_reg[0]; sc->sc_bustype = ca->ca_bustype; /* grab initial (current) color map */ + bt = &sc->sc_fbc->fbc_dac; bt->bt_addr = 0; for (i = 0; i < 256 * 3 / 4; i++) ((char *)&sc->sc_cmap)[i] = bt->bt_cmap >> 24; - /* make sure we are not blanked (see cgfourunblank) */ - bt->bt_addr = 0x06 << 24; /* command reg */ - bt->bt_ctrl = 0x73 << 24; /* overlay plane */ - bt->bt_addr = 0x04 << 24; /* read mask */ - bt->bt_ctrl = 0xff << 24; /* color planes */ + BT_INIT(bt, 24); +#if 0 /* See above. */ if (isconsole) { printf(" (console)\n"); -#ifdef RASTERCONSOLE - fbrcons_init(&sc->sc_fb); +#if defined(RASTERCONSOLE) && 0 /* XXX been told it doesn't work well. */ + fbrcons_init(fb); #endif } else +#endif /* 0 */ printf("\n"); - if ((node == fbnode && cputyp != CPU_SUN4) || - (isconsole && cputyp == CPU_SUN4)) - fb_attach(&sc->sc_fb); + + /* + * Even though we're not using rconsole, we'd still like + * to notice if we're the console framebuffer. + */ + fb_attach(fb, isconsole); +#endif } int @@ -217,7 +296,7 @@ cgfouropen(dev, flags, mode, p) { int unit = minor(dev); - if (unit >= cgfourcd.cd_ndevs || cgfourcd.cd_devs[unit] == NULL) + if (unit >= cgfour_cd.cd_ndevs || cgfour_cd.cd_devs[unit] == NULL) return (ENXIO); return (0); } @@ -240,7 +319,8 @@ cgfourioctl(dev, cmd, data, flags, p) int flags; struct proc *p; { - register struct cgfour_softc *sc = cgfourcd.cd_devs[minor(dev)]; +#if defined(SUN4) + register struct cgfour_softc *sc = cgfour_cd.cd_devs[minor(dev)]; register struct fbgattr *fba; int error; @@ -278,62 +358,109 @@ cgfourioctl(dev, cmd, data, flags, p) break; case FBIOGVIDEO: - *(int *)data = sc->sc_blanked; + *(int *)data = cgfour_get_video(sc); break; case FBIOSVIDEO: - if (*(int *)data) - cgfourunblank(&sc->sc_dev); - else if (!sc->sc_blanked) { - register volatile struct bt_regs *bt; - - bt = sc->sc_bt; - bt->bt_addr = 0x06 << 24; /* command reg */ - bt->bt_ctrl = 0x70 << 24; /* overlay plane */ - bt->bt_addr = 0x04 << 24; /* read mask */ - bt->bt_ctrl = 0x00 << 24; /* color planes */ - /* - * Set color 0 to black -- note that this overwrites - * R of color 1. - */ - bt->bt_addr = 0 << 24; - bt->bt_cmap = 0 << 24; - - sc->sc_blanked = 1; - } + cgfour_set_video(sc, *(int *)data); break; default: return (ENOTTY); } +#endif return (0); } /* + * Return the address that would map the given device at the given + * offset, allowing for the given protection, or return -1 for error. + * + * the cg4 maps it's overlay plane for 128K, followed by the enable + * plane for 128K, followed by the colour plane (for as much colour + * as their is.) + * + * As well, mapping at an offset of 0x04000000 causes the cg4 to map + * only it's colour plane, at 0. + */ +int +cgfourmmap(dev, off, prot) + dev_t dev; + int off, prot; +{ + register struct cgfour_softc *sc = cgfour_cd.cd_devs[minor(dev)]; + int poff; + +#define START_ENABLE (128*1024) +#define START_COLOR ((128*1024) + (128*1024)) +#define COLOR_SIZE (sc->sc_fb.fb_type.fb_width * \ + sc->sc_fb.fb_type.fb_height) +#define END_COLOR (START_COLOR + COLOR_SIZE) +#define NOOVERLAY (0x04000000) + + if (off & PGOFSET) + panic("cgfourmap"); + + if ((u_int)off >= NOOVERLAY) { + off =- NOOVERLAY; + + /* + * X11 maps a huge chunk of the frame buffer; far more than + * there really is. We compensate by double-mapping the + * first page for as many other pages as it wants + */ + while (off >= COLOR_SIZE) + off -= COLOR_SIZE; /* XXX thorpej ??? */ + + poff = off + PFOUR_COLOR_OFF_COLOR; + } else if ((u_int)off < START_ENABLE) { + /* + * in overlay plane + */ + poff = PFOUR_COLOR_OFF_OVERLAY + off; + } else if ((u_int)off < START_COLOR) { + /* + * in enable plane + */ + poff = (off - START_ENABLE) + PFOUR_COLOR_OFF_ENABLE; + } else if ((u_int)off < END_COLOR) { + /* + * in colour plane + */ + poff = (off - START_COLOR) + PFOUR_COLOR_OFF_COLOR; + } else + return (-1); + + return (REG2PHYS(&sc->sc_phys, poff, sc->sc_bustype) | PMAP_NC); +} + +#if defined(SUN4) +/* * Undo the effect of an FBIOSVIDEO that turns the video off. */ static void cgfourunblank(dev) struct device *dev; { - struct cgfour_softc *sc = (struct cgfour_softc *)dev; - register volatile struct bt_regs *bt; - if (sc->sc_blanked) { - sc->sc_blanked = 0; - bt = sc->sc_bt; - /* restore color 0 (and R of color 1) */ - bt->bt_addr = 0 << 24; - bt->bt_cmap = sc->sc_cmap.cm_chip[0]; - bt->bt_cmap = sc->sc_cmap.cm_chip[0] << 8; - bt->bt_cmap = sc->sc_cmap.cm_chip[0] << 16; - - /* restore read mask */ - bt->bt_addr = 0x06 << 24; /* command reg */ - bt->bt_ctrl = 0x73 << 24; /* overlay plane */ - bt->bt_addr = 0x04 << 24; /* read mask */ - bt->bt_ctrl = 0xff << 24; /* color planes */ - } + cgfour_set_video((struct cgfour_softc *)dev, 1); +} + +static int +cgfour_get_video(sc) + struct cgfour_softc *sc; +{ + + return (fb_pfour_get_video(&sc->sc_fb)); +} + +static void +cgfour_set_video(sc, enable) + struct cgfour_softc *sc; + int enable; +{ + + fb_pfour_set_video(&sc->sc_fb, enable); } /* @@ -350,7 +477,7 @@ cgfourloadcmap(sc, start, ncolors) ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; - bt = sc->sc_bt; + bt = &sc->sc_fbc->fbc_dac; bt->bt_addr = BT_D4M4(start) << 24; while (--count >= 0) { i = *ip++; @@ -361,53 +488,4 @@ cgfourloadcmap(sc, start, ncolors) bt->bt_cmap = i << 24; } } - -/* - * Return the address that would map the given device at the given - * offset, allowing for the given protection, or return -1 for error. - * - * the cg4 maps it's overlay plane for 128K, followed by the enable - * plane for 128K, followed by the colour plane (for as much colour - * as their is.) - * - * As well, mapping at an offset of 0x04000000 causes the cg4 to map - * only it's colour plane, at 0. - */ -int -cgfourmmap(dev, off, prot) - dev_t dev; - int off, prot; -{ - register struct cgfour_softc *sc = cgfourcd.cd_devs[minor(dev)]; - int poff; - -#define START_ENABLE (128*1024) -#define START_COLOUR (128*1024 + 128*1024) -#define COLOUR_SIZE (sc->sc_fb.fb_type.fb_width * sc->sc_fb.fb_type.fb_height) -#define END_COLOUR (START_COLOUR + COLOUR_SIZE) -#define NOOVERLAY (0x04000000) - - if (off & PGOFSET) - panic("cgfourmap"); - - if ((u_int)off >= NOOVERLAY) { - off = off - NOOVERLAY; - - /* - * X11 maps a huge chunk of the frame buffer; far more than - * there really is. We compensate by double-mapping the - * first page for as many other pages as it wants - */ - while (off >= COLOUR_SIZE) - off = 0; - poff = off + (CG4REG_COLOUR - CG4REG_OVERLAY); - } else if ((u_int)off < START_ENABLE) /* in overlay plane */ - poff = off; - else if ((u_int)off < START_COLOUR) /* in enable plane */ - poff = off + (CG4REG_ENABLE - CG4REG_OVERLAY) - START_ENABLE; - else if ((u_int)off < (CG4REG_END - CG4REG_OVERLAY)) /* in colour plane */ - poff = off + (CG4REG_COLOUR - CG4REG_OVERLAY) - START_COLOUR; - else - return (-1); - return (REG2PHYS(&sc->sc_phys, off, sc->sc_bustype) | PMAP_NC); -} +#endif diff --git a/sys/arch/sparc/dev/cgsix.c b/sys/arch/sparc/dev/cgsix.c index 9dab9af06b0..259024c7da6 100644 --- a/sys/arch/sparc/dev/cgsix.c +++ b/sys/arch/sparc/dev/cgsix.c @@ -1,4 +1,4 @@ -/* $NetBSD: cgsix.c,v 1.16 1995/10/08 01:39:16 pk Exp $ */ +/* $NetBSD: cgsix.c,v 1.25 1996/04/01 17:30:00 christos Exp $ */ /* * Copyright (c) 1993 @@ -53,6 +53,7 @@ */ #include <sys/param.h> +#include <sys/systm.h> #include <sys/buf.h> #include <sys/device.h> #include <machine/fbio.h> @@ -60,6 +61,7 @@ #include <sys/malloc.h> #include <sys/mman.h> #include <sys/tty.h> +#include <sys/conf.h> #ifdef DEBUG #include <sys/proc.h> @@ -71,12 +73,19 @@ #include <machine/autoconf.h> #include <machine/pmap.h> #include <machine/fbvar.h> +#include <machine/cpu.h> +#if defined(SUN4) +#include <machine/eeprom.h> +#endif +#include <machine/conf.h> #include <sparc/dev/btreg.h> #include <sparc/dev/btvar.h> #include <sparc/dev/cgsixreg.h> #include <sparc/dev/sbusvar.h> +#if defined(SUN4) #include <sparc/dev/pfourreg.h> +#endif union cursor_cmap { /* colormap, like bt_cmap, but tiny */ u_char cm_map[2][3]; /* 2 R/G/B entries */ @@ -118,9 +127,12 @@ int cgsixioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); int cgsixmmap __P((dev_t, int, int)); static void cg6_unblank __P((struct device *)); -struct cfdriver cgsixcd = { - NULL, "cgsix", cgsixmatch, cgsixattach, - DV_DULL, sizeof(struct cgsix_softc) +struct cfattach cgsix_ca = { + sizeof(struct cgsix_softc), cgsixmatch, cgsixattach +}; + +struct cfdriver cgsix_cd = { + NULL, "cgsix", DV_DULL }; /* frame buffer generic driver */ @@ -155,19 +167,35 @@ cgsixmatch(parent, vcf, aux) if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); + + /* + * Mask out invalid flags from the user. + */ + cf->cf_flags &= FB_USERMASK; + if (ca->ca_bustype == BUS_SBUS) return (1); -#ifdef SUN4 - if (ca->ca_bustype == BUS_PFOUR && - PFOUR_ID(ra->ra_pfour) == PFOUR_ID_FASTCOLOR) - return (1); - if (ca->ca_bustype == BUS_OBIO) { - struct cg6_layout *p = (struct cg6_layout *)ra->ra_paddr; - void *tmp = bus_tmp(&p->cg6_fhc_un.un_fhc, ca->ca_bustype); - return (probeget(tmp, 4) != 0); - } +#if defined(SUN4) + if (CPU_ISSUN4 && (ca->ca_bustype == BUS_OBIO)) { + void *tmp; + + /* + * Check for a pfour framebuffer. This is done somewhat + * differently on the cgsix than other pfour framebuffers. + */ + bus_untmp(); + tmp = bus_tmp(ra->ra_paddr + CGSIX_FHC_OFFSET, ca->ca_bustype); + if (probeget(tmp, 4) == -1) + return (0); + + if (fb_pfour_id(tmp) == PFOUR_ID_FASTCOLOR) { + cf->cf_flags |= FB_PFOUR; + return (1); + } + } #endif + return (0); } @@ -181,79 +209,105 @@ cgsixattach(parent, self, args) { register struct cgsix_softc *sc = (struct cgsix_softc *)self; register struct confargs *ca = args; - register int node = ca->ca_ra.ra_node, ramsize, i, isconsole; + register int node = 0, ramsize, i; register volatile struct bt_regs *bt; - register volatile struct cg6_layout *p; - char *nam; + struct fbdevice *fb = &sc->sc_fb; + int isconsole = 0, sbus = 1; + char *nam = NULL; extern struct tty *fbconstty; - sc->sc_fb.fb_driver = &cg6_fbdriver; - sc->sc_fb.fb_device = &sc->sc_dev; - sc->sc_fb.fb_type.fb_type = FBTYPE_SUNFAST_COLOR; + fb->fb_driver = &cg6_fbdriver; + fb->fb_device = &sc->sc_dev; + fb->fb_type.fb_type = FBTYPE_SUNFAST_COLOR; + fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags; + + /* + * Dunno what the PROM has mapped, though obviously it must have + * the video RAM mapped. Just map what we care about for ourselves + * (the FHC, THC, and Brooktree registers). + */ +#define O(memb) ((u_int)(&((struct cg6_layout *)0)->memb)) + sc->sc_physadr = ca->ca_ra.ra_reg[0]; + sc->sc_bustype = ca->ca_bustype; + sc->sc_bt = bt = (volatile struct bt_regs *) + mapiodev(ca->ca_ra.ra_reg, O(cg6_bt_un.un_btregs), + sizeof *sc->sc_bt, ca->ca_bustype); + sc->sc_fhc = (volatile int *) + mapiodev(ca->ca_ra.ra_reg, O(cg6_fhc_un.un_fhc), + sizeof *sc->sc_fhc, ca->ca_bustype); + sc->sc_thc = (volatile struct cg6_thc *) + mapiodev(ca->ca_ra.ra_reg, O(cg6_thc_un.un_thc), + sizeof *sc->sc_thc, ca->ca_bustype); + sc->sc_tec = (volatile struct cg6_tec_xxx *) + mapiodev(ca->ca_ra.ra_reg, O(cg6_tec_un.un_tec), + sizeof *sc->sc_tec, ca->ca_bustype); switch (ca->ca_bustype) { -#if defined(SUN4) - case BUS_PFOUR: - node = 0; -#if 0 - /* - * XXX cg6 reset routine is not good enough to - * rebuild state correctly! - */ - pfour_reset(); -#endif - /* - * XXX pfour register is confused? - */ - sc->sc_fb.fb_type.fb_width = 1152; - sc->sc_fb.fb_type.fb_height = 900; - nam = "cgsix"; - break; - case BUS_VME32: - node = 0; - nam = "cgsix"; - break; -#endif /* SUN4 */ case BUS_OBIO: + sbus = node = 0; + if (fb->fb_flags & FB_PFOUR) + nam = "cgsix/p4"; + else + nam = "cgsix"; + #if defined(SUN4M) - if (cputyp == CPU_SUN4M) { /* 4m has framebuffer on obio */ + if (CPU_ISSUN4M) { /* 4m has framebuffer on obio */ + node = ca->ca_ra.ra_node; nam = getpropstring(node, "model"); break; } #endif break; + + case BUS_VME32: + case BUS_VME16: + sbus = node = 0; + nam = "cgsix"; + break; + case BUS_SBUS: + node = ca->ca_ra.ra_node; nam = getpropstring(node, "model"); break; + + case BUS_MAIN: + printf("cgsix on mainbus?\n"); + return; } - sc->sc_fb.fb_type.fb_depth = 8; - fb_setsize(&sc->sc_fb, sc->sc_fb.fb_type.fb_depth, - 1152, 900, node, ca->ca_bustype); + /* Don't have to map the pfour register on the cgsix. */ + fb->fb_pfour = NULL; - ramsize = sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes; - sc->sc_fb.fb_type.fb_cmsize = 256; - sc->sc_fb.fb_type.fb_size = ramsize; - printf(": %s, %d x %d", nam, - sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height); - isconsole = node == fbnode && fbconstty != NULL; + fb->fb_type.fb_depth = 8; + fb_setsize(fb, fb->fb_type.fb_depth, 1152, 900, + node, ca->ca_bustype); - /* - * Dunno what the PROM has mapped, though obviously it must have - * the video RAM mapped. Just map what we care about for ourselves - * (the FHC, THC, and Brooktree registers). - */ -#define O(memb) ((u_int)(&((struct cg6_layout *)0)->memb)) - sc->sc_physadr = ca->ca_ra.ra_reg[0]; - sc->sc_bustype = ca->ca_bustype; - sc->sc_bt = bt = (volatile struct bt_regs *)mapiodev(ca->ca_ra.ra_reg, - O(cg6_bt_un.un_btregs), sizeof *sc->sc_bt, ca->ca_bustype); - sc->sc_fhc = (volatile int *)mapiodev(ca->ca_ra.ra_reg, - O(cg6_fhc_un.un_fhc), sizeof *sc->sc_fhc, ca->ca_bustype); - sc->sc_thc = (volatile struct cg6_thc *)mapiodev(ca->ca_ra.ra_reg, - O(cg6_thc_un.un_thc), sizeof *sc->sc_thc, ca->ca_bustype); - sc->sc_tec = (volatile struct cg6_tec_xxx *)mapiodev(ca->ca_ra.ra_reg, - O(cg6_tec_un.un_tec), sizeof *sc->sc_tec, ca->ca_bustype); + ramsize = fb->fb_type.fb_height * fb->fb_linebytes; + fb->fb_type.fb_cmsize = 256; + fb->fb_type.fb_size = ramsize; + printf(": %s, %d x %d", nam, fb->fb_type.fb_width, + fb->fb_type.fb_height); + +#if defined(SUN4) + if (CPU_ISSUN4) { + struct eeprom *eep = (struct eeprom *)eeprom_va; + int constype = (fb->fb_flags & FB_PFOUR) ? EE_CONS_P4OPT : + EE_CONS_COLOR; + /* + * Assume this is the console if there's no eeprom info + * to be found. + */ + if (eep == NULL || eep->eeConsole == constype) + isconsole = (fbconstty != NULL); + else + isconsole = 0; + } +#endif + +#if defined(SUN4C) || defined(SUN4M) + if (CPU_ISSUN4COR4M) + isconsole = node == fbnode && fbconstty != NULL; +#endif sc->sc_fhcrev = (*sc->sc_fhc >> FHC_REV_SHIFT) & (FHC_REV_MASK >> FHC_REV_SHIFT); @@ -273,19 +327,19 @@ cgsixattach(parent, self, args) if (isconsole) { printf(" (console)\n"); #ifdef RASTERCONSOLE - sc->sc_fb.fb_pixels = (caddr_t)mapiodev(ca->ca_ra.ra_reg, - O(cg6_ram[0]), ramsize, ca->ca_bustype); + sc->sc_fb.fb_pixels = (caddr_t) + mapiodev(ca->ca_ra.ra_reg, O(cg6_ram[0]), + ramsize, ca->ca_bustype); fbrcons_init(&sc->sc_fb); #endif } else printf("\n"); #if defined(SUN4C) || defined(SUN4M) - if (ca->ca_bustype == BUS_SBUS) + if (sbus) sbus_establish(&sc->sc_sd, &sc->sc_dev); -#endif /* SUN4C || SUN4M */ - if ((node == fbnode && cputyp != CPU_SUN4) || - (isconsole && cputyp == CPU_SUN4)) - fb_attach(&sc->sc_fb); +#endif + if (CPU_ISSUN4 || (node == fbnode)) + fb_attach(&sc->sc_fb, isconsole); } int @@ -296,7 +350,7 @@ cgsixopen(dev, flags, mode, p) { int unit = minor(dev); - if (unit >= cgsixcd.cd_ndevs || cgsixcd.cd_devs[unit] == NULL) + if (unit >= cgsix_cd.cd_ndevs || cgsix_cd.cd_devs[unit] == NULL) return (ENXIO); return (0); } @@ -307,7 +361,7 @@ cgsixclose(dev, flags, mode, p) int flags, mode; struct proc *p; { - struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)]; + struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)]; cg6_reset(sc); return (0); @@ -321,9 +375,9 @@ cgsixioctl(dev, cmd, data, flags, p) int flags; struct proc *p; { - register struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)]; + register struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)]; u_int count; - int i, v, error; + int v, error; union cursor_cmap tcm; switch (cmd) { @@ -480,7 +534,7 @@ cgsixioctl(dev, cmd, data, flags, p) default: #ifdef DEBUG - log(LOG_NOTICE, "cgsixioctl(%x) (%s[%d])\n", cmd, + log(LOG_NOTICE, "cgsixioctl(%lx) (%s[%d])\n", cmd, p->p_comm, p->p_pid); #endif return (ENOTTY); @@ -663,7 +717,7 @@ cgsixmmap(dev, off, prot) dev_t dev; int off, prot; { - register struct cgsix_softc *sc = cgsixcd.cd_devs[minor(dev)]; + register struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)]; register struct mmo *mo; register u_int u, sz; #define O(memb) ((u_int)(&((struct cg6_layout *)0)->memb)) @@ -698,7 +752,7 @@ cgsixmmap(dev, off, prot) sz = mo->mo_size ? mo->mo_size : sc->sc_fb.fb_type.fb_size; if (u < sz) return (REG2PHYS(&sc->sc_physadr, u + mo->mo_physoff, - sc->sc_bustype) | PMAP_NC); + sc->sc_bustype) | PMAP_NC); } #ifdef DEBUG { diff --git a/sys/arch/sparc/dev/cgsixreg.h b/sys/arch/sparc/dev/cgsixreg.h index 15a7d603f9e..d9b90977c85 100644 --- a/sys/arch/sparc/dev/cgsixreg.h +++ b/sys/arch/sparc/dev/cgsixreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: cgsixreg.h,v 1.3 1994/11/20 20:52:00 deraadt Exp $ */ +/* $NetBSD: cgsixreg.h,v 1.4 1996/02/27 22:09:31 thorpej Exp $ */ /* * Copyright (c) 1993 @@ -71,6 +71,9 @@ * we have only seen rev 1 & 2. */ +/* offsets */ +#define CGSIX_FHC_OFFSET 0x300000 + /* bits in FHC register */ #define FHC_FBID_MASK 0xff000000 /* bits 24..31 are frame buffer ID */ #define FHC_FBID_SHIFT 24 diff --git a/sys/arch/sparc/dev/cgthree.c b/sys/arch/sparc/dev/cgthree.c index 06c62b15e91..1599048c61d 100644 --- a/sys/arch/sparc/dev/cgthree.c +++ b/sys/arch/sparc/dev/cgthree.c @@ -1,4 +1,4 @@ -/* $NetBSD: cgthree.c,v 1.16 1995/10/08 01:39:18 pk Exp $ */ +/* $NetBSD: cgthree.c,v 1.27 1996/04/01 17:30:03 christos Exp $ */ /* * Copyright (c) 1992, 1993 @@ -53,12 +53,14 @@ */ #include <sys/param.h> +#include <sys/systm.h> #include <sys/buf.h> #include <sys/device.h> #include <sys/ioctl.h> #include <sys/malloc.h> #include <sys/mman.h> #include <sys/tty.h> +#include <sys/conf.h> #include <vm/vm.h> @@ -66,6 +68,8 @@ #include <machine/autoconf.h> #include <machine/pmap.h> #include <machine/fbvar.h> +#include <machine/cpu.h> +#include <machine/conf.h> #include <sparc/dev/btreg.h> #include <sparc/dev/btvar.h> @@ -77,10 +81,9 @@ struct cgthree_softc { struct device sc_dev; /* base device */ struct sbusdev sc_sd; /* sbus device */ struct fbdevice sc_fb; /* frame buffer device */ - volatile struct bt_regs *sc_bt; /* Brooktree registers */ - struct rom_reg sc_phys; /* display RAM (phys addr) */ + struct rom_reg sc_phys; /* phys address description */ + volatile struct fbcontrol *sc_fbc; /* Brooktree registers */ int sc_bustype; /* type of bus we live on */ - int sc_blanked; /* true if blanked */ union bt_cmap sc_cmap; /* Brooktree color map */ }; @@ -93,9 +96,12 @@ int cgthreeioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); int cgthreemmap __P((dev_t, int, int)); static void cgthreeunblank(struct device *); -struct cfdriver cgthreecd = { - NULL, "cgthree", cgthreematch, cgthreeattach, - DV_DULL, sizeof(struct cgthree_softc) +struct cfattach cgthree_ca = { + sizeof(struct cgthree_softc), cgthreematch, cgthreeattach +}; + +struct cfdriver cgthree_cd = { + NULL, "cgthree", DV_DULL }; /* frame buffer generic driver */ @@ -107,6 +113,8 @@ extern int fbnode; extern struct tty *fbconstty; static void cgthreeloadcmap __P((struct cgthree_softc *, int, int)); +static void cgthree_set_video __P((struct cgthree_softc *, int)); +static int cgthree_get_video __P((struct cgthree_softc *)); /* * Match a cgthree. @@ -120,6 +128,11 @@ cgthreematch(parent, vcf, aux) struct confargs *ca = aux; struct romaux *ra = &ca->ca_ra; + /* + * Mask out invalid flags from the user. + */ + cf->cf_flags &= FB_USERMASK; + if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); if (ca->ca_bustype == BUS_SBUS) @@ -138,32 +151,36 @@ cgthreeattach(parent, self, args) { register struct cgthree_softc *sc = (struct cgthree_softc *)self; register struct confargs *ca = args; - register int node = ca->ca_ra.ra_node, ramsize, i; + register int node = 0, ramsize, i; register volatile struct bt_regs *bt; - register struct cgthree_all *p; int isconsole; - char *nam; + int sbus = 1; + char *nam = NULL; sc->sc_fb.fb_driver = &cgthreefbdriver; sc->sc_fb.fb_device = &sc->sc_dev; + sc->sc_fb.fb_flags = sc->sc_dev.dv_cfdata->cf_flags; /* * The defaults below match my screen, but are not guaranteed * to be correct as defaults go... */ sc->sc_fb.fb_type.fb_type = FBTYPE_SUN3COLOR; switch (ca->ca_bustype) { -#if defined(SUN4M) case BUS_OBIO: - if (cputyp == CPU_SUN4M) /* 4m has framebuffer on obio */ + if (CPU_ISSUN4M) { /* 4m has framebuffer on obio */ + sbus = 0; + node = ca->ca_ra.ra_node; nam = getpropstring(node, "model"); - break; -#endif - + break; + } case BUS_VME32: - node = 0; + case BUS_VME16: + sbus = node = 0; nam = "cgthree"; break; + case BUS_SBUS: + node = ca->ca_ra.ra_node; nam = getpropstring(node, "model"); break; } @@ -173,7 +190,7 @@ cgthreeattach(parent, self, args) 1152, 900, node, ca->ca_bustype); ramsize = roundup(sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes, - NBPG); + NBPG); sc->sc_fb.fb_type.fb_cmsize = 256; sc->sc_fb.fb_type.fb_size = ramsize; printf(": %s, %d x %d", nam, @@ -186,27 +203,27 @@ cgthreeattach(parent, self, args) * going to print characters via rconsole. */ isconsole = node == fbnode && fbconstty != NULL; - p = (struct cgthree_all *)ca->ca_ra.ra_paddr; if ((sc->sc_fb.fb_pixels = ca->ca_ra.ra_vaddr) == NULL && isconsole) { /* this probably cannot happen, but what the heck */ sc->sc_fb.fb_pixels = mapiodev(ca->ca_ra.ra_reg, CG3REG_MEM, - ramsize, ca->ca_bustype); + ramsize, ca->ca_bustype); } - sc->sc_bt = bt = (volatile struct bt_regs *)mapiodev(ca->ca_ra.ra_reg, - CG3REG_REG, sizeof(struct bt_regs), ca->ca_bustype); + sc->sc_fbc = (volatile struct fbcontrol *) + mapiodev(ca->ca_ra.ra_reg, CG3REG_REG, + sizeof(struct fbcontrol), ca->ca_bustype); sc->sc_phys = ca->ca_ra.ra_reg[0]; sc->sc_bustype = ca->ca_bustype; /* grab initial (current) color map */ + bt = &sc->sc_fbc->fbc_dac; bt->bt_addr = 0; for (i = 0; i < 256 * 3 / 4; i++) sc->sc_cmap.cm_chip[i] = bt->bt_cmap; - /* make sure we are not blanked (see cgthreeunblank) */ - bt->bt_addr = 0x06; /* command reg */ - bt->bt_ctrl = 0x73; /* overlay plane */ - bt->bt_addr = 0x04; /* read mask */ - bt->bt_ctrl = 0xff; /* color planes */ + + /* make sure we are not blanked */ + cgthree_set_video(sc, 1); + BT_INIT(bt, 0); if (isconsole) { printf(" (console)\n"); @@ -215,12 +232,10 @@ cgthreeattach(parent, self, args) #endif } else printf("\n"); -#if defined(SUN4C) || defined(SUN4M) - if (ca->ca_bustype == BUS_SBUS) + if (sbus) sbus_establish(&sc->sc_sd, &sc->sc_dev); -#endif /* SUN4C || SUN4M */ if (node == fbnode) - fb_attach(&sc->sc_fb); + fb_attach(&sc->sc_fb, isconsole); } int @@ -231,7 +246,7 @@ cgthreeopen(dev, flags, mode, p) { int unit = minor(dev); - if (unit >= cgthreecd.cd_ndevs || cgthreecd.cd_devs[unit] == NULL) + if (unit >= cgthree_cd.cd_ndevs || cgthree_cd.cd_devs[unit] == NULL) return (ENXIO); return (0); } @@ -254,7 +269,7 @@ cgthreeioctl(dev, cmd, data, flags, p) int flags; struct proc *p; { - register struct cgthree_softc *sc = cgthreecd.cd_devs[minor(dev)]; + register struct cgthree_softc *sc = cgthree_cd.cd_devs[minor(dev)]; register struct fbgattr *fba; int error; @@ -292,29 +307,11 @@ cgthreeioctl(dev, cmd, data, flags, p) break; case FBIOGVIDEO: - *(int *)data = sc->sc_blanked; + *(int *)data = cgthree_get_video(sc); break; case FBIOSVIDEO: - if (*(int *)data) - cgthreeunblank(&sc->sc_dev); - else if (!sc->sc_blanked) { - register volatile struct bt_regs *bt; - - bt = sc->sc_bt; - bt->bt_addr = 0x06; /* command reg */ - bt->bt_ctrl = 0x70; /* overlay plane */ - bt->bt_addr = 0x04; /* read mask */ - bt->bt_ctrl = 0x00; /* color planes */ - /* - * Set color 0 to black -- note that this overwrites - * R of color 1. - */ - bt->bt_addr = 0; - bt->bt_cmap = 0; - - sc->sc_blanked = 1; - } + cgthree_set_video(sc, *(int *)data); break; default: @@ -330,22 +327,28 @@ static void cgthreeunblank(dev) struct device *dev; { - struct cgthree_softc *sc = (struct cgthree_softc *)dev; - register volatile struct bt_regs *bt; - if (sc->sc_blanked) { - sc->sc_blanked = 0; - bt = sc->sc_bt; - /* restore color 0 (and R of color 1) */ - bt->bt_addr = 0; - bt->bt_cmap = sc->sc_cmap.cm_chip[0]; - - /* restore read mask */ - bt->bt_addr = 0x06; /* command reg */ - bt->bt_ctrl = 0x73; /* overlay plane */ - bt->bt_addr = 0x04; /* read mask */ - bt->bt_ctrl = 0xff; /* color planes */ - } + cgthree_set_video((struct cgthree_softc *)dev, 1); +} + +static void +cgthree_set_video(sc, enable) + struct cgthree_softc *sc; + int enable; +{ + + if (enable) + sc->sc_fbc->fbc_ctrl |= FBC_VENAB; + else + sc->sc_fbc->fbc_ctrl &= ~FBC_VENAB; +} + +static int +cgthree_get_video(sc) + struct cgthree_softc *sc; +{ + + return ((sc->sc_fbc->fbc_ctrl & FBC_VENAB) != 0); } /* @@ -362,7 +365,7 @@ cgthreeloadcmap(sc, start, ncolors) ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; - bt = sc->sc_bt; + bt = &sc->sc_fbc->fbc_dac; bt->bt_addr = BT_D4M4(start); while (--count >= 0) bt->bt_cmap = *ip++; @@ -378,7 +381,7 @@ cgthreeloadcmap(sc, start, ncolors) * map the whole thing, so we repeatedly map the first 256K to the * first page of the color screen. If someone tries to use the overlay * and enable regions, they will get a surprise.... - * + * * As well, mapping at an offset of 0x04000000 causes the cg3 to be * mapped in flat mode without the cg4 emulation. */ @@ -387,7 +390,7 @@ cgthreemmap(dev, off, prot) dev_t dev; int off, prot; { - register struct cgthree_softc *sc = cgthreecd.cd_devs[minor(dev)]; + register struct cgthree_softc *sc = cgthree_cd.cd_devs[minor(dev)]; #define START (128*1024 + 128*1024) #define NOOVERLAY (0x04000000) diff --git a/sys/arch/sparc/dev/cgthreereg.h b/sys/arch/sparc/dev/cgthreereg.h index 0b8356e4126..073cc52e66c 100644 --- a/sys/arch/sparc/dev/cgthreereg.h +++ b/sys/arch/sparc/dev/cgthreereg.h @@ -1,4 +1,4 @@ -/* $NetBSD: cgthreereg.h,v 1.4 1994/11/20 20:52:03 deraadt Exp $ */ +/* $NetBSD: cgthreereg.h,v 1.5 1996/02/27 00:14:17 pk Exp $ */ /* * Copyright (c) 1992, 1993 @@ -58,7 +58,7 @@ struct cgthree_all { long ba_id; /* ID = 0xfe010104 on my IPC */ char ba_xxx0[0x400000-4]; - struct bt_regs ba_btreg; /* Brooktree registers */ - char ba_xxx1[0x400000-sizeof(struct bt_regs)]; + struct fbcontrol ba_fbc; /* Brooktree regs (+ misc control) */ + char ba_xxx1[0x400000-sizeof(struct fbcontrol)]; char ba_ram[4096]; /* actually larger */ }; diff --git a/sys/arch/sparc/dev/cgtwo.c b/sys/arch/sparc/dev/cgtwo.c index 17be2ccbc12..243c7cde111 100644 --- a/sys/arch/sparc/dev/cgtwo.c +++ b/sys/arch/sparc/dev/cgtwo.c @@ -1,4 +1,4 @@ -/* $NetBSD: cgtwo.c,v 1.5 1995/10/08 01:39:15 pk Exp $ */ +/* $NetBSD: cgtwo.c,v 1.16 1996/05/18 12:19:14 mrg Exp $ */ /* * Copyright (c) 1992, 1993 @@ -53,12 +53,14 @@ */ #include <sys/param.h> +#include <sys/systm.h> #include <sys/buf.h> #include <sys/device.h> #include <sys/ioctl.h> #include <sys/malloc.h> #include <sys/mman.h> #include <sys/tty.h> +#include <sys/conf.h> #include <vm/vm.h> @@ -66,10 +68,13 @@ #include <machine/autoconf.h> #include <machine/pmap.h> #include <machine/fbvar.h> +#if defined(SUN4) #include <machine/eeprom.h> - +#endif +#include <machine/conf.h> #include <machine/cgtworeg.h> + /* per-display variables */ struct cgtwo_softc { struct device sc_dev; /* base device */ @@ -91,10 +96,15 @@ int cgtwoclose __P((dev_t, int, int, struct proc *)); int cgtwoioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); int cgtwommap __P((dev_t, int, int)); static void cgtwounblank __P((struct device *)); +int cgtwogetcmap __P((struct cgtwo_softc *, struct fbcmap *)); +int cgtwoputcmap __P((struct cgtwo_softc *, struct fbcmap *)); -struct cfdriver cgtwocd = { - NULL, "cgtwo", cgtwomatch, cgtwoattach, - DV_DULL, sizeof(struct cgtwo_softc) +struct cfattach cgtwo_ca = { + sizeof(struct cgtwo_softc), cgtwomatch, cgtwoattach +}; + +struct cfdriver cgtwo_cd = { + NULL, "cgtwo", DV_DULL }; /* frame buffer generic driver */ @@ -105,8 +115,6 @@ static struct fbdriver cgtwofbdriver = { extern int fbnode; extern struct tty *fbconstty; -static void cgtwoloadcmap __P((struct cgtwo_softc *, int, int)); - /* * Match a cgtwo. */ @@ -118,18 +126,32 @@ cgtwomatch(parent, vcf, aux) struct cfdata *cf = vcf; struct confargs *ca = aux; struct romaux *ra = &ca->ca_ra; - int probe; +#if defined(SUN4) caddr_t tmp; +#endif + + /* + * Mask out invalid flags from the user. + */ + cf->cf_flags &= FB_USERMASK; + + if (ca->ca_bustype != BUS_VME16) + return (0); if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); +#if defined(SUN4) + if (!CPU_ISSUN4 || cf->cf_unit != 0) + return (0); + /* XXX - Must do our own mapping at CG2_CTLREG_OFF */ bus_untmp(); tmp = (caddr_t)bus_tmp(ra->ra_paddr + CG2_CTLREG_OFF, ca->ca_bustype); if (probeget(tmp, 2) != -1) return 1; - return (0); +#endif + return 0; } /* @@ -142,15 +164,25 @@ cgtwoattach(parent, self, args) { register struct cgtwo_softc *sc = (struct cgtwo_softc *)self; register struct confargs *ca = args; - register int node = 0, i; - register struct cgtwo_all *p; - struct eeprom *eep = (struct eeprom *)eeprom_va; - int isconsole; - char *nam; + register int node = 0; + int isconsole = 0; + char *nam = NULL; sc->sc_fb.fb_driver = &cgtwofbdriver; sc->sc_fb.fb_device = &sc->sc_dev; sc->sc_fb.fb_type.fb_type = FBTYPE_SUN2COLOR; + sc->sc_fb.fb_flags = sc->sc_dev.dv_cfdata->cf_flags; + + switch (ca->ca_bustype) { + case BUS_VME16: + node = 0; + nam = "cgtwo"; + break; + + default: + panic("cgtwoattach: impossible bustype"); + /* NOTREACHED */ + } sc->sc_fb.fb_type.fb_depth = 8; fb_setsize(&sc->sc_fb, sc->sc_fb.fb_type.fb_depth, @@ -158,8 +190,8 @@ cgtwoattach(parent, self, args) sc->sc_fb.fb_type.fb_cmsize = 256; sc->sc_fb.fb_type.fb_size = roundup(CG2_MAPPED_SIZE, NBPG); - printf(": cgtwo, %d x %d", sc->sc_fb.fb_type.fb_width, - sc->sc_fb.fb_type.fb_height); + printf(": %s, %d x %d", nam, + sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height); /* * When the ROM has mapped in a cgtwo display, the address @@ -167,30 +199,41 @@ cgtwoattach(parent, self, args) * registers ourselves. We only need the video RAM if we are * going to print characters via rconsole. */ - if (eep == NULL || eep->ee_diag.eed_console == EED_CONS_COLOR) - isconsole = (fbconstty != NULL); - else - isconsole = 0; - +#if defined(SUN4) + if (CPU_ISSUN4) { + struct eeprom *eep = (struct eeprom *)eeprom_va; + /* + * Assume this is the console if there's no eeprom info + * to be found. + */ + if (eep == NULL || eep->eeConsole == EE_CONS_COLOR) + isconsole = (fbconstty != NULL); + else + isconsole = 0; + } +#endif sc->sc_phys = ca->ca_ra.ra_reg[0]; sc->sc_bustype = ca->ca_bustype; if ((sc->sc_fb.fb_pixels = ca->ca_ra.ra_vaddr) == NULL && isconsole) { /* this probably cannot happen, but what the heck */ sc->sc_fb.fb_pixels = mapiodev(ca->ca_ra.ra_reg, CG2_PIXMAP_OFF, - CG2_PIXMAP_SIZE, ca->ca_bustype); + CG2_PIXMAP_SIZE, + PMAP_VME32/*ca->ca_bustype*/); } #ifndef offsetof #define offsetof(type, member) ((size_t)(&((type *)0)->member)) #endif - sc->sc_reg = (volatile struct cg2statusreg *)mapiodev(ca->ca_ra.ra_reg, - CG2_ROPMEM_OFF + offsetof(struct cg2fb, status.reg), - sizeof(struct cg2statusreg), ca->ca_bustype); + sc->sc_reg = (volatile struct cg2statusreg *) + mapiodev(ca->ca_ra.ra_reg, + CG2_ROPMEM_OFF + offsetof(struct cg2fb, status.reg), + sizeof(struct cg2statusreg), ca->ca_bustype); - sc->sc_cmap = (volatile u_short *)mapiodev(ca->ca_ra.ra_reg, - CG2_ROPMEM_OFF + offsetof(struct cg2fb, redmap[0]), - 3 * CG2_CMSIZE, ca->ca_bustype); + sc->sc_cmap = (volatile u_short *) + mapiodev(ca->ca_ra.ra_reg, + CG2_ROPMEM_OFF + offsetof(struct cg2fb, redmap[0]), + 3 * CG2_CMSIZE, ca->ca_bustype); if (isconsole) { printf(" (console)\n"); @@ -199,8 +242,9 @@ cgtwoattach(parent, self, args) #endif } else printf("\n"); - if (isconsole) - fb_attach(&sc->sc_fb); + + if (node == fbnode || CPU_ISSUN4) + fb_attach(&sc->sc_fb, isconsole); } int @@ -211,7 +255,7 @@ cgtwoopen(dev, flags, mode, p) { int unit = minor(dev); - if (unit >= cgtwocd.cd_ndevs || cgtwocd.cd_devs[unit] == NULL) + if (unit >= cgtwo_cd.cd_ndevs || cgtwo_cd.cd_devs[unit] == NULL) return (ENXIO); return (0); } @@ -234,9 +278,8 @@ cgtwoioctl(dev, cmd, data, flags, p) int flags; struct proc *p; { - register struct cgtwo_softc *sc = cgtwocd.cd_devs[minor(dev)]; + register struct cgtwo_softc *sc = cgtwo_cd.cd_devs[minor(dev)]; register struct fbgattr *fba; - int error; switch (cmd) { @@ -257,10 +300,10 @@ cgtwoioctl(dev, cmd, data, flags, p) break; case FBIOGETCMAP: - return cgtwogetcmap(sc, data); + return cgtwogetcmap(sc, (struct fbcmap *) data); case FBIOPUTCMAP: - return cgtwoputcmap(sc, data); + return cgtwoputcmap(sc, (struct fbcmap *) data); case FBIOGVIDEO: *(int *)data = sc->sc_reg->video_enab; @@ -284,7 +327,6 @@ cgtwounblank(dev) struct device *dev; { struct cgtwo_softc *sc = (struct cgtwo_softc *)dev; - sc->sc_reg->video_enab = 1; } @@ -381,7 +423,7 @@ cgtwommap(dev, off, prot) dev_t dev; int off, prot; { - register struct cgtwo_softc *sc = cgtwocd.cd_devs[minor(dev)]; + register struct cgtwo_softc *sc = cgtwo_cd.cd_devs[minor(dev)]; if (off & PGOFSET) panic("cgtwommap"); @@ -389,5 +431,5 @@ cgtwommap(dev, off, prot) if ((unsigned)off >= sc->sc_fb.fb_type.fb_size) return (-1); - return (REG2PHYS(&sc->sc_phys, off, PMAP_VME32) | PMAP_NC); + return (REG2PHYS(&sc->sc_phys, off, PMAP_VME32/*sc->sc_bustype*/) | PMAP_NC); } diff --git a/sys/arch/sparc/dev/cons.c b/sys/arch/sparc/dev/cons.c index d4e096bf88d..08df311233b 100644 --- a/sys/arch/sparc/dev/cons.c +++ b/sys/arch/sparc/dev/cons.c @@ -1,4 +1,4 @@ -/* $NetBSD: cons.c,v 1.15 1995/07/13 12:02:19 pk Exp $ */ +/* $NetBSD: cons.c,v 1.23.4.1 1996/06/02 09:07:53 mrg Exp $ */ /* * Copyright (c) 1992, 1993 @@ -49,7 +49,6 @@ */ #include <sys/param.h> -#include <sys/types.h> #include <sys/proc.h> #include <sys/systm.h> #include <sys/ioctl.h> @@ -57,11 +56,18 @@ #include <sys/file.h> #include <sys/conf.h> +#include <dev/cons.h> + #include <machine/bsd_openprom.h> +#include <machine/eeprom.h> #include <machine/psl.h> -#ifdef SUN4 +#include <machine/cpu.h> +#include <machine/kbd.h> +#if defined(SUN4) #include <machine/oldmon.h> #endif +#include <machine/autoconf.h> +#include <machine/conf.h> #include "zs.h" @@ -71,25 +77,25 @@ int rom_console_input; /* when set, hardclock calls cnrom() */ int cons_ocount; /* output byte count */ -extern struct promvec *promvec; - /* * The output driver may munge the minor number in cons.t_dev. */ struct tty cons; /* rom console tty device */ -static void (*fcnstop) __P((struct tty *, int)); +static int (*fcnstop) __P((struct tty *, int)); static void cnstart __P((struct tty *)); -void cnstop __P((struct tty *, int)); +int cnstop __P((struct tty *, int)); static void cnfbstart __P((struct tty *)); -static void cnfbstop __P((struct tty *, int)); +static int cnfbstop __P((struct tty *, int)); static void cnfbdma __P((void *)); +static struct tty *xxcntty __P((dev_t)); extern char char_type[]; -/*XXX*/static struct tty * -cntty() +/*XXX*/ +static struct tty * +xxcntty(dev_t dev) { return &cons; } @@ -99,16 +105,121 @@ consinit() { register struct tty *tp = &cons; register int in, out; - void zsconsole(); -/*XXX*/ cdevsw[0].d_tty = cntty; +/*XXX*/ cdevsw[0].d_tty = xxcntty; tp->t_dev = makedev(0, 0); /* /dev/console */ tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; tp->t_param = (int (*)(struct tty *, struct termios *))nullop; - in = *promvec->pv_stdin; - out = *promvec->pv_stdout; - switch (in) { + if (promvec->pv_romvec_vers > 2) { + /* We need to probe the PROM device tree */ + register int node,fd; + char buffer[128]; + register struct nodeops *no; + register struct v2devops *op; + register char *cp; + extern int fbnode; + + in = out = -1; + no = promvec->pv_nodeops; + op = &promvec->pv_v2devops; + + node = findroot(); + if (no->no_proplen(node, "stdin-path") >= sizeof(buffer)) { + printf("consinit: increase buffer size and recompile\n"); + goto setup_output; + } + /* XXX: fix above */ + + no->no_getprop(node, "stdin-path",buffer); + + /* + * Open an "instance" of this device. + * You'd think it would be appropriate to call v2_close() + * on the handle when we're done with it. But that seems + * to cause the device to shut down somehow; for the moment, + * we simply leave it open... + */ + if ((fd = op->v2_open(buffer)) == 0 || + (node = op->v2_fd_phandle(fd)) == 0) { + printf("consinit: bogus stdin path %s.\n",buffer); + goto setup_output; + } + if (no->no_proplen(node,"keyboard") >= 0) { + in = PROMDEV_KBD; + goto setup_output; + } + if (strcmp(getpropstring(node,"device_type"),"serial") != 0) { + /* not a serial, not keyboard. what is it?!? */ + in = -1; + goto setup_output; + } + /* + * At this point we assume the device path is in the form + * ....device@x,y:a for ttya and ...device@x,y:b for ttyb. + * If it isn't, we defer to the ROM + */ + cp = buffer; + while (*cp) + cp++; + cp -= 2; +#ifdef DEBUG + if (cp < buffer) + panic("consinit: bad stdin path %s",buffer); +#endif + /* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */ + if (cp[0]==':' && cp[1] >= 'a' && cp[1] <= 'z') + in = PROMDEV_TTYA + (cp[1] - 'a'); + /* else use rom */ +setup_output: + node = findroot(); + if (no->no_proplen(node, "stdout-path") >= sizeof(buffer)) { + printf("consinit: increase buffer size and recompile\n"); + goto setup_console; + } + /* XXX: fix above */ + + no->no_getprop(node, "stdout-path", buffer); + + if ((fd = op->v2_open(buffer)) == 0 || + (node = op->v2_fd_phandle(fd)) == 0) { + printf("consinit: bogus stdout path %s.\n",buffer); + goto setup_output; + } + if (strcmp(getpropstring(node,"device_type"),"display") == 0) { + /* frame buffer output */ + out = PROMDEV_SCREEN; + fbnode = node; + } else if (strcmp(getpropstring(node,"device_type"), "serial") + != 0) { + /* not screen, not serial. Whatzit? */ + out = -1; + } else { /* serial console. which? */ + /* + * At this point we assume the device path is in the + * form: + * ....device@x,y:a for ttya, etc. + * If it isn't, we defer to the ROM + */ + cp = buffer; + while (*cp) + cp++; + cp -= 2; +#ifdef DEBUG + if (cp < buffer) + panic("consinit: bad stdout path %s",buffer); +#endif + /* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */ + if (cp[0]==':' && cp[1] >= 'a' && cp[1] <= 'z') + out = PROMDEV_TTYA + (cp[1] - 'a'); + else out = -1; + } + } else { + in = *promvec->pv_stdin; + out = *promvec->pv_stdout; + } +setup_console: + switch (in) { #if NZS > 0 case PROMDEV_TTYA: zsconsole(tp, 0, 0, NULL); @@ -152,12 +263,13 @@ consinit() default: printf("unknown console output sink %d; using rom\n", out); tp->t_oproc = cnstart; - fcnstop = (void (*)(struct tty *, int))nullop; + fcnstop = (int (*)(struct tty *, int))nullop; break; } } /* ARGSUSED */ +int cnopen(dev, flag, mode, p) dev_t dev; int flag, mode; @@ -165,12 +277,42 @@ cnopen(dev, flag, mode, p) { register struct tty *tp = &cons; static int firstopen = 1; + static int rows = 0, cols = 0; - if(firstopen) { + if (firstopen) { clalloc(&tp->t_rawq, 1024, 1); clalloc(&tp->t_canq, 1024, 1); /* output queue doesn't need quoting */ clalloc(&tp->t_outq, 1024, 0); + tty_attach(tp); + /* + * get the console struct winsize. + */ + if (CPU_ISSUN4COR4M) { + int i; + char *prop; + + if ((prop = getpropstring(optionsnode, "screen-#rows"))) { + i = 0; + while (*prop != '\0') + i = i * 10 + *prop++ - '0'; + rows = (unsigned short)i; + } + if ((prop = getpropstring(optionsnode, "screen-#columns"))) { + i = 0; + while (*prop != '\0') + i = i * 10 + *prop++ - '0'; + cols = (unsigned short)i; + } + } + if (CPU_ISSUN4) { + struct eeprom *ep = (struct eeprom *)eeprom_va; + + if (ep) { + rows = (u_short)ep->eeTtyRows; + cols = (u_short)ep->eeTtyCols; + } + } firstopen = 0; } @@ -186,12 +328,15 @@ cnopen(dev, flag, mode, p) tp->t_state = TS_ISOPEN | TS_CARR_ON; (void)(*tp->t_param)(tp, &tp->t_termios); ttsetwater(tp); + tp->t_winsize.ws_row = rows; + tp->t_winsize.ws_col = cols; } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) return (EBUSY); return ((*linesw[tp->t_line].l_open)(dev, tp)); } /* ARGSUSED */ +int cnclose(dev, flag, mode, p) dev_t dev; int flag, mode; @@ -205,6 +350,7 @@ cnclose(dev, flag, mode, p) } /* ARGSUSED */ +int cnread(dev, uio, flag) dev_t dev; struct uio *uio; @@ -216,19 +362,21 @@ cnread(dev, uio, flag) } /* ARGSUSED */ +int cnwrite(dev, uio, flag) dev_t dev; struct uio *uio; int flag; { register struct tty *tp; - + if ((tp = constty) == NULL || (tp->t_state & (TS_CARR_ON|TS_ISOPEN)) != (TS_CARR_ON|TS_ISOPEN)) tp = &cons; return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); } +int cnioctl(dev, cmd, data, flag, p) dev_t dev; u_long cmd; @@ -258,6 +406,7 @@ cnioctl(dev, cmd, data, flag, p) return (ENOTTY); } +int cnselect(dev, which, p) dev_t dev; int which; @@ -281,9 +430,9 @@ cnstart(tp) register int c, s; register union { void (*v1)__P((int)); - void (*v3)__P((int, u_char *, int)); + int (*v3)__P((int, void *, int)); } putc; - register int fd, v; + register int fd = 0, v; s = spltty(); if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { @@ -291,7 +440,7 @@ cnstart(tp) return; } if ((v = promvec->pv_romvec_vers) > 2) { - putc.v3 = (void (*))promvec->pv_v2devops.v2_write; + putc.v3 = promvec->pv_v2devops.v2_write; fd = *promvec->pv_v2bootargs.v2_fd1; } else putc.v1 = promvec->pv_putchar; @@ -304,7 +453,7 @@ cnstart(tp) */ (void) splhigh(); if (v > 2) { - u_char c0 = c & 0177; + unsigned char c0 = c & 0177; (*putc.v3)(fd, &c0, 1); } else (*putc.v1)(c & 0177); @@ -318,12 +467,13 @@ cnstart(tp) splx(s); } -void +int cnstop(tp, flag) register struct tty *tp; int flag; { - (*fcnstop)(tp, flag); + (void)(*fcnstop)(tp, flag); + return 0; } /* @@ -367,7 +517,7 @@ cnfbstart(tp) /* * Stop frame buffer output: just assert TS_FLUSH if necessary. */ -static void +static int cnfbstop(tp, flag) register struct tty *tp; int flag; @@ -377,6 +527,7 @@ cnfbstop(tp, flag) if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY) tp->t_state |= TS_FLUSH; splx(s); + return 0; } /* @@ -387,7 +538,7 @@ cnfbdma(tpaddr) void *tpaddr; { register struct tty *tp = tpaddr; - register char *p, *q; + register unsigned char *p, *q; register int n, c, s; s = spltty(); /* paranoid */ @@ -406,7 +557,7 @@ cnfbdma(tpaddr) (*promvec->pv_v2devops.v2_write) (*promvec->pv_v2bootargs.v2_fd1, p, n); } else - (*promvec->pv_putstr)(p, n); + (*promvec->pv_putstr)((char *)p, n); ndflush(&tp->t_outq, n); } if (tp->t_line) @@ -423,6 +574,7 @@ cnfbdma(tpaddr) volatile int cn_rxc = -1; /* XXX receive `silo' */ /* called from hardclock, which is above spltty, so no tty calls! */ +int cnrom() { register int c; @@ -442,6 +594,7 @@ cnrom() } /* pseudo console software interrupt scheduled when cnrom() returns 1 */ +void cnrint() { register struct tty *tp; @@ -466,6 +619,7 @@ cnrint() (*linesw[tp->t_line].l_rint)(c, tp); } +int cngetc() { register int s, c; @@ -473,30 +627,30 @@ cngetc() if (promvec->pv_romvec_vers > 2) { register int n = 0; unsigned char c0; + s = splhigh(); while (n <= 0) { - s = splhigh(); n = (*promvec->pv_v2devops.v2_read) (*promvec->pv_v2bootargs.v2_fd0, &c0, 1); - splx(s); } + splx(s); c = c0; } else { -#ifdef SUN4 +#if defined(SUN4) /* SUN4 PROM: must turn off echo to avoid double char echo */ extern struct om_vector *oldpvec; - int saveecho; + int saveecho = 0; #endif s = splhigh(); -#ifdef SUN4 - if (cputyp == CPU_SUN4) { +#if defined(SUN4) + if (CPU_ISSUN4) { saveecho = *(oldpvec->echo); *(oldpvec->echo) = 0; } #endif c = (*promvec->pv_getchar)(); -#ifdef SUN4 - if (cputyp == CPU_SUN4) +#if defined(SUN4) + if (CPU_ISSUN4) *(oldpvec->echo) = saveecho; #endif splx(s); @@ -506,6 +660,7 @@ cngetc() return (c); } +void cnputc(c) register int c; { @@ -523,6 +678,7 @@ cnputc(c) splx(s); } +void cnpollc(on) int on; { diff --git a/sys/arch/sparc/dev/dma.c b/sys/arch/sparc/dev/dma.c index 54be0c4fdf8..ee40392c0fe 100644 --- a/sys/arch/sparc/dev/dma.c +++ b/sys/arch/sparc/dev/dma.c @@ -1,35 +1,7 @@ -/* $NetBSD: dma.c,v 1.8 1995/02/01 12:37:21 pk Exp $ */ +/* $NetBSD: dma.c,v 1.28.2.2 1996/07/02 23:46:29 jtc Exp $ */ /* - * Copyright (c) 1995 Theo de Raadt - * - * 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 under OpenBSD by - * Theo de Raadt. - * 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. - * + * Copyright (c) 1994 Paul Kranenburg. All rights reserved. * Copyright (c) 1994 Peter Galbavy. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -77,46 +49,63 @@ #include <scsi/scsiconf.h> #include <sparc/dev/sbusvar.h> -#include <sparc/dev/sbusreg.h> #include <sparc/dev/dmareg.h> #include <sparc/dev/dmavar.h> #include <sparc/dev/espreg.h> #include <sparc/dev/espvar.h> -#include <sparc/sparc/cache.h> - -/*#define DMA_TEST*/ - -extern int sbus_print __P((void *, char *)); - +int dmaprint __P((void *, char *)); void dmaattach __P((struct device *, struct device *, void *)); int dmamatch __P((struct device *, void *, void *)); +void dma_reset __P((struct dma_softc *)); +void dma_enintr __P((struct dma_softc *)); +int dma_isintr __P((struct dma_softc *)); +int espdmaintr __P((struct dma_softc *)); +int ledmaintr __P((struct dma_softc *)); +int dma_setup __P((struct dma_softc *, caddr_t *, size_t *, + int, size_t *)); +void dma_go __P((struct dma_softc *)); + +struct cfattach dma_ca = { + sizeof(struct dma_softc), dmamatch, dmaattach +}; -struct cfdriver dmacd = { - NULL, "dma", dmamatch, dmaattach, - DV_DULL, sizeof(struct dma_softc) +struct cfdriver dma_cd = { + NULL, "dma", DV_DULL }; -struct cfdriver ledmacd = { - NULL, "ledma", dmamatch, dmaattach, - DV_DULL, sizeof(struct dma_softc) +struct cfattach ledma_ca = { + sizeof(struct dma_softc), matchbyname, dmaattach }; -struct cfdriver espdmacd = { - NULL, "espdma", dmamatch, dmaattach, - DV_DULL, sizeof(struct dma_softc) +struct cfdriver ledma_cd = { + NULL, "ledma", DV_DULL }; int +dmaprint(aux, name) + void *aux; + char *name; +{ + register struct confargs *ca = aux; + + if (name) + printf("[%s at %s]", ca->ca_ra.ra_name, name); + printf(" slot 0x%x offset 0x%x", ca->ca_slot, ca->ca_offset); + return (UNCONF); +} + +int dmamatch(parent, vcf, aux) - struct device *parent; - void *vcf, *aux; + struct device *parent; + void *vcf, *aux; { - struct cfdata *cf = vcf; + struct cfdata *cf = vcf; register struct confargs *ca = aux; register struct romaux *ra = &ca->ca_ra; - if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) + if (strcmp(cf->cf_driver->cd_name, ra->ra_name) && + strcmp("espdma", ra->ra_name)) return (0); if (ca->ca_bustype == BUS_SBUS) return (1); @@ -129,353 +118,408 @@ dmamatch(parent, vcf, aux) */ void dmaattach(parent, self, aux) - struct device *parent, *self; - void *aux; + struct device *parent, *self; + void *aux; { register struct confargs *ca = aux; - struct confargs oca; - struct dma_softc *sc = (void *)self; - int node, base, slot; - char *name; - - /* XXX modifying ra_vaddr is bad! */ - if (ca->ca_ra.ra_vaddr == NULL) - ca->ca_ra.ra_vaddr = mapiodev(ca->ca_ra.ra_reg, 0, - ca->ca_ra.ra_len, ca->ca_bustype); - if ((u_long)ca->ca_ra.ra_paddr & PGOFSET) - (u_long)ca->ca_ra.ra_vaddr |= ((u_long)ca->ca_ra.ra_paddr & PGOFSET); + struct dma_softc *sc = (void *)self; +#if defined(SUN4C) || defined(SUN4M) + int node; + struct confargs oca; + char *name; +#endif + + if (ca->ca_ra.ra_vaddr == NULL || ca->ca_ra.ra_nvaddrs == 0) + ca->ca_ra.ra_vaddr = + mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len, + ca->ca_bustype); + sc->sc_regs = (struct dma_regs *) ca->ca_ra.ra_vaddr; /* - * What happens here is that if the esp driver has not been - * configured, then this returns a NULL pointer. Then when the - * esp actually gets configured, it does the opposing test, and - * if the sc->sc_dma field in it's softc is NULL, then tries to - * find the matching dma driver. + * If we're a ledma, check to see what cable type is currently + * active and set the appropriate bit in the ledma csr so that + * it gets used. If we didn't netboot, the PROM won't have the + * "cable-selection" property; default to TP and then the user + * can change it via a "link0" option to ifconfig. + */ + if (strcmp(ca->ca_ra.ra_name, "ledma") == 0) { + char *cabletype = getpropstring(ca->ca_ra.ra_node, + "cable-selection"); + if (strcmp(cabletype, "tpe") == 0) { + sc->sc_regs->csr |= DE_AUI_TP; + } else if (strcmp(cabletype, "aui") == 0) { + sc->sc_regs->csr &= ~DE_AUI_TP; + } else { + /* assume TP if nothing there */ + sc->sc_regs->csr |= DE_AUI_TP; + } + delay(20000); /* manual says we need 20ms delay */ + } + + /* + * Get transfer burst size from PROM and plug it into the controller + * registers. This is needed on the Sun4m; do others need it too? + * XXX */ - sc->sc_esp = ((struct esp_softc *) - getdevunit("esp", sc->sc_dev.dv_unit)); - if (sc->sc_esp) - sc->sc_esp->sc_dma = sc; + if (CPU_ISSUN4M) { + sc->sc_burst = getpropint(ca->ca_ra.ra_node,"burst-sizes", -1); + if (sc->sc_burst == -1) { + /* check parent SBus for burst sizes */ + if (((struct sbus_softc *)parent)->sc_burst == 0) + sc->sc_burst = SBUS_BURST_32 - 1; /* 1->16 */ + else + sc->sc_burst = + ((struct sbus_softc *)parent)->sc_burst; + } + sc->sc_regs->csr &= ~D_BURST_SIZE; /* must clear first */ + if (sc->sc_burst & SBUS_BURST_32) { + sc->sc_regs->csr |= D_BURST_32; + } else if (sc->sc_burst & SBUS_BURST_16) { + sc->sc_regs->csr |= D_BURST_16; + } else if (strcmp(ca->ca_ra.ra_name,"espdma") == 0) { + /* only espdma supports non-burst */ + sc->sc_regs->csr |= D_BURST_0; +#ifdef DIAGNOSTIC + } else { + printf(" <unknown burst size 0x%x>", sc->sc_burst); +#endif + } + } printf(": rev "); sc->sc_rev = sc->sc_regs->csr & D_DEV_ID; switch (sc->sc_rev) { - case DMAREV_4300: - printf("4/300\n"); + case DMAREV_0: + printf("0"); break; case DMAREV_1: - printf("1\n"); - break; - case DMAREV_ESC1: - printf("ESC1\n"); + printf("1"); break; case DMAREV_PLUS: - printf("1+\n"); + printf("1+"); break; case DMAREV_2: - printf("2\n"); + printf("2"); break; default: - printf("unknown\n"); + printf("unknown"); + } + printf("\n"); + + /* indirect functions */ + if (sc->sc_dev.dv_cfdata->cf_attach == &dma_ca) { + sc->intr = espdmaintr; + } else { + sc->intr = ledmaintr; } + sc->enintr = dma_enintr; + sc->isintr = dma_isintr; + sc->reset = dma_reset; + sc->setup = dma_setup; + sc->go = dma_go; + + sc->sc_node = ca->ca_ra.ra_node; + if (CPU_ISSUN4) + goto espsearch; #if defined(SUN4C) || defined(SUN4M) - if (ca->ca_bustype == BUS_SBUS) { - sc->sc_node = ca->ca_ra.ra_node; + if (ca->ca_bustype == BUS_SBUS) sbus_establish(&sc->sc_sd, &sc->sc_dev); + /* Propagate bootpath */ + if (ca->ca_ra.ra_bp != NULL && + (strcmp(ca->ca_ra.ra_bp->name, "espdma") == 0 || + strcmp(ca->ca_ra.ra_bp->name, "dma") == 0 || + strcmp(ca->ca_ra.ra_bp->name, "ledma") == 0)) + oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1; + else + oca.ca_ra.ra_bp = NULL; + + /* search through children */ + node = firstchild(sc->sc_node); + if (node != 0) do { + name = getpropstring(node, "name"); + if (!romprop(&oca.ca_ra, name, node)) + continue; + + sbus_translate(parent, &oca); + oca.ca_bustype = BUS_SBUS; + (void) config_found(&sc->sc_dev, (void *)&oca, dmaprint); + } while ((node = nextsibling(node)) != 0); else +#endif /* SUN4C || SUN4M */ + + if (strcmp(ca->ca_ra.ra_name, "dma") == 0) { +espsearch: /* - * If the device is in an SBUS slave slot, report - * it (but we don't care, because the corresponding - * ESP will also realize the same thing.) + * find the ESP by poking around the esp device structures + * + * What happens here is that if the esp driver has not been + * configured, then this returns a NULL pointer. Then when the + * esp actually gets configured, it does the opposing test, and + * if the sc->sc_dma field in it's softc is NULL, then tries to + * find the matching dma driver. + * */ - (void) sbus_slavecheck(self, ca); + sc->sc_esp = (struct esp_softc *) + getdevunit("esp", sc->sc_dev.dv_unit); /* - * if our name is not "dma", we may have subdevices - * below us in the device tree (like an esp) - * XXX: TDR: should we do this even if it is "dma"? + * and a back pointer to us, for DMA */ - if (strcmp(ca->ca_ra.ra_name, "dma") == 0) - return; - - /* search through children */ - for (node = firstchild(sc->sc_node); node; - node = nextsibling(node)) { - name = getpropstring(node, "name"); - if (!romprop(&oca.ca_ra, name, node)) - continue; - - /* - * advance bootpath if it currently points to us - * XXX There appears to be strangeness in the unit - * number on at least one espdma system (SS5 says - * espdma5, but nothing is available to compare - * against that digit 5... - */ - if (ca->ca_ra.ra_bp && - !strcmp(ca->ca_ra.ra_bp->name, ca->ca_ra.ra_name) && - ca->ca_ra.ra_bp->val[1] == (int)ca->ca_ra.ra_paddr) - oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1; - else - oca.ca_ra.ra_bp = NULL; - - base = (int)oca.ca_ra.ra_paddr; - if (SBUS_ABS(base)) { - oca.ca_slot = SBUS_ABS_TO_SLOT(base); - oca.ca_offset = SBUS_ABS_TO_OFFSET(base); - } else { - oca.ca_slot = slot = ca->ca_ra.ra_iospace; - oca.ca_offset = base; - oca.ca_ra.ra_paddr = (void *)SBUS_ADDR(slot, base); - } - oca.ca_bustype = BUS_SBUS; - (void) config_found(&sc->sc_dev, (void *)&oca, sbus_print); - } - + if (sc->sc_esp) + sc->sc_esp->sc_dma = sc; } -#endif /* SUN4C || SUN4M */ } void -dmareset(sc) - struct dma_softc *sc; +dma_reset(sc) + struct dma_softc *sc; { - DMAWAIT_PEND(sc); + DMAWAIT(sc); + DMA_DRAIN(sc); /* Drain (DMA rev 1) */ + DMACSR(sc) &= ~D_EN_DMA; /* Stop DMA */ + DMAWAIT1(sc); /* let things drain */ DMACSR(sc) |= D_RESET; /* reset DMA */ DELAY(200); /* what should this be ? */ + DMAWAIT1(sc); DMACSR(sc) &= ~D_RESET; /* de-assert reset line */ + DMACSR(sc) |= D_INT_EN; /* enable interrupts */ + if (sc->sc_rev > DMAREV_1) + DMACSR(sc) |= D_FASTER; + sc->sc_active = 0; /* and of course we aren't */ +} - switch (sc->sc_rev) { - case DMAREV_1: - case DMAREV_4300: - case DMAREV_ESC1: - break; - case DMAREV_PLUS: - case DMAREV_2: - if (sc->sc_esp->sc_rev >= ESP100A) - DMACSR(sc) |= D_FASTER; - break; - } - sc->sc_active = 0; /* and of course we aren't */ +void +dma_enintr(sc) + struct dma_softc *sc; +{ + sc->sc_regs->csr |= D_INT_EN; } int -dmapending(sc) +dma_isintr(sc) struct dma_softc *sc; { return (sc->sc_regs->csr & (D_INT_PEND|D_ERR_PEND)); } -/* bytes between loc and the end of this 16M region of memory */ -#define DMAMAX(loc) (0x01000000 - ((loc) & 0x00ffffff)) +#define DMAMAX(a) (0x01000000 - ((a) & 0x00ffffff)) -#define ESPMAX ((sc->sc_esp->sc_rev > ESP100A) ? \ - (16 * 1024 * 1024) : (64 * 1024)) /* - * Start a dma transfer or keep it going. - * We do the loading of the transfer counter. - * XXX: what about write-back caches? + * setup a dma transfer */ -void -dmastart(sc, addr, len, datain, poll) - struct dma_softc *sc; - void *addr; - size_t *len; - int datain, poll; +int +dma_setup(sc, addr, len, datain, dmasize) + struct dma_softc *sc; + caddr_t *addr; + size_t *len; + int datain; + size_t *dmasize; /* IN-OUT */ { - struct espregs *espr = sc->sc_esp->sc_regs; - int size; + u_long csr; - if (sc->sc_active) - panic("dma: dmastart() called while active\n"); + /* clear errors and D_TC flag */ + DMAWAIT(sc); + DMA_DRAIN(sc); /* ? */ + DMAWAIT1(sc); + DMACSR(sc) |= D_INVALIDATE; + DMAWAIT1(sc); +#if 0 + DMACSR(sc) &= ~D_INT_EN; +#endif sc->sc_dmaaddr = addr; sc->sc_dmalen = len; - sc->sc_dmapolling = poll; - sc->sc_dmadev2mem = datain; + + ESP_DMA(("%s: start %d@%p,%d\n", sc->sc_dev.dv_xname, + *sc->sc_dmalen, *sc->sc_dmaaddr, datain ? 1 : 0)); /* * the rules say we cannot transfer more than the limit * of this DMA chip (64k for old and 16Mb for new), * and we cannot cross a 16Mb boundary. */ - size = min(*sc->sc_dmalen, ESPMAX); - size = min(size, DMAMAX((size_t) *sc->sc_dmaaddr)); - sc->sc_segsize = size; - -#ifdef DMA_TEST - printf("%s: start %d@0x%08x [%s scsi] [chunk=%d] %d\n", - sc->sc_dev.dv_xname, - *sc->sc_dmalen, *sc->sc_dmaaddr, - datain ? "read from" : "write to", - sc->sc_segsize, poll); -#endif + *dmasize = sc->sc_dmasize = + min(*dmasize, DMAMAX((size_t) *sc->sc_dmaaddr)); - espr->espr_tcl = size; - espr->espr_tcm = size >> 8; - if (sc->sc_esp->sc_rev > ESP100A) - espr->espr_tch = size >> 16; - espr->espr_cmd = ESPCMD_DMA|ESPCMD_NOP; /* load the count in */ + ESP_DMA(("dma_setup: dmasize = %d\n", sc->sc_dmasize)); - DMADDR(sc) = *sc->sc_dmaaddr; - DMACSR(sc) = (DMACSR(sc) & ~(D_WRITE|D_INT_EN)) | D_EN_DMA | - (datain ? D_WRITE : 0) | (poll ? 0 : D_INT_EN); + /* Program the DMA address */ + if (CPU_ISSUN4M && sc->sc_dmasize) { + /* + * Use dvma mapin routines to map the buffer into DVMA space. + */ + sc->sc_dvmaaddr = *sc->sc_dmaaddr; + sc->sc_dvmakaddr = kdvma_mapin(sc->sc_dvmaaddr, + sc->sc_dmasize, 0); + if (sc->sc_dvmakaddr == NULL) + panic("dma: cannot allocate DVMA address"); + DMADDR(sc) = sc->sc_dvmakaddr; + } else + DMADDR(sc) = *sc->sc_dmaaddr; + + /* Setup DMA control register */ + csr = DMACSR(sc); + if (datain) + csr |= D_WRITE; + else + csr &= ~D_WRITE; + csr |= D_INT_EN; + DMACSR(sc) = csr; + + return 0; +} - /* and kick the SCSI */ - espr->espr_cmd = ESPCMD_DMA|ESPCMD_TRANS; +void +dma_go(sc) + struct dma_softc *sc; +{ + /* Start DMA */ + DMACSR(sc) |= D_EN_DMA; sc->sc_active = 1; } /* * Pseudo (chained) interrupt from the esp driver to kick the - * current running DMA transfer. espintr() cleans up errors. + * current running DMA transfer. I am replying on espintr() to + * pickup and clean errors for now * - * return 1 if a dma operation is being continued (for when all - * the data could not be transferred in one dma operation). + * return 1 if it was a DMA continue. */ int -dmaintr(sc, restart) - struct dma_softc *sc; - int restart; +espdmaintr(sc) + struct dma_softc *sc; { - struct espregs *espr = sc->sc_esp->sc_regs; - int trans = 0, resid; + int trans, resid; + u_long csr; + csr = DMACSR(sc); -#ifdef DMA_TEST - printf("%s: intr\n", sc->sc_dev.dv_xname); -#endif + ESP_DMA(("%s: intr: addr %p, csr %b\n", sc->sc_dev.dv_xname, + DMADDR(sc), csr, DMACSRBITS)); - if (DMACSR(sc) & D_ERR_PEND) { - printf("%s: error", sc->sc_dev.dv_xname); - if (sc->sc_rev == DMAREV_4300) - DMAWAIT_PEND(sc); + if (csr & D_ERR_PEND) { + DMACSR(sc) &= ~D_EN_DMA; /* Stop DMA */ DMACSR(sc) |= D_INVALIDATE; - return (0); + printf("%s: error: csr=%b\n", sc->sc_dev.dv_xname, + csr, DMACSRBITS); + return 0; } + /* This is an "assertion" :) */ if (sc->sc_active == 0) panic("dmaintr: DMA wasn't active"); - /* DMA has stopped, but flush it first */ - dmadrain(sc); - if (DMACSR(sc) & D_DRAINING) - printf("drain failed %d left\n", DMACSR(sc) & D_DRAINING); + /* clear errors and D_TC flag */ + DMAWAIT(sc); + DMA_DRAIN(sc); /* ? */ + DMAWAIT1(sc); + DMACSR(sc) |= D_INVALIDATE; + DMAWAIT1(sc); + + /* DMA has stopped */ DMACSR(sc) &= ~D_EN_DMA; sc->sc_active = 0; - /* - * XXX: The subtracting of resid and throwing away up to 31 - * bytes cannot be the best/right way to do this. There's got - * to be a better way, such as letting the DMA take control - * again and putting it into memory, or pulling it out and - * putting it in memory by ourselves. - * XXX in the meantime, just do this job silently - */ + if (sc->sc_dmasize == 0) { + /* A "Transfer Pad" operation completed */ + ESP_DMA(("dmaintr: discarded %d bytes (tcl=%d, tcm=%d)\n", + ESP_READ_REG(sc->sc_esp, ESP_TCL) | + (ESP_READ_REG(sc->sc_esp, ESP_TCM) << 8), + ESP_READ_REG(sc->sc_esp, ESP_TCL), + ESP_READ_REG(sc->sc_esp, ESP_TCM))); + return 0; + } + resid = 0; - if (!sc->sc_dmadev2mem && - (resid = (espr->espr_fflag & ESPFIFO_FF)) != 0) { -#if 0 - printf("empty FIFO of %d ", resid); -#endif - espr->espr_cmd = ESPCMD_FLUSH; - DELAY(1); + /* + * If a transfer onto the SCSI bus gets interrupted by the device + * (e.g. for a SAVEPOINTER message), the data in the FIFO counts + * as residual since the ESP counter registers get decremented as + * bytes are clocked into the FIFO. + */ + if (!(csr & D_WRITE) && + (resid = (ESP_READ_REG(sc->sc_esp, ESP_FFLAG) & ESPFIFO_FF)) != 0) { + ESP_DMA(("dmaintr: empty esp FIFO of %d ", resid)); + ESPCMD(sc->sc_esp, ESPCMD_FLUSH); + } + + if ((sc->sc_esp->sc_espstat & ESPSTAT_TC) == 0) { + /* + * `Terminal count' is off, so read the residue + * out of the ESP counter registers. + */ + resid += ( ESP_READ_REG(sc->sc_esp, ESP_TCL) | + (ESP_READ_REG(sc->sc_esp, ESP_TCM) << 8) | + ((sc->sc_esp->sc_cfg2 & ESPCFG2_FE) + ? (ESP_READ_REG(sc->sc_esp, ESP_TCH) << 16) + : 0)); + + if (resid == 0 && sc->sc_dmasize == 65536 && + (sc->sc_esp->sc_cfg2 & ESPCFG2_FE) == 0) + /* A transfer of 64K is encoded as `TCL=TCM=0' */ + resid = 65536; } - resid += espr->espr_tcl | (espr->espr_tcm << 8) | - (sc->sc_esp->sc_rev > ESP100A ? (espr->espr_tch << 16) : 0); - trans = sc->sc_segsize - resid; + + trans = sc->sc_dmasize - resid; if (trans < 0) { /* transferred < 0 ? */ printf("%s: xfer (%d) > req (%d)\n", - sc->sc_dev.dv_xname, trans, sc->sc_segsize); - trans = sc->sc_segsize; + sc->sc_dev.dv_xname, trans, sc->sc_dmasize); + trans = sc->sc_dmasize; } -#ifdef DMA_TEST - printf("dmaintr: resid=%d, trans=%d\n", resid, trans); -#endif + ESP_DMA(("dmaintr: tcl=%d, tcm=%d, tch=%d; trans=%d, resid=%d\n", + ESP_READ_REG(sc->sc_esp, ESP_TCL), + ESP_READ_REG(sc->sc_esp, ESP_TCM), + (sc->sc_esp->sc_cfg2 & ESPCFG2_FE) + ? ESP_READ_REG(sc->sc_esp, ESP_TCH) : 0, + trans, resid)); - if (sc->sc_dmadev2mem && vactype != VAC_NONE) + if (csr & D_WRITE) cache_flush(*sc->sc_dmaaddr, trans); - sc->sc_segsize -= trans; + if (CPU_ISSUN4M && sc->sc_dvmakaddr) + dvma_mapout((vm_offset_t)sc->sc_dvmakaddr, + (vm_offset_t)sc->sc_dvmaaddr, sc->sc_dmasize); + *sc->sc_dmalen -= trans; *sc->sc_dmaaddr += trans; -#ifdef DMA_TEST - printf("%s: %d/%d bytes left\n", sc->sc_dev.dv_xname, - *sc->sc_dmalen, sc->sc_segsize); -#endif - - /* completely finished with the DMA transaction */ - if (sc->sc_segsize == 0 && *sc->sc_dmalen == 0) - return (0); +#if 0 /* this is not normal operation just yet */ + if (*sc->sc_dmalen == 0 || + sc->sc_esp->sc_phase != sc->sc_esp->sc_prevphase) + return 0; - if (restart == 0) - return (1); /* and again */ - dmastart(sc, sc->sc_dmaaddr, sc->sc_dmalen, sc->sc_dmadev2mem, - sc->sc_dmapolling); - return (1); -} - -/* - * We have to ask rev 1 and 4/300 dma controllers to drain their fifo. - * Apparently the other chips have drained by the time we get an - * interrupt, but we check anyways. - */ -void -dmadrain(sc) - struct dma_softc *sc; -{ - switch (sc->sc_rev) { - case DMAREV_1: - case DMAREV_4300: - case DMAREV_PLUS: - case DMAREV_2: - if (DMACSR(sc) & D_DRAINING) - DMAWAIT_DRAIN(sc); - break; - case DMAREV_ESC1: - DMAWAIT_PEND(sc) - DMAWAIT_DRAIN(sc); /* XXX: needed? */ - break; - } - DMACSR(sc) |= D_INVALIDATE; + dma_start(sc, sc->sc_dmaaddr, sc->sc_dmalen, DMACSR(sc) & D_WRITE); + return 1; +#endif + return 0; } /* - * XXX - * During autoconfig we are in polled mode and we execute some commands. - * eventually we execute the last polled command. esp interrupts go through - * the dma chip's D_INT_EN gate. thus, because we have our data, we're happy - * and return. the esp chip has not, however, become unbusy. as soon as we - * execute our first non-polled command, we find the esp state machine is - * non-idle. it has not finished getting off the scsi bus, because it didn't - * get interrupts (and the polled code has long since gone it's merry way.) - * - * therefore, whenever we finish with a polled mode command, we enable - * interrupts so that we can get our data. it is probably safe to do so, - * since the scsi transfer has happened without error. the interrupts that - * will happen have no bearing on the higher level scsi subsystem, since it - * just functions to let the esp chip "clean up" it's state. + * Pseudo (chained) interrupt from the le driver to handle DMA + * errors. + * + * XXX: untested */ -void -dmaenintr(sc) - struct dma_softc *sc; -{ - DMACSR(sc) |= D_INT_EN; -} - int -dmadisintr(sc) +ledmaintr(sc) struct dma_softc *sc; { - int x = DMACSR(sc) & D_INT_EN; + u_long csr; - DMACSR(sc) &= ~D_INT_EN; - return x; + csr = DMACSR(sc); + + if (csr & D_ERR_PEND) { + printf("Lance DMA error, see your doctor!\n"); + DMACSR(sc) &= ~D_EN_DMA; /* Stop DMA */ + DMACSR(sc) |= D_INVALIDATE; + printf("%s: error: csr=%b\n", sc->sc_dev.dv_xname, + (u_int)csr, DMACSRBITS); + } + return 1; } diff --git a/sys/arch/sparc/dev/dmareg.h b/sys/arch/sparc/dev/dmareg.h index d19c5c2960e..3998581845a 100644 --- a/sys/arch/sparc/dev/dmareg.h +++ b/sys/arch/sparc/dev/dmareg.h @@ -1,9 +1,7 @@ -/* $NetBSD: dmareg.h,v 1.5 1994/11/20 20:52:06 deraadt Exp $ */ +/* $NetBSD: dmareg.h,v 1.8 1996/04/22 02:34:58 abrown Exp $ */ /* * Copyright (c) 1994 Peter Galbavy. All rights reserved. - * Copyright (c) 1995 Theo de Raadt. All rights reserved. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -14,8 +12,7 @@ * 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 Peter Galbavy and - * Theo de Raadt. + * This product includes software developed by Peter Galbavy. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * @@ -31,51 +28,64 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define DMACSRBITS "\020\01INT\02ERR\03DR1\04DR2\05IEN\011WRITE\016ENCNT\017TC\032DMAON" + struct dma_regs { - volatile u_long csr; /* DMA CSR */ -#define D_INT_PEND 0x00000001 /* interrupt pending */ -#define D_ERR_PEND 0x00000002 /* error pending */ -#define D_DRAINING 0x0000000c /* fifo draining */ -#define D_INT_EN 0x00000010 /* interrupt enable */ -#define D_INVALIDATE 0x00000020 /* invalidate fifo */ -#define D_SLAVE_ERR 0x00000040 /* slave access size error */ -#define D_DRAIN 0x00000040 /* drain fifo if DMAREV_1 */ -#define D_RESET 0x00000080 /* reset scsi */ -#define D_WRITE 0x00000100 /* 1 = dev -> mem */ -#define D_EN_DMA 0x00000200 /* enable DMA requests */ -#define D_R_PEND 0x00000400 /* no reset/flush allowed! */ -#define D_BYTEADDR 0x00001800 /* next byte to be accessed by esp */ -#define D_EN_CNT 0x00002000 /* enable byte counter */ -#define D_TC 0x00004000 /* terminal count */ -#define D_ILLAC 0x00008000 /* enable lance ethernet */ -#define D_DSBL_CSR_DRN 0x00010000 /* disable fifo drain on csr */ -#define D_DSBL_SCSI_DRN 0x00020000 /* disable fifo drain on reg */ -#define D_BURST_SIZE 0x000c0000 /* sbus read/write burst size */ -#define D_DIAG 0x00100000 /* disable fifo drain on addr */ -#define D_TWO_CYCLE 0x00200000 /* 2 clocks per transfer */ -#define D_FASTER 0x00400000 /* 3 clocks per transfer */ -#define D_TCI_DIS 0x00800000 /* disable intr on D_TC */ -#define D_EN_NEXT 0x01000000 /* enable auto next address */ -#define D_DMA_ON 0x02000000 /* enable dma from scsi */ -#define D_A_LOADED 0x04000000 /* address loaded */ -#define D_NA_LOADED 0x08000000 /* next address loaded */ -#define D_DEV_ID 0xf0000000 /* device ID */ -#define DMAREV_4300 0x00000000 /* Sunray DMA */ -#define DMAREV_ESC1 0x40000000 /* ESC gate array */ -#define DMAREV_1 0x80000000 /* 'DMA' */ -#define DMAREV_PLUS 0x90000000 /* 'DMA+' */ -#define DMAREV_2 0xa0000000 /* 'DMA2' */ + volatile u_long csr; /* DMA CSR */ +#define D_INT_PEND 0x00000001 /* interrupt pending */ +#define D_ERR_PEND 0x00000002 /* error pending */ +#define D_DRAINING 0x0000000c /* fifo draining */ +#define D_INT_EN 0x00000010 /* interrupt enable */ +#define D_INVALIDATE 0x00000020 /* invalidate fifo */ +#define D_SLAVE_ERR 0x00000040 /* slave access size error */ +#define D_DRAIN 0x00000040 /* drain fifo if DMAREV_1 */ +#define D_RESET 0x00000080 /* reset scsi */ +#define D_WRITE 0x00000100 /* 1 = dev -> mem */ +#define D_EN_DMA 0x00000200 /* enable DMA requests */ +#define D_R_PEND 0x00000400 /* something only on ver < 2 */ +#define D_EN_CNT 0x00002000 /* enable byte counter */ +#define D_TC 0x00004000 /* terminal count */ +#define D_DSBL_CSR_DRN 0x00010000 /* disable fifo drain on csr */ +#define D_DSBL_SCSI_DRN 0x00020000 /* disable fifo drain on reg */ +#define D_BURST_SIZE 0x000c0000 /* sbus read/write burst size */ +#define D_BURST_0 0x00080000 /* no bursts (SCSI-only) */ +#define D_BURST_16 0x00040000 /* 16-byte bursts */ +#define D_BURST_32 0x00000000 /* 32-byte bursts */ +#define D_DIAG 0x00100000 /* disable fifo drain on addr */ +#define D_TWO_CYCLE 0x00200000 /* 2 clocks per transfer */ +#define D_FASTER 0x00400000 /* 3 clocks per transfer */ +#define DE_AUI_TP 0x00400000 /* 1 for TP, 0 for AUI */ +#define D_TCI_DIS 0x00800000 /* disable intr on D_TC */ +#define D_EN_NEXT 0x01000000 /* enable auto next address */ +#define D_DMA_ON 0x02000000 /* enable dma from scsi */ +#define D_A_LOADED 0x04000000 /* address loaded */ +#define D_NA_LOADED 0x08000000 /* next address loaded */ +#define D_DEV_ID 0xf0000000 /* device ID */ +#define DMAREV_0 0x00000000 /* Sunray DMA */ +#define DMAREV_1 0x80000000 /* 'DMA' */ +#define DMAREV_PLUS 0x90000000 /* 'DMA+' */ +#define DMAREV_2 0xa0000000 /* 'DMA2' */ - volatile caddr_t addr; -#define DMA_D_ADDR 0x01 /* DMA ADDR */ + volatile caddr_t addr; +#define DMA_D_ADDR 0x01 /* DMA ADDR (in u_longs) */ - /* - * some versions of dma controller lack the following - * two registers -- do not use them! - */ + volatile u_long bcnt; /* DMA COUNT (in u_longs) */ +#define D_BCNT_MASK 0x00ffffff /* only 24 bits */ - volatile u_long bcnt; /* DMA COUNT */ -#define D_BCNT_MASK 0x00ffffff /* only 24 bits */ + volatile u_long test; /* DMA TEST (in u_longs) */ +#define en_testcsr addr /* enet registers overlap */ +#define en_cachev bcnt +#define en_bar test - volatile u_long test; /* DMA TEST (in u_longs) */ }; + +/* + * PROM-reported DMA burst sizes for the SBus + */ +#define SBUS_BURST_1 0x1 +#define SBUS_BURST_2 0x2 +#define SBUS_BURST_4 0x4 +#define SBUS_BURST_8 0x8 +#define SBUS_BURST_16 0x10 +#define SBUS_BURST_32 0x20 +#define SBUS_BURST_64 0x40 diff --git a/sys/arch/sparc/dev/dmavar.h b/sys/arch/sparc/dev/dmavar.h index c5ebb58357c..6bc42333a98 100644 --- a/sys/arch/sparc/dev/dmavar.h +++ b/sys/arch/sparc/dev/dmavar.h @@ -1,10 +1,7 @@ -/* $NetBSD: dmavar.h,v 1.4 1994/11/27 00:08:34 deraadt Exp $ */ +/* $NetBSD: dmavar.h,v 1.8 1996/04/22 02:35:00 abrown Exp $ */ /* - * Copyright (c) 1994 Peter Galbavy - * Copyright (c) 1995 Theo de Raadt - * All rights reserved. - * + * Copyright (c) 1994 Peter Galbavy. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -15,8 +12,7 @@ * 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 Peter Galbavy and - * Theo de Raadt. + * This product includes software developed by Peter Galbavy. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * @@ -33,49 +29,62 @@ */ struct dma_softc { - struct device sc_dev; /* us as a device */ - struct sbusdev sc_sd; /* sbus device */ - struct esp_softc *sc_esp; /* my scsi */ - struct dma_regs *sc_regs; /* the registers */ + struct device sc_dev; /* us as a device */ + struct sbusdev sc_sd; /* sbus device */ + struct esp_softc *sc_esp; /* my scsi */ + struct le_softc *sc_le; /* my ethernet */ + struct dma_regs *sc_regs; /* the registers */ int sc_active; /* DMA active ? */ int sc_rev; /* revision */ int sc_node; /* PROM node ID */ - - size_t sc_segsize; /* current operation */ - void **sc_dmaaddr; + int sc_burst; /* DVMA burst size in effect */ + caddr_t sc_dvmakaddr; /* DVMA cookies */ + caddr_t sc_dvmaaddr; /* */ + size_t sc_dmasize; + caddr_t *sc_dmaaddr; size_t *sc_dmalen; - char sc_dmapolling; /* ... is polled */ - char sc_dmadev2mem; /* transfer direction */ + void (*reset)(struct dma_softc *); /* reset routine */ + void (*enintr)(struct dma_softc *); /* enable interrupts */ + int (*isintr)(struct dma_softc *); /* interrupt ? */ + int (*intr)(struct dma_softc *); /* interrupt ! */ + int (*setup)(struct dma_softc *, caddr_t *, size_t *, int, size_t *); + void (*go)(struct dma_softc *); }; -void dmareset __P((struct dma_softc *sc)); -void dmastart __P((struct dma_softc *sc, void *addr, - size_t *len, int datain, int poll)); -int dmaintr __P((struct dma_softc *sc, int restart)); -int dmapending __P((struct dma_softc *sc)); -void dmadrain __P((struct dma_softc *sc)); -void dmaenintr __P((struct dma_softc *sc)); -int dmadisintr __P((struct dma_softc *sc)); - #define DMACSR(sc) (sc->sc_regs->csr) #define DMADDR(sc) (sc->sc_regs->addr) -#define DMABCNT(sc) (sc->sc_regs->bcnt) -#define TIME_WAIT(cond, msg, sc) { \ - int count = 500000; \ - while (--count > 0 && (cond)) \ - DELAY(1); \ - if (count == 0) { \ - printf("CSR = %x\n", (sc)->sc_regs->csr); \ - panic(msg); \ - } \ -} +/* + * We are not allowed to touch the DMA "flush" and "drain" bits + * while it is still thinking about a request (DMA_RP). + */ + +/* + * TIME WAIT (to debug hanging machine problem) + */ + +#define TIME_WAIT(COND, MSG, SC) { int count = 500000; \ + while (--count > 0 && (COND)) DELAY(1); \ + if (count == 0) { \ + printf("CSR = %lx\n",\ + SC->sc_regs->csr);\ + panic(MSG); } \ + } + +#define DMAWAIT(sc) TIME_WAIT((sc->sc_regs->csr & D_R_PEND), "DMAWAIT", sc) +#define DMAWAIT1(sc) TIME_WAIT((sc->sc_regs->csr & D_DRAINING), "DMAWAIT1", sc) +#define DMAREADY(sc) TIME_WAIT((!(sc->sc_regs->csr & D_DMA_ON)), "DMAREADY", sc) -#define DMAWAIT_PEND(sc) \ - TIME_WAIT((DMACSR(sc) & D_R_PEND), \ - "DMAWAIT_PEND", sc) +#define DMA_DRAIN(sc) if (sc->sc_rev < DMAREV_2) { \ + DMACSR(sc) |= D_DRAIN; \ + DMAWAIT1(sc); \ + } -/* keep punching the chip until it's flushed */ -#define DMAWAIT_DRAIN(sc) \ - TIME_WAIT((DMACSR(sc) |= D_DRAIN, DMACSR(sc) & D_DRAINING), \ - "DMAWAIT_DRAIN", sc) +/* DMA engine functions */ +#define DMA_ENINTR(r) (((r)->enintr)(r)) +#define DMA_ISINTR(r) (((r)->isintr)(r)) +#define DMA_RESET(r) (((r)->reset)(r)) +#define DMA_INTR(r) (((r)->intr)(r)) +#define DMA_ISACTIVE(r) ((r)->sc_active) +#define DMA_SETUP(a, b, c, d, e) (((a)->setup)(a, b, c, d, e)) +#define DMA_GO(r) (((r)->go)(r)) diff --git a/sys/arch/sparc/dev/esp.c b/sys/arch/sparc/dev/esp.c index 7941b614917..840ca8100d0 100644 --- a/sys/arch/sparc/dev/esp.c +++ b/sys/arch/sparc/dev/esp.c @@ -1,6 +1,10 @@ +/* $NetBSD: esp.c,v 1.47.2.1 1996/06/12 20:46:52 pk Exp $ */ + /* - * Copyright (c) 1995 Theo de Raadt - * + * Copyright (c) 1994 Peter Galbavy + * Copyright (c) 1995 Paul Kranenburg + * All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -11,33 +15,29 @@ * 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 under OpenBSD by - * Theo de Raadt. + * This product includes software developed by Peter Galbavy * 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. - */ - -/* - * Based IN PART on aic6360 by Jarle Greipsland, an older esp driver - * by Peter Galbavy, and work by Charles Hannum on a few other drivers. + * 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. */ /* - * todo: - * fix & enable sync - * confirm parity and bus failures do not lock up driver + * Based on aic6360 by Jarle Greipsland + * + * Acknowledgements: Many of the algorithms used in this driver are + * inspired by the work of Julian Elischer (julian@tfs.com) and + * Charles Hannum (mycroft@duality.gnu.ai.mit.edu). Thanks a million! */ #include <sys/types.h> @@ -59,62 +59,68 @@ #include <machine/cpu.h> #include <machine/autoconf.h> #include <sparc/dev/sbusvar.h> -#include <sparc/dev/dmavar.h> #include <sparc/dev/dmareg.h> +#include <sparc/dev/dmavar.h> #include <sparc/dev/espreg.h> #include <sparc/dev/espvar.h> -int esp_debug = ESP_SHOWPHASE|ESP_SHOWMISC|ESP_SHOWTRAC|ESP_SHOWCMDS; /**/ - -#if 1 -#define ESPD(x) -#else -#define ESPD(x) printf x -#endif +int esp_debug = 0; /*ESP_SHOWPHASE|ESP_SHOWMISC|ESP_SHOWTRAC|ESP_SHOWCMDS;*/ + +/*static*/ void espattach __P((struct device *, struct device *, void *)); +/*static*/ int espmatch __P((struct device *, void *, void *)); +/*static*/ int espprint __P((void *, char *)); +/*static*/ u_int esp_adapter_info __P((struct esp_softc *)); +/*static*/ void espreadregs __P((struct esp_softc *)); +/*static*/ void espselect __P((struct esp_softc *, + u_char, u_char, u_char *, u_char)); +/*static*/ void esp_scsi_reset __P((struct esp_softc *)); +/*static*/ void esp_reset __P((struct esp_softc *)); +/*static*/ void esp_init __P((struct esp_softc *, int)); +/*static*/ int esp_scsi_cmd __P((struct scsi_xfer *)); +/*static*/ int esp_poll __P((struct esp_softc *, struct ecb *)); +/*static*/ void esp_sched __P((struct esp_softc *)); +/*static*/ void esp_done __P((struct ecb *)); +/*static*/ void esp_msgin __P((struct esp_softc *)); +/*static*/ void esp_msgout __P((struct esp_softc *)); +/*static*/ int espintr __P((struct esp_softc *)); +/*static*/ void esp_timeout __P((void *arg)); +/*static*/ void esp_abort __P((struct esp_softc *, struct ecb *)); +int esp_stp2cpb __P((struct esp_softc *, int)); +int esp_cpb2stp __P((struct esp_softc *, int)); + +/* Linkup to the rest of the kernel */ +struct cfattach esp_ca = { + sizeof(struct esp_softc), espmatch, espattach +}; -void espattach __P((struct device *, struct device *, void *)); -int espmatch __P((struct device *, void *, void *)); -int espprint __P((void *, char *)); -void espreadregs __P((struct esp_softc *)); -int espgetbyte __P((struct esp_softc *, int)); -void espselect __P((struct esp_softc *)); -void esp_reset __P((struct esp_softc *)); -void esp_init __P((struct esp_softc *, int)); -int esp_scsi_cmd __P((struct scsi_xfer *)); -int esp_poll __P((struct esp_softc *, struct ecb *)); -int espphase __P((struct esp_softc *)); -void esp_sched __P((struct esp_softc *)); -void esp_done __P((struct ecb *)); -void esp_msgin __P((struct esp_softc *)); -void esp_makemsg __P((struct esp_softc *)); -void esp_msgout __P((struct esp_softc *)); -int espintr __P((struct esp_softc *)); -void esp_timeout __P((void *arg)); - -struct cfdriver espcd = { - NULL, "esp", espmatch, espattach, DV_DULL, sizeof(struct esp_softc) +struct cfdriver esp_cd = { + NULL, "esp", DV_DULL }; struct scsi_adapter esp_switch = { - esp_scsi_cmd, minphys, NULL, NULL + esp_scsi_cmd, + minphys, /* no max at this level; handled by DMA code */ + NULL, + NULL, }; struct scsi_device esp_dev = { - NULL, NULL, NULL, NULL + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ }; -/* - * Does anyone actually use this, and what for ? - */ int espprint(aux, name) void *aux; char *name; { - return (UNCONF); + if (name != NULL) + printf("%s: scsibus ", name); + return UNCONF; } - int espmatch(parent, vcf, aux) struct device *parent; @@ -132,7 +138,6 @@ espmatch(parent, vcf, aux) return (probeget(ra->ra_vaddr, 1) != -1); } - /* * Attach this instance, and then all the sub-devices */ @@ -143,9 +148,8 @@ espattach(parent, self, aux) { register struct confargs *ca = aux; struct esp_softc *sc = (void *)self; - struct espregs *espr; struct bootpath *bp; - int freq; + int dmachild = strncmp(parent->dv_xname, "dma", 3) == 0; /* * Make sure things are sane. I don't know if this is ever @@ -164,13 +168,11 @@ espattach(parent, self, aux) * address space. */ if (ca->ca_ra.ra_vaddr) - sc->sc_regs = (struct espregs *) ca->ca_ra.ra_vaddr; + sc->sc_reg = (volatile u_char *) ca->ca_ra.ra_vaddr; else { - sc->sc_regs = (struct espregs *) - mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len, - ca->ca_bustype); + sc->sc_reg = (volatile u_char *) + mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len, ca->ca_bustype); } - espr = sc->sc_regs; /* Other settings */ sc->sc_node = ca->ca_ra.ra_node; @@ -185,92 +187,138 @@ espattach(parent, self, aux) sc->sc_freq = ((struct sbus_softc *) sc->sc_dev.dv_parent)->sc_clockfreq; - freq = sc->sc_freq / 1000000; /* gimme Mhz */ - - /* - * This is the value used to start sync negotiations. For a - * 25Mhz clock, this gives us 40, or 160nS, or 6.25Mb/s. It - * is constant for each adapter. In turn, notice that the ESP - * register "SYNCTP" is = (250 / the negotiated period). - */ - sc->sc_minsync = 1000 / freq; - - /* 0 is actually 8, even though the register only has 3 bits */ - sc->sc_ccf = FREQTOCCF(freq) & 0x07; + /* gimme Mhz */ + sc->sc_freq /= 1000000; - /* The value must not be 1 -- make it 2 */ - if (sc->sc_ccf == 1) - sc->sc_ccf = 2; + if (dmachild) { + sc->sc_dma = (struct dma_softc *)parent; + sc->sc_dma->sc_esp = sc; + } else { + /* + * find the DMA by poking around the dma device structures + * + * What happens here is that if the dma driver has not been + * configured, then this returns a NULL pointer. Then when the + * dma actually gets configured, it does the opposing test, and + * if the sc->sc_esp field in it's softc is NULL, then tries to + * find the matching esp driver. + * + */ + sc->sc_dma = (struct dma_softc *) + getdevunit("dma", sc->sc_dev.dv_unit); - /* - * The recommended timeout is 250ms (1/4 seconds). This - * register is loaded with a value calculated as follows: - * - * (timout period) x (CLK frequency) - * reg = ------------------------------------- - * 8192 x (Clock Conversion Factor) - * - * We have the CCF from above. For a 25MHz clock this gives - * a constant of 153 (we round up). - */ - sc->sc_timeout = (sc->sc_freq / 4 / 8192 / sc->sc_ccf) + 1; + /* + * and a back pointer to us, for DMA + */ + if (sc->sc_dma) + sc->sc_dma->sc_esp = sc; + else + panic("espattach: no dma found"); + } /* - * find the corresponding DMA controller. + * It is necessary to try to load the 2nd config register here, + * to find out what rev the esp chip is, else the esp_reset + * will not set up the defaults correctly. */ - sc->sc_dma = ((struct dma_softc *)getdevunit("dma", - sc->sc_dev.dv_unit)); - if (sc->sc_dma) - sc->sc_dma->sc_esp = sc; - sc->sc_cfg1 = sc->sc_id | ESPCFG1_PARENB; - sc->sc_cfg2 = 0; - sc->sc_cfg3 = 0; + sc->sc_cfg2 = ESPCFG2_SCSI2 | ESPCFG2_RPE; + sc->sc_cfg3 = ESPCFG3_CDB; + ESP_WRITE_REG(sc, ESP_CFG2, sc->sc_cfg2); - /* - * The ESP100 only has a cfg1 register. The ESP100A has it, but - * lacks the cfg3 register. Thus, we can tell which chip we have. - * XXX: what about the FAS100A? - */ - espr->espr_cfg2 = ESPCFG2_SCSI2 | ESPCFG2_RPE; - if ((espr->espr_cfg2 & ~ESPCFG2_RSVD) != (ESPCFG2_SCSI2 | ESPCFG2_RPE)) { + if ((ESP_READ_REG(sc, ESP_CFG2) & ~ESPCFG2_RSVD) != (ESPCFG2_SCSI2 | ESPCFG2_RPE)) { printf(": ESP100"); sc->sc_rev = ESP100; } else { - espr->espr_cfg2 = 0; - espr->espr_cfg3 = 0; - espr->espr_cfg3 = ESPCFG3_CDB | ESPCFG3_FCLK; - if (espr->espr_cfg3 != (ESPCFG3_CDB | ESPCFG3_FCLK)) { + sc->sc_cfg2 = ESPCFG2_SCSI2; + ESP_WRITE_REG(sc, ESP_CFG2, sc->sc_cfg2); + sc->sc_cfg3 = 0; + ESP_WRITE_REG(sc, ESP_CFG3, sc->sc_cfg3); + sc->sc_cfg3 = (ESPCFG3_CDB | ESPCFG3_FCLK); + ESP_WRITE_REG(sc, ESP_CFG3, sc->sc_cfg3); + if (ESP_READ_REG(sc, ESP_CFG3) != (ESPCFG3_CDB | ESPCFG3_FCLK)) { printf(": ESP100A"); - /* XXX sc->sc_cfg2 = ESPCFG2_SCSI2 | ESPCFG2_FE; */ sc->sc_rev = ESP100A; } else { - espr->espr_cfg3 = 0; + /* ESPCFG2_FE enables > 64K transfers */ + sc->sc_cfg2 |= ESPCFG2_FE; + sc->sc_cfg3 = 0; + ESP_WRITE_REG(sc, ESP_CFG3, sc->sc_cfg3); printf(": ESP200"); sc->sc_rev = ESP200; } } + /* + * This is the value used to start sync negotiations + * Note that the ESP register "SYNCTP" is programmed + * in "clocks per byte", and has a minimum value of 4. + * The SCSI period used in negotiation is one-fourth + * of the time (in nanoseconds) needed to transfer one byte. + * Since the chip's clock is given in MHz, we have the following + * formula: 4 * period = (1000 / freq) * 4 + */ + sc->sc_minsync = 1000 / sc->sc_freq; + + /* + * Alas, we must now modify the value a bit, because it's + * only valid when can switch on FASTCLK and FASTSCSI bits + * in config register 3... + */ + switch (sc->sc_rev) { + case ESP100: + sc->sc_maxxfer = 64 * 1024; + sc->sc_minsync = 0; /* No synch on old chip? */ + break; + case ESP100A: + sc->sc_maxxfer = 64 * 1024; + sc->sc_minsync = esp_cpb2stp(sc, 5); /* Min clocks/byte is 5 */ + break; + case ESP200: + sc->sc_maxxfer = 16 * 1024 * 1024; + /* XXX - do actually set FAST* bits */ + } + + sc->sc_ccf = FREQTOCCF(sc->sc_freq); + + /* The value *must not* be == 1. Make it 2 */ + if (sc->sc_ccf == 1) + sc->sc_ccf = 2; + + /* + * The recommended timeout is 250ms. This register is loaded + * with a value calculated as follows, from the docs: + * + * (timout period) x (CLK frequency) + * reg = ------------------------------------- + * 8192 x (Clock Conversion Factor) + * + * Since CCF has a linear relation to CLK, this generally computes + * to the constant of 153. + */ + sc->sc_timeout = ((250 * 1000) * sc->sc_freq) / (8192 * sc->sc_ccf); + + /* CCF register only has 3 bits; 0 is actually 8 */ + sc->sc_ccf &= 7; + + /* Reset state & bus */ sc->sc_state = 0; esp_init(sc, 1); - printf(" %dMhz, target %d\n", freq, sc->sc_id); + printf(" %dMhz, target %d\n", sc->sc_freq, sc->sc_id); + /* add me to the sbus structures */ + sc->sc_sd.sd_reset = (void *) esp_reset; #if defined(SUN4C) || defined(SUN4M) if (ca->ca_bustype == BUS_SBUS) { - /* add to the sbus structures */ - sc->sc_sd.sd_reset = (void *) esp_reset; - sbus_establish(&sc->sc_sd, &sc->sc_dev); - - /* - * If the device is in an SBUS slave slot, bail now. - */ - if (sbus_slavecheck(self, ca)) - return; + if (dmachild) + sbus_establish(&sc->sc_sd, sc->sc_dev.dv_parent); + else + sbus_establish(&sc->sc_sd, &sc->sc_dev); } #endif /* SUN4C || SUN4M */ - /* and the interupts */ + /* and the interuppts */ sc->sc_ih.ih_fun = (void *) espintr; sc->sc_ih.ih_arg = sc; intr_establish(sc->sc_pri, &sc->sc_ih); @@ -286,23 +334,20 @@ espattach(parent, self, aux) sc->sc_link.openings = 2; /* - * If the boot path is "esp", and the numbers point to - * this controller, then advance the bootpath a step. - * XXX boot /sbus/esp/sd@3,0 passes in esp@0,0 -- which - * is almost always wrong, but match in that case anyways. + * If the boot path is "esp" at the moment and it's me, then + * walk our pointer to the sub-device, ready for the config + * below. */ bp = ca->ca_ra.ra_bp; switch (ca->ca_bustype) { case BUS_SBUS: if (bp != NULL && strcmp(bp->name, "esp") == 0 && - ((bp->val[0]==ca->ca_slot && - (bp->val[1]==ca->ca_offset || bp->val[1]==0)) || - (bp->val[0]==-1 && bp->val[1]==sc->sc_dev.dv_unit))) + SAME_ESP(sc, bp, ca)) bootpath_store(1, bp + 1); break; default: if (bp != NULL && strcmp(bp->name, "esp") == 0 && - bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit) + bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit) bootpath_store(1, bp + 1); break; } @@ -315,266 +360,317 @@ espattach(parent, self, aux) bootpath_store(1, NULL); } - /* - * Warning: This inserts two commands into the ESP command fifo. Because - * there are only 2 entries in that fifo, you may need to put a DELAY(1) - * after calling this, if you are going to issue another command soon. + * This is the generic esp reset function. It does not reset the SCSI bus, + * only this controllers, but kills any on-going commands, and also stops + * and resets the DMA. + * + * After reset, registers are loaded with the defaults from the attach + * routine above. */ void -espflush(sc) +esp_reset(sc) struct esp_softc *sc; { - struct espregs *espr = sc->sc_regs; - if (espr->espr_fflag & ESPFIFO_FF) { - espr->espr_cmd = ESPCMD_FLUSH; - espr->espr_cmd = ESPCMD_NOP; + /* reset DMA first */ + DMA_RESET(sc->sc_dma); + + /* reset SCSI chip */ + ESPCMD(sc, ESPCMD_RSTCHIP); + ESPCMD(sc, ESPCMD_NOP); + DELAY(500); + + /* do these backwards, and fall through */ + switch (sc->sc_rev) { + case ESP200: + ESP_WRITE_REG(sc, ESP_CFG3, sc->sc_cfg3); + case ESP100A: + ESP_WRITE_REG(sc, ESP_CFG2, sc->sc_cfg2); + case ESP100: + ESP_WRITE_REG(sc, ESP_CFG1, sc->sc_cfg1); + ESP_WRITE_REG(sc, ESP_CCF, sc->sc_ccf); + ESP_WRITE_REG(sc, ESP_SYNCOFF, 0); + ESP_WRITE_REG(sc, ESP_TIMEOUT, sc->sc_timeout); + break; + default: + printf("%s: unknown revision code, assuming ESP100\n", + sc->sc_dev.dv_xname); + ESP_WRITE_REG(sc, ESP_CFG1, sc->sc_cfg1); + ESP_WRITE_REG(sc, ESP_CCF, sc->sc_ccf); + ESP_WRITE_REG(sc, ESP_SYNCOFF, 0); + ESP_WRITE_REG(sc, ESP_TIMEOUT, sc->sc_timeout); } } /* - * returns -1 if no byte is available because fifo is empty. + * Reset the SCSI bus, but not the chip */ -int -espgetbyte(sc, dotrans) +void +esp_scsi_reset(sc) struct esp_softc *sc; - int dotrans; { - struct espregs *espr = sc->sc_regs; + /* stop DMA first, as the chip will return to Bus Free phase */ + DMACSR(sc->sc_dma) &= ~D_EN_DMA; - if (espr->espr_fflag & ESPFIFO_FF) - return espr->espr_fifo; - return -1; + printf("esp: resetting SCSI bus\n"); + ESPCMD(sc, ESPCMD_RSTSCSI); } /* - * Send a command to a target, as well as any required messages. - * There are three cases. The first two cases are fairly simple.. - * 1) command alone - * load command into fifo, and use ESPCMD_SELNATN - * 2) MSG_IDENTIFY + command - * load message and command into fifo, and use ESPCMD_SELATN - * 3) a bunch of messages + command - * load first message byte into fifo. Use ESPCMD_SELATNS. When the - * next interrupt occurs, load the remainer of the message into - * the fifo and use ESPCMD_TRANS. When the device is ready to - * receive the command, it will switch into COMMAND_PHASE, and - * at that point we will feed it the command. + * Initialize esp state machine */ void -espselect(sc) +esp_init(sc, doreset) struct esp_softc *sc; + int doreset; { - struct espregs *espr = sc->sc_regs; - register struct ecb *ecb = sc->sc_nexus; - register struct scsi_link *sc_link = ecb->xs->sc_link; - struct esp_tinfo *ti = &sc->sc_tinfo[sc_link->target]; - u_char *cmd = (u_char *)&ecb->cmd; - int loadcmd = 1; - int outcmd, i; - - espr->espr_selid = sc_link->target; - espr->espr_syncoff = ti->offset; - espr->espr_synctp = ti->synctp; - - sc->sc_state = ESPS_SELECTING; - - if (ecb->xs->flags & SCSI_RESET) - sc->sc_msgpriq = SEND_DEV_RESET; - else if (ti->flags & DO_NEGOTIATE) - sc->sc_msgpriq = SEND_SDTR; - else - sc->sc_msgpriq = SEND_IDENTIFY; - - if (sc->sc_msgpriq) { - esp_makemsg(sc); + struct ecb *ecb; + int r; - ESPD(("OM[")); - for (i = 0; i < sc->sc_omlen; i++) - ESPD(("%02x%c", sc->sc_omp[i], - (i == sc->sc_omlen-1) ? ']' : ' ')); - ESPD((" ")); + ESP_TRACE(("[ESP_INIT(%d)] ", doreset)); - espr->espr_fifo = sc->sc_omp[0]; /* 1st msg byte only */ - if (sc->sc_omlen == 1) { - outcmd = ESPCMD_SELATN; - } else { - outcmd = ESPCMD_SELATNS; - /* and this will will load the rest of the msg bytes */ - sc->sc_state = ESPS_SELECTSTOP; - loadcmd = 0; + if (sc->sc_state == 0) { /* First time through */ + TAILQ_INIT(&sc->ready_list); + TAILQ_INIT(&sc->nexus_list); + TAILQ_INIT(&sc->free_list); + sc->sc_nexus = NULL; + ecb = sc->sc_ecb; + bzero(ecb, sizeof(sc->sc_ecb)); + for (r = 0; r < sizeof(sc->sc_ecb) / sizeof(*ecb); r++) { + TAILQ_INSERT_TAIL(&sc->free_list, ecb, chain); + ECB_SETQ(ecb, ECB_QFREE); + ecb++; + } + bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo)); + } else { + sc->sc_flags |= ESP_ABORTING; + sc->sc_state = ESP_IDLE; + ecb = sc->sc_nexus; + if (ecb != NULL) { + ecb->xs->error = XS_TIMEOUT; + esp_done(ecb); + sc->sc_nexus = NULL; + } + while ((ecb = sc->nexus_list.tqh_first) != NULL) { + ecb->xs->error = XS_TIMEOUT; + esp_done(ecb); } - } else - outcmd = ESPCMD_SELNATN; + } - ESPD(("P%d/%02x/%d ", (ecb->xs->flags & SCSI_POLL) ? 1 : 0, outcmd, loadcmd)); + /* + * reset the chip to a known state + */ + esp_reset(sc); - if (loadcmd) { - ESPD(("CMD[")); - for (i = 0; i < ecb->clen; i++) - ESPD(("%02x%c", cmd[i], - (i == ecb->clen-1) ? ']' : ' ')); - ESPD((" ")); + sc->sc_phase = sc->sc_prevphase = INVALID_PHASE; + for (r = 0; r < 8; r++) { + struct esp_tinfo *tp = &sc->sc_tinfo[r]; +/* XXX - config flags per target: low bits: no reselect; high bits: no synch */ + int fl = sc->sc_dev.dv_cfdata->cf_flags; + + tp->flags = ((sc->sc_minsync && !(fl & (1<<(r+8)))) + ? T_NEGOTIATE : 0) | + ((fl & (1<<r)) ? T_RSELECTOFF : 0) | + T_NEED_TO_RESET; + tp->period = sc->sc_minsync; + tp->offset = 0; + } + sc->sc_flags &= ~ESP_ABORTING; - /* load the command into the FIFO */ - for (i = 0; i < ecb->clen; i++) - espr->espr_fifo = cmd[i]; + if (doreset) { + sc->sc_state = ESP_SBR; + ESPCMD(sc, ESPCMD_RSTSCSI); + return; } - espr->espr_cmd = outcmd; - if (!(ecb->xs->flags & SCSI_POLL)) - sc->sc_flags |= ESPF_MAYDISCON; + sc->sc_state = ESP_IDLE; + esp_sched(sc); + return; } - /* - * Reset the ESP and DMA chips. Stops any transactions dead in the water; - * does not cause an interrupt. + * Read the ESP registers, and save their contents for later use. + * ESP_STAT, ESP_STEP & ESP_INTR are mostly zeroed out when reading + * ESP_INTR - so make sure it is the last read. + * + * I think that (from reading the docs) most bits in these registers + * only make sense when he DMA CSR has an interrupt showing. Call only + * if an interrupt is pending. */ -void -esp_reset(sc) +void +espreadregs(sc) struct esp_softc *sc; { - struct espregs *espr = sc->sc_regs; - dmareset(sc->sc_dma); /* reset DMA first */ + sc->sc_espstat = ESP_READ_REG(sc, ESP_STAT); + /* Only the stepo bits are of interest */ + sc->sc_espstep = ESP_READ_REG(sc, ESP_STEP) & ESPSTEP_MASK; + sc->sc_espintr = ESP_READ_REG(sc, ESP_INTR); - espr->espr_cmd = ESPCMD_RSTCHIP; - DELAY(5); - espr->espr_cmd = ESPCMD_NOP; - DELAY(5); + /* + * Determine the SCSI bus phase, return either a real SCSI bus phase + * or some pseudo phase we use to detect certain exceptions. + */ - /* do these backwards, and fall through */ - switch (sc->sc_rev) { - case ESP200: - espr->espr_cfg3 = sc->sc_cfg3; - case ESP100A: - espr->espr_cfg2 = sc->sc_cfg2; - case ESP100: - espr->espr_cfg1 = sc->sc_cfg1; - espr->espr_ccf = sc->sc_ccf; - espr->espr_syncoff = 0; - espr->espr_timeout = sc->sc_timeout; - break; - } + sc->sc_phase = (sc->sc_espintr & ESPINTR_DIS) + ? /* Disconnected */ BUSFREE_PHASE + : sc->sc_espstat & ESPSTAT_PHASE; + + ESP_MISC(("regs[intr=%02x,stat=%02x,step=%02x] ", + sc->sc_espintr, sc->sc_espstat, sc->sc_espstep)); } /* - * Initialize esp state machine + * Convert Synchronous Transfer Period to chip register Clock Per Byte value. + */ +int +esp_stp2cpb(sc, period) + struct esp_softc *sc; + int period; +{ + int v; + v = (sc->sc_freq * period) / 250; + if (esp_cpb2stp(sc, v) < period) + /* Correct round-down error */ + v++; + return v; +} + +/* + * Convert chip register Clock Per Byte value to Synchronous Transfer Period. + */ +int +esp_cpb2stp(sc, cpb) + struct esp_softc *sc; + int cpb; +{ + return ((250 * cpb) / sc->sc_freq); +} + +/* + * Send a command to a target, set the driver state to ESP_SELECTING + * and let the caller take care of the rest. + * + * Keeping this as a function allows me to say that this may be done + * by DMA instead of programmed I/O soon. */ void -esp_init(sc, doreset) +espselect(sc, target, lun, cmd, clen) struct esp_softc *sc; - int doreset; + u_char target, lun; + u_char *cmd; + u_char clen; { - struct espregs *espr = sc->sc_regs; - struct ecb *ecb; + struct esp_tinfo *ti = &sc->sc_tinfo[target]; int i; - - /* - * reset the chip to a known state - */ - esp_reset(sc); - if (doreset) { - espr->espr_cmd = ESPCMD_RSTSCSI; - DELAY(500); - /* cheat: we don't want the state machine to reset again.. */ - esp_reset(sc); - } + ESP_TRACE(("[espselect(t%d,l%d,cmd:%x)] ", target, lun, *(u_char *)cmd)); - if (sc->sc_state == 0) { /* First time through */ - TAILQ_INIT(&sc->ready_list); - TAILQ_INIT(&sc->nexus_list); - TAILQ_INIT(&sc->free_list); - sc->sc_nexus = 0; - ecb = sc->sc_ecb; - bzero(ecb, sizeof(sc->sc_ecb)); - for (i = 0; i < sizeof(sc->sc_ecb) / sizeof(*ecb); i++) { - TAILQ_INSERT_TAIL(&sc->free_list, ecb, chain); - ecb++; - } - bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo)); + /* new state ESP_SELECTING */ + sc->sc_state = ESP_SELECTING; + + ESPCMD(sc, ESPCMD_FLUSH); + + /* + * The docs say the target register is never reset, and I + * can't think of a better place to set it + */ + ESP_WRITE_REG(sc, ESP_SELID, target); + if (ti->flags & T_SYNCMODE) { + ESP_WRITE_REG(sc, ESP_SYNCOFF, ti->offset); + ESP_WRITE_REG(sc, ESP_SYNCTP, esp_stp2cpb(sc, ti->period)); } else { - sc->sc_state = ESPS_IDLE; - if (sc->sc_nexus != NULL) { - sc->sc_nexus->xs->error = XS_DRIVER_STUFFUP; - untimeout(esp_timeout, sc->sc_nexus); - esp_done(sc->sc_nexus); - } - sc->sc_nexus = NULL; - while (ecb = sc->nexus_list.tqh_first) { - ecb->xs->error = XS_DRIVER_STUFFUP; - untimeout(esp_timeout, ecb); - esp_done(ecb); - } + ESP_WRITE_REG(sc, ESP_SYNCOFF, 0); + ESP_WRITE_REG(sc, ESP_SYNCTP, 0); } - - for (i = 0; i < 8; i++) { - struct esp_tinfo *ti = &sc->sc_tinfo[i]; - - ti->flags = DO_NEGOTIATE; - ti->period = sc->sc_minsync; - ti->synctp = 250 / ti->period; - ti->offset = ESP_SYNC_REQOFF; + + /* + * Who am I. This is where we tell the target that we are + * happy for it to disconnect etc. + */ + ESP_WRITE_REG(sc, ESP_FIFO, + MSG_IDENTIFY(lun, (ti->flags & T_RSELECTOFF)?0:1)); + + if (ti->flags & T_NEGOTIATE) { + /* Arbitrate, select and stop after IDENTIFY message */ + ESPCMD(sc, ESPCMD_SELATNS); + return; } - sc->sc_state = ESPS_IDLE; + + /* Now the command into the FIFO */ + for (i = 0; i < clen; i++) + ESP_WRITE_REG(sc, ESP_FIFO, *cmd++); + + /* And get the targets attention */ + ESPCMD(sc, ESPCMD_SELATN); + } /* - * Start a SCSI-command: This function is called by the higher level - * SCSI-driver to queue/run SCSI-commands. + * DRIVER FUNCTIONS CALLABLE FROM HIGHER LEVEL DRIVERS + */ + +/* + * Start a SCSI-command + * This function is called by the higher level SCSI-driver to queue/run + * SCSI-commands. */ -int +int esp_scsi_cmd(xs) struct scsi_xfer *xs; { struct scsi_link *sc_link = xs->sc_link; struct esp_softc *sc = sc_link->adapter_softc; - struct ecb *ecb; - int s; - - /*ESPD(("NS%08x/%08x/%d ", xs, xs->data, xs->datalen));*/ + struct ecb *ecb; + int s, flags; + + ESP_TRACE(("[esp_scsi_cmd] ")); + ESP_CMDS(("[0x%x, %d]->%d ", (int)xs->cmd->opcode, xs->cmdlen, + sc_link->target)); - /* XXX: set lun */ - xs->cmd->bytes[0] |= (sc_link->lun << SCSI_CMD_LUN_SHIFT); + flags = xs->flags; /* Get a esp command block */ s = splbio(); ecb = sc->free_list.tqh_first; if (ecb) { TAILQ_REMOVE(&sc->free_list, ecb, chain); + ECB_SETQ(ecb, ECB_QNONE); } splx(s); - + if (ecb == NULL) { - xs->error = XS_DRIVER_STUFFUP; + ESP_MISC(("TRY_AGAIN_LATER")); return TRY_AGAIN_LATER; } /* Initialize ecb */ - ecb->flags = ECB_ACTIVE; ecb->xs = xs; bcopy(xs->cmd, &ecb->cmd, xs->cmdlen); ecb->clen = xs->cmdlen; ecb->daddr = xs->data; ecb->dleft = xs->datalen; ecb->stat = 0; - + s = splbio(); TAILQ_INSERT_TAIL(&sc->ready_list, ecb, chain); - if ((xs->flags & SCSI_POLL) == 0) - timeout(esp_timeout, ecb, (xs->timeout * hz) / 1000); + ECB_SETQ(ecb, ECB_QREADY); + timeout(esp_timeout, ecb, (xs->timeout*hz)/1000); - if (sc->sc_state == ESPS_IDLE) + if (sc->sc_state == ESP_IDLE) esp_sched(sc); + splx(s); - /* Not allowed to use interrupts, use polling instead */ - if (xs->flags & SCSI_POLL) + if (flags & SCSI_POLL) { + /* Not allowed to use interrupts, use polling instead */ return esp_poll(sc, ecb); + } + + ESP_MISC(("SUCCESSFULLY_QUEUED")); return SUCCESSFULLY_QUEUED; + } /* @@ -586,57 +682,45 @@ esp_poll(sc, ecb) struct ecb *ecb; { struct scsi_xfer *xs = ecb->xs; - int count = xs->timeout * 1000; + int count = xs->timeout * 100; - ESP_TRACE(("esp_poll\n")); + ESP_TRACE(("[esp_poll] ")); while (count) { - if (dmapending(sc->sc_dma)) { - /* - * We decrement the interrupt event counter to - * repair it... because this isn't a real interrupt. - */ - if (espintr(sc)) - --sc->sc_intrcnt.ev_count; - continue; + if (DMA_ISINTR(sc->sc_dma)) { + espintr(sc); } +#if alternatively + if (ESP_READ_REG(sc, ESP_STAT) & ESPSTAT_INT) + espintr(sc); +#endif if (xs->flags & ITSDONE) break; - DELAY(1); + DELAY(10); + if (sc->sc_state == ESP_IDLE) { + ESP_TRACE(("[esp_poll: rescheduling] ")); + esp_sched(sc); + } count--; } if (count == 0) { - ecb->xs->error = XS_TIMEOUT; - sc_print_addr(ecb->xs->sc_link); - printf("timed out\n"); - esp_reset(sc); + ESP_MISC(("esp_poll: timeout")); + esp_timeout((caddr_t)ecb); } - dmaenintr(sc->sc_dma); + return COMPLETE; } /* - * Notice that we do not read the live register on an ESP100. On the - * ESP100A and above the FE (Feature Enable) bit in config 2 latches - * the phase in the register so it is safe to read. + * LOW LEVEL SCSI UTILITIES */ -int -espphase(sc) - struct esp_softc *sc; -{ - - if (sc->sc_rev > ESP100) - return (sc->sc_regs->espr_stat & ESPSTAT_PHASE); - return (sc->sc_espstat & ESPSTAT_PHASE); -} - /* * Schedule a scsi operation. This has now been pulled out of the interrupt * handler so that we may call it from esp_scsi_cmd and esp_done. This may * save us an unecessary interrupt just to get things going. Should only be - * called when state == ESPS_IDLE and at bio pl. + * called when state == ESP_IDLE and at bio pl. */ void esp_sched(sc) @@ -645,29 +729,40 @@ esp_sched(sc) struct scsi_link *sc_link; struct ecb *ecb; int t; - - ESP_TRACE(("esp_sched\n")); + + ESP_TRACE(("[esp_sched] ")); + if (sc->sc_state != ESP_IDLE) + panic("esp_sched: not IDLE (state=%d)", sc->sc_state); + + if (sc->sc_flags & ESP_ABORTING) + return; /* * Find first ecb in ready queue that is for a target/lunit * combinations that is not busy. */ for (ecb = sc->ready_list.tqh_first; ecb; ecb = ecb->chain.tqe_next) { - caddr_t cmd = (caddr_t) &ecb->cmd; sc_link = ecb->xs->sc_link; t = sc_link->target; if (!(sc->sc_tinfo[t].lubusy & (1 << sc_link->lun))) { - struct esp_tinfo *ti = &sc->sc_tinfo[ecb->xs->sc_link->target]; + struct esp_tinfo *ti = &sc->sc_tinfo[t]; + if ((ecb->flags & ECB_QBITS) != ECB_QREADY) + panic("esp: busy entry on ready list"); TAILQ_REMOVE(&sc->ready_list, ecb, chain); + ECB_SETQ(ecb, ECB_QNONE); sc->sc_nexus = ecb; sc->sc_flags = 0; - sc_link = ecb->xs->sc_link; - espselect(sc); - ti = &sc->sc_tinfo[sc_link->target]; + sc->sc_prevphase = INVALID_PHASE; sc->sc_dp = ecb->daddr; sc->sc_dleft = ecb->dleft; ti->lubusy |= (1<<sc_link->lun); +/*XXX*/if (sc->sc_msgpriq) { + printf("esp: message queue not empty: %x!\n", sc->sc_msgpriq); +} +/*XXX*/sc->sc_msgpriq = sc->sc_msgout = 0; + espselect(sc, t, sc_link->lun, + (u_char *)&ecb->cmd, ecb->clen); break; } else ESP_MISC(("%d:%d busy\n", t, sc_link->lun)); @@ -684,24 +779,27 @@ esp_done(ecb) struct scsi_xfer *xs = ecb->xs; struct scsi_link *sc_link = xs->sc_link; struct esp_softc *sc = sc_link->adapter_softc; + struct esp_tinfo *ti = &sc->sc_tinfo[sc_link->target]; - ESP_TRACE(("esp_done ")); + ESP_TRACE(("[esp_done(error:%x)] ", xs->error)); + + untimeout(esp_timeout, ecb); /* - * Now, if we've come here with no error code, i.e. we've kept the + * Now, if we've come here with no error code, i.e. we've kept the * initial XS_NOERROR, and the status code signals that we should - * check sense, we'll need to set up a request sense cmd block and - * push the command back into the ready queue *before* any other + * check sense, we'll need to set up a request sense cmd block and + * push the command back into the ready queue *before* any other * commands for this target/lunit, else we lose the sense info. * We don't support chk sense conditions for the request sense cmd. */ if (xs->error == XS_NOERROR) { - if (ecb->flags & ECB_CHKSENSE) + if ((ecb->flags & ECB_ABORTED) != 0) { + xs->error = XS_TIMEOUT; + } else if ((ecb->flags & ECB_CHKSENSE) != 0) { xs->error = XS_SENSE; - else if ((ecb->stat & ST_MASK) == SCSI_CHECK) { + } else if ((ecb->stat & ST_MASK) == SCSI_CHECK) { struct scsi_sense *ss = (void *)&ecb->cmd; - - ESPD(("RS ")); ESP_MISC(("requesting sense ")); /* First, save the return values */ xs->resid = ecb->dleft; @@ -709,35 +807,43 @@ esp_done(ecb) /* Next, setup a request sense command block */ bzero(ss, sizeof(*ss)); ss->opcode = REQUEST_SENSE; - ss->byte2 = sc_link->lun << SCSI_CMD_LUN_SHIFT; + /*ss->byte2 = sc_link->lun << 5;*/ ss->length = sizeof(struct scsi_sense_data); ecb->clen = sizeof(*ss); ecb->daddr = (char *)&xs->sense; ecb->dleft = sizeof(struct scsi_sense_data); - ecb->flags = ECB_ACTIVE|ECB_CHKSENSE; + ecb->flags |= ECB_CHKSENSE; +/*XXX - must take off queue here */ + if (ecb != sc->sc_nexus) { + panic("%s: esp_sched: floating ecb %p", + sc->sc_dev.dv_xname, ecb); + } TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain); - sc->sc_tinfo[sc_link->target].lubusy &= - ~(1<<sc_link->lun); - sc->sc_tinfo[sc_link->target].senses++; - /* found it */ - if (sc->sc_nexus != ecb) - TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain); - sc->sc_state = ESPS_IDLE; - esp_sched(sc); + ECB_SETQ(ecb, ECB_QREADY); + ti->lubusy &= ~(1<<sc_link->lun); + ti->senses++; + timeout(esp_timeout, ecb, (xs->timeout*hz)/1000); + if (sc->sc_nexus == ecb) { + sc->sc_nexus = NULL; + sc->sc_state = ESP_IDLE; + esp_sched(sc); + } return; - } else + } else { xs->resid = ecb->dleft; + } } xs->flags |= ITSDONE; -#if ESP_DEBUG > 1 +#ifdef ESP_DEBUG if (esp_debug & ESP_SHOWMISC) { - printf("err=0x%02x ", xs->error); - if (xs->error == XS_SENSE) - printf("sense=%02x\n", xs->sense.error_code); + printf("err=0x%02x ",xs->error); + if (xs->error == XS_SENSE) { + printf("sense=%2x; ", xs->sense.error_code); + } } - if ((xs->resid || xs->error > XS_SENSE) && (esp_debug & ESP_SHOWMISC)) { + if ((xs->resid || xs->error > XS_SENSE) && esp_debug & ESP_SHOWMISC) { if (xs->resid) printf("esp_done: resid=%d\n", xs->resid); if (xs->error) @@ -746,45 +852,41 @@ esp_done(ecb) #endif /* - * Remove the ECB from whatever queue it's on. We have to do a bit of - * a hack to figure out which queue it's on. Note that it is *not* - * necessary to cdr down the ready queue, but we must cdr down the - * nexus queue and see if it's there, so we can mark the unit as no - * longer busy. This code is sickening, but it works. + * Remove the ECB from whatever queue it's on. */ - if (ecb == sc->sc_nexus) { - sc->sc_tinfo[sc_link->target].lubusy &= ~(1<<sc_link->lun); + switch (ecb->flags & ECB_QBITS) { + case ECB_QNONE: + if (ecb != sc->sc_nexus) { + panic("%s: floating ecb", sc->sc_dev.dv_xname); + } sc->sc_nexus = NULL; - sc->sc_state = ESPS_IDLE; + sc->sc_state = ESP_IDLE; + ti->lubusy &= ~(1<<sc_link->lun); esp_sched(sc); - } else if (sc->ready_list.tqh_last == &ecb->chain.tqe_next) { + break; + case ECB_QREADY: TAILQ_REMOVE(&sc->ready_list, ecb, chain); - } else { - register struct ecb *ecb2; - - for (ecb2 = sc->nexus_list.tqh_first; ecb2; - ecb2 = ecb2->chain.tqe_next) - if (ecb2 == ecb) - break; - if (ecb2) { - TAILQ_REMOVE(&sc->nexus_list, ecb, chain); - sc->sc_tinfo[sc_link->target].lubusy &= - ~(1<<sc_link->lun); - } else if (ecb->chain.tqe_next) { - TAILQ_REMOVE(&sc->ready_list, ecb, chain); - } else { - printf("%s: can't find matching ecb\n", - sc->sc_dev.dv_xname); - Debugger(); - } + break; + case ECB_QNEXUS: + TAILQ_REMOVE(&sc->nexus_list, ecb, chain); + ti->lubusy &= ~(1<<sc_link->lun); + break; + case ECB_QFREE: + panic("%s: dequeue: busy ecb on free list", + sc->sc_dev.dv_xname); + break; + default: + panic("%s: dequeue: unknown queue %d", + sc->sc_dev.dv_xname, ecb->flags & ECB_QBITS); } - /* Put it on the free list. */ - ecb->flags = ECB_FREE; + + /* Put it on the free list, and clear flags. */ TAILQ_INSERT_HEAD(&sc->free_list, ecb, chain); + ecb->flags = ECB_QFREE; - sc->sc_tinfo[sc_link->target].cmds++; - ESPD(("DONE%d ", xs->resid)); + ti->cmds++; scsi_done(xs); + return; } /* @@ -797,13 +899,13 @@ esp_done(ecb) * else there will be an illegal command interrupt. */ #define esp_sched_msgout(m) \ - do { \ - sc->sc_regs->espr_cmd = ESPCMD_SETATN; \ - sc->sc_msgpriq |= (m); \ - ESPD(("Mq%02x ", sc->sc_msgpriq)); \ + do { \ + ESP_MISC(("esp_sched_msgout %d ", m)); \ + ESPCMD(sc, ESPCMD_SETATN); \ + sc->sc_msgpriq |= (m); \ } while (0) -#define IS1BYTEMSG(m) (((m) != 1 && ((unsigned)(m)) < 0x20) || (m) & 0x80) +#define IS1BYTEMSG(m) (((m) != 1 && (m) < 0x20) || (m) & 0x80) #define IS2BYTEMSG(m) (((m) & 0xf0) == 0x20) #define ISEXTMSG(m) ((m) == 1) @@ -817,22 +919,16 @@ void esp_msgin(sc) register struct esp_softc *sc; { - struct espregs *espr = sc->sc_regs; - struct ecb *ecb; - int extlen; - int x, i; - - ESP_TRACE(("esp_msgin ")); - - /* is something wrong ? */ - if (sc->sc_phase != MESSAGE_IN_PHASE) { - printf("%s: not MESSAGE_IN_PHASE\n", sc->sc_dev.dv_xname); + register int v; + + ESP_TRACE(("[esp_msgin(curmsglen:%d)] ", sc->sc_imlen)); + + if ((ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) == 0) { + printf("%s: msgin: no msg byte available\n", + sc->sc_dev.dv_xname); return; } - ESPD(("MSGIN:%d ", espr->espr_fflag & ESPFIFO_FF)); - -#ifdef fixme /* * Prepare for a new message. A message should (according * to the SCSI standard) be transmitted in one single @@ -840,187 +936,125 @@ esp_msgin(sc) * then this is a new message. */ if (sc->sc_prevphase != MESSAGE_IN_PHASE) { - sc->sc_flags &= ~ESPF_DROP_MSGI; - if (sc->sc_imlen > 0) { - printf("%s: message type %02x", - sc->sc_dev.dv_xname, sc->sc_imess[0]); - if (!IS1BYTEMSG(sc->sc_imess[0])) - printf(" %02x", sc->sc_imess[1]); - printf(" was dropped\n"); - } + sc->sc_flags &= ~ESP_DROP_MSGI; sc->sc_imlen = 0; } -#endif - /* - * Which target is reselecting us? (The ID bit really) - * On a reselection, there should be the reselecting target's - * id and an identify message in the fifo. - */ - if (sc->sc_state == ESPS_RESELECTED && sc->sc_imlen == 0) { - x = espgetbyte(sc, 0); - if (x == -1) { - printf("%s: msgin reselection found fifo empty\n", - sc->sc_dev.dv_xname); - return; - } - ESPD(("ID=%02x ", x)); - sc->sc_selid = (u_char)x & ~(1<<sc->sc_id); - ESP_MISC(("selid=0x%02x ", sc->sc_selid)); - } + v = ESP_READ_REG(sc, ESP_FIFO); + ESP_MISC(("<msgbyte:0x%02x>", v)); - /* - * If parity errors just dump everything on the floor - */ - if (sc->sc_espstat & ESPSTAT_PE) { - printf("%s: SCSI bus parity error\n", - sc->sc_dev.dv_xname); - esp_sched_msgout(SEND_PARITY_ERROR); - DELAY(1); - sc->sc_flags |= ESPF_DROP_MSGI; +#if 0 + if (sc->sc_state == ESP_RESELECTED && sc->sc_imlen == 0) { + /* + * Which target is reselecting us? (The ID bit really) + */ + sc->sc_selid = v; + sc->sc_selid &= ~(1<<sc->sc_id); + ESP_MISC(("selid=0x%2x ", sc->sc_selid)); + return; } +#endif + + sc->sc_imess[sc->sc_imlen] = v; /* * If we're going to reject the message, don't bother storing * the incoming bytes. But still, we need to ACK them. - * XXX: the above comment might be true -- this is not being - * done though! */ - if ((sc->sc_flags & ESPF_DROP_MSGI) == 0) { - x = espgetbyte(sc, 1); - if (x == -1) { - printf("%s: msgin fifo empty at %d\n", - sc->sc_dev.dv_xname, sc->sc_imlen); - if (sc->sc_espintr & ESPINTR_BS) { - espr->espr_cmd = ESPCMD_TRANS; - ESPD(("MSI:y ")); - } else - ESPD(("MSI:n ")); - return; - } - ESPD(("{%02x} ", (u_char)x)); - sc->sc_imess[sc->sc_imlen] = (u_char)x; - if (sc->sc_imlen >= ESP_MSGLEN_MAX) { - esp_sched_msgout(SEND_REJECT); - DELAY(1); - sc->sc_flags |= ESPF_DROP_MSGI; - } else { - sc->sc_imlen++; - /* - * This testing is suboptimal, but most - * messages will be of the one byte variety, so - * it should not effect performance - * significantly. - */ - if (sc->sc_imlen == 1 && IS1BYTEMSG(sc->sc_imess[0])) - goto gotit; - if (sc->sc_imlen == 2 && IS2BYTEMSG(sc->sc_imess[0])) - goto gotit; - if (sc->sc_imlen >= 3 && ISEXTMSG(sc->sc_imess[0]) && - sc->sc_imlen == sc->sc_imess[1] + 2) - goto gotit; - } - } - goto done; -gotit: - ESPD(("MP[")); - for (i=0; i<sc->sc_imlen; i++) - ESPD(("%02x%c", sc->sc_imess[i], - (i==sc->sc_imlen-1) ? ']' : ' ')); - ESPD((" ")); + if ((sc->sc_flags & ESP_DROP_MSGI)) { + ESPCMD(sc, ESPCMD_SETATN); + ESPCMD(sc, ESPCMD_MSGOK); + printf("<dropping msg byte %x>", + sc->sc_imess[sc->sc_imlen]); + return; + } - sc->sc_imlen = 0; /* message is fully received */ + if (sc->sc_imlen >= ESP_MAX_MSG_LEN) { + esp_sched_msgout(SEND_REJECT); + sc->sc_flags |= ESP_DROP_MSGI; + } else { + sc->sc_imlen++; + /* + * This testing is suboptimal, but most + * messages will be of the one byte variety, so + * it should not effect performance + * significantly. + */ + if (sc->sc_imlen == 1 && IS1BYTEMSG(sc->sc_imess[0])) + goto gotit; + if (sc->sc_imlen == 2 && IS2BYTEMSG(sc->sc_imess[0])) + goto gotit; + if (sc->sc_imlen >= 3 && ISEXTMSG(sc->sc_imess[0]) && + sc->sc_imlen == sc->sc_imess[1] + 2) + goto gotit; + } + /* Ack what we have so far */ + ESPCMD(sc, ESPCMD_MSGOK); + return; - ESP_MISC(("gotmsg ")); +gotit: + ESP_MSGS(("gotmsg(%x)", sc->sc_imess[0])); /* * Now we should have a complete message (1 byte, 2 byte * and moderately long extended messages). We only handle * extended messages which total length is shorter than - * ESP_MSGLEN_MAX. Longer messages will be amputated. + * ESP_MAX_MSG_LEN. Longer messages will be amputated. */ - if (sc->sc_state == ESPS_NEXUS || - sc->sc_state == ESPS_DOINGMSGIN || - sc->sc_state == ESPS_DOINGSTATUS) { - struct esp_tinfo *ti; - - ecb = sc->sc_nexus; - ti = &sc->sc_tinfo[ecb->xs->sc_link->target]; - - sc->sc_state = ESPS_NEXUS; /* where we go after this */ + if (sc->sc_state == ESP_HASNEXUS) { + struct ecb *ecb = sc->sc_nexus; + struct esp_tinfo *ti = &sc->sc_tinfo[ecb->xs->sc_link->target]; switch (sc->sc_imess[0]) { case MSG_CMDCOMPLETE: - ESP_MISC(("cmdcomplete ")); - if (!ecb) { - esp_sched_msgout(SEND_ABORT); - DELAY(1); - printf("%s: CMDCOMPLETE but no command?\n", - sc->sc_dev.dv_xname); - break; - } + ESP_MSGS(("cmdcomplete ")); if (sc->sc_dleft < 0) { - sc_print_addr(ecb->xs->sc_link); - printf("%d extra bytes\n", -sc->sc_dleft); - ecb->dleft = 0; + struct scsi_link *sc_link = ecb->xs->sc_link; + printf("esp: %d extra bytes from %d:%d\n", + -sc->sc_dleft, + sc_link->target, sc_link->lun); + sc->sc_dleft = 0; } ecb->xs->resid = ecb->dleft = sc->sc_dleft; - ecb->flags |= ECB_DONE; + sc->sc_flags |= ESP_BUSFREE_OK; break; + case MSG_MESSAGE_REJECT: - if (esp_debug & ESP_SHOWMISC) - printf("%s targ %d: our msg rejected by target\n", - sc->sc_dev.dv_xname, - ecb->xs->sc_link->target); - if (sc->sc_flags & ESPF_SYNCHNEGO) { - /* - * Device doesn't even know what sync is - * (right?) - */ - ti->offset = 0; - ti->period = sc->sc_minsync; - ti->synctp = 250 / ti->period; - sc->sc_flags &= ~ESPF_SYNCHNEGO; - ti->flags &= ~DO_NEGOTIATE; + if (esp_debug & ESP_SHOWMSGS) + printf("%s: our msg rejected by target\n", + sc->sc_dev.dv_xname); +#if 1 /* XXX - must remember last message */ +sc_print_addr(ecb->xs->sc_link); printf("MSG_MESSAGE_REJECT>>"); +#endif + if (sc->sc_flags & ESP_SYNCHNEGO) { + ti->period = ti->offset = 0; + sc->sc_flags &= ~ESP_SYNCHNEGO; + ti->flags &= ~T_NEGOTIATE; } /* Not all targets understand INITIATOR_DETECTED_ERR */ - if (sc->sc_msgout == SEND_INIT_DET_ERR) { + if (sc->sc_msgout == SEND_INIT_DET_ERR) esp_sched_msgout(SEND_ABORT); - DELAY(1); - } break; case MSG_NOOP: + ESP_MSGS(("noop ")); break; case MSG_DISCONNECT: - if (!ecb) { - esp_sched_msgout(SEND_ABORT); - DELAY(1); - printf("%s: nothing to DISCONNECT\n", - sc->sc_dev.dv_xname); - break; - } + ESP_MSGS(("disconnect ")); ti->dconns++; - TAILQ_INSERT_HEAD(&sc->nexus_list, ecb, chain); - ecb = sc->sc_nexus = NULL; - sc->sc_state = ESPS_EXPECTDISC; - sc->sc_flags |= ESPF_MAYDISCON; - break; - case MSG_SAVEDATAPOINTER: - if (!ecb) { - esp_sched_msgout(SEND_ABORT); - DELAY(1); - printf("%s: no DATAPOINTERs to save\n", - sc->sc_dev.dv_xname); + sc->sc_flags |= ESP_DISCON; + sc->sc_flags |= ESP_BUSFREE_OK; + if ((ecb->xs->sc_link->quirks & SDEV_AUTOSAVE) == 0) break; - } - ESPD(("DL%d/%d ", sc->sc_dleft, ecb->dleft)); + /*FALLTHROUGH*/ + case MSG_SAVEDATAPOINTER: + ESP_MSGS(("save datapointer ")); ecb->dleft = sc->sc_dleft; ecb->daddr = sc->sc_dp; break; case MSG_RESTOREPOINTERS: + ESP_MSGS(("restore datapointer ")); if (!ecb) { esp_sched_msgout(SEND_ABORT); - DELAY(1); printf("%s: no DATAPOINTERs to restore\n", sc->sc_dev.dv_xname); break; @@ -1028,43 +1062,95 @@ gotit: sc->sc_dp = ecb->daddr; sc->sc_dleft = ecb->dleft; break; + case MSG_PARITY_ERROR: + printf("%s:target%d: MSG_PARITY_ERROR\n", + sc->sc_dev.dv_xname, + ecb->xs->sc_link->target); + break; case MSG_EXTENDED: + ESP_MSGS(("extended(%x) ", sc->sc_imess[2])); switch (sc->sc_imess[2]) { case MSG_EXT_SDTR: + ESP_MSGS(("SDTR period %d, offset %d ", + sc->sc_imess[3], sc->sc_imess[4])); ti->period = sc->sc_imess[3]; ti->offset = sc->sc_imess[4]; - sc->sc_flags &= ~ESPF_SYNCHNEGO; - ti->flags &= ~DO_NEGOTIATE; - if (ti->offset == 0 || - ti->offset > ESP_SYNC_MAXOFF || - ti->period < sc->sc_minsync) { + if (sc->sc_minsync == 0) { + /* We won't do synch */ ti->offset = 0; - ti->period = sc->sc_minsync; - ti->synctp = 250 / ti->period; - break; + esp_sched_msgout(SEND_SDTR); + } else if (ti->offset == 0) { + printf("%s:%d: async\n", "esp", + ecb->xs->sc_link->target); + ti->offset = 0; + sc->sc_flags &= ~ESP_SYNCHNEGO; + } else if (ti->period > 124) { + printf("%s:%d: async\n", "esp", + ecb->xs->sc_link->target); + ti->offset = 0; + esp_sched_msgout(SEND_SDTR); + } else { + int r = 250/ti->period; + int s = (100*250)/ti->period - 100*r; + int p; + p = esp_stp2cpb(sc, ti->period); + ti->period = esp_cpb2stp(sc, p); +#ifdef ESP_DEBUG + sc_print_addr(ecb->xs->sc_link); +#endif + if ((sc->sc_flags&ESP_SYNCHNEGO) == 0) { + /* Target initiated negotiation */ + if (ti->flags & T_SYNCMODE) { + ti->flags &= ~T_SYNCMODE; +#ifdef ESP_DEBUG + printf("renegotiated "); +#endif + } + ESP_WRITE_REG(sc, ESP_SYNCOFF, + 0); + ESP_WRITE_REG(sc, ESP_SYNCTP, + 0); + /* Clamp to our maxima */ + if (ti->period < sc->sc_minsync) + ti->period = sc->sc_minsync; + if (ti->offset > 15) + ti->offset = 15; + esp_sched_msgout(SEND_SDTR); + } else { + /* we are sync */ + sc->sc_flags &= ~ESP_SYNCHNEGO; + ESP_WRITE_REG(sc, ESP_SYNCOFF, + ti->offset); + ESP_WRITE_REG(sc, ESP_SYNCTP, + p); + ti->flags |= T_SYNCMODE; + } +#ifdef ESP_DEBUG + printf("max sync rate %d.%02dMb/s\n", + r, s); +#endif } - printf("%s targ %d: sync, offset %d, period %dnsec\n", - sc->sc_dev.dv_xname, ecb->xs->sc_link->target, - ti->offset, ti->period * 4); - ti->synctp = 250 / ti->period; + ti->flags &= ~T_NEGOTIATE; break; - default: - /* Extended messages we don't handle */ - esp_sched_msgout(SEND_REJECT); - DELAY(1); + default: /* Extended messages we don't handle */ + ESPCMD(sc, ESPCMD_SETATN); break; } break; default: - /* thanks for that ident... XXX: we should check it? */ + ESP_MSGS(("ident ")); + /* thanks for that ident... */ if (!MSG_ISIDENTIFY(sc->sc_imess[0])) { - esp_sched_msgout(SEND_REJECT); - DELAY(1); + ESP_MISC(("unknown ")); +printf("%s: unimplemented message: %d\n", sc->sc_dev.dv_xname, sc->sc_imess[0]); + ESPCMD(sc, ESPCMD_SETATN); } break; } - } else if (sc->sc_state == ESPS_RESELECTED) { - struct scsi_link *sc_link; + } else if (sc->sc_state == ESP_RESELECTED) { + struct scsi_link *sc_link = NULL; + struct ecb *ecb; + struct esp_tinfo *ti; u_char lunit; if (MSG_ISIDENTIFY(sc->sc_imess[0])) { /* Identify? */ @@ -1073,115 +1159,65 @@ gotit: * Search wait queue for disconnected cmd * The list should be short, so I haven't bothered with * any more sophisticated structures than a simple - * singly linked list. + * singly linked list. */ lunit = sc->sc_imess[0] & 0x07; for (ecb = sc->nexus_list.tqh_first; ecb; - ecb = ecb->chain.tqe_next) { + ecb = ecb->chain.tqe_next) { sc_link = ecb->xs->sc_link; if (sc_link->lun == lunit && sc->sc_selid == (1<<sc_link->target)) { TAILQ_REMOVE(&sc->nexus_list, ecb, chain); + ECB_SETQ(ecb, ECB_QNONE); break; } } - if (!ecb) { - /* Invalid reselection! */ + if (!ecb) { /* Invalid reselection! */ esp_sched_msgout(SEND_ABORT); - DELAY(1); printf("esp: invalid reselect (idbit=0x%2x)\n", sc->sc_selid); - } else { + } else { /* Reestablish nexus */ /* - * Reestablish nexus: * Setup driver data structures and * do an implicit RESTORE POINTERS */ + ti = &sc->sc_tinfo[sc_link->target]; sc->sc_nexus = ecb; sc->sc_dp = ecb->daddr; sc->sc_dleft = ecb->dleft; - sc->sc_tinfo[sc_link->target].lubusy |= - (1<<sc_link->lun); - espr->espr_syncoff = - sc->sc_tinfo[sc_link->target].offset; - espr->espr_synctp = 250 / - sc->sc_tinfo[sc_link->target].period; + sc->sc_tinfo[sc_link->target].lubusy + |= (1<<sc_link->lun); + if (ti->flags & T_SYNCMODE) { + ESP_WRITE_REG(sc, ESP_SYNCOFF, + ti->offset); + ESP_WRITE_REG(sc, ESP_SYNCTP, + esp_stp2cpb(sc, ti->period)); + } else { + ESP_WRITE_REG(sc, ESP_SYNCOFF, 0); + ESP_WRITE_REG(sc, ESP_SYNCTP, 0); + } ESP_MISC(("... found ecb")); - sc->sc_state = ESPS_NEXUS; + sc->sc_state = ESP_HASNEXUS; } } else { printf("%s: bogus reselect (no IDENTIFY) %0x2x\n", sc->sc_dev.dv_xname, sc->sc_selid); esp_sched_msgout(SEND_DEV_RESET); - DELAY(1); } } else { /* Neither ESP_HASNEXUS nor ESP_RESELECTED! */ printf("%s: unexpected message in; will send DEV_RESET\n", sc->sc_dev.dv_xname); esp_sched_msgout(SEND_DEV_RESET); - DELAY(1); } -done: - espr->espr_cmd = ESPCMD_MSGOK; - espr->espr_cmd = ESPCMD_NOP; -} - -void -esp_makemsg(sc) - register struct esp_softc *sc; -{ - struct esp_tinfo *ti; - struct ecb *ecb = sc->sc_nexus; - int i; + /* Ack last message byte */ + ESPCMD(sc, ESPCMD_MSGOK); - sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq; - ESPD(("MQ%02x/%02x ", sc->sc_msgpriq, sc->sc_msgout)); - - sc->sc_omlen = 1; /* "Default" message len */ - switch (sc->sc_msgout) { - case SEND_SDTR: /* implies an IDENTIFY message */ - sc->sc_flags |= ESPF_SYNCHNEGO; - ti = &sc->sc_tinfo[ecb->xs->sc_link->target]; - sc->sc_omess[0] = MSG_IDENTIFY(ecb->xs->sc_link->lun, - !(ecb->xs->flags & SCSI_POLL)); - sc->sc_omess[1] = MSG_EXTENDED; - sc->sc_omess[2] = 3; - sc->sc_omess[3] = MSG_EXT_SDTR; - sc->sc_omess[4] = ti->period; - sc->sc_omess[5] = ti->offset; - sc->sc_omlen = 6; - /* Fallthrough! */ - case SEND_IDENTIFY: - sc->sc_omess[0] = MSG_IDENTIFY(ecb->xs->sc_link->lun, - !(ecb->xs->flags & SCSI_POLL)); - break; - case SEND_DEV_RESET: - sc->sc_omess[0] = MSG_BUS_DEV_RESET; - if (sc->sc_nexus) - sc->sc_nexus->flags |= ECB_DONE; - break; - case SEND_PARITY_ERROR: - sc->sc_omess[0] = MSG_PARITY_ERROR; - break; - case SEND_ABORT: - sc->sc_omess[0] = MSG_ABORT; - if (sc->sc_nexus) - sc->sc_nexus->flags |= ECB_DONE; - break; - case SEND_INIT_DET_ERR: - sc->sc_omess[0] = MSG_INITIATOR_DET_ERR; - break; - case SEND_REJECT: - sc->sc_omess[0] = MSG_MESSAGE_REJECT; - break; - default: - sc->sc_omess[0] = MSG_NOOP; - break; - } - sc->sc_omp = sc->sc_omess; + /* Done, reset message pointer. */ + sc->sc_flags &= ~ESP_DROP_MSGI; + sc->sc_imlen = 0; } @@ -1192,650 +1228,746 @@ void esp_msgout(sc) register struct esp_softc *sc; { - struct espregs *espr = sc->sc_regs; struct esp_tinfo *ti; struct ecb *ecb; - int i; - - /* Pick up highest priority message */ - sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq; - esp_makemsg(sc); - - for (i = 0; i < sc->sc_omlen; i++) - espr->espr_fifo = sc->sc_omp[i]; - espr->espr_cmd = ESPCMD_TRANS; -} - + size_t size; -void -esp_timeout(arg) - void *arg; -{ - struct ecb *ecb = (struct ecb *)arg; - struct esp_softc *sc; + ESP_TRACE(("[esp_msgout(priq:%x, prevphase:%x)]", sc->sc_msgpriq, sc->sc_prevphase)); - sc = ecb->xs->sc_link->adapter_softc; - sc_print_addr(ecb->xs->sc_link); - printf("timed out at %d %d\n", sc->sc_state, sc->sc_phase); + if (sc->sc_prevphase != MESSAGE_OUT_PHASE) { + /* Pick up highest priority message */ + sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq; + sc->sc_omlen = 1; /* "Default" message len */ + switch (sc->sc_msgout) { + case SEND_SDTR: + ecb = sc->sc_nexus; + ti = &sc->sc_tinfo[ecb->xs->sc_link->target]; + sc->sc_omess[0] = MSG_EXTENDED; + sc->sc_omess[1] = 3; + sc->sc_omess[2] = MSG_EXT_SDTR; + sc->sc_omess[3] = ti->period; + sc->sc_omess[4] = ti->offset; + sc->sc_omlen = 5; + break; + case SEND_IDENTIFY: + if (sc->sc_state != ESP_HASNEXUS) { + printf("esp at line %d: no nexus", __LINE__); + } + ecb = sc->sc_nexus; + sc->sc_omess[0] = MSG_IDENTIFY(ecb->xs->sc_link->lun,0); + break; + case SEND_DEV_RESET: + sc->sc_omess[0] = MSG_BUS_DEV_RESET; + sc->sc_flags |= ESP_BUSFREE_OK; + ecb = sc->sc_nexus; + ti = &sc->sc_tinfo[ecb->xs->sc_link->target]; + ti->flags &= ~T_SYNCMODE; + ti->flags |= T_NEGOTIATE; + break; + case SEND_PARITY_ERROR: + sc->sc_omess[0] = MSG_PARITY_ERROR; + break; + case SEND_ABORT: + sc->sc_omess[0] = MSG_ABORT; + sc->sc_flags |= ESP_BUSFREE_OK; + break; + case SEND_INIT_DET_ERR: + sc->sc_omess[0] = MSG_INITIATOR_DET_ERR; + break; + case SEND_REJECT: + sc->sc_omess[0] = MSG_MESSAGE_REJECT; + break; + default: + sc->sc_omess[0] = MSG_NOOP; + break; + } + sc->sc_omp = sc->sc_omess; + } - ecb->xs->error = XS_TIMEOUT; - esp_reset(sc); - esp_done(ecb); - printf("new ecb %08x\n", sc->sc_nexus); +#if 1 + /* (re)send the message */ + size = min(sc->sc_omlen, sc->sc_maxxfer); + DMA_SETUP(sc->sc_dma, &sc->sc_omp, &sc->sc_omlen, 0, &size); + /* Program the SCSI counter */ + ESP_WRITE_REG(sc, ESP_TCL, size); + ESP_WRITE_REG(sc, ESP_TCM, size >> 8); + if (sc->sc_cfg2 & ESPCFG2_FE) { + ESP_WRITE_REG(sc, ESP_TCH, size >> 16); + } + /* load the count in */ + ESPCMD(sc, ESPCMD_NOP|ESPCMD_DMA); + ESPCMD(sc, (size==0?ESPCMD_TRPAD:ESPCMD_TRANS)|ESPCMD_DMA); + DMA_GO(sc->sc_dma); +#else + { int i; + ESPCMD(sc, ESPCMD_FLUSH); + for (i = 0; i < sc->sc_omlen; i++) + ESP_WRITE_REG(sc, FIFO, sc->sc_omess[i]); + ESPCMD(sc, ESPCMD_TRANS); +#if test_stuck_on_msgout +printf("<<XXXmsgoutdoneXXX>>"); +#endif + } +#endif } /* - * Read the ESP registers, and save their contents for later use. - * ESP_STAT, ESP_STEP & ESP_INTR are mostly zeroed out when reading - * ESP_INTR - so make sure it is the last read. + * This is the most critical part of the driver, and has to know + * how to deal with *all* error conditions and phases from the SCSI + * bus. If there are no errors and the DMA was active, then call the + * DMA pseudo-interrupt handler. If this returns 1, then that was it + * and we can return from here without further processing. * - * XXX: TDR: this logic seems unsound - * I think that (from reading the docs) most bits in these registers - * only make sense when the DMA CSR has an interrupt showing. So I have - * coded this to not do anything if there is no interrupt or error - * pending. + * Most of this needs verifying. */ -void -espreadregs(sc) - struct esp_softc *sc; -{ - struct espregs *espr = sc->sc_regs; - - /* they mean nothing if the is no pending interrupt ??? */ - if (!(dmapending(sc->sc_dma))) - return; - - /* Only the stepo bits are of interest */ - sc->sc_espstep = espr->espr_step & ESPSTEP_MASK; - sc->sc_espstat = espr->espr_stat; - sc->sc_espintr = espr->espr_intr; - - ESP_MISC(("regs[intr=%02x,stat=%02x,step=%02x] ", sc->sc_espintr, - sc->sc_espstat, sc->sc_espstep)); -} - -/* - * Whatever we do, we must generate an interrupt if we expect to go - * to the next state. - * Note: this increments the events even if called from esp_poll() - */ -int +int espintr(sc) register struct esp_softc *sc; { - struct espregs *espr = sc->sc_regs; - register struct ecb *ecb = sc->sc_nexus; + register struct ecb *ecb; register struct scsi_link *sc_link; - u_char *cmd; struct esp_tinfo *ti; - int dmaintrwas, i; + int loop; + size_t size; - /* - * Revision 1 DMA's must have their interrupts disabled, - * otherwise we can get bus timeouts while reading ESP - * registers. - */ - if (sc->sc_dma->sc_rev == DMAREV_1) - dmaintrwas = dmadisintr(sc->sc_dma); - - espreadregs(sc); + ESP_TRACE(("[espintr]")); /* - * If either of these two things is true, we caused an interrupt. - * If we didn't, let's get out of here. + * I have made some (maybe seriously flawed) assumptions here, + * but basic testing (uncomment the printf() below), show that + * certainly something happens when this loop is here. + * + * The idea is that many of the SCSI operations take very little + * time, and going away and getting interrupted is too high an + * overhead to pay. For example, selecting, sending a message + * and command and then doing some work can be done in one "pass". + * + * The DELAY is not variable because I do not understand that the + * DELAY loop should be fixed-time regardless of CPU speed, but + * I am *assuming* that the faster SCSI processors get things done + * quicker (sending a command byte etc), and so there is no + * need to be too slow. + * + * This is a heuristic. It is 2 when at 20Mhz, 2 at 25Mhz and 1 + * at 40Mhz. This needs testing. */ - if ((sc->sc_espintr | dmapending(sc->sc_dma)) == 0) { - if (sc->sc_dma->sc_rev == DMAREV_1 && dmaintrwas) - dmaenintr(sc->sc_dma); - return (0); - } + for (loop = 0; 1;loop++, DELAY(50/sc->sc_freq)) { + /* a feeling of deja-vu */ + if (!DMA_ISINTR(sc->sc_dma)) + return (loop != 0); +#if 0 + if (loop) + printf("*"); +#endif - sc->sc_phase = espphase(sc); + /* and what do the registers say... */ + espreadregs(sc); - ESPD(("I%02x/%02x/%02x ", sc->sc_espintr, sc->sc_state, sc->sc_phase)); + sc->sc_intrcnt.ev_count++; - if (sc->sc_espintr & ESPINTR_SBR) { - espflush(sc); - printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname); - esp_init(sc, 0); /* Restart everything */ /* - * No interrupt expected, since there are now no - * ecb's in progress. + * At the moment, only a SCSI Bus Reset or Illegal + * Command are classed as errors. A disconnect is a + * valid condition, and we let the code check is the + * "ESP_BUSFREE_OK" flag was set before declaring it + * and error. + * + * Also, the status register tells us about "Gross + * Errors" and "Parity errors". Only the Gross Error + * is really bad, and the parity errors are dealt + * with later + * + * TODO + * If there are too many parity error, go to slow + * cable mode ? */ - goto done; - } - if (sc->sc_espintr & ESPINTR_ILL) { - printf("%s: illegal command %02x\n", - sc->sc_dev.dv_xname, espr->espr_cmd); - if (sc->sc_state == ESPS_NEXUS) { - ecb->xs->error = XS_DRIVER_STUFFUP; - untimeout(esp_timeout, ecb); - esp_done(ecb); + /* SCSI Reset */ + if (sc->sc_espintr & ESPINTR_SBR) { + if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) { + ESPCMD(sc, ESPCMD_FLUSH); + DELAY(1); + } + if (sc->sc_state != ESP_SBR) { + printf("%s: SCSI bus reset\n", + sc->sc_dev.dv_xname); + esp_init(sc, 0); /* Restart everything */ + return 1; + } +#if 0 + /*XXX*/ printf("<expected bus reset: " + "[intr %x, stat %x, step %d]>\n", + sc->sc_espintr, sc->sc_espstat, + sc->sc_espstep); +#endif + if (sc->sc_nexus) + panic("%s: nexus in reset state", + sc->sc_dev.dv_xname); + sc->sc_state = ESP_IDLE; + esp_sched(sc); + return 1; } - esp_reset(sc); - esp_sched(sc); /* start next command */ - goto done; - } - if (sc->sc_espstat & ESPSTAT_GE) { - /* no target ? */ - espflush(sc); - printf("%s: gross error\n", sc->sc_dev.dv_xname); - if (sc->sc_state == ESPS_NEXUS) { - ecb->xs->error = XS_DRIVER_STUFFUP; - untimeout(esp_timeout, ecb); - esp_done(ecb); - } - esp_reset(sc); - esp_sched(sc); - /* started next command, which will interrupt us */ - goto done; - } + ecb = sc->sc_nexus; - /* - * The `bad interrupts' have already been checked. - */ -states: - switch (sc->sc_state) { - case ESPS_IDLE: - ESPD(("I ")); +#define ESPINTR_ERR (ESPINTR_SBR|ESPINTR_ILL) + if (sc->sc_espintr & ESPINTR_ERR || + sc->sc_espstat & ESPSTAT_GE) { - sc->sc_nexus = NULL; + if (sc->sc_espstat & ESPSTAT_GE) { + /* no target ? */ + if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) { + ESPCMD(sc, ESPCMD_FLUSH); + DELAY(1); + } + if (sc->sc_state == ESP_HASNEXUS || + sc->sc_state == ESP_SELECTING) { + ecb->xs->error = XS_DRIVER_STUFFUP; + esp_done(ecb); + } + return 1; + } - if (sc->sc_espintr & ESPINTR_RESEL) { - sc->sc_state = ESPS_RESELECTED; - goto states; + if (sc->sc_espintr & ESPINTR_ILL) { + /* illegal command, out of sync ? */ + printf("%s: illegal command: 0x%x (state %d, phase %x, prevphase %x)\n", + sc->sc_dev.dv_xname, sc->sc_lastcmd, + sc->sc_state, sc->sc_phase, + sc->sc_prevphase); + if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) { + ESPCMD(sc, ESPCMD_FLUSH); + DELAY(1); + } + esp_init(sc, 0); /* Restart everything */ + return 1; + } } - esp_sched(sc); /* - * We will get an interrupt if esp_sched() queues - * anything to the scsi bus. + * Call if DMA is active. + * + * If DMA_INTR returns true, then maybe go 'round the loop + * again in case there is no more DMA queued, but a phase + * change is expected. */ - goto done; - case ESPS_SELECTING: + if (DMA_ISACTIVE(sc->sc_dma)) { + DMA_INTR(sc->sc_dma); + /* If DMA active here, then go back to work... */ + if (DMA_ISACTIVE(sc->sc_dma)) + return 1; + + if (sc->sc_dleft == 0 && + (sc->sc_espstat & ESPSTAT_TC) == 0) + printf("%s: !TC [intr %x, stat %x, step %d]" + " prevphase %x, resid %x\n", + sc->sc_dev.dv_xname, + sc->sc_espintr, + sc->sc_espstat, + sc->sc_espstep, + sc->sc_prevphase, + ecb?ecb->dleft:-1); + } + +#if 0 /* Unreliable on some ESP revisions? */ + if ((sc->sc_espstat & ESPSTAT_INT) == 0) { + printf("%s: spurious interrupt\n", sc->sc_dev.dv_xname); + return 1; + } +#endif + /* - * For a simple select, we sent either - * ESPCMD_SELATN or ESPCMD_SELNATN + * check for less serious errors */ - ESPD(("S ")); - - if (sc->sc_espintr & ESPINTR_DIS) { - sc->sc_state = ESPS_NEXUS; /* will cleanup */ - goto states; + if (sc->sc_espstat & ESPSTAT_PE) { + printf("%s: SCSI bus parity error\n", + sc->sc_dev.dv_xname); + if (sc->sc_prevphase == MESSAGE_IN_PHASE) + esp_sched_msgout(SEND_PARITY_ERROR); + else + esp_sched_msgout(SEND_INIT_DET_ERR); } - if (sc->sc_espintr & ESPINTR_RESEL) { + if (sc->sc_espintr & ESPINTR_DIS) { + ESP_MISC(("<DISC [intr %x, stat %x, step %d]>", + sc->sc_espintr,sc->sc_espstat,sc->sc_espstep)); + if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) { + ESPCMD(sc, ESPCMD_FLUSH); + DELAY(1); + } /* - * If we were trying to select a target, - * push our command back into the ready list. + * This command must (apparently) be issued within + * 250mS of a disconnect. So here you are... */ - if (sc->sc_state == ESPS_SELECTING) { - TAILQ_INSERT_HEAD(&sc->ready_list, - sc->sc_nexus, chain); - ecb = sc->sc_nexus = NULL; - } - sc->sc_state = ESPS_RESELECTED; - goto states; - } - - if (sc->sc_espintr == (ESPINTR_FC|ESPINTR_BS)) { - ESPD(("STEP%d ", sc->sc_espstep)); - if (sc->sc_espstep == 0) { - /* ATN: cannot happen */ - /* NATN: target did not assert message phase */ - sc->sc_state = ESPS_IDLE; - goto states; - } else if (sc->sc_espstep == 2) { - /* BOTH: target did not assert command phase */ - sc->sc_state = ESPS_IDLE; - goto states; - } else if (sc->sc_espstep == 3) { - /* BOTH: changed phase during cmd transfer */ - ESPD(("FF%d ", espr->espr_fflag & ESPFIFO_FF)); - if (espr->espr_fflag & ESPFIFO_FF) { - sc->sc_state = ESPS_IDLE; - goto states; + ESPCMD(sc, ESPCMD_ENSEL); + if (sc->sc_state != ESP_IDLE) { + if ((sc->sc_flags & ESP_SYNCHNEGO)) { +#ifdef ESP_DEBUG + if (ecb) + sc_print_addr(ecb->xs->sc_link); + printf("sync nego not completed!\n"); +#endif + sc->sc_flags &= ~ESP_SYNCHNEGO; + sc->sc_tinfo[ecb->xs->sc_link->target].offset = 0; + sc->sc_tinfo[ecb->xs->sc_link->target].flags &= ~T_NEGOTIATE; + } + /*XXX*/sc->sc_msgpriq = sc->sc_msgout = 0; + + /* it may be OK to disconnect */ + if (!(sc->sc_flags & ESP_BUSFREE_OK)) { + if (sc->sc_state == ESP_HASNEXUS) { + sc_print_addr(ecb->xs->sc_link); + printf("disconnect without" + "warning\n"); + } + ecb->xs->error = XS_TIMEOUT; + } else if (sc->sc_flags & ESP_DISCON) { + TAILQ_INSERT_HEAD(&sc->nexus_list, ecb, chain); + ECB_SETQ(ecb, ECB_QNEXUS); + sc->sc_nexus = NULL; + sc->sc_flags &= ~ESP_DISCON; + sc->sc_state = ESP_IDLE; +#if ESP_DEBUG +if ((esp_debug & 0x10000) && ecb->dleft == 0) { + printf("%s: silly disconnect (ecb %p [stat %x])\n", + sc->sc_dev.dv_xname, ecb, ecb->stat); +} +#endif + esp_sched(sc); + return 1; } - } - espr->espr_cmd = ESPCMD_NOP; /* unlatch fifo counter */ - if (sc->sc_phase != DATA_IN_PHASE && - sc->sc_tinfo[ecb->xs->sc_link->target].offset == 0) { - DELAY(1); - espflush(sc); + esp_done(ecb); + return 1; } + printf("%s: DISCONNECT in IDLE state!\n", + sc->sc_dev.dv_xname); + } - ecb = sc->sc_nexus; - if (!ecb) - panic("esp: not nexus at sc->sc_nexus"); - sc_link = ecb->xs->sc_link; - ti = &sc->sc_tinfo[sc_link->target]; - sc->sc_flags = 0; - - /* Clearly we succeeded at sending the message */ + /* did a message go out OK ? This must be broken */ + if (sc->sc_prevphase == MESSAGE_OUT_PHASE && + sc->sc_phase != MESSAGE_OUT_PHASE) { + /* we have sent it */ + if (sc->sc_msgout == SEND_SDTR && + (sc->sc_flags & ESP_SYNCHNEGO) == 0) { + /* We've just accepted new sync parameters */ + sc->sc_tinfo[ecb->xs->sc_link->target].flags |= + T_SYNCMODE; +if (ecb) sc_print_addr(ecb->xs->sc_link);else printf("NO nexus: "); +printf("target put in SYNC mode\n"); + } sc->sc_msgpriq &= ~sc->sc_msgout; sc->sc_msgout = 0; - if (sc->sc_msgpriq) - espr->espr_cmd = ESPCMD_SETATN; - - sc->sc_dp = ecb->daddr; /* implicit RESTOREDATAPOINTERS */ - sc->sc_dleft = ecb->dleft; - ti->lubusy |= (1<<sc_link->lun); - - sc->sc_state = ESPS_NEXUS; } - break; /* handle the phase */ - case ESPS_SELECTSTOP: - /* - * We wanted to select with multiple message bytes. - * As a result, we needed to use SELATNS. One - * message byte has been sent at this point. We need - * to send the other bytes, then the target will either - * switch to command phase to fetch the command or - * send us a message. - */ - ESPD(("SS%d ", sc->sc_espstep)); - if (sc->sc_espintr & ESPINTR_DIS) { - sc->sc_state = ESPS_NEXUS; - goto states; - } + switch (sc->sc_state) { + + case ESP_SBR: + printf("%s: waiting for SCSI Bus Reset to happen\n", + sc->sc_dev.dv_xname); + return 1; - if (sc->sc_espintr & ESPINTR_RESEL) { + case ESP_RESELECTED: /* - * If we were trying to select a target, - * push our command back into the ready list. + * we must be continuing a message ? */ - if (sc->sc_state == ESPS_SELECTING) { - TAILQ_INSERT_HEAD(&sc->ready_list, - sc->sc_nexus, chain); - ecb = sc->sc_nexus = NULL; + if (sc->sc_phase != MESSAGE_IN_PHASE) { + printf("%s: target didn't identify\n", + sc->sc_dev.dv_xname); + esp_init(sc, 1); + return 1; } - sc->sc_state = ESPS_RESELECTED; - goto states; - } +printf("<<RESELECT CONT'd>>"); +#if XXXX + esp_msgin(sc); + if (sc->sc_state != ESP_HASNEXUS) { + /* IDENTIFY fail?! */ + printf("%s: identify failed\n", + sc->sc_dev.dv_xname); + esp_init(sc, 1); + return 1; + } +#endif + break; - if (sc->sc_espintr & (ESPINTR_BS|ESPINTR_FC)) { - int i; + case ESP_IDLE: +if (sc->sc_flags & ESP_ICCS) printf("[[esp: BUMMER]]"); + case ESP_SELECTING: - /* - * Shove the remainder of the message bytes - * into the fifo. After we send them, command - * phase will request the command... - */ - espflush(sc); - for (i = 1; i < sc->sc_omlen; i++) - espr->espr_fifo = sc->sc_omp[i]; - espr->espr_cmd = ESPCMD_TRANS; - sc->sc_state = ESPS_MULTMSGEND; - goto done; - } - goto done; - case ESPS_MULTMSGEND: - ESPD(("MME ")); - if (sc->sc_espintr & ESPINTR_DIS) { - sc->sc_state = ESPS_NEXUS; - goto states; - } + if (sc->sc_espintr & ESPINTR_RESEL) { + /* + * If we're trying to select a + * target ourselves, push our command + * back into the ready list. + */ + if (sc->sc_state == ESP_SELECTING) { + ESP_MISC(("backoff selector ")); + sc_link = sc->sc_nexus->xs->sc_link; + ti = &sc->sc_tinfo[sc_link->target]; + TAILQ_INSERT_HEAD(&sc->ready_list, + sc->sc_nexus, chain); + ECB_SETQ(sc->sc_nexus, ECB_QREADY); + ti->lubusy &= ~(1<<sc_link->lun); + ecb = sc->sc_nexus = NULL; + } + sc->sc_state = ESP_RESELECTED; + if (sc->sc_phase != MESSAGE_IN_PHASE) { + /* + * Things are seriously fucked up. + * Pull the brakes, i.e. reset + */ + printf("%s: target didn't identify\n", + sc->sc_dev.dv_xname); + esp_init(sc, 1); + return 1; + } + if ((ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) != 2) { + printf("%s: RESELECT: %d bytes in FIFO!\n", + sc->sc_dev.dv_xname, + ESP_READ_REG(sc, ESP_FFLAG) & + ESPFIFO_FF); + esp_init(sc, 1); + return 1; + } + sc->sc_selid = ESP_READ_REG(sc, ESP_FIFO); + sc->sc_selid &= ~(1<<sc->sc_id); + ESP_MISC(("selid=0x%2x ", sc->sc_selid)); + esp_msgin(sc); /* Handle identify message */ + if (sc->sc_state != ESP_HASNEXUS) { + /* IDENTIFY fail?! */ + printf("%s: identify failed\n", + sc->sc_dev.dv_xname); + esp_init(sc, 1); + return 1; + } + continue; /* ie. next phase expected soon */ + } - sc->sc_msgpriq &= ~sc->sc_msgout; - sc->sc_msgout = 0; +#define ESPINTR_DONE (ESPINTR_FC|ESPINTR_BS) + if ((sc->sc_espintr & ESPINTR_DONE) == ESPINTR_DONE) { + ecb = sc->sc_nexus; + if (!ecb) + panic("esp: not nexus at sc->sc_nexus"); - ESPD(("F%d ", espr->espr_fflag & ESPFIFO_FF)); - if (espr->espr_fflag & ESPFIFO_FF) { - espflush(sc); - DELAY(1); - } + sc_link = ecb->xs->sc_link; + ti = &sc->sc_tinfo[sc_link->target]; + + switch (sc->sc_espstep) { + case 0: + printf("%s: select timeout/no disconnect\n", + sc->sc_dev.dv_xname); + esp_abort(sc, ecb); + return 1; + case 1: + if ((ti->flags & T_NEGOTIATE) == 0) { + printf("%s: step 1 & !NEG\n", + sc->sc_dev.dv_xname); + esp_abort(sc, ecb); + return 1; + } + if (sc->sc_phase != MESSAGE_OUT_PHASE) { + printf("%s: !MSGOUT\n", + sc->sc_dev.dv_xname); + esp_abort(sc, ecb); + return 1; + } + /* Start negotiating */ + ti->period = sc->sc_minsync; + ti->offset = 15; + sc->sc_msgpriq = SEND_SDTR; + sc->sc_flags |= ESP_SYNCHNEGO; + break; + case 3: + /* + * Grr, this is supposed to mean + * "target left command phase + * prematurely". It seems to happen + * regularly when sync mode is on. + * Look at FIFO to see if command + * went out. + * (Timing problems?) + */ + if ((ESP_READ_REG(sc, ESP_FFLAG)&ESPFIFO_FF) == 0) { + /* Hope for the best.. */ + break; + } + printf("(%s:%d:%d): selection failed;" + " %d left in FIFO " + "[intr %x, stat %x, step %d]\n", + sc->sc_dev.dv_xname, + sc_link->target, + sc_link->lun, + ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF, + sc->sc_espintr, sc->sc_espstat, + sc->sc_espstep); + ESPCMD(sc, ESPCMD_FLUSH); + sc->sc_flags |= ESP_ABORTING; + esp_sched_msgout(SEND_ABORT); + return 1; + case 2: + /* Select stuck at Command Phase */ + ESPCMD(sc, ESPCMD_FLUSH); + case 4: + /* So far, everything went fine */ + sc->sc_msgpriq = 0; + break; + } +#if 0 +/* Why set msgpriq? (and not raise ATN) */ + if (ecb->xs->flags & SCSI_RESET) + sc->sc_msgpriq = SEND_DEV_RESET; + else if (ti->flags & T_NEGOTIATE) + sc->sc_msgpriq = + SEND_IDENTIFY | SEND_SDTR; + else + sc->sc_msgpriq = SEND_IDENTIFY; +#endif + sc->sc_state = ESP_HASNEXUS; + /*???sc->sc_flags = 0; */ + sc->sc_prevphase = INVALID_PHASE; /* ?? */ + sc->sc_dp = ecb->daddr; + sc->sc_dleft = ecb->dleft; + ti->lubusy |= (1<<sc_link->lun); + break; + } else { + printf("%s: unexpected status after select" + ": [intr %x, stat %x, step %x]\n", + sc->sc_dev.dv_xname, + sc->sc_espintr, sc->sc_espstat, + sc->sc_espstep); + ESPCMD(sc, ESPCMD_FLUSH); + DELAY(1); + esp_abort(sc, ecb); + } + if (sc->sc_state == ESP_IDLE) { + printf("%s: stray interrupt\n", sc->sc_dev.dv_xname); + return 0; + } + break; - /* - * If there are more messages, re-assert - * ATN so that we will enter MSGOUT phase - * again. Also, pause till that interrupt is - * done to see if the phase changes. - */ - if (sc->sc_msgpriq) - espr->espr_cmd = ESPCMD_SETATN; - sc->sc_state = ESPS_NEXUS; - goto states; - case ESPS_RESELECTED: - ESPD(("RS ")); - - if (sc->sc_phase != MESSAGE_IN_PHASE) { - printf("%s: target didn't identify\n", - sc->sc_dev.dv_xname); - esp_init(sc, 1); - goto done; - } - esp_msgin(sc); - if (sc->sc_state != ESPS_NEXUS) { - /* IDENTIFY failed?! */ - printf("%s: identify failed\n", sc->sc_dev.dv_xname); - esp_init(sc, 1); - goto done; - } + case ESP_HASNEXUS: + if (sc->sc_flags & ESP_ICCS) { + unsigned char msg; - /* - * We will get an interrupt because of the ESPCMD_MSGOK - * interrupt inside esp_msgin() - */ - goto done; - case ESPS_DOINGDMA: - /* - * Call if DMA is still active. If dmaintr() has finished, - * delay a while to let things settle, and then re-read the - * phase. - * - * XXX: should check ESPINTR_DIS - */ - if (sc->sc_espstat & ESPSTAT_PE) { - printf("%s: SCSI bus parity error\n", - sc->sc_dev.dv_xname); - esp_sched_msgout(SEND_INIT_DET_ERR); - /* XXX: anything else to do? */ - } + sc->sc_flags &= ~ESP_ICCS; - if (sc->sc_espintr & ESPINTR_BS) { - /* - * ESP says we have changed phase, or have - * finished transferring all the bytes. It - * doesn't matter which case, either way we - * will let the phase determine what happens - * next. - */ - ESPD(("DOINGDMA:BS:%02x/%02x ", sc->sc_espstat, - espr->espr_tcl)); - if (sc->sc_dma->sc_active) { - dmaintr(sc->sc_dma, 0); - if (sc->sc_dma->sc_active) - goto done; - } - } else { - ESPD(("DOINGDMA:cont ")); - if (sc->sc_dma->sc_active) { - dmaintr(sc->sc_dma, 1); - if (sc->sc_dma->sc_active) - goto done; + if (!(sc->sc_espintr & ESPINTR_DONE)) { + printf("%s: ICCS: " + ": [intr %x, stat %x, step %x]\n", + sc->sc_dev.dv_xname, + sc->sc_espintr, sc->sc_espstat, + sc->sc_espstep); + } + if ((ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) != 2) { + printf("%s: ICCS: expected 2, got %d " + ": [intr %x, stat %x, step %x]\n", + sc->sc_dev.dv_xname, + ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF, + sc->sc_espintr, sc->sc_espstat, + sc->sc_espstep); + ESPCMD(sc, ESPCMD_FLUSH); + esp_abort(sc, ecb); + return 1; + } + ecb->stat = ESP_READ_REG(sc, ESP_FIFO); + msg = ESP_READ_REG(sc, ESP_FIFO); + ESP_PHASE(("<stat:(%x,%x)>", ecb->stat, msg)); + if (msg == MSG_CMDCOMPLETE) { + sc->sc_flags |= ESP_BUSFREE_OK; + ecb->xs->resid = ecb->dleft = sc->sc_dleft; + } else + printf("%s: STATUS_PHASE: msg %d\n", + sc->sc_dev.dv_xname, msg); + ESPCMD(sc, ESPCMD_MSGOK); + continue; /* ie. wait for disconnect */ } + break; + default: + panic("%s: invalid state: %d", + sc->sc_dev.dv_xname, + sc->sc_state); } - /* finished a DMA transaction */ - sc->sc_flags = 0; - - ecb->daddr = sc->sc_dp; /* implicit SAVEDATAPOINTERS */ - ecb->dleft = sc->sc_dleft; - /* - * ESP100 strangeness -- need to fetch a new phase -- - * why? + * Driver is now in state ESP_HASNEXUS, i.e. we + * have a current command working the SCSI bus. */ - if (sc->sc_rev==ESP100 && - sc->sc_tinfo[ecb->xs->sc_link->target].offset) { - sc->sc_espstat = espr->espr_stat & ESPSTAT_PHASE; - sc->sc_phase = espphase(sc); - /* XXX should check if sync under/overran */ - } - sc->sc_state = ESPS_NEXUS; - break; /* handle the phase */ - case ESPS_DOINGMSGOUT: - ESPD(("DMO ")); - if (sc->sc_espintr & ESPINTR_DIS) { - sc->sc_state = ESPS_NEXUS; /* will cleanup */ - goto states; + if (sc->sc_state != ESP_HASNEXUS || ecb == NULL) { + panic("esp no nexus"); } - if (sc->sc_espintr & ESPINTR_BS) { - sc->sc_msgpriq &= ~sc->sc_msgout; - sc->sc_msgout = 0; + switch (sc->sc_phase) { + case MESSAGE_OUT_PHASE: + ESP_PHASE(("MESSAGE_OUT_PHASE ")); + esp_msgout(sc); + sc->sc_prevphase = MESSAGE_OUT_PHASE; + break; + case MESSAGE_IN_PHASE: + ESP_PHASE(("MESSAGE_IN_PHASE ")); + if (sc->sc_espintr & ESPINTR_BS) { + ESPCMD(sc, ESPCMD_FLUSH); + sc->sc_flags |= ESP_WAITI; + ESPCMD(sc, ESPCMD_TRANS); + } else if (sc->sc_espintr & ESPINTR_FC) { + if ((sc->sc_flags & ESP_WAITI) == 0) { + printf("%s: MSGIN: unexpected FC bit: " + "[intr %x, stat %x, step %x]\n", + sc->sc_dev.dv_xname, + sc->sc_espintr, sc->sc_espstat, + sc->sc_espstep); + } + sc->sc_flags &= ~ESP_WAITI; + esp_msgin(sc); + } else { + printf("%s: MSGIN: weird bits: " + "[intr %x, stat %x, step %x]\n", + sc->sc_dev.dv_xname, + sc->sc_espintr, sc->sc_espstat, + sc->sc_espstep); + } + sc->sc_prevphase = MESSAGE_IN_PHASE; + break; + case COMMAND_PHASE: { + /* well, this means send the command again */ + u_char *cmd = (u_char *)&ecb->cmd; + int i; - ESPD(("F%d ", espr->espr_fflag & ESPFIFO_FF)); - if (espr->espr_fflag & ESPFIFO_FF) { - espflush(sc); + ESP_PHASE(("COMMAND_PHASE 0x%02x (%d) ", + ecb->cmd.opcode, ecb->clen)); + if (ESP_READ_REG(sc, ESP_FFLAG) & ESPFIFO_FF) { + ESPCMD(sc, ESPCMD_FLUSH); DELAY(1); } - - /* - * If there are more messages, re-assert - * ATN so that we will enter MSGOUT phase - * again. Also, pause till that interrupt is - * done to see if the phase changes. - */ - if (sc->sc_msgpriq) - espr->espr_cmd = ESPCMD_SETATN; + /* Now the command into the FIFO */ + for (i = 0; i < ecb->clen; i++) + ESP_WRITE_REG(sc, ESP_FIFO, *cmd++); + ESPCMD(sc, ESPCMD_TRANS); + sc->sc_prevphase = COMMAND_PHASE; + } break; - } - -#if 0 - if (sc->sc_espintr & ESPINTR_FC) { - /* - * XXX: the book claims that an ESPINTR_BS is - * generated, not ESPINTR_FC. Check if that is - * true. - */ - } -#endif - break; /* handle the phase */ - case ESPS_DOINGMSGIN: - /* - * We receive two interrupts per message byte here: one for - * the MSGOK command in esp_msgin(), and one for the TRANS - * command below. - */ - ESPD(("DMI ")); - - if (sc->sc_espintr & ESPINTR_DIS) { - sc->sc_state = ESPS_NEXUS; /* will cleanup */ - goto states; - } - - if (sc->sc_espstat & ESPSTAT_PE) { - printf("%s: SCSI bus parity error\n", - sc->sc_dev.dv_xname); - esp_sched_msgout(SEND_PARITY_ERROR); - espflush(sc); - sc->sc_state = ESPS_NEXUS; - /* XXX: are we missing some fifo handling? */ - goto done; /* will be interrupted for MSGOUT */ - } + case DATA_OUT_PHASE: + ESP_PHASE(("DATA_OUT_PHASE [%d] ", sc->sc_dleft)); + ESPCMD(sc, ESPCMD_FLUSH); + size = min(sc->sc_dleft, sc->sc_maxxfer); + DMA_SETUP(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft, + 0, &size); + sc->sc_prevphase = DATA_OUT_PHASE; + goto setup_xfer; + case DATA_IN_PHASE: + ESP_PHASE(("DATA_IN_PHASE ")); + if (sc->sc_rev == ESP100) + ESPCMD(sc, ESPCMD_FLUSH); + size = min(sc->sc_dleft, sc->sc_maxxfer); + DMA_SETUP(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft, + 1, &size); + sc->sc_prevphase = DATA_IN_PHASE; + setup_xfer: + /* Program the SCSI counter */ + ESP_WRITE_REG(sc, ESP_TCL, size); + ESP_WRITE_REG(sc, ESP_TCM, size >> 8); + if (sc->sc_cfg2 & ESPCFG2_FE) { + ESP_WRITE_REG(sc, ESP_TCH, size >> 16); + } + /* load the count in */ + ESPCMD(sc, ESPCMD_NOP|ESPCMD_DMA); - /* - * The two interrupts we receive per byte will alternate - * between entering the following two if() statements. - * XXX: just incase, are these two if()'s in the correct - * order? - */ - if (sc->sc_espintr & ESPINTR_BS) { /* - * interrupted by ESPCMD_MSGOK in esp_msgin() + * Note that if `size' is 0, we've already transceived + * all the bytes we want but we're still in DATA PHASE. + * Apparently, the device needs padding. Also, a + * transfer size of 0 means "maximum" to the chip + * DMA logic. */ - if (sc->sc_phase == MESSAGE_IN_PHASE) - espr->espr_cmd = ESPCMD_TRANS; - else { - ESPD(("PC ")); - /* - * XXX: The phase has been changed on us. - * This should lead us to discard the - * current (incomplete) message, perhaps - * assert an error(?), and go handle whatever - * new phase we are now in. - */ - break; + ESPCMD(sc, + (size==0?ESPCMD_TRPAD:ESPCMD_TRANS)|ESPCMD_DMA); + DMA_GO(sc->sc_dma); + return 1; + case STATUS_PHASE: + ESP_PHASE(("STATUS_PHASE ")); + sc->sc_flags |= ESP_ICCS; + ESPCMD(sc, ESPCMD_ICCS); + sc->sc_prevphase = STATUS_PHASE; + break; + case INVALID_PHASE: + break; + case BUSFREE_PHASE: + if (sc->sc_flags & ESP_BUSFREE_OK) { + /*It's fun the 1st time.. */ + sc->sc_flags &= ~ESP_BUSFREE_OK; } - goto done; - } - if (sc->sc_espintr & ESPINTR_FC) { - /* - * interrupted by ESPCMD_TRANS a few lines above. - */ - esp_msgin(sc); - goto done; + break; + default: + panic("esp: bogus bus phase\n"); } - goto done; - case ESPS_DOINGSTATUS: - if (sc->sc_espintr & ESPINTR_DIS) { - sc->sc_state = ESPS_NEXUS; /* will cleanup */ - goto states; + } + panic("esp: should not get here.."); +} + +void +esp_abort(sc, ecb) + struct esp_softc *sc; + struct ecb *ecb; +{ + if (ecb == sc->sc_nexus) { + if (sc->sc_state == ESP_HASNEXUS) { + sc->sc_flags |= ESP_ABORTING; + esp_sched_msgout(SEND_ABORT); } + } else { + if (sc->sc_state == ESP_IDLE) + esp_sched(sc); + } +} - if (sc->sc_espintr & (ESPINTR_FC|ESPINTR_BS)) { - i = espgetbyte(sc, 0); - if (i == -1) { - printf("%s: ESPS_DOINGSTATUS fifo empty\n", - sc->sc_dev.dv_xname); - /* XXX: how do we cleanup from this error? */ - goto done; - } - if (sc->sc_espstat & ESPSTAT_PE) { - printf("%s: SCSI bus parity error\n", - sc->sc_dev.dv_xname); - /* - * Can't tell what the real status should - * be, so force a later check. - */ - i = SCSI_CHECK; - } - ecb->stat = (u_char)i; - ESPD(("status=%02x ", (u_char)i)); +void +esp_timeout(arg) + void *arg; +{ + int s = splbio(); + struct ecb *ecb = (struct ecb *)arg; + struct esp_softc *sc; + struct scsi_xfer *xs = ecb->xs; - if (sc->sc_espintr & ESPINTR_FC) { - /* - * XXX assumes a single byte message -- - * and what about parity errors and other - * possible botches inside esp_msgin? - */ - esp_msgin(sc); - sc->sc_state = ESPS_NEXUS; - } else - sc->sc_state = ESPS_DOINGMSGIN; - goto done; - } - goto done; - case ESPS_EXPECTDISC: - /* - * We were told to expect a disconnection interrupt. - * When we get it, we can go back to other work. - */ - ESPD(("ED ")); - if (sc->sc_espintr & ESPINTR_DIS) { - espflush(sc); - DELAY(1); - espr->espr_cmd = ESPCMD_ENSEL; /* within 250ms of disconnect */ - sc->sc_state = ESPS_IDLE; - } - goto states; - case ESPS_NEXUS: - ESPD(("NX ")); + sc = xs->sc_link->adapter_softc; + sc_print_addr(xs->sc_link); +again: + printf("%s: timed out [ecb %p (flags 0x%x, dleft %x, stat %x)], " + "<state %d, nexus %p, phase(c %x, p %x), resid %x, msg(q %x,o %x) %s>", + sc->sc_dev.dv_xname, + ecb, ecb->flags, ecb->dleft, ecb->stat, + sc->sc_state, sc->sc_nexus, sc->sc_phase, sc->sc_prevphase, + sc->sc_dleft, sc->sc_msgpriq, sc->sc_msgout, + DMA_ISACTIVE(sc->sc_dma) ? "DMA active" : ""); +#if ESP_DEBUG > 0 + printf("TRACE: %s.", ecb->trace); +#endif - if (sc->sc_espintr & ESPINTR_DIS) { - espflush(sc); - DELAY(1); - espr->espr_cmd = ESPCMD_ENSEL; /* within 250ms of disconnect */ - sc->sc_msgpriq = sc->sc_msgout = 0; - - ESPD(("DD:")); - if (ecb->flags & ECB_DONE) { - ESPD(("D ")); - /* successfully finished a transaction */ - untimeout(esp_timeout, ecb); - esp_done(ecb); - } else if (sc->sc_flags & ESPF_MAYDISCON) { - ESPD(("M ")); - /* legal discon/recon is happening */ - TAILQ_INSERT_HEAD(&sc->nexus_list, - ecb, chain); - sc->sc_nexus = NULL; - sc->sc_state = ESPS_IDLE; - sc->sc_flags &= ~ESPF_MAYDISCON; - goto states; - } else { - ESPD(("U ")); - /* unexpected disconnection! fail. */ - ecb->xs->error = XS_TIMEOUT; - untimeout(esp_timeout, ecb); - esp_done(ecb); + if (ecb->flags & ECB_ABORTED) { + /* abort timed out */ + printf(" AGAIN\n"); + esp_init(sc, 1); + } else { + /* abort the operation that has timed out */ + printf("\n"); + xs->error = XS_TIMEOUT; + ecb->flags |= ECB_ABORTED; + esp_abort(sc, ecb); + /* 2 secs for the abort */ + if ((xs->flags & SCSI_POLL) == 0) + timeout(esp_timeout, ecb, 2 * hz); + else { + int count = 200000; + while (count) { + if (DMA_ISINTR(sc->sc_dma)) { + espintr(sc); + } + if (xs->flags & ITSDONE) + break; + DELAY(10); + --count; } - goto done; + if (count == 0) + goto again; } - break; /* handle the phase */ - default: - printf("%s: unknown state %d\n", - sc->sc_dev.dv_xname, sc->sc_state); - panic("cannot continue"); } - - ecb = sc->sc_nexus; - - switch (sc->sc_phase) { - case MESSAGE_OUT_PHASE: - /* - * ATN was asserted, and the bus changed into MSGOUT phase. - * Send a message. - */ - esp_msgout(sc); /* cause intr */ - sc->sc_state = ESPS_DOINGMSGOUT; - break; - case COMMAND_PHASE: - /* - * Apparently we need to repeat the previous command. - */ - espflush(sc); - DELAY(1); - cmd = (u_char *)&ecb->cmd; - - ESPD(("CMD[")); - for (i = 0; i < ecb->clen; i++) - ESPD(("%02x%c", cmd[i], - (i == ecb->clen-1) ? ']' : ' ')); - ESPD((" ")); - - /* Now the command into the FIFO */ - for (i = 0; i < ecb->clen; i++) - espr->espr_fifo = cmd[i]; - - espr->espr_cmd = ESPCMD_TRANS; /* cause intr */ - sc->sc_state = ESPS_NEXUS; - break; - case DATA_OUT_PHASE: - /* - * We can feed the device the data now. - */ - espflush(sc); - DELAY(1); - dmastart(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft, 0, - ecb->xs->flags & SCSI_POLL); /* cause intr */ - sc->sc_state = ESPS_DOINGDMA; - break; - case DATA_IN_PHASE: - /* - * The device is ready to give us the data. - */ - dmadrain(sc->sc_dma); - dmastart(sc->sc_dma, &sc->sc_dp, &sc->sc_dleft, 1, - ecb->xs->flags & SCSI_POLL); /* cause intr */ - sc->sc_state = ESPS_DOINGDMA; - break; - case MESSAGE_IN_PHASE: - espflush(sc); - DELAY(1); - espr->espr_cmd = ESPCMD_TRANS; /* cause intr */ - sc->sc_state = ESPS_DOINGMSGIN; - break; - case STATUS_PHASE: - espflush(sc); - DELAY(1); - espr->espr_cmd = ESPCMD_ICCS; /* cause intr */ - sc->sc_state = ESPS_DOINGSTATUS; - break; - default: - printf("%s: bogus bus phase %d\n", - sc->sc_dev.dv_xname); - break; - } - -done: - if (sc->sc_dma->sc_rev == DMAREV_1 && dmaintrwas) - dmaenintr(sc->sc_dma); - sc->sc_intrcnt.ev_count++; - return (1); + splx(s); } diff --git a/sys/arch/sparc/dev/espreg.h b/sys/arch/sparc/dev/espreg.h index 31db483c1bc..e08eebcad7c 100644 --- a/sys/arch/sparc/dev/espreg.h +++ b/sys/arch/sparc/dev/espreg.h @@ -1,9 +1,7 @@ -/* $NetBSD: espreg.h,v 1.5 1995/01/07 05:17:15 mycroft Exp $ */ +/* $NetBSD: espreg.h,v 1.7 1995/12/18 23:58:39 pk Exp $ */ /* * Copyright (c) 1994 Peter Galbavy. All rights reserved. - * Copyright (c) 1995 Theo de Raadt. All rights reserved. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -14,8 +12,7 @@ * 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 Peter Galbavy and - * Theo de Raadt + * This product includes software developed by Peter Galbavy. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * @@ -35,137 +32,117 @@ * Register addresses, relative to some base address */ -struct espregs { - volatile u_char espr_tcl; - volatile u_char x01; - volatile u_char x02; - volatile u_char x03; - volatile u_char espr_tcm; - volatile u_char x05; - volatile u_char x06; - volatile u_char x07; - volatile u_char espr_fifo; - volatile u_char x09; - volatile u_char x0a; - volatile u_char x0b; - volatile u_char espr_cmd; - volatile u_char x0d; - volatile u_char x0e; - volatile u_char x0f; - volatile u_char espr_stat; -#define espr_selid espr_stat - volatile u_char x11; - volatile u_char x12; - volatile u_char x13; - volatile u_char espr_intr; -#define espr_timeout espr_intr - volatile u_char x15; - volatile u_char x16; - volatile u_char x17; - volatile u_char espr_step; -#define espr_synctp espr_step - volatile u_char x19; - volatile u_char x1a; - volatile u_char x1b; - volatile u_char espr_fflag; -#define espr_syncoff espr_fflag - volatile u_char x1d; - volatile u_char x1e; - volatile u_char x1f; - volatile u_char espr_cfg1; - volatile u_char x21; - volatile u_char x22; - volatile u_char x23; - volatile u_char espr_ccf; - volatile u_char x25; - volatile u_char x26; - volatile u_char x27; - volatile u_char espr_test; - volatile u_char x29; - volatile u_char x2a; - volatile u_char x2b; - volatile u_char espr_cfg2; - volatile u_char x2d; - volatile u_char x2e; - volatile u_char x2f; - volatile u_char espr_cfg3; /* ESP200 only */ - volatile u_char x31; - volatile u_char x32; - volatile u_char x33; - volatile u_char espr_tch; /* ESP200 only */ -}; - -#define ESPCMD_DMA 0x80 /* DMA Bit */ -#define ESPCMD_NOP 0x00 /* No Operation */ -#define ESPCMD_FLUSH 0x01 /* Flush FIFO */ -#define ESPCMD_RSTCHIP 0x02 /* Reset Chip */ -#define ESPCMD_RSTSCSI 0x03 /* Reset SCSI Bus */ -#define ESPCMD_RESEL 0x40 /* Reselect Sequence */ -#define ESPCMD_SELNATN 0x41 /* Select without ATN */ -#define ESPCMD_SELATN 0x42 /* Select with ATN */ -#define ESPCMD_SELATNS 0x43 /* Select with ATN & Stop */ -#define ESPCMD_ENSEL 0x44 /* Enable (Re)Selection */ -#define ESPCMD_DISSEL 0x45 /* Disable (Re)Selection */ -#define ESPCMD_SELATN3 0x46 /* Select with ATN3 */ -#define ESPCMD_RESEL3 0x47 /* Reselect3 Sequence */ -#define ESPCMD_SNDMSG 0x20 /* Send Message */ -#define ESPCMD_SNDSTAT 0x21 /* Send Status */ -#define ESPCMD_SNDDATA 0x22 /* Send Data */ -#define ESPCMD_DISCSEQ 0x23 /* Disconnect Sequence */ -#define ESPCMD_TERMSEQ 0x24 /* Terminate Sequence */ -#define ESPCMD_TCCS 0x25 /* Target Command Comp Seq */ -#define ESPCMD_DISC 0x27 /* Disconnect */ -#define ESPCMD_RECMSG 0x28 /* Receive Message */ -#define ESPCMD_RECCMD 0x29 /* Receive Command */ -#define ESPCMD_RECDATA 0x2a /* Receive Data */ -#define ESPCMD_RECCSEQ 0x2b /* Receive Command Sequence*/ -#define ESPCMD_ABORT 0x04 /* Target Abort DMA */ -#define ESPCMD_TRANS 0x10 /* Transfer Information */ -#define ESPCMD_ICCS 0x11 /* Initiator Cmd Comp Seq */ -#define ESPCMD_MSGOK 0x12 /* Message Accepted */ -#define ESPCMD_TRPAD 0x18 /* Transfer Pad */ -#define ESPCMD_SETATN 0x1a /* Set ATN */ -#define ESPCMD_RSTATN 0x1b /* Reset ATN */ - -#define ESPSTAT_INT 0x80 /* Interrupt */ -#define ESPSTAT_GE 0x40 /* Gross Error */ -#define ESPSTAT_PE 0x20 /* Parity Error */ -#define ESPSTAT_TC 0x10 /* Terminal Count */ -#define ESPSTAT_VGC 0x08 /* Valid Group Code */ -#define ESPSTAT_PHASE 0x07 /* Phase bits */ - -#define ESPINTR_SBR 0x80 /* SCSI Bus Reset */ -#define ESPINTR_ILL 0x40 /* Illegal Command */ -#define ESPINTR_DIS 0x20 /* Disconnect */ -#define ESPINTR_BS 0x10 /* Bus Service */ -#define ESPINTR_FC 0x08 /* Function Complete */ -#define ESPINTR_RESEL 0x04 /* Reselected */ -#define ESPINTR_SELATN 0x02 /* Select with ATN */ -#define ESPINTR_SEL 0x01 /* Selected */ - -#define ESPSTEP_MASK 0x07 /* the last 3 bits */ -#define ESPSTEP_DONE 0x04 /* command went out */ - -#define ESPFIFO_SS 0xe0 /* Sequence Step (Dup) */ -#define ESPFIFO_FF 0x1f /* Bytes in FIFO */ - -#define ESPCFG1_SLOW 0x80 /* Slow Cable Mode */ -#define ESPCFG1_SRR 0x40 /* SCSI Reset Rep Int Dis */ -#define ESPCFG1_PTEST 0x20 /* Parity Test Mod */ -#define ESPCFG1_PARENB 0x10 /* Enable Parity Check */ -#define ESPCFG1_CTEST 0x08 /* Enable Chip Test */ -#define ESPCFG1_BUSID 0x07 /* Bus ID */ - -#define ESPCFG2_RSVD 0xe0 /* reserved */ -#define ESPCFG2_FE 0x40 /* Features Enable */ -#define ESPCFG2_DREQ 0x10 /* DREQ High Impedance */ -#define ESPCFG2_SCSI2 0x08 /* SCSI-2 Enable */ -#define ESPCFG2_BPA 0x04 /* Target Bad Parity Abort */ -#define ESPCFG2_RPE 0x02 /* Register Parity Error */ -#define ESPCFG2_DPE 0x01 /* DMA Parity Error */ - -#define ESPCFG3_IDM 0x10 /* ID Message Res Check */ -#define ESPCFG3_QTE 0x08 /* Queue Tag Enable */ -#define ESPCFG3_CDB 0x04 /* CDB 10-bytes OK */ -#define ESPCFG3_FSCSI 0x02 /* Fast SCSI */ -#define ESPCFG3_FCLK 0x01 /* Fast Clock (>25Mhz) */ +#define ESP_TCL 0x00 /* RW - Transfer Count Low */ +#define ESP_TCM 0x01 /* RW - Transfer Count Mid */ +#define ESP_TCH 0x0e /* RW - Transfer Count High */ + /* NOT on 53C90 */ + +#define ESP_FIFO 0x02 /* RW - FIFO data */ + +#define ESP_CMD 0x03 /* RW - Command (2 deep) */ +#define ESPCMD_DMA 0x80 /* DMA Bit */ +#define ESPCMD_NOP 0x00 /* No Operation */ +#define ESPCMD_FLUSH 0x01 /* Flush FIFO */ +#define ESPCMD_RSTCHIP 0x02 /* Reset Chip */ +#define ESPCMD_RSTSCSI 0x03 /* Reset SCSI Bus */ +#define ESPCMD_RESEL 0x40 /* Reselect Sequence */ +#define ESPCMD_SELNATN 0x41 /* Select without ATN */ +#define ESPCMD_SELATN 0x42 /* Select with ATN */ +#define ESPCMD_SELATNS 0x43 /* Select with ATN & Stop */ +#define ESPCMD_ENSEL 0x44 /* Enable (Re)Selection */ +#define ESPCMD_DISSEL 0x45 /* Disable (Re)Selection */ +#define ESPCMD_SELATN3 0x46 /* Select with ATN3 */ +#define ESPCMD_RESEL3 0x47 /* Reselect3 Sequence */ +#define ESPCMD_SNDMSG 0x20 /* Send Message */ +#define ESPCMD_SNDSTAT 0x21 /* Send Status */ +#define ESPCMD_SNDDATA 0x22 /* Send Data */ +#define ESPCMD_DISCSEQ 0x23 /* Disconnect Sequence */ +#define ESPCMD_TERMSEQ 0x24 /* Terminate Sequence */ +#define ESPCMD_TCCS 0x25 /* Target Command Comp Seq */ +#define ESPCMD_DISC 0x27 /* Disconnect */ +#define ESPCMD_RECMSG 0x28 /* Receive Message */ +#define ESPCMD_RECCMD 0x29 /* Receive Command */ +#define ESPCMD_RECDATA 0x2a /* Receive Data */ +#define ESPCMD_RECCSEQ 0x2b /* Receive Command Sequence*/ +#define ESPCMD_ABORT 0x04 /* Target Abort DMA */ +#define ESPCMD_TRANS 0x10 /* Transfer Information */ +#define ESPCMD_ICCS 0x11 /* Initiator Cmd Comp Seq */ +#define ESPCMD_MSGOK 0x12 /* Message Accepted */ +#define ESPCMD_TRPAD 0x18 /* Transfer Pad */ +#define ESPCMD_SETATN 0x1a /* Set ATN */ +#define ESPCMD_RSTATN 0x1b /* Reset ATN */ + +#define ESP_STAT 0x04 /* RO - Status */ +#define ESPSTAT_INT 0x80 /* Interrupt */ +#define ESPSTAT_GE 0x40 /* Gross Error */ +#define ESPSTAT_PE 0x20 /* Parity Error */ +#define ESPSTAT_TC 0x10 /* Terminal Count */ +#define ESPSTAT_VGC 0x08 /* Valid Group Code */ +#define ESPSTAT_PHASE 0x07 /* Phase bits */ + +#define ESP_SELID 0x04 /* WO - Select/Reselect Bus ID */ + +#define ESP_INTR 0x05 /* RO - Interrupt */ +#define ESPINTR_SBR 0x80 /* SCSI Bus Reset */ +#define ESPINTR_ILL 0x40 /* Illegal Command */ +#define ESPINTR_DIS 0x20 /* Disconnect */ +#define ESPINTR_BS 0x10 /* Bus Service */ +#define ESPINTR_FC 0x08 /* Function Complete */ +#define ESPINTR_RESEL 0x04 /* Reselected */ +#define ESPINTR_SELATN 0x02 /* Select with ATN */ +#define ESPINTR_SEL 0x01 /* Selected */ + +#define ESP_TIMEOUT 0x05 /* WO - Select/Reselect Timeout */ + +#define ESP_STEP 0x06 /* RO - Sequence Step */ +#define ESPSTEP_MASK 0x07 /* the last 3 bits */ +#define ESPSTEP_DONE 0x04 /* command went out */ + +#define ESP_SYNCTP 0x06 /* WO - Synch Transfer Period */ + /* Default 5 (53C9X) */ + +#define ESP_FFLAG 0x07 /* RO - FIFO Flags */ +#define ESPFIFO_SS 0xe0 /* Sequence Step (Dup) */ +#define ESPFIFO_FF 0x1f /* Bytes in FIFO */ + +#define ESP_SYNCOFF 0x07 /* WO - Synch Offset */ + /* 0 = ASYNC */ + /* 1 - 15 = SYNC bytes */ + +#define ESP_CFG1 0x08 /* RW - Configuration #1 */ +#define ESPCFG1_SLOW 0x80 /* Slow Cable Mode */ +#define ESPCFG1_SRR 0x40 /* SCSI Reset Rep Int Dis */ +#define ESPCFG1_PTEST 0x20 /* Parity Test Mod */ +#define ESPCFG1_PARENB 0x10 /* Enable Parity Check */ +#define ESPCFG1_CTEST 0x08 /* Enable Chip Test */ +#define ESPCFG1_BUSID 0x07 /* Bus ID */ + +#define ESP_CCF 0x09 /* WO - Clock Conversion Factor */ + /* 0 = 35.01 - 40Mhz */ + /* NEVER SET TO 1 */ + /* 2 = 10Mhz */ + /* 3 = 10.01 - 15Mhz */ + /* 4 = 15.01 - 20Mhz */ + /* 5 = 20.01 - 25Mhz */ + /* 6 = 25.01 - 30Mhz */ + /* 7 = 30.01 - 35Mhz */ + +#define ESP_TEST 0x0a /* WO - Test (Chip Test Only) */ + +#define ESP_CFG2 0x0b /* RW - Configuration #2 */ +#define ESPCFG2_RSVD 0xa0 /* reserved */ +#define ESPCFG2_FE 0x40 /* Features Enable */ +#define ESPCFG2_DREQ 0x10 /* DREQ High Impedance */ +#define ESPCFG2_SCSI2 0x08 /* SCSI-2 Enable */ +#define ESPCFG2_BPA 0x04 /* Target Bad Parity Abort */ +#define ESPCFG2_RPE 0x02 /* Register Parity Error */ +#define ESPCFG2_DPE 0x01 /* DMA Parity Error */ + +/* Config #3 only on 53C9X */ +#define ESP_CFG3 0x0c /* RW - Configuration #3 */ +#define ESPCFG3_RSVD 0xe0 /* reserved */ +#define ESPCFG3_IDM 0x10 /* ID Message Res Check */ +#define ESPCFG3_QTE 0x08 /* Queue Tag Enable */ +#define ESPCFG3_CDB 0x04 /* CDB 10-bytes OK */ +#define ESPCFG3_FSCSI 0x02 /* Fast SCSI */ +#define ESPCFG3_FCLK 0x01 /* Fast Clock (>25Mhz) */ diff --git a/sys/arch/sparc/dev/espvar.h b/sys/arch/sparc/dev/espvar.h index c8592af5b29..8b0b414a08a 100644 --- a/sys/arch/sparc/dev/espvar.h +++ b/sys/arch/sparc/dev/espvar.h @@ -1,37 +1,7 @@ -/* $NetBSD: espvar.h,v 1.3 1994/11/20 20:52:12 deraadt Exp $ */ +/* $NetBSD: espvar.h,v 1.13 1996/05/16 20:31:30 pk Exp $ */ /* - * Copyright (c) 1995 Theo de Raadt - * - * 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 under OpenBSD by - * Theo de Raadt. - * 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. - * * Copyright (c) 1994 Peter Galbavy. All rights reserved. - * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -58,82 +28,103 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* esp chip revisions */ -#define ESP100 0 -#define ESP100A 1 -#define ESP200 2 - -/* Grabbed from Julians SCSI aha-drivers */ -#ifdef DDB -int Debugger(); -#else DDB -#define Debugger() panic("should call debugger here (esp.c)") -#endif DDB - -#define ESP_MSGLEN_MAX 8 /* maximum msglen we handle */ -#define ESP_SYNC_REQOFF 0 /* offset we request */ -#define ESP_SYNC_MAXOFF 15 /* maximum supportable sync offset */ -#if ESP_SYNC_REQOFF > ESP_SYNC_MAXOFF -#warning requested sync offset is higher than maximum possible sync offset. -#endif +#define ESP_DEBUG 0 #define FREQTOCCF(freq) (((freq + 4) / 5)) -/* - * ECB. Holds additional information for each SCSI command - * Comments: We need a separate scsi command block because we may need - * to overwrite it with a request sense command. Basically, we refrain - * from fiddling with the scsi_xfer struct (except do the expected - * updating of return values). We'll generally update: - * xs->{flags,resid,error,sense,status} and occasionally xs->retries. +/* esp revisions */ +#define ESP100 0x01 +#define ESP100A 0x02 +#define ESP200 0x03 + +#if 0 +typedef caddr_t physaddr; + +struct esp_dma_seg { + physaddr addr; + long len; +}; +#endif + +/* + * ECB. Holds additional information for each SCSI command Comments: We + * need a separate scsi command block because we may need to overwrite it + * with a request sense command. Basicly, we refrain from fiddling with + * the scsi_xfer struct (except do the expected updating of return values). + * We'll generally update: xs->{flags,resid,error,sense,status} and + * occasionally xs->retries. */ struct ecb { TAILQ_ENTRY(ecb) chain; - struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */ - int flags; /* Status */ -#define ECB_FREE 0x00 -#define ECB_ACTIVE 0x01 -#define ECB_DONE 0x04 + struct scsi_xfer *xs; /* SCSI xfer ctrl block from above */ + int flags; /* Status */ +#define ECB_QNONE 0 +#define ECB_QFREE 1 +#define ECB_QREADY 2 +#define ECB_QNEXUS 3 +#define ECB_QBITS 0x07 #define ECB_CHKSENSE 0x08 - struct scsi_generic cmd; /* SCSI command block */ - int clen; - caddr_t daddr; /* Saved data pointer */ - int dleft; /* Residue */ - int stat; /* SCSI status byte */ +#define ECB_ABORTED 0x10 +#define ECB_SETQ(e, q) do (e)->flags = ((e)->flags&~ECB_QBITS)|(q); while(0) + struct scsi_generic cmd; /* SCSI command block */ + int clen; + char *daddr; /* Saved data pointer */ + int dleft; /* Residue */ + u_char stat; /* SCSI status byte */ +#if ESP_DEBUG > 0 + char trace[1000]; +#endif }; +#if ESP_DEBUG > 0 +#define ECB_TRACE(ecb, msg, a, b) do { \ + const char *f = "[" msg "]"; \ + int n = strlen((ecb)->trace); \ + if (n < (sizeof((ecb)->trace)-100)) \ + sprintf((ecb)->trace + n, f, a, b); \ +} while(0) +#else +#define ECB_TRACE(ecb, msg, a, b) +#endif -/* - * Some info about each (possible) target on the SCSI bus. This should - * probably have been a "per target+lunit" structure, but we'll leave it at +/* + * Some info about each (possible) target on the SCSI bus. This should + * probably have been a "per target+lunit" structure, but we'll leave it at * this for now. Is there a way to reliably hook it up to sc->fordriver?? */ struct esp_tinfo { - int cmds; /* #commands processed */ - int dconns; /* #disconnects */ - int touts; /* #timeouts */ - int perrs; /* #parity errors */ - int senses; /* #request sense commands sent */ - u_char lubusy; /* What luns are busy? */ - u_char flags; -#define DO_NEGOTIATE 0x01 /* (re)negotiate synchronous options */ -#define TARGET_BUSY 0x02 /* target is busy, i.e. cmd in progress */ - u_char period; /* sync period */ - u_char synctp; /* sync period translated for SYNCTP */ - u_char offset; /* sync offset */ -}; + int cmds; /* #commands processed */ + int dconns; /* #disconnects */ + int touts; /* #timeouts */ + int perrs; /* #parity errors */ + int senses; /* #request sense commands sent */ + ushort lubusy; /* What local units/subr. are busy? */ + u_char flags; +#define T_NEED_TO_RESET 0x01 /* Should send a BUS_DEV_RESET */ +#define T_NEGOTIATE 0x02 /* (Re)Negotiate synchronous options */ +#define T_BUSY 0x04 /* Target is busy, i.e. cmd in progress */ +#define T_SYNCMODE 0x08 /* sync mode has been negotiated */ +#define T_SYNCHOFF 0x10 /* .. */ +#define T_RSELECTOFF 0x20 /* .. */ + u_char period; /* Period suggestion */ + u_char offset; /* Offset suggestion */ +} tinfo_t; /* Register a linenumber (for debugging) */ #define LOGLINE(p) -#define ESP_SHOWECBS 0x01 -#define ESP_SHOWINTS 0x02 -#define ESP_SHOWCMDS 0x04 -#define ESP_SHOWMISC 0x08 -#define ESP_SHOWTRAC 0x10 -#define ESP_SHOWSTART 0x20 -#define ESP_SHOWPHASE 0x40 +#define ESP_SHOWECBS 0x01 +#define ESP_SHOWINTS 0x02 +#define ESP_SHOWCMDS 0x04 +#define ESP_SHOWMISC 0x08 +#define ESP_SHOWTRAC 0x10 +#define ESP_SHOWSTART 0x20 +#define ESP_SHOWPHASE 0x40 +#define ESP_SHOWDMA 0x80 +#define ESP_SHOWCCMDS 0x100 +#define ESP_SHOWMSGS 0x200 -#if ESP_DEBUG +#ifdef ESP_DEBUG +extern int esp_debug; #define ESP_ECBS(str) do {if (esp_debug & ESP_SHOWECBS) printf str;} while (0) #define ESP_MISC(str) do {if (esp_debug & ESP_SHOWMISC) printf str;} while (0) #define ESP_INTS(str) do {if (esp_debug & ESP_SHOWINTS) printf str;} while (0) @@ -141,6 +132,8 @@ struct esp_tinfo { #define ESP_CMDS(str) do {if (esp_debug & ESP_SHOWCMDS) printf str;} while (0) #define ESP_START(str) do {if (esp_debug & ESP_SHOWSTART) printf str;}while (0) #define ESP_PHASE(str) do {if (esp_debug & ESP_SHOWPHASE) printf str;}while (0) +#define ESP_DMA(str) do {if (esp_debug & ESP_SHOWDMA) printf str;}while (0) +#define ESP_MSGS(str) do {if (esp_debug & ESP_SHOWMSGS) printf str;}while (0) #else #define ESP_ECBS(str) #define ESP_MISC(str) @@ -149,85 +142,104 @@ struct esp_tinfo { #define ESP_CMDS(str) #define ESP_START(str) #define ESP_PHASE(str) +#define ESP_DMA(str) #endif +#define ESP_MAX_MSG_LEN 8 + struct esp_softc { - struct device sc_dev; - struct sbusdev sc_sd; /* sbus device */ - struct intrhand sc_ih; /* intr handler */ - struct evcnt sc_intrcnt; /* intr count */ - struct scsi_link sc_link; /* scsi lint struct */ - struct espregs *sc_regs; /* the registers */ - struct dma_softc *sc_dma; /* corresponding DMA ctrlr */ + struct device sc_dev; /* us as a device */ + struct sbusdev sc_sd; /* sbus device */ + struct intrhand sc_ih; /* intr handler */ + struct evcnt sc_intrcnt; /* intr count */ + struct scsi_link sc_link; /* scsi lint struct */ + volatile u_char *sc_reg; /* the registers */ + struct dma_softc *sc_dma; /* pointer to my dma */ /* register defaults */ - u_char sc_cfg1; /* config 1 */ - u_char sc_cfg2; /* config 2, only ESP100A/200 */ - u_char sc_cfg3; /* config 3, only ESP200 */ - u_char sc_ccf; /* clock conversion */ + u_char sc_cfg1; /* Config 1 */ + u_char sc_cfg2; /* Config 2, not ESP100 */ + u_char sc_cfg3; /* Config 3, only ESP200 */ + u_char sc_ccf; /* Clock Conversion */ u_char sc_timeout; - u_char sc_espintr; /* copies of registers */ + /* register copies, see espreadregs() */ + u_char sc_espintr; u_char sc_espstat; u_char sc_espstep; u_char sc_espfflags; - struct bootpath *sc_bp; /* current boot path component */ - /* Lists of command blocks */ - TAILQ_HEAD(ecb_list, ecb) free_list, ready_list, nexus_list; + TAILQ_HEAD(ecb_list, ecb) free_list, + ready_list, + nexus_list; - struct ecb *sc_nexus; /* current command */ - struct ecb sc_ecb[8]; /* one per target */ - struct esp_tinfo sc_tinfo[8]; + struct ecb *sc_nexus; /* current command */ + struct ecb sc_ecb[8]; /* one per target */ + struct esp_tinfo sc_tinfo[8]; - /* data about the current nexus (updated for every cmd switch) */ - caddr_t sc_dp; /* current data pointer */ - size_t sc_dleft; /* data left to transfer */ + /* Data about the current nexus (updated for every cmd switch) */ + caddr_t sc_dp; /* Current data pointer */ + ssize_t sc_dleft; /* Data left to transfer */ - /* adapter state */ - int sc_phase; /* bus phase (based on sc_espstat) */ - u_char sc_state; /* state applicable to the adapter */ + /* Adapter state */ + int sc_phase; /* Copy of what bus phase we are in */ + int sc_prevphase; /* Copy of what bus phase we were in */ + u_char sc_state; /* State applicable to the adapter */ u_char sc_flags; u_char sc_selid; + u_char sc_lastcmd; - /* message stuff */ - u_char sc_msgpriq; /* messages to send (see SEND_* below) */ - u_char sc_msgout; /* message that is on it's way out */ - u_char sc_omess[ESP_MSGLEN_MAX]; - u_char *sc_omp; /* message pointer (for multibyte messages) */ + /* Message stuff */ + u_char sc_msgpriq; /* One or more messages to send (encoded) */ + u_char sc_msgout; /* What message is on its way out? */ + u_char sc_omess[ESP_MAX_MSG_LEN]; + caddr_t sc_omp; /* Message pointer (for multibyte messages) */ size_t sc_omlen; - u_char sc_imess[ESP_MSGLEN_MAX + 1]; - u_char *sc_imp; /* message pointer (for multibyte messages) */ + u_char sc_imess[ESP_MAX_MSG_LEN + 1]; + caddr_t sc_imp; /* Message pointer (for multibyte messages) */ size_t sc_imlen; /* hardware/openprom stuff */ - int sc_node; /* PROM node ID */ - int sc_freq; /* Freq in HZ */ - int sc_pri; /* SBUS priority */ - int sc_id; /* our scsi id */ - int sc_rev; /* esp revision */ - int sc_minsync; /* minimum sync period / 4 */ + int sc_node; /* PROM node ID */ + int sc_freq; /* Freq in HZ */ + int sc_pri; /* SBUS priority */ + int sc_id; /* our scsi id */ + int sc_rev; /* esp revision */ + int sc_minsync; /* minimum sync period / 4 */ + int sc_maxxfer; /* maximum transfer size */ }; +/* + * Macros to read and write the chip's registers. + */ +#define ESP_READ_REG(sc, reg) \ + ((sc)->sc_reg[(reg) * 4]) +#define ESP_WRITE_REG(sc, reg, val) \ + do { \ + u_char v = (val); \ + (sc)->sc_reg[(reg) * 4] = v; \ + } while (0) + /* values for sc_state */ -#define ESPS_IDLE 0x01 /* waiting for something to do */ -#define ESPS_EXPECTDISC 0x02 /* a disconnect is going to happen */ -#define ESPS_SELECTING 0x03 /* SCSI command is arbiting */ -#define ESPS_RESELECTED 0x04 /* has been reselected */ -#define ESPS_NEXUS 0x05 /* actively using the SCSI bus */ -#define ESPS_DOINGDMA 0x06 /* doing a DMA transaction */ -#define ESPS_DOINGMSGOUT 0x07 /* message-out in progress */ -#define ESPS_DOINGMSGIN 0x08 /* message-in in progress */ -#define ESPS_DOINGSTATUS 0x09 /* status-in in progress */ -#define ESPS_SELECTSTOP 0x0a /* sent first byte of message.. */ -#define ESPS_MULTMSGEND 0x0b /* done sending multibyte msg */ +#define ESP_IDLE 0x01 /* waiting for something to do */ +#define ESP_TMP_UNAVAIL 0x02 /* Don't accept SCSI commands */ +#define ESP_SELECTING 0x03 /* SCSI command is arbiting */ +#define ESP_RESELECTED 0x04 /* Has been reselected */ +#define ESP_HASNEXUS 0x05 /* Actively using the SCSI bus */ +#define ESP_CLEANING 0x06 +#define ESP_SBR 0x07 /* Expect a SCSI RST because we commanded it */ /* values for sc_flags */ -#define ESPF_DROP_MSGI 0x01 /* Discard all msgs (parity err detected) */ -#define ESPF_MAYDISCON 0x02 /* disconnection allowed */ -#define ESPF_DONE 0x04 /* finished transaction */ -#define ESPF_SYNCHNEGO 0x08 /* Synch negotiation in progress. */ +#define ESP_DROP_MSGI 0x01 /* Discard all msgs (parity err detected) */ +#define ESP_DOINGDMA 0x02 /* The FIFO data path is active! */ +#define ESP_BUSFREE_OK 0x04 /* Bus free phase is OK. */ +#define ESP_SYNCHNEGO 0x08 /* Synch negotiation in progress. */ +/*#define ESP_BLOCKED 0x10 * Don't schedule new scsi bus operations */ +#define ESP_DISCON 0x10 /* Target sent DISCONNECT msg */ +#define ESP_ABORTING 0x20 /* Bailing out */ +#define ESP_ICCS 0x40 /* Expect status phase results */ +#define ESP_WAITI 0x80 /* Waiting for non-DMA data to arrive */ /* values for sc_msgout */ #define SEND_DEV_RESET 0x01 @@ -238,14 +250,25 @@ struct esp_softc { #define SEND_IDENTIFY 0x20 #define SEND_SDTR 0x40 -#define ST_MASK 0x3e /* bits 0, 6, and 7 are reserved */ +/* SCSI Status codes */ +#define ST_GOOD 0x00 +#define ST_CHKCOND 0x02 +#define ST_CONDMET 0x04 +#define ST_BUSY 0x08 +#define ST_INTERMED 0x10 +#define ST_INTERMED_CONDMET 0x14 +#define ST_RESERVATION_CONFLICT 0x18 +#define ST_CMD_TERM 0x22 +#define ST_QUEUE_FULL 0x28 -/* physical phase bits */ +#define ST_MASK 0x3e /* bit 0,6,7 is reserved */ + +/* phase bits */ #define IOI 0x01 #define CDI 0x02 #define MSGI 0x04 -/* values for sc_phase (where information transfer happens) */ +/* Information transfer phases */ #define DATA_OUT_PHASE (0) #define DATA_IN_PHASE (IOI) #define COMMAND_PHASE (CDI) @@ -255,5 +278,23 @@ struct esp_softc { #define PHASE_MASK (MSGI|CDI|IOI) -#define TARGETNAME(ecb) \ - ((struct device *)(ecb)->xs->sc_link->adapter_softc)->dv_xname +/* Some pseudo phases for getphase()*/ +#define BUSFREE_PHASE 0x100 /* Re/Selection no longer valid */ +#define INVALID_PHASE 0x101 /* Re/Selection valid, but no REQ yet */ +#define PSEUDO_PHASE 0x100 /* "pseudo" bit */ + +#ifdef ESP_DEBUG +#define ESPCMD(sc, cmd) do { \ + if (esp_debug & ESP_SHOWCCMDS) \ + printf("<cmd:0x%x>", (unsigned)cmd); \ + sc->sc_lastcmd = cmd; \ + ESP_WRITE_REG(sc, ESP_CMD, cmd); \ +} while (0) +#else +#define ESPCMD(sc, cmd) ESP_WRITE_REG(sc, ESP_CMD, cmd) +#endif + +#define SAME_ESP(sc, bp, ca) \ + ((bp->val[0] == ca->ca_slot && bp->val[1] == ca->ca_offset) || \ + (bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit)) + diff --git a/sys/arch/sparc/dev/fb.c b/sys/arch/sparc/dev/fb.c index ade9db9dbe6..836bc7dbdad 100644 --- a/sys/arch/sparc/dev/fb.c +++ b/sys/arch/sparc/dev/fb.c @@ -1,4 +1,4 @@ -/* $NetBSD: fb.c,v 1.11 1995/10/08 01:39:19 pk Exp $ */ +/* $NetBSD: fb.c,v 1.18 1996/04/01 17:29:54 christos Exp $ */ /* * Copyright (c) 1992, 1993 @@ -50,19 +50,24 @@ */ #include <sys/param.h> -#include <sys/conf.h> +#include <sys/systm.h> #include <sys/device.h> #include <sys/proc.h> +#include <sys/conf.h> #include <machine/autoconf.h> #include <machine/fbio.h> +#include <machine/kbd.h> #include <machine/fbvar.h> +#include <machine/conf.h> #if defined(SUN4) #include <machine/eeprom.h> +#include <sparc/dev/pfourreg.h> #endif static struct fbdevice *devfb; + void fb_unblank() { @@ -72,13 +77,71 @@ fb_unblank() } void -fb_attach(fb) +fb_attach(fb, isconsole) struct fbdevice *fb; + int isconsole; { + static int no_replace, seen_force; + + /* + * We've already had a framebuffer forced into /dev/fb. Don't + * allow any more, even if this is the console. + */ + if (seen_force) { + if (devfb) { /* sanity */ + printf("%s: /dev/fb already full\n", + fb->fb_device->dv_xname); + return; + } else + seen_force = 0; + } + + /* + * Check to see if we're being forced into /dev/fb. + */ + if (fb->fb_flags & FB_FORCE) { + if (devfb) + printf("%s: forcefully replacing %s\n", + fb->fb_device->dv_xname, + devfb->fb_device->dv_xname); + devfb = fb; + seen_force = no_replace = 1; + goto attached; + } + + /* + * Check to see if we're the console. If we are, then replace + * any currently existing framebuffer. + */ + if (isconsole) { + if (devfb) + printf("%s: replacing %s\n", fb->fb_device->dv_xname, + devfb->fb_device->dv_xname); + devfb = fb; + no_replace = 1; + goto attached; + } + + /* + * For the final case, we check to see if we can replace an + * existing framebuffer, if not, say so and return. + */ + if (no_replace) { + if (devfb) { /* sanity */ + printf("%s: /dev/fb already full\n", + fb->fb_device->dv_xname); + return; + } else + no_replace = 0; + } if (devfb) - printf("warning: multiple /dev/fb declarers\n"); + printf("%s: replacing %s\n", fb->fb_device->dv_xname, + devfb->fb_device->dv_xname); devfb = fb; + + attached: + printf("%s: attached to /dev/fb\n", devfb->fb_device->dv_xname); } int @@ -138,25 +201,18 @@ fb_setsize(fb, depth, def_width, def_height, node, bustype) * to be correct as defaults go... */ switch (bustype) { - case BUS_PFOUR: - fb->fb_type.fb_width = def_width; - fb->fb_type.fb_height = def_height; - fb->fb_linebytes = (fb->fb_type.fb_width * depth) / 8; - break; case BUS_VME16: case BUS_VME32: case BUS_OBIO: -#if defined(SUN4M) - if (cputyp == CPU_SUN4M) { /* 4m has framebuffer on obio */ - fb->fb_type.fb_width = getpropint(node, "width", - def_width); + if (CPU_ISSUN4M) { /* 4m has framebuffer on obio */ + fb->fb_type.fb_width = getpropint(node, "width", + def_width); fb->fb_type.fb_height = getpropint(node, "height", - def_height); + def_height); fb->fb_linebytes = getpropint(node, "linebytes", (fb->fb_type.fb_width * depth) / 8); break; } -#endif /* Set up some defaults. */ fb->fb_type.fb_width = def_width; fb->fb_type.fb_height = def_height; @@ -165,39 +221,104 @@ fb_setsize(fb, depth, def_width, def_height, node, bustype) * This is not particularly useful on Sun 4 VME framebuffers. * The EEPROM only contains info about the built-in. */ - if (cputyp == CPU_SUN4 && (bustype == BUS_VME16 || + if (CPU_ISSUN4 && (bustype == BUS_VME16 || bustype == BUS_VME32)) goto donesize; #if defined(SUN4) - if (cputyp==CPU_SUN4) { + if (CPU_ISSUN4) { struct eeprom *eep = (struct eeprom *)eeprom_va; - if (eep != NULL) { - switch (eep->ee_diag.eed_scrsize) { - case EED_SCR_1152X900: + + if (fb->fb_flags & FB_PFOUR) { + volatile u_int32_t pfour; + + /* + * Some pfour framebuffers, e.g. the + * cgsix, don't encode resolution the + * same, so the driver handles that. + * The driver can let us know that it + * needs to do this by not mapping in + * the pfour register by the time this + * routine is called. + */ + if (fb->fb_pfour == NULL) + goto donesize; + + pfour = *fb->fb_pfour; + + /* + * Use the pfour register to determine + * the size. Note that the cgsix and + * cgeight don't use this size encoding. + * In this case, we have to settle + * for the defaults we were provided + * with. + */ + if ((PFOUR_ID(pfour) == PFOUR_ID_COLOR24) || + (PFOUR_ID(pfour) == PFOUR_ID_FASTCOLOR)) + goto donesize; + + switch (PFOUR_SIZE(pfour)) { + case PFOUR_SIZE_1152X900: fb->fb_type.fb_width = 1152; fb->fb_type.fb_height = 900; break; - case EED_SCR_1024X1024: + + case PFOUR_SIZE_1024X1024: fb->fb_type.fb_width = 1024; fb->fb_type.fb_height = 1024; break; - case EED_SCR_1600X1280: + + case PFOUR_SIZE_1280X1024: + fb->fb_type.fb_width = 1280; + fb->fb_type.fb_height = 1024; + break; + + case PFOUR_SIZE_1600X1280: fb->fb_type.fb_width = 1600; fb->fb_type.fb_height = 1280; break; - case EED_SCR_1440X1440: + + case PFOUR_SIZE_1440X1440: fb->fb_type.fb_width = 1440; fb->fb_type.fb_height = 1440; break; - case EED_SCR_640X480: + + case PFOUR_SIZE_640X480: fb->fb_type.fb_width = 640; fb->fb_type.fb_height = 480; break; - case EED_SCR_1280X1024: - fb->fb_type.fb_width = 1280; + + default: + /* + * XXX: Do nothing, I guess. + * Should we print a warning about + * an unknown value? --thorpej + */ + break; + } + } else if (eep != NULL) { + switch (eep->eeScreenSize) { + case EE_SCR_1152X900: + fb->fb_type.fb_width = 1152; + fb->fb_type.fb_height = 900; + break; + + case EE_SCR_1024X1024: + fb->fb_type.fb_width = 1024; fb->fb_type.fb_height = 1024; break; + + case EE_SCR_1600X1280: + fb->fb_type.fb_width = 1600; + fb->fb_type.fb_height = 1280; + break; + + case EE_SCR_1440X1440: + fb->fb_type.fb_width = 1440; + fb->fb_type.fb_height = 1440; + break; + default: /* * XXX: Do nothing, I guess. @@ -210,20 +331,22 @@ fb_setsize(fb, depth, def_width, def_height, node, bustype) } #endif /* SUN4 */ #if defined(SUN4M) - if (cputyp==CPU_SUN4M) { + if (CPU_ISSUN4M) { /* XXX: need code to find 4/600 vme screen size */ } #endif /* SUN4M */ -donesize: + donesize: fb->fb_linebytes = (fb->fb_type.fb_width * depth) / 8; break; + case BUS_SBUS: - fb->fb_type.fb_width = getpropint(node, "width", 1152); - fb->fb_type.fb_height = getpropint(node, "height", 900); + fb->fb_type.fb_width = getpropint(node, "width", def_width); + fb->fb_type.fb_height = getpropint(node, "height", def_height); fb->fb_linebytes = getpropint(node, "linebytes", (fb->fb_type.fb_width * depth) / 8); break; + default: panic("fb_setsize: inappropriate bustype"); /* NOTREACHED */ @@ -233,7 +356,8 @@ donesize: #ifdef RASTERCONSOLE #include <machine/kbd.h> -extern int (*v_putc) __P((int)); +static int a2int __P((char *, int)); +static void fb_bell __P((int)); static int a2int(cp, deflt) @@ -278,40 +402,103 @@ fbrcons_init(fb) #if defined(RASTERCONS_FULLSCREEN) || defined(RASTERCONS_SMALLFONT) rc->rc_maxcol = rc->rc_width / rc->rc_font->width; - rc->rc_maxrow = rc->rc_height / rc->rc_font->height; + rc->rc_maxrow = rc->rc_height / rc->rc_font->height; #else #if defined(SUN4) - if (cputyp == CPU_SUN4) { + if (CPU_ISSUN4) { struct eeprom *eep = (struct eeprom *)eeprom_va; if (eep == NULL) { rc->rc_maxcol = 80; rc->rc_maxrow = 34; } else { - rc->rc_maxcol = eep->ee_diag.eed_colsize; - rc->rc_maxrow = eep->ee_diag.eed_rowsize; + rc->rc_maxcol = eep->eeTtyCols; + rc->rc_maxrow = eep->eeTtyRows; } } #endif /* SUN4 */ -#if defined(SUN4C) || defined(SUN4M) - if (cputyp != CPU_SUN4) { - rc->rc_maxcol = a2int(getpropstring(optionsnode, - "screen-#columns"), 80); - rc->rc_maxrow = a2int(getpropstring(optionsnode, - "screen-#rows"), 34); + + if (!CPU_ISSUN4) { + rc->rc_maxcol = + a2int(getpropstring(optionsnode, "screen-#columns"), 80); + rc->rc_maxrow = + a2int(getpropstring(optionsnode, "screen-#rows"), 34); } -#endif /* SUN4C || SUN4M */ #endif /* RASTERCONS_FULLSCREEN || RASTERCONS_SMALLFONT */ #if !(defined(RASTERCONS_FULLSCREEN) || defined(RASTERCONS_SMALLFONT)) /* Determine addresses of prom emulator row and column */ - if (cputyp == CPU_SUN4 || romgetcursoraddr(&rc->rc_row, &rc->rc_col)) + if (CPU_ISSUN4 || + romgetcursoraddr(&rc->rc_row, &rc->rc_col)) #endif rc->rc_row = rc->rc_col = NULL; rc->rc_bell = fb_bell; rcons_init(rc); /* Hook up virtual console */ - v_putc = (int (*) __P((int)))rcons_cnputc; + v_putc = rcons_cnputc; } #endif + +#if defined(SUN4) +/* + * Support routines for pfour framebuffers. + */ + +/* + * Probe for a pfour framebuffer. Return values: + * + * PFOUR_NOTPFOUR framebuffer is not a pfour + * framebuffer + * + * otherwise returns pfour ID + */ +int +fb_pfour_id(va) + void *va; +{ + volatile u_int32_t val, save, *pfour = va; + + /* Read the pfour register. */ + save = *pfour; + + /* + * Try to modify the type code. If it changes, put the + * original value back, and notify the caller that it's + * not a pfour framebuffer. + */ + val = save & ~PFOUR_REG_RESET; + *pfour = (val ^ PFOUR_FBTYPE_MASK); + if ((*pfour ^ val) & PFOUR_FBTYPE_MASK) { + *pfour = save; + return (PFOUR_NOTPFOUR); + } + + return (PFOUR_ID(val)); +} + +/* + * Return the status of the video enable. + */ +int +fb_pfour_get_video(fb) + struct fbdevice *fb; +{ + + return ((*fb->fb_pfour & PFOUR_REG_VIDEO) != 0); +} + +/* + * Enable or disable the framebuffer. + */ +void +fb_pfour_set_video(fb, enable) + struct fbdevice *fb; + int enable; +{ + volatile u_int32_t pfour; + + pfour = *fb->fb_pfour & ~(PFOUR_REG_INTCLR|PFOUR_REG_VIDEO); + *fb->fb_pfour = pfour | (enable ? PFOUR_REG_VIDEO : 0); +} +#endif /* SUN4 */ diff --git a/sys/arch/sparc/dev/fd.c b/sys/arch/sparc/dev/fd.c index fa729ce26ea..d4dee591b72 100644 --- a/sys/arch/sparc/dev/fd.c +++ b/sys/arch/sparc/dev/fd.c @@ -1,4 +1,4 @@ -/* $NetBSD: fd.c,v 1.13 1995/10/09 22:33:07 pk Exp $ */ +/* $NetBSD: fd.c,v 1.33.4.1 1996/06/12 20:52:25 pk Exp $ */ /*- * Copyright (c) 1993, 1994, 1995 Charles Hannum. @@ -43,7 +43,6 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> -#include <sys/conf.h> #include <sys/file.h> #include <sys/ioctl.h> #include <sys/device.h> @@ -52,12 +51,17 @@ #include <sys/disk.h> #include <sys/buf.h> #include <sys/uio.h> -#include <sys/mtio.h> +#include <sys/stat.h> #include <sys/syslog.h> #include <sys/queue.h> +#include <sys/conf.h> + +#include <dev/cons.h> #include <machine/cpu.h> #include <machine/autoconf.h> +#include <machine/conf.h> + #include <sparc/sparc/auxreg.h> #include <sparc/dev/fdreg.h> #include <sparc/dev/fdvar.h> @@ -128,10 +132,16 @@ extern struct fdcio *fdciop; int fdcmatch __P((struct device *, void *, void *)); void fdcattach __P((struct device *, struct device *, void *)); -struct cfdriver fdccd = { - NULL, "fdc", fdcmatch, fdcattach, DV_DULL, sizeof(struct fdc_softc) +struct cfattach fdc_ca = { + sizeof(struct fdc_softc), fdcmatch, fdcattach }; +struct cfdriver fdc_cd = { + NULL, "fdc", DV_DULL +}; + +__inline struct fd_type *fd_dev_to_type __P((struct fd_softc *, dev_t)); + /* * Floppies come in various flavors, e.g., 1.2MB vs 1.44MB; here is how * we tell them apart. @@ -184,6 +194,8 @@ struct fd_softc { #define FD_MOTOR_WAIT 0x04 /* motor coming up */ int sc_cylin; /* where we think the head is */ + void *sc_sdhook; /* shutdownhook cookie */ + TAILQ_ENTRY(fd_softc) sc_drivechain; int sc_ops; /* I/O ops since last switch */ struct buf sc_q; /* head of buf chain */ @@ -193,14 +205,19 @@ struct fd_softc { int fdmatch __P((struct device *, void *, void *)); void fdattach __P((struct device *, struct device *, void *)); -struct cfdriver fdcd = { - NULL, "fd", fdmatch, fdattach, DV_DISK, sizeof(struct fd_softc) +struct cfattach fd_ca = { + sizeof(struct fd_softc), fdmatch, fdattach }; -void fdgetdisklabel __P((struct fd_softc *)); +struct cfdriver fd_cd = { + NULL, "fd", DV_DISK +}; + +void fdgetdisklabel __P((dev_t)); int fd_get_parms __P((struct fd_softc *)); void fdstrategy __P((struct buf *)); void fdstart __P((struct fd_softc *)); +int fdprint __P((void *, char *)); struct dkdriver fddkdriver = { fdstrategy }; @@ -223,6 +240,9 @@ void fdchwintr __P((void)); int fdcswintr __P((struct fdc_softc *)); void fdcretry __P((struct fdc_softc *fdc)); void fdfinish __P((struct fd_softc *fd, struct buf *bp)); +void fd_do_eject __P((void)); +void fd_mountroot_hook __P((struct device *)); +static void fdconf __P((struct fdc_softc *)); #if PIL_FDSOFT == 4 #define IE_FDSOFT IE_L4 @@ -230,29 +250,44 @@ void fdfinish __P((struct fd_softc *fd, struct buf *bp)); #error 4 #endif -#define OBP_FDNAME (cputyp == CPU_SUN4M ? "SUNW,fdtwo" : "fd") +#define OBP_FDNAME (CPU_ISSUN4M ? "SUNW,fdtwo" : "fd") int fdcmatch(parent, match, aux) struct device *parent; void *match, *aux; { - struct cfdata *cf = match; register struct confargs *ca = aux; register struct romaux *ra = &ca->ca_ra; + /* + * Floppy doesn't exist on sun4. + */ + if (CPU_ISSUN4) + return (0); + + /* + * Floppy controller is on mainbus on sun4c. + */ + if ((CPU_ISSUN4C) && (ca->ca_bustype != BUS_MAIN)) + return (0); + + /* + * Floppy controller is on obio on sun4m. + */ + if ((CPU_ISSUN4M) && (ca->ca_bustype != BUS_OBIO)) + return (0); + /* Sun PROMs call the controller an "fd" or "SUNW,fdtwo" */ if (strcmp(OBP_FDNAME, ra->ra_name)) return (0); - if (ca->ca_bustype == BUS_MAIN) { - if (ca->ca_ra.ra_vaddr && - probeget(ca->ca_ra.ra_vaddr, 1) == -1) { - return (0); - } - return (1); + + if (ca->ca_ra.ra_vaddr && + probeget(ca->ca_ra.ra_vaddr, 1) == -1) { + return (0); } - return (0); + return (1); } /* @@ -260,7 +295,7 @@ fdcmatch(parent, match, aux) */ struct fdc_attach_args { int fa_drive; - int fa_bootdev; + struct bootpath *fa_bootpath; struct fd_type *fa_deftype; }; @@ -315,7 +350,8 @@ fdcattach(parent, self, aux) register struct confargs *ca = aux; struct fdc_softc *fdc = (void *)self; struct fdc_attach_args fa; - int n, pri; + struct bootpath *bp; + int pri; char code; if (ca->ca_ra.ra_vaddr) @@ -398,13 +434,36 @@ fdcattach(parent, self, aux) * Controller and drives are represented by one and the same * Openprom node, so we can as well check for the floppy boots here. */ - if (ca->ca_ra.ra_bp && - strcmp(ca->ca_ra.ra_bp->name, OBP_FDNAME) == 0 && - ca->ca_ra.ra_bp->val[0] == 0 && - ca->ca_ra.ra_bp->val[1] == 0) - fa.fa_bootdev = 1; - else - fa.fa_bootdev = 0; + fa.fa_bootpath = 0; + if ((bp = ca->ca_ra.ra_bp) && strcmp(bp->name, OBP_FDNAME) == 0) { + /* + * WOAH THERE! It looks like we can get the bootpath + * in several different formats!! The faked + * bootpath (and some v2?) looks like /fd@0,0 + * but the real bootpath on some v2 OpenPROM + * systems looks like /fd0. In the case of + * a floppy controller on obio (such as on the sun4m), + * we use "slot, offset" to determine if this is the + * right one. --thorpej + */ + switch (ca->ca_bustype) { + case BUS_MAIN: + if (((bp->val[0] == 0) && /* /fd@0,0 */ + (bp->val[1] == 0)) || + ((bp->val[0] == -1) && /* /fd0 */ + (bp->val[1] == 0))) + fa.fa_bootpath = bp; + break; + + case BUS_OBIO: + /* /obio0/SUNW,fdtwo@0,700000 */ + if ((bp->val[0] == ca->ca_slot) && + (bp->val[1] == ca->ca_offset)) + fa.fa_bootpath = bp; + break; + } + + } /* physical limit: four drives per controller. */ for (fa.fa_drive = 0; fa.fa_drive < 4; fa.fa_drive++) { @@ -422,10 +481,9 @@ fdmatch(parent, match, aux) void *match, *aux; { struct fdc_softc *fdc = (void *)parent; - struct cfdata *cf = match; struct fdc_attach_args *fa = aux; int drive = fa->fa_drive; - int n; + int n, ok; if (drive > 0) /* XXX - for now, punt > 1 drives */ @@ -439,13 +497,12 @@ fdmatch(parent, match, aux) } else { auxregbisc(AUXIO_FDS, 0); } - fdc->sc_nstat = 0; out_fdc(fdc, NE7CMD_RECAL); out_fdc(fdc, drive); /* wait for recalibrate */ - for (n = 0; n < 100000; n++) { - delay(10); + for (n = 0; n < 10000; n++) { + delay(1000); if ((*fdc->sc_reg_msr & (NE7_RQM|NE7_DIO|NE7_CB)) == NE7_RQM) { /* wait a bit longer till device *really* is ready */ delay(100000); @@ -471,15 +528,17 @@ fdmatch(parent, match, aux) printf("\n"); } #endif - if (n != 2 || (fdc->sc_status[0] & 0xf8) != 0x20) - return 0; + ok = (n == 2 && (fdc->sc_status[0] & 0xf8) == 0x20) ? 1 : 0; + /* turn off motor */ - if (fdc->sc_flags & FDC_82077) + if (fdc->sc_flags & FDC_82077) { + /* select drive and turn on motor */ *fdc->sc_reg_dor = FDO_FRST; - else + } else { auxregbisc(0, AUXIO_FDS); + } - return 1; + return ok; } /* @@ -499,7 +558,7 @@ fdattach(parent, self, aux) /* XXX Allow `flags' to override device type? */ if (type) - printf(": %s, %d cyl, %d head, %d sec\n", type->name, + printf(": %s %d cyl, %d head, %d sec\n", type->name, type->tracks, type->heads, type->sectrac); else printf(": density unknown\n"); @@ -519,14 +578,23 @@ fdattach(parent, self, aux) /* * We're told if we're the boot device in fdcattach(). */ - if (fa->fa_bootdev) - bootdv = &fd->sc_dv; + if (fa->fa_bootpath) + fa->fa_bootpath->dev = &fd->sc_dv; + + /* + * Establish a mountroot_hook anyway in case we booted + * with RB_ASKNAME and get selected as the boot device. + */ + mountroot_hook_establish(fd_mountroot_hook, &fd->sc_dv); + + /* Make sure the drive motor gets turned off at shutdown time. */ + fd->sc_sdhook = shutdownhook_establish(fd_motor_off, fd); /* XXX Need to do some more fiddling with sc_dk. */ dk_establish(&fd->sc_dk, &fd->sc_dv); } -inline struct fd_type * +__inline struct fd_type * fd_dev_to_type(fd, dev) struct fd_softc *fd; dev_t dev; @@ -548,8 +616,8 @@ fdstrategy(bp) int s; /* Valid unit, controller, and request? */ - if (unit >= fdcd.cd_ndevs || - (fd = fdcd.cd_devs[unit]) == 0 || + if (unit >= fd_cd.cd_ndevs || + (fd = fd_cd.cd_devs[unit]) == 0 || bp->b_blkno < 0 || (bp->b_bcount % FDC_BSIZE) != 0) { bp->b_error = EINVAL; @@ -582,7 +650,7 @@ fdstrategy(bp) #ifdef FD_DEBUG if (fdc_debug > 1) - printf("fdstrategy: b_blkno %d b_bcount %d blkno %d cylin %d\n", + printf("fdstrategy: b_blkno %d b_bcount %ld blkno %d cylin %ld\n", bp->b_blkno, bp->b_bcount, fd->sc_blkno, bp->b_cylin); #endif @@ -685,7 +753,7 @@ fd_set_motor(fdc) if (fdc->sc_flags & FDC_82077) { status = FDO_FRST | FDO_FDMAEN; - if (fd = fdc->sc_drives.tqh_first) + if ((fd = fdc->sc_drives.tqh_first) != NULL) status |= fd->sc_drive; for (n = 0; n < 4; n++) @@ -774,18 +842,19 @@ out_fdc(fdc, x) } int -Fdopen(dev, flags) +fdopen(dev, flags, fmt, p) dev_t dev; - int flags; + int flags, fmt; + struct proc *p; { - int unit; + int unit, pmask; struct fd_softc *fd; struct fd_type *type; unit = FDUNIT(dev); - if (unit >= fdcd.cd_ndevs) + if (unit >= fd_cd.cd_ndevs) return ENXIO; - fd = fdcd.cd_devs[unit]; + fd = fd_cd.cd_devs[unit]; if (fd == 0) return ENXIO; type = fd_dev_to_type(fd, dev); @@ -800,33 +869,70 @@ Fdopen(dev, flags) fd->sc_cylin = -1; fd->sc_flags |= FD_OPEN; + /* + * Only update the disklabel if we're not open anywhere else. + */ + if (fd->sc_dk.dk_openmask == 0) + fdgetdisklabel(dev); + + pmask = (1 << DISKPART(dev)); + + switch (fmt) { + case S_IFCHR: + fd->sc_dk.dk_copenmask |= pmask; + break; + + case S_IFBLK: + fd->sc_dk.dk_bopenmask |= pmask; + break; + } + fd->sc_dk.dk_openmask = + fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask; + return 0; } int -fdclose(dev, flags) +fdclose(dev, flags, fmt, p) dev_t dev; - int flags; + int flags, fmt; + struct proc *p; { - struct fd_softc *fd = fdcd.cd_devs[FDUNIT(dev)]; + struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; + int pmask = (1 << DISKPART(dev)); fd->sc_flags &= ~FD_OPEN; + + switch (fmt) { + case S_IFCHR: + fd->sc_dk.dk_copenmask &= ~pmask; + break; + + case S_IFBLK: + fd->sc_dk.dk_bopenmask &= ~pmask; + break; + } + fd->sc_dk.dk_openmask = + fd->sc_dk.dk_copenmask | fd->sc_dk.dk_bopenmask; + return 0; } int -fdread(dev, uio) +fdread(dev, uio, flag) dev_t dev; struct uio *uio; + int flag; { return (physio(fdstrategy, NULL, dev, B_READ, minphys, uio)); } int -fdwrite(dev, uio) +fdwrite(dev, uio, flag) dev_t dev; struct uio *uio; + int flag; { return (physio(fdstrategy, NULL, dev, B_WRITE, minphys, uio)); @@ -855,7 +961,6 @@ fdcstatus(dv, n, s) char *s; { struct fdc_softc *fdc = (void *)dv->dv_parent; - #if 0 /* * A 82072 seems to return <invalid command> on @@ -949,7 +1054,7 @@ fdchwintr(fdc) fdcresult(fdc); fdc->sc_istate = ISTATE_IDLE; ienab_bis(IE_FDSOFT); - goto done; + return 1; case ISTATE_IDLE: case ISTATE_SPURIOUS: auxregbisc(0, AUXIO_FDS); /* Does this help? */ @@ -957,12 +1062,12 @@ fdchwintr(fdc) fdc->sc_istate = ISTATE_SPURIOUS; printf("fdc: stray hard interrupt... "); ienab_bis(IE_FDSOFT); - goto done; + return 1; case ISTATE_DMA: break; default: printf("fdc: goofed ...\n"); - goto done; + return 1; } read = bp->b_flags & B_READ; @@ -1005,9 +1110,7 @@ fdchwintr(fdc) break; } } -done: - sc->sc_intrcnt.ev_count++; - return (1); + return 1; } #endif @@ -1023,7 +1126,7 @@ fdcswintr(fdc) struct fd_softc *fd; struct buf *bp; - int read, head, trac, sec, i, s, nblks; + int read, head, sec, nblks; struct fd_type *type; @@ -1246,11 +1349,12 @@ loop: printf("fdc: %d -> threshold\n", thr); #endif fdconf(fdc); - fdc->sc_state = DOIO; fdc->sc_overruns = 0; } - if (++fdc->sc_overruns < 3) + if (++fdc->sc_overruns < 3) { + fdc->sc_state = DOIO; goto loop; + } } fdcretry(fdc); goto loop; @@ -1367,7 +1471,7 @@ fdcretry(fdc) case 0: /* try again */ fdc->sc_state = - (fdc->sc_flags & FDC_EIS) ? DOIO : SEEKCOMPLETE; + (fdc->sc_flags & FDC_EIS) ? DOIO : DOSEEK; break; case 1: case 2: case 3: @@ -1383,6 +1487,7 @@ fdcretry(fdc) default: diskerr(bp, "fd", "hard error", LOG_PRINTF, fd->sc_skip / FDC_BSIZE, (struct disklabel *)NULL); + printf(" (st0 %b st1 %b st2 %b cyl %d head %d sec %d)\n", fdc->sc_status[0], NE7_ST0BITS, fdc->sc_status[1], NE7_ST1BITS, @@ -1406,7 +1511,11 @@ fdsize(dev) } int -fddump() +fddump(dev, blkno, va, size) + dev_t dev; + daddr_t blkno; + caddr_t va; + size_t size; { /* Not implemented. */ @@ -1414,29 +1523,18 @@ fddump() } int -fdioctl(dev, cmd, addr, flag) +fdioctl(dev, cmd, addr, flag, p) dev_t dev; u_long cmd; caddr_t addr; int flag; + struct proc *p; { - struct fd_softc *fd = fdcd.cd_devs[FDUNIT(dev)]; - struct disklabel buffer; + struct fd_softc *fd = fd_cd.cd_devs[FDUNIT(dev)]; int error; switch (cmd) { case DIOCGDINFO: - bzero(fd->sc_dk.dk_label, sizeof(struct disklabel)); - - fd->sc_dk.dk_label->d_secpercyl = fd->sc_type->seccyl; - fd->sc_dk.dk_label->d_type = DTYPE_FLOPPY; - fd->sc_dk.dk_label->d_secsize = FDC_BSIZE; - - if (readdisklabel(dev, fdstrategy, - fd->sc_dk.dk_label, - fd->sc_dk.dk_cpulabel) != NULL) - return EINVAL; - *(struct disklabel *)addr = *(fd->sc_dk.dk_label); return 0; @@ -1461,16 +1559,16 @@ fdioctl(dev, cmd, addr, flag) fd->sc_dk.dk_cpulabel); return error; - case MTIOCTOP: - if (((struct mtop *)addr)->mt_op != MTOFFL) - return EIO; -#ifdef COMPAT_SUNOS - case SUNOS_FDIOCEJECT: -#endif - auxregbisc(AUXIO_FDS, AUXIO_FEJ); - delay(10); - auxregbisc(AUXIO_FEJ, AUXIO_FDS); + case DIOCLOCK: + /* + * Nothing to do here, really. + */ + return 0; + + case DIOCEJECT: + fd_do_eject(); return 0; + #ifdef DEBUG case _IO('f', 100): { @@ -1492,7 +1590,7 @@ fdioctl(dev, cmd, addr, flag) ~CFG_THRHLD_MASK; ((struct fdc_softc *)fd->sc_dv.dv_parent)->sc_cfg |= (*(int *)addr & CFG_THRHLD_MASK); - fdconf(fd->sc_dv.dv_parent); + fdconf((struct fdc_softc *) fd->sc_dv.dv_parent); return 0; case _IO('f', 102): { @@ -1516,3 +1614,92 @@ fdioctl(dev, cmd, addr, flag) panic("fdioctl: impossible"); #endif } + +void +fdgetdisklabel(dev) + dev_t dev; +{ + int unit = FDUNIT(dev), i; + struct fd_softc *fd = fd_cd.cd_devs[unit]; + struct disklabel *lp = fd->sc_dk.dk_label; + struct cpu_disklabel *clp = fd->sc_dk.dk_cpulabel; + + bzero(lp, sizeof(struct disklabel)); + bzero(lp, sizeof(struct cpu_disklabel)); + + lp->d_type = DTYPE_FLOPPY; + lp->d_secsize = FDC_BSIZE; + lp->d_secpercyl = fd->sc_type->seccyl; + lp->d_nsectors = fd->sc_type->sectrac; + lp->d_ncylinders = fd->sc_type->tracks; + lp->d_ntracks = fd->sc_type->heads; /* Go figure... */ + lp->d_rpm = 3600; /* XXX like it matters... */ + + strncpy(lp->d_typename, "floppy", sizeof(lp->d_typename)); + strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname)); + lp->d_interleave = 1; + + lp->d_partitions[RAW_PART].p_offset = 0; + lp->d_partitions[RAW_PART].p_size = lp->d_secpercyl * lp->d_ncylinders; + lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED; + lp->d_npartitions = RAW_PART + 1; + + lp->d_magic = DISKMAGIC; + lp->d_magic2 = DISKMAGIC; + lp->d_checksum = dkcksum(lp); + + /* + * Call the generic disklabel extraction routine. If there's + * not a label there, fake it. + */ + if (readdisklabel(dev, fdstrategy, lp, clp) != NULL) { + strncpy(lp->d_packname, "default label", + sizeof(lp->d_packname)); + /* + * Reset the partition info; it might have gotten + * trashed in readdisklabel(). + * + * XXX Why do we have to do this? readdisklabel() + * should be safe... + */ + for (i = 0; i < MAXPARTITIONS; ++i) { + lp->d_partitions[i].p_offset = 0; + if (i == RAW_PART) { + lp->d_partitions[i].p_size = + lp->d_secpercyl * lp->d_ncylinders; + lp->d_partitions[i].p_fstype = FS_BSDFFS; + } else { + lp->d_partitions[i].p_size = 0; + lp->d_partitions[i].p_fstype = FS_UNUSED; + } + } + lp->d_npartitions = RAW_PART + 1; + } +} + +void +fd_do_eject() +{ + + auxregbisc(AUXIO_FDS, AUXIO_FEJ); + delay(10); + auxregbisc(AUXIO_FEJ, AUXIO_FDS); +} + +/* ARGSUSED */ +void +fd_mountroot_hook(dev) + struct device *dev; +{ + int c; + + fd_do_eject(); + printf("Insert filesystem floppy and press return."); + for (;;) { + c = cngetc(); + if ((c == '\r') || (c == '\n')) { + printf("\n"); + return; + } + } +} diff --git a/sys/arch/sparc/dev/fdreg.h b/sys/arch/sparc/dev/fdreg.h index a522eb2d3c2..4166d58b0ba 100644 --- a/sys/arch/sparc/dev/fdreg.h +++ b/sys/arch/sparc/dev/fdreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: fdreg.h,v 1.4 1995/06/28 04:31:19 cgd Exp $ */ +/* $NetBSD: fdreg.h,v 1.5 1996/02/01 22:32:27 mycroft Exp $ */ /*- * Copyright (c) 1991 The Regents of the University of California. @@ -42,7 +42,7 @@ /* uses NEC765 controller */ #include <dev/ic/nec765reg.h> -#ifndef LOCORE +#ifndef _LOCORE struct fdreg_77 { u_int8_t fd_statusA; u_int8_t fd_statusB; diff --git a/sys/arch/sparc/dev/fdvar.h b/sys/arch/sparc/dev/fdvar.h index f74d37ce41d..9a74ebcf162 100644 --- a/sys/arch/sparc/dev/fdvar.h +++ b/sys/arch/sparc/dev/fdvar.h @@ -1,5 +1,5 @@ /* - * $NetBSD: fdvar.h,v 1.3 1995/04/07 19:46:15 pk Exp $ + * $NetBSD: fdvar.h,v 1.4 1996/02/01 22:32:29 mycroft Exp $ * * Copyright (c) 1995 Paul Kranenburg * All rights reserved. @@ -36,7 +36,7 @@ #define FDC_NSTATUS 10 -#if !defined(LOCORE) +#ifndef _LOCORE struct fdcio { /* * 82072 (sun4c) and 82077 (sun4m) controllers have different @@ -62,9 +62,9 @@ struct fdcio { /* * Statictics. */ - struct evcnt fdcio_intrcnt; + struct evcnt fdcio_intrcnt; }; -#endif /* LOCORE */ +#endif /* _LOCORE */ /* istate values */ #define ISTATE_IDLE 0 /* No HW interrupt expected */ @@ -72,5 +72,5 @@ struct fdcio { #define ISTATE_SENSEI 2 /* Do SENSEI on next HW interrupt */ #define ISTATE_DMA 3 /* Pseudo-DMA in progress */ -#define SUNOS_FDIOCEJECT _IO('f', 24) +#define FDIOCEJECT _IO('f', 24) diff --git a/sys/arch/sparc/dev/if_ie.c b/sys/arch/sparc/dev/if_ie.c index 20aa5204d26..3bd3defb91a 100644 --- a/sys/arch/sparc/dev/if_ie.c +++ b/sys/arch/sparc/dev/if_ie.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_ie.c,v 1.15 1995/04/11 09:18:09 pk Exp $ */ +/* $NetBSD: if_ie.c,v 1.24 1996/05/07 01:28:28 thorpej Exp $ */ /*- * Copyright (c) 1993, 1994, 1995 Charles Hannum. @@ -57,7 +57,7 @@ * * Majorly cleaned up and 3C507 code merged by Charles Hannum. * - * Converted to SUN ie driver by Charles D. Cranor, + * Converted to SUN ie driver by Charles D. Cranor, * October 1994, January 1995. * This sun version based on i386 version 1.30. */ @@ -129,6 +129,11 @@ Mode of operation: #include <netinet/if_ether.h> #endif +#ifdef NS +#include <netns/ns.h> +#include <netns/ns_if.h> +#endif + #include <vm/vm.h> /* @@ -221,7 +226,6 @@ const char *ie_hardware_names[] = { struct ie_softc { struct device sc_dev; /* device structure */ struct intrhand sc_ih; /* interrupt info */ - struct evcnt sc_intrcnt; /* # of interrupts, per ie */ caddr_t sc_iobase; /* KVA of base of 24 bit addr space */ caddr_t sc_maddr; /* KVA of base of chip's RAM (16bit addr sp.)*/ @@ -230,15 +234,18 @@ struct ie_softc { struct arpcom sc_arpcom;/* system arpcom structure */ - void (*reset_586)(); /* card dependent reset function */ - void (*chan_attn)(); /* card dependent attn function */ - void (*run_586)(); /* card depenent "go on-line" function */ + void (*reset_586) __P((struct ie_softc *)); + /* card dependent reset function */ + void (*chan_attn) __P((struct ie_softc *)); + /* card dependent attn function */ + void (*run_586) __P((struct ie_softc *)); + /* card depenent "go on-line" function */ void (*memcopy) __P((const void *, void *, u_int)); /* card dependent memory copy function */ void (*memzero) __P((void *, u_int)); /* card dependent memory zero function */ - + enum ie_hardware hard_type; /* card type */ int want_mcsetup; /* mcsetup flag */ @@ -253,10 +260,10 @@ struct ie_softc { volatile struct ie_sys_ctl_block *scb; /* - * pointer and size of a block of KVA where the buffers + * pointer and size of a block of KVA where the buffers * are to be allocated from */ - + caddr_t buf_area; int buf_area_sz; @@ -294,7 +301,7 @@ static void ie_vmereset __P((struct ie_softc *)); static void ie_vmeattend __P((struct ie_softc *)); static void ie_vmerun __P((struct ie_softc *)); -void iewatchdog __P((/* short */)); +void iewatchdog __P((struct ifnet *)); int ieintr __P((void *)); int ieinit __P((struct ie_softc *)); int ieioctl __P((struct ifnet *, u_long, caddr_t)); @@ -302,6 +309,7 @@ void iestart __P((struct ifnet *)); void iereset __P((struct ie_softc *)); static void ie_readframe __P((struct ie_softc *, int)); static void ie_drop_packet_buffer __P((struct ie_softc *)); +int ie_setupram __P((struct ie_softc *)); static int command_and_wait __P((struct ie_softc *, int, void volatile *, int)); /*static*/ void ierint __P((struct ie_softc *)); @@ -311,6 +319,20 @@ static int ieget __P((struct ie_softc *, struct mbuf **, static void setup_bufs __P((struct ie_softc *)); static int mc_setup __P((struct ie_softc *, void *)); static void mc_reset __P((struct ie_softc *)); +static __inline int ether_equal __P((u_char *, u_char *)); +static __inline void ie_ack __P((struct ie_softc *, u_int)); +static __inline void ie_setup_config __P((volatile struct ie_config_cmd *, + int, int)); +static __inline int check_eh __P((struct ie_softc *, struct ether_header *, + int *)); +static __inline int ie_buflen __P((struct ie_softc *, int)); +static __inline int ie_packet_len __P((struct ie_softc *)); +static __inline void iexmit __P((struct ie_softc *)); +static __inline caddr_t Align __P((caddr_t)); + +static void chan_attn_timeout __P((void *)); +static void run_tdr __P((struct ie_softc *, struct ie_tdr_cmd *)); +static void iestop __P((struct ie_softc *)); #ifdef IEDEBUG void print_rbd __P((volatile struct ie_recv_buf_desc *)); @@ -319,11 +341,15 @@ int in_ierint = 0; int in_ietint = 0; #endif -int iematch(); -void ieattach(); +int iematch __P((struct device *, void *, void *)); +void ieattach __P((struct device *, struct device *, void *)); -struct cfdriver iecd = { - NULL, "ie", iematch, ieattach, DV_IFNET, sizeof(struct ie_softc) +struct cfattach ie_ca = { + sizeof(struct ie_softc), iematch, ieattach +}; + +struct cfdriver ie_cd = { + NULL, "ie", DV_IFNET }; /* @@ -344,7 +370,7 @@ struct cfdriver iecd = { * Here are a few useful functions. We could have done these as macros, but * since we have the inline facility, it makes sense to use that instead. */ -static inline void +static __inline void ie_setup_config(cmd, promiscuous, manchester) volatile struct ie_config_cmd *cmd; int promiscuous, manchester; @@ -364,7 +390,7 @@ ie_setup_config(cmd, promiscuous, manchester) cmd->ie_junk = 0xff; } -static inline void +static __inline void ie_ack(sc, mask) struct ie_softc *sc; u_int mask; @@ -375,12 +401,13 @@ ie_ack(sc, mask) } -int -iematch(parent, cf, aux) +int +iematch(parent, vcf, aux) struct device *parent; - struct cfdata *cf; + void *vcf; void *aux; { + struct cfdata *cf = vcf; struct confargs *ca = aux; struct romaux *ra = &ca->ca_ra; @@ -389,7 +416,7 @@ iematch(parent, cf, aux) if (ca->ca_bustype == BUS_SBUS) return (0); - if (cputyp == CPU_SUN4) { + if (CPU_ISSUN4) { /* * XXX need better probe here so we can figure out what we've got */ @@ -408,7 +435,7 @@ iematch(parent, cf, aux) /* * MULTIBUS/VME support */ -void +void ie_vmereset(sc) struct ie_softc *sc; { @@ -418,7 +445,7 @@ ie_vmereset(sc) iev->status = 0; } -void +void ie_vmeattend(sc) struct ie_softc *sc; { @@ -428,7 +455,7 @@ ie_vmeattend(sc) iev->status &= ~IEVME_ATTEN; /* down. */ } -void +void ie_vmerun(sc) struct ie_softc *sc; { @@ -473,7 +500,8 @@ ie_obrun(sc) */ void ieattach(parent, self, aux) - struct device *parent, *self; + struct device *parent; + struct device *self; void *aux; { struct ie_softc *sc = (void *) self; @@ -511,13 +539,13 @@ ieattach(parent, self, aux) * XXX */ - ie_map = vm_map_create(pmap_kernel(), (vm_offset_t)IEOB_ADBASE, + ie_map = vm_map_create(pmap_kernel(), (vm_offset_t)IEOB_ADBASE, (vm_offset_t)IEOB_ADBASE + sc->sc_msize, 1); if (ie_map == NULL) panic("ie_map"); sc->sc_maddr = (caddr_t) kmem_alloc(ie_map, sc->sc_msize); if (sc->sc_maddr == NULL) panic("ie kmem_alloc"); kvm_uncache(sc->sc_maddr, sc->sc_msize >> PGSHIFT); - if (((u_long)sc->sc_maddr & ~(NBPG-1)) != (u_long)sc->sc_maddr) + if (((u_long)sc->sc_maddr & ~(NBPG-1)) != (u_long)sc->sc_maddr) panic("unaligned dvmamalloc breaks"); sc->sc_iobase = (caddr_t)IEOB_ADBASE; /* 24 bit base addr */ (sc->memzero)(sc->sc_maddr, sc->sc_msize); @@ -539,7 +567,7 @@ ieattach(parent, self, aux) pa = pmap_extract(pmap_kernel(), (vm_offset_t)sc->sc_maddr); if (pa == 0) panic("ie pmap_extract"); pmap_enter(pmap_kernel(), trunc_page(IEOB_ADBASE+IE_SCP_ADDR), - (vm_offset_t)pa | PMAP_NC, + (vm_offset_t)pa | PMAP_NC /*| PMAP_IOC*/, VM_PROT_READ | VM_PROT_WRITE, 1); sc->scp = (volatile struct ie_sys_conf_ptr *) @@ -574,8 +602,8 @@ ieattach(parent, self, aux) /* 4 more */ rampaddr = rampaddr | ((iev->status & IEVME_HADDR) << 16); rampaddr -= (u_long)ca->ca_ra.ra_paddr; - sc->sc_maddr = mapiodev(ca->ca_ra.ra_reg, rampaddr, sc->sc_msize, - ca->ca_bustype); + sc->sc_maddr = mapiodev(ca->ca_ra.ra_reg, rampaddr, + sc->sc_msize, ca->ca_bustype); sc->sc_iobase = sc->sc_maddr; iev->pectrl = iev->pectrl | IEVME_PARACK; /* clear to start */ @@ -623,8 +651,8 @@ ieattach(parent, self, aux) /* XXX should reclaim resources? */ return; } - ifp->if_unit = sc->sc_dev.dv_unit; - ifp->if_name = iecd.cd_name; + bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + ifp->if_softc = sc; ifp->if_start = iestart; ifp->if_ioctl = ieioctl; ifp->if_watchdog = iewatchdog; @@ -651,6 +679,7 @@ ieattach(parent, self, aux) intr_establish(pri, &sc->sc_ih); break; case BUS_VME16: + case BUS_VME32: sc->sc_ih.ih_fun = ieintr; sc->sc_ih.ih_arg = sc; vmeintr_establish(ca->ca_ra.ra_intr[0].int_vec, pri, @@ -659,12 +688,10 @@ ieattach(parent, self, aux) #endif /* SUN4 */ } - evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt); - bp = ca->ca_ra.ra_bp; if (bp != NULL && strcmp(bp->name, "ie") == 0 && sc->sc_dev.dv_unit == bp->val[1]) - bootdv = &sc->sc_dev; + bp->dev = &sc->sc_dev; } @@ -674,10 +701,10 @@ ieattach(parent, self, aux) * an interrupt after a transmit has been started on it. */ void -iewatchdog(unit) - short unit; +iewatchdog(ifp) + struct ifnet *ifp; { - struct ie_softc *sc = iecd.cd_devs[unit]; + struct ie_softc *sc = ifp->if_softc; log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname); ++sc->sc_arpcom.ac_if.if_oerrors; @@ -701,12 +728,12 @@ void *v; * check for parity error */ if (sc->hard_type == IE_VME) { - volatile struct ievme *iev = (volatile struct ievme *)sc->sc_reg; - + volatile struct ievme *iev = (volatile struct ievme *)sc->sc_reg +; if (iev->status & IEVME_PERR) { printf("%s: parity error (ctrl %x @ %02x%04x)\n", - iev->pectrl, iev->pectrl & IEVME_HADDR, - iev->peaddr); + sc->sc_dev.dv_xname, iev->pectrl, + iev->pectrl & IEVME_HADDR, iev->peaddr); iev->pectrl = iev->pectrl | IEVME_PARACK; } } @@ -754,7 +781,6 @@ loop: if ((status = sc->scb->ie_status) & IE_ST_WHENCE) goto loop; - sc->sc_intrcnt.ev_count++; return 1; } @@ -777,9 +803,9 @@ ierint(sc) sc->sc_arpcom.ac_if.if_ipackets++; if (!--timesthru) { sc->sc_arpcom.ac_if.if_ierrors += - SWAP(scb->ie_err_crc) + + SWAP(scb->ie_err_crc) + SWAP(scb->ie_err_align) + - SWAP(scb->ie_err_resource) + + SWAP(scb->ie_err_resource) + SWAP(scb->ie_err_overrun); scb->ie_err_crc = scb->ie_err_align = scb->ie_err_resource = scb->ie_err_overrun = @@ -792,7 +818,7 @@ ierint(sc) (scb->ie_status & IE_RU_READY) == 0) { sc->rframes[0]->ie_fd_buf_desc = MK_16(sc->sc_maddr, sc->rbuffs[0]); - scb->ie_recv_list = + scb->ie_recv_list = MK_16(sc->sc_maddr, sc->rframes[0]); command_and_wait(sc, IE_RU_START, 0, 0); } @@ -823,7 +849,7 @@ ietint(sc) if (status & IE_STAT_OK) { sc->sc_arpcom.ac_if.if_opackets++; - sc->sc_arpcom.ac_if.if_collisions += + sc->sc_arpcom.ac_if.if_collisions += SWAP(status & IE_XS_MAXCOLL); } else if (status & IE_STAT_ABORT) { printf("%s: send aborted\n", sc->sc_dev.dv_xname); @@ -865,7 +891,7 @@ ietint(sc) * Compare two Ether/802 addresses for equality, inlined and unrolled for * speed. I'd love to have an inline assembler version of this... */ -static inline int +static __inline int ether_equal(one, two) u_char *one, *two; { @@ -888,7 +914,7 @@ ether_equal(one, two) * only client which will fiddle with IFF_PROMISC is BPF. This is * probably a good assumption, but we do not make it here. (Yet.) */ -static inline int +static __inline int check_eh(sc, eh, to_bpf) struct ie_softc *sc; struct ether_header *eh; @@ -991,7 +1017,7 @@ check_eh(sc, eh, to_bpf) * IE_RBUF_SIZE is an even power of two. If somehow the act_len exceeds * the size of the buffer, then we are screwed anyway. */ -static inline int +static __inline int ie_buflen(sc, head) struct ie_softc *sc; int head; @@ -1001,7 +1027,7 @@ ie_buflen(sc, head) & (IE_RBUF_SIZE | (IE_RBUF_SIZE - 1))); } -static inline int +static __inline int ie_packet_len(sc) struct ie_softc *sc; { @@ -1034,7 +1060,7 @@ ie_packet_len(sc) * command to the chip to be executed. On the way, if we have a BPF listener * also give him a copy. */ -inline static void +static __inline void iexmit(sc) struct ie_softc *sc; { @@ -1063,7 +1089,7 @@ iexmit(sc) sc->xmit_cmds[sc->xctail]->ie_xmit_desc = MK_16(sc->sc_maddr, sc->xmit_buffs[sc->xctail]); - sc->scb->ie_command_list = + sc->scb->ie_command_list = MK_16(sc->sc_maddr, sc->xmit_cmds[sc->xctail]); command_and_wait(sc, IE_CU_START, 0, 0); @@ -1079,7 +1105,7 @@ iexmit(sc) * length of the data available. This enables us to allocate mbuf * clusters in many situations where before we would have had a long * chain of partially-full mbufs. This should help to speed up the - * operation considerably. (Provided that it works, of course.) + * operation considerably. (Provided that it works, of course.) */ static inline int ieget(sc, mp, ehp, to_bpf) @@ -1385,7 +1411,7 @@ void iestart(ifp) struct ifnet *ifp; { - struct ie_softc *sc = iecd.cd_devs[ifp->if_unit]; + struct ie_softc *sc = ifp->if_softc; struct mbuf *m0, *m; u_char *buffer; u_short len; @@ -1408,7 +1434,7 @@ iestart(ifp) len = 0; buffer = sc->xmit_cbuffs[sc->xchead]; - for (m0 = m; m && (len +m->m_len) < IE_TBUF_SIZE; + for (m0 = m; m && (len +m->m_len) < IE_TBUF_SIZE; m = m->m_next) { bcopy(mtod(m, caddr_t), buffer, m->m_len); buffer += m->m_len; @@ -1435,7 +1461,7 @@ iestart(ifp) /* * set up IE's ram space */ -int +int ie_setupram(sc) struct ie_softc *sc; { @@ -1517,7 +1543,7 @@ iereset(sc) */ static void chan_attn_timeout(rock) - caddr_t rock; + void *rock; { *(int *)rock = 1; @@ -1528,9 +1554,9 @@ chan_attn_timeout(rock) * or be accepted, depending on the command. If the command pointer * is null, then pretend that the command is not an action command. * If the command pointer is not null, and the command is an action - * command, wait for - * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK - * to become true. + * command, wait for + * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK + * to become true. */ static int command_and_wait(sc, cmd, pcmd, mask) @@ -1638,7 +1664,7 @@ run_tdr(sc, cmd) #define ALLOC(p, n) _ALLOC(p, ALIGN(n)) /* XXX convert to this? */ #endif -static inline caddr_t +static __inline caddr_t Align(ptr) caddr_t ptr; { @@ -1661,13 +1687,11 @@ Align(ptr) * note: this function was written to be easy to understand, rather than * highly efficient (it isn't in the critical path). */ -static void +static void setup_bufs(sc) struct ie_softc *sc; { caddr_t ptr = sc->buf_area; /* memory pool */ - volatile struct ie_recv_frame_desc *rfd = (void *) ptr; - volatile struct ie_recv_buf_desc *rbd; int n, r; /* @@ -1677,14 +1701,15 @@ setup_bufs(sc) (sc->memzero)(ptr, sc->buf_area_sz); ptr = Align(ptr); /* set alignment and stick with it */ - n = (int)Align(sizeof(struct ie_xmit_cmd)) + - (int)Align(sizeof(struct ie_xmit_buf)) + IE_TBUF_SIZE; + n = (int)Align((caddr_t) sizeof(struct ie_xmit_cmd)) + + (int)Align((caddr_t) sizeof(struct ie_xmit_buf)) + IE_TBUF_SIZE; n *= NTXBUF; /* n = total size of xmit area */ n = sc->buf_area_sz - n;/* n = free space for recv stuff */ - r = (int)Align(sizeof(struct ie_recv_frame_desc)) + - (((int)Align(sizeof(struct ie_recv_buf_desc)) + IE_RBUF_SIZE) * B_PER_F); + r = (int)Align((caddr_t) sizeof(struct ie_recv_frame_desc)) + + (((int)Align((caddr_t) sizeof(struct ie_recv_buf_desc)) + + IE_RBUF_SIZE) * B_PER_F); /* r = size of one R frame */ @@ -1804,7 +1829,7 @@ mc_setup(sc, ptr) (sc->memcopy)((caddr_t)sc->mcast_addrs, (caddr_t)cmd->ie_mcast_addrs, sc->mcast_count * sizeof *sc->mcast_addrs); - cmd->ie_mcast_bytes = + cmd->ie_mcast_bytes = SWAP(sc->mcast_count * ETHER_ADDR_LEN); /* grrr... */ sc->scb->ie_command_list = MK_16(sc->sc_maddr, cmd); @@ -1831,7 +1856,6 @@ ieinit(sc) { volatile struct ie_sys_ctl_block *scb = sc->scb; void *ptr; - int n; ptr = sc->buf_area; @@ -1867,7 +1891,7 @@ ieinit(sc) cmd->com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST; cmd->com.ie_cmd_link = SWAP(0xffff); - (sc->memcopy)(sc->sc_arpcom.ac_enaddr, + (sc->memcopy)(sc->sc_arpcom.ac_enaddr, (caddr_t)&cmd->ie_address, sizeof cmd->ie_address); if (command_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) || @@ -1920,18 +1944,13 @@ ieioctl(ifp, cmd, data) u_long cmd; caddr_t data; { - struct ie_softc *sc = iecd.cd_devs[ifp->if_unit]; + struct ie_softc *sc = ifp->if_softc; struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; int s, error = 0; s = splnet(); - if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) { - splx(s); - return error; - } - switch(cmd) { case SIOCSIFADDR: @@ -1944,6 +1963,24 @@ ieioctl(ifp, cmd, data) arp_ifinit(&sc->sc_arpcom, ifa); break; #endif +#ifdef NS + /* XXX - This code is probably wrong. */ + case AF_NS: + { + struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; + + if (ns_nullhost(*ina)) + ina->x_host = + *(union ns_host *)(sc->sc_arpcom.ac_enaddr); + else + bcopy(ina->x_host.c_host, + sc->sc_arpcom.ac_enaddr, + sizeof(sc->sc_arpcom.ac_enaddr)); + /* Set new address. */ + ieinit(sc); + break; + } +#endif /* NS */ default: ieinit(sc); break; diff --git a/sys/arch/sparc/dev/if_le.c b/sys/arch/sparc/dev/if_le.c index 055e2a31a5c..4db240f0f62 100644 --- a/sys/arch/sparc/dev/if_le.c +++ b/sys/arch/sparc/dev/if_le.c @@ -1,6 +1,8 @@ -/* $NetBSD: if_le.c,v 1.24 1995/12/11 12:43:28 pk Exp $ */ +/* $NetBSD: if_le.c,v 1.35.4.1 1996/07/17 01:46:00 jtc Exp $ */ /*- + * Copyright (c) 1996 + * The President and Fellows of Harvard College. All rights reserved. * Copyright (c) 1995 Charles M. Hannum. All rights reserved. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. @@ -18,6 +20,8 @@ * 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 Aaron Brown and + * Harvard University. * 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 @@ -62,46 +66,92 @@ #include <sparc/dev/sbusvar.h> #include <sparc/dev/dmareg.h> #include <sparc/dev/dmavar.h> -#include <sparc/dev/if_lereg.h> -#include <sparc/dev/if_levar.h> + #include <dev/ic/am7990reg.h> -#define LE_NEED_BUF_CONTIG #include <dev/ic/am7990var.h> -#define LE_SOFTC(unit) lecd.cd_devs[unit] -#define LE_DELAY(x) DELAY(x) +#include <sparc/dev/if_lereg.h> +#include <sparc/dev/if_levar.h> int lematch __P((struct device *, void *, void *)); void leattach __P((struct device *, struct device *, void *)); -int leintr __P((void *)); -struct cfdriver lecd = { - NULL, "le", lematch, leattach, DV_IFNET, sizeof(struct le_softc) +#if defined(SUN4M) /* XXX */ +int myleintr __P((void *)); +int ledmaintr __P((struct dma_softc *)); + +int +myleintr(arg) + void *arg; +{ + register struct le_softc *lesc = arg; + + if (lesc->sc_dma->sc_regs->csr & D_ERR_PEND) + return ledmaintr(lesc->sc_dma); + + /* + * XXX There is a bug somewhere in the interrupt code that causes stray + * ethernet interrupts under high network load. This bug has been + * impossible to locate, so until it is found, we just ignore stray + * interrupts, as they do not in fact correspond to dropped packets. + */ + + /* return */ am7990_intr(arg); + return 1; +} +#endif + +struct cfattach le_ca = { + sizeof(struct le_softc), lematch, leattach }; -integrate void +hide void lewrcsr __P((struct am7990_softc *, u_int16_t, u_int16_t)); +hide u_int16_t lerdcsr __P((struct am7990_softc *, u_int16_t)); +hide void lehwinit __P((struct am7990_softc *)); + +hide void lewrcsr(sc, port, val) - struct le_softc *sc; + struct am7990_softc *sc; u_int16_t port, val; { - register struct lereg1 *ler1 = sc->sc_r1; + register struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; ler1->ler1_rap = port; ler1->ler1_rdp = val; } -integrate u_int16_t +hide u_int16_t lerdcsr(sc, port) - struct le_softc *sc; + struct am7990_softc *sc; u_int16_t port; { - register struct lereg1 *ler1 = sc->sc_r1; + register struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1; u_int16_t val; ler1->ler1_rap = port; val = ler1->ler1_rdp; return (val); -} +} + +hide void +lehwinit(sc) + struct am7990_softc *sc; +{ +#if defined(SUN4M) + struct le_softc *lesc = (struct le_softc *)sc; + + if (CPU_ISSUN4M && lesc->sc_dma) { + struct ifnet *ifp = &sc->sc_arpcom.ac_if; + + if (ifp->if_flags & IFF_LINK0) + lesc->sc_dma->sc_regs->csr |= DE_AUI_TP; + else if (ifp->if_flags & IFF_LINK1) + lesc->sc_dma->sc_regs->csr &= ~DE_AUI_TP; + + delay(20000); /* must not touch le for 20ms */ + } +#endif +} int lematch(parent, match, aux) @@ -125,15 +175,18 @@ leattach(parent, self, aux) struct device *parent, *self; void *aux; { - struct le_softc *sc = (void *)self; + struct le_softc *lesc = (struct le_softc *)self; + struct am7990_softc *sc = &lesc->sc_am7990; struct confargs *ca = aux; int pri; struct bootpath *bp; u_long laddr; - int dmachild = strncmp(parent->dv_xname, "ledma", 5) == 0; +#if defined(SUN4C) || defined(SUN4M) + int sbuschild = strncmp(parent->dv_xname, "sbus", 4) == 0; +#endif /* XXX the following declarations should be elsewhere */ - extern void myetheraddr(u_char *); + extern void myetheraddr __P((u_char *)); if (ca->ca_ra.ra_nintr != 1) { printf(": expected 1 interrupt, got %d\n", ca->ca_ra.ra_nintr); @@ -142,13 +195,13 @@ leattach(parent, self, aux) pri = ca->ca_ra.ra_intr[0].int_pri; printf(" pri %d", pri); - sc->sc_r1 = (struct lereg1 *)mapiodev(ca->ca_ra.ra_reg, 0, + lesc->sc_r1 = (struct lereg1 *)mapiodev(ca->ca_ra.ra_reg, 0, sizeof(struct lereg1), ca->ca_bustype); sc->sc_conf3 = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON; laddr = (u_long)dvma_malloc(MEMSIZE, &sc->sc_mem, M_NOWAIT); #if defined (SUN4M) - if ((laddr & 0xffffff) >= (laddr & 0xffffff) + MEMSIZE) + if ((laddr & 0xffffff) >= (laddr & 0xffffff) + MEMSIZE) panic("if_le: Lance buffer crosses 16MB boundary"); #endif sc->sc_addr = laddr & 0xffffff; @@ -156,14 +209,17 @@ leattach(parent, self, aux) myetheraddr(sc->sc_arpcom.ac_enaddr); - sc->sc_copytodesc = copytobuf_contig; - sc->sc_copyfromdesc = copyfrombuf_contig; - sc->sc_copytobuf = copytobuf_contig; - sc->sc_copyfrombuf = copyfrombuf_contig; - sc->sc_zerobuf = zerobuf_contig; + sc->sc_copytodesc = am7990_copytobuf_contig; + sc->sc_copyfromdesc = am7990_copyfrombuf_contig; + sc->sc_copytobuf = am7990_copytobuf_contig; + sc->sc_copyfrombuf = am7990_copyfrombuf_contig; + sc->sc_zerobuf = am7990_zerobuf_contig; - sc->sc_arpcom.ac_if.if_name = lecd.cd_name; - leconfig(sc); + sc->sc_rdcsr = lerdcsr; + sc->sc_wrcsr = lewrcsr; + sc->sc_hwinit = lehwinit; + + am7990_config(sc); bp = ca->ca_ra.ra_bp; switch (ca->ca_bustype) { @@ -173,44 +229,41 @@ leattach(parent, self, aux) (bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit)) case BUS_SBUS: - sc->sc_sd.sd_reset = (void *)lereset; - if (dmachild) { -#ifdef notyet - sc->sc_dma = (struct dma_softc *)parent; - sc->sc_dma->sc_le = sc; - sc->sc_dma->sc_regs->en_bar = laddr & 0xff000000; - sbus_establish(&sc->sc_sd, parent); -#endif + lesc->sc_sd.sd_reset = (void *)am7990_reset; + if (sbuschild) { + lesc->sc_dma = NULL; + sbus_establish(&lesc->sc_sd, &sc->sc_dev); } else { - sc->sc_dma = NULL; - sbus_establish(&sc->sc_sd, &sc->sc_dev); + lesc->sc_dma = (struct dma_softc *)parent; + lesc->sc_dma->sc_le = lesc; + lesc->sc_dma->sc_regs->en_bar = laddr & 0xff000000; + /* Assume SBus is grandparent */ + sbus_establish(&lesc->sc_sd, parent); } - if (bp != NULL && strcmp(bp->name, lecd.cd_name) == 0 && + if (bp != NULL && strcmp(bp->name, le_cd.cd_name) == 0 && SAME_LANCE(bp, ca)) - bootdv = &sc->sc_dev; + bp->dev = &sc->sc_dev; break; #endif /* SUN4C || SUN4M */ default: - if (bp != NULL && strcmp(bp->name, lecd.cd_name) == 0 && + if (bp != NULL && strcmp(bp->name, le_cd.cd_name) == 0 && sc->sc_dev.dv_unit == bp->val[1]) - bootdv = &sc->sc_dev; + bp->dev = &sc->sc_dev; break; } - sc->sc_ih.ih_fun = leintr; -#if defined(SUN4M) && 0 - if (cputyp == CPU_SUN4M) - sc->sc_ih.ih_fun = myleintr; + lesc->sc_ih.ih_fun = am7990_intr; +#if defined(SUN4M) /*XXX*/ + if (CPU_ISSUN4M) + lesc->sc_ih.ih_fun = myleintr; #endif - sc->sc_ih.ih_arg = sc; - intr_establish(pri, &sc->sc_ih); + lesc->sc_ih.ih_arg = sc; + intr_establish(pri, &lesc->sc_ih); /* now initialize DMA */ - if (sc->sc_dma) { - dmaenintr(sc->sc_dma); + if (lesc->sc_dma) { + DMA_ENINTR(lesc->sc_dma); } } - -#include <dev/ic/am7990.c> diff --git a/sys/arch/sparc/dev/if_levar.h b/sys/arch/sparc/dev/if_levar.h index 7361c4eae7a..934d74c932e 100644 --- a/sys/arch/sparc/dev/if_levar.h +++ b/sys/arch/sparc/dev/if_levar.h @@ -1,4 +1,4 @@ -/* $NetBSD: if_levar.h,v 1.2 1995/12/11 12:43:29 pk Exp $ */ +/* $NetBSD: if_levar.h,v 1.5 1996/05/07 01:27:32 thorpej Exp $ */ /*- * Copyright (c) 1995 Charles M. Hannum. All rights reserved. @@ -47,45 +47,10 @@ * This structure contains the output queue for the interface, its address, ... */ struct le_softc { - struct device sc_dev; /* base structure */ - struct arpcom sc_arpcom; /* Ethernet common part */ - - void (*sc_copytodesc)(); /* Copy to descriptor */ - void (*sc_copyfromdesc)(); /* Copy from descriptor */ - - void (*sc_copytobuf)(); /* Copy to buffer */ - void (*sc_copyfrombuf)(); /* Copy from buffer */ - void (*sc_zerobuf)(); /* and Zero bytes in buffer */ - - u_int16_t sc_conf3; /* CSR3 value */ - - void *sc_mem; /* base address of RAM -- CPU's view */ - u_long sc_addr; /* base address of RAM -- LANCE's view */ - u_long sc_memsize; /* size of RAM */ - - int sc_nrbuf; /* number of receive buffers */ - int sc_ntbuf; /* number of transmit buffers */ - int sc_last_rd; - int sc_first_td, sc_last_td, sc_no_td; - - int sc_initaddr; - int sc_rmdaddr; - int sc_tmdaddr; - int sc_rbufaddr; - int sc_tbufaddr; - -#ifdef LEDEBUG - int sc_debug; -#endif + struct am7990_softc sc_am7990; /* glue to MI code */ struct sbusdev sc_sd; /* sbus device */ struct intrhand sc_ih; /* interrupt vectoring */ struct lereg1 *sc_r1; /* LANCE registers */ struct dma_softc *sc_dma; /* pointer to my dma */ }; - -/* DMA macros for ledma */ -#define DMA_ENINTR(r) ((r->enintr)(r)) -#define DMA_ISINTR(r) ((r->isintr)(r)) -#define DMA_RESET(r) ((r->reset)(r)) - diff --git a/sys/arch/sparc/dev/kbd.c b/sys/arch/sparc/dev/kbd.c index 194da8fdd6e..f65228f0848 100644 --- a/sys/arch/sparc/dev/kbd.c +++ b/sys/arch/sparc/dev/kbd.c @@ -1,4 +1,4 @@ -/* $NetBSD: kbd.c,v 1.19 1995/07/06 05:35:34 pk Exp $ */ +/* $NetBSD: kbd.c,v 1.23 1996/04/01 17:34:34 christos Exp $ */ /* * Copyright (c) 1992, 1993 @@ -51,7 +51,6 @@ */ #include <sys/param.h> -#include <sys/conf.h> #include <sys/device.h> #include <sys/ioctl.h> #include <sys/kernel.h> @@ -59,8 +58,11 @@ #include <sys/syslog.h> #include <sys/systm.h> #include <sys/tty.h> +#include <sys/signalvar.h> +#include <sys/conf.h> #include <machine/autoconf.h> +#include <machine/conf.h> #include <machine/vuid_event.h> #include <sparc/dev/event_var.h> @@ -217,19 +219,10 @@ struct kbd_softc { } kbd_softc; /* Prototypes */ -void kbd_ascii(struct tty *); -void kbd_serial(struct tty *, void (*)(), void (*)()); -static void kbd_getid(void *); -void kbd_reset(struct kbd_state *); -static int kbd_translate(int, struct kbd_state *); -void kbd_rint(int); -int kbdopen(dev_t, int, int, struct proc *); -int kbdclose(dev_t, int, int, struct proc *); -int kbdread(dev_t, struct uio *, int); -int kbdwrite(dev_t, struct uio *, int); -int kbdioctl(dev_t, u_long, caddr_t, int, struct proc *); -int kbdselect(dev_t, int, struct proc *); -int kbd_docmd(int, int); +void kbd_reset __P((struct kbd_state *)); +static int kbd_translate __P((int, struct kbd_state *)); +void kbdattach __P((int)); +void kbd_repeat __P((void *arg)); /* set in kbdattach() */ int kbd_repeat_start; @@ -240,7 +233,8 @@ int kbd_repeat_step; * This happens before kbd_serial. */ void -kbd_ascii(struct tty *tp) +kbd_ascii(tp) + struct tty *tp; { kbd_softc.k_cons = tp; @@ -251,7 +245,10 @@ kbd_ascii(struct tty *tp) * We pick up the initial keyboard click state here as well. */ void -kbd_serial(struct tty *tp, void (*iopen)(), void (*iclose)()) +kbd_serial(tp, iopen, iclose) + struct tty *tp; + void (*iopen) __P((struct tty *)); + void (*iclose) __P((struct tty *)); { register struct kbd_softc *k; register char *cp; @@ -261,13 +258,11 @@ kbd_serial(struct tty *tp, void (*iopen)(), void (*iclose)()) k->k_open = iopen; k->k_close = iclose; -#if defined(SUN4C) || defined(SUN4M) - if (cputyp != CPU_SUN4) { + if (!CPU_ISSUN4) { cp = getpropstring(optionsnode, "keyboard-click?"); if (cp && strcmp(cp, "true") == 0) k->k_state.kbd_click = 1; } -#endif /* SUN4C || SUN4M */ } /* @@ -276,7 +271,8 @@ kbd_serial(struct tty *tp, void (*iopen)(), void (*iclose)()) * send a RESET, so that we can find out what kind of keyboard it is. */ void -kbdattach(int nkbd) +kbdattach(kbd) + int kbd; { register struct kbd_softc *k; register struct tty *tp; @@ -295,7 +291,8 @@ kbdattach(int nkbd) } void -kbd_reset(register struct kbd_state *ks) +kbd_reset(ks) + register struct kbd_state *ks; { /* * On first identification, wake up anyone waiting for type @@ -328,7 +325,6 @@ kbd_reset(register struct kbd_state *ks) break; default: printf("Unknown keyboard type %d\n", ks->kbd_id); - break; } ks->kbd_leds = 0; @@ -338,7 +334,9 @@ kbd_reset(register struct kbd_state *ks) * Turn keyboard up/down codes into ASCII. */ static int -kbd_translate(register int c, register struct kbd_state *ks) +kbd_translate(c, ks) + register int c; + register struct kbd_state *ks; { register int down; @@ -401,7 +399,8 @@ kbd_translate(register int c, register struct kbd_state *ks) void -kbd_repeat(void *arg) +kbd_repeat(arg) + void *arg; { struct kbd_softc *k = (struct kbd_softc *)arg; int s = spltty(); @@ -414,7 +413,8 @@ kbd_repeat(void *arg) } void -kbd_rint(register int c) +kbd_rint(c) + register int c; { register struct kbd_softc *k = &kbd_softc; register struct firm_event *fe; @@ -512,7 +512,11 @@ kbd_rint(register int c) } int -kbdopen(dev_t dev, int flags, int mode, struct proc *p) +kbdopen(dev, flags, mode, p) + dev_t dev; + int flags; + int mode; + struct proc *p; { int s, error; struct tty *tp; @@ -548,7 +552,11 @@ kbdopen(dev_t dev, int flags, int mode, struct proc *p) } int -kbdclose(dev_t dev, int flags, int mode, struct proc *p) +kbdclose(dev, flags, mode, p) + dev_t dev; + int flags; + int mode; + struct proc *p; { /* @@ -564,7 +572,10 @@ kbdclose(dev_t dev, int flags, int mode, struct proc *p) } int -kbdread(dev_t dev, struct uio *uio, int flags) +kbdread(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; { return (ev_read(&kbd_softc.k_events, uio, flags)); @@ -572,14 +583,22 @@ kbdread(dev_t dev, struct uio *uio, int flags) /* this routine should not exist, but is convenient to write here for now */ int -kbdwrite(dev_t dev, struct uio *uio, int flags) +kbdwrite(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; { return (EOPNOTSUPP); } int -kbdioctl(dev_t dev, u_long cmd, register caddr_t data, int flag, struct proc *p) +kbdioctl(dev, cmd, data, flag, p) + dev_t dev; + u_long cmd; + register caddr_t data; + int flag; + struct proc *p; { register struct kbd_softc *k = &kbd_softc; register struct kiockey *kmp; @@ -602,10 +621,11 @@ kbdioctl(dev_t dev, u_long cmd, register caddr_t data, int flag, struct proc *p) case KIOCGETKEY: if (((struct okiockey *)data)->kio_station == 118) { /* - * This is X11 asking if a type 3 keyboard is - * really a type 3 keyboard. Say yes. + * This is X11 asking (in an inappropriate fashion) + * if a type 3 keyboard is really a type 3 keyboard. + * Say yes (inappropriately). */ - ((struct okiockey *)data)->kio_entry = (u_char) HOLE; + ((struct okiockey *)data)->kio_entry = (u_char)HOLE; return (0); } break; @@ -680,7 +700,6 @@ kbdioctl(dev_t dev, u_long cmd, register caddr_t data, int flag, struct proc *p) int s; char leds = *(char *)data; struct tty *tp = kbd_softc.k_kbd; - s = spltty(); if (tp->t_outq.c_cc > 120) (void) tsleep((caddr_t)&lbolt, TTIPRI, @@ -699,6 +718,7 @@ kbdioctl(dev_t dev, u_long cmd, register caddr_t data, int flag, struct proc *p) *(char *)data = k->k_state.kbd_leds; return (0); + case FIONBIO: /* we will remove this someday (soon???) */ return (0); @@ -722,7 +742,10 @@ kbdioctl(dev_t dev, u_long cmd, register caddr_t data, int flag, struct proc *p) } int -kbdselect(dev_t dev, int rw, struct proc *p) +kbdselect(dev, rw, p) + dev_t dev; + int rw; + struct proc *p; { return (ev_select(&kbd_softc.k_events, rw, p)); @@ -734,7 +757,9 @@ kbdselect(dev_t dev, int rw, struct proc *p) * is flooding. (The keyboard runs at 1200 baud, or 120 cps.) */ int -kbd_docmd(int cmd, int isuser) +kbd_docmd(cmd, isuser) + int cmd; + int isuser; { register struct tty *tp = kbd_softc.k_kbd; register struct kbd_softc *k = &kbd_softc; diff --git a/sys/arch/sparc/dev/ms.c b/sys/arch/sparc/dev/ms.c index fb71f4ecb36..365d1c476b2 100644 --- a/sys/arch/sparc/dev/ms.c +++ b/sys/arch/sparc/dev/ms.c @@ -1,4 +1,4 @@ -/* $NetBSD: ms.c,v 1.5 1995/08/29 22:15:35 pk Exp $ */ +/* $NetBSD: ms.c,v 1.8 1996/04/01 17:29:52 christos Exp $ */ /* * Copyright (c) 1992, 1993 @@ -49,15 +49,20 @@ */ #include <sys/param.h> -#include <sys/conf.h> #include <sys/ioctl.h> #include <sys/kernel.h> #include <sys/proc.h> #include <sys/syslog.h> #include <sys/systm.h> #include <sys/tty.h> +#include <sys/signalvar.h> +#include <sys/conf.h> #include <machine/vuid_event.h> +#include <machine/cpu.h> +#include <machine/kbd.h> +#include <machine/conf.h> + #include <sparc/dev/event_var.h> /* @@ -92,7 +97,8 @@ struct ms_softc { void ms_serial(tp, iopen, iclose) struct tty *tp; - void (*iopen)(), (*iclose)(); + void (*iopen) __P((struct tty *)); + void (*iclose) __P((struct tty *)); { ms_softc.ms_mouse = tp; @@ -242,13 +248,18 @@ msopen(dev, flags, mode, p) int flags, mode; struct proc *p; { - int s, error; if (ms_softc.ms_events.ev_io) return (EBUSY); ms_softc.ms_events.ev_io = p; ev_init(&ms_softc.ms_events); /* may cause sleep */ + if (CPU_ISSUN4) { + /* We need to set the baud rate on the mouse. */ + ms_softc.ms_mouse->t_ispeed = + ms_softc.ms_mouse->t_ospeed = 1200; + } + (*ms_softc.ms_open)(ms_softc.ms_mouse); ms_softc.ms_ready = 1; /* start accepting events */ return (0); @@ -297,8 +308,6 @@ msioctl(dev, cmd, data, flag, p) int flag; struct proc *p; { - int s; - switch (cmd) { case FIONBIO: /* we will remove this someday (soon???) */ diff --git a/sys/arch/sparc/dev/obio.c b/sys/arch/sparc/dev/obio.c index f78bbcc2f37..37cf369fe48 100644 --- a/sys/arch/sparc/dev/obio.c +++ b/sys/arch/sparc/dev/obio.c @@ -1,7 +1,8 @@ -/* $NetBSD: obio.c,v 1.15 1995/05/27 08:12:51 pk Exp $ */ +/* $NetBSD: obio.c,v 1.24 1996/05/18 12:22:49 mrg Exp $ */ /* * Copyright (c) 1993, 1994 Theo de Raadt + * Copyright (c) 1995 Paul Kranenburg * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,6 +32,7 @@ */ #include <sys/param.h> +#include <sys/systm.h> #include <sys/device.h> #include <sys/malloc.h> @@ -48,10 +50,14 @@ #include <machine/ctlreg.h> #include <sparc/sparc/asm.h> #include <sparc/sparc/vaddrs.h> +#include <sparc/dev/sbusvar.h> struct bus_softc { - struct device sc_dev; /* base device */ - int nothing; + union { + struct device scu_dev; /* base device */ + struct sbus_softc scu_sbus; /* obio is another sbus slot */ + } bu; +#define sc_dev bu.scu_dev }; /* autoconfiguration driver */ @@ -60,17 +66,40 @@ static void obioattach __P((struct device *, struct device *, void *)); static void vmesattach __P((struct device *, struct device *, void *)); static void vmelattach __P((struct device *, struct device *, void *)); -struct cfdriver obiocd = { NULL, "obio", busmatch, obioattach, - DV_DULL, sizeof(struct bus_softc) +int busprint __P((void *, char *)); +static int busattach __P((struct device *, void *, void *, int)); +void * bus_map __P((struct rom_reg *, int, int)); +int obio_scan __P((struct device *, void *, void *)); +int vmes_scan __P((struct device *, void *, void *)); +int vmel_scan __P((struct device *, void *, void *)); +int vmeintr __P((void *)); + +struct cfattach obio_ca = { + sizeof(struct bus_softc), busmatch, obioattach +}; + +struct cfdriver obio_cd = { + NULL, "obio", DV_DULL }; -struct cfdriver vmelcd = { NULL, "vmel", busmatch, vmelattach, - DV_DULL, sizeof(struct bus_softc) + +struct cfattach vmel_ca = { + sizeof(struct bus_softc), busmatch, vmelattach }; -struct cfdriver vmescd = { NULL, "vmes", busmatch, vmesattach, - DV_DULL, sizeof(struct bus_softc) + +struct cfdriver vmel_cd = { + NULL, "vmel", DV_DULL }; -static int busattach __P((struct device *, void *, void *, int)); +struct cfattach vmes_ca = { + sizeof(struct bus_softc), busmatch, vmesattach +}; + +struct cfdriver vmes_cd = { + NULL, "vmes", DV_DULL +}; + +struct intrhand **vmeints; + int busmatch(parent, vcf, aux) @@ -81,8 +110,12 @@ busmatch(parent, vcf, aux) register struct confargs *ca = aux; register struct romaux *ra = &ca->ca_ra; - if (cputyp != CPU_SUN4) + if (CPU_ISSUN4M) + return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0); + + if (!CPU_ISSUN4) return (0); + return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0); } @@ -95,27 +128,180 @@ busprint(args, obio) if (ca->ca_ra.ra_name == NULL) ca->ca_ra.ra_name = "<unknown>"; + if (obio) printf("[%s at %s]", ca->ca_ra.ra_name, obio); - printf(" addr 0x%x", ca->ca_ra.ra_paddr); - if (ca->ca_ra.ra_intr[0].int_vec != -1) + + printf(" addr %p", ca->ca_ra.ra_paddr); + + if (CPU_ISSUN4 && ca->ca_ra.ra_intr[0].int_vec != -1) printf(" vec 0x%x", ca->ca_ra.ra_intr[0].int_vec); + return (UNCONF); } + +void +obioattach(parent, self, args) + struct device *parent, *self; + void *args; +{ +#if defined(SUN4M) + register struct bus_softc *sc = (struct bus_softc *)self; + struct confargs oca, *ca = args; + register struct romaux *ra = &ca->ca_ra; + register int node0, node; + register char *name; + register const char *sp; + const char *const *ssp; + extern int autoconf_nzs; + + static const char *const special4m[] = { + /* find these first */ + "eeprom", + "counter", + "auxio", + "", + /* place device to ignore here */ + "interrupt", + NULL + }; +#endif + + if (CPU_ISSUN4) { + if (self->dv_unit > 0) { + printf(" unsupported\n"); + return; + } + printf("\n"); + + (void)config_search(obio_scan, self, args); + bus_untmp(); + } + +#if defined(SUN4M) + if (!CPU_ISSUN4M) + return; + + /* + * There is only one obio bus (it is in fact one of the Sbus slots) + * How about VME? + */ + if (sc->sc_dev.dv_unit > 0) { + printf(" unsupported\n"); + return; + } + + printf("\n"); + + if (ra->ra_bp != NULL && strcmp(ra->ra_bp->name, "obio") == 0) + oca.ca_ra.ra_bp = ra->ra_bp + 1; + else + oca.ca_ra.ra_bp = NULL; + + sc->bu.scu_sbus.sc_range = ra->ra_range; + sc->bu.scu_sbus.sc_nrange = ra->ra_nrange; + + /* + * Loop through ROM children, fixing any relative addresses + * and then configuring each device. + * We first do the crucial ones, such as eeprom, etc. + */ + node0 = firstchild(ra->ra_node); + for (ssp = special4m ; *(sp = *ssp) != 0; ssp++) { + if ((node = findnode(node0, sp)) == 0) { + printf("could not find %s amongst obio devices\n", sp); + panic(sp); + } + if (!romprop(&oca.ca_ra, sp, node)) + continue; + + sbus_translate(self, &oca); + oca.ca_bustype = BUS_OBIO; + (void) config_found(&sc->sc_dev, (void *)&oca, busprint); + } + + for (node = node0; node; node = nextsibling(node)) { + name = getpropstring(node, "name"); + for (ssp = special4m ; (sp = *ssp) != NULL; ssp++) + if (strcmp(name, sp) == 0) + break; + + if (sp != NULL || !romprop(&oca.ca_ra, name, node)) + continue; + + if (strcmp(name, "zs") == 0) + /* XXX - see autoconf.c for this hack */ + autoconf_nzs++; + + /* Translate into parent address spaces */ + sbus_translate(self, &oca); + oca.ca_bustype = BUS_OBIO; + (void) config_found(&sc->sc_dev, (void *)&oca, busprint); + } +#endif +} + +void +vmesattach(parent, self, args) + struct device *parent, *self; + void *args; +{ + if (CPU_ISSUN4M || self->dv_unit > 0) { + printf(" unsupported\n"); + return; + } + printf("\n"); + + if (vmeints == NULL) { + vmeints = (struct intrhand **)malloc(256 * + sizeof(struct intrhand *), M_TEMP, M_NOWAIT); + bzero(vmeints, 256 * sizeof(struct intrhand *)); + } + (void)config_search(vmes_scan, self, args); + bus_untmp(); +} + +void +vmelattach(parent, self, args) + struct device *parent, *self; + void *args; +{ + if (CPU_ISSUN4M || self->dv_unit > 0) { + printf(" unsupported\n"); + return; + } + printf("\n"); + + if (vmeints == NULL) { + vmeints = (struct intrhand **)malloc(256 * + sizeof(struct intrhand *), M_TEMP, M_NOWAIT); + bzero(vmeints, 256 * sizeof(struct intrhand *)); + } + (void)config_search(vmel_scan, self, args); + bus_untmp(); +} + int busattach(parent, child, args, bustype) struct device *parent; - void *child, *args; + void *args, *child; int bustype; { +#if defined(SUN4) struct cfdata *cf = child; - register struct bus_softc *sc = (struct bus_softc *)parent; register struct confargs *ca = args; struct confargs oca; caddr_t tmp; - if (bustype == BUS_OBIO && cputyp == CPU_SUN4) { + if (bustype == BUS_OBIO && CPU_ISSUN4) { + + /* + * avoid sun4m entries which don't have valid PA's. + * no point in even probing them. + */ + if (cf->cf_loc[0] == -1) return 0; + /* * On the 4/100 obio addresses must be mapped at * 0x0YYYYYYY, but alias higher up (we avoid the @@ -123,64 +309,69 @@ busattach(parent, child, args, bustype) * XXX: We also assume that 4/[23]00 obio addresses * must be 0xZYYYYYYY, where (Z != 0) */ - if (cpumod==SUN4_100 && (cf->cf_loc[0] & 0xf0000000)) - return (0); - if (cpumod!=SUN4_100 && !(cf->cf_loc[0] & 0xf0000000)) - return (0); + if (cpumod == SUN4_100 && (cf->cf_loc[0] & 0xf0000000)) + return 0; + if (cpumod != SUN4_100 && !(cf->cf_loc[0] & 0xf0000000)) + return 0; } if (parent->dv_cfdata->cf_driver->cd_indirect) { printf(" indirect devices not supported\n"); - return (0); + return 0; } oca.ca_ra.ra_iospace = -1; oca.ca_ra.ra_paddr = (void *)cf->cf_loc[0]; oca.ca_ra.ra_len = 0; oca.ca_ra.ra_nreg = 1; - tmp = NULL; - if (oca.ca_ra.ra_paddr != (void *)-1) - tmp = bus_tmp(oca.ca_ra.ra_paddr, bustype); + if (oca.ca_ra.ra_paddr) + tmp = (caddr_t)bus_tmp(oca.ca_ra.ra_paddr, + bustype); + else + tmp = NULL; oca.ca_ra.ra_vaddr = tmp; oca.ca_ra.ra_intr[0].int_pri = cf->cf_loc[1]; if (bustype == BUS_VME16 || bustype == BUS_VME32) oca.ca_ra.ra_intr[0].int_vec = cf->cf_loc[2]; else oca.ca_ra.ra_intr[0].int_vec = -1; - oca.ca_ra.ra_nintr = 0; - if (oca.ca_ra.ra_intr[0].int_pri != -1) - oca.ca_ra.ra_nintr = 1; + oca.ca_ra.ra_nintr = 1; oca.ca_ra.ra_name = cf->cf_driver->cd_name; - oca.ca_ra.ra_bp = NULL; if (ca->ca_ra.ra_bp != NULL && - ((bustype == BUS_VME16 && strcmp(ca->ca_ra.ra_bp->name, "vmes") == 0) || - (bustype == BUS_VME32 && strcmp(ca->ca_ra.ra_bp->name, "vmel") == 0) || - (bustype == BUS_OBIO && strcmp(ca->ca_ra.ra_bp->name, "obio") == 0))) + ((bustype == BUS_VME16 && strcmp(ca->ca_ra.ra_bp->name,"vmes") ==0) || + (bustype == BUS_VME32 && strcmp(ca->ca_ra.ra_bp->name,"vmel") ==0) || + (bustype == BUS_OBIO && strcmp(ca->ca_ra.ra_bp->name,"obio") == 0))) oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1; + else + oca.ca_ra.ra_bp = NULL; oca.ca_bustype = bustype; - if ((*cf->cf_driver->cd_match)(parent, cf, &oca) == 0) - return (0); + if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0) + return 0; /* - * check if XXmatch() replaced the temporary mapping with - * a real mapping. If not, then make sure we don't pass the - * tmp mapping to the attach routine. + * check if XXmatch routine replaced the temporary mapping with + * a real mapping. If not, then make sure we don't pass the + * tmp mapping to the attach routine. */ if (oca.ca_ra.ra_vaddr == tmp) oca.ca_ra.ra_vaddr = NULL; /* wipe out tmp address */ /* - * the match routine will set "ra_len" if it wants us to + * the match routine will set "ra_len" if it wants us to * establish a mapping for it. * (which won't be seen on future XXmatch calls, * so not as useful as it seems.) */ if (oca.ca_ra.ra_len) - oca.ca_ra.ra_vaddr = bus_map(oca.ca_ra.ra_paddr, + oca.ca_ra.ra_vaddr = + bus_map(oca.ca_ra.ra_reg, oca.ca_ra.ra_len, oca.ca_bustype); config_attach(parent, cf, &oca, busprint); - return (1); + return 1; +#else + return 0; +#endif } int @@ -191,23 +382,6 @@ obio_scan(parent, child, args) return busattach(parent, child, args, BUS_OBIO); } -void -obioattach(parent, self, args) - struct device *parent, *self; - void *args; -{ - if (self->dv_unit > 0) { - printf(" unsupported\n"); - return; - } - printf("\n"); - - (void)config_search(obio_scan, self, args); - bus_untmp(); -} - -struct intrhand **vmeints; - int vmes_scan(parent, child, args) struct device *parent; @@ -216,26 +390,6 @@ vmes_scan(parent, child, args) return busattach(parent, child, args, BUS_VME16); } -void -vmesattach(parent, self, args) - struct device *parent, *self; - void *args; -{ - if (self->dv_unit > 0) { - printf(" unsupported\n"); - return; - } - printf("\n"); - - if (vmeints == NULL) { - vmeints = (struct intrhand **)malloc(256 * - sizeof(struct intrhand *), M_TEMP, M_NOWAIT); - bzero(vmeints, 256 * sizeof(struct intrhand *)); - } - (void)config_search(vmes_scan, self, args); - bus_untmp(); -} - int vmel_scan(parent, child, args) struct device *parent; @@ -244,26 +398,6 @@ vmel_scan(parent, child, args) return busattach(parent, child, args, BUS_VME32); } -void -vmelattach(parent, self, args) - struct device *parent, *self; - void *args; -{ - if (self->dv_unit > 0) { - printf(" unsupported\n"); - return; - } - printf("\n"); - - if (vmeints == NULL) { - vmeints = (struct intrhand **)malloc(256 * - sizeof(struct intrhand *), M_TEMP, M_NOWAIT); - bzero(vmeints, 256 * sizeof(struct intrhand *)); - } - (void)config_search(vmel_scan, self, args); - bus_untmp(); -} - int pil_to_vme[] = { -1, /* pil 0 */ -1, /* pil 1 */ @@ -291,10 +425,17 @@ vmeintr(arg) struct intrhand *ih; int i = 0; - vec = ldcontrolb(AC_VMEINTVEC | (pil_to_vme[level] << 1) | 1); +#ifdef DIAGNOSTIC + if (!CPU_ISSUN4) { + panic("vme: spurious interrupt"); + } +#endif + + vec = ldcontrolb((caddr_t) + (AC_VMEINTVEC | (pil_to_vme[level] << 1) | 1)); if (vec == -1) { printf("vme: spurious interrupt\n"); - return (0); + return 0; } for (ih = vmeints[vec]; ih; ih = ih->ih_next) @@ -307,9 +448,14 @@ void vmeintr_establish(vec, level, ih) int vec, level; struct intrhand *ih; -{ +{ struct intrhand *ihs; + if (!CPU_ISSUN4) { + panic("vmeintr_establish: not supported on cpu-type %d", + cputyp); + } + if (vec == -1) panic("vmeintr_establish: uninitialized vec\n"); @@ -344,14 +490,13 @@ vmeintr_establish(vec, level, ih) */ void * bus_map(pa, len, bustype) - void *pa; + struct rom_reg *pa; int len; int bustype; { - struct rom_reg rr; - u_long pf = (u_long)pa >> PGSHIFT; + u_long pf = (u_long)(pa->rr_paddr) >> PGSHIFT; u_long va, pte; - int pgtype; + int pgtype = -1; switch (bt2pmt[bustype]) { case PMAP_OBIO: @@ -370,12 +515,12 @@ bus_map(pa, len, bustype) pte = getpte(va); if ((pte & PG_V) != 0 && (pte & PG_TYPE) == pgtype && (pte & PG_PFNUM) == pf) - return ((void *)(va | ((u_long)pa & PGOFSET))); + return ((void *) + (va | ((u_long)pa->rr_paddr & PGOFSET)) ); /* note: preserve page offset */ } } - rr.rr_paddr = pa; - return mapiodev(&rr, 0, len, bustype); + return mapiodev(pa, 0, len, bustype); } void * @@ -387,8 +532,8 @@ bus_tmp(pa, bustype) int pmtype = bt2pmt[bustype]; pmap_enter(pmap_kernel(), TMPMAP_VA, - addr | pmtype | PMAP_NC, - VM_PROT_READ | VM_PROT_WRITE, 1); + addr | pmtype | PMAP_NC, + VM_PROT_READ | VM_PROT_WRITE, 1); return ((void *)(TMPMAP_VA | ((u_long) pa & PGOFSET)) ); } diff --git a/sys/arch/sparc/dev/pfourreg.h b/sys/arch/sparc/dev/pfourreg.h index de3f656dc35..8ec422c2019 100644 --- a/sys/arch/sparc/dev/pfourreg.h +++ b/sys/arch/sparc/dev/pfourreg.h @@ -1,6 +1,7 @@ -/* $Id: pfourreg.h,v 1.2 1995/11/09 21:26:14 deraadt Exp $ */ +/* $NetBSD: pfourreg.h,v 1.1 1996/02/27 22:09:36 thorpej Exp $ */ /* + * Copyright (c) 1996 Jason R. Thorpe. All rights reserved. * Copyright (c) 1995 Theo de Raadt * All rights reserved. * @@ -31,11 +32,18 @@ */ /* - * pfour bus registers. + * pfour framebuffer registers. */ -/* offsets */ -#define PFOUR_REG 0x300000 /* offset from 0x[0f]b000000 */ +/* Offset of bwtwo framebuffer from pfour register */ +#define PFOUR_BW_OFF 0x00100000 + +/* Offsets for color framebuffers */ +#define PFOUR_COLOR_OFF_OVERLAY 0x00100000 +#define PFOUR_COLOR_OFF_ENABLE 0x00300000 +#define PFOUR_COLOR_OFF_COLOR 0x00500000 +#define PFOUR_COLOR_OFF_END 0x00700000 +#define PFOUR_COLOR_OFF_CMAP 0xfff00000 /* (-0x00100000) */ #define PFOUR_REG_DIAG 0x80 #define PFOUR_REG_READBACKCLR 0x40 @@ -48,6 +56,7 @@ #define PFOUR_REG_FIRSTHALF 0x01 #define PFOUR_REG_RESET 0x01 +#define PFOUR_FBTYPE_MASK 0x7f000000 #define PFOUR_FBTYPE(x) ((x) >> 24) #define PFOUR_ID_MASK 0xf0 @@ -68,6 +77,4 @@ #define PFOUR_SIZE_1440X1440 0x04 #define PFOUR_SIZE_640X480 0x05 -int pfour_videosize __P((int reg, int *xp, int *yp)); -void pfour_reset __P((void)); - +#define PFOUR_NOTPFOUR -1 diff --git a/sys/arch/sparc/dev/power.c b/sys/arch/sparc/dev/power.c new file mode 100644 index 00000000000..02308765505 --- /dev/null +++ b/sys/arch/sparc/dev/power.c @@ -0,0 +1,103 @@ +/* $NetBSD: power.c,v 1.2 1996/05/16 15:56:56 abrown Exp $ */ + +/* + * Copyright (c) 1996 + * The President and Fellows of Harvard College. All rights reserved. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Aaron Brown and + * Harvard University. + * + * 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 Harvard University + * 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. + * + * $Id: power.c,v 1.1 1996/08/11 05:34:25 deraadt Exp $ + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/systm.h> + +#include <machine/autoconf.h> + +#include <sparc/dev/power.h> + +static int powermatch __P((struct device *, void *, void *)); +static void powerattach __P((struct device *, struct device *, void *)); + +struct cfattach power_ca = { + sizeof(struct device), powermatch, powerattach +}; + +struct cfdriver power_cd = { + NULL, "power", DV_DULL +}; + +/* + * This is the driver for the "power" register available on some Sun4m + * machines. This allows the machine to remove power automatically when + * shutdown or halted or whatever. + * + * XXX: this capability is not utilized in the current kernel. + */ + +static int +powermatch(parent, vcf, aux) + struct device *parent; + void *aux, *vcf; +{ + register struct confargs *ca = aux; + + if (CPU_ISSUN4M) + return (strcmp("power", ca->ca_ra.ra_name) == 0); + + return (0); +} + +/* ARGSUSED */ +static void +powerattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct confargs *ca = aux; + struct romaux *ra = &ca->ca_ra; + + power_reg = mapdev(ra->ra_reg, 0, 0, sizeof(long), ca->ca_bustype); + + printf("\n"); +} + +void +powerdown() +{ + *POWER_REG |= POWER_OFF; +} diff --git a/sys/arch/sparc/dev/power.h b/sys/arch/sparc/dev/power.h new file mode 100644 index 00000000000..252195b210c --- /dev/null +++ b/sys/arch/sparc/dev/power.h @@ -0,0 +1,60 @@ +/* $NetBSD: power.h,v 1.2 1996/05/16 15:56:57 abrown Exp $ */ + +/* + * Copyright (c) 1996 + * The President and Fellows of Harvard College. All rights reserved. + * + * All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Aaron Brown and + * Harvard University. + * + * 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 Harvard University + * 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. + * + * $Id: power.h,v 1.1 1996/08/11 05:34:25 deraadt Exp $ + * + */ + +/* + * Sun-4m power register. This register allows the computer to power itself + * down. + */ + +#define POWER_OFF 0x1 /* remove power */ + +#define POWER_REG ((volatile u_char *)(power_reg)) + +#define POWER_BITS "\20\1POWEROFF" + +#ifndef _LOCORE +volatile u_char *power_reg; +#endif + +void powerdown __P((void)); /* power off function */ diff --git a/sys/arch/sparc/dev/rcons_font.h b/sys/arch/sparc/dev/rcons_font.h index 0583e458e03..3cbc847ea53 100644 --- a/sys/arch/sparc/dev/rcons_font.h +++ b/sys/arch/sparc/dev/rcons_font.h @@ -1,4 +1,4 @@ -/* $NetBSD: rcons_font.h,v 1.2 1995/10/08 19:31:44 pk Exp $ */ +/* $NetBSD: rcons_font.h,v 1.3 1995/11/29 22:03:53 pk Exp $ */ /* * Raster Console font definition; this file exports `console_font', diff --git a/sys/arch/sparc/dev/sbus.c b/sys/arch/sparc/dev/sbus.c index 77ba2349467..32e52e31533 100644 --- a/sys/arch/sparc/dev/sbus.c +++ b/sys/arch/sparc/dev/sbus.c @@ -1,4 +1,4 @@ -/* $NetBSD: sbus.c,v 1.6 1995/02/01 12:37:28 pk Exp $ */ +/* $NetBSD: sbus.c,v 1.10 1996/04/22 02:35:03 abrown Exp $ */ /* * Copyright (c) 1992, 1993 @@ -49,6 +49,7 @@ */ #include <sys/param.h> +#include <sys/systm.h> #include <sys/device.h> #include <machine/autoconf.h> @@ -56,12 +57,19 @@ #include <sparc/dev/sbusreg.h> #include <sparc/dev/sbusvar.h> +int sbus_print __P((void *, char *)); +void sbusreset __P((int)); + /* autoconfiguration driver */ void sbus_attach __P((struct device *, struct device *, void *)); int sbus_match __P((struct device *, void *, void *)); -struct cfdriver sbuscd = { - NULL, "sbus", sbus_match, sbus_attach, - DV_DULL, sizeof(struct sbus_softc) + +struct cfattach sbus_ca = { + sizeof(struct sbus_softc), sbus_match, sbus_attach +}; + +struct cfdriver sbus_cd = { + NULL, "sbus", DV_DULL }; /* @@ -92,8 +100,9 @@ sbus_match(parent, vcf, aux) register struct confargs *ca = aux; register struct romaux *ra = &ca->ca_ra; - if (cputyp==CPU_SUN4) + if (CPU_ISSUN4) return (0); + return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0); } @@ -109,8 +118,7 @@ sbus_attach(parent, self, aux) register struct sbus_softc *sc = (struct sbus_softc *)self; struct confargs *ca = aux; register struct romaux *ra = &ca->ca_ra; - register int base, node, slot; - register int i; + register int node; register char *name; struct confargs oca; @@ -131,11 +139,19 @@ sbus_attach(parent, self, aux) sc->sc_clockfreq = getpropint(node, "clock-frequency", 25*1000*1000); printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq)); + /* + * Get the SBus burst transfer size if burst transfers are supported + */ + sc->sc_burst = getpropint(node, "burst-sizes", 0); + if (ra->ra_bp != NULL && strcmp(ra->ra_bp->name, "sbus") == 0) oca.ca_ra.ra_bp = ra->ra_bp + 1; else oca.ca_ra.ra_bp = NULL; + sc->sc_range = ra->ra_range; + sc->sc_nrange = ra->ra_nrange; + /* * Loop through ROM children, fixing any relative addresses * and then configuring each device. @@ -144,23 +160,60 @@ sbus_attach(parent, self, aux) name = getpropstring(node, "name"); if (!romprop(&oca.ca_ra, name, node)) continue; - base = (int)oca.ca_ra.ra_paddr; + + sbus_translate(self, &oca); + oca.ca_bustype = BUS_SBUS; + (void) config_found(&sc->sc_dev, (void *)&oca, sbus_print); + } +} + +void +sbus_translate(dev, ca) + struct device *dev; + struct confargs *ca; +{ + struct sbus_softc *sc = (struct sbus_softc *)dev; + register int base, slot; + register int i; + + if (sc->sc_nrange == 0) { + /* Old-style Sbus configuration */ + base = (int)ca->ca_ra.ra_paddr; if (SBUS_ABS(base)) { - oca.ca_slot = SBUS_ABS_TO_SLOT(base); - oca.ca_offset = SBUS_ABS_TO_OFFSET(base); + ca->ca_slot = SBUS_ABS_TO_SLOT(base); + ca->ca_offset = SBUS_ABS_TO_OFFSET(base); } else { - oca.ca_slot = slot = oca.ca_ra.ra_iospace; - oca.ca_offset = base; - oca.ca_ra.ra_paddr = (void *)SBUS_ADDR(slot, base); + ca->ca_slot = slot = ca->ca_ra.ra_iospace; + ca->ca_offset = base; + ca->ca_ra.ra_paddr = + (void *)SBUS_ADDR(slot, base); /* Fix any remaining register banks */ - for (i = 1; i < oca.ca_ra.ra_nreg; i++) { - base = (int)oca.ca_ra.ra_reg[i].rr_paddr; - oca.ca_ra.ra_reg[i].rr_paddr = + for (i = 1; i < ca->ca_ra.ra_nreg; i++) { + base = (int)ca->ca_ra.ra_reg[i].rr_paddr; + ca->ca_ra.ra_reg[i].rr_paddr = (void *)SBUS_ADDR(slot, base); } } - oca.ca_bustype = BUS_SBUS; - (void) config_found(&sc->sc_dev, (void *)&oca, sbus_print); + + } else { + + ca->ca_slot = ca->ca_ra.ra_iospace; + ca->ca_offset = (int)ca->ca_ra.ra_paddr; + + /* Translate into parent address spaces */ + for (i = 0; i < ca->ca_ra.ra_nreg; i++) { + int j, cspace = ca->ca_ra.ra_reg[i].rr_iospace; + + for (j = 0; j < sc->sc_nrange; j++) { + if (sc->sc_range[j].cspace == cspace) { + (int)ca->ca_ra.ra_reg[i].rr_paddr += + sc->sc_range[j].poffset; + (int)ca->ca_ra.ra_reg[i].rr_iospace = + sc->sc_range[j].pspace; + break; + } + } + } } } @@ -173,7 +226,25 @@ sbus_establish(sd, dev) register struct sbusdev *sd; register struct device *dev; { - register struct sbus_softc *sc = (struct sbus_softc *)dev->dv_parent; + register struct sbus_softc *sc; + register struct device *curdev; + + /* + * We have to look for the sbus by name, since it is not necessarily + * our immediate parent (i.e. sun4m /iommu/sbus/espdma/esp) + * We don't just use the device structure of the above-attached + * sbus, since we might (in the future) support multiple sbus's. + */ + for (curdev = dev->dv_parent; ; curdev = curdev->dv_parent) { + if (!curdev || !curdev->dv_xname) + panic("sbus_establish: can't find sbus parent for %s", + (sd->sd_dev->dv_xname ? sd->sd_dev->dv_xname : + "<unknown>")); + + if (strncmp(curdev->dv_xname, "sbus", 4) == 0) + break; + } + sc = (struct sbus_softc *) curdev; sd->sd_dev = dev; sd->sd_bchain = sc->sc_sbdev; @@ -188,7 +259,7 @@ sbusreset(sbus) int sbus; { register struct sbusdev *sd; - struct sbus_softc *sc = sbuscd.cd_devs[sbus]; + struct sbus_softc *sc = sbus_cd.cd_devs[sbus]; struct device *dev; printf("reset %s:", sc->sc_dev.dv_xname); @@ -200,24 +271,3 @@ sbusreset(sbus) } } } - -/* - * Returns true if this device is in a slave slot, so that drivers - * can bail rather than fail. - */ -int -sbus_slavecheck(self, ca) - struct device *self; - struct confargs *ca; -{ - int slave_only; - - slave_only = getpropint(findroot(), "slave-only", 8); - - if (slave_only & (1<<ca->ca_slot)) { - printf("%s: slave sbus slot -- not supported\n", - self->dv_xname); - return (1); - } - return (0); -} diff --git a/sys/arch/sparc/dev/sbusvar.h b/sys/arch/sparc/dev/sbusvar.h index 72badef900a..72fa1025523 100644 --- a/sys/arch/sparc/dev/sbusvar.h +++ b/sys/arch/sparc/dev/sbusvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: sbusvar.h,v 1.2 1994/11/20 20:52:27 deraadt Exp $ */ +/* $NetBSD: sbusvar.h,v 1.4 1996/04/22 02:35:05 abrown Exp $ */ /* * Copyright (c) 1992, 1993 @@ -67,8 +67,11 @@ struct sbus_softc { struct device sc_dev; /* base device */ int sc_clockfreq; /* clock frequency (in Hz) */ struct sbusdev *sc_sbdev; /* list of all children */ + struct rom_range *sc_range; + int sc_nrange; + int sc_burst; /* burst transfer sizes supported */ }; int sbusdev_match __P((struct cfdata *, void *)); void sbus_establish __P((struct sbusdev *, struct device *)); -int sbus_slavecheck __P((struct device *self, struct confargs *ca)); +void sbus_translate __P((struct device *, struct confargs *)); diff --git a/sys/arch/sparc/dev/si.c b/sys/arch/sparc/dev/si.c index ff0f4e400da..7908739ae4d 100644 --- a/sys/arch/sparc/dev/si.c +++ b/sys/arch/sparc/dev/si.c @@ -1,4 +1,4 @@ -/* $NetBSD: si.c,v 1.8 1996/01/01 22:40:56 thorpej Exp $ */ +/* $NetBSD: si.c,v 1.24 1996/05/13 01:53:45 thorpej Exp $ */ /* * Copyright (c) 1995 Jason R. Thorpe @@ -67,7 +67,8 @@ * for lots of helpful tips and suggestions. Thanks also to Paul Kranenburg * and Chris Torek for bits of insight needed along the way. Thanks to * David Gilbert and Andrew Gillham who risked filesystem life-and-limb - * for the sake of testing. + * for the sake of testing. Andrew Gillham helped work out the bugs + * the the 4/100 DMA code. */ /* @@ -116,6 +117,8 @@ #define DEBUG XXX #endif +#define COUNT_SW_LEFTOVERS XXX /* See sw DMA completion code */ + #include <dev/ic/ncr5380reg.h> #include <dev/ic/ncr5380var.h> @@ -135,10 +138,6 @@ */ #define MAX_DMA_LEN 0xE000 -#ifndef DEBUG -#define DEBUG XXX -#endif - #ifdef DEBUG int si_debug = 0; static int si_link_flags = 0 /* | SDEV_DB2 */ ; @@ -180,6 +179,11 @@ struct si_softc { * Alternatively, you can patch your kernel with DDB or some other * mechanism. The sc_options member of the softc is OR'd with * the value in si_options. + * + * On the "sw", interrupts (and thus) reselection don't work, so they're + * disabled by default. DMA is still a little dangerous, too. + * + * Note, there's a separate sw_options to make life easier. */ #define SI_ENABLE_DMA 0x01 /* Use DMA (maybe polled) */ #define SI_DMA_INTR 0x02 /* DMA completion interrupts */ @@ -187,6 +191,7 @@ struct si_softc { #define SI_OPTIONS_MASK (SI_ENABLE_DMA|SI_DMA_INTR|SI_DO_RESELECT) #define SI_OPTIONS_BITS "\10\3RESELECT\2DMA_INTR\1DMA" int si_options = SI_ENABLE_DMA; +int sw_options = SI_ENABLE_DMA; /* How long to wait for DMA before declaring an error. */ int si_dma_intr_timo = 500; /* ticks (sec. X 100) */ @@ -196,6 +201,7 @@ static void si_attach __P((struct device *, struct device *, void *)); static int si_intr __P((void *)); static void si_reset_adapter __P((struct ncr5380_softc *)); static void si_minphys __P((struct buf *)); +static int si_print __P((void *, char *)); void si_dma_alloc __P((struct ncr5380_softc *)); void si_dma_free __P((struct ncr5380_softc *)); @@ -235,15 +241,21 @@ static struct scsi_device si_dev = { /* The Sun SCSI-3 VME controller. */ -struct cfdriver sicd = { - NULL, "si", si_match, si_attach, - DV_DULL, sizeof(struct si_softc), NULL, 0, +struct cfattach si_ca = { + sizeof(struct si_softc), si_match, si_attach +}; + +struct cfdriver si_cd = { + NULL, "si", DV_DULL }; /* The Sun "SCSI Weird" 4/100 obio controller. */ -struct cfdriver swcd = { - NULL, "sw", si_match, si_attach, - DV_DULL, sizeof(struct si_softc), NULL, 0, +struct cfattach sw_ca = { + sizeof(struct si_softc), si_match, si_attach +}; + +struct cfdriver sw_cd = { + NULL, "sw", DV_DULL }; static int @@ -263,14 +275,14 @@ si_match(parent, vcf, args) { struct cfdata *cf = vcf; struct confargs *ca = args; - struct romaux *ra = &ca->ca_ra; + struct romaux *ra = &ca->ca_ra; /* Are we looking for the right thing? */ if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); /* Nothing but a Sun 4 is going to have these devices. */ - if (cputyp != CPU_SUN4) + if (!CPU_ISSUN4) return (0); /* @@ -283,13 +295,20 @@ si_match(parent, vcf, args) /* Figure out the bus type and look for the appropriate adapter. */ switch (ca->ca_bustype) { case BUS_VME16: + /* AFAIK, the `si' can only exist on the vmes. */ + if (strcmp(ra->ra_name, "si") || cpumod == SUN4_100) + return (0); break; case BUS_OBIO: /* AFAIK, an `sw' can only exist on the obio. */ - if (cpumod != SUN4_100) + if (strcmp(ra->ra_name, "sw") || cpumod != SUN4_100) return (0); break; + + default: + /* Don't know what we ended up with ... */ + return (0); } /* Make sure there is something there... */ @@ -323,17 +342,12 @@ si_attach(parent, self, args) int i; /* Pull in the options flags. */ - if (ca->ca_bustype == BUS_OBIO) { - /* - * XXX Interrupts and reselect don't work on the "sw". - * I don't know why (yet). Disable DMA by default, too. - * It's still a little dangerous. - */ - sc->sc_options = ncr_sc->sc_dev.dv_cfdata->cf_flags & - SI_OPTIONS_MASK; - } else - sc->sc_options = - ((ncr_sc->sc_dev.dv_cfdata->cf_flags | si_options) & SI_OPTIONS_MASK); + if (ca->ca_bustype == BUS_OBIO) + sc->sc_options = sw_options; + else + sc->sc_options = si_options; + sc->sc_options |= + (ncr_sc->sc_dev.dv_cfdata->cf_flags & SI_OPTIONS_MASK); /* Map the controller registers. */ regs = (struct si_regs *)mapiodev(ra->ra_reg, 0, @@ -392,6 +406,10 @@ si_attach(parent, self, args) ncr_sc->sc_intr_on = si_obio_intr_on; ncr_sc->sc_intr_off = si_obio_intr_off; break; + + default: + panic("\nsi_attach: impossible bus type 0x%x", ca->ca_bustype); + /* NOTREACHED */ } ncr_sc->sc_flags = 0; @@ -442,15 +460,19 @@ si_attach(parent, self, args) sc->sc_adapter_iv_am = VME_SUPV_DATA_24 | (ra->ra_intr[0].int_vec & 0xFF); break; + + default: + /* Impossible case handled above. */ + break; } printf(" pri %d\n", ra->ra_intr[0].int_pri); - if (sc->sc_options) + if (sc->sc_options) { printf("%s: options=%b\n", ncr_sc->sc_dev.dv_xname, - sc->sc_options, SI_OPTIONS_BITS); - + sc->sc_options, SI_OPTIONS_BITS); + } #ifdef DEBUG if (si_debug) - printf("si: Set TheSoftC=%x TheRegs=%x\n", sc, regs); + printf("si: Set TheSoftC=%p TheRegs=%p\n", sc, regs); ncr_sc->sc_link.flags |= si_link_flags; #endif @@ -679,7 +701,7 @@ found: dh->dh_dvma = (long)kdvma_mapin((caddr_t)addr, xlen, 0); if (dh->dh_dvma == 0) { /* Can't remap segment */ - printf("si_dma_alloc: can't remap %x/%x, doing PIO\n", + printf("si_dma_alloc: can't remap %p/%x, doing PIO\n", dh->dh_addr, dh->dh_maplen); dh->dh_flags = 0; return; @@ -733,7 +755,6 @@ si_dma_poll(ncr_sc) { struct si_softc *sc = (struct si_softc *)ncr_sc; struct sci_req *sr = ncr_sc->sc_current; - struct si_dma_handle *dh = sr->sr_dma_hand; volatile struct si_regs *si = sc->sc_regs; int tmo, csr_mask, csr; @@ -864,14 +885,14 @@ si_vme_dma_start(ncr_sc) */ data_pa = (u_long)(dh->dh_dvma - DVMA_BASE); if (data_pa & 1) - panic("si_dma_start: bad pa=0x%x", data_pa); + panic("si_dma_start: bad pa=0x%lx", data_pa); xlen = ncr_sc->sc_datalen; xlen &= ~1; sc->sc_xlen = xlen; /* XXX: or less... */ #ifdef DEBUG if (si_debug & 2) { - printf("si_dma_start: dh=0x%x, pa=0x%x, xlen=%d\n", + printf("si_dma_start: dh=%p, pa=0x%lx, xlen=%d\n", dh, data_pa, xlen); } #endif @@ -895,7 +916,7 @@ si_vme_dma_start(ncr_sc) } else { si->si_csr &= ~SI_CSR_BPCON; } - + si->dma_addrh = (u_short)(data_pa >> 16); si->dma_addrl = (u_short)(data_pa & 0xFFFF); @@ -997,12 +1018,15 @@ si_vme_dma_stop(ncr_sc) * * SCSI-3 VME interface is a little funny on writes: * if we have a disconnect, the dma has overshot by - * one byte and needs to be incremented. This is - * true if we have not transferred either all data - * or no data. XXX - from Matt Jacob + * one byte and the resid needs to be incremented. + * Only happens for partial transfers. + * (Thanks to Matt Jacob) */ resid = si->fifo_count & 0xFFFF; + if (dh->dh_flags & SIDH_OUT) + if ((resid > 0) && (resid < sc->sc_xlen)) + resid++; ntrans = sc->sc_xlen - resid; #ifdef DEBUG @@ -1162,14 +1186,14 @@ si_obio_dma_start(ncr_sc) */ data_pa = (u_long)(dh->dh_dvma - DVMA_BASE); if (data_pa & 1) - panic("si_dma_start: bad pa=0x%x", data_pa); + panic("si_dma_start: bad pa=0x%lx", data_pa); xlen = ncr_sc->sc_datalen; xlen &= ~1; sc->sc_xlen = xlen; /* XXX: or less... */ #ifdef DEBUG if (si_debug & 2) { - printf("si_dma_start: dh=0x%x, pa=0x%x, xlen=%d\n", + printf("si_dma_start: dh=%p, pa=0x%lx, xlen=%d\n", dh, data_pa, xlen); } #endif @@ -1260,6 +1284,19 @@ si_obio_dma_eop(ncr_sc) /* Not needed - DMA was stopped prior to examining sci_csr */ } +#if (defined(DEBUG) || defined(DIAGNOSTIC)) && !defined(COUNT_SW_LEFTOVERS) +#define COUNT_SW_LEFTOVERS +#endif +#ifdef COUNT_SW_LEFTOVERS +/* + * Let's find out how often these occur. Read these with DDB from time + * to time. + */ +int sw_3_leftover = 0; +int sw_2_leftover = 0; +int sw_1_leftover = 0; +int sw_0_leftover = 0; +#endif void si_obio_dma_stop(ncr_sc) @@ -1282,7 +1319,23 @@ si_obio_dma_stop(ncr_sc) /* First, halt the DMA engine. */ si->sw_csr &= ~SI_CSR_DMA_EN; + /* + * XXX HARDWARE BUG! + * Apparently, some early 4/100 SCSI controllers had a hardware + * bug that caused the controller to do illegal memory access. + * We see this as SI_CSR_DMA_BUS_ERR (makes sense). To work around + * this, we simply need to clean up after ourselves ... there will + * be as many as 3 bytes left over. Since we clean up "left-over" + * bytes on every read anyway, we just continue to chug along + * if SI_CSR_DMA_BUS_ERR is asserted. (This was probably worked + * around in hardware later with the "left-over byte" indicator + * in the VME controller.) + */ +#if 0 if (si->sw_csr & (SI_CSR_DMA_CONFLICT | SI_CSR_DMA_BUS_ERR)) { +#else + if (si->sw_csr & (SI_CSR_DMA_CONFLICT)) { +#endif printf("sw: DMA error, csr=0x%x, reset\n", si->sw_csr); sr->sr_xs->error = XS_DRIVER_STUFFUP; ncr_sc->sc_state |= NCR_ABORTING; @@ -1334,19 +1387,34 @@ si_obio_dma_stop(ncr_sc) switch (Dma_addr & 3) { case 3: - cp[-3] = (si->sw_bpr & 0xff000000) >> 24; - cp[-2] = (si->sw_bpr & 0x00ff0000) >> 16; - cp[-1] = (si->sw_bpr & 0x0000ff00) >> 8; + cp[0] = (si->sw_bpr & 0xff000000) >> 24; + cp[1] = (si->sw_bpr & 0x00ff0000) >> 16; + cp[2] = (si->sw_bpr & 0x0000ff00) >> 8; +#ifdef COUNT_SW_LEFTOVERS + ++sw_3_leftover; +#endif break; case 2: - cp[-2] = (si->sw_bpr & 0xff000000) >> 24; - cp[-1] = (si->sw_bpr & 0x00ff0000) >> 16; + cp[0] = (si->sw_bpr & 0xff000000) >> 24; + cp[1] = (si->sw_bpr & 0x00ff0000) >> 16; +#ifdef COUNT_SW_LEFTOVERS + ++sw_2_leftover; +#endif break; case 1: - cp[-1] = (si->sw_bpr & 0xff000000) >> 24; + cp[0] = (si->sw_bpr & 0xff000000) >> 24; +#ifdef COUNT_SW_LEFTOVERS + ++sw_1_leftover; +#endif + break; + +#ifdef COUNT_SW_LEFTOVERS + default: + ++sw_0_leftover; break; +#endif } } diff --git a/sys/arch/sparc/dev/xd.c b/sys/arch/sparc/dev/xd.c index b2fc2b6bfd7..dd5df1fa016 100644 --- a/sys/arch/sparc/dev/xd.c +++ b/sys/arch/sparc/dev/xd.c @@ -1,4 +1,4 @@ -/* $NetBSD: xd.c,v 1.11 1996/01/07 22:03:02 thorpej Exp $ */ +/* $NetBSD: xd.c,v 1.25 1996/04/22 02:42:06 christos Exp $ */ /* * @@ -36,7 +36,7 @@ * x d . c x y l o g i c s 7 5 3 / 7 0 5 3 v m e / s m d d r i v e r * * author: Chuck Cranor <chuck@ccrc.wustl.edu> - * id: $Id: xd.c,v 1.7 1996/03/04 20:35:23 chuck Exp $ + * id: $NetBSD: xd.c,v 1.25 1996/04/22 02:42:06 christos Exp $ * started: 27-Feb-95 * references: [1] Xylogics Model 753 User's Manual * part number: 166-753-001, Revision B, May 21, 1988. @@ -61,7 +61,6 @@ #include <sys/proc.h> #include <sys/systm.h> #include <sys/kernel.h> -#include <sys/conf.h> #include <sys/file.h> #include <sys/stat.h> #include <sys/ioctl.h> @@ -73,11 +72,14 @@ #include <sys/disk.h> #include <sys/syslog.h> #include <sys/dkbad.h> +#include <sys/conf.h> + #include <vm/vm.h> #include <vm/vm_kern.h> #include <machine/autoconf.h> #include <machine/sun_disklabel.h> +#include <machine/conf.h> #include <sparc/dev/xdreg.h> #include <sparc/dev/xdvar.h> @@ -215,25 +217,15 @@ inline void xdc_rqinit __P((struct xd_iorq *, struct xdc_softc *, struct xd_softc *, int, u_long, int, caddr_t, struct buf *)); void xdc_rqtopb __P((struct xd_iorq *, struct xd_iopb *, int, int)); -int xdc_start __P((struct xdc_softc *, int)); +void xdc_start __P((struct xdc_softc *, int)); int xdc_startbuf __P((struct xdc_softc *, struct xd_softc *, struct buf *)); int xdc_submit_iorq __P((struct xdc_softc *, int, int)); void xdc_tick __P((void *)); -int xdc_xdreset __P((struct xdc_softc *, struct xd_softc *)); +void xdc_xdreset __P((struct xdc_softc *, struct xd_softc *)); /* machine interrupt hook */ int xdcintr __P((void *)); -/* {b,c}devsw */ -int xdclose __P((dev_t, int, int)); -int xddump __P((dev_t)); -int xdioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); -int xdopen __P((dev_t, int, int)); -int xdread __P((dev_t, struct uio *)); -int xdwrite __P((dev_t, struct uio *)); -int xdsize __P((dev_t)); -void xdstrategy __P((struct buf *)); - /* autoconf */ int xdcmatch __P((struct device *, void *, void *)); void xdcattach __P((struct device *, struct device *, void *)); @@ -247,12 +239,21 @@ int xdgetdisklabel __P((struct xd_softc *, void *)); * cfdrivers: device driver interface to autoconfig */ -struct cfdriver xdccd = { - NULL, "xdc", xdcmatch, xdcattach, DV_DULL, sizeof(struct xdc_softc) +struct cfattach xdc_ca = { + sizeof(struct xdc_softc), xdcmatch, xdcattach +}; + + +struct cfdriver xdc_cd = { + NULL, "xdc", DV_DULL +}; + +struct cfattach xd_ca = { + sizeof(struct xd_softc), xdmatch, xdattach }; -struct cfdriver xdcd = { - NULL, "xd", xdmatch, xdattach, DV_DISK, sizeof(struct xd_softc) +struct cfdriver xd_cd = { + NULL, "xd", DV_DISK }; struct xdc_attach_args { /* this is the "aux" args to xdattach */ @@ -313,11 +314,11 @@ xdgetdisklabel(xd, b) if (sdl->sl_magic == SUN_DKMAGIC) xd->pcyl = sdl->sl_pcylinders; else { - printf("%s: WARNING: no `pcyl' in disk label.\n", + printf("%s: WARNING: no `pcyl' in disk label.\n", xd->sc_dev.dv_xname); xd->pcyl = xd->sc_dk.dk_label->d_ncylinders + xd->sc_dk.dk_label->d_acylinders; - printf("%s: WARNING: guessing pcyl=%d (ncyl+acyl)\n", + printf("%s: WARNING: guessing pcyl=%d (ncyl+acyl)\n", xd->sc_dev.dv_xname, xd->pcyl); } @@ -357,9 +358,9 @@ int xdcmatch(parent, match, aux) if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); - if (cputyp == CPU_SUN4) { + if (CPU_ISSUN4) { xdc = (struct xdc *) ra->ra_vaddr; - if (probeget(&xdc->xdc_csr, 1) == -1) + if (probeget((caddr_t) &xdc->xdc_csr, 1) == -1) return (0); xdc->xdc_csr = XDC_RESET; XDC_WAIT(xdc, del, XDC_RESETUSEC, XDC_RESET); @@ -372,7 +373,7 @@ int xdcmatch(parent, match, aux) /* * xdcattach: attach controller */ -void +void xdcattach(parent, self, aux) struct device *parent, *self; void *aux; @@ -400,7 +401,7 @@ xdcattach(parent, self, aux) xdc->sc_drives[lcv] = (struct xd_softc *) 0; /* allocate and zero buffers - * + * * note: we simplify the code by allocating the max number of iopbs and * iorq's up front. thus, we avoid linked lists and the costs * associated with them in exchange for wasting a little memory. */ @@ -511,13 +512,12 @@ xdcattach(parent, self, aux) * spin up and configure a disk after the system is booted (we can * call xdattach!). */ -int +int xdmatch(parent, match, aux) struct device *parent; void *match, *aux; { - struct xdc_softc *xdc = (void *) parent; struct cfdata *cf = match; struct xdc_attach_args *xa = aux; @@ -534,7 +534,7 @@ xdmatch(parent, match, aux) * xdattach: attach a disk. this can be called from autoconf and also * from xdopen/xdstrategy. */ -void +void xdattach(parent, self, aux) struct device *parent, *self; void *aux; @@ -543,7 +543,7 @@ xdattach(parent, self, aux) struct xd_softc *xd = (void *) self; struct xdc_softc *xdc = (void *) parent; struct xdc_attach_args *xa = aux; - int rqno, err, spt, mb, blk, lcv, fmode, s, newstate; + int rqno, err, spt = 0, mb, blk, lcv, fmode, s = 0, newstate; struct xd_iopb_drive *driopb; struct dkbad *dkb; struct bootpath *bp; @@ -717,9 +717,9 @@ xdattach(parent, self, aux) if (xa->booting) { /* restore bootpath! (do this via attach_args again?)*/ bp = bootpath_store(0, NULL); - if (bp && strcmp("xd", bp->name) == 0 && + if (bp && strcmp("xd", bp->name) == 0 && xd->xd_drive == bp->val[0]) - bootdv = &xd->sc_dev; + bp->dev = &xd->sc_dev; } dk_establish(&xd->sc_dk, &xd->sc_dev); /* XXX */ @@ -743,13 +743,13 @@ done: /* * xdclose: close device */ -int -xdclose(dev, flag, fmt) +int +xdclose(dev, flag, fmt, p) dev_t dev; int flag, fmt; - + struct proc *p; { - struct xd_softc *xd = xdcd.cd_devs[DISKUNIT(dev)]; + struct xd_softc *xd = xd_cd.cd_devs[DISKUNIT(dev)]; int part = DISKPART(dev); /* clear mask bits */ @@ -770,20 +770,22 @@ xdclose(dev, flag, fmt) /* * xddump: crash dump system */ -int -xddump(dev) - dev_t dev; - +int +xddump(dev, blkno, va, size) + dev_t dev; + daddr_t blkno; + caddr_t va; + size_t size; { int unit, part; struct xd_softc *xd; unit = DISKUNIT(dev); - if (unit >= xdcd.cd_ndevs) + if (unit >= xd_cd.cd_ndevs) return ENXIO; part = DISKPART(dev); - xd = xdcd.cd_devs[unit]; + xd = xd_cd.cd_devs[unit]; printf("%s%c: crash dump not supported (yet)\n", xd->sc_dev.dv_xname, 'a' + part); @@ -795,11 +797,11 @@ xddump(dev) * "dumpsize" == size of dump in clicks "physmem" == size of physical * memory (clicks, ctob() to get bytes) (normal case: dumpsize == * physmem) - * + * * dump a copy of physical memory to the dump device starting at sector * "dumplo" in the swap partition (make sure > 0). map in pages as * we go. use polled I/O. - * + * * XXX how to handle NON_CONTIG? */ } @@ -807,7 +809,7 @@ xddump(dev) /* * xdioctl: ioctls on XD drives. based on ioctl's of other netbsd disks. */ -int +int xdioctl(dev, command, addr, flag, p) dev_t dev; u_long command; @@ -822,7 +824,7 @@ xdioctl(dev, command, addr, flag, p) unit = DISKUNIT(dev); - if (unit >= xdcd.cd_ndevs || (xd = xdcd.cd_devs[unit]) == NULL) + if (unit >= xd_cd.cd_ndevs || (xd = xd_cd.cd_devs[unit]) == NULL) return (ENXIO); /* switch on ioctl type */ @@ -901,11 +903,11 @@ xdioctl(dev, command, addr, flag, p) * xdopen: open drive */ -int -xdopen(dev, flag, fmt) +int +xdopen(dev, flag, fmt, p) dev_t dev; int flag, fmt; - + struct proc *p; { int unit, part; struct xd_softc *xd; @@ -914,7 +916,7 @@ xdopen(dev, flag, fmt) /* first, could it be a valid target? */ unit = DISKUNIT(dev); - if (unit >= xdcd.cd_ndevs || (xd = xdcd.cd_devs[unit]) == NULL) + if (unit >= xd_cd.cd_ndevs || (xd = xd_cd.cd_devs[unit]) == NULL) return (ENXIO); part = DISKPART(dev); @@ -954,18 +956,20 @@ xdopen(dev, flag, fmt) } int -xdread(dev, uio) +xdread(dev, uio, flags) dev_t dev; struct uio *uio; + int flags; { return (physio(xdstrategy, NULL, dev, B_READ, minphys, uio)); } int -xdwrite(dev, uio) +xdwrite(dev, uio, flags) dev_t dev; struct uio *uio; + int flags; { return (physio(xdstrategy, NULL, dev, B_WRITE, minphys, uio)); @@ -976,28 +980,28 @@ xdwrite(dev, uio) * xdsize: return size of a partition for a dump */ -int +int xdsize(dev) dev_t dev; { struct xd_softc *xdsc; - int unit, part, size; + int part, size; /* valid unit? try an open */ - if (xdopen(dev, 0, S_IFBLK) != 0) + if (xdopen(dev, 0, S_IFBLK, NULL) != 0) return (-1); /* do it */ - xdsc = xdcd.cd_devs[DISKUNIT(dev)]; + xdsc = xd_cd.cd_devs[DISKUNIT(dev)]; part = DISKPART(dev); if (xdsc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) size = -1; /* only give valid size for swap partitions */ else size = xdsc->sc_dk.dk_label->d_partitions[part].p_size; - if (xdclose(dev, 0, S_IFBLK) != 0) + if (xdclose(dev, 0, S_IFBLK, NULL) != 0) return -1; return size; } @@ -1005,7 +1009,7 @@ xdsize(dev) * xdstrategy: buffering system interface to xd. */ -void +void xdstrategy(bp) struct buf *bp; @@ -1020,7 +1024,7 @@ xdstrategy(bp) /* check for live device */ - if (unit >= xdcd.cd_ndevs || (xd = xdcd.cd_devs[unit]) == 0 || + if (unit >= xd_cd.cd_ndevs || (xd = xd_cd.cd_devs[unit]) == 0 || bp->b_blkno < 0 || (bp->b_bcount % xd->sc_dk.dk_label->d_secsize) != 0) { bp->b_error = EINVAL; @@ -1062,7 +1066,7 @@ xdstrategy(bp) /* * now we know we have a valid buf structure that we need to do I/O * on. - * + * * note that we don't disksort because the controller has a sorting * algorithm built into the hardware. */ @@ -1115,14 +1119,12 @@ done: /* tells upper layers we are done with this * * xdcintr: hardware interrupt. */ -int +int xdcintr(v) void *v; { struct xdc_softc *xdcsc = v; - struct xd_softc *xd; - struct buf *bp; /* kick the event counter */ @@ -1156,7 +1158,7 @@ xdcintr(v) * xdc_rqinit: fill out the fields of an I/O request */ -inline void +inline void xdc_rqinit(rq, xdc, xd, md, blk, cnt, db, bp) struct xd_iorq *rq; struct xdc_softc *xdc; @@ -1181,7 +1183,7 @@ xdc_rqinit(rq, xdc, xd, md, blk, cnt, db, bp) * xdc_rqtopb: load up an IOPB based on an iorq */ -void +void xdc_rqtopb(iorq, iopb, cmd, subfun) struct xd_iorq *iorq; struct xd_iopb *iopb; @@ -1218,7 +1220,7 @@ xdc_rqtopb(iorq, iopb, cmd, subfun) XDPC_RBC | XDPC_ECC2; ctrl->throttle = XDC_THROTTLE; #ifdef sparc - if (cputyp == CPU_SUN4 && cpumod == SUN4_300) + if (CPU_ISSUN4 && cpumod == SUN4_300) ctrl->delay = XDC_DELAY_4_300; else ctrl->delay = XDC_DELAY_SPARC; @@ -1297,7 +1299,7 @@ xdc_rqtopb(iorq, iopb, cmd, subfun) * If you've already got an IORQ, you can call submit directly (currently * there is no need to do this). NORM requests are handled seperately. */ -int +int xdc_cmd(xdcsc, cmd, subfn, unit, block, scnt, dptr, fullmode) struct xdc_softc *xdcsc; int cmd, subfn, unit, block, scnt; @@ -1306,7 +1308,6 @@ xdc_cmd(xdcsc, cmd, subfn, unit, block, scnt, dptr, fullmode) { int rqno, submode = XD_STATE(fullmode), retry; - u_long dp; struct xd_iorq *iorq; struct xd_iopb *iopb; @@ -1364,7 +1365,7 @@ xdc_cmd(xdcsc, cmd, subfn, unit, block, scnt, dptr, fullmode) * start a buffer running, assumes nfree > 0 */ -int +int xdc_startbuf(xdcsc, xdsc, bp) struct xdc_softc *xdcsc; struct xd_softc *xdsc; @@ -1375,7 +1376,7 @@ xdc_startbuf(xdcsc, xdsc, bp) struct xd_iorq *iorq; struct xd_iopb *iopb; struct buf *wq; - u_long block, dp; + u_long block; caddr_t dbuf; if (!xdcsc->nfree) @@ -1409,7 +1410,7 @@ xdc_startbuf(xdcsc, xdsc, bp) /* * load request. we have to calculate the correct block number based * on partition info. - * + * * note that iorq points to the buffer as mapped into DVMA space, * where as the bp->b_data points to its non-DVMA mapping. */ @@ -1479,7 +1480,7 @@ xdc_startbuf(xdcsc, xdsc, bp) */ -int +int xdc_submit_iorq(xdcsc, iorqno, type) struct xdc_softc *xdcsc; int iorqno; @@ -1560,7 +1561,7 @@ xdc_submit_iorq(xdcsc, iorqno, type) * the caller is interesting in. if freeone is true, then it returns * when there is a free iorq. */ -int +int xdc_piodriver(xdcsc, iorqno, freeone) struct xdc_softc *xdcsc; char iorqno; @@ -1638,7 +1639,7 @@ xdc_piodriver(xdcsc, iorqno, freeone) * xdc_reset: reset one drive. NOTE: assumes xdc was just reset. * we steal iopb[0] for this, but we put it back when we are done. */ -int +void xdc_xdreset(xdcsc, xdsc) struct xdc_softc *xdcsc; struct xd_softc *xdsc; @@ -1672,14 +1673,14 @@ xdc_xdreset(xdcsc, xdsc) * xdc_reset: reset everything: requests are marked as errors except * a polled request (which is resubmitted) */ -int +int xdc_reset(xdcsc, quiet, blastmode, error, xdsc) struct xdc_softc *xdcsc; int quiet, blastmode, error; struct xd_softc *xdsc; { - int del = 0, lcv, poll = -1, retval = XD_ERR_AOK; + int del = 0, lcv, retval = XD_ERR_AOK; int oldfree = xdcsc->nfree; /* soft reset hardware */ @@ -1722,7 +1723,7 @@ xdc_reset(xdcsc, quiet, blastmode, error, xdsc) (vm_offset_t)iorq->buf->b_un.b_addr, iorq->buf->b_bcount); disk_unbusy(&xdcsc->reqs[lcv].xd->sc_dk, - (xdcsc->reqs[lcv].buf->b_bcount - + (xdcsc->reqs[lcv].buf->b_bcount - xdcsc->reqs[lcv].buf->b_resid)); biodone(iorq->buf); XDC_FREE(xdcsc, lcv); /* add to free list */ @@ -1770,7 +1771,7 @@ xdc_reset(xdcsc, quiet, blastmode, error, xdsc) * xdc_start: start all waiting buffers */ -int +void xdc_start(xdcsc, maxio) struct xdc_softc *xdcsc; int maxio; @@ -1790,14 +1791,13 @@ xdc_start(xdcsc, maxio) * xdc_remove_iorq: remove "done" IOPB's. */ -int +int xdc_remove_iorq(xdcsc) struct xdc_softc *xdcsc; { int errno, rqno, comm, errs; struct xdc *xdc = xdcsc->xdc; - u_long addr; struct xd_iopb *iopb; struct xd_iorq *iorq; struct buf *bp; @@ -1821,7 +1821,7 @@ xdc_remove_iorq(xdcsc) /* * get iopb that is done - * + * * hmm... I used to read the address of the done IOPB off the VME * registers and calculate the rqno directly from that. that worked * until I started putting a load on the controller. when loaded, i @@ -1889,7 +1889,7 @@ xdc_remove_iorq(xdcsc) * at the bad144 sector. to exit bad144 mode, we * must advance the pointers 1 sector and issue a new * request if there are still sectors left to process - * + * */ XDC_ADVANCE(iorq, 1); /* advance 1 sector */ @@ -1957,7 +1957,7 @@ xdc_remove_iorq(xdcsc) * is in lasterror. also, if iorq->errno == 0, then we recovered * from that error (otherwise iorq->errno == iorq->lasterror). */ -void +void xdc_perror(iorq, iopb, still_trying) struct xd_iorq *iorq; struct xd_iopb *iopb; @@ -1990,7 +1990,7 @@ xdc_perror(iorq, iopb, still_trying) * xdc_error: non-fatal error encountered... recover. * return AOK if resubmitted, return FAIL if this iopb is done */ -int +int xdc_error(xdcsc, iorq, iopb, rqno, comm) struct xdc_softc *xdcsc; struct xd_iorq *iorq; @@ -2062,7 +2062,7 @@ xdc_error(xdcsc, iorq, iopb, rqno, comm) /* * xdc_tick: make sure xd is still alive and ticking (err, kicking). */ -void +void xdc_tick(arg) void *arg; @@ -2070,7 +2070,7 @@ xdc_tick(arg) struct xdc_softc *xdcsc = arg; int lcv, s, reset = 0; #ifdef XDC_DIAG - int wait, run, free, done, whd; + int wait, run, free, done, whd = 0; u_char fqc[XDC_MAXIOPB], wqc[XDC_MAXIOPB], mark[XDC_MAXIOPB]; s = splbio(); wait = xdcsc->nwait; @@ -2100,7 +2100,7 @@ xdc_tick(arg) printf("\n"); for (lcv = 0; lcv < XDC_MAXIOPB; lcv++) { if (mark[lcv] == 0) - printf("MARK: running %d: mode %d done %d errs %d errno 0x%x ttl %d buf %x\n", + printf("MARK: running %d: mode %d done %d errs %d errno 0x%x ttl %d buf %p\n", lcv, xdcsc->reqs[lcv].mode, xdcsc->iopbase[lcv].done, xdcsc->iopbase[lcv].errs, @@ -2154,7 +2154,7 @@ xdc_tick(arg) * in user code, and is also useful for some debugging. we return * an error code. called at user priority. */ -int +int xdc_ioctlcmd(xd, dev, xio) struct xd_softc *xd; dev_t dev; @@ -2248,7 +2248,7 @@ xdc_ioctlcmd(xd, dev, xio) if (xio->dlen) { dvmabuf = dvma_malloc(xio->dlen, &buf, M_WAITOK); if (xio->cmd == XDCMD_WR || xio->cmd == XDCMD_XWR) { - if (err = copyin(xio->dptr, buf, xio->dlen)) { + if ((err = copyin(xio->dptr, buf, xio->dlen)) != 0) { dvma_free(dvmabuf, xio->dlen, &buf); return (err); } diff --git a/sys/arch/sparc/dev/xdreg.h b/sys/arch/sparc/dev/xdreg.h index addbe589534..c723d018d0d 100644 --- a/sys/arch/sparc/dev/xdreg.h +++ b/sys/arch/sparc/dev/xdreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: xdreg.h,v 1.1 1995/06/26 23:07:11 pk Exp $ */ +/* $NetBSD: xdreg.h,v 1.3 1996/03/31 22:38:54 pk Exp $ */ /* * @@ -203,9 +203,9 @@ struct xd_iopb { /* * some commands overload bytes 6 to 0x13 of the iopb with different meanings. - * these commands include: + * these commands include: * section 4.2: controller parameters - * section 4.3: drive parameters + * section 4.3: drive parameters * sectino 4.4: format parameters * * note that the commands that overload the iopb are not part of the @@ -287,7 +287,7 @@ struct xd_iopb_ctrl { #define XDC_DELAY_SPARC 0 /* - * drive parameters iopb: redefines bytes: 6, 8, 9, a, b, c, d, e + * drive parameters iopb: redefines bytes: 6, 8, 9, a, b, c, d, e */ struct xd_iopb_drive { @@ -311,7 +311,7 @@ struct xd_iopb_drive { }; /* - * format parameters iopb: redefines bytes: 6, 8, 9, a, b, c, d, 0x10, 0x11 + * format parameters iopb: redefines bytes: 6, 8, 9, a, b, c, d, 0x10, 0x11 */ struct xd_iopb_format { diff --git a/sys/arch/sparc/dev/xdvar.h b/sys/arch/sparc/dev/xdvar.h index 5417e3953ac..294f3a8c84b 100644 --- a/sys/arch/sparc/dev/xdvar.h +++ b/sys/arch/sparc/dev/xdvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: xdvar.h,v 1.2 1996/01/07 22:03:04 thorpej Exp $ */ +/* $NetBSD: xdvar.h,v 1.5 1996/03/31 22:38:56 pk Exp $ */ /* * @@ -32,9 +32,9 @@ */ /* - * x d v a r . h + * x d v a r . h * - * this file defines the software structure we use to control the + * this file defines the software structure we use to control the * 753/7053. * * author: Chuck Cranor <chuck@ccrc.wustl.edu> @@ -67,7 +67,7 @@ struct xd_iorq { #define XD_SUB_MASK 0xf0 /* mask bits for state */ #define XD_SUB_FREE 0x00 /* free */ #define XD_SUB_NORM 0x10 /* normal I/O request */ -#define XD_SUB_WAIT 0x20 /* normal I/O request in the +#define XD_SUB_WAIT 0x20 /* normal I/O request in the context of a process */ #define XD_SUB_POLL 0x30 /* polled mode */ #define XD_SUB_DONE 0x40 /* not active, but can't be free'd yet */ @@ -151,12 +151,12 @@ struct xdc_softc { struct buf sc_wq; /* queue'd IOPBs for this controller */ char freereq[XDC_MAXIOPB]; /* free list (stack) */ char waitq[XDC_MAXIOPB]; /* wait queue */ - char nfree; /* number of iopbs free */ - char nrun; /* number running */ - char nwait; /* number of waiting iopbs */ - char ndone; /* number of done IORQs */ - char waithead; /* head of queue */ - char waitend; /* end of queue */ + u_char nfree; /* number of iopbs free */ + u_char nrun; /* number running */ + u_char nwait; /* number of waiting iopbs */ + u_char ndone; /* number of done IORQs */ + u_char waithead; /* head of queue */ + u_char waitend; /* end of queue */ }; /* diff --git a/sys/arch/sparc/dev/xio.h b/sys/arch/sparc/dev/xio.h index e9e22859542..1ad5662b6be 100644 --- a/sys/arch/sparc/dev/xio.h +++ b/sys/arch/sparc/dev/xio.h @@ -1,4 +1,4 @@ -/* $NetBSD: xio.h,v 1.1 1995/06/26 23:07:26 pk Exp $ */ +/* $NetBSD: xio.h,v 1.2 1996/03/31 22:38:58 pk Exp $ */ /* * @@ -32,9 +32,9 @@ */ /* - * x i o . h + * x i o . h * - * this file defines the software structure we use to ioctl the + * this file defines the software structure we use to ioctl the * 753/7053. this interface isn't set in stone and may (or may not) * need adjustment. * diff --git a/sys/arch/sparc/dev/xy.c b/sys/arch/sparc/dev/xy.c index bd85ae48a25..2841bd9ba84 100644 --- a/sys/arch/sparc/dev/xy.c +++ b/sys/arch/sparc/dev/xy.c @@ -1,4 +1,4 @@ -/* $NetBSD: xy.c,v 1.3 1996/01/07 22:03:05 thorpej Exp $ */ +/* $NetBSD: xy.c,v 1.17 1996/04/22 02:42:04 christos Exp $ */ /* * @@ -36,7 +36,7 @@ * x y . c x y l o g i c s 4 5 0 / 4 5 1 s m d d r i v e r * * author: Chuck Cranor <chuck@ccrc.wustl.edu> - * id: $Id: xy.c,v 1.7 1996/03/04 20:35:25 chuck Exp $ + * id: $NetBSD: xy.c,v 1.17 1996/04/22 02:42:04 christos Exp $ * started: 14-Sep-95 * references: [1] Xylogics Model 753 User's Manual * part number: 166-753-001, Revision B, May 21, 1988. @@ -44,7 +44,7 @@ * [2] other NetBSD disk device drivers * [3] Xylogics Model 450 User's Manual * part number: 166-017-001, Revision B, 1983. - * [4] Addendum to Xylogics Model 450 Disk Controller User's + * [4] Addendum to Xylogics Model 450 Disk Controller User's * Manual, Jan. 1985. * [5] The 451 Controller, Rev. B3, September 2, 1986. * [6] David Jones <dej@achilles.net>'s unfinished 450/451 driver @@ -61,7 +61,6 @@ #include <sys/proc.h> #include <sys/systm.h> #include <sys/kernel.h> -#include <sys/conf.h> #include <sys/file.h> #include <sys/stat.h> #include <sys/ioctl.h> @@ -73,11 +72,14 @@ #include <sys/disk.h> #include <sys/syslog.h> #include <sys/dkbad.h> +#include <sys/conf.h> + #include <vm/vm.h> #include <vm/vm_kern.h> #include <machine/autoconf.h> #include <machine/sun_disklabel.h> +#include <machine/conf.h> #include <sparc/dev/xyreg.h> #include <sparc/dev/xyvar.h> @@ -151,32 +153,22 @@ int xyc_ioctlcmd __P((struct xy_softc *, dev_t dev, struct xd_iocmd *)); void xyc_perror __P((struct xy_iorq *, struct xy_iopb *, int)); int xyc_piodriver __P((struct xyc_softc *, struct xy_iorq *)); int xyc_remove_iorq __P((struct xyc_softc *)); -int xyc_reset __P((struct xyc_softc *, int, struct xy_iorq *, int, +int xyc_reset __P((struct xyc_softc *, int, struct xy_iorq *, int, struct xy_softc *)); inline void xyc_rqinit __P((struct xy_iorq *, struct xyc_softc *, struct xy_softc *, int, u_long, int, caddr_t, struct buf *)); void xyc_rqtopb __P((struct xy_iorq *, struct xy_iopb *, int, int)); -int xyc_start __P((struct xyc_softc *, struct xy_iorq *)); +void xyc_start __P((struct xyc_softc *, struct xy_iorq *)); int xyc_startbuf __P((struct xyc_softc *, struct xy_softc *, struct buf *)); int xyc_submit_iorq __P((struct xyc_softc *, struct xy_iorq *, int)); void xyc_tick __P((void *)); int xyc_unbusy __P((struct xyc *, int)); -int xyc_xyreset __P((struct xyc_softc *, struct xy_softc *)); +void xyc_xyreset __P((struct xyc_softc *, struct xy_softc *)); /* machine interrupt hook */ int xycintr __P((void *)); -/* {b,c}devsw */ -int xyclose __P((dev_t, int, int)); -int xydump __P((dev_t)); -int xyioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); -int xyopen __P((dev_t, int, int)); -int xyread __P((dev_t, struct uio *)); -int xywrite __P((dev_t, struct uio *)); -int xysize __P((dev_t)); -void xystrategy __P((struct buf *)); - /* autoconf */ int xycmatch __P((struct device *, void *, void *)); void xycattach __P((struct device *, struct device *, void *)); @@ -190,12 +182,20 @@ int xygetdisklabel __P((struct xy_softc *, void *)); * cfdrivers: device driver interface to autoconfig */ -struct cfdriver xyccd = { - NULL, "xyc", xycmatch, xycattach, DV_DULL, sizeof(struct xyc_softc) +struct cfattach xyc_ca = { + sizeof(struct xyc_softc), xycmatch, xycattach +}; + +struct cfdriver xyc_cd = { + NULL, "xyc", DV_DULL }; -struct cfdriver xycd = { - NULL, "xy", xymatch, xyattach, DV_DISK, sizeof(struct xy_softc) +struct cfattach xy_ca = { + sizeof(struct xy_softc), xymatch, xyattach +}; + +struct cfdriver xy_cd = { + NULL, "xy", DV_DISK }; struct xyc_attach_args { /* this is the "aux" args to xyattach */ @@ -256,11 +256,11 @@ xygetdisklabel(xy, b) if (sdl->sl_magic == SUN_DKMAGIC) xy->pcyl = sdl->sl_pcylinders; else { - printf("%s: WARNING: no `pcyl' in disk label.\n", - xy->sc_dev.dv_xname); + printf("%s: WARNING: no `pcyl' in disk label.\n", + xy->sc_dev.dv_xname); xy->pcyl = xy->sc_dk.dk_label->d_ncylinders + xy->sc_dk.dk_label->d_acylinders; - printf("%s: WARNING: guessing pcyl=%d (ncyl+acyl)\n", + printf("%s: WARNING: guessing pcyl=%d (ncyl+acyl)\n", xy->sc_dev.dv_xname, xy->pcyl); } @@ -295,14 +295,13 @@ int xycmatch(parent, match, aux) struct confargs *ca = aux; struct romaux *ra = &ca->ca_ra; struct xyc *xyc; - int del = 0; if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); - if (cputyp == CPU_SUN4) { + if (CPU_ISSUN4) { xyc = (struct xyc *) ra->ra_vaddr; - if (probeget(&xyc->xyc_rsetup, 1) == -1) + if (probeget((caddr_t) &xyc->xyc_rsetup, 1) == -1) return (0); if (xyc_unbusy(xyc, XYC_RESETUSEC) == XY_ERR_FAIL) return(0); @@ -313,7 +312,7 @@ int xycmatch(parent, match, aux) /* * xycattach: attach controller */ -void +void xycattach(parent, self, aux) struct device *parent, *self; void *aux; @@ -343,10 +342,10 @@ xycattach(parent, self, aux) for (lcv = 0; lcv < XYC_MAXDEV; lcv++) xyc->sc_drives[lcv] = (struct xy_softc *) 0; - /* + /* * allocate and zero buffers - * check boundaries of the KVA's ... all IOPBs must reside in - * the same 64K region. + * check boundaries of the KVA's ... all IOPBs must reside in + * the same 64K region. */ pbsz = XYC_MAXIOPB * sizeof(struct xy_iopb); @@ -359,7 +358,7 @@ xycattach(parent, self, aux) dvma_free(dtmp2, pbsz, &tmp2); ultmp = (u_long) dtmp; if ((ultmp & 0xffff0000) != ((ultmp + pbsz) & 0xffff0000)) { - printf("%s: can't alloc IOPB mem in 64K\n", + printf("%s: can't alloc IOPB mem in 64K\n", xyc->sc_dev.dv_xname); return; } @@ -374,9 +373,9 @@ xycattach(parent, self, aux) panic("xyc malloc"); bzero(xyc->reqs, XYC_MAXIOPB * sizeof(struct xy_iorq)); - /* + /* * init iorq to iopb pointers, and non-zero fields in the - * iopb which never change. + * iopb which never change. */ for (lcv = 0; lcv < XYC_MAXIOPB; lcv++) { @@ -414,8 +413,8 @@ xycattach(parent, self, aux) return; } if ((xyc->xyc->xyc_csr & XYC_ADRM) == 0) { - printf("%s: 24 bit addressing turned off\n", - xyc->sc_dev.dv_xname); + printf("%s: 24 bit addressing turned off\n", + xyc->sc_dev.dv_xname); printf("please set hardware jumpers JM1-JM2=in, JM3-JM4=out\n"); printf("to enable 24 bit mode and this driver\n"); return; @@ -458,13 +457,12 @@ xycattach(parent, self, aux) * spin up and configure a disk after the system is booted (we can * call xyattach!). */ -int +int xymatch(parent, match, aux) struct device *parent; void *match, *aux; { - struct xyc_softc *xyc = (void *) parent; struct cfdata *cf = match; struct xyc_attach_args *xa = aux; @@ -481,7 +479,7 @@ xymatch(parent, match, aux) * xyattach: attach a disk. this can be called from autoconf and also * from xyopen/xystrategy. */ -void +void xyattach(parent, self, aux) struct device *parent, *self; void *aux; @@ -490,7 +488,7 @@ xyattach(parent, self, aux) struct xy_softc *xy = (void *) self, *oxy; struct xyc_softc *xyc = (void *) parent; struct xyc_attach_args *xa = aux; - int res, err, spt, mb, blk, lcv, fmode, s, newstate; + int err, spt, mb, blk, lcv, fmode, s = 0, newstate; struct dkbad *dkb; struct bootpath *bp; @@ -565,13 +563,13 @@ xyattach(parent, self, aux) xy->nsect = 1; xy->sectpercyl = 1; for (lcv = 0; lcv < 126; lcv++) /* init empty bad144 table */ - xy->dkb.bt_bad[lcv].bt_cyl = + xy->dkb.bt_bad[lcv].bt_cyl = xy->dkb.bt_bad[lcv].bt_trksec = 0xffff; /* read disk label */ - for (xy->drive_type = 0 ; xy->drive_type <= XYC_MAXDT ; + for (xy->drive_type = 0 ; xy->drive_type <= XYC_MAXDT ; xy->drive_type++) { - err = xyc_cmd(xyc, XYCMD_RD, 0, xy->xy_drive, 0, 1, + err = xyc_cmd(xyc, XYCMD_RD, 0, xy->xy_drive, 0, 1, xa->dvmabuf, fmode); XYC_DONE(xyc, err); if (err == XY_ERR_AOK) break; @@ -605,9 +603,9 @@ xyattach(parent, self, aux) * 450/451 stupidity: the drive type is encoded into the format * of the disk. the drive type in the IOPB must match the drive * type in the format, or you will not be able to do I/O to the - * disk (you get header not found errors). if you have two drives - * of different sizes that have the same drive type in their - * formatting then you are out of luck. + * disk (you get header not found errors). if you have two drives + * of different sizes that have the same drive type in their + * formatting then you are out of luck. * * this problem was corrected in the 753/7053. */ @@ -624,7 +622,7 @@ xyattach(parent, self, aux) panic("xy drive size mismatch"); } } - + /* now set the real drive parameters! */ @@ -645,10 +643,10 @@ xyattach(parent, self, aux) * last track of the disk (i.e. second cyl of "acyl" area). */ - blk = (xy->ncyl + xy->acyl - 1) * (xy->nhead * xy->nsect) + + blk = (xy->ncyl + xy->acyl - 1) * (xy->nhead * xy->nsect) + /* last cyl */ (xy->nhead - 1) * xy->nsect; /* last head */ - err = xyc_cmd(xyc, XYCMD_RD, 0, xy->xy_drive, blk, 1, + err = xyc_cmd(xyc, XYCMD_RD, 0, xy->xy_drive, blk, 1, xa->dvmabuf, fmode); XYC_DONE(xyc, err); if (err) { @@ -681,9 +679,9 @@ xyattach(parent, self, aux) if (xa->booting) { /* restore bootpath! (do this via attach_args again?)*/ bp = bootpath_store(0, NULL); - if (bp && strcmp("xy", bp->name) == 0 && - xy->xy_drive == bp->val[0]) - bootdv = &xy->sc_dev; + if (bp && strcmp("xy", bp->name) == 0 && + xy->xy_drive == bp->val[0]) + bp->dev = &xy->sc_dev; } dk_establish(&xy->sc_dk, &xy->sc_dev); /* XXX */ @@ -707,13 +705,14 @@ done: /* * xyclose: close device */ -int -xyclose(dev, flag, fmt) +int +xyclose(dev, flag, fmt, p) dev_t dev; int flag, fmt; + struct proc *p; { - struct xy_softc *xy = xycd.cd_devs[DISKUNIT(dev)]; + struct xy_softc *xy = xy_cd.cd_devs[DISKUNIT(dev)]; int part = DISKPART(dev); /* clear mask bits */ @@ -734,20 +733,22 @@ xyclose(dev, flag, fmt) /* * xydump: crash dump system */ -int -xydump(dev) - dev_t dev; - +int +xydump(dev, blkno, va, size) + dev_t dev; + daddr_t blkno; + caddr_t va; + size_t size; { int unit, part; struct xy_softc *xy; unit = DISKUNIT(dev); - if (unit >= xycd.cd_ndevs) + if (unit >= xy_cd.cd_ndevs) return ENXIO; part = DISKPART(dev); - xy = xycd.cd_devs[unit]; + xy = xy_cd.cd_devs[unit]; printf("%s%c: crash dump not supported (yet)\n", xy->sc_dev.dv_xname, 'a' + part); @@ -759,11 +760,11 @@ xydump(dev) * "dumpsize" == size of dump in clicks "physmem" == size of physical * memory (clicks, ctob() to get bytes) (normal case: dumpsize == * physmem) - * + * * dump a copy of physical memory to the dump device starting at sector * "dumplo" in the swap partition (make sure > 0). map in pages as * we go. use polled I/O. - * + * * XXX how to handle NON_CONTIG? */ } @@ -771,7 +772,7 @@ xydump(dev) /* * xyioctl: ioctls on XY drives. based on ioctl's of other netbsd disks. */ -int +int xyioctl(dev, command, addr, flag, p) dev_t dev; u_long command; @@ -786,7 +787,7 @@ xyioctl(dev, command, addr, flag, p) unit = DISKUNIT(dev); - if (unit >= xycd.cd_ndevs || (xy = xycd.cd_devs[unit]) == NULL) + if (unit >= xy_cd.cd_ndevs || (xy = xy_cd.cd_devs[unit]) == NULL) return (ENXIO); /* switch on ioctl type */ @@ -866,11 +867,11 @@ xyioctl(dev, command, addr, flag, p) * xyopen: open drive */ -int -xyopen(dev, flag, fmt) +int +xyopen(dev, flag, fmt, p) dev_t dev; int flag, fmt; - + struct proc *p; { int unit, part; struct xy_softc *xy; @@ -879,7 +880,7 @@ xyopen(dev, flag, fmt) /* first, could it be a valid target? */ unit = DISKUNIT(dev); - if (unit >= xycd.cd_ndevs || (xy = xycd.cd_devs[unit]) == NULL) + if (unit >= xy_cd.cd_ndevs || (xy = xy_cd.cd_devs[unit]) == NULL) return (ENXIO); part = DISKPART(dev); @@ -890,7 +891,7 @@ xyopen(dev, flag, fmt) xa.dvmabuf = (char *)dvma_malloc(XYFM_BPS, &xa.buf, M_NOWAIT); xa.fullmode = XY_SUB_WAIT; xa.booting = 0; - xyattach((struct device *) xy->parent, + xyattach((struct device *) xy->parent, (struct device *) xy, &xa); dvma_free(xa.dvmabuf, XYFM_BPS, &xa.buf); if (xy->state == XY_DRIVE_UNKNOWN) { @@ -920,18 +921,20 @@ xyopen(dev, flag, fmt) } int -xyread(dev, uio) +xyread(dev, uio, flags) dev_t dev; struct uio *uio; + int flags; { return (physio(xystrategy, NULL, dev, B_READ, minphys, uio)); } int -xywrite(dev, uio) +xywrite(dev, uio, flags) dev_t dev; struct uio *uio; + int flags; { return (physio(xystrategy, NULL, dev, B_WRITE, minphys, uio)); @@ -942,28 +945,28 @@ xywrite(dev, uio) * xysize: return size of a partition for a dump */ -int +int xysize(dev) dev_t dev; { struct xy_softc *xysc; - int unit, part, size; + int part, size; /* valid unit? try an open */ - if (xyopen(dev, 0, S_IFBLK) != 0) + if (xyopen(dev, 0, S_IFBLK, NULL) != 0) return (-1); /* do it */ - xysc = xycd.cd_devs[DISKUNIT(dev)]; + xysc = xy_cd.cd_devs[DISKUNIT(dev)]; part = DISKPART(dev); if (xysc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP) size = -1; /* only give valid size for swap partitions */ else size = xysc->sc_dk.dk_label->d_partitions[part].p_size; - if (xyclose(dev, 0, S_IFBLK) != 0) + if (xyclose(dev, 0, S_IFBLK, NULL) != 0) return -1; return size; } @@ -972,14 +975,12 @@ xysize(dev) * xystrategy: buffering system interface to xy. */ -void +void xystrategy(bp) struct buf *bp; { struct xy_softc *xy; - struct xyc_softc *parent; - struct buf *wq; int s, unit; struct xyc_attach_args xa; @@ -987,7 +988,7 @@ xystrategy(bp) /* check for live device */ - if (unit >= xycd.cd_ndevs || (xy = xycd.cd_devs[unit]) == 0 || + if (unit >= xy_cd.cd_ndevs || (xy = xy_cd.cd_devs[unit]) == 0 || bp->b_blkno < 0 || (bp->b_bcount % xy->sc_dk.dk_label->d_secsize) != 0) { bp->b_error = EINVAL; @@ -1059,14 +1060,12 @@ done: /* tells upper layers we are done with this * * xycintr: hardware interrupt. */ -int +int xycintr(v) void *v; { struct xyc_softc *xycsc = v; - struct xy_softc *xy; - struct buf *bp; /* kick the event counter */ @@ -1094,7 +1093,7 @@ xycintr(v) * xyc_rqinit: fill out the fields of an I/O request */ -inline void +inline void xyc_rqinit(rq, xyc, xy, md, blk, cnt, db, bp) struct xy_iorq *rq; struct xyc_softc *xyc; @@ -1120,7 +1119,7 @@ xyc_rqinit(rq, xyc, xy, md, blk, cnt, db, bp) * xyc_rqtopb: load up an IOPB based on an iorq */ -void +void xyc_rqtopb(iorq, iopb, cmd, subfun) struct xy_iorq *iorq; struct xy_iopb *iopb; @@ -1190,7 +1189,7 @@ int del; * xyc_cmd: front end for POLL'd and WAIT'd commands. Returns 0 or error. * note that NORM requests are handled seperately. */ -int +int xyc_cmd(xycsc, cmd, subfn, unit, block, scnt, dptr, fullmode) struct xyc_softc *xycsc; int cmd, subfn, unit, block, scnt; @@ -1198,8 +1197,7 @@ xyc_cmd(xycsc, cmd, subfn, unit, block, scnt, dptr, fullmode) int fullmode; { - int submode = XY_STATE(fullmode), retry; - u_long dp; + int submode = XY_STATE(fullmode); struct xy_iorq *iorq = xycsc->ciorq; struct xy_iopb *iopb = xycsc->ciopb; @@ -1208,7 +1206,7 @@ xyc_cmd(xycsc, cmd, subfn, unit, block, scnt, dptr, fullmode) */ start: if (submode == XY_SUB_WAIT && XY_STATE(iorq->mode) != XY_SUB_FREE) { - if (tsleep(iorq, PRIBIO, "xyc_cmd", 0)) + if (tsleep(iorq, PRIBIO, "xyc_cmd", 0)) return(XY_ERR_FAIL); goto start; } @@ -1241,7 +1239,7 @@ start: * start a buffer for running */ -int +int xyc_startbuf(xycsc, xysc, bp) struct xyc_softc *xycsc; struct xy_softc *xysc; @@ -1251,7 +1249,7 @@ xyc_startbuf(xycsc, xysc, bp) int partno; struct xy_iorq *iorq; struct xy_iopb *iopb; - u_long block, dp; + u_long block; caddr_t dbuf; iorq = xysc->xyrq; @@ -1259,7 +1257,7 @@ xyc_startbuf(xycsc, xysc, bp) /* get buf */ - if (bp == NULL) + if (bp == NULL) panic("xyc_startbuf null buf"); partno = DISKPART(bp->b_dev); @@ -1273,7 +1271,7 @@ xyc_startbuf(xycsc, xysc, bp) /* * load request. we have to calculate the correct block number based * on partition info. - * + * * note that iorq points to the buffer as mapped into DVMA space, * where as the bp->b_data points to its non-DVMA mapping. */ @@ -1283,7 +1281,7 @@ xyc_startbuf(xycsc, xysc, bp) dbuf = kdvma_mapin(bp->b_data, bp->b_bcount, 0); if (dbuf == NULL) { /* out of DVMA space */ - printf("%s: warning: out of DVMA space\n", + printf("%s: warning: out of DVMA space\n", xycsc->sc_dev.dv_xname); return (XY_ERR_FAIL); /* XXX: need some sort of * call-back scheme here? */ @@ -1327,9 +1325,9 @@ xyc_startbuf(xycsc, xysc, bp) * time, where as a 451 can take them in chains. [the 450 claims it * can handle chains, but is appears to be buggy...] iopb are allocated * in DVMA space at boot up time. each disk gets one iopb, and the - * controller gets one (for POLL and WAIT commands). what happens if - * the iopb is busy? for i/o type [1], the buffers are queued at the - * "buff" layer and * picked up later by the interrupt routine. for case + * controller gets one (for POLL and WAIT commands). what happens if + * the iopb is busy? for i/o type [1], the buffers are queued at the + * "buff" layer and * picked up later by the interrupt routine. for case * [2] we can only be blocked if there is a WAIT type I/O request being * run. since this can only happen when we are crashing, we wait a sec * and then steal the IOPB. for case [3] the process can sleep @@ -1337,7 +1335,7 @@ xyc_startbuf(xycsc, xysc, bp) */ -int +int xyc_submit_iorq(xycsc, iorq, type) struct xyc_softc *xycsc; struct xy_iorq *iorq; @@ -1348,7 +1346,7 @@ xyc_submit_iorq(xycsc, iorq, type) u_long iopbaddr; #ifdef XYC_DEBUG - printf("xyc_submit_iorq(%s, addr=0x%x, type=%d)\n", + printf("xyc_submit_iorq(%s, addr=0x%x, type=%d)\n", xycsc->sc_dev.dv_xname, iorq, type); #endif @@ -1381,12 +1379,12 @@ xyc_submit_iorq(xycsc, iorq, type) iopb = xyc_chain(xycsc, iorq); /* build chain */ if (iopb == NULL) { /* nothing doing? */ - if (type == XY_SUB_NORM || type == XY_SUB_NOQ) + if (type == XY_SUB_NORM || type == XY_SUB_NOQ) return(XY_ERR_AOK); panic("xyc_submit_iorq: xyc_chain failed!\n"); } iopbaddr = (u_long) iopb - DVMA_BASE; - + XYC_GO(xycsc->xyc, iopbaddr); /* command now running, wrap it up */ @@ -1434,11 +1432,11 @@ struct xy_iorq *iorq; xycsc->iopbase[XYC_CTLIOPB].done == 0) iorq = &xycsc->reqs[XYC_CTLIOPB]; } - /* + /* * special case: if iorq != NULL then we have a POLL or WAIT request. * we let these take priority and do them first. */ - if (iorq) { + if (iorq) { xycsc->xy_chain[0] = iorq; iorq->iopb->chen = 0; return(iorq->iopb); @@ -1479,9 +1477,9 @@ struct xy_iorq *iorq; * * programmed i/o driver. this function takes over the computer * and drains off the polled i/o request. it returns the status of the iorq - * the caller is interesting in. + * the caller is interesting in. */ -int +int xyc_piodriver(xycsc, iorq) struct xyc_softc *xycsc; struct xy_iorq *iorq; @@ -1490,7 +1488,6 @@ xyc_piodriver(xycsc, iorq) int nreset = 0; int retval = 0; u_long res; - struct xyc *xyc = xycsc->xyc; #ifdef XYC_DEBUG printf("xyc_piodriver(%s, 0x%x)\n", xycsc->sc_dev.dv_xname, iorq); #endif @@ -1534,7 +1531,7 @@ xyc_piodriver(xycsc, iorq) /* start up any bufs that have queued */ - xyc_start(xycsc, NULL); + xyc_start(xycsc, NULL); return (retval); } @@ -1543,7 +1540,7 @@ xyc_piodriver(xycsc, iorq) * xyc_xyreset: reset one drive. NOTE: assumes xyc was just reset. * we steal iopb[XYC_CTLIOPB] for this, but we put it back when we are done. */ -int +void xyc_xyreset(xycsc, xysc) struct xyc_softc *xycsc; struct xy_softc *xysc; @@ -1558,7 +1555,7 @@ xyc_xyreset(xycsc, xysc) xycsc->ciopb->com = XYCMD_RST; xycsc->ciopb->unit = xysc->xy_drive; addr = (u_long) xycsc->ciopb - DVMA_BASE; - + XYC_GO(xycsc->xyc, addr); del = XYC_RESETUSEC; @@ -1585,7 +1582,7 @@ xyc_xyreset(xycsc, xysc) * xyc_reset: reset everything: requests are marked as errors except * a polled request (which is resubmitted) */ -int +int xyc_reset(xycsc, quiet, blastmode, error, xysc) struct xyc_softc *xycsc; int quiet, error; @@ -1593,7 +1590,7 @@ xyc_reset(xycsc, quiet, blastmode, error, xysc) struct xy_softc *xysc; { - int del = 0, lcv, poll = -1, retval = XY_ERR_AOK; + int del = 0, lcv, retval = XY_ERR_AOK; /* soft reset hardware */ @@ -1619,7 +1616,7 @@ xyc_reset(xycsc, quiet, blastmode, error, xysc) /* is it active? */ continue; - if (blastmode == XY_RSET_ALL || + if (blastmode == XY_RSET_ALL || blastmode != iorq) { /* failed */ iorq->errno = error; @@ -1666,7 +1663,7 @@ xyc_reset(xycsc, quiet, blastmode, error, xysc) * xyc_start: start waiting buffers */ -int +void xyc_start(xycsc, iorq) struct xyc_softc *xycsc; struct xy_iorq *iorq; @@ -1687,10 +1684,10 @@ xyc_start(xycsc, iorq) } /* - * xyc_remove_iorq: remove "done" IOPB's. + * xyc_remove_iorq: remove "done" IOPB's. */ -int +int xyc_remove_iorq(xycsc) struct xyc_softc *xycsc; @@ -1770,7 +1767,7 @@ xyc_remove_iorq(xycsc) * at the bad144 sector. to exit bad144 mode, we * must advance the pointers 1 sector and issue a new * request if there are still sectors left to process - * + * */ XYC_ADVANCE(iorq, 1); /* advance 1 sector */ @@ -1838,7 +1835,7 @@ xyc_remove_iorq(xycsc) * is in lasterror. also, if iorq->errno == 0, then we recovered * from that error (otherwise iorq->errno == iorq->lasterror). */ -void +void xyc_perror(iorq, iopb, still_trying) struct xy_iorq *iorq; struct xy_iopb *iopb; @@ -1871,7 +1868,7 @@ xyc_perror(iorq, iopb, still_trying) * xyc_error: non-fatal error encountered... recover. * return AOK if resubmitted, return FAIL if this iopb is done */ -int +int xyc_error(xycsc, iorq, iopb, comm) struct xyc_softc *xycsc; struct xy_iorq *iorq; @@ -1939,7 +1936,7 @@ xyc_error(xycsc, iorq, iopb, comm) /* * xyc_tick: make sure xy is still alive and ticking (err, kicking). */ -void +void xyc_tick(arg) void *arg; @@ -1976,14 +1973,14 @@ xyc_tick(arg) * * XXX missing a few commands (see the 7053 driver for ideas) */ -int +int xyc_ioctlcmd(xy, dev, xio) struct xy_softc *xy; dev_t dev; struct xd_iocmd *xio; { - int s, err, rqno, dummy; + int s, err, rqno, dummy = 0; caddr_t dvmabuf = NULL, buf = NULL; struct xyc_softc *xycsc; @@ -2018,7 +2015,7 @@ xyc_ioctlcmd(xy, dev, xio) if (xio->dlen) { dvmabuf = dvma_malloc(xio->dlen, &buf, M_WAITOK); if (xio->cmd == XYCMD_WR) { - if (err = copyin(xio->dptr, buf, xio->dlen)) { + if ((err = copyin(xio->dptr, buf, xio->dlen)) != 0) { dvma_free(dvmabuf, xio->dlen, &buf); return (err); } @@ -2147,7 +2144,7 @@ int errno; return(XY_ERA_SOFT); /* an FYI error */ - case XY_ERR_WPRO: + case XY_ERR_WPRO: return(XY_ERA_WPRO); /* write protect */ } diff --git a/sys/arch/sparc/dev/xyreg.h b/sys/arch/sparc/dev/xyreg.h index 757e73cfd9c..2508bb97a8e 100644 --- a/sys/arch/sparc/dev/xyreg.h +++ b/sys/arch/sparc/dev/xyreg.h @@ -1,4 +1,4 @@ -/* $NetBSD: xyreg.h,v 1.1 1995/09/25 20:35:15 chuck Exp $ */ +/* $NetBSD: xyreg.h,v 1.3 1996/03/31 22:39:02 pk Exp $ */ /* * @@ -90,9 +90,9 @@ struct xyc { * add iopb to the chain, and clear AREQ to resume I/O * * when the controller is done with a command it may interrupt (if you - * ask it to) and it will set the XYC_IPND bit in the csr. clear + * ask it to) and it will set the XYC_IPND bit in the csr. clear * the interrupt by writing one to this bit. - * + * * the format of the iopb is described in section 2.4 of the manual. * note that it is byte-swapped on the sun. */ diff --git a/sys/arch/sparc/dev/xyvar.h b/sys/arch/sparc/dev/xyvar.h index 5296d9fa202..e7ec8305980 100644 --- a/sys/arch/sparc/dev/xyvar.h +++ b/sys/arch/sparc/dev/xyvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: xyvar.h,v 1.2 1996/01/07 22:03:06 thorpej Exp $ */ +/* $NetBSD: xyvar.h,v 1.4 1996/03/31 22:39:04 pk Exp $ */ /* * @@ -32,9 +32,9 @@ */ /* - * x y v a r . h + * x y v a r . h * - * this file defines the software structure we use to control the + * this file defines the software structure we use to control the * 450/451. * * author: Chuck Cranor <chuck@ccrc.wustl.edu> @@ -67,7 +67,7 @@ struct xy_iorq { #define XY_SUB_MASK 0xf0 /* mask bits for state */ #define XY_SUB_FREE 0x00 /* free */ #define XY_SUB_NORM 0x10 /* normal I/O request */ -#define XY_SUB_WAIT 0x20 /* normal I/O request in the +#define XY_SUB_WAIT 0x20 /* normal I/O request in the context of a process */ #define XY_SUB_POLL 0x30 /* polled mode */ #define XY_SUB_DONE 0x40 /* not active, but can't be free'd yet */ diff --git a/sys/arch/sparc/dev/zs.c b/sys/arch/sparc/dev/zs.c index c37e8f97041..ee99cb25b5a 100644 --- a/sys/arch/sparc/dev/zs.c +++ b/sys/arch/sparc/dev/zs.c @@ -1,4 +1,4 @@ -/* $NetBSD: zs.c,v 1.28 1995/04/21 15:51:26 pk Exp $ */ +/* $NetBSD: zs.c,v 1.37.4.1 1996/06/02 09:07:55 mrg Exp $ */ /* * Copyright (c) 1992, 1993 @@ -48,17 +48,14 @@ * Zilog Z8530 (ZSCC) driver. * * Runs two tty ports (ttya and ttyb) on zs0, - * and runs a keyboard and mouse on zs1, and - * possibly two more tty ports (ttyc and ttyd) on zs2. + * and runs a keyboard and mouse on zs1. * * This driver knows far too much about chip to usage mappings. */ -#include "zs.h" - #include <sys/param.h> +#include <sys/systm.h> #include <sys/proc.h> #include <sys/device.h> -#include <sys/conf.h> #include <sys/file.h> #include <sys/ioctl.h> #include <sys/malloc.h> @@ -66,22 +63,26 @@ #include <sys/time.h> #include <sys/kernel.h> #include <sys/syslog.h> +#include <sys/conf.h> #include <machine/autoconf.h> +#include <machine/conf.h> #include <machine/cpu.h> #include <sparc/sparc/vaddrs.h> #include <sparc/sparc/auxreg.h> + #include <machine/kbd.h> #include <dev/ic/z8530reg.h> + #include <sparc/dev/zsvar.h> #ifdef KGDB #include <machine/remote-sl.h> #endif -#define ZSMAJOR 12 /* XXX */ +#define ZSMAJOR 12 /* XXX */ #define ZS_KBD 2 /* XXX */ #define ZS_MOUSE 3 /* XXX */ @@ -103,20 +104,25 @@ #endif /* - * Software state per found chip. + * Software state per found chip. This would be called `zs_softc', + * but the previous driver had a rather different zs_softc.... */ -struct zs_softc { - struct device sc_dev; /* base device */ - volatile struct zsdevice *sc_zs; /* chip registers */ - struct evcnt sc_intrcnt; - struct zs_chanstate sc_cs[2]; /* chan A/B software state */ +struct zsinfo { + struct device zi_dev; /* base device */ + volatile struct zsdevice *zi_zs;/* chip registers */ + struct zs_chanstate zi_cs[2]; /* channel A and B software state */ }; /* Definition of the driver for autoconfig. */ static int zsmatch __P((struct device *, void *, void *)); static void zsattach __P((struct device *, struct device *, void *)); -struct cfdriver zscd = { - NULL, "zs", zsmatch, zsattach, DV_TTY, sizeof(struct zs_softc) + +struct cfattach zs_ca = { + sizeof(struct zsinfo), zsmatch, zsattach +}; + +struct cfdriver zs_cd = { + NULL, "zs", DV_TTY }; /* Interrupt handlers. */ @@ -131,31 +137,41 @@ struct zs_chanstate *zslist; static void zsiopen __P((struct tty *)); static void zsiclose __P((struct tty *)); static void zsstart __P((struct tty *)); -void zsstop __P((struct tty *, int)); static int zsparam __P((struct tty *, struct termios *)); /* Routines purely local to this driver. */ static int zs_getspeed __P((volatile struct zschan *)); +#ifdef KGDB static void zs_reset __P((volatile struct zschan *, int, int)); +#endif static void zs_modem __P((struct zs_chanstate *, int)); static void zs_loadchannelregs __P((volatile struct zschan *, u_char *)); /* Console stuff. */ static struct tty *zs_ctty; /* console `struct tty *' */ static int zs_consin = -1, zs_consout = -1; -static int zscnputc __P((int)); /* console putc function */ +static void zscnputc __P((int)); /* console putc function */ static volatile struct zschan *zs_conschan; -static struct tty *zs_checkcons __P((struct zs_softc *, int, - struct zs_chanstate *)); +static struct tty *zs_checkcons __P((struct zsinfo *, int, struct zs_chanstate *)); #ifdef KGDB /* KGDB stuff. Must reboot to change zs_kgdbunit. */ extern int kgdb_dev, kgdb_rate; static int zs_kgdb_savedspeed; static void zs_checkkgdb __P((int, struct zs_chanstate *, struct tty *)); +void zskgdb __P((int)); +static int zs_kgdb_getc __P((void *)); +static void zs_kgdb_putc __P((void *, int)); #endif -extern void *findzs __P((int)); +static int zsrint __P((struct zs_chanstate *, volatile struct zschan *)); +static int zsxint __P((struct zs_chanstate *, volatile struct zschan *)); +static int zssint __P((struct zs_chanstate *, volatile struct zschan *)); + +void zsabort __P((void)); +static void zsoverrun __P((int, long *, char *)); + +#include "zs.h" /* XXX: */ static volatile struct zsdevice *zsaddr[NZS]; /* XXX, but saves work */ /* @@ -174,10 +190,13 @@ int zshardscope; int zsshortcuts; /* number of "shortcut" software interrupts */ #ifdef SUN4 -static u_char +static u_int zs_read __P((volatile struct zschan *, u_int reg)); +static u_int zs_write __P((volatile struct zschan *, u_int, u_int)); + +static u_int zs_read(zc, reg) volatile struct zschan *zc; - u_char reg; + u_int reg; { u_char val; @@ -188,10 +207,10 @@ zs_read(zc, reg) return val; } -static u_char +static u_int zs_write(zc, reg, val) volatile struct zschan *zc; - u_char reg, val; + u_int reg, val; { zc->zc_csr = reg; ZS_DELAY(); @@ -216,7 +235,8 @@ zsmatch(parent, vcf, aux) if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); - if (ca->ca_bustype==BUS_MAIN && cputyp!=CPU_SUN4) + if ((ca->ca_bustype == BUS_MAIN && !CPU_ISSUN4) || + (ca->ca_bustype == BUS_OBIO && CPU_ISSUN4M)) return (getpropint(ra->ra_node, "slave", -2) == cf->cf_unit); ra->ra_len = NBPG; return (probeget(ra->ra_vaddr, 1) != -1); @@ -235,7 +255,7 @@ zsattach(parent, dev, aux) void *aux; { register int zs = dev->dv_unit, unit; - register struct zs_softc *sc; + register struct zsinfo *zi; register struct zs_chanstate *cs; register volatile struct zsdevice *addr; register struct tty *tp, *ctp; @@ -246,7 +266,7 @@ zsattach(parent, dev, aux) int ringsize; if ((addr = zsaddr[zs]) == NULL) - addr = zsaddr[zs] = (volatile struct zsdevice *)findzs(zs); + addr = zsaddr[zs] = findzs(zs); if (ca->ca_bustype==BUS_MAIN) if ((void *)addr != ra->ra_vaddr) panic("zsattach"); @@ -263,36 +283,31 @@ zsattach(parent, dev, aux) intr_establish(PIL_TTY, &levelsoft); } else if (pri != prevpri) panic("broken zs interrupt scheme"); - sc = (struct zs_softc *)dev; - evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt); - sc->sc_zs = addr; + zi = (struct zsinfo *)dev; + zi->zi_zs = addr; unit = zs * 2; - cs = sc->sc_cs; + cs = zi->zi_cs; /* link into interrupt list with order (A,B) (B=A+1) */ cs[0].cs_next = &cs[1]; - cs[0].cs_sc = sc; cs[1].cs_next = zslist; - cs[1].cs_sc = sc; zslist = cs; cs->cs_unit = unit; cs->cs_speed = zs_getspeed(&addr->zs_chan[ZS_CHAN_A]); cs->cs_zc = &addr->zs_chan[ZS_CHAN_A]; - if ((ctp = zs_checkcons(sc, unit, cs)) != NULL) + if ((ctp = zs_checkcons(zi, unit, cs)) != NULL) tp = ctp; else { tp = ttymalloc(); tp->t_dev = makedev(ZSMAJOR, unit); tp->t_oproc = zsstart; tp->t_param = zsparam; - } - cs->cs_ttyp = tp; #ifdef KGDB - if (ctp == NULL) zs_checkkgdb(unit, cs, tp); #endif - ringsize = 4096; + } + cs->cs_ttyp = tp; if (unit == ZS_KBD) { /* * Keyboard: tell /dev/kbd driver how to talk to us. @@ -302,45 +317,51 @@ zsattach(parent, dev, aux) kbd_serial(tp, zsiopen, zsiclose); cs->cs_conk = 1; /* do L1-A processing */ ringsize = 128; + } else { + if (tp != ctp) + tty_attach(tp); + ringsize = 4096; } + cs->cs_ringmask = ringsize - 1; cs->cs_rbuf = malloc((u_long)ringsize * sizeof(*cs->cs_rbuf), - M_DEVBUF, M_NOWAIT); + M_DEVBUF, M_NOWAIT); unit++; cs++; - cs->cs_unit = unit; cs->cs_speed = zs_getspeed(&addr->zs_chan[ZS_CHAN_B]); cs->cs_zc = &addr->zs_chan[ZS_CHAN_B]; - if ((ctp = zs_checkcons(sc, unit, cs)) != NULL) + if ((ctp = zs_checkcons(zi, unit, cs)) != NULL) tp = ctp; else { tp = ttymalloc(); tp->t_dev = makedev(ZSMAJOR, unit); tp->t_oproc = zsstart; tp->t_param = zsparam; - } - cs->cs_ttyp = tp; - #ifdef KGDB - if (ctp == NULL) zs_checkkgdb(unit, cs, tp); #endif - ringsize = 4096; + } + cs->cs_ttyp = tp; if (unit == ZS_MOUSE) { /* * Mouse: tell /dev/mouse driver how to talk to us. */ - tp->t_ispeed = tp->t_ospeed = B1200; + tp->t_ispeed = tp->t_ospeed = cs->cs_speed; tp->t_cflag = CS8; ms_serial(tp, zsiopen, zsiclose); ringsize = 128; + } else { + if (tp != ctp) + tty_attach(tp); + ringsize = 4096; } cs->cs_ringmask = ringsize - 1; cs->cs_rbuf = malloc((u_long)ringsize * sizeof(*cs->cs_rbuf), - M_DEVBUF, M_NOWAIT); + M_DEVBUF, M_NOWAIT); } +#ifdef KGDB /* * Put a channel in a known state. Interrupts may be left disabled * or enabled, as desired. @@ -376,6 +397,7 @@ zs_reset(zc, inten, speed) reg[13] = tconst >> 8; zs_loadchannelregs(zc, reg); } +#endif /* * Declare the given tty (which is in fact &cons) as a console input @@ -391,9 +413,8 @@ zsconsole(tp, unit, out, fnstop) register struct tty *tp; register int unit; int out; - void (**fnstop) __P((struct tty *, int)); + int (**fnstop) __P((struct tty *, int)); { - extern int (*v_putc)(); int zs; volatile struct zsdevice *addr; @@ -403,7 +424,7 @@ zsconsole(tp, unit, out, fnstop) zs_consout = unit; zs = unit >> 1; if ((addr = zsaddr[zs]) == NULL) - addr = zsaddr[zs] = (volatile struct zsdevice *)findzs(zs); + addr = zsaddr[zs] = findzs(zs); zs_conschan = (unit & 1) == 0 ? &addr->zs_chan[ZS_CHAN_A] : &addr->zs_chan[ZS_CHAN_B]; v_putc = zscnputc; @@ -417,7 +438,7 @@ zsconsole(tp, unit, out, fnstop) /* * Polled console output putchar. */ -static int +static void zscnputc(c) int c; { @@ -431,10 +452,8 @@ zscnputc(c) * lowering current ipl. Need a better way. */ s = splhigh(); -#ifdef SUN4C /* XXX */ - if (cputyp==CPU_SUN4C && s <= (12 << 8)) + if (CPU_ISSUN4C && s <= (12 << 8)) /* XXX */ (void) splzs(); -#endif while ((zc->zc_csr & ZSRR0_TX_READY) == 0) ZS_DELAY(); zc->zc_data = c; @@ -447,15 +466,15 @@ zscnputc(c) * needed. Return console tty if it is to receive console input. */ static struct tty * -zs_checkcons(sc, unit, cs) - struct zs_softc *sc; +zs_checkcons(zi, unit, cs) + struct zsinfo *zi; int unit; struct zs_chanstate *cs; { register struct tty *tp; char *i, *o; - if ((tp = zs_ctty) == NULL) + if ((tp = zs_ctty) == NULL) /* XXX */ return (0); i = zs_consin == unit ? "input" : NULL; o = zs_consout == unit ? "output" : NULL; @@ -483,7 +502,7 @@ zs_checkcons(sc, unit, cs) tp->t_oproc = zsstart; } printf("%s%c: console %s\n", - sc->sc_dev.dv_xname, (unit & 1) + 'a', i ? (o ? "i/o" : i) : o); + zi->zi_dev.dv_xname, (unit & 1) + 'a', i ? (o ? "i/o" : i) : o); cs->cs_consio = 1; cs->cs_brkabort = 1; return (tp); @@ -568,13 +587,13 @@ zsopen(dev, flags, mode, p) { register struct tty *tp; register struct zs_chanstate *cs; - struct zs_softc *sc; + struct zsinfo *zi; int unit = minor(dev), zs = unit >> 1, error, s; - if (zs >= zscd.cd_ndevs || (sc = zscd.cd_devs[zs]) == NULL || + if (zs >= zs_cd.cd_ndevs || (zi = zs_cd.cd_devs[zs]) == NULL || unit == ZS_KBD || unit == ZS_MOUSE) return (ENXIO); - cs = &sc->sc_cs[unit & 1]; + cs = &zi->zi_cs[unit & 1]; if (cs->cs_consio) return (ENXIO); /* ??? */ tp = cs->cs_ttyp; @@ -595,7 +614,7 @@ zsopen(dev, flags, mode, p) return (EBUSY); } error = 0; - while (1) { + for (;;) { register int rr0; /* loop, turning on the device, until carrier present */ @@ -609,8 +628,9 @@ zsopen(dev, flags, mode, p) tp->t_state & TS_CARR_ON) break; tp->t_state |= TS_WOPEN; - if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, - ttopen, 0)) { + error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, + ttopen, 0); + if (error) { if (!(tp->t_state & TS_ISOPEN)) { zs_modem(cs, 0); tp->t_state &= ~TS_WOPEN; @@ -640,11 +660,11 @@ zsclose(dev, flags, mode, p) { register struct zs_chanstate *cs; register struct tty *tp; - struct zs_softc *sc; + struct zsinfo *zi; int unit = minor(dev), s; - sc = zscd.cd_devs[unit >> 1]; - cs = &sc->sc_cs[unit & 1]; + zi = zs_cd.cd_devs[unit >> 1]; + cs = &zi->zi_cs[unit & 1]; tp = cs->cs_ttyp; linesw[tp->t_line].l_close(tp, flags); if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN || @@ -682,15 +702,16 @@ zsread(dev, uio, flags) int flags; { register struct zs_chanstate *cs; - register struct zs_softc *sc; + register struct zsinfo *zi; register struct tty *tp; int unit = minor(dev); - sc = zscd.cd_devs[unit >> 1]; - cs = &sc->sc_cs[unit & 1]; + zi = zs_cd.cd_devs[unit >> 1]; + cs = &zi->zi_cs[unit & 1]; tp = cs->cs_ttyp; return (linesw[tp->t_line].l_read(tp, uio, flags)); + } int @@ -700,12 +721,12 @@ zswrite(dev, uio, flags) int flags; { register struct zs_chanstate *cs; - register struct zs_softc *sc; + register struct zsinfo *zi; register struct tty *tp; int unit = minor(dev); - sc = zscd.cd_devs[unit >> 1]; - cs = &sc->sc_cs[unit & 1]; + zi = zs_cd.cd_devs[unit >> 1]; + cs = &zi->zi_cs[unit & 1]; tp = cs->cs_ttyp; return (linesw[tp->t_line].l_write(tp, uio, flags)); @@ -716,18 +737,15 @@ zstty(dev) dev_t dev; { register struct zs_chanstate *cs; - register struct zs_softc *sc; + register struct zsinfo *zi; int unit = minor(dev); - sc = zscd.cd_devs[unit >> 1]; - cs = &sc->sc_cs[unit & 1]; + zi = zs_cd.cd_devs[unit >> 1]; + cs = &zi->zi_cs[unit & 1]; return (cs->cs_ttyp); -} -static int zsrint __P((struct zs_chanstate *, volatile struct zschan *)); -static int zsxint __P((struct zs_chanstate *, volatile struct zschan *)); -static int zssint __P((struct zs_chanstate *, volatile struct zschan *)); +} /* * ZS hardware interrupt. Scan all ZS channels. NB: we know here that @@ -746,64 +764,57 @@ zshard(intrarg) void *intrarg; { register struct zs_chanstate *a; - struct zs_softc *sc; #define b (a + 1) register volatile struct zschan *zc; register int rr3, intflags = 0, v, i, ringmask; - -#define ZSHARD_NEED_SOFTINTR 1 -#define ZSHARD_WAS_SERVICED 2 -#define ZSHARD_CHIP_GOTINTR 4 + static int zsrint(struct zs_chanstate *, volatile struct zschan *); + static int zsxint(struct zs_chanstate *, volatile struct zschan *); + static int zssint(struct zs_chanstate *, volatile struct zschan *); for (a = zslist; a != NULL; a = b->cs_next) { ringmask = a->cs_ringmask; rr3 = ZS_READ(a->cs_zc, 3); if (rr3 & (ZSRR3_IP_A_RX|ZSRR3_IP_A_TX|ZSRR3_IP_A_STAT)) { - intflags |= (ZSHARD_CHIP_GOTINTR|ZSHARD_WAS_SERVICED); + intflags |= 2; zc = a->cs_zc; i = a->cs_rbput; if (rr3 & ZSRR3_IP_A_RX && (v = zsrint(a, zc)) != 0) { a->cs_rbuf[i++ & ringmask] = v; - intflags |= ZSHARD_NEED_SOFTINTR; + intflags |= 1; } if (rr3 & ZSRR3_IP_A_TX && (v = zsxint(a, zc)) != 0) { a->cs_rbuf[i++ & ringmask] = v; - intflags |= ZSHARD_NEED_SOFTINTR; + intflags |= 1; } if (rr3 & ZSRR3_IP_A_STAT && (v = zssint(a, zc)) != 0) { a->cs_rbuf[i++ & ringmask] = v; - intflags |= ZSHARD_NEED_SOFTINTR; + intflags |= 1; } a->cs_rbput = i; } if (rr3 & (ZSRR3_IP_B_RX|ZSRR3_IP_B_TX|ZSRR3_IP_B_STAT)) { - intflags |= (ZSHARD_CHIP_GOTINTR|ZSHARD_WAS_SERVICED); + intflags |= 2; zc = b->cs_zc; i = b->cs_rbput; if (rr3 & ZSRR3_IP_B_RX && (v = zsrint(b, zc)) != 0) { b->cs_rbuf[i++ & ringmask] = v; - intflags |= ZSHARD_NEED_SOFTINTR; + intflags |= 1; } if (rr3 & ZSRR3_IP_B_TX && (v = zsxint(b, zc)) != 0) { b->cs_rbuf[i++ & ringmask] = v; - intflags |= ZSHARD_NEED_SOFTINTR; + intflags |= 1; } if (rr3 & ZSRR3_IP_B_STAT && (v = zssint(b, zc)) != 0) { b->cs_rbuf[i++ & ringmask] = v; - intflags |= ZSHARD_NEED_SOFTINTR; + intflags |= 1; } b->cs_rbput = i; } - if (intflags & ZSHARD_CHIP_GOTINTR) { - a->cs_sc->sc_intrcnt.ev_count++; - intflags &= ~ZSHARD_CHIP_GOTINTR; - } } #undef b - if (intflags & ZSHARD_NEED_SOFTINTR) { -#if defined(SUN4C) || defined(SUN4M) - if (cputyp==CPU_SUN4M || cputyp==CPU_SUN4C) { + if (intflags & 1) { + if (CPU_ISSUN4COR4M) { /* XXX -- but this will go away when zshard moves to locore.s */ struct clockframe *p = intrarg; @@ -817,10 +828,15 @@ zshard(intrarg) return (zssoft(intrarg)); } } + +#if defined(SUN4M) + if (CPU_ISSUN4M) + raise(0, PIL_TTY); + else #endif - ienab_bis(IE_ZSSOFT); + ienab_bis(IE_ZSSOFT); } - return (intflags & ZSHARD_WAS_SERVICED); + return (intflags & 2); } static int @@ -828,11 +844,9 @@ zsrint(cs, zc) register struct zs_chanstate *cs; register volatile struct zschan *zc; { - register u_int c; + register int c = zc->zc_data; - c = zc->zc_data; ZS_DELAY(); - if (cs->cs_conk) { register struct conk_state *conk = &zsconk_state; @@ -857,7 +871,7 @@ zsrint(cs, zc) } } #ifdef KGDB - if (c == FRAME_START && cs->cs_kgdb && + if (c == FRAME_START && cs->cs_kgdb && (cs->cs_ttyp->t_state & TS_ISOPEN) == 0) { zskgdb(cs->cs_unit); goto clearit; @@ -910,7 +924,7 @@ zssint(cs, zc) register struct zs_chanstate *cs; register volatile struct zschan *zc; { - register u_int rr0; + register int rr0; rr0 = zc->zc_csr; ZS_DELAY(); @@ -938,22 +952,21 @@ zssint(cs, zc) } } if ((rr0 & ZSRR0_BREAK) && cs->cs_brkabort) { -#ifdef SUN4 /* * XXX This might not be necessary. Test and * delete if it isn't. */ - if (cputyp==CPU_SUN4) { + if (CPU_ISSUN4) { while (zc->zc_csr & ZSRR0_BREAK) ZS_DELAY(); } -#endif zsabort(); return (0); } return (ZRING_MAKE(ZRING_SINT, rr0)); } +void zsabort() { @@ -970,6 +983,7 @@ zsabort() * KGDB framing character received: enter kernel debugger. This probably * should time out after a few seconds to avoid hanging on spurious input. */ +void zskgdb(unit) int unit; { @@ -1133,10 +1147,10 @@ zsioctl(dev, cmd, data, flag, p) struct proc *p; { int unit = minor(dev); - struct zs_softc *sc = zscd.cd_devs[unit >> 1]; - register struct tty *tp = sc->sc_cs[unit & 1].cs_ttyp; + struct zsinfo *zi = zs_cd.cd_devs[unit >> 1]; + register struct zs_chanstate *cs = &zi->zi_cs[unit & 1]; + register struct tty *tp = cs->cs_ttyp; register int error, s; - register struct zs_chanstate *cs = &sc->sc_cs[unit & 1]; error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p); if (error >= 0) @@ -1173,7 +1187,7 @@ zsioctl(dev, cmd, data, flag, p) break; } case TIOCSFLAGS: { - int userbits, driverbits = 0; + int userbits; error = suser(p->p_ucred, &p->p_acflag); if (error != 0) @@ -1230,16 +1244,10 @@ zsioctl(dev, cmd, data, flag, p) case TIOCCDTR: zs_modem(cs, 0); break; - case TIOCMGET: - /* XXX: fixme */ - *(int *)data = TIOCM_CAR | TIOCM_CTS | TIOCM_DTR | TIOCM_RTS; - return (0); case TIOCMSET: - /* XXX: fixme */ - zs_modem(cs, *(int *)data & (TIOCM_DTR|TIOCM_RTS)); - return (0); case TIOCMBIS: case TIOCMBIC: + case TIOCMGET: default: return (ENOTTY); } @@ -1256,9 +1264,9 @@ zsstart(tp) register struct zs_chanstate *cs; register int s, nch; int unit = minor(tp->t_dev); - struct zs_softc *sc = zscd.cd_devs[unit >> 1]; + struct zsinfo *zi = zs_cd.cd_devs[unit >> 1]; - cs = &sc->sc_cs[unit & 1]; + cs = &zi->zi_cs[unit & 1]; s = spltty(); /* @@ -1310,16 +1318,16 @@ out: /* * Stop output, e.g., for ^S or output flush. */ -void +int zsstop(tp, flag) register struct tty *tp; int flag; { register struct zs_chanstate *cs; register int s, unit = minor(tp->t_dev); - struct zs_softc *sc = zscd.cd_devs[unit >> 1]; + struct zsinfo *zi = zs_cd.cd_devs[unit >> 1]; - cs = &sc->sc_cs[unit & 1]; + cs = &zi->zi_cs[unit & 1]; s = splzs(); if (tp->t_state & TS_BUSY) { /* @@ -1330,6 +1338,7 @@ zsstop(tp, flag) tp->t_state |= TS_FLUSH; } splx(s); + return 0; } /* @@ -1344,8 +1353,8 @@ zsparam(tp, t) register struct termios *t; { int unit = minor(tp->t_dev); - struct zs_softc *sc = zscd.cd_devs[unit >> 1]; - register struct zs_chanstate *cs = &sc->sc_cs[unit & 1]; + struct zsinfo *zi = zs_cd.cd_devs[unit >> 1]; + register struct zs_chanstate *cs = &zi->zi_cs[unit & 1]; register int tmp, tmp5, cflag, s; /* @@ -1519,13 +1528,10 @@ zs_kgdb_getc(arg) void *arg; { register volatile struct zschan *zc = (volatile struct zschan *)arg; - u_char c; while ((zc->zc_csr & ZSRR0_RX_READY) == 0) ZS_DELAY(); - c = zc->zc_data; - ZS_DELAY(); - return c; + return (zc->zc_data); } /* @@ -1567,7 +1573,7 @@ zs_kgdb_init() } zs = unit >> 1; if ((addr = zsaddr[zs]) == NULL) - addr = zsaddr[zs] = (volatile struct zsdevice *)findzs(zs); + addr = zsaddr[zs] = findzs(zs); unit &= 1; zc = unit == 0 ? &addr->zs_chan[ZS_CHAN_A] : &addr->zs_chan[ZS_CHAN_B]; zs_kgdb_savedspeed = zs_getspeed(zc); diff --git a/sys/arch/sparc/dev/zsvar.h b/sys/arch/sparc/dev/zsvar.h index 3fef4d3981e..3234fbc7537 100644 --- a/sys/arch/sparc/dev/zsvar.h +++ b/sys/arch/sparc/dev/zsvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: zsvar.h,v 1.6 1996/01/24 19:52:57 gwr Exp $ */ +/* $NetBSD: zsvar.h,v 1.8 1996/03/31 22:39:08 pk Exp $ */ /* * Copyright (c) 1992, 1993 @@ -91,8 +91,7 @@ struct zsdevice { #define ZRING_MAKE(t, v) ((t) | (v) << 8) struct zs_chanstate { - struct zs_chanstate *cs_next; /* linked list for zshard() */ - struct zs_softc *cs_sc; /* points to my softc */ + struct zs_chanstate *cs_next; /* linked list for zshard() */ volatile struct zschan *cs_zc; /* points to hardware regs */ int cs_unit; /* unit number */ struct tty *cs_ttyp; /* ### */ @@ -163,17 +162,22 @@ struct zs_chanstate { * On the SparcStation the 1.6 microsecond recovery time is * handled in hardware. On the older Sun4 machine it isn't, and * software must deal with the problem. + * + * However, it *is* a problem on some Sun4m's (i.e. the SS20) (XXX: why?). + * Thus we leave in the delay. + * + * XXX: (ABB) Think about this more. */ -#ifdef SUN4 +#if defined(SUN4) + #define ZS_READ(c, r) zs_read(c, r) #define ZS_WRITE(c, r, v) zs_write(c, r, v) -#if defined(SUN4C) || defined(SUN4M) -#define ZS_DELAY() (cputyp == CPU_SUN4 ? delay(2) : 0) -#else -#define ZS_DELAY() delay(2) -#endif -#else +#define ZS_DELAY() (CPU_ISSUN4C ? (0) : delay(1)) + +#else /* SUN4 */ + #define ZS_READ(c, r) ((c)->zc_csr = (r), (c)->zc_csr) #define ZS_WRITE(c, r, v) ((c)->zc_csr = (r), (c)->zc_csr = (v)) -#define ZS_DELAY() -#endif +#define ZS_DELAY() (CPU_ISSUN4M ? delay(1) : 0) + +#endif /* SUN4 */ |