Google
 

Trailing-Edge - PDP-10 Archives - BB-F492Z-DD_1986 - 10,7/703mon/ethser.mac
There are 6 other files named ethser.mac in the archive. Click here to see a list.
	TITLE	ETHSER - ETHERNET SERVICE ROUTINES	V30
	SUBTTL	WILLIAM C. DAVENPORT/WXD	19-NOV-85


	SEARCH	F,S,MACSYM,ETHPRM
	T20SYM
	$RELOC
	$HIGH

;
;            H    H         H    H
;            |    |         |    |
;       H -- C -- C -- O -- C -- C -- H
;            |    |         |    |
;            H    H         H    H
;
;   ETHER, THE CODE THAT PUTS YOU TO SLEEP.

;THIS MODULE IMPLEMENTS A DEVICE INDEPENDENT INTERFACE TO ETHERNET

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY ONLY BE USED
;  OR COPIED IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.

.CPYRT<1985,1986>
;COPYRIGHT (C) 1985,1986 BY
;DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
;ALL RIGHTS RESERVED.



	XP	VETHSR,30	;ETHSER VERSION NUMBER

	ENTRY	ETHSER		;LOAD IF LIBRARY SEARCH


;LOOSE ENDS:
;	MULTI-CHANNEL ETHERNET SUPPORT
;	DYNAMIC KONTROLLER CONFIGURATION
	SUBTTL	TABLE OF CONTENTS


;               TABLE OF CONTENTS FOR ETHSER
;
;
;                        SECTION                                   PAGE
;    1. TABLE OF CONTENTS.........................................   2
;    2. ETHERNET SERVICE
;         2.1   INITIALIZATION....................................   3
;         2.2   ONCE A SECOND CODE................................   4
;         2.3   ETHERNET CHANNEL ONCE A SECOND CODE...............   5
;         2.4   ETHERNET PORTAL ONCE A SECOND CODE................   6
;         2.5   ETHERNET KONTROLLER ONCE A SECOND CODE............   7
;    3. ETHERNET USER SERVICE
;         3.1   FUNCTION DISPATCH.................................   8
;         3.2   OPEN PORTAL FUNCTION..............................  13
;         3.3   CLOSE PORTAL FUNCTION.............................  15
;         3.4   RECEIVE DATAGRAM FUNCTION.........................  16
;         3.5   TRANSMIT DATAGRAM FUNCTION........................  18
;         3.6   ENABLE MULTI-CAST ADDRESS FUNCTION................  20
;         3.7   DISABLE MULTI-CAST ADDRESS FUNCTION...............  21
;         3.8   READ CHANNEL LIST FUNCTION........................  22
;         3.9   READ CHANNEL INFORMATION FUNCTION.................  23
;         3.10  READ CHANNEL COUNTERS FUNCTION....................  24
;         3.11  SET CHANNEL ADDRESS FUNCTION......................  27
;         3.12  READ PORTAL LIST FUNCTION.........................  29
;         3.13  READ PORTAL INFORMATION FUNCTION..................  30
;         3.14  READ PORTAL COUNTERS FUNCTION.....................  31
;         3.15  READ KONTROLLER LIST..............................  33
;         3.16  READ KONTROLLER INFORMATION.......................  34
;         3.17  READ KONTROLLER COUNTERS..........................  35
;         3.18  READ ETHERNET LIST................................  38
;         3.19  READ ETHERNET INFORMATION.........................  39
;         3.20  REPORT PORTAL STATUS CHANGE.......................  40
;         3.21  CALL PORTAL USER..................................  41
;         3.22  GENERATE AN EA BLOCK..............................  42
;         3.23  RELEASE EA BLOCK..................................  43
;         3.24  CALL ETHERNET KONTROLLER..........................  44
;    4. ETHERNET CHANNEL SUPPORT
;         4.1   CREATE ETHERNET CHANNEL BLOCK.....................  45
;         4.2   GENERATE CHANNEL STATUS WORD......................  46
;         4.3   FIND ETHERNET CHANNEL BLOCK.......................  47
;    5. ETHERNET PORTAL SUPPORT
;         5.1   GENERATE ETHERNET PORTAL ID.......................  48
;         5.2   GENERATE PORTAL STATUS WORD.......................  49
;         5.3   FIND ETHERNET PORTAL BLOCK........................  50
;         5.4   ADD ETHERNET PORTAL BLOCK.........................  51
;         5.5   DELETE ETHERNET PORTAL BLOCK......................  52
;         5.6   FIND MULTI-CAST ADDRESS...........................  53
;         5.7   ADD MULTI-CAST ADDRESS............................  54
;         5.8   DELETE MULTI-CAST ADDRESS.........................  55
;         5.9   ENABLE PROTOCOL...................................  56
;         5.10  DISABLE PROTOCOL..................................  59
;         5.11  PROTOCOL STATE TRANSTITION........................  62
;    6. ETHERNET KONTROLLER SUPPORT
;         6.1   CREATE KONTROLLER BLOCK...........................  63
;         6.2   GENERATE KONTROLLER STATUS WORD...................  64
;         6.3   SELECT AN ETHERNET KONTROLLER.....................  65
;         6.4   FIND ETHERNET KONTROLLER BLOCK....................  66
;         6.5   ADD ETHERNET KONTROLLER BLOCK.....................  67
;    7. ETHERNET INTERRUPT SERVICE
;         7.1   KONTROLLER INITIALIZATION.........................  68
;         7.2   KONTROLLER OFFLINE................................  69
;         7.3   KONTROLLER ONLINE.................................  70
;         7.4   KONTROLLER FUNCTION DONE..........................  71
;    8. ETHERNET SUPPORT
;         8.1   UPDATE ETHERNET COUNTERS..........................  72
;         8.2   GENERATE TWO WORD GLOBAL BYTE POINTER.............  73
;    9. BYTE POINTERS.............................................  74
;   10. ETHERNET INFORMATION GETTAB TABLE.........................  75
;   11. THE END...................................................  76
	SUBTTL	ETHERNET SERVICE  --  INITIALIZATION


;ROUTINE CALLED TO INITIALIZE ETHERNET SERVICE
;LINKAGE: (CALLED FROM SYSINI)
;	PUSHJ	P,ETHINI
;RETURNS:
;	CPOPJ ALWAYS


ETHINI::SKIPE	%EICHN		;SYSTEM RESTART?
	POPJ	P,		;YES, RETURN
	PUSHJ	P,SAVQ1##	;SAVE Q1
	SE1ENT			;RUN IN SECTION 1
	PUSHJ	P,GENECB	;CREATE AN ETHERNET CHANNEL BLOCK
	  POPJ	P,		;ERROR, RETURN
	MOVX	T1,ECSONL	;MARK CHANNEL AS ONLINE
	IORM	T1,ECBSTS(Q1)	;...
IFN FTDECNET,<			;IF DECNET SUPPORT
	SKIPN	[M.DECN##]	;IS DECNET LOADED?
	JRST	ETHIN1		;NO, DON'T PRESET ETHERNET ADDRESS
	MOVE	T1,RTRHIO##	;GET HIGH ORDER DECNET ETHERNET ADDRESS
	SETZ	T2,		;CLEAR LOW ORDER ETHERNET ADDRESS
	MOVE	T3,RTRHOM##	;GET OUR DECNET AREA NUMBER
	LSH	T3,^D10		;POSITION CORRECTLY
	IOR	T3,RTRADR##	;COMBINE WITH OUR DECNET NODE ADDRESS
	ROTC	T2,-^D8		;GET LOW ORDER BYTE OF DECNET ADDRESS
	DPB	T3,[POINT 8,T2,15] ;AND INCLUDE HIGH ORDER BYTE OF ADDRESS
	DMOVEM	T1,ECBEAD(Q1)	;SAVE AS CHANNEL'S ETHERNET ADDRESS
ETHIN1:
>; END IFN FTDECNET
	POPJ	P,		;AND RETURN
	SUBTTL	ETHERNET SERVICE  --  ONCE A SECOND CODE


;ROUTINE CALLED ONCE A SECOND BY CLOCK1
;LINKAGE:
;	PUSHJ	P,ETHSEC
;RETURNS:
;	CPOPJ ALWAYS

ETHSEC::
IFN FTMP,<
	SKPCPU	(0)		;ARE WE ON POLICY CPU?
	POPJ	P,		;NO, RETURN
>; END IFN FTMP
	PUSHJ	P,SAVQ1##	;SAVE Q1
	SE1ENT			;RUN IN SECTION 1
	SKIPA	Q1,%EICHN	;GET ADDRESS OF FIRST CHANNEL BLOCK
ETHSE1:	MOVE	Q1,ECBSYS(Q1)	;GET ADDRESS OF NEXT CHANNEL BLOCK
	PJUMPE	Q1,CPOPJ##	;IF END OF LIST, RETURN
	PUSHJ	P,ECBSEC	;DO CHANNEL ONCE A SECOND PROCESSING
	JRST	ETHSE1		;LOOP BACK FOR ALL CHANNELS
	SUBTTL	ETHERNET SERVICE  --  ETHERNET CHANNEL ONCE A SECOND CODE


;ROUTINE CALLED ONCE A SECOND FOR EACH ETHERNET CHANNEL
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	PUSHJ	P,ECBSEC
;RETURNS:
;	CPOPJ ALWAYS

ECBSEC:	PUSHJ	P,SAVQ##	;SAVE Q1-Q3
	AOS	ECBCTR+CC.SLZ(Q1) ;UPDATE SECONDS SINCE COUNTERS LAST ZEROED
	SKIPA	Q2,ECBEPB(Q1)	;GET ADDRESS OF FIRST PORTAL BLOCK
ECBSE1:	MOVE	Q2,EPBNXT(Q2)	;GET ADDRESS OF NEXT PORTAL BLOCK
	JUMPE	Q2,ECBSE2	;IF END OF LIST, GO DO KONTROLLERS
	MOVE	Q3,EPBEKB(Q2)	;GET ADDRESS OF ASSIGNED KONTROLLER BLOCK
	PUSHJ	P,EPBSEC	;DO PORTAL ONCE A SECOND PROCESSING
	JRST	ECBSE1		;LOOP BACK FOR ALL PORTALS
ECBSE2:	SKIPA	Q3,ECBEKB(Q1)	;GET ADDRESS OF FIRST KONTROLLER BLOCK
ECBSE3:	MOVE	Q3,EKBNXT(Q3)	;GET ADDRESS OF NEXT KONTROLLER BLOCK
	PJUMPE	Q3,CPOPJ##	;RETURN AT END OF LIST
	PUSHJ	P,EKBSEC	;DO KONTROLLER ONCE A SECOND PROCESSING
	JRST	ECBSE3		;LOOP BACK FOR ALL KONTROLLERS
	SUBTTL	ETHERNET SERVICE  --  ETHERNET PORTAL ONCE A SECOND CODE


;ROUTINE CALLED ONCE A SECOND FOR EACH ETHERNET PORTAL ON A CHANNEL
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,EPBSEC
;RETURNS:
;	CPOPJ ALWAYS

EPBSEC:	AOS	EPBCTR+PC.SLZ(Q2) ;UPDATE SECONDS SINCE COUNTERS LAST ZEROED
	LDB	T1,EPPSTS	;GET CURRENT PROTOCOL STATE
	MOVE	T1,EPBTBL(T1)	;GET ADDRESS OF DISPATCH ROUTINE
	PJRST	(T1)		;DISPATCH BASED ON PROTOCOL STATE

;ONCE A SECOND DISPATCH TABLE BASED ON PROTOCOL STATE

EPBTBL:	IFIW	CPOPJ##		;(0) DISABLED
	IFIW	ETHEPT		;(1) DISABLED, WANT TO ENABLE
	IFIW	CPOPJ##		;(2) ENABLE IN PROGRESS
	IFIW	CPOPJ##		;(3) ENABLE IN PROGRESS, WANT TO DISABLE
	IFIW	CPOPJ##		;(4) ENABLED
	IFIW	ETHDPT		;(5) ENABLED, WANT TO DISABLE
	IFIW	CPOPJ##		;(6) DISABLE IN PROGRESS
	SUBTTL	ETHERNET SERVICE  --  ETHERNET KONTROLLER ONCE A SECOND CODE


;ROUTINE CALLED ONCE A SECOND FOR EACH ETHERNET KONTROLLER ON A CHANNEL
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,EKBSEC
;RETURNS:
;	CPOPJ ALWAYS

EKBSEC:	AOS	EKBCTR+KC.SLZ(Q3) ;UPDATE SECONDS SINCE COUNTERS LAST ZEROED
	MOVX	T1,EKSSEA	;NEED TO SET ETHERNET ADDRESS?
	TDNN	T1,EKBSTS(Q3)	;...
	POPJ	P,		;NO, RETURN
	ANDCAM	T1,EKBSTS(Q3)	;YES, CLEAR FLAG, WILL GET RESET IF NEEDED
	PUSHJ	P,SAVP3##	;SAVE P3
	MOVEI	T1,EK.SEA	;FUNCTION SET ETHERNET ADDRESS
	PUSHJ	P,GENEAB	;GENERATE AN EA BLOCK
	  PJRST	EKBSCX		;GO RESET CLOCK LEVEL FLAGS AND RETURN
	DMOVE	T1,ECBEAD(Q1)	;GET CHANNEL'S ETHERNET ADDRESS
	DMOVEM	T1,.EAEAD(P3)	;STORE IN EA BLOCK
	XMOVEI	T1,ETCSCA	;GET ADDRESS OF COMPLETION ROUTINE
	PUSHJ	P,CALKON	;CALL KONTROLLER
	  JRST	[PUSHJ	P,GIVEAB ;ERROR, RELEASE EA BLOCK
		 PJRST	EKBSCX]	;GO RESET CLOCK LEVEL FLAGS AND RETURN
	POPJ	P,		;RETURN

EKBSCX:	MOVX	T1,EKSSEA	;FLAG SET ETHERNET ADDRESS FUNCTION
	IORM	T1,EKBSTS(Q3)	;...
	POPJ	P,		;RETURN
	SUBTTL	ETHERNET USER SERVICE  --  FUNCTION DISPATCH


;ROUTINE CALLED TO INTERFACE TO ETHERNET
;LINKAGE:
;	T1/ FUNCTION CODE (NU.XXX)
;	T2/ ADDRESS OF UN BLOCK
;	PUSHJ	P,ETHSER
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

DLLUNI::!			;TOPS-20 NAME FOR THIS
ETHSER::SKIPLE	T1		;RANGE CHECK FUNCTION CODE
	CAILE	T1,NU.MAX	;...
	STOPCD	[ERRRET	(UNIFC%)],DEBUG,ETHIFC ;++INVALID FUNCTION CODE
	PUSHJ	P,SAVE4##	;SAVE P1-P4
	PUSHJ	P,SAVQ##	;AND Q1-Q3
	SE1ENT			;RUN IN SECTION 1
	MOVE	P1,T1		;SAVE FUNCTION CODE
	MOVE	P4,T2		;AND ADDRESS OF UN BLOCK
	MOVE	P2,ETHDSF(P1)	;GET FUNCTION SPECIFIC FLAGS

	TXNN	P2,DF.PID	;VALID PORTAL ID REQUIRED?
	JRST	ETHSR1		;NO, SKIP CHECK
	LOAD	T1,UNPID,(P4)	;GET PORTAL ID FROM UN BLOCK
	PUSHJ	P,FNDEPB	;FIND ETHERNET PORTAL BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	MOVX	T1,EPSOPN	;GET PORTAL OPEN FLAG
	TXNE	P2,DF.OPN	;IS PORTAL REQUIRED TO BE OPEN?
	TDNE	T1,EPBSTS(Q2)	;YES, IS PORTAL CURRENTLY OPEN?
	SKIPA			;YES, CONTINUE
	ERRRET	(UNPWS%)	;NO, PORTAL IS IN WRONG STATE
	MOVE	T1,EPBPTY(Q2)	;GET PROTOCOL TYPE CODE
	CAXN	T1,PT%INF	;IS THIS AN INFORMATION ONLY PORTAL?
	TXNN	P2,DF.NIP	;YES, VALID FUNCTION FOR INFORMATION PORTALS?
	SKIPA			;YES, CONTINUE
	ERRRET	(UNIFC%)	;NO, INVALID FUNCTION FOR PORTAL
	LDB	T1,EPPSTS	;GET CURRENT PROTOCOL STATE
	CAIE	T1,.PSENA	;IS PROTOCOL ENABLED?
	TXNN	P2,DF.ENA	;NO, IS IT REQUIRED TO BE ENABLED?
	SKIPA			;EITHER ENABLED, OR NOT REQUIRED TO BE
	ERRRET	(UNPWS%)	;YES, PORTAL IS IN WRONG STATE

				;CONTINUED ON NEXT PAGE
				;CONTINUED FROM PREVIOUS PAGE

ETHSR1:	MOVE	T1,ETHDSP(P1)	;GET ADDRESS OF FUNCTION SPECIFIC ROUTINE
	PUSHJ	P,(T1)		;CALL FUNCTION SPECIFIC ROUTINE
	  POPJ	P,		;ERROR, ERROR CODE IN T1

	CAIE	P1,NU.OPN	;AN OPEN PORTAL FUNCTION?
	TXNE	P2,DF.PID	;NO, DID FUNCTION REQUIRE A PORTAL BLOCK?
	SKIPA			;YES, UPDATE PORTAL RUN FLAG
	PJRST	CPOPJ1##	;NO, JUST RETURN
	CAIN	P1,NU.CLO	;CLOSE PORTAL FUNCTION?
	SKIPA	T1,[.PSDIS]	;YES, GET DISABLED PROTOCOL STATE
	LDB	T1,EPPSTS	;GET CURRENT PROTOCOL STATE
	CAIE	T1,.PSENA	;IS PROTOCOL ENABLED?
	TDZA	T1,T1		;NO, CLEAR RUN FLAG
	MOVEI	T1,1		;YES, SET RUN FLAG
	STOR	T1,UNRUN,(P4)	;STORE RUN FLAG
	PJRST	CPOPJ1##	;AND RETURN

;GENERIC ERROR RETURN WHICH RELEASES EA BLOCKS

ETHSRX:	PUSH	P,T1		;SAVE ERROR CODE
	PUSHJ	P,GIVEAB	;RELEASE EA BLOCK
	PJRST	TPOPJ##		;RESTORE ERROR CODE AND RETURN
;ETHERNET FUNCTION DISPATCH TABLES

DEFINE	FNC,<

XALL				;;LIST GENERATED TABLE

DISP	0,				0,	ETHIFC	;;PLACE HOLDER
DISP	0,				NU.OPN,	ETHOPN	;;OPEN PORTAL
DISP	DF.PID!DF.OPN,			NU.CLO,	ETHCLO	;;CLOSE PORTAL
DISP	DF.PID!DF.OPN!DF.ENA!DF.NIP,	NU.RCV,	ETHRDG	;;RECEIVE DATAGRAM
DISP	DF.PID!DF.OPN!DF.ENA!DF.NIP,	NU.XMT,	ETHXDG	;;TRANSMIT DATAGRAM
DISP	DF.PID!DF.OPN!DF.NIP,		NU.EMA,	ETHEMA	;;ENABLE MULTI-CAST
DISP	DF.PID!DF.OPN!DF.NIP,		NU.DMA,	ETHDMA	;;DISABLE MULTI-CAST

DISP	0,				NU.RCL,	ETHRCL	;;READ CHANNEL LIST
DISP	0,				NU.RCI,	ETHRCI	;;READ CHANNEL INFO
DISP	DF.PID,				NU.RCC,	ETHRCC	;;READ CHANNEL COUNTERS
DISP	0,				NU.SCA,	ETHSCA	;;SET CHANNEL ADDRESS

DISP	0,				NU.RPL,	ETHRPL	;;READ PORTAL LIST
DISP	0,				NU.RPI,	ETHRPI	;;READ PORTAL INFO
DISP	DF.PID,				NU.RPC,	ETHRPC	;;READ PORTAL COUNTERS

DISP	0,				NU.RKL,	ETHRKL	;;READ KONTROLLER LIST
DISP	0,				NU.RKI,	ETHRKI	;;READ KONTROLLER INFO
DISP	DF.PID,				NU.RKC,	ETHRKC	;;READ KONTROLLER COUNTERS

SALL				;;TURN LISTING BACK OFF

>; END DEFINE FNC
;GENERATE FUNCTION FLAGS TABLE

DF.CID==400000,,000000		;REQUIRE VALID CHANNEL ID
DF.PID==200000,,000000		;REQUIRE VALID PORTAL ID
DF.KID==100000,,000000		;REQUIRE VALID KONTROLLER ID
DF.OPN==040000,,000000		;REQUIRE PORTAL TO BE OPEN
DF.ENA==020000,,000000		;REQUIRE PORTAL TO BE ENABLED
DF.NIP==010000,,000000		;NOT VALID FOR INFORMATION ONLY PORTALS

DEFINE	DISP(FLAG,CODE,ADDR),<
	FLAG			;CODE
>; END DEFINE DISP

ETHDSF:	FNC			;GENERATE FUNCTION FLAGS TABLE
;GENERATE FUNCTION DISPATCH TABLE

DEFINE	DISP(FLAG,CODE,ADDR),<
IF1,<IFN <CODE-<.-ETHDSP>>,<PRINTX ?Table ETHDSP entry CODE is out of order>>
	IFIW	ADDR		;CODE
>; END DEFINE DISP

ETHDSP:	FNC			;GENERATE FUNCTION DISPATCH TABLE
IF1,<IFN <NU.MAX-<.-ETHDSP-1>>,<PRINTX ?Table ETHDSP is missing entries>>
	SUBTTL	ETHERNET USER SERVICE  --  OPEN PORTAL FUNCTION


;HERE TO PROCESS AN OPEN PORTAL CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	PUSHJ	P,ETHOPN
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHOPN:	MOVEI	T2,EPBLEN	;GET LENGTH OF PORTAL BLOCK
	PUSHJ	P,GETEWZ##	;ALLOCATE ZEROED CORE FOR PORTAL BLOCK
	  STOPCD [ERRRET (UNRES%)],DEBUG,ETHCCP ;++CAN'T CREATE PORTAL BLOCK
	MOVE	Q2,T1		;SAVE ADDRESS IN Q2
	LOAD	T1,UNJCH,(P4)	;GET JCH OF PORTAL OWNER
	MOVEM	T1,EPBJCH(Q2)	;SAVE IN PORTAL BLOCK
	LOAD	T1,UNUID,(P4)	;GET CALLBACK ID
	MOVEM	T1,EPBCBI(Q2)	;SAVE IN PORTAL BLOCK
	LOAD	T1,UNCBA,(P4)	;GET CALLBACK ADDRESS
	MOVEM	T1,EPBCBA(Q2)	;SAVE IN PORTAL BLOCK
	LOADE	T1,UNPRO,(P4)	;GET REQUESTED PROTOCOL TYPE CODE
	MOVEM	T1,EPBPTY(Q2)	;STORE IN PORTAL BLOCK
	JUMPL	T1,ETHOPP	;JUMP IF PSEUDO-PROTOCOL TYPE
	LOAD	T1,UNPAD,(P4)	;GET PROTOCOL PADDING FLAG
	DPB	T1,EPPPAD	;STORE IN PORTAL BLOCK
	SETZM	T1,EPBCTR+PC.SLZ(Q2) ;CLEAR SECONDS SINCE COUNTERS LAST ZEROED
	MOVX	T1,EPSOPN	;MARK PORTAL AS CURRENTLY OPEN
	IORM	T1,EPBSTS(Q2)	;...
	MOVEI	T1,.PSDIS	;AND PROTOCOL AS DISABLED
	DPB	T1,EPPSTS	;...
	LOAD	T1,UNCHN,(P4)	;GET CHANNEL ID
	PUSHJ	P,FNDECB	;FIND ETHERNET CHANNEL BLOCK
	  JRST	ETHOPX		;ERROR, ERROR CODE IN T1
	PUSHJ	P,GENPID	;GENERATE PORTAL ID
	MOVEM	T1,EPBPID(Q2)	;STORE IN PORTAL BLOCK
	STOR	T1,UNPID,(P4)	;ALSO STORE INTO UN BLOCK
	PUSHJ	P,ADDEPB	;ADD PORTAL TO ETHERNET CHANNEL
	  JRST	ETHOPX		;ERROR, ERROR CODE IN T1
	PUSHJ	P,ETHEPT	;INITIATE ENABLE OF PROTOCOL
	PJRST	CPOPJ1##	;AND RETURN

ETHOPX:	PUSH	P,T1		;SAVE ERROR CODE
	MOVEI	T1,EPBLEN	;GET LENGTH OF PORTAL BLOCK
	MOVE	T2,Q2		;AND ADDRESS OF PORTAL BLOCK
	PUSHJ	P,GIVEWS##	;RELEASE CORE
	PJRST	TPOPJ##		;RESTORE ERROR CODE AND RETURN

				;CONTINUED ON NEXT PAGE
				;CONTINUED FROM PREVIOUS PAGE

ETHOPP:	CAXE	T1,PT%INF	;INFORMATION PROTOCOL TYPE?
	ERRRET	(UNIVP%,ETHOPX)	;NO, INVALID PROTOCOL TYPE
	MOVX	T1,EPSOPN	;MARK PORTAL AS CURRENTLY OPEN
	IORM	T1,EPBSTS(Q2)	;...
	MOVEI	T1,.PSENA	;AND PROTOCOL AS ENABLED
	DPB	T1,EPPSTS	;...
	SETZ	T1,		;USE CHANNEL 0 ID
	PUSHJ	P,FNDECB	;FIND ETHERNET CHANNEL BLOCK
	  JRST	ETHOPX		;ERROR, ERROR CODE IN T1
	PUSHJ	P,GENPID	;GENERATE PORTAL ID
	MOVEM	T1,EPBPID(Q2)	;STORE IN PORTAL BLOCK
	STOR	T1,UNPID,(P4)	;ALSO STORE INTO UN BLOCK
	PUSHJ	P,ADDEPB	;ADD PORTAL TO INFORMATION CHANNEL
	  JRST	ETHOPX		;ERROR, ERROR CODE IN T1
	PJRST	CPOPJ1##	;RETURN
	SUBTTL	ETHERNET USER SERVICE  --  CLOSE PORTAL FUNCTION


;HERE TO PROCESS A CLOSE PORTAL CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETHCLO
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHCLO:	MOVX	T1,EPSOPN	;MARK PORTAL AS CLOSED
	ANDCAM	T1,EPBSTS(Q2)	;...
	MOVE	T1,EPBPTY(Q2)	;GET PROTOCOL TYPE CODE
	JUMPL	T1,ETHCLP	;JUMP IF PSEUDO-PROTOCOL TYPE
	PUSHJ	P,ETHDPT	;INITIATE DISABLE OF PROTOCOL
	PJRST	CPOPJ1##	;AND RETURN

ETHCLP:	PUSHJ	P,DELEPB	;DELETE PORTAL BLOCK FROM ETHERNET CHANNEL
	  JFCL			;SHOULDN'T FAIL
	MOVEI	T1,EPBLEN	;GET LENGTH OF PORTAL BLOCK
	MOVE	T2,Q2		;AND ADDRESS OF PORTAL BLOCK
	PUSHJ	P,GIVEWS##	;RELEASE PORTAL BLOCK
	PJRST	CPOPJ1##	;AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  RECEIVE DATAGRAM FUNCTION


;HERE TO PROCESS A POST RECEIVE DATAGRAM BUFFER CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETHRDG
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

IFN VMC.XC-UNA.EV,<PRINTX ? UN and MSD values for EXEC mapping disagree>
IFN VMC.US-UNA.UV,<PRINTX ? UN and MSD values for USER mapping disagree>
IFN VMC.NO-UNA.PH,<PRINTX ? UN and MSD values for PHYSICAL mapping disagree>

ETHRDG:	PUSHJ	P,SAVP3##	;SAVE P3
	MOVEI	T1,EK.RDG	;FUNCTION RECEIVE DATAGRAM
	PUSHJ	P,GENEAB	;GENERATE AN EA BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	LOAD	T1,UNBSZ,(P4)	;GET DATAGRAM SIZE IN BYTES
	JUMPE	T1,ETHRD1	;JUMP IF MSD STYLE RECEIVE
	MOVEM	T1,MD.BYT+.EAMSD(P3) ;SAVE IN MSD IN EA BLOCK
	LOAD	T1,UNADS,(P4)	;GET ADDRESS SPACE OF DATAGRAM
	STOR	T1,MDVMC,+.EAMSD(P3) ;STORE IN MSD
	DMOVE	T1,UN.BFA(P4)	;GET BYTE POINTER TO DATA
	PUSHJ	P,GTWGBP	;GENERATE A TWO WORD GLOBAL BYTE POINTER
	MOVEM	T1,MD.AUX+.EAMSD(P3) ;SAVE P&S PORTION OF BYTE POINTER
	MOVEM	T2,MD.ALA+.EAMSD(P3) ;AND ADDRESS PORTION OF BYTE POINTER
	JRST	ETHRD2		;CONTINUE
ETHRD1:	MOVE	T1,UN.BFA(P4)	;GET ADDRESS OF FIRST MSD
	MOVEM	T1,MD.NXT+.EAMSD(P3) ;SAVE IN MSD OF EA BLOCK
ETHRD2:	LOAD	T2,UNRID,(P4)	;GET COMPLETION DATA
	DMOVE	T3,UN.BFA(P4)	;...
	XMOVEI	T1,ETCRDG	;GET ADDRESS OF COMPLETION ROUTINE
	PUSHJ	P,CALKON	;CALL KONTROLLER
	  PJRST	ETHSRX		;ERROR, ERROR CODE IN T1
	AOS	EPBRBC(Q2)	;INCREMENT COUNT OF CURRENT RECEIVE BUFFERS
	PJRST	CPOPJ1##	;RETURN
;HERE TO PROCESS RECEIVE DATAGRAM COMPLETION INTERRUPT
;LINKAGE: (CALLED AT INTERRUPT LEVEL)
;	T2/ USER'S REQUEST ID
;	T3-T4/ USER'S ORIGINAL BUFFER POINTER
;	P3/ ADDRESS OF EA BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETCRDG
;RETURNS:
;	CPOPJ ALWAYS

ETCRDG:	PUSHJ	P,SAVP4##	;SAVE P4
	XMOVEI	P4,EPBCBU(Q2)	;GET ADDRESS OF CALLBACK UN BLOCK
	STOR	T2,UNRID,(P4)	;STORE USER'S REQUEST ID
	DMOVEM	T3,UN.BFA(P4)	;AND USER'S ORIGINAL BUFFER POINTER
	SOS	EPBRBC(Q2)	;DECREMENT COUNT OF CURRENT RECEIVE BUFFERS
	MOVE	T1,.EADPT(P3)	;GET PROTOCOL TYPE
	STOR	T1,UNPRO,(P4)	;STORE IN UN BLOCK
	MOVE	T1,.EADSZ(P3)	;GET SIZE OF RECEIVED DATAGRAM
	STOR	T1,UNBSZ,(P4)	;STORE IN UN BLOCK
	DMOVE	T1,.EADSA(P3)	;GET SOURCE ADDRESS OF DATAGRAM
	DMOVEM	T1,UN.SAD(P4)	;STORE IN UN BLOCK
	DMOVE	T1,.EADDA(P3)	;GET DESTINATION ADDRESS OF DATAGRAM
	DMOVEM	T1,UN.DAD(P4)	;STORE IN UN BLOCK
	TXNN	T1,<BYTE (8) 1,0,0,0> ;IS DESTINATION A MULTI-CAST ADDRESS?
	JRST	ETCRD1		;NO, ACCEPT DATAGRAM
	MOVE	T3,EPBPTY(Q2)	;GET PROTOCOL TYPE
	CAXN	T3,PT%PRM	;PORTAL RUNNING IN PROMISCUOUS MODE?
	JRST	ETCRD1		;YES, ACCEPT DATAGRAM
	PUSHJ	P,FNDMCA	;FIND MULTI-CAST ADDRESS BLOCK
	  SKIPA			;NONE, PORTAL NOT ENABLED FOR THIS ADDRESS
	JRST	ETCRD1		;FOUND IT, CONTINUE
	MOVEI	T1,UNRAB%	;GET RECEIVE ABORTED ERROR CODE
	MOVEM	T1,.EADST(P3)	;STORE IN EA BLOCK

ETCRD1:	MOVE	T1,.EADSZ(P3)	;GET SIZE OF DATAGRAM IN BYTES
	ADDM	T1,EPBCTR+PC.BYR(Q2) ;UPDATE TOTAL BYTES RECEIVED
	ADDM	T1,%EIBYR	;...
	AOS	EPBCTR+PC.DGR(Q2) ;AND TOTAL DATAGRAMS RECEIVED
	AOS	%EIDGR		;...
	MOVEI	T1,NU.RCV	;GIVE USER RECEIVE DONE CALLBACK
	MOVE	T3,.EADST(P3)	;GET DATAGRAM STATUS
	PUSHJ	P,CALUSR	;GIVE CALLBACK
	PJRST	GIVEAB		;RELEASE EA BLOCK AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  TRANSMIT DATAGRAM FUNCTION


;HERE TO PROCESS A TRANSMIT DATAGRAM CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETHXDG
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

IFN VMC.XC-UNA.EV,<PRINTX ? UN and MSD values for EXEC mapping disagree>
IFN VMC.US-UNA.UV,<PRINTX ? UN and MSD values for USER mapping disagree>
IFN VMC.NO-UNA.PH,<PRINTX ? UN and MSD values for PHYSICAL mapping disagree>

ETHXDG:	PUSHJ	P,SAVP3##	;SAVE P3
	MOVEI	T1,EK.XDG	;FUNCTION TRANSMIT DATAGRAM
	PUSHJ	P,GENEAB	;GENERATE AN EA BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	DMOVE	T1,ECBEAD(Q1)	;GET SOURCE ETHERNET ADDRESS
	DMOVEM	T1,.EADSA(P3)	;STORE IN EA BLOCK
	DMOVE	T1,UN.DAD(P4)	;GET DESTINATION ETHERNET ADDRESS
	DMOVEM	T1,.EADDA(P3)	;STORE IN EA BLOCK
	LOAD	T1,UNBSZ,(P4)	;GET DATAGRAM SIZE IN BYTES
	JUMPE	T1,ETHXD1	;JUMP IF MSD STYLE TRANSMIT
	MOVEM	T1,MD.BYT+.EAMSD(P3) ;SAVE IN MSD IN EA BLOCK
	LOAD	T1,UNADS,(P4)	;GET ADDRESS SPACE OF DATAGRAM
	STOR	T1,MDVMC,+.EAMSD(P3) ;STORE IN MSD
	DMOVE	T1,UN.BFA(P4)	;GET BYTE POINTER TO DATA
	PUSHJ	P,GTWGBP	;GENERATE A TWO WORD GLOBAL BYTE POINTER
	MOVEM	T1,MD.AUX+.EAMSD(P3) ;SAVE P&S PORTION OF BYTE POINTER
	MOVEM	T2,MD.ALA+.EAMSD(P3) ;AND ADDRESS PORTION OF BYTE POINTER
	JRST	ETHXD2		;CONTINUE
ETHXD1:	MOVE	T1,UN.BFA(P4)	;GET ADDRESS OF FIRST MSD
	MOVEM	T1,MD.NXT+.EAMSD(P3) ;SAVE IN MSD OF EA BLOCK
ETHXD2:	LOAD	T2,UNRID,(P4)	;GET COMPLETION DATA
	DMOVE	T3,UN.BFA(P4)	;...
	XMOVEI	T1,ETCXDG	;GET ADDRESS OF COMPLETION ROUTINE
	PUSHJ	P,CALKON	;CALL KONTROLLER
	  PJRST	ETHSRX		;ERROR, ERROR CODE IN T1
	AOS	EPBXBC(Q2)	;INCREMENT COUNT OF CURRENT TRANSMIT BUFFERS
	PJRST	CPOPJ1##	;RETURN
;HERE TO PROCESS TRANSMIT DATAGRAM COMPLETION INTERRUPT
;LINKAGE: (CALLED AT INTERRUPT LEVEL)
;	T2/ USER'S REQUEST ID
;	T3-T4/ USER'S ORIGINAL BUFFER POINTER
;	P3/ ADDRESS OF EA BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETCXDG
;RETURNS:
;	CPOPJ ALWAYS

ETCXDG:	PUSHJ	P,SAVP4##	;SAVE P4
	XMOVEI	P4,EPBCBU(Q2)	;GET ADDRESS OF CALLBACK UN BLOCK
	STOR	T2,UNRID,(P4)	;STORE USER'S REQUEST ID
	DMOVEM	T3,UN.BFA(P4)	;AND ORIGINAL BUFFER POINTER
	SOS	EPBXBC(Q2)	;DECREMENT COUNT OF CURRENT TRANSMIT BUFFERS
	MOVE	T1,.EADPT(P3)	;GET PROTOCOL TYPE
	STOR	T1,UNPRO,(P4)	;STORE IN UN BLOCK
	MOVE	T1,.EADSZ(P3)	;GET SIZE OF TRANSMITTED DATAGRAM
	STOR	T1,UNBSZ,(P4)	;STORE IN UN BLOCK
	DMOVE	T1,.EADDA(P3)	;GET DESTINATION ADDRESS OF DATAGRAM
	DMOVEM	T1,UN.DAD(P4)	;STORE IN UN BLOCK
	DMOVE	T1,.EADSA(P3)	;GET SOURCE ADDRESS OF DATAGRAM
	DMOVEM	T1,UN.SAD(P4)	;STORE IN UN BLOCK
	MOVE	T1,.EADSZ(P3)	;GET DATAGRAM SIZE IN BYTES
	ADDM	T1,EPBCTR+PC.BYX(Q2) ;UPDATE TOTAL BYTES TRANSMITTED
	ADDM	T1,%EIBYX	;...
	AOS	EPBCTR+PC.DGX(Q2) ;AND TOTAL DATAGRAMS TRANSMITTED
	AOS	%EIDGX		;...
	MOVEI	T1,NU.XMT	;GIVE USER TRANSMIT DONE CALLBACK
	MOVE	T3,.EADST(P3)	;GET DATAGRAM STATUS
	PUSHJ	P,CALUSR	;GIVE CALLBACK
	PJRST	GIVEAB		;RELEASE EA BLOCK AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  ENABLE MULTI-CAST ADDRESS FUNCTION


;HERE TO PROCESS AN ENABLE MULTI-CAST ADDRESS CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETHEMA
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHEMA:	DMOVE	T1,UN.DAD(P4)	;GET MULTI-CAST ADDRESS FROM UN BLOCK
	PJRST	ADDMCA		;ADD MULTI-CAST ADDRESS TO PORTAL AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  DISABLE MULTI-CAST ADDRESS FUNCTION


;HERE TO PROCESS A DISABLE MULTI-CAST ADDRESS CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETHDMA
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHDMA:	DMOVE	T1,UN.DAD(P4)	;GET MULTI-CAST ADDRESS FROM UN BLOCK
	PJRST	DELMCA		;DELETE MULTI-CAST ADDRESS BLOCK AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  READ CHANNEL LIST FUNCTION


;HERE TO PROCESS A READ CHANNEL LIST CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	PUSHJ	P,ETHRCL
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHRCL:	XMOVEI	Q1,%EICHN-ECBSYS ;GET FIRST-1 CHANNEL BLOCK ADDRESS
	XMOVEI	T1,ETXRCL	;AND ADDRESS OF READ CHANNEL LIST ROUTINE
	PJRST	ETHRXL		;READ CHANNEL LIST AND RETURN

;ROUTINE CALLED BY ETHRXL TO READ NEXT CHANNEL'S STATUS WORD

ETXRCL:	MOVE	Q1,ECBSYS(Q1)	;GET ADDRESS OF NEXT CHANNEL BLOCK
	PJUMPE	Q1,CPOPJ##	;RETURN IF AT END OF LIST
	AOS	(P)		;PRESET SKIP RETURN
	PJRST	GENCSW		;GENERATE CHANNEL STATUS WORD AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  READ CHANNEL INFORMATION FUNCTION


;HERE TO PROCESS A READ CHANNEL INFORMATION CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	PUSHJ	P,ETHRCI
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHRCI:	LOAD	T1,UNSID,(P4)	;GET CHANNEL ID
	PUSHJ	P,FNDECB	;FIND ETHERNET CHANNEL BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	PUSHJ	P,GENCSW	;GENERATE CHANNEL STATUS WORD
	STOR	T1,UNSID,(P4)	;STORE FOR CALLER
	DMOVE	T1,ECBEAD(Q1)	;GET CURRENT CHANNEL ETHERNET ADDRESS
	DMOVEM	T1,UN.CAR(P4)	;STORE IN UN BLOCK
	SETZB	T1,T2		;ZERO PRIMARY HARDWARE ETHERNET ADDRESS
	SKIPE	Q3,ECBEKB(Q1)	;GET ADDRESS OF PRIMARY ETHERNET KONTROLLER
	DMOVE	T1,EKBHEA(Q3)	;GET PRIMARY HARDWARE KONTROLLER ADDRESS
	DMOVEM	T1,UN.HAD(P4)	;STORE IN UN BLOCK
	MOVEI	T1,RCITLN	;GET LENGTH OF CHANNEL INFORMATION TABLE
	XMOVEI	T2,RCITAB	;AND ADDRESS OF CHANNEL INFORMATION TABLE
	PJRST	ETHRXI		;STORE CHANNEL INFORMATION AND RETURN


;TABLE OF INSTRUCTIONS FOR FETCHING CHANNEL INFORMATION

DEFINE	INF(CODE,INST),<
IF1,<IFN <CODE-<.-RCITAB>>,<PRINTX ?Table RCITAB entry CODE is out of order>>
	EXP	INST		;;INSTRUCTION TO FETCH VALUE
>; END DEFINE INF

RCITAB:	INF	<CI.CNM>,  <MOVE  T1,ECBCID(Q1)>   ;CHANNEL NUMBER
	INF	<CI.EAD+0>,<MOVE  T1,ECBEAD+0(Q1)> ;CURRENT ETHERNET ADDRESS
	INF	<CI.EAD+1>,<MOVE  T1,ECBEAD+1(Q1)> ;...
RCITLN==.-RCITAB		;LENGTH OF CHANNEL INFORMATION TABLE
IF1,<IFN <CI.LEN-<.-RCITAB>>,<PRINTX ?Table RCITAB is missing entries>>
	SUBTTL	ETHERNET USER SERVICE  --  READ CHANNEL COUNTERS FUNCTION


;HERE TO PROCESS A READ CHANNEL COUNTERS CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,ETHRCC
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHRCC:	PUSHJ	P,SAVP3##	;SAVE P3
	PUSHJ	P,SAVQ##	;SAVE Q1-Q3
	LOAD	T1,UNSID,(P4)	;GET CHANNEL ID
	PUSHJ	P,FNDECB	;FIND ETHERNET CHANNEL BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	PUSHJ	P,GENCSW	;GENERATE CHANNEL STATUS WORD
	STOR	T1,UNSID,(P4)	;STORE FOR CALLER
	MOVEI	T1,EK.RKC	;FUNCTION READ AND CLEAR KONTROLLER COUNTERS
	PUSHJ	P,GENEAB	;GENERATE AN EA BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	MOVEI	T2,KC.LEN	;GET LENGTH OF COUNTERS AREA
	MOVEM	T2,.EACBS(P3)	;SAVE IN EA BLOCK
	PUSHJ	P,GETEWZ##	;GET BUFFER TO READ COUNTERS INTO
	  ERRRET (UNRES%,ETHSRX) ;RESOURCE ERROR, RETURN
	MOVEM	T1,.EACBA(P3)	;SAVE BUFFER ADDRESS IN EA BLOCK
	LOAD	T2,UNRID,(P4)	;GET COMPLETION DATA
	LOAD	T3,UNBSZ,(P4)	;...
	LOAD	T4,UNZRO,(P4)	;...
	DPB	T4,[POINT 1,T3,0] ;...
	MOVE	T4,UN.BFA(P4)	;...
	PUSHJ	P,ETXRCC	;INITIATE READING OF CHANNEL COUNTERS
	PJRST	CPOPJ1##	;AND RETURN

				;CONTINUED ON NEXT PAGE
				;CONTINUED FROM PREVIOUS PAGE

;HERE TO READ EACH KONTROLLER'S COUNTERS

ETXRCC:	SKIPA	Q3,ECBEKB(Q1)	;GET ADDRESS OF FIRST ETHERNET KONTROLLER
ETXRC1:	MOVE	Q3,EKBNXT(Q3)	;GET ADDRESS OF NEXT ETHERNET KONTROLLER
	JUMPE	Q3,ETCRCC	;IF NO MORE KONTROLLERS, RETURN COUNTERS
	XMOVEI	T1,ETXRC2	;GET ADDRESS OF COMPLETION ROUTINE
	PUSHJ	P,CALKON	;CALL KONTROLLER
	  JRST	ETXRC1		;ERROR, LOOP BACK FOR NEXT KONTROLLER
	POPJ	P,		;RETURN

;HERE TO PROCESS READ AND CLEAR KONTROLLER COUNTERS COMPLETION INTERRUPT

ETXRC2:	PUSH	P,T2		;SAVE CALLBACK INFORMATION
	PUSH	P,T3		;...
	PUSH	P,T4		;...
	MOVEI	T1,KC.LEN	;GET LENGTH OF COUNTERS AREA
	MOVE	T2,UKCUAP	;GET POINTER TO COUNTERS UPDATE ACTION TABLE
	MOVE	T3,.EACBA(P3)	;GET ADDRESS OF COUNTERS BUFFER
	XMOVEI	T4,EKBCTR(Q3)	;AND ADDRESS OF KONTROLLER COUNTERS BLOCK
	PUSHJ	P,UPDCTR	;UPDATE KONTROLLER'S COUNTERS
	MOVEI	T1,KC.LEN	;GET LENGTH OF COUNTERS AREA
	MOVE	T2,UKCUAP	;GET POINTER TO COUNTERS UPDATE ACTION TABLE
	MOVE	T3,.EACBA(P3)	;GET ADDRESS OF COUNTERS BUFFER
	XMOVEI	T4,ECBCTR(Q1)	;AND ADDRESS OF CHANNEL COUNTERS BLOCK
	PUSHJ	P,UPDCTR	;UPDATE CHANNEL'S COUNTERS
	POP	P,T4		;RESTORE CALLBACK INFORMATION
	POP	P,T3		;...
	POP	P,T2		;...
	JRST	ETXRC1		;LOOP BACK FOR ALL KONTROLLERS
;HERE TO PROCESS READ CHANNEL COUNTERS COMPLETION INTERRUPT
;LINKAGE: (CALLED AT INTERRUPT LEVEL)
;	T2/ USER'S REQUEST ID
;	T3/ LENGTH OF USER'S COUNTERS BUFFER (BIT 0 IS ZERO FLAG)
;	T4/ ADDRESS OF USER'S COUNTERS BUFFER
;	P3/ ADDRESS OF EA BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,ETCRCC
;RETURNS:
;	CPOPJ ALWAYS

ETCRCC:	PUSHJ	P,SAVP4##	;SAVE P4
	XMOVEI	P4,EPBCBU(Q2)	;GET ADDRESS OF CALLBACK UN BLOCK
	STOR	T2,UNRID,(P4)	;STORE USER'S REQUEST ID
	MOVEM	T4,UN.BFA(P4)	;STORE ADDRESS OF USER'S COUNTERS BUFFER
	LDB	T4,[POINT 1,T3,0] ;GET ZERO FLAG
	STOR	T4,UNZRO,(P4)	;STORE IN UN BLOCK
	TLZ	T3,(1B0)	;CLEAR ZERO FLAG
	CAILE	T3,CC.LEN	;BUFFER LARGER THAN COUNTERS AREA?
	MOVEI	T3,CC.LEN	;YES, USE LENGTH OF COUNTERS AREA
	STOR	T3,UNBSZ,(P4)	;STORE NUMBER OF COUNTERS RETURNED
	MOVE	T1,T3		;GET LENGTH OF USER BUFFER AREA
	XMOVEI	T2,ECBCTR(Q1)	;GET ADDRESS OF COUNTERS AREA
	MOVE	T3,UN.BFA(P4)	;AND ADDRESS OF USER BUFFER AREA
	EXTEND	T1,[XBLT]	;COPY COUNTERS TO USER BUFFER
	LOAD	T1,UNZRO,(P4)	;GET ZERO COUNTERS FLAG
	JUMPE	T1,ETCRC2	;JUMP IF JUST READING COUNTERS
	MOVEI	T1,CC.LEN-1	;ZERO CHANNEL COUNTERS BLOCK
	XMOVEI	T2,ECBCTR(Q1)	;...
	XMOVEI	T3,ECBCTR+1(Q1)	;...
	SETZM	ECBCTR(Q1)	;ZERO FIRST WORD OF BLOCK
	EXTEND	T1,[XBLT]	;ZERO REMAINDER
ETCRC2:	MOVEI	T1,NU.RCC	;GET READ CHANNEL COUNTERS CALLBACK
	SETZ	T3,		;AND VALID DATA STATUS RETURN CODE
	PUSHJ	P,CALUSR	;...
	MOVEI	T1,KC.LEN	;GET LENGTH OF COUNTERS BUFFER
	MOVE	T2,.EACBA(P3)	;AND ADDRESS OF BUFFER
	PUSHJ	P,GIVEWS##	;RELEASE COUNTERS BUFFER
	PJRST	GIVEAB		;RELEASE EA BLOCK AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  SET CHANNEL ADDRESS FUNCTION


;HERE TO PROCESS A SET CHANNEL ADDRESS CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	PUSHJ	P,ETHSCA
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHSCA:	PUSHJ	P,SAVP3##	;SAVE P3
	LOAD	T1,UNSID,(P4)	;GET CHANNEL ID
	PUSHJ	P,FNDECB	;FIND ETHERNET CHANNEL BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	PUSHJ	P,GENCSW	;GENERATE CHANNEL STATUS WORD
	STOR	T1,UNSID,(P4)	;STORE FOR CALLER
	DMOVE	T1,UN.DAD(P4)	;GET NEW ETHERNET ADDRESS
	TXNE	T1,<BYTE (8) 1,0,0,0> ;IS THIS A MULTI-CAST ADDRESS?
	ERRRET	(UNICA%)	;YES, ILLEGAL CHANNEL ADDRESS
	DMOVEM	T1,ECBEAD(Q1)	;STORE NEW ETHERNET ADDRESS
	ETHLOK			;INTERLOCK AGAINST SMP RACES
	SKIPA	Q3,ECBEKB(Q1)	;GET ADDRESS OF FIRST KONTROLLER BLOCK
ETHSA1:	MOVE	Q3,EKBNXT(Q3)	;GET ADDRESS OF NEXT KONTROLLER BLOCK
	JUMPE	Q3,ETHSA2	;EXIT LOOP AT END OF LIST
	MOVX	T1,EKSSEA	;SET FLAG FOR CLOCK LEVEL TO SET ADDRESS
	IORM	T1,EKBSTS(Q3)	;...
	JRST	ETHSA1		;LOOP BACK FOR ALL KONTROLLERS
ETHSA2:	ETHULK			;RELEASE SMP INTERLOCK
	PJRST	CPOPJ1##	;AND RETURN
;HERE TO PROCESS SET ETHERNET ADDRESS COMPLETION INTERRUPT
;LINKAGE: (CALLED AT INTERRUPT LEVEL)
;	P3/ ADDRESS OF EA BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETCSCA
;RETURNS:
;	CPOPJ ALWAYS

ETCSCA:	PUSHJ	P,SAVP4##	;SAVE P4
	ETHLOK			;INTERLOCK AGAINST SMP RACES
	SKIPA	Q2,ECBEPB(Q1)	;GET ADDRESS OF FIRST PORTAL BLOCK
ETCSA1:	MOVE	Q2,EPBNXT(Q2)	;GET ADDRESS OF NEXT PORTAL BLOCK
	PJUMPE	Q2,UNLETH##	;RETURN AT END OF LIST
	CAME	Q3,EPBEKB(Q2)	;THIS PORTAL USING THIS KONTROLLER?
	JRST	ETCSA2		;NO, SKIP THIS PORTAL
	XMOVEI	P4,EPBCBU(Q2)	;GET ADDRESS OF CALLBACK UN BLOCK
	SETZ	T1,		;STORE REQUEST ID OF ZERO
	STOR	T1,UNRID,(P4)	;...
	DMOVE	T1,ECBEAD(Q1)	;GET NEW CHANNEL ADDRESS
	DMOVEM	T1,UN.DAD(P4)	;STORE IN UN BLOCK
	MOVEI	T1,NU.SCA	;GIVE USER SET CHANNEL ADDRESS CALLBACK
	PUSHJ	P,CALUSR	;GIVE CALLBACK
ETCSA2:	JRST	ETCSA1		;LOOP BACK FOR ALL PORTALS
	SUBTTL	ETHERNET USER SERVICE  --  READ PORTAL LIST FUNCTION


;HERE TO PROCESS A READ PORTAL LIST CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	PUSHJ	P,ETHRPL
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHRPL:	LOAD	T1,UNSID,(P4)	;GET CHANNEL ID
	PUSHJ	P,FNDECB	;FIND ETHERNET CHANNEL BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	PUSHJ	P,GENCSW	;GENERATE CHANNEL STATUS WORD
	STOR	T1,UNSID,(P4)	;STORE FOR CALLER
	XMOVEI	Q2,ECBEPB-EPBNXT(Q1) ;GET FIRST-1 PORTAL BLOCK ADDRESS
	XMOVEI	T1,ETXRPL	;AND ADDRESS OF READ PORTAL LIST ROUTINE
	PJRST	ETHRXL		;READ PORTAL LIST AND RETURN

;ROUTINE CALLED BY ETHRXL TO READ NEXT PORTAL'S STATUS WORD

ETXRPL:	MOVE	Q2,EPBNXT(Q2)	;GET ADDRESS OF NEXT PORTAL BLOCK
	PJUMPE	Q2,CPOPJ##	;RETURN IF AT END OF LIST
	AOS	(P)		;PRESET SKIP RETURN
	PJRST	GENPSW		;GENERATE PORTAL STATUS WORD AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  READ PORTAL INFORMATION FUNCTION


;HERE TO PROCESS A READ PORTAL INFORMATION CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	PUSHJ	P,ETHRPI
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHRPI:	LOAD	T1,UNSID,(P4)	;GET PORTAL ID
	PUSHJ	P,FNDEPB	;FIND ETHERNET PORTAL BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	PUSHJ	P,GENPSW	;GENERATE PORTAL STATUS WORD
	STOR	T1,UNSID,(P4)	;STORE FOR CALLER
	MOVX	T1,EPSOPN	;IS PORTAL CURRENTLY OPEN?
	TDNN	T1,EPBSTS(Q2)	;...
	ERRRET	(UNPWS%)	;NO, PORTAL IS IN WRONG STATE
	MOVEI	T1,RPITLN	;GET LENGTH OF PORTAL INFORMATION TABLE
	XMOVEI	T2,RPITAB	;AND ADDRESS OF PORTAL INFORMATION TABLE
	PJRST	ETHRXI		;STORE PORTAL INFORMATION AND RETURN


;TABLE OF INSTRUCTIONS FOR FETCHING PORTAL INFORMATION

DEFINE	INF(CODE,INST),<
IF1,<IFN <CODE-<.-RPITAB>>,<PRINTX ?Table RPITAB entry CODE is out of order>>
	EXP	INST		;;INSTRUCTION TO FETCH VALUE
>; END DEFINE INF

RPITAB:	INF	<PI.JCH>,<MOVE  T1,EPBJCH(Q2)>	;JCH OF PORTAL OWNER
	INF	<PI.PIW>,<PUSHJ P,RPIPIW>	;PROTOCOL IDENTIFICATION WORD
	INF	<PI.CSW>,<PUSHJ P,GENCSW>	;CHANNEL STATUS WORD
	INF	<PI.KSW>,<PUSHJ P,GENKSW>	;KONTROLLER STATUS WORD
RPITLN==.-RPITAB		;LENGTH OF PORTAL INFORMATION TABLE
IF1,<IFN <PI.LEN-<.-RPITAB>>,<PRINTX ?Table RPITAB is missing entries>>


;ROUTINE TO COMPUTE PROTOCOL IDENTIFICATION WORD

RPIPIW:	LDB	T1,EPPPAD	;GET PADDING FLAG
	ROT	T1,-1		;POSITION INTO SIGN BIT
	ADD	T1,EPBPTY(Q2)	;ADD IN PROTOCOL TYPE
	POPJ	P,		;AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  READ PORTAL COUNTERS FUNCTION


;HERE TO PROCESS A READ PORTAL COUNTERS CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,ETHRPC
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHRPC:	PUSHJ	P,SAVP3##	;SAVE P3
	PUSHJ	P,SAVQ##	;SAVE Q1-Q3
	MOVEI	T1,EK.RPC	;FUNCTION READ AND CLEAR PORTAL COUNTERS
	PUSHJ	P,GENEAB	;GENERATE AN EA BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	LOAD	T1,UNSID,(P4)	;GET PORTAL ID
	PUSHJ	P,FNDEPB	;FIND ETHERNET PORTAL BLOCK
	  PJRST	ETHSRX		;ERROR, ERROR CODE IN T1
	PUSHJ	P,GENPSW	;GENERATE PORTAL STATUS WORD
	STOR	T1,UNSID,(P4)	;STORE FOR CALLER
	MOVX	T1,EPSOPN	;IS PORTAL CURRENTLY OPEN?
	TDNN	T1,EPBSTS(Q2)	;...
	ERRRET	(UNPWS%,ETHSRX)	;NO, PORTAL IS IN WRONG STATE
	MOVEI	T1,PC.LEN	;GET LENGTH OF COUNTERS AREA
	MOVEM	T1,.EACBS(P3)	;SAVE IN EA BLOCK
	XMOVEI	T1,EPBCTR(Q2)	;GET ADDRESS OF COUNTERS AREA
	MOVEM	T1,.EACBA(P3)	;SAVE IN EA BLOCK
	LOAD	T2,UNRID,(P4)	;GET COMPLETION DATA
	LOAD	T3,UNBSZ,(P4)	;...
	LOAD	T4,UNZRO,(P4)	;...
	DPB	T4,[POINT 1,T3,0] ;...
	MOVE	T4,UN.BFA(P4)	;...
	XMOVEI	T1,ETCRPC	;GET ADDRESS OF COMPLETION ROUTINE
	PUSHJ	P,CALKON	;CALL KONTROLLER
	  PUSHJ	P,ETCRPC	;ERROR, GO RETURN COUNTERS
	PJRST	CPOPJ1##	;AND RETURN
;HERE TO PROCESS READ PORTAL COUNTERS COMPLETION INTERRUPT
;LINKAGE: (CALLED AT INTERRUPT LEVEL)
;	T2/ USER'S REQUEST ID
;	T3/ LENGTH OF USER'S COUNTERS BUFFER (BIT 0 IS ZERO FLAG)
;	T4/ ADDRESS OF USER'S COUNTERS BUFFER
;	P3/ ADDRESS OF EA BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETCRPC
;RETURNS:
;	CPOPJ ALWAYS

ETCRPC:	PUSHJ	P,SAVP4##	;SAVE P4
	XMOVEI	P4,EPBCBU(Q2)	;GET ADDRESS OF CALLBACK UN BLOCK
	STOR	T2,UNRID,(P4)	;STORE USER'S REQUEST ID
	MOVEM	T4,UN.BFA(P4)	;STORE ADDRESS OF USER'S COUNTERS BUFFER
	LDB	T4,[POINT 1,T3,0] ;GET ZERO FLAG
	STOR	T4,UNZRO,(P4)	;STORE IN UN BLOCK
	TLZ	T3,(1B0)	;CLEAR ZERO FLAG
	CAILE	T3,PC.LEN	;BUFFER LARGER THAN COUNTERS AREA?
	MOVEI	T3,PC.LEN	;YES, USE LENGTH OF COUNTERS AREA
	STOR	T3,UNBSZ,(P4)	;STORE NUMBER OF COUNTERS RETURNED
	MOVE	T1,T3		;GET LENGTH OF USER BUFFER AREA
	MOVE	T2,.EACBA(P3)	;GET ADDRESS OF COUNTERS AREA
	MOVE	T3,UN.BFA(P4)	;AND ADDRESS OF USER BUFFER AREA
	EXTEND	T1,[XBLT]	;COPY COUNTERS TO USER BUFFER
	LOAD	T1,UNZRO,(P4)	;GET ZERO COUNTERS FLAG
	JUMPE	T1,ETCRP2	;JUMP IF JUST READING COUNTERS
	MOVEI	T1,PC.LEN-1	;ZERO PORTAL COUNTERS BLOCK
	MOVE	T2,.EACBA(P3)	;...
	XMOVEI	T3,1(T2)	;...
	SETZM	(T2)		;ZERO FIRST WORD OF BLOCK
	EXTEND	T1,[XBLT]	;ZERO REMAINDER
ETCRP2:	MOVEI	T1,NU.RPC	;GET READ PORTAL COUNTERS CALLBACK
	SETZ	T3,		;AND VALID DATA STATUS RETURN CODE
	PUSHJ	P,CALUSR	;...
	PJRST	GIVEAB		;RELEASE EA BLOCK AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  READ KONTROLLER LIST


;HERE TO PROCESS A READ KONTROLLER LIST CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	PUSHJ	P,ETHRKL
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHRKL:	LOAD	T1,UNSID,(P4)	;GET CHANNEL ID
	PUSHJ	P,FNDECB	;FIND ETHERNET CHANNEL BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	PUSHJ	P,GENCSW	;GENERATE CHANNEL STATUS WORD
	STOR	T1,UNSID,(P4)	;STORE FOR CALLER
	XMOVEI	Q3,ECBEKB-EKBNXT(Q1) ;GET FIRST-1 KONTROLLER BLOCK ADDRESS
	XMOVEI	T1,ETXRKL	;AND ADDRESS OF READ KONTROLLER LIST ROUTINE
	PJRST	ETHRXL		;READ KONTROLLER LIST AND RETURN

;ROUTINE CALLED BY ETHRXL TO READ NEXT KONTROLLER'S STATUS WORD

ETXRKL:	MOVE	Q3,EKBNXT(Q3)	;GET ADDRESS OF NEXT KONTROLLER BLOCK
	PJUMPE	Q3,CPOPJ##	;RETURN IF AT END OF LIST
	AOS	(P)		;PRESET SKIP RETURN
	PJRST	GENKSW		;GENERATE KONTROLLER STATUS WORD AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  READ KONTROLLER INFORMATION


;HERE TO PROCESS A READ KONTROLLER INFORMATION CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	PUSHJ	P,ETHRKI
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHRKI:	LOAD	T1,UNSID,(P4)	;GET KONTROLLER ID
	PUSHJ	P,FNDEKB	;FIND ETHERNET KONTROLLER BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	PUSHJ	P,GENKSW	;GENERATE KONTROLLER STATUS WORD
	STOR	T1,UNSID,(P4)	;STORE FOR CALLER
	MOVEI	T1,RKITLN	;GET LENGTH OF KONTROLLER INFORMATION TABLE
	XMOVEI	T2,RKITAB	;AND ADDRESS OF KONTROLLER INFORMATION TABLE
	PJRST	ETHRXI		;STORE KONTROLLER INFORMATION AND RETURN


;TABLE OF INSTRUCTIONS FOR FETCHING KONTROLLER INFORMATION

DEFINE	INF(CODE,INST),<
IF1,<IFN <CODE-<.-RKITAB>>,<PRINTX ?Table RKITAB entry CODE is out of order>>
	EXP	INST		;;INSTRUCTION TO FETCH VALUE
>; END DEFINE INF

RKITAB:	INF	<KI.CSW>,  <PUSHJ P,GENCSW>	  ;CHANNEL STATUS WORD
	INF	<KI.CPU>,  <LDB   T1,EKPCPU>	  ;CPU NUMBER OF KONTROLLER
	INF	<KI.TYP>,  <LDB   T1,EKPKTY>	  ;KONTROLLER TYPE
	INF	<KI.KNO>,  <LDB   T1,EKPKNO>	  ;KONTROLLER NUMBER
	INF	<KI.HEA+0>,<MOVE  T1,EKBHEA+0(Q3)> ;HARDWARE ETHERNET ADDRESS
	INF	<KI.HEA+1>,<MOVE  T1,EKBHEA+1(Q3)> ;HARDWARE ETHERNET ADDRESS
RKITLN==.-RKITAB		;LENGTH OF KONTROLLER INFORMATION TABLE
IF1,<IFN <KI.LEN-<.-RKITAB>>,<PRINTX ?Table RKITAB is missing entries>>
	SUBTTL	ETHERNET USER SERVICE  --  READ KONTROLLER COUNTERS


;HERE TO PROCESS A READ KONTROLLER COUNTERS CALL TO ETHSER
;LINKAGE:
;	P4/ ADDRESS OF UN BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,ETHRKC
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHRKC:	PUSHJ	P,SAVP3##	;SAVE P3
	LOAD	T1,UNSID,(P4)	;GET KONTROLLER ID
	PUSHJ	P,FNDEKB	;FIND ETHERNET KONTROLLER BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	PUSHJ	P,GENKSW	;GENERATE KONTROLLER STATUS WORD
	STOR	T1,UNSID,(P4)	;STORE FOR CALLER
	MOVEI	T1,EK.RKC	;FUNCTION READ AND CLEAR KONTROLLER COUNTERS
	PUSHJ	P,GENEAB	;GENERATE AN EA BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	MOVEI	T2,KC.LEN	;GET LENGTH OF COUNTERS AREA
	MOVEM	T2,.EACBS(P3)	;SAVE IN EA BLOCK
	PUSHJ	P,GETEWZ##	;GET BUFFER TO READ COUNTERS INTO
	  ERRRET (UNRES%,ETHSRX) ;RESOURCE ERROR, RETURN
	MOVEM	T1,.EACBA(P3)	;SAVE BUFFER ADDRESS IN EA BLOCK
	LOAD	T2,UNRID,(P4)	;GET COMPLETION DATA
	LOAD	T3,UNBSZ,(P4)	;...
	LOAD	T4,UNZRO,(P4)	;...
	DPB	T4,[POINT 1,T3,0] ;...
	MOVE	T4,UN.BFA(P4)	;...
	PUSHJ	P,ETXRKC	;INITIATE READING OF KONTROLLER COUNTERS
	PJRST	CPOPJ1##	;AND RETURN

				;CONTINUED ON NEXT PAGE
				;CONTINUED FROM PREVIOUS PAGE

;HERE TO READ KONTROLLER'S COUNTERS

ETXRKC:	XMOVEI	T1,ETXRK1	;GET ADDRESS OF COMPLETION ROUTINE
	PUSHJ	P,CALKON	;CALL KONTROLLER
	  PJRST	ETCRKC		;ERROR, GO RETURN COUNTERS
	POPJ	P,		;RETURN

;HERE TO PROCESS READ AND CLEAR KONTROLLER COUNTERS COMPLETION INTERRUPT

ETXRK1:	PUSH	P,T2		;SAVE CALLBACK INFORMATION
	PUSH	P,T3		;...
	PUSH	P,T4		;...
	MOVEI	T1,KC.LEN	;GET LENGTH OF COUNTERS AREA
	MOVE	T2,UKCUAP	;GET POINTER TO COUNTERS UPDATE ACTION TABLE
	MOVE	T3,.EACBA(P3)	;GET ADDRESS OF COUNTERS BUFFER
	XMOVEI	T4,EKBCTR(Q3)	;AND ADDRESS OF KONTROLLER COUNTERS BLOCK
	PUSHJ	P,UPDCTR	;UPDATE KONTROLLER'S COUNTERS
	MOVEI	T1,KC.LEN	;GET LENGTH OF COUNTERS AREA
	MOVE	T2,UKCUAP	;GET POINTER TO COUNTERS UPDATE ACTION TABLE
	MOVE	T3,.EACBA(P3)	;GET ADDRESS OF COUNTERS BUFFER
	XMOVEI	T4,ECBCTR(Q1)	;AND ADDRESS OF CHANNEL COUNTERS BLOCK
	PUSHJ	P,UPDCTR	;UPDATE CHANNEL'S COUNTERS
	POP	P,T4		;RESTORE CALLBACK INFORMATION
	POP	P,T3		;...
	POP	P,T2		;...
	PJRST	ETCRKC		;GO RETURN KONTROLLER COUNTERS
;HERE TO PROCESS READ KONTROLLER COUNTERS COMPLETION INTERRUPT
;LINKAGE: (CALLED AT INTERRUPT LEVEL)
;	T2/ USER'S REQUEST ID
;	T3/ LENGTH OF USER'S COUNTERS BUFFER (BIT 0 IS ZERO FLAG)
;	T4/ ADDRESS OF USER'S COUNTERS BUFFER
;	P3/ ADDRESS OF EA BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETCRKC
;RETURNS:
;	CPOPJ ALWAYS

ETCRKC:	PUSHJ	P,SAVP4##	;SAVE P4
	XMOVEI	P4,EPBCBU(Q2)	;GET ADDRESS OF CALLBACK UN BLOCK
	STOR	T2,UNRID,(P4)	;STORE USER'S REQUEST ID
	MOVEM	T4,UN.BFA(P4)	;STORE ADDRESS OF USER'S COUNTERS BUFFER
	LDB	T4,[POINT 1,T3,0] ;GET ZERO FLAG
	STOR	T4,UNZRO,(P4)	;STORE IN UN BLOCK
	TLZ	T3,(1B0)	;CLEAR ZERO FLAG
	CAILE	T3,KC.LEN	;BUFFER LARGER THAN COUNTERS AREA?
	MOVEI	T3,KC.LEN	;YES, USE LENGTH OF COUNTERS AREA
	STOR	T3,UNBSZ,(P4)	;STORE NUMBER OF COUNTERS RETURNED
	MOVE	T1,T3		;GET LENGTH OF USER BUFFER AREA
	XMOVEI	T2,EKBCTR(Q3)	;GET ADDRESS OF COUNTERS AREA
	MOVE	T3,UN.BFA(P4)	;AND ADDRESS OF USER BUFFER AREA
	EXTEND	T1,[XBLT]	;COPY COUNTERS TO USER BUFFER
	LOAD	T1,UNZRO,(P4)	;GET ZERO COUNTERS FLAG
	JUMPE	T1,ETCRK2	;JUMP IF JUST READING COUNTERS
	MOVEI	T1,KC.LEN-1	;ZERO KONTROLLER COUNTERS
	XMOVEI	T2,EKBCTR(Q3)	;...
	XMOVEI	T3,EKBCTR+1(Q3)	;...
	SETZM	EKBCTR(Q3)	;ZERO FIRST WORD OF BLOCK
	EXTEND	T1,[XBLT]	;ZERO REMAINDER
ETCRK2:	MOVEI	T1,NU.RKC	;GET READ KONTROLLER COUNTERS CALLBACK
	SETZ	T3,		;AND VALID DATA STATUS RETURN CODE
	PUSHJ	P,CALUSR	;GIVE COMPLETION CALLBACK
	MOVEI	T1,KC.LEN	;GET LENGTH OF COUNTERS BUFFER
	MOVE	T2,.EACBA(P3)	;AND ADDRESS OF BUFFER
	PUSHJ	P,GIVEWS##	;RELEASE COUNTERS BUFFER
	PJRST	GIVEAB		;RELEASE EA BLOCK AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  READ ETHERNET LIST


;HERE TO PROCESS A READ ETHERNET LIST CALL
;LINKAGE:
;	T1/ ADDRESS OF ROUTINE TO RETURN NEXT STATUS WORD
;	P4/ ADDRESS OF UN BLOCK
;	PUSHJ	P,ETHRXL
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHRXL:	PUSHJ	P,SAVE3##	;SAVE P1-P3
	MOVE	P3,T1		;SAVE ADDRESS OF STATUS ROUTINE
	LOAD	P1,UNBSZ,(P4)	;GET SIZE OF USER BUFFER
	JUMPLE	P1,[ERRRET (UNIBS%)] ;ERROR, INVALID BUFFER SIZE
	LOAD	P2,UNBFA,(P4)	;GET ADDRESS OF USER BUFFER
	JUMPLE	P2,[ERRRET (UNIFB%)] ;ERROR, ILLEGALLY FORMATTED BUFFER
	ETHLOK			;INTERLOCK AGAINST SMP RACES
ETHRL1:	PUSHJ	P,(P3)		;GET NEXT STATUS WORD
	  JRST	ETHRL2		;EXIT LOOP AT END OF LIST
	JUMPLE	P1,ETHRL2	;EXIT LOOP IF NO MORE ROOM IN BUFFER
	MOVEM	T1,(P2)		;STORE STATUS WORD INTO USER BUFFER
	XMOVEI	P2,1(P2)	;INCREMENT USER BUFFER POINTER
	SOJA	P1,ETHRL1	;LOOP THROUGH ALL STATUS WORDS
ETHRL2:	ETHULK			;RELEASE SMP INTERLOCK
	LOAD	T1,UNBSZ,(P4)	;GET ORIGINAL SIZE OF USER BUFFER
	SUB	T1,P1		;CALCULATE NUMBER OF ENTRIES STORED
	STOR	T1,UNBSZ,(P4)	;STORE INTO UN BLOCK
	PJRST	CPOPJ1##	;RETURN
	SUBTTL	ETHERNET USER SERVICE  --  READ ETHERNET INFORMATION


;HERE TO PROCESS A READ ETHERNET INFORMATION CALL
;LINKAGE:
;	T1/ LENGTH OF INFORMATION TABLE
;	T2/ ADDRESS OF INFORMATION TABLE
;	P4/ ADDRESS OF UN BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETHRXI
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ETHRXI:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	DMOVE	P1,T1		;SAVE SIZE AND ADDRESS OF INFORMATION TABLE
	LOAD	T3,UNBSZ,(P4)	;GET SIZE OF USER BUFFER
	JUMPL	T3,[ERRRET (UNIBS%)] ;ERROR, INVALID BUFFER SIZE
	JUMPE	T3,ETHRI2	;JUMP IF NO BUFFER
	LOAD	T4,UNBFA,(P4)	;GET ADDRESS OF USER BUFFER
	JUMPLE	T4,[ERRRET (UNIFB%)] ;ERROR, ILLEGALLY FORMATTED BUFFER
ETHRI1:	JUMPLE	P1,ETHRI2	;EXIT LOOP IF NO MORE TABLE ENTRIES
	JUMPLE	T3,ETHRI2	;EXIT LOOP IF NO MORE ROOM IN BUFFER
	XCT	(P2)		;FETCH NEXT INFORMATION WORD
	MOVEM	T1,(T4)		;STORE INTO USER BUFFER
	XMOVEI	T4,1(T4)	;INCREMENT USER BUFFER POINTER
	SOJ	T3,		;DECREMENT USER COUNT
	XMOVEI	P2,1(P2)	;INCREMENT TABLE ADDRESS
	SOJA	P1,ETHRI1	;LOOP BACK TO PROCESS ENTIRE TABLE
ETHRI2:	LOAD	T1,UNBSZ,(P4)	;GET ORIGINAL SIZE OF USER BUFFER
	SUB	T1,T3		;CALCULATE NUMBER OF ENTRIES STORED
	STOR	T1,UNBSZ,(P4)	;STORE INTO UN BLOCK
	PJRST	CPOPJ1##	;RETURN
	SUBTTL	ETHERNET USER SERVICE  --  REPORT PORTAL STATUS CHANGE


;ROUTINE TO REPORT CURRENT PORTAL STATUS BACK TO PORTAL USER
;LINKAGE: (MAY BE CALLED AT INTERRUPT LEVEL)
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,CALSTS
;RETURNS:
;	CPOPJ ALWAYS

CALSTS:	PUSHJ	P,SAVP4##	;SAVE P4
	XMOVEI	P4,EPBCBU(Q2)	;GET ADDRESS OF CALLBACK UN BLOCK
	SETZ	T1,		;ZERO REQUEST ID FOR UNSOLICITED CALLBACK
	STOR	T1,UNRID,(P4)	;...
	STOR	T1,UNBSZ,(P4)	;ALSO CLEAR SIZE OF DATA BUFFER
	DMOVE	T1,ECBEAD(Q1)	;GET CURRENT CHANNEL ETHERNET ADDRESS
	DMOVEM	T1,UN.CAR(P4)	;STORE IN UN BLOCK
	SETZB	T1,T2		;ZERO PRIMARY HARDWARE ETHERNET ADDRESS
	SKIPE	Q3		;PROTOCOL HAVE AN ETHERNET KONTROLLER ASSIGNED?
	DMOVE	T1,EKBHEA(Q3)	;YES, GET ITS HARDWARE ADDRESS
	DMOVEM	T1,UN.HAD(P4)	;STORE IN UN BLOCK
	MOVEI	T1,NU.RCI	;GIVE READ CHANNEL INFORMATION CALLBACK
	PJRST	CALUSR		;CALL USER AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  CALL PORTAL USER


;ROUTINE TO CALLBACK TO PORTAL USER
;LINKAGE:
;	T1/ FUNCTION CODE (UN.XXX)
;	T3/ FUNCTION SPECIFIC STATUS
;	P4/ ADDRESS OF UN BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,CALUSR
;RETURNS:
;	CPOPJ ALWAYS

CALUSR:	MOVE	T2,ECBCID(Q1)	;GET ETHERNET CHANNEL ID
	STOR	T2,UNCHN,(P4)	;STORE IN UN BLOCK
	MOVE	T2,EPBPID(Q2)	;GET PORTAL ID
	STOR	T2,UNPID,(P4)	;STORE INTO UN BLOCK
	MOVE	T2,EPBCBI(Q2)	;GET USER'S CALLBACK ID
	STOR	T2,UNUID,(P4)	;STORE INTO UN BLOCK
	LDB	T2,EPPSTS	;GET CURRENT PROTOCOL STATE
	CAIE	T2,.PSENA	;IS PROTOCOL ENABLED?
	TDZA	T2,T2		;NO, CLEAR RUN FLAG
	MOVEI	T2,1		;YES, SET RUN FLAG
	STOR	T2,UNRUN,(P4)	;STORE RUN FLAG
	MOVE	T2,P4		;GET UN BLOCK ADDRESS
	MOVE	T4,EPBCBA(Q2)	;GET USER'S CALLBACK ADDRESS
	PUSHJ	P,(T4)		;CALLBACK USER
	  JFCL			;IGNORE NON-SKIP RETURN
	POPJ	P,		;RETURN
	SUBTTL	ETHERNET USER SERVICE  --  GENERATE AN EA BLOCK


;ROUTINE CALLED TO GENERATE AN EA BLOCK FOR A PROTOCOL
;LINKAGE:
;	T1/ KONTROLLER FUNCTION CODE (EK.XXX)
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,GENEAB
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS WITH:
;	P3/ ADDRESS OF EA BLOCK

GENEAB:	PUSH	P,T1		;SAVE FUNCTION CODE
	MOVEI	T2,.EALEN	;GET LENGTH OF EA BLOCK
	PUSHJ	P,GETEWZ##	;ALLOCATE ZEROED CORE FOR EA BLOCK
	  PJRST	[POP	P,(P)	;ERROR, CLEAR STACK
		 ERRRET (UNRES%)] ;AND GIVE ERROR RETURN
	MOVE	P3,T1		;GET ADDRESS OF EA BLOCK
	POP	P,.EAFCN(P3)	;SAVE FUNCTION CODE IN EA BLOCK
	MOVEM	Q2,.EAFCP(P3)	;SAVE ADDRESS OF PORTAL BLOCK IN EA BLOCK
	PJRST	CPOPJ1##	;AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  RELEASE EA BLOCK


;ROUTINE CALLED TO RELEASE AN EA BLOCK
;LINKAGE:
;	P3/ ADDRESS OF EA BLOCK
;	PUSHJ	P,GIVEAB
;RETURNS:
;	CPOPJ ALWAYS

GIVEAB:	MOVEI	T1,.EALEN	;GET LENGTH OF EA BLOCK
	MOVE	T2,P3		;AND ADDRESS OF EA BLOCK
	PJRST	GIVEWS##	;RELEASE EA BLOCK AND RETURN
	SUBTTL	ETHERNET USER SERVICE  --  CALL ETHERNET KONTROLLER


;ROUTINE TO CALL AN ETHERNET KONTROLLER
;LINKAGE:
;	T1/ ADDRESS OF COMPLETION ROUTINE
;	T2-T4/ FUNCTION COMPLETION DATA
;	P3/ ADDRESS OF EA BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK (OR ZERO)
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,CALKON
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	T2-T4/ FUNCTION COMPLETION DATA
;	CPOPJ1 ON SUCCESS

CALKON:	JUMPE	Q3,CALKOX	;JUMP IF NO KONTROLLER BLOCK
	MOVEM	T1,.EAFCA(P3)	;STORE FUNCTION COMPLETION ROUTINE ADDRESS
	DMOVEM	T2,.EAFCD(P3)	;STORE FUNCTION COMPLETION DATA
	MOVEM	T4,.EAFCD+2(P3)	;STORE FUNCTION COMPLETION DATA
	MOVE	T1,P3		;GET ADDRESS OF EA BLOCK
	MOVE	T2,EKBKKB(Q3)	;AND ADDRESS OF KONTROLLER'S KONTROLLER BLOCK
	SKIPE	T3,Q2		;HAVE AN ETHERNET PORTAL BLOCK?
	MOVE	T3,EPBKPB(Q2)	;YES, GET KONTROLLER'S PROTOCOL BLOCK
	MOVE	T4,EKBKDA(Q3)	;GET ADDRESS OF KONTROLLER'S DISPATCH ROUTINE
	PUSHJ	P,(T4)		;DISPATCH TO KONTROLLER
	  SKIPA			;ERROR, RESTORE FUNCTION COMPLETION DATA
	PJRST	CPOPJ1##	;SUCCESS, RETURN
	DMOVE	T2,.EAFCD(P3)	;RESTORE FUNCTION COMPLETION DATA
	MOVE	T4,.EAFCD+2(P3)	;...
	POPJ	P,		;AND RETURN

CALKOX:	MOVE	Q2,.EAFCP(P3)	;GET ADDRESS OF ETHERNET PORTAL BLOCK
	PUSHJ	P,(T1)		;CALL COMPLETION ROUTINE
	PJRST	CPOPJ1##	;AND RETURN
	SUBTTL	ETHERNET CHANNEL SUPPORT  --  CREATE ETHERNET CHANNEL BLOCK


;ROUTINE TO CREATE AN ETHERNET CHANNEL BLOCK
;LINKAGE:
;	PUSHJ	P,GENECB
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS WITH:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK

GENECB:	MOVEI	T2,ECBLEN	;GET SIZE OF ETHERNET CHANNEL BLOCK
	PUSHJ	P,GETEWZ##	;ALLOCATE ZEROED CORE FOR CHANNEL BLOCK
	  STOPCD [ERRRET (UNRES%)],DEBUG,ETHCCC ;++CAN'T CREATE CHANNEL BLOCK
	MOVE	Q1,T1		;SAVE ADDRESS IN Q1
	AOS	T1,%EINEC	;INCREMENT NUMBER OF CHANNELS
	SUBI	T1,1		;CONVERT COUNT INTO CHANNEL ID
	MOVEM	T1,ECBCID(Q1)	;SET CHANNEL ID
	ETHLOK			;INTERLOCK AGAINST SMP RACES
	XMOVEI	T4,%EICHN-ECBSYS ;SET UP POINTER TO FIRST-1 CHANNEL BLOCK
GENEC1:	MOVE	T3,ECBSYS(T4)	;GET ADDRESS OF NEXT CHANNEL BLOCK
	JUMPE	T3,GENEC2	;JUMP AT END OF CHANNEL LIST
	MOVE	T4,T3		;SAVE POINTER TO PREVIOUS CHANNEL BLOCK
	JRST	GENEC1		;LOOP BACK TO FIND END OF LIST
GENEC2:	MOVEM	Q1,ECBSYS(T4)	;LINK THIS CHANNEL AT END OF LIST
	SETZM	ECBSYS(Q1)	;...
	ETHULK			;RELEASE SMP INTERLOCK
	PJRST	CPOPJ1##	;AND RETURN
	SUBTTL	ETHERNET CHANNEL SUPPORT  --  GENERATE CHANNEL STATUS WORD


;ROUTINE TO GENERATE CHANNEL STATUS WORD
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	PUSHJ	P,GENCSW
;RETURNS:
;	CPOPJ ALWAYS WITH:
;	T1/ CHANNEL STATUS WORD
;MUST PRESERVE T3-T4

GENCSW:	SETZ	T1,		;START WITH ZERO
	MOVE	T2,ECBSTS(Q1)	;GET CHANNEL STATUS
	TXNE	T2,ECSONL	;IS CHANNEL ONLINE?
	TXO	T1,ET.CON	;YES, SET ONLINE FLAG
	MOVE	T2,ECBCID(Q1)	;GET CHANNEL ID
	DPB	T2,[POINTR (T1,ET.CID)] ;STORE IN CHANNEL STATUS WORD
	POPJ	P,		;AND RETURN
	SUBTTL	ETHERNET CHANNEL SUPPORT  --  FIND ETHERNET CHANNEL BLOCK


;ROUTINE TO FIND AN ETHERNET CHANNEL BLOCK GIVEN CHANNEL ID
;LINKAGE:
;	T1/ CHANNEL ID
;	PUSHJ	P,FNDECB
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE
;	CPOPJ1 ON SUCCESS WITH:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK

FNDECB:	ANDX	T1,ET.CID	;MASK TO JUST CHANNEL ID
	ETHLOK			;INTERLOCK AGAINST SMP RACES
	SKIPA	Q1,%EICHN	;GET ADDRESS OF FIRST ETHERNET CHANNEL BLOCK
FNDEC1:	MOVE	Q1,ECBSYS(Q1)	;GET ADDRESS OF NEXT ETHERNET CHANNEL BLOCK
	JUMPE	Q1,[ERRRET (UNNSC%,UNLETH##)] ;ERROR, NO SUCH CHANNEL
	CAME	T1,ECBCID(Q1)	;FOUND CORRECT CHANNEL BLOCK?
	JRST	FNDEC1		;NO, LOOP THROUGH ALL CHANNELS
	ETHULK			;RELEASE SMP INTERLOCK
	PJRST	CPOPJ1##	;RETURN
	SUBTTL	ETHERNET PORTAL SUPPORT  --  GENERATE ETHERNET PORTAL ID


;ROUTINE TO GENERATE AN ETHERNET PORTAL ID
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,GENPID
;RETURNS:
;	CPOPJ ALWAYS WITH:
;	T1/ PORTAL ID

GENPID:	SETZ	T1,		;START WITH ZERO
	MOVE	T2,ECBCID(Q1)	;GET ETHERNET CHANNEL ID
	DPB	T2,PIPECN	;STORE IN PORTAL ID
	DPB	Q2,PIPEPB	;INCLUDE ETHERNET PORTAL BLOCK ADDRESS
	POPJ	P,		;AND RETURN
	SUBTTL	ETHERNET PORTAL SUPPORT  --  GENERATE PORTAL STATUS WORD


;ROUTINE TO GENERATE PORTAL STATUS WORD
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,GENPSW
;RETURNS:
;	CPOPJ ALWAYS WITH:
;	T1/ PORTAL STATUS WORD
;MUST PRESERVE T3-T4

GENPSW:	SETZ	T1,		;START WITH ZERO
	LDB	T2,EPPSTS	;GET CURRENT PROTOCOL STATUS
	CAIN	T2,.PSENA	;IS PROTOCOL ENABLED?
	TXO	T1,ET.PON	;YES, MARK PROTOCOL AS ONLINE
	MOVE	T2,EPBPID(Q2)	;GET PORTAL ID
	DPB	T2,[POINTR (T1,ET.PID)] ;STORE IN PORTAL STATUS WORD
	POPJ	P,		;AND RETURN
	SUBTTL	ETHERNET PORTAL SUPPORT  --  FIND ETHERNET PORTAL BLOCK


;ROUTINE TO FIND AN ETHERNET PORTAL BLOCK GIVEN PORTAL ID
;LINKAGE:
;	T1/ PORTAL ID
;	PUSHJ	P,FNDEPB
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS WITH:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK

FNDEPB:	ANDX	T1,ET.PID	;MASK TO JUST PORTAL ID
	LDB	Q2,PIPEPB	;GET ETHERNET PORTAL BLOCK ADDRESS
	LDB	T1,PIPECN	;GET ETHERNET CHANNEL ID
	PUSHJ	P,FNDECB	;FIND THE ETHERNET CHANNEL BLOCK
	  POPJ	P,		;ERROR, ERROR CODE ALREADY IN T1
	ETHLOK			;INTERLOCK AGAINST SMP RACES
	SKIPA	T1,ECBEPB(Q1)	;GET ADDRESS OF FIRST ETHERNET PORTAL BLOCK
FNDEP1:	MOVE	T1,EPBNXT(T1)	;GET ADDRESS OF NEXT ETHERNET PORTAL BLOCK
	JUMPE	T1,[ERRRET (UNNSP%,UNLETH##)] ;ERROR, NO SUCH PORTAL
	CAME	T1,Q2		;FOUND CORRECT PORTAL BLOCK?
	JRST	FNDEP1		;NO, LOOP THROUGH ALL PORTALS
	MOVE	Q3,EPBEKB(Q2)	;GET ADDRESS OF ETHERNET KONTROLLER BLOCK
	ETHULK			;RELEASE SMP INTERLOCK
	PJRST	CPOPJ1##	;YES, RETURN
	SUBTTL	ETHERNET PORTAL SUPPORT  --  ADD ETHERNET PORTAL BLOCK


;ROUTINE TO ADD AN ETHERNET PORTAL TO AN ETHERNET CHANNEL
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,ADDEPB
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

ADDEPB:	ETHLOK			;INTERLOCK AGAINST SMP RACES
	XMOVEI	T4,ECBEPB-EPBNXT(Q1) ;SETUP POINTER TO FIRST PORTAL BLOCK
ADDEP1:	MOVE	T3,EPBNXT(T4)	;GET POINTER TO NEXT PORTAL BLOCK
	JUMPE	T3,ADDEP2	;JUMP AT END OF PORTAL LIST
	MOVE	T1,EPBPTY(T3)	;GET THIS PORTAL'S PROTOCOL TYPE
	CAMN	T1,EPBPTY(Q2)	;CONFLICT WITH NEW PORTAL'S PROTOCOL TYPE?
	AOJN	T1,[ERRRET (UNPIU%,UNLETH##)] ;YES, ERROR IF NOT INFO PORTAL
	MOVE	T4,T3		;SAVE POINTER TO PREVIOUS PORTAL BLOCK
	JRST	ADDEP1		;LOOP BACK TO CHECK ALL PORTALS
ADDEP2:	MOVEM	Q2,EPBNXT(T4)	;POINT PREVIOUS PORTAL TO NEW PORTAL BLOCK
	SETZM	EPBNXT(Q2)	;TERMINATE LIST WITH THIS PORTAL BLOCK
	ETHULK			;RELEASE SMP INTERLOCK
	PJRST	CPOPJ1##	;AND RETURN
	SUBTTL	ETHERNET PORTAL SUPPORT  --  DELETE ETHERNET PORTAL BLOCK


;ROUTINE TO DELETE AN ETHERNET PORTAL FROM AN ETHERNET CHANNEL
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,DELEPB
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

DELEPB:	ETHLOK			;INTERLOCK AGAINST SMP RACES
	XMOVEI	T4,ECBEPB-EPBNXT(Q1) ;SETUP POINTER TO FIRST PORTAL BLOCK
DELEP1:	MOVE	T3,EPBNXT(T4)	;GET POINTER TO NEXT PORTAL BLOCK
	JUMPE	T3,[ERRRET (UNNSP%,UNLETH##)] ;ERROR IF NO MORE PORTAL BLOCKS
	CAMN	T3,Q2		;FOUND SUBJECT PORTAL BLOCK?
	JRST	DELEP2		;YES, EXIT LOOP
	MOVE	T4,T3		;SAVE POINTER TO PREVIOUS PORTAL BLOCK
	JRST	DELEP1		;LOOP BACK TO CHECK ALL PORTALS
DELEP2:	MOVE	T3,EPBNXT(T3)	;GET POINTER TO NEXT PORTAL BLOCK
	MOVEM	T3,EPBNXT(T4)	;POINT PREVIOUS PORTAL TO NEXT PORTAL BLOCK
	ETHULK			;RELEASE SMP INTERLOCK
	PJRST	CPOPJ1##	;AND RETURN
	SUBTTL	ETHERNET PORTAL SUPPORT  --  FIND MULTI-CAST ADDRESS


;ROUTINE TO FIND A MULTI-CAST ADDRESS BELONGING TO A PORTAL
;LINKAGE:
;	T1-T2/ MULTI-CAST ADDRESS
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,FNDMCA
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS WITH:
;	T1/ ADDRESS OF MULTI-CAST ADDRESS BLOCK

FNDMCA:	PUSHJ	P,SAVE4##	;SAVE P1-P4
	DMOVE	P1,T1		;SAVE MULTI-CAST ADDRESS
	ETHLOK			;INTERLOCK AGAINST RACES
	XMOVEI	P4,EPBEMB-EMBNXT(Q2) ;SETUP POINTER TO FIRST MULTI-CAST BLOCK
FNDMC1:	MOVE	P3,EMBNXT(P4)	;GET POINTER TO NEXT MULTI-CAST BLOCK
	JUMPE	P3,[ERRRET (UNIMA%,UNLETH##)] ;ERROR IF END OF MULTI-CAST LIST
	CAMN	P1,EMBMCA(P3)	;MATCH SUBJECT MULTI-CAST ADDRESS?
	CAME	P2,EMBMCA+1(P3)	;...
	SKIPA			;NO, CONTINUE SEARCHING
	JRST	FNDMC2		;YES, EXIT LOOP
	MOVE	P4,P3		;SAVE POINTER TO PREVIOUS MULTI-CAST BLOCK
	JRST	FNDMC1		;LOOP BACK TO CHECK ALL MULTI-CAST BLOCKS
FNDMC2:	MOVE	T1,P3		;GET ADDRESS OF MULTI-CAST ADDRESS BLOCK
	ETHULK			;RELEASE SMP INTERLOCK
	PJRST	CPOPJ1##	;AND RETURN
	SUBTTL	ETHERNET PORTAL SUPPORT  --  ADD MULTI-CAST ADDRESS


;ROUTINE TO ADD A MULTI-CAST ADDRESS TO A PORTAL
;LINKAGE:
;	T1-T2/ MULTI-CAST ADDRESS
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,ADDMCA
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS WITH:
;	T1/ ADDRESS OF MULTI-CAST ADDRESS BLOCK

ADDMCA:	PUSHJ	P,SAVE3##	;SAVE P1-P3
	DMOVE	P1,T1		;SAVE MULTI-CAST ADDRESS
	MOVEI	T2,EMBLEN	;GET LENGTH OF MULTI-CAST ADDRESS BLOCK
	PUSHJ	P,GETEWZ##	;ALLOCATE ZEROED CORE FOR BLOCK
	  STOPCD [ERRRET (UNRES%)],DEBUG,ETHCCM ;++CAN'T CREATE MULTI-CAST BLOCK
	MOVE	P3,T1		;SAVE ADDRESS OF MULTI-CAST BLOCK
	DMOVEM	P1,EMBMCA(P3)	;STORE MULTI-CAST ADDRESS
	ETHLOK			;INTERLOCK AGAINST RACES
	XMOVEI	P2,EPBEMB-EMBNXT(Q2) ;SETUP POINTER TO FIRST MULTI-CAST BLOCK
ADDMC1:	MOVE	P1,EMBNXT(P2)	;GET POINTER TO NEXT MULTI-CAST BLOCK
	JUMPE	P1,ADDMC2	;JUMP AT END OF MULTI-CAST LIST
	DMOVE	T1,EMBMCA(P1)	;GET MULTI-CAST ADDRESS
	CAMN	T1,EMBMCA(P3)	;MATCH SUBJECT MULTI-CAST ADDRESS?
	CAME	T2,EMBMCA+1(P3)	;...
	SKIPA			;NO, CONTINUE SEARCHING
	JRST	ADDMC3		;YES, EXIT LOOP
	MOVE	P2,P1		;SAVE POINTER TO PREVIOUS MULTI-CAST BLOCK
	JRST	ADDMC1		;LOOP BACK TO CHECK ALL MULTI-CAST BLOCKS
ADDMC2:	MOVEM	P3,EMBNXT(P2)	;LINK NEW BLOCK TO PREVIOUS MULTI-CAST BLOCK
	MOVE	T1,P3		;GET ADDRESS OF NEW MULTI-CAST ADDRESS BLOCK
	JRST	ADDMC4		;AND CONTINUE
ADDMC3:	MOVEI	T1,EMBLEN	;GET LENGTH OF MULTI-CAST BLOCK
	MOVE	T2,P3		;AND ADDRESS OF BLOCK
	PUSHJ	P,GIVEWS##	;RELEASE DUPLICATE MULTI-CAST BLOCK
	MOVE	T1,P1		;GET ADDRESS OF MULTI-CAST ADDRESS BLOCK
ADDMC4:	ETHULK			;RELEASE SMP INTERLOCK
	PJRST	CPOPJ1##	;AND RETURN
	SUBTTL	ETHERNET PORTAL SUPPORT  --  DELETE MULTI-CAST ADDRESS


;ROUTINE TO DELETE A MULTI-CAST ADDRESS FROM A PORTAL
;LINKAGE:
;	T1-T2/ MULTI-CAST ADDRESS
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,DELMCA
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS

DELMCA:	PUSHJ	P,SAVE4##	;SAVE P1-P4
	DMOVE	P1,T1		;SAVE MULTI-CAST ADDRESS
	ETHLOK			;INTERLOCK AGAINST RACES
	XMOVEI	P4,EPBEMB-EMBNXT(Q2) ;SETUP POINTER TO FIRST MULTI-CAST BLOCK
DELMC1:	MOVE	P3,EMBNXT(P4)	;GET POINTER TO NEXT MULTI-CAST BLOCK
	JUMPE	P3,[ERRRET (UNIMA%,UNLETH##)] ;ERROR IF END OF MULTI-CAST LIST
	CAMN	P1,EMBMCA(P3)	;MATCH SUBJECT MULTI-CAST ADDRESS?
	CAME	P2,EMBMCA+1(P3)	;...
	SKIPA			;NO, CONTINUE SEARCHING
	JRST	DELMC2		;YES, EXIT LOOP
	MOVE	P4,P3		;SAVE POINTER TO PREVIOUS MULTI-CAST BLOCK
	JRST	DELMC1		;LOOP BACK TO CHECK ALL MULTI-CAST BLOCKS
DELMC2:	MOVE	T1,EMBNXT(P3)	;GET LINK TO NEXT BLOCK
	MOVEM	T1,EMBNXT(P4)	;UNLINK THIS MULTI-CAST ADDRESS BLOCK
	MOVEI	T1,EMBLEN	;GET LENGTH OF MULTI-CAST ADDRESS BLOCK
	MOVE	T2,P3		;AND ADDRESS OF BLOCK
	PUSHJ	P,GIVEWS##	;DEALLOCATE MULTI-CAST ADDRESS BLOCK
	ETHULK			;RELEASE SMP INTERLOCK
	PJRST	CPOPJ1##	;AND RETURN
	SUBTTL	ETHERNET PORTAL SUPPORT  --  ENABLE PROTOCOL


;ROUTINE CALLED TO ENABLE A PROTOCOL
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,ETHEPT
;RETURNS:
;	CPOPJ ALWAYS

ETHEPT:	XMOVEI	T1,EPTTB1	;GET ADDRESS OF STATE TRANSITION TABLE
	PJRST	PSTDSP		;DISPATCH BASED ON PROTOCOL STATE

;ENABLE PROTOCOL STATE TRANSITION TABLE

EPTTB1:	XWD	.PSEIP, ETHEP1	;(0) DISABLED
	XWD	.PSEIP, ETHEP1	;(1) DISABLED, WANT TO ENABLE
	XWD	    -1,	CPOPJ##	;(2) ENABLE IN PROGRESS
	XWD	    -1, CPOPJ##	;(3) ENABLE IN PROGRESS, WANT TO DISABLE
	XWD	    -1,	CPOPJ##	;(4) ENABLED
	XWD	    -1, CPOPJ##	;(5) ENABLED, WANT TO DISABLE
	XWD	    -1,	CPOPJ##	;(6) DISABLE IN PROGRESS
;HERE TO START THE ENABLE OF A PROTOCOL
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,ETHEP1
;RETURNS:
;	CPOPJ ALWAYS

ETHEP1:	PUSHJ	P,SAVP3##	;SAVE P3
	PUSHJ	P,SELEKB	;SELECT A KONTROLLER FOR THIS PROTOCOL
	  JRST	ETHEP2		;IF NONE, GO SET DISABLED, WANT TO ENABLE STATE
	MOVEI	T1,EK.EPT	;FUNCTION ENABLE PROTOCOL TYPE
	PUSHJ	P,GENEAB	;GENERATE AN EA BLOCK
	  PJRST	ETHEP2		;ERROR, GO SET DISABLED, WANT TO ENABLE STATE
	MOVE	T1,EPBPTY(Q2)	;GET PROTOCOL TYPE
	MOVEM	T1,.EAPTY(P3)	;STORE IN EA BLOCK
	LDB	T1,EPPPAD	;GET PROTOCOL PADDING FLAG
	MOVEM	T1,.EAPAD(P3)	;STORE IN EA BLOCK
	MOVEM	Q2,.EAPPB(P3)	;STORE ADDRESS OF PORTAL BLOCK
	XMOVEI	T1,ETCEPT	;GET ADDRESS OF COMPLETION ROUTINE
	PUSHJ	P,CALKON	;CALL KONTROLLER
	  JRST	[PUSHJ	P,GIVEAB ;ERROR, RELEASE EA BLOCK
		 PJRST	ETHEP2]	;GO SET DISABLED, WANT TO ENABLE STATE
	POPJ	P,		;RETURN

ETHEP2:	SETZB	Q3,EPBEKB(Q2)	;ZERO KONTROLLER BLOCK ADDRESS
	XMOVEI	T1,EPTTB2	;GET ADDRESS OF STATE TRANSITION TABLE
	PJRST	PSTDSP		;DISPATCH BASED ON PROTOCOL STATE

;ENABLE PROTOCOL PENDING STATE TRANSITION TABLE

EPTTB2:	XWD	    -1, CPOPJ##	;(0) DISABLED
	XWD	    -1, CPOPJ##	;(1) DISABLED, WANT TO ENABLE
	XWD	.PSDWE,	CPOPJ##	;(2) ENABLE IN PROGRESS
	XWD	.PSDIS, ETCDP1	;(3) ENABLE IN PROGRESS, WANT TO DISABLE
	XWD	    -1,	CPOPJ##	;(4) ENABLED
	XWD	    -1, CPOPJ##	;(5) ENABLED, WANT TO DISABLE
	XWD	    -1,	CPOPJ##	;(6) DISABLE IN PROGRESS
;ROUTINE CALLED ON ENABLE PROTOCOL COMPLETION INTERRUPT
;LINKAGE: (CALLED AT INTERRUPT LEVEL)
;	P3/ ADDRESS OF EA BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETCEPT
;RETURNS:
;	CPOPJ ALWAYS

ETCEPT:	XMOVEI	T1,EPTTB3	;GET ADDRESS OF STATE TRANSITION TABLE
	PUSHJ	P,PSTDSP	;DISPATCH BASED ON PROTOCOL STATE
	PJRST	GIVEAB		;RELEASE EA BLOCK AND RETURN

;ENABLE PROTOCOL DONE STATE TRANSITION TABLE

EPTTB3:	XWD	    -1, ETHEPX	;(0) DISABLED
	XWD	    -1, ETHEPX	;(1) DISABLED, WANT TO ENABLE
	XWD	.PSENA,	ETCEP1	;(2) ENABLE IN PROGRESS
	XWD	.PSEWD, ETCEP1	;(3) ENABLE IN PROGRESS, WANT TO DISABLE
	XWD	    -1,	ETHEPX	;(4) ENABLED
	XWD	    -1, ETHEPX	;(5) ENABLED, WANT TO DISABLE
	XWD	    -1,	ETHEPX	;(6) DISABLE IN PROGRESS

ETCEP1:	MOVE	T1,.EAPPB(P3)	;GET ADDRESS OF KONTROLLER'S PROTOCOL BLOCK
	MOVEM	T1,EPBKPB(Q2)	;SAVE IN PORTAL BLOCK
	PUSHJ	P,CALSTS	;GIVE USER STATUS CHANGE CALLBACK
	LDB	T1,EPPSTS	;GET CURRENT PORTAL STATUS
	CAIN	T1,.PSEWD	;ENABLED, WANT TO DISABLE?
	PJRST	ETHDPT		;YES, INITIATE DISABLE OF PROTOCOL
	POPJ	P,		;NO, RETURN

;HERE ON AN UNEXPECTED PROTOCOL STATE TRANSITION

ETHEPX:	STOPCD	CPOPJ##,DEBUG,ETHUES ;++UNEXPECTED ENABLE PROTOCOL STATE
	SUBTTL	ETHERNET PORTAL SUPPORT  --  DISABLE PROTOCOL


;ROUTINE CALLED TO DISABLE A PROTOCOL
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,ETHDPT
;RETURNS:
;	CPOPJ ALWAYS

ETHDPT:	XMOVEI	T1,DPTTB1	;GET ADDRESS OF STATE TRANSITION TABLE
	PJRST	PSTDSP		;DISPATCH BASED ON PROTOCOL STATE

;DISABLE PROTOCOL STATE TRANSITION TABLE

DPTTB1:	XWD	    -1, CPOPJ##	;(0) DISABLED
	XWD	.PSDIS, ETCDP1	;(1) DISABLED, WANT TO ENABLE
	XWD	.PSEPD,	CPOPJ##	;(2) ENABLE IN PROGRESS
	XWD	    -1, CPOPJ##	;(3) ENABLE IN PROGRESS, WANT TO DISABLE
	XWD	.PSDIP,	ETHDP1	;(4) ENABLED
	XWD	.PSDIP, ETHDP1	;(5) ENABLED, WANT TO DISABLE
	XWD	    -1,	CPOPJ##	;(6) DISABLE IN PROGRESS
;HERE TO START THE DISABLE OF A PROTOCOL
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,ETHDP1
;RETURNS:
;	CPOPJ ALWAYS

ETHDP1:	PUSHJ	P,SAVP3##	;SAVE P3
	PUSHJ	P,CALSTS	;GIVE USER STATUS CHANGE CALLBACK
	MOVEI	T1,EK.DPT	;FUNCTION DISABLE PROTOCOL TYPE
	PUSHJ	P,GENEAB	;GENERATE AN EA BLOCK
	  PJRST	ETHDP2		;ERROR, GO SET ENABLED, WANT TO DISABLE STATE
	MOVE	T1,EPBPTY(Q2)	;GET PROTOCOL TYPE
	MOVEM	T1,.EAPTY(P3)	;STORE IN EA BLOCK
	LDB	T1,EPPPAD	;GET PROTOCOL PADDING FLAG
	MOVEM	T1,.EAPAD(P3)	;STORE IN EA BLOCK
	MOVEM	Q2,.EAPPB(P3)	;STORE ADDRESS OF PORTAL BLOCK
	XMOVEI	T1,ETCDPT	;GET ADDRESS OF COMPLETION ROUTINE
	PUSHJ	P,CALKON	;CALL KONTROLLER
	  JRST	[PUSHJ	P,GIVEAB ;ERROR, RELEASE EA BLOCK
		 PJRST	ETHDP2]	;GO SET ENABLED, WANT TO DISABLE STATE
	POPJ	P,		;RETURN

ETHDP2:	XMOVEI	T1,DPTTB2	;GET ADDRESS OF STATE TRANSITION TABLE
	PJRST	PSTDSP		;DISPATCH BASED ON PROTOCOL STATE

;DISABLE PROTOCOL PENDING STATE TRANSITION TABLE

DPTTB2:	XWD	    -1, CPOPJ##	;(0) DISABLED
	XWD	    -1, CPOPJ##	;(1) DISABLED, WANT TO ENABLE
	XWD	    -1,	CPOPJ##	;(2) ENABLE IN PROGRESS
	XWD	    -1, CPOPJ##	;(3) ENABLE IN PROGRESS, WANT TO DISABLE
	XWD	    -1,	CPOPJ##	;(4) ENABLED
	XWD	    -1, CPOPJ##	;(5) ENABLED, WANT TO DISABLE
	XWD	.PSEWD,	CPOPJ##	;(6) DISABLE IN PROGRESS
;ROUTINE CALLED ON DISABLE PROTOCOL COMPLETION INTERRUPT
;LINKAGE: (CALLED AT INTERRUPT LEVEL)
;	P3/ ADDRESS OF EA BLOCK
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETCDPT
;RETURNS:
;	CPOPJ ALWAYS

ETCDPT:	XMOVEI	T1,DPTTB3	;GET ADDRESS OF STATE TRANSITION TABLE
	PUSHJ	P,PSTDSP	;DISPATCH BASED ON PROTOCOL STATE
	PJRST	GIVEAB		;RELEASE EA BLOCK AND RETURN

;DISABLE PROTOCOL DONE STATE TRANSITION TABLE

DPTTB3:	XWD	    -1, ETHDPX	;(0) DISABLED
	XWD	    -1, ETHDPX	;(1) DISABLED, WANT TO ENABLE
	XWD	    -1,	ETHDPX	;(2) ENABLE IN PROGRESS
	XWD	    -1, ETHDPX	;(3) ENABLE IN PROGRESS, WANT TO DISABLE
	XWD	    -1,	ETHDPX	;(4) ENABLED
	XWD	    -1, ETHDPX	;(5) ENABLED, WANT TO DISABLE
	XWD	.PSDIS,	ETCDP1	;(6) DISABLE IN PROGRESS

ETCDP1:	SETZB	Q3,EPBEKB(Q2)	;ZERO KONTROLLER BLOCK ADDRESS
	MOVX	T1,EPSOPN	;IS PORTAL OPEN?
	TDNE	T1,EPBSTS(Q2)	;...
	PJRST	ETHEPT		;YES, GO TRY TO ENABLE PROTOCOL
	PUSHJ	P,SAVP4##	;SAVE P4
	XMOVEI	P4,EPBCBU(Q2)	;GET ADDRESS OF CALLBACK UN BLOCK
	MOVE	T1,EPBPTY(Q2)	;GET PROTOCOL TYPE CODE
	STOR	T1,UNPRO,(P4)	;STORE IN UN BLOCK
	MOVEI	T1,NU.CLO	;GIVE USER CLOSE PORTAL CALLBACK
	PUSHJ	P,CALUSR	;...
	PUSHJ	P,DELEPB	;DELETE PORTAL BLOCK FROM ETHERNET CHANNEL
	  JFCL			;DON'T CARE IF ERROR
	MOVEI	T1,EPBLEN	;GET LENGTH OF PORTAL BLOCK
	MOVE	T2,Q2		;AND ADDRESS OF PORTAL BLOCK
	PJRST	GIVEWS##	;RELEASE PORTAL BLOCK AND RETURN

;HERE ON AN UNEXPECTED PROTOCOL STATE TRANSITION

ETHDPX:	STOPCD	CPOPJ##,DEBUG,ETHUDS ;++UNEXPECTED DISABLE PROTOCOL STATE
	SUBTTL	ETHERNET PORTAL SUPPORT  --  PROTOCOL STATE TRANSTITION


;ROUTINE CALLED FOR PROTOCOL STATE TRANSITIONS
;LINKAGE:
;	T1/ ADDRESS OF STATE TRANSITION TABLE
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,PSTDSP
;RETURNS:
;	CPOPJ OR CPOPJ1 BASED ON TRANSITION ROUTINE

PSTDSP:	ETHLOK			;INTERLOCK AGAINST SMP RACES
	LDB	T2,EPPSTS	;GET CURRENT PROTOCOL STATUS
	CAILE	T2,.PSMAX	;RANGE CHECK PROTOCOL STATUS
	STOPCD	UNLETH##,DEBUG,ETHIPS ;++INVALID PROTOCOL STATE
	ADD	T1,T2		;COMPUTE DISPATCH TABLE OFFSET
	HLRE	T3,(T1)		;GET NEW PROTOCOL STATE
	JUMPL	T3,PSTDS1	;JUMP IF NO CHANGE OF STATE
	DPB	T2,EPPPST	;SAVE PREVIOUS STATE
	DPB	T3,EPPSTS	;STORE UPDATED PROTOCOL STATUS
PSTDS1:	ETHULK			;RELEASE SMP INTERLOCK
	HRRZ	T3,(T1)		;GET LOCAL ADDRESS OF ROUTINE
	PJRST	(T3)		;DISPATCH TO TRANSITION ROUTINE AND RETURN
	SUBTTL	ETHERNET KONTROLLER SUPPORT  --  CREATE KONTROLLER BLOCK


;ROUTINE TO CREATE AN ETHERNET KONTROLLER BLOCK
;LINKAGE:
;	PUSHJ	P,GENEKB
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS WITH:
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK

GENEKB:	MOVEI	T2,EKBLEN	;GET LENGTH OF ETHERNET KONTROLLER BLOCK
	S0PSHJ	AUTCOR##	;ALLOCATE ZEROED CORE FOR KONTROLLER BLOCK
	  ERRRET (UNRES%)	;ERROR, NO RESOURCES
	MOVE	Q3,T1		;SAVE ADDRESS OF ETHERNET KONTROLLER BLOCK
	AOS	T1,%EINEK	;INCREMENT NUMBER OF KONTROLLERS
	MOVEM	T1,EKBKID(Q3)	;SET KONTROLLER ID
	ETHLOK			;INTERLOCK AGAINST SMP RACES
	XMOVEI	T4,%EIKON-EKBSYS ;SET UP POINTER TO FIRST-1 KONTROLLER BLOCK
GENEK1:	MOVE	T3,EKBSYS(T4)	;GET ADDRESS OF NEXT KONTROLLER BLOCK
	JUMPE	T3,GENEK2	;JUMP AT END OF KONTROLLER LIST
	MOVE	T4,T3		;SAVE POINTER TO PREVIOUS KONTROLLER BLOCK
	JRST	GENEK1		;LOOP BACK TO FIND END OF LIST
GENEK2:	MOVEM	Q3,EKBSYS(T4)	;LINK THIS KONTROLLER AT END OF LIST
	SETZM	EKBSYS(Q3)	;...
	ETHULK			;RELEASE SMP INTERLOCK
	PJRST	CPOPJ1##	;AND RETURN
	SUBTTL	ETHERNET KONTROLLER SUPPORT  --  GENERATE KONTROLLER STATUS WORD


;ROUTINE TO GENERATE KONTROLLER STATUS WORD
;LINKAGE:
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,GENKSW
;RETURNS:
;	CPOPJ ALWAYS WITH:
;	T1/ KONTROLLER STATUS WORD
;MUST PRESERVE T3-T4

GENKSW:	SETZ	T1,		;START WITH ZERO
	MOVE	T2,EKBSTS(Q3)	;GET KONTROLLER STATUS
	TXNE	T2,EKSONL	;IS KONTROLLER ONLINE?
	TXO	T1,ET.KON	;YES, MARK KONTROLLER AS ONLINE
	MOVE	T2,EKBKID(Q3)	;GET KONTROLLER ID
	DPB	T2,[POINTR (T1,ET.KID)] ;STORE IN KONTROLLER STATUS WORD
	POPJ	P,		;AND RETURN
	SUBTTL	ETHERNET KONTROLLER SUPPORT  --  SELECT AN ETHERNET KONTROLLER


;ROUTINE TO SELECT AN ETHERNET KONTROLLER FOR AN ETHERNET PORTAL
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q2/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,SELEKB
;RETURNS:
;	CPOPJ ON ERROR
;	CPOPJ1 ON SUCCESS WITH:
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK

SELEKB:	ETHLOK			;INTERLOCK AGAINST SMP RACES
	SETZ	T2,		;USED TO REMEMBER FIRST USABLE KONTROLLER
	SKIPA	Q3,ECBEKB(Q1)	;GET ADDRESS OF FIRST KONTROLLER
SELEK1:	MOVE	Q3,EKBNXT(Q3)	;GET ADDRESS OF NEXT KONTROLLER
	JUMPE	Q3,[MOVE  Q3,T2	;IF NONE, GET REMEMBERED KONTROLLER'S ADDRESS
		    JRST  SELEK2] ;AND EXIT LOOP
	MOVX	T1,EKSONL	;IS KONTROLLER ONLINE?
	TDNN	T1,EKBSTS(Q3)	;...
	JRST	SELEK1		;NO, LOOP BACK TO CHECK NEXT KONTROLLER
	SKIPN	T2		;ALREADY REMEMBERED FIRST USABLE KONTROLLER?
	MOVE	T2,Q3		;NO, REMEMBER THIS KONTROLLER
	LDB	T1,EKPCPU	;GET CPU NUMBER OF ETHERNET KONTROLLER
	CAME	T1,.CPCPN##	;ACCESSIBLE BY THIS CPU?
	JRST	SELEK1		;NO, LOOP BACK TO CHECK NEXT KONTROLLER
SELEK2:	MOVEM	Q3,EPBEKB(Q2)	;STORE KONTROLLER BLOCK ADDRESS IN PORTAL BLOCK
	ETHULK			;RELEASE SMP INTERLOCK
	PJUMPN	Q3,CPOPJ1##	;AND RETURN
	POPJ	P,		;...
	SUBTTL	ETHERNET KONTROLLER SUPPORT  --  FIND ETHERNET KONTROLLER BLOCK


;ROUTINE TO FIND AN ETHERNET KONTROLLER BLOCK GIVEN KONTROLLER ID
;LINKAGE:
;	T1/ KONTROLLER ID
;	PUSHJ	P,FNDEKB
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS WITH:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK

FNDEKB:	ANDX	T1,ET.KID	;MASK TO JUST KONTROLLER ID
	ETHLOK			;INTERLOCK AGAINST SMP RACES
	SKIPA	Q1,%EICHN	;GET ADDRESS OF FIRST ETHERNET CHANNEL BLOCK
FNDEK1:	MOVE	Q1,ECBSYS(Q1)	;GET ADDRESS OF NEXT ETHERNET CHANNEL BLOCK
	JUMPE	Q1,[ERRRET (UNNSK%,UNLETH##)] ;ERROR, NO SUCH KONTROLLER
	SKIPA	Q3,ECBEKB(Q1)	;GET ADDRESS OF FIRST ETHERNET KONTROLLER BLOCK
FNDEK2:	MOVE	Q3,EKBNXT(Q3)	;GET ADDRESS OF NEXT ETHERNET KONTROLLER BLOCK
	JUMPE	Q3,FNDEK1	;END OF KONTROLLER LIST, TRY NEXT CHANNEL
	CAME	T1,EKBKID(Q3)	;FOUND CORRECT KONTROLLER BLOCK?
	JRST	FNDEK2		;NO, LOOP THROUGH ALL KONTROLLERS
	ETHULK			;RELEASE SMP INTERLOCK
	PJRST	CPOPJ1##	;RETURN
	SUBTTL	ETHERNET KONTROLLER SUPPORT  --  ADD ETHERNET KONTROLLER BLOCK


;ROUTINE TO ADD AN ETHERNET KONTROLLER TO AN ETHERNET CHANNEL
;LINKAGE:
;	Q1/ ADDRESS OF ETHERNET CHANNEL BLOCK
;	Q3/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ADDEKB
;RETURNS:
;	CPOPJ ALWAYS

ADDEKB:	ETHLOK			;INTERLOCK AGAINST SMP RACES
	XMOVEI	T4,ECBEKB-EKBNXT(Q1) ;SETUP POINTER TO FIRST KONTROLLER BLOCK
ADDEK1:	MOVE	T3,EKBNXT(T4)	;GET POINTER TO NEXT KONTROLLER BLOCK
	JUMPE	T3,ADDEK2	;JUMP AT END OF KONTROLLER LIST
	CAMN	T3,Q3		;KONTROLLER ALREADY IN LIST?
	PJRST	UNLETH##	;YES, RELEASE SMP INTERLOCK AND RETURN
	MOVE	T4,T3		;SAVE POINTER TO PREVIOUS KONTROLLER BLOCK
	JRST	ADDEK1		;LOOP BACK TO FIND END OF LIST
ADDEK2:	MOVEM	Q3,EKBNXT(T4)	;POINT PREVIOUS KONTROLLER TO NEW KONTROLLER
	SETZM	EKBNXT(Q3)	;TERMINATE LIST WITH THIS KONTROLLER BLOCK
	MOVEM	Q1,EKBECB(Q3)	;SAVE ADDRESS OF ETHERNET CHANNEL BLOCK
	PJRST	UNLETH##	;RELEASE SMP INTERLOCK AND RETURN
	SUBTTL	ETHERNET INTERRUPT SERVICE  --  KONTROLLER INITIALIZATION


;ROUTINE CALLED BY DEVICE DRIVER WHEN A KONTROLLER IS INITIALIZED
;LINKAGE: (CALLED AT ONCE TIME)
;	T1/ ADDRESS OF KONTROLLER'S KONTROLLER BLOCK
;	T2/ ADDRESS OF KONTROLLER'S DISPATCH ROUTINE
;	T3/ KONTROLLER TYPE,,KONTROLLER NUMBER
;	PUSHJ	P,ETKINI
;RETURNS:
;	CPOPJ ON ERROR WITH:
;	T1/ ERROR CODE (UNXXX%)
;	CPOPJ1 ON SUCCESS WITH:
;	T1/ ADDRESS OF ETHERNET KONTROLLER BLOCK

ETKINI::PUSHJ	P,SAVE3##	;SAVE P1-P3
	PUSHJ	P,SAVQ##	;AND Q1-Q3
	DMOVE	P1,T1		;SAVE KONTROLLER'S BLOCK AND ROUTINE ADDRESSES
	MOVE	P3,T3		;SAVE KONTROLLER TYPE CODE
	PUSHJ	P,GENEKB	;CREATE AN ETHERNET KONTROLLER BLOCK
	  POPJ	P,		;ERROR, ERROR CODE IN T1
	MOVEM	P1,EKBKKB(Q3)	;SAVE ADDRESS OF KONTROLLER'S KONTROLLER BLOCK
	MOVEM	P2,EKBKDA(Q3)	;AND ADDRESS OF KONTROLLER'S DISPATCH ROUTINE
	MOVE	T1,.CPCPN##	;GET OUR CPU NUMBER
	DPB	T1,EKPCPU	;SAVE IN KONTROLLER BLOCK
	HLRZ	T1,P3		;GET KONTROLLER TYPE CODE
	DPB	T1,EKPKTY	;SAVE IN KONTROLLER BLOCK
	HRRZ	T1,P3		;GET KONTROLLER NUMBER
	DPB	T1,EKPKNO	;SAVE IN KONTROLLER BLOCK
	MOVE	T1,Q3		;GET ADDRESS OF ETHERNET KONTROLLER BLOCK
	PJRST	CPOPJ1##	;AND RETURN
	SUBTTL	ETHERNET INTERRUPT SERVICE  --  KONTROLLER OFFLINE


;ROUTINE CALLED BY DEVICE DRIVER ON KONTROLLER OFFLINE
;LINKAGE:
;	T1/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	PUSHJ	P,ETKOFL
;RETURNS:
;	CPOPJ ALWAYS

ETKOFL::PUSHJ	P,SAVQ##	;SAVE Q1-Q3
	MOVE	Q3,T1		;GET ADDRESS OF ETHERNET KONTROLLER BLOCK
	MOVX	T1,EKSONL	;MARK KONTROLLER AS OFFLINE
	ANDCAM	T1,EKBSTS(Q3)	;...
	SKIPN	Q1,EKBECB(Q3)	;GET ADDRESS OF ETHERNET CHANNEL BLOCK
	POPJ	P,		;NONE, JUST RETURN NOW
	ETHLOK			;INTERLOCK AGAINST SMP RACES
	SKIPA	Q2,ECBEPB(Q1)	;GET ADDRESS OF FIRST ETHERNET PORTAL BLOCK
ETKOF1:	MOVE	Q2,EPBNXT(Q2)	;GET ADDRESS OF NEXT ETHERNET PORTAL BLOCK
	JUMPE	Q2,UNLETH##	;RETURN AT END OF PORTAL LIST
	MOVE	T1,EPBEKB(Q2)	;GET ADDRESS OF ASSIGNED KONTROLLER BLOCK
	CAMN	T1,Q3		;MATCH OFFLINE KONTROLLER?
	PUSHJ	P,ETHDPT	;YES, INITIATE DISABLE OF PROTOCOL
	JRST	ETKOF1		;LOOP BACK TO CHECK ALL PORTALS
	SUBTTL	ETHERNET INTERRUPT SERVICE  --  KONTROLLER ONLINE


;ROUTINE CALLED BY DEVICE DRIVER ON KONTROLLER ONLINE
;LINKAGE:
;	T1/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	T2-T3/ HARDWARE ETHERNET ADDRESS
;	PUSHJ	P,ETKONL
;RETURNS:
;	CPOPJ ALWAYS

ETKONL::PUSHJ	P,SAVQ##	;SAVE Q1-Q3
	MOVE	Q3,T1		;GET ADDRESS OF ETHERNET KONTROLLER BLOCK
	DMOVEM	T2,EKBHEA(Q3)	;STORE HARDWARE ETHERNET ADDRESS
	MOVX	T1,EKSONL	;MARK KONTROLLER AS ONLINE
	IORM	T1,EKBSTS(Q3)	;...
	SKIPE	Q1,EKBECB(Q3)	;ALREADY ASSIGNED TO A CHANNEL?
	JRST	ETKON1		;YES, DON'T NEED TO ADD KONTROLLER THEN
	MOVE	Q1,%EICHN	;GET ADDRESS OF ETHERNET CHANNEL BLOCK
	PUSHJ	P,ADDEKB	;ADD KONTROLLER TO CHANNEL
ETKON1:	SKIPE	ECBEAD(Q1)	;DOES CHANNEL HAVE AN ETHERNET ADDRESS?
	JRST	ETKON2		;YES, SET KONTROLLER TO THAT ADDRESS
	DMOVE	T1,EKBHEA(Q3)	;NO, GET HARDWARE ADDRESS OF KONTROLLER
	DMOVEM	T1,ECBEAD(Q1)	;AND SET THAT UP AS CHANNEL'S ADDRESS
	POPJ	P,		;RETURN
ETKON2:	MOVX	T1,EKSSEA	;FLAG SET ETHERNET ADDRESS FUNCTION
	IORM	T1,EKBSTS(Q3)	;...
	POPJ	P,		;AND RETURN
	SUBTTL	ETHERNET INTERRUPT SERVICE  --  KONTROLLER FUNCTION DONE


;ROUTINE CALLED BY DEVICE DRIVER ON KONTROLLER FUNCTION DONE
;LINKAGE:
;	T1/ ADDRESS OF EA BLOCK
;	T2/ ADDRESS OF ETHERNET KONTROLLER BLOCK
;	T3/ ADDRESS OF ETHERNET PORTAL BLOCK
;	PUSHJ	P,ETKINT
;RETURNS:
;	CPOPJ ALWAYS

ETKINT::PUSHJ	P,SAVP3##	;SAVE P3
	PUSHJ	P,SAVQ##	;AND Q1-Q3
	MOVE	P3,T1		;GET ADDRESS OF EA BLOCK
	MOVE	Q3,T2		;AND ADDRESS OF ETHERNET KONTROLLER BLOCK
	MOVE	Q2,.EAFCP(P3)	;AND ADDRESS OF ETHERNET PORTAL BLOCK
	MOVE	Q1,EKBECB(Q3)	;GET ADDRESS OF ETHERNET CHANNEL BLOCK
	DMOVE	T2,.EAFCD(P3)	;GET COMPLETION DATA
	MOVE	T4,.EAFCD+2(P3)	;...
	PJRST	@.EAFCA(P3)	;DISPATCH TO COMPLETION ROUTINE AND RETURN
	SUBTTL	ETHERNET SUPPORT  --  UPDATE ETHERNET COUNTERS


;ROUTINE CALLED TO UPDATE ETHERNET COUNTERS
;LINKAGE:
;	T1/ LENGTH OF COUNTERS AREA
;	T2/ ILDB BYTE POINTER TO UPDATE ACTION TABLE
;	T3/ ADDRESS OF SOURCE COUNTERS AREA
;	T4/ ADDRESS OF DESTINATION COUNTERS AREA
;RETURNS:
;	CPOPJ ALWAYS

UPDCTR:	PUSHJ	P,SAVE2##	;SAVE P1-P2
	DMOVE	P1,T1		;SAVE LENGTH AND BYTE POINTER TO ACTION TABLE
UPDCT1:	ILDB	T2,P2		;GET UPDATE ACTION CODE
	MOVE	T1,(T3)		;GET VALUE OF NEXT COUNTER
	XCT	UPDCOD(T2)	;UPDATE COUNTER APPROPRIATELY
	XMOVEI	T3,1(T3)	;UPDATE SOURCE COUNTERS ADDRESS
	XMOVEI	T4,1(T4)	;AND DESTINATION COUNTERS ADDRESS
	SOJG	P1,UPDCT1	;LOOP BACK FOR ALL COUNTERS
	POPJ	P,		;AND RETURN

;TABLE OF UPDATE ACTIONS

UPDCOD:	ADDM	T1,(T4)		;ADDITIVE COUNTER
	IORM	T1,(T4)		;ADDITIVE BITMAP
	SUBTTL	ETHERNET SUPPORT  --  GENERATE TWO WORD GLOBAL BYTE POINTER


;ROUTINE TO GENERATE A TWO WORD GLOBAL BYTE POINTER FROM
;ANY VALID ONE OR TWO WORD BYTE POINTER
;LINKAGE:
;	T1-T2/ BYTE POINTER
;	PUSHJ	P,GTWGBP
;RETURNS:
;	CPOPJ ALWAYS WITH:
;	T1-T2/ TWO WORD GLOBAL BYTE POINTER

GTWGBP::LDB	T3,[POINT 6,T1,5] ;GET "P" FIELD OF BYTE POINTER
	CAILE	T3,44		;IS THIS A ONE WORD GLOBAL BYTE POINTER?
	JRST	GTWGB2		;YES, PROCESS SEPERATELY
	TLNE	T1,(1B12)	;IS IT A ONE WORD LOCAL BYTE POINTER?
	JRST	GTWGB1		;NO, CONTINUE
	LDB	T2,[POINT 23,T1,35] ;YES, CONVERT INTO TWO WORD LOCAL
	TLO	T2,(1B0)	;...
	TLO	T1,(1B12)	;...
	TDZ	T1,[37,,777777]	;...
GTWGB1:	TLNN	T2,(1B0)	;IS IT ALREADY A TWO WORD GLOBAL BYTE POINTER?
	POPJ	P,		;YES, RETURN
	HLRZ	T3,T2		;GET INDIRECT AND INDEX FIELDS
	HRRZS	T2		;ISOLATE ADDRESS WITH ZERO SECTION NUMBER
	DPB	T3,[POINT 5,T2,5] ;STORE BACK INDIRECT AND INDEX FIELDS
	POPJ	P,		;AND RETURN
GTWGB2:	MOVE	T2,T1		;SET UP ADDRESS PORTION OF BYTE POINTER
	TLZ	T2,(77B5)	;...
	ROT	T3,-1		;COMPUTE TABLE OFFSET AND LH/RH FLAG
	TLZN	T3,(1B0)	;SELECT EITHER LEFT OR RIGHT HALF WORD
	SKIPA	T1,OWBTWB-22(T3) ;FETCH FIRST WORD OF BYTE POINTER
	MOVS	T1,OWBTWB-22(T3) ;...
	HLLZS	T1		;KEEP JUST "P" AND "S" FIELDS
	POPJ	P,		;AND RETURN

;TABLE FOR CONVERTING FROM ONE WORD GLOBAL "P&S" VALUE TO NORMAL
;BYTE POINTER "P" AND "S" FIELDS

OWBTWB:	000000,,440600		;44,,45
	360600,,300600		;46,,47
	220600,,140600		;50,,51
	060600,,000600		;52,,53
	441000,,341000		;54,,55
	241000,,141000		;56,,57
	041000,,440700		;60,,61
	350700,,260700		;62,,63
	170700,,100700		;64,,65
	010700,,441100		;66,,67
	331100,,221100		;70,,71
	111100,,001100		;72,,73
	442200,,222200		;74,,75
	002200,,444400		;76,,77
	SUBTTL	BYTE POINTERS


;BYTE POINTERS FOR PORTAL ID IN T1

PIPECN:	POINTR	(T1,PI.ECI)		;ETHERNET CHANNEL ID
PIPEPB:	POINTR	(T1,PI.EPB)		;ETHERNET PORTAL BLOCK ADDRESS


;BYTE POINTERS FOR ETHERNET PORTAL BLOCK

EPPPST:	POINTR	(EPBSTS(Q2),EPSPST)	;PREVIOUS PROTOCOL STATUS
EPPSTS:	POINTR	(EPBSTS(Q2),EPSSTS)	;CURRENT PROTOCOL STATUS
EPPPAD:	POINTR	(EPBSTS(Q2),EPSPAD)	;PROTOCOL PADDING BIT


;BYTE POINTERS FOR ETHERNET KONTROLLER BLOCK

EKPCPU:	POINTR	(EKBKTY(Q3),EKYCPU)	;CPU NUMBER OF KONTROLLER
EKPKTY:	POINTR	(EKBKTY(Q3),EKYKTY)	;KONTROLLER TYPE CODE
EKPKNO:	POINTR	(EKBKTY(Q3),EKYKNO)	;KONTROLLER NUMBER


;BYTE POINTERS TO COUNTERS UPDATE ACTION TABLES

UKCUAP:	POINT	1,UKCUAT		;POINTER TO KONTROLLER ACTION TABLE


;UPDATE ACTION TABLES

UKCUAT:	EXP	1B<KC.XFM>!1B<KC.RFM>	;TRANSMIT AND RECEIVE FAILURE MASKS
	SUBTTL	ETHERNET INFORMATION GETTAB TABLE


;GETTAB TABLE .GTETH(202) - ETHERNET INFORMATION

	$LOW			;PUT INTO LOW SEGMENT

ETHGTB::			;ETHERNET INFORMATION GETTAB TABLE
%EINEC:	BLOCK	1		;NUMBER OF ETHERNET CHANNELS ON SYSTEM
%EICHN: BLOCK	1		;ADDRESS OF FIRST ETHERNET CHANNEL BLOCK
%EINEK:	BLOCK	1		;NUMBER OF ETHERNET KONTROLLERS ON SYSTEM
%EIKON:	BLOCK	1		;ADDRESS OF FIRST ETHERNET KONTROLLER BLOCK
%EISYS:	ECBSYS,,EKBSYS		;OFFSETS TO SYSTEM WIDE LINK WORDS
%EISTS:	ECBSTS,,EKBSTS		;OFFSETS TO STATUS WORDS

%EIBYR:	BLOCK	1		;TOTAL BYTES RECEIVED
%EIBYX:	BLOCK	1		;TOTAL BYTES TRANSMITTED
%EIDGR:	BLOCK	1		;TOTAL DATAGRAMS RECEIVED
%EIDGX:	BLOCK	1		;TOTAL DATAGRAMS TRANSMITTED

ETHMXL==:<.-ETHGTB-1>B26	;MAXIMUM ENTRY IN TABLE FOR GETTAB UUO

	$HIGH			;BACK TO HIGH SEGMENT
	SUBTTL	THE END


ETHLIT:!XLIST			;LITERALS
	LIT
	LIST

ETHEND:!END