impattach takes 2 arguments
[unix-history] / usr / src / sys / vax / if / if_il.c
CommitLineData
eaa60542 1/* if_il.c 4.12 82/10/10 */
f0d51478
BF
2
3#include "il.h"
f0d51478
BF
4
5/*
6 * Interlan Ethernet Communications Controller interface
7 */
f0d51478
BF
8#include "../h/param.h"
9#include "../h/systm.h"
10#include "../h/mbuf.h"
11#include "../h/pte.h"
12#include "../h/buf.h"
13#include "../h/protosw.h"
14#include "../h/socket.h"
f0d51478 15#include "../h/vmmac.h"
eaa60542
BJ
16#include <errno.h>
17
18#include "../net/if.h"
19#include "../net/netisr.h"
20#include "../net/route.h"
d2cc167c
BJ
21#include "../netinet/in.h"
22#include "../netinet/in_systm.h"
d2cc167c
BJ
23#include "../netinet/ip.h"
24#include "../netinet/ip_var.h"
25#include "../netpup/pup.h"
eaa60542
BJ
26
27#include "../vax/cpu.h"
28#include "../vax/mtpr.h"
29#include "../vaxif/if_ilreg.h"
30#include "../vaxif/if_il.h"
31#include "../vaxif/if_uba.h"
32#include "../vaxuba/ubareg.h"
33#include "../vaxuba/ubavar.h"
f0d51478
BF
34
35#define ILMTU 1500
36
37int ilprobe(), ilattach(), ilrint(), ilcint();
38struct uba_device *ilinfo[NIL];
39u_short ilstd[] = { 0 };
40struct uba_driver ildriver =
41 { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo };
f0d51478 42#define ILUNIT(x) minor(x)
8d38dbc2 43int ilinit(),iloutput(),ilreset(),ilwatch();
f0d51478 44
caf0e371
SL
45u_char il_ectop[3] = { 0x02, 0x60, 0x8c };
46u_char ilbroadcastaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
47
f0d51478
BF
48/*
49 * Ethernet software status per interface.
50 *
51 * Each interface is referenced by a network interface structure,
52 * is_if, which the routing code uses to locate the interface.
53 * This structure contains the output queue for the interface, its address, ...
54 * We also have, for each interface, a UBA interface structure, which
55 * contains information about the UNIBUS resources held by the interface:
56 * map registers, buffered data paths, etc. Information is cached in this
57 * structure for use by the if_uba.c routines in running the interface
58 * efficiently.
59 */
60struct il_softc {
61 struct ifnet is_if; /* network-visible interface */
62 struct ifuba is_ifuba; /* UNIBUS resources */
8d38dbc2
SL
63 int is_flags;
64#define ILF_OACTIVE 0x1 /* output is active */
65#define ILF_RCVPENDING 0x2 /* start rcv in ilcint */
66#define ILF_STATPENDING 0x4 /* stat cmd pending */
67 short is_lastcmd; /* can't read csr, so must save it */
68 short is_scaninterval; /* interval of stat collection */
69#define ILWATCHINTERVAL 60 /* once every 60 seconds */
70 struct il_stats is_stats; /* holds on-board statistics */
71 struct il_stats is_sum; /* summation over time */
72 int is_ubaddr; /* mapping registers of is_stats */
f0d51478
BF
73} il_softc[NIL];
74
f0d51478
BF
75ilprobe(reg)
76 caddr_t reg;
77{
78 register int br, cvec; /* r11, r10 value-result */
79 register struct ildevice *addr = (struct ildevice *)reg;
80 register i;
81
f0d51478
BF
82#ifdef lint
83 br = 0; cvec = br; br = cvec;
8d38dbc2 84 ilrint(0); ilcint(0); ilwatch(0);
f0d51478
BF
85#endif
86
87 addr->il_csr = ILC_OFFLINE|IL_CIE;
88 DELAY(100000);
8d38dbc2 89 i = addr->il_csr; /* clear CDONE */
f0d51478
BF
90 if (cvec > 0 && cvec != 0x200)
91 cvec -= 4;
92 return (1);
93}
94
f0d51478
BF
95/*
96 * Interface exists: make available by filling in network interface
97 * record. System will initialize the interface when it is ready
98 * to accept packets. A STATUS command is done to get the ethernet
99 * address and other interesting data.
100 */
101ilattach(ui)
102 struct uba_device *ui;
103{
104 register struct il_softc *is = &il_softc[ui->ui_unit];
caf0e371 105 register struct ifnet *ifp = &is->is_if;
f0d51478 106 register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
caf0e371 107 struct sockaddr_in *sin;
f0d51478 108
caf0e371
SL
109 ifp->if_unit = ui->ui_unit;
110 ifp->if_name = "il";
111 ifp->if_mtu = ILMTU;
112 ifp->if_net = ui->ui_flags;
f0d51478
BF
113
114 /*
8d38dbc2
SL
115 * Reset the board and map the statistics
116 * buffer onto the Unibus.
f0d51478 117 */
8d38dbc2
SL
118 addr->il_csr = ILC_RESET;
119 while ((addr->il_csr&IL_CDONE) == 0)
120 ;
121 if (addr->il_csr&IL_STATUS)
122 printf("il%d: reset failed, csr=%b\n", ui->ui_unit,
123 addr->il_csr, IL_BITS);
f0d51478 124
8d38dbc2
SL
125 is->is_ubaddr = uballoc(ui->ui_ubanum, &is->is_stats,
126 sizeof (struct il_stats), 0);
127 addr->il_bar = is->is_ubaddr & 0xffff;
128 addr->il_bcr = sizeof (struct il_stats);
129 addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT;
130 while ((addr->il_csr&IL_CDONE) == 0)
131 ;
132 if (addr->il_csr&IL_STATUS)
133 printf("il%d: status failed, csr=%b\n", ui->ui_unit,
134 addr->il_csr, IL_BITS);
135 ubarelse(ui->ui_ubanum, &is->is_ubaddr);
f0d51478
BF
136 printf("il%d: addr=%x:%x:%x:%x:%x:%x module=%s firmware=%s\n",
137 ui->ui_unit,
8d38dbc2
SL
138 is->is_stats.ils_addr[0]&0xff, is->is_stats.ils_addr[1]&0xff,
139 is->is_stats.ils_addr[2]&0xff, is->is_stats.ils_addr[3]&0xff,
140 is->is_stats.ils_addr[4]&0xff, is->is_stats.ils_addr[5]&0xff,
141 is->is_stats.ils_module, is->is_stats.ils_firmware);
142 ifp->if_host[0] =
143 ((is->is_stats.ils_addr[3]&0xff)<<16) | 0x800000 |
144 ((is->is_stats.ils_addr[4]&0xff)<<8) |
145 (is->is_stats.ils_addr[5]&0xff);
caf0e371 146 sin = (struct sockaddr_in *)&ifp->if_addr;
f0d51478 147 sin->sin_family = AF_INET;
caf0e371 148 sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
f0d51478 149
caf0e371 150 sin = (struct sockaddr_in *)&ifp->if_broadaddr;
f0d51478 151 sin->sin_family = AF_INET;
caf0e371
SL
152 sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
153 ifp->if_flags = IFF_BROADCAST;
f0d51478 154
caf0e371
SL
155 ifp->if_init = ilinit;
156 ifp->if_output = iloutput;
157 ifp->if_ubareset = ilreset;
8d38dbc2
SL
158 ifp->if_watchdog = ilwatch;
159 is->is_scaninterval = ILWATCHINTERVAL;
160 ifp->if_timer = is->is_scaninterval;
f0d51478 161 is->is_ifuba.ifu_flags = UBA_CANTWAIT;
caf0e371
SL
162#ifdef notdef
163 is->is_ifuba.ifu_flags |= UBA_NEEDBDP;
164#endif
165 if_attach(ifp);
f0d51478
BF
166}
167
168/*
169 * Reset of interface after UNIBUS reset.
170 * If interface is on specified uba, reset its state.
171 */
172ilreset(unit, uban)
173 int unit, uban;
174{
175 register struct uba_device *ui;
f0d51478
BF
176
177 if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 ||
178 ui->ui_ubanum != uban)
179 return;
180 printf(" il%d", unit);
181 ilinit(unit);
182}
183
184/*
185 * Initialization of interface; clear recorded pending
186 * operations, and reinitialize UNIBUS usage.
187 */
188ilinit(unit)
189 int unit;
190{
191 register struct il_softc *is = &il_softc[unit];
192 register struct uba_device *ui = ilinfo[unit];
193 register struct ildevice *addr;
8d38dbc2 194 int s;
f0d51478
BF
195
196 if (if_ubainit(&is->is_ifuba, ui->ui_ubanum,
197 sizeof (struct il_rheader), (int)btoc(ILMTU)) == 0) {
198 printf("il%d: can't initialize\n", unit);
199 is->is_if.if_flags &= ~IFF_UP;
200 return;
201 }
8d38dbc2
SL
202 is->is_ubaddr = uballoc(ui->ui_ubanum, &is->is_stats,
203 sizeof (struct il_stats), 0);
f0d51478
BF
204 addr = (struct ildevice *)ui->ui_addr;
205
206 /*
207 * Set board online.
208 * Hang receive buffer and start any pending
209 * writes by faking a transmit complete.
210 * Receive bcr is not a muliple of 4 so buffer
211 * chaining can't happen.
212 */
213 s = splimp();
214 addr->il_csr = ILC_ONLINE;
caf0e371
SL
215 while ((addr->il_csr & IL_CDONE) == 0)
216 ;
f0d51478
BF
217 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
218 addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
8d38dbc2
SL
219 addr->il_csr =
220 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
caf0e371
SL
221 while ((addr->il_csr & IL_CDONE) == 0)
222 ;
8d38dbc2 223 is->is_flags = ILF_OACTIVE;
f0d51478 224 is->is_if.if_flags |= IFF_UP;
8d38dbc2 225 is->is_lastcmd = 0;
f0d51478
BF
226 ilcint(unit);
227 splx(s);
a13c006d 228 if_rtinit(&is->is_if, RTF_UP);
f0d51478
BF
229}
230
231/*
232 * Start output on interface.
233 * Get another datagram to send off of the interface queue,
234 * and map it to the interface before starting the output.
235 */
236ilstart(dev)
237 dev_t dev;
238{
caf0e371 239 int unit = ILUNIT(dev), dest, len;
f0d51478
BF
240 struct uba_device *ui = ilinfo[unit];
241 register struct il_softc *is = &il_softc[unit];
242 register struct ildevice *addr;
f0d51478 243 struct mbuf *m;
caf0e371 244 short csr;
f0d51478 245
f0d51478 246 IF_DEQUEUE(&is->is_if.if_snd, m);
8d38dbc2
SL
247 addr = (struct ildevice *)ui->ui_addr;
248 if (m == 0) {
249 if ((is->is_flags & ILF_STATPENDING) == 0)
250 return;
251 addr->il_bar = is->is_ubaddr & 0xfff;
252 addr->il_bcr = sizeof (struct il_stats);
253 csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE;
254 is->is_flags &= ~ILF_STATPENDING;
255 goto startcmd;
256 }
f0d51478 257 len = if_wubaput(&is->is_ifuba, m);
f0d51478
BF
258 if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
259 UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp);
f0d51478
BF
260 addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff;
261 addr->il_bcr = len;
8d38dbc2
SL
262 csr =
263 ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE;
264
265startcmd:
266 is->is_lastcmd = csr & IL_CMD;
caf0e371 267 addr->il_csr = csr;
8d38dbc2 268 is->is_flags |= ILF_OACTIVE;
f0d51478
BF
269}
270
271/*
272 * Command done interrupt.
f0d51478
BF
273 */
274ilcint(unit)
275 int unit;
276{
f0d51478 277 register struct il_softc *is = &il_softc[unit];
caf0e371 278 struct uba_device *ui = ilinfo[unit];
f0d51478 279 register struct ildevice *addr = (struct ildevice *)ui->ui_addr;
5565eee9 280 short csr;
f0d51478 281
8d38dbc2 282 if ((is->is_flags & ILF_OACTIVE) == 0) {
caf0e371 283 printf("il%d: stray xmit interrupt, csr=%b\n", unit,
8d38dbc2 284 addr->il_csr, IL_BITS);
f0d51478
BF
285 return;
286 }
caf0e371 287
5565eee9 288 csr = addr->il_csr;
f0d51478 289 /*
8d38dbc2
SL
290 * Hang receive buffer if it couldn't
291 * be done earlier (in ilrint).
f0d51478 292 */
8d38dbc2 293 if (is->is_flags & ILF_RCVPENDING) {
f0d51478
BF
294 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
295 addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
8d38dbc2
SL
296 addr->il_csr =
297 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
caf0e371
SL
298 while ((addr->il_csr & IL_CDONE) == 0)
299 ;
8d38dbc2
SL
300 is->is_flags &= ~ILF_RCVPENDING;
301 }
302 is->is_flags &= ~ILF_OACTIVE;
5565eee9 303 csr &= IL_STATUS;
8d38dbc2
SL
304 switch (is->is_lastcmd) {
305
306 case ILC_XMIT:
307 is->is_if.if_opackets++;
5565eee9 308 if (csr > ILERR_RETRIES)
8d38dbc2
SL
309 is->is_if.if_oerrors++;
310 break;
311
312 case ILC_STAT:
5565eee9 313 if (csr == ILERR_SUCCESS)
8d38dbc2
SL
314 iltotal(is);
315 break;
f0d51478
BF
316 }
317 if (is->is_ifuba.ifu_xtofree) {
318 m_freem(is->is_ifuba.ifu_xtofree);
319 is->is_ifuba.ifu_xtofree = 0;
320 }
8d38dbc2 321 ilstart(unit);
f0d51478
BF
322}
323
324/*
325 * Ethernet interface receiver interrupt.
326 * If input error just drop packet.
327 * Otherwise purge input buffered data path and examine
328 * packet to determine type. If can't determine length
329 * from type, then have to drop packet. Othewise decapsulate
330 * packet based on type and pass to type specific higher-level
331 * input routine.
332 */
333ilrint(unit)
334 int unit;
335{
336 register struct il_softc *is = &il_softc[unit];
337 struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr;
338 register struct il_rheader *il;
339 struct mbuf *m;
340 int len, off, resid;
341 register struct ifqueue *inq;
342
f0d51478
BF
343 is->is_if.if_ipackets++;
344 if (is->is_ifuba.ifu_flags & UBA_NEEDBDP)
345 UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp);
346 il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr);
347 len = il->ilr_length - sizeof(struct il_rheader);
8d38dbc2 348 if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 || len > ILMTU) {
f0d51478
BF
349 is->is_if.if_ierrors++;
350#ifdef notdef
351 if (is->is_if.if_ierrors % 100 == 0)
352 printf("il%d: += 100 input errors\n", unit);
353#endif
f0d51478
BF
354 goto setup;
355 }
356
357 /*
358 * Deal with trailer protocol: if type is PUP trailer
359 * get true type from first 16-bit word past data.
360 * Remember that type was trailer by setting off.
361 */
362#define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off))))
363 if (il->ilr_type >= ILPUP_TRAIL &&
364 il->ilr_type < ILPUP_TRAIL+ILPUP_NTRAILER) {
365 off = (il->ilr_type - ILPUP_TRAIL) * 512;
366 if (off >= ILMTU)
367 goto setup; /* sanity */
368 il->ilr_type = *ildataaddr(il, off, u_short *);
369 resid = *(ildataaddr(il, off+2, u_short *));
370 if (off + resid > len)
371 goto setup; /* sanity */
372 len = off + resid;
373 } else
374 off = 0;
375 if (len == 0)
376 goto setup;
377
378 /*
379 * Pull packet off interface. Off is nonzero if packet
380 * has trailing header; ilget will then force this header
381 * information to be at the front, but we still have to drop
382 * the type and length which are at the front of any trailer data.
383 */
384 m = if_rubaget(&is->is_ifuba, len, off);
385 if (m == 0)
386 goto setup;
387 if (off) {
388 m->m_off += 2 * sizeof (u_short);
389 m->m_len -= 2 * sizeof (u_short);
390 }
391 switch (il->ilr_type) {
392
393#ifdef INET
394 case ILPUP_IPTYPE:
395 schednetisr(NETISR_IP);
396 inq = &ipintrq;
397 break;
398#endif
399 default:
400 m_freem(m);
401 goto setup;
402 }
403
404 if (IF_QFULL(inq)) {
405 IF_DROP(inq);
406 m_freem(m);
caf0e371
SL
407 goto setup;
408 }
409 IF_ENQUEUE(inq, m);
f0d51478
BF
410
411setup:
412 /*
413 * Reset for next packet if possible.
414 * If waiting for transmit command completion, set flag
415 * and wait until command completes.
416 */
8d38dbc2
SL
417 if (is->is_flags & ILF_OACTIVE) {
418 is->is_flags |= ILF_RCVPENDING;
caf0e371
SL
419 return;
420 }
421 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff;
422 addr->il_bcr = sizeof(struct il_rheader) + ILMTU + 6;
8d38dbc2
SL
423 addr->il_csr =
424 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE;
caf0e371
SL
425 while ((addr->il_csr & IL_CDONE) == 0)
426 ;
f0d51478
BF
427}
428
429/*
430 * Ethernet output routine.
431 * Encapsulate a packet of type family for the local net.
432 * Use trailer local net encapsulation if enough data in first
433 * packet leaves a multiple of 512 bytes of data in remainder.
434 */
435iloutput(ifp, m0, dst)
436 struct ifnet *ifp;
437 struct mbuf *m0;
438 struct sockaddr *dst;
439{
440 int type, dest, s, error;
441 register struct il_softc *is = &il_softc[ifp->if_unit];
442 register struct mbuf *m = m0;
443 register struct il_xheader *il;
caf0e371 444 register int off, i;
f0d51478 445
f0d51478
BF
446 switch (dst->sa_family) {
447
448#ifdef INET
449 case AF_INET:
450 dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
451 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
452 if (off > 0 && (off & 0x1ff) == 0 &&
453 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
454 type = ILPUP_TRAIL + (off>>9);
455 m->m_off -= 2 * sizeof (u_short);
456 m->m_len += 2 * sizeof (u_short);
457 *mtod(m, u_short *) = ILPUP_IPTYPE;
458 *(mtod(m, u_short *) + 1) = m->m_len;
459 goto gottrailertype;
460 }
461 type = ILPUP_IPTYPE;
462 off = 0;
463 goto gottype;
464#endif
465
466 default:
467 printf("il%d: can't handle af%d\n", ifp->if_unit,
468 dst->sa_family);
469 error = EAFNOSUPPORT;
470 goto bad;
471 }
472
473gottrailertype:
474 /*
475 * Packet to be sent as trailer: move first packet
476 * (control information) to end of chain.
477 */
478 while (m->m_next)
479 m = m->m_next;
480 m->m_next = m0;
481 m = m0->m_next;
482 m0->m_next = 0;
483 m0 = m;
484
485gottype:
486 /*
487 * Add local net header. If no space in first mbuf,
488 * allocate another.
489 */
490 if (m->m_off > MMAXOFF ||
491 MMINOFF + sizeof (struct il_xheader) > m->m_off) {
492 m = m_get(M_DONTWAIT);
493 if (m == 0) {
494 error = ENOBUFS;
495 goto bad;
496 }
497 m->m_next = m0;
498 m->m_off = MMINOFF;
499 m->m_len = sizeof (struct il_xheader);
500 } else {
501 m->m_off -= sizeof (struct il_xheader);
502 m->m_len += sizeof (struct il_xheader);
503 }
504 il = mtod(m, struct il_xheader *);
505 if ((dest &~ 0xff) == 0)
caf0e371 506 bcopy(ilbroadcastaddr, il->ilx_dhost, 6);
f0d51478 507 else {
8d38dbc2 508 u_char *to = dest & 0x8000 ? is->is_stats.ils_addr : il_ectop;
caf0e371
SL
509
510 bcopy(to, il->ilx_dhost, 3);
f0d51478
BF
511 il->ilx_dhost[3] = (dest>>8) & 0x7f;
512 il->ilx_dhost[4] = (dest>>16) & 0xff;
513 il->ilx_dhost[5] = (dest>>24) & 0xff;
514 }
515 il->ilx_type = type;
516
517 /*
518 * Queue message on interface, and start output if interface
519 * not yet active.
520 */
521 s = splimp();
522 if (IF_QFULL(&ifp->if_snd)) {
523 IF_DROP(&ifp->if_snd);
caf0e371
SL
524 splx(s);
525 m_freem(m);
526 return (ENOBUFS);
f0d51478
BF
527 }
528 IF_ENQUEUE(&ifp->if_snd, m);
8d38dbc2 529 if ((is->is_flags & ILF_OACTIVE) == 0)
f0d51478
BF
530 ilstart(ifp->if_unit);
531 splx(s);
532 return (0);
caf0e371 533
f0d51478
BF
534bad:
535 m_freem(m0);
caf0e371 536 return (error);
f0d51478 537}
8d38dbc2
SL
538
539/*
540 * Watchdog routine, request statistics from board.
541 */
542ilwatch(unit)
543 int unit;
544{
545 register struct il_softc *is = &il_softc[unit];
546 register struct ifnet *ifp = &is->is_if;
547 int s;
548
549 if (is->is_flags & ILF_STATPENDING) {
550 ifp->if_timer = is->is_scaninterval;
551 return;
552 }
553 s = splimp();
554 is->is_flags |= ILF_STATPENDING;
555 if ((is->is_flags & ILF_OACTIVE) == 0)
556 ilstart(ifp->if_unit);
557 splx(s);
558 ifp->if_timer = is->is_scaninterval;
559}
560
561/*
562 * Total up the on-board statistics.
563 */
564iltotal(is)
565 register struct il_softc *is;
566{
567 register u_short *interval, *sum, *end;
568
569 interval = &is->is_stats.ils_frames;
570 sum = &is->is_sum.ils_frames;
571 end = is->is_sum.ils_fill2;
572 while (sum < end)
573 *sum++ += *interval++;
574 is->is_if.if_collisions = is->is_sum.ils_collis;
575}