126e46883SJohn Baldwin /*-
226e46883SJohn Baldwin * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved.
326e46883SJohn Baldwin * Author: Denis I.Timofeev <timofeev@granch.ru>
426e46883SJohn Baldwin *
526e46883SJohn Baldwin * Redistributon and use in source and binary forms, with or without
626e46883SJohn Baldwin * modification, are permitted provided that the following conditions
726e46883SJohn Baldwin * are met:
826e46883SJohn Baldwin * 1. Redistributions of source code must retain the above copyright
926e46883SJohn Baldwin * notice unmodified, this list of conditions, and the following
1026e46883SJohn Baldwin * disclaimer.
1126e46883SJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright
1226e46883SJohn Baldwin * notice, this list of conditions and the following disclaimer in the
1326e46883SJohn Baldwin * documentation and/or other materials provided with the distribution.
1426e46883SJohn Baldwin *
1526e46883SJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1626e46883SJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1726e46883SJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1826e46883SJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1926e46883SJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2026e46883SJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2126e46883SJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2226e46883SJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2326e46883SJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY
2426e46883SJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2526e46883SJohn Baldwin * SUCH DAMAGE.
2626e46883SJohn Baldwin *
2726e46883SJohn Baldwin */
2826e46883SJohn Baldwin
2926e46883SJohn Baldwin #include <sys/cdefs.h>
3026e46883SJohn Baldwin /*
3126e46883SJohn Baldwin * Device driver for Granch SBNI12 leased line adapters
3226e46883SJohn Baldwin *
3326e46883SJohn Baldwin * Revision 2.0.0 1997/08/06
3426e46883SJohn Baldwin * Initial revision by Alexey Zverev
3526e46883SJohn Baldwin *
3626e46883SJohn Baldwin * Revision 2.0.1 1997/08/11
3726e46883SJohn Baldwin * Additional internal statistics support (tx statistics)
3826e46883SJohn Baldwin *
3926e46883SJohn Baldwin * Revision 2.0.2 1997/11/05
4026e46883SJohn Baldwin * if_bpf bug has been fixed
4126e46883SJohn Baldwin *
4226e46883SJohn Baldwin * Revision 2.0.3 1998/12/20
4326e46883SJohn Baldwin * Memory leakage has been eliminated in
4426e46883SJohn Baldwin * the sbni_st and sbni_timeout routines.
4526e46883SJohn Baldwin *
4626e46883SJohn Baldwin * Revision 3.0 2000/08/10 by Yaroslav Polyakov
4726e46883SJohn Baldwin * Support for PCI cards. 4.1 modification.
4826e46883SJohn Baldwin *
4926e46883SJohn Baldwin * Revision 3.1 2000/09/12
5026e46883SJohn Baldwin * Removed extra #defines around bpf functions
5126e46883SJohn Baldwin *
5226e46883SJohn Baldwin * Revision 4.0 2000/11/23 by Denis Timofeev
5326e46883SJohn Baldwin * Completely redesigned the buffer management
5426e46883SJohn Baldwin *
5526e46883SJohn Baldwin * Revision 4.1 2001/01/21
5626e46883SJohn Baldwin * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards
5726e46883SJohn Baldwin *
5826e46883SJohn Baldwin * Written with reference to NE2000 driver developed by David Greenman.
5926e46883SJohn Baldwin */
6026e46883SJohn Baldwin
6126e46883SJohn Baldwin #include <sys/param.h>
6226e46883SJohn Baldwin #include <sys/bus.h>
6326e46883SJohn Baldwin #include <sys/systm.h>
6426e46883SJohn Baldwin #include <sys/socket.h>
6526e46883SJohn Baldwin #include <sys/sockio.h>
6626e46883SJohn Baldwin #include <sys/mbuf.h>
6726e46883SJohn Baldwin #include <sys/kernel.h>
6826e46883SJohn Baldwin #include <sys/priv.h>
6926e46883SJohn Baldwin #include <sys/proc.h>
7026e46883SJohn Baldwin #include <sys/callout.h>
7126e46883SJohn Baldwin #include <sys/syslog.h>
7226e46883SJohn Baldwin #include <sys/random.h>
7326e46883SJohn Baldwin
7426e46883SJohn Baldwin #include <machine/bus.h>
7526e46883SJohn Baldwin #include <sys/rman.h>
7626e46883SJohn Baldwin #include <machine/resource.h>
7726e46883SJohn Baldwin
7826e46883SJohn Baldwin #include <net/if.h>
7976039bc8SGleb Smirnoff #include <net/if_var.h>
8026e46883SJohn Baldwin #include <net/if_dl.h>
8126e46883SJohn Baldwin #include <net/ethernet.h>
8226e46883SJohn Baldwin #include <net/bpf.h>
8326e46883SJohn Baldwin #include <net/if_types.h>
8426e46883SJohn Baldwin
8526e46883SJohn Baldwin #include <dev/sbni/if_sbnireg.h>
8626e46883SJohn Baldwin #include <dev/sbni/if_sbnivar.h>
8726e46883SJohn Baldwin
8826e46883SJohn Baldwin static void sbni_init(void *);
8926e46883SJohn Baldwin static void sbni_init_locked(struct sbni_softc *);
903fba06adSJustin Hibbits static void sbni_start(if_t);
913fba06adSJustin Hibbits static void sbni_start_locked(if_t);
923fba06adSJustin Hibbits static int sbni_ioctl(if_t, u_long, caddr_t);
9326e46883SJohn Baldwin static void sbni_stop(struct sbni_softc *);
9426e46883SJohn Baldwin static void handle_channel(struct sbni_softc *);
9526e46883SJohn Baldwin
9626e46883SJohn Baldwin static void card_start(struct sbni_softc *);
9726e46883SJohn Baldwin static int recv_frame(struct sbni_softc *);
9826e46883SJohn Baldwin static void send_frame(struct sbni_softc *);
9926e46883SJohn Baldwin static int upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t);
10026e46883SJohn Baldwin static int skip_tail(struct sbni_softc *, u_int, u_int32_t);
10126e46883SJohn Baldwin static void interpret_ack(struct sbni_softc *, u_int);
10226e46883SJohn Baldwin static void download_data(struct sbni_softc *, u_int32_t *);
10326e46883SJohn Baldwin static void prepare_to_send(struct sbni_softc *);
10426e46883SJohn Baldwin static void drop_xmit_queue(struct sbni_softc *);
10526e46883SJohn Baldwin static int get_rx_buf(struct sbni_softc *);
10626e46883SJohn Baldwin static void indicate_pkt(struct sbni_softc *);
10726e46883SJohn Baldwin static void change_level(struct sbni_softc *);
10826e46883SJohn Baldwin static int check_fhdr(struct sbni_softc *, u_int *, u_int *,
10926e46883SJohn Baldwin u_int *, u_int *, u_int32_t *);
11026e46883SJohn Baldwin static int append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t);
11126e46883SJohn Baldwin static void timeout_change_level(struct sbni_softc *);
11226e46883SJohn Baldwin static void send_frame_header(struct sbni_softc *, u_int32_t *);
11326e46883SJohn Baldwin static void set_initial_values(struct sbni_softc *, struct sbni_flags);
11426e46883SJohn Baldwin
11526e46883SJohn Baldwin static u_int32_t calc_crc32(u_int32_t, caddr_t, u_int);
1165773ac11SJohn Baldwin static callout_func_t sbni_timeout;
11726e46883SJohn Baldwin
11826e46883SJohn Baldwin static __inline u_char sbni_inb(struct sbni_softc *, enum sbni_reg);
11926e46883SJohn Baldwin static __inline void sbni_outb(struct sbni_softc *, enum sbni_reg, u_char);
12026e46883SJohn Baldwin static __inline void sbni_insb(struct sbni_softc *, u_char *, u_int);
12126e46883SJohn Baldwin static __inline void sbni_outsb(struct sbni_softc *, u_char *, u_int);
12226e46883SJohn Baldwin
12326e46883SJohn Baldwin static u_int32_t crc32tab[];
12426e46883SJohn Baldwin
12526e46883SJohn Baldwin #ifdef SBNI_DUAL_COMPOUND
12626e46883SJohn Baldwin static struct mtx headlist_lock;
12726e46883SJohn Baldwin MTX_SYSINIT(headlist_lock, &headlist_lock, "sbni headlist", MTX_DEF);
12826e46883SJohn Baldwin static struct sbni_softc *sbni_headlist;
12926e46883SJohn Baldwin #endif
13026e46883SJohn Baldwin
13126e46883SJohn Baldwin /* -------------------------------------------------------------------------- */
13226e46883SJohn Baldwin
13326e46883SJohn Baldwin static __inline u_char
sbni_inb(struct sbni_softc * sc,enum sbni_reg reg)13426e46883SJohn Baldwin sbni_inb(struct sbni_softc *sc, enum sbni_reg reg)
13526e46883SJohn Baldwin {
13626e46883SJohn Baldwin return bus_space_read_1(
13726e46883SJohn Baldwin rman_get_bustag(sc->io_res),
13826e46883SJohn Baldwin rman_get_bushandle(sc->io_res),
13926e46883SJohn Baldwin sc->io_off + reg);
14026e46883SJohn Baldwin }
14126e46883SJohn Baldwin
14226e46883SJohn Baldwin static __inline void
sbni_outb(struct sbni_softc * sc,enum sbni_reg reg,u_char value)14326e46883SJohn Baldwin sbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value)
14426e46883SJohn Baldwin {
14526e46883SJohn Baldwin bus_space_write_1(
14626e46883SJohn Baldwin rman_get_bustag(sc->io_res),
14726e46883SJohn Baldwin rman_get_bushandle(sc->io_res),
14826e46883SJohn Baldwin sc->io_off + reg, value);
14926e46883SJohn Baldwin }
15026e46883SJohn Baldwin
15126e46883SJohn Baldwin static __inline void
sbni_insb(struct sbni_softc * sc,u_char * to,u_int len)15226e46883SJohn Baldwin sbni_insb(struct sbni_softc *sc, u_char *to, u_int len)
15326e46883SJohn Baldwin {
15426e46883SJohn Baldwin bus_space_read_multi_1(
15526e46883SJohn Baldwin rman_get_bustag(sc->io_res),
15626e46883SJohn Baldwin rman_get_bushandle(sc->io_res),
15726e46883SJohn Baldwin sc->io_off + DAT, to, len);
15826e46883SJohn Baldwin }
15926e46883SJohn Baldwin
16026e46883SJohn Baldwin static __inline void
sbni_outsb(struct sbni_softc * sc,u_char * from,u_int len)16126e46883SJohn Baldwin sbni_outsb(struct sbni_softc *sc, u_char *from, u_int len)
16226e46883SJohn Baldwin {
16326e46883SJohn Baldwin bus_space_write_multi_1(
16426e46883SJohn Baldwin rman_get_bustag(sc->io_res),
16526e46883SJohn Baldwin rman_get_bushandle(sc->io_res),
16626e46883SJohn Baldwin sc->io_off + DAT, from, len);
16726e46883SJohn Baldwin }
16826e46883SJohn Baldwin
16926e46883SJohn Baldwin /*
17026e46883SJohn Baldwin Valid combinations in CSR0 (for probing):
17126e46883SJohn Baldwin
17226e46883SJohn Baldwin VALID_DECODER 0000,0011,1011,1010
17326e46883SJohn Baldwin
17426e46883SJohn Baldwin ; 0 ; -
17526e46883SJohn Baldwin TR_REQ ; 1 ; +
17626e46883SJohn Baldwin TR_RDY ; 2 ; -
17726e46883SJohn Baldwin TR_RDY TR_REQ ; 3 ; +
17826e46883SJohn Baldwin BU_EMP ; 4 ; +
17926e46883SJohn Baldwin BU_EMP TR_REQ ; 5 ; +
18026e46883SJohn Baldwin BU_EMP TR_RDY ; 6 ; -
18126e46883SJohn Baldwin BU_EMP TR_RDY TR_REQ ; 7 ; +
18226e46883SJohn Baldwin RC_RDY ; 8 ; +
18326e46883SJohn Baldwin RC_RDY TR_REQ ; 9 ; +
18426e46883SJohn Baldwin RC_RDY TR_RDY ; 10 ; -
18526e46883SJohn Baldwin RC_RDY TR_RDY TR_REQ ; 11 ; -
18626e46883SJohn Baldwin RC_RDY BU_EMP ; 12 ; -
18726e46883SJohn Baldwin RC_RDY BU_EMP TR_REQ ; 13 ; -
18826e46883SJohn Baldwin RC_RDY BU_EMP TR_RDY ; 14 ; -
18926e46883SJohn Baldwin RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; -
19026e46883SJohn Baldwin */
19126e46883SJohn Baldwin
19226e46883SJohn Baldwin #define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
19326e46883SJohn Baldwin
19426e46883SJohn Baldwin int
sbni_probe(struct sbni_softc * sc)19526e46883SJohn Baldwin sbni_probe(struct sbni_softc *sc)
19626e46883SJohn Baldwin {
19726e46883SJohn Baldwin u_char csr0;
19826e46883SJohn Baldwin
19926e46883SJohn Baldwin csr0 = sbni_inb(sc, CSR0);
20026e46883SJohn Baldwin if (csr0 != 0xff && csr0 != 0x00) {
20126e46883SJohn Baldwin csr0 &= ~EN_INT;
20226e46883SJohn Baldwin if (csr0 & BU_EMP)
20326e46883SJohn Baldwin csr0 |= EN_INT;
20426e46883SJohn Baldwin
20526e46883SJohn Baldwin if (VALID_DECODER & (1 << (csr0 >> 4)))
20626e46883SJohn Baldwin return (0);
20726e46883SJohn Baldwin }
20826e46883SJohn Baldwin
20926e46883SJohn Baldwin return (ENXIO);
21026e46883SJohn Baldwin }
21126e46883SJohn Baldwin
21226e46883SJohn Baldwin /*
21326e46883SJohn Baldwin * Install interface into kernel networking data structures
21426e46883SJohn Baldwin */
215*aa386085SZhenlei Huang void
sbni_attach(struct sbni_softc * sc,int unit,struct sbni_flags flags)21626e46883SJohn Baldwin sbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags)
21726e46883SJohn Baldwin {
2183fba06adSJustin Hibbits if_t ifp;
21926e46883SJohn Baldwin u_char csr0;
2203fba06adSJustin Hibbits uint64_t baudrate;
22126e46883SJohn Baldwin
22226e46883SJohn Baldwin ifp = sc->ifp = if_alloc(IFT_ETHER);
22326e46883SJohn Baldwin sbni_outb(sc, CSR0, 0);
22426e46883SJohn Baldwin set_initial_values(sc, flags);
22526e46883SJohn Baldwin
22626e46883SJohn Baldwin /* Initialize ifnet structure */
2273fba06adSJustin Hibbits if_setsoftc(ifp, sc);
22826e46883SJohn Baldwin if_initname(ifp, "sbni", unit);
2293fba06adSJustin Hibbits if_setinitfn(ifp, sbni_init);
2303fba06adSJustin Hibbits if_setstartfn(ifp, sbni_start);
2313fba06adSJustin Hibbits if_setioctlfn(ifp, sbni_ioctl);
2323fba06adSJustin Hibbits if_setsendqlen(ifp, ifqmaxlen);
23326e46883SJohn Baldwin
23426e46883SJohn Baldwin /* report real baud rate */
23526e46883SJohn Baldwin csr0 = sbni_inb(sc, CSR0);
2363fba06adSJustin Hibbits baudrate = (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate);
23726e46883SJohn Baldwin
2383fba06adSJustin Hibbits if_setbaudrate(ifp, baudrate);
2393fba06adSJustin Hibbits if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
24026e46883SJohn Baldwin
2413fba06adSJustin Hibbits mtx_init(&sc->lock, if_name(ifp), MTX_NETWORK_LOCK, MTX_DEF);
24226e46883SJohn Baldwin callout_init_mtx(&sc->wch, &sc->lock, 0);
24326e46883SJohn Baldwin ether_ifattach(ifp, sc->enaddr);
24426e46883SJohn Baldwin /* device attach does transition from UNCONFIGURED to IDLE state */
24526e46883SJohn Baldwin
2463fba06adSJustin Hibbits if_printf(ifp, "speed %ju, rxl ", (uintmax_t)baudrate);
24726e46883SJohn Baldwin if (sc->delta_rxl)
24826e46883SJohn Baldwin printf("auto\n");
24926e46883SJohn Baldwin else
25026e46883SJohn Baldwin printf("%d (fixed)\n", sc->cur_rxl_index);
25126e46883SJohn Baldwin }
25226e46883SJohn Baldwin
25326e46883SJohn Baldwin void
sbni_detach(struct sbni_softc * sc)25426e46883SJohn Baldwin sbni_detach(struct sbni_softc *sc)
25526e46883SJohn Baldwin {
25626e46883SJohn Baldwin
25726e46883SJohn Baldwin SBNI_LOCK(sc);
25826e46883SJohn Baldwin sbni_stop(sc);
25926e46883SJohn Baldwin SBNI_UNLOCK(sc);
26026e46883SJohn Baldwin callout_drain(&sc->wch);
26126e46883SJohn Baldwin ether_ifdetach(sc->ifp);
26226e46883SJohn Baldwin if (sc->irq_handle)
26326e46883SJohn Baldwin bus_teardown_intr(sc->dev, sc->irq_res, sc->irq_handle);
26426e46883SJohn Baldwin mtx_destroy(&sc->lock);
26526e46883SJohn Baldwin if_free(sc->ifp);
26626e46883SJohn Baldwin }
26726e46883SJohn Baldwin
26826e46883SJohn Baldwin void
sbni_release_resources(struct sbni_softc * sc)26926e46883SJohn Baldwin sbni_release_resources(struct sbni_softc *sc)
27026e46883SJohn Baldwin {
27126e46883SJohn Baldwin
27226e46883SJohn Baldwin if (sc->irq_res)
27326e46883SJohn Baldwin bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
27426e46883SJohn Baldwin sc->irq_res);
27526e46883SJohn Baldwin if (sc->io_res && sc->io_off == 0)
27626e46883SJohn Baldwin bus_release_resource(sc->dev, SYS_RES_IOPORT, sc->io_rid,
27726e46883SJohn Baldwin sc->io_res);
27826e46883SJohn Baldwin }
27926e46883SJohn Baldwin
28026e46883SJohn Baldwin /* -------------------------------------------------------------------------- */
28126e46883SJohn Baldwin
28226e46883SJohn Baldwin static void
sbni_init(void * xsc)28326e46883SJohn Baldwin sbni_init(void *xsc)
28426e46883SJohn Baldwin {
28526e46883SJohn Baldwin struct sbni_softc *sc;
28626e46883SJohn Baldwin
28726e46883SJohn Baldwin sc = (struct sbni_softc *)xsc;
28826e46883SJohn Baldwin SBNI_LOCK(sc);
28926e46883SJohn Baldwin sbni_init_locked(sc);
29026e46883SJohn Baldwin SBNI_UNLOCK(sc);
29126e46883SJohn Baldwin }
29226e46883SJohn Baldwin
29326e46883SJohn Baldwin static void
sbni_init_locked(struct sbni_softc * sc)29426e46883SJohn Baldwin sbni_init_locked(struct sbni_softc *sc)
29526e46883SJohn Baldwin {
2963fba06adSJustin Hibbits if_t ifp;
29726e46883SJohn Baldwin
29826e46883SJohn Baldwin ifp = sc->ifp;
29926e46883SJohn Baldwin
30026e46883SJohn Baldwin /*
30126e46883SJohn Baldwin * kludge to avoid multiple initialization when more than once
30226e46883SJohn Baldwin * protocols configured
30326e46883SJohn Baldwin */
3043fba06adSJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
30526e46883SJohn Baldwin return;
30626e46883SJohn Baldwin
30726e46883SJohn Baldwin card_start(sc);
30826e46883SJohn Baldwin callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc);
30926e46883SJohn Baldwin
3103fba06adSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
3113fba06adSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
31226e46883SJohn Baldwin
31326e46883SJohn Baldwin /* attempt to start output */
31426e46883SJohn Baldwin sbni_start_locked(ifp);
31526e46883SJohn Baldwin }
31626e46883SJohn Baldwin
31726e46883SJohn Baldwin static void
sbni_start(if_t ifp)3183fba06adSJustin Hibbits sbni_start(if_t ifp)
31926e46883SJohn Baldwin {
3203fba06adSJustin Hibbits struct sbni_softc *sc = if_getsoftc(ifp);
32126e46883SJohn Baldwin
32226e46883SJohn Baldwin SBNI_LOCK(sc);
32326e46883SJohn Baldwin sbni_start_locked(ifp);
32426e46883SJohn Baldwin SBNI_UNLOCK(sc);
32526e46883SJohn Baldwin }
32626e46883SJohn Baldwin
32726e46883SJohn Baldwin static void
sbni_start_locked(if_t ifp)3283fba06adSJustin Hibbits sbni_start_locked(if_t ifp)
32926e46883SJohn Baldwin {
3303fba06adSJustin Hibbits struct sbni_softc *sc = if_getsoftc(ifp);
33126e46883SJohn Baldwin
33226e46883SJohn Baldwin if (sc->tx_frameno == 0)
33326e46883SJohn Baldwin prepare_to_send(sc);
33426e46883SJohn Baldwin }
33526e46883SJohn Baldwin
33626e46883SJohn Baldwin static void
sbni_stop(struct sbni_softc * sc)33726e46883SJohn Baldwin sbni_stop(struct sbni_softc *sc)
33826e46883SJohn Baldwin {
33926e46883SJohn Baldwin sbni_outb(sc, CSR0, 0);
34026e46883SJohn Baldwin drop_xmit_queue(sc);
34126e46883SJohn Baldwin
34226e46883SJohn Baldwin if (sc->rx_buf_p) {
34326e46883SJohn Baldwin m_freem(sc->rx_buf_p);
34426e46883SJohn Baldwin sc->rx_buf_p = NULL;
34526e46883SJohn Baldwin }
34626e46883SJohn Baldwin
34726e46883SJohn Baldwin callout_stop(&sc->wch);
3483fba06adSJustin Hibbits if_setdrvflagbits(sc->ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
34926e46883SJohn Baldwin }
35026e46883SJohn Baldwin
35126e46883SJohn Baldwin /* -------------------------------------------------------------------------- */
35226e46883SJohn Baldwin
35326e46883SJohn Baldwin /* interrupt handler */
35426e46883SJohn Baldwin
35526e46883SJohn Baldwin /*
35626e46883SJohn Baldwin * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not
35726e46883SJohn Baldwin * be looked as two independent single-channel devices. Every channel seems
35826e46883SJohn Baldwin * as Ethernet interface but interrupt handler must be common. Really, first
35926e46883SJohn Baldwin * channel ("master") driver only registers the handler. In it's struct softc
36026e46883SJohn Baldwin * it has got pointer to "slave" channel's struct softc and handles that's
36126e46883SJohn Baldwin * interrupts too.
36226e46883SJohn Baldwin * softc of successfully attached ISA SBNI boards is linked to list.
36326e46883SJohn Baldwin * While next board driver is initialized, it scans this list. If one
36426e46883SJohn Baldwin * has found softc with same irq and ioaddr different by 4 then it assumes
36526e46883SJohn Baldwin * this board to be "master".
36626e46883SJohn Baldwin */
36726e46883SJohn Baldwin
36826e46883SJohn Baldwin void
sbni_intr(void * arg)36926e46883SJohn Baldwin sbni_intr(void *arg)
37026e46883SJohn Baldwin {
37126e46883SJohn Baldwin struct sbni_softc *sc;
37226e46883SJohn Baldwin int repeat;
37326e46883SJohn Baldwin
37426e46883SJohn Baldwin sc = (struct sbni_softc *)arg;
37526e46883SJohn Baldwin
37626e46883SJohn Baldwin do {
37726e46883SJohn Baldwin repeat = 0;
37826e46883SJohn Baldwin SBNI_LOCK(sc);
37926e46883SJohn Baldwin if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) {
38026e46883SJohn Baldwin handle_channel(sc);
38126e46883SJohn Baldwin repeat = 1;
38226e46883SJohn Baldwin }
38326e46883SJohn Baldwin SBNI_UNLOCK(sc);
38426e46883SJohn Baldwin if (sc->slave_sc) {
38526e46883SJohn Baldwin /* second channel present */
38626e46883SJohn Baldwin SBNI_LOCK(sc->slave_sc);
38726e46883SJohn Baldwin if (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY)) {
38826e46883SJohn Baldwin handle_channel(sc->slave_sc);
38926e46883SJohn Baldwin repeat = 1;
39026e46883SJohn Baldwin }
39126e46883SJohn Baldwin SBNI_UNLOCK(sc->slave_sc);
39226e46883SJohn Baldwin }
39326e46883SJohn Baldwin } while (repeat);
39426e46883SJohn Baldwin }
39526e46883SJohn Baldwin
39626e46883SJohn Baldwin static void
handle_channel(struct sbni_softc * sc)39726e46883SJohn Baldwin handle_channel(struct sbni_softc *sc)
39826e46883SJohn Baldwin {
39926e46883SJohn Baldwin int req_ans;
40026e46883SJohn Baldwin u_char csr0;
40126e46883SJohn Baldwin
40226e46883SJohn Baldwin sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ);
40326e46883SJohn Baldwin
40426e46883SJohn Baldwin sc->timer_ticks = CHANGE_LEVEL_START_TICKS;
40526e46883SJohn Baldwin for (;;) {
40626e46883SJohn Baldwin csr0 = sbni_inb(sc, CSR0);
40726e46883SJohn Baldwin if ((csr0 & (RC_RDY | TR_RDY)) == 0)
40826e46883SJohn Baldwin break;
40926e46883SJohn Baldwin
41026e46883SJohn Baldwin req_ans = !(sc->state & FL_PREV_OK);
41126e46883SJohn Baldwin
41226e46883SJohn Baldwin if (csr0 & RC_RDY)
41326e46883SJohn Baldwin req_ans = recv_frame(sc);
41426e46883SJohn Baldwin
41526e46883SJohn Baldwin /*
41626e46883SJohn Baldwin * TR_RDY always equals 1 here because we have owned the marker,
41726e46883SJohn Baldwin * and we set TR_REQ when disabled interrupts
41826e46883SJohn Baldwin */
41926e46883SJohn Baldwin csr0 = sbni_inb(sc, CSR0);
42026e46883SJohn Baldwin if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0)
42126e46883SJohn Baldwin if_printf(sc->ifp, "internal error!\n");
42226e46883SJohn Baldwin
42326e46883SJohn Baldwin /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */
42426e46883SJohn Baldwin if (req_ans || sc->tx_frameno != 0)
42526e46883SJohn Baldwin send_frame(sc);
42626e46883SJohn Baldwin else {
42726e46883SJohn Baldwin /* send the marker without any data */
42826e46883SJohn Baldwin sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ);
42926e46883SJohn Baldwin }
43026e46883SJohn Baldwin }
43126e46883SJohn Baldwin
43226e46883SJohn Baldwin sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT);
43326e46883SJohn Baldwin }
43426e46883SJohn Baldwin
43526e46883SJohn Baldwin /*
43626e46883SJohn Baldwin * Routine returns 1 if it need to acknoweledge received frame.
43726e46883SJohn Baldwin * Empty frame received without errors won't be acknoweledged.
43826e46883SJohn Baldwin */
43926e46883SJohn Baldwin
44026e46883SJohn Baldwin static int
recv_frame(struct sbni_softc * sc)44126e46883SJohn Baldwin recv_frame(struct sbni_softc *sc)
44226e46883SJohn Baldwin {
44326e46883SJohn Baldwin u_int32_t crc;
44426e46883SJohn Baldwin u_int framelen, frameno, ack;
44526e46883SJohn Baldwin u_int is_first, frame_ok;
44626e46883SJohn Baldwin
44726e46883SJohn Baldwin crc = CRC32_INITIAL;
44826e46883SJohn Baldwin if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) {
44926e46883SJohn Baldwin frame_ok = framelen > 4 ?
45026e46883SJohn Baldwin upload_data(sc, framelen, frameno, is_first, crc) :
45126e46883SJohn Baldwin skip_tail(sc, framelen, crc);
45226e46883SJohn Baldwin if (frame_ok)
45326e46883SJohn Baldwin interpret_ack(sc, ack);
45426e46883SJohn Baldwin } else {
45526e46883SJohn Baldwin framelen = 0;
45626e46883SJohn Baldwin frame_ok = 0;
45726e46883SJohn Baldwin }
45826e46883SJohn Baldwin
45926e46883SJohn Baldwin sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER);
46026e46883SJohn Baldwin if (frame_ok) {
46126e46883SJohn Baldwin sc->state |= FL_PREV_OK;
46226e46883SJohn Baldwin if (framelen > 4)
46326e46883SJohn Baldwin sc->in_stats.all_rx_number++;
46426e46883SJohn Baldwin } else {
46526e46883SJohn Baldwin sc->state &= ~FL_PREV_OK;
46626e46883SJohn Baldwin change_level(sc);
46726e46883SJohn Baldwin sc->in_stats.all_rx_number++;
46826e46883SJohn Baldwin sc->in_stats.bad_rx_number++;
46926e46883SJohn Baldwin }
47026e46883SJohn Baldwin
47126e46883SJohn Baldwin return (!frame_ok || framelen > 4);
47226e46883SJohn Baldwin }
47326e46883SJohn Baldwin
47426e46883SJohn Baldwin static void
send_frame(struct sbni_softc * sc)47526e46883SJohn Baldwin send_frame(struct sbni_softc *sc)
47626e46883SJohn Baldwin {
47726e46883SJohn Baldwin u_int32_t crc;
47826e46883SJohn Baldwin u_char csr0;
47926e46883SJohn Baldwin
48026e46883SJohn Baldwin crc = CRC32_INITIAL;
48126e46883SJohn Baldwin if (sc->state & FL_NEED_RESEND) {
48226e46883SJohn Baldwin /* if frame was sended but not ACK'ed - resend it */
48326e46883SJohn Baldwin if (sc->trans_errors) {
48426e46883SJohn Baldwin sc->trans_errors--;
48526e46883SJohn Baldwin if (sc->framelen != 0)
48626e46883SJohn Baldwin sc->in_stats.resend_tx_number++;
48726e46883SJohn Baldwin } else {
48826e46883SJohn Baldwin /* cannot xmit with many attempts */
48926e46883SJohn Baldwin drop_xmit_queue(sc);
49026e46883SJohn Baldwin goto do_send;
49126e46883SJohn Baldwin }
49226e46883SJohn Baldwin } else
49326e46883SJohn Baldwin sc->trans_errors = TR_ERROR_COUNT;
49426e46883SJohn Baldwin
49526e46883SJohn Baldwin send_frame_header(sc, &crc);
49626e46883SJohn Baldwin sc->state |= FL_NEED_RESEND;
49726e46883SJohn Baldwin /*
49826e46883SJohn Baldwin * FL_NEED_RESEND will be cleared after ACK, but if empty
49926e46883SJohn Baldwin * frame sended then in prepare_to_send next frame
50026e46883SJohn Baldwin */
50126e46883SJohn Baldwin
50226e46883SJohn Baldwin if (sc->framelen) {
50326e46883SJohn Baldwin download_data(sc, &crc);
50426e46883SJohn Baldwin sc->in_stats.all_tx_number++;
50526e46883SJohn Baldwin sc->state |= FL_WAIT_ACK;
50626e46883SJohn Baldwin }
50726e46883SJohn Baldwin
50826e46883SJohn Baldwin sbni_outsb(sc, (u_char *)&crc, sizeof crc);
50926e46883SJohn Baldwin
51026e46883SJohn Baldwin do_send:
51126e46883SJohn Baldwin csr0 = sbni_inb(sc, CSR0);
51226e46883SJohn Baldwin sbni_outb(sc, CSR0, csr0 & ~TR_REQ);
51326e46883SJohn Baldwin
51426e46883SJohn Baldwin if (sc->tx_frameno) {
51526e46883SJohn Baldwin /* next frame exists - request to send */
51626e46883SJohn Baldwin sbni_outb(sc, CSR0, csr0 | TR_REQ);
51726e46883SJohn Baldwin }
51826e46883SJohn Baldwin }
51926e46883SJohn Baldwin
52026e46883SJohn Baldwin static void
download_data(struct sbni_softc * sc,u_int32_t * crc_p)52126e46883SJohn Baldwin download_data(struct sbni_softc *sc, u_int32_t *crc_p)
52226e46883SJohn Baldwin {
52326e46883SJohn Baldwin struct mbuf *m;
52426e46883SJohn Baldwin caddr_t data_p;
52526e46883SJohn Baldwin u_int data_len, pos, slice;
52626e46883SJohn Baldwin
52726e46883SJohn Baldwin data_p = NULL; /* initialized to avoid warn */
52826e46883SJohn Baldwin pos = 0;
52926e46883SJohn Baldwin
53026e46883SJohn Baldwin for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) {
53126e46883SJohn Baldwin if (pos + m->m_len > sc->outpos) {
53226e46883SJohn Baldwin data_len = m->m_len - (sc->outpos - pos);
53326e46883SJohn Baldwin data_p = mtod(m, caddr_t) + (sc->outpos - pos);
53426e46883SJohn Baldwin
53526e46883SJohn Baldwin goto do_copy;
53626e46883SJohn Baldwin } else
53726e46883SJohn Baldwin pos += m->m_len;
53826e46883SJohn Baldwin }
53926e46883SJohn Baldwin
54026e46883SJohn Baldwin data_len = 0;
54126e46883SJohn Baldwin
54226e46883SJohn Baldwin do_copy:
54326e46883SJohn Baldwin pos = 0;
54426e46883SJohn Baldwin do {
54526e46883SJohn Baldwin if (data_len) {
54626e46883SJohn Baldwin slice = min(data_len, sc->framelen - pos);
54726e46883SJohn Baldwin sbni_outsb(sc, data_p, slice);
54826e46883SJohn Baldwin *crc_p = calc_crc32(*crc_p, data_p, slice);
54926e46883SJohn Baldwin
55026e46883SJohn Baldwin pos += slice;
55126e46883SJohn Baldwin if (data_len -= slice)
55226e46883SJohn Baldwin data_p += slice;
55326e46883SJohn Baldwin else {
55426e46883SJohn Baldwin do {
55526e46883SJohn Baldwin m = m->m_next;
55626e46883SJohn Baldwin } while (m != NULL && m->m_len == 0);
55726e46883SJohn Baldwin
55826e46883SJohn Baldwin if (m) {
55926e46883SJohn Baldwin data_len = m->m_len;
56026e46883SJohn Baldwin data_p = mtod(m, caddr_t);
56126e46883SJohn Baldwin }
56226e46883SJohn Baldwin }
56326e46883SJohn Baldwin } else {
56426e46883SJohn Baldwin /* frame too short - zero padding */
56526e46883SJohn Baldwin
56626e46883SJohn Baldwin pos = sc->framelen - pos;
56726e46883SJohn Baldwin while (pos--) {
56826e46883SJohn Baldwin sbni_outb(sc, DAT, 0);
56926e46883SJohn Baldwin *crc_p = CRC32(0, *crc_p);
57026e46883SJohn Baldwin }
57126e46883SJohn Baldwin return;
57226e46883SJohn Baldwin }
57326e46883SJohn Baldwin } while (pos < sc->framelen);
57426e46883SJohn Baldwin }
57526e46883SJohn Baldwin
57626e46883SJohn Baldwin static int
upload_data(struct sbni_softc * sc,u_int framelen,u_int frameno,u_int is_first,u_int32_t crc)57726e46883SJohn Baldwin upload_data(struct sbni_softc *sc, u_int framelen, u_int frameno,
57826e46883SJohn Baldwin u_int is_first, u_int32_t crc)
57926e46883SJohn Baldwin {
58026e46883SJohn Baldwin int frame_ok;
58126e46883SJohn Baldwin
58226e46883SJohn Baldwin if (is_first) {
58326e46883SJohn Baldwin sc->wait_frameno = frameno;
58426e46883SJohn Baldwin sc->inppos = 0;
58526e46883SJohn Baldwin }
58626e46883SJohn Baldwin
58726e46883SJohn Baldwin if (sc->wait_frameno == frameno) {
58826e46883SJohn Baldwin if (sc->inppos + framelen <= ETHER_MAX_LEN) {
58926e46883SJohn Baldwin frame_ok = append_frame_to_pkt(sc, framelen, crc);
59026e46883SJohn Baldwin
59126e46883SJohn Baldwin /*
59226e46883SJohn Baldwin * if CRC is right but framelen incorrect then transmitter
593453130d9SPedro F. Giffuni * error was occurred... drop entire packet
59426e46883SJohn Baldwin */
59526e46883SJohn Baldwin } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) {
59626e46883SJohn Baldwin sc->wait_frameno = 0;
59726e46883SJohn Baldwin sc->inppos = 0;
598c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
59926e46883SJohn Baldwin /* now skip all frames until is_first != 0 */
60026e46883SJohn Baldwin }
60126e46883SJohn Baldwin } else
60226e46883SJohn Baldwin frame_ok = skip_tail(sc, framelen, crc);
60326e46883SJohn Baldwin
60426e46883SJohn Baldwin if (is_first && !frame_ok) {
60526e46883SJohn Baldwin /*
60626e46883SJohn Baldwin * Frame has been violated, but we have stored
60726e46883SJohn Baldwin * is_first already... Drop entire packet.
60826e46883SJohn Baldwin */
60926e46883SJohn Baldwin sc->wait_frameno = 0;
610c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_IERRORS, 1);
61126e46883SJohn Baldwin }
61226e46883SJohn Baldwin
61326e46883SJohn Baldwin return (frame_ok);
61426e46883SJohn Baldwin }
61526e46883SJohn Baldwin
61626e46883SJohn Baldwin static __inline void send_complete(struct sbni_softc *);
61726e46883SJohn Baldwin
61826e46883SJohn Baldwin static __inline void
send_complete(struct sbni_softc * sc)61926e46883SJohn Baldwin send_complete(struct sbni_softc *sc)
62026e46883SJohn Baldwin {
62126e46883SJohn Baldwin m_freem(sc->tx_buf_p);
62226e46883SJohn Baldwin sc->tx_buf_p = NULL;
623c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_OPACKETS, 1);
62426e46883SJohn Baldwin }
62526e46883SJohn Baldwin
62626e46883SJohn Baldwin static void
interpret_ack(struct sbni_softc * sc,u_int ack)62726e46883SJohn Baldwin interpret_ack(struct sbni_softc *sc, u_int ack)
62826e46883SJohn Baldwin {
62926e46883SJohn Baldwin if (ack == FRAME_SENT_OK) {
63026e46883SJohn Baldwin sc->state &= ~FL_NEED_RESEND;
63126e46883SJohn Baldwin
63226e46883SJohn Baldwin if (sc->state & FL_WAIT_ACK) {
63326e46883SJohn Baldwin sc->outpos += sc->framelen;
63426e46883SJohn Baldwin
63526e46883SJohn Baldwin if (--sc->tx_frameno) {
63626e46883SJohn Baldwin sc->framelen = min(
63726e46883SJohn Baldwin sc->maxframe, sc->pktlen - sc->outpos);
63826e46883SJohn Baldwin } else {
63926e46883SJohn Baldwin send_complete(sc);
64026e46883SJohn Baldwin prepare_to_send(sc);
64126e46883SJohn Baldwin }
64226e46883SJohn Baldwin }
64326e46883SJohn Baldwin }
64426e46883SJohn Baldwin
64526e46883SJohn Baldwin sc->state &= ~FL_WAIT_ACK;
64626e46883SJohn Baldwin }
64726e46883SJohn Baldwin
64826e46883SJohn Baldwin /*
64926e46883SJohn Baldwin * Glue received frame with previous fragments of packet.
65026e46883SJohn Baldwin * Indicate packet when last frame would be accepted.
65126e46883SJohn Baldwin */
65226e46883SJohn Baldwin
65326e46883SJohn Baldwin static int
append_frame_to_pkt(struct sbni_softc * sc,u_int framelen,u_int32_t crc)65426e46883SJohn Baldwin append_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc)
65526e46883SJohn Baldwin {
65626e46883SJohn Baldwin caddr_t p;
65726e46883SJohn Baldwin
65826e46883SJohn Baldwin if (sc->inppos + framelen > ETHER_MAX_LEN)
65926e46883SJohn Baldwin return (0);
66026e46883SJohn Baldwin
66126e46883SJohn Baldwin if (!sc->rx_buf_p && !get_rx_buf(sc))
66226e46883SJohn Baldwin return (0);
66326e46883SJohn Baldwin
66426e46883SJohn Baldwin p = sc->rx_buf_p->m_data + sc->inppos;
66526e46883SJohn Baldwin sbni_insb(sc, p, framelen);
66626e46883SJohn Baldwin if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER)
66726e46883SJohn Baldwin return (0);
66826e46883SJohn Baldwin
66926e46883SJohn Baldwin sc->inppos += framelen - 4;
67026e46883SJohn Baldwin if (--sc->wait_frameno == 0) { /* last frame received */
67126e46883SJohn Baldwin indicate_pkt(sc);
672c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_IPACKETS, 1);
67326e46883SJohn Baldwin }
67426e46883SJohn Baldwin
67526e46883SJohn Baldwin return (1);
67626e46883SJohn Baldwin }
67726e46883SJohn Baldwin
67826e46883SJohn Baldwin /*
67926e46883SJohn Baldwin * Prepare to start output on adapter. Current priority must be set to splimp
68026e46883SJohn Baldwin * before this routine is called.
68126e46883SJohn Baldwin * Transmitter will be actually activated when marker has been accepted.
68226e46883SJohn Baldwin */
68326e46883SJohn Baldwin
68426e46883SJohn Baldwin static void
prepare_to_send(struct sbni_softc * sc)68526e46883SJohn Baldwin prepare_to_send(struct sbni_softc *sc)
68626e46883SJohn Baldwin {
68726e46883SJohn Baldwin struct mbuf *m;
68826e46883SJohn Baldwin u_int len;
68926e46883SJohn Baldwin
69026e46883SJohn Baldwin /* sc->tx_buf_p == NULL here! */
69126e46883SJohn Baldwin if (sc->tx_buf_p)
69226e46883SJohn Baldwin printf("sbni: memory leak!\n");
69326e46883SJohn Baldwin
69426e46883SJohn Baldwin sc->outpos = 0;
69526e46883SJohn Baldwin sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
69626e46883SJohn Baldwin
69726e46883SJohn Baldwin for (;;) {
6983fba06adSJustin Hibbits sc->tx_buf_p = if_dequeue(sc->ifp);
69926e46883SJohn Baldwin if (!sc->tx_buf_p) {
70026e46883SJohn Baldwin /* nothing to transmit... */
70126e46883SJohn Baldwin sc->pktlen = 0;
70226e46883SJohn Baldwin sc->tx_frameno = 0;
70326e46883SJohn Baldwin sc->framelen = 0;
7043fba06adSJustin Hibbits if_setdrvflagbits(sc->ifp, 0, IFF_DRV_OACTIVE);
70526e46883SJohn Baldwin return;
70626e46883SJohn Baldwin }
70726e46883SJohn Baldwin
70826e46883SJohn Baldwin for (len = 0, m = sc->tx_buf_p; m; m = m->m_next)
70926e46883SJohn Baldwin len += m->m_len;
71026e46883SJohn Baldwin
71126e46883SJohn Baldwin if (len != 0)
71226e46883SJohn Baldwin break;
71326e46883SJohn Baldwin m_freem(sc->tx_buf_p);
71426e46883SJohn Baldwin }
71526e46883SJohn Baldwin
71626e46883SJohn Baldwin if (len < SBNI_MIN_LEN)
71726e46883SJohn Baldwin len = SBNI_MIN_LEN;
71826e46883SJohn Baldwin
71926e46883SJohn Baldwin sc->pktlen = len;
720057b4402SPedro F. Giffuni sc->tx_frameno = howmany(len, sc->maxframe);
72126e46883SJohn Baldwin sc->framelen = min(len, sc->maxframe);
72226e46883SJohn Baldwin
72326e46883SJohn Baldwin sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ);
7243fba06adSJustin Hibbits if_setdrvflagbits(sc->ifp, IFF_DRV_OACTIVE, 0);
72526e46883SJohn Baldwin BPF_MTAP(sc->ifp, sc->tx_buf_p);
72626e46883SJohn Baldwin }
72726e46883SJohn Baldwin
72826e46883SJohn Baldwin static void
drop_xmit_queue(struct sbni_softc * sc)72926e46883SJohn Baldwin drop_xmit_queue(struct sbni_softc *sc)
73026e46883SJohn Baldwin {
73126e46883SJohn Baldwin struct mbuf *m;
73226e46883SJohn Baldwin
73326e46883SJohn Baldwin if (sc->tx_buf_p) {
73426e46883SJohn Baldwin m_freem(sc->tx_buf_p);
73526e46883SJohn Baldwin sc->tx_buf_p = NULL;
736c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1);
73726e46883SJohn Baldwin }
73826e46883SJohn Baldwin
73926e46883SJohn Baldwin for (;;) {
7403fba06adSJustin Hibbits m = if_dequeue(sc->ifp);
74126e46883SJohn Baldwin if (m == NULL)
74226e46883SJohn Baldwin break;
74326e46883SJohn Baldwin m_freem(m);
744c8dfaf38SGleb Smirnoff if_inc_counter(sc->ifp, IFCOUNTER_OERRORS, 1);
74526e46883SJohn Baldwin }
74626e46883SJohn Baldwin
74726e46883SJohn Baldwin sc->tx_frameno = 0;
74826e46883SJohn Baldwin sc->framelen = 0;
74926e46883SJohn Baldwin sc->outpos = 0;
75026e46883SJohn Baldwin sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
7513fba06adSJustin Hibbits if_setdrvflagbits(sc->ifp, 0, IFF_DRV_OACTIVE);
75226e46883SJohn Baldwin }
75326e46883SJohn Baldwin
75426e46883SJohn Baldwin static void
send_frame_header(struct sbni_softc * sc,u_int32_t * crc_p)75526e46883SJohn Baldwin send_frame_header(struct sbni_softc *sc, u_int32_t *crc_p)
75626e46883SJohn Baldwin {
75726e46883SJohn Baldwin u_int32_t crc;
75826e46883SJohn Baldwin u_int len_field;
75926e46883SJohn Baldwin u_char value;
76026e46883SJohn Baldwin
76126e46883SJohn Baldwin crc = *crc_p;
76226e46883SJohn Baldwin len_field = sc->framelen + 6; /* CRC + frameno + reserved */
76326e46883SJohn Baldwin
76426e46883SJohn Baldwin if (sc->state & FL_NEED_RESEND)
76526e46883SJohn Baldwin len_field |= FRAME_RETRY; /* non-first attempt... */
76626e46883SJohn Baldwin
76726e46883SJohn Baldwin if (sc->outpos == 0)
76826e46883SJohn Baldwin len_field |= FRAME_FIRST;
76926e46883SJohn Baldwin
77026e46883SJohn Baldwin len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD;
77126e46883SJohn Baldwin sbni_outb(sc, DAT, SBNI_SIG);
77226e46883SJohn Baldwin
77326e46883SJohn Baldwin value = (u_char)len_field;
77426e46883SJohn Baldwin sbni_outb(sc, DAT, value);
77526e46883SJohn Baldwin crc = CRC32(value, crc);
77626e46883SJohn Baldwin value = (u_char)(len_field >> 8);
77726e46883SJohn Baldwin sbni_outb(sc, DAT, value);
77826e46883SJohn Baldwin crc = CRC32(value, crc);
77926e46883SJohn Baldwin
78026e46883SJohn Baldwin sbni_outb(sc, DAT, sc->tx_frameno);
78126e46883SJohn Baldwin crc = CRC32(sc->tx_frameno, crc);
78226e46883SJohn Baldwin sbni_outb(sc, DAT, 0);
78326e46883SJohn Baldwin crc = CRC32(0, crc);
78426e46883SJohn Baldwin *crc_p = crc;
78526e46883SJohn Baldwin }
78626e46883SJohn Baldwin
78726e46883SJohn Baldwin /*
78826e46883SJohn Baldwin * if frame tail not needed (incorrect number or received twice),
78926e46883SJohn Baldwin * it won't store, but CRC will be calculated
79026e46883SJohn Baldwin */
79126e46883SJohn Baldwin
79226e46883SJohn Baldwin static int
skip_tail(struct sbni_softc * sc,u_int tail_len,u_int32_t crc)79326e46883SJohn Baldwin skip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc)
79426e46883SJohn Baldwin {
79526e46883SJohn Baldwin while (tail_len--)
79626e46883SJohn Baldwin crc = CRC32(sbni_inb(sc, DAT), crc);
79726e46883SJohn Baldwin
79826e46883SJohn Baldwin return (crc == CRC32_REMAINDER);
79926e46883SJohn Baldwin }
80026e46883SJohn Baldwin
80126e46883SJohn Baldwin static int
check_fhdr(struct sbni_softc * sc,u_int * framelen,u_int * frameno,u_int * ack,u_int * is_first,u_int32_t * crc_p)80226e46883SJohn Baldwin check_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno,
80326e46883SJohn Baldwin u_int *ack, u_int *is_first, u_int32_t *crc_p)
80426e46883SJohn Baldwin {
80526e46883SJohn Baldwin u_int32_t crc;
80626e46883SJohn Baldwin u_char value;
80726e46883SJohn Baldwin
80826e46883SJohn Baldwin crc = *crc_p;
80926e46883SJohn Baldwin if (sbni_inb(sc, DAT) != SBNI_SIG)
81026e46883SJohn Baldwin return (0);
81126e46883SJohn Baldwin
81226e46883SJohn Baldwin value = sbni_inb(sc, DAT);
81326e46883SJohn Baldwin *framelen = (u_int)value;
81426e46883SJohn Baldwin crc = CRC32(value, crc);
81526e46883SJohn Baldwin value = sbni_inb(sc, DAT);
81626e46883SJohn Baldwin *framelen |= ((u_int)value) << 8;
81726e46883SJohn Baldwin crc = CRC32(value, crc);
81826e46883SJohn Baldwin
81926e46883SJohn Baldwin *ack = *framelen & FRAME_ACK_MASK;
82026e46883SJohn Baldwin *is_first = (*framelen & FRAME_FIRST) != 0;
82126e46883SJohn Baldwin
82226e46883SJohn Baldwin if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3)
82326e46883SJohn Baldwin return (0);
82426e46883SJohn Baldwin
82526e46883SJohn Baldwin value = sbni_inb(sc, DAT);
82626e46883SJohn Baldwin *frameno = (u_int)value;
82726e46883SJohn Baldwin crc = CRC32(value, crc);
82826e46883SJohn Baldwin
82926e46883SJohn Baldwin crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */
83026e46883SJohn Baldwin *framelen -= 2;
83126e46883SJohn Baldwin
83226e46883SJohn Baldwin *crc_p = crc;
83326e46883SJohn Baldwin return (1);
83426e46883SJohn Baldwin }
83526e46883SJohn Baldwin
83626e46883SJohn Baldwin static int
get_rx_buf(struct sbni_softc * sc)83726e46883SJohn Baldwin get_rx_buf(struct sbni_softc *sc)
83826e46883SJohn Baldwin {
83926e46883SJohn Baldwin struct mbuf *m;
84026e46883SJohn Baldwin
841c6499eccSGleb Smirnoff MGETHDR(m, M_NOWAIT, MT_DATA);
84226e46883SJohn Baldwin if (m == NULL) {
84326e46883SJohn Baldwin if_printf(sc->ifp, "cannot allocate header mbuf\n");
84426e46883SJohn Baldwin return (0);
84526e46883SJohn Baldwin }
84626e46883SJohn Baldwin
84726e46883SJohn Baldwin /*
84826e46883SJohn Baldwin * We always put the received packet in a single buffer -
84926e46883SJohn Baldwin * either with just an mbuf header or in a cluster attached
85026e46883SJohn Baldwin * to the header. The +2 is to compensate for the alignment
85126e46883SJohn Baldwin * fixup below.
85226e46883SJohn Baldwin */
85326e46883SJohn Baldwin if (ETHER_MAX_LEN + 2 > MHLEN) {
85426e46883SJohn Baldwin /* Attach an mbuf cluster */
8552a8c860fSRobert Watson if (!(MCLGET(m, M_NOWAIT))) {
85626e46883SJohn Baldwin m_freem(m);
85726e46883SJohn Baldwin return (0);
85826e46883SJohn Baldwin }
85926e46883SJohn Baldwin }
86026e46883SJohn Baldwin m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2;
86126e46883SJohn Baldwin
86226e46883SJohn Baldwin /*
86326e46883SJohn Baldwin * The +2 is to longword align the start of the real packet.
86426e46883SJohn Baldwin * (sizeof ether_header == 14)
86526e46883SJohn Baldwin * This is important for NFS.
86626e46883SJohn Baldwin */
86726e46883SJohn Baldwin m_adj(m, 2);
86826e46883SJohn Baldwin sc->rx_buf_p = m;
86926e46883SJohn Baldwin return (1);
87026e46883SJohn Baldwin }
87126e46883SJohn Baldwin
87226e46883SJohn Baldwin static void
indicate_pkt(struct sbni_softc * sc)87326e46883SJohn Baldwin indicate_pkt(struct sbni_softc *sc)
87426e46883SJohn Baldwin {
8753fba06adSJustin Hibbits if_t ifp = sc->ifp;
87626e46883SJohn Baldwin struct mbuf *m;
87726e46883SJohn Baldwin
87826e46883SJohn Baldwin m = sc->rx_buf_p;
87926e46883SJohn Baldwin m->m_pkthdr.rcvif = ifp;
88026e46883SJohn Baldwin m->m_pkthdr.len = m->m_len = sc->inppos;
88126e46883SJohn Baldwin sc->rx_buf_p = NULL;
88226e46883SJohn Baldwin
88326e46883SJohn Baldwin SBNI_UNLOCK(sc);
8843fba06adSJustin Hibbits if_input(ifp, m);
88526e46883SJohn Baldwin SBNI_LOCK(sc);
88626e46883SJohn Baldwin }
88726e46883SJohn Baldwin
88826e46883SJohn Baldwin /* -------------------------------------------------------------------------- */
88926e46883SJohn Baldwin
89026e46883SJohn Baldwin /*
89126e46883SJohn Baldwin * Routine checks periodically wire activity and regenerates marker if
89226e46883SJohn Baldwin * connect was inactive for a long time.
89326e46883SJohn Baldwin */
89426e46883SJohn Baldwin
89526e46883SJohn Baldwin static void
sbni_timeout(void * xsc)89626e46883SJohn Baldwin sbni_timeout(void *xsc)
89726e46883SJohn Baldwin {
89826e46883SJohn Baldwin struct sbni_softc *sc;
89926e46883SJohn Baldwin u_char csr0;
90026e46883SJohn Baldwin
90126e46883SJohn Baldwin sc = (struct sbni_softc *)xsc;
90226e46883SJohn Baldwin SBNI_ASSERT_LOCKED(sc);
90326e46883SJohn Baldwin
90426e46883SJohn Baldwin csr0 = sbni_inb(sc, CSR0);
90526e46883SJohn Baldwin if (csr0 & RC_CHK) {
90626e46883SJohn Baldwin if (sc->timer_ticks) {
90726e46883SJohn Baldwin if (csr0 & (RC_RDY | BU_EMP))
90826e46883SJohn Baldwin /* receiving not active */
90926e46883SJohn Baldwin sc->timer_ticks--;
91026e46883SJohn Baldwin } else {
91126e46883SJohn Baldwin sc->in_stats.timeout_number++;
91226e46883SJohn Baldwin if (sc->delta_rxl)
91326e46883SJohn Baldwin timeout_change_level(sc);
91426e46883SJohn Baldwin
91526e46883SJohn Baldwin sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES);
91626e46883SJohn Baldwin csr0 = sbni_inb(sc, CSR0);
91726e46883SJohn Baldwin }
91826e46883SJohn Baldwin }
91926e46883SJohn Baldwin
92026e46883SJohn Baldwin sbni_outb(sc, CSR0, csr0 | RC_CHK);
92126e46883SJohn Baldwin callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc);
92226e46883SJohn Baldwin }
92326e46883SJohn Baldwin
92426e46883SJohn Baldwin /* -------------------------------------------------------------------------- */
92526e46883SJohn Baldwin
92626e46883SJohn Baldwin static void
card_start(struct sbni_softc * sc)92726e46883SJohn Baldwin card_start(struct sbni_softc *sc)
92826e46883SJohn Baldwin {
92926e46883SJohn Baldwin sc->timer_ticks = CHANGE_LEVEL_START_TICKS;
93026e46883SJohn Baldwin sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
93126e46883SJohn Baldwin sc->state |= FL_PREV_OK;
93226e46883SJohn Baldwin
93326e46883SJohn Baldwin sc->inppos = 0;
93426e46883SJohn Baldwin sc->wait_frameno = 0;
93526e46883SJohn Baldwin
93626e46883SJohn Baldwin sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES);
93726e46883SJohn Baldwin sbni_outb(sc, CSR0, EN_INT);
93826e46883SJohn Baldwin }
93926e46883SJohn Baldwin
94026e46883SJohn Baldwin /* -------------------------------------------------------------------------- */
94126e46883SJohn Baldwin
94226e46883SJohn Baldwin static u_char rxl_tab[] = {
94326e46883SJohn Baldwin 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
94426e46883SJohn Baldwin 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
94526e46883SJohn Baldwin };
94626e46883SJohn Baldwin
94726e46883SJohn Baldwin #define SIZE_OF_TIMEOUT_RXL_TAB 4
94826e46883SJohn Baldwin static u_char timeout_rxl_tab[] = {
94926e46883SJohn Baldwin 0x03, 0x05, 0x08, 0x0b
95026e46883SJohn Baldwin };
95126e46883SJohn Baldwin
95226e46883SJohn Baldwin static void
set_initial_values(struct sbni_softc * sc,struct sbni_flags flags)95326e46883SJohn Baldwin set_initial_values(struct sbni_softc *sc, struct sbni_flags flags)
95426e46883SJohn Baldwin {
95526e46883SJohn Baldwin if (flags.fixed_rxl) {
95626e46883SJohn Baldwin sc->delta_rxl = 0; /* disable receive level autodetection */
95726e46883SJohn Baldwin sc->cur_rxl_index = flags.rxl;
95826e46883SJohn Baldwin } else {
95926e46883SJohn Baldwin sc->delta_rxl = DEF_RXL_DELTA;
96026e46883SJohn Baldwin sc->cur_rxl_index = DEF_RXL;
96126e46883SJohn Baldwin }
96226e46883SJohn Baldwin
96326e46883SJohn Baldwin sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE;
96426e46883SJohn Baldwin sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
96526e46883SJohn Baldwin sc->maxframe = DEFAULT_FRAME_LEN;
96626e46883SJohn Baldwin
96726e46883SJohn Baldwin /*
96826e46883SJohn Baldwin * generate Ethernet address (0x00ff01xxxxxx)
96926e46883SJohn Baldwin */
97026e46883SJohn Baldwin *(u_int16_t *) sc->enaddr = htons(0x00ff);
97126e46883SJohn Baldwin if (flags.mac_addr) {
97226e46883SJohn Baldwin *(u_int32_t *) (sc->enaddr + 2) =
97326e46883SJohn Baldwin htonl(flags.mac_addr | 0x01000000);
97426e46883SJohn Baldwin } else {
97526e46883SJohn Baldwin *(u_char *) (sc->enaddr + 2) = 0x01;
97626e46883SJohn Baldwin read_random(sc->enaddr + 3, 3);
97726e46883SJohn Baldwin }
97826e46883SJohn Baldwin }
97926e46883SJohn Baldwin
98026e46883SJohn Baldwin #ifdef SBNI_DUAL_COMPOUND
98126e46883SJohn Baldwin void
sbni_add(struct sbni_softc * sc)98226e46883SJohn Baldwin sbni_add(struct sbni_softc *sc)
98326e46883SJohn Baldwin {
98426e46883SJohn Baldwin
98526e46883SJohn Baldwin mtx_lock(&headlist_lock);
98626e46883SJohn Baldwin sc->link = sbni_headlist;
98726e46883SJohn Baldwin sbni_headlist = sc;
98826e46883SJohn Baldwin mtx_unlock(&headlist_lock);
98926e46883SJohn Baldwin }
99026e46883SJohn Baldwin
99126e46883SJohn Baldwin struct sbni_softc *
connect_to_master(struct sbni_softc * sc)99226e46883SJohn Baldwin connect_to_master(struct sbni_softc *sc)
99326e46883SJohn Baldwin {
99426e46883SJohn Baldwin struct sbni_softc *p, *p_prev;
99526e46883SJohn Baldwin
99626e46883SJohn Baldwin mtx_lock(&headlist_lock);
99726e46883SJohn Baldwin for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) {
99826e46883SJohn Baldwin if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 ||
99926e46883SJohn Baldwin rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) {
100026e46883SJohn Baldwin p->slave_sc = sc;
100126e46883SJohn Baldwin if (p_prev)
100226e46883SJohn Baldwin p_prev->link = p->link;
100326e46883SJohn Baldwin else
100426e46883SJohn Baldwin sbni_headlist = p->link;
100526e46883SJohn Baldwin mtx_unlock(&headlist_lock);
100626e46883SJohn Baldwin return p;
100726e46883SJohn Baldwin }
100826e46883SJohn Baldwin }
100926e46883SJohn Baldwin mtx_unlock(&headlist_lock);
101026e46883SJohn Baldwin
101126e46883SJohn Baldwin return (NULL);
101226e46883SJohn Baldwin }
101326e46883SJohn Baldwin
101426e46883SJohn Baldwin #endif /* SBNI_DUAL_COMPOUND */
101526e46883SJohn Baldwin
101626e46883SJohn Baldwin /* Receive level auto-selection */
101726e46883SJohn Baldwin
101826e46883SJohn Baldwin static void
change_level(struct sbni_softc * sc)101926e46883SJohn Baldwin change_level(struct sbni_softc *sc)
102026e46883SJohn Baldwin {
102126e46883SJohn Baldwin if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */
102226e46883SJohn Baldwin return;
102326e46883SJohn Baldwin
102426e46883SJohn Baldwin if (sc->cur_rxl_index == 0)
102526e46883SJohn Baldwin sc->delta_rxl = 1;
102626e46883SJohn Baldwin else if (sc->cur_rxl_index == 15)
102726e46883SJohn Baldwin sc->delta_rxl = -1;
102826e46883SJohn Baldwin else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd)
102926e46883SJohn Baldwin sc->delta_rxl = -sc->delta_rxl;
103026e46883SJohn Baldwin
103126e46883SJohn Baldwin sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl];
103226e46883SJohn Baldwin sbni_inb(sc, CSR0); /* it needed for PCI cards */
103326e46883SJohn Baldwin sbni_outb(sc, CSR1, *(u_char *)&sc->csr1);
103426e46883SJohn Baldwin
103526e46883SJohn Baldwin sc->prev_rxl_rcvd = sc->cur_rxl_rcvd;
103626e46883SJohn Baldwin sc->cur_rxl_rcvd = 0;
103726e46883SJohn Baldwin }
103826e46883SJohn Baldwin
103926e46883SJohn Baldwin static void
timeout_change_level(struct sbni_softc * sc)104026e46883SJohn Baldwin timeout_change_level(struct sbni_softc *sc)
104126e46883SJohn Baldwin {
104226e46883SJohn Baldwin sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl];
104326e46883SJohn Baldwin if (++sc->timeout_rxl >= 4)
104426e46883SJohn Baldwin sc->timeout_rxl = 0;
104526e46883SJohn Baldwin
104626e46883SJohn Baldwin sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
104726e46883SJohn Baldwin sbni_inb(sc, CSR0);
104826e46883SJohn Baldwin sbni_outb(sc, CSR1, *(u_char *)&sc->csr1);
104926e46883SJohn Baldwin
105026e46883SJohn Baldwin sc->prev_rxl_rcvd = sc->cur_rxl_rcvd;
105126e46883SJohn Baldwin sc->cur_rxl_rcvd = 0;
105226e46883SJohn Baldwin }
105326e46883SJohn Baldwin
105426e46883SJohn Baldwin /* -------------------------------------------------------------------------- */
105526e46883SJohn Baldwin
105626e46883SJohn Baldwin /*
105726e46883SJohn Baldwin * Process an ioctl request. This code needs some work - it looks
105826e46883SJohn Baldwin * pretty ugly.
105926e46883SJohn Baldwin */
106026e46883SJohn Baldwin
106126e46883SJohn Baldwin static int
sbni_ioctl(if_t ifp,u_long command,caddr_t data)10623fba06adSJustin Hibbits sbni_ioctl(if_t ifp, u_long command, caddr_t data)
106326e46883SJohn Baldwin {
106426e46883SJohn Baldwin struct sbni_softc *sc;
106526e46883SJohn Baldwin struct ifreq *ifr;
106626e46883SJohn Baldwin struct thread *td;
106726e46883SJohn Baldwin struct sbni_in_stats *in_stats;
106826e46883SJohn Baldwin struct sbni_flags flags;
106926e46883SJohn Baldwin int error;
107026e46883SJohn Baldwin
10713fba06adSJustin Hibbits sc = if_getsoftc(ifp);
107226e46883SJohn Baldwin ifr = (struct ifreq *)data;
107326e46883SJohn Baldwin td = curthread;
107426e46883SJohn Baldwin error = 0;
107526e46883SJohn Baldwin
107626e46883SJohn Baldwin switch (command) {
107726e46883SJohn Baldwin case SIOCSIFFLAGS:
107826e46883SJohn Baldwin /*
107926e46883SJohn Baldwin * If the interface is marked up and stopped, then start it.
108026e46883SJohn Baldwin * If it is marked down and running, then stop it.
108126e46883SJohn Baldwin */
108226e46883SJohn Baldwin SBNI_LOCK(sc);
10833fba06adSJustin Hibbits if (if_getflags(ifp) & IFF_UP) {
10843fba06adSJustin Hibbits if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING))
108526e46883SJohn Baldwin sbni_init_locked(sc);
108626e46883SJohn Baldwin } else {
10873fba06adSJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
108826e46883SJohn Baldwin sbni_stop(sc);
108926e46883SJohn Baldwin }
109026e46883SJohn Baldwin }
109126e46883SJohn Baldwin SBNI_UNLOCK(sc);
109226e46883SJohn Baldwin break;
109326e46883SJohn Baldwin
109426e46883SJohn Baldwin case SIOCADDMULTI:
109526e46883SJohn Baldwin case SIOCDELMULTI:
109626e46883SJohn Baldwin /*
109726e46883SJohn Baldwin * Multicast list has changed; set the hardware filter
109826e46883SJohn Baldwin * accordingly.
109926e46883SJohn Baldwin */
110026e46883SJohn Baldwin error = 0;
110126e46883SJohn Baldwin /* if (ifr == NULL)
110226e46883SJohn Baldwin error = EAFNOSUPPORT; */
110326e46883SJohn Baldwin break;
110426e46883SJohn Baldwin
110526e46883SJohn Baldwin /*
110626e46883SJohn Baldwin * SBNI specific ioctl
110726e46883SJohn Baldwin */
110826e46883SJohn Baldwin case SIOCGHWFLAGS: /* get flags */
110926e46883SJohn Baldwin SBNI_LOCK(sc);
11103fba06adSJustin Hibbits bcopy((caddr_t)if_getlladdr(sc->ifp)+3, (caddr_t) &flags, 3);
111126e46883SJohn Baldwin flags.rxl = sc->cur_rxl_index;
111226e46883SJohn Baldwin flags.rate = sc->csr1.rate;
111326e46883SJohn Baldwin flags.fixed_rxl = (sc->delta_rxl == 0);
111426e46883SJohn Baldwin flags.fixed_rate = 1;
111526e46883SJohn Baldwin SBNI_UNLOCK(sc);
11162f471660SBrooks Davis bcopy(&flags, &ifr->ifr_ifru, sizeof(flags));
111726e46883SJohn Baldwin break;
111826e46883SJohn Baldwin
111926e46883SJohn Baldwin case SIOCGINSTATS:
112026e46883SJohn Baldwin in_stats = malloc(sizeof(struct sbni_in_stats), M_DEVBUF,
112126e46883SJohn Baldwin M_WAITOK);
112226e46883SJohn Baldwin SBNI_LOCK(sc);
112326e46883SJohn Baldwin bcopy(&sc->in_stats, in_stats, sizeof(struct sbni_in_stats));
112426e46883SJohn Baldwin SBNI_UNLOCK(sc);
11258f4dfca1SBrooks Davis error = copyout(in_stats, ifr_data_get_ptr(ifr),
112626e46883SJohn Baldwin sizeof(struct sbni_in_stats));
112726e46883SJohn Baldwin free(in_stats, M_DEVBUF);
112826e46883SJohn Baldwin break;
112926e46883SJohn Baldwin
113026e46883SJohn Baldwin case SIOCSHWFLAGS: /* set flags */
113126e46883SJohn Baldwin /* root only */
113226e46883SJohn Baldwin error = priv_check(td, PRIV_DRIVER);
113326e46883SJohn Baldwin if (error)
113426e46883SJohn Baldwin break;
11352f471660SBrooks Davis bcopy(&ifr->ifr_ifru, &flags, sizeof(flags));
113626e46883SJohn Baldwin SBNI_LOCK(sc);
113726e46883SJohn Baldwin if (flags.fixed_rxl) {
113826e46883SJohn Baldwin sc->delta_rxl = 0;
113926e46883SJohn Baldwin sc->cur_rxl_index = flags.rxl;
114026e46883SJohn Baldwin } else {
114126e46883SJohn Baldwin sc->delta_rxl = DEF_RXL_DELTA;
114226e46883SJohn Baldwin sc->cur_rxl_index = DEF_RXL;
114326e46883SJohn Baldwin }
114426e46883SJohn Baldwin sc->csr1.rxl = rxl_tab[sc->cur_rxl_index];
114526e46883SJohn Baldwin sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE;
114626e46883SJohn Baldwin if (flags.mac_addr)
114726e46883SJohn Baldwin bcopy((caddr_t) &flags,
11483fba06adSJustin Hibbits (caddr_t) if_getlladdr(sc->ifp)+3, 3);
114926e46883SJohn Baldwin
115026e46883SJohn Baldwin /* Don't be afraid... */
115126e46883SJohn Baldwin sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES);
115226e46883SJohn Baldwin SBNI_UNLOCK(sc);
115326e46883SJohn Baldwin break;
115426e46883SJohn Baldwin
115526e46883SJohn Baldwin case SIOCRINSTATS:
115626e46883SJohn Baldwin SBNI_LOCK(sc);
115726e46883SJohn Baldwin if (!(error = priv_check(td, PRIV_DRIVER))) /* root only */
115826e46883SJohn Baldwin bzero(&sc->in_stats, sizeof(struct sbni_in_stats));
115926e46883SJohn Baldwin SBNI_UNLOCK(sc);
116026e46883SJohn Baldwin break;
116126e46883SJohn Baldwin
116226e46883SJohn Baldwin default:
116326e46883SJohn Baldwin error = ether_ioctl(ifp, command, data);
116426e46883SJohn Baldwin break;
116526e46883SJohn Baldwin }
116626e46883SJohn Baldwin
116726e46883SJohn Baldwin return (error);
116826e46883SJohn Baldwin }
116926e46883SJohn Baldwin
117026e46883SJohn Baldwin /* -------------------------------------------------------------------------- */
117126e46883SJohn Baldwin
117226e46883SJohn Baldwin static u_int32_t
calc_crc32(u_int32_t crc,caddr_t p,u_int len)117326e46883SJohn Baldwin calc_crc32(u_int32_t crc, caddr_t p, u_int len)
117426e46883SJohn Baldwin {
117526e46883SJohn Baldwin while (len--)
117626e46883SJohn Baldwin crc = CRC32(*p++, crc);
117726e46883SJohn Baldwin
117826e46883SJohn Baldwin return (crc);
117926e46883SJohn Baldwin }
118026e46883SJohn Baldwin
118126e46883SJohn Baldwin static u_int32_t crc32tab[] __aligned(8) = {
118226e46883SJohn Baldwin 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37,
118326e46883SJohn Baldwin 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E,
118426e46883SJohn Baldwin 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605,
118526e46883SJohn Baldwin 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C,
118626e46883SJohn Baldwin 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53,
118726e46883SJohn Baldwin 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A,
118826e46883SJohn Baldwin 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661,
118926e46883SJohn Baldwin 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278,
119026e46883SJohn Baldwin 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF,
119126e46883SJohn Baldwin 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6,
119226e46883SJohn Baldwin 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD,
119326e46883SJohn Baldwin 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4,
119426e46883SJohn Baldwin 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B,
119526e46883SJohn Baldwin 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82,
119626e46883SJohn Baldwin 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9,
119726e46883SJohn Baldwin 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0,
119826e46883SJohn Baldwin 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7,
119926e46883SJohn Baldwin 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE,
120026e46883SJohn Baldwin 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795,
120126e46883SJohn Baldwin 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C,
120226e46883SJohn Baldwin 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3,
120326e46883SJohn Baldwin 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA,
120426e46883SJohn Baldwin 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1,
120526e46883SJohn Baldwin 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8,
120626e46883SJohn Baldwin 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F,
120726e46883SJohn Baldwin 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76,
120826e46883SJohn Baldwin 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D,
120926e46883SJohn Baldwin 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344,
121026e46883SJohn Baldwin 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B,
121126e46883SJohn Baldwin 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12,
121226e46883SJohn Baldwin 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739,
121326e46883SJohn Baldwin 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320,
121426e46883SJohn Baldwin 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17,
121526e46883SJohn Baldwin 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E,
121626e46883SJohn Baldwin 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525,
121726e46883SJohn Baldwin 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C,
121826e46883SJohn Baldwin 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73,
121926e46883SJohn Baldwin 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A,
122026e46883SJohn Baldwin 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541,
122126e46883SJohn Baldwin 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158,
122226e46883SJohn Baldwin 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF,
122326e46883SJohn Baldwin 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6,
122426e46883SJohn Baldwin 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED,
122526e46883SJohn Baldwin 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4,
122626e46883SJohn Baldwin 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB,
122726e46883SJohn Baldwin 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2,
122826e46883SJohn Baldwin 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589,
122926e46883SJohn Baldwin 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190,
123026e46883SJohn Baldwin 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87,
123126e46883SJohn Baldwin 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E,
123226e46883SJohn Baldwin 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5,
123326e46883SJohn Baldwin 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC,
123426e46883SJohn Baldwin 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3,
123526e46883SJohn Baldwin 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA,
123626e46883SJohn Baldwin 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1,
123726e46883SJohn Baldwin 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8,
123826e46883SJohn Baldwin 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F,
123926e46883SJohn Baldwin 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856,
124026e46883SJohn Baldwin 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D,
124126e46883SJohn Baldwin 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064,
124226e46883SJohn Baldwin 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B,
124326e46883SJohn Baldwin 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832,
124426e46883SJohn Baldwin 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419,
124526e46883SJohn Baldwin 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000
124626e46883SJohn Baldwin };
1247