/* * Copyright (c) 1998, Larry Lile * All rights reserved. * * For latest sources and information on this driver, please * go to http://anarchy.stdio.com. * * Questions, comments or suggestions should be directed to * Larry Lile . * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: if_oltr.c,v 1.5 1999/05/09 17:07:24 peter Exp $ */ #include "pci.h" #include "oltr.h" #include "opt_inet.h" #include "bpf.h" #if (NOLTR + NPCI) > 0 /*#define TRlldInlineIO*/ #define ISA_ADAPTERS (OC_3115 | OC_3117 | OC_3118) #define PCI_ADAPTERS (OC_3133 | OC_3136 | OC_3137 | \ OC_3139 | OC_3140 | OC_3141 | \ OC_3250 | OC_3540 ) #define PCI_VENDOR_OLICOM 0x108D char *AdapterName[] = { /* 0 */ "Olicom XT Adapter [unsupported]", /* 1 */ "Olicom OC-3115", /* 2 */ "Olicom ISA 16/4 Adapter (OC-3117)", /* 3 */ "Olicom ISA 16/4 Adapter (OC-3118)", /* 4 */ "Olicom MCA 16/4 Adapter (OC-3129) [unsupported]", /* 5 */ "Olicom MCA 16/4 Adapter (OC-3129) [unsupported]", /* 6 */ "Olicom MCA 16/4 Adapter (OC-3129) [unsupported]", /* 7 */ "Olicom EISA 16/4 Adapter (OC-3133)", /* 8 */ "Olicom EISA 16/4 Adapter (OC-3133)", /* 9 */ "Olicom EISA 16/4 Server Adapter (OC-3135)", /* 10 */ "Olicom PCI 16/4 Adapter (OC-3136)", /* 11 */ "Olicom PCI 16/4 Adapter (OC-3136)", /* 12 */ "Olicom PCI/II 16/4 Adapter (OC-3137)", /* 13 */ "Olicom PCI 16/4 Adapter (OC-3139)", /* 14 */ "Olicom RapidFire 3140 16/4 PCI Adapter (OC-3140)", /* 15 */ "Olicom RapidFire 3141 Fiber Adapter (OC-3141)", /* 16 */ "Olicom PCMCIA 16/4 Adapter (OC-3220) [unsupported]", /* 17 */ "Olicom PCMCIA 16/4 Adapter (OC-3121, OC-3230, OC-3232) [unsupported]", /* 18 */ "Olicom PCMCIA 16/4 Adapter (OC-3250)", /* 19 */ "Olicom RapidFire 3540 4/16/100 Adapter (OC-3540)" }; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if NBPF > 0 #include #endif #if NPNP > 0 #include #endif #include #include #include #if NPCI > 0 #include #include #endif #include "contrib/dev/oltr/trlld.h" #ifndef TRLLD_SPEED_AUTO #define TRLLD_SPEED_AUTO 0 #endif #define MIN(A,B) (((A) < (B)) ? (A) : (B)) #define MIN3(A,B,C) (MIN(A, (MIN(B, C)))) void *oltr_malloc(ssize_t, TRlldAdapterConfig_t *); /* * Glue functions prototypes for PMW kit IO */ #ifndef TRlldInlineIO static void DriverOutByte __P((unsigned short, unsigned char)); static void DriverOutWord __P((unsigned short, unsigned short)); static void DriverOutDword __P((unsigned short, unsigned long)); static void DriverRepOutByte __P((unsigned short, unsigned char *, int)); static void DriverRepOutWord __P((unsigned short, unsigned short *, int)); static void DriverRepOutDword __P((unsigned short, unsigned long *, int)); static unsigned char DriverInByte __P((unsigned short)); static unsigned short DriverInWord __P((unsigned short)); static unsigned long DriverInDword __P((unsigned short)); static void DriverRepInByte __P((unsigned short, unsigned char *, int)); static void DriverRepInWord __P((unsigned short, unsigned short *, int)); static void DriverRepInDword __P((unsigned short, unsigned long *, int)); #endif /*TRlldInlineIO*/ static void DriverSuspend __P((unsigned short)); static void DriverStatus __P((void *, TRlldStatus_t *)); static void DriverCloseCompleted __P((void *)); static void DriverStatistics __P((void *, TRlldStatistics_t *)); static void DriverTransmitFrameCompleted __P((void *, void *, int)); static void DriverReceiveFrameCompleted __P((void *, int, int, void *, int)); typedef struct tx_buf { int index; int count; char *buf; struct mbuf *m; } tx_buf_t; typedef struct rx_buf { int index; char *buf; } rx_buf_t; #ifndef EXTRA_OLTR #if NPCI > 0 #define EXTRA_OLTR 8 #else #define EXTRA_OLTR 0 #endif /* NPCI */ #endif /* EXTRA_OLTR */ #ifndef OLTR_PROMISC_MODE #define OLTR_PROMISC_MODE (TRLLD_PROM_LLC) #endif #define ALL_OPTIONS (IFM_TOK_ETR | IFM_TOK_SRCRT | IFM_TOK_ALLR | IFM_TOK_DTR | IFM_TOK_CLASSIC | IFM_TOK_AUTO) /* List sizes MUST be a power of 2 */ #define TX_LIST_SIZE 16 #define RX_LIST_SIZE 16 #define TX_LIST_MASK (TX_LIST_SIZE - 1) #define RX_LIST_MASK (RX_LIST_SIZE - 1) #define RX_BUFFER_LEN (8*1024) #define TX_BUFFER_LEN (8*1024) struct oltr_softc { struct arpcom arpcom; struct ifmedia ifmedia; TRlldAdapterConfig_t *config; TRlldAdapter_t *TRlldAdapter; int unit; u_short PromiscMode; u_short AdapterMode; int hw_state; #define HW_UNKNOWN 0 /* initial/absent state */ #define HW_FOUND 1 /* found, not initialized */ #define HW_BAD 2 /* fatal error */ #define HW_FAILED 3 /* closed eg. by remove, allow manual reopen */ #define HW_LOADING 4 #define HW_CLOSING 5 #define HW_CLOSING2 6 #define HW_CLOSED 7 #define HW_OPENING 8 #define HW_OPEN 9 #define HW_ERROR 10 /* temporary error */ u_long GroupAddress; u_long FunctionalAddress; int poll_adapter; int tx_next; int tx_avail; tx_buf_t tx_buffer[TX_LIST_SIZE]; TRlldTransmit_t tx_frame; int rx_next; int rx_avail; rx_buf_t rx_buffer[RX_LIST_SIZE]; struct callout_handle oltr_ch; struct callout_handle poll_ch; }; static struct oltr_softc oltr_softc[NOLTR + EXTRA_OLTR]; /* * Driver function prototypes */ static int oltr_probe __P((struct isa_device *)); static int oltr_attach __P((struct isa_device *)); static void oltr_init __P((struct oltr_softc *)); static void oltr_intr __P((int)); static void oltr_start __P((struct ifnet *)); static void oltr_stop __P((struct oltr_softc *)); static int oltr_ioctl __P((struct ifnet *, u_long, caddr_t)); static int oltr_attach_common __P((struct oltr_softc *)); void oltr_timeout __P((void *)); void adapter_poll __P((void *)); struct isa_driver oltrdriver = { oltr_probe, oltr_attach, "oltr", 0 }; int isa_cards = 0; #if NPCI > 0 static u_long oltr_count = NOLTR; static const char *oltr_pci_probe __P((pcici_t, pcidi_t)); static void oltr_pci_attach __P((pcici_t, int)); static void oltr_pci_intr __P((void *)); static void oltr_pci_shutdown __P((int, void *)); static struct pci_device oltr_device = { "oltr", oltr_pci_probe, oltr_pci_attach, &oltr_count, NULL }; COMPAT_PCI_DRIVER(oltr_pci, oltr_device); int pci_cards = 0; #endif /* NPCI */ static int oltr_ifmedia_upd __P((struct ifnet *)); static void oltr_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); static TRlldDriver_t oltrLldDriver = { TRLLD_VERSION, #ifndef TRlldInlineIO DriverOutByte, DriverOutWord, DriverOutDword, DriverRepOutByte, DriverRepOutWord, DriverRepOutDword, DriverInByte, DriverInWord, DriverInDword, DriverRepInByte, DriverRepInWord, DriverRepInDword, #endif /*TRlldInlineIO*/ DriverSuspend, DriverStatus, DriverCloseCompleted, DriverStatistics, DriverTransmitFrameCompleted, DriverReceiveFrameCompleted, }; TRlldAdapterConfig_t oltr_config[NOLTR + EXTRA_OLTR]; void * oltr_malloc(Size, Adapter) ssize_t Size; TRlldAdapterConfig_t *Adapter; { /* If the adapter needs memory below 16M for DMA then use contigmalloc */ if (Adapter->mode & TRLLD_MODE_16M) /* Adapter using ISA DMA buffer below 16M */ return(contigmalloc(Size, M_DEVBUF, M_NOWAIT, 0ul, 0xfffffful, 1ul, 0x10000ul)); else return(malloc(Size, M_DEVBUF, M_NOWAIT)); } /* * Driver Functions */ static int oltr_probe(is) struct isa_device *is; { static int find_completed = 0, assigned[NOLTR]; struct oltr_softc *sc = &oltr_softc[is->id_unit]; int i; printf("oltr%d: oltr_probe\n", is->id_unit); /* Make life easy, use the Olicom supplied find function on the first probe * to probe all of the ISA adapters. Then give them to each unit as requested. * Try to match the adapters to units based on the iobase, but if iobase? then * just give out the next available adapter. */ if (!find_completed) { isa_cards = TRlldFind(&oltrLldDriver, &oltr_config[0], ISA_ADAPTERS, NOLTR); /*for (i = 0; i < isa_cards; i++) { printf("TRlldFind: card %d - %s MAC %6D\n", i + 1, AdapterName[oltr_config[i].type], oltr_config[i].macaddress, ":"); }*/ for (i = 0; i < NOLTR; i++) assigned[i] = 0; find_completed = 1; } sc->unit = is->id_unit; sc->hw_state = HW_UNKNOWN; if (find_completed && ((isa_cards == 0) || (is->id_unit > isa_cards))) return(0); if (((is->id_iobase < 0xa00) || (is->id_iobase > 0xbe0)) && (is->id_iobase != 0xffffffff)) { printf("oltr%d: port address impossible (0x%X)\n", is->id_unit, is->id_iobase); return(0); } /* Auto assign lowest available card not already in use */ if (is->id_iobase == 0xffffffff) { printf("oltr%d: auto assigning card.\n", is->id_unit); for (i = 0; assigned[i]; i++); assigned[i] = 1; sc->config = &oltr_config[i]; is->id_iobase = sc->config->iobase0; /* Claim our port space */ if (!is->id_irq) is->id_irq = (1 << sc->config->interruptlevel); /* Claim our interrupt */ is->id_intr = (inthand2_t *)oltr_intr; if ((is->id_drq == 0xffffffff) && (sc->config->dmalevel != TRLLD_DMA_PIO)) is->id_drq = sc->config->dmalevel; /* Claim our dma channel */ printf("oltr%d: <%s> [%6D]\n", is->id_unit, AdapterName[sc->config->type], sc->config->macaddress, ":"); sc->hw_state = HW_FOUND; return(1); } else { /* Assign based on iobase address provided in kernel config */ for (i = 0; i < NOLTR; i++) { if (is->id_iobase == oltr_config[i].iobase0) { if (assigned[i]) { printf("oltr%d: adapter (0x%X) already assigned.\n", is->id_unit, is->id_iobase); return(0); } assigned[i] = 1; sc->config = &oltr_config[i]; if (is->id_irq == 0) is->id_irq = (1 << sc->config->interruptlevel); /* Claim our interrupt */ is->id_intr = (inthand2_t *)oltr_intr; if ((is->id_drq == 0xffffffff) && (sc->config->dmalevel != TRLLD_DMA_PIO)) is->id_drq = sc->config->dmalevel; /* Claim our dma channel */ printf("oltr%d: <%s> [%6D]\n", is->id_unit, AdapterName[sc->config->type], sc->config->macaddress, ":"); sc->hw_state = HW_FOUND; return(1); } } } return(0); /* Card was not found */ } #if NPCI > 0 static const char * oltr_pci_probe(config_id, device_id) pcici_t config_id; pcidi_t device_id; { u_char PCIConfigurationSpace[64]; u_long command; int i, j, rc; printf("oltr: oltr_pci_probe\n"); j = NOLTR + pci_cards; if (pci_cards == EXTRA_OLTR) return(NULL); if (((device_id & 0xffff) == PCI_VENDOR_OLICOM) && ((((device_id >> 16) & 0xffff) == 0x0001) || (((device_id >> 16) & 0xffff) == 0x0004) || (((device_id >> 16) & 0xffff) == 0x0005) || (((device_id >> 16) & 0xffff) == 0x0007) || (((device_id >> 16) & 0xffff) == 0x0008))) { for (i = 0; i < 64; i++) PCIConfigurationSpace[i] = pci_cfgread(config_id, i, /*bytes*/1); rc = TRlldPCIConfig(&oltrLldDriver, &oltr_config[j], PCIConfigurationSpace); if ((rc == TRLLD_PCICONFIG_OK) || (rc == TRLLD_PCICONFIG_SET_COMMAND)) { if (rc == TRLLD_PCICONFIG_SET_COMMAND) { printf("oltr: setting bus-master mode\n"); command = pci_conf_read(config_id, PCIR_COMMAND); pci_conf_write(config_id, PCIR_COMMAND, (command | PCIM_CMD_BUSMASTEREN)); } pci_cards++; return (AdapterName[oltr_config[j].type]); } else { if (rc == TRLLD_PCICONFIG_FAIL) printf("oltr: TRlldPCIConfig failed!\n"); if (rc == TRLLD_PCICONFIG_VERSION) printf("oltr: wrong LLD version\n"); } } return(NULL); } #endif /* NPCI */ static int oltr_attach(is) struct isa_device *is; { struct oltr_softc *sc = &oltr_softc[is->id_unit]; int rc; sc->unit = is->id_unit; if (!oltr_attach_common(sc)) return(0); /* If the kernel config does not match the current card configuration then * adjust the card settings to match the kernel. */ if ((ffs(is->id_irq) - 1) != sc->config->interruptlevel) { rc = TRlldSetInterrupt(sc->TRlldAdapter, is->id_irq); if (rc != TRLLD_CONFIG_OK) { printf("oltr%d: Unable to change adapter interrupt level (%x)\n", sc->unit, rc); return(0); } } /* Set dma level, fall back to pio if possible. (following SCO driver example) */ if (is->id_drq != sc->config->dmalevel) { rc = TRlldSetDMA(sc->TRlldAdapter, is->id_drq, &sc->config->mode); if (rc != TRLLD_CONFIG_OK) { if ((sc->config->dmalevel != TRLLD_DMA_PIO) && (TRlldSetDMA(sc->TRlldAdapter, TRLLD_DMA_PIO, &sc->config->mode) != TRLLD_CONFIG_OK)) { printf("oltr%d: unable to change dma level from %d to %d (%x)\n", sc->unit, sc->config->dmalevel, is->id_drq, rc); } printf("oltr%d: Unable to change adapter dma level, using PIO mode (%x)\n", sc->unit, rc); sc->config->dmalevel = TRLLD_DMA_PIO; rc = TRlldSetDMA(sc->TRlldAdapter, is->id_drq, &sc->config->mode); } is->id_irq = sc->config->dmalevel; } return(1); } #if NPCI > 0 static void oltr_pci_attach(config_id, unit) pcici_t config_id; int unit; { struct oltr_softc *sc = &oltr_softc[unit]; sc->unit = unit; sc->config = &oltr_config[unit]; sc->hw_state = HW_FOUND; printf("oltr%d: mac address [%6D]\n", sc->unit, sc->config->macaddress, ":"); if (!oltr_attach_common(sc)) return; /* Map our interrupt */ if (!pci_map_int(config_id, oltr_pci_intr, sc, &net_imask)) { printf("oltr%d: couldn't map interrupt\n", unit); return; } } #endif /* NPCI */ static int oltr_attach_common(sc) struct oltr_softc *sc; { struct ifnet *ifp = &sc->arpcom.ac_if; u_int bufsize; int rc, i, j; /*printf("oltr%d: attach_common called\n", sc->unit);*/ /* Allocate adapter memory buffer */ bufsize = TRlldAdapterSize(); sc->TRlldAdapter = (TRlldAdapter_t *)oltr_malloc(bufsize, sc->config); if (sc->TRlldAdapter == NULL) { printf("oltr%d: Unable to allocate adapter memory block (%d bytes)\n", sc->unit, bufsize); } /*printf("oltr%d: Adapter memory block (%p %d bytes)\n", sc->unit, sc->TRlldAdapter, bufsize);*/ /* Setup transmit pool */ for (i = 0; i < TX_LIST_SIZE; i++) { sc->tx_buffer[i].index = i; sc->tx_buffer[i].buf = (char *)oltr_malloc(TX_BUFFER_LEN, sc->config); /* If we have a failure then free everything and get out */ if (!sc->tx_buffer[i].buf) { printf("oltr%d: Unable to allocate transmit buffers.\n", sc->unit); for (j = 0; j < i; j++) free(sc->tx_buffer[j].buf, M_DEVBUF); return(0); } } sc->tx_next = 0; sc->tx_avail = TX_LIST_SIZE; sc->tx_frame.FragmentCount = 0; /* Setup receive pool */ for (i = 0; i < RX_LIST_SIZE; i++) { sc->rx_buffer[i].index = i; sc->rx_buffer[i].buf = (char *)oltr_malloc(RX_BUFFER_LEN, sc->config); /* If we have a failure then free everything and get out */ if (!sc->rx_buffer[i].buf) { printf("oltr%d: Unable to allocate receive buffers.\n", sc->unit); for (j = 0; j < i; j++) free(sc->rx_buffer[j].buf, M_DEVBUF); return(0); } } sc->rx_next = 0; sc->rx_avail = RX_LIST_SIZE; /*printf("oltr%d: Allocated receive buffers\n", sc->unit); */ /* Set up adapter polling mechanism */ sc->poll_adapter = 1; callout_handle_init(&sc->poll_ch); sc->poll_ch = timeout(adapter_poll, (void *)sc->unit, (1*hz)/1000); callout_handle_init(&sc->oltr_ch); /* Initialize adapter */ rc = TRlldAdapterInit(&oltrLldDriver, sc->TRlldAdapter, kvtop(sc->TRlldAdapter), (void *)sc->unit, sc->config); if (rc != TRLLD_INIT_OK) { switch (rc) { case TRLLD_INIT_NOT_FOUND: printf("oltr%d: Adapter not found or malfunctioning.\n", sc->unit); sc->hw_state = HW_BAD; return(0); case TRLLD_INIT_UNSUPPORTED: printf("oltr%d: Adapter not supported by low level driver.\n", sc->unit); sc->hw_state = HW_UNKNOWN; return(0); case TRLLD_INIT_PHYS16: printf("oltr%d: Adapter memory block above 16M, must be below 16M.\n", sc->unit); return(0); case TRLLD_INIT_VERSION: printf("oltr%d: Low level driver version mismatch.\n", sc->unit); return(0); default: printf("oltr%d: Unknown initilization error occoured (%x).\n", sc->unit, rc); return(0); } } /* Download Adapter Microcode */ /*printf("oltr%d: Downloading adapter microcode...", sc->unit);*/ sc->hw_state = HW_LOADING; switch(sc->config->mactype) { case TRLLD_MAC_TMS: /* TMS microcode */ rc = TRlldDownload(sc->TRlldAdapter, TRlldMacCode); break; case TRLLD_MAC_HAWKEYE: /* Hawkeye microcode */ rc = TRlldDownload(sc->TRlldAdapter, TRlldHawkeyeMac); break; case TRLLD_MAC_BULLSEYE: /* Bullseye microcode */ rc = TRlldDownload(sc->TRlldAdapter, TRlldBullseyeMac); break; default: printf("oltr%d: unknown mactype %d\n", sc->unit, sc->config->mactype); return(0); } /*if (rc == TRLLD_DOWNLOAD_OK) printf("done\n");*/ if ((rc == TRLLD_DOWNLOAD_ERROR) || (rc == TRLLD_STATE)) { printf("oltr%d: Adapter microcode download failed! (rc = %x)\n", sc->unit, rc); sc->hw_state = HW_BAD; return(0); } TRlldSetSpeed(sc->TRlldAdapter, TRLLD_SPEED_AUTO); sc->PromiscMode = 0; sc->AdapterMode = 0; /* Do the ifnet initialization */ ifp->if_softc = sc; ifp->if_unit = sc->unit; ifp->if_name = "oltr"; ifp->if_output = iso88025_output; ifp->if_init = (if_init_f_t *)oltr_init; ifp->if_start = oltr_start; ifp->if_ioctl = oltr_ioctl; ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX; bcopy(sc->config->macaddress, sc->arpcom.ac_enaddr, sizeof(sc->config->macaddress)); /* Set up common ifmedia options */ ifmedia_init(&sc->ifmedia, 0, oltr_ifmedia_upd, oltr_ifmedia_sts); ifmedia_add(&sc->ifmedia, IFM_TOKEN | IFM_AUTO, 0 , NULL); ifmedia_add(&sc->ifmedia, IFM_TOKEN | IFM_TOK_UTP4, 0 , NULL); ifmedia_add(&sc->ifmedia, IFM_TOKEN | IFM_TOK_UTP16, 0 , NULL); ifmedia_set(&sc->ifmedia, IFM_TOKEN | IFM_AUTO); if_attach(ifp); iso88025_ifattach(ifp); #if NBPF > 0 bpfattach(ifp, DLT_IEEE802, sizeof(struct iso88025_header)); #endif printf("oltr%d: Adapter modes - ", sc->unit); if (sc->config->mode & TRLLD_MODE_16M) printf("TRLLD_MODE_16M "); if (sc->config->mode & TRLLD_MODE_PHYSICAL) printf("TRLLD_MODE_PHYSICAL "); if (sc->config->mode & TRLLD_MODE_FIXED_CFG) printf("TRLLD_MODE_FIXED_CFG "); if (sc->config->mode & TRLLD_MODE_SHORT_SLOT) printf("TRLLD_MODE_SHORT_SLOT "); if (sc->config->mode & TRLLD_MODE_CANNOT_DISABLE) printf("TRLLD_MODE_CANNOT_DISABLE "); if (sc->config->mode & TRLLD_MODE_SHARE_INTERRUPT) printf("TRLLD_MODE_SHARE_INTERRUPT "); if (sc->config->mode & TRLLD_MODE_MEMORY) printf("TRLLD_MODE_MEMORY "); printf("\n"); return(1); } #if NPCI > 0 static void oltr_pci_shutdown(howto, sc) int howto; void *sc; { printf("oltr: oltr_pci_shutdown called\n"); } #endif /* NPCI */ static int oltr_ifmedia_upd(ifp) struct ifnet *ifp; { struct oltr_softc *sc = ifp->if_softc; struct ifmedia *ifm = &sc->ifmedia; if (IFM_TYPE(ifm->ifm_media) != IFM_TOKEN) return(EINVAL); switch(IFM_SUBTYPE(ifm->ifm_media)) { case IFM_AUTO: TRlldSetSpeed(sc->TRlldAdapter, TRLLD_SPEED_AUTO); break; case IFM_TOK_UTP4: TRlldSetSpeed(sc->TRlldAdapter, TRLLD_SPEED_4MBPS); break; case IFM_TOK_UTP16: TRlldSetSpeed(sc->TRlldAdapter, TRLLD_SPEED_16MBPS); break; default: return(EINVAL); } if (IFM_TYPE_OPTIONS(ifm->ifm_media) & IFM_TOK_ETR) printf("oltr%d: ETR not implemented\n", sc->unit); if (IFM_TYPE_OPTIONS(ifm->ifm_media) & IFM_TOK_SRCRT) printf("oltr%d: source-routing not implemented\n", sc->unit); if (IFM_TYPE_OPTIONS(ifm->ifm_media) & IFM_TOK_ALLR) printf("oltr%d: all source routes not implemented\n", sc->unit); if (IFM_TYPE_OPTIONS(ifm->ifm_media) & IFM_TOK_DTR) { sc->AdapterMode |= TRLLD_MODE_FORCE_TXI; sc->AdapterMode &= ~TRLLD_MODE_FORCE_TKP; } if (IFM_TYPE_OPTIONS(ifm->ifm_media) & IFM_TOK_CLASSIC) { sc->AdapterMode |= TRLLD_MODE_FORCE_TKP; sc->AdapterMode &= ~TRLLD_MODE_FORCE_TXI; } if (IFM_TYPE_OPTIONS(ifm->ifm_media) & IFM_TOK_AUTO) sc->AdapterMode &= ~(TRLLD_MODE_FORCE_TXI | TRLLD_MODE_FORCE_TKP); if (IFM_TYPE_OPTIONS(ifm->ifm_media) & ~ALL_OPTIONS) return(EINVAL); return(0); } static void oltr_ifmedia_sts(ifp, ifmr) struct ifnet *ifp; struct ifmediareq *ifmr; { struct oltr_softc *sc = ifp->if_softc; struct ifmedia *ifm = &sc->ifmedia; ifmr->ifm_active = IFM_TYPE(ifm->ifm_media)|IFM_SUBTYPE(ifm->ifm_media)|IFM_TYPE_OPTIONS(ifm->ifm_media); return; } void oltr_timeout(token) void *token; { struct oltr_softc *sc = &oltr_softc[(int)token]; int unit = (int)token, s; s = splimp(); printf("oltr%d: adapter timed out (%x)\n", unit, sc->hw_state); splx(s); } void adapter_poll(token) void *token; { int unit = (int)token, poll_timeout = 0, s; struct oltr_softc *sc = &oltr_softc[unit]; #if 0 static int rx_buffers = 0, tx_buffers = 0, rc; #endif s = splimp(); /* Check to make sure we are not polling a dead card */ if ((sc->hw_state == HW_BAD) || (sc->hw_state == HW_UNKNOWN)) { sc->poll_adapter = -1; splx(s); return; } /*printf("oltr%d: adapter poll.\n", unit);*/ /* If the adapter is to be polled again, then set up * next timeout poll */ if (sc->poll_adapter) { poll_timeout = TRlldPoll(sc->TRlldAdapter); sc->poll_ch = timeout(adapter_poll, (void *)unit, (poll_timeout * hz)/1000); } #if 0 rc = TRlldReceiveFree(sc->TRlldAdapter); if (rx_buffers != rc) { printf("oltr%d: %d receive buffers available\n", sc->unit, rc); rx_buffers = rc; } rc = TRlldTransmitFree(sc->TRlldAdapter); if (tx_buffers != rc) { printf("oltr%d: %d transmit buffers available\n", sc->unit, rc); tx_buffers = rc; } #endif splx(s); } static void oltr_init(sc) struct oltr_softc *sc; { struct ifnet *ifp = &sc->arpcom.ac_if; int i, rc; /*printf("oltr%d: oltr_init\n", sc->unit);*/ /* * Adapter should be freshly downloaded or previously closed before * bringing it back on line. */ if ((sc->hw_state != HW_CLOSED) && (sc->hw_state != HW_LOADING) && (sc->hw_state != HW_CLOSING2)) { printf("oltr%d: adapter not ready to be opened (%d).\n", sc->unit, sc->hw_state); return; } /* Allocate and set up the DMA channel */ if (sc->config->dmalevel != TRLLD_DMA_PIO) { rc = isa_dma_acquire(sc->config->dmalevel); isa_dmacascade(sc->config->dmalevel); } /* Open the adapter */ sc->hw_state = HW_OPENING; rc = TRlldOpen(sc->TRlldAdapter, sc->arpcom.ac_enaddr, sc->GroupAddress, sc->FunctionalAddress, ifp->if_mtu + 52, sc->AdapterMode); if (rc != TRLLD_OPEN_OK) { printf("oltr%d: Adapter failed to open (rc = %x)\n", sc->unit, rc); sc->hw_state = HW_FAILED; } else { /*printf("oltr%d: adapter opening...\n", sc->unit);*/ /*ifp->if_flags |= (IFF_UP | IFF_RUNNING);*/ ifp->if_flags &= ~IFF_OACTIVE; } sc->oltr_ch = timeout(oltr_timeout, (void *)sc->unit, 30*hz); tsleep((void *)sc->unit, 1, "oltrop", 30*hz); /* Give the receive buffers to the adapter */ for (i = 0; i < RX_LIST_SIZE; i++) { rc = TRlldReceiveFragment(sc->TRlldAdapter, (void *)sc->rx_buffer[sc->rx_next & RX_LIST_MASK].buf, kvtop(sc->rx_buffer[sc->rx_next & RX_LIST_MASK].buf), RX_BUFFER_LEN, (void *)sc->rx_buffer[sc->rx_next & RX_LIST_MASK].index); if (rc != TRLLD_RECEIVE_OK) { printf("oltr%d: Adapter refused fragment %d (rc = %d).\n", sc->unit, i, rc); break; } else { sc->rx_avail--; } sc->rx_next++; } sc->tx_frame.FragmentCount = 0; return; } static void oltr_intr(unit) int unit; { struct oltr_softc *sc = &oltr_softc[unit]; int rc; /*printf("oltr%d: oltr_intr\n", unit);*/ /* Too noisy */ rc= TRlldInterruptService(sc->TRlldAdapter); if (rc == TRLLD_NO_INTERRUPT) printf("oltr%d: interrupt not serviced.\n", unit); } #if NPCI > 0 static void oltr_pci_intr(psc) void *psc; { struct oltr_softc *sc = (struct oltr_softc *)psc; int rc = 0; /*printf("oltr%d: oltr_pci_intr\n", sc->unit);*/ /* Too noisy */ rc = TRlldInterruptService(sc->TRlldAdapter); if (rc == TRLLD_NO_INTERRUPT) printf("oltr%d: pci interrupt not serviced.\n", sc->unit); } #endif /* NPCI */ static void oltr_start(ifp) struct ifnet *ifp; { struct oltr_softc *sc = &oltr_softc[ifp->if_unit]; struct mbuf *m0, *m; int len, i, k, rc; /*printf("oltr%d: oltr_start\n", sc->unit);*/ outloop: i = (sc->tx_next & TX_LIST_MASK); /* Just to shorten thing up */ /* Check to see if we have enough room to transmit */ if (sc->tx_avail <= 0) { /* No free buffers, hold off the upper layers */ /*printf("oltr%d: transmit queue full.\n", sc->unit);*/ ifp->if_flags |= IFF_OACTIVE; return; } if (sc->tx_frame.FragmentCount > 0) { if (!(sc->config->mode & TRLLD_MODE_16M)) { sc->tx_next++; m0 = sc->tx_buffer[i].m; goto restart; } } IF_DEQUEUE(&ifp->if_snd, m); if (m == 0) { /*printf("oltr%d: oltr_start NULL packet dequeued.\n", sc->unit);*/ ifp->if_flags &= ~IFF_OACTIVE; return; } /* Keep a pointer to the head of the packet */ m0 = m; if (sc->config->mode & TRLLD_MODE_16M) { /* ISA Adapters - bounce buffers */ for (len = 0; m != 0; m = m->m_next) { sc->tx_frame.TransmitFragment[0].VirtualAddress = sc->tx_buffer[i].buf; sc->tx_frame.TransmitFragment[0].PhysicalAddress = kvtop(sc->tx_buffer[i].buf); bcopy(mtod(m, caddr_t), sc->tx_buffer[i].buf + len, m->m_len); len += m->m_len; } sc->tx_frame.FragmentCount = 1; sc->tx_frame.TransmitFragment[0].count = len; sc->tx_next++; sc->tx_avail--; } else { /* PCI Adapters w/DMA */ for (k = 0; m!= 0; m = m->m_next) { sc->tx_frame.TransmitFragment[k].VirtualAddress = mtod(m, caddr_t); sc->tx_frame.TransmitFragment[k].PhysicalAddress = kvtop(mtod(m, caddr_t)); sc->tx_frame.TransmitFragment[k].count = m->m_len; k++; sc->tx_avail--; } sc->tx_frame.FragmentCount = k; sc->tx_buffer[i].count = k; sc->tx_buffer[i].m = m0; if (sc->tx_avail < 0) { /*printf("oltr%d: transmit buffers exhausted.\n", sc->unit);*/ goto nobuffers; } sc->tx_next++; } restart: rc = TRlldTransmitFrame(sc->TRlldAdapter, &sc->tx_frame, (void *)sc->tx_buffer[i].index); sc->tx_frame.FragmentCount = 0; if (rc != TRLLD_TRANSMIT_OK) { printf("oltr%d: TRlldTransmitFrame returned (%x)\n", sc->unit, rc); ifp->if_oerrors++; goto bad; } #if NBPF > 0 if (ifp->if_bpf) bpf_mtap(ifp, m0); #endif bad: if (sc->config->mode & TRLLD_MODE_16M) { m_freem(m0); } goto outloop; nobuffers: ifp->if_flags |= IFF_OACTIVE; return; } static void oltr_stop(sc) struct oltr_softc *sc; { struct ifnet *ifp = &sc->arpcom.ac_if; printf("oltr%d: otlr_stop\n", sc->unit); ifp->if_flags &= ~(IFF_UP | IFF_RUNNING | IFF_OACTIVE); sc->hw_state = HW_CLOSING; TRlldClose(sc->TRlldAdapter, 0); sc->oltr_ch = timeout(oltr_timeout, (void *)sc->unit, 30*hz); tsleep((void *)sc->unit, 1, "oltrcl", 30*hz); } static int oltr_ioctl(ifp, cmd, data) struct ifnet *ifp; u_long cmd; caddr_t data; { struct oltr_softc *sc = &oltr_softc[ifp->if_unit]; struct ifreq *ifr = (struct ifreq *)data; int error = 0, s; /*printf("oltr%d: oltr_ioctl\n", ifp->if_unit);*/ s = splimp(); switch (cmd) { case SIOCSIFADDR: case SIOCGIFADDR: case SIOCSIFMTU: error = iso88025_ioctl(ifp, cmd, data); break; case SIOCSIFFLAGS: /* * If the interface is marked up and stopped, then start it. * If it is marked down and running, then stop it. */ if (ifp->if_flags & IFF_UP) { if ((ifp->if_flags & IFF_RUNNING) == 0) oltr_init(sc); } else { if (ifp->if_flags & IFF_RUNNING) { oltr_stop(sc); ifp->if_flags &= ~IFF_RUNNING; } } if ((ifp->if_flags & IFF_PROMISC) != sc->PromiscMode) { if (ifp->if_flags & IFF_PROMISC) TRlldSetPromiscuousMode(sc->TRlldAdapter, OLTR_PROMISC_MODE); else TRlldSetPromiscuousMode(sc->TRlldAdapter, 0); sc->PromiscMode = (ifp->if_flags & IFF_PROMISC); } break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, cmd); break; default: error = EINVAL; } splx(s); return(error); } /* * PMW Callback functions ---------------------------------------------------- */ static void DriverSuspend(MicroSeconds) unsigned short MicroSeconds; { DELAY(MicroSeconds); } static void DriverStatus(DriverHandle, Status) void *DriverHandle; TRlldStatus_t *Status; { struct oltr_softc *sc = &oltr_softc[(int)DriverHandle]; struct ifnet *ifp = &sc->arpcom.ac_if; switch (Status->Type) { case TRLLD_STS_ON_WIRE: if (sc->hw_state == HW_OPENING) { sc->hw_state = HW_OPEN; ifp->if_flags |= (IFF_UP | IFF_RUNNING); /*printf("oltr%d: Adapter inserted.\n", sc->unit);*/ untimeout(oltr_timeout, (void *)sc->unit, sc->oltr_ch); wakeup_one((void *)sc->unit); } break; case TRLLD_STS_SELFTEST_STATUS: if (Status->Specification.SelftestStatus == TRLLD_ST_OK) { printf("oltr%d: adapter status good. (close completed/self-test)\n", sc->unit); if ((sc->hw_state == HW_LOADING) || (sc->hw_state == HW_CLOSING) || (sc->hw_state == HW_CLOSING2)) { sc->hw_state = HW_CLOSED; break; } } else { printf("oltr%d: Self test failed: ", sc->unit); switch (Status->Specification.SelftestStatus) { case TRLLD_ST_ERROR + 0: printf("Initial Test Error\n"); break; case TRLLD_ST_ERROR + 1: printf("Adapter Software Checksum Error\n"); break; case TRLLD_ST_ERROR + 2: printf("Adapter RAM Error\n"); break; case TRLLD_ST_ERROR + 4: printf("Instruction Test Error\n"); break; case TRLLD_ST_ERROR + 5: printf("Protocol Handler/RI Hw Error\n"); break; case TRLLD_ST_ERROR + 6: printf("System Interface Register Error\n"); break; case TRLLD_ST_TIMEOUT: printf("Selftest did not complete\n"); break; default: printf("Unknown error (%x)\n", Status->Specification.SelftestStatus); } } break; case TRLLD_STS_INIT_STATUS: printf("oltr%d: Adapter initialization failed: ", sc->unit); switch(Status->Specification.InitStatus) { case TRLLD_INIT_ERROR + 0x01: printf("Invalid init block (LLD error)\n"); break; case TRLLD_INIT_ERROR + 0x02: printf("Invalid options (LLD error)\n"); break; case TRLLD_INIT_ERROR + 0x03: printf("Invalid rcv burst (LLD error)\n"); break; case TRLLD_INIT_ERROR + 0x04: printf("Invalid xmt burst (LLD error)\n"); break; case TRLLD_INIT_ERROR + 0x05: printf("Invalid DMA threshold (LLD error)\n"); break; case TRLLD_INIT_ERROR + 0x06: printf("Invalid scb addr\n"); break; case TRLLD_INIT_ERROR + 0x07: printf("Invalid ssb addr\n"); break; case TRLLD_INIT_ERROR + 0x08: printf("DIO parity error (HW error)\n"); break; case TRLLD_INIT_ERROR + 0x09: printf("DMA timeout (May be interrupt failing if PIO mode or PCI2)\n"); break; case TRLLD_INIT_ERROR + 0x0A: printf("DMA parity error (HW error)\n"); break; case TRLLD_INIT_ERROR + 0x0B: printf("DMA bus error (HW error)\n"); break; case TRLLD_INIT_ERROR + 0x0C: printf("DMA data error\n"); break; case TRLLD_INIT_ERROR + 0x0D: printf("Adapter Check\n"); break; case TRLLD_INIT_TIMEOUT: printf("Adapter initialization did not complete\n"); break; case TRLLD_INIT_DMA_ERROR: printf("Adapter cannot access system memory\n"); break; case TRLLD_INIT_INTR_ERROR: printf("Adapter cannot interrupt\n"); break; case TRLLD_OPEN_TIMEOUT: printf("Adapter did not complete open within 30 seconds\n"); break; case TRLLD_OPEN_ERROR + 0x01: printf("Invalid open options (LLD error)\n"); break; case TRLLD_OPEN_ERROR + 0x04: printf("TxBuffer count error (LLD error)\n"); break; case TRLLD_OPEN_ERROR + 0x10: printf("Buffer size error (LLD error)\n"); break; case TRLLD_OPEN_ERROR + 0x20: printf("List size error (LLD error)\n"); break; default: if (Status->Specification.InitStatus & 0x700) { switch (Status->Specification.InitStatus & 0x70F) { case TRLLD_OPEN_REPEAT + 0x01: printf("Lobe media test - "); break; case TRLLD_OPEN_REPEAT + 0x02: printf("Physical insertion - "); break; case TRLLD_OPEN_REPEAT + 0x03: printf("Address verification - "); break; case TRLLD_OPEN_REPEAT + 0x04: printf("Participation in ring poll - "); break; case TRLLD_OPEN_REPEAT + 0x05: printf("Request initialization - "); break; case TRLLD_OPEN_REPEAT + 0x09: printf("Request registration (TXI) - "); break; case TRLLD_OPEN_REPEAT + 0x0A: printf("Lobe media test (TXI) - "); break; default: printf("Unknown phase (%x) - ", Status->Specification.InitStatus & 0x00F); } switch (Status->Specification.InitStatus & 0x7F0) { case TRLLD_OPEN_REPEAT + 0x10: printf("Function failure (No cable?)\n"); break; case TRLLD_OPEN_REPEAT + 0x20: printf("Signal loss\n"); break; case TRLLD_OPEN_REPEAT + 0x50: printf("Timeout\n"); break; case TRLLD_OPEN_REPEAT + 0x60: printf("Ring failure (TKP) / Protocol error (TXI)\n"); break; case TRLLD_OPEN_REPEAT + 0x70: printf("Ring beaconing\n"); break; case TRLLD_OPEN_REPEAT + 0x80: printf("Duplicate node address (TKP) / Insert denied (TXI)\n"); break; case TRLLD_OPEN_REPEAT + 0x90: printf("Request initialization (TKP)\n"); break; case TRLLD_OPEN_REPEAT + 0xa0: printf("Remove received\n"); break; case TRLLD_OPEN_REPEAT + 0xb0: printf("C-port address changed (TXI)\n"); break; default: printf("Unknown type (%x)\n", Status->Specification.InitStatus & 0x0F0); } } else { printf("Unknown error (%x)\n", Status->Specification.InitStatus); } } break; case TRLLD_STS_RING_STATUS: if (Status->Specification.RingStatus != 0) { printf("oltr%d: Ring status change: ", sc->unit); if (Status->Specification.RingStatus & TRLLD_RS_HARD_ERROR) printf("[Hard error] "); if (Status->Specification.RingStatus & TRLLD_RS_SOFT_ERROR) printf("[Soft error] "); if (Status->Specification.RingStatus & TRLLD_RS_TRANSMIT_BEACON) printf("[Transmit beacon] "); if (Status->Specification.RingStatus & TRLLD_RS_LOBE_WIRE_FAULT) printf("[Wire fault] "); if (Status->Specification.RingStatus & TRLLD_RS_AUTO_REMOVAL_ERROR) printf("[Auto removal] "); if (Status->Specification.RingStatus & TRLLD_RS_REMOVE_RECEIVED) printf("[Remove received] "); if (Status->Specification.RingStatus & TRLLD_RS_COUNTER_OVERFLOW) printf("[Counter overflow] "); if (Status->Specification.RingStatus & TRLLD_RS_SINGLE_STATION) printf("[Single station] "); if (Status->Specification.RingStatus & TRLLD_RS_RING_RECOVERY) printf("[Ring recovery] "); printf("\n"); } break; case TRLLD_STS_ADAPTER_CHECK: printf("oltr%d: Adapter check (%x %x %x %x)\n", sc->unit, Status->Specification.AdapterCheck[0], Status->Specification.AdapterCheck[1], Status->Specification.AdapterCheck[2], Status->Specification.AdapterCheck[3]); break; case TRLLD_STS_PROMISCUOUS_STOPPED: printf("oltr%d: Promiscuous mode stopped: ", sc->unit); switch(Status->Specification.PromRemovedCause) { case TRLLD_PROM_REMOVE_RECEIVED: printf("Remove received\n"); break; case TRLLD_PROM_POLL_FAILURE: printf("Poll failure\n"); break; default: printf("Unknown (%x)\n", Status->Specification.PromRemovedCause); } break; case TRLLD_STS_LLD_ERROR: printf("oltr%d: LLD error (%x %x %x %x) ", sc->unit, Status->Specification.InternalError[0], Status->Specification.InternalError[1], Status->Specification.InternalError[2], Status->Specification.InternalError[3]); break; case TRLLD_STS_ADAPTER_TIMEOUT: printf("oltr%d: Adapter operation timed out: ", sc->unit); switch(Status->Specification.AdapterTimeout) { case TRLLD_COMMAND_TIMEOUT: printf("Command\n"); case TRLLD_TRANSMIT_TIMEOUT: printf("Transmit\n"); case TRLLD_INTERRUPT_TIMEOUT: printf("Interrupt\n"); default: printf("Unknown (%x)\n", Status->Specification.AdapterTimeout); } break; default: printf("oltr%d: Unknown status type (%x)\n", sc->unit, Status->Type); } if (Status->Closed) { if (sc->hw_state > HW_BAD) { sc->hw_state = HW_FAILED; printf("oltr%d: closing adapter due to failure.\n", sc->unit); oltr_stop(sc); } } } static void DriverCloseCompleted(DriverHandle) void *DriverHandle; { struct oltr_softc *sc = &oltr_softc[(int)DriverHandle]; printf("oltr%d: DriverCloseCompleted\n", sc->unit); untimeout(oltr_timeout, (void *)sc->unit, sc->oltr_ch); wakeup_one((void *)sc->unit); if ((sc->hw_state != HW_CLOSING) && (sc->hw_state != HW_CLOSING2) && (sc->hw_state != HW_CLOSED)) { printf("oltr%d: adapter close complete called in wrong state (%d)\n", sc->unit, sc->hw_state); return; } sc->hw_state = HW_CLOSING2; if (sc->config->dmalevel != TRLLD_DMA_PIO) isa_dma_release(sc->config->dmalevel); } static void DriverStatistics(DriverHandle, Statistics) void *DriverHandle; TRlldStatistics_t *Statistics; { printf("oltr: DriverStatistics\n"); } static void DriverTransmitFrameCompleted(DriverHandle, FrameHandle, TransmitStatus) void *DriverHandle; void *FrameHandle; int TransmitStatus; { int frame = (int)FrameHandle; struct oltr_softc *sc = &oltr_softc[(int)DriverHandle]; struct ifnet *ifp = &sc->arpcom.ac_if; /*printf("oltr%d: transmit complete frame %d\n", sc->unit, frame);*/ if (TransmitStatus == TRLLD_TRANSMIT_OK) { ifp->if_opackets++; } else { printf("oltr%d: DriverTransmitFrameCompleted (frame %d status %x)\n", sc->unit, frame, TransmitStatus); ifp->if_oerrors++; } if ((frame < 0) || (frame > TX_LIST_SIZE)) { printf("oltr%d: bogus transmit frame. (%d)\n", sc->unit, frame); return; } if (sc->config->mode & TRLLD_MODE_16M) { sc->tx_avail++; } else { m_freem(sc->tx_buffer[frame].m); sc->tx_avail += sc->tx_buffer[frame].count; } if ((ifp->if_flags & IFF_OACTIVE) && (sc->tx_avail > 0)) { ifp->if_flags &= ~(IFF_OACTIVE); oltr_start(ifp); } } static void DriverReceiveFrameCompleted(DriverHandle, ByteCount, FragmentCount, FragmentHandle, ReceiveStatus) void *DriverHandle; int ByteCount; int FragmentCount; void *FragmentHandle; int ReceiveStatus; { struct oltr_softc *sc = &oltr_softc[(int)DriverHandle]; struct ifnet *ifp = &sc->arpcom.ac_if; struct iso88025_header *th; struct mbuf *m0, *m1, *m; int j = (int)FragmentHandle, rc, frame_len = ByteCount, mac_hdr_len; int mbuf_offset, mbuf_size, frag_offset, length; char *frag = sc->rx_buffer[j].buf; /*printf("oltr%d: ReceiveFrameCompleted (Size %d Count %d Start %d)\n", sc->unit, ByteCount, FragmentCount, j);*/ if (sc->hw_state >= HW_OPEN) { /* Hardware operating normally */ if (frag != sc->rx_buffer[sc->rx_next & RX_LIST_MASK].buf) { printf("oltr%d: ring buffer pointer blown\n", sc->unit); oltr_stop(sc); return; } if (ReceiveStatus == TRLLD_RCV_OK) { /* Receive good frame */ MGETHDR(m0, M_DONTWAIT, MT_DATA); mbuf_size = MHLEN; if (m0 == NULL) { ifp->if_ierrors++; goto out; } if (ByteCount + 2 > MHLEN) { MCLGET(m0, M_DONTWAIT); mbuf_size = MCLBYTES; if ((m0->m_flags & M_EXT) == 0) { m_freem(m0); ifp->if_ierrors++; goto out; } } m0->m_pkthdr.rcvif = &sc->arpcom.ac_if; m0->m_pkthdr.len = ByteCount; m0->m_len = 0; m0->m_data += 2; mbuf_size -=2; th = mtod(m0, struct iso88025_header *); m0->m_pkthdr.header = (void *)th; m = m0; mbuf_offset = 0; frag_offset = 0; while (frame_len > 0) { length = MIN3(frame_len, (RX_BUFFER_LEN - frag_offset), (mbuf_size - mbuf_offset)); bcopy(frag + frag_offset, mtod(m, char *) + mbuf_offset, length); m->m_len += length; mbuf_offset += length; frag_offset += length; frame_len -= length; if (frag_offset == RX_BUFFER_LEN) { frag = sc->rx_buffer[++j].buf; frag_offset = 0; } if ((mbuf_offset == mbuf_size) && (frame_len > 0)) { MGET(m1, M_DONTWAIT, MT_DATA); mbuf_size = MHLEN; if (m1 == NULL) { ifp->if_ierrors++; m_freem(m0); goto out; } if (frame_len > MHLEN) { MCLGET(m1, M_DONTWAIT); mbuf_size = MCLBYTES; if ((m1->m_flags & M_EXT) == 0) { m_freem(m0); m_freem(m1); ifp->if_ierrors++; goto out; } } m->m_next = m1; m = m1; mbuf_offset = 0; m->m_len = 0; } } ifp->if_ipackets++; #if NBPF > 0 if (ifp->if_bpf) bpf_mtap(ifp, m0); #endif if (ifp->if_flags & IFF_PROMISC) if (bcmp(th->iso88025_dhost, etherbroadcastaddr, sizeof(th->iso88025_dhost)) != 0) { if (((th->iso88025_dhost[0] & 0x7f) != sc->arpcom.ac_enaddr[0]) || (bcmp(th->iso88025_dhost + 1, sc->arpcom.ac_enaddr + 1, ISO88025_ADDR_LEN - 1))) { m_freem(m0); goto out; } } mac_hdr_len = ISO88025_HDR_LEN; if (th->iso88025_shost[0] & 0x80) /* Check for source routing info */ mac_hdr_len += (ntohs(th->rcf) & 0x1f00) >> 8; m0->m_pkthdr.len -= mac_hdr_len; m0->m_len -= mac_hdr_len; m0->m_data += mac_hdr_len; iso88025_input(&sc->arpcom.ac_if, th, m0); } else { if (ReceiveStatus != TRLLD_RCV_NO_DATA) { printf("oltr%d: receive error. (ReceiveStatus=%d)\n", sc->unit, ReceiveStatus); ifp->if_ierrors++; } } out: while (FragmentCount > 0) { rc = TRlldReceiveFragment(sc->TRlldAdapter, (void *)sc->rx_buffer[sc->rx_next & RX_LIST_MASK].buf, kvtop(sc->rx_buffer[sc->rx_next & RX_LIST_MASK].buf), RX_BUFFER_LEN, (void *)sc->rx_buffer[sc->rx_next & RX_LIST_MASK].index); if (rc == TRLLD_RECEIVE_OK) { sc->rx_next++; FragmentCount--; } else { printf("oltr%d: Adapter refused fragment (%d).\n", sc->unit, sc->rx_next - 1); sc->rx_avail += FragmentCount; break; } } } else { /* Hardware being closed */ if (frag != sc->rx_buffer[sc->rx_next++ & RX_LIST_MASK].buf) { printf("oltr%d: ring buffer pointer blown\n", sc->unit); } sc->rx_avail += FragmentCount; } } /* * ---------------------------- PMW Glue ------------------------------- */ #ifndef TRlldInlineIO static void DriverOutByte(IOAddress, value) unsigned short IOAddress; unsigned char value; { outb(IOAddress, value); } static void DriverOutWord(IOAddress, value) unsigned short IOAddress; unsigned short value; { outw(IOAddress, value); } static void DriverOutDword(IOAddress, value) unsigned short IOAddress; unsigned long value; { outl(IOAddress, value); } static void DriverRepOutByte(IOAddress, DataPointer, ByteCount) unsigned short IOAddress; unsigned char *DataPointer; int ByteCount; { outsb(IOAddress, (void *)DataPointer, ByteCount); } static void DriverRepOutWord(IOAddress, DataPointer, WordCount) unsigned short IOAddress; unsigned short *DataPointer; int WordCount; { outsw(IOAddress, (void *)DataPointer, WordCount); } static void DriverRepOutDword(IOAddress, DataPointer, DWordCount) unsigned short IOAddress; unsigned long *DataPointer; int DWordCount; { outsl(IOAddress, (void *)DataPointer, DWordCount); } static unsigned char DriverInByte(IOAddress) unsigned short IOAddress; { return(inb(IOAddress)); } static unsigned short DriverInWord(IOAddress) unsigned short IOAddress; { return(inw(IOAddress)); } static unsigned long DriverInDword(IOAddress) unsigned short IOAddress; { return(inl(IOAddress)); } static void DriverRepInByte(IOAddress, DataPointer, ByteCount) unsigned short IOAddress; unsigned char *DataPointer; int ByteCount; { insb(IOAddress, (void *)DataPointer, ByteCount); } static void DriverRepInWord(IOAddress, DataPointer, WordCount) unsigned short IOAddress; unsigned short *DataPointer; int WordCount; { insw(IOAddress, (void *)DataPointer, WordCount); } static void DriverRepInDword(IOAddress, DataPointer, DWordCount) unsigned short IOAddress; unsigned long *DataPointer; int DWordCount; { insl(IOAddress, (void *)DataPointer, DWordCount); } #endif /* TRlldInlineIO */ #endif /* NOLTR */