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