1 /* if_pcl.c 4.4 83/07/06 */ 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 491