code:
/*	$OpenBSD: if_dereg.h,v 1.4 2003/06/02 23:27:57 millert Exp $	*/
/*	$NetBSD: if_dereg.h,v 1.3 1996/04/08 18:34:55 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.
 *
 *	@(#)if_dereg.h	7.3 (Berkeley) 6/28/90
 */

/*
 * DEC DEUNA interface
 */
struct dedevice {
	union {
		short	p0_w;
		char	p0_b[2];
	} u_p0;
#define	pcsr0	u_p0.p0_w
#define	pclow		u_p0.p0_b[0]
#define	pchigh		u_p0.p0_b[1]
	short	pcsr1;
	short	pcsr2;
	short	pcsr3;
};

/*
 * PCSR 0 bit descriptions
 */
#define	PCSR0_SERI	0x8000		/* Status error interrupt */
#define	PCSR0_PCEI	0x4000		/* Port command error interrupt */
#define	PCSR0_RXI	0x2000		/* Receive done interrupt */
#define	PCSR0_TXI	0x1000		/* Transmit done interrupt */
#define	PCSR0_DNI	0x0800		/* Done interrupt */
#define	PCSR0_RCBI	0x0400		/* Receive buffer unavail intrpt */
#define	PCSR0_FATI	0x0100		/* Fatal error interrupt */
#define	PCSR0_INTR	0x0080		/* Interrupt summary */
#define	PCSR0_INTE	0x0040		/* Interrupt enable */
#define	PCSR0_RSET	0x0020		/* DEUNA reset */
#define	PCSR0_CMASK	0x000f		/* command mask */

#define	PCSR0_BITS	"\20\20SERI\17PCEI\16RXI\15TXI\14DNI\13RCBI\11FATI\10INTR\7INTE\6RSET"

/* bits 0-3 are for the PORT_COMMAND */
#define	CMD_NOOP	0x0
#define	CMD_GETPCBB	0x1		/* Get PCB Block */
#define	CMD_GETCMD	0x2		/* Execute command in PCB */
#define	CMD_STEST	0x3		/* Self test mode */
#define	CMD_START	0x4		/* Reset xmit and receive ring ptrs */
#define	CMD_BOOT	0x5		/* Boot DEUNA */
#define	CMD_PDMD	0x8		/* Polling demand */
#define	CMD_TMRO	0x9		/* Sanity timer on */
#define	CMD_TMRF	0xa		/* Sanity timer off */
#define	CMD_RSTT	0xb		/* Reset sanity timer */
#define	CMD_STOP	0xf		/* Suspend operation */

/*
 * PCSR 1 bit descriptions
 */
#define	PCSR1_XPWR	0x8000		/* Transceiver power BAD */
#define	PCSR1_ICAB	0x4000		/* Interconnect cabling BAD */
#define	PCSR1_STCODE	0x3f00		/* Self test error code */
#define	PCSR1_PCTO	0x0080		/* Port command timed out */
#define	PCSR1_ILLINT	0x0040		/* Illegal interrupt */
#define	PCSR1_TIMEOUT	0x0020		/* Timeout */
#define	PCSR1_POWER	0x0010		/* Power fail */
#define	PCSR1_RMTC	0x0008		/* Remote console reserved */
#define	PCSR1_STMASK	0x0007		/* State */

/* bit 0-3 are for STATE */
#define	STAT_RESET	0x0
#define	STAT_PRIMLD	0x1		/* Primary load */
#define	STAT_READY	0x2
#define	STAT_RUN	0x3
#define	STAT_UHALT	0x5		/* UNIBUS halted */
#define	STAT_NIHALT	0x6		/* NI halted */
#define	STAT_NIUHALT	0x7		/* NI and UNIBUS Halted */

#define	PCSR1_BITS	"\20\20XPWR\17ICAB\10PCTO\7ILLINT\6TIMEOUT\5POWER\4RMTC"

/*
 * Port Control Block Base
 */
struct de_pcbb {
	short	pcbb0;		/* function */
	short	pcbb2;		/* command specific */
	short	pcbb4;
	short	pcbb6;
};

/* PCBB function codes */
#define	FC_NOOP		0x00		/* NO-OP */
#define	FC_LSUADDR	0x01		/* Load and start microaddress */
#define	FC_RDDEFAULT	0x02		/* Read default physical address */
#define	FC_RDPHYAD	0x04		/* Read physical address */
#define	FC_WTPHYAD	0x05		/* Write physical address */
#define	FC_RDMULTI	0x06		/* Read multicast address list */
#define	FC_WTMULTI	0x07		/* Read multicast address list */
#define	FC_RDRING	0x08		/* Read ring format */
#define	FC_WTRING	0x09		/* Write ring format */
#define	FC_RDCNTS	0x0a		/* Read counters */
#define	FC_RCCNTS	0x0b		/* Read and clear counters */
#define	FC_RDMODE	0x0c		/* Read mode */
#define	FC_WTMODE	0x0d		/* Write mode */
#define	FC_RDSTATUS	0x0e		/* Read port status */
#define	FC_RCSTATUS	0x0f		/* Read and clear port status */
#define	FC_DUMPMEM	0x10		/* Dump internal memory */
#define	FC_LOADMEM	0x11		/* Load internal memory */
#define	FC_RDSYSID	0x12		/* Read system ID parameters */
#define	FC_WTSYSID	0x13		/* Write system ID parameters */
#define	FC_RDSERAD	0x14		/* Read load server address */
#define	FC_WTSERAD	0x15		/* Write load server address */

/*
 * Unibus Data Block Base (UDBB) for ring buffers
 */
struct de_udbbuf {
	short	b_tdrbl;	/* Transmit desc ring base low 16 bits */
	char	b_tdrbh;	/* Transmit desc ring base high 2 bits */
	char	b_telen;	/* Length of each transmit entry */
	short	b_trlen;	/* Number of entries in the XMIT desc ring */
	short	b_rdrbl;	/* Receive desc ring base low 16 bits */
	char	b_rdrbh;	/* Receive desc ring base high 2 bits */
	char	b_relen;	/* Length of each receive entry */
	short	b_rrlen;	/* Number of entries in the RECV desc ring */
};

/*
 * Transmit/Receive Ring Entry
 */
struct de_ring {
	short	r_slen;			/* Segment length */
	short	r_segbl;		/* Segment address (low 16 bits) */
	char	r_segbh;		/* Segment address (hi 2 bits) */
	u_char	r_flags;		/* Status flags */
	u_short	r_tdrerr;		/* Errors */
#define	r_lenerr	r_tdrerr
	short	r_rid;			/* Request ID */
};

#define	XFLG_OWN	0x80		/* If 0 then owned by driver */
#define	XFLG_ERRS	0x40		/* Error summary */
#define	XFLG_MTCH	0x20		/* Address match on xmit request */
#define	XFLG_MORE	0x10		/* More than one entry required */
#define	XFLG_ONE	0x08		/* One collision encountered */
#define	XFLG_DEF	0x04		/* Transmit deferred */
#define	XFLG_STP	0x02		/* Start of packet */
#define	XFLG_ENP	0x01		/* End of packet */

#define	XFLG_BITS	"\10\10OWN\7ERRS\6MTCH\5MORE\4ONE\3DEF\2STP\1ENP"

#define	XERR_BUFL	0x8000		/* Buffer length error */
#define	XERR_UBTO	0x4000		/* UNIBUS tiemout */
#define	XERR_LCOL	0x1000		/* Late collision */
#define	XERR_LCAR	0x0800		/* Loss of carrier */
#define	XERR_RTRY	0x0400		/* Failed after 16 retries */
#define	XERR_TDR	0x03ff		/* TDR value */

#define	XERR_BITS	"\20\20BUFL\17UBTO\15LCOL\14LCAR\13RTRY"

#define	RFLG_OWN	0x80		/* If 0 then owned by driver */
#define	RFLG_ERRS	0x40		/* Error summary */
#define	RFLG_FRAM	0x20		/* Framing error */
#define	RFLG_OFLO	0x10		/* Message overflow */
#define	RFLG_CRC	0x08		/* CRC error */
#define	RFLG_STP	0x02		/* Start of packet */
#define	RFLG_ENP	0x01		/* End of packet */

#define	RFLG_BITS	"\10\10OWN\7ERRS\6FRAM\5OFLO\4CRC\2STP\1ENP"

#define	RERR_BUFL	0x8000		/* Buffer length error */
#define	RERR_UBTO	0x4000		/* UNIBUS tiemout */
#define	RERR_NCHN	0x2000		/* No data chaining */
#define	RERR_MLEN	0x0fff		/* Message length */

#define	RERR_BITS	"\20\20BUFL\17UBTO\16NCHN"

/* mode description bits */
#define	MOD_HDX		0x0001		/* Half duplex mode */
#define	MOD_LOOP	0x0004		/* Enable internal loopback */
#define	MOD_DTCR	0x0008		/* Disables CRC generation */
#define	MOD_DMNT	0x0200		/* Disable maintenance features */
#define	MOD_ECT		0x0400		/* Enable collision test */
#define	MOD_TPAD	0x1000		/* Transmit message pad enable */
#define	MOD_DRDC	0x2000		/* Disable data chaining */
#define	MOD_ENAL	0x4000		/* Enable all multicast */
#define	MOD_PROM	0x8000		/* Enable promiscuous mode */

struct	de_buf {
	struct ether_header db_head;	/* header */
	char	db_data[ETHERMTU];	/* packet data */
	int	db_crc;			/* CRC - on receive only */
};


code:
/*	$OpenBSD: if_le.c,v 1.19 2014/12/22 02:26:54 tedu Exp $	*/
/*	$NetBSD: if_le.c,v 1.14 1999/08/14 18:40:23 ragge Exp $	*/

/*-
 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
 * Simulation Facility, NASA Ames Research Center.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*-
 * Copyright (c) 1992, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Ralph Campbell and Rick Macklem.
 *
 * 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.
 *
 *	@(#)if_le.c	8.2 (Berkeley) 11/16/93
 */

#include "bpfilter.h"

#include <sys/param.h>
#include <sys/syslog.h>
#include <sys/socket.h>
#include <sys/device.h>
#include <sys/reboot.h>

#include <uvm/uvm_extern.h>

#include <net/if.h>
#include <net/if_media.h>

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

#include <machine/cpu.h>
#include <machine/nexus.h>
#include <machine/scb.h>

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

#define ETHER_MIN_LEN   64      /* minimum frame length, including CRC */
#define	LEVEC	0xd4	/* Interrupt vector on 3300/3400 */

struct le_softc {
	struct	am7990_softc sc_am7990; /* Must be first */
	struct  evcount sc_intrcnt;
	int	sc_vec;
	volatile uint16_t *sc_rap;
	volatile uint16_t *sc_rdp;
};

int	le_ibus_match(struct device *, void *, void *);
void	le_ibus_attach(struct device *, struct device *, void *);
void	lewrcsr(struct lance_softc *, uint16_t, uint16_t);
uint16_t lerdcsr(struct lance_softc *, uint16_t);
void	lance_copytobuf_gap2(struct lance_softc *, void *, int, int);
void	lance_copyfrombuf_gap2(struct lance_softc *, void *, int, int);
void	lance_zerobuf_gap2(struct lance_softc *, int, int);

struct cfattach le_ibus_ca = {
	sizeof(struct le_softc), le_ibus_match, le_ibus_attach
};

void
lewrcsr(struct lance_softc *ls, uint16_t port, uint16_t val)
{
	struct le_softc *sc = (void *)ls;

	*sc->sc_rap = port;
	*sc->sc_rdp = val;
}

uint16_t
lerdcsr(struct lance_softc *ls, uint16_t port)
{
	struct le_softc *sc = (void *)ls;

	*sc->sc_rap = port;
	return *sc->sc_rdp;
}

int
le_ibus_match(struct device *parent, void *cf, void *aux)
{
	struct bp_conf *bp = aux;

	if (strcmp("lance", bp->type))
		return 0;
	return 1;
}

void
le_ibus_attach(struct device *parent, struct device *self, void *aux)
{
	struct le_softc *lesc = (void *)self;
	struct lance_softc *sc = &lesc->sc_am7990.lsc;
	int *lance_addr;
	int i, br;

	lesc->sc_rdp = (short *)vax_map_physmem(0x20084400, 1);
	lesc->sc_rap = lesc->sc_rdp + 2;

	/*
	 * Set interrupt vector, by forcing an interrupt.
	 */
	scb_vecref(0, 0); /* Clear vector ref */
	*lesc->sc_rap = LE_CSR0;
	*lesc->sc_rdp = LE_C0_STOP;
	DELAY(100);
	*lesc->sc_rdp = LE_C0_INIT|LE_C0_INEA;
	DELAY(100000);
	i = scb_vecref(&lesc->sc_vec, &br);
	if (i == 0 || lesc->sc_vec == 0)
		return;
	scb_vecalloc(lesc->sc_vec, (void *)am7990_intr, sc,
	     SCB_ISTACK, &lesc->sc_intrcnt);
	evcount_attach(&lesc->sc_intrcnt, self->dv_xname, &lesc->sc_vec);

	printf(": vec %d ipl %x\n%s", lesc->sc_vec, br, self->dv_xname);
	/*
	 * MD functions.
	 */
	sc->sc_rdcsr = lerdcsr;
	sc->sc_wrcsr = lewrcsr;
	sc->sc_nocarrier = NULL;

	sc->sc_mem = (void *)uvm_km_valloc(kernel_map, (128 * 1024));
	if (sc->sc_mem == 0)
		return;

	ioaccess((vaddr_t)sc->sc_mem, 0x20120000, (128 * 1024) >> VAX_PGSHIFT);

	sc->sc_addr = 0;
	sc->sc_memsize = (64 * 1024);

	sc->sc_copytodesc = lance_copytobuf_gap2;
	sc->sc_copyfromdesc = lance_copyfrombuf_gap2;
	sc->sc_copytobuf = lance_copytobuf_gap2;
	sc->sc_copyfrombuf = lance_copyfrombuf_gap2;
	sc->sc_zerobuf = lance_zerobuf_gap2;

	/*
	 * Get the ethernet address out of rom
	 */
	lance_addr = (int *)vax_map_physmem(0x20084200, 1);
	for (i = 0; i < 6; i++)
		sc->sc_arpcom.ac_enaddr[i] = (u_char)lance_addr[i];
	vax_unmap_physmem((vaddr_t)lance_addr, 1);

	am7990_config(&lesc->sc_am7990);
}

/*
 * gap2: two bytes of data followed by two bytes of pad.
 *
 * Buffers must be 4-byte aligned.  The code doesn't worry about
 * doing an extra byte.
 */

void
lance_copytobuf_gap2(struct lance_softc *sc, void *fromv, int boff, int len)
{
	volatile caddr_t buf = sc->sc_mem;
	caddr_t from = fromv;
	volatile uint16_t *bptr;

	if (boff & 0x1) {
		/* handle unaligned first byte */
		bptr = ((volatile uint16_t *)buf) + (boff - 1);
		*bptr = (*from++ << 8) | (*bptr & 0xff);
		bptr += 2;
		len--;
	} else
		bptr = ((volatile uint16_t *)buf) + boff;
	while (len > 1) {
		*bptr = (from[1] << 8) | (from[0] & 0xff);
		bptr += 2;
		from += 2;
		len -= 2;
	}
	if (len == 1)
		*bptr = (uint16_t)*from;
}

void
lance_copyfrombuf_gap2(struct lance_softc *sc, void *tov, int boff, int len)
{
	volatile caddr_t buf = sc->sc_mem;
	caddr_t to = tov;
	volatile uint16_t *bptr;
	uint16_t tmp;

	if (boff & 0x1) {
		/* handle unaligned first byte */
		bptr = ((volatile uint16_t *)buf) + (boff - 1);
		*to++ = (*bptr >> 8) & 0xff;
		bptr += 2;
		len--;
	} else
		bptr = ((volatile uint16_t *)buf) + boff;
	while (len > 1) {
		tmp = *bptr;
		*to++ = tmp & 0xff;
		*to++ = (tmp >> 8) & 0xff;
		bptr += 2;
		len -= 2;
	}
	if (len == 1)
		*to = *bptr & 0xff;
}

void
lance_zerobuf_gap2(struct lance_softc *sc, int boff, int len)
{
	volatile caddr_t buf = sc->sc_mem;
	volatile uint16_t *bptr;

	if ((unsigned)boff & 0x1) {
		bptr = ((volatile uint16_t *)buf) + (boff - 1);
		*bptr &= 0xff;
		bptr += 2;
		len--;
	} else
		bptr = ((volatile uint16_t *)buf) + boff;
	while (len > 0) {
		*bptr = 0;
		bptr += 2;
		len -= 2;
	}
}

license: unknown


code:
/*	$OpenBSD: if_qe.c,v 1.35 2015/07/04 10:12:52 dlg Exp $	*/
/*      $NetBSD: if_qe.c,v 1.51 2002/06/08 12:28:37 ragge Exp $ */
/*
 * Copyright (c) 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.
 */

/*
 * Driver for DEQNA/DELQA ethernet cards.
 * Things that is still to do:
 *	Handle ubaresets. Does not work at all right now.
 *	Fix ALLMULTI reception. But someone must tell me how...
 *	Collect statistics.
 */

#include "bpfilter.h"

#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/sockio.h>

#include <net/if.h>
#include <net/if_dl.h>

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

#if NBPFILTER > 0
#include <net/bpf.h>
#include <net/bpfdesc.h>
#endif

#include <machine/bus.h>

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

#define RXDESCS	30	/* # of receive descriptors */
#define TXDESCS	60	/* # transmit descs */

/*
 * Structure containing the elements that must be in DMA-safe memory.
 */
struct qe_cdata {
	struct qe_ring	qc_recv[RXDESCS+1];	/* Receive descriptors */
	struct qe_ring	qc_xmit[TXDESCS+1];	/* Transmit descriptors */
	u_int8_t	qc_setup[128];		/* Setup packet layout */
};

struct	qe_softc {
	struct device	sc_dev;		/* Configuration common part	*/
	struct evcount	sc_intrcnt;	/* Interrupt counting		*/
	int		sc_cvec;
	struct arpcom	sc_ac;		/* Ethernet common part		*/
#define sc_if	sc_ac.ac_if		/* network-visible interface	*/
	bus_space_tag_t sc_iot;
	bus_addr_t	sc_ioh;
	bus_dma_tag_t	sc_dmat;
	struct qe_cdata *sc_qedata;	/* Descriptor struct		*/
	struct qe_cdata *sc_pqedata;	/* Unibus address of above	*/
	struct mbuf*	sc_txmbuf[TXDESCS];
	struct mbuf*	sc_rxmbuf[RXDESCS];
	bus_dmamap_t	sc_xmtmap[TXDESCS];
	bus_dmamap_t	sc_rcvmap[RXDESCS];
	struct ubinfo	sc_ui;
	int		sc_intvec;	/* Interrupt vector		*/
	int		sc_nexttx;
	int		sc_inq;
	int		sc_lastack;
	int		sc_nextrx;
	int		sc_setup;	/* Setup packet in queue	*/
};

static	int	qematch(struct device *, struct cfdata *, void *);
static	void	qeattach(struct device *, struct device *, void *);
static	void	qeinit(struct qe_softc *);
static	void	qestart(struct ifnet *);
static	void	qeintr(void *);
static	int	qeioctl(struct ifnet *, u_long, caddr_t);
static	int	qe_add_rxbuf(struct qe_softc *, int);
static	void	qe_setup(struct qe_softc *);
static	void	qetimeout(struct ifnet *);

struct	cfattach qe_ca = {
	sizeof(struct qe_softc), (cfmatch_t)qematch, qeattach
};

struct cfdriver qe_cd = {
	NULL, "qe", DV_IFNET
};

#define	QE_WCSR(iot, ioh, csr, val) \
	bus_space_write_2(iot, ioh, csr, val)
#define	QE_RCSR(iot, ioh, csr) \
	bus_space_read_2(iot, ioh, csr)

#define	LOWORD(x)	((int)(x) & 0xffff)
#define	HIWORD(x)	(((int)(x) >> 16) & 0x3f)

/*
 * Check for present DEQNA. Done by sending a fake setup packet
 * and wait for interrupt.
 */
int
qematch(struct device *parent, struct cfdata *cf, void *aux)
{
	struct	uba_attach_args *ua = aux;
	struct	uba_softc *ubasc = (struct uba_softc *)parent;
	struct ubinfo ui;
#define	PROBESIZE	4096
	struct qe_ring *ring;
	struct	qe_ring *rp;
	int error;

	ring = malloc(PROBESIZE, M_TEMP, M_WAITOK | M_ZERO);

	ubasc->uh_lastiv -= 4;
	QE_WCSR(ua->ua_iot, ua->ua_ioh, QE_CSR_CSR, QE_RESET);
	QE_WCSR(ua->ua_iot, ua->ua_ioh, QE_CSR_VECTOR, ubasc->uh_lastiv);

	/*
	 * Map the ring area. Actually this is done only to be able to
	 * send and receive a internal packet; some junk is loopbacked
	 * so that the DEQNA has a reason to interrupt.
	 */
	ui.ui_size = PROBESIZE;
	ui.ui_vaddr = (caddr_t)&ring[0];
	if ((error = uballoc((void *)parent, &ui, UBA_CANTWAIT))) {
		free(ring, M_TEMP, PROBESIZE);
		return 0;
	}

	/*
	 * Init a simple "fake" receive and transmit descriptor that
	 * points to some unused area. Send a fake setup packet.
	 */
	rp = (void *)ui.ui_baddr;
	ring[0].qe_flag = ring[0].qe_status1 = QE_NOTYET;
	ring[0].qe_addr_lo = LOWORD(&rp[4]);
	ring[0].qe_addr_hi = HIWORD(&rp[4]) | QE_VALID | QE_EOMSG | QE_SETUP;
	ring[0].qe_buf_len = -64;

	ring[2].qe_flag = ring[2].qe_status1 = QE_NOTYET;
	ring[2].qe_addr_lo = LOWORD(&rp[4]);
	ring[2].qe_addr_hi = HIWORD(&rp[4]) | QE_VALID;
	ring[2].qe_buf_len = -(1500/2);

	QE_WCSR(ua->ua_iot, ua->ua_ioh, QE_CSR_CSR,
	    QE_RCSR(ua->ua_iot, ua->ua_ioh, QE_CSR_CSR) & ~QE_RESET);
	DELAY(1000);

	/*
	 * Start the interface and wait for the packet.
	 */
	QE_WCSR(ua->ua_iot, ua->ua_ioh, QE_CSR_CSR,
	    QE_INT_ENABLE|QE_XMIT_INT|QE_RCV_INT);
	QE_WCSR(ua->ua_iot, ua->ua_ioh, QE_CSR_RCLL, LOWORD(&rp[2]));
	QE_WCSR(ua->ua_iot, ua->ua_ioh, QE_CSR_RCLH, HIWORD(&rp[2]));
	QE_WCSR(ua->ua_iot, ua->ua_ioh, QE_CSR_XMTL, LOWORD(rp));
	QE_WCSR(ua->ua_iot, ua->ua_ioh, QE_CSR_XMTH, HIWORD(rp));
	DELAY(10000);

	/*
	 * All done with the bus resources.
	 */
	ubfree((void *)parent, &ui);
	free(ring, M_TEMP, PROBESIZE);
	return 1;
}

/*
 * Interface exists: make available by filling in network interface
 * record.  System will initialize the interface when it is ready
 * to accept packets.
 */
void
qeattach(struct device *parent, struct device *self, void *aux)
{
	struct	uba_attach_args *ua = aux;
	struct	uba_softc *ubasc = (struct uba_softc *)parent;
	struct	qe_softc *sc = (struct qe_softc *)self;
	struct	ifnet *ifp = (struct ifnet *)&sc->sc_if;
	struct	qe_ring *rp;
	int i, error;

	sc->sc_iot = ua->ua_iot;
	sc->sc_ioh = ua->ua_ioh;
	sc->sc_dmat = ua->ua_dmat;

        /*
         * Allocate DMA safe memory for descriptors and setup memory.
         */

	sc->sc_ui.ui_size = sizeof(struct qe_cdata);
	if ((error = ubmemalloc((struct uba_softc *)parent, &sc->sc_ui, 0))) {
		printf(": unable to ubmemalloc(), error = %d\n", error);
		return;
	}
	sc->sc_pqedata = (struct qe_cdata *)sc->sc_ui.ui_baddr;
	sc->sc_qedata = (struct qe_cdata *)sc->sc_ui.ui_vaddr;

	/*
	 * Zero the newly allocated memory.
	 */
	bzero(sc->sc_qedata, sizeof(struct qe_cdata));
	/*
	 * Create the transmit descriptor DMA maps. We take advantage
	 * of the fact that the Qbus address space is big, and therefore
	 * allocate map registers for all transmit descriptors also,
	 * so that we can avoid this each time we send a packet.
	 */
	for (i = 0; i < TXDESCS; i++) {
		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
		    1, MCLBYTES, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
		    &sc->sc_xmtmap[i]))) {
			printf(": unable to create tx DMA map %d, error = %d\n",
			    i, error);
			goto fail_4;
		}
	}

	/*
	 * Create receive buffer DMA maps.
	 */
	for (i = 0; i < RXDESCS; i++) {
		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
		    MCLBYTES, 0, BUS_DMA_NOWAIT,
		    &sc->sc_rcvmap[i]))) {
			printf(": unable to create rx DMA map %d, error = %d\n",
			    i, error);
			goto fail_5;
		}
	}
	/*
	 * Pre-allocate the receive buffers.
	 */
	for (i = 0; i < RXDESCS; i++) {
		if ((error = qe_add_rxbuf(sc, i)) != 0) {
			printf(": unable to allocate or map rx buffer %d\n,"
			    " error = %d\n", i, error);
			goto fail_6;
		}
	}

	/*
	 * Create ring loops of the buffer chains.
	 * This is only done once.
	 */

	rp = sc->sc_qedata->qc_recv;
	rp[RXDESCS].qe_addr_lo = LOWORD(&sc->sc_pqedata->qc_recv[0]);
	rp[RXDESCS].qe_addr_hi = HIWORD(&sc->sc_pqedata->qc_recv[0]) |
	    QE_VALID | QE_CHAIN;
	rp[RXDESCS].qe_flag = rp[RXDESCS].qe_status1 = QE_NOTYET;

	rp = sc->sc_qedata->qc_xmit;
	rp[TXDESCS].qe_addr_lo = LOWORD(&sc->sc_pqedata->qc_xmit[0]);
	rp[TXDESCS].qe_addr_hi = HIWORD(&sc->sc_pqedata->qc_xmit[0]) |
	    QE_VALID | QE_CHAIN;
	rp[TXDESCS].qe_flag = rp[TXDESCS].qe_status1 = QE_NOTYET;

	/*
	 * Get the vector that were set at match time, and remember it.
	 */
	sc->sc_intvec = ubasc->uh_lastiv;
	QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR, QE_RESET);
	DELAY(1000);
	QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR,
	    QE_RCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR) & ~QE_RESET);

	/*
	 * Read out ethernet address and tell which type this card is.
	 */
	for (i = 0; i < 6; i++)
		sc->sc_ac.ac_enaddr[i] =
		    QE_RCSR(sc->sc_iot, sc->sc_ioh, i * 2) & 0xff;

	QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_VECTOR, sc->sc_intvec | 1);
	printf(": %s, address %s\n",
	    QE_RCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_VECTOR) & 1 ?
	      "delqa" : "deqna", ether_sprintf(sc->sc_ac.ac_enaddr));

	QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_VECTOR,
	    QE_RCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_VECTOR) & ~1); /* ??? */

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

	strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, sizeof ifp->if_xname);
	ifp->if_softc = sc;
	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
	ifp->if_start = qestart;
	ifp->if_ioctl = qeioctl;
	ifp->if_watchdog = qetimeout;
	IFQ_SET_READY(&ifp->if_snd);

	/*
	 * Attach the interface.
	 */
	if_attach(ifp);
	ether_ifattach(ifp);

	return;

	/*
	 * Free any resources we've allocated during the failed attach
	 * attempt.  Do this in reverse order and fall through.
	 */
 fail_6:
	for (i = 0; i < RXDESCS; i++) {
		if (sc->sc_rxmbuf[i] != NULL) {
			bus_dmamap_unload(sc->sc_dmat, sc->sc_xmtmap[i]);
			m_freem(sc->sc_rxmbuf[i]);
		}
	}
 fail_5:
	for (i = 0; i < RXDESCS; i++) {
		if (sc->sc_rcvmap[i] != NULL)
			bus_dmamap_destroy(sc->sc_dmat, sc->sc_rcvmap[i]);
	}
 fail_4:
	for (i = 0; i < TXDESCS; i++) {
		if (sc->sc_xmtmap[i] != NULL)
			bus_dmamap_destroy(sc->sc_dmat, sc->sc_xmtmap[i]);
	}
}

/*
 * Initialization of interface.
 */
void
qeinit(struct qe_softc *sc)
{
	struct ifnet *ifp = (struct ifnet *)&sc->sc_if;
	struct qe_cdata *qc = sc->sc_qedata;
	int i;

	/*
	 * Reset the interface.
	 */
	QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR, QE_RESET);
	DELAY(1000);
	QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR,
	    QE_RCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR) & ~QE_RESET);
	QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_VECTOR, sc->sc_intvec);

	sc->sc_nexttx = sc->sc_inq = sc->sc_lastack = 0;
	/*
	 * Release and init transmit descriptors.
	 */
	for (i = 0; i < TXDESCS; i++) {
		if (sc->sc_txmbuf[i]) {
			bus_dmamap_unload(sc->sc_dmat, sc->sc_xmtmap[i]);
			m_freem(sc->sc_txmbuf[i]);
			sc->sc_txmbuf[i] = 0;
		}
		qc->qc_xmit[i].qe_addr_hi = 0; /* Clear valid bit */
		qc->qc_xmit[i].qe_status1 = qc->qc_xmit[i].qe_flag = QE_NOTYET;
	}

	/*
	 * Init receive descriptors.
	 */
	for (i = 0; i < RXDESCS; i++)
		qc->qc_recv[i].qe_status1 = qc->qc_recv[i].qe_flag = QE_NOTYET;
	sc->sc_nextrx = 0;

	/*
	 * Write the descriptor addresses to the device.
	 * Receiving packets will be enabled in the interrupt routine.
	 */
	QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR,
	    QE_INT_ENABLE|QE_XMIT_INT|QE_RCV_INT);
	QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_RCLL,
	    LOWORD(sc->sc_pqedata->qc_recv));
	QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_RCLH,
	    HIWORD(sc->sc_pqedata->qc_recv));

	ifp->if_flags |= IFF_RUNNING;
	ifp->if_flags &= ~IFF_OACTIVE;

	/*
	 * Send a setup frame.
	 * This will start the transmit machinery as well.
	 */
	qe_setup(sc);

}

/*
 * Start output on interface.
 */
void
qestart(struct ifnet *ifp)
{
	struct qe_softc *sc = ifp->if_softc;
	struct qe_cdata *qc = sc->sc_qedata;
	paddr_t	buffer;
	struct mbuf *m, *m0;
	int idx, len, s, i, totlen, error;
	short orword, csr;

	if ((QE_RCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR) & QE_RCV_ENABLE) == 0)
		return;

	s = splnet();
	while (sc->sc_inq < (TXDESCS - 1)) {

		if (sc->sc_setup) {
			qe_setup(sc);
			continue;
		}
		idx = sc->sc_nexttx;
		IFQ_POLL(&ifp->if_snd, m);
		if (m == NULL)
			goto out;
		/*
		 * Count number of mbufs in chain.
		 * Always do DMA directly from mbufs, therefore the transmit
		 * ring is really big.
		 */
		for (m0 = m, i = 0; m0; m0 = m0->m_next)
			if (m0->m_len)
				i++;
		if (i >= TXDESCS)
			panic("qestart");

		if ((i + sc->sc_inq) >= (TXDESCS - 1)) {
			ifp->if_flags |= IFF_OACTIVE;
			goto out;
		}

		IFQ_DEQUEUE(&ifp->if_snd, m);

#if NBPFILTER > 0
		if (ifp->if_bpf)
			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
#endif
		ifp->if_opackets++;

		/*
		 * m now points to a mbuf chain that can be loaded.
		 * Loop around and set it.
		 */
		totlen = 0;
		for (m0 = m; m0; m0 = m0->m_next) {
			error = bus_dmamap_load(sc->sc_dmat, sc->sc_xmtmap[idx],
			    mtod(m0, void *), m0->m_len, 0, 0);
			buffer = sc->sc_xmtmap[idx]->dm_segs[0].ds_addr;
			len = m0->m_len;
			if (len == 0)
				continue;

			totlen += len;
			/* Word alignment calc */
			orword = 0;
			if (totlen == m->m_pkthdr.len) {
				if (totlen < ETHER_MIN_LEN)
					len += (ETHER_MIN_LEN - totlen);
				orword |= QE_EOMSG;
				sc->sc_txmbuf[idx] = m;
			}
			if ((buffer & 1) || (len & 1))
				len += 2;
			if (buffer & 1)
				orword |= QE_ODDBEGIN;
			if ((buffer + len) & 1)
				orword |= QE_ODDEND;
			qc->qc_xmit[idx].qe_buf_len = -(len/2);
			qc->qc_xmit[idx].qe_addr_lo = LOWORD(buffer);
			qc->qc_xmit[idx].qe_addr_hi = HIWORD(buffer);
			qc->qc_xmit[idx].qe_flag =
			    qc->qc_xmit[idx].qe_status1 = QE_NOTYET;
			qc->qc_xmit[idx].qe_addr_hi |= (QE_VALID | orword);
			if (++idx == TXDESCS)
				idx = 0;
			sc->sc_inq++;
		}
#ifdef DIAGNOSTIC
		if (totlen != m->m_pkthdr.len)
			panic("qestart: len fault");
#endif

		/*
		 * Kick off the transmit logic, if it is stopped.
		 */
		csr = QE_RCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR);
		if (csr & QE_XL_INVALID) {
			QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_XMTL,
			    LOWORD(&sc->sc_pqedata->qc_xmit[sc->sc_nexttx]));
			QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_XMTH,
			    HIWORD(&sc->sc_pqedata->qc_xmit[sc->sc_nexttx]));
		}
		sc->sc_nexttx = idx;
	}
	if (sc->sc_inq == (TXDESCS - 1))
		ifp->if_flags |= IFF_OACTIVE;

out:	if (sc->sc_inq)
		ifp->if_timer = 5; /* If transmit logic dies */
	splx(s);
}

static void
qeintr(void *arg)
{
	struct qe_softc *sc = arg;
	struct qe_cdata *qc = sc->sc_qedata;
	struct ifnet *ifp = &sc->sc_if;
	struct ether_header *eh;
	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
	struct mbuf *m;
	int csr, status1, status2, len;

	csr = QE_RCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR);

	QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR,
	    QE_RCV_ENABLE | QE_INT_ENABLE | QE_XMIT_INT | QE_RCV_INT | QE_ILOOP);

	if (csr & QE_RCV_INT) {
		while (qc->qc_recv[sc->sc_nextrx].qe_status1 != QE_NOTYET) {
			status1 = qc->qc_recv[sc->sc_nextrx].qe_status1;
			status2 = qc->qc_recv[sc->sc_nextrx].qe_status2;

			m = sc->sc_rxmbuf[sc->sc_nextrx];
			len = ((status1 & QE_RBL_HI) |
			    (status2 & QE_RBL_LO)) + 60;
			qe_add_rxbuf(sc, sc->sc_nextrx);
			m->m_pkthdr.len = m->m_len = len;
			if (++sc->sc_nextrx == RXDESCS)
				sc->sc_nextrx = 0;
			eh = mtod(m, struct ether_header *);
			/*
			 * ALLMULTI means PROMISC in this driver.
			 */
			if ((ifp->if_flags & IFF_ALLMULTI) &&
			    ((eh->ether_dhost[0] & 1) == 0) &&
			    bcmp(sc->sc_ac.ac_enaddr, eh->ether_dhost,
			    ETHER_ADDR_LEN)) {
				m_freem(m);
				continue;
			}

			if ((status1 & QE_ESETUP) == 0)
				ml_enqueue(&ml, m);
			else
				m_freem(m);
		}
		if_input(ifp, &ml);
	}

	if (csr & (QE_XMIT_INT|QE_XL_INVALID)) {
		while (qc->qc_xmit[sc->sc_lastack].qe_status1 != QE_NOTYET) {
			int idx = sc->sc_lastack;

			sc->sc_inq--;
			if (++sc->sc_lastack == TXDESCS)
				sc->sc_lastack = 0;

			/* XXX collect statistics */
			qc->qc_xmit[idx].qe_addr_hi &= ~QE_VALID;
			qc->qc_xmit[idx].qe_status1 =
			    qc->qc_xmit[idx].qe_flag = QE_NOTYET;

			if (qc->qc_xmit[idx].qe_addr_hi & QE_SETUP)
				continue;
			bus_dmamap_unload(sc->sc_dmat, sc->sc_xmtmap[idx]);
			if (sc->sc_txmbuf[idx]) {
				m_freem(sc->sc_txmbuf[idx]);
				sc->sc_txmbuf[idx] = 0;
			}
		}
		ifp->if_timer = 0;
		ifp->if_flags &= ~IFF_OACTIVE;
		qestart(ifp); /* Put in more in queue */
	}
	/*
	 * How can the receive list get invalid???
	 * Verified that it happens anyway.
	 */
	if ((qc->qc_recv[sc->sc_nextrx].qe_status1 == QE_NOTYET) &&
	    (QE_RCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR) & QE_RL_INVALID)) {
		QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_RCLL,
		    LOWORD(&sc->sc_pqedata->qc_recv[sc->sc_nextrx]));
		QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_RCLH,
		    HIWORD(&sc->sc_pqedata->qc_recv[sc->sc_nextrx]));
	}
}

/*
 * Process an ioctl request.
 */
int
qeioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
	struct qe_softc *sc = ifp->if_softc;
	struct ifaddr *ifa = (struct ifaddr *)data;
	int s, error = 0;

	s = splnet();

	switch (cmd) {
	case SIOCSIFADDR:
		ifp->if_flags |= IFF_UP;
		switch(ifa->ifa_addr->sa_family) {
		case AF_INET:
			qeinit(sc);
			arp_ifinit(&sc->sc_ac, ifa);
			break;
		}
		break;

	case SIOCSIFFLAGS:
		if ((ifp->if_flags & IFF_UP) == 0 &&
		    (ifp->if_flags & IFF_RUNNING) != 0) {
			/*
			 * If interface is marked down and it is running,
			 * stop it. (by disabling receive mechanism).
			 */
			QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR,
			    QE_RCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR) &
			      ~QE_RCV_ENABLE);
			ifp->if_flags &= ~IFF_RUNNING;
		} else if ((ifp->if_flags & IFF_UP) != 0 &&
			   (ifp->if_flags & IFF_RUNNING) == 0) {
			/*
			 * If interface it marked up and it is stopped, then
			 * start it.
			 */
			qeinit(sc);
		} else if ((ifp->if_flags & IFF_UP) != 0) {
			/*
			 * Send a new setup packet to match any new changes.
			 * (Like IFF_PROMISC etc)
			 */
			qe_setup(sc);
		}
		break;

	default:
		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
	}

	if (error == ENETRESET) {
		if (ifp->if_flags & IFF_RUNNING)
			qe_setup(sc);
		error = 0;
	}

	splx(s);
	return (error);
}

/*
 * Add a receive buffer to the indicated descriptor.
 */
int
qe_add_rxbuf(struct qe_softc *sc, int i)
{
	struct mbuf *m;
	struct qe_ring *rp;
	vaddr_t addr;
	int error;

	MGETHDR(m, M_DONTWAIT, MT_DATA);
	if (m == NULL)
		return (ENOBUFS);

	MCLGET(m, M_DONTWAIT);
	if ((m->m_flags & M_EXT) == 0) {
		m_freem(m);
		return (ENOBUFS);
	}

	if (sc->sc_rxmbuf[i] != NULL)
		bus_dmamap_unload(sc->sc_dmat, sc->sc_rcvmap[i]);

	error = bus_dmamap_load(sc->sc_dmat, sc->sc_rcvmap[i],
	    m->m_ext.ext_buf, m->m_ext.ext_size, NULL, BUS_DMA_NOWAIT);
	if (error)
		panic("%s: can't load rx DMA map %d, error = %d",
		    sc->sc_dev.dv_xname, i, error);
	sc->sc_rxmbuf[i] = m;

	bus_dmamap_sync(sc->sc_dmat, sc->sc_rcvmap[i], 0,
	    sc->sc_rcvmap[i]->dm_mapsize, BUS_DMASYNC_PREREAD);

	/*
	 * We know that the mbuf cluster is page aligned. Also, be sure
	 * that the IP header will be longword aligned.
	 */
	m->m_data += 2;
	addr = sc->sc_rcvmap[i]->dm_segs[0].ds_addr + 2;
	rp = &sc->sc_qedata->qc_recv[i];
	rp->qe_flag = rp->qe_status1 = QE_NOTYET;
	rp->qe_addr_lo = LOWORD(addr);
	rp->qe_addr_hi = HIWORD(addr) | QE_VALID;
	rp->qe_buf_len = -(m->m_ext.ext_size - 2)/2;

	return (0);
}

/*
 * Create a setup packet and put in queue for sending.
 */
void
qe_setup(struct qe_softc *sc)
{
	struct ether_multi *enm;
	struct ether_multistep step;
	struct qe_cdata *qc = sc->sc_qedata;
	struct ifnet *ifp = &sc->sc_if;
	struct arpcom *ac = &sc->sc_ac;
	u_int8_t *enaddr = ac->ac_enaddr;
	int i, j, k, idx, s;

	s = splnet();
	if (sc->sc_inq == (TXDESCS - 1)) {
		sc->sc_setup = 1;
		splx(s);
		return;
	}
	sc->sc_setup = 0;
	/*
	 * Init the setup packet with valid info.
	 */
	memset(qc->qc_setup, 0xff, sizeof(qc->qc_setup)); /* Broadcast */
	for (i = 0; i < ETHER_ADDR_LEN; i++)
		qc->qc_setup[i * 8 + 1] = enaddr[i]; /* Own address */

	/*
	 * Multicast handling. The DEQNA can handle up to 12 direct
	 * ethernet addresses.
	 */
	j = 3; k = 0;
	ifp->if_flags &= ~IFF_ALLMULTI;

	if (ac->ac_multirangecnt > 0) {
		ifp->if_flags |= IFF_ALLMULTI;
		goto setit;
	}

	ETHER_FIRST_MULTI(step, ac, enm);
	while (enm != NULL) {
		for (i = 0; i < ETHER_ADDR_LEN; i++)
			qc->qc_setup[i * 8 + j + k] = enm->enm_addrlo[i];
		j++;
		if (j == 8) {
			j = 1; k += 64;
		}
		if (k > 64) {
			ifp->if_flags |= IFF_ALLMULTI;
			break;
		}
		ETHER_NEXT_MULTI(step, enm);
	}

setit:
	idx = sc->sc_nexttx;
	qc->qc_xmit[idx].qe_buf_len = -64;

	/*
	 * How is the DEQNA turned in ALLMULTI mode???
	 * Until someone tells me, fall back to PROMISC when more than
	 * 12 ethernet addresses.
	 */
	if (ifp->if_flags & IFF_ALLMULTI)
		ifp->if_flags |= IFF_PROMISC;
	else if (ifp->if_pcount == 0)
		ifp->if_flags &= ~IFF_PROMISC;
	if (ifp->if_flags & IFF_PROMISC)
		qc->qc_xmit[idx].qe_buf_len = -65;

	qc->qc_xmit[idx].qe_addr_lo = LOWORD(sc->sc_pqedata->qc_setup);
	qc->qc_xmit[idx].qe_addr_hi =
	    HIWORD(sc->sc_pqedata->qc_setup) | QE_SETUP | QE_EOMSG;
	qc->qc_xmit[idx].qe_status1 = qc->qc_xmit[idx].qe_flag = QE_NOTYET;
	qc->qc_xmit[idx].qe_addr_hi |= QE_VALID;

	if (QE_RCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_CSR) & QE_XL_INVALID) {
		QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_XMTL,
		    LOWORD(&sc->sc_pqedata->qc_xmit[idx]));
		QE_WCSR(sc->sc_iot, sc->sc_ioh, QE_CSR_XMTH,
		    HIWORD(&sc->sc_pqedata->qc_xmit[idx]));
	}

	sc->sc_inq++;
	if (++sc->sc_nexttx == TXDESCS)
		sc->sc_nexttx = 0;
	splx(s);
}

/*
 * Check for dead transmit logic. Not uncommon.
 */
void
qetimeout(struct ifnet *ifp)
{
	struct qe_softc *sc = ifp->if_softc;

	if (sc->sc_inq == 0)
		return;

	printf("%s: xmit logic died, resetting...\n", sc->sc_dev.dv_xname);
	/*
	 * Do a reset of interface, to get it going again.
	 * Will it work by just restart the transmit logic?
	 */
	qeinit(sc);
}


code:
/*	$OpenBSD: if_qereg.h,v 1.7 2003/06/02 23:27:57 millert Exp $	*/
/*	$NetBSD: if_qereg.h,v 1.6 2001/06/19 13:42:18 wiz Exp $ */
/*
 * Copyright (c) 1988 Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Digital Equipment Corp.
 *
 * 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.
 *
 *	@(#)if_qereg.h	7.3 (Berkeley) 6/28/90
 */

/* @(#)if_qereg.h	1.2 (ULTRIX) 1/3/85 */

/****************************************************************
 *								*
 *        Licensed from Digital Equipment Corporation 		*
 *                       Copyright (c) 				*
 *               Digital Equipment Corporation			*
 *                   Maynard, Massachusetts 			*
 *                         1985, 1986 				*
 *                    All rights reserved. 			*
 *								*
 *        The Information in this software is subject to change *
 *   without notice and should not be construed as a commitment *
 *   by  Digital  Equipment  Corporation.   Digital   makes  no *
 *   representations about the suitability of this software for *
 *   any purpose.  It is supplied "As Is" without expressed  or *
 *   implied  warranty. 					*
 *								*
 *        If the Regents of the University of California or its *
 *   licensees modify the software in a manner creating  	*
 *   derivative copyright rights, appropriate copyright  	*
 *   legends may be placed on  the derivative work in addition  *
 *   to that set forth above. 					*
 *								*
 ****************************************************************/
/* ---------------------------------------------------------------------
 * Modification History
 *
 *  13 Feb. 84 -- rjl
 *
 *	Initial version of driver. derived from IL driver.
 *
 * ---------------------------------------------------------------------
 */

/*
 * Digital Q-BUS to NI Adapter
 */
#ifdef notdef
struct qedevice {
	u_short	qe_sta_addr[2]; 	/* Station address (actually 6 	*/
	u_short	qe_rcvlist_lo; 		/* Receive list lo address 	*/
	u_short	qe_rcvlist_hi; 		/* Receive list hi address 	*/
	u_short	qe_xmtlist_lo;		/* Transmit list lo address 	*/
	u_short	qe_xmtlist_hi;		/* Transmit list hi address 	*/
	u_short	qe_vector;		/* Interrupt vector 		*/
	u_short	qe_csr;			/* Command and Status Register 	*/
};
#endif

/*
 * Register offsets in register space.
 */
#define	QE_CSR_ADDR1	0
#define	QE_CSR_ADDR2	2
#define	QE_CSR_RCLL	4
#define	QE_CSR_RCLH	6
#define	QE_CSR_XMTL	8
#define	QE_CSR_XMTH	10
#define	QE_CSR_VECTOR	12
#define	QE_CSR_CSR	14

/*
 * Command and status bits (csr)
 */
#define QE_RCV_ENABLE	0x0001		/* Receiver enable		*/
#define QE_RESET	0x0002		/* Software reset		*/
#define QE_NEX_MEM_INT	0x0004		/* Non existent mem interrupt	*/
#define QE_LOAD_ROM	0x0008		/* Load boot/diag from rom	*/
#define QE_XL_INVALID	0x0010		/* Transmit list invalid	*/
#define QE_RL_INVALID	0x0020		/* Receive list invalid		*/
#define QE_INT_ENABLE	0x0040		/* Interrupt enable		*/
#define QE_XMIT_INT	0x0080		/* Transmit interrupt		*/
#define QE_ILOOP 	0x0100		/* Internal loopback		*/
#define QE_ELOOP	0x0200		/* External loopback		*/
#define QE_STIM_ENABLE	0x0400		/* Sanity timer enable		*/
#define QE_POWERUP	0x1000		/* Tranceiver power on		*/
#define QE_CARRIER	0x2000		/* Carrier detect		*/
#define QE_RCV_INT	0x8000		/* Receiver interrupt		*/

/*
 * Transmit and receive ring discriptor ---------------------------
 *
 * The QNA uses the flag, status1 and the valid bit as a handshake/semiphore
 * mechinism.
 *
 * The flag word is written on ( bits 15,15 set to 1 ) when it reads the
 * descriptor. If the valid bit is set it considers the address to be valid.
 * When it uses the buffer pointed to by the valid address it sets status word
 * one.
 */
struct qe_ring	{
	u_short qe_flag;		/* Buffer utilization flags	*/
	u_short qe_addr_hi;
	u_short qe_addr_lo;		/* Low order bits of address	*/
	short qe_buf_len;		/* Negative buffer length	*/
	u_short qe_status1;		/* Status word one		*/
	u_short qe_status2;		/* Status word two		*/
};

/*
 * High word address control bits.
 */
#define	QE_VALID		0x8000
#define	QE_CHAIN		0x4000
#define	QE_EOMSG		0x2000
#define	QE_SETUP		0x1000
#define	QE_ODDEND		0x0080
#define	QE_ODDBEGIN		0x0040

/*
 * Status word definations (receive)
 *	word1
 */
#define QE_OVF			0x0001	/* Receiver overflow		*/
#define QE_CRCERR		0x0002	/* CRC error			*/
#define QE_FRAME		0x0004	/* Framing alignment error	*/
#define QE_SHORT		0x0008	/* Packet size < 10 bytes	*/
#define QE_RBL_HI		0x0700	/* Hi bits of receive len	*/
#define QE_RUNT			0x0800	/* Runt packet			*/
#define QE_DISCARD		0x1000	/* Discard the packet		*/
#define QE_ESETUP		0x2000	/* Looped back setup or eloop	*/
#define QE_ERROR		0x4000	/* Receiver error		*/
#define QE_LASTNOT		0x8000	/* Not the last in the packet	*/
/*	word2								*/
#define QE_RBL_LO		0x00ff	/* Low bits of receive len	*/

/*
 * Status word definations (transmit)
 *	word1
 */
#define QE_CCNT			0x00f0	/* Collision count this packet	*/
#define QE_FAIL			0x0100	/* Heart beat check failure	*/
#define QE_ABORT		0x0200	/* Transmission abort		*/
#define QE_STE16		0x0400	/* Sanity timer default on	*/
#define QE_NOCAR		0x0800	/* No carrier			*/
#define QE_LOSS			0x1000	/* Loss of carrier while xmit	*/
/*	word2								*/
#define QE_TDR			0x3fff	/* Time domain reflectometry	*/

/*
 * General constant definations
 */
#define QEALLOC 		0	/* Allocate an mbuf		*/
#define QENOALLOC		1	/* No mbuf allocation		*/
#define QEDEALLOC		2	/* Release an mbuf chain	*/

#define QE_NOTYET		0x8000	/* Descriptor not in use yet	*/
#define QE_INUSE		0x4000	/* Descriptor being used by QNA	*/
#define QE_MASK			0xc000	/* Lastnot/error/used mask	*/

/*
 * Values for the length of the setup packet that control reception filter.
 */
#define	QE_SETUPLEN		128	/* Size of setup packet		*/
#define QE_ALLMULTI		1	/* Receive all multicasts	*/
#define QE_PROMISC		2	/* Receive all packets		*/


code:
/*	$OpenBSD: if_uba.h,v 1.7 2003/11/10 21:05:04 miod Exp $	*/
/*	$NetBSD: if_uba.h,v 1.6 1996/08/20 14:07:50 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.
 *
 *	@(#)if_uba.h	7.4 (Berkeley) 6/28/90
 */

/*
 * Structure and routine definitions
 * for UNIBUS network interfaces.
 */

#define	IF_MAXNUBAMR	10
/*
 * Each interface has structures giving information
 * about UNIBUS resources held by the interface
 * for each send and receive buffer.
 *
 * We hold IF_NUBAMR map registers for datagram data, starting
 * at ifr_mr.  Map register ifr_mr[-1] maps the local network header
 * ending on the page boundary.  Bdp's are reserved for read and for
 * write, given by ifr_bdp.  The prototype of the map register for
 * read and for write is saved in ifr_proto.
 *
 * When write transfers are not full pages on page boundaries we just
 * copy the data into the pages mapped on the UNIBUS and start the
 * transfer.  If a write transfer is of a (1024 byte) page on a page
 * boundary, we swap in UNIBUS pte's to reference the pages, and then
 * remap the initial pages (from ifu_wmap) when the transfer completes.
 *
 * When read transfers give whole pages of data to be input, we
 * allocate page frames from a network page list and trade them
 * with the pages already containing the data, mapping the allocated
 * pages to replace the input pages for the next UNIBUS data input.
 */

/*
 * Information per interface.
 */
struct	ifubinfo {
	short	iff_flags;			/* used during uballoc's */
	short	iff_hlen;			/* local net header length */
	struct	uba_regs *iff_uba;		/* uba adaptor regs, in vm */
	pt_entry_t *iff_ubamr;			/* uba map regs, in vm */
	struct	uba_softc *iff_softc;		/* uba */
};

/*
 * Information per buffer.
 */
struct ifrw {
	caddr_t	ifrw_addr;			/* virt addr of header */
	short	ifrw_bdp;			/* unibus bdp */
	short	ifrw_flags;			/* type, etc. */
#define	IFRW_W	0x01				/* is a transmit buffer */
	int	ifrw_info;			/* value from ubaalloc */
	int	ifrw_proto;			/* map register prototype */
	pt_entry_t *ifrw_mr;			/* base of map registers */
};

/*
 * Information per transmit buffer, including the above.
 */
struct ifxmt {
	struct	ifrw ifrw;
	caddr_t	ifw_base;			/* virt addr of buffer */
	pt_entry_t ifw_wmap[IF_MAXNUBAMR];	/* base pages for output */
	struct	mbuf *ifw_xtofree;		/* pages being dma'd out */
	short	ifw_xswapd;			/* mask of clusters swapped */
	short	ifw_nmr;			/* number of entries in wmap */
};
#define	ifw_addr	ifrw.ifrw_addr
#define	ifw_bdp		ifrw.ifrw_bdp
#define	ifw_flags	ifrw.ifrw_flags
#define	ifw_info	ifrw.ifrw_info
#define	ifw_proto	ifrw.ifrw_proto
#define	ifw_mr		ifrw.ifrw_mr

/*
 * Most interfaces have a single receive and a single transmit buffer,
 * and use struct ifuba to store all of the unibus information.
 */
struct ifuba {
	struct	ifubinfo ifu_info;
	struct	ifrw ifu_r;
	struct	ifxmt ifu_xmt;
};

#define	ifu_softc	ifu_info.iff_softc
#define	ifu_hlen	ifu_info.iff_hlen
#define	ifu_uba		ifu_info.iff_uba
#define	ifu_ubamr	ifu_info.iff_ubamr
#define	ifu_flags	ifu_info.iff_flags
#define	ifu_w		ifu_xmt.ifrw
#define	ifu_xtofree	ifu_xmt.ifw_xtofree

#ifdef 	_KERNEL
#define	if_ubainit(ifuba, uban, hlen, nmr) \
		if_ubaminit(&(ifuba)->ifu_info, uban, hlen, nmr, \
			&(ifuba)->ifu_r, 1, &(ifuba)->ifu_xmt, 1)
#define	if_rubaget(ifu, totlen, off0, ifp) \
		if_ubaget(&(ifu)->ifu_info, &(ifu)->ifu_r, totlen, off0, ifp)
#define	if_wubaput(ifu, m) \
		if_ubaput(&(ifu)->ifu_info, &(ifu)->ifu_xmt, m)

/* Prototypes */
int	if_ubaminit(struct ifubinfo *, struct uba_softc *, int, int,
	    struct ifrw *, int, struct ifxmt *, int);
int	if_ubaput(struct ifubinfo *, struct ifxmt *, struct mbuf *);
struct mbuf *if_ubaget(struct ifubinfo *, struct ifrw *, int,
	struct ifnet *);

#endif


code:
/*	$OpenBSD: if_ze.c,v 1.10 2014/11/05 07:09:04 jsg Exp $	*/
/*      $NetBSD: if_ze.c,v 1.3 2000/01/24 02:54:03 matt Exp $ */
/*
 * Copyright (c) 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.
 */

#include <sys/param.h>
#include <sys/socket.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/sockio.h>

#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>

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

#include <machine/bus.h>
#include <machine/nexus.h>
#include <machine/cpu.h>
#include <machine/scb.h>
#include <machine/sid.h>

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

/*
 * Addresses.
 */
#define SGECADDR        0x20008000
#define NISA_ROM        0x20084000
#define	SGECVEC		0x108

static	int	zematch(struct device *, struct cfdata *, void *);
static	void	zeattach(struct device *, struct device *, void *);

struct	cfattach ze_ibus_ca = {
	sizeof(struct ze_softc), (cfmatch_t)zematch, zeattach
};

/*
 * Check for present SGEC.
 */
int
zematch(parent, cf, aux)
	struct	device *parent;
	struct	cfdata *cf;
	void	*aux;
{
	struct bp_conf *bp = aux;

	/*
	 * Should some more intelligent checking be done???
	 */
	if (strcmp(bp->type, "sgec") == 0)
		return 1;
	return 0;
}

/*
 * Interface exists: make available by filling in network interface
 * record.  System will initialize the interface when it is ready
 * to accept packets.
 */
void
zeattach(parent, self, aux)
	struct	device *parent, *self;
	void	*aux;
{
	extern struct vax_bus_dma_tag vax_bus_dma_tag;
	struct	ze_softc *sc = (struct ze_softc *)self;
	int *ea, i;

	/*
	 * Map in SGEC registers.
	 */
	sc->sc_ioh = vax_map_physmem(SGECADDR, 1);
	sc->sc_iot = 0; /* :-) */
	sc->sc_dmat = &vax_bus_dma_tag;

	sc->sc_intvec = SGECVEC;

	/*
	 * Map in, read and release ethernet rom address.
	 */
	ea = (int *)vax_map_physmem(NISA_ROM, 1);
	for (i = 0; i < ETHER_ADDR_LEN; i++)
		if (vax_boardtype == VAX_BTYP_660)
			sc->sc_ac.ac_enaddr[i] = (ea[i] >> 24) & 0377;
		else
			sc->sc_ac.ac_enaddr[i] = (ea[i] >> 8) & 0377;

	vax_unmap_physmem((vaddr_t)ea, 1);

	scb_vecalloc(SGECVEC, (void (*)(void *)) sgec_intr, sc,
	    SCB_ISTACK, &sc->sc_intrcnt);
	evcount_attach(&sc->sc_intrcnt, sc->sc_dev.dv_xname, &sc->sc_intvec);

	sgec_attach(sc);
}


code:
/*	$OpenBSD: sgec.c,v 1.29 2015/06/24 09:40:54 mpi Exp $	*/
/*      $NetBSD: sgec.c,v 1.5 2000/06/04 02:14:14 matt Exp $ */
/*
 * Copyright (c) 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.
 */

/*
 * Driver for the SGEC (Second Generation Ethernet Controller), sitting
 * on for example the VAX 4000/300 (KA670).
 *
 * The SGEC looks like a mixture of the DEQNA and the TULIP. Fun toy.
 *
 * Even though the chip is capable to use virtual addresses (read the
 * System Page Table directly) this driver doesn't do so, and there
 * is no benefit in doing it either in NetBSD of today.
 *
 * Things that is still to do:
 *	Collect statistics.
 *	Use imperfect filtering when many multicast addresses.
 */

#include "bpfilter.h"

#include <sys/param.h>
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/sockio.h>

#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>

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

#if NBPFILTER > 0
#include <net/bpf.h>
#include <net/bpfdesc.h>
#endif

#include <machine/bus.h>

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

void	sgec_rxintr(struct ze_softc *);
void	sgec_txintr(struct ze_softc *);
void	zeinit(struct ze_softc *);
int	zeioctl(struct ifnet *, u_long, caddr_t);
int	ze_ifmedia_change(struct ifnet *const);
void	ze_ifmedia_status(struct ifnet *const, struct ifmediareq *);
void	zekick(struct ze_softc *);
int	zereset(struct ze_softc *);
void	zestart(struct ifnet *);
void	zetimeout(struct ifnet *);
int	ze_add_rxbuf(struct ze_softc *, int);
void	ze_setup(struct ze_softc *);

struct	cfdriver ze_cd = {
	NULL, "ze", DV_IFNET
};

#define	ZE_WCSR(csr, val) \
	bus_space_write_4(sc->sc_iot, sc->sc_ioh, csr, val)
#define	ZE_RCSR(csr) \
	bus_space_read_4(sc->sc_iot, sc->sc_ioh, csr)

/*
 * Interface exists: make available by filling in network interface
 * record.  System will initialize the interface when it is ready
 * to accept packets.
 */
void
sgec_attach(sc)
	struct ze_softc *sc;
{
	struct	ifnet *ifp = (struct ifnet *)&sc->sc_if;
	struct	ze_tdes *tp;
	struct	ze_rdes *rp;
	bus_dma_segment_t seg;
	int i, s, rseg, error;

        /*
         * Allocate DMA safe memory for descriptors and setup memory.
         */
	if ((error = bus_dmamem_alloc(sc->sc_dmat,
	    sizeof(struct ze_cdata), NBPG, 0, &seg, 1, &rseg,
	    BUS_DMA_NOWAIT)) != 0) {
		printf(": unable to allocate control data, error = %d\n",
		    error);
		goto fail_0;
	}

	if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
	    sizeof(struct ze_cdata), (caddr_t *)&sc->sc_zedata,
	    BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
		printf(": unable to map control data, error = %d\n", error);
		goto fail_1;
	}

	if ((error = bus_dmamap_create(sc->sc_dmat,
	    sizeof(struct ze_cdata), 1,
	    sizeof(struct ze_cdata), 0, BUS_DMA_NOWAIT,
	    &sc->sc_cmap)) != 0) {
		printf(": unable to create control data DMA map, error = %d\n",
		    error);
		goto fail_2;
	}

	if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_cmap,
	    sc->sc_zedata, sizeof(struct ze_cdata), NULL,
	    BUS_DMA_NOWAIT)) != 0) {
		printf(": unable to load control data DMA map, error = %d\n",
		    error);
		goto fail_3;
	}

	/*
	 * Zero the newly allocated memory.
	 */
	bzero(sc->sc_zedata, sizeof(struct ze_cdata));
	/*
	 * Create the transmit descriptor DMA maps.
	 */
	for (i = 0; i < TXDESCS; i++) {
		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
		    1, MCLBYTES, 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,
		    &sc->sc_xmtmap[i]))) {
			printf(": unable to create tx DMA map %d, error = %d\n",
			    i, error);
			goto fail_4;
		}
	}

	/*
	 * Create receive buffer DMA maps.
	 */
	for (i = 0; i < RXDESCS; i++) {
		if ((error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
		    MCLBYTES, 0, BUS_DMA_NOWAIT,
		    &sc->sc_rcvmap[i]))) {
			printf(": unable to create rx DMA map %d, error = %d\n",
			    i, error);
			goto fail_5;
		}
	}
	/*
	 * Pre-allocate the receive buffers.
	 */
	s = splnet();
	for (i = 0; i < RXDESCS; i++) {
		if ((error = ze_add_rxbuf(sc, i)) != 0) {
			printf(": unable to allocate or map rx buffer %d\n,"
			    " error = %d\n", i, error);
			goto fail_6;
		}
	}
	splx(s);

	/*
	 * Create ring loops of the buffer chains.
	 * This is only done once.
	 */
	sc->sc_pzedata = (struct ze_cdata *)sc->sc_cmap->dm_segs[0].ds_addr;

	rp = sc->sc_zedata->zc_recv;
	rp[RXDESCS].ze_framelen = ZE_FRAMELEN_OW;
	rp[RXDESCS].ze_rdes1 = ZE_RDES1_CA;
	rp[RXDESCS].ze_bufaddr = (char *)sc->sc_pzedata->zc_recv;

	tp = sc->sc_zedata->zc_xmit;
	tp[TXDESCS].ze_tdr = ZE_TDR_OW;
	tp[TXDESCS].ze_tdes1 = ZE_TDES1_CA;
	tp[TXDESCS].ze_bufaddr = (char *)sc->sc_pzedata->zc_xmit;

	if (zereset(sc))
		return;

	strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, sizeof ifp->if_xname);
	ifp->if_softc = sc;
	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
	ifp->if_start = zestart;
	ifp->if_ioctl = zeioctl;
	ifp->if_watchdog = zetimeout;

	/*
	 * Attach the interface.
	 */
	if_attach(ifp);
	ether_ifattach(ifp);

	printf(": address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr));

	ifmedia_init(&sc->sc_ifmedia, 0, ze_ifmedia_change,
	    ze_ifmedia_status);
	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0, 0);
	ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5);
	/* supposedly connected, and the first Tx attempt will let us know */
	sc->sc_flags |= SGECF_LINKUP;
	return;

	/*
	 * Free any resources we've allocated during the failed attach
	 * attempt.  Do this in reverse order and fall through.
	 */
 fail_6:
	for (i = 0; i < RXDESCS; i++) {
		if (sc->sc_rxmbuf[i] != NULL) {
			bus_dmamap_unload(sc->sc_dmat, sc->sc_rcvmap[i]);
			m_freem(sc->sc_rxmbuf[i]);
		}
	}
 fail_5:
	for (i = 0; i < RXDESCS; i++) {
		if (sc->sc_rcvmap[i] != NULL)
			bus_dmamap_destroy(sc->sc_dmat, sc->sc_rcvmap[i]);
	}
 fail_4:
	for (i = 0; i < TXDESCS; i++) {
		if (sc->sc_xmtmap[i] != NULL)
			bus_dmamap_destroy(sc->sc_dmat, sc->sc_xmtmap[i]);
	}
	bus_dmamap_unload(sc->sc_dmat, sc->sc_cmap);
 fail_3:
	bus_dmamap_destroy(sc->sc_dmat, sc->sc_cmap);
 fail_2:
	bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_zedata,
	    sizeof(struct ze_cdata));
 fail_1:
	bus_dmamem_free(sc->sc_dmat, &seg, rseg);
 fail_0:
	return;
}

int
ze_ifmedia_change(struct ifnet *const ifp)
{
	return (0);
}

void
ze_ifmedia_status(struct ifnet *const ifp, struct ifmediareq *req)
{
	struct ze_softc *sc = ifp->if_softc;

	req->ifm_status = IFM_AVALID;
	if (sc->sc_flags & SGECF_LINKUP)
		req->ifm_status |= IFM_ACTIVE;
	req->ifm_active = IFM_10_5 | IFM_ETHER;
}

/*
 * Initialization of interface.
 */
void
zeinit(sc)
	struct ze_softc *sc;
{
	struct ifnet *ifp = (struct ifnet *)&sc->sc_if;
	struct ze_cdata *zc = sc->sc_zedata;
	int i;

	/*
	 * Reset the interface.
	 */
	if (zereset(sc))
		return;

	sc->sc_nexttx = sc->sc_inq = sc->sc_lastack = 0;
	/*
	 * Release and init transmit descriptors.
	 */
	for (i = 0; i < TXDESCS; i++) {
		if (sc->sc_txmbuf[i]) {
			bus_dmamap_unload(sc->sc_dmat, sc->sc_xmtmap[i]);
			m_freem(sc->sc_txmbuf[i]);
			sc->sc_txmbuf[i] = 0;
		}
		zc->zc_xmit[i].ze_tdr = 0; /* Clear valid bit */
	}

	/*
	 * Init receive descriptors.
	 */
	for (i = 0; i < RXDESCS; i++)
		zc->zc_recv[i].ze_framelen = ZE_FRAMELEN_OW;
	sc->sc_nextrx = 0;

	ZE_WCSR(ZE_CSR6, ZE_NICSR6_IE | ZE_NICSR6_BL_8 | ZE_NICSR6_ST |
	    ZE_NICSR6_SR | ZE_NICSR6_DC);

	ifp->if_flags |= IFF_RUNNING;
	ifp->if_flags &= ~IFF_OACTIVE;

	/*
	 * Send a setup frame.
	 * This will start the transmit machinery as well.
	 */
	ze_setup(sc);

}

/*
 * Kick off the transmit logic, if it is stopped.
 * On the VXT2000 we need to always reprogram CSR4,
 * so stop it unconditionnaly.
 */
void
zekick(struct ze_softc *sc)
{
	u_int csr5;

	csr5 = ZE_RCSR(ZE_CSR5);
	if (ISSET(sc->sc_flags, SGECF_VXTQUIRKS)) {
		if ((csr5 & ZE_NICSR5_TS) == ZE_NICSR5_TS_RUN) {
			ZE_WCSR(ZE_CSR6, ZE_RCSR(ZE_CSR6) & ~ZE_NICSR6_ST);
			while ((ZE_RCSR(ZE_CSR5) & ZE_NICSR5_TS) !=
			    ZE_NICSR5_TS_STOP)
				DELAY(10);
		}
		ZE_WCSR(ZE_CSR4,
		    (vaddr_t)&sc->sc_pzedata->zc_xmit[sc->sc_nexttx]);
		ZE_WCSR(ZE_CSR1, ZE_NICSR1_TXPD);
		if ((csr5 & ZE_NICSR5_TS) == ZE_NICSR5_TS_RUN) {
			ZE_WCSR(ZE_CSR6, ZE_RCSR(ZE_CSR6) | ZE_NICSR6_ST);
			while ((ZE_RCSR(ZE_CSR5) & ZE_NICSR5_TS) ==
			    ZE_NICSR5_TS_STOP)
				DELAY(10);
		}
	} else {
		if ((csr5 & ZE_NICSR5_TS) != ZE_NICSR5_TS_RUN)
			ZE_WCSR(ZE_CSR1, ZE_NICSR1_TXPD);
	}
}

/*
 * Start output on interface.
 */
void
zestart(ifp)
	struct ifnet *ifp;
{
	struct ze_softc *sc = ifp->if_softc;
	struct ze_cdata *zc = sc->sc_zedata;
	paddr_t	buffer;
	struct mbuf *m, *m0;
	int idx, len, s, i, totlen, error;
	int old_inq = sc->sc_inq;
	short orword;

	s = splnet();
	while (sc->sc_inq < (TXDESCS - 1)) {
		if (ISSET(sc->sc_flags, SGECF_SETUP)) {
			ze_setup(sc);
			continue;
		}
		idx = sc->sc_nexttx;
		IF_DEQUEUE(&sc->sc_if.if_snd, m);
		if (m == NULL)
			goto out;
		/*
		 * Count number of mbufs in chain.
		 * Always do DMA directly from mbufs, therefore the transmit
		 * ring is really big.
		 */
		for (m0 = m, i = 0; m0; m0 = m0->m_next)
			if (m0->m_len)
				i++;
		if (i >= TXDESCS)
			panic("zestart"); /* XXX */

		if ((i + sc->sc_inq) >= (TXDESCS - 1)) {
			IF_PREPEND(&sc->sc_if.if_snd, m);
			ifp->if_flags |= IFF_OACTIVE;
			goto out;
		}

#if NBPFILTER > 0
		if (ifp->if_bpf)
			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
#endif
		/*
		 * m now points to a mbuf chain that can be loaded.
		 * Loop around and set it.
		 */
		totlen = 0;
		orword = ZE_TDES1_FS;
		for (m0 = m; m0; m0 = m0->m_next) {
			error = bus_dmamap_load(sc->sc_dmat, sc->sc_xmtmap[idx],
			    mtod(m0, void *), m0->m_len, 0, 0);
			buffer = sc->sc_xmtmap[idx]->dm_segs[0].ds_addr;
			len = m0->m_len;
			if (len == 0)
				continue;

			totlen += len;
			/* Word alignment calc */
			if (totlen == m->m_pkthdr.len) {
				if (totlen < ETHER_ADDR_LEN)
					len += (ETHER_ADDR_LEN - totlen);
				orword |= ZE_TDES1_LS;
				sc->sc_txmbuf[idx] = m;
			}
			zc->zc_xmit[idx].ze_bufsize = len;
			zc->zc_xmit[idx].ze_bufaddr = (char *)buffer;
			zc->zc_xmit[idx].ze_tdes1 = orword | ZE_TDES1_IC;
			zc->zc_xmit[idx].ze_tdr = ZE_TDR_OW;

			if (++idx == TXDESCS)
				idx = 0;
			sc->sc_inq++;
			orword = 0;
		}
#ifdef DIAGNOSTIC
		if (totlen != m->m_pkthdr.len)
			panic("zestart: len fault");
#endif

		/*
		 * Kick off the transmit logic, if it is stopped.
		 */
		zekick(sc);
		sc->sc_nexttx = idx;
	}
	if (sc->sc_inq == (TXDESCS - 1))
		ifp->if_flags |= IFF_OACTIVE;

out:	if (old_inq < sc->sc_inq)
		ifp->if_timer = 5; /* If transmit logic dies */
	splx(s);
}

void
sgec_rxintr(struct ze_softc *sc)
{
	struct ze_cdata *zc = sc->sc_zedata;
	struct ifnet *ifp = &sc->sc_if;
	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
	struct mbuf *m;
	u_short rdes0;
	int len;

	while ((zc->zc_recv[sc->sc_nextrx].ze_framelen &
	    ZE_FRAMELEN_OW) == 0) {
		rdes0 = zc->zc_recv[sc->sc_nextrx].ze_rdes0;
		if (rdes0 & ZE_RDES0_ES) {
			rdes0 &= ~ZE_RDES0_TL;	/* not really an error */
			if ((rdes0 & (ZE_RDES0_OF | ZE_RDES0_CE | ZE_RDES0_CS |
			    ZE_RDES0_LE | ZE_RDES0_RF)) == 0)
				rdes0 &= ~ZE_RDES0_ES;
		}
		if (rdes0 & ZE_RDES0_ES) {
			ifp->if_ierrors++;
			if (rdes0 & ZE_RDES0_CS)
				ifp->if_collisions++;
			m = NULL;
		} else {
			m = sc->sc_rxmbuf[sc->sc_nextrx];
			len = zc->zc_recv[sc->sc_nextrx].ze_framelen;
		}
		ze_add_rxbuf(sc, sc->sc_nextrx);
		if (m != NULL) {
			m->m_pkthdr.len = m->m_len = len;
			ml_enqueue(&ml, m);
		}
		if (++sc->sc_nextrx == RXDESCS)
			sc->sc_nextrx = 0;
	}
	if_input(ifp, &ml);
}

void
sgec_txintr(struct ze_softc *sc)
{
	struct ze_cdata *zc = sc->sc_zedata;
	struct ifnet *ifp = &sc->sc_if;
	int oldlink = sc->sc_flags & SGECF_LINKUP;
	u_short tdes0;

	while ((zc->zc_xmit[sc->sc_lastack].ze_tdr & ZE_TDR_OW) == 0) {
		int idx = sc->sc_lastack;

		if (sc->sc_lastack == sc->sc_nexttx)
			break;
		sc->sc_inq--;
		if (++sc->sc_lastack == TXDESCS)
			sc->sc_lastack = 0;

		if ((zc->zc_xmit[idx].ze_tdes1 & ZE_TDES1_DT) ==
		    ZE_TDES1_DT_SETUP) {
			continue;
		}

		tdes0 = zc->zc_xmit[idx].ze_tdes0;
		if (tdes0 & ZE_TDES0_ES) {
			if (tdes0 & ZE_TDES0_TO)
				printf("%s: transmit watchdog timeout\n",
				    sc->sc_dev.dv_xname);
			if (tdes0 & (ZE_TDES0_LO | ZE_TDES0_NC))
				sc->sc_flags &= ~SGECF_LINKUP;
			else
				sc->sc_flags |= SGECF_LINKUP;
			if (tdes0 & ZE_TDES0_EC) {
				printf("%s: excessive collisions, tdr %d\n",
				    sc->sc_dev.dv_xname,
				    zc->zc_xmit[idx].ze_tdr & ~ZE_TDR_OW);
				ifp->if_collisions += 16;
			} else if (tdes0 & ZE_TDES0_LC)
				ifp->if_collisions +=
				    (tdes0 & ZE_TDES0_CC) >> 3;
			if (tdes0 & ZE_TDES0_UF)
				printf("%s: underflow\n", sc->sc_dev.dv_xname);
			ifp->if_oerrors++;
			if (tdes0 & (ZE_TDES0_TO | ZE_TDES0_UF))
				zeinit(sc);
		} else {
			sc->sc_flags |= SGECF_LINKUP;
			if (zc->zc_xmit[idx].ze_tdes1 & ZE_TDES1_LS)
				ifp->if_opackets++;
			bus_dmamap_unload(sc->sc_dmat, sc->sc_xmtmap[idx]);
			if (sc->sc_txmbuf[idx]) {
				m_freem(sc->sc_txmbuf[idx]);
				sc->sc_txmbuf[idx] = 0;
			}
		}
	}

	/* Notify link status change */
	if ((sc->sc_flags & SGECF_LINKUP) != oldlink) {
		if (oldlink != 0) {
			ifp->if_link_state = LINK_STATE_DOWN;
			ifp->if_baudrate = 0;
		} else {
			ifp->if_link_state = LINK_STATE_UP;
			ifp->if_baudrate = IF_Mbps(10);
		}
		if_link_state_change(ifp);
	}

	if (sc->sc_inq == 0)
		ifp->if_timer = 0;
	ifp->if_flags &= ~IFF_OACTIVE;
	zestart(ifp); /* Put in more in queue */
}

int
sgec_intr(sc)
	struct ze_softc *sc;
{
	int s, csr;

	csr = ZE_RCSR(ZE_CSR5);
	if ((csr & ZE_NICSR5_IS) == 0) /* Wasn't we */
		return 0;

	/*
	 * On some systems, interrupts are handled at spl4, this can end up
	 * in pool corruption.
	 */
	s = splnet();

	ZE_WCSR(ZE_CSR5, csr);

	if (csr & ZE_NICSR5_ME) {
		printf("%s: memory error, resetting\n", sc->sc_dev.dv_xname);
		zeinit(sc);
		splx(s);
		return (1);
	}

	if (csr & ZE_NICSR5_RI)
		sgec_rxintr(sc);

	if (csr & ZE_NICSR5_TI)
		sgec_txintr(sc);

	splx(s);

	return 1;
}

/*
 * Process an ioctl request.
 */
int
zeioctl(ifp, cmd, data)
	struct ifnet *ifp;
	u_long cmd;
	caddr_t data;
{
	struct ze_softc *sc = ifp->if_softc;
	struct ifaddr *ifa = (struct ifaddr *)data;
	struct ifreq *ifr = (struct ifreq *)data;
	int s, error = 0;

	s = splnet();

	switch (cmd) {
	case SIOCSIFADDR:
		ifp->if_flags |= IFF_UP;
		switch(ifa->ifa_addr->sa_family) {
		case AF_INET:
			zeinit(sc);
			arp_ifinit(&sc->sc_ac, ifa);
			break;
		}
		break;

	case SIOCSIFMEDIA:
	case SIOCGIFMEDIA:
		error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
		break;

	case SIOCSIFFLAGS:
		if ((ifp->if_flags & IFF_UP) == 0 &&
		    (ifp->if_flags & IFF_RUNNING) != 0) {
			/*
			 * If interface is marked down and it is running,
			 * stop it. (by disabling receive mechanism).
			 */
			ZE_WCSR(ZE_CSR6, ZE_RCSR(ZE_CSR6) &
			    ~(ZE_NICSR6_ST|ZE_NICSR6_SR));
			ifp->if_flags &= ~IFF_RUNNING;
		} else if ((ifp->if_flags & IFF_UP) != 0 &&
			   (ifp->if_flags & IFF_RUNNING) == 0) {
			/*
			 * If interface it marked up and it is stopped, then
			 * start it.
			 */
			zeinit(sc);
		} else if ((ifp->if_flags & IFF_UP) != 0) {
			/*
			 * Send a new setup packet to match any new changes.
			 * (Like IFF_PROMISC etc)
			 */
			ze_setup(sc);
		}
		break;

	default:
		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
	}

	if (error == ENETRESET) {
		if (ifp->if_flags & IFF_RUNNING)
			ze_setup(sc);
		error = 0;
	}

	splx(s);
	return (error);
}

/*
 * Add a receive buffer to the indicated descriptor.
 */
int
ze_add_rxbuf(sc, i)
	struct ze_softc *sc;
	int i;
{
	struct mbuf *m;
	struct ze_rdes *rp;
	int error;

	splassert(IPL_NET);

	MGETHDR(m, M_DONTWAIT, MT_DATA);
	if (m == NULL)
		return (ENOBUFS);

	MCLGET(m, M_DONTWAIT);
	if ((m->m_flags & M_EXT) == 0) {
		m_freem(m);
		return (ENOBUFS);
	}

	if (sc->sc_rxmbuf[i] != NULL)
		bus_dmamap_unload(sc->sc_dmat, sc->sc_rcvmap[i]);

	error = bus_dmamap_load(sc->sc_dmat, sc->sc_rcvmap[i],
	    m->m_ext.ext_buf, m->m_ext.ext_size, NULL, BUS_DMA_NOWAIT);
	if (error)
		panic("%s: can't load rx DMA map %d, error = %d",
		    sc->sc_dev.dv_xname, i, error);
	sc->sc_rxmbuf[i] = m;

	bus_dmamap_sync(sc->sc_dmat, sc->sc_rcvmap[i], 0,
	    sc->sc_rcvmap[i]->dm_mapsize, BUS_DMASYNC_PREREAD);

	/*
	 * We know that the mbuf cluster is page aligned. Also, be sure
	 * that the IP header will be longword aligned.
	 */
	m->m_data += 2;
	rp = &sc->sc_zedata->zc_recv[i];
	rp->ze_bufsize = (m->m_ext.ext_size - 2);
	rp->ze_bufaddr = (char *)sc->sc_rcvmap[i]->dm_segs[0].ds_addr + 2;
	rp->ze_framelen = ZE_FRAMELEN_OW;

	return (0);
}

/*
 * Create a setup packet and put in queue for sending.
 */
void
ze_setup(sc)
	struct ze_softc *sc;
{
	struct ether_multi *enm;
	struct ether_multistep step;
	struct ze_cdata *zc = sc->sc_zedata;
	struct ifnet *ifp = &sc->sc_if;
	struct arpcom *ac = &sc->sc_ac;
	u_int8_t *enaddr = ac->ac_enaddr;
	int j, idx, s, reg;

	s = splnet();
	if (sc->sc_inq == (TXDESCS - 1)) {
		SET(sc->sc_flags, SGECF_SETUP);
		splx(s);
		return;
	}
	CLR(sc->sc_flags, SGECF_SETUP);

	/*
	 * Init the setup packet with valid info.
	 */
	memset(zc->zc_setup, 0xff, sizeof(zc->zc_setup)); /* Broadcast */
	bcopy(enaddr, zc->zc_setup, ETHER_ADDR_LEN);

	/*
	 * Multicast handling. The SGEC can handle up to 16 direct
	 * ethernet addresses.
	 */
	j = 16;
	ifp->if_flags &= ~IFF_ALLMULTI;

	if (ac->ac_multirangecnt > 0) {
		ifp->if_flags |= IFF_ALLMULTI;
		goto setit;
	}

	ETHER_FIRST_MULTI(step, ac, enm);
	while (enm != NULL) {
		bcopy(enm->enm_addrlo, &zc->zc_setup[j], ETHER_ADDR_LEN);
		j += 8;
		ETHER_NEXT_MULTI(step, enm);
		if (enm != NULL && j == sizeof(zc->zc_setup)) {
			ifp->if_flags |= IFF_ALLMULTI;
			break;
		}
	}

setit:
	/*
	 * Fiddle with the receive logic.
	 */
	reg = ZE_RCSR(ZE_CSR6);
	DELAY(10);
	ZE_WCSR(ZE_CSR6, reg & ~ZE_NICSR6_SR); /* Stop rx */
	while ((ZE_RCSR(ZE_CSR5) & ZE_NICSR5_RS) != ZE_NICSR5_RS_STOP)
		DELAY(10);
	reg &= ~ZE_NICSR6_AF;
	if (ifp->if_flags & IFF_PROMISC)
		reg |= ZE_NICSR6_AF_PROM;
	else if (ifp->if_flags & IFF_ALLMULTI)
		reg |= ZE_NICSR6_AF_ALLM;
	DELAY(10);
	ZE_WCSR(ZE_CSR6, reg);
	while ((ZE_RCSR(ZE_CSR5) & ZE_NICSR5_RS) == ZE_NICSR5_RS_STOP)
		DELAY(10);
	/*
	 * Only send a setup packet if needed.
	 */
	if ((ifp->if_flags & (IFF_PROMISC|IFF_ALLMULTI)) == 0) {
		idx = sc->sc_nexttx;
		zc->zc_xmit[idx].ze_tdes1 = ZE_TDES1_DT_SETUP;
		zc->zc_xmit[idx].ze_bufsize = 128;
		zc->zc_xmit[idx].ze_bufaddr = sc->sc_pzedata->zc_setup;
		zc->zc_xmit[idx].ze_tdr = ZE_TDR_OW;

		zekick(sc);

		sc->sc_inq++;
		if (++sc->sc_nexttx == TXDESCS)
			sc->sc_nexttx = 0;
	}
	splx(s);
}

/*
 * Check for dead transmit logic.
 */
void
zetimeout(ifp)
	struct ifnet *ifp;
{
	struct ze_softc *sc = ifp->if_softc;

	if (sc->sc_inq == 0)
		return;

	printf("%s: xmit logic died, resetting...\n", sc->sc_dev.dv_xname);
	/*
	 * Do a reset of interface, to get it going again.
	 * Will it work by just restart the transmit logic?
	 */
	zeinit(sc);
}

/*
 * Reset chip:
 * Set/reset the reset flag.
 *  Write interrupt vector.
 *  Write ring buffer addresses.
 *  Write SBR.
 */
int
zereset(sc)
	struct ze_softc *sc;
{
	int reg, i, s;

	ZE_WCSR(ZE_CSR6, ZE_NICSR6_RE);
	DELAY(50000);
	if (ZE_RCSR(ZE_CSR5) & ZE_NICSR5_SF) {
		printf("%s: selftest failed\n", sc->sc_dev.dv_xname);
		return 1;
	}

	/*
	 * Get the vector that were set at match time, and remember it.
	 * WHICH VECTOR TO USE? Take one unused. XXX
	 * Funny way to set vector described in the programmers manual.
	 */
	reg = ZE_NICSR0_IPL14 | sc->sc_intvec | ZE_NICSR0_MBO; /* SYNC/ASYNC??? */
	i = 10;
	s = splnet();
	do {
		if (i-- == 0) {
			printf("Failing SGEC CSR0 init\n");
			splx(s);
			return 1;
		}
		ZE_WCSR(ZE_CSR0, reg);
	} while (ZE_RCSR(ZE_CSR0) != reg);
	splx(s);

	ZE_WCSR(ZE_CSR3, (vaddr_t)sc->sc_pzedata->zc_recv);
	ZE_WCSR(ZE_CSR4, (vaddr_t)sc->sc_pzedata->zc_xmit);
	return 0;
}


code:
/*	$OpenBSD: sgecreg.h,v 1.4 2011/09/26 21:44:04 miod Exp $	*/
/*	$NetBSD: sgecreg.h,v 1.1 1999/08/08 11:41:29 ragge Exp $	*/
/*
 * Copyright (c) 1988 Regents of the University of California.
 * All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Digital Equipment Corp.
 *
 * 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.
 *
 */

/* Driver for SGEC (second generation Ethernet controller) chip, type DC-541,
   found on the KA670 (and probably other) CPU.

   17 May 1998...Jay Maynard, jmaynard@phoenix.net
*/

/* SGEC CSRs */
struct zedevice {
	u_long ze_nicsr0;	/* vector address, IPL, sync mode */
	u_long ze_nicsr1;	/* TX poll demand */
	u_long ze_nicsr2;	/* RX poll demand */
	struct ze_rdes *ze_nicsr3;	/* RX descriptor list address */
	struct ze_tdes *ze_nicsr4;	/* TX descriptor list address */
	u_long ze_nicsr5;	/* SGEC status */
	u_long ze_nicsr6;	/* SGEC command/mode */
	u_long ze_nicsr7;	/* system page table base address */
	u_long ze_nivcsr8;	/* reserved virtual CSR */
	u_long ze_nivcsr9;	/* watchdog timers (virtual) */
	u_long ze_nivcsr10;	/* revision, missed frame count (v) */
	u_long ze_nivcsr11;	/* boot message verification (low) (v) */
	u_long ze_nivcsr12;	/* boot message verification (high) (v) */
	u_long ze_nivcsr13;	/* boot message processor (v) */
	u_long ze_nivcsr14;	/* diagnostic breakpoint (v) */
	u_long ze_nicsr15;	/* monitor command */
};

/*
 * Register offsets.
 */
#define	ZE_CSR0		0
#define	ZE_CSR1		4
#define	ZE_CSR2		8
#define	ZE_CSR3		12
#define	ZE_CSR4		16
#define	ZE_CSR5		20
#define	ZE_CSR6		24
#define	ZE_CSR7		28
#define	ZE_CSR8		32
#define	ZE_CSR9		36
#define	ZE_CSR10	40
#define	ZE_CSR11	44
#define	ZE_CSR12	48
#define	ZE_CSR13	52
#define	ZE_CSR14	56
#define	ZE_CSR15	60

/* SGEC bit definitions */
/* NICSR0: */
#define ZE_NICSR0_IPL 0xc0000000	/* interrupt priority level: */
#define ZE_NICSR0_IPL14 0x00000000	/* 0x14 */
#define ZE_NICSR0_IPL15 0x40000000	/* 0x15 */
#define ZE_NICSR0_IPL16 0x80000000	/* 0x16 */
#define ZE_NICSR0_IPL17 0xc0000000	/* 0x17 */
#define ZE_NICSR0_SA 0x20000000		/* sync(1)/async mode */
#define ZE_NICSR0_MBO 0x1fff0003	/* must be set to one on write */
#define ZE_NICSR0_IV_MASK 0x0000fffc	/* bits for the interrupt vector */

/* NICSR1: */
#define ZE_NICSR1_TXPD 0xffffffff	/* transmit polling demand */

/* NICSR2: */
#define ZE_NICSR2_RXPD 0xffffffff	/* receive polling demand */

/* NICSR3 and NICSR4 are pure addresses */
/* NICSR5: */
#define ZE_NICSR5_ID 0x80000000		/* init done */
#define ZE_NICSR5_SF 0x40000000		/* self-test failed */
#define ZE_NICSR5_SS 0x3c000000		/* self-test status field */
#define ZE_NICSR5_TS 0x03000000		/* transmission state: */
#define ZE_NICSR5_TS_STOP 0x00000000	/* stopped */
#define ZE_NICSR5_TS_RUN 0x01000000	/* running */
#define ZE_NICSR5_TS_SUSP 0x02000000	/* suspended */
#define ZE_NICSR5_RS 0x00c00000		/* reception state: */
#define ZE_NICSR5_RS_STOP 0x00000000	/* stopped */
#define ZE_NICSR5_RS_RUN 0x00400000	/* running */
#define ZE_NICSR5_RS_SUSP 0x00800000	/* suspended */
#define ZE_NICSR5_OM 0x00060000		/* operating mode: */
#define ZE_NICSR5_OM_NORM 0x00000000	/* normal */
#define ZE_NICSR5_OM_ILBK 0x00020000	/* internal loopback */
#define ZE_NICSR5_OM_ELBK 0x00040000	/* external loopback */
#define ZE_NICSR5_OM_DIAG 0x00060000	/* reserved for diags */
#define ZE_NICSR5_DN 0x00010000		/* virtual CSR access done */
#define ZE_NICSR5_MBO 0x0038ff00	/* must be one */
#define ZE_NICSR5_BO 0x00000080		/* boot message received */
#define ZE_NICSR5_TW 0x00000040		/* transmit watchdog timeout */
#define ZE_NICSR5_RW 0x00000020		/* receive watchdog timeout */
#define ZE_NICSR5_ME 0x00000010		/* memory error */
#define ZE_NICSR5_RU 0x00000008		/* receive buffer unavailable */
#define ZE_NICSR5_RI 0x00000004		/* receiver interrupt */
#define ZE_NICSR5_TI 0x00000002		/* transmitter interrupt */
#define ZE_NICSR5_IS 0x00000001		/* interrupt summary */
/* whew! */

/* NICSR6: */
#define ZE_NICSR6_RE 0x80000000		/* reset */
#define ZE_NICSR6_IE 0x40000000		/* interrupt enable */
#define ZE_NICSR6_MBO 0x01e7f000	/* must be one */
#define ZE_NICSR6_BL 0x1e000000		/* burst limit mask */
#define ZE_NICSR6_BL_8 0x10000000	/* 8 longwords */
#define ZE_NICSR6_BL_4 0x08000000	/* 4 longwords */
#define ZE_NICSR6_BL_2 0x04000000	/* 2 longwords */
#define ZE_NICSR6_BL_1 0x02000000	/* 1 longword */
#define ZE_NICSR6_BE 0x00100000		/* boot message enable */
#define ZE_NICSR6_SE 0x00080000		/* single cycle enable */
#define ZE_NICSR6_ST 0x00000800		/* start(1)/stop(0) transmission */
#define ZE_NICSR6_SR 0x00000400		/* start(1)/stop(0) reception */
#define ZE_NICSR6_OM 0x00000300		/* operating mode: */
#define ZE_NICSR6_OM_NORM 0x00000000	/* normal */
#define ZE_NICSR6_OM_ILBK 0x00000100	/* internal loopback */
#define ZE_NICSR6_OM_ELBK 0x00000200	/* external loopback */
#define ZE_NICSR6_OM_DIAG 0x00000300	/* reserved for diags */
#define ZE_NICSR6_DC 0x00000080		/* disable data chaining */
#define ZE_NICSR6_FC 0x00000040		/* force collision mode */
#define ZE_NICSR6_PB 0x00000008		/* pass bad frames */
#define ZE_NICSR6_AF 0x00000006		/* address filtering mode: */
#define ZE_NICSR6_AF_NORM 0x00000000	/* normal filtering */
#define ZE_NICSR6_AF_PROM 0x00000002	/* promiscuous mode */
#define ZE_NICSR6_AF_ALLM 0x00000004	/* all multicasts */

/* NICSR7 is an address, NICSR8 is reserved */
/* NICSR9: */
#define ZE_VNICSR9_RT 0xffff0000	/* receiver timeout, *1.6 us */
#define ZE_VNICSR9_TT 0x0000ffff	/* transmitter timeout */

/* NICSR10: */
#define ZE_VNICSR10_RN 0x001f0000	/* SGEC version */
#define ZE_VNICSR10_MFC 0x0000ffff	/* missed frame counter */

/* if you want to know what's in NICSRs 11-15, define them yourself! */

/* Descriptors: */
/* Receive descriptor */
struct ze_rdes {
	u_short ze_rdes0;		/* descriptor word 0 flags */
	u_short ze_framelen;		/* received frame length */
	u_char ze_rsvd1[3];		/* unused bytes */
	u_char ze_rdes1;		/* descriptor word 1 flags */
	short ze_pageoffset;		/* offset of buffer in page */
	short ze_bufsize;		/* length of data buffer */
	u_char *ze_bufaddr;		/* address of data buffer */
};

/* Receive descriptor bits */
#define ZE_FRAMELEN_OW 0x8000		/* SGEC owns this descriptor */
#define ZE_RDES0_ES 0x8000		/* an error has occurred */
#define ZE_RDES0_LE 0x4000		/* length error */
#define ZE_RDES0_DT 0x3000		/* data type: */
#define ZE_RDES0_DT_NORM 0x0000		/* normal frame */
#define ZE_RDES0_DT_ILBK 0x1000		/* internally looped back frame */
#define ZE_RDES0_DT_ELBK 0x2000		/* externally looped back frame */
#define ZE_RDES0_RF 0x0800		/* runt frame */
#define ZE_RDES0_BO 0x0400		/* buffer overflow */
#define ZE_RDES0_FS 0x0200		/* first segment */
#define ZE_RDES0_LS 0x0100		/* last segment */
#define ZE_RDES0_TL 0x0080		/* frame too long */
#define ZE_RDES0_CS 0x0040		/* collision seen */
#define ZE_RDES0_FT 0x0020		/* Ethernet frame type */
#define ZE_RDES0_TN 0x0008		/* address translation not valid */
#define ZE_RDES0_DB 0x0004		/* dribbling bits seen */
#define ZE_RDES0_CE 0x0002		/* CRC error */
#define ZE_RDES0_OF 0x0001		/* internal FIFO overflow */
#define ZE_RDES1_CA 0x80		/* chain address */
#define ZE_RDES1_VA 0x40		/* virtual address */
#define ZE_RDES1_VT 0x20		/* virtual(1)/phys PTE address */

/* Transmit descriptor */
struct ze_tdes {
	u_short ze_tdes0;		/* descriptor word 0 flags */
	u_short ze_tdr;			/* TDR count of cable fault */
	u_char ze_rsvd1[2];		/* unused bytes */
	u_short ze_tdes1;		/* descriptor word 1 flags */
	short ze_pageoffset;		/* offset of buffer in page */
	short ze_bufsize;		/* length of data buffer */
	u_char *ze_bufaddr;		/* address of data buffer */
};

/* Transmit descriptor bits */
#define ZE_TDR_OW 0x8000		/* SGEC owns this descriptor */
#define ZE_TDES0_ES 0x8000		/* an error has occurred */
#define ZE_TDES0_TO 0x4000		/* transmit watchdog timeout */
#define ZE_TDES0_LE 0x1000		/* length error */
#define ZE_TDES0_LO 0x0800		/* loss of carrier */
#define ZE_TDES0_NC 0x0400		/* no carrier */
#define ZE_TDES0_LC 0x0200		/* late collision */
#define ZE_TDES0_EC 0x0100		/* excessive collisions */
#define ZE_TDES0_HF 0x0080		/* heartbeat fail */
#define ZE_TDES0_CC 0x0078		/* collision count mask */
#define ZE_TDES0_TN 0x0004		/* address translation invalid */
#define ZE_TDES0_UF 0x0002		/* underflow */
#define ZE_TDES0_DE 0x0001		/* transmission deferred */
#define ZE_TDES1_CA 0x8000		/* chain address */
#define ZE_TDES1_VA 0x4000		/* virtual address */
#define ZE_TDES1_DT 0x3000		/* data type: */
#define ZE_TDES1_DT_NORM 0x0000		/* normal transmit frame */
#define ZE_TDES1_DT_SETUP 0x2000	/* setup frame */
#define ZE_TDES1_DT_DIAG 0x3000		/* diagnostic frame */
#define ZE_TDES1_AC 0x0800		/* CRC disable */
#define ZE_TDES1_FS 0x0400		/* first segment */
#define ZE_TDES1_LS 0x0200		/* last segment */
#define ZE_TDES1_IC 0x0100		/* interrupt on completion */
#define ZE_TDES1_VT 0x0080		/* virtual(1)/phys PTE address */


code:
/*	$OpenBSD: sgecvar.h,v 1.6 2008/08/22 17:09:06 deraadt Exp $	*/
/*      $NetBSD: sgecvar.h,v 1.2 2000/06/04 02:14:14 matt Exp $ */
/*
 * Copyright (c) 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.
 */

#define RXDESCS	30	/* # of receive descriptors */
#define TXDESCS	60	/* # transmit descs */

/*
 * Descriptors must be an even number; optimisation thing.
 */
struct ze_cdata {
	struct ze_rdes	zc_recv[RXDESCS+2];	/* Receive descriptors */
	struct ze_tdes	zc_xmit[TXDESCS+2];	/* Transmit descriptors */
	u_int8_t	zc_setup[128];		/* Setup packet layout */
};

struct	ze_softc {
	struct device	sc_dev;		/* Configuration common part	*/
	struct evcount	sc_intrcnt;	/* Interrupt counters           */
	struct arpcom	sc_ac;		/* Ethernet common part		*/
#define sc_if	sc_ac.ac_if		/* network-visible interface	*/
	struct ifmedia sc_ifmedia;
	bus_space_tag_t sc_iot;
	bus_addr_t	sc_ioh;
	bus_dma_tag_t	sc_dmat;
	struct ze_cdata *sc_zedata;	/* Descriptor struct		*/
	struct ze_cdata *sc_pzedata;	/* Physical address of above	*/
	bus_dmamap_t	sc_cmap;	/* Map for control structures	*/
	struct mbuf*	sc_txmbuf[TXDESCS];
	struct mbuf*	sc_rxmbuf[RXDESCS];
	bus_dmamap_t	sc_xmtmap[TXDESCS];
	bus_dmamap_t	sc_rcvmap[RXDESCS];
	int		sc_intvec;	/* Interrupt vector		*/
	int		sc_nexttx;
	int		sc_inq;
	int		sc_lastack;
	int		sc_nextrx;
	int		sc_flags;
#define	SGECF_SETUP		0x00000001	/* need to send setup packet */
#define	SGECF_VXTQUIRKS		0x00000002	/* need VXT2000 care */
#define SGECF_LINKUP		0x00000004	/* got link */
};

void	sgec_attach(struct ze_softc *);
int	sgec_intr(struct ze_softc *);


code: src/sys/arch/vax/include

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


code:
/*	$OpenBSD: _float.h,v 1.1 2012/06/26 16:12:45 deraadt Exp $	*/

/*
 * Copyright (c) 1989 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.
 */

#ifndef _MACHINE__FLOAT_H_
#define _MACHINE__FLOAT_H_

#define __FLT_RADIX		2		/* b */
#define __FLT_ROUNDS		1		/* FP addition rounds to nearest */
#define __FLT_EVAL_METHOD	0		/* no promotions */

#define __FLT_MANT_DIG		24		/* p */
#define __FLT_EPSILON		1.19209290E-7F	/* b**(1-p) */
#define __FLT_DIG		6		/* floor((p-1)*log10(b))+(b == 10) */
#define __FLT_MIN_EXP		(-127)		/* emin */
#define __FLT_MIN		2.93873588E-39F	/* b**(emin-1) */
#define __FLT_MIN_10_EXP	(-38)		/* ceil(log10(b**(emin-1))) */
#define __FLT_MAX_EXP		127		/* emax */
#define __FLT_MAX		1.70141173E+38F	/* (1-b**(-p))*b**emax */
#define __FLT_MAX_10_EXP	38		/* floor(log10((1-b**(-p))*b**emax)) */

#define __DBL_MANT_DIG		56
#define __DBL_EPSILON		2.77555756156289135E-17
#define __DBL_DIG		16
#define __DBL_MIN_EXP		(-127)
#define __DBL_MIN		2.938735877055718770E-39
#define __DBL_MIN_10_EXP	(-38)
#define __DBL_MAX_EXP		127
#define __DBL_MAX		1.701411834604692294E+38
#define __DBL_MAX_10_EXP	38

#define __LDBL_MANT_DIG		DBL_MANT_DIG
#define __LDBL_EPSILON		DBL_EPSILON
#define __LDBL_DIG		DBL_DIG
#define __LDBL_MIN_EXP		DBL_MIN_EXP
#define __LDBL_MIN		DBL_MIN
#define __LDBL_MIN_10_EXP	DBL_MIN_10_EXP
#define __LDBL_MAX_EXP		DBL_MAX_EXP
#define __LDBL_MAX		DBL_MAX
#define __LDBL_MAX_10_EXP	DBL_MAX_10_EXP

#define __DECIMAL_DIG		18

#endif /* _MACHINE__FLOAT_H_ */


code:
/*	$OpenBSD: _types.h,v 1.21 2014/03/19 05:14:13 guenther Exp $	*/

/*-
 * Copyright (c) 1990, 1993
 *	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.
 *
 *	@(#)types.h	8.3 (Berkeley) 1/5/94
 *	@(#)ansi.h	8.2 (Berkeley) 1/4/94
 */

#ifndef _MACHINE__TYPES_H_
#define _MACHINE__TYPES_H_

#if defined(_KERNEL)
typedef struct label_t {
	long val[6];
} label_t;
#endif

/*
 * _ALIGN(p) rounds p (pointer or byte index) up to a correctly-aligned
 * value for all data types (int, long, ...).   The result is an
 * unsigned long and must be cast to any desired pointer type.
 *
 * _ALIGNED_POINTER is a boolean macro that checks whether an address
 * is valid to fetch data elements of type t from on this architecture.
 * This does not reflect the optimal alignment, just the possibility
 * (within reasonable limits).
 */
#define	_ALIGNBYTES		(sizeof(int) - 1)
#define	_STACKALIGNBYTES	_ALIGNBYTES
#define	_ALIGN(p)		(((unsigned long)(p) + _ALIGNBYTES) & ~_ALIGNBYTES)
#define	_ALIGNED_POINTER(p,t)	((((unsigned long)(p)) & (sizeof(t) - 1)) == 0)

/* 7.18.1.1 Exact-width integer types */
typedef	signed char		__int8_t;
typedef	unsigned char		__uint8_t;
typedef	short			__int16_t;
typedef	unsigned short		__uint16_t;
typedef	int			__int32_t;
typedef	unsigned int		__uint32_t;
/* LONGLONG */
typedef	long long		__int64_t;
/* LONGLONG */
typedef	unsigned long long	__uint64_t;

/* 7.18.1.2 Minimum-width integer types */
typedef	__int8_t		__int_least8_t;
typedef	__uint8_t		__uint_least8_t;
typedef	__int16_t		__int_least16_t;
typedef	__uint16_t		__uint_least16_t;
typedef	__int32_t		__int_least32_t;
typedef	__uint32_t		__uint_least32_t;
typedef	__int64_t		__int_least64_t;
typedef	__uint64_t		__uint_least64_t;

/* 7.18.1.3 Fastest minimum-width integer types */
typedef	__int32_t		__int_fast8_t;
typedef	__uint32_t		__uint_fast8_t;
typedef	__int32_t		__int_fast16_t;
typedef	__uint32_t		__uint_fast16_t;
typedef	__int32_t		__int_fast32_t;
typedef	__uint32_t		__uint_fast32_t;
typedef	__int64_t		__int_fast64_t;
typedef	__uint64_t		__uint_fast64_t;
#define	__INT_FAST8_MIN		INT32_MIN
#define	__INT_FAST16_MIN	INT32_MIN
#define	__INT_FAST32_MIN	INT32_MIN
#define	__INT_FAST64_MIN	INT64_MIN
#define	__INT_FAST8_MAX		INT32_MAX
#define	__INT_FAST16_MAX	INT32_MAX
#define	__INT_FAST32_MAX	INT32_MAX
#define	__INT_FAST64_MAX	INT64_MAX
#define	__UINT_FAST8_MAX	UINT32_MAX
#define	__UINT_FAST16_MAX	UINT32_MAX
#define	__UINT_FAST32_MAX	UINT32_MAX
#define	__UINT_FAST64_MAX	UINT64_MAX

/* 7.18.1.4 Integer types capable of holding object pointers */
typedef	long			__intptr_t;
typedef	unsigned long		__uintptr_t;

/* 7.18.1.5 Greatest-width integer types */
typedef	__int64_t		__intmax_t;
typedef	__uint64_t		__uintmax_t;

/* Register size */
typedef long			__register_t;

/* VM system types */
typedef unsigned long		__vaddr_t;
typedef unsigned long		__paddr_t;
typedef unsigned long		__vsize_t;
typedef unsigned long		__psize_t;

/* Standard system types */
typedef	double			__double_t;
typedef	float			__float_t;
typedef long			__ptrdiff_t;
typedef	unsigned long		__size_t;
typedef	long			__ssize_t;
#if defined(__GNUC__) && __GNUC__ >= 3
typedef	__builtin_va_list	__va_list;
#else
typedef	char *			__va_list;
#endif

/* Wide character support types */
#ifndef __cplusplus
typedef	int			__wchar_t;
#endif
typedef int			__wint_t;
typedef	int			__rune_t;
typedef	void *			__wctrans_t;
typedef	void *			__wctype_t;

#endif	/* _MACHINE__TYPES_H_ */