summaryrefslogtreecommitdiff
path: root/vms
diff options
context:
space:
mode:
Diffstat (limited to 'vms')
-rw-r--r--vms/000readme175
-rw-r--r--vms/build.com34
-rw-r--r--vms/defs.h42
-rw-r--r--vms/descrip.mms77
-rw-r--r--vms/ldrset.c183
-rw-r--r--vms/ldrset.cld9
-rw-r--r--vms/ldrutil.mar104
-rw-r--r--vms/scsi.c400
8 files changed, 1024 insertions, 0 deletions
diff --git a/vms/000readme b/vms/000readme
new file mode 100644
index 0000000..854d58a
--- /dev/null
+++ b/vms/000readme
@@ -0,0 +1,175 @@
+MTX -- SCSI Tape Attached Medium Changer Control Program
+
+Copyright 1997 by Leonard N. Zubkoff <lnz@dandelion.com>
+
+VMS port, April 1998, by TECSys Development, Inc.
+
+SECTION I - Disclaimer
+
+ These programs / ports are distributed in the hopes that they
+ will be useful, but WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+ While a significant amount of testing has been performed, and while
+ TDI believes that this utility is safe, ONLY YOU can make that
+ determination with respect to your environment. There are NO
+ GUARANTEES WHATSOEVER that use of this program will not CRASH
+ YOUR SYSTEM or worse. TDI disclaims any responsibility for any
+ losses or damages from the use of this program.
+
+SECTION II - MTX program
+
+***CAUTIONS***
+ * Attempting to check the status of the drive with 1 tape manually
+ inserted in the drive, and no magazine results in an unexpected
+ SCSI status message. During porting of this program on a VS4000/90a,
+ it is believed that the handling of this status message caused
+ some sort of scsi state problem wherein subsequent accesses to
+ the changer from normal MKDRIVER activity resulted in SCSI bus
+ phase errors and an ultimate system failure. Power cycles of both
+ the drive and the host were required to rectify the problem.
+
+Instructions:
+ Read instructions (particularly section III below on the LDRSET utility).
+ Compile (DEC C) and link image, copy to an appropriate install location
+ Define a foreign symbol to access the program
+ Use UNIX syntax to operate program per documentation (MTX.DOC)
+
+ A descrip.mms file is provided if you have MMS or MMK installed.
+ You can build everything from scratch by doing a MMK/FROM_SOURCE. This
+ includes the LDRSET utility described below. You should be in the mtx
+ root directory before you do this, NOT [.vms].
+
+ If you do not have or use MMS or MMK, I can highly recommend MMK as
+ a great tool. It is available from www.madgoat.com. If you still do
+ not have mmk or mms, a build.com is provided. Again, you should be in
+ the mtx root directory before you do this, NOT [.vms].
+
+ Note: If you are on an alpha, the mms[k]-built exe files will be called
+ .alpha_exe, not .exe. Adjust following instructions accordingly.
+
+Example:
+ $ MMS/DESCRIP=[.VMS] !Or MMK, or @[.VMS]BUILD
+ $ copy mtx.exe DISK$USERDISK:[USERS.FRED.UTILS]MTX
+ $ MTX:==$DISK$USERDISK:[USERS.FRED.UTILS]MTX.EXE
+ $ MTX -f MKA500 status
+ --or--
+ $ DEFINE TAPE MKA500
+ $ MTX status
+
+Notes:
+ * This code does NOT compile under VAX C... the only issue is VAX C's
+ incorrect assertion that a 'boolean' is not an acceptable "expression"
+ on either side of a || operator. If you are on VAX C - upgrade. If you
+ really must... then use a ((int)...) around the left-hand-side
+ of the lines where the compiler complains.... like so:
+ if (((int)StorageElementFull[FirstStorageElementNumber]) ||
+
+ * The following symbols result from 'status' or element movement commands:
+ MTX_DTE (Data Transfer Element)
+ FULL:n (Full, with element 'n'... if n=0, then unknown ele)
+ EMPTY
+ MTX_MSZ (Magazine SiZe)
+ n (Number of magazine slots)
+ MTX_STE01 thru MTX_STExx (STorage Element, Max is MTX_MSZ)
+ FULL
+ EMPTY
+ These will allow a DCL program to process the results
+ of the status command
+
+ * PHY_IO and DIAGNOSE are required to run the program as it stands
+ today. Yes, the GKdriver dox say PHY_IO or LOG_IO.... MKdriver
+ thinks otherwise. It wins.
+
+ * The program IS equipped to handle being installed with DIAGNOSE
+ and PHY_IO. A certain level of checking is done to see that the
+ right type of device is being targeted for the autoloader manipulation
+ SCSI commands. [see next item]
+
+ * There is an indicator bit in DEVCHAR2 that indicates the presence of
+ a loader on a tape. Unfortunately, it appears that the "knowledge" of
+ whether a loader is present or not is hard-coded into mkdriver. This
+ means that if you don't have the magic DEC rom's in your Archive
+ loader, then the LDR bit is not set. This makes the LDR bit effectively
+ useless unless you want to write a kernel dinker program you could
+ run from startup to "fix" the DEVCHAR2 longword. (Incidentally,
+ if you ship the autoloader commands at a TZ30 (a non-loader drive),
+ the tz30 blows it off w/o any adverse side-effects - I would hope
+ that other drives are as tolerant.)
+
+ Because of this misfeature, the code to check the LDR flag in DEVCHAR2
+ is commented out.
+
+ *See section below on LDRSET utility if you want to use this
+ feature anyway (recommended).
+
+ * This program has been tested under:
+ VAX C V2.2, VAX/VMS 6.1, VS 4000/90A **with code modifications
+ DEC C V5.2, VAX/VMS 6.1, VS 4000/90A
+ DEC C V5.3, AXP/VMS 6.2, DEC3000-300X
+
+
+SECTION III - LDRSET Utility
+
+Description:
+ This is a small KERNEL MODE utility program to go set or reset
+ the DEV$M_LDR flag in UCB$L_DEVCHAR2 for a specified device. While
+ a certain amount of checking is performed, and while the author
+ believes that this utility is safe, ONLY YOU can make that
+ determination with respect to your environment. There are NO
+ GUARANTEES WHATSOEVER that use of this program will not CRASH
+ YOUR SYSTEM or worse. TDI disclaims any responsibility for any
+ losses or damages from the use of this program.
+
+ With all that said... this utility can be used [example: system
+ startup] to set the LDR flag for the autoloader tape device.
+ With the loader flag properly set, you can re-enable the LDR
+ check section in MTX and be fairly well certain that the MTX
+ utility will not be used against a drive that is not a SCSI
+ MAGTAPE with a LOADER attached.
+
+Instructions:
+ Compile (DEC C ***ONLY***) the LDRSET C program
+
+ Alpha:
+ MACRO/MIGRATE the LDRUTIL.MAR program
+ LINK LDRSET,LDRUTIL/SYSEXE to generate the image
+
+ Vax
+ MACRO the LDRUTIL.MAR program
+ LINK LDRSET,LDRUTIL to generate the image
+
+ [NOTE!!! ---> DO NOT USE RESULTING IMAGE IF THERE ARE ANY COMPILE OR LINK
+ ERRORS!!!]
+
+ Copy to an appropriate install location.
+
+ Edit provided CLD file to reflect the installed location
+
+ Use the following syntax:
+ $ SET COMMAND LDRSET
+ $ LDRSET MKA500: /SET !Sets the loader present flag on MKA500
+ $ LDRSET MKA500: /RESET !Clears the loader present flag on MKA500
+
+Alpha example:
+ $ CC/DECC/DEBUG/NOOPT LDRSET
+ $ MACRO/MIGRATE LDRUTIL
+ $ LINK LDRSET,LDRUTIL/SYSEXE
+
+Vax example:
+ $ CC/DECC/DEBUG/NOOPT LDRSET
+ $ MACRO LDRUTIL
+ $ LINK LDRSET,LDRUTIL
+
+Common:
+ $ copy LDRSET.EXE DISK$USERDISK:[USERS.FRED.UTILS]LDRSET.EXE
+ $ copy LDRSET.CLD DISK$USERDISK:[USERS.FRED.UTILS]LDRSET.CLD
+ $ EDIT DISK$USERDISK:[USERS.FRED.UTILS]LDRSET.CLD
+ ...change image sys$disk:[]ldrset line to :
+ image DISK$USERDISK:[USERS.FRED.UTILS]LDRSET.EXE
+ $ LDRSET MKA500 /SET
+
+ * This program has been tested under:
+ DEC C V5.2, VAX/VMS 6.1, VS 4000/90A
+ DEC C V5.6, AXP/VMS 7.1, AS 1000A
+
diff --git a/vms/build.com b/vms/build.com
new file mode 100644
index 0000000..2f6308d
--- /dev/null
+++ b/vms/build.com
@@ -0,0 +1,34 @@
+$!x='f$ver(0)
+$ if f$parse("[.VMS]A.A").eqs.""
+$ then
+$ write sys$output "?Error: Use $ @[.VMS]BUILD from the mtx directory"
+$ exit 44
+$ endif
+$ alpha = f$getsyi("hw_model").ge.1024
+$ vax = .not.alpha
+$ exe = "EXE"
+$ obj = "OBJ"
+$ sysexe=""
+$ migrate=""
+$ if alpha then exe="ALPHA_EXE"
+$ if alpha then obj="ALPHA_OBJ"
+$ if alpha then sysexe="/SYSEXE"
+$ if alpha then migrate="/MIGRATION/NOOPT"
+$ set verify
+$ if "''p1'".eqs."LINK" then goto do_link
+$ CC /DECC/DEB/NOOP MTX.C/DEB/NOOP/OBJECT=MTX.'obj'
+$ if f$search("MTX.''obj';-1").nes."" then -
+ purge/log MTX.'obj'
+$ CC /DECC/DEB/NOOP [.VMS]LDRSET.C/DEB/NOOP/OBJECT=[.VMS]LDRSET.'obj'
+$ if f$search("[.VMS]LDRSET.''obj';-1").nes."" then -
+ purge/log [.VMS]LDRSET.'obj'
+$ MACRO'migrate' /DEB [.VMS]LDRUTIL.MAR -
+ /OBJECT=[.VMS]LDRUTIL.'obj'
+$ if f$search("[.VMS]LDRUTIL.''obj';-1").nes."" then -
+ purge/log [.VMS]LDRUTIL.'obj'
+$!
+$ do_link:
+$ link/notrace mtx.'obj'/exe=mtx.'exe'
+$ link [.vms]ldrset.'obj',[.vms]ldrutil.'obj' -
+ /exe=ldrset.'exe' 'sysexe'
+$ exit
diff --git a/vms/defs.h b/vms/defs.h
new file mode 100644
index 0000000..68dd7d7
--- /dev/null
+++ b/vms/defs.h
@@ -0,0 +1,42 @@
+#ifdef __DECC
+#pragma module MTX "V01-00"
+#else
+#module MTX "V01-00"
+#endif
+
+typedef int DEVICE_TYPE;
+
+#include <ssdef.h>
+#include <lib$routines.h>
+#include <ots$routines.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <iodef.h>
+#include <descrip.h>
+#include <dcdef.h>
+#include <devdef.h>
+#include <dvidef.h>
+#include <starlet.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <prvdef.h>
+
+#if defined(__DECC)
+#pragma member_alignment save
+#pragma nomember_alignment
+#endif
+
+/*
+ Define either of the following symbols as 1 to enable checking of
+ the LDR flag for specified devices. DO NOT set these bits if you
+ do not 1) have a DEC-recognized autoloader, or 2) use the LDRSET
+ utility to set the LDR flag for the target devices.
+*/
+
+#define USING_DEC_DRIVE 0
+#define USING_LDRSET 0
+
+static unsigned long VMS_ExitCode = SS$_ABORT;
diff --git a/vms/descrip.mms b/vms/descrip.mms
new file mode 100644
index 0000000..fb08467
--- /dev/null
+++ b/vms/descrip.mms
@@ -0,0 +1,77 @@
+!
+! MMS System build for MTX and LDRSET utility
+!
+!Global build flag macros
+!
+CDEBUG = /DEB/NOOP
+MDEBUG = /DEB
+
+CFLAGS = /DECC$(CDEBUG)
+MFLAGS = $(MDEBUG)
+
+.IFDEF __AXP__
+.SUFFIXES .ALPHA_OBJ
+MFLAGS = /MIGRATE$(MFLAGS)/NOOP
+DBG = .ALPHA_DBG
+EXE = .ALPHA_EXE
+OBJ = .ALPHA_OBJ
+OPT = .ALPHA_OPT
+SYSEXE=/SYSEXE
+
+.ELSE
+DBG = .DBG
+EXE = .EXE
+OPT = .OPT
+OBJ = .OBJ
+SYSEXE=
+
+.ENDIF
+
+PURGEOBJ = if f$search("$(MMS$TARGET_NAME)$(OBJ);-1").nes."" then purge/log $(MMS$TARGET_NAME)$(OBJ)
+
+!
+!Bend the default build rules for C, MACRO, and MESSAGE
+!
+.C$(OBJ) :
+ $(CC) $(CFLAGS) $(MMS$SOURCE)$(CDEBUG)/OBJECT=$(MMS$TARGET_NAME)$(OBJ)
+ $(PURGEOBJ)
+.MAR$(OBJ) :
+ $(MACRO) $(MFLAGS) $(MMS$SOURCE)$(MDEBUG)/OBJECT=$(MMS$TARGET_NAME)$(OBJ)
+ $(PURGEOBJ)
+.CLD$(OBJ) :
+ SET COMMAND/OBJECT=$(MMS$TARGET_NAME)$(OBJ) $(MMS$SOURCE)
+ $(PURGEOBJ)
+.MSG$(OBJ) :
+ MESSAGE $(MMS$SOURCE)/OBJECT=$(MMS$TARGET_NAME)$(OBJ)
+ $(PURGEOBJ)
+
+
+DEFAULT : ERROR,-
+ MTX,-
+ LDRSET
+ @ !
+
+ERROR :
+ @ if f$parse("[.VMS]A.A").eqs."" then write sys$output "?Error: Use $ MMS/DESCRIP=[.VMS] from the mtx directory"
+
+MTX : mtx$(EXE)
+ @ !
+
+mtx$(EXE) : mtx$(OBJ)
+ $ link/notrace mtx$(OBJ)/exe=mtx$(EXE)
+
+mtx$(OBJ) : mtx.c,[.vms]scsi.c,[.vms]defs.h
+
+LDRSET : ldrset$(EXE),ldrset.cld
+ @ !
+
+ldrset.cld : [.vms]ldrset.cld
+ $ copy [.vms]ldrset.cld []/log
+
+ldrset$(EXE) : [.vms]ldrset$(OBJ),[.vms]ldrutil$(OBJ)
+ $ link [.vms]ldrset$(OBJ),[.vms]ldrutil$(OBJ)/exe=ldrset$(EXE)$(SYSEXE)
+
+[.vms]ldrset$(OBJ) : [.vms]ldrset.c
+
+[.vms]ldrutil$(OBJ) : [.vms]ldrutil.mar
+
diff --git a/vms/ldrset.c b/vms/ldrset.c
new file mode 100644
index 0000000..c0efd0c
--- /dev/null
+++ b/vms/ldrset.c
@@ -0,0 +1,183 @@
+/* LDRSET - Set the state of the LDR flag in UCB$L_DEVCHAR2 for a
+** SCSI magtape. REQUIRES CMKRNL privilege.
+**
+** Copyright 1999 by TECSys Development, Inc. http://www.tditx.com
+**
+** This program is free software; you may redistribute and/or modify it under
+** the terms of the GNU General Public License Version 2 as published by the
+** Free Software Foundation.
+**
+** This program is distributed in the hope that it will be useful, but
+** WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
+** or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+** for complete details.
+**
+** Description:
+** This is a small KERNEL MODE utility program to go set or reset
+** the DEV$M_LDR flag in UCB$L_DEVCHAR2 for a specified device. While
+** a certain amount of checking is performed, and while the author
+** believes that this utility is safe, ONLY YOU can make that
+** determination with respect to your environment. There are NO
+** GUARANTEES WHATSOEVER that use of this program will not CRASH
+** YOUR SYSTEM or worse. TDI disclaims any responsibility for any
+** losses or damages from the use of this program.
+**
+** With all that said... this utility can be used [example: system
+** startup] to set the LDR flag for the autoloader tape device.
+** With the loader flag properly set, you can re-enable the LDR
+** check section in MTX and be fairly well certain that the MTX
+** utility will not be used against a drive that is not a SCSI
+** MAGTAPE with a LOADER attached.
+**
+**
+** LDRSET.CLD:
+** define verb LDRSET
+** image sys$disk:[]ldrset.exe
+** parameter p1, label=device,
+** prompt="Device",
+** value(required,type=$FILE)
+** qualifier SET, nonnegatable
+** qualifier RESET, nonnegatable
+** disallow any2 (SET, RESET)
+** disallow NOT SET AND NOT RESET
+*/
+#ifdef __DECC
+#pragma module LDRSET "V01-00"
+#else
+#module LDRSET "V01-00"
+#endif
+
+#include <ssdef.h>
+#include <dcdef.h>
+#include <devdef.h>
+#include <dvidef.h>
+#include <descrip.h>
+#include <stdio.h>
+#include <string.h>
+#include <lib$routines.h>
+#include <starlet.h>
+
+#ifndef DESCR_CNT
+#define DESCR_CNT 16
+/* MUST BE of the form 2^N!, big enough for max concurrent usage */
+#endif
+
+static struct dsc$descriptor_s *
+descr(
+ char *str)
+{
+static struct dsc$descriptor_s d_descrtbl[DESCR_CNT]; /* MAX usage! */
+static unsigned short int descridx=0;
+ struct dsc$descriptor_s *d_ret = &d_descrtbl[descridx];
+
+ descridx = (descridx+1)&(DESCR_CNT-1);
+
+ d_ret->dsc$w_length = strlen((const char *)str);
+ d_ret->dsc$a_pointer = (char *)str;
+
+ d_ret->dsc$b_class =
+ d_ret->dsc$b_dtype = 0;
+ return(d_ret);
+}
+
+extern unsigned long int finducb();
+extern unsigned long int _setldr();
+extern unsigned long int _clrldr();
+
+unsigned long int
+set_ldrstate(
+ int devch,
+ int setstate)
+{
+ unsigned long int ret;
+ struct ucbdef *ucb;
+
+ if (~(ret=finducb(devch,&ucb))&1)
+ return(ret);
+
+ if (setstate)
+ return(_setldr(ucb));
+ else
+ return(_clrldr(ucb));
+}
+
+extern unsigned long int CLI$PRESENT();
+extern unsigned long int CLI$GET_VALUE();
+
+static unsigned long int
+cld_special(
+ char *kwd_name)
+{
+ lib$establish(lib$sig_to_ret);
+ return(CLI$PRESENT(descr(kwd_name)));
+}
+
+int
+main(){
+ unsigned long int ret;
+ unsigned long int ismnt = 0;
+ unsigned long int dvcls = 0;
+ unsigned long int dchr2 = 0;
+ struct itmlst_3 {
+ unsigned short int ilen;
+ unsigned short int code;
+ unsigned long int *returnP;
+ unsigned long int ignored;
+ } dvi_itmlst[] = {
+ {4, DVI$_MNT, 0/*&ismnt*/, 0},
+ {4, DVI$_DEVCLASS, 0/*&dvcls*/, 0},
+ {4, DVI$_DEVCHAR2, 0/*&dchr2*/, 0},
+ {0,0,0,0} };
+ unsigned long int iosb[2];
+ struct dsc$descriptor_s *dp_tmp;
+ struct dsc$descriptor_d dy_devn = { 0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0 };
+ unsigned long int devch=0;
+
+ dvi_itmlst[0].returnP = &ismnt;
+ dvi_itmlst[1].returnP = &dvcls;
+ dvi_itmlst[2].returnP = &dchr2;
+
+ if (~(ret=CLI$PRESENT(dp_tmp=descr("DEVICE")))&1) {
+ printf("?Error obtaining CLD DEVICE parameter\n");
+ return(ret); }
+ if (~(ret=CLI$GET_VALUE(dp_tmp,&dy_devn,0))&1) {
+ printf("?Error obtaining CLD DEVICE value\n");
+ return(ret); }
+
+ if (~(ret=sys$alloc(&dy_devn,0,0,0,0))&1) {
+ printf("?Error allocating specified device\n");
+ return(ret); }
+
+ if (~(ret=sys$assign(&dy_devn,&devch,0,0))&1) {
+ printf("?Error assigning a channel to specified device\n");
+ return(ret); }
+
+ if (~(ret=sys$getdviw(0,devch,0,&dvi_itmlst,&iosb,0,0,0))&1) {
+ printf("?Error obtaining device information(1)\n");
+ return(ret); }
+ if (~(ret=iosb[0])&1) {
+ printf("?Error obtaining device information(2)\n");
+ return(ret); }
+
+ if (dvcls != DC$_TAPE) {
+ printf("?Device is not a tape drive\n");
+ return(SS$_IVDEVNAM); }
+
+ if (~dchr2 & DEV$M_SCSI) {
+ printf("?Device is not a SCSI device\n");
+ return(SS$_IVDEVNAM); }
+
+ if (ismnt) {
+ printf("?Device is mounted\n");
+ return(SS$_DEVMOUNT); }
+
+ if (cld_special("SET")&1)
+ return(set_ldrstate(devch,1));
+
+ if (cld_special("RESET")&1)
+ return(set_ldrstate(devch,0));
+
+ /* Either SET or RESET above must be present to win */
+ printf("?CLD structural error - see source\n");
+ return(SS$_BADPARAM);
+}
diff --git a/vms/ldrset.cld b/vms/ldrset.cld
new file mode 100644
index 0000000..0dfc543
--- /dev/null
+++ b/vms/ldrset.cld
@@ -0,0 +1,9 @@
+define verb LDRSET
+ image sys$disk:[]ldrset.exe
+ parameter p1, label=device,
+ prompt="Device",
+ value(required,type=$FILE)
+ qualifier SET, nonnegatable
+ qualifier RESET, nonnegatable
+ disallow any2 (SET, RESET)
+ disallow NOT SET AND NOT RESET
diff --git a/vms/ldrutil.mar b/vms/ldrutil.mar
new file mode 100644
index 0000000..9d0ea31
--- /dev/null
+++ b/vms/ldrutil.mar
@@ -0,0 +1,104 @@
+ .title LDRUTIL - Obtain ucb for assigned channel
+ .ident /LDRUTIL V1.0/
+; LDRUTIL - VMS UCB LDR bit utility library
+;
+; TECSys Development, Inc., April 1998
+;
+; This file may be copied under the terms and conditions of version 2
+; of the GNU General Public License, as published by the Free
+; Software Foundation (Cambridge, Massachusetts).
+;
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program; if not, write to the Free Software
+; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+;
+;
+ .link "sys$system:sys.stb"/selective_search
+ .library /sys$share:lib/
+
+ .NTYPE ...IS_IT_ALPHA,R22 ;Get the type of R22
+ ...IS_IT_ALPHA = <...IS_IT_ALPHA@-4&^XF>-5
+ .IIF EQ,...IS_IT_ALPHA, ALPHA=1
+
+ $ssdef
+ $ucbdef
+ $ccbdef
+ $chfdef
+ $dcdef
+ $devdef
+ $pcbdef
+
+ .psect $$code,exe,rd,nowrt,shr
+.IF NDF,ALPHA
+.entry finducb,^m<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel
+.IFF
+.call_entry, 2,home_args=TRUE,-
+ preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,-
+ output=<r0,r1>,-
+ label=finducb
+.endc
+ movzwl 4(AP),r0 ;prep to find UCB
+ jsb g^IOC$VERIFYCHAN ;callable from user mode!
+ blbc r0,20$
+ movl CCB$L_UCB(r1),@8(AP) ;save UCB address
+ movzbl #1,r0
+20$: ret
+
+.IF NDF,ALPHA
+.entry __setldr,^m<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel
+.IFF
+.call_entry, 2,home_args=TRUE,-
+ preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,-
+ output=<r0,r1>,-
+ label=__setldr
+.endc
+ movl 4(AP),r1
+ bisl #DEV$M_LDR,UCB$L_DEVCHAR2(r1)
+ movzbl #1,r0
+ ret
+
+.IF NDF,ALPHA
+.entry _setldr,^m<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel
+.IFF
+.call_entry, 2,home_args=TRUE,-
+ preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,-
+ output=<r0,r1>,-
+ label=_setldr
+.endc
+ $cmkrnl_s -
+ routin = __setldr,-
+ arglst = (AP)
+ ret
+
+.IF NDF,ALPHA
+.entry __clrldr,^m<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel
+.IFF
+.call_entry, 2,home_args=TRUE,-
+ preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,-
+ output=<r0,r1>,-
+ label=__clrldr
+.endc
+ movl 4(AP),r1
+ bicl #DEV$M_LDR,UCB$L_DEVCHAR2(r1)
+ movzbl #1,r0
+ ret
+
+.IF NDF,ALPHA
+.entry _clrldr,^m<r2,r3,r4,r5,r6,r7,r8,r9> ;Find UCB address from channel
+.IFF
+.call_entry, 2,home_args=TRUE,-
+ preserve=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>,-
+ output=<r0,r1>,-
+ label=_clrldr
+.endc
+ $cmkrnl_s -
+ routin = __clrldr,-
+ arglst = (AP)
+ ret
+
+ .end
diff --git a/vms/scsi.c b/vms/scsi.c
new file mode 100644
index 0000000..5b32572
--- /dev/null
+++ b/vms/scsi.c
@@ -0,0 +1,400 @@
+/* SCSI.C - VMS-specific SCSI routines.
+**
+** TECSys Development, Inc., April 1998
+**
+** This module began life as a program called CDWRITE20, a CD-R control
+** program for VMS. No real functionality from the original CDWRITE20
+** is present in this module, but in the interest of making certain that
+** proper credit is given where it may be due, the copyrights and inclusions
+** from the CDWRITE20 program are included below.
+**
+** The portions of coding in this module ascribable to TECSys Development
+** are hereby also released under the terms and conditions of version 2
+** of the GNU General Public License as described below....
+*/
+
+/* The remainder of these credits are included directly from the CDWRITE20
+** sources. */
+
+/* Copyright 1994 Yggdrasil Computing, Inc. */
+/* Written by Adam J. Richter (adam@yggdrasil.com) */
+
+/* Rewritten February 1997 by Eberhard Heuser-Hofmann*/
+/* using the OpenVMS generic scsi-interface */
+/* see the README-file, how to setup your machine */
+
+/*
+** Modified March 1997 by John Vottero to use overlapped, async I/O
+** and lots of buffers to help prevent buffer underruns.
+** Also improved error reporting.
+*/
+
+/* This file may be copied under the terms and conditions of version 2
+ of the GNU General Public License, as published by the Free
+ Software Foundation (Cambridge, Massachusetts).
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The second notice comes from sys$examples:gktest.c (OpenVMS 7.0)*/
+
+/*
+** COPYRIGHT (c) 1993 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 OF 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.
+*/
+
+/*
+ Define the Generic SCSI Command Descriptor.
+*/
+
+typedef struct scsi$desc
+{
+ unsigned int SCSI$L_OPCODE; /* SCSI Operation Code */
+ unsigned int SCSI$L_FLAGS; /* SCSI Flags Bit Map */
+ unsigned char *SCSI$A_CMD_ADDR; /* ->SCSI Command Buffer */
+ unsigned int SCSI$L_CMD_LEN; /* SCSI Command Length (bytes) */
+ unsigned char *SCSI$A_DATA_ADDR; /* ->SCSI Data Buffer */
+ unsigned int SCSI$L_DATA_LEN; /* SCSI Data Length (bytes) */
+ unsigned int SCSI$L_PAD_LEN; /* SCSI Pad Length (bytes) */
+ unsigned int SCSI$L_PH_CH_TMOUT; /* SCSI Phase Change Timeout (seconds) */
+ unsigned int SCSI$L_DISCON_TMOUT; /* SCSI Disconnect Timeout (seconds) */
+ unsigned int SCSI$L_RES_1; /* Reserved */
+ unsigned int SCSI$L_RES_2; /* Reserved */
+ unsigned int SCSI$L_RES_3; /* Reserved */
+ unsigned int SCSI$L_RES_4; /* Reserved */
+ unsigned int SCSI$L_RES_5; /* Reserved */
+ unsigned int SCSI$L_RES_6; /* Reserved */
+}
+SCSI$DESC;
+
+
+/*
+ Define the SCSI Input/Output Status Block.
+*/
+
+typedef struct scsi$iosb
+{
+ unsigned short SCSI$W_VMS_STAT; /* VMS Status Code */
+ unsigned long SCSI$L_IOSB_TFR_CNT; /* Actual Byte Count Transferred */
+ unsigned char SCSI$B_IOSB_FILL_1; /* Unused */
+ unsigned char SCSI$B_IOSB_STS; /* SCSI Device Status */
+}
+SCSI$IOSB;
+
+
+/*
+ Define the VMS symbolic representation for a successful SCSI command.
+*/
+
+#define SCSI$K_GOOD 0
+
+
+/*
+ Define the SCSI Flag Field Constants.
+*/
+
+#define SCSI$K_WRITE 0x0 /* Data Transfer Direction: Write */
+#define SCSI$K_READ 0x1 /* Data Transfer Direction: Read */
+#define SCSI$K_FL_ENAB_DIS 0x2 /* Enable Disconnect/Reconnect */
+
+
+/*
+ Define DESCR_CNT. It must be a power of two and large enough
+ for the maximum concurrent usage of descriptors.
+*/
+
+#define DESCR_CNT 16
+
+
+#define MK_EFN 0 /* Event Flag Number */
+#define FailureStatusP(Status) (~(Status) & 1)
+
+
+static struct dsc$descriptor_s *descr(char *String)
+{
+ static struct dsc$descriptor_s d_descrtbl[DESCR_CNT];
+ static unsigned short descridx = 0;
+ struct dsc$descriptor_s *d_ret = &d_descrtbl[descridx];
+ descridx = (descridx + 1) & (DESCR_CNT - 1);
+ d_ret->dsc$w_length = strlen((const char *) String);
+ d_ret->dsc$a_pointer = String;
+ d_ret->dsc$b_class = 0;
+ d_ret->dsc$b_dtype = 0;
+
+ return d_ret;
+}
+
+
+static int SCSI_OpenDevice(char *DeviceName)
+{
+ unsigned long d_dev[2], iosb[2], Status;
+ union prvdef setprivs, newprivs;
+ unsigned long ismnt = 0;
+ unsigned long dvcls = 0;
+ unsigned long dchr2 = 0;
+ int DeviceFD = 0;
+ struct itmlst_3
+ {
+ unsigned short ilen;
+ unsigned short code;
+ unsigned long *returnP;
+ unsigned long ignored;
+ }
+ dvi_itmlst[] = {
+ { 4, DVI$_MNT, 0 /*&ismnt*/, 0 },
+ { 4, DVI$_DEVCLASS, 0 /*&dvcls*/, 0 },
+ { 4, DVI$_DEVCHAR2, 0 /*&dchr2*/, 0 },
+ { 0, 0, 0, 0 }
+ };
+
+ dvi_itmlst[0].returnP = &ismnt;
+ dvi_itmlst[1].returnP = &dvcls;
+ dvi_itmlst[2].returnP = &dchr2;
+
+ Status = sys$alloc(descr(DeviceName), 0, 0, 0, 0);
+
+ if (FailureStatusP(Status))
+ {
+ VMS_ExitCode = Status;
+ FatalError("cannot allocate device '%s' - %X\n", DeviceName, Status);
+ }
+
+ Status = sys$assign(descr(DeviceName), &DeviceFD, 0, 0);
+ if (FailureStatusP(Status))
+ {
+ VMS_ExitCode = Status;
+ FatalError("cannot open device '%s' - %X\n", DeviceName, Status);
+ }
+
+ Status = sys$getdviw(0, DeviceFD, 0, &dvi_itmlst, &iosb, 0, 0, 0);
+ if (FailureStatusP(Status))
+ {
+ VMS_ExitCode = Status;
+ FatalError("cannot $getdvi(1) on device '%s' - %X\n", DeviceName, Status);
+ }
+
+ if (FailureStatusP(Status = iosb[0]))
+ {
+ VMS_ExitCode = Status;
+ FatalError("cannot $getdvi(2) on device '%s' - %X\n", DeviceName, Status);
+ }
+
+ if (dvcls != DC$_TAPE)
+ {
+ VMS_ExitCode = SS$_IVDEVNAM;
+ FatalError("specified device is NOT a magtape: operation denied\n");
+ }
+#ifndef __DECC
+#ifndef DEV$M_SCSI
+#define DEV$M_SCSI 0x1000000
+#endif
+#endif
+ if (~dchr2 & DEV$M_SCSI)
+ {
+ VMS_ExitCode = SS$_IVDEVNAM;
+ FatalError("specified magtape is NOT a SCSI device: operation denied\n");
+ }
+#if USING_DEC_DRIVE | USING_LDRSET
+#ifndef __DECC
+#ifndef DEV$M_LDR
+#define DEV$M_LDR 0x100000
+#endif
+#endif
+ if (~dchr2 & DEV$M_LDR)
+ {
+ VMS_ExitCode = SS$_IVDEVNAM;
+ FatalError("specified SCSI magtape does not have a loader: operation denied\n");
+ }
+#endif
+ if (ismnt)
+ {
+ VMS_ExitCode = SS$_DEVMOUNT;
+ FatalError("specified device is mounted: operation denied\n");
+ }
+
+ ots$move5(0, 0, 0, sizeof(newprivs), &newprivs);
+ newprivs.prv$v_diagnose = 1;
+ newprivs.prv$v_log_io = 1;
+ newprivs.prv$v_phy_io = 1;
+ Status = sys$setprv(1, &newprivs, 0, 0);
+
+ if (FailureStatusP(Status))
+ {
+ VMS_ExitCode = Status;
+ FatalError("error enabling privs (diagnose,log_io,phy_io): operation denied\n");
+ }
+
+ Status = sys$setprv(1, 0, 0, &setprivs);
+ if (FailureStatusP(Status))
+ {
+ VMS_ExitCode = Status;
+ FatalError("error retrieving current privs: operation denied\n");
+ }
+
+ if (!setprivs.prv$v_diagnose)
+ {
+ VMS_ExitCode = SS$_NODIAGNOSE;
+ FatalError("DIAGNOSE privilege is required: operation denied\n");
+ }
+
+ if (!setprivs.prv$v_phy_io && !setprivs.prv$v_log_io)
+ {
+ VMS_ExitCode = SS$_NOPHY_IO;
+ FatalError("PHY_IO or LOG_IO privilege is required: operation denied\n");
+ }
+
+ return DeviceFD;
+}
+
+
+static void SCSI_CloseDevice(char *DeviceName, int DeviceFD)
+{
+ unsigned long Status;
+
+ Status = sys$dassgn(DeviceFD);
+ if (FailureStatusP(Status))
+ FatalError("cannot close SCSI device '%s' - %X\n", DeviceName, Status);
+}
+
+
+static int SCSI_ExecuteCommand( int DeviceFD,
+ Direction_T Direction,
+ CDB_T *CDB,
+ int CDB_Length,
+ void *DataBuffer,
+ int DataBufferLength,
+ RequestSense_T *RequestSense)
+{
+ SCSI$DESC cmd_desc;
+ SCSI$IOSB cmd_iosb;
+ unsigned long Status;
+ int Result;
+ memset(RequestSense, 0, sizeof(RequestSense_T));
+ /* Issue the QIO to send the SCSI Command. */
+ ots$move5(0, 0, 0, sizeof(cmd_desc), &cmd_desc);
+ cmd_desc.SCSI$L_OPCODE = 1; /* Only defined SCSI opcode... a VMS thing */
+ cmd_desc.SCSI$A_CMD_ADDR = CDB;
+ cmd_desc.SCSI$L_CMD_LEN = CDB_Length;
+ cmd_desc.SCSI$A_DATA_ADDR = DataBuffer;
+ cmd_desc.SCSI$L_DATA_LEN = DataBufferLength;
+ cmd_desc.SCSI$L_PAD_LEN = 0;
+ cmd_desc.SCSI$L_PH_CH_TMOUT = 180; /* SCSI Phase Change Timeout (seconds) */
+ cmd_desc.SCSI$L_DISCON_TMOUT = 180; /* SCSI Disconnect Timeout (seconds) */
+
+ switch (Direction)
+ {
+ /*
+ NOTE: Do NOT include flag SCSI$K_FL_ENAB_SYNC.
+ It does NOT work for this case.
+ */
+ case Input:
+ cmd_desc.SCSI$L_FLAGS = SCSI$K_READ | SCSI$K_FL_ENAB_DIS;
+ break;
+
+ case Output:
+ cmd_desc.SCSI$L_FLAGS = SCSI$K_WRITE | SCSI$K_FL_ENAB_DIS;
+ break;
+ }
+
+ /* Issue the SCSI Command. */
+ Status = sys$qiow(MK_EFN, DeviceFD, IO$_DIAGNOSE, &cmd_iosb, 0, 0,
+ &cmd_desc, sizeof(cmd_desc), 0, 0, 0, 0);
+ Result = SCSI$K_GOOD;
+
+ if (Status & 1)
+ Status = cmd_iosb.SCSI$W_VMS_STAT;
+
+ if (Status & 1)
+ Result = cmd_iosb.SCSI$B_IOSB_STS;
+
+ if (Result != SCSI$K_GOOD)
+ {
+ unsigned char RequestSenseCDB[6] =
+ { 0x03 /* REQUEST_SENSE */, 0, 0, 0, sizeof(RequestSense_T), 0 };
+
+ printf("SCSI command error: %d - requesting sense data\n", Result);
+
+ /* Execute Request Sense to determine the failure reason. */
+ ots$move5(0, 0, 0, sizeof(cmd_desc), &cmd_desc);
+ cmd_desc.SCSI$L_OPCODE = 1; /* Only defined SCSI opcode... a VMS thing */
+ cmd_desc.SCSI$L_FLAGS = SCSI$K_READ | SCSI$K_FL_ENAB_DIS;
+ cmd_desc.SCSI$A_CMD_ADDR = RequestSenseCDB;
+ cmd_desc.SCSI$L_CMD_LEN = 6;
+ cmd_desc.SCSI$A_DATA_ADDR = RequestSense;
+ cmd_desc.SCSI$L_DATA_LEN = sizeof(RequestSense_T);
+ cmd_desc.SCSI$L_PH_CH_TMOUT = 180;
+ cmd_desc.SCSI$L_DISCON_TMOUT = 180;
+
+ /* Issue the QIO to send the Request Sense Command. */
+ Status = sys$qiow(MK_EFN, DeviceFD, IO$_DIAGNOSE, &cmd_iosb, 0, 0,
+ &cmd_desc, sizeof(cmd_desc), 0, 0, 0, 0);
+ if (FailureStatusP(Status))
+ {
+ printf("?Error returned from REQUEST_SENSE(1): %%X%08lX\n", Status);
+ sys$exit(Status);
+ }
+
+ /* Check the VMS Status from QIO. */
+ Status = cmd_iosb.SCSI$W_VMS_STAT;
+ if (FailureStatusP(Status))
+ {
+ printf("?Error returned from REQUEST_SENSE(2): %%X%08lX\n", Status);
+ sys$exit(Status);
+ }
+ }
+ return Result;
+}
+
+
+static void VMS_DefineStatusSymbols(void)
+{
+ char SymbolName[32], SymbolValue[32];
+ int StorageElementNumber;
+
+ if (DataTransferElementFull)
+ {
+ /* Define MTX_DTE Symbol (environment variable) as 'FULL:n'. */
+ sprintf(SymbolValue, "FULL:%d",
+ DataTransferElementSourceStorageElementNumber);
+ lib$set_symbol(descr("MTX_DTE"), descr(SymbolValue), &2);
+ }
+ else
+ {
+ /* Define MTX_DTE Symbol (environment variable) as 'EMPTY'. */
+ lib$set_symbol(descr("MTX_DTE"), descr("EMPTY"), &2);
+ }
+
+ /* Define MTX_MSZ Symbol (environment variable) "Magazine SiZe" as 'n'. */
+ sprintf(SymbolValue, "%d", StorageElementCount);
+ lib$set_symbol(descr("MTX_MSZ"), descr(SymbolValue), &2);
+ for (StorageElementNumber = 1;
+ StorageElementNumber <= StorageElementCount;
+ StorageElementNumber++)
+ {
+ sprintf(SymbolName, "MTX_STE%02d", StorageElementNumber);
+ strcpy(SymbolValue,
+ (StorageElementFull[StorageElementNumber] ? "FULL" : "EMPTY"));
+ lib$set_symbol(descr(SymbolName), descr(SymbolValue), &2);
+ }
+}