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