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: stable/11/sys/dev/sbni/if_sbni.c 337909 2018-08-16 15:27:19Z brooks $");
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>
82257176Sglebius#include <net/if_var.h>
83152315Sru#include <net/if_dl.h>
8486752Sfjoe#include <net/ethernet.h>
8586752Sfjoe#include <net/bpf.h>
86147256Sbrooks#include <net/if_types.h>
8786752Sfjoe
8886752Sfjoe#include <dev/sbni/if_sbnireg.h>
8986752Sfjoe#include <dev/sbni/if_sbnivar.h>
9086752Sfjoe
9186752Sfjoestatic void	sbni_init(void *);
92180263Sjhbstatic void	sbni_init_locked(struct sbni_softc *);
9386752Sfjoestatic void	sbni_start(struct ifnet *);
94180263Sjhbstatic void	sbni_start_locked(struct ifnet *);
9586752Sfjoestatic int	sbni_ioctl(struct ifnet *, u_long, caddr_t);
9686752Sfjoestatic void	sbni_stop(struct sbni_softc *);
9786752Sfjoestatic void	handle_channel(struct sbni_softc *);
9886752Sfjoe
9986752Sfjoestatic void	card_start(struct sbni_softc *);
10086752Sfjoestatic int	recv_frame(struct sbni_softc *);
10186752Sfjoestatic void	send_frame(struct sbni_softc *);
10286752Sfjoestatic int	upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t);
10386752Sfjoestatic int	skip_tail(struct sbni_softc *, u_int, u_int32_t);
10486752Sfjoestatic void	interpret_ack(struct sbni_softc *, u_int);
10586752Sfjoestatic void	download_data(struct sbni_softc *, u_int32_t *);
10686752Sfjoestatic void	prepare_to_send(struct sbni_softc *);
10786752Sfjoestatic void	drop_xmit_queue(struct sbni_softc *);
10886752Sfjoestatic int	get_rx_buf(struct sbni_softc *);
10986752Sfjoestatic void	indicate_pkt(struct sbni_softc *);
11086752Sfjoestatic void	change_level(struct sbni_softc *);
11186752Sfjoestatic int	check_fhdr(struct sbni_softc *, u_int *, u_int *,
11286752Sfjoe			   u_int *, u_int *, u_int32_t *);
11386752Sfjoestatic int	append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t);
11486752Sfjoestatic void	timeout_change_level(struct sbni_softc *);
11586752Sfjoestatic void	send_frame_header(struct sbni_softc *, u_int32_t *);
11686752Sfjoestatic void	set_initial_values(struct sbni_softc *, struct sbni_flags);
11786752Sfjoe
11886752Sfjoestatic u_int32_t	calc_crc32(u_int32_t, caddr_t, u_int);
11986752Sfjoestatic timeout_t	sbni_timeout;
12086752Sfjoe
12186752Sfjoestatic __inline u_char	sbni_inb(struct sbni_softc *, enum sbni_reg);
12286752Sfjoestatic __inline void	sbni_outb(struct sbni_softc *, enum sbni_reg, u_char);
12386752Sfjoestatic __inline void	sbni_insb(struct sbni_softc *, u_char *, u_int);
12486752Sfjoestatic __inline void	sbni_outsb(struct sbni_softc *, u_char *, u_int);
12586752Sfjoe
12686752Sfjoestatic u_int32_t crc32tab[];
12786752Sfjoe
12886752Sfjoe#ifdef SBNI_DUAL_COMPOUND
129180263Sjhbstatic struct mtx headlist_lock;
130180263SjhbMTX_SYSINIT(headlist_lock, &headlist_lock, "sbni headlist", MTX_DEF);
131180263Sjhbstatic struct sbni_softc *sbni_headlist;
13286752Sfjoe#endif
13386752Sfjoe
13486752Sfjoe/* -------------------------------------------------------------------------- */
13586752Sfjoe
13686752Sfjoestatic __inline u_char
13786752Sfjoesbni_inb(struct sbni_softc *sc, enum sbni_reg reg)
13886752Sfjoe{
139101400Sfjoe	return bus_space_read_1(
140101400Sfjoe	    rman_get_bustag(sc->io_res),
141101400Sfjoe	    rman_get_bushandle(sc->io_res),
142101400Sfjoe	    sc->io_off + reg);
14386752Sfjoe}
14486752Sfjoe
14586752Sfjoestatic __inline void
14686752Sfjoesbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value)
14786752Sfjoe{
148101400Sfjoe	bus_space_write_1(
149101400Sfjoe	    rman_get_bustag(sc->io_res),
150101400Sfjoe	    rman_get_bushandle(sc->io_res),
151101400Sfjoe	    sc->io_off + reg, value);
15286752Sfjoe}
15386752Sfjoe
15486752Sfjoestatic __inline void
15586752Sfjoesbni_insb(struct sbni_softc *sc, u_char *to, u_int len)
15686752Sfjoe{
157101400Sfjoe	bus_space_read_multi_1(
158101400Sfjoe	    rman_get_bustag(sc->io_res),
159101400Sfjoe	    rman_get_bushandle(sc->io_res),
160101400Sfjoe	    sc->io_off + DAT, to, len);
16186752Sfjoe}
16286752Sfjoe
16386752Sfjoestatic __inline void
16486752Sfjoesbni_outsb(struct sbni_softc *sc, u_char *from, u_int len)
16586752Sfjoe{
166101400Sfjoe	bus_space_write_multi_1(
167101400Sfjoe	    rman_get_bustag(sc->io_res),
168101400Sfjoe	    rman_get_bushandle(sc->io_res),
169101400Sfjoe	    sc->io_off + DAT, from, len);
17086752Sfjoe}
17186752Sfjoe
17286752Sfjoe
17386752Sfjoe/*
17486752Sfjoe	Valid combinations in CSR0 (for probing):
17586752Sfjoe
17686752Sfjoe	VALID_DECODER	0000,0011,1011,1010
17786752Sfjoe
17886752Sfjoe				    	; 0   ; -
17986752Sfjoe				TR_REQ	; 1   ; +
18086752Sfjoe			TR_RDY	    	; 2   ; -
18186752Sfjoe			TR_RDY	TR_REQ	; 3   ; +
18286752Sfjoe		BU_EMP		    	; 4   ; +
18386752Sfjoe		BU_EMP	     	TR_REQ	; 5   ; +
18486752Sfjoe		BU_EMP	TR_RDY	    	; 6   ; -
18586752Sfjoe		BU_EMP	TR_RDY	TR_REQ	; 7   ; +
18686752Sfjoe	RC_RDY 		     		; 8   ; +
18786752Sfjoe	RC_RDY			TR_REQ	; 9   ; +
18886752Sfjoe	RC_RDY		TR_RDY		; 10  ; -
18986752Sfjoe	RC_RDY		TR_RDY	TR_REQ	; 11  ; -
19086752Sfjoe	RC_RDY	BU_EMP			; 12  ; -
19186752Sfjoe	RC_RDY	BU_EMP		TR_REQ	; 13  ; -
19286752Sfjoe	RC_RDY	BU_EMP	TR_RDY		; 14  ; -
19386752Sfjoe	RC_RDY	BU_EMP	TR_RDY	TR_REQ	; 15  ; -
19486752Sfjoe*/
19586752Sfjoe
19686752Sfjoe#define VALID_DECODER	(2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
19786752Sfjoe
19886752Sfjoe
19986752Sfjoeint
20086752Sfjoesbni_probe(struct sbni_softc *sc)
20186752Sfjoe{
20286752Sfjoe	u_char csr0;
20386752Sfjoe
20486752Sfjoe	csr0 = sbni_inb(sc, CSR0);
20586752Sfjoe	if (csr0 != 0xff && csr0 != 0x00) {
20686752Sfjoe		csr0 &= ~EN_INT;
20786752Sfjoe		if (csr0 & BU_EMP)
20886752Sfjoe			csr0 |= EN_INT;
20986752Sfjoe
21086752Sfjoe		if (VALID_DECODER & (1 << (csr0 >> 4)))
21186752Sfjoe			return (0);
21286752Sfjoe	}
21386752Sfjoe
21486752Sfjoe	return (ENXIO);
21586752Sfjoe}
21686752Sfjoe
21786752Sfjoe
21886752Sfjoe/*
21986752Sfjoe * Install interface into kernel networking data structures
22086752Sfjoe */
221180263Sjhbint
22286752Sfjoesbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags)
22386752Sfjoe{
22486752Sfjoe	struct ifnet *ifp;
22586752Sfjoe	u_char csr0;
22686752Sfjoe
227147256Sbrooks	ifp = sc->ifp = if_alloc(IFT_ETHER);
228147256Sbrooks	if (ifp == NULL)
229180263Sjhb		return (ENOMEM);
23086752Sfjoe	sbni_outb(sc, CSR0, 0);
23186752Sfjoe	set_initial_values(sc, flags);
23286752Sfjoe
233121752Sbrooks	/* Initialize ifnet structure */
234121752Sbrooks	ifp->if_softc	= sc;
235121816Sbrooks	if_initname(ifp, "sbni", unit);
236121752Sbrooks	ifp->if_init	= sbni_init;
237121752Sbrooks	ifp->if_start	= sbni_start;
238121752Sbrooks	ifp->if_ioctl	= sbni_ioctl;
239207554Ssobomax	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
24086752Sfjoe
241121752Sbrooks	/* report real baud rate */
242121752Sbrooks	csr0 = sbni_inb(sc, CSR0);
243121752Sbrooks	ifp->if_baudrate =
244121752Sbrooks		(csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate);
24586752Sfjoe
246180263Sjhb	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
247180263Sjhb
248180263Sjhb	mtx_init(&sc->lock, ifp->if_xname, MTX_NETWORK_LOCK, MTX_DEF);
249180263Sjhb	callout_init_mtx(&sc->wch, &sc->lock, 0);
250147256Sbrooks	ether_ifattach(ifp, sc->enaddr);
25186752Sfjoe	/* device attach does transition from UNCONFIGURED to IDLE state */
25286752Sfjoe
253263102Sglebius	if_printf(ifp, "speed %ju, rxl ", (uintmax_t)ifp->if_baudrate);
25486752Sfjoe	if (sc->delta_rxl)
25586752Sfjoe		printf("auto\n");
25686752Sfjoe	else
25786752Sfjoe		printf("%d (fixed)\n", sc->cur_rxl_index);
258180263Sjhb	return (0);
25986752Sfjoe}
26086752Sfjoe
261180263Sjhbvoid
262180263Sjhbsbni_detach(struct sbni_softc *sc)
263180263Sjhb{
264180263Sjhb
265180263Sjhb	SBNI_LOCK(sc);
266180263Sjhb	sbni_stop(sc);
267180263Sjhb	SBNI_UNLOCK(sc);
268180263Sjhb	callout_drain(&sc->wch);
269180263Sjhb	ether_ifdetach(sc->ifp);
270180263Sjhb	if (sc->irq_handle)
271180263Sjhb		bus_teardown_intr(sc->dev, sc->irq_res, sc->irq_handle);
272180263Sjhb	mtx_destroy(&sc->lock);
273180263Sjhb	if_free(sc->ifp);
274180263Sjhb}
275180263Sjhb
276180263Sjhbvoid
277180263Sjhbsbni_release_resources(struct sbni_softc *sc)
278180263Sjhb{
279180263Sjhb
280180263Sjhb	if (sc->irq_res)
281180263Sjhb		bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
282180263Sjhb		    sc->irq_res);
283180263Sjhb	if (sc->io_res && sc->io_off == 0)
284180263Sjhb		bus_release_resource(sc->dev, SYS_RES_IOPORT, sc->io_rid,
285180263Sjhb		    sc->io_res);
286180263Sjhb}
287180263Sjhb
28886752Sfjoe/* -------------------------------------------------------------------------- */
28986752Sfjoe
29086752Sfjoestatic void
29186752Sfjoesbni_init(void *xsc)
29286752Sfjoe{
29386752Sfjoe	struct sbni_softc *sc;
294180263Sjhb
295180263Sjhb	sc = (struct sbni_softc *)xsc;
296180263Sjhb	SBNI_LOCK(sc);
297180263Sjhb	sbni_init_locked(sc);
298180263Sjhb	SBNI_UNLOCK(sc);
299180263Sjhb}
300180263Sjhb
301180263Sjhbstatic void
302180263Sjhbsbni_init_locked(struct sbni_softc *sc)
303180263Sjhb{
30486752Sfjoe	struct ifnet *ifp;
30586752Sfjoe
306147256Sbrooks	ifp = sc->ifp;
30786752Sfjoe
30886752Sfjoe	/*
30986752Sfjoe	 * kludge to avoid multiple initialization when more than once
31086752Sfjoe	 * protocols configured
31186752Sfjoe	 */
312148887Srwatson	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
31386752Sfjoe		return;
31486752Sfjoe
31586752Sfjoe	card_start(sc);
316180263Sjhb	callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc);
31786752Sfjoe
318148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
319148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
32086752Sfjoe
32186752Sfjoe	/* attempt to start output */
322180263Sjhb	sbni_start_locked(ifp);
32386752Sfjoe}
32486752Sfjoe
32586752Sfjoestatic void
32686752Sfjoesbni_start(struct ifnet *ifp)
32786752Sfjoe{
32886752Sfjoe	struct sbni_softc *sc = ifp->if_softc;
329180263Sjhb
330180263Sjhb	SBNI_LOCK(sc);
331180263Sjhb	sbni_start_locked(ifp);
332180263Sjhb	SBNI_UNLOCK(sc);
333180263Sjhb}
334180263Sjhb
335180263Sjhbstatic void
336180263Sjhbsbni_start_locked(struct ifnet *ifp)
337180263Sjhb{
338180263Sjhb	struct sbni_softc *sc = ifp->if_softc;
339180263Sjhb
34086752Sfjoe	if (sc->tx_frameno == 0)
34186752Sfjoe		prepare_to_send(sc);
34286752Sfjoe}
34386752Sfjoe
34486752Sfjoe
34586752Sfjoestatic void
34686752Sfjoesbni_stop(struct sbni_softc *sc)
34786752Sfjoe{
34886752Sfjoe	sbni_outb(sc, CSR0, 0);
34986752Sfjoe	drop_xmit_queue(sc);
35086752Sfjoe
35186752Sfjoe	if (sc->rx_buf_p) {
35286752Sfjoe		m_freem(sc->rx_buf_p);
35386752Sfjoe		sc->rx_buf_p = NULL;
35486752Sfjoe	}
35586752Sfjoe
356180263Sjhb	callout_stop(&sc->wch);
357180263Sjhb	sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
35886752Sfjoe}
35986752Sfjoe
36086752Sfjoe/* -------------------------------------------------------------------------- */
36186752Sfjoe
36286752Sfjoe/* interrupt handler */
36386752Sfjoe
36486752Sfjoe/*
36586752Sfjoe * 	SBNI12D-10, -11/ISA boards within "common interrupt" mode could not
36686752Sfjoe * be looked as two independent single-channel devices. Every channel seems
36786752Sfjoe * as Ethernet interface but interrupt handler must be common. Really, first
36886752Sfjoe * channel ("master") driver only registers the handler. In it's struct softc
36986752Sfjoe * it has got pointer to "slave" channel's struct softc and handles that's
37086752Sfjoe * interrupts too.
37186752Sfjoe *	softc of successfully attached ISA SBNI boards is linked to list.
37286752Sfjoe * While next board driver is initialized, it scans this list. If one
37386752Sfjoe * has found softc with same irq and ioaddr different by 4 then it assumes
37486752Sfjoe * this board to be "master".
37586752Sfjoe */
37686752Sfjoe
37786752Sfjoevoid
37886752Sfjoesbni_intr(void *arg)
37986752Sfjoe{
38086752Sfjoe	struct sbni_softc *sc;
38186752Sfjoe	int repeat;
38286752Sfjoe
38386752Sfjoe	sc = (struct sbni_softc *)arg;
38486752Sfjoe
38586752Sfjoe	do {
38686752Sfjoe		repeat = 0;
387180263Sjhb		SBNI_LOCK(sc);
38886752Sfjoe		if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) {
38986752Sfjoe			handle_channel(sc);
39086752Sfjoe			repeat = 1;
39186752Sfjoe		}
392180263Sjhb		SBNI_UNLOCK(sc);
393180263Sjhb		if (sc->slave_sc) {
394180263Sjhb			/* second channel present */
395180263Sjhb			SBNI_LOCK(sc->slave_sc);
396180263Sjhb			if (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY)) {
397180263Sjhb				handle_channel(sc->slave_sc);
398180263Sjhb				repeat = 1;
399180263Sjhb			}
400180263Sjhb			SBNI_UNLOCK(sc->slave_sc);
40186752Sfjoe		}
40286752Sfjoe	} while (repeat);
40386752Sfjoe}
40486752Sfjoe
40586752Sfjoe
40686752Sfjoestatic void
40786752Sfjoehandle_channel(struct sbni_softc *sc)
40886752Sfjoe{
40986752Sfjoe	int req_ans;
41086752Sfjoe	u_char csr0;
41186752Sfjoe
41286752Sfjoe	sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ);
41386752Sfjoe
41486752Sfjoe	sc->timer_ticks = CHANGE_LEVEL_START_TICKS;
41586752Sfjoe	for (;;) {
41686752Sfjoe		csr0 = sbni_inb(sc, CSR0);
41786752Sfjoe		if ((csr0 & (RC_RDY | TR_RDY)) == 0)
41886752Sfjoe			break;
41986752Sfjoe
42086752Sfjoe		req_ans = !(sc->state & FL_PREV_OK);
42186752Sfjoe
42286752Sfjoe		if (csr0 & RC_RDY)
42386752Sfjoe			req_ans = recv_frame(sc);
42486752Sfjoe
42586752Sfjoe		/*
42686752Sfjoe		 * TR_RDY always equals 1 here because we have owned the marker,
42786752Sfjoe		 * and we set TR_REQ when disabled interrupts
42886752Sfjoe		 */
42986752Sfjoe		csr0 = sbni_inb(sc, CSR0);
43086752Sfjoe		if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0)
431180263Sjhb			if_printf(sc->ifp, "internal error!\n");
43286752Sfjoe
43386752Sfjoe		/* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */
43486752Sfjoe		if (req_ans || sc->tx_frameno != 0)
43586752Sfjoe			send_frame(sc);
436101393Sfjoe		else {
43786752Sfjoe			/* send the marker without any data */
43886752Sfjoe			sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ);
439101393Sfjoe		}
44086752Sfjoe	}
44186752Sfjoe
44286752Sfjoe	sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT);
44386752Sfjoe}
44486752Sfjoe
44586752Sfjoe
44686752Sfjoe/*
44786752Sfjoe * Routine returns 1 if it need to acknoweledge received frame.
44886752Sfjoe * Empty frame received without errors won't be acknoweledged.
44986752Sfjoe */
45086752Sfjoe
45186752Sfjoestatic int
45286752Sfjoerecv_frame(struct sbni_softc *sc)
45386752Sfjoe{
45486752Sfjoe	u_int32_t crc;
45586752Sfjoe	u_int framelen, frameno, ack;
45686752Sfjoe	u_int is_first, frame_ok;
45786752Sfjoe
45886752Sfjoe	crc = CRC32_INITIAL;
45986752Sfjoe	if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) {
460101393Sfjoe		frame_ok = framelen > 4 ?
461101393Sfjoe		    upload_data(sc, framelen, frameno, is_first, crc) :
462101393Sfjoe		    skip_tail(sc, framelen, crc);
46386752Sfjoe		if (frame_ok)
46486752Sfjoe			interpret_ack(sc, ack);
465171243Speter	} else {
466171243Speter		framelen = 0;
46786752Sfjoe		frame_ok = 0;
468171243Speter	}
46986752Sfjoe
47086752Sfjoe	sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER);
47186752Sfjoe	if (frame_ok) {
47286752Sfjoe		sc->state |= FL_PREV_OK;
47386752Sfjoe		if (framelen > 4)
47486752Sfjoe			sc->in_stats.all_rx_number++;
47586752Sfjoe	} else {
47686752Sfjoe		sc->state &= ~FL_PREV_OK;
47786752Sfjoe		change_level(sc);
47886752Sfjoe		sc->in_stats.all_rx_number++;
47986752Sfjoe		sc->in_stats.bad_rx_number++;
48086752Sfjoe	}
48186752Sfjoe
48286752Sfjoe	return (!frame_ok || framelen > 4);
48386752Sfjoe}
48486752Sfjoe
48586752Sfjoe
48686752Sfjoestatic void
48786752Sfjoesend_frame(struct sbni_softc *sc)
48886752Sfjoe{
48986752Sfjoe	u_int32_t crc;
49086752Sfjoe	u_char csr0;
49186752Sfjoe
49286752Sfjoe	crc = CRC32_INITIAL;
49386752Sfjoe	if (sc->state & FL_NEED_RESEND) {
49486752Sfjoe
49586752Sfjoe		/* if frame was sended but not ACK'ed - resend it */
49686752Sfjoe		if (sc->trans_errors) {
49786752Sfjoe			sc->trans_errors--;
49886752Sfjoe			if (sc->framelen != 0)
49986752Sfjoe				sc->in_stats.resend_tx_number++;
50086752Sfjoe		} else {
50186752Sfjoe			/* cannot xmit with many attempts */
50286752Sfjoe			drop_xmit_queue(sc);
50386752Sfjoe			goto do_send;
50486752Sfjoe		}
50586752Sfjoe	} else
50686752Sfjoe		sc->trans_errors = TR_ERROR_COUNT;
50786752Sfjoe
50886752Sfjoe	send_frame_header(sc, &crc);
50986752Sfjoe	sc->state |= FL_NEED_RESEND;
51086752Sfjoe	/*
51186752Sfjoe	 * FL_NEED_RESEND will be cleared after ACK, but if empty
51286752Sfjoe	 * frame sended then in prepare_to_send next frame
51386752Sfjoe	 */
51486752Sfjoe
51586752Sfjoe
51686752Sfjoe	if (sc->framelen) {
51786752Sfjoe		download_data(sc, &crc);
51886752Sfjoe		sc->in_stats.all_tx_number++;
51986752Sfjoe		sc->state |= FL_WAIT_ACK;
52086752Sfjoe	}
52186752Sfjoe
52286752Sfjoe	sbni_outsb(sc, (u_char *)&crc, sizeof crc);
52386752Sfjoe
52486752Sfjoedo_send:
52586752Sfjoe	csr0 = sbni_inb(sc, CSR0);
52686752Sfjoe	sbni_outb(sc, CSR0, csr0 & ~TR_REQ);
52786752Sfjoe
52886752Sfjoe	if (sc->tx_frameno) {
52986752Sfjoe		/* next frame exists - request to send */
53086752Sfjoe		sbni_outb(sc, CSR0, csr0 | TR_REQ);
53186752Sfjoe	}
53286752Sfjoe}
53386752Sfjoe
53486752Sfjoe
53586752Sfjoestatic void
53686752Sfjoedownload_data(struct sbni_softc *sc, u_int32_t *crc_p)
53786752Sfjoe{
53886752Sfjoe	struct mbuf *m;
53986752Sfjoe	caddr_t	data_p;
54086752Sfjoe	u_int data_len, pos, slice;
54186752Sfjoe
54286752Sfjoe	data_p = NULL;		/* initialized to avoid warn */
54386752Sfjoe	pos = 0;
54486752Sfjoe
54586752Sfjoe	for (m = sc->tx_buf_p;  m != NULL && pos < sc->pktlen;  m = m->m_next) {
54686752Sfjoe		if (pos + m->m_len > sc->outpos) {
54786752Sfjoe			data_len = m->m_len - (sc->outpos - pos);
54886752Sfjoe			data_p = mtod(m, caddr_t) + (sc->outpos - pos);
54986752Sfjoe
55086752Sfjoe			goto do_copy;
55186752Sfjoe		} else
55286752Sfjoe			pos += m->m_len;
55386752Sfjoe	}
55486752Sfjoe
55586752Sfjoe	data_len = 0;
55686752Sfjoe
55786752Sfjoedo_copy:
55886752Sfjoe	pos = 0;
55986752Sfjoe	do {
56086752Sfjoe		if (data_len) {
56186752Sfjoe			slice = min(data_len, sc->framelen - pos);
56286752Sfjoe			sbni_outsb(sc, data_p, slice);
56386752Sfjoe			*crc_p = calc_crc32(*crc_p, data_p, slice);
56486752Sfjoe
56586752Sfjoe			pos += slice;
56686752Sfjoe			if (data_len -= slice)
56786752Sfjoe				data_p += slice;
56886752Sfjoe			else {
569101393Sfjoe				do {
570101393Sfjoe					m = m->m_next;
571101393Sfjoe				} while (m != NULL && m->m_len == 0);
57286752Sfjoe
57386752Sfjoe				if (m) {
57486752Sfjoe					data_len = m->m_len;
57586752Sfjoe					data_p = mtod(m, caddr_t);
57686752Sfjoe				}
57786752Sfjoe			}
57886752Sfjoe		} else {
57986752Sfjoe			/* frame too short - zero padding */
58086752Sfjoe
58186752Sfjoe			pos = sc->framelen - pos;
58286752Sfjoe			while (pos--) {
58386752Sfjoe				sbni_outb(sc, DAT, 0);
58486752Sfjoe				*crc_p = CRC32(0, *crc_p);
58586752Sfjoe			}
58686752Sfjoe			return;
58786752Sfjoe		}
58886752Sfjoe	} while (pos < sc->framelen);
58986752Sfjoe}
59086752Sfjoe
59186752Sfjoe
59286752Sfjoestatic int
59386752Sfjoeupload_data(struct sbni_softc *sc, u_int framelen, u_int frameno,
59486752Sfjoe	    u_int is_first, u_int32_t crc)
59586752Sfjoe{
59686752Sfjoe	int frame_ok;
59786752Sfjoe
59886752Sfjoe	if (is_first) {
59986752Sfjoe		sc->wait_frameno = frameno;
60086752Sfjoe		sc->inppos = 0;
60186752Sfjoe	}
60286752Sfjoe
60386752Sfjoe	if (sc->wait_frameno == frameno) {
60486752Sfjoe
60586752Sfjoe		if (sc->inppos + framelen  <=  ETHER_MAX_LEN) {
60686752Sfjoe			frame_ok = append_frame_to_pkt(sc, framelen, crc);
60786752Sfjoe
60886752Sfjoe		/*
60986752Sfjoe		 * if CRC is right but framelen incorrect then transmitter
610298955Spfg		 * error was occurred... drop entire packet
61186752Sfjoe		 */
61286752Sfjoe		} else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) {
61386752Sfjoe			sc->wait_frameno = 0;
61486752Sfjoe			sc->inppos = 0;
615271849Sglebius			if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
61686752Sfjoe			/* now skip all frames until is_first != 0 */
61786752Sfjoe		}
61886752Sfjoe	} else
61986752Sfjoe		frame_ok = skip_tail(sc, framelen, crc);
62086752Sfjoe
62186752Sfjoe	if (is_first && !frame_ok) {
62286752Sfjoe		/*
62386752Sfjoe		 * Frame has been violated, but we have stored
62486752Sfjoe		 * is_first already... Drop entire packet.
62586752Sfjoe		 */
62686752Sfjoe		sc->wait_frameno = 0;
627271849Sglebius		if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
62886752Sfjoe	}
62986752Sfjoe
63086752Sfjoe	return (frame_ok);
63186752Sfjoe}
63286752Sfjoe
63386752Sfjoe
63486752Sfjoestatic __inline void	send_complete(struct sbni_softc *);
63586752Sfjoe
63686752Sfjoestatic __inline void
63786752Sfjoesend_complete(struct sbni_softc *sc)
63886752Sfjoe{
63986752Sfjoe	m_freem(sc->tx_buf_p);
64086752Sfjoe	sc->tx_buf_p = NULL;
641271849Sglebius	if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1);
64286752Sfjoe}
64386752Sfjoe
64486752Sfjoe
64586752Sfjoestatic void
64686752Sfjoeinterpret_ack(struct sbni_softc *sc, u_int ack)
64786752Sfjoe{
64886752Sfjoe	if (ack == FRAME_SENT_OK) {
64986752Sfjoe		sc->state &= ~FL_NEED_RESEND;
65086752Sfjoe
65186752Sfjoe		if (sc->state & FL_WAIT_ACK) {
65286752Sfjoe			sc->outpos += sc->framelen;
65386752Sfjoe
654101393Sfjoe			if (--sc->tx_frameno) {
655101393Sfjoe				sc->framelen = min(
656101393Sfjoe				    sc->maxframe, sc->pktlen - sc->outpos);
657101393Sfjoe			} else {
65886752Sfjoe				send_complete(sc);
65986752Sfjoe				prepare_to_send(sc);
66086752Sfjoe			}
66186752Sfjoe		}
66286752Sfjoe	}
66386752Sfjoe
66486752Sfjoe	sc->state &= ~FL_WAIT_ACK;
66586752Sfjoe}
66686752Sfjoe
66786752Sfjoe
66886752Sfjoe/*
66986752Sfjoe * Glue received frame with previous fragments of packet.
67086752Sfjoe * Indicate packet when last frame would be accepted.
67186752Sfjoe */
67286752Sfjoe
67386752Sfjoestatic int
67486752Sfjoeappend_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc)
67586752Sfjoe{
67686752Sfjoe	caddr_t p;
67786752Sfjoe
67886752Sfjoe	if (sc->inppos + framelen > ETHER_MAX_LEN)
67986752Sfjoe		return (0);
68086752Sfjoe
68186752Sfjoe	if (!sc->rx_buf_p && !get_rx_buf(sc))
68286752Sfjoe		return (0);
68386752Sfjoe
68486752Sfjoe	p = sc->rx_buf_p->m_data + sc->inppos;
68586752Sfjoe	sbni_insb(sc, p, framelen);
68686752Sfjoe	if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER)
68786752Sfjoe		return (0);
68886752Sfjoe
68986752Sfjoe	sc->inppos += framelen - 4;
69086752Sfjoe	if (--sc->wait_frameno == 0) {		/* last frame received */
69186752Sfjoe		indicate_pkt(sc);
692271849Sglebius		if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
69386752Sfjoe	}
69486752Sfjoe
69586752Sfjoe	return (1);
69686752Sfjoe}
69786752Sfjoe
69886752Sfjoe
69986752Sfjoe/*
70086752Sfjoe * Prepare to start output on adapter. Current priority must be set to splimp
70186752Sfjoe * before this routine is called.
70286752Sfjoe * Transmitter will be actually activated when marker has been accepted.
70386752Sfjoe */
70486752Sfjoe
70586752Sfjoestatic void
70686752Sfjoeprepare_to_send(struct sbni_softc *sc)
70786752Sfjoe{
70886752Sfjoe	struct mbuf *m;
70986752Sfjoe	u_int len;
71086752Sfjoe
71186752Sfjoe	/* sc->tx_buf_p == NULL here! */
71286752Sfjoe	if (sc->tx_buf_p)
71386752Sfjoe		printf("sbni: memory leak!\n");
71486752Sfjoe
71586752Sfjoe	sc->outpos = 0;
71686752Sfjoe	sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
71786752Sfjoe
71886752Sfjoe	for (;;) {
719147256Sbrooks		IF_DEQUEUE(&sc->ifp->if_snd, sc->tx_buf_p);
72086752Sfjoe		if (!sc->tx_buf_p) {
72186752Sfjoe			/* nothing to transmit... */
72286752Sfjoe			sc->pktlen     = 0;
72386752Sfjoe			sc->tx_frameno = 0;
72486752Sfjoe			sc->framelen   = 0;
725148887Srwatson			sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
72686752Sfjoe			return;
72786752Sfjoe		}
72886752Sfjoe
72986752Sfjoe		for (len = 0, m = sc->tx_buf_p;  m;  m = m->m_next)
73086752Sfjoe			len += m->m_len;
73186752Sfjoe
73286752Sfjoe		if (len != 0)
73386752Sfjoe			break;
73486752Sfjoe		m_freem(sc->tx_buf_p);
73586752Sfjoe	}
73686752Sfjoe
73786752Sfjoe	if (len < SBNI_MIN_LEN)
73886752Sfjoe		len = SBNI_MIN_LEN;
73986752Sfjoe
74086752Sfjoe	sc->pktlen	= len;
741298646Spfg	sc->tx_frameno	= howmany(len, sc->maxframe);
74286752Sfjoe	sc->framelen	= min(len, sc->maxframe);
74386752Sfjoe
74486752Sfjoe	sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ);
745148887Srwatson	sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE;
746147256Sbrooks	BPF_MTAP(sc->ifp, sc->tx_buf_p);
74786752Sfjoe}
74886752Sfjoe
74986752Sfjoe
75086752Sfjoestatic void
75186752Sfjoedrop_xmit_queue(struct sbni_softc *sc)
75286752Sfjoe{
75386752Sfjoe	struct mbuf *m;
75486752Sfjoe
75586752Sfjoe	if (sc->tx_buf_p) {
75686752Sfjoe		m_freem(sc->tx_buf_p);
75786752Sfjoe		sc->tx_buf_p = NULL;
758271849Sglebius		if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1);
75986752Sfjoe	}
76086752Sfjoe
76186752Sfjoe	for (;;) {
762147256Sbrooks		IF_DEQUEUE(&sc->ifp->if_snd, m);
76386752Sfjoe		if (m == NULL)
76486752Sfjoe			break;
76586752Sfjoe		m_freem(m);
766271849Sglebius		if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1);
76786752Sfjoe	}
76886752Sfjoe
76986752Sfjoe	sc->tx_frameno	= 0;
77086752Sfjoe	sc->framelen	= 0;
77186752Sfjoe	sc->outpos	= 0;
77286752Sfjoe	sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
773148887Srwatson	sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
77486752Sfjoe}
77586752Sfjoe
77686752Sfjoe
77786752Sfjoestatic void
77886752Sfjoesend_frame_header(struct sbni_softc *sc, u_int32_t *crc_p)
77986752Sfjoe{
78086752Sfjoe	u_int32_t crc;
78186752Sfjoe	u_int len_field;
78286752Sfjoe	u_char value;
78386752Sfjoe
78486752Sfjoe	crc = *crc_p;
78586752Sfjoe	len_field = sc->framelen + 6;	/* CRC + frameno + reserved */
78686752Sfjoe
78786752Sfjoe	if (sc->state & FL_NEED_RESEND)
78886752Sfjoe		len_field |= FRAME_RETRY;	/* non-first attempt... */
78986752Sfjoe
79086752Sfjoe	if (sc->outpos == 0)
79186752Sfjoe		len_field |= FRAME_FIRST;
79286752Sfjoe
79386752Sfjoe	len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD;
79486752Sfjoe	sbni_outb(sc, DAT, SBNI_SIG);
79586752Sfjoe
79686752Sfjoe	value = (u_char)len_field;
79786752Sfjoe	sbni_outb(sc, DAT, value);
79886752Sfjoe	crc = CRC32(value, crc);
79986752Sfjoe	value = (u_char)(len_field >> 8);
80086752Sfjoe	sbni_outb(sc, DAT, value);
80186752Sfjoe	crc = CRC32(value, crc);
80286752Sfjoe
80386752Sfjoe	sbni_outb(sc, DAT, sc->tx_frameno);
80486752Sfjoe	crc = CRC32(sc->tx_frameno, crc);
80586752Sfjoe	sbni_outb(sc, DAT, 0);
80686752Sfjoe	crc = CRC32(0, crc);
80786752Sfjoe	*crc_p = crc;
80886752Sfjoe}
80986752Sfjoe
81086752Sfjoe
81186752Sfjoe/*
81286752Sfjoe * if frame tail not needed (incorrect number or received twice),
81386752Sfjoe * it won't store, but CRC will be calculated
81486752Sfjoe */
81586752Sfjoe
81686752Sfjoestatic int
81786752Sfjoeskip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc)
81886752Sfjoe{
81986752Sfjoe	while (tail_len--)
82086752Sfjoe		crc = CRC32(sbni_inb(sc, DAT), crc);
82186752Sfjoe
82286752Sfjoe	return (crc == CRC32_REMAINDER);
82386752Sfjoe}
82486752Sfjoe
82586752Sfjoe
82686752Sfjoestatic int
82786752Sfjoecheck_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno,
82886752Sfjoe	   u_int *ack, u_int *is_first, u_int32_t *crc_p)
82986752Sfjoe{
83086752Sfjoe	u_int32_t crc;
83186752Sfjoe	u_char value;
83286752Sfjoe
83386752Sfjoe	crc = *crc_p;
83486752Sfjoe	if (sbni_inb(sc, DAT) != SBNI_SIG)
83586752Sfjoe		return (0);
83686752Sfjoe
83786752Sfjoe	value = sbni_inb(sc, DAT);
83886752Sfjoe	*framelen = (u_int)value;
83986752Sfjoe	crc = CRC32(value, crc);
84086752Sfjoe	value = sbni_inb(sc, DAT);
84186752Sfjoe	*framelen |= ((u_int)value) << 8;
84286752Sfjoe	crc = CRC32(value, crc);
84386752Sfjoe
84486752Sfjoe	*ack = *framelen & FRAME_ACK_MASK;
84586752Sfjoe	*is_first = (*framelen & FRAME_FIRST) != 0;
84686752Sfjoe
84786752Sfjoe	if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3)
84886752Sfjoe		return (0);
84986752Sfjoe
85086752Sfjoe	value = sbni_inb(sc, DAT);
85186752Sfjoe	*frameno = (u_int)value;
85286752Sfjoe	crc = CRC32(value, crc);
85386752Sfjoe
85486752Sfjoe	crc = CRC32(sbni_inb(sc, DAT), crc);		/* reserved byte */
85586752Sfjoe	*framelen -= 2;
85686752Sfjoe
85786752Sfjoe	*crc_p = crc;
85886752Sfjoe	return (1);
85986752Sfjoe}
86086752Sfjoe
86186752Sfjoe
86286752Sfjoestatic int
86386752Sfjoeget_rx_buf(struct sbni_softc *sc)
86486752Sfjoe{
86586752Sfjoe	struct mbuf *m;
86686752Sfjoe
867243857Sglebius	MGETHDR(m, M_NOWAIT, MT_DATA);
86886752Sfjoe	if (m == NULL) {
869147256Sbrooks		if_printf(sc->ifp, "cannot allocate header mbuf\n");
87086752Sfjoe		return (0);
87186752Sfjoe	}
87286752Sfjoe
87386752Sfjoe	/*
87486752Sfjoe	 * We always put the received packet in a single buffer -
87586752Sfjoe	 * either with just an mbuf header or in a cluster attached
87686752Sfjoe	 * to the header. The +2 is to compensate for the alignment
87786752Sfjoe	 * fixup below.
87886752Sfjoe	 */
87986752Sfjoe	if (ETHER_MAX_LEN + 2 > MHLEN) {
88086752Sfjoe		/* Attach an mbuf cluster */
881276750Srwatson		if (!(MCLGET(m, M_NOWAIT))) {
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);
1147332161Sbrooks		bcopy(&flags, &ifr->ifr_ifru, sizeof(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);
1156337909Sbrooks		error = copyout(in_stats, ifr_data_get_ptr(ifr),
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;
1166332161Sbrooks		bcopy(&ifr->ifr_ifru, &flags, sizeof(flags));
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