1*13196Sroot /* if_hy.c 4.9 83/06/19 */ 211195Ssam 311195Ssam #include "hy.h" 411195Ssam #if NHY > 0 511195Ssam 611195Ssam /* 711195Ssam * Network Systems Copropration Hyperchanel interface 811195Ssam * 913058Ssam * 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" 2413088Ssam 2511195Ssam #include "../net/if.h" 2611207Ssam #include "../net/netisr.h" 2711195Ssam #include "../net/route.h" 2811195Ssam #include "../netinet/in.h" 2911195Ssam #include "../netinet/in_systm.h" 3011195Ssam #include "../netinet/ip.h" 3111195Ssam #include "../netinet/ip_var.h" 3211195Ssam 3311207Ssam #include "../vax/cpu.h" 3411207Ssam #include "../vax/mtpr.h" 3511207Ssam #include "../vaxuba/ubareg.h" 3611207Ssam #include "../vaxuba/ubavar.h" 3711195Ssam #include "../vaxif/if_hy.h" 3811198Ssam #include "../vaxif/if_hyreg.h" 3911195Ssam #include "../vaxif/if_uba.h" 4011195Ssam 4111195Ssam #define HYROUTE 4211195Ssam #define HYELOG 4311195Ssam #define HYMTU 576 4411195Ssam 4513058Ssam int hyprobe(), hyattach(), hyinit(), hyioctl(); 4613058Ssam int hyoutput(), hyreset(), hywatch(); 4711195Ssam struct uba_device *hyinfo[NHY]; 4811195Ssam u_short hystd[] = { 0772410, 0 }; 4911195Ssam struct uba_driver hydriver = 5011195Ssam { hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo }; 5111195Ssam 5211195Ssam /* 5311195Ssam * Hyperchannel software status per interface. 5411195Ssam * 5511195Ssam * Each interface is referenced by a network interface structure, 5611195Ssam * hy_if, which the routing code uses to locate the interface. 5711195Ssam * This structure contains the output queue for the interface, its address, ... 5811195Ssam * We also have, for each interface, a UBA interface structure, which 5911195Ssam * contains information about the UNIBUS resources held by the interface: 6011195Ssam * map registers, buffered data paths, etc. Information is cached in this 6111195Ssam * structure for use by the if_uba.c routines in running the interface 6211195Ssam * efficiently. 6311195Ssam */ 6411195Ssam struct hy_softc { 6511195Ssam struct ifnet hy_if; /* network-visible interface */ 6611195Ssam struct ifuba hy_ifuba; /* UNIBUS resources */ 6711207Ssam short hy_flags; /* flags */ 6811207Ssam short hy_state; /* driver state */ 6911195Ssam int hy_ilen; /* mp length on input */ 7011195Ssam int hy_olen; /* packet length on output */ 7111195Ssam int hy_lastwcr; /* last command's word count */ 7211195Ssam short hy_savedstate; /* saved for reissue after status */ 7311195Ssam short hy_savedcmd; /* saved command for reissue */ 7411195Ssam int hy_savedcount; /* saved byte count for reissue */ 7511195Ssam int hy_savedaddr; /* saved unibus address for reissue */ 7611195Ssam int hy_ntime; /* number of timeouts since last cmd */ 7711195Ssam int hy_retry; /* retry counter */ 7811207Ssam struct hy_stat hy_stat; /* statistics */ 7911207Ssam struct hy_status hy_status; /* status */ 8011195Ssam } hy_softc[NHY]; 8111195Ssam 8211195Ssam #ifdef HYELOG 8311207Ssam #define HYE_MAX 0x18 8411207Ssam u_long hy_elog[(HYE_MAX+1)*4]; 8511195Ssam #endif 8611195Ssam 8711195Ssam #ifdef DEBUG 8811195Ssam #define printL lprintf 8911195Ssam #define printD if (hy_debug_flag) lprintf 9011195Ssam int hy_debug_flag = 0; 9111195Ssam /* 9211195Ssam * hy_nodebug bit 0x01 set hy_debug_flag on hycancel 9311195Ssam * hy_nodebug bit 0x02 set hy_debug_flag on command reissue 9411195Ssam * hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt 9511195Ssam * hy_nodebug bit 0x08 set hy_debug_flag on hyouput 9611195Ssam * hy_nodebug bit 0x10 set hy_debug_flag on hyouput with associated data 9711195Ssam */ 9811195Ssam int hy_nodebug = 0x0; 9911195Ssam #else 10011195Ssam #define printD hyvoid 10111195Ssam #endif 10211195Ssam 10311195Ssam /* 10411207Ssam * Requests for service (in order by descending priority). 10511195Ssam */ 10611195Ssam #define RQ_ENDOP 001 /* end the last adapter function */ 10711195Ssam #define RQ_REISSUE 002 /* reissue previous cmd after status */ 10811195Ssam #define RQ_STATUS 004 /* get the status of the adapter */ 10911195Ssam #define RQ_STATISTICS 010 /* get the statistics of the adapter */ 11011195Ssam #define RQ_MARKDOWN 020 /* mark this adapter port down */ 11111195Ssam #define RQ_MARKUP 040 /* mark this interface up */ 11211195Ssam 11311195Ssam #define RQ_XASSOC 0100 /* associated data to transmit */ 11411195Ssam 11511195Ssam /* 11611207Ssam * Driver states. 11711195Ssam */ 11811195Ssam #define STARTUP 0 /* initial state (before fully there) */ 11911195Ssam #define IDLE 1 /* idle state */ 12011195Ssam #define STATSENT 2 /* status cmd sent to adapter */ 12111195Ssam #define ENDOPSENT 3 /* end operation cmd sent */ 12211195Ssam #define RECVSENT 4 /* input message cmd sent */ 12311195Ssam #define RECVDATASENT 5 /* input data cmd sent */ 12411195Ssam #define XMITSENT 6 /* transmit message cmd sent */ 12511195Ssam #define XMITDATASENT 7 /* transmit data cmd sent */ 12611195Ssam #define WAITING 8 /* waiting for messages */ 12711195Ssam #define CLEARSENT 9 /* clear wait for message cmd sent */ 12811195Ssam #define MARKPORT 10 /* mark this host's adapter port down issued */ 12911195Ssam #define RSTATSENT 11 /* read statistics cmd sent to adapter */ 13011195Ssam 13111195Ssam #ifdef DEBUG 13211195Ssam char *hy_state_names[] = { 13311195Ssam "Startup", 13411195Ssam "Idle", 13511195Ssam "Status Sent", 13611195Ssam "End op Sent", 13711195Ssam "Recieve Message Proper Sent", 13811195Ssam "Recieve Data Sent", 13911195Ssam "Transmit Message Proper Sent", 14011195Ssam "Transmit Data Sent", 14111195Ssam "Wait for Message Sent", 14211195Ssam "Clear Wait for Message Sent", 14311195Ssam "Mark Port Down Sent", 14411195Ssam "Read Statistics Sent" 14511195Ssam }; 14611195Ssam #endif 14711195Ssam 14811195Ssam #define SCANINTERVAL 10 /* seconds */ 14911195Ssam #define MAXINTERVAL 20 /* seconds (max action) */ 15011195Ssam 15111195Ssam /* 15211195Ssam * Cause a device interrupt. This code uses a buffer starting at 15311195Ssam * location zero on the unibus (which is already mapped by the 15411195Ssam * autoconfigure code in the kernel). 15511195Ssam */ 15611195Ssam hyprobe(reg) 15711195Ssam caddr_t reg; 15811195Ssam { 15911195Ssam register int br, cvec; /* r11, r10 value-result */ 16011195Ssam register struct hydevice *addr = (struct hydevice *) reg; 16111195Ssam 16211195Ssam #ifdef lint 16311195Ssam br = 0; cvec = br; br = cvec; 16411195Ssam hyint(0); 16511195Ssam #endif 16611195Ssam /* 16711195Ssam * request adapter status to a buffer starting at unibus location 0 16811195Ssam */ 16911195Ssam addr->hyd_bar = 0; 17011195Ssam addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1); 17111195Ssam addr->hyd_dbuf = HYF_STATUS; 17211195Ssam #ifdef PI13 17311195Ssam addr->hyd_csr |= S_GO | S_IE | S_IATTN; 17411195Ssam #else 17511195Ssam addr->hyd_csr |= S_GO | S_IE; 17611195Ssam #endif 17711195Ssam DELAY(10000); 17811195Ssam #ifdef PI13 17911195Ssam addr->hyd_csr |= S_CLRINT; /* clear any stacked interrupts */ 18011195Ssam #endif 18111195Ssam addr->hyd_csr &= ~(S_IE | S_CLRINT); /* disable further interrupts */ 18211195Ssam return(1); 18311207Ssam } 18411195Ssam 18511195Ssam /* 18611195Ssam * Interface exists: make available by filling in network interface 18711195Ssam * record. System will initialize the interface when it is ready 18811195Ssam * to accept packets. 18911195Ssam */ 19011195Ssam hyattach(ui) 19111195Ssam struct uba_device *ui; 19211195Ssam { 19311195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 19411195Ssam register struct ifnet *ifp = &is->hy_if; 19511195Ssam 19611195Ssam ifp->if_unit = ui->ui_unit; 19711195Ssam ifp->if_name = "hy"; 19811195Ssam ifp->if_mtu = HYMTU; 19911195Ssam is->hy_state = STARTUP; /* don't allow state transitions yet */ 20011195Ssam ifp->if_init = hyinit; 20113058Ssam 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]; 23813065Ssam struct sockaddr_in *sin; 23911195Ssam int s; 24011195Ssam 24113088Ssam sin = (struct sockaddr_in *)&is->hy_if.if_addr; 24213065Ssam if (in_netof(sin->sin_addr) == 0) 24313065Ssam return; 24411195Ssam if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum, 24511195Ssam sizeof (struct hy_hdr), (int)btoc(HYMTU)) == 0) { 24611195Ssam #ifdef DEBUG 24711207Ssam if (hy_nodebug & 4) 24811207Ssam hy_debug_flag = 1; 24911195Ssam #endif 25011195Ssam printf("hy%d: can't initialize\n", unit); 25111195Ssam is->hy_if.if_flags &= ~IFF_UP; 25211195Ssam return; 25311195Ssam } 25413088Ssam is->hy_if.if_flags |= IFF_RUNNING; 25511195Ssam /* 25611207Ssam * Issue wait for message and start the state machine 25711195Ssam */ 25811195Ssam s = splimp(); 25911195Ssam is->hy_state = IDLE; 26011195Ssam is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP; 26111195Ssam is->hy_retry = 0; 26211195Ssam hyact(ui); 26311195Ssam splx(s); 26411207Ssam } 26511195Ssam 26611195Ssam /* 26711207Ssam * Issue a command to the adapter 26811195Ssam */ 26911195Ssam hystart(ui, cmd, count, ubaddr) 27011195Ssam struct uba_device *ui; 27111207Ssam int cmd, count, ubaddr; 27211195Ssam { 27311195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 27411195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 27511195Ssam 27611195Ssam #ifdef DEBUG 27711207Ssam printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n", 27811207Ssam ui->ui_unit, cmd, count, ubaddr); 27911195Ssam printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 28011207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 28111207Ssam addr->hyd_wcr); 28211195Ssam #endif 28311207Ssam if (((is->hy_flags & RQ_REISSUE) == 0) && 28411207Ssam (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) { 28511195Ssam is->hy_savedstate = is->hy_state; 28611195Ssam is->hy_savedcmd = cmd; 28711195Ssam is->hy_savedcount = count; 28811195Ssam is->hy_savedaddr = ubaddr; 28911195Ssam } 29011195Ssam addr->hyd_bar = ubaddr & 0xffff; 29111207Ssam addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1); 29211195Ssam addr->hyd_dbuf = cmd; 29311195Ssam #ifdef PI13 29411195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN; 29511195Ssam #else 29611195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE; 29711195Ssam #endif 29811195Ssam #ifdef DEBUG 29911195Ssam printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 30011207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 30111207Ssam addr->hyd_wcr); 30211195Ssam #endif 30311195Ssam #ifdef HYLOG 30411195Ssam { 30511195Ssam struct { 30611207Ssam u_char hcmd; 30711207Ssam u_char hstate; 30811207Ssam short hcount; 30911195Ssam } hcl; 31011195Ssam 31111195Ssam hcl.hcmd = cmd; 31211195Ssam hcl.hstate = is->hy_state; 31311195Ssam hcl.hcount = count; 31411195Ssam hylog(HYL_CMD, sizeof(hcl), (char *)&hcl); 31511195Ssam } 31611195Ssam #endif 31711195Ssam is->hy_ntime = 0; 31811207Ssam } 31911195Ssam 32011195Ssam int hyint_active = 0; /* set during hy interrupt */ 32111195Ssam /* 32211207Ssam * Hyperchannel interface interrupt. 32311195Ssam * 32411195Ssam * An interrupt can occur for many reasons. Examine the status of 32511195Ssam * the hyperchannel status bits to determine what to do next. 32611195Ssam * 32711195Ssam * If input error just drop packet. 32811195Ssam * Otherwise purge input buffered data path and examine 32911195Ssam * packet to determine type. Othewise decapsulate 33011195Ssam * packet based on type and pass to type specific higher-level 33111195Ssam * input routine. 33211195Ssam */ 33311195Ssam hyint(unit) 33411195Ssam int unit; 33511195Ssam { 33611195Ssam register struct hy_softc *is = &hy_softc[unit]; 33711195Ssam register struct uba_device *ui = hyinfo[unit]; 33811207Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 33911195Ssam 34011207Ssam if (hyint_active) 34111195Ssam panic("RECURSIVE HYPERCHANNEL INTERRUPT"); 34211195Ssam hyint_active++; 34311195Ssam #ifdef DEBUG 34411195Ssam printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 34511195Ssam unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 34611195Ssam #endif 34711195Ssam #ifdef HYLOG 34811195Ssam logit: 34911195Ssam { 35011195Ssam struct { 35111207Ssam u_char hstate; 35211207Ssam u_char hflags; 35311207Ssam short hcsr; 35411207Ssam short hwcr; 35511195Ssam } hil; 35611195Ssam hil.hstate = is->hy_state; 35711195Ssam hil.hflags = is->hy_flags; 35811195Ssam hil.hcsr = addr->hyd_csr; 35911195Ssam hil.hwcr = addr->hyd_wcr; 36011195Ssam hylog(HYL_INT, sizeof(hil), (char *)&hil); 36111195Ssam } 36211195Ssam #endif 36311207Ssam if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) { 36411195Ssam /* 36511207Ssam * Error bit set, some sort of error in the interface. 36611195Ssam * 36711207Ssam * The adapter sets attn on command completion so that's not 36811207Ssam * a real error even though the interface considers it one. 36911195Ssam */ 37011195Ssam #ifdef DEBUG 37111207Ssam if (hy_nodebug & 4) 37211207Ssam hy_debug_flag = 1; 37311195Ssam #endif 37411207Ssam printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n", 37511207Ssam addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 37611207Ssam addr->hyd_wcr); 37711207Ssam if (addr->hyd_csr & S_NEX) { 37811195Ssam printf("hy%d: NEX - Non Existant Memory\n", unit); 37911195Ssam #ifdef PI13 38011195Ssam addr->hyd_csr |= S_NEX; /* as per PI13 manual */ 38111195Ssam #else 38211195Ssam addr->hyd_csr &= ~S_NEX; 38311195Ssam #endif 38411195Ssam hycancel(ui); 38511195Ssam #ifdef PI13 38611207Ssam } else if (addr->hyd_csr & S_POWEROFF) { 38711207Ssam printf("hy%d: Power Off bit set, trying to reset\n", 38811207Ssam unit); 38911195Ssam addr->hyd_csr |= S_POWEROFF; 39011195Ssam DELAY(100); 39111207Ssam if (addr->hyd_csr & S_POWEROFF) { 39211195Ssam if_down(&is->hy_if); 39311195Ssam is->hy_state = STARTUP; 39411207Ssam printf( 39511207Ssam "hy%d: Power Off Error, network shutdown\n", 39611207Ssam unit); 39711195Ssam } 39811195Ssam #endif 39911195Ssam } else { 40011195Ssam printf("hy%d: BAR overflow\n", unit); 40111195Ssam hycancel(ui); 40211195Ssam } 40311207Ssam } else if (HYS_NORMAL(addr)) { 40411195Ssam /* 40511207Ssam * Normal interrupt, bump state machine unless in state 40611195Ssam * waiting and no data present (assumed to be word count 40711207Ssam * zero interrupt or other hardware botch). 40811195Ssam */ 40911207Ssam if (is->hy_state != WAITING || HYS_RECVDATA(addr)) 41011195Ssam hyact(ui); 41111207Ssam } else if (HYS_ABNORMAL(addr)) { 41211195Ssam /* 41311207Ssam * Abnormal termination. 41411195Ssam * bump error counts, retry the last function 41511195Ssam * 'MAXRETRY' times before kicking the bucket. 41611195Ssam * 41711207Ssam * Don't reissue the cmd if in certain states, abnormal 41811207Ssam * on a reissued cmd or max retry exceeded. 41911195Ssam */ 42011195Ssam #ifdef HYLOG 42111195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 42211195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 42311195Ssam goto logit; 42411195Ssam } 42511195Ssam #endif 42611195Ssam #ifdef DEBUG 42711207Ssam if (hy_nodebug & 4) 42811207Ssam hy_debug_flag = 1; 42911195Ssam printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n", 43011195Ssam unit, hy_state_names[is->hy_state], is->hy_state); 43111207Ssam printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n", 43211207Ssam is->hy_flags, is->hy_ilen, is->hy_olen, 43311207Ssam is->hy_lastwcr, is->hy_retry); 43411207Ssam printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n", 43511207Ssam is->hy_savedstate, is->hy_savedcount, 43611207Ssam is->hy_savedaddr, is->hy_savedcmd); 43711195Ssam #endif 43811195Ssam #ifdef PI13 43911195Ssam addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */ 44011195Ssam #endif 44111207Ssam if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT) 44211195Ssam is->hy_if.if_oerrors++; 44311207Ssam if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT) 44411195Ssam is->hy_if.if_ierrors++; 44511195Ssam if (is->hy_state == XMITDATASENT || 44611195Ssam is->hy_state == RECVSENT || 44711195Ssam is->hy_state == RECVDATASENT || 44811207Ssam (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY) 44911195Ssam hycancel(ui); 45011207Ssam else { 45111195Ssam #ifdef DEBUG 45211207Ssam if (hy_nodebug & 2) 45311207Ssam hy_debug_flag = 1; 45411195Ssam #endif 45511195Ssam is->hy_retry++; 45611195Ssam is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE; 45711195Ssam is->hy_state = IDLE; 45811195Ssam hyact(ui); 45911195Ssam } 46011195Ssam } else { 46111195Ssam /* 46211195Ssam * Interrupt is neither normal, abnormal, or interface error. 46311195Ssam * Ignore it. It's either stacked or a word count 0. 46411195Ssam */ 46511195Ssam #ifdef HYLOG 46611195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 46711195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 46811195Ssam goto logit; 46911195Ssam } 47011195Ssam #endif 47111195Ssam #ifdef DEBUG 47211195Ssam printD("hy%d: possible stacked interrupt ignored\n", unit); 47311195Ssam #endif 47411195Ssam } 47511195Ssam #ifdef DEBUG 47611195Ssam printD("hy%d: hyint exit\n\n", unit); 47711195Ssam #endif 47811195Ssam hyint_active = 0; 47911195Ssam 48011207Ssam } 48111195Ssam 48211195Ssam /* 48311195Ssam * Encapsulate a packet of type family for the local net. 48411195Ssam */ 48511195Ssam hyoutput(ifp, m0, dst) 48611195Ssam struct ifnet *ifp; 48711195Ssam struct mbuf *m0; 48811195Ssam struct sockaddr *dst; 48911195Ssam { 49011195Ssam register struct hym_hdr *hym; 49111195Ssam register struct mbuf *m; 49211195Ssam #ifdef HYROUTE 49311195Ssam register struct hyroute *r = &hy_route[ifp->if_unit]; 49411195Ssam #endif 49511195Ssam short dtype; /* packet type */ 49611195Ssam int dhost; /* destination adapter address */ 49711195Ssam int dlen; 49811195Ssam int mplen = 0; /* message proper length */ 49911195Ssam short loopback = 0; /* hardware loopback requested */ 50011195Ssam int error = 0; 50111195Ssam int s; 50211195Ssam 50311195Ssam #ifdef DEBUG 50411207Ssam if (hy_nodebug & 8) 50511207Ssam hy_debug_flag = 1; 50611195Ssam #endif 50711195Ssam dlen = 0; 50811195Ssam for (m = m0; m; m = m->m_next) 50911195Ssam dlen += m->m_len; 51011195Ssam m = m0; 51111195Ssam switch(dst->sa_family) { 51211195Ssam 51311195Ssam #ifdef INET 51411195Ssam case AF_INET: { 51511195Ssam register struct ip *ip = mtod(m, struct ip *); 51611195Ssam register struct sockaddr_in *sin = (struct sockaddr_in *)dst; 51711195Ssam register long hostaddr = in_lnaof(sin->sin_addr); 51811195Ssam 51911195Ssam dhost = hostaddr & 0xffff; 52011195Ssam dtype = HYLINK_IP; 52111195Ssam #ifdef DEBUG 52211207Ssam printD("hy%d: output to host %x, dhost %x\n", 52311207Ssam ifp->if_unit, sin->sin_addr.s_addr, dhost); 52411195Ssam #endif 52511195Ssam /* 52611207Ssam * Debugging loopback support: 52711195Ssam * upper byte of 24 bit host number interpreted as follows 52811195Ssam * 0x00 --> no loopback 52911195Ssam * 0x01 --> hardware loop through remote adapter 53011195Ssam * other --> software loop through remote ip layer 53111195Ssam */ 53211195Ssam if (hostaddr & 0xff0000) { 53311195Ssam struct in_addr temp; 53411195Ssam 53511195Ssam temp = ip->ip_dst; 53611195Ssam ip->ip_dst = ip->ip_src; 53711195Ssam ip->ip_src = temp; 53811195Ssam if ((hostaddr & 0xff0000) == 0x10000) 53911195Ssam loopback = H_LOOPBK; 54011195Ssam } 54111195Ssam /* 54211195Ssam * If entire packet won't fit in message proper, just 54311195Ssam * send hyperchannel hardware header and ip header in 54411195Ssam * message proper. If that won't fit either, just send 54511195Ssam * the maximum message proper. 54611195Ssam * 54711195Ssam * This insures that the associated data is at least a 54811195Ssam * TCP/UDP header in length and thus prevents potential 54911195Ssam * problems with very short word counts. 55011195Ssam */ 55111195Ssam if (dlen > MPSIZE - sizeof (struct hy_hdr)) { 55211195Ssam mplen = sizeof(struct hy_hdr) + (ip->ip_hl << 2); 55311195Ssam if (mplen > MPSIZE) 55411195Ssam mplen = MPSIZE; 55511195Ssam } 55611195Ssam break; 55711195Ssam } 55811195Ssam #endif 55911195Ssam 56011195Ssam default: 56111207Ssam printf("hy%d: can't handle af%d\n", ifp->if_unit, 56211207Ssam dst->sa_family); 56311195Ssam #ifdef DEBUG 56411207Ssam if (hy_nodebug & 4) 56511207Ssam hy_debug_flag = 1; 56611195Ssam #endif 56711195Ssam error = EAFNOSUPPORT; 56811195Ssam goto drop; 56911195Ssam } 57011195Ssam 57111195Ssam /* 57211207Ssam * Add the software and hardware hyperchannel headers. 57311195Ssam * If there's not enough space in the first mbuf, allocate another. 57411195Ssam * If that should fail, drop this sucker. 57511195Ssam * No extra space for headers is allocated. 57611195Ssam */ 57711195Ssam if (m->m_off > MMAXOFF || 57811195Ssam MMINOFF + sizeof(struct hym_hdr) > m->m_off) { 57911207Ssam m = m_get(M_DONTWAIT, MT_HEADER); 58011195Ssam if (m == 0) { 58111195Ssam m = m0; 58211195Ssam error = ENOBUFS; 58311195Ssam goto drop; 58411195Ssam } 58511195Ssam m->m_next = m0; 58611195Ssam m->m_off = MMINOFF; 58711195Ssam m->m_len = sizeof(struct hym_hdr); 58811195Ssam } else { 58911195Ssam m->m_off -= sizeof(struct hym_hdr); 59011195Ssam m->m_len += sizeof(struct hym_hdr); 59111195Ssam } 59211195Ssam hym = mtod(m, struct hym_hdr *); 59311195Ssam hym->hym_mplen = mplen; 59411195Ssam hym->hym_hdr.hyh_type = dtype; 59511195Ssam hym->hym_hdr.hyh_off = 0; 59612772Ssam hym->hym_hdr.hyh_from = htons((u_short)ifp->if_host[0]); 59711195Ssam hym->hym_hdr.hyh_param = loopback; 59811195Ssam #ifdef HYROUTE 59911207Ssam if (r->hyr_lasttime.tv_sec != 0) { 60011195Ssam register struct hy_hash *rh; 60111195Ssam register int i; 60211195Ssam 60311195Ssam i = HYRHASH(dhost); 60411195Ssam rh = &r->hyr_hash[i]; 60511195Ssam i = 0; 60611195Ssam while (rh->hyr_key != dhost) { 60711195Ssam rh++; i++; 60811195Ssam if (rh > &r->hyr_hash[HYRSIZE]) 60911195Ssam rh = &r->hyr_hash[0]; 61011195Ssam if (rh->hyr_flags == 0 || i > HYRSIZE) 61111195Ssam goto notfound; 61211195Ssam } 61311195Ssam if (rh->hyr_flags & HYR_GATE) { 61411195Ssam loopback = 0; /* no hardware loopback on gateways */ 61511195Ssam i = rh->hyr_nextgate; 61611195Ssam if (i >= rh->hyr_egate) 61711195Ssam rh->hyr_nextgate = rh->hyr_pgate; 61811195Ssam else 61911195Ssam rh->hyr_nextgate++; 62011195Ssam rh = &r->hyr_hash[r->hyr_gateway[i]]; 62111195Ssam if ((rh->hyr_flags & HYR_DIR) == 0) 62211195Ssam goto notfound; 62311195Ssam } 62411195Ssam hym->hym_hdr.hyh_ctl = rh->hyr_ctl; 62511195Ssam hym->hym_hdr.hyh_access = rh->hyr_access; 62611195Ssam hym->hym_hdr.hyh_to = rh->hyr_dst; 62711195Ssam } else { 62811195Ssam hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS; 62911195Ssam hym->hym_hdr.hyh_access = 0; 63012772Ssam hym->hym_hdr.hyh_to = htons((u_short)dhost); 63111195Ssam } 63211195Ssam #else 63311195Ssam hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS; 63411195Ssam hym->hym_hdr.hyh_access = 0; 63511195Ssam hym->hym_hdr.hyh_to = htons(dhost); 63611195Ssam #endif 63711195Ssam 63811195Ssam if (hym->hym_mplen) { 63911195Ssam hym->hym_hdr.hyh_ctl |= H_ASSOC; 64011195Ssam #ifdef DEBUG 64111207Ssam if (hy_nodebug & 16) 64211207Ssam hy_debug_flag = 1; 64311195Ssam #endif 64411207Ssam } else 64511207Ssam hym->hym_hdr.hyh_ctl &= ~H_ASSOC; 64611195Ssam #ifdef DEBUG 64711207Ssam printD("hy%d: output mplen=%x ctl=%x access=%x to=%x", 64811195Ssam ifp->if_unit, hym->hym_mplen, hym->hym_hdr.hyh_ctl, 64911207Ssam hym->hym_hdr.hyh_access, hym->hym_hdr.hyh_to); 65011207Ssam printD(" (adapter %x) from=%x param=%x type=%x off=%x\n", 65111195Ssam hym->hym_hdr.hyh_to_adapter, 65211195Ssam hym->hym_hdr.hyh_from, hym->hym_hdr.hyh_param, 65311195Ssam hym->hym_hdr.hyh_type, hym->hym_hdr.hyh_off); 65411195Ssam #endif 65511195Ssam s = splimp(); 65611195Ssam if (IF_QFULL(&ifp->if_snd)) { 65711195Ssam IF_DROP(&ifp->if_snd); 65811195Ssam error = ENOBUFS; 65911195Ssam splx(s); 66011195Ssam goto drop; 66111195Ssam } 66211195Ssam IF_ENQUEUE(&ifp->if_snd, m); 66311195Ssam if (hy_softc[ifp->if_unit].hy_state == WAITING) 66411195Ssam hyact(hyinfo[ifp->if_unit]); 66511195Ssam splx(s); 66611207Ssam return (0); 66711195Ssam notfound: 66811207Ssam error = ENETUNREACH; /* XXX */ 66911195Ssam drop: 67011195Ssam m_freem(m); 67111207Ssam return (error); 67211207Ssam } 67311195Ssam 67411195Ssam hyact(ui) 67511195Ssam register struct uba_device *ui; 67611195Ssam { 67711195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 67811195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 67911195Ssam 68011195Ssam actloop: 68111195Ssam #ifdef DEBUG 68211207Ssam printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, 68311207Ssam hy_state_names[is->hy_state]); 68411195Ssam #endif 68511195Ssam switch (is->hy_state) { 68611195Ssam 68711195Ssam case STARTUP: 68811195Ssam goto endintr; 68911195Ssam 69011195Ssam case IDLE: { 69111195Ssam register rq = is->hy_flags; 69211195Ssam 69311195Ssam if (rq & RQ_STATUS) { 69411195Ssam is->hy_flags &= ~RQ_STATUS; 69511195Ssam is->hy_state = STATSENT; 69611207Ssam hystart(ui, HYF_STATUS, sizeof (is->hy_status), 69713088Ssam is->hy_ifuba.ifu_r.ifrw_info); 69811195Ssam } else if (rq & RQ_ENDOP) { 69911195Ssam is->hy_flags &= ~RQ_ENDOP; 70011195Ssam is->hy_state = ENDOPSENT; 70111195Ssam hystart(ui, HYF_END_OP, 0, 0); 70211195Ssam } else if (rq & RQ_STATISTICS) { 70311195Ssam is->hy_flags &= ~RQ_STATISTICS; 70411195Ssam is->hy_state = RSTATSENT; 70511207Ssam hystart(ui, HYF_RSTATS, sizeof (is->hy_stat), 70613088Ssam is->hy_ifuba.ifu_r.ifrw_info); 70711207Ssam } else if (HYS_RECVDATA(addr)) { 70811195Ssam is->hy_state = RECVSENT; 70911195Ssam is->hy_retry = 0; 71011207Ssam hystart(ui, HYF_INPUTMSG, MPSIZE, 71113088Ssam is->hy_ifuba.ifu_r.ifrw_info); 71211195Ssam } else if (rq & RQ_REISSUE) { 71311195Ssam is->hy_flags &= ~RQ_REISSUE; 71411195Ssam is->hy_state = is->hy_savedstate; 71511195Ssam #ifdef DEBUG 71611207Ssam printD("hy%d: reissue cmd=0x%x count=%d", 71711207Ssam ui->ui_unit, is->hy_savedcmd, is->hy_savedcount); 71811207Ssam printD(" ubaddr=0x%x retry=%d\n", 71911207Ssam is->hy_savedaddr, is->hy_retry); 72011195Ssam #endif 72111207Ssam hystart(ui, is->hy_savedcmd, is->hy_savedcount, 72213088Ssam is->hy_savedaddr); 72311195Ssam } else { 72411195Ssam register struct mbuf *m; 72511195Ssam 72611195Ssam IF_DEQUEUE(&is->hy_if.if_snd, m); 72711207Ssam if (m != NULL) { 72811195Ssam register struct hym_hdr *hym; 72911195Ssam register int mplen; 73011195Ssam register int cmd; 73111195Ssam 73211195Ssam is->hy_state = XMITSENT; 73311195Ssam is->hy_retry = 0; 73411195Ssam hym = mtod(m, struct hym_hdr *); 73511195Ssam #ifdef HYLOG 73611207Ssam hylog(HYL_XMIT, sizeof(struct hym_hdr), 73713088Ssam (char *)hym); 73811195Ssam #endif 73911195Ssam mplen = hym->hym_mplen; 74011207Ssam if (hym->hym_hdr.hyh_to_adapter == 74113088Ssam hym->hym_hdr.hyh_from_adapter) 74211207Ssam cmd = HYF_XMITLOCMSG; 74311207Ssam else 74411207Ssam cmd = HYF_XMITMSG; 74511195Ssam #ifdef DEBUG 74611195Ssam printD("hy%d: hym_hdr = ", ui->ui_unit); 74711207Ssam if (hy_debug_flag) 74811207Ssam hyprintdata((char *)hym, 74913088Ssam sizeof (struct hym_hdr)); 75011195Ssam #endif 75111195Ssam /* 75211207Ssam * Strip off the software part of 75311195Ssam * the hyperchannel header 75411195Ssam */ 75511195Ssam m->m_off += sizeof(struct hym_data); 75611195Ssam m->m_len -= sizeof(struct hym_data); 75711195Ssam is->hy_olen = if_wubaput(&is->hy_ifuba, m); 75811195Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 75911207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 76011207Ssam is->hy_ifuba.ifu_w.ifrw_bdp); 76111195Ssam #ifdef DEBUG 76211207Ssam printD( 76311207Ssam "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 76411195Ssam ui->ui_unit, mplen, is->hy_olen); 76511207Ssam if (hy_debug_flag) 76611207Ssam hyprintdata( 76713088Ssam is->hy_ifuba.ifu_w.ifrw_addr, 76813088Ssam is->hy_olen); 76911195Ssam #endif 77011207Ssam hystart(ui, cmd, 77113088Ssam (mplen == 0) ? is->hy_olen : mplen, 77213088Ssam is->hy_ifuba.ifu_w.ifrw_info); 77311195Ssam if (mplen != 0) 77411195Ssam is->hy_flags |= RQ_XASSOC; 77511195Ssam } else if (rq & RQ_MARKDOWN) { 77611195Ssam is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN); 77711195Ssam is->hy_state = MARKPORT; 77811195Ssam is->hy_retry = 0; 77911195Ssam /* 78011207Ssam * Port number is taken from status data 78111195Ssam */ 78211207Ssam hystart(ui, 78312772Ssam (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)), 78412772Ssam 0, 0); 78511195Ssam } else if (rq & RQ_MARKUP) { 78611195Ssam register struct ifnet *ifp = &is->hy_if; 78711207Ssam register struct sockaddr_in *sin = 78811207Ssam (struct sockaddr_in *)&ifp->if_addr; 78911195Ssam 79011207Ssam is->hy_flags &= ~RQ_MARKUP; 79111195Ssam is->hy_retry = 0; 79211195Ssam /* 79313065Ssam * Fill in the host number 79411207Ssam * from the status buffer 79511195Ssam */ 79611207Ssam printf( 79711207Ssam "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n", 79811195Ssam ui->ui_unit, 79911195Ssam is->hy_stat.hyc_uaddr, 80011195Ssam PORTNUM(&is->hy_status), 80111207Ssam (is->hy_stat.hyc_atype[0]<<8) | 80211207Ssam is->hy_stat.hyc_atype[1], 80311195Ssam is->hy_stat.hyc_atype[2]); 80411195Ssam 80511207Ssam ifp->if_host[0] = 80611207Ssam (is->hy_stat.hyc_uaddr << 8) | 80711207Ssam PORTNUM(&is->hy_status); 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: 82512772Ssam 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, 91213088Ssam 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", 91713088Ssam 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, 93513088Ssam (int)(HYMTU-len+sizeof (struct hy_hdr)), 93613088Ssam (int)(is->hy_ifuba.ifu_r.ifrw_info + len)); 93711207Ssam } else { 93812772Ssam 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, 95013088Ssam 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 95912772Ssam 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) { 966*13196Sroot register int 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, 98113088Ssam 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: 101513088Ssam ; 101611195Ssam #ifdef DEBUG 101711207Ssam printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, 101811207Ssam hy_state_names[is->hy_state]); 101911195Ssam #endif 102011207Ssam } 102111195Ssam 102211195Ssam /* 102313088Ssam * Called from device interrupt when receiving data. 102411195Ssam * Examine packet to determine type. Decapsulate packet 102511195Ssam * based on type and pass to type specific higher-level 102611195Ssam * input routine. 102711195Ssam */ 102813088Ssam hyrecvdata(ui, hyh, len) 102911195Ssam struct uba_device *ui; 103013088Ssam register struct hy_hdr *hyh; 103111195Ssam int len; 103211195Ssam { 103311195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 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) 115413088Ssam 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) 118613088Ssam int code, len; 118711195Ssam char *ptr; 118811195Ssam { 118911195Ssam register unsigned char *p; 119011195Ssam int s; 119111195Ssam 119211195Ssam s = splimp(); 119311195Ssam if (hy_log.hyl_self != &hy_log) { 119411195Ssam hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 119511195Ssam hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 119611195Ssam hy_log.hyl_self = &hy_log; 119711195Ssam hy_log.hyl_enable = HYL_DISABLED; 119811195Ssam hy_log.hyl_onerr = HYL_CATCH1; 119911195Ssam } 120011207Ssam if (hy_log.hyl_enable == HYL_DISABLED || 120111207Ssam hy_log.hyl_enable == HYL_CAUGHT1 || 120211207Ssam hy_log.hyl_enable == HYL_CAUGHTSTATUS || 120311207Ssam (hy_log.hyl_enable == HYL_CATCHSTATUS && code != HYL_STATUS)) 120411207Ssam goto out; 120511195Ssam p = hy_log.hyl_ptr; 120611195Ssam if (p + len + 2 >= hy_log.hyl_eptr) { 120712772Ssam bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p)); 120811195Ssam p = &hy_log.hyl_buf[0]; 120911195Ssam if (hy_log.hyl_enable == HYL_CATCH1) { 121011195Ssam hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHT1; 121111195Ssam goto out; 121211195Ssam } 121311195Ssam if (hy_log.hyl_enable == HYL_CATCHSTATUS) { 121411195Ssam hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHTSTATUS; 121511195Ssam goto out; 121611195Ssam } 121711195Ssam } 121811195Ssam *p++ = code; 121911195Ssam *p++ = len; 122013088Ssam bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len); 122111195Ssam hy_log.hyl_ptr = p + len; 122211195Ssam out: 122311195Ssam splx(s); 122411195Ssam } 122511195Ssam #endif 122611195Ssam 122712772Ssam /*ARGSUSED*/ 122813058Ssam hyioctl(ifp, cmd, data) 122913058Ssam register struct ifnet *ifp; 123011207Ssam int cmd; 123111207Ssam caddr_t data; 123211195Ssam { 123313065Ssam struct sockaddr_in *sin; 123413088Ssam struct ifreq *ifr = (struct ifreq *)data; 123511207Ssam int s = splimp(), error = 0; 123611195Ssam 123711195Ssam switch(cmd) { 123811195Ssam 123913065Ssam case SIOCSIFADDR: 124013065Ssam if (ifp->if_flags & IFF_RUNNING) 124113065Ssam if_rtinit(ifp, -1); 124213065Ssam sin = (struct sockaddr_in *)&ifr->ifr_addr; 124313065Ssam ifp->if_net = in_netof(sin->sin_addr); 124413065Ssam sin = (struct sockaddr_in *)&ifp->if_addr; 124513065Ssam sin->sin_family = AF_INET; 124613065Ssam sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]); 124713065Ssam if (ifp->if_flags & IFF_RUNNING) 124813065Ssam if_rtinit(ifp, RTF_UP); 124913065Ssam else 125013065Ssam hyinit(ifp->if_unit); 125113065Ssam break; 125213065Ssam 125311195Ssam case HYSETROUTE: 125411207Ssam if (!suser()) { 125511207Ssam error = EPERM; 125611207Ssam goto bad; 125711195Ssam } 125813058Ssam hy_route[ifp->if_unit] = *(struct hyroute *)ifr->ifr_data; 125913058Ssam hy_route[ifp->if_unit].hyr_lasttime = time; 126011195Ssam break; 126111195Ssam 126211195Ssam case HYGETROUTE: 126313058Ssam *(struct hyroute *)ifr->ifr_data = hy_route[ifp->if_unit]; 126411195Ssam break; 126511195Ssam 126611195Ssam default: 126713058Ssam error = EINVAL; 126811195Ssam break; 126911195Ssam } 127011207Ssam bad: 127111195Ssam splx(s); 127211207Ssam return (error); 127311195Ssam } 127411207Ssam #endif 1275