Commit | Line | Data |
---|---|---|
49ff8a6a KS |
1 | /* |
2 | * Copyright (c) 1986 Regents of the University of California. | |
5f9369d6 | 3 | * All rights reserved. |
49ff8a6a | 4 | * |
5f9369d6 KB |
5 | * This code is derived from software contributed to Berkeley by |
6 | * Micom-Interlan Inc. | |
7 | * | |
8 | * Redistribution and use in source and binary forms are permitted | |
9 | * provided that the above copyright notice and this paragraph are | |
10 | * duplicated in all such forms and that any documentation, | |
11 | * advertising materials, and other materials related to such | |
12 | * distribution and use acknowledge that the software was developed | |
13 | * by the University of California, Berkeley. The name of the | |
14 | * University may not be used to endorse or promote products derived | |
15 | * from this software without specific prior written permission. | |
16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
17 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
18 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
19 | * | |
c18e27ed | 20 | * @(#)if_ix.c 7.6 (Berkeley) %G% |
49ff8a6a KS |
21 | */ |
22 | ||
23 | #include "np.h" | |
24 | #if NNP > 0 | |
25 | ||
26 | /* | |
27 | * Interlan NP100 Ethernet Communications Controller interface | |
28 | */ | |
c18e27ed | 29 | #include "machine/pte.h" |
49ff8a6a KS |
30 | |
31 | #include "param.h" | |
32 | #include "systm.h" | |
33 | #include "mbuf.h" | |
34 | #include "buf.h" | |
35 | #include "protosw.h" | |
36 | #include "socket.h" | |
37 | #include "vmmac.h" | |
38 | #include "ioctl.h" | |
39 | #include "errno.h" | |
40 | ||
41 | #include "../net/if.h" | |
42 | #include "../net/netisr.h" | |
43 | #include "../net/route.h" | |
44 | ||
45 | #ifdef INET | |
46 | #include "../netinet/in.h" | |
47 | #include "../netinet/in_systm.h" | |
48 | #include "../netinet/in_var.h" | |
49 | #include "../netinet/ip.h" | |
50 | #include "../netinet/if_ether.h" | |
51 | #endif | |
52 | ||
53 | #ifdef NS | |
54 | #include "../netns/ns.h" | |
55 | #include "../netns/ns_if.h" | |
56 | #endif | |
57 | ||
58 | #include "../vax/cpu.h" | |
59 | #include "../vax/mtpr.h" | |
60 | #include "../vaxif/if_uba.h" | |
61 | #include "../vaxuba/ubareg.h" | |
62 | #include "../vaxuba/ubavar.h" | |
63 | #include "../vaxuba/npreg.h" | |
64 | #include "../vaxif/if_ix.h" | |
65 | ||
66 | int ixattach(), ixrint(), ixcint(); | |
67 | #define ILUNIT(x) minor(x) | |
4f02060d | 68 | int ixinit(), ixioctl(), ixreset(), ixwatch(), ixstart(); |
49ff8a6a KS |
69 | int (*IxAttach)() = ixattach; |
70 | int (*IxReset)() = ixreset; | |
71 | ||
72 | /* | |
73 | * Ethernet software status per interface. | |
74 | * | |
75 | * Each interface is referenced by a network interface structure, | |
76 | * ix_if, which the routing code uses to locate the interface. | |
77 | * This structure contains the output queue for the interface, its address, ... | |
78 | * We also have, for each interface, a UBA interface structure, which | |
79 | * contains information about the UNIBUS resources held by the interface: | |
80 | * map registers, buffered data paths, etc. Information is cached in this | |
81 | * structure for use by the if_uba.c routines in running the interface | |
82 | * efficiently. | |
83 | */ | |
84 | struct ix_softc { | |
85 | struct arpcom ix_ac; /* Ethernet common part */ | |
86 | #define ix_if ix_ac.ac_if /* network-visible interface */ | |
87 | #define ix_addr ix_ac.ac_enaddr /* hardware Ethernet address */ | |
88 | int ix_flags; | |
89 | #define IXF_OACTIVE 0x1 /* output is active */ | |
90 | #define IXF_RCVPENDING 0x2 /* start rcv in ilcint */ | |
91 | #define IXF_GOTUBA 0x4 /* unibus resources mapped */ | |
92 | #define IXF_RUNNING 0x8 /* board is running */ | |
93 | #define IXF_SETADDR 0x10 /* physical address is changed */ | |
94 | #define IXF_STATPENDING 0x20 /* stat cmd pending */ | |
95 | #define IXF_GOTCQE 0x40 /* np resources available */ | |
785d9ccc MK |
96 | #define IXF_OWATCH 0x80 /* is output hung? */ |
97 | #define IXF_RWATCH 0x100 /* is input hung? */ | |
49ff8a6a KS |
98 | struct ifuba ix_ifuba; /* unibus resources */ |
99 | u_short ix_aid; /* Access Id returned by open DDL */ | |
100 | u_short ix_badcqe; | |
101 | struct npmaster *ix_mp; /* Board physio request header */ | |
102 | struct npreq *ix_rrp; /* Cached npreq for recv */ | |
103 | struct npreq *ix_wrp; /* Cached npreq for xmit */ | |
104 | short ix_scaninterval; /* interval of stat collection */ | |
105 | #define IXWATCHINTERVAL 60 /* once every 60 seconds */ | |
106 | union ix_stats ix_stats; /* holds on-board statistics */ | |
107 | int ix_ubaddr; /* mapping registers of ix_stats */ | |
108 | } ix_softc[NNP]; | |
109 | extern struct uba_device *npdinfo[]; | |
110 | ||
111 | /* | |
112 | * Interface exists: make available by filling in network interface | |
113 | * record. System will initialize the interface when it is ready | |
114 | * to accept packets. We can't even get the ethernet address | |
115 | * or other interesting data until the board has been downloaded. | |
116 | * running ifconfig will attempt to start unit. | |
117 | */ | |
118 | ixattach(ui) | |
119 | struct uba_device *ui; | |
120 | { | |
121 | register struct ix_softc *ix = &ix_softc[ui->ui_unit]; | |
122 | register struct ifnet *ifp = &ix->ix_if; | |
123 | extern struct npmaster npmasters[]; | |
124 | ||
125 | ifp->if_unit = ui->ui_unit; | |
126 | ifp->if_name = "ix"; | |
127 | ifp->if_mtu = ETHERMTU; | |
128 | ifp->if_flags = IFF_BROADCAST; | |
129 | ||
130 | ifp->if_init = ixinit; | |
4f02060d KS |
131 | ifp->if_output = ether_output; |
132 | ifp->if_start = ixstart; | |
49ff8a6a KS |
133 | ifp->if_ioctl = ixioctl; |
134 | ifp->if_reset = ixreset; | |
135 | ||
136 | ix->ix_mp = npmasters + ui->ui_unit; | |
137 | ix->ix_ifuba.ifu_flags = UBA_CANTWAIT; | |
138 | ||
139 | if_attach(ifp); | |
140 | } | |
141 | ||
142 | struct npreq * | |
143 | ix_GetReq(mp, addr, len) | |
144 | struct npmaster *mp; | |
145 | caddr_t addr; | |
146 | { | |
147 | int unit = mp->unit; | |
148 | register struct npreq *rp; | |
149 | register struct CQE *ep; | |
150 | struct ix_softc *ix = ix_softc + unit; | |
151 | extern struct npreq *NpGetReq(); | |
152 | ||
153 | while ((rp = NpGetReq(mp->reqtab)) == NULL) { | |
154 | mp->reqtab->flags |= WANTREQ; | |
155 | sleep((caddr_t)(mp->reqtab), PZERO - 1); | |
156 | } | |
157 | rp->flags = KERNREQ; /* Clear flags */ | |
158 | ||
159 | ep = rp->element; /* Associated CQE */ | |
160 | ep->cqe_famid = (unsign32)ix; /* Process ID */ | |
161 | ep->cqe_wind = 0; /* Amount of buffer mapped */ | |
162 | ep->cqe_nbuf = 1; /* Must be 1, no buffer chain */ | |
163 | ep->cqe_char = 1; /* Driver owns this CQE */ | |
164 | ep->cqe_prot = NPDLA; /* Data Link Access protocol */ | |
165 | ep->cqe_bcnt = len; /* Byte count */ | |
166 | rp->bufaddr = (caddr_t) (UBADDRMASK & (int) addr);/* mapped buffer */ | |
167 | ep->cqe_dma[0] = (unsign16)LOWORD(rp->bufaddr); | |
168 | ep->cqe_dma[1] = (unsign16)HIWORD(rp->bufaddr); | |
169 | return (rp); | |
170 | } | |
171 | ||
172 | ix_DoReq(mp, rp, cmd, addr, len, rpb, routine) | |
173 | struct npmaster *mp; | |
174 | register struct npreq *rp; | |
175 | u_short cmd; | |
176 | caddr_t addr; | |
177 | int len; | |
178 | register u_short *rpb; | |
179 | int (*routine)(); | |
180 | { | |
181 | register struct CQE *ep = rp->element; | |
182 | register u_short *p = &ep->rpb1; | |
183 | u_short cnt = *rpb++; | |
184 | extern long NpDebug; | |
185 | int pri; | |
785d9ccc | 186 | int result = 0; |
49ff8a6a KS |
187 | |
188 | ep->cqe_ust0 = ep->cqe_ust1 = NPCLEAR; /* Clear status */ | |
189 | ep->cqe_bcnt = len; /* Byte count */ | |
785d9ccc | 190 | rp->flags = KERNREQ | REQALOC; /* Clear flags */ |
49ff8a6a KS |
191 | rp->bufaddr = (caddr_t) (UBADDRMASK & (int) addr);/* mapped buffer */ |
192 | rp->intr = routine; | |
193 | rp->user = (caddr_t) (ep->cqe_func = cmd);/* In case pissed on in CQE */ | |
194 | ep->cqe_dma[0] = (unsign16)LOWORD(rp->bufaddr); | |
195 | ep->cqe_dma[1] = (unsign16)HIWORD(rp->bufaddr); | |
196 | ep->cqe_lenrpb = cnt + cnt; | |
197 | for (; cnt > 0; cnt--) *p++ = *rpb++; | |
198 | ||
199 | if (NpDebug & DEBCQE) | |
200 | printf("Function is %x ep %x reqid %x\n", ep->cqe_func, ep, ep->cqe_reqid); | |
201 | if (NpDebug & DEBCQE) | |
202 | printf("irp len = %x rp = %x\n", ep->cqe_lenrpb, rp); | |
203 | if (routine == 0) { | |
204 | NpAddReq(mp->reqtab, rp); /* Queue onto active list */ | |
205 | while (!(rp->flags & REQDONE)) { | |
c4054532 | 206 | pri = spl5(); |
49ff8a6a KS |
207 | NpAddCQE(ep, &mp->shmemp->devcq, mp); |
208 | sleep((caddr_t)rp, PZERO - 1); | |
209 | splx(pri); | |
210 | } | |
211 | if (rp->flags & IOABORT || ep->cqe_sts != NPDONE | |
212 | || ep->cqe_ust0 != NPDONE | |
213 | || ep->cqe_ust1 != NPOK) { | |
214 | struct ix_softc *ix = (struct ix_softc *)ep->cqe_famid; | |
785d9ccc MK |
215 | printf("ix%d: Req failed, cmd %x, stat %x, flags %x, ", |
216 | ix->ix_if.if_unit, rp->user, | |
217 | ep->cqe_sts, rp->flags); | |
49ff8a6a | 218 | printf("ust error %x,%x\n", ep->cqe_ust0, ep->cqe_ust1); |
785d9ccc | 219 | result = 1; |
49ff8a6a KS |
220 | } |
221 | NpRemReq(rp); /* Clear request */ | |
222 | } else { | |
c4054532 | 223 | pri = spl5(); |
49ff8a6a KS |
224 | NpAddCQE(ep, &mp->shmemp->devcq, mp); |
225 | splx(pri); | |
226 | } | |
785d9ccc | 227 | return(result); |
49ff8a6a | 228 | } |
49ff8a6a KS |
229 | /* |
230 | * Reset of interface after UNIBUS reset. | |
231 | * If interface is on specified uba, reset its state. | |
232 | */ | |
233 | ixreset(unit, uban, softp) | |
234 | int unit, uban; | |
235 | caddr_t softp; | |
236 | { | |
237 | register struct uba_device *ui; | |
238 | int mask = IXF_SETADDR; /* Only remember new physaddr */ | |
239 | ||
240 | if (unit >= NNP || (ui = npdinfo[unit]) == 0 || ui->ui_alive == 0 || | |
241 | ui->ui_ubanum != uban) | |
242 | return; | |
243 | printf(" ix%d reset", unit); | |
244 | if (softp) | |
245 | mask |= IXF_GOTUBA; /* UBA mapping regs still valid; */ | |
246 | ix_softc[unit].ix_if.if_flags &= ~IFF_RUNNING; | |
247 | ix_softc[unit].ix_flags &= mask; | |
248 | } | |
249 | ||
c4054532 | 250 | int ix_MacLoop = 0; |
49ff8a6a KS |
251 | |
252 | /* | |
253 | * Initialization of interface; clear recorded pending | |
254 | * operations, and reinitialize UNIBUS usage. | |
255 | */ | |
256 | ixinit(unit) | |
257 | int unit; | |
258 | { | |
259 | register struct ix_softc *ix = &ix_softc[unit]; | |
260 | struct uba_device *ui = npdinfo[unit]; | |
261 | register struct ifnet *ifp = &ix->ix_if; | |
262 | register struct CQE *ep; | |
263 | struct npreq *rp; | |
264 | struct npmaster *mp = ix->ix_mp; | |
265 | register u_short *dpmp = & mp->shmemp->statblock.sb_dpm; | |
266 | u_short rpb[7]; | |
267 | int s; | |
268 | ||
269 | /* not yet, if address still unknown */ | |
785d9ccc MK |
270 | if ((ifp->if_addrlist == (struct ifaddr *)0) || |
271 | (ix->ix_flags & IXF_RUNNING)) | |
49ff8a6a KS |
272 | return; |
273 | if ((mp->flags & AVAILABLE) == 0 || (*dpmp & PROTOMASK(NPDLA)) == 0) { | |
274 | ifp->if_flags &= ~IFF_UP; | |
275 | return; | |
276 | } | |
277 | if ((ix->ix_flags & IXF_GOTUBA) == 0) { | |
278 | ix->ix_ifuba.ifu_flags = UBA_CANTWAIT; | |
279 | if (if_ubainit(&ix->ix_ifuba, ui->ui_ubanum, | |
280 | sizeof (struct ether_header), (int)btoc(ETHERMTU)) == 0) { | |
281 | printf("ix%d: can't initialize\n", unit); | |
282 | ix->ix_if.if_flags &= ~IFF_UP; | |
283 | return; | |
284 | } | |
285 | ix->ix_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&ix->ix_stats, | |
286 | sizeof (union ix_stats), 0); | |
287 | ix->ix_flags |= IXF_GOTUBA; | |
288 | } | |
289 | if ((ix->ix_flags & IXF_GOTCQE) == 0) { | |
290 | ix->ix_rrp = ix_GetReq(mp, ix->ix_ifuba.ifu_r.ifrw_info, | |
291 | ETHERMTU); | |
292 | ix->ix_wrp = ix_GetReq(mp, 0, 0); | |
293 | ix->ix_flags |= IXF_GOTCQE; | |
294 | } | |
295 | ||
296 | rp = ix->ix_wrp; | |
297 | ep = rp->element; | |
298 | ||
299 | /* Changing the ethernet address resets the dla module, | |
300 | so must do it before opening the channel */ | |
301 | if (ix->ix_flags & IXF_SETADDR) { | |
302 | register char *cp = (char *) &ix->ix_stats; | |
303 | int spincount; | |
304 | int x; | |
785d9ccc MK |
305 | /* Try Issuing an open channel request before reprogramming |
306 | the physical address */ | |
307 | rpb[0] = 6; /* RPB length */ | |
308 | rpb[2] = 0x10; /* Share with any smart users */ | |
309 | rpb[3] = 0; /* Take (a copy of) all frames */ | |
310 | rpb[5] = 8; /* On board rcv queue length */ | |
311 | rpb[6] = 0; /* XMT packets as is */ | |
312 | if (ix_DoReq(mp, rp, IXC_OPEN, 0, 0, rpb, 0)) | |
313 | return; | |
314 | /* Proceed with LDPA */ | |
49ff8a6a KS |
315 | *cp++ = 1; |
316 | bcopy(ix->ix_addr, (caddr_t)cp, 6); | |
317 | rpb[0] = 1; /* RPB length */ | |
785d9ccc MK |
318 | if (ix_DoReq(mp, rp, IXC_LDPA, ix->ix_ubaddr, 7, rpb, 0)) |
319 | return; | |
49ff8a6a KS |
320 | #ifndef TheyFinallyFixedTheBoard |
321 | /* Board requires some time to reinitialize its protocols */ | |
322 | x = spl1(); | |
323 | spincount = 2000000; | |
324 | while (((*dpmp & PROTOMASK(NPDLA))==0) && spincount > 0) | |
325 | spincount--; | |
326 | if (spincount==0) { | |
327 | printf("ix%d: failed to reinitialize DLA module\n", | |
328 | unit); | |
329 | splx(x); | |
330 | } | |
331 | splx(x); | |
332 | #endif | |
333 | } | |
334 | rpb[0] = 6; /* RPB length */ | |
335 | rpb[2] = 0x10; /* Share with any smart users */ | |
785d9ccc MK |
336 | if (ix_MacLoop) rpb[2] |= 0x8; |
337 | /* Enable software loopback on board */ | |
49ff8a6a KS |
338 | rpb[3] = 0; /* Take (a copy of) all frames */ |
339 | rpb[5] = 8; /* On board rcv queue length */ | |
340 | rpb[6] = 0; /* XMT packets as is */ | |
785d9ccc MK |
341 | if (ix_DoReq(mp, rp, IXC_OPEN, 0, 0, rpb, 0)) |
342 | return; | |
49ff8a6a KS |
343 | |
344 | ix->ix_aid = ep->rpb1; | |
345 | ||
346 | /* Here we request our ethernet address, if we didn't reset it*/ | |
347 | if ((ix->ix_flags & IXF_SETADDR)==0) { | |
348 | rpb[0] = 2; | |
349 | rpb[1] = ix->ix_aid; | |
350 | rpb[2] = 0; /* get all stats */ | |
785d9ccc | 351 | if (ix_DoReq(mp, rp, IXC_GSTAT, /* Get Stats */ |
49ff8a6a | 352 | (caddr_t) ix->ix_ubaddr, sizeof(ix->ix_stats) - 8, |
785d9ccc MK |
353 | rpb, 0)) |
354 | return; | |
49ff8a6a KS |
355 | bcopy((caddr_t) &ix->ix_stats, (caddr_t) ix->ix_addr, 6); |
356 | } | |
357 | ix->ix_if.if_flags |= IFF_RUNNING; | |
358 | ix->ix_flags |= IXF_RUNNING; | |
359 | ifp->if_watchdog = ixwatch; | |
360 | ifp->if_timer = ix->ix_scaninterval = IXWATCHINTERVAL; | |
361 | ixrint(mp, 0); | |
362 | } | |
363 | ||
364 | /* | |
365 | * Start output on interface. | |
366 | * Get another datagram to send off of the interface queue, | |
367 | * and map it to the interface before starting the output. | |
368 | */ | |
4f02060d KS |
369 | ixstart(ifp) |
370 | struct ifnet *ifp; | |
49ff8a6a KS |
371 | { |
372 | int len = 0; | |
4f02060d | 373 | int unit = ifp->if_unit; |
49ff8a6a KS |
374 | register struct ix_softc *ix = &ix_softc[unit]; |
375 | register struct mbuf *n; | |
376 | struct mbuf *m; | |
377 | int s, error = 0; | |
378 | struct npmaster *mp = ix->ix_mp; | |
379 | struct npreq *rp = ix->ix_wrp; | |
380 | struct CQE *ep; | |
381 | u_short rpb[8]; | |
382 | ||
383 | IF_DEQUEUE(&ix->ix_if.if_snd, m); | |
384 | if (m == 0) { | |
385 | if (ix->ix_flags & IXF_STATPENDING) { | |
c4054532 | 386 | ix->ix_flags &= ~IXF_STATPENDING; |
4f02060d | 387 | ix->ix_if.if_flags |= IFF_OACTIVE; |
49ff8a6a KS |
388 | rpb[0] = 2; |
389 | rpb[1] = ix->ix_aid; | |
390 | rpb[2] = 0; /* get all stats */ | |
391 | ix_DoReq(mp, rp, IXC_GSTAT, /* general Stats */ | |
392 | (caddr_t) ix->ix_ubaddr, sizeof(ix->ix_stats) - 8, | |
393 | rpb, ixcint); | |
394 | } | |
4f02060d | 395 | return (0); |
49ff8a6a KS |
396 | } |
397 | /* | |
398 | * Ensure minimum packet length. | |
399 | * This makes the safe assumtion that there are no virtual holes | |
400 | * after the data. | |
401 | * For security, it might be wise to zero out the added bytes, | |
402 | * but we're mainly interested in speed at the moment. | |
403 | */ | |
404 | len = if_wubaput(&ix->ix_ifuba, m); | |
405 | if (len - sizeof(struct ether_header) < ETHERMIN) | |
406 | len = ETHERMIN + sizeof(struct ether_header); | |
407 | ||
4f02060d | 408 | ix->ix_if.if_flags |= IFF_OACTIVE; |
49ff8a6a KS |
409 | |
410 | /* Now setup to call np driver */ | |
411 | rpb[0] = 8; | |
412 | rpb[1] = ix->ix_aid; | |
413 | ix_DoReq(mp, rp, IXC_XMIT, /* send frame */ | |
414 | ix->ix_ifuba.ifu_w.ifrw_info, len, rpb, ixcint); | |
4f02060d | 415 | return (0); |
49ff8a6a KS |
416 | } |
417 | ||
418 | /* | |
419 | * Command done interrupt. (almost) | |
420 | */ | |
421 | ixcint(mp, rp) | |
422 | struct npmaster *mp; | |
423 | struct npreq *rp; | |
424 | { | |
425 | struct CQE *ep; | |
426 | register struct ix_softc *ix; | |
427 | int s = splimp(); | |
428 | ||
429 | ep = rp->element; | |
430 | ix = (struct ix_softc *)ep->cqe_famid; | |
785d9ccc | 431 | ix->ix_flags &= ~IXF_OWATCH; |
4f02060d | 432 | if ((ix->ix_if.if_flags & IFF_OACTIVE) == 0) { |
49ff8a6a KS |
433 | printf("ix%d: stray xmit interrupt, npreq=%x\n", |
434 | ix->ix_if.if_unit, rp); | |
435 | } | |
4f02060d | 436 | ix->ix_if.if_flags &= ~IFF_OACTIVE; |
785d9ccc MK |
437 | if (rp->flags & IOABORT || ep->cqe_sts != NPDONE |
438 | || ep->cqe_ust0 != NPDONE || ep->cqe_ust1 != NPOK) { | |
439 | if (ep->cqe_ust1 == 0x48) | |
440 | ix->ix_if.if_oerrors++; | |
441 | else { | |
442 | struct ix_softc *ix = (struct ix_softc *)ep->cqe_famid; | |
443 | printf( | |
444 | "ix%d: ixcint failed, cmd %x, stat %x, flags %x, ", | |
445 | ix->ix_if.if_unit, rp->user, | |
446 | ep->cqe_sts, rp->flags); | |
447 | printf("ust error %x,%x\n", ep->cqe_ust0, ep->cqe_ust1); | |
448 | if (++ix->ix_badcqe > 65) { | |
449 | ix->ix_badcqe = 0; | |
450 | printf("ixcint: shutting down unix dla\n"); | |
451 | ix->ix_if.if_flags &= ~IFF_UP; | |
452 | } | |
453 | } | |
454 | } | |
455 | else switch (ep->cqe_func) { | |
49ff8a6a KS |
456 | |
457 | case IXC_XMIT: | |
785d9ccc | 458 | ix->ix_if.if_opackets++; |
49ff8a6a KS |
459 | break; |
460 | ||
461 | case IXC_GSTAT: | |
785d9ccc | 462 | ix->ix_if.if_collisions += ix->ix_stats.ixg.macg_xrty; |
49ff8a6a | 463 | } |
785d9ccc | 464 | done: |
49ff8a6a KS |
465 | if (ix->ix_ifuba.ifu_xtofree) { |
466 | m_freem(ix->ix_ifuba.ifu_xtofree); | |
467 | ix->ix_ifuba.ifu_xtofree = 0; | |
468 | } | |
785d9ccc | 469 | if ((ix->ix_if.if_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING)) |
4f02060d | 470 | (void) ixstart(&ix->ix_if); |
49ff8a6a KS |
471 | splx(s); |
472 | } | |
473 | ||
474 | /* | |
475 | * Ethernet interface receiver interrupt. | |
476 | * If input error just drop packet. | |
477 | * Otherwise purge input buffered data path and examine | |
478 | * packet to determine type. If can't determine length | |
479 | * from type, then have to drop packet. Othewise decapsulate | |
480 | * packet based on type and pass to type specific higher-level | |
481 | * input routine. | |
482 | */ | |
483 | ixrint(mp, rp) | |
484 | struct npmaster *mp; | |
485 | struct npreq *rp; | |
486 | { | |
487 | struct CQE *ep; | |
488 | register struct ix_softc *ix = ix_softc + mp->unit; | |
489 | register struct ether_header *il; | |
490 | struct mbuf *m; | |
491 | int len, off, resid, s; | |
492 | register struct ifqueue *inq; | |
493 | ||
494 | if ((ix->ix_flags & IXF_RUNNING) == 0) | |
495 | return; | |
496 | if (rp == 0) | |
497 | goto setup; | |
785d9ccc | 498 | ix->ix_flags &= ~(IXF_RCVPENDING|IXF_RWATCH); |
49ff8a6a KS |
499 | ep = rp->element; |
500 | ix->ix_if.if_ipackets++; | |
501 | if (ix->ix_ifuba.ifu_flags & UBA_NEEDBDP) | |
502 | UBAPURGE(ix->ix_ifuba.ifu_uba, ix->ix_ifuba.ifu_r.ifrw_bdp); | |
503 | il = (struct ether_header *)(ix->ix_ifuba.ifu_r.ifrw_addr); | |
504 | len = ep->cqe_bcnt - sizeof (struct ether_header); | |
785d9ccc | 505 | if (ep->cqe_sts != NPDONE || rp->flags & IOABORT |
49ff8a6a KS |
506 | || ep->cqe_ust0 != NPDONE |
507 | || ep->cqe_ust1 != NPOK) { | |
785d9ccc MK |
508 | printf("ix%drint: cqe error, cmd %x, stat %x, flags %x, ", |
509 | ix->ix_if.if_unit, rp->user, ep->cqe_sts, rp->flags); | |
510 | printf("ust error %x,%x\n", ep->cqe_ust0, ep->cqe_ust1); | |
511 | if (++ix->ix_badcqe > 50) { | |
49ff8a6a KS |
512 | ix->ix_badcqe = 0; |
513 | printf("ixrint: shutting down unix dla\n"); | |
514 | ix->ix_if.if_flags &= ~IFF_UP; | |
515 | return; | |
516 | } | |
517 | goto setup; | |
518 | } | |
519 | ||
520 | if ( len < 46 || len > ETHERMTU) { | |
521 | ix->ix_if.if_ierrors++; | |
522 | #ifdef notdef | |
523 | if (ix->ix_if.if_ierrors % 100 == 0) | |
524 | printf("ix%d: += 100 input errors\n", unit); | |
525 | #endif | |
526 | goto setup; | |
527 | } | |
528 | ||
529 | /* | |
530 | * Deal with trailer protocol: if type is trailer type | |
531 | * get true type from first 16-bit word past data. | |
532 | * Remember that type was trailer by setting off. | |
533 | */ | |
534 | il->ether_type = ntohs((u_short)il->ether_type); | |
535 | #define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off)))) | |
536 | if (il->ether_type >= ETHERTYPE_TRAIL && | |
537 | il->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { | |
538 | off = (il->ether_type - ETHERTYPE_TRAIL) * 512; | |
539 | if (off >= ETHERMTU) | |
540 | goto setup; /* sanity */ | |
541 | il->ether_type = ntohs(*ildataaddr(il, off, u_short *)); | |
542 | resid = ntohs(*(ildataaddr(il, off+2, u_short *))); | |
543 | if (off + resid > len) | |
544 | goto setup; /* sanity */ | |
545 | len = off + resid; | |
546 | } else | |
547 | off = 0; | |
548 | if (len == 0) | |
549 | goto setup; | |
550 | ||
551 | /* | |
552 | * Pull packet off interface. Off is nonzero if packet | |
553 | * has trailing header; ilget will then force this header | |
554 | * information to be at the front, but we still have to drop | |
555 | * the type and length which are at the front of any trailer data. | |
556 | */ | |
557 | m = if_rubaget(&ix->ix_ifuba, len, off, &ix->ix_if); | |
4f02060d KS |
558 | if (m) |
559 | ether_input(&ix->ix_if, il, m); | |
49ff8a6a KS |
560 | |
561 | setup: | |
562 | /* | |
563 | * Reset for next packet if possible. | |
564 | * If waiting for transmit command completion, set flag | |
565 | * and wait until command completes. | |
566 | */ | |
567 | if (rp == 0) { | |
568 | rp = ix->ix_rrp; | |
569 | rp->intr = ixrint; | |
570 | ep = rp->element; | |
571 | } | |
572 | len = ETHERMTU + sizeof(struct ether_header); | |
573 | ||
574 | /* Now setup to call np driver */ | |
575 | /* Initializations of request structure */ | |
576 | ||
577 | ep->cqe_func = IXC_RECV; /* get frame */ | |
578 | ep->cqe_ust0 = ep->cqe_ust1 = NPCLEAR; /* Clear status */ | |
579 | ep->cqe_bcnt = len; /* Byte count */ | |
580 | ep->cqe_lenrpb = 10; /* RPB length */ | |
581 | ep->rpb1 = ix->ix_aid; /* which channel */ | |
582 | ep->rpb2 = 65535; /* Timeout */ | |
583 | ||
584 | ix->ix_flags |= IXF_RCVPENDING; | |
585 | ||
c4054532 | 586 | s = spl5(); |
49ff8a6a KS |
587 | NpAddCQE(ep, &mp->shmemp->devcq, mp); /* Add CQE to device's queue */ |
588 | splx(s); | |
589 | } | |
590 | ||
591 | ||
785d9ccc | 592 | long ixwatchcount; |
49ff8a6a KS |
593 | /* |
594 | * Watchdog routine, request statistics from board. | |
595 | */ | |
596 | ixwatch(unit) | |
597 | int unit; | |
598 | { | |
599 | register struct ix_softc *ix = &ix_softc[unit]; | |
600 | register struct ifnet *ifp = &ix->ix_if; | |
601 | int s; | |
602 | ||
785d9ccc MK |
603 | ixwatchcount++; |
604 | if (ix->ix_badcqe > 1) { | |
605 | ix->ix_badcqe--; /* If errors aren't happening too fast, | |
606 | give the board a reprieve */ | |
607 | } | |
608 | s = splimp(); | |
49ff8a6a KS |
609 | if (ix->ix_flags & IXF_STATPENDING) { |
610 | ifp->if_timer = ix->ix_scaninterval; | |
785d9ccc MK |
611 | ix->ix_flags |= IXF_OWATCH; |
612 | splx(s); | |
49ff8a6a KS |
613 | return; |
614 | } | |
49ff8a6a | 615 | ix->ix_flags |= IXF_STATPENDING; |
4f02060d KS |
616 | if ((ix->ix_if.if_flags & IFF_OACTIVE) == 0) |
617 | (void) ixstart(ifp); | |
785d9ccc MK |
618 | else |
619 | ix->ix_flags |= IXF_OWATCH; | |
620 | if (ix->ix_flags & IXF_RCVPENDING) | |
621 | ix->ix_flags |= IXF_RWATCH; | |
49ff8a6a KS |
622 | splx(s); |
623 | ifp->if_timer = ix->ix_scaninterval; | |
624 | } | |
625 | /* | |
626 | * Process an ioctl request. | |
627 | */ | |
628 | ixioctl(ifp, cmd, data) | |
629 | register struct ifnet *ifp; | |
630 | int cmd; | |
631 | caddr_t data; | |
632 | { | |
633 | register struct ifaddr *ifa = (struct ifaddr *)data; | |
634 | register struct ix_softc *ix = &ix_softc[ifp->if_unit]; | |
635 | int s = splimp(), error = 0; | |
636 | ||
637 | switch (cmd) { | |
638 | ||
639 | case SIOCSIFADDR: | |
640 | ifp->if_flags |= IFF_UP; | |
641 | ixinit(ifp->if_unit); | |
642 | if ((ifp->if_flags & IFF_UP) == 0) | |
643 | return (EBUSY); | |
644 | ||
4f02060d | 645 | switch (ifa->ifa_addr->sa_family) { |
49ff8a6a KS |
646 | #ifdef INET |
647 | case AF_INET: | |
648 | ((struct arpcom *)ifp)->ac_ipaddr = | |
649 | IA_SIN(ifa)->sin_addr; | |
650 | arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); | |
651 | break; | |
652 | #endif | |
653 | #ifdef NS | |
654 | case AF_NS: | |
655 | { | |
656 | register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); | |
657 | ||
658 | if (ns_nullhost(*ina)) { | |
659 | ina->x_host = * (union ns_host *) | |
660 | (ix_softc[ifp->if_unit].ix_addr); | |
661 | } else { | |
662 | return | |
663 | ix_setaddr(ina->x_host.c_host, ifp->if_unit); | |
664 | } | |
665 | break; | |
666 | } | |
667 | #endif | |
668 | } | |
669 | break; | |
670 | ||
671 | case SIOCSIFFLAGS: | |
672 | if ((ifp->if_flags & IFF_UP) == 0 && | |
673 | ix->ix_flags & IXF_RUNNING) { | |
674 | ix->ix_flags &= ~IXF_RUNNING; | |
675 | NpReset(ix->ix_mp, 0); | |
676 | } else if (ifp->if_flags & IFF_UP && | |
677 | (ix->ix_flags & IXF_RUNNING) == 0) | |
678 | ixinit(ifp->if_unit); | |
679 | break; | |
680 | ||
681 | default: | |
682 | error = EINVAL; | |
683 | } | |
684 | splx(s); | |
685 | return (error); | |
686 | } | |
687 | ||
688 | /* | |
689 | * set ethernet address for unit | |
690 | */ | |
691 | ix_setaddr(physaddr, unit) | |
692 | u_char *physaddr; | |
693 | int unit; | |
694 | { | |
695 | register struct ix_softc *ix = &ix_softc[unit]; | |
696 | ||
697 | if (! (ix->ix_flags & IXF_RUNNING)) | |
698 | return (EBUSY); | |
699 | ||
700 | /* The following is a big cop out due to the fact that | |
701 | Changing the ethernet address resets the dla module, | |
702 | so must re-open the channel, anyway. */ | |
703 | ||
704 | ||
705 | bcopy((caddr_t)physaddr, (caddr_t)ix->ix_addr, sizeof ix->ix_addr); | |
706 | ix->ix_flags &= ~IXF_RUNNING; | |
707 | ix->ix_flags |= IXF_SETADDR; | |
708 | ixinit(unit); | |
709 | NpKill(ix->ix_mp, ix->ix_rrp); | |
710 | } | |
785d9ccc MK |
711 | static showme() { |
712 | return ((int) &(ix_softc->ix_badcqe)); | |
713 | } | |
49ff8a6a | 714 | #endif |