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