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