code:
/*	$OpenBSD: ubavar.h,v 1.9 2015/02/01 15:27:11 miod Exp $	*/
/*	$NetBSD: ubavar.h,v 1.31 2001/04/26 19:16:07 ragge Exp $	*/

/*
 * Copyright (c) 1982, 1986 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. 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.
 *
 *	@(#)ubavar.h	7.7 (Berkeley) 6/28/90
 */
#ifndef _QBUS_UBAVAR_H
#define	_QBUS_UBAVAR_H

/*
 * This file contains definitions related to the kernel structures
 * for dealing with the unibus adapters.
 *
 * Each uba has a uba_softc structure.
 * Each unibus controller which is not a device has a uba_ctlr structure.
 * Each unibus device has a uba_device structure.
 */

/*
 * Per-uba structure.
 *
 * This structure holds the interrupt vector for the uba,
 * and its address in physical and virtual space.  At boot time
 * we determine the devices attached to the uba's and their
 * interrupt vectors, filling in uh_vec.  We free the map
 * register and bdp resources of the uba into the structures
 * defined here.
 *
 * During normal operation, resources are allocated and returned
 * to the structures here.  We watch the number of passive releases
 * on each uba, and if the number is excessive may reset the uba.
 *
 * When uba resources are needed and not available, or if a device
 * which can tolerate no other uba activity (rk07) gets on the bus,
 * then device drivers may have to wait to get to the bus and are
 * queued here.  It is also possible for processes to block in
 * the unibus driver in resource wait (mrwant, bdpwant); these
 * wait states are also recorded here.
 */
struct	uba_softc {
	struct	device uh_dev;		/* Device struct, autoconfig */
	struct	evcount uh_intrcnt;		/* interrupt counting */
	SIMPLEQ_HEAD(, uba_unit) uh_resq;	/* resource wait chain */
	SIMPLEQ_HEAD(, uba_reset) uh_resetq;	/* ubareset queue */
	int	uh_lastiv;		/* last free interrupt vector */
	int	(*uh_errchk)(struct uba_softc *);
	void	(*uh_beforescan)(struct uba_softc *);
	void	(*uh_afterscan)(struct uba_softc *);
	void	(*uh_ubainit)(struct uba_softc *);
	void	(*uh_ubapurge)(struct uba_softc *, int);
	short	uh_nr;			/* Unibus sequential number */
	bus_space_tag_t	uh_iot;		/* Tag for this Unibus */
	bus_space_handle_t uh_ioh;	/* Handle for I/O space */
	bus_dma_tag_t	uh_dmat;
};

/*
 * Per-controller structure.
 * The unit struct is common to both the adapter and the controller
 * to which it belongs. It is only used on controllers that handles
 * BDP's, and calls the adapter queueing subroutines.
 */
struct	uba_unit {
	SIMPLEQ_ENTRY(uba_unit) uu_resq;/* Queue while waiting for resources */
	void	*uu_softc;	/* Pointer to units softc */
	int	uu_bdp;		/* for controllers that hang on to bdp's */
	int    (*uu_ready)(struct uba_unit *);
	void	*uu_ref;	/* Buffer this is related to */
	short   uu_xclu;        /* want exclusive use of bdp's */
};

/*
 * Reset structure. All devices that needs to be reinitialized
 * after an ubareset registers with this struct.
 */
struct	uba_reset {
	SIMPLEQ_ENTRY(uba_reset) ur_resetq;
	void (*ur_reset)(struct device *);
	struct device *ur_dev;
};

/*
 * uba_attach_args is used during autoconfiguration. It is sent
 * from ubascan() to each (possible) device.
 */
struct uba_attach_args {
	bus_space_tag_t	ua_iot;		/* Tag for this bus I/O-space */
	bus_addr_t	ua_ioh;		/* I/O regs addr */
	bus_dma_tag_t	ua_dmat;
	void		*ua_icookie;	/* Cookie for interrupt establish */
	int		ua_iaddr;	/* Full CSR address of device */
	int		ua_br;		/* IPL this dev interrupted on */
	int		ua_cvec;	/* Vector for this device */
};

/*
 * Flags to UBA map/bdp allocation routines
 */
#define	UBA_NEEDBDP	0x01		/* transfer needs a bdp */
#define	UBA_CANTWAIT	0x02		/* don't block me */
#define	UBA_NEED16	0x04		/* need 16 bit addresses only */
#define	UBA_HAVEBDP	0x08		/* use bdp specified in high bits */
#define	UBA_DONTQUE	0x10		/* Do not enqueue xfer */

/*
 * Struct for unibus allocation.
 */
struct ubinfo {
	bus_dmamap_t ui_dmam;
	bus_dma_segment_t ui_seg;
	int ui_rseg;
	caddr_t ui_vaddr;
	bus_addr_t ui_baddr;
	bus_size_t ui_size;
};

/*
 * Some common defines for all subtypes of U/Q-buses/adapters.
 */
#define ubdevreg(addr) ((addr) & 017777)

#ifdef _KERNEL
void uba_intr_establish(void *, int, void (*)(void *), void *, struct evcount *);
void uba_reset_establish(void (*)(struct device *), struct device *);
void uba_attach(struct uba_softc *, unsigned long);
void uba_enqueue(struct uba_unit *);
void uba_done(struct uba_softc *);
void ubareset(struct uba_softc *);
int uballoc(struct uba_softc *, struct ubinfo *, int);
int ubmemalloc(struct uba_softc *, struct ubinfo *, int);
void ubfree(struct uba_softc *, struct ubinfo *);
void ubmemfree(struct uba_softc *, struct ubinfo *);
#endif /* _KERNEL */

#endif /* _QBUS_UBAVAR_H */


code:
/*	$OpenBSD: uda.c,v 1.11 2014/12/23 21:39:12 miod Exp $	*/
/*	$NetBSD: uda.c,v 1.36 2000/06/04 06:17:05 matt Exp $	*/
/*
 * Copyright (c) 1996 Ludd, University of Lule}, Sweden.
 * Copyright (c) 1988 Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Chris Torek.
 *
 * 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. 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.
 *
 *	@(#)uda.c	7.32 (Berkeley) 2/13/91
 */

/*
 * UDA50 disk device driver
 */

#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/buf.h>
#include <sys/malloc.h>

#include <machine/bus.h>
#include <machine/sid.h>

#include <arch/vax/qbus/ubavar.h>
#include <arch/vax/mscp/mscp.h>
#include <arch/vax/mscp/mscpreg.h>
#include <arch/vax/mscp/mscpvar.h>

/*
 * Software status, per controller.
 */
struct	uda_softc {
	struct	device sc_dev;	/* Autoconfig info */
	struct	evcount sc_intrcnt; /* Interrupt counting */
	int	sc_cvec;
	struct	uba_unit sc_unit; /* Struct common for UBA to communicate */
	struct	mscp_pack *sc_uuda;	/* Unibus address of uda struct */
	struct	mscp_pack sc_uda;	/* Struct for uda communication */
	bus_dma_tag_t		sc_dmat;
	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_iph;
	bus_space_handle_t	sc_sah;
	bus_dmamap_t		sc_cmap;/* Control structures */
	struct	mscp *sc_mscp;		/* Keep pointer to active mscp */
	struct	mscp_softc *sc_softc;	/* MSCP info (per mscpvar.h) */
	int	sc_wticks;	/* watchdog timer ticks */
	int	sc_inq;
};

static	int	udamatch(struct device *, struct cfdata *, void *);
static	void	udaattach(struct device *, struct device *, void *);
static	void	udareset(struct device *);
static	void	udaintr(void *);
int	udaready(struct uba_unit *);
void	udactlrdone(struct device *);
int	udaprint(void *, const char *);
void	udasaerror(struct device *, int);
void	udago(struct device *, struct mscp_xi *);

struct	cfattach mtc_ca = {
	sizeof(struct uda_softc), (cfmatch_t)udamatch, udaattach
};

struct	cfdriver mtc_cd = {
	NULL, "mtc", DV_TAPE
};

struct	cfattach uda_ca = {
	sizeof(struct uda_softc), (cfmatch_t)udamatch, udaattach
};

struct	cfdriver uda_cd = {
	NULL, "uda", DV_DISK
};

/*
 * More driver definitions, for generic MSCP code.
 */
struct	mscp_ctlr uda_mscp_ctlr = {
	udactlrdone,
	udago,
	udasaerror,
};

/*
 * Miscellaneous private variables.
 */
static	int	ivec_no;

int
udaprint(aux, name)
	void	*aux;
	const char	*name;
{
	if (name)
		printf("%s: mscpbus", name);
	return UNCONF;
}

/*
 * Poke at a supposed UDA50 to see if it is there.
 */
int
udamatch(parent, cf, aux)
	struct device *parent;
	struct cfdata *cf;
	void *aux;
{
	struct	uba_attach_args *ua = aux;
	struct	mscp_softc mi;	/* Nice hack */
	struct	uba_softc *ubasc;
	int	tries;

	/* Get an interrupt vector. */
	ubasc = (void *)parent;
	ivec_no = ubasc->uh_lastiv - 4;

	mi.mi_iot = ua->ua_iot;
	mi.mi_iph = ua->ua_ioh;
	mi.mi_sah = ua->ua_ioh + 2;
	mi.mi_swh = ua->ua_ioh + 2;

	/*
	 * Initialise the controller (partially).  The UDA50 programmer's
	 * manual states that if initialisation fails, it should be retried
	 * at least once, but after a second failure the port should be
	 * considered `down'; it also mentions that the controller should
	 * initialise within ten seconds.  Or so I hear; I have not seen
	 * this manual myself.
	 */
	tries = 0;
again:

	bus_space_write_2(mi.mi_iot, mi.mi_iph, 0, 0); /* Start init */
	if (mscp_waitstep(&mi, MP_STEP1, MP_STEP1) == 0)
		return 0; /* Nothing here... */

	bus_space_write_2(mi.mi_iot, mi.mi_sah, 0,
	    MP_ERR | (NCMDL2 << 11) | (NRSPL2 << 8) | MP_IE | (ivec_no >> 2));

	if (mscp_waitstep(&mi, MP_STEP2, MP_STEP2) == 0) {
		printf("udaprobe: init step2 no change. sa=%x\n",
		    bus_space_read_2(mi.mi_iot, mi.mi_sah, 0));
		goto bad;
	}

	/* should have interrupted by now */
	return 1;
bad:
	if (++tries < 2)
		goto again;
	return 0;
}

void
udaattach(parent, self, aux)
	struct device *parent, *self;
	void *aux;
{
	struct	uda_softc *sc = (void *)self;
	struct	uba_attach_args *ua = aux;
	struct	uba_softc *uh = (void *)parent;
	struct	mscp_attach_args ma;
	int	ctlr, error, rseg;
	bus_dma_segment_t seg;

	printf("\n");

	uh->uh_lastiv -= 4;	/* remove dynamic interrupt vector */

	uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
	    udaintr, sc, &sc->sc_intrcnt);
	uba_reset_establish(udareset, &sc->sc_dev);
	sc->sc_cvec = ua->ua_cvec;
	evcount_attach(&sc->sc_intrcnt, sc->sc_dev.dv_xname, &sc->sc_cvec);

	sc->sc_iot = ua->ua_iot;
	sc->sc_iph = ua->ua_ioh;
	sc->sc_sah = ua->ua_ioh + 2;
	sc->sc_dmat = ua->ua_dmat;
	ctlr = sc->sc_dev.dv_unit;

	/*
	 * Fill in the uba_unit struct, so we can communicate with the uba.
	 */
	sc->sc_unit.uu_softc = sc;	/* Backpointer to softc */
	sc->sc_unit.uu_ready = udaready;/* go routine called from adapter */

	/*
	 * Map the communication area and command and
	 * response packets into Unibus space.
	 */
	if ((error = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct mscp_pack),
	    NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
		printf("Alloc ctrl area %d\n", error);
		return;
	}
	if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
	    sizeof(struct mscp_pack), (caddr_t *) &sc->sc_uda,
	    BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
		printf("Map ctrl area %d\n", error);
err:		bus_dmamem_free(sc->sc_dmat, &seg, rseg);
		return;
	}
	if ((error = bus_dmamap_create(sc->sc_dmat, sizeof(struct mscp_pack),
	    1, sizeof(struct mscp_pack), 0, BUS_DMA_NOWAIT, &sc->sc_cmap))) {
		printf("Create DMA map %d\n", error);
err2:		bus_dmamem_unmap(sc->sc_dmat, (caddr_t)&sc->sc_uda,
		    sizeof(struct mscp_pack));
		goto err;
	}
	if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cmap,
	    &sc->sc_uda, sizeof(struct mscp_pack), 0, BUS_DMA_NOWAIT))) {
		printf("Load ctrl map %d\n", error);
		bus_dmamap_destroy(sc->sc_dmat, sc->sc_cmap);
		goto err2;
	}

	bzero(&sc->sc_uda, sizeof (struct mscp_pack));

	/*
	 * The only thing that differ UDA's and Tape ctlr's is
	 * their vcid. Because there is no way to determine which
	 * ctlr type it is, we check what is generated and later
	 * set the correct vcid.
	 */
	ma.ma_type = (strcmp(self->dv_cfdata->cf_driver->cd_name,
	    mtc_cd.cd_name) ? MSCPBUS_DISK : MSCPBUS_TAPE);

	ma.ma_mc = &uda_mscp_ctlr;
	ma.ma_type |= MSCPBUS_UDA;
	ma.ma_uda = &sc->sc_uda;
	ma.ma_softc = &sc->sc_softc;
	ma.ma_iot = sc->sc_iot;
	ma.ma_iph = sc->sc_iph;
	ma.ma_sah = sc->sc_sah;
	ma.ma_swh = sc->sc_sah;
	ma.ma_dmat = sc->sc_dmat;
	ma.ma_dmam = sc->sc_cmap;
	ma.ma_ivec = ivec_no;
	ma.ma_ctlrnr = (ua->ua_iaddr == 0172150 ? 0 : 1);	/* XXX */
	ma.ma_adapnr = uh->uh_nr;
	config_found(&sc->sc_dev, &ma, udaprint);
}

/*
 * Start a transfer if there are free resources available, otherwise
 * let it go in udaready, forget it for now.
 * Called from mscp routines.
 */
void
udago(usc, mxi)
	struct device *usc;
	struct mscp_xi *mxi;
{
	struct uda_softc *sc = (void *)usc;
	struct uba_unit *uu;
	struct buf *bp = mxi->mxi_bp;
	int err;

	/*
	 * If we already have transfers queued, don't try to load
	 * the map again.
	 */
	if (sc->sc_inq == 0) {
		err = bus_dmamap_load(sc->sc_dmat, mxi->mxi_dmam, bp->b_data,
		    bp->b_bcount, (bp->b_flags & B_PHYS ? bp->b_proc : NULL),
		    BUS_DMA_NOWAIT);
		if (err == 0) {
			mscp_dgo(sc->sc_softc, mxi);
			return;
		}
	}
	uu = malloc(sizeof(struct uba_unit), M_DEVBUF, M_NOWAIT);
	if (uu == 0)
		panic("udago: no mem");
	uu->uu_ready = udaready;
	uu->uu_softc = sc;
	uu->uu_ref = mxi;
	uba_enqueue(uu);
	sc->sc_inq++;
}

/*
 * Called if we have been blocked for resources, and resources
 * have been freed again. Return 1 if we could start all
 * transfers again, 0 if we still are waiting.
 * Called from uba resource free routines.
 */
int
udaready(uu)
	struct uba_unit *uu;
{
	struct uda_softc *sc = uu->uu_softc;
	struct mscp_xi *mxi = uu->uu_ref;
	struct buf *bp = mxi->mxi_bp;
	int err;

	err = bus_dmamap_load(sc->sc_dmat, mxi->mxi_dmam, bp->b_data,
	    bp->b_bcount, (bp->b_flags & B_PHYS ? bp->b_proc : NULL),
	    BUS_DMA_NOWAIT);
	if (err)
		return 0;
	mscp_dgo(sc->sc_softc, mxi);
	sc->sc_inq--;
	free(uu, M_DEVBUF, sizeof(struct uba_unit));
	return 1;
}

static struct saerr {
	int	code;		/* error code (including UDA_ERR) */
	char	*desc;		/* what it means: Efoo => foo error */
} saerr[] = {
	{ 0100001, "Eunibus packet read" },
	{ 0100002, "Eunibus packet write" },
	{ 0100003, "EUDA ROM and RAM parity" },
	{ 0100004, "EUDA RAM parity" },
	{ 0100005, "EUDA ROM parity" },
	{ 0100006, "Eunibus ring read" },
	{ 0100007, "Eunibus ring write" },
	{ 0100010, " unibus interrupt master failure" },
	{ 0100011, "Ehost access timeout" },
	{ 0100012, " host exceeded command limit" },
	{ 0100013, " unibus bus master failure" },
	{ 0100014, " DM XFC fatal error" },
	{ 0100015, " hardware timeout of instruction loop" },
	{ 0100016, " invalid virtual circuit id" },
	{ 0100017, "Eunibus interrupt write" },
	{ 0104000, "Efatal sequence" },
	{ 0104040, " D proc ALU" },
	{ 0104041, "ED proc control ROM parity" },
	{ 0105102, "ED proc w/no BD#2 or RAM parity" },
	{ 0105105, "ED proc RAM buffer" },
	{ 0105152, "ED proc SDI" },
	{ 0105153, "ED proc write mode wrap serdes" },
	{ 0105154, "ED proc read mode serdes, RSGEN & ECC" },
	{ 0106040, "EU proc ALU" },
	{ 0106041, "EU proc control reg" },
	{ 0106042, " U proc DFAIL/cntl ROM parity/BD #1 test CNT" },
	{ 0106047, " U proc const PROM err w/D proc running SDI test" },
	{ 0106055, " unexpected trap" },
	{ 0106071, "EU proc const PROM" },
	{ 0106072, "EU proc control ROM parity" },
	{ 0106200, "Estep 1 data" },
	{ 0107103, "EU proc RAM parity" },
	{ 0107107, "EU proc RAM buffer" },
	{ 0107115, " test count wrong (BD 12)" },
	{ 0112300, "Estep 2" },
	{ 0122240, "ENPR" },
	{ 0122300, "Estep 3" },
	{ 0142300, "Estep 4" },
	{ 0, " unknown error code" }
};

/*
 * If the error bit was set in the controller status register, gripe,
 * then (optionally) reset the controller and requeue pending transfers.
 */
void
udasaerror(usc, doreset)
	struct device *usc;
	int doreset;
{
	struct	uda_softc *sc = (void *)usc;
	int code = bus_space_read_2(sc->sc_iot, sc->sc_sah, 0);
	struct saerr *e;

	if ((code & MP_ERR) == 0)
		return;
	for (e = saerr; e->code; e++)
		if (e->code == code)
			break;
	printf("%s: controller error, sa=0%o (%s%s)\n",
		sc->sc_dev.dv_xname, code, e->desc + 1,
		*e->desc == 'E' ? " error" : "");
#if 0 /* XXX we just avoid panic when autoconfig non-existent KFQSA devices */
	if (doreset) {
		mscp_requeue(sc->sc_softc);
/*		(void) udainit(sc);	XXX */
	}
#endif
}

/*
 * Interrupt routine.  Depending on the state of the controller,
 * continue initialisation, or acknowledge command and response
 * interrupts, and process responses.
 */
static void
udaintr(arg)
	void *arg;
{
	struct uda_softc *sc = arg;
	struct uba_softc *uh;
	struct mscp_pack *ud;

	sc->sc_wticks = 0;	/* reset interrupt watchdog */

	/* ctlr fatal error */
	if (bus_space_read_2(sc->sc_iot, sc->sc_sah, 0) & MP_ERR) {
		udasaerror(&sc->sc_dev, 1);
		return;
	}
	ud = &sc->sc_uda;
	/*
	 * Handle buffer purge requests.
	 * XXX - should be done in bus_dma_sync().
	 */
	uh = (void *)sc->sc_dev.dv_parent;
	if (ud->mp_ca.ca_bdp) {
		if (uh->uh_ubapurge)
			(*uh->uh_ubapurge)(uh, ud->mp_ca.ca_bdp);
		ud->mp_ca.ca_bdp = 0;
		/* signal purge complete */
		bus_space_write_2(sc->sc_iot, sc->sc_sah, 0, 0);
	}

	mscp_intr(sc->sc_softc);
}

/*
 * A Unibus reset has occurred on UBA uban.  Reinitialise the controller(s)
 * on that Unibus, and requeue outstanding I/O.
 */
static void
udareset(struct device *dev)
{
	struct uda_softc *sc = (void *)dev;
	/*
	 * Our BDP (if any) is gone; our command (if any) is
	 * flushed; the device is no longer mapped; and the
	 * UDA50 is not yet initialised.
	 */
	if (sc->sc_unit.uu_bdp) {
		/* printf("<%d>", UBAI_BDP(sc->sc_unit.uu_bdp)); */
		sc->sc_unit.uu_bdp = 0;
	}

	/* reset queues and requeue pending transfers */
	mscp_requeue(sc->sc_softc);

	/*
	 * If it fails to initialise we will notice later and
	 * try again (and again...).  Do not call udastart()
	 * here; it will be done after the controller finishes
	 * initialisation.
	 */
/* XXX	if (udainit(sc)) */
		printf(" (hung)");
}

void
udactlrdone(usc)
	struct device *usc;
{
	struct uda_softc *sc = (void *)usc;

	uba_done((struct uba_softc *)sc->sc_dev.dv_parent);
}

license: unknown


code:
/Makefile/1.13/Sun Jul 13 21:18:44 2014//TOPENBSD_5_8_BASE
/Makefile.inc/1.5/Fri Nov 15 03:10:33 2013//TOPENBSD_5_8_BASE
D/boot////
D/common////
D/xxboot////

path: sys/arch/vax/stand/CVS/Entries


code: src/sys/arch/vax/stand

path: sys/arch/vax/stand/CVS/Repository


code:
#	$OpenBSD: Makefile,v 1.13 2014/07/13 21:18:44 jasper Exp $
#	$NetBSD: Makefile,v 1.21 1999/03/06 16:36:04 ragge Exp $
#

.if ${MACHINE} == "vax"
SUBDIR=	boot xxboot
.endif

.include <bsd.subdir.mk>

path: sys/arch/vax/stand/Makefile


code:
#	$OpenBSD: Makefile.inc,v 1.5 2013/11/15 03:10:33 uebayasi Exp $
#	$NetBSD: Makefile.inc,v 1.6 2002/02/24 01:04:23 matt Exp $

RELOC=0x39F000
.PATH:	${.CURDIR}/../../vax ${.CURDIR}/../common

CFLAGS+=	-fno-stack-protector
CPPFLAGS+=-I. -I${.CURDIR}/../../../../ -I${.CURDIR}/../../ -I${.CURDIR}/../common -I${.CURDIR}/../../include
CPPFLAGS+=-DRELOC=${RELOC}

# Private handling of assembler files.
.s.o:
	${CC} -x assembler-with-cpp ${CPPFLAGS} -E ${.IMPSRC} | ${AS} -o ${.TARGET}


path: sys/arch/vax/stand/boot/CVS/Entries


code: src/sys/arch/vax/stand/boot

path: sys/arch/vax/stand/boot/CVS/Repository


code:
#	$OpenBSD: Makefile,v 1.13 2014/07/13 21:18:44 jasper Exp $
#	$NetBSD: Makefile,v 1.27 2002/04/07 07:00:25 matt Exp $

S!=	cd ${.CURDIR}/../../../../; pwd
NOMAN=	# defined
NOPIE=

.include <bsd.own.mk>

PROG=	boot
DEVS=	ra.c mfm.c if_qe.c if_le.c if_ze.c if_de.c
SRCS=	srt0.S boot.c devopen.c conf.c autoconf.c netio.c rom.c romread.S \
	urem.s udiv.s consio.c consio2.S str.S ${DEVS} findcpu.c

CPPFLAGS+=-DSUPPORT_BOOTPARAMS -DSUPPORT_DHCP -D_STANDALONE \
	-DNO_MID_CHECK
#CPPFLAGS+=-DBOOTP_DEBUG -DNETIF_DEBUG -DETHER_DEBUG -DNFS_DEBUG -DDEV_DEBUG \
#	-DRPC_DEBUG -DRARP_DEBUG -DPARANOID

BINDIR=/usr/mdec

SA_ZLIB=	yes
USE_LOADFILE=	yes
SAREL=
.include "${S}/lib/libsa/Makefile.inc"
LIBSA=	${SALIB}

Z_AS=	library
CFLAGS+=-I${S}/lib/libsa
.include "${S}/lib/libz/Makefile.inc"
LIBZ=	${ZLIB}

.PATH:	${S}/lib/libkern/arch/vax ${S}/lib/libkern
SRCS+= moddi3.c negdi2.c

.if ${MACHINE} == "vax"
.if !make(obj)
.BEGIN:
	@([ -h machine ] || ln -s ${.CURDIR}/../../../${MACHINE}/include machine)
.NOPATH: machine
CLEANFILES+=	machine
.endif
.endif

START=start
STRIP?=strip
CLEANFILES+=	${PROG}.sym

${PROG}: ${OBJS} ${LIBSA} ${LIBZ}
	${LD} -N -Ttext ${RELOC} -e ${START} -o ${PROG}.sym ${OBJS} \
	    -Llib/sa -L. ${LIBSA} ${LIBZ} ${LIBSA}
	${STRIP} -o ${PROG} ${PROG}.sym

clean::
	rm -f a.out [Ee]rrs mklog *.core ${PROG} ${OBJS} ${LOBJS} \
	    ${CLEANFILES}

.include <bsd.prog.mk>

path: sys/arch/vax/stand/boot/Makefile


code:
/*	$OpenBSD: autoconf.c,v 1.16 2013/08/15 13:00:48 otto Exp $ */
/*	$NetBSD: autoconf.c,v 1.19 2002/06/01 15:33:22 ragge Exp $ */
/*
 * Copyright (c) 1994, 1998 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *     This product includes software developed at Ludd, University of Lule}.
 * 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.
 */

 /* All bugs are subject to removal without further notice */

#include <sys/param.h>

#include <lib/libsa/stand.h>

#include <machine/mtpr.h>
#include <machine/sid.h>
#include <machine/intr.h>
#include <machine/rpb.h>
#include <machine/scb.h>
#include <arch/vax/mbus/mbusreg.h>
#include <arch/vax/mbus/fwioreg.h>
#include "vaxstand.h"

void autoconf(void);
void findcpu(void);
void consinit(void);
void scbinit(void);
void clkstart(void);
time_t getsecs(void);
void scb_stray(void *);
void scb_silent(void *);
void longjmp(int *);
void rtimer(void *);

long *bootregs;

/*
 * Do some initial setup. Also create a fake RPB for net-booted machines
 * that don't have an in-prom VMB.
 */

void
autoconf(void)
{
	int copyrpb = 1;
	int fromnet = (bootregs[12] != -1);

	findcpu(); /* Configures CPU variables */
	scbinit(); /* Setup interrupts */
	consinit(); /* Allow us to print out things */
	clkstart(); /* Fix interval clock etc */

#ifdef DEV_DEBUG
	printf("Register contents:\n");
	for (copyrpb = 0; copyrpb < 13; copyrpb++)
		printf("r%d: %lx\n", copyrpb, bootregs[copyrpb]);
#endif
	switch (vax_boardtype) {

	case VAX_BTYP_780:
	case VAX_BTYP_790:
	case VAX_BTYP_8000:
	case VAX_BTYP_9CC:
	case VAX_BTYP_9RR:
	case VAX_BTYP_1202:
		if (fromnet == 0)
			break;
		copyrpb = 0;
		bootrpb.devtyp = bootregs[0];
		bootrpb.adpphy = bootregs[1];
		bootrpb.csrphy = bootregs[2];
		bootrpb.unit = bootregs[3];
		bootrpb.rpb_bootr5 = bootregs[5];
		bootrpb.pfncnt = 0;
		break;

	case VAX_BTYP_46:
	case VAX_BTYP_48:
		{int *map, i;

		/* Map all 16MB of I/O space to low 16MB of memory */
		map = (int *)0x700000; /* XXX */
		*(int *)0x20080008 = (int)map; /* XXX */
		for (i = 0; i < 0x8000; i++)
			map[i] = 0x80000000 | i;
		}break;

		break;
	}

	if (copyrpb) {
		struct rpb *prpb = (struct rpb *)bootregs[11];
		bcopy((caddr_t)prpb, &bootrpb, sizeof(struct rpb));
		if (prpb->iovec) {
			bootrpb.iovec = (int)alloc(prpb->iovecsz);
			bcopy((caddr_t)prpb->iovec, (caddr_t)bootrpb.iovec,
			    prpb->iovecsz);
		}
	}
}

/*
 * Clock handling routines, needed to do timing in standalone programs.
 */

volatile int tickcnt;

time_t
getsecs(void)
{
	return tickcnt/100;
}

struct ivec_dsp **scb;
struct ivec_dsp *scb_vec;
extern struct ivec_dsp idsptch;
extern int jbuf[10];
extern int mcheck_silent;

static void
mcheck(void *arg)
{
	int off, *mfp = (int *)&arg;

	if (!mcheck_silent) {
		off = (mfp[7]/4 + 8);
		printf("Machine check, pc=%x, psl=%x\n", mfp[off], mfp[off+1]);
	}
	longjmp(jbuf);
}

/*
 * Init the SCB and set up a handler for all vectors in the lower space,
 * to detect unwanted interrupts.
 */
void
scbinit(void)
{
	int i;

	/*
	 * Allocate space. We need one page for the SCB, and 128*20 == 2.5k
	 * for the vectors. The SCB must be on a page boundary.
	 */
	i = (int)alloc(VAX_NBPG + 128*sizeof(scb_vec[0])) + VAX_PGOFSET;
	i &= ~VAX_PGOFSET;

	mtpr(i, PR_SCBB);
	scb = (void *)i;
	scb_vec = (struct ivec_dsp *)(i + VAX_NBPG);

	for (i = 0; i < 128; i++) {
		scb[i] = &scb_vec[i];
		(int)scb[i] |= SCB_ISTACK;	/* Only interrupt stack */
		scb_vec[i] = idsptch;
		scb_vec[i].hoppaddr = scb_stray;
		scb_vec[i].pushlarg = (void *) (i * 4);
		scb_vec[i].ev = NULL;
	}
	scb_vec[4/4].hoppaddr = mcheck;
	if (vax_boardtype == VAX_BTYP_60)
		scb_vec[0x60/4].hoppaddr = scb_silent;
}

void
clkstart(void)
{
	scb_vec[0xc0/4].hoppaddr = rtimer;
	if (vax_boardtype != VAX_BTYP_VXT)
		mtpr(-10000, PR_NICR);		/* Load in count register */
	mtpr(0x800000d1, PR_ICCS);	/* Start clock and enable interrupt */

	if (vax_boardtype == VAX_BTYP_60) {
		extern int ka60_ioslot;

		/* enable M-Bus clock in IOCSR */
		*(unsigned int *)(MBUS_SLOT_BASE(ka60_ioslot) +
		    FWIO_IOCSR_OFFSET) |= FWIO_IOCSR_CLKIEN;
	}

	mtpr(20, PR_IPL);
}

extern int sluttid, senast, skip;

void
rtimer(void *arg)
{
	mtpr(31, PR_IPL);
	tickcnt++;
	mtpr(0xc1, PR_ICCS);
	if (skip)
		return;
	if ((vax_boardtype == VAX_BTYP_46) ||
	    (vax_boardtype == VAX_BTYP_48) ||
	    (vax_boardtype == VAX_BTYP_49)) {
		int nu = sluttid - getsecs();
		if (senast != nu) {
			mtpr(20, PR_IPL);
			longjmp(jbuf);
		}
	}
}

#ifdef __ELF__
#define	IDSPTCH "idsptch"
#define	EIDSPTCH "eidsptch"
#define	CMN_IDSPTCH "cmn_idsptch"
#else
#define	IDSPTCH "_idsptch"
#define	EIDSPTCH "_eidsptch"
#define	CMN_IDSPTCH "_cmn_idsptch"
#endif

asm(
	".text\n"
	".align	2\n"
	".globl	" IDSPTCH ", " EIDSPTCH "\n"
IDSPTCH ":\n"
	"pushr	$0x3f\n"
	".word	0x9f16\n"
	".long	" CMN_IDSPTCH "\n"
	".long	0\n"
	".long	0\n"
	".long	0\n"
EIDSPTCH ":\n"

CMN_IDSPTCH ":\n"
	"movl	(%sp)+,%r0\n"
	"pushl	4(%r0)\n"
	"calls	$1,*(%r0)\n"
	"popr	$0x3f\n"
	"rei\n"
);

/*
 * Stray interrupt handler.
 * This function must _not_ save any registers (in the reg save mask).
 */
void
scb_stray(void *arg)
{
	static int vector, ipl;

	ipl = mfpr(PR_IPL);
	vector = (int) arg;
	printf("stray interrupt: vector 0x%x, ipl %d\n", vector, ipl);
}

void
scb_silent(void *arg)
{
	/* nothing */
}


code:
/*	$OpenBSD: boot.c,v 1.25 2014/02/19 22:13:53 miod Exp $ */
/*	$NetBSD: boot.c,v 1.18 2002/05/31 15:58:26 ragge Exp $ */
/*-
 * Copyright (c) 1982, 1986 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. 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.
 *
 *	@(#)boot.c	7.15 (Berkeley) 5/4/91
 */

#include <sys/param.h>
#include <sys/reboot.h>
#include <sys/stat.h>
#define _KERNEL
#include <sys/fcntl.h>
#undef _KERNEL

#include <lib/libkern/libkern.h>
#include <lib/libsa/stand.h>
#include <lib/libsa/loadfile.h>

#include "machine/rpb.h"
#include "machine/sid.h"

#include "vaxstand.h"

/*
 * Boot program... arguments passed in r10 and r11 determine
 * whether boot stops to ask for system name and which device
 * boot comes from.
 */

char line[100];
int	bootdev, debug;
extern	unsigned opendev;

char   rnddata[BOOTRANDOM_MAX];

void	usage(char *), boot(char *), halt(char *);
void	Xmain(void);
void	autoconf(void);
time_t	getsecs(void);
int	loadrandom(const char *, char *, size_t);
int	setjmp(int *);
int	testkey(void);

const struct vals {
	char	*namn;
	void	(*func)(char *);
	char	*info;
} val[] = {
	{"?", usage, "Show this help menu"},
	{"help", usage, "Same as '?'"},
	{"boot", boot, "Load and execute file"},
	{"halt", halt, "Halts the system"},
	{0, 0},
};

int jbuf[10];
int sluttid, senast, skip, askname;
int mcheck_silent;
struct rpb bootrpb;

void
Xmain(void)
{
	int io;
	int j, nu;
	char transition = '\010';
	u_long marks[MARK_MAX];

	io = 0;
	skip = 1;
	autoconf();

	/*
	 * Some VAXstation 4000 PROMs slowly erase the whole screen with \010
	 * if running with glass console - at least VS4000/60 and VS4000/VLC;
	 * this is probably the LCG PROM at fault. Use a different transition
	 * pattern, it's not as nice but it does not take 3(!) seconds to
	 * display...
	 */
	if (((vax_boardtype == VAX_BTYP_46 &&
	      (vax_siedata & 0xff) == VAX_VTYP_46) ||
	     (vax_boardtype == VAX_BTYP_48 &&
	      vax_cpustype == VAX_STYP_48)) &&
	    (vax_confdata & 0x100) == 0)
		transition = ' ';

	askname = bootrpb.rpb_bootr5 & RB_ASKNAME;
	printf("\n\r>> OpenBSD/vax boot [%s] <<\n", "1.18");
	printf(">> Press enter to autoboot now, or any other key to abort:  ");
	sluttid = getsecs() + 5;
	senast = 0;
	skip = 0;
	setjmp(jbuf);
	for (;;) {
		nu = sluttid - getsecs();
		if (senast != nu)
			printf("%c%d", transition, nu);
		if (nu <= 0)
			break;
		senast = nu;
		if ((j = (testkey() & 0177))) {
			skip = 1;
			if (j != 10 && j != 13) {
				printf("\nPress '?' for help");
				askname = 1;
			}
			break;
		}
	}
	skip = 1;
	printf("\n");

	if (setjmp(jbuf))
		askname = 1;

	/* First try to autoboot */
	if (askname == 0) {
		int err;

		errno = 0;
		printf("> boot bsd\n");
		boot(NULL);
	}

	/* If any key pressed, or autoboot failed, go to conversational boot */
	for (;;) {
		const struct vals *v = &val[0];
		char *c, *d;

		printf("> ");
		gets(line);

		c = line;
		while (*c == ' ')
			c++;

		if (c[0] == 0)
			continue;

		if ((d = strchr(c, ' ')))
			*d++ = 0;

		while (v->namn) {
			if (strcmp(v->namn, c) == 0)
				break;
			v++;
		}
		if (v->namn)
			(*v->func)(d);
		else
			printf("Unknown command: %s\n", c);
	}
}

void
halt(char *hej)
{
	asm("halt");
}

void
boot(char *arg)
{
	char *fn = "bsd";
	int howto, err;
	u_long marks[MARK_MAX];
	static int rnd_loaded = 0;

	if (arg) {
		while (*arg == ' ')
			arg++;

		if (*arg != '-') {
			fn = arg;
			if ((arg = strchr(arg, ' '))) {
				*arg++ = 0;
				while (*arg == ' ')
					arg++;
			} else
				goto load;
		}
		if (*arg != '-') {
fail:			printf("usage: boot [filename] [-acsd]\n");
			return;
		}

		howto = 0;

		while (*++arg) {
			if (*arg == 'a')
				howto |= RB_ASKNAME;
			else if (*arg == 'c')
				howto |= RB_CONFIG;
			else if (*arg == 'd')
				howto |= RB_KDB;
			else if (*arg == 's')
				howto |= RB_SINGLE;
			else
				goto fail;
		}
		bootrpb.rpb_bootr5 = howto;
	}
load:
	/*
	 * Attempt to load /etc/random.seed if loading from a disk.
	 */
	switch (bootrpb.devtyp) {
	default:
		break;
	case BDEV_UDA:
	case BDEV_RD:
	case BDEV_SD:
	case BDEV_SDN:
	case BDEV_SDS:
		if (rnd_loaded == 0)
			rnd_loaded = loadrandom(BOOTRANDOM, rnddata,
			    sizeof(rnddata));
		break;
	}

	marks[MARK_START] = 0;
	err = loadfile(fn, marks, LOAD_KERNEL|COUNT_KERNEL);
	if (err == 0) {
		machdep_start((char *)marks[MARK_ENTRY],
				      marks[MARK_NSYM],
			      (void *)marks[MARK_START],
			      (void *)marks[MARK_SYM],
			      (void *)marks[MARK_END]);
	}
	printf("%s: boot failed: %s\n", fn, strerror(errno));
}

void
usage(char *hej)
{
	const struct vals *v = &val[0];
	int i;

	printf("Commands:\n");
	while (v->namn) {
		printf("%s ", v->namn);
		for (i = 1 + strlen(v->namn); (i & 7) != 0; i++)
			printf(" ");
		printf("%s\n", v->info);
		v++;
	}
}

int
loadrandom(const char *name, char *buf, size_t buflen)
{
	struct stat sb;
	int fd;
	int rc = 0;

	fd = open(name, O_RDONLY);
	if (fd == -1) {
		if (errno != EPERM)
			printf("cannot open %s: %s\n", name, strerror(errno));
		return 0;
	}
	if (fstat(fd, &sb) == -1 || sb.st_uid != 0 || !S_ISREG(sb.st_mode) ||
	    (sb.st_mode & (S_IWOTH|S_IROTH)))
		goto fail;
	(void) read(fd, buf, buflen);
	rc = 1;
fail:
	close(fd);
	return rc;
}


code:
/*	$OpenBSD: conf.c,v 1.6 2011/07/06 18:32:59 miod Exp $ */
/*	$NetBSD: conf.c,v 1.10 2000/06/15 19:53:23 ragge Exp $ */
/*
 * Copyright (c) 1994 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *     This product includes software developed at Ludd, University of Lule}.
 * 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.
 */

 /* All bugs are subject to removal without further notice */

#include "sys/param.h"

#include <netinet/in.h>

#include "../../include/rpb.h"

#include "lib/libkern/libkern.h"

#include "lib/libsa/stand.h"
#include "lib/libsa/ufs.h"
#include "lib/libsa/nfs.h"
#include "lib/libsa/cd9660.h"

#include "vaxstand.h"

static int nostrategy(void *, int, daddr32_t, size_t, void *, size_t *);

struct	devsw devsw[]={
	SADEV("qe",nostrategy, qeopen, qeclose, noioctl), /* DEQNA */
	SADEV("ra",rastrategy, raopen, nullsys, noioctl),
	SADEV("mt",rastrategy, raopen, nullsys, noioctl),
        SADEV("rom",romstrategy, romopen, nullsys, noioctl),
        SADEV("hd",mfmstrategy, mfmopen, nullsys, noioctl),
        SADEV("sd",romstrategy, romopen, nullsys, noioctl),
	SADEV("sd",romstrategy, romopen, nullsys, noioctl),	/* SDN */
	SADEV("sd",romstrategy, romopen, nullsys, noioctl),	/* SDS */
	SADEV("st",nullsys, nullsys, nullsys, noioctl),
	SADEV("le",nostrategy, leopen, leclose, noioctl), /* LANCE */
	SADEV("ze",nostrategy, zeopen, zeclose, noioctl), /* SGEC */
	SADEV("de",nostrategy, deopen, declose, noioctl), /* DEUNA */
};

int	cnvtab[] = {
	BDEV_QE,
	BDEV_UDA,
	BDEV_TK,
	-1,
	BDEV_RD,
	BDEV_SD,
	BDEV_SDN,
	BDEV_SDS,
	BDEV_ST,
	BDEV_LE,
	BDEV_ZE,
	BDEV_DE,
};

int     ndevs = (sizeof(devsw)/sizeof(devsw[0]));

struct fs_ops file_system[] = {
	{ ufs_open, ufs_close, ufs_read, ufs_write, ufs_seek, ufs_stat },
	{ nfs_open, nfs_close, nfs_read, nfs_write, nfs_seek, nfs_stat },
	{ cd9660_open, cd9660_close, cd9660_read, cd9660_write,
	    cd9660_seek, cd9660_stat },
};

int nfsys = (sizeof(file_system) / sizeof(struct fs_ops));

int
nostrategy(void *f, int func, daddr32_t dblk,
    size_t size, void *buf, size_t *rsize)
{
	*rsize = size;
	bzero(buf, size);
	return 0;
}


code:
/*	$OpenBSD: consio.c,v 1.10 2008/08/18 23:20:44 miod Exp $ */
/*	$NetBSD: consio.c,v 1.13 2002/05/24 21:40:59 ragge Exp $ */
/*
 * Copyright (c) 1994, 1998 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *     This product includes software developed at Ludd, University of Lule}.
 * 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.
 */

 /* All bugs are subject to removal without further notice */

#include <sys/param.h>

#include "../vax/gencons.h"

#include "mtpr.h"
#include "sid.h"
#include "rpb.h"
#include "ka630.h"

#include "data.h"

#include <machine/cvax.h>
#include <arch/vax/mbus/mbusreg.h>

void setup(void);

static void (*put_fp)(int)  = NULL;
static int (*get_fp)(void) = NULL;
static int (*test_fp)(void) = NULL;

/*
 * I/O using mtpr/mfpr
 */

void	pr_putchar(int c);
int	pr_getchar(void);
int	pr_testchar(void);

/*
 * I/O using ROM routines
 */

void	rom_putchar(int c);
int	rom_getchar(void);
int	rom_testchar(void);

int	rom_putc;		/* ROM-address of put-routine */
int	rom_getc;		/* ROM-address of get-routine */

/*
 * I/O using the KA630 ROM console routines
 */

/* Pointer to KA630 console page, initialized by ka630_consinit */
unsigned char	*ka630_conspage;
void	ka630_consinit(void);

void	ka630_rom_putchar(int c);
int	ka630_rom_getchar(void);
int	ka630_rom_testchar(void);

/*
 * I/O using the KA53 ROM console routines
 */

unsigned char  *ka53_conspage;
void	ka53_consinit(void);

void	ka53_rom_putchar(int c);
int	ka53_rom_getchar(void);
int	ka53_rom_testchar(void);

/*
 * I/O using the VXT2000 serial ports
 */

void	vxt_putchar(int c);
int	vxt_getchar(void);
int	vxt_testchar(void);

/*
 * I/O using the KA60 ROM console routines
 */

unsigned char  *ka60_conspage;
void	ka60_consinit(void);

void	ka60_rom_putchar(int c);
int	ka60_rom_getchar(void);
int	ka60_rom_testchar(void);

void	putchar(int);
int	getchar(void);
int	testkey(void);
void	consinit(void);
void	_rtt(void);

void
putchar(int c)
{
	(*put_fp)(c);
	if (c == 10)
		(*put_fp)(13);		/* CR/LF */
}

int
getchar(void)
{
	int c;

	do
		c = (*get_fp)() & 0177;
	while (c == 17 || c == 19);		/* ignore XON/XOFF */
	if (c < 96 && c > 64)
		c += 32;			/* force lowercase */
	return c;
}

int
testkey(void)
{
	return (*test_fp)();
}

/*
 * setup() is called out of the startup files (start.s, srt0.s) and
 * initializes data which are globally used and is called before main().
 */
void
consinit(void)
{
	put_fp = pr_putchar; /* Default */
	get_fp = pr_getchar;
	test_fp = pr_testchar;

	/*
	 * According to the vax_boardtype (vax_cputype is not specific
	 * enough to do that) we decide which method/routines to use
	 * for console I/O.
	 * mtpr/mfpr are restricted to serial consoles, ROM-based routines
	 * support both serial and graphical consoles.
	 * We default to mtpr routines; so that we don't crash if
	 * it isn't a supported system.
	 */
	switch (vax_boardtype) {

	case VAX_BTYP_43:
	case VAX_BTYP_410:
	case VAX_BTYP_420:
		put_fp = rom_putchar;
		get_fp = rom_getchar;
		test_fp = rom_testchar;
		rom_putc = 0x20040058;		/* 537133144 */
		rom_getc = 0x20040044;		/* 537133124 */
		break;

	case VAX_BTYP_VXT:
		put_fp = rom_putchar;
		get_fp = vxt_getchar;
		test_fp = vxt_testchar;
		rom_putc = 0x20040058;		/* 537133144 */
		rom_getc = 0x20040044;		/* 537133124 */
		break;

	case VAX_BTYP_630:
		ka630_consinit();
		break;

	case VAX_BTYP_46:
	case VAX_BTYP_48:
	case VAX_BTYP_49:
		put_fp = rom_putchar;
		get_fp = rom_getchar;
		test_fp = rom_testchar;
		rom_putc = 0x20040068;
		rom_getc = 0x20040054;
		break;

	case VAX_BTYP_1303:
		ka53_consinit();
		break;

	case VAX_BTYP_60:
		ka60_consinit();
		break;

#ifdef notdef
	case VAX_BTYP_630:
	case VAX_BTYP_650:
	case VAX_BTYP_9CC:
		put_fp = pr_putchar;
		get_fp = pr_getchar;
		break
#endif
	}
	return;
}

/*
 * putchar() using MTPR
 */
void
pr_putchar(int c)
{
	int	timeout = 1<<15;	/* don't hang the machine! */

	/*
	 * On KA88 we may get C-S/C-Q from the console.
	 * Must obey it.
	 */
	while (mfpr(PR_RXCS) & GC_DON) {
		if ((mfpr(PR_RXDB) & 0x7f) == 19) {
			while (1) {
				while ((mfpr(PR_RXCS) & GC_DON) == 0)
					;
				if ((mfpr(PR_RXDB) & 0x7f) == 17)
					break;
			}
		}
	}

	while ((mfpr(PR_TXCS) & GC_RDY) == 0)  /* Wait until xmit ready */
		if (--timeout < 0)
			break;
	mtpr(c, PR_TXDB);		/* xmit character */
}

/*
 * getchar() using MFPR
 */
int
pr_getchar(void)
{
	while ((mfpr(PR_RXCS) & GC_DON) == 0)
		;	/* wait for char */
	return (mfpr(PR_RXDB));			/* now get it */
}

int
pr_testchar(void)
{
	if (mfpr(PR_RXCS) & GC_DON)
		return mfpr(PR_RXDB);
	else
		return 0;
}

/*
 * void ka630_consinit (void)  ==> initialize KA630 ROM console I/O
 */
void ka630_consinit(void)
{
	short *NVR;
	int i;

	/* Find the console page */
	NVR = (short *) KA630_NVR_ADRS;

	i = *NVR++ & 0xFF;
	i |= (*NVR++ & 0xFF) << 8;
	i |= (*NVR++ & 0xFF) << 16;
	i |= (*NVR++ & 0xFF) << 24;

	ka630_conspage = (char *) i;

	/* Go to last row to minimize confusion */
	ka630_conspage[KA630_ROW] = ka630_conspage[KA630_MAXROW];
	ka630_conspage[KA630_COL] = ka630_conspage[KA630_MINCOL];

	/* Use KA630 ROM console I/O routines */
	put_fp = ka630_rom_putchar;
	get_fp = ka630_rom_getchar;
	test_fp = ka630_rom_testchar;
}

/*
 * void ka53_consinit (void)  ==> initialize KA53 ROM console I/O
 */
void ka53_consinit(void)
{
	ka53_conspage = (char *) 0x2014044b;

	put_fp = ka53_rom_putchar;
	get_fp = ka53_rom_getchar;
	test_fp = ka53_rom_testchar;
}

/*
 * VXT2000 console routines.
 *
 * While we can use the rom putchar routine, the rom getchar routine
 * will happily return the last key pressed, even if it is not pressed
 * anymore.
 *
 * To guard against this, we monitor the keyboard serial port and will
 * only invoke the rom function (which will do the keyboard layout
 * translation for us) if there is indeed a new keyboard event (we still
 * need to guard against dead keys, hence the while() condition in
 * vxt_getchar). This still unfortunately causes phantom characters to
 * appear when playing with the shift keys, but nothing backspace can't
 * erase, so this will be a minor annoyance.
 *
 * If console is on the serial port, we do not use the prom routines at
 * all.
 */
static volatile int *vxtregs = (int *)0x200A0000;

#define	CH_SRA		0x01
#define	CH_CRA		0x02
#define	CH_DATA		0x03
#define	CH_SRC		0x11
#define	CH_CRC		0x12
#define	CH_DATC		0x13

#define	CR_RX_ENA	0x01
#define	CR_TX_ENA	0x04
#define SR_RX_RDY	0x01
#define SR_TX_RDY	0x04

int
vxt_getchar(void)
{
	if (vax_confdata & 2) {
		vxtregs[CH_CRC] = CR_RX_ENA;
		while ((vxtregs[CH_SRC] & SR_RX_RDY) == 0 ||
		    rom_testchar() == 0)
			;
		return rom_getchar();
	} else {
		vxtregs[CH_CRA] = CR_RX_ENA;
		while ((vxtregs[CH_SRA] & SR_RX_RDY) == 0)
			;
		return vxtregs[CH_DATA];
	}
}

int
vxt_testchar(void)
{
	if (vax_confdata & 2) {
		vxtregs[CH_CRC] = CR_RX_ENA;
		if ((vxtregs[CH_SRC] & SR_RX_RDY) == 0)
			return 0;
		return rom_testchar();
	} else {
		vxtregs[CH_CRA] = CR_RX_ENA;
		if ((vxtregs[CH_SRA] & SR_RX_RDY) == 0)
			return 0;
		return vxtregs[CH_DATA];
	}
}

int ka60_ioslot = -1;

/*
 * void ka60_consinit (void)  ==> initialize KA60 ROM console I/O
 */
void ka60_consinit(void)
{
	extern int jbuf[10];
	extern int mcheck_silent;
	extern int setjmp(int *);

	int mid, fbicaddr;
	uint32_t modtype, fbicrange;

	for (mid = 0; mid < MBUS_SLOT_MAX; mid++) {
		fbicaddr = MBUS_SLOT_BASE(mid) + FBIC_BASE;

		if (setjmp(jbuf)) {
			/* this slot is empty */
			continue;
		}
		mcheck_silent = 1;
		modtype = *(uint32_t *)(fbicaddr + FBIC_MODTYPE);
		mcheck_silent = 0;

		if ((modtype & MODTYPE_CLASS_MASK) >> MODTYPE_CLASS_SHIFT !=
		    CLASS_IO)
			continue;

		ka60_ioslot = mid;

		fbicrange = *(uint32_t *)(fbicaddr + FBIC_RANGE);
		if (fbicrange ==
		    ((HOST_TO_MBUS(CVAX_SSC) & RANGE_MATCH) | RANGE_ENABLE))
			break;
	}
	mcheck_silent = 0;

	if (ka60_ioslot < 0) {
		/*
		 * This shouldn't happen. Try mid #5 (enclosure slot #4) as a
		 * supposedly sane default.
		 */
		ka60_ioslot = 5;
	}

	ka60_conspage = (char *) *(unsigned int *)0x20140514;
	put_fp = ka60_rom_putchar;
	get_fp = ka60_rom_getchar;
	test_fp = ka60_rom_testchar;
}


code:
/*	$OpenBSD: consio2.S,v 1.3 2013/07/05 21:13:06 miod Exp $ */
/*	$NetBSD: consio2.S,v 1.1 2002/02/24 01:04:24 matt Exp $ */
/*
 * Copyright (c) 1994, 1998 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *     This product includes software developed at Ludd, University of Lule}.
 * 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.
 */

#include <machine/asm.h>

/*
 * int rom_putchar (int c)	==> putchar() using ROM-routines
 */
ENTRY(rom_putchar, R2)
	movl	4(%ap), %r2		# move argument to R2
	jsb	*_C_LABEL(rom_putc)	# write it
	ret				# that is all

/*
 * int rom_getchar (void)	==> getchar() using ROM-routines
 */
ENTRY(rom_getchar, R1)
loop:					# do {
	jsb	*_C_LABEL(rom_getc)	#   call the getc-routine
	tstl	%r0			#   check if char ready
	beql	loop			# } while (R0 == 0)
	movl	%r1, %r0		# R1 holds char
	ret				# we are done

ENTRY(rom_testchar, 0)
	mnegl	$1,%r0
	jsb	*_C_LABEL(rom_getc)
	tstl	%r0
	beql	1f
	movl	%r1,%r0
1:	ret

ENTRY(_rtt, 0)
	halt

/*
 * int ka630_rom_getchar (void) ==> getchar() using ROM-routines on KA630
 */
ENTRY(ka630_rom_getchar, R11|R1)
	movl	_C_LABEL(ka630_conspage),%r11  # load location of console page
1:					# do {
	jsb	*0x1C(%r11)		#   call the getc-routine (KA630_GETC)
	blbc	%r0,1b			# } while (R0 == 0)
	movl	%r1,%r0			# R1 holds char
	ret				# we are done

ENTRY(ka630_rom_testchar, R3|R1)
	movl	_C_LABEL(ka630_conspage),%r3
	jsb	*0x1C(%r3)
	blbc	%r0,1f
	movl	%r1,%r0
1:	ret

/*
 * int ka630_rom_putchar (int c) ==> putchar() using ROM-routines on KA630
 */
ENTRY(ka630_rom_putchar, R11|R1)
	movl	_C_LABEL(ka630_conspage),%r11
				# load location of console page
1:				# do {
	jsb	*0x20(%r11)	#   is rom ready? (KA630_PUTC_POLL)
	blbc	%r0,1b		# } while (R0 == 0)
	movl	4(%ap),%r1	# R1 holds char
	jsb	*0x24(%r11)	# output character (KA630_PUTC)
	ret			# we are done

/*
 * int ka53_rom_getchar (void)	==> getchar() using ROM-routines on KA53
 */
ENTRY(ka53_rom_getchar, R11|R1)
	movl	_C_LABEL(ka53_conspage),%r11
				# load location of console page
1:				# do {
	jsb	*0x64(%r11)	#   test for char
	blbc	%r0,1b		# } while (R0 == 0)
	jsb	*0x6c(%r11)	# get the char
	ret			# we are done

ENTRY(ka53_rom_testchar, R3|R1)
	movl	_C_LABEL(ka53_conspage),%r3
	jsb	*0x64(%r3)
	blbc	%r0,1f
	jsb	*0x6c(%r3)	# get the char
1:	ret

/*
 * int ka53_rom_putchar (int c) ==> putchar() using ROM-routines on KA53
 */
ENTRY(ka53_rom_putchar, R11|R1)
	movl	_C_LABEL(ka53_conspage),%r11
				# load location of console page
1:				# do {
	jsb	*0x20(%r11)	#   is rom ready?
	blbc	%r0,1b		# } whi	le (R0 == 0)
	movl	4(%ap),%r1	# R1 holds char
	jsb	*0x24(%r11)	# output character
	ret			# we are done

/*
 * int ka60_rom_getchar (void)	==> getchar() using ROM-routines on KA60
 */
ENTRY(ka60_rom_getchar, R11|R10|R9|R8|R7|R6|R5|R4|R3|R2|R1)
1:
	movl	_C_LABEL(ka60_conspage),%r0
				# load location of console page
				# do {
	jsb	*0xfc(%r0)	#   get the char, if any
	blbc	%r0,1b		# } while (R0 == 0)
	movl	%r1,%r0
	ret			# we are done

ENTRY(ka60_rom_testchar, R11|R10|R9|R8|R7|R6|R5|R4|R3|R2|R1)
	movl	_C_LABEL(ka60_conspage),%r0
	jsb	*0xfc(%r0)
	blbc	%r0,1f
	movl	%r1,%r0
1:	ret

/*
 * int ka60_rom_putchar (int c) ==> putchar() using ROM-routines on KA60
 */
ENTRY(ka60_rom_putchar, R11|R10|R9|R8|R7|R6|R5|R4|R3|R2|R1)
1:
	movl	_C_LABEL(ka60_conspage),%r0
				# load location of console page
	movl	4(%ap),%r1	# R1 holds char
	jsb	*0x114(%r0)	# output character
	blbc	%r0, 1b		# failed? retry
	ret			# we are done


code:
/*	$OpenBSD: data.h,v 1.2 2002/06/11 09:36:23 hugh Exp $ */
/*	$NetBSD: data.h,v 1.3 2001/07/26 15:05:09 wiz Exp $ */
/*
 * Copyright (c) 1995 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * This code is derived from software contributed to Ludd by
 * Bertram Barth.
 *
 * 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 at Ludd, University of
 *      Lule}, Sweden and its contributors.
 * 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.
 */

 /* All bugs are subject to removal without further notice */

/*
 * rpb->iovec gives pointer to this structure.
 *
 * bqo->unit_init() is used to initialize the controller,
 * bqo->qio() is used to read from boot-device
 */

struct bqo {
	long  qio;            /*  4  QIO entry  */
	long  map;            /*  4  Mapping entry  */
	long  select;         /*  4  Selection entry  */
	long  drivrname;      /*  4  Offset to driver name  */
	short version;        /*  2  Version number of VMB  */
	short vercheck;       /*  2  Check field  */
	/* offset: 20 */
	long  reselect;       /*  4  Reselection entry  */
	long  move;           /*  4  Move driver entry  */
	long  unit_init;      /*  4  Unit initialization entry  */
	long  auxdrname;      /*  4  Offset to auxiliary driver name  */
	long  umr_dis;        /*  4  UNIBUS Map Registers to disable  */
	/* offset: 40 */
	long  ucode;          /*  4  Absolute address of booting microcode  */
	long  unit_disc;      /*  4  Unit disconnecting entry */
	long  devname;        /*  4  Offset to boot device name */
	long  umr_tmpl;       /*  4  UNIBUS map register template */
	/* offset: 60 */
	/*
	 * the rest is unknown / unnecessary ...
	 */
	long  xxx[6];		/* 24 --	total: 84 bytes */
};

extern struct bqo *bqo;


code:
/*	$OpenBSD: devopen.c,v 1.5 2011/07/06 18:32:59 miod Exp $ */
/*	$NetBSD: devopen.c,v 1.10 2002/05/24 21:40:59 ragge Exp $ */
/*
 * Copyright (c) 1997 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed at Ludd, University of
 *      Lule}, Sweden and its contributors.
 * 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.
 */

#include <lib/libsa/stand.h>

#include "machine/rpb.h"
#include "machine/sid.h"
#include "machine/pte.h"

#include "vaxstand.h"

int	atoi(char *);
int nexaddr, csrbase;

int
devopen(f, fname, file)
	struct open_file *f;
	const char *fname;
	char **file;
{
	int dev, unit, ctlr, part, adapt, i, a[4], x;
	int *mapregs;
	struct devsw *dp;
	extern int cnvtab[];
	char *s, *c;

	part = 0;

	/*
	 * Adaptor and controller are normally zero (or uninteresting),
	 * but we need to do some conversion here anyway (if it's a
	 * manual boot, but that's checked by the device driver).
	 * Set them to -1 to tell if it's a set number or default.
	 */
	dev = bootrpb.devtyp;
	unit = bootrpb.unit;
	adapt = ctlr = -1;

	if (dev == BDEV_KDB)
		dev = BDEV_UDA; /* use the same driver */

	for (i = 0, dp = 0; i < ndevs; i++)
		if (cnvtab[i] == dev)
			dp = devsw + i;

	if ((s = index((char *)fname, '('))) {
		*s++ = 0;

		for (i = 0, dp = devsw; i < ndevs; i++, dp++)
			if (dp->dv_name && strcmp(dp->dv_name, fname) == 0)
				break;

		if (i == ndevs) {
			printf("No such device - Configured devices are:\n");
			for (dp = devsw, i = 0; i < ndevs; i++, dp++)
				if (dp->dv_name && (i == 0 ||
				    strcmp(dp->dv_name, (dp[-1]).dv_name) != 0))
					printf(" %s", dp->dv_name);
			printf("\n");
			return EINVAL;
		}

		dev = cnvtab[i];
		if ((c = index(s, ')')) == 0)
			goto usage;
		*c++ = 0;

		/*
		 * If the user has specified sd(), we need to pick the
		 * correct BDEV_SDx value, depending on the machine type.
		 */
		if (dev == BDEV_SD) {
			switch (vax_boardtype) {
			case VAX_BTYP_46:
			case VAX_BTYP_48:
			case VAX_BTYP_49:
			case VAX_BTYP_1303:
				dev = BDEV_SDN;		/* asc(4) */
				break;
			case VAX_BTYP_60:
				dev = BDEV_SDS;		/* sii(4) */
				break;
			}
		}

		x = 0;
		if (*s) do {
			a[x++] = atoi(s);
			while (*s >= '0' && *s <= '9')
				s++;

			if (*s != ',' && *s != 0)
				goto usage;
		} while (*s++);

		if (x)
			part = a[x - 1];
		if (x > 1)
			unit = a[x - 2];
		if (x > 2)
			ctlr = a[x - 3];
		if (x > 3)
			adapt = a[0];
		*file = c;
	} else {
		*file = (char *)fname;
		c = (char *)fname;
	}

	if (!dp->dv_open) {
		printf("Can't open device type %d\n", dev);
		return ENXIO;
	}
	f->f_dev = dp;
	bootrpb.unit = unit;
	bootrpb.devtyp = dev;

	nexaddr = bootrpb.adpphy;
	switch (vax_boardtype) {
	case VAX_BTYP_610:
		nexaddr = 0; /* No map regs */
		csrbase = 0x20000000;
		break;

	case VAX_BTYP_VXT:
		nexaddr = 0;
		csrbase = bootrpb.csrphy;
		break;
	default:
		nexaddr = 0; /* No map regs */
		csrbase = 0x20000000;
		/* Always map in the lowest 4M on qbus-based machines */
		mapregs = (void *)0x20088000;
		if (bootrpb.adpphy == 0x20087800)
			for (i = 0; i < 8192; i++)
				mapregs[i] = PG_V | i;
		break;
	}

#ifdef DEV_DEBUG
	printf("rpb.type %d rpb.unit %d rpb.csr %lx rpb.adp %lx\n",
	    bootrpb.devtyp, bootrpb.unit, bootrpb.csrphy, bootrpb.adpphy);
	printf("adapter %d ctlr %d unit %d part %d\n", adapt, ctlr, unit, part);
	printf("nexaddr %x csrbase %x\n", nexaddr, csrbase);
#endif

	return (*dp->dv_open)(f, adapt, ctlr, unit, part);

usage:
	printf("usage: dev(adapter,controller,unit,partition)file -asd\n");
	return EINVAL;
}


code:
/*	$OpenBSD: if_de.c,v 1.4 2014/08/21 14:24:08 mpi Exp $ */
/*	$NetBSD: if_de.c,v 1.2 2002/05/24 21:41:40 ragge Exp $	*/

/*
 * Copyright (c) 2000 Ludd, University of Lule}, Sweden. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed at Ludd, University of
 *      Lule}, Sweden and its contributors.
 * 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.
 *
 *	Standalone routine for the DEUNA Ethernet controller.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/queue.h>

#include <net/if.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>

#include <lib/libsa/netif.h>
#include <lib/libsa/stand.h>

#include <arch/vax/if/if_dereg.h>

#define	DE_PCSR0	0
#define	DE_PCSR1	2
#define	DE_PCSR2	4
#define	DE_PCSR3	6

#include "arch/vax/include/sid.h"
#include "arch/vax/include/rpb.h"
#include "arch/vax/include/pte.h"

#include "vaxstand.h"

static int de_get(struct iodesc *, void *, size_t, time_t);
static int de_put(struct iodesc *, void *, size_t);
static void dewait(char *);

struct netif_driver de_driver = {
	0, 0, 0, 0, de_get, de_put,
};

#define NRCV 8		/* allocate 8 receive descriptors */
#define NXMT 4		/* and 4 transmit - must be >1 */

struct de_cdata {
	/* the following structures are always mapped in */
        struct  de_pcbb dc_pcbb;        /* port control block */
        struct  de_ring dc_xrent[NXMT]; /* transmit ring entries */
        struct  de_ring dc_rrent[NRCV]; /* receive ring entries */
        struct  de_udbbuf dc_udbbuf;    /* UNIBUS data buffer */
	char	dc_rbuf[NRCV][ETHER_MAX_LEN];
	char	dc_xbuf[NXMT][ETHER_MAX_LEN];
        /* end mapped area */
};

static volatile struct de_cdata *dc, *pdc;
static volatile char *addr;
static int crx, ctx;
#define DE_WCSR(csr, val) *(volatile u_short *)(addr + (csr)) = (val)
#define DE_WLOW(val) *(volatile u_char *)(addr + DE_PCSR0) = (val)
#define DE_WHIGH(val) *(volatile u_char *)(addr + DE_PCSR0 + 1) = (val)
#define DE_RCSR(csr) *(volatile u_short *)(addr + (csr))
#define LOWORD(x)       ((u_int)(x) & 0xffff)
#define HIWORD(x)       (((u_int)(x) >> 16) & 0x3)
#define	dereg(x)	((x) & 017777)

int
deopen(struct open_file *f, int adapt, int ctlr, int unit, int part)
{
	int i, cdata, *map, npgs;
	char eaddr[6];

	/* point to the device in memory */
	if (askname == 0) /* Override if autoboot */
		addr = (char *)bootrpb.csrphy;
	else {
		addr = (char *)csrbase + dereg(0174510);
		bootrpb.csrphy = (int)addr;
	}
#ifdef DEV_DEBUG
	printf("deopen: csrbase %x addr %p nexaddr %x\n",
	    csrbase, addr, nexaddr);
#endif
	/* reset the device and wait for completion */
	DE_WCSR(DE_PCSR0, 0);
	{volatile int j = 100; while (--j);}
	DE_WCSR(DE_PCSR0, PCSR0_RSET);
	dewait("reset");

	/* Map in the control structures and buffers */
	dc = alloc(sizeof(struct de_cdata));
	(int)pdc = (int)dc & VAX_PGOFSET;
	map = (int *)nexaddr + 512;
	npgs = (sizeof(struct de_cdata) >> VAX_PGSHIFT) + 1;
	cdata = (int)dc >> VAX_PGSHIFT;
	for (i = 0; i < npgs; i++) {
		map[i] = PG_V | (cdata + i);
	}

	bzero((char *)dc, sizeof(struct de_cdata));

	/* Tell the DEUNA about our PCB */
	DE_WCSR(DE_PCSR2, LOWORD(pdc));
	DE_WCSR(DE_PCSR3, HIWORD(pdc));
	DE_WLOW(CMD_GETPCBB);
	dewait("pcbb");

	/* Get our address */
	dc->dc_pcbb.pcbb0 = FC_RDPHYAD;
	DE_WLOW(CMD_GETCMD);
	dewait("read physaddr");
	bcopy((char *)&dc->dc_pcbb.pcbb2, eaddr, 6);

	/* Create and link the descriptors */
	for (i=0; i < NRCV; i++) {
		volatile struct de_ring *rp = &dc->dc_rrent[i];

		rp->r_lenerr = 0;
		rp->r_segbl = LOWORD(&pdc->dc_rbuf[i][0]);
		rp->r_segbh = HIWORD(&pdc->dc_rbuf[i][0]);
		rp->r_flags = RFLG_OWN;
		rp->r_slen = ETHER_MAX_LEN;
	}
	for (i=0; i < NXMT; i++) {
		volatile struct de_ring *rp = &dc->dc_xrent[i];

		rp->r_segbl = LOWORD(&pdc->dc_xbuf[i][0]);
		rp->r_segbh = HIWORD(&pdc->dc_xbuf[i][0]);
		rp->r_tdrerr = 0;
		rp->r_flags = 0;
	}
	crx = ctx = 0;

	/* set the transmit and receive ring header addresses */
	dc->dc_pcbb.pcbb0 = FC_WTRING;
	dc->dc_pcbb.pcbb2 = LOWORD(&pdc->dc_udbbuf);
	dc->dc_pcbb.pcbb4 = HIWORD(&pdc->dc_udbbuf);

	dc->dc_udbbuf.b_tdrbl = LOWORD(&pdc->dc_xrent[0]);
	dc->dc_udbbuf.b_tdrbh = HIWORD(&pdc->dc_xrent[0]);
	dc->dc_udbbuf.b_telen = sizeof (struct de_ring) / sizeof(u_int16_t);
	dc->dc_udbbuf.b_trlen = NXMT;
	dc->dc_udbbuf.b_rdrbl = LOWORD(&pdc->dc_rrent[0]);
	dc->dc_udbbuf.b_rdrbh = HIWORD(&pdc->dc_rrent[0]);
	dc->dc_udbbuf.b_relen = sizeof (struct de_ring) / sizeof(u_int16_t);
	dc->dc_udbbuf.b_rrlen = NRCV;

	DE_WLOW(CMD_GETCMD);
	dewait("wtring");

	dc->dc_pcbb.pcbb0 = FC_WTMODE;
	dc->dc_pcbb.pcbb2 = MOD_DRDC|MOD_TPAD|MOD_HDX;
	DE_WLOW(CMD_GETCMD);
	dewait("wtmode");

	DE_WLOW(CMD_START);
	dewait("start");

	DE_WLOW(CMD_PDMD);
	dewait("initpoll");
	/* Should be running by now */

	net_devinit(f, &de_driver, eaddr);

	return 0;
}

int
de_get(struct iodesc *desc, void *pkt, size_t maxlen, time_t timeout)
{
	volatile int to = 100000 * timeout;
	int len, csr0;

	if ((csr0 = DE_RCSR(DE_PCSR0)) & PCSR0_INTR)
		DE_WHIGH(csr0 >> 8);
retry:
	if (to-- == 0)
		return 0;

	if (dc->dc_rrent[crx].r_flags & RFLG_OWN)
		goto retry;

	if (dc->dc_rrent[crx].r_flags & RFLG_ERRS)
		len = 0;
	else
		len = dc->dc_rrent[crx].r_lenerr & RERR_MLEN;

	if (len > maxlen)
		len = maxlen;
	if (len)
		bcopy((char *)&dc->dc_rbuf[crx][0], pkt, len);

	dc->dc_rrent[crx].r_flags = RFLG_OWN;
	dc->dc_rrent[crx].r_lenerr = 0;
#ifdef DEV_DEBUG
	printf("Got packet: len %d idx %d maxlen %ld\n", len, crx, maxlen);
#endif
	if (++crx == NRCV)
		crx = 0;

	if (len == 0)
		goto retry;
	return len;
}

int
de_put(struct iodesc *desc, void *pkt, size_t len)
{
	volatile int to = 100000;
	int csr0;

	if ((csr0 = DE_RCSR(DE_PCSR0)) & PCSR0_INTR)
		DE_WHIGH(csr0 >> 8);
#ifdef DEV_DEBUG
	printf("de_put: len %ld\n", len);
#endif
retry:
	if (to-- == 0)
		return -1;

	if (dc->dc_xrent[ctx].r_flags & RFLG_OWN)
		goto retry;

	bcopy(pkt, (char *)&dc->dc_xbuf[ctx][0], len);

	dc->dc_xrent[ctx].r_slen = len;
	dc->dc_xrent[ctx].r_tdrerr = 0;
	dc->dc_xrent[ctx].r_flags = XFLG_OWN|XFLG_STP|XFLG_ENP;

	DE_WLOW(CMD_PDMD);
	dewait("start");

	if (++ctx == NXMT)
		ctx = 0;
	return len;
}

int
declose(struct open_file *f)
{
	DE_WCSR(DE_PCSR0, PCSR0_RSET);
	dewait("close");
	return 0;
}

void
dewait(char *fn)
{
	int csr0;

#ifdef DEV_DEBUG
	printf("dewait: %s...", fn);
#endif
	while ((DE_RCSR(DE_PCSR0) & PCSR0_INTR) == 0)
		;
	csr0 = DE_RCSR(DE_PCSR0);
	DE_WHIGH(csr0 >> 8);
#ifdef DEV_DEBUG
	if (csr0 & PCSR0_PCEI)
		printf("failed! CSR0 %x", csr0);
	else
		printf("done");
	printf(", PCSR1 %x\n", DE_RCSR(DE_PCSR1));
#endif
}


code:
/*	$OpenBSD: if_le.c,v 1.9 2014/08/21 14:24:08 mpi Exp $ */
/*	$NetBSD: if_le.c,v 1.6 2000/05/20 13:30:03 ragge Exp $ */
/*
 * Copyright (c) 1997, 1999 Ludd, University of Lule}, Sweden.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed at Ludd, University of
 *      Lule}, Sweden and its contributors.
 * 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.
 */

/*
 * Standalone routine for MicroVAX LANCE chip.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/socket.h>

#include <net/if.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>

#include <machine/sid.h>
#include <machine/rpb.h>

#include <lib/libsa/netif.h>
#include <lib/libsa/stand.h>

#include <arch/vax/mbus/mbusreg.h>
#include <arch/vax/mbus/fwioreg.h>

#include <dev/ic/lancereg.h>
#include <dev/ic/am7990reg.h>

#include "vaxstand.h"

/*
 * Buffer sizes.
 */
#define TLEN    1
#define NTBUF   (1 << TLEN)
#define RLEN    3
#define NRBUF   (1 << RLEN)
#define BUFSIZE 1518

#define ETHER_MIN_LEN   64      /* minimum frame length, including CRC */

#define	QW_ALLOC(x)	(((int)alloc((x) + 7) + 7) & ~7)

static int le_get(struct iodesc *, void *, size_t, time_t);
static int le_put(struct iodesc *, void *, size_t);
static void copyout(void *from, int dest, int len);
static void copyin(int src, void *to, int len);

struct netif_driver le_driver = {
	0, 0, 0, 0, le_get, le_put,
};

/*
 * Init block & buffer descriptors according to DEC system
 * specification documentation.
 */
struct initblock {
	short	ib_mode;
	char	ib_padr[6]; /* Ethernet address */
	int	ib_ladrf1;
	int	ib_ladrf2;
	int	ib_rdr; /* Receive address */
	int	ib_tdr; /* Transmit address */
} *initblock = NULL;

struct nireg {
	volatile u_short ni_rdp;       /* data port */
	volatile short ni_pad0;
	volatile short ni_rap;       /* register select port */
} *nireg;

volatile struct	buffdesc {
	int	bd_adrflg;
	short	bd_bcnt;
	short	bd_mcnt;
} *rdesc, *tdesc;

static	int addoff;
static	int lebufaddr;

/* Flags in the address field */
#define	BR_OWN	0x80000000
#define	BR_ERR	0x40000000
#define	BR_FRAM	0x20000000
#define	BR_OFLO	0x10000000
#define	BR_CRC	0x08000000
#define	BR_BUFF	0x04000000
#define	BR_STP	0x02000000
#define	BR_ENP	0x01000000

#define	BT_OWN	0x80000000
#define	BT_ERR	0x40000000
#define	BT_MORE	0x10000000
#define	BT_ONE	0x08000000
#define	BT_DEF	0x04000000
#define	BT_STP	0x02000000
#define	BT_ENP	0x01000000

int	next_rdesc, next_tdesc;

#define	LEWRCSR(port, val) { \
	nireg->ni_rap = (port); \
	nireg->ni_rdp = (val); \
}

#define	LERDCSR(port) \
	(nireg->ni_rap = port, nireg->ni_rdp)

int
leopen(struct open_file *f, int adapt, int ctlr, int unit, int part)
{
	int i, *ea;
	volatile int to = 100000;
	u_char eaddr[6];

	next_rdesc = next_tdesc = 0;

	if (vax_boardtype == VAX_BTYP_650 &&
	    vax_cpustype == VAX_STYP_640) {
		lebufaddr = 0x20120000;
		ea = (void *)0x20084200;
		nireg = (void *)0x20084400;
	} else if (vax_boardtype == VAX_BTYP_60) {
		extern int ka60_ioslot;
		lebufaddr = MBUS_SLOT_BASE(ka60_ioslot) + FWIO_LANCE_BUF_OFFSET;
		ea = (int *)(MBUS_SLOT_BASE(ka60_ioslot) + FWIO_ESAR_OFFSET);
		for (i = 0; i < 6; i++) {
			eaddr[i] = *(u_char *)((int)ea + 2);
			ea++;
		}
		ea = NULL;
		nireg = (void *)(MBUS_SLOT_BASE(ka60_ioslot) +
		    FWIO_LANCE_REG_OFFSET);
	} else {
		*(int *)0x20080014 = 0; /* Be sure we do DMA in low 16MB */
		ea = (void *)0x20090000; /* XXX Ethernet address */
		nireg = (void *)0x200e0000;
	}
	if (askname == 0) /* Override if autoboot */
		nireg = (void *)bootrpb.csrphy;
	else /* Tell kernel from where we booted */
		bootrpb.csrphy = (int)nireg;

	if (vax_boardtype == VAX_BTYP_43)
		addoff = 0x28000000;
	else
		addoff = 0;
igen:
	LEWRCSR(LE_CSR0, LE_C0_STOP);
	while (to--)
		;

	if (ea != NULL) {
		for (i = 0; i < 6; i++)
			eaddr[i] = ea[i] & 0377;
	}

	if (initblock == NULL) {
		(void *)initblock =
		    (char *)QW_ALLOC(sizeof(struct initblock)) + addoff;
		initblock->ib_mode = LE_MODE_NORMAL;
		bcopy(eaddr, initblock->ib_padr, 6);
		initblock->ib_ladrf1 = 0;
		initblock->ib_ladrf2 = 0;

		(int)rdesc = QW_ALLOC(sizeof(struct buffdesc) * NRBUF) + addoff;
		initblock->ib_rdr = (RLEN << 29) | (int)rdesc;
		if (lebufaddr)
			initblock->ib_rdr -= (int)initblock;
		(int)tdesc = QW_ALLOC(sizeof(struct buffdesc) * NTBUF) + addoff;
		initblock->ib_tdr = (TLEN << 29) | (int)tdesc;
		if (lebufaddr)
			initblock->ib_tdr -= (int)initblock;
		if (lebufaddr)
			copyout(initblock, 0, sizeof(struct initblock));

		for (i = 0; i < NRBUF; i++) {
			rdesc[i].bd_adrflg = QW_ALLOC(BUFSIZE) | BR_OWN;
			if (lebufaddr)
				rdesc[i].bd_adrflg -= (int)initblock;
			rdesc[i].bd_bcnt = -BUFSIZE;
			rdesc[i].bd_mcnt = 0;
		}
		if (lebufaddr)
			copyout((void *)rdesc, (int)rdesc - (int)initblock,
			    sizeof(struct buffdesc) * NRBUF);

		for (i = 0; i < NTBUF; i++) {
			tdesc[i].bd_adrflg = QW_ALLOC(BUFSIZE);
			if (lebufaddr)
				tdesc[i].bd_adrflg -= (int)initblock;
			tdesc[i].bd_bcnt = 0xf000;
			tdesc[i].bd_mcnt = 0;
		}
		if (lebufaddr)
			copyout((void *)tdesc, (int)tdesc - (int)initblock,
			    sizeof(struct buffdesc) * NTBUF);
	}

	if (lebufaddr) {
		LEWRCSR(LE_CSR1, 0);
		LEWRCSR(LE_CSR2, 0);
	} else {
		LEWRCSR(LE_CSR1, (int)initblock & 0xffff);
		LEWRCSR(LE_CSR2, ((int)initblock >> 16) & 0xff);
	}

	LEWRCSR(LE_CSR0, LE_C0_INIT);

	to = 100000;
	while (to--) {
		if (LERDCSR(LE_CSR0) & LE_C0_IDON)
			break;
		if (LERDCSR(LE_CSR0) & LE_C0_ERR) {
			printf("lance init error: csr0 %x\n", LERDCSR(LE_CSR0));
			goto igen;
		}
	}

	LEWRCSR(LE_CSR0, LE_C0_INEA | LE_C0_STRT | LE_C0_IDON);

	net_devinit(f, &le_driver, eaddr);
	return 0;
}

int
le_get(struct iodesc *desc, void *pkt, size_t maxlen, time_t timeout)
{
	int csr, len;
	volatile int to = 100000 * timeout;

retry:
	if (to-- == 0)
		return 0;

	csr = LERDCSR(LE_CSR0);
	LEWRCSR(LE_CSR0, csr & (LE_C0_BABL|LE_C0_MISS|LE_C0_MERR|LE_C0_RINT));

	if (lebufaddr)
		copyin((int)&rdesc[next_rdesc] - (int)initblock,
		    (void *)&rdesc[next_rdesc], sizeof(struct buffdesc));
	if (rdesc[next_rdesc].bd_adrflg & BR_OWN)
		goto retry;

        if (rdesc[next_rdesc].bd_adrflg & BR_ERR)
                len = 0;
        else {
		if ((len = rdesc[next_rdesc].bd_mcnt - 4) > maxlen)
			len = maxlen;

		if (lebufaddr)
			copyin((rdesc[next_rdesc].bd_adrflg&0xffffff),
			    pkt, len);
		else
			bcopy((char *)(rdesc[next_rdesc].bd_adrflg&0xffffff) +
			    addoff, pkt, len);
	}

	rdesc[next_rdesc].bd_mcnt = 0;
	rdesc[next_rdesc].bd_adrflg |= BR_OWN;
	if (lebufaddr)
		copyout((void *)&rdesc[next_rdesc], (int)&rdesc[next_rdesc] -
		    (int)initblock, sizeof(struct buffdesc));
	if (++next_rdesc >= NRBUF)
		next_rdesc = 0;

	if (len == 0)
		goto retry;
	return len;
}

int
le_put(struct iodesc *desc, void *pkt, size_t len)
{
	volatile int to = 100000;
	int csr;

retry:
	if (--to == 0)
		return -1;

	csr = LERDCSR(LE_CSR0);
	LEWRCSR(LE_CSR0, csr & (LE_C0_MISS|LE_C0_CERR|LE_C0_TINT));

	if (lebufaddr)
		copyin((int)&tdesc[next_tdesc] - (int)initblock,
		    (void *)&tdesc[next_tdesc], sizeof(struct buffdesc));
	if (tdesc[next_tdesc].bd_adrflg & BT_OWN)
		goto retry;

	if (lebufaddr)
		copyout(pkt, (tdesc[next_tdesc].bd_adrflg & 0xffffff), len);
	else
		bcopy(pkt, (char *)(tdesc[next_tdesc].bd_adrflg & 0xffffff) +
		    addoff, len);
	tdesc[next_tdesc].bd_bcnt =
	    (len < ETHER_MIN_LEN ? -ETHER_MIN_LEN : -len);
	tdesc[next_tdesc].bd_mcnt = 0;
	tdesc[next_tdesc].bd_adrflg |= BT_OWN | BT_STP | BT_ENP;
	if (lebufaddr)
		copyout((void *)&tdesc[next_tdesc], (int)&tdesc[next_tdesc] -
		    (int)initblock, sizeof(struct buffdesc));

	LEWRCSR(LE_CSR0, LE_C0_TDMD);

	to = 100000;
	while (((LERDCSR(LE_CSR0) & LE_C0_TINT) == 0) && --to)
		;

	LEWRCSR(LE_CSR0, LE_C0_TINT);
	if (++next_tdesc >= NTBUF)
		next_tdesc = 0;

	if (to)
		return len;

	return -1;
}

int
leclose(struct open_file *f)
{
	LEWRCSR(LE_CSR0, LE_C0_STOP);

	return 0;
}

void
copyout(void *f, int dest, int len)
{
	if (vax_boardtype == VAX_BTYP_60) {
		u_char *from = f;
		u_char *toaddr = (u_char *)lebufaddr + dest;

		while (len-- > 0)
			*toaddr++ = *from++;
	} else {
		short *from = f;
		short *toaddr;

		toaddr = (short *)lebufaddr + dest;

		while (len > 0) {
			*toaddr = *from++;
			toaddr += 2;
			len -= 2;
		}
	}
}

void
copyin(int src, void *f, int len)
{
	if (vax_boardtype == VAX_BTYP_60) {
		u_char *to = f;
		u_char *fromaddr;

		fromaddr = (u_char *)lebufaddr + src;

		while (len-- > 0)
			*to++ = *fromaddr++;
	} else {
		short *to = f;
		short *fromaddr;

		fromaddr = (short *)lebufaddr + src;

		while (len > 0) {
			*to++ = *fromaddr;
			fromaddr += 2;
			len -= 2;
		}
	}
}


code:
/*	$OpenBSD: if_qe.c,v 1.4 2014/08/21 14:24:08 mpi Exp $ */
/*	$NetBSD: if_qe.c,v 1.3 2000/05/20 13:30:03 ragge Exp $ */

/*
 * Copyright (c) 1998 Roar Thron�s.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Roar Thron�s.
 * 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.
 *
 *	Standalone routine for the DEQNA.
 */

#include <sys/param.h>
#include <sys/types.h>

#include <netinet/in.h>

#include <lib/libsa/netif.h>
#include <lib/libsa/stand.h>

#include <arch/vax/if/if_qereg.h>

#include "../include/rpb.h"

#include "vaxstand.h"

static int qe_get(struct iodesc *desc, void *pkt, size_t, time_t timeout);
static int qe_put(struct iodesc *desc, void *pkt, size_t);
static void qe_init(u_char *eaddr);

struct netif_driver qe_driver = {
	0, 0, 0, 0, qe_get, qe_put,
};

#define NRCV	1		       /* Receive descriptors	       */
#define NXMT	1			/* Transmit descriptors		*/

#define QE_INTS	       (QE_RCV_INT | QE_XMIT_INT)
#define MAXPACKETSIZE  0x800		/* Because of (buggy) DEQNA */

static struct  qe_softc {
	struct	qe_ring rring[NRCV+2];	/* Receive ring descriptors	*/
	struct	qe_ring tring[NXMT+2];	/* Xmit ring descriptors	*/
	u_char	setup_pkt[16][8];	/* Setup packet			*/
	char	qein[2048], qeout[2048];/* Packet buffers		*/
} qe_softc;

static	struct qe_softc *sc = &qe_softc;
static	int addr;

#define QE_WCSR(csr, val) \
	(*((volatile u_short *)(addr + (csr))) = (val))
#define QE_RCSR(csr) \
	*((volatile u_short *)(addr + (csr)))
#define DELAY(x)		{volatile int i = x;while (--i);}
#define LOWORD(x)	((int)(x) & 0xffff)
#define HIWORD(x)	(((int)(x) >> 16) & 0x3f)
#define qereg(x) ((x) & 017777)

int
qeopen(struct open_file *f, int adapt, int ctlr, int unit, int part) {
	u_char eaddr[6];

	if (askname == 0)
		addr = bootrpb.csrphy;	/* Autoboot; use RPB instead */
	else {
		addr = 0x20000000;
		if (unit == 0)
			addr += qereg(0774440); /* XQA0 */
		else if (unit == 1)
			addr += qereg(0174460); /* XQB0 */
		else
			return ECTLR;
	}

	qe_init(eaddr);

	net_devinit(f, &qe_driver, eaddr);
	return 0;
}

void
qe_init(u_char *eaddr)
{
	int i,j;

	QE_WCSR(QE_CSR_CSR, QE_RESET);
	QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) & ~QE_RESET);

	for (i = 0; i < 6; i++) {
		sc->setup_pkt[i][1] = QE_RCSR(i * 2);
		sc->setup_pkt[i+8][1] = QE_RCSR(i * 2);
		sc->setup_pkt[i][2] = 0xff;
		sc->setup_pkt[i+8][2] = QE_RCSR(i * 2);
		for (j=3; j < 8; j++) {
			sc->setup_pkt[i][j] = QE_RCSR(i * 2);
			sc->setup_pkt[i+8][j] = QE_RCSR(i * 2);
		}
		eaddr[i] = QE_RCSR(i * 2);
	}

	bzero((caddr_t)sc->rring, sizeof(struct qe_ring));
	sc->rring->qe_buf_len = -64;
	sc->rring->qe_addr_lo = (short)((int)sc->setup_pkt);
	sc->rring->qe_addr_hi = (short)((int)sc->setup_pkt >> 16);

	bzero((caddr_t)sc->tring, sizeof(struct qe_ring));
	sc->tring->qe_buf_len = -64;
	sc->tring->qe_addr_lo = (short)((int)sc->setup_pkt);
	sc->tring->qe_addr_hi = (short)((int)sc->setup_pkt >> 16);

	sc->rring[0].qe_flag = sc->rring[0].qe_status1 = QE_NOTYET;
	sc->rring->qe_addr_hi |= QE_VALID;

	sc->tring[0].qe_flag = sc->tring[0].qe_status1 = QE_NOTYET;
	sc->tring->qe_addr_hi |= QE_VALID | QE_SETUP | QE_EOMSG;

	QE_WCSR(QE_CSR_CSR, QE_XMIT_INT | QE_RCV_INT);

	QE_WCSR(QE_CSR_RCLL, LOWORD(sc->rring));
	QE_WCSR(QE_CSR_RCLH, HIWORD(sc->rring));
	QE_WCSR(QE_CSR_XMTL, LOWORD(sc->tring));
	QE_WCSR(QE_CSR_XMTH, HIWORD(sc->tring));

	while ((QE_RCSR(QE_CSR_CSR) & QE_INTS) != QE_INTS)
		;
	QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) | QE_INTS);
	QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) & ~(QE_INT_ENABLE|QE_ELOOP));
	QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) | QE_ILOOP);

	sc->rring[0].qe_addr_lo = (short)((int)sc->qein & 0xffff);
	sc->rring[0].qe_addr_hi = (short)((int)sc->qein >> 16);
	sc->rring[0].qe_buf_len=-MAXPACKETSIZE/2;
	sc->rring[0].qe_addr_hi |= QE_VALID;
	sc->rring[0].qe_flag=sc->rring[0].qe_status1=QE_NOTYET;
	sc->rring[0].qe_status2=1;

	sc->rring[1].qe_addr_lo = 0;
	sc->rring[1].qe_addr_hi = 0;
	sc->rring[1].qe_flag=sc->rring[1].qe_status1=QE_NOTYET;
	sc->rring[1].qe_status2=1;

	sc->tring[0].qe_addr_lo = (short)((int)sc->qeout & 0xffff);
	sc->tring[0].qe_addr_hi = (short)((int)sc->qeout >> 16);
	sc->tring[0].qe_buf_len=0;
	sc->tring[0].qe_flag=sc->tring[0].qe_status1=QE_NOTYET;
	sc->tring[0].qe_addr_hi |= QE_EOMSG|QE_VALID;

	sc->tring[1].qe_flag=sc->tring[1].qe_status1=QE_NOTYET;
	sc->tring[1].qe_addr_lo = 0;
	sc->tring[1].qe_addr_hi = 0;

	QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) | QE_RCV_ENABLE);
	QE_WCSR(QE_CSR_RCLL, LOWORD(sc->rring));
	QE_WCSR(QE_CSR_RCLH, HIWORD(sc->rring));
}

int
qe_get(struct iodesc *desc, void *pkt, size_t maxlen, time_t timeout) {
	int len, j;

retry:
	for(j = 0x10000;j && (QE_RCSR(QE_CSR_CSR) & QE_RCV_INT) == 0; j--)
		;

	if ((QE_RCSR(QE_CSR_CSR) & QE_RCV_INT) == 0)
		goto fail;

	QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) & ~(QE_RCV_ENABLE|QE_XMIT_INT));

	len= ((sc->rring[0].qe_status1 & QE_RBL_HI) |
	    (sc->rring[0].qe_status2 & QE_RBL_LO)) + 60;

	if (sc->rring[0].qe_status1 & 0xc000)
		goto fail;

	if (len == 0)
		goto retry;

	bcopy((void*)sc->qein,pkt,len);

end:
	sc->rring[0].qe_status2 = sc->rring[1].qe_status2 = 1;
	sc->rring[0].qe_flag=sc->rring[0].qe_status1=QE_NOTYET;
	sc->rring[1].qe_flag=sc->rring[1].qe_status1=QE_NOTYET;
	QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) | QE_RCV_ENABLE);

	QE_WCSR(QE_CSR_RCLL, LOWORD(sc->rring));
	QE_WCSR(QE_CSR_RCLH, HIWORD(sc->rring));
	return len;

fail:	len = -1;
	goto end;
}

int
qe_put(struct iodesc *desc, void *pkt, size_t len) {
	int j;

	bcopy(pkt, (char *)sc->qeout, len);
	sc->tring[0].qe_buf_len=-len/2;
	sc->tring[0].qe_flag=sc->tring[0].qe_status1=QE_NOTYET;
	sc->tring[1].qe_flag=sc->tring[1].qe_status1=QE_NOTYET;

	QE_WCSR(QE_CSR_XMTL, LOWORD(sc->tring));
	QE_WCSR(QE_CSR_XMTH, HIWORD(sc->tring));

	for(j = 0; (j < 0x10000) && ((QE_RCSR(QE_CSR_CSR) & QE_XMIT_INT) == 0); j++)
		;

	if ((QE_RCSR(QE_CSR_CSR) & QE_XMIT_INT) == 0) {
		char eaddr[6];

		qe_init(eaddr);
		return -1;
	}
	QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) & ~QE_RCV_INT);

	if (sc->tring[0].qe_status1 & 0xc000) {
		char eaddr[6];

		qe_init(eaddr);
		return -1;
	}
	return len;
}

int
qeclose(struct open_file *nif)
{
	QE_WCSR(QE_CSR_CSR, QE_RESET);
	QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) & ~QE_RESET);

	return 0;
}


code:
/*	$OpenBSD: if_ze.c,v 1.6 2014/08/21 14:24:08 mpi Exp $ */
/*	$NetBSD: if_ze.c,v 1.12 2002/05/27 16:54:18 ragge Exp $	*/
/*
 * Copyright (c) 1998 James R. Maynard III.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by James R. Maynard III.
 * 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.
 *
 *	Standalone routine for the SGEC Ethernet controller.
 */

#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/queue.h>

#include <net/if.h>

#include <netinet/in.h>
#include <netinet/if_ether.h>

#include <lib/libsa/netif.h>
#include <lib/libsa/stand.h>
#include <lib/libsa/net.h>

#include <arch/vax/if/sgecreg.h>

#include "arch/vax/include/sid.h"
#include "arch/vax/include/rpb.h"

#include "vaxstand.h"

static int ze_get(struct iodesc *, void *, size_t, time_t);
static int ze_put(struct iodesc *, void *, size_t);

#define ETHER_MIN_LEN 64
#define ETHER_MAX_LEN 1518

struct netif_driver ze_driver = {
	0, 0, 0, 0, ze_get, ze_put,
};

#define NRCV 8				/* allocate 8 receive descriptors */
#define NXMT 4				/* and 4 transmit - must be >1 */
#define SETUP_FRAME_LEN 128		/* length of the setup frame */

/* allocate a buffer on an octaword boundary */
#define OW_ALLOC(x) ((void *)((int)((int)alloc((x) + 15) + 15) & ~15))

static	volatile struct zedevice *addr;

struct ze_tdes *ze_tdes_list;	/* transmit desc list */
struct ze_rdes *ze_rdes_list;	/* and receive desc list */
u_char ze_myaddr[ETHER_ADDR_LEN];	/* my Ethernet address */

int
zeopen(struct open_file *f, int adapt, int ctlr, int unit, int part)
{
	u_long nicsr0_work, *nisa_rom;
	struct ze_tdes *ze_setup_tdes_list;
	int i;

	/* point to the device in memory */
	if (askname == 0) /* Override if autoboot */
		addr = (struct zedevice *)bootrpb.csrphy;
	else
		addr = (struct zedevice *)0x20008000;

	/* reset the device and wait for completion */
	addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_RE;
	while ((addr->ze_nicsr5 & ZE_NICSR5_ID) == 0)
		;
	if (addr->ze_nicsr5 & ZE_NICSR5_SF) {
		printf("SGEC self-test failed...\n");
		return 1;
	}

	/* Get our Ethernet address */
	if (vax_boardtype == VAX_BTYP_49) {
		nisa_rom = (u_long *)0x27800000;
		for (i=0; i<ETHER_ADDR_LEN; i++)
			ze_myaddr[i] = nisa_rom[i] & 0377;
	} else if (vax_boardtype == VAX_BTYP_VXT) {
		nisa_rom = (u_long *)0x200c4000;
		for (i=0; i<ETHER_ADDR_LEN; i++)
			ze_myaddr[i] = nisa_rom[i] & 0xff;
	} else {
		nisa_rom = (u_long *)0x20084000;
		for (i=0; i<ETHER_ADDR_LEN; i++)
			if (vax_boardtype == VAX_BTYP_660)
				ze_myaddr[i] = (nisa_rom[i] & 0xff000000) >> 24;
			else
				ze_myaddr[i] = (nisa_rom[i] & 0x0000ff00) >> 8;
	}
	printf("SGEC: Ethernet address %s", ether_sprintf(ze_myaddr));

	/* initialize SGEC operating mode */
	/* disable interrupts here */
	nicsr0_work = ZE_NICSR0_IPL14 | ZE_NICSR0_SA | ZE_NICSR0_MBO |
		(ZE_NICSR0_IV_MASK & 0x0108);
	do {
		addr->ze_nicsr0 = nicsr0_work;
	} while (addr->ze_nicsr0 != nicsr0_work);
	if (addr->ze_nicsr5 & ZE_NICSR5_ME)
		addr->ze_nicsr5 |= ZE_NICSR5_ME;
	/* reenable interrupts here */

	/* Allocate space for descriptor lists and buffers,
		then initialize them. Set up both lists as a ring. */
	ze_rdes_list = OW_ALLOC((NRCV+1) * sizeof(struct ze_rdes));
	ze_tdes_list = OW_ALLOC((NXMT+1) * sizeof(struct ze_tdes));
	for (i=0; i < NRCV; i++) {
		bzero(ze_rdes_list+i,sizeof(struct ze_rdes));
		ze_rdes_list[i].ze_framelen = ZE_FRAMELEN_OW;
		ze_rdes_list[i].ze_bufsize = ETHER_MAX_LEN;
		ze_rdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
	}
	bzero(ze_rdes_list+NRCV,sizeof(struct ze_rdes));
	ze_rdes_list[NRCV].ze_framelen = ZE_FRAMELEN_OW;
	ze_rdes_list[NRCV].ze_rdes1 = ZE_RDES1_CA;
	ze_rdes_list[NRCV].ze_bufaddr = (u_char *)ze_rdes_list;
	for (i=0; i < NXMT; i++) {
		bzero(ze_tdes_list+i,sizeof(struct ze_tdes));
		ze_tdes_list[i].ze_tdes1 = ZE_TDES1_FS | ZE_TDES1_LS;
		ze_tdes_list[i].ze_bufsize = ETHER_MAX_LEN;
		ze_tdes_list[i].ze_bufaddr = alloc(ETHER_MAX_LEN);
	}
	bzero(ze_tdes_list+NXMT,sizeof(struct ze_tdes));
	ze_tdes_list[NXMT].ze_tdes1 = ZE_TDES1_CA;
	ze_tdes_list[NXMT].ze_tdr = ZE_TDR_OW;
	ze_tdes_list[NXMT].ze_bufaddr = (u_char *)ze_tdes_list;

	printf(".");	/* XXX VXT */

	/* Build setup frame. We set the SGEC to do a
		perfect filter on our own address. */
	ze_setup_tdes_list = OW_ALLOC(2*sizeof(struct ze_tdes));
	bzero(ze_setup_tdes_list+0,2*sizeof(struct ze_tdes));
	ze_setup_tdes_list[0].ze_tdr = ZE_TDR_OW;
	ze_setup_tdes_list[0].ze_tdes1 = ZE_TDES1_DT_SETUP;
	ze_setup_tdes_list[0].ze_bufsize = SETUP_FRAME_LEN;
	ze_setup_tdes_list[0].ze_bufaddr = alloc(SETUP_FRAME_LEN);
	bzero(ze_setup_tdes_list[0].ze_bufaddr,SETUP_FRAME_LEN);
	for (i=0; i < 16; i++)
		bcopy(ze_myaddr,ze_setup_tdes_list[0].ze_bufaddr+(8*i),
			ETHER_ADDR_LEN);
	ze_setup_tdes_list[1].ze_tdes1 = ZE_TDES1_CA;
	ze_setup_tdes_list[1].ze_bufaddr = (u_char *)ze_setup_tdes_list;

	printf(".");	/* XXX VXT */

	/* Start the transmitter and initialize almost everything else. */
	addr->ze_nicsr4 = ze_setup_tdes_list;
	addr->ze_nicsr6 = ZE_NICSR6_MBO | ZE_NICSR6_SE | ZE_NICSR6_ST |
		ZE_NICSR6_DC | ZE_NICSR6_BL_4;
	while ((addr->ze_nicsr5 & ZE_NICSR5_TS) != ZE_NICSR5_TS_SUSP)
		;	/* wait for the frame to be processed */

	printf(".");	/* XXX VXT */

	/* Setup frame is done processing, initialize the receiver and
		point the transmitter to the real tdes list. */
	addr->ze_nicsr4 = ze_tdes_list;
	addr->ze_nicsr3 = ze_rdes_list;
	addr->ze_nicsr6 |= ZE_NICSR6_SR;

	/* And away-y-y we go! */

	printf("\n");
	net_devinit(f, &ze_driver, ze_myaddr);
	return 0;
}

int
ze_get(desc, pkt, maxlen, timeout)
	struct iodesc *desc;
	void *pkt;
	size_t maxlen;
	time_t timeout;
{
	int timeout_ctr=100000*timeout, len, rdes;

	while (timeout_ctr-- > 0) {

	/* If there's not a packet waiting for us, just decrement the
		timeout counter. */
		if (!(addr->ze_nicsr5 & ZE_NICSR5_RI))
			continue;

	/* Look through the receive descriptor list for the packet. */
		for (rdes=0; rdes<NRCV; rdes++) {
			if (ze_rdes_list[rdes].ze_framelen & ZE_FRAMELEN_OW)
				continue;

	/* If the packet has an error, ignore it. */
			if (ze_rdes_list[rdes].ze_rdes0 & ZE_RDES0_ES)
				len = 0;

	/* Copy the packet, up to the length supplied by the caller, to
		the caller's buffer. */
			else {
				if ((len = (ze_rdes_list[rdes].ze_framelen &
					(~ ZE_FRAMELEN_OW))) > maxlen)
					len = maxlen;
				bcopy((void *)ze_rdes_list[rdes].ze_bufaddr,
					pkt,len);
			}

	/* Give ownership of this descriptor back to the SGEC. */
			ze_rdes_list[rdes].ze_framelen = ZE_FRAMELEN_OW;

	/* If we actually got a good packet, reset the error flags and
		tell the SGEC to look for more before returning. */
			if (len > 0) {
				addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI |
					ZE_NICSR5_IS;
				addr->ze_nicsr2=ZE_NICSR2_RXPD;
				return len;
			}
		}
	}

	/* If we're going to return an error indication, at least reset the
		error flags and tell the SGEC to keep receiving first. */
	addr->ze_nicsr5=ZE_NICSR5_RU | ZE_NICSR5_RI | ZE_NICSR5_IS;
	addr->ze_nicsr2=ZE_NICSR2_RXPD;
	return 0;
}

int
ze_put(desc, pkt, len)
	struct iodesc *desc;
	void *pkt;
	size_t len;
{
	int timeout=100000;

	/* The SGEC maintains its position in the transmit descriptor list
	for the next frame to transmit. Unfortunately, there's no way to tell
	from software just where that is. We're forced to reset the position
	whenever we send a frame, which requires waiting for the previous
	frame to be sent. Argh. */
	while ((addr->ze_nicsr5 & ZE_NICSR5_TS) == ZE_NICSR5_TS_RUN)
		;

	/* Copy the packet to the buffer we allocated. */
	bcopy(pkt, (void *)ze_tdes_list[0].ze_bufaddr, len);

	/* Set the packet length in the descriptor, increasing it to the
		minimum size if needed. */
	ze_tdes_list[0].ze_bufsize = len;
	if (len < ETHER_MIN_LEN)
		ze_tdes_list[0].ze_bufsize = ETHER_MIN_LEN;

	/* Give ownership of the descriptor to the SGEC and tell it to start
		transmitting. */
	ze_tdes_list[0].ze_tdr = ZE_TDR_OW;
	addr->ze_nicsr4 = ze_tdes_list;
	addr->ze_nicsr1 = ZE_NICSR1_TXPD;

	/* Wait for the frame to be sent, but not too long. */
	timeout = 100000;
	while (((addr->ze_nicsr5 & ZE_NICSR5_TI) == 0) && (--timeout>0))
		;

	/* Reset the transmitter interrupt pending flag. */
	addr->ze_nicsr5 |= ZE_NICSR5_TI;

	/* Return good if we didn't timeout, or error if we did. */
	if (timeout>0) return len;
	return -1;
}

int
zeclose(struct open_file *f)
{
	addr->ze_nicsr6 = ZE_NICSR6_RE;

	return 0;
}