xref: /csrg-svn/sys/vax/if/if_en.c (revision 5083)
1 /*	if_en.c	4.14	81/11/26	*/
2 
3 #include "en.h"
4 /*
5  * Ethernet interface driver
6  */
7 
8 #include "../h/param.h"
9 #include "../h/systm.h"
10 #include "../h/mbuf.h"
11 #include "../h/pte.h"
12 #include "../h/buf.h"
13 #include "../h/protosw.h"
14 #include "../h/socket.h"
15 #include "../h/ubareg.h"
16 #include "../h/ubavar.h"
17 #include "../h/enreg.h"
18 #include "../h/cpu.h"
19 #include "../h/mtpr.h"
20 #include "../h/vmmac.h"
21 #include "../net/in.h"
22 #include "../net/in_systm.h"
23 #include "../net/if.h"
24 #include "../net/if_en.h"
25 #include "../net/if_uba.h"
26 #include "../net/ip.h"
27 #include "../net/ip_var.h"
28 
29 #define	ENMTU	1024
30 
31 int	enprobe(), enattach(), enrint(), enxint(), encollide();
32 struct	uba_device *eninfo[NEN];
33 u_short enstd[] = { 0 };
34 struct	uba_driver endriver =
35 	{ enprobe, 0, enattach, 0, enstd, "es", eninfo };
36 #define	ENUNIT(x)	minor(x)
37 
38 struct	en_softc {
39 	struct	ifnet *es_if;
40 	struct	ifuba *es_ifuba;
41 	short	es_delay;
42 	short	es_mask;
43 	u_char	es_addr;
44 	u_char	es_lastx;
45 	short	es_oactive;
46 	short	es_olen;
47 } en_softc[NEN];
48 
49 enprobe(reg)
50 	caddr_t reg;
51 {
52 	register int br, cvec;
53 	register struct endevice *addr = (struct endevice *)reg;
54 
55 COUNT(ENPROBE);
56 #ifdef lint
57 	br = 0; cvec = br; br = cvec;
58 	enrint(0); enxint(0); encollide(0);
59 #endif
60 	addr->en_istat = 0;
61 	addr->en_owc = -1;
62 	addr->en_oba = 0;
63 	addr->en_ostat = EN_IEN|EN_GO;
64 	DELAY(100000);
65 	addr->en_ostat = 0;
66 	return (1);
67 }
68 
69 /*ARGSUSED*/
70 enattach(ui)
71 	struct uba_device *ui;
72 {
73 
74 COUNT(ENATTACH);
75 	eninit(ui->ui_unit);
76 	/* net initialization, based on ui->ui_flags?!? */
77 }
78 
79 eninit(unit)
80 	int unit;
81 {
82 	register struct uba_device *ui;
83 	register struct endevice *addr;
84 	register struct en_softc *es;
85 
86 COUNT(ENINIT);
87 	if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0) {
88 		printf("es%d: not alive\n", unit);
89 		return;
90 	}
91 	es = &en_softc[unit];
92 	if (if_ubainit(es->es_ifuba, ui->ui_ubanum,
93 	    sizeof (struct en_header), btop(ENMTU)) == 0) {
94 		printf("es%d: can't initialize\n", unit);
95 		return;
96 	}
97 	addr = (struct endevice *)ui->ui_addr;
98 	addr->en_istat = addr->en_ostat = 0;
99 }
100 
101 enreset(uban)
102 	int uban;
103 {
104 	register int unit;
105 	struct uba_device *ui;
106 
107 COUNT(ENRESET);
108 	for (unit = 0; unit < NEN; unit++) {
109 		ui = eninfo[unit];
110 		if (ui == 0 || ui->ui_ubanum != uban || ui->ui_alive == 0)
111 			continue;
112 		eninit(unit);
113 		printf("es%d ", unit);
114 	}
115 }
116 
117 int	enlastdel = 25;
118 
119 enstart(dev)
120 	dev_t dev;
121 {
122         int unit;
123 	struct uba_device *ui;
124 	register struct endevice *addr;
125 	register struct en_softc *es;
126 	register struct ifuba *ifu;
127 	struct mbuf *m;
128 	int dest;
129 COUNT(ENSTART);
130 
131 	unit = ENUNIT(dev);
132 	ui = eninfo[unit];
133 	es = &en_softc[unit];
134 	if (es->es_oactive)
135 		goto restart;
136 	IF_DEQUEUE(&es->es_if->if_snd, m);
137 	if (m == 0) {
138 		es->es_oactive = 0;
139 		return;
140 	}
141 	dest = mtod(m, struct en_header *)->en_dhost;
142 	es->es_olen = if_wubaput(&es->es_ifuba, m);
143 	if (es->es_lastx && es->es_lastx == dest)
144 		es->es_delay = enlastdel;
145 	else
146 		es->es_lastx = dest;
147 restart:
148 	ifu = es->es_ifuba;
149 	UBAPURGE(ifu->ifu_uba, ifu->ifu_w.ifrw_bdp);
150 	addr = (struct endevice *)ui->ui_addr;
151 	addr->en_oba = (int)ifu->ifu_w.ifrw_addr;
152 	addr->en_odelay = es->es_delay;
153 	addr->en_owc = -((es->es_olen + 1) >> 1);
154 	addr->en_ostat = EN_IEN|EN_GO;
155 	es->es_oactive = 1;
156 }
157 
158 enxint(unit)
159 	int unit;
160 {
161 	register struct endevice *addr;
162 	register struct uba_device *ui;
163 	register struct en_softc *es;
164 COUNT(ENXINT);
165 
166 	ui = eninfo[unit];
167 	es = &en_softc[unit];
168 	if (es->es_oactive == 0)
169 		return;
170 	addr = (struct endevice *)ui->ui_addr;
171 	es = &en_softc[unit];
172 	es->es_oactive = 0;
173 	es->es_delay = 0;
174 	es->es_mask = ~0;
175 	if (addr->en_ostat&EN_OERROR)
176 		printf("es%d: output error\n", unit);
177 	if (es->es_if->if_snd.ifq_head == 0) {
178 		es->es_lastx = 0;
179 		return;
180 	}
181 	enstart(unit);
182 }
183 
184 encollide(unit)
185 	int unit;
186 {
187 	register struct en_softc *es;
188 COUNT(ENCOLLIDE);
189 
190 	es = &en_softc[unit];
191 	es->es_if->if_collisions++;
192 	if (es->es_oactive == 0)
193 		return;
194 	if (es->es_mask == 0) {
195 		printf("es%d: send error\n", unit);
196 		enxint(unit);
197 	} else {
198 		es->es_mask <<= 1;
199 		es->es_delay = mfpr(ICR) &~ es->es_mask;
200 		enstart(unit);
201 	}
202 }
203 
204 enrint(unit)
205 	int unit;
206 {
207 	struct endevice *addr;
208 	register struct en_softc *es;
209 	register struct ifuba *ifu;
210 	struct en_header *en;
211     	struct mbuf *m;
212 	struct ifqueue *inq;
213 	register int len;
214 	int off;
215 COUNT(ENRINT);
216 
217 	addr = (struct endevice *)eninfo[unit]->ui_addr;
218 	if (addr->en_istat&EN_IERROR) {
219 		es->es_if->if_ierrors++;
220 		printf("es%d: input error\n", unit);
221 		goto setup;
222 	}
223 	ifu = en_softc[unit].es_ifuba;
224 	UBAPURGE(ifu->ifu_uba, ifu->ifu_r.ifrw_bdp);
225 	en = (struct en_header *)(ifu->ifu_r.ifrw_addr);
226 #define	endataaddr(en, off, type)	((type)(((caddr_t)((en)+1)+(off))))
227 	if (en->en_type >= ENPUP_TRAIL &&
228 	    en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) {
229 		off = (en->en_type - ENPUP_TRAIL) * 512;
230 		en->en_type = *endataaddr(en, off, u_short *);
231 		off += 2;
232 	} else
233 		off = 0;
234 	switch (en->en_type) {
235 
236 #ifdef INET
237 	case ENPUP_IPTYPE:
238 		len = endataaddr(en, off, struct ip *)->ip_len;
239 		setipintr();
240 		inq = &ipintrq;
241 		break;
242 #endif
243 
244 	default:
245 		printf("en%d: unknow pkt type 0x%x\n", en->en_type);
246 		goto setup;
247 	}
248 	if (len == 0)
249 		goto setup;
250 	m = if_rubaget(&ifu->ifu_r, len, off);
251 	IF_ENQUEUE(inq, m);
252 setup:
253 	addr->en_iba = es->es_ifuba->ifu_r.ifrw_info;
254 	addr->en_iwc = -(sizeof (struct en_header) + ENMTU) >> 1;
255 	addr->en_istat = EN_IEN|EN_GO;
256 }
257 
258 /*
259  * Ethernet output routine.
260  * Encapsulate a packet of type family for the local net.
261  */
262 enoutput(ifp, m0, pf)
263 	struct ifnet *ifp;
264 	struct mbuf *m0;
265 	int pf;
266 {
267 	int type, dest;
268 	register struct mbuf *m;
269 	register struct en_header *en;
270 	int s;
271 
272 	switch (pf) {
273 
274 #ifdef INET
275 	case PF_INET: {
276 		register struct ip *ip = mtod(m0, struct ip *);
277 		int off;
278 
279 		off = ip->ip_len - (ip->ip_hl << 2);
280 		if (off && off % 512 == 0 && m0->m_off >= MMINOFF + 2) {
281 			type = ENPUP_TRAIL + (off>>9);
282 			m0->m_off -= 2;
283 			m0->m_len += 2;
284 			*mtod(m0, u_short *) = ENPUP_IPTYPE;
285 		} else {
286 			type = ENPUP_IPTYPE;
287 			off = 0;
288 		}
289 		dest = ip->ip_dst.s_addr >> 24;
290 		}
291 		break;
292 #endif
293 
294 	default:
295 		printf("en%d: can't encapsulate pf%d\n", ifp->if_unit, pf);
296 		m_freem(m0);
297 		return (0);
298 	}
299 	if (MMINOFF + sizeof (struct en_header) > m0->m_off) {
300 		m = m_get(0);
301 		if (m == 0) {
302 			m_freem(m0);
303 			return (0);
304 		}
305 		m->m_next = m0;
306 		m->m_off = MMINOFF;
307 		m->m_len = sizeof (struct en_header);
308 	} else {
309 		m = m0;
310 		m->m_off -= sizeof (struct en_header);
311 		m->m_len += sizeof (struct en_header);
312 	}
313 	en = mtod(m, struct en_header *);
314 	en->en_shost = ifp->if_host[0];
315 	en->en_dhost = dest;
316 	en->en_type = type;
317 	s = splimp();
318 	IF_ENQUEUE(&ifp->if_snd, m);
319 	splx(s);
320 	if (en_softc[ifp->if_unit].es_oactive == 0)
321 		enstart(ifp->if_unit);
322 }
323