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