mem device now takes flag
[unix-history] / usr / src / sys / tahoe / if / if_ace.c
CommitLineData
430f81c3
MK
1/*
2 * Copyright (c) 1988 Regents of the University of California.
3 * All rights reserved.
4 *
003ca8a0
MK
5 * This code is derived from software contributed to Berkeley by
6 * Computer Consoles Inc.
7 *
430f81c3 8 * Redistribution and use in source and binary forms are permitted
616d42db
KB
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the University of California, Berkeley. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
430f81c3 19 *
c18e27ed 20 * @(#)if_ace.c 7.5 (Berkeley) %G%
430f81c3 21 */
bc54ef3d
SL
22
23/*
24 * ACC VERSAbus Ethernet controller
25 */
26#include "ace.h"
27#if NACE > 0
28
4a6cc6f7
SL
29#include "param.h"
30#include "systm.h"
003ca8a0 31#include "malloc.h"
4a6cc6f7
SL
32#include "mbuf.h"
33#include "buf.h"
34#include "protosw.h"
35#include "socket.h"
36#include "vmmac.h"
37#include "ioctl.h"
38#include "errno.h"
39#include "vmparam.h"
56ad8000 40#include "syslog.h"
bc54ef3d
SL
41
42#include "../net/if.h"
43#include "../net/netisr.h"
44#include "../net/route.h"
56ad8000 45#ifdef INET
bc54ef3d
SL
46#include "../netinet/in.h"
47#include "../netinet/in_systm.h"
4a6cc6f7 48#include "../netinet/in_var.h"
bc54ef3d
SL
49#include "../netinet/ip.h"
50#include "../netinet/ip_var.h"
51#include "../netinet/if_ether.h"
56ad8000
SL
52#endif
53#ifdef NS
54#include "../netns/ns.h"
55#include "../netns/ns_if.h"
56#endif
bc54ef3d 57
c18e27ed
KM
58#include "machine/cpu.h"
59#include "machine/pte.h"
cee84cde 60
bc54ef3d
SL
61#include "../tahoe/mtpr.h"
62#include "../tahoeif/if_acereg.h"
4a6cc6f7 63#include "../tahoevba/vbavar.h"
bc54ef3d 64
003ca8a0 65int aceprobe(), aceattach(), acerint(), acecint(), acestart();
bc54ef3d 66struct vba_device *aceinfo[NACE];
5efb6689 67long acestd[] = { 0 };
bc54ef3d 68struct vba_driver acedriver =
0d5152c1 69 { aceprobe, 0, aceattach, 0, acestd, "ace", aceinfo, "v/eiu", 0 };
bc54ef3d
SL
70
71int aceinit(), aceoutput(), aceioctl(), acereset();
72struct mbuf *aceget();
73
74/*
75 * Ethernet software status per interface.
76 *
77 * Each interface is referenced by a network interface structure,
78 * is_if, which the routing code uses to locate the interface.
79 * This structure contains the output queue for the interface, its address, ...
80 */
81struct ace_softc {
82 struct arpcom is_ac; /* Ethernet common part */
83#define is_if is_ac.ac_if /* network-visible interface */
84#define is_addr is_ac.ac_enaddr /* hardware Ethernet address */
bc54ef3d
SL
85 short is_flags;
86#define ACEF_OACTIVE 0x1 /* output is active */
87#define ACEF_RCVPENDING 0x2 /* start rcv in acecint */
88 short is_promiscuous; /* true is enabled */
89 short is_segboundry; /* first TX Seg in dpm */
90 short is_eictr; /* Rx segment tracking ctr */
91 short is_eoctr; /* Tx segment tracking ctr */
92 short is_txnext; /* Next available Tx segment */
93 short is_currnd; /* current random backoff */
94 struct ace_stats is_stats; /* holds board statistics */
95 short is_xcnt; /* count xmitted segments to be acked
96 by the controller */
56ad8000 97 long is_ivec; /* autoconfig interrupt vector base */
0d5152c1
SL
98 struct pte *is_map; /* pte map for dual ported memory */
99 caddr_t is_dpm; /* address of mapped memory */
bc54ef3d
SL
100} ace_softc[NACE];
101extern struct ifnet loif;
102
56ad8000 103aceprobe(reg, vi)
bc54ef3d 104 caddr_t reg;
56ad8000 105 struct vba_device *vi;
bc54ef3d 106{
56ad8000
SL
107 register br, cvec; /* must be r12, r11 */
108 struct acedevice *ap = (struct acedevice *)reg;
109 struct ace_softc *is = &ace_softc[vi->ui_unit];
bc54ef3d
SL
110
111#ifdef lint
9d61b7ff 112 br = 0; cvec = br; br = cvec;
bc54ef3d
SL
113 acerint(0); acecint(0);
114#endif
115 if (badaddr(reg, 2))
56ad8000
SL
116 return (0);
117 movow(&ap->csr, CSR_RESET);
bc54ef3d 118 DELAY(10000);
56ad8000
SL
119#ifdef notdef
120 /*
121 * Select two spaces for the interrupts aligned to an
122 * eight vector boundary and fitting in 8 bits (as
123 * required by the controller) -- YECH. The controller
124 * will be notified later at initialization time.
125 */
126 if ((vi->ui_hd->vh_lastiv -= 2) > 0xff)
127 vi->ui_hd->vh_lastiv = 0x200;
128 is->is_ivec = vi->ui_hd->vh_lastiv = vi->ui_hd->vh_lastiv &~ 0x7;
129#else
130 is->is_ivec = 0x90+vi->ui_unit*8;
131#endif
132 br = 0x14, cvec = is->is_ivec; /* XXX */
133 return (sizeof (*ap));
bc54ef3d
SL
134}
135
136/*
137 * Interface exists: make available by filling in network interface
138 * record. System will initialize the interface when it is ready
139 * to accept packets.
140 */
141aceattach(ui)
142 struct vba_device *ui;
143{
144 register short unit = ui->ui_unit;
145 register struct ace_softc *is = &ace_softc[unit];
146 register struct ifnet *ifp = &is->is_if;
147 register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
148 register short *wp, i;
bc54ef3d
SL
149
150 ifp->if_unit = unit;
151 ifp->if_name = "ace";
152 ifp->if_mtu = ETHERMTU;
153 /*
b50833d9 154 * Get station's addresses and set multicast hash table.
bc54ef3d 155 */
b50833d9
SL
156 for (wp = (short *)addr->station, i = 0; i < 6; i++)
157 is->is_addr[i] = ~*wp++;
158 printf("ace%d: hardware address %s\n", unit,
159 ether_sprintf(is->is_addr));
bc54ef3d 160 is->is_promiscuous = 0;
b50833d9
SL
161 for (wp = (short *)addr->hash, i = 0; i < 8; i++)
162 movow(wp++, ~0xf);
4a6cc6f7
SL
163 movow(&addr->bcastena[0], ~0xffff);
164 movow(&addr->bcastena[1], ~0xffff);
0d5152c1
SL
165 /*
166 * Allocate and map dual ported VERSAbus memory.
167 */
00aaa8a5
MK
168 if (vbmemalloc(32, (caddr_t)ui->ui_flags,
169 &is->is_map, &is->is_dpm) == 0) {
170 printf("ace%d: can't allocate VERSAbus memory map\n", unit);
171 return;
172 }
0d5152c1 173
bc54ef3d 174 ifp->if_init = aceinit;
385e8f24 175 ifp->if_output = ether_output;
003ca8a0 176 ifp->if_start = acestart;
bc54ef3d
SL
177 ifp->if_ioctl = aceioctl;
178 ifp->if_reset = acereset;
003ca8a0 179 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
bc54ef3d
SL
180 if_attach(ifp);
181}
182
bc54ef3d
SL
183/*
184 * Reset of interface after "system" reset.
185 */
186acereset(unit, vban)
187 int unit, vban;
188{
189 register struct vba_device *ui;
190
191 if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 ||
192 ui->ui_vbanum != vban)
193 return;
194 printf(" ace%d", unit);
195 aceinit(unit);
196}
197
198/*
199 * Initialization of interface; clear recorded pending operations
200 */
201aceinit(unit)
202 int unit;
203{
204 register struct ace_softc *is = &ace_softc[unit];
205 register struct vba_device *ui = aceinfo[unit];
206 register struct acedevice *addr;
bc54ef3d 207 register short Csr;
4a6cc6f7 208 register int s;
bc54ef3d 209
003ca8a0 210 if (is->is_if.if_addrlist == (struct ifaddr *)0)
bc54ef3d 211 return;
003ca8a0 212 if ((is->is_if.if_flags & IFF_RUNNING) == 0) {
bc54ef3d
SL
213 /*
214 * Reset the controller, initialize the recieve buffers,
215 * and turn the controller on again and set board online.
216 */
217 addr = (struct acedevice *)ui->ui_addr;
218 s = splimp();
4a6cc6f7 219 movow(&addr->csr, CSR_RESET);
bc54ef3d
SL
220 DELAY(10000);
221
222 /*
0d5152c1
SL
223 * Clean up dpm since the controller might
224 * jumble dpm after reset.
bc54ef3d 225 */
0d5152c1 226 acesetup(unit);
4a6cc6f7 227 movow(&addr->csr, CSR_GO);
bc54ef3d
SL
228 Csr = addr->csr;
229 if (Csr & CSR_ACTIVE) {
56ad8000 230 movow(&addr->ivct, is->is_ivec);
bc54ef3d 231 Csr |= CSR_IENA | is->is_promiscuous;
4a6cc6f7 232 movow(&addr->csr, Csr);
bc54ef3d
SL
233 is->is_flags = 0;
234 is->is_xcnt = 0;
4a6cc6f7 235 is->is_if.if_flags |= IFF_RUNNING;
bc54ef3d
SL
236 }
237 splx(s);
238 }
4a6cc6f7 239 if (is->is_if.if_snd.ifq_head)
003ca8a0 240 acestart(&is->is_if);
bc54ef3d
SL
241}
242
243/*
244 * Start output on interface.
245 * Get another datagram to send off of the interface queue,
246 * and map it to the interface before starting the output.
bc54ef3d 247 */
003ca8a0
MK
248acestart(ifp)
249 register struct ifnet *ifp;
bc54ef3d
SL
250{
251 register struct tx_segment *txs;
4a6cc6f7
SL
252 register long len;
253 register int s;
bc54ef3d 254 struct mbuf *m;
4a6cc6f7 255 short retries;
003ca8a0 256#define is ((struct ace_softc *)ifp)
bc54ef3d
SL
257
258again:
259 txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11));
260 if (txs->tx_csr & TCS_TBFULL) {
261 is->is_stats.tx_busy++;
003ca8a0
MK
262 ifp->if_flags |= IFF_OACTIVE;
263 return (0);
bc54ef3d 264 }
4a6cc6f7 265 s = splimp();
003ca8a0 266 IF_DEQUEUE(&ifp->if_snd, m);
4a6cc6f7 267 splx(s);
0d5152c1 268 if (m == 0) {
003ca8a0
MK
269 ifp->if_flags &= ~IFF_OACTIVE;
270 return (0);
0d5152c1 271 }
003ca8a0 272 len = aceput(txs->tx_data, m);
bc54ef3d
SL
273 retries = txs->tx_csr & TCS_RTC;
274 if (retries > 0)
275 acebakoff(is, txs, retries);
276
277 /*
278 * Ensure minimum packet length.
279 * This makes the safe assumtion that there are no virtual holes
280 * after the data.
281 * For security, it might be wise to zero out the added bytes,
282 * but we're mainly interested in speed at the moment.
283 */
bc54ef3d
SL
284 if (len - sizeof (struct ether_header) < ETHERMIN)
285 len = ETHERMIN + sizeof (struct ether_header);
bc54ef3d
SL
286 if (++is->is_txnext > SEG_MAX)
287 is->is_txnext = is->is_segboundry;
003ca8a0 288 ifp->if_opackets++;
bc54ef3d
SL
289 is->is_xcnt++;
290 len = (len & 0x7fff) | TCS_TBFULL;
4a6cc6f7 291 movow(txs, len);
bc54ef3d 292 goto again;
003ca8a0 293#undef is
bc54ef3d
SL
294}
295
296/*
297 * Transmit done interrupt.
298 */
299acecint(unit)
300 int unit;
301{
302 register struct ace_softc *is = &ace_softc[unit];
bc54ef3d 303 register struct tx_segment *txseg;
4a6cc6f7 304 short eostat;
bc54ef3d
SL
305
306 if (is->is_xcnt <= 0) {
56ad8000 307 log(LOG_ERR, "ace%d: stray xmit interrupt, xcnt %d\n",
bc54ef3d
SL
308 unit, is->is_xcnt);
309 is->is_xcnt = 0;
4a6cc6f7 310 if (is->is_if.if_snd.ifq_head)
003ca8a0 311 acestart(&is->is_if);
bc54ef3d
SL
312 return;
313 }
314 is->is_xcnt--;
315 txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm);
316 eostat = txseg->tx_csr;
317 if ((eostat & TCS_TBFULL) == 0) {
318 is->is_stats.tx_retries += eostat & TCS_RTC;
319 if (eostat & TCS_RTFAIL) {
320 is->is_stats.tx_discarded++;
321 is->is_if.if_oerrors++;
322 } else
323 is->is_stats.tx_datagrams++;
324 if (++is->is_eoctr >= 16)
325 is->is_eoctr = is->is_segboundry;
326 }
4a6cc6f7 327 if (is->is_if.if_snd.ifq_head)
003ca8a0 328 acestart(&is->is_if);
bc54ef3d
SL
329}
330
331/*
332 * Ethernet interface receiver interrupt.
333 * If input error just drop packet.
334 * Otherwise purge input buffered data path and examine
335 * packet to determine type. If can't determine length
336 * from type, then have to drop packet. Othewise decapsulate
337 * packet based on type and pass to type specific higher-level
338 * input routine.
339 */
340acerint(unit)
341 int unit;
342{
343 register struct ace_softc *is = &ace_softc[unit];
344 register struct ifqueue *inq;
345 register struct ether_header *ace;
346 register struct rx_segment *rxseg;
bc54ef3d
SL
347 int len, s, off, resid;
348 struct mbuf *m;
349 short eistat;
350
4a6cc6f7
SL
351 if ((is->is_if.if_flags&IFF_RUNNING) == 0)
352 return;
bc54ef3d
SL
353again:
354 rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm);
355 eistat = rxseg->rx_csr;
356 if ((eistat & RCS_RBFULL) == 0)
357 return;
358 is->is_if.if_ipackets++;
359 if (++is->is_eictr >= is->is_segboundry)
360 is->is_eictr = 0;
361 len = eistat & RCS_RBC;
362 if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) ||
363 len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) {
364 if (eistat & RCS_ROVRN)
365 is->is_stats.rx_overruns++;
366 if (eistat & RCS_RCRC)
367 is->is_stats.rx_crc_errors++;
368 if (eistat & RCS_RODD)
369 is->is_stats.rx_align_errors++;
370 if (len < ET_MINLEN)
371 is->is_stats.rx_underruns++;
372 if (len > ET_MAXLEN+CRC_SIZE)
373 is->is_stats.rx_overruns++;
374 is->is_if.if_ierrors++;
375 rxseg->rx_csr = 0;
376 return;
377 } else
378 is->is_stats.rx_datagrams++;
379 ace = (struct ether_header *)rxseg->rx_data;
bc54ef3d 380 len -= sizeof (struct ether_header);
bc54ef3d 381 /*
4a6cc6f7 382 * Deal with trailer protocol: if type is trailer
bc54ef3d
SL
383 * get true type from first 16-bit word past data.
384 * Remember that type was trailer by setting off.
385 */
386 ace->ether_type = ntohs((u_short)ace->ether_type);
bc54ef3d
SL
387#define acedataaddr(ace, off, type) \
388 ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off))))
4a6cc6f7
SL
389 if (ace->ether_type >= ETHERTYPE_TRAIL &&
390 ace->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
391 off = (ace->ether_type - ETHERTYPE_TRAIL) * 512;
bc54ef3d
SL
392 if (off >= ETHERMTU)
393 goto setup; /* sanity */
394 ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *));
395 resid = ntohs(*(acedataaddr(ace, off+2, u_short *)));
396 if (off + resid > len)
397 goto setup; /* sanity */
398 len = off + resid;
399 } else
400 off = 0;
401 if (len == 0)
402 goto setup;
403
404 /*
405 * Pull packet off interface. Off is nonzero if packet
406 * has trailing header; aceget will then force this header
003ca8a0 407 * information to be at the front.
bc54ef3d 408 */
56ad8000 409 m = aceget((u_char *)rxseg->rx_data, len, off, &is->is_if);
bc54ef3d
SL
410 if (m == 0)
411 goto setup;
bc54ef3d
SL
412 switch (ace->ether_type) {
413
414#ifdef INET
4a6cc6f7 415 case ETHERTYPE_IP:
bc54ef3d
SL
416 schednetisr(NETISR_IP);
417 inq = &ipintrq;
418 break;
56ad8000 419#endif
bc54ef3d 420
4a6cc6f7 421 case ETHERTYPE_ARP:
bc54ef3d
SL
422 arpinput(&is->is_ac, m);
423 goto setup;
4a6cc6f7
SL
424#ifdef NS
425 case ETHERTYPE_NS:
426 schednetisr(NETISR_NS);
427 inq = &nsintrq;
428 break;
429
bc54ef3d
SL
430#endif
431 default:
432 m_freem(m);
433 goto setup;
434 }
435 if (IF_QFULL(inq)) {
436 IF_DROP(inq);
437 m_freem(m);
438 goto setup;
439 }
440 s = splimp();
441 IF_ENQUEUE(inq, m);
442 splx(s);
443setup:
444 rxseg->rx_csr = 0;
445 goto again;
446}
447
bc54ef3d
SL
448/*
449 * Routine to copy from mbuf chain to transmit buffer on the VERSAbus
450 * If packet size is less than the minimum legal size,
451 * the buffer is expanded. We probably should zero out the extra
452 * bytes for security, but that would slow things down.
453 */
003ca8a0 454aceput(txbuf, m)
4a6cc6f7 455 char *txbuf;
bc54ef3d 456 struct mbuf *m;
385e8f24 457#ifdef notdef
bc54ef3d 458{
56ad8000
SL
459 register u_char *bp, *mcp;
460 register short *s1, *s2;
4a6cc6f7 461 register u_int len;
bc54ef3d 462 register struct mbuf *mp;
4a6cc6f7 463 int total;
bc54ef3d 464
003ca8a0 465 total = mp->m_pkthdr.len;
4a6cc6f7 466 bp = (u_char *)txbuf;
385e8f24 467 for (mp = m; mp; mp = mp->m_next) {
bc54ef3d
SL
468 len = mp->m_len;
469 if (len == 0)
470 continue;
bc54ef3d
SL
471 mcp = mtod(mp, u_char *);
472 if (((int)mcp & 01) && ((int)bp & 01)) {
473 /* source & destination at odd addresses */
4a6cc6f7 474 movob(bp++, *mcp++);
bc54ef3d
SL
475 --len;
476 }
477 if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
385e8f24 478 int l = len & 1;
bc54ef3d
SL
479
480 s1 = (short *)bp;
481 s2 = (short *)mcp;
003ca8a0
MK
482 len >>= 1; /* count # of shorts */
483 while (len-- != 0)
4a6cc6f7 484 movow(s1++, *s2++);
385e8f24
KS
485 len = l; /* # remaining bytes */
486 bp = (u_char *)s1;
487 mcp = (u_char *)s2;
488 }
489 while (len-- != 0)
490 movob(bp++, *mcp++);
491 }
492 m_freem(m);
493 return (total);
494}
495#else
496{
497 register u_char *bp, *mcp;
498 register short *s1, *s2;
499 register u_int len;
500 register struct mbuf *mp;
501 int total;
502
503 total = 0;
504 bp = (u_char *)txbuf;
505 for (mp = m; (mp); mp = mp->m_next) {
506 len = mp->m_len;
507 if (len == 0)
508 continue;
509 total += len;
510 mcp = mtod(mp, u_char *);
511 if (((int)mcp & 01) && ((int)bp & 01)) {
512 /* source & destination at odd addresses */
513 movob(bp++, *mcp++);
514 --len;
515 }
516 if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
517 register u_int l;
518
519 s1 = (short *)bp;
520 s2 = (short *)mcp;
521 l = len >> 1; /* count # of shorts */
522 while (l-- != 0)
523 movow(s1++, *s2++);
524 len &= 1; /* # remaining bytes */
bc54ef3d
SL
525 bp = (u_char *)s1;
526 mcp = (u_char *)s2;
527 }
4a6cc6f7
SL
528 while (len-- != 0)
529 movob(bp++, *mcp++);
bc54ef3d
SL
530 }
531 m_freem(m);
532 return (total);
533}
385e8f24 534#endif
bc54ef3d 535
bc54ef3d
SL
536/*
537 * Routine to copy from VERSAbus memory into mbufs.
538 *
539 * Warning: This makes the fairly safe assumption that
540 * mbufs have even lengths.
541 */
542struct mbuf *
003ca8a0 543aceget(rxbuf, totlen, off, ifp)
bc54ef3d 544 u_char *rxbuf;
003ca8a0 545 int totlen, off;
56ad8000 546 struct ifnet *ifp;
bc54ef3d 547{
56ad8000 548 register u_char *cp, *mcp;
bc54ef3d 549 register struct mbuf *m;
003ca8a0 550 register int tlen;
bc54ef3d 551 struct mbuf *top = 0, **mp = &top;
003ca8a0
MK
552 int len;
553 u_char *packet_end;
554
555 rxbuf += sizeof (struct ether_header);
556 cp = rxbuf;
557 packet_end = cp + totlen;
558 if (off) {
559 off += 2 * sizeof(u_short);
560 totlen -= 2 *sizeof(u_short);
561 cp = rxbuf + off;
562 }
563
564 MGETHDR(m, M_DONTWAIT, MT_DATA);
565 if (m == 0)
566 return (0);
567 m->m_pkthdr.rcvif = ifp;
568 m->m_pkthdr.len = totlen;
569 m->m_len = MHLEN;
bc54ef3d 570
bc54ef3d 571 while (totlen > 0) {
003ca8a0
MK
572 if (top) {
573 MGET(m, M_DONTWAIT, MT_DATA);
574 if (m == 0) {
575 m_freem(top);
576 return (0);
577 }
578 m->m_len = MLEN;
579 }
580 len = min(totlen, (packet_end - cp));
581 if (len >= MINCLSIZE) {
582 MCLGET(m, M_DONTWAIT);
583 if (m->m_flags & M_EXT)
584 m->m_len = len = min(len, MCLBYTES);
6adc8625 585 else
003ca8a0 586 len = m->m_len;
bc54ef3d 587 } else {
56ad8000 588 /*
003ca8a0 589 * Place initial small packet/header at end of mbuf.
56ad8000 590 */
003ca8a0
MK
591 if (len < m->m_len) {
592 if (top == 0 && len + max_linkhdr <= m->m_len)
593 m->m_data += max_linkhdr;
594 m->m_len = len;
595 } else
596 len = m->m_len;
56ad8000 597 }
003ca8a0 598 mcp = mtod(m, u_char *);
bc54ef3d
SL
599 /*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/
600 /*cp += len; mcp += len;*/
601 tlen = len;
602 if (((int)mcp & 01) && ((int)cp & 01)) {
603 /* source & destination at odd addresses */
604 *mcp++ = *cp++;
605 --tlen;
606 }
607 if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) {
608 register short *s1, *s2;
609 register int l;
610
611 s1 = (short *)mcp;
612 s2 = (short *)cp;
613 l = tlen >> 1; /* count # of shorts */
614 while (l-- > 0) /* copy shorts */
615 *s1++ = *s2++;
616 tlen &= 1; /* # remaining bytes */
617 mcp = (u_char *)s1;
618 cp = (u_char *)s2;
619 }
620 while (tlen-- > 0)
621 *mcp++ = *cp++;
622 *mp = m;
623 mp = &m->m_next;
003ca8a0
MK
624 totlen -= len;
625 if (cp == packet_end)
626 cp = rxbuf;
bc54ef3d
SL
627 }
628 return (top);
bc54ef3d
SL
629}
630
b50833d9
SL
631/* backoff table masks */
632short random_mask_tbl[16] = {
6adc8625
SL
633 0x0040, 0x00c0, 0x01c0, 0x03c0, 0x07c0, 0x0fc0, 0x1fc0, 0x3fc0,
634 0x7fc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0, 0xffc0
b50833d9
SL
635};
636
bc54ef3d
SL
637acebakoff(is, txseg, retries)
638 struct ace_softc *is;
639 struct tx_segment *txseg;
640 register int retries;
641{
642 register short *pBakNum, random_num;
643 short *pMask;
644
645 pMask = &random_mask_tbl[0];
646 pBakNum = &txseg->tx_backoff[0];
647 while (--retries >= 0) {
648 random_num = (is->is_currnd = (is->is_currnd * 18741)-13849);
649 random_num &= *pMask++;
6adc8625 650 *pBakNum++ = random_num ^ (short)(0xff00 | 0x00fc);
bc54ef3d
SL
651 }
652}
653
654/*
655 * Process an ioctl request.
656 */
657aceioctl(ifp, cmd, data)
658 register struct ifnet *ifp;
659 int cmd;
660 caddr_t data;
661{
4a6cc6f7 662 register struct ifaddr *ifa = (struct ifaddr *)data;
56ad8000 663 struct acedevice *addr;
4a6cc6f7 664 int s = splimp(), error = 0;
bc54ef3d 665
bc54ef3d
SL
666 switch (cmd) {
667
668 case SIOCSIFADDR:
4a6cc6f7 669 ifp->if_flags |= IFF_UP;
385e8f24 670 switch (ifa->ifa_addr->sa_family) {
56ad8000
SL
671#ifdef INET
672 case AF_INET:
673 aceinit(ifp->if_unit); /* before arpwhohas */
674 ((struct arpcom *)ifp)->ac_ipaddr =
675 IA_SIN(ifa)->sin_addr;
676 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
677 break;
678#endif
679#ifdef NS
680 case AF_NS: {
87a9540f
SL
681 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
682 struct ace_softc *is = &ace_softc[ifp->if_unit];
56ad8000
SL
683
684 if (!ns_nullhost(*ina)) {
685 ifp->if_flags &= ~IFF_RUNNING;
56ad8000 686 addr = (struct acedevice *)
87a9540f 687 aceinfo[ifp->if_unit]->ui_addr;
56ad8000
SL
688 movow(&addr->csr, CSR_RESET);
689 DELAY(10000);
690 /* set station address & copy addr to arp */
b50833d9 691 acesetaddr(ifp->if_unit, addr,
56ad8000
SL
692 ina->x_host.c_host);
693 } else
87a9540f 694 ina->x_host = *(union ns_host *)is->is_addr;
56ad8000
SL
695 aceinit(ifp->if_unit);
696 break;
697 }
698#endif
699 default:
700 aceinit(ifp->if_unit);
701 break;
702 }
bc54ef3d
SL
703 break;
704
56ad8000
SL
705 case SIOCSIFFLAGS:
706 if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) {
707 addr = (struct acedevice *)
708 (aceinfo[ifp->if_unit]->ui_addr);
709 movow(&addr->csr, CSR_RESET);
710 ifp->if_flags &= ~IFF_RUNNING;
711 } else if (ifp->if_flags&IFF_UP &&
712 (ifp->if_flags&IFF_RUNNING) == 0)
713 aceinit(ifp->if_unit);
bc54ef3d 714 break;
bc54ef3d
SL
715
716 default:
717 error = EINVAL;
718 }
719 splx(s);
720 return (error);
721}
722
b50833d9
SL
723/*
724 * Set the on-board station address, then read it back
725 * to initialize the address used by ARP (among others).
726 */
727acesetaddr(unit, addr, station)
728 short unit;
729 struct acedevice *addr;
9d61b7ff 730 u_char *station;
b50833d9
SL
731{
732 struct ace_softc *is = &ace_softc[unit];
733 register short *wp, i;
734
735 for (wp = (short *)addr->station, i = 0; i < 6; i++)
736 movow(wp++, ~*station++);
737 for (wp = (short *)addr->station, i = 0; i < 6; i++)
738 is->is_addr[i] = ~*wp++;
739 printf("ace%d: hardware address %s\n", unit,
740 ether_sprintf(is->is_addr));
741}
742
743/*
744 * Setup the device for use. Initialize dual-ported memory,
745 * backoff parameters, and various other software state.
746 */
0d5152c1 747acesetup(unit)
bc54ef3d
SL
748 int unit;
749{
750 register struct ace_softc *is = &ace_softc[unit];
bc54ef3d 751 register char *pData1;
0d5152c1
SL
752 register short i;
753 struct acedevice *addr;
bc54ef3d 754
0d5152c1 755 bzero(is->is_dpm, 16384*2);
bc54ef3d 756 is->is_currnd = 49123;
0d5152c1 757 addr = (struct acedevice *)aceinfo[unit]->ui_addr;
bc54ef3d 758 is->is_segboundry = (addr->segb >> 11) & 0xf;
0d5152c1 759 pData1 = is->is_dpm + (is->is_segboundry << 11);
bc54ef3d
SL
760 for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) {
761 acebakoff(is, (struct tx_segment *)pData1, 15);
762 pData1 += sizeof (struct tx_segment);
763 }
764 is->is_eictr = 0;
765 is->is_eoctr = is->is_txnext = is->is_segboundry;
766 bzero((char *)&is->is_stats, sizeof (is->is_stats));
767}
768#endif