1*11207Ssam /* if_hy.c 4.3 83/02/21 */ 211195Ssam 311195Ssam #include "hy.h" 411195Ssam #if NHY > 0 511195Ssam 611195Ssam /* 711195Ssam * Network Systems Copropration Hyperchanel interface 811195Ssam * 9*11207Ssam * 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" 21*11207Ssam #include "../h/time.h" 22*11207Ssam #include "../h/kernel.h" 23*11207Ssam #include "../h/ioctl.h" 2411195Ssam 2511195Ssam #include "../net/if.h" 26*11207Ssam #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 34*11207Ssam #include "../vax/cpu.h" 35*11207Ssam #include "../vax/mtpr.h" 36*11207Ssam 37*11207Ssam #include "../vaxuba/ubareg.h" 38*11207Ssam #include "../vaxuba/ubavar.h" 39*11207Ssam 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 */ 69*11207Ssam short hy_flags; /* flags */ 70*11207Ssam 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 */ 80*11207Ssam struct hy_stat hy_stat; /* statistics */ 81*11207Ssam struct hy_status hy_status; /* status */ 8211195Ssam } hy_softc[NHY]; 8311195Ssam 8411195Ssam #ifdef HYELOG 85*11207Ssam #define HYE_MAX 0x18 86*11207Ssam 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 /* 106*11207Ssam * 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 /* 118*11207Ssam * 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); 185*11207Ssam } 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; 205*11207Ssam ifp->if_reset = hyreset; 20611195Ssam ifp->if_watchdog = hywatch; 20711195Ssam ifp->if_timer = SCANINTERVAL; 20811195Ssam is->hy_ifuba.ifu_flags = UBA_CANTWAIT; 209*11207Ssam #ifdef notdef 21011195Ssam is->hy_ifuba.ifu_flags |= UBA_NEEDBDP; 21111195Ssam #endif 21211195Ssam if_attach(ifp); 213*11207Ssam } 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 register struct hy_softc *is; 22411195Ssam 225*11207Ssam if (unit >= NHY || ui == 0 || ui->ui_alive == 0 || 226*11207Ssam ui->ui_ubanum != uban) 22711195Ssam return; 22811195Ssam printf(" hy%d", unit); 22911195Ssam hyinit(unit); 230*11207Ssam } 23111195Ssam 23211195Ssam /* 23311195Ssam * Initialization of interface; clear recorded pending 23411195Ssam * operations, and reinitialize UNIBUS usage. 23511195Ssam */ 23611195Ssam hyinit(unit) 23711195Ssam int unit; 23811195Ssam { 23911195Ssam register struct hy_softc *is = &hy_softc[unit]; 24011195Ssam register struct uba_device *ui = hyinfo[unit]; 24111195Ssam int s; 24211195Ssam 24311195Ssam if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum, 24411195Ssam sizeof (struct hy_hdr), (int)btoc(HYMTU)) == 0) { 24511195Ssam #ifdef DEBUG 246*11207Ssam if (hy_nodebug & 4) 247*11207Ssam hy_debug_flag = 1; 24811195Ssam #endif 24911195Ssam printf("hy%d: can't initialize\n", unit); 25011195Ssam is->hy_if.if_flags &= ~IFF_UP; 25111195Ssam return; 25211195Ssam } 25311195Ssam /* 254*11207Ssam * Issue wait for message and start the state machine 25511195Ssam */ 25611195Ssam s = splimp(); 25711195Ssam is->hy_state = IDLE; 25811195Ssam is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP; 25911195Ssam is->hy_retry = 0; 26011195Ssam hyact(ui); 26111195Ssam splx(s); 262*11207Ssam } 26311195Ssam 26411195Ssam /* 265*11207Ssam * Issue a command to the adapter 26611195Ssam */ 26711195Ssam hystart(ui, cmd, count, ubaddr) 26811195Ssam struct uba_device *ui; 269*11207Ssam int cmd, count, ubaddr; 27011195Ssam { 27111195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 27211195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 27311195Ssam 27411195Ssam #ifdef DEBUG 275*11207Ssam printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n", 276*11207Ssam ui->ui_unit, cmd, count, ubaddr); 27711195Ssam printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 278*11207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 279*11207Ssam addr->hyd_wcr); 28011195Ssam #endif 281*11207Ssam if (((is->hy_flags & RQ_REISSUE) == 0) && 282*11207Ssam (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) { 28311195Ssam is->hy_savedstate = is->hy_state; 28411195Ssam is->hy_savedcmd = cmd; 28511195Ssam is->hy_savedcount = count; 28611195Ssam is->hy_savedaddr = ubaddr; 28711195Ssam } 28811195Ssam addr->hyd_bar = ubaddr & 0xffff; 289*11207Ssam addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1); 29011195Ssam addr->hyd_dbuf = cmd; 29111195Ssam #ifdef PI13 29211195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN; 29311195Ssam #else 29411195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE; 29511195Ssam #endif 29611195Ssam #ifdef DEBUG 29711195Ssam printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 298*11207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 299*11207Ssam addr->hyd_wcr); 30011195Ssam #endif 30111195Ssam #ifdef HYLOG 30211195Ssam { 30311195Ssam struct { 304*11207Ssam u_char hcmd; 305*11207Ssam u_char hstate; 306*11207Ssam short hcount; 30711195Ssam } hcl; 30811195Ssam 30911195Ssam hcl.hcmd = cmd; 31011195Ssam hcl.hstate = is->hy_state; 31111195Ssam hcl.hcount = count; 31211195Ssam hylog(HYL_CMD, sizeof(hcl), (char *)&hcl); 31311195Ssam } 31411195Ssam #endif 31511195Ssam is->hy_ntime = 0; 316*11207Ssam } 31711195Ssam 31811195Ssam int hyint_active = 0; /* set during hy interrupt */ 31911195Ssam /* 320*11207Ssam * Hyperchannel interface interrupt. 32111195Ssam * 32211195Ssam * An interrupt can occur for many reasons. Examine the status of 32311195Ssam * the hyperchannel status bits to determine what to do next. 32411195Ssam * 32511195Ssam * If input error just drop packet. 32611195Ssam * Otherwise purge input buffered data path and examine 32711195Ssam * packet to determine type. Othewise decapsulate 32811195Ssam * packet based on type and pass to type specific higher-level 32911195Ssam * input routine. 33011195Ssam */ 33111195Ssam hyint(unit) 33211195Ssam int unit; 33311195Ssam { 33411195Ssam register struct hy_softc *is = &hy_softc[unit]; 33511195Ssam register struct uba_device *ui = hyinfo[unit]; 336*11207Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 33711195Ssam 338*11207Ssam if (hyint_active) 33911195Ssam panic("RECURSIVE HYPERCHANNEL INTERRUPT"); 34011195Ssam hyint_active++; 34111195Ssam #ifdef DEBUG 34211195Ssam printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 34311195Ssam unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 34411195Ssam #endif 34511195Ssam #ifdef HYLOG 34611195Ssam logit: 34711195Ssam { 34811195Ssam struct { 349*11207Ssam u_char hstate; 350*11207Ssam u_char hflags; 351*11207Ssam short hcsr; 352*11207Ssam short hwcr; 35311195Ssam } hil; 35411195Ssam hil.hstate = is->hy_state; 35511195Ssam hil.hflags = is->hy_flags; 35611195Ssam hil.hcsr = addr->hyd_csr; 35711195Ssam hil.hwcr = addr->hyd_wcr; 35811195Ssam hylog(HYL_INT, sizeof(hil), (char *)&hil); 35911195Ssam } 36011195Ssam #endif 361*11207Ssam if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) { 36211195Ssam /* 363*11207Ssam * Error bit set, some sort of error in the interface. 36411195Ssam * 365*11207Ssam * The adapter sets attn on command completion so that's not 366*11207Ssam * a real error even though the interface considers it one. 36711195Ssam */ 36811195Ssam #ifdef DEBUG 369*11207Ssam if (hy_nodebug & 4) 370*11207Ssam hy_debug_flag = 1; 37111195Ssam #endif 372*11207Ssam printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n", 373*11207Ssam addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 374*11207Ssam addr->hyd_wcr); 375*11207Ssam if (addr->hyd_csr & S_NEX) { 37611195Ssam printf("hy%d: NEX - Non Existant Memory\n", unit); 37711195Ssam #ifdef PI13 37811195Ssam addr->hyd_csr |= S_NEX; /* as per PI13 manual */ 37911195Ssam #else 38011195Ssam addr->hyd_csr &= ~S_NEX; 38111195Ssam #endif 38211195Ssam hycancel(ui); 38311195Ssam #ifdef PI13 384*11207Ssam } else if (addr->hyd_csr & S_POWEROFF) { 385*11207Ssam printf("hy%d: Power Off bit set, trying to reset\n", 386*11207Ssam unit); 38711195Ssam addr->hyd_csr |= S_POWEROFF; 38811195Ssam DELAY(100); 389*11207Ssam if (addr->hyd_csr & S_POWEROFF) { 39011195Ssam if_down(&is->hy_if); 39111195Ssam is->hy_state = STARTUP; 392*11207Ssam printf( 393*11207Ssam "hy%d: Power Off Error, network shutdown\n", 394*11207Ssam unit); 39511195Ssam } 39611195Ssam #endif 39711195Ssam } else { 39811195Ssam printf("hy%d: BAR overflow\n", unit); 39911195Ssam hycancel(ui); 40011195Ssam } 401*11207Ssam } else if (HYS_NORMAL(addr)) { 40211195Ssam /* 403*11207Ssam * Normal interrupt, bump state machine unless in state 40411195Ssam * waiting and no data present (assumed to be word count 405*11207Ssam * zero interrupt or other hardware botch). 40611195Ssam */ 407*11207Ssam if (is->hy_state != WAITING || HYS_RECVDATA(addr)) 40811195Ssam hyact(ui); 409*11207Ssam } else if (HYS_ABNORMAL(addr)) { 41011195Ssam /* 411*11207Ssam * Abnormal termination. 41211195Ssam * bump error counts, retry the last function 41311195Ssam * 'MAXRETRY' times before kicking the bucket. 41411195Ssam * 415*11207Ssam * Don't reissue the cmd if in certain states, abnormal 416*11207Ssam * on a reissued cmd or max retry exceeded. 41711195Ssam */ 41811195Ssam #ifdef HYLOG 41911195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 42011195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 42111195Ssam goto logit; 42211195Ssam } 42311195Ssam #endif 42411195Ssam #ifdef DEBUG 425*11207Ssam if (hy_nodebug & 4) 426*11207Ssam hy_debug_flag = 1; 42711195Ssam printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n", 42811195Ssam unit, hy_state_names[is->hy_state], is->hy_state); 429*11207Ssam printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n", 430*11207Ssam is->hy_flags, is->hy_ilen, is->hy_olen, 431*11207Ssam is->hy_lastwcr, is->hy_retry); 432*11207Ssam printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n", 433*11207Ssam is->hy_savedstate, is->hy_savedcount, 434*11207Ssam is->hy_savedaddr, is->hy_savedcmd); 43511195Ssam #endif 43611195Ssam #ifdef PI13 43711195Ssam addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */ 43811195Ssam #endif 439*11207Ssam if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT) 44011195Ssam is->hy_if.if_oerrors++; 441*11207Ssam if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT) 44211195Ssam is->hy_if.if_ierrors++; 44311195Ssam if (is->hy_state == XMITDATASENT || 44411195Ssam is->hy_state == RECVSENT || 44511195Ssam is->hy_state == RECVDATASENT || 446*11207Ssam (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY) 44711195Ssam hycancel(ui); 448*11207Ssam else { 44911195Ssam #ifdef DEBUG 450*11207Ssam if (hy_nodebug & 2) 451*11207Ssam hy_debug_flag = 1; 45211195Ssam #endif 45311195Ssam is->hy_retry++; 45411195Ssam is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE; 45511195Ssam is->hy_state = IDLE; 45611195Ssam hyact(ui); 45711195Ssam } 45811195Ssam } else { 45911195Ssam /* 46011195Ssam * Interrupt is neither normal, abnormal, or interface error. 46111195Ssam * Ignore it. It's either stacked or a word count 0. 46211195Ssam */ 46311195Ssam #ifdef HYLOG 46411195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 46511195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 46611195Ssam goto logit; 46711195Ssam } 46811195Ssam #endif 46911195Ssam #ifdef DEBUG 47011195Ssam printD("hy%d: possible stacked interrupt ignored\n", unit); 47111195Ssam #endif 47211195Ssam } 47311195Ssam #ifdef DEBUG 47411195Ssam printD("hy%d: hyint exit\n\n", unit); 47511195Ssam #endif 47611195Ssam hyint_active = 0; 47711195Ssam 478*11207Ssam } 47911195Ssam 48011195Ssam /* 48111195Ssam * Encapsulate a packet of type family for the local net. 48211195Ssam * Use trailer local net encapsulation if enough data in first 48311195Ssam * packet leaves a multiple of 512 bytes of data in remainder. 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 504*11207Ssam if (hy_nodebug & 8) 505*11207Ssam 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 522*11207Ssam printD("hy%d: output to host %x, dhost %x\n", 523*11207Ssam ifp->if_unit, sin->sin_addr.s_addr, dhost); 52411195Ssam #endif 52511195Ssam /* 526*11207Ssam * 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: 561*11207Ssam printf("hy%d: can't handle af%d\n", ifp->if_unit, 562*11207Ssam dst->sa_family); 56311195Ssam #ifdef DEBUG 564*11207Ssam if (hy_nodebug & 4) 565*11207Ssam hy_debug_flag = 1; 56611195Ssam #endif 56711195Ssam error = EAFNOSUPPORT; 56811195Ssam goto drop; 56911195Ssam } 57011195Ssam 57111195Ssam /* 572*11207Ssam * 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) { 579*11207Ssam 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; 59611195Ssam hym->hym_hdr.hyh_from = htons(ifp->if_host[0]); 59711195Ssam hym->hym_hdr.hyh_param = loopback; 59811195Ssam #ifdef HYROUTE 599*11207Ssam 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; 63011195Ssam hym->hym_hdr.hyh_to = htons(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 headerexists: 63911195Ssam if (hym->hym_mplen) { 64011195Ssam hym->hym_hdr.hyh_ctl |= H_ASSOC; 64111195Ssam #ifdef DEBUG 642*11207Ssam if (hy_nodebug & 16) 643*11207Ssam hy_debug_flag = 1; 64411195Ssam #endif 645*11207Ssam } else 646*11207Ssam hym->hym_hdr.hyh_ctl &= ~H_ASSOC; 64711195Ssam #ifdef DEBUG 648*11207Ssam printD("hy%d: output mplen=%x ctl=%x access=%x to=%x", 64911195Ssam ifp->if_unit, hym->hym_mplen, hym->hym_hdr.hyh_ctl, 650*11207Ssam hym->hym_hdr.hyh_access, hym->hym_hdr.hyh_to); 651*11207Ssam printD(" (adapter %x) from=%x param=%x type=%x off=%x\n", 65211195Ssam hym->hym_hdr.hyh_to_adapter, 65311195Ssam hym->hym_hdr.hyh_from, hym->hym_hdr.hyh_param, 65411195Ssam hym->hym_hdr.hyh_type, hym->hym_hdr.hyh_off); 65511195Ssam #endif 65611195Ssam s = splimp(); 65711195Ssam if (IF_QFULL(&ifp->if_snd)) { 65811195Ssam IF_DROP(&ifp->if_snd); 65911195Ssam error = ENOBUFS; 66011195Ssam splx(s); 66111195Ssam goto drop; 66211195Ssam } 66311195Ssam IF_ENQUEUE(&ifp->if_snd, m); 66411195Ssam if (hy_softc[ifp->if_unit].hy_state == WAITING) 66511195Ssam hyact(hyinfo[ifp->if_unit]); 66611195Ssam splx(s); 667*11207Ssam return (0); 66811195Ssam notfound: 669*11207Ssam error = ENETUNREACH; /* XXX */ 67011195Ssam drop: 67111195Ssam m_freem(m); 672*11207Ssam return (error); 673*11207Ssam } 67411195Ssam 67511195Ssam hyact(ui) 67611195Ssam register struct uba_device *ui; 67711195Ssam { 67811195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 67911195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 68011195Ssam 68111195Ssam actloop: 68211195Ssam #ifdef DEBUG 683*11207Ssam printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, 684*11207Ssam hy_state_names[is->hy_state]); 68511195Ssam #endif 68611195Ssam switch (is->hy_state) { 68711195Ssam 68811195Ssam case STARTUP: 68911195Ssam goto endintr; 69011195Ssam 69111195Ssam case IDLE: { 69211195Ssam register rq = is->hy_flags; 69311195Ssam 69411195Ssam if (rq & RQ_STATUS) { 69511195Ssam is->hy_flags &= ~RQ_STATUS; 69611195Ssam is->hy_state = STATSENT; 697*11207Ssam hystart(ui, HYF_STATUS, sizeof (is->hy_status), 698*11207Ssam is->hy_ifuba.ifu_r.ifrw_info); 69911195Ssam } else if (rq & RQ_ENDOP) { 70011195Ssam is->hy_flags &= ~RQ_ENDOP; 70111195Ssam is->hy_state = ENDOPSENT; 70211195Ssam hystart(ui, HYF_END_OP, 0, 0); 70311195Ssam } else if (rq & RQ_STATISTICS) { 70411195Ssam is->hy_flags &= ~RQ_STATISTICS; 70511195Ssam is->hy_state = RSTATSENT; 706*11207Ssam hystart(ui, HYF_RSTATS, sizeof (is->hy_stat), 707*11207Ssam is->hy_ifuba.ifu_r.ifrw_info); 708*11207Ssam } else if (HYS_RECVDATA(addr)) { 70911195Ssam is->hy_state = RECVSENT; 71011195Ssam is->hy_retry = 0; 711*11207Ssam hystart(ui, HYF_INPUTMSG, MPSIZE, 712*11207Ssam is->hy_ifuba.ifu_r.ifrw_info); 71311195Ssam } else if (rq & RQ_REISSUE) { 71411195Ssam is->hy_flags &= ~RQ_REISSUE; 71511195Ssam is->hy_state = is->hy_savedstate; 71611195Ssam #ifdef DEBUG 717*11207Ssam printD("hy%d: reissue cmd=0x%x count=%d", 718*11207Ssam ui->ui_unit, is->hy_savedcmd, is->hy_savedcount); 719*11207Ssam printD(" ubaddr=0x%x retry=%d\n", 720*11207Ssam is->hy_savedaddr, is->hy_retry); 72111195Ssam #endif 722*11207Ssam hystart(ui, is->hy_savedcmd, is->hy_savedcount, 723*11207Ssam is->hy_savedaddr); 72411195Ssam } else { 72511195Ssam register struct mbuf *m; 72611195Ssam 72711195Ssam IF_DEQUEUE(&is->hy_if.if_snd, m); 728*11207Ssam if (m != NULL) { 72911195Ssam register struct hym_hdr *hym; 73011195Ssam register int mplen; 73111195Ssam register int cmd; 73211195Ssam 73311195Ssam is->hy_state = XMITSENT; 73411195Ssam is->hy_retry = 0; 73511195Ssam hym = mtod(m, struct hym_hdr *); 73611195Ssam #ifdef HYLOG 737*11207Ssam hylog(HYL_XMIT, sizeof(struct hym_hdr), 738*11207Ssam (char *)hym); 73911195Ssam #endif 74011195Ssam mplen = hym->hym_mplen; 741*11207Ssam if (hym->hym_hdr.hyh_to_adapter == 742*11207Ssam hym->hym_hdr.hyh_from_adapter) 743*11207Ssam cmd = HYF_XMITLOCMSG; 744*11207Ssam else 745*11207Ssam cmd = HYF_XMITMSG; 74611195Ssam #ifdef DEBUG 74711195Ssam printD("hy%d: hym_hdr = ", ui->ui_unit); 748*11207Ssam if (hy_debug_flag) 749*11207Ssam hyprintdata((char *)hym, 750*11207Ssam sizeof (struct hym_hdr)); 75111195Ssam #endif 75211195Ssam /* 753*11207Ssam * Strip off the software part of 75411195Ssam * the hyperchannel header 75511195Ssam */ 75611195Ssam m->m_off += sizeof(struct hym_data); 75711195Ssam m->m_len -= sizeof(struct hym_data); 75811195Ssam is->hy_olen = if_wubaput(&is->hy_ifuba, m); 75911195Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 760*11207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 761*11207Ssam is->hy_ifuba.ifu_w.ifrw_bdp); 76211195Ssam #ifdef DEBUG 763*11207Ssam printD( 764*11207Ssam "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 76511195Ssam ui->ui_unit, mplen, is->hy_olen); 766*11207Ssam if (hy_debug_flag) 767*11207Ssam hyprintdata( 768*11207Ssam is->hy_ifuba.ifu_w.ifrw_addr, 769*11207Ssam is->hy_olen); 77011195Ssam #endif 771*11207Ssam hystart(ui, cmd, 772*11207Ssam (mplen == 0) ? is->hy_olen : mplen, 773*11207Ssam is->hy_ifuba.ifu_w.ifrw_info); 77411195Ssam if (mplen != 0) 77511195Ssam is->hy_flags |= RQ_XASSOC; 77611195Ssam } else if (rq & RQ_MARKDOWN) { 77711195Ssam is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN); 77811195Ssam is->hy_state = MARKPORT; 77911195Ssam is->hy_retry = 0; 78011195Ssam /* 781*11207Ssam * Port number is taken from status data 78211195Ssam */ 783*11207Ssam hystart(ui, 784*11207Ssam HYF_MARKP0 | (PORTNUM(&is->hy_status) << 2), 785*11207Ssam 0, 0); 78611195Ssam } else if (rq & RQ_MARKUP) { 78711195Ssam register struct ifnet *ifp = &is->hy_if; 788*11207Ssam register struct sockaddr_in *sin = 789*11207Ssam (struct sockaddr_in *)&ifp->if_addr; 79011195Ssam 791*11207Ssam is->hy_flags &= ~RQ_MARKUP; 79211195Ssam is->hy_retry = 0; 79311195Ssam /* 794*11207Ssam * Fill in the Internet address 795*11207Ssam * from the status buffer 79611195Ssam */ 797*11207Ssam printf( 798*11207Ssam "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n", 79911195Ssam ui->ui_unit, 80011195Ssam is->hy_stat.hyc_uaddr, 80111195Ssam PORTNUM(&is->hy_status), 802*11207Ssam (is->hy_stat.hyc_atype[0]<<8) | 803*11207Ssam is->hy_stat.hyc_atype[1], 80411195Ssam is->hy_stat.hyc_atype[2]); 80511195Ssam 806*11207Ssam ifp->if_host[0] = 807*11207Ssam (is->hy_stat.hyc_uaddr << 8) | 808*11207Ssam PORTNUM(&is->hy_status); 80911195Ssam sin->sin_family = AF_INET; 810*11207Ssam sin->sin_addr = 811*11207Ssam if_makeaddr(ifp->if_net, ifp->if_host[0]); 81211195Ssam ifp->if_flags |= IFF_UP; 81311195Ssam if_rtinit(ifp, RTF_UP); 81411195Ssam #ifdef HYLOG 81511195Ssam hylog(HYL_UP, 0, (char *)0); 81611195Ssam #endif 81711195Ssam } else { 81811195Ssam is->hy_state = WAITING; 81911195Ssam is->hy_retry = 0; 82011195Ssam hystart(ui, HYF_WAITFORMSG, 0, 0); 82111195Ssam } 82211195Ssam } 823*11207Ssam break; 82411195Ssam } 82511195Ssam 82611195Ssam case STATSENT: 827*11207Ssam bcopy(is->hy_ifuba.ifu_r.ifrw_addr, &is->hy_status, 828*11207Ssam sizeof (struct hy_status)); 82911195Ssam #ifdef DEBUG 830*11207Ssam printD("hy%d: status - %x %x %x %x %x %x %x %x\n", 831*11207Ssam ui->ui_unit, is->hy_status.hys_gen_status, 832*11207Ssam is->hy_status.hys_last_fcn, 833*11207Ssam is->hy_status.hys_resp_trunk, 834*11207Ssam is->hy_status.hys_status_trunk, 835*11207Ssam is->hy_status.hys_recd_resp, 836*11207Ssam is->hy_status.hys_error, 837*11207Ssam is->hy_status.hys_caddr, 838*11207Ssam is->hy_status.hys_pad); 83911195Ssam #endif 84011195Ssam is->hy_state = IDLE; 84111195Ssam #ifdef HYLOG 842*11207Ssam hylog(HYL_STATUS, sizeof (struct hy_status), 843*11207Ssam (char *)&is->hy_status); 84411195Ssam #endif 84511195Ssam #ifdef HYELOG 84611195Ssam { 84711195Ssam register int i; 84811195Ssam 84911195Ssam i = is->hy_status.hys_error; 85011195Ssam if (i < HYE_MAX) 85111195Ssam i = HYE_MAX; 85211195Ssam switch (is->hy_status.hys_last_fcn) { 85311195Ssam case HYF_XMITLOCMSG: 85411195Ssam i += HYE_MAX+1; /* fall through */ 85511195Ssam case HYF_XMITLSTDATA: 85611195Ssam i += HYE_MAX+1; /* fall through */ 85711195Ssam case HYF_XMITMSG: 85811195Ssam i += HYE_MAX+1; 85911195Ssam } 86011195Ssam hy_elog[i]++; 86111195Ssam } 86211195Ssam #endif 86311195Ssam break; 86411195Ssam 86511195Ssam case RSTATSENT: { 866*11207Ssam register struct hy_stat *p = 867*11207Ssam (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr; 86811195Ssam 86911195Ssam is->hy_stat.hyc_msgcnt = ntohl(p->hyc_msgcnt); 87011195Ssam is->hy_stat.hyc_dbcnt = ntohl(p->hyc_dbcnt); 87111195Ssam is->hy_stat.hyc_tbusy = ntohl(p->hyc_tbusy); 87211195Ssam is->hy_stat.hyc_hwret = ntohl(p->hyc_hwret); 87311195Ssam is->hy_stat.hyc_crcbad = ntohl(p->hyc_crcbad); 87411195Ssam is->hy_stat.hyc_mcret = ntohl(p->hyc_mcret); 87511195Ssam is->hy_stat.hyc_tdabort = ntohl(p->hyc_tdabort); 87611195Ssam is->hy_stat.hyc_atype[0] = p->hyc_atype[0]; 87711195Ssam is->hy_stat.hyc_atype[1] = p->hyc_atype[1]; 87811195Ssam is->hy_stat.hyc_atype[2] = p->hyc_atype[2]; 87911195Ssam is->hy_stat.hyc_uaddr = p->hyc_uaddr; 88011195Ssam #ifdef DEBUG 881*11207Ssam printD( 882*11207Ssam "hy%d: statistics - msgcnt %d dbcnt %d hwret %d tbusy %d crcbad %d\n", 88311195Ssam ui->ui_unit, 88411195Ssam is->hy_stat.hyc_msgcnt, is->hy_stat.hyc_dbcnt, 88511195Ssam is->hy_stat.hyc_tbusy, is->hy_stat.hyc_hwret, 88611195Ssam is->hy_stat.hyc_crcbad); 88711195Ssam printD(" mcret %d tdabort %d atype %x %x %x uaddr %x\n", 88811195Ssam is->hy_stat.hyc_mcret, is->hy_stat.hyc_tdabort, 88911195Ssam is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1], 89011195Ssam is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr); 89111195Ssam #endif 89211195Ssam is->hy_state = IDLE; 89311195Ssam #ifdef HYLOG 894*11207Ssam hylog(HYL_STATISTICS, sizeof (struct hy_stat), 895*11207Ssam (char *)&is->hy_stat); 89611195Ssam #endif 89711195Ssam break; 89811195Ssam } 89911195Ssam 90011195Ssam case CLEARSENT: 90111195Ssam is->hy_state = IDLE; 90211195Ssam break; 90311195Ssam 90411195Ssam case ENDOPSENT: 90511195Ssam is->hy_state = IDLE; 90611195Ssam break; 90711195Ssam 90811195Ssam case RECVSENT: { 909*11207Ssam register struct hy_hdr *hyh; 910*11207Ssam register unsigned len; 91111195Ssam 912*11207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 913*11207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 914*11207Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 915*11207Ssam hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 916*11207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 917*11207Ssam if (len > MPSIZE) { 918*11207Ssam printf("hy%d: RECVD MP > MPSIZE (%d)\n", 919*11207Ssam ui->ui_unit, len); 92011195Ssam #ifdef DEBUG 921*11207Ssam hy_debug_flag = 1; 922*11207Ssam printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 923*11207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, 924*11207Ssam addr->hyd_bar, addr->hyd_wcr); 92511195Ssam #endif 926*11207Ssam } 92711195Ssam #ifdef DEBUG 928*11207Ssam printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len); 929*11207Ssam if (hy_debug_flag) 930*11207Ssam hyprintdata((char *)hyh, len); 93111195Ssam #endif 932*11207Ssam if (hyh->hyh_ctl & H_ASSOC) { 933*11207Ssam is->hy_state = RECVDATASENT; 934*11207Ssam is->hy_ilen = len; 935*11207Ssam is->hy_retry = 0; 936*11207Ssam hystart(ui, HYF_INPUTDATA, 937*11207Ssam HYMTU-len+sizeof (struct hy_hdr), 938*11207Ssam is->hy_ifuba.ifu_r.ifrw_info + len); 939*11207Ssam } else { 940*11207Ssam hyrecvdata(ui, hyh, len); 941*11207Ssam is->hy_state = IDLE; 94211195Ssam } 943*11207Ssam break; 944*11207Ssam } 94511195Ssam 94611195Ssam case RECVDATASENT: { 947*11207Ssam register struct hy_hdr *hyh; 948*11207Ssam register unsigned len; 94911195Ssam 950*11207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 951*11207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 952*11207Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 953*11207Ssam hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 954*11207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 95511195Ssam #ifdef DEBUG 956*11207Ssam printD("hy%d: recvd assoc data, len = %d, data = ", 957*11207Ssam ui->ui_unit, len); 958*11207Ssam if (hy_debug_flag) 959*11207Ssam hyprintdata((char *)hyh + is->hy_ilen, len); 96011195Ssam #endif 961*11207Ssam hyrecvdata(ui, hyh, len + is->hy_ilen); 962*11207Ssam is->hy_state = IDLE; 963*11207Ssam break; 964*11207Ssam } 96511195Ssam 96611195Ssam case XMITSENT: 967*11207Ssam if (is->hy_flags & RQ_XASSOC) { 968*11207Ssam register unsigned len; 96911195Ssam 970*11207Ssam is->hy_flags &= ~RQ_XASSOC; 971*11207Ssam is->hy_state = XMITDATASENT; 972*11207Ssam is->hy_retry = 0; 973*11207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 974*11207Ssam if (len > is->hy_olen) { 975*11207Ssam printf( 976*11207Ssam "hy%d: xmit error - len > hy_olen [%d > %d]\n", 977*11207Ssam ui->ui_unit, len, is->hy_olen); 97811195Ssam #ifdef DEBUG 979*11207Ssam hy_debug_flag = 1; 98011195Ssam #endif 98111195Ssam } 982*11207Ssam hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len, 983*11207Ssam is->hy_ifuba.ifu_w.ifrw_info + len); 984*11207Ssam break; 985*11207Ssam } 986*11207Ssam /* fall through to ... */ 98711195Ssam 98811195Ssam case XMITDATASENT: 989*11207Ssam hyxmitdata(ui); 990*11207Ssam is->hy_state = IDLE; 991*11207Ssam break; 99211195Ssam 99311195Ssam case WAITING: /* wait for message complete or output requested */ 994*11207Ssam if (HYS_RECVDATA(addr)) 99511195Ssam is->hy_state = IDLE; 99611195Ssam else { 99711195Ssam is->hy_state = CLEARSENT; 99811195Ssam is->hy_retry = 0; 99911195Ssam hystart(ui, HYF_CLRWFMSG, 0, 0); 100011195Ssam } 100111195Ssam break; 100211195Ssam 100311195Ssam case MARKPORT: 100411195Ssam is->hy_state = STARTUP; 100511195Ssam is->hy_if.if_flags &= ~IFF_UP; 100611195Ssam goto endintr; 100711195Ssam 100811195Ssam default: 1009*11207Ssam printf("hy%d: DRIVER BUG - INVALID STATE %d\n", 1010*11207Ssam ui->ui_unit, is->hy_state); 101111195Ssam panic("HYPERCHANNEL IN INVALID STATE"); 101211195Ssam /*NOTREACHED*/ 1013*11207Ssam } 101411195Ssam if (is->hy_state == IDLE) 101511195Ssam goto actloop; 101611195Ssam endintr: 101711195Ssam #ifdef DEBUG 1018*11207Ssam printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, 1019*11207Ssam hy_state_names[is->hy_state]); 102011195Ssam #endif 1021*11207Ssam return (0); 1022*11207Ssam } 102311195Ssam 102411195Ssam /* 102511195Ssam * Called from device interrupt when recieving data. 102611195Ssam * Examine packet to determine type. Decapsulate packet 102711195Ssam * based on type and pass to type specific higher-level 102811195Ssam * input routine. 102911195Ssam */ 103011195Ssam hyrecvdata(ui, hyh0, len) 103111195Ssam struct uba_device *ui; 103211195Ssam struct hy_hdr *hyh0; 103311195Ssam int len; 103411195Ssam { 103511195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 103611195Ssam register struct hy_hdr *hyh = hyh0; 103711195Ssam struct mbuf *m; 103811195Ssam register struct ifqueue *inq; 103911195Ssam 104011195Ssam is->hy_if.if_ipackets++; 104111195Ssam #ifdef DEBUG 1042*11207Ssam printD("hy%d: recieved packet, len = %d (actual %d)\n", 1043*11207Ssam ui->ui_unit, len, 1044*11207Ssam len - (hyh->hyh_off + sizeof (struct hy_hdr))); 104511195Ssam #endif 104611195Ssam #ifdef HYLOG 104711195Ssam { 104811195Ssam struct { 104911195Ssam short hlen; 105011195Ssam struct hy_hdr hhdr; 105111195Ssam } hh; 105211195Ssam hh.hlen = len; 105311195Ssam hh.hhdr = *hyh; 105411195Ssam hylog(HYL_RECV, sizeof(hh), (char *)&hh); 105511195Ssam } 105611195Ssam #endif 105711195Ssam if (len > HYMTU + MPSIZE || len == 0) 105811195Ssam return; /* sanity */ 105911195Ssam /* 106011195Ssam * Pull packet off interface. 106111195Ssam */ 106211195Ssam m = if_rubaget(&is->hy_ifuba, len, 0); 1063*11207Ssam if (m == NULL) 106411195Ssam return; 106511195Ssam switch (hyh->hyh_type) { 106611195Ssam 106711195Ssam #ifdef INET 106811195Ssam case HYLINK_IP: 106911195Ssam /* 1070*11207Ssam * Strip the variable portion of the hyperchannel header 1071*11207Ssam * (fixed portion stripped in if_rubaget). 107211195Ssam */ 107311195Ssam m->m_len -= hyh->hyh_off; 107411195Ssam m->m_off += hyh->hyh_off; 107511195Ssam schednetisr(NETISR_IP); 107611195Ssam inq = &ipintrq; 107711195Ssam break; 107811195Ssam #endif 107911195Ssam default: 108011195Ssam m_freem(m); 108111195Ssam return; 108211195Ssam } 108311195Ssam if (IF_QFULL(inq)) { 108411195Ssam IF_DROP(inq); 108511195Ssam m_freem(m); 108611195Ssam } else 108711195Ssam IF_ENQUEUE(inq, m); 1088*11207Ssam } 108911195Ssam 109011195Ssam /* 1091*11207Ssam * Transmit done, release resources, bump counters. 109211195Ssam */ 109311195Ssam hyxmitdata(ui) 109411195Ssam struct uba_device *ui; 109511195Ssam { 109611195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 109711195Ssam 109811195Ssam is->hy_if.if_opackets++; 1099*11207Ssam if (is->hy_ifuba.ifu_xtofree) { 110011195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 110111195Ssam is->hy_ifuba.ifu_xtofree = 0; 110211195Ssam } 1103*11207Ssam } 110411195Ssam 110511195Ssam hycancel(ui) 110611195Ssam register struct uba_device *ui; 110711195Ssam { 110811195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 110911195Ssam 1110*11207Ssam if (is->hy_ifuba.ifu_xtofree) { 111111195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 111211195Ssam is->hy_ifuba.ifu_xtofree = 0; 111311195Ssam } 111411195Ssam #ifdef DEBUG 1115*11207Ssam if (hy_nodebug & 1) 1116*11207Ssam hy_debug_flag = 1; 111711195Ssam #endif 111811195Ssam #ifdef DEBUG 111911195Ssam printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n", 112011195Ssam ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd, 112111195Ssam is->hy_savedcount, is->hy_savedaddr); 1122*11207Ssam printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n", 1123*11207Ssam is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr, 1124*11207Ssam is->hy_retry); 1125*11207Ssam printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n", 1126*11207Ssam is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, 1127*11207Ssam is->hy_savedcmd); 112811195Ssam #endif 112911195Ssam is->hy_state = IDLE; 113011195Ssam is->hy_flags |= (RQ_ENDOP | RQ_STATUS); 113111195Ssam hyact(ui); 1132*11207Ssam } 113311195Ssam 113411195Ssam #ifdef DEBUG 113511195Ssam hyprintdata(cp, len) 113611195Ssam register char *cp; 113711195Ssam register int len; 113811195Ssam { 113911195Ssam register int count = 16; 114011195Ssam register char *fmt; 114111195Ssam static char regfmt[] = "\n\t %x"; 114211195Ssam 114311195Ssam fmt = ®fmt[2]; 114411195Ssam while (--len >= 0) { 114511195Ssam printL(fmt, *cp++ & 0xff); 114611195Ssam fmt = ®fmt[2]; 114711195Ssam if (--count <= 0) { 114811195Ssam fmt = ®fmt[0]; 114911195Ssam count = 16; 115011195Ssam } 115111195Ssam } 115211195Ssam printL("\n"); 115311195Ssam } 115411195Ssam #endif 115511195Ssam 115611195Ssam hywatch(unit) 115711195Ssam int unit; 115811195Ssam { 115911195Ssam register struct hy_softc *is = &hy_softc[unit]; 116011195Ssam register struct uba_device *ui = hyinfo[unit]; 116111195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 116211195Ssam int s; 116311195Ssam 116411195Ssam s = splimp(); 116511195Ssam is->hy_if.if_timer = SCANINTERVAL; 1166*11207Ssam if (is->hy_ntime > 2 && is->hy_state != WAITING && 1167*11207Ssam is->hy_state != STARTUP && is->hy_state != IDLE) { 116811195Ssam printf("hy%d: watchdog timer expired\n", unit); 116911195Ssam hycancel(ui); 117011195Ssam } 117111195Ssam #ifdef PI13 117211195Ssam if ((addr->hyd_csr & S_POWEROFF) != 0) { 117311195Ssam addr->hyd_csr |= S_POWEROFF; 117411195Ssam DELAY(100); 117511195Ssam if ((addr->hyd_csr & S_POWEROFF) == 0) { 117611195Ssam printf("hy%d: adapter power restored\n", unit); 117711195Ssam is->hy_state = IDLE; 1178*11207Ssam is->hy_flags |= 1179*11207Ssam (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS); 118011195Ssam hyact(ui); 118111195Ssam } 118211195Ssam } 118311195Ssam #endif 118411195Ssam splx(s); 118511195Ssam } 118611195Ssam 118711195Ssam #ifdef HYLOG 118811195Ssam hylog(code, len, ptr) 118911195Ssam int code; 119011195Ssam int len; 119111195Ssam char *ptr; 119211195Ssam { 119311195Ssam register unsigned char *p; 119411195Ssam int s; 119511195Ssam 119611195Ssam s = splimp(); 119711195Ssam if (hy_log.hyl_self != &hy_log) { 119811195Ssam hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 119911195Ssam hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 120011195Ssam hy_log.hyl_self = &hy_log; 120111195Ssam hy_log.hyl_enable = HYL_DISABLED; 120211195Ssam hy_log.hyl_onerr = HYL_CATCH1; 120311195Ssam } 1204*11207Ssam if (hy_log.hyl_enable == HYL_DISABLED || 1205*11207Ssam hy_log.hyl_enable == HYL_CAUGHT1 || 1206*11207Ssam hy_log.hyl_enable == HYL_CAUGHTSTATUS || 1207*11207Ssam (hy_log.hyl_enable == HYL_CATCHSTATUS && code != HYL_STATUS)) 1208*11207Ssam goto out; 120911195Ssam p = hy_log.hyl_ptr; 121011195Ssam if (p + len + 2 >= hy_log.hyl_eptr) { 121111195Ssam bzero(p, hy_log.hyl_eptr - p); 121211195Ssam p = &hy_log.hyl_buf[0]; 121311195Ssam if (hy_log.hyl_enable == HYL_CATCH1) { 121411195Ssam hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHT1; 121511195Ssam goto out; 121611195Ssam } 121711195Ssam if (hy_log.hyl_enable == HYL_CATCHSTATUS) { 121811195Ssam hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHTSTATUS; 121911195Ssam goto out; 122011195Ssam } 122111195Ssam } 122211195Ssam *p++ = code; 122311195Ssam *p++ = len; 122411195Ssam bcopy(ptr, p, len); 122511195Ssam hy_log.hyl_ptr = p + len; 122611195Ssam out: 122711195Ssam splx(s); 122811195Ssam } 122911195Ssam #endif 123011195Ssam 1231*11207Ssam hyioctl(dev, cmd, data, flag) 1232*11207Ssam dev_t dev; 1233*11207Ssam int cmd; 1234*11207Ssam caddr_t data; 1235*11207Ssam int flag; 123611195Ssam { 1237*11207Ssam int s = splimp(), error = 0; 123811195Ssam 123911195Ssam if (minor(dev) >= NHY) { 1240*11207Ssam error = ENXIO; 1241*11207Ssam goto bad; 124211195Ssam } 124311195Ssam switch(cmd) { 124411195Ssam 124511195Ssam case HYSETROUTE: 1246*11207Ssam if (!suser()) { 1247*11207Ssam error = EPERM; 1248*11207Ssam goto bad; 124911195Ssam } 1250*11207Ssam hy_route[minor(dev)] = *(struct hyroute *)data; 1251*11207Ssam hy_route[minor(dev)].hyr_lasttime = time; 125211195Ssam break; 125311195Ssam 125411195Ssam case HYGETROUTE: 1255*11207Ssam *(struct hyroute *)data = hy_route[minor(dev)]; 125611195Ssam break; 125711195Ssam 125811195Ssam default: 1259*11207Ssam error = ENXIO; 126011195Ssam break; 126111195Ssam } 1262*11207Ssam bad: 126311195Ssam splx(s); 1264*11207Ssam return (error); 126511195Ssam } 1266*11207Ssam #endif 1267