if_sbni.c revision 106937
186752Sfjoe/*
286752Sfjoe * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved.
386752Sfjoe * Author: Denis I.Timofeev <timofeev@granch.ru>
486752Sfjoe *
586752Sfjoe * Redistributon and use in source and binary forms, with or without
686752Sfjoe * modification, are permitted provided that the following conditions
786752Sfjoe * are met:
886752Sfjoe * 1. Redistributions of source code must retain the above copyright
986752Sfjoe *    notice unmodified, this list of conditions, and the following
1086752Sfjoe *    disclaimer.
1186752Sfjoe * 2. Redistributions in binary form must reproduce the above copyright
1286752Sfjoe *    notice, this list of conditions and the following disclaimer in the
1386752Sfjoe *    documentation and/or other materials provided with the distribution.
1486752Sfjoe *
1586752Sfjoe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1686752Sfjoe * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1786752Sfjoe * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1886752Sfjoe * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1986752Sfjoe * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2086752Sfjoe * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2186752Sfjoe * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2286752Sfjoe * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2386752Sfjoe * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY
2486752Sfjoe * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2586752Sfjoe * SUCH DAMAGE.
2686752Sfjoe *
2786752Sfjoe * $FreeBSD: head/sys/dev/sbni/if_sbni.c 106937 2002-11-14 23:54:55Z sam $
2886752Sfjoe */
2986752Sfjoe
3086752Sfjoe/*
3186752Sfjoe * Device driver for Granch SBNI12 leased line adapters
3286752Sfjoe *
3386752Sfjoe * Revision 2.0.0  1997/08/06
3486752Sfjoe * Initial revision by Alexey Zverev
3586752Sfjoe *
3686752Sfjoe * Revision 2.0.1 1997/08/11
3786752Sfjoe * Additional internal statistics support (tx statistics)
3886752Sfjoe *
3986752Sfjoe * Revision 2.0.2 1997/11/05
4086752Sfjoe * if_bpf bug has been fixed
4186752Sfjoe *
4286752Sfjoe * Revision 2.0.3 1998/12/20
4386752Sfjoe * Memory leakage has been eliminated in
4486752Sfjoe * the sbni_st and sbni_timeout routines.
4586752Sfjoe *
4686752Sfjoe * Revision 3.0 2000/08/10 by Yaroslav Polyakov
4786752Sfjoe * Support for PCI cards. 4.1 modification.
4886752Sfjoe *
4986752Sfjoe * Revision 3.1 2000/09/12
5086752Sfjoe * Removed extra #defines around bpf functions
5186752Sfjoe *
5286752Sfjoe * Revision 4.0 2000/11/23 by Denis Timofeev
5386752Sfjoe * Completely redesigned the buffer management
5486752Sfjoe *
5586752Sfjoe * Revision 4.1 2001/01/21
5686752Sfjoe * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards
5786752Sfjoe *
5886752Sfjoe * Written with reference to NE2000 driver developed by David Greenman.
5986752Sfjoe */
6086752Sfjoe
6186752Sfjoe
6286752Sfjoe#include <sys/param.h>
6386752Sfjoe#include <sys/systm.h>
6486752Sfjoe#include <sys/socket.h>
6586752Sfjoe#include <sys/sockio.h>
6686752Sfjoe#include <sys/mbuf.h>
6786752Sfjoe#include <sys/kernel.h>
6886752Sfjoe#include <sys/proc.h>
6986752Sfjoe#include <sys/callout.h>
7086752Sfjoe#include <sys/syslog.h>
71101400Sfjoe#include <sys/random.h>
7286752Sfjoe
73101400Sfjoe#include <machine/bus.h>
74101400Sfjoe#include <sys/rman.h>
75101400Sfjoe#include <machine/resource.h>
76101400Sfjoe
7786752Sfjoe#include <net/if.h>
7886752Sfjoe#include <net/ethernet.h>
7986752Sfjoe#include <net/if_arp.h>
8086752Sfjoe#include <net/bpf.h>
8186752Sfjoe
8286752Sfjoe#include <dev/sbni/if_sbnireg.h>
8386752Sfjoe#include <dev/sbni/if_sbnivar.h>
8486752Sfjoe
8586752Sfjoe#define ASM_CRC 1
8686752Sfjoe
8786752Sfjoestatic void	sbni_init(void *);
8886752Sfjoestatic void	sbni_start(struct ifnet *);
8986752Sfjoestatic int	sbni_ioctl(struct ifnet *, u_long, caddr_t);
9086752Sfjoestatic void	sbni_watchdog(struct ifnet *);
9186752Sfjoestatic void	sbni_stop(struct sbni_softc *);
9286752Sfjoestatic void	handle_channel(struct sbni_softc *);
9386752Sfjoe
9486752Sfjoestatic void	card_start(struct sbni_softc *);
9586752Sfjoestatic int	recv_frame(struct sbni_softc *);
9686752Sfjoestatic void	send_frame(struct sbni_softc *);
9786752Sfjoestatic int	upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t);
9886752Sfjoestatic int	skip_tail(struct sbni_softc *, u_int, u_int32_t);
9986752Sfjoestatic void	interpret_ack(struct sbni_softc *, u_int);
10086752Sfjoestatic void	download_data(struct sbni_softc *, u_int32_t *);
10186752Sfjoestatic void	prepare_to_send(struct sbni_softc *);
10286752Sfjoestatic void	drop_xmit_queue(struct sbni_softc *);
10386752Sfjoestatic int	get_rx_buf(struct sbni_softc *);
10486752Sfjoestatic void	indicate_pkt(struct sbni_softc *);
10586752Sfjoestatic void	change_level(struct sbni_softc *);
10686752Sfjoestatic int	check_fhdr(struct sbni_softc *, u_int *, u_int *,
10786752Sfjoe			   u_int *, u_int *, u_int32_t *);
10886752Sfjoestatic int	append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t);
10986752Sfjoestatic void	timeout_change_level(struct sbni_softc *);
11086752Sfjoestatic void	send_frame_header(struct sbni_softc *, u_int32_t *);
11186752Sfjoestatic void	set_initial_values(struct sbni_softc *, struct sbni_flags);
11286752Sfjoe
11386752Sfjoestatic u_int32_t	calc_crc32(u_int32_t, caddr_t, u_int);
11486752Sfjoestatic timeout_t	sbni_timeout;
11586752Sfjoe
11686752Sfjoestatic __inline u_char	sbni_inb(struct sbni_softc *, enum sbni_reg);
11786752Sfjoestatic __inline void	sbni_outb(struct sbni_softc *, enum sbni_reg, u_char);
11886752Sfjoestatic __inline void	sbni_insb(struct sbni_softc *, u_char *, u_int);
11986752Sfjoestatic __inline void	sbni_outsb(struct sbni_softc *, u_char *, u_int);
12086752Sfjoe
12186752Sfjoestatic u_int32_t crc32tab[];
12286752Sfjoe
12386752Sfjoe#ifdef SBNI_DUAL_COMPOUND
12489092Smsmithstruct sbni_softc *sbni_headlist;
12586752Sfjoe#endif
12686752Sfjoe
12786752Sfjoeu_int32_t next_sbni_unit;
12886752Sfjoe
12986752Sfjoe/* -------------------------------------------------------------------------- */
13086752Sfjoe
13186752Sfjoestatic __inline u_char
13286752Sfjoesbni_inb(struct sbni_softc *sc, enum sbni_reg reg)
13386752Sfjoe{
134101400Sfjoe	return bus_space_read_1(
135101400Sfjoe	    rman_get_bustag(sc->io_res),
136101400Sfjoe	    rman_get_bushandle(sc->io_res),
137101400Sfjoe	    sc->io_off + reg);
13886752Sfjoe}
13986752Sfjoe
14086752Sfjoestatic __inline void
14186752Sfjoesbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value)
14286752Sfjoe{
143101400Sfjoe	bus_space_write_1(
144101400Sfjoe	    rman_get_bustag(sc->io_res),
145101400Sfjoe	    rman_get_bushandle(sc->io_res),
146101400Sfjoe	    sc->io_off + reg, value);
14786752Sfjoe}
14886752Sfjoe
14986752Sfjoestatic __inline void
15086752Sfjoesbni_insb(struct sbni_softc *sc, u_char *to, u_int len)
15186752Sfjoe{
152101400Sfjoe	bus_space_read_multi_1(
153101400Sfjoe	    rman_get_bustag(sc->io_res),
154101400Sfjoe	    rman_get_bushandle(sc->io_res),
155101400Sfjoe	    sc->io_off + DAT, to, len);
15686752Sfjoe}
15786752Sfjoe
15886752Sfjoestatic __inline void
15986752Sfjoesbni_outsb(struct sbni_softc *sc, u_char *from, u_int len)
16086752Sfjoe{
161101400Sfjoe	bus_space_write_multi_1(
162101400Sfjoe	    rman_get_bustag(sc->io_res),
163101400Sfjoe	    rman_get_bushandle(sc->io_res),
164101400Sfjoe	    sc->io_off + DAT, from, len);
16586752Sfjoe}
16686752Sfjoe
16786752Sfjoe
16886752Sfjoe/*
16986752Sfjoe	Valid combinations in CSR0 (for probing):
17086752Sfjoe
17186752Sfjoe	VALID_DECODER	0000,0011,1011,1010
17286752Sfjoe
17386752Sfjoe				    	; 0   ; -
17486752Sfjoe				TR_REQ	; 1   ; +
17586752Sfjoe			TR_RDY	    	; 2   ; -
17686752Sfjoe			TR_RDY	TR_REQ	; 3   ; +
17786752Sfjoe		BU_EMP		    	; 4   ; +
17886752Sfjoe		BU_EMP	     	TR_REQ	; 5   ; +
17986752Sfjoe		BU_EMP	TR_RDY	    	; 6   ; -
18086752Sfjoe		BU_EMP	TR_RDY	TR_REQ	; 7   ; +
18186752Sfjoe	RC_RDY 		     		; 8   ; +
18286752Sfjoe	RC_RDY			TR_REQ	; 9   ; +
18386752Sfjoe	RC_RDY		TR_RDY		; 10  ; -
18486752Sfjoe	RC_RDY		TR_RDY	TR_REQ	; 11  ; -
18586752Sfjoe	RC_RDY	BU_EMP			; 12  ; -
18686752Sfjoe	RC_RDY	BU_EMP		TR_REQ	; 13  ; -
18786752Sfjoe	RC_RDY	BU_EMP	TR_RDY		; 14  ; -
18886752Sfjoe	RC_RDY	BU_EMP	TR_RDY	TR_REQ	; 15  ; -
18986752Sfjoe*/
19086752Sfjoe
19186752Sfjoe#define VALID_DECODER	(2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
19286752Sfjoe
19386752Sfjoe
19486752Sfjoeint
19586752Sfjoesbni_probe(struct sbni_softc *sc)
19686752Sfjoe{
19786752Sfjoe	u_char csr0;
19886752Sfjoe
19986752Sfjoe	csr0 = sbni_inb(sc, CSR0);
20086752Sfjoe	if (csr0 != 0xff && csr0 != 0x00) {
20186752Sfjoe		csr0 &= ~EN_INT;
20286752Sfjoe		if (csr0 & BU_EMP)
20386752Sfjoe			csr0 |= EN_INT;
20486752Sfjoe
20586752Sfjoe		if (VALID_DECODER & (1 << (csr0 >> 4)))
20686752Sfjoe			return (0);
20786752Sfjoe	}
20886752Sfjoe
20986752Sfjoe	return (ENXIO);
21086752Sfjoe}
21186752Sfjoe
21286752Sfjoe
21386752Sfjoe/*
21486752Sfjoe * Install interface into kernel networking data structures
21586752Sfjoe */
21686752Sfjoevoid
21786752Sfjoesbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags)
21886752Sfjoe{
21986752Sfjoe	struct ifnet *ifp;
22086752Sfjoe	u_char csr0;
22186752Sfjoe
22286752Sfjoe	ifp = &sc->arpcom.ac_if;
22386752Sfjoe	sbni_outb(sc, CSR0, 0);
22486752Sfjoe	set_initial_values(sc, flags);
22586752Sfjoe
22686752Sfjoe	callout_handle_init(&sc->wch);
22786752Sfjoe	if (!ifp->if_name) {
22886752Sfjoe		/* Initialize ifnet structure */
22986752Sfjoe		ifp->if_softc	= sc;
23086752Sfjoe		ifp->if_unit	= unit;
23186752Sfjoe		ifp->if_name	= "sbni";
23286752Sfjoe		ifp->if_init	= sbni_init;
23386752Sfjoe		ifp->if_start	= sbni_start;
23486752Sfjoe	        ifp->if_output	= ether_output;
23586752Sfjoe		ifp->if_ioctl	= sbni_ioctl;
23686752Sfjoe		ifp->if_watchdog	= sbni_watchdog;
23786752Sfjoe		ifp->if_snd.ifq_maxlen	= IFQ_MAXLEN;
23886752Sfjoe
23986752Sfjoe		/* report real baud rate */
24086752Sfjoe		csr0 = sbni_inb(sc, CSR0);
24186752Sfjoe		ifp->if_baudrate =
24286752Sfjoe			(csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate);
24386752Sfjoe
24486752Sfjoe	        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
245106937Ssam		ether_ifattach(ifp, sc->arpcom.ac_enaddr);
24686752Sfjoe	}
24786752Sfjoe	/* device attach does transition from UNCONFIGURED to IDLE state */
24886752Sfjoe
249104256Sbrooks	if_printf(ifp, "speed %ld, address %6D, rxl ",
250104256Sbrooks	       ifp->if_baudrate, sc->arpcom.ac_enaddr, ":");
25186752Sfjoe	if (sc->delta_rxl)
25286752Sfjoe		printf("auto\n");
25386752Sfjoe	else
25486752Sfjoe		printf("%d (fixed)\n", sc->cur_rxl_index);
25586752Sfjoe}
25686752Sfjoe
25786752Sfjoe/* -------------------------------------------------------------------------- */
25886752Sfjoe
25986752Sfjoestatic void
26086752Sfjoesbni_init(void *xsc)
26186752Sfjoe{
26286752Sfjoe	struct sbni_softc *sc;
26386752Sfjoe	struct ifnet *ifp;
26486752Sfjoe	int  s;
26586752Sfjoe
26686752Sfjoe	sc = (struct sbni_softc *)xsc;
26786752Sfjoe	ifp = &sc->arpcom.ac_if;
26886752Sfjoe
26986752Sfjoe	/* address not known */
27086752Sfjoe	if (TAILQ_EMPTY(&ifp->if_addrhead))
27186752Sfjoe		return;
27286752Sfjoe
27386752Sfjoe	/*
27486752Sfjoe	 * kludge to avoid multiple initialization when more than once
27586752Sfjoe	 * protocols configured
27686752Sfjoe	 */
27786752Sfjoe	if (ifp->if_flags & IFF_RUNNING)
27886752Sfjoe		return;
27986752Sfjoe
28086752Sfjoe	s = splimp();
28186752Sfjoe	ifp->if_timer = 0;
28286752Sfjoe	card_start(sc);
28386752Sfjoe	sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ);
28486752Sfjoe
28586752Sfjoe	ifp->if_flags |= IFF_RUNNING;
28686752Sfjoe	ifp->if_flags &= ~IFF_OACTIVE;
28786752Sfjoe
28886752Sfjoe	/* attempt to start output */
28986752Sfjoe	sbni_start(ifp);
29086752Sfjoe	splx(s);
29186752Sfjoe}
29286752Sfjoe
29386752Sfjoe
29486752Sfjoestatic void
29586752Sfjoesbni_start(struct ifnet *ifp)
29686752Sfjoe{
29786752Sfjoe	struct sbni_softc *sc = ifp->if_softc;
29886752Sfjoe	if (sc->tx_frameno == 0)
29986752Sfjoe		prepare_to_send(sc);
30086752Sfjoe}
30186752Sfjoe
30286752Sfjoe
30386752Sfjoestatic void
30486752Sfjoesbni_stop(struct sbni_softc *sc)
30586752Sfjoe{
30686752Sfjoe	sbni_outb(sc, CSR0, 0);
30786752Sfjoe	drop_xmit_queue(sc);
30886752Sfjoe
30986752Sfjoe	if (sc->rx_buf_p) {
31086752Sfjoe		m_freem(sc->rx_buf_p);
31186752Sfjoe		sc->rx_buf_p = NULL;
31286752Sfjoe	}
31386752Sfjoe
31486752Sfjoe	untimeout(sbni_timeout, sc, sc->wch);
31586752Sfjoe	sc->wch.callout = NULL;
31686752Sfjoe}
31786752Sfjoe
31886752Sfjoe/* -------------------------------------------------------------------------- */
31986752Sfjoe
32086752Sfjoe/* interrupt handler */
32186752Sfjoe
32286752Sfjoe/*
32386752Sfjoe * 	SBNI12D-10, -11/ISA boards within "common interrupt" mode could not
32486752Sfjoe * be looked as two independent single-channel devices. Every channel seems
32586752Sfjoe * as Ethernet interface but interrupt handler must be common. Really, first
32686752Sfjoe * channel ("master") driver only registers the handler. In it's struct softc
32786752Sfjoe * it has got pointer to "slave" channel's struct softc and handles that's
32886752Sfjoe * interrupts too.
32986752Sfjoe *	softc of successfully attached ISA SBNI boards is linked to list.
33086752Sfjoe * While next board driver is initialized, it scans this list. If one
33186752Sfjoe * has found softc with same irq and ioaddr different by 4 then it assumes
33286752Sfjoe * this board to be "master".
33386752Sfjoe */
33486752Sfjoe
33586752Sfjoevoid
33686752Sfjoesbni_intr(void *arg)
33786752Sfjoe{
33886752Sfjoe	struct sbni_softc *sc;
33986752Sfjoe	int repeat;
34086752Sfjoe
34186752Sfjoe	sc = (struct sbni_softc *)arg;
34286752Sfjoe
34386752Sfjoe	do {
34486752Sfjoe		repeat = 0;
34586752Sfjoe		if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) {
34686752Sfjoe			handle_channel(sc);
34786752Sfjoe			repeat = 1;
34886752Sfjoe		}
349101393Sfjoe		if (sc->slave_sc && 	/* second channel present */
350101393Sfjoe		    (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY))) {
35186752Sfjoe			handle_channel(sc->slave_sc);
35286752Sfjoe			repeat = 1;
35386752Sfjoe		}
35486752Sfjoe	} while (repeat);
35586752Sfjoe}
35686752Sfjoe
35786752Sfjoe
35886752Sfjoestatic void
35986752Sfjoehandle_channel(struct sbni_softc *sc)
36086752Sfjoe{
36186752Sfjoe	int req_ans;
36286752Sfjoe	u_char csr0;
36386752Sfjoe
36486752Sfjoe	sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ);
36586752Sfjoe
36686752Sfjoe	sc->timer_ticks = CHANGE_LEVEL_START_TICKS;
36786752Sfjoe	for (;;) {
36886752Sfjoe		csr0 = sbni_inb(sc, CSR0);
36986752Sfjoe		if ((csr0 & (RC_RDY | TR_RDY)) == 0)
37086752Sfjoe			break;
37186752Sfjoe
37286752Sfjoe		req_ans = !(sc->state & FL_PREV_OK);
37386752Sfjoe
37486752Sfjoe		if (csr0 & RC_RDY)
37586752Sfjoe			req_ans = recv_frame(sc);
37686752Sfjoe
37786752Sfjoe		/*
37886752Sfjoe		 * TR_RDY always equals 1 here because we have owned the marker,
37986752Sfjoe		 * and we set TR_REQ when disabled interrupts
38086752Sfjoe		 */
38186752Sfjoe		csr0 = sbni_inb(sc, CSR0);
38286752Sfjoe		if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0)
38386752Sfjoe			printf("sbni: internal error!\n");
38486752Sfjoe
38586752Sfjoe		/* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */
38686752Sfjoe		if (req_ans || sc->tx_frameno != 0)
38786752Sfjoe			send_frame(sc);
388101393Sfjoe		else {
38986752Sfjoe			/* send the marker without any data */
39086752Sfjoe			sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ);
391101393Sfjoe		}
39286752Sfjoe	}
39386752Sfjoe
39486752Sfjoe	sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT);
39586752Sfjoe}
39686752Sfjoe
39786752Sfjoe
39886752Sfjoe/*
39986752Sfjoe * Routine returns 1 if it need to acknoweledge received frame.
40086752Sfjoe * Empty frame received without errors won't be acknoweledged.
40186752Sfjoe */
40286752Sfjoe
40386752Sfjoestatic int
40486752Sfjoerecv_frame(struct sbni_softc *sc)
40586752Sfjoe{
40686752Sfjoe	u_int32_t crc;
40786752Sfjoe	u_int framelen, frameno, ack;
40886752Sfjoe	u_int is_first, frame_ok;
40986752Sfjoe
41086752Sfjoe	crc = CRC32_INITIAL;
41186752Sfjoe	if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) {
412101393Sfjoe		frame_ok = framelen > 4 ?
413101393Sfjoe		    upload_data(sc, framelen, frameno, is_first, crc) :
414101393Sfjoe		    skip_tail(sc, framelen, crc);
41586752Sfjoe		if (frame_ok)
41686752Sfjoe			interpret_ack(sc, ack);
41786752Sfjoe	} else
41886752Sfjoe		frame_ok = 0;
41986752Sfjoe
42086752Sfjoe	sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER);
42186752Sfjoe	if (frame_ok) {
42286752Sfjoe		sc->state |= FL_PREV_OK;
42386752Sfjoe		if (framelen > 4)
42486752Sfjoe			sc->in_stats.all_rx_number++;
42586752Sfjoe	} else {
42686752Sfjoe		sc->state &= ~FL_PREV_OK;
42786752Sfjoe		change_level(sc);
42886752Sfjoe		sc->in_stats.all_rx_number++;
42986752Sfjoe		sc->in_stats.bad_rx_number++;
43086752Sfjoe	}
43186752Sfjoe
43286752Sfjoe	return (!frame_ok || framelen > 4);
43386752Sfjoe}
43486752Sfjoe
43586752Sfjoe
43686752Sfjoestatic void
43786752Sfjoesend_frame(struct sbni_softc *sc)
43886752Sfjoe{
43986752Sfjoe	u_int32_t crc;
44086752Sfjoe	u_char csr0;
44186752Sfjoe
44286752Sfjoe	crc = CRC32_INITIAL;
44386752Sfjoe	if (sc->state & FL_NEED_RESEND) {
44486752Sfjoe
44586752Sfjoe		/* if frame was sended but not ACK'ed - resend it */
44686752Sfjoe		if (sc->trans_errors) {
44786752Sfjoe			sc->trans_errors--;
44886752Sfjoe			if (sc->framelen != 0)
44986752Sfjoe				sc->in_stats.resend_tx_number++;
45086752Sfjoe		} else {
45186752Sfjoe			/* cannot xmit with many attempts */
45286752Sfjoe			drop_xmit_queue(sc);
45386752Sfjoe			goto do_send;
45486752Sfjoe		}
45586752Sfjoe	} else
45686752Sfjoe		sc->trans_errors = TR_ERROR_COUNT;
45786752Sfjoe
45886752Sfjoe	send_frame_header(sc, &crc);
45986752Sfjoe	sc->state |= FL_NEED_RESEND;
46086752Sfjoe	/*
46186752Sfjoe	 * FL_NEED_RESEND will be cleared after ACK, but if empty
46286752Sfjoe	 * frame sended then in prepare_to_send next frame
46386752Sfjoe	 */
46486752Sfjoe
46586752Sfjoe
46686752Sfjoe	if (sc->framelen) {
46786752Sfjoe		download_data(sc, &crc);
46886752Sfjoe		sc->in_stats.all_tx_number++;
46986752Sfjoe		sc->state |= FL_WAIT_ACK;
47086752Sfjoe	}
47186752Sfjoe
47286752Sfjoe	sbni_outsb(sc, (u_char *)&crc, sizeof crc);
47386752Sfjoe
47486752Sfjoedo_send:
47586752Sfjoe	csr0 = sbni_inb(sc, CSR0);
47686752Sfjoe	sbni_outb(sc, CSR0, csr0 & ~TR_REQ);
47786752Sfjoe
47886752Sfjoe	if (sc->tx_frameno) {
47986752Sfjoe		/* next frame exists - request to send */
48086752Sfjoe		sbni_outb(sc, CSR0, csr0 | TR_REQ);
48186752Sfjoe	}
48286752Sfjoe}
48386752Sfjoe
48486752Sfjoe
48586752Sfjoestatic void
48686752Sfjoedownload_data(struct sbni_softc *sc, u_int32_t *crc_p)
48786752Sfjoe{
48886752Sfjoe	struct mbuf *m;
48986752Sfjoe	caddr_t	data_p;
49086752Sfjoe	u_int data_len, pos, slice;
49186752Sfjoe
49286752Sfjoe	data_p = NULL;		/* initialized to avoid warn */
49386752Sfjoe	pos = 0;
49486752Sfjoe
49586752Sfjoe	for (m = sc->tx_buf_p;  m != NULL && pos < sc->pktlen;  m = m->m_next) {
49686752Sfjoe		if (pos + m->m_len > sc->outpos) {
49786752Sfjoe			data_len = m->m_len - (sc->outpos - pos);
49886752Sfjoe			data_p = mtod(m, caddr_t) + (sc->outpos - pos);
49986752Sfjoe
50086752Sfjoe			goto do_copy;
50186752Sfjoe		} else
50286752Sfjoe			pos += m->m_len;
50386752Sfjoe	}
50486752Sfjoe
50586752Sfjoe	data_len = 0;
50686752Sfjoe
50786752Sfjoedo_copy:
50886752Sfjoe	pos = 0;
50986752Sfjoe	do {
51086752Sfjoe		if (data_len) {
51186752Sfjoe			slice = min(data_len, sc->framelen - pos);
51286752Sfjoe			sbni_outsb(sc, data_p, slice);
51386752Sfjoe			*crc_p = calc_crc32(*crc_p, data_p, slice);
51486752Sfjoe
51586752Sfjoe			pos += slice;
51686752Sfjoe			if (data_len -= slice)
51786752Sfjoe				data_p += slice;
51886752Sfjoe			else {
519101393Sfjoe				do {
520101393Sfjoe					m = m->m_next;
521101393Sfjoe				} while (m != NULL && m->m_len == 0);
52286752Sfjoe
52386752Sfjoe				if (m) {
52486752Sfjoe					data_len = m->m_len;
52586752Sfjoe					data_p = mtod(m, caddr_t);
52686752Sfjoe				}
52786752Sfjoe			}
52886752Sfjoe		} else {
52986752Sfjoe			/* frame too short - zero padding */
53086752Sfjoe
53186752Sfjoe			pos = sc->framelen - pos;
53286752Sfjoe			while (pos--) {
53386752Sfjoe				sbni_outb(sc, DAT, 0);
53486752Sfjoe				*crc_p = CRC32(0, *crc_p);
53586752Sfjoe			}
53686752Sfjoe			return;
53786752Sfjoe		}
53886752Sfjoe	} while (pos < sc->framelen);
53986752Sfjoe}
54086752Sfjoe
54186752Sfjoe
54286752Sfjoestatic int
54386752Sfjoeupload_data(struct sbni_softc *sc, u_int framelen, u_int frameno,
54486752Sfjoe	    u_int is_first, u_int32_t crc)
54586752Sfjoe{
54686752Sfjoe	int frame_ok;
54786752Sfjoe
54886752Sfjoe	if (is_first) {
54986752Sfjoe		sc->wait_frameno = frameno;
55086752Sfjoe		sc->inppos = 0;
55186752Sfjoe	}
55286752Sfjoe
55386752Sfjoe	if (sc->wait_frameno == frameno) {
55486752Sfjoe
55586752Sfjoe		if (sc->inppos + framelen  <=  ETHER_MAX_LEN) {
55686752Sfjoe			frame_ok = append_frame_to_pkt(sc, framelen, crc);
55786752Sfjoe
55886752Sfjoe		/*
55986752Sfjoe		 * if CRC is right but framelen incorrect then transmitter
56086752Sfjoe		 * error was occured... drop entire packet
56186752Sfjoe		 */
56286752Sfjoe		} else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) {
56386752Sfjoe			sc->wait_frameno = 0;
56486752Sfjoe			sc->inppos = 0;
56586752Sfjoe			sc->arpcom.ac_if.if_ierrors++;
56686752Sfjoe			/* now skip all frames until is_first != 0 */
56786752Sfjoe		}
56886752Sfjoe	} else
56986752Sfjoe		frame_ok = skip_tail(sc, framelen, crc);
57086752Sfjoe
57186752Sfjoe	if (is_first && !frame_ok) {
57286752Sfjoe		/*
57386752Sfjoe		 * Frame has been violated, but we have stored
57486752Sfjoe		 * is_first already... Drop entire packet.
57586752Sfjoe		 */
57686752Sfjoe		sc->wait_frameno = 0;
57786752Sfjoe		sc->arpcom.ac_if.if_ierrors++;
57886752Sfjoe	}
57986752Sfjoe
58086752Sfjoe	return (frame_ok);
58186752Sfjoe}
58286752Sfjoe
58386752Sfjoe
58486752Sfjoestatic __inline void	send_complete(struct sbni_softc *);
58586752Sfjoe
58686752Sfjoestatic __inline void
58786752Sfjoesend_complete(struct sbni_softc *sc)
58886752Sfjoe{
58986752Sfjoe	m_freem(sc->tx_buf_p);
59086752Sfjoe	sc->tx_buf_p = NULL;
59186752Sfjoe	sc->arpcom.ac_if.if_opackets++;
59286752Sfjoe}
59386752Sfjoe
59486752Sfjoe
59586752Sfjoestatic void
59686752Sfjoeinterpret_ack(struct sbni_softc *sc, u_int ack)
59786752Sfjoe{
59886752Sfjoe	if (ack == FRAME_SENT_OK) {
59986752Sfjoe		sc->state &= ~FL_NEED_RESEND;
60086752Sfjoe
60186752Sfjoe		if (sc->state & FL_WAIT_ACK) {
60286752Sfjoe			sc->outpos += sc->framelen;
60386752Sfjoe
604101393Sfjoe			if (--sc->tx_frameno) {
605101393Sfjoe				sc->framelen = min(
606101393Sfjoe				    sc->maxframe, sc->pktlen - sc->outpos);
607101393Sfjoe			} else {
60886752Sfjoe				send_complete(sc);
60986752Sfjoe				prepare_to_send(sc);
61086752Sfjoe			}
61186752Sfjoe		}
61286752Sfjoe	}
61386752Sfjoe
61486752Sfjoe	sc->state &= ~FL_WAIT_ACK;
61586752Sfjoe}
61686752Sfjoe
61786752Sfjoe
61886752Sfjoe/*
61986752Sfjoe * Glue received frame with previous fragments of packet.
62086752Sfjoe * Indicate packet when last frame would be accepted.
62186752Sfjoe */
62286752Sfjoe
62386752Sfjoestatic int
62486752Sfjoeappend_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc)
62586752Sfjoe{
62686752Sfjoe	caddr_t p;
62786752Sfjoe
62886752Sfjoe	if (sc->inppos + framelen > ETHER_MAX_LEN)
62986752Sfjoe		return (0);
63086752Sfjoe
63186752Sfjoe	if (!sc->rx_buf_p && !get_rx_buf(sc))
63286752Sfjoe		return (0);
63386752Sfjoe
63486752Sfjoe	p = sc->rx_buf_p->m_data + sc->inppos;
63586752Sfjoe	sbni_insb(sc, p, framelen);
63686752Sfjoe	if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER)
63786752Sfjoe		return (0);
63886752Sfjoe
63986752Sfjoe	sc->inppos += framelen - 4;
64086752Sfjoe	if (--sc->wait_frameno == 0) {		/* last frame received */
64186752Sfjoe		indicate_pkt(sc);
64286752Sfjoe		sc->arpcom.ac_if.if_ipackets++;
64386752Sfjoe	}
64486752Sfjoe
64586752Sfjoe	return (1);
64686752Sfjoe}
64786752Sfjoe
64886752Sfjoe
64986752Sfjoe/*
65086752Sfjoe * Prepare to start output on adapter. Current priority must be set to splimp
65186752Sfjoe * before this routine is called.
65286752Sfjoe * Transmitter will be actually activated when marker has been accepted.
65386752Sfjoe */
65486752Sfjoe
65586752Sfjoestatic void
65686752Sfjoeprepare_to_send(struct sbni_softc *sc)
65786752Sfjoe{
65886752Sfjoe	struct mbuf *m;
65986752Sfjoe	u_int len;
66086752Sfjoe
66186752Sfjoe	/* sc->tx_buf_p == NULL here! */
66286752Sfjoe	if (sc->tx_buf_p)
66386752Sfjoe		printf("sbni: memory leak!\n");
66486752Sfjoe
66586752Sfjoe	sc->outpos = 0;
66686752Sfjoe	sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
66786752Sfjoe
66886752Sfjoe	for (;;) {
66986752Sfjoe		IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, sc->tx_buf_p);
67086752Sfjoe		if (!sc->tx_buf_p) {
67186752Sfjoe			/* nothing to transmit... */
67286752Sfjoe			sc->pktlen     = 0;
67386752Sfjoe			sc->tx_frameno = 0;
67486752Sfjoe			sc->framelen   = 0;
67586752Sfjoe			sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
67686752Sfjoe			return;
67786752Sfjoe		}
67886752Sfjoe
67986752Sfjoe		for (len = 0, m = sc->tx_buf_p;  m;  m = m->m_next)
68086752Sfjoe			len += m->m_len;
68186752Sfjoe
68286752Sfjoe		if (len != 0)
68386752Sfjoe			break;
68486752Sfjoe		m_freem(sc->tx_buf_p);
68586752Sfjoe	}
68686752Sfjoe
68786752Sfjoe	if (len < SBNI_MIN_LEN)
68886752Sfjoe		len = SBNI_MIN_LEN;
68986752Sfjoe
69086752Sfjoe	sc->pktlen	= len;
69186752Sfjoe	sc->tx_frameno	= (len + sc->maxframe - 1) / sc->maxframe;
69286752Sfjoe	sc->framelen	= min(len, sc->maxframe);
69386752Sfjoe
69486752Sfjoe	sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ);
69586752Sfjoe	sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
696106937Ssam	BPF_MTAP(&sc->arpcom.ac_if, sc->tx_buf_p);
69786752Sfjoe}
69886752Sfjoe
69986752Sfjoe
70086752Sfjoestatic void
70186752Sfjoedrop_xmit_queue(struct sbni_softc *sc)
70286752Sfjoe{
70386752Sfjoe	struct mbuf *m;
70486752Sfjoe
70586752Sfjoe	if (sc->tx_buf_p) {
70686752Sfjoe		m_freem(sc->tx_buf_p);
70786752Sfjoe		sc->tx_buf_p = NULL;
70886752Sfjoe		sc->arpcom.ac_if.if_oerrors++;
70986752Sfjoe	}
71086752Sfjoe
71186752Sfjoe	for (;;) {
71286752Sfjoe		IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m);
71386752Sfjoe		if (m == NULL)
71486752Sfjoe			break;
71586752Sfjoe		m_freem(m);
71686752Sfjoe		sc->arpcom.ac_if.if_oerrors++;
71786752Sfjoe	}
71886752Sfjoe
71986752Sfjoe	sc->tx_frameno	= 0;
72086752Sfjoe	sc->framelen	= 0;
72186752Sfjoe	sc->outpos	= 0;
72286752Sfjoe	sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
72386752Sfjoe	sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
72486752Sfjoe}
72586752Sfjoe
72686752Sfjoe
72786752Sfjoestatic void
72886752Sfjoesend_frame_header(struct sbni_softc *sc, u_int32_t *crc_p)
72986752Sfjoe{
73086752Sfjoe	u_int32_t crc;
73186752Sfjoe	u_int len_field;
73286752Sfjoe	u_char value;
73386752Sfjoe
73486752Sfjoe	crc = *crc_p;
73586752Sfjoe	len_field = sc->framelen + 6;	/* CRC + frameno + reserved */
73686752Sfjoe
73786752Sfjoe	if (sc->state & FL_NEED_RESEND)
73886752Sfjoe		len_field |= FRAME_RETRY;	/* non-first attempt... */
73986752Sfjoe
74086752Sfjoe	if (sc->outpos == 0)
74186752Sfjoe		len_field |= FRAME_FIRST;
74286752Sfjoe
74386752Sfjoe	len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD;
74486752Sfjoe	sbni_outb(sc, DAT, SBNI_SIG);
74586752Sfjoe
74686752Sfjoe	value = (u_char)len_field;
74786752Sfjoe	sbni_outb(sc, DAT, value);
74886752Sfjoe	crc = CRC32(value, crc);
74986752Sfjoe	value = (u_char)(len_field >> 8);
75086752Sfjoe	sbni_outb(sc, DAT, value);
75186752Sfjoe	crc = CRC32(value, crc);
75286752Sfjoe
75386752Sfjoe	sbni_outb(sc, DAT, sc->tx_frameno);
75486752Sfjoe	crc = CRC32(sc->tx_frameno, crc);
75586752Sfjoe	sbni_outb(sc, DAT, 0);
75686752Sfjoe	crc = CRC32(0, crc);
75786752Sfjoe	*crc_p = crc;
75886752Sfjoe}
75986752Sfjoe
76086752Sfjoe
76186752Sfjoe/*
76286752Sfjoe * if frame tail not needed (incorrect number or received twice),
76386752Sfjoe * it won't store, but CRC will be calculated
76486752Sfjoe */
76586752Sfjoe
76686752Sfjoestatic int
76786752Sfjoeskip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc)
76886752Sfjoe{
76986752Sfjoe	while (tail_len--)
77086752Sfjoe		crc = CRC32(sbni_inb(sc, DAT), crc);
77186752Sfjoe
77286752Sfjoe	return (crc == CRC32_REMAINDER);
77386752Sfjoe}
77486752Sfjoe
77586752Sfjoe
77686752Sfjoestatic int
77786752Sfjoecheck_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno,
77886752Sfjoe	   u_int *ack, u_int *is_first, u_int32_t *crc_p)
77986752Sfjoe{
78086752Sfjoe	u_int32_t crc;
78186752Sfjoe	u_char value;
78286752Sfjoe
78386752Sfjoe	crc = *crc_p;
78486752Sfjoe	if (sbni_inb(sc, DAT) != SBNI_SIG)
78586752Sfjoe		return (0);
78686752Sfjoe
78786752Sfjoe	value = sbni_inb(sc, DAT);
78886752Sfjoe	*framelen = (u_int)value;
78986752Sfjoe	crc = CRC32(value, crc);
79086752Sfjoe	value = sbni_inb(sc, DAT);
79186752Sfjoe	*framelen |= ((u_int)value) << 8;
79286752Sfjoe	crc = CRC32(value, crc);
79386752Sfjoe
79486752Sfjoe	*ack = *framelen & FRAME_ACK_MASK;
79586752Sfjoe	*is_first = (*framelen & FRAME_FIRST) != 0;
79686752Sfjoe
79786752Sfjoe	if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3)
79886752Sfjoe		return (0);
79986752Sfjoe
80086752Sfjoe	value = sbni_inb(sc, DAT);
80186752Sfjoe	*frameno = (u_int)value;
80286752Sfjoe	crc = CRC32(value, crc);
80386752Sfjoe
80486752Sfjoe	crc = CRC32(sbni_inb(sc, DAT), crc);		/* reserved byte */
80586752Sfjoe	*framelen -= 2;
80686752Sfjoe
80786752Sfjoe	*crc_p = crc;
80886752Sfjoe	return (1);
80986752Sfjoe}
81086752Sfjoe
81186752Sfjoe
81286752Sfjoestatic int
81386752Sfjoeget_rx_buf(struct sbni_softc *sc)
81486752Sfjoe{
81586752Sfjoe	struct mbuf *m;
81686752Sfjoe
81786752Sfjoe	MGETHDR(m, M_DONTWAIT, MT_DATA);
81886752Sfjoe	if (m == NULL) {
819104256Sbrooks		if_printf(&sc->arpcom.ac_if, "cannot allocate header mbuf\n");
82086752Sfjoe		return (0);
82186752Sfjoe	}
82286752Sfjoe
82386752Sfjoe	/*
82486752Sfjoe	 * We always put the received packet in a single buffer -
82586752Sfjoe	 * either with just an mbuf header or in a cluster attached
82686752Sfjoe	 * to the header. The +2 is to compensate for the alignment
82786752Sfjoe	 * fixup below.
82886752Sfjoe	 */
82986752Sfjoe	if (ETHER_MAX_LEN + 2 > MHLEN) {
83086752Sfjoe		/* Attach an mbuf cluster */
83186752Sfjoe		MCLGET(m, M_DONTWAIT);
83286752Sfjoe		if ((m->m_flags & M_EXT) == 0) {
83386752Sfjoe			m_freem(m);
83486752Sfjoe			return (0);
83586752Sfjoe		}
83686752Sfjoe	}
83786752Sfjoe	m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2;
83886752Sfjoe
83986752Sfjoe	/*
84086752Sfjoe	 * The +2 is to longword align the start of the real packet.
84186752Sfjoe	 * (sizeof ether_header == 14)
84286752Sfjoe	 * This is important for NFS.
84386752Sfjoe	 */
84486752Sfjoe	m_adj(m, 2);
84586752Sfjoe	sc->rx_buf_p = m;
84686752Sfjoe	return (1);
84786752Sfjoe}
84886752Sfjoe
84986752Sfjoe
85086752Sfjoestatic void
85186752Sfjoeindicate_pkt(struct sbni_softc *sc)
85286752Sfjoe{
853106937Ssam	struct ifnet *ifp = &sc->arpcom.ac_if;
85486752Sfjoe	struct mbuf *m;
85586752Sfjoe
85686752Sfjoe	m = sc->rx_buf_p;
857106937Ssam	m->m_pkthdr.rcvif = ifp;
85886752Sfjoe	m->m_pkthdr.len   = m->m_len = sc->inppos;
85986752Sfjoe
860106937Ssam	(*ifp->if_input)(ifp, m);
86186752Sfjoe	sc->rx_buf_p = NULL;
86286752Sfjoe}
86386752Sfjoe
86486752Sfjoe/* -------------------------------------------------------------------------- */
86586752Sfjoe
86686752Sfjoe/*
86786752Sfjoe * Routine checks periodically wire activity and regenerates marker if
86886752Sfjoe * connect was inactive for a long time.
86986752Sfjoe */
87086752Sfjoe
87186752Sfjoestatic void
87286752Sfjoesbni_timeout(void *xsc)
87386752Sfjoe{
87486752Sfjoe	struct sbni_softc *sc;
87586752Sfjoe	int s;
87686752Sfjoe	u_char csr0;
87786752Sfjoe
87886752Sfjoe	sc = (struct sbni_softc *)xsc;
87986752Sfjoe	s = splimp();
88086752Sfjoe
88186752Sfjoe	csr0 = sbni_inb(sc, CSR0);
88286752Sfjoe	if (csr0 & RC_CHK) {
88386752Sfjoe
88486752Sfjoe		if (sc->timer_ticks) {
88586752Sfjoe			if (csr0 & (RC_RDY | BU_EMP))
88686752Sfjoe				/* receiving not active */
88786752Sfjoe				sc->timer_ticks--;
88886752Sfjoe		} else {
88986752Sfjoe			sc->in_stats.timeout_number++;
89086752Sfjoe			if (sc->delta_rxl)
89186752Sfjoe				timeout_change_level(sc);
89286752Sfjoe
89386752Sfjoe			sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES);
89486752Sfjoe			csr0 = sbni_inb(sc, CSR0);
89586752Sfjoe		}
89686752Sfjoe	}
89786752Sfjoe
89886752Sfjoe	sbni_outb(sc, CSR0, csr0 | RC_CHK);
89986752Sfjoe	sc->wch = timeout(sbni_timeout, sc, hz/SBNI_HZ);
90086752Sfjoe	splx(s);
90186752Sfjoe}
90286752Sfjoe
90386752Sfjoe/* -------------------------------------------------------------------------- */
90486752Sfjoe
90586752Sfjoestatic void
90686752Sfjoecard_start(struct sbni_softc *sc)
90786752Sfjoe{
90886752Sfjoe	sc->timer_ticks = CHANGE_LEVEL_START_TICKS;
90986752Sfjoe	sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
91086752Sfjoe	sc->state |= FL_PREV_OK;
91186752Sfjoe
91286752Sfjoe	sc->inppos = 0;
91386752Sfjoe	sc->wait_frameno = 0;
91486752Sfjoe
91586752Sfjoe	sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES);
91686752Sfjoe	sbni_outb(sc, CSR0, EN_INT);
91786752Sfjoe}
91886752Sfjoe
91986752Sfjoe/* -------------------------------------------------------------------------- */
92086752Sfjoe
92186752Sfjoe/*
92286752Sfjoe * Device timeout/watchdog routine. Entered if the device neglects to
92386752Sfjoe *	generate an interrupt after a transmit has been started on it.
92486752Sfjoe */
92586752Sfjoe
92686752Sfjoestatic void
92786752Sfjoesbni_watchdog(struct ifnet *ifp)
92886752Sfjoe{
92986752Sfjoe	log(LOG_ERR, "sbni%d: device timeout\n", ifp->if_unit);
93086752Sfjoe	ifp->if_oerrors++;
93186752Sfjoe}
93286752Sfjoe
93386752Sfjoe
93486752Sfjoestatic u_char rxl_tab[] = {
93586752Sfjoe	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
93686752Sfjoe	0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
93786752Sfjoe};
93886752Sfjoe
93986752Sfjoe#define SIZE_OF_TIMEOUT_RXL_TAB 4
94086752Sfjoestatic u_char timeout_rxl_tab[] = {
94186752Sfjoe	0x03, 0x05, 0x08, 0x0b
94286752Sfjoe};
94386752Sfjoe
94486752Sfjoestatic void
94586752Sfjoeset_initial_values(struct sbni_softc *sc, struct sbni_flags flags)
94686752Sfjoe{
94786752Sfjoe	if (flags.fixed_rxl) {
94886752Sfjoe		sc->delta_rxl = 0; /* disable receive level autodetection */
94986752Sfjoe		sc->cur_rxl_index = flags.rxl;
95086752Sfjoe	} else {
95186752Sfjoe		sc->delta_rxl = DEF_RXL_DELTA;
95286752Sfjoe		sc->cur_rxl_index = DEF_RXL;
95386752Sfjoe	}
95486752Sfjoe
95586752Sfjoe	sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE;
95686752Sfjoe	sc->csr1.rxl  = rxl_tab[sc->cur_rxl_index];
95786752Sfjoe	sc->maxframe  = DEFAULT_FRAME_LEN;
95886752Sfjoe
95986752Sfjoe	/*
96086752Sfjoe	 * generate Ethernet address (0x00ff01xxxxxx)
96186752Sfjoe	 */
962101400Sfjoe	*(u_int16_t *) sc->arpcom.ac_enaddr = htons(0x00ff);
963101400Sfjoe	if (flags.mac_addr) {
964101400Sfjoe		*(u_int32_t *) (sc->arpcom.ac_enaddr + 2) =
965101400Sfjoe		    htonl(flags.mac_addr | 0x01000000);
966101400Sfjoe	} else {
967101400Sfjoe		*(u_char *) (sc->arpcom.ac_enaddr + 2) = 0x01;
968101400Sfjoe		read_random(sc->arpcom.ac_enaddr + 3, 3);
96986752Sfjoe	}
97086752Sfjoe}
97186752Sfjoe
97286752Sfjoe
97386752Sfjoe#ifdef SBNI_DUAL_COMPOUND
97486752Sfjoe
97586752Sfjoestruct sbni_softc *
97686752Sfjoeconnect_to_master(struct sbni_softc *sc)
97786752Sfjoe{
978101400Sfjoe	struct sbni_softc *p, *p_prev;
97986752Sfjoe
980101400Sfjoe	for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) {
981101400Sfjoe		if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 ||
982101400Sfjoe		    rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) {
983101400Sfjoe			p->slave_sc = sc;
984101400Sfjoe			if (p_prev)
985101400Sfjoe				p_prev->link = p->link;
986101400Sfjoe			else
987101400Sfjoe				sbni_headlist = p->link;
988101400Sfjoe			return p;
98986752Sfjoe		}
99086752Sfjoe	}
99186752Sfjoe
99286752Sfjoe	return (NULL);
99386752Sfjoe}
99486752Sfjoe
99586752Sfjoe#endif	/* SBNI_DUAL_COMPOUND */
99686752Sfjoe
99786752Sfjoe
99886752Sfjoe/* Receive level auto-selection */
99986752Sfjoe
100086752Sfjoestatic void
100186752Sfjoechange_level(struct sbni_softc *sc)
100286752Sfjoe{
100386752Sfjoe	if (sc->delta_rxl == 0)		/* do not auto-negotiate RxL */
100486752Sfjoe		return;
100586752Sfjoe
100686752Sfjoe	if (sc->cur_rxl_index == 0)
100786752Sfjoe		sc->delta_rxl = 1;
100886752Sfjoe	else if (sc->cur_rxl_index == 15)
100986752Sfjoe		sc->delta_rxl = -1;
101086752Sfjoe	else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd)
101186752Sfjoe		sc->delta_rxl = -sc->delta_rxl;
101286752Sfjoe
101386752Sfjoe	sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl];
101486752Sfjoe	sbni_inb(sc, CSR0);	/* it needed for PCI cards */
101586752Sfjoe	sbni_outb(sc, CSR1, *(u_char *)&sc->csr1);
101686752Sfjoe
101786752Sfjoe	sc->prev_rxl_rcvd = sc->cur_rxl_rcvd;
101886752Sfjoe	sc->cur_rxl_rcvd  = 0;
101986752Sfjoe}
102086752Sfjoe
102186752Sfjoe
102286752Sfjoestatic void
102386752Sfjoetimeout_change_level(struct sbni_softc *sc)
102486752Sfjoe{
102586752Sfjoe	sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl];
102686752Sfjoe	if (++sc->timeout_rxl >= 4)
102786752Sfjoe		sc->timeout_rxl = 0;
102886752Sfjoe
102986752Sfjoe	sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
103086752Sfjoe	sbni_inb(sc, CSR0);
103186752Sfjoe	sbni_outb(sc, CSR1, *(u_char *)&sc->csr1);
103286752Sfjoe
103386752Sfjoe	sc->prev_rxl_rcvd = sc->cur_rxl_rcvd;
103486752Sfjoe	sc->cur_rxl_rcvd  = 0;
103586752Sfjoe}
103686752Sfjoe
103786752Sfjoe/* -------------------------------------------------------------------------- */
103886752Sfjoe
103986752Sfjoe/*
104086752Sfjoe * Process an ioctl request. This code needs some work - it looks
104186752Sfjoe *	pretty ugly.
104286752Sfjoe */
104386752Sfjoe
104486752Sfjoestatic int
104586752Sfjoesbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
104686752Sfjoe{
104786752Sfjoe	struct sbni_softc *sc;
104886752Sfjoe	struct ifreq *ifr;
104993593Sjhb	struct thread *td;
105086752Sfjoe	struct sbni_in_stats *in_stats;
105186752Sfjoe	struct sbni_flags flags;
105286752Sfjoe	int error, s;
105386752Sfjoe
105486752Sfjoe	sc = ifp->if_softc;
105586752Sfjoe	ifr = (struct ifreq *)data;
105693593Sjhb	td = curthread;
105786752Sfjoe	error = 0;
105886752Sfjoe
105986752Sfjoe	s = splimp();
106086752Sfjoe
106186752Sfjoe	switch (command) {
106286752Sfjoe	case SIOCSIFFLAGS:
106386752Sfjoe		/*
106486752Sfjoe		 * If the interface is marked up and stopped, then start it.
106586752Sfjoe		 * If it is marked down and running, then stop it.
106686752Sfjoe		 */
106786752Sfjoe		if (ifp->if_flags & IFF_UP) {
106886752Sfjoe			if (!(ifp->if_flags & IFF_RUNNING))
106986752Sfjoe				sbni_init(sc);
107086752Sfjoe		} else {
107186752Sfjoe			if (ifp->if_flags & IFF_RUNNING) {
107286752Sfjoe				sbni_stop(sc);
107386752Sfjoe				ifp->if_flags &= ~IFF_RUNNING;
107486752Sfjoe			}
107586752Sfjoe		}
107686752Sfjoe		break;
107786752Sfjoe
107886752Sfjoe	case SIOCADDMULTI:
107986752Sfjoe	case SIOCDELMULTI:
108086752Sfjoe		/*
108186752Sfjoe		 * Multicast list has changed; set the hardware filter
108286752Sfjoe		 * accordingly.
108386752Sfjoe		 */
108486752Sfjoe		error = 0;
108586752Sfjoe		/* if (ifr == NULL)
108686752Sfjoe			error = EAFNOSUPPORT; */
108786752Sfjoe		break;
108886752Sfjoe
108986752Sfjoe	case SIOCSIFMTU:
109086752Sfjoe		if (ifr->ifr_mtu > ETHERMTU)
109186752Sfjoe			error = EINVAL;
109286752Sfjoe		else
109386752Sfjoe			ifp->if_mtu = ifr->ifr_mtu;
109486752Sfjoe		break;
109586752Sfjoe
109686752Sfjoe		/*
109786752Sfjoe		 * SBNI specific ioctl
109886752Sfjoe		 */
109986752Sfjoe	case SIOCGHWFLAGS:	/* get flags */
110086752Sfjoe		bcopy((caddr_t) sc->arpcom.ac_enaddr+3, (caddr_t) &flags, 3);
110186752Sfjoe		flags.rxl = sc->cur_rxl_index;
110286752Sfjoe		flags.rate = sc->csr1.rate;
110386752Sfjoe		flags.fixed_rxl = (sc->delta_rxl == 0);
110486752Sfjoe		flags.fixed_rate = 1;
110586752Sfjoe		ifr->ifr_data = *(caddr_t*) &flags;
110686752Sfjoe		break;
110786752Sfjoe
110886752Sfjoe	case SIOCGINSTATS:
110986752Sfjoe		in_stats = (struct sbni_in_stats *)ifr->ifr_data;
111086752Sfjoe		bcopy((void *)(&(sc->in_stats)), (void *)in_stats,
111186752Sfjoe		      sizeof(struct sbni_in_stats));
111286752Sfjoe		break;
111386752Sfjoe
111486752Sfjoe	case SIOCSHWFLAGS:	/* set flags */
111586752Sfjoe		/* root only */
111693593Sjhb		error = suser(td);
111786752Sfjoe		if (error)
111886752Sfjoe			break;
111986752Sfjoe		flags = *(struct sbni_flags*)&ifr->ifr_data;
112086752Sfjoe		if (flags.fixed_rxl) {
112186752Sfjoe			sc->delta_rxl = 0;
112286752Sfjoe			sc->cur_rxl_index = flags.rxl;
112386752Sfjoe		} else {
112486752Sfjoe			sc->delta_rxl = DEF_RXL_DELTA;
112586752Sfjoe			sc->cur_rxl_index = DEF_RXL;
112686752Sfjoe		}
112786752Sfjoe		sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
112886752Sfjoe		sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE;
112986752Sfjoe		if (flags.mac_addr)
113086752Sfjoe			bcopy((caddr_t) &flags,
113186752Sfjoe			      (caddr_t) sc->arpcom.ac_enaddr+3, 3);
113286752Sfjoe
113386752Sfjoe		/* Don't be afraid... */
113486752Sfjoe		sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES);
113586752Sfjoe		break;
113686752Sfjoe
113786752Sfjoe	case SIOCRINSTATS:
113893593Sjhb		if (!(error = suser(td)))	/* root only */
113986752Sfjoe			bzero(&sc->in_stats, sizeof(struct sbni_in_stats));
114086752Sfjoe		break;
114186752Sfjoe
114286752Sfjoe	default:
1143106937Ssam		error = ether_ioctl(ifp, command, data);
1144106937Ssam		break;
114586752Sfjoe	}
114686752Sfjoe
114786752Sfjoe	splx(s);
114886752Sfjoe	return (error);
114986752Sfjoe}
115086752Sfjoe
115186752Sfjoe/* -------------------------------------------------------------------------- */
115286752Sfjoe
115386752Sfjoe#ifdef ASM_CRC
115486752Sfjoe
115586752Sfjoestatic u_int32_t
115686752Sfjoecalc_crc32(u_int32_t crc, caddr_t p, u_int len)
115786752Sfjoe{
115886752Sfjoe	register u_int32_t  _crc __asm ("ax");
115986752Sfjoe	_crc = crc;
116086752Sfjoe
116186752Sfjoe	__asm __volatile (
116286752Sfjoe		"xorl	%%ebx, %%ebx\n"
116386752Sfjoe		"movl	%1, %%esi\n"
116486752Sfjoe		"movl	%2, %%ecx\n"
116586752Sfjoe		"movl	$crc32tab, %%edi\n"
116686752Sfjoe		"shrl	$2, %%ecx\n"
116786752Sfjoe		"jz	1f\n"
116886752Sfjoe
116986752Sfjoe		".align 4\n"
117086752Sfjoe	"0:\n"
117186752Sfjoe		"movb	%%al, %%bl\n"
117286752Sfjoe		"movl	(%%esi), %%edx\n"
117386752Sfjoe		"shrl	$8, %%eax\n"
117486752Sfjoe		"xorb	%%dl, %%bl\n"
117586752Sfjoe		"shrl	$8, %%edx\n"
117686752Sfjoe		"xorl	(%%edi,%%ebx,4), %%eax\n"
117786752Sfjoe
117886752Sfjoe		"movb	%%al, %%bl\n"
117986752Sfjoe		"shrl	$8, %%eax\n"
118086752Sfjoe		"xorb	%%dl, %%bl\n"
118186752Sfjoe		"shrl	$8, %%edx\n"
118286752Sfjoe		"xorl	(%%edi,%%ebx,4), %%eax\n"
118386752Sfjoe
118486752Sfjoe		"movb	%%al, %%bl\n"
118586752Sfjoe		"shrl	$8, %%eax\n"
118686752Sfjoe		"xorb	%%dl, %%bl\n"
118786752Sfjoe		"movb	%%dh, %%dl\n"
118886752Sfjoe		"xorl	(%%edi,%%ebx,4), %%eax\n"
118986752Sfjoe
119086752Sfjoe		"movb	%%al, %%bl\n"
119186752Sfjoe		"shrl	$8, %%eax\n"
119286752Sfjoe		"xorb	%%dl, %%bl\n"
119386752Sfjoe		"addl	$4, %%esi\n"
119486752Sfjoe		"xorl	(%%edi,%%ebx,4), %%eax\n"
119586752Sfjoe
119686752Sfjoe		"decl	%%ecx\n"
119786752Sfjoe		"jnz	0b\n"
119886752Sfjoe
119986752Sfjoe	"1:\n"
120086752Sfjoe		"movl	%2, %%ecx\n"
120186752Sfjoe		"andl	$3, %%ecx\n"
120286752Sfjoe		"jz	2f\n"
120386752Sfjoe
120486752Sfjoe		"movb	%%al, %%bl\n"
120586752Sfjoe		"shrl	$8, %%eax\n"
120686752Sfjoe		"xorb	(%%esi), %%bl\n"
120786752Sfjoe		"xorl	(%%edi,%%ebx,4), %%eax\n"
120886752Sfjoe
120986752Sfjoe		"decl	%%ecx\n"
121086752Sfjoe		"jz	2f\n"
121186752Sfjoe
121286752Sfjoe		"movb	%%al, %%bl\n"
121386752Sfjoe		"shrl	$8, %%eax\n"
121486752Sfjoe		"xorb	1(%%esi), %%bl\n"
121586752Sfjoe		"xorl	(%%edi,%%ebx,4), %%eax\n"
121686752Sfjoe
121786752Sfjoe		"decl	%%ecx\n"
121886752Sfjoe		"jz	2f\n"
121986752Sfjoe
122086752Sfjoe		"movb	%%al, %%bl\n"
122186752Sfjoe		"shrl	$8, %%eax\n"
122286752Sfjoe		"xorb	2(%%esi), %%bl\n"
122386752Sfjoe		"xorl	(%%edi,%%ebx,4), %%eax\n"
122486752Sfjoe	"2:\n"
122586752Sfjoe		:
122686752Sfjoe		: "a" (_crc), "g" (p), "g" (len)
122786752Sfjoe		: "ax", "bx", "cx", "dx", "si", "di"
122886752Sfjoe	);
122986752Sfjoe
123086752Sfjoe	return (_crc);
123186752Sfjoe}
123286752Sfjoe
123386752Sfjoe#else	/* ASM_CRC */
123486752Sfjoe
123586752Sfjoestatic u_int32_t
123686752Sfjoecalc_crc32(u_int32_t crc, caddr_t p, u_int len)
123786752Sfjoe{
123886752Sfjoe	while (len--)
123986752Sfjoe		crc = CRC32(*p++, crc);
124086752Sfjoe
124186752Sfjoe	return (crc);
124286752Sfjoe}
124386752Sfjoe
124486752Sfjoe#endif	/* ASM_CRC */
124586752Sfjoe
124686752Sfjoe
1247103844Salfredstatic u_int32_t crc32tab[] __aligned(8) = {
124886752Sfjoe	0xD202EF8D,  0xA505DF1B,  0x3C0C8EA1,  0x4B0BBE37,
124986752Sfjoe	0xD56F2B94,  0xA2681B02,  0x3B614AB8,  0x4C667A2E,
125086752Sfjoe	0xDCD967BF,  0xABDE5729,  0x32D70693,  0x45D03605,
125186752Sfjoe	0xDBB4A3A6,  0xACB39330,  0x35BAC28A,  0x42BDF21C,
125286752Sfjoe	0xCFB5FFE9,  0xB8B2CF7F,  0x21BB9EC5,  0x56BCAE53,
125386752Sfjoe	0xC8D83BF0,  0xBFDF0B66,  0x26D65ADC,  0x51D16A4A,
125486752Sfjoe	0xC16E77DB,  0xB669474D,  0x2F6016F7,  0x58672661,
125586752Sfjoe	0xC603B3C2,  0xB1048354,  0x280DD2EE,  0x5F0AE278,
125686752Sfjoe	0xE96CCF45,  0x9E6BFFD3,  0x0762AE69,  0x70659EFF,
125786752Sfjoe	0xEE010B5C,  0x99063BCA,  0x000F6A70,  0x77085AE6,
125886752Sfjoe	0xE7B74777,  0x90B077E1,  0x09B9265B,  0x7EBE16CD,
125986752Sfjoe	0xE0DA836E,  0x97DDB3F8,  0x0ED4E242,  0x79D3D2D4,
126086752Sfjoe	0xF4DBDF21,  0x83DCEFB7,  0x1AD5BE0D,  0x6DD28E9B,
126186752Sfjoe	0xF3B61B38,  0x84B12BAE,  0x1DB87A14,  0x6ABF4A82,
126286752Sfjoe	0xFA005713,  0x8D076785,  0x140E363F,  0x630906A9,
126386752Sfjoe	0xFD6D930A,  0x8A6AA39C,  0x1363F226,  0x6464C2B0,
126486752Sfjoe	0xA4DEAE1D,  0xD3D99E8B,  0x4AD0CF31,  0x3DD7FFA7,
126586752Sfjoe	0xA3B36A04,  0xD4B45A92,  0x4DBD0B28,  0x3ABA3BBE,
126686752Sfjoe	0xAA05262F,  0xDD0216B9,  0x440B4703,  0x330C7795,
126786752Sfjoe	0xAD68E236,  0xDA6FD2A0,  0x4366831A,  0x3461B38C,
126886752Sfjoe	0xB969BE79,  0xCE6E8EEF,  0x5767DF55,  0x2060EFC3,
126986752Sfjoe	0xBE047A60,  0xC9034AF6,  0x500A1B4C,  0x270D2BDA,
127086752Sfjoe	0xB7B2364B,  0xC0B506DD,  0x59BC5767,  0x2EBB67F1,
127186752Sfjoe	0xB0DFF252,  0xC7D8C2C4,  0x5ED1937E,  0x29D6A3E8,
127286752Sfjoe	0x9FB08ED5,  0xE8B7BE43,  0x71BEEFF9,  0x06B9DF6F,
127386752Sfjoe	0x98DD4ACC,  0xEFDA7A5A,  0x76D32BE0,  0x01D41B76,
127486752Sfjoe	0x916B06E7,  0xE66C3671,  0x7F6567CB,  0x0862575D,
127586752Sfjoe	0x9606C2FE,  0xE101F268,  0x7808A3D2,  0x0F0F9344,
127686752Sfjoe	0x82079EB1,  0xF500AE27,  0x6C09FF9D,  0x1B0ECF0B,
127786752Sfjoe	0x856A5AA8,  0xF26D6A3E,  0x6B643B84,  0x1C630B12,
127886752Sfjoe	0x8CDC1683,  0xFBDB2615,  0x62D277AF,  0x15D54739,
127986752Sfjoe	0x8BB1D29A,  0xFCB6E20C,  0x65BFB3B6,  0x12B88320,
128086752Sfjoe	0x3FBA6CAD,  0x48BD5C3B,  0xD1B40D81,  0xA6B33D17,
128186752Sfjoe	0x38D7A8B4,  0x4FD09822,  0xD6D9C998,  0xA1DEF90E,
128286752Sfjoe	0x3161E49F,  0x4666D409,  0xDF6F85B3,  0xA868B525,
128386752Sfjoe	0x360C2086,  0x410B1010,  0xD80241AA,  0xAF05713C,
128486752Sfjoe	0x220D7CC9,  0x550A4C5F,  0xCC031DE5,  0xBB042D73,
128586752Sfjoe	0x2560B8D0,  0x52678846,  0xCB6ED9FC,  0xBC69E96A,
128686752Sfjoe	0x2CD6F4FB,  0x5BD1C46D,  0xC2D895D7,  0xB5DFA541,
128786752Sfjoe	0x2BBB30E2,  0x5CBC0074,  0xC5B551CE,  0xB2B26158,
128886752Sfjoe	0x04D44C65,  0x73D37CF3,  0xEADA2D49,  0x9DDD1DDF,
128986752Sfjoe	0x03B9887C,  0x74BEB8EA,  0xEDB7E950,  0x9AB0D9C6,
129086752Sfjoe	0x0A0FC457,  0x7D08F4C1,  0xE401A57B,  0x930695ED,
129186752Sfjoe	0x0D62004E,  0x7A6530D8,  0xE36C6162,  0x946B51F4,
129286752Sfjoe	0x19635C01,  0x6E646C97,  0xF76D3D2D,  0x806A0DBB,
129386752Sfjoe	0x1E0E9818,  0x6909A88E,  0xF000F934,  0x8707C9A2,
129486752Sfjoe	0x17B8D433,  0x60BFE4A5,  0xF9B6B51F,  0x8EB18589,
129586752Sfjoe	0x10D5102A,  0x67D220BC,  0xFEDB7106,  0x89DC4190,
129686752Sfjoe	0x49662D3D,  0x3E611DAB,  0xA7684C11,  0xD06F7C87,
129786752Sfjoe	0x4E0BE924,  0x390CD9B2,  0xA0058808,  0xD702B89E,
129886752Sfjoe	0x47BDA50F,  0x30BA9599,  0xA9B3C423,  0xDEB4F4B5,
129986752Sfjoe	0x40D06116,  0x37D75180,  0xAEDE003A,  0xD9D930AC,
130086752Sfjoe	0x54D13D59,  0x23D60DCF,  0xBADF5C75,  0xCDD86CE3,
130186752Sfjoe	0x53BCF940,  0x24BBC9D6,  0xBDB2986C,  0xCAB5A8FA,
130286752Sfjoe	0x5A0AB56B,  0x2D0D85FD,  0xB404D447,  0xC303E4D1,
130386752Sfjoe	0x5D677172,  0x2A6041E4,  0xB369105E,  0xC46E20C8,
130486752Sfjoe	0x72080DF5,  0x050F3D63,  0x9C066CD9,  0xEB015C4F,
130586752Sfjoe	0x7565C9EC,  0x0262F97A,  0x9B6BA8C0,  0xEC6C9856,
130686752Sfjoe	0x7CD385C7,  0x0BD4B551,  0x92DDE4EB,  0xE5DAD47D,
130786752Sfjoe	0x7BBE41DE,  0x0CB97148,  0x95B020F2,  0xE2B71064,
130886752Sfjoe	0x6FBF1D91,  0x18B82D07,  0x81B17CBD,  0xF6B64C2B,
130986752Sfjoe	0x68D2D988,  0x1FD5E91E,  0x86DCB8A4,  0xF1DB8832,
131086752Sfjoe	0x616495A3,  0x1663A535,  0x8F6AF48F,  0xF86DC419,
131186752Sfjoe	0x660951BA,  0x110E612C,  0x88073096,  0xFF000000
131286752Sfjoe};
1313