xref: /original-bsd/sys/vax/if/if_hy.c (revision f95533f0)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Tektronix Inc.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)if_hy.c	7.7 (Berkeley) 12/16/90
11  */
12 
13 /*
14  * 4.2 BSD Unix Kernel - Vax Network Interface Support
15  *
16  * $Header: if_hy.c,v 10.1 84/07/22 21:02:56 steveg Exp $
17  * $Locker:  $
18  *
19  * Modifications from Berkeley 4.2 BSD
20  * Copyright (c) 1983, Tektronix Inc.
21  * All Rights Reserved
22  *
23  * $Log:	if_hy.c,v $
24  *	Revision 10.1  84/07/22  21:02:56  steveg
25  *	define PI13 (moved from if_hyreg.h, somehow got dropped in the process)
26  *	rework hywatch to check for power fails first
27  *
28  *	Revision 10.0  84/06/30  19:54:27  steveg
29  *	Big Build
30  *
31  *	Revision 3.17  84/06/20  19:20:28  steveg
32  *	increment hy_ntime in hywatch
33  *	print out state name, csr, last command, and hy_flags when watchdog timer
34  *	expires
35  *
36  *	Revision 3.16  84/06/20  19:09:34  steveg
37  *	turn on continuous logging by default
38  *
39  *	Revision 3.15  84/05/30  22:19:09  steveg
40  *	changes to reflect new layout ot statistics data
41  *
42  *	Revision 3.14  84/05/30  19:25:15  steveg
43  *	move driver states to if_hy.h so log printing programs can use them
44  *
45  *	Revision 3.13  84/05/30  17:13:26  steveg
46  *	make it compile
47  *
48  *	Revision 3.12  84/05/30  13:46:16  steveg
49  *	rework logging
50  *
51  *	Revision 3.11  84/05/18  19:35:02  steveg
52  *	clear IFF_RUNNING and IFF_UP on unibus reset to force resource allocation
53  *	by the init routine
54  *
55  *	Revision 3.10  84/05/04  12:14:44  steveg
56  *	more rework to make it actually work under 4.2
57  *
58  *	Revision 3.9  84/05/01  23:34:52  steveg
59  *	fix typo so it compiles (unit -> ui->ui_unit)
60  *
61  *	Revision 3.8  84/05/01  23:18:30  steveg
62  *	changes after talking with rickk
63  *	- check power off more closely
64  *	- support remote loopback through A710 adapters
65  *	- IMPLINK -> HYLINK
66  *	- return EHOSTUNREACH on hyroute failure
67  *	- bump if_collisions on abnormal interrupts that aren't input or output
68  *
69  *
70  */
71 
72 
73 #include "hy.h"
74 #if NHY > 0
75 
76 /*
77  * Network Systems Copropration Hyperchanel interface
78  */
79 #include "../include/pte.h"
80 
81 #include "sys/param.h"
82 #include "sys/systm.h"
83 #include "sys/mbuf.h"
84 #include "sys/buf.h"
85 #include "sys/protosw.h"
86 #include "sys/socket.h"
87 #include "sys/vmmac.h"
88 #include "sys/errno.h"
89 #include "sys/time.h"
90 #include "sys/kernel.h"
91 #include "sys/ioctl.h"
92 
93 #include "net/if.h"
94 #include "net/netisr.h"
95 #include "net/route.h"
96 
97 #ifdef	INET
98 #include "netinet/in.h"
99 #include "netinet/in_systm.h"
100 #include "netinet/in_var.h"
101 #include "netinet/ip.h"
102 #endif
103 
104 #include "../include/cpu.h"
105 #include "../include/mtpr.h"
106 #include "../uba/ubareg.h"
107 #include "../uba/ubavar.h"
108 
109 /*
110  * configuration specific paramters
111  *	- change as appropriate for particular installaions
112  */
113 #define	HYROUTE
114 #define	HYELOG
115 #define	HYLOG
116 #define	HYMTU	1100
117 #define PI13
118 
119 #ifdef	DEBUG
120 #define	HYLOG
121 #endif
122 
123 #include "if_hy.h"
124 #include "if_hyreg.h"
125 #include "if_uba.h"
126 
127 int	hyprobe(), hyattach(), hyinit(), hyioctl();
128 int	hyoutput(), hyreset(), hywatch();
129 struct	uba_device *hyinfo[NHY];
130 u_short hystd[] = { 0772410, 0 };
131 struct	uba_driver hydriver =
132 	{ hyprobe, 0, hyattach, 0, hystd, "hy", hyinfo };
133 
134 /*
135  * Hyperchannel software status per interface.
136  *
137  * Each interface is referenced by a network interface structure,
138  * hy_if, which the routing code uses to locate the interface.
139  * This structure contains the output queue for the interface, its address, ...
140  * We also have, for each interface, a UBA interface structure, which
141  * contains information about the UNIBUS resources held by the interface:
142  * map registers, buffered data paths, etc.  Information is cached in this
143  * structure for use by the if_uba.c routines in running the interface
144  * efficiently.
145  */
146 struct	hy_softc {
147 	struct	ifnet hy_if;		/* network-visible interface */
148 	struct	ifuba hy_ifuba;		/* UNIBUS resources */
149 	short	hy_flags;		/* flags */
150 	short	hy_state;		/* driver state */
151 	u_short	hy_host;		/* local host number */
152 	struct	in_addr hy_addr;	/* internet address */
153 	int	hy_olen;		/* packet length on output */
154 	int	hy_lastwcr;		/* last command's word count */
155 	short	hy_savedstate;		/* saved for reissue after status */
156 	short	hy_savedcmd;		/* saved command for reissue */
157 	int	hy_savedcount;		/* saved byte count for reissue */
158 	int	hy_savedaddr;		/* saved unibus address for reissue */
159 	int	hy_ntime;		/* number of timeouts since last cmd */
160 	int	hy_retry;		/* retry counter */
161 	struct	hy_stat hy_stat;	/* statistics */
162 	struct	hy_status hy_status;	/* status */
163 } hy_softc[NHY];
164 
165 #ifdef HYELOG
166 u_long	hy_elog[HYE_SIZE];
167 #endif
168 
169 #ifdef HYLOG
170 struct hy_log hy_log;
171 #endif
172 
173 #ifdef HYROUTE
174 struct hy_route hy_route[NHY];
175 #endif
176 
177 #ifdef DEBUG
178 #define printL	printf
179 #define printD	if (hy_debug_flag) printf
180 int	hy_debug_flag = 0;
181 /*
182  * hy_nodebug bit 0x01	set hy_debug_flag on hycancel
183  * hy_nodebug bit 0x02	set hy_debug_flag on command reissue
184  * hy_nodebug bit 0x04	set hy_debug_flag on abnormal interrupt
185  */
186 int	hy_nodebug = 0x0;
187 #endif
188 
189 #define SCANINTERVAL	10	/* seconds */
190 #define MAXINTERVAL	20	/* seconds (max action) */
191 
192 /*
193  * Cause a device interrupt.  This code uses a buffer starting at
194  * location zero on the unibus (which is already mapped by the
195  * autoconfigure code in the kernel).
196  */
197 hyprobe(reg)
198 	caddr_t reg;
199 {
200 	register int br, cvec;		/* r11, r10 value-result */
201 	register struct hydevice *addr = (struct hydevice *) reg;
202 
203 #ifdef lint
204 	br = 0; cvec = br; br = cvec;
205 	hyint(0);
206 #endif
207 	/*
208 	 * request adapter status to a buffer starting at unibus location 0
209 	 */
210 	addr->hyd_bar = 0;
211 	addr->hyd_wcr = -((sizeof(struct hy_status) + 1) >> 1);
212 	addr->hyd_dbuf = HYF_STATUS;
213 #ifdef PI13
214 	addr->hyd_csr |= S_GO | S_IE | S_IATTN;
215 #else
216 	addr->hyd_csr |= S_GO | S_IE;
217 #endif
218 	DELAY(10000);
219 #ifdef PI13
220 	addr->hyd_csr |= S_CLRINT;	/* clear any stacked interrupts */
221 #endif
222 	addr->hyd_csr &= ~(S_IE | S_CLRINT);	/* disable further interrupts */
223 	return(sizeof(struct hydevice));
224 }
225 
226 /*
227  * Interface exists: make available by filling in network interface
228  * record.  System will initialize the interface when it is ready
229  * to accept packets.
230  */
231 hyattach(ui)
232 	struct uba_device *ui;
233 {
234 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
235 	register struct ifnet *ifp = &is->hy_if;
236 
237 	ifp->if_unit = ui->ui_unit;
238 	ifp->if_name = "hy";
239 	ifp->if_mtu = HYMTU;
240 	is->hy_state = STARTUP;		/* don't allow state transitions yet */
241 	ifp->if_init = hyinit;
242 	ifp->if_ioctl = hyioctl;
243 	ifp->if_output = hyoutput;
244 	ifp->if_reset = hyreset;
245 	ifp->if_watchdog = hywatch;
246 	ifp->if_timer = SCANINTERVAL;
247 	is->hy_ifuba.ifu_flags = UBA_CANTWAIT;
248 #ifdef notdef
249 	is->hy_ifuba.ifu_flags |= UBA_NEEDBDP;
250 #endif
251 	if_attach(ifp);
252 }
253 
254 /*
255  * Reset of interface after UNIBUS reset.
256  * If interface is on specified uba, reset its state.
257  */
258 hyreset(unit, uban)
259 	int unit, uban;
260 {
261 	register struct uba_device *ui;
262 	register struct hy_softc *is;
263 
264 	if (unit >= NHY || (ui = hyinfo[unit]) == 0 || ui->ui_alive == 0 ||
265 	  ui->ui_ubanum != uban)
266 		return;
267 	printf(" hy%d", unit);
268 	is = &hy_softc[unit];		/* force unibus resource allocation */
269 	is->hy_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
270 	hyinit(unit);
271 }
272 
273 /*
274  * Initialization of interface; clear recorded pending
275  * operations, and reinitialize UNIBUS usage.
276  */
277 hyinit(unit)
278 	int unit;
279 {
280 	register struct hy_softc *is = &hy_softc[unit];
281 	register struct uba_device *ui = hyinfo[unit];
282 	register struct mbuf *m;
283 	int s;
284 
285 	if (is->hy_if.if_addrlist == 0)		/* address still unknown */
286 		return;
287 	if (is->hy_if.if_flags & IFF_RUNNING)	/* just reset the device */
288 		goto justreset;
289 	if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum,
290 	    sizeof (struct hym_hdr), (int)btoc(HYMTU)) == 0) {
291 #ifdef DEBUG
292 		if (hy_nodebug & 4)
293 			hy_debug_flag = 1;
294 #endif
295 		printf("hy%d: can't initialize\n", unit);
296 		is->hy_if.if_flags &= ~IFF_UP;
297 		return;
298 	}
299 	is->hy_if.if_flags |= IFF_RUNNING;
300 
301 justreset:
302 	/*
303 	 * remove any left over outgoing messages, reset the hardware and
304 	 * start the state machine
305 	 */
306 	s = splimp();
307 #ifdef HYLOG
308 	hylog(HYL_RESET, 0, (char *)0);
309 #endif
310 	is->hy_state = IDLE;
311 	is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP;
312 	is->hy_retry = 0;
313 	for(;;) {
314 		IF_DEQUEUE(&is->hy_if.if_snd, m);
315 		if (m != NULL)
316 			m_freem(m);
317 		else
318 			break;
319 	}
320 	hycancel(ui);		/* also bumps the state machine */
321 	splx(s);
322 }
323 
324 /*
325  * Issue a command to the adapter
326  */
327 hystart(ui, cmd, count, ubaddr)
328 	struct uba_device *ui;
329 	int cmd, count, ubaddr;
330 {
331 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
332 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
333 
334 #ifdef DEBUG
335 	printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n",
336 		ui->ui_unit, cmd, count, ubaddr);
337 	printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
338 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
339 		addr->hyd_wcr);
340 #endif
341 	if (((is->hy_flags & RQ_REISSUE) == 0) &&
342 	  (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) {
343 		is->hy_savedstate = is->hy_state;
344 		is->hy_savedcmd = cmd;
345 		is->hy_savedcount = count;
346 		is->hy_savedaddr = ubaddr;
347 	}
348 #ifdef PI13
349 	if (addr->hyd_csr & S_POWEROFF) {
350 		printf("hy%d: \"Soft\" Adapter Power Failure (hystart)\n", ui->ui_unit);
351 		addr->hyd_csr |= S_POWEROFF;
352 		DELAY(100);
353 		if (addr->hyd_csr & S_POWEROFF) {
354 			printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hystart)\n", ui->ui_unit);
355 			if_down(&is->hy_if);
356 			is->hy_if.if_flags &= ~IFF_UP;
357 			is->hy_state = STARTUP;
358 		} else {
359 			printf("hy%d: Adapter Power Restored (hystart)\n", ui->ui_unit);
360 		}
361 		return;
362 	}
363 #endif
364 	addr->hyd_bar = ubaddr & 0xffff;
365 	addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1);
366 	addr->hyd_dbuf = cmd;
367 #ifdef PI13
368 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE | S_IATTN;
369 #else
370 	addr->hyd_csr = ((ubaddr >> XBASHIFT) & S_XBA) | S_GO | S_IE;
371 #endif
372 #ifdef DEBUG
373 	printD("hy%d: exit hystart - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
374 		ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
375 		addr->hyd_wcr);
376 #endif
377 #ifdef HYLOG
378 	{
379 		struct {
380 			u_char	hcmd;
381 			u_char	hstate;
382 			short	hcount;
383 		} hcl;
384 
385 		hcl.hcmd = cmd;
386 		hcl.hstate = is->hy_state;
387 		hcl.hcount = count;
388 		hylog(HYL_CMD, sizeof(hcl), (char *)&hcl);
389 	}
390 #endif
391 	is->hy_ntime = 0;
392 }
393 
394 int hyint_active = 0;		/* set during hy interrupt */
395 /*
396  * Hyperchannel interface interrupt.
397  *
398  * An interrupt can occur for many reasons.  Examine the status of
399  * the hyperchannel status bits to determine what to do next.
400  *
401  * If input error just drop packet.
402  * Otherwise purge input buffered data path and examine
403  * packet to determine type.  Othewise decapsulate
404  * packet based on type and pass to type specific higher-level
405  * input routine.
406  */
407 hyint(unit)
408 	int unit;
409 {
410 	register struct hy_softc *is = &hy_softc[unit];
411 	register struct uba_device *ui = hyinfo[unit];
412 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
413 
414 	if (hyint_active)
415 		panic("RECURSIVE HYPERCHANNEL INTERRUPT");
416 	hyint_active++;
417 #ifdef DEBUG
418 	printD("hy%d: hyint enter - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
419 		unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar, addr->hyd_wcr);
420 #endif
421 #ifdef HYLOG
422 logit:
423 	{
424 		struct {
425 			u_char	hstate;
426 			u_char	hflags;
427 			short	hcsr;
428 			short	hwcr;
429 		} hil;
430 		hil.hstate = is->hy_state;
431 		hil.hflags = is->hy_flags;
432 		hil.hcsr = addr->hyd_csr;
433 		hil.hwcr = addr->hyd_wcr;
434 		hylog(HYL_INT, sizeof(hil), (char *)&hil);
435 	}
436 #endif
437 	if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) {
438 		/*
439 		 * Error bit set, some sort of error in the interface.
440 		 *
441 		 * The adapter sets attn on command completion so that's not
442 		 * a real error even though the interface considers it one.
443 		 */
444 #ifdef DEBUG
445 		if (hy_nodebug & 4)
446 			hy_debug_flag = 1;
447 #endif
448 		printf("csr = 0x%b\nbar = 0x%x\nwcr = 0x%x\n",
449 			addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
450 			addr->hyd_wcr);
451 		if (addr->hyd_csr & S_NEX) {
452 			printf("hy%d: NEX - Non Existant Memory\n", unit);
453 #ifdef PI13
454 			addr->hyd_csr |= S_NEX;  /* as per PI13 manual */
455 #else
456 			addr->hyd_csr &= ~S_NEX;
457 #endif
458 			hycancel(ui);
459 #ifdef PI13
460 		} else if (addr->hyd_csr & S_POWEROFF) {
461 			printf("hy%d: \"Soft\" Adapter Power Failure (hyint)\n", unit);
462 			addr->hyd_csr |= S_POWEROFF;
463 			DELAY(100);
464 			if (addr->hyd_csr & S_POWEROFF) {
465 				printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hyint)\n", unit);
466 				if_down(&is->hy_if);
467 				is->hy_if.if_flags &= ~IFF_UP;
468 				is->hy_state = STARTUP;
469 			} else {
470 				printf("hy%d: Adapter Power Restored (hyint)\n", unit);
471 			}
472 #endif
473 		} else {
474 			printf("hy%d:  BAR overflow\n", unit);
475 			hycancel(ui);
476 		}
477 	} else if (HYS_NORMAL(addr)) {
478 		/*
479 		 * Normal interrupt, bump state machine unless in state
480 		 * waiting and no data present (assumed to be word count
481 		 * zero interrupt or other hardware botch).
482 		 */
483 		if (is->hy_state != WAITING || HYS_RECVDATA(addr))
484 			hyact(ui);
485 	} else if (HYS_ABNORMAL(addr)) {
486 		/*
487 		 * Abnormal termination.
488 		 * bump error counts, retry the last function
489 		 * 'MAXRETRY' times before kicking the bucket.
490 		 *
491 		 * Don't reissue the cmd if in certain states, abnormal
492 		 * on a reissued cmd or max retry exceeded.
493 		 */
494 #ifdef HYLOG
495 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
496 			hy_log.hyl_enable = hy_log.hyl_onerr;
497 			goto logit;
498 		}
499 #endif
500 #ifdef DEBUG
501 		if (hy_nodebug & 4)
502 			hy_debug_flag = 1;
503 		printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n",
504 			unit, hy_state_names[is->hy_state], is->hy_state);
505 		printD("\tflags 0x%x olen %d lastwcr %d retry %d\n",
506 			is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry);
507 		printD("\tsaved: state %d count %d cmd 0x%x ptr 0x%x\n",
508 			is->hy_savedstate, is->hy_savedcount,
509 			is->hy_savedaddr, is->hy_savedcmd);
510 #endif
511 #ifdef PI13
512 		addr->hyd_csr &= ~S_C;  /* clear the damned PI-13 */
513 #endif
514 		if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT)
515 			is->hy_if.if_oerrors++;
516 		else if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT)
517 			is->hy_if.if_ierrors++;
518 		else
519 			is->hy_if.if_collisions++;	/* other errors */
520 		if (is->hy_state == XMITDATASENT ||
521 		    is->hy_state == RECVSENT ||
522 		    is->hy_state == RECVDATASENT ||
523 		    (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY)
524 			hycancel(ui);
525 		else {
526 #ifdef DEBUG
527 			if (hy_nodebug & 2)
528 				hy_debug_flag = 1;
529 #endif
530 			is->hy_retry++;
531 			is->hy_flags |= RQ_ENDOP | RQ_STATUS | RQ_REISSUE;
532 			is->hy_state = IDLE;
533 			hyact(ui);
534 		}
535 	} else {
536 		/*
537 		 * Interrupt is neither normal, abnormal, or interface error.
538 		 * Ignore it. It's either stacked or a word count 0.
539 		 */
540 #ifdef HYLOG
541 		if (hy_log.hyl_enable != hy_log.hyl_onerr) {
542 			hy_log.hyl_enable = hy_log.hyl_onerr;
543 			goto logit;
544 		}
545 #endif
546 #ifdef DEBUG
547 		printD("hy%d: possible stacked interrupt ignored\n", unit);
548 #endif
549 	}
550 #ifdef DEBUG
551 	printD("hy%d: hyint exit\n\n", unit);
552 #endif
553 	hyint_active = 0;
554 
555 }
556 
557 int hyoutprint = 0;
558 
559 /*
560  * Encapsulate a packet of type family for the local net.
561  */
562 hyoutput(ifp, m0, dst)
563 	struct ifnet *ifp;
564 	struct mbuf *m0;
565 	struct sockaddr *dst;
566 {
567 	register struct hym_hdr *hym;
568 	register struct mbuf *m;
569 	register char *mp;
570 	int dlen;	/* packet size, incl hardware header, but not sw header */
571 	int error = 0;
572 	int s;
573 
574 	/*
575 	 * Calculate packet length for later deciding whether it will fit
576 	 * in a message proper or we also need associated data.
577 	 */
578 	dlen = 0;
579 	for (m = m0; m; m = m->m_next)
580 		dlen += m->m_len;
581 	m = m0;
582 	if (dst->sa_family == AF_HYLINK) {	/* don't add header */
583 		dlen -= HYM_SWLEN;
584 		goto headerexists;
585 	}
586 
587 	/*
588 	 * Add the software and hardware hyperchannel headers.
589 	 * If there's not enough space in the first mbuf, allocate another.
590 	 * If that should fail, drop this sucker.
591 	 * No extra space for headers is allocated.
592 	 */
593 	mp = mtod(m, char *);	/* save pointer to real message */
594 	M_PREPEND(m, sizeof(struct hym_hdr), M_DONTWAIT);
595 	if (m == 0) {
596 		error = ENOBUFS;
597 		goto bad;
598 	}
599 	dlen += sizeof(struct hym_hdr) - HYM_SWLEN;
600 
601 	hym = mtod(m, struct hym_hdr *);
602 
603 	bzero((caddr_t)hym, sizeof(struct hym_hdr));
604 
605 	switch(dst->sa_family) {
606 
607 #ifdef INET
608 	case AF_INET: {
609 		int i;
610 
611 		/*
612 		 * if loopback address, swizzle ip header so when
613 		 * it comes back it looks like it was addressed to us
614 		 */
615 		i = hyroute(ifp, (u_long)in_lnaof(((struct sockaddr_in *)dst)->sin_addr), hym);
616 		if (i < 0)
617 			goto notfound;
618 		if (i > 0) {
619 			struct in_addr temp;
620 
621 			temp.s_addr = ((struct ip *)mp)->ip_dst.s_addr;
622 			((struct ip *)mp)->ip_dst.s_addr = ((struct ip *)mp)->ip_src.s_addr;
623 			((struct ip *)mp)->ip_src.s_addr = temp.s_addr;
624 		}
625 		/*
626 		 * If entire packet won't fit in message proper, just
627 		 * send hyperchannel hardware header and ip header in
628 		 * message proper.
629 		 *
630 		 * This insures that the associated data is at least a
631 		 * TCP/UDP header in length and thus prevents potential
632 		 * problems with very short word counts.
633 		 */
634 		if (dlen > MPSIZE)
635 			hym->hym_mplen = sizeof(struct hy_hdr) + (((struct ip *)mp)->ip_hl << 2);
636 		hym->hym_type = HYLINK_IP;
637 		break;
638 	}
639 #endif
640 
641 	default:
642 		printf("hy%d: can't handle af%d\n", ifp->if_unit,
643 			dst->sa_family);
644 		error = EAFNOSUPPORT;
645 		goto drop;
646 	}
647 
648 
649 headerexists:
650 
651 	/*
652 	 * insure message proper is below the maximum
653 	 */
654 	if (hym->hym_mplen > MPSIZE || (dlen > MPSIZE && hym->hym_mplen == 0))
655 		hym->hym_mplen = MPSIZE;
656 
657 	hym->hym_from = htons(hy_softc[ifp->if_unit].hy_host);
658 	if (hym->hym_mplen)
659 		hym->hym_ctl |= H_ASSOC;
660 	else
661 		hym->hym_ctl &= ~H_ASSOC;
662 	if (hyoutprint) printf("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n",
663 		ifp->if_unit, hym->hym_mplen, hym->hym_ctl,
664 		hym->hym_access, hym->hym_to, hym->hym_from,
665 		hym->hym_param, hym->hym_type);
666 #ifdef DEBUG
667 	printD("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n",
668 		ifp->if_unit, hym->hym_mplen, hym->hym_ctl,
669 		hym->hym_access, hym->hym_to, hym->hym_from,
670 		hym->hym_param, hym->hym_type);
671 #endif
672 	s = splimp();
673 	if (IF_QFULL(&ifp->if_snd)) {
674 		IF_DROP(&ifp->if_snd);
675 		error = ENOBUFS;
676 		splx(s);
677 		goto drop;
678 	}
679 	IF_ENQUEUE(&ifp->if_snd, m);
680 	if (hy_softc[ifp->if_unit].hy_state == WAITING)
681 		hyact(hyinfo[ifp->if_unit]);
682 	splx(s);
683 	return (0);
684 notfound:
685 	error = EHOSTUNREACH;
686 drop:
687 	m_freem(m);
688 	return (error);
689 }
690 
691 int
692 hyroute(ifp, dest, hym)
693 	register struct ifnet *ifp;
694 	u_long dest;
695 	register struct hym_hdr *hym;
696 {
697 #ifdef HYROUTE
698 	register struct hy_route *rt = &hy_route[ifp->if_unit];
699 	register struct hyr_hash *rhash;
700 	register int i;
701 #endif
702 
703 	hym->hym_param = 0;
704 #ifdef HYROUTE
705 	if (rt->hyr_lasttime != 0) {
706 		i = HYRHASH(dest);
707 		rhash = &rt->hyr_hash[i];
708 		i = 0;
709 		while (rhash->hyr_key != dest) {
710 			if (rhash->hyr_flags == 0 || i > HYRSIZE)
711 				return(-1);
712 			rhash++; i++;
713 			if (rhash >= &rt->hyr_hash[HYRSIZE])
714 				rhash = &rt->hyr_hash[0];
715 		}
716 		if (rhash->hyr_flags & HYR_GATE) {
717 			i = rhash->hyr_nextgate;
718 			if (i >= rhash->hyr_egate)
719 				rhash->hyr_nextgate = rhash->hyr_pgate;
720 			else
721 				rhash->hyr_nextgate++;
722 			rhash = &rt->hyr_hash[rt->hyr_gateway[i]];
723 			if ((rhash->hyr_flags & HYR_DIR) == 0)
724 				return(-1);
725 		} else if (rhash->hyr_flags & HYR_LOOP) {
726 			hym->hym_param = H_LOOPBK;	/* adapter loopback */
727 		} else if (rhash->hyr_flags & HYR_RLOOP) {
728 			hym->hym_param = H_RLOOPBK;	/* A710 remote loopback */
729 		}
730 		hym->hym_ctl = rhash->hyr_ctl;
731 		hym->hym_access = rhash->hyr_access;
732 		hym->hym_to = rhash->hyr_dst;
733 	} else {
734 #endif
735 		hym->hym_ctl = H_XTRUNKS | H_RTRUNKS;
736 		hym->hym_access = 0;
737 		hym->hym_to = htons((u_short)dest);
738 		if (dest & 0x010000)
739 			hym->hym_param = H_LOOPBK;	/* adapter loopback */
740 		else if (dest & 0x020000)
741 			hym->hym_param = H_RLOOPBK;	/* A710 remote loopback */
742 #ifdef HYROUTE
743 	}
744 #endif
745 
746 	if (hym->hym_param == 0)
747 		return(0);
748 	else
749 		return(1);
750 }
751 
752 hyact(ui)
753 	register struct uba_device *ui;
754 {
755 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
756 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
757 
758 actloop:
759 #ifdef DEBUG
760 	printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit,
761 		hy_state_names[is->hy_state]);
762 #endif
763 	switch (is->hy_state) {
764 
765 	case STARTUP:
766 		goto endintr;
767 
768 	case IDLE: {
769 		register rq = is->hy_flags;
770 
771 		if (rq & RQ_STATUS) {
772 			is->hy_flags &= ~RQ_STATUS;
773 			is->hy_state = STATSENT;
774 			hystart(ui, HYF_STATUS, sizeof (is->hy_status),
775 			    is->hy_ifuba.ifu_r.ifrw_info);
776 		} else if (rq & RQ_ENDOP) {
777 			is->hy_flags &= ~RQ_ENDOP;
778 			is->hy_state = ENDOPSENT;
779 			hystart(ui, HYF_END_OP, 0, 0);
780 		} else if (rq & RQ_STATISTICS) {
781 			is->hy_flags &= ~RQ_STATISTICS;
782 			is->hy_state = RSTATSENT;
783 			hystart(ui, HYF_RSTATS, sizeof (is->hy_stat),
784 			    is->hy_ifuba.ifu_r.ifrw_info);
785 		} else if (HYS_RECVDATA(addr)) {
786 			is->hy_state = RECVSENT;
787 			is->hy_retry = 0;
788 			hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info + HYM_SWLEN);
789 		} else if (rq & RQ_REISSUE) {
790 			is->hy_flags &= ~RQ_REISSUE;
791 			is->hy_state = is->hy_savedstate;
792 #ifdef DEBUG
793 			printD("hy%d: reissue cmd=0x%x count=%d",
794 			  ui->ui_unit, is->hy_savedcmd, is->hy_savedcount);
795 			printD(" ubaddr=0x%x retry=%d\n",
796 			  is->hy_savedaddr, is->hy_retry);
797 #endif
798 			hystart(ui, is->hy_savedcmd, is->hy_savedcount,
799 			    is->hy_savedaddr);
800 		} else {
801 			register struct mbuf *m;
802 
803 			IF_DEQUEUE(&is->hy_if.if_snd, m);
804 			if (m != NULL) {
805 				register struct hym_hdr *hym;
806 				register int mplen;
807 				register int cmd;
808 
809 				is->hy_state = XMITSENT;
810 				is->hy_retry = 0;
811 				hym = mtod(m, struct hym_hdr *);
812 #ifdef HYLOG
813 				hylog(HYL_XMIT, sizeof(struct hym_hdr),
814 				    (char *)hym);
815 #endif
816 				mplen = hym->hym_mplen;
817 				if (hym->hym_to_adapter == hym->hym_from_adapter)
818 					cmd = HYF_XMITLOCMSG;
819 				else
820 					cmd = HYF_XMITMSG;
821 #ifdef DEBUG
822 				printD("hy%d: hym_hdr = ", ui->ui_unit);
823 				if (hy_debug_flag)
824 					hyprintdata((char *)hym,
825 					    sizeof (struct hym_hdr));
826 #endif
827 				is->hy_olen = if_wubaput(&is->hy_ifuba, m) - HYM_SWLEN;
828 				if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
829 					UBAPURGE(is->hy_ifuba.ifu_uba,
830 						is->hy_ifuba.ifu_w.ifrw_bdp);
831 #ifdef DEBUG
832 				printD(
833 		"hy%d: sending packet (mplen = %d, hy_olen = %d) data = ",
834 					ui->ui_unit, mplen, is->hy_olen);
835 				if (hy_debug_flag)
836 					hyprintdata(
837 					    is->hy_ifuba.ifu_w.ifrw_addr,
838 					    is->hy_olen + HYM_SWLEN);
839 #endif
840 				if (mplen == 0) {
841 					is->hy_flags &= ~RQ_XASSOC;
842 					mplen = is->hy_olen;
843 				} else {
844 					is->hy_flags |= RQ_XASSOC;
845 				}
846 				hystart(ui, cmd, mplen, is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN);
847 			} else if (rq & RQ_MARKDOWN) {
848 				is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN);
849 				is->hy_state = MARKPORT;
850 				is->hy_retry = 0;
851 				/*
852 				 * Port number is taken from status data
853 				 */
854 				hystart(ui,
855 				 (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)),
856 				 0, 0);
857 			} else if (rq & RQ_MARKUP) {
858 				register struct ifnet *ifp = &is->hy_if;
859 
860 				is->hy_flags &= ~RQ_MARKUP;
861 				is->hy_retry = 0;
862 				/*
863 				 * Fill in the host number
864 				 * from the status buffer
865 				 */
866 				printf(
867 	"hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n",
868 					ui->ui_unit,
869 					is->hy_stat.hyc_uaddr,
870 					PORTNUM(&is->hy_status),
871 					(is->hy_stat.hyc_atype[0]<<8) |
872 						is->hy_stat.hyc_atype[1],
873 					is->hy_stat.hyc_atype[2]);
874 
875 				is->hy_host =
876 				  (is->hy_stat.hyc_uaddr << 8) |
877 					PORTNUM(&is->hy_status);
878 				ifp->if_flags |= IFF_UP;
879 #ifdef HYLOG
880 				hylog(HYL_UP, 0, (char *)0);
881 #endif
882 			} else {
883 				is->hy_state = WAITING;
884 				is->hy_retry = 0;
885 				hystart(ui, HYF_WAITFORMSG, 0, 0);
886 			}
887 		}
888 		break;
889 	}
890 
891 	case STATSENT:
892 		bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status,
893 		  sizeof (struct hy_status));
894 #ifdef DEBUG
895 		printD("hy%d: status - %x %x %x %x %x %x %x %x\n",
896 			ui->ui_unit, is->hy_status.hys_gen_status,
897 			is->hy_status.hys_last_fcn,
898 			is->hy_status.hys_resp_trunk,
899 			is->hy_status.hys_status_trunk,
900 			is->hy_status.hys_recd_resp,
901 			is->hy_status.hys_error,
902 			is->hy_status.hys_caddr,
903 			is->hy_status.hys_pad);
904 #endif
905 		is->hy_state = IDLE;
906 #ifdef HYLOG
907 		hylog(HYL_STATUS, sizeof (struct hy_status),
908 			(char *)&is->hy_status);
909 #endif
910 #ifdef HYELOG
911 		{
912 			register int i;
913 
914 			i = is->hy_status.hys_error;
915 			if (i > HYE_MAX)
916 				i = HYE_MAX;
917 			switch (is->hy_status.hys_last_fcn) {
918 				case HYF_XMITLOCMSG:
919 					i += HYE_MAX+1;	/* fall through */
920 				case HYF_XMITLSTDATA:
921 					i += HYE_MAX+1;	/* fall through */
922 				case HYF_XMITMSG:
923 					i += HYE_MAX+1;
924 			}
925 			hy_elog[i]++;
926 		}
927 #endif
928 		break;
929 
930 	case RSTATSENT: {
931 		register struct hy_stat *p =
932 			(struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr;
933 
934 		bcopy((caddr_t)p, (caddr_t)&is->hy_stat, sizeof(struct hy_stat));
935 #ifdef DEBUG
936 
937 		printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n",
938 			ui->ui_unit,
939 			(is->hy_stat.hyc_df0[0]<<16) | (is->hy_stat.hyc_df0[1]<<8) | is->hy_stat.hyc_df0[2],
940 			(is->hy_stat.hyc_df1[0]<<16) | (is->hy_stat.hyc_df1[1]<<8) | is->hy_stat.hyc_df1[2],
941 			(is->hy_stat.hyc_df2[0]<<16) | (is->hy_stat.hyc_df2[1]<<8) | is->hy_stat.hyc_df2[2],
942 			(is->hy_stat.hyc_df3[0]<<16) | (is->hy_stat.hyc_df3[1]<<8) | is->hy_stat.hyc_df3[2]);
943 		printD("	ret0 %d ret1 %d ret2 %d ret3 %d\n",
944 			(is->hy_stat.hyc_ret0[0]<<16) | (is->hy_stat.hyc_ret0[1]<<8) | is->hy_stat.hyc_ret0[2],
945 			(is->hy_stat.hyc_ret1[0]<<16) | (is->hy_stat.hyc_ret1[1]<<8) | is->hy_stat.hyc_ret1[2],
946 			(is->hy_stat.hyc_ret2[0]<<16) | (is->hy_stat.hyc_ret2[1]<<8) | is->hy_stat.hyc_ret2[2],
947 			(is->hy_stat.hyc_ret3[0]<<16) | (is->hy_stat.hyc_ret3[1]<<8) | is->hy_stat.hyc_ret3[2]);
948 		printD("	cancel %d abort %d atype %x %x %x uaddr %x\n",
949 			(is->hy_stat.hyc_cancel[0]<<8) | is->hy_stat.hyc_cancel[1],
950 			(is->hy_stat.hyc_abort[0]<<8) | is->hy_stat.hyc_abort[1],
951 			is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1],
952 			is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr);
953 #endif
954 		is->hy_state = IDLE;
955 #ifdef HYLOG
956 		hylog(HYL_STATISTICS, sizeof (struct hy_stat),
957 			(char *)&is->hy_stat);
958 #endif
959 		break;
960 	}
961 
962 	case CLEARSENT:
963 		is->hy_state = IDLE;
964 		break;
965 
966 	case ENDOPSENT:
967 		is->hy_state = IDLE;
968 		break;
969 
970 	case RECVSENT: {
971 		register struct hym_hdr *hym;
972 		register unsigned len;
973 
974 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
975 			UBAPURGE(is->hy_ifuba.ifu_uba,
976 			    is->hy_ifuba.ifu_r.ifrw_bdp);
977 		hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
978 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
979 		if (len > MPSIZE) {
980 			printf("hy%d: RECVD MP > MPSIZE (%d)\n",
981 			    ui->ui_unit, len);
982 			is->hy_state = IDLE;
983 #ifdef DEBUG
984 			hy_debug_flag = 1;
985 			printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
986 				ui->ui_unit, addr->hyd_csr, HY_CSR_BITS,
987 				addr->hyd_bar, addr->hyd_wcr);
988 #endif
989 		}
990 		hym->hym_mplen = len;
991 #ifdef DEBUG
992 		printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len);
993 		if (hy_debug_flag)
994 			hyprintdata((char *)hym, len + HYM_SWLEN);
995 #endif
996 		if (hym->hym_ctl & H_ASSOC) {
997 			is->hy_state = RECVDATASENT;
998 			is->hy_retry = 0;
999 			hystart(ui, HYF_INPUTDATA,
1000 			    (int)(HYMTU + sizeof (struct hy_hdr) - len),
1001 			    (int)(HYM_SWLEN + is->hy_ifuba.ifu_r.ifrw_info + len));
1002 		} else {
1003 			hyrecvdata(ui, hym, (int)len + HYM_SWLEN);
1004 			is->hy_state = IDLE;
1005 		}
1006 		break;
1007 	}
1008 
1009 	case RECVDATASENT: {
1010 		register struct hym_hdr *hym;
1011 		register unsigned len;
1012 
1013 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
1014 			UBAPURGE(is->hy_ifuba.ifu_uba,
1015 			    is->hy_ifuba.ifu_r.ifrw_bdp);
1016 		hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
1017 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
1018 #ifdef DEBUG
1019 		printD("hy%d: recvd assoc data, len = %d, data = ",
1020 			ui->ui_unit, len);
1021 		if (hy_debug_flag)
1022 			hyprintdata((char *)hym + hym->hym_mplen, len);
1023 #endif
1024 		hyrecvdata(ui, hym, (int)(len + hym->hym_mplen + HYM_SWLEN));
1025 		is->hy_state = IDLE;
1026 		break;
1027 	}
1028 
1029 	case XMITSENT:
1030 		if (is->hy_flags & RQ_XASSOC) {
1031 			register int len;
1032 
1033 			is->hy_flags &= ~RQ_XASSOC;
1034 			is->hy_state = XMITDATASENT;
1035 			is->hy_retry = 0;
1036 			len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
1037 			if (len > is->hy_olen) {
1038 				printf(
1039 				"hy%d: xmit error - len > hy_olen [%d > %d]\n",
1040 				ui->ui_unit, len, is->hy_olen);
1041 #ifdef DEBUG
1042 				hy_debug_flag = 1;
1043 #endif
1044 			}
1045 			hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len,
1046 			    is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN + len);
1047 			break;
1048 		}
1049 		/* fall through to ... */
1050 
1051 	case XMITDATASENT:
1052 		hyxmitdata(ui);
1053 		is->hy_state = IDLE;
1054 		break;
1055 
1056 	case WAITING:	/* wait for message complete or output requested */
1057 		if (HYS_RECVDATA(addr))
1058 			is->hy_state = IDLE;
1059 		else {
1060 			is->hy_state = CLEARSENT;
1061 			is->hy_retry = 0;
1062 			hystart(ui, HYF_CLRWFMSG, 0, 0);
1063 		}
1064 		break;
1065 
1066 	case MARKPORT:
1067 		is->hy_state = STARTUP;
1068 		if_down(&is->hy_if);
1069 		is->hy_if.if_flags &= ~IFF_UP;
1070 		goto endintr;
1071 
1072 	default:
1073 		printf("hy%d: DRIVER BUG - INVALID STATE %d\n",
1074 			ui->ui_unit, is->hy_state);
1075 		panic("HYPERCHANNEL IN INVALID STATE");
1076 		/*NOTREACHED*/
1077 	}
1078 	if (is->hy_state == IDLE)
1079 		goto actloop;
1080 endintr:
1081 	;
1082 #ifdef DEBUG
1083 	printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit,
1084 		hy_state_names[is->hy_state]);
1085 #endif
1086 }
1087 
1088 struct sockproto hypproto = { PF_HYLINK };
1089 struct sockaddr_in hypdst = { sizeof(hypdst), AF_HYLINK };
1090 struct sockaddr_in hypsrc = { sizeof(hypsrc), AF_HYLINK };
1091 
1092 /*
1093  * Called from device interrupt when receiving data.
1094  * Examine packet to determine type.  Decapsulate packet
1095  * based on type and pass to type specific higher-level
1096  * input routine.
1097  */
1098 hyrecvdata(ui, hym, len)
1099 	struct uba_device *ui;
1100 	register struct hym_hdr *hym;
1101 	int len;
1102 {
1103 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
1104     	struct mbuf *m;
1105 	register struct ifqueue *inq;
1106 
1107 	is->hy_if.if_ipackets++;
1108 #ifdef DEBUG
1109 	printD("hy%d: recieved packet, len = %d\n", ui->ui_unit, len);
1110 #endif
1111 #ifdef HYLOG
1112 	{
1113 		struct {
1114 			short hlen;
1115 			struct hym_hdr hhdr;
1116 		} hh;
1117 		hh.hlen = len;
1118 		hh.hhdr = *hym;
1119 		hylog(HYL_RECV, sizeof(hh), (char *)&hh);
1120 	}
1121 #endif
1122 	if (len > HYMTU + MPSIZE || len == 0)
1123 		return;			/* sanity */
1124 	/*
1125 	 * Pull packet off interface.
1126 	 */
1127 	m = if_rubaget(&is->hy_ifuba, len, 0, &is->hy_if);
1128 	if (m == NULL)
1129 		return;
1130 
1131 	/*
1132 	 * if normal or adapter loopback response packet believe hym_type,
1133 	 * otherwise, use the raw input queue cause it's a response from an
1134 	 * adapter command.
1135 	 */
1136 	if (hym->hym_param != 0 && (u_short)hym->hym_param != 0x80ff)
1137 		goto rawlinkin;
1138 
1139 	switch (hym->hym_type) {
1140 
1141 #ifdef INET
1142 	case HYLINK_IP:
1143 		schednetisr(NETISR_IP);
1144 		inq = &ipintrq;
1145 		break;
1146 #endif
1147 	default:
1148 	rawlinkin:
1149 		{
1150 			M_PREPEND(m, sizeof(struct hym_hdr), M_DONTWAIT);
1151 			if (m == 0) {
1152 				m_freem(m);
1153 				return;
1154 			}
1155 			bcopy((caddr_t)hym, mtod(m, caddr_t), sizeof(struct hym_hdr));
1156 			hypproto.sp_protocol = 0;
1157 			hypdst.sin_addr = is->hy_addr;
1158 			hypsrc.sin_addr = is->hy_addr;
1159 			raw_input(m, &hypproto, (struct sockaddr *)&hypsrc,
1160 				(struct sockaddr *)&hypdst);
1161 			return;
1162 		}
1163 	}
1164 	if (IF_QFULL(inq)) {
1165 		IF_DROP(inq);
1166 		m_freem(m);
1167 	} else
1168 		IF_ENQUEUE(inq, m);
1169 }
1170 
1171 /*
1172  * Transmit done, release resources, bump counters.
1173  */
1174 hyxmitdata(ui)
1175 	struct uba_device *ui;
1176 {
1177 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
1178 
1179 	is->hy_if.if_opackets++;
1180 	if (is->hy_ifuba.ifu_xtofree) {
1181 		m_freem(is->hy_ifuba.ifu_xtofree);
1182 		is->hy_ifuba.ifu_xtofree = 0;
1183 	}
1184 }
1185 
1186 hycancel(ui)
1187 	register struct uba_device *ui;
1188 {
1189 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
1190 
1191 	if (is->hy_ifuba.ifu_xtofree) {
1192 		m_freem(is->hy_ifuba.ifu_xtofree);
1193 		is->hy_ifuba.ifu_xtofree = 0;
1194 	}
1195 #ifdef HYLOG
1196 	hylog(HYL_CANCEL, 0, (char *)0);
1197 #endif
1198 #ifdef DEBUG
1199 	if (hy_nodebug & 1)
1200 		hy_debug_flag = 1;
1201 #endif
1202 #ifdef DEBUG
1203 	printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n",
1204 		ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd,
1205 		is->hy_savedcount, is->hy_savedaddr);
1206 	printD("\tflags 0x%x olen %d lastwcr %d retry %d\n",
1207 		is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry);
1208 	printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n",
1209 		is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr,
1210 		is->hy_savedcmd);
1211 #endif
1212 	is->hy_state = IDLE;
1213 	is->hy_flags |= (RQ_ENDOP | RQ_STATUS);
1214 	hyact(ui);
1215 }
1216 
1217 #ifdef DEBUG
1218 hyprintdata(cp, len)
1219 	register char *cp;
1220 	register int len;
1221 {
1222 	register int count = 16;
1223 	register char *fmt;
1224 	static char regfmt[] = "\n\t %x";
1225 
1226 	fmt = &regfmt[2];
1227 	while (--len >= 0) {
1228 		printL(fmt, *cp++ & 0xff);
1229 		fmt = &regfmt[2];
1230 		if (--count <= 0) {
1231 			fmt = &regfmt[0];
1232 			count = 16;
1233 		}
1234 	}
1235 	printL("\n");
1236 }
1237 #endif
1238 
1239 hywatch(unit)
1240 	int unit;
1241 {
1242 	register struct hy_softc *is = &hy_softc[unit];
1243 	register struct uba_device *ui = hyinfo[unit];
1244 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
1245 	int s;
1246 
1247 	s = splimp();
1248 #ifdef PI13
1249 	if ((addr->hyd_csr & S_POWEROFF) != 0) {
1250 		addr->hyd_csr |= S_POWEROFF;
1251 		DELAY(100);
1252 		if ((addr->hyd_csr & S_POWEROFF) == 0) {
1253 			printf("hy%d: Adapter Power Restored (hywatch)\n", unit);
1254 			is->hy_state = IDLE;
1255 			is->hy_flags |=
1256 			  (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS);
1257 			hyact(ui);
1258 		}
1259 	}
1260 #endif
1261 	if (++is->hy_ntime >= 2 && is->hy_state != WAITING &&
1262 	  is->hy_state != STARTUP && is->hy_state != IDLE) {
1263 #ifdef HYLOG
1264 		printf("hy%d: watchdog timer expired in state \"%s\"\n", unit,
1265 			hy_state_names[is->hy_state]);
1266 #else
1267 		printf("hy%d: watchdog timer expired in state %d\n", unit,
1268 			is->hy_state);
1269 #endif
1270 		printf("hy%d: last command 0x%x, flags 0x%x, csr 0x%b\n", unit,
1271 			is->hy_savedcmd, is->hy_flags, addr->hyd_csr, HY_CSR_BITS);
1272 		hycancel(ui);
1273 	}
1274 	splx(s);
1275 	is->hy_if.if_timer = SCANINTERVAL;
1276 }
1277 
1278 #ifdef HYLOG
1279 hylog(code, len, ptr)
1280 	int code, len;
1281 	char *ptr;
1282 {
1283 	register unsigned char *p;
1284 	int s;
1285 
1286 	s = splimp();
1287 	if (hy_log.hyl_self != &hy_log) {
1288 		hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE];
1289 		hy_log.hyl_ptr = &hy_log.hyl_buf[0];
1290 		hy_log.hyl_self = &hy_log;
1291 		hy_log.hyl_enable = HYL_CONTINUOUS;
1292 		hy_log.hyl_onerr = HYL_CONTINUOUS;
1293 		hy_log.hyl_count = 0;
1294 		hy_log.hyl_icount = 16;
1295 		hy_log.hyl_filter = 0xffff;	/* enable all */
1296 	}
1297 	if (hy_log.hyl_enable == HYL_DISABLED || ((1 << code) & hy_log.hyl_filter) == 0)
1298 		goto out;
1299 	p = hy_log.hyl_ptr;
1300 	if (p + len + 3 >= hy_log.hyl_eptr) {
1301 		bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p));
1302 		p = &hy_log.hyl_buf[0];
1303 		if (hy_log.hyl_enable != HYL_CONTINUOUS) {
1304 			hy_log.hyl_enable = HYL_DISABLED;
1305 			goto out;
1306 		}
1307 	}
1308 	*p++ = code;
1309 	*p++ = len;
1310 	bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len);
1311 	if (hy_log.hyl_count != 0 && --hy_log.hyl_count == 0) {
1312 		*p++ = '\0';
1313 		hy_log.hyl_enable = HYL_DISABLED;
1314 		hy_log.hyl_count = hy_log.hyl_icount;
1315 	}
1316 	p += len;
1317 	if (hy_log.hyl_wait != 0) {		/* wakeup HYGETLOG if wanted */
1318 		if (hy_log.hyl_wait <= p - hy_log.hyl_ptr) {
1319 			wakeup((caddr_t)&hy_log);
1320 			hy_log.hyl_wait = 0;
1321 		} else
1322 			hy_log.hyl_wait -= p - hy_log.hyl_ptr;
1323 	}
1324 	hy_log.hyl_ptr = p;
1325 out:
1326 	splx(s);
1327 }
1328 #endif
1329 
1330 /*ARGSUSED*/
1331 hyioctl(ifp, cmd, data)
1332 	register struct ifnet *ifp;
1333 	int cmd;
1334 	caddr_t	data;
1335 {
1336 	struct ifaddr *ifa = (struct ifaddr *) data;
1337 	struct hyrsetget *sg = (struct hyrsetget *)data;
1338 #if defined(HYLOG) || defined(HYELOG)
1339 	struct hylsetget *sgl = (struct hylsetget *)data;
1340 #endif
1341 	struct hy_route *r = (struct hy_route *)&hy_route[ifp->if_unit];
1342 	int s = splimp(), error = 0;
1343 #ifdef HYLOG
1344 	struct hy_softc *is = &hy_softc[ifp->if_unit];
1345 	struct {
1346 		u_char	hstate;
1347 		u_char	hflags;
1348 		u_short	iflags;
1349 		int	hcmd;
1350 		int	herror;
1351 		u_long	haddr;
1352 		u_long	hmisc;
1353 	} hil;
1354 
1355 	hil.hmisc = -1;
1356 	hil.hstate = is->hy_state;
1357 	hil.hflags = is->hy_flags;
1358 	hil.hcmd = cmd;
1359 #endif
1360 
1361 	switch(cmd) {
1362 
1363 	case SIOCSIFADDR:
1364 		if (ifa->ifa_addr->sa_family != AF_INET)
1365 			return(EINVAL);
1366 		if ((ifp->if_flags & IFF_RUNNING) == 0)
1367 			hyinit(ifp->if_unit);
1368 		hy_softc[ifp->if_unit].hy_addr = IA_SIN(ifa)->sin_addr;
1369 #ifdef HYLOG
1370 		hil.haddr = is->hy_addr.s_addr;
1371 #endif
1372 		break;
1373 
1374 	case HYSETROUTE:
1375 		if (error = suser(u.u_cred, &u.u_acflag))
1376 			goto out;
1377 
1378 		if (sg->hyrsg_len != sizeof(struct hy_route)) {
1379 			error = EINVAL;
1380 			goto out;
1381 		}
1382 		if (copyin((caddr_t)(sg->hyrsg_ptr), (caddr_t)r, sg->hyrsg_len)) {
1383 			r->hyr_lasttime = 0;	/* disable further routing if trouble */
1384 			error = EFAULT;
1385 			goto out;
1386 		}
1387 		r->hyr_lasttime = time.tv_sec;
1388 #ifdef HYLOG
1389 		hil.hmisc = r->hyr_lasttime;
1390 #endif
1391 		break;
1392 
1393 	case HYGETROUTE:
1394 		if (sg->hyrsg_len < sizeof(struct hy_route)) {
1395 			error = EINVAL;
1396 			goto out;
1397 		}
1398 		if (copyout((caddr_t)r, (caddr_t) (sg->hyrsg_ptr), sizeof(struct hy_route))) {
1399 			error = EFAULT;
1400 			goto out;
1401 		}
1402 		break;
1403 
1404 #ifdef HYELOG
1405 	case HYGETELOG:
1406 		if (sgl->hylsg_len < sizeof(hy_elog)) {
1407 			error = EINVAL;
1408 			goto out;
1409 		}
1410 		if (copyout((caddr_t)hy_elog, sgl->hylsg_ptr, sizeof(hy_elog))) {
1411 			error = EFAULT;
1412 			goto out;
1413 		}
1414 		if (sgl->hylsg_cmd) {
1415 			if (error = suser(u.u_cred, &u.u_acflag))
1416 				goto out;
1417 			bzero((caddr_t)hy_elog, sizeof(hy_elog));
1418 		}
1419 		break;
1420 #endif
1421 
1422 #ifdef HYLOG
1423 	case HYSETLOG:
1424 		if (error = suser(u.u_cred, &u.u_acflag))
1425 			goto out;
1426 		hy_log.hyl_enable = HYL_DISABLED;
1427 		hylog(HYL_NOP, 0, (char *)0);		/* force log init */
1428 		hy_log.hyl_enable = sgl->hylsg_cmd & 0x0f;
1429 		hy_log.hyl_onerr = (sgl->hylsg_cmd >> 4) & 0x0f;
1430 		hy_log.hyl_filter = (sgl->hylsg_cmd >> 8) & 0xffffff;
1431 		hy_log.hyl_count = hy_log.hyl_icount = sgl->hylsg_len;
1432 		wakeup((caddr_t)&hy_log);	/* wakeup sleeping HYGETLOG */
1433 		break;
1434 
1435 	case HYGETLOG:
1436 		if (sgl->hylsg_len < sizeof(hy_log)) {
1437 			error = EINVAL;
1438 			goto out;
1439 		}
1440 		if (sgl->hylsg_cmd != 0) {
1441 			if (hy_log.hyl_wait) {
1442 				error = EBUSY;
1443 				goto out;
1444 			}
1445 			hy_log.hyl_wait = sgl->hylsg_cmd;
1446 			sleep((caddr_t)&hy_log, PZERO - 1);
1447 		}
1448 
1449 		if (copyout((caddr_t)&hy_log, sgl->hylsg_ptr, sizeof(hy_log))) {
1450 			error = EFAULT;
1451 			goto out;
1452 		}
1453 		break;
1454 #endif
1455 
1456 	default:
1457 		error = EINVAL;
1458 		break;
1459 	}
1460 out:
1461 #ifdef HYLOG
1462 	hil.herror = error;
1463 	hil.iflags = ifp->if_flags;
1464 	hil.haddr = is->hy_addr.s_addr;
1465 	hylog(HYL_IOCTL, sizeof(hil), (char *)&hil);
1466 #endif
1467 	splx(s);
1468 	return (error);
1469 }
1470 #endif
1471