xref: /original-bsd/sys/vax/if/if_ec.c (revision 05cf3734)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)if_ec.c	7.7 (Berkeley) 06/28/90
8  */
9 
10 #include "ec.h"
11 #if NEC > 0
12 
13 /*
14  * 3Com Ethernet Controller interface
15  */
16 #include "machine/pte.h"
17 
18 #include "param.h"
19 #include "systm.h"
20 #include "mbuf.h"
21 #include "buf.h"
22 #include "protosw.h"
23 #include "socket.h"
24 #include "syslog.h"
25 #include "vmmac.h"
26 #include "ioctl.h"
27 #include "errno.h"
28 
29 #include "../net/if.h"
30 #include "../net/netisr.h"
31 #include "../net/route.h"
32 
33 #ifdef INET
34 #include "../netinet/in.h"
35 #include "../netinet/in_systm.h"
36 #include "../netinet/in_var.h"
37 #include "../netinet/ip.h"
38 #include "../netinet/if_ether.h"
39 #endif
40 
41 #ifdef NS
42 #include "../netns/ns.h"
43 #include "../netns/ns_if.h"
44 #endif
45 
46 #include "../vax/cpu.h"
47 #include "../vax/mtpr.h"
48 #include "if_ecreg.h"
49 #include "if_uba.h"
50 #include "../vaxuba/ubareg.h"
51 #include "../vaxuba/ubavar.h"
52 
53 #if CLSIZE == 2
54 #define ECBUFSIZE	32		/* on-board memory, clusters */
55 #endif
56 
57 int	ecubamem(), ecprobe(), ecattach(), ecrint(), ecxint(), eccollide();
58 struct	uba_device *ecinfo[NEC];
59 u_short ecstd[] = { 0 };
60 struct	uba_driver ecdriver =
61 	{ ecprobe, 0, ecattach, 0, ecstd, "ec", ecinfo, 0, 0, 0, 0, ecubamem };
62 
63 int	ecinit(),ecioctl(),ecstart(),ecreset(),ether_output();
64 struct	mbuf *ecget();
65 
66 extern struct ifnet loif;
67 
68 /*
69  * Ethernet software status per interface.
70  *
71  * Each interface is referenced by a network interface structure,
72  * es_if, which the routing code uses to locate the interface.
73  * This structure contains the output queue for the interface, its address, ...
74  * We also have, for each interface, a UBA interface structure, which
75  * contains information about the UNIBUS resources held by the interface:
76  * map registers, buffered data paths, etc.  Information is cached in this
77  * structure for use by the if_uba.c routines in running the interface
78  * efficiently.
79  */
80 struct	ec_softc {
81 	struct	arpcom es_ac;		/* common Ethernet structures */
82 #define	es_if	es_ac.ac_if		/* network-visible interface */
83 #define	es_addr	es_ac.ac_enaddr		/* hardware Ethernet address */
84 	struct	ifuba es_ifuba;		/* UNIBUS resources */
85 	short	es_mask;		/* mask for current output delay */
86 	u_char	*es_buf[16];		/* virtual addresses of buffers */
87 } ec_softc[NEC];
88 
89 /*
90  * Configure on-board memory for an interface.
91  * Called from autoconfig and after a uba reset.
92  * The address of the memory on the uba is supplied in the device flags.
93  */
94 ecubamem(ui, uban)
95 	register struct uba_device *ui;
96 {
97 	register caddr_t ecbuf = (caddr_t) &umem[uban][ui->ui_flags];
98 	register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr;
99 
100 	/*
101 	 * Make sure csr is there (we run before ecprobe).
102 	 */
103 	if (badaddr((caddr_t)addr, 2))
104 		return (-1);
105 #if VAX780
106 	if (cpu == VAX_780 && uba_hd[uban].uh_uba->uba_sr) {
107 		uba_hd[uban].uh_uba->uba_sr = uba_hd[uban].uh_uba->uba_sr;
108 		return (-1);
109 	}
110 #endif
111 	/*
112 	 * Make sure memory is turned on
113 	 */
114 	addr->ec_rcr = EC_AROM;
115 	/*
116 	 * Tell the system that the board has memory here, so it won't
117 	 * attempt to allocate the addresses later.
118 	 */
119 	if (ubamem(uban, ui->ui_flags, ECBUFSIZE*CLSIZE, 1) == 0) {
120 		printf("ec%d: cannot reserve uba addresses\n", ui->ui_unit);
121 		addr->ec_rcr = EC_MDISAB;	/* disable memory */
122 		return (-1);
123 	}
124 	/*
125 	 * Check for existence of buffers on Unibus.
126 	 */
127 	if (badaddr((caddr_t)ecbuf, 2)) {
128 bad:
129 		printf("ec%d: buffer mem not found\n", ui->ui_unit);
130 		(void) ubamem(uban, ui->ui_flags, ECBUFSIZE*2, 0);
131 		addr->ec_rcr = EC_MDISAB;	/* disable memory */
132 		return (-1);
133 	}
134 #if VAX780
135 	if (cpu == VAX_780 && uba_hd[uban].uh_uba->uba_sr) {
136 		uba_hd[uban].uh_uba->uba_sr = uba_hd[uban].uh_uba->uba_sr;
137 		goto bad;
138 	}
139 #endif
140 	if (ui->ui_alive == 0)		/* Only printf from autoconfig */
141 		printf("ec%d: mem %x-%x\n", ui->ui_unit,
142 			ui->ui_flags, ui->ui_flags + ECBUFSIZE*CLBYTES - 1);
143 	ui->ui_type = 1;		/* Memory on, allocated */
144 	return (0);
145 }
146 
147 /*
148  * Do output DMA to determine interface presence and
149  * interrupt vector.  DMA is too short to disturb other hosts.
150  */
151 ecprobe(reg, ui)
152 	caddr_t reg;
153 	struct uba_device *ui;
154 {
155 	register int br, cvec;		/* r11, r10 value-result */
156 	register struct ecdevice *addr = (struct ecdevice *)reg;
157 	register caddr_t ecbuf = (caddr_t) &umem[ui->ui_ubanum][ui->ui_flags];
158 
159 #ifdef lint
160 	br = 0; cvec = br; br = cvec;
161 	ecrint(0); ecxint(0); eccollide(0);
162 #endif
163 
164 	/*
165 	 * Check that buffer memory was found and enabled.
166 	 */
167 	if (ui->ui_type == 0)
168 		return(0);
169 	/*
170 	 * Make a one byte packet in what should be buffer #0.
171 	 * Submit it for sending.  This should cause an xmit interrupt.
172 	 * The xmit interrupt vector is 8 bytes after the receive vector,
173 	 * so adjust for this before returning.
174 	 */
175 	*(u_short *)ecbuf = (u_short) 03777;
176 	ecbuf[03777] = '\0';
177 	addr->ec_xcr = EC_XINTEN|EC_XWBN;
178 	DELAY(100000);
179 	addr->ec_xcr = EC_XCLR;
180 	if (cvec > 0 && cvec != 0x200) {
181 		if (cvec & 04) {	/* collision interrupt */
182 			cvec -= 04;
183 			br += 1;		/* rcv is collision + 1 */
184 		} else {		/* xmit interrupt */
185 			cvec -= 010;
186 			br += 2;		/* rcv is xmit + 2 */
187 		}
188 	}
189 	return (1);
190 }
191 
192 /*
193  * Interface exists: make available by filling in network interface
194  * record.  System will initialize the interface when it is ready
195  * to accept packets.
196  */
197 ecattach(ui)
198 	struct uba_device *ui;
199 {
200 	struct ec_softc *es = &ec_softc[ui->ui_unit];
201 	register struct ifnet *ifp = &es->es_if;
202 	register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr;
203 	int i, j;
204 	u_char *cp;
205 
206 	ifp->if_unit = ui->ui_unit;
207 	ifp->if_name = "ec";
208 	ifp->if_mtu = ETHERMTU;
209 
210 	/*
211 	 * Read the ethernet address off the board, one nibble at a time.
212 	 */
213 	addr->ec_xcr = EC_UECLR; /* zero address pointer */
214 	addr->ec_rcr = EC_AROM;
215 	cp = es->es_addr;
216 #define	NEXTBIT	addr->ec_rcr = EC_AROM|EC_ASTEP; addr->ec_rcr = EC_AROM
217 	for (i=0; i < sizeof (es->es_addr); i++) {
218 		*cp = 0;
219 		for (j=0; j<=4; j+=4) {
220 			*cp |= ((addr->ec_rcr >> 8) & 0xf) << j;
221 			NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT;
222 		}
223 		cp++;
224 	}
225 	printf("ec%d: hardware address %s\n", ui->ui_unit,
226 		ether_sprintf(es->es_addr));
227 	ifp->if_init = ecinit;
228 	ifp->if_ioctl = ecioctl;
229 	ifp->if_output = ether_output;
230 	ifp->if_start = ecstart;
231 	ifp->if_reset = ecreset;
232 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
233 	for (i=0; i<16; i++)
234 		es->es_buf[i]
235 		    = (u_char *)&umem[ui->ui_ubanum][ui->ui_flags + 2048*i];
236 	if_attach(ifp);
237 }
238 
239 /*
240  * Reset of interface after UNIBUS reset.
241  * If interface is on specified uba, reset its state.
242  */
243 ecreset(unit, uban)
244 	int unit, uban;
245 {
246 	register struct uba_device *ui;
247 
248 	if (unit >= NEC || (ui = ecinfo[unit]) == 0 || ui->ui_alive == 0 ||
249 	    ui->ui_ubanum != uban)
250 		return;
251 	printf(" ec%d", unit);
252 	ec_softc[unit].es_if.if_flags &= ~IFF_RUNNING;
253 	ecinit(unit);
254 }
255 
256 /*
257  * Initialization of interface; clear recorded pending
258  * operations, and reinitialize UNIBUS usage.
259  */
260 ecinit(unit)
261 	int unit;
262 {
263 	struct ec_softc *es = &ec_softc[unit];
264 	struct ecdevice *addr;
265 	register struct ifnet *ifp = &es->es_if;
266 	int i, s;
267 
268 	/* not yet, if address still unknown */
269 	if (ifp->if_addrlist == (struct ifaddr *)0)
270 		return;
271 
272 	/*
273 	 * Hang receive buffers and start any pending writes.
274 	 * Writing into the rcr also makes sure the memory
275 	 * is turned on.
276 	 */
277 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
278 		u_short start_read;
279 		addr = (struct ecdevice *)ecinfo[unit]->ui_addr;
280 		s = splimp();
281 		/*
282 		 * write our ethernet address into the address recognition ROM
283 		 * so we can always use the same EC_READ bits (referencing ROM),
284 		 * in case we change the address sometime.
285 		 * Note that this is safe here as the receiver is NOT armed.
286 		 */
287 		ec_setaddr(es->es_addr, unit);
288 		/*
289 		 * Arm the receiver
290 #ifdef MULTI
291 		if (es->es_if.if_flags & IFF_PROMISC)
292 			start_read = EC_PROMISC;
293 		else if (es->es_if.if_flags & IFF_MULTI)
294 			start_read = EC_MULTI;
295 		else
296 #endif MULTI
297 			start_read = EC_READ;
298 		 */
299 		for (i = ECRHBF; i >= ECRLBF; i--)
300 			addr->ec_rcr = EC_READ | i;
301 		es->es_if.if_flags &= ~IFF_OACTIVE;
302 		es->es_mask = ~0;
303 		es->es_if.if_flags |= IFF_RUNNING;
304 		if (es->es_if.if_snd.ifq_head)
305 			(void) ecstart(&es->es_if);
306 		splx(s);
307 	}
308 }
309 
310 /*
311  * Start output on interface.  Get another datagram to send
312  * off of the interface queue, and copy it to the interface
313  * before starting the output.
314  */
315 ecstart(ifp)
316 struct ifnet *ifp;
317 {
318 	int unit = ifp->if_unit;
319 	register struct ec_softc *es = &ec_softc[unit];
320 	struct ecdevice *addr;
321 	struct mbuf *m;
322 
323 	if ((es->es_if.if_flags & IFF_RUNNING) == 0)
324 		return (0);
325 	IF_DEQUEUE(&es->es_if.if_snd, m);
326 	if (m == 0)
327 		return (0);
328 	ecput(es->es_buf[ECTBF], m);
329 	addr = (struct ecdevice *)ecinfo[unit]->ui_addr;
330 	addr->ec_xcr = EC_WRITE|ECTBF;
331 	es->es_if.if_flags |= IFF_OACTIVE;
332 	return (0);
333 }
334 
335 /*
336  * Ethernet interface transmitter interrupt.
337  * Start another output if more data to send.
338  */
339 ecxint(unit)
340 	int unit;
341 {
342 	register struct ec_softc *es = &ec_softc[unit];
343 	register struct ecdevice *addr =
344 		(struct ecdevice *)ecinfo[unit]->ui_addr;
345 
346 	if ((es->es_if.if_flags & IFF_OACTIVE) == 0)
347 		return;
348 	if ((addr->ec_xcr&EC_XDONE) == 0 || (addr->ec_xcr&EC_XBN) != ECTBF) {
349 		printf("ec%d: stray xmit interrupt, xcr=%b\n", unit,
350 			addr->ec_xcr, EC_XBITS);
351 		es->es_if.if_flags &= ~IFF_OACTIVE;
352 		addr->ec_xcr = EC_XCLR;
353 		return;
354 	}
355 	es->es_if.if_opackets++;
356 	es->es_if.if_flags &= ~IFF_OACTIVE;
357 	es->es_mask = ~0;
358 	addr->ec_xcr = EC_XCLR;
359 	if (es->es_if.if_snd.ifq_head)
360 		(void) ecstart(&es->es_if);
361 }
362 
363 /*
364  * Collision on ethernet interface.  Do exponential
365  * backoff, and retransmit.  If have backed off all
366  * the way print warning diagnostic, and drop packet.
367  */
368 eccollide(unit)
369 	int unit;
370 {
371 	register struct ec_softc *es = &ec_softc[unit];
372 	register struct ecdevice *addr =
373 	    (struct ecdevice *)ecinfo[unit]->ui_addr;
374 	register i;
375 	int delay;
376 
377 	es->es_if.if_collisions++;
378 	if ((es->es_if.if_flags & IFF_OACTIVE) == 0)
379 		return;
380 
381 	/*
382 	 * Es_mask is a 16 bit number with n low zero bits, with
383 	 * n the number of backoffs.  When es_mask is 0 we have
384 	 * backed off 16 times, and give up.
385 	 */
386 	if (es->es_mask == 0) {
387 		u_short start_read;
388 		es->es_if.if_oerrors++;
389 		log(LOG_ERR, "ec%d: send error\n", unit);
390 		/*
391 		 * Reset interface, then requeue rcv buffers.
392 		 * Some incoming packets may be lost, but that
393 		 * can't be helped.
394 		 */
395 		addr->ec_xcr = EC_UECLR;
396 #ifdef MULTI
397 		if (es->es_if.if_flags & IFF_PROMISC)
398 			start_read = EC_PROMISC;
399 		else if (es->es_if.if_flags & IFF_MULTI)
400 			start_read = EC_MULTI;
401 		else
402 #endif MULTI
403 			start_read = EC_READ;
404 		for (i=ECRHBF; i>=ECRLBF; i--)
405 			addr->ec_rcr = start_read|i;
406 		/*
407 		 * Reset and transmit next packet (if any).
408 		 */
409 		es->es_if.if_flags &= ~IFF_OACTIVE;
410 		es->es_mask = ~0;
411 		if (es->es_if.if_snd.ifq_head)
412 			(void) ecstart(&es->es_if);
413 		return;
414 	}
415 	/*
416 	 * Do exponential backoff.  Compute delay based on low bits
417 	 * of the interval timer (1 bit for each transmission attempt,
418 	 * but at most 5 bits).  Then delay for that number of
419 	 * slot times.  A slot time is 51.2 microseconds (rounded to 51).
420 	 * This does not take into account the time already used to
421 	 * process the interrupt.
422 	 */
423 	es->es_mask <<= 1;
424 	delay = mfpr(ICR) & 0x1f &~ es->es_mask;
425 	DELAY(delay * 51);
426 	/*
427 	 * Clear the controller's collision flag, thus enabling retransmit.
428 	 */
429 	addr->ec_xcr = EC_CLEAR;
430 }
431 
432 /*
433  * Ethernet interface receiver interrupt.
434  * If input error just drop packet.
435  * Otherwise examine
436  * packet to determine type.  If can't determine length
437  * from type, then have to drop packet.  Othewise decapsulate
438  * packet based on type and pass to type specific higher-level
439  * input routine.
440  */
441 ecrint(unit)
442 	int unit;
443 {
444 	struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr;
445 
446 	while (addr->ec_rcr & EC_RDONE)
447 		ecread(unit);
448 }
449 
450 ecread(unit)
451 	int unit;
452 {
453 	register struct ec_softc *es = &ec_softc[unit];
454 	struct ecdevice *addr = (struct ecdevice *)ecinfo[unit]->ui_addr;
455 	register struct ether_header *ec;
456     	struct mbuf *m;
457 	int len, off, resid, ecoff, rbuf;
458 	register struct ifqueue *inq;
459 	u_short start_read;
460 	u_char *ecbuf;
461 
462 	es->es_if.if_ipackets++;
463 	rbuf = addr->ec_rcr & EC_RBN;
464 	if (rbuf < ECRLBF || rbuf > ECRHBF)
465 		panic("ecrint");
466 	ecbuf = es->es_buf[rbuf];
467 	ecoff = *(short *)ecbuf;
468 	if (ecoff <= ECRDOFF || ecoff > 2046) {
469 		es->es_if.if_ierrors++;
470 #ifdef notdef
471 		if (es->es_if.if_ierrors % 100 == 0)
472 			printf("ec%d: += 100 input errors\n", unit);
473 #endif
474 		goto setup;
475 	}
476 
477 	/*
478 	 * Get input data length.
479 	 * Get pointer to ethernet header (in input buffer).
480 	 * Deal with trailer protocol: if type is trailer type
481 	 * get true type from first 16-bit word past data.
482 	 * Remember that type was trailer by setting off.
483 	 */
484 	len = ecoff - ECRDOFF - sizeof (struct ether_header);
485 	ec = (struct ether_header *)(ecbuf + ECRDOFF);
486 	ec->ether_type = ntohs((u_short)ec->ether_type);
487 #define	ecdataaddr(ec, off, type)	((type)(((caddr_t)((ec)+1)+(off))))
488 	if (ec->ether_type >= ETHERTYPE_TRAIL &&
489 	    ec->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
490 		off = (ec->ether_type - ETHERTYPE_TRAIL) * 512;
491 		if (off >= ETHERMTU)
492 			goto setup;		/* sanity */
493 		ec->ether_type = ntohs(*ecdataaddr(ec, off, u_short *));
494 		resid = ntohs(*(ecdataaddr(ec, off+2, u_short *)));
495 		if (off + resid > len)
496 			goto setup;		/* sanity */
497 		len = off + resid;
498 	} else
499 		off = 0;
500 	if (len == 0)
501 		goto setup;
502 
503 	/*
504 	 * Pull packet off interface.  Off is nonzero if packet
505 	 * has trailing header; ecget will then force this header
506 	 * information to be at the front, but we still have to drop
507 	 * the type and length which are at the front of any trailer data.
508 	 */
509 	m = ecget(ecbuf, len, off, &es->es_if);
510 	if (m)
511 		ether_input(&es->es_if, ec, m);
512 	/*
513 	 * Reset for next packet.
514 	 */
515 setup:
516 #ifdef MULTI
517 		if (es->es_if.if_flags & IFF_PROMISC)
518 			start_read = EC_PROMISC;
519 		else if (es->es_if.if_flags & IFF_MULTI)
520 			start_read = EC_MULTI;
521 		else
522 #endif MULTI
523 			start_read = EC_READ;
524 	addr->ec_rcr = start_read|EC_RCLR|rbuf;
525 }
526 
527 /*
528  * Routine to copy from mbuf chain to transmit
529  * buffer in UNIBUS memory.
530  * If packet size is less than the minimum legal size,
531  * the buffer is expanded.  We probably should zero out the extra
532  * bytes for security, but that would slow things down.
533  */
534 ecput(ecbuf, m)
535 	u_char *ecbuf;
536 	struct mbuf *m;
537 {
538 	register struct mbuf *mp;
539 	register int off;
540 	u_char *bp;
541 
542 	for (off = 2048, mp = m; mp; mp = mp->m_next)
543 		off -= mp->m_len;
544 	if (2048 - off < ETHERMIN + sizeof (struct ether_header))
545 		off = 2048 - ETHERMIN - sizeof (struct ether_header);
546 	*(u_short *)ecbuf = off;
547 	bp = (u_char *)(ecbuf + off);
548 	for (mp = m; mp; mp = mp->m_next) {
549 		register unsigned len = mp->m_len;
550 		u_char *mcp;
551 
552 		if (len == 0)
553 			continue;
554 		mcp = mtod(mp, u_char *);
555 		if ((unsigned)bp & 01) {
556 			*bp++ = *mcp++;
557 			len--;
558 		}
559 		if (off = (len >> 1)) {
560 			register u_short *to, *from;
561 
562 			to = (u_short *)bp;
563 			from = (u_short *)mcp;
564 			do
565 				*to++ = *from++;
566 			while (--off > 0);
567 			bp = (u_char *)to,
568 			mcp = (u_char *)from;
569 		}
570 		if (len & 01)
571 			*bp++ = *mcp++;
572 	}
573 	m_freem(m);
574 }
575 
576 /*
577  * Routine to copy from UNIBUS memory into mbufs.
578  * Similar in spirit to if_rubaget.
579  *
580  * Warning: This makes the fairly safe assumption that
581  * mbufs have even lengths.
582  */
583 struct mbuf *
584 ecget(ecbuf, totlen, off0, ifp)
585 	u_char *ecbuf;
586 	int totlen, off0;
587 	struct ifnet *ifp;
588 {
589 	register struct mbuf *m;
590 	struct mbuf *top = 0, **mp = &top;
591 	register int off = off0, len;
592 	u_char *cp = (ecbuf += ECRDOFF + sizeof (struct ether_header));
593 	u_char *packet_end = cp + totlen;
594 
595 	if (off) {
596 		off += 2 * sizeof(u_short);
597 		totlen -= 2 *sizeof(u_short);
598 		cp += off;
599 	}
600 
601 	MGETHDR(m, M_DONTWAIT, MT_DATA);
602 	if (m == 0)
603 		return (0);
604 	m->m_pkthdr.rcvif = ifp;
605 	m->m_pkthdr.len = totlen;
606 	m->m_len = MHLEN;
607 
608 	while (totlen > 0) {
609 		register int words;
610 		u_char *mcp;
611 
612 		if (top) {
613 			MGET(m, M_DONTWAIT, MT_DATA);
614 			if (m == 0) {
615 				m_freem(top);
616 				return (0);
617 			}
618 			m->m_len = MLEN;
619 		}
620 		len = min(totlen, (packet_end - cp));
621 		if (len >= MINCLSIZE) {
622 			MCLGET(m, M_DONTWAIT);
623 			if (m->m_flags & M_EXT)
624 				m->m_len = len = min(len, MCLBYTES);
625 			else
626 				len = m->m_len;
627 		} else {
628 			/*
629 			 * Place initial small packet/header at end of mbuf.
630 			 */
631 			if (len < m->m_len) {
632 				if (top == 0 && len + max_linkhdr <= m->m_len)
633 					m->m_data += max_linkhdr;
634 				m->m_len = len;
635 			} else
636 				len = m->m_len;
637 		}
638 		mcp = mtod(m, u_char *);
639 		if (words = (len >> 1)) {
640 			register u_short *to, *from;
641 
642 			to = (u_short *)mcp;
643 			from = (u_short *)cp;
644 			do
645 				*to++ = *from++;
646 			while (--words > 0);
647 			mcp = (u_char *)to;
648 			cp = (u_char *)from;
649 		}
650 		if (len & 01)
651 			*mcp++ = *cp++;
652 		*mp = m;
653 		mp = &m->m_next;
654 		totlen -= len;
655 		if (cp == packet_end)
656 			cp = ecbuf;
657 	}
658 	return (top);
659 bad:
660 	m_freem(top);
661 	return (0);
662 }
663 
664 /*
665  * Process an ioctl request.
666  */
667 ecioctl(ifp, cmd, data)
668 	register struct ifnet *ifp;
669 	int cmd;
670 	caddr_t data;
671 {
672 	register struct ifaddr *ifa = (struct ifaddr *)data;
673 	struct ec_softc *es = &ec_softc[ifp->if_unit];
674 	struct ecdevice *addr;
675 	int s = splimp(), error = 0;
676 
677 	addr = (struct ecdevice *)(ecinfo[ifp->if_unit]->ui_addr);
678 
679 	switch (cmd) {
680 
681 	case SIOCSIFADDR:
682 		ifp->if_flags |= IFF_UP;
683 
684 		switch (ifa->ifa_addr->sa_family) {
685 #ifdef INET
686 		case AF_INET:
687 			ecinit(ifp->if_unit);	/* before arpwhohas */
688 			((struct arpcom *)ifp)->ac_ipaddr =
689 				IA_SIN(ifa)->sin_addr;
690 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
691 			break;
692 #endif
693 #ifdef NS
694 		case AF_NS:
695 		    {
696 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
697 
698 			if (ns_nullhost(*ina))
699 				ina->x_host = *(union ns_host *)(es->es_addr);
700 			else {
701 				/*
702 				 * The manual says we can't change the address
703 				 * while the receiver is armed,
704 				 * so reset everything
705 				 */
706 				ifp->if_flags &= ~IFF_RUNNING;
707 				bcopy((caddr_t)ina->x_host.c_host,
708 				    (caddr_t)es->es_addr, sizeof(es->es_addr));
709 			}
710 			ecinit(ifp->if_unit); /* does ec_setaddr() */
711 			break;
712 		    }
713 #endif
714 		default:
715 			ecinit(ifp->if_unit);
716 			break;
717 		}
718 		break;
719 
720 	case SIOCSIFFLAGS:
721 		if ((ifp->if_flags & IFF_UP) == 0 &&
722 		    ifp->if_flags & IFF_RUNNING) {
723 			addr->ec_xcr = EC_UECLR;
724 			ifp->if_flags &= ~IFF_RUNNING;
725 		} else if (ifp->if_flags & IFF_UP &&
726 		    (ifp->if_flags & IFF_RUNNING) == 0)
727 			ecinit(ifp->if_unit);
728 		break;
729 
730 	default:
731 		error = EINVAL;
732 	}
733 	splx(s);
734 	return (error);
735 }
736 
737 ec_setaddr(physaddr,unit)
738 	u_char *physaddr;
739 	int unit;
740 {
741 	struct ec_softc *es = &ec_softc[unit];
742 	struct uba_device *ui = ecinfo[unit];
743 	register struct ecdevice *addr = (struct ecdevice *)ui->ui_addr;
744 	register char nibble;
745 	register int i, j;
746 
747 	/*
748 	 * Use the ethernet address supplied
749 	 * Note that we do a UECLR here, so the receive buffers
750 	 * must be requeued.
751 	 */
752 
753 #ifdef DEBUG
754 	printf("ec_setaddr: setting address for unit %d = %s",
755 		unit, ether_sprintf(physaddr));
756 #endif
757 	addr->ec_xcr = EC_UECLR;
758 	addr->ec_rcr = 0;
759 	/* load requested address */
760 	for (i = 0; i < 6; i++) { /* 6 bytes of address */
761 	    es->es_addr[i] = physaddr[i];
762 	    nibble = physaddr[i] & 0xf; /* lower nibble */
763 	    addr->ec_rcr = (nibble << 8);
764 	    addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */
765 	    addr->ec_rcr = (nibble << 8);
766 	    for (j=0; j < 4; j++) {
767 		addr->ec_rcr = 0;
768 		addr->ec_rcr = EC_ASTEP; /* step counter */
769 		addr->ec_rcr = 0;
770 	    }
771 	    nibble = (physaddr[i] >> 4) & 0xf; /* upper nibble */
772 	    addr->ec_rcr = (nibble << 8);
773 	    addr->ec_rcr = (nibble << 8) + EC_AWCLK; /* latch nibble */
774 	    addr->ec_rcr = (nibble << 8);
775 	    for (j=0; j < 4; j++) {
776 		addr->ec_rcr = 0;
777 		addr->ec_rcr = EC_ASTEP; /* step counter */
778 		addr->ec_rcr = 0;
779 	    }
780 	}
781 #ifdef DEBUG
782 	/*
783 	 * Read the ethernet address off the board, one nibble at a time.
784 	 */
785 	addr->ec_xcr = EC_UECLR;
786 	addr->ec_rcr = 0; /* read RAM */
787 	cp = es->es_addr;
788 #undef NEXTBIT
789 #define	NEXTBIT	addr->ec_rcr = EC_ASTEP; addr->ec_rcr = 0
790 	for (i=0; i < sizeof (es->es_addr); i++) {
791 		*cp = 0;
792 		for (j=0; j<=4; j+=4) {
793 			*cp |= ((addr->ec_rcr >> 8) & 0xf) << j;
794 			NEXTBIT; NEXTBIT; NEXTBIT; NEXTBIT;
795 		}
796 		cp++;
797 	}
798 	printf("ec_setaddr: RAM address for unit %d = %s",
799 		unit, ether_sprintf(physaddr));
800 #endif
801 }
802 #endif
803