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