xref: /csrg-svn/sys/vax/if/if_hy.c (revision 13065)
1 /*	if_hy.c	4.7	83/06/13	*/
2 
3 #include "hy.h"
4 #if NHY > 0
5 
6 /*
7  * Network Systems Copropration Hyperchanel interface
8  *
9  * UNTESTED WITH 4.2
10  */
11 #include "../machine/pte.h"
12 
13 #include "../h/param.h"
14 #include "../h/systm.h"
15 #include "../h/mbuf.h"
16 #include "../h/buf.h"
17 #include "../h/protosw.h"
18 #include "../h/socket.h"
19 #include "../h/vmmac.h"
20 #include "../h/errno.h"
21 #include "../h/time.h"
22 #include "../h/kernel.h"
23 #include "../h/ioctl.h"
24 #include "../net/if.h"
25 #include "../net/netisr.h"
26 #include "../net/route.h"
27 #include "../netinet/in.h"
28 #include "../netinet/in_systm.h"
29 #include "../netinet/ip.h"
30 #include "../netinet/ip_var.h"
31 
32 #include "../vax/cpu.h"
33 #include "../vax/mtpr.h"
34 #include "../vaxuba/ubareg.h"
35 #include "../vaxuba/ubavar.h"
36 #include "../vaxif/if_hy.h"
37 #include "../vaxif/if_hyreg.h"
38 #include "../vaxif/if_uba.h"
39 
40 #define HYROUTE
41 #define HYELOG
42 #define	HYMTU	576
43 
44 int	hyprobe(), hyattach(), hyinit(), hyioctl();
45 int	hyoutput(), hyreset(), hywatch();
46 struct	uba_device *hyinfo[NHY];
47 u_short hystd[] = { 0772410, 0 };
48 struct	uba_driver hydriver =
49 	{ hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo };
50 
51 /*
52  * Hyperchannel software status per interface.
53  *
54  * Each interface is referenced by a network interface structure,
55  * hy_if, which the routing code uses to locate the interface.
56  * This structure contains the output queue for the interface, its address, ...
57  * We also have, for each interface, a UBA interface structure, which
58  * contains information about the UNIBUS resources held by the interface:
59  * map registers, buffered data paths, etc.  Information is cached in this
60  * structure for use by the if_uba.c routines in running the interface
61  * efficiently.
62  */
63 struct	hy_softc {
64 	struct	ifnet hy_if;		/* network-visible interface */
65 	struct	ifuba hy_ifuba;		/* UNIBUS resources */
66 	short	hy_flags;		/* flags */
67 	short	hy_state;		/* driver state */
68 	int	hy_ilen;		/* mp length on input */
69 	int	hy_olen;		/* packet length on output */
70 	int	hy_lastwcr;		/* last command's word count */
71 	short	hy_savedstate;		/* saved for reissue after status */
72 	short	hy_savedcmd;		/* saved command for reissue */
73 	int	hy_savedcount;		/* saved byte count for reissue */
74 	int	hy_savedaddr;		/* saved unibus address for reissue */
75 	int	hy_ntime;		/* number of timeouts since last cmd */
76 	int	hy_retry;		/* retry counter */
77 	struct	hy_stat hy_stat;	/* statistics */
78 	struct	hy_status hy_status;	/* status */
79 } hy_softc[NHY];
80 
81 #ifdef HYELOG
82 #define HYE_MAX	0x18
83 u_long	hy_elog[(HYE_MAX+1)*4];
84 #endif
85 
86 #ifdef DEBUG
87 #define printL	lprintf
88 #define printD	if (hy_debug_flag) lprintf
89 int	hy_debug_flag = 0;
90 /*
91  * hy_nodebug bit 0x01	set hy_debug_flag on hycancel
92  * hy_nodebug bit 0x02	set hy_debug_flag on command reissue
93  * hy_nodebug bit 0x04	set hy_debug_flag on abnormal interrupt
94  * hy_nodebug bit 0x08	set hy_debug_flag on hyouput
95  * hy_nodebug bit 0x10	set hy_debug_flag on hyouput with associated data
96  */
97 int	hy_nodebug = 0x0;
98 #else
99 #define printD	hyvoid
100 #endif
101 
102 /*
103  * Requests for service (in order by descending priority).
104  */
105 #define RQ_ENDOP	001	/* end the last adapter function */
106 #define RQ_REISSUE	002	/* reissue previous cmd after status */
107 #define RQ_STATUS	004	/* get the status of the adapter */
108 #define RQ_STATISTICS	010	/* get the statistics of the adapter */
109 #define RQ_MARKDOWN	020	/* mark this adapter port down */
110 #define RQ_MARKUP	040	/* mark this interface up */
111 
112 #define RQ_XASSOC	0100	/* associated data to transmit */
113 
114 /*
115  * Driver states.
116  */
117 #define	STARTUP		0	/* initial state (before fully there) */
118 #define	IDLE		1	/* idle state */
119 #define	STATSENT	2	/* status cmd sent to adapter */
120 #define	ENDOPSENT	3	/* end operation cmd sent */
121 #define	RECVSENT	4	/* input message cmd sent */
122 #define	RECVDATASENT	5	/* input data cmd sent */
123 #define	XMITSENT	6	/* transmit message cmd sent */
124 #define	XMITDATASENT	7	/* transmit data cmd sent */
125 #define	WAITING		8	/* waiting for messages */
126 #define	CLEARSENT	9	/* clear wait for message cmd sent */
127 #define MARKPORT	10	/* mark this host's adapter port down issued */
128 #define RSTATSENT	11	/* read statistics cmd sent to adapter */
129 
130 #ifdef DEBUG
131 char *hy_state_names[] = {
132 	"Startup",
133 	"Idle",
134 	"Status Sent",
135 	"End op Sent",
136 	"Recieve Message Proper Sent",
137 	"Recieve Data Sent",
138 	"Transmit Message Proper Sent",
139 	"Transmit Data Sent",
140 	"Wait for Message Sent",
141 	"Clear Wait for Message Sent",
142 	"Mark Port Down Sent",
143 	"Read Statistics Sent"
144 };
145 #endif
146 
147 #define SCANINTERVAL	10	/* seconds */
148 #define MAXINTERVAL	20	/* seconds (max action) */
149 
150 /*
151  * Cause a device interrupt.  This code uses a buffer starting at
152  * location zero on the unibus (which is already mapped by the
153  * autoconfigure code in the kernel).
154  */
155 hyprobe(reg)
156 	caddr_t reg;
157 {
158 	register int br, cvec;		/* r11, r10 value-result */
159 	register struct hydevice *addr = (struct hydevice *) reg;
160 
161 #ifdef lint
162 	br = 0; cvec = br; br = cvec;
163 	hyint(0);
164 #endif
165 	/*
166 	 * request adapter status to a buffer starting at unibus location 0
167 	 */
168 	addr->hyd_bar = 0;
169 	addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1);
170 	addr->hyd_dbuf = HYF_STATUS;
171 #ifdef PI13
172 	addr->hyd_csr |= S_GO | S_IE | S_IATTN;
173 #else
174 	addr->hyd_csr |= S_GO | S_IE;
175 #endif
176 	DELAY(10000);
177 #ifdef PI13
178 	addr->hyd_csr |= S_CLRINT;	/* clear any stacked interrupts */
179 #endif
180 	addr->hyd_csr &= ~(S_IE | S_CLRINT);	/* disable further interrupts */
181 	return(1);
182 }
183 
184 /*
185  * Interface exists: make available by filling in network interface
186  * record.  System will initialize the interface when it is ready
187  * to accept packets.
188  */
189 hyattach(ui)
190 	struct uba_device *ui;
191 {
192 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
193 	register struct ifnet *ifp = &is->hy_if;
194 
195 	ifp->if_unit = ui->ui_unit;
196 	ifp->if_name = "hy";
197 	ifp->if_mtu = HYMTU;
198 	is->hy_state = STARTUP;		/* don't allow state transitions yet */
199 	ifp->if_init = hyinit;
200 	ifp->if_ioctl = hyioctl;
201 	ifp->if_output = hyoutput;
202 	ifp->if_reset = hyreset;
203 	ifp->if_watchdog = hywatch;
204 	ifp->if_timer = SCANINTERVAL;
205 	is->hy_ifuba.ifu_flags = UBA_CANTWAIT;
206 #ifdef notdef
207 	is->hy_ifuba.ifu_flags |= UBA_NEEDBDP;
208 #endif
209 	if_attach(ifp);
210 }
211 
212 /*
213  * Reset of interface after UNIBUS reset.
214  * If interface is on specified uba, reset its state.
215  */
216 hyreset(unit, uban)
217 	int unit, uban;
218 {
219 	register struct uba_device *ui = hyinfo[unit];
220 
221 	if (unit >= NHY || ui == 0 || ui->ui_alive == 0 ||
222 	  ui->ui_ubanum != uban)
223 		return;
224 	printf(" hy%d", unit);
225 	hyinit(unit);
226 }
227 
228 /*
229  * Initialization of interface; clear recorded pending
230  * operations, and reinitialize UNIBUS usage.
231  */
232 hyinit(unit)
233 	int unit;
234 {
235 	register struct hy_softc *is = &hy_softc[unit];
236 	register struct uba_device *ui = hyinfo[unit];
237 	struct sockaddr_in *sin;
238 	int s;
239 
240 	sin = (struct sockaddr_in *)&is->is_if.if_addr;
241 	if (in_netof(sin->sin_addr) == 0)
242 		return;
243 	if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum,
244 	    sizeof (struct hy_hdr), (int)btoc(HYMTU)) == 0) {
245 #ifdef DEBUG
246 		if (hy_nodebug & 4)
247 			hy_debug_flag = 1;
248 #endif
249 		printf("hy%d: can't initialize\n", unit);
250 		is->hy_if.if_flags &= ~IFF_UP;
251 		return;
252 	}
253 	is->is_hy.if_flags |= IFF_RUNNING;
254 	/*
255 	 * Issue wait for message and start the state machine
256 	 */
257 	s = splimp();
258 	is->hy_state = IDLE;
259 	is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP;
260 	is->hy_retry = 0;
261 	hyact(ui);
262 	splx(s);
263 }
264 
265 /*
266  * Issue a command to the adapter
267  */
268 hystart(ui, cmd, count, ubaddr)
269 	struct uba_device *ui;
270 	int cmd, count, ubaddr;
271 {
272 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
273 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
274 
275 #ifdef DEBUG
276 	printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n",
277 		ui->ui_unit, cmd, count, ubaddr);
278 	printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
279 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
280 		addr->hyd_wcr);
281 #endif
282 	if (((is->hy_flags & RQ_REISSUE) == 0) &&
283 	  (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) {
284 		is->hy_savedstate = is->hy_state;
285 		is->hy_savedcmd = cmd;
286 		is->hy_savedcount = count;
287 		is->hy_savedaddr = ubaddr;
288 	}
289 	addr->hyd_bar = ubaddr & 0xffff;
290 	addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1);
291 	addr->hyd_dbuf = cmd;
292 #ifdef PI13
293 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN;
294 #else
295 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE;
296 #endif
297 #ifdef DEBUG
298 	printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
299 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
300 		addr->hyd_wcr);
301 #endif
302 #ifdef HYLOG
303 	{
304 		struct {
305 			u_char	hcmd;
306 			u_char	hstate;
307 			short	hcount;
308 		} hcl;
309 
310 		hcl.hcmd = cmd;
311 		hcl.hstate = is->hy_state;
312 		hcl.hcount = count;
313 		hylog(HYL_CMD, sizeof(hcl), (char *)&hcl);
314 	}
315 #endif
316 	is->hy_ntime = 0;
317 }
318 
319 int hyint_active = 0;		/* set during hy interrupt */
320 /*
321  * Hyperchannel interface interrupt.
322  *
323  * An interrupt can occur for many reasons.  Examine the status of
324  * the hyperchannel status bits to determine what to do next.
325  *
326  * If input error just drop packet.
327  * Otherwise purge input buffered data path and examine
328  * packet to determine type.  Othewise decapsulate
329  * packet based on type and pass to type specific higher-level
330  * input routine.
331  */
332 hyint(unit)
333 	int unit;
334 {
335 	register struct hy_softc *is = &hy_softc[unit];
336 	register struct uba_device *ui = hyinfo[unit];
337 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
338 
339 	if (hyint_active)
340 		panic("RECURSIVE HYPERCHANNEL INTERRUPT");
341 	hyint_active++;
342 #ifdef DEBUG
343 	printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
344 		unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
345 #endif
346 #ifdef HYLOG
347 logit:
348 	{
349 		struct {
350 			u_char	hstate;
351 			u_char	hflags;
352 			short	hcsr;
353 			short	hwcr;
354 		} hil;
355 		hil.hstate = is->hy_state;
356 		hil.hflags = is->hy_flags;
357 		hil.hcsr = addr->hyd_csr;
358 		hil.hwcr = addr->hyd_wcr;
359 		hylog(HYL_INT, sizeof(hil), (char *)&hil);
360 	}
361 #endif
362 	if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) {
363 		/*
364 		 * Error bit set, some sort of error in the interface.
365 		 *
366 		 * The adapter sets attn on command completion so that's not
367 		 * a real error even though the interface considers it one.
368 		 */
369 #ifdef DEBUG
370 		if (hy_nodebug & 4)
371 			hy_debug_flag = 1;
372 #endif
373 		printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n",
374 			addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
375 			addr->hyd_wcr);
376 		if (addr->hyd_csr & S_NEX) {
377 			printf("hy%d: NEX - Non Existant Memory\n", unit);
378 #ifdef PI13
379 			addr->hyd_csr |= S_NEX;  /* as per PI13 manual */
380 #else
381 			addr->hyd_csr &= ~S_NEX;
382 #endif
383 			hycancel(ui);
384 #ifdef PI13
385 		} else if (addr->hyd_csr & S_POWEROFF) {
386 			printf("hy%d: Power Off bit set, trying to reset\n",
387 				unit);
388 			addr->hyd_csr |= S_POWEROFF;
389 			DELAY(100);
390 			if (addr->hyd_csr & S_POWEROFF) {
391 				if_down(&is->hy_if);
392 				is->hy_state = STARTUP;
393 				printf(
394 				  "hy%d: Power Off Error, network shutdown\n",
395 				  unit);
396 			}
397 #endif
398 		} else {
399 			printf("hy%d:  BAR overflow\n", unit);
400 			hycancel(ui);
401 		}
402 	} else if (HYS_NORMAL(addr)) {
403 		/*
404 		 * Normal interrupt, bump state machine unless in state
405 		 * waiting and no data present (assumed to be word count
406 		 * zero interrupt or other hardware botch).
407 		 */
408 		if (is->hy_state != WAITING || HYS_RECVDATA(addr))
409 			hyact(ui);
410 	} else if (HYS_ABNORMAL(addr)) {
411 		/*
412 		 * Abnormal termination.
413 		 * bump error counts, retry the last function
414 		 * 'MAXRETRY' times before kicking the bucket.
415 		 *
416 		 * Don't reissue the cmd if in certain states, abnormal
417 		 * on a reissued cmd or max retry exceeded.
418 		 */
419 #ifdef HYLOG
420 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
421 			hy_log.hyl_enable = hy_log.hyl_onerr;
422 			goto logit;
423 		}
424 #endif
425 #ifdef DEBUG
426 		if (hy_nodebug & 4)
427 			hy_debug_flag = 1;
428 		printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n",
429 			unit, hy_state_names[is->hy_state], is->hy_state);
430 		printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n",
431 			is->hy_flags, is->hy_ilen, is->hy_olen,
432 			is->hy_lastwcr, is->hy_retry);
433 		printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n",
434 			is->hy_savedstate, is->hy_savedcount,
435 			is->hy_savedaddr, is->hy_savedcmd);
436 #endif
437 #ifdef PI13
438 		addr->hyd_csr &= ~S_C;  /* clear the damned PI-13 */
439 #endif
440 		if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT)
441 			is->hy_if.if_oerrors++;
442 		if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT)
443 			is->hy_if.if_ierrors++;
444 		if (is->hy_state == XMITDATASENT ||
445 		    is->hy_state == RECVSENT ||
446 		    is->hy_state == RECVDATASENT ||
447 		    (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY)
448 			hycancel(ui);
449 		else {
450 #ifdef DEBUG
451 			if (hy_nodebug & 2)
452 				hy_debug_flag = 1;
453 #endif
454 			is->hy_retry++;
455 			is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE;
456 			is->hy_state = IDLE;
457 			hyact(ui);
458 		}
459 	} else {
460 		/*
461 		 * Interrupt is neither normal, abnormal, or interface error.
462 		 * Ignore it. It's either stacked or a word count 0.
463 		 */
464 #ifdef HYLOG
465 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
466 			hy_log.hyl_enable = hy_log.hyl_onerr;
467 			goto logit;
468 		}
469 #endif
470 #ifdef DEBUG
471 		printD("hy%d: possible stacked interrupt ignored\n", unit);
472 #endif
473 	}
474 #ifdef DEBUG
475 	printD("hy%d: hyint exit\n\n", unit);
476 #endif
477 	hyint_active = 0;
478 
479 }
480 
481 /*
482  * Encapsulate a packet of type family for the local net.
483  * Use trailer local net encapsulation if enough data in first
484  * packet leaves a multiple of 512 bytes of data in remainder.
485  */
486 hyoutput(ifp, m0, dst)
487 	struct ifnet *ifp;
488 	struct mbuf *m0;
489 	struct sockaddr *dst;
490 {
491 	register struct hym_hdr *hym;
492 	register struct mbuf *m;
493 #ifdef HYROUTE
494 	register struct hyroute *r = &hy_route[ifp->if_unit];
495 #endif
496 	short dtype;		/* packet type */
497 	int dhost;		/* destination adapter address */
498 	int dlen;
499 	int mplen = 0;		/* message proper length */
500 	short loopback = 0;	/* hardware loopback requested */
501 	int error = 0;
502 	int s;
503 
504 #ifdef DEBUG
505 	if (hy_nodebug & 8)
506 		hy_debug_flag = 1;
507 #endif
508 	dlen = 0;
509 	for (m = m0; m; m = m->m_next)
510 		dlen += m->m_len;
511 	m = m0;
512 	switch(dst->sa_family) {
513 
514 #ifdef INET
515 	case AF_INET: {
516 		register struct ip *ip = mtod(m, struct ip *);
517 		register struct sockaddr_in *sin = (struct sockaddr_in *)dst;
518 		register long hostaddr = in_lnaof(sin->sin_addr);
519 
520 		dhost = hostaddr & 0xffff;
521 		dtype = HYLINK_IP;
522 #ifdef DEBUG
523 		printD("hy%d: output to host %x, dhost %x\n",
524 			ifp->if_unit, sin->sin_addr.s_addr, dhost);
525 #endif
526 		/*
527 		 * Debugging loopback support:
528 		 * upper byte of 24 bit host number interpreted as follows
529 		 *	0x00 --> no loopback
530 		 *	0x01 --> hardware loop through remote adapter
531 		 *	other --> software loop through remote ip layer
532 		 */
533 		if (hostaddr & 0xff0000) {
534 			struct in_addr temp;
535 
536 			temp = ip->ip_dst;
537 			ip->ip_dst = ip->ip_src;
538 			ip->ip_src = temp;
539 			if ((hostaddr & 0xff0000) == 0x10000)
540 				loopback = H_LOOPBK;
541 		}
542 		/*
543 		 * If entire packet won't fit in message proper, just
544 		 * send hyperchannel hardware header and ip header in
545 		 * message proper.  If that won't fit either, just send
546 		 * the maximum message proper.
547 		 *
548 		 * This insures that the associated data is at least a
549 		 * TCP/UDP header in length and thus prevents potential
550 		 * problems with very short word counts.
551 		 */
552 		if (dlen > MPSIZE - sizeof (struct hy_hdr)) {
553 			mplen = sizeof(struct hy_hdr) + (ip->ip_hl << 2);
554 			if (mplen > MPSIZE)
555 				mplen = MPSIZE;
556 		}
557 		break;
558 	}
559 #endif
560 
561 	default:
562 		printf("hy%d: can't handle af%d\n", ifp->if_unit,
563 			dst->sa_family);
564 #ifdef DEBUG
565 		if (hy_nodebug & 4)
566 			hy_debug_flag = 1;
567 #endif
568 		error = EAFNOSUPPORT;
569 		goto drop;
570 	}
571 
572 	/*
573 	 * Add the software and hardware hyperchannel headers.
574 	 * If there's not enough space in the first mbuf, allocate another.
575 	 * If that should fail, drop this sucker.
576 	 * No extra space for headers is allocated.
577 	 */
578 	if (m->m_off > MMAXOFF ||
579 	    MMINOFF + sizeof(struct hym_hdr) > m->m_off) {
580 		m = m_get(M_DONTWAIT, MT_HEADER);
581 		if (m == 0) {
582 			m = m0;
583 			error = ENOBUFS;
584 			goto drop;
585 		}
586 		m->m_next = m0;
587 		m->m_off = MMINOFF;
588 		m->m_len = sizeof(struct hym_hdr);
589 	} else {
590 		m->m_off -= sizeof(struct hym_hdr);
591 		m->m_len += sizeof(struct hym_hdr);
592 	}
593 	hym = mtod(m, struct hym_hdr *);
594 	hym->hym_mplen = mplen;
595 	hym->hym_hdr.hyh_type = dtype;
596 	hym->hym_hdr.hyh_off = 0;
597 	hym->hym_hdr.hyh_from = htons((u_short)ifp->if_host[0]);
598 	hym->hym_hdr.hyh_param = loopback;
599 #ifdef HYROUTE
600 	if (r->hyr_lasttime.tv_sec != 0) {
601 		register struct hy_hash *rh;
602 		register int i;
603 
604 		i = HYRHASH(dhost);
605 		rh = &r->hyr_hash[i];
606 		i = 0;
607 		while (rh->hyr_key != dhost) {
608 			rh++; i++;
609 			if (rh > &r->hyr_hash[HYRSIZE])
610 				rh = &r->hyr_hash[0];
611 			if (rh->hyr_flags == 0 || i > HYRSIZE)
612 				goto notfound;
613 		}
614 		if (rh->hyr_flags & HYR_GATE) {
615 			loopback = 0;	/* no hardware loopback on gateways */
616 			i = rh->hyr_nextgate;
617 			if (i >= rh->hyr_egate)
618 				rh->hyr_nextgate = rh->hyr_pgate;
619 			else
620 				rh->hyr_nextgate++;
621 			rh = &r->hyr_hash[r->hyr_gateway[i]];
622 			if ((rh->hyr_flags & HYR_DIR) == 0)
623 				goto notfound;
624 		}
625 		hym->hym_hdr.hyh_ctl = rh->hyr_ctl;
626 		hym->hym_hdr.hyh_access = rh->hyr_access;
627 		hym->hym_hdr.hyh_to = rh->hyr_dst;
628 	} else {
629 		hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS;
630 		hym->hym_hdr.hyh_access = 0;
631 		hym->hym_hdr.hyh_to = htons((u_short)dhost);
632 	}
633 #else
634 	hym->hym_hdr.hyh_ctl = H_XTRUNKS | H_RTRUNKS;
635 	hym->hym_hdr.hyh_access = 0;
636 	hym->hym_hdr.hyh_to = htons(dhost);
637 #endif
638 
639 	if (hym->hym_mplen) {
640 		hym->hym_hdr.hyh_ctl |= H_ASSOC;
641 #ifdef DEBUG
642 		if (hy_nodebug & 16)
643 			hy_debug_flag = 1;
644 #endif
645 	} else
646 		hym->hym_hdr.hyh_ctl &= ~H_ASSOC;
647 #ifdef DEBUG
648 	printD("hy%d: output mplen=%x ctl=%x access=%x to=%x",
649 		ifp->if_unit, hym->hym_mplen, hym->hym_hdr.hyh_ctl,
650 		hym->hym_hdr.hyh_access, hym->hym_hdr.hyh_to);
651 	printD(" (adapter %x) from=%x param=%x type=%x off=%x\n",
652 		hym->hym_hdr.hyh_to_adapter,
653 		hym->hym_hdr.hyh_from, hym->hym_hdr.hyh_param,
654 		hym->hym_hdr.hyh_type, hym->hym_hdr.hyh_off);
655 #endif
656 	s = splimp();
657 	if (IF_QFULL(&ifp->if_snd)) {
658 		IF_DROP(&ifp->if_snd);
659 		error = ENOBUFS;
660 		splx(s);
661 		goto drop;
662 	}
663 	IF_ENQUEUE(&ifp->if_snd, m);
664 	if (hy_softc[ifp->if_unit].hy_state == WAITING)
665 		hyact(hyinfo[ifp->if_unit]);
666 	splx(s);
667 	return (0);
668 notfound:
669 	error = ENETUNREACH;			/* XXX */
670 drop:
671 	m_freem(m);
672 	return (error);
673 }
674 
675 hyact(ui)
676 	register struct uba_device *ui;
677 {
678 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
679 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
680 
681 actloop:
682 #ifdef DEBUG
683 	printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit,
684 		hy_state_names[is->hy_state]);
685 #endif
686 	switch (is->hy_state) {
687 
688 	case STARTUP:
689 		goto endintr;
690 
691 	case IDLE: {
692 		register rq = is->hy_flags;
693 
694 		if (rq & RQ_STATUS) {
695 			is->hy_flags &= ~RQ_STATUS;
696 			is->hy_state = STATSENT;
697 			hystart(ui, HYF_STATUS, sizeof (is->hy_status),
698 				is->hy_ifuba.ifu_r.ifrw_info);
699 		} else if (rq & RQ_ENDOP) {
700 			is->hy_flags &= ~RQ_ENDOP;
701 			is->hy_state = ENDOPSENT;
702 			hystart(ui, HYF_END_OP, 0, 0);
703 		} else if (rq & RQ_STATISTICS) {
704 			is->hy_flags &= ~RQ_STATISTICS;
705 			is->hy_state = RSTATSENT;
706 			hystart(ui, HYF_RSTATS, sizeof (is->hy_stat),
707 				is->hy_ifuba.ifu_r.ifrw_info);
708 		} else if (HYS_RECVDATA(addr)) {
709 			is->hy_state = RECVSENT;
710 			is->hy_retry = 0;
711 			hystart(ui, HYF_INPUTMSG, MPSIZE,
712 				is->hy_ifuba.ifu_r.ifrw_info);
713 		} else if (rq & RQ_REISSUE) {
714 			is->hy_flags &= ~RQ_REISSUE;
715 			is->hy_state = is->hy_savedstate;
716 #ifdef DEBUG
717 			printD("hy%d: reissue cmd=0x%x count=%d",
718 			  ui->ui_unit, is->hy_savedcmd, is->hy_savedcount);
719 			printD(" ubaddr=0x%x retry=%d\n",
720 			  is->hy_savedaddr, is->hy_retry);
721 #endif
722 			hystart(ui, is->hy_savedcmd, is->hy_savedcount,
723 				is->hy_savedaddr);
724 		} else {
725 			register struct mbuf *m;
726 
727 			IF_DEQUEUE(&is->hy_if.if_snd, m);
728 			if (m != NULL) {
729 				register struct hym_hdr *hym;
730 				register int mplen;
731 				register int cmd;
732 
733 				is->hy_state = XMITSENT;
734 				is->hy_retry = 0;
735 				hym = mtod(m, struct hym_hdr *);
736 #ifdef HYLOG
737 				hylog(HYL_XMIT, sizeof(struct hym_hdr),
738 					(char *)hym);
739 #endif
740 				mplen = hym->hym_mplen;
741 				if (hym->hym_hdr.hyh_to_adapter ==
742 				  hym->hym_hdr.hyh_from_adapter)
743 					cmd = HYF_XMITLOCMSG;
744 				else
745 					cmd = HYF_XMITMSG;
746 #ifdef DEBUG
747 				printD("hy%d: hym_hdr = ", ui->ui_unit);
748 				if (hy_debug_flag)
749 					hyprintdata((char *)hym,
750 					  sizeof (struct hym_hdr));
751 #endif
752 				/*
753 				 * Strip off the software part of
754 				 * the hyperchannel header
755 				 */
756 				m->m_off += sizeof(struct hym_data);
757 				m->m_len -= sizeof(struct hym_data);
758 				is->hy_olen = if_wubaput(&is->hy_ifuba, m);
759 				if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
760 					UBAPURGE(is->hy_ifuba.ifu_uba,
761 						is->hy_ifuba.ifu_w.ifrw_bdp);
762 #ifdef DEBUG
763 				printD(
764 		"hy%d: sending packet (mplen = %d, hy_olen = %d) data = ",
765 					ui->ui_unit, mplen, is->hy_olen);
766 				if (hy_debug_flag)
767 					hyprintdata(
768 					  is->hy_ifuba.ifu_w.ifrw_addr,
769 					  is->hy_olen);
770 #endif
771 				hystart(ui, cmd,
772 				   (mplen == 0) ? is->hy_olen : mplen,
773 				   is->hy_ifuba.ifu_w.ifrw_info);
774 				if (mplen != 0)
775 					is->hy_flags |= RQ_XASSOC;
776 			} else if (rq & RQ_MARKDOWN) {
777 				is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN);
778 				is->hy_state = MARKPORT;
779 				is->hy_retry = 0;
780 				/*
781 				 * Port number is taken from status data
782 				 */
783 				hystart(ui,
784 				 (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)),
785 				 0, 0);
786 			} else if (rq & RQ_MARKUP) {
787 				register struct ifnet *ifp = &is->hy_if;
788 				register struct sockaddr_in *sin =
789 				   (struct sockaddr_in *)&ifp->if_addr;
790 
791 				is->hy_flags &= ~RQ_MARKUP;
792 				is->hy_retry = 0;
793 				/*
794 				 * Fill in the host number
795 				 * from the status buffer
796 				 */
797 				printf(
798 	"hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n",
799 					ui->ui_unit,
800 					is->hy_stat.hyc_uaddr,
801 					PORTNUM(&is->hy_status),
802 					(is->hy_stat.hyc_atype[0]<<8) |
803 						is->hy_stat.hyc_atype[1],
804 					is->hy_stat.hyc_atype[2]);
805 
806 				ifp->if_host[0] =
807 				  (is->hy_stat.hyc_uaddr << 8) |
808 					PORTNUM(&is->hy_status);
809 				sin->sin_addr =
810 				   if_makeaddr(ifp->if_net, ifp->if_host[0]);
811 				ifp->if_flags |= IFF_UP;
812 				if_rtinit(ifp, RTF_UP);
813 #ifdef HYLOG
814 				hylog(HYL_UP, 0, (char *)0);
815 #endif
816 			} else {
817 				is->hy_state = WAITING;
818 				is->hy_retry = 0;
819 				hystart(ui, HYF_WAITFORMSG, 0, 0);
820 			}
821 		}
822 		break;
823 	}
824 
825 	case STATSENT:
826 		bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status,
827 		  sizeof (struct hy_status));
828 #ifdef DEBUG
829 		printD("hy%d: status - %x %x %x %x %x %x %x %x\n",
830 			ui->ui_unit, is->hy_status.hys_gen_status,
831 			is->hy_status.hys_last_fcn,
832 			is->hy_status.hys_resp_trunk,
833 			is->hy_status.hys_status_trunk,
834 			is->hy_status.hys_recd_resp,
835 			is->hy_status.hys_error,
836 			is->hy_status.hys_caddr,
837 			is->hy_status.hys_pad);
838 #endif
839 		is->hy_state = IDLE;
840 #ifdef HYLOG
841 		hylog(HYL_STATUS, sizeof (struct hy_status),
842 			(char *)&is->hy_status);
843 #endif
844 #ifdef HYELOG
845 		{
846 			register int i;
847 
848 			i = is->hy_status.hys_error;
849 			if (i < HYE_MAX)
850 				i = HYE_MAX;
851 			switch (is->hy_status.hys_last_fcn) {
852 				case HYF_XMITLOCMSG:
853 					i += HYE_MAX+1;	/* fall through */
854 				case HYF_XMITLSTDATA:
855 					i += HYE_MAX+1;	/* fall through */
856 				case HYF_XMITMSG:
857 					i += HYE_MAX+1;
858 			}
859 			hy_elog[i]++;
860 		}
861 #endif
862 		break;
863 
864 	case RSTATSENT: {
865 		register struct hy_stat *p =
866 			(struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr;
867 
868 		is->hy_stat.hyc_msgcnt = ntohl(p->hyc_msgcnt);
869 		is->hy_stat.hyc_dbcnt = ntohl(p->hyc_dbcnt);
870 		is->hy_stat.hyc_tbusy = ntohl(p->hyc_tbusy);
871 		is->hy_stat.hyc_hwret = ntohl(p->hyc_hwret);
872 		is->hy_stat.hyc_crcbad = ntohl(p->hyc_crcbad);
873 		is->hy_stat.hyc_mcret = ntohl(p->hyc_mcret);
874 		is->hy_stat.hyc_tdabort = ntohl(p->hyc_tdabort);
875 		is->hy_stat.hyc_atype[0] = p->hyc_atype[0];
876 		is->hy_stat.hyc_atype[1] = p->hyc_atype[1];
877 		is->hy_stat.hyc_atype[2] = p->hyc_atype[2];
878 		is->hy_stat.hyc_uaddr = p->hyc_uaddr;
879 #ifdef DEBUG
880 		printD(
881 	"hy%d: statistics - msgcnt %d dbcnt %d hwret %d tbusy %d crcbad %d\n",
882 			ui->ui_unit,
883 			is->hy_stat.hyc_msgcnt, is->hy_stat.hyc_dbcnt,
884 			is->hy_stat.hyc_tbusy, is->hy_stat.hyc_hwret,
885 			is->hy_stat.hyc_crcbad);
886 		printD("	mcret %d tdabort %d atype %x %x %x uaddr %x\n",
887 			is->hy_stat.hyc_mcret, is->hy_stat.hyc_tdabort,
888 			is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1],
889 			is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr);
890 #endif
891 		is->hy_state = IDLE;
892 #ifdef HYLOG
893 		hylog(HYL_STATISTICS, sizeof (struct hy_stat),
894 			(char *)&is->hy_stat);
895 #endif
896 		break;
897 	}
898 
899 	case CLEARSENT:
900 		is->hy_state = IDLE;
901 		break;
902 
903 	case ENDOPSENT:
904 		is->hy_state = IDLE;
905 		break;
906 
907 	case RECVSENT: {
908 		register struct hy_hdr *hyh;
909 		register unsigned len;
910 
911 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
912 			UBAPURGE(is->hy_ifuba.ifu_uba,
913 				is->hy_ifuba.ifu_r.ifrw_bdp);
914 		hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
915 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
916 		if (len > MPSIZE) {
917 			printf("hy%d: RECVD MP > MPSIZE (%d)\n",
918 				ui->ui_unit, len);
919 #ifdef DEBUG
920 			hy_debug_flag = 1;
921 			printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
922 				ui->ui_unit, addr->hyd_csr, HY_CSR_BITS,
923 				addr->hyd_bar, addr->hyd_wcr);
924 #endif
925 		}
926 #ifdef DEBUG
927 		printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len);
928 		if (hy_debug_flag)
929 			hyprintdata((char *)hyh, len);
930 #endif
931 		if (hyh->hyh_ctl & H_ASSOC) {
932 			is->hy_state = RECVDATASENT;
933 			is->hy_ilen = len;
934 			is->hy_retry = 0;
935 			hystart(ui, HYF_INPUTDATA,
936 			  (int)(HYMTU-len+sizeof (struct hy_hdr)),
937 			  (int)(is->hy_ifuba.ifu_r.ifrw_info + len));
938 		} else {
939 			hyrecvdata(ui, hyh, (int)len);
940 			is->hy_state = IDLE;
941 		}
942 		break;
943 	}
944 
945 	case RECVDATASENT: {
946 		register struct hy_hdr *hyh;
947 		register unsigned len;
948 
949 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
950 			UBAPURGE(is->hy_ifuba.ifu_uba,
951 				is->hy_ifuba.ifu_r.ifrw_bdp);
952 		hyh = (struct hy_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
953 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
954 #ifdef DEBUG
955 		printD("hy%d: recvd assoc data, len = %d, data = ",
956 			ui->ui_unit, len);
957 		if (hy_debug_flag)
958 			hyprintdata((char *)hyh + is->hy_ilen, len);
959 #endif
960 		hyrecvdata(ui, hyh, (int)(len + is->hy_ilen));
961 		is->hy_state = IDLE;
962 		break;
963 	}
964 
965 	case XMITSENT:
966 		if (is->hy_flags & RQ_XASSOC) {
967 			register unsigned len;
968 
969 			is->hy_flags &= ~RQ_XASSOC;
970 			is->hy_state = XMITDATASENT;
971 			is->hy_retry = 0;
972 			len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
973 			if (len > is->hy_olen) {
974 				printf(
975 				"hy%d: xmit error - len > hy_olen [%d > %d]\n",
976 				ui->ui_unit, len, is->hy_olen);
977 #ifdef DEBUG
978 				hy_debug_flag = 1;
979 #endif
980 			}
981 			hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len,
982 				is->hy_ifuba.ifu_w.ifrw_info + len);
983 			break;
984 		}
985 		/* fall through to ... */
986 
987 	case XMITDATASENT:
988 		hyxmitdata(ui);
989 		is->hy_state = IDLE;
990 		break;
991 
992 	case WAITING:	/* wait for message complete or output requested */
993 		if (HYS_RECVDATA(addr))
994 			is->hy_state = IDLE;
995 		else {
996 			is->hy_state = CLEARSENT;
997 			is->hy_retry = 0;
998 			hystart(ui, HYF_CLRWFMSG, 0, 0);
999 		}
1000 		break;
1001 
1002 	case MARKPORT:
1003 		is->hy_state = STARTUP;
1004 		is->hy_if.if_flags &= ~IFF_UP;
1005 		goto endintr;
1006 
1007 	default:
1008 		printf("hy%d: DRIVER BUG - INVALID STATE %d\n",
1009 			ui->ui_unit, is->hy_state);
1010 		panic("HYPERCHANNEL IN INVALID STATE");
1011 		/*NOTREACHED*/
1012 	}
1013 	if (is->hy_state == IDLE)
1014 		goto actloop;
1015 endintr:
1016 #ifdef DEBUG
1017 	printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit,
1018 		hy_state_names[is->hy_state]);
1019 #endif
1020 }
1021 
1022 /*
1023  * Called from device interrupt when recieving data.
1024  * Examine packet to determine type.  Decapsulate packet
1025  * based on type and pass to type specific higher-level
1026  * input routine.
1027  */
1028 hyrecvdata(ui, hyh0, len)
1029 	struct uba_device *ui;
1030 	struct hy_hdr *hyh0;
1031 	int len;
1032 {
1033 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
1034 	register struct hy_hdr *hyh = hyh0;
1035     	struct mbuf *m;
1036 	register struct ifqueue *inq;
1037 
1038 	is->hy_if.if_ipackets++;
1039 #ifdef DEBUG
1040 	printD("hy%d: recieved packet, len = %d (actual %d)\n",
1041 		ui->ui_unit, len,
1042 		len - (hyh->hyh_off + sizeof (struct hy_hdr)));
1043 #endif
1044 #ifdef HYLOG
1045 	{
1046 		struct {
1047 			short hlen;
1048 			struct hy_hdr hhdr;
1049 		} hh;
1050 		hh.hlen = len;
1051 		hh.hhdr = *hyh;
1052 		hylog(HYL_RECV, sizeof(hh), (char *)&hh);
1053 	}
1054 #endif
1055 	if (len > HYMTU + MPSIZE || len == 0)
1056 		return;			/* sanity */
1057 	/*
1058 	 * Pull packet off interface.
1059 	 */
1060 	m = if_rubaget(&is->hy_ifuba, len, 0);
1061 	if (m == NULL)
1062 		return;
1063 	switch (hyh->hyh_type) {
1064 
1065 #ifdef INET
1066 	case HYLINK_IP:
1067 		/*
1068 		 * Strip the variable portion of the hyperchannel header
1069 		 * (fixed portion stripped in if_rubaget).
1070 		 */
1071 		m->m_len -= hyh->hyh_off;
1072 		m->m_off += hyh->hyh_off;
1073 		schednetisr(NETISR_IP);
1074 		inq = &ipintrq;
1075 		break;
1076 #endif
1077 	default:
1078 		m_freem(m);
1079 		return;
1080 	}
1081 	if (IF_QFULL(inq)) {
1082 		IF_DROP(inq);
1083 		m_freem(m);
1084 	} else
1085 		IF_ENQUEUE(inq, m);
1086 }
1087 
1088 /*
1089  * Transmit done, release resources, bump counters.
1090  */
1091 hyxmitdata(ui)
1092 	struct uba_device *ui;
1093 {
1094 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
1095 
1096 	is->hy_if.if_opackets++;
1097 	if (is->hy_ifuba.ifu_xtofree) {
1098 		m_freem(is->hy_ifuba.ifu_xtofree);
1099 		is->hy_ifuba.ifu_xtofree = 0;
1100 	}
1101 }
1102 
1103 hycancel(ui)
1104 	register struct uba_device *ui;
1105 {
1106 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
1107 
1108 	if (is->hy_ifuba.ifu_xtofree) {
1109 		m_freem(is->hy_ifuba.ifu_xtofree);
1110 		is->hy_ifuba.ifu_xtofree = 0;
1111 	}
1112 #ifdef DEBUG
1113 	if (hy_nodebug & 1)
1114 		hy_debug_flag = 1;
1115 #endif
1116 #ifdef DEBUG
1117 	printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n",
1118 		ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd,
1119 		is->hy_savedcount, is->hy_savedaddr);
1120 	printD("\tflags 0x%x ilen %d olen %d lastwcr %d retry %d\n",
1121 		is->hy_flags, is->hy_ilen, is->hy_olen, is->hy_lastwcr,
1122 		is->hy_retry);
1123 	printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n",
1124 		is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr,
1125 		is->hy_savedcmd);
1126 #endif
1127 	is->hy_state = IDLE;
1128 	is->hy_flags |= (RQ_ENDOP | RQ_STATUS);
1129 	hyact(ui);
1130 }
1131 
1132 #ifdef DEBUG
1133 hyprintdata(cp, len)
1134 	register char *cp;
1135 	register int len;
1136 {
1137 	register int count = 16;
1138 	register char *fmt;
1139 	static char regfmt[] = "\n\t %x";
1140 
1141 	fmt = &regfmt[2];
1142 	while (--len >= 0) {
1143 		printL(fmt, *cp++ & 0xff);
1144 		fmt = &regfmt[2];
1145 		if (--count <= 0) {
1146 			fmt = &regfmt[0];
1147 			count = 16;
1148 		}
1149 	}
1150 	printL("\n");
1151 }
1152 #endif
1153 
1154 hywatch(unit)
1155 int unit;
1156 {
1157 	register struct hy_softc *is = &hy_softc[unit];
1158 	register struct uba_device *ui = hyinfo[unit];
1159 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
1160 	int s;
1161 
1162 	s = splimp();
1163 	is->hy_if.if_timer = SCANINTERVAL;
1164 	if (is->hy_ntime > 2 && is->hy_state != WAITING &&
1165 	  is->hy_state != STARTUP && is->hy_state != IDLE) {
1166 		printf("hy%d: watchdog timer expired\n", unit);
1167 		hycancel(ui);
1168 	}
1169 #ifdef PI13
1170 	if ((addr->hyd_csr & S_POWEROFF) != 0) {
1171 		addr->hyd_csr |= S_POWEROFF;
1172 		DELAY(100);
1173 		if ((addr->hyd_csr & S_POWEROFF) == 0) {
1174 			printf("hy%d: adapter power restored\n", unit);
1175 			is->hy_state = IDLE;
1176 			is->hy_flags |=
1177 			  (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS);
1178 			hyact(ui);
1179 		}
1180 	}
1181 #endif
1182 	splx(s);
1183 }
1184 
1185 #ifdef HYLOG
1186 hylog(code, len, ptr)
1187 	int code;
1188 	int len;
1189 	char *ptr;
1190 {
1191 	register unsigned char *p;
1192 	int s;
1193 
1194 	s = splimp();
1195 	if (hy_log.hyl_self != &hy_log) {
1196 		hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE];
1197 		hy_log.hyl_ptr = &hy_log.hyl_buf[0];
1198 		hy_log.hyl_self = &hy_log;
1199 		hy_log.hyl_enable = HYL_DISABLED;
1200 		hy_log.hyl_onerr = HYL_CATCH1;
1201 	}
1202 	if (hy_log.hyl_enable == HYL_DISABLED ||
1203 	  hy_log.hyl_enable == HYL_CAUGHT1 ||
1204 	  hy_log.hyl_enable == HYL_CAUGHTSTATUS ||
1205 	  (hy_log.hyl_enable == HYL_CATCHSTATUS && code != HYL_STATUS))
1206 		goto out;
1207 	p = hy_log.hyl_ptr;
1208 	if (p + len + 2 >= hy_log.hyl_eptr) {
1209 		bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p));
1210 		p = &hy_log.hyl_buf[0];
1211 		if (hy_log.hyl_enable == HYL_CATCH1) {
1212 			hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHT1;
1213 			goto out;
1214 		}
1215 		if (hy_log.hyl_enable == HYL_CATCHSTATUS) {
1216 			hy_log.hyl_enable = hy_log.hyl_onerr = HYL_CAUGHTSTATUS;
1217 			goto out;
1218 		}
1219 	}
1220 	*p++ = code;
1221 	*p++ = len;
1222 	bcopy(ptr, (caddr_t)p, (unsigned)len);
1223 	hy_log.hyl_ptr = p + len;
1224 out:
1225 	splx(s);
1226 }
1227 #endif
1228 
1229 /*ARGSUSED*/
1230 hyioctl(ifp, cmd, data)
1231 	register struct ifnet *ifp;
1232 	int cmd;
1233 	caddr_t	data;
1234 {
1235 	struct sockaddr_in *sin;
1236 	int s = splimp(), error = 0;
1237 
1238 	switch(cmd) {
1239 
1240 	case SIOCSIFADDR:
1241 		if (ifp->if_flags & IFF_RUNNING)
1242 			if_rtinit(ifp, -1);
1243 		sin = (struct sockaddr_in *)&ifr->ifr_addr;
1244 		ifp->if_net = in_netof(sin->sin_addr);
1245 		sin = (struct sockaddr_in *)&ifp->if_addr;
1246 		sin->sin_family = AF_INET;
1247 		sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
1248 		if (ifp->if_flags & IFF_RUNNING)
1249 			if_rtinit(ifp, RTF_UP);
1250 		else
1251 			hyinit(ifp->if_unit);
1252 		break;
1253 
1254 	case HYSETROUTE:
1255 		if (!suser()) {
1256 			error = EPERM;
1257 			goto bad;
1258 		}
1259 		hy_route[ifp->if_unit] = *(struct hyroute *)ifr->ifr_data;
1260 		hy_route[ifp->if_unit].hyr_lasttime = time;
1261 		break;
1262 
1263 	case HYGETROUTE:
1264 		*(struct hyroute *)ifr->ifr_data = hy_route[ifp->if_unit];
1265 		break;
1266 
1267 	default:
1268 		error = EINVAL;
1269 		break;
1270 	}
1271 bad:
1272 	splx(s);
1273 	return (error);
1274 }
1275 #endif
1276