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