From c5c63975d538cf48ceb99ba48c341293676d15c0 Mon Sep 17 00:00:00 2001 From: julian Date: Thu, 21 Oct 1999 09:06:11 +0000 Subject: Whistle's Netgraph link-layer (sometimes more) networking infrastructure. Been in production for 3 years now. Gives Instant Frame relay to if_sr and if_ar drivers, and PPPOE support soon. See: ftp://ftp.whistle.com/pub/archie/netgraph/index.html for on-line manual pages. Reviewed by: Doug Rabson (dfr@freebsd.org) Obtained from: Whistle CVS tree --- sys/dev/sr/if_sr.c | 699 ++++++++++++++++++++++++++++++++++++++++++++++--- sys/dev/sr/if_sr.h | 23 ++ sys/dev/sr/if_sr_isa.c | 699 ++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 1347 insertions(+), 74 deletions(-) create mode 100644 sys/dev/sr/if_sr.h (limited to 'sys/dev/sr') diff --git a/sys/dev/sr/if_sr.c b/sys/dev/sr/if_sr.c index 6be7958..f50f7a5 100644 --- a/sys/dev/sr/if_sr.c +++ b/sys/dev/sr/if_sr.c @@ -48,16 +48,23 @@ */ #include "sr.h" +#include "opt_netgraph.h" +#ifdef NETGRAPH +#include +#else /* NETGRAPH */ #ifdef notyet #include "fr.h" #else #define NFR 0 #endif +#endif /* NETGRAPH */ +#ifdef NETGRAPH #include "sppp.h" #if NSPPP <= 0 #error Device 'sr' requires sppp. #endif +#endif /* NETGRAPH */ #include #include @@ -68,9 +75,13 @@ #include #include +#ifdef NETGRAPH +#include +#else /* NETGRAPH */ #include #include +#endif /* NETGRAPH */ #include @@ -78,13 +89,19 @@ #include #include +#ifdef NETGRAPH +#include +#include +#endif /* NETGRAPH */ /* #define USE_MODEMCK */ #ifndef BUGGY #define BUGGY 0 #endif +#ifndef NETGRAPH #define PPP_HEADER_LEN 4 +#endif /* NETGRAPH */ /* * These macros are used to hide the difference between the way the @@ -142,7 +159,9 @@ struct sr_hardc { }; static int next_sc_unit = 0; +#ifndef NETGRAPH static int sr_watcher = 0; +#endif /* NETGRAPH */ static struct sr_hardc sr_hardc[NSR]; static struct sr_hardc *sr_hardc_pci; @@ -151,17 +170,20 @@ static struct sr_hardc *sr_hardc_pci; * every channel (port). */ struct sr_softc { +#ifndef NETGRAPH struct sppp ifsppp; /* PPP service w/in system */ +#endif /* NETGRAPH */ struct sr_hardc *hc; /* card-level information */ int unit; /* With regard to all sr devices */ int subunit; /* With regard to this card */ +#ifndef NETGRAPH int attached; /* attached to FR or PPP */ int protocol; /* FR or PPP */ #define N2_USE_FRP 2 /* Frame Relay Protocol */ #define N2_USE_PPP 1 /* Point-to-Point Protocol */ - +#endif /* NETGRAPH */ struct buf_block { u_int txdesc; /* DPRAM offset */ u_int txstart;/* DPRAM offset */ @@ -185,8 +207,40 @@ struct sr_softc { u_int clk_cfg; /* Clock configuration */ int scachan; /* channel # on card */ +#ifdef NETGRAPH + int running; /* something is attached so we are running */ + int dcd; /* do we have dcd? */ + /* ---netgraph bits --- */ + char nodename[NG_NODELEN + 1]; /* store our node name */ + int datahooks; /* number of data hooks attached */ + node_p node; /* netgraph node */ + hook_p hook; /* data hook */ + hook_p debug_hook; + struct ifqueue xmitq_hipri; /* hi-priority transmit queue */ + struct ifqueue xmitq; /* transmit queue */ + int flags; /* state */ +#define SCF_RUNNING 0x01 /* board is active */ +#define SCF_OACTIVE 0x02 /* output is active */ + int out_dog; /* watchdog cycles output count-down */ +#if ( __FreeBSD__ >= 3 ) + struct callout_handle handle; /* timeout(9) handle */ +#endif + u_long inbytes, outbytes; /* stats */ + u_long lastinbytes, lastoutbytes; /* a second ago */ + u_long inrate, outrate; /* highest rate seen */ + u_long inlast; /* last input N secs ago */ + u_long out_deficit; /* output since last input */ + u_long oerrors, ierrors[6]; + u_long opackets, ipackets; +#endif /* NETGRAPH */ }; +#ifdef NETGRAPH +#define DOG_HOLDOFF 6 /* dog holds off for 6 secs */ +#define QUITE_A_WHILE 300 /* 5 MINUTES */ +#define LOTS_OF_PACKETS 100 +#endif /* NETGRAPH */ + /* * List of valid interrupt numbers for the N2 ISA card. */ @@ -267,11 +321,17 @@ struct sr_hardc *srattach_pci(int unit, vm_offset_t plx_vaddr, void srintr_hc(struct sr_hardc *hc); static ointhand2_t srintr; + static int srattach(struct sr_hardc *hc); static void sr_xmit(struct sr_softc *sc); +#ifndef NETGRAPH static void srstart(struct ifnet *ifp); static int srioctl(struct ifnet *ifp, u_long cmd, caddr_t data); static void srwatchdog(struct ifnet *ifp); +#else +static void srstart(struct sr_softc *sc); +static void srwatchdog(struct sr_softc *sc); +#endif /* NETGRAPH */ static int sr_packet_avail(struct sr_softc *sc, int *len, u_char *rxstat); static void sr_copy_rxbuf(struct mbuf *m, struct sr_softc *sc, int len); static void sr_eat_packet(struct sr_softc *sc, int single); @@ -287,7 +347,11 @@ static void sr_init_tx_dmac(struct sr_softc *sc); static void sr_dmac_intr(struct sr_hardc *hc, u_char isr); static void sr_msci_intr(struct sr_hardc *hc, u_char isr); static void sr_timer_intr(struct sr_hardc *hc, u_char isr); +#ifndef NETGRAPH static void sr_modemck(void *x); +#else +static void sr_modemck(struct sr_softc *x); +#endif /* NETGRAPH */ static u_int src_get8_io(u_int base, u_int off); static u_int src_get16_io(u_int base, u_int off); @@ -298,6 +362,7 @@ static u_int src_get16_mem(u_int base, u_int off); static void src_put8_mem(u_int base, u_int off, u_int val); static void src_put16_mem(u_int base, u_int off, u_int val); +#ifndef NETGRAPH #if NFR > 0 extern void fr_detach(struct ifnet *); extern int fr_attach(struct ifnet *); @@ -306,6 +371,36 @@ extern void fr_flush(struct ifnet *); extern int fr_input(struct ifnet *, struct mbuf *); extern struct mbuf *fr_dequeue(struct ifnet *); #endif +#else +static void ngsr_watchdog_frame(void * arg); +static void ngsr_init(void* ignored); +static int ngsr_constructor(node_p *nodep); +static int ngsr_rcvmsg(node_p node, struct ng_mesg *msg, + const char *retaddr, struct ng_mesg **resp); +static int ngsr_rmnode(node_p node); +static int ngsr_newhook(node_p node, hook_p hook, const char *name); +/*static hook_p ngsr_findhook(node_p node, char *name);*/ +static int ngsr_connect(hook_p hook); /* already PARTLY linked */ +static int ngsr_rcvdata(hook_p hook, struct mbuf *m, meta_p meta); +static int ngsr_disconnect(hook_p hook); /* notify on disconnect */ + +static struct ng_type typestruct = { + NG_VERSION, + NG_SR_NODE_TYPE, + NULL, + ngsr_constructor, + ngsr_rcvmsg, + ngsr_rmnode, + ngsr_newhook, + NULL, + ngsr_connect, + ngsr_rcvdata, + ngsr_rcvdata, + ngsr_disconnect +}; + +static int ngsr_done_init = 0; +#endif /* NETGRAPH */ /* * I/O for ISA N2 card(s) @@ -569,6 +664,15 @@ srattach_isa(struct isa_device *id) u_char mar; struct sr_hardc *hc = &sr_hardc[id->id_unit]; + /* + * Allocate the software interface table(s) + */ + MALLOC(hc->sc, struct sr_softc *, + hc->numports * sizeof(struct sr_softc), M_DEVBUF, M_WAITOK); + if (hc->sc == NULL) + return(0); + bzero(hc->sc, hc->numports * sizeof(struct sr_softc)); + id->id_ointr = srintr; outb(hc->iobase + SR_PCR, inb(hc->iobase + SR_PCR) | SR_PCR_SCARUN); @@ -588,13 +692,6 @@ srattach_isa(struct isa_device *id) outb(hc->iobase + SR_BAR, mar); /* - * Allocate the software interface table(s) - */ - hc->sc = malloc(hc->numports * sizeof(struct sr_softc), - M_DEVBUF, M_WAITOK); - bzero(hc->sc, hc->numports * sizeof(struct sr_softc)); - - /* * Get the TX clock direction and configuration. The default is a * single external clock which is used by RX and TX. */ @@ -680,13 +777,19 @@ srattach_pci(int unit, vm_offset_t plx_vaddr, vm_offset_t sca_vaddr) hc = hc->next; } - hc = malloc(sizeof(struct sr_hardc), M_DEVBUF, M_WAITOK); - *hcp = hc; - bzero(hc, sizeof(struct sr_hardc)); + MALLOC(hc, struct sr_hardc *, sizeof(*hc), M_DEVBUF, M_WAITOK); + if (hc == NULL) + return NULL; + bzero(hc, sizeof(*hc)); - hc->sc = malloc(numports * sizeof(struct sr_softc), - M_DEVBUF, M_WAITOK); + MALLOC(hc->sc, struct sr_softc *, + numports * sizeof(struct sr_softc), M_DEVBUF, M_WAITOK); + if (hc->sc == NULL) { + FREE(hc, M_DEVBUF); + return NULL; + } bzero(hc->sc, numports * sizeof(struct sr_softc)); + *hcp = hc; hc->numports = numports; hc->cunit = unit; @@ -779,13 +882,17 @@ srattach_pci(int unit, vm_offset_t plx_vaddr, vm_offset_t sca_vaddr) /* * Register the ports on the adapter. * Fill in the info for each port. +#ifndef NETGRAPH * Attach each port to sppp and bpf. +#endif */ static int srattach(struct sr_hardc *hc) { struct sr_softc *sc = hc->sc; +#ifndef NETGRAPH struct ifnet *ifp; +#endif /* NETGRAPH */ int unit; /* index: channel w/in card */ /* @@ -813,6 +920,10 @@ srattach(struct sr_hardc *hc) sr_init_tx_dmac(sc); sr_init_msci(sc); + printf("sr%d: Adapter %d, port %d.\n", + sc->unit, hc->cunit, sc->subunit); + +#ifndef NETGRAPH ifp = &sc->ifsppp.pp_if; ifp->if_softc = sc; ifp->if_unit = sc->unit; @@ -823,9 +934,6 @@ srattach(struct sr_hardc *hc) ifp->if_start = srstart; ifp->if_watchdog = srwatchdog; - printf("sr%d: Adapter %d, port %d.\n", - sc->unit, hc->cunit, sc->subunit); - /* * Despite the fact that we want to allow both PPP *and* * Frame Relay access to a channel, due to the architecture @@ -846,6 +954,25 @@ srattach(struct sr_hardc *hc) if_attach(ifp); bpfattach(ifp, DLT_PPP, PPP_HEADER_LEN); +#else /* NETGRAPH */ + /* + * we have found a node, make sure our 'type' is availabe. + */ + if (ngsr_done_init == 0) ngsr_init(NULL); + if (ng_make_node_common(&typestruct, &sc->node) != 0) + return (0); + sc->node->private = sc; + callout_handle_init(&sc->handle); + sc->xmitq.ifq_maxlen = IFQ_MAXLEN; + sc->xmitq_hipri.ifq_maxlen = IFQ_MAXLEN; + sprintf(sc->nodename, "%s%d", NG_SR_NODE_TYPE, sc->unit); + if (ng_name_node(sc->node, sc->nodename)) { + ng_rmnode(sc->node); + ng_unref(sc->node); + return (0); + } + sc->running = 0; +#endif /* NETGRAPH */ } if (hc->mempages) @@ -855,26 +982,24 @@ srattach(struct sr_hardc *hc) } /* - * N2 Interrupt Service Routine. - * Get the ISA interrupts. - * + * N2 Interrupt Service Routine + * * First figure out which SCA gave the interrupt. - * + * Process it. + * See if there is other interrupts pending. + * Repeat until there no interrupts remain. */ static void srintr(int unit) -{ - struct sr_hardc *hc; +{ + struct sr_hardc *hc; hc = &sr_hardc[unit]; srintr_hc(hc); - return; + return; } -/* - * PCI interrupts come straight here - */ void srintr_hc(struct sr_hardc *hc) { @@ -908,7 +1033,11 @@ srintr_hc(struct sr_hardc *hc) #if BUGGY > 2 printf("src%d: srintr_hc isr0 %x, isr1 %x, isr2 %x\n", +#ifndef NETGRAPH unit, isr0, isr1, isr2); +#else + hc->cunit, isr0, isr1, isr2); +#endif /* NETGRAPH */ #endif /* @@ -938,7 +1067,9 @@ sr_xmit(struct sr_softc *sc) u_short cda_value; /* starting descriptor */ u_short eda_value; /* ending descriptor */ struct sr_hardc *hc; +#ifndef NETGRAPH struct ifnet *ifp; /* O/S Network Services */ +#endif /* NETGRAPH */ dmac_channel *dmac; /* DMA channel registers */ #if BUGGY > 0 @@ -946,7 +1077,9 @@ sr_xmit(struct sr_softc *sc) #endif hc = sc->hc; +#ifndef NETGRAPH ifp = &sc->ifsppp.pp_if; +#endif /* NETGRAPH */ dmac = &hc->sca->dmac[DMAC_TXCH(sc->scachan)]; /* @@ -979,11 +1112,18 @@ sr_xmit(struct sr_softc *sc) if (sc->txb_next_tx == SR_TX_BLOCKS) /* handle wrap... */ sc->txb_next_tx = 0; +#ifndef NETGRAPH /* * Finally, we'll set a timout (which will start srwatchdog()) * within the O/S network services layer... */ ifp->if_timer = 2; /* Value in seconds. */ +#else + /* + * Don't time out for a while. + */ + sc->out_dog = DOG_HOLDOFF; /* give ourself some breathing space*/ +#endif /* NETGRAPH */ } /* @@ -1000,10 +1140,16 @@ sr_xmit(struct sr_softc *sc) * The function that clears that should ensure that the transmitter * and its DMA is in a "good" idle state. */ +#ifndef NETGRAPH static void srstart(struct ifnet *ifp) { struct sr_softc *sc; /* channel control structure */ +#else +static void +srstart(struct sr_softc *sc) +{ +#endif /* NETGRAPH */ struct sr_hardc *hc; /* card control/config block */ int len; /* total length of a packet */ int pkts; /* packets placed in DPRAM */ @@ -1014,16 +1160,15 @@ srstart(struct ifnet *ifp) sca_descriptor *txdesc; /* working descriptor pointr */ struct buf_block *blkp; + hc = sc->hc; +#ifndef NETGRAPH #if BUGGY > 0 printf("sr: srstart( ifp=%08x)\n", ifp); #endif - sc = ifp->if_softc; - hc = sc->hc; - if ((ifp->if_flags & IFF_RUNNING) == 0) return; - +#endif /* NETGRAPH */ /* * It is OK to set the memory window outside the loop because all tx * buffers and descriptors are assumed to be in the same 16K window. @@ -1045,7 +1190,11 @@ top_srstart: * See if we have space for more packets. */ if (sc->txb_inuse == SR_TX_BLOCKS) { /* out of space? */ +#ifndef NETGRAPH ifp->if_flags |= IFF_OACTIVE; /* yes, mark active */ +#else + /*ifp->if_flags |= IFF_OACTIVE;*/ /* yes, mark active */ +#endif /* NETGRAPH */ if (hc->mempages) SRC_SET_OFF(hc->iobase); @@ -1071,6 +1220,7 @@ top_srstart: * dispatch table to select the service we're getting a packet * from... */ +#ifndef NETGRAPH switch (sc->protocol) { #if NFR > 0 case N2_USE_FRP: @@ -1081,7 +1231,12 @@ top_srstart: default: mtx = sppp_dequeue(ifp); } - +#else /* NETGRAPH */ + IF_DEQUEUE(&sc->xmitq_hipri, mtx); + if (mtx == NULL) { + IF_DEQUEUE(&sc->xmitq, mtx); + } +#endif /* NETGRAPH */ if (!mtx) { if (hc->mempages) SRC_SET_OFF(hc->iobase); @@ -1114,8 +1269,12 @@ top_srstart: sc->unit, mtx, len); #endif +#ifndef NETGRAPH if (ifp->if_bpf) bpf_mtap(ifp, mtx); +#else /* NETGRAPH */ + sc->outbytes += len; +#endif /* NETGRAPH */ /* * We can perform a straight copy because the tranmit @@ -1159,7 +1318,11 @@ top_srstart: * and update the statistics... */ m_freem(mtx); +#ifndef NETGRAPH ++sc->ifsppp.pp_if.if_opackets; +#else /* NETGRAPH */ + sc->opackets++; +#endif /* NETGRAPH */ /* * Check if we have space for another packet. XXX This is @@ -1176,6 +1339,7 @@ top_srstart: /* * We'll pull the next message to be sent (if any) */ +#ifndef NETGRAPH switch (sc->protocol) { #if NFR > 0 case N2_USE_FRP: @@ -1186,7 +1350,12 @@ top_srstart: default: mtx = sppp_dequeue(ifp); } - +#else /* NETGRAPH */ + IF_DEQUEUE(&sc->xmitq_hipri, mtx); + if (mtx == NULL) { + IF_DEQUEUE(&sc->xmitq, mtx); + } +#endif /* NETGRAPH */ if (!mtx) { /* no message? We're done! */ #if BUGGY > 9 printf("sr%d.srstart: pending=0, pkts=%d\n", @@ -1231,6 +1400,7 @@ top_srstart: goto top_srstart; } +#ifndef NETGRAPH /* * Handle ioctl's at the device level, though we *will* call up * a layer... @@ -1407,37 +1577,56 @@ srioctl(struct ifnet *ifp, u_long cmd, caddr_t data) return 0; } +#endif /* NETGRAPH */ /* * This is to catch lost tx interrupts. */ static void +#ifndef NETGRAPH srwatchdog(struct ifnet *ifp) +#else +srwatchdog(struct sr_softc *sc) +#endif /* NETGRAPH */ { int got_st0, got_st1, got_st3, got_dsr; +#ifndef NETGRAPH struct sr_softc *sc = ifp->if_softc; +#endif /* NETGRAPH */ struct sr_hardc *hc = sc->hc; msci_channel *msci = &hc->sca->msci[sc->scachan]; dmac_channel *dmac = &sc->hc->sca->dmac[sc->scachan]; #if BUGGY > 0 +#ifndef NETGRAPH printf("srwatchdog(unit=%d)\n", unit); +#else + printf("srwatchdog(unit=%d)\n", sc->unit); +#endif /* NETGRAPH */ #endif +#ifndef NETGRAPH if (!(ifp->if_flags & IFF_RUNNING)) return; ifp->if_oerrors++; /* update output error count */ +#else /* NETGRAPH */ + sc->oerrors++; /* update output error count */ +#endif /* NETGRAPH */ got_st0 = SRC_GET8(hc->sca_base, msci->st0); got_st1 = SRC_GET8(hc->sca_base, msci->st1); got_st3 = SRC_GET8(hc->sca_base, msci->st3); got_dsr = SRC_GET8(hc->sca_base, dmac->dsr); +#ifndef NETGRAPH #if 0 if (ifp->if_flags & IFF_DEBUG) #endif printf("sr%d: transmit failed, " +#else /* NETGRAPH */ + printf("sr%d: transmit failed, " +#endif /* NETGRAPH */ "ST0 %02x, ST1 %02x, ST3 %02x, DSR %02x.\n", sc->unit, got_st0, got_st1, got_st3, got_dsr); @@ -1448,12 +1637,20 @@ srwatchdog(struct ifnet *ifp) SRC_PUT8(hc->sca_base, msci->st1, SCA_ST1_UDRN); } sc->xmit_busy = 0; +#ifndef NETGRAPH ifp->if_flags &= ~IFF_OACTIVE; +#else + /*ifp->if_flags &= ~IFF_OACTIVE; */ +#endif /* NETGRAPH */ if (sc->txb_inuse && --sc->txb_inuse) sr_xmit(sc); +#ifndef NETGRAPH srstart(ifp); /* restart transmitter */ +#else + srstart(sc); /* restart transmitter */ +#endif /* NETGRAPH */ } static void @@ -1468,6 +1665,7 @@ sr_up(struct sr_softc *sc) printf("sr_up(sc=%08x)\n", sc); #endif +#ifndef NETGRAPH /* * This section should really do the attach to the appropriate * system service, be it frame relay or PPP... @@ -1489,6 +1687,7 @@ sr_up(struct sr_softc *sc) sc->attached = sc->protocol; } +#endif /* NETGRAPH */ /* * Enable transmitter and receiver. Raise DTR and RTS. Enable * interrupts. @@ -1537,10 +1736,16 @@ sr_up(struct sr_softc *sc) inb(hc->iobase); /* XXX slow it down a bit. */ SRC_PUT8(hc->sca_base, msci->cmd, SCA_CMD_TXENABLE); +#ifndef NETGRAPH #ifdef USE_MODEMCK if (sr_watcher == 0) sr_modemck(NULL); #endif +#else /* NETGRAPH */ + untimeout(ngsr_watchdog_frame, sc, sc->handle); + sc->handle = timeout(ngsr_watchdog_frame, sc, hz); + sc->running = 1; +#endif /* NETGRAPH */ } static void @@ -1554,6 +1759,10 @@ sr_down(struct sr_softc *sc) #if BUGGY > 0 printf("sr_down(sc=%08x)\n", sc); #endif +#ifdef NETGRAPH + untimeout(ngsr_watchdog_frame, sc, sc->handle); + sc->running = 0; +#endif /* NETGRAPH */ /* * Disable transmitter and receiver. Lower DTR and RTS. Disable @@ -1601,6 +1810,7 @@ sr_down(struct sr_softc *sc) SRC_GET8(hc->sca_base, sca->ier1) & ~0xF0); } +#ifndef NETGRAPH /* * This section does the detach from the currently configured net * service, be it frame relay or PPP... @@ -1617,6 +1827,7 @@ sr_down(struct sr_softc *sc) } sc->attached = 0; +#endif /* NETGRAPH */ } /* @@ -2373,7 +2584,9 @@ sr_get_packets(struct sr_softc *sc) u_int len; /* length of pending packet */ struct sr_hardc *hc; /* card-level information */ sca_descriptor *rxdesc; /* descriptor in memory */ +#ifndef NETGRAPH struct ifnet *ifp; /* network intf ctl table */ +#endif /* NETGRAPH */ struct mbuf *m = NULL; /* message buffer */ #if BUGGY > 0 @@ -2381,7 +2594,9 @@ sr_get_packets(struct sr_softc *sc) #endif hc = sc->hc; +#ifndef NETGRAPH ifp = &sc->ifsppp.pp_if; +#endif /* NETGRAPH */ if (hc->mempages) { SRC_SET_MEM(hc->iobase, sc->rxdesc); @@ -2412,6 +2627,10 @@ sr_get_packets(struct sr_softc *sc) #endif pkts++; +#ifdef NETGRAPH + sc->inbytes += len; + sc->inlast = 0; +#endif /* NETGRAPH */ /* * OK, we've settled the incoming message status. We can now @@ -2434,7 +2653,11 @@ sr_get_packets(struct sr_softc *sc) /* * construct control information for pass-off */ +#ifndef NETGRAPH m->m_pkthdr.rcvif = ifp; +#else + m->m_pkthdr.rcvif = NULL; +#endif /* NETGRAPH */ m->m_pkthdr.len = m->m_len = len; if (len > MHLEN) { MCLGET(m, M_DONTWAIT); @@ -2455,6 +2678,7 @@ sr_get_packets(struct sr_softc *sc) */ sr_copy_rxbuf(m, sc, len); /* copy from DPRAM */ +#ifndef NETGRAPH if (ifp->if_bpf) bpf_mtap(ifp, m); @@ -2469,7 +2693,6 @@ sr_get_packets(struct sr_softc *sc) bp[4], bp[5], bp[6]); } #endif - /* * Pass off the message to PPP, connecting it it to * the system... @@ -2487,6 +2710,24 @@ sr_get_packets(struct sr_softc *sc) ifp->if_ipackets++; +#else /* NETGRAPH */ +#if BUGGY > 3 + { + u_char *bp; + + bp = mtod(m,u_char *); + printf("sr%d: rd=%02x:%02x:%02x:%02x:%02x:%02x", + sc->unit, + bp[0], bp[1], bp[2], + bp[4], bp[5], bp[6]); + printf(":%02x:%02x:%02x:%02x:%02x:%02x\n", + bp[6], bp[7], bp[8], + bp[9], bp[10], bp[11]); + } +#endif + ng_queue_data(sc->hook, m, NULL); + sc->ipackets++; +#endif /* NETGRAPH */ /* * Update the eda to the previous descriptor. */ @@ -2523,7 +2764,11 @@ sr_get_packets(struct sr_softc *sc) */ sr_eat_packet(sc, 1); +#ifndef NETGRAPH ifp->if_ierrors++; +#else + sc->ierrors[0]++; +#endif /* NETGRAPH */ got_st3 = SRC_GET8(hc->sca_base, hc->sca->msci[sc->scachan].st3); @@ -2605,8 +2850,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) if (dsr & SCA_DSR_COF) { printf("sr%d: TX DMA Counter overflow, " "txpacket no %lu.\n", +#ifndef NETGRAPH sc->unit, sc->ifsppp.pp_if.if_opackets); sc->ifsppp.pp_if.if_oerrors++; +#else + sc->unit, sc->opackets); + sc->oerrors++; +#endif /* NETGRAPH */ } /* * Check for (& process) a Buffer overflow @@ -2615,11 +2865,19 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) printf("sr%d: TX DMA Buffer overflow, " "txpacket no %lu, dsr %02x, " "cda %04x, eda %04x.\n", +#ifndef NETGRAPH sc->unit, sc->ifsppp.pp_if.if_opackets, +#else + sc->unit, sc->opackets, +#endif /* NETGRAPH */ dsr, SRC_GET16(hc->sca_base, dmac->cda), SRC_GET16(hc->sca_base, dmac->eda)); +#ifndef NETGRAPH sc->ifsppp.pp_if.if_oerrors++; +#else + sc->oerrors++; +#endif /* NETGRAPH */ } /* * Check for (& process) an End of Transfer (OK) @@ -2637,8 +2895,14 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) printf("sr%d: TX Completed OK\n", sc->unit); #endif sc->xmit_busy = 0; +#ifndef NETGRAPH sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE; sc->ifsppp.pp_if.if_timer = 0; +#else + /* XXX may need to mark tx inactive? */ + sc->out_deficit++; + sc->out_dog = DOG_HOLDOFF; +#endif /* NETGRAPH */ if (sc->txb_inuse && --sc->txb_inuse) sr_xmit(sc); @@ -2660,14 +2924,22 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) #if BUGGY > 0 int tt, ind; +#ifndef NETGRAPH tt = sc->ifsppp.pp_if.if_ipackets; +#else /* NETGRAPH */ + tt = sc->ipackets; +#endif /* NETGRAPH */ ind = sc->rxhind; #endif sr_get_packets(sc); - #if BUGGY > 0 - if (tt == sc->ifsppp.pp_if.if_ipackets) { +#ifndef NETGRAPH + if (tt == sc->ifsppp.pp_if.if_ipackets) +#else /* NETGRAPH */ + if (tt == sc->ipackets) +#endif /* NETGRAPH */ + { sca_descriptor *rxdesc; int i; @@ -2702,7 +2974,7 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) if (hc->mempages) SRC_SET_OFF(hc->iobase); } -#endif +#endif /* BUGGY */ } /* * Check for Counter overflow @@ -2710,8 +2982,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) if (dsr & SCA_DSR_COF) { printf("sr%d: RX DMA Counter overflow, " "rxpkts %lu.\n", +#ifndef NETGRAPH sc->unit, sc->ifsppp.pp_if.if_ipackets); sc->ifsppp.pp_if.if_ierrors++; +#else /* NETGRAPH */ + sc->unit, sc->ipackets); + sc->ierrors[1]++; +#endif /* NETGRAPH */ } /* * Check for Buffer overflow @@ -2720,7 +2997,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) printf("sr%d: RX DMA Buffer overflow, " "rxpkts %lu, rxind %d, " "cda %x, eda %x, dsr %x.\n", +#ifndef NETGRAPH sc->unit, sc->ifsppp.pp_if.if_ipackets, +#else /* NETGRAPH */ + sc->unit, sc->ipackets, +#endif /* NETGRAPH */ sc->rxhind, SRC_GET16(hc->sca_base, dmac->cda), SRC_GET16(hc->sca_base, dmac->eda), @@ -2734,7 +3015,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) SRC_SET_ON(hc->iobase); sr_eat_packet(sc, 0); +#ifndef NETGRAPH sc->ifsppp.pp_if.if_ierrors++; +#else /* NETGRAPH */ + sc->ierrors[2]++; +#endif /* NETGRAPH */ SRC_PUT8(hc->sca_base, sca->msci[mch].cmd, @@ -2747,7 +3032,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) "rxpkts %lu, rxind %d, " "cda %x, eda %x, dsr %x. After\n", sc->unit, +#ifndef NETGRAPH + sc->ipackets, +#else /* NETGRAPH */ sc->ifsppp.pp_if.if_ipackets, +#endif /* NETGRAPH */ sc->rxhind, SRC_GET16(hc->sca_base, dmac->cda), SRC_GET16(hc->sca_base, dmac->eda), @@ -2770,8 +3059,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) */ printf("sr%d: RX End of xfer, rxpkts %lu.\n", sc->unit, +#ifndef NETGRAPH sc->ifsppp.pp_if.if_ipackets); sc->ifsppp.pp_if.if_ierrors++; +#else + sc->ipackets); + sc->ierrors[3]++; +#endif /* NETGRAPH */ } } isr1 >>= 4; /* process next half of ISR */ @@ -2785,12 +3079,16 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) for (mch = 0; mch < NCHAN; mch++) { if (dotxstart & 0x0C) { /* TX initiation enabled? */ sc = &hc->sc[mch]; +#ifndef NETGRAPH srstart(&sc->ifsppp.pp_if); +#else + srstart(sc); +#endif /* NETGRAPH */ } dotxstart >>= 4;/* shift for next channel */ } } - +#ifndef NETGRAPH /* * Perform timeout on an FR channel * @@ -2910,6 +3208,38 @@ sr_modemck(void *arg) splx(s); } +#else /* NETGRAPH */ +/* + * If a port is open/active, it's DCD state is checked + * and a loss of DCD is recognized (and eventually processed?). + */ +static void +sr_modemck(struct sr_softc *sc ) +{ + u_int s; + u_char got_st3; /* contents of ST3 */ + struct sr_hardc *hc = sc->hc; /* card's configuration */ + msci_channel *msci; /* regs specific to channel */ + + s = splimp(); + + + if (sc->running == 0) + return; + /* + * OK, now we can go looking at this channel's register contents... + */ + msci = &hc->sca->msci[sc->scachan]; + got_st3 = SRC_GET8(hc->sca_base, msci->st3); + + /* + * We want to see if the DCD signal is up (DCD is true if zero) + */ + sc->dcd = (got_st3 & SCA_ST3_DCD) == 0; + splx(s); +} + +#endif /* NETGRAPH */ static void sr_msci_intr(struct sr_hardc *hc, u_char isr0) { @@ -2922,6 +3252,301 @@ sr_timer_intr(struct sr_hardc *hc, u_char isr2) printf("src%d: SRINTR: TIMER\n", hc->cunit); } +#ifdef NETGRAPH +/***************************************** + * Device timeout/watchdog routine. + * called once per second. + * checks to see that if activity was expected, that it hapenned. + * At present we only look to see if expected output was completed. + */ +static void +ngsr_watchdog_frame(void * arg) +{ + struct sr_softc * sc = arg; + int s; + int speed; + + if(sc->running == 0) + return; /* if we are not running let timeouts die */ + /* + * calculate the apparent throughputs + * XXX a real hack + */ + s = splimp(); + speed = sc->inbytes - sc->lastinbytes; + sc->lastinbytes = sc->inbytes; + if ( sc->inrate < speed ) + sc->inrate = speed; + speed = sc->outbytes - sc->lastoutbytes; + sc->lastoutbytes = sc->outbytes; + if ( sc->outrate < speed ) + sc->outrate = speed; + sc->inlast++; + splx(s); + + if ((sc->inlast > QUITE_A_WHILE) + && (sc->out_deficit > LOTS_OF_PACKETS)) { + log(LOG_ERR, "sr%d: No response from remote end\n", sc->unit); + s = splimp(); + sr_down(sc); + sr_up(sc); + sc->inlast = sc->out_deficit = 0; + splx(s); + } else if ( sc->xmit_busy ) { /* no TX -> no TX timeouts */ + if (sc->out_dog == 0) { + log(LOG_ERR, "sr%d: Transmit failure.. no clock?\n", + sc->unit); + srwatchdog(sc); +#if 0 + s = splimp(); + sr_down(sc); + sr_up(sc); + splx(s); +#endif + sc->inlast = sc->out_deficit = 0; + } else { + sc->out_dog--; + } + } + sr_modemck(sc); /* update the DCD status */ + sc->handle = timeout(ngsr_watchdog_frame, sc, hz); +} + +/*********************************************************************** + * This section contains the methods for the Netgraph interface + ***********************************************************************/ +/* + * It is not possible or allowable to create a node of this type. + * If the hardware exists, it will already have created it. + */ +static int +ngsr_constructor(node_p *nodep) +{ + return (EINVAL); +} + +/* + * give our ok for a hook to be added... + * If we are not running this should kick the device into life. + * We allow hooks called "control" and dlci[1-1023] + * The hook's private info points to our stash of info about that + * channel. + */ +static int +ngsr_newhook(node_p node, hook_p hook, const char *name) +{ + struct sr_softc * sc = node->private; + + /* + * check if it's our friend the debug hook + */ + if (strcmp(name, NG_SR_HOOK_DEBUG) == 0) { + hook->private = NULL; /* paranoid */ + sc->debug_hook = hook; + return (0); + } + + /* + * Check for raw mode hook. + */ + if (strcmp(name, NG_SR_HOOK_RAW) != 0) { + return (EINVAL); + } + hook->private = sc; + sc->hook = hook; + sc->datahooks++; + sr_up(sc); + return (0); +} + +/* + * incoming messages. + * Just respond to the generic TEXT_STATUS message + */ +static int +ngsr_rcvmsg(node_p node, + struct ng_mesg *msg, const char *retaddr, struct ng_mesg **resp) +{ + struct sr_softc * sc; + int error = 0; + + sc = node->private; + switch (msg->header.typecookie) { + case NG_SR_COOKIE: + error = EINVAL; + break; + case NGM_GENERIC_COOKIE: + switch(msg->header.cmd) { + case NGM_TEXT_STATUS: { + char *arg; + int pos = 0; + int resplen = sizeof(struct ng_mesg) + 512; + MALLOC(*resp, struct ng_mesg *, resplen, + M_NETGRAPH, M_NOWAIT); + if (*resp == NULL) { + error = ENOMEM; + break; + } + bzero(*resp, resplen); + arg = (*resp)->data; + + /* + * Put in the throughput information. + */ + pos = sprintf(arg, "%ld bytes in, %ld bytes out\n" + "highest rate seen: %ld B/S in, %ld B/S out\n", + sc->inbytes, sc->outbytes, + sc->inrate, sc->outrate); + pos += sprintf(arg + pos, + "%ld output errors\n", + sc->oerrors); + pos += sprintf(arg + pos, + "ierrors = %ld, %ld, %ld, %ld, %ld, %ld\n", + sc->ierrors[0], + sc->ierrors[1], + sc->ierrors[2], + sc->ierrors[3], + sc->ierrors[4], + sc->ierrors[5]); + + (*resp)->header.version = NG_VERSION; + (*resp)->header.arglen = strlen(arg) + 1; + (*resp)->header.token = msg->header.token; + (*resp)->header.typecookie = NG_SR_COOKIE; + (*resp)->header.cmd = msg->header.cmd; + strncpy((*resp)->header.cmdstr, "status", + NG_CMDSTRLEN); + } + break; + default: + error = EINVAL; + break; + } + break; + default: + error = EINVAL; + break; + } + free(msg, M_NETGRAPH); + return (error); +} + +/* + * get data from another node and transmit it to the correct channel + */ +static int +ngsr_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) +{ + int s; + int error = 0; + struct sr_softc * sc = hook->node->private; + struct ifqueue *xmitq_p; + + /* + * data doesn't come in from just anywhere (e.g control hook) + */ + if ( hook->private == NULL) { + error = ENETDOWN; + goto bad; + } + + /* + * Now queue the data for when it can be sent + */ + if (meta && meta->priority > 0) { + xmitq_p = (&sc->xmitq_hipri); + } else { + xmitq_p = (&sc->xmitq); + } + s = splimp(); + if (IF_QFULL(xmitq_p)) { + IF_DROP(xmitq_p); + splx(s); + error = ENOBUFS; + goto bad; + } + IF_ENQUEUE(xmitq_p, m); + splx(s); + srstart(sc); + return (0); + +bad: + /* + * It was an error case. + * check if we need to free the mbuf, and then return the error + */ + NG_FREE_DATA(m, meta); + return (error); +} + +/* + * do local shutdown processing.. + * this node will refuse to go away, unless the hardware says to.. + * don't unref the node, or remove our name. just clear our links up. + */ +static int +ngsr_rmnode(node_p node) +{ + struct sr_softc * sc = node->private; + + sr_down(sc); + ng_cutlinks(node); + node->flags &= ~NG_INVALID; /* bounce back to life */ + return (0); +} + +/* already linked */ +static int +ngsr_connect(hook_p hook) +{ + /* be really amiable and just say "YUP that's OK by me! " */ + return (0); +} + +/* + * notify on hook disconnection (destruction) + * + * Invalidate the private data associated with this dlci. + * For this type, removal of the last link resets tries to destroy the node. + * As the device still exists, the shutdown method will not actually + * destroy the node, but reset the device and leave it 'fresh' :) + * + * The node removal code will remove all references except that owned by the + * driver. + */ +static int +ngsr_disconnect(hook_p hook) +{ + struct sr_softc * sc = hook->node->private; + int s; + /* + * If it's the data hook, then free resources etc. + */ + if (hook->private) { + s = splimp(); + sc->datahooks--; + if (sc->datahooks == 0) + sr_down(sc); + splx(s); + } else { + sc->debug_hook = NULL; + } + return (0); +} + +/* + * called during bootup + * or LKM loading to put this type into the list of known modules + */ +static void +ngsr_init(void *ignored) +{ + if (ng_newtype(&typestruct)) + printf("ngsr install failed\n"); + ngsr_done_init = 1; +} +#endif /* NETGRAPH */ + /* ********************************* END ************************************ */ diff --git a/sys/dev/sr/if_sr.h b/sys/dev/sr/if_sr.h new file mode 100644 index 0000000..d01a2cb --- /dev/null +++ b/sys/dev/sr/if_sr.h @@ -0,0 +1,23 @@ +/* + * if_sr.h + * + * Copyright (C) 1997-1999 Whistle Communications Inc. + * All rights reserved. + * + * $FreeBSD$ + */ + +#ifndef _I386_ISA_IF_SR_H_ +#define _I386_ISA_IF_SR_H_ + +/* Node type name and type cookie */ +#define NG_SR_NODE_TYPE "sync_sr" +#define NG_SR_COOKIE 860552148 + +/* Netgraph hooks */ +#define NG_SR_HOOK_DEBUG "debug" +#define NG_SR_HOOK_CONTROL "control" +#define NG_SR_HOOK_RAW "rawdata" + +#endif /* _I386_ISA_IF_SR_H_ */ + diff --git a/sys/dev/sr/if_sr_isa.c b/sys/dev/sr/if_sr_isa.c index 6be7958..f50f7a5 100644 --- a/sys/dev/sr/if_sr_isa.c +++ b/sys/dev/sr/if_sr_isa.c @@ -48,16 +48,23 @@ */ #include "sr.h" +#include "opt_netgraph.h" +#ifdef NETGRAPH +#include +#else /* NETGRAPH */ #ifdef notyet #include "fr.h" #else #define NFR 0 #endif +#endif /* NETGRAPH */ +#ifdef NETGRAPH #include "sppp.h" #if NSPPP <= 0 #error Device 'sr' requires sppp. #endif +#endif /* NETGRAPH */ #include #include @@ -68,9 +75,13 @@ #include #include +#ifdef NETGRAPH +#include +#else /* NETGRAPH */ #include #include +#endif /* NETGRAPH */ #include @@ -78,13 +89,19 @@ #include #include +#ifdef NETGRAPH +#include +#include +#endif /* NETGRAPH */ /* #define USE_MODEMCK */ #ifndef BUGGY #define BUGGY 0 #endif +#ifndef NETGRAPH #define PPP_HEADER_LEN 4 +#endif /* NETGRAPH */ /* * These macros are used to hide the difference between the way the @@ -142,7 +159,9 @@ struct sr_hardc { }; static int next_sc_unit = 0; +#ifndef NETGRAPH static int sr_watcher = 0; +#endif /* NETGRAPH */ static struct sr_hardc sr_hardc[NSR]; static struct sr_hardc *sr_hardc_pci; @@ -151,17 +170,20 @@ static struct sr_hardc *sr_hardc_pci; * every channel (port). */ struct sr_softc { +#ifndef NETGRAPH struct sppp ifsppp; /* PPP service w/in system */ +#endif /* NETGRAPH */ struct sr_hardc *hc; /* card-level information */ int unit; /* With regard to all sr devices */ int subunit; /* With regard to this card */ +#ifndef NETGRAPH int attached; /* attached to FR or PPP */ int protocol; /* FR or PPP */ #define N2_USE_FRP 2 /* Frame Relay Protocol */ #define N2_USE_PPP 1 /* Point-to-Point Protocol */ - +#endif /* NETGRAPH */ struct buf_block { u_int txdesc; /* DPRAM offset */ u_int txstart;/* DPRAM offset */ @@ -185,8 +207,40 @@ struct sr_softc { u_int clk_cfg; /* Clock configuration */ int scachan; /* channel # on card */ +#ifdef NETGRAPH + int running; /* something is attached so we are running */ + int dcd; /* do we have dcd? */ + /* ---netgraph bits --- */ + char nodename[NG_NODELEN + 1]; /* store our node name */ + int datahooks; /* number of data hooks attached */ + node_p node; /* netgraph node */ + hook_p hook; /* data hook */ + hook_p debug_hook; + struct ifqueue xmitq_hipri; /* hi-priority transmit queue */ + struct ifqueue xmitq; /* transmit queue */ + int flags; /* state */ +#define SCF_RUNNING 0x01 /* board is active */ +#define SCF_OACTIVE 0x02 /* output is active */ + int out_dog; /* watchdog cycles output count-down */ +#if ( __FreeBSD__ >= 3 ) + struct callout_handle handle; /* timeout(9) handle */ +#endif + u_long inbytes, outbytes; /* stats */ + u_long lastinbytes, lastoutbytes; /* a second ago */ + u_long inrate, outrate; /* highest rate seen */ + u_long inlast; /* last input N secs ago */ + u_long out_deficit; /* output since last input */ + u_long oerrors, ierrors[6]; + u_long opackets, ipackets; +#endif /* NETGRAPH */ }; +#ifdef NETGRAPH +#define DOG_HOLDOFF 6 /* dog holds off for 6 secs */ +#define QUITE_A_WHILE 300 /* 5 MINUTES */ +#define LOTS_OF_PACKETS 100 +#endif /* NETGRAPH */ + /* * List of valid interrupt numbers for the N2 ISA card. */ @@ -267,11 +321,17 @@ struct sr_hardc *srattach_pci(int unit, vm_offset_t plx_vaddr, void srintr_hc(struct sr_hardc *hc); static ointhand2_t srintr; + static int srattach(struct sr_hardc *hc); static void sr_xmit(struct sr_softc *sc); +#ifndef NETGRAPH static void srstart(struct ifnet *ifp); static int srioctl(struct ifnet *ifp, u_long cmd, caddr_t data); static void srwatchdog(struct ifnet *ifp); +#else +static void srstart(struct sr_softc *sc); +static void srwatchdog(struct sr_softc *sc); +#endif /* NETGRAPH */ static int sr_packet_avail(struct sr_softc *sc, int *len, u_char *rxstat); static void sr_copy_rxbuf(struct mbuf *m, struct sr_softc *sc, int len); static void sr_eat_packet(struct sr_softc *sc, int single); @@ -287,7 +347,11 @@ static void sr_init_tx_dmac(struct sr_softc *sc); static void sr_dmac_intr(struct sr_hardc *hc, u_char isr); static void sr_msci_intr(struct sr_hardc *hc, u_char isr); static void sr_timer_intr(struct sr_hardc *hc, u_char isr); +#ifndef NETGRAPH static void sr_modemck(void *x); +#else +static void sr_modemck(struct sr_softc *x); +#endif /* NETGRAPH */ static u_int src_get8_io(u_int base, u_int off); static u_int src_get16_io(u_int base, u_int off); @@ -298,6 +362,7 @@ static u_int src_get16_mem(u_int base, u_int off); static void src_put8_mem(u_int base, u_int off, u_int val); static void src_put16_mem(u_int base, u_int off, u_int val); +#ifndef NETGRAPH #if NFR > 0 extern void fr_detach(struct ifnet *); extern int fr_attach(struct ifnet *); @@ -306,6 +371,36 @@ extern void fr_flush(struct ifnet *); extern int fr_input(struct ifnet *, struct mbuf *); extern struct mbuf *fr_dequeue(struct ifnet *); #endif +#else +static void ngsr_watchdog_frame(void * arg); +static void ngsr_init(void* ignored); +static int ngsr_constructor(node_p *nodep); +static int ngsr_rcvmsg(node_p node, struct ng_mesg *msg, + const char *retaddr, struct ng_mesg **resp); +static int ngsr_rmnode(node_p node); +static int ngsr_newhook(node_p node, hook_p hook, const char *name); +/*static hook_p ngsr_findhook(node_p node, char *name);*/ +static int ngsr_connect(hook_p hook); /* already PARTLY linked */ +static int ngsr_rcvdata(hook_p hook, struct mbuf *m, meta_p meta); +static int ngsr_disconnect(hook_p hook); /* notify on disconnect */ + +static struct ng_type typestruct = { + NG_VERSION, + NG_SR_NODE_TYPE, + NULL, + ngsr_constructor, + ngsr_rcvmsg, + ngsr_rmnode, + ngsr_newhook, + NULL, + ngsr_connect, + ngsr_rcvdata, + ngsr_rcvdata, + ngsr_disconnect +}; + +static int ngsr_done_init = 0; +#endif /* NETGRAPH */ /* * I/O for ISA N2 card(s) @@ -569,6 +664,15 @@ srattach_isa(struct isa_device *id) u_char mar; struct sr_hardc *hc = &sr_hardc[id->id_unit]; + /* + * Allocate the software interface table(s) + */ + MALLOC(hc->sc, struct sr_softc *, + hc->numports * sizeof(struct sr_softc), M_DEVBUF, M_WAITOK); + if (hc->sc == NULL) + return(0); + bzero(hc->sc, hc->numports * sizeof(struct sr_softc)); + id->id_ointr = srintr; outb(hc->iobase + SR_PCR, inb(hc->iobase + SR_PCR) | SR_PCR_SCARUN); @@ -588,13 +692,6 @@ srattach_isa(struct isa_device *id) outb(hc->iobase + SR_BAR, mar); /* - * Allocate the software interface table(s) - */ - hc->sc = malloc(hc->numports * sizeof(struct sr_softc), - M_DEVBUF, M_WAITOK); - bzero(hc->sc, hc->numports * sizeof(struct sr_softc)); - - /* * Get the TX clock direction and configuration. The default is a * single external clock which is used by RX and TX. */ @@ -680,13 +777,19 @@ srattach_pci(int unit, vm_offset_t plx_vaddr, vm_offset_t sca_vaddr) hc = hc->next; } - hc = malloc(sizeof(struct sr_hardc), M_DEVBUF, M_WAITOK); - *hcp = hc; - bzero(hc, sizeof(struct sr_hardc)); + MALLOC(hc, struct sr_hardc *, sizeof(*hc), M_DEVBUF, M_WAITOK); + if (hc == NULL) + return NULL; + bzero(hc, sizeof(*hc)); - hc->sc = malloc(numports * sizeof(struct sr_softc), - M_DEVBUF, M_WAITOK); + MALLOC(hc->sc, struct sr_softc *, + numports * sizeof(struct sr_softc), M_DEVBUF, M_WAITOK); + if (hc->sc == NULL) { + FREE(hc, M_DEVBUF); + return NULL; + } bzero(hc->sc, numports * sizeof(struct sr_softc)); + *hcp = hc; hc->numports = numports; hc->cunit = unit; @@ -779,13 +882,17 @@ srattach_pci(int unit, vm_offset_t plx_vaddr, vm_offset_t sca_vaddr) /* * Register the ports on the adapter. * Fill in the info for each port. +#ifndef NETGRAPH * Attach each port to sppp and bpf. +#endif */ static int srattach(struct sr_hardc *hc) { struct sr_softc *sc = hc->sc; +#ifndef NETGRAPH struct ifnet *ifp; +#endif /* NETGRAPH */ int unit; /* index: channel w/in card */ /* @@ -813,6 +920,10 @@ srattach(struct sr_hardc *hc) sr_init_tx_dmac(sc); sr_init_msci(sc); + printf("sr%d: Adapter %d, port %d.\n", + sc->unit, hc->cunit, sc->subunit); + +#ifndef NETGRAPH ifp = &sc->ifsppp.pp_if; ifp->if_softc = sc; ifp->if_unit = sc->unit; @@ -823,9 +934,6 @@ srattach(struct sr_hardc *hc) ifp->if_start = srstart; ifp->if_watchdog = srwatchdog; - printf("sr%d: Adapter %d, port %d.\n", - sc->unit, hc->cunit, sc->subunit); - /* * Despite the fact that we want to allow both PPP *and* * Frame Relay access to a channel, due to the architecture @@ -846,6 +954,25 @@ srattach(struct sr_hardc *hc) if_attach(ifp); bpfattach(ifp, DLT_PPP, PPP_HEADER_LEN); +#else /* NETGRAPH */ + /* + * we have found a node, make sure our 'type' is availabe. + */ + if (ngsr_done_init == 0) ngsr_init(NULL); + if (ng_make_node_common(&typestruct, &sc->node) != 0) + return (0); + sc->node->private = sc; + callout_handle_init(&sc->handle); + sc->xmitq.ifq_maxlen = IFQ_MAXLEN; + sc->xmitq_hipri.ifq_maxlen = IFQ_MAXLEN; + sprintf(sc->nodename, "%s%d", NG_SR_NODE_TYPE, sc->unit); + if (ng_name_node(sc->node, sc->nodename)) { + ng_rmnode(sc->node); + ng_unref(sc->node); + return (0); + } + sc->running = 0; +#endif /* NETGRAPH */ } if (hc->mempages) @@ -855,26 +982,24 @@ srattach(struct sr_hardc *hc) } /* - * N2 Interrupt Service Routine. - * Get the ISA interrupts. - * + * N2 Interrupt Service Routine + * * First figure out which SCA gave the interrupt. - * + * Process it. + * See if there is other interrupts pending. + * Repeat until there no interrupts remain. */ static void srintr(int unit) -{ - struct sr_hardc *hc; +{ + struct sr_hardc *hc; hc = &sr_hardc[unit]; srintr_hc(hc); - return; + return; } -/* - * PCI interrupts come straight here - */ void srintr_hc(struct sr_hardc *hc) { @@ -908,7 +1033,11 @@ srintr_hc(struct sr_hardc *hc) #if BUGGY > 2 printf("src%d: srintr_hc isr0 %x, isr1 %x, isr2 %x\n", +#ifndef NETGRAPH unit, isr0, isr1, isr2); +#else + hc->cunit, isr0, isr1, isr2); +#endif /* NETGRAPH */ #endif /* @@ -938,7 +1067,9 @@ sr_xmit(struct sr_softc *sc) u_short cda_value; /* starting descriptor */ u_short eda_value; /* ending descriptor */ struct sr_hardc *hc; +#ifndef NETGRAPH struct ifnet *ifp; /* O/S Network Services */ +#endif /* NETGRAPH */ dmac_channel *dmac; /* DMA channel registers */ #if BUGGY > 0 @@ -946,7 +1077,9 @@ sr_xmit(struct sr_softc *sc) #endif hc = sc->hc; +#ifndef NETGRAPH ifp = &sc->ifsppp.pp_if; +#endif /* NETGRAPH */ dmac = &hc->sca->dmac[DMAC_TXCH(sc->scachan)]; /* @@ -979,11 +1112,18 @@ sr_xmit(struct sr_softc *sc) if (sc->txb_next_tx == SR_TX_BLOCKS) /* handle wrap... */ sc->txb_next_tx = 0; +#ifndef NETGRAPH /* * Finally, we'll set a timout (which will start srwatchdog()) * within the O/S network services layer... */ ifp->if_timer = 2; /* Value in seconds. */ +#else + /* + * Don't time out for a while. + */ + sc->out_dog = DOG_HOLDOFF; /* give ourself some breathing space*/ +#endif /* NETGRAPH */ } /* @@ -1000,10 +1140,16 @@ sr_xmit(struct sr_softc *sc) * The function that clears that should ensure that the transmitter * and its DMA is in a "good" idle state. */ +#ifndef NETGRAPH static void srstart(struct ifnet *ifp) { struct sr_softc *sc; /* channel control structure */ +#else +static void +srstart(struct sr_softc *sc) +{ +#endif /* NETGRAPH */ struct sr_hardc *hc; /* card control/config block */ int len; /* total length of a packet */ int pkts; /* packets placed in DPRAM */ @@ -1014,16 +1160,15 @@ srstart(struct ifnet *ifp) sca_descriptor *txdesc; /* working descriptor pointr */ struct buf_block *blkp; + hc = sc->hc; +#ifndef NETGRAPH #if BUGGY > 0 printf("sr: srstart( ifp=%08x)\n", ifp); #endif - sc = ifp->if_softc; - hc = sc->hc; - if ((ifp->if_flags & IFF_RUNNING) == 0) return; - +#endif /* NETGRAPH */ /* * It is OK to set the memory window outside the loop because all tx * buffers and descriptors are assumed to be in the same 16K window. @@ -1045,7 +1190,11 @@ top_srstart: * See if we have space for more packets. */ if (sc->txb_inuse == SR_TX_BLOCKS) { /* out of space? */ +#ifndef NETGRAPH ifp->if_flags |= IFF_OACTIVE; /* yes, mark active */ +#else + /*ifp->if_flags |= IFF_OACTIVE;*/ /* yes, mark active */ +#endif /* NETGRAPH */ if (hc->mempages) SRC_SET_OFF(hc->iobase); @@ -1071,6 +1220,7 @@ top_srstart: * dispatch table to select the service we're getting a packet * from... */ +#ifndef NETGRAPH switch (sc->protocol) { #if NFR > 0 case N2_USE_FRP: @@ -1081,7 +1231,12 @@ top_srstart: default: mtx = sppp_dequeue(ifp); } - +#else /* NETGRAPH */ + IF_DEQUEUE(&sc->xmitq_hipri, mtx); + if (mtx == NULL) { + IF_DEQUEUE(&sc->xmitq, mtx); + } +#endif /* NETGRAPH */ if (!mtx) { if (hc->mempages) SRC_SET_OFF(hc->iobase); @@ -1114,8 +1269,12 @@ top_srstart: sc->unit, mtx, len); #endif +#ifndef NETGRAPH if (ifp->if_bpf) bpf_mtap(ifp, mtx); +#else /* NETGRAPH */ + sc->outbytes += len; +#endif /* NETGRAPH */ /* * We can perform a straight copy because the tranmit @@ -1159,7 +1318,11 @@ top_srstart: * and update the statistics... */ m_freem(mtx); +#ifndef NETGRAPH ++sc->ifsppp.pp_if.if_opackets; +#else /* NETGRAPH */ + sc->opackets++; +#endif /* NETGRAPH */ /* * Check if we have space for another packet. XXX This is @@ -1176,6 +1339,7 @@ top_srstart: /* * We'll pull the next message to be sent (if any) */ +#ifndef NETGRAPH switch (sc->protocol) { #if NFR > 0 case N2_USE_FRP: @@ -1186,7 +1350,12 @@ top_srstart: default: mtx = sppp_dequeue(ifp); } - +#else /* NETGRAPH */ + IF_DEQUEUE(&sc->xmitq_hipri, mtx); + if (mtx == NULL) { + IF_DEQUEUE(&sc->xmitq, mtx); + } +#endif /* NETGRAPH */ if (!mtx) { /* no message? We're done! */ #if BUGGY > 9 printf("sr%d.srstart: pending=0, pkts=%d\n", @@ -1231,6 +1400,7 @@ top_srstart: goto top_srstart; } +#ifndef NETGRAPH /* * Handle ioctl's at the device level, though we *will* call up * a layer... @@ -1407,37 +1577,56 @@ srioctl(struct ifnet *ifp, u_long cmd, caddr_t data) return 0; } +#endif /* NETGRAPH */ /* * This is to catch lost tx interrupts. */ static void +#ifndef NETGRAPH srwatchdog(struct ifnet *ifp) +#else +srwatchdog(struct sr_softc *sc) +#endif /* NETGRAPH */ { int got_st0, got_st1, got_st3, got_dsr; +#ifndef NETGRAPH struct sr_softc *sc = ifp->if_softc; +#endif /* NETGRAPH */ struct sr_hardc *hc = sc->hc; msci_channel *msci = &hc->sca->msci[sc->scachan]; dmac_channel *dmac = &sc->hc->sca->dmac[sc->scachan]; #if BUGGY > 0 +#ifndef NETGRAPH printf("srwatchdog(unit=%d)\n", unit); +#else + printf("srwatchdog(unit=%d)\n", sc->unit); +#endif /* NETGRAPH */ #endif +#ifndef NETGRAPH if (!(ifp->if_flags & IFF_RUNNING)) return; ifp->if_oerrors++; /* update output error count */ +#else /* NETGRAPH */ + sc->oerrors++; /* update output error count */ +#endif /* NETGRAPH */ got_st0 = SRC_GET8(hc->sca_base, msci->st0); got_st1 = SRC_GET8(hc->sca_base, msci->st1); got_st3 = SRC_GET8(hc->sca_base, msci->st3); got_dsr = SRC_GET8(hc->sca_base, dmac->dsr); +#ifndef NETGRAPH #if 0 if (ifp->if_flags & IFF_DEBUG) #endif printf("sr%d: transmit failed, " +#else /* NETGRAPH */ + printf("sr%d: transmit failed, " +#endif /* NETGRAPH */ "ST0 %02x, ST1 %02x, ST3 %02x, DSR %02x.\n", sc->unit, got_st0, got_st1, got_st3, got_dsr); @@ -1448,12 +1637,20 @@ srwatchdog(struct ifnet *ifp) SRC_PUT8(hc->sca_base, msci->st1, SCA_ST1_UDRN); } sc->xmit_busy = 0; +#ifndef NETGRAPH ifp->if_flags &= ~IFF_OACTIVE; +#else + /*ifp->if_flags &= ~IFF_OACTIVE; */ +#endif /* NETGRAPH */ if (sc->txb_inuse && --sc->txb_inuse) sr_xmit(sc); +#ifndef NETGRAPH srstart(ifp); /* restart transmitter */ +#else + srstart(sc); /* restart transmitter */ +#endif /* NETGRAPH */ } static void @@ -1468,6 +1665,7 @@ sr_up(struct sr_softc *sc) printf("sr_up(sc=%08x)\n", sc); #endif +#ifndef NETGRAPH /* * This section should really do the attach to the appropriate * system service, be it frame relay or PPP... @@ -1489,6 +1687,7 @@ sr_up(struct sr_softc *sc) sc->attached = sc->protocol; } +#endif /* NETGRAPH */ /* * Enable transmitter and receiver. Raise DTR and RTS. Enable * interrupts. @@ -1537,10 +1736,16 @@ sr_up(struct sr_softc *sc) inb(hc->iobase); /* XXX slow it down a bit. */ SRC_PUT8(hc->sca_base, msci->cmd, SCA_CMD_TXENABLE); +#ifndef NETGRAPH #ifdef USE_MODEMCK if (sr_watcher == 0) sr_modemck(NULL); #endif +#else /* NETGRAPH */ + untimeout(ngsr_watchdog_frame, sc, sc->handle); + sc->handle = timeout(ngsr_watchdog_frame, sc, hz); + sc->running = 1; +#endif /* NETGRAPH */ } static void @@ -1554,6 +1759,10 @@ sr_down(struct sr_softc *sc) #if BUGGY > 0 printf("sr_down(sc=%08x)\n", sc); #endif +#ifdef NETGRAPH + untimeout(ngsr_watchdog_frame, sc, sc->handle); + sc->running = 0; +#endif /* NETGRAPH */ /* * Disable transmitter and receiver. Lower DTR and RTS. Disable @@ -1601,6 +1810,7 @@ sr_down(struct sr_softc *sc) SRC_GET8(hc->sca_base, sca->ier1) & ~0xF0); } +#ifndef NETGRAPH /* * This section does the detach from the currently configured net * service, be it frame relay or PPP... @@ -1617,6 +1827,7 @@ sr_down(struct sr_softc *sc) } sc->attached = 0; +#endif /* NETGRAPH */ } /* @@ -2373,7 +2584,9 @@ sr_get_packets(struct sr_softc *sc) u_int len; /* length of pending packet */ struct sr_hardc *hc; /* card-level information */ sca_descriptor *rxdesc; /* descriptor in memory */ +#ifndef NETGRAPH struct ifnet *ifp; /* network intf ctl table */ +#endif /* NETGRAPH */ struct mbuf *m = NULL; /* message buffer */ #if BUGGY > 0 @@ -2381,7 +2594,9 @@ sr_get_packets(struct sr_softc *sc) #endif hc = sc->hc; +#ifndef NETGRAPH ifp = &sc->ifsppp.pp_if; +#endif /* NETGRAPH */ if (hc->mempages) { SRC_SET_MEM(hc->iobase, sc->rxdesc); @@ -2412,6 +2627,10 @@ sr_get_packets(struct sr_softc *sc) #endif pkts++; +#ifdef NETGRAPH + sc->inbytes += len; + sc->inlast = 0; +#endif /* NETGRAPH */ /* * OK, we've settled the incoming message status. We can now @@ -2434,7 +2653,11 @@ sr_get_packets(struct sr_softc *sc) /* * construct control information for pass-off */ +#ifndef NETGRAPH m->m_pkthdr.rcvif = ifp; +#else + m->m_pkthdr.rcvif = NULL; +#endif /* NETGRAPH */ m->m_pkthdr.len = m->m_len = len; if (len > MHLEN) { MCLGET(m, M_DONTWAIT); @@ -2455,6 +2678,7 @@ sr_get_packets(struct sr_softc *sc) */ sr_copy_rxbuf(m, sc, len); /* copy from DPRAM */ +#ifndef NETGRAPH if (ifp->if_bpf) bpf_mtap(ifp, m); @@ -2469,7 +2693,6 @@ sr_get_packets(struct sr_softc *sc) bp[4], bp[5], bp[6]); } #endif - /* * Pass off the message to PPP, connecting it it to * the system... @@ -2487,6 +2710,24 @@ sr_get_packets(struct sr_softc *sc) ifp->if_ipackets++; +#else /* NETGRAPH */ +#if BUGGY > 3 + { + u_char *bp; + + bp = mtod(m,u_char *); + printf("sr%d: rd=%02x:%02x:%02x:%02x:%02x:%02x", + sc->unit, + bp[0], bp[1], bp[2], + bp[4], bp[5], bp[6]); + printf(":%02x:%02x:%02x:%02x:%02x:%02x\n", + bp[6], bp[7], bp[8], + bp[9], bp[10], bp[11]); + } +#endif + ng_queue_data(sc->hook, m, NULL); + sc->ipackets++; +#endif /* NETGRAPH */ /* * Update the eda to the previous descriptor. */ @@ -2523,7 +2764,11 @@ sr_get_packets(struct sr_softc *sc) */ sr_eat_packet(sc, 1); +#ifndef NETGRAPH ifp->if_ierrors++; +#else + sc->ierrors[0]++; +#endif /* NETGRAPH */ got_st3 = SRC_GET8(hc->sca_base, hc->sca->msci[sc->scachan].st3); @@ -2605,8 +2850,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) if (dsr & SCA_DSR_COF) { printf("sr%d: TX DMA Counter overflow, " "txpacket no %lu.\n", +#ifndef NETGRAPH sc->unit, sc->ifsppp.pp_if.if_opackets); sc->ifsppp.pp_if.if_oerrors++; +#else + sc->unit, sc->opackets); + sc->oerrors++; +#endif /* NETGRAPH */ } /* * Check for (& process) a Buffer overflow @@ -2615,11 +2865,19 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) printf("sr%d: TX DMA Buffer overflow, " "txpacket no %lu, dsr %02x, " "cda %04x, eda %04x.\n", +#ifndef NETGRAPH sc->unit, sc->ifsppp.pp_if.if_opackets, +#else + sc->unit, sc->opackets, +#endif /* NETGRAPH */ dsr, SRC_GET16(hc->sca_base, dmac->cda), SRC_GET16(hc->sca_base, dmac->eda)); +#ifndef NETGRAPH sc->ifsppp.pp_if.if_oerrors++; +#else + sc->oerrors++; +#endif /* NETGRAPH */ } /* * Check for (& process) an End of Transfer (OK) @@ -2637,8 +2895,14 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) printf("sr%d: TX Completed OK\n", sc->unit); #endif sc->xmit_busy = 0; +#ifndef NETGRAPH sc->ifsppp.pp_if.if_flags &= ~IFF_OACTIVE; sc->ifsppp.pp_if.if_timer = 0; +#else + /* XXX may need to mark tx inactive? */ + sc->out_deficit++; + sc->out_dog = DOG_HOLDOFF; +#endif /* NETGRAPH */ if (sc->txb_inuse && --sc->txb_inuse) sr_xmit(sc); @@ -2660,14 +2924,22 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) #if BUGGY > 0 int tt, ind; +#ifndef NETGRAPH tt = sc->ifsppp.pp_if.if_ipackets; +#else /* NETGRAPH */ + tt = sc->ipackets; +#endif /* NETGRAPH */ ind = sc->rxhind; #endif sr_get_packets(sc); - #if BUGGY > 0 - if (tt == sc->ifsppp.pp_if.if_ipackets) { +#ifndef NETGRAPH + if (tt == sc->ifsppp.pp_if.if_ipackets) +#else /* NETGRAPH */ + if (tt == sc->ipackets) +#endif /* NETGRAPH */ + { sca_descriptor *rxdesc; int i; @@ -2702,7 +2974,7 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) if (hc->mempages) SRC_SET_OFF(hc->iobase); } -#endif +#endif /* BUGGY */ } /* * Check for Counter overflow @@ -2710,8 +2982,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) if (dsr & SCA_DSR_COF) { printf("sr%d: RX DMA Counter overflow, " "rxpkts %lu.\n", +#ifndef NETGRAPH sc->unit, sc->ifsppp.pp_if.if_ipackets); sc->ifsppp.pp_if.if_ierrors++; +#else /* NETGRAPH */ + sc->unit, sc->ipackets); + sc->ierrors[1]++; +#endif /* NETGRAPH */ } /* * Check for Buffer overflow @@ -2720,7 +2997,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) printf("sr%d: RX DMA Buffer overflow, " "rxpkts %lu, rxind %d, " "cda %x, eda %x, dsr %x.\n", +#ifndef NETGRAPH sc->unit, sc->ifsppp.pp_if.if_ipackets, +#else /* NETGRAPH */ + sc->unit, sc->ipackets, +#endif /* NETGRAPH */ sc->rxhind, SRC_GET16(hc->sca_base, dmac->cda), SRC_GET16(hc->sca_base, dmac->eda), @@ -2734,7 +3015,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) SRC_SET_ON(hc->iobase); sr_eat_packet(sc, 0); +#ifndef NETGRAPH sc->ifsppp.pp_if.if_ierrors++; +#else /* NETGRAPH */ + sc->ierrors[2]++; +#endif /* NETGRAPH */ SRC_PUT8(hc->sca_base, sca->msci[mch].cmd, @@ -2747,7 +3032,11 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) "rxpkts %lu, rxind %d, " "cda %x, eda %x, dsr %x. After\n", sc->unit, +#ifndef NETGRAPH + sc->ipackets, +#else /* NETGRAPH */ sc->ifsppp.pp_if.if_ipackets, +#endif /* NETGRAPH */ sc->rxhind, SRC_GET16(hc->sca_base, dmac->cda), SRC_GET16(hc->sca_base, dmac->eda), @@ -2770,8 +3059,13 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) */ printf("sr%d: RX End of xfer, rxpkts %lu.\n", sc->unit, +#ifndef NETGRAPH sc->ifsppp.pp_if.if_ipackets); sc->ifsppp.pp_if.if_ierrors++; +#else + sc->ipackets); + sc->ierrors[3]++; +#endif /* NETGRAPH */ } } isr1 >>= 4; /* process next half of ISR */ @@ -2785,12 +3079,16 @@ sr_dmac_intr(struct sr_hardc *hc, u_char isr1) for (mch = 0; mch < NCHAN; mch++) { if (dotxstart & 0x0C) { /* TX initiation enabled? */ sc = &hc->sc[mch]; +#ifndef NETGRAPH srstart(&sc->ifsppp.pp_if); +#else + srstart(sc); +#endif /* NETGRAPH */ } dotxstart >>= 4;/* shift for next channel */ } } - +#ifndef NETGRAPH /* * Perform timeout on an FR channel * @@ -2910,6 +3208,38 @@ sr_modemck(void *arg) splx(s); } +#else /* NETGRAPH */ +/* + * If a port is open/active, it's DCD state is checked + * and a loss of DCD is recognized (and eventually processed?). + */ +static void +sr_modemck(struct sr_softc *sc ) +{ + u_int s; + u_char got_st3; /* contents of ST3 */ + struct sr_hardc *hc = sc->hc; /* card's configuration */ + msci_channel *msci; /* regs specific to channel */ + + s = splimp(); + + + if (sc->running == 0) + return; + /* + * OK, now we can go looking at this channel's register contents... + */ + msci = &hc->sca->msci[sc->scachan]; + got_st3 = SRC_GET8(hc->sca_base, msci->st3); + + /* + * We want to see if the DCD signal is up (DCD is true if zero) + */ + sc->dcd = (got_st3 & SCA_ST3_DCD) == 0; + splx(s); +} + +#endif /* NETGRAPH */ static void sr_msci_intr(struct sr_hardc *hc, u_char isr0) { @@ -2922,6 +3252,301 @@ sr_timer_intr(struct sr_hardc *hc, u_char isr2) printf("src%d: SRINTR: TIMER\n", hc->cunit); } +#ifdef NETGRAPH +/***************************************** + * Device timeout/watchdog routine. + * called once per second. + * checks to see that if activity was expected, that it hapenned. + * At present we only look to see if expected output was completed. + */ +static void +ngsr_watchdog_frame(void * arg) +{ + struct sr_softc * sc = arg; + int s; + int speed; + + if(sc->running == 0) + return; /* if we are not running let timeouts die */ + /* + * calculate the apparent throughputs + * XXX a real hack + */ + s = splimp(); + speed = sc->inbytes - sc->lastinbytes; + sc->lastinbytes = sc->inbytes; + if ( sc->inrate < speed ) + sc->inrate = speed; + speed = sc->outbytes - sc->lastoutbytes; + sc->lastoutbytes = sc->outbytes; + if ( sc->outrate < speed ) + sc->outrate = speed; + sc->inlast++; + splx(s); + + if ((sc->inlast > QUITE_A_WHILE) + && (sc->out_deficit > LOTS_OF_PACKETS)) { + log(LOG_ERR, "sr%d: No response from remote end\n", sc->unit); + s = splimp(); + sr_down(sc); + sr_up(sc); + sc->inlast = sc->out_deficit = 0; + splx(s); + } else if ( sc->xmit_busy ) { /* no TX -> no TX timeouts */ + if (sc->out_dog == 0) { + log(LOG_ERR, "sr%d: Transmit failure.. no clock?\n", + sc->unit); + srwatchdog(sc); +#if 0 + s = splimp(); + sr_down(sc); + sr_up(sc); + splx(s); +#endif + sc->inlast = sc->out_deficit = 0; + } else { + sc->out_dog--; + } + } + sr_modemck(sc); /* update the DCD status */ + sc->handle = timeout(ngsr_watchdog_frame, sc, hz); +} + +/*********************************************************************** + * This section contains the methods for the Netgraph interface + ***********************************************************************/ +/* + * It is not possible or allowable to create a node of this type. + * If the hardware exists, it will already have created it. + */ +static int +ngsr_constructor(node_p *nodep) +{ + return (EINVAL); +} + +/* + * give our ok for a hook to be added... + * If we are not running this should kick the device into life. + * We allow hooks called "control" and dlci[1-1023] + * The hook's private info points to our stash of info about that + * channel. + */ +static int +ngsr_newhook(node_p node, hook_p hook, const char *name) +{ + struct sr_softc * sc = node->private; + + /* + * check if it's our friend the debug hook + */ + if (strcmp(name, NG_SR_HOOK_DEBUG) == 0) { + hook->private = NULL; /* paranoid */ + sc->debug_hook = hook; + return (0); + } + + /* + * Check for raw mode hook. + */ + if (strcmp(name, NG_SR_HOOK_RAW) != 0) { + return (EINVAL); + } + hook->private = sc; + sc->hook = hook; + sc->datahooks++; + sr_up(sc); + return (0); +} + +/* + * incoming messages. + * Just respond to the generic TEXT_STATUS message + */ +static int +ngsr_rcvmsg(node_p node, + struct ng_mesg *msg, const char *retaddr, struct ng_mesg **resp) +{ + struct sr_softc * sc; + int error = 0; + + sc = node->private; + switch (msg->header.typecookie) { + case NG_SR_COOKIE: + error = EINVAL; + break; + case NGM_GENERIC_COOKIE: + switch(msg->header.cmd) { + case NGM_TEXT_STATUS: { + char *arg; + int pos = 0; + int resplen = sizeof(struct ng_mesg) + 512; + MALLOC(*resp, struct ng_mesg *, resplen, + M_NETGRAPH, M_NOWAIT); + if (*resp == NULL) { + error = ENOMEM; + break; + } + bzero(*resp, resplen); + arg = (*resp)->data; + + /* + * Put in the throughput information. + */ + pos = sprintf(arg, "%ld bytes in, %ld bytes out\n" + "highest rate seen: %ld B/S in, %ld B/S out\n", + sc->inbytes, sc->outbytes, + sc->inrate, sc->outrate); + pos += sprintf(arg + pos, + "%ld output errors\n", + sc->oerrors); + pos += sprintf(arg + pos, + "ierrors = %ld, %ld, %ld, %ld, %ld, %ld\n", + sc->ierrors[0], + sc->ierrors[1], + sc->ierrors[2], + sc->ierrors[3], + sc->ierrors[4], + sc->ierrors[5]); + + (*resp)->header.version = NG_VERSION; + (*resp)->header.arglen = strlen(arg) + 1; + (*resp)->header.token = msg->header.token; + (*resp)->header.typecookie = NG_SR_COOKIE; + (*resp)->header.cmd = msg->header.cmd; + strncpy((*resp)->header.cmdstr, "status", + NG_CMDSTRLEN); + } + break; + default: + error = EINVAL; + break; + } + break; + default: + error = EINVAL; + break; + } + free(msg, M_NETGRAPH); + return (error); +} + +/* + * get data from another node and transmit it to the correct channel + */ +static int +ngsr_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) +{ + int s; + int error = 0; + struct sr_softc * sc = hook->node->private; + struct ifqueue *xmitq_p; + + /* + * data doesn't come in from just anywhere (e.g control hook) + */ + if ( hook->private == NULL) { + error = ENETDOWN; + goto bad; + } + + /* + * Now queue the data for when it can be sent + */ + if (meta && meta->priority > 0) { + xmitq_p = (&sc->xmitq_hipri); + } else { + xmitq_p = (&sc->xmitq); + } + s = splimp(); + if (IF_QFULL(xmitq_p)) { + IF_DROP(xmitq_p); + splx(s); + error = ENOBUFS; + goto bad; + } + IF_ENQUEUE(xmitq_p, m); + splx(s); + srstart(sc); + return (0); + +bad: + /* + * It was an error case. + * check if we need to free the mbuf, and then return the error + */ + NG_FREE_DATA(m, meta); + return (error); +} + +/* + * do local shutdown processing.. + * this node will refuse to go away, unless the hardware says to.. + * don't unref the node, or remove our name. just clear our links up. + */ +static int +ngsr_rmnode(node_p node) +{ + struct sr_softc * sc = node->private; + + sr_down(sc); + ng_cutlinks(node); + node->flags &= ~NG_INVALID; /* bounce back to life */ + return (0); +} + +/* already linked */ +static int +ngsr_connect(hook_p hook) +{ + /* be really amiable and just say "YUP that's OK by me! " */ + return (0); +} + +/* + * notify on hook disconnection (destruction) + * + * Invalidate the private data associated with this dlci. + * For this type, removal of the last link resets tries to destroy the node. + * As the device still exists, the shutdown method will not actually + * destroy the node, but reset the device and leave it 'fresh' :) + * + * The node removal code will remove all references except that owned by the + * driver. + */ +static int +ngsr_disconnect(hook_p hook) +{ + struct sr_softc * sc = hook->node->private; + int s; + /* + * If it's the data hook, then free resources etc. + */ + if (hook->private) { + s = splimp(); + sc->datahooks--; + if (sc->datahooks == 0) + sr_down(sc); + splx(s); + } else { + sc->debug_hook = NULL; + } + return (0); +} + +/* + * called during bootup + * or LKM loading to put this type into the list of known modules + */ +static void +ngsr_init(void *ignored) +{ + if (ng_newtype(&typestruct)) + printf("ngsr install failed\n"); + ngsr_done_init = 1; +} +#endif /* NETGRAPH */ + /* ********************************* END ************************************ */ -- cgit v1.1