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