1*13065Ssam /* if_hy.c 4.7 83/06/13 */ 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" 2411195Ssam #include "../net/if.h" 2511207Ssam #include "../net/netisr.h" 2611195Ssam #include "../net/route.h" 2711195Ssam #include "../netinet/in.h" 2811195Ssam #include "../netinet/in_systm.h" 2911195Ssam #include "../netinet/ip.h" 3011195Ssam #include "../netinet/ip_var.h" 3111195Ssam 3211207Ssam #include "../vax/cpu.h" 3311207Ssam #include "../vax/mtpr.h" 3411207Ssam #include "../vaxuba/ubareg.h" 3511207Ssam #include "../vaxuba/ubavar.h" 3611195Ssam #include "../vaxif/if_hy.h" 3711198Ssam #include "../vaxif/if_hyreg.h" 3811195Ssam #include "../vaxif/if_uba.h" 3911195Ssam 4011195Ssam #define HYROUTE 4111195Ssam #define HYELOG 4211195Ssam #define HYMTU 576 4311195Ssam 4413058Ssam int hyprobe(), hyattach(), hyinit(), hyioctl(); 4513058Ssam int hyoutput(), hyreset(), hywatch(); 4611195Ssam struct uba_device *hyinfo[NHY]; 4711195Ssam u_short hystd[] = { 0772410, 0 }; 4811195Ssam struct uba_driver hydriver = 4911195Ssam { hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo }; 5011195Ssam 5111195Ssam /* 5211195Ssam * Hyperchannel software status per interface. 5311195Ssam * 5411195Ssam * Each interface is referenced by a network interface structure, 5511195Ssam * hy_if, which the routing code uses to locate the interface. 5611195Ssam * This structure contains the output queue for the interface, its address, ... 5711195Ssam * We also have, for each interface, a UBA interface structure, which 5811195Ssam * contains information about the UNIBUS resources held by the interface: 5911195Ssam * map registers, buffered data paths, etc. Information is cached in this 6011195Ssam * structure for use by the if_uba.c routines in running the interface 6111195Ssam * efficiently. 6211195Ssam */ 6311195Ssam struct hy_softc { 6411195Ssam struct ifnet hy_if; /* network-visible interface */ 6511195Ssam struct ifuba hy_ifuba; /* UNIBUS resources */ 6611207Ssam short hy_flags; /* flags */ 6711207Ssam short hy_state; /* driver state */ 6811195Ssam int hy_ilen; /* mp length on input */ 6911195Ssam int hy_olen; /* packet length on output */ 7011195Ssam int hy_lastwcr; /* last command's word count */ 7111195Ssam short hy_savedstate; /* saved for reissue after status */ 7211195Ssam short hy_savedcmd; /* saved command for reissue */ 7311195Ssam int hy_savedcount; /* saved byte count for reissue */ 7411195Ssam int hy_savedaddr; /* saved unibus address for reissue */ 7511195Ssam int hy_ntime; /* number of timeouts since last cmd */ 7611195Ssam int hy_retry; /* retry counter */ 7711207Ssam struct hy_stat hy_stat; /* statistics */ 7811207Ssam struct hy_status hy_status; /* status */ 7911195Ssam } hy_softc[NHY]; 8011195Ssam 8111195Ssam #ifdef HYELOG 8211207Ssam #define HYE_MAX 0x18 8311207Ssam u_long hy_elog[(HYE_MAX+1)*4]; 8411195Ssam #endif 8511195Ssam 8611195Ssam #ifdef DEBUG 8711195Ssam #define printL lprintf 8811195Ssam #define printD if (hy_debug_flag) lprintf 8911195Ssam int hy_debug_flag = 0; 9011195Ssam /* 9111195Ssam * hy_nodebug bit 0x01 set hy_debug_flag on hycancel 9211195Ssam * hy_nodebug bit 0x02 set hy_debug_flag on command reissue 9311195Ssam * hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt 9411195Ssam * hy_nodebug bit 0x08 set hy_debug_flag on hyouput 9511195Ssam * hy_nodebug bit 0x10 set hy_debug_flag on hyouput with associated data 9611195Ssam */ 9711195Ssam int hy_nodebug = 0x0; 9811195Ssam #else 9911195Ssam #define printD hyvoid 10011195Ssam #endif 10111195Ssam 10211195Ssam /* 10311207Ssam * Requests for service (in order by descending priority). 10411195Ssam */ 10511195Ssam #define RQ_ENDOP 001 /* end the last adapter function */ 10611195Ssam #define RQ_REISSUE 002 /* reissue previous cmd after status */ 10711195Ssam #define RQ_STATUS 004 /* get the status of the adapter */ 10811195Ssam #define RQ_STATISTICS 010 /* get the statistics of the adapter */ 10911195Ssam #define RQ_MARKDOWN 020 /* mark this adapter port down */ 11011195Ssam #define RQ_MARKUP 040 /* mark this interface up */ 11111195Ssam 11211195Ssam #define RQ_XASSOC 0100 /* associated data to transmit */ 11311195Ssam 11411195Ssam /* 11511207Ssam * Driver states. 11611195Ssam */ 11711195Ssam #define STARTUP 0 /* initial state (before fully there) */ 11811195Ssam #define IDLE 1 /* idle state */ 11911195Ssam #define STATSENT 2 /* status cmd sent to adapter */ 12011195Ssam #define ENDOPSENT 3 /* end operation cmd sent */ 12111195Ssam #define RECVSENT 4 /* input message cmd sent */ 12211195Ssam #define RECVDATASENT 5 /* input data cmd sent */ 12311195Ssam #define XMITSENT 6 /* transmit message cmd sent */ 12411195Ssam #define XMITDATASENT 7 /* transmit data cmd sent */ 12511195Ssam #define WAITING 8 /* waiting for messages */ 12611195Ssam #define CLEARSENT 9 /* clear wait for message cmd sent */ 12711195Ssam #define MARKPORT 10 /* mark this host's adapter port down issued */ 12811195Ssam #define RSTATSENT 11 /* read statistics cmd sent to adapter */ 12911195Ssam 13011195Ssam #ifdef DEBUG 13111195Ssam char *hy_state_names[] = { 13211195Ssam "Startup", 13311195Ssam "Idle", 13411195Ssam "Status Sent", 13511195Ssam "End op Sent", 13611195Ssam "Recieve Message Proper Sent", 13711195Ssam "Recieve Data Sent", 13811195Ssam "Transmit Message Proper Sent", 13911195Ssam "Transmit Data Sent", 14011195Ssam "Wait for Message Sent", 14111195Ssam "Clear Wait for Message Sent", 14211195Ssam "Mark Port Down Sent", 14311195Ssam "Read Statistics Sent" 14411195Ssam }; 14511195Ssam #endif 14611195Ssam 14711195Ssam #define SCANINTERVAL 10 /* seconds */ 14811195Ssam #define MAXINTERVAL 20 /* seconds (max action) */ 14911195Ssam 15011195Ssam /* 15111195Ssam * Cause a device interrupt. This code uses a buffer starting at 15211195Ssam * location zero on the unibus (which is already mapped by the 15311195Ssam * autoconfigure code in the kernel). 15411195Ssam */ 15511195Ssam hyprobe(reg) 15611195Ssam caddr_t reg; 15711195Ssam { 15811195Ssam register int br, cvec; /* r11, r10 value-result */ 15911195Ssam register struct hydevice *addr = (struct hydevice *) reg; 16011195Ssam 16111195Ssam #ifdef lint 16211195Ssam br = 0; cvec = br; br = cvec; 16311195Ssam hyint(0); 16411195Ssam #endif 16511195Ssam /* 16611195Ssam * request adapter status to a buffer starting at unibus location 0 16711195Ssam */ 16811195Ssam addr->hyd_bar = 0; 16911195Ssam addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1); 17011195Ssam addr->hyd_dbuf = HYF_STATUS; 17111195Ssam #ifdef PI13 17211195Ssam addr->hyd_csr |= S_GO | S_IE | S_IATTN; 17311195Ssam #else 17411195Ssam addr->hyd_csr |= S_GO | S_IE; 17511195Ssam #endif 17611195Ssam DELAY(10000); 17711195Ssam #ifdef PI13 17811195Ssam addr->hyd_csr |= S_CLRINT; /* clear any stacked interrupts */ 17911195Ssam #endif 18011195Ssam addr->hyd_csr &= ~(S_IE | S_CLRINT); /* disable further interrupts */ 18111195Ssam return(1); 18211207Ssam } 18311195Ssam 18411195Ssam /* 18511195Ssam * Interface exists: make available by filling in network interface 18611195Ssam * record. System will initialize the interface when it is ready 18711195Ssam * to accept packets. 18811195Ssam */ 18911195Ssam hyattach(ui) 19011195Ssam struct uba_device *ui; 19111195Ssam { 19211195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 19311195Ssam register struct ifnet *ifp = &is->hy_if; 19411195Ssam 19511195Ssam ifp->if_unit = ui->ui_unit; 19611195Ssam ifp->if_name = "hy"; 19711195Ssam ifp->if_mtu = HYMTU; 19811195Ssam is->hy_state = STARTUP; /* don't allow state transitions yet */ 19911195Ssam ifp->if_init = hyinit; 20013058Ssam ifp->if_ioctl = hyioctl; 20111195Ssam ifp->if_output = hyoutput; 20211207Ssam ifp->if_reset = hyreset; 20311195Ssam ifp->if_watchdog = hywatch; 20411195Ssam ifp->if_timer = SCANINTERVAL; 20511195Ssam is->hy_ifuba.ifu_flags = UBA_CANTWAIT; 20611207Ssam #ifdef notdef 20711195Ssam is->hy_ifuba.ifu_flags |= UBA_NEEDBDP; 20811195Ssam #endif 20911195Ssam if_attach(ifp); 21011207Ssam } 21111195Ssam 21211195Ssam /* 21311195Ssam * Reset of interface after UNIBUS reset. 21411195Ssam * If interface is on specified uba, reset its state. 21511195Ssam */ 21611195Ssam hyreset(unit, uban) 21711195Ssam int unit, uban; 21811195Ssam { 21911195Ssam register struct uba_device *ui = hyinfo[unit]; 22011195Ssam 22111207Ssam if (unit >= NHY || ui == 0 || ui->ui_alive == 0 || 22211207Ssam ui->ui_ubanum != uban) 22311195Ssam return; 22411195Ssam printf(" hy%d", unit); 22511195Ssam hyinit(unit); 22611207Ssam } 22711195Ssam 22811195Ssam /* 22911195Ssam * Initialization of interface; clear recorded pending 23011195Ssam * operations, and reinitialize UNIBUS usage. 23111195Ssam */ 23211195Ssam hyinit(unit) 23311195Ssam int unit; 23411195Ssam { 23511195Ssam register struct hy_softc *is = &hy_softc[unit]; 23611195Ssam register struct uba_device *ui = hyinfo[unit]; 237*13065Ssam struct sockaddr_in *sin; 23811195Ssam int s; 23911195Ssam 240*13065Ssam sin = (struct sockaddr_in *)&is->is_if.if_addr; 241*13065Ssam if (in_netof(sin->sin_addr) == 0) 242*13065Ssam return; 24311195Ssam if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum, 24411195Ssam sizeof (struct hy_hdr), (int)btoc(HYMTU)) == 0) { 24511195Ssam #ifdef DEBUG 24611207Ssam if (hy_nodebug & 4) 24711207Ssam 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 } 25313059Ssam is->is_hy.if_flags |= IFF_RUNNING; 25411195Ssam /* 25511207Ssam * Issue wait for message and start the state machine 25611195Ssam */ 25711195Ssam s = splimp(); 25811195Ssam is->hy_state = IDLE; 25911195Ssam is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP; 26011195Ssam is->hy_retry = 0; 26111195Ssam hyact(ui); 26211195Ssam splx(s); 26311207Ssam } 26411195Ssam 26511195Ssam /* 26611207Ssam * Issue a command to the adapter 26711195Ssam */ 26811195Ssam hystart(ui, cmd, count, ubaddr) 26911195Ssam struct uba_device *ui; 27011207Ssam int cmd, count, ubaddr; 27111195Ssam { 27211195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 27311195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 27411195Ssam 27511195Ssam #ifdef DEBUG 27611207Ssam printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n", 27711207Ssam ui->ui_unit, cmd, count, ubaddr); 27811195Ssam printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 27911207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 28011207Ssam addr->hyd_wcr); 28111195Ssam #endif 28211207Ssam if (((is->hy_flags & RQ_REISSUE) == 0) && 28311207Ssam (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) { 28411195Ssam is->hy_savedstate = is->hy_state; 28511195Ssam is->hy_savedcmd = cmd; 28611195Ssam is->hy_savedcount = count; 28711195Ssam is->hy_savedaddr = ubaddr; 28811195Ssam } 28911195Ssam addr->hyd_bar = ubaddr & 0xffff; 29011207Ssam addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1); 29111195Ssam addr->hyd_dbuf = cmd; 29211195Ssam #ifdef PI13 29311195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN; 29411195Ssam #else 29511195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE; 29611195Ssam #endif 29711195Ssam #ifdef DEBUG 29811195Ssam printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 29911207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 30011207Ssam addr->hyd_wcr); 30111195Ssam #endif 30211195Ssam #ifdef HYLOG 30311195Ssam { 30411195Ssam struct { 30511207Ssam u_char hcmd; 30611207Ssam u_char hstate; 30711207Ssam short hcount; 30811195Ssam } hcl; 30911195Ssam 31011195Ssam hcl.hcmd = cmd; 31111195Ssam hcl.hstate = is->hy_state; 31211195Ssam hcl.hcount = count; 31311195Ssam hylog(HYL_CMD, sizeof(hcl), (char *)&hcl); 31411195Ssam } 31511195Ssam #endif 31611195Ssam is->hy_ntime = 0; 31711207Ssam } 31811195Ssam 31911195Ssam int hyint_active = 0; /* set during hy interrupt */ 32011195Ssam /* 32111207Ssam * Hyperchannel interface interrupt. 32211195Ssam * 32311195Ssam * An interrupt can occur for many reasons. Examine the status of 32411195Ssam * the hyperchannel status bits to determine what to do next. 32511195Ssam * 32611195Ssam * If input error just drop packet. 32711195Ssam * Otherwise purge input buffered data path and examine 32811195Ssam * packet to determine type. Othewise decapsulate 32911195Ssam * packet based on type and pass to type specific higher-level 33011195Ssam * input routine. 33111195Ssam */ 33211195Ssam hyint(unit) 33311195Ssam int unit; 33411195Ssam { 33511195Ssam register struct hy_softc *is = &hy_softc[unit]; 33611195Ssam register struct uba_device *ui = hyinfo[unit]; 33711207Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 33811195Ssam 33911207Ssam if (hyint_active) 34011195Ssam panic("RECURSIVE HYPERCHANNEL INTERRUPT"); 34111195Ssam hyint_active++; 34211195Ssam #ifdef DEBUG 34311195Ssam printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 34411195Ssam unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 34511195Ssam #endif 34611195Ssam #ifdef HYLOG 34711195Ssam logit: 34811195Ssam { 34911195Ssam struct { 35011207Ssam u_char hstate; 35111207Ssam u_char hflags; 35211207Ssam short hcsr; 35311207Ssam short hwcr; 35411195Ssam } hil; 35511195Ssam hil.hstate = is->hy_state; 35611195Ssam hil.hflags = is->hy_flags; 35711195Ssam hil.hcsr = addr->hyd_csr; 35811195Ssam hil.hwcr = addr->hyd_wcr; 35911195Ssam hylog(HYL_INT, sizeof(hil), (char *)&hil); 36011195Ssam } 36111195Ssam #endif 36211207Ssam if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) { 36311195Ssam /* 36411207Ssam * Error bit set, some sort of error in the interface. 36511195Ssam * 36611207Ssam * The adapter sets attn on command completion so that's not 36711207Ssam * a real error even though the interface considers it one. 36811195Ssam */ 36911195Ssam #ifdef DEBUG 37011207Ssam if (hy_nodebug & 4) 37111207Ssam hy_debug_flag = 1; 37211195Ssam #endif 37311207Ssam printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n", 37411207Ssam addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, 37511207Ssam addr->hyd_wcr); 37611207Ssam if (addr->hyd_csr & S_NEX) { 37711195Ssam printf("hy%d: NEX - Non Existant Memory\n", unit); 37811195Ssam #ifdef PI13 37911195Ssam addr->hyd_csr |= S_NEX; /* as per PI13 manual */ 38011195Ssam #else 38111195Ssam addr->hyd_csr &= ~S_NEX; 38211195Ssam #endif 38311195Ssam hycancel(ui); 38411195Ssam #ifdef PI13 38511207Ssam } else if (addr->hyd_csr & S_POWEROFF) { 38611207Ssam printf("hy%d: Power Off bit set, trying to reset\n", 38711207Ssam unit); 38811195Ssam addr->hyd_csr |= S_POWEROFF; 38911195Ssam DELAY(100); 39011207Ssam if (addr->hyd_csr & S_POWEROFF) { 39111195Ssam if_down(&is->hy_if); 39211195Ssam is->hy_state = STARTUP; 39311207Ssam printf( 39411207Ssam "hy%d: Power Off Error, network shutdown\n", 39511207Ssam unit); 39611195Ssam } 39711195Ssam #endif 39811195Ssam } else { 39911195Ssam printf("hy%d: BAR overflow\n", unit); 40011195Ssam hycancel(ui); 40111195Ssam } 40211207Ssam } else if (HYS_NORMAL(addr)) { 40311195Ssam /* 40411207Ssam * Normal interrupt, bump state machine unless in state 40511195Ssam * waiting and no data present (assumed to be word count 40611207Ssam * zero interrupt or other hardware botch). 40711195Ssam */ 40811207Ssam if (is->hy_state != WAITING || HYS_RECVDATA(addr)) 40911195Ssam hyact(ui); 41011207Ssam } else if (HYS_ABNORMAL(addr)) { 41111195Ssam /* 41211207Ssam * Abnormal termination. 41311195Ssam * bump error counts, retry the last function 41411195Ssam * 'MAXRETRY' times before kicking the bucket. 41511195Ssam * 41611207Ssam * Don't reissue the cmd if in certain states, abnormal 41711207Ssam * on a reissued cmd or max retry exceeded. 41811195Ssam */ 41911195Ssam #ifdef HYLOG 42011195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 42111195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 42211195Ssam goto logit; 42311195Ssam } 42411195Ssam #endif 42511195Ssam #ifdef DEBUG 42611207Ssam if (hy_nodebug & 4) 42711207Ssam hy_debug_flag = 1; 42811195Ssam printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n", 42911195Ssam unit, hy_state_names[is->hy_state], is->hy_state); 43011207Ssam printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n", 43111207Ssam is->hy_flags, is->hy_ilen, is->hy_olen, 43211207Ssam is->hy_lastwcr, is->hy_retry); 43311207Ssam printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n", 43411207Ssam is->hy_savedstate, is->hy_savedcount, 43511207Ssam is->hy_savedaddr, is->hy_savedcmd); 43611195Ssam #endif 43711195Ssam #ifdef PI13 43811195Ssam addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */ 43911195Ssam #endif 44011207Ssam if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT) 44111195Ssam is->hy_if.if_oerrors++; 44211207Ssam if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT) 44311195Ssam is->hy_if.if_ierrors++; 44411195Ssam if (is->hy_state == XMITDATASENT || 44511195Ssam is->hy_state == RECVSENT || 44611195Ssam is->hy_state == RECVDATASENT || 44711207Ssam (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY) 44811195Ssam hycancel(ui); 44911207Ssam else { 45011195Ssam #ifdef DEBUG 45111207Ssam if (hy_nodebug & 2) 45211207Ssam hy_debug_flag = 1; 45311195Ssam #endif 45411195Ssam is->hy_retry++; 45511195Ssam is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE; 45611195Ssam is->hy_state = IDLE; 45711195Ssam hyact(ui); 45811195Ssam } 45911195Ssam } else { 46011195Ssam /* 46111195Ssam * Interrupt is neither normal, abnormal, or interface error. 46211195Ssam * Ignore it. It's either stacked or a word count 0. 46311195Ssam */ 46411195Ssam #ifdef HYLOG 46511195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 46611195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 46711195Ssam goto logit; 46811195Ssam } 46911195Ssam #endif 47011195Ssam #ifdef DEBUG 47111195Ssam printD("hy%d: possible stacked interrupt ignored\n", unit); 47211195Ssam #endif 47311195Ssam } 47411195Ssam #ifdef DEBUG 47511195Ssam printD("hy%d: hyint exit\n\n", unit); 47611195Ssam #endif 47711195Ssam hyint_active = 0; 47811195Ssam 47911207Ssam } 48011195Ssam 48111195Ssam /* 48211195Ssam * Encapsulate a packet of type family for the local net. 48311195Ssam * Use trailer local net encapsulation if enough data in first 48411195Ssam * packet leaves a multiple of 512 bytes of data in remainder. 48511195Ssam */ 48611195Ssam hyoutput(ifp, m0, dst) 48711195Ssam struct ifnet *ifp; 48811195Ssam struct mbuf *m0; 48911195Ssam struct sockaddr *dst; 49011195Ssam { 49111195Ssam register struct hym_hdr *hym; 49211195Ssam register struct mbuf *m; 49311195Ssam #ifdef HYROUTE 49411195Ssam register struct hyroute *r = &hy_route[ifp->if_unit]; 49511195Ssam #endif 49611195Ssam short dtype; /* packet type */ 49711195Ssam int dhost; /* destination adapter address */ 49811195Ssam int dlen; 49911195Ssam int mplen = 0; /* message proper length */ 50011195Ssam short loopback = 0; /* hardware loopback requested */ 50111195Ssam int error = 0; 50211195Ssam int s; 50311195Ssam 50411195Ssam #ifdef DEBUG 50511207Ssam if (hy_nodebug & 8) 50611207Ssam hy_debug_flag = 1; 50711195Ssam #endif 50811195Ssam dlen = 0; 50911195Ssam for (m = m0; m; m = m->m_next) 51011195Ssam dlen += m->m_len; 51111195Ssam m = m0; 51211195Ssam switch(dst->sa_family) { 51311195Ssam 51411195Ssam #ifdef INET 51511195Ssam case AF_INET: { 51611195Ssam register struct ip *ip = mtod(m, struct ip *); 51711195Ssam register struct sockaddr_in *sin = (struct sockaddr_in *)dst; 51811195Ssam register long hostaddr = in_lnaof(sin->sin_addr); 51911195Ssam 52011195Ssam dhost = hostaddr & 0xffff; 52111195Ssam dtype = HYLINK_IP; 52211195Ssam #ifdef DEBUG 52311207Ssam printD("hy%d: output to host %x, dhost %x\n", 52411207Ssam ifp->if_unit, sin->sin_addr.s_addr, dhost); 52511195Ssam #endif 52611195Ssam /* 52711207Ssam * Debugging loopback support: 52811195Ssam * upper byte of 24 bit host number interpreted as follows 52911195Ssam * 0x00 --> no loopback 53011195Ssam * 0x01 --> hardware loop through remote adapter 53111195Ssam * other --> software loop through remote ip layer 53211195Ssam */ 53311195Ssam if (hostaddr & 0xff0000) { 53411195Ssam struct in_addr temp; 53511195Ssam 53611195Ssam temp = ip->ip_dst; 53711195Ssam ip->ip_dst = ip->ip_src; 53811195Ssam ip->ip_src = temp; 53911195Ssam if ((hostaddr & 0xff0000) == 0x10000) 54011195Ssam loopback = H_LOOPBK; 54111195Ssam } 54211195Ssam /* 54311195Ssam * If entire packet won't fit in message proper, just 54411195Ssam * send hyperchannel hardware header and ip header in 54511195Ssam * message proper. If that won't fit either, just send 54611195Ssam * the maximum message proper. 54711195Ssam * 54811195Ssam * This insures that the associated data is at least a 54911195Ssam * TCP/UDP header in length and thus prevents potential 55011195Ssam * problems with very short word counts. 55111195Ssam */ 55211195Ssam if (dlen > MPSIZE - sizeof (struct hy_hdr)) { 55311195Ssam mplen = sizeof(struct hy_hdr) + (ip->ip_hl << 2); 55411195Ssam if (mplen > MPSIZE) 55511195Ssam mplen = MPSIZE; 55611195Ssam } 55711195Ssam break; 55811195Ssam } 55911195Ssam #endif 56011195Ssam 56111195Ssam default: 56211207Ssam printf("hy%d: can't handle af%d\n", ifp->if_unit, 56311207Ssam dst->sa_family); 56411195Ssam #ifdef DEBUG 56511207Ssam if (hy_nodebug & 4) 56611207Ssam hy_debug_flag = 1; 56711195Ssam #endif 56811195Ssam error = EAFNOSUPPORT; 56911195Ssam goto drop; 57011195Ssam } 57111195Ssam 57211195Ssam /* 57311207Ssam * Add the software and hardware hyperchannel headers. 57411195Ssam * If there's not enough space in the first mbuf, allocate another. 57511195Ssam * If that should fail, drop this sucker. 57611195Ssam * No extra space for headers is allocated. 57711195Ssam */ 57811195Ssam if (m->m_off > MMAXOFF || 57911195Ssam MMINOFF + sizeof(struct hym_hdr) > m->m_off) { 58011207Ssam m = m_get(M_DONTWAIT, MT_HEADER); 58111195Ssam if (m == 0) { 58211195Ssam m = m0; 58311195Ssam error = ENOBUFS; 58411195Ssam goto drop; 58511195Ssam } 58611195Ssam m->m_next = m0; 58711195Ssam m->m_off = MMINOFF; 58811195Ssam m->m_len = sizeof(struct hym_hdr); 58911195Ssam } else { 59011195Ssam m->m_off -= sizeof(struct hym_hdr); 59111195Ssam m->m_len += sizeof(struct hym_hdr); 59211195Ssam } 59311195Ssam hym = mtod(m, struct hym_hdr *); 59411195Ssam hym->hym_mplen = mplen; 59511195Ssam hym->hym_hdr.hyh_type = dtype; 59611195Ssam hym->hym_hdr.hyh_off = 0; 59712772Ssam hym->hym_hdr.hyh_from = htons((u_short)ifp->if_host[0]); 59811195Ssam hym->hym_hdr.hyh_param = loopback; 59911195Ssam #ifdef HYROUTE 60011207Ssam if (r->hyr_lasttime.tv_sec != 0) { 60111195Ssam register struct hy_hash *rh; 60211195Ssam register int i; 60311195Ssam 60411195Ssam i = HYRHASH(dhost); 60511195Ssam rh = &r->hyr_hash[i]; 60611195Ssam i = 0; 60711195Ssam while (rh->hyr_key != dhost) { 60811195Ssam rh++; i++; 60911195Ssam if (rh > &r->hyr_hash[HYRSIZE]) 61011195Ssam rh = &r->hyr_hash[0]; 61111195Ssam if (rh->hyr_flags == 0 || i > HYRSIZE) 61211195Ssam goto notfound; 61311195Ssam } 61411195Ssam if (rh->hyr_flags & HYR_GATE) { 61511195Ssam loopback = 0; /* no hardware loopback on gateways */ 61611195Ssam i = rh->hyr_nextgate; 61711195Ssam if (i >= rh->hyr_egate) 61811195Ssam rh->hyr_nextgate = rh->hyr_pgate; 61911195Ssam else 62011195Ssam rh->hyr_nextgate++; 62111195Ssam rh = &r->hyr_hash[r->hyr_gateway[i]]; 62211195Ssam if ((rh->hyr_flags & HYR_DIR) == 0) 62311195Ssam goto notfound; 62411195Ssam } 62511195Ssam hym->hym_hdr.hyh_ctl = rh->hyr_ctl; 62611195Ssam hym->hym_hdr.hyh_access = rh->hyr_access; 62711195Ssam hym->hym_hdr.hyh_to = rh->hyr_dst; 62811195Ssam } else { 62911195Ssam hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS; 63011195Ssam hym->hym_hdr.hyh_access = 0; 63112772Ssam hym->hym_hdr.hyh_to = htons((u_short)dhost); 63211195Ssam } 63311195Ssam #else 63411195Ssam hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS; 63511195Ssam hym->hym_hdr.hyh_access = 0; 63611195Ssam hym->hym_hdr.hyh_to = htons(dhost); 63711195Ssam #endif 63811195Ssam 63911195Ssam if (hym->hym_mplen) { 64011195Ssam hym->hym_hdr.hyh_ctl |= H_ASSOC; 64111195Ssam #ifdef DEBUG 64211207Ssam if (hy_nodebug & 16) 64311207Ssam hy_debug_flag = 1; 64411195Ssam #endif 64511207Ssam } else 64611207Ssam hym->hym_hdr.hyh_ctl &= ~H_ASSOC; 64711195Ssam #ifdef DEBUG 64811207Ssam printD("hy%d: output mplen=%x ctl=%x access=%x to=%x", 64911195Ssam ifp->if_unit, hym->hym_mplen, hym->hym_hdr.hyh_ctl, 65011207Ssam hym->hym_hdr.hyh_access, hym->hym_hdr.hyh_to); 65111207Ssam 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); 66711207Ssam return (0); 66811195Ssam notfound: 66911207Ssam error = ENETUNREACH; /* XXX */ 67011195Ssam drop: 67111195Ssam m_freem(m); 67211207Ssam return (error); 67311207Ssam } 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 68311207Ssam printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, 68411207Ssam 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; 69711207Ssam hystart(ui, HYF_STATUS, sizeof (is->hy_status), 69811207Ssam 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; 70611207Ssam hystart(ui, HYF_RSTATS, sizeof (is->hy_stat), 70711207Ssam is->hy_ifuba.ifu_r.ifrw_info); 70811207Ssam } else if (HYS_RECVDATA(addr)) { 70911195Ssam is->hy_state = RECVSENT; 71011195Ssam is->hy_retry = 0; 71111207Ssam hystart(ui, HYF_INPUTMSG, MPSIZE, 71211207Ssam 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 71711207Ssam printD("hy%d: reissue cmd=0x%x count=%d", 71811207Ssam ui->ui_unit, is->hy_savedcmd, is->hy_savedcount); 71911207Ssam printD(" ubaddr=0x%x retry=%d\n", 72011207Ssam is->hy_savedaddr, is->hy_retry); 72111195Ssam #endif 72211207Ssam hystart(ui, is->hy_savedcmd, is->hy_savedcount, 72311207Ssam is->hy_savedaddr); 72411195Ssam } else { 72511195Ssam register struct mbuf *m; 72611195Ssam 72711195Ssam IF_DEQUEUE(&is->hy_if.if_snd, m); 72811207Ssam 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 73711207Ssam hylog(HYL_XMIT, sizeof(struct hym_hdr), 73811207Ssam (char *)hym); 73911195Ssam #endif 74011195Ssam mplen = hym->hym_mplen; 74111207Ssam if (hym->hym_hdr.hyh_to_adapter == 74211207Ssam hym->hym_hdr.hyh_from_adapter) 74311207Ssam cmd = HYF_XMITLOCMSG; 74411207Ssam else 74511207Ssam cmd = HYF_XMITMSG; 74611195Ssam #ifdef DEBUG 74711195Ssam printD("hy%d: hym_hdr = ", ui->ui_unit); 74811207Ssam if (hy_debug_flag) 74911207Ssam hyprintdata((char *)hym, 75011207Ssam sizeof (struct hym_hdr)); 75111195Ssam #endif 75211195Ssam /* 75311207Ssam * 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) 76011207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 76111207Ssam is->hy_ifuba.ifu_w.ifrw_bdp); 76211195Ssam #ifdef DEBUG 76311207Ssam printD( 76411207Ssam "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 76511195Ssam ui->ui_unit, mplen, is->hy_olen); 76611207Ssam if (hy_debug_flag) 76711207Ssam hyprintdata( 76811207Ssam is->hy_ifuba.ifu_w.ifrw_addr, 76911207Ssam is->hy_olen); 77011195Ssam #endif 77111207Ssam hystart(ui, cmd, 77211207Ssam (mplen == 0) ? is->hy_olen : mplen, 77311207Ssam 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 /* 78111207Ssam * Port number is taken from status data 78211195Ssam */ 78311207Ssam hystart(ui, 78412772Ssam (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)), 78512772Ssam 0, 0); 78611195Ssam } else if (rq & RQ_MARKUP) { 78711195Ssam register struct ifnet *ifp = &is->hy_if; 78811207Ssam register struct sockaddr_in *sin = 78911207Ssam (struct sockaddr_in *)&ifp->if_addr; 79011195Ssam 79111207Ssam is->hy_flags &= ~RQ_MARKUP; 79211195Ssam is->hy_retry = 0; 79311195Ssam /* 794*13065Ssam * Fill in the host number 79511207Ssam * from the status buffer 79611195Ssam */ 79711207Ssam printf( 79811207Ssam "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), 80211207Ssam (is->hy_stat.hyc_atype[0]<<8) | 80311207Ssam is->hy_stat.hyc_atype[1], 80411195Ssam is->hy_stat.hyc_atype[2]); 80511195Ssam 80611207Ssam ifp->if_host[0] = 80711207Ssam (is->hy_stat.hyc_uaddr << 8) | 80811207Ssam PORTNUM(&is->hy_status); 80911207Ssam sin->sin_addr = 81011207Ssam if_makeaddr(ifp->if_net, ifp->if_host[0]); 81111195Ssam ifp->if_flags |= IFF_UP; 81211195Ssam if_rtinit(ifp, RTF_UP); 81311195Ssam #ifdef HYLOG 81411195Ssam hylog(HYL_UP, 0, (char *)0); 81511195Ssam #endif 81611195Ssam } else { 81711195Ssam is->hy_state = WAITING; 81811195Ssam is->hy_retry = 0; 81911195Ssam hystart(ui, HYF_WAITFORMSG, 0, 0); 82011195Ssam } 82111195Ssam } 82211207Ssam break; 82311195Ssam } 82411195Ssam 82511195Ssam case STATSENT: 82612772Ssam bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status, 82711207Ssam sizeof (struct hy_status)); 82811195Ssam #ifdef DEBUG 82911207Ssam printD("hy%d: status - %x %x %x %x %x %x %x %x\n", 83011207Ssam ui->ui_unit, is->hy_status.hys_gen_status, 83111207Ssam is->hy_status.hys_last_fcn, 83211207Ssam is->hy_status.hys_resp_trunk, 83311207Ssam is->hy_status.hys_status_trunk, 83411207Ssam is->hy_status.hys_recd_resp, 83511207Ssam is->hy_status.hys_error, 83611207Ssam is->hy_status.hys_caddr, 83711207Ssam is->hy_status.hys_pad); 83811195Ssam #endif 83911195Ssam is->hy_state = IDLE; 84011195Ssam #ifdef HYLOG 84111207Ssam hylog(HYL_STATUS, sizeof (struct hy_status), 84211207Ssam (char *)&is->hy_status); 84311195Ssam #endif 84411195Ssam #ifdef HYELOG 84511195Ssam { 84611195Ssam register int i; 84711195Ssam 84811195Ssam i = is->hy_status.hys_error; 84911195Ssam if (i < HYE_MAX) 85011195Ssam i = HYE_MAX; 85111195Ssam switch (is->hy_status.hys_last_fcn) { 85211195Ssam case HYF_XMITLOCMSG: 85311195Ssam i += HYE_MAX+1; /* fall through */ 85411195Ssam case HYF_XMITLSTDATA: 85511195Ssam i += HYE_MAX+1; /* fall through */ 85611195Ssam case HYF_XMITMSG: 85711195Ssam i += HYE_MAX+1; 85811195Ssam } 85911195Ssam hy_elog[i]++; 86011195Ssam } 86111195Ssam #endif 86211195Ssam break; 86311195Ssam 86411195Ssam case RSTATSENT: { 86511207Ssam register struct hy_stat *p = 86611207Ssam (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr; 86711195Ssam 86811195Ssam is->hy_stat.hyc_msgcnt = ntohl(p->hyc_msgcnt); 86911195Ssam is->hy_stat.hyc_dbcnt = ntohl(p->hyc_dbcnt); 87011195Ssam is->hy_stat.hyc_tbusy = ntohl(p->hyc_tbusy); 87111195Ssam is->hy_stat.hyc_hwret = ntohl(p->hyc_hwret); 87211195Ssam is->hy_stat.hyc_crcbad = ntohl(p->hyc_crcbad); 87311195Ssam is->hy_stat.hyc_mcret = ntohl(p->hyc_mcret); 87411195Ssam is->hy_stat.hyc_tdabort = ntohl(p->hyc_tdabort); 87511195Ssam is->hy_stat.hyc_atype[0] = p->hyc_atype[0]; 87611195Ssam is->hy_stat.hyc_atype[1] = p->hyc_atype[1]; 87711195Ssam is->hy_stat.hyc_atype[2] = p->hyc_atype[2]; 87811195Ssam is->hy_stat.hyc_uaddr = p->hyc_uaddr; 87911195Ssam #ifdef DEBUG 88011207Ssam printD( 88111207Ssam "hy%d: statistics - msgcnt %d dbcnt %d hwret %d tbusy %d crcbad %d\n", 88211195Ssam ui->ui_unit, 88311195Ssam is->hy_stat.hyc_msgcnt, is->hy_stat.hyc_dbcnt, 88411195Ssam is->hy_stat.hyc_tbusy, is->hy_stat.hyc_hwret, 88511195Ssam is->hy_stat.hyc_crcbad); 88611195Ssam printD(" mcret %d tdabort %d atype %x %x %x uaddr %x\n", 88711195Ssam is->hy_stat.hyc_mcret, is->hy_stat.hyc_tdabort, 88811195Ssam is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1], 88911195Ssam is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr); 89011195Ssam #endif 89111195Ssam is->hy_state = IDLE; 89211195Ssam #ifdef HYLOG 89311207Ssam hylog(HYL_STATISTICS, sizeof (struct hy_stat), 89411207Ssam (char *)&is->hy_stat); 89511195Ssam #endif 89611195Ssam break; 89711195Ssam } 89811195Ssam 89911195Ssam case CLEARSENT: 90011195Ssam is->hy_state = IDLE; 90111195Ssam break; 90211195Ssam 90311195Ssam case ENDOPSENT: 90411195Ssam is->hy_state = IDLE; 90511195Ssam break; 90611195Ssam 90711195Ssam case RECVSENT: { 90811207Ssam register struct hy_hdr *hyh; 90911207Ssam register unsigned len; 91011195Ssam 91111207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 91211207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 91311207Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 91411207Ssam hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 91511207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 91611207Ssam if (len > MPSIZE) { 91711207Ssam printf("hy%d: RECVD MP > MPSIZE (%d)\n", 91811207Ssam ui->ui_unit, len); 91911195Ssam #ifdef DEBUG 92011207Ssam hy_debug_flag = 1; 92111207Ssam printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 92211207Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, 92311207Ssam addr->hyd_bar, addr->hyd_wcr); 92411195Ssam #endif 92511207Ssam } 92611195Ssam #ifdef DEBUG 92711207Ssam printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len); 92811207Ssam if (hy_debug_flag) 92911207Ssam hyprintdata((char *)hyh, len); 93011195Ssam #endif 93111207Ssam if (hyh->hyh_ctl & H_ASSOC) { 93211207Ssam is->hy_state = RECVDATASENT; 93311207Ssam is->hy_ilen = len; 93411207Ssam is->hy_retry = 0; 93511207Ssam hystart(ui, HYF_INPUTDATA, 93612772Ssam (int)(HYMTU-len+sizeof (struct hy_hdr)), 93712772Ssam (int)(is->hy_ifuba.ifu_r.ifrw_info + len)); 93811207Ssam } else { 93912772Ssam hyrecvdata(ui, hyh, (int)len); 94011207Ssam is->hy_state = IDLE; 94111195Ssam } 94211207Ssam break; 94311207Ssam } 94411195Ssam 94511195Ssam case RECVDATASENT: { 94611207Ssam register struct hy_hdr *hyh; 94711207Ssam register unsigned len; 94811195Ssam 94911207Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 95011207Ssam UBAPURGE(is->hy_ifuba.ifu_uba, 95111207Ssam is->hy_ifuba.ifu_r.ifrw_bdp); 95211207Ssam hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 95311207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 95411195Ssam #ifdef DEBUG 95511207Ssam printD("hy%d: recvd assoc data, len = %d, data = ", 95611207Ssam ui->ui_unit, len); 95711207Ssam if (hy_debug_flag) 95811207Ssam hyprintdata((char *)hyh + is->hy_ilen, len); 95911195Ssam #endif 96012772Ssam hyrecvdata(ui, hyh, (int)(len + is->hy_ilen)); 96111207Ssam is->hy_state = IDLE; 96211207Ssam break; 96311207Ssam } 96411195Ssam 96511195Ssam case XMITSENT: 96611207Ssam if (is->hy_flags & RQ_XASSOC) { 96711207Ssam register unsigned len; 96811195Ssam 96911207Ssam is->hy_flags &= ~RQ_XASSOC; 97011207Ssam is->hy_state = XMITDATASENT; 97111207Ssam is->hy_retry = 0; 97211207Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 97311207Ssam if (len > is->hy_olen) { 97411207Ssam printf( 97511207Ssam "hy%d: xmit error - len > hy_olen [%d > %d]\n", 97611207Ssam ui->ui_unit, len, is->hy_olen); 97711195Ssam #ifdef DEBUG 97811207Ssam hy_debug_flag = 1; 97911195Ssam #endif 98011195Ssam } 98111207Ssam hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len, 98211207Ssam is->hy_ifuba.ifu_w.ifrw_info + len); 98311207Ssam break; 98411207Ssam } 98511207Ssam /* fall through to ... */ 98611195Ssam 98711195Ssam case XMITDATASENT: 98811207Ssam hyxmitdata(ui); 98911207Ssam is->hy_state = IDLE; 99011207Ssam break; 99111195Ssam 99211195Ssam case WAITING: /* wait for message complete or output requested */ 99311207Ssam if (HYS_RECVDATA(addr)) 99411195Ssam is->hy_state = IDLE; 99511195Ssam else { 99611195Ssam is->hy_state = CLEARSENT; 99711195Ssam is->hy_retry = 0; 99811195Ssam hystart(ui, HYF_CLRWFMSG, 0, 0); 99911195Ssam } 100011195Ssam break; 100111195Ssam 100211195Ssam case MARKPORT: 100311195Ssam is->hy_state = STARTUP; 100411195Ssam is->hy_if.if_flags &= ~IFF_UP; 100511195Ssam goto endintr; 100611195Ssam 100711195Ssam default: 100811207Ssam printf("hy%d: DRIVER BUG - INVALID STATE %d\n", 100911207Ssam ui->ui_unit, is->hy_state); 101011195Ssam panic("HYPERCHANNEL IN INVALID STATE"); 101111195Ssam /*NOTREACHED*/ 101211207Ssam } 101311195Ssam if (is->hy_state == IDLE) 101411195Ssam goto actloop; 101511195Ssam endintr: 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 /* 102311195Ssam * Called from device interrupt when recieving data. 102411195Ssam * Examine packet to determine type. Decapsulate packet 102511195Ssam * based on type and pass to type specific higher-level 102611195Ssam * input routine. 102711195Ssam */ 102811195Ssam hyrecvdata(ui, hyh0, len) 102911195Ssam struct uba_device *ui; 103011195Ssam struct hy_hdr *hyh0; 103111195Ssam int len; 103211195Ssam { 103311195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 103411195Ssam register struct hy_hdr *hyh = hyh0; 103511195Ssam struct mbuf *m; 103611195Ssam register struct ifqueue *inq; 103711195Ssam 103811195Ssam is->hy_if.if_ipackets++; 103911195Ssam #ifdef DEBUG 104011207Ssam printD("hy%d: recieved packet, len = %d (actual %d)\n", 104111207Ssam ui->ui_unit, len, 104211207Ssam len - (hyh->hyh_off + sizeof (struct hy_hdr))); 104311195Ssam #endif 104411195Ssam #ifdef HYLOG 104511195Ssam { 104611195Ssam struct { 104711195Ssam short hlen; 104811195Ssam struct hy_hdr hhdr; 104911195Ssam } hh; 105011195Ssam hh.hlen = len; 105111195Ssam hh.hhdr = *hyh; 105211195Ssam hylog(HYL_RECV, sizeof(hh), (char *)&hh); 105311195Ssam } 105411195Ssam #endif 105511195Ssam if (len > HYMTU + MPSIZE || len == 0) 105611195Ssam return; /* sanity */ 105711195Ssam /* 105811195Ssam * Pull packet off interface. 105911195Ssam */ 106011195Ssam m = if_rubaget(&is->hy_ifuba, len, 0); 106111207Ssam if (m == NULL) 106211195Ssam return; 106311195Ssam switch (hyh->hyh_type) { 106411195Ssam 106511195Ssam #ifdef INET 106611195Ssam case HYLINK_IP: 106711195Ssam /* 106811207Ssam * Strip the variable portion of the hyperchannel header 106911207Ssam * (fixed portion stripped in if_rubaget). 107011195Ssam */ 107111195Ssam m->m_len -= hyh->hyh_off; 107211195Ssam m->m_off += hyh->hyh_off; 107311195Ssam schednetisr(NETISR_IP); 107411195Ssam inq = &ipintrq; 107511195Ssam break; 107611195Ssam #endif 107711195Ssam default: 107811195Ssam m_freem(m); 107911195Ssam return; 108011195Ssam } 108111195Ssam if (IF_QFULL(inq)) { 108211195Ssam IF_DROP(inq); 108311195Ssam m_freem(m); 108411195Ssam } else 108511195Ssam IF_ENQUEUE(inq, m); 108611207Ssam } 108711195Ssam 108811195Ssam /* 108911207Ssam * Transmit done, release resources, bump counters. 109011195Ssam */ 109111195Ssam hyxmitdata(ui) 109211195Ssam struct uba_device *ui; 109311195Ssam { 109411195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 109511195Ssam 109611195Ssam is->hy_if.if_opackets++; 109711207Ssam if (is->hy_ifuba.ifu_xtofree) { 109811195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 109911195Ssam is->hy_ifuba.ifu_xtofree = 0; 110011195Ssam } 110111207Ssam } 110211195Ssam 110311195Ssam hycancel(ui) 110411195Ssam register struct uba_device *ui; 110511195Ssam { 110611195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 110711195Ssam 110811207Ssam if (is->hy_ifuba.ifu_xtofree) { 110911195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 111011195Ssam is->hy_ifuba.ifu_xtofree = 0; 111111195Ssam } 111211195Ssam #ifdef DEBUG 111311207Ssam if (hy_nodebug & 1) 111411207Ssam hy_debug_flag = 1; 111511195Ssam #endif 111611195Ssam #ifdef DEBUG 111711195Ssam printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n", 111811195Ssam ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd, 111911195Ssam is->hy_savedcount, is->hy_savedaddr); 112011207Ssam printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n", 112111207Ssam is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr, 112211207Ssam is->hy_retry); 112311207Ssam printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n", 112411207Ssam is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, 112511207Ssam is->hy_savedcmd); 112611195Ssam #endif 112711195Ssam is->hy_state = IDLE; 112811195Ssam is->hy_flags |= (RQ_ENDOP | RQ_STATUS); 112911195Ssam hyact(ui); 113011207Ssam } 113111195Ssam 113211195Ssam #ifdef DEBUG 113311195Ssam hyprintdata(cp, len) 113411195Ssam register char *cp; 113511195Ssam register int len; 113611195Ssam { 113711195Ssam register int count = 16; 113811195Ssam register char *fmt; 113911195Ssam static char regfmt[] = "\n\t %x"; 114011195Ssam 114111195Ssam fmt = ®fmt[2]; 114211195Ssam while (--len >= 0) { 114311195Ssam printL(fmt, *cp++ & 0xff); 114411195Ssam fmt = ®fmt[2]; 114511195Ssam if (--count <= 0) { 114611195Ssam fmt = ®fmt[0]; 114711195Ssam count = 16; 114811195Ssam } 114911195Ssam } 115011195Ssam printL("\n"); 115111195Ssam } 115211195Ssam #endif 115311195Ssam 115411195Ssam hywatch(unit) 115511195Ssam int unit; 115611195Ssam { 115711195Ssam register struct hy_softc *is = &hy_softc[unit]; 115811195Ssam register struct uba_device *ui = hyinfo[unit]; 115911195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 116011195Ssam int s; 116111195Ssam 116211195Ssam s = splimp(); 116311195Ssam is->hy_if.if_timer = SCANINTERVAL; 116411207Ssam if (is->hy_ntime > 2 && is->hy_state != WAITING && 116511207Ssam is->hy_state != STARTUP && is->hy_state != IDLE) { 116611195Ssam printf("hy%d: watchdog timer expired\n", unit); 116711195Ssam hycancel(ui); 116811195Ssam } 116911195Ssam #ifdef PI13 117011195Ssam if ((addr->hyd_csr & S_POWEROFF) != 0) { 117111195Ssam addr->hyd_csr |= S_POWEROFF; 117211195Ssam DELAY(100); 117311195Ssam if ((addr->hyd_csr & S_POWEROFF) == 0) { 117411195Ssam printf("hy%d: adapter power restored\n", unit); 117511195Ssam is->hy_state = IDLE; 117611207Ssam is->hy_flags |= 117711207Ssam (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS); 117811195Ssam hyact(ui); 117911195Ssam } 118011195Ssam } 118111195Ssam #endif 118211195Ssam splx(s); 118311195Ssam } 118411195Ssam 118511195Ssam #ifdef HYLOG 118611195Ssam hylog(code, len, ptr) 118711195Ssam int code; 118811195Ssam int len; 118911195Ssam char *ptr; 119011195Ssam { 119111195Ssam register unsigned char *p; 119211195Ssam int s; 119311195Ssam 119411195Ssam s = splimp(); 119511195Ssam if (hy_log.hyl_self != &hy_log) { 119611195Ssam hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 119711195Ssam hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 119811195Ssam hy_log.hyl_self = &hy_log; 119911195Ssam hy_log.hyl_enable = HYL_DISABLED; 120011195Ssam hy_log.hyl_onerr = HYL_CATCH1; 120111195Ssam } 120211207Ssam if (hy_log.hyl_enable == HYL_DISABLED || 120311207Ssam hy_log.hyl_enable == HYL_CAUGHT1 || 120411207Ssam hy_log.hyl_enable == HYL_CAUGHTSTATUS || 120511207Ssam (hy_log.hyl_enable == HYL_CATCHSTATUS && code != HYL_STATUS)) 120611207Ssam goto out; 120711195Ssam p = hy_log.hyl_ptr; 120811195Ssam if (p + len + 2 >= hy_log.hyl_eptr) { 120912772Ssam bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p)); 121011195Ssam p = &hy_log.hyl_buf[0]; 121111195Ssam if (hy_log.hyl_enable == HYL_CATCH1) { 121211195Ssam hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHT1; 121311195Ssam goto out; 121411195Ssam } 121511195Ssam if (hy_log.hyl_enable == HYL_CATCHSTATUS) { 121611195Ssam hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHTSTATUS; 121711195Ssam goto out; 121811195Ssam } 121911195Ssam } 122011195Ssam *p++ = code; 122111195Ssam *p++ = len; 122212772Ssam bcopy(ptr, (caddr_t)p, (unsigned)len); 122311195Ssam hy_log.hyl_ptr = p + len; 122411195Ssam out: 122511195Ssam splx(s); 122611195Ssam } 122711195Ssam #endif 122811195Ssam 122912772Ssam /*ARGSUSED*/ 123013058Ssam hyioctl(ifp, cmd, data) 123113058Ssam register struct ifnet *ifp; 123211207Ssam int cmd; 123311207Ssam caddr_t data; 123411195Ssam { 1235*13065Ssam struct sockaddr_in *sin; 123611207Ssam int s = splimp(), error = 0; 123711195Ssam 123811195Ssam switch(cmd) { 123911195Ssam 1240*13065Ssam case SIOCSIFADDR: 1241*13065Ssam if (ifp->if_flags & IFF_RUNNING) 1242*13065Ssam if_rtinit(ifp, -1); 1243*13065Ssam sin = (struct sockaddr_in *)&ifr->ifr_addr; 1244*13065Ssam ifp->if_net = in_netof(sin->sin_addr); 1245*13065Ssam sin = (struct sockaddr_in *)&ifp->if_addr; 1246*13065Ssam sin->sin_family = AF_INET; 1247*13065Ssam sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]); 1248*13065Ssam if (ifp->if_flags & IFF_RUNNING) 1249*13065Ssam if_rtinit(ifp, RTF_UP); 1250*13065Ssam else 1251*13065Ssam hyinit(ifp->if_unit); 1252*13065Ssam break; 1253*13065Ssam 125411195Ssam case HYSETROUTE: 125511207Ssam if (!suser()) { 125611207Ssam error = EPERM; 125711207Ssam goto bad; 125811195Ssam } 125913058Ssam hy_route[ifp->if_unit] = *(struct hyroute *)ifr->ifr_data; 126013058Ssam hy_route[ifp->if_unit].hyr_lasttime = time; 126111195Ssam break; 126211195Ssam 126311195Ssam case HYGETROUTE: 126413058Ssam *(struct hyroute *)ifr->ifr_data = hy_route[ifp->if_unit]; 126511195Ssam break; 126611195Ssam 126711195Ssam default: 126813058Ssam error = EINVAL; 126911195Ssam break; 127011195Ssam } 127111207Ssam bad: 127211195Ssam splx(s); 127311207Ssam return (error); 127411195Ssam } 127511207Ssam #endif 1276