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