if_sbni.c revision 243857
1139749Simp/*-
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 243857 2012-12-04 09:32:43Z glebius $");
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>
65180263Sjhb#include <sys/bus.h>
6686752Sfjoe#include <sys/systm.h>
6786752Sfjoe#include <sys/socket.h>
6886752Sfjoe#include <sys/sockio.h>
6986752Sfjoe#include <sys/mbuf.h>
7086752Sfjoe#include <sys/kernel.h>
71164033Srwatson#include <sys/priv.h>
7286752Sfjoe#include <sys/proc.h>
7386752Sfjoe#include <sys/callout.h>
7486752Sfjoe#include <sys/syslog.h>
75101400Sfjoe#include <sys/random.h>
7686752Sfjoe
77101400Sfjoe#include <machine/bus.h>
78101400Sfjoe#include <sys/rman.h>
79101400Sfjoe#include <machine/resource.h>
80101400Sfjoe
8186752Sfjoe#include <net/if.h>
82152315Sru#include <net/if_dl.h>
8386752Sfjoe#include <net/ethernet.h>
8486752Sfjoe#include <net/bpf.h>
85147256Sbrooks#include <net/if_types.h>
8686752Sfjoe
8786752Sfjoe#include <dev/sbni/if_sbnireg.h>
8886752Sfjoe#include <dev/sbni/if_sbnivar.h>
8986752Sfjoe
9086752Sfjoestatic void	sbni_init(void *);
91180263Sjhbstatic void	sbni_init_locked(struct sbni_softc *);
9286752Sfjoestatic void	sbni_start(struct ifnet *);
93180263Sjhbstatic void	sbni_start_locked(struct ifnet *);
9486752Sfjoestatic int	sbni_ioctl(struct ifnet *, u_long, caddr_t);
9586752Sfjoestatic void	sbni_stop(struct sbni_softc *);
9686752Sfjoestatic void	handle_channel(struct sbni_softc *);
9786752Sfjoe
9886752Sfjoestatic void	card_start(struct sbni_softc *);
9986752Sfjoestatic int	recv_frame(struct sbni_softc *);
10086752Sfjoestatic void	send_frame(struct sbni_softc *);
10186752Sfjoestatic int	upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t);
10286752Sfjoestatic int	skip_tail(struct sbni_softc *, u_int, u_int32_t);
10386752Sfjoestatic void	interpret_ack(struct sbni_softc *, u_int);
10486752Sfjoestatic void	download_data(struct sbni_softc *, u_int32_t *);
10586752Sfjoestatic void	prepare_to_send(struct sbni_softc *);
10686752Sfjoestatic void	drop_xmit_queue(struct sbni_softc *);
10786752Sfjoestatic int	get_rx_buf(struct sbni_softc *);
10886752Sfjoestatic void	indicate_pkt(struct sbni_softc *);
10986752Sfjoestatic void	change_level(struct sbni_softc *);
11086752Sfjoestatic int	check_fhdr(struct sbni_softc *, u_int *, u_int *,
11186752Sfjoe			   u_int *, u_int *, u_int32_t *);
11286752Sfjoestatic int	append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t);
11386752Sfjoestatic void	timeout_change_level(struct sbni_softc *);
11486752Sfjoestatic void	send_frame_header(struct sbni_softc *, u_int32_t *);
11586752Sfjoestatic void	set_initial_values(struct sbni_softc *, struct sbni_flags);
11686752Sfjoe
11786752Sfjoestatic u_int32_t	calc_crc32(u_int32_t, caddr_t, u_int);
11886752Sfjoestatic timeout_t	sbni_timeout;
11986752Sfjoe
12086752Sfjoestatic __inline u_char	sbni_inb(struct sbni_softc *, enum sbni_reg);
12186752Sfjoestatic __inline void	sbni_outb(struct sbni_softc *, enum sbni_reg, u_char);
12286752Sfjoestatic __inline void	sbni_insb(struct sbni_softc *, u_char *, u_int);
12386752Sfjoestatic __inline void	sbni_outsb(struct sbni_softc *, u_char *, u_int);
12486752Sfjoe
12586752Sfjoestatic u_int32_t crc32tab[];
12686752Sfjoe
12786752Sfjoe#ifdef SBNI_DUAL_COMPOUND
128180263Sjhbstatic struct mtx headlist_lock;
129180263SjhbMTX_SYSINIT(headlist_lock, &headlist_lock, "sbni headlist", MTX_DEF);
130180263Sjhbstatic struct sbni_softc *sbni_headlist;
13186752Sfjoe#endif
13286752Sfjoe
13386752Sfjoe/* -------------------------------------------------------------------------- */
13486752Sfjoe
13586752Sfjoestatic __inline u_char
13686752Sfjoesbni_inb(struct sbni_softc *sc, enum sbni_reg reg)
13786752Sfjoe{
138101400Sfjoe	return bus_space_read_1(
139101400Sfjoe	    rman_get_bustag(sc->io_res),
140101400Sfjoe	    rman_get_bushandle(sc->io_res),
141101400Sfjoe	    sc->io_off + reg);
14286752Sfjoe}
14386752Sfjoe
14486752Sfjoestatic __inline void
14586752Sfjoesbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value)
14686752Sfjoe{
147101400Sfjoe	bus_space_write_1(
148101400Sfjoe	    rman_get_bustag(sc->io_res),
149101400Sfjoe	    rman_get_bushandle(sc->io_res),
150101400Sfjoe	    sc->io_off + reg, value);
15186752Sfjoe}
15286752Sfjoe
15386752Sfjoestatic __inline void
15486752Sfjoesbni_insb(struct sbni_softc *sc, u_char *to, u_int len)
15586752Sfjoe{
156101400Sfjoe	bus_space_read_multi_1(
157101400Sfjoe	    rman_get_bustag(sc->io_res),
158101400Sfjoe	    rman_get_bushandle(sc->io_res),
159101400Sfjoe	    sc->io_off + DAT, to, len);
16086752Sfjoe}
16186752Sfjoe
16286752Sfjoestatic __inline void
16386752Sfjoesbni_outsb(struct sbni_softc *sc, u_char *from, u_int len)
16486752Sfjoe{
165101400Sfjoe	bus_space_write_multi_1(
166101400Sfjoe	    rman_get_bustag(sc->io_res),
167101400Sfjoe	    rman_get_bushandle(sc->io_res),
168101400Sfjoe	    sc->io_off + DAT, from, len);
16986752Sfjoe}
17086752Sfjoe
17186752Sfjoe
17286752Sfjoe/*
17386752Sfjoe	Valid combinations in CSR0 (for probing):
17486752Sfjoe
17586752Sfjoe	VALID_DECODER	0000,0011,1011,1010
17686752Sfjoe
17786752Sfjoe				    	; 0   ; -
17886752Sfjoe				TR_REQ	; 1   ; +
17986752Sfjoe			TR_RDY	    	; 2   ; -
18086752Sfjoe			TR_RDY	TR_REQ	; 3   ; +
18186752Sfjoe		BU_EMP		    	; 4   ; +
18286752Sfjoe		BU_EMP	     	TR_REQ	; 5   ; +
18386752Sfjoe		BU_EMP	TR_RDY	    	; 6   ; -
18486752Sfjoe		BU_EMP	TR_RDY	TR_REQ	; 7   ; +
18586752Sfjoe	RC_RDY 		     		; 8   ; +
18686752Sfjoe	RC_RDY			TR_REQ	; 9   ; +
18786752Sfjoe	RC_RDY		TR_RDY		; 10  ; -
18886752Sfjoe	RC_RDY		TR_RDY	TR_REQ	; 11  ; -
18986752Sfjoe	RC_RDY	BU_EMP			; 12  ; -
19086752Sfjoe	RC_RDY	BU_EMP		TR_REQ	; 13  ; -
19186752Sfjoe	RC_RDY	BU_EMP	TR_RDY		; 14  ; -
19286752Sfjoe	RC_RDY	BU_EMP	TR_RDY	TR_REQ	; 15  ; -
19386752Sfjoe*/
19486752Sfjoe
19586752Sfjoe#define VALID_DECODER	(2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
19686752Sfjoe
19786752Sfjoe
19886752Sfjoeint
19986752Sfjoesbni_probe(struct sbni_softc *sc)
20086752Sfjoe{
20186752Sfjoe	u_char csr0;
20286752Sfjoe
20386752Sfjoe	csr0 = sbni_inb(sc, CSR0);
20486752Sfjoe	if (csr0 != 0xff && csr0 != 0x00) {
20586752Sfjoe		csr0 &= ~EN_INT;
20686752Sfjoe		if (csr0 & BU_EMP)
20786752Sfjoe			csr0 |= EN_INT;
20886752Sfjoe
20986752Sfjoe		if (VALID_DECODER & (1 << (csr0 >> 4)))
21086752Sfjoe			return (0);
21186752Sfjoe	}
21286752Sfjoe
21386752Sfjoe	return (ENXIO);
21486752Sfjoe}
21586752Sfjoe
21686752Sfjoe
21786752Sfjoe/*
21886752Sfjoe * Install interface into kernel networking data structures
21986752Sfjoe */
220180263Sjhbint
22186752Sfjoesbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags)
22286752Sfjoe{
22386752Sfjoe	struct ifnet *ifp;
22486752Sfjoe	u_char csr0;
22586752Sfjoe
226147256Sbrooks	ifp = sc->ifp = if_alloc(IFT_ETHER);
227147256Sbrooks	if (ifp == NULL)
228180263Sjhb		return (ENOMEM);
22986752Sfjoe	sbni_outb(sc, CSR0, 0);
23086752Sfjoe	set_initial_values(sc, flags);
23186752Sfjoe
232121752Sbrooks	/* Initialize ifnet structure */
233121752Sbrooks	ifp->if_softc	= sc;
234121816Sbrooks	if_initname(ifp, "sbni", unit);
235121752Sbrooks	ifp->if_init	= sbni_init;
236121752Sbrooks	ifp->if_start	= sbni_start;
237121752Sbrooks	ifp->if_ioctl	= sbni_ioctl;
238207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
23986752Sfjoe
240121752Sbrooks	/* report real baud rate */
241121752Sbrooks	csr0 = sbni_inb(sc, CSR0);
242121752Sbrooks	ifp->if_baudrate =
243121752Sbrooks		(csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate);
24486752Sfjoe
245180263Sjhb	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
246180263Sjhb
247180263Sjhb	mtx_init(&sc->lock, ifp->if_xname, MTX_NETWORK_LOCK, MTX_DEF);
248180263Sjhb	callout_init_mtx(&sc->wch, &sc->lock, 0);
249147256Sbrooks	ether_ifattach(ifp, sc->enaddr);
25086752Sfjoe	/* device attach does transition from UNCONFIGURED to IDLE state */
25186752Sfjoe
252126966Smdodd	if_printf(ifp, "speed %ld, rxl ", ifp->if_baudrate);
25386752Sfjoe	if (sc->delta_rxl)
25486752Sfjoe		printf("auto\n");
25586752Sfjoe	else
25686752Sfjoe		printf("%d (fixed)\n", sc->cur_rxl_index);
257180263Sjhb	return (0);
25886752Sfjoe}
25986752Sfjoe
260180263Sjhbvoid
261180263Sjhbsbni_detach(struct sbni_softc *sc)
262180263Sjhb{
263180263Sjhb
264180263Sjhb	SBNI_LOCK(sc);
265180263Sjhb	sbni_stop(sc);
266180263Sjhb	SBNI_UNLOCK(sc);
267180263Sjhb	callout_drain(&sc->wch);
268180263Sjhb	ether_ifdetach(sc->ifp);
269180263Sjhb	if (sc->irq_handle)
270180263Sjhb		bus_teardown_intr(sc->dev, sc->irq_res, sc->irq_handle);
271180263Sjhb	mtx_destroy(&sc->lock);
272180263Sjhb	if_free(sc->ifp);
273180263Sjhb}
274180263Sjhb
275180263Sjhbvoid
276180263Sjhbsbni_release_resources(struct sbni_softc *sc)
277180263Sjhb{
278180263Sjhb
279180263Sjhb	if (sc->irq_res)
280180263Sjhb		bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
281180263Sjhb		    sc->irq_res);
282180263Sjhb	if (sc->io_res && sc->io_off == 0)
283180263Sjhb		bus_release_resource(sc->dev, SYS_RES_IOPORT, sc->io_rid,
284180263Sjhb		    sc->io_res);
285180263Sjhb}
286180263Sjhb
28786752Sfjoe/* -------------------------------------------------------------------------- */
28886752Sfjoe
28986752Sfjoestatic void
29086752Sfjoesbni_init(void *xsc)
29186752Sfjoe{
29286752Sfjoe	struct sbni_softc *sc;
293180263Sjhb
294180263Sjhb	sc = (struct sbni_softc *)xsc;
295180263Sjhb	SBNI_LOCK(sc);
296180263Sjhb	sbni_init_locked(sc);
297180263Sjhb	SBNI_UNLOCK(sc);
298180263Sjhb}
299180263Sjhb
300180263Sjhbstatic void
301180263Sjhbsbni_init_locked(struct sbni_softc *sc)
302180263Sjhb{
30386752Sfjoe	struct ifnet *ifp;
30486752Sfjoe
305147256Sbrooks	ifp = sc->ifp;
30686752Sfjoe
30786752Sfjoe	/*
30886752Sfjoe	 * kludge to avoid multiple initialization when more than once
30986752Sfjoe	 * protocols configured
31086752Sfjoe	 */
311148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
31286752Sfjoe		return;
31386752Sfjoe
31486752Sfjoe	card_start(sc);
315180263Sjhb	callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc);
31686752Sfjoe
317148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
318148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
31986752Sfjoe
32086752Sfjoe	/* attempt to start output */
321180263Sjhb	sbni_start_locked(ifp);
32286752Sfjoe}
32386752Sfjoe
32486752Sfjoestatic void
32586752Sfjoesbni_start(struct ifnet *ifp)
32686752Sfjoe{
32786752Sfjoe	struct sbni_softc *sc = ifp->if_softc;
328180263Sjhb
329180263Sjhb	SBNI_LOCK(sc);
330180263Sjhb	sbni_start_locked(ifp);
331180263Sjhb	SBNI_UNLOCK(sc);
332180263Sjhb}
333180263Sjhb
334180263Sjhbstatic void
335180263Sjhbsbni_start_locked(struct ifnet *ifp)
336180263Sjhb{
337180263Sjhb	struct sbni_softc *sc = ifp->if_softc;
338180263Sjhb
33986752Sfjoe	if (sc->tx_frameno == 0)
34086752Sfjoe		prepare_to_send(sc);
34186752Sfjoe}
34286752Sfjoe
34386752Sfjoe
34486752Sfjoestatic void
34586752Sfjoesbni_stop(struct sbni_softc *sc)
34686752Sfjoe{
34786752Sfjoe	sbni_outb(sc, CSR0, 0);
34886752Sfjoe	drop_xmit_queue(sc);
34986752Sfjoe
35086752Sfjoe	if (sc->rx_buf_p) {
35186752Sfjoe		m_freem(sc->rx_buf_p);
35286752Sfjoe		sc->rx_buf_p = NULL;
35386752Sfjoe	}
35486752Sfjoe
355180263Sjhb	callout_stop(&sc->wch);
356180263Sjhb	sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
35786752Sfjoe}
35886752Sfjoe
35986752Sfjoe/* -------------------------------------------------------------------------- */
36086752Sfjoe
36186752Sfjoe/* interrupt handler */
36286752Sfjoe
36386752Sfjoe/*
36486752Sfjoe * 	SBNI12D-10, -11/ISA boards within "common interrupt" mode could not
36586752Sfjoe * be looked as two independent single-channel devices. Every channel seems
36686752Sfjoe * as Ethernet interface but interrupt handler must be common. Really, first
36786752Sfjoe * channel ("master") driver only registers the handler. In it's struct softc
36886752Sfjoe * it has got pointer to "slave" channel's struct softc and handles that's
36986752Sfjoe * interrupts too.
37086752Sfjoe *	softc of successfully attached ISA SBNI boards is linked to list.
37186752Sfjoe * While next board driver is initialized, it scans this list. If one
37286752Sfjoe * has found softc with same irq and ioaddr different by 4 then it assumes
37386752Sfjoe * this board to be "master".
37486752Sfjoe */
37586752Sfjoe
37686752Sfjoevoid
37786752Sfjoesbni_intr(void *arg)
37886752Sfjoe{
37986752Sfjoe	struct sbni_softc *sc;
38086752Sfjoe	int repeat;
38186752Sfjoe
38286752Sfjoe	sc = (struct sbni_softc *)arg;
38386752Sfjoe
38486752Sfjoe	do {
38586752Sfjoe		repeat = 0;
386180263Sjhb		SBNI_LOCK(sc);
38786752Sfjoe		if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) {
38886752Sfjoe			handle_channel(sc);
38986752Sfjoe			repeat = 1;
39086752Sfjoe		}
391180263Sjhb		SBNI_UNLOCK(sc);
392180263Sjhb		if (sc->slave_sc) {
393180263Sjhb			/* second channel present */
394180263Sjhb			SBNI_LOCK(sc->slave_sc);
395180263Sjhb			if (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY)) {
396180263Sjhb				handle_channel(sc->slave_sc);
397180263Sjhb				repeat = 1;
398180263Sjhb			}
399180263Sjhb			SBNI_UNLOCK(sc->slave_sc);
40086752Sfjoe		}
40186752Sfjoe	} while (repeat);
40286752Sfjoe}
40386752Sfjoe
40486752Sfjoe
40586752Sfjoestatic void
40686752Sfjoehandle_channel(struct sbni_softc *sc)
40786752Sfjoe{
40886752Sfjoe	int req_ans;
40986752Sfjoe	u_char csr0;
41086752Sfjoe
41186752Sfjoe	sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ);
41286752Sfjoe
41386752Sfjoe	sc->timer_ticks = CHANGE_LEVEL_START_TICKS;
41486752Sfjoe	for (;;) {
41586752Sfjoe		csr0 = sbni_inb(sc, CSR0);
41686752Sfjoe		if ((csr0 & (RC_RDY | TR_RDY)) == 0)
41786752Sfjoe			break;
41886752Sfjoe
41986752Sfjoe		req_ans = !(sc->state & FL_PREV_OK);
42086752Sfjoe
42186752Sfjoe		if (csr0 & RC_RDY)
42286752Sfjoe			req_ans = recv_frame(sc);
42386752Sfjoe
42486752Sfjoe		/*
42586752Sfjoe		 * TR_RDY always equals 1 here because we have owned the marker,
42686752Sfjoe		 * and we set TR_REQ when disabled interrupts
42786752Sfjoe		 */
42886752Sfjoe		csr0 = sbni_inb(sc, CSR0);
42986752Sfjoe		if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0)
430180263Sjhb			if_printf(sc->ifp, "internal error!\n");
43186752Sfjoe
43286752Sfjoe		/* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */
43386752Sfjoe		if (req_ans || sc->tx_frameno != 0)
43486752Sfjoe			send_frame(sc);
435101393Sfjoe		else {
43686752Sfjoe			/* send the marker without any data */
43786752Sfjoe			sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ);
438101393Sfjoe		}
43986752Sfjoe	}
44086752Sfjoe
44186752Sfjoe	sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT);
44286752Sfjoe}
44386752Sfjoe
44486752Sfjoe
44586752Sfjoe/*
44686752Sfjoe * Routine returns 1 if it need to acknoweledge received frame.
44786752Sfjoe * Empty frame received without errors won't be acknoweledged.
44886752Sfjoe */
44986752Sfjoe
45086752Sfjoestatic int
45186752Sfjoerecv_frame(struct sbni_softc *sc)
45286752Sfjoe{
45386752Sfjoe	u_int32_t crc;
45486752Sfjoe	u_int framelen, frameno, ack;
45586752Sfjoe	u_int is_first, frame_ok;
45686752Sfjoe
45786752Sfjoe	crc = CRC32_INITIAL;
45886752Sfjoe	if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) {
459101393Sfjoe		frame_ok = framelen > 4 ?
460101393Sfjoe		    upload_data(sc, framelen, frameno, is_first, crc) :
461101393Sfjoe		    skip_tail(sc, framelen, crc);
46286752Sfjoe		if (frame_ok)
46386752Sfjoe			interpret_ack(sc, ack);
464171243Speter	} else {
465171243Speter		framelen = 0;
46686752Sfjoe		frame_ok = 0;
467171243Speter	}
46886752Sfjoe
46986752Sfjoe	sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER);
47086752Sfjoe	if (frame_ok) {
47186752Sfjoe		sc->state |= FL_PREV_OK;
47286752Sfjoe		if (framelen > 4)
47386752Sfjoe			sc->in_stats.all_rx_number++;
47486752Sfjoe	} else {
47586752Sfjoe		sc->state &= ~FL_PREV_OK;
47686752Sfjoe		change_level(sc);
47786752Sfjoe		sc->in_stats.all_rx_number++;
47886752Sfjoe		sc->in_stats.bad_rx_number++;
47986752Sfjoe	}
48086752Sfjoe
48186752Sfjoe	return (!frame_ok || framelen > 4);
48286752Sfjoe}
48386752Sfjoe
48486752Sfjoe
48586752Sfjoestatic void
48686752Sfjoesend_frame(struct sbni_softc *sc)
48786752Sfjoe{
48886752Sfjoe	u_int32_t crc;
48986752Sfjoe	u_char csr0;
49086752Sfjoe
49186752Sfjoe	crc = CRC32_INITIAL;
49286752Sfjoe	if (sc->state & FL_NEED_RESEND) {
49386752Sfjoe
49486752Sfjoe		/* if frame was sended but not ACK'ed - resend it */
49586752Sfjoe		if (sc->trans_errors) {
49686752Sfjoe			sc->trans_errors--;
49786752Sfjoe			if (sc->framelen != 0)
49886752Sfjoe				sc->in_stats.resend_tx_number++;
49986752Sfjoe		} else {
50086752Sfjoe			/* cannot xmit with many attempts */
50186752Sfjoe			drop_xmit_queue(sc);
50286752Sfjoe			goto do_send;
50386752Sfjoe		}
50486752Sfjoe	} else
50586752Sfjoe		sc->trans_errors = TR_ERROR_COUNT;
50686752Sfjoe
50786752Sfjoe	send_frame_header(sc, &crc);
50886752Sfjoe	sc->state |= FL_NEED_RESEND;
50986752Sfjoe	/*
51086752Sfjoe	 * FL_NEED_RESEND will be cleared after ACK, but if empty
51186752Sfjoe	 * frame sended then in prepare_to_send next frame
51286752Sfjoe	 */
51386752Sfjoe
51486752Sfjoe
51586752Sfjoe	if (sc->framelen) {
51686752Sfjoe		download_data(sc, &crc);
51786752Sfjoe		sc->in_stats.all_tx_number++;
51886752Sfjoe		sc->state |= FL_WAIT_ACK;
51986752Sfjoe	}
52086752Sfjoe
52186752Sfjoe	sbni_outsb(sc, (u_char *)&crc, sizeof crc);
52286752Sfjoe
52386752Sfjoedo_send:
52486752Sfjoe	csr0 = sbni_inb(sc, CSR0);
52586752Sfjoe	sbni_outb(sc, CSR0, csr0 & ~TR_REQ);
52686752Sfjoe
52786752Sfjoe	if (sc->tx_frameno) {
52886752Sfjoe		/* next frame exists - request to send */
52986752Sfjoe		sbni_outb(sc, CSR0, csr0 | TR_REQ);
53086752Sfjoe	}
53186752Sfjoe}
53286752Sfjoe
53386752Sfjoe
53486752Sfjoestatic void
53586752Sfjoedownload_data(struct sbni_softc *sc, u_int32_t *crc_p)
53686752Sfjoe{
53786752Sfjoe	struct mbuf *m;
53886752Sfjoe	caddr_t	data_p;
53986752Sfjoe	u_int data_len, pos, slice;
54086752Sfjoe
54186752Sfjoe	data_p = NULL;		/* initialized to avoid warn */
54286752Sfjoe	pos = 0;
54386752Sfjoe
54486752Sfjoe	for (m = sc->tx_buf_p;  m != NULL && pos < sc->pktlen;  m = m->m_next) {
54586752Sfjoe		if (pos + m->m_len > sc->outpos) {
54686752Sfjoe			data_len = m->m_len - (sc->outpos - pos);
54786752Sfjoe			data_p = mtod(m, caddr_t) + (sc->outpos - pos);
54886752Sfjoe
54986752Sfjoe			goto do_copy;
55086752Sfjoe		} else
55186752Sfjoe			pos += m->m_len;
55286752Sfjoe	}
55386752Sfjoe
55486752Sfjoe	data_len = 0;
55586752Sfjoe
55686752Sfjoedo_copy:
55786752Sfjoe	pos = 0;
55886752Sfjoe	do {
55986752Sfjoe		if (data_len) {
56086752Sfjoe			slice = min(data_len, sc->framelen - pos);
56186752Sfjoe			sbni_outsb(sc, data_p, slice);
56286752Sfjoe			*crc_p = calc_crc32(*crc_p, data_p, slice);
56386752Sfjoe
56486752Sfjoe			pos += slice;
56586752Sfjoe			if (data_len -= slice)
56686752Sfjoe				data_p += slice;
56786752Sfjoe			else {
568101393Sfjoe				do {
569101393Sfjoe					m = m->m_next;
570101393Sfjoe				} while (m != NULL && m->m_len == 0);
57186752Sfjoe
57286752Sfjoe				if (m) {
57386752Sfjoe					data_len = m->m_len;
57486752Sfjoe					data_p = mtod(m, caddr_t);
57586752Sfjoe				}
57686752Sfjoe			}
57786752Sfjoe		} else {
57886752Sfjoe			/* frame too short - zero padding */
57986752Sfjoe
58086752Sfjoe			pos = sc->framelen - pos;
58186752Sfjoe			while (pos--) {
58286752Sfjoe				sbni_outb(sc, DAT, 0);
58386752Sfjoe				*crc_p = CRC32(0, *crc_p);
58486752Sfjoe			}
58586752Sfjoe			return;
58686752Sfjoe		}
58786752Sfjoe	} while (pos < sc->framelen);
58886752Sfjoe}
58986752Sfjoe
59086752Sfjoe
59186752Sfjoestatic int
59286752Sfjoeupload_data(struct sbni_softc *sc, u_int framelen, u_int frameno,
59386752Sfjoe	    u_int is_first, u_int32_t crc)
59486752Sfjoe{
59586752Sfjoe	int frame_ok;
59686752Sfjoe
59786752Sfjoe	if (is_first) {
59886752Sfjoe		sc->wait_frameno = frameno;
59986752Sfjoe		sc->inppos = 0;
60086752Sfjoe	}
60186752Sfjoe
60286752Sfjoe	if (sc->wait_frameno == frameno) {
60386752Sfjoe
60486752Sfjoe		if (sc->inppos + framelen  <=  ETHER_MAX_LEN) {
60586752Sfjoe			frame_ok = append_frame_to_pkt(sc, framelen, crc);
60686752Sfjoe
60786752Sfjoe		/*
60886752Sfjoe		 * if CRC is right but framelen incorrect then transmitter
60986752Sfjoe		 * error was occured... drop entire packet
61086752Sfjoe		 */
61186752Sfjoe		} else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) {
61286752Sfjoe			sc->wait_frameno = 0;
61386752Sfjoe			sc->inppos = 0;
614147256Sbrooks			sc->ifp->if_ierrors++;
61586752Sfjoe			/* now skip all frames until is_first != 0 */
61686752Sfjoe		}
61786752Sfjoe	} else
61886752Sfjoe		frame_ok = skip_tail(sc, framelen, crc);
61986752Sfjoe
62086752Sfjoe	if (is_first && !frame_ok) {
62186752Sfjoe		/*
62286752Sfjoe		 * Frame has been violated, but we have stored
62386752Sfjoe		 * is_first already... Drop entire packet.
62486752Sfjoe		 */
62586752Sfjoe		sc->wait_frameno = 0;
626147256Sbrooks		sc->ifp->if_ierrors++;
62786752Sfjoe	}
62886752Sfjoe
62986752Sfjoe	return (frame_ok);
63086752Sfjoe}
63186752Sfjoe
63286752Sfjoe
63386752Sfjoestatic __inline void	send_complete(struct sbni_softc *);
63486752Sfjoe
63586752Sfjoestatic __inline void
63686752Sfjoesend_complete(struct sbni_softc *sc)
63786752Sfjoe{
63886752Sfjoe	m_freem(sc->tx_buf_p);
63986752Sfjoe	sc->tx_buf_p = NULL;
640147256Sbrooks	sc->ifp->if_opackets++;
64186752Sfjoe}
64286752Sfjoe
64386752Sfjoe
64486752Sfjoestatic void
64586752Sfjoeinterpret_ack(struct sbni_softc *sc, u_int ack)
64686752Sfjoe{
64786752Sfjoe	if (ack == FRAME_SENT_OK) {
64886752Sfjoe		sc->state &= ~FL_NEED_RESEND;
64986752Sfjoe
65086752Sfjoe		if (sc->state & FL_WAIT_ACK) {
65186752Sfjoe			sc->outpos += sc->framelen;
65286752Sfjoe
653101393Sfjoe			if (--sc->tx_frameno) {
654101393Sfjoe				sc->framelen = min(
655101393Sfjoe				    sc->maxframe, sc->pktlen - sc->outpos);
656101393Sfjoe			} else {
65786752Sfjoe				send_complete(sc);
65886752Sfjoe				prepare_to_send(sc);
65986752Sfjoe			}
66086752Sfjoe		}
66186752Sfjoe	}
66286752Sfjoe
66386752Sfjoe	sc->state &= ~FL_WAIT_ACK;
66486752Sfjoe}
66586752Sfjoe
66686752Sfjoe
66786752Sfjoe/*
66886752Sfjoe * Glue received frame with previous fragments of packet.
66986752Sfjoe * Indicate packet when last frame would be accepted.
67086752Sfjoe */
67186752Sfjoe
67286752Sfjoestatic int
67386752Sfjoeappend_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc)
67486752Sfjoe{
67586752Sfjoe	caddr_t p;
67686752Sfjoe
67786752Sfjoe	if (sc->inppos + framelen > ETHER_MAX_LEN)
67886752Sfjoe		return (0);
67986752Sfjoe
68086752Sfjoe	if (!sc->rx_buf_p && !get_rx_buf(sc))
68186752Sfjoe		return (0);
68286752Sfjoe
68386752Sfjoe	p = sc->rx_buf_p->m_data + sc->inppos;
68486752Sfjoe	sbni_insb(sc, p, framelen);
68586752Sfjoe	if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER)
68686752Sfjoe		return (0);
68786752Sfjoe
68886752Sfjoe	sc->inppos += framelen - 4;
68986752Sfjoe	if (--sc->wait_frameno == 0) {		/* last frame received */
69086752Sfjoe		indicate_pkt(sc);
691147256Sbrooks		sc->ifp->if_ipackets++;
69286752Sfjoe	}
69386752Sfjoe
69486752Sfjoe	return (1);
69586752Sfjoe}
69686752Sfjoe
69786752Sfjoe
69886752Sfjoe/*
69986752Sfjoe * Prepare to start output on adapter. Current priority must be set to splimp
70086752Sfjoe * before this routine is called.
70186752Sfjoe * Transmitter will be actually activated when marker has been accepted.
70286752Sfjoe */
70386752Sfjoe
70486752Sfjoestatic void
70586752Sfjoeprepare_to_send(struct sbni_softc *sc)
70686752Sfjoe{
70786752Sfjoe	struct mbuf *m;
70886752Sfjoe	u_int len;
70986752Sfjoe
71086752Sfjoe	/* sc->tx_buf_p == NULL here! */
71186752Sfjoe	if (sc->tx_buf_p)
71286752Sfjoe		printf("sbni: memory leak!\n");
71386752Sfjoe
71486752Sfjoe	sc->outpos = 0;
71586752Sfjoe	sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
71686752Sfjoe
71786752Sfjoe	for (;;) {
718147256Sbrooks		IF_DEQUEUE(&sc->ifp->if_snd, sc->tx_buf_p);
71986752Sfjoe		if (!sc->tx_buf_p) {
72086752Sfjoe			/* nothing to transmit... */
72186752Sfjoe			sc->pktlen     = 0;
72286752Sfjoe			sc->tx_frameno = 0;
72386752Sfjoe			sc->framelen   = 0;
724148887Srwatson			sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
72586752Sfjoe			return;
72686752Sfjoe		}
72786752Sfjoe
72886752Sfjoe		for (len = 0, m = sc->tx_buf_p;  m;  m = m->m_next)
72986752Sfjoe			len += m->m_len;
73086752Sfjoe
73186752Sfjoe		if (len != 0)
73286752Sfjoe			break;
73386752Sfjoe		m_freem(sc->tx_buf_p);
73486752Sfjoe	}
73586752Sfjoe
73686752Sfjoe	if (len < SBNI_MIN_LEN)
73786752Sfjoe		len = SBNI_MIN_LEN;
73886752Sfjoe
73986752Sfjoe	sc->pktlen	= len;
74086752Sfjoe	sc->tx_frameno	= (len + sc->maxframe - 1) / sc->maxframe;
74186752Sfjoe	sc->framelen	= min(len, sc->maxframe);
74286752Sfjoe
74386752Sfjoe	sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ);
744148887Srwatson	sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
745147256Sbrooks	BPF_MTAP(sc->ifp, sc->tx_buf_p);
74686752Sfjoe}
74786752Sfjoe
74886752Sfjoe
74986752Sfjoestatic void
75086752Sfjoedrop_xmit_queue(struct sbni_softc *sc)
75186752Sfjoe{
75286752Sfjoe	struct mbuf *m;
75386752Sfjoe
75486752Sfjoe	if (sc->tx_buf_p) {
75586752Sfjoe		m_freem(sc->tx_buf_p);
75686752Sfjoe		sc->tx_buf_p = NULL;
757147256Sbrooks		sc->ifp->if_oerrors++;
75886752Sfjoe	}
75986752Sfjoe
76086752Sfjoe	for (;;) {
761147256Sbrooks		IF_DEQUEUE(&sc->ifp->if_snd, m);
76286752Sfjoe		if (m == NULL)
76386752Sfjoe			break;
76486752Sfjoe		m_freem(m);
765147256Sbrooks		sc->ifp->if_oerrors++;
76686752Sfjoe	}
76786752Sfjoe
76886752Sfjoe	sc->tx_frameno	= 0;
76986752Sfjoe	sc->framelen	= 0;
77086752Sfjoe	sc->outpos	= 0;
77186752Sfjoe	sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
772148887Srwatson	sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
77386752Sfjoe}
77486752Sfjoe
77586752Sfjoe
77686752Sfjoestatic void
77786752Sfjoesend_frame_header(struct sbni_softc *sc, u_int32_t *crc_p)
77886752Sfjoe{
77986752Sfjoe	u_int32_t crc;
78086752Sfjoe	u_int len_field;
78186752Sfjoe	u_char value;
78286752Sfjoe
78386752Sfjoe	crc = *crc_p;
78486752Sfjoe	len_field = sc->framelen + 6;	/* CRC + frameno + reserved */
78586752Sfjoe
78686752Sfjoe	if (sc->state & FL_NEED_RESEND)
78786752Sfjoe		len_field |= FRAME_RETRY;	/* non-first attempt... */
78886752Sfjoe
78986752Sfjoe	if (sc->outpos == 0)
79086752Sfjoe		len_field |= FRAME_FIRST;
79186752Sfjoe
79286752Sfjoe	len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD;
79386752Sfjoe	sbni_outb(sc, DAT, SBNI_SIG);
79486752Sfjoe
79586752Sfjoe	value = (u_char)len_field;
79686752Sfjoe	sbni_outb(sc, DAT, value);
79786752Sfjoe	crc = CRC32(value, crc);
79886752Sfjoe	value = (u_char)(len_field >> 8);
79986752Sfjoe	sbni_outb(sc, DAT, value);
80086752Sfjoe	crc = CRC32(value, crc);
80186752Sfjoe
80286752Sfjoe	sbni_outb(sc, DAT, sc->tx_frameno);
80386752Sfjoe	crc = CRC32(sc->tx_frameno, crc);
80486752Sfjoe	sbni_outb(sc, DAT, 0);
80586752Sfjoe	crc = CRC32(0, crc);
80686752Sfjoe	*crc_p = crc;
80786752Sfjoe}
80886752Sfjoe
80986752Sfjoe
81086752Sfjoe/*
81186752Sfjoe * if frame tail not needed (incorrect number or received twice),
81286752Sfjoe * it won't store, but CRC will be calculated
81386752Sfjoe */
81486752Sfjoe
81586752Sfjoestatic int
81686752Sfjoeskip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc)
81786752Sfjoe{
81886752Sfjoe	while (tail_len--)
81986752Sfjoe		crc = CRC32(sbni_inb(sc, DAT), crc);
82086752Sfjoe
82186752Sfjoe	return (crc == CRC32_REMAINDER);
82286752Sfjoe}
82386752Sfjoe
82486752Sfjoe
82586752Sfjoestatic int
82686752Sfjoecheck_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno,
82786752Sfjoe	   u_int *ack, u_int *is_first, u_int32_t *crc_p)
82886752Sfjoe{
82986752Sfjoe	u_int32_t crc;
83086752Sfjoe	u_char value;
83186752Sfjoe
83286752Sfjoe	crc = *crc_p;
83386752Sfjoe	if (sbni_inb(sc, DAT) != SBNI_SIG)
83486752Sfjoe		return (0);
83586752Sfjoe
83686752Sfjoe	value = sbni_inb(sc, DAT);
83786752Sfjoe	*framelen = (u_int)value;
83886752Sfjoe	crc = CRC32(value, crc);
83986752Sfjoe	value = sbni_inb(sc, DAT);
84086752Sfjoe	*framelen |= ((u_int)value) << 8;
84186752Sfjoe	crc = CRC32(value, crc);
84286752Sfjoe
84386752Sfjoe	*ack = *framelen & FRAME_ACK_MASK;
84486752Sfjoe	*is_first = (*framelen & FRAME_FIRST) != 0;
84586752Sfjoe
84686752Sfjoe	if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3)
84786752Sfjoe		return (0);
84886752Sfjoe
84986752Sfjoe	value = sbni_inb(sc, DAT);
85086752Sfjoe	*frameno = (u_int)value;
85186752Sfjoe	crc = CRC32(value, crc);
85286752Sfjoe
85386752Sfjoe	crc = CRC32(sbni_inb(sc, DAT), crc);		/* reserved byte */
85486752Sfjoe	*framelen -= 2;
85586752Sfjoe
85686752Sfjoe	*crc_p = crc;
85786752Sfjoe	return (1);
85886752Sfjoe}
85986752Sfjoe
86086752Sfjoe
86186752Sfjoestatic int
86286752Sfjoeget_rx_buf(struct sbni_softc *sc)
86386752Sfjoe{
86486752Sfjoe	struct mbuf *m;
86586752Sfjoe
866243857Sglebius	MGETHDR(m, M_NOWAIT, MT_DATA);
86786752Sfjoe	if (m == NULL) {
868147256Sbrooks		if_printf(sc->ifp, "cannot allocate header mbuf\n");
86986752Sfjoe		return (0);
87086752Sfjoe	}
87186752Sfjoe
87286752Sfjoe	/*
87386752Sfjoe	 * We always put the received packet in a single buffer -
87486752Sfjoe	 * either with just an mbuf header or in a cluster attached
87586752Sfjoe	 * to the header. The +2 is to compensate for the alignment
87686752Sfjoe	 * fixup below.
87786752Sfjoe	 */
87886752Sfjoe	if (ETHER_MAX_LEN + 2 > MHLEN) {
87986752Sfjoe		/* Attach an mbuf cluster */
880243857Sglebius		MCLGET(m, M_NOWAIT);
88186752Sfjoe		if ((m->m_flags & M_EXT) == 0) {
88286752Sfjoe			m_freem(m);
88386752Sfjoe			return (0);
88486752Sfjoe		}
88586752Sfjoe	}
88686752Sfjoe	m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2;
88786752Sfjoe
88886752Sfjoe	/*
88986752Sfjoe	 * The +2 is to longword align the start of the real packet.
89086752Sfjoe	 * (sizeof ether_header == 14)
89186752Sfjoe	 * This is important for NFS.
89286752Sfjoe	 */
89386752Sfjoe	m_adj(m, 2);
89486752Sfjoe	sc->rx_buf_p = m;
89586752Sfjoe	return (1);
89686752Sfjoe}
89786752Sfjoe
89886752Sfjoe
89986752Sfjoestatic void
90086752Sfjoeindicate_pkt(struct sbni_softc *sc)
90186752Sfjoe{
902147256Sbrooks	struct ifnet *ifp = sc->ifp;
90386752Sfjoe	struct mbuf *m;
90486752Sfjoe
90586752Sfjoe	m = sc->rx_buf_p;
906106937Ssam	m->m_pkthdr.rcvif = ifp;
90786752Sfjoe	m->m_pkthdr.len   = m->m_len = sc->inppos;
908180263Sjhb	sc->rx_buf_p = NULL;
90986752Sfjoe
910180263Sjhb	SBNI_UNLOCK(sc);
911106937Ssam	(*ifp->if_input)(ifp, m);
912180263Sjhb	SBNI_LOCK(sc);
91386752Sfjoe}
91486752Sfjoe
91586752Sfjoe/* -------------------------------------------------------------------------- */
91686752Sfjoe
91786752Sfjoe/*
91886752Sfjoe * Routine checks periodically wire activity and regenerates marker if
91986752Sfjoe * connect was inactive for a long time.
92086752Sfjoe */
92186752Sfjoe
92286752Sfjoestatic void
92386752Sfjoesbni_timeout(void *xsc)
92486752Sfjoe{
92586752Sfjoe	struct sbni_softc *sc;
92686752Sfjoe	u_char csr0;
92786752Sfjoe
92886752Sfjoe	sc = (struct sbni_softc *)xsc;
929180263Sjhb	SBNI_ASSERT_LOCKED(sc);
93086752Sfjoe
93186752Sfjoe	csr0 = sbni_inb(sc, CSR0);
93286752Sfjoe	if (csr0 & RC_CHK) {
93386752Sfjoe
93486752Sfjoe		if (sc->timer_ticks) {
93586752Sfjoe			if (csr0 & (RC_RDY | BU_EMP))
93686752Sfjoe				/* receiving not active */
93786752Sfjoe				sc->timer_ticks--;
93886752Sfjoe		} else {
93986752Sfjoe			sc->in_stats.timeout_number++;
94086752Sfjoe			if (sc->delta_rxl)
94186752Sfjoe				timeout_change_level(sc);
94286752Sfjoe
94386752Sfjoe			sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES);
94486752Sfjoe			csr0 = sbni_inb(sc, CSR0);
94586752Sfjoe		}
94686752Sfjoe	}
94786752Sfjoe
948180263Sjhb	sbni_outb(sc, CSR0, csr0 | RC_CHK);
949180263Sjhb	callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc);
95086752Sfjoe}
95186752Sfjoe
95286752Sfjoe/* -------------------------------------------------------------------------- */
95386752Sfjoe
95486752Sfjoestatic void
95586752Sfjoecard_start(struct sbni_softc *sc)
95686752Sfjoe{
95786752Sfjoe	sc->timer_ticks = CHANGE_LEVEL_START_TICKS;
95886752Sfjoe	sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
95986752Sfjoe	sc->state |= FL_PREV_OK;
96086752Sfjoe
96186752Sfjoe	sc->inppos = 0;
96286752Sfjoe	sc->wait_frameno = 0;
96386752Sfjoe
96486752Sfjoe	sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES);
96586752Sfjoe	sbni_outb(sc, CSR0, EN_INT);
96686752Sfjoe}
96786752Sfjoe
96886752Sfjoe/* -------------------------------------------------------------------------- */
96986752Sfjoe
97086752Sfjoestatic u_char rxl_tab[] = {
97186752Sfjoe	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
97286752Sfjoe	0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
97386752Sfjoe};
97486752Sfjoe
97586752Sfjoe#define SIZE_OF_TIMEOUT_RXL_TAB 4
97686752Sfjoestatic u_char timeout_rxl_tab[] = {
97786752Sfjoe	0x03, 0x05, 0x08, 0x0b
97886752Sfjoe};
97986752Sfjoe
98086752Sfjoestatic void
98186752Sfjoeset_initial_values(struct sbni_softc *sc, struct sbni_flags flags)
98286752Sfjoe{
98386752Sfjoe	if (flags.fixed_rxl) {
98486752Sfjoe		sc->delta_rxl = 0; /* disable receive level autodetection */
98586752Sfjoe		sc->cur_rxl_index = flags.rxl;
98686752Sfjoe	} else {
98786752Sfjoe		sc->delta_rxl = DEF_RXL_DELTA;
98886752Sfjoe		sc->cur_rxl_index = DEF_RXL;
98986752Sfjoe	}
99086752Sfjoe
99186752Sfjoe	sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE;
99286752Sfjoe	sc->csr1.rxl  = rxl_tab[sc->cur_rxl_index];
99386752Sfjoe	sc->maxframe  = DEFAULT_FRAME_LEN;
99486752Sfjoe
99586752Sfjoe	/*
99686752Sfjoe	 * generate Ethernet address (0x00ff01xxxxxx)
99786752Sfjoe	 */
998147256Sbrooks	*(u_int16_t *) sc->enaddr = htons(0x00ff);
999101400Sfjoe	if (flags.mac_addr) {
1000147256Sbrooks		*(u_int32_t *) (sc->enaddr + 2) =
1001101400Sfjoe		    htonl(flags.mac_addr | 0x01000000);
1002101400Sfjoe	} else {
1003147256Sbrooks		*(u_char *) (sc->enaddr + 2) = 0x01;
1004147256Sbrooks		read_random(sc->enaddr + 3, 3);
100586752Sfjoe	}
100686752Sfjoe}
100786752Sfjoe
100886752Sfjoe
100986752Sfjoe#ifdef SBNI_DUAL_COMPOUND
1010180263Sjhbvoid
1011180263Sjhbsbni_add(struct sbni_softc *sc)
1012180263Sjhb{
101386752Sfjoe
1014180263Sjhb	mtx_lock(&headlist_lock);
1015180263Sjhb	sc->link = sbni_headlist;
1016180263Sjhb	sbni_headlist = sc;
1017180263Sjhb	mtx_unlock(&headlist_lock);
1018180263Sjhb}
1019180263Sjhb
102086752Sfjoestruct sbni_softc *
102186752Sfjoeconnect_to_master(struct sbni_softc *sc)
102286752Sfjoe{
1023101400Sfjoe	struct sbni_softc *p, *p_prev;
102486752Sfjoe
1025180263Sjhb	mtx_lock(&headlist_lock);
1026101400Sfjoe	for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) {
1027101400Sfjoe		if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 ||
1028101400Sfjoe		    rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) {
1029101400Sfjoe			p->slave_sc = sc;
1030101400Sfjoe			if (p_prev)
1031101400Sfjoe				p_prev->link = p->link;
1032101400Sfjoe			else
1033101400Sfjoe				sbni_headlist = p->link;
1034180263Sjhb			mtx_unlock(&headlist_lock);
1035101400Sfjoe			return p;
103686752Sfjoe		}
103786752Sfjoe	}
1038180263Sjhb	mtx_unlock(&headlist_lock);
103986752Sfjoe
104086752Sfjoe	return (NULL);
104186752Sfjoe}
104286752Sfjoe
104386752Sfjoe#endif	/* SBNI_DUAL_COMPOUND */
104486752Sfjoe
104586752Sfjoe
104686752Sfjoe/* Receive level auto-selection */
104786752Sfjoe
104886752Sfjoestatic void
104986752Sfjoechange_level(struct sbni_softc *sc)
105086752Sfjoe{
105186752Sfjoe	if (sc->delta_rxl == 0)		/* do not auto-negotiate RxL */
105286752Sfjoe		return;
105386752Sfjoe
105486752Sfjoe	if (sc->cur_rxl_index == 0)
105586752Sfjoe		sc->delta_rxl = 1;
105686752Sfjoe	else if (sc->cur_rxl_index == 15)
105786752Sfjoe		sc->delta_rxl = -1;
105886752Sfjoe	else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd)
105986752Sfjoe		sc->delta_rxl = -sc->delta_rxl;
106086752Sfjoe
106186752Sfjoe	sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl];
106286752Sfjoe	sbni_inb(sc, CSR0);	/* it needed for PCI cards */
106386752Sfjoe	sbni_outb(sc, CSR1, *(u_char *)&sc->csr1);
106486752Sfjoe
106586752Sfjoe	sc->prev_rxl_rcvd = sc->cur_rxl_rcvd;
106686752Sfjoe	sc->cur_rxl_rcvd  = 0;
106786752Sfjoe}
106886752Sfjoe
106986752Sfjoe
107086752Sfjoestatic void
107186752Sfjoetimeout_change_level(struct sbni_softc *sc)
107286752Sfjoe{
107386752Sfjoe	sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl];
107486752Sfjoe	if (++sc->timeout_rxl >= 4)
107586752Sfjoe		sc->timeout_rxl = 0;
107686752Sfjoe
107786752Sfjoe	sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
107886752Sfjoe	sbni_inb(sc, CSR0);
107986752Sfjoe	sbni_outb(sc, CSR1, *(u_char *)&sc->csr1);
108086752Sfjoe
108186752Sfjoe	sc->prev_rxl_rcvd = sc->cur_rxl_rcvd;
108286752Sfjoe	sc->cur_rxl_rcvd  = 0;
108386752Sfjoe}
108486752Sfjoe
108586752Sfjoe/* -------------------------------------------------------------------------- */
108686752Sfjoe
108786752Sfjoe/*
108886752Sfjoe * Process an ioctl request. This code needs some work - it looks
108986752Sfjoe *	pretty ugly.
109086752Sfjoe */
109186752Sfjoe
109286752Sfjoestatic int
109386752Sfjoesbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
109486752Sfjoe{
109586752Sfjoe	struct sbni_softc *sc;
109686752Sfjoe	struct ifreq *ifr;
109793593Sjhb	struct thread *td;
109886752Sfjoe	struct sbni_in_stats *in_stats;
109986752Sfjoe	struct sbni_flags flags;
1100180263Sjhb	int error;
110186752Sfjoe
110286752Sfjoe	sc = ifp->if_softc;
110386752Sfjoe	ifr = (struct ifreq *)data;
110493593Sjhb	td = curthread;
110586752Sfjoe	error = 0;
110686752Sfjoe
110786752Sfjoe	switch (command) {
110886752Sfjoe	case SIOCSIFFLAGS:
110986752Sfjoe		/*
111086752Sfjoe		 * If the interface is marked up and stopped, then start it.
111186752Sfjoe		 * If it is marked down and running, then stop it.
111286752Sfjoe		 */
1113180263Sjhb		SBNI_LOCK(sc);
111486752Sfjoe		if (ifp->if_flags & IFF_UP) {
1115148887Srwatson			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
1116180263Sjhb				sbni_init_locked(sc);
111786752Sfjoe		} else {
1118148887Srwatson			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
111986752Sfjoe				sbni_stop(sc);
112086752Sfjoe			}
112186752Sfjoe		}
1122180263Sjhb		SBNI_UNLOCK(sc);
112386752Sfjoe		break;
112486752Sfjoe
112586752Sfjoe	case SIOCADDMULTI:
112686752Sfjoe	case SIOCDELMULTI:
112786752Sfjoe		/*
112886752Sfjoe		 * Multicast list has changed; set the hardware filter
112986752Sfjoe		 * accordingly.
113086752Sfjoe		 */
113186752Sfjoe		error = 0;
113286752Sfjoe		/* if (ifr == NULL)
113386752Sfjoe			error = EAFNOSUPPORT; */
113486752Sfjoe		break;
113586752Sfjoe
113686752Sfjoe		/*
113786752Sfjoe		 * SBNI specific ioctl
113886752Sfjoe		 */
113986752Sfjoe	case SIOCGHWFLAGS:	/* get flags */
1140180263Sjhb		SBNI_LOCK(sc);
1141152315Sru		bcopy((caddr_t)IF_LLADDR(sc->ifp)+3, (caddr_t) &flags, 3);
114286752Sfjoe		flags.rxl = sc->cur_rxl_index;
114386752Sfjoe		flags.rate = sc->csr1.rate;
114486752Sfjoe		flags.fixed_rxl = (sc->delta_rxl == 0);
114586752Sfjoe		flags.fixed_rate = 1;
1146180263Sjhb		SBNI_UNLOCK(sc);
114786752Sfjoe		ifr->ifr_data = *(caddr_t*) &flags;
114886752Sfjoe		break;
114986752Sfjoe
115086752Sfjoe	case SIOCGINSTATS:
1151180263Sjhb		in_stats = malloc(sizeof(struct sbni_in_stats), M_DEVBUF,
1152180263Sjhb		    M_WAITOK);
1153180263Sjhb		SBNI_LOCK(sc);
1154180263Sjhb		bcopy(&sc->in_stats, in_stats, sizeof(struct sbni_in_stats));
1155180263Sjhb		SBNI_UNLOCK(sc);
1156180263Sjhb		error = copyout(ifr->ifr_data, in_stats,
1157180263Sjhb		    sizeof(struct sbni_in_stats));
1158180263Sjhb		free(in_stats, M_DEVBUF);
115986752Sfjoe		break;
116086752Sfjoe
116186752Sfjoe	case SIOCSHWFLAGS:	/* set flags */
116286752Sfjoe		/* root only */
1163164033Srwatson		error = priv_check(td, PRIV_DRIVER);
116486752Sfjoe		if (error)
116586752Sfjoe			break;
116686752Sfjoe		flags = *(struct sbni_flags*)&ifr->ifr_data;
1167180263Sjhb		SBNI_LOCK(sc);
116886752Sfjoe		if (flags.fixed_rxl) {
116986752Sfjoe			sc->delta_rxl = 0;
117086752Sfjoe			sc->cur_rxl_index = flags.rxl;
117186752Sfjoe		} else {
117286752Sfjoe			sc->delta_rxl = DEF_RXL_DELTA;
117386752Sfjoe			sc->cur_rxl_index = DEF_RXL;
117486752Sfjoe		}
117586752Sfjoe		sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
117686752Sfjoe		sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE;
117786752Sfjoe		if (flags.mac_addr)
117886752Sfjoe			bcopy((caddr_t) &flags,
1179152315Sru			      (caddr_t) IF_LLADDR(sc->ifp)+3, 3);
118086752Sfjoe
118186752Sfjoe		/* Don't be afraid... */
118286752Sfjoe		sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES);
1183180263Sjhb		SBNI_UNLOCK(sc);
118486752Sfjoe		break;
118586752Sfjoe
118686752Sfjoe	case SIOCRINSTATS:
1187180263Sjhb		SBNI_LOCK(sc);
1188164033Srwatson		if (!(error = priv_check(td, PRIV_DRIVER)))	/* root only */
118986752Sfjoe			bzero(&sc->in_stats, sizeof(struct sbni_in_stats));
1190180263Sjhb		SBNI_UNLOCK(sc);
119186752Sfjoe		break;
119286752Sfjoe
119386752Sfjoe	default:
1194106937Ssam		error = ether_ioctl(ifp, command, data);
1195106937Ssam		break;
119686752Sfjoe	}
119786752Sfjoe
119886752Sfjoe	return (error);
119986752Sfjoe}
120086752Sfjoe
120186752Sfjoe/* -------------------------------------------------------------------------- */
120286752Sfjoe
120386752Sfjoestatic u_int32_t
120486752Sfjoecalc_crc32(u_int32_t crc, caddr_t p, u_int len)
120586752Sfjoe{
120686752Sfjoe	while (len--)
120786752Sfjoe		crc = CRC32(*p++, crc);
120886752Sfjoe
120986752Sfjoe	return (crc);
121086752Sfjoe}
121186752Sfjoe
1212103844Salfredstatic u_int32_t crc32tab[] __aligned(8) = {
121386752Sfjoe	0xD202EF8D,  0xA505DF1B,  0x3C0C8EA1,  0x4B0BBE37,
121486752Sfjoe	0xD56F2B94,  0xA2681B02,  0x3B614AB8,  0x4C667A2E,
121586752Sfjoe	0xDCD967BF,  0xABDE5729,  0x32D70693,  0x45D03605,
121686752Sfjoe	0xDBB4A3A6,  0xACB39330,  0x35BAC28A,  0x42BDF21C,
121786752Sfjoe	0xCFB5FFE9,  0xB8B2CF7F,  0x21BB9EC5,  0x56BCAE53,
121886752Sfjoe	0xC8D83BF0,  0xBFDF0B66,  0x26D65ADC,  0x51D16A4A,
121986752Sfjoe	0xC16E77DB,  0xB669474D,  0x2F6016F7,  0x58672661,
122086752Sfjoe	0xC603B3C2,  0xB1048354,  0x280DD2EE,  0x5F0AE278,
122186752Sfjoe	0xE96CCF45,  0x9E6BFFD3,  0x0762AE69,  0x70659EFF,
122286752Sfjoe	0xEE010B5C,  0x99063BCA,  0x000F6A70,  0x77085AE6,
122386752Sfjoe	0xE7B74777,  0x90B077E1,  0x09B9265B,  0x7EBE16CD,
122486752Sfjoe	0xE0DA836E,  0x97DDB3F8,  0x0ED4E242,  0x79D3D2D4,
122586752Sfjoe	0xF4DBDF21,  0x83DCEFB7,  0x1AD5BE0D,  0x6DD28E9B,
122686752Sfjoe	0xF3B61B38,  0x84B12BAE,  0x1DB87A14,  0x6ABF4A82,
122786752Sfjoe	0xFA005713,  0x8D076785,  0x140E363F,  0x630906A9,
122886752Sfjoe	0xFD6D930A,  0x8A6AA39C,  0x1363F226,  0x6464C2B0,
122986752Sfjoe	0xA4DEAE1D,  0xD3D99E8B,  0x4AD0CF31,  0x3DD7FFA7,
123086752Sfjoe	0xA3B36A04,  0xD4B45A92,  0x4DBD0B28,  0x3ABA3BBE,
123186752Sfjoe	0xAA05262F,  0xDD0216B9,  0x440B4703,  0x330C7795,
123286752Sfjoe	0xAD68E236,  0xDA6FD2A0,  0x4366831A,  0x3461B38C,
123386752Sfjoe	0xB969BE79,  0xCE6E8EEF,  0x5767DF55,  0x2060EFC3,
123486752Sfjoe	0xBE047A60,  0xC9034AF6,  0x500A1B4C,  0x270D2BDA,
123586752Sfjoe	0xB7B2364B,  0xC0B506DD,  0x59BC5767,  0x2EBB67F1,
123686752Sfjoe	0xB0DFF252,  0xC7D8C2C4,  0x5ED1937E,  0x29D6A3E8,
123786752Sfjoe	0x9FB08ED5,  0xE8B7BE43,  0x71BEEFF9,  0x06B9DF6F,
123886752Sfjoe	0x98DD4ACC,  0xEFDA7A5A,  0x76D32BE0,  0x01D41B76,
123986752Sfjoe	0x916B06E7,  0xE66C3671,  0x7F6567CB,  0x0862575D,
124086752Sfjoe	0x9606C2FE,  0xE101F268,  0x7808A3D2,  0x0F0F9344,
124186752Sfjoe	0x82079EB1,  0xF500AE27,  0x6C09FF9D,  0x1B0ECF0B,
124286752Sfjoe	0x856A5AA8,  0xF26D6A3E,  0x6B643B84,  0x1C630B12,
124386752Sfjoe	0x8CDC1683,  0xFBDB2615,  0x62D277AF,  0x15D54739,
124486752Sfjoe	0x8BB1D29A,  0xFCB6E20C,  0x65BFB3B6,  0x12B88320,
124586752Sfjoe	0x3FBA6CAD,  0x48BD5C3B,  0xD1B40D81,  0xA6B33D17,
124686752Sfjoe	0x38D7A8B4,  0x4FD09822,  0xD6D9C998,  0xA1DEF90E,
124786752Sfjoe	0x3161E49F,  0x4666D409,  0xDF6F85B3,  0xA868B525,
124886752Sfjoe	0x360C2086,  0x410B1010,  0xD80241AA,  0xAF05713C,
124986752Sfjoe	0x220D7CC9,  0x550A4C5F,  0xCC031DE5,  0xBB042D73,
125086752Sfjoe	0x2560B8D0,  0x52678846,  0xCB6ED9FC,  0xBC69E96A,
125186752Sfjoe	0x2CD6F4FB,  0x5BD1C46D,  0xC2D895D7,  0xB5DFA541,
125286752Sfjoe	0x2BBB30E2,  0x5CBC0074,  0xC5B551CE,  0xB2B26158,
125386752Sfjoe	0x04D44C65,  0x73D37CF3,  0xEADA2D49,  0x9DDD1DDF,
125486752Sfjoe	0x03B9887C,  0x74BEB8EA,  0xEDB7E950,  0x9AB0D9C6,
125586752Sfjoe	0x0A0FC457,  0x7D08F4C1,  0xE401A57B,  0x930695ED,
125686752Sfjoe	0x0D62004E,  0x7A6530D8,  0xE36C6162,  0x946B51F4,
125786752Sfjoe	0x19635C01,  0x6E646C97,  0xF76D3D2D,  0x806A0DBB,
125886752Sfjoe	0x1E0E9818,  0x6909A88E,  0xF000F934,  0x8707C9A2,
125986752Sfjoe	0x17B8D433,  0x60BFE4A5,  0xF9B6B51F,  0x8EB18589,
126086752Sfjoe	0x10D5102A,  0x67D220BC,  0xFEDB7106,  0x89DC4190,
126186752Sfjoe	0x49662D3D,  0x3E611DAB,  0xA7684C11,  0xD06F7C87,
126286752Sfjoe	0x4E0BE924,  0x390CD9B2,  0xA0058808,  0xD702B89E,
126386752Sfjoe	0x47BDA50F,  0x30BA9599,  0xA9B3C423,  0xDEB4F4B5,
126486752Sfjoe	0x40D06116,  0x37D75180,  0xAEDE003A,  0xD9D930AC,
126586752Sfjoe	0x54D13D59,  0x23D60DCF,  0xBADF5C75,  0xCDD86CE3,
126686752Sfjoe	0x53BCF940,  0x24BBC9D6,  0xBDB2986C,  0xCAB5A8FA,
126786752Sfjoe	0x5A0AB56B,  0x2D0D85FD,  0xB404D447,  0xC303E4D1,
126886752Sfjoe	0x5D677172,  0x2A6041E4,  0xB369105E,  0xC46E20C8,
126986752Sfjoe	0x72080DF5,  0x050F3D63,  0x9C066CD9,  0xEB015C4F,
127086752Sfjoe	0x7565C9EC,  0x0262F97A,  0x9B6BA8C0,  0xEC6C9856,
127186752Sfjoe	0x7CD385C7,  0x0BD4B551,  0x92DDE4EB,  0xE5DAD47D,
127286752Sfjoe	0x7BBE41DE,  0x0CB97148,  0x95B020F2,  0xE2B71064,
127386752Sfjoe	0x6FBF1D91,  0x18B82D07,  0x81B17CBD,  0xF6B64C2B,
127486752Sfjoe	0x68D2D988,  0x1FD5E91E,  0x86DCB8A4,  0xF1DB8832,
127586752Sfjoe	0x616495A3,  0x1663A535,  0x8F6AF48F,  0xF86DC419,
127686752Sfjoe	0x660951BA,  0x110E612C,  0x88073096,  0xFF000000
127786752Sfjoe};
1278