Google
 

Trailing-Edge - PDP-10 Archives - BB-BT99V-BB_1990 - 10,7/mon/raxkon.mac
There are 9 other files named raxkon.mac in the archive. Click here to see a list.
TITLE	RAXKON - DRIVER FOR DISKS ON AN HSC-50	V46
SUBTTL	JOSEPH A. DZIEDZIC/JAD	28-SEP-90

	SEARCH	F,S,DEVPRM,SCAPRM,MSCPAR,MACSYM
	$RELOC
	$HIGH


;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED
;  OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1984,1986,1988,1990.
;ALL RIGHTS RESERVED.

.CPYRT<1984,1990>


XP	VRXKON,46


RAXKON::!ENTRY	RAXKON		;LOAD IF LIBRARY SEARCH
	SUBTTL	COMMENTARY


COMMENT	|

RAXKON IS INTENDED AS A BLACK BOX INTERFACE BETWEEN FILSER AND THE
SYSTEMS COMMUNICATION ARCHITECTURE.  MANY OF THE ENTRY POINTS IN
RAXKON SPECIFIED BY THE "IDEAL" CONTROLLER HAVE NO COUNTERPART IN
OUR DEALINGS WITH THE HSC-50 STORAGE CONTROLLER, AS IT HANDLES ALL
POSITIONING, LATENCY OPTIMIZATION, AND ERROR RECOVERY.  WHERE THIS
IS THE CASE THE REQUIRED GLOBAL ROUTINES ARE AN ELABORATE NO-OP.

|; END OF COMMENT
	SUBTTL	AUTOCONFIGURATION TABLES

RAFIX==0			;NOT FIXED HEAD (THOUGH WE NEVER POSITION)
RAOFS==0			;NO OFFSET, BUT WANT FILIO TO DO ERROR RECOVERY
RARDC==400000			;NO 10/11 COMPATABILITY MODE
RAUNL==400000			;NO UNLOAD CAPABILITY (NOT QUITE TRUE)
RACPY==0			;CAN TELL UNIT TYPE EVEN IF KONTROL IS BUSY
RAMX==KOPMX			;CAPABLE OF MULTIPLE TRANSFERS
RADRB==KOPDRB			;USES DISK I/O REQUEST BLOCKS
RABMX==0			;NOT A BLOCK MULTIPLEX KONTROLLER
RAECA==0			;TRY OFFSET/RECAL BEFORE TRYING ECC
RAERNO==0			;NO DRIVE REGISTERS TO SAVE ON ERROR

RAXDMX==^D8*4			;MAXIMUM DRIVES PER KONTROLLER
				;8 K.SDI BOARDS (MAX), 4 DRIVES PER K.SDI BOARD
RAXHDN==^D255			;HIGHEST DRIVE NUMBER ON KONTROLLER

;DRIVER CHARACTERISTICS
;	RAX	= RAXCNF
;	DSK	= DISK
;	0	= MAXIMUM DEVICES IN SYSTEM (NO LIMIT)
;	TYPRA	= KONTROLLER TYPE
;	RAXDMX	= MAXIMUM DRIVES PER KONTROLLER
;	RAXHDN	= HIGHEST DRIVE NUMBER ON KONTROLLER
;	MDSEC0	= SECTION FOR KDB/UDB
;	MDSEC0	= SECTION FOR DDB
DRVCHR	(RAX,DSK,0,TYPRA,RAXDMX,RAXHDN,MDSEC0,MDSEC0,DR.MCD)

	.ORG	KONUDB		;START OF HSC/RA SPECIFIC DATA
RAXUTB:!BLOCK	RAXDMX		;TABLE OF POINTERS TO UDBS
RAXEBK:!BLOCK	1		;DUMMY ERROR REGISTER STORAGE WORD
RAKCID:!BLOCK	2		;CONTROLLER ID
				;TABLES INDEXED BY CPU NUMBER
RAKCTI::!BLOCK	6		;CONNECT TABLE INDEX FOR THIS KONTROLLER
RAKTIM:!BLOCK	6		;KONTROLLER TIMEOUT COUNTER
RAKTMO:!BLOCK	6		;KONTROLLER TIMEOUT VALUE (SECONDS)
				;END OF TABLES INDEXED BY CPU NUMBER
RAXIUM:! BLOCK	RAXDMW		;IGNORE DRIVE MASK
RAXNUM:! BLOCK	RAXDMW		;NEW DRIVE MASK
RAXKLN:!			;LENGTH OF KDB
	.ORG

;PROTOTYPE KDB
RAXKDB:	XXKON	(RA)
	KDBEND

EQUATE	(LOCAL,0,<RAXICD,RAXICL,RAXUDB,RAXULP,RAXULB>)
EQUATE	(LOCAL,CPOPJ##,<RAXINI,RAXINX,RAXRLD,RAXEDL>)
EQUATE	(LOCAL,CPOPJ1##,<RAXCFG>)

	RAXUDB==0		;NO PROTOTYPE UDB
	RAXULN==UNIEBK		;LENGTH OF UDB

RAXDSP:	DRVDSP	(RAX,DSKCHN##,DSKDDB##,DDBLEN##,DSKDIA##)

RAXCKT:	EXP	TYPRA,	0	;COMPATIBLE KONTROLLER TABLE


	RAXRBT==24*74		;RANDOM BLOCK READ TIMER
	SUBTTL	PROCESS NAME AND BUFFERING DEFINITIONS


;THE PROCESS NAME STRINGS ARE REQUIRED BY SCA TO BE 16 BYTE
;8-BIT ASCII STRINGS

;SOURCE PROCESS NAME STRING FOR THE TOPS-10 MSCP DISK DRIVER

OURDNM:	ASCI8	(<T-10$DISK       >)

;DESTINATION PROCESS NAME STRING FOR THE MSCP DISK SERVER

YURDNM:	ASCI8	(<MSCP$DISK       >)


;BUFFERING/CREDIT DEFINITIONS FOR THE CALL TO SC.CON

DCREDT==^D1			;MINIMUM RECEIVE CREDIT

HSCBFN==^D25			;NUMBER OF BUFFERS HSC SHOULD KEEP FOR US

DGNUM==^D5			;NUMBER OF DATAGRAM BUFFERS WE NEED
	SUBTTL	START DRIVE POSITIONING


;ROUTINE TO CAUSE THE DRIVE TO DO A RECALIBRATE OPERATION.
;CALL:
;	J/ KDB ADDRESS
;	U/ UDB ADDRESS
;	PUSHJ	P,RAXRCL
;RETURN:
;	CPOPJ IF ERROR
;	CPOPJ1 WITH RECAL STARTED
;
;NOTE:  FILSER NEVER CALLS THIS ROUTINE, BUT COMMON DOES ON
;RESUMPTION AFTER A SYSTEM SLEEP.  OTHERWISE IT COULD BE A
;PUSHJ P,RAXDIE TO CATCH FILSER ERRORS.

RAXRCL==CPOPJ1##		;STARTED


;ROUTINE TO START A POSITION OPERATION GOING. CALL WITH UNIBLK(U)
;CONTAINING THE DESIRED BLOCK NUMBER.
;CALL:
;	J/ KDB ADDRESS
;	U/ UDB ADDRESS
;	PUSHJ	P,RAXPOS
;RETURN:
;	CPOPJ IF ERRORS
;	CPOPJ1 WITH POSITION STARTED

RAXPOS:	JSP	T1,RAXDIE	;FILSER SHOULDN'T GET HERE
	SUBTTL	START DATA TRANSFER


;ROUTINES TO START A DATA TRANSFER GOING ON A DRIVE.  ENTRY POINTS:
;
;	RAXRED	- READ DATA, DON'T STOP ON ERROR
;	RAXRDS	- READ DATA, STOP ON ERROR
;	RAXRDF	- READ FORMAT
;	RAXWRT	- WRITE DATA, DON'T STOP ON ERROR
;	RAXWTS	- WRITE DATA, STOP ON ERROR
;	RAXWTF	- WRITE FORMAT
;
;CALL:
;	J/ KDB ADDRESS
;	U/ UDB ADDRESS
;	P1/ CHN ADDRESS
;	T1/ DRB ADDRESS
;	PUSHJ	P,RAXxxx
;RETURN:
;	CPOPJ IF ERRORS WITH ERROR BITS IN T1
;	CPOPJ1 IF TRANSFER STARTED SUCCESSFULLY

;HERE TO START TRANSFER TO READ/WRITE FORMATS

RAXRDF:	SKIPA	T2,[OP.RD]	;GET FUNCTION CODE FOR READ
RAXWTF:	MOVEI	T2,OP.WR	;GET FUNCTION CODE FOR WRITE
	PUSHJ	P,RAXDIE	;I DON'T THINK WE CAN FORMAT THESE, CAN WE?
	JRST	RAXDGO		;JOIN COMMON TRANSFER CODE
;HERE TO START TRANSFER TO READ/WRITE DATA, NOT STOPPING ON ERRORS

RAXRED:	SKIPA	T2,[OP.RD]	;GET FUNCTION CODE FOR READ
RAXWRT:	MOVEI	T2,OP.WR	;GET FUNCTION CODE FOR WRITE
	JRST	RAXDGO		;JOIN COMMON TRANSFER CODE


;HERE TO START TRANSFER TO READ/WRITE DATA, STOPPING ON ERRORS

RAXRDS:	SKIPA	T2,[OP.RD]	;GET FUNCTION CODE FOR READ
RAXWTS:	MOVEI	T2,OP.WR	;GET FUNCTION CODE FOR WRITE

;HERE FROM ALL TRANSFER OPERATIONS TO ACTUALLY DO THE WORK WITH
;T1 CONTAINING THE DRB ADDRESS AND T2 CONTAINING THE FUNCTION

;THROUGHOUT THIS CODE, P1 CONTAINS KDB ADDRESS OFFSET BY OUR CPU NUMBER
;TO MAKE REFERENCES TO THE VARIOUS INDEXED BY CPU TABLES EASIER.

RAXDGO:	SE1ENT			;ENSURE WE RUN IN NZS
	PUSHJ	P,SAVE4##	;SAVE AC'S WE WILL CLOBBER
	PUSHJ	P,SAVR##	;THIS LOOKS LIKE A SEMI-PRESERVED AC NOW
	HRRZ	P1,J		;GET THE KDB ADDRESS
	ADD	P1,.CPCPN##	;OFFSET KDB ADDRESS BY OUR CPU NUMBER
	MOVE	P3,T1		;COPY DRB ADDRESS
	MOVEM	T2,DRBOPC##(P3)	;SAVE THE OPERATION CODE
	MOVE	T1,T2		;COPY THE OPERATION CODE FOR CONECT
	MOVE	T3,P3		;COPY THE DRB ADDRESS FOR POSSIBLE ERROR RETURN
	PUSHJ	P,CONECT	;CONNECT TO THE DRIVE
	  POPJ	P,		;DRIVE IS DOWN, RETURN WITH ERROR FLAGS IN T1
	MOVE	T1,DRBOPC##(P3)	;GET THE OPERATION CODE
	MOVX	T2,BS.HDM	;GET THE TRANSFER MODE
	MOVE	T3,DRBPRG##(P3)	;GET ADDRESS OF THE CHANNEL PROGRAM
	PUSH	P,P3		;SAVE DRB ADDRESS
	PUSHJ	P,MSCMIO##	;MAP THE I/O
	  JRST	[POP	P,P3	;COULDN'T, RESTORE DRB ADDRESS
		 JRST	RAXGE2]	;LET FILIO QUEUE THE REQUEST
	POP	P,P3		;RESTORE DRB ADDRESS
	HRRZ	T1,J		;GET KDB ADDRESS
	ADD	T1,.CPCPN##	;OFFSET BY OUR CPU NUMBER
	EXCH	T1,P1		;PUT IT BACK IN P1, GET BUFFER NAME IN T1
	MOVEM	T1,DRBBHD##(P3)	;STORE BUFFER NAME
	MOVE	T1,P.CRF(P2)	;GET COMMAND REFERENCE NUMBER
	MOVEM	T1,DRBCRF##(P3)	;STORE
	MOVE	T1,DRBBLK##(P3)	;GET LOGICAL BLOCK NUMBER
	LSH	T1,4		;POSITION IT IN 32 BITS
	PUSHJ	P,REVFUL##	;REVERSE IT FOR THE HSC
	MOVEM	T1,P.LBN(P2)	;STORE
	MOVE	T1,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	LSH	T1,4		;POSITION IT IN 32 BITS
	PUSHJ	P,REVFUL##	;REVERSE IT FOR THE HSC
	MOVEM	T1,P.UNIT(P2)	;STORE
	MOVE	P4,RAKCTI(P1)	;GET CONNECT TABLE INDEX
	SKIPG	MSCCID##(P4)	;MAKE SURE WE HAVE A CONNECTION
	PUSHJ	P,RAXDIE	;NO, WE SHOULD HAVE CAUGHT THIS SOONER
	BLCAL.	(SC.DCI##,<MSCCID##(P4)>) ;GET DESTINATION CONNECT ID
	  JRST	RAXGE1		;ERROR, VC MUST HAVE BEEN CLOSED
	MOVEM	T1,P.BUFF+2(P2)	;STORE LAST PART OF BUFFER NAME
	BLCAL.	(SC.SMG##,<MSCCID##(P4),[0],[P%LBN],P2,[MSCPRI],[1],[0]>) ;DO IT
	  SKIPA			;ERROR ON THE SEND
	JRST	CPOPJ1##	;SKIP RETURN

;HERE IF WE HAD AN ERROR ON THE MESSAGE SEND - FIGURE OUT WHY
;AND TAKE SOME APPROPRIATE ACTION

	CAIE	T1,.SCNEC	;NOT ENOUGH CREDIT?
	CAIN	T1,.SCSWS	;OR CONNECTION IN WRONG STATE?
	SKIPA			;YES
	PUSHJ	P,RAXDIE	;NO, DIE FOR NOW
	CAIE	T1,.SCNEC	;NO CREDITS?
	JRST	RAXGE1		;NO, DON'T LIGHT KOPCNA
	MOVSI	T1,KOPCNA	;NO CREDIT IS AVAILABLE
	IORM	T1,KONCNA(J)	; SO TELL FILSER TO SHUT UP FOR A WHILE

;RETURN THE BHD/BSD(S) WE USED TO MAP THIS TRANSFER

RAXGE1:	SKIPE	T1,DRBBHD##(P3)	;GET BUFFER NAME
	PUSHJ	P,PPDRHD##	;RETURN BHD AND BSD(S)
	SETZM	DRBBHD##(P3)	;DON'T DO THIS TWICE
	MOVSI	T1,KOPCNA	;DID WE RUN OUT OF CREDITS?
	TDNN	T1,KONCNA(J)	;...
	SKIPA	T1,[KOPOFL]	;NO, CALL THE ERROR OFFLINE

;HERE WHEN MSCCOM COULDN'T MAP THE I/O LIST - QUEUE THE REQUEST

RAXGE2:	MOVEI	T1,KOPNOC	;TELL FILSER WE DIDN'T HAVE CREDITS
	MOVE	T3,P3		;DRB ADDRESS BACK WHERE FILSER EXPECTS
	POPJ	P,		;RETURN WITH ERROR FLAG
	SUBTTL	INTERRUPT HANDLER


;ROUTINE CALLED WHEN AN INTERRUPT OCCURS.  THE HSC-50 DOESN'T
;INTERRUPT SO IF WE GET HERE SOMETHING TERRIBLE HAS HAPPENED.
;CALL:
;	J/ KDB ADDRESS
;	PUSHJ	P,RAXINT
;RETURN:
;	CPOPJ ALWAYS THROUGH FILINT WITH:
;
;	T1/ COMMUNICATION WORDS
;	T2/ CONI
;	T3/ ENDING STATUS
;	T4/ MASK OF INTERRUPTING UNITS

RAXINT:	JRST	RAXDIE		;FILSER SHOULDN'T GET HERE
	SUBTTL	STOP TRANSFER FOR HUNG RECOVERY


;ROUTINE TO STOP THE CURRENT TRANSFER WHEN THE HUNG TIMER TIMES OUT.
;ONCMOD WILL CALL THIS ROUTINE IF A DRIVE TIMES OUT DURING ONCE,
;OTHERWISE IT COULD BE MADE A CALL TO RAXDIE.
;CALL:
;	J/ KDB ADDRESS
;	PUSHJ	P,RAXSTP
;RETURN:
;	CPOPJ IF COULDN'T STOP DRIVE
;	CPOPJ1 IF SUCCESSFUL

RAXSTP==CPOPJ1##		;TELL ONCMOD IT WAS STOPPED
	SUBTTL	DETERMINE CAPACITY AND STATUS


;ROUTINE TO RETURN CAPACITY AND STATUS OF AN HSC-50 DRIVE TO FILSER.
;CALL:
;	J/ KDB ADDRESS
;	U/ UDB ADDRESS
;	PUSHJ	P,RAXCPY
;RETURN:
;	CPOPJ IF ERROR
;	CPOPJ1 IF DRIVE EXISTS AND IS OK TO USE WITH:
;
;	T1/ BLOCKS PER UNIT
;	T2/ BLOCKS PER UNIT INCLUDING MAINTENANCE CYLINDERS
;	T3/ BLOCKS PER UNIT IN 10/11 COMPATIBILITY MODE
;	T4/ STATUS BITS (KOPUHE,KOPNSU),,UNIT TYPE
;	W/ BLOCKS PER TRACK,,BLOCKS PER CYLINDER

RAXCPY:	PUSHJ	P,SAVE1##	;SAVE P1
	SETZ	P1,		;GET A ZERO
	MOVE	T1,.CPBIT##	;BIT FOR THIS CPU
	TDNE	T1,UDBCAM(U)	;IS UNIT ATTACHED THROUGH THIS CPU?
	AOSA	(P)		;YES, SET FOR SKIP RETURN
	MOVSI	P1,KOPNSU!KOPUHE ;NO, GET SOME ERROR BITS
	MOVE	T1,UNIBPU(U)	;LOAD UP THE VALUES I PREVIOUSLY STORED
	MOVE	T2,UNIBPM(U)	;...
	MOVE	T3,UNIBUC(U)	;...
	LDB	W,UNYBPY##	;GET BLOCKS/CYLINDER
	LDB	T4,UNYBPT##	;GET BLOCKS/TRACK
	HRL	W,T4		;IN W
	LDB	T4,UNYUTP##	;GET UNIT TYPE
	IOR	T4,P1		;INCLUDE ERROR BITS IF UNIT WASN'T ATTACHED
	POPJ	P,		;RETURN
	$INIT

;ROUTINE TO CHECK FOR KONTROLLER UP
;CALL:
;	J/ KDB ADDRESS
;RETURN:
;	CPOPJ1 ALWAYS

RAXUPA:	PJSP	T1,CPOPJ1##	;ALWAYS UP, SET T1 NON-ZERO (WH LOCKOUT)


;ROUTINE TO CHECK WRITE-LOCK STATUS OF A CI DISK DURING ONCE-ONLY.
;CALL:
;	J/ KDB ADDRESS
;	U/ UDB ADDRESS
;RETURN:
;	CPOPJ IF WRITE-ENABLED
;	CPOPJ1 IF WRITE-LOCKED

RAXHWP:	SETZM	ONLDON##	;START AFRESH
	PUSHJ	P,SAVE4##	;SAVE SOME AC'S AGAINST CORRUPTION
	SE1ENT			;ENSURE WE RUN IN NZS
	HRRZ	P4,J		;GET KDB ADDRESS
	ADD	P4,.CPCPN##	;OFFSET BY OUR CPU NUMBER
	MOVE	P4,RAKCTI(P4)	;GET THE CONNECT TABLE INDEX
	PUSHJ	P,MSCGBF##	;GET A BUFFER TO USE
	  POPJ	P,		;NONE AVAILABLE?
	MOVE	T1,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	PUSHJ	P,MSCCUS##	;CHECK UNIT STATUS
	MOVSI	T1,3*ONCTIM##	;WAIT A WHILE
	SKIPN	ONLDON##	;DID IT COMPLETE YET?
	SOJG	T1,.-1		;NO, WAIT A WHILE LONGER
	JUMPLE	T1,CPOPJ##	;IF IT FAILED, JUST ASSUME WRITE-ENABLE
	MOVE	T1,ONLFLG##	;GET THE FLAGS
	TLNE	T1,(UF.WPS!UF.WPH) ;WRITE-PROTECT?
	AOS	(P)		;YES, SET FOR SKIP RETURN
	POPJ	P,		;RETURN

	$HIGH
	SUBTTL	RETURN ECC MASK AND POSITION


;AS THE HSC-50 DOES ALL ERROR RECOVERY THIS ROUTINE IS AN ELABORATE NO-OP.


;ROUTINE TO RETURN THE ECC POSITION AND MASK TO FILIO FOR AN ECC
;CORRECTABLE ERROR IN A BLOCK.
;CALL:
;	J/ KDB ADDRESS
;	PUSHJ	P,RAXECC
;RETURN:
;	CPOPJ IF NO ECC INFORMATION AVAILABLE
;	CPOPJ1 WITH CORRECTION DATA AS FOLLOWS:
;
;	T1/ WORD POSITION OF START OF ERROR RELATIVE TO START OF BLOCK
;	T2-T3/ MASK

RAXECC:	JSP	T1,RAXDIE	;FILSER SHOULDN'T GET HERE
	SUBTTL	DIRECT FILIO IN ERROR RECOVERY


;ROUTINE TO DIRECT FILIO IN ERROR RECOVERY.
;CALL:
;	J/ KDB ADDRESS
;	T1/ RETRY NUMBER
;	P1/ CHN ADDRESS
;	PUSHJ	P,RAXERR
;RETURN:
;	CPOPJ ALWAYS WITH:
;
;	T1/ 0 IF STRAIGHT RETRY
;	    2 IF LAST TIME
;	    3 IF GIVE UP

RAXERR:	MOVEI	T1,3		;GIVE UP, CAN'T DO ANYTHING THE HSC-50 CAN'T
	POPJ	P,		;RETURN
	SUBTTL	MISCELLANEOUS GLOBAL FUNCTIONS


;ROUTINE TO RETURN THE LATENCY TIME.  WE ALWAYS LIE AND SAY WE
;ARE ON CYLINDER (ZERO LATENCY TIME) SO FILSER WILL START I/O.
;CALL:
;	J/ KDB ADDRESS
;	PUSHJ	P,RAXLTM
;RETURN:
;	CPOPJ1 ALWAYS WITH:
;	T1/ LATENCY TIME

RAXLTM:	MOVEI	T1,0		;ZERO LATENCY TIME
	JRST	CPOPJ1##	;SKIP RETURN


;ROUTINE TO RETURN THE DISTANCE TO THE TARGET CYLINDER.  WE ALWAYS
;LIE AND SAY WE ARE ON CYLINDER (ZERO DISTANCE) SO FILSER WILL START
;I/O.
;CALL:
;	J/ KDB ADDRESS
;	PUSHJ	P,RAXCCM
;RETURN:
;	CPOPJ WITH:
;	T1/ DISTANCE FROM CURRENT CYLINDER TO TARGET CYLINDER

RAXCCM:	MOVEI	T1,0		;RETURN A ZERO
	POPJ	P,		;RETURN


;ROUTINES WHICH SHOULD NEVER BE CALLED SINCE THE DISPATCH BITS IN
;COMMOD PROHIBIT THIS.  IF WE DO GET HERE IT IS PROBABLY A SIGN
;SOMEONE HAS GOOFED VERY BADLY, SO DIE WITHOUT FURTHER ADO.

RAXRDC:				;READ 10/11 COMPATIBILITY MODE
RAXWTC:				;WRITE 10/11 COMPATIBILITY MODE
RAXUNL:				;UNLOAD DRIVE
	STOPCD	.,STOP,RAXXIF,	;++ RAXKON ISN'T FANCY
	SUBTTL	CHECK DRIVE/CONTROLLER STATUS


;ROUTINE TO ENSURE THE HSC-50 VIRTUAL CIRCUIT IS IN AN ACCEPTABLE
;STATE FOR THE DATA TRANSFER OPERATION ABOUT TO BE DONE.
;CALL:
;	J/ KDB ADDRESS
;	U/ UDB ADDRESS
;	T1/ FUNCTION CODE
;	T3/ DRB ADDRESS
;	PUSHJ	P,CONECT
;RETURN:
;	CPOPJ IF ERROR WITH:
;	T1/ ERROR BITS
;	CPOPJ1 IF OK WITH:
;	T1/ FUNCTION CODE

CONECT:	MOVE	T2,.CPBIT##	;BIT FOR THIS CPU
	TDNN	T2,UDBCAM(U)	;IS THIS CPU ATTACHED TO THIS UNIT?
	JRST	CONOFL		;NO, CALL THE UNIT OFFLINE
	SKIPGE	KONCNA(J)	;NO CREDIT AVAILABLE?
	JRST	CONCNA		;YES
	CAIE	T1,OP.WR	;IS THIS A WRITE FUNCTION?
	JRST	CONEC1		;NO, DON'T CARE ABOUT WRITE PROTECT
	MOVSI	T2,UNPHWP	;GET HARDWARE WRITE PROTECT BIT
	TDNE	T2,UNIDES(U)	;IS THE UNIT WRITE PROTECTED?
	JRST	CONHWP		;YES
CONEC1:	MOVSI	T2,UNPOFL	;GET OFF-LINE BIT
	TDNE	T2,UNIDES(U)	;IS THE DRIVE OFF-LINE?
	JRST	CONOFL		;YES
	JRST	CPOPJ1##	;THAT WAS HARD

CONHWP:	MOVEI	T1,KOPWLK	;GET THE WRITE LOCK BIT
	POPJ	P,		;RETURN

CONOFL:	MOVEI	T1,KOPOFL	;GET THE OFF-LINE BIT
	POPJ	P,		;RETURN

CONCNA:	MOVEI	T1,KOPNOC	;GET THE NO CREDITS BIT
	POPJ	P,		;RETURN


;ROUTINE TO MAKE SURE THE KONTROLLER HAS A PI ASSIGNMENT.
;YOU GUESSED IT, ANOTHER SUPERFLUOUS GLOBAL.
;CALL:
;	J/ KDB ADDRESS
;	PUSHJ	P,RAXALV
;RETURN:
;	CPOPJ ALWAYS

RAXALV==CPOPJ##		;IT HAS A PI ASSIGNMENT
	SUBTTL	ERROR LOGGING ROUTINES


;ROUTINE TO READ THE "REGISTERS" INTO KONEBK FOR THE HSC-50.
;CALL:
;	J/ KDB ADDRESS
;	PUSHJ	P,RAXREG
;RETURN:
;	CPOPJ ALWAYS

RAXREG==CPOPJ##		;NO REGISTERS TO READ


;ROUTINE TO CREATE QUEUE A SYSTEM ERROR BLOCK FOR FILIO
;SEE MDEELG IN FILIO FOR CALLING SEQUENCE

RAXELG:	PUSH	P,F		;SAVE F
	HRRZS	F		;AVOID XADDR MESS
	XMOVEI	T2,ELGBEG	;POINT TO OUR XFER TABLE
	PUSHJ	P,XFRSEB##	;ALLOCATE AND FILL THE BLOCK
	  JFCL			;NO CORE--PUNT
	PJRST	FPOPJ##		;ALREADY QUEUED--JUST RETURN

ELGBEG:	SEBTBL	(.ERCIE,ELGEND,EX.QUE)
	MOVE	UDBNAM(U)	;(R00) PHYSICAL UNIT NAME
	MOVE	UNIHID(U)	;(R01) PACK (HOME BLOCK) ID
	MOVE	UNILOG(U)	;(R02) LOGICAL UNIT NAME
	MOVE	UNIHBN(U)	;(R03) BLOCK OF LAST (HARD?) ERROR
	MOVE	UNIECT(U)	;(R04) RETRY COUNT
	MOVE	UNISOF(U)	;(R05) 1CONI - ERROR CONI AFTER INITIAL ATTEMPT
	MOVE	UNIERR(U)	;(R06) 2CONI - ERROR CONI AFTER 1ST RECAL.
	MOVE	UNIMCT(U)	;(R07) SOFTWARE DETECTED ERROR COUNTS
	MOVE	UNIPCT(U)	;(R10) SEEK INCOMPLETE ERRORS
	MOVE	UNIHNG(U)	;(R11) HUNG COUNTS
	MOVE	DEVFIL(F)	;(R12) FILE NAME
	HLLZ	DEVEXT(F)	;(R13) FILE EXTENSION
	MOVE	JBTPPN##(J)	;(R14) USER'S PPN
	MOVE	JBTNAM##(J)	;(R15) USER'S PROGRAM NAME
	MOVE	UNICCT(U)	;(R16) NUM. OF BAT SLOTS
	MOVE	T4		;(R17) FILIO SOFT ERROR CODE
ELGEND:!
	SUBTTL	KONTROLLER ONCE PER SECOND CODE


;ROUTINE CALLED ONCE PER SECOND TO DO TIMING, ETC., FOR THE HSC.
;CALL:
;	J/ KDB ADDRESS
;	PUSHJ	P,RAXSEC
;RETURN:
;	CPOPJ ALWAYS

RAXSEC:	SE1ENT			;ENSURE WE RUN IN NZS
	PUSHJ	P,SAVE4##	;SAVE AC'S WE WILL CLOBBER
	PUSHJ	P,SAVR##	;THIS LOOKS LIKE A SEMI-PRESERVED AC NOW
	HRRZ	P1,J		;GET KDB ADDRESS
	ADD	P1,.CPCPN##	;OFFSET BY OUR CPU NUMBER
	SKIPE	RAKTIM(P1)	;SKIP IF TIMER IS NOT RUNNING
	SOSLE	RAKTIM(P1)	;DECREMENT AND TEST FOR TIMEOUT
	JRST	RAXSE1		;TIMER STILL RUNNING
	MOVE	T1,RAKTMO(P1)	;GET THE TIMEOUT
	MOVEM	T1,RAKTIM(P1)	;RESET FOR NEXT PASS
	SKIPL	P4,RAKCTI(P1)	;GET CONNECT TABLE INDEX, SKIP IF DISCONNECTED
	SKIPG	MSCCID##(P4)	;STILL CONNECTED?
	POPJ	P,		;NO, QUIT NOW
	MOVX	T1,DT.GCS	;IS A MESSAGE STILL OUTSTANDING?
	TDNE	T1,MSCFLG(P4)	;...
	JFCL			;YES, WHAT DO WE DO NEXT?
	SETZB	T1,T2		;UNIT & COMMAND REFERENCE NUMBER OF 0 FOR NOW
	PUSHJ	P,MSCGCS##	;SEND A GET COMMAND STATUS PACKET
	MOVX	T1,DT.GCS	;INDICATE WE'VE DONE SO
	IORM	T1,MSCFLG(P4)	;...
	PJRST	CHKRRB##	;SEE IF WE NEED TO READ RANDOM BLOCKS

RAXSE1:	SKIPL	P4,RAKCTI(P1)	;GET CONNECT TABLE INDEX, DISCONNECTED?
	SKIPG	MSCCID##(P4)	;STILL CONNECTED?
	POPJ	P,		;NO, DON'T TICKLE THE DISKS
	PJRST	CHKRRB##	;SEE IF WE NEED TO READ RANDOM BLOCKS



;HERE ON RETURN FROM GET COMMAND STATUS COMMAND

RAXGCS:	MOVX	T1,DT.GCS	;WE'VE GOTTEN AN ANSWER
	ANDCAM	T1,MSCFLG##(P4)	; SO CLEAR THE FLAG
	SKIPN	T1,P.OTRF(P2)	;GET THE COMMAND REFERENCE NUMBER
	JRST	RAXGC1		;JUST AN HSC POLL
;CHECK FOR OUTSTANDING REQUEST HERE
RAXGC1:	PJRST	MSCRBF##	;RETURN THE PACKET AND RETURN
	SUBTTL	INTERFACE TO MSCCOM - DRIVER DISPATCH TABLE


;DISPATCH TABLE FOR MSCCOM RECALLS AFTER CALLS TO MSCCOM ROUTINES.
;THESE ARE NEGATIVE INDEXES INTO RAXDDT.  SEE .RR??? IN MSCPAR.

;DISPATCH TABLE FOR SCS NOTIFICATION CALLS ROUTED HERE VIA MSCCOM.
;ENTRIES FLAGGED BY "*" ARE CALLED WITH THE CTI IN T2 (AS OPPOSED
;TO THE CID WHICH IS SUPPLIED FROM SCS ON THE CALL TO MSCCOM).
;THE KDB ADDRESS (IF ANY) IS PASSED IN J.

;OTHER NOTES:  WE NEVER GET HERE FOR THE DATAGRAM/MESSAGE RECEIVED
;ENTRIES BUT THEY ARE IN THE TABLE TO MAKE IT CONSISTENT WITH THE
;TABLE IN MSCCOM.

	IFIW	RAXCUS		;.RRCUS - UNIT STATUS RETURNED
	IFIW	RAXXFR		;.RRXFR - TRANSFER COMPLETE
	IFIW	RAXAVA		;.RRAVA - UNSOLICITED UNIT AVAILABLE
	IFIW	RAXGUS		;.RRGUS - UNIT STATUS RETURNED
	IFIW	RAXGCS		;.RRGCS - COMMAND STATUS
	IFIW	RAXAON		;.RRAON - UNIT AVAILABLE ONLINE COMPLETE
	IFIW	RAXOON		;.RROON - ONCE BIND ONLINE COMPLETE
	IFIW	RAXUON		;.RRONL - UNIT ONLINE COMMAND COMPLETE
	IFIW	RAXGNU		;.RRGNU - RETURN FROM GET NEXT UNIT
	IFIW	RAXSCC		;.RRSCC - RETURN FROM SET CONTROLLER CHARACTERISTICS
RAXDDT::IFIW	CPOPJ##		;.SSDGR - DATAGRAM RECEIVED *
	IFIW	CPOPJ##		;.SSMGR - MESSAGE RECEIVED *
	IFIW	RAXPBC		;.SSPBC - PORT BROKE CONNECTION *
	IFIW	CPOPJ##		;.SSCTL - CONNECTION TO LISTEN
	IFIW	RAXCRA		;.SSCRA - CONNECTION RESPONSE AVAILABLE *
	IFIW	CPOPJ##		;.SSMSC - MESSAGE/DATAGRAM SEND COMPLETE
	IFIW	CPOPJ##		;.SSDDG - DATAGRAM DROPPED
	IFIW	CPOPJ##		;.SSLCL - LITTLE CREDIT LEFT
	IFIW	RAXONL		;.SSNCO - NODE COMING ONLINE
	IFIW	CPOPJ##		;.SSOSD - OK TO SEND DATA
	IFIW	CPOPJ##		;.SSRID - REQUEST DISCONNECT
	IFIW	RAXCIA		;.SSCIA - CREDIT IS AVAILABLE *
	IFIW	CPOPJ##		;.SSDMA - DMA OPERATION COMPLETE
IF1,<IFN <.-RAXDDT-1>-.SSAFT,<PRINTX ?Dispatch table RAXDDT is incomplete>>
	SUBTTL	DRIVER DISPATCH - DATA TRANSFER COMPLETE


RAXXFR:	HRRZ	P1,J		;GET KDB ADDRESS
	ADD	P1,.CPCPN##	;OFFSET BY OUR CPU NUMBER
	LOAD	T1,PKYECD,(P2)	;GET THE END CODE
	CAIG	T1,OP%GUS	;IS THIS A "REAL" MESSAGE
	PJRST	MSCRBF##	;NO, RETURN THE PACKET AND EXIT
	PUSHJ	P,MSCGUN##	;GET THE UNIT NUMBER
	PUSHJ	P,GETUDB	;GET THE UDB FOR THAT UNIT
	  STOPCD MSCRBF##,DEBUG,RAXUGA, ;++UDB GONE AWAY
	MOVE	T1,P.CRF(P2)	;GET THE COMMAND REFERENCE NUMBER
	PUSHJ	P,FNDDRB	;FIND THE DRB FOR THIS ONE
	  STOPCD MSCRBF##,EVENT,RAXCRM, ;++COMMAND REFERENCE NUMBER MISSING
	MOVE	P3,T3		;SAVE THE DRB ADDRESS SOMEWHERE SAFE
	LOAD	T1,PKYEST,(P2)	;GET THE END STATUS
	JUMPE	T1,RAXXF2	;GO IF SUCCESSFUL TRANSFER
	CAIE	T1,ST%AVL	;AVAILABLE?
	JRST	RAXXF1		;NO
	MOVE	T1,UDBPDN(U)	;PHYSICAL DRIVE NUMBER
	PUSH	P,T1		;STUFF IT ON THE STACK
	PJRST	RAXAVU		;FAKE LIKE THIS WAS AN AVAILABLE INTERRUPT

RAXXF1:	SETZ	T2,		;GET A ZERO
	CAIN	T1,ST%OFL	;OFFLINE?
	MOVEI	T2,KOPOFL	;YES
	CAIN	T1,ST%WPR	;WRITE PROTECTED?
	MOVEI	T2,KOPWLK	;YES
	SKIPN	T1,T2		;ANYTHING?
	MOVEI	T1,KOPDER	;NO, CALL IT DEVICE ERROR
	IORM	T1,DRBSTS##(P3)	;...
	JRST	RAXXF3		;PROCEED TO CALL FILSER
RAXXF2:	MOVE	T2,P.STS(P2)	;GET THE STATUS WORD
	TXNN	T2,EF.LOG	;ERROR LOG REQUEST?
	JUMPE	T1,RAXXF3	;JUMP IF NO ERRORS
	PUSHJ	P,MSCRSW##	;PUT STATUS WORD BACK IN ORIGINAL ORDER
	MOVEI	T1,CI%LEN	;LENGTH OF ERROR BLOCK
	PUSHJ	P,ALCSEB##	;GRAB A SYSTEM ERROR BLOCK
	  JRST	RAXXF3		;SORRY, WE TRIED
	MOVEI	T2,SEC%CI	;GET THE CODE
	DPB	T2,[POINT 9,.EBTYP(T1),8] ;STORE IN HEADER
	$LDCID	T2,MSCCID##(P4)	;GET CONNECT BLOCK ADDRESS
	MOVE	T2,.CBPBK(T2)	;GET THE PATH BLOCK ADDRESS
	LOAD	T2,PBDPN,(T2)	;GET THE DESTINATION PORT (NODE) NUMBER
	MOVEM	T2,.EBHDR+CI%NOD(T1) ;STORE
	MOVE	T2,UNIHID(U)	;GET VOLUME ID
	MOVEM	T2,.EBHDR+CI%VID(T1) ;STUFF IT
	MOVE	T2,UNIBRC(U)	;COMPUTE TOTAL BLOCKS READ
	ADD	T2,UNIDRC(U)	;...
	ADD	T2,UNIMRC(U)	;...
	MOVEM	T2,.EBHDR+CI%RED(T1) ;STUFF IT
	MOVE	T2,UNIBWC(U)	;COMPUTE TOTAL BLOCKS WRITTEN
	ADD	T2,UNIDWC(U)	;...
	ADD	T2,UNIMWC(U)	;...
	MOVEM	T2,.EBHDR+CI%WRT(T1) ;STUFF IT
;CI%PS1, CI%PS2
	MOVEI	T2,P.TRBC-P.CRF+1 ;NUMBER OF WORDS TO MOVE
	XMOVEI	T3,P.CRF(P2)	;SOURCE
	MOVEI	T4,.EBHDR+CI%PAK(T1) ;DESTINATION
	EXTEND	T2,[XBLT]	;MOVE THE DATA
	PUSHJ	P,QUESEB##	;QUEUE THE BLOCK

RAXXF3:	PUSHJ	P,MSCRBF##	;RETURN THE BUFFER
	MOVE	T1,DRBOPC##(P3)	;GET SAVED OPERATION CODE
	CAIN	T1,OP.RD	;READ?
	SKIPA	T1,[OPRED]	;YES, GET CODE FOR FILSER
	MOVEI	T1,OPWRT	;NO, GET WRITE CODE
	HRL	T1,UDBPDN(U)	;PHYSICAL DRIVE NUMBER IN LH (T1)
	MOVEI	T2,KOPDER	;BIT TO TEST
	TDNE	T2,DRBSTS##(P3)	;WAS THERE A HARD DATA ERROR?
	TRO	T1,IODERR	;TELL FILINT
	ANDCAM	T2,DRBSTS##(P3)	;MAKE SURE BIT IS OFF
	SETZ	T2,		;CLEAR THE CONI WORD (NO USEFUL DATA)
	MOVE	T3,P3		;COPY DRB ADDRESS
	SETZ	T4,		;NO ONE HAS POSITIONED
	S0JRST	FLHTID##	;CALL FILSER AND RETURN
	SUBTTL	DRIVER DISPATCH - PORT BROKE CONNECTION/CREDIT AVAILABLE


RAXPBC:	SETOM	MSCCID##(P4)	;MAKE THE CONNECT ID LOOK INVALID
	SETZM	MSCFLG##(P4)	;ALLOW RE-USE OF THIS CTI SLOT
	JUMPE	J,CPOPJ##	;RETURN IF NO KDB SET UP YET
	HRRZ	T1,J		;GET KDB ADDRESS
	ADD	T1,.CPCPN##	;OFFSET BY OUR CPU NUMBER
	SETOM	RAKCTI(T1)	;MAKE SURE OUR CTI LOOKS INVALID
	SETZM	RAKTIM(T1)	;TURN OFF POLLING TIMER ALSO
	MOVE	P1,.CPBIT##	;BIT FOR THIS CPU
	ANDCAM	P1,KDBCAM(J)	;THIS CPU CAN NO LONGER SEE THIS KONTROLLER
	MOVE	P2,KDBIUN(J)	;GET AOBJN POINTER TO UNITS ON THIS KDB

RAXPB1:	SKIPE	U,(P2)		;GET UDB ADDRESS
	TDNN	P1,UDBCAM(U)	;IS THIS CPU ATTACHED TO THIS UNIT?
	JRST	RAXPB2		;NO UNIT OR THIS CPU NOT ATTACHED
	ANDCAM	P1,UDBCAM(U)	;CLEAR THE BIT
	MOVEI	T1,CPUMSK	;MASK FOR ALL CPUS
	TDNN	T1,UDBCAM(U)	;CAN ANY OTHER CPU SEE THIS UNIT?
	S0PSHJ	FILDN##		;NO, TELL FILSER THIS UNIT IS DOWN, AND
				; REQUEUE ALL ACTIVE DRBS FOR THE UNIT
RAXPB2:	AOBJN	P2,RAXPB1	;LOOP FOR OTHER UNITS
	POPJ	P,		;RETURN


RAXCIA:	MOVSI	T1,KOPCNA	;TELL FILSER IT'S OK TO DO MORE I/O
	ANDCAM	T1,KONCNA(J)	;...
	POPJ	P,		;RETURN
	SUBTTL	DRIVER DISPATCH - CONNECTION RESPONSE AVAILABLE


;HERE WHEN A CONNECTION RESPONSE IS AVAILABLE.  IF IT WAS
;ACCEPTED, BUILD A CHN AND KDB AND START LOOKING AT UNITS.
;CALL:
;	T3/ -1 IF ACCEPTED, 0 IF REJECTED
;	T4/ REJECTED REASON IF REJECTED
;	P4/ CTI
;	PUSHJ	P,RAXCRA
;RETURN:
;	CPOPJ ALWAYS

RAXCRA:	MOVX	T1,DT.IRC	;INDICATE CONNECT DONE
	ANDCAM	T1,MSCFLG##(P4)	;...
	JUMPN	T3,MSCSCC##	;IF CONNECTION ACCEPTED GO SET UP CONTROLLER
	SETZM	MSCFLG##(P4)	;CLEAR FLAGS (ALLOW CTI REUSE)
	POPJ	P,		;RETURN

;HERE ON RETURN FROM SET CONTROLLER CHARACTERISTICS COMMAND

RAXSCC:	MOVE	T1,P.CNTF(P2)	;GET THE CONTROLLER FLAGS FIELD
	PUSHJ	P,REVFUL##	;REVERSE THE BYTES FROM THE HSC
	TXNN	T1,CF.576	;IS IT A 576-BYTE CONTROLLER?
	STOPCD	MSCRBF##,EVENT,RAXKN5,DIEKN5 ;++KONTROLLER NOT IN 576-BYTE SECTOR MODE
	$LDCID	T1,MSCCID##(P4)	;GET THE CB ADDRESS
	MOVE	T1,.CBPBK(T1)	;GET THE PATH BLOCK ADDRESS
	LOAD	P3,PBSBI,(T1)	;GET THE SYSTEM BLOCK INDEX
	LOAD	T1,PBDPN,(T1)	;GET THE DESTINATION PORT (NODE) NUMBER
	SKIPE	J,MSCDKA##-1(P3) ;IS THERE ALREADY A DISK KDB ADDRESS?
	JRST	RAXSC1		;YES
	PUSH	P,T1		;SAVE PORT NUMBER
	XMOVEI	T1,RAXDSP	;POINT TO OUR DISPATCH TABLE
	MOVEM	T1,.CPDRV##	;SETUP
	MOVE	T1,.CPCPN##	;GET OUR CPU NUMBER
	PUSHJ	P,AUTADP##	;GENERATE A BYTE POINTER
	POP	P,T3		;GET PORT NUMBER BACK
	MOVEI	T4,1(T3)	;PLUS ONE TO AVOID OVERFLOW
	DPB	T4,T1		;STORE AS LIMIT FOR THIS CPU
	AOS	T2		;ADVANCE TO ALLOCATED WORD
	DPB	T3,T1		;SET ALLOCATED COUNT SO FAR
	MOVE	T1,.CPPCB##	;GET PCB ADDRESS
	MOVE	T1,KDBDVC(T1)	;GET KLIPA'S DEVICE CODE
	TDO	T1,[7B2+400000]	;BOGUS CPU NUMBER, CROCK UP DEVICE CODE
	MOVEM	T1,.CPDVC##	;STORE DEVICE INFORMATION FOR AUTCHN
	MOVSI	T1,CP.KLP	;GET CHANNEL TYPE BITS
	TRO	T1,400000	;*** SPECIAL CROCKERY TO IGNORE DUPLICATE CHNS
	PUSHJ	P,AUTCHN##	;BUILD A CHANNEL DATA BLOCK
	  PJRST	MSCRBF##	;NO CORE, RETURN MESSAGE AND RETURN
	MOVE	P1,.CPCHA##	;GET CHANNEL DATA BLOCK ADDRESS
	HRRZ	T1,.CPDVC##	;GET KLIPA'S DEVICE CODE/4
	XMOVEI	T2,RAXDSP	;DISPATCH
	MOVE	T3,.CPCHA##	;GET CHANNEL DATA BLOCK ADDRESS
	PUSHJ	P,AUTSET##	;SET UP THE REST OF AUTCON'S VARIABLES
	MOVNI	T1,1		;NO MASSBUS UNIT NUMBER
	MOVEI	T2,TYPRA	;KONTROLLER TYPE CODE
	PUSHJ	P,DSKKON##	;BUILD A KONTROLLER DATA BLOCK
	  PJRST	MSCRBF##	;NO CORE, RETURN THE MESSAGE AND RETURN
	SETZM	KDBDVC(J)	;LET NO ONE FIND US (DIAG. UUO, ETC.)
	MOVEM	J,MSCDKA##-1(P3) ;STORE KDB ADDRESS FOR FUTURE REFERENCE
	SETOM	RAKCTI(J)	;MAKE ALL CONNECT ID'S LOOK INVALID
	MOVEI	T1,5		;NUMBER OF CPU'S MAXIMUM -1
	XMOVEI	T2,RAKCTI(J)	;SOURCE
	XMOVEI	T3,RAKCTI+1(J)	;DESTINATION
	EXTEND	T1,[XBLT]	;GET THEM ALL
	DMOVE	T1,P.CNTI(P2)	;GET THE CONTROLLER ID FIELD
	DMOVEM	T1,RAKCID(J)	;STORE IN KDB
	JRST	RAXSC2		;CONTINUE

RAXSC1:	DMOVE	T1,P.CNTI(P2)	;GET THE CONTROLLER ID FIELD
	CAMN	T1,RAKCID(J)	;SHOULD MATCH EXISTING VALUES
	CAME	T2,RAKCID+1(J)	;...
	STOPCD	MSCRBF##,DEBUG,RAXKIM, ;++KONTROLLER ID MISMATCH
RAXSC2:	MOVEM	J,MSCKDB##(P4)	;STORE KDB ADDRESS IN TABLE INDEXED BY CTI
	HRRZ	P1,J		;GET KDB ADDRESS
	ADD	P1,.CPCPN##	;OFFSET BY OUR CPU NUMBER
	MOVEM	P4,RAKCTI(P1)	;SAVE THE CONNECT TABLE INDEX
	MOVE	T1,P.CTMO(P2)	;GET KONTROLLLER TIMEOUT
	PUSHJ	P,REVFUL##	;MAKE IT MEANINGFUL
	LDB	T1,[POINT 8,T1,31] ;GET JUST THE LOW ORDER BYTE
	SUBI	T1,2		;MAKE SURE WE GET THERE BEFORE THE HSC DROPS US
	MOVEM	T1,RAKTMO(P1)	;...
	MOVEM	T1,RAKTIM(P1)	;SET INITIAL TIMER VALUE
	MOVE	T1,.CPBIT##	;GET THE BIT FOR THIS CPU
	IORM	T1,KDBCAM(J)	;I CAN SEE THIS KONTROLLER
	MOVX	T1,DT.NXU	;SHOW THIS IS THE FIRST TIME
	IORM	T1,MSCFLG##(P4)	; SO WE CAN HANDLE UNIT ZERO
	SETZ	T1,		;GET A ZERO FOR UNIT NUMBER
	JRST	MSCGNU##	;ASK FOR STATUS OF FIRST UNIT

;LOOP OVER ALL UNITS ON THIS HSC AND BUILD UDBS IF REQUIRED

RAXGUL:	POP	P,T1		;RESTORE CURRENT UNIT NUMBER
	AOJA	T1,MSCGNU##	;INCREMENT UNIT NUMBER AND CHECK NEXT UNIT

;HERE ON RETURN FROM GET NEXT UNIT COMMAND

RAXGNU:	PUSHJ	P,MSCGUN##	;GET THE UNIT NUMBER FROM THE PACKET
	JUMPN	T1,RAXGU1	;GO IF UNIT NUMBER NON-ZERO
	LOAD	T2,PKYEST,(P2)	;GET THE UNIT STATUS
	CAIN	T3,ST%OFL	;CHECK FOR OFFLINE
	JRST	MSCRBF##	;WE'RE NOT INTERESTED IF NO DRIVES
	MOVX	T2,DT.NXU	;IS THIS THE FIRST TIME WE SAW A ZERO?
	TDNN	T2,MSCFLG##(P4)	;...
	JRST	MSCRBF##	;NO, THIS ZERO MEANT NO MORE UNITS
RAXGU1:	MOVX	T2,DT.NXU	;SHOW WE'VE HANDLED UNIT ZERO IF IT EXISTS
	ANDCAM	T2,MSCFLG##(P4)	;...
	PUSH	P,T1		;SAVE CURRENT UNIT NUMBER
	PUSHJ	P,RAXPUS	;PROCESS THE UNIT STATUS
	  JRST	RAXGUL		;UNIT IS UNACCEPTABLE FOR SOME REASON
	SKIPN	BNDFLG##	;HAVE WE CALLED ONCBND YET?
	JRST	RAXGUL		;NO, JUST PROCEED TO NEXT UNIT
	HRRZ	T1,UNIALT(U)	;IS THERE AN ALTERNATE PORT?
	JUMPE	T1,RAXGU2	;NO, BIND THE UNIT TO THIS PORT
	MOVEI	T2,CPUMSK	;MASK FOR ALL CPUS
	TDNE	T2,UDBCAM(T1)	;IS THE PORT ATTACHED ELSEWHERE?
	JRST	RAXGUL		;YES, DON'T BIND THIS UNIT
RAXGU2:	POP	P,T1		;RESTORE CURRENT UNIT NUMBER
	MOVEI	R,.RRONL	;RECALL CODE
	PJRST	MSCUON##	;DO AN ONLINE FOR THIS UNIT
	SUBTTL	DRIVER DISPATCH - RETURN FROM SET ONLINE COMMANDS


;HERE ON RETURN FROM SET ONLINE COMMAND

RAXAON:	MOVEI	P1,1		;SET P1 TO +1
	JRST	RAXUO1		;JOIN COMMON CODE

RAXOON:	TDZA	P1,P1		;CLEAR P1 AND SKIP
RAXUON:	SETO	P1,		;SET P1 TO -1
RAXUO1:	PUSHJ	P,MSCGUN##	;GET THE UNIT NUMBER
	PUSH	P,T1		;SAVE CURRENT UNIT NUMBER
	PUSHJ	P,GETUDB	;GET THE UDB ADDRESS
	  STOPCD RAXUO4,DEBUG,RAXUWA, ;++UDB WENT AWAY?!
	LOAD	T1,PKYEST,(P2)	;GET THE END CODE
	JUMPE	T1,RAXUO2	;JUMP IF IT SUCCEEDED
IFN FTMP,<
	CAIN	T1,ST%CMD	;INVALID COMMAND?
	JRST	RAXAV1		;YES, ONE CPU BEAT US TO IT, ASK AGAIN
>; END IFN FTMP
	CAIE	T1,ST%OFL	;IT COULD FAIL WITH OFFLINE IF BOTH HSC'S
				; TELL US ABOUT THE SAME UNIT SIMULTANEOUSLY
	CAIN	T1,ST%MFE	;OR MEDIA FORMAT ERROR?
	JRST	RAXUO4		;CAN THIS RESPONSE AND IGNORE THE UNIT
	STOPCD	RAXUO4,DEBUG,RAXUOF,DIEUNI##, ;++UNIT ONLINE FAILED

RAXUO2:	MOVE	T1,P.UNFL(P2)	;GET UNIT FLAGS
	PUSHJ	P,REVFUL##	;REVERSE THE BYTES
	SKIPE	DINITF##	;IN DISK ONCE-ONLY CODE?
	MOVEM	T1,ONLFLG##	;YES, SAVE FLAGS FOR SUBSEQUENT ONLINE COMMANDS
	TXNN	T1,UF.576	;IS IT IN 576-BYTE SECTOR MODE?
	STOPCD	RAXUO3,EVENT,RAXUN5,DIEUNI## ;++UNIT NOT IN 576-BYTE SECTOR MODE
	MOVSI	T2,UNPHWP	;GET HARDWARE WRITE PROTECT FLAG
	ANDCAM	T2,UNIDES(U)	;CLEAR IT FIRST
	TXNE	T1,UF.WPH!UF.WPS ;UNIT WRITE LOCKED?
	IORM	T2,UNIDES(U)	;YES, SET THE FLAG
	MOVSI	T1,UNPOFL!UNPWMD ;CLEAR OFFLINE BITS
	ANDCAM	T1,UNIDES(U)	;...
	MOVE	T1,.CPBIT##	;BIT FOR THIS CPU
	IORM	T1,UDBCAM(U)	;SHOW THIS PORT IS ATTACHED VIA THIS CPU
	MOVE	T1,P.UNSZ(P2)	;GET UNIT SIZE
	PUSHJ	P,REVFUL##	;MAKE IT SENSIBLE
	LSH	T1,-4		;RIGHT-JUSTIFY IT
	MOVEM	T1,UNIBPU(U)	;STORE THE VALUES IN THE UDB
	MOVEM	T1,UNIBPM(U)	;...
	MOVEM	T1,UNIBUC(U)	;...
	JUMPE	P1,RAXUO4	;ON TO NEXT UNIT IF ONCE ONLINE CALL
	PUSHJ	P,GIVINT	;GIVE FILSER A FREE INTERRUPT FOR THIS UNIT IF NECESSARY
	JRST	RAXUO4		;PROCEED
;HERE TO SET UNIT OFFLINE IF WE DON'T LIKE IT

RAXUO3:	MOVSI	T1,U2PIGN	;IGNORE THE AVAILABLE MESSAGE
	IORM	T1,UNIDS2(U)	; WHICH WILL HAPPEN AFTER THE OFFLINE
	HRRZ	T2,UNIALT(U)	;ALTERNATE PORT?
	SKIPE	T2		;IF SO,
	IORM	T1,UNIDS2(T2)	; IGNORE IT HERE AS WELL
	MOVE	T1,(P)		;GET THE CURRENT UNIT NUMBER
	PUSHJ	P,MSCUOF##	;SET IT OFFLINE (NO RECALL)
	PUSHJ	P,MSCGBF##	;GET A BUFFER BACK TO REPLACE THE ONE WE USED
	  JRST	TPOPJ##		;CAN'T, GIVE UP
RAXUO4:	JUMPL	P1,RAXGUL	;ON TO NEXT UNIT IF NOT ONCE BIND COMPLETE
	SKIPG	P1		;IF ONCE ONLINE COMPLETE,
	SETOM	ONLDON##	; SHOW THE ONLINE COMPLETED
	ADJSP	P,-1		;CLEAN UP THE STACK
	PJRST	MSCRBF##	;RETURN THE BUFFER AND RETURN
	SUBTTL	DRIVER DISPATCH - UNSOLICITED UNIT AVAILABLE INTERRUPT


;HERE ON AN UNSOLICITED UNIT AVAILABLE INTERRUPT

RAXAVA:	PUSHJ	P,MSCGUN##	;GET THE UNIT NUMBER
	PUSH	P,T1		;SAVE THE UNIT NUMBER
	PUSHJ	P,GETUDB	;GET THE ASSOCIATED UDB
	  JRST	RAXAV1		;NONE, MUST BE FIRST TIME WE SAW THIS UNIT(?)
	MOVSI	T1,U2PIGN	;SHOULD THIS UNIT AVAILABLE MSG BE IGNORED?
	TDNN	T1,UNIDS2(U)	;...
	JRST	RAXAVU		;NO
	ANDCAM	T1,UNIDS2(U)	;YES, BUT ONLY ONCE
	JRST	TPOPJ##		;CLEAN STACK AND IGNORE THE UNIT
RAXAVU:	MOVEI	T1,CPUMSK	;CLEAR PORT ATTACHED BITS
	ANDCAM	T1,UDBCAM(U)	; FOR ALL CPUS
	S0PSHJ	FILDN##		;TELL FILSER THIS UNIT IS DOWN
	HRRZ	U,UNIALT(U)	;GET UDB FOR ALTERNATE UNIT
	JUMPE	U,RAXAV1	;JUMP IF NO ALTERNATE
	MOVEI	T1,CPUMSK	;CLEAR PORT ATTACHED BITS
	ANDCAM	T1,UDBCAM(U)	; FOR ALL CPUS
	PUSH	P,J		;SAVE J
	MOVE	J,UDBKDB(U)	;LOAD WITH CORRECT KDB
	S0PSHJ	FILDN##		;TELL FILSER THIS UNIT IS DOWN
	POP	P,J		;RESTORE J
RAXAV1:	POP	P,T1		;RESTORE THE UNIT NUMBER
	PJRST	MSCGUS##	;ASK FOR UNIT STATUS

;HERE ON RETURN FROM GET UNIT STATUS COMMAND

RAXGUS:	PUSHJ	P,MSCGUN##	;GET THE UNIT NUMBER
	PUSH	P,T1		;SAVE THE UNIT NUMBER
	PUSHJ	P,RAXPUS	;PROCESS THE UNIT STATUS
	  JRST	RAXGS2		;NOT ACCEPTABLE, DON'T DO AN ONLINE
	SKIPN	BNDFLG##	;HAVE WE CALLED RAXBND YET?
	JRST	RAXGS2		;NO (STRANGE), DON'T BIND THE UNIT YET
	HRRZ	T1,UNIALT(U)	;GET ALTERNATE UDB ADDRESS
	JUMPE	T1,RAXGS1	;JUMP IF NO ALTERNATE
	MOVEI	T2,CPUMSK	;MASK FOR ALL CPUS
	ANDCAM	T2,UDBCAM(T1)	;OBVIOUSLY NO LONGER ATTACHED HERE
RAXGS1:	POP	P,T1		;RESTORE CURRENT UNIT NUMBER
	MOVEI	R,.RRAON	;RECALL CODE
	PJRST	MSCUON##	;DO AN ONLINE FOR THIS UNIT

RAXGS2:	ADJSP	P,-1		;CLEAN UP THE STACK
	PJRST	MSCRBF##	;RETURN THE BUFFER AND RETURN
	SUBTTL	UNIT STATUS PROCESSING


;ROUTINE CALLED AFTER A CHECK UNIT STATUS (GET UNIT STATUS FROM ONCMOD).
;CALL:
;	P2/ PACKET ADDRESS
;	PUSHJ	P,RAXCUS
;RETURN:
;	CPOPJ ALWAYS

RAXCUS:	SETZM	ONLFLG##	;CLEAR THIS IN CASE ERROR
	PUSHJ	P,MSCGUN##	;GET THE UNIT NUMBER
	PUSHJ	P,GETUDB	;GET THE UDB ADDRESS
	  JRST	RAXCU1		;RATHER ODD
	MOVE	T1,P.UNFL(P2)	;GET UNIT FLAGS
	PUSHJ	P,REVFUL##	;REVERSE BYTES
	MOVEM	T1,ONLFLG##	;SAVE FOR ONCMOD
RAXCU1:	SETOM	ONLDON##	;SHOW THE COMMAND COMPLETED
	PJRST	MSCRBF##	;RETURN PACKET AND RETURN
	SUBTTL	PROCESS UNIT STATUS


;ROUTINE CALLED AFTER A GET NEXT UNIT OR GET UNIT STATUS COMMAND.
;CREATE A UDB IF REQUIRED AND FILL IN THE UDB DATA.
;CALL:
;	T1/ UNIT NUMBER (ALA HSC)
;	P2/ PACKET ADDRESS
;	J/ KDB ADDRESS
;	PUSHJ	P,RAXPUS
;RETURN:
;	CPOPJ IF UNIT IS NOT USABLE (OFFLINE/NO PACK MOUNTED)
;	CPOPJ1 IF UNIT MAY BE USED WITH:
;	T1/ UNIT STATUS,,REASON FOR OFFLINE
;P1 AND P3 ARE USABLE BY THIS ROUTINE.

RAXPUS:	PUSH	P,T1		;SAVE THE UNIT NUMBER FOR LATER REFERENCE
	PUSHJ	P,GETUDB	;DOES THIS UNIT ALREADY EXIST?
	  JRST	RAXPU3		;NO
	ADJSP	P,-1		;CLEAN OFF THE STACK
	MOVE	T1,.CPBIT##	;BIT FOR THIS CPU
	ANDCAM	T1,UDBCAM(U)	;WE NO LONGER HAVE IT ATTACHED

;CHECK FOR CONSISTANCY OF SERIAL NUMBERS, ETC.

	LOAD	T1,PKYEST,(P2)	;GET STATE OF UNIT
	MOVS	P1,T1		;SAVE FOR RETURN TO CALLER
	CAIE	T1,ST%OFL	;OFFLINE?
	JRST	RAXPU1		;NO
	LOAD	T1,PKYQSB,(P2)	;YES, GET REASON FOR OFFLINE
	HRR	P1,T1		;SAVE FOR RETURN TO CALLER
	CAIE	T1,SB%NVM	;NO VOLUME MOUNTED?
	POPJ	P,		;UNIT IS NO GOOD, FORGET ABOUT IT
	JRST	RAXPU2		;GO CHECK CONSISTANCY

RAXPU1:	CAIE	T1,ST%AVL	;UNIT ISN'T OFFLINE, IS IT AVAILABLE?
	JUMPN	T1,CPOPJ##	;NOT AVAILABLE, IF NOT ONLINE THEN NOT USABLE
RAXPU2:	MOVE	T1,P.UNTI(P2)	;GET THE UNIT ID
	PUSHJ	P,REVFUL##	;MAKE IT SOMEWHAT REASONABLE
	LSH	T1,-4		;RIGHT-JUSTIFY IT
	CAME	T1,UDBDSN(U)	;MATCH?
	POPJ	P,		;NO, UNIT IS NOT USABLE
	MOVE	T1,P.UNTI+1(P2)	;GET THE UNIT ID SECOND WORD
	PUSHJ	P,REVFUL##	;MAKE IT SOMEWHAT REASONABLE
	LSH	T1,-4		;RIGHT-JUSTIFY IT
	CAME	T1,UDBDSN+1(U)	;MATCH?
	POPJ	P,		;NO, UNIT IS NOT USABLE
	JRST	RAXPU6		;SKIP RETURN
;HERE IF THIS IS A BRAND NEW UNIT

RAXPU3:	SKIPGE	P3,T1		;WAS THERE A FREE SLOT FOR THIS UNIT?
	JRST	TPOPJ##		;NO, FORGET ABOUT THIS UNIT
	MOVE	T1,(P)		;GET PHYSICAL UNIT NUMBER
	IDIVI	T1,^D256	;COMPUTE OFFSET INTO IGNORE MASK
	ADDI	T1,RAXIUM(J)	;INDEX INTO IGNORE MASK TABLE
	MOVE	T2,BITTBL##(T2)	;TRANSLATE OVERFLOW INTO BIT REPRESENTATION
	TDNE	T2,(T1)		;WANT TO IGNORE THIS DRIVE?
	JRST	TPOPJ##		;YES
	LOAD	T1,PKYEST,(P2)	;GET STATE OF UNIT
	MOVS	P1,T1		;SAVE FOR RETURN TO CALLER
	CAIE	T1,ST%OFL	;OFFLINE?
	JRST	RAXPU4		;NO
	LOAD	T1,PKYQSB,(P2)	;YES, GET REASON FOR OFFLINE
	HRR	P1,T1		;SAVE FOR RETURN TO CALLER
	CAIE	T1,SB%NVM	;NO VOLUME MOUNTED?
	JRST	TPOPJ##		;UNIT IS NO GOOD, FORGET ABOUT IT
	JRST	RAXPU5		;SEE IF WE KNOW ABOUT THIS TYPE OF UNIT

RAXPU4:	CAIE	T1,ST%AVL	;UNIT ISN'T OFFLINE, IS IT AVAILABLE?
	JUMPN	T1,TPOPJ##	;NOT AVAILABLE, IF NOT ONLINE THEN NOT USABLE
RAXPU5:	MOVE	T1,.CPPCB##	;GET PCB ADDRESS
	MOVE	T1,KDBDVC(T1)	;GET KLIPA'S DEVICE CODE/4
	XMOVEI	T2,RAXDSP	;DISPATCH
	MOVE	T3,KDBCHN(J)	;CHANNEL DATA BLOCK
	PUSHJ	P,AUTSET##	;SET UP CPU VARIABLES
	MOVE	T1,P.MEDI(P2)	;GET THE MEDIA TYPE WORD
	PUSHJ	P,REVFUL##	;REVERSE IT SO IT MAKES SENSE
	PUSHJ	P,UNTYPE	;DETERMINE IF WE KNOW ABOUT THIS TYPE OF UNIT
	  JRST	TPOPJ##		;NO, FORGET ABOUT THIS UNIT
	MOVE	T1,P.UNFL(P2)	;GET UNIT TYPE FLAGS
	PUSHJ	P,REVFUL##	;MAKE UNDERSTANDABLE
	TXNN	T1,UF.RMV	;REMOVABLE MEDIA?
	TLO	T2,(1B0)	;NO, SO LIGHT THIS BIT
	POP	P,T1		;RESTORE PHYSICAL UNIT NUMBER
	MOVSS	T1		;PUT IN CORRECT HALF
	HRR	T1,P3		;GET UDB TALE OFFSET
	PUSHJ	P,DSKDRV##	;BUILD AND LINK THE UDB
	  POPJ	P,		;NO CORE
	MOVE	T1,P.UNTI(P2)	;GET THE UNIT ID
	PUSHJ	P,REVFUL##	;MAKE IT SOMEWHAT REASONABLE
	LSH	T1,-4		;RIGHT-JUSTIFY IT
	MOVEM	T1,UDBDSN(U)	;SAVE IN UDB
	MOVE	T1,P.UNTI+1(P2)	;GET THE UNIT ID SECOND WORD
	PUSHJ	P,REVFUL##	;MAKE IT SOMEWHAT REASONABLE
	LSH	T1,-4		;RIGHT-JUSTIFY IT
	MOVEM	T1,UDBDSN+1(U)	;SAVE IN UDB
	MOVE	T1,P.TRCK(P2)	;GET TRACK/GROUP SIZE WORD
	PUSHJ	P,REVFUL##	;MAKE IT SENSIBLE
	LDB	T2,[POINT 16,T1,15] ;GET THE GROUP SIZE IN TRACKS
	LDB	T1,[POINT 16,T1,31] ;GET THE TRACK SIZE IN SECTORS
	IMUL	T2,T1		;CONVERT THE GROUP SIZE TO SECTORS AND SAVE IN T2
	DPB	T1,UNYBPT##	;STORE BLOCKS/TRACK (= BLOCKS/SECTOR) IN UDB
	MOVE	T1,P.CYL(P2)	;GET CYLINDER SIZE WORD
	PUSHJ	P,REVFUL##	;MAKE IT SENSIBLE
	LSH	T1,-4		;RIGHT-JUSTIFY IT
	ANDI	T1,177777	;KEEP JUST 16 BITS WORTH
	IMUL	T1,T2		;CYLINDER SIZE IN GROUPS TIMES GROUP SIZE IN SECTORS
				; GIVES CYLINDER SIZE IN SECTORS (BLOCKS)
	DPB	T1,UNYBPY##	;STORE IN UDB
	S0PSHJ	MATUN##		;CHECK FOR SERIAL NUMBER MATCH, SET UP UNIALT
	  JFCL			;SHOULD NEVER SKIP RETURN
	MOVE	T1,[RAXRBT,,RAXRBT] ;GET INITIAL RANDOM BLOCK READ TIMER
	ADDI	T1,(P3)		;OFFSET BY SLOT TO MINIMIZE I/O ACTIVITY
	MOVEM	T1,UNIRBT(U)	;SET INITIAL,,RUNNING TIMER
RAXPU6:	MOVE	T1,P1		;RETURN STATUS IN T1 AS ADVERTISED
	JRST	CPOPJ1##	;SKIP RETURN
	SUBTTL	MISCELLANEOUS ROUTINES


;ROUTINE TO RETURN THE DRB ADDRESS FOR A COMMAND REFERENCE NUMBER.
;CALL:
;	T1/ COMMAND REFERENCE NUMBER
;	J/ KDB ADDRESS
;	PUSHJ	P,FNDDRB
;RETURN:
;	CPOPJ IF NO MATCHING DRB
;	CPOPJ1 IF MATCHING DRB WITH:
;	T3/ DRB ADDRESS

FNDDRB:	MOVEI	T3,ACTDRB##-DRBLNK## ;PRESET PREDECESSOR
FNDDR1:	HRRZ	T3,DRBLNK##(T3)	;GET LINK TO NEXT DRB
	CAIN	T3,ACTDRB##	;BACK TO BEGINNING?
	POPJ	P,		;YES, NOT FOUND
	CAME	T1,DRBCRF##(T3)	;COMMAND REFERENCE NUMBER MATCH?
	JRST	FNDDR1		;NO, KEEP LOOKING
	JRST	CPOPJ1##	;YES, SKIP RETURN


;ROUTINE CALLED ON KN5 STOPCODE FROM DIE TO PRINT INFORMATION.
;CALL:
;	PUSHJ	P,DIEKN5
;RETURN:
;	CPOPJ ALWAYS

DIEKN5:	PUSHJ	P,INLMES##	;START THE MESSAGE
	ASCIZ	/CI node /
	$LDCID	T1,MSCCID##(P4)	;GET THE CB ADDRESS
	MOVE	T1,.CBPBK(T1)	;GET THE PATH BLOCK ADDRESS
	LOAD	T1,PBDPN,(T1)	;GET THE DESTINATION NODE
	PUSHJ	P,RADX10##	;PRINT CI NODE NUMBER
	PJSP	T1,CONMES##	;MORE STUFF AND RETURN
	ASCIZ	/ set to 512-byte sector mode - controller ignored/
;ROUTINE TO RETURN THE UDB ADDRESS FOR A PARTICULAR UNIT.
;CALL:
;	T1/ ONE-BASED UNIT NUMBER (ALA HSC)
;	J/ KDB ADDRESS
;	PUSHJ	P,GETUDB
;RETURN:
;	CPOPJ IF NO SUCH UNIT WITH:
;	T1/ PHYSICAL UNIT SLOT IN KONTAB TO USE OR -1
;		IF NO FREE SLOT FOR UNIT
;	CPOPJ1 IF UNIT EXISTS WITH:
;	U/ UDB ADDRESS

GETUDB:	MOVE	T2,KDBIUN(J)	;GET AOBJN POINTER TO KONTAB FOR THIS KDB
	SETZ	T3,		;HAVEN'T FOUND A FREE SLOT YET
GETUD1:	SKIPN	U,0(T2)		;GET A UDB ADDRESS
	JRST	GETUD2		;NONE HERE
	CAMN	T1,UDBPDN(U)	;PHYSICAL DRIVE NUMBERS MATCH?
	JRST	CPOPJ1##	;YES, SKIP RETURN
	JRST	GETUD3		;NO, BUT THERE WAS A UDB, SKIP A TEST

GETUD2:	SKIPN	T3		;ALREADY FOUND A FREE SLOT?
	MOVE	T3,T2		;NO, SAVE POINTER TO IT
GETUD3:	AOBJN	T2,GETUD1	;LOOP FOR ALL UNITS
	SKIPN	T1,T3		;DID WE FIND A FREE SLOT?
	JRST	[SETO	T1,	;NO, RETURN MINUS ONE
		 POPJ	P,]	;RETURN
	HRRZS	T1		;ISOLATE OFFSET FROM START OF RAKNTB
	HRRZ	T2,KDBIUN(J)	;GET START OF RAKNTB
	SUB	T1,T2		;CALCULATE A PHYSICAL UNIT NUMBER TO USE
	POPJ	P,		;RETURN
;ROUTINE TO GIVE FILSER A FREE INTERRUPT WHEN A DRIVE COMES ONLINE.
;CALL:
;	U/ UDB ADDRESS FOR ONLINE UNIT
;	PUSHJ	P,GIVINT
;RETURN:
;	CPOPJ ALWAYS

GIVINT:	HRRZ	T1,UDBCAM(U)	;ANY OTHER CPU'S HAVE THIS UNIT ATTACHED?
	CAME	T1,.CPBIT##	;...
	POPJ	P,		;YES, NO NEED FOR FREE INTERRUPT
	PUSH	P,U		;SAVE UDB ADDRESS
	PUSH	P,J		;SAVE KDB ADDRESS
	S0PSHJ	FLPUDB##	;TAKE OVER FROM THE ALTERNATE PORT
	MOVE	U,-1(P)		;GET BACK UDB ADDRESS
	S0PSHJ	ATTUDB		;CALL UNIT ATTACH CODE IN FILIO
	MOVE	J,(P)		;GET BACK KDB ADDRESS
	MOVE	U,-1(P)		;GET BACK UDB ADDRESS
	MOVEI	T1,OPPOS	;GET POSITION INTERRUPT CODE FOR FILSER
	HRL	T1,UDBPDN(U)	;PHYSICAL DRIVE NUMBER IN LH (T1)
	SETZB	T2,T3		;NO CONI OR DRB
	LDB	T4,UNYKOF##	;GET KONTAB OFFSET
	MOVE	T4,BITTBL##(T4)	;GET THE APPROPRIATE BIT FOR THIS UNIT
	S0PSHJ	FLHTID##	;GIVE FILSER THE POSITION INTERRUPT
JUPOPJ:	POP	P,J		;RESTORE KDB ADDRESS
	JRST	UPOPJ##		;RESTORE UDB ADDRESS AND RETURN


;ROUTINE TO CALL ATTCPD IN FILIO.  ATTCPD MUST BE CALLED IN SECTION
;ZERO AND WE CAN'T USE S0PSHJ DIRECTLY BECAUSE SSEC0 DOESN'T SUPPORT
;THE CPOPJ2 RETURN.
;CALL:
;	U/ UDB ADDRESS
;	PUSHJ	P,ATTUDB
;RETURN:
;	CPOPJ ALWAYS

ATTUDB:	PUSHJ	P,ATTCPD##	;CALL FILIO
	 POPJ	P,		;UNIT NOT DOWN, WE DON'T CARE
	  PUSHJ	P,RAXDIE	;KONTROLLER BUSY, SHOULD NEVER HAPPEN
	POPJ	P,		;UNIT IS ATTACHED
;ROUTINE TO RETURN A DRIVE TYPE CODE FOR AUTCON BASED ON THE
;MEDIA TYPE RETURNED IN THE GET UNIT STATUS PACKET.
;CALL:
;	T1/ MEDIA TYPE WORD
;	PUSHJ	P,UNTYPE
;RETURN:
;	CPOPJ IF NO MATCH
;	CPOPJ1 IF MEDIA TYPE FOUND WITH:
;	T2/ UNIT TYPE CODE

UNTYPE:	MOVSI	T2,-UNTYPL	;-VE LENGTH OF TABLE
	CAME	T1,UNTYPT(T2)	;FIND A MATCH?
	AOBJN	T2,.-1		;NO, KEEP LOOKING
	JUMPGE	T2,CPOPJ##	;RETURN IF NO MATCH
	HRRZS	T2		;ISOLATE UNIT TYPE CODE (UNYUTP)
	JRST	CPOPJ1##	;SKIP RETURN

UNTYPT:	BYTE (16) 022544,010120	;RA80
	BYTE (16) 022544,010121	;RA81
	BYTE (16) 021244,010074	;RA60
UNTYPL==.-UNTYPT		;LENGTH OF TABLE
	SUBTTL	DRIVER DISPATCH - NODE ONLINE


;HERE WHEN A NODE HAS COME ONLINE, EITHER FOR THE FIRST TIME OR
;AFTER IT HAS DROPPED OFF-LINE.
;CALL:
;	T2/ PBI
;	PUSHJ	P,RAXONL
;RETURN:
;	CPOPJ ALWAYS

RAXONL:	MOVE	P2,T2		;COPY PBI TO SOMEWHERE SAFE
	BLCAL.	(SC.RPB##,<P2>)	;READ THE CONFIGURATION DATA FOR THIS NODE
	  POPJ	P,		;CAN'T DO IT, IGNORE THE ONLINE
	LDB	T2,[POINT PKSID,.RPDPC(T1),PKPID] ;GET TYPE OF NODE
	PUSH	P,T2		;SAVE IT A MOMENT
	MOVE	T2,T1		;COPY ADDRESS TO PROPER AC
	MOVEI	T1,.RPLEN	;LENGTH OF BLOCK
	PUSHJ	P,GIVSWS##	;RETURN THE BLOCK TO THE FREE POOL
	POP	P,T1		;RESTORE NODE TYPE
	CAIE	T1,ID.HSC	;IS IT AN HSC?
	POPJ	P,		;NO, DON'T CONNECT TO IT
	PUSHJ	P,MSCGCI##	;GET A CONNECT TABLE INDEX
	  POPJ	P,		;NONE AVAILABLE, IGNORE THE ONLINE
	HRRZ	P4,T1		;SAVE THE CTI IN A PERMANENT AC
	XMOVEI	T1,RAXDDT	;GET ADDRESS OF DRIVER DISPATCH TABLE
	MOVEM	T1,MSCDDT##(P4)	;STORE FOR MSCCOM
	MOVX	T1,DT.IRC	;INDICATE WE ARE RELOADING
	IORM	T1,MSCFLG##(P4)	;...
	BLCAL.	(SC.CON##,<<.,OURDNM>,<.,YURDNM>,P2,[DCREDT],[DCREDT],<.,MSCINT##>,P4,[0],[HSCBFN],[DGNUM]>)
	  STOPCD CPOPJ##,DEBUG,RAXCSF, ;++CONNECT TO MSCP SERVER FAILED
	POPJ	P,		;RETURN AND WAIT FOR CONNECT RESPONSE
	SUBTTL	THE END


RAXDIE:	STOPCD	.,STOP,RAXRAX,	;++ RAXKON IS MISERABLE

RAXEND:!END