summaryrefslogtreecommitdiff
path: root/sys/arch/sparc/dev
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1996-08-11 05:35:37 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1996-08-11 05:35:37 +0000
commite511a52691ddb2290f5d3c9ca6e9f0fc3b320289 (patch)
treef68510b774a71e2a0879cb013e3abd7a15665abc /sys/arch/sparc/dev
parentfc98d7c9a0046f274410f903f952ef6224f68e10 (diff)
netbsd port, now we merge our changes back in
Diffstat (limited to 'sys/arch/sparc/dev')
-rw-r--r--sys/arch/sparc/dev/amd7930.c69
-rw-r--r--sys/arch/sparc/dev/amd7930var.h6
-rw-r--r--sys/arch/sparc/dev/bt_subr.c5
-rw-r--r--sys/arch/sparc/dev/btreg.h62
-rw-r--r--sys/arch/sparc/dev/bwtwo.c380
-rw-r--r--sys/arch/sparc/dev/bwtworeg.h17
-rw-r--r--sys/arch/sparc/dev/cgeight.c383
-rw-r--r--sys/arch/sparc/dev/cgfour.c346
-rw-r--r--sys/arch/sparc/dev/cgsix.c216
-rw-r--r--sys/arch/sparc/dev/cgsixreg.h5
-rw-r--r--sys/arch/sparc/dev/cgthree.c143
-rw-r--r--sys/arch/sparc/dev/cgthreereg.h6
-rw-r--r--sys/arch/sparc/dev/cgtwo.c118
-rw-r--r--sys/arch/sparc/dev/cons.c226
-rw-r--r--sys/arch/sparc/dev/dma.c628
-rw-r--r--sys/arch/sparc/dev/dmareg.h104
-rw-r--r--sys/arch/sparc/dev/dmavar.h93
-rw-r--r--sys/arch/sparc/dev/esp.c2560
-rw-r--r--sys/arch/sparc/dev/espreg.h255
-rw-r--r--sys/arch/sparc/dev/espvar.h335
-rw-r--r--sys/arch/sparc/dev/fb.c275
-rw-r--r--sys/arch/sparc/dev/fd.c367
-rw-r--r--sys/arch/sparc/dev/fdreg.h4
-rw-r--r--sys/arch/sparc/dev/fdvar.h10
-rw-r--r--sys/arch/sparc/dev/if_ie.c191
-rw-r--r--sys/arch/sparc/dev/if_le.c157
-rw-r--r--sys/arch/sparc/dev/if_levar.h39
-rw-r--r--sys/arch/sparc/dev/kbd.c99
-rw-r--r--sys/arch/sparc/dev/ms.c21
-rw-r--r--sys/arch/sparc/dev/obio.c361
-rw-r--r--sys/arch/sparc/dev/pfourreg.h21
-rw-r--r--sys/arch/sparc/dev/power.c103
-rw-r--r--sys/arch/sparc/dev/power.h60
-rw-r--r--sys/arch/sparc/dev/rcons_font.h2
-rw-r--r--sys/arch/sparc/dev/sbus.c132
-rw-r--r--sys/arch/sparc/dev/sbusvar.h7
-rw-r--r--sys/arch/sparc/dev/si.c160
-rw-r--r--sys/arch/sparc/dev/xd.c176
-rw-r--r--sys/arch/sparc/dev/xdreg.h10
-rw-r--r--sys/arch/sparc/dev/xdvar.h20
-rw-r--r--sys/arch/sparc/dev/xio.h6
-rw-r--r--sys/arch/sparc/dev/xy.c245
-rw-r--r--sys/arch/sparc/dev/xyreg.h6
-rw-r--r--sys/arch/sparc/dev/xyvar.h8
-rw-r--r--sys/arch/sparc/dev/zs.c274
-rw-r--r--sys/arch/sparc/dev/zsvar.h28
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 */