if_pn.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:35k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* if_pn.c - proNET-80 network interface driver */
  2. /* Copyright 1984,1985,1986,1987,1988,1989 Wind River Systems, Inc. */
  3. extern char copyright_wind_river[]; static char *copyright=copyright_wind_river;
  4. static char sccsid[] = "@(#)if_pn.c 2.1 11/4/86 (c) 1986 Proteon, Inc.";
  5. /*
  6. modification history
  7. --------------------
  8. 01k,07aug89,gae  changed iv68k.h to iv.h.
  9. 01j,05sep88,gae  got rid of non-functional code.
  10. 01i,03sep88,gae  fixed bug with >2 pronets in ring.
  11. 01h,20aug88,gae  fixed wire-center/bootrom hang problem by disabling
  12.  interrupts in pnreset().  ifdef'd out DMA stuff.
  13.  got rid of gratuitous taskDelay() in pnoutput.
  14.  called pnprobe() in pnattach().
  15. 01g,12jul88,gae  merged in Carl Reed's fixes.  Lint.  Cleanup.
  16.  fixed pn_softc definition thanks to Phil Wiborg.
  17. 01f,07jul88,jcf  lint.
  18. 01e,30may88,dnw  changed to v4 names.
  19. 01d,10may88,llk  include ioLib.h for READ constants.
  20.  changed vxTdelay to taskDelay.
  21. 01c,08feb88,rdc  fixed several races and bugs.
  22. 01b,17nov87,dnw  changed pnattach to take int vec num instead of vec adrs.
  23. 01a,06nov87,rdc  written.
  24. */
  25. /*
  26. DESCRIPTION
  27. ProNET device driver for proNET VMEbus interfaces (p1500 and p1580).
  28. The only user callable routine is:
  29.    pnattach (unit, addr, ivec, ilevel)
  30. BUGS
  31. Only one 'unit' allowed; proNet-80 (not proNet-10) is hard-coded.
  32. */
  33. #include "vxWorks.h"
  34. #include "iv.h"
  35. #include "ioLib.h"
  36. #include "ioctl.h"
  37. #include "memLib.h"
  38. #include "etherLib.h"
  39. #include "param.h"
  40. #include "mbuf.h"
  41. #include "protosw.h"
  42. #include "socket.h"
  43. #include "errno.h"
  44. #include "if.h"
  45. #include "route.h"
  46. #ifdef INET
  47. #include "in.h"
  48. #include "in_systm.h"
  49. #include "in_var.h"
  50. #include "ip.h"
  51. #endif INET
  52. #include "if_pn.h"
  53. #include "if_ether.h"
  54. IMPORT VOID ipintr ();
  55. #define NPN 1 /* maximum number of proNET boards */
  56. #define IS_80 TRUE /* TRUE=proNET-80, FALSE=proNET-10 */
  57. /**************************************************************************/
  58. /*    maximum transmission unit defined --                                */
  59. /*        you can set PNMTU at anything from 576 on up, so long as you    */
  60. /*        recongnize the weaknesses of 4.2BSD in assumuing too much about */
  61. /*        the MTU of other TCP/IP implementations. Thus 576 is the most   */
  62. /*        "compatible" value. 1536 is a popular "large" value, because    */
  63. /*        it is a multiple of 512, which the trailer scheme liked.        */
  64. /*        The absolute maximum size is 4096, which is enforced.           */
  65. /**************************************************************************/
  66. /* Adjust the next line for desired MTU (576 <= PNMTU).
  67.  * Acceptable values are 576, 1024, 1536, 2048, 2560, 3072, 3584, 4096
  68.  */
  69. #define PNMTU 4096
  70. /* Do not to touch the next group of lines.
  71.  * They check the value and set other constants based on it.
  72.  */
  73. #if PNMTU>4096
  74. #undef PNMTU
  75. #define PNMTU 4096
  76. #endif PNMTU>4096
  77. #define PNMRU (PNMTU + 16)
  78. #define PNBUFSIZE (PNMRU + sizeof(struct pn_header))
  79. #define PNCMDSIZE 4096
  80. /* end of don't touch */
  81. /**************************************************************************/
  82. /*   debugging and tracing stuff                                          */
  83. /**************************************************************************/
  84. int pn_tracehdr  = FALSE; /* TRUE => trace headers (slowly!!) */
  85. int pn_logerrors = FALSE; /* TRUE => log all I/O errors */
  86. #define pntracehdr  if (pn_tracehdr) pnprt_hdr
  87. #define pnprintf    if (pn_logerrors) logMsg
  88. BOOL pn_copy = FALSE;
  89. /* XXX most boards won't allow long word transfers on 'just' even boundaries */
  90. #define pncopy(x,y,l) (pn_copy ? bcopy(x,y,l) : bcopyBytes(x,y,l))
  91. LOCAL u_short pn_modes[] = /* three operating modes */
  92.     {
  93.     PN_RST, /* digital loopback */
  94.     PN_MEN, /* analog loopback */
  95.     PN_JNR|PN_MEN /* network mode */
  96.     };
  97. /**************************************************************************/
  98. /* Software status of each interface.                                     */
  99. /*                                                                        */
  100. /* Each interface is referenced by a network interface structure,         */
  101. /* vs_if, which the routing code uses to locate the interface.            */
  102. /* Structure contains the output queue for the interface, its address, ...*/
  103. /**************************************************************************/
  104. struct pn_softc
  105.     {
  106.     struct arpcom vs_ac; /* common Ethernet structures */
  107. #define vs_if vs_ac.ac_if /* network-visible interface */
  108. #define vs_enaddr vs_ac.ac_enaddr /* hardware ethernet address */
  109.     short vs_oactive; /* is output active */
  110.     short vs_olen; /* output length */
  111.     u_short vs_ostrt; /* output start, for retransmission */
  112.     short vs_tries; /* transmit current retry count */
  113.     short vs_init; /* number of ring inits */
  114.     short vs_refused; /* number of packets refused */
  115.     short vs_timeouts; /* number of transmit timeouts */
  116.     short vs_otimeout; /* number of output timeouts */
  117.     short vs_ibadf; /* number of input bad formats */
  118.     short vs_parity; /* number of parity errors */
  119.     u_short rcvhd; /* beginning of the rcv blk, for RBUFDMAPTR */
  120.     caddr_t vs_tbuf; /* xmt buffer */
  121.     int pnIntLevel;           /* VME interrupt level */
  122.     struct pn_regs *pn_regs;
  123.     } pn_softc[NPN];
  124. /* forward declarations */
  125. LOCAL int pnprobe ();
  126. LOCAL VOID pnreset ();
  127. LOCAL VOID pninit ();
  128. LOCAL int pnidentify ();
  129. LOCAL VOID pnstart ();
  130. LOCAL VOID pnxint ();
  131. LOCAL VOID pnwatchdog ();
  132. LOCAL VOID pnrint ();
  133. LOCAL VOID pnoutput ();
  134. LOCAL VOID pnioctl ();
  135. LOCAL VOID pnsetaddr ();
  136. LOCAL VOID pnrcsrintr ();
  137. LOCAL VOID pntcsrintr ();
  138. LOCAL struct mbuf *emptyrbuf ();
  139. /*******************************************************************************
  140. *
  141. * pnattach -
  142. *
  143. * Interface exists: make available by filling in network interface record.
  144. * System will initialize the interface when it is ready to accept packets.
  145. *
  146. * RETURNS: OK or ERROR
  147. */
  148. STATUS pnattach (unit, addr, ivec, ilevel)
  149.     int unit; 
  150.     FAST struct pn_regs *addr;
  151.     int ivec;
  152.     int ilevel;
  153.     {
  154.     FAST struct pn_softc *vs = &pn_softc[unit];
  155.     if (pnprobe (addr) == 0)
  156. return (ERROR);
  157.     vs->pnIntLevel = ilevel;
  158.     vs->pn_regs    = addr;
  159.     addr->pn_ctl.rdmaint     = (unsigned short) ((ivec+0) & 0xff);
  160.     addr->pn_ctl.tdmaint_nxm = (unsigned short) ((ivec+1) & 0xff);
  161.     addr->pn_ctl.rcsrint     = (unsigned short) ((ivec+2) & 0xff);
  162.     addr->pn_ctl.tcsrint     = (unsigned short) ((ivec+3) & 0xff);
  163.     addr->pn_ctl.dma_int     = (unsigned short) 0;
  164.     (void) intConnect (INUM_TO_IVEC (ivec+2), pnrcsrintr, unit);
  165.     (void) intConnect (INUM_TO_IVEC (ivec+3), pntcsrintr, unit);
  166.     sysIntEnable (ilevel);
  167.     vs->vs_if.if_unit     = unit;
  168.     vs->vs_if.if_name     = "pn";
  169.     vs->vs_if.if_mtu      = PNMTU;
  170.     vs->vs_if.if_init     = pninit;
  171.     vs->vs_if.if_ioctl    = pnioctl;
  172.     vs->vs_if.if_output   = pnoutput;
  173.     vs->vs_if.if_reset    = pnreset;
  174.     vs->vs_if.if_timer    = 0;
  175.     vs->vs_if.if_watchdog = pnwatchdog; 
  176.     vs->vs_if.if_flags    = IFF_BROADCAST;
  177.     if_attach (&vs->vs_if);
  178.     return (OK);
  179.     }
  180. /*******************************************************************************
  181. *
  182. * pnprobe - probe for presence of hardware
  183. *
  184. * RETURNS: 0 if no device, otherwise non-zero
  185. */
  186. LOCAL int pnprobe (reg)
  187.     caddr_t reg;
  188.     {
  189.     int dummy;
  190.     FAST struct pn_regs *addr = (struct pn_regs *)reg;
  191.     int rcsrLen = sizeof (addr->pn_ctl.rcsr);
  192.     int tcsrLen = sizeof (addr->pn_ctl.tcsr);
  193.     if (vxMemProbe ((char *)&addr->pn_ctl.rcsr, READ, rcsrLen, (char *)&dummy)
  194. == ERROR ||
  195. vxMemProbe ((char *)&addr->pn_ctl.tcsr, READ, tcsrLen, (char *)&dummy)
  196.  == ERROR)
  197.       {
  198.       return (0);
  199.       }
  200.     /* reset interface, enable, and wait till dust settles */
  201.     /* should try to stay in ring */
  202.     if (addr->pn_ctl.rcsr & PN_JNR)
  203. addr->pn_ctl.rcsr = PN_RST | PN_JNR;
  204.     else
  205. addr->pn_ctl.rcsr = PN_RST;
  206.     addr->pn_ctl.tcsr = PN_RST;
  207.     taskDelay (10);
  208.     return (sizeof (struct pn_regs));
  209.     }
  210. /*******************************************************************************
  211. *
  212. * pnreset - reset of interface
  213. */
  214. LOCAL VOID pnreset (unit)
  215.     int unit;
  216.     {
  217.     FAST struct pn_softc *vs = &pn_softc[unit];
  218.     FAST struct pn_regs *addr = vs->pn_regs; 
  219.     pninit (unit);
  220.     /* XXX need to?
  221.     vs->vs_if.if_flags &= ~IFF_RUNNING;
  222.     */
  223.     /* disable interrupts */
  224.     sysIntDisable (vs->pnIntLevel);
  225.     /* set interface to known state (not interrupting) */
  226.     /* should try to stay in ring */
  227.     if (addr->pn_ctl.rcsr & PN_JNR)
  228. addr->pn_ctl.rcsr = PN_RST | PN_JNR;
  229.     else
  230. addr->pn_ctl.rcsr = PN_RST;
  231.     addr->pn_ctl.tcsr = PN_RST;
  232.     taskDelay (10);
  233.     }
  234. /*******************************************************************************
  235. *
  236. * pninit -
  237. *
  238. * Initialization of interface; clear recorded pending
  239. * operations, and start any pending writes.
  240. */
  241. LOCAL VOID pninit (unit)
  242.     int unit;
  243.     {
  244.     FAST int s;
  245.     FAST struct pn_softc *vs = &pn_softc[unit];
  246.     FAST struct pn_regs *addr = vs->pn_regs; 
  247.     if (vs->vs_tbuf == (caddr_t) 0 &&
  248. (vs->vs_tbuf = (caddr_t) malloc ((unsigned) PNBUFSIZE)) == (caddr_t) 0)
  249. {
  250. logMsg ("pninit: out of memory!");
  251. return;
  252. }
  253.     /* Now that the buffers and mapping are set,
  254.      * figure out our address and complete out host address;
  255.      * pnidentify () will do a self-test.
  256.      */
  257.     if (pnidentify (unit, 1) == 0)
  258. {
  259. vs->vs_if.if_flags &= ~IFF_UP;
  260. free((char *)vs->vs_tbuf);
  261. vs->vs_tbuf = (caddr_t) 0;
  262. return;
  263. }
  264.     
  265.     /* Reset the interface, and stay in the ring */
  266.     addr->pn_ctl.tcsr = PN_RST; /* reset xmt */
  267.     addr->pn_ctl.rcsr = PN_RST | PN_JNR | PN_MEN; /* reset rcv */
  268.     taskDelay (60);
  269.     vs->vs_init     = 0; /* clear counters */
  270.     vs->vs_refused  = 0;
  271.     vs->vs_timeouts = 0;
  272.     vs->vs_otimeout = 0;
  273.     vs->vs_ibadf    = 0;
  274.     vs->vs_parity   = 0;
  275.     /* hang receive, start any pending writes by faking a transmit complete */
  276.     s = splimp ();
  277.     vs->rcvhd            = 0; /* RCOUNTER starts at 0 */
  278.     addr->pn_ctl.rcsr    = PN_IEN | PN_JNR | PN_MEN | PN_CEN;
  279.     vs->vs_oactive       = 1;
  280.     vs->vs_if.if_flags  |= IFF_UP | IFF_RUNNING;
  281.     pnxint (unit);
  282.     splx (s);
  283.     }
  284. /*******************************************************************************
  285. *
  286. * pnidentify -
  287. *
  288. * Do a moderately thorough self-test in all three modes.
  289. * Mostly to keep defective nodes off the ring than to be especially thorough.
  290. *
  291. * RETURNS: host address, or 0 if error
  292. */
  293. LOCAL int pnidentify (unit, flg)
  294.     int unit;
  295.     int flg;
  296.     {
  297.     FAST struct pn_header *v;
  298.     FAST int ix;
  299.     FAST int successes;
  300.     FAST int failures;
  301.     u_short shost = 0;
  302.     u_short t_strt;    /* t_strt is start of TBUFAD, and refers to lwords */
  303.     u_short *msg;
  304.     u_short *msgStart;
  305.     u_short pktsz;
  306.     int test;
  307.     BOOL ignorexmt            = TRUE;
  308.     FAST struct pn_softc *vs  = &pn_softc[unit];
  309.     FAST struct pn_regs *addr = vs->pn_regs; 
  310.     t_strt = (TBUFSIZE - ((sizeof(struct pn_header) + 3) >> 2)) & 0x3ff;
  311.     if ((msgStart = (u_short *) malloc (PNBUFSIZE)) == NULL)
  312. {
  313. logMsg ("pnidentify: out of memory!n");
  314. return (0);
  315. }
  316.     /* Build a multicast address to identify our address.
  317.      * We need do this only once, since nobody else is about to use
  318.      * the intermediate transmit buffer (vs->vs_tbuf) that
  319.      * we snagged in pninit().
  320.      */
  321.     addr->pn_ctl.tbufad = t_strt; /* reset tbufad to 0? */
  322.     v = (struct pn_header *)(vs->vs_tbuf);
  323.     v->vh_dhost   = PN_BROADCAST; /* multicast destination address */
  324.     v->vh_shost   = 0; /* will be overwritten with ours */
  325.     v->vh_version = RING_VERSION;
  326.     v->vh_type    = RING_DIAGNOSTICS;
  327.     v->vh_info    = 0;
  328.     vs->vs_olen = (sizeof(struct pn_header) + 1) >> 1;
  329.     /* For each of the modes (digital, analog, network), go through
  330.      * a self-test that requires me to send PNIDENTSUCC good packets
  331.      * in PNIDENTRETRY attempts. Use broadcast destination to find out
  332.      * who I am, then use this as my address to check my address match
  333.      * logic. Only data checked is the vh_type field.
  334.      */
  335.     ix = (addr->pn_ctl.rcsr & PN_JNR) == PN_JNR ? 2 : 0;
  336.     for (; ix < 4; ix++)
  337. {
  338. successes = 0; /* clear successes for this mode */
  339. failures  = 0; /* and clear failures, too */
  340. /* take over device, and leave ring */
  341. addr->pn_ctl.tcsr = PN_RST;
  342. test = (ix < 2) ? ix : 2;
  343. addr->pn_ctl.rcsr = pn_modes[test]; /* test mode */
  344. /* retry loop */
  345. while (successes < PNIDENTSUCC && failures < PNIDENTRETRY)
  346.     {
  347.     /* cancel any previous unfinished operations */
  348.     addr->pn_ctl.rcsr = PN_RST|pn_modes[test];
  349.     addr->pn_ctl.tcsr = PN_RST;
  350.     taskDelay (1); /* let's give it a little more time */
  351.     /* start a receive */
  352.     addr->pn_ctl.rcounter   = 0; /* RCNTR after rcv is pkt size */
  353.     addr->pn_ctl.rcsr       = pn_modes[test]|PN_CEN; /* do it */
  354.     /* send our output packet:
  355.      *   set up TCSR, TBUFAD, and TBUFDA's
  356.      */
  357.     addr->pn_ctl.tbufad = t_strt;
  358.     msg = (u_short *)vs->vs_tbuf;
  359.     while ((addr->pn_ctl.tbufad & 0x7ff) != TBUFSIZE)
  360. {
  361. addr->pn_ctl.tbufda = *msg++;
  362. addr->pn_ctl.tbufda = *msg++;
  363. }
  364.     addr->pn_ctl.tbufad = t_strt;
  365.     addr->pn_ctl.tcsr   = PN_INI|PN_ORI;
  366.     taskDelay (1); /* wait to receive message */
  367.     if ((addr->pn_ctl.rcsr & PN_RDY) == 0 ||
  368. (addr->pn_ctl.tcsr & PN_RDY) == 0)
  369. {
  370. failures++;
  371. continue;
  372. }
  373.     /* check csr status on this packet */
  374.     if ((addr->pn_ctl.rstatr & PNRERR) ||
  375. (addr->pn_ctl.tcsr   & PNTERR))
  376. {
  377. failures++;
  378. continue;
  379. }
  380.     if (ignorexmt && test == 0)
  381. {
  382. /* Ignore the first xmit message.
  383.  * There is a problem with Proteon's software address
  384.  * override so the address returned from the first
  385.  * broadcast message after powerup may be wrong.
  386.  */
  387. ignorexmt = FALSE;
  388. continue;
  389. }
  390.     /* copy out the rcv pkt from RBUFFER to rbuf */
  391.     msg = msgStart;
  392.     for (pktsz = 0;
  393.  pktsz < PNBUFSIZE && pktsz < (addr->pn_ctl.rcntr >> 1);
  394.  pktsz++)
  395. {
  396. *msg++ = addr->pn_rbuffer [pktsz];
  397. }
  398.     addr->pn_ctl.rstcntr = 0; /* clear CNTR */
  399.     v = (struct pn_header *) msgStart;
  400.     /* proper message type */
  401.     if ((v->vh_type & 0xff) == RING_DIAGNOSTICS)
  402. {
  403. if (shost == 0)
  404.     {
  405.     shost = v->vh_shost & 0xff;
  406.     ((struct pn_header *)(vs->vs_tbuf))->vh_dhost = shost;
  407.     }
  408.   successes++;
  409. }
  410.     else
  411.       failures++;
  412.     v->vh_type = 0; /* zap it out so we can check again */
  413.     }
  414. if (failures >= PNIDENTRETRY)
  415.     {
  416.     if (flg)
  417. {
  418. printf("pn%d: failed self-test after %d tries in %s moden",
  419. unit, PNIDENTRETRY, ix == 0 ? "digital loopback" :
  420. (ix == 1 ? "analog loopback" : "network"));
  421. printf("pn%d: rstatr = %#x, rcsr = %#x, tcsr = %#xn",
  422. unit, 0x7 & addr->pn_ctl.rstatr, /*PN_SBITS,*/
  423. 0xffff & addr->pn_ctl.rcsr/*, PN_RBITS*/,
  424. 0xffff & addr->pn_ctl.tcsr/*, PN_TBITS*/);
  425. }
  426.     addr->pn_ctl.rcsr = PN_RST; /* kill the sick board */
  427.     addr->pn_ctl.tcsr = PN_RST;
  428.     free ((char *) msgStart);
  429.     return (0);
  430.     }
  431. }
  432.     free ((char *) msgStart);
  433.     return (shost);
  434.     }
  435. /*******************************************************************************
  436. *
  437. * pnstart - start or restart output on interface
  438. *
  439. * If interface active, then a retransmit, just restuff registers and go.
  440. * If interface not already active, get another datagram off the interface
  441. * queue, copy to buffer and send it.
  442. */
  443. LOCAL VOID pnstart (unit)
  444.     int unit;
  445.     {
  446.     int s;
  447.     FAST struct mbuf *m;
  448.     FAST struct pn_softc *vs  = &pn_softc[unit];
  449.     FAST struct pn_regs *addr = vs->pn_regs; 
  450.     /* active? */
  451.     if (vs->vs_oactive)
  452. {
  453. addr->pn_ctl.tbufad = vs->vs_ostrt; /* retransmit */
  454. goto restart;
  455. }
  456.     /* not active, try dequeueing a new message */
  457.     s = splimp();
  458.     IF_DEQUEUE(&vs->vs_if.if_snd, m);
  459.     splx (s);
  460.     /* any message? */
  461.     if (m == NULL) 
  462. {
  463. vs->vs_oactive = 0;
  464. return;
  465. }
  466.     /* prepare to send */
  467.     vs->vs_olen = filltbuf (unit, vs->vs_tbuf, m);
  468.     m_freem (m);
  469. restart :
  470.     /* make sure this packet will fit in the interface */
  471.     if (vs->vs_olen > PNBUFSIZE)
  472. {
  473. printf ("pn%d: vs_olen: %d > PNBUFSIZEn", unit, vs->vs_olen);
  474. panic ("pnstart: vs_olen botch");
  475. }
  476.     vs->vs_if.if_timer = PNTIMEOUT;
  477.     vs->vs_oactive = 1;
  478.     /* supposed to setup for 82258 transmit dma here */
  479.     if (addr->pn_ctl.tcsr & PN_NOK) 
  480. vs->vs_init++; /* count ring inits */
  481.     addr->pn_ctl.tcsr = PN_IEN | PN_INI | PN_ORI;
  482.     }
  483. /*******************************************************************************
  484. *
  485. * pnwatchdog -
  486. *
  487. * Transmit watchdog timer routine. This routine gets called when we lose
  488. * a transmit interrupt. The best we can do is try to restart output.
  489. */
  490. LOCAL VOID pnwatchdog (unit)
  491.     int unit;
  492.     {
  493.     FAST int s;
  494.     FAST struct pn_softc *vs = &pn_softc[unit];
  495.     pnprintf("pn%d: lost a transmit interrupt.n", unit);
  496.     vs->vs_timeouts++;
  497.     s = splimp ();
  498.     pnstart (unit);
  499.     splx (s);
  500.     }
  501. /*******************************************************************************
  502. *
  503. * pnxint - transmit interrupt
  504. *
  505. * Start new output if more data available.
  506. */
  507. LOCAL VOID pnxint (unit)
  508.     int unit;
  509.     {
  510.     FAST struct pn_softc *vs  = &pn_softc[unit];
  511.     FAST struct pn_regs *addr = vs->pn_regs; 
  512.     FAST int tcsr             = addr->pn_ctl.tcsr & 0xffff;
  513.     vs->vs_if.if_timer = 0;
  514.     addr->pn_ctl.tcsr = PN_RTI; /* clear/reset the interrupt */
  515.     if (vs->vs_oactive == 0) 
  516. {
  517. pnprintf("pn%d: stray interrupt tcsr = %#xn", unit, tcsr/*,PN_TBITS*/);
  518. return;
  519. }
  520.     /* retransmit on soft error.
  521.      * TODO: sort retransmits to end of queue if possible
  522.      */
  523.     if (tcsr & (PN_TMO | PN_REF))
  524. {
  525. if (vs->vs_tries++ < PNRETRY) 
  526.     {
  527.     if (tcsr & PN_TMO)
  528. vs->vs_otimeout++;
  529.     if (tcsr & PN_REF)
  530. {
  531. vs->vs_if.if_collisions++;
  532. vs->vs_refused++;
  533. }
  534.     pnstart (unit); /* restart this message */
  535.     return;
  536.     }
  537. }
  538.     vs->vs_if.if_opackets++;
  539.     vs->vs_oactive = 0;
  540.     vs->vs_tries   = 0;
  541.     if (tcsr & PNTERR)
  542. {
  543. vs->vs_if.if_oerrors++;
  544. pnprintf ("pn%d: error tcsr = %#xn", unit, tcsr/*, PN_TBITS*/);
  545. }
  546.     pnstart (unit);
  547.     }
  548. /*******************************************************************************
  549. *
  550. * pnrint - receive interrupt
  551. *
  552. * First, stash data on packet just received. Then
  553. * swap receive buffers and start a new receive. Now! Then check error
  554. * status of packet. Then undo trailers, examine the packet, and pass it
  555. * on the the appropriate higher protocol.
  556. */
  557. LOCAL VOID pnrint (unit, rcsr, rstatr, rcntr)
  558.     int unit;
  559.     FAST int rcsr; /* this is the current input CSR */
  560.     FAST int rstatr; /* ditto here as status register */
  561.     int rcntr;
  562.     {
  563.     FAST struct pn_header *pn;
  564.     FAST struct mbuf *m;
  565.     struct ifqueue *inq;
  566.     int len;
  567.     int s;
  568.     FAST int off;
  569.     int type;
  570.     short resid; /* this is the current residual */
  571.     int index;
  572.     FAST struct pn_softc *vs  = &pn_softc[unit];
  573.     FAST struct pn_regs *addr = vs->pn_regs; 
  574.     vs->vs_if.if_ipackets++;
  575.     /* save device registers, as we are restarting
  576.      * (note rcsr saved it initial interrupt time)
  577.      */
  578.     if (rcntr < vs->rcvhd)
  579. len = RBUFSIZE - vs->rcvhd + rcntr;
  580.     else
  581.         len = rcntr  - vs->rcvhd; /* only 14 addr bits */
  582.     len -= sizeof (struct pn_header); /* but remove local net hdr len */
  583.     /* get a pointer to packet in RBUFFER */
  584.     index = vs->rcvhd;
  585.     pn = (struct pn_header *)&(addr->pn_rbuffer[index >> 1]);
  586.     pntracehdr ("rint", pn, 1);
  587.     vs->rcvhd = (rcntr + 3) & 0x3ffc;   /* blk addr of next pkt */
  588.     if (! (vs->vs_if.if_flags & IFF_UP))
  589.       {
  590.       pnprintf ("pn%d: not up!n", unit);
  591.       return;
  592.       }
  593.     /* Now that a new receive has been started, do the processing
  594.      * on the old packet (bufno)
  595.      */
  596.     if (rstatr & PNRERR) 
  597. {
  598. pnprintf("pn%d: receive error, rcsr = %#x, rstatr = %#xn",
  599.                   unit, rcsr, rstatr);
  600. if (rstatr & RBDF)
  601.     vs->vs_ibadf++;
  602. goto dropit;
  603. }
  604.     if (rcsr & PN_PER)
  605. {
  606. /* don't have to clear it because the recieve command
  607.  * above wrote 0 to the parity bit
  608.  */
  609. vs->vs_parity++;
  610. /* Only on 10 megabit proNET is PN_PER an end-to-end parity
  611.  * bit. On 80 megabit, it returns to the intended use of
  612.  * node-to-node parity. End-to-end parity errors on 80 megabit
  613.  * give PN_BDF.
  614.  */
  615. if (!IS_80)
  616.     goto dropit;
  617. }
  618.     /* fundamental length check */
  619.     if ((rstatr & ROVR) || (len > PNMRU) || (len <= 0))
  620. {
  621. pnprintf(
  622. "pn%d: len too long or short, len = %d, rcsr = %#x, rstatr = %#xn",
  623.     unit, len, rcsr, /*PN_RBITS,*/ rstatr/*, PN_SBITS*/);
  624. goto dropit;
  625. }
  626.     /* check the protocol header version */
  627.     if (pn->vh_version != RING_VERSION)
  628. {
  629. pnprintf("pn%d: bad protocol header version %dn",
  630.  unit, pn->vh_version & 0xff);
  631. goto dropit;
  632. }
  633.     /* untested trailer handling -- taken straight from VAX code */
  634.     off = 0;
  635. #define pndataaddr(pn, off, type) ((type)(((caddr_t)((pn)+1)+(off))))
  636.     if (pn->vh_type >= RING_IPTrailer &&
  637. pn->vh_type < RING_IPTrailer+RING_IPNTrailer) 
  638. {
  639. off = (pn->vh_type - RING_IPTrailer) * 512;
  640. if (off > PNMTU) 
  641. {
  642.     pnprintf("pn%d: off > PNMTU, off = %d, rcsr = %#xn",
  643. unit, off, rcsr/*, PN_RBITS*/);
  644.     goto dropit;
  645. }
  646. pn->vh_type = ntohs(*pndataaddr(pn, off, u_short *));
  647. resid = ntohs(*pndataaddr(pn, 2+off, u_short *));
  648.     /* 2+off -> better code */
  649. if (off + resid > len) 
  650.     {
  651.     pnprintf ("pn%d: trailer packet too shortn", unit);
  652.     pnprintf ("pn%d: len=%d, off=%d, resid=%d, rcsr=%#x, rstatr=%#xn",
  653. unit, len, off, resid,
  654. rcsr/*, PN_RBITS*/, rstatr/*, PN_SBITS*/);
  655.     goto dropit;
  656.     }
  657. len = off + resid;
  658. }
  659.     if (len == 0) 
  660. {
  661. pnprintf("pn%d: len is zero, rcsr = %#x, rstatr = %#xn",
  662.                   unit, rcsr/*, PN_RBITS*/, rstatr/*, PN_SBITS*/);
  663. goto dropit;
  664. }
  665.     /* save packet type for later demux */
  666.     type = pn->vh_type & 0xff;
  667.     /* Copy buffer into mbuf chain, without net header.
  668.      * Could wait until type is o.k., but almost certainly is so why wait
  669.      * Note that this part of the code runs SLOW, which is why the
  670.      * multiple receive buffers are used. It still must be reckoned
  671.      * that the keyboard is still locked out...
  672.      */
  673.     m = emptyrbuf (unit, addr, index, len, off, sizeof(struct pn_header), 
  674.   &vs->vs_if);
  675.     if (m == 0) /* success? */
  676. goto dropit;
  677.     /* remove trailer header length header */
  678.     if (off)
  679. {
  680.      struct ifnet *ifp;
  681.      ifp = *(mtod (m, struct ifnet **));
  682.      m->m_off += 2 * sizeof (u_short);
  683.      m->m_len -= 2 * sizeof (u_short);
  684.      *(mtod (m, struct ifnet **)) = ifp;
  685. }
  686.     /* demultiplex on packet type */
  687.     switch (type)
  688. {
  689. #ifdef INET
  690. case RING_IP:
  691.     inq = &ipintrq;
  692.     s = splimp ();
  693.     if (IF_QFULL(inq)) 
  694. {
  695. IF_DROP(inq);
  696. m_freem (m);
  697. }
  698.     else
  699. IF_ENQUEUE(inq, m);
  700.     splx (s);
  701.     netJobAdd (ipintr, 0);
  702.     break;
  703. #endif
  704. default:
  705.     pnprintf ("pn%d: unknown pkt type %#xn", unit, type);
  706.     m_freem (m);
  707. }
  708.     return; /* next packet receive is already started */
  709. dropit : /* drop packet on floor -- count them!! */
  710.     pnprintf ("pn%d: dropped it!n", unit);
  711.     vs->vs_if.if_ierrors++;
  712.     }
  713. /*******************************************************************************
  714. *
  715. * pnoutput -
  716. *
  717. * RETURNS: 0 if OK, otherwise UNIX errno
  718. */
  719. LOCAL VOID pnoutput (ifp, m0, dst)
  720.     struct ifnet *ifp;
  721.     struct mbuf *m0;
  722.     struct sockaddr *dst;
  723.     {
  724.     FAST struct pn_header *pn;
  725.     FAST int s;
  726.     int type;
  727.     int dest;
  728.     int error;
  729.     u_short info              = 0;
  730.     FAST struct mbuf *m       = m0;
  731.     FAST int unit             = ifp->if_unit;
  732.     FAST struct pn_softc *vs  = &pn_softc[unit];
  733.     FAST struct pn_regs *addr = vs->pn_regs; 
  734.     switch (dst->sa_family) 
  735. {
  736. #ifdef INET
  737. case AF_INET:
  738.     dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
  739.     /*
  740.      * Take the local net address part of the address,
  741.      * and use it as node number. This is not exactly
  742.      * kosher under some circumstances, but I'll let it fly.
  743.      */
  744.     if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) 
  745. {
  746. pnprintf("pn%d: can't do af%dn", unit, dst->sa_family);
  747. error = EPERM;
  748. goto bad;
  749. }
  750.     type = RING_IP; /* NO TRAILERS OUTBOUND */
  751.     break;
  752. #endif
  753. default:
  754.     pnprintf("pn%d: can't handle af%dn", unit, dst->sa_family);
  755.     error = EAFNOSUPPORT;
  756.     goto bad;
  757. }
  758.     /* add local net header.  If no space in first mbuf, allocate another */
  759.     if (m->m_off > MMAXOFF || MMINOFF + sizeof (struct pn_header) > m->m_off) 
  760. {
  761. m = m_get(M_DONTWAIT, MT_HEADER);
  762. if (m == (struct mbuf *)0) 
  763.     {
  764.     error = ENOBUFS;
  765.     goto bad;
  766.     }
  767. m->m_next = m0;
  768. m->m_off = MMINOFF;
  769. m->m_len = sizeof (struct pn_header);
  770. }
  771.     else 
  772. {
  773. m->m_off -= sizeof (struct pn_header);
  774. m->m_len += sizeof (struct pn_header);
  775. }
  776.     pn = mtod (m, struct pn_header *);
  777.     pn->vh_shost = in_lnaof ( ((struct arpcom *)ifp)->ac_ipaddr); 
  778.     if (pn->vh_shost == 0)
  779. {
  780. panic ("pnoutput: interface not found in in_ifaddrn");
  781. error = EPERM;
  782. goto bad;
  783. }
  784.     /* map the destination address if it's a broadcast */
  785.     if ((pn->vh_dhost = dest) == INADDR_ANY)
  786. pn->vh_dhost = PN_BROADCAST;
  787.     pn->vh_version = RING_VERSION;
  788.     pn->vh_type    = type;
  789.     pn->vh_info    = htons (info); /* this gets changed if testing packets */
  790.     /* queue packet, and if interface not active, send */
  791.     s = splimp ();
  792.     if (IF_QFULL(&ifp->if_snd)) 
  793. {
  794. IF_DROP(&ifp->if_snd);
  795. error = ENOBUFS;
  796. goto qfull;
  797. }
  798.     IF_ENQUEUE(&ifp->if_snd, m);
  799.     if (vs->vs_oactive == 0)
  800. pnstart (unit);
  801.     splx (s);
  802.     return (0);
  803. qfull :
  804.     m0 = m;
  805.     splx (s);
  806. bad :
  807.     m_freem (m0);
  808.     return (error);
  809.     }
  810. /*******************************************************************************
  811. *
  812. * pnioctl -
  813. */
  814. LOCAL VOID pnioctl (ifp, cmd, data)
  815.     FAST struct ifnet *ifp;
  816.     int cmd;
  817.     caddr_t data;
  818.     {
  819.     FAST struct sockaddr *sin;
  820.     FAST struct ifaddr *ifa = (struct ifaddr *)data;
  821.     int error               = 0;
  822.     FAST int s              = splimp();
  823.     switch (cmd) 
  824. {
  825. case SIOCSIFADDR:
  826.     sin = (struct sockaddr *)data;
  827.     if (sin->sa_family != AF_INET)
  828. {
  829. error = EINVAL;
  830. break;
  831. }
  832.     pnsetaddr(ifp, (struct sockaddr_in *)sin);
  833.     /* store the internet address in arpcom */
  834.     ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
  835.     if (!(ifp->if_flags & IFF_RUNNING))
  836. {
  837. pninit (ifp->if_unit);
  838. if ((ifp->if_flags & IFF_UP) == 0)
  839.     error = ENETDOWN; /* self test failed, give error */
  840. }
  841.     break;
  842. case SIOCSIFFLAGS:
  843.     /* not implemented (set interface up/down) */
  844. default:
  845.     error = EINVAL;
  846.     break;
  847. }
  848.     splx (s);
  849.     return (error);
  850.     }
  851. /*******************************************************************************
  852. *
  853. * pnsetaddr - set pronet address
  854. *
  855. * set up the address for this interface.  Uses the network number
  856. * from the passed address and an invalid host number.
  857. * pnidentify figures out and inserts real host address later.
  858. */
  859. LOCAL VOID pnsetaddr (ifp, sin)
  860.     FAST struct ifnet *ifp;
  861.     FAST struct sockaddr_in *sin;
  862.     {
  863.     FAST struct pn_softc *vs  = &pn_softc[ifp->if_unit];
  864.     FAST struct pn_regs *addr = vs->pn_regs; 
  865.     int lna = in_lnaof (((struct sockaddr_in *)sin)->sin_addr);
  866.     /* set the board's host number, overriding the hardware address */
  867.     if (IS_80)
  868. addr->pn_ctl.rbufdmaptr = 0xc000 | lna;
  869.     }
  870. /*******************************************************************************
  871. *
  872. * pnrcsrintr - rcv csr intr handler
  873. */
  874. LOCAL VOID pnrcsrintr (unit)
  875.     int unit;
  876.     {
  877.     int csr;
  878.     int rstatr;
  879.     int rcntr;
  880.     FAST struct pn_regs *addr = pn_softc[unit].pn_regs;
  881.     if ((addr->pn_ctl.rcsr & (PN_IRQ|PN_RDY)) != (PN_IRQ|PN_RDY))
  882. logMsg ("proNET: rcv csr vector number clash!n");
  883.     else
  884. {
  885. csr    = addr->pn_ctl.rcsr & 0xffff;
  886. rstatr = addr->pn_ctl.rstatr & 0x7;
  887. rcntr  = addr->pn_ctl.rcntr & 0x3fff; 
  888. netJobAdd (pnrint, unit, csr, rstatr, rcntr);
  889. }
  890.     addr->pn_ctl.rcsr =  PN_IEN | PN_MEN | PN_JNR | PN_RTI | PN_CEN;
  891.     addr->pn_ctl.rstcntr = 0; /* get ready for next pkt */
  892.     }
  893. /*******************************************************************************
  894. *
  895. * pntcsrintr - xmt csr intr handler
  896. */
  897. LOCAL VOID pntcsrintr (unit)
  898.     FAST int unit;
  899.     {
  900.     FAST struct pn_softc *vs  = &pn_softc[unit];
  901.     FAST struct pn_regs *addr = vs->pn_regs;
  902.     FAST int tcsr             = addr->pn_ctl.tcsr & 0xffff;
  903.     FAST int rfsreg           = addr->pn_ctl.rfsreg & 0xffff;
  904.     sysBusIntAck (vs->pnIntLevel);
  905.     if ((tcsr & (PN_IRQ|PN_RDY)) != (PN_IRQ|PN_RDY))
  906. {
  907. pnprintf("proNET: xmt csr vector number clash!n");
  908. logMsg ("tcsr = %#xn", addr->pn_ctl.tcsr );
  909. if ((addr->pn_ctl.tcsr & (PN_IRQ)) != (PN_IRQ))
  910.     logMsg ("PN_IRQ not onn");
  911. if ((addr->pn_ctl.tcsr & (PN_RDY)) != (PN_RDY))
  912.     logMsg ("PN_RDY not onn");
  913. addr->pn_ctl.tcsr = PN_RTI; /* clear/reset the interrupt */
  914. }
  915.     else
  916. {
  917. /* should call pnxint() here, but duplicated here for speed */
  918. vs->vs_if.if_timer = 0;
  919. addr->pn_ctl.tcsr = PN_RTI; /* clear/reset the interrupt */
  920. if (vs->vs_oactive == 0) 
  921.     {
  922.     pnprintf("pn%d: stray interrupt tcsr = %#xn",
  923.      unit, tcsr/*, PN_TBITS*/);
  924.     return;
  925.     }
  926. /* retransmit on soft error
  927.  * TODO: sort retransmits to end of queue if possible
  928.  */
  929. if (tcsr & PNTERR)
  930.     {
  931.     if (vs->vs_tries++ < PNRETRY) 
  932. {
  933. /* re-order refused bits and cancel the "any":
  934.  *  what's wrong here?
  935.  *
  936.  * rfsreg = ((rfsreg >> 9) & 0x7f) | ((rfsreg & 0xff) << 7);
  937.  */
  938. if (tcsr & PN_TMO)
  939.     {
  940.     vs->vs_otimeout++;
  941.     pnprintf ("pntcsrintr: RESTART (TIMEOUT) %#xn", rfsreg);
  942.     }
  943. if (tcsr & PN_REF)
  944.     {
  945.     vs->vs_if.if_collisions++;
  946.     vs->vs_refused++;
  947.     pnprintf ("pntcsrintr: RESTART (refused) %#xn", rfsreg);
  948.     }
  949. if (tcsr & PN_BDF)
  950.     {
  951.     pnprintf ("pntcsrintr: RESTART (bad form) %#xn", rfsreg);
  952.     }
  953. /* doesn't need to be at task level, 'cuz we're restarting */
  954. pnstart (unit);
  955. return;
  956. }
  957.     }
  958. vs->vs_if.if_opackets++;
  959. vs->vs_oactive = 0;
  960. vs->vs_tries   = 0;
  961. if (tcsr & PNTERR)
  962.     {
  963.     vs->vs_if.if_oerrors++;
  964.     pnprintf("pn%d: error tcsr = %#xn", unit, tcsr/*, PN_TBITS*/);
  965.     }
  966. /* let's only call pnstart if there are messages in the output queue */
  967. if (vs->vs_if.if_snd.ifq_len > 0)  
  968.     netJobAdd (pnstart, unit);
  969. }
  970.     }
  971. /*******************************************************************************
  972. *
  973. * filltbuf -
  974. *
  975. * takes a chain of mbufs and copies the chain into a buffer.
  976. * returns the number of bytes put into the buffer.  if board is
  977. * not swabbing it also swabs the bytes. does not free mbuf chain.
  978. *
  979. * RETURNS: number of bytes filled
  980. */
  981. LOCAL int filltbuf (unit, buf, mchain)
  982.     int unit;
  983.     caddr_t buf;
  984.     struct mbuf *mchain;
  985.     {
  986.     FAST u_long *tbufda;
  987.     FAST struct mbuf *m;
  988.     BOOL odd             = FALSE;
  989.     int len              = 0;
  990.     struct pn_softc *vs  = &pn_softc[unit];
  991.     struct pn_regs *addr = vs->pn_regs; 
  992.     /* sum mbuf chain, and check for odd length mbuf's */
  993.     for (m = mchain; m != NULL; m = m->m_next)
  994. {
  995. if (m->m_len & 0x1 || m->m_off & 0x1)
  996.     odd = TRUE;
  997. len += m->m_len;
  998. }
  999.     tbufda = (u_long*)&addr->pn_ctl.tbufda;
  1000.     vs->vs_ostrt = (TBUFSIZE - ((len + 3) >> 2)) & 0x3ff;
  1001.     addr->pn_ctl.tbufad = vs->vs_ostrt;
  1002.     m = mchain;
  1003.     if (odd)
  1004. {
  1005. caddr_t bpend;
  1006. FAST caddr_t bp = buf;
  1007. /* double buffering! however this code probably never runs */
  1008. for (; m != NULL; m = m->m_next)
  1009.     {
  1010.     pncopy (mtod (m, caddr_t), bp, m->m_len);
  1011.     bp += m->m_len;
  1012.     }
  1013. bpend = bp;
  1014. for (bp = buf; bp < bpend; bp += 4)
  1015.     *tbufda = *(u_long *)bp;
  1016. }
  1017.     else
  1018. {
  1019. int flag = 0;
  1020. for (; m != NULL; m = m->m_next)
  1021.     flag = movep (mtod (m, u_long *), tbufda, m->m_len, flag);
  1022. }
  1023.     addr->pn_ctl.tbufad = vs->vs_ostrt;
  1024.     return (len);
  1025.     }
  1026. /*******************************************************************************
  1027. *
  1028. * emptyrbuf - empty a buffer into a chain of mbufs
  1029. *
  1030. * This routine is admitted to be hard to understand.  It is doing three
  1031. * things at once: copying the buffer, moving IP trailers to the front of
  1032. * the packet and skipping the ring header.
  1033. *
  1034. * NOTE:
  1035. * IP trailers part is not tested.
  1036. *
  1037. * RETURNS: the start of the chain, or 0 if error
  1038. *
  1039. * ARGSUSED
  1040. */
  1041. LOCAL struct mbuf *emptyrbuf (unit, addr, pktad, totlen, off0, skip, ifp)
  1042.     int unit; /* unit number */
  1043.     struct pn_regs *addr; /* device address */
  1044.     int pktad; /* index of pkt in RBUFFER */
  1045.     FAST int totlen; /* bytes to copy */
  1046.     int off0; /* trailer offset */
  1047.     int skip; /* header length */
  1048.     struct ifnet *ifp;
  1049.     {
  1050.     FAST int len;
  1051.     FAST struct mbuf *m;
  1052.     struct mbuf *top = (struct mbuf *) 0;
  1053.     FAST struct mbuf **mp = &top;
  1054.     int off          = off0; /* assuming off = 0, ie. no trailers */
  1055.     int index        = ((pktad + skip) >> 1) & 0x1fff; /* word array index */
  1056.     FAST caddr_t bp  = (caddr_t)&addr->pn_rbuffer[index];
  1057.     pntracehdr ("input", (struct pn_header *)&(addr->pn_rbuffer[pktad>>1]), 1);
  1058.     while (totlen > 0)
  1059. {
  1060. MGET(m,M_DONTWAIT,MT_DATA);
  1061. if (m == (struct mbuf *)0)
  1062.     {
  1063.     if (top != (struct mbuf *)0)
  1064.       m_freem (top);
  1065.     return ((struct mbuf *)0);
  1066.     }
  1067. if (off)
  1068.     {
  1069.     len = totlen - off;
  1070.     index = ((pktad + off + skip) >> 1) & 0x1fff;
  1071.     bp = (caddr_t)&(addr->pn_rbuffer[index]);
  1072.     }
  1073. else
  1074.     len = totlen;
  1075. m->m_off = MMINOFF;
  1076. if (ifp)
  1077.     {
  1078.     /* Leave room for ifp */
  1079.     m->m_len = MIN(MLEN - sizeof(ifp), len);
  1080.     m->m_off += sizeof(ifp);
  1081.     }
  1082. else 
  1083.     m->m_len = MIN(MLEN, len);
  1084. m->m_next = (struct mbuf *)0; 
  1085. if ((index << 1) + m->m_len >= RBUFSIZE)
  1086.     {
  1087.     caddr_t tp = mtod (m, caddr_t);
  1088.     int cut = RBUFSIZE - (index << 1);
  1089.     pncopy(bp,tp,cut);
  1090.     pncopy((caddr_t)addr->pn_rbuffer,tp+cut,m->m_len-cut);
  1091.     index = (m->m_len - cut) >> 1;
  1092.     bp = (caddr_t)&(addr->pn_rbuffer[index]);
  1093.     }
  1094. else
  1095.     {
  1096.     pncopy(bp, mtod (m,caddr_t), m->m_len);
  1097.     index += (m->m_len >> 1);
  1098.     bp += m->m_len;
  1099.     }
  1100. *mp = m;
  1101. mp = &m->m_next;
  1102. if (off)
  1103.     {
  1104.     off += m->m_len;
  1105.     if (off == totlen)
  1106. {
  1107. index = ((pktad + skip) >> 1) & 0x1fff;
  1108. bp = (caddr_t)&(addr->pn_rbuffer[index]);
  1109. off = 0;
  1110. totlen = off0;
  1111. }
  1112.     }
  1113. else
  1114.     totlen -= m->m_len;
  1115. if (ifp) 
  1116.     {
  1117.     /* prepend interface pointer to first mbuf */
  1118.     m->m_len += sizeof(ifp);
  1119.     m->m_off -= sizeof(ifp);
  1120.     *(mtod (m, struct ifnet **)) = ifp;
  1121.     ifp = (struct ifnet *)0;
  1122.     }
  1123.       }
  1124.     return (top);
  1125.     }
  1126. /* debugging aid printout routines */
  1127. /*******************************************************************************
  1128. *
  1129. * pnprt_hdr - print the local net header in "v" with title "s"
  1130. */
  1131. LOCAL VOID pnprt_hdr (s, v, nl)
  1132.     char *s;
  1133.     FAST struct pn_header *v;
  1134.     int nl;
  1135.     {
  1136.     printf ("%10s @ %#10x: d=%#x s=%#x v=%#x t=%#x i=%#x",
  1137. s, v,
  1138. 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
  1139. 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
  1140. 0xffff & (int)(v->vh_info));
  1141.     if (nl)
  1142. printf("n");
  1143.     }
  1144. /*******************************************************************************
  1145. *
  1146. * pn_errors - print error statistics and zero
  1147. */
  1148. VOID pn_errors (unit)
  1149.     {
  1150.     FAST struct pn_softc *vs = &pn_softc[unit];
  1151.     printf ("oerrors = %d", vs->vs_if.if_oerrors);
  1152.     vs->vs_if.if_oerrors = 0;
  1153.     printf ("otimeout = %d", vs->vs_otimeout);
  1154.     vs->vs_otimeout = 0;
  1155.     printf ("collisions = %d", vs->vs_if.if_collisions);
  1156.     vs->vs_if.if_collisions = 0;
  1157.     printf ("refused = %d", vs->vs_refused);
  1158.     vs->vs_refused = 0;
  1159.     }
  1160. BOOL xmovep (from, to, len)
  1161.     short *from;
  1162.     short *to;
  1163.     int len;
  1164.     {
  1165.     while (len -= 2)
  1166. *to = *from++;
  1167.     }