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