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