xref: /csrg-svn/sys/vax/if/if_en.c (revision 5083)
1*5083Swnj /*	if_en.c	4.14	81/11/26	*/
24686Swnj 
34686Swnj #include "en.h"
44686Swnj /*
54686Swnj  * Ethernet interface driver
64686Swnj  */
74686Swnj 
84686Swnj #include "../h/param.h"
94686Swnj #include "../h/systm.h"
104686Swnj #include "../h/mbuf.h"
114686Swnj #include "../h/pte.h"
124686Swnj #include "../h/buf.h"
13*5083Swnj #include "../h/protosw.h"
14*5083Swnj #include "../h/socket.h"
154686Swnj #include "../h/ubareg.h"
164686Swnj #include "../h/ubavar.h"
174686Swnj #include "../h/enreg.h"
18*5083Swnj #include "../h/cpu.h"
194686Swnj #include "../h/mtpr.h"
20*5083Swnj #include "../h/vmmac.h"
21*5083Swnj #include "../net/in.h"
22*5083Swnj #include "../net/in_systm.h"
23*5083Swnj #include "../net/if.h"
24*5083Swnj #include "../net/if_en.h"
25*5083Swnj #include "../net/if_uba.h"
26*5083Swnj #include "../net/ip.h"
27*5083Swnj #include "../net/ip_var.h"
284686Swnj 
29*5083Swnj #define	ENMTU	1024
30*5083Swnj 
314686Swnj int	enprobe(), enattach(), enrint(), enxint(), encollide();
324686Swnj struct	uba_device *eninfo[NEN];
334686Swnj u_short enstd[] = { 0 };
344686Swnj struct	uba_driver endriver =
35*5083Swnj 	{ enprobe, 0, enattach, 0, enstd, "es", eninfo };
364686Swnj #define	ENUNIT(x)	minor(x)
374686Swnj 
38*5083Swnj struct	en_softc {
39*5083Swnj 	struct	ifnet *es_if;
40*5083Swnj 	struct	ifuba *es_ifuba;
41*5083Swnj 	short	es_delay;
42*5083Swnj 	short	es_mask;
43*5083Swnj 	u_char	es_addr;
44*5083Swnj 	u_char	es_lastx;
45*5083Swnj 	short	es_oactive;
46*5083Swnj 	short	es_olen;
47*5083Swnj } en_softc[NEN];
484686Swnj 
494686Swnj enprobe(reg)
504686Swnj 	caddr_t reg;
514686Swnj {
524686Swnj 	register int br, cvec;
534686Swnj 	register struct endevice *addr = (struct endevice *)reg;
544686Swnj 
55*5083Swnj COUNT(ENPROBE);
564686Swnj #ifdef lint
574686Swnj 	br = 0; cvec = br; br = cvec;
584922Swnj 	enrint(0); enxint(0); encollide(0);
594686Swnj #endif
604686Swnj 	addr->en_istat = 0;
614686Swnj 	addr->en_owc = -1;
624686Swnj 	addr->en_oba = 0;
634771Swnj 	addr->en_ostat = EN_IEN|EN_GO;
644686Swnj 	DELAY(100000);
654686Swnj 	addr->en_ostat = 0;
664686Swnj 	return (1);
674686Swnj }
684686Swnj 
694906Swnj /*ARGSUSED*/
704686Swnj enattach(ui)
714686Swnj 	struct uba_device *ui;
724686Swnj {
734688Swnj 
74*5083Swnj COUNT(ENATTACH);
75*5083Swnj 	eninit(ui->ui_unit);
76*5083Swnj 	/* net initialization, based on ui->ui_flags?!? */
774686Swnj }
784686Swnj 
794688Swnj eninit(unit)
804686Swnj 	int unit;
81*5083Swnj {
82*5083Swnj 	register struct uba_device *ui;
834686Swnj 	register struct endevice *addr;
84*5083Swnj 	register struct en_softc *es;
854686Swnj 
86*5083Swnj COUNT(ENINIT);
874686Swnj 	if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0) {
88*5083Swnj 		printf("es%d: not alive\n", unit);
894686Swnj 		return;
904686Swnj 	}
91*5083Swnj 	es = &en_softc[unit];
92*5083Swnj 	if (if_ubainit(es->es_ifuba, ui->ui_ubanum,
93*5083Swnj 	    sizeof (struct en_header), btop(ENMTU)) == 0) {
94*5083Swnj 		printf("es%d: can't initialize\n", unit);
95*5083Swnj 		return;
964686Swnj 	}
974686Swnj 	addr = (struct endevice *)ui->ui_addr;
98*5083Swnj 	addr->en_istat = addr->en_ostat = 0;
994686Swnj }
1004686Swnj 
1014686Swnj enreset(uban)
1024686Swnj 	int uban;
1034686Swnj {
1044686Swnj 	register int unit;
1054686Swnj 	struct uba_device *ui;
1064686Swnj 
107*5083Swnj COUNT(ENRESET);
1084686Swnj 	for (unit = 0; unit < NEN; unit++) {
1094686Swnj 		ui = eninfo[unit];
1104686Swnj 		if (ui == 0 || ui->ui_ubanum != uban || ui->ui_alive == 0)
1114686Swnj 			continue;
1124688Swnj 		eninit(unit);
113*5083Swnj 		printf("es%d ", unit);
1144686Swnj 	}
1154686Swnj }
1164686Swnj 
1174717Swnj int	enlastdel = 25;
118*5083Swnj 
1194688Swnj enstart(dev)
1204686Swnj 	dev_t dev;
1214686Swnj {
1224686Swnj         int unit;
1234686Swnj 	struct uba_device *ui;
124*5083Swnj 	register struct endevice *addr;
125*5083Swnj 	register struct en_softc *es;
126*5083Swnj 	register struct ifuba *ifu;
127*5083Swnj 	struct mbuf *m;
128*5083Swnj 	int dest;
1294688Swnj COUNT(ENSTART);
1304686Swnj 
1314686Swnj 	unit = ENUNIT(dev);
1324686Swnj 	ui = eninfo[unit];
133*5083Swnj 	es = &en_softc[unit];
134*5083Swnj 	if (es->es_oactive)
135*5083Swnj 		goto restart;
136*5083Swnj 	IF_DEQUEUE(&es->es_if->if_snd, m);
137*5083Swnj 	if (m == 0) {
138*5083Swnj 		es->es_oactive = 0;
1394686Swnj 		return;
1404686Swnj 	}
141*5083Swnj 	dest = mtod(m, struct en_header *)->en_dhost;
142*5083Swnj 	es->es_olen = if_wubaput(&es->es_ifuba, m);
143*5083Swnj 	if (es->es_lastx && es->es_lastx == dest)
144*5083Swnj 		es->es_delay = enlastdel;
145*5083Swnj 	else
146*5083Swnj 		es->es_lastx = dest;
147*5083Swnj restart:
148*5083Swnj 	ifu = es->es_ifuba;
149*5083Swnj 	UBAPURGE(ifu->ifu_uba, ifu->ifu_w.ifrw_bdp);
1504686Swnj 	addr = (struct endevice *)ui->ui_addr;
151*5083Swnj 	addr->en_oba = (int)ifu->ifu_w.ifrw_addr;
152*5083Swnj 	addr->en_odelay = es->es_delay;
153*5083Swnj 	addr->en_owc = -((es->es_olen + 1) >> 1);
1544771Swnj 	addr->en_ostat = EN_IEN|EN_GO;
155*5083Swnj 	es->es_oactive = 1;
1564686Swnj }
1574686Swnj 
1584686Swnj enxint(unit)
1594686Swnj 	int unit;
1604686Swnj {
1614686Swnj 	register struct endevice *addr;
1624686Swnj 	register struct uba_device *ui;
163*5083Swnj 	register struct en_softc *es;
1644686Swnj COUNT(ENXINT);
1654686Swnj 
1664686Swnj 	ui = eninfo[unit];
167*5083Swnj 	es = &en_softc[unit];
168*5083Swnj 	if (es->es_oactive == 0)
169*5083Swnj 		return;
1704686Swnj 	addr = (struct endevice *)ui->ui_addr;
171*5083Swnj 	es = &en_softc[unit];
172*5083Swnj 	es->es_oactive = 0;
173*5083Swnj 	es->es_delay = 0;
174*5083Swnj 	es->es_mask = ~0;
175*5083Swnj 	if (addr->en_ostat&EN_OERROR)
176*5083Swnj 		printf("es%d: output error\n", unit);
177*5083Swnj 	if (es->es_if->if_snd.ifq_head == 0) {
178*5083Swnj 		es->es_lastx = 0;
1794686Swnj 		return;
1804686Swnj 	}
181*5083Swnj 	enstart(unit);
1824686Swnj }
1834686Swnj 
1844686Swnj encollide(unit)
1854686Swnj 	int unit;
1864686Swnj {
187*5083Swnj 	register struct en_softc *es;
1884686Swnj COUNT(ENCOLLIDE);
1894686Swnj 
190*5083Swnj 	es = &en_softc[unit];
191*5083Swnj 	es->es_if->if_collisions++;
192*5083Swnj 	if (es->es_oactive == 0)
1934686Swnj 		return;
194*5083Swnj 	if (es->es_mask == 0) {
195*5083Swnj 		printf("es%d: send error\n", unit);
196*5083Swnj 		enxint(unit);
1974686Swnj 	} else {
198*5083Swnj 		es->es_mask <<= 1;
199*5083Swnj 		es->es_delay = mfpr(ICR) &~ es->es_mask;
200*5083Swnj 		enstart(unit);
2014686Swnj 	}
2024686Swnj }
2034686Swnj 
2044686Swnj enrint(unit)
2054686Swnj 	int unit;
2064686Swnj {
207*5083Swnj 	struct endevice *addr;
208*5083Swnj 	register struct en_softc *es;
209*5083Swnj 	register struct ifuba *ifu;
210*5083Swnj 	struct en_header *en;
211*5083Swnj     	struct mbuf *m;
212*5083Swnj 	struct ifqueue *inq;
2134686Swnj 	register int len;
214*5083Swnj 	int off;
2154686Swnj COUNT(ENRINT);
2164686Swnj 
217*5083Swnj 	addr = (struct endevice *)eninfo[unit]->ui_addr;
2184771Swnj 	if (addr->en_istat&EN_IERROR) {
219*5083Swnj 		es->es_if->if_ierrors++;
220*5083Swnj 		printf("es%d: input error\n", unit);
221*5083Swnj 		goto setup;
2224686Swnj 	}
223*5083Swnj 	ifu = en_softc[unit].es_ifuba;
224*5083Swnj 	UBAPURGE(ifu->ifu_uba, ifu->ifu_r.ifrw_bdp);
225*5083Swnj 	en = (struct en_header *)(ifu->ifu_r.ifrw_addr);
226*5083Swnj #define	endataaddr(en, off, type)	((type)(((caddr_t)((en)+1)+(off))))
227*5083Swnj 	if (en->en_type >= ENPUP_TRAIL &&
228*5083Swnj 	    en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) {
229*5083Swnj 		off = (en->en_type - ENPUP_TRAIL) * 512;
230*5083Swnj 		en->en_type = *endataaddr(en, off, u_short *);
231*5083Swnj 		off += 2;
232*5083Swnj 	} else
233*5083Swnj 		off = 0;
234*5083Swnj 	switch (en->en_type) {
235*5083Swnj 
236*5083Swnj #ifdef INET
237*5083Swnj 	case ENPUP_IPTYPE:
238*5083Swnj 		len = endataaddr(en, off, struct ip *)->ip_len;
239*5083Swnj 		setipintr();
240*5083Swnj 		inq = &ipintrq;
2414686Swnj 		break;
2424686Swnj #endif
2434686Swnj 
244*5083Swnj 	default:
245*5083Swnj 		printf("en%d: unknow pkt type 0x%x\n", en->en_type);
246*5083Swnj 		goto setup;
2474686Swnj 	}
248*5083Swnj 	if (len == 0)
249*5083Swnj 		goto setup;
250*5083Swnj 	m = if_rubaget(&ifu->ifu_r, len, off);
251*5083Swnj 	IF_ENQUEUE(inq, m);
2524688Swnj setup:
253*5083Swnj 	addr->en_iba = es->es_ifuba->ifu_r.ifrw_info;
254*5083Swnj 	addr->en_iwc = -(sizeof (struct en_header) + ENMTU) >> 1;
2554771Swnj 	addr->en_istat = EN_IEN|EN_GO;
2564688Swnj }
2574686Swnj 
258*5083Swnj /*
259*5083Swnj  * Ethernet output routine.
260*5083Swnj  * Encapsulate a packet of type family for the local net.
261*5083Swnj  */
262*5083Swnj enoutput(ifp, m0, pf)
263*5083Swnj 	struct ifnet *ifp;
264*5083Swnj 	struct mbuf *m0;
265*5083Swnj 	int pf;
2664686Swnj {
267*5083Swnj 	int type, dest;
268*5083Swnj 	register struct mbuf *m;
269*5083Swnj 	register struct en_header *en;
270*5083Swnj 	int s;
2714686Swnj 
272*5083Swnj 	switch (pf) {
273*5083Swnj 
274*5083Swnj #ifdef INET
275*5083Swnj 	case PF_INET: {
276*5083Swnj 		register struct ip *ip = mtod(m0, struct ip *);
277*5083Swnj 		int off;
278*5083Swnj 
279*5083Swnj 		off = ip->ip_len - (ip->ip_hl << 2);
280*5083Swnj 		if (off && off % 512 == 0 && m0->m_off >= MMINOFF + 2) {
281*5083Swnj 			type = ENPUP_TRAIL + (off>>9);
282*5083Swnj 			m0->m_off -= 2;
283*5083Swnj 			m0->m_len += 2;
284*5083Swnj 			*mtod(m0, u_short *) = ENPUP_IPTYPE;
285*5083Swnj 		} else {
286*5083Swnj 			type = ENPUP_IPTYPE;
287*5083Swnj 			off = 0;
288*5083Swnj 		}
289*5083Swnj 		dest = ip->ip_dst.s_addr >> 24;
290*5083Swnj 		}
291*5083Swnj 		break;
292*5083Swnj #endif
293*5083Swnj 
294*5083Swnj 	default:
295*5083Swnj 		printf("en%d: can't encapsulate pf%d\n", ifp->if_unit, pf);
296*5083Swnj 		m_freem(m0);
297*5083Swnj 		return (0);
2984686Swnj 	}
299*5083Swnj 	if (MMINOFF + sizeof (struct en_header) > m0->m_off) {
300*5083Swnj 		m = m_get(0);
301*5083Swnj 		if (m == 0) {
302*5083Swnj 			m_freem(m0);
303*5083Swnj 			return (0);
304*5083Swnj 		}
305*5083Swnj 		m->m_next = m0;
306*5083Swnj 		m->m_off = MMINOFF;
307*5083Swnj 		m->m_len = sizeof (struct en_header);
308*5083Swnj 	} else {
309*5083Swnj 		m = m0;
310*5083Swnj 		m->m_off -= sizeof (struct en_header);
311*5083Swnj 		m->m_len += sizeof (struct en_header);
312*5083Swnj 	}
313*5083Swnj 	en = mtod(m, struct en_header *);
314*5083Swnj 	en->en_shost = ifp->if_host[0];
315*5083Swnj 	en->en_dhost = dest;
316*5083Swnj 	en->en_type = type;
317*5083Swnj 	s = splimp();
318*5083Swnj 	IF_ENQUEUE(&ifp->if_snd, m);
319*5083Swnj 	splx(s);
320*5083Swnj 	if (en_softc[ifp->if_unit].es_oactive == 0)
321*5083Swnj 		enstart(ifp->if_unit);
3224686Swnj }
323