	.TITLE	MKSET - Set magtape skipfile behavior
	.IDENT	'V02'
;****************************************************************************
;*                                                                          *
;*  COPYRIGHT © 1996 BY      						    *
;*  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.                 *
;*                                                                          *
;*                                                                          *
;****************************************************************************
	.PAGE
;+
;
; FACILITY:
;	Alpha or VAX utility to control MKdriver skipfile behavior
; 
; ABSTRACT:
;
; MKset is a short and sweet utility to set or reset fast skipfile
; mode with MKdriver. It's coded in Macro to make it simple to put
; on both Vax and Alpha in a hurry.
; It is derived from asnvd, which has been in use on Vax and Alpha
; for several years so most of it's debugged already. - gce
;
; Usage:
;  MKSET/ALWAYS  MKcnnn:	Set up device MKcnnn: to always use
;				skip by filemarks if hardware supports it
;  MKSET/NEVER   MKcnnn:	Set up device MKcnnn: to never use
;				skip by filemarks (but use skip by records!)
;  MKSET/PER_IO  MKcnnnn:	Set up device MKcnnnn: to skip by records
;				unless the io$_skipfile has the io$m_fastskip
;				modifier in the $qio function call.
;  MKSET/EVEN1   MKcnnnn:	Sets to allow fast skip even if 1 or 2
;				filemarks if otherwise it would be used
;  MKSET/DENSITY:vvv MKcnnnn:	Sets to use SCSI density vvv (decimal) 
;				instead of normal default (0)
;
; The MKcnnn: device MUST be a local SCSI tape controlled by MKdriver or
;	nothing will happen. The MK behavior is set up by a SETCHAR call
;	which requires PHY_IO privs and which has a null P1 parameter
;	so that any other driver's buffer check for normal io$_setchar
;	will cause the $qio to fail due to access violation. The device
;	name is checked to contain "MK", to have its devchar2 SCSI bit set
;	and its MSCP bit clear, to be of tape class, and to be a local
;	device to further ensure this utility sends no requests to a non
;	MK device, however low the risk of such may be.
; 
; AUTHOR:
; 
; Glenn Everhart	17-Oct-1996
;	Many parts taken from ASNVD by Glenn C. Everhart, 1988-1995
;
; REVISION HISTORY:
;--
	.PAGE
	.SBTTL	EXTERNAL AND LOCAL DEFINITIONS

; 
; EXTERNAL SYMBOLS
; 
; Note: There are a number of these defs that aren't needed in THIS
; util but are due to its history.
;
	$ATRDEF
	$DCDEF				;DEFINE DEVICE CLASS
	$DEVDEF				;DEFINE DEVICE CHARACTERISTICS
	$DVIDEF				;Symbols for $GETDVI service.
	$FABDEF
	$FIBDEF				;Symbols for file information block.
	$MTDEF
	$IODEF				;DEFINE I/O FUNCTION CODES
	$NAMDEF
	$PRDEF				;DEFINE PROCESSOR REGISTERS
	$RMSDEF
	$SSDEF				;DEFINE SYSTEM STATUS CODES
	$STRDEF
	$STSDEF				;Symbols for returned status.
	$TPADEF				;Symbols for LIB$TPARSE calls.
	$XABDEF


; Macro to check return status of system calls.
;
	.MACRO	ON_ERR	THERE,?HERE
	BLBS	R0,HERE
	BRW	THERE
HERE:	.ENDM	ON_ERR

;
;
;
	.PSECT	ADVDD_DATA,RD,WRT,NOEXE,LONG

	.ALIGN LONG
;
iosb:	.blkl	2
IOSTATUS: .BLKQ 1

;**
MKN_BUF:			; Buffer to hold device name.
	.BLKB	80		; (expect 64 bytes max)
MKN_BUF_SIZ = . - MKN_BUF

MKN_BUF_DESC:			; Descriptor pointing to device name.
	.WORD	MKN_BUF_SIZ
	.BYTE   DSC$K_DTYPE_T   ; TEXT TYPE
        .BYTE   1       	; STATIC STRING
	.ADDRESS MKN_BUF

MKN_BUF_USED:
	.LONG	0		; $getdvi returns actual length here
;**
DEFNAM:

WRK:	.BLKL	1	;SCRATCH INTEGER
; DESCRIPTOR FOR MKn: "FILENAME"
	.ALIGN LONG
MKFNM:	.WORD	 255.	;LENGTH
MKFTP:	.BYTE	DSC$K_DTYPE_T	;TEXT TYPE
	.BYTE	1	; STATIC STRING
	.ADDRESS	MKFNMD
MKFNMD:	.BLKB	256.	; DATA AREA
	.align long
wrkstr:	.word	20	;length
	.byte	dsc$k_dtype_t	;text
	.byte	1	;static
	.address	wrkdat
wrkdat:	.blkb	20
	.byte	0,0,0,0	;safety
	.blkl	128
;
MKCHN:	.LONG	0	;CHANNEL HOLDERS
; Item list for $getdvi which we use to be sure we really have a channel to
; an MK device (to the extent possible to quickly check)

VPID:				; Owner of device (if any).
	.BLKL	1

MKN_DEVCHAR2:	.LONG	0
MKN_REMOTE:	.LONG	0
MKN_ITEM_LIST:			; device list for $GETDVI.
	.WORD	 64	; Make sure we a have a physical device name.
	.WORD	 DVI$_DEVNAM
	.ADDRESS MKN_BUF
	.ADDRESS MKN_BUF_USED
	.WORD	4		; 4 byte boolean if dvc is remote
	.WORD	DVI$_REMOTE_DEVICE	; Be sure the device is local!
	.ADDRESS MKN_REMOTE
	.LONG	0
	.WORD	 4		; See if someone has this device allocated.
	.WORD	 DVI$_PID
	.ADDRESS VPID
	.LONG	 0
	.WORD	4		; DEVCHAR2 is 4 bytes long
	.WORD	DVI$_DEVCHAR2	; Get that item though
	.ADDRESS MKN_DEVCHAR2	; Put the data here
	.LONG	0		; and don't store the length anywhere
	.WORD	 4
	.WORD	 DVI$_DEVCLASS	; Check for a terminal.
	.ADDRESS MKN_CLASS
	.LONG	 0
	.LONG	 0		; End if item list.
	.LONG	0,0		; Safety
MKN_CLASS:
	.LONG	1		; We will check against dc$_tape later
;
; Name bit to look for in device name
MKSTR:	.ASCID	/MK/		; "MK" must exist in the device name.
	.ALIGN LONG
MKIDX1:	.LONG	0		; index of string
MKIDX2:	.LONG	0		; Index of substring
;
; FOR initial use, don't bother allocating the file. Assume the
; user can somehow allocate a contiguous file of the size he wants
; for himself.
;
P1DSC:	.ASCID	/UNIT/		; The device name we get given. Must be there.
fsfdsc:	.ascid	/ALWAYS/	;force fast-skip on
ssfdsc:	.ascid	/PER_IO/	;default condition, fcn modifier can get fast
				; but normal default is skip by records
frodsc:	.ascid	/NEVER/		;Forces mk to always skip by records
evndsc:	.ascid	/EVEN1/
dnsdsc:	.ascid	/DENSITY/
	.align long
fsfflg:	.long	0		;0 for default slow skip, 1 for fast skipfile
dnsval:	.long	0		;density scsi value
;
; Note it is REQUIRED that the following two areas remain contiguous.
dcl_cmd:        .ASCID  /MKSET /
cmdbuff:        .BLKB   256             ;This buffer must be contig with dcl_cmd
        .ALIGN  LONG
cmdline:        .WORD   0
                .BYTE   DSC$K_DTYPE_T
                .BYTE   DSC$K_CLASS_D
                .ADDRESS 0
        .EXTRN  MKSET_CLD
        .ALIGN LONG
;
ERROR:	.LONG	2
MESS:	.LONG	SS$_ABORT
	.LONG	0

	.PSECT	ADMKD_CODE,RD,NOWRT,EXE,LONG
	.ENTRY	ADMKD,^M<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11>
	clrl	dnsval
; Allow foreign command calling now
        PUSHAQ  CMDLINE         ;Get the foreign command line
        CALLS   #1,G^LIB$GET_FOREIGN
        ON_ERR  ADMKD_EXIT

; This hack will work where the command is MKSET. If it is not we may need
; to change the DCL_CMD string
        PUSHAQ  CMDLINE
        PUSHAQ  DCL_CMD
        PUSHAQ  CMDLINE
        CALLS   #3,G^STR$CONCAT

        PUSHAL  MKSET_CLD
        PUSHAQ  CMDLINE
        CALLS   #2,G^CLI$DCL_PARSE
        ON_ERR  ADMKD_EXIT

	CLRL	FSFFLG		;DEFAULT TO NOT FAST SKIP
	PUSHAB	FSFDSC		;/ALWAYS
	CALLS #1,G^CLI$PRESENT
	CMPL	R0,#CLI$_PRESENT
	BNEQ	42$		;IF NEQ NO
; Force skipfile to be used always if drive allows it.
	MOVL	#<IO$M_ALLOWFAST_ALWAYS>,FSFFLG
42$:
; Default skip behavior. Allow skip by files if fcn mod there in skipfiles
	PUSHAB	SSFDSC		;/PER_IO ?
	CALLS #1,G^CLI$PRESENT
	CMPL	R0,#CLI$_PRESENT
	BNEQ	142$		;IF NEQ NO
; Allow but do not force skipfile
	MOVL	#IO$M_ALLOWFAST_PER_IO,FSFFLG
142$:
	PUSHAB	WRK		;PUSH LONGWORD ADDR FOR RETLENGTH
	PUSHAB	MKFNM		;ADDRESS OF DESCRIPTOR TO RETURN
	PUSHAB	P1DSC		; GET P1 (MKn: UNIT)
	CALLS	#3,G^CLI$GET_VALUE	;GET VALUE OF NAME TO MKFNM
	ON_ERR	ADMKD_EXIT

; force skipfile new stuff OFF
	PUSHAB	FRODSC		;/NEVER
	CALLS #1,G^CLI$PRESENT
	CMPL	R0,#CLI$_PRESENT
	BNEQ	242$		;IF NEQ NO
	movl	#io$m_ALLOWFAST_NEVER,fsfflg
242$:
	pushab	evndsc		;/even1?
	calls	#1,g^CLI$PRESENT
	CMPL	R0,#CLI$_PRESENT
	bneq	243$
	movl	#<IO$M_ALLOWFAST_ALWAYS!io$m_ALLOWFAST_NEVER>,fsfflg
243$:
	pushab	dnsdsc		; /density:nn
	calls	#1,g^cli$present	;see if /dens cmd was given
	CMPL	R0,#CLI$_PRESENT
	bneq	245$
; ok, gotta get the value he said.
	pushab	wrk	; area for ret length
	pushab	wrkstr	; working string
	pushab	dnsdsc	; look for /dens:nnnn value
	calls	#3,g^cli$get_value	;get value string
	blbc	r0,245$		;if none given ignore it
	pushl	#17	; ignore blanks
	pushl	#4	; 4 byte result
	pushab	dnsval	; store into density value
	pushab	wrkstr	; get from work string
	movl	#<IO$M_ALLOWFAST_ALWAYS!io$m_ALLOWFAST_PER_IO>,fsfflg
	calls	#4,g^ots$cvt_tu_l	;convert the number
	blbs	r0,245$	; if all well, leave it there.
	clrl	dnsval	; on error use density 0
245$:
; MUST HAVE ASSIGNMENT TO MK: UNIT IN ANY CASE.
	$ASSIGN_S -
		DEVNAM=MKFNM,-		; GET CHANNEL FOR MKn:
		CHAN=MKCHN
	ON_ERR	ADMKD_EXIT		; SKIP OUT IF ERROR
; Now we want to find something out about the device, to check if we can
; that this is a local MK device. For this we use  $getdvi.
	$GETDVI_S -
		CHAN=MKchn,-		; Command line has device name.
		ITMLST=MKN_ITEM_LIST
	BLBS	R0,140$
	BRW	adMKd_EXIT
140$:
	MOVW	MKN_BUF_USED,MKN_BUF_DESC	; Set descriptor size right
;
; Check that this is (apparently) an MK device.
;MKN_DEVCHAR2:	.LONG	0
	BITL	#DEV$M_MSCP,MKN_DEVCHAR2	; If this is an MSCP device
	BEQL	340$
; The MSCP bit is set...can't be an MK
341$:	MOVL	#SS$_IVDEVNAM,R0		; Use a plausible err code
	BRW	ADMKD_EXIT
340$:
	BITL	#DEV$M_SCSI,MKN_DEVCHAR2	; Be sure the SCSI bit is set
	BEQL	341$				; or fail and exit
;
; Check that the class is tape.
	CMPL	MKN_CLASS,#DC$_TAPE
	BNEQ	341$				; if not tape, skip out
; check that the device is local
	TSTL	MKN_REMOTE
	BNEQ	341$				; If device is not local, don't use
;
; Check that the name of the device starts with "MK" in MKN_buf
	tstw	MKN_buf_desc	; Be sure no zero length source is there
	bleq	341$
	pushab	mkstr		; Substring is arg 3
	pushab	mkidx1		; String index
	pushab	mkidx2		; substring index
	pushab	MKN_buf_desc	; Main string
	CALLS	#4,g^STR$FIND_FIRST_SUBSTRING
	TSTL	R0		; Did we find at least one?
	BEQL	341$		; if R0 is 0, we found none so exit
;
; Looks like it might be an MK device and local.
; Now do the work.
; We use the couple of function modifiers below to tell mkdriver what to do
; and it ignores the rest of setmode. This is done at FDT time in the
; driver.
;
; Now verify this is indeed an MKDRIVER unit.
; First, does its name start with "MK"?
; (DCL will upcase the name for us.)
; MKfnmd has name data

; ISSUE the command to dkdriver
; (The following line allows us to switch to another base function
;  very quickly. Setchar for magtape is good, though, since it normally
;  just returns illiofunc, so nothing's going to already be using it.)
basefunc=io$_setchar	;function we modify for mkdriver
; Note that another setchar function would have a buffer,so if this
; $qio gets to a driver not expecting it, it'll get accvio errs in the
; normal sysqiofdt routines. Thus this will not be mistaken for a real
; setchar anywhere, but will alter skipfile functions as it should.
;
; Note too that the MK code expects ONE qualifier only to be set,
; not more.
	MOVL	FSFFLG,R0
	ADDL2	#BASEFUNC,R0
; Note we do NOT have a P1, so it remains zero here and will thus cause
; an accvio if some driver other than mkdriver is used, unless of course
; some user driver also overloads setchar.
	movab	wrkstr,r3
	$QIOW_S	EFN=#0,CHAN=MKCHN,FUNC=r0,IOSB=IOSB,p1=(r3),p2=dnsval
	$DASSGN_S CHAN=MKCHN
	MOVL	IOSB,R0		; Return IOSB status
	BNEQ	500$
	MOVL	#SS$_UNSUPPORTED,R0
500$:
	RET
ADMKD_EXIT:
	RET
	.END ADMKD
