|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989 Carnegie Mellon University
4: * All Rights Reserved.
5: *
6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
11: *
12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15: *
16: * Carnegie Mellon requests users of this software to return to
17: *
18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
22: *
23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: * Olivetti PC586 Mach Ethernet driver v1.0
28: * Copyright Ing. C. Olivetti & C. S.p.A. 1988, 1989
29: * All rights reserved.
30: *
31: */
32:
33: /*
34: Copyright 1988, 1989 by Olivetti Advanced Technology Center, Inc.,
35: Cupertino, California.
36:
37: All Rights Reserved
38:
39: Permission to use, copy, modify, and distribute this software and
40: its documentation for any purpose and without fee is hereby
41: granted, provided that the above copyright notice appears in all
42: copies and that both the copyright notice and this permission notice
43: appear in supporting documentation, and that the name of Olivetti
44: not be used in advertising or publicity pertaining to distribution
45: of the software without specific, written prior permission.
46:
47: OLIVETTI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
48: INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
49: IN NO EVENT SHALL OLIVETTI BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
50: CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
51: LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
52: NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUR OF OR IN CONNECTION
53: WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
54: */
55:
56: /*
57: Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
58:
59: All Rights Reserved
60:
61: Permission to use, copy, modify, and distribute this software and
62: its documentation for any purpose and without fee is hereby
63: granted, provided that the above copyright notice appears in all
64: copies and that both the copyright notice and this permission notice
65: appear in supporting documentation, and that the name of Intel
66: not be used in advertising or publicity pertaining to distribution
67: of the software without specific, written prior permission.
68:
69: INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
70: INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
71: IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
72: CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
73: LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
74: NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
75: WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
76: */
77:
78: /*
79: * NOTE:
80: * by rvb:
81: * 1. The best book on the 82586 is:
82: * LAN Components User's Manual by Intel
83: * The copy I found was dated 1984. This really tells you
84: * what the state machines are doing
85: * 2. In the current design, we only do one write at a time,
86: * though the hardware is capable of chaining and possibly
87: * even batching. The problem is that we only make one
88: * transmit buffer available in sram space.
89: * 3.
90: * n. Board Memory Map
91: RFA/FD 0 - 227 0x228 bytes
92: 226 = 0x19 * 0x16 bytes
93: RBD 228 - 3813 0x35ec bytes
94: 35e8 = 0x19 * 0x228 bytes
95: == 0x0a bytes (bd) + 2 bytes + 21c bytes
96: CU 3814 - 3913 0x100 bytes
97: TBD 3914 - 39a3 0x90 bytes
98: 90 = No 18 * 0x08 bytes
99: TBUF 39a4 - 3fdd 0x63a bytes (= 1594(10))
100: SCB 3fde - 3fed 0x10 bytes
101: ISCP 3fee - 3ff5 0x08 bytes
102: SCP 3ff6 - 3fff 0x0a bytes
103: *
104: */
105:
106: /*
107: * NOTE:
108: *
109: * Currently this driver doesn't support trailer protocols for
110: * packets. Once that is added, please remove this comment.
111: *
112: * Also, some lacking material includes the DLI code. If you
113: * are compiling this driver with DLI set, lookout, that code
114: * has not been looked at.
115: *
116: */
117:
118: #define DEBUG
119: #define IF_CNTRS MACH
120: #define NDLI 0
121:
122: #include <pc586.h>
123:
124: #ifdef MACH_KERNEL
125: #include <kern/time_out.h>
126: #include <device/device_types.h>
127: #include <device/errno.h>
128: #include <device/io_req.h>
129: #include <device/if_hdr.h>
130: #include <device/if_ether.h>
131: #include <device/net_status.h>
132: #include <device/net_io.h>
133: #else MACH_KERNEL
134: #include <sys/param.h>
135: #include <mach/machine/vm_param.h>
136: #include <sys/systm.h>
137: #include <sys/mbuf.h>
138: #include <sys/buf.h>
139: #include <sys/protosw.h>
140: #include <sys/socket.h>
141: #include <sys/vmmac.h>
142: #include <sys/ioctl.h>
143: #include <sys/errno.h>
144: #include <sys/syslog.h>
145:
146: #include <net/if.h>
147: #include <net/netisr.h>
148: #include <net/route.h>
149:
150: #ifdef INET
151: #include <netinet/in.h>
152: #include <netinet/in_systm.h>
153: #include <netinet/in_var.h>
154: #include <netinet/ip.h>
155: #include <netinet/if_ether.h>
156: #endif
157:
158: #ifdef NS
159: #include <netns/ns.h>
160: #include <netns/ns_if.h>
161: #endif
162:
163: #if DLI
164: #include <net/dli_var.h>
165: struct dli_var de_dlv[NDE];
166: #endif DLI
167: #endif MACH_KERNEL
168:
169: #include <i386/ipl.h>
170: #include <mach/vm_param.h>
171: #include <vm/vm_kern.h>
172: #include <chips/busses.h>
173: #include <i386at/if_pc586.h>
174:
175: #define SPLNET spl6
176: #if __STDC__
177: #define CMD(x, y, unit) *(u_short *)(pc_softc[unit].prom + OFFSET_ ## x) = (u_short) (y)
178: #else __STDC__
179: #define CMD(x, y, unit) *(u_short *)(pc_softc[unit].prom + OFFSET_/**/x) = (u_short) (y)
180: #endif __STDC__
181:
182: #define pc586chatt(unit) CMD(CHANATT, 0x0001, unit)
183: #define pc586inton(unit) CMD(INTENAB, CMD_1, unit)
184: #define pc586intoff(unit) CMD(INTENAB, CMD_0, unit)
185:
186: int pc586probe();
187: void pc586attach();
188: int pc586intr(), pc586init(), pc586output(), pc586ioctl(), pc586reset();
189: int pc586watch(), pc586rcv(), pc586xmt(), pc586bldcu();
190: int pc586diag(), pc586config();
191: char *pc586bldru();
192: char *ram_to_ptr();
193: u_short ptr_to_ram();
194:
195: static vm_offset_t pc586_std[NPC586] = { 0 };
196: static struct bus_device *pc586_info[NPC586];
197: struct bus_driver pcdriver =
198: {pc586probe, 0, pc586attach, 0, pc586_std, "pc", pc586_info, 0, 0, 0};
199:
200: char t_packet[ETHERMTU + sizeof(struct ether_header) + sizeof(long)];
201: int xmt_watch = 0;
202:
203: typedef struct {
204: #ifdef MACH_KERNEL
205: struct ifnet ds_if; /* generic interface header */
206: u_char ds_addr[6]; /* Ethernet hardware address */
207: #else MACH_KERNEL
208: struct arpcom pc586_ac;
209: #define ds_if pc586_ac.ac_if
210: #define ds_addr pc586_ac.ac_enaddr
211: #endif MACH_KERNEL
212: int flags;
213: int seated;
214: int timer;
215: int open;
216: fd_t *begin_fd;
217: fd_t *end_fd;
218: rbd_t *end_rbd;
219: char *prom;
220: char *sram;
221: int tbusy;
222: short mode;
223: } pc_softc_t;
224: pc_softc_t pc_softc[NPC586];
225:
226: struct pc586_cntrs {
227: struct {
228: u_int xmt, xmti;
229: u_int defer;
230: u_int busy;
231: u_int sleaze, intrinsic, intrinsic_count;
232: u_int chain;
233: } xmt;
234: struct {
235: u_int rcv;
236: u_int ovw;
237: u_int crc;
238: u_int frame;
239: u_int rscerrs, ovrnerrs;
240: u_int partial, bad_chain, fill;
241: } rcv;
242: u_int watch;
243: } pc586_cntrs[NPC586];
244:
245:
246: #ifdef IF_CNTRS
247: int pc586_narp = 1, pc586_arp = 0;
248: int pc586_ein[32], pc586_eout[32];
249: int pc586_lin[128/8], pc586_lout[128/8];
250: static
251: log_2(no)
252: unsigned long no;
253: {
254: return ({ unsigned long _temp__;
255: asm("bsr %1, %0; jne 0f; xorl %0, %0; 0:" :
256: "=r" (_temp__) : "a" (no));
257: _temp__;});
258: }
259: #endif IF_CNTRS
260:
261: /*
262: * pc586probe:
263: *
264: * This function "probes" or checks for the pc586 board on the bus to see
265: * if it is there. As far as I can tell, the best break between this
266: * routine and the attach code is to simply determine whether the board
267: * is configured in properly. Currently my approach to this is to write
268: * and read a word from the SRAM on the board being probed. If the word
269: * comes back properly then we assume the board is there. The config
270: * code expects to see a successful return from the probe routine before
271: * attach will be called.
272: *
273: * input : address device is mapped to, and unit # being checked
274: * output : a '1' is returned if the board exists, and a 0 otherwise
275: *
276: */
277: pc586probe(port, dev)
278: struct bus_device *dev;
279: {
280: caddr_t addr = (caddr_t)dev->address;
281: int unit = dev->unit;
282: int len = round_page(0x4000);
283: int sram_len = round_page(0x4000);
284: extern vm_offset_t phys_last_addr;
285: int i;
286: volatile char *b_prom;
287: volatile char *b_sram;
288: volatile u_short*t_ps;
289:
290: if ((unit < 0) || (unit > NPC586)) {
291: printf("pc%d: board out of range [0..%d]\n",
292: unit, NPC586);
293: return(0);
294: }
295: if ((addr > (caddr_t)0x100000) && (addr < (caddr_t)phys_last_addr))
296: return 0;
297:
298: if (kmem_alloc_pageable(kernel_map, (vm_offset_t *) &b_prom, len)
299: != KERN_SUCCESS) {
300: printf("pc%d: can not allocate memory for prom.\n", unit);
301: return 0;
302: }
303: if (kmem_alloc_pageable(kernel_map, (vm_offset_t *) &b_sram, sram_len)
304: != KERN_SUCCESS) {
305: printf("pc%d: can not allocate memory for sram.\n", unit);
306: return 0;
307: }
308: (void)pmap_map(b_prom, (vm_offset_t)addr,
309: (vm_offset_t)addr+len,
310: VM_PROT_READ | VM_PROT_WRITE);
311: if ((int)addr > 0x100000) /* stupid hardware */
312: addr += EXTENDED_ADDR;
313: addr += 0x4000; /* sram space */
314: (void)pmap_map(b_sram, (vm_offset_t)addr,
315: (vm_offset_t)addr+sram_len,
316: VM_PROT_READ | VM_PROT_WRITE);
317:
318: *(b_prom + OFFSET_RESET) = 1;
319: { int i; for (i = 0; i < 1000; i++); /* 4 clocks at 6Mhz */}
320: *(b_prom + OFFSET_RESET) = 0;
321: t_ps = (u_short *)(b_sram + OFFSET_SCB);
322: *(t_ps) = (u_short)0x5a5a;
323: if (*(t_ps) != (u_short)0x5a5a) {
324: kmem_free(kernel_map, b_prom, len);
325: kmem_free(kernel_map, b_sram, sram_len);
326: return(0);
327: }
328: t_ps = (u_short *)(b_prom + + OFFSET_PROM);
329: #define ETHER0 0x00
330: #define ETHER1 0xaa
331: #define ETHER2 0x00
332: if ((t_ps[0]&0xff) == ETHER0 &&
333: (t_ps[1]&0xff) == ETHER1 &&
334: (t_ps[2]&0xff) == ETHER2)
335: pc_softc[unit].seated = TRUE;
336: #undef ETHER0
337: #undef ETHER1
338: #undef ETHER2
339: #define ETHER0 0x00
340: #define ETHER1 0x00
341: #define ETHER2 0x1c
342: if ((t_ps[0]&0xff) == ETHER0 ||
343: (t_ps[1]&0xff) == ETHER1 ||
344: (t_ps[2]&0xff) == ETHER2)
345: pc_softc[unit].seated = TRUE;
346: #undef ETHER0
347: #undef ETHER1
348: #undef ETHER2
349: if (pc_softc[unit].seated != TRUE) {
350: kmem_free(kernel_map, b_prom, len);
351: kmem_free(kernel_map, b_sram, sram_len);
352: return(0);
353: }
354: (volatile char *)pc_softc[unit].prom = (volatile char *)b_prom;
355: (volatile char *)pc_softc[unit].sram = (volatile char *)b_sram;
356: return(1);
357: }
358:
359: /*
360: * pc586attach:
361: *
362: * This function attaches a PC586 board to the "system". The rest of
363: * runtime structures are initialized here (this routine is called after
364: * a successful probe of the board). Once the ethernet address is read
365: * and stored, the board's ifnet structure is attached and readied.
366: *
367: * input : bus_device structure setup in autoconfig
368: * output : board structs and ifnet is setup
369: *
370: */
371: void pc586attach(dev)
372: struct bus_device *dev;
373: {
374: struct ifnet *ifp;
375: u_char *addr_p;
376: u_short *b_addr;
377: u_char unit = (u_char)dev->unit;
378: pc_softc_t *sp = &pc_softc[unit];
379: volatile scb_t *scb_p;
380:
381: take_dev_irq(dev);
382: printf(", port = %x, spl = %d, pic = %d. ",
383: dev->address, dev->sysdep, dev->sysdep1);
384:
385: sp->timer = -1;
386: sp->flags = 0;
387: sp->mode = 0;
388: sp->open = 0;
389: CMD(RESET, CMD_1, unit);
390: { int i; for (i = 0; i < 1000; i++); /* 4 clocks at 6Mhz */}
391: CMD(RESET, CMD_0, unit);
392: b_addr = (u_short *)(sp->prom + OFFSET_PROM);
393: addr_p = (u_char *)sp->ds_addr;
394: addr_p[0] = b_addr[0];
395: addr_p[1] = b_addr[1];
396: addr_p[2] = b_addr[2];
397: addr_p[3] = b_addr[3];
398: addr_p[4] = b_addr[4];
399: addr_p[5] = b_addr[5];
400: printf("ethernet id [%x:%x:%x:%x:%x:%x]",
401: addr_p[0], addr_p[1], addr_p[2],
402: addr_p[3], addr_p[4], addr_p[5]);
403:
404: scb_p = (volatile scb_t *)(sp->sram + OFFSET_SCB);
405: scb_p->scb_crcerrs = 0; /* initialize counters */
406: scb_p->scb_alnerrs = 0;
407: scb_p->scb_rscerrs = 0;
408: scb_p->scb_ovrnerrs = 0;
409:
410: ifp = &(sp->ds_if);
411: ifp->if_unit = unit;
412: ifp->if_mtu = ETHERMTU;
413: ifp->if_flags = IFF_BROADCAST;
414: #ifdef MACH_KERNEL
415: ifp->if_header_size = sizeof(struct ether_header);
416: ifp->if_header_format = HDR_ETHERNET;
417: ifp->if_address_size = 6;
418: ifp->if_address = (char *)&sp->ds_addr[0];
419: if_init_queues(ifp);
420: #else MACH_KERNEL
421: ifp->if_name = "pc";
422: ifp->if_init = pc586init;
423: ifp->if_output = pc586output;
424: ifp->if_ioctl = pc586ioctl;
425: ifp->if_reset = pc586reset;
426: ifp->if_next = NULL;
427: if_attach(ifp);
428: #endif MACH_KERNEL
429: }
430:
431: /*
432: * pc586reset:
433: *
434: * This routine is in part an entry point for the "if" code. Since most
435: * of the actual initialization has already (we hope already) been done
436: * by calling pc586attach().
437: *
438: * input : unit number or board number to reset
439: * output : board is reset
440: *
441: */
442: pc586reset(unit)
443: int unit;
444: {
445: pc_softc[unit].ds_if.if_flags &= ~IFF_RUNNING;
446: pc_softc[unit].flags &= ~(DSF_LOCK|DSF_RUNNING);
447: return(pc586init(unit));
448:
449: }
450:
451: /*
452: * pc586init:
453: *
454: * Another routine that interfaces the "if" layer to this driver.
455: * Simply resets the structures that are used by "upper layers".
456: * As well as calling pc586hwrst that does reset the pc586 board.
457: *
458: * input : board number
459: * output : structures (if structs) and board are reset
460: *
461: */
462: pc586init(unit)
463: int unit;
464: {
465: struct ifnet *ifp;
466: int stat;
467: spl_t oldpri;
468:
469: ifp = &(pc_softc[unit].ds_if);
470: #ifdef MACH_KERNEL
471: #else MACH_KERNEL
472: if (ifp->if_addrlist == (struct ifaddr *)0) {
473: return;
474: }
475: #endif MACH_KERNEL
476: oldpri = SPLNET();
477: if ((stat = pc586hwrst(unit)) == TRUE) {
478: #ifdef MACH_KERNEL
479: #undef HZ
480: #define HZ hz
481: #endif MACH_KERNEL
482: timeout(pc586watch, &(ifp->if_unit), 5*HZ);
483: pc_softc[unit].timer = 5;
484:
485: pc_softc[unit].ds_if.if_flags |= IFF_RUNNING;
486: pc_softc[unit].flags |= DSF_RUNNING;
487: pc_softc[unit].tbusy = 0;
488: pc586start(unit);
489: #if DLI
490: dli_init();
491: #endif DLI
492: } else
493: printf("pc%d init(): trouble resetting board.\n", unit);
494: splx(oldpri);
495: return(stat);
496: }
497:
498: #ifdef MACH_KERNEL
499: /*ARGSUSED*/
500: pc586open(dev, flag)
501: dev_t dev;
502: int flag;
503: {
504: register int unit;
505: pc_softc_t *sp;
506:
507: unit = minor(dev); /* XXX */
508: if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
509: return (ENXIO);
510:
511: pc_softc[unit].ds_if.if_flags |= IFF_UP;
512: pc586init(unit);
513: return (0);
514: }
515: #endif MACH_KERNEL
516:
517: /*
518: * pc586start:
519: *
520: * This is yet another interface routine that simply tries to output a
521: * in an mbuf after a reset.
522: *
523: * input : board number
524: * output : stuff sent to board if any there
525: *
526: */
527: pc586start(unit)
528: int unit;
529: {
530: #ifdef MACH_KERNEL
531: io_req_t m;
532: #else MACH_KERNEL
533: struct mbuf *m;
534: #endif MACH_KERNEL
535: struct ifnet *ifp;
536: register pc_softc_t *is = &pc_softc[unit];
537: volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
538:
539: if (is->tbusy) {
540: if (!(scb_p->scb_status & 0x0700)) { /* ! IDLE */
541: is->tbusy = 0;
542: pc586_cntrs[unit].xmt.busy++;
543: /*
544: * This is probably just a race. The xmt'r is just
545: * became idle but WE have masked interrupts so ...
546: */
547: if (xmt_watch) printf("!!");
548: } else
549: return;
550: }
551:
552: ifp = &(pc_softc[unit].ds_if);
553: IF_DEQUEUE(&ifp->if_snd, m);
554: #ifdef MACH_KERNEL
555: if (m != 0)
556: #else MACH_KERNEL
557: if (m != (struct mbuf *)0)
558: #endif MACH_KERNEL
559: {
560: is->tbusy++;
561: pc586_cntrs[unit].xmt.xmt++;
562: pc586xmt(unit, m);
563: }
564: return;
565: }
566:
567: /*
568: * pc586read:
569: *
570: * This routine does the actual copy of data (including ethernet header
571: * structure) from the pc586 to an mbuf chain that will be passed up
572: * to the "if" (network interface) layer. NOTE: we currently
573: * don't handle trailer protocols, so if that is needed, it will
574: * (at least in part) be added here. For simplicities sake, this
575: * routine copies the receive buffers from the board into a local (stack)
576: * buffer until the frame has been copied from the board. Once in
577: * the local buffer, the contents are copied to an mbuf chain that
578: * is then enqueued onto the appropriate "if" queue.
579: *
580: * input : board number, and an frame descriptor pointer
581: * output : the packet is put into an mbuf chain, and passed up
582: * assumes : if any errors occur, packet is "dropped on the floor"
583: *
584: */
585: pc586read(unit, fd_p)
586: int unit;
587: fd_t *fd_p;
588: {
589: register pc_softc_t *is = &pc_softc[unit];
590: register struct ifnet *ifp = &is->ds_if;
591: struct ether_header eh;
592: #ifdef MACH_KERNEL
593: ipc_kmsg_t new_kmsg;
594: struct ether_header *ehp;
595: struct packet_header *pkt;
596: char *dp;
597: #else MACH_KERNEL
598: struct mbuf *m, *tm;
599: #endif MACH_KERNEL
600: rbd_t *rbd_p;
601: u_char *buffer_p;
602: u_char *mb_p;
603: u_short mlen, len, clen;
604: u_short bytes_in_msg, bytes_in_mbuf, bytes;
605:
606:
607: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
608: printf("pc%d read(): board is not running.\n", ifp->if_unit);
609: pc586intoff(ifp->if_unit);
610: }
611: pc586_cntrs[unit].rcv.rcv++;
612: #ifdef MACH_KERNEL
613: new_kmsg = net_kmsg_get();
614: if (new_kmsg == IKM_NULL) {
615: /*
616: * Drop the received packet.
617: */
618: is->ds_if.if_rcvdrops++;
619:
620: /*
621: * not only do we want to return, we need to drop the packet on
622: * the floor to clear the interrupt.
623: */
624: return 1;
625: }
626: ehp = (struct ether_header *) (&net_kmsg(new_kmsg)->header[0]);
627: pkt = (struct packet_header *)(&net_kmsg(new_kmsg)->packet[0]);
628:
629: /*
630: * Get ether header.
631: */
632: ehp->ether_type = fd_p->length;
633: len = sizeof(struct ether_header);
634: bcopy16(fd_p->source, ehp->ether_shost, ETHER_ADD_SIZE);
635: bcopy16(fd_p->destination, ehp->ether_dhost, ETHER_ADD_SIZE);
636:
637: /*
638: * Get packet body.
639: */
640: dp = (char *)(pkt + 1);
641:
642: rbd_p = (rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit);
643: if (rbd_p == 0) {
644: printf("pc%d read(): Invalid buffer\n", unit);
645: if (pc586hwrst(unit) != TRUE) {
646: printf("pc%d read(): hwrst trouble.\n", unit);
647: }
648: net_kmsg_put(new_kmsg);
649: return 0;
650: }
651:
652: do {
653: buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr);
654: bytes_in_msg = rbd_p->status & RBD_SW_COUNT;
655: bcopy16((u_short *)buffer_p,
656: (u_short *)dp,
657: (bytes_in_msg + 1) & ~1); /* but we know it's even */
658: len += bytes_in_msg;
659: dp += bytes_in_msg;
660: if (rbd_p->status & RBD_SW_EOF)
661: break;
662: rbd_p = (rbd_t *)ram_to_ptr(rbd_p->next_rbd_offset, unit);
663: } while ((int) rbd_p);
664:
665: pkt->type = ehp->ether_type;
666: pkt->length =
667: len - sizeof(struct ether_header)
668: + sizeof(struct packet_header);
669:
670: /*
671: * Send the packet to the network module.
672: */
673: net_packet(ifp, new_kmsg, pkt->length, ethernet_priority(new_kmsg));
674: return 1;
675: #else MACH_KERNEL
676: eh.ether_type = ntohs(fd_p->length);
677: bcopy16(fd_p->source, eh.ether_shost, ETHER_ADD_SIZE);
678: bcopy16(fd_p->destination, eh.ether_dhost, ETHER_ADD_SIZE);
679:
680: if ((rbd_p =(rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit))== (rbd_t *)NULL) {
681: printf("pc%d read(): Invalid buffer\n", unit);
682: if (pc586hwrst(unit) != TRUE) {
683: printf("pc%d read(): hwrst trouble.\n", unit);
684: }
685: return 0;
686: }
687:
688: bytes_in_msg = rbd_p->status & RBD_SW_COUNT;
689: buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr);
690: MGET(m, M_DONTWAIT, MT_DATA);
691: tm = m;
692: if (m == (struct mbuf *)0) {
693: /*
694: * not only do we want to return, we need to drop the packet on
695: * the floor to clear the interrupt.
696: *
697: */
698: printf("pc%d read(): No mbuf 1st\n", unit);
699: if (pc586hwrst(unit) != TRUE) {
700: pc586intoff(unit);
701: printf("pc%d read(): hwrst trouble.\n", unit);
702: pc_softc[unit].timer = 0;
703: }
704: return 0;
705: }
706: m->m_next = (struct mbuf *) 0;
707: m->m_len = MLEN;
708: if (bytes_in_msg > 2 * MLEN - sizeof (struct ifnet **)) {
709: MCLGET(m);
710: }
711: /*
712: * first mbuf in the packet must contain a pointer to the
713: * ifnet structure. other mbufs that follow and make up
714: * the packet do not need this pointer in the mbuf.
715: *
716: */
717: *(mtod(tm, struct ifnet **)) = ifp;
718: mlen = sizeof (struct ifnet **);
719: clen = mlen;
720: bytes_in_mbuf = m->m_len - sizeof(struct ifnet **);
721: mb_p = mtod(tm, u_char *) + sizeof (struct ifnet **);
722: bytes = min(bytes_in_mbuf, bytes_in_msg);
723: do {
724: if (bytes & 1)
725: len = bytes + 1;
726: else
727: len = bytes;
728: bcopy16(buffer_p, mb_p, len);
729: clen += bytes;
730: mlen += bytes;
731:
732: if (!(bytes_in_mbuf -= bytes)) {
733: MGET(tm->m_next, M_DONTWAIT, MT_DATA);
734: tm = tm->m_next;
735: if (tm == (struct mbuf *)0) {
736: m_freem(m);
737: printf("pc%d read(): No mbuf nth\n", unit);
738: if (pc586hwrst(unit) != TRUE) {
739: pc586intoff(unit);
740: printf("pc%d read(): hwrst trouble.\n", unit);
741: pc_softc[unit].timer = 0;
742: }
743: return 0;
744: }
745: mlen = 0;
746: tm->m_len = MLEN;
747: bytes_in_mbuf = MLEN;
748: mb_p = mtod(tm, u_char *);
749: } else
750: mb_p += bytes;
751:
752: if (!(bytes_in_msg -= bytes)) {
753: if (rbd_p->status & RBD_SW_EOF ||
754: (rbd_p = (rbd_t *)ram_to_ptr(rbd_p->next_rbd_offset, unit)) ==
755: NULL) {
756: tm->m_len = mlen;
757: break;
758: } else {
759: bytes_in_msg = rbd_p->status & RBD_SW_COUNT;
760: buffer_p = (u_char *)(pc_softc[unit].sram + rbd_p->buffer_addr);
761: }
762: } else
763: buffer_p += bytes;
764:
765: bytes = min(bytes_in_mbuf, bytes_in_msg);
766: } while(1);
767: #ifdef IF_CNTRS
768: /* clen -= (sizeof (struct ifnet **)
769: clen += 4 /* crc */;
770: clen += sizeof (struct ether_header);
771: pc586_ein[log_2(clen)]++;
772: if (clen < 128) pc586_lin[clen>>3]++;
773:
774: if (eh.ether_type == ETHERTYPE_ARP) {
775: pc586_arp++;
776: if (pc586_narp) {
777: pc586_ein[log_2(clen)]--;
778: if (clen < 128) pc586_lin[clen>>3]--;
779: }
780: }
781: #endif IF_CNTRS
782: /*
783: * received packet is now in a chain of mbuf's. next step is
784: * to pass the packet upwards.
785: *
786: */
787: pc586send_packet_up(m, &eh, is);
788: return 1;
789: #endif MACH_KERNEL
790: }
791:
792: /*
793: * Send a packet composed of an mbuf chain to the higher levels
794: *
795: */
796: #ifndef MACH_KERNEL
797: pc586send_packet_up(m, eh, is)
798: struct mbuf *m;
799: struct ether_header *eh;
800: pc_softc_t *is;
801: {
802: register struct ifqueue *inq;
803: spl_t opri;
804:
805: switch (eh->ether_type) {
806: #ifdef INET
807: case ETHERTYPE_IP:
808: schednetisr(NETISR_IP);
809: inq = &ipintrq;
810: break;
811: case ETHERTYPE_ARP:
812: arpinput(&is->pc586_ac, m);
813: return;
814: #endif
815: #ifdef NS
816: case ETHERTYPE_NS:
817: schednetisr(NETISR_NS);
818: inq = &nsintrq;
819: break;
820: #endif
821: default:
822: #if DLI
823: {
824: eh.ether_type = htons(eh.ether_type);
825: dli_input(m,eh.ether_type,&eh.ether_shost[0],
826: &de_dlv[ds->ds_if.if_unit], &eh);
827: }
828: #else DLI
829: m_freem(m);
830: #endif DLI
831: return;
832: }
833: opri = SPLNET();
834: if (IF_QFULL(inq)) {
835: IF_DROP(inq);
836: splx(opri);
837: m_freem(m);
838: return;
839: }
840: IF_ENQUEUE(inq, m);
841: splx(opri);
842: return;
843: }
844: #endif MACH_KERNEL
845:
846: #ifdef MACH_KERNEL
847: pc586output(dev, ior)
848: dev_t dev;
849: io_req_t ior;
850: {
851: register int unit;
852:
853: unit = minor(dev); /* XXX */
854: if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
855: return (ENXIO);
856:
857: return (net_write(&pc_softc[unit].ds_if, pc586start, ior));
858: }
859:
860: pc586setinput(dev, receive_port, priority, filter, filter_count)
861: dev_t dev;
862: mach_port_t receive_port;
863: int priority;
864: filter_t filter[];
865: unsigned int filter_count;
866: {
867: register int unit = minor(dev);
868: if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
869: return (ENXIO);
870:
871: return (net_set_filter(&pc_softc[unit].ds_if,
872: receive_port, priority,
873: filter, filter_count));
874: }
875: #else MACH_KERNEL
876: /*
877: * pc586output:
878: *
879: * This routine is called by the "if" layer to output a packet to
880: * the network. This code resolves the local ethernet address, and
881: * puts it into the mbuf if there is room. If not, then a new mbuf
882: * is allocated with the header information and precedes the data
883: * to be transmitted. The routines that actually transmit the
884: * data (pc586xmt()) expect the ethernet structure to precede
885: * the data in the mbuf. This information is required by the
886: * 82586's transfer command segment, and thus mbuf's cannot
887: * be simply "slammed" out onto the network.
888: *
889: * input: ifnet structure pointer, an mbuf with data, and address
890: * to be resolved
891: * output: mbuf is updated to hold enet address, or a new mbuf
892: * with the address is added
893: *
894: */
895: pc586output(ifp, m0, dst)
896: struct ifnet *ifp;
897: struct mbuf *m0;
898: struct sockaddr *dst;
899: {
900: register pc_softc_t *is = &pc_softc[ifp->if_unit];
901: register struct mbuf *m = m0;
902: int type, error;
903: spl_t opri;
904: u_char edst[6];
905: struct in_addr idst;
906: register struct ether_header *eh;
907: register int off;
908: int usetrailers;
909:
910: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
911: printf("pc%d output(): board is not running.\n", ifp->if_unit);
912: pc586intoff(ifp->if_unit);
913: error = ENETDOWN;
914: goto bad;
915: }
916: switch (dst->sa_family) {
917:
918: #ifdef INET
919: case AF_INET:
920: idst = ((struct sockaddr_in *)dst)->sin_addr;
921: if (!arpresolve(&is->pc586_ac, m, &idst, edst, &usetrailers)){
922: return (0); /* if not yet resolved */
923: }
924: off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
925:
926: if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
927: m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
928: type = ETHERTYPE_TRAIL + (off>>9);
929: m->m_off -= 2 * sizeof (u_short);
930: m->m_len += 2 * sizeof (u_short);
931: *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
932: *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
933: goto gottrailertype;
934: }
935: type = ETHERTYPE_IP;
936: off = 0;
937: goto gottype;
938: #endif
939: #ifdef NS
940: case AF_NS:
941: type = ETHERTYPE_NS;
942: bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
943: (caddr_t)edst, sizeof (edst));
944: off = 0;
945: goto gottype;
946: #endif
947:
948: #if DLI
949: case AF_DLI:
950: if (m->m_len < sizeof(struct ether_header))
951: {
952: error = EMSGSIZE;
953: goto bad;
954: }
955: eh = mtod(m, struct ether_header *);
956: bcopy(dst->sa_data, (caddr_t)eh->ether_dhost,
957: sizeof (eh->ether_dhost));
958: goto gotheader;
959: #endif DLI
960:
961: case AF_UNSPEC:
962: eh = (struct ether_header *)dst->sa_data;
963: bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
964: type = eh->ether_type;
965: goto gottype;
966:
967: default:
968: printf("pc%d output(): can't handle af%d\n",
969: ifp->if_unit, dst->sa_family);
970: error = EAFNOSUPPORT;
971: goto bad;
972: }
973:
974: gottrailertype:
975: /*
976: * Packet to be sent as trailer: move first packet
977: * (control information) to end of chain.
978: */
979: while (m->m_next)
980: m = m->m_next;
981: m->m_next = m0;
982: m = m0->m_next;
983: m0->m_next = 0;
984: m0 = m;
985:
986: gottype:
987: /*
988: * Add local net header. If no space in first mbuf,
989: * allocate another.
990: */
991: if (m->m_off > MMAXOFF ||
992: MMINOFF + sizeof (struct ether_header) > m->m_off) {
993: m = m_get(M_DONTWAIT, MT_HEADER);
994: if (m == 0) {
995: error = ENOBUFS;
996: goto bad;
997: }
998: m->m_next = m0;
999: m->m_off = MMINOFF;
1000: m->m_len = sizeof (struct ether_header);
1001: } else {
1002: m->m_off -= sizeof (struct ether_header);
1003: m->m_len += sizeof (struct ether_header);
1004: }
1005: eh = mtod(m, struct ether_header *);
1006: eh->ether_type = htons((u_short)type);
1007: bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
1008: bcopy((caddr_t)is->ds_addr,(caddr_t)eh->ether_shost, sizeof(edst));
1009: #if DLI
1010: gotheader:
1011: #endif DLI
1012:
1013: /*
1014: * Queue message on interface, and start output if interface
1015: * not yet active.
1016: */
1017: opri = SPLNET();
1018: if (IF_QFULL(&ifp->if_snd)) {
1019: IF_DROP(&ifp->if_snd);
1020: splx(opri);
1021: m_freem(m);
1022: return (ENOBUFS);
1023: }
1024: IF_ENQUEUE(&ifp->if_snd, m);
1025: /*
1026: * Some action needs to be added here for checking whether the
1027: * board is already transmitting. If it is, we don't want to
1028: * start it up (ie call pc586start()). We will attempt to send
1029: * packets that are queued up after an interrupt occurs. Some
1030: * flag checking action has to happen here and/or in the start
1031: * routine. This note is here to remind me that some thought
1032: * is needed and there is a potential problem here.
1033: *
1034: */
1035: pc586start(ifp->if_unit);
1036: splx(opri);
1037: return (0);
1038: bad:
1039: m_freem(m0);
1040: return (error);
1041: }
1042: #endif MACH_KERNEL
1043:
1044: #ifdef MACH_KERNEL
1045: pc586getstat(dev, flavor, status, count)
1046: dev_t dev;
1047: int flavor;
1048: dev_status_t status; /* pointer to OUT array */
1049: unsigned int *count; /* out */
1050: {
1051: register int unit = minor(dev);
1052: register pc_softc_t *sp;
1053:
1054: if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
1055: return (ENXIO);
1056:
1057: sp = &pc_softc[unit];
1058: return (net_getstat(&sp->ds_if, flavor, status, count));
1059: }
1060:
1061: pc586setstat(dev, flavor, status, count)
1062: dev_t dev;
1063: int flavor;
1064: dev_status_t status;
1065: unsigned int count;
1066: {
1067: register int unit = minor(dev);
1068: register pc_softc_t *sp;
1069:
1070: if (unit < 0 || unit >= NPC586 || !pc_softc[unit].seated)
1071: return (ENXIO);
1072:
1073: sp = &pc_softc[unit];
1074:
1075: switch (flavor) {
1076: case NET_STATUS:
1077: {
1078: /*
1079: * All we can change are flags, and not many of those.
1080: */
1081: register struct net_status *ns = (struct net_status *)status;
1082: int mode = 0;
1083:
1084: if (count < NET_STATUS_COUNT)
1085: return (D_INVALID_OPERATION);
1086:
1087: if (ns->flags & IFF_ALLMULTI)
1088: mode |= MOD_ENAL;
1089: if (ns->flags & IFF_PROMISC)
1090: mode |= MOD_PROM;
1091:
1092: /*
1093: * Force a complete reset if the receive mode changes
1094: * so that these take effect immediately.
1095: */
1096: if (sp->mode != mode) {
1097: sp->mode = mode;
1098: if (sp->flags & DSF_RUNNING) {
1099: sp->flags &= ~(DSF_LOCK|DSF_RUNNING);
1100: pc586init(unit);
1101: }
1102: }
1103: break;
1104: }
1105:
1106: default:
1107: return (D_INVALID_OPERATION);
1108: }
1109: return (D_SUCCESS);
1110:
1111: }
1112: #else MACH_KERNEL
1113: /*
1114: * pc586ioctl:
1115: *
1116: * This routine processes an ioctl request from the "if" layer
1117: * above.
1118: *
1119: * input : pointer the appropriate "if" struct, command, and data
1120: * output : based on command appropriate action is taken on the
1121: * pc586 board(s) or related structures
1122: * return : error is returned containing exit conditions
1123: *
1124: */
1125: pc586ioctl(ifp, cmd, data)
1126: struct ifnet *ifp;
1127: int cmd;
1128: caddr_t data;
1129: {
1130: register struct ifaddr *ifa = (struct ifaddr *)data;
1131: int unit = ifp->if_unit;
1132: register pc_softc_t *is = &pc_softc[unit];
1133: short mode = 0;
1134: int error = 0;
1135: spl_t opri;
1136:
1137: opri = SPLNET();
1138: switch (cmd) {
1139: case SIOCSIFADDR:
1140: ifp->if_flags |= IFF_UP;
1141: pc586init(unit);
1142: switch (ifa->ifa_addr.sa_family) {
1143: #ifdef INET
1144: case AF_INET:
1145: ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
1146: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
1147: break;
1148: #endif
1149: #ifdef NS
1150: case AF_NS:
1151: {
1152: register struct ns_addr *ina =
1153: &(IA_SNS(ifa)->sns_addr);
1154: if (ns_nullhost(*ina))
1155: ina->x_host = *(union ns_host *)(ds->ds_addr);
1156: else
1157: pc586setaddr(ina->x_host.c_host, unit);
1158: break;
1159: }
1160: #endif
1161: }
1162: break;
1163: case SIOCSIFFLAGS:
1164: if (ifp->if_flags & IFF_ALLMULTI)
1165: mode |= MOD_ENAL;
1166: if (ifp->if_flags & IFF_PROMISC)
1167: mode |= MOD_PROM;
1168: /*
1169: * force a complete reset if the receive multicast/
1170: * promiscuous mode changes so that these take
1171: * effect immediately.
1172: *
1173: */
1174: if (is->mode != mode) {
1175: is->mode = mode;
1176: if (is->flags & DSF_RUNNING) {
1177: is->flags &= ~(DSF_LOCK|DSF_RUNNING);
1178: pc586init(unit);
1179: }
1180: }
1181: if ((ifp->if_flags & IFF_UP) == 0 && is->flags & DSF_RUNNING) {
1182: printf("pc%d ioctl(): board is not running\n", unit);
1183: is->flags &= ~(DSF_LOCK | DSF_RUNNING);
1184: is->timer = -1;
1185: pc586intoff(unit);
1186: } else if (ifp->if_flags & IFF_UP && (is->flags & DSF_RUNNING) == 0) {
1187: pc586init(unit);
1188: }
1189: break;
1190: #ifdef IF_CNTRS
1191: case SIOCCIFCNTRS:
1192: if (!suser()) {
1193: error = EPERM;
1194: break;
1195: }
1196: bzero((caddr_t)pc586_ein, sizeof (pc586_ein));
1197: bzero((caddr_t)pc586_eout, sizeof (pc586_eout));
1198: bzero((caddr_t)pc586_lin, sizeof (pc586_lin));
1199: bzero((caddr_t)pc586_lout, sizeof (pc586_lout));
1200: bzero((caddr_t)&pc586_arp, sizeof (int));
1201: bzero((caddr_t)&pc586_cntrs, sizeof (pc586_cntrs));
1202: break;
1203: #endif IF_CNTRS
1204: default:
1205: error = EINVAL;
1206: }
1207: splx(opri);
1208: return (error);
1209: }
1210: #endif MACH_KERNEL
1211:
1212: /*
1213: * pc586hwrst:
1214: *
1215: * This routine resets the pc586 board that corresponds to the
1216: * board number passed in.
1217: *
1218: * input : board number to do a hardware reset
1219: * output : board is reset
1220: *
1221: */
1222: pc586hwrst(unit)
1223: int unit;
1224: {
1225: CMD(CHANATT, CMD_0, unit);
1226: CMD(RESET, CMD_1, unit);
1227: { int i; for (i = 0; i < 1000; i++); /* 4 clocks at 6Mhz */}
1228: CMD(RESET,CMD_0, unit);
1229:
1230: /*
1231: * for (i = 0; i < 1000000; i++);
1232: * with this loop above and with the reset toggle also looping to
1233: * 1000000. We don't see the reset behaving as advertised. DOES
1234: * IT HAPPEN AT ALL. In particular, NORMODE, ENABLE, and XFER
1235: * should all be zero and they have not changed at all.
1236: */
1237: CMD(INTENAB, CMD_0, unit);
1238: CMD(NORMMODE, CMD_0, unit);
1239: CMD(XFERMODE, CMD_1, unit);
1240:
1241: pc586bldcu(unit);
1242:
1243: if (pc586diag(unit) == FALSE)
1244: return(FALSE);
1245:
1246: if (pc586config(unit) == FALSE)
1247: return(FALSE);
1248: /*
1249: * insert code for loopback test here
1250: *
1251: */
1252: pc586rustrt(unit);
1253:
1254: pc586inton(unit);
1255: CMD(NORMMODE, CMD_1, unit);
1256: return(TRUE);
1257: }
1258:
1259: /*
1260: * pc586watch():
1261: *
1262: * This routine is the watchdog timer routine for the pc586 chip. If
1263: * chip wedges, this routine will fire and cause a board reset and
1264: * begin again.
1265: *
1266: * input : which board is timing out
1267: * output : potential board reset if wedged
1268: *
1269: */
1270: int watch_dead = 0;
1271: pc586watch(b_ptr)
1272: caddr_t b_ptr;
1273: {
1274: spl_t opri;
1275: int unit = *b_ptr;
1276:
1277: if ((pc_softc[unit].ds_if.if_flags & IFF_UP) == 0) {
1278: return;
1279: }
1280: if (pc_softc[unit].timer == -1) {
1281: timeout(pc586watch, b_ptr, 5*HZ);
1282: return;
1283: }
1284: if (--pc_softc[unit].timer != -1) {
1285: timeout(pc586watch, b_ptr, 1*HZ);
1286: return;
1287: }
1288:
1289: opri = SPLNET();
1290: #ifdef notdef
1291: printf("pc%d watch(): 6sec timeout no %d\n", unit, ++watch_dead);
1292: #endif notdef
1293: pc586_cntrs[unit].watch++;
1294: if (pc586hwrst(unit) != TRUE) {
1295: printf("pc%d watch(): hwrst trouble.\n", unit);
1296: pc_softc[unit].timer = 0;
1297: } else {
1298: timeout(pc586watch, b_ptr, 1*HZ);
1299: pc_softc[unit].timer = 5;
1300: }
1301: splx(opri);
1302: }
1303:
1304: /*
1305: * pc586intr:
1306: *
1307: * This function is the interrupt handler for the pc586 ethernet
1308: * board. This routine will be called whenever either a packet
1309: * is received, or a packet has successfully been transfered and
1310: * the unit is ready to transmit another packet.
1311: *
1312: * input : board number that interrupted
1313: * output : either a packet is received, or a packet is transfered
1314: *
1315: */
1316: pc586intr(unit)
1317: int unit;
1318: {
1319: volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1320: volatile ac_t *cb_p = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
1321: int next, x;
1322: int i;
1323: u_short int_type;
1324:
1325: if (pc_softc[unit].seated == FALSE) {
1326: printf("pc%d intr(): board not seated\n", unit);
1327: return(-1);
1328: }
1329:
1330: while ((int_type = (scb_p->scb_status & SCB_SW_INT)) != 0) {
1331: pc586ack(unit);
1332: if (int_type & SCB_SW_FR) {
1333: pc586rcv(unit);
1334: watch_dead=0;
1335: }
1336: if (int_type & SCB_SW_RNR) {
1337: pc586_cntrs[unit].rcv.ovw++;
1338: #ifdef notdef
1339: printf("pc%d intr(): receiver overrun! begin_fd = %x\n",
1340: unit, pc_softc[unit].begin_fd);
1341: #endif notdef
1342: pc586rustrt(unit);
1343: }
1344: if (int_type & SCB_SW_CNA) {
1345: /*
1346: * At present, we don't care about CNA's. We
1347: * believe they are a side effect of XMT.
1348: */
1349: }
1350: if (int_type & SCB_SW_CX) {
1351: /*
1352: * At present, we only request Interrupt for
1353: * XMT.
1354: */
1355: if ((!(cb_p->ac_status & AC_SW_OK)) ||
1356: (cb_p->ac_status & (0xfff^TC_SQE))) {
1357: if (cb_p->ac_status & TC_DEFER) {
1358: if (xmt_watch) printf("DF");
1359: pc586_cntrs[unit].xmt.defer++;
1360: } else if (cb_p->ac_status & (TC_COLLISION|0xf)) {
1361: if (xmt_watch) printf("%x",cb_p->ac_status & 0xf);
1362: } else if (xmt_watch)
1363: printf("pc%d XMT: %x %x\n",
1364: unit, cb_p->ac_status, cb_p->ac_command);
1365: }
1366: pc586_cntrs[unit].xmt.xmti++;
1367: pc_softc[unit].tbusy = 0;
1368: pc586start(unit);
1369: }
1370: pc_softc[unit].timer = 5;
1371: }
1372: return(0);
1373: }
1374:
1375: /*
1376: * pc586rcv:
1377: *
1378: * This routine is called by the interrupt handler to initiate a
1379: * packet transfer from the board to the "if" layer above this
1380: * driver. This routine checks if a buffer has been successfully
1381: * received by the pc586. If so, the routine pc586read is called
1382: * to do the actual transfer of the board data (including the
1383: * ethernet header) into a packet (consisting of an mbuf chain).
1384: *
1385: * input : number of the board to check
1386: * output : if a packet is available, it is "sent up"
1387: *
1388: */
1389: pc586rcv(unit)
1390: int unit;
1391: {
1392: fd_t *fd_p;
1393:
1394: for (fd_p = pc_softc[unit].begin_fd; fd_p != (fd_t *)NULL;
1395: fd_p = pc_softc[unit].begin_fd) {
1396: if (fd_p->status == 0xffff || fd_p->rbd_offset == 0xffff) {
1397: if (pc586hwrst(unit) != TRUE)
1398: printf("pc%d rcv(): hwrst ffff trouble.\n",
1399: unit);
1400: return;
1401: } else if (fd_p->status & AC_SW_C) {
1402: fd_t *bfd = (fd_t *)ram_to_ptr(fd_p->link_offset, unit);
1403:
1404: if (fd_p->status == (RFD_DONE|RFD_RSC)) {
1405: /* lost one */;
1406: #ifdef notdef
1407: printf("pc%d RCV: RSC %x\n",
1408: unit, fd_p->status);
1409: #endif notdef
1410: pc586_cntrs[unit].rcv.partial++;
1411: } else if (!(fd_p->status & RFD_OK))
1412: printf("pc%d RCV: !OK %x\n",
1413: unit, fd_p->status);
1414: else if (fd_p->status & 0xfff)
1415: printf("pc%d RCV: ERRs %x\n",
1416: unit, fd_p->status);
1417: else
1418: if (!pc586read(unit, fd_p))
1419: return;
1420: if (!pc586requeue(unit, fd_p)) { /* abort on chain error */
1421: if (pc586hwrst(unit) != TRUE)
1422: printf("pc%d rcv(): hwrst trouble.\n", unit);
1423: return;
1424: }
1425: pc_softc[unit].begin_fd = bfd;
1426: } else
1427: break;
1428: }
1429: return;
1430: }
1431:
1432: /*
1433: * pc586requeue:
1434: *
1435: * This routine puts rbd's used in the last receive back onto the
1436: * free list for the next receive.
1437: *
1438: */
1439: pc586requeue(unit, fd_p)
1440: int unit;
1441: fd_t *fd_p;
1442: {
1443: rbd_t *l_rbdp;
1444: rbd_t *f_rbdp;
1445:
1446: #ifndef REQUEUE_DBG
1447: if (bad_rbd_chain(fd_p->rbd_offset, unit))
1448: return 0;
1449: #endif REQUEUE_DBG
1450: f_rbdp = (rbd_t *)ram_to_ptr(fd_p->rbd_offset, unit);
1451: if (f_rbdp != NULL) {
1452: l_rbdp = f_rbdp;
1453: while ( (!(l_rbdp->status & RBD_SW_EOF)) &&
1454: (l_rbdp->next_rbd_offset != 0xffff))
1455: {
1456: l_rbdp->status = 0;
1457: l_rbdp = (rbd_t *)ram_to_ptr(l_rbdp->next_rbd_offset,
1458: unit);
1459: }
1460: l_rbdp->next_rbd_offset = PC586NULL;
1461: l_rbdp->status = 0;
1462: l_rbdp->size |= AC_CW_EL;
1463: pc_softc[unit].end_rbd->next_rbd_offset =
1464: ptr_to_ram((char *)f_rbdp, unit);
1465: pc_softc[unit].end_rbd->size &= ~AC_CW_EL;
1466: pc_softc[unit].end_rbd= l_rbdp;
1467: }
1468:
1469: fd_p->status = 0;
1470: fd_p->command = AC_CW_EL;
1471: fd_p->link_offset = PC586NULL;
1472: fd_p->rbd_offset = PC586NULL;
1473:
1474: pc_softc[unit].end_fd->link_offset = ptr_to_ram((char *)fd_p, unit);
1475: pc_softc[unit].end_fd->command = 0;
1476: pc_softc[unit].end_fd = fd_p;
1477:
1478: return 1;
1479: }
1480:
1481: /*
1482: * pc586xmt:
1483: *
1484: * This routine fills in the appropriate registers and memory
1485: * locations on the PC586 board and starts the board off on
1486: * the transmit.
1487: *
1488: * input : board number of interest, and a pointer to the mbuf
1489: * output : board memory and registers are set for xfer and attention
1490: *
1491: */
1492: #ifdef DEBUG
1493: int xmt_debug = 0;
1494: #endif DEBUG
1495: pc586xmt(unit, m)
1496: int unit;
1497: #ifdef MACH_KERNEL
1498: io_req_t m;
1499: #else MACH_KERNEL
1500: struct mbuf *m;
1501: #endif MACH_KERNEL
1502: {
1503: pc_softc_t *is = &pc_softc[unit];
1504: register u_char *xmtdata_p = (u_char *)(is->sram + OFFSET_TBUF);
1505: register u_short *xmtshort_p;
1506: #ifdef MACH_KERNEL
1507: register struct ether_header *eh_p = (struct ether_header *)m->io_data;
1508: #else MACH_KERNEL
1509: struct mbuf *tm_p = m;
1510: register struct ether_header *eh_p = mtod(m, struct ether_header *);
1511: u_char *mb_p = mtod(m, u_char *) + sizeof(struct ether_header);
1512: u_short count = m->m_len - sizeof(struct ether_header);
1513: #endif MACH_KERNEL
1514: volatile scb_t *scb_p = (volatile scb_t *)(is->sram + OFFSET_SCB);
1515: volatile ac_t *cb_p = (volatile ac_t *)(is->sram + OFFSET_CU);
1516: tbd_t *tbd_p = (tbd_t *)(is->sram + OFFSET_TBD);
1517: u_short tbd = OFFSET_TBD;
1518: u_short len, clen = 0;
1519:
1520: cb_p->ac_status = 0;
1521: cb_p->ac_command = (AC_CW_EL|AC_TRANSMIT|AC_CW_I);
1522: cb_p->ac_link_offset = PC586NULL;
1523: cb_p->cmd.transmit.tbd_offset = OFFSET_TBD;
1524:
1525: bcopy16(eh_p->ether_dhost, cb_p->cmd.transmit.dest_addr, ETHER_ADD_SIZE);
1526: cb_p->cmd.transmit.length = (u_short)(eh_p->ether_type);
1527:
1528: #ifndef MACH_KERNEL
1529: #ifdef DEBUG
1530: if (xmt_debug)
1531: printf("XMT mbuf: L%d @%x ", count, mb_p);
1532: #endif DEBUG
1533: #endif MACH_KERNEL
1534: tbd_p->act_count = 0;
1535: tbd_p->buffer_base = 0;
1536: tbd_p->buffer_addr = ptr_to_ram(xmtdata_p, unit);
1537: #ifdef MACH_KERNEL
1538: { int Rlen, Llen;
1539: clen = m->io_count - sizeof(struct ether_header);
1540: Llen = clen & 1;
1541: Rlen = ((int)(m->io_data + sizeof(struct ether_header))) & 1;
1542:
1543: bcopy16(m->io_data + sizeof(struct ether_header) - Rlen,
1544: xmtdata_p,
1545: clen + (Rlen + Llen) );
1546: xmtdata_p += clen + Llen;
1547: tbd_p->act_count = clen;
1548: tbd_p->buffer_addr += Rlen;
1549: }
1550: #else MACH_KERNEL
1551: do {
1552: if (count) {
1553: if (clen + count > ETHERMTU)
1554: break;
1555: if (count & 1)
1556: len = count + 1;
1557: else
1558: len = count;
1559: bcopy16(mb_p, xmtdata_p, len);
1560: clen += count;
1561: tbd_p->act_count += count;
1562: xmtdata_p += len;
1563: if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1564: break;
1565: if (count & 1) {
1566: /* go to the next descriptor */
1567: tbd_p++->next_tbd_offset = (tbd += sizeof (tbd_t));
1568: tbd_p->act_count = 0;
1569: tbd_p->buffer_base = 0;
1570: tbd_p->buffer_addr = ptr_to_ram(xmtdata_p, unit);
1571: /* at the end -> coallesce remaining mbufs */
1572: if (tbd == OFFSET_TBD + (N_TBD-1) * sizeof (tbd_t)) {
1573: pc586sftwsleaze(&count, &mb_p, &tm_p, unit);
1574: continue;
1575: }
1576: /* next mbuf short -> coallesce as needed */
1577: if ( (tm_p->m_next == (struct mbuf *) 0) ||
1578: #define HDW_THRESHOLD 55
1579: tm_p->m_len > HDW_THRESHOLD)
1580: /* ok */;
1581: else {
1582: pc586hdwsleaze(&count, &mb_p, &tm_p, unit);
1583: continue;
1584: }
1585: }
1586: } else if ((tm_p = tm_p->m_next) == (struct mbuf *)0)
1587: break;
1588: count = tm_p->m_len;
1589: mb_p = mtod(tm_p, u_char *);
1590: #ifdef DEBUG
1591: if (xmt_debug)
1592: printf("mbuf+ L%d @%x ", count, mb_p);
1593: #endif DEBUG
1594: } while (1);
1595: #endif MACH_KERNEL
1596: #ifdef DEBUG
1597: if (xmt_debug)
1598: printf("CLEN = %d\n", clen);
1599: #endif DEBUG
1600: if (clen < ETHERMIN) {
1601: tbd_p->act_count += ETHERMIN - clen;
1602: for (xmtshort_p = (u_short *)xmtdata_p;
1603: clen < ETHERMIN;
1604: clen += 2) *xmtshort_p++ = 0;
1605: }
1606: tbd_p->act_count |= TBD_SW_EOF;
1607: tbd_p->next_tbd_offset = PC586NULL;
1608: #ifdef IF_CNTRS
1609: clen += sizeof (struct ether_header) + 4 /* crc */;
1610: pc586_eout[log_2(clen)]++;
1611: if (clen < 128) pc586_lout[clen>>3]++;
1612: #endif IF_CNTRS
1613: #ifdef DEBUG
1614: if (xmt_debug) {
1615: pc586tbd(unit);
1616: printf("\n");
1617: }
1618: #endif DEBUG
1619:
1620: while (scb_p->scb_command) ;
1621: scb_p->scb_command = SCB_CU_STRT;
1622: pc586chatt(unit);
1623:
1624: #ifdef MACH_KERNEL
1625: iodone(m);
1626: #else MACH_KERNEL
1627: for (count=0; ((count < 6) && (eh_p->ether_dhost[count] == 0xff)); count++) ;
1628: if (count == 6) {
1629: pc586send_packet_up(m, eh_p, is);
1630: } else
1631: m_freem(m);
1632: #endif MACH_KERNEL
1633: return;
1634: }
1635:
1636: /*
1637: * pc586bldcu:
1638: *
1639: * This function builds up the command unit structures. It inits
1640: * the scp, iscp, scb, cb, tbd, and tbuf.
1641: *
1642: */
1643: pc586bldcu(unit)
1644: {
1645: char *sram = pc_softc[unit].sram;
1646: scp_t *scp_p = (scp_t *)(sram + OFFSET_SCP);
1647: iscp_t *iscp_p = (iscp_t *)(sram + OFFSET_ISCP);
1648: volatile scb_t *scb_p = (volatile scb_t *)(sram + OFFSET_SCB);
1649: volatile ac_t *cb_p = (volatile ac_t *)(sram + OFFSET_CU);
1650: tbd_t *tbd_p = (tbd_t *)(sram + OFFSET_TBD);
1651: int i;
1652:
1653: scp_p->scp_sysbus = 0;
1654: scp_p->scp_iscp = OFFSET_ISCP;
1655: scp_p->scp_iscp_base = 0;
1656:
1657: iscp_p->iscp_busy = 1;
1658: iscp_p->iscp_scb_offset = OFFSET_SCB;
1659: iscp_p->iscp_scb = 0;
1660: iscp_p->iscp_scb_base = 0;
1661:
1662: pc586_cntrs[unit].rcv.crc += scb_p->scb_crcerrs;
1663: pc586_cntrs[unit].rcv.frame += scb_p->scb_alnerrs;
1664: pc586_cntrs[unit].rcv.rscerrs += scb_p->scb_rscerrs;
1665: pc586_cntrs[unit].rcv.ovrnerrs += scb_p->scb_ovrnerrs;
1666: scb_p->scb_status = 0;
1667: scb_p->scb_command = 0;
1668: scb_p->scb_cbl_offset = OFFSET_CU;
1669: scb_p->scb_rfa_offset = OFFSET_RU;
1670: scb_p->scb_crcerrs = 0;
1671: scb_p->scb_alnerrs = 0;
1672: scb_p->scb_rscerrs = 0;
1673: scb_p->scb_ovrnerrs = 0;
1674:
1675: scb_p->scb_command = SCB_RESET;
1676: pc586chatt(unit);
1677: for (i = 1000000; iscp_p->iscp_busy && (i-- > 0); );
1678: if (!i) printf("pc%d bldcu(): iscp_busy timeout.\n", unit);
1679: for (i = STATUS_TRIES; i-- > 0; ) {
1680: if (scb_p->scb_status == (SCB_SW_CX|SCB_SW_CNA))
1681: break;
1682: }
1683: if (!i)
1684: printf("pc%d bldcu(): not ready after reset.\n", unit);
1685: pc586ack(unit);
1686:
1687: cb_p->ac_status = 0;
1688: cb_p->ac_command = AC_CW_EL;
1689: cb_p->ac_link_offset = OFFSET_CU;
1690:
1691: tbd_p->act_count = 0;
1692: tbd_p->next_tbd_offset = PC586NULL;
1693: tbd_p->buffer_addr = 0;
1694: tbd_p->buffer_base = 0;
1695: return;
1696: }
1697:
1698: /*
1699: * pc586bldru:
1700: *
1701: * This function builds the linear linked lists of fd's and
1702: * rbd's. Based on page 4-32 of 1986 Intel microcom handbook.
1703: *
1704: */
1705: char *
1706: pc586bldru(unit)
1707: int unit;
1708: {
1709: fd_t *fd_p = (fd_t *)(pc_softc[unit].sram + OFFSET_RU);
1710: ru_t *rbd_p = (ru_t *)(pc_softc[unit].sram + OFFSET_RBD);
1711: int i;
1712:
1713: pc_softc[unit].begin_fd = fd_p;
1714: for(i = 0; i < N_FD; i++, fd_p++) {
1715: fd_p->status = 0;
1716: fd_p->command = 0;
1717: fd_p->link_offset = ptr_to_ram((char *)(fd_p + 1), unit);
1718: fd_p->rbd_offset = PC586NULL;
1719: }
1720: pc_softc[unit].end_fd = --fd_p;
1721: fd_p->link_offset = PC586NULL;
1722: fd_p->command = AC_CW_EL;
1723: fd_p = (fd_t *)(pc_softc[unit].sram + OFFSET_RU);
1724:
1725: fd_p->rbd_offset = ptr_to_ram((char *)rbd_p, unit);
1726: for(i = 0; i < N_RBD; i++, rbd_p = (ru_t *) &(rbd_p->rbuffer[RCVBUFSIZE])) {
1727: rbd_p->r.status = 0;
1728: rbd_p->r.buffer_addr = ptr_to_ram((char *)(rbd_p->rbuffer),
1729: unit);
1730: rbd_p->r.buffer_base = 0;
1731: rbd_p->r.size = RCVBUFSIZE;
1732: if (i != N_RBD-1) {
1733: rbd_p->r.next_rbd_offset=ptr_to_ram(&(rbd_p->rbuffer[RCVBUFSIZE]),
1734: unit);
1735: } else {
1736: rbd_p->r.next_rbd_offset = PC586NULL;
1737: rbd_p->r.size |= AC_CW_EL;
1738: pc_softc[unit].end_rbd = (rbd_t *)rbd_p;
1739: }
1740: }
1741: return (char *)pc_softc[unit].begin_fd;
1742: }
1743:
1744: /*
1745: * pc586rustrt:
1746: *
1747: * This routine starts the receive unit running. First checks if the
1748: * board is actually ready, then the board is instructed to receive
1749: * packets again.
1750: *
1751: */
1752: pc586rustrt(unit)
1753: int unit;
1754: {
1755: volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1756: char *strt;
1757:
1758: if ((scb_p->scb_status & SCB_RUS_READY) == SCB_RUS_READY)
1759: return;
1760:
1761: strt = pc586bldru(unit);
1762: scb_p->scb_command = SCB_RU_STRT;
1763: scb_p->scb_rfa_offset = ptr_to_ram(strt, unit);
1764: pc586chatt(unit);
1765: return;
1766: }
1767:
1768: /*
1769: * pc586diag:
1770: *
1771: * This routine does a 586 op-code number 7, and obtains the
1772: * diagnose status for the pc586.
1773: *
1774: */
1775: pc586diag(unit)
1776: int unit;
1777: {
1778: volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1779: volatile ac_t *cb_p = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
1780: int i;
1781:
1782: if (scb_p->scb_status & SCB_SW_INT) {
1783: printf("pc%d diag(): bad initial state %\n",
1784: unit, scb_p->scb_status);
1785: pc586ack(unit);
1786: }
1787: cb_p->ac_status = 0;
1788: cb_p->ac_command = (AC_DIAGNOSE|AC_CW_EL);
1789: scb_p->scb_command = SCB_CU_STRT;
1790: pc586chatt(unit);
1791:
1792: for(i = 0; i < 0xffff; i++)
1793: if ((cb_p->ac_status & AC_SW_C))
1794: break;
1795: if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
1796: printf("pc%d: diag failed; status = %x\n",
1797: unit, cb_p->ac_status);
1798: return(FALSE);
1799: }
1800:
1801: if ( (scb_p->scb_status & SCB_SW_INT) && (scb_p->scb_status != SCB_SW_CNA) ) {
1802: printf("pc%d diag(): bad final state %x\n",
1803: unit, scb_p->scb_status);
1804: pc586ack(unit);
1805: }
1806: return(TRUE);
1807: }
1808:
1809: /*
1810: * pc586config:
1811: *
1812: * This routine does a standard config of the pc586 board.
1813: *
1814: */
1815: pc586config(unit)
1816: int unit;
1817: {
1818: volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1819: volatile ac_t *cb_p = (volatile ac_t *)(pc_softc[unit].sram + OFFSET_CU);
1820: int i;
1821:
1822:
1823: /*
1824: if ((scb_p->scb_status != SCB_SW_CNA) && (scb_p->scb_status & SCB_SW_INT) ) {
1825: printf("pc%d config(): unexpected initial state %x\n",
1826: unit, scb_p->scb_status);
1827: }
1828: */
1829: pc586ack(unit);
1830:
1831: cb_p->ac_status = 0;
1832: cb_p->ac_command = (AC_CONFIGURE|AC_CW_EL);
1833:
1834: /*
1835: * below is the default board configuration from p2-28 from 586 book
1836: */
1837: cb_p->cmd.configure.fifolim_bytecnt = 0x080c;
1838: cb_p->cmd.configure.addrlen_mode = 0x2600;
1839: cb_p->cmd.configure.linprio_interframe = 0x6000;
1840: cb_p->cmd.configure.slot_time = 0xf200;
1841: cb_p->cmd.configure.hardware = 0x0000;
1842: cb_p->cmd.configure.min_frame_len = 0x0040;
1843:
1844: scb_p->scb_command = SCB_CU_STRT;
1845: pc586chatt(unit);
1846:
1847: for(i = 0; i < 0xffff; i++)
1848: if ((cb_p->ac_status & AC_SW_C))
1849: break;
1850: if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
1851: printf("pc%d: config-configure failed; status = %x\n",
1852: unit, cb_p->ac_status);
1853: return(FALSE);
1854: }
1855: /*
1856: if (scb_p->scb_status & SCB_SW_INT) {
1857: printf("pc%d configure(): bad configure state %x\n",
1858: unit, scb_p->scb_status);
1859: pc586ack(unit);
1860: }
1861: */
1862: cb_p->ac_status = 0;
1863: cb_p->ac_command = (AC_IASETUP|AC_CW_EL);
1864:
1865: bcopy16(pc_softc[unit].ds_addr, cb_p->cmd.iasetup, ETHER_ADD_SIZE);
1866:
1867: scb_p->scb_command = SCB_CU_STRT;
1868: pc586chatt(unit);
1869:
1870: for (i = 0; i < 0xffff; i++)
1871: if ((cb_p->ac_status & AC_SW_C))
1872: break;
1873: if (i == 0xffff || !(cb_p->ac_status & AC_SW_OK)) {
1874: printf("pc%d: config-address failed; status = %x\n",
1875: unit, cb_p->ac_status);
1876: return(FALSE);
1877: }
1878: /*
1879: if ((scb_p->scb_status & SCB_SW_INT) != SCB_SW_CNA) {
1880: printf("pc%d configure(): unexpected final state %x\n",
1881: unit, scb_p->scb_status);
1882: }
1883: */
1884: pc586ack(unit);
1885:
1886: return(TRUE);
1887: }
1888:
1889: /*
1890: * pc586ack:
1891: */
1892: pc586ack(unit)
1893: {
1894: volatile scb_t *scb_p = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1895: int i;
1896:
1897: if (!(scb_p->scb_command = scb_p->scb_status & SCB_SW_INT))
1898: return;
1899: CMD(CHANATT, 0x0001, unit);
1900: for (i = 1000000; scb_p->scb_command && (i-- > 0); );
1901: if (!i)
1902: printf("pc%d pc586ack(): board not accepting command.\n", unit);
1903: }
1904:
1905: char *
1906: ram_to_ptr(offset, unit)
1907: int unit;
1908: u_short offset;
1909: {
1910: if (offset == PC586NULL)
1911: return(NULL);
1912: if (offset > 0x3fff) {
1913: printf("ram_to_ptr(%x, %d)\n", offset, unit);
1914: panic("range");
1915: return(NULL);
1916: }
1917: return(pc_softc[unit].sram + offset);
1918: }
1919:
1920: #ifndef REQUEUE_DBG
1921: bad_rbd_chain(offset, unit)
1922: {
1923: rbd_t *rbdp;
1924: char *sram = pc_softc[unit].sram;
1925:
1926: for (;;) {
1927: if (offset == PC586NULL)
1928: return 0;
1929: if (offset > 0x3fff) {
1930: printf("pc%d: bad_rbd_chain offset = %x\n",
1931: unit, offset);
1932: pc586_cntrs[unit].rcv.bad_chain++;
1933: return 1;
1934: }
1935:
1936: rbdp = (rbd_t *)(sram + offset);
1937: offset = rbdp->next_rbd_offset;
1938: }
1939: }
1940: #endif REQUEUE_DBG
1941:
1942: u_short
1943: ptr_to_ram(k_va, unit)
1944: char *k_va;
1945: int unit;
1946: {
1947: return((u_short)(k_va - pc_softc[unit].sram));
1948: }
1949:
1950: pc586scb(unit)
1951: {
1952: volatile scb_t *scb = (volatile scb_t *)(pc_softc[unit].sram + OFFSET_SCB);
1953: volatile u_short*cmd = (volatile u_short *)(pc_softc[unit].prom + OFFSET_NORMMODE);
1954: u_short i;
1955:
1956: i = scb->scb_status;
1957: printf("stat: stat %x, cus %x, rus %x //",
1958: (i&0xf000)>>12, (i&0x0700)>>8, (i&0x0070)>>4);
1959: i = scb->scb_command;
1960: printf(" cmd: ack %x, cuc %x, ruc %x\n",
1961: (i&0xf000)>>12, (i&0x0700)>>8, (i&0x0070)>>4);
1962:
1963: printf("crc %d[%d], align %d[%d], rsc %d[%d], ovr %d[%d]\n",
1964: scb->scb_crcerrs, pc586_cntrs[unit].rcv.crc,
1965: scb->scb_alnerrs, pc586_cntrs[unit].rcv.frame,
1966: scb->scb_rscerrs, pc586_cntrs[unit].rcv.rscerrs,
1967: scb->scb_ovrnerrs, pc586_cntrs[unit].rcv.ovrnerrs);
1968:
1969: printf("cbl %x, rfa %x //", scb->scb_cbl_offset, scb->scb_rfa_offset);
1970: printf(" norm %x, ena %x, xfer %x //",
1971: cmd[0] & 1, cmd[3] & 1, cmd[4] & 1);
1972: printf(" atn %x, reset %x, type %x, stat %x\n",
1973: cmd[1] & 1, cmd[2] & 1, cmd[5] & 1, cmd[6] & 1);
1974: }
1975:
1976: pc586tbd(unit)
1977: {
1978: pc_softc_t *is = &pc_softc[unit];
1979: tbd_t *tbd_p = (tbd_t *)(is->sram + OFFSET_TBD);
1980: int i = 0;
1981: int sum = 0;
1982:
1983: do {
1984: sum += (tbd_p->act_count & ~TBD_SW_EOF);
1985: printf("%d: addr %x, count %d (%d), next %x, base %x\n",
1986: i++, tbd_p->buffer_addr,
1987: (tbd_p->act_count & ~TBD_SW_EOF), sum,
1988: tbd_p->next_tbd_offset,
1989: tbd_p->buffer_base);
1990: if (tbd_p->act_count & TBD_SW_EOF)
1991: break;
1992: tbd_p = (tbd_t *)(is->sram + tbd_p->next_tbd_offset);
1993: } while (1);
1994: }
1995:
1996: #ifndef MACH_KERNEL
1997: pc586hdwsleaze(countp, mb_pp, tm_pp, unit)
1998: struct mbuf **tm_pp;
1999: u_char **mb_pp;
2000: u_short *countp;
2001: {
2002: struct mbuf *tm_p = *tm_pp;
2003: u_char *mb_p = *mb_pp;
2004: u_short count = 0;
2005: u_char *cp;
2006: int len;
2007:
2008: pc586_cntrs[unit].xmt.sleaze++;
2009: /*
2010: * can we get a run that will be coallesced or
2011: * that terminates before breaking
2012: */
2013: do {
2014: count += tm_p->m_len;
2015: if (tm_p->m_len & 1)
2016: break;
2017: } while ((tm_p = tm_p->m_next) != (struct mbuf *)0);
2018: if ( (tm_p == (struct mbuf *)0) ||
2019: count > HDW_THRESHOLD) {
2020: *countp = (*tm_pp)->m_len;
2021: *mb_pp = mtod((*tm_pp), u_char *);
2022: printf("\n");
2023: return;
2024: }
2025:
2026: /* we need to copy */
2027: pc586_cntrs[unit].xmt.intrinsic++;
2028: tm_p = *tm_pp;
2029: mb_p = *mb_pp;
2030: count = 0;
2031: cp = (u_char *) t_packet;
2032: do {
2033: bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2034: count += len;
2035: if (count > HDW_THRESHOLD)
2036: break;
2037: cp += len;
2038: if (tm_p->m_next == (struct mbuf *)0)
2039: break;
2040: tm_p = tm_p->m_next;
2041: } while (1);
2042: pc586_cntrs[unit].xmt.intrinsic_count += count;
2043: *countp = count;
2044: *mb_pp = (u_char *) t_packet;
2045: *tm_pp = tm_p;
2046: return;
2047: }
2048:
2049: pc586sftwsleaze(countp, mb_pp, tm_pp, unit)
2050: struct mbuf **tm_pp;
2051: u_char **mb_pp;
2052: u_short *countp;
2053: {
2054: struct mbuf *tm_p = *tm_pp;
2055: u_char *mb_p = *mb_pp;
2056: u_short count = 0;
2057: u_char *cp = (u_char *) t_packet;
2058: int len;
2059:
2060: pc586_cntrs[unit].xmt.chain++;
2061: /* we need to copy */
2062: do {
2063: bcopy(mtod(tm_p, u_char *), cp, len = tm_p->m_len);
2064: count += len;
2065: cp += len;
2066: if (tm_p->m_next == (struct mbuf *)0)
2067: break;
2068: tm_p = tm_p->m_next;
2069: } while (1);
2070:
2071: *countp = count;
2072: *mb_pp = (u_char *) t_packet;
2073: *tm_pp = tm_p;
2074: return;
2075: }
2076: #endif MACH_KERNEL
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.