xref: /csrg-svn/sys/vax/if/if_pcl.c (revision 11816)
1 /*	if_pcl.c	4.1	83/03/31	*/
2 
3 #include "pcl.h"
4 #if NPCL > 0
5 /*
6  * DEC CSS PCL-11B Parallel Communications Interface
7  *
8  * Written by Mike Muuss.
9  */
10 #include "../machine/pte.h"
11 
12 #include "../h/param.h"
13 #include "../h/systm.h"
14 #include "../h/mbuf.h"
15 #include "../h/buf.h"
16 #include "../h/protosw.h"
17 #include "../h/socket.h"
18 #include "../h/vmmac.h"
19 #include "../h/errno.h"
20 
21 #include "../net/if.h"
22 #include "../net/netisr.h"
23 #include "../net/route.h"
24 #include "../netinet/in.h"
25 #include "../netinet/in_systm.h"
26 #include "../netinet/ip.h"
27 #include "../netinet/ip_var.h"
28 
29 #include "../vax/cpu.h"
30 #include "../vax/mtpr.h"
31 #include "../vaxif/if_pclreg.h"
32 #include "../vaxif/if_uba.h"
33 #include "../vaxuba/ubareg.h"
34 #include "../vaxuba/ubavar.h"
35 
36 /* The MTU has been carefully selected to prevent fragmentation <-> ArpaNet */
37 #define	PCLMTU	(1006)		/* Max transmission unit (bytes) */
38 
39 int	pclprobe(), pclattach(), pclrint(), pclxint();
40 int	pclinit(),pcloutput(),pclreset();
41 
42 struct	uba_device	*pclinfo[NPCL];
43 u_short pclstd[] = { 0 };
44 #define	PCLUNIT(x)	minor(x)
45 struct	uba_driver pcldriver =
46 	{ pclprobe, 0, pclattach, 0, pclstd, "pcl", pclinfo };
47 
48 /*
49  * PCL software status per interface.
50  *
51  * Each interface is referenced by a network interface structure,
52  * sc_if, which the routing code uses to locate the interface.
53  * This structure contains the output queue for the interface, its address, ...
54  * We also have, for each interface, a UBA interface structure, which
55  * contains information about the UNIBUS resources held by the interface:
56  * map registers, buffered data paths, etc.  Information is cached in this
57  * structure for use by the if_uba.c routines in running the interface
58  * efficiently.
59  */
60 struct	pcl_softc {
61 	struct	ifnet sc_if;		/* network-visible interface */
62 	struct	ifuba sc_ifuba;		/* UNIBUS resources */
63 	short	sc_oactive;		/* is output active? */
64 	short	sc_olen;		/* length of last output */
65 	short	sc_lastdest;		/* previous destination */
66 	short	sc_odest;		/* current xmit destination */
67 	short	sc_pattern;		/* identification pattern */
68 } pcl_softc[NPCL];
69 
70 /*
71  * Structure of "local header", which only goes between
72  * pcloutput and pclstart.
73  */
74 struct pcl_header {
75 	short	pcl_dest;		/* Destination PCL station */
76 };
77 
78 /*
79  * Do non-DMA output of 1 word to determine presence of interface,
80  * and to find the interupt vector.  1 word messages are a special
81  * case in the receiver routine, and will be discarded.
82  */
83 pclprobe(reg)
84 	caddr_t reg;
85 {
86 	register int br, cvec;		/* r11, r10 value-result */
87 	register struct pcldevice *addr = (struct pcldevice *)reg;
88 
89 #ifdef lint
90 	br = 0; cvec = br; br = cvec;
91 	pclrint(0); pclxint(0);
92 #endif
93 	addr->pcl_rcr = PCL_RCINIT;
94 	addr->pcl_tcr = PCL_TXINIT;
95 	addr->pcl_tsba = 0xFFFE;
96 	/* going for 01777776 */
97 	addr->pcl_tsbc = -4;		/* really short */
98 	addr->pcl_tcr =
99 	 ((1 & 0xF) << 8) | PCL_TXNPR | PCL_SNDWD | PCL_STTXM | PCL_IE | 0x0030;
100 	DELAY(100000);
101 	addr->pcl_tcr = PCL_TXINIT;
102 	return (sizeof (struct pcldevice));
103 }
104 
105 /*
106  * Interface exists: make available by filling in network interface
107  * record.  System will initialize the interface when it is ready
108  * to accept packets.
109  */
110 pclattach(ui)
111 	struct uba_device *ui;
112 {
113 	register struct pcl_softc *sc = &pcl_softc[ui->ui_unit];
114 	register struct sockaddr_in *sin;
115 
116 	sc->sc_if.if_unit = ui->ui_unit;
117 	sc->sc_if.if_name = "pcl";
118 	sc->sc_if.if_mtu = PCLMTU;
119 	/* copy network addr from flags long */
120 	sc->sc_if.if_net = in_netof(htonl(ui->ui_flags));
121 	sc->sc_if.if_host[0] = in_lnaof(htonl(ui->ui_flags));
122 
123 	sin = (struct sockaddr_in *)&sc->sc_if.if_addr;
124 	sin->sin_family = AF_INET;
125 	sin->sin_addr.s_addr = htonl(ui->ui_flags);
126 
127 	sc->sc_if.if_init = pclinit;
128 	sc->sc_if.if_output = pcloutput;
129 	sc->sc_if.if_reset = pclreset;
130 	sc->sc_ifuba.ifu_flags = UBA_NEEDBDP;
131 	if_attach(&sc->sc_if);
132 }
133 
134 /*
135  * Reset of interface after UNIBUS reset.
136  * If interface is on specified uba, reset its state.
137  */
138 pclreset(unit, uban)
139 	int unit, uban;
140 {
141 	register struct uba_device *ui;
142 
143 	if (unit >= NPCL || (ui = pclinfo[unit]) == 0 || ui->ui_alive == 0 ||
144 	    ui->ui_ubanum != uban)
145 		return;
146 	printf(" pcl%d", unit);
147 	pclinit(unit);
148 }
149 
150 /*
151  * Initialization of interface; clear recorded pending
152  * operations, and reinitialize UNIBUS usage.
153  */
154 pclinit(unit)
155 	int unit;
156 {
157 	register struct pcl_softc *sc = &pcl_softc[unit];
158 	register struct uba_device *ui = pclinfo[unit];
159 	register struct pcldevice *addr;
160 	int s;
161 
162 	if (if_ubainit(&sc->sc_ifuba, ui->ui_ubanum, 0,
163 	    (int)btoc(PCLMTU)) == 0) {
164 		printf("pcl%d: can't init\n", unit);
165 		sc->sc_if.if_flags &= ~IFF_UP;
166 		return;
167 	}
168 	addr = (struct pcldevice *)ui->ui_addr;
169 	addr->pcl_rcr = PCL_RCINIT;
170 	addr->pcl_tcr = PCL_TXINIT;
171 
172 	/*
173 	 * Hang a receive and start any
174 	 * pending writes by faking a transmit complete.
175 	 */
176 	s = splimp();
177 	addr->pcl_rdba = (short) sc->sc_ifuba.ifu_r.ifrw_info;
178 	addr->pcl_rdbc = -PCLMTU;
179 	addr->pcl_rcr = (((int)(sc->sc_ifuba.ifu_r.ifrw_info>>12))&0x0030) |
180 		PCL_RCNPR | PCL_RCVWD | PCL_RCVDAT | PCL_IE;
181 	sc->sc_oactive = 0;
182 	sc->sc_if.if_flags |= IFF_UP;		/* Mark interface up */
183 	pclstart(unit);
184 	splx(s);
185 	/* Set up routing table entry */
186 	if_rtinit(&sc->sc_if, RTF_UP);
187 }
188 
189 /*
190  * PCL output routine.
191  */
192 pcloutput(ifp, m, dst)
193 	struct ifnet *ifp;
194 	struct mbuf *m;
195 	struct sockaddr *dst;
196 {
197 	int type, dest, s, error;
198 	struct pcl_header *pclp;
199 	struct mbuf *m2;
200 
201 	switch (dst->sa_family) {
202 
203 #ifdef INET
204 	case AF_INET:
205 		dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
206 		dest = ntohl(dest);	/* ??? */
207 		dest = dest & 0xff;
208 		break;
209 #endif
210 	default:
211 		printf("pcl%d: can't handle af%d\n", ifp->if_unit,
212 			dst->sa_family);
213 		error = EAFNOSUPPORT;
214 		goto bad;
215 	}
216 
217 	/*
218 	 * Add pseudo local net header.
219 	 * Actually, it does not get transmitted, but merely stripped
220 	 * off and used by the START routine to route the packet.
221 	 * If no space in first mbuf, allocate another.
222 	 */
223 	if (m->m_off > MMAXOFF ||
224 	    MMINOFF + sizeof (struct pcl_header) > m->m_off) {
225 		m2 = m_get(M_DONTWAIT, MT_HEADER);
226 		if (m2 == 0) {
227 			error = ENOBUFS;
228 			goto bad;
229 		}
230 		m2->m_next = m;
231 		m2->m_off = MMINOFF;
232 		m2->m_len = sizeof (struct pcl_header);
233 		m = m2;
234 	} else {
235 		m->m_off -= sizeof (struct pcl_header);
236 		m->m_len += sizeof (struct pcl_header);
237 	}
238 	pclp = mtod(m, struct pcl_header *);
239 	pclp->pcl_dest = dest;
240 
241 	/*
242 	 * Queue message on interface, and start output if interface
243 	 * not yet active.
244 	 */
245 	s = splimp();
246 	if (IF_QFULL(&ifp->if_snd)) {
247 		IF_DROP(&ifp->if_snd);
248 		error = ENOBUFS;
249 		goto qfull;
250 	}
251 	IF_ENQUEUE(&ifp->if_snd, m);
252 	if (pcl_softc[ifp->if_unit].sc_oactive == 0)
253 		pclstart(ifp->if_unit);
254 	splx(s);
255 	return (0);
256 qfull:
257 	splx(s);
258 bad:
259 	m_freem(m);
260 	return (error);
261 }
262 
263 /*
264  * Start or restart output on interface.
265  * If interface is already active, then this is a retransmit.
266  * If interface is not already active, get another datagram
267  * to send off of the interface queue, and map it to the interface
268  * before starting the output.
269  */
270 pclstart(dev)
271 	dev_t dev;
272 {
273         int unit = PCLUNIT(dev);
274 	struct uba_device *ui = pclinfo[unit];
275 	register struct pcl_softc *sc = &pcl_softc[unit];
276 	register struct pcldevice *addr;
277 	struct mbuf *m;
278 
279 	if (sc->sc_oactive)
280 		goto restart;
281 
282 	/*
283 	 * Not already active: dequeue another request
284 	 * and map it to the UNIBUS.  If no more requests,
285 	 * just return.
286 	 */
287 	IF_DEQUEUE(&sc->sc_if.if_snd, m);
288 	if (m == 0) {
289 		sc->sc_oactive = 0;
290 		return;
291 	}
292 
293 	/*
294 	 * Pull destination node out of pseudo-local net header.
295 	 * remove it from outbound data.
296 	 * Note that if_wubaput calls m_bcopy, which is prepared for
297 	 * m_len to be 0 in the first mbuf in the chain.
298 	 */
299 	sc->sc_odest = mtod(m, struct pcl_header *)->pcl_dest;
300 	m->m_off += sizeof (struct pcl_header);
301 	m->m_len -= sizeof (struct pcl_header);
302 
303 	/* Map out to the DMA area */
304 	sc->sc_olen = if_wubaput(&sc->sc_ifuba, m);
305 
306 restart:
307 	/*
308 	 * Have request mapped to UNIBUS for transmission.
309 	 * Purge any stale data from this BDP, and start the otput.
310 	 */
311 	if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
312 		UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_w.ifrw_bdp);
313 	addr = (struct pcldevice *)ui->ui_addr;
314 	addr->pcl_tcr = PCL_TXINIT;
315 	addr->pcl_tsba = (int)sc->sc_ifuba.ifu_w.ifrw_info;
316 	addr->pcl_tsbc = -sc->sc_olen;
317 
318 	/*
319 	 * RIB (retry if busy) is used on the second and subsequent packets
320 	 * to a single host, because TCP often wants to transmit multiple
321 	 * buffers in a row,
322 	 * and if they are all going to the same place, the second and
323 	 * subsequent ones may be lost due to receiver not ready again yet.
324 	 * This can cause serious problems, because the TCP will resend the
325 	 * whole window, which just repeats the problem.  The result is that
326 	 * a perfectly good link appears not to work unless we take steps here.
327 	 */
328 	addr->pcl_tcr = (((int)(sc->sc_ifuba.ifu_w.ifrw_info>>12))&0x0030) |
329 		((sc->sc_odest & 0xF)<<8) |
330 		PCL_TXNPR | PCL_SNDWD | PCL_STTXM | PCL_IE |
331 		(sc->sc_odest == sc->sc_lastdest ? PCL_RIB : 0);
332 	sc->sc_lastdest = sc->sc_odest;
333 	sc->sc_oactive = 1;
334 }
335 
336 /*
337  * PCL transmitter interrupt.
338  * Start another output if more data to send.
339  */
340 pclxint(unit)
341 	int unit;
342 {
343 	register struct uba_device *ui = pclinfo[unit];
344 	register struct pcl_softc *sc = &pcl_softc[unit];
345 	register struct pcldevice *addr = (struct pcldevice *)ui->ui_addr;
346 
347 	if (sc->sc_oactive == 0) {
348 		printf ("pcl%d: stray interrupt\n", unit);
349 		return;
350 	}
351 	if (addr->pcl_tsr & PCL_ERR) {
352 		sc->sc_lastdest = 0;		/* don't bother with RIB */
353 		if (addr->pcl_tsr & PCL_MSTDWN) {
354 			addr->pcl_tmmr = PCL_MASTER|PCL_AUTOADDR;
355 			pclstart(unit);	/* Retry */
356 			printf("pcl%d: master\n", unit );
357 			return;
358 		}
359 		if (addr->pcl_tsr & PCL_RESPB) {
360 			/* Log as an error */
361 			printf("pcl%d: send error, tcr=%b tsr=%b\n",
362 				unit, addr->pcl_tcr, PCL_TCSRBITS,
363 				addr->pcl_tsr, PCL_TERRBITS);
364 			sc->sc_if.if_oerrors++;
365 		}
366 	} else
367 		sc->sc_if.if_opackets++;
368 	sc->sc_oactive = 0;
369 	if (sc->sc_ifuba.ifu_xtofree) {
370 		m_freem(sc->sc_ifuba.ifu_xtofree);
371 		sc->sc_ifuba.ifu_xtofree = 0;
372 	}
373 	pclstart(unit);
374 }
375 
376 /*
377  * PCL interface receiver interrupt.
378  * If input error just drop packet.
379  */
380 pclrint(unit)
381 	int unit;
382 {
383 	register struct pcl_softc *sc = &pcl_softc[unit];
384 	struct pcldevice *addr = (struct pcldevice *)pclinfo[unit]->ui_addr;
385     	struct mbuf *m;
386 	int len, plen; short resid;
387 	register struct ifqueue *inq;
388 	int off;
389 
390 	sc->sc_if.if_ipackets++;
391 	/*
392 	 * Purge BDP; drop if input error indicated.
393 	 */
394 	if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP)
395 		UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_r.ifrw_bdp);
396 	if (addr->pcl_rsr & PCL_ERR) {
397 		printf("pcl%d: rcv error, rcr=%b rsr=%b\n",
398 			unit, addr->pcl_rcr, PCL_RCSRBITS,
399 			addr->pcl_rsr, PCL_RERRBITS);
400 		sc->sc_if.if_ierrors++;
401 		goto setup;
402 	}
403 	len = PCLMTU + addr->pcl_rdbc;
404 	if (len <= 0 || len > PCLMTU) {
405 		printf("pcl%d: bad len=%d.\n", unit, len);
406 		sc->sc_if.if_ierrors++;
407 		goto setup;
408 	}
409 
410 	/* Really short packets will be part of the startup sequence */
411 	if (len <= 4) {
412 		/* Later, do comming-up processing here */
413 		goto setup;	/* drop packet */
414 	}
415 
416 	/*
417 	 * Pull packet off interface.
418 	 */
419 	m = if_rubaget(&sc->sc_ifuba, len, 0);
420 	if (m == 0)
421 		goto setup;
422 
423 	schednetisr(NETISR_IP);
424 	inq = &ipintrq;
425 
426 	if (IF_QFULL(inq)) {
427 		IF_DROP(inq);
428 		m_freem(m);
429 	} else
430 		IF_ENQUEUE(inq, m);
431 setup:
432 	/*
433 	 * Reset for next packet.
434 	 */
435 	addr->pcl_rcr = PCL_RCINIT;
436 	addr->pcl_rdba = (int)sc->sc_ifuba.ifu_r.ifrw_info;
437 	addr->pcl_rdbc = -PCLMTU;
438 	addr->pcl_rcr = (((int)(sc->sc_ifuba.ifu_w.ifrw_info>>12))&0x0030) |
439 		PCL_RCNPR | PCL_RCVWD | PCL_RCVDAT | PCL_IE;
440 }
441 #endif
442