1*13058Ssam /* if_hy.c 4.5 83/06/12 */ 211195Ssam 311195Ssam #include "hy.h" 411195Ssam #if NHY > 0 511195Ssam 611195Ssam /* 711195Ssam * Network Systems Copropration Hyperchanel interface 811195Ssam * 9*13058Ssam * UNTESTED WITH 4.2 1011195Ssam */ 1111195Ssam #include "../machine/pte.h" 1211195Ssam 1311195Ssam #include "../h/param.h" 1411195Ssam #include "../h/systm.h" 1511195Ssam #include "../h/mbuf.h" 1611195Ssam #include "../h/buf.h" 1711195Ssam #include "../h/protosw.h" 1811195Ssam #include "../h/socket.h" 1911195Ssam #include "../h/vmmac.h" 2011195Ssam #include "../h/errno.h" 2111207Ssam #include "../h/time.h" 2211207Ssam #include "../h/kernel.h" 2311207Ssam #include "../h/ioctl.h" 2411195Ssam #include "../net/if.h" 2511207Ssam #include "../net/netisr.h" 2611195Ssam #include "../net/route.h" 2711195Ssam #include "../netinet/in.h" 2811195Ssam #include "../netinet/in_systm.h" 2911195Ssam #include "../netinet/ip.h" 3011195Ssam #include "../netinet/ip_var.h" 3111195Ssam 3211207Ssam #include "../vax/cpu.h" 3311207Ssam #include "../vax/mtpr.h" 3411207Ssam #include "../vaxuba/ubareg.h" 3511207Ssam #include "../vaxuba/ubavar.h" 3611195Ssam #include "../vaxif/if_hy.h" 3711198Ssam #include "../vaxif/if_hyreg.h" 3811195Ssam #include "../vaxif/if_uba.h" 3911195Ssam 4011195Ssam #define HYROUTE 4111195Ssam #define HYELOG 4211195Ssam #define HYMTU 576 4311195Ssam 44*13058Ssam int hyprobe(), hyattach(), hyinit(), hyioctl(); 45*13058Ssam int hyoutput(), hyreset(), hywatch(); 4611195Ssam struct uba_device *hyinfo[NHY]; 4711195Ssam u_short hystd[] = { 0772410, 0 }; 4811195Ssam struct uba_driver hydriver = 4911195Ssam { hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo }; 5011195Ssam 5111195Ssam /* 5211195Ssam * Hyperchannel software status per interface. 5311195Ssam * 5411195Ssam * Each interface is referenced by a network interface structure, 5511195Ssam * hy_if, which the routing code uses to locate the interface. 5611195Ssam * This structure contains the output queue for the interface, its address, ... 5711195Ssam * We also have, for each interface, a UBA interface structure, which 5811195Ssam * contains information about the UNIBUS resources held by the interface: 5911195Ssam * map registers, buffered data paths, etc. Information is cached in this 6011195Ssam * structure for use by the if_uba.c routines in running the interface 6111195Ssam * efficiently. 6211195Ssam */ 6311195Ssam struct hy_softc { 6411195Ssam struct ifnet hy_if; /* network-visible interface */ 6511195Ssam struct ifuba hy_ifuba; /* UNIBUS resources */ 6611207Ssam short hy_flags; /* flags */ 6711207Ssam short hy_state; /* driver state */ 6811195Ssam int hy_ilen; /* mp length on input */ 6911195Ssam int hy_olen; /* packet length on output */ 7011195Ssam int hy_lastwcr; /* last command's word count */ 7111195Ssam short hy_savedstate; /* saved for reissue after status */ 7211195Ssam short hy_savedcmd; /* saved command for reissue */ 7311195Ssam int hy_savedcount; /* saved byte count for reissue */ 7411195Ssam int hy_savedaddr; /* saved unibus address for reissue */ 7511195Ssam int hy_ntime; /* number of timeouts since last cmd */ 7611195Ssam int hy_retry; /* retry counter */ 7711207Ssam struct hy_stat hy_stat; /* statistics */ 7811207Ssam struct hy_status hy_status; /* status */ 7911195Ssam } hy_softc[NHY]; 8011195Ssam 8111195Ssam #ifdef HYELOG 8211207Ssam #define HYE_MAX 0x18 8311207Ssam u_long hy_elog[(HYE_MAX+1)*4]; 8411195Ssam #endif 8511195Ssam 8611195Ssam #ifdef DEBUG 8711195Ssam #define printL lprintf 8811195Ssam #define printD if (hy_debug_flag) lprintf 8911195Ssam int hy_debug_flag = 0; 9011195Ssam /* 9111195Ssam * hy_nodebug bit 0x01 set hy_debug_flag on hycancel 9211195Ssam * hy_nodebug bit 0x02 set hy_debug_flag on command reissue 9311195Ssam * hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt 9411195Ssam * hy_nodebug bit 0x08 set hy_debug_flag on hyouput 9511195Ssam * hy_nodebug bit 0x10 set hy_debug_flag on hyouput with associated data 9611195Ssam */ 9711195Ssam int hy_nodebug = 0x0; 9811195Ssam #else 9911195Ssam #define printD hyvoid 10011195Ssam #endif 10111195Ssam 10211195Ssam /* 10311207Ssam * Requests for service (in order by descending priority). 10411195Ssam */ 10511195Ssam #define RQ_ENDOP 001 /* end the last adapter function */ 10611195Ssam #define RQ_REISSUE 002 /* reissue previous cmd after status */ 10711195Ssam #define RQ_STATUS 004 /* get the status of the adapter */ 10811195Ssam #define RQ_STATISTICS 010 /* get the statistics of the adapter */ 10911195Ssam #define RQ_MARKDOWN 020 /* mark this adapter port down */ 11011195Ssam #define RQ_MARKUP 040 /* mark this interface up */ 11111195Ssam 11211195Ssam #define RQ_XASSOC 0100 /* associated data to transmit */ 11311195Ssam 11411195Ssam /* 11511207Ssam * Driver states. 11611195Ssam */ 11711195Ssam #define STARTUP 0 /* initial state (before fully there) */ 11811195Ssam #define IDLE 1 /* idle state */ 11911195Ssam #define STATSENT 2 /* status cmd sent to adapter */ 12011195Ssam #define ENDOPSENT 3 /* end operation cmd sent */ 12111195Ssam #define RECVSENT 4 /* input message cmd sent */ 12211195Ssam #define RECVDATASENT 5 /* input data cmd sent */ 12311195Ssam #define XMITSENT 6 /* transmit message cmd sent */ 12411195Ssam #define XMITDATASENT 7 /* transmit data cmd sent */ 12511195Ssam #define WAITING 8 /* waiting for messages */ 12611195Ssam #define CLEARSENT 9 /* clear wait for message cmd sent */ 12711195Ssam #define MARKPORT 10 /* mark this host's adapter port down issued */ 12811195Ssam #define RSTATSENT 11 /* read statistics cmd sent to adapter */ 12911195Ssam 13011195Ssam #ifdef DEBUG 13111195Ssam char *hy_state_names[] = { 13211195Ssam "Startup", 13311195Ssam "Idle", 13411195Ssam "Status Sent", 13511195Ssam "End op Sent", 13611195Ssam "Recieve Message Proper Sent", 13711195Ssam "Recieve Data Sent", 13811195Ssam "Transmit Message Proper Sent", 13911195Ssam "Transmit Data Sent", 14011195Ssam "Wait for Message Sent", 14111195Ssam "Clear Wait for Message Sent", 14211195Ssam "Mark Port Down Sent", 14311195Ssam "Read Statistics Sent" 14411195Ssam }; 14511195Ssam #endif 14611195Ssam 14711195Ssam #define SCANINTERVAL 10 /* seconds */ 14811195Ssam #define MAXINTERVAL 20 /* seconds (max action) */ 14911195Ssam 15011195Ssam /* 15111195Ssam * Cause a device interrupt. This code uses a buffer starting at 15211195Ssam * location zero on the unibus (which is already mapped by the 15311195Ssam * autoconfigure code in the kernel). 15411195Ssam */ 15511195Ssam hyprobe(reg) 15611195Ssam caddr_t reg; 15711195Ssam { 15811195Ssam register int br, cvec; /* r11, r10 value-result */ 15911195Ssam register struct hydevice *addr = (struct hydevice *) reg; 16011195Ssam 16111195Ssam #ifdef lint 16211195Ssam br = 0; cvec = br; br = cvec; 16311195Ssam hyint(0); 16411195Ssam #endif 16511195Ssam /* 16611195Ssam * request adapter status to a buffer starting at unibus location 0 16711195Ssam */ 16811195Ssam addr->hyd_bar = 0; 16911195Ssam addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1); 17011195Ssam addr->hyd_dbuf = HYF_STATUS; 17111195Ssam #ifdef PI13 17211195Ssam addr->hyd_csr |= S_GO | S_IE | S_IATTN; 17311195Ssam #else 17411195Ssam addr->hyd_csr |= S_GO | S_IE; 17511195Ssam #endif 17611195Ssam DELAY(10000); 17711195Ssam #ifdef PI13 17811195Ssam addr->hyd_csr |= S_CLRINT; /* clear any stacked interrupts */ 17911195Ssam #endif 18011195Ssam addr->hyd_csr &= ~(S_IE | S_CLRINT); /* disable further interrupts */ 18111195Ssam return(1); 18211207Ssam } 18311195Ssam 18411195Ssam /* 18511195Ssam * Interface exists: make available by filling in network interface 18611195Ssam * record. System will initialize the interface when it is ready 18711195Ssam * to accept packets. 18811195Ssam */ 18911195Ssam hyattach(ui) 19011195Ssam struct uba_device *ui; 19111195Ssam { 19211195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 19311195Ssam register struct ifnet *ifp = &is->hy_if; 19411195Ssam 19511195Ssam ifp->if_unit = ui->ui_unit; 19611195Ssam ifp->if_name = "hy"; 19711195Ssam ifp->if_mtu = HYMTU; 19811195Ssam ifp->if_net = ui->ui_flags; 19911195Ssam is->hy_state = STARTUP; /* don't allow state transitions yet */ 20011195Ssam ifp->if_init = hyinit; 201*13058Ssam ifp->if_ioctl = hyioctl; 20211195Ssam ifp->if_output = hyoutput; 20311207Ssam ifp->if_reset = hyreset; 20411195Ssam ifp->if_watchdog = hywatch; 20511195Ssam ifp->if_timer = SCANINTERVAL; 20611195Ssam is->hy_ifuba.ifu_flags = UBA_CANTWAIT; 20711207Ssam #ifdef notdef 20811195Ssam is->hy_ifuba.ifu_flags |= UBA_NEEDBDP; 20911195Ssam #endif 21011195Ssam if_attach(ifp); 21111207Ssam } 21211195Ssam 21311195Ssam /* 21411195Ssam * Reset of interface after UNIBUS reset. 21511195Ssam * If interface is on specified uba, reset its state. 21611195Ssam */ 21711195Ssam hyreset(unit, uban) 21811195Ssam int unit, uban; 21911195Ssam { 22011195Ssam register struct uba_device *ui = hyinfo[unit]; 22111195Ssam 22211207Ssam if (unit >= NHY || ui == 0 || ui->ui_alive == 0 || 22311207Ssam ui->ui_ubanum != uban) 22411195Ssam return; 22511195Ssam printf(" hy%d", unit); 22611195Ssam hyinit(unit); 22711207Ssam } 22811195Ssam 22911195Ssam /* 23011195Ssam * Initialization of interface; clear recorded pending 23111195Ssam * operations, and reinitialize UNIBUS usage. 23211195Ssam */ 23311195Ssam hyinit(unit) 23411195Ssam int unit; 23511195Ssam { 23611195Ssam register struct hy_softc *is = &hy_softc[unit]; 23711195Ssam register struct uba_device *ui = hyinfo[unit]; 23811195Ssam int s; 23911195Ssam 24011195Ssam if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum, 24111195Ssam sizeof (struct hy_hdr), (int)btoc(HYMTU)) == 0) { 24211195Ssam #ifdef DEBUG 24311207Ssam if (hy_nodebug & 4) 24411207Ssam hy_debug_flag = 1; 24511195Ssam #endif 24611195Ssam printf("hy%d: can't initialize\n", unit); 24711195Ssam is->hy_if.if_flags &= ~IFF_UP; 24811195Ssam return; 24911195Ssam } 25011195Ssam /* 25111207Ssam * Issue wait for message and start the state machine 25211195Ssam */ 25311195Ssam s = splimp(); 25411195Ssam is->hy_state = IDLE; 25511195Ssam is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP; 25611195Ssam is->hy_retry = 0; 25711195Ssam hyact(ui); 25811195Ssam splx(s); 25911207Ssam } 26011195Ssam 26111195Ssam /* 26211207Ssam * Issue a command to the adapter 26311195Ssam */ 26411195Ssam hystart(ui, cmd, count, ubaddr) 26511195Ssam struct uba_device *ui; 26611207Ssam int cmd, count, ubaddr; 26711195Ssam { 26811195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 26911195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 27011195Ssam 27111195Ssam #ifdef DEBUG 27211207Ssam printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n", 27311207Ssam ui->ui_unit, cmd, count, ubaddr); 27411195Ssam printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 27511207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 27611207Ssam addr->hyd_wcr); 27711195Ssam #endif 27811207Ssam if (((is->hy_flags & RQ_REISSUE) == 0) && 27911207Ssam (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) { 28011195Ssam is->hy_savedstate = is->hy_state; 28111195Ssam is->hy_savedcmd = cmd; 28211195Ssam is->hy_savedcount = count; 28311195Ssam is->hy_savedaddr = ubaddr; 28411195Ssam } 28511195Ssam addr->hyd_bar = ubaddr & 0xffff; 28611207Ssam addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1); 28711195Ssam addr->hyd_dbuf = cmd; 28811195Ssam #ifdef PI13 28911195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN; 29011195Ssam #else 29111195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE; 29211195Ssam #endif 29311195Ssam #ifdef DEBUG 29411195Ssam printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 29511207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 29611207Ssam addr->hyd_wcr); 29711195Ssam #endif 29811195Ssam #ifdef HYLOG 29911195Ssam { 30011195Ssam struct { 30111207Ssam u_char hcmd; 30211207Ssam u_char hstate; 30311207Ssam short hcount; 30411195Ssam } hcl; 30511195Ssam 30611195Ssam hcl.hcmd = cmd; 30711195Ssam hcl.hstate = is->hy_state; 30811195Ssam hcl.hcount = count; 30911195Ssam hylog(HYL_CMD, sizeof(hcl), (char *)&hcl); 31011195Ssam } 31111195Ssam #endif 31211195Ssam is->hy_ntime = 0; 31311207Ssam } 31411195Ssam 31511195Ssam int hyint_active = 0; /* set during hy interrupt */ 31611195Ssam /* 31711207Ssam * Hyperchannel interface interrupt. 31811195Ssam * 31911195Ssam * An interrupt can occur for many reasons. Examine the status of 32011195Ssam * the hyperchannel status bits to determine what to do next. 32111195Ssam * 32211195Ssam * If input error just drop packet. 32311195Ssam * Otherwise purge input buffered data path and examine 32411195Ssam * packet to determine type. Othewise decapsulate 32511195Ssam * packet based on type and pass to type specific higher-level 32611195Ssam * input routine. 32711195Ssam */ 32811195Ssam hyint(unit) 32911195Ssam int unit; 33011195Ssam { 33111195Ssam register struct hy_softc *is = &hy_softc[unit]; 33211195Ssam register struct uba_device *ui = hyinfo[unit]; 33311207Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 33411195Ssam 33511207Ssam if (hyint_active) 33611195Ssam panic("RECURSIVE HYPERCHANNEL INTERRUPT"); 33711195Ssam hyint_active++; 33811195Ssam #ifdef DEBUG 33911195Ssam printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 34011195Ssam unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 34111195Ssam #endif 34211195Ssam #ifdef HYLOG 34311195Ssam logit: 34411195Ssam { 34511195Ssam struct { 34611207Ssam u_char hstate; 34711207Ssam u_char hflags; 34811207Ssam short hcsr; 34911207Ssam short hwcr; 35011195Ssam } hil; 35111195Ssam hil.hstate = is->hy_state; 35211195Ssam hil.hflags = is->hy_flags; 35311195Ssam hil.hcsr = addr->hyd_csr; 35411195Ssam hil.hwcr = addr->hyd_wcr; 35511195Ssam hylog(HYL_INT, sizeof(hil), (char *)&hil); 35611195Ssam } 35711195Ssam #endif 35811207Ssam if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) { 35911195Ssam /* 36011207Ssam * Error bit set, some sort of error in the interface. 36111195Ssam * 36211207Ssam * The adapter sets attn on command completion so that's not 36311207Ssam * a real error even though the interface considers it one. 36411195Ssam */ 36511195Ssam #ifdef DEBUG 36611207Ssam if (hy_nodebug & 4) 36711207Ssam hy_debug_flag = 1; 36811195Ssam #endif 36911207Ssam printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n", 37011207Ssam addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 37111207Ssam addr->hyd_wcr); 37211207Ssam if (addr->hyd_csr & S_NEX) { 37311195Ssam printf("hy%d: NEX - Non Existant Memory\n", unit); 37411195Ssam #ifdef PI13 37511195Ssam addr->hyd_csr |= S_NEX; /* as per PI13 manual */ 37611195Ssam #else 37711195Ssam addr->hyd_csr &= ~S_NEX; 37811195Ssam #endif 37911195Ssam hycancel(ui); 38011195Ssam #ifdef PI13 38111207Ssam } else if (addr->hyd_csr & S_POWEROFF) { 38211207Ssam printf("hy%d: Power Off bit set, trying to reset\n", 38311207Ssam unit); 38411195Ssam addr->hyd_csr |= S_POWEROFF; 38511195Ssam DELAY(100); 38611207Ssam if (addr->hyd_csr & S_POWEROFF) { 38711195Ssam if_down(&is->hy_if); 38811195Ssam is->hy_state = STARTUP; 38911207Ssam printf( 39011207Ssam "hy%d: Power Off Error, network shutdown\n", 39111207Ssam unit); 39211195Ssam } 39311195Ssam #endif 39411195Ssam } else { 39511195Ssam printf("hy%d: BAR overflow\n", unit); 39611195Ssam hycancel(ui); 39711195Ssam } 39811207Ssam } else if (HYS_NORMAL(addr)) { 39911195Ssam /* 40011207Ssam * Normal interrupt, bump state machine unless in state 40111195Ssam * waiting and no data present (assumed to be word count 40211207Ssam * zero interrupt or other hardware botch). 40311195Ssam */ 40411207Ssam if (is->hy_state != WAITING || HYS_RECVDATA(addr)) 40511195Ssam hyact(ui); 40611207Ssam } else if (HYS_ABNORMAL(addr)) { 40711195Ssam /* 40811207Ssam * Abnormal termination. 40911195Ssam * bump error counts, retry the last function 41011195Ssam * 'MAXRETRY' times before kicking the bucket. 41111195Ssam * 41211207Ssam * Don't reissue the cmd if in certain states, abnormal 41311207Ssam * on a reissued cmd or max retry exceeded. 41411195Ssam */ 41511195Ssam #ifdef HYLOG 41611195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 41711195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 41811195Ssam goto logit; 41911195Ssam } 42011195Ssam #endif 42111195Ssam #ifdef DEBUG 42211207Ssam if (hy_nodebug & 4) 42311207Ssam hy_debug_flag = 1; 42411195Ssam printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n", 42511195Ssam unit, hy_state_names[is->hy_state], is->hy_state); 42611207Ssam printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n", 42711207Ssam is->hy_flags, is->hy_ilen, is->hy_olen, 42811207Ssam is->hy_lastwcr, is->hy_retry); 42911207Ssam printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n", 43011207Ssam is->hy_savedstate, is->hy_savedcount, 43111207Ssam is->hy_savedaddr, is->hy_savedcmd); 43211195Ssam #endif 43311195Ssam #ifdef PI13 43411195Ssam addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */ 43511195Ssam #endif 43611207Ssam if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT) 43711195Ssam is->hy_if.if_oerrors++; 43811207Ssam if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT) 43911195Ssam is->hy_if.if_ierrors++; 44011195Ssam if (is->hy_state == XMITDATASENT || 44111195Ssam is->hy_state == RECVSENT || 44211195Ssam is->hy_state == RECVDATASENT || 44311207Ssam (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY) 44411195Ssam hycancel(ui); 44511207Ssam else { 44611195Ssam #ifdef DEBUG 44711207Ssam if (hy_nodebug & 2) 44811207Ssam hy_debug_flag = 1; 44911195Ssam #endif 45011195Ssam is->hy_retry++; 45111195Ssam is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE; 45211195Ssam is->hy_state = IDLE; 45311195Ssam hyact(ui); 45411195Ssam } 45511195Ssam } else { 45611195Ssam /* 45711195Ssam * Interrupt is neither normal, abnormal, or interface error. 45811195Ssam * Ignore it. It's either stacked or a word count 0. 45911195Ssam */ 46011195Ssam #ifdef HYLOG 46111195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 46211195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 46311195Ssam goto logit; 46411195Ssam } 46511195Ssam #endif 46611195Ssam #ifdef DEBUG 46711195Ssam printD("hy%d: possible stacked interrupt ignored\n", unit); 46811195Ssam #endif 46911195Ssam } 47011195Ssam #ifdef DEBUG 47111195Ssam printD("hy%d: hyint exit\n\n", unit); 47211195Ssam #endif 47311195Ssam hyint_active = 0; 47411195Ssam 47511207Ssam } 47611195Ssam 47711195Ssam /* 47811195Ssam * Encapsulate a packet of type family for the local net. 47911195Ssam * Use trailer local net encapsulation if enough data in first 48011195Ssam * packet leaves a multiple of 512 bytes of data in remainder. 48111195Ssam */ 48211195Ssam hyoutput(ifp, m0, dst) 48311195Ssam struct ifnet *ifp; 48411195Ssam struct mbuf *m0; 48511195Ssam struct sockaddr *dst; 48611195Ssam { 48711195Ssam register struct hym_hdr *hym; 48811195Ssam register struct mbuf *m; 48911195Ssam #ifdef HYROUTE 49011195Ssam register struct hyroute *r = &hy_route[ifp->if_unit]; 49111195Ssam #endif 49211195Ssam short dtype; /* packet type */ 49311195Ssam int dhost; /* destination adapter address */ 49411195Ssam int dlen; 49511195Ssam int mplen = 0; /* message proper length */ 49611195Ssam short loopback = 0; /* hardware loopback requested */ 49711195Ssam int error = 0; 49811195Ssam int s; 49911195Ssam 50011195Ssam #ifdef DEBUG 50111207Ssam if (hy_nodebug & 8) 50211207Ssam hy_debug_flag = 1; 50311195Ssam #endif 50411195Ssam dlen = 0; 50511195Ssam for (m = m0; m; m = m->m_next) 50611195Ssam dlen += m->m_len; 50711195Ssam m = m0; 50811195Ssam switch(dst->sa_family) { 50911195Ssam 51011195Ssam #ifdef INET 51111195Ssam case AF_INET: { 51211195Ssam register struct ip *ip = mtod(m, struct ip *); 51311195Ssam register struct sockaddr_in *sin = (struct sockaddr_in *)dst; 51411195Ssam register long hostaddr = in_lnaof(sin->sin_addr); 51511195Ssam 51611195Ssam dhost = hostaddr & 0xffff; 51711195Ssam dtype = HYLINK_IP; 51811195Ssam #ifdef DEBUG 51911207Ssam printD("hy%d: output to host %x, dhost %x\n", 52011207Ssam ifp->if_unit, sin->sin_addr.s_addr, dhost); 52111195Ssam #endif 52211195Ssam /* 52311207Ssam * Debugging loopback support: 52411195Ssam * upper byte of 24 bit host number interpreted as follows 52511195Ssam * 0x00 --> no loopback 52611195Ssam * 0x01 --> hardware loop through remote adapter 52711195Ssam * other --> software loop through remote ip layer 52811195Ssam */ 52911195Ssam if (hostaddr & 0xff0000) { 53011195Ssam struct in_addr temp; 53111195Ssam 53211195Ssam temp = ip->ip_dst; 53311195Ssam ip->ip_dst = ip->ip_src; 53411195Ssam ip->ip_src = temp; 53511195Ssam if ((hostaddr & 0xff0000) == 0x10000) 53611195Ssam loopback = H_LOOPBK; 53711195Ssam } 53811195Ssam /* 53911195Ssam * If entire packet won't fit in message proper, just 54011195Ssam * send hyperchannel hardware header and ip header in 54111195Ssam * message proper. If that won't fit either, just send 54211195Ssam * the maximum message proper. 54311195Ssam * 54411195Ssam * This insures that the associated data is at least a 54511195Ssam * TCP/UDP header in length and thus prevents potential 54611195Ssam * problems with very short word counts. 54711195Ssam */ 54811195Ssam if (dlen > MPSIZE - sizeof (struct hy_hdr)) { 54911195Ssam mplen = sizeof(struct hy_hdr) + (ip->ip_hl << 2); 55011195Ssam if (mplen > MPSIZE) 55111195Ssam mplen = MPSIZE; 55211195Ssam } 55311195Ssam break; 55411195Ssam } 55511195Ssam #endif 55611195Ssam 55711195Ssam default: 55811207Ssam printf("hy%d: can't handle af%d\n", ifp->if_unit, 55911207Ssam dst->sa_family); 56011195Ssam #ifdef DEBUG 56111207Ssam if (hy_nodebug & 4) 56211207Ssam hy_debug_flag = 1; 56311195Ssam #endif 56411195Ssam error = EAFNOSUPPORT; 56511195Ssam goto drop; 56611195Ssam } 56711195Ssam 56811195Ssam /* 56911207Ssam * Add the software and hardware hyperchannel headers. 57011195Ssam * If there's not enough space in the first mbuf, allocate another. 57111195Ssam * If that should fail, drop this sucker. 57211195Ssam * No extra space for headers is allocated. 57311195Ssam */ 57411195Ssam if (m->m_off > MMAXOFF || 57511195Ssam MMINOFF + sizeof(struct hym_hdr) > m->m_off) { 57611207Ssam m = m_get(M_DONTWAIT, MT_HEADER); 57711195Ssam if (m == 0) { 57811195Ssam m = m0; 57911195Ssam error = ENOBUFS; 58011195Ssam goto drop; 58111195Ssam } 58211195Ssam m->m_next = m0; 58311195Ssam m->m_off = MMINOFF; 58411195Ssam m->m_len = sizeof(struct hym_hdr); 58511195Ssam } else { 58611195Ssam m->m_off -= sizeof(struct hym_hdr); 58711195Ssam m->m_len += sizeof(struct hym_hdr); 58811195Ssam } 58911195Ssam hym = mtod(m, struct hym_hdr *); 59011195Ssam hym->hym_mplen = mplen; 59111195Ssam hym->hym_hdr.hyh_type = dtype; 59211195Ssam hym->hym_hdr.hyh_off = 0; 59312772Ssam hym->hym_hdr.hyh_from = htons((u_short)ifp->if_host[0]); 59411195Ssam hym->hym_hdr.hyh_param = loopback; 59511195Ssam #ifdef HYROUTE 59611207Ssam if (r->hyr_lasttime.tv_sec != 0) { 59711195Ssam register struct hy_hash *rh; 59811195Ssam register int i; 59911195Ssam 60011195Ssam i = HYRHASH(dhost); 60111195Ssam rh = &r->hyr_hash[i]; 60211195Ssam i = 0; 60311195Ssam while (rh->hyr_key != dhost) { 60411195Ssam rh++; i++; 60511195Ssam if (rh > &r->hyr_hash[HYRSIZE]) 60611195Ssam rh = &r->hyr_hash[0]; 60711195Ssam if (rh->hyr_flags == 0 || i > HYRSIZE) 60811195Ssam goto notfound; 60911195Ssam } 61011195Ssam if (rh->hyr_flags & HYR_GATE) { 61111195Ssam loopback = 0; /* no hardware loopback on gateways */ 61211195Ssam i = rh->hyr_nextgate; 61311195Ssam if (i >= rh->hyr_egate) 61411195Ssam rh->hyr_nextgate = rh->hyr_pgate; 61511195Ssam else 61611195Ssam rh->hyr_nextgate++; 61711195Ssam rh = &r->hyr_hash[r->hyr_gateway[i]]; 61811195Ssam if ((rh->hyr_flags & HYR_DIR) == 0) 61911195Ssam goto notfound; 62011195Ssam } 62111195Ssam hym->hym_hdr.hyh_ctl = rh->hyr_ctl; 62211195Ssam hym->hym_hdr.hyh_access = rh->hyr_access; 62311195Ssam hym->hym_hdr.hyh_to = rh->hyr_dst; 62411195Ssam } else { 62511195Ssam hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS; 62611195Ssam hym->hym_hdr.hyh_access = 0; 62712772Ssam hym->hym_hdr.hyh_to = htons((u_short)dhost); 62811195Ssam } 62911195Ssam #else 63011195Ssam hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS; 63111195Ssam hym->hym_hdr.hyh_access = 0; 63211195Ssam hym->hym_hdr.hyh_to = htons(dhost); 63311195Ssam #endif 63411195Ssam 63511195Ssam if (hym->hym_mplen) { 63611195Ssam hym->hym_hdr.hyh_ctl |= H_ASSOC; 63711195Ssam #ifdef DEBUG 63811207Ssam if (hy_nodebug & 16) 63911207Ssam hy_debug_flag = 1; 64011195Ssam #endif 64111207Ssam } else 64211207Ssam hym->hym_hdr.hyh_ctl &= ~H_ASSOC; 64311195Ssam #ifdef DEBUG 64411207Ssam printD("hy%d: output mplen=%x ctl=%x access=%x to=%x", 64511195Ssam ifp->if_unit, hym->hym_mplen, hym->hym_hdr.hyh_ctl, 64611207Ssam hym->hym_hdr.hyh_access, hym->hym_hdr.hyh_to); 64711207Ssam printD(" (adapter %x) from=%x param=%x type=%x off=%x\n", 64811195Ssam hym->hym_hdr.hyh_to_adapter, 64911195Ssam hym->hym_hdr.hyh_from, hym->hym_hdr.hyh_param, 65011195Ssam hym->hym_hdr.hyh_type, hym->hym_hdr.hyh_off); 65111195Ssam #endif 65211195Ssam s = splimp(); 65311195Ssam if (IF_QFULL(&ifp->if_snd)) { 65411195Ssam IF_DROP(&ifp->if_snd); 65511195Ssam error = ENOBUFS; 65611195Ssam splx(s); 65711195Ssam goto drop; 65811195Ssam } 65911195Ssam IF_ENQUEUE(&ifp->if_snd, m); 66011195Ssam if (hy_softc[ifp->if_unit].hy_state == WAITING) 66111195Ssam hyact(hyinfo[ifp->if_unit]); 66211195Ssam splx(s); 66311207Ssam return (0); 66411195Ssam notfound: 66511207Ssam error = ENETUNREACH; /* XXX */ 66611195Ssam drop: 66711195Ssam m_freem(m); 66811207Ssam return (error); 66911207Ssam } 67011195Ssam 67111195Ssam hyact(ui) 67211195Ssam register struct uba_device *ui; 67311195Ssam { 67411195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 67511195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 67611195Ssam 67711195Ssam actloop: 67811195Ssam #ifdef DEBUG 67911207Ssam printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, 68011207Ssam hy_state_names[is->hy_state]); 68111195Ssam #endif 68211195Ssam switch (is->hy_state) { 68311195Ssam 68411195Ssam case STARTUP: 68511195Ssam goto endintr; 68611195Ssam 68711195Ssam case IDLE: { 68811195Ssam register rq = is->hy_flags; 68911195Ssam 69011195Ssam if (rq & RQ_STATUS) { 69111195Ssam is->hy_flags &= ~RQ_STATUS; 69211195Ssam is->hy_state = STATSENT; 69311207Ssam hystart(ui, HYF_STATUS, sizeof (is->hy_status), 69411207Ssam is->hy_ifuba.ifu_r.ifrw_info); 69511195Ssam } else if (rq & RQ_ENDOP) { 69611195Ssam is->hy_flags &= ~RQ_ENDOP; 69711195Ssam is->hy_state = ENDOPSENT; 69811195Ssam hystart(ui, HYF_END_OP, 0, 0); 69911195Ssam } else if (rq & RQ_STATISTICS) { 70011195Ssam is->hy_flags &= ~RQ_STATISTICS; 70111195Ssam is->hy_state = RSTATSENT; 70211207Ssam hystart(ui, HYF_RSTATS, sizeof (is->hy_stat), 70311207Ssam is->hy_ifuba.ifu_r.ifrw_info); 70411207Ssam } else if (HYS_RECVDATA(addr)) { 70511195Ssam is->hy_state = RECVSENT; 70611195Ssam is->hy_retry = 0; 70711207Ssam hystart(ui, HYF_INPUTMSG, MPSIZE, 70811207Ssam is->hy_ifuba.ifu_r.ifrw_info); 70911195Ssam } else if (rq & RQ_REISSUE) { 71011195Ssam is->hy_flags &= ~RQ_REISSUE; 71111195Ssam is->hy_state = is->hy_savedstate; 71211195Ssam #ifdef DEBUG 71311207Ssam printD("hy%d: reissue cmd=0x%x count=%d", 71411207Ssam ui->ui_unit, is->hy_savedcmd, is->hy_savedcount); 71511207Ssam printD(" ubaddr=0x%x retry=%d\n", 71611207Ssam is->hy_savedaddr, is->hy_retry); 71711195Ssam #endif 71811207Ssam hystart(ui, is->hy_savedcmd, is->hy_savedcount, 71911207Ssam is->hy_savedaddr); 72011195Ssam } else { 72111195Ssam register struct mbuf *m; 72211195Ssam 72311195Ssam IF_DEQUEUE(&is->hy_if.if_snd, m); 72411207Ssam if (m != NULL) { 72511195Ssam register struct hym_hdr *hym; 72611195Ssam register int mplen; 72711195Ssam register int cmd; 72811195Ssam 72911195Ssam is->hy_state = XMITSENT; 73011195Ssam is->hy_retry = 0; 73111195Ssam hym = mtod(m, struct hym_hdr *); 73211195Ssam #ifdef HYLOG 73311207Ssam hylog(HYL_XMIT, sizeof(struct hym_hdr), 73411207Ssam (char *)hym); 73511195Ssam #endif 73611195Ssam mplen = hym->hym_mplen; 73711207Ssam if (hym->hym_hdr.hyh_to_adapter == 73811207Ssam hym->hym_hdr.hyh_from_adapter) 73911207Ssam cmd = HYF_XMITLOCMSG; 74011207Ssam else 74111207Ssam cmd = HYF_XMITMSG; 74211195Ssam #ifdef DEBUG 74311195Ssam printD("hy%d: hym_hdr = ", ui->ui_unit); 74411207Ssam if (hy_debug_flag) 74511207Ssam hyprintdata((char *)hym, 74611207Ssam sizeof (struct hym_hdr)); 74711195Ssam #endif 74811195Ssam /* 74911207Ssam * Strip off the software part of 75011195Ssam * the hyperchannel header 75111195Ssam */ 75211195Ssam m->m_off += sizeof(struct hym_data); 75311195Ssam m->m_len -= sizeof(struct hym_data); 75411195Ssam is->hy_olen = if_wubaput(&is->hy_ifuba, m); 75511195Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 75611207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 75711207Ssam is->hy_ifuba.ifu_w.ifrw_bdp); 75811195Ssam #ifdef DEBUG 75911207Ssam printD( 76011207Ssam "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 76111195Ssam ui->ui_unit, mplen, is->hy_olen); 76211207Ssam if (hy_debug_flag) 76311207Ssam hyprintdata( 76411207Ssam is->hy_ifuba.ifu_w.ifrw_addr, 76511207Ssam is->hy_olen); 76611195Ssam #endif 76711207Ssam hystart(ui, cmd, 76811207Ssam (mplen == 0) ? is->hy_olen : mplen, 76911207Ssam is->hy_ifuba.ifu_w.ifrw_info); 77011195Ssam if (mplen != 0) 77111195Ssam is->hy_flags |= RQ_XASSOC; 77211195Ssam } else if (rq & RQ_MARKDOWN) { 77311195Ssam is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN); 77411195Ssam is->hy_state = MARKPORT; 77511195Ssam is->hy_retry = 0; 77611195Ssam /* 77711207Ssam * Port number is taken from status data 77811195Ssam */ 77911207Ssam hystart(ui, 78012772Ssam (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)), 78112772Ssam 0, 0); 78211195Ssam } else if (rq & RQ_MARKUP) { 78311195Ssam register struct ifnet *ifp = &is->hy_if; 78411207Ssam register struct sockaddr_in *sin = 78511207Ssam (struct sockaddr_in *)&ifp->if_addr; 78611195Ssam 78711207Ssam is->hy_flags &= ~RQ_MARKUP; 78811195Ssam is->hy_retry = 0; 78911195Ssam /* 79011207Ssam * Fill in the Internet address 79111207Ssam * from the status buffer 79211195Ssam */ 79311207Ssam printf( 79411207Ssam "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n", 79511195Ssam ui->ui_unit, 79611195Ssam is->hy_stat.hyc_uaddr, 79711195Ssam PORTNUM(&is->hy_status), 79811207Ssam (is->hy_stat.hyc_atype[0]<<8) | 79911207Ssam is->hy_stat.hyc_atype[1], 80011195Ssam is->hy_stat.hyc_atype[2]); 80111195Ssam 80211207Ssam ifp->if_host[0] = 80311207Ssam (is->hy_stat.hyc_uaddr << 8) | 80411207Ssam PORTNUM(&is->hy_status); 80511195Ssam sin->sin_family = AF_INET; 80611207Ssam sin->sin_addr = 80711207Ssam if_makeaddr(ifp->if_net, ifp->if_host[0]); 80811195Ssam ifp->if_flags |= IFF_UP; 80911195Ssam if_rtinit(ifp, RTF_UP); 81011195Ssam #ifdef HYLOG 81111195Ssam hylog(HYL_UP, 0, (char *)0); 81211195Ssam #endif 81311195Ssam } else { 81411195Ssam is->hy_state = WAITING; 81511195Ssam is->hy_retry = 0; 81611195Ssam hystart(ui, HYF_WAITFORMSG, 0, 0); 81711195Ssam } 81811195Ssam } 81911207Ssam break; 82011195Ssam } 82111195Ssam 82211195Ssam case STATSENT: 82312772Ssam bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status, 82411207Ssam sizeof (struct hy_status)); 82511195Ssam #ifdef DEBUG 82611207Ssam printD("hy%d: status - %x %x %x %x %x %x %x %x\n", 82711207Ssam ui->ui_unit, is->hy_status.hys_gen_status, 82811207Ssam is->hy_status.hys_last_fcn, 82911207Ssam is->hy_status.hys_resp_trunk, 83011207Ssam is->hy_status.hys_status_trunk, 83111207Ssam is->hy_status.hys_recd_resp, 83211207Ssam is->hy_status.hys_error, 83311207Ssam is->hy_status.hys_caddr, 83411207Ssam is->hy_status.hys_pad); 83511195Ssam #endif 83611195Ssam is->hy_state = IDLE; 83711195Ssam #ifdef HYLOG 83811207Ssam hylog(HYL_STATUS, sizeof (struct hy_status), 83911207Ssam (char *)&is->hy_status); 84011195Ssam #endif 84111195Ssam #ifdef HYELOG 84211195Ssam { 84311195Ssam register int i; 84411195Ssam 84511195Ssam i = is->hy_status.hys_error; 84611195Ssam if (i < HYE_MAX) 84711195Ssam i = HYE_MAX; 84811195Ssam switch (is->hy_status.hys_last_fcn) { 84911195Ssam case HYF_XMITLOCMSG: 85011195Ssam i += HYE_MAX+1; /* fall through */ 85111195Ssam case HYF_XMITLSTDATA: 85211195Ssam i += HYE_MAX+1; /* fall through */ 85311195Ssam case HYF_XMITMSG: 85411195Ssam i += HYE_MAX+1; 85511195Ssam } 85611195Ssam hy_elog[i]++; 85711195Ssam } 85811195Ssam #endif 85911195Ssam break; 86011195Ssam 86111195Ssam case RSTATSENT: { 86211207Ssam register struct hy_stat *p = 86311207Ssam (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr; 86411195Ssam 86511195Ssam is->hy_stat.hyc_msgcnt = ntohl(p->hyc_msgcnt); 86611195Ssam is->hy_stat.hyc_dbcnt = ntohl(p->hyc_dbcnt); 86711195Ssam is->hy_stat.hyc_tbusy = ntohl(p->hyc_tbusy); 86811195Ssam is->hy_stat.hyc_hwret = ntohl(p->hyc_hwret); 86911195Ssam is->hy_stat.hyc_crcbad = ntohl(p->hyc_crcbad); 87011195Ssam is->hy_stat.hyc_mcret = ntohl(p->hyc_mcret); 87111195Ssam is->hy_stat.hyc_tdabort = ntohl(p->hyc_tdabort); 87211195Ssam is->hy_stat.hyc_atype[0] = p->hyc_atype[0]; 87311195Ssam is->hy_stat.hyc_atype[1] = p->hyc_atype[1]; 87411195Ssam is->hy_stat.hyc_atype[2] = p->hyc_atype[2]; 87511195Ssam is->hy_stat.hyc_uaddr = p->hyc_uaddr; 87611195Ssam #ifdef DEBUG 87711207Ssam printD( 87811207Ssam "hy%d: statistics - msgcnt %d dbcnt %d hwret %d tbusy %d crcbad %d\n", 87911195Ssam ui->ui_unit, 88011195Ssam is->hy_stat.hyc_msgcnt, is->hy_stat.hyc_dbcnt, 88111195Ssam is->hy_stat.hyc_tbusy, is->hy_stat.hyc_hwret, 88211195Ssam is->hy_stat.hyc_crcbad); 88311195Ssam printD(" mcret %d tdabort %d atype %x %x %x uaddr %x\n", 88411195Ssam is->hy_stat.hyc_mcret, is->hy_stat.hyc_tdabort, 88511195Ssam is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1], 88611195Ssam is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr); 88711195Ssam #endif 88811195Ssam is->hy_state = IDLE; 88911195Ssam #ifdef HYLOG 89011207Ssam hylog(HYL_STATISTICS, sizeof (struct hy_stat), 89111207Ssam (char *)&is->hy_stat); 89211195Ssam #endif 89311195Ssam break; 89411195Ssam } 89511195Ssam 89611195Ssam case CLEARSENT: 89711195Ssam is->hy_state = IDLE; 89811195Ssam break; 89911195Ssam 90011195Ssam case ENDOPSENT: 90111195Ssam is->hy_state = IDLE; 90211195Ssam break; 90311195Ssam 90411195Ssam case RECVSENT: { 90511207Ssam register struct hy_hdr *hyh; 90611207Ssam register unsigned len; 90711195Ssam 90811207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 90911207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 91011207Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 91111207Ssam hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 91211207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 91311207Ssam if (len > MPSIZE) { 91411207Ssam printf("hy%d: RECVD MP > MPSIZE (%d)\n", 91511207Ssam ui->ui_unit, len); 91611195Ssam #ifdef DEBUG 91711207Ssam hy_debug_flag = 1; 91811207Ssam printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 91911207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, 92011207Ssam addr->hyd_bar, addr->hyd_wcr); 92111195Ssam #endif 92211207Ssam } 92311195Ssam #ifdef DEBUG 92411207Ssam printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len); 92511207Ssam if (hy_debug_flag) 92611207Ssam hyprintdata((char *)hyh, len); 92711195Ssam #endif 92811207Ssam if (hyh->hyh_ctl & H_ASSOC) { 92911207Ssam is->hy_state = RECVDATASENT; 93011207Ssam is->hy_ilen = len; 93111207Ssam is->hy_retry = 0; 93211207Ssam hystart(ui, HYF_INPUTDATA, 93312772Ssam (int)(HYMTU-len+sizeof (struct hy_hdr)), 93412772Ssam (int)(is->hy_ifuba.ifu_r.ifrw_info + len)); 93511207Ssam } else { 93612772Ssam hyrecvdata(ui, hyh, (int)len); 93711207Ssam is->hy_state = IDLE; 93811195Ssam } 93911207Ssam break; 94011207Ssam } 94111195Ssam 94211195Ssam case RECVDATASENT: { 94311207Ssam register struct hy_hdr *hyh; 94411207Ssam register unsigned len; 94511195Ssam 94611207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 94711207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 94811207Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 94911207Ssam hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 95011207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 95111195Ssam #ifdef DEBUG 95211207Ssam printD("hy%d: recvd assoc data, len = %d, data = ", 95311207Ssam ui->ui_unit, len); 95411207Ssam if (hy_debug_flag) 95511207Ssam hyprintdata((char *)hyh + is->hy_ilen, len); 95611195Ssam #endif 95712772Ssam hyrecvdata(ui, hyh, (int)(len + is->hy_ilen)); 95811207Ssam is->hy_state = IDLE; 95911207Ssam break; 96011207Ssam } 96111195Ssam 96211195Ssam case XMITSENT: 96311207Ssam if (is->hy_flags & RQ_XASSOC) { 96411207Ssam register unsigned len; 96511195Ssam 96611207Ssam is->hy_flags &= ~RQ_XASSOC; 96711207Ssam is->hy_state = XMITDATASENT; 96811207Ssam is->hy_retry = 0; 96911207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 97011207Ssam if (len > is->hy_olen) { 97111207Ssam printf( 97211207Ssam "hy%d: xmit error - len > hy_olen [%d > %d]\n", 97311207Ssam ui->ui_unit, len, is->hy_olen); 97411195Ssam #ifdef DEBUG 97511207Ssam hy_debug_flag = 1; 97611195Ssam #endif 97711195Ssam } 97811207Ssam hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len, 97911207Ssam is->hy_ifuba.ifu_w.ifrw_info + len); 98011207Ssam break; 98111207Ssam } 98211207Ssam /* fall through to ... */ 98311195Ssam 98411195Ssam case XMITDATASENT: 98511207Ssam hyxmitdata(ui); 98611207Ssam is->hy_state = IDLE; 98711207Ssam break; 98811195Ssam 98911195Ssam case WAITING: /* wait for message complete or output requested */ 99011207Ssam if (HYS_RECVDATA(addr)) 99111195Ssam is->hy_state = IDLE; 99211195Ssam else { 99311195Ssam is->hy_state = CLEARSENT; 99411195Ssam is->hy_retry = 0; 99511195Ssam hystart(ui, HYF_CLRWFMSG, 0, 0); 99611195Ssam } 99711195Ssam break; 99811195Ssam 99911195Ssam case MARKPORT: 100011195Ssam is->hy_state = STARTUP; 100111195Ssam is->hy_if.if_flags &= ~IFF_UP; 100211195Ssam goto endintr; 100311195Ssam 100411195Ssam default: 100511207Ssam printf("hy%d: DRIVER BUG - INVALID STATE %d\n", 100611207Ssam ui->ui_unit, is->hy_state); 100711195Ssam panic("HYPERCHANNEL IN INVALID STATE"); 100811195Ssam /*NOTREACHED*/ 100911207Ssam } 101011195Ssam if (is->hy_state == IDLE) 101111195Ssam goto actloop; 101211195Ssam endintr: 101311195Ssam #ifdef DEBUG 101411207Ssam printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, 101511207Ssam hy_state_names[is->hy_state]); 101611195Ssam #endif 101711207Ssam } 101811195Ssam 101911195Ssam /* 102011195Ssam * Called from device interrupt when recieving data. 102111195Ssam * Examine packet to determine type. Decapsulate packet 102211195Ssam * based on type and pass to type specific higher-level 102311195Ssam * input routine. 102411195Ssam */ 102511195Ssam hyrecvdata(ui, hyh0, len) 102611195Ssam struct uba_device *ui; 102711195Ssam struct hy_hdr *hyh0; 102811195Ssam int len; 102911195Ssam { 103011195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 103111195Ssam register struct hy_hdr *hyh = hyh0; 103211195Ssam struct mbuf *m; 103311195Ssam register struct ifqueue *inq; 103411195Ssam 103511195Ssam is->hy_if.if_ipackets++; 103611195Ssam #ifdef DEBUG 103711207Ssam printD("hy%d: recieved packet, len = %d (actual %d)\n", 103811207Ssam ui->ui_unit, len, 103911207Ssam len - (hyh->hyh_off + sizeof (struct hy_hdr))); 104011195Ssam #endif 104111195Ssam #ifdef HYLOG 104211195Ssam { 104311195Ssam struct { 104411195Ssam short hlen; 104511195Ssam struct hy_hdr hhdr; 104611195Ssam } hh; 104711195Ssam hh.hlen = len; 104811195Ssam hh.hhdr = *hyh; 104911195Ssam hylog(HYL_RECV, sizeof(hh), (char *)&hh); 105011195Ssam } 105111195Ssam #endif 105211195Ssam if (len > HYMTU + MPSIZE || len == 0) 105311195Ssam return; /* sanity */ 105411195Ssam /* 105511195Ssam * Pull packet off interface. 105611195Ssam */ 105711195Ssam m = if_rubaget(&is->hy_ifuba, len, 0); 105811207Ssam if (m == NULL) 105911195Ssam return; 106011195Ssam switch (hyh->hyh_type) { 106111195Ssam 106211195Ssam #ifdef INET 106311195Ssam case HYLINK_IP: 106411195Ssam /* 106511207Ssam * Strip the variable portion of the hyperchannel header 106611207Ssam * (fixed portion stripped in if_rubaget). 106711195Ssam */ 106811195Ssam m->m_len -= hyh->hyh_off; 106911195Ssam m->m_off += hyh->hyh_off; 107011195Ssam schednetisr(NETISR_IP); 107111195Ssam inq = &ipintrq; 107211195Ssam break; 107311195Ssam #endif 107411195Ssam default: 107511195Ssam m_freem(m); 107611195Ssam return; 107711195Ssam } 107811195Ssam if (IF_QFULL(inq)) { 107911195Ssam IF_DROP(inq); 108011195Ssam m_freem(m); 108111195Ssam } else 108211195Ssam IF_ENQUEUE(inq, m); 108311207Ssam } 108411195Ssam 108511195Ssam /* 108611207Ssam * Transmit done, release resources, bump counters. 108711195Ssam */ 108811195Ssam hyxmitdata(ui) 108911195Ssam struct uba_device *ui; 109011195Ssam { 109111195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 109211195Ssam 109311195Ssam is->hy_if.if_opackets++; 109411207Ssam if (is->hy_ifuba.ifu_xtofree) { 109511195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 109611195Ssam is->hy_ifuba.ifu_xtofree = 0; 109711195Ssam } 109811207Ssam } 109911195Ssam 110011195Ssam hycancel(ui) 110111195Ssam register struct uba_device *ui; 110211195Ssam { 110311195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 110411195Ssam 110511207Ssam if (is->hy_ifuba.ifu_xtofree) { 110611195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 110711195Ssam is->hy_ifuba.ifu_xtofree = 0; 110811195Ssam } 110911195Ssam #ifdef DEBUG 111011207Ssam if (hy_nodebug & 1) 111111207Ssam hy_debug_flag = 1; 111211195Ssam #endif 111311195Ssam #ifdef DEBUG 111411195Ssam printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n", 111511195Ssam ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd, 111611195Ssam is->hy_savedcount, is->hy_savedaddr); 111711207Ssam printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n", 111811207Ssam is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr, 111911207Ssam is->hy_retry); 112011207Ssam printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n", 112111207Ssam is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, 112211207Ssam is->hy_savedcmd); 112311195Ssam #endif 112411195Ssam is->hy_state = IDLE; 112511195Ssam is->hy_flags |= (RQ_ENDOP | RQ_STATUS); 112611195Ssam hyact(ui); 112711207Ssam } 112811195Ssam 112911195Ssam #ifdef DEBUG 113011195Ssam hyprintdata(cp, len) 113111195Ssam register char *cp; 113211195Ssam register int len; 113311195Ssam { 113411195Ssam register int count = 16; 113511195Ssam register char *fmt; 113611195Ssam static char regfmt[] = "\n\t %x"; 113711195Ssam 113811195Ssam fmt = ®fmt[2]; 113911195Ssam while (--len >= 0) { 114011195Ssam printL(fmt, *cp++ & 0xff); 114111195Ssam fmt = ®fmt[2]; 114211195Ssam if (--count <= 0) { 114311195Ssam fmt = ®fmt[0]; 114411195Ssam count = 16; 114511195Ssam } 114611195Ssam } 114711195Ssam printL("\n"); 114811195Ssam } 114911195Ssam #endif 115011195Ssam 115111195Ssam hywatch(unit) 115211195Ssam int unit; 115311195Ssam { 115411195Ssam register struct hy_softc *is = &hy_softc[unit]; 115511195Ssam register struct uba_device *ui = hyinfo[unit]; 115611195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 115711195Ssam int s; 115811195Ssam 115911195Ssam s = splimp(); 116011195Ssam is->hy_if.if_timer = SCANINTERVAL; 116111207Ssam if (is->hy_ntime > 2 && is->hy_state != WAITING && 116211207Ssam is->hy_state != STARTUP && is->hy_state != IDLE) { 116311195Ssam printf("hy%d: watchdog timer expired\n", unit); 116411195Ssam hycancel(ui); 116511195Ssam } 116611195Ssam #ifdef PI13 116711195Ssam if ((addr->hyd_csr & S_POWEROFF) != 0) { 116811195Ssam addr->hyd_csr |= S_POWEROFF; 116911195Ssam DELAY(100); 117011195Ssam if ((addr->hyd_csr & S_POWEROFF) == 0) { 117111195Ssam printf("hy%d: adapter power restored\n", unit); 117211195Ssam is->hy_state = IDLE; 117311207Ssam is->hy_flags |= 117411207Ssam (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS); 117511195Ssam hyact(ui); 117611195Ssam } 117711195Ssam } 117811195Ssam #endif 117911195Ssam splx(s); 118011195Ssam } 118111195Ssam 118211195Ssam #ifdef HYLOG 118311195Ssam hylog(code, len, ptr) 118411195Ssam int code; 118511195Ssam int len; 118611195Ssam char *ptr; 118711195Ssam { 118811195Ssam register unsigned char *p; 118911195Ssam int s; 119011195Ssam 119111195Ssam s = splimp(); 119211195Ssam if (hy_log.hyl_self != &hy_log) { 119311195Ssam hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 119411195Ssam hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 119511195Ssam hy_log.hyl_self = &hy_log; 119611195Ssam hy_log.hyl_enable = HYL_DISABLED; 119711195Ssam hy_log.hyl_onerr = HYL_CATCH1; 119811195Ssam } 119911207Ssam if (hy_log.hyl_enable == HYL_DISABLED || 120011207Ssam hy_log.hyl_enable == HYL_CAUGHT1 || 120111207Ssam hy_log.hyl_enable == HYL_CAUGHTSTATUS || 120211207Ssam (hy_log.hyl_enable == HYL_CATCHSTATUS && code != HYL_STATUS)) 120311207Ssam goto out; 120411195Ssam p = hy_log.hyl_ptr; 120511195Ssam if (p + len + 2 >= hy_log.hyl_eptr) { 120612772Ssam bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p)); 120711195Ssam p = &hy_log.hyl_buf[0]; 120811195Ssam if (hy_log.hyl_enable == HYL_CATCH1) { 120911195Ssam hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHT1; 121011195Ssam goto out; 121111195Ssam } 121211195Ssam if (hy_log.hyl_enable == HYL_CATCHSTATUS) { 121311195Ssam hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHTSTATUS; 121411195Ssam goto out; 121511195Ssam } 121611195Ssam } 121711195Ssam *p++ = code; 121811195Ssam *p++ = len; 121912772Ssam bcopy(ptr, (caddr_t)p, (unsigned)len); 122011195Ssam hy_log.hyl_ptr = p + len; 122111195Ssam out: 122211195Ssam splx(s); 122311195Ssam } 122411195Ssam #endif 122511195Ssam 122612772Ssam /*ARGSUSED*/ 1227*13058Ssam hyioctl(ifp, cmd, data) 1228*13058Ssam register struct ifnet *ifp; 122911207Ssam int cmd; 123011207Ssam caddr_t data; 123111195Ssam { 123211207Ssam int s = splimp(), error = 0; 123311195Ssam 123411195Ssam switch(cmd) { 123511195Ssam 123611195Ssam case HYSETROUTE: 123711207Ssam if (!suser()) { 123811207Ssam error = EPERM; 123911207Ssam goto bad; 124011195Ssam } 1241*13058Ssam hy_route[ifp->if_unit] = *(struct hyroute *)ifr->ifr_data; 1242*13058Ssam hy_route[ifp->if_unit].hyr_lasttime = time; 124311195Ssam break; 124411195Ssam 124511195Ssam case HYGETROUTE: 1246*13058Ssam *(struct hyroute *)ifr->ifr_data = hy_route[ifp->if_unit]; 124711195Ssam break; 124811195Ssam 124911195Ssam default: 1250*13058Ssam error = EINVAL; 125111195Ssam break; 125211195Ssam } 125311207Ssam bad: 125411195Ssam splx(s); 125511207Ssam return (error); 125611195Ssam } 125711207Ssam #endif 1258