xref: /original-bsd/sys/vax/if/if_hy.c (revision dddc135c)
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.2 (Berkeley) 08/04/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 	if (m->m_off > MMAXOFF ||
605 	    MMINOFF + sizeof(struct hym_hdr) > m->m_off) {
606 		m = m_get(M_DONTWAIT, MT_HEADER);
607 		if (m == 0) {
608 			m = m0;
609 			error = ENOBUFS;
610 			goto drop;
611 		}
612 		m->m_next = m0;
613 		m->m_off = MMINOFF;
614 		m->m_len = sizeof(struct hym_hdr);
615 	} else {
616 		m->m_off -= sizeof(struct hym_hdr);
617 		m->m_len += sizeof(struct hym_hdr);
618 	}
619 
620 	dlen += sizeof(struct hym_hdr) - HYM_SWLEN;
621 
622 	hym = mtod(m, struct hym_hdr *);
623 
624 	bzero((caddr_t)hym, sizeof(struct hym_hdr));
625 
626 	switch(dst->sa_family) {
627 
628 #ifdef INET
629 	case AF_INET: {
630 		int i;
631 
632 		/*
633 		 * if loopback address, swizzle ip header so when
634 		 * it comes back it looks like it was addressed to us
635 		 */
636 		i = hyroute(ifp, (u_long)in_lnaof(((struct sockaddr_in *)dst)->sin_addr), hym);
637 		if (i < 0)
638 			goto notfound;
639 		if (i > 0) {
640 			struct in_addr temp;
641 
642 			temp.s_addr = ((struct ip *)mp)->ip_dst.s_addr;
643 			((struct ip *)mp)->ip_dst.s_addr = ((struct ip *)mp)->ip_src.s_addr;
644 			((struct ip *)mp)->ip_src.s_addr = temp.s_addr;
645 		}
646 		/*
647 		 * If entire packet won't fit in message proper, just
648 		 * send hyperchannel hardware header and ip header in
649 		 * message proper.
650 		 *
651 		 * This insures that the associated data is at least a
652 		 * TCP/UDP header in length and thus prevents potential
653 		 * problems with very short word counts.
654 		 */
655 		if (dlen > MPSIZE)
656 			hym->hym_mplen = sizeof(struct hy_hdr) + (((struct ip *)mp)->ip_hl << 2);
657 		hym->hym_type = HYLINK_IP;
658 		break;
659 	}
660 #endif
661 
662 	default:
663 		printf("hy%d: can't handle af%d\n", ifp->if_unit,
664 			dst->sa_family);
665 		error = EAFNOSUPPORT;
666 		goto drop;
667 	}
668 
669 
670 headerexists:
671 
672 	/*
673 	 * insure message proper is below the maximum
674 	 */
675 	if (hym->hym_mplen > MPSIZE || (dlen > MPSIZE && hym->hym_mplen == 0))
676 		hym->hym_mplen = MPSIZE;
677 
678 	hym->hym_from = htons(hy_softc[ifp->if_unit].hy_host);
679 	if (hym->hym_mplen)
680 		hym->hym_ctl |= H_ASSOC;
681 	else
682 		hym->hym_ctl &= ~H_ASSOC;
683 	if (hyoutprint) printf("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n",
684 		ifp->if_unit, hym->hym_mplen, hym->hym_ctl,
685 		hym->hym_access, hym->hym_to, hym->hym_from,
686 		hym->hym_param, hym->hym_type);
687 #ifdef DEBUG
688 	printD("hy%d: output mplen=%x ctl=%x access=%x to=%x from=%x param=%x type=%x\n",
689 		ifp->if_unit, hym->hym_mplen, hym->hym_ctl,
690 		hym->hym_access, hym->hym_to, hym->hym_from,
691 		hym->hym_param, hym->hym_type);
692 #endif
693 	s = splimp();
694 	if (IF_QFULL(&ifp->if_snd)) {
695 		IF_DROP(&ifp->if_snd);
696 		error = ENOBUFS;
697 		splx(s);
698 		goto drop;
699 	}
700 	IF_ENQUEUE(&ifp->if_snd, m);
701 	if (hy_softc[ifp->if_unit].hy_state == WAITING)
702 		hyact(hyinfo[ifp->if_unit]);
703 	splx(s);
704 	return (0);
705 notfound:
706 	error = EHOSTUNREACH;
707 drop:
708 	m_freem(m);
709 	return (error);
710 }
711 
712 int
713 hyroute(ifp, dest, hym)
714 	register struct ifnet *ifp;
715 	u_long dest;
716 	register struct hym_hdr *hym;
717 {
718 #ifdef HYROUTE
719 	register struct hy_route *rt = &hy_route[ifp->if_unit];
720 	register struct hyr_hash *rhash;
721 	register int i;
722 #endif
723 
724 	hym->hym_param = 0;
725 #ifdef HYROUTE
726 	if (rt->hyr_lasttime != 0) {
727 		i = HYRHASH(dest);
728 		rhash = &rt->hyr_hash[i];
729 		i = 0;
730 		while (rhash->hyr_key != dest) {
731 			if (rhash->hyr_flags == 0 || i > HYRSIZE)
732 				return(-1);
733 			rhash++; i++;
734 			if (rhash >= &rt->hyr_hash[HYRSIZE])
735 				rhash = &rt->hyr_hash[0];
736 		}
737 		if (rhash->hyr_flags & HYR_GATE) {
738 			i = rhash->hyr_nextgate;
739 			if (i >= rhash->hyr_egate)
740 				rhash->hyr_nextgate = rhash->hyr_pgate;
741 			else
742 				rhash->hyr_nextgate++;
743 			rhash = &rt->hyr_hash[rt->hyr_gateway[i]];
744 			if ((rhash->hyr_flags & HYR_DIR) == 0)
745 				return(-1);
746 		} else if (rhash->hyr_flags & HYR_LOOP) {
747 			hym->hym_param = H_LOOPBK;	/* adapter loopback */
748 		} else if (rhash->hyr_flags & HYR_RLOOP) {
749 			hym->hym_param = H_RLOOPBK;	/* A710 remote loopback */
750 		}
751 		hym->hym_ctl = rhash->hyr_ctl;
752 		hym->hym_access = rhash->hyr_access;
753 		hym->hym_to = rhash->hyr_dst;
754 	} else {
755 #endif
756 		hym->hym_ctl = H_XTRUNKS | H_RTRUNKS;
757 		hym->hym_access = 0;
758 		hym->hym_to = htons((u_short)dest);
759 		if (dest & 0x010000)
760 			hym->hym_param = H_LOOPBK;	/* adapter loopback */
761 		else if (dest & 0x020000)
762 			hym->hym_param = H_RLOOPBK;	/* A710 remote loopback */
763 #ifdef HYROUTE
764 	}
765 #endif
766 
767 	if (hym->hym_param == 0)
768 		return(0);
769 	else
770 		return(1);
771 }
772 
773 hyact(ui)
774 	register struct uba_device *ui;
775 {
776 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
777 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
778 
779 actloop:
780 #ifdef DEBUG
781 	printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit,
782 		hy_state_names[is->hy_state]);
783 #endif
784 	switch (is->hy_state) {
785 
786 	case STARTUP:
787 		goto endintr;
788 
789 	case IDLE: {
790 		register rq = is->hy_flags;
791 
792 		if (rq & RQ_STATUS) {
793 			is->hy_flags &= ~RQ_STATUS;
794 			is->hy_state = STATSENT;
795 			hystart(ui, HYF_STATUS, sizeof (is->hy_status),
796 			    is->hy_ifuba.ifu_r.ifrw_info);
797 		} else if (rq & RQ_ENDOP) {
798 			is->hy_flags &= ~RQ_ENDOP;
799 			is->hy_state = ENDOPSENT;
800 			hystart(ui, HYF_END_OP, 0, 0);
801 		} else if (rq & RQ_STATISTICS) {
802 			is->hy_flags &= ~RQ_STATISTICS;
803 			is->hy_state = RSTATSENT;
804 			hystart(ui, HYF_RSTATS, sizeof (is->hy_stat),
805 			    is->hy_ifuba.ifu_r.ifrw_info);
806 		} else if (HYS_RECVDATA(addr)) {
807 			is->hy_state = RECVSENT;
808 			is->hy_retry = 0;
809 			hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info + HYM_SWLEN);
810 		} else if (rq & RQ_REISSUE) {
811 			is->hy_flags &= ~RQ_REISSUE;
812 			is->hy_state = is->hy_savedstate;
813 #ifdef DEBUG
814 			printD("hy%d: reissue cmd=0x%x count=%d",
815 			  ui->ui_unit, is->hy_savedcmd, is->hy_savedcount);
816 			printD(" ubaddr=0x%x retry=%d\n",
817 			  is->hy_savedaddr, is->hy_retry);
818 #endif
819 			hystart(ui, is->hy_savedcmd, is->hy_savedcount,
820 			    is->hy_savedaddr);
821 		} else {
822 			register struct mbuf *m;
823 
824 			IF_DEQUEUE(&is->hy_if.if_snd, m);
825 			if (m != NULL) {
826 				register struct hym_hdr *hym;
827 				register int mplen;
828 				register int cmd;
829 
830 				is->hy_state = XMITSENT;
831 				is->hy_retry = 0;
832 				hym = mtod(m, struct hym_hdr *);
833 #ifdef HYLOG
834 				hylog(HYL_XMIT, sizeof(struct hym_hdr),
835 				    (char *)hym);
836 #endif
837 				mplen = hym->hym_mplen;
838 				if (hym->hym_to_adapter == hym->hym_from_adapter)
839 					cmd = HYF_XMITLOCMSG;
840 				else
841 					cmd = HYF_XMITMSG;
842 #ifdef DEBUG
843 				printD("hy%d: hym_hdr = ", ui->ui_unit);
844 				if (hy_debug_flag)
845 					hyprintdata((char *)hym,
846 					    sizeof (struct hym_hdr));
847 #endif
848 				is->hy_olen = if_wubaput(&is->hy_ifuba, m) - HYM_SWLEN;
849 				if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
850 					UBAPURGE(is->hy_ifuba.ifu_uba,
851 						is->hy_ifuba.ifu_w.ifrw_bdp);
852 #ifdef DEBUG
853 				printD(
854 		"hy%d: sending packet (mplen = %d, hy_olen = %d) data = ",
855 					ui->ui_unit, mplen, is->hy_olen);
856 				if (hy_debug_flag)
857 					hyprintdata(
858 					    is->hy_ifuba.ifu_w.ifrw_addr,
859 					    is->hy_olen + HYM_SWLEN);
860 #endif
861 				if (mplen == 0) {
862 					is->hy_flags &= ~RQ_XASSOC;
863 					mplen = is->hy_olen;
864 				} else {
865 					is->hy_flags |= RQ_XASSOC;
866 				}
867 				hystart(ui, cmd, mplen, is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN);
868 			} else if (rq & RQ_MARKDOWN) {
869 				is->hy_flags &= ~(RQ_MARKUP | RQ_MARKDOWN);
870 				is->hy_state = MARKPORT;
871 				is->hy_retry = 0;
872 				/*
873 				 * Port number is taken from status data
874 				 */
875 				hystart(ui,
876 				 (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)),
877 				 0, 0);
878 			} else if (rq & RQ_MARKUP) {
879 				register struct ifnet *ifp = &is->hy_if;
880 
881 				is->hy_flags &= ~RQ_MARKUP;
882 				is->hy_retry = 0;
883 				/*
884 				 * Fill in the host number
885 				 * from the status buffer
886 				 */
887 				printf(
888 	"hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n",
889 					ui->ui_unit,
890 					is->hy_stat.hyc_uaddr,
891 					PORTNUM(&is->hy_status),
892 					(is->hy_stat.hyc_atype[0]<<8) |
893 						is->hy_stat.hyc_atype[1],
894 					is->hy_stat.hyc_atype[2]);
895 
896 				is->hy_host =
897 				  (is->hy_stat.hyc_uaddr << 8) |
898 					PORTNUM(&is->hy_status);
899 				ifp->if_flags |= IFF_UP;
900 #ifdef HYLOG
901 				hylog(HYL_UP, 0, (char *)0);
902 #endif
903 			} else {
904 				is->hy_state = WAITING;
905 				is->hy_retry = 0;
906 				hystart(ui, HYF_WAITFORMSG, 0, 0);
907 			}
908 		}
909 		break;
910 	}
911 
912 	case STATSENT:
913 		bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status,
914 		  sizeof (struct hy_status));
915 #ifdef DEBUG
916 		printD("hy%d: status - %x %x %x %x %x %x %x %x\n",
917 			ui->ui_unit, is->hy_status.hys_gen_status,
918 			is->hy_status.hys_last_fcn,
919 			is->hy_status.hys_resp_trunk,
920 			is->hy_status.hys_status_trunk,
921 			is->hy_status.hys_recd_resp,
922 			is->hy_status.hys_error,
923 			is->hy_status.hys_caddr,
924 			is->hy_status.hys_pad);
925 #endif
926 		is->hy_state = IDLE;
927 #ifdef HYLOG
928 		hylog(HYL_STATUS, sizeof (struct hy_status),
929 			(char *)&is->hy_status);
930 #endif
931 #ifdef HYELOG
932 		{
933 			register int i;
934 
935 			i = is->hy_status.hys_error;
936 			if (i > HYE_MAX)
937 				i = HYE_MAX;
938 			switch (is->hy_status.hys_last_fcn) {
939 				case HYF_XMITLOCMSG:
940 					i += HYE_MAX+1;	/* fall through */
941 				case HYF_XMITLSTDATA:
942 					i += HYE_MAX+1;	/* fall through */
943 				case HYF_XMITMSG:
944 					i += HYE_MAX+1;
945 			}
946 			hy_elog[i]++;
947 		}
948 #endif
949 		break;
950 
951 	case RSTATSENT: {
952 		register struct hy_stat *p =
953 			(struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr;
954 
955 		bcopy((caddr_t)p, (caddr_t)&is->hy_stat, sizeof(struct hy_stat));
956 #ifdef DEBUG
957 
958 		printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n",
959 			ui->ui_unit,
960 			(is->hy_stat.hyc_df0[0]<<16) | (is->hy_stat.hyc_df0[1]<<8) | is->hy_stat.hyc_df0[2],
961 			(is->hy_stat.hyc_df1[0]<<16) | (is->hy_stat.hyc_df1[1]<<8) | is->hy_stat.hyc_df1[2],
962 			(is->hy_stat.hyc_df2[0]<<16) | (is->hy_stat.hyc_df2[1]<<8) | is->hy_stat.hyc_df2[2],
963 			(is->hy_stat.hyc_df3[0]<<16) | (is->hy_stat.hyc_df3[1]<<8) | is->hy_stat.hyc_df3[2]);
964 		printD("	ret0 %d ret1 %d ret2 %d ret3 %d\n",
965 			(is->hy_stat.hyc_ret0[0]<<16) | (is->hy_stat.hyc_ret0[1]<<8) | is->hy_stat.hyc_ret0[2],
966 			(is->hy_stat.hyc_ret1[0]<<16) | (is->hy_stat.hyc_ret1[1]<<8) | is->hy_stat.hyc_ret1[2],
967 			(is->hy_stat.hyc_ret2[0]<<16) | (is->hy_stat.hyc_ret2[1]<<8) | is->hy_stat.hyc_ret2[2],
968 			(is->hy_stat.hyc_ret3[0]<<16) | (is->hy_stat.hyc_ret3[1]<<8) | is->hy_stat.hyc_ret3[2]);
969 		printD("	cancel %d abort %d atype %x %x %x uaddr %x\n",
970 			(is->hy_stat.hyc_cancel[0]<<8) | is->hy_stat.hyc_cancel[1],
971 			(is->hy_stat.hyc_abort[0]<<8) | is->hy_stat.hyc_abort[1],
972 			is->hy_stat.hyc_atype[0], is->hy_stat.hyc_atype[1],
973 			is->hy_stat.hyc_atype[2], is->hy_stat.hyc_uaddr);
974 #endif
975 		is->hy_state = IDLE;
976 #ifdef HYLOG
977 		hylog(HYL_STATISTICS, sizeof (struct hy_stat),
978 			(char *)&is->hy_stat);
979 #endif
980 		break;
981 	}
982 
983 	case CLEARSENT:
984 		is->hy_state = IDLE;
985 		break;
986 
987 	case ENDOPSENT:
988 		is->hy_state = IDLE;
989 		break;
990 
991 	case RECVSENT: {
992 		register struct hym_hdr *hym;
993 		register unsigned len;
994 
995 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
996 			UBAPURGE(is->hy_ifuba.ifu_uba,
997 			    is->hy_ifuba.ifu_r.ifrw_bdp);
998 		hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
999 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
1000 		if (len > MPSIZE) {
1001 			printf("hy%d: RECVD MP > MPSIZE (%d)\n",
1002 			    ui->ui_unit, len);
1003 			is->hy_state = IDLE;
1004 #ifdef DEBUG
1005 			hy_debug_flag = 1;
1006 			printD("hy%d: csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
1007 				ui->ui_unit, addr->hyd_csr, HY_CSR_BITS,
1008 				addr->hyd_bar, addr->hyd_wcr);
1009 #endif
1010 		}
1011 		hym->hym_mplen = len;
1012 #ifdef DEBUG
1013 		printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len);
1014 		if (hy_debug_flag)
1015 			hyprintdata((char *)hym, len + HYM_SWLEN);
1016 #endif
1017 		if (hym->hym_ctl & H_ASSOC) {
1018 			is->hy_state = RECVDATASENT;
1019 			is->hy_retry = 0;
1020 			hystart(ui, HYF_INPUTDATA,
1021 			    (int)(HYMTU + sizeof (struct hy_hdr) - len),
1022 			    (int)(HYM_SWLEN + is->hy_ifuba.ifu_r.ifrw_info + len));
1023 		} else {
1024 			hyrecvdata(ui, hym, (int)len + HYM_SWLEN);
1025 			is->hy_state = IDLE;
1026 		}
1027 		break;
1028 	}
1029 
1030 	case RECVDATASENT: {
1031 		register struct hym_hdr *hym;
1032 		register unsigned len;
1033 
1034 		if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
1035 			UBAPURGE(is->hy_ifuba.ifu_uba,
1036 			    is->hy_ifuba.ifu_r.ifrw_bdp);
1037 		hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
1038 		len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
1039 #ifdef DEBUG
1040 		printD("hy%d: recvd assoc data, len = %d, data = ",
1041 			ui->ui_unit, len);
1042 		if (hy_debug_flag)
1043 			hyprintdata((char *)hym + hym->hym_mplen, len);
1044 #endif
1045 		hyrecvdata(ui, hym, (int)(len + hym->hym_mplen + HYM_SWLEN));
1046 		is->hy_state = IDLE;
1047 		break;
1048 	}
1049 
1050 	case XMITSENT:
1051 		if (is->hy_flags & RQ_XASSOC) {
1052 			register int len;
1053 
1054 			is->hy_flags &= ~RQ_XASSOC;
1055 			is->hy_state = XMITDATASENT;
1056 			is->hy_retry = 0;
1057 			len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
1058 			if (len > is->hy_olen) {
1059 				printf(
1060 				"hy%d: xmit error - len > hy_olen [%d > %d]\n",
1061 				ui->ui_unit, len, is->hy_olen);
1062 #ifdef DEBUG
1063 				hy_debug_flag = 1;
1064 #endif
1065 			}
1066 			hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len,
1067 			    is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN + len);
1068 			break;
1069 		}
1070 		/* fall through to ... */
1071 
1072 	case XMITDATASENT:
1073 		hyxmitdata(ui);
1074 		is->hy_state = IDLE;
1075 		break;
1076 
1077 	case WAITING:	/* wait for message complete or output requested */
1078 		if (HYS_RECVDATA(addr))
1079 			is->hy_state = IDLE;
1080 		else {
1081 			is->hy_state = CLEARSENT;
1082 			is->hy_retry = 0;
1083 			hystart(ui, HYF_CLRWFMSG, 0, 0);
1084 		}
1085 		break;
1086 
1087 	case MARKPORT:
1088 		is->hy_state = STARTUP;
1089 		if_down(&is->hy_if);
1090 		is->hy_if.if_flags &= ~IFF_UP;
1091 		goto endintr;
1092 
1093 	default:
1094 		printf("hy%d: DRIVER BUG - INVALID STATE %d\n",
1095 			ui->ui_unit, is->hy_state);
1096 		panic("HYPERCHANNEL IN INVALID STATE");
1097 		/*NOTREACHED*/
1098 	}
1099 	if (is->hy_state == IDLE)
1100 		goto actloop;
1101 endintr:
1102 	;
1103 #ifdef DEBUG
1104 	printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit,
1105 		hy_state_names[is->hy_state]);
1106 #endif
1107 }
1108 
1109 struct sockproto hypproto = { PF_HYLINK };
1110 struct sockaddr_in hypdst = { AF_HYLINK };
1111 struct sockaddr_in hypsrc = { AF_HYLINK };
1112 
1113 /*
1114  * Called from device interrupt when receiving data.
1115  * Examine packet to determine type.  Decapsulate packet
1116  * based on type and pass to type specific higher-level
1117  * input routine.
1118  */
1119 hyrecvdata(ui, hym, len)
1120 	struct uba_device *ui;
1121 	register struct hym_hdr *hym;
1122 	int len;
1123 {
1124 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
1125     	struct mbuf *m;
1126 	register struct ifqueue *inq;
1127 
1128 	is->hy_if.if_ipackets++;
1129 #ifdef DEBUG
1130 	printD("hy%d: recieved packet, len = %d\n", ui->ui_unit, len);
1131 #endif
1132 #ifdef HYLOG
1133 	{
1134 		struct {
1135 			short hlen;
1136 			struct hym_hdr hhdr;
1137 		} hh;
1138 		hh.hlen = len;
1139 		hh.hhdr = *hym;
1140 		hylog(HYL_RECV, sizeof(hh), (char *)&hh);
1141 	}
1142 #endif
1143 	if (len > HYMTU + MPSIZE || len == 0)
1144 		return;			/* sanity */
1145 	/*
1146 	 * Pull packet off interface.
1147 	 */
1148 	m = if_rubaget(&is->hy_ifuba, len, 0, &is->hy_if);
1149 	if (m == NULL)
1150 		return;
1151 
1152 	/*
1153 	 * if normal or adapter loopback response packet believe hym_type,
1154 	 * otherwise, use the raw input queue cause it's a response from an
1155 	 * adapter command.
1156 	 */
1157 	if (hym->hym_param != 0 && (u_short)hym->hym_param != 0x80ff)
1158 		goto rawlinkin;
1159 
1160 	switch (hym->hym_type) {
1161 
1162 #ifdef INET
1163 	case HYLINK_IP:
1164 		schednetisr(NETISR_IP);
1165 		inq = &ipintrq;
1166 		break;
1167 #endif
1168 	default:
1169 	rawlinkin:
1170 		{
1171 			struct mbuf *m0;
1172 
1173 			MGET(m0, M_DONTWAIT, MT_DATA);
1174 			if (m0 == 0) {
1175 				m_freem(m);
1176 				return;
1177 			}
1178 			m0->m_off = MMINOFF;
1179 			m0->m_len = sizeof(struct hym_hdr);
1180 			m0->m_next = m;
1181 			bcopy((caddr_t)hym, mtod(m0, caddr_t), sizeof(struct hym_hdr));
1182 			m = m0;
1183 			hypproto.sp_protocol = 0;
1184 			hypdst.sin_addr = is->hy_addr;
1185 			hypsrc.sin_addr = is->hy_addr;
1186 			raw_input(m, &hypproto, (struct sockaddr *)&hypsrc,
1187 				(struct sockaddr *)&hypdst);
1188 			return;
1189 		}
1190 	}
1191 	if (IF_QFULL(inq)) {
1192 		IF_DROP(inq);
1193 		m_freem(m);
1194 	} else
1195 		IF_ENQUEUE(inq, m);
1196 }
1197 
1198 /*
1199  * Transmit done, release resources, bump counters.
1200  */
1201 hyxmitdata(ui)
1202 	struct uba_device *ui;
1203 {
1204 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
1205 
1206 	is->hy_if.if_opackets++;
1207 	if (is->hy_ifuba.ifu_xtofree) {
1208 		m_freem(is->hy_ifuba.ifu_xtofree);
1209 		is->hy_ifuba.ifu_xtofree = 0;
1210 	}
1211 }
1212 
1213 hycancel(ui)
1214 	register struct uba_device *ui;
1215 {
1216 	register struct hy_softc *is = &hy_softc[ui->ui_unit];
1217 
1218 	if (is->hy_ifuba.ifu_xtofree) {
1219 		m_freem(is->hy_ifuba.ifu_xtofree);
1220 		is->hy_ifuba.ifu_xtofree = 0;
1221 	}
1222 #ifdef HYLOG
1223 	hylog(HYL_CANCEL, 0, (char *)0);
1224 #endif
1225 #ifdef DEBUG
1226 	if (hy_nodebug & 1)
1227 		hy_debug_flag = 1;
1228 #endif
1229 #ifdef DEBUG
1230 	printD("hy%d: cancel from state \"%s\" cmd=0x%x count=%d ptr=0x%x\n",
1231 		ui->ui_unit, hy_state_names[is->hy_state], is->hy_savedcmd,
1232 		is->hy_savedcount, is->hy_savedaddr);
1233 	printD("\tflags 0x%x olen %d lastwcr %d retry %d\n",
1234 		is->hy_flags, is->hy_olen, is->hy_lastwcr, is->hy_retry);
1235 	printD("\tsaved: state %d count %d ptr 0x%x cmd 0x%x\n",
1236 		is->hy_savedstate, is->hy_savedcount, is->hy_savedaddr,
1237 		is->hy_savedcmd);
1238 #endif
1239 	is->hy_state = IDLE;
1240 	is->hy_flags |= (RQ_ENDOP | RQ_STATUS);
1241 	hyact(ui);
1242 }
1243 
1244 #ifdef DEBUG
1245 hyprintdata(cp, len)
1246 	register char *cp;
1247 	register int len;
1248 {
1249 	register int count = 16;
1250 	register char *fmt;
1251 	static char regfmt[] = "\n\t %x";
1252 
1253 	fmt = &regfmt[2];
1254 	while (--len >= 0) {
1255 		printL(fmt, *cp++ & 0xff);
1256 		fmt = &regfmt[2];
1257 		if (--count <= 0) {
1258 			fmt = &regfmt[0];
1259 			count = 16;
1260 		}
1261 	}
1262 	printL("\n");
1263 }
1264 #endif
1265 
1266 hywatch(unit)
1267 	int unit;
1268 {
1269 	register struct hy_softc *is = &hy_softc[unit];
1270 	register struct uba_device *ui = hyinfo[unit];
1271 	register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
1272 	int s;
1273 
1274 	s = splimp();
1275 #ifdef PI13
1276 	if ((addr->hyd_csr & S_POWEROFF) != 0) {
1277 		addr->hyd_csr |= S_POWEROFF;
1278 		DELAY(100);
1279 		if ((addr->hyd_csr & S_POWEROFF) == 0) {
1280 			printf("hy%d: Adapter Power Restored (hywatch)\n", unit);
1281 			is->hy_state = IDLE;
1282 			is->hy_flags |=
1283 			  (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS);
1284 			hyact(ui);
1285 		}
1286 	}
1287 #endif
1288 	if (++is->hy_ntime >= 2 && is->hy_state != WAITING &&
1289 	  is->hy_state != STARTUP && is->hy_state != IDLE) {
1290 #ifdef HYLOG
1291 		printf("hy%d: watchdog timer expired in state \"%s\"\n", unit,
1292 			hy_state_names[is->hy_state]);
1293 #else
1294 		printf("hy%d: watchdog timer expired in state %d\n", unit,
1295 			is->hy_state);
1296 #endif
1297 		printf("hy%d: last command 0x%x, flags 0x%x, csr 0x%b\n", unit,
1298 			is->hy_savedcmd, is->hy_flags, addr->hyd_csr, HY_CSR_BITS);
1299 		hycancel(ui);
1300 	}
1301 	splx(s);
1302 	is->hy_if.if_timer = SCANINTERVAL;
1303 }
1304 
1305 #ifdef HYLOG
1306 hylog(code, len, ptr)
1307 	int code, len;
1308 	char *ptr;
1309 {
1310 	register unsigned char *p;
1311 	int s;
1312 
1313 	s = splimp();
1314 	if (hy_log.hyl_self != &hy_log) {
1315 		hy_log.hyl_eptr = &hy_log.hyl_buf[HYL_SIZE];
1316 		hy_log.hyl_ptr = &hy_log.hyl_buf[0];
1317 		hy_log.hyl_self = &hy_log;
1318 		hy_log.hyl_enable = HYL_CONTINUOUS;
1319 		hy_log.hyl_onerr = HYL_CONTINUOUS;
1320 		hy_log.hyl_count = 0;
1321 		hy_log.hyl_icount = 16;
1322 		hy_log.hyl_filter = 0xffff;	/* enable all */
1323 	}
1324 	if (hy_log.hyl_enable == HYL_DISABLED || ((1 << code) & hy_log.hyl_filter) == 0)
1325 		goto out;
1326 	p = hy_log.hyl_ptr;
1327 	if (p + len + 3 >= hy_log.hyl_eptr) {
1328 		bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p));
1329 		p = &hy_log.hyl_buf[0];
1330 		if (hy_log.hyl_enable != HYL_CONTINUOUS) {
1331 			hy_log.hyl_enable = HYL_DISABLED;
1332 			goto out;
1333 		}
1334 	}
1335 	*p++ = code;
1336 	*p++ = len;
1337 	bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len);
1338 	if (hy_log.hyl_count != 0 && --hy_log.hyl_count == 0) {
1339 		*p++ = '\0';
1340 		hy_log.hyl_enable = HYL_DISABLED;
1341 		hy_log.hyl_count = hy_log.hyl_icount;
1342 	}
1343 	p += len;
1344 	if (hy_log.hyl_wait != 0) {		/* wakeup HYGETLOG if wanted */
1345 		if (hy_log.hyl_wait <= p - hy_log.hyl_ptr) {
1346 			wakeup((caddr_t)&hy_log);
1347 			hy_log.hyl_wait = 0;
1348 		} else
1349 			hy_log.hyl_wait -= p - hy_log.hyl_ptr;
1350 	}
1351 	hy_log.hyl_ptr = p;
1352 out:
1353 	splx(s);
1354 }
1355 #endif
1356 
1357 /*ARGSUSED*/
1358 hyioctl(ifp, cmd, data)
1359 	register struct ifnet *ifp;
1360 	int cmd;
1361 	caddr_t	data;
1362 {
1363 	struct ifaddr *ifa = (struct ifaddr *) data;
1364 	struct hyrsetget *sg = (struct hyrsetget *)data;
1365 #if defined(HYLOG) || defined(HYELOG)
1366 	struct hylsetget *sgl = (struct hylsetget *)data;
1367 #endif
1368 	struct hy_route *r = (struct hy_route *)&hy_route[ifp->if_unit];
1369 	int s = splimp(), error = 0;
1370 #ifdef HYLOG
1371 	struct hy_softc *is = &hy_softc[ifp->if_unit];
1372 	struct {
1373 		u_char	hstate;
1374 		u_char	hflags;
1375 		u_short	iflags;
1376 		int	hcmd;
1377 		int	herror;
1378 		u_long	haddr;
1379 		u_long	hmisc;
1380 	} hil;
1381 
1382 	hil.hmisc = -1;
1383 	hil.hstate = is->hy_state;
1384 	hil.hflags = is->hy_flags;
1385 	hil.hcmd = cmd;
1386 #endif
1387 
1388 	switch(cmd) {
1389 
1390 	case SIOCSIFADDR:
1391 		if (ifa->ifa_addr.sa_family != AF_INET)
1392 			return(EINVAL);
1393 		if ((ifp->if_flags & IFF_RUNNING) == 0)
1394 			hyinit(ifp->if_unit);
1395 		hy_softc[ifp->if_unit].hy_addr = IA_SIN(ifa)->sin_addr;
1396 #ifdef HYLOG
1397 		hil.haddr = is->hy_addr.s_addr;
1398 #endif
1399 		break;
1400 
1401 	case HYSETROUTE:
1402 		if (!suser()) {
1403 			error = EPERM;
1404 			goto out;
1405 		}
1406 
1407 		if (sg->hyrsg_len != sizeof(struct hy_route)) {
1408 			error = EINVAL;
1409 			goto out;
1410 		}
1411 		if (copyin((caddr_t)(sg->hyrsg_ptr), (caddr_t)r, sg->hyrsg_len)) {
1412 			r->hyr_lasttime = 0;	/* disable further routing if trouble */
1413 			error = EFAULT;
1414 			goto out;
1415 		}
1416 		r->hyr_lasttime = time.tv_sec;
1417 #ifdef HYLOG
1418 		hil.hmisc = r->hyr_lasttime;
1419 #endif
1420 		break;
1421 
1422 	case HYGETROUTE:
1423 		if (sg->hyrsg_len < sizeof(struct hy_route)) {
1424 			error = EINVAL;
1425 			goto out;
1426 		}
1427 		if (copyout((caddr_t)r, (caddr_t) (sg->hyrsg_ptr), sizeof(struct hy_route))) {
1428 			error = EFAULT;
1429 			goto out;
1430 		}
1431 		break;
1432 
1433 #ifdef HYELOG
1434 	case HYGETELOG:
1435 		if (sgl->hylsg_len < sizeof(hy_elog)) {
1436 			error = EINVAL;
1437 			goto out;
1438 		}
1439 		if (copyout((caddr_t)hy_elog, sgl->hylsg_ptr, sizeof(hy_elog))) {
1440 			error = EFAULT;
1441 			goto out;
1442 		}
1443 		if (sgl->hylsg_cmd) {
1444 			if (!suser()) {
1445 				error = EPERM;
1446 				goto out;
1447 			}
1448 			bzero((caddr_t)hy_elog, sizeof(hy_elog));
1449 		}
1450 		break;
1451 #endif
1452 
1453 #ifdef HYLOG
1454 	case HYSETLOG:
1455 		if (!suser()) {
1456 			error = EPERM;
1457 			goto out;
1458 		}
1459 		hy_log.hyl_enable = HYL_DISABLED;
1460 		hylog(HYL_NOP, 0, (char *)0);		/* force log init */
1461 		hy_log.hyl_enable = sgl->hylsg_cmd & 0x0f;
1462 		hy_log.hyl_onerr = (sgl->hylsg_cmd >> 4) & 0x0f;
1463 		hy_log.hyl_filter = (sgl->hylsg_cmd >> 8) & 0xffffff;
1464 		hy_log.hyl_count = hy_log.hyl_icount = sgl->hylsg_len;
1465 		wakeup((caddr_t)&hy_log);	/* wakeup sleeping HYGETLOG */
1466 		break;
1467 
1468 	case HYGETLOG:
1469 		if (sgl->hylsg_len < sizeof(hy_log)) {
1470 			error = EINVAL;
1471 			goto out;
1472 		}
1473 		if (sgl->hylsg_cmd != 0) {
1474 			if (hy_log.hyl_wait) {
1475 				error = EBUSY;
1476 				goto out;
1477 			}
1478 			hy_log.hyl_wait = sgl->hylsg_cmd;
1479 			sleep((caddr_t)&hy_log, PZERO - 1);
1480 		}
1481 
1482 		if (copyout((caddr_t)&hy_log, sgl->hylsg_ptr, sizeof(hy_log))) {
1483 			error = EFAULT;
1484 			goto out;
1485 		}
1486 		break;
1487 #endif
1488 
1489 	default:
1490 		error = EINVAL;
1491 		break;
1492 	}
1493 out:
1494 #ifdef HYLOG
1495 	hil.herror = error;
1496 	hil.iflags = ifp->if_flags;
1497 	hil.haddr = is->hy_addr.s_addr;
1498 	hylog(HYL_IOCTL, sizeof(hil), (char *)&hil);
1499 #endif
1500 	splx(s);
1501 	return (error);
1502 }
1503 #endif
1504