	.NLIST
;
; Version:	'X-61'
;
	.LIST ME
;
;****************************************************************************
;*									    *
;*  COPYRIGHT (c) 1990, 1991, 1993, 1994				    *
;*  DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS.		    *
;*  ALL RIGHTS RESERVED.						    *
;*									    *
;*  THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED   *
;*  ONLY IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE   *
;*  INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR  ANY  OTHER   *
;*  COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY   *
;*  OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF	 THE  SOFTWARE IS  HEREBY   *
;*  TRANSFERRED.							    *
;*									    *
;*  THE INFORMATION IN THIS SOFTWARE IS	 SUBJECT TO CHANGE WITHOUT NOTICE   *
;*  AND	 SHOULD	 NOT  BE  CONSTRUED AS	A COMMITMENT BY DIGITAL EQUIPMENT   *
;*  CORPORATION.							    *
;*									    *
;*  DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE  OR  RELIABILITY OF ITS   *
;*  SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.		    *
;*									    *
;*									    *
;****************************************************************************

;++
;
; FACILITY:  EVMS System Macro Libraries
;
; ABSTRACT:
;
;	This file contains macros that are commonly used by the
;	EVMS executive and drivers.
;
; ENVIRONMENT:
;
;	n/a
;
;--
;
;
; AUTHOR:  The VMS Group	 CREATION DATE:	 19-Apr-1990
;
; MODIFIED BY:
;
;	X-61	RCL		Rick Lord		26-Mar-1996
;		Add new macro SPI$INITIAL_PROCESSING for use by the
;		SCSI class drivers.
;
;	X-60	PJH		Paul J. Houlihan	29-Jun-1995
;		Get rid of a temporary macro and change default of the
;		pending I/O routine.
;
;	X-59	LSS0350		Leonard S. Szubowicz	28-Jun-1995
;		Change the Step 2 driver sub-version that is initialized by the
;		DPTAB macro to DPT$K_STEP2_V5 for Theta EFT.  See edit X-14
;		to DPTDEF.SDL.
;
;	X-58	PJH		Paul J. Houlihan	26-Jun-1995
;		Add new driver entry macro for pending I/O routine.
;
;	X-57	PJH		Paul J. Houlihan	22-Jun-1995
;		Add initialization of new DDT routine vector cell to DDTAB.
;
;	X-56	LSS0345		Leonard S. Szubowicz	27-Apr-1995
;		Change the Step 2 driver sub-version that is initialized by the
;		DPTAB macro to DPT$K_STEP2_V4 for Theta IFT.  See edit X-13
;		to DPTDEF.SDL.
;
;	X-55	DED		Denise E. Dumas		9-Mar-1995
;		Fast Path support: add INITIATE_SETUP, INCREMENT_IOCNT,
;		CALL_REQCOM_LOCAL, IOFORK_CPU, IPINT_CPU_FAST, and 
;		MSCP_IO_SETUP.
;
;	X-54	LSS0320		Leonard S. Szubowicz	16-Feb-1995
;		64-Bit Virtual Addressing: Modify the CALL_READCHK, 
;		CALL_READCHKR, CALL_READLOCK, CALL_READLOCK_ERR, CALL_WRITECHK, 
;		CALL_WRITECHKR, CALL_WRITELOCK, CALL_WRITELOCK_ERR,
;		CALL_MODIFYLOCK, and CALL_MODIFYLOCK_ERR macros to handle
;		64-bit buffer addresses.
;
;	X-53	JCH703a	John C. Hallyburton, Jr.	17-Jan-1995
;		Fix FAST_FDT table entry in DDTAB to generate a reference
;		to the "real" FAST_FDT code entry.
;
;	X-52	LSS0313		Leonard S. Szubowicz	 4-Nov-1994
;		Change X-51 to reflect last minute change to X-47U1.
;		DPT_STORE_DIPL macro should call IOC$SETUP_UCB_DIPL with only
;		the UCB pointer as a parameter.
;
;	X-51	LSS0313		Leonard S. Szubowicz	 3-Nov-1994
;		Fold X-47U1 from Zeta.
;		Add DPT_STORE_DIPL macro which can be used instead of
;		"DPT_STORE UCB,UCB$B_DIPL,dipl_const" to load the platform-
;		specific DIPL for the adapter.  See STAR::EVMS_IO note 378.13
;		for details.
;
;	X-50	LSS0312		Leonard S. Szubowicz	24-Oct-1994
;		Change the Step 2 driver sub-version that is initialized by the
;		DPTAB macro to DPT$K_STEP2_V3 because of the various I/O data 
;		structure changes that are necessary to support 64-bits and 
;		Fast I/O.  See edit X-12 to DPTDEF.SDL.
;
;	X-49	LSS0311		Leonard S. Szubowicz	17-Oct-1994
;		Add FDT_64 macro to allow drivers to declare what functions
;		can accept a 64-bit $QIO P1 parameter.  Initialize the new
;		FDT$Q_OK64BIT cell in the FDT_INI macro.  See "Chapter 20: QIO
;		and Device Drivers" in DOCD$:[EVMS.CMS_64B]DS-64BITS.PS.
;
;	X-48	JCH703	John C. Hallyburton, Jr.		 5-Oct-1994
;		Update DDTAB to correspond to Fast-IO DDT addition.
;		Correct typo in IOFORK descriptive comment.
;
;	X-47	JFD0558		James F. Dunham		 3-AUG-1994
;		Change SPI$CONNECT to pass a port state context value along
;		with the port_state_callback routine address
;
;	X-47	JFD0498		James F. Dunham		19-MAY-1994
;		1). Change arguments to SC$CMD_BUFFER_ALLOC to not require
;		    return size address
;		2). Include all SCSI-2 data structures in SCQ$ version checks
;		3). Correct argument order fo ACA_START_PROCESSING and ACA_END_PROCESSING
;		4). Fix initialization of SCQ$PS_PORT_STATE_CALLBACK
;
;	X-47-0	JFD0254		James F. Dunham		 1-APR-1994
;		Add updated SPI$, PORT$ and COMM$ macros for the SCSI-2
;		Class / Common / Port Interfaces
;
;	X-46	RAR032		Buzzy Ritter		11-Mar-1994
;		Fix default TYPE parameter in SPI$RESET to match traditional
;		behavior.
;
;	X-45	ROW0844		Ralph O. Weber		21-DEC-1993 11:48
;		Update DPT$IW_STEPVER to signal data structure changes
;		created in ROW0842.
;
;	X-44	ROW0842		Ralph O. Weber		16-DEC-1993 16:20
;		Add DPTAB setup for DPT$IW_IOHANDLES.  Add DDTAB setup for
;		DDT$PS_CSR_MAPPING.  These two new fields are part of driver-
;		based PCI bus CSR mapping support.
;
;	X-43	RCL		Rick Lord		4-Nov-93
;
;		Remove SPI$ macros for calling the SCSI port driver
;		target mode routines. The SPDT vectors for these
;		routines have been removed because target mode is
;		not currently supported.
;
;	X-42	JCN		Jan Nordh		29-Sep-1993
;		Convert all SPI$ macros from JSB to CALL interfaces.
;		Merged LPL1015 with my edits.
;		LPL1015		Lee Leahy		 8 Jul 1993
;		1.)  Modified SP1/SPI$SEND_COMMAND macro:
;			Added the type parameter.
;			Initialized the SCDRP$IS_QUEUE_CHAR field using the type parameter.
;		2.)  Added the following MACROS:
;			SPI$FREEZE_QUEUE
;			SPI$RELEASE_QUEUE
;			SPI$FLUSH_QUEUE
;		3.)  Modified SP1/SPI$RESET macro:
;			Added the type parameter.
;			When type != BUS, call SPDT$PS_RESET_DEVICE instead
;				of SPDT$L_RESET.
;		4.)  Modify SP1/SPI$CONNECT macro:
;			Add PORT_CALLBACK parameter.
;			Initialize SCDT$PS_PORT_CALLBACK
;
;	X-41	LSS293		Leonard S. Szubowicz	10-Sep-1993
;		HLLDD: Add an consistency check to try to catch inappropriate
;		usage of DDTAB JSB_START and a call entry $DRIVER_START_ENTRY.
;		This consistency check only works if both are in the same
;		module, but should be useful nonetheless.
;
;	X-40	LSS0291		Leonard S. Szubowicz	 9-Sep-1993
;		HLLDD: Remove support for STEP=1 drivers: Change DPTAB, DDTAB,
;		macros.	 FUNCTAB is obsolete, but informs about its replacement.
;		Also, treat invalid values for YES/NO parameters (and similar
;		keyword parameters) on step 2 macros as errors instead of
;		warnings.  And, remove old $x macros (see edits X-35 and X-37).
;
;	X-39	LSS0289		Leonard S. Szubowicz	 3-Sep-1993
;		In DPTAB, change the informational message about the
;		obsolescence of STEP=1 drivers, now that it is fast approaching,
;		to a more noticable warning.
;
;	X-38	DEE0195		David E. Eiche		 25-Aug-1993
;		Make FDT label a global symbol for HLL driver table support.
;
;	X-37	LSS0283		Leonard S. Szubowicz	 18-Aug-1993
;		HLLDD: Generate warning messages in old $x macros to use CALL_x
;		instead.  These macros will be removed in FT3. (see X-35)
;		Also, add support for PRESERVE=<NULL> to $DRIVER_x_ENTRY macros.
;
;	X-36	WDB:HLL066	Walter D. Blaschuk, Jr.	 18-AUG-1993
;		HLLDD Project: Remove the generic offdefs in the
;		$DRIVER_entrypoint_ENTRY macros.
;
;	X-35	WDB:HLL065	Walter D. Blaschuk, Jr.	 04-AUG-1993
;		HLLDD Project: Change the Step 2 macros to use
;		"CALL_" as a prefix rather than "$".
;
;	X-33	LSS0276		Leonard S. Szubowicz	  9-Jul-1993
;		Add DDTAB JSB_START and JSB_ALTSTART for step 2 drivers that
;		continue to use a JSB start I/O and fork environment.
;
;	X-32	LSS0276		Leonard S. Szubowicz	  1-Jul-1993
;		Use the .GLOBAL directive instead of .EXTERNAL.	 The .EXTERNAL
;		directive does not allow the symbol to be defined by the current
;		module.	 However, .GLOBAL allows the symbol to be defined
;		in the current module as well as externally (see X-31, X-17).
;
;	X-31	LSS0276		Leonard S. Szubowicz	 28-Jun-1993
;		Add .EXTERNAL directives for new routine references added by
;		edit X-30.  This makes these macros function transparently
;		in environments that use the .DISABLE GLOBAL directive.
;
;	X-30	LSS0276		Leonard S. Szubowicz	 24-Jun-1993
;		Add support for callable fork routines as in EVMS$IO_CMS:
;		HLLDD-FORK.MEM to the FORK, FORK_ROUTINE, FORK_WAIT, IOFORK,
;		RELCHAN, REQCOM, REQCHAN, REQPCHAN, WFIKPCH, and WFIRLCH macros.
;
;	X-29	WDB:HLL060C	Walter D. Blaschuk, Jr. 03-JUN-1993
;		HLLDD Project: Change names of offsets to inbound
;		driver routines.
;
;	X-28	WDB:HLL060C	Walter D. Blaschuk, Jr. 03-JUN-1993
;		HLLDD Project: FDT Support routine Macros bugs.
;		Fix COM_STD$SETATTNAST again
;
;	X-27	WDB:HLL060B	Walter D. Blaschuk, Jr. 20-MAY-1993
;		HLLDD Project: FDT Support routine Macros bugs.
;		1)COM_STD$SETATTNAST  and  COM_STD$SETCTRLAST  will
;		  conditionally return on error,
;		2)$DRIVER_FDT_ENTRY will now,  by default, preserve
;		  R2-R15.
;
;	X-26	WDA		Walter D. Arbo		06-May-1993
;		Make ARG names to $OFFSET macros consistent across
;		for the $DRIVER_<inbound routine>_ENTRY macros.
;
;	X-25	WDB:HLL060A	Walter D. Blaschuk, Jr. 12-APR-1993
;		HLLDD Project: FDT Support routine Macros
;		Added to the  *LOCK_ERR	 support routine macros an
;		interface warning alerting the user that the error
;		callback routines must have the standard call
;		interface.
;
;	X-24	WDB:HLL060	Walter D. Blaschuk, Jr. 25-MAR-1993
;		HLLDD Project: FDT Support routine Macros
;		Alter some support routine macros so the interface
;		is identical to the Step 1 JSB interfaces.
;
;	X-23	DEE0176		David E. Eiche		05-Mar-1993
;		Restore DDT$PS_MNTV_SSSC and DDT$PS_MNTV_SQD to DDTAB
;		pending changes to the host-based shadowing code.
;
;	X-22	LSS0269		Leonard S. Szubowicz	 4-Mar-1993
;		Edit X-21 prematurely removed the definition of the symbol
;		EVMS$DRIVER_DPT from the DPTAB macro.  DPTAB will still
;		define this symbol if the driver is a step 1 driver and it
;		has not overridden the default DPT name.
;
;	X-21	LSS0267		Leonard S. Szubowicz	26-Feb-1993
;		In the DDTAB macro, use $$STEP for all step dependent
;		conditionals once a value for $$STEP is assured.  The STEP
;		parameter is optional and may not have been specified.
;		In FDT_INI, do not save and restore current PSECT which is
;		problematic if the current PSECT is DRIVER_DATA.
;		Also, in DPTAB, remove definition of EVMS$DRIVER_DPT symbol.
;
;	X-20	WDA		W.D.Arbo		18-Feb-1993
;		Make corrections to macros added in X-19.
;		Make DPT corrections for X-18.	Bump STEPVER to 2.
;		Change IOC$CANCEL to IOC$CANCELIO inside DDTAB.
;
;	X-19	WDA		W.D.Arbo		11-Feb-1993
;		Add macros for converting Step 1 inbound driver routines
;		written in Macro-32 to Step 2.	These macros define symbolic
;		AP offsets for the arguments and optionally move the arguments
;		into the expected registers.
;
;	X-18	DEE0174		David E. Eiche		26-Jan-1993
;		Fix typos in the new FDT_xxx macros.  Fix the FUNCTB reference
;		in the DDTAB macro to be a .ADDRESS rather than GENRADDR.
;		Remove LMF fields from the DPTAB.  Remove unused mount
;		verification slots from DDTAB.
;
;	X-17	LSS0264		Leonard S. Szubowicz	22-Jan-1993
;		In the DDTAB macro, fix a typo in a reference to DDT$$BASE.
;		In DPTAB, DDTAB, and FDT_INI macros declare all the new
;		system routine references that were added by X-15 as external
;		symbols.  This is required if .DISABLE GLOBAL is in effect.
;		Also, in DDTAB make STEP=1 the default if no prior or
;		current declaration.  In DDTAB and DPTAB check to make sure
;		that the current step is the same as any prior declaration.
;
;	X-16	WDB:HLL022	Walter D. Blaschuk, Jr. 11-Jan-1993
;		HLLDD Project: FDT processing changes.
;		Add the Macro-32 macros which will set up the entry
;		points to driver specific upper level FDT routines.
;		These entry points will be .CALL_ENTRY and move the
;		standard inputs into the commonly used registers.
;
;	X-15	DEE0171		David E. Eiche		12-Jan-1993
;		Modify DPTAB and DDTAB to add STEP 2 driver dispatch
;		fields.	 Add FDT_INI, FDT_BUF and FDT_ACT macros to
;		implement the STEP 2 function decision table format.
;
;	X-14	WDB:HLL009	Walter D. Blaschuk, Jr. 11-Jan-1993
;		HLLDD Project: FDT processing changes.
;		Add the Macro-32 macros which will set up the calls
;		to the FDT completion routines and some FDT support
;		routines.
;
;	X-13	WDB:HLL008	Walter D. Blaschuk, Jr. 06-Jan-1993
;		HLLDD Project: FDT processing changes.
;		Add the $FDTARGDEF macro for the use in Step 2 upper
;		level FDT routines for parameter offsets.
;		Add FDT2 .long 0 to the DDTTAB macro temporarily.
;
;	X-12	LSS0258		Leonard S. Szubowicz	16-Nov-1992
;		Remove usage of EVAX and VAX conditionals in the DPT_STORE
;		and DRIVER_CODE macros.
;
;	X-11	TYC		Theresa Chin		22-Jun-1992
;		Add SP1$ macros to use CALL interface rather than JSB
;		to call various SCSI routines.	Also use new SCQDEF
;		data structure to pass parameters in SP1$CONNECT macro.
;
;	X-10	PJH		Paul J. Houlihan	08-May-1992
;		Remove obsolete $PRTCT* macros.
;
;	X-9	ROW0810		Ralph O. Weber		23-APR-1992 17:54
;		Add a reference to $PDSCDEF in DPT_STORE_ISR.  This should
;		prevent driver writers from having to make an explicit
;		invocation of the $PDSCDEF macro.
;
;	---------- Ident numbering change due to master pack reorg ---------
;
;	X-16	LSS0241		Leonard S. Szubowicz	27-Feb-1992
;		In macro DPTAB assure DPT is quadword aligned and in macro
;		DDTAB assure DDT is quadword aligned.  Also, in macros
;		TIMEDWAIT and TIMEDELAY allocate enough stack space to handle
;		a less than longword aligned stack.
;
;	X-15	ROW0798		Ralph O. Weber		31-DEC-1991 10:49
;		Add BT_ORDER parameter to DPTAB macro and use its value to
;		set DPT$IS_BTORDER.  The macro compiler no longer crashes
;		when presented with the extended DPTAB parameter list.
;		This completes the work begun in ROW0788.
;
;	X-14	ROW0796		Ralph O. Weber		19-DEC-1991 17:15
;		Add informational message to DPTAB that cautions against
;		use of STEP=1 drivers.
;
;	X-13	JTK		Jim Klumpp		04-Dec-1991
;		Remove the following obsolete macros: ADPDISP,
;		BI_NODE_RESET, LOADALT, PURDPR, RELALT, RELDPR,
;		RELMP, REQALT, REQDPR, REQMPR.
;
;	X-12	ROW0790		Ralph O. Weber		18-NOV-1991 14:33
;		Change SPI$CONNECT to return SS$_NOSUCHDEV in R0 instead of
;		bugchecking.  This (combined with some already done changes
;		in DKDRIVER) will eliminate any boot-time driver loading
;		dependencies between DKDRIVER and PK%DRIVER.
;
;	X-11	LSS0234		Leonard S. Szubowicz	14-Nov-1991
;		Remove the VAX-specific version of CPUDISP from this source
;		file.  It was replacing the Alpha-specific version previously
;		defined in SYSMAR.MAR.	Also remove obsolete CPUDISPATCH and
;		SUBCPUDISPATCH macros.
;
;	X-10	BJT266		Benjamin J. Thomas III	11-Nov-1991
;		Modify the IOFORK macro to be a consumer of FORK
;
;	X-9	ROW0788		Ralph O. Weber		23-OCT-1991 15:08
;		Add DPT$IS_BTORDER to DPTAB macro.  Currently, I cannot stick
;		in a DPTAB parameter to set the value.	The macro compiler
;		blows up when I try.
;
;	X-8	BJT253		Benjamin J. Thomas III	11-Oct-1991
;		Once again, fix up CRAM_ALLOC order of arguments
;
;	X-7	BJT248		Benjamin J. Thomas III	20-Sep-1991
;		Fix up CRAM_ALLOC, arguments are pushed in the wrong order
;
;	X-6	ROW0783		Ralph O. Weber		16-SEP-1991 09:00
;		Fix SPI$CONNECT to use PUSHR/POPR instead of PUSHQ/POPQ.
;		Gag!  How did this bogus tripe last so long?
;
;	X-5	BJT238		Benjamin J. Thomas III	04-Sep-1991
;		Add ADP argument to CRAM_ALLOC
;
;	X-4	CEG		Clair Grant		08-Aug-1991
;		In DRIVER_CODE and DRIVER_DATA, make psects be 32-byte aligned.
;
;	X-3	LSS0192		Leonard S. Szubowicz	28-Jun-1991
;		Remove obsolete UNIBUS/MASSBUS map register macros.
;
;	X-2	ROW0754		Ralph O. Weber		15-MAY-1991 11:35
;		Add $SVA_TO_PA, system virtual address to physical address
;		conversion.  Add $SVAPTE_TO_PA, SVAPTE + BOFF to physical
;		address conversion.
;
;	---------- Ident numbering change due to move from SYS to LIB ---------
;
;	X-7	SCM		Steven C. Mayhew	13-Mar-1991
;		removed old SCS macros.	 The new SCS macros are in the
;		cluster facility (SYSAP_MACROS.MAR) and will still be in
;		LIB.MLB
;
;	X-6	ROW0741		Ralph O. Weber		13-MAR-1991 10:44
;		Add the CHANNEL_ASSIGN and CANCEL_SELECTIVE fields used by
;		open VMS to the DDTAB macro initialization of a DDT.  Also,
;		leave the first longword of the DDT unused and add a
;		DDT$IW_SIZE field, as required by the terminal class driver.
;
;	X-5	ROW0740		Ralph O. Weber		12-MAR-1991 15:38
;		Add SPI$FINISH_COMMAND so that the macros match the
;		documentation.	This change matches MCY002 (X-160) in
;		the VAX/VMS development streem.
;
;	---------- Ident numbering change due to master pack reorg ---------
;
;	X-1K28	JTK		Jim Klumpp		05-Mar-1991
;		In TIMEDWAIT macro, perform the approriate LDQ/STQ sequence
;		on the NSEC parameter based on its type.
;
;	X-1K27	BJT0220		Benjamin J. Thomas III	10-Feb-1991
;		Add RETURN parameter to REQCOM to allow RSB or RET exits
;
;	X-1K26	BJT0219		Benjamin J. Thomas III	28-Jan-1991
;		Update REQCOM to be JSB/RSB pair rather than JMP.
;
;	X-1K25	ROW0728		Ralph O. Weber		24-JAN-1991 15:58
;		Add a RETURN parameter to the IOFORK macro, like was done to
;		the FORK macro in ROW0709.  This is necessary to facilitate
;		coding of interrupt service routines, which are called via
;		a CALL not a JSB.
;
;	X-1K24	ROW0723		Ralph O. Weber		21-JAN-1991 17:07
;		Fix the SPI$TQE_WAIT macro so that it can deal with an
;		input stack arrangement that is longword but not quadword
;		aligned.
;
;	X-1K23	ROW0722		Ralph O. Weber		20-JAN-1991 21:09
;		Update the SPI$CONNECT macro to use the newly created system
;		cell IOC$GL_SPI_CONNECT instead of EXE$GL_SYS_SPECIFIC.
;
;	X-1K22	ROW0720		Ralph O. Weber		16-JAN-1991 15:23
;		Change the TICKS and SECONDS parameters on the SPI$TQE_WAIT
;		macro to allow values other than compile time constants.
;		Also fix mistake in setting up the parameters to the
;		SPDT$PS_TQE_WAIT call.
;
;	X-1K19	BJT215		Benjamin J. Thomas III	12-Jan-1991
;		Add CRAM macros: CRAM_ALLOC, CRAM_DEALLOC, CRAM_IO,
;		CRAM_QUEUE, CRAM_WAIT and CRAM_CMD
;
;	X-1K18	ROW0715		Ralph O. Weber		21-DEC-1990 16:45
;		Add SPI$TQE_WAIT macro.	 SPI$TQE_WAIT is a SCSI class/port
;		interface macro that waits a class driver KP thread for a
;		specified number of seconds (or VMS clock ticks).
;
;	X-1K17	ROW0714		Ralph O. Weber		07-DEC-1990 11:43
;		Merge late V5.4 change in SPI$MAP_BUFFER into this source.
;		Original change was done by Jim Klumpp.	 It adds apriority
;		parameter to the SPI$MAP_BUFFER macro.
;
;	X-1K16	BJT213		Benjamin J. Thomas III	 5-Dec-1990
;		Sigh.  Fix missing .ENDC in TIMEDWAIT
;
;	X-1K15	BJT213		Benjamin J. Thomas III	27-Nov-1990
;		Fix omission in TIMEDWAIT argument list.
;
;	X-1K14	BJT213		Benjamin J. Thomas III	16-Nov-1990
;		Add new TIMEDWAIT macro.
;		Obsolete TIMEWAIT macro.
;		Add new TIMEDELAY macro.
;
;	X-1K13	ROW0710		Ralph O. Weber		16-NOV-1990 14:29
;		In DPTAB: Add space for loader handle (to permit eventual
;		unloading of drivers).	Quad align DPT$Q_LINKTIME.
;
;	X-1K12	ROW0709		Ralph O. Weber		12-NOV-1990 18:26
;		Add RETURN=RSB parameters to WFIKPCH, WFIRLCH, FORK, and
;		FORK_WAIT so that these macros can be used by the kernel
;		process services routines (which are call-based).  Fix
;		REQPCHAN to use IOC$PRIMITIVE_REQCHAN{H/L} instead of
;		IOC$PRIMITIVE_REQ*P*CHAN{H/L}.	Add KP stack size and
;		register save mask parameters to DDTAB.
;
;	X-1K11	LSS0184		Leonard S. Szubowicz	 7-Nov-1990
;		Change the psect attributes used by the DRIVER_CODE and
;		DRIVER_DATA macros such that the psects could be grouped into
;		image sections in the manner required for an execlet.
;
;	X-1K10	ROW0707		Ralph O. Weber		04-NOV-1990 10:00
;		Enhance the DDTAB macro to generate an entry for the kernel
;		process start I/O routine, DDT$PS_KP_STARTIO.  When a driver
;		uses kernel processes, DDT$PS_START will point to
;		EXE$KP_STARTIO (a common routine that gets the start I/O
;		kernel process thread started at the address pointed to by
;		DDT$PS_KP_STARTIO.
;
;	X-1K9	LSS0182		Leonard S. Szubowicz	 2-Nov-1990
;		Add optional DPT=EVMS$DRIVER_DPT arg to DPTAB to allow the
;		definition of an alternate global symbol for the DPT location.
;		Make the DRIVER$$STRUC_INIT and DRIVER$$STRUC_REINIT entry
;		point names, which are defined by DPT_STORE INIT and REINIT,
;		to be local symbols.  The above are required to link MBDRIVER
;		and NLDRIVER together into the SYSDEVICE.EXE image.
;		Also, remove extra .SAVE_PSECT generated by DPT_STORE INIT,
;		and add declaration of linkage psect to DRIVER_CODE macro.
;
;	X-1K8	ROW0706		Ralph O. Weber		28-OCT-1990 17:07
;		- Eliminate the generation of a CALL (to the reinit routine)
;		  by DPT_STORE REINIT.	The necessary call is already being
;		  done by the exec routine that calls init and reinit
;		  routines.
;		- Fix bad DSC symbol references in DPTAB.
;		- Change DPT$K_STEP1 to DPT$K_STEP_1 in DPTAB.
;
;	X-1K7	ROW0703		Ralph O. Weber		15-OCT-1990 17:27
;		Change DPTAB macro to reference DPT$Q_LINKTIME instead of
;		DPT$IQ_LINKTIME.  SDL cannot build both symbols in a way
;		that makes BLISS happy.	 So, I had to stop creating the IQ
;		tagged symbol.
;
;	X-1K6	ROW0701		Ralph O. Weber		10-OCT-1990 16:54
;		Update DPTAB, DPT_STORE, DDTAB, and FUNCTAB to match the
;		current design.	 Also, add DRIVER_CODE and DRIVER_DATA macros.
;
;	X-1K5	WCT0209		Ward C. Travis		27-Sep-1990
;		Provide	  stubbed  functions   for  $PRTCTINI	and
;		$PRTCTEND  until  new  proposal/design is  hammered
;		out.
;
;	X-1K4	LSS0167		Leonard S. Szubowicz	14-Sep-1990
;		Add new macro FORK_ROUTINE to declare fork routine entry point.
;
;	X-1K3	LSS0161		Leonard S. Szubowicz	 1-Aug-1990
;		Changes to the FORK, IOFORK, FORK_WAIT, REQPCHAN, WFIKPCH, and
;		WFIRLCH macros in support of the "simple fork" mechanism on
;		EVAX.  Also remove the obsolete REQSCHAN and RELSCHAN macros.
;
;**


; CRAM Macros

; CRAM_ALLOC	- Used to allocate a CRAM

	.MACRO	CRAM_ALLOC -
			CRAM,	-	; Address of longword for CRAM address
			IDB=#0,	-	; (Optional) Address of IDB
			UCB=#0, -	; (Optional) Address of UCB
			ADP=#0		; (Optional) Address of ADP

	CLRL	-(SP)			; Clear space for returned address
	PUSHL	ADP			; Pass pointer to ADP
	PUSHL	UCB			; Pass pointer to UCB
	PUSHL	IDB			; Pass pointer to IDB
	PUSHAB	12(SP)			; Point to CRAM address on stack
	CALLS	#4,G^IOC$ALLOCATE_CRAM	; Allocate a CRAM
	POPL	CRAM			; Retrieve the CRAM address
	.ENDM	CRAM_ALLOC

; CRAM_DEALLOC - Deallocate a CRAM

	.MACRO	CRAM_DEALLOC -
			CRAM		; Address of CRAM

	PUSHL	CRAM			; Point to the CRAM
	CALLS	#1,G^IOC$DEALLOCATE_CRAM; Deallocate it
	.ENDM	CRAM_DEALLOC

; CRAM_IO - Perform I/O operation with a CRAM

	.MACRO	CRAM_IO	-
			CRAM		; Address of CRAM

	PUSHL	CRAM			; Point to the CRAM
	CALLS	#1,G^IOC$CRAM_IO	; Perform the operation
	.ENDM	CRAM_IO

; CRAM_QUEUE - Queue an I/O operation with the CRAM

	.MACRO	CRAM_QUEUE -
			CRAM		; Address of the CRAM

	PUSHL	CRAM			; Point to the CRAM
	CALLS	#1,G^IOC$CRAM_QUEUE	; Queue it
	.ENDM	CRAM_QUEUE

; CRAM_WAIT - Wait for I/O operation to be finished

	.MACRO	CRAM_WAIT -
			CRAM		; Address of the CRAM

	PUSHL	CRAM			; Point to the CRAM
	CALLS	#1,G^IOC$CRAM_WAIT	; Wait for the operation to complete
	.ENDM	CRAM_WAIT

; CRAM_CMD - Obtain bus and operation specific COMMAND, MASK and RBADR fields

	.MACRO	CRAM_CMD -
			INDEX,	-	; Command index
			OFFSET,	-	; Offset from base CSR address
			ADP,	-	; Pointer to ADP
			CRAM=#0,-	; (Optional) Address of CRAM
			COMMAND=#0	; (Optional) Address of octaword buffer

	PUSHL	COMMAND			; Point to COMMAND field
	PUSHL	CRAM			; Point to the CRAM
	PUSHL	ADP			; Point to the ADP
	PUSHL	OFFSET			; Save the offset
	PUSHL	INDEX			; Save the INDEX
	CALLS	#5,G^IOC$CRAM_CMD	; Get the command
	.ENDM	CRAM_CMD

;
;
;
; GENERATE DRIVER DISPATCH TABLE
;
; DDTAB	-- A ton of parameters, see the macro definition below.
;
;
	.MACRO	DDTAB	DEVNAM,-		; device name for symbol
			START=0,-		; start I/O routine
			CTRLINIT=0,-		; controller init routine
			FUNCTB,-		; FDT address
			CANCEL=0,-		; cancel I/O routine
			REGDMP=0,-		; register dump routine
			DIAGBF=0,-		; diagnostic buffer size
			ERLGBF=0,-		; error log buffer size
			UNITINIT=0,-		; unit init routine
			ALTSTART=0,-		; alt start I/O routine
			MNTVER=0,-		; mount verification routine
			CLONEDUCB=0,-		; cloned UCB routine
			MNTV_SSSC=0,-		; mount ver rout. for shadow sets
			MNTV_FOR=0,-		; mount ver rout. for /FOREIGN
			MNTV_SQD=0,-		; mount ver rout. for tapes
			CHANNEL_ASSIGN=0,-	; routine to call from $ASSIGN
			CANCEL_SELECTIVE=0,-	; selective cancel routine
			KP_STACK_SIZE=0,-	; KP stack byte count
			KP_REG_MASK=0,-		; KP register save mask
			KP_STARTIO=0,-		; start I/O for KP drivers
			CSR_MAPPING=0,-		; CSR mapping routine
			AUX_STORAGE=0,-
			AUX_ROUTINE=0,-
			STEP,-
			JSB_START,-		; start I/O jsb (step 2)
			JSB_ALTSTART,-		; alt start I/O jsb (step 2)
			FAST_FDT,-		; Fast-IO FDT routine (post step 2)
			PENDING_IO=0 		; Pending I/O routine
	$DDTDEF
	$FDTDEF

	.IF	NOT_BLANK,STEP		;if STEP= explicitly specified
	  .IF	DIFFERENT <STEP>,<2>	;  assure that value is 2
	     .ERROR ;DDTAB must declare driver %extract(0,4,<STEP>)=2 ;
	  .ENDC
	  .IF	DEFINED,$$STEP		;if previously specified
	    .IF NOT_EQUAL,$$STEP-STEP	;  assure this is same value
	      .ERROR $$STEP	;DDTAB %extract(0,4,<STEP>)=STEP conflicts with prior declaration;
	    .ENDC
	  .ENDC
	  $$STEP = STEP
	.ENDC

	.IF	NOT_DEFINED,$$STEP
	  $$STEP = 2
	  .PRINT $$STEP ;DDTAB is assuming driver %extract(0,4,<STEP>)=2;
	.ENDC

	.IF	IDENTICAL <START>,<EXE$KP_STARTIO>
	  .ERROR ;%extract(0,5,<START>)=EXE$KP_STARTIO isn't valid for %extract(0,4,<STEP>)=2. Try EXE_STD$KP_STARTIO ;
	.ENDC
	.IF	IDENTICAL <CANCEL>,<IOC$CANCELIO>
	  .ERROR ;%extract(0,6,<CANCEL>)=IOC$CANCELIO isn't valid for %extract(0,4,<STEP>)=2. Try IOC_STD$CANCELIO ;
	.ENDC
	.IF	IDENTICAL <MNTVER>,<IOC$MNTVER>
	  .ERROR ;%extract(0,6,<MNTVER>)=IOC$MNTVER isn't valid for %extract(0,4,<STEP>)=2. Try IOC_STD$MNTVER ;
	.ENDC

	.IF	NOT_BLANK,JSB_START
	  .IF	DIFFERENT,START,0
	    .IF	DIFFERENT,START,IOC$START_C2J
	      .WARN ;%extract(0,5,<START>)=START superseded by %extract(0,9,<JSB_START>)=JSB_START;
	    .ENDC
	  .ENDC
	.ENDC

	.IF	NOT_BLANK,JSB_ALTSTART
	  .IF	DIFFERENT,ALTSTART,0
	    .IF	DIFFERENT,ALTSTART,IOC$ALTSTART_C2J
	      .WARN ;%extract(0,8,<ALTSTART>)=ALTSTART superseded by %extract(0,12,<JSB_ALTSTART>)=JSB_ALTSTART;
	    .ENDC
	  .ENDC
	.ENDC


	DRIVER_DATA
	.ALIGN	QUAD
'DEVNAM'$DDT::
DDT$$BASE:
	.LONG	0 ; reserved
	.LONG	0 ; reserved
	ASSUME	DDT$IW_SIZE  EQ <.-DDT$$BASE>
	.WORD	DDT$K_LENGTH
	.WORD	0
	ASSUME	DDT$IW_DIAGBUF	EQ <.-DDT$$BASE>
	.WORD	DIAGBF
	ASSUME	DDT$IW_ERRORBUF	 EQ <.-DDT$$BASE>
	.WORD	ERLGBF
	ASSUME	DDT$IW_FDTSIZE	EQ <.-DDT$$BASE>
	.WORD	FDT$K_LENGTH

	.WORD	0

	.IF	BLANK,JSB_START
	  .GLOBAL  IOC$RETURN_SUCCESS
	  ASSUME   DDT$PS_START_2  EQ <.-DDT$$BASE>
	  GENRADDR START,IOC$RETURN_SUCCESS
	  ASSUME   DDT$PS_START_JSB  EQ <.-DDT$$BASE>
	  .LONG	0
	.IFF
	  $$JSB_START = 1
	  .GLOBAL  IOC$RETURN,IOC$START_C2J
	  ASSUME   DDT$PS_START_2  EQ <.-DDT$$BASE>
	  GENRADDR IOC$START_C2J
	  ASSUME   DDT$PS_START_JSB  EQ <.-DDT$$BASE>
	  GENRADDR JSB_START,IOC$RETURN
	.ENDC

	ASSUME	DDT$PS_CTRLINIT_2  EQ <.-DDT$$BASE>
	.GLOBAL	 IOC$RETURN_SUCCESS
	GENRADDR CTRLINIT,IOC$RETURN_SUCCESS

	ASSUME	DDT$PS_UNITINIT_2  EQ <.-DDT$$BASE>
	.GLOBAL	 IOC$RETURN_SUCCESS
	GENRADDR UNITINIT,IOC$RETURN_SUCCESS

	ASSUME	DDT$PS_CLONEDUCB_2  EQ <.-DDT$$BASE>
	.GLOBAL	 IOC$RETURN_SUCCESS
	GENRADDR CLONEDUCB,IOC$RETURN_SUCCESS

	ASSUME	DDT$PS_FDT_2  EQ <.-DDT$$BASE>
	.ADDRESS FUNCTB

	ASSUME	DDT$PS_CANCEL_2	 EQ <.-DDT$$BASE>
	.GLOBAL	 IOC$RETURN_SUCCESS
	GENRADDR CANCEL,IOC$RETURN_SUCCESS

	ASSUME	DDT$PS_REGDUMP_2  EQ <.-DDT$$BASE>
	.GLOBAL	 IOC$RETURN_SUCCESS
	GENRADDR REGDMP,IOC$RETURN_SUCCESS

	.IF	BLANK,JSB_ALTSTART
	  .GLOBAL  IOC$RETURN_SUCCESS
	  ASSUME   DDT$PS_ALTSTART_2  EQ <.-DDT$$BASE>
	  GENRADDR ALTSTART,IOC$RETURN_SUCCESS
	  ASSUME   DDT$PS_ALTSTART_JSB	EQ <.-DDT$$BASE>
	  .LONG	0
	.IFF
	  $$JSB_ALTSTART = 1
	  .GLOBAL  IOC$RETURN,IOC$ALTSTART_C2J
	  ASSUME   DDT$PS_ALTSTART_2  EQ <.-DDT$$BASE>
	  GENRADDR IOC$ALTSTART_C2J
	  ASSUME   DDT$PS_ALTSTART_JSB	EQ <.-DDT$$BASE>
	  GENRADDR JSB_ALTSTART,IOC$RETURN
	.ENDC

	ASSUME	DDT$PS_MNTVER_2	 EQ <.-DDT$$BASE>
	.GLOBAL	 IOC_STD$MNTVER
	GENRADDR MNTVER,IOC_STD$MNTVER

	ASSUME	DDT$PS_MNTV_SSSC  EQ <.-DDT$$BASE>
	GENRADDR MNTV_SSSC
	ASSUME	DDT$PS_MNTV_FOR	 EQ <.-DDT$$BASE>
	GENRADDR MNTV_FOR
	ASSUME	DDT$PS_MNTV_SQD	 EQ <.-DDT$$BASE>
	GENRADDR MNTV_SQD
	ASSUME	DDT$PS_AUX_STORAGE  EQ <.-DDT$$BASE>
	GENRADDR AUX_STORAGE
	ASSUME	DDT$PS_AUX_ROUTINE  EQ <.-DDT$$BASE>
	GENRADDR AUX_ROUTINE

	ASSUME	DDT$PS_CHANNEL_ASSIGN_2	 EQ <.-DDT$$BASE>
	.GLOBAL	 IOC$RETURN_UNSUPPORTED
	GENRADDR CHANNEL_ASSIGN,IOC$RETURN_UNSUPPORTED

	ASSUME	DDT$PS_CANCEL_SELECTIVE_2  EQ <.-DDT$$BASE>
	.GLOBAL	 IOC$RETURN_UNSUPPORTED
	GENRADDR CANCEL_SELECTIVE,IOC$RETURN_UNSUPPORTED

	ASSUME	DDT$IS_STACK_BCNT  EQ <.-DDT$$BASE>
	.LONG	KP_STACK_SIZE
	ASSUME	DDT$IS_REG_MASK	 EQ <.-DDT$$BASE>
	.LONG	KP_REG_MASK
	ASSUME	DDT$PS_KP_STARTIO  EQ <.-DDT$$BASE>
	GENRADDR KP_STARTIO

	ASSUME	DDT$PS_CSR_MAPPING  EQ <.-DDT$$BASE>
	.GLOBAL	 IOC$RETURN_SUCCESS
	GENRADDR CSR_MAPPING,IOC$RETURN_SUCCESS

        ASSUME  DDT$PS_FAST_FDT EQ <.-DDT$$BASE>
        .IF     BLANK,FAST_FDT
          .LONG 0
        .IFF
          GENRADDR FAST_FDT
        .ENDC

	ASSUME	DDT$PS_PENDING_IO  EQ <.-DDT$$BASE>
	.GLOBAL	 EXE_STD$INSERT_IRP 
	  GENRADDR PENDING_IO,EXE_STD$INSERT_IRP 

	ASSUME	DDT$PS_CUSTOMER EQ <.-DDT$$BASE>
	.ADDRESS 0
	ASSUME	DDT$C_LENGTH  EQ <.-DDT$$BASE>
	.ENDM	DDTAB

;
; DEVICE DRIVER PROLOGUE TABLE
;
; DPTAB -- parameters for days, see macro definition below.
;
	.MACRO	DPTAB	END,		-	; not used in EVMS
			ADAPTER,	-	; Adapter type
			FLAGS=0,	-	; DPT flags
			UCBSIZE,	-	; size of UCB
			UNLOAD=0,	-	; unload routine
			MAXUNITS=8,	-	; max units to configure
			DEFUNITS=1,	-	; default units to configure
			DELIVER=0,	-	; unit delivery routine
			VECTOR=0,	-	; driver-spec address
			NAME,		-	; driver name
			SMP=NO,		-	; not used in EVMS
			DECODE=0,	-	; DECwindows-spec address
			STEP=0,		-	; EVMS driver step number
			IDB_CRAMS=0,	-	; CRAMs allocated on IDB
			UCB_CRAMS=0,	-	; CRAMs allocated on each UCB
			BT_ORDER=0,	-	; Boot-time init ordering control
			IOHANDLES=0,	-	; IOHANDLES needed by driver
			DDT=DDT$$BASE,	-
			STRUC_INIT=DRIVER$STRUC_INIT, -
			STRUC_REINIT=DRIVER$STRUC_REINIT, -
			PSECT=$$$105_PROLOGUE,-
			DPT=DRIVER$DPT


	.IF	DIFFERENT,<STEP>,<2>
	  .ERROR 0 ;DPTAB must declare driver %extract(0,4,<STEP>)=2 ;
	.ENDC

	.IF	DEFINED,$$STEP		;if previously specified
	  .IF NOT_EQUAL,$$STEP-STEP	;  assure this is same value
	    .ERROR $$STEP	;DPTAB %extract(0,4,<STEP>)=STEP conflicts with prior declaration;
	  .ENDC
	.ENDC

	$$STEP = <STEP>

	$DPTDEF
	$SPLCODDEF
	$DSCDEF
	$NAMDEF
	.SAVE
	DRIVER_DATA  PSECT
	.ALIGN	QUAD
'DPT'::

	ASSUME	DPT$PS_FLINK EQ 0
	ASSUME	DPT$PS_BLINK EQ 4
	.LONG	0, 0

	ASSUME	DPT$IW_SIZE  EQ <.-DPT>
	.WORD	DPT$K_BASE_LEN+NAM$C_MAXRSS
	ASSUME	DPT$IB_TYPE  EQ <.-DPT>
	.BYTE	DYN$C_DPT
	.BYTE	0

	ASSUME	DPT$IW_STEP  EQ <.-DPT>
	.WORD	DPT$K_STEP_'STEP'
	ASSUME	DPT$IW_STEPVER	EQ <.-DPT>
	.IF	EQUAL,$$STEP - 2
	  .WORD	DPT$K_STEP2_V5
	.IFF
	  .WORD	DPT$K_STEP1_V2
	.ENDC

	ASSUME	DPT$IW_DEFUNITS	 EQ <.-DPT>
	.WORD	DEFUNITS
	ASSUME	DPT$IW_MAXUNITS	 EQ <.-DPT>
	.WORD	MAXUNITS
	ASSUME	DPT$IW_UCBSIZE	EQ <.-DPT>
	.WORD	UCBSIZE
	ASSUME	DPT$IW_IOHANDLES  EQ <.-DPT>
	.WORD	IOHANDLES
	ASSUME	DPT$IW_IDB_CRAMS  EQ <.-DPT>
	.WORD	IDB_CRAMS
	ASSUME	DPT$IW_UCB_CRAMS  EQ <.-DPT>
	.WORD	UCB_CRAMS

	ASSUME	DPT$IL_FLAGS  EQ <.-DPT>
	.IIF IDN <SMP>,<YES>, ..SMP_FLAG.. = DPT$M_SMPMOD
	.LONG	FLAGS!..SMP_FLAG..

	ASSUME	DPT$IL_ADPTYPE	EQ <.-DPT>
	.LONG	AT$_'ADAPTER'
	ASSUME	DPT$IL_REFC  EQ <.-DPT>
	.LONG	0

	ASSUME	DPT$PS_INIT_PD	EQ <.-DPT>
	.ADDRESS  STRUC_INIT
	ASSUME	DPT$PS_REINIT_PD  EQ <.-DPT>
	.ADDRESS  STRUC_REINIT

	ASSUME	DPT$PS_DELIVER_2  EQ <.-DPT>
	.ADDRESS  DELIVER
	ASSUME	DPT$PS_UNLOAD  EQ <.-DPT>
	.ADDRESS  UNLOAD

	ASSUME	DPT$PS_DDT  EQ <.-DPT>
	.ADDRESS  DDT
	ASSUME	DPT$PS_DDB_LIST	 EQ <.-DPT>
	.LONG	0

	ASSUME	DPT$IS_BTORDER	EQ <.-DPT>
	.LONG	BT_ORDER

	ASSUME	DPT$PS_VECTOR  EQ <.-DPT>
	.ADDRESS  VECTOR

	ASSUME	DPT$T_NAME  EQ <.-DPT>
	$$$=.
	.ASCIC	/NAME/
	.=$$$+DPT$S_NAME

	ASSUME	DPT$IL_ECOLEVEL	 EQ <.-DPT>
	.LONG	0
	ASSUME	DPT$L_UCODE  EQ <.-DPT>
	.LONG	0

	ASSUME	DPT$Q_LINKTIME	EQ <.-DPT>
	.QUAD	0

	ASSUME	DPT$IW_INAME_LEN  EQ <.-DPT>
	.WORD	NAM$C_MAXRSS
	ASSUME	DPT$IB_INAME_TYPE  EQ <.-DPT>
	.BYTE	DSC$K_DTYPE_T
	ASSUME	DPT$IB_INAME_CLASS  EQ <.-DPT>
	.BYTE	DSC$K_CLASS_S
	ASSUME	DPT$PS_INAME_PTR  EQ <.-DPT>
	.ADDRESS  DPT+DPT$T_IMAGE_NAME

	ASSUME	DPT$IL_LOADER_HANDLE  EQ <.-DPT>
	ASSUME	DPT$S_LOADER_HANDLE EQ 16
	.LONG	0,0,0,0

	ASSUME	DPT$L_DECW_SNAME  EQ <.-DPT>
	.ADDRESS  DECODE

	ASSUME	DPT$PS_CUSTOMER EQ <.-DPT>
	.LONG	0

	ASSUME	DPT$K_BASE_LEN	EQ <.-DPT>

	ASSUME	DPT$T_IMAGE_NAME  EQ <.-DPT>
	.BLKB	NAM$C_MAXRSS

	.IIF NDF ..SMP_FLAG.., ..SMP_FLAG.. = 0

	.MDELETE DPTAB
	.ENDM	DPTAB

;
; STORE DPT INITIALIZATION ROUTINE GENERATOR
;
;	DPT_STORE STRUC_TYPE,STRUC_OFFSET,OPERATION,EXPRESSION,POS,SIZE
;
;	STRUC_TYPE = STRUC TYPE CODE (DDB,UCB,CRB,IDB)
;		   = "INIT" IF START OF INIT TABLE
;		   = "REINIT" IF START OF RE-INIT TABLE
;		   = "END" IF END OF RE-INIT TABLE
;	STRUC_OFFSET = UNSIGNED OFFSET INTO STRUC
;	OPERATION = TYPE OF INITIALIZATION OPERATION
;		    B=BYTE,W=WORD,L=LONG,D=RELATIVE TO DRIVER,V=FIELD
;		    IF PRECEDED BY "@" (IE. @B) THEN EXPRESSION
;		    IS ADDRESS OF DATA
;	EXPRESSION = EXPRESSION TO BE STORED
;	POS = BIT POSITION (FOR OPERATION = V ONLY)
;	SIZE = FIELD SIZE (FOR OPERATION = V ONLY)
;
	.MACRO	DPT_STORE STR_TYPE,STR_OFF,OPER,EXP,POS,SIZE,	-
		crb=4,ddb=8,idb=12,orb=16,ucb=20,		-
		letters$$=< #L W B AB(r2)(r3)(r4)(r5)(r6)>
	.IF IDN <STR_TYPE>,<INIT>
op$$=0
lit$$=0
reg$$=0
	DRIVER_CODE
DRIVER$STRUC_INIT:
	.CALL_ENTRY	PRESERVE=<R2,R3,R4,R5,R6>
	MOVL	crb(ap),r2
	MOVL	ddb(ap),r3
	MOVL	idb(ap),r4
	MOVL	orb(ap),r5
	MOVL	ucb(ap),r6
	.IFF
	.IF IDN <STR_TYPE>,<REINIT>
	RET
DRIVER$STRUC_REINIT:
	.CALL_ENTRY	PRESERVE=<R2,R3,R4,R5,R6>
	MOVL	crb(ap),r2
	MOVL	ddb(ap),r3
	MOVL	idb(ap),r4
	MOVL	orb(ap),r5
	MOVL	ucb(ap),r6
	.IFF
	.IF IDN <STR_TYPE>,<END>
	RET
	.RESTORE

	.IFF
crb$$=10
ddb$$=14
idb$$=18
orb$$=22
ucb$$=26
reg$$='str_type'$$
op$$=2
lit$$=1
	.IRPC	C,<OPER>
	.IIF IDN <C>,<@>, lit$$=0
	.IIF IDN <C>,<L>, op$$=2
	.IIF IDN <C>,<W>, op$$=4
	.IIF IDN <C>,<B>, op$$=6
	.IIF IDN <C>,<V>, op$$=-1
	.IIF IDN <C>,<D>, op$$=8
	.IIF IDN <C>,<D>, lit$$=0
	.ENDR
	.IF LT op$$
	INSV	%extract(lit$$,1,letters$$)<'exp'>, -
		#pos, #size, 'str_off'%extract(reg$$,4,letters$$)
	.IFF
	MOV%extract(op$$,2,letters$$)	%extract(lit$$,1,letters$$)<'exp'>, -
		'str_off'%extract(reg$$,4,letters$$)
	.ENDC

	.ENDC
	.ENDC
	.ENDC
	.ENDM	DPT_STORE

;
; Store ISR procedure descriptor and entry point address in
;
;
; DPT_STORE_ISR VEC_OFF,ENTRY
;
;	VEC_OFF - CRB Interrupt transfer vector
;	ENTRY	- Address (label) of .call_entry for ISR
;			  (procedure descriptor)
;
;
	.MACRO	DPT_STORE_ISR VEC_OFF,ENTRY
	$PDSCDEF
	MOVAL 'entry',R0
	MOVL  R0,<<'vec_off'>+VEC$PS_ISR_PD>(R2)
	MOVL  PDSC$Q_ENTRY(R0),<<'vec_off'>+VEC$PS_ISR_CODE>(R2)
	.ENDM	DPT_STORE_ISR


;++
; Setup platform-specific DIPL value in the device UCB.
; This macro is valid only in the contex of a DPT_STORE INIT or REINIT section.
;
; DPT_STORE_DIPL
;--
	.MACRO	DPT_STORE_DIPL
	PUSHL	R6			;param1 = UCB address
	CALLS	#1,IOC$SETUP_UCB_DIPL
	.ENDM	DPT_STORE_DIPL


;++
; Setup a device driver code PSECT
;
; DRIVER_CODE [PSECT-Name]
;
;	PSECT-Name - Optional name of driver code PSECT.  The default is
;		     $$$115_DRIVER.
;--

	.MACRO	DRIVER_CODE -
		PNAME=$$$115_DRIVER,LNAME=$$$115_LINKAGE
	.PSECT	LNAME,5,PIC,CON,REL,LCL,NOSHR,NOEXE,RD,WRT
	.LINKAGE_PSECT LNAME
	.PSECT	'PNAME',5,NOWRT,EXE,PIC
	.ENDM	DRIVER_CODE

;++
; Setup a device driver data PSECT
;
; DRIVER_DATA [PSECT-Name]
;
;	PSECT-Name - Optional name of driver data PSECT.  The default is
;		     $$$110_DATA.
;--

	.MACRO	DRIVER_DATA -
		PNAME=$$$110_DATA
	.PSECT	'PNAME',5,WRT,NOEXE,PIC
	.ENDM	DRIVER_DATA
;++
; Provides standard .CALL_ENTRY and standard AP offsets for the four parameters
; of all Step 2 upper level FDT routines. These offsets are used to move input
; parameters from their offsets from the AP to the commonly used register.
; The default preserve registers are R2-R11.  FETCH=YES is the default and will
; cause the macro to move the AP inputs to the commonly used registers.	 If
; FETCH=NO then the inputs will not be moved.
; This macro is intended for the use by private driver specific upper level FDT
; routines.
;
;  your_upper_level_fdt_routine_name:
;  $DRIVER_FDT_ENTRY	PRESERVE=<R2,R9>, FETCH=YES
;
;--
	.MACRO	$DRIVER_FDT_ENTRY -
		PRESERVE=<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12,R13,R14,R15>, -
		FETCH=YES

	$FDTARGDEF

	$$$USE_PRESERVE = 1
	.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
	.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

	.IF	EQ,$$$USE_PRESERVE-1
	  .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
	.IF_FALSE
	  .CALL_ENTRY
	.ENDC

	.IF	DIFFERENT,FETCH,NO	; Validate FETCH keyword.
	  .IF	DIFFERENT,FETCH,YES	; If not 'NO' and not 'YES' give error.
	    .ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must be either YES or NO;
	  .ENDC
	.ENDC

	.IF IDENTICAL,FETCH,YES
	MOVL	FDTARG$_IRP(AP),R3
	MOVL	FDTARG$_PCB(AP),R4
	MOVL	FDTARG$_UCB(AP),R5
	MOVL	FDTARG$_CCB(AP),R6
	.ENDC

	.ENDM	$DRIVER_FDT_ENTRY
;++
; Provides standard AP offsets for the four parameters of all Step 2 upper
; level FDT routines. These offsets are used to move input parameters from their
; offsets from the AP to a register.
;
;  $FDTARGDEF
;
;--
	.MACRO	$FDTARGDEF

	$OFFDEF	FDTARG,<IRP,PCB,UCB,CCB>

	.ENDM	$FDTARGDEF


;++
;
; CREATE FORK PROCESS
;
; FORK	ROUTINE=fork_routine,CONTINUE=label,RETURN=rsb,ENVIRONMENT=JSB|CALL
;
;	ROUTINE	- is an optional parameter that specifies the name of the fork
;		  routine.  If not specified it is assumed that the fork routine
;		  immediately follows the FORK macro.
;	CONTINUE- is an optional parameter that specifies the label where
;		  execution continues after the fork routine has been queued.
;		  If not specified, control returns to the caller of the routine
;		  that invoked the FORK macro.
;	RETURN -  "Caller's caller" return semantic (RSB - default, or RET)
;	ENVIRONMENT - is an optional keyword that specifies the fork routine
;		  environment as either JSB or CALL.  The default is JSB.
;		  If specified as JSB, then EXE$PRIMITIVE_FORK is called and
;		  a .JSB_ENTRY directive is used to generate the fork routine.
;		  If specified as CALL, then EXE_STD$PRIMITIVE_FORK is called,
;		  the RETURN parameter is ignored and assumed to be RET, a
;		  .CALL_ENTRY directive is used to generate the fork routine,
;		  the FR3, FR4, and FKB parameters in the fork routine are
;		  copied into R3, R4, and R5.
;
; IMPLICIT INPUTS:
;
;	R3	- Arbitrary 64-bit input value for fork routine
;	R4	- Arbitrary 64-bit input value for fork routine
;	R5	- FKB
;
; IMPLICIT OUTPUTS:
;
;    ENVIRONMENT=CALL
;	R0,R1	- Scratched.
;
;    ENVIRONMENT=JSB
;	R3,R4	- Outputs of EXE$PRIMITIVE_FORK.
;
;--
	.MACRO	FORK	ROUTINE,CONTINUE,RETURN=RSB,ENVIRONMENT=JSB,?L1

	$FKBDEF

	.IF	DIFFERENT,ENVIRONMENT,JSB	;validate environment keyword
	  .IF	DIFFERENT,ENVIRONMENT,CALL
	    .ERROR 0 ;Keyword %EXTRACT(0,11,<ENVIRONMENT>) must be either CALL or JSB;
	  .ENDC
	.ENDC

	.IF	BLANK,<ROUTINE>
	  MOVAB	L1,FKB$L_FPC(R5)
	.IF_FALSE
	  MOVAB	ROUTINE,FKB$L_FPC(R5)
	.ENDC

	.IF	IDENTICAL,ENVIRONMENT,CALL

	  .GLOBAL EXE_STD$PRIMITIVE_FORK
	  EVAX_OR R31,R3,R16		;R16 (P1) = full 64-bits of R3
	  EVAX_OR R31,R4,R17		;R17 (P2) = full 64-bits of R4
	  PUSHL	R5			;P3 = FKB
	  PUSHL	R17			;P2 = full 64-bits of R4
	  PUSHL	R16			;P1 = full 64-bits of R3
	  CALLS	#3,EXE_STD$PRIMITIVE_FORK

	  .IF	BLANK,<CONTINUE>
	    RET
	  .IF_FALSE
	    BRW	CONTINUE
	  .ENDC

	  .IF	BLANK,<ROUTINE>
L1:	    .CALL_ENTRY	INPUT=<R16,R17>,PRESERVE=<R3,R4,R5>

	    $OFFDEF	FORKARG,<FR3,FR4,FKB>

	    ASSUME	FORKARG$_FR3 EQ <1*4>
	    ASSUME	FORKARG$_FR4 EQ <2*4>
	    EVAX_OR	R31,R16,R3		;R3 = full 64-bits of FORKARG$_FR3
	    EVAX_OR	R31,R17,R4		;R4 = full 64-bits of FORKARG$_FR4
	    MOVL	FORKARG$_FKB(AP),R5	;R5 = FKB

	  .ENDC

	.IF_FALSE	;IDENTICAL,ENVIRONMENT,CALL

	  .GLOBAL	EXE$PRIMITIVE_FORK
	  .SET_REGISTERS	-
		READ	= <R3,R4,R5>,-
		WRITTEN	= <R3,R4>
	  JSB	G^EXE$PRIMITIVE_FORK

	  .IF	BLANK,<CONTINUE>
	    RETURN
	  .IF_FALSE
	    BRW	CONTINUE
	  .ENDC

	  .IF	BLANK,<ROUTINE>
L1:	    .JSB_ENTRY	INPUT=<R3,R4,R5>,SCRATCH=<R0,R1,R2,R3,R4>
	  .ENDC

	.ENDC		;IDENTICAL,ENVIRONMENT,CALL

	.ENDM	FORK

;++
;
; FORK ROUTINE ENTRY POINT DECLARATION
;
; FORK_ROUTINE	NAME=fork_routine_name, SYMBOL=LOCAL|GLOBAL,
;		ENVIRONMENT=JSB|CALL,FETCH=YES|NO
;
;	NAME	- is an optional parameter that specifies the name of the fork
;		  routine.
;	SYMBOL	- is an optional keyword that specifies if the routine name
;		  should be declared as a local or global symbol.  The default
;		  is for a local symbol.
;	ENVIRONMENT - is an optional keyword that specifies the fork routine
;		  environment as either JSB or CALL.  If specified as JSB,
;		  then a .JSB_ENTRY directive is used to for the fork routine.
;		  If specified as CALL, then a .CALL_ENTRY directive is used to
;		  for the fork routine.	 The default is JSB.
;	FETCH	- is an optional YES/NO parameter that specifies if the fork
;		  routine parameters for an ENVIRONMENT=CALL fork routine
;		  should be copied into the traditional R3. R4. and R5 registers.
;		  The default is YES.
;
;--
	.MACRO	FORK_ROUTINE	NAME,SYMBOL=LOCAL,ENVIRONMENT=JSB,FETCH=YES

	.IF	DIFFERENT,SYMBOL,GLOBAL		;validate SYMBOL keyword
	  .IF	DIFFERENT,SYMBOL,LOCAL
	    .ERROR 0 ;Keyword %EXTRACT(0,6,<SYMBOL>) must be either LOCAL or GLOBAL;
	  .ENDC
	.ENDC

	.IF	DIFFERENT,ENVIRONMENT,JSB	;validate ENVIRONMENT keyword
	  .IF	DIFFERENT,ENVIRONMENT,CALL
	    .ERROR 0 ;Keyword %EXTRACT(0,11,<ENVIRONMENT>) must be either CALL or JSB;
	  .ENDC
	.ENDC

	.IF	DIFFERENT,FETCH,YES		;validate FETCH keyword
	  .IF	DIFFERENT,FETCH,NO
	    .ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
	  .ENDC
	.ENDC


	.IF	NOT_BLANK,<NAME>		;define routine name
	.IF	IDENTICAL,SYMBOL,GLOBAL
NAME::
	.IF_FALSE
NAME:
	.ENDC
	.ENDC
	.IF	IDENTICAL,ENVIRONMENT,CALL
						;declare CALL entry point
	  .CALL_ENTRY	INPUT=<R16,R17>
	  $OFFDEF	FORKARG,<FR3,FR4,FKB>	;define parameter offsets
	  .IF	IDENTICAL,FETCH,YES
	    ASSUME	FORKARG$_FR3 EQ <1*4>
	    EVAX_OR	R31,R16,R3		;R3 = full 64-bits of P1 (R16)
	    ASSUME	FORKARG$_FR4 EQ <2*4>
	    EVAX_OR	R31,R17,R4		;R4 = full 64-bits of P2 (R17)
	    MOVL	FORKARG$_FKB(AP),R5	;R5 = FKB
	  .ENDC

	.IF_FALSE	;IDENTICAL,ENVIRONMENT,CALL
						;declare JSB entry point
	  .JSB_ENTRY	INPUT=<R3,R4,R5>,SCRATCH=<R0,R1,R2,R3,R4>

	.ENDC		;IDENTICAL,ENVIRONMENT,CALL

	.ENDM	FORK_ROUTINE

;++
;
; FORK AND WAIT (for from 0 to 1 seconds)
;
; FORK_WAIT  ROUTINE=fork_routine,CONTINUE=label,RETURN=rsb,ENVIRONMENT=JSB|CALL
;
;	ROUTINE	- is an optional parameter that specifies the name of the fork
;		  routine.  If not specified it is assumed that the fork routine
;		  immediately follows the FORK_WAIT macro.
;	CONTINUE- is an optional parameter that specifies the label where
;		  execution continues after the fork routine has been queued.
;		  If not specified, control returns to the caller of the routine
;		  that invoked the FORK_WAIT macro.
;	RETURN -  "Caller's caller" return semantic (RSB - default, or RET)
;	ENVIRONMENT - is an optional keyword that specifies the fork routine
;		  environment as either JSB or CALL.  The default is JSB.
;		  If specified as JSB, then EXE$PRIMITIVE_FORK_WAIT is called
;		  and a .JSB_ENTRY directive is used to generate the fork
;		  routine.
;		  If specified as CALL, then EXE_STD$PRIMITIVE_FORK_WAIT is
;		  called, the RETURN parameter is ignored and assumed to be RET,
;		  a .CALL_ENTRY directive is used to generate the fork routine,
;		  the FR3, FR4, and FKB parameters in the fork routine are
;		  copied into R3, R4, and R5.
;
; IMPLICIT INPUTS:
;
;	R3	- Arbitrary 64-bit input value for fork routine
;	R4	- Arbitrary 64-bit input value for fork routine
;	R5	- FKB
;
; IMPLICIT OUTPUTS:
;
;    ENVIRONMENT=CALL
;	R0,R1	- Scratched.
;
;    ENVIRONMENT=JSB
;		- All register preserved, including R0,R1
;
;--
	.MACRO	FORK_WAIT	ROUTINE,CONTINUE,RETURN=RSB,ENVIRONMENT=JSB,?L1

	$FKBDEF

	.IF	DIFFERENT,ENVIRONMENT,JSB	;validate environment keyword
	  .IF	DIFFERENT,ENVIRONMENT,CALL
	    .ERROR 0 ;Keyword %EXTRACT(0,11,<ENVIRONMENT>) must be either CALL or JSB;
	  .ENDC
	.ENDC

	.IF	BLANK,<ROUTINE>
	  MOVAB	L1,FKB$L_FPC(R5)
	.IF_FALSE
	  MOVAB	ROUTINE,FKB$L_FPC(R5)
	.ENDC

	.IF	IDENTICAL,ENVIRONMENT,CALL

	  .GLOBAL EXE_STD$PRIMITIVE_FORK_WAIT
	  EVAX_OR R31,R3,R16		;R16 (P1) = full 64-bits of R3
	  EVAX_OR R31,R4,R17		;R17 (P2) = full 64-bits of R4
	  PUSHL	R5			;P3 = FKB
	  PUSHL	R17			;P2 = full 64-bits of R4
	  PUSHL	R16			;P1 = full 64-bits of R3
	  CALLS	#3,EXE_STD$PRIMITIVE_FORK_WAIT

	  .IF	BLANK,<CONTINUE>
	    RET
	  .IF_FALSE
	    BRW	CONTINUE
	  .ENDC

	  .IF	BLANK,<ROUTINE>
L1:	    .CALL_ENTRY	INPUT=<R16,R17>,PRESERVE=<R3,R4,R5>

	    $OFFDEF	FORKARG,<FR3,FR4,FKB>

	    ASSUME	FORKARG$_FR3 EQ <1*4>
	    ASSUME	FORKARG$_FR4 EQ <2*4>
	    EVAX_OR	R31,R16,R3		;R3 = full 64-bits of FORKARG$_FR3
	    EVAX_OR	R31,R17,R4		;R4 = full 64-bits of FORKARG$_FR4
	    MOVL	FORKARG$_FKB(AP),R5	;R5 = FKB

	  .ENDC

	.IF_FALSE	;IDENTICAL,ENVIRONMENT,CALL

	  .GLOBAL	EXE$PRIMITIVE_FORK_WAIT
	  .SET_REGISTERS	-
		READ	= <R3,R4,R5>
	  JSB	G^EXE$PRIMITIVE_FORK_WAIT

	  .IF	BLANK,<CONTINUE>
	    RETURN
	  .IF_FALSE
	    BRW	CONTINUE
	  .ENDC

	  .IF	BLANK,<ROUTINE>
L1:	    .JSB_ENTRY	INPUT=<R3,R4,R5>,SCRATCH=<R0,R1,R2,R3,R4>
	  .ENDC

	.ENDC		;IDENTICAL,ENVIRONMENT,CALL

	.ENDM	FORK_WAIT

;++
;
; CREATE I/O DRIVER FORK PROCESS
;
; IOFORK is very similar to FORK with the following differences: (1) The fork
; block address in R5 is assumed to be a UCB; (2) The UCB$M_TIM bit is cleared;
; (3) ordinary FORK is invoked.
;
; IOFORK  ROUTINE=fork_routine,CONTINUE=label,RETURN=rsb,ENVIRONMENT=JSB|CALL
;
;	ROUTINE	- is an optional parameter that specifies the name of the fork
;		  routine.  If not specified it is assumed that the fork routine
;		  immediately follows the IOFORK macro.
;	CONTINUE- is an optional parameter that specifies the label where
;		  execution continues after the fork routine has been queued.
;		  If not specified, control returns to the caller of the routine
;		  that invoked the IOFORK macro.
;	RETURN -  "Caller's caller" return semantic (RSB - default, or RET)
;	ENVIRONMENT - is an optional keyword that specifies the fork routine
;		  environment as either JSB or CALL.  The default is JSB.
;		  If specified as JSB, then EXE$PRIMITIVE_FORK is called and
;		  a .JSB_ENTRY directive is used to generate the fork routine.
;		  If specified as CALL, then EXE_STD$PRIMITIVE_FORK is called,
;		  the RETURN parameter is ignored and assumed to be RET, a
;		  .CALL_ENTRY directive is used to generate the fork routine,
;		  the FR3, FR4, and FKB parameters in the fork routine are
;		  copied into R3, R4, and R5.
;
; IMPLICIT INPUTS:
;
;	R3	- Arbitrary 64-bit input value for fork routine
;	R4	- Arbitrary 64-bit input value for fork routine
;	R5	- UCB
;
; IMPLICIT OUTPUTS:
;
;    ENVIRONMENT=CALL
;	R0,R1	- Scratched.
;
;    ENVIRONMENT=JSB
;	R3,R4	- Outputs of EXE$PRIMITIVE_FORK.
;
;--
	.MACRO	IOFORK	ROUTINE,CONTINUE,RETURN=RSB,ENVIRONMENT=JSB

	$FKBDEF					; Define fork block symbols
	$UCBDEF					; Define UCB symbols

	ASSUME	UCB$Q_FR3	EQ FKB$Q_FR3
	ASSUME	UCB$Q_FR4	EQ FKB$Q_FR4
	ASSUME	UCB$L_FPC	EQ FKB$L_FPC

; Disable timeouts in the UCB and fork normally

	BICL	#UCB$M_TIM,UCB$L_STS(R5)
	FORK	ROUTINE,CONTINUE,RETURN,ENVIRONMENT

	.ENDM	IOFORK

;
; Function Decision Table Macro Definitions
; These definitions implement the STEP 2 FDT format.
;
; The FDT_INI macro clears the buffered function mask
; to zero and points each slot in the action vector at
; EXE$ILLIOFUNC.
;
	.MACRO	FDT_INI	FDT=DRIVER$FDT
	$FDTDEF
	DRIVER_DATA
	$$DEFH = 0
	$$DEFL = 0
	.ALIGN	QUAD
FDT$$START = .
'FDT'::
	ASSUME	FDT$Q_BUFFERED EQ .-FDT$$START
	.LONG	0,0
	ASSUME	FDT$PS_FUNC_RTN EQ .-FDT$$START
	.GLOBAL EXE$ILLIOFUNC
	.REPEAT -
		1 @ IO$S_FCODE
	.ADDRESS -
		EXE$ILLIOFUNC
	.ENDR
	ASSUME	FDT$Q_OK64BIT EQ .-FDT$$START
	.LONG	0,0
        ASSUME	FDT$K_LENGTH EQ .-FDT$$START
	.ENDM	FDT_INI

;
; The FDT_BUF macro builds the buffered function mask
; from the function codes values passed in the CODES
; parameter.  Note that the function code is AND'ed with
; IO$_VIRTUAL (63) to ensure that it stays within the
; range of the initialized action vector.
;
	.MACRO	FDT_BUF CODES
	.IF	NOT_DEFINED, FDT$$START
	  FDT_INI
	.ENDC
	.SAVE
	DRIVER_DATA
	$$BUFH = 0
	$$BUFL = 0
	.IRP	X, <CODES>
	  .IF	  GREATER, <IO$_'X & IO$_VIRTUAL> - 31
	    $$BUFH = $$BUFH ! <1 @ <<IO$_'X & IO$_VIRTUAL> - 32>>
	  .IF_FALSE
	    $$BUFL = $$BUFL ! <1 @ <IO$_'X & IO$_VIRTUAL>>
	  .ENDC
	.ENDR
	. = FDT$$START + FDT$Q_BUFFERED
	.LONG	$$BUFL,$$BUFH
	.RESTORE
	.ENDM	FDT_BUF

;
; The FDT_ACT macro definition builds the action vector.
; The slot corresponding to each code in the CODES parameter is
; set to the routine address specified in the ACTION parameter.
;
	.MACRO	FDT_ACT ACTION,CODES
	.IF	NOT_DEFINED, FDT$$START
	  FDT_INI
	.ENDC
	.SAVE
	DRIVER_DATA
	.IRP	X, <CODES>
	  .IF	  GREATER, <IO$_'X & IO$_VIRTUAL> - 31
	    .IF	  NOT_EQUAL, $$DEFH & <1 @ <<IO$_'X & IO$_VIRTUAL> - 32>>
	      .ERROR 0 ; Multiple actions defined for function IO$_'X ;
	    .IF_FALSE
	      $$DEFH   = $$DEFH !< 1 @ <<IO$_'X & IO$_VIRTUAL> - 32>>
	      . = FDT$$START + FDT$PS_FUNC_RTN + <4 * <IO$_'X & IO$_VIRTUAL>>
	      .ADDRESS ACTION
	    .ENDC
	  .IF_FALSE
	    .IF	  NOT_EQUAL, $$DEFL & <1 @ <IO$_'X & IO$_VIRTUAL>>
	      .ERROR 0 ; Multiple actions defined for function IO$_'X ;
	    .IF_FALSE
	      $$DEFL = $$DEFL ! <1 @ <IO$_'X & IO$_VIRTUAL>>
	      . = FDT$$START + FDT$PS_FUNC_RTN + <4 * <IO$_'X & IO$_VIRTUAL>>
	      .ADDRESS ACTION
	    .ENDC
	  .ENDC
	.ENDR
	.RESTORE
	.ENDM	FDT_ACT
;
; The FDT_64 macro builds the 64-bit functions mask
; from the function codes values passed in the CODES
; parameter.  Note that the function code is AND'ed with
; IO$_VIRTUAL (63) to ensure that it stays within the
; range of the initialized action vector.
;
	.MACRO	FDT_64 CODES
	.IF	NOT_DEFINED, FDT$$START
	  FDT_INI
	.ENDC
	.SAVE_PSECT
	DRIVER_DATA
	$$OK64H = 0
	$$OK64L = 0
	.IRP	X, <CODES>
	  .IF	  GREATER, <IO$_'X & IO$_VIRTUAL> - 31
	    $$OK64H = $$OK64H ! <1 @ <<IO$_'X & IO$_VIRTUAL> - 32>>
	  .IF_FALSE
	    $$OK64L = $$OK64L ! <1 @ <IO$_'X & IO$_VIRTUAL>>
	  .ENDC
	.ENDR
	. = FDT$$START + FDT$Q_OK64BIT
	.LONG	$$OK64L,$$OK64H
	.RESTORE_PSECT
	.ENDM	FDT_64
;
;
; Obsolete STEP=1 function table entry macro
;
	.MACRO	FUNCTAB ACTION,CODES
	.ERROR	0 ;FUNCTAB is an obsolete macro used by STEP=1 drivers;
	.PRINT	0 ;Use FDT_INI, FDT_BUF, and FDT_ACT instead;
	.ENDM

;
; GENERATE ADDRESS FOR DRIVER DISPATCH AND FUNCTION DECISION TABLES
;
; GENRADDR ADDRESS,DEFAULT
;
; Note that DEFAULT is set to IOC$RETURN to preserve existing
; behavior.
;
	.MACRO	GENRADDR ADDRESS,DEFAULT=IOC$RETURN
	.IF IDENTICAL	<Address>,<0>
	.ADDRESS	DEFAULT
	.IFF
	.ADDRESS	ADDRESS
	.ENDC
	.ENDM	GENRADDR



;
; I/O REQUEST COMPLETE
;
; REQCOM	RETURN=rsb,ENVIRONMENT=JSB|CALL
;
;	RETURN -  "Caller's caller" return semantic (RSB - default, or RET)
;	ENVIRONMENT - is an optional keyword that specifies the caller's
;		  environment as either JSB or CALL.  The default is JSB.
;		  If specified as JSB, then the RETURN parameter is used.
;
; IMPLICIT INPUTS:
;
;	R0	- First longword of I/O status by value
;	R1	- Second longword of I/O status by value
;	R5	- Unit Control Block
;
; IMPLICIT OUTPUTS:
;
;	R0,R1	- Scratched
;

	.MACRO	REQCOM	RETURN=RSB,ENVIRONMENT=JSB

	.IF	DIFFERENT,ENVIRONMENT,JSB	;validate environment keyword
	  .IF	DIFFERENT,ENVIRONMENT,CALL
	    .ERROR 0 ;Keyword %EXTRACT(0,11,<ENVIRONMENT>) must be either CALL or JSB;
	  .ENDC
	.ENDC

	CALL_REQCOM		;ioc_std$reqcom (iost1=r0,iost2=r1,ucb=r5)

	.IF	IDENTICAL,ENVIRONMENT,CALL
	  RET			;return to caller
	.IF_FALSE
	  RETURN		;return to caller
	.ENDC

	.ENDM	REQCOM

;
; RELEASE ALL CHANNELS
;
; RELCHAN
;
; IMPLICIT INPUTS:
;
;	R5	- Unit Control Block
;
; IMPLICIT OUTPUTS:
;
;	R0,R1	- Scratched
;

	.MACRO	RELCHAN
	CALL_RELCHAN		;ioc_std$relchan (ucb=r5)
	.ENDM	RELCHAN


;++
;
; REQUEST CHANNEL
;
; REQCHAN PRI=LOW|HIGH,ENVIRONMENT=JSB|CALL
;
;	PRI	- if identical to the string HIGH, then IOC$PRIMITIVE_REQPCHANH
;		  is called, otherwise IOC$PRIMITIVE_REQPCHANL is called
;	ENVIRONMENT - is an optional keyword that specifies the callers and
;		  grant routine environment as either JSB or CALL.  The default
;		  is JSB.  If specified as JSB, then an RSB is used to return
;		  from the current routine if the channel is not granted
;		  immediately and a .JSB_ENTRY directive is used to generate
;		  the grant routine.  If specified as CALL, then an RET is used
;		  to return from the current routine if the channel is not
;		  granted immediately, a .CALL_ENTRY directive is used to
;		  generate the grant routine, and the grant routine parameters
;		  are copied into R3, R4, and R5.
;
; IMPLICIT INPUTS:
;
;	R5	- UCB address
;	R3	- Passed on to channel grant fork routine, if called.
;
; IMPLICIT OUTPUTS:
;
;	R4	- Contains the IDB address.
;	R0,R1	- Scratched
;--

	.MACRO	REQCHAN PRI=LOW,ENVIRONMENT=JSB,?L1,?L2

	.IF	DIFFERENT,PRI,LOW		;validate PRI keyword
	  .IF	DIFFERENT,PRI,HIGH
	    .ERROR 0 ;Keyword %EXTRACT(0,3,<PRI>) must be either LOW or HIGH;
	  .ENDC
	.ENDC

	.IF	DIFFERENT,ENVIRONMENT,JSB	;validate ENVIRONMENT keyword
	  .IF	DIFFERENT,ENVIRONMENT,CALL
	    .ERROR 0 ;Keyword %EXTRACT(0,11,<ENVIRONMENT>) must be either CALL or JSB;
	  .ENDC
	.ENDC

	$UCBDEF
	MOVAB	L1,UCB$L_FPC(R5)	;store grant routine address in UCB

	SUBL	#4,SP			;allocate space for returned IDB pointer
	PUSHAB	(SP)			;P3 = pointer to IDB pointer
	PUSHL	R5			;P2 = UCB
	PUSHL	R3			;P1 = IRP

	.IF	IDENTICAL,PRI,HIGH
	.GLOBAL	IOC_STD$PRIMITIVE_REQCHANH
	CALLS	#3,G^IOC_STD$PRIMITIVE_REQCHANH
	.IF_FALSE
	.GLOBAL	IOC_STD$PRIMITIVE_REQCHANL
	CALLS	#3,G^IOC_STD$PRIMITIVE_REQCHANL
	.ENDC

	POPL	R4			;R4 = IDB for return
	BLBS	R0,L2			;if not granted then return

	.IF	IDENTICAL,ENVIRONMENT,CALL

	  RET

L1:	  .CALL_ENTRY	PRESERVE=<R3,R4,R5>

	  $OFFDEF	ARG,<IRP,IDB,UCB>

	  MOVL	ARG$_IRP(AP),R3		;R3 = IRP
	  MOVL	ARG$_IDB(AP),R4		;R4 = IDB
	  MOVL	ARG$_UCB(AP),R5		;R5 = UCB

	.IF_FALSE	;IDENTICAL,ENVIRONMENT,CALL

	  RSB

L1:	  .JSB_ENTRY	INPUT=<R3,R4,R5>,SCRATCH=<R0,R1,R2,R3,R4>

	.ENDC		;IDENTICAL,ENVIRONMENT,CALL
L2:

	.ENDM	REQCHAN

;++
;
; REQUEST PRIMARY CHANNEL
;
; REQPCHAN PRI
;
; This is equivalent to REQCHAN.  Please consult the description of REQCHAN.
;
;--
	.MACRO	REQPCHAN PRI,ENVIRONMENT
	REQCHAN PRI,ENVIRONMENT
	.ENDM	REQPCHAN


;++
; TIMEWAIT - obsolete, use TIMEDWAIT
;--

	.MACRO	TIMEWAIT  TIME,BITVAL,SOURCE,CONTEXT,SENSE
.ERROR	; TIMEWAIT is obsolete - use TIMEDWAIT;
	.ENDM

;++
;
; TIMEDWAIT - Timed Wait Loop with Imbedded Tests
;
; Macro to wait for a specified interval of time. Instructions that test for
; various exit conditions may be imbedded within the wait loop, if so desired.
;
; INPUTS:
;
;	TIME - the number of 10 micro-second intervals to wait
;	INS1 - first instruction to imbed within wait loop
;	INS2 - second instruction to imbed within wait loop
;	INS3 - third instruction to imbed within wait loop
;	INS4 - fourth instruction to imbed within wait loop
;	INS5 - fifth instruction to imbed within wait loop
;	INS6 - sixth instruction to imbed within wait loop
;	DONELBL - label for exit from wait loop
;	IMBEDLBL - Label for beginning of user supplied instructions
;	UBLBL - Label for end of user supplied instructions
;	NSEC  - Number of nanoseconds to wait before timeout (cannot be used
;			with TIME parameter)
;	BUS   - Address of ADP if a bus specific delay is required
;	USERINS - list of user instructions.  Allows use of more than 6
;		instructions.  For example, USERINS=<<MOVL #1,R0>,<MOVL R5,R8>>
;
; OUTPUTS:
;
;	R0 - indicates success or failure status.  Success is defined as
;		not timing out.	 Note that the status of SS$_NORMAL is preloaded
;		into R0, but that the user instructions may overwrite this.
;		Also note that the SS$_TIMEOUT status from the the
;		EXE$TIMEDWAIT_COMPLETE call cannot be overwritten by the user
;		code.
;	R1 - destroyed, all other registers preserved.
;
;--
	.MACRO	TIMEDWAIT TIME,INS1,INS2,INS3,INS4,INS5,INS6,DONELBL,?IMBEDLBL,UBLBL,NSEC,BUS,USERINS,?L1

; Stack usage:
;
; ^		+------------------------+
; | stack	|	Addr(Delta_Time) | <- call argument #1
; | growth	+------------------------+
;		|	Addr(End_Time)	 | <- call argument #2
;		+------------------------+
;		|	Addr(End_Time)	 | <- saved ptr for later copying
;		+------------------------+
;		|			 | <- potential spare longword
;		+------------------------+
;	new SP->|			 | <- R1 (quad aligned)
;		+-	Delta time	-+
;		|			 |
;		+------------------------+
;		|			 | <- 8(R1)
;		+-	End Time	-+
;		|			 |
;		+------------------------+
;	SP->	|			 |
;		.			 .
;		.			 .
;		.			 .
;

; First, quadword align the stack, handling arbitrary stack alignment

	SUBL2	#^X18,SP		; Make space for 2 quad aligned items
	ADDL3	#7,SP,R1		; Round up SP, place into R1
	BICL2	#7,R1			; Compute quad aligned base

	PUSHAB	8(R1)			; Spare copy of END_VALUE address

.IF NOT_BLANK, NSEC
.NTYPE $$$ARGTYPE, NSEC
.IF EQ <$$$ARGTYPE @ -4> - 5		; If NSEC parameter is specified as
	EVAX_STQ NSEC,(R1)		; a register, then do a STQ directly.
.IFF					; Otherwise do a LDQ/STQ sequence.
	EVAX_LDQ R0,NSEC		; Fetch the delta time
	EVAX_STQ R0,(R1)		; Save the delta time
.ENDC
.ENDC

.IF NOT_BLANK, TIME
  .IIF NOT_BLANK, NSEC, .ERROR ; TIMEDWAIT: MULTIPLE TIMING PARAMETERS SPECIFIED
	MOVL	TIME,R0			; Load 10 microsecond count into R0
	EVAX_MULQ #10000,R0,R0		; Compute nanoseconds (10 * 1000 per 10 usec)
	EVAX_STQ R0,(R1)		; Save the delta time
.ENDC
	PUSHAQ	8(R1)			; Place argument #2 (END_VALUE addr)
	PUSHAQ	(R1)			; "	"	 #1 (DELTA addr)
	CALLS	#2,G^EXE$TIMEDWAIT_SETUP; Set up end value
	BLBC	R0,L1			; Just exit on error

; Imbedded label and user specified instructions
;	First, set up the INS<n> instructions for the existing invocations
;	Then, add the USERINS instruction list.

IMBEDLBL:
	'INS1'
	'INS2'
	'INS3'
	'INS4'
	'INS5'
	'INS6'

.IF NOT_BLANK, <USERINS>
	.IRP	INST,<USERINS>
	INST
	.ENDR
.ENDC

.IIF NOT_BLANK, UBLBL, UBLBL:		; Label at end of user instructions

; Add bus specific delay, if requested

	.IF NOT_BLANK, BUS
	PUSHL	BUS			; Save ADP address
	CALLS	#1,G^EXE$BUS_DELAY	; Adapter specific delay
	.ENDC

; End of loop test - check for completion (timeout)

	PUSHL	(SP)			; Copy END_VALUE pointer
	CALLS	#1,G^EXE$TIMEDWAIT_COMPLETE ; Check for completion
	BLBS	R0,IMBEDLBL		; Loop if not yet done

; Exit point - clean up the stack

.IIF NOT_BLANK, DONELBL, DONELBL:	; Termination label for exits

L1:	ADDL2	#<^X18+4>,SP		; Restore SP
	.ENDM TIMEDWAIT

;++
;
; TIMEDELAY - Delay for a specific amount of time
;
;	TIMEDELAY TIME
;
;	TIME	- number of nanoseconds to delay (quadword)
;
;--


	.MACRO	TIMEDELAY	TIME
	SUBL2	#^X10,SP		; Make space for 1 quad aligned item
	ADDL3	#7,SP,R0		; Round up SP, place into R1
	BICL2	#7,R0			; Compute quad aligned base
	EVAX_STQ	TIME,(R0)	; Store the delay time
	PUSHL	R0			; Point to the delay time
	CALLS	#1,G^EXE$DELAY		; Execute the delay
	ADDL2	#^X10,SP		; Restore the stack
	.ENDM

;++
;
; WAITFOR INTERRUPT OR TIMEOUT AND KEEP CHANNEL
;
; WFIKPCH EXCPT,TIME,NEWIPL,RETURN=rsb,ENVIRONMENT=JSB|CALL,TOUTROUT
;
;	EXCPT	- label of the timeout handling code within the interupt context
;		  routine that follows the WFIKPCH macro.
;	TIME	- timeout value in seconds.  This value is loaded into R1 before
;		  calling IOC_STD$PRIMITIVE_WFIKPCH.
;	NEWIPL	- specifies the new IPL that is set on return from
;		  IOC_STD$PRIMITIVE_WFIKPCH.  This value is loaded into R2
;		  before calling IOC_STD$PRIMITIVE_WFIKPCH.
;	RETURN -  "Caller's caller" return semantic (RSB - default, or RET)
;	ENVIRONMENT - is an optional keyword that specifies the current and
;		  resume routine environment as either JSB or CALL. The default
;		  is JSB.  If specified as JSB, then the RETURN parameter is
;		  used to generate a returns from the current routine and a
;		  .JSB_ENTRY directive is used to generate the resume routine.
;		  If specified as CALL, then the RETURN parameter is ignored
;		  and assumed to be RET, a .CALL_ENTRY directive is used to
;		  generate the resume routine, the IRP, FR4, and UCB parameters
;		  in the resume routine are copied into R3, R4, and R5.
;	TOUTROUT - is an optional parameter that specifies the timeout routine
;		  entry point which can be either a CALL or JSB entry point.
;		  If not specified then the resume routine entry point is also
;		  used as the timeout routine entry point.  This paramter can
;		  not be specified together with the EXCPT parameter.
;
; IMPLICIT INPUTS:
;
;	R3	- IRP pointer, passed on to fork routine
;	R4	- Passed on to fork routine, full 64-bits
;	R5	- UCB address
;
; IMPLICIT OUTPUTS:
;
;	R0,R1,R2 - Scratched
;
;--
	.MACRO	WFIKPCH EXCPT,TIME,NEWIPL=(SP)+,RETURN=RSB,ENVIRONMENT=JSB,-
			TOUTROUT,?L1

	.IF	DIFFERENT,ENVIRONMENT,JSB	;validate ENVIRONMENT keyword
	  .IF	DIFFERENT,ENVIRONMENT,CALL
	    .ERROR 0 ;Keyword %EXTRACT(0,11,<ENVIRONMENT>) must be either CALL or JSB;
	  .ENDC
	.ENDC

	.IF	NOT_BLANK,TOUTROUT		;disallow both EXCPT, TOUTROUT
	  .IF	NOT_BLANK,EXCPT
	    .ERROR 0 ;%EXTRACT(0,5,<EXCPT>) label and %EXTRACT(0,5,<TOUTROUT>) routine disallowed together;
	  .ENDC
	.ENDC

	$UCBDEF

	.IF	BLANK,TIME
	  ASHL	#16,#1,R1
	.IF_FALSE
	  .IF	DIFFERENT,<TIME>,<R1>
	    MOVL TIME,R1
	  .ENDC
	.ENDC

	.IF	IDENTICAL,<NEWIPL>,<R1>
	  .ERROR 0 ;Usage of R1 as %EXTRACT(0,6,<NEWIPL>) conflicts with R1 parameter to IOC$PRIMITIVE_WFIKPCH;
	.ENDC

	.IF	DIFFERENT,<NEWIPL>,<R2>
	  MOVL	NEWIPL,R2
	.ENDC

	MOVAB	L1,UCB$L_FPC(R5)	;setup fork routine address

	.IF	NOT_BLANK,TOUTROUT	;setup timeout routine address
	  MOVAB	TOUTROUT,UCB$PS_TOUTROUT(R5)
	.IF_FALSE
	  MOVAB	L1,UCB$PS_TOUTROUT(R5)
	.ENDC

	.GLOBAL	IOC_STD$PRIMITIVE_WFIKPCH
	EVAX_OR	R31,R4,R17		;R17 (P2) = full 64-bits of R4
	PUSHL	R2			;P5 = restore_ipl
	PUSHL	R1			;P4 = time out value
	PUSHL	R5			;P3 = UCB
	PUSHL	R17			;P2 = full 64-bits of R4
	PUSHL	R3			;P1 = IRP
	CALLS	#5,IOC_STD$PRIMITIVE_WFIKPCH

	.IF	IDENTICAL,ENVIRONMENT,CALL

	  RET

L1:	  .CALL_ENTRY	INPUT=<R17>,PRESERVE=<R3,R4,R5>

	  $OFFDEF	ARG,<IRP,FR4,UCB>	;define parameter offsets

	  MOVL	ARG$_IRP(AP),R3		;R3 = IRP
	  ASSUME	ARG$_FR4 EQ <2*4>
	  EVAX_OR	R31,R17,R4	;R4 = full 64-bits of P2 (R17)
	  MOVL	ARG$_UCB(AP),R5		;R5 = UKB

	.IF_FALSE	;IDENTICAL,ENVIRONMENT,CALL

	  RETURN

L1:	  .JSB_ENTRY	INPUT=<R3,R4,R5>,SCRATCH=<R0,R1,R2,R3,R4>

	.ENDC		;IDENTICAL,ENVIRONMENT,CALL

	.IF	NOT_BLANK,EXCPT
	  BITL	#UCB$M_TIMOUT,UCB$L_STS(R5)
	  BNEQ	EXCPT
	.ENDC

	.ENDM	WFIKPCH

;+
;
; WAITFOR INTERRUPT OR TIMEOUT AND RELEASE CHANNEL
;
; WFIRLCH EXCPT,TIME,NEWIPL,RETURN=rsb,ENVIRONMENT=JSB|CALL,TOUTROUT
;
;	EXCPT	- label of the timeout handling code within the interupt context
;		  routine that follows the WFIRLCH macro.
;	TIME	- timeout value in seconds.  This value is loaded into R1 before
;		  calling IOC_STD$PRIMITIVE_WFIRLCH.
;	NEWIPL	- specifies the new IPL that is set on return from
;		  IOC_STD$PRIMITIVE_WFIRLCH.  This value is loaded into R2
;		  before calling IOC_STD$PRIMITIVE_WFIRLCH.
;	ENVIRONMENT - is an optional keyword that specifies the current and
;		  resume routine environment as either JSB or CALL. The default
;		  is JSB.  If specified as JSB, then the RETURN parameter is
;		  used to generate a returns from the current routine and a
;		  .JSB_ENTRY directive is used to generate the resume routine.
;		  If specified as CALL, then the RETURN parameter is ignored
;		  and assumed to be RET, a .CALL_ENTRY directive is used to
;		  generate the resume routine, the IRP, FR4, and UCB parameters
;		  in the resume routine are copied into R3, R4, and R5.
;	TOUTROUT - is an optional parameter that specifies the timeout routine
;		  entry point which can be either a CALL or JSB entry point.
;		  If not specified then the resume routine entry point is also
;		  used as the timeout routine entry point.  This paramter can
;		  not be specified together with the EXCPT parameter.
; IMPLICIT INPUTS:
;
;	R3	- IRP pointer, passed on to fork routine
;	R4	- Passed on to fork routine, full 64-bits
;	R5	- UCB address
;
; IMPLICIT OUTPUTS:
;
;	R0,R1,R2 - Scratched
;
;--

	.MACRO	WFIRLCH EXCPT,TIME,NEWIPL=(SP)+,RETURN=RSB,ENVIRONMENT=JSB,-
			TOUTROUT,?L1

	.IF	DIFFERENT,ENVIRONMENT,JSB	;validate ENVIRONMENT keyword
	  .IF	DIFFERENT,ENVIRONMENT,CALL
	    .ERROR 0 ;Keyword %EXTRACT(0,11,<ENVIRONMENT>) must be either CALL or JSB;
	  .ENDC
	.ENDC

	.IF	NOT_BLANK,TOUTROUT		;disallow both EXCPT, TOUTROUT
	  .IF	NOT_BLANK,EXCPT
	    .ERROR 0 ;%EXTRACT(0,5,<EXCPT>) label and %EXTRACT(0,5,<TOUTROUT>) routine disallowed together;
	  .ENDC
	.ENDC

	$UCBDEF

	.IF	BLANK,TIME
	  ASHL	#16,#1,R1
	.IF_FALSE
	  .IF	DIFFERENT,<TIME>,<R1>
	    MOVL TIME,R1
	  .ENDC
	.ENDC

	.IF	IDENTICAL,<NEWIPL>,<R1>
	  .ERROR 0 ;Usage of R1 as %EXTRACT(0,6,<NEWIPL>) conflicts with R1 parameter to IOC$PRIMITIVE_WFIKPCH;
	.ENDC

	.IF	DIFFERENT,<NEWIPL>,<R2>
	  MOVL	NEWIPL,R2
	.ENDC

	MOVAB	L1,UCB$L_FPC(R5)	;setup fork routine address

	.IF	NOT_BLANK,TOUTROUT	;setup timeout routine address
	  MOVAB	TOUTROUT,UCB$PS_TOUTROUT(R5)
	.IF_FALSE
	  MOVAB	L1,UCB$PS_TOUTROUT(R5)
	.ENDC

	.GLOBAL	IOC_STD$PRIMITIVE_WFIRLCH
	EVAX_OR	R31,R4,R17		;R17 (P2) = full 64-bits of R4
	PUSHL	R2			;P5 = restore_ipl
	PUSHL	R1			;P4 = time out value
	PUSHL	R5			;P3 = UCB
	PUSHL	R17			;P2 = full 64-bits of R4
	PUSHL	R3			;P1 = IRP
	CALLS	#5,IOC_STD$PRIMITIVE_WFIRLCH

	.IF	IDENTICAL,ENVIRONMENT,CALL

	  RET

L1:	  .CALL_ENTRY	INPUT=<R17>,PRESERVE=<R3,R4,R5>

	  $OFFDEF	ARG,<IRP,FR4,UCB>	;define parameter offsets

	  MOVL	ARG$_IRP(AP),R3		;R3 = IRP
	  ASSUME	ARG$_FR4 EQ <2*4>
	  EVAX_OR	R31,R17,R4	;R4 = full 64-bits of P2 (R17)
	  MOVL	ARG$_UCB(AP),R5		;R5 = UKB

	.IF_FALSE	;IDENTICAL,ENVIRONMENT,CALL

	  RETURN

L1:	  .JSB_ENTRY	INPUT=<R3,R4,R5>,SCRATCH=<R0,R1,R2,R3,R4>

	.ENDC		;IDENTICAL,ENVIRONMENT,CALL

	.IF	NOT_BLANK,EXCPT
	  BITL	#UCB$M_TIMOUT,UCB$L_STS(R5)
	  BNEQ	EXCPT
	.ENDC

	.ENDM	WFIRLCH

;+
; $SVAPTE_TO_PA
;
;	Convert an SVAPTE+BOFF to a physical address
;
;   Parameters:
;
;	SVAPTE	System virtual address of a page table entry (required)
;	BOFF	Byte offset (optional -- default=#0)
;	PA	Address of quadword to receive physical address (optional)
;
;   Outputs:
;
;	R0	physical address (quadword register)
;	R1	scratched
;-
	.MACRO	$SVAPTE_TO_PA SVAPTE,BOFF=#0,PA
	.GLOBAL IOC$SVAPTE_TO_PA
	.IF	NB PA
	PUSHAB	PA			; PA present
	$$$ARGS=3			;   make parameter
	.IFF
	$$$ARGS=2			; PA omitted
	.ENDC
	MOVZWL	BOFF,-(SP)		; Make BOFF parameter
	PUSHL	SVAPTE			; Make SVAPTE parameter
	CALLS	#$$$ARGS,IOC$SVAPTE_TO_PA
	.ENDM	$SVAPTE_TO_PA




;+
; $SVA_TO_PA
;
;	Convert a system virtual address to a physical address
;
;   Parameters:
;
;	SVA	System virtual address (required)
;	PA	Address of quadword to receive physical address (optional)
;
;   Outputs:
;
;	R0	physical address (quadword register)
;	R1	scratched
;-
	.MACRO	$SVA_TO_PA SVA,PA
	.GLOBAL IOC$SVA_TO_PA
	.IF	NB PA
	PUSHAB	PA			; PA present
	$$$ARGS=2			;   make parameter
	.IFF
	$$$ARGS=1			; PA omitted
	.ENDC
	PUSHL	SVA			; Make SVAPTE parameter
	CALLS	#$$$ARGS,IOC$SVA_TO_PA
	.ENDM	$SVA_TO_PA

;+
; GET_PDT_INDEX -- GIVEN A PDT ADDRESS, FIND THE CORRESPONDING INDEX
;			FOR THIS PDT IN THE LOAD SHARING PDT TABLE
;
; INPUTS:
;
;	INDEXREG = REGISTER TO BE USED FOR GETTING THE INDEX
;	PDTREG = REGISTER WHICH CONTAINS THE PDT ADDRESS
;	TBLREG = REGISTER TO BE USED FOR PDT TABLE ADDRESS
;
; OUTPUTS:
;
;	INDEXREG WILL CONTAIN THE INDEX OF THE SPECIFIED PDT
;		IF EQUAL TO "PDTLIST$C_MAX_INDEX", IT MEANS
;		THE SPECIFIED PDT ADDRESS WASN'T IN THE TABLE
;
;-
	.MACRO	GET_PDT_INDEX INDEXREG=R1,PDTREG=R4,TBLREG=R2,?LOOP,?EXIT
	.show binary
	CLRL	INDEXREG		; Initialize index
	MOVL	G^SCS$GL_LOAD_SHARE_PDT_TABLE,-
		TBLREG			; Get the PDT addr table
LOOP:	CMPL	#PDTLIST$C_MAX_INDEX,-
		INDEXREG		; Is this the last index
	BEQL	EXIT			; If so, done
	CMPL	PDTREG,(TBLREG)[INDEXREG] ; Is this the same PDT address?
	BEQL	EXIT			; If yes, we have the index
	INCL	INDEXREG		; Increment index
	BRB	LOOP			; Go back to loop
EXIT:
	.noshow binary
	.ENDM	GET_PDT_INDEX


;
; Macros to allow declaration of Adapter types and Adapter initialization
; routines.  These macros are meant to be invoked in modules that are linked
; into SYSLOAXXX.EXE images.
;

;++
; Macro ADAPDESC.
;	Create NUM_PAGES, INIT_ROUTINES, and ADAPTERS arrays.
; INPUTS:
;	ADPTYPES - List of specific nexus device (adapter) types that conform
;		   to the general type described by the remainder of the input
;		   arguments.
;	NUMPAGES - The number of pages required for the adapter's register
;		   space.
;	INITRTN - The name of an adapter-specific initialization routine.
;
; Note: Each invocation of this macro corresponds to 1 "general" adapter type.
;	Each element in an ADPTYPES list corresponds to 1 "specific" type.
;
; Note: This macro is invoked in one of two environments.  These environments
;	are defined by whether or not the symbol $$$VMSDEFINED is defined or
;	not.  When the symbol is defined, this means that we are expanding an
;	invocation of the macro supported by DIGITAL, appearing in the module
;	INIADPxxx, whereas, if the symbol is NOT defined, this is a user
;	written invocation.  The only difference in the compiled data is that
;	a separate set of .PSECT's are used for the two environments.
;--
	.MACRO	ADAPDESC	ADPTYPES,NUMPAGES,INITRTN
	.SAVE

;
; Create three arrays; a list of specific device type codes (NDT$_),
; a NUM_PAGES array that contains the number of pages to be mapped for each
; corresponding device types, and the INIT_ROUTINES array that contains
; self relative addresses of initialization routines for the corresponding
; device types.	 Each array is contained in two .PSECTs, with the first
; such .PSECT of a pair, containing DIGITAL contributions and the second
; .PSECT containing user contributions.
;
	.IRP	ADPTYPE,ADPTYPES	; Repeat for each unique adp type...

	.if	DF	$$$VMSDEFINED	; If VMS distributed software.
		.PSECT	$$$INIT$DATA0
	.iff				; If user written invocation.
		.PSECT	$$$INIT$DATA1
	.endc				; End .PSECT selection conditional.
	.LONG	ADPTYPE			; Add an entry to ADAPTERS array.

	.if	DF	$$$VMSDEFINED	; If VMS distributed software.
		.PSECT	$$$INIT$DATA2	; Add an entry to the NUM_PAGES array.
	.iff				; If user written invocation.
		.PSECT	$$$INIT$DATA3	; Add an entry to the NUM_PAGES array.
	.endc				; End .PSECT selection conditional.
	.WORD	NUMPAGES		; Store number of pages to be mapped.

	.if	DF	$$$VMSDEFINED	; If VMS distributed software.
		.PSECT	$$$INIT$DATA4	; Add entry to the INIT_ROUTINES array.
	.iff				; If user written invocation.
		.PSECT	$$$INIT$DATA5	; Add entry to the INIT_ROUTINES array.
	.endc				; End .PSECT selection conditional.
	.IF NOT_BLANK INITRTN		; If ADP init routine is specified...
		.LONG	<INITRTN-.>	; Add self-relative pointer to routine.
	.IF_FALSE			; Else...
		.LONG	0		; Add a 0 entry to INIT_ROUTINES.
	.ENDC

	.ENDR

	.RESTORE
	.ENDM	ADAPDESC

;
; ADAP_INIRUT - macro to declare label of an adapter initialization routine
; and to set the proper .PSECT so that the routine will be properly placed
; when linked into SYSLOAXXX.EXE.
;

	.MACRO	ADAP_INIRUT	ROUTINE

	.PSECT	$$$INIT$CODE,QUAD
ROUTINE:
	.ENDM	ADAP_INIRUT


;++
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SCSI Port/Class Driver Interface () Macros
;
;	The following macros are used to invoke the SPI PORT/CLASS interface.
;	The SCSI Port Interface (SPI) macros and their usage are defined in the
;	OpenVMS Device Support Manual
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$ABORT_COMMAND ( spdt, scdrp, scdt )
;
;	This macro is used by SCSI class drivers to abort a SCSI CDB.
;
;	A tiered abort processing sequence will be attempted, and will progress to
;	each level, until the specified request (and possibily others are aborted)
;
;		o Abort Tag		- Aborts I_T_L_Q Nexus
;		o Abort 		- Aborts I_T_L_* Nexus
;		o Clear Queue		- Aborts *_T_L_* Nexus
;		o Bus Device Reset	- Aborts *_T_*_* Nexus
;		o Bus Reset		- Aborts *_*_*_* Nexus
;
;	I_T_L_Q nexus = A nexus between an Initiator, Target, Logical unit, and Queue tag
;			* = all elements present in respective set
;
;	Inputs:
;		spdt	= Port SPDT address
;		scdrp	= Class SCDRP address of request to be aborted
;		scdt	= Port SCDT Address
;
;	Outputs:
;		R0 = SS$_ABORT_ITLQ		= Successful Abort Tag
;		     SS$_ABORT_ITL		= Successful Abort 
;		     SS$_ABORT_TL		= Successful Clear Queue
;		     SS$_ABORT_T		= Successful Bus Device Reset
;		     SS$_ABORT			= Successful Bus Reset
;		     SS$_NO_ABORT		= No SCSI CDB to abort
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$ABORT_COMMAND SPDT = R4, SCDRP = R5, SCDT = R3
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	PUSHL	SCDT			; Pass SCDT address
	PUSHL	SCDRP			; Pass SCDRP address
	PUSHL	SPDT			; Pass SPDT address
	CALLS	#3, @SPDT$PS_CD_ABORT_COMMAND(SPDT)
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$BUFFER_MAP ( spdt, scdrp, prio )
;
;	This macro is used by SCSI class drivers to map a request for data transfer.
;	The request is mapped according to the existing port specific mapping rules.
;
;	Inputs:	spdt	= Port SPDT address
;		scdrp	= Class SCDRP address
;		prio	= Priority (0=low, 1=high)
;
;	Outputs: R0 = Status
;
;	See Device Support Manual for input and output SPDT, SCDRP field values
;
;	Call Environment
;		FORK IPL with FORK lock held
;		KP (Kernel Process) Thread
;
;	NOTE: If mapping resources are not available, this routine will stall the
;	      current KP thread until such a time as resources become available.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$BUFFER_MAP SPDT = R4, SCDRP = R5, PRIO = LOW
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	.IF	IDN PRIO, HIGH
	PUSHL	#1			; High priority specified
	.IFF
	PUSHL	#0			; Low prioirty specified
	.ENDC
	PUSHL	SCDRP			; Pass SCDRP address
	PUSHL	SPDT			; Pass SPDT address
	CALLS	#3, @SPDT$PS_CD_BUFFER_MAP(SPDT)
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$BUFFER_UNMAP ( spdt, scdrp )
;
;	This macro is used by SCSI class drivers to release previously allocated
;	mapping resources
;
;	Inputs:	spdt	= Port SPDT address
;		scdrp	= Class SCDRP address
;
;	Outputs: R0 = Status
;
;	See Device Support Manual for input and output SPDT, SCDRP field values
;
;	Call Environment
;		FORK IPL with FORK lock held
;		KP (Kernel Process) Thread
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$BUFFER_UNMAP  SPDT = R4, SCDRP = R5
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	PUSHL	SCDRP			; Pass SCDRP address
	PUSHL	SPDT			; Pass SPDT address
	CALLS	#2, @SPDT$PS_CD_BUFFER_UNMAP(SPDT)
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$INITIAL_PROCESSING (spdt, scdrp, bufadr, bufsiz)
;
;	This macro is invoked by SCSI class drivers to call into a common
;	routine which performs a tolerant INQUIRY command. It may be called
;	with or without a buffer, as the goal may be to simply have the port
;	common layer determine the SDTR characteristics of the device being
;	queried. If a buffer is specified, it must be a system space
;	address.
;
;	Inputs:	spdt	= Port SPDT address
;		scdrp	= SCDRP address
;		bufadr	= INQUIRY buffer address (optional)
;		bufsiz	= INQUIRY buffer size (optional)
;
;	Outputs:
;		R0 = Port status from last INQUIRY command issued
;
;	Call Environment
;		FORK IPL with FORK lock held
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO  SPI$INITIAL_PROCESSING SPDT = R4, SCDRP = R5, BUFADR, BUFSIZ

	.IIF	NDF SPDT$C_VERSION, $SPDTDEF

	.IF BLANK BUFADR
		.IF BLANK BUFSIZ
			PUSHL	SCDRP
			PUSHL	SPDT
			CALLS	#2, @SPDT$PS_CD_INITIAL_PROCESSING(SPDT)
		.IFF
			.ERROR ;SPI$INITIAL_PROCESSING, BUFSIZ with no BUFADR
		.ENDC
	.IFF
		.IF BLANK BUFSIZ
			.ERROR ;SPI$INITIAL_PROCESSING, BUFADR with no BUFSIZ
		.IFF
			PUSHL	BUFSIZ
			PUSHL	BUFADR
			PUSHL	SCDRP
			PUSHL	SPDT
			CALLS	#4, @SPDT$PS_CD_INITIAL_PROCESSING(SPDT)
		.ENDC
	.ENDC

	.ENDM   SPI$INITIAL_PROCESSING

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$CMD_BUFFER_ALLOC (spdt, scdrp, buf_size, ret_param_ptr)
;
;	This macro is used by SCSI class drivers to allocate a CDB buffer.
;
;	Inputs:	spdt	= Port SPDT address
;		scdrp	= Class SCDRP address
;		buf_size = requested size of command buffer
;		ret_param_ptr = return address to store size of buffer
;
;	Outputs: R0 = (Port specific buffer allocation status)
;
;	Call Environment
;		FORK IPL with FORK lock held
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$CMD_BUFFER_ALLOC SPDT = R4, SCDRP = R5, BUF_SIZE = R1, RET_PARAM_PTR = R2
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	CLRL	-(SP)			; Clear space for return address
	MOVL	SP, -(SP)		; Point to return data addr. on stack
	PUSHL	BUF_SIZE		; Pass command buf. size
	PUSHL	SCDRP			; Pass SCDRP address
	PUSHL	SPDT			; Pass SPDT address
	CALLS	#4, @SPDT$PS_CD_CMD_BUFFER_ALLOC(SPDT)
	MOVL	(SP)+, RET_PARAM_PTR	; Retrieve buffer address
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$CMD_BUFFER_DEALLOC (spdt, scdrp)
;
;	This macro is used by SCSI class drivers to deallocate a previously
;	allocated CDB buffer.
;
;	Inputs:	spdt	= Port SPDT address
;		scdrp	= Class SCDRP address
;
;	Outputs: R0 = (Port specific buffer deallocation status)
;
;	Call Environment
;		FORK IPL with FORK lock held
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$CMD_BUFFER_DEALLOC SPDT = R4, SCDRP = R5
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	PUSHL	SCDRP			; Pass SCDRP address
	PUSHL	SPDT			; Pass SPDT address
	CALLS	#2, @SPDT$PS_CD_CMD_BUFFER_DEALLOC(SPDT)
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$CONNECT ( scqptr )
;
;	This macro is called by class drivers to create a connection from
;	a SCSI class driver to a SCSI port driver which will persist until it
;	is broken by a call to SC$DISCONNECT.
;
;	Input:	(target_mode_callback,		; Target Mode Callback
;		 interface_version,		; SCDRP & SCDT Version numbers
;		 target_mode_context,		; Targer Mode Context
;		 SCSI ID,			; SCSI port/bus ID
;		 SCSI LUN,			; SCSI LUN
;		 port_state_callback )		; Port State Callback
;
;	Outputs:
;		R0 = Call status
;		R1 = Maximum byte count
;		R2 = SCDT address
;		R3 = PORT Capability Flags
;		R4 = SPDT address
;
;	Call Environment
;		FORK IPL with FORK lock held
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$CONNECT SELECT_CALLBACK,INTERFACE_VERSION,-
			    PORT_STATE_CONTEXT=#0,-
			    SCSI_IDS = R1, SCSI_LUN = R2,-
			    port_callback, -
			    ?SPI$CALL, ?SPI$ERROR
	.IIF	NDF SCDT$C_VERSION, $SCDTDEF
	.IIF	NDF SCDRP$C_VERSION, $SCDRPDEF
	.IIF	NDF SCQ$C_VERSION, $SCQDEF
	.IIF	NDF STDT$C_VERSION, $STDTDEF
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF

	MOVL	G^IOC$GL_SPI_CONNECT, R0
	BLSS	SPI$CALL			; Check S0 address
	MOVL	#SS$_NOSUCHDEV, R0		; If not, simulate
	BRW	SPI$ERROR			; error return

SPI$CALL:
	SUBL3	#SCQ$K_LENGTH, SP, R3		; Subtract size of data struct
	SUBL	#SCQ$K_LENGTH+4, SP		; Make longword aligned space
	BICL	#3, R3				;  on stack for the structure

	MOVL	#SCQ$K_CLSPOT_SP1, -		; Set to SP1$ protocol
		SCQ$IS_CLSPOT_PROTOCOL(R3)	;

	.IF NB INTERFACE_VERSION
	MOVL	INTERFACE_VERSION, -		; Copy version numbers of
		SCQ$IS_VERSION_NOS(R3)		; SCSI data structures
	.IF_FALSE
	MOVL	#SCDRP$C_VERSION -		; SCDRP version number
		!< SPDT$C_VERSION @ 8 > -	; SPDT version number
		!< SCDT$C_VERSION @ 16 > -	; SPDT version number
		!< STDT$C_VERSION @ 24 >, -	; SPDT version number
		SCQ$IS_VERSION_NOS(R3)
	.ENDC

	MOVL	SCSI_IDS, SCQ$IS_SCSI_IDS(R3)	; Copy SCSI port/bus IDs
	MOVL	SCSI_LUN, SCQ$IS_SCSI_LUN(R3)	; Copy SCSI LUN value

	.IF NB	SELECT_CALLBACK
	MOVAL	SELECT_CALLBACK, -		; Copy target mode callback
		SCQ$PS_SEL_CALLBACK(R3)		;  routine address
	.IF_FALSE
	CLRL	SCQ$PS_SEL_CALLBACK(R3)
	.ENDC


	.IF NB	PORT_CALLBACK
	MOVAL	PORT_CALLBACK, -		; Copy port state callback
		SCQ$PS_PORT_STATE_CALLBACK(R3)	;  routine address
	.IF_FALSE
	CLRL	SCQ$PS_PORT_STATE_CALLBACK(R3)
	.ENDC
	MOVL	PORT_STATE_CONTEXT, -		; Copy port state callback context 
		SCQ$IS_PORT_STATE_CONTEXT(R3)	;  data

	PUSHL	R3				; Pass ptr. to SCQ structure
	CALLS	#1, (R0)			; Same as CALLS SC$MASTER_CONNECT.

;
; Need to retrieve output data to registers
;
	MOVL	SCQ$PS_SCDT(R3), R2		; Retrieve SCDT address
	MOVL	SCQ$PS_SPDT(R3), R4		; Retrieve SPDT address
	MOVL	SCQ$IS_MAX_BCNT(R3), R1		; Retrieve max. byte count
	MOVL	SCQ$IS_PORT_SERV_FLAGS(R3), R3	; Retrieve port capability

	ADDL	#SCQ$K_LENGTH+4, SP		; Restore Stack pointer
SPI$ERROR:
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$CONNECTION_CHAR_GET (scdrp, spi_cc)
;
;	This macro is used by SCSI class drivers to read connection characteristics
;	for an existing connection.
;
;	Inputs:	scdrp	= Class SCDRP address
;		spi_cc	= SPI$ characteristics buffer address
;
;	Outputs:
;		R0   = Status
;
;	Call Environment
;		FORK IPL with FORK lock held
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$CONNECTION_CHAR_GET SPDT = R4, SCDRP = R5, SPI_CC = R2
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	PUSHL	SPI_CC			; Pass char. output buffer address
	PUSHL	SCDRP			; Pass SCDRP address
	CALLS	#2, @SPDT$PS_CD_CONNECTION_CHAR_GET(SPDT)
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$CONNECTION_CHAR_SET (scdrp, spi_cc)
;
;	This macro is used by SCSI class drivers to setup specific connection
;	characteristics on a connection by connection basis. The port will
;	remember these characteristics for the life of the connection or
;	until they are reset by another call to this routine.
;	for an existing connection.
;
;	Inputs:	scdrp	= Class SCDRP address
;		spi_cc	= SPI$ characteristics buffer address
;
;	Outputs:
;		R0   = Status
;
;	Call Environment
;		FORK IPL with FORK lock held
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$CONNECTION_CHAR_SET SPDT = R4, SCDRP = R5, SPI_CC = R2
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	PUSHL	SPI_CC			; Pass char. input buffer address
	PUSHL	SCDRP			; Pass SCDRP address
	CALLS	#2, @SPDT$PS_CD_CONNECTION_CHAR_SET(SPDT)
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$DISCONNECT ( spdt, scdt )
;
;	This macro is used by SCSI class drivers to break an existing connection
;	to the port driver - it does not reference the device managed by this
;	port & class driver connection at all.
;
;	Inputs:
;		spdt(AP) = Port SPDT address.
;		scdt(AP) = SCDT address.
;
;	Outputs:
;		R0 = Status
;
;	Call Environment
;		FORK IPL with FORK lock held
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$DISCONNECT SPDT = R4, SCDT = R3
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	PUSHL	SCDT			; Pass SCDT address
	PUSHL	SPDT			; Pass SPDT address
	CALLS	#2, @SPDT$PS_CD_DISCONNECT(SPDT)
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$QUEUE_FLUSH ( spdt, scdrp )
;
;	This macro is used by SCSI class drivers to flush the port queue
;
;	Inputs:	spdt	= Port SPDT address
;		scdrp	= Class SCDRP address
;
;	Outputs: R0 = Status
;
;	See Device Support Manual for input and output SPDT, SCDRP field values
;
;	Call Environment
;		FORK IPL with FORK lock held
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$QUEUE_FLUSH SPDT = R4, SCDRP = R5
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	PUSHL	SCDRP			; Pass SCDRP address
	PUSHL	SPDT			; Pass SPDT address
	CALLS	#2, @SPDT$PS_CD_QUEUE_FLUSH(SPDT)
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$QUEUE_FREEZE ( spdt, scdrp )
;
;	This macro is used by SCSI class drivers to freeze the port queue
;
;	Inputs:	spdt	= Port SPDT address
;		scdrp	= Class SCDRP address
;
;	Outputs: R0 = Status
;
;	See Device Support Manual for input and output SPDT, SCDRP field values
;
;	Call Environment
;		FORK IPL with FORK lock held
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$QUEUE_FREEZE SPDT = R4, SCDRP = R5
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	PUSHL	SCDRP			; Pass SCDRP address
	PUSHL	SPDT			; Pass SPDT address
	CALLS	#2, @SPDT$PS_CD_QUEUE_FREEZE(SPDT)
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$QUEUE_RELEASE ( spdt, scdrp )
;
;	This macro is used by SCSI class drivers to release the port queue
;	and restart the port queue processing.
;
;	Inputs:	spdt	= Port SPDT address
;		scdrp	= Class SCDRP address
;
;	Outputs: R0 = Status
;
;	See Device Support Manual for input and output SPDT, SCDRP field values
;
;	Call Environment
;		FORK IPL with FORK lock held
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$QUEUE_RELEASE SPDT = R4, SCDRP = R5
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	PUSHL	SCDRP			; Pass SCDRP address
	PUSHL	SPDT			; Pass SPDT address
	CALLS	#2, @SPDT$PS_CD_QUEUE_RELEASE(SPDT)
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$RESET_DEVICE ( spdt, scdrp )
;
;	This macro is used by SCSI class drivers to reset the SCSI device
;
;	Inputs:	spdt	= Port SPDT address
;		scdrp	= Class SCDRP address
;
;	Outputs: R0 = Status
;
;	See Device Support Manual for input and output SPDT, SCDRP field values
;
;	Call Environment
;		FORK IPL with FORK lock held
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$RESET_DEVICE SPDT = R4, SCDRP = R5
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	PUSHL	SCDRP			; Pass SCDRP address
	PUSHL	SPDT			; Pass SPDT address
	CALLS	#2, @SPDT$PS_CD_RESET_DEVICE(SPDT)
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$RESET_SCSI_BUS ( spdt, scdrp )
;
;	This macro is used by SCSI class drivers to reset the SCSI bus calling
;	the port specific code to assert the RST line
;
;	Inputs:	spdt	= Port SPDT address
;		scdrp	= Class SCDRP address
;
;	Outputs: R0 = Status
;
;	See Device Support Manual for input and output SPDT, SCDRP field values
;
;	Call Environment
;		FORK IPL with FORK lock held
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$RESET_SCSI_BUS SPDT = R4, SCDRP = R5
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	PUSHL	SCDRP			; Pass SCDRP address
	PUSHL	SPDT			; Pass SPDT address
	CALLS	#2, @SPDT$PS_CD_RESET_SCSI_BUS(SPDT)
	.ENDM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SPI$SEND_COMMAND ( spdt, scdrp, qchar )
;
;	This routine is called by class drivers to send multiple commands to a
;	SCSI device, with an associated queue characteristic value.
;
;	Inputs:	spdt	= Port SPDT address
;		scdrp	= Class SCDRP address
;		qchar	= Queue characteristics
;			(unordered, ordered, head, not_queue, aca)
;
;	Outputs: R0 = Status
;
;	See Device Support Manual for input and output SPDT, SCDRP field values
;
;	Call Environment
;		FORK IPL with FORK lock held
;		KP (Kernel Process) Thread
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	.MACRO	SPI$SEND_COMMAND SPDT = R4, SCDRP = R5, type = NOT_QUEUED
	.IIF	NDF SPDT$C_VERSION, $SPDTDEF
	.IF	DIFFERENT type, SCDRP$IS_QUEUE_CHAR(SCDRP)
	.IF	DF SCDRP$K_QCHAR_'type
	MOVL	#SCDRP$K_QCHAR_'type, SCDRP$IS_QUEUE_CHAR(SCDRP)
	.IFF
	MOVL	type, SCDRP$IS_QUEUE_CHAR(SCDRP)
	.ENDC
	.ENDC
	PUSHL	SCDRP			; Pass SCDRP address
	PUSHL	SPDT			; Pass SPDT address
	CALLS	#2, @SPDT$PS_CD_SEND_COMMAND(SPDT)
	.ENDM


;
;	Macros for converting inbound driver routines to Step 2
;
;   These macros assist in converting inbound driver routines from JSB
;   interfaces to call interfaces.  The PRESERVE paramater takes a list
;   of registers which are passed to the .CALL_ENTRY directive.	 The list
;   defaults to registers which were declared as scratch in the JSB interface.
;   The FETCH parameter controls whether the macro generates instructions to
;   move the arguments from the stack into the registers which the JSB interface
;   had defined.  This defaults to YES.	 If NO is specified the programmer
;   is responsible for finding the arguments at offsets to the AP.
;
;   The macro will always declare symbolic AP offsets for the arguments in the
;   form ARG$_name, and a .CALL_ENTRY directive.
;
;   To make an inbound driver routine callable simply replace the .JSB_ENTRY
;   directive with the appropriate macro.  Pass all registers modified by the
;   routine, or routines which it calls, to the PRESERVE parameter.  (That is,
;   specify any registers mentioned in the PRESERVE, SCRATCH or INPUT parameters
;   of the .JSB_ENTRY to the PRESEVE parameter).  For example:
;
;   SO$CANCELIO:
;	.JSB_ENTRY  INPUT=<R2,R3,R4,R5,R8>, SCRATCH=<R0,R1,R2,R3,R4,R5>, -
;		    PRESERVE=<R6,R7,R8,R9,R10,R11>
;   -------------------
;   SO$CANCELIO:
;	$DRIVER_CANCEL_ENTRY PRESERVE=<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11>
;
	.MACRO $DRIVER_ALTSTART_ENTRY PRESERVE=<R2,R3,R4,R5>, FETCH=YES

		.IF DIFFERENT,FETCH,YES			; Validate FETCH parameter
			.IF DIFFERENT,FETCH,NO
			.ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
			.ENDC
		.ENDC

		.IF DEFINED,$$JSB_ALTSTART
			.WARN 0 ;Use of DDTAB JSB_ALTSTART is inconsistent with this call interface alt start I/O routine;
		.ENDC

		$OFFDEF ALTARG, < -
			irp, -
			ucb >

		$$$USE_PRESERVE = 1
		.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
		.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

		.IF	EQ,$$$USE_PRESERVE-1
		  .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
		.IF_FALSE
		  .CALL_ENTRY
		.ENDC

		.IF IDENTICAL FETCH YES
		MOVL	altarg$_irp(AP), R3
		MOVL	altarg$_ucb(AP), R5
		.ENDC
	.ENDM

	.MACRO $DRIVER_CANCEL_ENTRY PRESERVE=<R2,R3,R4>, FETCH=YES

		.IF DIFFERENT,FETCH,YES			; Validate FETCH parameter
			.IF DIFFERENT,FETCH,NO
			.ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
			.ENDC
		.ENDC

		$OFFDEF CANARG, < -
			chan,-
			irp,-
			pcb,-
			ucb,-
			reason >


		$$$USE_PRESERVE = 1
		.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
		.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

		.IF	EQ,$$$USE_PRESERVE-1
		  .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
		.IF_FALSE
		  .CALL_ENTRY
		.ENDC

		.IF IDENTICAL FETCH YES
		MOVL	canarg$_chan(AP), R2
		MOVL	canarg$_irp(AP), R3
		MOVL	canarg$_pcb(AP), R4
		MOVL	canarg$_ucb(AP), R5
		MOVL	canarg$_reason(AP), R8
		.ENDC
	.ENDM

	.MACRO $DRIVER_CLONEDUCB_ENTRY PRESERVE=<R3>, FETCH=YES

		.IF DIFFERENT,FETCH,YES			; Validate FETCH parameter
			.IF DIFFERENT,FETCH,NO
			.ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
			.ENDC
		.ENDC

		$OFFDEF CLONEARG, < -
			cloned_ucb,-
			ddt,-
			pcb,-
			template_ucb >


		$$$USE_PRESERVE = 1
		.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
		.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

		.IF	EQ,$$$USE_PRESERVE-1
		  .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
		.IF_FALSE
		  .CALL_ENTRY
		.ENDC

		.IF IDENTICAL FETCH YES
		MOVL	#SS$_NORMAL, R0
		MOVL	clonearg$_cloned_ucb(AP), R2
		MOVL	clonearg$_ddt(AP), R3
		MOVL	clonearg$_pcb(AP), R4
		MOVL	clonearg$_template_ucb(AP), R5
		.ENDC

	.ENDM

	.MACRO $DRIVER_CTRLINIT_ENTRY PRESERVE=<R2>, FETCH=YES

		.IF DIFFERENT,FETCH,YES			; Validate FETCH parameter
			.IF DIFFERENT,FETCH,NO
			.ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
			.ENDC
		.ENDC

		$OFFDEF CTRLARG, < -
			idb, -
			ddb, -
			crb >


		$$$USE_PRESERVE = 1
		.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
		.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

		.IF	EQ,$$$USE_PRESERVE-1
		  .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
		.IF_FALSE
		  .CALL_ENTRY
		.ENDC

		.IF IDENTICAL FETCH YES
		MOVL	#SS$_NORMAL, R0
		MOVL	ctrlarg$_idb(AP), R4
		MOVL	ctrlarg$_idb(AP), R5
		MOVL	ctrlarg$_ddb(AP), R6
		MOVL	ctrlarg$_crb(AP), R8
		.ENDC
	.ENDM

	.MACRO $DRIVER_REGDUMP_ENTRY PRESERVE=<R2>, FETCH=YES

		.IF DIFFERENT,FETCH,YES			; Validate FETCH parameter
			.IF DIFFERENT,FETCH,NO
			.ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
			.ENDC
		.ENDC

		$OFFDEF REGARG, < -
			buffer, -
			cram, -
			ucb >


		$$$USE_PRESERVE = 1
		.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
		.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

		.IF	EQ,$$$USE_PRESERVE-1
		  .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
		.IF_FALSE
		  .CALL_ENTRY
		.ENDC

		.IF IDENTICAL FETCH YES
		MOVL	regarg$_buffer(AP), R0
		MOVL	regarg$_cram(AP), R4
		MOVL	regarg$_ucb(AP), R5
		.ENDC
	.ENDM

	.MACRO $DRIVER_START_ENTRY PRESERVE=<R2,R4>, FETCH=YES

		.IF DIFFERENT,FETCH,YES			; Validate FETCH parameter
			.IF DIFFERENT,FETCH,NO
			.ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
			.ENDC
		.ENDC

		.IF DEFINED,$$JSB_START
			.WARN 0 ;Use of DDTAB JSB_START is inconsistent with this call interface start I/O routine;
		.ENDC

		$OFFDEF STARTARG, < -
			irp, -
			ucb >


		$$$USE_PRESERVE = 1
		.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
		.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

		.IF	EQ,$$$USE_PRESERVE-1
		  .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
		.IF_FALSE
		  .CALL_ENTRY
		.ENDC

		.IF IDENTICAL FETCH YES
		MOVL	startarg$_irp(AP), R3
		MOVL	startarg$_ucb(AP), R5
		.ENDC
	.ENDM

	.MACRO $DRIVER_DELIVER_ENTRY PRESERVE=<R2>, FETCH=YES

		.IF DIFFERENT,FETCH,YES			; Validate FETCH parameter
			.IF DIFFERENT,FETCH,NO
			.ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
			.ENDC
		.ENDC

		$OFFDEF DLVRARG, < -
			idb, -
			unit_number, -
			scratch_area, -
			adp >


		$$$USE_PRESERVE = 1
		.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
		.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

		.IF	EQ,$$$USE_PRESERVE-1
		  .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
		.IF_FALSE
		  .CALL_ENTRY
		.ENDC

		.IF IDENTICAL FETCH YES
		MOVL	dlvrarg$_idb(AP), R3
		MOVL	dlvrarg$_idb(AP), R4
		MOVL	dlvrarg$_unit_number(AP), R5
		MOVL	dlvrarg$_scratch_area(AP), R7
		MOVL	dlvrarg$_adp(AP), R8
		.ENDC
	.ENDM

	.MACRO $DRIVER_UNITINIT_ENTRY PRESERVE=<R2>, FETCH=YES

		.IF DIFFERENT,FETCH,YES			; Validate FETCH parameter
			.IF DIFFERENT,FETCH,NO
			.ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
			.ENDC
		.ENDC

		$OFFDEF UNITARG, < -
			idb, -
			ucb >

		$$$USE_PRESERVE = 1
		.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
		.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

		.IF	EQ,$$$USE_PRESERVE-1
		  .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
		.IF_FALSE
		  .CALL_ENTRY
		.ENDC

		.IF IDENTICAL FETCH YES
		MOVL	#SS$_NORMAL, R0
		MOVL	unitarg$_idb(AP), R4
		MOVL	unitarg$_ucb(AP), R5
		.ENDC
	.ENDM

	.MACRO $DRIVER_MNTVER_ENTRY PRESERVE, FETCH=YES

		.IF DIFFERENT,FETCH,YES			; Validate FETCH parameter
			.IF DIFFERENT,FETCH,NO
			.ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
			.ENDC
		.ENDC

		$OFFDEF MNTARG, < -
			irp, -
			ucb >

		$$$USE_PRESERVE = 1
		.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
		.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

		.IF	EQ,$$$USE_PRESERVE-1
		  .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
		.IF_FALSE
		  .CALL_ENTRY
		.ENDC

		.IF IDENTICAL FETCH YES
		MOVL	mntarg$_irp(AP), R3
		MOVL	mntarg$_ucb(AP), R5
		.ENDC
	.ENDM

	.MACRO $DRIVER_CHANNEL_ASSIGN_ENTRY PRESERVE, FETCH=YES

		.IF DIFFERENT,FETCH,YES			; Validate FETCH parameter
			.IF DIFFERENT,FETCH,NO
			.ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
			.ENDC
		.ENDC

		$OFFDEF CHANARG, < -
			ucb, -
			ccb >

		$$$USE_PRESERVE = 1
		.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
		.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

		.IF	EQ,$$$USE_PRESERVE-1
		  .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
		.IF_FALSE
		  .CALL_ENTRY
		.ENDC

		.IF IDENTICAL FETCH YES
		MOVL	chanarg$_ucb(AP), R5
		MOVL	chanarg$_ccb(AP), R8
		.ENDC
	.ENDM

	.MACRO $DRIVER_CANCEL_SELECTIVE_ENTRY PRESERVE, FETCH=YES

		.IF DIFFERENT,FETCH,YES			; Validate FETCH parameter
			.IF DIFFERENT,FETCH,NO
			.ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
			.ENDC
		.ENDC

		$OFFDEF CANSARG, < -
			pcb, -
			ucb, -
			chan, -
			iosb_vector, -
			iosb_count >

		$$$USE_PRESERVE = 1
		.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
		.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

		.IF	EQ,$$$USE_PRESERVE-1
		  .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
		.IF_FALSE
		  .CALL_ENTRY
		.ENDC

		.IF IDENTICAL FETCH YES
		MOVL	#SS$_UNSUPPORTED, R0
		MOVL	cansarg$_pcb(AP), R4
		MOVL	cansarg$_ucb(AP), R5
		MOVL	cansarg$_chan(AP), R6
		MOVL	cansarg$_iosb_vector(AP), R7
		MOVL	cansarg$_iosb_count(AP), R8
		.ENDC
	.ENDM

;
;	Macro for converting driver error callback routines to Step 2
;
	.MACRO $DRIVER_ERRRTN_ENTRY PRESERVE, FETCH=YES

		.IF DIFFERENT,FETCH,YES		; Validate FETCH parameter
			.IF DIFFERENT,FETCH,NO
			.ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
			.ENDC
		.ENDC

		$OFFDEF ERRARG, < -
			irp, -
			pcb, -
			ucb, -
			ccb, -
			status>

		$$$USE_PRESERVE = 1
		.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
		.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

		.IF	EQ,$$$USE_PRESERVE-1
		  .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
		.IF_FALSE
		  .CALL_ENTRY
		.ENDC

		.IF IDENTICAL FETCH YES
		MOVL	errarg$_irp(AP),R3
		MOVL	errarg$_pcb(AP),R4
		MOVL	errarg$_ucb(AP),R5
		MOVL	errarg$_ccb(AP),R6
		MOVL	errarg$_status(AP),R0
		.ENDC
	.ENDM
;*************************************************************

; Macro to set up and call the Step 2 FDT Completion routine
; EXE_STD$ABORTIO.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R0 - Final $QIO System Service status
;

	.MACRO CALL_ABORTIO DO_RET=YES	; (Optional) Automatic RET insertion.

	.IF	DIFFERENT,DO_RET,NO	; Validate DO_RET keyword.
	  .IF	DIFFERENT,DO_RET,YES	; If not 'NO' and not 'YES' give warn.
	    .ERROR 0 ;Keyword %EXTRACT(0,6,<DO_RET>) must be either YES or NO;
	  .ENDC
	.ENDC

	PUSHL	R0			; Pass Final $QIO system status.
	PUSHL	R5			; Pass pointer to UCB.
	PUSHL	R4			; Pass pointer to PCB.
	PUSHL	R3			; Pass pointer to IRP.
	CALLS	#4,G^EXE_STD$ABORTIO	; Abort the I/O.

	.IF IDENTICAL,DO_RET,YES
	RET				; Provide the RET instruction.
	.ENDC

	.ENDM	CALL_ABORTIO


; Macro to set up and call the Step 2 FDT Completion routine
; EXE_STD$FINISHIO.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R5 - UCB
;	R0 - First longword of the IOSB.
;	R1 - Second longword the the IOSB.
;
	.MACRO	CALL_FINISHIO -
			DO_RET=YES	; (Optional) Automatic RET insertion.

	.IF	DIFFERENT,DO_RET,NO	; Validate DO_RET keyword.
	  .IF	DIFFERENT,DO_RET,YES	; If not 'NO' and not 'YES' give warn.
	    .ERROR 0 ;Keyword %EXTRACT(0,6,<DO_RET>) must be either YES or NO;
	  .ENDC
	.ENDC

	MOVL	R0,IRP$L_IOST1(R3)	; Move into the IRP the IOST1.
	MOVL	R1,IRP$L_IOST2(R3)	; Move into the IRP the IOST2.

	PUSHL	R5			; Pass pointer to UCB.
	PUSHL	R3			; Pass pointer to IRP.
	CALLS	#2,G^EXE_STD$FINISHIO	; Finish the I/O.

	.IF IDENTICAL,DO_RET,YES
	RET				; Provide the RET instruction.
	.ENDC

	.ENDM	CALL_FINISHIO
;
; Macro to set up and call the Step 2 FDT Completion routine
; EXE_STD$FINISHIOC.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R5 - UCB
;	R0 - First longword of the IOSB.
;	R1 - Will be cleared.
;
	.MACRO	CALL_FINISHIOC DO_RET=YES	; (Optional) Automatic RET insertion.

	CLRL	R1			; Clear R1 to clear IOST2 in FINISHIO.

	CALL_FINISHIO DO_RET		; Call $FINISHIO.

	.ENDM	CALL_FINISHIOC
;
; Macro to set up and call the Step 2 FDT Completion routine
; EXE_STD$FINISHIO_NOIOST.
; The IRP$_IOST fields are not filled in in this macro so that the caller
; has greater control over the contents.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R5 - UCB
;
	.MACRO	CALL_FINISHIO_NOIOST -
			DO_RET=YES	; (Optional) Automatic RET insertion.

	.IF	DIFFERENT,DO_RET,NO	; Validate DO_RET keyword.
	  .IF	DIFFERENT,DO_RET,YES	; If not 'NO' and not 'YES' give warn.
	    .ERROR 0 ;Keyword %EXTRACT(0,6,<DO_RET>) must be either YES or NO;
	  .ENDC
	.ENDC

	PUSHL	R5			; Pass pointer to UCB.
	PUSHL	R3			; Pass pointer to IRP.
	CALLS	#2,G^EXE_STD$FINISHIO	; Finish the I/O.

	.IF IDENTICAL,DO_RET,YES
	RET				; Provide the RET instruction.
	.ENDC

	.ENDM	CALL_FINISHIO_NOIOST

;
; Macro to set up and call the Step 2 FDT Completion routine
; EXE_STD$IORSNWAIT.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R6 - CCB
;	R0 - Final $QIO System Service Status.
;	R1 - Resource number.
;
	.MACRO	CALL_IORSNWAIT -
			DO_RET=YES	; (Optional) Automatic RET insertion.

	.IF	DIFFERENT,DO_RET,NO	; Validate DO_RET keyword.
	  .IF	DIFFERENT,DO_RET,YES	; If not 'NO' and not 'YES' give warn.
	    .ERROR 0 ;Keyword %EXTRACT(0,6,<DO_RET>) must be either YES or NO;
	  .ENDC
	.ENDC

	PUSHL	R1			; Pass resource number.
	PUSHL	R0			; Pass final status.
	PUSHL	R6			; Pass pointer to CCB.
	PUSHL	R5			; Pass pointer to UCB.
	PUSHL	R4			; Pass pointer to PCB.
	PUSHL	R3			; Pass pointer to IRP.
	CALLS	#6,G^EXE_STD$IORSNWAIT	; Call resource wait..

	.IF IDENTICAL,DO_RET,YES
	RET				; Provide the RET instruction.
	.ENDC

	.ENDM	CALL_IORSNWAIT

;
; Macro to set up and call the Step 2 FDT support routine
; EXE_STD$MODIFYLOCK for former users of the obsolete EXE$MODIFYLOCK routine.
; On error this macro will RET.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R6 - CCB
;	R1 - Size of I/O buffer
;	R0 - 64-bit address of I/O buffer
;
; IMPLICIT OUTPUTS:
;
;	R0 - Status
;	R1 - IRP$L_SVAPTE = SVA of the PTE that maps the 1st page of the buffer
;	R2 - Modify function indicator = 5
;
	.MACRO	CALL_MODIFYLOCK ?L1

	$SETUP_CALL64	ARG_COUNT=6
        $PUSH_ARG64	R1		; Param6 = buffer size in bytes
        $PUSH_ARG64	R0		; Param5 = 64-bit buffer address
	$PUSH_ARG64	R6		; Param4 = pointer to CCB.
        $PUSH_ARG64	R5		; Param3 = pointer to UCB
        $PUSH_ARG64	R4		; Param2 = pointer to PCB
        $PUSH_ARG64	R3		; Param1 = pointer to IRP
        $CALL64 EXE_STD$MODIFYLOCK	; Lock buffer for I/O read/write by dev
	.BRANCH_LIKELY
	BLBS	R0,L1			; Success: YES - Cont. FDT processing.
	RET				; Return. ABORTIO called.
					; Now preserve JSB interface outputs.
L1:	MOVL	IRP$L_SVAPTE(R3),R1	; Get SVA of start of buffer in R1.
	MOVL	#5,R2			; Indicate modify function.

	.ENDM	CALL_MODIFYLOCK
;
; Macro to set up and call the Step 2 FDT support routine
; EXE_STD$MODIFYLOCK with an error callback routine for former users of the
; obsolete EXE$MODIFYLOCK_ERR routine.

;
; INPUTS:
;
;	INTERFACE_WARNING	- YES: Warn the user that the interface has
;				       changed since the conversion to call
;				       interfaces and the macro does not
;				       attempt to correct this inconsistancy.
;				- NO:  No warning will be issued.
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R6 - CCB
;	R0 - 64-bit address of I/O buffer
;	R1 - Size of I/O buffer
;	R2 - Caller's error callback routine with standard call interface
;
; IMPLICIT OUTPUTS:
;
;	R0 - Status
;	R1 - IRP$L_SVAPTE = SVA of the PTE that maps the 1st page of the buffer
;	R2 - Modify function indicator = 5
;
	.MACRO	CALL_MODIFYLOCK_ERR INTERFACE_WARNING=YES ?L1

    .IF DIFFERENT,INTERFACE_WARNING,NO	; Validate INTERFACE_WARNING keyword.
    .IF DIFFERENT,INTERFACE_WARNING,YES ; If not 'NO' and not 'YES' give warning
    .ERROR 0 ;Keyword %EXTRACT(0,17,<INTERFACE_WARNING>) must be YES or NO;
    .ENDC
    .ENDC

    .IF IDENTICAL,INTERFACE_WARNING,YES ; Give the interface warning.
    .WARN  0 ;$MODIFYLOCK_ERR interface changed: R2 must have a standard call interface. Set Keyword %EXTRACT(0,17,<INTERFACE_WARNING>)=NO to suppress message.;
    .ENDC

	$SETUP_CALL64	ARG_COUNT=7
	$PUSH_ARG64	R2		; Param7 = caller's error call back routine,
        $PUSH_ARG64	R1		; Param6 = buffer size in bytes
        $PUSH_ARG64	R0		; Param5 = 64-bit buffer address
	$PUSH_ARG64	R6		; Param4 = pointer to CCB.
        $PUSH_ARG64	R5		; Param3 = pointer to UCB
        $PUSH_ARG64	R4		; Param2 = pointer to PCB
        $PUSH_ARG64	R3		; Param1 = pointer to IRP
        $CALL64 EXE_STD$MODIFYLOCK	; Lock buffer for I/O read/write by dev
	.BRANCH_LIKELY
	BLBS	R0,L1			; Success: YES - Cont. FDT processing.
	RET				; Return. Callback & ABORTIO called.
					; Now preserve JSB interface outputs.
L1:	MOVL	IRP$L_SVAPTE(R3),R1	; Get SVA of start of buffer in R1.
	MOVL	#5,R2			; Indicate modify function.

	.ENDM	CALL_MODIFYLOCK_ERR
;
; Macro to set up and call the Step 2 FDT support routine
; EXE_STD$READCHK for former users of the obsolete EXE$READCHK routine.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R1 - Size of I/O buffer
;	R0 - 64-bit address of I/O buffer
;
; IMPLICIT OUTPUTS:
;
;	R0 - 64-bit address of I/O buffer
;	R1 - IRP$L_BCNT = length of transfer in bytes.
;	R2 - Read function indicator = 1
;	R3 - IRP
;
	.MACRO	CALL_READCHK ?L1

	$PUSH64	R0			; Save 64-bit pointer to I/O buffer.

	$SETUP_CALL64	ARG_COUNT=5
        $PUSH_ARG64	R1		; Param5 = buffer size in bytes
        $PUSH_ARG64	R0		; Param4 = 64-bit buffer address
        $PUSH_ARG64	R5		; Param3 = pointer to UCB
        $PUSH_ARG64	R4		; Param2 = pointer to PCB
        $PUSH_ARG64	R3		; Param1 = pointer to IRP
        $CALL64 EXE_STD$READCHK		; Assure accessible for I/O read from dev
	.BRANCH_LIKELY
	BLBS	R0,L1			; Success? YES - Cont. FDT processing.
	ADDL	#8,SP			; Discard pointer to I/O buffer.
					; R0 contains the final $QIO status...
					;   for input into EXE_STD$ABORTIO.
	CALL_ABORTIO DO_RET=YES		; Abort the I/O and...
					; Ret from FDT Completion Routine with:
					;  1)$QIO status in FDT Context area,
					;  2)IRP$PS_FDT_CONTEXT cleared,
					;  3)SS$_FDT_COMPL in R0.
					; Now preserve JSB interface outputs.
L1:	MOVL	IRP$L_BCNT(R3),R1	; Get transfer size in R1.
	MOVL	#1,R2			; Indicate read function.
	$POP64	R0			; Restore the 64-bit pointer to I/O buffer.

	.ENDM	CALL_READCHK
;
; Macro to set up and call the Step 2 FDT support routine
; EXE_STD$READCHK for former users of the obsolete EXE$READCHKR routine.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R1 - Size of I/O buffer
;	R0 - 64-bit address of I/O buffer
;
; IMPLICIT OUTPUTS:
;
;	R0 - Status
;	R1 - IRP$L_BCNT = length of transfer in bytes.
;	R2 - Read function indicator = 1
;	R3 - IRP
;
	.MACRO	CALL_READCHKR
					; Push the input parameters...
	$SETUP_CALL64	ARG_COUNT=5
        $PUSH_ARG64	R1		; Param5 = buffer size in bytes
        $PUSH_ARG64	R0		; Param4 = 64-bit buffer address
        $PUSH_ARG64	R5		; Param3 = pointer to UCB
        $PUSH_ARG64	R4		; Param2 = pointer to PCB
        $PUSH_ARG64	R3		; Param1 = pointer to IRP
        $CALL64 EXE_STD$READCHK		; Assure accessible for I/O read from dev
					; Now preserve JSB interface outputs.
	MOVL	IRP$L_BCNT(R3),R1	; Get transfer size in R1.
	MOVL	#1,R2			; Indicate read function.

	.ENDM	CALL_READCHKR

;
; Macro to set up and call the Step 2 FDT support routine
; EXE_STD$READLOCK for former users of the obsolete EXE$READLOCK routine.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R6 - CCB
;	R0 - 64-bit address of I/O buffer
;	R1 - Size of I/O buffer
;
; IMPLICIT OUTPUTS:
;
;	R0 - Status
;	R1 - IRP$L_SVAPTE = SVA of the PTE that maps the 1st page of the buffer
;	R2 - Read function indicator = 1
;
	.MACRO	CALL_READLOCK ?L1

	$SETUP_CALL64	ARG_COUNT=6
        $PUSH_ARG64	R1		; Param6 = buffer size in bytes
        $PUSH_ARG64	R0		; Param5 = 64-bit buffer address
	$PUSH_ARG64	R6		; Param4 = pointer to CCB.
        $PUSH_ARG64	R5		; Param3 = pointer to UCB
        $PUSH_ARG64	R4		; Param2 = pointer to PCB
        $PUSH_ARG64	R3		; Param1 = pointer to IRP
        $CALL64 EXE_STD$READLOCK	; Lock buffer for I/O read from dev
	.BRANCH_LIKELY
	BLBS	R0,L1			; Success: YES - Cont. FDT processing.
	RET				; Return. ABORTIO called.
					; Now preserve JSB interface outputs.
L1:	MOVL	IRP$L_SVAPTE(R3),R1	; Get SVA of start of buffer in R1.
	MOVL	#1,R2			; Indicate read function.

	.ENDM	CALL_READLOCK
;
; Macro to set up and call the Step 2 FDT support routine
; EXE_STD$READLOCK with an error callback routine for former users of the
; obsolete EXE$READLOCK_ERR routine.
;
; INPUTS:
;
;	INTERFACE_WARNING	- YES: Warn the user that the interface has
;				       changed since the conversion to call
;				       interfaces and the macro does not
;				       attempt to correct this inconsistancy.
;				- NO:  No warning will be issued.
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R6 - CCB
;	R0 - 64-bit address of I/O buffer
;	R1 - Size of I/O buffer
;	R2 - Caller's error callback routine with standard call interface
;
; IMPLICIT OUTPUTS:
;
;	R0 - Status
;	R1 - IRP$L_SVAPTE = SVA of the PTE that maps the 1st page of the buffer
;	R2 - Read function indicator = 1
;
	.MACRO	CALL_READLOCK_ERR INTERFACE_WARNING=YES ?L1

    .IF DIFFERENT,INTERFACE_WARNING,NO	; Validate INTERFACE_WARNING keyword.
    .IF DIFFERENT,INTERFACE_WARNING,YES ; If not 'NO' and not 'YES' give warning
    .ERROR 0 ;Keyword %EXTRACT(0,17,<INTERFACE_WARNING>) must be YES or NO;
    .ENDC
    .ENDC

    .IF IDENTICAL,INTERFACE_WARNING,YES ; Give the interface warning.
    .WARN  0 ;$READLOCK_ERR interface changed: R2 must have a standard call interface. Set Keyword %EXTRACT(0,17,<INTERFACE_WARNING>)=NO to suppress message.;
    .ENDC

	$SETUP_CALL64	ARG_COUNT=7
	$PUSH_ARG64	R2		; Param7 = caller's error call back routine,
        $PUSH_ARG64	R1		; Param6 = buffer size in bytes
        $PUSH_ARG64	R0		; Param5 = 64-bit buffer address
	$PUSH_ARG64	R6		; Param4 = pointer to CCB.
        $PUSH_ARG64	R5		; Param3 = pointer to UCB
        $PUSH_ARG64	R4		; Param2 = pointer to PCB
        $PUSH_ARG64	R3		; Param1 = pointer to IRP
        $CALL64 EXE_STD$READLOCK	; Lock buffer for I/O read from dev
	.BRANCH_LIKELY
	BLBS	R0,L1			; Success: YES - Cont. FDT processing.
	RET				; Return. Callback & ABORTIO called.
					; Now preserve JSB interface outputs.
L1:	MOVL	IRP$L_SVAPTE(R3),R1	; Get SVA of start of buffer in R1.
	MOVL	#1,R2			; Indicate read function.

	.ENDM	CALL_READLOCK_ERR

;
; Macro to set up and call the Step 2 FDT support routine
; EXE_STD$WRITECHK for former users of the obsolete EXE$WRITECHK routine.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R1 - Size of I/O buffer
;	R0 - 64-bit address of I/O buffer
;
; IMPLICIT OUTPUTS:
;
;	R0 - 64-bit address of I/O buffer
;	R1 - IRP$L_BCNT = length of transfer in bytes.
;	R2 - Write function indicator = 0
;	R3 - IRP
;
	.MACRO	CALL_WRITECHK ?L1

	$PUSH64	R0			; Save 64-bit pointer to I/O buffer.

	$SETUP_CALL64	ARG_COUNT=5
        $PUSH_ARG64	R1		; Param5 = buffer size in bytes
        $PUSH_ARG64	R0		; Param4 = 64-bit buffer address
        $PUSH_ARG64	R5		; Param3 = pointer to UCB
        $PUSH_ARG64	R4		; Param2 = pointer to PCB
        $PUSH_ARG64	R3		; Param1 = pointer to IRP
        $CALL64 EXE_STD$WRITECHK	; Assure accessible for I/O write to dev
	.BRANCH_LIKELY
	BLBS	R0,L1			; Success? YES - Continue.
	ADDL	#8,SP			; Discard pointer to I/O buffer.
					; R0 contains the final $QIO status...
					;   for input into EXE_STD$ABORTIO.
	CALL_ABORTIO DO_RET=YES		; Abort the I/O and...
					; Ret from FDT Completion Routine with:
					;  1)$QIO status in FDT Context area,
					;  2)IRP$PS_FDT_CONTEXT cleared,
					;  3)SS$_FDT_COMPL in R0.
					; Now preserve JSB interface outputs.
L1:	MOVL	IRP$L_BCNT(R3),R1	; Get transfer size in R1.
	CLRL	R2			; Indicate write function.
	$POP64	R0			; Restore the 64-bit pointer to I/O buffer.

	.ENDM	CALL_WRITECHK
;
; Macro to set up and call the Step 2 FDT support routine
; EXE_STD$WRITECHK for former users of the obsolete EXE$WRITECHKR routine.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R1 - Size of I/O buffer
;	R0 - 64-bit address of I/O buffer
;
; IMPLICIT OUTPUTS:
;
;	R0 - Status
;	R1 - IRP$L_BCNT = length of transfer in bytes.
;	R2 - Write function indicator = 0
;	R3 - IRP
;
	.MACRO	CALL_WRITECHKR
					; Push the input parameters...
	$SETUP_CALL64	ARG_COUNT=5
        $PUSH_ARG64	R1		; Param5 = buffer size in bytes
        $PUSH_ARG64	R0		; Param4 = 64-bit buffer address
        $PUSH_ARG64	R5		; Param3 = pointer to UCB
        $PUSH_ARG64	R4		; Param2 = pointer to PCB
        $PUSH_ARG64	R3		; Param1 = pointer to IRP
        $CALL64 EXE_STD$WRITECHK	; Assure accessible for I/O write to dev
					; Now preserve JSB interface outputs.
	MOVL	IRP$L_BCNT(R3),R1	; Get transfer size in R1.
	CLRL	R2			; Indicate write function.

	.ENDM	CALL_WRITECHKR

;
; Macro to set up and call the Step 2 FDT support routine
; EXE_STD$WRITELOCK for former users of the obsolete EXE$WRITELOCK routine.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R6 - CCB
;	R0 - 64-bit address of I/O buffer
;	R1 - Size of I/O buffer
;
; IMPLICIT OUTPUTS:
;
;	R0 - Status
;	R1 - IRP$L_SVAPTE = SVA of the PTE that maps the 1st page of the buffer
;	R2 - Write function indicator = 1
;
	.MACRO	CALL_WRITELOCK ?L1

	$SETUP_CALL64	ARG_COUNT=6
        $PUSH_ARG64	R1		; Param6 = buffer size in bytes
        $PUSH_ARG64	R0		; Param5 = 64-bit buffer address
	$PUSH_ARG64	R6		; Param4 = pointer to CCB.
        $PUSH_ARG64	R5		; Param3 = pointer to UCB
        $PUSH_ARG64	R4		; Param2 = pointer to PCB
        $PUSH_ARG64	R3		; Param1 = pointer to IRP
        $CALL64 EXE_STD$WRITELOCK	; Lock buffer for I/O write to dev
	.BRANCH_LIKELY
	BLBS	R0,L1			; Success: YES - Cont. FDT processing.
	RET				; Return. ABORTIO called.
					; Now preserve JSB interface outputs.
L1:	MOVL	IRP$L_SVAPTE(R3),R1	; Get SVA of start of buffer in R1.
	CLRL	R2			; Indicate write function.

	.ENDM	CALL_WRITELOCK
;
; Macro to set up and call the Step 2 FDT support routine
; EXE_STD$WRITELOCK with an error callback routine for former users of the
; obsolete EXE$WRITELOCK_ERR routine.
;
; INPUTS:
;
;	INTERFACE_WARNING	- YES: Warn the user that the interface has
;				       changed since the conversion to call
;				       interfaces and the macro does not
;				       attempt to correct this inconsistancy.
;				- NO:  No warning will be issued.
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R6 - CCB
;	R0 - 64-bit address of I/O buffer
;	R1 - Size of I/O buffer
;	R2 - Caller's error callback routine with standard call interface
;
; IMPLICIT OUTPUTS:
;
;	R0 - Status
;	R1 - IRP$L_SVAPTE = SVA of the PTE that maps the 1st page of the buffer
;	R2 - Write function indicator = 1
;
	.MACRO	CALL_WRITELOCK_ERR INTERFACE_WARNING=YES ?L1

    .IF DIFFERENT,INTERFACE_WARNING,NO	; Validate INTERFACE_WARNING keyword.
    .IF DIFFERENT,INTERFACE_WARNING,YES ; If not 'NO' and not 'YES' give warning
    .ERROR 0 ;Keyword %EXTRACT(0,17,<INTERFACE_WARNING>) must be YES or NO;
    .ENDC
    .ENDC

    .IF IDENTICAL,INTERFACE_WARNING,YES ; Give the interface warning.
    .WARN  0 ;$WRITELOCK_ERR interface changed: R2 must have a standard call interface. Set Keyword %EXTRACT(0,17,<INTERFACE_WARNING>)=NO to suppress message.;
    .ENDC

	$SETUP_CALL64	ARG_COUNT=7
	$PUSH_ARG64	R2		; Param7 = caller's error call back routine,
        $PUSH_ARG64	R1		; Param6 = buffer size in bytes
        $PUSH_ARG64	R0		; Param5 = 64-bit buffer address
	$PUSH_ARG64	R6		; Param4 = pointer to CCB.
        $PUSH_ARG64	R5		; Param3 = pointer to UCB
        $PUSH_ARG64	R4		; Param2 = pointer to PCB
        $PUSH_ARG64	R3		; Param1 = pointer to IRP
        $CALL64 EXE_STD$WRITELOCK	; Lock buffer for I/O write to dev
	.BRANCH_LIKELY
	BLBS	R0,L1			; Success: YES - Cont. FDT processing.
	RET				; Return. Callback & ABORTIO called.
					; Now preserve JSB interface outputs.
L1:	MOVL	IRP$L_SVAPTE(R3),R1	; Get SVA of start of buffer in R1.
	CLRL	R2			; Indicate write function.

	.ENDM	CALL_WRITELOCK_ERR

;
; Macro to set up and call the Step 2 FDT support routine
; COM_STD$SETATTNAST.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R6 - CCB
;	R7 - AST list head.
;
	.MACRO	CALL_SETATTNAST ?L1

	PUSHL	R7			; Pass pointer to AST list head.
	PUSHL	R6			; Pass pointer to CCB.
	PUSHL	R5			; Pass pointer to UCB.
	PUSHL	R4			; Pass pointer to PCB.
	PUSHL	R3			; Pass pointer to IRP.
	CALLS	#5,G^COM_STD$SETATTNAST	;
	.BRANCH_LIKELY
	BLBS	R0,L1			; Success: YES - Cont. FDT processing.
	RET				; Return. ABORTIO called.
L1:
	.ENDM	CALL_SETATTNAST
;
; Macro to set up and call the Step 2 FDT support routine
; COM_STD$SETCTRLAST.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;	R6 - CCB
;	R7 - AST list head
;	R2 - Summary mask address.
;
	.MACRO	CALL_SETCTRLAST ?L1

	SUBL	#4,SP			; Allocate stack for returned TAST addr.
	PUSHAB	(SP)			; Point to TAST addr on stack.
	PUSHL	R2			; Pass pointer to current summary mask.
	PUSHL	R7			; Pass pointer to AST list head.
	PUSHL	R5			; Pass pointer to UCB.
	PUSHL	R4			; Pass pointer to PCB.
	PUSHL	R3			; Pass pointer to IRP.
	CALLS	#6,G^COM_STD$SETCTRLAST	; Make the call.
	.BRANCH_LIKELY
	BLBS	R0,L1			; Success: YES - Cont. FDT processing.
	RET				; Return. ABORTIO called.
					; Now preserve JSB interface outputs.
L1:	MOVL	(SP),R2			; Retrieve TAST addr from stack to R2.
	ADDL	#4,SP			; Clean up stack.

	.ENDM	CALL_SETCTRLAST
;
;
;
; Macro to set up and call the Step 2 FDT Completion routine
; EXE_STD$QIOACPPKT.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R4 - PCB
;	R5 - UCB
;
	.MACRO	CALL_QIOACPPKT -
			DO_RET=YES	; (Optional) Automatic RET insertion.

	.IF	DIFFERENT,DO_RET,NO	; Validate DO_RET keyword.
	  .IF	DIFFERENT,DO_RET,YES	; If not 'NO' and not 'YES' give warn.
	    .ERROR 0 ;Keyword %EXTRACT(0,6,<DO_RET>) must be either YES or NO;
	  .ENDC
	.ENDC

	PUSHL	R5			; Pass pointer to UCB.
	PUSHL	R4			; Pass pointer to PCB.
	PUSHL	R3			; Pass pointer to IRP.
	CALLS	#3,G^EXE_STD$QIOACPPKT	; Queue the ACP I/O Request packet.

	.IF IDENTICAL,DO_RET,YES
	RET				; Provide the RET instruction.
	.ENDC

	.ENDM	CALL_QIOACPPKT
;
; Macro in-line the function of the Step 2 FDT Completion routine
; EXE_STD$QIODRVPKT.
;
; IMPLICIT INPUTS:
;
;	R3 - IRP
;	R5 - UCB
;
	.MACRO	CALL_QIODRVPKT -
			DO_RET=YES	; (Optional) Automatic RET insertion.

	.IF	DIFFERENT,DO_RET,NO	; Validate DO_RET keyword.
	  .IF	DIFFERENT,DO_RET,YES	; If not 'NO' and not 'YES' give warn.
	    .ERROR 0 ;Keyword %EXTRACT(0,6,<DO_RET>) must be either YES or NO;
	  .ENDC
	.ENDC

	CLRL	IRP$PS_FDT_CONTEXT(R3)	; Clear the FDT CONTEXT pointer.
	PUSHL	R5			; UCB address for input.
	PUSHL	R3			; IRP address for input.
	CALLS	#2,EXE_STD$INSIOQ	; Insert the IRP on the device queue.
	MOVZWL	#SS$_FDT_COMPL,R0	; Set completion status.

	.IF IDENTICAL,DO_RET,YES
	RET				; Provide the RET instruction.
	.ENDC

	.ENDM	CALL_QIODRVPKT


;
;	Macros for Post Step 2 routines
;
;   These macros assist in fetching of arguments for Post Step 2 inbound driver
;   routines with call interfaces. The macros are provided for consistency with
;   Step 2 conventions. The PRESERVE parameter takes a list
;   of registers which are passed to the .CALL_ENTRY directive.	
;   The FETCH parameter controls whether the macro generates instructions to
;   move the arguments from the stack into the registers which the JSB interface
;   had defined.  This defaults to YES.	 If NO is specified the programmer
;   is responsible for finding the arguments at offsets to the AP.
;
;   The macro will always declare symbolic AP offsets for the arguments in the
;   form ARG$_name, and a .CALL_ENTRY directive.
;
	.MACRO $DRIVER_PENDING_IO_ENTRY PRESERVE, FETCH=YES

		.IF DIFFERENT,FETCH,YES  ; Validate FETCH parameter
			.IF DIFFERENT,FETCH,NO
			.ERROR 0 ;Keyword %EXTRACT(0,5,<FETCH>) must either be YES or NO;
			.ENDC
		.ENDC

		$OFFDEF PENDING_IO_ARG, < -
			LIST_HEAD, -
			IRP >

		$$$USE_PRESERVE = 1
		.IIF	IDENTICAL,<PRESERVE>,<NULL>, $$$USE_PRESERVE = 0
		.IIF	IDENTICAL,<PRESERVE>,<null>, $$$USE_PRESERVE = 0

		.IF	EQ,$$$USE_PRESERVE-1
		   .CALL_ENTRY %EXTRACT(0,8,<PRESERVE>) = <PRESERVE>
		.IF_FALSE
		   .CALL_ENTRY
		.ENDC

		.IF IDENTICAL FETCH YES
		MOVL	PENDING_IO_ARG$_LIST_HEAD(AP), R1
		MOVL	PENDING_IO_ARG$_IRP(AP), R3
		.ENDC
	.ENDM



;++
; INITIATE_SETUP - Clears UCB cancel, timout and loads IRP diagbuf
;
;   Make I/O setup a bit more convenient 
;
; INPUTS:
;
; 	UCB		Default = R5
;	IRP		Default = R3
;	TEMP_REG        Default = R22  
;			
; OUTPUTS:
;
;       None  
;--
        .MACRO INITIATE_SETUP UCB=R5, IRP=R3, TEMP_REG=R22, ?L1, ?L2

	.GLOBAL PMS_STD$START_IO

   .IF DF	CA$_MEASURE_IOT

	.BRANCH_LIKELY
	BBC	#IRP$V_DOPMS,IRP$L_STS(IRP),L1 ; Branch if no performance monitoring
	PUSHL	IRP			; One param
	CALLS #1,PMS_STD$START_IO	; insert start of I/O transaction msg
   .ENDC

L1:	BICL	#UCB$M_CANCEL!UCB$M_TIMOUT,UCB$L_STS(UCB) ;Clear cancel and time out
	.BRANCH_LIKELY
	BBC	#IRP$V_DIAGBUF,IRP$L_STS(IRP),L2 	; Branch if no diagnostic buffer
	MOVL	@IRP$L_DIAGBUF(IRP),TEMP_REG		; Get address of diagnostic buffer data area
	MOVQ	G^EXE$GQ_SYSTIME,(TEMP_REG)		; Insert I/O operation start time7
L2:

	.ENDM	INITIATE_SETUP

;++
; INCREMENT_IOCNT - Increment counter
;
;   Increments debugging counter in IOCNT structure off UCB
;   if such a structure exists.
;
; INPUTS:
;
;	COUNTER   Name of the field to increment (macro prefixes with IOCNT$L_ )
; 	UCB	  	Default = R5
;	TEMP_REG        Default = R22
;
; OUTPUTS:
;
;       None  
;--
        .MACRO INCREMENT_IOCNT  COUNTER, UCB=R5, TEMP_REG=R22, ?L1

	$IOCNTDEF

	MOVL	UCB$PS_IO_COUNTERS(UCB),TEMP_REG
	BEQL	L1
	INCL 	IOCNT$L_'COUNTER(TEMP_REG)
L1:
	.ENDM	INCREMENT_IOCNT


;++
; CALL_REQCOM_LOCAL - I/O Request Completion, Local IOPOST Queue
;
; INPUTS:
;
;       CDRP 		Default = R5 
;			Class driver request packet, 
;			containing IRP I/O status and UCB pointer
;
; IMPLICIT INPUTS:  	I/O status is already in CDRP
;
; IMPLICIT OUTPUTS: 
;
;       None
;--
        .MACRO  CALL_REQCOM_LOCAL CDRP=R5

	.GLOBAL	IOC_STD$REQCOM_LOCAL     
                                          ; Push input parameter...
        PUSHL   CDRP                      ; CDRP 
        CALLS   #1,G^IOC_STD$REQCOM_LOCAL ; Make the call

        .ENDM   CALL_REQCOM_LOCAL

;++
; IOFORK_CPU - Create fork thread on desired CPU
;
; INPUTS:
;
;       FKB		Fork block used to create fork thread 
;			Note: FPC and FLCK must already set up in FKB
;			and written to main memory with a memory barrier.
;
;	CURRENT_CPUDB 	Register containing Current CPU database address.
;       	     				
;	DESTIN_CPUDB	Register containing CPUDB address where fork thread 
;			will be queued. Register cannot be R0.
;	
;
; IMPLICIT INPUTS:  
;
; IMPLICIT OUTPUTS: 
;	R0, R1, R16 trashed by MTPR
;--

.MACRO  IOFORK_CPU         FKB,CURRENT_CPUDB,DESTIN_CPUDB,TEMP_REG1=R22, -
			   TEMP_REG2=R23, ?L1, ?L2, ?L3

	$CPUDEF				; CPU definitions

	CMPL    CURRENT_CPUDB,DESTIN_CPUDB; Are we on desired CPU?
	BNEQ	L1			; No, go do ipint
;
; 	Else insert the FKB on the IPL 8 fork queue and softint if needed. 
;
ASSUME CPU$S_SWIQFL/CPU$K_NUM_SWIQS EQ 8 ; Assumption required for offest 
FQH_SIZE=8                      	;  Size of queue header 
OFFSET8=<<8-6>*FQH_SIZE>+4		; Offset to tail of IPL8 fork queue 

        INSQUE  FKB, - 			; Insert FKB on tail of IPL8 fork Q
                @CPU$Q_SWIQFL+OFFSET8(CURRENT_CPUDB)

        BNEQ    L3                      ; Branch if queue is populated to avoid
                                        ; unneeded IPL8 interrupt
        SOFTINT S^#IPL$_IOLOCK8         ; Request fork at IPL 8
	BRW 	L3			; and get out of here
;
;       Put FKB on interrupt affinity queue and IPINT if needed.
;
L1:	$INSQTI	 FKB,-			; Insert FKB (note R0 trashed)
		CPU$PS_IO_INT_AFF_QFL(DESTIN_CPUDB)
	BNEQ	L3	    			; Branch if queue not empty 
						; Else have to IPINT 
        MOVAB	CPU$L_WORK_REQ(DESTIN_CPUDB), -
		 TEMP_REG1			; Get work request addr 

L2:	EVAX_LDLL -
		TEMP_REG2,(TEMP_REG1)		; Load temp2 from work req
	BISL 	#CPU$M_IO_INT_AFF,TEMP_REG2	; Tell other CPU why the IPINT
	EVAX_STLC -
		TEMP_REG2,(TEMP_REG1)		; Try to store 	
	.BRANCH_UNLIKELY 
  	EVAX_BEQ TEMP_REG2,L2			; Try again on failure

	IPINT_CPU_FAST CPUDB=DESTIN_CPUDB	; Send IPINT

L3:	
        .ENDM   IOFORK_CPU

;++
; IPINT_CPU_FAST - streamlined IPINT of a single CPU
;
; INPUTS:
;
;	CPUDB 	= address of the processor to be interrupted
;                 default = R1
; IMPLICIT INPUTS:
;
;	IPL is assumed to be at least 2.
;
; This macro replicates SMP$INTPROC. If that code has to
; change, the macro should probably change as well.
;
; Processor interrupts can be considered the same as write requests
; in terms of ordering problems under this architecture.  By generating
; an MB before the interrupt request it is guaranteed that any cells updates
; will be ordered ahead of the interrupt.
;
; MTPR instruction expects param in R16, leaves R0/R1/R16/R17 unpredictable. 
;
;--
        .MACRO  IPINT_CPU_FAST	CPUDB=R1

	MOVL 	CPU$L_PHY_CPUID(CPUDB),R16 	; Get physical CPU ID
	EVAX_MB					; Generate a Memory Barrier
	EVAX_MTPR_IPIR	R16			; Generate the interrupt
						; to the CPU
        .ENDM   IPINT_CPU_FAST


	.LIST
