xref: /original-bsd/sys/vax/if/if_dp.c (revision 21eed380)
1 /*
2  * Copyright (c) 1990 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)if_dp.c	7.10 (Berkeley) 05/04/92
8  */
9 
10 #include "dp.h"
11 #if NDP > 0
12 
13 /*
14  * DPV-11 device driver, X.25 version
15  *
16  * Derived from dmc-11 driver:
17  *
18  *	Bill Nesheim
19  *	Cornell University
20  *
21  *	Lou Salkind
22  *	New York University
23  */
24 
25 /* #define DEBUG	/* for base table dump on fatal error */
26 
27 #include "../include/pte.h"
28 
29 #include "sys/param.h"
30 #include "sys/systm.h"
31 #include "sys/mbuf.h"
32 #include "sys/buf.h"
33 #include "sys/ioctl.h"		/* must precede tty.h */
34 #include "sys/protosw.h"
35 #include "sys/socket.h"
36 #include "sys/socketvar.h"
37 #include "sys/syslog.h"
38 #include "sys/vmmac.h"
39 #include "sys/errno.h"
40 #include "sys/time.h"
41 #include "sys/kernel.h"
42 
43 #include "net/if.h"
44 #include "net/if_types.h"
45 #include "net/netisr.h"
46 #include "net/route.h"
47 
48 #include "../include/cpu.h"
49 #include "../include/mtpr.h"
50 
51 #define	dzdevice dpdevice
52 #include "../uba/pdma.h"
53 #include "../uba/ubavar.h"
54 
55 #include "netccitt/x25.h"
56 #include "netccitt/pk.h"
57 #include "netccitt/pk_var.h"
58 
59 #include "if_dpreg.h"
60 
61 /*
62  * Driver information for auto-configuration stuff.
63  */
64 int	dpprobe(), dpattach(), dpinit(), dpioctl(), dprint(), dpxint();
65 int	dpoutput(), dpreset(), dptimeout(), dpstart(), dptestoutput();
66 int	x25_ifoutput(), x25_rtrequest();
67 
68 struct	uba_device *dpinfo[NDP];
69 
70 u_short	dpstd[] = { 0 };
71 struct	uba_driver dpdriver =
72 	{ dpprobe, 0, dpattach, 0, dpstd, "dp", dpinfo };
73 
74 /*
75  * Pdma structures for fast interrupts.
76  */
77 struct	pdma dppdma[2*NDP];
78 
79 /*
80  * DP software status per interface.
81  *
82  * Each interface is referenced by a network interface structure,
83  * dp_if, which the routing code uses to locate the interface.
84  * This structure contains the output queue for the interface, its address, ...
85  */
86 struct dp_softc {
87 	struct	ifnet dp_if;		/* network-visible interface */
88 	int	dp_ipl;
89 	struct	dpdevice *dp_addr;	/* dpcsr address */
90 	short	dp_iused;		/* input buffers given to DP */
91 	short	dp_flags;		/* flags */
92 #define DPF_RUNNING	0x01		/* device initialized */
93 #define DPF_ONLINE	0x02		/* device running (had a RDYO) */
94 #define DPF_RESTART	0x04		/* software restart in progress */
95 #define DPF_FLUSH	0x08		/* had a ROVR, flush ipkt when done */
96 #define DPF_X25UP	0x10		/* XXX -- someday we'll do PPP also */
97 	short	dp_ostate;		/* restarting, etc. */
98 	short	dp_istate;		/* not sure this is necessary */
99 #define DPS_IDLE	0
100 #define DPS_RESTART	1
101 #define DPS_ACTIVE	2
102 #define DPS_XEM		3		/* transmitting CRC, etc. */
103 	short	dp_olen;		/* length of last packet sent */
104 	short	dp_ilen;		/* length of last packet recvd */
105 	char	dp_obuf[DP_MTU+8];
106 	char	dp_ibuf[DP_MTU+8];
107 } dp_softc[NDP];
108 
109 /*
110  * Debug info
111  */
112 struct	dpstat {
113 	long	start;
114 	long	nohdr;
115 	long	init;
116 	long	rint;
117 	long	xint;
118 	long	reset;
119 	long	ioctl;
120 	long	down;
121 	long	mchange;
122 	long	timeout;
123 	long	rsm;
124 	long	rem;
125 	long	remchr;
126 	long	rga;
127 	long	xem;
128 	long	rovr;
129 } dpstat;
130 
131 short dp_ilb = 0;
132 short dp_log = 0;
133 
134 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
135 int dp_sizes[] = {
136 	sizeof(dp_softc[0]), sizeof(struct ifnet),
137 	_offsetof(struct dp_softc, dp_obuf[0]),
138 	_offsetof(struct dp_softc, dp_ibuf[0]),
139 	};
140 
141 dpprobe(reg, ui)
142 	caddr_t reg;
143 	struct	uba_device *ui;
144 {
145 	register int br, cvec;
146 	register struct dpdevice *addr = (struct dpdevice *)reg;
147 	register int unit = ui->ui_unit;
148 
149 #ifdef lint
150 	br = 0; cvec = br; br = cvec;
151 	dprint(0); dpxint(0);
152 #endif
153 	(void) spl6();
154 	addr->dpclr = DP_CLR;
155 	addr->dpclr = DP_XIE|DP_XE;
156 	DELAY(100000);
157 	dp_softc[unit].dp_ipl = br = qbgetpri();
158 	dp_softc[unit].dp_addr = addr;
159 	addr->dpclr = 0;
160 	if (cvec && cvec != 0x200){
161 		cvec -= 4;
162 	}
163 	return (1);
164 }
165 
166 /*
167  * Interface exists: make available by filling in network interface
168  * record.  System will initialize the interface when it is ready
169  * to accept packets.
170  */
171 dpattach(ui)
172 	register struct uba_device *ui;
173 {
174 	register struct dp_softc *dp = &dp_softc[ui->ui_unit];
175 
176 	dp->dp_if.if_unit = ui->ui_unit;
177 	dp->dp_if.if_name = "dp";
178 	dp->dp_if.if_mtu = DP_MTU;
179 	dp->dp_if.if_init = dpinit;
180 	dp->dp_if.if_output = x25_ifoutput;
181 	dp->dp_if.if_type = IFT_X25;
182 	dp->dp_if.if_hdrlen = 5;
183 	dp->dp_if.if_addrlen = 8;
184 	dp->dp_if.if_start = dpstart;
185 	dp->dp_if.if_ioctl = dpioctl;
186 	dp->dp_if.if_reset = dpreset;
187 	dp->dp_if.if_watchdog = dptimeout;
188 	dp->dp_if.if_flags = 0;
189 	if_attach(&dp->dp_if);
190 }
191 
192 /*
193  * Reset of interface after UNIBUS reset.
194  * If interface is on specified UBA, reset its state.
195  */
196 dpreset(unit, uban)
197 	int unit, uban;
198 {
199 	register struct uba_device *ui;
200 	register struct dp_softc *dp = &dp_softc[unit];
201 	register struct dpdevice *addr;
202 
203 	dpstat.reset++;
204 	if (unit >= NDP || (ui = dpinfo[unit]) == 0 || ui->ui_alive == 0 ||
205 	    ui->ui_ubanum != uban)
206 		return;
207 	dpdown(unit);
208 	dpinit(unit);
209 	printf(" dp%d", unit);
210 }
211 
212 /*
213  * Initialization of interface.
214  */
215 dpinit(unit)
216 	int unit;
217 {
218 	register struct dp_softc *dp = &dp_softc[unit];
219 	register struct dpdevice *addr;
220 	register struct ifaddr *ifa;
221 	register struct pdma *pdp = &dppdma[unit*2];
222 	int base, s;
223 
224 	dpstat.init++;
225 	/*
226 	 * Check to see that an address has been set.
227 	 */
228 	for (ifa = dp->dp_if.if_addrlist; ifa; ifa = ifa->ifa_next)
229 		if (ifa->ifa_addr->sa_family != AF_LINK)
230 			break;
231 	if (ifa == (struct ifaddr *) 0)
232 		return;
233 
234 	addr = dp->dp_addr;
235 	s = splimp();
236 	dp->dp_iused = 0;
237 	dp->dp_istate = dp->dp_ostate = DPS_IDLE;
238 	dp->dp_if.if_flags |= IFF_RUNNING;
239 	dp->dp_if.if_flags &= ~IFF_OACTIVE;
240 
241 	pdp->p_addr = addr;
242 	pdp->p_fcn = dpxint;
243 	pdp->p_mem = pdp->p_end = dp->dp_obuf;
244 	pdp++;
245 	pdp->p_addr = addr;
246 	pdp->p_fcn = dprint;
247 	/* force initial interrupt to come to dprint */
248 	pdp->p_mem = pdp->p_end = dp->dp_ibuf + DP_MTU + 8;
249 
250 	addr->dpclr = DP_CLR;
251 	DELAY(5000);
252 	/* DP_ATA = 0, DP_CHRM = 0, DP_SSLM = 1, (enable aborts),
253 			    CRC = CCIIT, initially all ones, 2nd addr = 0 */
254 	addr->dpsar = DP_SSLM | DP_IDLE;
255 	addr->dpclr = DP_XE | dp_ilb;
256 	addr->dptdsr = DP_XSM;
257 	/* enable receiver, receive interrupt, DTR, RTS */
258 	addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR | DP_RTS;
259 	dpstart(&dp->dp_if);
260 	splx(s);
261 }
262 
263 /*
264  * Start output on interface.  Get another datagram
265  * to send from the interface queue and map it to
266  * the interface before starting output.
267  *
268  */
269 dpstart(ifp)
270 	struct ifnet *ifp;
271 {
272 	int s, unit = ifp->if_unit, error = 0, len;
273 	register struct dp_softc *dp = &dp_softc[unit];
274 	register struct dpdevice *addr = dp->dp_addr;
275 	register struct mbuf *m;
276 	register char *cp;
277 	char *cplim;
278 
279 	/*
280 	 * If already doing output, go away and depend on transmit
281 	 * complete or error.
282 	 */
283 	dpstat.start++;
284 	if ((dp->dp_if.if_flags & IFF_OACTIVE) ||
285 	    (dp->dp_if.if_flags & IFF_RUNNING) == 0)
286 		goto out;
287 	IF_DEQUEUE(&dp->dp_if.if_snd, m);
288 	if (m == 0)
289 		goto out;
290 	dp->dp_if.if_collisions++;
291 	if (m->m_flags & M_PKTHDR)
292 		len = m->m_pkthdr.len;
293 	else {
294 		struct mbuf *m0 = m;
295 		for (len = 0; m; m = m->m_next)
296 			len += m->m_len;
297 		m = m0;
298 		dpstat.nohdr++;
299 	}
300 	if (len < 2)
301 		goto out;
302 	if (len > DP_MTU) {
303 		error = EINVAL;
304 		goto out;
305 	}
306 	dppdma[2*unit].p_mem = cp = dp->dp_obuf;
307 	while (m) {
308 		struct mbuf *n;
309 		bcopy(mtod(m, caddr_t), (caddr_t)cp, m->m_len);
310 		cp += m->m_len;
311 		MFREE(m, n); m = n;
312 	}
313 	dppdma[2*unit].p_end = cp - 1;
314 	dp->dp_if.if_flags |= IFF_OACTIVE;
315 	dp->dp_ostate = DPS_ACTIVE;
316 	dp->dp_if.if_collisions--;
317 	dp->dp_olen = len;
318 	if (dp_log) {
319 		register u_char *p = (u_char *)dp->dp_obuf;
320 		log(LOG_DEBUG, "dpoutput(%d):%x %x %x %x %x\n",
321 			len, p[0], p[1], p[2], p[3], p[4]);
322 	}
323 	addr->dpsar = DP_SSLM | DP_IDLE;
324 	addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR | DP_RTS;
325 	addr->dpclr = DP_XIE | DP_XE | dp_ilb;
326 	addr->dptdsr = DP_XSM;
327 out:
328 	return (error);
329 }
330 /*
331  * Receive done or error interrupt
332  */
333 dprint(unit, pdma, addr)
334 register struct pdma *pdma;
335 register struct dpdevice *addr;
336 {
337 	register struct dp_softc *dp = &dp_softc[unit];
338 	short rdsr = addr->dprdsr, rcsr = pdma->p_arg;
339 
340 	dpstat.rint++;
341 	splx(dp->dp_ipl);
342 	if (rdsr & DP_RGA) {
343 		/* DP_ATA = 0, DP_CHRM = 0, DP_SSLM = 1, (enable aborts),
344 			    CRC = CCIIT, initially all ones, 2nd addr = 0 */
345 		addr->dpsar = DP_SSLM | DP_IDLE;
346 		addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR | DP_RTS;
347 		dpstat.rga++;
348 		return;
349 	}
350 	if (rdsr & DP_RSM) { /* Received Start of Message */
351 		dpstat.rsm++;
352 		pdma->p_mem = dp->dp_ibuf;
353 		if (rcsr & DP_RDR) {
354 		    dp->dp_ibuf[0] = rdsr & DP_RBUF;
355 		    pdma->p_mem++;
356 		}
357 		dp->dp_flags &= ~DPF_FLUSH;
358 		return;
359 	}
360 	if (rdsr & DP_REM) { /* Received End of Message */
361 		dpstat.rem++;
362 		if (rcsr & DP_RDR) {
363 		    *(pdma->p_mem++) = rdsr;
364 		    dpstat.remchr++;
365 		}
366 		dp->dp_ilen = pdma->p_mem - dp->dp_ibuf;
367 		if (rdsr & DP_REC || dp->dp_flags & DPF_FLUSH) {
368 			dp->dp_if.if_ierrors++;
369 		} else
370 			dpinput(&dp->dp_if, dp->dp_ilen, dp->dp_ibuf);
371 		pdma->p_mem = pdma->p_end;
372 		dp->dp_flags &= ~ DPF_FLUSH;
373 		return;
374 	}
375 	if (rdsr & DP_ROVR) {
376 		dpstat.rovr++;
377 		dp->dp_flags |= DPF_FLUSH;
378 		return;
379 	}
380 	if (rcsr & DP_MSC) {
381 		dpstat.mchange++;
382 		if (0 == (rcsr & DP_DSR)) {
383 			log(LOG_DEBUG, "dp%d: lost modem\n", unit);
384 			/*dpdown(unit);*/
385 		}
386 		return;
387 	}
388 	dp->dp_flags |= DPF_FLUSH;
389 	if (pdma->p_mem != pdma->p_end)
390 		log(LOG_DEBUG, "dp%d: unexplained receiver interrupt\n", unit);
391 }
392 /*
393  * Transmit complete or error interrupt
394  */
395 dpxint(unit, pdma, addr)
396 register struct pdma *pdma;
397 register struct dpdevice *addr;
398 {
399 	register struct dp_softc *dp = &dp_softc[unit];
400 	int s;
401 
402 	splx(dp->dp_ipl);
403 	dpstat.xint++;
404 	if (addr->dptdsr & DP_XERR) {
405 		log(LOG_DEBUG, "if_dp%d: data late\n", unit);
406 	restart:
407 		pdma->p_mem = dp->dp_obuf;
408 		addr->dptdsr = DP_XSM;
409 		dp->dp_if.if_oerrors++;
410 		return;
411 	}
412 	switch (dp->dp_ostate) {
413 
414 	case DPS_ACTIVE:
415 		if (pdma->p_mem != pdma->p_end) {
416 			log(LOG_DEBUG, "if_dp%d: misc error in dpxint\n", unit);
417 			goto restart;
418 		}
419 		addr->dpsar = DP_IDLE|DP_SSLM;
420 		addr->dpclr = DP_XE | DP_XIE | dp_ilb;
421 		addr->dptdsr = DP_XEM | (0xff & pdma->p_mem[0]);
422 		addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR | DP_RTS;
423 		dp->dp_ostate = DPS_XEM;
424 		break;
425 
426 	case DPS_XEM:
427 		dpstat.xem++;
428 		dp->dp_if.if_opackets++;
429 		dp->dp_ostate = DPS_IDLE;
430 		dp->dp_if.if_flags &= ~IFF_OACTIVE;
431 		if (dp->dp_if.if_snd.ifq_len)
432 			dpstart(&dp->dp_if);
433 		else {
434 			addr->dpsar = DP_IDLE|DP_SSLM;
435 			addr->dpclr = DP_XE | dp_ilb;
436 			addr->dptdsr = DP_XSM;
437 			addr->dprcsr = DP_RIE | DP_MIE | DP_RE | DP_DTR|DP_RTS;
438 		}
439 		break;
440 
441 	default:
442 		log(LOG_DEBUG, "if_dp%d: impossible state in dpxint\n");
443 	}
444 }
445 
446 dpinput(ifp, len, buffer)
447 register struct ifnet *ifp;
448 caddr_t buffer;
449 {
450 	register struct ifqueue *inq;
451 	register struct mbuf *m;
452 	extern struct ifqueue hdintrq, ipintrq;
453 	int isr;
454 	extern struct mbuf *m_devget();
455 
456 	ifp->if_ipackets++;
457 	if (dp_log) {
458 		register u_char *p = (u_char *)buffer;
459 		log(LOG_DEBUG, "dpinput(%d):%x %x %x %x %x\n",
460 			len, p[0], p[1], p[2], p[3], p[4]);
461 	}
462 
463     {
464 	register struct ifaddr *ifa = ifp->if_addrlist;
465 	register u_char *cp = (u_char *)buffer;
466 
467 	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
468 		if (ifa->ifa_addr->sa_family != AF_LINK)
469 			break;
470 	if (cp[0] == 0xff && cp[1] == 0x3) {
471 		/* This is a UI HDLC Packet, so we'll assume PPP
472 		   protocol.  for now, IP only. */
473 		buffer += 4;
474 		len -= 4;
475 		inq = &ipintrq;
476 		isr = NETISR_IP;
477 	} else {
478 		inq = &hdintrq;
479 		isr = NETISR_CCITT;
480 	}
481     }
482 	if (len <= 0)
483 		return;
484 
485 	m = m_devget(buffer, len , 0, ifp, 0);
486 	if (m == 0)
487 		return;
488 
489 	if(IF_QFULL(inq)) {
490 		IF_DROP(inq);
491 		m_freem(m);
492 	} else {
493 		IF_ENQUEUE(inq, m);
494 		schednetisr(isr);
495 	}
496 }
497 
498 /*
499  * Process an ioctl request.
500  */
501 dpioctl(ifp, cmd, data)
502 	register struct ifnet *ifp;
503 	int cmd;
504 	caddr_t data;
505 {
506 	register struct ifaddr *ifa = (struct ifaddr *)data;
507 	int s = splimp(), error = 0;
508 	struct dp_softc *dp = &dp_softc[ifp->if_unit];
509 
510 	dpstat.ioctl++;
511 	switch (cmd) {
512 	case SIOCSIFCONF_X25:
513 		ifp->if_flags |= IFF_UP;
514 		error = hd_ctlinput(PRC_IFUP, ifa->ifa_addr);
515 		if (error == 0)
516 			dpinit(ifp->if_unit);
517 		break;
518 
519 	case SIOCSIFADDR:
520 		ifa->ifa_rtrequest = x25_rtrequest;
521 		break;
522 
523 	case SIOCSIFFLAGS:
524 		if ((ifp->if_flags & IFF_UP) == 0 &&
525 		    (ifp->if_flags & IFF_RUNNING))
526 			dpdown(ifp->if_unit);
527 		else if (ifp->if_flags & IFF_UP &&
528 		    (ifp->if_flags & IFF_RUNNING) == 0)
529 			dpinit(ifp->if_unit);
530 		break;
531 
532 
533 	default:
534 		error = EINVAL;
535 	}
536 	splx(s);
537 	return (error);
538 }
539 /*
540  * Reset a device and mark down.
541  * Flush output queue and drop queue limit.
542  */
543 dpdown(unit)
544 int unit;
545 {
546 
547 	register struct dp_softc *dp = &dp_softc[unit];
548 	register struct dpdevice *addr = dp->dp_addr;
549 
550 	dpstat.down++;
551 	if_qflush(&dp->dp_if.if_snd);
552 	dp->dp_flags = 0;
553 	dp->dp_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
554 
555 	addr->dpclr = DP_CLR;
556 	DELAY(1000);
557 	addr->dpsar = 0;
558 	addr->dprcsr = 0;
559 }
560 
561 /*
562  * Watchdog timeout to see that transmitted packets don't
563  * lose interrupts.  The device has to be online (the first
564  * transmission may block until the other side comes up).
565  */
566 dptimeout(unit)
567 	int unit;
568 {
569 	register struct dp_softc *dp;
570 
571 	/* currently not armed */
572 	dpstat.timeout++;
573 	dp = &dp_softc[unit];
574 	if (dp->dp_if.if_flags & IFF_OACTIVE) {
575 		dpstart(&dp->dp_if);
576 	}
577 }
578 /*
579  * For debugging loopback activity.
580  */
581 static char pppheader[4] = { -1, 3, 0, 0x21 };
582 int dp_louts;
583 
584 dptestoutput(ifp, m, dst, rt)
585 register struct ifnet *ifp;
586 register struct mbuf *m;
587 struct sockaddr *dst;
588 struct rtentry *rt;
589 {
590 	/*
591 	 * Queue message on interface, and start output if interface
592 	 * not yet active.
593 	 */
594 	int s = splimp(), error = 0;
595 	dp_louts++;
596 	M_PREPEND(m, sizeof pppheader, M_DONTWAIT);
597 	if (m == 0) {
598 		splx(s);
599 		return ENOBUFS;
600 	}
601 	bcopy(pppheader, mtod(m, caddr_t), sizeof pppheader);
602 	if (IF_QFULL(&ifp->if_snd)) {
603 		IF_DROP(&ifp->if_snd);
604 	    /* printf("%s%d: HDLC says OK to send but queue full, may hang\n",
605 			ifp->if_name, ifp->if_unit);*/
606 		m_freem(m);
607 		error = ENOBUFS;
608 	} else {
609 		IF_ENQUEUE(&ifp->if_snd, m);
610 		if ((ifp->if_flags & IFF_OACTIVE) == 0)
611 			(*ifp->if_start)(ifp);
612 	}
613 	splx(s);
614 	return (error);
615 }
616 
617 #endif
618