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