FreeBSD/Linux Kernel Cross Reference
sys/dev/isa/if_hp.c
1 /* $NetBSD: if_hp.c,v 1.37 2003/08/07 16:31:07 agc Exp $ */
2
3 /* XXX THIS DRIVER IS BROKEN. IT WILL NOT EVEN COMPILE. */
4
5 /*-
6 * Copyright (c) 1990 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*-
35 * Copyright (c) 1990, 1991 William F. Jolitz.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 */
65
66 /*
67 * HP LAN Ethernet driver
68 *
69 * Parts inspired from Tim Tucker's if_wd driver for the wd8003,
70 * insight on the ne2000 gained from Robert Clements PC/FTP driver.
71 *
72 * receive bottom end totally rewritten by Curt Mayer, Dec 1992.
73 * no longer loses back to back packets.
74 * note to driver writers: RTFM!
75 *
76 * hooks for packet filter added by Charles Hannum, 29DEC1992.
77 *
78 * Mostly rewritten for HP-labelled EISA controllers by Charles Hannum,
79 * 18JAN1993.
80 */
81
82 #include <sys/cdefs.h>
83 __KERNEL_RCSID(0, "$NetBSD: if_hp.c,v 1.37 2003/08/07 16:31:07 agc Exp $");
84
85 #include "hp.h"
86 #if NHP > 0
87
88 #include "opt_inet.h"
89 #include "opt_ns.h"
90 #include "rnd.h"
91
92 #include <sys/param.h>
93 #include <sys/systm.h>
94 #include <sys/mbuf.h>
95 #include <sys/buf.h>
96 #include <sys/protosw.h>
97 #include <sys/socket.h>
98 #include <sys/ioctl.h>
99 #include <sys/errno.h>
100 #include <sys/syslog.h>
101 #if NRND > 0
102 #include <sys/rnd.h>
103 #endif
104
105 #include <net/if.h>
106 #include <net/if_ether.h>
107
108 #ifdef INET
109 #include <netinet/in.h>
110 #include <netinet/in_systm.h>
111 #include <netinet/in_var.h>
112 #include <netinet/ip.h>
113 #include <netinet/if_inarp.h>
114 #endif
115
116 #ifdef NS
117 #include <netns/ns.h>
118 #include <netns/ns_if.h>
119 #endif
120
121 #include "bpfilter.h"
122 #if NBPFILTER > 0
123 #include <sys/select.h>
124 #include <net/bpf.h>
125 #include <net/bpfdesc.h>
126 #endif
127
128 #include <machine/cpu.h>
129 #include <machine/pio.h>
130
131 #include <i386/isa/isa_device.h> /* XXX BROKEN */
132 #include <dev/isa/if_nereg.h>
133 #include <i386/isa/icu.h> /* XXX BROKEN */
134
135 int hpprobe(), hpattach(), hpintr();
136 int hpstart(), hpinit(), ether_output(), hpioctl();
137
138 struct isa_driver hpdriver =
139 {
140 hpprobe, hpattach, "hp",
141 };
142
143 struct mbuf *hpget();
144
145 /*
146 * Ethernet software status per interface.
147 *
148 * Each interface is referenced by a network interface structure,
149 * ns_if, which the routing code uses to locate the interface.
150 * This structure contains the output queue for the interface, its address, ...
151 */
152 struct hp_softc {
153 struct ethercom ns_ec; /* Ethernet common part */
154 #define ns_if ns_ac.ac_if /* network-visible interface */
155 int ns_flags;
156 #define DSF_LOCK 1 /* block re-entering enstart */
157 int ns_oactive;
158 int ns_mask;
159 struct prhdr ns_ph; /* hardware header of incoming packet */
160 u_char ns_pb[2048];
161 u_char ns_txstart; /* transmitter buffer start */
162 u_char ns_rxstart; /* receiver buffer start */
163 u_char ns_rxend; /* receiver buffer end */
164 u_char hp_type; /* HP board type */
165 u_char hp_irq; /* interrupt vector */
166 short ns_port; /* i/o port base */
167 short ns_mode; /* word/byte mode */
168 short ns_rcr;
169 #if NBPFILTER > 0
170 caddr_t ns_bpf;
171 #endif
172 u_int8_t ns_addrp[ETHER_ADDR_LEN]; /* hardware Ethernet address */
173
174 #if NRND > 0
175 rndsource_element_t rnd_source;
176 #endif
177 }
178 hp_softc[NHP];
179 #define ENBUFSIZE (sizeof(struct ether_header) + ETHERMTU + 2 + ETHER_MIN_LEN)
180
181 #define PAT(n) (0xa55a + 37*(n))
182
183 u_short boarddata[16];
184
185 #define hp_option (-8)
186 #define hp_data (-4)
187 #define HP_RUN (0x01)
188 #define HP_DATA (0x10)
189
190 hpprobe(dvp)
191 struct isa_device *dvp;
192 {
193 int val, i, s, sum, pat;
194 struct hp_softc *ns = &hp_softc[0];
195 int hpc;
196
197 #ifdef lint
198 hpintr(0);
199 #endif
200
201 hpc = (ns->ns_port = dvp->id_iobase + 0x10);
202 s = splnet();
203
204 ns->hp_irq = ffs(dvp->id_irq) - 1;
205
206 /* Extract board address */
207 for (i = 0; i < 6; i++)
208 ns->ns_addrp[i] = inb(hpc - 0x10 + i);
209 ns->hp_type = inb(hpc - 0x10 + 7);
210
211 if (ns->ns_addrp[0] != 0x08 ||
212 ns->ns_addrp[1] != 0x00 ||
213 ns->ns_addrp[2] != 0x09) {
214 splx(s);
215 return 0;
216 }
217 /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
218 /* On this board, WTS means 32-bit transfers, which is still
219 * experimental. - mycroft, 18JAN93 */
220 #ifdef HP_32BIT
221 ns->ns_mode = DSDC_WTS | DSDC_BMS | DSDC_FT1;
222 #else
223 ns->ns_mode = DSDC_BMS | DSDC_FT1;
224 #endif
225 ns->ns_txstart = 0 * 1024 / DS_PGSIZE;
226 ns->ns_rxend = 32 * 1024 / DS_PGSIZE;
227
228 ns->ns_rxstart = ns->ns_txstart + (PKTSZ / DS_PGSIZE);
229
230 outb(hpc + hp_option, HP_RUN);
231
232 #if 0
233 outb(hpc + ds0_isr, 0xff);
234 outb(hpc + ds_cmd, DSCM_NODMA | DSCM_PG0 | DSCM_STOP);
235 delay(1000);
236
237 /* Check cmd reg and fail if not right */
238 if ((i = inb(hpc + ds_cmd)) != (DSCM_NODMA | DSCM_PG0 | DSCM_STOP)) {
239 splx(s);
240 return (0);
241 }
242 #endif
243
244 outb(hpc + hp_option, 0);
245
246 splx(s);
247 return (32);
248 }
249 /*
250 * Fetch from onboard ROM/RAM
251 */
252 hpfetch(ns, up, ad, len)
253 struct hp_softc *ns;
254 caddr_t up;
255 {
256 u_char cmd;
257 int hpc = ns->ns_port;
258 int counter = 100000;
259
260 outb(hpc + hp_option, inb(hpc + hp_option) | HP_DATA);
261
262 cmd = inb(hpc + ds_cmd);
263 outb(hpc + ds_cmd, DSCM_NODMA | DSCM_PG0 | DSCM_START);
264
265 /* Setup remote DMA */
266 outb(hpc + ds0_isr, DSIS_RDC);
267
268 if (ns->ns_mode & DSDC_WTS)
269 len = (len + 3) & ~3;
270 else
271 len = (len + 1) & ~1;
272
273 outb(hpc + ds0_rbcr0, len);
274 outb(hpc + ds0_rbcr1, len >> 8);
275 outb(hpc + ds0_rsar0, ad);
276 outb(hpc + ds0_rsar1, ad >> 8);
277
278 #ifdef HP_DEBUG
279 printf("hpfetch: len=%d ioaddr=0x%03x addr=0x%04x option=0x%02x %d-bit\n",
280 len, hpc + hp_data, ad, inb(hpc + hp_option),
281 ns->ns_mode & DSDC_WTS ? 32 : 16);
282 printf("hpfetch: cmd=0x%02x isr=0x%02x ",
283 inb(hpc + ds_cmd), inb(hpc + ds0_isr));
284 outb(hpc + ds_cmd, DSCM_NODMA | DSCM_PG2 | DSCM_START);
285 printf("imr=0x%02x rcr=0x%02x tcr=0x%02x dcr=0x%02x\n",
286 inb(hpc + ds0_imr), inb(hpc + ds0_rcr), inb(hpc + ds0_tcr),
287 inb(hpc + ds0_dcr));
288 #endif
289
290 /* Execute & extract from card */
291 outb(hpc + ds_cmd, DSCM_RREAD | DSCM_PG0 | DSCM_START);
292
293 #ifdef HP_32BIT
294 if (ns->ns_mode & DSDC_WTS)
295 len = (caddr_t) insd(hpc + hp_data, up, len >> 2) - up;
296 else
297 #endif
298 len = (caddr_t) insw(hpc + hp_data, up, len >> 1) - up;
299
300 #ifdef HP_DEBUG
301 printf("hpfetch: done len=%d\n", len);
302 #endif
303
304 /* Wait till done, then shutdown feature */
305 while ((inb(hpc + ds0_isr) & DSIS_RDC) == 0 && counter-- > 0);
306 outb(hpc + ds0_isr, DSIS_RDC);
307 outb(hpc + ds_cmd, cmd);
308
309 outb(hpc + hp_option, inb(hpc + hp_option) & ~HP_DATA);
310 }
311 /*
312 * Put to onboard RAM
313 */
314 hpput(ns, up, ad, len)
315 struct hp_softc *ns;
316 caddr_t up;
317 {
318 u_char cmd;
319 int hpc = ns->ns_port;
320 int counter = 100000;
321
322 outb(hpc + hp_option, inb(hpc + hp_option) | HP_DATA);
323
324 cmd = inb(hpc + ds_cmd);
325 outb(hpc + ds_cmd, DSCM_NODMA | DSCM_PG0 | DSCM_START);
326
327 /* Setup for remote DMA */
328 outb(hpc + ds0_isr, DSIS_RDC);
329
330 if (ns->ns_mode & DSDC_WTS)
331 len = (len + 3) & ~3;
332 else
333 len = (len + 1) & ~1;
334
335 #ifdef HP_DEBUG
336 printf("hpput: len=%d ioaddr=0x%03x addr=0x%04x option=0x%02x %d-bit\n",
337 len, hpc + hp_data, ad, inb(hpc + hp_option),
338 ns->ns_mode & DSDC_WTS ? 32 : 16);
339 printf("hpput: cmd=0x%02x isr=0x%02x ",
340 inb(hpc + ds_cmd), inb(hpc + ds0_isr));
341 outb(hpc + ds_cmd, DSCM_NODMA | DSCM_PG2 | DSCM_START);
342 printf("imr=0x%02x rcr=0x%02x tcr=0x%02x dcr=0x%02x\n",
343 inb(hpc + ds0_imr), inb(hpc + ds0_rcr), inb(hpc + ds0_tcr),
344 inb(hpc + ds0_dcr));
345 {
346 unsigned char *p = (unsigned char *) up;
347 int n = len;
348 printf("hpput:");
349 while (n--)
350 printf(" %02x", *(p++));
351 printf("\n");
352 }
353 #endif
354
355 outb(hpc + ds_cmd, DSCM_NODMA | DSCM_PG0 | DSCM_START);
356 outb(hpc + ds0_rbcr0, 0xff);
357 outb(hpc + ds_cmd, DSCM_RREAD | DSCM_PG0 | DSCM_START);
358
359 outb(hpc + ds0_rbcr0, len);
360 outb(hpc + ds0_rbcr1, len >> 8);
361 outb(hpc + ds0_rsar0, ad);
362 outb(hpc + ds0_rsar1, ad >> 8);
363
364 /* Execute & stuff to card */
365 outb(hpc + ds_cmd, DSCM_RWRITE | DSCM_PG0 | DSCM_START);
366
367 #ifdef HP_32BIT
368 if (ns->ns_mode & DSDC_WTS)
369 len = (caddr_t) outsd(hpc + hp_data, up, len >> 2) - up;
370 else
371 #endif
372 len = (caddr_t) outsw(hpc + hp_data, up, len >> 1) - up;
373
374 #ifdef HP_DEBUG
375 printf("hpput: done len=%d\n", len);
376 #endif
377
378 /* Wait till done, then shutdown feature */
379 while ((inb(hpc + ds0_isr) & DSIS_RDC) == 0 && counter-- > 0);
380 outb(hpc + ds0_isr, DSIS_RDC);
381 outb(hpc + ds_cmd, cmd);
382
383 outb(hpc + hp_option, inb(hpc + hp_option) & ~HP_DATA);
384 }
385 /*
386 * Reset of interface.
387 */
388 hpreset(unit, uban)
389 int unit, uban;
390 {
391 struct hp_softc *ns = &hp_softc[unit];
392 int hpc = ns->ns_port;
393 if (unit >= NHP)
394 return;
395 printf("hp%d: reset\n", unit);
396 outb(hpc + hp_option, 0);
397 ns->ns_flags &= ~DSF_LOCK;
398 hpinit(unit);
399 }
400
401 static char *
402 hp_id(type)
403 u_char type;
404 {
405 static struct {
406 u_char type;
407 char *name;
408 } boards[] = {
409 {
410 0x00, "hp27240"
411 }, {
412 0x10, "hp24240"
413 }, {
414 0x01, "hp27245"
415 }, {
416 0x02, "hp27250"
417 }, {
418 0x81, "hp27247"
419 }, {
420 0x91, "hp27247r1"
421 }
422 };
423 int n = sizeof(boards) / sizeof(boards[0]);
424
425 while (n)
426 if (boards[--n].type == type)
427 return boards[n].name;
428
429 return "UNKNOWN";
430 }
431 /*
432 * Interface exists: make available by filling in network interface
433 * record. System will initialize the interface when it is ready
434 * to accept packets. We get the ethernet address here.
435 */
436 hpattach(dvp)
437 struct isa_device *dvp;
438 {
439 int unit = dvp->id_unit;
440 struct hp_softc *ns = &hp_softc[unit];
441 struct ifnet *ifp = &ns->ns_if;
442
443 ifp->if_unit = unit;
444 ifp->if_name = hpdriver.name;
445 ifp->if_mtu = ETHERMTU;
446 printf("hp%d: %s %d-bit ethernet address %s\n", unit,
447 hp_id(ns->hp_type), ns->ns_mode & DSDC_WTS ? 32 : 16,
448 ether_sprintf(ns->ns_addrp));
449 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
450 ifp->if_output = ether_output;
451 ifp->if_start = hpstart;
452 ifp->if_ioctl = hpioctl;
453 ifp->if_reset = hpreset;
454 ifp->if_watchdog = 0;
455 IFQ_SET_READY(&ifp->if_snd);
456 if_attach(ifp);
457
458 #if NBPFILTER > 0
459 bpfattach(&ns->ns_bpf, ifp, DLT_EN10MB,
460 sizeof(struct ether_header));
461 #endif
462
463 #if NRND > 0
464 rnd_attach_source(&ns->rnd_source, ns->sc_dev.dv_xname,
465 RND_TYPE_NET, 0);
466 #endif
467
468 }
469 /*
470 * Initialization of interface; set up initialization block
471 * and transmit/receive descriptor rings.
472 */
473 hpinit(unit)
474 int unit;
475 {
476 struct hp_softc *ns = &hp_softc[unit];
477 struct ifnet *ifp = &ns->ns_if;
478 int s;
479 int i;
480 char *cp;
481 int hpc = ns->ns_port;
482
483 if (ifp->if_addrlist == (struct ifaddr *) 0)
484 return;
485 if (ifp->if_flags & IFF_RUNNING)
486 return;
487
488 s = splnet();
489
490 #ifdef HP_DEBUG
491 printf("hpinit: hp%d at 0x%x irq %d\n", unit, hpc, (int) ns->hp_irq);
492 printf("hpinit: promiscuous mode %s\n",
493 ns->ns_if.if_flags & IFF_PROMISC ? "on" : "off");
494 #endif
495
496 ns->ns_rcr = (ns->ns_if.if_flags & IFF_BROADCAST ? DSRC_AB : 0) |
497 (ns->ns_if.if_flags & IFF_PROMISC ? DSRC_PRO : 0);
498 #ifdef HP_LOG_ERRORS
499 ns->ns_rcr |= DSRC_SEP;
500 #endif
501
502 /* set irq and turn on board */
503 outb(hpc + hp_option, HP_RUN | (ns->hp_irq << 1));
504
505 /* init regs */
506 outb(hpc + ds_cmd, DSCM_NODMA | DSCM_PG0 | DSCM_STOP);
507 outb(hpc + ds0_dcr, 0);
508 outb(hpc + ds0_rbcr0, 0);
509 outb(hpc + ds0_rbcr1, 0);
510 outb(hpc + ds0_rcr, DSRC_MON);
511 outb(hpc + ds0_tpsr, ns->ns_txstart);
512 outb(hpc + ds0_imr, 0);
513 outb(hpc + ds0_tcr, DSTC_LB0);
514 outb(hpc + ds0_pstart, ns->ns_rxstart);
515 outb(hpc + ds0_bnry, ns->ns_rxend - 1);
516 outb(hpc + ds0_pstop, ns->ns_rxend);
517 outb(hpc + ds0_isr, 0xff);
518 outb(hpc + ds_cmd, DSCM_NODMA | DSCM_PG1 | DSCM_STOP);
519 outb(hpc + ds1_curr, ns->ns_rxstart);
520
521 /* set physical address on ethernet */
522 for (i = 0; i < 6; i++)
523 outb(hpc + ds1_par0 + i, ns->ns_addrp[i]);
524
525 /* clr logical address hash filter for now */
526 for (i = 0; i < 8; i++)
527 outb(hpc + ds1_mar0 + i, 0xff);
528
529 /* fire it up */
530 outb(hpc + ds_cmd, DSCM_NODMA | DSCM_PG0 | DSCM_START);
531 outb(hpc + ds0_dcr, ns->ns_mode);
532 outb(hpc + ds0_rcr, ns->ns_rcr);
533 outb(hpc + ds0_tcr, 0);
534 outb(hpc + ds0_imr, 0xff);
535
536 ns->ns_if.if_flags |= IFF_RUNNING;
537 ns->ns_flags &= ~DSF_LOCK;
538 ns->ns_oactive = 0;
539 ns->ns_mask = ~0;
540 hpstart(ifp);
541
542 #ifdef HP_DEBUG
543 printf("hpinit: done\n", unit, hpc);
544 #endif
545
546 splx(s);
547 }
548 /*
549 * Setup output on interface.
550 * Get another datagram to send off of the interface queue,
551 * and map it to the interface before starting the output.
552 * called only at splnet or interrupt level.
553 */
554 hpstart(ifp)
555 struct ifnet *ifp;
556 {
557 struct hp_softc *ns = &hp_softc[ifp->if_unit];
558 struct mbuf *m0, *m;
559 int buffer;
560 int len, i, total;
561 int hpc = ns->ns_port;
562
563 /*
564 * The DS8390 has only one transmit buffer, if it is busy we
565 * must wait until the transmit interrupt completes.
566 */
567 if (ns->ns_flags & DSF_LOCK)
568 return;
569
570 if (inb(hpc + ds_cmd) & DSCM_TRANS)
571 return;
572
573 if ((ns->ns_if.if_flags & IFF_RUNNING) == 0)
574 return;
575
576 IFQ_DEQUEUE(&ns->ns_if.if_snd, m);
577
578 if (m == 0)
579 return;
580
581 /*
582 * Copy the mbuf chain into the transmit buffer
583 */
584
585 ns->ns_flags |= DSF_LOCK; /* prevent entering hpstart */
586 buffer = ns->ns_txstart * DS_PGSIZE;
587 i = 0;
588 total = len = m->m_pkthdr.len;
589
590 #ifdef HP_DEBUG
591 printf("hpstart: len=%d\n", len);
592 #endif
593
594 #if NBPFILTER > 0
595 if (ns->ns_bpf)
596 bpf_mtap(ns->ns_bpf, m);
597 #endif
598
599 for (m0 = m; m != 0;) {
600 if (m->m_len & 1 && t > m->m_len) {
601 m->m_len -= 1;
602 hpput(ns, mtod(m, caddr_t), buffer, m->m_len);
603 t -= m->m_len;
604 buffer += m->m_len;
605 m->m_data += m->m_len;
606 m->m_len = 1;
607 m = m_pullup(m, 2);
608 } else {
609 hpput(ns, mtod(m, caddr_t), buffer, m->m_len);
610 t -= m->m_len;
611 buffer += m->m_len;
612 MFREE(m, m0);
613 m = m0;
614 }
615 }
616
617 /*
618 * Init transmit length registers, and set transmit start flag.
619 */
620 len = total;
621 if (len < ETHER_MIN_LEN)
622 len = ETHER_MIN_LEN;
623 #error broken here ! need to set to 0 the pad space in buffer !
624 outb(hpc + ds_cmd, DSCM_NODMA | DSCM_PG0 | DSCM_START);
625 outb(hpc + ds0_tbcr0, len & 0xff);
626 outb(hpc + ds0_tbcr1, (len >> 8) & 0xff);
627 outb(hpc + ds0_tpsr, ns->ns_txstart);
628 outb(hpc + ds_cmd, DSCM_TRANS | DSCM_NODMA | DSCM_PG0 | DSCM_START);
629
630 #ifdef HP_DEBUG
631 printf("hpstart: done\n", hpc);
632 #endif
633 }
634 /*
635 * Controller interrupt.
636 */
637 hpintr(unit)
638 {
639 struct hp_softc *ns = &hp_softc[unit];
640 u_char cmd, isr;
641 int hpc = ns->ns_port;
642 u_char err;
643
644 /* Save cmd, clear interrupt */
645 cmd = inb(hpc + ds_cmd);
646 loop:
647 isr = inb(hpc + ds0_isr);
648 outb(hpc + ds_cmd, DSCM_NODMA | DSCM_PG0 | DSCM_START);
649 outb(hpc + ds0_isr, isr);
650
651 /* Receiver error */
652 if (isr & DSIS_RXE) {
653 /* need to read these registers to clear status */
654 err = inb(hpc + ds0_rsr);
655 (void) inb(hpc + 0xD);
656 (void) inb(hpc + 0xE);
657 (void) inb(hpc + 0xF);
658 ns->ns_if.if_ierrors++;
659 #ifdef HP_LOG_ERRORS
660 isr |= DSIS_RX;
661 #endif
662 }
663 /* We received something */
664 if (isr & DSIS_RX) {
665 u_char bnry;
666 u_char curr;
667 u_short addr;
668 int len;
669 int i;
670 unsigned char c;
671
672 while (1) {
673 outb(hpc + ds_cmd, DSCM_START | DSCM_NODMA | DSCM_PG0);
674 bnry = inb(hpc + ds0_bnry);
675 outb(hpc + ds_cmd, DSCM_START | DSCM_NODMA | DSCM_PG1);
676 curr = inb(hpc + ds1_curr);
677
678 #ifdef HP_DEBUG
679 printf("hpintr: receive isr=0x%02x bnry=0x%02x curr=0x%02x\n",
680 isr, bnry, curr);
681 #endif
682
683 if (++bnry >= ns->ns_rxend)
684 bnry = ns->ns_rxstart;
685
686 /* if ring empty, done! */
687 if (bnry == curr)
688 break;
689
690 addr = bnry * DS_PGSIZE;
691
692 outb(hpc + hp_option, inb(hpc + hp_option) | HP_DATA);
693
694 #if 0
695 /* send packet with auto packet release */
696 outb(hpc + ds_cmd, DSCM_START | DSCM_NODMA | DSCM_PG0);
697 outb(hpc + ds0_rbcr1, 0x0f);
698 outb(hpc + ds0_dcr, ns->ns_mode | DSDC_AR);
699 outb(hpc + ds_cmd, DSCM_SENDP | DSCM_PG0 | DSCM_START);
700 #endif
701
702 /* get length */
703 hpfetch(ns, (caddr_t) & ns->ns_ph, addr, sizeof ns->ns_ph);
704 addr += sizeof ns->ns_ph;
705
706 #ifdef HP_DEBUG
707 printf("hpintr: sendp packet hdr: %x %x %x %x\n",
708 ns->ns_ph.pr_status,
709 ns->ns_ph.pr_nxtpg,
710 ns->ns_ph.pr_sz0,
711 ns->ns_ph.pr_sz1);
712 #endif
713
714 #ifdef HP_LOG_ERRORS
715 if (ns->ns_ph.pr_status & (DSRS_CRC | DSRS_FO | DSRS_DFR)) {
716 /* Get packet header */
717 if (len > 14)
718 len = 14;
719 hpfetch(ns, (caddr_t) (ns->ns_pb), addr, len);
720
721 /* move boundary up */
722 bnry = ns->ns_ph.pr_nxtpg;
723 if (--bnry < ns->ns_rxstart)
724 bnry = ns->ns_rxend - 1;
725 outb(hpc + ds_cmd, DSCM_START | DSCM_NODMA | DSCM_PG0);
726 outb(hpc + ds0_bnry, bnry);
727
728 printf("hp%d: receive error status=0x%02x\n", unit,
729 ns->ns_ph.pr_status);
730 printf("hp%d: packet header:", unit);
731 {
732 int n;
733 for (n = 0; n < len; n++)
734 printf(" %02x", ns->ns_pb[n]);
735 }
736 printf("\n");
737
738 continue;
739 }
740 #endif
741
742 ns->ns_if.if_ipackets++;
743 len = ns->ns_ph.pr_sz0 + (ns->ns_ph.pr_sz1 << 8);
744 if (len < ETHER_MIN_LEN || len > ETHER_MAX_LEN) {
745 printf("hpintr: bnry %x curr %x\n", bnry, curr);
746 printf("hpintr: packet hdr: %x %x %x %x\n",
747 ns->ns_ph.pr_status,
748 ns->ns_ph.pr_nxtpg,
749 ns->ns_ph.pr_sz0,
750 ns->ns_ph.pr_sz1);
751 printf("isr = 0x%x reg_isr=0x%x\n",
752 isr, inb(hpc + ds0_isr));
753 outb(hpc + ds_cmd, DSCM_START | DSCM_NODMA | DSCM_PG0);
754 bnry = inb(hpc + ds0_bnry);
755 outb(hpc + ds_cmd, DSCM_START | DSCM_NODMA | DSCM_PG1);
756 curr = inb(hpc + ds1_curr);
757 printf("hpintr: new bnry %x curr %x\n", bnry, curr);
758 printf("hpintr: bad len %d\n-hanging-\n",
759 len);
760 while (1);
761 }
762 /* read packet */
763 hpfetch(ns, (caddr_t) (ns->ns_pb), addr, len);
764
765 /* move boundary up */
766 bnry = ns->ns_ph.pr_nxtpg;
767 if (--bnry < ns->ns_rxstart)
768 bnry = ns->ns_rxend - 1;
769 outb(hpc + ds_cmd, DSCM_START | DSCM_NODMA | DSCM_PG0);
770 outb(hpc + ds0_bnry, bnry);
771
772 #ifdef HP_DEBUG
773 printf("hpintr: receive done bnry=0x%02x\n", bnry);
774 #endif
775
776 outb(hpc + hp_option, inb(hpc + hp_option) & ~HP_DATA);
777
778 /* adjust for ether header and checksum */
779 len -= sizeof(struct ether_header) + sizeof(long);
780
781 /* process packet */
782 hpread(ns, (caddr_t) (ns->ns_pb), len);
783 }
784 }
785 /* Transmit error */
786 if (isr & DSIS_TXE) {
787 ns->ns_flags &= ~DSF_LOCK;
788 /* Need to read these registers to clear status */
789 ns->ns_if.if_collisions += inb(hpc + ds0_tbcr0);
790 ns->ns_if.if_oerrors++;
791 }
792 /* Packet Transmitted */
793 if (isr & DSIS_TX) {
794 ns->ns_flags &= ~DSF_LOCK;
795 ++ns->ns_if.if_opackets;
796 ns->ns_if.if_collisions += inb(hpc + ds0_tbcr0);
797 }
798 /* Receiver ovverun? */
799 if (isr & DSIS_ROVRN) {
800 log(LOG_ERR, "hp%d: error: isr %x\n", ns - hp_softc, isr
801 /* , DSIS_BITS */ );
802 outb(hpc + ds0_rbcr0, 0);
803 outb(hpc + ds0_rbcr1, 0);
804 outb(hpc + ds0_tcr, DSTC_LB0);
805 outb(hpc + ds0_rcr, DSRC_MON);
806 outb(hpc + ds_cmd, DSCM_START | DSCM_NODMA);
807 outb(hpc + ds0_rcr, ns->ns_rcr);
808 outb(hpc + ds0_tcr, 0);
809 }
810 /* Any more to send? */
811 outb(hpc + ds_cmd, DSCM_NODMA | DSCM_PG0 | DSCM_START);
812 hpstart(&ns->ns_if);
813 outb(hpc + ds_cmd, cmd);
814 outb(hpc + ds0_imr, 0xff);
815
816 #if NRND > 0
817 if (irs)
818 rnd_add_uint32(&sc->rnd_source, isr);
819 #endif
820
821 /* Still more to do? */
822 isr = inb(hpc + ds0_isr);
823 if (isr)
824 goto loop;
825 }
826 /*
827 * Pass a packet to the higher levels.
828 * We deal with the trailer protocol here.
829 */
830 hpread(ns, buf, len)
831 struct hp_softc *ns;
832 char *buf;
833 int len;
834 {
835 struct ether_header *eh;
836 struct mbuf *m;
837 int off, resid;
838 struct ifqueue *inq;
839 u_short etype;
840
841 /*
842 * Deal with trailer protocol: if type is trailer type
843 * get true type from first 16-bit word past data.
844 * Remember that type was trailer by setting off.
845 */
846 eh = (struct ether_header *) buf;
847 etype = ntohs((u_short) eh->ether_type);
848 #define hpdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off))))
849 if (etype >= ETHERTYPE_TRAIL &&
850 etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) {
851 off = (etype - ETHERTYPE_TRAIL) * 512;
852 if (off >= ETHERMTU)
853 return; /* sanity */
854 eh->ether_type = *hpdataaddr(eh, off, u_short *);
855 resid = ntohs(*(hpdataaddr(eh, off + 2, u_short *)));
856 if (off + resid > len)
857 return; /* sanity */
858 len = off + resid;
859 } else
860 off = 0;
861
862 if (len == 0)
863 return;
864
865 #if NBPFILTER > 0
866 if (ns->ns_bpf)
867 bpf_tap(ns->ns_bpf, buf, len + sizeof(struct ether_header));
868 #endif
869
870 if ((ns->ns_if.if_flags & IFF_PROMISC)
871 && memcmp(eh->ether_dhost, ns->ns_addrp,
872 sizeof(eh->ether_dhost)) != 0
873 && memcmp(eh->ether_dhost, etherbroadcastaddr,
874 sizeof(eh->ether_dhost)) != 0)
875 return;
876
877 /*
878 * Pull packet off interface. Off is nonzero if packet
879 * has trailing header; hpget will then force this header
880 * information to be at the front, but we still have to drop
881 * the type and length which are at the front of any trailer data.
882 */
883 m = hpget(buf, len, off, &ns->ns_if);
884 if (m == 0)
885 return;
886
887 ether_input(&ns->ns_if, eh, m);
888 }
889 /*
890 * Supporting routines
891 */
892
893 /*
894 * Pull read data off a interface.
895 * Len is length of data, with local net header stripped.
896 * Off is non-zero if a trailer protocol was used, and
897 * gives the offset of the trailer information.
898 * We copy the trailer information and then all the normal
899 * data into mbufs. When full cluster sized units are present
900 * we copy into clusters.
901 */
902 struct mbuf *
903 hpget(buf, totlen, off0, ifp)
904 caddr_t buf;
905 int totlen, off0;
906 struct ifnet *ifp;
907 {
908 struct mbuf *top, **mp, *m, *p;
909 int off = off0, len;
910 caddr_t cp = buf;
911 char *epkt;
912
913 buf += sizeof(struct ether_header);
914 cp = buf;
915 epkt = cp + totlen;
916
917
918 if (off) {
919 cp += off + 2 * sizeof(u_short);
920 totlen -= 2 * sizeof(u_short);
921 }
922 MGETHDR(m, M_DONTWAIT, MT_DATA);
923 if (m == 0)
924 return (0);
925 m->m_pkthdr.rcvif = ifp;
926 m->m_pkthdr.len = totlen;
927 m->m_len = MHLEN;
928
929 top = 0;
930 mp = ⊤
931 while (totlen > 0) {
932 if (top) {
933 MGET(m, M_DONTWAIT, MT_DATA);
934 if (m == 0) {
935 m_freem(top);
936 return (0);
937 }
938 m->m_len = MLEN;
939 }
940 len = min(totlen, epkt - cp);
941 if (len >= MINCLSIZE) {
942 MCLGET(m, M_DONTWAIT);
943 if (m->m_flags & M_EXT)
944 m->m_len = len = min(len, MCLBYTES);
945 else
946 len = m->m_len;
947 } else {
948 /*
949 * Place initial small packet/header at end of mbuf.
950 */
951 if (len < m->m_len) {
952 if (top == 0 && len + max_linkhdr <= m->m_len)
953 m->m_data += max_linkhdr;
954 m->m_len = len;
955 } else
956 len = m->m_len;
957 }
958 memcpy(mtod(m, caddr_t), cp, (unsigned) len);
959 cp += len;
960 *mp = m;
961 mp = &m->m_next;
962 totlen -= len;
963 if (cp == epkt)
964 cp = buf;
965 }
966 return (top);
967 }
968 /*
969 * Process an ioctl request.
970 */
971 hpioctl(ifp, cmd, data)
972 struct ifnet *ifp;
973 u_long cmd;
974 caddr_t data;
975 {
976 struct ifaddr *ifa = (struct ifaddr *) data;
977 struct hp_softc *ns = &hp_softc[ifp->if_unit];
978 struct ifreq *ifr = (struct ifreq *) data;
979 int s = splnet(), error = 0;
980
981
982 switch (cmd) {
983
984 case SIOCSIFADDR:
985 ifp->if_flags |= IFF_UP;
986
987 switch (ifa->ifa_addr->sa_family) {
988 #ifdef INET
989 case AF_INET:
990 hpinit(ifp->if_unit); /* before arpwhohas */
991 ((struct arpcom *) ifp)->ac_ipaddr =
992 IA_SIN(ifa)->sin_addr;
993 arpwhohas((struct arpcom *) ifp, &IA_SIN(ifa)->sin_addr);
994 break;
995 #endif
996 #ifdef NS
997 case AF_NS:
998 {
999 struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
1000
1001 if (ns_nullhost(*ina))
1002 ina->x_host = *(union ns_host *) (ns->ns_addrp);
1003 else {
1004 /*
1005 * The manual says we can't change the address
1006 * while the receiver is armed,
1007 * so reset everything
1008 */
1009 ifp->if_flags &= ~IFF_RUNNING;
1010 memcpy((caddr_t) ns->ns_addrp,
1011 (caddr_t) ina->x_host.c_host,
1012 sizeof(ns->ns_addrp));
1013 }
1014 hpinit(ifp->if_unit); /* does hp_setaddr() */
1015 break;
1016 }
1017 #endif
1018 default:
1019 hpinit(ifp->if_unit);
1020 break;
1021 }
1022 break;
1023
1024 case SIOCSIFFLAGS:
1025 #ifdef HP_DEBUG
1026 printf("hp: setting flags, up: %s, running: %s\n",
1027 ifp->if_flags & IFF_UP ? "yes" : "no",
1028 ifp->if_flags & IFF_RUNNING ? "yes" : "no");
1029 #endif
1030 if ((ifp->if_flags & IFF_UP) == 0 &&
1031 ifp->if_flags & IFF_RUNNING) {
1032 ifp->if_flags &= ~IFF_RUNNING;
1033 outb(ns->ns_port + ds_cmd, DSCM_STOP | DSCM_NODMA);
1034 } else
1035 if (ifp->if_flags & IFF_UP &&
1036 (ifp->if_flags & IFF_RUNNING) == 0)
1037 hpinit(ifp->if_unit);
1038 break;
1039
1040 #ifdef notdef
1041 case SIOCGHWADDR:
1042 memcpy((caddr_t) & ifr->ifr_data, (caddr_t) ns->ns_addrp,
1043 sizeof(ns->ns_addrp));
1044 break;
1045 #endif
1046
1047 default:
1048 error = EINVAL;
1049 }
1050 splx(s);
1051 return (error);
1052 }
1053 #endif
Cache object: d7f99744d3ff943c5c7a3fa76016b3e1
|