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