xref: /csrg-svn/sys/tahoe/if/if_ace.c (revision 24007)
1*24007Ssam /*	if_ace.c	1.1	85/07/21	*/
2*24007Ssam 
3*24007Ssam /*
4*24007Ssam  * ACC VERSAbus Ethernet controller
5*24007Ssam  */
6*24007Ssam #include "ace.h"
7*24007Ssam #if NACE > 0
8*24007Ssam 
9*24007Ssam #include "../machine/pte.h"
10*24007Ssam 
11*24007Ssam #include "../h/param.h"
12*24007Ssam #include "../h/systm.h"
13*24007Ssam #include "../h/mbuf.h"
14*24007Ssam #include "../h/buf.h"
15*24007Ssam #include "../h/protosw.h"
16*24007Ssam #include "../h/socket.h"
17*24007Ssam #include "../h/vmmac.h"
18*24007Ssam #include "../h/ioctl.h"
19*24007Ssam #include "../h/errno.h"
20*24007Ssam #include "../h/vmparam.h"
21*24007Ssam 
22*24007Ssam #include "../net/if.h"
23*24007Ssam #include "../net/netisr.h"
24*24007Ssam #include "../net/route.h"
25*24007Ssam #include "../netinet/in.h"
26*24007Ssam #include "../netinet/in_systm.h"
27*24007Ssam #include "../netinet/ip.h"
28*24007Ssam #include "../netinet/ip_var.h"
29*24007Ssam #include "../netinet/if_ether.h"
30*24007Ssam #include "../netpup/pup.h"
31*24007Ssam 
32*24007Ssam #include "../tahoe/mtpr.h"
33*24007Ssam #include "../tahoeif/if_acereg.h"
34*24007Ssam #include "../vba/vbavar.h"
35*24007Ssam 
36*24007Ssam #define	LONET	124
37*24007Ssam 
38*24007Ssam /*
39*24007Ssam  * Configuration table, for 2 units (should be defined by config)
40*24007Ssam  */
41*24007Ssam #define	ACEVECTOR	0x90
42*24007Ssam long	acestd[] = { 0x0ff0000, 0xff0100 };		/* controller */
43*24007Ssam 
44*24007Ssam extern	char ace0utl[], ace1utl[];			/* dpm */
45*24007Ssam char	*acemap[]= { ace0utl, ace1utl };
46*24007Ssam extern	long ACE0map[], ACE1map[];
47*24007Ssam long	*ACEmap[] = { ACE0map, ACE1map };
48*24007Ssam long	ACEmapa[] = { 0xfff80000, 0xfff90000 };
49*24007Ssam 
50*24007Ssam /* station address */
51*24007Ssam char	ace_station[6] = { ~0x8, ~0x0, ~0x3, ~0x0, ~0x0, ~0x1 };
52*24007Ssam /* multicast hash table initializer */
53*24007Ssam char	ace_hash[8] = { ~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF,~0xF };
54*24007Ssam /* backoff table masks */
55*24007Ssam short random_mask_tbl[16] = {
56*24007Ssam 	0x0040, 0x00C0, 0x01C0, 0x03C0, 0x07C0, 0x0FC0, 0x1FC0, 0x3FC0,
57*24007Ssam 	0x7FC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0, 0xFFC0
58*24007Ssam };
59*24007Ssam 
60*24007Ssam int	aceprobe(), aceattach(), acerint(), acecint();
61*24007Ssam struct	vba_device *aceinfo[NACE];
62*24007Ssam struct	vba_driver acedriver =
63*24007Ssam 	{ aceprobe, 0,aceattach,0,acestd,"ace",aceinfo,"v/eiu",0 };
64*24007Ssam 
65*24007Ssam #define	ACEUNIT(x)	minor(x)
66*24007Ssam 
67*24007Ssam int	aceinit(), aceoutput(), aceioctl(), acereset();
68*24007Ssam struct	mbuf *aceget();
69*24007Ssam 
70*24007Ssam /*
71*24007Ssam  * Ethernet software status per interface.
72*24007Ssam  *
73*24007Ssam  * Each interface is referenced by a network interface structure,
74*24007Ssam  * is_if, which the routing code uses to locate the interface.
75*24007Ssam  * This structure contains the output queue for the interface, its address, ...
76*24007Ssam  */
77*24007Ssam struct	ace_softc {
78*24007Ssam 	struct	arpcom is_ac;		/* Ethernet common part	*/
79*24007Ssam #define	is_if	is_ac.ac_if		/* network-visible interface */
80*24007Ssam #define	is_addr	is_ac.ac_enaddr		/* hardware Ethernet address */
81*24007Ssam 	char	*is_dpm;
82*24007Ssam 	short	is_flags;
83*24007Ssam #define	ACEF_OACTIVE	0x1		/* output is active */
84*24007Ssam #define	ACEF_RCVPENDING	0x2		/* start rcv in acecint	*/
85*24007Ssam 	short	is_promiscuous;		/* true is enabled */
86*24007Ssam 	short	is_segboundry;		/* first TX Seg in dpm */
87*24007Ssam 	short	is_eictr;		/* Rx segment tracking ctr */
88*24007Ssam 	short	is_eoctr;		/* Tx segment tracking ctr */
89*24007Ssam 	short	is_txnext;		/* Next available Tx segment */
90*24007Ssam 	short	is_currnd;		/* current random backoff */
91*24007Ssam 	struct	ace_stats is_stats;	/* holds board statistics */
92*24007Ssam 	short	is_xcnt;		/* count xmitted segments to be acked
93*24007Ssam 					   by the controller */
94*24007Ssam } ace_softc[NACE];
95*24007Ssam extern	struct ifnet loif;
96*24007Ssam 
97*24007Ssam aceprobe(reg)
98*24007Ssam 	caddr_t reg;
99*24007Ssam {
100*24007Ssam 	register struct acedevice *addr = (struct acedevice *)reg;
101*24007Ssam 
102*24007Ssam #ifdef lint
103*24007Ssam 	acerint(0); acecint(0);
104*24007Ssam #endif
105*24007Ssam 	if (badaddr(reg, 2))
106*24007Ssam 		return(0);
107*24007Ssam 	movew((short)CSR_RESET, &addr->csr);
108*24007Ssam 	DELAY(10000);
109*24007Ssam 	return (sizeof (struct acedevice));
110*24007Ssam }
111*24007Ssam 
112*24007Ssam /*
113*24007Ssam  * Interface exists: make available by filling in network interface
114*24007Ssam  * record.  System will initialize the interface when it is ready
115*24007Ssam  * to accept packets.
116*24007Ssam  */
117*24007Ssam aceattach(ui)
118*24007Ssam 	struct vba_device *ui;
119*24007Ssam {
120*24007Ssam 	register short unit = ui->ui_unit;
121*24007Ssam 	register struct ace_softc *is = &ace_softc[unit];
122*24007Ssam 	register struct ifnet *ifp = &is->is_if;
123*24007Ssam 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
124*24007Ssam 	register short *wp, i;
125*24007Ssam 	struct sockaddr_in *sin;
126*24007Ssam 
127*24007Ssam 	ifp->if_unit = unit;
128*24007Ssam 	ifp->if_name = "ace";
129*24007Ssam 	ifp->if_mtu = ETHERMTU;
130*24007Ssam 	/*
131*24007Ssam 	 * Set station's addresses, multicast
132*24007Ssam 	 * hash table, and initialize dual ported memory.
133*24007Ssam 	 */
134*24007Ssam 	ace_station[5] = ~(unit + 1);
135*24007Ssam 	acesetetaddr(unit, addr, ace_station);
136*24007Ssam 	is->is_promiscuous = 0;
137*24007Ssam 	wp = (short *)addr->hash;
138*24007Ssam 	for (i =  0; i < 8; i++)
139*24007Ssam 		movew((short)ace_hash[i], wp++);
140*24007Ssam 	movew((short)~0xffff, &addr->bcastena[0]);
141*24007Ssam 	movew((short)~0xffff, &addr->bcastena[1]);
142*24007Ssam 	aceclean(unit);
143*24007Ssam 	sin = (struct sockaddr_in *)&ifp->if_addr;
144*24007Ssam 	sin->sin_family = AF_INET;
145*24007Ssam 	ifp->if_init = aceinit;
146*24007Ssam 	ifp->if_output = aceoutput;
147*24007Ssam 	ifp->if_ioctl = aceioctl;
148*24007Ssam 	ifp->if_reset = acereset;
149*24007Ssam 	if_attach(ifp);
150*24007Ssam }
151*24007Ssam 
152*24007Ssam acesetetaddr(unit, addr, station_addr)
153*24007Ssam 	short unit;
154*24007Ssam 	struct acedevice *addr;
155*24007Ssam 	char *station_addr;
156*24007Ssam {
157*24007Ssam 	register short *wp, i;
158*24007Ssam 	register char *cp;
159*24007Ssam 	struct ace_softc *is = &ace_softc[unit];
160*24007Ssam 
161*24007Ssam 	wp = (short *)addr->station;
162*24007Ssam 	cp = station_addr;
163*24007Ssam 	for (i = 0; i < 6; i++)
164*24007Ssam 		movew((short)*cp++, wp++);
165*24007Ssam 	wp = (short *)addr->station;
166*24007Ssam 	cp = (char *)&is->is_addr;
167*24007Ssam 	for (i = 0; i < 6; i++)
168*24007Ssam 		*cp++ = ~(*wp++);
169*24007Ssam }
170*24007Ssam 
171*24007Ssam /*
172*24007Ssam  * Reset of interface after "system" reset.
173*24007Ssam  */
174*24007Ssam acereset(unit, vban)
175*24007Ssam 	int unit, vban;
176*24007Ssam {
177*24007Ssam 	register struct vba_device *ui;
178*24007Ssam 
179*24007Ssam 	if (unit >= NACE || (ui = aceinfo[unit]) == 0 || ui->ui_alive == 0 ||
180*24007Ssam 	    ui->ui_vbanum != vban)
181*24007Ssam 		return;
182*24007Ssam 	printf(" ace%d", unit);
183*24007Ssam 	aceinit(unit);
184*24007Ssam }
185*24007Ssam 
186*24007Ssam /*
187*24007Ssam  * Initialization of interface; clear recorded pending operations
188*24007Ssam  */
189*24007Ssam aceinit(unit)
190*24007Ssam 	int unit;
191*24007Ssam {
192*24007Ssam 	register struct ace_softc *is = &ace_softc[unit];
193*24007Ssam 	register struct vba_device *ui = aceinfo[unit];
194*24007Ssam 	register struct acedevice *addr;
195*24007Ssam 	register struct ifnet *ifp = &is->is_if;
196*24007Ssam 	register struct sockaddr_in *sin;
197*24007Ssam 	register short Csr;
198*24007Ssam 	register int i, s;
199*24007Ssam 
200*24007Ssam 	sin = (struct sockaddr_in *)&ifp->if_addr;
201*24007Ssam 	if (sin->sin_addr.s_addr == 0)		/* address still unknown */
202*24007Ssam 		return;
203*24007Ssam 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
204*24007Ssam 		/*
205*24007Ssam 		 * Reset the controller, initialize the recieve buffers,
206*24007Ssam 		 * and turn the controller on again and set board online.
207*24007Ssam 		 */
208*24007Ssam 		addr = (struct acedevice *)ui->ui_addr;
209*24007Ssam 		s = splimp();
210*24007Ssam 		movew((short)CSR_RESET, &addr->csr);
211*24007Ssam 		DELAY(10000);
212*24007Ssam 
213*24007Ssam 		/*
214*24007Ssam 		 * clean up dpm since the controller might
215*24007Ssam 		 * jumble dpm after reset
216*24007Ssam 		 */
217*24007Ssam 		aceclean(unit);
218*24007Ssam 		movew((short)CSR_GO, &addr->csr);
219*24007Ssam 		Csr = addr->csr;
220*24007Ssam 		if (Csr & CSR_ACTIVE) {
221*24007Ssam 			movew((short)(ACEVECTOR + unit*8), &addr->ivct);
222*24007Ssam 			Csr |= CSR_IENA | is->is_promiscuous;
223*24007Ssam 			if (ifp->if_net == LONET)
224*24007Ssam 				Csr |= CSR_LOOP3;
225*24007Ssam 			movew(Csr, &addr->csr);
226*24007Ssam 			is->is_flags = 0;
227*24007Ssam 			is->is_xcnt = 0;
228*24007Ssam 			is->is_if.if_flags |= IFF_UP|IFF_RUNNING;
229*24007Ssam 		}
230*24007Ssam 		splx(s);
231*24007Ssam 	}
232*24007Ssam 
233*24007Ssam 	if (is->is_if.if_flags & IFF_UP) {
234*24007Ssam 		if_rtinit(&is->is_if, RTF_UP);
235*24007Ssam 		aceStart(unit);
236*24007Ssam 	}
237*24007Ssam 	arpwhohas(&is->is_ac, &sin->sin_addr);
238*24007Ssam }
239*24007Ssam 
240*24007Ssam /*
241*24007Ssam  * Start output on interface.
242*24007Ssam  * Get another datagram to send off of the interface queue,
243*24007Ssam  * and map it to the interface before starting the output.
244*24007Ssam  *
245*24007Ssam  */
246*24007Ssam acestart(dev)
247*24007Ssam 	dev_t dev;
248*24007Ssam {
249*24007Ssam 	register struct tx_segment *txs;
250*24007Ssam 	register long len, x;
251*24007Ssam 	int unit = ACEUNIT(dev);
252*24007Ssam 	struct vba_device *ui = aceinfo[unit];
253*24007Ssam 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
254*24007Ssam 	register struct ace_softc *is = &ace_softc[unit];
255*24007Ssam 	struct mbuf *m;
256*24007Ssam 	short retries, idx;
257*24007Ssam 
258*24007Ssam again:
259*24007Ssam 	txs = (struct tx_segment*)(is->is_dpm + (is->is_txnext << 11));
260*24007Ssam 	if (txs->tx_csr & TCS_TBFULL) {
261*24007Ssam 		is->is_stats.tx_busy++;
262*24007Ssam 		return;
263*24007Ssam 	}
264*24007Ssam 	x = splimp();
265*24007Ssam 	IF_DEQUEUE(&is->is_if.if_snd, m);
266*24007Ssam 	splx(x);
267*24007Ssam 	if (m == 0)
268*24007Ssam 		return;
269*24007Ssam 	len = aceput(unit, txs->tx_data, m);
270*24007Ssam 	retries = txs->tx_csr & TCS_RTC;
271*24007Ssam 	if (retries > 0)
272*24007Ssam 		acebakoff(is, txs, retries);
273*24007Ssam 
274*24007Ssam 	/*
275*24007Ssam 	 * Ensure minimum packet length.
276*24007Ssam 	 * This makes the safe assumtion that there are no virtual holes
277*24007Ssam 	 * after the data.
278*24007Ssam 	 * For security, it might be wise to zero out the added bytes,
279*24007Ssam 	 * but we're mainly interested in speed at the moment.
280*24007Ssam 	 */
281*24007Ssam #ifdef notdef
282*24007Ssam 	if (len - sizeof (struct ether_header) < ETHERMIN)
283*24007Ssam 		len = ETHERMIN + sizeof (struct ether_header);
284*24007Ssam #else
285*24007Ssam 	if (len - 14 < ETHERMIN)
286*24007Ssam 		len = ETHERMIN + 14;
287*24007Ssam #endif
288*24007Ssam 	if (++is->is_txnext > SEG_MAX)
289*24007Ssam 		is->is_txnext = is->is_segboundry;
290*24007Ssam 	is->is_if.if_opackets++;
291*24007Ssam 	is->is_xcnt++;
292*24007Ssam 	len = (len & 0x7fff) | TCS_TBFULL;
293*24007Ssam 	movew((short)len, txs);
294*24007Ssam 	goto again;
295*24007Ssam }
296*24007Ssam 
297*24007Ssam /*
298*24007Ssam  * Transmit done interrupt.
299*24007Ssam  */
300*24007Ssam acecint(unit)
301*24007Ssam 	int unit;
302*24007Ssam {
303*24007Ssam 	register struct ace_softc *is = &ace_softc[unit];
304*24007Ssam 	struct vba_device *ui = aceinfo[unit];
305*24007Ssam 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
306*24007Ssam 	register struct tx_segment *txseg;
307*24007Ssam 	short txidx, eostat;
308*24007Ssam 
309*24007Ssam 	if (is->is_xcnt <= 0)  {
310*24007Ssam 		txidx = (addr->tseg >> 11) & 0xf;
311*24007Ssam 		printf("ace%d: stray xmit interrupt, xcnt %d\n",
312*24007Ssam 		    unit, is->is_xcnt);
313*24007Ssam 		is->is_xcnt = 0;
314*24007Ssam 		aceStart(unit);
315*24007Ssam 		return;
316*24007Ssam 	}
317*24007Ssam 	is->is_xcnt--;
318*24007Ssam 	txseg = (struct tx_segment *)((is->is_eoctr << 11) + is->is_dpm);
319*24007Ssam 	eostat = txseg->tx_csr;
320*24007Ssam 	if ((eostat & TCS_TBFULL) == 0) {
321*24007Ssam 		is->is_stats.tx_retries += eostat & TCS_RTC;
322*24007Ssam 		if (eostat & TCS_RTFAIL)  {
323*24007Ssam 			is->is_stats.tx_discarded++;
324*24007Ssam 			is->is_if.if_oerrors++;
325*24007Ssam 		} else
326*24007Ssam 			is->is_stats.tx_datagrams++;
327*24007Ssam 		if (++is->is_eoctr >= 16)
328*24007Ssam 			is->is_eoctr = is->is_segboundry;
329*24007Ssam 	}
330*24007Ssam 	aceStart(unit);
331*24007Ssam }
332*24007Ssam 
333*24007Ssam /*
334*24007Ssam  * Ethernet interface receiver interrupt.
335*24007Ssam  * If input error just drop packet.
336*24007Ssam  * Otherwise purge input buffered data path and examine
337*24007Ssam  * packet to determine type.  If can't determine length
338*24007Ssam  * from type, then have to drop packet.  Othewise decapsulate
339*24007Ssam  * packet based on type and pass to type specific higher-level
340*24007Ssam  * input routine.
341*24007Ssam  */
342*24007Ssam acerint(unit)
343*24007Ssam 	int unit;
344*24007Ssam {
345*24007Ssam 	register struct ace_softc *is = &ace_softc[unit];
346*24007Ssam 	register struct ifqueue *inq;
347*24007Ssam 	register struct ether_header *ace;
348*24007Ssam 	register struct rx_segment *rxseg;
349*24007Ssam 	struct acedevice *addr = (struct acedevice *)aceinfo[unit]->ui_addr;
350*24007Ssam 	int len, s, off, resid;
351*24007Ssam 	struct mbuf *m;
352*24007Ssam 	short eistat;
353*24007Ssam 
354*24007Ssam again:
355*24007Ssam 	rxseg = (struct rx_segment *)((is->is_eictr << 11) + is->is_dpm);
356*24007Ssam 	eistat = rxseg->rx_csr;
357*24007Ssam 	if ((eistat & RCS_RBFULL) == 0)
358*24007Ssam 		return;
359*24007Ssam 	is->is_if.if_ipackets++;
360*24007Ssam 	if (++is->is_eictr >= is->is_segboundry)
361*24007Ssam 		is->is_eictr = 0;
362*24007Ssam 	len = eistat & RCS_RBC;
363*24007Ssam 	if ((eistat & (RCS_ROVRN | RCS_RCRC | RCS_RODD)) ||
364*24007Ssam 	    len < ET_MINLEN || len > ET_MAXLEN+CRC_SIZE) {
365*24007Ssam 		if (eistat & RCS_ROVRN)
366*24007Ssam 			is->is_stats.rx_overruns++;
367*24007Ssam 		if (eistat & RCS_RCRC)
368*24007Ssam 			is->is_stats.rx_crc_errors++;
369*24007Ssam 		if (eistat & RCS_RODD)
370*24007Ssam 			is->is_stats.rx_align_errors++;
371*24007Ssam 		if (len < ET_MINLEN)
372*24007Ssam 			is->is_stats.rx_underruns++;
373*24007Ssam 		if (len > ET_MAXLEN+CRC_SIZE)
374*24007Ssam 			is->is_stats.rx_overruns++;
375*24007Ssam 		is->is_if.if_ierrors++;
376*24007Ssam 		rxseg->rx_csr = 0;
377*24007Ssam 		return;
378*24007Ssam 	} else
379*24007Ssam 		is->is_stats.rx_datagrams++;
380*24007Ssam 	ace = (struct ether_header *)rxseg->rx_data;
381*24007Ssam #ifdef notdef
382*24007Ssam 	len -= sizeof (struct ether_header);
383*24007Ssam #else
384*24007Ssam 	len -= 14;
385*24007Ssam #endif
386*24007Ssam 	/*
387*24007Ssam 	 * Deal with trailer protocol: if type is PUP trailer
388*24007Ssam 	 * get true type from first 16-bit word past data.
389*24007Ssam 	 * Remember that type was trailer by setting off.
390*24007Ssam 	 */
391*24007Ssam 	ace->ether_type = ntohs((u_short)ace->ether_type);
392*24007Ssam #ifdef notdef
393*24007Ssam #define	acedataaddr(ace, off, type) \
394*24007Ssam     ((type)(((caddr_t)(((char *)ace)+sizeof (struct ether_header))+(off))))
395*24007Ssam #else
396*24007Ssam #define	acedataaddr(ace, off, type) \
397*24007Ssam     ((type)(((caddr_t)(((char *)ace)+14)+(off))))
398*24007Ssam #endif
399*24007Ssam 	if (ace->ether_type >= ETHERPUP_TRAIL &&
400*24007Ssam 	    ace->ether_type < ETHERPUP_TRAIL+ETHERPUP_NTRAILER) {
401*24007Ssam 		off = (ace->ether_type - ETHERPUP_TRAIL) * 512;
402*24007Ssam 		if (off >= ETHERMTU)
403*24007Ssam 			goto setup;		/* sanity */
404*24007Ssam 		ace->ether_type = ntohs(*acedataaddr(ace, off, u_short *));
405*24007Ssam 		resid = ntohs(*(acedataaddr(ace, off+2, u_short *)));
406*24007Ssam 		if (off + resid > len)
407*24007Ssam 			goto setup;		/* sanity */
408*24007Ssam 		len = off + resid;
409*24007Ssam 	} else
410*24007Ssam 		off = 0;
411*24007Ssam 	if (len == 0)
412*24007Ssam 		goto setup;
413*24007Ssam 
414*24007Ssam 	/*
415*24007Ssam 	 * Pull packet off interface.  Off is nonzero if packet
416*24007Ssam 	 * has trailing header; aceget will then force this header
417*24007Ssam 	 * information to be at the front, but we still have to drop
418*24007Ssam 	 * the type and length which are at the front of any trailer data.
419*24007Ssam 	 */
420*24007Ssam 	m = aceget(unit, rxseg->rx_data, len, off);
421*24007Ssam 	if (m == 0)
422*24007Ssam 		goto setup;
423*24007Ssam 	if (off) {
424*24007Ssam 		m->m_off += 2 * sizeof (u_short);
425*24007Ssam 		m->m_len -= 2 * sizeof (u_short);
426*24007Ssam 	}
427*24007Ssam 	switch (ace->ether_type) {
428*24007Ssam 
429*24007Ssam #ifdef INET
430*24007Ssam 	case ETHERPUP_IPTYPE:
431*24007Ssam 		schednetisr(NETISR_IP);
432*24007Ssam 		inq = &ipintrq;
433*24007Ssam 		break;
434*24007Ssam 
435*24007Ssam 	case ETHERPUP_ARPTYPE:
436*24007Ssam 		arpinput(&is->is_ac, m);
437*24007Ssam 		goto setup;
438*24007Ssam #endif
439*24007Ssam 	default:
440*24007Ssam 		m_freem(m);
441*24007Ssam 		goto setup;
442*24007Ssam 	}
443*24007Ssam 	if (IF_QFULL(inq)) {
444*24007Ssam 		IF_DROP(inq);
445*24007Ssam 		m_freem(m);
446*24007Ssam 		goto setup;
447*24007Ssam 	}
448*24007Ssam 	s = splimp();
449*24007Ssam 	IF_ENQUEUE(inq, m);
450*24007Ssam 	splx(s);
451*24007Ssam setup:
452*24007Ssam 	rxseg->rx_csr = 0;
453*24007Ssam 	goto again;
454*24007Ssam }
455*24007Ssam 
456*24007Ssam /*
457*24007Ssam  * Ethernet output routine.
458*24007Ssam  * Encapsulate a packet of type family for the local net.
459*24007Ssam  * Use trailer local net encapsulation if enough data in first
460*24007Ssam  * packet leaves a multiple of 512 bytes of data in remainder.
461*24007Ssam  */
462*24007Ssam aceoutput(ifp, m0, dst)
463*24007Ssam 	struct ifnet *ifp;
464*24007Ssam 	struct mbuf *m0;
465*24007Ssam 	struct sockaddr *dst;
466*24007Ssam {
467*24007Ssam 	register struct ace_softc *is = &ace_softc[ifp->if_unit];
468*24007Ssam 	register struct mbuf *m = m0;
469*24007Ssam 	register struct ether_header *ace;
470*24007Ssam 	register int off;
471*24007Ssam 	struct mbuf *mcopy = (struct mbuf *)0;
472*24007Ssam 	int type, s, error;
473*24007Ssam 	struct ether_addr edst;
474*24007Ssam 	struct in_addr idst;
475*24007Ssam 
476*24007Ssam 	switch (dst->sa_family) {
477*24007Ssam 
478*24007Ssam #ifdef INET
479*24007Ssam 	case AF_INET:
480*24007Ssam 		idst = ((struct sockaddr_in *)dst)->sin_addr;
481*24007Ssam 		if (!arpresolve(&is->is_ac, m, &idst, &edst))
482*24007Ssam 			return (0);	/* if not yet resolved */
483*24007Ssam 		if (in_lnaof(idst) == INADDR_ANY)
484*24007Ssam 			mcopy = m_copy(m, 0, (int)M_COPYALL);
485*24007Ssam 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
486*24007Ssam 		/* need per host negotiation */
487*24007Ssam 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0 && off > 0 &&
488*24007Ssam 		    (off & 0x1ff) == 0 &&
489*24007Ssam 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
490*24007Ssam 			type = ETHERPUP_TRAIL + (off>>9);
491*24007Ssam 			m->m_off -= 2 * sizeof (u_short);
492*24007Ssam 			m->m_len += 2 * sizeof (u_short);
493*24007Ssam 			*mtod(m, u_short *) = htons((u_short)ETHERPUP_IPTYPE);
494*24007Ssam 			*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
495*24007Ssam 			goto gottrailertype;
496*24007Ssam 		}
497*24007Ssam 		type = ETHERPUP_IPTYPE;
498*24007Ssam 		off = 0;
499*24007Ssam 		goto gottype;
500*24007Ssam #endif
501*24007Ssam 
502*24007Ssam 	case AF_UNSPEC:
503*24007Ssam 		ace = (struct ether_header *)dst->sa_data;
504*24007Ssam #ifdef notdef
505*24007Ssam 		edst = ace->ether_dhost;
506*24007Ssam #else
507*24007Ssam 		bcopy((caddr_t)ace->ether_dhost, (caddr_t)&edst, 6);
508*24007Ssam #endif
509*24007Ssam 		type = ace->ether_type;
510*24007Ssam 		goto gottype;
511*24007Ssam 
512*24007Ssam 	default:
513*24007Ssam 		printf("ace%d: can't handle af%d\n",
514*24007Ssam 		    ifp->if_unit, dst->sa_family);
515*24007Ssam 		error = EAFNOSUPPORT;
516*24007Ssam 		goto bad;
517*24007Ssam 	}
518*24007Ssam 
519*24007Ssam gottrailertype:
520*24007Ssam 	/*
521*24007Ssam 	 * Packet to be sent as trailer: move first packet
522*24007Ssam 	 * (control information) to end of chain.
523*24007Ssam 	 */
524*24007Ssam 	while (m->m_next)
525*24007Ssam 		m = m->m_next;
526*24007Ssam 	m->m_next = m0;
527*24007Ssam 	m = m0->m_next;
528*24007Ssam 	m0->m_next = 0;
529*24007Ssam 	m0 = m;
530*24007Ssam 
531*24007Ssam gottype:
532*24007Ssam 	/*
533*24007Ssam 	 * Add local net header.  If no space in first mbuf,
534*24007Ssam 	 * allocate another.
535*24007Ssam 	 */
536*24007Ssam 	if (m->m_off > MMAXOFF ||
537*24007Ssam #ifdef notdef
538*24007Ssam 	    MMINOFF + sizeof (struct ether_header) > m->m_off) {
539*24007Ssam #else
540*24007Ssam 	    MMINOFF + 14 > m->m_off) {
541*24007Ssam #endif
542*24007Ssam 		m = m_get(M_DONTWAIT, MT_HEADER);
543*24007Ssam 		if (m == 0) {
544*24007Ssam 			error = ENOBUFS;
545*24007Ssam 			goto bad;
546*24007Ssam 		}
547*24007Ssam 		m->m_next = m0;
548*24007Ssam 		m->m_off = MMINOFF;
549*24007Ssam #ifdef notdef
550*24007Ssam 		m->m_len = sizeof (struct ether_header);
551*24007Ssam #else
552*24007Ssam 		m->m_len = 14;
553*24007Ssam #endif
554*24007Ssam 	} else {
555*24007Ssam #ifdef notdef
556*24007Ssam 		m->m_off -= sizeof (struct ether_header);
557*24007Ssam 		m->m_len += sizeof (struct ether_header);
558*24007Ssam #else
559*24007Ssam 		m->m_off -= 14;
560*24007Ssam 		m->m_len += 14;
561*24007Ssam #endif
562*24007Ssam 	}
563*24007Ssam 	ace = mtod(m, struct ether_header *);
564*24007Ssam #ifdef notdef
565*24007Ssam 	ace->ether_dhost = edst;
566*24007Ssam 	ace->ether_shost = is->is_addr;
567*24007Ssam #else
568*24007Ssam 	bcopy((caddr_t)&edst, (caddr_t)ace->ether_dhost, 6);
569*24007Ssam 	bcopy((caddr_t)&is->is_addr, (caddr_t)ace->ether_shost, 6);
570*24007Ssam #endif
571*24007Ssam 	ace->ether_type = htons((u_short)type);
572*24007Ssam 
573*24007Ssam 	/*
574*24007Ssam 	 * Queue message on interface, and start output if interface
575*24007Ssam 	 * not yet active.
576*24007Ssam 	 */
577*24007Ssam 	s = splimp();
578*24007Ssam 	if (IF_QFULL(&ifp->if_snd)) {
579*24007Ssam 		IF_DROP(&ifp->if_snd);
580*24007Ssam 		error = ENOBUFS;
581*24007Ssam 		goto qfull;
582*24007Ssam 	}
583*24007Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
584*24007Ssam 	splx(s);
585*24007Ssam 	aceStart(ifp->if_unit);
586*24007Ssam 	return (mcopy ? looutput(&loif, mcopy, dst) : 0);
587*24007Ssam qfull:
588*24007Ssam 	m0 = m;
589*24007Ssam 	splx(s);
590*24007Ssam bad:
591*24007Ssam 	m_freem(m0);
592*24007Ssam 	if (mcopy)
593*24007Ssam 		m_freem(mcopy);
594*24007Ssam 	return (error);
595*24007Ssam }
596*24007Ssam 
597*24007Ssam aceStart(unit)
598*24007Ssam 	int unit;
599*24007Ssam {
600*24007Ssam 	register struct ace_softc *is = &ace_softc[unit];
601*24007Ssam 
602*24007Ssam 	if (is->is_flags & ACEF_OACTIVE)
603*24007Ssam 		return;
604*24007Ssam 	is->is_flags |= ACEF_OACTIVE;
605*24007Ssam 	acestart((dev_t)unit);
606*24007Ssam 	is->is_flags &= ~ACEF_OACTIVE;
607*24007Ssam }
608*24007Ssam 
609*24007Ssam /*
610*24007Ssam  * Routine to copy from mbuf chain to transmit buffer on the VERSAbus
611*24007Ssam  * If packet size is less than the minimum legal size,
612*24007Ssam  * the buffer is expanded.  We probably should zero out the extra
613*24007Ssam  * bytes for security, but that would slow things down.
614*24007Ssam  */
615*24007Ssam aceput(unit, txbuf, m)
616*24007Ssam 	int unit;			/* for statistics collection */
617*24007Ssam 	u_char *txbuf;
618*24007Ssam 	struct mbuf *m;
619*24007Ssam {
620*24007Ssam 	register u_char *bp, *mcp;	/* known to be r12, r11 */
621*24007Ssam 	register short *s1, *s2;	/* known to be r10, r9 */
622*24007Ssam 	register unsigned len;
623*24007Ssam 	register struct mbuf *mp;
624*24007Ssam 	int total, idx;
625*24007Ssam 
626*24007Ssam 	total = 0;
627*24007Ssam 	bp = txbuf;
628*24007Ssam 	for (mp = m;(mp); mp = mp->m_next) {
629*24007Ssam 		len = mp->m_len;
630*24007Ssam 		if (len == 0)
631*24007Ssam 			continue;
632*24007Ssam 		total += len;
633*24007Ssam 		mcp = mtod(mp, u_char *);
634*24007Ssam 		if (((int)mcp & 01) && ((int)bp & 01)) {
635*24007Ssam 			/* source & destination at odd addresses */
636*24007Ssam 			/* *bp++ = *mcp++; */
637*24007Ssam 			asm("movob (r11),(r12)");
638*24007Ssam 			bp++, mcp++;
639*24007Ssam 			--len;
640*24007Ssam 		}
641*24007Ssam 		if (len > 1 && (((int)mcp & 01)==0) && (((int)bp & 01)==0)) {
642*24007Ssam 			register int l;
643*24007Ssam 
644*24007Ssam 			s1 = (short *)bp;
645*24007Ssam 			s2 = (short *)mcp;
646*24007Ssam 			l = len >> 1;		/* count # of shorts */
647*24007Ssam 			while (l-- > 0) {
648*24007Ssam 				/* *s1++ = *s2++; */
649*24007Ssam 				asm("movow (r9),(r10)");
650*24007Ssam 				s1++, s2++;
651*24007Ssam 			}
652*24007Ssam 			len &= 1;		/* # remaining bytes */
653*24007Ssam 			bp = (u_char *)s1;
654*24007Ssam 			mcp = (u_char *)s2;
655*24007Ssam 		}
656*24007Ssam 		while (len-- > 0) {
657*24007Ssam 			/* *bp++ = *mcp++;  */
658*24007Ssam 			asm("movob (r11),(r12)");
659*24007Ssam 			bp++, mcp++;
660*24007Ssam 		}
661*24007Ssam 	}
662*24007Ssam 	m_freem(m);
663*24007Ssam 	return (total);
664*24007Ssam }
665*24007Ssam 
666*24007Ssam movew(data, to)
667*24007Ssam 	short data, *to;
668*24007Ssam {
669*24007Ssam 
670*24007Ssam 	asm("movow 6(fp),*8(fp)");
671*24007Ssam }
672*24007Ssam 
673*24007Ssam /*
674*24007Ssam  * Routine to copy from VERSAbus memory into mbufs.
675*24007Ssam  *
676*24007Ssam  * Warning: This makes the fairly safe assumption that
677*24007Ssam  * mbufs have even lengths.
678*24007Ssam  */
679*24007Ssam struct mbuf *
680*24007Ssam aceget(unit, rxbuf, totlen, off0)
681*24007Ssam 	int unit;			/* for statistics collection */
682*24007Ssam 	u_char *rxbuf;
683*24007Ssam 	int totlen, off0;
684*24007Ssam {
685*24007Ssam 	register u_char *cp, *mcp;	/* known to be r12, r11 */
686*24007Ssam 	register int tlen;
687*24007Ssam 	register struct mbuf *m;
688*24007Ssam 	struct mbuf *top = 0, **mp = &top;
689*24007Ssam 	int len, off = off0;
690*24007Ssam 
691*24007Ssam #ifdef notdef
692*24007Ssam 	cp = rxbuf + sizeof (struct ether_header);
693*24007Ssam #else
694*24007Ssam 	cp = rxbuf + 14;
695*24007Ssam #endif
696*24007Ssam 	while (totlen > 0) {
697*24007Ssam 		register int words;
698*24007Ssam 
699*24007Ssam 		MGET(m, M_DONTWAIT, MT_DATA);
700*24007Ssam 		if (m == 0)
701*24007Ssam 			goto bad;
702*24007Ssam 		if (off) {
703*24007Ssam 			len = totlen - off;
704*24007Ssam #ifdef notdef
705*24007Ssam 			cp = rxbuf + sizeof (struct ether_header) + off;
706*24007Ssam #else
707*24007Ssam 			cp = rxbuf + 14 + off;
708*24007Ssam #endif
709*24007Ssam 		} else
710*24007Ssam 			len = totlen;
711*24007Ssam 		if (len >= CLBYTES) {
712*24007Ssam 			struct mbuf *p;
713*24007Ssam 
714*24007Ssam 			MCLGET(p, 1);
715*24007Ssam 			if (p != 0) {
716*24007Ssam 				m->m_len = len = CLBYTES;
717*24007Ssam 				m->m_off = (int)p - (int)m;
718*24007Ssam 			} else {
719*24007Ssam 				m->m_len = len = MIN(MLEN, len);
720*24007Ssam 				m->m_off = MMINOFF;
721*24007Ssam 			}
722*24007Ssam 		} else {
723*24007Ssam 			m->m_len = len = MIN(MLEN, len);
724*24007Ssam 			m->m_off = MMINOFF;
725*24007Ssam 		}
726*24007Ssam 		mcp = mtod(m, u_char *);
727*24007Ssam 		/*bcopy((caddr_t)cp, (caddr_t)mcp, len);*/
728*24007Ssam 		/*cp += len; mcp += len;*/
729*24007Ssam 		tlen = len;
730*24007Ssam 		if (((int)mcp & 01) && ((int)cp & 01)) {
731*24007Ssam 			/* source & destination at odd addresses */
732*24007Ssam 			*mcp++ = *cp++;
733*24007Ssam 			--tlen;
734*24007Ssam 		}
735*24007Ssam 		if (tlen > 1 && (((int)mcp&01) == 0) && (((int)cp&01) == 0)) {
736*24007Ssam 			register short *s1, *s2;
737*24007Ssam 			register int l;
738*24007Ssam 
739*24007Ssam 			s1 = (short *)mcp;
740*24007Ssam 			s2 = (short *)cp;
741*24007Ssam 			l = tlen >> 1;		/* count # of shorts */
742*24007Ssam 			while (l-- > 0)		/* copy shorts */
743*24007Ssam 				*s1++ = *s2++;
744*24007Ssam 			tlen &= 1;		/* # remaining bytes */
745*24007Ssam 			mcp = (u_char *)s1;
746*24007Ssam 			cp = (u_char *)s2;
747*24007Ssam 		}
748*24007Ssam 		while (tlen-- > 0)
749*24007Ssam 			*mcp++ = *cp++;
750*24007Ssam 		*mp = m;
751*24007Ssam 		mp = &m->m_next;
752*24007Ssam 		if (off == 0) {
753*24007Ssam 			totlen -= len;
754*24007Ssam 			continue;
755*24007Ssam 		}
756*24007Ssam 		off += len;
757*24007Ssam 		if (off == totlen) {
758*24007Ssam #ifdef notdef
759*24007Ssam 			cp = rxbuf + sizeof (struct ether_header);
760*24007Ssam #else
761*24007Ssam 			cp = rxbuf + 14;
762*24007Ssam #endif
763*24007Ssam 			off = 0;
764*24007Ssam 			totlen = off0;
765*24007Ssam 		}
766*24007Ssam 	}
767*24007Ssam 	return (top);
768*24007Ssam bad:
769*24007Ssam 	m_freem(top);
770*24007Ssam 	return (0);
771*24007Ssam }
772*24007Ssam 
773*24007Ssam acebakoff(is, txseg, retries)
774*24007Ssam 	struct ace_softc *is;
775*24007Ssam 	struct tx_segment *txseg;
776*24007Ssam 	register int retries;
777*24007Ssam {
778*24007Ssam 	register short *pBakNum, random_num;
779*24007Ssam 	short *pMask;
780*24007Ssam 
781*24007Ssam 	pMask = &random_mask_tbl[0];
782*24007Ssam 	pBakNum = &txseg->tx_backoff[0];
783*24007Ssam 	while (--retries >= 0) {
784*24007Ssam 		random_num = (is->is_currnd = (is->is_currnd * 18741)-13849);
785*24007Ssam 		random_num &= *pMask++;
786*24007Ssam 		*pBakNum++ = random_num ^ (short)(0xFF00 | 0x00FC);
787*24007Ssam 	}
788*24007Ssam }
789*24007Ssam 
790*24007Ssam /*
791*24007Ssam  * Process an ioctl request.
792*24007Ssam  */
793*24007Ssam aceioctl(ifp, cmd, data)
794*24007Ssam 	register struct ifnet *ifp;
795*24007Ssam 	int cmd;
796*24007Ssam 	caddr_t data;
797*24007Ssam {
798*24007Ssam 	register struct ifreq *ifr = (struct ifreq *)data;
799*24007Ssam 	int s, error = 0;
800*24007Ssam 
801*24007Ssam 	s = splimp();
802*24007Ssam 	switch (cmd) {
803*24007Ssam 
804*24007Ssam 	case SIOCSIFADDR:
805*24007Ssam 		if (ifp->if_flags & IFF_RUNNING)
806*24007Ssam 			if_rtinit(ifp, -1);	/* delete previous route */
807*24007Ssam 		acesetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
808*24007Ssam 		aceinit(ifp->if_unit);
809*24007Ssam 		break;
810*24007Ssam 
811*24007Ssam #ifdef notdef
812*24007Ssam 	case SIOCSETETADDR: {		/* set Ethernet station address */
813*24007Ssam 		struct vba_device *ui;
814*24007Ssam 		struct acedevice *addr;
815*24007Ssam 		struct sockaddr_in *sin;
816*24007Ssam 
817*24007Ssam 		ifp->if_flags &= ~IFF_RUNNING | IFF_UP;
818*24007Ssam 		sin = (struct sockaddr_in *)&ifr->ifr_addr;
819*24007Ssam 		ui = aceinfo[ifp->if_unit];
820*24007Ssam 		addr = (struct acedevice *)ui->ui_addr;
821*24007Ssam 		movew((short)CSR_RESET, &addr->csr);
822*24007Ssam 		DELAY(10000);
823*24007Ssam 		/* set station address and copy addr to arp struct */
824*24007Ssam 		acesetetaddr(ifp->if_unit, addr, &sin->sin_zero[2]);
825*24007Ssam 		aceinit(ifp->if_unit);		/* Re-initialize */
826*24007Ssam 		break;
827*24007Ssam 	}
828*24007Ssam #endif
829*24007Ssam 
830*24007Ssam 	default:
831*24007Ssam 		error = EINVAL;
832*24007Ssam 	}
833*24007Ssam 	splx(s);
834*24007Ssam 	return (error);
835*24007Ssam }
836*24007Ssam 
837*24007Ssam acesetaddr(ifp, sin)
838*24007Ssam 	register struct ifnet *ifp;
839*24007Ssam 	register struct sockaddr_in *sin;
840*24007Ssam {
841*24007Ssam 
842*24007Ssam 	ifp->if_addr = *(struct sockaddr *)sin;
843*24007Ssam 	ifp->if_net = in_netof(sin->sin_addr);
844*24007Ssam 	ifp->if_host[0] = in_lnaof(sin->sin_addr);
845*24007Ssam 	sin = (struct sockaddr_in *)&ifp->if_broadaddr;
846*24007Ssam 	sin->sin_family = AF_INET;
847*24007Ssam 	sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
848*24007Ssam 	ifp->if_flags |= IFF_BROADCAST;
849*24007Ssam }
850*24007Ssam 
851*24007Ssam aceclean(unit)
852*24007Ssam 	int unit;
853*24007Ssam {
854*24007Ssam 	register struct ace_softc *is = &ace_softc[unit];
855*24007Ssam 	register struct ifnet *ifp = &is->is_if;
856*24007Ssam 	register struct vba_device *ui = aceinfo[unit];
857*24007Ssam 	register struct acedevice *addr = (struct acedevice *)ui->ui_addr;
858*24007Ssam 	register short i, data;
859*24007Ssam 	register char *pData1;
860*24007Ssam 
861*24007Ssam 	ioaccess(ACEmap[unit], ACEmapa[unit], ACEBPTE);
862*24007Ssam 	is->is_dpm = acemap[unit];		/* init dpm */
863*24007Ssam 	bzero((char *)is->is_dpm, 16384*2);
864*24007Ssam 
865*24007Ssam 	is->is_currnd = 49123;
866*24007Ssam 	is->is_segboundry = (addr->segb >> 11) & 0xf;
867*24007Ssam 	pData1 = (char*)((int)is->is_dpm + (is->is_segboundry << 11));
868*24007Ssam 	for (i = SEG_MAX + 1 - is->is_segboundry; --i >= 0;) {
869*24007Ssam 		acebakoff(is, (struct tx_segment *)pData1, 15);
870*24007Ssam 		pData1 += sizeof (struct tx_segment);
871*24007Ssam 	}
872*24007Ssam 	is->is_eictr = 0;
873*24007Ssam 	is->is_eoctr = is->is_txnext = is->is_segboundry;
874*24007Ssam 	bzero((char *)&is->is_stats, sizeof (is->is_stats));
875*24007Ssam }
876*24007Ssam #endif
877