Start development on 386BSD 0.0
[unix-history] / .ref-BSD-4_3_Net_2 / usr / src / sys / i386 / isa / if_ne.c
CommitLineData
af359dea
C
1/*-
2 * Copyright (c) 1990, 1991 William F. Jolitz.
3 * Copyright (c) 1990 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)if_ne.c 7.4 (Berkeley) 5/21/91
35 */
36
93b2b8c5
BJ
37/*
38 * NE2000 Ethernet driver
93b2b8c5
BJ
39 *
40 * Parts inspired from Tim Tucker's if_wd driver for the wd8003,
41 * insight on the ne2000 gained from Robert Clements PC/FTP driver.
42 */
43
af359dea
C
44#include "ne.h"
45#if NNE > 0
46
93b2b8c5
BJ
47#include "param.h"
48#include "systm.h"
49#include "mbuf.h"
50#include "buf.h"
51#include "protosw.h"
52#include "socket.h"
53#include "ioctl.h"
54#include "errno.h"
55#include "syslog.h"
56
af359dea
C
57#include "net/if.h"
58#include "net/netisr.h"
59#include "net/route.h"
93b2b8c5
BJ
60
61#ifdef INET
af359dea
C
62#include "netinet/in.h"
63#include "netinet/in_systm.h"
64#include "netinet/in_var.h"
65#include "netinet/ip.h"
66#include "netinet/if_ether.h"
93b2b8c5
BJ
67#endif
68
69#ifdef NS
af359dea
C
70#include "netns/ns.h"
71#include "netns/ns_if.h"
93b2b8c5
BJ
72#endif
73
af359dea
C
74#include "i386/isa/isa_device.h"
75#include "i386/isa/if_nereg.h"
76#include "i386/isa/icu.h"
93b2b8c5
BJ
77
78int neprobe(), neattach(), neintr();
af359dea 79int nestart(),neinit(), ether_output(), neioctl();
93b2b8c5 80
c6b0f337 81struct isa_driver nedriver = {
93b2b8c5
BJ
82 neprobe, neattach, "ne",
83};
84
93b2b8c5
BJ
85struct mbuf *neget();
86
af359dea
C
87#define ETHER_MIN_LEN 64
88#define ETHER_MAX_LEN 1536
89
93b2b8c5
BJ
90/*
91 * Ethernet software status per interface.
92 *
93 * Each interface is referenced by a network interface structure,
94 * ns_if, which the routing code uses to locate the interface.
95 * This structure contains the output queue for the interface, its address, ...
96 */
97struct ne_softc {
98 struct arpcom ns_ac; /* Ethernet common part */
99#define ns_if ns_ac.ac_if /* network-visible interface */
100#define ns_addr ns_ac.ac_enaddr /* hardware Ethernet address */
101 int ns_flags;
102#define DSF_LOCK 1 /* block re-entering enstart */
103 int ns_oactive ;
104 int ns_mask ;
105 int ns_ba; /* byte addr in buffer ram of inc pkt */
106 int ns_cur; /* current page being filled */
107 struct prhdr ns_ph; /* hardware header of incoming packet*/
108 struct ether_header ns_eh; /* header of incoming packet */
109 u_char ns_pb[2048 /*ETHERMTU+sizeof(long)*/];
110} ne_softc[NNE] ;
af359dea 111#define ENBUFSIZE (sizeof(struct ether_header) + ETHERMTU + 2 + ETHER_MIN_LEN)
93b2b8c5
BJ
112
113int nec;
114
115u_short boarddata[16];
116
117neprobe(dvp)
c6b0f337 118 struct isa_device *dvp;
93b2b8c5
BJ
119{
120 int val,i,s;
121 register struct ne_softc *ns = &ne_softc[0];
122
123#ifdef lint
124 neintr(0);
125#endif
126
c6b0f337 127 nec = dvp->id_iobase;
93b2b8c5
BJ
128 s = splimp();
129
af359dea 130 /* Reset the bastard */
93b2b8c5
BJ
131 val = inb(nec+ne_reset);
132 DELAY(2000000);
133 outb(nec+ne_reset,val);
134
135 outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA);
c6b0f337
BJ
136
137 i = 1000000;
af359dea 138 while ((inb(nec+ds0_isr)&DSIS_RESET) == 0 && i-- > 0);
c6b0f337
BJ
139 if (i < 0) return (0);
140
93b2b8c5
BJ
141 outb(nec+ds0_isr, 0xff);
142
143 /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
144 outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
145
146 outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
c6b0f337
BJ
147 DELAY(10000);
148
af359dea 149 /* Check cmd reg and fail if not right */
c6b0f337
BJ
150 if ((i=inb(nec+ds_cmd)) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP))
151 return(0);
152
93b2b8c5
BJ
153 outb(nec+ds0_tcr, 0);
154 outb(nec+ds0_rcr, DSRC_MON);
155 outb(nec+ds0_pstart, RBUF/DS_PGSIZE);
156 outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE);
157 outb(nec+ds0_bnry, RBUFEND/DS_PGSIZE);
158 outb(nec+ds0_imr, 0);
159 outb(nec+ds0_isr, 0);
160 outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
161 outb(nec+ds1_curr, RBUF/DS_PGSIZE);
162 outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
af359dea 163
c6b0f337 164#ifdef NEDEBUG
af359dea
C
165#define PAT(n) (0xa55a + 37*(n))
166#define RCON 37
167 { int i, rom, pat;
168
169 rom=1;
170 printf("ne ram ");
171
172 for (i = 0; i < 0xfff0; i+=4) {
173 pat = PAT(i);
174 neput(&pat,i,4);
175 nefetch(&pat,i,4);
176 if (pat == PAT(i)) {
177 if (rom) {
178 rom=0;
179 printf(" %x", i);
180 }
181 } else {
182 if (!rom) {
183 rom=1;
184 printf("..%x ", i);
185 }
186 }
187 pat=0;
188 neput(&pat,i,4);
93b2b8c5 189 }
af359dea 190 printf("\n");
93b2b8c5 191 }
c6b0f337 192#endif
af359dea
C
193
194 /* Extract board address */
195 nefetch ((caddr_t)boarddata, 0, sizeof(boarddata));
93b2b8c5 196 for(i=0; i < 6; i++) ns->ns_addr[i] = boarddata[i];
93b2b8c5
BJ
197 splx(s);
198 return (1);
199}
200
af359dea
C
201/*
202 * Fetch from onboard ROM/RAM
203 */
204nefetch (up, ad, len) caddr_t up; {
93b2b8c5
BJ
205 u_char cmd;
206
207 cmd = inb(nec+ds_cmd);
208 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
af359dea
C
209
210 /* Setup remote dma */
93b2b8c5 211 outb (nec+ds0_isr, DSIS_RDC);
af359dea
C
212 outb (nec+ds0_rbcr0, len);
213 outb (nec+ds0_rbcr1, len>>8);
214 outb (nec+ds0_rsar0, ad);
215 outb (nec+ds0_rsar1, ad>>8);
216
217 /* Execute & extract from card */
93b2b8c5
BJ
218 outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
219 insw (nec+ne_data, up, len/2);
af359dea
C
220
221 /* Wait till done, then shutdown feature */
222 while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) ;
93b2b8c5
BJ
223 outb (nec+ds0_isr, DSIS_RDC);
224 outb (nec+ds_cmd, cmd);
225}
226
af359dea
C
227/*
228 * Put to onboard RAM
229 */
230neput (up, ad, len) caddr_t up; {
93b2b8c5
BJ
231 u_char cmd;
232
233 cmd = inb(nec+ds_cmd);
234 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
af359dea
C
235
236 /* Setup for remote dma */
93b2b8c5 237 outb (nec+ds0_isr, DSIS_RDC);
af359dea
C
238 if(len&1) len++; /* roundup to words */
239 outb (nec+ds0_rbcr0, len);
240 outb (nec+ds0_rbcr1, len>>8);
241 outb (nec+ds0_rsar0, ad);
242 outb (nec+ds0_rsar1, ad>>8);
243
244 /* Execute & stuff to card */
93b2b8c5
BJ
245 outb (nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START);
246 outsw (nec+ne_data, up, len/2);
af359dea
C
247
248 /* Wait till done, then shutdown feature */
249 while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) ;
93b2b8c5
BJ
250 outb (nec+ds0_isr, DSIS_RDC);
251 outb (nec+ds_cmd, cmd);
252}
253
254/*
255 * Reset of interface.
256 */
257nereset(unit, uban)
258 int unit, uban;
259{
260 if (unit >= NNE)
261 return;
262 printf("ne%d: reset\n", unit);
263 ne_softc[unit].ns_flags &= ~DSF_LOCK;
264 neinit(unit);
265}
266
267/*
268 * Interface exists: make available by filling in network interface
269 * record. System will initialize the interface when it is ready
270 * to accept packets. We get the ethernet address here.
271 */
272neattach(dvp)
c6b0f337 273 struct isa_device *dvp;
93b2b8c5 274{
c6b0f337 275 int unit = dvp->id_unit;
93b2b8c5
BJ
276 register struct ne_softc *ns = &ne_softc[unit];
277 register struct ifnet *ifp = &ns->ns_if;
278
279 ifp->if_unit = unit;
280 ifp->if_name = nedriver.name ;
281 ifp->if_mtu = ETHERMTU;
e243739b 282 printf (" ethernet address %s", ether_sprintf(ns->ns_addr)) ;
af359dea 283 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
93b2b8c5 284 ifp->if_init = neinit;
af359dea
C
285 ifp->if_output = ether_output;
286 ifp->if_start = nestart;
93b2b8c5
BJ
287 ifp->if_ioctl = neioctl;
288 ifp->if_reset = nereset;
289 ifp->if_watchdog = 0;
290 if_attach(ifp);
291}
292
293/*
294 * Initialization of interface; set up initialization block
295 * and transmit/receive descriptor rings.
296 */
297neinit(unit)
298 int unit;
299{
300 register struct ne_softc *ns = &ne_softc[unit];
301 struct ifnet *ifp = &ns->ns_if;
302 int s;
303 register i; char *cp;
304
305 if (ifp->if_addrlist == (struct ifaddr *)0) return;
306 if (ifp->if_flags & IFF_RUNNING) return;
307
308 s = splimp();
309
310 /* set physical address on ethernet */
311 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
312 for (i=0 ; i < 6 ; i++) outb(nec+ds1_par0+i,ns->ns_addr[i]);
313
314 /* clr logical address hash filter for now */
315 for (i=0 ; i < 8 ; i++) outb(nec+ds1_mar0+i,0xff);
316
317 /* init regs */
318 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
319 outb (nec+ds0_rbcr0, 0);
320 outb (nec+ds0_rbcr1, 0);
321 outb (nec+ds0_imr, 0);
322 outb (nec+ds0_isr, 0xff);
af359dea 323
93b2b8c5
BJ
324 /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
325 outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
326 outb(nec+ds0_tcr, 0);
327 outb (nec+ds0_rcr, DSRC_MON);
328 outb (nec+ds0_tpsr, 0);
329 outb(nec+ds0_pstart, RBUF/DS_PGSIZE);
330 outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE);
c67ce870 331 outb(nec+ds0_bnry, RBUF/DS_PGSIZE);
93b2b8c5
BJ
332 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
333 outb(nec+ds1_curr, RBUF/DS_PGSIZE);
334 ns->ns_cur = RBUF/DS_PGSIZE;
335 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
336 outb (nec+ds0_rcr, DSRC_AB);
337 outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
338 outb (nec+ds0_imr, 0xff);
339
340 ns->ns_if.if_flags |= IFF_RUNNING;
341 ns->ns_oactive = 0; ns->ns_mask = ~0;
af359dea 342 nestart(ifp);
93b2b8c5
BJ
343 splx(s);
344}
345
346/*
347 * Setup output on interface.
348 * Get another datagram to send off of the interface queue,
349 * and map it to the interface before starting the output.
350 * called only at splimp or interrupt level.
351 */
af359dea
C
352nestart(ifp)
353 struct ifnet *ifp;
93b2b8c5 354{
af359dea 355 register struct ne_softc *ns = &ne_softc[ifp->if_unit];
93b2b8c5
BJ
356 struct mbuf *m0, *m;
357 int buffer;
af359dea 358 int len = 0, i, total,t;
93b2b8c5
BJ
359
360 /*
361 * The DS8390 has only one transmit buffer, if it is busy we
362 * must wait until the transmit interrupt completes.
363 */
364 outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
365
c6b0f337
BJ
366 if (ns->ns_flags & DSF_LOCK)
367 return;
368
93b2b8c5
BJ
369 if (inb(nec+ds_cmd) & DSCM_TRANS)
370 return;
371
372 if ((ns->ns_if.if_flags & IFF_RUNNING) == 0)
373 return;
374
375 IF_DEQUEUE(&ns->ns_if.if_snd, m);
376
377 if (m == 0)
378 return;
379
380 /*
381 * Copy the mbuf chain into the transmit buffer
382 */
383
c6b0f337 384 ns->ns_flags |= DSF_LOCK; /* prevent entering nestart */
93b2b8c5 385 buffer = TBUF; len = i = 0;
af359dea
C
386 t = 0;
387 for (m0 = m; m != 0; m = m->m_next)
388 t += m->m_len;
389
390 m = m0;
391 total = t;
392 for (m0 = m; m != 0; ) {
393
394 if (m->m_len&1 && t > m->m_len) {
395 neput(mtod(m, caddr_t), buffer, m->m_len - 1);
396 t -= m->m_len - 1;
397 buffer += m->m_len - 1;
398 m->m_data += m->m_len - 1;
399 m->m_len = 1;
400 m = m_pullup(m, 2);
401 } else {
402 neput(mtod(m, caddr_t), buffer, m->m_len);
403 buffer += m->m_len;
404 t -= m->m_len;
405 MFREE(m, m0);
406 m = m0;
407 }
93b2b8c5
BJ
408 }
409
93b2b8c5
BJ
410 /*
411 * Init transmit length registers, and set transmit start flag.
412 */
413
af359dea
C
414 len = total;
415 if (len < ETHER_MIN_LEN) len = ETHER_MIN_LEN;
93b2b8c5
BJ
416 outb(nec+ds0_tbcr0,len&0xff);
417 outb(nec+ds0_tbcr1,(len>>8)&0xff);
418 outb(nec+ds0_tpsr, TBUF/DS_PGSIZE);
419 outb(nec+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START);
420}
421
af359dea 422/* buffer successor/predecessor in ring? */
c67ce870
BJ
423#define succ(n) (((n)+1 >= RBUFEND/DS_PGSIZE) ? RBUF/DS_PGSIZE : (n)+1)
424#define pred(n) (((n)-1 < RBUF/DS_PGSIZE) ? RBUFEND/DS_PGSIZE-1 : (n)-1)
af359dea 425
93b2b8c5
BJ
426/*
427 * Controller interrupt.
428 */
af359dea 429neintr(unit)
93b2b8c5 430{
af359dea 431 register struct ne_softc *ns = &ne_softc[unit];
93b2b8c5
BJ
432 u_char cmd,isr;
433
af359dea 434 /* Save cmd, clear interrupt */
93b2b8c5 435 cmd = inb (nec+ds_cmd);
c6b0f337 436loop:
93b2b8c5 437 isr = inb (nec+ds0_isr);
c6b0f337 438 outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
c67ce870 439 outb(nec+ds0_isr, isr);
93b2b8c5 440
af359dea 441 /* Receiver error */
93b2b8c5
BJ
442 if (isr & DSIS_RXE) {
443 /* need to read these registers to clear status */
444 (void) inb(nec+ ds0_rsr);
445 (void) inb(nec+ 0xD);
446 (void) inb(nec + 0xE);
447 (void) inb(nec + 0xF);
448 ns->ns_if.if_ierrors++;
449 }
450
af359dea 451 /* We received something; rummage thru tiny ring buffer */
c67ce870 452 if (isr & (DSIS_RX|DSIS_RXE|DSIS_ROVRN)) {
93b2b8c5
BJ
453 u_char pend,lastfree;
454
455 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
456 pend = inb(nec+ds1_curr);
457 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
458 lastfree = inb(nec+ds0_bnry);
af359dea
C
459
460 /* Have we wrapped? */
c67ce870 461 if (lastfree >= RBUFEND/DS_PGSIZE)
93b2b8c5 462 lastfree = RBUF/DS_PGSIZE;
c67ce870
BJ
463 if (pend < lastfree && ns->ns_cur < pend)
464 lastfree = ns->ns_cur;
465 else if (ns->ns_cur > lastfree)
466 lastfree = ns->ns_cur;
467
af359dea 468 /* Something in the buffer? */
c67ce870 469 while (pend != lastfree) {
93b2b8c5
BJ
470 u_char nxt;
471
af359dea
C
472 /* Extract header from microcephalic board */
473 nefetch(&ns->ns_ph,lastfree*DS_PGSIZE,
c67ce870
BJ
474 sizeof(ns->ns_ph));
475 ns->ns_ba = lastfree*DS_PGSIZE+sizeof(ns->ns_ph);
93b2b8c5 476
af359dea 477 /* Incipient paranoia */
c6b0f337 478 if (ns->ns_ph.pr_status == DSRS_RPC ||
af359dea 479 /* for dequna's */
c6b0f337 480 ns->ns_ph.pr_status == 0x21)
93b2b8c5 481 nerecv (ns);
c6b0f337
BJ
482#ifdef NEDEBUG
483 else {
af359dea
C
484 printf("cur %x pnd %x lfr %x ",
485 ns->ns_cur, pend, lastfree);
486 printf("nxt %x len %x ", ns->ns_ph.pr_nxtpg,
487 (ns->ns_ph.pr_sz1<<8)+ ns->ns_ph.pr_sz0);
488 printf("Bogus Sts %x\n", ns->ns_ph.pr_status);
c6b0f337
BJ
489 }
490#endif
93b2b8c5
BJ
491
492 nxt = ns->ns_ph.pr_nxtpg ;
af359dea
C
493
494 /* Sanity check */
495 if ( nxt >= RBUF/DS_PGSIZE && nxt <= RBUFEND/DS_PGSIZE
496 && nxt <= pend)
93b2b8c5
BJ
497 ns->ns_cur = nxt;
498 else ns->ns_cur = nxt = pend;
af359dea
C
499
500 /* Set the boundaries */
c67ce870
BJ
501 lastfree = nxt;
502 outb(nec+ds0_bnry, pred(nxt));
503 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
c6b0f337 504 pend = inb(nec+ds1_curr);
c67ce870 505 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
af359dea 506 }
93b2b8c5 507 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
93b2b8c5 508 }
af359dea
C
509
510 /* Transmit error */
93b2b8c5 511 if (isr & DSIS_TXE) {
c67ce870 512 ns->ns_flags &= ~DSF_LOCK;
af359dea 513 /* Need to read these registers to clear status */
93b2b8c5
BJ
514 ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
515 ns->ns_if.if_oerrors++;
516 }
af359dea
C
517
518 /* Packet Transmitted */
c6b0f337 519 if (isr & DSIS_TX) {
c67ce870 520 ns->ns_flags &= ~DSF_LOCK;
93b2b8c5 521 ++ns->ns_if.if_opackets;
c67ce870
BJ
522 ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
523 }
524
af359dea 525 /* Receiver ovverun? */
c67ce870 526 if (isr & DSIS_ROVRN) {
af359dea
C
527 log(LOG_ERR, "ne%d: error: isr %x\n", ns-ne_softc, isr
528 /*, DSIS_BITS*/);
c67ce870
BJ
529 outb(nec+ds0_rbcr0, 0);
530 outb(nec+ds0_rbcr1, 0);
531 outb(nec+ds0_tcr, DSTC_LB0);
532 outb(nec+ds0_rcr, DSRC_MON);
533 outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
534 outb(nec+ds0_rcr, DSRC_AB);
535 outb(nec+ds0_tcr, 0);
93b2b8c5 536 }
c6b0f337 537
af359dea 538 /* Any more to send? */
93b2b8c5 539 outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
af359dea 540 nestart(&ns->ns_if);
c6b0f337 541 outb (nec+ds_cmd, cmd);
93b2b8c5 542 outb (nec+ds0_imr, 0xff);
af359dea
C
543
544 /* Still more to do? */
c6b0f337
BJ
545 isr = inb (nec+ds0_isr);
546 if(isr) goto loop;
93b2b8c5
BJ
547}
548
549/*
550 * Ethernet interface receiver interface.
551 * If input error just drop packet.
552 * Otherwise examine packet to determine type. If can't determine length
553 * from type, then have to drop packet. Othewise decapsulate
554 * packet based on type and pass to type specific higher-level
555 * input routine.
556 */
557nerecv(ns)
558 register struct ne_softc *ns;
559{
560 int len,i;
561
562 ns->ns_if.if_ipackets++;
563 len = ns->ns_ph.pr_sz0 + (ns->ns_ph.pr_sz1<<8);
af359dea
C
564 if(len < ETHER_MIN_LEN || len > ETHER_MAX_LEN)
565 return;
566
567 /* this need not be so torturous - one/two bcopys at most into mbufs */
568 nefetch(ns->ns_pb, ns->ns_ba, min(len,DS_PGSIZE-sizeof(ns->ns_ph)));
569 if (len > DS_PGSIZE-sizeof(ns->ns_ph)) {
93b2b8c5
BJ
570 int l = len - (DS_PGSIZE-sizeof(ns->ns_ph)), b ;
571 u_char *p = ns->ns_pb + (DS_PGSIZE-sizeof(ns->ns_ph));
572
93b2b8c5
BJ
573 if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
574 b = ns->ns_cur*DS_PGSIZE;
575
576 while (l >= DS_PGSIZE) {
af359dea 577 nefetch(p, b, DS_PGSIZE);
93b2b8c5 578 p += DS_PGSIZE; l -= DS_PGSIZE;
af359dea
C
579 if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
580 b = ns->ns_cur*DS_PGSIZE;
93b2b8c5 581 }
93b2b8c5 582 if (l > 0)
af359dea 583 nefetch(p, b, l);
93b2b8c5 584 }
af359dea
C
585 /* don't forget checksum! */
586 len -= sizeof(struct ether_header) + sizeof(long);
93b2b8c5 587
93b2b8c5
BJ
588 neread(ns,(caddr_t)(ns->ns_pb), len);
589}
590
591/*
592 * Pass a packet to the higher levels.
593 * We deal with the trailer protocol here.
594 */
595neread(ns, buf, len)
596 register struct ne_softc *ns;
597 char *buf;
598 int len;
599{
600 register struct ether_header *eh;
601 struct mbuf *m;
602 int off, resid;
603 register struct ifqueue *inq;
604
605 /*
606 * Deal with trailer protocol: if type is trailer type
607 * get true type from first 16-bit word past data.
608 * Remember that type was trailer by setting off.
609 */
610 eh = (struct ether_header *)buf;
611 eh->ether_type = ntohs((u_short)eh->ether_type);
612#define nedataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
613 if (eh->ether_type >= ETHERTYPE_TRAIL &&
614 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
615 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
616 if (off >= ETHERMTU) return; /* sanity */
617 eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
618 resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
619 if (off + resid > len) return; /* sanity */
620 len = off + resid;
621 } else off = 0;
622
623 if (len == 0) return;
624
625 /*
626 * Pull packet off interface. Off is nonzero if packet
627 * has trailing header; neget will then force this header
628 * information to be at the front, but we still have to drop
629 * the type and length which are at the front of any trailer data.
630 */
631 m = neget(buf, len, off, &ns->ns_if);
632 if (m == 0) return;
633
af359dea 634 ether_input(&ns->ns_if, eh, m);
93b2b8c5
BJ
635}
636
637/*
638 * Supporting routines
639 */
640
641/*
642 * Pull read data off a interface.
643 * Len is length of data, with local net header stripped.
644 * Off is non-zero if a trailer protocol was used, and
645 * gives the offset of the trailer information.
646 * We copy the trailer information and then all the normal
647 * data into mbufs. When full cluster sized units are present
648 * we copy into clusters.
649 */
650struct mbuf *
651neget(buf, totlen, off0, ifp)
652 caddr_t buf;
653 int totlen, off0;
654 struct ifnet *ifp;
655{
656 struct mbuf *top, **mp, *m, *p;
657 int off = off0, len;
658 register caddr_t cp = buf;
af359dea
C
659 char *epkt;
660
661 buf += sizeof(struct ether_header);
662 cp = buf;
663 epkt = cp + totlen;
664
665
666 if (off) {
667 cp += off + 2 * sizeof(u_short);
668 totlen -= 2 * sizeof(u_short);
669 }
670
671 MGETHDR(m, M_DONTWAIT, MT_DATA);
672 if (m == 0)
673 return (0);
674 m->m_pkthdr.rcvif = ifp;
675 m->m_pkthdr.len = totlen;
676 m->m_len = MHLEN;
93b2b8c5 677
93b2b8c5
BJ
678 top = 0;
679 mp = &top;
680 while (totlen > 0) {
af359dea
C
681 if (top) {
682 MGET(m, M_DONTWAIT, MT_DATA);
683 if (m == 0) {
684 m_freem(top);
685 return (0);
686 }
687 m->m_len = MLEN;
688 }
689 len = min(totlen, epkt - cp);
690 if (len >= MINCLSIZE) {
691 MCLGET(m, M_DONTWAIT);
692 if (m->m_flags & M_EXT)
693 m->m_len = len = min(len, MCLBYTES);
93b2b8c5 694 else
af359dea 695 len = m->m_len;
93b2b8c5 696 } else {
93b2b8c5 697 /*
af359dea 698 * Place initial small packet/header at end of mbuf.
93b2b8c5 699 */
af359dea
C
700 if (len < m->m_len) {
701 if (top == 0 && len + max_linkhdr <= m->m_len)
702 m->m_data += max_linkhdr;
703 m->m_len = len;
704 } else
705 len = m->m_len;
93b2b8c5 706 }
af359dea
C
707 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
708 cp += len;
93b2b8c5
BJ
709 *mp = m;
710 mp = &m->m_next;
af359dea
C
711 totlen -= len;
712 if (cp == epkt)
713 cp = buf;
93b2b8c5
BJ
714 }
715 return (top);
93b2b8c5
BJ
716}
717
718/*
719 * Process an ioctl request.
720 */
721neioctl(ifp, cmd, data)
722 register struct ifnet *ifp;
723 int cmd;
724 caddr_t data;
725{
726 register struct ifaddr *ifa = (struct ifaddr *)data;
727 struct ne_softc *ns = &ne_softc[ifp->if_unit];
728 struct ifreq *ifr = (struct ifreq *)data;
729 int s = splimp(), error = 0;
730
731
732 switch (cmd) {
733
734 case SIOCSIFADDR:
735 ifp->if_flags |= IFF_UP;
736
af359dea 737 switch (ifa->ifa_addr->sa_family) {
93b2b8c5
BJ
738#ifdef INET
739 case AF_INET:
740 neinit(ifp->if_unit); /* before arpwhohas */
741 ((struct arpcom *)ifp)->ac_ipaddr =
742 IA_SIN(ifa)->sin_addr;
743 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
744 break;
745#endif
746#ifdef NS
747 case AF_NS:
748 {
749 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
750
751 if (ns_nullhost(*ina))
752 ina->x_host = *(union ns_host *)(ns->ns_addr);
753 else {
754 /*
755 * The manual says we can't change the address
756 * while the receiver is armed,
757 * so reset everything
758 */
759 ifp->if_flags &= ~IFF_RUNNING;
760 bcopy((caddr_t)ina->x_host.c_host,
761 (caddr_t)ns->ns_addr, sizeof(ns->ns_addr));
762 }
763 neinit(ifp->if_unit); /* does ne_setaddr() */
764 break;
765 }
766#endif
767 default:
768 neinit(ifp->if_unit);
769 break;
770 }
771 break;
772
773 case SIOCSIFFLAGS:
774 if ((ifp->if_flags & IFF_UP) == 0 &&
775 ifp->if_flags & IFF_RUNNING) {
776 ifp->if_flags &= ~IFF_RUNNING;
777 outb(nec+ds_cmd,DSCM_STOP|DSCM_NODMA);
778 } else if (ifp->if_flags & IFF_UP &&
779 (ifp->if_flags & IFF_RUNNING) == 0)
780 neinit(ifp->if_unit);
781 break;
782
783#ifdef notdef
784 case SIOCGHWADDR:
785 bcopy((caddr_t)ns->ns_addr, (caddr_t) &ifr->ifr_data,
786 sizeof(ns->ns_addr));
787 break;
788#endif
789
790 default:
791 error = EINVAL;
792 }
793 splx(s);
794 return (error);
795}
93b2b8c5 796#endif