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