diff options
Diffstat (limited to 'vms')
-rw-r--r-- | vms/000readme | 175 | ||||
-rw-r--r-- | vms/build.com | 34 | ||||
-rw-r--r-- | vms/defs.h | 42 | ||||
-rw-r--r-- | vms/descrip.mms | 77 | ||||
-rw-r--r-- | vms/ldrset.c | 183 | ||||
-rw-r--r-- | vms/ldrset.cld | 9 | ||||
-rw-r--r-- | vms/ldrutil.mar | 104 | ||||
-rw-r--r-- | vms/scsi.c | 400 |
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); + } +} |