if_sbni.c revision 180263
1139749Simp/*- 286752Sfjoe * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved. 386752Sfjoe * Author: Denis I.Timofeev <timofeev@granch.ru> 486752Sfjoe * 586752Sfjoe * Redistributon and use in source and binary forms, with or without 686752Sfjoe * modification, are permitted provided that the following conditions 786752Sfjoe * are met: 886752Sfjoe * 1. Redistributions of source code must retain the above copyright 986752Sfjoe * notice unmodified, this list of conditions, and the following 1086752Sfjoe * disclaimer. 1186752Sfjoe * 2. Redistributions in binary form must reproduce the above copyright 1286752Sfjoe * notice, this list of conditions and the following disclaimer in the 1386752Sfjoe * documentation and/or other materials provided with the distribution. 1486752Sfjoe * 1586752Sfjoe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1686752Sfjoe * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1786752Sfjoe * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1886752Sfjoe * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1986752Sfjoe * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2086752Sfjoe * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2186752Sfjoe * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2286752Sfjoe * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2386752Sfjoe * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY 2486752Sfjoe * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2586752Sfjoe * SUCH DAMAGE. 2686752Sfjoe * 2786752Sfjoe */ 2886752Sfjoe 29119419Sobrien#include <sys/cdefs.h> 30119419Sobrien__FBSDID("$FreeBSD: head/sys/dev/sbni/if_sbni.c 180263 2008-07-04 20:53:41Z jhb $"); 31119419Sobrien 3286752Sfjoe/* 3386752Sfjoe * Device driver for Granch SBNI12 leased line adapters 3486752Sfjoe * 3586752Sfjoe * Revision 2.0.0 1997/08/06 3686752Sfjoe * Initial revision by Alexey Zverev 3786752Sfjoe * 3886752Sfjoe * Revision 2.0.1 1997/08/11 3986752Sfjoe * Additional internal statistics support (tx statistics) 4086752Sfjoe * 4186752Sfjoe * Revision 2.0.2 1997/11/05 4286752Sfjoe * if_bpf bug has been fixed 4386752Sfjoe * 4486752Sfjoe * Revision 2.0.3 1998/12/20 4586752Sfjoe * Memory leakage has been eliminated in 4686752Sfjoe * the sbni_st and sbni_timeout routines. 4786752Sfjoe * 4886752Sfjoe * Revision 3.0 2000/08/10 by Yaroslav Polyakov 4986752Sfjoe * Support for PCI cards. 4.1 modification. 5086752Sfjoe * 5186752Sfjoe * Revision 3.1 2000/09/12 5286752Sfjoe * Removed extra #defines around bpf functions 5386752Sfjoe * 5486752Sfjoe * Revision 4.0 2000/11/23 by Denis Timofeev 5586752Sfjoe * Completely redesigned the buffer management 5686752Sfjoe * 5786752Sfjoe * Revision 4.1 2001/01/21 5886752Sfjoe * Support for PCI Dual cards and new SBNI12D-10, -11 Dual/ISA cards 5986752Sfjoe * 6086752Sfjoe * Written with reference to NE2000 driver developed by David Greenman. 6186752Sfjoe */ 6286752Sfjoe 6386752Sfjoe 6486752Sfjoe#include <sys/param.h> 65180263Sjhb#include <sys/bus.h> 6686752Sfjoe#include <sys/systm.h> 6786752Sfjoe#include <sys/socket.h> 6886752Sfjoe#include <sys/sockio.h> 6986752Sfjoe#include <sys/mbuf.h> 7086752Sfjoe#include <sys/kernel.h> 71164033Srwatson#include <sys/priv.h> 7286752Sfjoe#include <sys/proc.h> 7386752Sfjoe#include <sys/callout.h> 7486752Sfjoe#include <sys/syslog.h> 75101400Sfjoe#include <sys/random.h> 7686752Sfjoe 77101400Sfjoe#include <machine/bus.h> 78101400Sfjoe#include <sys/rman.h> 79101400Sfjoe#include <machine/resource.h> 80101400Sfjoe 8186752Sfjoe#include <net/if.h> 82152315Sru#include <net/if_dl.h> 8386752Sfjoe#include <net/ethernet.h> 8486752Sfjoe#include <net/bpf.h> 85147256Sbrooks#include <net/if_types.h> 8686752Sfjoe 8786752Sfjoe#include <dev/sbni/if_sbnireg.h> 8886752Sfjoe#include <dev/sbni/if_sbnivar.h> 8986752Sfjoe 9086752Sfjoe#define ASM_CRC 1 9186752Sfjoe 9286752Sfjoestatic void sbni_init(void *); 93180263Sjhbstatic void sbni_init_locked(struct sbni_softc *); 9486752Sfjoestatic void sbni_start(struct ifnet *); 95180263Sjhbstatic void sbni_start_locked(struct ifnet *); 9686752Sfjoestatic int sbni_ioctl(struct ifnet *, u_long, caddr_t); 9786752Sfjoestatic void sbni_stop(struct sbni_softc *); 9886752Sfjoestatic void handle_channel(struct sbni_softc *); 9986752Sfjoe 10086752Sfjoestatic void card_start(struct sbni_softc *); 10186752Sfjoestatic int recv_frame(struct sbni_softc *); 10286752Sfjoestatic void send_frame(struct sbni_softc *); 10386752Sfjoestatic int upload_data(struct sbni_softc *, u_int, u_int, u_int, u_int32_t); 10486752Sfjoestatic int skip_tail(struct sbni_softc *, u_int, u_int32_t); 10586752Sfjoestatic void interpret_ack(struct sbni_softc *, u_int); 10686752Sfjoestatic void download_data(struct sbni_softc *, u_int32_t *); 10786752Sfjoestatic void prepare_to_send(struct sbni_softc *); 10886752Sfjoestatic void drop_xmit_queue(struct sbni_softc *); 10986752Sfjoestatic int get_rx_buf(struct sbni_softc *); 11086752Sfjoestatic void indicate_pkt(struct sbni_softc *); 11186752Sfjoestatic void change_level(struct sbni_softc *); 11286752Sfjoestatic int check_fhdr(struct sbni_softc *, u_int *, u_int *, 11386752Sfjoe u_int *, u_int *, u_int32_t *); 11486752Sfjoestatic int append_frame_to_pkt(struct sbni_softc *, u_int, u_int32_t); 11586752Sfjoestatic void timeout_change_level(struct sbni_softc *); 11686752Sfjoestatic void send_frame_header(struct sbni_softc *, u_int32_t *); 11786752Sfjoestatic void set_initial_values(struct sbni_softc *, struct sbni_flags); 11886752Sfjoe 11986752Sfjoestatic u_int32_t calc_crc32(u_int32_t, caddr_t, u_int); 12086752Sfjoestatic timeout_t sbni_timeout; 12186752Sfjoe 12286752Sfjoestatic __inline u_char sbni_inb(struct sbni_softc *, enum sbni_reg); 12386752Sfjoestatic __inline void sbni_outb(struct sbni_softc *, enum sbni_reg, u_char); 12486752Sfjoestatic __inline void sbni_insb(struct sbni_softc *, u_char *, u_int); 12586752Sfjoestatic __inline void sbni_outsb(struct sbni_softc *, u_char *, u_int); 12686752Sfjoe 12786752Sfjoestatic u_int32_t crc32tab[]; 12886752Sfjoe 12986752Sfjoe#ifdef SBNI_DUAL_COMPOUND 130180263Sjhbstatic struct mtx headlist_lock; 131180263SjhbMTX_SYSINIT(headlist_lock, &headlist_lock, "sbni headlist", MTX_DEF); 132180263Sjhbstatic struct sbni_softc *sbni_headlist; 13386752Sfjoe#endif 13486752Sfjoe 13586752Sfjoe/* -------------------------------------------------------------------------- */ 13686752Sfjoe 13786752Sfjoestatic __inline u_char 13886752Sfjoesbni_inb(struct sbni_softc *sc, enum sbni_reg reg) 13986752Sfjoe{ 140101400Sfjoe return bus_space_read_1( 141101400Sfjoe rman_get_bustag(sc->io_res), 142101400Sfjoe rman_get_bushandle(sc->io_res), 143101400Sfjoe sc->io_off + reg); 14486752Sfjoe} 14586752Sfjoe 14686752Sfjoestatic __inline void 14786752Sfjoesbni_outb(struct sbni_softc *sc, enum sbni_reg reg, u_char value) 14886752Sfjoe{ 149101400Sfjoe bus_space_write_1( 150101400Sfjoe rman_get_bustag(sc->io_res), 151101400Sfjoe rman_get_bushandle(sc->io_res), 152101400Sfjoe sc->io_off + reg, value); 15386752Sfjoe} 15486752Sfjoe 15586752Sfjoestatic __inline void 15686752Sfjoesbni_insb(struct sbni_softc *sc, u_char *to, u_int len) 15786752Sfjoe{ 158101400Sfjoe bus_space_read_multi_1( 159101400Sfjoe rman_get_bustag(sc->io_res), 160101400Sfjoe rman_get_bushandle(sc->io_res), 161101400Sfjoe sc->io_off + DAT, to, len); 16286752Sfjoe} 16386752Sfjoe 16486752Sfjoestatic __inline void 16586752Sfjoesbni_outsb(struct sbni_softc *sc, u_char *from, u_int len) 16686752Sfjoe{ 167101400Sfjoe bus_space_write_multi_1( 168101400Sfjoe rman_get_bustag(sc->io_res), 169101400Sfjoe rman_get_bushandle(sc->io_res), 170101400Sfjoe sc->io_off + DAT, from, len); 17186752Sfjoe} 17286752Sfjoe 17386752Sfjoe 17486752Sfjoe/* 17586752Sfjoe Valid combinations in CSR0 (for probing): 17686752Sfjoe 17786752Sfjoe VALID_DECODER 0000,0011,1011,1010 17886752Sfjoe 17986752Sfjoe ; 0 ; - 18086752Sfjoe TR_REQ ; 1 ; + 18186752Sfjoe TR_RDY ; 2 ; - 18286752Sfjoe TR_RDY TR_REQ ; 3 ; + 18386752Sfjoe BU_EMP ; 4 ; + 18486752Sfjoe BU_EMP TR_REQ ; 5 ; + 18586752Sfjoe BU_EMP TR_RDY ; 6 ; - 18686752Sfjoe BU_EMP TR_RDY TR_REQ ; 7 ; + 18786752Sfjoe RC_RDY ; 8 ; + 18886752Sfjoe RC_RDY TR_REQ ; 9 ; + 18986752Sfjoe RC_RDY TR_RDY ; 10 ; - 19086752Sfjoe RC_RDY TR_RDY TR_REQ ; 11 ; - 19186752Sfjoe RC_RDY BU_EMP ; 12 ; - 19286752Sfjoe RC_RDY BU_EMP TR_REQ ; 13 ; - 19386752Sfjoe RC_RDY BU_EMP TR_RDY ; 14 ; - 19486752Sfjoe RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; - 19586752Sfjoe*/ 19686752Sfjoe 19786752Sfjoe#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200) 19886752Sfjoe 19986752Sfjoe 20086752Sfjoeint 20186752Sfjoesbni_probe(struct sbni_softc *sc) 20286752Sfjoe{ 20386752Sfjoe u_char csr0; 20486752Sfjoe 20586752Sfjoe csr0 = sbni_inb(sc, CSR0); 20686752Sfjoe if (csr0 != 0xff && csr0 != 0x00) { 20786752Sfjoe csr0 &= ~EN_INT; 20886752Sfjoe if (csr0 & BU_EMP) 20986752Sfjoe csr0 |= EN_INT; 21086752Sfjoe 21186752Sfjoe if (VALID_DECODER & (1 << (csr0 >> 4))) 21286752Sfjoe return (0); 21386752Sfjoe } 21486752Sfjoe 21586752Sfjoe return (ENXIO); 21686752Sfjoe} 21786752Sfjoe 21886752Sfjoe 21986752Sfjoe/* 22086752Sfjoe * Install interface into kernel networking data structures 22186752Sfjoe */ 222180263Sjhbint 22386752Sfjoesbni_attach(struct sbni_softc *sc, int unit, struct sbni_flags flags) 22486752Sfjoe{ 22586752Sfjoe struct ifnet *ifp; 22686752Sfjoe u_char csr0; 22786752Sfjoe 228147256Sbrooks ifp = sc->ifp = if_alloc(IFT_ETHER); 229147256Sbrooks if (ifp == NULL) 230180263Sjhb return (ENOMEM); 23186752Sfjoe sbni_outb(sc, CSR0, 0); 23286752Sfjoe set_initial_values(sc, flags); 23386752Sfjoe 234121752Sbrooks /* Initialize ifnet structure */ 235121752Sbrooks ifp->if_softc = sc; 236121816Sbrooks if_initname(ifp, "sbni", unit); 237121752Sbrooks ifp->if_init = sbni_init; 238121752Sbrooks ifp->if_start = sbni_start; 239121752Sbrooks ifp->if_ioctl = sbni_ioctl; 240180263Sjhb IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 24186752Sfjoe 242121752Sbrooks /* report real baud rate */ 243121752Sbrooks csr0 = sbni_inb(sc, CSR0); 244121752Sbrooks ifp->if_baudrate = 245121752Sbrooks (csr0 & 0x01 ? 500000 : 2000000) / (1 << flags.rate); 24686752Sfjoe 247180263Sjhb ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 248180263Sjhb 249180263Sjhb mtx_init(&sc->lock, ifp->if_xname, MTX_NETWORK_LOCK, MTX_DEF); 250180263Sjhb callout_init_mtx(&sc->wch, &sc->lock, 0); 251147256Sbrooks ether_ifattach(ifp, sc->enaddr); 25286752Sfjoe /* device attach does transition from UNCONFIGURED to IDLE state */ 25386752Sfjoe 254126966Smdodd if_printf(ifp, "speed %ld, rxl ", ifp->if_baudrate); 25586752Sfjoe if (sc->delta_rxl) 25686752Sfjoe printf("auto\n"); 25786752Sfjoe else 25886752Sfjoe printf("%d (fixed)\n", sc->cur_rxl_index); 259180263Sjhb return (0); 26086752Sfjoe} 26186752Sfjoe 262180263Sjhbvoid 263180263Sjhbsbni_detach(struct sbni_softc *sc) 264180263Sjhb{ 265180263Sjhb 266180263Sjhb SBNI_LOCK(sc); 267180263Sjhb sbni_stop(sc); 268180263Sjhb SBNI_UNLOCK(sc); 269180263Sjhb callout_drain(&sc->wch); 270180263Sjhb ether_ifdetach(sc->ifp); 271180263Sjhb if (sc->irq_handle) 272180263Sjhb bus_teardown_intr(sc->dev, sc->irq_res, sc->irq_handle); 273180263Sjhb mtx_destroy(&sc->lock); 274180263Sjhb if_free(sc->ifp); 275180263Sjhb} 276180263Sjhb 277180263Sjhbvoid 278180263Sjhbsbni_release_resources(struct sbni_softc *sc) 279180263Sjhb{ 280180263Sjhb 281180263Sjhb if (sc->irq_res) 282180263Sjhb bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid, 283180263Sjhb sc->irq_res); 284180263Sjhb if (sc->io_res && sc->io_off == 0) 285180263Sjhb bus_release_resource(sc->dev, SYS_RES_IOPORT, sc->io_rid, 286180263Sjhb sc->io_res); 287180263Sjhb} 288180263Sjhb 28986752Sfjoe/* -------------------------------------------------------------------------- */ 29086752Sfjoe 29186752Sfjoestatic void 29286752Sfjoesbni_init(void *xsc) 29386752Sfjoe{ 29486752Sfjoe struct sbni_softc *sc; 295180263Sjhb 296180263Sjhb sc = (struct sbni_softc *)xsc; 297180263Sjhb SBNI_LOCK(sc); 298180263Sjhb sbni_init_locked(sc); 299180263Sjhb SBNI_UNLOCK(sc); 300180263Sjhb} 301180263Sjhb 302180263Sjhbstatic void 303180263Sjhbsbni_init_locked(struct sbni_softc *sc) 304180263Sjhb{ 30586752Sfjoe struct ifnet *ifp; 30686752Sfjoe 307147256Sbrooks ifp = sc->ifp; 30886752Sfjoe 30986752Sfjoe /* 31086752Sfjoe * kludge to avoid multiple initialization when more than once 31186752Sfjoe * protocols configured 31286752Sfjoe */ 313148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) 31486752Sfjoe return; 31586752Sfjoe 31686752Sfjoe card_start(sc); 317180263Sjhb callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc); 31886752Sfjoe 319148887Srwatson ifp->if_drv_flags |= IFF_DRV_RUNNING; 320148887Srwatson ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 32186752Sfjoe 32286752Sfjoe /* attempt to start output */ 323180263Sjhb sbni_start_locked(ifp); 32486752Sfjoe} 32586752Sfjoe 32686752Sfjoestatic void 32786752Sfjoesbni_start(struct ifnet *ifp) 32886752Sfjoe{ 32986752Sfjoe struct sbni_softc *sc = ifp->if_softc; 330180263Sjhb 331180263Sjhb SBNI_LOCK(sc); 332180263Sjhb sbni_start_locked(ifp); 333180263Sjhb SBNI_UNLOCK(sc); 334180263Sjhb} 335180263Sjhb 336180263Sjhbstatic void 337180263Sjhbsbni_start_locked(struct ifnet *ifp) 338180263Sjhb{ 339180263Sjhb struct sbni_softc *sc = ifp->if_softc; 340180263Sjhb 34186752Sfjoe if (sc->tx_frameno == 0) 34286752Sfjoe prepare_to_send(sc); 34386752Sfjoe} 34486752Sfjoe 34586752Sfjoe 34686752Sfjoestatic void 34786752Sfjoesbni_stop(struct sbni_softc *sc) 34886752Sfjoe{ 34986752Sfjoe sbni_outb(sc, CSR0, 0); 35086752Sfjoe drop_xmit_queue(sc); 35186752Sfjoe 35286752Sfjoe if (sc->rx_buf_p) { 35386752Sfjoe m_freem(sc->rx_buf_p); 35486752Sfjoe sc->rx_buf_p = NULL; 35586752Sfjoe } 35686752Sfjoe 357180263Sjhb callout_stop(&sc->wch); 358180263Sjhb sc->ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 35986752Sfjoe} 36086752Sfjoe 36186752Sfjoe/* -------------------------------------------------------------------------- */ 36286752Sfjoe 36386752Sfjoe/* interrupt handler */ 36486752Sfjoe 36586752Sfjoe/* 36686752Sfjoe * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not 36786752Sfjoe * be looked as two independent single-channel devices. Every channel seems 36886752Sfjoe * as Ethernet interface but interrupt handler must be common. Really, first 36986752Sfjoe * channel ("master") driver only registers the handler. In it's struct softc 37086752Sfjoe * it has got pointer to "slave" channel's struct softc and handles that's 37186752Sfjoe * interrupts too. 37286752Sfjoe * softc of successfully attached ISA SBNI boards is linked to list. 37386752Sfjoe * While next board driver is initialized, it scans this list. If one 37486752Sfjoe * has found softc with same irq and ioaddr different by 4 then it assumes 37586752Sfjoe * this board to be "master". 37686752Sfjoe */ 37786752Sfjoe 37886752Sfjoevoid 37986752Sfjoesbni_intr(void *arg) 38086752Sfjoe{ 38186752Sfjoe struct sbni_softc *sc; 38286752Sfjoe int repeat; 38386752Sfjoe 38486752Sfjoe sc = (struct sbni_softc *)arg; 38586752Sfjoe 38686752Sfjoe do { 38786752Sfjoe repeat = 0; 388180263Sjhb SBNI_LOCK(sc); 38986752Sfjoe if (sbni_inb(sc, CSR0) & (RC_RDY | TR_RDY)) { 39086752Sfjoe handle_channel(sc); 39186752Sfjoe repeat = 1; 39286752Sfjoe } 393180263Sjhb SBNI_UNLOCK(sc); 394180263Sjhb if (sc->slave_sc) { 395180263Sjhb /* second channel present */ 396180263Sjhb SBNI_LOCK(sc->slave_sc); 397180263Sjhb if (sbni_inb(sc->slave_sc, CSR0) & (RC_RDY | TR_RDY)) { 398180263Sjhb handle_channel(sc->slave_sc); 399180263Sjhb repeat = 1; 400180263Sjhb } 401180263Sjhb SBNI_UNLOCK(sc->slave_sc); 40286752Sfjoe } 40386752Sfjoe } while (repeat); 40486752Sfjoe} 40586752Sfjoe 40686752Sfjoe 40786752Sfjoestatic void 40886752Sfjoehandle_channel(struct sbni_softc *sc) 40986752Sfjoe{ 41086752Sfjoe int req_ans; 41186752Sfjoe u_char csr0; 41286752Sfjoe 41386752Sfjoe sbni_outb(sc, CSR0, (sbni_inb(sc, CSR0) & ~EN_INT) | TR_REQ); 41486752Sfjoe 41586752Sfjoe sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 41686752Sfjoe for (;;) { 41786752Sfjoe csr0 = sbni_inb(sc, CSR0); 41886752Sfjoe if ((csr0 & (RC_RDY | TR_RDY)) == 0) 41986752Sfjoe break; 42086752Sfjoe 42186752Sfjoe req_ans = !(sc->state & FL_PREV_OK); 42286752Sfjoe 42386752Sfjoe if (csr0 & RC_RDY) 42486752Sfjoe req_ans = recv_frame(sc); 42586752Sfjoe 42686752Sfjoe /* 42786752Sfjoe * TR_RDY always equals 1 here because we have owned the marker, 42886752Sfjoe * and we set TR_REQ when disabled interrupts 42986752Sfjoe */ 43086752Sfjoe csr0 = sbni_inb(sc, CSR0); 43186752Sfjoe if ((csr0 & TR_RDY) == 0 || (csr0 & RC_RDY) != 0) 432180263Sjhb if_printf(sc->ifp, "internal error!\n"); 43386752Sfjoe 43486752Sfjoe /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */ 43586752Sfjoe if (req_ans || sc->tx_frameno != 0) 43686752Sfjoe send_frame(sc); 437101393Sfjoe else { 43886752Sfjoe /* send the marker without any data */ 43986752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) & ~TR_REQ); 440101393Sfjoe } 44186752Sfjoe } 44286752Sfjoe 44386752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | EN_INT); 44486752Sfjoe} 44586752Sfjoe 44686752Sfjoe 44786752Sfjoe/* 44886752Sfjoe * Routine returns 1 if it need to acknoweledge received frame. 44986752Sfjoe * Empty frame received without errors won't be acknoweledged. 45086752Sfjoe */ 45186752Sfjoe 45286752Sfjoestatic int 45386752Sfjoerecv_frame(struct sbni_softc *sc) 45486752Sfjoe{ 45586752Sfjoe u_int32_t crc; 45686752Sfjoe u_int framelen, frameno, ack; 45786752Sfjoe u_int is_first, frame_ok; 45886752Sfjoe 45986752Sfjoe crc = CRC32_INITIAL; 46086752Sfjoe if (check_fhdr(sc, &framelen, &frameno, &ack, &is_first, &crc)) { 461101393Sfjoe frame_ok = framelen > 4 ? 462101393Sfjoe upload_data(sc, framelen, frameno, is_first, crc) : 463101393Sfjoe skip_tail(sc, framelen, crc); 46486752Sfjoe if (frame_ok) 46586752Sfjoe interpret_ack(sc, ack); 466171243Speter } else { 467171243Speter framelen = 0; 46886752Sfjoe frame_ok = 0; 469171243Speter } 47086752Sfjoe 47186752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) ^ CT_ZER); 47286752Sfjoe if (frame_ok) { 47386752Sfjoe sc->state |= FL_PREV_OK; 47486752Sfjoe if (framelen > 4) 47586752Sfjoe sc->in_stats.all_rx_number++; 47686752Sfjoe } else { 47786752Sfjoe sc->state &= ~FL_PREV_OK; 47886752Sfjoe change_level(sc); 47986752Sfjoe sc->in_stats.all_rx_number++; 48086752Sfjoe sc->in_stats.bad_rx_number++; 48186752Sfjoe } 48286752Sfjoe 48386752Sfjoe return (!frame_ok || framelen > 4); 48486752Sfjoe} 48586752Sfjoe 48686752Sfjoe 48786752Sfjoestatic void 48886752Sfjoesend_frame(struct sbni_softc *sc) 48986752Sfjoe{ 49086752Sfjoe u_int32_t crc; 49186752Sfjoe u_char csr0; 49286752Sfjoe 49386752Sfjoe crc = CRC32_INITIAL; 49486752Sfjoe if (sc->state & FL_NEED_RESEND) { 49586752Sfjoe 49686752Sfjoe /* if frame was sended but not ACK'ed - resend it */ 49786752Sfjoe if (sc->trans_errors) { 49886752Sfjoe sc->trans_errors--; 49986752Sfjoe if (sc->framelen != 0) 50086752Sfjoe sc->in_stats.resend_tx_number++; 50186752Sfjoe } else { 50286752Sfjoe /* cannot xmit with many attempts */ 50386752Sfjoe drop_xmit_queue(sc); 50486752Sfjoe goto do_send; 50586752Sfjoe } 50686752Sfjoe } else 50786752Sfjoe sc->trans_errors = TR_ERROR_COUNT; 50886752Sfjoe 50986752Sfjoe send_frame_header(sc, &crc); 51086752Sfjoe sc->state |= FL_NEED_RESEND; 51186752Sfjoe /* 51286752Sfjoe * FL_NEED_RESEND will be cleared after ACK, but if empty 51386752Sfjoe * frame sended then in prepare_to_send next frame 51486752Sfjoe */ 51586752Sfjoe 51686752Sfjoe 51786752Sfjoe if (sc->framelen) { 51886752Sfjoe download_data(sc, &crc); 51986752Sfjoe sc->in_stats.all_tx_number++; 52086752Sfjoe sc->state |= FL_WAIT_ACK; 52186752Sfjoe } 52286752Sfjoe 52386752Sfjoe sbni_outsb(sc, (u_char *)&crc, sizeof crc); 52486752Sfjoe 52586752Sfjoedo_send: 52686752Sfjoe csr0 = sbni_inb(sc, CSR0); 52786752Sfjoe sbni_outb(sc, CSR0, csr0 & ~TR_REQ); 52886752Sfjoe 52986752Sfjoe if (sc->tx_frameno) { 53086752Sfjoe /* next frame exists - request to send */ 53186752Sfjoe sbni_outb(sc, CSR0, csr0 | TR_REQ); 53286752Sfjoe } 53386752Sfjoe} 53486752Sfjoe 53586752Sfjoe 53686752Sfjoestatic void 53786752Sfjoedownload_data(struct sbni_softc *sc, u_int32_t *crc_p) 53886752Sfjoe{ 53986752Sfjoe struct mbuf *m; 54086752Sfjoe caddr_t data_p; 54186752Sfjoe u_int data_len, pos, slice; 54286752Sfjoe 54386752Sfjoe data_p = NULL; /* initialized to avoid warn */ 54486752Sfjoe pos = 0; 54586752Sfjoe 54686752Sfjoe for (m = sc->tx_buf_p; m != NULL && pos < sc->pktlen; m = m->m_next) { 54786752Sfjoe if (pos + m->m_len > sc->outpos) { 54886752Sfjoe data_len = m->m_len - (sc->outpos - pos); 54986752Sfjoe data_p = mtod(m, caddr_t) + (sc->outpos - pos); 55086752Sfjoe 55186752Sfjoe goto do_copy; 55286752Sfjoe } else 55386752Sfjoe pos += m->m_len; 55486752Sfjoe } 55586752Sfjoe 55686752Sfjoe data_len = 0; 55786752Sfjoe 55886752Sfjoedo_copy: 55986752Sfjoe pos = 0; 56086752Sfjoe do { 56186752Sfjoe if (data_len) { 56286752Sfjoe slice = min(data_len, sc->framelen - pos); 56386752Sfjoe sbni_outsb(sc, data_p, slice); 56486752Sfjoe *crc_p = calc_crc32(*crc_p, data_p, slice); 56586752Sfjoe 56686752Sfjoe pos += slice; 56786752Sfjoe if (data_len -= slice) 56886752Sfjoe data_p += slice; 56986752Sfjoe else { 570101393Sfjoe do { 571101393Sfjoe m = m->m_next; 572101393Sfjoe } while (m != NULL && m->m_len == 0); 57386752Sfjoe 57486752Sfjoe if (m) { 57586752Sfjoe data_len = m->m_len; 57686752Sfjoe data_p = mtod(m, caddr_t); 57786752Sfjoe } 57886752Sfjoe } 57986752Sfjoe } else { 58086752Sfjoe /* frame too short - zero padding */ 58186752Sfjoe 58286752Sfjoe pos = sc->framelen - pos; 58386752Sfjoe while (pos--) { 58486752Sfjoe sbni_outb(sc, DAT, 0); 58586752Sfjoe *crc_p = CRC32(0, *crc_p); 58686752Sfjoe } 58786752Sfjoe return; 58886752Sfjoe } 58986752Sfjoe } while (pos < sc->framelen); 59086752Sfjoe} 59186752Sfjoe 59286752Sfjoe 59386752Sfjoestatic int 59486752Sfjoeupload_data(struct sbni_softc *sc, u_int framelen, u_int frameno, 59586752Sfjoe u_int is_first, u_int32_t crc) 59686752Sfjoe{ 59786752Sfjoe int frame_ok; 59886752Sfjoe 59986752Sfjoe if (is_first) { 60086752Sfjoe sc->wait_frameno = frameno; 60186752Sfjoe sc->inppos = 0; 60286752Sfjoe } 60386752Sfjoe 60486752Sfjoe if (sc->wait_frameno == frameno) { 60586752Sfjoe 60686752Sfjoe if (sc->inppos + framelen <= ETHER_MAX_LEN) { 60786752Sfjoe frame_ok = append_frame_to_pkt(sc, framelen, crc); 60886752Sfjoe 60986752Sfjoe /* 61086752Sfjoe * if CRC is right but framelen incorrect then transmitter 61186752Sfjoe * error was occured... drop entire packet 61286752Sfjoe */ 61386752Sfjoe } else if ((frame_ok = skip_tail(sc, framelen, crc)) != 0) { 61486752Sfjoe sc->wait_frameno = 0; 61586752Sfjoe sc->inppos = 0; 616147256Sbrooks sc->ifp->if_ierrors++; 61786752Sfjoe /* now skip all frames until is_first != 0 */ 61886752Sfjoe } 61986752Sfjoe } else 62086752Sfjoe frame_ok = skip_tail(sc, framelen, crc); 62186752Sfjoe 62286752Sfjoe if (is_first && !frame_ok) { 62386752Sfjoe /* 62486752Sfjoe * Frame has been violated, but we have stored 62586752Sfjoe * is_first already... Drop entire packet. 62686752Sfjoe */ 62786752Sfjoe sc->wait_frameno = 0; 628147256Sbrooks sc->ifp->if_ierrors++; 62986752Sfjoe } 63086752Sfjoe 63186752Sfjoe return (frame_ok); 63286752Sfjoe} 63386752Sfjoe 63486752Sfjoe 63586752Sfjoestatic __inline void send_complete(struct sbni_softc *); 63686752Sfjoe 63786752Sfjoestatic __inline void 63886752Sfjoesend_complete(struct sbni_softc *sc) 63986752Sfjoe{ 64086752Sfjoe m_freem(sc->tx_buf_p); 64186752Sfjoe sc->tx_buf_p = NULL; 642147256Sbrooks sc->ifp->if_opackets++; 64386752Sfjoe} 64486752Sfjoe 64586752Sfjoe 64686752Sfjoestatic void 64786752Sfjoeinterpret_ack(struct sbni_softc *sc, u_int ack) 64886752Sfjoe{ 64986752Sfjoe if (ack == FRAME_SENT_OK) { 65086752Sfjoe sc->state &= ~FL_NEED_RESEND; 65186752Sfjoe 65286752Sfjoe if (sc->state & FL_WAIT_ACK) { 65386752Sfjoe sc->outpos += sc->framelen; 65486752Sfjoe 655101393Sfjoe if (--sc->tx_frameno) { 656101393Sfjoe sc->framelen = min( 657101393Sfjoe sc->maxframe, sc->pktlen - sc->outpos); 658101393Sfjoe } else { 65986752Sfjoe send_complete(sc); 66086752Sfjoe prepare_to_send(sc); 66186752Sfjoe } 66286752Sfjoe } 66386752Sfjoe } 66486752Sfjoe 66586752Sfjoe sc->state &= ~FL_WAIT_ACK; 66686752Sfjoe} 66786752Sfjoe 66886752Sfjoe 66986752Sfjoe/* 67086752Sfjoe * Glue received frame with previous fragments of packet. 67186752Sfjoe * Indicate packet when last frame would be accepted. 67286752Sfjoe */ 67386752Sfjoe 67486752Sfjoestatic int 67586752Sfjoeappend_frame_to_pkt(struct sbni_softc *sc, u_int framelen, u_int32_t crc) 67686752Sfjoe{ 67786752Sfjoe caddr_t p; 67886752Sfjoe 67986752Sfjoe if (sc->inppos + framelen > ETHER_MAX_LEN) 68086752Sfjoe return (0); 68186752Sfjoe 68286752Sfjoe if (!sc->rx_buf_p && !get_rx_buf(sc)) 68386752Sfjoe return (0); 68486752Sfjoe 68586752Sfjoe p = sc->rx_buf_p->m_data + sc->inppos; 68686752Sfjoe sbni_insb(sc, p, framelen); 68786752Sfjoe if (calc_crc32(crc, p, framelen) != CRC32_REMAINDER) 68886752Sfjoe return (0); 68986752Sfjoe 69086752Sfjoe sc->inppos += framelen - 4; 69186752Sfjoe if (--sc->wait_frameno == 0) { /* last frame received */ 69286752Sfjoe indicate_pkt(sc); 693147256Sbrooks sc->ifp->if_ipackets++; 69486752Sfjoe } 69586752Sfjoe 69686752Sfjoe return (1); 69786752Sfjoe} 69886752Sfjoe 69986752Sfjoe 70086752Sfjoe/* 70186752Sfjoe * Prepare to start output on adapter. Current priority must be set to splimp 70286752Sfjoe * before this routine is called. 70386752Sfjoe * Transmitter will be actually activated when marker has been accepted. 70486752Sfjoe */ 70586752Sfjoe 70686752Sfjoestatic void 70786752Sfjoeprepare_to_send(struct sbni_softc *sc) 70886752Sfjoe{ 70986752Sfjoe struct mbuf *m; 71086752Sfjoe u_int len; 71186752Sfjoe 71286752Sfjoe /* sc->tx_buf_p == NULL here! */ 71386752Sfjoe if (sc->tx_buf_p) 71486752Sfjoe printf("sbni: memory leak!\n"); 71586752Sfjoe 71686752Sfjoe sc->outpos = 0; 71786752Sfjoe sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 71886752Sfjoe 71986752Sfjoe for (;;) { 720147256Sbrooks IF_DEQUEUE(&sc->ifp->if_snd, sc->tx_buf_p); 72186752Sfjoe if (!sc->tx_buf_p) { 72286752Sfjoe /* nothing to transmit... */ 72386752Sfjoe sc->pktlen = 0; 72486752Sfjoe sc->tx_frameno = 0; 72586752Sfjoe sc->framelen = 0; 726148887Srwatson sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 72786752Sfjoe return; 72886752Sfjoe } 72986752Sfjoe 73086752Sfjoe for (len = 0, m = sc->tx_buf_p; m; m = m->m_next) 73186752Sfjoe len += m->m_len; 73286752Sfjoe 73386752Sfjoe if (len != 0) 73486752Sfjoe break; 73586752Sfjoe m_freem(sc->tx_buf_p); 73686752Sfjoe } 73786752Sfjoe 73886752Sfjoe if (len < SBNI_MIN_LEN) 73986752Sfjoe len = SBNI_MIN_LEN; 74086752Sfjoe 74186752Sfjoe sc->pktlen = len; 74286752Sfjoe sc->tx_frameno = (len + sc->maxframe - 1) / sc->maxframe; 74386752Sfjoe sc->framelen = min(len, sc->maxframe); 74486752Sfjoe 74586752Sfjoe sbni_outb(sc, CSR0, sbni_inb(sc, CSR0) | TR_REQ); 746148887Srwatson sc->ifp->if_drv_flags |= IFF_DRV_OACTIVE; 747147256Sbrooks BPF_MTAP(sc->ifp, sc->tx_buf_p); 74886752Sfjoe} 74986752Sfjoe 75086752Sfjoe 75186752Sfjoestatic void 75286752Sfjoedrop_xmit_queue(struct sbni_softc *sc) 75386752Sfjoe{ 75486752Sfjoe struct mbuf *m; 75586752Sfjoe 75686752Sfjoe if (sc->tx_buf_p) { 75786752Sfjoe m_freem(sc->tx_buf_p); 75886752Sfjoe sc->tx_buf_p = NULL; 759147256Sbrooks sc->ifp->if_oerrors++; 76086752Sfjoe } 76186752Sfjoe 76286752Sfjoe for (;;) { 763147256Sbrooks IF_DEQUEUE(&sc->ifp->if_snd, m); 76486752Sfjoe if (m == NULL) 76586752Sfjoe break; 76686752Sfjoe m_freem(m); 767147256Sbrooks sc->ifp->if_oerrors++; 76886752Sfjoe } 76986752Sfjoe 77086752Sfjoe sc->tx_frameno = 0; 77186752Sfjoe sc->framelen = 0; 77286752Sfjoe sc->outpos = 0; 77386752Sfjoe sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 774148887Srwatson sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 77586752Sfjoe} 77686752Sfjoe 77786752Sfjoe 77886752Sfjoestatic void 77986752Sfjoesend_frame_header(struct sbni_softc *sc, u_int32_t *crc_p) 78086752Sfjoe{ 78186752Sfjoe u_int32_t crc; 78286752Sfjoe u_int len_field; 78386752Sfjoe u_char value; 78486752Sfjoe 78586752Sfjoe crc = *crc_p; 78686752Sfjoe len_field = sc->framelen + 6; /* CRC + frameno + reserved */ 78786752Sfjoe 78886752Sfjoe if (sc->state & FL_NEED_RESEND) 78986752Sfjoe len_field |= FRAME_RETRY; /* non-first attempt... */ 79086752Sfjoe 79186752Sfjoe if (sc->outpos == 0) 79286752Sfjoe len_field |= FRAME_FIRST; 79386752Sfjoe 79486752Sfjoe len_field |= (sc->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD; 79586752Sfjoe sbni_outb(sc, DAT, SBNI_SIG); 79686752Sfjoe 79786752Sfjoe value = (u_char)len_field; 79886752Sfjoe sbni_outb(sc, DAT, value); 79986752Sfjoe crc = CRC32(value, crc); 80086752Sfjoe value = (u_char)(len_field >> 8); 80186752Sfjoe sbni_outb(sc, DAT, value); 80286752Sfjoe crc = CRC32(value, crc); 80386752Sfjoe 80486752Sfjoe sbni_outb(sc, DAT, sc->tx_frameno); 80586752Sfjoe crc = CRC32(sc->tx_frameno, crc); 80686752Sfjoe sbni_outb(sc, DAT, 0); 80786752Sfjoe crc = CRC32(0, crc); 80886752Sfjoe *crc_p = crc; 80986752Sfjoe} 81086752Sfjoe 81186752Sfjoe 81286752Sfjoe/* 81386752Sfjoe * if frame tail not needed (incorrect number or received twice), 81486752Sfjoe * it won't store, but CRC will be calculated 81586752Sfjoe */ 81686752Sfjoe 81786752Sfjoestatic int 81886752Sfjoeskip_tail(struct sbni_softc *sc, u_int tail_len, u_int32_t crc) 81986752Sfjoe{ 82086752Sfjoe while (tail_len--) 82186752Sfjoe crc = CRC32(sbni_inb(sc, DAT), crc); 82286752Sfjoe 82386752Sfjoe return (crc == CRC32_REMAINDER); 82486752Sfjoe} 82586752Sfjoe 82686752Sfjoe 82786752Sfjoestatic int 82886752Sfjoecheck_fhdr(struct sbni_softc *sc, u_int *framelen, u_int *frameno, 82986752Sfjoe u_int *ack, u_int *is_first, u_int32_t *crc_p) 83086752Sfjoe{ 83186752Sfjoe u_int32_t crc; 83286752Sfjoe u_char value; 83386752Sfjoe 83486752Sfjoe crc = *crc_p; 83586752Sfjoe if (sbni_inb(sc, DAT) != SBNI_SIG) 83686752Sfjoe return (0); 83786752Sfjoe 83886752Sfjoe value = sbni_inb(sc, DAT); 83986752Sfjoe *framelen = (u_int)value; 84086752Sfjoe crc = CRC32(value, crc); 84186752Sfjoe value = sbni_inb(sc, DAT); 84286752Sfjoe *framelen |= ((u_int)value) << 8; 84386752Sfjoe crc = CRC32(value, crc); 84486752Sfjoe 84586752Sfjoe *ack = *framelen & FRAME_ACK_MASK; 84686752Sfjoe *is_first = (*framelen & FRAME_FIRST) != 0; 84786752Sfjoe 84886752Sfjoe if ((*framelen &= FRAME_LEN_MASK) < 6 || *framelen > SBNI_MAX_FRAME - 3) 84986752Sfjoe return (0); 85086752Sfjoe 85186752Sfjoe value = sbni_inb(sc, DAT); 85286752Sfjoe *frameno = (u_int)value; 85386752Sfjoe crc = CRC32(value, crc); 85486752Sfjoe 85586752Sfjoe crc = CRC32(sbni_inb(sc, DAT), crc); /* reserved byte */ 85686752Sfjoe *framelen -= 2; 85786752Sfjoe 85886752Sfjoe *crc_p = crc; 85986752Sfjoe return (1); 86086752Sfjoe} 86186752Sfjoe 86286752Sfjoe 86386752Sfjoestatic int 86486752Sfjoeget_rx_buf(struct sbni_softc *sc) 86586752Sfjoe{ 86686752Sfjoe struct mbuf *m; 86786752Sfjoe 868111119Simp MGETHDR(m, M_DONTWAIT, MT_DATA); 86986752Sfjoe if (m == NULL) { 870147256Sbrooks if_printf(sc->ifp, "cannot allocate header mbuf\n"); 87186752Sfjoe return (0); 87286752Sfjoe } 87386752Sfjoe 87486752Sfjoe /* 87586752Sfjoe * We always put the received packet in a single buffer - 87686752Sfjoe * either with just an mbuf header or in a cluster attached 87786752Sfjoe * to the header. The +2 is to compensate for the alignment 87886752Sfjoe * fixup below. 87986752Sfjoe */ 88086752Sfjoe if (ETHER_MAX_LEN + 2 > MHLEN) { 88186752Sfjoe /* Attach an mbuf cluster */ 882111119Simp MCLGET(m, M_DONTWAIT); 88386752Sfjoe if ((m->m_flags & M_EXT) == 0) { 88486752Sfjoe m_freem(m); 88586752Sfjoe return (0); 88686752Sfjoe } 88786752Sfjoe } 88886752Sfjoe m->m_pkthdr.len = m->m_len = ETHER_MAX_LEN + 2; 88986752Sfjoe 89086752Sfjoe /* 89186752Sfjoe * The +2 is to longword align the start of the real packet. 89286752Sfjoe * (sizeof ether_header == 14) 89386752Sfjoe * This is important for NFS. 89486752Sfjoe */ 89586752Sfjoe m_adj(m, 2); 89686752Sfjoe sc->rx_buf_p = m; 89786752Sfjoe return (1); 89886752Sfjoe} 89986752Sfjoe 90086752Sfjoe 90186752Sfjoestatic void 90286752Sfjoeindicate_pkt(struct sbni_softc *sc) 90386752Sfjoe{ 904147256Sbrooks struct ifnet *ifp = sc->ifp; 90586752Sfjoe struct mbuf *m; 90686752Sfjoe 90786752Sfjoe m = sc->rx_buf_p; 908106937Ssam m->m_pkthdr.rcvif = ifp; 90986752Sfjoe m->m_pkthdr.len = m->m_len = sc->inppos; 910180263Sjhb sc->rx_buf_p = NULL; 91186752Sfjoe 912180263Sjhb SBNI_UNLOCK(sc); 913106937Ssam (*ifp->if_input)(ifp, m); 914180263Sjhb SBNI_LOCK(sc); 91586752Sfjoe} 91686752Sfjoe 91786752Sfjoe/* -------------------------------------------------------------------------- */ 91886752Sfjoe 91986752Sfjoe/* 92086752Sfjoe * Routine checks periodically wire activity and regenerates marker if 92186752Sfjoe * connect was inactive for a long time. 92286752Sfjoe */ 92386752Sfjoe 92486752Sfjoestatic void 92586752Sfjoesbni_timeout(void *xsc) 92686752Sfjoe{ 92786752Sfjoe struct sbni_softc *sc; 92886752Sfjoe u_char csr0; 92986752Sfjoe 93086752Sfjoe sc = (struct sbni_softc *)xsc; 931180263Sjhb SBNI_ASSERT_LOCKED(sc); 93286752Sfjoe 93386752Sfjoe csr0 = sbni_inb(sc, CSR0); 93486752Sfjoe if (csr0 & RC_CHK) { 93586752Sfjoe 93686752Sfjoe if (sc->timer_ticks) { 93786752Sfjoe if (csr0 & (RC_RDY | BU_EMP)) 93886752Sfjoe /* receiving not active */ 93986752Sfjoe sc->timer_ticks--; 94086752Sfjoe } else { 94186752Sfjoe sc->in_stats.timeout_number++; 94286752Sfjoe if (sc->delta_rxl) 94386752Sfjoe timeout_change_level(sc); 94486752Sfjoe 94586752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 94686752Sfjoe csr0 = sbni_inb(sc, CSR0); 94786752Sfjoe } 94886752Sfjoe } 94986752Sfjoe 950180263Sjhb sbni_outb(sc, CSR0, csr0 | RC_CHK); 951180263Sjhb callout_reset(&sc->wch, hz/SBNI_HZ, sbni_timeout, sc); 95286752Sfjoe} 95386752Sfjoe 95486752Sfjoe/* -------------------------------------------------------------------------- */ 95586752Sfjoe 95686752Sfjoestatic void 95786752Sfjoecard_start(struct sbni_softc *sc) 95886752Sfjoe{ 95986752Sfjoe sc->timer_ticks = CHANGE_LEVEL_START_TICKS; 96086752Sfjoe sc->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); 96186752Sfjoe sc->state |= FL_PREV_OK; 96286752Sfjoe 96386752Sfjoe sc->inppos = 0; 96486752Sfjoe sc->wait_frameno = 0; 96586752Sfjoe 96686752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1 | PR_RES); 96786752Sfjoe sbni_outb(sc, CSR0, EN_INT); 96886752Sfjoe} 96986752Sfjoe 97086752Sfjoe/* -------------------------------------------------------------------------- */ 97186752Sfjoe 97286752Sfjoestatic u_char rxl_tab[] = { 97386752Sfjoe 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 97486752Sfjoe 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f 97586752Sfjoe}; 97686752Sfjoe 97786752Sfjoe#define SIZE_OF_TIMEOUT_RXL_TAB 4 97886752Sfjoestatic u_char timeout_rxl_tab[] = { 97986752Sfjoe 0x03, 0x05, 0x08, 0x0b 98086752Sfjoe}; 98186752Sfjoe 98286752Sfjoestatic void 98386752Sfjoeset_initial_values(struct sbni_softc *sc, struct sbni_flags flags) 98486752Sfjoe{ 98586752Sfjoe if (flags.fixed_rxl) { 98686752Sfjoe sc->delta_rxl = 0; /* disable receive level autodetection */ 98786752Sfjoe sc->cur_rxl_index = flags.rxl; 98886752Sfjoe } else { 98986752Sfjoe sc->delta_rxl = DEF_RXL_DELTA; 99086752Sfjoe sc->cur_rxl_index = DEF_RXL; 99186752Sfjoe } 99286752Sfjoe 99386752Sfjoe sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 99486752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 99586752Sfjoe sc->maxframe = DEFAULT_FRAME_LEN; 99686752Sfjoe 99786752Sfjoe /* 99886752Sfjoe * generate Ethernet address (0x00ff01xxxxxx) 99986752Sfjoe */ 1000147256Sbrooks *(u_int16_t *) sc->enaddr = htons(0x00ff); 1001101400Sfjoe if (flags.mac_addr) { 1002147256Sbrooks *(u_int32_t *) (sc->enaddr + 2) = 1003101400Sfjoe htonl(flags.mac_addr | 0x01000000); 1004101400Sfjoe } else { 1005147256Sbrooks *(u_char *) (sc->enaddr + 2) = 0x01; 1006147256Sbrooks read_random(sc->enaddr + 3, 3); 100786752Sfjoe } 100886752Sfjoe} 100986752Sfjoe 101086752Sfjoe 101186752Sfjoe#ifdef SBNI_DUAL_COMPOUND 1012180263Sjhbvoid 1013180263Sjhbsbni_add(struct sbni_softc *sc) 1014180263Sjhb{ 101586752Sfjoe 1016180263Sjhb mtx_lock(&headlist_lock); 1017180263Sjhb sc->link = sbni_headlist; 1018180263Sjhb sbni_headlist = sc; 1019180263Sjhb mtx_unlock(&headlist_lock); 1020180263Sjhb} 1021180263Sjhb 102286752Sfjoestruct sbni_softc * 102386752Sfjoeconnect_to_master(struct sbni_softc *sc) 102486752Sfjoe{ 1025101400Sfjoe struct sbni_softc *p, *p_prev; 102686752Sfjoe 1027180263Sjhb mtx_lock(&headlist_lock); 1028101400Sfjoe for (p = sbni_headlist, p_prev = NULL; p; p_prev = p, p = p->link) { 1029101400Sfjoe if (rman_get_start(p->io_res) == rman_get_start(sc->io_res) + 4 || 1030101400Sfjoe rman_get_start(p->io_res) == rman_get_start(sc->io_res) - 4) { 1031101400Sfjoe p->slave_sc = sc; 1032101400Sfjoe if (p_prev) 1033101400Sfjoe p_prev->link = p->link; 1034101400Sfjoe else 1035101400Sfjoe sbni_headlist = p->link; 1036180263Sjhb mtx_unlock(&headlist_lock); 1037101400Sfjoe return p; 103886752Sfjoe } 103986752Sfjoe } 1040180263Sjhb mtx_unlock(&headlist_lock); 104186752Sfjoe 104286752Sfjoe return (NULL); 104386752Sfjoe} 104486752Sfjoe 104586752Sfjoe#endif /* SBNI_DUAL_COMPOUND */ 104686752Sfjoe 104786752Sfjoe 104886752Sfjoe/* Receive level auto-selection */ 104986752Sfjoe 105086752Sfjoestatic void 105186752Sfjoechange_level(struct sbni_softc *sc) 105286752Sfjoe{ 105386752Sfjoe if (sc->delta_rxl == 0) /* do not auto-negotiate RxL */ 105486752Sfjoe return; 105586752Sfjoe 105686752Sfjoe if (sc->cur_rxl_index == 0) 105786752Sfjoe sc->delta_rxl = 1; 105886752Sfjoe else if (sc->cur_rxl_index == 15) 105986752Sfjoe sc->delta_rxl = -1; 106086752Sfjoe else if (sc->cur_rxl_rcvd < sc->prev_rxl_rcvd) 106186752Sfjoe sc->delta_rxl = -sc->delta_rxl; 106286752Sfjoe 106386752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index += sc->delta_rxl]; 106486752Sfjoe sbni_inb(sc, CSR0); /* it needed for PCI cards */ 106586752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 106686752Sfjoe 106786752Sfjoe sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 106886752Sfjoe sc->cur_rxl_rcvd = 0; 106986752Sfjoe} 107086752Sfjoe 107186752Sfjoe 107286752Sfjoestatic void 107386752Sfjoetimeout_change_level(struct sbni_softc *sc) 107486752Sfjoe{ 107586752Sfjoe sc->cur_rxl_index = timeout_rxl_tab[sc->timeout_rxl]; 107686752Sfjoe if (++sc->timeout_rxl >= 4) 107786752Sfjoe sc->timeout_rxl = 0; 107886752Sfjoe 107986752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 108086752Sfjoe sbni_inb(sc, CSR0); 108186752Sfjoe sbni_outb(sc, CSR1, *(u_char *)&sc->csr1); 108286752Sfjoe 108386752Sfjoe sc->prev_rxl_rcvd = sc->cur_rxl_rcvd; 108486752Sfjoe sc->cur_rxl_rcvd = 0; 108586752Sfjoe} 108686752Sfjoe 108786752Sfjoe/* -------------------------------------------------------------------------- */ 108886752Sfjoe 108986752Sfjoe/* 109086752Sfjoe * Process an ioctl request. This code needs some work - it looks 109186752Sfjoe * pretty ugly. 109286752Sfjoe */ 109386752Sfjoe 109486752Sfjoestatic int 109586752Sfjoesbni_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 109686752Sfjoe{ 109786752Sfjoe struct sbni_softc *sc; 109886752Sfjoe struct ifreq *ifr; 109993593Sjhb struct thread *td; 110086752Sfjoe struct sbni_in_stats *in_stats; 110186752Sfjoe struct sbni_flags flags; 1102180263Sjhb int error; 110386752Sfjoe 110486752Sfjoe sc = ifp->if_softc; 110586752Sfjoe ifr = (struct ifreq *)data; 110693593Sjhb td = curthread; 110786752Sfjoe error = 0; 110886752Sfjoe 110986752Sfjoe switch (command) { 111086752Sfjoe case SIOCSIFFLAGS: 111186752Sfjoe /* 111286752Sfjoe * If the interface is marked up and stopped, then start it. 111386752Sfjoe * If it is marked down and running, then stop it. 111486752Sfjoe */ 1115180263Sjhb SBNI_LOCK(sc); 111686752Sfjoe if (ifp->if_flags & IFF_UP) { 1117148887Srwatson if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1118180263Sjhb sbni_init_locked(sc); 111986752Sfjoe } else { 1120148887Srwatson if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 112186752Sfjoe sbni_stop(sc); 112286752Sfjoe } 112386752Sfjoe } 1124180263Sjhb SBNI_UNLOCK(sc); 112586752Sfjoe break; 112686752Sfjoe 112786752Sfjoe case SIOCADDMULTI: 112886752Sfjoe case SIOCDELMULTI: 112986752Sfjoe /* 113086752Sfjoe * Multicast list has changed; set the hardware filter 113186752Sfjoe * accordingly. 113286752Sfjoe */ 113386752Sfjoe error = 0; 113486752Sfjoe /* if (ifr == NULL) 113586752Sfjoe error = EAFNOSUPPORT; */ 113686752Sfjoe break; 113786752Sfjoe 113886752Sfjoe /* 113986752Sfjoe * SBNI specific ioctl 114086752Sfjoe */ 114186752Sfjoe case SIOCGHWFLAGS: /* get flags */ 1142180263Sjhb SBNI_LOCK(sc); 1143152315Sru bcopy((caddr_t)IF_LLADDR(sc->ifp)+3, (caddr_t) &flags, 3); 114486752Sfjoe flags.rxl = sc->cur_rxl_index; 114586752Sfjoe flags.rate = sc->csr1.rate; 114686752Sfjoe flags.fixed_rxl = (sc->delta_rxl == 0); 114786752Sfjoe flags.fixed_rate = 1; 1148180263Sjhb SBNI_UNLOCK(sc); 114986752Sfjoe ifr->ifr_data = *(caddr_t*) &flags; 115086752Sfjoe break; 115186752Sfjoe 115286752Sfjoe case SIOCGINSTATS: 1153180263Sjhb in_stats = malloc(sizeof(struct sbni_in_stats), M_DEVBUF, 1154180263Sjhb M_WAITOK); 1155180263Sjhb SBNI_LOCK(sc); 1156180263Sjhb bcopy(&sc->in_stats, in_stats, sizeof(struct sbni_in_stats)); 1157180263Sjhb SBNI_UNLOCK(sc); 1158180263Sjhb error = copyout(ifr->ifr_data, in_stats, 1159180263Sjhb sizeof(struct sbni_in_stats)); 1160180263Sjhb free(in_stats, M_DEVBUF); 116186752Sfjoe break; 116286752Sfjoe 116386752Sfjoe case SIOCSHWFLAGS: /* set flags */ 116486752Sfjoe /* root only */ 1165164033Srwatson error = priv_check(td, PRIV_DRIVER); 116686752Sfjoe if (error) 116786752Sfjoe break; 116886752Sfjoe flags = *(struct sbni_flags*)&ifr->ifr_data; 1169180263Sjhb SBNI_LOCK(sc); 117086752Sfjoe if (flags.fixed_rxl) { 117186752Sfjoe sc->delta_rxl = 0; 117286752Sfjoe sc->cur_rxl_index = flags.rxl; 117386752Sfjoe } else { 117486752Sfjoe sc->delta_rxl = DEF_RXL_DELTA; 117586752Sfjoe sc->cur_rxl_index = DEF_RXL; 117686752Sfjoe } 117786752Sfjoe sc->csr1.rxl = rxl_tab[sc->cur_rxl_index]; 117886752Sfjoe sc->csr1.rate = flags.fixed_rate ? flags.rate : DEFAULT_RATE; 117986752Sfjoe if (flags.mac_addr) 118086752Sfjoe bcopy((caddr_t) &flags, 1181152315Sru (caddr_t) IF_LLADDR(sc->ifp)+3, 3); 118286752Sfjoe 118386752Sfjoe /* Don't be afraid... */ 118486752Sfjoe sbni_outb(sc, CSR1, *(char*)(&sc->csr1) | PR_RES); 1185180263Sjhb SBNI_UNLOCK(sc); 118686752Sfjoe break; 118786752Sfjoe 118886752Sfjoe case SIOCRINSTATS: 1189180263Sjhb SBNI_LOCK(sc); 1190164033Srwatson if (!(error = priv_check(td, PRIV_DRIVER))) /* root only */ 119186752Sfjoe bzero(&sc->in_stats, sizeof(struct sbni_in_stats)); 1192180263Sjhb SBNI_UNLOCK(sc); 119386752Sfjoe break; 119486752Sfjoe 119586752Sfjoe default: 1196106937Ssam error = ether_ioctl(ifp, command, data); 1197106937Ssam break; 119886752Sfjoe } 119986752Sfjoe 120086752Sfjoe return (error); 120186752Sfjoe} 120286752Sfjoe 120386752Sfjoe/* -------------------------------------------------------------------------- */ 120486752Sfjoe 120586752Sfjoe#ifdef ASM_CRC 120686752Sfjoe 120786752Sfjoestatic u_int32_t 120886752Sfjoecalc_crc32(u_int32_t crc, caddr_t p, u_int len) 120986752Sfjoe{ 121086752Sfjoe register u_int32_t _crc __asm ("ax"); 121186752Sfjoe _crc = crc; 121286752Sfjoe 121386752Sfjoe __asm __volatile ( 121486752Sfjoe "xorl %%ebx, %%ebx\n" 121586752Sfjoe "movl %1, %%esi\n" 121686752Sfjoe "movl %2, %%ecx\n" 121786752Sfjoe "movl $crc32tab, %%edi\n" 121886752Sfjoe "shrl $2, %%ecx\n" 121986752Sfjoe "jz 1f\n" 122086752Sfjoe 122186752Sfjoe ".align 4\n" 122286752Sfjoe "0:\n" 122386752Sfjoe "movb %%al, %%bl\n" 122486752Sfjoe "movl (%%esi), %%edx\n" 122586752Sfjoe "shrl $8, %%eax\n" 122686752Sfjoe "xorb %%dl, %%bl\n" 122786752Sfjoe "shrl $8, %%edx\n" 122886752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 122986752Sfjoe 123086752Sfjoe "movb %%al, %%bl\n" 123186752Sfjoe "shrl $8, %%eax\n" 123286752Sfjoe "xorb %%dl, %%bl\n" 123386752Sfjoe "shrl $8, %%edx\n" 123486752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 123586752Sfjoe 123686752Sfjoe "movb %%al, %%bl\n" 123786752Sfjoe "shrl $8, %%eax\n" 123886752Sfjoe "xorb %%dl, %%bl\n" 123986752Sfjoe "movb %%dh, %%dl\n" 124086752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 124186752Sfjoe 124286752Sfjoe "movb %%al, %%bl\n" 124386752Sfjoe "shrl $8, %%eax\n" 124486752Sfjoe "xorb %%dl, %%bl\n" 124586752Sfjoe "addl $4, %%esi\n" 124686752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 124786752Sfjoe 124886752Sfjoe "decl %%ecx\n" 124986752Sfjoe "jnz 0b\n" 125086752Sfjoe 125186752Sfjoe "1:\n" 125286752Sfjoe "movl %2, %%ecx\n" 125386752Sfjoe "andl $3, %%ecx\n" 125486752Sfjoe "jz 2f\n" 125586752Sfjoe 125686752Sfjoe "movb %%al, %%bl\n" 125786752Sfjoe "shrl $8, %%eax\n" 125886752Sfjoe "xorb (%%esi), %%bl\n" 125986752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 126086752Sfjoe 126186752Sfjoe "decl %%ecx\n" 126286752Sfjoe "jz 2f\n" 126386752Sfjoe 126486752Sfjoe "movb %%al, %%bl\n" 126586752Sfjoe "shrl $8, %%eax\n" 126686752Sfjoe "xorb 1(%%esi), %%bl\n" 126786752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 126886752Sfjoe 126986752Sfjoe "decl %%ecx\n" 127086752Sfjoe "jz 2f\n" 127186752Sfjoe 127286752Sfjoe "movb %%al, %%bl\n" 127386752Sfjoe "shrl $8, %%eax\n" 127486752Sfjoe "xorb 2(%%esi), %%bl\n" 127586752Sfjoe "xorl (%%edi,%%ebx,4), %%eax\n" 127686752Sfjoe "2:\n" 1277117433Skan : "=a" (_crc) 1278117433Skan : "g" (p), "g" (len) 1279117433Skan : "bx", "cx", "dx", "si", "di" 128086752Sfjoe ); 128186752Sfjoe 128286752Sfjoe return (_crc); 128386752Sfjoe} 128486752Sfjoe 128586752Sfjoe#else /* ASM_CRC */ 128686752Sfjoe 128786752Sfjoestatic u_int32_t 128886752Sfjoecalc_crc32(u_int32_t crc, caddr_t p, u_int len) 128986752Sfjoe{ 129086752Sfjoe while (len--) 129186752Sfjoe crc = CRC32(*p++, crc); 129286752Sfjoe 129386752Sfjoe return (crc); 129486752Sfjoe} 129586752Sfjoe 129686752Sfjoe#endif /* ASM_CRC */ 129786752Sfjoe 129886752Sfjoe 1299103844Salfredstatic u_int32_t crc32tab[] __aligned(8) = { 130086752Sfjoe 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37, 130186752Sfjoe 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E, 130286752Sfjoe 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605, 130386752Sfjoe 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C, 130486752Sfjoe 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53, 130586752Sfjoe 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A, 130686752Sfjoe 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661, 130786752Sfjoe 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278, 130886752Sfjoe 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF, 130986752Sfjoe 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6, 131086752Sfjoe 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD, 131186752Sfjoe 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4, 131286752Sfjoe 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B, 131386752Sfjoe 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82, 131486752Sfjoe 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9, 131586752Sfjoe 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0, 131686752Sfjoe 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7, 131786752Sfjoe 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE, 131886752Sfjoe 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795, 131986752Sfjoe 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C, 132086752Sfjoe 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3, 132186752Sfjoe 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA, 132286752Sfjoe 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1, 132386752Sfjoe 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8, 132486752Sfjoe 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F, 132586752Sfjoe 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76, 132686752Sfjoe 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D, 132786752Sfjoe 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344, 132886752Sfjoe 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B, 132986752Sfjoe 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12, 133086752Sfjoe 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739, 133186752Sfjoe 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320, 133286752Sfjoe 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17, 133386752Sfjoe 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E, 133486752Sfjoe 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525, 133586752Sfjoe 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C, 133686752Sfjoe 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73, 133786752Sfjoe 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A, 133886752Sfjoe 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541, 133986752Sfjoe 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158, 134086752Sfjoe 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF, 134186752Sfjoe 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6, 134286752Sfjoe 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED, 134386752Sfjoe 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4, 134486752Sfjoe 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB, 134586752Sfjoe 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2, 134686752Sfjoe 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589, 134786752Sfjoe 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190, 134886752Sfjoe 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87, 134986752Sfjoe 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E, 135086752Sfjoe 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5, 135186752Sfjoe 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC, 135286752Sfjoe 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3, 135386752Sfjoe 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA, 135486752Sfjoe 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1, 135586752Sfjoe 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8, 135686752Sfjoe 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F, 135786752Sfjoe 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856, 135886752Sfjoe 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D, 135986752Sfjoe 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064, 136086752Sfjoe 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B, 136186752Sfjoe 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832, 136286752Sfjoe 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419, 136386752Sfjoe 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000 136486752Sfjoe}; 1365