Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
8011f5df | 2 | * @(#)if_hy.c 6.9 (Berkeley) %G% |
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 |
119 | int hyprobe(), hyattach(), hyinit(), hyioctl(); |
120 | int hyoutput(), hyreset(), hywatch(); | |
fd47138a SL |
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 */ | |
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 |
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]; | |
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 |
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 | |
fd47138a SL |
177 | */ |
178 | int 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 | */ | |
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 */ | |
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 | */ | |
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; | |
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 | */ | |
250 | hyreset(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 | */ | |
269 | hyinit(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 | |
293 | justreset: | |
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 | */ |
319 | hystart(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 | |
386 | int 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 | */ | |
399 | hyint(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 | |
414 | logit: | |
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 |
549 | int hyoutprint = 0; |
550 | ||
fd47138a SL |
551 | /* |
552 | * Encapsulate a packet of type family for the local net. | |
fd47138a SL |
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; | |
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 | 652 | headerexists: |
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 | 687 | notfound: |
bdddb192 | 688 | error = EHOSTUNREACH; |
fd47138a SL |
689 | drop: |
690 | m_freem(m); | |
38061563 SL |
691 | return (error); |
692 | } | |
fd47138a | 693 | |
bdddb192 MK |
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 | ||
bdddb192 MK |
749 | if (hym->hym_param == 0) |
750 | return(0); | |
751 | else | |
752 | return(1); | |
753 | } | |
754 | ||
fd47138a SL |
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: | |
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; | |
1083 | endintr: | |
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 |
1091 | struct sockproto hypproto = { PF_HYLINK }; |
1092 | struct sockaddr_in hypdst = { AF_HYLINK }; | |
1093 | struct 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 | 1101 | hyrecvdata(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 | */ |
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++; | |
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 | |
1195 | hycancel(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 | |
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 = ®fmt[2]; | |
1236 | while (--len >= 0) { | |
1237 | printL(fmt, *cp++ & 0xff); | |
1238 | fmt = ®fmt[2]; | |
1239 | if (--count <= 0) { | |
1240 | fmt = ®fmt[0]; | |
1241 | count = 16; | |
1242 | } | |
1243 | } | |
1244 | printL("\n"); | |
1245 | } | |
1246 | #endif | |
1247 | ||
1248 | hywatch(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 | |
1288 | hylog(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 |
1334 | out: |
1335 | splx(s); | |
1336 | } | |
1337 | #endif | |
1338 | ||
66923854 | 1339 | /*ARGSUSED*/ |
89ca046d SL |
1340 | hyioctl(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 |
1475 | out: |
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 |