Latest fixes from Nesheim@cornell
[unix-history] / usr / src / sys / vax / if / if_ex.c
CommitLineData
da7c5cc6
KM
1/*
2 * Copyright (c) 1982 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
6 * @(#)if_ex.c 6.3 (Berkeley) %G%
7 */
8
063e82dc
MK
9
10#include "ex.h"
11
12/*
13 * Excelan EXOS 204 Interface
14 *
15 * George Powers
16 * Excelan Inc.
17 */
18
19#include "../machine/pte.h"
20
1a568327
MK
21#include "param.h"
22#include "systm.h"
23#include "mbuf.h"
24#include "buf.h"
25#include "protosw.h"
26#include "socket.h"
27#include "vmmac.h"
28#include "ioctl.h"
29#include "errno.h"
063e82dc
MK
30
31#include "../net/if.h"
32#include "../net/netisr.h"
33#include "../net/route.h"
34#include "../netinet/in.h"
35#include "../netinet/in_systm.h"
1a568327 36#include "../netinet/in_var.h"
063e82dc
MK
37#include "../netinet/ip.h"
38#include "../netinet/ip_var.h"
39#include "../netinet/if_ether.h"
1a568327 40#ifdef PUP
063e82dc 41#include "../netpup/pup.h"
1a568327 42#endif
063e82dc
MK
43
44#include "../vax/cpu.h"
45#include "../vax/mtpr.h"
1a568327
MK
46#include "if_exreg.h"
47#include "if_uba.h"
063e82dc
MK
48#include "../vaxuba/ubareg.h"
49#include "../vaxuba/ubavar.h"
50
51#define DEBUG /* check for "impossible" events */
52
53#define NH2X 4 /* a sufficient number is critical */
54#define NX2H 4 /* this is pretty arbitrary */
55#define EXWATCHINTVL 10 /* call exwatch() every 10 seconds */
56
57int exprobe(), exattach(), excdint();
58struct uba_device *exinfo[NEX];
59u_short exstd[] = { 0 };
60struct uba_driver exdriver =
61 { exprobe, 0, exattach, 0, exstd, "ex", exinfo };
62int exinit(),exoutput(),exioctl(),exreset(),exwatch();
63struct ex_msg *exgetcbuf();
64
65/*
66 * Ethernet software status per interface.
67 *
68 * Each interface is referenced by a network interface structure,
69 * xs_if, which the routing code uses to locate the interface.
70 * This structure contains the output queue for the interface, its address, ...
71 * We also have, for each interface, a UBA interface structure, which
72 * contains information about the UNIBUS resources held by the interface:
73 * map registers, buffered data paths, etc. Information is cached in this
74 * structure for use by the if_uba.c routines in running the interface
75 * efficiently.
76 */
77struct ex_softc {
063e82dc
MK
78 struct arpcom xs_ac; /* Ethernet common part */
79#define xs_if xs_ac.ac_if /* network-visible interface */
80#define xs_addr xs_ac.ac_enaddr /* hardware Ethernet address */
1a568327
MK
81#ifdef DEBUG
82 int xs_wait;
83#endif
063e82dc
MK
84 struct ifuba xs_ifuba; /* UNIBUS resources */
85 int xs_flags; /* private flags */
86#define EX_XPENDING 1 /* xmit rqst pending on EXOS */
87#define EX_STATPENDING (1<<1) /* stats rqst pending on EXOS */
88 struct ex_msg *xs_h2xnext; /* host pointer to request queue */
89 struct ex_msg *xs_x2hnext; /* host pointer to reply queue */
90 u_long xs_ubaddr; /* map info for structs below */
91#define UNIADDR(x) ((u_long)(x)&0x3FFFF)
92#define P_UNIADDR(x) ((u_long)(x)&0x3FFF0)
93 /* the following structures are always mapped in */
94 u_short xs_h2xhdr; /* EXOS's request queue header */
95 u_short xs_x2hhdr; /* EXOS's reply queue header */
96 struct ex_msg xs_h2xent[NH2X]; /* request msg buffers */
97 struct ex_msg xs_x2hent[NX2H]; /* reply msg buffers */
98 struct confmsg xs_cm; /* configuration message */
99 struct stat_array xs_xsa; /* EXOS writes stats here */
100 /* end mapped area */
101#define INCORE_BASE(p) (((u_long)(&(p)->xs_h2xhdr)) & 0xFFFFFFF0)
102#define RVAL_OFF(n) ((u_long)(&(ex_softc[0].n)) - INCORE_BASE(&ex_softc[0]))
103#define LVAL_OFF(n) ((u_long)(ex_softc[0].n) - INCORE_BASE(&ex_softc[0]))
104#define H2XHDR_OFFSET RVAL_OFF(xs_h2xhdr)
105#define X2HHDR_OFFSET RVAL_OFF(xs_x2hhdr)
106#define H2XENT_OFFSET LVAL_OFF(xs_h2xent)
107#define X2HENT_OFFSET LVAL_OFF(xs_x2hent)
108#define CM_OFFSET RVAL_OFF(xs_cm)
109#define SA_OFFSET RVAL_OFF(xs_xsa)
110#define INCORE_SIZE RVAL_OFF(xs_end)
111 int xs_end; /* place holder */
112} ex_softc[NEX];
113
114/*
115 * The following structure is a kludge to store a cvec value
116 * between the time exprobe is called, and exconfig.
117 */
118struct ex_cvecs {
119 struct exdevice *xc_csraddr;
120 int xc_cvec;
121}ex_cvecs[NEX];
122
123int ex_ncall = 0; /* counts calls to exprobe */
124
125exprobe(reg)
126 caddr_t reg;
127{
128 register int br, cvec; /* r11, r10 value-result */
129 register struct exdevice *addr = (struct exdevice *)reg;
130 register i;
131
132 /*
133 * We program the EXOS interrupt vector, like dmf device.
134 */
135 br = 0x15;
136 cvec = (uba_hd[numuba].uh_lastiv -= 4);
137#ifdef DEBUG
138printf("exprobe%d: cvec = %o\n", ex_ncall, cvec);
139#endif
140 ex_cvecs[ex_ncall].xc_csraddr = addr;
141 ex_cvecs[ex_ncall++].xc_cvec = cvec;
142 /*
143 * Reset EXOS and run self-test (guaranteed to
144 * complete within 2 seconds).
145 */
146 addr->xd_porta = EX_RESET;
147 i = 1000000;
148 while (((addr->xd_portb & EX_TESTOK) == 0) && --i)
149 ;
150 if ((addr->xd_portb & EX_TESTOK) == 0) {
151 printf("ex: self-test failed\n");
152 return 0;
153 }
154 return (sizeof(struct exdevice));
155}
156
157/*
158 * Interface exists: make available by filling in network interface
159 * record. System will initialize the interface when it is ready
160 * to accept packets. Board is temporarily configured and issues
161 * a NET_ADDRS command, only to get the Ethernet address.
162 */
163exattach(ui)
164 struct uba_device *ui;
165{
166 register struct ex_softc *xs = &ex_softc[ui->ui_unit];
167 register struct ifnet *ifp = &xs->xs_if;
168 register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
063e82dc
MK
169 register struct ex_msg *bp;
170
171 ifp->if_unit = ui->ui_unit;
172 ifp->if_name = "ex";
173 ifp->if_mtu = ETHERMTU;
174
175 /*
176 * Temporarily map queues in order to configure EXOS
177 */
178 xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs), INCORE_SIZE, 0);
179 exconfig(ui, 0); /* without interrupts */
180 if (xs->xs_cm.cm_cc) goto badconf;
181
182 bp = exgetcbuf(xs);
183 bp->mb_rqst = LLNET_ADDRS;
184 bp->mb_na.na_mask = READ_OBJ;
185 bp->mb_na.na_slot = PHYSSLOT;
186 bp->mb_status |= MH_EXOS;
187 addr->xd_portb = EX_NTRUPT;
188 bp = xs->xs_x2hnext;
189 while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */
190 ;
191 printf("ex%d: HW %c.%c, NX %c.%c, addr %x.%x.%x.%x.%x.%x\n",
192 ui->ui_unit,
193 xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3],
194 xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1],
195 bp->mb_na.na_addrs[0], bp->mb_na.na_addrs[1],
196 bp->mb_na.na_addrs[2], bp->mb_na.na_addrs[3],
197 bp->mb_na.na_addrs[4], bp->mb_na.na_addrs[5]);
198 bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr,
199 sizeof (xs->xs_addr));
200
063e82dc
MK
201 ifp->if_init = exinit;
202 ifp->if_output = exoutput;
203 ifp->if_ioctl = exioctl;
204 ifp->if_reset = exreset;
1a568327 205 ifp->if_flags = IFF_BROADCAST;
063e82dc
MK
206 xs->xs_ifuba.ifu_flags = UBA_CANTWAIT;
207 if_attach(ifp);
208badconf:
209 ubarelse(ui->ui_ubanum, &xs->xs_ubaddr);
210}
211
212/*
213 * Reset of interface after UNIBUS reset.
214 * If interface is on specified uba, reset its state.
215 */
216exreset(unit, uban)
217 int unit, uban;
218{
219 register struct uba_device *ui;
220
221 if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0 ||
222 ui->ui_ubanum != uban)
223 return;
224 printf(" ex%d", unit);
1a568327 225 ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING;
063e82dc
MK
226 exinit(unit);
227}
228
229/*
230 * Initialization of interface; clear recorded pending
231 * operations, and reinitialize UNIBUS usage.
232 * Called at boot time (with interrupts disabled?),
233 * and at ifconfig time via exioctl, with interrupts disabled.
234 */
235exinit(unit)
236 int unit;
237{
238 register struct ex_softc *xs = &ex_softc[unit];
239 register struct uba_device *ui = exinfo[unit];
240 register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
241 register struct ifnet *ifp = &xs->xs_if;
063e82dc
MK
242 register struct ex_msg *bp;
243 int s;
244
1a568327
MK
245 /* not yet, if address still unknown */
246 if (ifp->if_addrlist == (struct ifaddr *)0)
063e82dc
MK
247 return;
248
249 if (ifp->if_flags & IFF_RUNNING)
1a568327 250 return;
063e82dc
MK
251 if (if_ubainit(&xs->xs_ifuba, ui->ui_ubanum,
252 sizeof (struct ether_header),
253 (int)btoc(EXMAXRBUF-sizeof(struct ether_header))) == 0) {
254 printf("ex%d: can't initialize\n", unit);
255 xs->xs_if.if_flags &= ~IFF_UP;
256 return;
257 }
258 xs->xs_ubaddr = uballoc(ui->ui_ubanum, INCORE_BASE(xs), INCORE_SIZE, 0);
259 exconfig(ui, 4); /* with vectored interrupts*/
260 /*
261 * Put EXOS on the Ethernet, using NET_MODE command
262 */
263 bp = exgetcbuf(xs);
264 bp->mb_rqst = LLNET_MODE;
265 bp->mb_nm.nm_mask = WRITE_OBJ;
266 bp->mb_nm.nm_optn = 0;
267 bp->mb_nm.nm_mode = MODE_PERF;
268 bp->mb_status |= MH_EXOS;
269 addr->xd_portb = EX_NTRUPT;
270 bp = xs->xs_x2hnext;
271 while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */
272 ;
273 bp->mb_length = MBDATALEN;
274 bp->mb_status |= MH_EXOS; /* free up buffer */
275 addr->xd_portb = EX_NTRUPT; /* tell EXOS about it */
276 xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
277
278 ifp->if_watchdog = exwatch;
279 ifp->if_timer = EXWATCHINTVL;
280 s = splimp(); /* are interrupts always disabled here, anyway? */
281 exhangrcv(unit); /* hang receive request */
282 exstart(unit); /* start transmits */
1a568327 283 xs->xs_if.if_flags |= IFF_RUNNING;
063e82dc 284 splx(s);
063e82dc
MK
285}
286
287/*
288 * Reset, test, and configure EXOS. This routine assumes
289 * that message queues, etc. have already been mapped into
290 * the UBA. It is called by exinit, and should also be
291 * callable by exattach.
292 */
293exconfig(ui, itype)
294 struct uba_device *ui;
295 int itype;
296{
297 register int unit = ui->ui_unit;
298 register struct ex_softc *xs = &ex_softc[unit];
299 register struct exdevice *addr = (struct exdevice *) ui->ui_addr;
300 register struct confmsg *cm = &xs->xs_cm;
301 register struct ex_msg *bp;
302 int i;
303 u_long shiftreg;
304
305 xs->xs_flags = 0;
306 /*
307 * Reset EXOS, wait for self-test to complete
308 */
309 addr->xd_porta = EX_RESET;
310 while ((addr->xd_portb & EX_TESTOK) == 0)
311 ;
312 /*
313 * Set up configuration message.
314 */
315 cm->cm_1rsrv = 1;
316 cm->cm_cc = 0xFF;
317 cm->cm_opmode = 0; /* link-level controller mode */
318 cm->cm_dfo = 0x0101; /* enable host data order conversion */
319 cm->cm_dcn1 = 1;
320 cm->cm_2rsrv[0] =
321 cm->cm_2rsrv[1] = 0;
322 cm->cm_ham = 3; /* absolute address mode */
323 cm->cm_3rsrv = 0;
324 cm->cm_mapsiz = 0;
325 cm->cm_byteptrn[0] = 0x01; /* EXOS deduces data order of host */
326 cm->cm_byteptrn[1] = 0x03; /* by looking at this pattern */
327 cm->cm_byteptrn[2] = 0x07;
328 cm->cm_byteptrn[3] = 0x0F;
329 cm->cm_wordptrn[0] = 0x0103;
330 cm->cm_wordptrn[1] = 0x070F;
331 cm->cm_lwordptrn = 0x0103070F;
332 for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0;
333 cm->cm_mba = 0xFFFFFFFF;
334 cm->cm_nproc = 0xFF;
335 cm->cm_nmbox = 0xFF;
336 cm->cm_nmcast = 0xFF;
337 cm->cm_nhost = 1;
338 cm->cm_h2xba = P_UNIADDR(xs->xs_ubaddr);
339 cm->cm_h2xhdr = H2XHDR_OFFSET;
340 cm->cm_h2xtyp = 0; /* should never wait for rqst buffer */
341 cm->cm_x2hba = cm->cm_h2xba;
342 cm->cm_x2hhdr = X2HHDR_OFFSET;
343 cm->cm_x2htyp = itype; /* 0 for none, 4 for vectored */
344 for (i=0; (addr != ex_cvecs[i].xc_csraddr); i++)
345#ifdef DEBUG
346 if (i >= NEX)
347 panic("ex: matching csr address not found");
348#endif
349 ;
350 cm->cm_x2haddr = ex_cvecs[i].xc_cvec; /* stashed here by exprobe */
351 /*
352 * Set up message queues and headers.
353 * First the request queue.
354 */
355 for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) {
356 bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
357 bp->mb_rsrv = 0;
358 bp->mb_length = MBDATALEN;
359 bp->mb_status = MH_HOST;
360 bp->mb_next = bp+1;
361 }
362 xs->xs_h2xhdr =
363 xs->xs_h2xent[NH2X-1].mb_link =
364 (u_short)H2XENT_OFFSET;
365 xs->xs_h2xnext =
366 xs->xs_h2xent[NH2X-1].mb_next =
367 xs->xs_h2xent;
368
369 /* Now the reply queue. */
370 for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) {
371 bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));
372 bp->mb_rsrv = 0;
373 bp->mb_length = MBDATALEN;
374 bp->mb_status = MH_EXOS;
375 bp->mb_next = bp+1;
376 }
377 xs->xs_x2hhdr =
378 xs->xs_x2hent[NX2H-1].mb_link =
379 (u_short)X2HENT_OFFSET;
380 xs->xs_x2hnext =
381 xs->xs_x2hent[NX2H-1].mb_next =
382 xs->xs_x2hent;
383
384 /*
385 * Write config msg address to EXOS and wait for
386 * configuration to complete (guaranteed response
387 * within 2 seconds).
388 */
389 shiftreg = (u_long)0x0000FFFF;
390 for (i = 0; i < 8; i++) {
391 if (i == 4)
392 shiftreg = P_UNIADDR(xs->xs_ubaddr) + CM_OFFSET;
393 while (addr->xd_portb & EX_UNREADY)
394 ;
395 addr->xd_portb = (u_char)(shiftreg & 0xFF);
396 shiftreg >>= 8;
397 }
398 for (i = 1000000; (cm->cm_cc == 0xFF) && i; --i);
399 if (cm->cm_cc)
400 printf("ex%d: configuration failed; cc = %x\n",
401 unit, cm->cm_cc);
402}
403
404/*
405 * Start or re-start output on interface.
406 * Get another datagram to send off of the interface queue,
407 * and map it to the interface before starting the output.
408 * This routine is called by exinit(), exoutput(), and excdint().
409 * In all cases, interrupts by EXOS are disabled.
410 */
411exstart(unit)
412 int unit;
413{
414 struct uba_device *ui = exinfo[unit];
415 register struct ex_softc *xs = &ex_softc[unit];
416 register struct exdevice *addr = (struct exdevice *)ui->ui_addr;
417 register struct ex_msg *bp;
418 struct mbuf *m;
419 int len;
420
421#ifdef DEBUG
422 if (xs->xs_flags & EX_XPENDING)
423 panic("exstart(): xmit still pending");
424#endif
425 IF_DEQUEUE(&xs->xs_if.if_snd, m);
426 if (m == 0)
427 return;
428 len = if_wubaput(&xs->xs_ifuba, m);
429 if (len - sizeof(struct ether_header) < ETHERMIN)
430 len = ETHERMIN + sizeof(struct ether_header);
431 /*
432 * Place a transmit request.
433 */
434 bp = exgetcbuf(xs);
435 bp->mb_rqst = LLRTRANSMIT;
436 bp->mb_et.et_nblock = 1;
437 bp->mb_et.et_blks[0].bb_len = (u_short)len;
438 *(u_long *)bp->mb_et.et_blks[0].bb_addr =
439 UNIADDR(xs->xs_ifuba.ifu_w.ifrw_info);
440 xs->xs_flags |= EX_XPENDING;
441 bp->mb_status |= MH_EXOS;
442 addr->xd_portb = EX_NTRUPT;
443}
444
445/*
446 * Command done interrupt.
447 */
448excdint(unit)
449 int unit;
450{
451 register struct ex_softc *xs = &ex_softc[unit];
452 register struct ex_msg *bp = xs->xs_x2hnext;
453 struct uba_device *ui = exinfo[unit];
454 struct exdevice *addr = (struct exdevice *)ui->ui_addr;
455
456 while ((bp->mb_status & MH_OWNER) == MH_HOST) {
457 switch (bp->mb_rqst) {
458 case LLRECEIVE:
459 exrecv(unit, bp);
460 exhangrcv(unit);
461 break;
462 case LLRTRANSMIT:
463#ifdef DEBUG
464 if ((xs->xs_flags & EX_XPENDING) == 0)
465 panic("exxmit: no xmit pending");
466#endif
467 xs->xs_flags &= ~EX_XPENDING;
468 xs->xs_if.if_opackets++;
469 if (bp->mb_rply == LL_OK) {
470 ;
471 } else if (bp->mb_rply & LLXM_1RTRY) {
472 xs->xs_if.if_collisions++;
473 } else if (bp->mb_rply & LLXM_RTRYS) {
474 xs->xs_if.if_collisions += 2; /* guess */
475 } else if (bp->mb_rply & LLXM_ERROR) {
476 xs->xs_if.if_oerrors++;
477 printf("ex%d: transmit error=%b\n",
478 unit, bp->mb_rply, XMIT_BITS);
479 }
480 if (xs->xs_ifuba.ifu_xtofree) {
481 m_freem(xs->xs_ifuba.ifu_xtofree);
482 xs->xs_ifuba.ifu_xtofree = 0;
483 }
484 exstart(unit);
485 break;
486 case LLNET_STSTCS:
487 xs->xs_if.if_ierrors = xs->xs_xsa.sa_crc;
488 xs->xs_flags &= ~EX_STATPENDING;
489 break;
490#ifdef DEBUG
491 default:
492 panic("ex%d: unknown reply");
493#endif
494 } /* end of switch */
495 bp->mb_length = MBDATALEN;
496 bp->mb_status |= MH_EXOS; /* free up buffer */
497 addr->xd_portb = EX_NTRUPT; /* tell EXOS about it */
498 bp = xs->xs_x2hnext = xs->xs_x2hnext->mb_next;
499 }
500}
501
502/*
503 * Get a request buffer, fill in standard values, advance pointer.
504 */
505struct ex_msg *
506exgetcbuf(xs)
507 struct ex_softc *xs;
508{
509 register struct ex_msg *bp = xs->xs_h2xnext;
510
511#ifdef DEBUG
512 if ((bp->mb_status & MH_OWNER) == MH_EXOS)
513 panic("exgetcbuf(): EXOS owns message buffer");
514#endif
515 bp->mb_1rsrv = 0;
516 bp->mb_length = MBDATALEN;
517 xs->xs_h2xnext = xs->xs_h2xnext->mb_next;
518 return bp;
519}
520
521/*
522 * Process Ethernet receive completion:
523 * If input error just drop packet.
524 * Otherwise purge input buffered data path and examine
525 * packet to determine type. If can't determine length
526 * from type, then have to drop packet. Otherwise decapsulate
527 * packet based on type and pass to type-specific higher-level
528 * input routine.
529 */
530exrecv(unit, bp)
531 int unit;
532 register struct ex_msg *bp;
533{
534 register struct ex_softc *xs = &ex_softc[unit];
535 register struct ether_header *eh;
536 struct mbuf *m;
537 register int len, off, resid;
538 register struct ifqueue *inq;
539
540 xs->xs_if.if_ipackets++;
541 len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4;
542 if (bp->mb_rply != LL_OK) {
543 xs->xs_if.if_ierrors++;
544 printf("ex%d: receive error=%b\n",
545 unit, bp->mb_rply, RECV_BITS);
546 return;
547 }
548 eh = (struct ether_header *)(xs->xs_ifuba.ifu_r.ifrw_addr);
549
550 /*
1a568327 551 * Deal with trailer protocol: if type is trailer
063e82dc
MK
552 * get true type from first 16-bit word past data.
553 * Remember that type was trailer by setting off.
554 */
555 eh->ether_type = ntohs((u_short)eh->ether_type);
556#define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
1a568327
MK
557 if (eh->ether_type >= ETHERTYPE_TRAIL &&
558 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
559 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
063e82dc
MK
560 if (off >= ETHERMTU)
561 return; /* sanity */
562 eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *));
563 resid = ntohs(*(exdataaddr(eh, off+2, u_short *)));
564 if (off + resid > len)
565 return; /* sanity */
566 len = off + resid;
567 } else
568 off = 0;
569 if (len == 0)
570 return;
571
572 /*
573 * Pull packet off interface. Off is nonzero if packet
574 * has trailing header; if_rubaget will then force this header
575 * information to be at the front, but we still have to drop
576 * the type and length which are at the front of any trailer data.
577 */
578 m = if_rubaget(&xs->xs_ifuba, len, off);
579 if (m == 0)
580 return;
581 if (off) {
582 m->m_off += 2 * sizeof (u_short);
583 m->m_len -= 2 * sizeof (u_short);
584 }
585 switch (eh->ether_type) {
586
587#ifdef INET
1a568327 588 case ETHERTYPE_IP:
063e82dc
MK
589 schednetisr(NETISR_IP); /* is this necessary */
590 inq = &ipintrq;
591 break;
592
1a568327 593 case ETHERTYPE_ARP:
063e82dc
MK
594 arpinput(&xs->xs_ac, m);
595 return;
596#endif
597 default:
598 m_freem(m);
599 return;
600 }
601
602 if (IF_QFULL(inq)) {
603 IF_DROP(inq);
604 m_freem(m);
605 return;
606 }
607 IF_ENQUEUE(inq, m);
608}
609
610/*
611 * Send receive request to EXOS.
612 * This routine is called by exinit and excdint,
613 * with interrupts disabled in both cases.
614 */
615exhangrcv(unit)
616 int unit;
617{
618 register struct ex_softc *xs = &ex_softc[unit];
619 register struct ex_msg *bp = exgetcbuf(xs);
620 struct exdevice *addr = (struct exdevice *)exinfo[unit]->ui_addr;
621
622 bp->mb_rqst = LLRECEIVE;
623 bp->mb_er.er_nblock = 1;
624 bp->mb_er.er_blks[0].bb_len = EXMAXRBUF;
625 *(u_long *)bp->mb_er.er_blks[0].bb_addr =
626 UNIADDR(xs->xs_ifuba.ifu_r.ifrw_info);
627 bp->mb_status |= MH_EXOS;
628 addr->xd_portb = EX_NTRUPT;
629}
630
631/*
632 * Ethernet output routine.
633 * Encapsulate a packet of type family for the local net.
634 * Use trailer local net encapsulation if enough data in first
635 * packet leaves a multiple of 512 bytes of data in remainder.
636 */
637exoutput(ifp, m0, dst)
638 register struct ifnet *ifp;
639 register struct mbuf *m0;
640 struct sockaddr *dst;
641{
642 int type, s, error;
643 u_char edst[6];
644 struct in_addr idst;
645 register struct ex_softc *xs = &ex_softc[ifp->if_unit];
646 register struct mbuf *m = m0;
647 register struct ether_header *eh;
648 register int off;
649
650 switch (dst->sa_family) {
651
652#ifdef INET
653 case AF_INET:
654 idst = ((struct sockaddr_in *)dst)->sin_addr;
655 if (!arpresolve(&xs->xs_ac, m, &idst, edst))
656 return (0); /* if not yet resolved */
657 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
658 /* need per host negotiation */
659 if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
660 if (off > 0 && (off & 0x1ff) == 0 &&
661 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
1a568327 662 type = ETHERTYPE_TRAIL + (off>>9);
063e82dc
MK
663 m->m_off -= 2 * sizeof (u_short);
664 m->m_len += 2 * sizeof (u_short);
1a568327 665 *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
063e82dc
MK
666 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
667 goto gottrailertype;
668 }
1a568327 669 type = ETHERTYPE_IP;
063e82dc
MK
670 off = 0;
671 goto gottype;
672#endif
673
674 case AF_UNSPEC:
675 eh = (struct ether_header *)dst->sa_data;
676 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
677 type = eh->ether_type;
678 goto gottype;
679
680 default:
681 printf("ex%d: can't handle af%d\n", ifp->if_unit,
682 dst->sa_family);
683 error = EAFNOSUPPORT;
684 goto bad;
685 }
686
687gottrailertype:
688 /*
689 * Packet to be sent as trailer: move first packet
690 * (control information) to end of chain.
691 */
692 while (m->m_next)
693 m = m->m_next;
694 m->m_next = m0;
695 m = m0->m_next;
696 m0->m_next = 0;
697 m0 = m;
698
699gottype:
700 /*
701 * Add local net header. If no space in first mbuf,
702 * allocate another.
703 */
704 if (m->m_off > MMAXOFF ||
705 MMINOFF + sizeof (struct ether_header) > m->m_off) {
706 m = m_get(M_DONTWAIT, MT_HEADER);
707 if (m == 0) {
708 error = ENOBUFS;
709 goto bad;
710 }
711 m->m_next = m0;
712 m->m_off = MMINOFF;
713 m->m_len = sizeof (struct ether_header);
714 } else {
715 m->m_off -= sizeof (struct ether_header);
716 m->m_len += sizeof (struct ether_header);
717 }
718 eh = mtod(m, struct ether_header *);
719 eh->ether_type = htons((u_short)type);
720 bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
721 bcopy((caddr_t)xs->xs_addr, (caddr_t)eh->ether_shost, 6);
722
723 /*
724 * Queue message on interface, and start output if interface
725 * not yet active.
726 */
727 s = splimp();
728 if (IF_QFULL(&ifp->if_snd)) {
729 IF_DROP(&ifp->if_snd);
730 splx(s);
731 m_freem(m);
732 return (ENOBUFS);
733 }
734 IF_ENQUEUE(&ifp->if_snd, m);
735 /*
736 * If transmit request not already pending, then
737 * kick the back end.
738 */
739 if ((xs->xs_flags & EX_XPENDING) == 0) {
740 exstart(ifp->if_unit);
741 }
742#ifdef DEBUG
743 else {
744 xs->xs_wait++;
745 }
746#endif
747 splx(s);
748 return (0);
749
750bad:
751 m_freem(m0);
752 return (error);
753}
754
755/*
756 * Watchdog routine - place stats request to EXOS
757 * (This could be dispensed with, if you don't care
758 * about the if_ierrors count, or are willing to receive
759 * bad packets in order to derive it.)
760 */
761exwatch(unit)
762 int unit;
763{
764 struct uba_device *ui = exinfo[unit];
765 struct exdevice *addr = (struct exdevice *)ui->ui_addr;
766 register struct ex_softc *xs = &ex_softc[unit];
767 register struct ex_msg *bp;
768 int s = splimp();
769
770 if (xs->xs_flags & EX_STATPENDING) goto exspnd;
771 bp = exgetcbuf(xs);
772 xs->xs_flags |= EX_STATPENDING;
773 bp->mb_rqst = LLNET_STSTCS;
774 bp->mb_ns.ns_mask = READ_OBJ;
775 bp->mb_ns.ns_rsrv = 0;
776 bp->mb_ns.ns_nobj = 8; /* read all 8 stats objects */
777 bp->mb_ns.ns_xobj = 0; /* starting with the 1st one */
778 bp->mb_ns.ns_bufp = P_UNIADDR(xs->xs_ubaddr) + SA_OFFSET;
779 bp->mb_status |= MH_EXOS;
780 addr->xd_portb = EX_NTRUPT;
781exspnd:
782 splx(s);
783 xs->xs_if.if_timer = EXWATCHINTVL;
784}
785
786/*
787 * Process an ioctl request.
788 */
789exioctl(ifp, cmd, data)
790 register struct ifnet *ifp;
791 int cmd;
792 caddr_t data;
793{
1a568327 794 register struct ifaddr *ifa = (struct ifaddr *)data;
063e82dc
MK
795 int s = splimp(), error = 0;
796
797 switch (cmd) {
798
799 case SIOCSIFADDR:
1a568327
MK
800 ifp->if_flags |= IFF_UP;
801 ecinit(ifp->if_unit);
802
803 switch (ifa->ifa_addr.sa_family) {
804 case AF_INET:
805 ((struct arpcom *)ifp)->ac_ipaddr =
806 IA_SIN(ifa)->sin_addr;
807 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
808 break;
809 }
063e82dc
MK
810 break;
811
812 default:
813 error = EINVAL;
814 }
815 splx(s);
816 return (error);
817}