changes for var. length sockaddrs, routing lookup changes,
[unix-history] / usr / src / sys / tahoe / if / if_ex.c
CommitLineData
19df187f
KS
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Excelan 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 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * @(#)if_ex.c 7.1 (Berkeley) %G%
21 */
22
23#include "ex.h"
24
25#if NEX > 0
26
27/*
28 * Excelan EXOS 202(VME) & 203(QBUS) Link Level Ethernet Interface Drivers
29 */
30#include "param.h"
31#include "systm.h"
32#include "mbuf.h"
33#include "buf.h"
34#include "protosw.h"
35#include "socket.h"
36#include "vmmac.h"
37#include "ioctl.h"
38#include "errno.h"
39#include "vmparam.h"
40#include "syslog.h"
41#include "uio.h"
42
43#include "../net/if.h"
44#include "../net/netisr.h"
45#include "../net/route.h"
46
47#ifdef INET
48#include "../netinet/in.h"
49#include "../netinet/in_systm.h"
50#include "../netinet/in_var.h"
51#include "../netinet/ip.h"
52#include "../netinet/if_ether.h"
53#endif
54
55#ifdef NS
56#include "../netns/ns.h"
57#include "../netns/ns_if.h"
58#endif
59
60#include "../tahoe/cpu.h"
61#include "../tahoe/pte.h"
62#include "../tahoe/mtpr.h"
63
64#include "../tahoevba/vbavar.h"
65#include "if_exreg.h"
66#include "if_vba.h"
67
68
69#define NH2X 32 /* Host to eXcelan request buffers */
70
71#define NX2H 16 /* eXcelan to Host reply buffers */
72#define NREC 16 /* Number of RECeive buffers */
73#define NTRB 4 /* Number of TRansmit Buffers */
74#define NVBI (NREC + NTRB)
75
76#define EXWATCHINTVL 10 /* call exwatch every x secs */
77
78int exprobe(), exslave(), exattach(), exintr(), exstart();
79struct vba_device *exinfo[NEX];
80
81long exstd[] = { 0 };
82
83
84struct vba_driver exdriver =
85 { exprobe, 0, exattach, exstart, exstd, "ex", exinfo };
86int exinit(),ether_output(),exioctl(),exreset(),exwatch();
87struct ex_msg *exgetcbuf();
88int ex_ncall = 0; /* counts calls to exprobe */
89u_long busoff;
90
91/*
92 * Ethernet software status per interface.
93 *
94 * Each interface is referenced by a network interface structure, xs_if, which
95 * the routing code uses to locate the interface. This structure contains the
96 * output queue for the interface, its address, ... NOTE: To configure multiple
97 * controllers, the sizeof this structure must be a multiple of 16 (xs_h2xhdr).
98 */
99struct ex_softc {
100 struct arpcom xs_ac; /* Ethernet common part */
101#define xs_if xs_ac.ac_if /* network-visible interface */
102#define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */
103 int xs_flags; /* private flags */
104#define EX_XPENDING 1 /* xmit rqst pending on EXOS */
105#define EX_STATPENDING (1<<1) /* stats rqst pending on EXOS */
106#define EX_RUNNING (1<<2) /* board is running */
107#define EX_SETADDR (1<<3) /* physaddr has been changed */
108 int xs_cvec; /* probe stores cvec here */
109 short xs_enetunit; /* unit number for enet filtering */
110 short xs_enetinit; /* enet inetrface is initialized */
111 struct ex_msg *xs_h2xnext; /* host pointer to request queue */
112 struct ex_msg *xs_x2hnext; /* host pointer to reply queue */
113 u_long xs_qbaddr; /* map info for structs below */
114 /* the following structures are always mapped in */
115 u_short xs_h2xhdr; /* EXOS's request queue header */
116 u_short xs_x2hhdr; /* EXOS's reply queue header */
117 struct ex_msg xs_h2xent[NH2X];/* request msg buffers */
118 struct ex_msg xs_x2hent[NX2H];/* reply msg buffers */
119 struct confmsg xs_cm; /* configuration message */
120 struct stat_array xs_xsa; /* EXOS writes stats here */
121 /* end mapped area */
122#define BUSADDR(x) ((0x3D000000 | ((u_long)(kvtophys(x))&0xFFFFFF)) + busoff)
123#define P_BUSADDR(x) ((0x3D000000 | ((u_long)(kvtophys(x))&0xFFFFF0)) + busoff)
124#define INCORE_BASE(p) (((u_long)(&(p)->xs_h2xhdr)) & 0xFFFFFFF0)
125#define RVAL_OFF(n) ((u_long)(&(ex_softc[0].n)) - INCORE_BASE(&ex_softc[0]))
126#define LVAL_OFF(n) ((u_long)(ex_softc[0].n) - INCORE_BASE(&ex_softc[0]))
127#define H2XHDR_OFFSET RVAL_OFF(xs_h2xhdr)
128#define X2HHDR_OFFSET RVAL_OFF(xs_x2hhdr)
129#define H2XENT_OFFSET LVAL_OFF(xs_h2xent)
130#define X2HENT_OFFSET LVAL_OFF(xs_x2hent)
131#define CM_OFFSET RVAL_OFF(xs_cm)
132#define SA_OFFSET RVAL_OFF(xs_xsa)
133#define FreePkBuf(b) (((b)->iff_mbuf = (struct mbuf *)xs->xs_pkblist),\
134 (xs->xs_pkblist = b))
135 struct ifvba xs_vbinfo[NVBI];/* Bus Resources (low core) */
136 struct ifvba *xs_pkblist; /* free list of above */
137 char xs_nrec; /* number of pending receive buffers */
138 char xs_ntrb; /* number of pending transmit buffers */
139 char pad[6]; /* make BUSADDR macros */
140} ex_softc[NEX];
141
142int ex_padcheck = sizeof (struct ex_softc);
143
144exprobe(reg, vi)
145 caddr_t reg;
146 struct vba_device *vi;
147{
148 register br, cvec; /* r12, r11 value-result */
149 register struct exdevice *exaddr = (struct exdevice *)reg;
150 int i;
151
152 if (badaddr(exaddr, 2))
153 return 0;
154 /*
155 * Reset EXOS and run self-test (should complete within 2 seconds).
156 */
157 movow(&exaddr->ex_porta, EX_RESET);
158 for (i = 1000000; i; i--) {
159 uncache(&(exaddr->ex_portb));
160 if (exaddr->ex_portb & EX_TESTOK)
161 break;
162 }
163 if ((exaddr->ex_portb & EX_TESTOK) == 0)
164 return 0;
165 br = 0x15;
166 cvec = --vi->ui_hd->vh_lastiv;
167 ex_softc[vi->ui_unit].xs_cvec = cvec;
168 ex_ncall++;
169 return (sizeof(struct exdevice));
170}
171
172/*
173 * Interface exists: make available by filling in network interface record.
174 * System will initialize the interface when it is ready to accept packets.
175 * A NET_ADDRS command is done to get the ethernet address.
176 */
177exattach(ui)
178 register struct vba_device *ui;
179{
180 register struct ex_softc *xs = &ex_softc[ui->ui_unit];
181 register struct ifnet *ifp = &xs->xs_if;
182 register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
183 register struct ex_msg *bp;
184
185 ifp->if_unit = ui->ui_unit;
186 ifp->if_name = "ex";
187 ifp->if_mtu = ETHERMTU;
188 ifp->if_init = exinit;
189 ifp->if_ioctl = exioctl;
190 ifp->if_output = ether_output;
191 ifp->if_reset = exreset;
192 ifp->if_start = exstart;
193
194 if (if_vbareserve(xs->xs_vbinfo, NVBI, EXMAXRBUF) == 0)
195 return;
196 /*
197 * Temporarily map queues in order to configure EXOS
198 */
199 xs->xs_qbaddr = INCORE_BASE(xs);
200 exconfig(ui, 0); /* without interrupts */
201 if (xs->xs_cm.cm_cc)
202 return; /* bad conf */
203 /*
204 * Get Ethernet address.
205 */
206 if ((bp = exgetcbuf(xs, LLNET_ADDRS)) == (struct ex_msg *)0)
207 panic("exattach");
208 bp->mb_na.na_mask = READ_OBJ;
209 bp->mb_na.na_slot = PHYSSLOT;
210 bp->mb_status |= MH_EXOS;
211 movow(&exaddr->ex_portb, EX_NTRUPT);
212 bp = xs->xs_x2hnext;
213 do {
214 uncache(&bp->mb_status);
215 } while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
216 printf("ex%d: HW %c.%c NX %c.%c, hardware address %s\n",
217 ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3],
218 xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1],
219 ether_sprintf(bp->mb_na.na_addrs));
220 bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr,
221 sizeof(xs->xs_addr));
222 if_attach(ifp);
223}
224
225/*
226 * Reset of interface after BUS reset.
227 * If interface is on specified vba, reset its state.
228 */
229exreset(unit)
230int unit;
231{
232 register struct vba_device *ui;
233
234 if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0)
235 return;
236 printf(" ex%d", unit);
237 ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING;
238 ex_softc[unit].xs_flags &= ~EX_RUNNING;
239
240 exinit(unit);
241}
242
243/*
244 * Initialization of interface; clear recorded pending operations, and
245 * reinitialize BUS usage. Called at boot time, and at ifconfig time via
246 * exioctl, with interrupts disabled.
247 */
248exinit(unit)
249int unit;
250{
251 register struct ex_softc *xs = &ex_softc[unit];
252 register struct vba_device *ui = exinfo[unit];
253 register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
254 register struct ifnet *ifp = &xs->xs_if;
255 register struct sockaddr_in *sin;
256 register struct ex_msg *bp;
257 int s;
258
259 /* not yet, if address still unknown */
260 if (ifp->if_addrlist == (struct ifaddr *)0)
261 return;
262 if (xs->xs_flags & EX_RUNNING)
263 return;
264
265 xs->xs_qbaddr = INCORE_BASE(xs);
266 exconfig(ui, 4); /* with vectored interrupts*/
267
268 /*
269 * Put EXOS on the Ethernet, using NET_MODE command
270 */
271 if ((bp = exgetcbuf(xs, LLNET_MODE)) == (struct ex_msg *)0)
272 panic("exinit");
273 bp->mb_nm.nm_mask = WRITE_OBJ;
274 bp->mb_nm.nm_optn = 0;
275 bp->mb_nm.nm_mode = MODE_PERF;
276 bp->mb_status |= MH_EXOS;
277 movow(&exaddr->ex_portb, EX_NTRUPT);
278 bp = xs->xs_x2hnext;
279 do {
280 uncache(&bp->mb_status);
281 } while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
282 bp->mb_length = MBDATALEN;
283 bp->mb_status |= MH_EXOS; /* free up buffer */
284 movow(&exaddr->ex_portb, EX_NTRUPT);
285 xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
286
287 ifp->if_watchdog = exwatch;
288 ifp->if_timer = EXWATCHINTVL;
289 s = splimp(); /* are interrupts disabled here, anyway? */
290 exhangrcv(unit);
291 xs->xs_if.if_flags |= IFF_RUNNING;
292 xs->xs_flags |= EX_RUNNING;
293 if (xs->xs_flags & EX_SETADDR)
294 ex_setaddr((u_char *)0, unit);
295 exstart(&ex_softc[unit].xs_if); /* start transmits */
296 splx(s); /* are interrupts disabled here, anyway? */
297}
298
299/*
300 * Reset, test, and configure EXOS. It is called by exinit, and exattach.
301 * Returns 0 if successful, 1 if self-test failed.
302 */
303exconfig(ui, itype)
304struct vba_device *ui;
305int itype;
306{
307 register int unit = ui->ui_unit;
308 register struct ex_softc *xs = &ex_softc[unit];
309 register struct exdevice *exaddr = (struct exdevice *) ui->ui_addr;
310 register struct confmsg *cm = &xs->xs_cm;
311 register struct ex_msg *bp;
312 register struct ifvba *pkb;
313 int i;
314 u_long shiftreg;
315 static u_char cmaddr[8] = {0xFF, 0xFF, 0, 0};
316
317 xs->xs_flags = 0;
318 /*
319 * Reset EXOS, wait for self-test to complete
320 */
321 movow(&exaddr->ex_porta, EX_RESET);
322 do {
323 uncache(&exaddr->ex_portb);
324 } while ((exaddr->ex_portb & EX_TESTOK) == 0) ;
325 /*
326 * Set up configuration message.
327 */
328 cm->cm_1rsrv = 1;
329 cm->cm_cc = 0xFF;
330 cm->cm_opmode = 0; /* link-level controller mode */
331 cm->cm_dfo = 0x0101; /* enable host data order conversion */
332 cm->cm_dcn1 = 1;
333 cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0;
334 cm->cm_ham = 3; /* absolute address mode */
335 cm->cm_3rsrv = 0;
336 cm->cm_mapsiz = 0;
337 cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */
338 cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */
339 cm->cm_byteptrn[2] = 0x07;
340 cm->cm_byteptrn[3] = 0x0F;
341 cm->cm_wordptrn[0] = 0x0103;
342 cm->cm_wordptrn[1] = 0x070F;
343 cm->cm_lwordptrn = 0x0103070F;
344 for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0;
345 cm->cm_mba = 0xFFFFFFFF;
346 cm->cm_nproc = 0xFF;
347 cm->cm_nmbox = 0xFF;
348 cm->cm_nmcast = 0xFF;
349 cm->cm_nhost = 1;
350 cm->cm_h2xba = P_BUSADDR(xs->xs_qbaddr);
351 cm->cm_h2xhdr = H2XHDR_OFFSET;
352 cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */
353 cm->cm_x2hba = cm->cm_h2xba;
354 cm->cm_x2hhdr = X2HHDR_OFFSET;
355 cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */
356 cm->cm_x2haddr = xs->xs_cvec; /* ivec allocated in exprobe */
357 /*
358 * Set up message queues and headers.
359 * First the request queue
360 */
361 for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) {
362 bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
363 bp->mb_rsrv = 0;
364 bp->mb_length = MBDATALEN;
365 bp->mb_status = MH_HOST;
366 bp->mb_next = bp+1;
367 }
368 xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET;
369 xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent;
370
371 /* Now the reply queue. */
372 for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) {
373 bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
374 bp->mb_rsrv = 0;
375 bp->mb_length = MBDATALEN;
376 bp->mb_status = MH_EXOS;
377 bp->mb_next = bp+1;
378 }
379 xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET;
380 xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent;
381 xs->xs_nrec = 0;
382 xs->xs_ntrb = 0;
383 xs->xs_pkblist = xs->xs_vbinfo + NVBI - 1;
384 for (pkb = xs->xs_pkblist; pkb >= xs->xs_vbinfo; pkb--)
385 pkb->iff_mbuf = (struct mbuf *)(pkb - 1);
386 xs->xs_vbinfo[0].iff_mbuf = 0;
387
388 /*
389 * Write config msg address to EXOS and wait for configuration to
390 * complete (guaranteed response within 2 seconds).
391 */
392 shiftreg = P_BUSADDR(xs->xs_qbaddr) + CM_OFFSET;
393 for (i = 4; i < 8; i++) {
394 cmaddr[i] = (u_char)(shiftreg & 0xFF);
395 shiftreg >>= 8;
396 }
397 for (i = 0; i < 8; i++) {
398 do {
399 uncache(&exaddr->ex_portb);
400 } while (exaddr->ex_portb & EX_UNREADY) ;
401 DELAY(500);
402 movow(&exaddr->ex_portb, cmaddr[i]);
403 }
404 for (i = 500000; i; --i) {
405 DELAY(10);
406 uncache(&cm->cm_cc);
407 if (cm->cm_cc != 0xFF)
408 break;
409 }
410 if (cm->cm_cc)
411 printf("ex%d: configuration failed; cc=%x\n", unit, cm->cm_cc);
412}
413
414/*
415 * Start or re-start output on interface. Get another datagram to send off of
416 * the interface queue, and map it to the interface before starting the output.
417 * This routine is called by exinit(), exoutput(), and excdint(). In all cases,
418 * interrupts by EXOS are disabled.
419 */
420exstart(ifp)
421struct ifnet *ifp;
422{
423 int unit = ifp->if_unit;
424 struct vba_device *ui = exinfo[unit];
425 register struct ex_softc *xs = &ex_softc[unit];
426 struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
427 register struct ex_msg *bp;
428 register struct mbuf *m;
429 int len;
430 register struct ifvba *pkb;
431 struct mbuf *m0;
432 register int nb, tlen;
433 union l_util {
434 u_long l;
435 struct i86_long i;
436 } l_util;
437
438 if (xs->xs_ntrb >= NTRB)
439 return;
440 if (xs->xs_pkblist == 0) {
441 printf("ex%d: vbinfo exhausted, would panic", unit);
442 return;
443 }
444 IF_DEQUEUE(&xs->xs_if.if_snd, m);
445 if (m == 0)
446 return;
447 /*
448 * Get a transmit request.
449 */
450 if ((bp = exgetcbuf(xs, LLRTRANSMIT)) == (struct ex_msg *)0) {
451 m_freem(m);
452 printf("exstart: no command buffers\n");
453 return;
454 }
455 xs->xs_ntrb++;
456 bp->mb_pkb = pkb = xs->xs_pkblist;
457 xs->xs_pkblist = (struct ifvba *)pkb->iff_mbuf;
458 nb = 0; tlen = 0; m0 = 0;
459 pkb->iff_mbuf = m; /* save mbuf pointer to free when done */
460 /*
461 * point directly to the first group of mbufs to be transmitted. The
462 * hardware can only support NFRAGMENTS descriptors.
463 */
464 while (m && ((nb < NFRAGMENTS-1) || (m->m_next == 0)) ) {
465 l_util.l = BUSADDR(mtod(m, char *));
466 bp->mb_et.et_blks[nb].bb_len = (u_short)m->m_len;
467 bp->mb_et.et_blks[nb].bb_addr = l_util.i;
468 tlen += m->m_len;
469 m0 = m;
470 m = m->m_next;
471 nb++;
472 }
473
474 /* 0 end of chain pointed to by iff_mbuf, to be freed when xmit done */
475 if (m0)
476 m0->m_next = 0;
477
478 /*
479 * if not all of the descriptors would fit then merge remaining data
480 * into the transmit buffer, and point to it. Note: the mbufs are freed
481 * during the merge, they do not have to be freed when we get the
482 * transmit interrupt.
483 */
484 if (m) {
485 len = if_vbaput(pkb->iff_buffer, m);
486 l_util.l = BUSADDR(pkb->iff_buffer);
487 bp->mb_et.et_blks[nb].bb_len = (u_short)len;
488 bp->mb_et.et_blks[nb].bb_addr = l_util.i;
489 tlen += len;
490 nb++;
491 }
492
493 /*
494 * If the total length of the packet is too small, pad the last frag
495 */
496 if (tlen - sizeof(struct ether_header) < ETHERMIN) {
497 len = (ETHERMIN + sizeof(struct ether_header)) - tlen;
498 bp->mb_et.et_blks[nb-1].bb_len += (u_short)len;
499 tlen += len;
500 }
501
502 /* set number of fragments in descriptor */
503 bp->mb_et.et_nblock = nb;
504 bp->mb_status |= MH_EXOS;
505 movow(&exaddr->ex_portb, EX_NTRUPT);
506}
507
508/*
509 * interrupt service routine.
510 */
511exintr(unit)
512 int unit;
513{
514 register struct ex_softc *xs = &ex_softc[unit];
515 register struct ex_msg *bp = xs->xs_x2hnext;
516 struct vba_device *ui = exinfo[unit];
517 struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;
518
519 uncache(&bp->mb_status);
520 while ((bp->mb_status & MH_OWNER) == MH_HOST) {
521 switch (bp->mb_rqst) {
522 case LLRECEIVE:
523 if (--xs->xs_nrec < 0)
524 xs->xs_nrec = 0;
525 exrecv(unit, bp);
526 FreePkBuf(bp->mb_pkb);
527 bp->mb_pkb = (struct ifvba *)0;
528 exhangrcv(unit);
529 break;
530
531 case LLTRANSMIT:
532 case LLRTRANSMIT:
533 if (--xs->xs_ntrb < 0)
534 xs->xs_ntrb = 0;
535 xs->xs_if.if_opackets++;
536 if (bp->mb_rply == LL_OK)
537 ;
538 else if (bp->mb_rply & LLXM_1RTRY)
539 xs->xs_if.if_collisions++;
540 else if (bp->mb_rply & LLXM_RTRYS)
541 xs->xs_if.if_collisions += 2; /* guess */
542 else if (bp->mb_rply & LLXM_ERROR)
543 if (xs->xs_if.if_oerrors++ % 100 == 0)
544 printf("ex%d: 100 transmit errors=%b\n",
545 unit, bp->mb_rply, XMIT_BITS);
546 if (bp->mb_pkb->iff_mbuf) {
547 m_freem(bp->mb_pkb->iff_mbuf);
548 bp->mb_pkb->iff_mbuf = (struct mbuf *)0;
549 }
550 FreePkBuf(bp->mb_pkb);
551 bp->mb_pkb = (struct ifvba *)0;
552 exstart(&ex_softc[unit].xs_if);
553 exhangrcv(unit);
554 break;
555
556 case LLNET_STSTCS:
557 xs->xs_if.if_ierrors += xs->xs_xsa.sa_crc;
558 xs->xs_flags &= ~EX_STATPENDING;
559 break;
560
561 default:
562 printf("ex%d: unknown reply 0x%x", unit, bp->mb_rqst);
563 }
564 bp->mb_length = MBDATALEN;
565 bp->mb_status |= MH_EXOS; /* free up buffer */
566 movow(&exaddr->ex_portb, EX_NTRUPT); /* tell EXOS about it */
567 bp = bp->mb_next;
568 uncache(&bp->mb_status);
569 }
570 xs->xs_x2hnext = bp;
571}
572
573/*
574 * Get a request buffer, fill in standard values, advance pointer.
575 */
576struct ex_msg *
577exgetcbuf(xs, req)
578struct ex_softc *xs;
579int req;
580{
581 register struct ex_msg *bp;
582 struct ifvba *pkb;
583 int s = splimp();
584
585 bp = xs->xs_h2xnext;
586 uncache(&bp->mb_status);
587 if ((bp->mb_status & MH_OWNER) == MH_EXOS) {
588 splx(s);
589 return (struct ex_msg *)0;
590 }
591 xs->xs_h2xnext = bp->mb_next;
592 bp->mb_1rsrv = 0;
593 bp->mb_rqst = req;
594 bp->mb_length = MBDATALEN;
595 bp->mb_pkb = (struct ifvba *)0;
596 splx(s);
597 return bp;
598}
599
600/*
601 * Process Ethernet receive completion: If input error just drop packet,
602 * otherwise examine packet to determine type. If can't determine length from
603 * type, then have to drop packet, otherwise decapsulate packet based on type
604 * and pass to type-specific higher-level input routine.
605 */
606exrecv(unit, bp)
607int unit;
608register struct ex_msg *bp;
609{
610 register struct ex_softc *xs = &ex_softc[unit];
611 register struct ether_header *eh;
612 register struct mbuf *m;
613 int len, off, resid;
614 register struct ifqueue *inq;
615 int s;
616
617 xs->xs_if.if_ipackets++;
618 /* total length - header - crc */
619 len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4;
620 if (bp->mb_rply != LL_OK) {
621 if (xs->xs_if.if_ierrors++ % 100 == 0)
622 printf("ex%d: 100 receive errors=%b\n",
623 unit, bp->mb_rply, RECV_BITS);
624 return;
625 }
626 eh = (struct ether_header *)(bp->mb_pkb->iff_buffer);
627
628 /*
629 * Deal with trailer protocol: if type is PUP trailer get true type from
630 * first 16-bit word past data. Remember that type was trailer by
631 * setting off.
632 */
633 eh->ether_type = ntohs((u_short)eh->ether_type);
634#define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
635 if (eh->ether_type >= ETHERTYPE_TRAIL &&
636 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
637 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
638 if (off >= ETHERMTU)
639 return; /* sanity */
640 eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *));
641 resid = ntohs(*(exdataaddr(eh, off+2, u_short *)));
642 if (off + resid > len)
643 return; /* sanity */
644 len = off + resid;
645 } else
646 off = 0;
647 if (len == 0)
648 return;
649 /*
650 * Pull packet off interface. Off is nonzero if packet
651 * has trailing header; if_vbaget will then force this header
652 * information to be at the front, but we still have to drop
653 * the type and length which are at the front of any trailer data.
654 */
655 m = if_vbaget(bp->mb_pkb->iff_buffer, len, off, &xs->xs_if, 0);
656 if (m == 0)
657 return;
658 ether_input(&xs->xs_if, eh, m);
659 return;
660}
661
662/*
663 * Hang a receive request. This routine is called by exinit and excdint,
664 * with interrupts disabled in both cases.
665 */
666exhangrcv(unit)
667 int unit;
668{
669 register struct ex_softc *xs = &ex_softc[unit];
670 register struct ex_msg *bp;
671 register struct ifvba *pkb;
672 short mustint = 0;
673 union l_util {
674 u_long l;
675 struct i86_long i;
676 } l_util;
677
678 while (xs->xs_nrec < NREC) {
679 if (xs->xs_pkblist == (struct ifvba *)0)
680 break;
681 if ((bp = exgetcbuf(xs, LLRECEIVE)) == (struct ex_msg *)0) {
682 break;
683 }
684 pkb = bp->mb_pkb = xs->xs_pkblist;
685 xs->xs_pkblist = (struct ifvba *)bp->mb_pkb->iff_mbuf;
686
687 xs->xs_nrec += 1;
688 bp->mb_er.er_nblock = 1;
689 bp->mb_er.er_blks[0].bb_len = EXMAXRBUF;
690 l_util.l = BUSADDR(pkb->iff_buffer);
691 bp->mb_er.er_blks[0].bb_addr = l_util.i;
692 bp->mb_status |= MH_EXOS;
693 mustint = 1;
694 }
695 if (mustint == 0)
696 return;
697 movow(&((struct exdevice *)exinfo[unit]->ui_addr)->ex_portb, EX_NTRUPT);
698}
699
700/*
701 * Ethernet output routine is ether_output().
702 */
703
704/*
705 * Watchdog routine (currently not used). Might use this to get stats from EXOS.
706 */
707exwatch(unit)
708int unit;
709{
710 struct exdevice *exaddr = (struct exdevice *)exinfo[unit]->ui_addr;
711 register struct ex_softc *xs = &ex_softc[unit];
712 register struct ex_msg *bp;
713 int s = splimp();
714
715 if (xs->xs_flags & EX_STATPENDING)
716 goto exspnd;
717 if ((bp = exgetcbuf(xs, LLNET_STSTCS)) == (struct ex_msg *)0) {
718 splx(s);
719 return;
720 }
721 xs->xs_flags |= EX_STATPENDING;
722 bp->mb_ns.ns_mask = READ_OBJ;
723 bp->mb_ns.ns_rsrv = 0;
724 bp->mb_ns.ns_nobj = 8;
725 bp->mb_ns.ns_xobj = 0;
726 bp->mb_ns.ns_bufp = P_BUSADDR(xs->xs_qbaddr) + SA_OFFSET;
727 bp->mb_status |= MH_EXOS;
728 movow(&exaddr->ex_portb, EX_NTRUPT);
729exspnd: splx(s);
730 xs->xs_if.if_timer = EXWATCHINTVL;
731}
732
733/*
734 * Process an ioctl request.
735 */
736exioctl(ifp, cmd, data)
737 register struct ifnet *ifp;
738 int cmd;
739 caddr_t data;
740{
741 register struct ifaddr *ifa = (struct ifaddr *)data;
742 register struct ex_softc *xs = &ex_softc[ifp->if_unit];
743 int s = splimp(), error = 0;
744
745 switch (cmd) {
746
747 case SIOCSIFADDR:
748 ifp->if_flags |= IFF_UP;
749 exinit(ifp->if_unit);
750
751 switch (ifa->ifa_addr->sa_family) {
752#ifdef INET
753 case AF_INET:
754 ((struct arpcom *)ifp)->ac_ipaddr =
755 IA_SIN(ifa)->sin_addr;
756 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
757 break;
758#endif
759#ifdef NS
760 case AF_NS:
761 {
762 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
763
764 if (ns_nullhost(*ina))
765 ina->x_host = *(union ns_host *)(xs->xs_addr);
766 else
767 ex_setaddr(ina->x_host.c_host,ifp->if_unit);
768 break;
769 }
770#endif
771 }
772 break;
773
774 case SIOCSIFFLAGS:
775 if ((ifp->if_flags & IFF_UP) == 0 &&
776 xs->xs_flags & EX_RUNNING) {
777 movow(&((struct exdevice *)
778 (exinfo[ifp->if_unit]->ui_addr))->ex_porta, EX_RESET);
779 xs->xs_flags &= ~EX_RUNNING;
780 } else if (ifp->if_flags & IFF_UP &&
781 (xs->xs_flags & EX_RUNNING) == 0)
782 exinit(ifp->if_unit);
783 break;
784
785 default:
786 error = EINVAL;
787 }
788 splx(s);
789 return (error);
790}
791
792/*
793 * set ethernet address for unit
794 */
795ex_setaddr(physaddr, unit)
796 u_char *physaddr;
797 int unit;
798{
799 register struct ex_softc *xs = &ex_softc[unit];
800 struct vba_device *ui = exinfo[unit];
801 register struct exdevice *addr= (struct exdevice *)ui->ui_addr;
802 register struct ex_msg *bp;
803
804 if (physaddr) {
805 xs->xs_flags |= EX_SETADDR;
806 bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6);
807 }
808 if (! (xs->xs_flags & EX_RUNNING))
809 return;
810 bp = exgetcbuf(xs);
811 bp->mb_rqst = LLNET_ADDRS;
812 bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ;
813 bp->mb_na.na_slot = PHYSSLOT;
814 bcopy((caddr_t)xs->xs_addr, (caddr_t)bp->mb_na.na_addrs, 6);
815 bp->mb_status |= MH_EXOS;
816 movow(&addr->ex_portb, EX_NTRUPT);
817 bp = xs->xs_x2hnext;
818 do {
819 uncache(&bp->mb_status);
820 } while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
821#ifdef DEBUG
822 log(LOG_DEBUG, "ex%d: reset addr %s\n", ui->ui_unit,
823 ether_sprintf(bp->mb_na.na_addrs));
824#endif
825 /*
826 * Now, re-enable reception on phys slot.
827 */
828 bp = exgetcbuf(xs);
829 bp->mb_rqst = LLNET_RECV;
830 bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ;
831 bp->mb_nr.nr_slot = PHYSSLOT;
832 bp->mb_status |= MH_EXOS;
833 movow(&addr->ex_portb, EX_NTRUPT);
834 bp = xs->xs_x2hnext;
835 do {
836 uncache(&bp->mb_status);
837 } while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */
838 ;
839}
840#endif