1*11198Ssam /* if_hy.c 4.2 83/02/21 */ 211195Ssam 311195Ssam #include "hy.h" 411195Ssam #if NHY > 0 511195Ssam 611195Ssam /* 711195Ssam * Network Systems Copropration Hyperchanel interface 811195Ssam * 911195Ssam * MUST BE UPDATED FOR 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/cpu.h" 2011195Ssam #include "../h/vmmac.h" 2111195Ssam #include "../h/dir.h" 2211195Ssam #include "../h/user.h" 2311195Ssam #include "../h/errno.h" 2411195Ssam 2511195Ssam #include "../net/if.h" 2611195Ssam #include "../net/route.h" 2711195Ssam 2811195Ssam #include "../netinet/in.h" 2911195Ssam #include "../netinet/in_systm.h" 3011195Ssam #include "../netinet/ip.h" 3111195Ssam #include "../netinet/ip_var.h" 3211195Ssam 3311195Ssam #include "../vaxif/if_hy.h" 34*11198Ssam #include "../vaxif/if_hyreg.h" 3511195Ssam #include "../vaxif/if_uba.h" 3611195Ssam 3711195Ssam #include "../vax/mtpr.h" 3811195Ssam #include "../vaxuba/ubareg.h" 3911195Ssam #include "../vaxuba/ubavar.h" 4011195Ssam 4111195Ssam #define HYROUTE 4211195Ssam #define HYELOG 4311195Ssam #define HYMTU 576 4411195Ssam 4511195Ssam int hyprobe(), hyattach(), hyinit(), 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 */ 6611195Ssam short hy_flags; /* flags */ 6711195Ssam 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 */ 7711195Ssam struct hy_stat hy_stat; /* statistics */ 7811195Ssam struct hy_status hy_status; /* status */ 7911195Ssam } hy_softc[NHY]; 8011195Ssam 8111195Ssam #ifdef HYELOG 8211195Ssam #define HYE_MAX 0x18 /* max error code is 0x17, 0x18 bin gets out of range */ 8311195Ssam 8411195Ssam unsigned long hy_elog[(HYE_MAX+1)*4]; 8511195Ssam #endif 8611195Ssam 8711195Ssam 8811195Ssam #ifdef DEBUG 8911195Ssam #define printL lprintf 9011195Ssam #define printD if (hy_debug_flag) lprintf 9111195Ssam int hy_debug_flag = 0; 9211195Ssam /* 9311195Ssam * hy_nodebug bit 0x01 set hy_debug_flag on hycancel 9411195Ssam * hy_nodebug bit 0x02 set hy_debug_flag on command reissue 9511195Ssam * hy_nodebug bit 0x04 set hy_debug_flag on abnormal interrupt 9611195Ssam * hy_nodebug bit 0x08 set hy_debug_flag on hyouput 9711195Ssam * hy_nodebug bit 0x10 set hy_debug_flag on hyouput with associated data 9811195Ssam */ 9911195Ssam int hy_nodebug = 0x0; 10011195Ssam #else 10111195Ssam #define printD hyvoid 10211195Ssam #endif 10311195Ssam 10411195Ssam /* 10511195Ssam * requests for service (in order by descending priority) 10611195Ssam */ 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 /* 11611195Ssam * more flags 11711195Ssam */ 11811195Ssam 11911195Ssam #define RQ_XASSOC 0100 /* associated data to transmit */ 12011195Ssam 12111195Ssam /* 12211195Ssam * driver states 12311195Ssam */ 12411195Ssam 12511195Ssam #define STARTUP 0 /* initial state (before fully there) */ 12611195Ssam #define IDLE 1 /* idle state */ 12711195Ssam #define STATSENT 2 /* status cmd sent to adapter */ 12811195Ssam #define ENDOPSENT 3 /* end operation cmd sent */ 12911195Ssam #define RECVSENT 4 /* input message cmd sent */ 13011195Ssam #define RECVDATASENT 5 /* input data cmd sent */ 13111195Ssam #define XMITSENT 6 /* transmit message cmd sent */ 13211195Ssam #define XMITDATASENT 7 /* transmit data cmd sent */ 13311195Ssam #define WAITING 8 /* waiting for messages */ 13411195Ssam #define CLEARSENT 9 /* clear wait for message cmd sent */ 13511195Ssam #define MARKPORT 10 /* mark this host's adapter port down issued */ 13611195Ssam #define RSTATSENT 11 /* read statistics cmd sent to adapter */ 13711195Ssam 13811195Ssam #ifdef DEBUG 13911195Ssam char *hy_state_names[] = { 14011195Ssam "Startup", 14111195Ssam "Idle", 14211195Ssam "Status Sent", 14311195Ssam "End op Sent", 14411195Ssam "Recieve Message Proper Sent", 14511195Ssam "Recieve Data Sent", 14611195Ssam "Transmit Message Proper Sent", 14711195Ssam "Transmit Data Sent", 14811195Ssam "Wait for Message Sent", 14911195Ssam "Clear Wait for Message Sent", 15011195Ssam "Mark Port Down Sent", 15111195Ssam "Read Statistics Sent" 15211195Ssam }; 15311195Ssam #endif 15411195Ssam 15511195Ssam #define SCANINTERVAL 10 /* seconds */ 15611195Ssam #define MAXINTERVAL 20 /* seconds (max action) */ 15711195Ssam 15811195Ssam /* 15911195Ssam * Cause a device interrupt. This code uses a buffer starting at 16011195Ssam * location zero on the unibus (which is already mapped by the 16111195Ssam * autoconfigure code in the kernel). 16211195Ssam */ 16311195Ssam hyprobe(reg) 16411195Ssam caddr_t reg; 16511195Ssam { 16611195Ssam register int br, cvec; /* r11, r10 value-result */ 16711195Ssam register struct hydevice *addr = (struct hydevice *) reg; 16811195Ssam 16911195Ssam #ifdef lint 17011195Ssam br = 0; cvec = br; br = cvec; 17111195Ssam hyint(0); 17211195Ssam #endif 17311195Ssam /* 17411195Ssam * request adapter status to a buffer starting at unibus location 0 17511195Ssam */ 17611195Ssam addr->hyd_bar = 0; 17711195Ssam addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1); 17811195Ssam addr->hyd_dbuf = HYF_STATUS; 17911195Ssam #ifdef PI13 18011195Ssam addr->hyd_csr |= S_GO | S_IE | S_IATTN; 18111195Ssam #else 18211195Ssam addr->hyd_csr |= S_GO | S_IE; 18311195Ssam #endif 18411195Ssam DELAY(10000); 18511195Ssam #ifdef PI13 18611195Ssam addr->hyd_csr |= S_CLRINT; /* clear any stacked interrupts */ 18711195Ssam #endif 18811195Ssam addr->hyd_csr &= ~(S_IE | S_CLRINT); /* disable further interrupts */ 18911195Ssam return(1); 19011195Ssam } /* hyprobe */ 19111195Ssam 19211195Ssam /* 19311195Ssam * Interface exists: make available by filling in network interface 19411195Ssam * record. System will initialize the interface when it is ready 19511195Ssam * to accept packets. 19611195Ssam */ 19711195Ssam hyattach(ui) 19811195Ssam struct uba_device *ui; 19911195Ssam { 20011195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 20111195Ssam register struct ifnet *ifp = &is->hy_if; 20211195Ssam 20311195Ssam ifp->if_unit = ui->ui_unit; 20411195Ssam ifp->if_name = "hy"; 20511195Ssam ifp->if_mtu = HYMTU; 20611195Ssam ifp->if_net = ui->ui_flags; 20711195Ssam 20811195Ssam is->hy_state = STARTUP; /* don't allow state transitions yet */ 20911195Ssam 21011195Ssam ifp->if_init = hyinit; 21111195Ssam ifp->if_output = hyoutput; 21211195Ssam ifp->if_ubareset = hyreset; 21311195Ssam ifp->if_watchdog = hywatch; 21411195Ssam ifp->if_timer = SCANINTERVAL; 21511195Ssam is->hy_ifuba.ifu_flags = UBA_CANTWAIT; 21611195Ssam #ifdef SUPBDP 21711195Ssam is->hy_ifuba.ifu_flags |= UBA_NEEDBDP; 21811195Ssam #endif 21911195Ssam if_attach(ifp); 22011195Ssam } /* hyattach */ 22111195Ssam 22211195Ssam /* 22311195Ssam * Reset of interface after UNIBUS reset. 22411195Ssam * If interface is on specified uba, reset its state. 22511195Ssam */ 22611195Ssam hyreset(unit, uban) 22711195Ssam int unit, uban; 22811195Ssam { 22911195Ssam register struct uba_device *ui = hyinfo[unit]; 23011195Ssam register struct hy_softc *is; 23111195Ssam 23211195Ssam if (unit >= NHY || ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban) 23311195Ssam return; 23411195Ssam 23511195Ssam printf(" hy%d", unit); 23611195Ssam hyinit(unit); 23711195Ssam } /* hyreset */ 23811195Ssam 23911195Ssam /* 24011195Ssam * Initialization of interface; clear recorded pending 24111195Ssam * operations, and reinitialize UNIBUS usage. 24211195Ssam */ 24311195Ssam hyinit(unit) 24411195Ssam int unit; 24511195Ssam { 24611195Ssam register struct hy_softc *is = &hy_softc[unit]; 24711195Ssam register struct uba_device *ui = hyinfo[unit]; 24811195Ssam int s; 24911195Ssam 25011195Ssam if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum, 25111195Ssam sizeof (struct hy_hdr), (int)btoc(HYMTU)) == 0) { 25211195Ssam #ifdef DEBUG 25311195Ssam if (hy_nodebug & 4) hy_debug_flag = 1; 25411195Ssam #endif 25511195Ssam printf("hy%d: can't initialize\n", unit); 25611195Ssam is->hy_if.if_flags &= ~IFF_UP; 25711195Ssam return; 25811195Ssam } 25911195Ssam 26011195Ssam /* 26111195Ssam * issue wait for message and start the state machine 26211195Ssam */ 26311195Ssam s = splimp(); 26411195Ssam is->hy_state = IDLE; 26511195Ssam is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP; 26611195Ssam is->hy_retry = 0; 26711195Ssam hyact(ui); 26811195Ssam splx(s); 26911195Ssam } /* hyinit */ 27011195Ssam 27111195Ssam 27211195Ssam /* 27311195Ssam * issue a command to the adapter 27411195Ssam */ 27511195Ssam hystart(ui, cmd, count, ubaddr) 27611195Ssam struct uba_device *ui; 27711195Ssam int cmd; 27811195Ssam int count; 27911195Ssam int ubaddr; 28011195Ssam { 28111195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 28211195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 28311195Ssam 28411195Ssam #ifdef DEBUG 28511195Ssam printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n", ui->ui_unit, cmd, count, ubaddr); 28611195Ssam printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 28711195Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 28811195Ssam #endif 28911195Ssam 29011195Ssam if (((is->hy_flags & RQ_REISSUE) == 0) && (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) { 29111195Ssam is->hy_savedstate = is->hy_state; 29211195Ssam is->hy_savedcmd = cmd; 29311195Ssam is->hy_savedcount = count; 29411195Ssam is->hy_savedaddr = ubaddr; 29511195Ssam } 29611195Ssam 29711195Ssam addr->hyd_bar = ubaddr & 0xffff; 29811195Ssam addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1); /* was byte count */ 29911195Ssam addr->hyd_dbuf = cmd; 30011195Ssam #ifdef PI13 30111195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN; 30211195Ssam #else 30311195Ssam addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE; 30411195Ssam #endif 30511195Ssam #ifdef DEBUG 30611195Ssam printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 30711195Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 30811195Ssam #endif 30911195Ssam #ifdef HYLOG 31011195Ssam { 31111195Ssam struct { 31211195Ssam unsigned char hcmd; 31311195Ssam unsigned char hstate; 31411195Ssam short hcount; 31511195Ssam } hcl; 31611195Ssam 31711195Ssam hcl.hcmd = cmd; 31811195Ssam hcl.hstate = is->hy_state; 31911195Ssam hcl.hcount = count; 32011195Ssam hylog(HYL_CMD, sizeof(hcl), (char *)&hcl); 32111195Ssam } 32211195Ssam #endif 32311195Ssam is->hy_ntime = 0; 32411195Ssam } /* hystart */ 32511195Ssam 32611195Ssam int hyint_active = 0; /* set during hy interrupt */ 32711195Ssam 32811195Ssam /* 32911195Ssam * hyperchannel interface interrupt. 33011195Ssam * 33111195Ssam * An interrupt can occur for many reasons. Examine the status of 33211195Ssam * the hyperchannel status bits to determine what to do next. 33311195Ssam * 33411195Ssam * If input error just drop packet. 33511195Ssam * Otherwise purge input buffered data path and examine 33611195Ssam * packet to determine type. Othewise decapsulate 33711195Ssam * packet based on type and pass to type specific higher-level 33811195Ssam * input routine. 33911195Ssam */ 34011195Ssam hyint(unit) 34111195Ssam int unit; 34211195Ssam { 34311195Ssam register struct hy_softc *is = &hy_softc[unit]; 34411195Ssam register struct uba_device *ui = hyinfo[unit]; 34511195Ssam register struct hydevice *addr = 34611195Ssam (struct hydevice *)ui->ui_addr; 34711195Ssam 34811195Ssam if (hyint_active) { 34911195Ssam panic("RECURSIVE HYPERCHANNEL INTERRUPT"); 35011195Ssam } 35111195Ssam 35211195Ssam hyint_active++; 35311195Ssam 35411195Ssam #ifdef DEBUG 35511195Ssam printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 35611195Ssam unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 35711195Ssam #endif 35811195Ssam #ifdef HYLOG 35911195Ssam logit: 36011195Ssam { 36111195Ssam struct { 36211195Ssam unsigned char hstate; 36311195Ssam unsigned char hflags; 36411195Ssam short hcsr; 36511195Ssam short hwcr; 36611195Ssam } hil; 36711195Ssam hil.hstate = is->hy_state; 36811195Ssam hil.hflags = is->hy_flags; 36911195Ssam hil.hcsr = addr->hyd_csr; 37011195Ssam hil.hwcr = addr->hyd_wcr; 37111195Ssam hylog(HYL_INT, sizeof(hil), (char *)&hil); 37211195Ssam } 37311195Ssam #endif 37411195Ssam 37511195Ssam if (ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) { 37611195Ssam /* 37711195Ssam * error bit set, some sort of error in the interface 37811195Ssam * 37911195Ssam * the adapter sets attn on command completion so that's not 38011195Ssam * a real error even though the interface considers it one 38111195Ssam */ 38211195Ssam #ifdef DEBUG 38311195Ssam if (hy_nodebug & 4) hy_debug_flag = 1; 38411195Ssam #endif 38511195Ssam printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n", addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 38611195Ssam 38711195Ssam if ((addr->hyd_csr & S_NEX) != 0) { 38811195Ssam printf("hy%d: NEX - Non Existant Memory\n", unit); 38911195Ssam #ifdef PI13 39011195Ssam addr->hyd_csr |= S_NEX; /* as per PI13 manual */ 39111195Ssam #else 39211195Ssam addr->hyd_csr &= ~S_NEX; 39311195Ssam #endif 39411195Ssam hycancel(ui); 39511195Ssam #ifdef PI13 39611195Ssam } else if ((addr->hyd_csr & S_POWEROFF) != 0) { 39711195Ssam printf("hy%d: Power Off bit set, trying to reset\n", unit); 39811195Ssam addr->hyd_csr |= S_POWEROFF; 39911195Ssam DELAY(100); 40011195Ssam if ((addr->hyd_csr & S_POWEROFF) != 0) { 40111195Ssam if_down(&is->hy_if); 40211195Ssam is->hy_state = STARTUP; 40311195Ssam printf("hy%d: Power Off Error, network shutdown\n", unit); 40411195Ssam } 40511195Ssam #endif 40611195Ssam } else { 40711195Ssam printf("hy%d: BAR overflow\n", unit); 40811195Ssam hycancel(ui); 40911195Ssam } 41011195Ssam } else if (NORMAL(addr)) { 41111195Ssam /* 41211195Ssam * normal interrupt, bump state machine unless in state 41311195Ssam * waiting and no data present (assumed to be word count 41411195Ssam * zero interrupt or other hardware botch) 41511195Ssam */ 41611195Ssam if (is->hy_state != WAITING || RECV_DATA(addr)) 41711195Ssam hyact(ui); 41811195Ssam 41911195Ssam } else if (ABNORMAL(addr)) { 42011195Ssam /* 42111195Ssam * abnormal termination. 42211195Ssam * bump error counts, retry the last function 42311195Ssam * 'MAXRETRY' times before kicking the bucket. 42411195Ssam * 42511195Ssam * don't reissue the cmd if in certain states, abnormal 42611195Ssam * on a reissued cmd or max retry exceeded 42711195Ssam */ 42811195Ssam #ifdef HYLOG 42911195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 43011195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 43111195Ssam goto logit; 43211195Ssam } 43311195Ssam #endif 43411195Ssam #ifdef DEBUG 43511195Ssam if (hy_nodebug & 4) hy_debug_flag = 1; 43611195Ssam printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n", 43711195Ssam unit, hy_state_names[is->hy_state], is->hy_state); 43811195Ssam printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n", 43911195Ssam is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr, is->hy_retry, 44011195Ssam is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, is->hy_savedcmd); 44111195Ssam #endif 44211195Ssam #ifdef PI13 44311195Ssam addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */ 44411195Ssam #endif 44511195Ssam if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT) { 44611195Ssam is->hy_if.if_oerrors++; 44711195Ssam } else if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT) { 44811195Ssam is->hy_if.if_ierrors++; 44911195Ssam } 45011195Ssam 45111195Ssam if (is->hy_state == XMITDATASENT || 45211195Ssam is->hy_state == RECVSENT || 45311195Ssam is->hy_state == RECVDATASENT || 45411195Ssam (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY) { 45511195Ssam hycancel(ui); 45611195Ssam } else { 45711195Ssam #ifdef DEBUG 45811195Ssam if (hy_nodebug & 2) hy_debug_flag = 1; 45911195Ssam #endif 46011195Ssam is->hy_retry++; 46111195Ssam is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE; 46211195Ssam is->hy_state = IDLE; 46311195Ssam hyact(ui); 46411195Ssam } 46511195Ssam } else { 46611195Ssam /* 46711195Ssam * Interrupt is neither normal, abnormal, or interface error. 46811195Ssam * Ignore it. It's either stacked or a word count 0. 46911195Ssam */ 47011195Ssam #ifdef HYLOG 47111195Ssam if (hy_log.hyl_enable != hy_log.hyl_onerr) { 47211195Ssam hy_log.hyl_enable = hy_log.hyl_onerr; 47311195Ssam goto logit; 47411195Ssam } 47511195Ssam #endif 47611195Ssam #ifdef DEBUG 47711195Ssam printD("hy%d: possible stacked interrupt ignored\n", unit); 47811195Ssam #endif 47911195Ssam } 48011195Ssam 48111195Ssam #ifdef DEBUG 48211195Ssam printD("hy%d: hyint exit\n\n", unit); 48311195Ssam #endif 48411195Ssam hyint_active = 0; 48511195Ssam 48611195Ssam } /* hyint */ 48711195Ssam 48811195Ssam /* 48911195Ssam * Encapsulate a packet of type family for the local net. 49011195Ssam * Use trailer local net encapsulation if enough data in first 49111195Ssam * packet leaves a multiple of 512 bytes of data in remainder. 49211195Ssam */ 49311195Ssam hyoutput(ifp, m0, dst) 49411195Ssam struct ifnet *ifp; 49511195Ssam struct mbuf *m0; 49611195Ssam struct sockaddr *dst; 49711195Ssam { 49811195Ssam register struct hym_hdr *hym; 49911195Ssam register struct mbuf *m; 50011195Ssam #ifdef HYROUTE 50111195Ssam register struct hyroute *r = &hy_route[ifp->if_unit]; 50211195Ssam #endif 50311195Ssam short dtype; /* packet type */ 50411195Ssam int dhost; /* destination adapter address */ 50511195Ssam int dlen; 50611195Ssam int mplen = 0; /* message proper length */ 50711195Ssam short loopback = 0; /* hardware loopback requested */ 50811195Ssam int error = 0; 50911195Ssam int s; 51011195Ssam 51111195Ssam #ifdef DEBUG 51211195Ssam if (hy_nodebug & 8) hy_debug_flag = 1; 51311195Ssam #endif 51411195Ssam dlen = 0; 51511195Ssam for (m = m0; m; m = m->m_next) 51611195Ssam dlen += m->m_len; 51711195Ssam m = m0; 51811195Ssam 51911195Ssam switch(dst->sa_family) { 52011195Ssam 52111195Ssam #ifdef INET 52211195Ssam case AF_INET: { 52311195Ssam register struct ip *ip = mtod(m, struct ip *); 52411195Ssam register struct sockaddr_in *sin = (struct sockaddr_in *)dst; 52511195Ssam register long hostaddr = in_lnaof(sin->sin_addr); 52611195Ssam 52711195Ssam dhost = hostaddr & 0xffff; 52811195Ssam dtype = HYLINK_IP; 52911195Ssam #ifdef DEBUG 53011195Ssam printD("hy%d: output to host %x, dhost %x\n", ifp->if_unit, sin->sin_addr.s_addr, dhost); 53111195Ssam #endif 53211195Ssam /* 53311195Ssam * debugging loopback support: 53411195Ssam * upper byte of 24 bit host number interpreted as follows 53511195Ssam * 0x00 --> no loopback 53611195Ssam * 0x01 --> hardware loop through remote adapter 53711195Ssam * other --> software loop through remote ip layer 53811195Ssam */ 53911195Ssam if (hostaddr & 0xff0000) { 54011195Ssam struct in_addr temp; 54111195Ssam 54211195Ssam temp = ip->ip_dst; 54311195Ssam ip->ip_dst = ip->ip_src; 54411195Ssam ip->ip_src = temp; 54511195Ssam if ((hostaddr & 0xff0000) == 0x10000) 54611195Ssam loopback = H_LOOPBK; 54711195Ssam } 54811195Ssam /* 54911195Ssam * If entire packet won't fit in message proper, just 55011195Ssam * send hyperchannel hardware header and ip header in 55111195Ssam * message proper. If that won't fit either, just send 55211195Ssam * the maximum message proper. 55311195Ssam * 55411195Ssam * This insures that the associated data is at least a 55511195Ssam * TCP/UDP header in length and thus prevents potential 55611195Ssam * problems with very short word counts. 55711195Ssam */ 55811195Ssam if (dlen > MPSIZE - sizeof (struct hy_hdr)) { 55911195Ssam mplen = sizeof(struct hy_hdr) + (ip->ip_hl << 2); 56011195Ssam if (mplen > MPSIZE) 56111195Ssam mplen = MPSIZE; 56211195Ssam } 56311195Ssam break; 56411195Ssam } 56511195Ssam #endif 56611195Ssam 56711195Ssam default: 56811195Ssam printf("hy%d: can't handle af%d\n", ifp->if_unit, dst->sa_family); 56911195Ssam #ifdef DEBUG 57011195Ssam if (hy_nodebug & 4) hy_debug_flag = 1; 57111195Ssam #endif 57211195Ssam error = EAFNOSUPPORT; 57311195Ssam goto drop; 57411195Ssam } 57511195Ssam 57611195Ssam /* 57711195Ssam * add the software and hardware hyperchannel headers. 57811195Ssam * If there's not enough space in the first mbuf, allocate another. 57911195Ssam * If that should fail, drop this sucker. 58011195Ssam * No extra space for headers is allocated. 58111195Ssam */ 58211195Ssam if (m->m_off > MMAXOFF || 58311195Ssam MMINOFF + sizeof(struct hym_hdr) > m->m_off) { 58411195Ssam m = m_get(M_DONTWAIT); 58511195Ssam if (m == 0) { 58611195Ssam m = m0; 58711195Ssam error = ENOBUFS; 58811195Ssam goto drop; 58911195Ssam } 59011195Ssam m->m_next = m0; 59111195Ssam m->m_off = MMINOFF; 59211195Ssam m->m_len = sizeof(struct hym_hdr); 59311195Ssam } else { 59411195Ssam m->m_off -= sizeof(struct hym_hdr); 59511195Ssam m->m_len += sizeof(struct hym_hdr); 59611195Ssam } 59711195Ssam hym = mtod(m, struct hym_hdr *); 59811195Ssam hym->hym_mplen = mplen; 59911195Ssam hym->hym_hdr.hyh_type = dtype; 60011195Ssam hym->hym_hdr.hyh_off = 0; 60111195Ssam hym->hym_hdr.hyh_from = htons(ifp->if_host[0]); 60211195Ssam hym->hym_hdr.hyh_param = loopback; 60311195Ssam #ifdef HYROUTE 60411195Ssam if (r->hyr_lasttime != 0) { 60511195Ssam register struct hy_hash *rh; 60611195Ssam register int i; 60711195Ssam 60811195Ssam i = HYRHASH(dhost); 60911195Ssam rh = &r->hyr_hash[i]; 61011195Ssam i = 0; 61111195Ssam while (rh->hyr_key != dhost) { 61211195Ssam rh++; i++; 61311195Ssam if (rh > &r->hyr_hash[HYRSIZE]) 61411195Ssam rh = &r->hyr_hash[0]; 61511195Ssam if (rh->hyr_flags == 0 || i > HYRSIZE) 61611195Ssam goto notfound; 61711195Ssam } 61811195Ssam if (rh->hyr_flags & HYR_GATE) { 61911195Ssam loopback = 0; /* no hardware loopback on gateways */ 62011195Ssam i = rh->hyr_nextgate; 62111195Ssam if (i >= rh->hyr_egate) 62211195Ssam rh->hyr_nextgate = rh->hyr_pgate; 62311195Ssam else 62411195Ssam rh->hyr_nextgate++; 62511195Ssam rh = &r->hyr_hash[r->hyr_gateway[i]]; 62611195Ssam if ((rh->hyr_flags & HYR_DIR) == 0) 62711195Ssam goto notfound; 62811195Ssam } 62911195Ssam hym->hym_hdr.hyh_ctl = rh->hyr_ctl; 63011195Ssam hym->hym_hdr.hyh_access = rh->hyr_access; 63111195Ssam hym->hym_hdr.hyh_to = rh->hyr_dst; 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 } 63711195Ssam #else 63811195Ssam hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS; 63911195Ssam hym->hym_hdr.hyh_access = 0; 64011195Ssam hym->hym_hdr.hyh_to = htons(dhost); 64111195Ssam #endif 64211195Ssam 64311195Ssam headerexists: 64411195Ssam 64511195Ssam if (hym->hym_mplen) { 64611195Ssam hym->hym_hdr.hyh_ctl |= H_ASSOC; 64711195Ssam #ifdef DEBUG 64811195Ssam if (hy_nodebug & 16) hy_debug_flag = 1; 64911195Ssam #endif 65011195Ssam } else hym->hym_hdr.hyh_ctl &= ~H_ASSOC; 65111195Ssam 65211195Ssam #ifdef DEBUG 65311195Ssam printD("hy%d: output mplen=%x ctl=%x access=%x to=%x (adapter %x) from=%x param=%x type=%x off=%x\n", 65411195Ssam ifp->if_unit, hym->hym_mplen, hym->hym_hdr.hyh_ctl, 65511195Ssam hym->hym_hdr.hyh_access, hym->hym_hdr.hyh_to, 65611195Ssam hym->hym_hdr.hyh_to_adapter, 65711195Ssam hym->hym_hdr.hyh_from, hym->hym_hdr.hyh_param, 65811195Ssam hym->hym_hdr.hyh_type, hym->hym_hdr.hyh_off); 65911195Ssam #endif 66011195Ssam 66111195Ssam 66211195Ssam s = splimp(); 66311195Ssam if (IF_QFULL(&ifp->if_snd)) { 66411195Ssam IF_DROP(&ifp->if_snd); 66511195Ssam error = ENOBUFS; 66611195Ssam splx(s); 66711195Ssam goto drop; 66811195Ssam } 66911195Ssam IF_ENQUEUE(&ifp->if_snd, m); 67011195Ssam if (hy_softc[ifp->if_unit].hy_state == WAITING) 67111195Ssam hyact(hyinfo[ifp->if_unit]); 67211195Ssam splx(s); 67311195Ssam return(0); 67411195Ssam 67511195Ssam notfound: 67611195Ssam error = ENETUNREACH; /* KLUDGE - should produce better error number */ 67711195Ssam drop: 67811195Ssam m_freem(m); 67911195Ssam return(error); 68011195Ssam } /* hyoutput */ 68111195Ssam 68211195Ssam hyact(ui) 68311195Ssam register struct uba_device *ui; 68411195Ssam { 68511195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 68611195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 68711195Ssam 68811195Ssam actloop: 68911195Ssam 69011195Ssam #ifdef DEBUG 69111195Ssam printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit, hy_state_names[is->hy_state]); 69211195Ssam #endif 69311195Ssam 69411195Ssam switch (is->hy_state) { 69511195Ssam 69611195Ssam case STARTUP: 69711195Ssam goto endintr; 69811195Ssam 69911195Ssam case IDLE: { 70011195Ssam register rq = is->hy_flags; 70111195Ssam 70211195Ssam if (rq & RQ_STATUS) { 70311195Ssam is->hy_flags &= ~RQ_STATUS; 70411195Ssam is->hy_state = STATSENT; 70511195Ssam hystart(ui, HYF_STATUS, sizeof(is->hy_status), is->hy_ifuba.ifu_r.ifrw_info); 70611195Ssam } else if (rq & RQ_ENDOP) { 70711195Ssam is->hy_flags &= ~RQ_ENDOP; 70811195Ssam is->hy_state = ENDOPSENT; 70911195Ssam hystart(ui, HYF_END_OP, 0, 0); 71011195Ssam } else if (rq & RQ_STATISTICS) { 71111195Ssam is->hy_flags &= ~RQ_STATISTICS; 71211195Ssam is->hy_state = RSTATSENT; 71311195Ssam hystart(ui, HYF_RSTATS, sizeof(is->hy_stat), is->hy_ifuba.ifu_r.ifrw_info); 71411195Ssam } else if (RECV_DATA(addr)) { 71511195Ssam is->hy_state = RECVSENT; 71611195Ssam is->hy_retry = 0; 71711195Ssam hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info); 71811195Ssam } else if (rq & RQ_REISSUE) { 71911195Ssam is->hy_flags &= ~RQ_REISSUE; 72011195Ssam is->hy_state = is->hy_savedstate; 72111195Ssam #ifdef DEBUG 72211195Ssam printD("hy%d: reissue cmd=0x%x count=%d ubaddr=0x%x retry=%d\n", 72311195Ssam ui->ui_unit, is->hy_savedcmd, 72411195Ssam is->hy_savedcount, is->hy_savedaddr, is->hy_retry); 72511195Ssam #endif 72611195Ssam hystart(ui, is->hy_savedcmd, is->hy_savedcount, is->hy_savedaddr); 72711195Ssam } else { 72811195Ssam register struct mbuf *m; 72911195Ssam 73011195Ssam IF_DEQUEUE(&is->hy_if.if_snd, m); 73111195Ssam if (m != 0) { 73211195Ssam register struct hym_hdr *hym; 73311195Ssam register int mplen; 73411195Ssam register int cmd; 73511195Ssam 73611195Ssam is->hy_state = XMITSENT; 73711195Ssam is->hy_retry = 0; 73811195Ssam hym = mtod(m, struct hym_hdr *); 73911195Ssam #ifdef HYLOG 74011195Ssam hylog(HYL_XMIT, sizeof(struct hym_hdr), (char *)hym); 74111195Ssam #endif 74211195Ssam mplen = hym->hym_mplen; 74311195Ssam cmd = (hym->hym_hdr.hyh_to_adapter == hym->hym_hdr.hyh_from_adapter) ? 74411195Ssam HYF_XMITLOCMSG : HYF_XMITMSG; 74511195Ssam #ifdef DEBUG 74611195Ssam printD("hy%d: hym_hdr = ", ui->ui_unit); 74711195Ssam if (hy_debug_flag) hyprintdata((char *)hym, sizeof(struct hym_hdr)); 74811195Ssam #endif 74911195Ssam /* 75011195Ssam * strip off the software part of 75111195Ssam * the hyperchannel header 75211195Ssam */ 75311195Ssam m->m_off += sizeof(struct hym_data); 75411195Ssam m->m_len -= sizeof(struct hym_data); 75511195Ssam is->hy_olen = if_wubaput(&is->hy_ifuba, m); 75611195Ssam #ifdef SUPBDP 75711195Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) 75811195Ssam UBAPURGE(is->hy_ifuba.ifu_uba, is->hy_ifuba.ifu_w.ifrw_bdp); 75911195Ssam #endif 76011195Ssam #ifdef DEBUG 76111195Ssam printD("hy%d: sending packet (mplen = %d, hy_olen = %d) data = ", 76211195Ssam ui->ui_unit, mplen, is->hy_olen); 76311195Ssam if (hy_debug_flag) hyprintdata(is->hy_ifuba.ifu_w.ifrw_addr, is->hy_olen); 76411195Ssam #endif 76511195Ssam hystart(ui, cmd, (mplen == 0) ? is->hy_olen : mplen, 76611195Ssam is->hy_ifuba.ifu_w.ifrw_info); 76711195Ssam if (mplen != 0) 76811195Ssam is->hy_flags |= RQ_XASSOC; 76911195Ssam } else if (rq & RQ_MARKDOWN) { 77011195Ssam is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN); 77111195Ssam is->hy_state = MARKPORT; 77211195Ssam is->hy_retry = 0; 77311195Ssam /* 77411195Ssam * port number is taken from status data 77511195Ssam */ 77611195Ssam hystart(ui, HYF_MARKP0 | (PORTNUM(&is->hy_status) << 2), 0, 0); 77711195Ssam } else if (rq & RQ_MARKUP) { 77811195Ssam register struct ifnet *ifp = &is->hy_if; 77911195Ssam register struct sockaddr_in *sin = (struct sockaddr_in *)&ifp->if_addr; 78011195Ssam 78111195Ssam is->hy_flags &= ~(RQ_MARKUP); 78211195Ssam is->hy_retry = 0; 78311195Ssam /* 78411195Ssam * Fill in the internet address from the status buffer 78511195Ssam */ 78611195Ssam printf("hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n", 78711195Ssam ui->ui_unit, 78811195Ssam is->hy_stat.hyc_uaddr, 78911195Ssam PORTNUM(&is->hy_status), 79011195Ssam (is->hy_stat.hyc_atype[0]<<8) | is->hy_stat.hyc_atype[1], 79111195Ssam is->hy_stat.hyc_atype[2]); 79211195Ssam 79311195Ssam ifp->if_host[0] = (is->hy_stat.hyc_uaddr << 8) | PORTNUM(&is->hy_status); 79411195Ssam sin->sin_family = AF_INET; 79511195Ssam sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]); 79611195Ssam ifp->if_flags |= IFF_UP; 79711195Ssam if_rtinit(ifp, RTF_UP); 79811195Ssam #ifdef HYLOG 79911195Ssam hylog(HYL_UP, 0, (char *)0); 80011195Ssam #endif 80111195Ssam 80211195Ssam } else { 80311195Ssam is->hy_state = WAITING; 80411195Ssam is->hy_retry = 0; 80511195Ssam hystart(ui, HYF_WAITFORMSG, 0, 0); 80611195Ssam } 80711195Ssam } 80811195Ssam } 80911195Ssam break; 81011195Ssam 81111195Ssam case STATSENT: 81211195Ssam 81311195Ssam bcopy(is->hy_ifuba.ifu_r.ifrw_addr, &is->hy_status, sizeof(struct hy_status)); 81411195Ssam #ifdef DEBUG 81511195Ssam printD("hy%d: status - %x %x %x %x %x %x %x %x\n", ui->ui_unit, 81611195Ssam is->hy_status.hys_gen_status, is->hy_status.hys_last_fcn, 81711195Ssam is->hy_status.hys_resp_trunk, is->hy_status.hys_status_trunk, 81811195Ssam is->hy_status.hys_recd_resp, is->hy_status.hys_error, 81911195Ssam is->hy_status.hys_caddr, is->hy_status.hys_pad); 82011195Ssam #endif 82111195Ssam is->hy_state = IDLE; 82211195Ssam #ifdef HYLOG 82311195Ssam hylog(HYL_STATUS, sizeof(struct hy_status), (char *)&is->hy_status); 82411195Ssam #endif 82511195Ssam #ifdef HYELOG 82611195Ssam { 82711195Ssam register int i; 82811195Ssam 82911195Ssam i = is->hy_status.hys_error; 83011195Ssam if (i < HYE_MAX) 83111195Ssam i = HYE_MAX; 83211195Ssam switch (is->hy_status.hys_last_fcn) { 83311195Ssam case HYF_XMITLOCMSG: 83411195Ssam i += HYE_MAX+1; /* fall through */ 83511195Ssam case HYF_XMITLSTDATA: 83611195Ssam i += HYE_MAX+1; /* fall through */ 83711195Ssam case HYF_XMITMSG: 83811195Ssam i += HYE_MAX+1; 83911195Ssam } 84011195Ssam hy_elog[i]++; 84111195Ssam } 84211195Ssam #endif 84311195Ssam break; 84411195Ssam 84511195Ssam case RSTATSENT: { 84611195Ssam register struct hy_stat *p = (struct hy_stat *) is->hy_ifuba.ifu_r.ifrw_addr; 84711195Ssam 84811195Ssam is->hy_stat.hyc_msgcnt = ntohl(p->hyc_msgcnt); 84911195Ssam is->hy_stat.hyc_dbcnt = ntohl(p->hyc_dbcnt); 85011195Ssam is->hy_stat.hyc_tbusy = ntohl(p->hyc_tbusy); 85111195Ssam is->hy_stat.hyc_hwret = ntohl(p->hyc_hwret); 85211195Ssam is->hy_stat.hyc_crcbad = ntohl(p->hyc_crcbad); 85311195Ssam is->hy_stat.hyc_mcret = ntohl(p->hyc_mcret); 85411195Ssam is->hy_stat.hyc_tdabort = ntohl(p->hyc_tdabort); 85511195Ssam is->hy_stat.hyc_atype[0] = p->hyc_atype[0]; 85611195Ssam is->hy_stat.hyc_atype[1] = p->hyc_atype[1]; 85711195Ssam is->hy_stat.hyc_atype[2] = p->hyc_atype[2]; 85811195Ssam is->hy_stat.hyc_uaddr = p->hyc_uaddr; 85911195Ssam 86011195Ssam #ifdef DEBUG 86111195Ssam printD("hy%d: statistics - msgcnt %d dbcnt %d hwret %d tbusy %d crcbad %d\n", 86211195Ssam ui->ui_unit, 86311195Ssam is->hy_stat.hyc_msgcnt, is->hy_stat.hyc_dbcnt, 86411195Ssam is->hy_stat.hyc_tbusy, is->hy_stat.hyc_hwret, 86511195Ssam is->hy_stat.hyc_crcbad); 86611195Ssam printD(" mcret %d tdabort %d atype %x %x %x uaddr %x\n", 86711195Ssam is->hy_stat.hyc_mcret, is->hy_stat.hyc_tdabort, 86811195Ssam is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1], 86911195Ssam is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr); 87011195Ssam #endif 87111195Ssam is->hy_state = IDLE; 87211195Ssam #ifdef HYLOG 87311195Ssam hylog(HYL_STATISTICS, sizeof(struct hy_stat), (char *)&is->hy_stat); 87411195Ssam #endif 87511195Ssam break; 87611195Ssam } 87711195Ssam 87811195Ssam case CLEARSENT: 87911195Ssam is->hy_state = IDLE; 88011195Ssam break; 88111195Ssam 88211195Ssam case ENDOPSENT: 88311195Ssam is->hy_state = IDLE; 88411195Ssam break; 88511195Ssam 88611195Ssam case RECVSENT: { 88711195Ssam register struct hy_hdr *hyh; 88811195Ssam register unsigned len; 88911195Ssam 89011195Ssam #ifdef SUPBDP 89111195Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) /* purge the BDP */ 89211195Ssam UBAPURGE(is->hy_ifuba.ifu_uba, is->hy_ifuba.ifu_r.ifrw_bdp); 89311195Ssam #endif 89411195Ssam hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 89511195Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 89611195Ssam if (len > MPSIZE) { 89711195Ssam printf("hy%d: RECVD MP > MPSIZE (%d)\n", ui->ui_unit, len); 89811195Ssam #ifdef DEBUG 89911195Ssam hy_debug_flag = 1; 90011195Ssam printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n", 90111195Ssam ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr); 90211195Ssam #endif 90311195Ssam } 90411195Ssam 90511195Ssam #ifdef DEBUG 90611195Ssam printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len); 90711195Ssam if (hy_debug_flag) hyprintdata((char *)hyh, len); 90811195Ssam #endif 90911195Ssam if (hyh->hyh_ctl & H_ASSOC) { 91011195Ssam is->hy_state = RECVDATASENT; 91111195Ssam is->hy_ilen = len; 91211195Ssam is->hy_retry = 0; 91311195Ssam hystart(ui, HYF_INPUTDATA, HYMTU-len+sizeof(struct hy_hdr), is->hy_ifuba.ifu_r.ifrw_info + len); 91411195Ssam } else { 91511195Ssam hyrecvdata(ui, hyh, len); 91611195Ssam is->hy_state = IDLE; 91711195Ssam } 91811195Ssam break; 91911195Ssam } 92011195Ssam 92111195Ssam case RECVDATASENT: { 92211195Ssam register struct hy_hdr *hyh; 92311195Ssam register unsigned len; 92411195Ssam 92511195Ssam #ifdef SUPBDP 92611195Ssam if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP) /* purge the BDP */ 92711195Ssam UBAPURGE(is->hy_ifuba.ifu_uba, is->hy_ifuba.ifu_r.ifrw_bdp); 92811195Ssam #endif 92911195Ssam hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr); 93011195Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 93111195Ssam #ifdef DEBUG 93211195Ssam printD("hy%d: recvd assoc data, len = %d, data = ", ui->ui_unit, len); 93311195Ssam if (hy_debug_flag) hyprintdata((char *)hyh + is->hy_ilen, len); 93411195Ssam #endif 93511195Ssam hyrecvdata(ui, hyh, len + is->hy_ilen); 93611195Ssam is->hy_state = IDLE; 93711195Ssam break; 93811195Ssam } 93911195Ssam 94011195Ssam case XMITSENT: 94111195Ssam if (is->hy_flags & RQ_XASSOC) { 94211195Ssam register unsigned len; /* number of bytes sent in message proper */ 94311195Ssam 94411195Ssam is->hy_flags &= ~RQ_XASSOC; 94511195Ssam is->hy_state = XMITDATASENT; 94611195Ssam is->hy_retry = 0; 94711195Ssam len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1; 94811195Ssam if (len > is->hy_olen) { 94911195Ssam printf("hy%d: xmit error - len > hy_olen [%d > %d]\n", ui->ui_unit, len, is->hy_olen); 95011195Ssam #ifdef DEBUG 95111195Ssam hy_debug_flag = 1; 95211195Ssam #endif 95311195Ssam } 95411195Ssam hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len, 95511195Ssam is->hy_ifuba.ifu_w.ifrw_info + len); 95611195Ssam break; 95711195Ssam } 95811195Ssam 95911195Ssam /* fall through to ... */ 96011195Ssam 96111195Ssam case XMITDATASENT: 96211195Ssam hyxmitdata(ui); 96311195Ssam is->hy_state = IDLE; 96411195Ssam break; 96511195Ssam 96611195Ssam case WAITING: /* wait for message complete or output requested */ 96711195Ssam if (RECV_DATA(addr)) 96811195Ssam is->hy_state = IDLE; 96911195Ssam else { 97011195Ssam is->hy_state = CLEARSENT; 97111195Ssam is->hy_retry = 0; 97211195Ssam hystart(ui, HYF_CLRWFMSG, 0, 0); 97311195Ssam } 97411195Ssam break; 97511195Ssam 97611195Ssam case MARKPORT: 97711195Ssam is->hy_state = STARTUP; 97811195Ssam is->hy_if.if_flags &= ~IFF_UP; 97911195Ssam goto endintr; 98011195Ssam 98111195Ssam default: 98211195Ssam printf("hy%d: DRIVER BUG - INVALID STATE %d\n", ui->ui_unit, is->hy_state); 98311195Ssam panic("HYPERCHANNEL IN INVALID STATE"); 98411195Ssam /*NOTREACHED*/ 98511195Ssam 98611195Ssam } /* end of switch */ 98711195Ssam 98811195Ssam if (is->hy_state == IDLE) 98911195Ssam goto actloop; 99011195Ssam endintr: 99111195Ssam 99211195Ssam #ifdef DEBUG 99311195Ssam printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit, hy_state_names[is->hy_state]); 99411195Ssam #endif 99511195Ssam return(0); 99611195Ssam } /* hyact */ 99711195Ssam 99811195Ssam /* 99911195Ssam * Called from device interrupt when recieving data. 100011195Ssam * Examine packet to determine type. Decapsulate packet 100111195Ssam * based on type and pass to type specific higher-level 100211195Ssam * input routine. 100311195Ssam */ 100411195Ssam hyrecvdata(ui, hyh0, len) 100511195Ssam struct uba_device *ui; 100611195Ssam struct hy_hdr *hyh0; 100711195Ssam int len; 100811195Ssam { 100911195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 101011195Ssam register struct hy_hdr *hyh = hyh0; 101111195Ssam struct mbuf *m; 101211195Ssam register struct ifqueue *inq; 101311195Ssam 101411195Ssam is->hy_if.if_ipackets++; 101511195Ssam #ifdef DEBUG 101611195Ssam printD("hy%d: recieved packet, len = %d (actual %d)\n", ui->ui_unit, len, len - (hyh->hyh_off + sizeof(struct hy_hdr))); 101711195Ssam #endif 101811195Ssam #ifdef HYLOG 101911195Ssam { 102011195Ssam struct { 102111195Ssam short hlen; 102211195Ssam struct hy_hdr hhdr; 102311195Ssam } hh; 102411195Ssam hh.hlen = len; 102511195Ssam hh.hhdr = *hyh; 102611195Ssam hylog(HYL_RECV, sizeof(hh), (char *)&hh); 102711195Ssam } 102811195Ssam #endif 102911195Ssam 103011195Ssam if (len > HYMTU + MPSIZE || len == 0) 103111195Ssam return; /* sanity */ 103211195Ssam 103311195Ssam /* 103411195Ssam * Pull packet off interface. 103511195Ssam */ 103611195Ssam m = if_rubaget(&is->hy_ifuba, len, 0); 103711195Ssam if (m == 0) 103811195Ssam return; 103911195Ssam 104011195Ssam switch (hyh->hyh_type) { 104111195Ssam 104211195Ssam #ifdef INET 104311195Ssam case HYLINK_IP: 104411195Ssam /* 104511195Ssam * strip the variable portion of the hyperchannel header 104611195Ssam * (fixed portion stripped in if_rubaget) 104711195Ssam */ 104811195Ssam m->m_len -= hyh->hyh_off; 104911195Ssam m->m_off += hyh->hyh_off; 105011195Ssam /* 105111195Ssam * sent the packet up the chain to IP 105211195Ssam */ 105311195Ssam schednetisr(NETISR_IP); 105411195Ssam inq = &ipintrq; 105511195Ssam break; 105611195Ssam #endif 105711195Ssam default: 105811195Ssam m_freem(m); 105911195Ssam return; 106011195Ssam } 106111195Ssam 106211195Ssam if (IF_QFULL(inq)) { 106311195Ssam IF_DROP(inq); 106411195Ssam m_freem(m); 106511195Ssam } else 106611195Ssam IF_ENQUEUE(inq, m); 106711195Ssam } /* hyrecvdata */ 106811195Ssam 106911195Ssam /* 107011195Ssam * transmit done, release resources, bump counters 107111195Ssam */ 107211195Ssam hyxmitdata(ui) 107311195Ssam struct uba_device *ui; 107411195Ssam { 107511195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 107611195Ssam 107711195Ssam is->hy_if.if_opackets++; 107811195Ssam 107911195Ssam if (is->hy_ifuba.ifu_xtofree) { /* free left over pages */ 108011195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 108111195Ssam is->hy_ifuba.ifu_xtofree = 0; 108211195Ssam } 108311195Ssam } /* hyxmitdata */ 108411195Ssam 108511195Ssam hycancel(ui) 108611195Ssam register struct uba_device *ui; 108711195Ssam { 108811195Ssam register struct hy_softc *is = &hy_softc[ui->ui_unit]; 108911195Ssam 109011195Ssam if (is->hy_ifuba.ifu_xtofree) { /* free left over pages */ 109111195Ssam m_freem(is->hy_ifuba.ifu_xtofree); 109211195Ssam is->hy_ifuba.ifu_xtofree = 0; 109311195Ssam } 109411195Ssam 109511195Ssam #ifdef DEBUG 109611195Ssam if (hy_nodebug & 1) hy_debug_flag = 1; 109711195Ssam #endif 109811195Ssam 109911195Ssam #ifdef DEBUG 110011195Ssam printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n", 110111195Ssam ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd, 110211195Ssam is->hy_savedcount, is->hy_savedaddr); 110311195Ssam printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n", 110411195Ssam is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr, is->hy_retry, 110511195Ssam is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr, is->hy_savedcmd); 110611195Ssam #endif 110711195Ssam is->hy_state = IDLE; 110811195Ssam is->hy_flags |= (RQ_ENDOP | RQ_STATUS); 110911195Ssam hyact(ui); 111011195Ssam } /* hycancel */ 111111195Ssam 111211195Ssam #ifdef DEBUG 111311195Ssam hyprintdata(cp, len) 111411195Ssam register char *cp; 111511195Ssam register int len; 111611195Ssam { 111711195Ssam register int count = 16; 111811195Ssam register char *fmt; 111911195Ssam static char regfmt[] = "\n\t %x"; 112011195Ssam 112111195Ssam fmt = ®fmt[2]; 112211195Ssam while (--len >= 0) { 112311195Ssam printL(fmt, *cp++ & 0xff); 112411195Ssam fmt = ®fmt[2]; 112511195Ssam if (--count <= 0) { 112611195Ssam fmt = ®fmt[0]; 112711195Ssam count = 16; 112811195Ssam } 112911195Ssam } 113011195Ssam printL("\n"); 113111195Ssam } 113211195Ssam #endif 113311195Ssam 113411195Ssam hywatch(unit) 113511195Ssam int unit; 113611195Ssam { 113711195Ssam register struct hy_softc *is = &hy_softc[unit]; 113811195Ssam register struct uba_device *ui = hyinfo[unit]; 113911195Ssam register struct hydevice *addr = (struct hydevice *)ui->ui_addr; 114011195Ssam int s; 114111195Ssam 114211195Ssam s = splimp(); 114311195Ssam is->hy_if.if_timer = SCANINTERVAL; 114411195Ssam if (is->hy_ntime > 2 && is->hy_state != WAITING && is->hy_state != STARTUP && is->hy_state != IDLE) { 114511195Ssam printf("hy%d: watchdog timer expired\n", unit); 114611195Ssam hycancel(ui); 114711195Ssam } 114811195Ssam #ifdef PI13 114911195Ssam if ((addr->hyd_csr & S_POWEROFF) != 0) { 115011195Ssam addr->hyd_csr |= S_POWEROFF; 115111195Ssam DELAY(100); 115211195Ssam if ((addr->hyd_csr & S_POWEROFF) == 0) { 115311195Ssam printf("hy%d: adapter power restored\n", unit); 115411195Ssam is->hy_state = IDLE; 115511195Ssam is->hy_flags |= (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS); 115611195Ssam hyact(ui); 115711195Ssam } 115811195Ssam } 115911195Ssam #endif 116011195Ssam splx(s); 116111195Ssam } 116211195Ssam 116311195Ssam #ifdef HYLOG 116411195Ssam hylog(code, len, ptr) 116511195Ssam int code; 116611195Ssam int len; 116711195Ssam char *ptr; 116811195Ssam { 116911195Ssam register unsigned char *p; 117011195Ssam int s; 117111195Ssam 117211195Ssam s = splimp(); 117311195Ssam 117411195Ssam if (hy_log.hyl_self != &hy_log) { 117511195Ssam hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE]; 117611195Ssam hy_log.hyl_ptr = &hy_log.hyl_buf[0]; 117711195Ssam hy_log.hyl_self = &hy_log; 117811195Ssam hy_log.hyl_enable = HYL_DISABLED; 117911195Ssam hy_log.hyl_onerr = HYL_CATCH1; 118011195Ssam } 118111195Ssam 118211195Ssam if (hy_log.hyl_enable == HYL_DISABLED 118311195Ssam || hy_log.hyl_enable == HYL_CAUGHT1 118411195Ssam || hy_log.hyl_enable == HYL_CAUGHTSTATUS 118511195Ssam || (hy_log.hyl_enable == HYL_CATCHSTATUS && code != HYL_STATUS)) 118611195Ssam goto out; 118711195Ssam 118811195Ssam p = hy_log.hyl_ptr; 118911195Ssam 119011195Ssam if (p + len + 2 >= hy_log.hyl_eptr) { 119111195Ssam bzero(p, hy_log.hyl_eptr - p); 119211195Ssam p = &hy_log.hyl_buf[0]; 119311195Ssam if (hy_log.hyl_enable == HYL_CATCH1) { 119411195Ssam hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHT1; 119511195Ssam goto out; 119611195Ssam } 119711195Ssam if (hy_log.hyl_enable == HYL_CATCHSTATUS) { 119811195Ssam hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHTSTATUS; 119911195Ssam goto out; 120011195Ssam } 120111195Ssam } 120211195Ssam 120311195Ssam *p++ = code; 120411195Ssam *p++ = len; 120511195Ssam bcopy(ptr, p, len); 120611195Ssam hy_log.hyl_ptr = p + len; 120711195Ssam out: 120811195Ssam splx(s); 120911195Ssam } 121011195Ssam #endif 121111195Ssam 121211195Ssam hyioctl(dev, cmd, addr, flag) 121311195Ssam dev_t dev; 121411195Ssam int cmd; 121511195Ssam caddr_t addr; 121611195Ssam int flag; 121711195Ssam { 121811195Ssam register struct hyroute *r = &hy_route[minor(dev)]; 121911195Ssam register int s; 122011195Ssam 122111195Ssam if (minor(dev) >= NHY) { 122211195Ssam u.u_error = ENXIO; 122311195Ssam return; 122411195Ssam } 122511195Ssam s = splimp(); 122611195Ssam 122711195Ssam switch(cmd) { 122811195Ssam 122911195Ssam case HYSETROUTE: 123011195Ssam if (suser()) { 123111195Ssam if (copyin(addr, (caddr_t)r, sizeof(*r))) 123211195Ssam u.u_error = EFAULT; 123311195Ssam r->hyr_lasttime = time; 123411195Ssam } 123511195Ssam break; 123611195Ssam 123711195Ssam case HYGETROUTE: 123811195Ssam if (copyout((caddr_t)r, addr, sizeof(*r))) 123911195Ssam u.u_error = EFAULT; 124011195Ssam break; 124111195Ssam 124211195Ssam default: 124311195Ssam u.u_error = ENXIO; 124411195Ssam break; 124511195Ssam } 124611195Ssam splx(s); 124711195Ssam } 1248