date and time created 91/04/03 12:32:20 by william
[unix-history] / usr / src / sys / i386 / isa / if_ne.c
CommitLineData
93b2b8c5
BJ
1#include "ne.h"
2#if NNE > 0
3/*
4 * NE2000 Ethernet driver
5 * Copyright (C) 1990 W. Jolitz
5033d830 6 * @(#)if_ne.c 1.6 (Berkeley) %G%
93b2b8c5
BJ
7 *
8 * Parts inspired from Tim Tucker's if_wd driver for the wd8003,
9 * insight on the ne2000 gained from Robert Clements PC/FTP driver.
10 */
11
12#include "param.h"
13#include "systm.h"
14#include "mbuf.h"
15#include "buf.h"
16#include "protosw.h"
17#include "socket.h"
18#include "ioctl.h"
19#include "errno.h"
20#include "syslog.h"
21
22#include "../net/if.h"
23#include "../net/netisr.h"
24#include "../net/route.h"
25
26#ifdef INET
27#include "../netinet/in.h"
28#include "../netinet/in_systm.h"
29#include "../netinet/in_var.h"
30#include "../netinet/ip.h"
31#include "../netinet/if_ether.h"
32#endif
33
34#ifdef NS
35#include "../netns/ns.h"
36#include "../netns/ns_if.h"
37#endif
38
4686adac 39#include "machine/isa/isa_device.h"
93b2b8c5
BJ
40#include "if_nereg.h"
41#include "icu.h"
42
43int neprobe(), neattach(), neintr();
44int neinit(), neoutput(), neioctl();
45
c6b0f337
BJ
46#include "dbg.h"
47struct isa_driver nedriver = {
93b2b8c5
BJ
48 neprobe, neattach, "ne",
49};
50
93b2b8c5
BJ
51struct mbuf *neget();
52
53/*
54 * Ethernet software status per interface.
55 *
56 * Each interface is referenced by a network interface structure,
57 * ns_if, which the routing code uses to locate the interface.
58 * This structure contains the output queue for the interface, its address, ...
59 */
60struct ne_softc {
61 struct arpcom ns_ac; /* Ethernet common part */
62#define ns_if ns_ac.ac_if /* network-visible interface */
63#define ns_addr ns_ac.ac_enaddr /* hardware Ethernet address */
64 int ns_flags;
65#define DSF_LOCK 1 /* block re-entering enstart */
66 int ns_oactive ;
67 int ns_mask ;
68 int ns_ba; /* byte addr in buffer ram of inc pkt */
69 int ns_cur; /* current page being filled */
70 struct prhdr ns_ph; /* hardware header of incoming packet*/
71 struct ether_header ns_eh; /* header of incoming packet */
72 u_char ns_pb[2048 /*ETHERMTU+sizeof(long)*/];
73} ne_softc[NNE] ;
74#define ENBUFSIZE (sizeof(struct ether_header) + ETHERMTU + 2 + 64)
75
76int nec;
77
78u_short boarddata[16];
79
80neprobe(dvp)
c6b0f337 81 struct isa_device *dvp;
93b2b8c5
BJ
82{
83 int val,i,s;
84 register struct ne_softc *ns = &ne_softc[0];
85
86#ifdef lint
87 neintr(0);
88#endif
89
c6b0f337 90 nec = dvp->id_iobase;
93b2b8c5
BJ
91 s = splimp();
92
93 /* reset the bastard */
94 val = inb(nec+ne_reset);
95 DELAY(2000000);
96 outb(nec+ne_reset,val);
97
98 outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA);
c6b0f337
BJ
99
100 i = 1000000;
101 while ((inb(nec+ds0_isr)&DSIS_RESET) == 0 && i-- > 0) nulldev();
102 if (i < 0) return (0);
103
93b2b8c5
BJ
104 outb(nec+ds0_isr, 0xff);
105
106 /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
107 outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
108
109 outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
c6b0f337
BJ
110 DELAY(10000);
111
112 /* check cmd reg and fail if not right */
113 if ((i=inb(nec+ds_cmd)) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP))
114 return(0);
115
93b2b8c5
BJ
116 outb(nec+ds0_tcr, 0);
117 outb(nec+ds0_rcr, DSRC_MON);
118 outb(nec+ds0_pstart, RBUF/DS_PGSIZE);
119 outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE);
120 outb(nec+ds0_bnry, RBUFEND/DS_PGSIZE);
121 outb(nec+ds0_imr, 0);
122 outb(nec+ds0_isr, 0);
123 outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
124 outb(nec+ds1_curr, RBUF/DS_PGSIZE);
125 outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
126 fetchrom (boarddata, 0, sizeof(boarddata));
c6b0f337 127#ifdef NEDEBUG
93b2b8c5
BJ
128/*{ int i,rom;
129 rom=1;
130printf("ne ram ");
131 for (i = 0; i < 0xfff0; i+=4) {
132 int pat;
133 pat = 0xa55a+i*37;
134 putram(&pat,i,4);
135 fetchram(&pat,i,4);
136 if (pat == 0xa55a+i*37) {
137 if (rom) { rom=0; printf(" %x", i); }
138 } else {
139 if (!rom) { rom=1; printf("..%x ", i); }
140 }
141 pat=0;
142 putram(&pat,i,4);
143 }
144printf("\n");
145}*/
c6b0f337 146#endif
93b2b8c5
BJ
147/* checksum data? */
148 /* extract board address */
149 for(i=0; i < 6; i++) ns->ns_addr[i] = boarddata[i];
93b2b8c5
BJ
150 splx(s);
151 return (1);
152}
153
154fetchrom (up, ad, len) u_short *up; {
155 u_char cmd;
156
157 cmd = inb(nec+ds_cmd);
158 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
159 outb (nec+ds0_isr, DSIS_RDC);
160 outb (nec+ds0_rbcr0, len&0xff);
161 outb (nec+ds0_rbcr1, (len>>8)&0xff);
162 outb (nec+ds0_rsar0, ad&0xff);
163 outb (nec+ds0_rsar1, (ad>>8)&0xff);
164 outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
165 insw (nec+ne_data, up, len/2);
c6b0f337
BJ
166 pausestr ("x",1);
167 while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) pausestr("fetchrom",0);
93b2b8c5
BJ
168 outb (nec+ds0_isr, DSIS_RDC);
169 outb (nec+ds_cmd, cmd);
170}
171
c6b0f337 172static recur;
93b2b8c5
BJ
173fetchram (up, ad, len) caddr_t up; {
174 u_char cmd;
175
c6b0f337 176 recur++;
93b2b8c5
BJ
177 cmd = inb(nec+ds_cmd);
178 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
179 outb (nec+ds0_isr, DSIS_RDC);
180 outb (nec+ds0_rbcr0, len&0xff);
181 outb (nec+ds0_rbcr1, (len>>8)&0xff);
182 outb (nec+ds0_rsar0, ad&0xff);
183 outb (nec+ds0_rsar1, (ad>>8)&0xff);
184 outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
185 insw (nec+ne_data, up, len/2);
c6b0f337
BJ
186 pausestr ("x",1);
187 while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) pausestr("fetchram",0);
93b2b8c5
BJ
188 outb (nec+ds0_isr, DSIS_RDC);
189 outb (nec+ds_cmd, cmd);
c6b0f337 190 recur--;
93b2b8c5
BJ
191}
192
193putram (up, ad, len) caddr_t up; {
194 u_char cmd;
195
c6b0f337 196 recur++;
93b2b8c5
BJ
197 cmd = inb(nec+ds_cmd);
198 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
199 outb (nec+ds0_isr, DSIS_RDC);
200 if(len&1) len++;
201 outb (nec+ds0_rbcr0, len&0xff);
202 outb (nec+ds0_rbcr1, (len>>8)&0xff);
203 outb (nec+ds0_rsar0, ad&0xff);
204 outb (nec+ds0_rsar1, (ad>>8)&0xff);
205 outb (nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START);
206 outsw (nec+ne_data, up, len/2);
c6b0f337
BJ
207 pausestr ("x",1);
208 while ((inb (nec+ds0_isr) & DSIS_RDC) == 0)
209 if(pausestr("putram",0)<0) break;
93b2b8c5
BJ
210 outb (nec+ds0_isr, DSIS_RDC);
211 outb (nec+ds_cmd, cmd);
c6b0f337 212 recur--;
93b2b8c5
BJ
213}
214
215/*
216 * Reset of interface.
217 */
218nereset(unit, uban)
219 int unit, uban;
220{
221 if (unit >= NNE)
222 return;
223 printf("ne%d: reset\n", unit);
224 ne_softc[unit].ns_flags &= ~DSF_LOCK;
225 neinit(unit);
226}
227
228/*
229 * Interface exists: make available by filling in network interface
230 * record. System will initialize the interface when it is ready
231 * to accept packets. We get the ethernet address here.
232 */
233neattach(dvp)
c6b0f337 234 struct isa_device *dvp;
93b2b8c5 235{
c6b0f337 236 int unit = dvp->id_unit;
93b2b8c5
BJ
237 register struct ne_softc *ns = &ne_softc[unit];
238 register struct ifnet *ifp = &ns->ns_if;
239
240 ifp->if_unit = unit;
241 ifp->if_name = nedriver.name ;
242 ifp->if_mtu = ETHERMTU;
e243739b 243 printf (" ethernet address %s", ether_sprintf(ns->ns_addr)) ;
93b2b8c5
BJ
244 ifp->if_flags = IFF_BROADCAST|IFF_NOTRAILERS;
245 ifp->if_init = neinit;
246 ifp->if_output = neoutput;
247 ifp->if_ioctl = neioctl;
248 ifp->if_reset = nereset;
249 ifp->if_watchdog = 0;
250 if_attach(ifp);
251}
252
253/*
254 * Initialization of interface; set up initialization block
255 * and transmit/receive descriptor rings.
256 */
257neinit(unit)
258 int unit;
259{
260 register struct ne_softc *ns = &ne_softc[unit];
261 struct ifnet *ifp = &ns->ns_if;
262 int s;
263 register i; char *cp;
264
265 if (ifp->if_addrlist == (struct ifaddr *)0) return;
266 if (ifp->if_flags & IFF_RUNNING) return;
267
268 s = splimp();
269
270 /* set physical address on ethernet */
271 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
272 for (i=0 ; i < 6 ; i++) outb(nec+ds1_par0+i,ns->ns_addr[i]);
273
274 /* clr logical address hash filter for now */
275 for (i=0 ; i < 8 ; i++) outb(nec+ds1_mar0+i,0xff);
276
277 /* init regs */
278 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
279 outb (nec+ds0_rbcr0, 0);
280 outb (nec+ds0_rbcr1, 0);
281 outb (nec+ds0_imr, 0);
282 outb (nec+ds0_isr, 0xff);
283 /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
284 outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
285 outb(nec+ds0_tcr, 0);
286 outb (nec+ds0_rcr, DSRC_MON);
287 outb (nec+ds0_tpsr, 0);
288 outb(nec+ds0_pstart, RBUF/DS_PGSIZE);
289 outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE);
c67ce870 290 outb(nec+ds0_bnry, RBUF/DS_PGSIZE);
93b2b8c5
BJ
291 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
292 outb(nec+ds1_curr, RBUF/DS_PGSIZE);
293 ns->ns_cur = RBUF/DS_PGSIZE;
294 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
295 outb (nec+ds0_rcr, DSRC_AB);
296 outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
297 outb (nec+ds0_imr, 0xff);
298
299 ns->ns_if.if_flags |= IFF_RUNNING;
300 ns->ns_oactive = 0; ns->ns_mask = ~0;
301 if (ns->ns_if.if_snd.ifq_head) nestart(ns);
302 splx(s);
303}
304
305/*
306 * Setup output on interface.
307 * Get another datagram to send off of the interface queue,
308 * and map it to the interface before starting the output.
309 * called only at splimp or interrupt level.
310 */
311nestart(ns)
312 register struct ne_softc *ns;
313{
314 struct mbuf *m0, *m;
315 int buffer;
316 int len = 0, i;
317
318 /*
319 * The DS8390 has only one transmit buffer, if it is busy we
320 * must wait until the transmit interrupt completes.
321 */
322 outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
323
c6b0f337
BJ
324 if (ns->ns_flags & DSF_LOCK)
325 return;
326
93b2b8c5
BJ
327 if (inb(nec+ds_cmd) & DSCM_TRANS)
328 return;
329
330 if ((ns->ns_if.if_flags & IFF_RUNNING) == 0)
331 return;
332
333 IF_DEQUEUE(&ns->ns_if.if_snd, m);
334
335 if (m == 0)
336 return;
337
338 /*
339 * Copy the mbuf chain into the transmit buffer
340 */
341
c6b0f337 342 ns->ns_flags |= DSF_LOCK; /* prevent entering nestart */
93b2b8c5
BJ
343 buffer = TBUF; len = i = 0;
344 for (m0 = m; m != 0; m = m->m_next) {
345/*int j;*/
346 putram(mtod(m, caddr_t), buffer, m->m_len);
347 buffer += m->m_len;
348 len += m->m_len;
349/*for(j=0; i < len;i++,j++) puthex(mtod(m,u_char *)[j]);
350printf("|"); */
351 }
352
353 /*
354 * If this was a broadcast packet loop it
355 * back because the hardware can't hear its own
356 * transmits.
357 */
358 /*if (bcmp((caddr_t)(mtod(m0, struct ether_header *)->ether_dhost),
359 (caddr_t)etherbroadcastaddr,
360 sizeof(etherbroadcastaddr)) == 0) {
361 neread(ns, m0);
362 } else {
363*/
364 m_freem(m0);
365 /*}*/
366
367 /*
368 * Init transmit length registers, and set transmit start flag.
369 */
370
c67ce870 371#ifdef NEDEBUGx
c6b0f337
BJ
372if(len < 0 || len > 1536)
373pg("T Bogus Length %d\n", len);
374dprintf(DEXPAND,"snd %d ", len);
375#endif
376 if (len < 60) len = 60;
93b2b8c5
BJ
377 outb(nec+ds0_tbcr0,len&0xff);
378 outb(nec+ds0_tbcr1,(len>>8)&0xff);
379 outb(nec+ds0_tpsr, TBUF/DS_PGSIZE);
380 outb(nec+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START);
381}
382
c67ce870
BJ
383#define succ(n) (((n)+1 >= RBUFEND/DS_PGSIZE) ? RBUF/DS_PGSIZE : (n)+1)
384#define pred(n) (((n)-1 < RBUF/DS_PGSIZE) ? RBUFEND/DS_PGSIZE-1 : (n)-1)
93b2b8c5
BJ
385/*
386 * Controller interrupt.
387 */
c6b0f337 388neintr(vec, ppl)
93b2b8c5
BJ
389 int vec;
390{
391 register struct ne_softc *ns = &ne_softc[0];
392 u_char cmd,isr;
c6b0f337 393static cnt;
93b2b8c5 394
c6b0f337 395 /* save cmd, clear interrupt */
93b2b8c5 396 cmd = inb (nec+ds_cmd);
c6b0f337 397loop:
93b2b8c5 398 isr = inb (nec+ds0_isr);
c67ce870 399#ifdef NEDEBUGx
c6b0f337
BJ
400dprintf(DEXPAND,"|ppl %x isr %x ", ppl, isr);
401#endif
402
403 outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
c67ce870 404 outb(nec+ds0_isr, isr);
93b2b8c5 405
93b2b8c5 406
c67ce870 407 if (isr & (DSIS_RXE|DSIS_TXE|DSIS_ROVRN))
93b2b8c5
BJ
408 log(LOG_ERR, "ne%d: error: isr %x\n", ns-ne_softc, isr/*, DSIS_BITS*/);
409
c67ce870 410#ifdef notdef
93b2b8c5
BJ
411 /* receiver ovverun? */
412 if (isr & DSIS_ROVRN) {
413 u_char pend,lastfree;
414
415 outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA);
416 outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA|DSCM_PG1);
417 pend = inb(nec+ds1_curr);
418 outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA|DSCM_PG0);
419 lastfree = inb(nec+ds0_bnry);
c6b0f337 420#ifdef NEDEBUG
93b2b8c5 421printf("Cur %x pend %x lastfree %x ", ns->ns_cur, pend, lastfree);
c6b0f337 422#endif
93b2b8c5 423 /* have we wrapped */
c67ce870 424 if (lastfree >= RBUFEND/DS_PGSIZE)
93b2b8c5
BJ
425 lastfree = RBUF/DS_PGSIZE;
426 /* something in the buffer? */
427 if (pend != succ(lastfree)) {
428 u_char nxt;
429
430 fetchram(&ns->ns_ph,ns->ns_cur*DS_PGSIZE, sizeof(ns->ns_ph));
431 ns->ns_ba = ns->ns_cur*DS_PGSIZE+sizeof(ns->ns_ph);
432
433 if (ns->ns_ph.pr_status & DSRS_RPC)
434 nerecv (ns);
435
436 nxt = ns->ns_ph.pr_nxtpg ;
c6b0f337 437#ifdef NEDEBUG
93b2b8c5 438printf("nxt %x ", nxt);
c6b0f337 439#endif
93b2b8c5
BJ
440 /* sanity check */
441 if ( nxt >= RBUF/DS_PGSIZE
442 && nxt <= RBUFEND/DS_PGSIZE && nxt <= pend)
443 ns->ns_cur = nxt;
444 else ns->ns_cur = nxt = pend;
445 lastfree = pred(nxt);
446 outb(nec+ds0_bnry, lastfree);
447 } else ns->ns_cur = pend;
448
449 outb(nec+ds0_rbcr0,0);
450 outb(nec+ds0_rbcr1,0);
451 outb(nec+ds0_tcr,DSTC_LB0);
452 outb(nec+ds0_rcr, DSRC_MON);
453 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
454 outb (nec+ds0_rcr, DSRC_AB);
455 outb(nec+ds0_tcr,0);
93b2b8c5 456 }
c67ce870 457#endif
93b2b8c5
BJ
458
459 /* receiver error */
460 if (isr & DSIS_RXE) {
461 /* need to read these registers to clear status */
462 (void) inb(nec+ ds0_rsr);
463 (void) inb(nec+ 0xD);
464 (void) inb(nec + 0xE);
465 (void) inb(nec + 0xF);
466 ns->ns_if.if_ierrors++;
467 }
468
c67ce870 469 if (isr & (DSIS_RX|DSIS_RXE|DSIS_ROVRN)) {
93b2b8c5
BJ
470 u_char pend,lastfree;
471
472 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
473 pend = inb(nec+ds1_curr);
474 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
475 lastfree = inb(nec+ds0_bnry);
c6b0f337
BJ
476#ifdef NEDEBUG
477dprintf(DEXPAND,"cur %x pnd %x lfr %x ", ns->ns_cur, pend, lastfree);
478#endif
93b2b8c5 479 /* have we wrapped */
c67ce870 480 if (lastfree >= RBUFEND/DS_PGSIZE)
93b2b8c5 481 lastfree = RBUF/DS_PGSIZE;
c67ce870
BJ
482 if (pend < lastfree && ns->ns_cur < pend)
483 lastfree = ns->ns_cur;
484 else if (ns->ns_cur > lastfree)
485 lastfree = ns->ns_cur;
486
93b2b8c5 487 /* something in the buffer? */
c67ce870 488 while (pend != lastfree) {
93b2b8c5
BJ
489 u_char nxt;
490
c67ce870
BJ
491 fetchram(&ns->ns_ph,lastfree*DS_PGSIZE,
492 sizeof(ns->ns_ph));
493 ns->ns_ba = lastfree*DS_PGSIZE+sizeof(ns->ns_ph);
93b2b8c5 494
c67ce870 495 /* paranoia */
c6b0f337
BJ
496 if (ns->ns_ph.pr_status == DSRS_RPC ||
497 ns->ns_ph.pr_status == 0x21)
93b2b8c5 498 nerecv (ns);
c6b0f337
BJ
499#ifdef NEDEBUG
500 else {
501printf("cur %x pnd %x lfr %x ", ns->ns_cur, pend, lastfree);
502printf("nxt %x len %x ", ns->ns_ph.pr_nxtpg, (ns->ns_ph.pr_sz1<<8)+
503 ns->ns_ph.pr_sz0);
504pg("Bogus Sts %x ", ns->ns_ph.pr_status);
505 }
506#endif
93b2b8c5
BJ
507
508 nxt = ns->ns_ph.pr_nxtpg ;
c6b0f337 509#ifdef NEDEBUG
93b2b8c5 510dprintf(DEXPAND,"nxt %x ", nxt);
c6b0f337 511#endif
93b2b8c5
BJ
512 /* sanity check */
513 if ( nxt >= RBUF/DS_PGSIZE
514 && nxt <= RBUFEND/DS_PGSIZE && nxt <= pend)
515 ns->ns_cur = nxt;
516 else ns->ns_cur = nxt = pend;
c67ce870
BJ
517 lastfree = nxt;
518 outb(nec+ds0_bnry, pred(nxt));
519 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
c6b0f337 520 pend = inb(nec+ds1_curr);
c67ce870
BJ
521 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
522 } /*else ns->ns_cur = pend;*/
523#ifdef NEDEBUG
524dprintf(DEXPAND,"cur %x pnd %x lfR %x ", ns->ns_cur, pend, lastfree);
525#endif
93b2b8c5 526 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
93b2b8c5
BJ
527 }
528 if (isr & DSIS_TXE) {
c67ce870 529 ns->ns_flags &= ~DSF_LOCK;
c6b0f337
BJ
530#ifdef NEDEBUG
531dprintf(DEXPAND," clsn");
532#endif
93b2b8c5
BJ
533 /* need to read these registers to clear status */
534 ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
535 ns->ns_if.if_oerrors++;
536 }
c6b0f337 537 if (isr & DSIS_TX) {
c67ce870 538#ifdef NEDEBUGx
c6b0f337
BJ
539dprintf(DEXPAND,"tx ");
540#endif
c67ce870 541 ns->ns_flags &= ~DSF_LOCK;
93b2b8c5 542 ++ns->ns_if.if_opackets;
c67ce870
BJ
543 ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
544 }
545
546 /* receiver ovverun? */
547 if (isr & DSIS_ROVRN) {
548 outb(nec+ds0_rbcr0, 0);
549 outb(nec+ds0_rbcr1, 0);
550 outb(nec+ds0_tcr, DSTC_LB0);
551 outb(nec+ds0_rcr, DSRC_MON);
552 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
553 outb(nec+ds0_rcr, DSRC_AB);
554 outb(nec+ds0_tcr, 0);
93b2b8c5 555 }
c6b0f337 556
93b2b8c5
BJ
557 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
558 nestart(ns);
c6b0f337 559 outb (nec+ds_cmd, cmd);
93b2b8c5 560 outb (nec+ds0_imr, 0xff);
c6b0f337
BJ
561 isr = inb (nec+ds0_isr);
562 if(isr) goto loop;
563
564#ifdef NEDEBUG
565 if(++cnt % 10 == 0) dprintf(DEXPAND,"\n");
566#endif
93b2b8c5
BJ
567}
568
569/*
570 * Ethernet interface receiver interface.
571 * If input error just drop packet.
572 * Otherwise examine packet to determine type. If can't determine length
573 * from type, then have to drop packet. Othewise decapsulate
574 * packet based on type and pass to type specific higher-level
575 * input routine.
576 */
577nerecv(ns)
578 register struct ne_softc *ns;
579{
580 int len,i;
581
582 ns->ns_if.if_ipackets++;
583 len = ns->ns_ph.pr_sz0 + (ns->ns_ph.pr_sz1<<8);
c6b0f337
BJ
584if(len < 60 || len > 1536) {
585#ifdef NEDEBUG
586pg(DEXPAND,"R Bogus Length %d", len);
587#endif
588return;
589}
93b2b8c5 590 fetchram(ns->ns_pb,ns->ns_ba,min(len,DS_PGSIZE-sizeof(ns->ns_ph)));
c6b0f337 591#ifdef NEDEBUG
93b2b8c5
BJ
592if (!bcmp((caddr_t)ns->ns_pb, (caddr_t)ns->ns_addr, 6)
593&& !bcmp((caddr_t)ns->ns_pb, (caddr_t)etherbroadcastaddr, 6)) {
594printf("G%x ", ns->ns_cur);
595return;
596}/* else
597printf("P%x ", ns->ns_cur);*/
c6b0f337 598#endif
93b2b8c5
BJ
599 if(len > DS_PGSIZE-sizeof(ns->ns_ph)) {
600 int l = len - (DS_PGSIZE-sizeof(ns->ns_ph)), b ;
601 u_char *p = ns->ns_pb + (DS_PGSIZE-sizeof(ns->ns_ph));
602
c6b0f337
BJ
603#ifdef NEDEBUG
604dprintf(DEXPAND,"len %d(%d|", len, p - ns->ns_pb);
605#endif
93b2b8c5
BJ
606 if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
607 b = ns->ns_cur*DS_PGSIZE;
608
609 while (l >= DS_PGSIZE) {
610 fetchram(p,b,DS_PGSIZE);
611 p += DS_PGSIZE; l -= DS_PGSIZE;
612 if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
613 b = ns->ns_cur*DS_PGSIZE;
c6b0f337
BJ
614#ifdef NEDEBUG
615dprintf(DEXPAND,"%d|", p - ns->ns_pb);
616#endif
93b2b8c5 617 }
c6b0f337
BJ
618#ifdef NEDEBUG
619dprintf(DEXPAND,"%d) ", l);
620#endif
93b2b8c5
BJ
621 if (l > 0)
622 fetchram(p,b,l);
623 }
624 len -=
625 sizeof(struct ether_header)
626 + sizeof(long); /* don't forget checksum! */
627
628
629 neread(ns,(caddr_t)(ns->ns_pb), len);
630}
631
c6b0f337
BJ
632pausestr(s,n) char *s; {
633static downcnt;
634
635 if(n) { downcnt = 0xffff; return(0); }
636 if(--downcnt > 0) return(0);
637#ifdef NEDEBUG
638 pg(" <%s> recur %d sts %x ", s, recur, inb (nec+ds0_isr));
639#endif
640 return(-1);
641}
642
643
93b2b8c5
BJ
644/*
645 * Pass a packet to the higher levels.
646 * We deal with the trailer protocol here.
647 */
648neread(ns, buf, len)
649 register struct ne_softc *ns;
650 char *buf;
651 int len;
652{
653 register struct ether_header *eh;
654 struct mbuf *m;
655 int off, resid;
656 register struct ifqueue *inq;
657
658 /*
659 * Deal with trailer protocol: if type is trailer type
660 * get true type from first 16-bit word past data.
661 * Remember that type was trailer by setting off.
662 */
663 eh = (struct ether_header *)buf;
664 eh->ether_type = ntohs((u_short)eh->ether_type);
665#define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
666 if (eh->ether_type >= ETHERTYPE_TRAIL &&
667 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
668 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
669 if (off >= ETHERMTU) return; /* sanity */
670 eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
671 resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
672 if (off + resid > len) return; /* sanity */
673 len = off + resid;
674 } else off = 0;
675
676 if (len == 0) return;
677
678 /*
679 * Pull packet off interface. Off is nonzero if packet
680 * has trailing header; neget will then force this header
681 * information to be at the front, but we still have to drop
682 * the type and length which are at the front of any trailer data.
683 */
684 m = neget(buf, len, off, &ns->ns_if);
685 if (m == 0) return;
686
687 if (off) {
688 struct ifnet *ifp;
689
690 ifp = *(mtod(m, struct ifnet **));
691 m->m_off += 2 * sizeof (u_short);
692 m->m_len -= 2 * sizeof (u_short);
693 *(mtod(m, struct ifnet **)) = ifp;
694 }
695 switch (eh->ether_type) {
696#ifdef INET
697 case ETHERTYPE_IP:
698 /*if (ns->ns_ac.ac_ipaddr == 0) goto raw;*/
699 schednetisr(NETISR_IP);
700 inq = &ipintrq;
701 break;
702
703 case ETHERTYPE_ARP:
704 arpinput(&ns->ns_ac, m);
705 return;
706#endif
707#ifdef NS
708 case ETHERTYPE_NS:
709 schednetisr(NETISR_NS);
710 inq = &nsintrq;
711 break;
712
713#endif
714 default:
715 m_freem(m);
716 return;
717 }
718
719 if (IF_QFULL(inq)) {
720 IF_DROP(inq);
721 m_freem(m);
722 return;
723 }
724 IF_ENQUEUE(inq, m);
725}
726
727/*
728 * Ethernet output routine.
729 * Encapsulate a packet of type family for the local net.
730 * Use trailer local net encapsulation if enough data in first
731 * packet leaves a multiple of 512 bytes of data in remainder.
732 */
733neoutput(ifp, m0, dst)
734 struct ifnet *ifp;
735 struct mbuf *m0;
736 struct sockaddr *dst;
737{
738 int type, s, error;
739 u_char edst[6];
740 struct in_addr idst;
741 register struct ne_softc *ns = &ne_softc[ifp->if_unit];
742 register struct mbuf *m = m0;
743 register struct ether_header *eh;
744 register int off;
745 extern struct ifnet loif;
746 struct mbuf *mcopy = (struct mbuf *)0;
747 int usetrailers;
748
749 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
750 error = ENETDOWN;
751 goto bad;
752 }
753
754 switch (dst->sa_family) {
755#ifdef INET
756 case AF_INET:
757 idst = ((struct sockaddr_in *)dst)->sin_addr;
758 if (!arpresolve(&ns->ns_ac, m, &idst, edst, &usetrailers))
759 return (0); /* if not yet resolved */
760 if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr,
761 sizeof(edst)))
762 mcopy = m_copy(m, 0, (int)M_COPYALL);
763 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
764
c6b0f337 765
93b2b8c5
BJ
766 /* need per host negotiation */
767 if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
768 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
769 type = ETHERTYPE_TRAIL + (off>>9);
770 m->m_off -= 2 * sizeof (u_short);
771 m->m_len += 2 * sizeof (u_short);
772 *mtod(m, u_short *) = ntohs((u_short)ETHERTYPE_IP);
773 *(mtod(m, u_short *) + 1) = ntohs((u_short)m->m_len);
774 goto gottrailertype;
775 }
776 type = ETHERTYPE_IP;
777 off = 0;
778 goto gottype;
779#endif
780#ifdef NS
781 case AF_NS:
782 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
783 (caddr_t)edst, sizeof (edst));
784
785 if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost,
786 sizeof(edst))) {
787
788 mcopy = m_copy(m, 0, (int)M_COPYALL);
789 } else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost,
790 sizeof(edst))) {
791
792 return(looutput(&loif, m, dst));
793 }
794 type = ETHERTYPE_NS;
795 off = 0;
796 goto gottype;
797#endif
798
799 case AF_UNSPEC:
800 eh = (struct ether_header *)dst->sa_data;
801 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
802 type = eh->ether_type;
803 goto gottype;
804
805 default:
806 printf("ne%d: can't handle af%d\n", ifp->if_unit,
807 dst->sa_family);
808 error = EAFNOSUPPORT;
809 goto bad;
810 }
811
812gottrailertype:
813 /*
814 * Packet to be sent as trailer: move first packet
815 * (control information) to end of chain.
816 */
817 while (m->m_next)
818 m = m->m_next;
819 m->m_next = m0;
820 m = m0->m_next;
821 m0->m_next = 0;
822 m0 = m;
823
824gottype:
825 /*
826 * Add local net header. If no space in first mbuf,
827 * allocate another.
828 */
829 if (m->m_off > MMAXOFF ||
830 MMINOFF + sizeof (struct ether_header) > m->m_off) {
831 m = m_get(M_DONTWAIT, MT_HEADER);
832 if (m == 0) {
833 error = ENOBUFS;
834 goto bad;
835 }
836 m->m_next = m0;
837 m->m_off = MMINOFF;
838 m->m_len = sizeof (struct ether_header);
839 } else {
840 m->m_off -= sizeof (struct ether_header);
841 m->m_len += sizeof (struct ether_header);
842 }
843 eh = mtod(m, struct ether_header *);
844 bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
845 bcopy((caddr_t)ns->ns_addr, (caddr_t)eh->ether_shost,
846 sizeof (eh->ether_shost));
847 eh->ether_type = htons((u_short)type);
848
849 /*
850 * Queue message on interface, and start output if interface
851 * not yet active.
852 */
853 s = splimp();
854 if (IF_QFULL(&ifp->if_snd)) {
855 IF_DROP(&ifp->if_snd);
856 splx(s);
857 m_freem(m);
858 return (ENOBUFS);
859 }
860 IF_ENQUEUE(&ifp->if_snd, m);
861 nestart(ns);
862 splx(s);
863 return (mcopy ? looutput(&loif, mcopy, dst) : 0);
864
865bad:
866 m_freem(m0);
867 if (mcopy)
868 m_freem(mcopy);
869 return (error);
870}
871
872/*
873 * Supporting routines
874 */
875
876/*
877 * Pull read data off a interface.
878 * Len is length of data, with local net header stripped.
879 * Off is non-zero if a trailer protocol was used, and
880 * gives the offset of the trailer information.
881 * We copy the trailer information and then all the normal
882 * data into mbufs. When full cluster sized units are present
883 * we copy into clusters.
884 */
885struct mbuf *
886neget(buf, totlen, off0, ifp)
887 caddr_t buf;
888 int totlen, off0;
889 struct ifnet *ifp;
890{
891 struct mbuf *top, **mp, *m, *p;
892 int off = off0, len;
893 register caddr_t cp = buf;
894
895 cp = buf + sizeof(struct ether_header);
896 top = 0;
897 mp = &top;
898 while (totlen > 0) {
899 u_char *mcp;
900
901 MGET(m, M_DONTWAIT, MT_DATA);
902 if (m == 0)
903 goto bad;
904 if (off) {
905 len = totlen - off;
906 cp = buf + off + sizeof (struct ether_header);
907 } else
908 len = totlen;
909 if (ifp)
910 len += sizeof(ifp);
911 if (len >= NBPG) {
912 MCLGET(m);
913 if (m->m_len == CLBYTES)
914 m->m_len = len = MIN(len, CLBYTES);
915 else
916 m->m_len = len = MIN(MLEN, len);
917 } else {
918 m->m_len = len = MIN(MLEN, len);
919 m->m_off = MMINOFF;
920 }
921 mcp = mtod(m, u_char *);
922 if (ifp) {
923 /*
924 * Prepend interface pointer to first mbuf.
925 */
926 *(mtod(m, struct ifnet **)) = ifp;
927 mcp += sizeof(ifp);
928 len -= sizeof(ifp);
929 ifp = (struct ifnet *)0;
930 }
931 bcopy(cp, mcp, len);
932 cp += len ; mcp += len ;
933 *mp = m;
934 mp = &m->m_next;
935 if (off == 0) {
936 totlen -= len;
937 continue;
938 }
939 off += len;
940 if (off == totlen) {
941 cp = buf + sizeof (struct ether_header);
942 off = 0;
943 totlen = off0;
944 }
945 }
946 return (top);
947bad:
948 m_freem(top);
949 return (0);
950}
951
952/*
953 * Map a chain of mbufs onto a network interface
954 * in preparation for an i/o operation.
955 * The argument chain of mbufs includes the local network
956 * header which is copied to be in the mapped, aligned
957 * i/o space.
958 */
959neput(cp, m)
960 register caddr_t cp;
961 register struct mbuf *m;
962{
963 register struct mbuf *mp;
964 register int i;
965 int x, cc = 0, t;
966 caddr_t dp;
967
968 while (m) {
969 dp = mtod(m, char *);
970 bcopy(mtod(m, caddr_t), cp, (unsigned)m->m_len);
971 cp += m->m_len;
972 cc += m->m_len;
973 MFREE(m, mp);
974 m = mp;
975 }
976 return (max(cc, ETHERMIN + sizeof(struct ether_header)));
977}
978
979/*
980 * Process an ioctl request.
981 */
982neioctl(ifp, cmd, data)
983 register struct ifnet *ifp;
984 int cmd;
985 caddr_t data;
986{
987 register struct ifaddr *ifa = (struct ifaddr *)data;
988 struct ne_softc *ns = &ne_softc[ifp->if_unit];
989 struct ifreq *ifr = (struct ifreq *)data;
990 int s = splimp(), error = 0;
991
992
993 switch (cmd) {
994
995 case SIOCSIFADDR:
996 ifp->if_flags |= IFF_UP;
997
998 switch (ifa->ifa_addr.sa_family) {
999#ifdef INET
1000 case AF_INET:
1001 neinit(ifp->if_unit); /* before arpwhohas */
1002 ((struct arpcom *)ifp)->ac_ipaddr =
1003 IA_SIN(ifa)->sin_addr;
1004 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
1005 break;
1006#endif
1007#ifdef NS
1008 case AF_NS:
1009 {
1010 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
1011
1012 if (ns_nullhost(*ina))
1013 ina->x_host = *(union ns_host *)(ns->ns_addr);
1014 else {
1015 /*
1016 * The manual says we can't change the address
1017 * while the receiver is armed,
1018 * so reset everything
1019 */
1020 ifp->if_flags &= ~IFF_RUNNING;
1021 bcopy((caddr_t)ina->x_host.c_host,
1022 (caddr_t)ns->ns_addr, sizeof(ns->ns_addr));
1023 }
1024 neinit(ifp->if_unit); /* does ne_setaddr() */
1025 break;
1026 }
1027#endif
1028 default:
1029 neinit(ifp->if_unit);
1030 break;
1031 }
1032 break;
1033
1034 case SIOCSIFFLAGS:
1035 if ((ifp->if_flags & IFF_UP) == 0 &&
1036 ifp->if_flags & IFF_RUNNING) {
1037 ifp->if_flags &= ~IFF_RUNNING;
1038 outb(nec+ds_cmd,DSCM_STOP|DSCM_NODMA);
1039 } else if (ifp->if_flags & IFF_UP &&
1040 (ifp->if_flags & IFF_RUNNING) == 0)
1041 neinit(ifp->if_unit);
1042 break;
1043
1044#ifdef notdef
1045 case SIOCGHWADDR:
1046 bcopy((caddr_t)ns->ns_addr, (caddr_t) &ifr->ifr_data,
1047 sizeof(ns->ns_addr));
1048 break;
1049#endif
1050
1051 default:
1052 error = EINVAL;
1053 }
1054 splx(s);
1055 return (error);
1056}
1057
1058nesetaddr(ifp, sin)
1059 register struct ifnet *ifp;
1060 register struct sockaddr_in *sin;
1061{
1062#ifdef notdef
1063 ifp->if_addr = *(struct sockaddr *)sin;
1064 ifp->if_net = in_netof(sin->sin_addr);
1065 ifp->if_host[0] = in_lnaof(sin->sin_addr);
1066 if (nepaddr[ifp->if_unit][0] == '3')
1067 nepaddr[ifp->if_unit][0] = ifp->if_host[0] << 1;
1068 sin = (struct sockaddr_in *)&ifp->if_broadaddr;
1069 sin->sin_family = AF_INET;
1070 sin->sin_addr = in_makeaddr(ifp->if_net, INADDR_ANY);
1071 ifp->if_flags |= IFF_BROADCAST;
1072#endif
1073}
1074#endif