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