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