(FILECREATED "30-Oct-85 19:04:30" {ERIS}<LISPCORE>SOURCES>10MBDRIVER.;16 53339  

      changes to:  (FNS \10MB.TURNONETHER)

      previous date: "18-Sep-85 15:10:49" {ERIS}<LISPCORE>SOURCES>10MBDRIVER.;15)


(* Copyright (c) 1982, 1983, 1984, 1985 by Xerox Corporation. All rights reserved.)

(PRETTYCOMPRINT 10MBDRIVERCOMS)

(RPAQQ 10MBDRIVERCOMS ((COMS (* raw packet interface)
			       (FNS \10MBGETPACKET \10MBSENDPACKET \10MBENCAPSULATE \10MB.BROADCASTP 
				    \10MBWATCHER))
			 (COMS (* Machine independent part)
			       (FNS \10MB.STARTDRIVER \10MB.CREATENDB \10MB.INPUT.INTERRUPT 
				    \10MB.OUTPUT.INTERRUPT \10MB.NOTESTAT)
			       (INITVARS (\10MB.RCLK.BOX (CREATECELL \FIXP))
					 (\10MB.EXPECTED.RECEIVE.INTERVAL 60)
					 (\10MB.INPUT.TIMEOUT (TIMES \RCLKSECOND 
								  \10MB.EXPECTED.RECEIVE.INTERVAL))
					 (\10MB.INPUT.TIMER (SETUPTIMER 0)))
			       (GLOBALVARS \10MB.RCLK.BOX \10MB.EXPECTED.RECEIVE.INTERVAL 
					   \10MB.INPUT.TIMEOUT \10MB.INPUT.TIMER))
			 (COMS (* Buffer management)
			       (FNS \10MB.LOADINPUTQ \RELEASE.IOCB \GET.IOCB \INIT.ETHER.BUFFER.POOL)
			       (INITVARS (\10MBPACKETLENGTH 448)))
			 (COMS (* Dolphin/Dlion head)
			       (FNS \10MB.GETPACKETLENGTH \10MB.GETPACKETSTATUS \QUEUE.INPUT.IOCB 
				    \QUEUE.OUTPUT.IOCB \10MB.TURNOFFETHER \10MB.TURNONETHER 
				    \10MB.RESTART.ETHER)
			       (DECLARE: EVAL@COMPILE DONTCOPY (COMS * 10MBDECLARATIONS)))
			 (COMS (* Misc)
			       (FNS \NOMACHINETYPE)
			       (FNS IOCBQLENGTH))
			 (INITVARS \10MB.GETGARBAGE \10MB.COLLECTSTATS)
			 (COMS (* PUP address resolution)
			       (FNS \HANDLE.RAW.3TO10 \TRANSLATE.3TO10 PRINT3TO10 \NOTE.3TO10)
			       (INITVARS (\10MBTYPE.PUP 512)
					 (\10MBTYPE.3TO10 513))
			       (GLOBALVARS \10MBTYPE.3TO10 \10MBTYPE.PUP)
			       (CONSTANTS \EPT.3TO10)
			       (ADDVARS (\PACKET.PRINTERS (513 . PRINT3TO10))))
			 (DECLARE: EVAL@COMPILE DONTCOPY (FILES (LOADCOMP)
								DOVEETHER LLETHER LLNS))))



(* raw packet interface)

(DEFINEQ

(\10MBGETPACKET
  [LAMBDA NIL                                                (* bvm: "28-FEB-83 11:39")
    (PROG (PACKET)
          (RETURN (COND
		    ((SETQ PACKET (\DEQUEUE \10MB.RAWPACKETQ))
		      [COND
			(\RAWTRACING (\MAYBEPRINTPACKET PACKET (QUOTE RAWGET]
		      PACKET])

(\10MBSENDPACKET
  [LAMBDA (NDB PACKET)                                       (* bvm: "26-Apr-84 09:30")
    (PROG ([DROPIT (AND \ETHERLIGHTNING (EQ 0 (RAND 0 \ETHERLIGHTNING]
	   IOCB BUFLENGTH)
          [COND
	    (\RAWTRACING (\MAYBEPRINTPACKET PACKET (QUOTE RAWPUT]
          [COND
	    ((AND (NOT (fetch NDBCANHEARSELF of NDB))
		  (OR (fetch 10MBMULTICASTP of PACKET)
		      (EQNSHOSTNUMBER (fetch 10MBDESTHOST of PACKET)
				      \MY.NSHOSTNUMBER)))    (* We would hear this packet if our hardware let us, so
							     fake receipt)
	      (PROG ((COPYPACKET (\ALLOCATE.ETHERPACKET)))
		    (\BLT (LOCF (fetch 10MBLENGTH of COPYPACKET))
			  (LOCF (fetch 10MBLENGTH of PACKET))
			  (ADD1 (fetch 10MBLENGTH of PACKET)))
                                                             (* Copy all data that would have been transmitted)
		    (replace EPTYPE of COPYPACKET with (fetch 10MBTYPE of PACKET))
		    (replace EPNETWORK of COPYPACKET with NDB)
		    (\ENQUEUE \10MB.RAWPACKETQ COPYPACKET]
          (UNINTERRUPTABLY
              (replace EPTRANSMITTING of PACKET with T)
	      (COND
		([OR DROPIT (NULL (SETQ IOCB (\GET.IOCB (QUOTE OUTPUT]
                                                             (* Fake transmission)
		  (replace EPNETWORK of PACKET with NIL))
		(T (replace EPNETWORK of PACKET with IOCB)
		   (SETQ BUFLENGTH (IMAX (fetch 10MBLENGTH of PACKET)
					 \10MB.MINPACKETLENGTH))
		   (\TEMPLOCKPAGES PACKET (COND
				     ((IGEQ BUFLENGTH \MIN2PAGEBUFLENGTH)
				       2)
				     (T 1)))                 (* Put on microcode queue)
		   (\QUEUE.OUTPUT.IOCB NDB IOCB (fetch 10MBPACKETBASE of PACKET)
				       BUFLENGTH)
		   T))
	      (\ENQUEUE (fetch NDBTQ of NDB)
			PACKET)                              (* Put on driver's queue to pick up after microcode 
							     finishes with it)
	      )
          (RETURN (AND IOCB T])

(\10MBENCAPSULATE
  [LAMBDA (NDB PACKET PDH LENGTH TYPE)                       (* bvm: " 7-MAR-83 12:44")
                                                             (* Encapsulates packets for 10mb net)
    (replace 10MBDESTHOST of PACKET with PDH)
    (replace 10MBSOURCEHOST of PACKET with \MY.NSHOSTNUMBER)
    (replace 10MBLENGTH of PACKET with (IPLUS (FOLDHI LENGTH BYTESPERWORD)
					      \10MBENCAPSULATION.WORDS))
    (replace 10MBTYPE of PACKET with TYPE)
    PACKET])

(\10MB.BROADCASTP
  [LAMBDA (PACKET)                                           (* bvm: "23-Apr-84 14:34")
    (fetch 10MBMULTICASTP of PACKET])

(\10MBWATCHER
  [LAMBDA (NDB)                                              (* bvm: "26-OCT-83 15:23")
                                                             (* Process that watches the 10mb net and pulls packets 
							     in. Decodes the type and passes packet to interested 
							     party)
    (PROG ((CNTR 0)
	   PACKET)
      LP  (UNINTERRUPTABLY
              (\10MB.INPUT.INTERRUPT NDB)
	      (\10MB.OUTPUT.INTERRUPT NDB))
          [COND
	    ((SETQ PACKET (\10MBGETPACKET))                  (* Got something)
	      (\HANDLE.RAW.PACKET PACKET)
	      (COND
		((ILESSP (add CNTR 1)
			 \MAXWATCHERGETS)                    (* Hack to get better ether service in lieu of 
							     preemption)
		  (GO LP]
          (BLOCK)
          (SETQ CNTR 0)
          (GO LP])
)



(* Machine independent part)

(DEFINEQ

(\10MB.STARTDRIVER
  (LAMBDA (NDB RESTARTFLG MYNSNUMBER)                        (* ejs: " 7-Sep-85 19:24")
    (\10MB.TURNOFFETHER NDB)
    (OR (\INIT.ETHER.BUFFER.POOL)
	(ERROR "Unable to create buffer pool"))
    (replace NDBTQ of NDB with (create SYSQUEUE))
    (SETQ \10MB.RAWPACKETQ (create SYSQUEUE))
    (SETQ \10MB.INPUT.TIMEOUT (TIMES \RCLKSECOND \10MB.EXPECTED.RECEIVE.INTERVAL))
    (\10MB.TURNONETHER NDB NIL NIL (OR MYNSNUMBER T)
		       0 0)
    (PROG ((LEN 0)
	   (IQ (fetch NDBIQ of NDB)))
          (COND
	    (IQ (SETQ LEN (\10MB.LOADINPUTQ NDB (fetch SYSQUEUEHEAD of IQ))))
	    (T (replace NDBIQ of NDB with (SETQ IQ (create SYSQUEUE)))))
          (bind IOCB PACKET to (IDIFFERENCE \10MB.IDEAL.INPUT.LENGTH LEN)
	     while (SETQ IOCB (\GET.IOCB (QUOTE INPUT)))
	     do (SETQ PACKET (\ALLOCATE.ETHERPACKET))
		(\TEMPLOCKPAGES PACKET 2)
		(replace EPNETWORK of PACKET with IOCB)
		(\QUEUE.INPUT.IOCB NDB IOCB (fetch 10MBPACKETBASE of PACKET)
				   \10MBPACKETLENGTH)        (* Add IOCB to microcode's queue)
		(\ENQUEUE IQ PACKET)                         (* and to driver's queue, so it can process it after 
							     arrival)
		(add LEN 1))
          (replace NDBIQLENGTH of NDB with LEN)
          (replace NDBWATCHER of NDB with (ADD.PROCESS (LIST (QUOTE \10MBWATCHER)
							     (KWOTE NDB))
						       (QUOTE RESTARTABLE)
						       (QUOTE SYSTEM)
						       (QUOTE AFTEREXIT)
						       (QUOTE DELETE)))
          (RETURN NDB))))

(\10MB.CREATENDB
  [LAMBDA (ETHERTASK#)                                       (* bvm: "15-Feb-85 22:18")
    (\10MB.STARTDRIVER (create NDB
			       NDBNSNET# ← 0
			       NDBPUPNET# ← 0
			       NETTYPE ← 10
			       NDBPUPTYPE ← \10MBTYPE.PUP
			       NDBTRANSMITTER ←(FUNCTION \10MBSENDPACKET)
			       NDBENCAPSULATOR ←(FUNCTION \10MBENCAPSULATE)
			       NDBBROADCASTP ←(FUNCTION \10MB.BROADCASTP)
			       NDBTASK# ← ETHERTASK#
			       NDBETHERFLUSHER ←(FUNCTION \10MB.TURNOFFETHER)
			       NDBCANHEARSELF ←(EQ \MACHINETYPE \DOLPHIN])

(\10MB.INPUT.INTERRUPT
  (LAMBDA (NDB)                                              (* ejs: "18-Sep-85 14:46")

          (* This routine gets called when 10MB input signals an interrupt. See if the head of the input queue has indeed been
	  processed, and if so, take care of it)


    (PROG ((PACKET (fetch SYSQUEUEHEAD of (fetch NDBIQ of NDB)))
	   STATUS ACCEPTPACKET IOCB)
          (COND
	    ((AND PACKET (NEQ (SETQ STATUS (\10MB.GETPACKETSTATUS (SETQ IOCB (fetch EPNETWORK
										of PACKET))))
			      \ES.PENDING))                  (* Yes, something is there, and microcode is finished 
							     with it)
	      (\DEQUEUE (fetch NDBIQ of NDB))
	      (COND
		(\10MB.COLLECTSTATS (\10MB.NOTESTAT STATUS PACKET (QUOTE INPUT))))
	      (COND
		((SETQ ACCEPTPACKET (OR (EQ STATUS \ES.GOOD.PACKET)
					\10MB.GETGARBAGE))
		  (PROG ((LENGTH (\10MB.GETPACKETLENGTH IOCB)))
                                                             (* Accept the packet)
		        (replace 10MBLENGTH of PACKET with LENGTH)
		        (\RCLK (LOCF (fetch EPTIMESTAMP of PACKET)))
		        (replace EPRECEIVING of PACKET with NIL)
		        (replace EPNETWORK of PACKET with NDB)
		        (replace EPTYPE of PACKET with (fetch 10MBTYPE of PACKET))
		        (COND
			  ((AND (OR (EQ \MACHINETYPE \DANDELION)
				    (EQ \MACHINETYPE \DAYBREAK))
				(IGREATERP LENGTH \MIN2PAGEBUFLENGTH))

          (* Dandelion ether uCode doesn't set the dirty bit on pages of PACKET, so make sure the second page gets marked 
	  dirty if it needs to be. The first page has been implicitly marked dirty by the replaces above)


			    (\PUTBASE PACKET (SUB1 (ITIMES WORDSPERPAGE 2))
				      0)))
		        (\TEMPUNLOCKPAGES PACKET 2)
		        (\ENQUEUE \10MB.RAWPACKETQ PACKET))
		  (PROGN                                     (* Now stuff a new buffer on queue)
			 (SETQ PACKET (\ALLOCATE.ETHERPACKET))
			 (\TEMPLOCKPAGES PACKET 2)
			 (replace EPNETWORK of PACKET with IOCB))))
                                                             (* Now stuff a buffer back on the input)
	      (\QUEUE.INPUT.IOCB NDB IOCB (fetch 10MBPACKETBASE of PACKET)
				 \10MBPACKETLENGTH)
	      (\ENQUEUE (fetch NDBIQ of NDB)
			PACKET))
	    (PACKET                                          (* There is something there, and the microcode is NOT 
							     finished with it)
		    (COND
		      ((NOT (fetch EPRECEIVING of PACKET))

          (* * Furthermore, this is the first time we've seen this packet at the head of the receive queue.
	  We timestamp it, and if it's still here sometime later, we kick the Ethernet receiver microcode, just in case it's 
	  turned itself off)


			(SETUPTIMER \10MB.INPUT.TIMEOUT \10MB.INPUT.TIMER (QUOTE TICKS))
			(replace EPRECEIVING of PACKET with T))
		      (T 

          (* * We've seen this packet before. Check for timeout, and kick the receiver microcode if necessary)


			 (COND
			   ((TIMEREXPIRED? \10MB.INPUT.TIMER (QUOTE TICKS))
			     (\10MB.RESTART.ETHER NDB)       (* Update the timestamp)
			     (SETUPTIMER \10MB.INPUT.TIMEOUT \10MB.INPUT.TIMER (QUOTE TICKS))))))))
          (RETURN ACCEPTPACKET))))

(\10MB.OUTPUT.INTERRUPT
  [LAMBDA (NDB)                                              (* bvm: "10-JUN-83 14:56")

          (* This routine gets called when 10MB output signals an interrupt. Remove the head of the output queue and put it on
	  the done queue)


    (PROG ((NEXTPACKET (fetch SYSQUEUEHEAD of (fetch NDBTQ of NDB)))
	   STATUS IOCB)
          (RETURN (COND
		    ((AND NEXTPACKET (OR (NULL (SETQ IOCB (fetch EPNETWORK of NEXTPACKET)))
					 (NEQ (SETQ STATUS (\10MB.GETPACKETSTATUS IOCB))
					      \ES.PENDING)))
                                                             (* Yes, microcode has finished processing this buffer)
		      (\DEQUEUE (fetch NDBTQ of NDB))
		      (replace EPTRANSMITTING of NEXTPACKET with NIL)
		      (replace EPNETWORK of NEXTPACKET with NIL)
		      (\REQUEUE.ETHERPACKET NEXTPACKET)
		      [COND
			(IOCB (\RELEASE.IOCB IOCB (QUOTE OUTPUT))
			      (\TEMPUNLOCKPAGES NEXTPACKET 2)
			      (COND
				(\10MB.COLLECTSTATS (\10MB.NOTESTAT STATUS NEXTPACKET (QUOTE OUTPUT]
		      T])

(\10MB.NOTESTAT
  [LAMBDA (STATUS BUF USE)                                   (* bvm: "15-JUL-82 14:43")
                                                             (* Increment counter associated with this status)
    NIL])
)

(RPAQ? \10MB.RCLK.BOX (CREATECELL \FIXP))

(RPAQ? \10MB.EXPECTED.RECEIVE.INTERVAL 60)

(RPAQ? \10MB.INPUT.TIMEOUT (TIMES \RCLKSECOND \10MB.EXPECTED.RECEIVE.INTERVAL))

(RPAQ? \10MB.INPUT.TIMER (SETUPTIMER 0))
(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS \10MB.RCLK.BOX \10MB.EXPECTED.RECEIVE.INTERVAL \10MB.INPUT.TIMEOUT \10MB.INPUT.TIMER)
)



(* Buffer management)

(DEFINEQ

(\10MB.LOADINPUTQ
  [LAMBDA (NDB PACKETS)                                      (* bvm: "28-FEB-83 17:36")

          (* PACKETS points at the first of several buffers of NDB's IQ. We load them into the microcode's chain.
	  Value returned is the number of buffers)


    (bind (CNT ← 0) while PACKETS
       do (\TEMPLOCKPAGES PACKETS 2)
	  (\QUEUE.INPUT.IOCB NDB (fetch EPNETWORK of PACKETS)
			     (fetch 10MBPACKETBASE of PACKETS)
			     \10MBPACKETLENGTH)
	  (SETQ PACKETS (fetch EPLINK of PACKETS))
	  (add CNT 1)
       finally (RETURN CNT])

(\RELEASE.IOCB
  [LAMBDA (IOCB USE)                                         (* bvm: " 3-MAR-83 16:17")
                                                             (* Returns an IOCB to the free pool.
							     USE is INPUT or OUTPUT, according to which side should 
							     be credited. Must be called uninterruptably)
    (COND
      ((NOT (AND IOCB (EMADDRESSP IOCB)))
	(ERROR "ARG NOT IOCB" IOCB))
      (T (SELECTQ USE
		  (INPUT (add \IOCB.INPUT.ALLOC 1))
		  (OUTPUT (add \IOCB.OUTPUT.ALLOC 1))
		  (\ILLEGAL.ARG USE))
	 (replace D0NEXTIOCB of IOCB with (\LOLOC \IOCBFREELIST))
                                                             (* (\LOLOC NIL) = 0 works also)
	 (SETQ \IOCBFREELIST IOCB)
	 NIL])

(\GET.IOCB
  [LAMBDA (USE)                                              (* edited: "14-Aug-85 16:46")

          (* returns a IOCB for INPUT or OUTPUT use, or NIL if none is available. This must be called uninterruptably, since 
	  we don't have any easy way of GCing these guys)


    (DECLARE (GLOBALVARS \10MBLOCALNDB))
    (COND
      ((AND \IOCBFREELIST (IGREATERP (SELECTQ USE
					      (INPUT \IOCB.INPUT.ALLOC)
					      (OUTPUT \IOCB.OUTPUT.ALLOC)
					      (\ILLEGAL.ARG USE))
				     0))
	(SELECTQ USE
		 (INPUT (add \IOCB.INPUT.ALLOC -1))
		 (add \IOCB.OUTPUT.ALLOC -1))

          (* * I removed the call to HELP that used to be in here. If the IOCB freelist goes NIL, the packet is dropped on the
	  floor)


	(PROG1 \IOCBFREELIST (SETQ \IOCBFREELIST (EMPOINTER (fetch D0NEXTIOCB of \IOCBFREELIST)))
                                                             (* Note that (EMPOINTER 0) = NIL, so this works even 
							     when free list runs out)
	       ])

(\INIT.ETHER.BUFFER.POOL
  [LAMBDA NIL                                                (* ejs: "26-Jul-85 23:14")

          (* Divides up the zone bcpl reserved for us into IOCB's used for sending/receiving ether packets.
	  The IOCB's must be quad-aligned. When an ether packet is to be sent, or prepared for receiving, an IOCB is assigned 
	  to it. The IOCB contains length and status info and a pointer to the ether packet buffer in Lisp space.
	  The IOCB's are chained for the microcode, and the packets are chained independently in Lisp space so that we can 
	  keep track of them after the microcode finishes. \IOCBFREELIST points at the first IOCB; there are a total of 
	  \IOCBTOTAL of them.)


    (PROG (LASTBUF BUFFER ZONE ZONELENGTH)
          (COND
	    ((EQ (SETQ ZONELENGTH (fetch (IFPAGE MDSZoneLength) of \InterfacePage))
		 0)                                          (* Bcpl was unable to allocate any space for us)
	      (SETQ \IOCBFREELIST NIL)
	      (SETQ \IOCBTOTAL 0)
	      (RETURN))
	    (T (SETQ ZONE (fetch (IFPAGE MDSZone) of \InterfacePage))
	       [SETQ ZONELENGTH (IDIFFERENCE ZONELENGTH (IDIFFERENCE ZONE (SETQ ZONE
								       (CEIL ZONE (ITIMES 2 
										     WORDSPERQUAD]
                                                             (* 8-align the zone, in case the microcode cares, and 
							     adjust the length downward if necessary)
	       (SETQ ZONE (EMPOINTER ZONE))                  (* Make an actual pointer)
	       ))
          (SETQ \IOCBTOTAL (IMIN (IQUOTIENT (IDIFFERENCE ZONELENGTH 3)
					    (SELECTC \MACHINETYPE
						     (\DAYBREAK \DoveEther.IOIOCBLength)
						     \IOCB.LENGTH))
				 \MAXIOCBS))
          (SETQ \IOCBFREELIST ZONE)
          (to \IOCBTOTAL
	     do                                              (* Link the idle IOCB's together using short addresses)
		[replace D0NEXTIOCB of ZONE with (\LOLOC (SETQ ZONE (\ADDBASE ZONE
									      (SELECTC \MACHINETYPE
										       (\DAYBREAK
											 
									  \DoveEther.IOIOCBLength)
										       \IOCB.LENGTH]
	     finally (replace D0NEXTIOCB of ZONE with 0))
          [SETQ \TELERAIDIOCB (PROG1 \IOCBFREELIST (SETQ \IOCBFREELIST (EMPOINTER (fetch D0NEXTIOCB
										     of \IOCBFREELIST]
                                                             (* Pop one off for TeleRaid)
          (add \IOCBTOTAL -1)
          [SETQ \IOCB.INPUT.ALLOC (SETQ \IOCB.INPUT.TOTAL (SETQ \IOCB.OUTPUT.ALLOC
		(SETQ \IOCB.OUTPUT.TOTAL (IQUOTIENT (ITIMES \IOCBTOTAL 2)
						    3]
          (SETQ \10MB.IDEAL.INPUT.LENGTH (IMIN \10MB.MAX.INPUT.LENGTH (IQUOTIENT \IOCBTOTAL 2)))
          (RETURN \IOCBTOTAL])
)

(RPAQ? \10MBPACKETLENGTH 448)



(* Dolphin/Dlion head)

(DEFINEQ

(\10MB.GETPACKETLENGTH
  (LAMBDA (IOCB)                                             (* ejs: "18-Sep-85 15:09")
    (SELECTC \MACHINETYPE
	     (\DANDELION (fetch DLIOCBBYTESUSED of IOCB))
	     (\DAYBREAK (fetch (Dove.EtherIOIOCB count) of IOCB))
	     (\DOLPHIN (FOLDLO (fetch D0IOCBBYTESUSED of IOCB)
			       BYTESPERWORD))
	     (\NOMACHINETYPE))))

(\10MB.GETPACKETSTATUS
  [LAMBDA (IOCB)                                             (* ejs: "26-Jul-85 22:43")

          (* * Translate device bits to device-independent constants)



          (* * Now allow odd-length packets to be received)


    (SELECTC \MACHINETYPE
	     [\DANDELION (PROG ((STATUS (fetch DLIOCBSTATUS of IOCB)))
			       (RETURN (COND
					 ((EQ STATUS 0)
					   \ES.PENDING)
					 [(EQ (fetch DLFOROUTPUTUSE of IOCB)
					      0)             (* Input errors)
					   (COND
					     ((EQ (fetch DLIOCBLENGTH of IOCB)
						  65535)
					       \ES.PACKET.TOO.LONG)
					     (T (COND
						  ((EQ (SETQ STATUS (LOGAND STATUS
									    (LOGOR \DL.BAD.ALIGNMENT 
										   \DL.OVERRUN 
										   \DL.BAD.CRC)))
						       0)
						    \ES.GOOD.PACKET)
						  ((NEQ (LOGAND STATUS \DL.OVERRUN)
							0)
						    \ES.OVERRUN)
						  ((NEQ (LOGAND STATUS \DL.BAD.CRC)
							0)
						    (COND
						      ((EQ (LOGAND STATUS (LOGOR \DL.BAD.ALIGNMENT 
										 \DL.ODDLENGTH))
							   0)
							\ES.BAD.CRC)
						      (T \ES.BAD.CRC&ALIGNMENT)))
						  ((NEQ (LOGAND STATUS \DL.BAD.ALIGNMENT)
							0)
						    \ES.BAD.ALIGNMENT)
						  (T \ES.OTHER.ERROR]
					 (T                  (* Output errors)
					    (COND
					      ((EQ (fetch DLRETRANSMISSIONMASK of IOCB)
						   8191)
						\ES.TOO.MANY.COLLISIONS)
					      (T (COND
						   ((EQ (LOGAND STATUS (LOGOR \DL.COLLISION 
									      \DL.UNDERRUN))
							0)
						     \ES.GOOD.PACKET)
						   (T \ES.UNDERRUN]
	     (\DAYBREAK (\DoveEther.GetPacketStatus IOCB))
	     [\DOLPHIN (PROG ((STATUS (fetch D0IOCBSTATUS of IOCB)))
			     (RETURN (SELECTC STATUS
					      (0 \ES.PENDING)
					      (\D0.GOOD.PACKET \ES.GOOD.PACKET)
					      (\D0.LATE.COLLISION \ES.LATE.COLLISION)
					      (\D0.TOO.MANY.COLLISIONS \ES.TOO.MANY.COLLISIONS)
					      (\D0.PACKET.TOO.LONG \ES.PACKET.TOO.LONG)
					      (\D0.BAD.ALIGNMENT \ES.BAD.ALIGNMENT)
					      (\D0.INPUT.BAD.CRC \ES.BAD.CRC)
					      ((LOGOR \D0.BAD.ALIGNMENT \D0.INPUT.BAD.CRC)
						\ES.BAD.CRC&ALIGNMENT)
					      (COND
						((NEQ (LOGAND STATUS \D0.INPUT.OVERRUN)
						      0)
						  \ES.OVERRUN)
						((NEQ (LOGAND STATUS \D0.OUTPUT.UNDERRUN)
						      0)
						  \ES.UNDERRUN)
						(T \ES.OTHER.ERROR]
	     (\NOMACHINETYPE])

(\QUEUE.INPUT.IOCB
  (LAMBDA (NDB IOCB BUFFER LENGTH)                           (* ejs: " 7-Sep-85 19:42")

          (* Add IOCB to the end of the microcode input queue, with BUFFER of LENGTH words as its buffer.
	  I.e., this is a buffer that packets will be read into)


    (PROG ((CSB (fetch NDBCSB of NDB)))
          (SELECTC \MACHINETYPE
		   (\DANDELION (replace DLFOROUTPUTUSE of IOCB with 0)
                                                             (* So that \10MB.GETPACKETSTATUS can tell which way 
							     packet is going)
			       (replace DLNEXTIOCB of IOCB with 0)
			       (replace DLRETRANSMISSIONMASK of IOCB with 0)
			       (replace DLIOCBSTATUS of IOCB with \ES.PENDING)
			       (replace DLIOCBLENGTH of IOCB with LENGTH)
			       (replace DLIOCBBUFFER of IOCB with BUFFER)
			       (COND
				 ((NEQ (fetch DLFIRSTICB of CSB)
				       0)                    (* There are some packets there, so add this to end)
				   (replace DLNEXTIOCB of (OR (EMPOINTER (fetch DLLASTICB
									    of CSB))
							      (RAID "Garbage last ICB"))
				      with (\LOLOC IOCB))))
			       (COND
				 ((AND (EQ (fetch DLFIRSTICB of CSB)
					   0)
				       (EQ (fetch DLIOCBSTATUS of IOCB)
					   \ES.PENDING))

          (* No buffers left, so queue this as the only one. While we were in the last clause, microcode could have eaten up 
	  its last buffer, which is why we test twice)


				   (replace DLFIRSTICB of CSB with (\LOLOC IOCB))
				   (\DEVICE.OUTPUT \DL.ENABLE.INPUT \DL.ETHERINPUTREG)))
			       (replace DLLASTICB of CSB with (\LOLOC IOCB)))
		   (\DAYBREAK (\DoveEther.QueueInput IOCB BUFFER LENGTH))
		   (\DOLPHIN (replace D0NEXTIOCB of IOCB with 0)
			     (replace D0RETRANSMISSIONMASK of IOCB with 0)
			     (replace D0IOCBSTATUS of IOCB with \ES.PENDING)
			     (replace D0IOCBLENGTH of IOCB with (UNFOLD LENGTH BYTESPERWORD))
			     (replace D0IOCBBUFFER of IOCB with BUFFER)
			     (COND
			       ((NEQ (fetch D0FIRSTICB of CSB)
				     0)                      (* There are some packets there, so add this to end)
				 (replace D0NEXTIOCB of (OR (EMPOINTER (fetch D0LASTICB of CSB))
							    (RAID "Garbage last ICB"))
				    with (\LOLOC IOCB))))
			     (COND
			       ((AND (EQ (fetch D0FIRSTICB of CSB)
					 0)
				     (EQ (fetch D0IOCBSTATUS of IOCB)
					 \ES.PENDING))

          (* No buffers left, so queue this as the only one. While we were in the last clause, microcode could have eaten up 
	  its last buffer, which is why we test twice)


				 (replace D0FIRSTICB of CSB with (\LOLOC IOCB))
				 (\DEVICE.OUTPUT \D0.ENABLE.10MBINPUT (\D0.CONTROLLERBITS NDB 
										   \D0.INPUTSTATE))))
			     (replace D0LASTICB of CSB with (\LOLOC IOCB)))
		   (\NOMACHINETYPE)))))

(\QUEUE.OUTPUT.IOCB
  [LAMBDA (NDB IOCB BUFFER LENGTH)                           (* ejs: "26-Jul-85 22:46")
                                                             (* Queue up IOCB for transmission.
							     LENGTH is length of BUFFER in words)
    (PROG ((CSB (fetch NDBCSB of NDB)))
          (SELECTC \MACHINETYPE
		   (\DANDELION (replace DLFOROUTPUTUSE of IOCB with 1)
                                                             (* So that \10MB.GETPACKETSTATUS can tell which way 
							     packet is going)
			       (replace DLIOCBLENGTH of IOCB with LENGTH)
			       (replace DLNEXTIOCB of IOCB with 0)
			       (replace DLRETRANSMISSIONMASK of IOCB with 0)
			       (replace DLIOCBSTATUS of IOCB with \ES.PENDING)
			       (replace DLIOCBBUFFER of IOCB with BUFFER)
			       [COND
				 ((NEQ (fetch DLFIRSTOCB of CSB)
				       0)                    (* Hardware active, add to end of chain)
				   (replace DLNEXTIOCB of (OR (EMPOINTER (fetch DLLASTOCB
									    of CSB))
							      (RAID "Garbage Last OCB"))
				      with (\LOLOC IOCB]
			       (COND
				 ((AND (EQ (fetch DLFIRSTOCB of CSB)
					   0)
				       (EQ (fetch DLIOCBSTATUS of IOCB)
					   \ES.PENDING))     (* Separate check, as the hardware could have just gone
							     idle since we last checked)
				   (replace DLFIRSTOCB of CSB with (\LOLOC IOCB))
				   (\DEVICE.OUTPUT \DL.ENABLE.OUTPUT \DL.ETHEROUTPUTREG)))
			       (replace DLLASTOCB of CSB with (\LOLOC IOCB)))
		   (\DAYBREAK (\DoveEther.QueueOutput IOCB BUFFER LENGTH))
		   (\DOLPHIN (replace D0IOCBLENGTH of IOCB with (UNFOLD LENGTH BYTESPERWORD))
			     (replace D0NEXTIOCB of IOCB with 0)
			     (replace D0RETRANSMISSIONMASK of IOCB with 0)
			     (replace D0IOCBSTATUS of IOCB with \ES.PENDING)
			     (replace D0IOCBBUFFER of IOCB with BUFFER)
			     [COND
			       ((NEQ (fetch D0FIRSTOCB of CSB)
				     0)                      (* Hardware active, add to end of chain)
				 (replace D0NEXTIOCB of (OR (EMPOINTER (fetch D0LASTOCB of CSB))
							    (RAID "Garbage Last OCB"))
				    with (\LOLOC IOCB]
			     [COND
			       ((AND (EQ (fetch D0FIRSTOCB of CSB)
					 0)
				     (EQ (fetch D0IOCBSTATUS of IOCB)
					 \ES.PENDING))       (* Separate check, as the hardware could have just gone
							     idle since we last checked)
				 (replace D0FIRSTOCB of CSB with (\LOLOC IOCB))
				 (\DEVICE.OUTPUT \D0.ENABLE.10MBOUTPUT (\D0.CONTROLLERBITS NDB 
										  \D0.OUTPUTSTATE]
			     (replace D0LASTOCB of CSB with (\LOLOC IOCB)))
		   (\NOMACHINETYPE])

(\10MB.TURNOFFETHER
  [LAMBDA (NDB)                                              (* ejs: "26-Jul-85 22:47")
    (SELECTC \MACHINETYPE
	     (\DANDELION (\DL.TURNOFFETHER))
	     (\DAYBREAK (\DoveEther.MakeSureOff))
	     (\DOLPHIN (\D0.TURNOFFETHER NDB))
	     (\NOMACHINETYPE])

(\10MB.TURNONETHER
  (LAMBDA (NDB SMASHSTATE NEWSTATE NSHOSTNUMBER ININTERRUPT OUTINTERRUPT)
                                                             (* ejs: "30-Oct-85 17:41")

          (* * Reset and activate ether associated with NDB. If SMASHSTATE is given, it is a CSB-length block into which 
	  state is saved for later restoration by passing as the NEWSTATE arg. If NEWSTATE is NIL, then the remaining non-NIL
	  args give parameters for this activation: the host number for microcode to watch for, T meaning my own number;
	  and interrupt masks for when a packet arrives or finishes transmitting)



          (* * For Daybreak, SMASHSTATE and NEWSTATE must be NIL)


    (PROG ((CSB (fetch NDBCSB of NDB)))
	    (SELECTC \MACHINETYPE
		       (\DANDELION (\DL.TURNOFFETHER))
		       (\DAYBREAK (\DoveEther.MakeSureOff SMASHSTATE))
		       (\DOLPHIN (\D0.TURNOFFETHER NDB))
		       (\NOMACHINETYPE))
	    (COND
	      ((AND SMASHSTATE (NEQ \MACHINETYPE \DAYBREAK))
		(COND
		  (CSB (\BLT SMASHSTATE CSB \CSB.LENGTH))
		  (T                                         (* Arcane way of indicating ether is off.
							     May have to revisit)
		     (\PUTBASE CSB 4 65535)))))
	    (COND
	      ((AND NEWSTATE (NEQ \MACHINETYPE \DAYBREAK))
                                                             (* Smash old state into CSB)
		(COND
		  ((EQ (\GETBASE NEWSTATE 4)
			 65535)                              (* Leave ether off)
		    (RETURN)))
		(\BLT CSB NEWSTATE \CSB.LENGTH))
	      (T (SELECTC \MACHINETYPE
			    (\DANDELION (OR CSB (replace NDBCSB of NDB
						     with (SETQ CSB (LOCF (fetch DLETHERNET
										 of \IOPAGE)))))
					(COND
					  (NEWSTATE          (* Smash old state into CSB)
                                                             (* I don't think you can get here! --ejs)
						    (COND
						      ((EQ (\GETBASE NEWSTATE 4)
							     65535)
                                                             (* Leave ether off)
							(RETURN)))
						    (\BLT CSB NEWSTATE \CSB.LENGTH))
					  (T                 (* Initialize the Ether CSB according to args.
							     No buffers initially)
					     (replace DLFIRSTOCB of CSB with 0)
					     (replace DLFIRSTICB of CSB with 0)
					     (AND NSHOSTNUMBER
						    (COND
						      ((EQ NSHOSTNUMBER T)
							(\BLT (LOCF (fetch DLLOCALHOST0
									 of CSB))
								(LOCF (fetch (IFPAGE NSHost0)
									 of \InterfacePage))
								\#WDS.NSHOSTNUMBER))
						      (T (\STORENSHOSTNUMBER (LOCF (fetch 
										     DLLOCALHOST0
											of CSB))
									       NSHOSTNUMBER))))
					     (AND OUTINTERRUPT (replace DLOUTPUTMASK
								    of CSB with OUTINTERRUPT))
					     (AND ININTERRUPT (replace DLINPUTMASK of CSB
								   with ININTERRUPT))
					     (replace DLMISSEDPACKETS of CSB with 0)
					     (replace DLLASTICB of CSB with 0)
					     (replace DLLASTOCB of CSB with 0)))
					(\DEVICE.OUTPUT \DL.ENABLE.INPUT \DL.ETHERINPUTREG))
			    (\DAYBREAK (\DoveEther.TurnOn NSHOSTNUMBER NEWSTATE))
			    (\DOLPHIN (OR CSB (replace NDBCSB of NDB
						   with (SETQ CSB
							    (EMPOINTER (IPLUS 65280
										(LLSH (fetch
											  NDBTASK#
											   of
											    NDB)
											4))))))
                                                             (* Initialize the Ether CSB according to args.
							     No buffers initially)
				      (replace D0FIRSTOCB of CSB with 0)
				      (replace D0FIRSTICB of CSB with 0)
				      (AND NSHOSTNUMBER
					     (COND
					       ((EQ NSHOSTNUMBER T)
						 (\BLT (LOCF (fetch D0LOCALHOST0 of CSB))
							 (LOCF (fetch (IFPAGE NSHost0)
								  of \InterfacePage))
							 \#WDS.NSHOSTNUMBER))
					       (T (\STORENSHOSTNUMBER (LOCF (fetch D0LOCALHOST0
										 of CSB))
									NSHOSTNUMBER))))
				      (AND OUTINTERRUPT (replace D0OUTPUTMASK of CSB
							     with OUTINTERRUPT))
				      (AND ININTERRUPT (replace D0INPUTMASK of CSB
							    with ININTERRUPT))
				      (replace D0LASTICB of CSB with 0)
				      (replace D0LASTOCB of CSB with 0)
				      (\DEVICE.OUTPUT \D0.ENABLE.10MBINPUT (\D0.CONTROLLERBITS
							  NDB \D0.INPUTSTATE)))
			    (\NOMACHINETYPE))))
	    (SELECTC \MACHINETYPE
		       (\DANDELION (\DEVICE.OUTPUT \DL.ENABLE.INPUT \DL.ETHERINPUTREG))
		       (\DAYBREAK)
		       (\DOLPHIN (\DEVICE.OUTPUT \D0.ENABLE.10MBINPUT (\D0.CONTROLLERBITS NDB 
										   \D0.INPUTSTATE)))
		       (\NOMACHINETYPE))
	    (RETURN NDB))))

(\10MB.RESTART.ETHER
  (LAMBDA (NDB)                                              (* ejs: "18-Sep-85 15:10")

          (* * Kick the Ethernet receiver microcode (or Daybreak IOP) to restart the Ethernet receiver task.
	  This function gets called when the 10MBDRIVER thinks the Ethernet has been accidentally disabled)


    (SELECTC \MACHINETYPE
	     (\DANDELION (\DEVICE.OUTPUT \DL.ENABLE.INPUT \DL.ETHERINPUTREG))
	     (\DOLPHIN (\DEVICE.OUTPUT \D0.ENABLE.10MBINPUT (\D0.CONTROLLERBITS NDB \D0.INPUTSTATE)))
	     (\DAYBREAK (\DoveIO.NotifyIOP (fetch (Dove.EtherFCB etherInWorkMask) of 
									    \DoveEther.FCBPointer)))
	     NIL)))
)
(DECLARE: EVAL@COMPILE DONTCOPY 

(RPAQQ 10MBDECLARATIONS ((COMS (RECORDS 10MBENCAPSULATION)
				 (CONSTANTS \10MBENCAPSULATION.WORDS))
			   (MACROS \D0.CONTROLLERBITS \D0.TURNOFFETHER \DL.TURNOFFETHER)
			   (RECORDS D0ETHERCSB D0ETHERIOCB DLETHERCSB DLETHERIOCB)
			   (CONSTANTS (\D0.ENABLE.10MBINPUT 49152)
				      (\D0.ENABLE.10MBOUTPUT 192)
				      (\D0.RESET.10MBCONTROLLER 512)
				      (\D0.INPUTSTATE 1)
				      (\D0.OUTPUTSTATE 2)
				      (\CSB.LENGTH 16)
				      (\IOCB.LENGTH 8)
				      (\MIN2PAGEBUFLENGTH 232)
				      (\10MB.MINPACKETLENGTH 30))
			   (CONSTANTS * DLIONETHERCONSTANTS)
			   (CONSTANTS * ETHERSTATUSCONSTANTS)
			   (CONSTANTS * D0ETHERSTATUSCONSTANTS)
			   (CONSTANTS * DLETHERSTATUSCONSTANTS)
			   (CONSTANTS (\MAXLLBUFFERPAGES 2)
				      (\MINLLBUFFERPAGES 1)
				      (\MAXIOCBS 64)
				      (\10MB.MAX.INPUT.LENGTH 20))
			   (GLOBALVARS \IOCB.INPUT.ALLOC \IOCB.INPUT.TOTAL \IOCB.OUTPUT.ALLOC 
				       \IOCB.OUTPUT.TOTAL \IOCBTOTAL \10MB.GETGARBAGE 
				       \10MB.RAWPACKETQ \10MB.IDEAL.INPUT.LENGTH \10MB.COLLECTSTATS 
				       \MACHINETYPE \10MBPACKETLENGTH \IOCBFREELIST)))
[DECLARE: EVAL@COMPILE 

(ACCESSFNS 10MBENCAPSULATION ((10MBBASE (LOCF (fetch (ETHERPACKET EPENCAPSULATION) of DATUM))))
			       (BLOCKRECORD 10MBBASE ((10MBLENGTH WORD)
                                                             (* Length of packet in words, starting at the next 
							     word. Not part of the actual packet;
							     it is here for convenience)
					       (10MBDESTHOST0 3 WORD)
                                                             (* Immediate destination host)
					       (10MBSOURCEHOST0 3 WORD)
                                                             (* Us)
					       (10MBTYPE WORD)
                                                             (* Type of packet -- PUP, NS)
					       )
					      (BLOCKRECORD 10MBBASE ((NIL WORD)
                                                             (* Length)
							      (NIL BITS 7)
							      (10MBMULTICASTP FLAG)
							      (NIL BITS 8)
                                                             (* Lo bit of first destination byte is the multicast 
							     bit)
							      ))
					      (ACCESSFNS 10MBDESTHOST0 ((10MBDESTHOST
							      (\LOADNSHOSTNUMBER (LOCF DATUM))
							      (\STORENSHOSTNUMBER (LOCF DATUM)
										    NEWVALUE))
							    (10MBPACKETBASE (LOCF DATUM))
							    (10MBDESTHOSTBASE (LOCF DATUM))))
					      (ACCESSFNS 10MBSOURCEHOST0
							   ((10MBSOURCEHOST (\LOADNSHOSTNUMBER
									      (LOCF DATUM))
									    (\STORENSHOSTNUMBER
									      (LOCF DATUM)
									      NEWVALUE))
							    (10MBSOURCEHOSTBASE (LOCF DATUM)))))
			       (TYPE? (type? ETHERPACKET DATUM)))
]
(DECLARE: EVAL@COMPILE 

(RPAQQ \10MBENCAPSULATION.WORDS 7)

(CONSTANTS \10MBENCAPSULATION.WORDS)
)
(DECLARE: EVAL@COMPILE 
(PUTPROPS \D0.CONTROLLERBITS MACRO ((NDB STATE)
	   (* Returns a TASKREG argument for use with \DEVICE.INPUT / OUTPUT for controller's STATE 
	      reg, 0 <= STATE < 15; \D0.ETHERTASKNUMBER is a global set in initialization)
	   (LOGOR (LLSH (fetch NDBTASK# of NDB)
			4)
		  STATE)))
(PUTPROPS \D0.TURNOFFETHER MACRO (OPENLAMBDA (NDB)
					     (\D0.STARTIO \D0.RESET.10MBCONTROLLER)))
(PUTPROPS \DL.TURNOFFETHER MACRO (NIL (PROGN (\DEVICE.OUTPUT \DL.TURNOFFETHER \DL.ETHERINPUTREG)
					     (to 3 repeatuntil (ZEROP (LOGAND (\DEVICE.INPUT 
									       \DL.ETHERSTATUSREG)
									      (LOGOR 
										\DL.INPUT.ENABLED 
									       \DL.OUTPUT.ENABLED)))))
				      ))
)
[DECLARE: EVAL@COMPILE 

(BLOCKRECORD D0ETHERCSB ((D0FIRSTOCB WORD)                 (* Short pointer to first OCB)
			   (D0OUTPUTMASK WORD)               (* Bit mask for output interrupt)
			   (D0INPUTMASK WORD)                (* Bit mask for input interrupt)
			   (D0MISSEDPACKETS WORD)            (* Count of missed packets 
							     (for debugging))
			   (D0FIRSTICB WORD)                 (* Short pointer to first ICB)
			   (D0LOCALHOST0 WORD)               (* Address we are listening for, 48d bits)
			   (D0LOCALHOST1 WORD)
			   (D0LOCALHOST2 WORD)
			   (D0UCODESCRATCH 4 WORD)           (* Scratch buffer for microcode)
			   (D0LASTICB WORD)                  (* Short pointer to last ICB if D0FIRSTICB non-null;
							     not used by microcode)
			   (D0LASTOCB WORD)                  (* last OCB if D0FIRSTOCB non-null)
			   (D0CSBSPARE 2 WORD)))

(BLOCKRECORD D0ETHERIOCB ((D0NEXTIOCB WORD)                (* Short pointer to next one)
			    (D0RETRANSMISSIONMASK WORD)      (* Retransmission mask, output only)
			    (NIL WORD)
			    (D0IOCBSTATUS WORD)              (* Completion code, filled in by microcode task)
			    (D0IOCBBYTESUSED WORD)           (* Number of bytes received)
			    (D0IOCBLENGTH WORD)              (* Length of buffer in bytes)
			    (D0IOCBBUFFERLO WORD)            (* Long pointer to buffer. Must be locked and quad-1 
							     aligned)
			    (D0IOCBBUFFERHI WORD))
			   (ACCESSFNS D0ETHERIOCB ((D0IOCBBUFFER (\VAG2 (fetch D0IOCBBUFFERHI
									       of DATUM)
									    (fetch D0IOCBBUFFERLO
									       of DATUM))
								   (PROGN (replace D0IOCBBUFFERHI
									       of DATUM
									       with (\HILOC
											NEWVALUE))
									    (replace D0IOCBBUFFERLO
									       of DATUM
									       with (\LOLOC
											NEWVALUE))))))
)

(BLOCKRECORD DLETHERCSB ((DLLOCALHOST0 WORD)               (* Address we are listening for, 48d bits)
			   (DLLOCALHOST1 WORD)
			   (DLLOCALHOST2 WORD)
			   (DLFIRSTICB WORD)                 (* Short pointer to first ICB)
			   (DLINPUTMASK WORD)                (* Bit mask for input interrupt)
			   (DLFIRSTOCB WORD)                 (* Short pointer to first OCB)
			   (DLOUTPUTMASK WORD)               (* Bit mask for output interrupt)
			   (DLMISSEDPACKETS WORD)            (* Count of missed packets 
							     (for debugging))
			   (DLLASTICB WORD)                  (* Short pointer to last ICB if DLFIRSTICB non-null;
							     not used by microcode)
			   (DLLASTOCB WORD)                  (* last OCB if DLFIRSTOCB non-null)
			   ))

(BLOCKRECORD DLETHERIOCB ((DLIOCBLENGTH WORD)              (* Length of buffer in bytes)
			    (DLIOCBBUFFERLO WORD)            (* Long pointer to buffer. Must be locked and quad-1 
							     aligned)
			    (DLIOCBBUFFERHI WORD)
			    (DLRETRANSMISSIONMASK WORD)      (* Retransmission mask, output only)
			    (DLIOCBBYTESUSED WORD)           (* Number of bytes received)
			    (DLIOCBSTATUS WORD)              (* Completion code, filled in by microcode task)
			    (DLNEXTIOCB WORD)                (* Short pointer to next one)
			    (DLFOROUTPUTUSE WORD)            (* Not used by microcode)
			    )
			   (ACCESSFNS DLETHERIOCB ((DLIOCBBUFFER (\VAG2 (fetch DLIOCBBUFFERHI
									       of DATUM)
									    (fetch DLIOCBBUFFERLO
									       of DATUM))
								   (PROGN (replace DLIOCBBUFFERHI
									       of DATUM
									       with (\HILOC
											NEWVALUE))
									    (replace DLIOCBBUFFERLO
									       of DATUM
									       with (\LOLOC
											NEWVALUE))))))
)
]
(DECLARE: EVAL@COMPILE 

(RPAQQ \D0.ENABLE.10MBINPUT 49152)

(RPAQQ \D0.ENABLE.10MBOUTPUT 192)

(RPAQQ \D0.RESET.10MBCONTROLLER 512)

(RPAQQ \D0.INPUTSTATE 1)

(RPAQQ \D0.OUTPUTSTATE 2)

(RPAQQ \CSB.LENGTH 16)

(RPAQQ \IOCB.LENGTH 8)

(RPAQQ \MIN2PAGEBUFLENGTH 232)

(RPAQQ \10MB.MINPACKETLENGTH 30)

(CONSTANTS (\D0.ENABLE.10MBINPUT 49152)
	   (\D0.ENABLE.10MBOUTPUT 192)
	   (\D0.RESET.10MBCONTROLLER 512)
	   (\D0.INPUTSTATE 1)
	   (\D0.OUTPUTSTATE 2)
	   (\CSB.LENGTH 16)
	   (\IOCB.LENGTH 8)
	   (\MIN2PAGEBUFLENGTH 232)
	   (\10MB.MINPACKETLENGTH 30))
)

(RPAQQ DLIONETHERCONSTANTS ((\DL.ETHERINPUTREG 5)
			      (\DL.ETHEROUTPUTREG 12)
			      (\DL.ETHERSTATUSREG 1)
			      (\DL.TURNOFFETHER 2)
			      (\DL.ENABLE.OUTPUT 1)
			      (\DL.ENABLE.INPUT 1)
			      (\DL.INPUT.ENABLED 1024)
			      (\DL.OUTPUT.ENABLED 256)))
(DECLARE: EVAL@COMPILE 

(RPAQQ \DL.ETHERINPUTREG 5)

(RPAQQ \DL.ETHEROUTPUTREG 12)

(RPAQQ \DL.ETHERSTATUSREG 1)

(RPAQQ \DL.TURNOFFETHER 2)

(RPAQQ \DL.ENABLE.OUTPUT 1)

(RPAQQ \DL.ENABLE.INPUT 1)

(RPAQQ \DL.INPUT.ENABLED 1024)

(RPAQQ \DL.OUTPUT.ENABLED 256)

(CONSTANTS (\DL.ETHERINPUTREG 5)
	   (\DL.ETHEROUTPUTREG 12)
	   (\DL.ETHERSTATUSREG 1)
	   (\DL.TURNOFFETHER 2)
	   (\DL.ENABLE.OUTPUT 1)
	   (\DL.ENABLE.INPUT 1)
	   (\DL.INPUT.ENABLED 1024)
	   (\DL.OUTPUT.ENABLED 256))
)

(RPAQQ ETHERSTATUSCONSTANTS ((\ES.PENDING 0)
			       (\ES.GOOD.PACKET 1)
			       (\ES.PACKET.TOO.LONG 2)
			       (\ES.BAD.CRC 3)
			       (\ES.BAD.CRC&ALIGNMENT 4)
			       (\ES.BAD.ALIGNMENT 5)
			       (\ES.OVERRUN 6)
			       (\ES.TOO.MANY.COLLISIONS 7)
			       (\ES.UNDERRUN 8)
			       (\ES.LATE.COLLISION 9)
			       (\ES.OTHER.ERROR 10)))
(DECLARE: EVAL@COMPILE 

(RPAQQ \ES.PENDING 0)

(RPAQQ \ES.GOOD.PACKET 1)

(RPAQQ \ES.PACKET.TOO.LONG 2)

(RPAQQ \ES.BAD.CRC 3)

(RPAQQ \ES.BAD.CRC&ALIGNMENT 4)

(RPAQQ \ES.BAD.ALIGNMENT 5)

(RPAQQ \ES.OVERRUN 6)

(RPAQQ \ES.TOO.MANY.COLLISIONS 7)

(RPAQQ \ES.UNDERRUN 8)

(RPAQQ \ES.LATE.COLLISION 9)

(RPAQQ \ES.OTHER.ERROR 10)

(CONSTANTS (\ES.PENDING 0)
	   (\ES.GOOD.PACKET 1)
	   (\ES.PACKET.TOO.LONG 2)
	   (\ES.BAD.CRC 3)
	   (\ES.BAD.CRC&ALIGNMENT 4)
	   (\ES.BAD.ALIGNMENT 5)
	   (\ES.OVERRUN 6)
	   (\ES.TOO.MANY.COLLISIONS 7)
	   (\ES.UNDERRUN 8)
	   (\ES.LATE.COLLISION 9)
	   (\ES.OTHER.ERROR 10))
)

(RPAQQ D0ETHERSTATUSCONSTANTS ((\D0.BAD.ALIGNMENT 2048)
				 (\D0.INPUT.OVERRUN 1024)
				 (\D0.INPUT.BAD.PACKET 512)
				 (\D0.INPUT.BAD.CRC 256)
				 (\D0.OUTPUT.UNDERRUN 64)
				 (\D0.COLLISION 32)
				 (\D0.OUTPUT.BAD.PARITY 128)
				 (\D0.OUTPUT.FAULT 16)
				 (\D0.GOOD.PACKET 16384)
				 (\D0.PACKET.TOO.LONG 25088)
				 (\D0.TOO.MANY.COLLISIONS 25600)
				 (\D0.LATE.COLLISION 26112)
				 (\D0.BUFFER.TOO.SHORT 26624)))
(DECLARE: EVAL@COMPILE 

(RPAQQ \D0.BAD.ALIGNMENT 2048)

(RPAQQ \D0.INPUT.OVERRUN 1024)

(RPAQQ \D0.INPUT.BAD.PACKET 512)

(RPAQQ \D0.INPUT.BAD.CRC 256)

(RPAQQ \D0.OUTPUT.UNDERRUN 64)

(RPAQQ \D0.COLLISION 32)

(RPAQQ \D0.OUTPUT.BAD.PARITY 128)

(RPAQQ \D0.OUTPUT.FAULT 16)

(RPAQQ \D0.GOOD.PACKET 16384)

(RPAQQ \D0.PACKET.TOO.LONG 25088)

(RPAQQ \D0.TOO.MANY.COLLISIONS 25600)

(RPAQQ \D0.LATE.COLLISION 26112)

(RPAQQ \D0.BUFFER.TOO.SHORT 26624)

(CONSTANTS (\D0.BAD.ALIGNMENT 2048)
	   (\D0.INPUT.OVERRUN 1024)
	   (\D0.INPUT.BAD.PACKET 512)
	   (\D0.INPUT.BAD.CRC 256)
	   (\D0.OUTPUT.UNDERRUN 64)
	   (\D0.COLLISION 32)
	   (\D0.OUTPUT.BAD.PARITY 128)
	   (\D0.OUTPUT.FAULT 16)
	   (\D0.GOOD.PACKET 16384)
	   (\D0.PACKET.TOO.LONG 25088)
	   (\D0.TOO.MANY.COLLISIONS 25600)
	   (\D0.LATE.COLLISION 26112)
	   (\D0.BUFFER.TOO.SHORT 26624))
)

(RPAQQ DLETHERSTATUSCONSTANTS ((\DL.COLLISION 64)
				 (\DL.UNDERRUN 32)
				 (\DL.BAD.ALIGNMENT 16)
				 (\DL.OVERRUN 8)
				 (\DL.BAD.CRC 4)
				 (\DL.ODDLENGTH 2)))
(DECLARE: EVAL@COMPILE 

(RPAQQ \DL.COLLISION 64)

(RPAQQ \DL.UNDERRUN 32)

(RPAQQ \DL.BAD.ALIGNMENT 16)

(RPAQQ \DL.OVERRUN 8)

(RPAQQ \DL.BAD.CRC 4)

(RPAQQ \DL.ODDLENGTH 2)

(CONSTANTS (\DL.COLLISION 64)
	   (\DL.UNDERRUN 32)
	   (\DL.BAD.ALIGNMENT 16)
	   (\DL.OVERRUN 8)
	   (\DL.BAD.CRC 4)
	   (\DL.ODDLENGTH 2))
)
(DECLARE: EVAL@COMPILE 

(RPAQQ \MAXLLBUFFERPAGES 2)

(RPAQQ \MINLLBUFFERPAGES 1)

(RPAQQ \MAXIOCBS 64)

(RPAQQ \10MB.MAX.INPUT.LENGTH 20)

(CONSTANTS (\MAXLLBUFFERPAGES 2)
	   (\MINLLBUFFERPAGES 1)
	   (\MAXIOCBS 64)
	   (\10MB.MAX.INPUT.LENGTH 20))
)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS \IOCB.INPUT.ALLOC \IOCB.INPUT.TOTAL \IOCB.OUTPUT.ALLOC \IOCB.OUTPUT.TOTAL \IOCBTOTAL 
	    \10MB.GETGARBAGE \10MB.RAWPACKETQ \10MB.IDEAL.INPUT.LENGTH \10MB.COLLECTSTATS 
	    \MACHINETYPE \10MBPACKETLENGTH \IOCBFREELIST)
)
)



(* Misc)

(DEFINEQ

(\NOMACHINETYPE
  [LAMBDA NIL                                                (* bvm: "24-JUL-82 17:47")
    (RAID "Operation not implemented on this machine"])
)
(DEFINEQ

(IOCBQLENGTH
  [LAMBDA (FIRSTIOCB)                                        (* bvm: " 2-MAR-83 17:52")
    (OR FIRSTIOCB (SETQ FIRSTIOCB \IOCBFREELIST))
    (while FIRSTIOCB sum (PROGN (SETQ FIRSTIOCB (EMPOINTER (fetch D0NEXTIOCB of FIRSTIOCB)))
				1])
)

(RPAQ? \10MB.GETGARBAGE NIL)

(RPAQ? \10MB.COLLECTSTATS NIL)



(* PUP address resolution)

(DEFINEQ

(\HANDLE.RAW.3TO10
  [LAMBDA (PACKET TYPE)                                      (* bvm: "15-Feb-85 21:11")

          (* Called when a TRANSLATION packet is received. This is either a packet requesting a 10-to-3 translation, in which 
	  case we respond if it is asking about us; or it is a response to a request of ours, in which case we store the info 
	  in the cache)


    (COND
      ((EQ TYPE \10MBTYPE.3TO10)
	(PROG ((NDB (fetch EPNETWORK of PACKET)))
	      (AND XIPTRACEFLG (\MAYBEPRINTPACKET PACKET (QUOTE GET)))
	      [SELECTC (fetch TRANSOPERATION of PACKET)
		       [\TRANS.OP.REQUEST (COND
					    ((EQ (fetch TRANSPUPHOST of PACKET)
						 (fetch NDBPUPHOST# of NDB))
                                                             (* It's for us)
					      (COND
						((IGEQ (fetch 10MBLENGTH of PACKET)
						       (IPLUS \10MBENCAPSULATION.WORDS
							      (FOLDHI \TRANS.DATALENGTH BYTESPERWORD))
						       )     (* Add sender's address to cache)
						  (\NOTE.3TO10 (fetch TRANSSENDERNSHOST of PACKET)
							       (fetch TRANSSENDERPUPHOST
								  of PACKET)
							       NDB)))
					      (replace TRANSNSHOST of PACKET with (\LOCALNSHOSTNUMBER)
						       )     (* Add in the information he wants)
					      (replace TRANSOPERATION of PACKET with 
									       \TRANS.OP.RESPONSE)
					      (ENCAPSULATE.ETHERPACKET NDB PACKET
								       (fetch TRANSSENDERNSHOST
									  of PACKET)
								       \TRANS.DATALENGTH 
								       \10MBTYPE.3TO10)
                                                             (* Send back the response)
					      (AND XIPTRACEFLG (NOT (MEMB (QUOTE TRANS)
									  XIPIGNORETYPES))
						   (PRINT3TO10 PACKET (QUOTE PUT)
							       XIPTRACEFILE))
					      (replace EPREQUEUE of PACKET with (QUOTE FREE))
					      (TRANSMIT.ETHERPACKET NDB PACKET)
					      (RETURN]
		       (\TRANS.OP.RESPONSE                   (* Add the information to the cache)
					   (\NOTE.3TO10 (fetch TRANSNSHOST of PACKET)
							(fetch TRANSPUPHOST of PACKET)
							NDB))
		       (COND
			 (XIPTRACEFLG (ERROR "Bad 3:10 operation" PACKET]
	      (\RELEASE.ETHERPACKET PACKET))
	T])

(\TRANSLATE.3TO10
  [LAMBDA (PUPHOSTNUMBER NDB)                                (* bvm: "15-Feb-85 21:11")

          (* Translate from an PUPHOSTNUMBER to a NSHOSTNUMBER for the indicated network. If we don't have the translation, we
	  initiate a probe for it and return NIL)


    (OR [CADR (ASSOC PUPHOSTNUMBER (ffetch NDBTRANSLATIONS of (\DTEST NDB (QUOTE NDB]
	(PROG ((MYPUPHOSTNUMBER (ffetch NDBPUPHOST# of NDB))
	       PACKET)
	      (COND
		((EQ MYPUPHOSTNUMBER 0)                      (* We don't know who we are yet)
		  (RETURN)))
	      (SETQ PACKET (\ALLOCATE.ETHERPACKET))
	      (replace EPTYPE of PACKET with \EPT.3TO10)
	      (freplace TRANSOPERATION of PACKET with \TRANS.OP.REQUEST)
	      (freplace TRANSPUPHOST of PACKET with PUPHOSTNUMBER)
	      (freplace TRANSSENDERNSHOST of PACKET with (\LOCALNSHOSTNUMBER))
	      (freplace TRANSSENDERPUPHOST of PACKET with MYPUPHOSTNUMBER)
	      (ENCAPSULATE.ETHERPACKET NDB PACKET BROADCASTNSHOSTNUMBER \TRANS.DATALENGTH 
				       \10MBTYPE.3TO10)
	      (AND XIPTRACEFLG (\MAYBEPRINTPACKET PACKET (QUOTE PUT)))
	      (freplace EPREQUEUE of PACKET with (QUOTE FREE))
	      (TRANSMIT.ETHERPACKET NDB PACKET)              (* We didn't find out this time, but we will later on)
	      (RETURN])

(PRINT3TO10
  [LAMBDA (EPKT CALLER FILE PRE.NOTE DOFILTER)               (* bvm: "14-Feb-85 21:21")
    (COND
      ((OR (NOT DOFILTER)
	   (NOT (MEMB (QUOTE TRANS)
		      XIPIGNORETYPES)))
	(OR FILE (SETQ FILE XIPTRACEFILE))
	(FRESHLINE FILE)
	(COND
	  (PRE.NOTE (PRIN1 PRE.NOTE FILE)))
	(SELECTC (fetch TRANSOPERATION of EPKT)
		 (\TRANS.OP.REQUEST (printout FILE CALLER " 3:10 trans request for "
					      (fetch TRANSPUPHOST of EPKT)
					      " from "
					      (fetch TRANSSENDERPUPHOST of EPKT)
					      " = ")
				    (PRINTNSHOSTNUMBER (fetch TRANSSENDERNSHOST of EPKT)
						       FILE))
		 (\TRANS.OP.RESPONSE (printout FILE CALLER " 3:10 trans response: "
					       (fetch TRANSPUPHOST of EPKT)
					       " = ")
				     (PRINTNSHOSTNUMBER (fetch TRANSNSHOST of EPKT)
							FILE))
		 (printout FILE CALLER " unknown 10 to 3 translation operation "
			   (fetch TRANSOPERATION of EPKT)))
	(TERPRI FILE])

(\NOTE.3TO10
  [LAMBDA (NSHOST PUPHOST NDB)                               (* bvm: "26-MAR-83 15:03")
                                                             (* Update cache to include this pairing)
    (PROG [(A (ASSOC PUPHOST (ffetch NDBTRANSLATIONS of (\DTEST NDB (QUOTE NDB]
          (COND
	    (A (RPLACA (CDR A)
		       NSHOST))
	    (T (push (ffetch NDBTRANSLATIONS of NDB)
		     (LIST PUPHOST NSHOST (CLOCK 0])
)

(RPAQ? \10MBTYPE.PUP 512)

(RPAQ? \10MBTYPE.3TO10 513)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(GLOBALVARS \10MBTYPE.3TO10 \10MBTYPE.PUP)
)
(DECLARE: EVAL@COMPILE 

(RPAQQ \EPT.3TO10 513)

(CONSTANTS \EPT.3TO10)
)

(ADDTOVAR \PACKET.PRINTERS (513 . PRINT3TO10))
(DECLARE: EVAL@COMPILE DONTCOPY 
(FILESLOAD (LOADCOMP)
	   DOVEETHER LLETHER LLNS)
)
(PUTPROPS 10MBDRIVER COPYRIGHT ("Xerox Corporation" 1982 1983 1984 1985))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (2015 6106 (\10MBGETPACKET 2025 . 2348) (\10MBSENDPACKET 2350 . 4521) (\10MBENCAPSULATE 
4523 . 5067) (\10MB.BROADCASTP 5069 . 5228) (\10MBWATCHER 5230 . 6104)) (6144 13443 (\10MB.STARTDRIVER
 6154 . 7888) (\10MB.CREATENDB 7890 . 8478) (\10MB.INPUT.INTERRUPT 8480 . 12016) (
\10MB.OUTPUT.INTERRUPT 12018 . 13203) (\10MB.NOTESTAT 13205 . 13441)) (13835 19275 (\10MB.LOADINPUTQ 
13845 . 14470) (\RELEASE.IOCB 14472 . 15275) (\GET.IOCB 15277 . 16357) (\INIT.ETHER.BUFFER.POOL 16359
 . 19273)) (19342 34467 (\10MB.GETPACKETLENGTH 19352 . 19745) (\10MB.GETPACKETSTATUS 19747 . 22293) (
\QUEUE.INPUT.IOCB 22295 . 25484) (\QUEUE.OUTPUT.IOCB 25486 . 28470) (\10MB.TURNOFFETHER 28472 . 28770)
 (\10MB.TURNONETHER 28772 . 33780) (\10MB.RESTART.ETHER 33782 . 34465)) (46863 47046 (\NOMACHINETYPE 
46873 . 47044)) (47047 47350 (IOCBQLENGTH 47057 . 47348)) (47456 52884 (\HANDLE.RAW.3TO10 47466 . 
49887) (\TRANSLATE.3TO10 49889 . 51334) (PRINT3TO10 51336 . 52387) (\NOTE.3TO10 52389 . 52882)))))
STOP