BSD 4_3 release
[unix-history] / usr / src / sys / vaxif / if_hy.c
CommitLineData
da7c5cc6 1/*
95f51977 2 * @(#)if_hy.c 7.1 (Berkeley) 6/5/86
da7c5cc6 3 */
bdddb192
MK
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
fd47138a
SL
64
65#include "hy.h"
66#if NHY > 0
67
68/*
69 * Network Systems Copropration Hyperchanel interface
fd47138a 70 */
bdddb192
MK
71#include "machine/pte.h"
72
b05c393d
MK
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"
44eb2da3 84
fd47138a 85#include "../net/if.h"
38061563 86#include "../net/netisr.h"
fd47138a 87#include "../net/route.h"
ac840736 88
ac840736 89#ifdef INET
fd47138a
SL
90#include "../netinet/in.h"
91#include "../netinet/in_systm.h"
ac840736 92#include "../netinet/in_var.h"
fd47138a 93#include "../netinet/ip.h"
ac840736 94#endif
fd47138a 95
38061563 96#include "../vax/cpu.h"
fd47138a
SL
97#include "../vax/mtpr.h"
98#include "../vaxuba/ubareg.h"
99#include "../vaxuba/ubavar.h"
38061563 100
bdddb192
MK
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
b05c393d
MK
115#include "if_hy.h"
116#include "if_hyreg.h"
117#include "if_uba.h"
fd47138a 118
89ca046d
SL
119int hyprobe(), hyattach(), hyinit(), hyioctl();
120int hyoutput(), hyreset(), hywatch();
fd47138a
SL
121struct uba_device *hyinfo[NHY];
122u_short hystd[] = { 0772410, 0 };
123struct 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 */
138struct hy_softc {
139 struct ifnet hy_if; /* network-visible interface */
140 struct ifuba hy_ifuba; /* UNIBUS resources */
38061563
SL
141 short hy_flags; /* flags */
142 short hy_state; /* driver state */
b05c393d
MK
143 u_short hy_host; /* local host number */
144 struct in_addr hy_addr; /* internet address */
fd47138a
SL
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 */
38061563
SL
153 struct hy_stat hy_stat; /* statistics */
154 struct hy_status hy_status; /* status */
fd47138a
SL
155} hy_softc[NHY];
156
157#ifdef HYELOG
bdddb192
MK
158u_long hy_elog[HYE_SIZE];
159#endif
160
161#ifdef HYLOG
162struct hy_log hy_log;
163#endif
164
165#ifdef HYROUTE
166struct hy_route hy_route[NHY];
fd47138a
SL
167#endif
168
fd47138a 169#ifdef DEBUG
bdddb192
MK
170#define printL printf
171#define printD if (hy_debug_flag) printf
fd47138a
SL
172int 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
fd47138a
SL
177 */
178int hy_nodebug = 0x0;
fd47138a
SL
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 */
189hyprobe(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 */
bdddb192 215 return(sizeof(struct hydevice));
38061563 216}
fd47138a
SL
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 */
223hyattach(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;
fd47138a 232 is->hy_state = STARTUP; /* don't allow state transitions yet */
fd47138a 233 ifp->if_init = hyinit;
89ca046d 234 ifp->if_ioctl = hyioctl;
fd47138a 235 ifp->if_output = hyoutput;
38061563 236 ifp->if_reset = hyreset;
fd47138a
SL
237 ifp->if_watchdog = hywatch;
238 ifp->if_timer = SCANINTERVAL;
239 is->hy_ifuba.ifu_flags = UBA_CANTWAIT;
38061563 240#ifdef notdef
fd47138a
SL
241 is->hy_ifuba.ifu_flags |= UBA_NEEDBDP;
242#endif
243 if_attach(ifp);
38061563 244}
fd47138a
SL
245
246/*
247 * Reset of interface after UNIBUS reset.
248 * If interface is on specified uba, reset its state.
249 */
250hyreset(unit, uban)
251 int unit, uban;
252{
bdddb192
MK
253 register struct uba_device *ui;
254 register struct hy_softc *is;
fd47138a 255
bdddb192 256 if (unit >= NHY || (ui = hyinfo[unit]) == 0 || ui->ui_alive == 0 ||
38061563 257 ui->ui_ubanum != uban)
fd47138a 258 return;
fd47138a 259 printf(" hy%d", unit);
bdddb192
MK
260 is = &hy_softc[unit]; /* force unibus resource allocation */
261 is->hy_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
fd47138a 262 hyinit(unit);
38061563 263}
fd47138a
SL
264
265/*
266 * Initialization of interface; clear recorded pending
267 * operations, and reinitialize UNIBUS usage.
268 */
269hyinit(unit)
270 int unit;
271{
272 register struct hy_softc *is = &hy_softc[unit];
273 register struct uba_device *ui = hyinfo[unit];
bdddb192 274 register struct mbuf *m;
fd47138a
SL
275 int s;
276
b05c393d 277 if (is->hy_if.if_addrlist == 0) /* address still unknown */
abcd48c6 278 return;
bdddb192
MK
279 if (is->hy_if.if_flags & IFF_RUNNING) /* just reset the device */
280 goto justreset;
fd47138a 281 if (if_ubainit(&is->hy_ifuba, ui->ui_ubanum,
bdddb192 282 sizeof (struct hym_hdr), (int)btoc(HYMTU)) == 0) {
fd47138a 283#ifdef DEBUG
38061563
SL
284 if (hy_nodebug & 4)
285 hy_debug_flag = 1;
fd47138a
SL
286#endif
287 printf("hy%d: can't initialize\n", unit);
288 is->hy_if.if_flags &= ~IFF_UP;
289 return;
290 }
44eb2da3 291 is->hy_if.if_flags |= IFF_RUNNING;
bdddb192
MK
292
293justreset:
fd47138a 294 /*
bdddb192
MK
295 * remove any left over outgoing messages, reset the hardware and
296 * start the state machine
fd47138a
SL
297 */
298 s = splimp();
bdddb192
MK
299#ifdef HYLOG
300 hylog(HYL_RESET, 0, (char *)0);
301#endif
fd47138a
SL
302 is->hy_state = IDLE;
303 is->hy_flags = RQ_STATUS | RQ_STATISTICS | RQ_MARKUP;
304 is->hy_retry = 0;
bdddb192
MK
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 */
fd47138a 313 splx(s);
38061563 314}
fd47138a
SL
315
316/*
38061563 317 * Issue a command to the adapter
fd47138a
SL
318 */
319hystart(ui, cmd, count, ubaddr)
320 struct uba_device *ui;
38061563 321 int cmd, count, ubaddr;
fd47138a
SL
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
38061563
SL
327 printD("hy%d: hystart cmd = 0x%x count=%d ubaddr=0x%x\n",
328 ui->ui_unit, cmd, count, ubaddr);
fd47138a 329 printD("hy%d: - csr = 0x%b, bar = 0x%x, wcr = 0x%x\n",
38061563
SL
330 ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
331 addr->hyd_wcr);
fd47138a 332#endif
38061563
SL
333 if (((is->hy_flags & RQ_REISSUE) == 0) &&
334 (cmd != HYF_STATUS) && (cmd != HYF_END_OP) && (cmd != HYF_RSTATS)) {
fd47138a
SL
335 is->hy_savedstate = is->hy_state;
336 is->hy_savedcmd = cmd;
337 is->hy_savedcount = count;
338 is->hy_savedaddr = ubaddr;
339 }
bdddb192
MK
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
fd47138a 356 addr->hyd_bar = ubaddr & 0xffff;
38061563 357 addr->hyd_wcr = is->hy_lastwcr = -((count+1) >> 1);
fd47138a
SL
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",
38061563
SL
366 ui->ui_unit, addr->hyd_csr, HY_CSR_BITS, addr->hyd_bar,
367 addr->hyd_wcr);
fd47138a
SL
368#endif
369#ifdef HYLOG
370 {
371 struct {
38061563
SL
372 u_char hcmd;
373 u_char hstate;
374 short hcount;
fd47138a
SL
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;
38061563 384}
fd47138a
SL
385
386int hyint_active = 0; /* set during hy interrupt */
fd47138a 387/*
38061563 388 * Hyperchannel interface interrupt.
fd47138a
SL
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 */
399hyint(unit)
400 int unit;
401{
402 register struct hy_softc *is = &hy_softc[unit];
403 register struct uba_device *ui = hyinfo[unit];
38061563 404 register struct hydevice *addr = (struct hydevice *)ui->ui_addr;
fd47138a 405
38061563 406 if (hyint_active)
fd47138a 407 panic("RECURSIVE HYPERCHANNEL INTERRUPT");
fd47138a 408 hyint_active++;
fd47138a
SL
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
414logit:
415 {
416 struct {
38061563
SL
417 u_char hstate;
418 u_char hflags;
419 short hcsr;
420 short hwcr;
fd47138a
SL
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
38061563 429 if (HYS_ERROR(addr) && ((addr->hyd_csr & S_ATTN) == 0)) {
fd47138a 430 /*
38061563 431 * Error bit set, some sort of error in the interface.
fd47138a 432 *
38061563
SL
433 * The adapter sets attn on command completion so that's not
434 * a real error even though the interface considers it one.
fd47138a
SL
435 */
436#ifdef DEBUG
38061563
SL
437 if (hy_nodebug & 4)
438 hy_debug_flag = 1;
fd47138a 439#endif
38061563
SL
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) {
fd47138a
SL
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
38061563 452 } else if (addr->hyd_csr & S_POWEROFF) {
bdddb192 453 printf("hy%d: \"Soft\" Adapter Power Failure (hyint)\n", unit);
fd47138a
SL
454 addr->hyd_csr |= S_POWEROFF;
455 DELAY(100);
38061563 456 if (addr->hyd_csr & S_POWEROFF) {
bdddb192 457 printf( "hy%d: \"Hard\" Adapter Power Failure, Network Shutdown (hyint)\n", unit);
fd47138a 458 if_down(&is->hy_if);
bdddb192 459 is->hy_if.if_flags &= ~IFF_UP;
fd47138a 460 is->hy_state = STARTUP;
bdddb192
MK
461 } else {
462 printf("hy%d: Adapter Power Restored (hyint)\n", unit);
fd47138a
SL
463 }
464#endif
465 } else {
466 printf("hy%d: BAR overflow\n", unit);
467 hycancel(ui);
468 }
38061563 469 } else if (HYS_NORMAL(addr)) {
fd47138a 470 /*
38061563 471 * Normal interrupt, bump state machine unless in state
fd47138a 472 * waiting and no data present (assumed to be word count
38061563 473 * zero interrupt or other hardware botch).
fd47138a 474 */
38061563 475 if (is->hy_state != WAITING || HYS_RECVDATA(addr))
fd47138a 476 hyact(ui);
38061563 477 } else if (HYS_ABNORMAL(addr)) {
fd47138a 478 /*
38061563 479 * Abnormal termination.
fd47138a
SL
480 * bump error counts, retry the last function
481 * 'MAXRETRY' times before kicking the bucket.
482 *
38061563
SL
483 * Don't reissue the cmd if in certain states, abnormal
484 * on a reissued cmd or max retry exceeded.
fd47138a
SL
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
38061563
SL
493 if (hy_nodebug & 4)
494 hy_debug_flag = 1;
fd47138a
SL
495 printD("hy%d: abnormal interrupt, driver state \"%s\" (%d)\n",
496 unit, hy_state_names[is->hy_state], is->hy_state);
bdddb192
MK
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);
38061563
SL
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);
fd47138a
SL
502#endif
503#ifdef PI13
504 addr->hyd_csr &= ~S_C; /* clear the damned PI-13 */
505#endif
38061563 506 if (is->hy_state == XMITSENT || is->hy_state == XMITDATASENT)
fd47138a 507 is->hy_if.if_oerrors++;
bdddb192 508 else if (is->hy_state == RECVSENT || is->hy_state == RECVDATASENT)
fd47138a 509 is->hy_if.if_ierrors++;
bdddb192
MK
510 else
511 is->hy_if.if_collisions++; /* other errors */
fd47138a
SL
512 if (is->hy_state == XMITDATASENT ||
513 is->hy_state == RECVSENT ||
514 is->hy_state == RECVDATASENT ||
38061563 515 (is->hy_flags & RQ_REISSUE) != 0 || is->hy_retry > MAXRETRY)
fd47138a 516 hycancel(ui);
38061563 517 else {
fd47138a 518#ifdef DEBUG
38061563
SL
519 if (hy_nodebug & 2)
520 hy_debug_flag = 1;
fd47138a
SL
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 }
fd47138a
SL
542#ifdef DEBUG
543 printD("hy%d: hyint exit\n\n", unit);
544#endif
545 hyint_active = 0;
546
38061563 547}
fd47138a 548
bdddb192
MK
549int hyoutprint = 0;
550
fd47138a
SL
551/*
552 * Encapsulate a packet of type family for the local net.
fd47138a
SL
553 */
554hyoutput(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;
bdddb192 561 register char *mp;
bdddb192 562 int dlen; /* packet size, incl hardware header, but not sw header */
fd47138a
SL
563 int error = 0;
564 int s;
565
bdddb192
MK
566 /*
567 * Calculate packet length for later deciding whether it will fit
568 * in a message proper or we also need associated data.
569 */
fd47138a
SL
570 dlen = 0;
571 for (m = m0; m; m = m->m_next)
572 dlen += m->m_len;
573 m = m0;
bdddb192
MK
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
fd47138a
SL
608 switch(dst->sa_family) {
609
610#ifdef INET
611 case AF_INET: {
bdddb192 612 int i;
fd47138a 613
fd47138a 614 /*
bdddb192
MK
615 * if loopback address, swizzle ip header so when
616 * it comes back it looks like it was addressed to us
fd47138a 617 */
bdddb192
MK
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) {
fd47138a
SL
622 struct in_addr temp;
623
bdddb192
MK
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;
fd47138a
SL
627 }
628 /*
629 * If entire packet won't fit in message proper, just
630 * send hyperchannel hardware header and ip header in
bdddb192 631 * message proper.
fd47138a
SL
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 */
bdddb192
MK
637 if (dlen > MPSIZE)
638 hym->hym_mplen = sizeof(struct hy_hdr) + (((struct ip *)mp)->ip_hl << 2);
639 hym->hym_type = HYLINK_IP;
fd47138a
SL
640 break;
641 }
642#endif
643
644 default:
38061563
SL
645 printf("hy%d: can't handle af%d\n", ifp->if_unit,
646 dst->sa_family);
fd47138a
SL
647 error = EAFNOSUPPORT;
648 goto drop;
649 }
650
fd47138a 651
bdddb192 652headerexists:
fd47138a 653
bdddb192
MK
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
b05c393d 660 hym->hym_from = htons(hy_softc[ifp->if_unit].hy_host);
bdddb192
MK
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);
fd47138a 669#ifdef DEBUG
bdddb192
MK
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);
fd47138a 674#endif
fd47138a
SL
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);
38061563 686 return (0);
fd47138a 687notfound:
bdddb192 688 error = EHOSTUNREACH;
fd47138a
SL
689drop:
690 m_freem(m);
38061563
SL
691 return (error);
692}
fd47138a 693
bdddb192
MK
694int
695hyroute(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
bdddb192
MK
749 if (hym->hym_param == 0)
750 return(0);
751 else
752 return(1);
753}
754
fd47138a
SL
755hyact(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
761actloop:
fd47138a 762#ifdef DEBUG
38061563
SL
763 printD("hy%d: hyact, enter state \"%s\"\n", ui->ui_unit,
764 hy_state_names[is->hy_state]);
fd47138a 765#endif
fd47138a
SL
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;
38061563 777 hystart(ui, HYF_STATUS, sizeof (is->hy_status),
44eb2da3 778 is->hy_ifuba.ifu_r.ifrw_info);
fd47138a
SL
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;
38061563 786 hystart(ui, HYF_RSTATS, sizeof (is->hy_stat),
44eb2da3 787 is->hy_ifuba.ifu_r.ifrw_info);
38061563 788 } else if (HYS_RECVDATA(addr)) {
fd47138a
SL
789 is->hy_state = RECVSENT;
790 is->hy_retry = 0;
bdddb192 791 hystart(ui, HYF_INPUTMSG, MPSIZE, is->hy_ifuba.ifu_r.ifrw_info + HYM_SWLEN);
fd47138a
SL
792 } else if (rq & RQ_REISSUE) {
793 is->hy_flags &= ~RQ_REISSUE;
794 is->hy_state = is->hy_savedstate;
795#ifdef DEBUG
38061563
SL
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);
fd47138a 800#endif
38061563 801 hystart(ui, is->hy_savedcmd, is->hy_savedcount,
44eb2da3 802 is->hy_savedaddr);
fd47138a
SL
803 } else {
804 register struct mbuf *m;
805
806 IF_DEQUEUE(&is->hy_if.if_snd, m);
38061563 807 if (m != NULL) {
fd47138a
SL
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
38061563 816 hylog(HYL_XMIT, sizeof(struct hym_hdr),
44eb2da3 817 (char *)hym);
fd47138a
SL
818#endif
819 mplen = hym->hym_mplen;
bdddb192 820 if (hym->hym_to_adapter == hym->hym_from_adapter)
38061563
SL
821 cmd = HYF_XMITLOCMSG;
822 else
823 cmd = HYF_XMITMSG;
fd47138a
SL
824#ifdef DEBUG
825 printD("hy%d: hym_hdr = ", ui->ui_unit);
38061563
SL
826 if (hy_debug_flag)
827 hyprintdata((char *)hym,
44eb2da3 828 sizeof (struct hym_hdr));
fd47138a 829#endif
bdddb192 830 is->hy_olen = if_wubaput(&is->hy_ifuba, m) - HYM_SWLEN;
fd47138a 831 if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
38061563
SL
832 UBAPURGE(is->hy_ifuba.ifu_uba,
833 is->hy_ifuba.ifu_w.ifrw_bdp);
fd47138a 834#ifdef DEBUG
38061563
SL
835 printD(
836 "hy%d: sending packet (mplen = %d, hy_olen = %d) data = ",
fd47138a 837 ui->ui_unit, mplen, is->hy_olen);
38061563
SL
838 if (hy_debug_flag)
839 hyprintdata(
44eb2da3 840 is->hy_ifuba.ifu_w.ifrw_addr,
bdddb192 841 is->hy_olen + HYM_SWLEN);
fd47138a 842#endif
bdddb192
MK
843 if (mplen == 0) {
844 is->hy_flags &= ~RQ_XASSOC;
845 mplen = is->hy_olen;
846 } else {
fd47138a 847 is->hy_flags |= RQ_XASSOC;
bdddb192
MK
848 }
849 hystart(ui, cmd, mplen, is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN);
fd47138a
SL
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 /*
38061563 855 * Port number is taken from status data
fd47138a 856 */
38061563 857 hystart(ui,
66923854
SL
858 (int)(HYF_MARKP0|(PORTNUM(&is->hy_status)<<2)),
859 0, 0);
fd47138a
SL
860 } else if (rq & RQ_MARKUP) {
861 register struct ifnet *ifp = &is->hy_if;
fd47138a 862
38061563 863 is->hy_flags &= ~RQ_MARKUP;
fd47138a
SL
864 is->hy_retry = 0;
865 /*
abcd48c6 866 * Fill in the host number
38061563 867 * from the status buffer
fd47138a 868 */
38061563
SL
869 printf(
870 "hy%d: unit number 0x%x port %d type %x microcode level 0x%x\n",
fd47138a
SL
871 ui->ui_unit,
872 is->hy_stat.hyc_uaddr,
873 PORTNUM(&is->hy_status),
38061563
SL
874 (is->hy_stat.hyc_atype[0]<<8) |
875 is->hy_stat.hyc_atype[1],
fd47138a
SL
876 is->hy_stat.hyc_atype[2]);
877
b05c393d 878 is->hy_host =
38061563
SL
879 (is->hy_stat.hyc_uaddr << 8) |
880 PORTNUM(&is->hy_status);
fd47138a 881 ifp->if_flags |= IFF_UP;
fd47138a
SL
882#ifdef HYLOG
883 hylog(HYL_UP, 0, (char *)0);
884#endif
fd47138a
SL
885 } else {
886 is->hy_state = WAITING;
887 is->hy_retry = 0;
888 hystart(ui, HYF_WAITFORMSG, 0, 0);
889 }
890 }
38061563 891 break;
fd47138a 892 }
fd47138a
SL
893
894 case STATSENT:
66923854 895 bcopy(is->hy_ifuba.ifu_r.ifrw_addr, (caddr_t)&is->hy_status,
38061563 896 sizeof (struct hy_status));
fd47138a 897#ifdef DEBUG
38061563
SL
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);
fd47138a
SL
907#endif
908 is->hy_state = IDLE;
909#ifdef HYLOG
38061563
SL
910 hylog(HYL_STATUS, sizeof (struct hy_status),
911 (char *)&is->hy_status);
fd47138a
SL
912#endif
913#ifdef HYELOG
914 {
915 register int i;
916
917 i = is->hy_status.hys_error;
bdddb192 918 if (i > HYE_MAX)
fd47138a
SL
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: {
38061563
SL
934 register struct hy_stat *p =
935 (struct hy_stat *)is->hy_ifuba.ifu_r.ifrw_addr;
fd47138a 936
bdddb192 937 bcopy((caddr_t)p, (caddr_t)&is->hy_stat, sizeof(struct hy_stat));
fd47138a 938#ifdef DEBUG
bdddb192
MK
939
940 printD("hy%d: statistics - df0 %d df1 %d df2 %d df3 %d\n",
fd47138a 941 ui->ui_unit,
bdddb192
MK
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],
fd47138a
SL
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
38061563
SL
959 hylog(HYL_STATISTICS, sizeof (struct hy_stat),
960 (char *)&is->hy_stat);
fd47138a
SL
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: {
bdddb192 974 register struct hym_hdr *hym;
38061563
SL
975 register unsigned len;
976
977 if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
978 UBAPURGE(is->hy_ifuba.ifu_uba,
44eb2da3 979 is->hy_ifuba.ifu_r.ifrw_bdp);
bdddb192 980 hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
38061563
SL
981 len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
982 if (len > MPSIZE) {
983 printf("hy%d: RECVD MP > MPSIZE (%d)\n",
44eb2da3 984 ui->ui_unit, len);
bdddb192 985 is->hy_state = IDLE;
fd47138a 986#ifdef DEBUG
38061563
SL
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);
fd47138a 991#endif
38061563 992 }
bdddb192 993 hym->hym_mplen = len;
fd47138a 994#ifdef DEBUG
38061563
SL
995 printD("hy%d: recvd mp, len = %d, data = ", ui->ui_unit, len);
996 if (hy_debug_flag)
bdddb192 997 hyprintdata((char *)hym, len + HYM_SWLEN);
fd47138a 998#endif
bdddb192 999 if (hym->hym_ctl & H_ASSOC) {
38061563 1000 is->hy_state = RECVDATASENT;
38061563
SL
1001 is->hy_retry = 0;
1002 hystart(ui, HYF_INPUTDATA,
bdddb192
MK
1003 (int)(HYMTU + sizeof (struct hy_hdr) - len),
1004 (int)(HYM_SWLEN + is->hy_ifuba.ifu_r.ifrw_info + len));
38061563 1005 } else {
bdddb192 1006 hyrecvdata(ui, hym, (int)len + HYM_SWLEN);
38061563 1007 is->hy_state = IDLE;
fd47138a 1008 }
38061563
SL
1009 break;
1010 }
fd47138a
SL
1011
1012 case RECVDATASENT: {
bdddb192 1013 register struct hym_hdr *hym;
38061563
SL
1014 register unsigned len;
1015
1016 if (is->hy_ifuba.ifu_flags & UBA_NEEDBDP)
1017 UBAPURGE(is->hy_ifuba.ifu_uba,
44eb2da3 1018 is->hy_ifuba.ifu_r.ifrw_bdp);
bdddb192 1019 hym = (struct hym_hdr *) (is->hy_ifuba.ifu_r.ifrw_addr);
38061563 1020 len = (0xffff & (addr->hyd_wcr - is->hy_lastwcr)) << 1;
fd47138a 1021#ifdef DEBUG
38061563
SL
1022 printD("hy%d: recvd assoc data, len = %d, data = ",
1023 ui->ui_unit, len);
1024 if (hy_debug_flag)
bdddb192 1025 hyprintdata((char *)hym + hym->hym_mplen, len);
fd47138a 1026#endif
bdddb192 1027 hyrecvdata(ui, hym, (int)(len + hym->hym_mplen + HYM_SWLEN));
38061563
SL
1028 is->hy_state = IDLE;
1029 break;
1030 }
fd47138a
SL
1031
1032 case XMITSENT:
38061563 1033 if (is->hy_flags & RQ_XASSOC) {
efb82358 1034 register int len;
fd47138a 1035
38061563
SL
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);
fd47138a 1044#ifdef DEBUG
38061563 1045 hy_debug_flag = 1;
fd47138a 1046#endif
fd47138a 1047 }
38061563 1048 hystart(ui, HYF_XMITLSTDATA, is->hy_olen - len,
bdddb192 1049 is->hy_ifuba.ifu_w.ifrw_info + HYM_SWLEN + len);
38061563
SL
1050 break;
1051 }
1052 /* fall through to ... */
fd47138a
SL
1053
1054 case XMITDATASENT:
38061563
SL
1055 hyxmitdata(ui);
1056 is->hy_state = IDLE;
1057 break;
fd47138a
SL
1058
1059 case WAITING: /* wait for message complete or output requested */
38061563 1060 if (HYS_RECVDATA(addr))
fd47138a
SL
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;
bdddb192 1071 if_down(&is->hy_if);
fd47138a
SL
1072 is->hy_if.if_flags &= ~IFF_UP;
1073 goto endintr;
1074
1075 default:
38061563
SL
1076 printf("hy%d: DRIVER BUG - INVALID STATE %d\n",
1077 ui->ui_unit, is->hy_state);
fd47138a
SL
1078 panic("HYPERCHANNEL IN INVALID STATE");
1079 /*NOTREACHED*/
38061563 1080 }
fd47138a
SL
1081 if (is->hy_state == IDLE)
1082 goto actloop;
1083endintr:
44eb2da3 1084 ;
fd47138a 1085#ifdef DEBUG
38061563
SL
1086 printD("hy%d: hyact, exit at \"%s\"\n", ui->ui_unit,
1087 hy_state_names[is->hy_state]);
fd47138a 1088#endif
38061563 1089}
fd47138a 1090
bdddb192
MK
1091struct sockproto hypproto = { PF_HYLINK };
1092struct sockaddr_in hypdst = { AF_HYLINK };
1093struct sockaddr_in hypsrc = { AF_HYLINK };
1094
fd47138a 1095/*
44eb2da3 1096 * Called from device interrupt when receiving data.
fd47138a
SL
1097 * Examine packet to determine type. Decapsulate packet
1098 * based on type and pass to type specific higher-level
1099 * input routine.
1100 */
bdddb192 1101hyrecvdata(ui, hym, len)
fd47138a 1102 struct uba_device *ui;
bdddb192 1103 register struct hym_hdr *hym;
fd47138a
SL
1104 int len;
1105{
1106 register struct hy_softc *is = &hy_softc[ui->ui_unit];
fd47138a
SL
1107 struct mbuf *m;
1108 register struct ifqueue *inq;
1109
1110 is->hy_if.if_ipackets++;
1111#ifdef DEBUG
bdddb192 1112 printD("hy%d: recieved packet, len = %d\n", ui->ui_unit, len);
fd47138a
SL
1113#endif
1114#ifdef HYLOG
1115 {
1116 struct {
1117 short hlen;
bdddb192 1118 struct hym_hdr hhdr;
fd47138a
SL
1119 } hh;
1120 hh.hlen = len;
bdddb192 1121 hh.hhdr = *hym;
fd47138a
SL
1122 hylog(HYL_RECV, sizeof(hh), (char *)&hh);
1123 }
1124#endif
fd47138a
SL
1125 if (len > HYMTU + MPSIZE || len == 0)
1126 return; /* sanity */
fd47138a
SL
1127 /*
1128 * Pull packet off interface.
1129 */
ac840736 1130 m = if_rubaget(&is->hy_ifuba, len, 0, &is->hy_if);
38061563 1131 if (m == NULL)
fd47138a 1132 return;
bdddb192
MK
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) {
fd47138a
SL
1143
1144#ifdef INET
1145 case HYLINK_IP:
fd47138a
SL
1146 schednetisr(NETISR_IP);
1147 inq = &ipintrq;
1148 break;
1149#endif
1150 default:
bdddb192
MK
1151 rawlinkin:
1152 {
1153 struct mbuf *m0;
1154
1155 MGET(m0, M_DONTWAIT, MT_DATA);
ac840736 1156 if (m0 == 0) {
bdddb192
MK
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;
b05c393d
MK
1166 hypdst.sin_addr = is->hy_addr;
1167 hypsrc.sin_addr = is->hy_addr;
bdddb192
MK
1168 raw_input(m, &hypproto, (struct sockaddr *)&hypsrc,
1169 (struct sockaddr *)&hypdst);
1170 return;
1171 }
fd47138a 1172 }
fd47138a
SL
1173 if (IF_QFULL(inq)) {
1174 IF_DROP(inq);
1175 m_freem(m);
1176 } else
1177 IF_ENQUEUE(inq, m);
38061563 1178}
fd47138a
SL
1179
1180/*
38061563 1181 * Transmit done, release resources, bump counters.
fd47138a
SL
1182 */
1183hyxmitdata(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++;
38061563 1189 if (is->hy_ifuba.ifu_xtofree) {
fd47138a
SL
1190 m_freem(is->hy_ifuba.ifu_xtofree);
1191 is->hy_ifuba.ifu_xtofree = 0;
1192 }
38061563 1193}
fd47138a
SL
1194
1195hycancel(ui)
1196 register struct uba_device *ui;
1197{
1198 register struct hy_softc *is = &hy_softc[ui->ui_unit];
1199
38061563 1200 if (is->hy_ifuba.ifu_xtofree) {
fd47138a
SL
1201 m_freem(is->hy_ifuba.ifu_xtofree);
1202 is->hy_ifuba.ifu_xtofree = 0;
1203 }
bdddb192
MK
1204#ifdef HYLOG
1205 hylog(HYL_CANCEL, 0, (char *)0);
1206#endif
fd47138a 1207#ifdef DEBUG
38061563
SL
1208 if (hy_nodebug & 1)
1209 hy_debug_flag = 1;
fd47138a 1210#endif
fd47138a
SL
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);
bdddb192
MK
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);
38061563
SL
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);
fd47138a
SL
1220#endif
1221 is->hy_state = IDLE;
1222 is->hy_flags |= (RQ_ENDOP | RQ_STATUS);
1223 hyact(ui);
38061563 1224}
fd47138a
SL
1225
1226#ifdef DEBUG
1227hyprintdata(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
1248hywatch(unit)
44eb2da3 1249 int unit;
fd47138a
SL
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();
fd47138a
SL
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) {
bdddb192 1262 printf("hy%d: Adapter Power Restored (hywatch)\n", unit);
fd47138a 1263 is->hy_state = IDLE;
38061563
SL
1264 is->hy_flags |=
1265 (RQ_MARKUP | RQ_STATISTICS | RQ_ENDOP | RQ_STATUS);
fd47138a
SL
1266 hyact(ui);
1267 }
1268 }
1269#endif
bdddb192
MK
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 }
fd47138a 1283 splx(s);
bdddb192 1284 is->hy_if.if_timer = SCANINTERVAL;
fd47138a
SL
1285}
1286
1287#ifdef HYLOG
1288hylog(code, len, ptr)
44eb2da3 1289 int code, len;
fd47138a
SL
1290 char *ptr;
1291{
1292 register unsigned char *p;
1293 int s;
1294
1295 s = splimp();
fd47138a
SL
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;
bdddb192
MK
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 */
fd47138a 1305 }
bdddb192 1306 if (hy_log.hyl_enable == HYL_DISABLED || ((1 << code) & hy_log.hyl_filter) == 0)
38061563 1307 goto out;
fd47138a 1308 p = hy_log.hyl_ptr;
bdddb192 1309 if (p + len + 3 >= hy_log.hyl_eptr) {
66923854 1310 bzero((caddr_t)p, (unsigned)(hy_log.hyl_eptr - p));
fd47138a 1311 p = &hy_log.hyl_buf[0];
bdddb192
MK
1312 if (hy_log.hyl_enable != HYL_CONTINUOUS) {
1313 hy_log.hyl_enable = HYL_DISABLED;
fd47138a
SL
1314 goto out;
1315 }
1316 }
fd47138a
SL
1317 *p++ = code;
1318 *p++ = len;
44eb2da3 1319 bcopy((caddr_t)ptr, (caddr_t)p, (unsigned)len);
bdddb192
MK
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 }
a7683b43 1325 p += len;
bdddb192 1326 if (hy_log.hyl_wait != 0) { /* wakeup HYGETLOG if wanted */
a7683b43 1327 if (hy_log.hyl_wait <= p - hy_log.hyl_ptr) {
bdddb192
MK
1328 wakeup((caddr_t)&hy_log);
1329 hy_log.hyl_wait = 0;
a7683b43
MK
1330 } else
1331 hy_log.hyl_wait -= p - hy_log.hyl_ptr;
bdddb192 1332 }
a7683b43 1333 hy_log.hyl_ptr = p;
fd47138a
SL
1334out:
1335 splx(s);
1336}
1337#endif
1338
66923854 1339/*ARGSUSED*/
89ca046d
SL
1340hyioctl(ifp, cmd, data)
1341 register struct ifnet *ifp;
38061563
SL
1342 int cmd;
1343 caddr_t data;
fd47138a 1344{
b05c393d 1345 struct ifaddr *ifa = (struct ifaddr *) data;
bdddb192
MK
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];
38061563 1351 int s = splimp(), error = 0;
bdddb192
MK
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
fd47138a 1369
fd47138a
SL
1370 switch(cmd) {
1371
abcd48c6 1372 case SIOCSIFADDR:
ac840736 1373 if (ifa->ifa_addr.sa_family != AF_INET)
bdddb192 1374 return(EINVAL);
b05c393d
MK
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;
bdddb192 1378#ifdef HYLOG
b05c393d 1379 hil.haddr = is->hy_addr.s_addr;
bdddb192 1380#endif
abcd48c6
SL
1381 break;
1382
fd47138a 1383 case HYSETROUTE:
38061563
SL
1384 if (!suser()) {
1385 error = EPERM;
bdddb192
MK
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;
fd47138a 1397 }
bdddb192
MK
1398 r->hyr_lasttime = time.tv_sec;
1399#ifdef HYLOG
1400 hil.hmisc = r->hyr_lasttime;
1401#endif
fd47138a
SL
1402 break;
1403
1404 case HYGETROUTE:
bdddb192
MK
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 }
fd47138a
SL
1413 break;
1414
bdddb192
MK
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;
8011f5df 1461 sleep((caddr_t)&hy_log, PZERO - 1);
bdddb192
MK
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
fd47138a 1471 default:
89ca046d 1472 error = EINVAL;
fd47138a
SL
1473 break;
1474 }
bdddb192
MK
1475out:
1476#ifdef HYLOG
1477 hil.herror = error;
1478 hil.iflags = ifp->if_flags;
b05c393d 1479 hil.haddr = is->hy_addr.s_addr;
bdddb192
MK
1480 hylog(HYL_IOCTL, sizeof(hil), (char *)&hil);
1481#endif
fd47138a 1482 splx(s);
38061563 1483 return (error);
fd47138a 1484}
38061563 1485#endif