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