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) 06/05/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 pcl_header { 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 488