1 /* 2 * Copyright (c) 1982, 1986, 1988 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_acc.c 7.5 (Berkeley) 06/29/88 18 */ 19 20 #include "acc.h" 21 #if NACC > 0 22 23 /* 24 * ACC LH/DH ARPAnet IMP interface driver. 25 */ 26 #include "../machine/pte.h" 27 28 #include "param.h" 29 #include "systm.h" 30 #include "mbuf.h" 31 #include "buf.h" 32 #include "protosw.h" 33 #include "socket.h" 34 #include "vmmac.h" 35 36 #include "../net/if.h" 37 #include "../netimp/if_imp.h" 38 39 #include "../vax/cpu.h" 40 #include "../vax/mtpr.h" 41 #include "if_accreg.h" 42 #include "if_uba.h" 43 #include "../vaxuba/ubareg.h" 44 #include "../vaxuba/ubavar.h" 45 46 int accprobe(), accattach(), accrint(), accxint(); 47 struct uba_device *accinfo[NACC]; 48 u_short accstd[] = { 0 }; 49 struct uba_driver accdriver = 50 { accprobe, 0, accattach, 0, accstd, "acc", accinfo }; 51 52 int accinit(), accoutput(), accdown(), accreset(); 53 54 /* 55 * "Lower half" of IMP interface driver. 56 * 57 * Each IMP interface is handled by a common module which handles 58 * the IMP-host protocol and a hardware driver which manages the 59 * hardware specific details of talking with the IMP. 60 * 61 * The hardware portion of the IMP driver handles DMA and related 62 * management of UNIBUS resources. The IMP protocol module interprets 63 * contents of these messages and "controls" the actions of the 64 * hardware module during IMP resets, but not, for instance, during 65 * UNIBUS resets. 66 * 67 * The two modules are coupled at "attach time", and ever after, 68 * through the imp interface structure. Higher level protocols, 69 * e.g. IP, interact with the IMP driver, rather than the ACC. 70 */ 71 struct acc_softc { 72 struct imp_softc *acc_imp; /* data structure shared with IMP */ 73 struct ifuba acc_ifuba; /* UNIBUS resources */ 74 struct mbuf *acc_iq; /* input reassembly queue */ 75 short acc_olen; /* size of last message sent */ 76 char acc_flush; /* flush remainder of message */ 77 } acc_softc[NACC]; 78 79 /* 80 * Reset the IMP and cause a transmitter interrupt by 81 * performing a null DMA. 82 */ 83 accprobe(reg) 84 caddr_t reg; 85 { 86 register int br, cvec; /* r11, r10 value-result */ 87 register struct accdevice *addr = (struct accdevice *)reg; 88 89 #ifdef lint 90 br = 0; cvec = br; br = cvec; 91 accrint(0); accxint(0); 92 #endif 93 addr->icsr = ACC_RESET; DELAY(5000); 94 addr->ocsr = ACC_RESET; DELAY(5000); 95 addr->ocsr = OUT_BBACK; DELAY(5000); 96 addr->owc = 0; 97 addr->ocsr = ACC_IE | ACC_GO; DELAY(5000); 98 addr->ocsr = 0; 99 if (cvec && cvec != 0x200) /* transmit -> receive */ 100 cvec -= 4; 101 return (1); 102 } 103 104 /* 105 * Call the IMP module to allow it to set up its internal 106 * state, then tie the two modules together by setting up 107 * the back pointers to common data structures. 108 */ 109 accattach(ui) 110 register struct uba_device *ui; 111 { 112 register struct acc_softc *sc = &acc_softc[ui->ui_unit]; 113 register struct impcb *ip; 114 115 if ((sc->acc_imp = impattach(ui->ui_driver->ud_dname, ui->ui_unit, 116 accreset)) == 0) 117 return; 118 ip = &sc->acc_imp->imp_cb; 119 ip->ic_init = accinit; 120 ip->ic_output = accoutput; 121 ip->ic_down = accdown; 122 sc->acc_ifuba.ifu_flags = UBA_CANTWAIT; 123 #ifdef notdef 124 sc->acc_ifuba.ifu_flags |= UBA_NEEDBDP; 125 #endif 126 } 127 128 /* 129 * Reset interface after UNIBUS reset. 130 * If interface is on specified uba, reset its state. 131 */ 132 accreset(unit, uban) 133 int unit, uban; 134 { 135 register struct uba_device *ui; 136 struct acc_softc *sc; 137 138 if (unit >= NACC || (ui = accinfo[unit]) == 0 || ui->ui_alive == 0 || 139 ui->ui_ubanum != uban) 140 return; 141 printf(" acc%d", unit); 142 sc = &acc_softc[unit]; 143 sc->acc_imp->imp_if.if_flags &= ~IFF_RUNNING; 144 accoflush(unit); 145 /* must go through IMP to allow it to set state */ 146 (*sc->acc_imp->imp_if.if_init)(sc->acc_imp->imp_if.if_unit); 147 } 148 149 /* 150 * Initialize interface: clear recorded pending operations, 151 * and retrieve, and initialize UNIBUS resources. Note 152 * return value is used by IMP init routine to mark IMP 153 * unavailable for outgoing traffic. 154 */ 155 accinit(unit) 156 int unit; 157 { 158 register struct acc_softc *sc; 159 register struct uba_device *ui; 160 register struct accdevice *addr; 161 int info; 162 163 if (unit >= NACC || (ui = accinfo[unit]) == 0 || ui->ui_alive == 0) { 164 printf("acc%d: not alive\n", unit); 165 return (0); 166 } 167 sc = &acc_softc[unit]; 168 /* 169 * Header length is 0 since we have to passs 170 * the IMP leader up to the protocol interpretation 171 * routines. If we had the header length as 172 * sizeof(struct imp_leader), then the if_ routines 173 * would asssume we handle it on input and output. 174 */ 175 if ((sc->acc_imp->imp_if.if_flags & IFF_RUNNING) == 0 && 176 if_ubainit(&sc->acc_ifuba, ui->ui_ubanum, 0, 177 (int)btoc(IMP_RCVBUF)) == 0) { 178 printf("acc%d: can't initialize\n", unit); 179 sc->acc_imp->imp_if.if_flags &= ~(IFF_UP | IFF_RUNNING); 180 return (0); 181 } 182 sc->acc_imp->imp_if.if_flags |= IFF_RUNNING; 183 addr = (struct accdevice *)ui->ui_addr; 184 185 /* 186 * Reset the imp interface; 187 * the delays are pure guesswork. 188 */ 189 addr->ocsr = ACC_RESET; DELAY(5000); 190 addr->ocsr = OUT_BBACK; DELAY(5000); /* reset host master ready */ 191 addr->ocsr = 0; 192 if (accinputreset(addr, unit) == 0) { 193 ui->ui_alive = 0; 194 return (0); 195 } 196 197 /* 198 * Put up a read. We can't restart any outstanding writes 199 * until we're back in synch with the IMP (i.e. we've flushed 200 * the NOOPs it throws at us). 201 * Note: IMP_RCVBUF includes the leader. 202 */ 203 info = sc->acc_ifuba.ifu_r.ifrw_info; 204 addr->iba = (u_short)info; 205 addr->iwc = -((IMP_RCVBUF) >> 1); 206 #ifdef LOOPBACK 207 addr->ocsr |= OUT_BBACK; 208 #endif 209 addr->icsr = 210 IN_MRDY | ACC_IE | IN_WEN | ((info & 0x30000) >> 12) | ACC_GO; 211 return (1); 212 } 213 214 accinputreset(addr, unit) 215 register struct accdevice *addr; 216 register int unit; 217 { 218 register int i; 219 220 addr->icsr = ACC_RESET; DELAY(5000); 221 addr->icsr = IN_MRDY | IN_WEN; /* close the relay */ 222 DELAY(10000); 223 /* YECH!!! */ 224 for (i = 0; i < 500; i++) { 225 if ((addr->icsr & IN_HRDY) || 226 (addr->icsr & (IN_RMR | IN_IMPBSY)) == 0) 227 return (1); 228 addr->icsr = IN_MRDY | IN_WEN; DELAY(10000); 229 /* keep turning IN_RMR off */ 230 } 231 printf("acc%d: imp doesn't respond, icsr=%b\n", unit, 232 addr->icsr, ACC_INBITS); 233 return (0); 234 } 235 236 /* 237 * Drop the host ready line to mark host down. 238 */ 239 accdown(unit) 240 int unit; 241 { 242 register struct accdevice *addr; 243 244 addr = (struct accdevice *)(accinfo[unit]->ui_addr); 245 addr->ocsr = ACC_RESET; 246 DELAY(5000); 247 addr->ocsr = OUT_BBACK; /* reset host master ready */ 248 accoflush(unit); 249 return (1); 250 } 251 252 accoflush(unit) 253 int unit; 254 { 255 register struct acc_softc *sc = &acc_softc[unit]; 256 257 sc->acc_imp->imp_cb.ic_oactive = 0; 258 if (sc->acc_ifuba.ifu_xtofree) { 259 m_freem(sc->acc_ifuba.ifu_xtofree); 260 sc->acc_ifuba.ifu_xtofree = 0; 261 } 262 } 263 264 /* 265 * Start output on an interface. 266 */ 267 accoutput(unit, m) 268 int unit; 269 struct mbuf *m; 270 { 271 int info; 272 register struct acc_softc *sc = &acc_softc[unit]; 273 register struct accdevice *addr; 274 u_short cmd; 275 276 sc->acc_olen = if_wubaput(&sc->acc_ifuba, m); 277 /* 278 * Have request mapped to UNIBUS for 279 * transmission; start the output. 280 */ 281 if (sc->acc_ifuba.ifu_flags & UBA_NEEDBDP) 282 UBAPURGE(sc->acc_ifuba.ifu_uba, sc->acc_ifuba.ifu_w.ifrw_bdp); 283 addr = (struct accdevice *)accinfo[unit]->ui_addr; 284 info = sc->acc_ifuba.ifu_w.ifrw_info; 285 addr->oba = (u_short)info; 286 addr->owc = -((sc->acc_olen + 1) >> 1); 287 cmd = ACC_IE | OUT_ENLB | ((info & 0x30000) >> 12) | ACC_GO; 288 #ifdef LOOPBACK 289 cmd |= OUT_BBACK; 290 #endif 291 addr->ocsr = cmd; 292 sc->acc_imp->imp_cb.ic_oactive = 1; 293 } 294 295 /* 296 * Output interrupt handler. 297 */ 298 accxint(unit) 299 int unit; 300 { 301 register struct acc_softc *sc = &acc_softc[unit]; 302 register struct accdevice *addr; 303 304 addr = (struct accdevice *)accinfo[unit]->ui_addr; 305 if (sc->acc_imp->imp_cb.ic_oactive == 0) { 306 printf("acc%d: stray xmit interrupt, csr=%b\n", unit, 307 addr->ocsr, ACC_OUTBITS); 308 return; 309 } 310 sc->acc_imp->imp_if.if_opackets++; 311 sc->acc_imp->imp_cb.ic_oactive = 0; 312 if (addr->ocsr & ACC_ERR) { 313 printf("acc%d: output error, ocsr=%b, icsr=%b\n", unit, 314 addr->ocsr, ACC_OUTBITS, addr->icsr, ACC_INBITS); 315 sc->acc_imp->imp_if.if_oerrors++; 316 } 317 if (sc->acc_ifuba.ifu_xtofree) { 318 m_freem(sc->acc_ifuba.ifu_xtofree); 319 sc->acc_ifuba.ifu_xtofree = 0; 320 } 321 impstart(sc->acc_imp); 322 } 323 324 /* 325 * Input interrupt handler 326 */ 327 accrint(unit) 328 int unit; 329 { 330 register struct acc_softc *sc = &acc_softc[unit]; 331 register struct accdevice *addr; 332 struct mbuf *m; 333 int len, info; 334 335 addr = (struct accdevice *)accinfo[unit]->ui_addr; 336 sc->acc_imp->imp_if.if_ipackets++; 337 338 /* 339 * Purge BDP; flush message if error indicated. 340 */ 341 if (sc->acc_ifuba.ifu_flags & UBA_NEEDBDP) 342 UBAPURGE(sc->acc_ifuba.ifu_uba, sc->acc_ifuba.ifu_r.ifrw_bdp); 343 if (addr->icsr & ACC_ERR) { 344 printf("acc%d: input error, csr=%b\n", unit, 345 addr->icsr, ACC_INBITS); 346 sc->acc_imp->imp_if.if_ierrors++; 347 sc->acc_flush = 1; 348 } 349 350 if (sc->acc_flush) { 351 if (addr->icsr & IN_EOM) 352 sc->acc_flush = 0; 353 goto setup; 354 } 355 len = IMP_RCVBUF + (addr->iwc << 1); 356 if (len < 0 || len > IMP_RCVBUF) { 357 printf("acc%d: bad length=%d\n", unit, len); 358 sc->acc_imp->imp_if.if_ierrors++; 359 goto setup; 360 } 361 362 /* 363 * The offset parameter is always 0 since using 364 * trailers on the ARPAnet is insane. 365 */ 366 m = if_rubaget(&sc->acc_ifuba, len, 0, &sc->acc_imp->imp_if); 367 if (m == 0) 368 goto setup; 369 if ((addr->icsr & IN_EOM) == 0) { 370 if (sc->acc_iq) 371 m_cat(sc->acc_iq, m); 372 else 373 sc->acc_iq = m; 374 goto setup; 375 } 376 if (sc->acc_iq) { 377 m_cat(sc->acc_iq, m); 378 m = sc->acc_iq; 379 sc->acc_iq = 0; 380 } 381 impinput(unit, m); 382 383 setup: 384 /* 385 * Setup for next message. 386 */ 387 info = sc->acc_ifuba.ifu_r.ifrw_info; 388 addr->iba = (u_short)info; 389 addr->iwc = -((IMP_RCVBUF)>> 1); 390 addr->icsr = 391 IN_MRDY | ACC_IE | IN_WEN | ((info & 0x30000) >> 12) | ACC_GO; 392 } 393 #endif 394