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.2 (Berkeley) 08/04/88 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 if (m->m_off > MMAXOFF || 245 MMINOFF + sizeof (struct pcl_header) > m->m_off) { 246 m2 = m_get(M_DONTWAIT, MT_HEADER); 247 if (m2 == 0) { 248 error = ENOBUFS; 249 goto bad; 250 } 251 m2->m_next = m; 252 m2->m_off = MMINOFF; 253 m2->m_len = sizeof (struct pcl_header); 254 m = m2; 255 } else { 256 m->m_off -= sizeof (struct pcl_header); 257 m->m_len += sizeof (struct pcl_header); 258 } 259 pclp = mtod(m, struct pcl_header *); 260 pclp->pcl_dest = dest; 261 262 /* 263 * Queue message on interface, and start output if interface 264 * not yet active. 265 */ 266 s = splimp(); 267 if (IF_QFULL(&ifp->if_snd)) { 268 IF_DROP(&ifp->if_snd); 269 error = ENOBUFS; 270 goto qfull; 271 } 272 IF_ENQUEUE(&ifp->if_snd, m); 273 if (pcl_softc[ifp->if_unit].sc_oactive == 0) 274 pclstart(ifp->if_unit); 275 splx(s); 276 return (0); 277 qfull: 278 splx(s); 279 bad: 280 m_freem(m); 281 return (error); 282 } 283 284 /* 285 * Start or restart output on interface. 286 * If interface is already active, then this is a retransmit. 287 * If interface is not already active, get another datagram 288 * to send off of the interface queue, and map it to the interface 289 * before starting the output. 290 */ 291 pclstart(dev) 292 dev_t dev; 293 { 294 int unit = PCLUNIT(dev); 295 struct uba_device *ui = pclinfo[unit]; 296 register struct pcl_softc *sc = &pcl_softc[unit]; 297 register struct pcldevice *addr; 298 struct mbuf *m; 299 300 if (sc->sc_oactive) 301 goto restart; 302 303 /* 304 * Not already active: dequeue another request 305 * and map it to the UNIBUS. If no more requests, 306 * just return. 307 */ 308 IF_DEQUEUE(&sc->sc_if.if_snd, m); 309 if (m == 0) { 310 sc->sc_oactive = 0; 311 return; 312 } 313 314 /* 315 * Pull destination node out of pseudo-local net header. 316 * remove it from outbound data. 317 * Note that if_wubaput calls m_bcopy, which is prepared for 318 * m_len to be 0 in the first mbuf in the chain. 319 */ 320 sc->sc_bdest = mtod(m, struct pcl_header *)->pcl_dest; 321 sc->sc_odest = sc->sc_bdest? sc->sc_bdest: 1; 322 m->m_off += sizeof (struct pcl_header); 323 m->m_len -= sizeof (struct pcl_header); 324 325 /* Map out to the DMA area */ 326 sc->sc_olen = if_wubaput(&sc->sc_ifuba, m); 327 328 restart: 329 /* 330 * Have request mapped to UNIBUS for transmission. 331 * Purge any stale data from this BDP, and start the output. 332 */ 333 if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP) 334 UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_w.ifrw_bdp); 335 addr = (struct pcldevice *)ui->ui_addr; 336 addr->pcl_tcr = PCL_TXINIT; 337 addr->pcl_tsba = (int)sc->sc_ifuba.ifu_w.ifrw_info; 338 addr->pcl_tsbc = -sc->sc_olen; 339 340 /* 341 * RIB (retry if busy) is used on the second and subsequent packets 342 * to a single host, because TCP often wants to transmit multiple 343 * buffers in a row, 344 * and if they are all going to the same place, the second and 345 * subsequent ones may be lost due to receiver not ready again yet. 346 * This can cause serious problems, because the TCP will resend the 347 * whole window, which just repeats the problem. The result is that 348 * a perfectly good link appears not to work unless we take steps here. 349 */ 350 addr->pcl_tcr = (((int)(sc->sc_ifuba.ifu_w.ifrw_info>>12))&0x0030) | 351 ((sc->sc_odest & 0xF)<<8) | 352 PCL_TXNPR | PCL_SNDWD | PCL_STTXM | PCL_IE | 353 (sc->sc_odest == sc->sc_lastdest ? PCL_RIB : 0); 354 sc->sc_lastdest = sc->sc_odest; 355 sc->sc_oactive = 1; 356 } 357 358 /* 359 * PCL transmitter interrupt. 360 * Start another output if more data to send. 361 */ 362 pclxint(unit) 363 int unit; 364 { 365 register struct uba_device *ui = pclinfo[unit]; 366 register struct pcl_softc *sc = &pcl_softc[unit]; 367 register struct pcldevice *addr = (struct pcldevice *)ui->ui_addr; 368 369 if (sc->sc_oactive == 0) { 370 printf ("pcl%d: stray interrupt\n", unit); 371 return; 372 } 373 if (addr->pcl_tsr & PCL_ERR) { 374 sc->sc_lastdest = 0; /* don't bother with RIB */ 375 if (addr->pcl_tsr & PCL_MSTDWN) { 376 addr->pcl_tmmr = PCL_MASTER|PCL_AUTOADDR; 377 pclstart(unit); /* Retry */ 378 printf("pcl%d: master\n", unit ); 379 return; 380 } 381 #ifndef PCL_TESTING 382 if ((addr->pcl_tsr & (PCL_ERR|PCL_RESPB)) == (PCL_ERR|0)) { 383 ; /* Receiver Offline -- not exactly an error */ 384 } else { 385 #else 386 { 387 #endif 388 /* Log as an error */ 389 printf("pcl%d: send error, tcr=%b tsr=%b\n", 390 unit, addr->pcl_tcr, PCL_TCSRBITS, 391 addr->pcl_tsr, PCL_TERRBITS); 392 sc->sc_if.if_oerrors++; 393 } 394 } else 395 sc->sc_if.if_opackets++; 396 if (sc->sc_bdest == 0 && sc->sc_odest < PCLMAXTDM) { 397 sc->sc_odest++; /* do next host (broadcast) */ 398 } else { 399 sc->sc_oactive = 0; 400 if (sc->sc_ifuba.ifu_xtofree) { 401 m_freem(sc->sc_ifuba.ifu_xtofree); 402 sc->sc_ifuba.ifu_xtofree = 0; 403 } 404 } 405 pclstart(unit); 406 } 407 408 /* 409 * PCL interface receiver interrupt. 410 * If input error just drop packet. 411 */ 412 pclrint(unit) 413 int unit; 414 { 415 register struct pcl_softc *sc = &pcl_softc[unit]; 416 struct pcldevice *addr = (struct pcldevice *)pclinfo[unit]->ui_addr; 417 struct mbuf *m; 418 int len; 419 register struct ifqueue *inq; 420 421 sc->sc_if.if_ipackets++; 422 /* 423 * Purge BDP; drop if input error indicated. 424 */ 425 if (sc->sc_ifuba.ifu_flags & UBA_NEEDBDP) 426 UBAPURGE(sc->sc_ifuba.ifu_uba, sc->sc_ifuba.ifu_r.ifrw_bdp); 427 if (addr->pcl_rsr & PCL_ERR) { 428 printf("pcl%d: rcv error, rcr=%b rsr=%b\n", 429 unit, addr->pcl_rcr, PCL_RCSRBITS, 430 addr->pcl_rsr, PCL_RERRBITS); 431 sc->sc_if.if_ierrors++; 432 goto setup; 433 } 434 len = PCLMTU + addr->pcl_rdbc; 435 if (len <= 0 || len > PCLMTU) { 436 printf("pcl%d: bad len=%d.\n", unit, len); 437 sc->sc_if.if_ierrors++; 438 goto setup; 439 } 440 441 /* Really short packets will be part of the startup sequence */ 442 if (len <= 4) { 443 /* Later, do comming-up processing here */ 444 goto setup; /* drop packet */ 445 } 446 447 /* 448 * Pull packet off interface. 449 */ 450 m = if_rubaget(&sc->sc_ifuba, len, 0, &sc->sc_if); 451 if (m == 0) 452 goto setup; 453 454 schednetisr(NETISR_IP); 455 inq = &ipintrq; 456 457 if (IF_QFULL(inq)) { 458 IF_DROP(inq); 459 m_freem(m); 460 } else 461 IF_ENQUEUE(inq, m); 462 setup: 463 /* 464 * Reset for next packet. 465 */ 466 addr->pcl_rcr = PCL_RCINIT; 467 addr->pcl_rdba = (int)sc->sc_ifuba.ifu_r.ifrw_info; 468 addr->pcl_rdbc = -PCLMTU; 469 addr->pcl_rcr = (((int)(sc->sc_ifuba.ifu_w.ifrw_info>>12))&0x0030) | 470 PCL_RCNPR | PCL_RCVWD | PCL_RCVDAT | PCL_IE; 471 } 472 473 /* 474 * Process an ioctl request. 475 */ 476 /* ARGSUSED */ 477 pclioctl(ifp, cmd, data) 478 register struct ifnet *ifp; 479 int cmd; 480 caddr_t data; 481 { 482 int s = splimp(), error = 0; 483 484 switch (cmd) { 485 486 case SIOCSIFADDR: 487 ifp->if_flags |= IFF_UP; 488 if ((ifp->if_flags & IFF_RUNNING) == 0) 489 pclinit(ifp->if_unit); 490 break; 491 492 default: 493 error = EINVAL; 494 } 495 splx(s); 496 return (error); 497 } 498 #endif 499