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