working driver
[unix-history] / usr / src / sys / tahoe / if / if_enp.c
CommitLineData
7779e59b 1/* if_enp.c 1.5 87/04/29 */
6013a59e
SL
2
3#include "enp.h"
6013a59e 4#if NENP > 0
6013a59e 5/*
7779e59b 6 * CMC ENP-20 Ethernet Controller.
6013a59e 7 */
6013a59e
SL
8#include "param.h"
9#include "systm.h"
10#include "mbuf.h"
11#include "buf.h"
12#include "protosw.h"
13#include "socket.h"
14#include "vmmac.h"
bc2cef1e 15#include "ioctl.h"
6013a59e 16#include "errno.h"
bc2cef1e
SL
17#include "vmparam.h"
18#include "syslog.h"
6013a59e
SL
19#include "uio.h"
20
21#include "../net/if.h"
22#include "../net/netisr.h"
23#include "../net/route.h"
bc2cef1e 24#ifdef INET
6013a59e 25#include "../netinet/in.h"
6013a59e 26#include "../netinet/in_systm.h"
bc2cef1e 27#include "../netinet/in_var.h"
6013a59e
SL
28#include "../netinet/ip.h"
29#include "../netinet/ip_var.h"
30#include "../netinet/if_ether.h"
bc2cef1e
SL
31#endif
32#ifdef NS
33#include "../netns/ns.h"
34#include "../netns/ns_if.h"
35#endif
36
37#include "../tahoe/cpu.h"
38#include "../tahoe/pte.h"
39#include "../tahoe/mtpr.h"
6013a59e
SL
40
41#include "../tahoevba/vbavar.h"
bc2cef1e 42#include "../tahoeif/if_enpreg.h"
6013a59e 43
bc2cef1e
SL
44#define ENPSTART 0xf02000 /* standard enp start addr */
45#define ENPUNIT(dev) (minor(dev)) /* for enp ram devices */
7779e59b
SL
46/* macros for dealing with longs in i/o space */
47#define ENPGETLONG(a) ((((u_short *)(a))[0] << 16)|(((u_short *)(a))[1]))
48#define ENPSETLONG(a,v) \
49 { register u_short *wp = (u_short *)(a); \
50 wp[0] = ((u_short *)&(v))[0]; wp[1] = ((u_short *)&(v))[1];}
6013a59e
SL
51
52int enpprobe(), enpattach(), enpintr();
fea301bf 53long enpstd[] = { 0xfff41000, 0xfff61000, 0 };
bc2cef1e 54struct vba_device *enpinfo[NENP];
6013a59e 55struct vba_driver enpdriver =
bc2cef1e 56 { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 };
6013a59e 57
bc2cef1e 58int enpinit(), enpioctl(), enpreset(), enpoutput();
6013a59e
SL
59struct mbuf *enpget();
60
6013a59e
SL
61/*
62 * Ethernet software status per interface.
63 *
64 * Each interface is referenced by a network interface structure,
65 * es_if, which the routing code uses to locate the interface.
66 * This structure contains the output queue for the interface, its address, ...
67 */
bc2cef1e
SL
68struct enp_softc {
69 struct arpcom es_ac; /* common ethernet structures */
70#define es_if es_ac.ac_if
7779e59b 71#define es_addr es_ac.ac_enaddr
bc2cef1e 72 short es_ivec; /* interrupt vector */
bc2cef1e
SL
73} enp_softc[NENP];
74extern struct ifnet loif;
75
76enpprobe(reg, vi)
77 caddr_t reg;
78 struct vba_device *vi;
6013a59e 79{
bc2cef1e
SL
80 register br, cvec; /* must be r12, r11 */
81 register struct enpdevice *addr = (struct enpdevice *)reg;
82 struct enp_softc *es = &enp_softc[vi->ui_unit];
6013a59e 83
bc2cef1e 84#ifdef lint
9d61b7ff 85 br = 0; cvec = br; br = cvec;
bc2cef1e
SL
86 enpintr(0);
87#endif
9d61b7ff 88 if (badaddr((caddr_t)addr, 2) || badaddr((caddr_t)&addr->enp_ram[0], 2))
bc2cef1e
SL
89 return (0);
90 es->es_ivec = --vi->ui_hd->vh_lastiv;
91 addr->enp_state = S_ENPRESET; /* reset by VERSAbus reset */
92 br = 0x14, cvec = es->es_ivec; /* XXX */
93 return (sizeof (struct enpdevice));
6013a59e
SL
94}
95
96/*
97 * Interface exists: make available by filling in network interface
98 * record. System will initialize the interface when it is ready
99 * to accept packets.
100 */
bc2cef1e
SL
101enpattach(ui)
102 register struct vba_device *ui;
6013a59e 103{
bc2cef1e
SL
104 struct enp_softc *es = &enp_softc[ui->ui_unit];
105 register struct ifnet *ifp = &es->es_if;
6013a59e 106
bc2cef1e 107 ifp->if_unit = ui->ui_unit;
6013a59e
SL
108 ifp->if_name = "enp";
109 ifp->if_mtu = ETHERMTU;
6013a59e
SL
110 ifp->if_init = enpinit;
111 ifp->if_ioctl = enpioctl;
112 ifp->if_output = enpoutput;
113 ifp->if_reset = enpreset;
bc2cef1e 114 ifp->if_flags = IFF_BROADCAST;
6013a59e
SL
115 if_attach(ifp);
116}
117
6013a59e 118/*
bc2cef1e 119 * Reset of interface after "system" reset.
6013a59e 120 */
bc2cef1e
SL
121enpreset(unit, vban)
122 int unit, vban;
6013a59e 123{
bc2cef1e 124 register struct vba_device *ui;
6013a59e 125
bc2cef1e
SL
126 if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
127 ui->ui_vbanum != vban)
128 return;
129 printf(" enp%d", unit);
6013a59e
SL
130 enpinit(unit);
131}
132
133/*
bc2cef1e 134 * Initialization of interface; clear recorded pending operations.
6013a59e 135 */
bc2cef1e
SL
136enpinit(unit)
137 int unit;
6013a59e 138{
bc2cef1e
SL
139 struct enp_softc *es = &enp_softc[unit];
140 register struct vba_device *ui = enpinfo[unit];
141 struct enpdevice *addr;
142 register struct ifnet *ifp = &es->es_if;
143 int s;
6013a59e 144
bc2cef1e
SL
145 if (ifp->if_addrlist == (struct ifaddr *)0)
146 return;
147 if ((ifp->if_flags & IFF_RUNNING) == 0) {
148 addr = (struct enpdevice *)ui->ui_addr;
149 s = splimp();
150 RESET_ENP(addr);
151 DELAY(200000);
bc2cef1e
SL
152 es->es_if.if_flags |= IFF_RUNNING;
153 splx(s);
154 }
6013a59e
SL
155}
156
6013a59e
SL
157/*
158 * Ethernet interface interrupt.
159 */
bc2cef1e
SL
160enpintr(unit)
161 int unit;
6013a59e 162{
bc2cef1e
SL
163 register struct enpdevice *addr;
164 register BCB *bcbp;
6013a59e 165
bc2cef1e 166 addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
9d61b7ff 167#if ENP == 30
bc2cef1e 168 if (!IS_ENP_INTR(addr))
6013a59e 169 return;
bc2cef1e 170 ACK_ENP_INTR(addr);
9d61b7ff
SL
171#endif
172 while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) {
173 (void) enpread(&enp_softc[unit], bcbp);
174 (void) ringput((RING *)&addr->enp_enpfree, bcbp);
6013a59e 175 }
6013a59e
SL
176}
177
178/*
179 * Read input packet, examine its packet type, and enqueue it.
180 */
9d61b7ff 181enpread(es, bcbp)
bc2cef1e
SL
182 struct enp_softc *es;
183 register BCB *bcbp;
6013a59e
SL
184{
185 register struct ether_header *enp;
186 struct mbuf *m;
9d61b7ff 187 int s, len, off, resid;
6013a59e
SL
188 register struct ifqueue *inq;
189
190 es->es_if.if_ipackets++;
6013a59e
SL
191 /*
192 * Get input data length.
193 * Get pointer to ethernet header (in input buffer).
194 * Deal with trailer protocol: if type is PUP trailer
195 * get true type from first 16-bit word past data.
196 * Remember that type was trailer by setting off.
197 */
bc2cef1e 198 len = bcbp->b_msglen - sizeof (struct ether_header);
7779e59b 199 enp = (struct ether_header *)ENPGETLONG(&bcbp->b_addr);
bc2cef1e
SL
200#define enpdataaddr(enp, off, type) \
201 ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off))))
202 enp->ether_type = ntohs((u_short)enp->ether_type);
203 if (enp->ether_type >= ETHERTYPE_TRAIL &&
204 enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
205 off = (enp->ether_type - ETHERTYPE_TRAIL) * 512;
206 if (off >= ETHERMTU)
207 goto setup;
208 enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *));
209 resid = ntohs(*(enpdataaddr(enp, off+2, u_short *)));
210 if (off + resid > len)
211 goto setup;
6013a59e 212 len = off + resid;
bc2cef1e 213 } else
6013a59e 214 off = 0;
bc2cef1e
SL
215 if (len == 0)
216 goto setup;
6013a59e 217
6013a59e
SL
218 /*
219 * Pull packet off interface. Off is nonzero if packet
220 * has trailing header; enpget will then force this header
221 * information to be at the front, but we still have to drop
222 * the type and length which are at the front of any trailer data.
223 */
7779e59b 224 m = enpget((u_char *)enp, len, off, &es->es_if);
bc2cef1e
SL
225 if (m == 0)
226 goto setup;
227 if (off) {
228 struct ifnet *ifp;
6013a59e 229
bc2cef1e 230 ifp = *(mtod(m, struct ifnet **));
6013a59e
SL
231 m->m_off += 2 * sizeof (u_short);
232 m->m_len -= 2 * sizeof (u_short);
bc2cef1e 233 *(mtod(m, struct ifnet **)) = ifp;
6013a59e 234 }
bc2cef1e 235 switch (enp->ether_type) {
6013a59e 236
6013a59e 237#ifdef INET
bc2cef1e 238 case ETHERTYPE_IP:
6013a59e
SL
239 schednetisr(NETISR_IP);
240 inq = &ipintrq;
241 break;
bc2cef1e
SL
242#endif
243 case ETHERTYPE_ARP:
6013a59e 244 arpinput(&es->es_ac, m);
bc2cef1e
SL
245 goto setup;
246
247#ifdef NS
248 case ETHERTYPE_NS:
249 schednetisr(NETISR_NS);
250 inq = &nsintrq;
251 break;
6013a59e 252#endif
bc2cef1e 253 default:
6013a59e 254 m_freem(m);
bc2cef1e 255 goto setup;
6013a59e 256 }
bc2cef1e 257 if (IF_QFULL(inq)) {
6013a59e
SL
258 IF_DROP(inq);
259 m_freem(m);
bc2cef1e 260 goto setup;
6013a59e
SL
261 }
262 s = splimp();
263 IF_ENQUEUE(inq, m);
264 splx(s);
bc2cef1e
SL
265setup:
266 return (0);
6013a59e
SL
267}
268
269/*
270 * Ethernet output routine. (called by user)
271 * Encapsulate a packet of type family for the local net.
272 * Use trailer local net encapsulation if enough data in first
273 * packet leaves a multiple of 512 bytes of data in remainder.
274 * If destination is this address or broadcast, send packet to
275 * loop device to kludge around the fact that 3com interfaces can't
276 * talk to themselves.
277 */
6013a59e 278enpoutput(ifp, m0, dst)
bc2cef1e
SL
279 struct ifnet *ifp;
280 struct mbuf *m0;
281 struct sockaddr *dst;
6013a59e 282{
6013a59e
SL
283 register struct enp_softc *es = &enp_softc[ifp->if_unit];
284 register struct mbuf *m = m0;
285 register struct ether_header *enp;
9d61b7ff 286 register int off;
bc2cef1e
SL
287 struct mbuf *mcopy = (struct mbuf *)0;
288 int type, s, error, usetrailers;
289 u_char edst[6];
290 struct in_addr idst;
6013a59e 291
bc2cef1e
SL
292 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
293 error = ENETDOWN;
294 goto bad;
295 }
296 switch (dst->sa_family) {
6013a59e
SL
297#ifdef INET
298 case AF_INET:
299 idst = ((struct sockaddr_in *)dst)->sin_addr;
bc2cef1e
SL
300 if (!arpresolve(&es->es_ac, m, &idst, edst, &usetrailers))
301 return (0); /* if not yet resolved */
302 if (!bcmp((caddr_t)edst, (caddr_t)etherbroadcastaddr,
303 sizeof (edst)))
304 mcopy = m_copy(m, 0, (int)M_COPYALL);
305 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
306 if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
307 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
308 type = ETHERTYPE_TRAIL + (off>>9);
309 m->m_off -= 2 * sizeof (u_short);
310 m->m_len += 2 * sizeof (u_short);
7779e59b
SL
311 *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
312 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
bc2cef1e 313 goto gottrailertype;
6013a59e 314 }
bc2cef1e 315 type = ETHERTYPE_IP;
6013a59e
SL
316 off = 0;
317 goto gottype;
318#endif
bc2cef1e
SL
319#ifdef NS
320 case AF_NS:
321 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
322 (caddr_t)edst, sizeof (edst));
323 if (!bcmp((caddr_t)edst, (caddr_t)&ns_broadhost, sizeof (edst)))
324 mcopy = m_copy(m, 0, (int)M_COPYALL);
325 else if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost,
326 sizeof (edst)))
327 return (looutput(&loif, m, dst));
328 type = ETHERTYPE_NS;
329 off = 0;
330 goto gottype;
6013a59e 331#endif
6013a59e
SL
332 case AF_UNSPEC:
333 enp = (struct ether_header *)dst->sa_data;
bc2cef1e 334 bcopy((caddr_t)enp->ether_dhost, (caddr_t)edst, sizeof (edst));
6013a59e
SL
335 type = enp->ether_type;
336 goto gottype;
337
338 default:
bc2cef1e
SL
339 log(LOG_ERR, "enp%d: can't handle af%d\n",
340 ifp->if_unit, dst->sa_family);
6013a59e
SL
341 error = EAFNOSUPPORT;
342 goto bad;
343 }
344
345gottrailertype:
346 /*
347 * Packet to be sent as trailer: move first packet
348 * (control information) to end of chain.
349 */
350 while (m->m_next)
351 m = m->m_next;
352 m->m_next = m0;
353 m = m0->m_next;
354 m0->m_next = 0;
355 m0 = m;
356
357gottype:
358 /*
359 * Add local net header. If no space in first mbuf,
360 * allocate another.
361 */
362 if (m->m_off > MMAXOFF ||
bc2cef1e 363 MMINOFF + sizeof (struct ether_header) > m->m_off) {
6013a59e 364 m = m_get(M_DONTWAIT, MT_HEADER);
bc2cef1e 365 if (m == 0) {
6013a59e
SL
366 error = ENOBUFS;
367 goto bad;
368 }
369 m->m_next = m0;
370 m->m_off = MMINOFF;
bc2cef1e
SL
371 m->m_len = sizeof (struct ether_header);
372 } else {
373 m->m_off -= sizeof (struct ether_header);
374 m->m_len += sizeof (struct ether_header);
6013a59e
SL
375 }
376 enp = mtod(m, struct ether_header *);
bc2cef1e 377 bcopy((caddr_t)edst, (caddr_t)enp->ether_dhost, sizeof (edst));
7779e59b
SL
378 bcopy((caddr_t)es->es_addr, (caddr_t)enp->ether_shost,
379 sizeof (es->es_addr));
bc2cef1e 380 enp->ether_type = htons((u_short)type);
6013a59e
SL
381
382 /*
383 * Queue message on interface if possible
384 */
6013a59e 385 s = splimp();
bc2cef1e 386 if (enpput(ifp->if_unit, m)) {
6013a59e 387 error = ENOBUFS;
6013a59e
SL
388 goto qfull;
389 }
bc2cef1e 390 splx(s);
6013a59e 391 es->es_if.if_opackets++;
bc2cef1e 392 return (mcopy ? looutput(&loif, mcopy, dst) : 0);
6013a59e 393qfull:
bc2cef1e 394 splx(s);
6013a59e
SL
395 m0 = m;
396bad:
397 m_freem(m0);
bc2cef1e
SL
398 if (mcopy)
399 m_freem(mcopy);
400 return (error);
6013a59e
SL
401}
402
403/*
bc2cef1e 404 * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus.
6013a59e 405 */
bc2cef1e
SL
406enpput(unit, m)
407 int unit;
408 struct mbuf *m;
6013a59e
SL
409{
410 register BCB *bcbp;
bc2cef1e 411 register struct enpdevice *addr;
6013a59e
SL
412 register struct mbuf *mp;
413 register u_char *bp;
bc2cef1e
SL
414 register u_int len;
415 u_char *mcp;
6013a59e 416
bc2cef1e 417 addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
9d61b7ff 418 if (ringempty((RING *)&addr->enp_hostfree))
bc2cef1e 419 return (1);
9d61b7ff 420 bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree);
6013a59e 421 bcbp->b_len = 0;
7779e59b 422 bp = (u_char *)ENPGETLONG(&bcbp->b_addr);
bc2cef1e 423 for (mp = m; mp; mp = mp->m_next) {
6013a59e 424 len = mp->m_len;
bc2cef1e 425 if (len == 0)
6013a59e 426 continue;
bc2cef1e
SL
427 mcp = mtod(mp, u_char *);
428 enpcopy(mcp, bp, len);
6013a59e
SL
429 bp += len;
430 bcbp->b_len += len;
431 }
7779e59b 432 bcbp->b_len = MAX(ETHERMIN+sizeof (struct ether_header), bcbp->b_len);
6013a59e 433 bcbp->b_reserved = 0;
9d61b7ff 434 if (ringput((RING *)&addr->enp_toenp, bcbp) == 1)
bc2cef1e 435 INTR_ENP(addr);
6013a59e 436 m_freem(m);
bc2cef1e 437 return (0);
6013a59e
SL
438}
439
440/*
bc2cef1e 441 * Routine to copy from VERSAbus memory into mbufs.
6013a59e
SL
442 *
443 * Warning: This makes the fairly safe assumption that
444 * mbufs have even lengths.
445 */
446struct mbuf *
bc2cef1e
SL
447enpget(rxbuf, totlen, off0, ifp)
448 u_char *rxbuf;
449 int totlen, off0;
450 struct ifnet *ifp;
6013a59e 451{
bc2cef1e 452 register u_char *cp, *mcp;
6013a59e 453 register struct mbuf *m;
bc2cef1e
SL
454 struct mbuf *top = 0, **mp = &top;
455 int len, off = off0;
6013a59e 456
bc2cef1e
SL
457 cp = rxbuf + sizeof (struct ether_header);
458 while (totlen > 0) {
6013a59e
SL
459 MGET(m, M_DONTWAIT, MT_DATA);
460 if (m == 0)
461 goto bad;
bc2cef1e 462 if (off) {
6013a59e 463 len = totlen - off;
bc2cef1e
SL
464 cp = rxbuf + sizeof (struct ether_header) + off;
465 } else
6013a59e 466 len = totlen;
bc2cef1e 467 if (len >= NBPG) {
bc2cef1e
SL
468 MCLGET(m);
469 if (m->m_len == CLBYTES)
470 m->m_len = len = MIN(len, CLBYTES);
471 else
6013a59e 472 m->m_len = len = MIN(MLEN, len);
bc2cef1e 473 } else {
6013a59e
SL
474 m->m_len = len = MIN(MLEN, len);
475 m->m_off = MMINOFF;
476 }
6013a59e 477 mcp = mtod(m, u_char *);
bc2cef1e
SL
478 if (ifp) {
479 /*
480 * Prepend interface pointer to first mbuf.
481 */
482 *(mtod(m, struct ifnet **)) = ifp;
483 mcp += sizeof (ifp);
484 len -= sizeof (ifp);
485 ifp = (struct ifnet *)0;
486 }
9d61b7ff 487 enpcopy(cp, mcp, (u_int)len);
6013a59e
SL
488 cp += len;
489 *mp = m;
490 mp = &m->m_next;
bc2cef1e 491 if (off == 0) {
6013a59e
SL
492 totlen -= len;
493 continue;
494 }
495 off += len;
bc2cef1e
SL
496 if (off == totlen) {
497 cp = rxbuf + sizeof (struct ether_header);
6013a59e
SL
498 off = 0;
499 totlen = off0;
500 }
501 }
502 return (top);
503bad:
504 m_freem(top);
505 return (0);
506}
507
bc2cef1e 508enpcopy(from, to, cnt)
9d61b7ff
SL
509 register u_char *from, *to;
510 register u_int cnt;
bc2cef1e
SL
511{
512 register c;
513 register short *f, *t;
514
515 if (((int)from&01) && ((int)to&01)) {
516 /* source & dest at odd addresses */
517 *to++ = *from++;
518 --cnt;
519 }
520 if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) {
521 t = (short *)to;
522 f = (short *)from;
523 for (c = cnt>>1; c; --c) /* even address copy */
524 *t++ = *f++;
525 cnt &= 1;
526 if (cnt) { /* odd len */
9d61b7ff
SL
527 from = (u_char *)f;
528 to = (u_char *)t;
bc2cef1e
SL
529 *to = *from;
530 }
531 }
9d61b7ff 532 while ((int)cnt-- > 0) /* one of the address(es) must be odd */
bc2cef1e
SL
533 *to++ = *from++;
534}
535
6013a59e
SL
536/*
537 * Process an ioctl request.
6013a59e 538 */
6013a59e 539enpioctl(ifp, cmd, data)
bc2cef1e
SL
540 register struct ifnet *ifp;
541 int cmd;
542 caddr_t data;
6013a59e 543{
bc2cef1e
SL
544 register struct ifaddr *ifa = (struct ifaddr *)data;
545 struct enpdevice *addr;
546 int s = splimp(), error = 0;
6013a59e
SL
547
548 switch (cmd) {
549
550 case SIOCSIFADDR:
bc2cef1e
SL
551 ifp->if_flags |= IFF_UP;
552 switch (ifa->ifa_addr.sa_family) {
553#ifdef INET
554 case AF_INET:
555 enpinit(ifp->if_unit);
556 ((struct arpcom *)ifp)->ac_ipaddr =
557 IA_SIN(ifa)->sin_addr;
558 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
559 break;
560#endif
561#ifdef NS
562 case AF_NS: {
563 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
564 struct enp_softc *es = &enp_softc[ifp->if_unit];
565
566 if (!ns_nullhost(*ina)) {
567 ifp->if_flags &= ~IFF_RUNNING;
568 addr = (struct enpdevice *)
569 enpinfo[ifp->if_unit]->ui_addr;
570 enpsetaddr(ifp->if_unit, addr,
571 ina->x_host.c_host);
572 } else
7779e59b 573 ina->x_host = *(union ns_host *)es->es_addr;
bc2cef1e 574 enpinit(ifp->if_unit);
6013a59e
SL
575 break;
576 }
bc2cef1e
SL
577#endif
578 default:
579 enpinit(ifp->if_unit);
580 break;
6013a59e 581 }
6013a59e
SL
582 break;
583
bc2cef1e
SL
584 case SIOCSIFFLAGS:
585 if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) {
586 enpinit(ifp->if_unit); /* reset board */
587 ifp->if_flags &= ~IFF_RUNNING;
588 } else if (ifp->if_flags&IFF_UP &&
589 (ifp->if_flags&IFF_RUNNING) == 0)
590 enpinit(ifp->if_unit);
6013a59e
SL
591 break;
592
593 default:
594 error = EINVAL;
595 }
bc2cef1e
SL
596 splx(s);
597 return (error);
6013a59e
SL
598}
599
bc2cef1e
SL
600enpsetaddr(unit, addr, enaddr)
601 int unit;
602 struct enpdevice *addr;
603 u_char *enaddr;
6013a59e 604{
7779e59b
SL
605
606 enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr,
607 sizeof (struct ether_addr));
bc2cef1e 608 enpinit(unit);
7779e59b
SL
609 enpgetaddr(unit, addr);
610}
611
612enpgetaddr(unit, addr)
613 int unit;
614 struct enpdevice *addr;
615{
616 struct enp_softc *es = &enp_softc[unit];
617
618 enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr,
619 sizeof (struct ether_addr));
620 printf("enp%d: hardware address %s\n",
621 unit, ether_sprintf(es->es_addr));
6013a59e
SL
622}
623
624/*
bc2cef1e 625 * Routines to synchronize enp and host.
6013a59e 626 */
9d61b7ff 627#ifdef notdef
6013a59e 628static
bc2cef1e
SL
629ringinit(rp, size)
630 register RING *rp;
6013a59e 631{
6013a59e
SL
632
633 rp->r_rdidx = rp->r_wrtidx = 0;
634 rp->r_size = size;
635}
636
637static
9d61b7ff 638ringfull(rp)
bc2cef1e 639 register RING *rp;
6013a59e 640{
9d61b7ff 641 register short idx;
bc2cef1e 642
9d61b7ff
SL
643 idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
644 return (idx == rp->r_rdidx);
6013a59e
SL
645}
646
647static
9d61b7ff 648fir(rp)
bc2cef1e 649 register RING *rp;
6013a59e 650{
6013a59e 651
9d61b7ff
SL
652 return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0);
653}
654#endif
655
656static
657ringempty(rp)
658 register RING *rp;
659{
660
661 return (rp->r_rdidx == rp->r_wrtidx);
6013a59e
SL
662}
663
664static
bc2cef1e
SL
665ringput(rp, v)
666 register RING *rp;
9d61b7ff 667 BCB *v;
6013a59e
SL
668{
669 register int idx;
6013a59e
SL
670
671 idx = (rp->r_wrtidx + 1) & (rp->r_size-1);
bc2cef1e 672 if (idx != rp->r_rdidx) {
7779e59b 673 ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v);
6013a59e 674 rp->r_wrtidx = idx;
bc2cef1e 675 if ((idx -= rp->r_rdidx) < 0)
6013a59e 676 idx += rp->r_size;
bc2cef1e 677 return (idx); /* num ring entries */
6013a59e 678 }
bc2cef1e 679 return (0);
6013a59e
SL
680}
681
682static
bc2cef1e
SL
683ringget(rp)
684 register RING *rp;
6013a59e
SL
685{
686 register int i = 0;
bc2cef1e
SL
687
688 if (rp->r_rdidx != rp->r_wrtidx) {
7779e59b 689 i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]);
6013a59e
SL
690 rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1);
691 }
bc2cef1e 692 return (i);
6013a59e
SL
693}
694
bc2cef1e
SL
695/*
696 * ENP Ram device.
697 */
698enpr_open(dev)
699 dev_t dev;
6013a59e 700{
bc2cef1e
SL
701 register int unit = ENPUNIT(dev);
702 struct vba_device *ui;
703 struct enpdevice *addr;
6013a59e 704
bc2cef1e
SL
705 if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 ||
706 (addr = (struct enpdevice *)ui->ui_addr) == 0)
707 return (ENODEV);
708 if (addr->enp_state != S_ENPRESET)
709 return (EACCES); /* enp is not in reset state, don't open */
710 return (0);
6013a59e
SL
711}
712
9d61b7ff 713/*ARGSUSED*/
bc2cef1e
SL
714enpr_close(dev)
715 dev_t dev;
6013a59e 716{
6013a59e 717
bc2cef1e 718 return (0);
6013a59e
SL
719}
720
bc2cef1e
SL
721enpr_read(dev, uio)
722 dev_t dev;
723 register struct uio *uio;
6013a59e 724{
bc2cef1e
SL
725 register struct iovec *iov;
726 struct enpdevice *addr;
6013a59e 727
bc2cef1e
SL
728 if (uio->uio_offset > RAM_SIZE)
729 return (ENODEV);
9d61b7ff 730 iov = uio->uio_iov;
bc2cef1e
SL
731 if (uio->uio_offset + iov->iov_len > RAM_SIZE)
732 iov->iov_len = RAM_SIZE - uio->uio_offset;
733 addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
7779e59b
SL
734 if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0)
735 return (EFAULT);
9d61b7ff
SL
736 enpcopy((u_char *)&addr->enp_ram[uio->uio_offset],
737 (u_char *)iov->iov_base, (u_int)iov->iov_len);
bc2cef1e
SL
738 uio->uio_resid -= iov->iov_len;
739 iov->iov_len = 0;
740 return (0);
6013a59e
SL
741}
742
bc2cef1e
SL
743enpr_write(dev, uio)
744 dev_t dev;
745 register struct uio *uio;
746{
747 register struct enpdevice *addr;
748 register struct iovec *iov;
6013a59e 749
bc2cef1e
SL
750 addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr;
751 iov = uio->uio_iov;
752 if (uio->uio_offset > RAM_SIZE)
753 return (ENODEV);
754 if (uio->uio_offset + iov->iov_len > RAM_SIZE)
755 iov->iov_len = RAM_SIZE - uio->uio_offset;
7779e59b
SL
756 if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0)
757 return (EFAULT);
9d61b7ff
SL
758 enpcopy((u_char *)iov->iov_base,
759 (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len);
bc2cef1e
SL
760 uio->uio_resid -= iov->iov_len;
761 iov->iov_len = 0;
762 return (0);
763}
764
9d61b7ff 765/*ARGSUSED*/
bc2cef1e
SL
766enpr_ioctl(dev, cmd, data)
767 dev_t dev;
768 caddr_t data;
6013a59e 769{
bc2cef1e 770 register unit = ENPUNIT(dev);
7779e59b 771 struct enpdevice *addr;
6013a59e 772
bc2cef1e
SL
773 addr = (struct enpdevice *)enpinfo[unit]->ui_addr;
774 switch(cmd) {
775
776 case ENPIOGO:
7779e59b 777 ENPSETLONG(&addr->enp_base, addr);
bc2cef1e
SL
778 addr->enp_intrvec = enp_softc[unit].es_ivec;
779 ENP_GO(addr, ENPSTART);
780 DELAY(200000);
781 enpinit(unit);
7779e59b
SL
782 /*
783 * Fetch Ethernet address after link level
784 * is booted (firmware copies manufacturer's
785 * address from on-board ROM).
786 */
787 enpgetaddr(unit, addr);
788 addr->enp_state = S_ENPRUN;
bc2cef1e
SL
789 break;
790
791 case ENPIORESET:
792 RESET_ENP(addr);
7779e59b 793 addr->enp_state = S_ENPRESET;
bc2cef1e
SL
794 DELAY(100000);
795 break;
7779e59b
SL
796 default:
797 return (EINVAL);
6013a59e 798 }
bc2cef1e 799 return (0);
6013a59e
SL
800}
801#endif