1 /* if_en.c 4.14 81/11/26 */ 2 3 #include "en.h" 4 /* 5 * Ethernet interface driver 6 */ 7 8 #include "../h/param.h" 9 #include "../h/systm.h" 10 #include "../h/mbuf.h" 11 #include "../h/pte.h" 12 #include "../h/buf.h" 13 #include "../h/protosw.h" 14 #include "../h/socket.h" 15 #include "../h/ubareg.h" 16 #include "../h/ubavar.h" 17 #include "../h/enreg.h" 18 #include "../h/cpu.h" 19 #include "../h/mtpr.h" 20 #include "../h/vmmac.h" 21 #include "../net/in.h" 22 #include "../net/in_systm.h" 23 #include "../net/if.h" 24 #include "../net/if_en.h" 25 #include "../net/if_uba.h" 26 #include "../net/ip.h" 27 #include "../net/ip_var.h" 28 29 #define ENMTU 1024 30 31 int enprobe(), enattach(), enrint(), enxint(), encollide(); 32 struct uba_device *eninfo[NEN]; 33 u_short enstd[] = { 0 }; 34 struct uba_driver endriver = 35 { enprobe, 0, enattach, 0, enstd, "es", eninfo }; 36 #define ENUNIT(x) minor(x) 37 38 struct en_softc { 39 struct ifnet *es_if; 40 struct ifuba *es_ifuba; 41 short es_delay; 42 short es_mask; 43 u_char es_addr; 44 u_char es_lastx; 45 short es_oactive; 46 short es_olen; 47 } en_softc[NEN]; 48 49 enprobe(reg) 50 caddr_t reg; 51 { 52 register int br, cvec; 53 register struct endevice *addr = (struct endevice *)reg; 54 55 COUNT(ENPROBE); 56 #ifdef lint 57 br = 0; cvec = br; br = cvec; 58 enrint(0); enxint(0); encollide(0); 59 #endif 60 addr->en_istat = 0; 61 addr->en_owc = -1; 62 addr->en_oba = 0; 63 addr->en_ostat = EN_IEN|EN_GO; 64 DELAY(100000); 65 addr->en_ostat = 0; 66 return (1); 67 } 68 69 /*ARGSUSED*/ 70 enattach(ui) 71 struct uba_device *ui; 72 { 73 74 COUNT(ENATTACH); 75 eninit(ui->ui_unit); 76 /* net initialization, based on ui->ui_flags?!? */ 77 } 78 79 eninit(unit) 80 int unit; 81 { 82 register struct uba_device *ui; 83 register struct endevice *addr; 84 register struct en_softc *es; 85 86 COUNT(ENINIT); 87 if (unit >= NEN || (ui = eninfo[unit]) == 0 || ui->ui_alive == 0) { 88 printf("es%d: not alive\n", unit); 89 return; 90 } 91 es = &en_softc[unit]; 92 if (if_ubainit(es->es_ifuba, ui->ui_ubanum, 93 sizeof (struct en_header), btop(ENMTU)) == 0) { 94 printf("es%d: can't initialize\n", unit); 95 return; 96 } 97 addr = (struct endevice *)ui->ui_addr; 98 addr->en_istat = addr->en_ostat = 0; 99 } 100 101 enreset(uban) 102 int uban; 103 { 104 register int unit; 105 struct uba_device *ui; 106 107 COUNT(ENRESET); 108 for (unit = 0; unit < NEN; unit++) { 109 ui = eninfo[unit]; 110 if (ui == 0 || ui->ui_ubanum != uban || ui->ui_alive == 0) 111 continue; 112 eninit(unit); 113 printf("es%d ", unit); 114 } 115 } 116 117 int enlastdel = 25; 118 119 enstart(dev) 120 dev_t dev; 121 { 122 int unit; 123 struct uba_device *ui; 124 register struct endevice *addr; 125 register struct en_softc *es; 126 register struct ifuba *ifu; 127 struct mbuf *m; 128 int dest; 129 COUNT(ENSTART); 130 131 unit = ENUNIT(dev); 132 ui = eninfo[unit]; 133 es = &en_softc[unit]; 134 if (es->es_oactive) 135 goto restart; 136 IF_DEQUEUE(&es->es_if->if_snd, m); 137 if (m == 0) { 138 es->es_oactive = 0; 139 return; 140 } 141 dest = mtod(m, struct en_header *)->en_dhost; 142 es->es_olen = if_wubaput(&es->es_ifuba, m); 143 if (es->es_lastx && es->es_lastx == dest) 144 es->es_delay = enlastdel; 145 else 146 es->es_lastx = dest; 147 restart: 148 ifu = es->es_ifuba; 149 UBAPURGE(ifu->ifu_uba, ifu->ifu_w.ifrw_bdp); 150 addr = (struct endevice *)ui->ui_addr; 151 addr->en_oba = (int)ifu->ifu_w.ifrw_addr; 152 addr->en_odelay = es->es_delay; 153 addr->en_owc = -((es->es_olen + 1) >> 1); 154 addr->en_ostat = EN_IEN|EN_GO; 155 es->es_oactive = 1; 156 } 157 158 enxint(unit) 159 int unit; 160 { 161 register struct endevice *addr; 162 register struct uba_device *ui; 163 register struct en_softc *es; 164 COUNT(ENXINT); 165 166 ui = eninfo[unit]; 167 es = &en_softc[unit]; 168 if (es->es_oactive == 0) 169 return; 170 addr = (struct endevice *)ui->ui_addr; 171 es = &en_softc[unit]; 172 es->es_oactive = 0; 173 es->es_delay = 0; 174 es->es_mask = ~0; 175 if (addr->en_ostat&EN_OERROR) 176 printf("es%d: output error\n", unit); 177 if (es->es_if->if_snd.ifq_head == 0) { 178 es->es_lastx = 0; 179 return; 180 } 181 enstart(unit); 182 } 183 184 encollide(unit) 185 int unit; 186 { 187 register struct en_softc *es; 188 COUNT(ENCOLLIDE); 189 190 es = &en_softc[unit]; 191 es->es_if->if_collisions++; 192 if (es->es_oactive == 0) 193 return; 194 if (es->es_mask == 0) { 195 printf("es%d: send error\n", unit); 196 enxint(unit); 197 } else { 198 es->es_mask <<= 1; 199 es->es_delay = mfpr(ICR) &~ es->es_mask; 200 enstart(unit); 201 } 202 } 203 204 enrint(unit) 205 int unit; 206 { 207 struct endevice *addr; 208 register struct en_softc *es; 209 register struct ifuba *ifu; 210 struct en_header *en; 211 struct mbuf *m; 212 struct ifqueue *inq; 213 register int len; 214 int off; 215 COUNT(ENRINT); 216 217 addr = (struct endevice *)eninfo[unit]->ui_addr; 218 if (addr->en_istat&EN_IERROR) { 219 es->es_if->if_ierrors++; 220 printf("es%d: input error\n", unit); 221 goto setup; 222 } 223 ifu = en_softc[unit].es_ifuba; 224 UBAPURGE(ifu->ifu_uba, ifu->ifu_r.ifrw_bdp); 225 en = (struct en_header *)(ifu->ifu_r.ifrw_addr); 226 #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 227 if (en->en_type >= ENPUP_TRAIL && 228 en->en_type < ENPUP_TRAIL+ENPUP_NTRAILER) { 229 off = (en->en_type - ENPUP_TRAIL) * 512; 230 en->en_type = *endataaddr(en, off, u_short *); 231 off += 2; 232 } else 233 off = 0; 234 switch (en->en_type) { 235 236 #ifdef INET 237 case ENPUP_IPTYPE: 238 len = endataaddr(en, off, struct ip *)->ip_len; 239 setipintr(); 240 inq = &ipintrq; 241 break; 242 #endif 243 244 default: 245 printf("en%d: unknow pkt type 0x%x\n", en->en_type); 246 goto setup; 247 } 248 if (len == 0) 249 goto setup; 250 m = if_rubaget(&ifu->ifu_r, len, off); 251 IF_ENQUEUE(inq, m); 252 setup: 253 addr->en_iba = es->es_ifuba->ifu_r.ifrw_info; 254 addr->en_iwc = -(sizeof (struct en_header) + ENMTU) >> 1; 255 addr->en_istat = EN_IEN|EN_GO; 256 } 257 258 /* 259 * Ethernet output routine. 260 * Encapsulate a packet of type family for the local net. 261 */ 262 enoutput(ifp, m0, pf) 263 struct ifnet *ifp; 264 struct mbuf *m0; 265 int pf; 266 { 267 int type, dest; 268 register struct mbuf *m; 269 register struct en_header *en; 270 int s; 271 272 switch (pf) { 273 274 #ifdef INET 275 case PF_INET: { 276 register struct ip *ip = mtod(m0, struct ip *); 277 int off; 278 279 off = ip->ip_len - (ip->ip_hl << 2); 280 if (off && off % 512 == 0 && m0->m_off >= MMINOFF + 2) { 281 type = ENPUP_TRAIL + (off>>9); 282 m0->m_off -= 2; 283 m0->m_len += 2; 284 *mtod(m0, u_short *) = ENPUP_IPTYPE; 285 } else { 286 type = ENPUP_IPTYPE; 287 off = 0; 288 } 289 dest = ip->ip_dst.s_addr >> 24; 290 } 291 break; 292 #endif 293 294 default: 295 printf("en%d: can't encapsulate pf%d\n", ifp->if_unit, pf); 296 m_freem(m0); 297 return (0); 298 } 299 if (MMINOFF + sizeof (struct en_header) > m0->m_off) { 300 m = m_get(0); 301 if (m == 0) { 302 m_freem(m0); 303 return (0); 304 } 305 m->m_next = m0; 306 m->m_off = MMINOFF; 307 m->m_len = sizeof (struct en_header); 308 } else { 309 m = m0; 310 m->m_off -= sizeof (struct en_header); 311 m->m_len += sizeof (struct en_header); 312 } 313 en = mtod(m, struct en_header *); 314 en->en_shost = ifp->if_host[0]; 315 en->en_dhost = dest; 316 en->en_type = type; 317 s = splimp(); 318 IF_ENQUEUE(&ifp->if_snd, m); 319 splx(s); 320 if (en_softc[ifp->if_unit].es_oactive == 0) 321 enstart(ifp->if_unit); 322 } 323