1*12772Ssam /* if_hy.c 4.4 83/05/27 */ 211195Ssam 311195Ssam #include "hy.h" 411195Ssam #if NHY > 0 511195Ssam 611195Ssam /* 711195Ssam * Network Systems Copropration Hyperchanel interface 811195Ssam * 911207Ssam * UNTESTED WITH 4.1C 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 2511195Ssam #include "../net/if.h" 2611207Ssam #include "../net/netisr.h" 2711195Ssam #include "../net/route.h" 2811195Ssam 2911195Ssam #include "../netinet/in.h" 3011195Ssam #include "../netinet/in_systm.h" 3111195Ssam #include "../netinet/ip.h" 3211195Ssam #include "../netinet/ip_var.h" 3311195Ssam 3411207Ssam #include "../vax/cpu.h" 3511207Ssam #include "../vax/mtpr.h" 3611207Ssam 3711207Ssam #include "../vaxuba/ubareg.h" 3811207Ssam #include "../vaxuba/ubavar.h" 3911207Ssam 4011195Ssam #include "../vaxif/if_hy.h" 4111198Ssam #include "../vaxif/if_hyreg.h" 4211195Ssam #include "../vaxif/if_uba.h" 4311195Ssam 4411195Ssam #define HYROUTE 4511195Ssam #define HYELOG 4611195Ssam #define HYMTU 576 4711195Ssam 4811195Ssam int hyprobe(), hyattach(), hyinit(), hyoutput(), hyreset(), hywatch(); 4911195Ssam struct uba_device *hyinfo[NHY]; 5011195Ssam u_short hystd[] = { 0772410, 0 }; 5111195Ssam struct uba_driver hydriver = 5211195Ssam { hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo }; 5311195Ssam 5411195Ssam /* 5511195Ssam * Hyperchannel software status per interface. 5611195Ssam * 5711195Ssam * Each interface is referenced by a network interface structure, 5811195Ssam * hy_if, which the routing code uses to locate the interface. 5911195Ssam * This structure contains the output queue for the interface, its address, ... 6011195Ssam * We also have, for each interface, a UBA interface structure, which 6111195Ssam * contains information about the UNIBUS resources held by the interface: 6211195Ssam * map registers, buffered data paths, etc. Information is cached in this 6311195Ssam * structure for use by the if_uba.c routines in running the interface 6411195Ssam * efficiently. 6511195Ssam */ 6611195Ssam struct hy_softc { 6711195Ssam struct ifnet hy_if; /* network-visible interface */ 6811195Ssam struct ifuba hy_ifuba; /* UNIBUS resources */ 6911207Ssam short hy_flags; /* flags */ 7011207Ssam short hy_state; /* driver state */ 7111195Ssam int hy_ilen; /* mp length on input */ 7211195Ssam int hy_olen; /* packet length on output */ 7311195Ssam int hy_lastwcr; /* last command's word count */ 7411195Ssam short hy_savedstate; /* saved for reissue after status */ 7511195Ssam short hy_savedcmd; /* saved command for reissue */ 7611195Ssam int hy_savedcount; /* saved byte count for reissue */ 7711195Ssam int hy_savedaddr; /* saved unibus address for reissue */ 7811195Ssam int hy_ntime; /* number of timeouts since last cmd */ 7911195Ssam int hy_retry; /* retry counter */ 8011207Ssam struct hy_stat hy_stat; /* statistics */ 8111207Ssam struct hy_status hy_status; /* status */ 8211195Ssam } hy_softc[NHY]; 8311195Ssam 8411195Ssam #ifdef HYELOG 8511207Ssam #define HYE_MAX 0x18 8611207Ssam u_long hy_elog[(HYE_MAX+1)*4]; 8711195Ssam #endif 8811195Ssam 8911195Ssam #ifdef DEBUG 9011195Ssam #define printL lprintf 9111195Ssam #define printD if (hy_debug_flag) lprintf 9211195Ssam int hy_debug_flag = 0; 9311195Ssam /* 9411195Ssam * hy_nodebug bit 0x01 set hy_debug_flag on hycancel 9511195Ssam * hy_nodebug bit 0x02 set hy_debug_flag on command reissue 9611195Ssam * hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt 9711195Ssam * hy_nodebug bit 0x08 set hy_debug_flag on hyouput 9811195Ssam * hy_nodebug bit 0x10 set hy_debug_flag on hyouput with associated data 9911195Ssam */ 10011195Ssam int hy_nodebug = 0x0; 10111195Ssam #else 10211195Ssam #define printD hyvoid 10311195Ssam #endif 10411195Ssam 10511195Ssam /* 10611207Ssam * Requests for service (in order by descending priority). 10711195Ssam */ 10811195Ssam #define RQ_ENDOP 001 /* end the last adapter function */ 10911195Ssam #define RQ_REISSUE 002 /* reissue previous cmd after status */ 11011195Ssam #define RQ_STATUS 004 /* get the status of the adapter */ 11111195Ssam #define RQ_STATISTICS 010 /* get the statistics of the adapter */ 11211195Ssam #define RQ_MARKDOWN 020 /* mark this adapter port down */ 11311195Ssam #define RQ_MARKUP 040 /* mark this interface up */ 11411195Ssam 11511195Ssam #define RQ_XASSOC 0100 /* associated data to transmit */ 11611195Ssam 11711195Ssam /* 11811207Ssam * Driver states. 11911195Ssam */ 12011195Ssam #define STARTUP 0 /* initial state (before fully there) */ 12111195Ssam #define IDLE 1 /* idle state */ 12211195Ssam #define STATSENT 2 /* status cmd sent to adapter */ 12311195Ssam #define ENDOPSENT 3 /* end operation cmd sent */ 12411195Ssam #define RECVSENT 4 /* input message cmd sent */ 12511195Ssam #define RECVDATASENT 5 /* input data cmd sent */ 12611195Ssam #define XMITSENT 6 /* transmit message cmd sent */ 12711195Ssam #define XMITDATASENT 7 /* transmit data cmd sent */ 12811195Ssam #define WAITING 8 /* waiting for messages */ 12911195Ssam #define CLEARSENT 9 /* clear wait for message cmd sent */ 13011195Ssam #define MARKPORT 10 /* mark this host's adapter port down issued */ 13111195Ssam #define RSTATSENT 11 /* read statistics cmd sent to adapter */ 13211195Ssam 13311195Ssam #ifdef DEBUG 13411195Ssam char *hy_state_names[] = { 13511195Ssam "Startup", 13611195Ssam "Idle", 13711195Ssam "Status Sent", 13811195Ssam "End op Sent", 13911195Ssam "Recieve Message Proper Sent", 14011195Ssam "Recieve Data Sent", 14111195Ssam "Transmit Message Proper Sent", 14211195Ssam "Transmit Data Sent", 14311195Ssam "Wait for Message Sent", 14411195Ssam "Clear Wait for Message Sent", 14511195Ssam "Mark Port Down Sent", 14611195Ssam "Read Statistics Sent" 14711195Ssam }; 14811195Ssam #endif 14911195Ssam 15011195Ssam #define SCANINTERVAL 10 /* seconds */ 15111195Ssam #define MAXINTERVAL 20 /* seconds (max action) */ 15211195Ssam 15311195Ssam /* 15411195Ssam * Cause a device interrupt. This code uses a buffer starting at 15511195Ssam * location zero on the unibus (which is already mapped by the 15611195Ssam * autoconfigure code in the kernel). 15711195Ssam */ 15811195Ssam hyprobe(reg) 15911195Ssam caddr_t reg; 16011195Ssam { 16111195Ssam register int br, cvec; /* r11, r10 value-result */ 16211195Ssam register struct hydevice *addr = (struct hydevice *) reg; 16311195Ssam 16411195Ssam #ifdef lint 16511195Ssam br = 0; cvec = br; br = cvec; 16611195Ssam hyint(0); 16711195Ssam #endif 16811195Ssam /* 16911195Ssam * request adapter status to a buffer starting at unibus location 0 17011195Ssam */ 17111195Ssam addr->hyd_bar = 0; 17211195Ssam addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1); 17311195Ssam addr->hyd_dbuf = HYF_STATUS; 17411195Ssam #ifdef PI13 17511195Ssam addr->hyd_csr |= S_GO | S_IE | S_IATTN; 17611195Ssam #else 17711195Ssam addr->hyd_csr |= S_GO | S_IE; 17811195Ssam #endif 17911195Ssam DELAY(10000); 18011195Ssam #ifdef PI13 18111195Ssam addr->hyd_csr |= S_CLRINT; /* clear any stacked interrupts */ 18211195Ssam #endif 18311195Ssam addr->hyd_csr &= ~(S_IE | S_CLRINT); /* disable further interrupts */ 18411195Ssam return(1); 18511207Ssam } 18611195Ssam 18711195Ssam /* 18811195Ssam * Interface exists: make available by filling in network interface 18911195Ssam * record. System will initialize the interface when it is ready 19011195Ssam * to accept packets. 19111195Ssam */ 19211195Ssam hyattach(ui) 19311195Ssam struct uba_device *ui; 19411195Ssam { 19511195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 19611195Ssam register struct ifnet *ifp = &is->hy_if; 19711195Ssam 19811195Ssam ifp->if_unit = ui->ui_unit; 19911195Ssam ifp->if_name = "hy"; 20011195Ssam ifp->if_mtu = HYMTU; 20111195Ssam ifp->if_net = ui->ui_flags; 20211195Ssam is->hy_state = STARTUP; /* don't allow state transitions yet */ 20311195Ssam ifp->if_init = hyinit; 20411195Ssam ifp->if_output = hyoutput; 20511207Ssam ifp->if_reset = hyreset; 20611195Ssam ifp->if_watchdog = hywatch; 20711195Ssam ifp->if_timer = SCANINTERVAL; 20811195Ssam is->hy_ifuba.ifu_flags = UBA_CANTWAIT; 20911207Ssam #ifdef notdef 21011195Ssam is->hy_ifuba.ifu_flags |= UBA_NEEDBDP; 21111195Ssam #endif 21211195Ssam if_attach(ifp); 21311207Ssam } 21411195Ssam 21511195Ssam /* 21611195Ssam * Reset of interface after UNIBUS reset. 21711195Ssam * If interface is on specified uba, reset its state. 21811195Ssam */ 21911195Ssam hyreset(unit, uban) 22011195Ssam int unit, uban; 22111195Ssam { 22211195Ssam register struct uba_device *ui = hyinfo[unit]; 22311195Ssam 22411207Ssam if (unit >= NHY || ui == 0 || ui->ui_alive == 0 || 22511207Ssam ui->ui_ubanum != uban) 22611195Ssam return; 22711195Ssam printf(" hy%d", unit); 22811195Ssam hyinit(unit); 22911207Ssam } 23011195Ssam 23111195Ssam /* 23211195Ssam * Initialization of interface; clear recorded pending 23311195Ssam * operations, and reinitialize UNIBUS usage. 23411195Ssam */ 23511195Ssam hyinit(unit) 23611195Ssam int unit; 23711195Ssam { 23811195Ssam register struct hy_softc *is = &hy_softc[unit]; 23911195Ssam register struct uba_device *ui = hyinfo[unit]; 24011195Ssam int s; 24111195Ssam 24211195Ssam if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum, 24311195Ssam sizeof (struct hy_hdr), (int)btoc(HYMTU)) == 0) { 24411195Ssam #ifdef DEBUG 24511207Ssam if (hy_nodebug & 4) 24611207Ssam hy_debug_flag = 1; 24711195Ssam #endif 24811195Ssam printf("hy%d: can't initialize\n", unit); 24911195Ssam is->hy_if.if_flags &= ~IFF_UP; 25011195Ssam return; 25111195Ssam } 25211195Ssam /* 25311207Ssam * Issue wait for message and start the state machine 25411195Ssam */ 25511195Ssam s = splimp(); 25611195Ssam is->hy_state = IDLE; 25711195Ssam is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP; 25811195Ssam is->hy_retry = 0; 25911195Ssam hyact(ui); 26011195Ssam splx(s); 26111207Ssam } 26211195Ssam 26311195Ssam /* 26411207Ssam * Issue a command to the adapter 26511195Ssam */ 26611195Ssam hystart(ui, cmd, count, ubaddr) 26711195Ssam struct uba_device *ui; 26811207Ssam int cmd, count, ubaddr; 26911195Ssam { 27011195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 27111195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 27211195Ssam 27311195Ssam #ifdef DEBUG 27411207Ssam printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n", 27511207Ssam ui->ui_unit, cmd, count, ubaddr); 27611195Ssam printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 27711207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 27811207Ssam addr->hyd_wcr); 27911195Ssam #endif 28011207Ssam if (((is->hy_flags & RQ_REISSUE) == 0) && 28111207Ssam (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) { 28211195Ssam is->hy_savedstate = is->hy_state; 28311195Ssam is->hy_savedcmd = cmd; 28411195Ssam is->hy_savedcount = count; 28511195Ssam is->hy_savedaddr = ubaddr; 28611195Ssam } 28711195Ssam addr->hyd_bar = ubaddr & 0xffff; 28811207Ssam addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1); 28911195Ssam addr->hyd_dbuf = cmd; 29011195Ssam #ifdef PI13 29111195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN; 29211195Ssam #else 29311195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE; 29411195Ssam #endif 29511195Ssam #ifdef DEBUG 29611195Ssam printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 29711207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 29811207Ssam addr->hyd_wcr); 29911195Ssam #endif 30011195Ssam #ifdef HYLOG 30111195Ssam { 30211195Ssam struct { 30311207Ssam u_char hcmd; 30411207Ssam u_char hstate; 30511207Ssam short hcount; 30611195Ssam } hcl; 30711195Ssam 30811195Ssam hcl.hcmd = cmd; 30911195Ssam hcl.hstate = is->hy_state; 31011195Ssam hcl.hcount = count; 31111195Ssam hylog(HYL_CMD, sizeof(hcl), (char *)&hcl); 31211195Ssam } 31311195Ssam #endif 31411195Ssam is->hy_ntime = 0; 31511207Ssam } 31611195Ssam 31711195Ssam int hyint_active = 0; /* set during hy interrupt */ 31811195Ssam /* 31911207Ssam * Hyperchannel interface interrupt. 32011195Ssam * 32111195Ssam * An interrupt can occur for many reasons. Examine the status of 32211195Ssam * the hyperchannel status bits to determine what to do next. 32311195Ssam * 32411195Ssam * If input error just drop packet. 32511195Ssam * Otherwise purge input buffered data path and examine 32611195Ssam * packet to determine type. Othewise decapsulate 32711195Ssam * packet based on type and pass to type specific higher-level 32811195Ssam * input routine. 32911195Ssam */ 33011195Ssam hyint(unit) 33111195Ssam int unit; 33211195Ssam { 33311195Ssam register struct hy_softc *is = &hy_softc[unit]; 33411195Ssam register struct uba_device *ui = hyinfo[unit]; 33511207Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 33611195Ssam 33711207Ssam if (hyint_active) 33811195Ssam panic("RECURSIVE HYPERCHANNEL INTERRUPT"); 33911195Ssam hyint_active++; 34011195Ssam #ifdef DEBUG 34111195Ssam printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 34211195Ssam unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 34311195Ssam #endif 34411195Ssam #ifdef HYLOG 34511195Ssam logit: 34611195Ssam { 34711195Ssam struct { 34811207Ssam u_char hstate; 34911207Ssam u_char hflags; 35011207Ssam short hcsr; 35111207Ssam short hwcr; 35211195Ssam } hil; 35311195Ssam hil.hstate = is->hy_state; 35411195Ssam hil.hflags = is->hy_flags; 35511195Ssam hil.hcsr = addr->hyd_csr; 35611195Ssam hil.hwcr = addr->hyd_wcr; 35711195Ssam hylog(HYL_INT, sizeof(hil), (char *)&hil); 35811195Ssam } 35911195Ssam #endif 36011207Ssam if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) { 36111195Ssam /* 36211207Ssam * Error bit set, some sort of error in the interface. 36311195Ssam * 36411207Ssam * The adapter sets attn on command completion so that's not 36511207Ssam * a real error even though the interface considers it one. 36611195Ssam */ 36711195Ssam #ifdef DEBUG 36811207Ssam if (hy_nodebug & 4) 36911207Ssam hy_debug_flag = 1; 37011195Ssam #endif 37111207Ssam printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n", 37211207Ssam addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 37311207Ssam addr->hyd_wcr); 37411207Ssam if (addr->hyd_csr & S_NEX) { 37511195Ssam printf("hy%d: NEX - Non Existant Memory\n", unit); 37611195Ssam #ifdef PI13 37711195Ssam addr->hyd_csr |= S_NEX; /* as per PI13 manual */ 37811195Ssam #else 37911195Ssam addr->hyd_csr &= ~S_NEX; 38011195Ssam #endif 38111195Ssam hycancel(ui); 38211195Ssam #ifdef PI13 38311207Ssam } else if (addr->hyd_csr & S_POWEROFF) { 38411207Ssam printf("hy%d: Power Off bit set, trying to reset\n", 38511207Ssam unit); 38611195Ssam addr->hyd_csr |= S_POWEROFF; 38711195Ssam DELAY(100); 38811207Ssam if (addr->hyd_csr & S_POWEROFF) { 38911195Ssam if_down(&is->hy_if); 39011195Ssam is->hy_state = STARTUP; 39111207Ssam printf( 39211207Ssam "hy%d: Power Off Error, network shutdown\n", 39311207Ssam unit); 39411195Ssam } 39511195Ssam #endif 39611195Ssam } else { 39711195Ssam printf("hy%d: BAR overflow\n", unit); 39811195Ssam hycancel(ui); 39911195Ssam } 40011207Ssam } else if (HYS_NORMAL(addr)) { 40111195Ssam /* 40211207Ssam * Normal interrupt, bump state machine unless in state 40311195Ssam * waiting and no data present (assumed to be word count 40411207Ssam * zero interrupt or other hardware botch). 40511195Ssam */ 40611207Ssam if (is->hy_state != WAITING || HYS_RECVDATA(addr)) 40711195Ssam hyact(ui); 40811207Ssam } else if (HYS_ABNORMAL(addr)) { 40911195Ssam /* 41011207Ssam * Abnormal termination. 41111195Ssam * bump error counts, retry the last function 41211195Ssam * 'MAXRETRY' times before kicking the bucket. 41311195Ssam * 41411207Ssam * Don't reissue the cmd if in certain states, abnormal 41511207Ssam * on a reissued cmd or max retry exceeded. 41611195Ssam */ 41711195Ssam #ifdef HYLOG 41811195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 41911195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 42011195Ssam goto logit; 42111195Ssam } 42211195Ssam #endif 42311195Ssam #ifdef DEBUG 42411207Ssam if (hy_nodebug & 4) 42511207Ssam hy_debug_flag = 1; 42611195Ssam printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n", 42711195Ssam unit, hy_state_names[is->hy_state], is->hy_state); 42811207Ssam printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n", 42911207Ssam is->hy_flags, is->hy_ilen, is->hy_olen, 43011207Ssam is->hy_lastwcr, is->hy_retry); 43111207Ssam printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n", 43211207Ssam is->hy_savedstate, is->hy_savedcount, 43311207Ssam is->hy_savedaddr, is->hy_savedcmd); 43411195Ssam #endif 43511195Ssam #ifdef PI13 43611195Ssam addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */ 43711195Ssam #endif 43811207Ssam if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT) 43911195Ssam is->hy_if.if_oerrors++; 44011207Ssam if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT) 44111195Ssam is->hy_if.if_ierrors++; 44211195Ssam if (is->hy_state == XMITDATASENT || 44311195Ssam is->hy_state == RECVSENT || 44411195Ssam is->hy_state == RECVDATASENT || 44511207Ssam (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY) 44611195Ssam hycancel(ui); 44711207Ssam else { 44811195Ssam #ifdef DEBUG 44911207Ssam if (hy_nodebug & 2) 45011207Ssam hy_debug_flag = 1; 45111195Ssam #endif 45211195Ssam is->hy_retry++; 45311195Ssam is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE; 45411195Ssam is->hy_state = IDLE; 45511195Ssam hyact(ui); 45611195Ssam } 45711195Ssam } else { 45811195Ssam /* 45911195Ssam * Interrupt is neither normal, abnormal, or interface error. 46011195Ssam * Ignore it. It's either stacked or a word count 0. 46111195Ssam */ 46211195Ssam #ifdef HYLOG 46311195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 46411195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 46511195Ssam goto logit; 46611195Ssam } 46711195Ssam #endif 46811195Ssam #ifdef DEBUG 46911195Ssam printD("hy%d: possible stacked interrupt ignored\n", unit); 47011195Ssam #endif 47111195Ssam } 47211195Ssam #ifdef DEBUG 47311195Ssam printD("hy%d: hyint exit\n\n", unit); 47411195Ssam #endif 47511195Ssam hyint_active = 0; 47611195Ssam 47711207Ssam } 47811195Ssam 47911195Ssam /* 48011195Ssam * Encapsulate a packet of type family for the local net. 48111195Ssam * Use trailer local net encapsulation if enough data in first 48211195Ssam * packet leaves a multiple of 512 bytes of data in remainder. 48311195Ssam */ 48411195Ssam hyoutput(ifp, m0, dst) 48511195Ssam struct ifnet *ifp; 48611195Ssam struct mbuf *m0; 48711195Ssam struct sockaddr *dst; 48811195Ssam { 48911195Ssam register struct hym_hdr *hym; 49011195Ssam register struct mbuf *m; 49111195Ssam #ifdef HYROUTE 49211195Ssam register struct hyroute *r = &hy_route[ifp->if_unit]; 49311195Ssam #endif 49411195Ssam short dtype; /* packet type */ 49511195Ssam int dhost; /* destination adapter address */ 49611195Ssam int dlen; 49711195Ssam int mplen = 0; /* message proper length */ 49811195Ssam short loopback = 0; /* hardware loopback requested */ 49911195Ssam int error = 0; 50011195Ssam int s; 50111195Ssam 50211195Ssam #ifdef DEBUG 50311207Ssam if (hy_nodebug & 8) 50411207Ssam hy_debug_flag = 1; 50511195Ssam #endif 50611195Ssam dlen = 0; 50711195Ssam for (m = m0; m; m = m->m_next) 50811195Ssam dlen += m->m_len; 50911195Ssam m = m0; 51011195Ssam switch(dst->sa_family) { 51111195Ssam 51211195Ssam #ifdef INET 51311195Ssam case AF_INET: { 51411195Ssam register struct ip *ip = mtod(m, struct ip *); 51511195Ssam register struct sockaddr_in *sin = (struct sockaddr_in *)dst; 51611195Ssam register long hostaddr = in_lnaof(sin->sin_addr); 51711195Ssam 51811195Ssam dhost = hostaddr & 0xffff; 51911195Ssam dtype = HYLINK_IP; 52011195Ssam #ifdef DEBUG 52111207Ssam printD("hy%d: output to host %x, dhost %x\n", 52211207Ssam ifp->if_unit, sin->sin_addr.s_addr, dhost); 52311195Ssam #endif 52411195Ssam /* 52511207Ssam * Debugging loopback support: 52611195Ssam * upper byte of 24 bit host number interpreted as follows 52711195Ssam * 0x00 --> no loopback 52811195Ssam * 0x01 --> hardware loop through remote adapter 52911195Ssam * other --> software loop through remote ip layer 53011195Ssam */ 53111195Ssam if (hostaddr & 0xff0000) { 53211195Ssam struct in_addr temp; 53311195Ssam 53411195Ssam temp = ip->ip_dst; 53511195Ssam ip->ip_dst = ip->ip_src; 53611195Ssam ip->ip_src = temp; 53711195Ssam if ((hostaddr & 0xff0000) == 0x10000) 53811195Ssam loopback = H_LOOPBK; 53911195Ssam } 54011195Ssam /* 54111195Ssam * If entire packet won't fit in message proper, just 54211195Ssam * send hyperchannel hardware header and ip header in 54311195Ssam * message proper. If that won't fit either, just send 54411195Ssam * the maximum message proper. 54511195Ssam * 54611195Ssam * This insures that the associated data is at least a 54711195Ssam * TCP/UDP header in length and thus prevents potential 54811195Ssam * problems with very short word counts. 54911195Ssam */ 55011195Ssam if (dlen > MPSIZE - sizeof (struct hy_hdr)) { 55111195Ssam mplen = sizeof(struct hy_hdr) + (ip->ip_hl << 2); 55211195Ssam if (mplen > MPSIZE) 55311195Ssam mplen = MPSIZE; 55411195Ssam } 55511195Ssam break; 55611195Ssam } 55711195Ssam #endif 55811195Ssam 55911195Ssam default: 56011207Ssam printf("hy%d: can't handle af%d\n", ifp->if_unit, 56111207Ssam dst->sa_family); 56211195Ssam #ifdef DEBUG 56311207Ssam if (hy_nodebug & 4) 56411207Ssam hy_debug_flag = 1; 56511195Ssam #endif 56611195Ssam error = EAFNOSUPPORT; 56711195Ssam goto drop; 56811195Ssam } 56911195Ssam 57011195Ssam /* 57111207Ssam * Add the software and hardware hyperchannel headers. 57211195Ssam * If there's not enough space in the first mbuf, allocate another. 57311195Ssam * If that should fail, drop this sucker. 57411195Ssam * No extra space for headers is allocated. 57511195Ssam */ 57611195Ssam if (m->m_off > MMAXOFF || 57711195Ssam MMINOFF + sizeof(struct hym_hdr) > m->m_off) { 57811207Ssam m = m_get(M_DONTWAIT, MT_HEADER); 57911195Ssam if (m == 0) { 58011195Ssam m = m0; 58111195Ssam error = ENOBUFS; 58211195Ssam goto drop; 58311195Ssam } 58411195Ssam m->m_next = m0; 58511195Ssam m->m_off = MMINOFF; 58611195Ssam m->m_len = sizeof(struct hym_hdr); 58711195Ssam } else { 58811195Ssam m->m_off -= sizeof(struct hym_hdr); 58911195Ssam m->m_len += sizeof(struct hym_hdr); 59011195Ssam } 59111195Ssam hym = mtod(m, struct hym_hdr *); 59211195Ssam hym->hym_mplen = mplen; 59311195Ssam hym->hym_hdr.hyh_type = dtype; 59411195Ssam hym->hym_hdr.hyh_off = 0; 595*12772Ssam hym->hym_hdr.hyh_from = htons((u_short)ifp->if_host[0]); 59611195Ssam hym->hym_hdr.hyh_param = loopback; 59711195Ssam #ifdef HYROUTE 59811207Ssam if (r->hyr_lasttime.tv_sec != 0) { 59911195Ssam register struct hy_hash *rh; 60011195Ssam register int i; 60111195Ssam 60211195Ssam i = HYRHASH(dhost); 60311195Ssam rh = &r->hyr_hash[i]; 60411195Ssam i = 0; 60511195Ssam while (rh->hyr_key != dhost) { 60611195Ssam rh++; i++; 60711195Ssam if (rh > &r->hyr_hash[HYRSIZE]) 60811195Ssam rh = &r->hyr_hash[0]; 60911195Ssam if (rh->hyr_flags == 0 || i > HYRSIZE) 61011195Ssam goto notfound; 61111195Ssam } 61211195Ssam if (rh->hyr_flags & HYR_GATE) { 61311195Ssam loopback = 0; /* no hardware loopback on gateways */ 61411195Ssam i = rh->hyr_nextgate; 61511195Ssam if (i >= rh->hyr_egate) 61611195Ssam rh->hyr_nextgate = rh->hyr_pgate; 61711195Ssam else 61811195Ssam rh->hyr_nextgate++; 61911195Ssam rh = &r->hyr_hash[r->hyr_gateway[i]]; 62011195Ssam if ((rh->hyr_flags & HYR_DIR) == 0) 62111195Ssam goto notfound; 62211195Ssam } 62311195Ssam hym->hym_hdr.hyh_ctl = rh->hyr_ctl; 62411195Ssam hym->hym_hdr.hyh_access = rh->hyr_access; 62511195Ssam hym->hym_hdr.hyh_to = rh->hyr_dst; 62611195Ssam } else { 62711195Ssam hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS; 62811195Ssam hym->hym_hdr.hyh_access = 0; 629*12772Ssam hym->hym_hdr.hyh_to = htons((u_short)dhost); 63011195Ssam } 63111195Ssam #else 63211195Ssam hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS; 63311195Ssam hym->hym_hdr.hyh_access = 0; 63411195Ssam hym->hym_hdr.hyh_to = htons(dhost); 63511195Ssam #endif 63611195Ssam 63711195Ssam if (hym->hym_mplen) { 63811195Ssam hym->hym_hdr.hyh_ctl |= H_ASSOC; 63911195Ssam #ifdef DEBUG 64011207Ssam if (hy_nodebug & 16) 64111207Ssam hy_debug_flag = 1; 64211195Ssam #endif 64311207Ssam } else 64411207Ssam hym->hym_hdr.hyh_ctl &= ~H_ASSOC; 64511195Ssam #ifdef DEBUG 64611207Ssam printD("hy%d: output mplen=%x ctl=%x access=%x to=%x", 64711195Ssam ifp->if_unit, hym->hym_mplen, hym->hym_hdr.hyh_ctl, 64811207Ssam hym->hym_hdr.hyh_access, hym->hym_hdr.hyh_to); 64911207Ssam printD(" (adapter %x) from=%x param=%x type=%x off=%x\n", 65011195Ssam hym->hym_hdr.hyh_to_adapter, 65111195Ssam hym->hym_hdr.hyh_from, hym->hym_hdr.hyh_param, 65211195Ssam hym->hym_hdr.hyh_type, hym->hym_hdr.hyh_off); 65311195Ssam #endif 65411195Ssam s = splimp(); 65511195Ssam if (IF_QFULL(&ifp->if_snd)) { 65611195Ssam IF_DROP(&ifp->if_snd); 65711195Ssam error = ENOBUFS; 65811195Ssam splx(s); 65911195Ssam goto drop; 66011195Ssam } 66111195Ssam IF_ENQUEUE(&ifp->if_snd, m); 66211195Ssam if (hy_softc[ifp->if_unit].hy_state == WAITING) 66311195Ssam hyact(hyinfo[ifp->if_unit]); 66411195Ssam splx(s); 66511207Ssam return (0); 66611195Ssam notfound: 66711207Ssam error = ENETUNREACH; /* XXX */ 66811195Ssam drop: 66911195Ssam m_freem(m); 67011207Ssam return (error); 67111207Ssam } 67211195Ssam 67311195Ssam hyact(ui) 67411195Ssam register struct uba_device *ui; 67511195Ssam { 67611195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 67711195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 67811195Ssam 67911195Ssam actloop: 68011195Ssam #ifdef DEBUG 68111207Ssam printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, 68211207Ssam hy_state_names[is->hy_state]); 68311195Ssam #endif 68411195Ssam switch (is->hy_state) { 68511195Ssam 68611195Ssam case STARTUP: 68711195Ssam goto endintr; 68811195Ssam 68911195Ssam case IDLE: { 69011195Ssam register rq = is->hy_flags; 69111195Ssam 69211195Ssam if (rq & RQ_STATUS) { 69311195Ssam is->hy_flags &= ~RQ_STATUS; 69411195Ssam is->hy_state = STATSENT; 69511207Ssam hystart(ui, HYF_STATUS, sizeof (is->hy_status), 69611207Ssam is->hy_ifuba.ifu_r.ifrw_info); 69711195Ssam } else if (rq & RQ_ENDOP) { 69811195Ssam is->hy_flags &= ~RQ_ENDOP; 69911195Ssam is->hy_state = ENDOPSENT; 70011195Ssam hystart(ui, HYF_END_OP, 0, 0); 70111195Ssam } else if (rq & RQ_STATISTICS) { 70211195Ssam is->hy_flags &= ~RQ_STATISTICS; 70311195Ssam is->hy_state = RSTATSENT; 70411207Ssam hystart(ui, HYF_RSTATS, sizeof (is->hy_stat), 70511207Ssam is->hy_ifuba.ifu_r.ifrw_info); 70611207Ssam } else if (HYS_RECVDATA(addr)) { 70711195Ssam is->hy_state = RECVSENT; 70811195Ssam is->hy_retry = 0; 70911207Ssam hystart(ui, HYF_INPUTMSG, MPSIZE, 71011207Ssam is->hy_ifuba.ifu_r.ifrw_info); 71111195Ssam } else if (rq & RQ_REISSUE) { 71211195Ssam is->hy_flags &= ~RQ_REISSUE; 71311195Ssam is->hy_state = is->hy_savedstate; 71411195Ssam #ifdef DEBUG 71511207Ssam printD("hy%d: reissue cmd=0x%x count=%d", 71611207Ssam ui->ui_unit, is->hy_savedcmd, is->hy_savedcount); 71711207Ssam printD(" ubaddr=0x%x retry=%d\n", 71811207Ssam is->hy_savedaddr, is->hy_retry); 71911195Ssam #endif 72011207Ssam hystart(ui, is->hy_savedcmd, is->hy_savedcount, 72111207Ssam is->hy_savedaddr); 72211195Ssam } else { 72311195Ssam register struct mbuf *m; 72411195Ssam 72511195Ssam IF_DEQUEUE(&is->hy_if.if_snd, m); 72611207Ssam if (m != NULL) { 72711195Ssam register struct hym_hdr *hym; 72811195Ssam register int mplen; 72911195Ssam register int cmd; 73011195Ssam 73111195Ssam is->hy_state = XMITSENT; 73211195Ssam is->hy_retry = 0; 73311195Ssam hym = mtod(m, struct hym_hdr *); 73411195Ssam #ifdef HYLOG 73511207Ssam hylog(HYL_XMIT, sizeof(struct hym_hdr), 73611207Ssam (char *)hym); 73711195Ssam #endif 73811195Ssam mplen = hym->hym_mplen; 73911207Ssam if (hym->hym_hdr.hyh_to_adapter == 74011207Ssam hym->hym_hdr.hyh_from_adapter) 74111207Ssam cmd = HYF_XMITLOCMSG; 74211207Ssam else 74311207Ssam cmd = HYF_XMITMSG; 74411195Ssam #ifdef DEBUG 74511195Ssam printD("hy%d: hym_hdr = ", ui->ui_unit); 74611207Ssam if (hy_debug_flag) 74711207Ssam hyprintdata((char *)hym, 74811207Ssam sizeof (struct hym_hdr)); 74911195Ssam #endif 75011195Ssam /* 75111207Ssam * Strip off the software part of 75211195Ssam * the hyperchannel header 75311195Ssam */ 75411195Ssam m->m_off += sizeof(struct hym_data); 75511195Ssam m->m_len -= sizeof(struct hym_data); 75611195Ssam is->hy_olen = if_wubaput(&is->hy_ifuba, m); 75711195Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 75811207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 75911207Ssam is->hy_ifuba.ifu_w.ifrw_bdp); 76011195Ssam #ifdef DEBUG 76111207Ssam printD( 76211207Ssam "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 76311195Ssam ui->ui_unit, mplen, is->hy_olen); 76411207Ssam if (hy_debug_flag) 76511207Ssam hyprintdata( 76611207Ssam is->hy_ifuba.ifu_w.ifrw_addr, 76711207Ssam is->hy_olen); 76811195Ssam #endif 76911207Ssam hystart(ui, cmd, 77011207Ssam (mplen == 0) ? is->hy_olen : mplen, 77111207Ssam is->hy_ifuba.ifu_w.ifrw_info); 77211195Ssam if (mplen != 0) 77311195Ssam is->hy_flags |= RQ_XASSOC; 77411195Ssam } else if (rq & RQ_MARKDOWN) { 77511195Ssam is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN); 77611195Ssam is->hy_state = MARKPORT; 77711195Ssam is->hy_retry = 0; 77811195Ssam /* 77911207Ssam * Port number is taken from status data 78011195Ssam */ 78111207Ssam hystart(ui, 782*12772Ssam (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)), 783*12772Ssam 0, 0); 78411195Ssam } else if (rq & RQ_MARKUP) { 78511195Ssam register struct ifnet *ifp = &is->hy_if; 78611207Ssam register struct sockaddr_in *sin = 78711207Ssam (struct sockaddr_in *)&ifp->if_addr; 78811195Ssam 78911207Ssam is->hy_flags &= ~RQ_MARKUP; 79011195Ssam is->hy_retry = 0; 79111195Ssam /* 79211207Ssam * Fill in the Internet address 79311207Ssam * from the status buffer 79411195Ssam */ 79511207Ssam printf( 79611207Ssam "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n", 79711195Ssam ui->ui_unit, 79811195Ssam is->hy_stat.hyc_uaddr, 79911195Ssam PORTNUM(&is->hy_status), 80011207Ssam (is->hy_stat.hyc_atype[0]<<8) | 80111207Ssam is->hy_stat.hyc_atype[1], 80211195Ssam is->hy_stat.hyc_atype[2]); 80311195Ssam 80411207Ssam ifp->if_host[0] = 80511207Ssam (is->hy_stat.hyc_uaddr << 8) | 80611207Ssam PORTNUM(&is->hy_status); 80711195Ssam sin->sin_family = AF_INET; 80811207Ssam sin->sin_addr = 80911207Ssam if_makeaddr(ifp->if_net, ifp->if_host[0]); 81011195Ssam ifp->if_flags |= IFF_UP; 81111195Ssam if_rtinit(ifp, RTF_UP); 81211195Ssam #ifdef HYLOG 81311195Ssam hylog(HYL_UP, 0, (char *)0); 81411195Ssam #endif 81511195Ssam } else { 81611195Ssam is->hy_state = WAITING; 81711195Ssam is->hy_retry = 0; 81811195Ssam hystart(ui, HYF_WAITFORMSG, 0, 0); 81911195Ssam } 82011195Ssam } 82111207Ssam break; 82211195Ssam } 82311195Ssam 82411195Ssam case STATSENT: 825*12772Ssam bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status, 82611207Ssam sizeof (struct hy_status)); 82711195Ssam #ifdef DEBUG 82811207Ssam printD("hy%d: status - %x %x %x %x %x %x %x %x\n", 82911207Ssam ui->ui_unit, is->hy_status.hys_gen_status, 83011207Ssam is->hy_status.hys_last_fcn, 83111207Ssam is->hy_status.hys_resp_trunk, 83211207Ssam is->hy_status.hys_status_trunk, 83311207Ssam is->hy_status.hys_recd_resp, 83411207Ssam is->hy_status.hys_error, 83511207Ssam is->hy_status.hys_caddr, 83611207Ssam is->hy_status.hys_pad); 83711195Ssam #endif 83811195Ssam is->hy_state = IDLE; 83911195Ssam #ifdef HYLOG 84011207Ssam hylog(HYL_STATUS, sizeof (struct hy_status), 84111207Ssam (char *)&is->hy_status); 84211195Ssam #endif 84311195Ssam #ifdef HYELOG 84411195Ssam { 84511195Ssam register int i; 84611195Ssam 84711195Ssam i = is->hy_status.hys_error; 84811195Ssam if (i < HYE_MAX) 84911195Ssam i = HYE_MAX; 85011195Ssam switch (is->hy_status.hys_last_fcn) { 85111195Ssam case HYF_XMITLOCMSG: 85211195Ssam i += HYE_MAX+1; /* fall through */ 85311195Ssam case HYF_XMITLSTDATA: 85411195Ssam i += HYE_MAX+1; /* fall through */ 85511195Ssam case HYF_XMITMSG: 85611195Ssam i += HYE_MAX+1; 85711195Ssam } 85811195Ssam hy_elog[i]++; 85911195Ssam } 86011195Ssam #endif 86111195Ssam break; 86211195Ssam 86311195Ssam case RSTATSENT: { 86411207Ssam register struct hy_stat *p = 86511207Ssam (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr; 86611195Ssam 86711195Ssam is->hy_stat.hyc_msgcnt = ntohl(p->hyc_msgcnt); 86811195Ssam is->hy_stat.hyc_dbcnt = ntohl(p->hyc_dbcnt); 86911195Ssam is->hy_stat.hyc_tbusy = ntohl(p->hyc_tbusy); 87011195Ssam is->hy_stat.hyc_hwret = ntohl(p->hyc_hwret); 87111195Ssam is->hy_stat.hyc_crcbad = ntohl(p->hyc_crcbad); 87211195Ssam is->hy_stat.hyc_mcret = ntohl(p->hyc_mcret); 87311195Ssam is->hy_stat.hyc_tdabort = ntohl(p->hyc_tdabort); 87411195Ssam is->hy_stat.hyc_atype[0] = p->hyc_atype[0]; 87511195Ssam is->hy_stat.hyc_atype[1] = p->hyc_atype[1]; 87611195Ssam is->hy_stat.hyc_atype[2] = p->hyc_atype[2]; 87711195Ssam is->hy_stat.hyc_uaddr = p->hyc_uaddr; 87811195Ssam #ifdef DEBUG 87911207Ssam printD( 88011207Ssam "hy%d: statistics - msgcnt %d dbcnt %d hwret %d tbusy %d crcbad %d\n", 88111195Ssam ui->ui_unit, 88211195Ssam is->hy_stat.hyc_msgcnt, is->hy_stat.hyc_dbcnt, 88311195Ssam is->hy_stat.hyc_tbusy, is->hy_stat.hyc_hwret, 88411195Ssam is->hy_stat.hyc_crcbad); 88511195Ssam printD(" mcret %d tdabort %d atype %x %x %x uaddr %x\n", 88611195Ssam is->hy_stat.hyc_mcret, is->hy_stat.hyc_tdabort, 88711195Ssam is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1], 88811195Ssam is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr); 88911195Ssam #endif 89011195Ssam is->hy_state = IDLE; 89111195Ssam #ifdef HYLOG 89211207Ssam hylog(HYL_STATISTICS, sizeof (struct hy_stat), 89311207Ssam (char *)&is->hy_stat); 89411195Ssam #endif 89511195Ssam break; 89611195Ssam } 89711195Ssam 89811195Ssam case CLEARSENT: 89911195Ssam is->hy_state = IDLE; 90011195Ssam break; 90111195Ssam 90211195Ssam case ENDOPSENT: 90311195Ssam is->hy_state = IDLE; 90411195Ssam break; 90511195Ssam 90611195Ssam case RECVSENT: { 90711207Ssam register struct hy_hdr *hyh; 90811207Ssam register unsigned len; 90911195Ssam 91011207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 91111207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 91211207Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 91311207Ssam hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 91411207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 91511207Ssam if (len > MPSIZE) { 91611207Ssam printf("hy%d: RECVD MP > MPSIZE (%d)\n", 91711207Ssam ui->ui_unit, len); 91811195Ssam #ifdef DEBUG 91911207Ssam hy_debug_flag = 1; 92011207Ssam printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 92111207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, 92211207Ssam addr->hyd_bar, addr->hyd_wcr); 92311195Ssam #endif 92411207Ssam } 92511195Ssam #ifdef DEBUG 92611207Ssam printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len); 92711207Ssam if (hy_debug_flag) 92811207Ssam hyprintdata((char *)hyh, len); 92911195Ssam #endif 93011207Ssam if (hyh->hyh_ctl & H_ASSOC) { 93111207Ssam is->hy_state = RECVDATASENT; 93211207Ssam is->hy_ilen = len; 93311207Ssam is->hy_retry = 0; 93411207Ssam hystart(ui, HYF_INPUTDATA, 935*12772Ssam (int)(HYMTU-len+sizeof (struct hy_hdr)), 936*12772Ssam (int)(is->hy_ifuba.ifu_r.ifrw_info + len)); 93711207Ssam } else { 938*12772Ssam hyrecvdata(ui, hyh, (int)len); 93911207Ssam is->hy_state = IDLE; 94011195Ssam } 94111207Ssam break; 94211207Ssam } 94311195Ssam 94411195Ssam case RECVDATASENT: { 94511207Ssam register struct hy_hdr *hyh; 94611207Ssam register unsigned len; 94711195Ssam 94811207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 94911207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 95011207Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 95111207Ssam hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 95211207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 95311195Ssam #ifdef DEBUG 95411207Ssam printD("hy%d: recvd assoc data, len = %d, data = ", 95511207Ssam ui->ui_unit, len); 95611207Ssam if (hy_debug_flag) 95711207Ssam hyprintdata((char *)hyh + is->hy_ilen, len); 95811195Ssam #endif 959*12772Ssam hyrecvdata(ui, hyh, (int)(len + is->hy_ilen)); 96011207Ssam is->hy_state = IDLE; 96111207Ssam break; 96211207Ssam } 96311195Ssam 96411195Ssam case XMITSENT: 96511207Ssam if (is->hy_flags & RQ_XASSOC) { 96611207Ssam register unsigned len; 96711195Ssam 96811207Ssam is->hy_flags &= ~RQ_XASSOC; 96911207Ssam is->hy_state = XMITDATASENT; 97011207Ssam is->hy_retry = 0; 97111207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 97211207Ssam if (len > is->hy_olen) { 97311207Ssam printf( 97411207Ssam "hy%d: xmit error - len > hy_olen [%d > %d]\n", 97511207Ssam ui->ui_unit, len, is->hy_olen); 97611195Ssam #ifdef DEBUG 97711207Ssam hy_debug_flag = 1; 97811195Ssam #endif 97911195Ssam } 98011207Ssam hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len, 98111207Ssam is->hy_ifuba.ifu_w.ifrw_info + len); 98211207Ssam break; 98311207Ssam } 98411207Ssam /* fall through to ... */ 98511195Ssam 98611195Ssam case XMITDATASENT: 98711207Ssam hyxmitdata(ui); 98811207Ssam is->hy_state = IDLE; 98911207Ssam break; 99011195Ssam 99111195Ssam case WAITING: /* wait for message complete or output requested */ 99211207Ssam if (HYS_RECVDATA(addr)) 99311195Ssam is->hy_state = IDLE; 99411195Ssam else { 99511195Ssam is->hy_state = CLEARSENT; 99611195Ssam is->hy_retry = 0; 99711195Ssam hystart(ui, HYF_CLRWFMSG, 0, 0); 99811195Ssam } 99911195Ssam break; 100011195Ssam 100111195Ssam case MARKPORT: 100211195Ssam is->hy_state = STARTUP; 100311195Ssam is->hy_if.if_flags &= ~IFF_UP; 100411195Ssam goto endintr; 100511195Ssam 100611195Ssam default: 100711207Ssam printf("hy%d: DRIVER BUG - INVALID STATE %d\n", 100811207Ssam ui->ui_unit, is->hy_state); 100911195Ssam panic("HYPERCHANNEL IN INVALID STATE"); 101011195Ssam /*NOTREACHED*/ 101111207Ssam } 101211195Ssam if (is->hy_state == IDLE) 101311195Ssam goto actloop; 101411195Ssam endintr: 101511195Ssam #ifdef DEBUG 101611207Ssam printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, 101711207Ssam hy_state_names[is->hy_state]); 101811195Ssam #endif 101911207Ssam } 102011195Ssam 102111195Ssam /* 102211195Ssam * Called from device interrupt when recieving data. 102311195Ssam * Examine packet to determine type. Decapsulate packet 102411195Ssam * based on type and pass to type specific higher-level 102511195Ssam * input routine. 102611195Ssam */ 102711195Ssam hyrecvdata(ui, hyh0, len) 102811195Ssam struct uba_device *ui; 102911195Ssam struct hy_hdr *hyh0; 103011195Ssam int len; 103111195Ssam { 103211195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 103311195Ssam register struct hy_hdr *hyh = hyh0; 103411195Ssam struct mbuf *m; 103511195Ssam register struct ifqueue *inq; 103611195Ssam 103711195Ssam is->hy_if.if_ipackets++; 103811195Ssam #ifdef DEBUG 103911207Ssam printD("hy%d: recieved packet, len = %d (actual %d)\n", 104011207Ssam ui->ui_unit, len, 104111207Ssam len - (hyh->hyh_off + sizeof (struct hy_hdr))); 104211195Ssam #endif 104311195Ssam #ifdef HYLOG 104411195Ssam { 104511195Ssam struct { 104611195Ssam short hlen; 104711195Ssam struct hy_hdr hhdr; 104811195Ssam } hh; 104911195Ssam hh.hlen = len; 105011195Ssam hh.hhdr = *hyh; 105111195Ssam hylog(HYL_RECV, sizeof(hh), (char *)&hh); 105211195Ssam } 105311195Ssam #endif 105411195Ssam if (len > HYMTU + MPSIZE || len == 0) 105511195Ssam return; /* sanity */ 105611195Ssam /* 105711195Ssam * Pull packet off interface. 105811195Ssam */ 105911195Ssam m = if_rubaget(&is->hy_ifuba, len, 0); 106011207Ssam if (m == NULL) 106111195Ssam return; 106211195Ssam switch (hyh->hyh_type) { 106311195Ssam 106411195Ssam #ifdef INET 106511195Ssam case HYLINK_IP: 106611195Ssam /* 106711207Ssam * Strip the variable portion of the hyperchannel header 106811207Ssam * (fixed portion stripped in if_rubaget). 106911195Ssam */ 107011195Ssam m->m_len -= hyh->hyh_off; 107111195Ssam m->m_off += hyh->hyh_off; 107211195Ssam schednetisr(NETISR_IP); 107311195Ssam inq = &ipintrq; 107411195Ssam break; 107511195Ssam #endif 107611195Ssam default: 107711195Ssam m_freem(m); 107811195Ssam return; 107911195Ssam } 108011195Ssam if (IF_QFULL(inq)) { 108111195Ssam IF_DROP(inq); 108211195Ssam m_freem(m); 108311195Ssam } else 108411195Ssam IF_ENQUEUE(inq, m); 108511207Ssam } 108611195Ssam 108711195Ssam /* 108811207Ssam * Transmit done, release resources, bump counters. 108911195Ssam */ 109011195Ssam hyxmitdata(ui) 109111195Ssam struct uba_device *ui; 109211195Ssam { 109311195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 109411195Ssam 109511195Ssam is->hy_if.if_opackets++; 109611207Ssam if (is->hy_ifuba.ifu_xtofree) { 109711195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 109811195Ssam is->hy_ifuba.ifu_xtofree = 0; 109911195Ssam } 110011207Ssam } 110111195Ssam 110211195Ssam hycancel(ui) 110311195Ssam register struct uba_device *ui; 110411195Ssam { 110511195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 110611195Ssam 110711207Ssam if (is->hy_ifuba.ifu_xtofree) { 110811195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 110911195Ssam is->hy_ifuba.ifu_xtofree = 0; 111011195Ssam } 111111195Ssam #ifdef DEBUG 111211207Ssam if (hy_nodebug & 1) 111311207Ssam hy_debug_flag = 1; 111411195Ssam #endif 111511195Ssam #ifdef DEBUG 111611195Ssam printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n", 111711195Ssam ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd, 111811195Ssam is->hy_savedcount, is->hy_savedaddr); 111911207Ssam printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n", 112011207Ssam is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr, 112111207Ssam is->hy_retry); 112211207Ssam printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n", 112311207Ssam is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, 112411207Ssam is->hy_savedcmd); 112511195Ssam #endif 112611195Ssam is->hy_state = IDLE; 112711195Ssam is->hy_flags |= (RQ_ENDOP | RQ_STATUS); 112811195Ssam hyact(ui); 112911207Ssam } 113011195Ssam 113111195Ssam #ifdef DEBUG 113211195Ssam hyprintdata(cp, len) 113311195Ssam register char *cp; 113411195Ssam register int len; 113511195Ssam { 113611195Ssam register int count = 16; 113711195Ssam register char *fmt; 113811195Ssam static char regfmt[] = "\n\t %x"; 113911195Ssam 114011195Ssam fmt = ®fmt[2]; 114111195Ssam while (--len >= 0) { 114211195Ssam printL(fmt, *cp++ & 0xff); 114311195Ssam fmt = ®fmt[2]; 114411195Ssam if (--count <= 0) { 114511195Ssam fmt = ®fmt[0]; 114611195Ssam count = 16; 114711195Ssam } 114811195Ssam } 114911195Ssam printL("\n"); 115011195Ssam } 115111195Ssam #endif 115211195Ssam 115311195Ssam hywatch(unit) 115411195Ssam int unit; 115511195Ssam { 115611195Ssam register struct hy_softc *is = &hy_softc[unit]; 115711195Ssam register struct uba_device *ui = hyinfo[unit]; 115811195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 115911195Ssam int s; 116011195Ssam 116111195Ssam s = splimp(); 116211195Ssam is->hy_if.if_timer = SCANINTERVAL; 116311207Ssam if (is->hy_ntime > 2 && is->hy_state != WAITING && 116411207Ssam is->hy_state != STARTUP && is->hy_state != IDLE) { 116511195Ssam printf("hy%d: watchdog timer expired\n", unit); 116611195Ssam hycancel(ui); 116711195Ssam } 116811195Ssam #ifdef PI13 116911195Ssam if ((addr->hyd_csr & S_POWEROFF) != 0) { 117011195Ssam addr->hyd_csr |= S_POWEROFF; 117111195Ssam DELAY(100); 117211195Ssam if ((addr->hyd_csr & S_POWEROFF) == 0) { 117311195Ssam printf("hy%d: adapter power restored\n", unit); 117411195Ssam is->hy_state = IDLE; 117511207Ssam is->hy_flags |= 117611207Ssam (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS); 117711195Ssam hyact(ui); 117811195Ssam } 117911195Ssam } 118011195Ssam #endif 118111195Ssam splx(s); 118211195Ssam } 118311195Ssam 118411195Ssam #ifdef HYLOG 118511195Ssam hylog(code, len, ptr) 118611195Ssam int code; 118711195Ssam int len; 118811195Ssam char *ptr; 118911195Ssam { 119011195Ssam register unsigned char *p; 119111195Ssam int s; 119211195Ssam 119311195Ssam s = splimp(); 119411195Ssam if (hy_log.hyl_self != &hy_log) { 119511195Ssam hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 119611195Ssam hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 119711195Ssam hy_log.hyl_self = &hy_log; 119811195Ssam hy_log.hyl_enable = HYL_DISABLED; 119911195Ssam hy_log.hyl_onerr = HYL_CATCH1; 120011195Ssam } 120111207Ssam if (hy_log.hyl_enable == HYL_DISABLED || 120211207Ssam hy_log.hyl_enable == HYL_CAUGHT1 || 120311207Ssam hy_log.hyl_enable == HYL_CAUGHTSTATUS || 120411207Ssam (hy_log.hyl_enable == HYL_CATCHSTATUS && code != HYL_STATUS)) 120511207Ssam goto out; 120611195Ssam p = hy_log.hyl_ptr; 120711195Ssam if (p + len + 2 >= hy_log.hyl_eptr) { 1208*12772Ssam bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p)); 120911195Ssam p = &hy_log.hyl_buf[0]; 121011195Ssam if (hy_log.hyl_enable == HYL_CATCH1) { 121111195Ssam hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHT1; 121211195Ssam goto out; 121311195Ssam } 121411195Ssam if (hy_log.hyl_enable == HYL_CATCHSTATUS) { 121511195Ssam hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHTSTATUS; 121611195Ssam goto out; 121711195Ssam } 121811195Ssam } 121911195Ssam *p++ = code; 122011195Ssam *p++ = len; 1221*12772Ssam bcopy(ptr, (caddr_t)p, (unsigned)len); 122211195Ssam hy_log.hyl_ptr = p + len; 122311195Ssam out: 122411195Ssam splx(s); 122511195Ssam } 122611195Ssam #endif 122711195Ssam 1228*12772Ssam #ifdef notdef 1229*12772Ssam /*ARGSUSED*/ 123011207Ssam hyioctl(dev, cmd, data, flag) 123111207Ssam dev_t dev; 123211207Ssam int cmd; 123311207Ssam caddr_t data; 123411207Ssam int flag; 123511195Ssam { 123611207Ssam int s = splimp(), error = 0; 123711195Ssam 123811195Ssam if (minor(dev) >= NHY) { 123911207Ssam error = ENXIO; 124011207Ssam goto bad; 124111195Ssam } 124211195Ssam switch(cmd) { 124311195Ssam 124411195Ssam case HYSETROUTE: 124511207Ssam if (!suser()) { 124611207Ssam error = EPERM; 124711207Ssam goto bad; 124811195Ssam } 124911207Ssam hy_route[minor(dev)] = *(struct hyroute *)data; 125011207Ssam hy_route[minor(dev)].hyr_lasttime = time; 125111195Ssam break; 125211195Ssam 125311195Ssam case HYGETROUTE: 125411207Ssam *(struct hyroute *)data = hy_route[minor(dev)]; 125511195Ssam break; 125611195Ssam 125711195Ssam default: 125811207Ssam error = ENXIO; 125911195Ssam break; 126011195Ssam } 126111207Ssam bad: 126211195Ssam splx(s); 126311207Ssam return (error); 126411195Ssam } 126511207Ssam #endif 1266*12772Ssam #endif 1267