From fda82fc2b9bc477624e28193c49783cd2dfdbc8e Mon Sep 17 00:00:00 2001 From: Julian Elischer Date: Wed, 10 Mar 1999 10:11:43 +0000 Subject: Submitted by: Larry Lile Move the Olicom token ring driver to the officially sanctionned location of /sys/contrib. Also fix some brokenness in the generic token ring support. Be warned that if_dl.h has been changed and SOME programs might like recompilation. --- sys/contrib/dev/oltr/if_oltr.c | 1517 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1517 insertions(+) create mode 100644 sys/contrib/dev/oltr/if_oltr.c (limited to 'sys/contrib/dev/oltr/if_oltr.c') diff --git a/sys/contrib/dev/oltr/if_oltr.c b/sys/contrib/dev/oltr/if_oltr.c new file mode 100644 index 000000000000..e39471479a64 --- /dev/null +++ b/sys/contrib/dev/oltr/if_oltr.c @@ -0,0 +1,1517 @@ +/* + * 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.17 1999/02/12 19:05:35 lile Exp lile $ + */ + + +#include "pci.h" +#include "oltr.h" +#include "opt_inet.h" +#include "bpfilter.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 NBPFILTER > 0 +#include +#endif + +#if NPNP > 0 +#include +#endif + +#include +#include +#include + +#if NPCI > 0 +#include +#include +#endif + +#include "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 +}; + +DATA_SET(pcidevice_set, 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; + register_intr(ffs(is->id_irq) - 1, is->id_id, is->id_ri_flags, is->id_intr, &net_imask, is->id_unit); + 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; + register_intr(ffs(is->id_irq) - 1, is->id_id, is->id_ri_flags, is->id_intr, &net_imask, is->id_unit); + 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 NBPFILTER > 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 NBPFILTER > 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 NBPFILTER > 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 */ -- cgit v1.2.3