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