Annotation of Net2/arch/i386/isa/if_we.c, revision 1.1.1.3

1.1       root        1: /*-
                      2:  * Copyright (c) 1990 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * This code is derived from software contributed to Berkeley by
                      6:  * Tim L. Tucker.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. All advertising materials mentioning features or use of this software
                     17:  *    must display the following acknowledgement:
                     18:  *     This product includes software developed by the University of
                     19:  *     California, Berkeley and its contributors.
                     20:  * 4. Neither the name of the University nor the names of its contributors
                     21:  *    may be used to endorse or promote products derived from this software
                     22:  *    without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  *
                     36:  *     @(#)if_we.c     7.3 (Berkeley) 5/21/91
1.1.1.3 ! root       37:  *
        !            38:  * PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
        !            39:  * --------------------         -----   ----------------------
        !            40:  * CURRENT PATCH LEVEL:         3       00047
        !            41:  * --------------------         -----   ----------------------
        !            42:  *
        !            43:  * 20 Sep 92   Barry Lustig            WD8013 16 bit mode -- enable
        !            44:  *                                             with "option WD8013".
        !            45:  * 19 Sep 92   Michael Galassi         Fixed multiboard routing
        !            46:  * 09 Sep 92   Mike Durkin             Fix Danpex EW-2016 & other 8013 clones
1.1       root       47:  */
                     48: 
                     49: /*
                     50:  * Modification history
                     51:  *
                     52:  * 8/28/89 - Initial version(if_wd.c), Tim L Tucker
1.1.1.3 ! root       53:  *
        !            54:  * 92.09.19 - Changes to allow multiple we interfaces in one box.
        !            55:  *          Allowed interupt handler to look at unit other than 0
        !            56:  *            Bdry was static, made it into an array w/ one entry per
        !            57:  *          interface.  [email protected] (Michael Galassi)
        !            58:  *
        !            59:  * BPF Packet Filter Support added by Marc Frajola, 12/30/92
        !            60:  * Input & other routines re-written by David Greenman, 1/2/93
        !            61:  * BPF trailer support added by David Greenman, 1/7/93
        !            62:  *
        !            63:  * $Log: if_we.c,v $
        !            64:  * Revision 1.5  1993/04/10 15:58:56  glass
        !            65:  * Fixed so they are useable when compiled with options NS.  Not that I know
        !            66:  * anyone who will.....
        !            67:  *
        !            68:  * Revision 1.4  1993/04/08  08:26:54  deraadt
        !            69:  * dmesg output at boottime now tries to print out information as
        !            70:  * soon as it is available. The output looks much more like Sunos.
        !            71:  *
        !            72:  * Revision 1.3  1993/03/24  23:54:19  cgd
        !            73:  * brought in drivers from David Greenman's ([email protected])
        !            74:  * BPF package
        !            75:  *
        !            76:  * Revision 1.2  93/02/18  17:21:57  davidg
        !            77:  * Bugs in mbuf cluster allocation fixed
        !            78:  * Problem with nfs wanting mbufs aligned on longword boundries fixed
        !            79:  * 
1.1       root       80:  */
                     81:  
                     82: #include "we.h"
                     83: #if    NWE > 0
                     84: /*
                     85:  * Western Digital 8003 ethernet/starlan adapter
                     86:  *
                     87:  * Supports the following interface cards:
                     88:  * WD8003E, WD8003EBT, WD8003S, WD8003SBT, WD8013EBT
                     89:  *
                     90:  * The Western Digital card is one of many AT/MCA ethernet interfaces
                     91:  * based on the National DS8390 Network Interface chip set.
                     92:  */
                     93: #include "param.h"
                     94: #include "mbuf.h"
                     95: #include "socket.h"
                     96: #include "ioctl.h"
                     97: #include "errno.h"
                     98: #include "syslog.h"
                     99: 
                    100: #include "net/if.h"
1.1.1.3 ! root      101: #include "net/if_types.h"
        !           102: #include "net/if_dl.h"
1.1       root      103: #include "net/netisr.h"
                    104: 
                    105: #ifdef INET
                    106: #include "netinet/in.h"
                    107: #include "netinet/in_systm.h"
                    108: #include "netinet/in_var.h"
                    109: #include "netinet/ip.h"
                    110: #include "netinet/if_ether.h"
                    111: #endif
                    112: 
                    113: #ifdef NS
                    114: #include "netns/ns.h"
                    115: #include "netns/ns_if.h"
                    116: #endif
                    117: 
1.1.1.3 ! root      118: #include "bpfilter.h"
        !           119: #if NBPFILTER > 0
        !           120: #include "net/bpf.h"
        !           121: #include "net/bpfdesc.h"
        !           122: #endif
        !           123: 
1.1.1.2   root      124: #include "i386/isa/isa.h"
1.1       root      125: #include "i386/isa/if_wereg.h"
                    126: #include "i386/isa/isa_device.h"
1.1.1.2   root      127: #include "i386/isa/icu.h"
1.1.1.3 ! root      128: #if 0
        !           129: #include "i386/include/pio.h"
        !           130: #endif
        !           131: 
        !           132: static inline char *we_ring_copy();
1.1       root      133:  
                    134: /*
                    135:  * This constant should really be 60 because the we adds 4 bytes of crc.
1.1.1.2   root      136:  * However when set to 60 our packets are ignored by deunas , 3coms are
1.1       root      137:  * okay ??????????????????????????????????????????
                    138:  */
                    139: #define ETHER_MIN_LEN 64
                    140: #define        ETHER_ADDR_LEN 6
                    141: #define ETHER_HDR_SIZE 14
                    142:  
                    143: /*
                    144:  * Ethernet software status per interface.
                    145:  *
                    146:  * Each interface is referenced by a network interface structure,
                    147:  * qe_if, which the routing code uses to locate the interface.
                    148:  * This structure contains the output queue for the interface, its address, ...
                    149:  */
                    150: struct we_softc {
                    151:        struct  arpcom we_ac;           /* Ethernet common part         */
                    152: #define        we_if   we_ac.ac_if             /* network-visible interface    */
                    153: #define        we_addr we_ac.ac_enaddr         /* hardware Ethernet address    */
1.1.1.3 ! root      154: #define        ns_addrp we_ac.ac_enaddr                /* hardware Ethernet address    */
1.1       root      155:        u_char  we_flags;               /* software state               */
                    156: #define        WDF_RUNNING     0x01
                    157: #define WDF_TXBUSY     0x02
1.1.1.3 ! root      158: #if NBPFILTER > 0
        !           159: #define        WDF_ATTACHED    0x80
        !           160: #endif
1.1       root      161: 
                    162:        u_char  we_type;                /* interface type code          */
                    163:        u_short we_vector;              /* interrupt vector             */
                    164:        short   we_io_ctl_addr;         /* i/o bus address, control     */
                    165:        short   we_io_nic_addr;         /* i/o bus address, DS8390      */
                    166: 
                    167:        caddr_t we_vmem_addr;           /* card RAM virtual memory base */
                    168:        u_long  we_vmem_size;           /* card RAM bytes               */
                    169:        caddr_t we_vmem_ring;           /* receive ring RAM vaddress    */
                    170:        caddr_t we_vmem_end;            /* receive ring RAM end */
1.1.1.3 ! root      171:        caddr_t we_bpf;                 /* Magic Cookie for BPF */
1.1       root      172: } we_softc[NWE];
                    173: 
                    174: int    weprobe(), weattach(), weintr(), westart();
                    175: int    weinit(), ether_output(), weioctl(), wereset(), wewatchdog();
                    176: 
                    177: struct isa_driver wedriver = {
                    178:        weprobe, weattach, "we",
                    179: };
                    180:  
1.1.1.2   root      181: static unsigned short wemask[] =
                    182:        { IRQ9, IRQ3, IRQ5, IRQ7, IRQ10, IRQ11, IRQ15, IRQ4 };
                    183:        
1.1       root      184: /*
1.1.1.2   root      185:  * Probe the WD8003 to see if its there
1.1       root      186:  */
                    187: weprobe(is)
                    188:        struct isa_device *is;
                    189: {
                    190:        register int i;
                    191:        register struct we_softc *sc = &we_softc[is->id_unit];
                    192:        union we_mem_sel wem;
                    193:        u_char sum;
1.1.1.3 ! root      194: #ifdef WD8013                                          /* 20 Sep 92*/
        !           195:        union we_laar laar;
        !           196: 
        !           197:        laar.laar_byte = 0;
        !           198: #endif /* WD8013*/
        !           199: 
        !           200:        wem.ms_byte = 0;                                /* 20 Sep 92*/
1.1       root      201:  
1.1.1.2   root      202:        /* reset card to force it into a known state. */
                    203:        outb(is->id_iobase, 0x80);
                    204:        DELAY(100);
                    205:        outb(is->id_iobase, 0x00);
                    206:        /* wait in the case this card is reading it's EEROM */
                    207:        DELAY(5000);
                    208: 
1.1.1.3 ! root      209: #ifdef WD8013                                          /* 20 Sep 92*/
        !           210:        /* allow the NIC to access the shared RAM 16 bits at a time */
        !           211: 
        !           212:        laar.addr_l19 = 1;
        !           213:        laar.lan_16_en = 1;
        !           214:        laar.mem_16_en = 1;
        !           215:        outb(is->id_iobase+5, laar.laar_byte);  /* Write a 0xc1 */
        !           216: #endif /* WD8013*/
        !           217: 
1.1       root      218:        /*
                    219:         * Here we check the card ROM, if the checksum passes, and the
                    220:         * type code and ethernet address check out, then we know we have
                    221:         * a wd8003 card.
                    222:         *
                    223:         * Autoconfiguration: No warning message is printed on error.
                    224:         */
                    225:        for (sum = 0, i = 0; i < 8; ++i)
                    226:            sum += inb(is->id_iobase + WD_ROM_OFFSET + i);
1.1.1.3 ! root      227:        if (sum != WD_CHECKSUM) {               /* 09 Sep 92*/
        !           228: #ifdef WECOMPAT
        !           229:            printf( "we: probe: checksum failed... installing anyway\n");
        !           230:            printf( "we: Danpex EW-2016 or other 8013 clone card?\n");
        !           231: #else  /* !WECOMPAT*/
1.1       root      232:             return (0);
1.1.1.3 ! root      233: #endif /* !WECOMPAT*/
        !           234:        }
1.1       root      235:        sc->we_type = inb(is->id_iobase + WD_ROM_OFFSET + 6);
1.1.1.2   root      236: #ifdef nope
                    237:        if ((sc->we_type & WD_REVMASK) != 2             /* WD8003E or WD8003S */
                    238:                && (sc->we_type & WD_REVMASK) != 4      /* WD8003EBT */
                    239:                && (sc->we_type & WD_REVMASK) != 6)        /* WD8003ELB? */
1.1       root      240:             return (0);
1.1.1.2   root      241: #endif
                    242: /*printf("type %x ", sc->we_type);*/
                    243:        if (sc->we_type & WD_SOFTCONFIG) {
                    244:                int iv = inb(is->id_iobase + 1) & 4 |
                    245:                        ((inb(is->id_iobase+4) & 0x60) >> 5);
                    246: /*printf("iv %d ", iv);*/
                    247:                if (wemask[iv] != is->id_irq)
                    248:                        return(0);
                    249:                outb(is->id_iobase+4, inb(is->id_iobase+4) | 0x80);
                    250:        }
1.1       root      251: 
                    252:        /*
                    253:         * Setup card RAM area and i/o addresses
                    254:         * Kernel Virtual to segment C0000-DFFFF?????
                    255:         */
                    256:        sc->we_io_ctl_addr = is->id_iobase;
                    257:        sc->we_io_nic_addr = sc->we_io_ctl_addr + WD_NIC_OFFSET;
                    258:        sc->we_vector = is->id_irq;
                    259:        sc->we_vmem_addr = (caddr_t)is->id_maddr;
                    260:        sc->we_vmem_size = is->id_msize;
                    261:        sc->we_vmem_ring = sc->we_vmem_addr + (WD_PAGE_SIZE * WD_TXBUF_SIZE);
                    262:        sc->we_vmem_end = sc->we_vmem_addr + is->id_msize;
                    263: 
                    264:        /*
                    265:         * Save board ROM station address
                    266:         */
                    267:        for (i = 0; i < ETHER_ADDR_LEN; ++i)
                    268:            sc->we_addr[i] = inb(sc->we_io_ctl_addr + WD_ROM_OFFSET + i);
                    269: 
                    270:        /*
                    271:         * Mapin interface memory, setup memory select register
                    272:         */
1.1.1.2   root      273:         wem.ms_addr = kvtop(sc->we_vmem_addr) >> 13;
1.1       root      274:        wem.ms_enable = 1;
                    275:        wem.ms_reset = 0;
                    276:        outb(sc->we_io_ctl_addr, wem.ms_byte);
                    277: 
                    278:        /*
                    279:         * clear interface memory, then sum to make sure its valid
                    280:         */
                    281:        for (i = 0; i < sc->we_vmem_size; ++i)
                    282:            sc->we_vmem_addr[i] = 0x0;
                    283:        for (sum = 0, i = 0; i < sc->we_vmem_size; ++i)
                    284:            sum += sc->we_vmem_addr[i];
                    285:        if (sum != 0x0) {
                    286:             printf("we%d: wd8003 dual port RAM address error\n", is->id_unit);
                    287:            return (0);
                    288:        }
                    289: 
                    290:        return (WD_IO_PORTS);
                    291: }
                    292:  
                    293: /*
                    294:  * Interface exists: make available by filling in network interface
                    295:  * record.  System will initialize the interface when it is ready
                    296:  * to accept packets.
                    297:  */
                    298: weattach(is)
                    299:        struct isa_device *is;
                    300: {
                    301:        register struct we_softc *sc = &we_softc[is->id_unit];
                    302:        register struct ifnet *ifp = &sc->we_if;
                    303:        union we_command wecmd;
1.1.1.3 ! root      304:        struct ifaddr *ifa;
        !           305:        struct sockaddr_dl *sdl;
1.1       root      306:  
                    307:        wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
                    308:        wecmd.cs_stp = 1;
                    309:        wecmd.cs_sta = 0;
                    310:        wecmd.cs_ps = 0;
                    311:        outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
                    312:        /*
                    313:         * Initialize ifnet structure
                    314:         */
                    315:        ifp->if_unit = is->id_unit;
                    316:        ifp->if_name = "we" ;
                    317:        ifp->if_mtu = ETHERMTU;
                    318:        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS ;
                    319:        ifp->if_init = weinit;
                    320:        ifp->if_output = ether_output;
                    321:        ifp->if_start = westart;
                    322:        ifp->if_ioctl = weioctl;
                    323:        ifp->if_reset = wereset;
                    324:        ifp->if_watchdog = wewatchdog;
                    325:        if_attach(ifp);
1.1.1.3 ! root      326:        /* Search down the ifa address list looking for the AF_LINK type entry */
        !           327:        ifa = ifp->if_addrlist;
        !           328:        while ((ifa != 0) &&
        !           329:               (ifa->ifa_addr != 0) &&
        !           330:               (ifa->ifa_addr->sa_family != AF_LINK))
        !           331:                {
        !           332:                ifa = ifa->ifa_next;
        !           333:                }
        !           334:        /* If we find an AF_LINK type entry, we well fill in the hardware addr */
        !           335:        if ((ifa != 0) &&
        !           336:            (ifa->ifa_addr != 0))
        !           337:                {
        !           338:                /* Fill in the link level address for this interface */
        !           339:                sdl = (struct sockaddr_dl *)ifa->ifa_addr;
        !           340:                sdl->sdl_type = IFT_ETHER;
        !           341:                sdl->sdl_alen = ETHER_ADDR_LEN;
        !           342:                sdl->sdl_slen = 0;
        !           343:                bcopy(sc->we_addr, LLADDR(sdl), ETHER_ADDR_LEN);
        !           344:                }
        !           345: 
        !           346: #if NBPFILTER > 0
        !           347:        sc->we_flags &= ~WDF_ATTACHED;  /* Make sure BPF attach flag clear */
        !           348: #endif
1.1       root      349:  
                    350:        /*
                    351:         * Banner...
                    352:         */
1.1.1.3 ! root      353:        printf("we%d: %saddr %s\n", is->id_unit,
        !           354:                (sc->we_type & WD_ETHERNET) ? "enet" : "slan",
1.1       root      355:                ether_sprintf(sc->we_addr));
                    356: }
                    357:  
                    358: /*
                    359:  * Reset of interface.
                    360:  */
                    361: wereset(unit, uban)
                    362:        int unit, uban;
                    363: {
                    364:        if (unit >= NWE)
                    365:                return;
                    366:        printf("we%d: reset\n", unit);
                    367: /*     we_softc[unit].we_flags &= ~WDF_RUNNING; */
                    368:        weinit(unit);
                    369: }
                    370:  
                    371: /*
                    372:  * Take interface offline.
                    373:  */
                    374: westop(unit)
                    375:        int unit;
                    376: {
                    377:        register struct we_softc *sc = &we_softc[unit];
                    378:        union we_command wecmd;
                    379:        int s;
                    380:  
                    381:        /*
                    382:         * Shutdown DS8390
                    383:         */
                    384:        s = splimp();
                    385:        wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
                    386:        wecmd.cs_stp = 1;
                    387:        wecmd.cs_sta = 0;
                    388:        wecmd.cs_ps = 0;
                    389:        outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
                    390:        (void) splx(s);
                    391: }
                    392: 
                    393: wewatchdog(unit) {
                    394: 
1.1.1.3 ! root      395:        weintr(unit);
        !           396:        /*log(LOG_WARNING,"we%d: soft reset\n", unit);
1.1       root      397:        westop(unit);
1.1.1.3 ! root      398:        weinit(unit);*/
1.1       root      399: }
                    400: 
1.1.1.3 ! root      401: static Bdry[NWE];                                      /* 19 Sep 92*/
1.1       root      402: /*
                    403:  * Initialization of interface (really just DS8390). 
                    404:  */
                    405: weinit(unit)
                    406:        int unit;
                    407: {
                    408:        register struct we_softc *sc = &we_softc[unit];
                    409:        register struct ifnet *ifp = &sc->we_if;
                    410:        union we_command wecmd;
                    411:        int i, s;
1.1.1.3 ! root      412: 
        !           413: #if NBPFILTER > 0
        !           414:        if ((sc->we_flags & WDF_ATTACHED) == 0) {
        !           415:                bpfattach(&sc->we_bpf, ifp, DLT_EN10MB,
        !           416:                        sizeof(struct ether_header));
        !           417:                sc->we_flags |= WDF_ATTACHED;
        !           418:        }
        !           419: #endif
        !           420: 
1.1       root      421:        /* address not known */
                    422:        if (ifp->if_addrlist == (struct ifaddr *)0)
                    423:                return;
                    424: 
                    425:        /* already running */
                    426:        /*if (ifp->if_flags & IFF_RUNNING) return; */
                    427: 
                    428:        /*
                    429:         * Initialize DS8390 in order given in NSC NIC manual.
                    430:         * this is stock code...please see the National manual for details.
                    431:         */
                    432:        s = splhigh();
1.1.1.3 ! root      433:        Bdry[unit] = 0;                                 /* 19 Sep 92*/
1.1       root      434:        wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
                    435:        wecmd.cs_stp = 1;
                    436:        wecmd.cs_sta = 0;
                    437:        wecmd.cs_ps = 0;
                    438:        outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
1.1.1.3 ! root      439: #ifdef WD8013                                          /* 20 Sep 92*/
        !           440:        /* enable 16 bit access if 8013 card */
        !           441:        outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG16);
        !           442: #else  /* !WD8013*/
1.1       root      443:        outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG);
1.1.1.3 ! root      444: #endif /* !WD8013*/
1.1       root      445:        outb(sc->we_io_nic_addr + WD_P0_RBCR0, 0);
                    446:        outb(sc->we_io_nic_addr + WD_P0_RBCR1, 0);
                    447:        outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_MON);
                    448:        outb(sc->we_io_nic_addr + WD_P0_TCR, WD_T_CONFIG);
                    449:        outb(sc->we_io_nic_addr + WD_P0_TPSR, 0);
                    450:        outb(sc->we_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE);
                    451:        outb(sc->we_io_nic_addr + WD_P0_PSTOP,
                    452:                sc->we_vmem_size / WD_PAGE_SIZE);
                    453:        outb(sc->we_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE);
                    454:        outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff);
                    455:        outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG);
                    456:        wecmd.cs_ps = 1;
                    457:        outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
                    458:        for (i = 0; i < ETHER_ADDR_LEN; ++i)
                    459:            outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]);
                    460:        for (i = 0; i < ETHER_ADDR_LEN; ++i)    /* == broadcast addr */
                    461:            outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff);
                    462:        outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE);
                    463:        wecmd.cs_ps = 0;
                    464:        wecmd.cs_stp = 0;
                    465:        wecmd.cs_sta = 1;
                    466:        wecmd.cs_rd = 0x4;
                    467:        outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte);
1.1.1.3 ! root      468: #if NBPFILTER > 0
        !           469:        if (sc->we_if.if_flags & IFF_PROMISC) {
        !           470:                outb(sc->we_io_nic_addr + WD_P0_RCR,
        !           471:                         WD_R_PRO | WD_R_SEP | WD_R_AR | WD_R_CONFIG);
        !           472:        } else
        !           473: #endif
        !           474:                outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG);
1.1       root      475: 
                    476:        /*
                    477:         * Take the interface out of reset, program the vector, 
                    478:         * enable interrupts, and tell the world we are up.
                    479:         */
                    480:        ifp->if_flags |= IFF_RUNNING;
                    481:        sc->we_flags &= ~WDF_TXBUSY;
                    482:        (void) splx(s);
                    483:        westart(ifp);
                    484: }
                    485:  
                    486: /*
                    487:  * Start output on interface.
                    488:  */
                    489: westart(ifp)
                    490:        struct ifnet *ifp;
                    491: {
                    492:        register struct we_softc *sc = &we_softc[ifp->if_unit];
                    493:        struct mbuf *m0, *m;
                    494:        register caddr_t buffer;
                    495:        int len, s;
                    496:        union we_command wecmd;
1.1.1.3 ! root      497: 
1.1       root      498:        /*
                    499:         * The DS8390 has only one transmit buffer, if it is busy we
                    500:         * must wait until the transmit interrupt completes.
                    501:         */
                    502:        s = splhigh();
1.1.1.3 ! root      503: 
1.1       root      504:        if (sc->we_flags & WDF_TXBUSY) {
                    505:                (void) splx(s);
                    506:                return;
                    507:        }
                    508:        IF_DEQUEUE(&sc->we_if.if_snd, m);
                    509:        if (m == 0) {
                    510:                (void) splx(s);
                    511:                return;
                    512:        }
                    513:        sc->we_flags |= WDF_TXBUSY; 
1.1.1.3 ! root      514: 
1.1       root      515:        (void) splx(s);
                    516: 
1.1.1.3 ! root      517: #if NBPFILTER > 0
        !           518:        if (sc->we_bpf) {
        !           519:                u_short etype;
        !           520:                int off, datasize, resid;
        !           521:                struct ether_header *eh;
        !           522:                struct trailer_header {
        !           523:                        u_short ether_type;
        !           524:                        u_short ether_residual;
        !           525:                } trailer_header;
        !           526:                char ether_packet[ETHERMTU+100];
        !           527:                char *ep;
        !           528: 
        !           529:                ep = ether_packet;
        !           530: 
        !           531:                /*
        !           532:                 * We handle trailers below:
        !           533:                 * Copy ether header first, then residual data,
        !           534:                 * then data. Put all this in a temporary buffer
        !           535:                 * 'ether_packet' and send off to bpf. Since the
        !           536:                 * system has generated this packet, we assume
        !           537:                 * that all of the offsets in the packet are
        !           538:                 * correct; if they're not, the system will almost
        !           539:                 * certainly crash in m_copydata.
        !           540:                 * We make no assumptions about how the data is
        !           541:                 * arranged in the mbuf chain (i.e. how much
        !           542:                 * data is in each mbuf, if mbuf clusters are
        !           543:                 * used, etc.), which is why we use m_copydata
        !           544:                 * to get the ether header rather than assume
        !           545:                 * that this is located in the first mbuf.
        !           546:                 */
        !           547:                /* copy ether header */
        !           548:                m_copydata(m, 0, sizeof(struct ether_header), ep);
        !           549:                eh = (struct ether_header *) ep;
        !           550:                ep += sizeof(struct ether_header);
        !           551:                etype = ntohs(eh->ether_type);
        !           552:                if (etype >= ETHERTYPE_TRAIL &&
        !           553:                    etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
        !           554:                        datasize = ((etype - ETHERTYPE_TRAIL) << 9);
        !           555:                        off = datasize + sizeof(struct ether_header);
        !           556: 
        !           557:                        /* copy trailer_header into a data structure */
        !           558:                        m_copydata(m, off, sizeof(struct trailer_header),
        !           559:                                &trailer_header.ether_type);
        !           560: 
        !           561:                        /* copy residual data */
        !           562:                        m_copydata(m, off+sizeof(struct trailer_header),
        !           563:                                resid = ntohs(trailer_header.ether_residual) -
        !           564:                                sizeof(struct trailer_header), ep);
        !           565:                        ep += resid;
        !           566: 
        !           567:                        /* copy data */
        !           568:                        m_copydata(m, sizeof(struct ether_header), datasize, ep);
        !           569:                        ep += datasize;
        !           570: 
        !           571:                        /* restore original ether packet type */
        !           572:                        eh->ether_type = trailer_header.ether_type;
        !           573: 
        !           574:                        bpf_tap(sc->we_bpf, ether_packet, ep - ether_packet);
        !           575:                } else
        !           576:                        bpf_mtap(sc->we_bpf, m);
        !           577:        }
        !           578: #endif
        !           579: 
1.1       root      580:        /*
                    581:         * Copy the mbuf chain into the transmit buffer
                    582:         */
                    583:        buffer = sc->we_vmem_addr;
                    584:        len = 0;
                    585:        for (m0 = m; m != 0; m = m->m_next) {
                    586:                bcopy(mtod(m, caddr_t), buffer, m->m_len);
                    587:                buffer += m->m_len;
                    588:                len += m->m_len;
                    589:        }
                    590: 
                    591:        m_freem(m0);
                    592: 
                    593:        /*
                    594:         * Init transmit length registers, and set transmit start flag.
                    595:         */
                    596:        s = splhigh();
                    597:        len = MAX(len, ETHER_MIN_LEN);
                    598:        wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
                    599:        wecmd.cs_ps = 0;
                    600:        outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
                    601:        outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff);
                    602:        outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8);
                    603:        wecmd.cs_txp = 1;
                    604:        outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
1.1.1.3 ! root      605:        sc->we_if.if_timer = 3;
1.1       root      606:        (void) splx(s);
                    607: }
                    608:  
                    609: /*
                    610:  * Ethernet interface interrupt processor
                    611:  */
                    612: weintr(unit)
                    613:        int unit;
                    614: {
                    615:        register struct we_softc *sc = &we_softc[unit];
                    616:        union we_command wecmd;
                    617:        union we_interrupt weisr;
                    618: 
                    619:  
                    620:        /* disable onboard interrupts, then get interrupt status */
                    621:        wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
                    622:        wecmd.cs_ps = 0;
                    623:        outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
                    624:        weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
                    625: loop:
                    626:        outb(sc->we_io_nic_addr + WD_P0_ISR, weisr.is_byte);
                    627: 
                    628:        /* transmit error */
                    629:        if (weisr.is_txe) {
                    630:                /* need to read these registers to clear status */
                    631:                sc->we_if.if_collisions +=
                    632:                    inb(sc->we_io_nic_addr + WD_P0_TBCR0);
                    633:                ++sc->we_if.if_oerrors;
                    634:        }
                    635: 
                    636:        /* receiver error */
                    637:        if (weisr.is_rxe) {
                    638:                /* need to read these registers to clear status */
                    639:                (void) inb(sc->we_io_nic_addr + 0xD);
                    640:                (void) inb(sc->we_io_nic_addr + 0xE);
                    641:                (void) inb(sc->we_io_nic_addr + 0xF);
                    642:                ++sc->we_if.if_ierrors;
                    643:        }
                    644: 
                    645:        /* normal transmit complete */
                    646:        if (weisr.is_ptx || weisr.is_txe)
                    647:                wetint (unit);
                    648: 
                    649:        /* normal receive notification */
                    650:        if (weisr.is_prx || weisr.is_rxe)
                    651:                werint (unit);
                    652: 
                    653:        /* try to start transmit */
                    654:        westart(&sc->we_if);
                    655: 
                    656:        /* re-enable onboard interrupts */
                    657:        wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
                    658:        wecmd.cs_ps = 0;
                    659:        outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
                    660:        outb(sc->we_io_nic_addr + WD_P0_IMR, 0xff/*WD_I_CONFIG*/);
                    661:        weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR);
                    662:        if (weisr.is_byte) goto loop;
                    663: }
                    664:  
                    665: /*
                    666:  * Ethernet interface transmit interrupt.
                    667:  */
                    668: wetint(unit)
                    669:        int unit;
                    670: {
                    671:        register struct we_softc *sc = &we_softc[unit];
                    672: 
                    673:        /*
                    674:         * Do some statistics (assume page zero of NIC mapped in)
                    675:         */
                    676:        sc->we_flags &= ~WDF_TXBUSY; 
                    677:        sc->we_if.if_timer = 0;
                    678:        ++sc->we_if.if_opackets;
                    679:        sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0);
                    680: }
                    681:  
                    682: /*
                    683:  * Ethernet interface receiver interrupt.
                    684:  */
                    685: werint(unit)
                    686:        int unit;
                    687: {
                    688:        register struct we_softc *sc = &we_softc[unit];
                    689:        u_char bnry, curr;
                    690:        long len;
                    691:        union we_command wecmd;
                    692:        struct we_ring *wer;
                    693:  
                    694:        /*
                    695:         * Traverse the receive ring looking for packets to pass back.
                    696:         * The search is complete when we find a descriptor not in use.
                    697:         */
                    698:        wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
                    699:        wecmd.cs_ps = 0;
                    700:        outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
                    701:        bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY);
                    702:        wecmd.cs_ps = 1;
                    703:        outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
                    704:        curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
1.1.1.3 ! root      705:        if(Bdry[unit])                                  /* 19 Sep 92*/
        !           706:                bnry = Bdry[unit];
1.1       root      707: 
                    708:        while (bnry != curr)
                    709:        {
                    710:                /* get pointer to this buffer header structure */
                    711:                wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8));
                    712: 
                    713:                /* count includes CRC */
                    714:                len = wer->we_count - 4;
1.1.1.3 ! root      715:                if (len > 30 && len <= ETHERMTU+100)
1.1       root      716:                        weread(sc, (caddr_t)(wer + 1), len);
1.1.1.3 ! root      717:                else printf("we%d: reject - bad length %d", unit, len);
1.1       root      718: 
                    719: outofbufs:
                    720:                wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND);
                    721:                wecmd.cs_ps = 0;
                    722:                outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
                    723: 
                    724:                /* advance on chip Boundry register */
                    725:                if((caddr_t) wer + WD_PAGE_SIZE - 1 > sc->we_vmem_end) {
                    726:                        bnry = WD_TXBUF_SIZE;
                    727:                        outb(sc->we_io_nic_addr + WD_P0_BNRY,
                    728:                                        sc->we_vmem_size / WD_PAGE_SIZE-1);
                    729:        
                    730:                } else {
                    731:                        if (len > 30 && len <= ETHERMTU+100)
                    732:                                bnry = wer->we_next_packet;
                    733:                        else bnry = curr;
                    734: 
                    735:                        /* watch out for NIC overflow, reset Boundry if invalid */
                    736:                        if ((bnry - 1) < WD_TXBUF_SIZE) {
                    737:                                outb(sc->we_io_nic_addr + WD_P0_BNRY,
                    738:                                        (sc->we_vmem_size / WD_PAGE_SIZE) - 1);
                    739:                                bnry = WD_TXBUF_SIZE;
                    740:                        } else
                    741:                                outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1);
                    742:                }
                    743: 
                    744:                /* refresh our copy of CURR */
                    745:                wecmd.cs_ps = 1;
                    746:                outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte);
                    747:                curr = inb(sc->we_io_nic_addr + WD_P1_CURR);
                    748:        }
1.1.1.3 ! root      749:        Bdry[unit] = bnry;                              /* 19 Sep 92*/
1.1       root      750: }
                    751: 
                    752: /*
                    753:  * Process an ioctl request.
                    754:  */
                    755: weioctl(ifp, cmd, data)
                    756:        register struct ifnet *ifp;
                    757:        int cmd;
                    758:        caddr_t data;
                    759: {
                    760:        register struct ifaddr *ifa = (struct ifaddr *)data;
                    761:        struct we_softc *sc = &we_softc[ifp->if_unit];
                    762:        struct ifreq *ifr = (struct ifreq *)data;
                    763:        int s = splimp(), error = 0;
                    764: 
                    765: 
                    766:        switch (cmd) {
                    767: 
                    768:        case SIOCSIFADDR:
                    769:                ifp->if_flags |= IFF_UP;
                    770: 
                    771:                switch (ifa->ifa_addr->sa_family) {
                    772: #ifdef INET
                    773:                case AF_INET:
                    774:                        weinit(ifp->if_unit);   /* before arpwhohas */
                    775:                        ((struct arpcom *)ifp)->ac_ipaddr =
                    776:                                IA_SIN(ifa)->sin_addr;
                    777:                        arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
                    778:                        break;
                    779: #endif
                    780: #ifdef NS
                    781:                case AF_NS:
                    782:                    {
                    783:                        register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
                    784: 
                    785:                        if (ns_nullhost(*ina))
1.1.1.3 ! root      786:                                ina->x_host = *(union ns_host *)(sc->ns_addrp);
1.1       root      787:                        else {
                    788:                                /* 
1.1.1.2   root      789:                                 * The manual says we cant change the address 
1.1       root      790:                                 * while the receiver is armed,
                    791:                                 * so reset everything
                    792:                                 */
                    793:                                ifp->if_flags &= ~IFF_RUNNING; 
                    794:                                bcopy((caddr_t)ina->x_host.c_host,
1.1.1.3 ! root      795:                                    (caddr_t)sc->ns_addrp, sizeof(sc->ns_addrp));
1.1       root      796:                        }
                    797:                        weinit(ifp->if_unit); /* does ne_setaddr() */
                    798:                        break;
                    799:                    }
                    800: #endif
                    801:                default:
                    802:                        weinit(ifp->if_unit);
                    803:                        break;
                    804:                }
                    805:                break;
                    806: 
                    807:        case SIOCSIFFLAGS:
                    808:                if ((ifp->if_flags & IFF_UP) == 0 &&
                    809:                    ifp->if_flags & IFF_RUNNING) {
                    810:                        ifp->if_flags &= ~IFF_RUNNING;
                    811:                        westop(ifp->if_unit);
                    812:                } else if (ifp->if_flags & IFF_UP &&
                    813:                    (ifp->if_flags & IFF_RUNNING) == 0)
                    814:                        weinit(ifp->if_unit);
1.1.1.3 ! root      815: #if NBPFILTER > 0
        !           816:                if (sc->we_if.if_flags & IFF_PROMISC) {
        !           817:                        outb(sc->we_io_nic_addr + WD_P0_RCR,
        !           818:                                 WD_R_PRO | WD_R_SEP | WD_R_AR | WD_R_CONFIG);
        !           819:                } else
        !           820: #endif
        !           821:                        outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG);
1.1       root      822:                break;
                    823: 
                    824: #ifdef notdef
                    825:        case SIOCGHWADDR:
                    826:                bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data,
                    827:                        sizeof(sc->sc_addr));
                    828:                break;
                    829: #endif
                    830: 
                    831:        default:
                    832:                error = EINVAL;
                    833:        }
                    834:        splx(s);
                    835:        return (error);
                    836: }
                    837: /*
                    838:  * set ethernet address for unit
                    839:  */
                    840: wesetaddr(physaddr, unit)
                    841:        u_char *physaddr;
                    842:        int unit;
                    843: {
                    844:        register struct we_softc *sc = &we_softc[unit];
                    845:        register int i;
                    846: 
                    847:        /*
                    848:         * Rewrite ethernet address, and then force restart of NIC
                    849:         */
                    850:        for (i = 0; i < ETHER_ADDR_LEN; i++)
                    851:                sc->we_addr[i] = physaddr[i];
                    852:        sc->we_flags &= ~WDF_RUNNING;
                    853:        weinit(unit);
                    854: }
                    855:  
1.1.1.3 ! root      856: #define        ringoffset(sc, eh, off, type) \
        !           857:        ((type)( ((caddr_t)(eh)+(off) >= (sc)->we_vmem_end) ? \
        !           858:                (((caddr_t)(eh)+(off))) - (sc)->we_vmem_end \
1.1       root      859:                + (sc)->we_vmem_ring: \
1.1.1.3 ! root      860:                ((caddr_t)(eh)+(off)) ))
1.1       root      861: /*
                    862:  * Pass a packet to the higher levels.
                    863:  * We deal with the trailer protocol here.
                    864:  */
                    865: weread(sc, buf, len)
                    866:        register struct we_softc *sc;
                    867:        char *buf;
                    868:        int len;
                    869: {
1.1.1.3 ! root      870:        caddr_t we_ring_copy();
        !           871:        struct ether_header *eh;
        !           872:        struct mbuf *m, *head, *we_ring_to_mbuf();
1.1       root      873:        int off, resid;
1.1.1.3 ! root      874:        u_short etype;
        !           875:        struct trailer_header {
        !           876:                u_short trail_type;
        !           877:                u_short trail_residual;
        !           878:        } trailer_header;
        !           879: 
        !           880:        ++sc->we_if.if_ipackets;
        !           881: 
        !           882:        /* Allocate a header mbuf */
        !           883:        MGETHDR(m, M_DONTWAIT, MT_DATA);
        !           884:        if (m == 0)
        !           885:                goto bad;
        !           886:        m->m_pkthdr.rcvif = &sc->we_if;
        !           887:        m->m_pkthdr.len = len;
        !           888:        m->m_len = 0;
        !           889:        head = m;
1.1       root      890: 
                    891:        eh = (struct ether_header *)buf;
                    892: 
1.1.1.3 ! root      893: #define EROUND ((sizeof(struct ether_header) + 3) & ~3)
        !           894: #define EOFF   (EROUND - sizeof(struct ether_header))
        !           895: 
        !           896:        /*
        !           897:         * The following assumes there is room for
        !           898:         * the ether header in the header mbuf
        !           899:         */
        !           900:        head->m_data += EOFF;
        !           901:        bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header));
        !           902:        buf += sizeof(struct ether_header);
        !           903:        head->m_len += sizeof(struct ether_header);
1.1       root      904:        len -= sizeof(struct ether_header);
1.1.1.3 ! root      905: 
        !           906:        etype = ntohs((u_short)eh->ether_type);
1.1       root      907: 
                    908:        /*
1.1.1.3 ! root      909:         * Deal with trailer protocol:
        !           910:         * If trailer protocol, calculate the datasize as 'off',
        !           911:         * which is also the offset to the trailer header.
        !           912:         * Set resid to the amount of packet data following the
        !           913:         * trailer header.
        !           914:         * Finally, copy residual data into mbuf chain.
1.1       root      915:         */
1.1.1.3 ! root      916:        if (etype >= ETHERTYPE_TRAIL &&
        !           917:            etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
        !           918: 
        !           919:                off = (etype - ETHERTYPE_TRAIL) << 9;
        !           920:                if ((off + sizeof(struct trailer_header)) > len)
        !           921:                        goto bad;       /* insanity */
        !           922: 
        !           923:                eh->ether_type = *ringoffset(sc, buf, off, u_short *);
        !           924:                resid = ntohs(*ringoffset(sc, buf, off+2, u_short *));
        !           925: 
        !           926:                if ((off + resid) > len) goto bad;      /* insanity */
        !           927: 
        !           928:                resid -= sizeof(struct trailer_header);
        !           929:                if (resid < 0) goto bad;        /* insanity */
        !           930: 
        !           931:                m = we_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *), head, resid);
        !           932:                if (m == 0) goto bad;
        !           933: 
        !           934:                len = off;
        !           935:                head->m_pkthdr.len -= 4; /* subtract trailer header */
        !           936:        }
        !           937: 
        !           938:        /*
        !           939:         * Pull packet off interface. Or if this was a trailer packet,
        !           940:         * the data portion is appended.
        !           941:         */
        !           942:        m = we_ring_to_mbuf(sc, buf, m, len);
        !           943:        if (m == 0) goto bad;
        !           944: 
        !           945: #if NBPFILTER > 0
        !           946:        /*
        !           947:         * Check if there's a bpf filter listening on this interface.
        !           948:         * If so, hand off the raw packet to bpf. 
        !           949:         */
        !           950:        if (sc->we_bpf) {
        !           951:                bpf_mtap(sc->we_bpf, head);
        !           952:        }
        !           953: 
        !           954:        /*
        !           955:         * Note that the interface cannot be in promiscuous mode if
        !           956:         * there are no bpf listeners.  And if we are in promiscuous
        !           957:         * mode, we have to check if this packet is really ours.
        !           958:         *
        !           959:         * XXX This test does not support multicasts.
        !           960:         */
        !           961:        if ((sc->we_if.if_flags & IFF_PROMISC) &&
        !           962:                bcmp(eh->ether_dhost, sc->we_addr,
        !           963:                        sizeof(eh->ether_dhost)) != 0 &&
        !           964:                bcmp(eh->ether_dhost, etherbroadcastaddr,
        !           965:                        sizeof(eh->ether_dhost)) != 0) {
        !           966: 
        !           967:                m_freem(head);
        !           968:                return;
        !           969:        }
        !           970: #endif
        !           971: 
        !           972:        /*
        !           973:         * Fix up data start offset in mbuf to point past ether header
        !           974:         */
        !           975:        m_adj(head, sizeof(struct ether_header));
        !           976: 
        !           977:        /*
        !           978:         * silly ether_input routine needs 'type' in host byte order
        !           979:         */
        !           980:        eh->ether_type = ntohs(eh->ether_type);
        !           981: 
        !           982:        ether_input(&sc->we_if, eh, head);
        !           983:        return;
        !           984: 
        !           985: bad:   if (head)
        !           986:                m_freem(head);
        !           987:        return;
1.1       root      988: }
                    989: 
                    990: /*
                    991:  * Supporting routines
                    992:  */
                    993: 
                    994: /*
1.1.1.3 ! root      995:  * Copy data from receive buffer to end of mbuf chain
        !           996:  * allocate additional mbufs as needed. return pointer
        !           997:  * to last mbuf in chain.
        !           998:  * sc = we info
        !           999:  * src = pointer in we ring buffer
        !          1000:  * dst = pointer to last mbuf in mbuf chain to copy to
        !          1001:  * amount = amount of data to copy
1.1       root     1002:  */
                   1003: struct mbuf *
1.1.1.3 ! root     1004: we_ring_to_mbuf(sc,src,dst,total_len)
1.1       root     1005:        struct we_softc *sc;
1.1.1.3 ! root     1006:        char *src;
        !          1007:        struct mbuf *dst;
        !          1008:        int total_len;
1.1       root     1009: {
1.1.1.3 ! root     1010:        register struct mbuf *m = dst;
1.1       root     1011: 
1.1.1.3 ! root     1012:        while (total_len > 0) {
        !          1013:                register int amount = min(total_len, M_TRAILINGSPACE(m));
1.1       root     1014: 
1.1.1.3 ! root     1015:                if (amount == 0) { /* no more data in this mbuf, alloc another */
        !          1016:                        /*
        !          1017:                         * if there is enough data for an mbuf cluster, attempt
        !          1018:                         * to allocate one of those, otherwise, a regular mbuf
        !          1019:                         * will do.
        !          1020:                         */ 
        !          1021:                        dst = m;
1.1       root     1022:                        MGET(m, M_DONTWAIT, MT_DATA);
1.1.1.3 ! root     1023:                        if (m == 0)
1.1       root     1024:                                return (0);
                   1025: 
1.1.1.3 ! root     1026:                        if (total_len >= MINCLSIZE)
        !          1027:                                MCLGET(m, M_DONTWAIT);
        !          1028: 
        !          1029:                        m->m_len = 0;
        !          1030:                        dst->m_next = m;
        !          1031:                        amount = min(total_len, M_TRAILINGSPACE(m));
1.1       root     1032:                }
1.1.1.3 ! root     1033: 
        !          1034:                src = we_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount);
        !          1035: 
        !          1036:                m->m_len += amount;
        !          1037:                total_len -= amount;
        !          1038: 
1.1       root     1039:        }
1.1.1.3 ! root     1040:        return (m);
        !          1041: }
        !          1042: 
        !          1043: static inline char *
        !          1044: we_ring_copy(sc,src,dst,amount)
        !          1045:        struct we_softc *sc;
        !          1046:        char    *src;
        !          1047:        char    *dst;
        !          1048:        int     amount;
        !          1049: {
        !          1050:        int     tmp_amount;
        !          1051: 
        !          1052:        /* does copy wrap to lower addr in ring buffer? */
        !          1053:        if (src + amount > sc->we_vmem_end) {
        !          1054:                tmp_amount = sc->we_vmem_end - src;
        !          1055:                bcopy(src,dst,tmp_amount); /* copy amount up to end */
        !          1056:                amount -= tmp_amount;
        !          1057:                src = sc->we_vmem_ring;
        !          1058:                dst += tmp_amount;
        !          1059:        }
        !          1060: 
        !          1061:        bcopy(src, dst, amount);
        !          1062: 
        !          1063:        return(src + amount);
1.1       root     1064: }
                   1065: #endif
1.1.1.3 ! root     1066: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.