[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference stkhlm::magtape

Title:MAGNETIC TAPEDRIVES
Moderator:STKHLM::GJOHNSSON
Created:Mon Sep 21 1987
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:3775
Total number of notes:13147

3702.0. "Fast Tape Positioning on DLT drives" by STOWKS::SLUIS (Hans van Sluis -- Storage Engineering Support Europe- DTN 889 9526) Mon Mar 24 1997 12:31

Fast Tape Positioning on DLT drives
===================================


This tool allows system managers to 'skip' directly to the tape position 
where their data resides. This tool can be used in places where a 
$SET MAGTAPE <Device> /SKIP=FILES=n is used. It is based on 
proven code in the HSM for OpenVMS product.

This tool has proven to work on :
- HSJ & HSD connected TZ8x drives
- MSCP-served TZ8x-drives
- Local connected SCSI TZ8x drives
The used version of the Operating System was OpenVMS V6.2 (both VAX and
Alpha). However, recompilation on OpenVMS V6.1 will get this tool to work.

To be able to build this tool, you'll need :
- 1500 blocks of disk space
- A C-compiler (DEC C)
- 5 minutes or less, just to issue a $@COMPILE.COM

The usage of this tool is as follows :
1) fasttape :== "$DISK$USER:[YOUNAMEIT.ALPHA]FASTTAPE.EXE"   or
   fasttape :== "$DISK$USER:[YOUNAMEIT.VAX]FASTTAPE.EXE"    
2) fasttape -device <Device> -p <Required Position>

This tool can be given to customers without any support.


T.RTitleUserPersonal
Name
DateLines
3702.1FASTTAPE.HSTOWKS::SLUISHans van Sluis -- Storage Engineering Support Europe- DTN 889 9526Mon Mar 24 1997 12:321121
/*
**++
**  FACILITY:  Storage Management Group Products
**
**  MODULE DESCRIPTION:
**
**      Contains definitions for skipmarks.c.  This is a conglomeration of stuff
**	from several .h files.
**
**  AUTHORS:
**
**      Dan Kyler
**
**  CREATION DATE:  18 May 1994
**
**  DESIGN ISSUES:
**
**      VMS Specific
**
**
**  MODIFICATION HISTORY:
**
**	X-3		    Steve Jensen		19-Jul-1995
**
**	    QAR 692 -- Add workaround for SCSI REQUEST_SENSE misbehavior.
**	    
**      X-2		    Steve Jensen		18-AUG-1994
**
**	    Made changes for DECC compiles.  Rather than use the handcrafted
**	    versions of these things, we'd rather use the system defined ones,
**	    if they exist.   Especially for VAX/Alpha portability.
**--
*/

/*	  
**  From SMFS' scsi.h:
*/	  

/*
 * @(#) vms_scsi_util.h 1.1 94/03/09 Copyright(c) 1994 Digital Equipment
Corporation.
 *
 *  Copyright (c) Digital Equipment Corporation, 1994
 *  All Rights Reserved.  Unpublished rights reserved
 *  under the copyright laws of the United States.
 *  
 *  The software contained on this media is proprietary
 *  to and embodies the confidential technology of 
 *  Digital Equipment Corporation.  Possession, use,
 *  duplication or dissemination of the software and
 *  media is authorized only pursuant to a valid written
 *  license from Digital Equipment Corporation.
 *
 *  RESTRICTED RIGHTS LEGEND   Use, duplication, or 
 *  disclosure by the U.S. Government is subject to
 *  restrictions as set forth in Subparagraph (c)(1)(ii)
 *  of DFARS 252.227-7013, or in FAR 52.227-19, as
 *  applicable.
 */
/****************************************************************************
 *
 *
 * Facility:
 *
 *      NetWorker    
 *
 * Abstract:
 *
 *      Private header file defining structures and functions
 *      used by scsi_util.c to access SCSI jukebox devices.
 *
 * Author:
 *
 *      Roger Walker
 *
 * Date:
 *
 *      3-Jan-1994   
 *
 * Revision History:
 *
 * 7-Mar-1994	Carl Appellof
 * 	Added SCSI space command cdb
 *
 * 	Added #define for size of all cdb structures because
 * 	DECC compiler pads structures, and VMS MKDRIVER doesn't
 * 	like to see wrong lengths for cdbs.
 *
 */
#include <stddef.h>		/* for offsetof() */

#define SENSE_NO_SENSE		    0x00
#define SENSE_RECOVERED_ERROR	    0x01
#define SENSE_NOT_READY		    0x02
#define SENSE_MEDIUM_ERROR	    0x03
#define SENSE_HARDWARE_ERROR	    0x04
#define SENSE_ILLEGAL_REQUEST	    0x05
#define SENSE_UNIT_ATTENTION	    0x06
#define SENSE_DATA_PROTECT	    0x07
#define SENSE_BLANK_CHECK	    0x08
#define SENSE_VENDOR		    0x09
#define SENSE_COPY_ABORTED	    0x0a
#define SENSE_ABORTED_COMMAND	    0x0b
#define SENSE_EQUAL		    0x0c
#define SENSE_VOLUME_OVERFLOW	    0x0d
#define SENSE_MISCOMPARE	    0x0e
#define SENSE_RESERVED		    0x0f

#define FLAGS_READ 1
#define FLAGS_DISCONNECT 2

struct qio_cmd_struct { int opcode;
                        int flags;
                        char *command_adr;
                        int command_len;
                        char *data_adr;
                        int data_len;
                        int pad_len;
                        int phase_tmo;
                        int disc_tmo;
                        int reserved[30];
};


typedef struct
{
    unsigned short int status;
    unsigned short int bcnt;
    unsigned long int dev_specific;
} IOSB;

struct scsi_iosb_struct { 
    short status;
    unsigned short bcnt_low;
    unsigned short bcnt_high;
    unsigned char filler;
    unsigned char scsi_status; 
};

typedef struct {
  char opcode;
  unsigned filler1  : 5;
  unsigned lun      : 3;
  unsigned char filler2[2];
  unsigned char len;
  unsigned char control;
} req_sense_cdb;
#define req_sense_cdb_size (1+offsetof(req_sense_cdb, control))


struct sense_data_struct {
  unsigned int error    : 7;		/*  0..  */
  unsigned int valid    : 1;		/*  ..0  */

  unsigned char segment;		/*  1    */

  unsigned int key      : 4;		/*  2..  */
  unsigned int filler1  : 1;		/*  ...  */
  unsigned int ili      : 1;		/*  ...  */
  unsigned int eom      : 1;		/*  ...  */
  unsigned int fm       : 1;		/*  ..2  */

  unsigned char info[4];		/*  3-6  */

  unsigned char add_len;		/*  7    */
  unsigned char cmd_spec_data[4];	/*  8-11 */
  unsigned char add_sense_code;		/* 12    */
  unsigned char add_sense_code_qual;	/* 13    */
  unsigned char fruc;			/* 14    */

  unsigned bit_pointer  : 3;		/* 15..  */
  unsigned bpv          : 1;		/*  ...  */
  unsigned filler2      : 2;            /*  ...  */
  unsigned command_data : 1;		/*  ...  */
  unsigned sksv         : 1;		/*  ..15 */

  unsigned char field_pt[2];		/* 16-17 */
  
  /*	  
  **  QAR 692
  **
  **	Add a big buffer at the end.  This keeps the scsi stuff from writing
  **	over the end of the sense_data record, which is apparently does on at
  **	least VMS V6.2 Alpha.  This is just a workaround so memory after this
  **	structure is not corrupted by the request_sense command.
  */	  

  char	    filler3[255];		/* Keep scsi from overwritting memory */
};

/*
 * Space Command
 */
#define SPACE_COMMAND 0x11
#define SPACE_FILES_SUBCODE 1

typedef struct {
    unsigned char opcode;
    unsigned subcode:3;
    unsigned filler:5;
    char count[3];
    unsigned char control;
} space_cdb;
#define space_cdb_size (1+offsetof(space_cdb, control))

#define READ_POSITION 0x34
typedef struct {
    unsigned reserved1 : 2;
    unsigned BPU : 1;
    unsigned reserved2 : 3;
    unsigned EOP : 1;
    unsigned BOP : 1;
    unsigned char partition_number;
    unsigned char reserved3;
    unsigned char reserved4;
    unsigned char first_block[4];
    unsigned char last_block[4];
    unsigned char reserved5;
    unsigned char blocks_in_buffer[3];
    unsigned char bytes_in_buffer[4];
} READPOS_DATA;

typedef struct
{
    unsigned char opcode;
    unsigned BT : 1;
    unsigned reserved1 : 4;
    unsigned lun : 3;
    unsigned char reserved2;    
    unsigned char reserved3;    
    unsigned char reserved4;    
    unsigned char reserved5;    
    unsigned char reserved6;    
    unsigned char reserved7;    
    unsigned char reserved8;    
    unsigned char control;
} READPOS_CMD;

/*
 * Macro to stuff a signed 32-bit int into a 3-byte SCSI command
 * block.  Takes an int and a char pointer as args.  No need for
 * masking things like (number >> 16), since we store into a char,
 * which will naturally truncate the result.
 */
#define I_TO_B3(number, bytes) { \
				(bytes)[0] = (number >> 16); \
			        (bytes)[1] = (number >> 8); \
				(bytes)[2] = (number); \
			       }

#define I_TO_B2(number, bytes) { \
				(bytes)[0] = (number >> 8); \
				(bytes)[1] = (number); \
			       }

#define B4_TO_I(bytes) (((bytes)[0] << 24) | \
			((bytes)[1] << 16) | \
			((bytes)[2] << 8) | \
			(bytes)[3])

static int b2_to_i(unsigned char *bytes);

#if defined (__DECC) && defined (__ALPHA)
#include <devdef.h>
#else
#ifndef __DEVDEF_LOADED

/*	  
**  From SMFS' devdef.h:
*/	  
/**/
/******************************************************************************/
/**                                                                          **/
/**  Copyright (c) 1994                                                      **/
/**  by DIGITAL Equipment Corporation, Maynard, Mass.                        **/
/**                                                                          **/
/**  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.                 **/
/**                                                                          **/
/******************************************************************************/
/*******************************************************************************
*************************************************/
/* Created 11-MAR-1994 09:23:57 by VAX SDL V3.2-12     Source: 15-NOV-1991
16:16:33 WRK$ROOT:[SRC]DEVDEF.SDL;1 */
/*******************************************************************************
*************************************************/
 
/*** MODULE $DEVDEF ***/
/*                                                                          */
/*  THE FOLLOWING BITS DEFINE THE DEVICE CHARACTERISTICS FOR                */
/*  BOTH THE UCBS AND RMS.                                                  */
/*                                                                          */
#define DEV$M_REC 1
#define DEV$M_CCL 2
#define DEV$M_TRM 4
#define DEV$M_DIR 8
#define DEV$M_SDI 16
#define DEV$M_SQD 32
#define DEV$M_SPL 64
#define DEV$M_OPR 128
#define DEV$M_RCT 256
#define DEV$M_NET 8192
#define DEV$M_FOD 16384
#define DEV$M_DUA 32768
#define DEV$M_SHR 65536
#define DEV$M_GEN 131072
#define DEV$M_AVL 262144
#define DEV$M_MNT 524288
#define DEV$M_MBX 1048576
#define DEV$M_DMT 2097152
#define DEV$M_ELG 4194304
#define DEV$M_ALL 8388608
#define DEV$M_FOR 16777216
#define DEV$M_SWL 33554432
#define DEV$M_IDV 67108864
#define DEV$M_ODV 134217728
#define DEV$M_RND 268435456
#define DEV$M_RTM 536870912
#define DEV$M_RCK 1073741824
#define DEV$M_WCK -2147483648
#define DEV$M_CLU 1
#define DEV$M_DET 2
#define DEV$M_RTT 4
#define DEV$M_CDP 8
#define DEV$M_2P 16
#define DEV$M_MSCP 32
#define DEV$M_SSM 64
#define DEV$M_SRV 128
#define DEV$M_RED 256
#define DEV$M_NNM 512
#define DEV$M_WBC 1024
#define DEV$M_WTC 2048
#define DEV$M_HOC 4096
#define DEV$M_LOC 8192
#define DEV$M_DFS 16384
#define DEV$M_DAP 32768
#define DEV$M_NLT 65536
#define DEV$M_SEX 131072
#define DEV$M_SHD 262144
#define DEV$M_VRT 524288
#define DEV$M_LDR 1048576
#define DEV$M_NOLB 2097152
#define DEV$M_NOCLU 4194304
#define DEV$M_VMEM 8388608
#define DEV$M_SCSI 16777216
#define DEV$M_WLG 33554432
#define DEV$M_NOFE 67108864
#define DEV$M_AIP 134217728
#define DEV$M_CRAMIO 268435456
#define DEV$M_DTN 536870912

union DEVDEF {
    variant_struct  {
        unsigned DEV$V_REC : 1;         /* DEVICE RECORD ORIENTED           */
        unsigned DEV$V_CCL : 1;         /* CARRIAGE CONTROL DEVICE          */
        unsigned DEV$V_TRM : 1;         /* DEVICE IS A TERMINAL             */
        unsigned DEV$V_DIR : 1;         /* DEVICE IS DIRECTORY STRUCTURED   */
        unsigned DEV$V_SDI : 1;         /* DEVICE IS SINGLE DIRECTORY STRUCTURED
 */
        unsigned DEV$V_SQD : 1;         /* SEQUENTIAL BLOCK-ORIENTED DEVICE
(I.E., MAGTAPE)  */
        unsigned DEV$V_SPL : 1;         /* DEVICE BEING SPOOLED             */
        unsigned DEV$V_OPR : 1;         /* DEVICE IS AN OPERATOR            */
        unsigned DEV$V_RCT : 1;         /* DISK CONTAINS RCT (DEC STANDARD 166
DISK)  */
        unsigned DEVDEF$$_FILL_1 : 4;   /* SPARES TO CORRESPOND WITH RSX11M  */
        unsigned DEV$V_NET : 1;         /* NETWORK DEVICE                   */
        unsigned DEV$V_FOD : 1;         /* FILES-ORIENTED DEVICE (I.E., DISK AND
MT)  */
        unsigned DEV$V_DUA : 1;         /* DEVICE IS DUAL PORTED            */
        unsigned DEV$V_SHR : 1;         /* DEVICE SHAREABLE                 */
        unsigned DEV$V_GEN : 1;         /* DEVICE IS A GENERIC DEVICE       */
        unsigned DEV$V_AVL : 1;         /* DEVICE AVAILABLE FOR USE         */
        unsigned DEV$V_MNT : 1;         /* DEVICE IS MOUNTED                */
        unsigned DEV$V_MBX : 1;         /* DEVICE IS A MAILBOX              */
        unsigned DEV$V_DMT : 1;         /* DEVICE MARKED FOR DISMOUNT       */
        unsigned DEV$V_ELG : 1;         /* DEVICE HAS ERROR LOGGING ENABLED  */
        unsigned DEV$V_ALL : 1;         /* DEVICE IS ALLOCATED              */
        unsigned DEV$V_FOR : 1;         /* DEVICE IS MOUNTED FOREIGN (I.E.,
NON-FILE STRUCTURED)  */
        unsigned DEV$V_SWL : 1;         /* DEVICE IS SOFTWARE WRITE LOCKED  */
        unsigned DEV$V_IDV : 1;         /* DEVICE CAPABLE OF PROVIDING INPUT  */
        unsigned DEV$V_ODV : 1;         /* DEVICE CAPABLE OF PROVIDING OUTPUT  */
        unsigned DEV$V_RND : 1;         /* DEVICE ALLOWS RANDOM ACCESS      */
        unsigned DEV$V_RTM : 1;         /* DEVICE IS REALTIME IN NATURE     */
        unsigned DEV$V_RCK : 1;         /* DEVICE HAS READ CHECKING ENABLED  */
        unsigned DEV$V_WCK : 1;         /* DEVICE HAS WRITE CHECKING ENABLED  */
        } DEV$R_DEVDEF_BITS0;
    variant_struct  {
        unsigned DEV$V_CLU : 1;         /* DEVICE IS AVAILABLE CLUSTER-WIDE */
        unsigned DEV$V_DET : 1;         /* DEVICE IS DETACHED TERMINAL      */
        unsigned DEV$V_RTT : 1;         /* DEVICE HAS REMOTE TERMINAL UCB
EXTENSION */
        unsigned DEV$V_CDP : 1;         /* DUAL PATH DEVICE WITH 2 UCBs     */
        unsigned DEV$V_2P : 1;          /* TWO PATHS ARE KNOWN TO THIS DEVICE */
        unsigned DEV$V_MSCP : 1;        /* DEVICE ACCESSED USING MSCP (disk or
tape) */
        unsigned DEV$V_SSM : 1;         /* DEVICE IS A SHADOW SET MEMBER    */
        unsigned DEV$V_SRV : 1;         /* DEVICE IS SERVED VIA THE MSCP SERVER
*/
        unsigned DEV$V_RED : 1;         /* DEVICE IS redirected terminal    */
        unsigned DEV$V_NNM : 1;         /* DEVICE HAS "node$" PREFIX        */
        unsigned DEV$V_WBC : 1;         /* DEVICE SUPPORTS WRITE-BACK CACHING */
        unsigned DEV$V_WTC : 1;         /* DEVICE SUPPORTS WRITE-THROUGH CACHING
*/
        unsigned DEV$V_HOC : 1;         /* DEVICE SUPPORTS HOST CACHING     */
        unsigned DEV$V_LOC : 1;         /* DEVICE ACCESSIBLE VIA LOCAL
(NON-EMULATED) CONTROLLER */
        unsigned DEV$V_DFS : 1;         /* DEVICE IS DFS-SERVED             */
        unsigned DEV$V_DAP : 1;         /* DEVICE IS DAP ACCESSED           */
        unsigned DEV$V_NLT : 1;         /* DEVICE IS NOT-LAST-TRACK (I.E. IT HAS
NO BAD BLOCK */
/* INFORMATION ON ITS LAST TRACK)                                           */
        unsigned DEV$V_SEX : 1;         /* DEVICE (tape) SUPPORTS SERIOUS
EXCEPTION HANDLING */
        unsigned DEV$V_SHD : 1;         /* DEVICE IS A MEMBER OF A HOST BASED
SHADOW SET */
        unsigned DEV$V_VRT : 1;         /* DEVICE IS A SHADOW SET VIRTUAL UNIT */
        unsigned DEV$V_LDR : 1;         /* LOADER PRESENT (TAPES)           */
        unsigned DEV$V_NOLB : 1;        /* DEVICE IGNORES SERVER LOAD BALANCING
REQUESTS */
        unsigned DEV$V_NOCLU : 1;       /* DEVICE WILL NEVER BE AVAILABLE
CLUSTER-WIDE */
        unsigned DEV$V_VMEM : 1;        /* Virtual member of a constituent set */
        unsigned DEV$V_SCSI : 1;        /* DEVICE IS A SCSI DEVICE          */
        unsigned DEV$V_WLG : 1;         /* DEVICE HAS WRITE LOGGING CAPABILITY */
        unsigned DEV$V_NOFE : 1;        /* DEVICE DOESN'T SUPPORT FORCED ERROR */
        unsigned DEV$V_AIP : 1;         /* Allocation in progress (MME)     */
        unsigned DEV$V_CRAMIO : 1;      /* Performs Mailbox I/O             */
        unsigned DEV$V_DTN : 1;         /* Device has DDR Device Type Name
available */
        unsigned DEV$V_fill_0 : 2;
        } DEV$R_DEVDEF_BITS1;
    }  ;
#define __DEVDEF_LOADED 1
#endif	/* DEVDEF loaded    */
#endif  /* __DECC && __ALPHA */

#if defined (__DECC) && defined (__ALPHA)
#include <ucbdef.h>
#else
#ifndef	__UCBDEF_LOADED

/*	  
**  From SMFS' ucbdef.h:
*/	  
/*******************************************************************************
*************************************************/
/* Created 20-JAN-1992 16:20:33 by VAX SDL V3.2-12     Source: 31-MAY-1990
14:16:57 V54_RESD$:[LIB.LIS]UCBDEF.SDL;1 */
/*******************************************************************************
*************************************************/
 
/*** MODULE $UCBDEF ***/
#define UCB$M_TIM 1
#define UCB$M_INT 2
#define UCB$M_ERLOGIP 4
#define UCB$M_CANCEL 8
#define UCB$M_ONLINE 16
#define UCB$M_POWER 32
#define UCB$M_TIMOUT 64
#define UCB$M_INTTYPE 128
#define UCB$M_BSY 256
#define UCB$M_MOUNTING 512
#define UCB$M_DEADMO 1024
#define UCB$M_VALID 2048
#define UCB$M_UNLOAD 4096
#define UCB$M_TEMPLATE 8192
#define UCB$M_MNTVERIP 16384
#define UCB$M_WRONGVOL 32768
#define UCB$M_DELETEUCB 65536
#define UCB$M_LCL_VALID 131072
#define UCB$M_SUPMVMSG 262144
#define UCB$M_MNTVERPND 524288
#define UCB$M_DISMOUNT 1048576
#define UCB$M_CLUTRAN 2097152
#define UCB$M_WRTLOCKMV 4194304
#define UCB$M_SVPN_END 8388608
#define UCB$M_ALTBSY 16777216
#define UCB$M_SNAPSHOT 33554432
#define UCB$M_JOB 1
#define UCB$M_TEMPL_BSY 64
#define UCB$M_PRMMBX 1
#define UCB$M_DELMBX 2
#define UCB$M_SHMMBX 8
#define UCB$M_TT_TIMO 2
#define UCB$M_TT_NOTIF 4
#define UCB$M_TT_HANGUP 8
#define UCB$M_TT_NOLOGINS 32768
#define UCB$M_NT_BFROVF 4
#define UCB$M_NT_NAME 16
#define UCB$M_NT_BREAK 32
#define UCB$M_ECC 1
#define UCB$M_DIAGBUF 2
#define UCB$M_NOCNVRT 4
#define UCB$M_DX_WRITE 8
#define UCB$M_DATACACHE 16
#define UCB$M_MSCP_MNTVERIP 256
#define UCB$M_MSCP_INITING 512
#define UCB$M_MSCP_WAITBMP 1024
#define UCB$M_MSCP_FLOVR 2048
#define UCB$M_MSCP_PKACK 4096
#define UCB$M_MSCP_WRTP 8192
#define UCB$M_MSCP_IGNSRV 16384
#define UCB$M_DU_SHMV_STRTD 8
#define UCB$M_DU_0MNOTE 32
#define UCB$M_TU_OVRSQCHK 1
#define UCB$M_TU_TRACEACT 2
#define UCB$M_TU_SEQNOP 4
#define UCB$M_TU_1DENS 8
#define UCB$M_TU_DENS_DETERMINED 16
#define UCB$M_SHD_SEQCMD_HERE 1024
#define UCB$M_SHD_SEQCMD_THERE 2048
#define UCB$M_SHD_PASSIVE_MV 4096
#define UCB$K_LENGTH 164                /*LENGTH OF STANDARD UCB            */
#define UCB$C_LENGTH 164                /*LENGTH OF STANDARD UCB            */
#define UCB$K_ERL_LENGTH 180            /*SIZE OF ERROR LOG UCB             */
#define UCB$C_ERL_LENGTH 180            /*SIZE OF ERROR LOG UCB             */
#define UCB$K_DP_LENGTH 192             /* Size of dual path UCB            */
#define UCB$C_DP_LENGTH 192             /* size of dual path UCB            */
#define UCB$K_2P_LENGTH 192             /* Size of dual path UCB            */
#define UCB$C_2P_LENGTH 192             /* size of dual path UCB            */
#define UCB$M_AST_ARMED 32768
#define UCB$K_LCL_TAPE_LENGTH 216       /* Size of local tape UCB           */
#define UCB$C_LCL_TAPE_LENGTH 216       /* Size of local tape UCB           */
#define UCB$K_LCL_DISK_LENGTH 228       /* Size of local disk UCB           */
#define UCB$C_LCL_DISK_LENGTH 228       /* Size of local disk UCB           */
#define UCB$K_MSCP_DISK_LENGTH 268      /* Size of MSCP disk UCB            */
#define UCB$K_MSCP_TAPE_LENGTH 268      /* Size of MSCP tape UCB            */
struct UCBDEF {
#pragma nostandard
    variant_union  {
        unsigned long int UCB$L_FQFL;   /*FORK QUEUE FORWARD LINK           */
        unsigned short int UCB$W_UNIT_SEED; /* UNIT NUMBER SEED             */
        unsigned short int UCB$W_MB_SEED; /* MB -- UNIT NUMBER SEED         */
        unsigned long int UCB$L_RQFL;   /* NET -- RCV QUEUE FORWARD LINK    */
        } UCB$R_FQFL_OVERLAY;
    variant_union  {
        unsigned long int UCB$L_FQBL;   /*FORK QUEUE BACKWARD LINK          */
        unsigned long int UCB$L_RQBL;   /* NET -- RCV QUEUE BACKWARD LINK   */
        } UCB$R_FQBL_OVERLAY;
    unsigned short int UCB$W_SIZE;      /*SIZE OF UCB IN BYTES              */
    unsigned char UCB$B_TYPE;           /*STRUCTURE TYPE FOR UCB            */
    variant_union  {
        unsigned char UCB$B_FLCK;       /*FORK LOCK NUMBER                  */
        unsigned char UCB$B_FIPL;       /*FORK IPL                          */
        } UCB$R_FLCK_OVERLAY;
    variant_union  {
        unsigned long int UCB$L_FPC;    /*FORK PC                           */
        unsigned long int UCB$L_ASTQFL; /* MB -- AST QUEUE LISTHEAD FORWARD LINK
 */
        char UCB$T_PARTNER;             /* NET -- PARTNER'S NODENAME        */
        } UCB$R_FPC_OVERLAY;
    variant_union  {
        unsigned long int UCB$L_FR3;    /*FORK R3                           */
        unsigned long int UCB$L_ASTQBL; /* MB -- AST QUEUE LISTHEAD BACKWARD
LINK  */
        } UCB$R_FR3_OVERLAY;
    variant_union  {
        unsigned long int UCB$L_FR4;    /*FORK R4                           */
        variant_struct  {
            unsigned short int UCB$W_MSGMAX; /* MB -- MAXIMUM MESSAGES ALLOWED 
*/
            unsigned short int UCB$W_MSGCNT; /* MB -- CURRENT NUMBER OF MESSAGES
 */
            } UCB$R_MB_FR4_FIELDS;
        unsigned long int UCB$L_FIRST;  /* NET -- ADDR OF 1ST SEG OF CHAINED MSG
 */
        } UCB$R_FR4_OVERLAY;
    variant_union  {
        unsigned short int UCB$W_BUFQUO; /* BUFFERED I/O QUOTA CHARGED FOR THIS
UCB */
        unsigned short int UCB$W_DSTADDR; /* NET -- REMOTE CONNECT NO.      */
        } UCB$R_BUFQUO_OVERLAY;
    variant_union  {
        unsigned short int UCB$W_INIQUO; /* INITIAL BUFFERED I/O QUOTA FOR THIS
UCB */
        unsigned short int UCB$W_SRCADDR; /* NET -- LOCAL CONNECT NO.       */
        } UCB$R_INIQUO_OVERLAY;
    struct ORBDEF *UCB$L_ORB;		/* OBJECT'S RIGHTS BLOCK ADDRESS    */
    variant_union  {
        unsigned long int UCB$L_LOCKID; /*DEVICE LOCK ID                    */
        unsigned long int UCB$L_CPID;   /*PID CHARGED FOR BUFQUO BY UCBCREDEL */
        } UCB$R_LOCKID_OVERLAY;
    unsigned long int UCB$L_CRB;        /*ADDRESS OF PRIMARY CHANNEL REQUEST
BLOCK  */
    unsigned long int UCB$L_DLCK;       /*ADDRESS OF DEVICE IPL SPINLOCK    */
    struct DDBDEF *UCB$L_DDB;		/*BACKPOINTER TO DEVICE DATA BLOCK  */
    unsigned long int UCB$L_PID;        /*PROCESS ID OF OWNER PROCESS       */
    unsigned long int UCB$L_LINK;       /*ADDRESS OF NEXT UCB FOR RESPECTIVE DDB
 */
    struct VCBDEF *UCB$L_VCB;		/*ADDRESS OF VOLUME CONTROL BLOCK   */
    variant_union  {                            /*DEVICE CHARACTERISTIC BITS    
   */
        unsigned int UCB$Q_DEVCHAR [2]; /* Device characteristic bits quadword */
        variant_struct  {
            unsigned long int UCB$L_DEVCHAR; /*  Original device characteristic
bits */
            unsigned long int UCB$L_DEVCHAR2; /*  Extended device characteristic
bits */
            } UCB$R_DEVCHAR_Q_BLOCK;
        } UCB$R_DEVCHAR;
    unsigned long int UCB$L_AFFINITY;   /*DEVICE AFFINITY                   */
    variant_union  {
        unsigned long int UCB$L_XTRA;   /*EXTRA LONGWORD (FOR SMP)          */
        unsigned long int UCB$L_ALTIOWQ; /*ALTERNATE STARTIO WAIT           */
/*QUEUE                                                                     */
        } UCB$R_XTRA_OVERLAY;
    unsigned char UCB$B_DEVCLASS;       /*DEVICE CLASS                      */
    unsigned char UCB$B_DEVTYPE;        /*DEVICE TYPE                       */
    unsigned short int UCB$W_DEVBUFSIZ; /*DEVICE DEFAULT BUFFER SIZE        */
    variant_union  {                            /*DEVICE DEPENDENT DATA         
   */
        unsigned int UCB$Q_DEVDEPEND [2]; /*Device dependent quadword       */
        variant_struct  {
            variant_union  {
                unsigned long int UCB$L_DEVDEPEND; /*  First device dependent
longword */
                variant_struct  {               /*    Disk fields               
   */
                    unsigned char UCB$B_SECTORS; /*	Sectors per track   */
                    unsigned char UCB$B_TRACKS; /*	Track per cylinder  */
                    unsigned short int UCB$W_CYLINDERS; /*	Cylinders per
disk */
                    } UCB$R_DISK_DEVDEPEND;
                variant_struct  {               /*    Terminal fields           
   */
                    char UCBDEF$$_TERM_DEVDEPEND_FILL [3];
                    unsigned char UCB$B_VERTSZ; /*	Vertical page size
(lines per page) */
                    } UCB$R_TERM_DEVDEPEND;
                variant_struct  {               /*    Network fields            
   */
                    unsigned char UCB$B_LOCSRV; /*	Local link services  */
                    unsigned char UCB$B_REMSRV; /*	Remote link services */
                    unsigned short int UCB$W_BYTESTOGO; /*	No. of bytes
left in rcv bfr */
                    } UCB$R_NET_DEVDEPEND;
                } UCB$R_DEVDEPEND_OVERLAY;
            variant_union  {
                unsigned long int UCB$L_DEVDEPND2; /*  Second device dependent
long word  */
                unsigned long int UCB$L_TT_DEVDP1; /*    Terminal -- Device
dependent long word  */
                } UCB$R_DEVDEPND2_OVERLAY;
            } UCB$R_DEVDEPEND_Q_BLOCK;
        } UCB$R_DEVDEPEND_Q_OVERLAY;
    variant_union  {                            /*2nd QUADWORD DEVICE DEPENDENT
DATA  */
        unsigned int UCB$Q_DEVDEPEND2 [2]; /*Device dependent quadword      */
        variant_struct  {
            variant_union  {
                unsigned long int UCB$L_DEVDEPND3; /*  3rd device dependent
longword */
                } UCB$R_DEVDEPND3_OVERLAY;
            variant_union  {
                unsigned long int UCB$L_DEVDEPND4; /*  4th device dependent long
word  */
                } UCB$R_DEVDEPND4_OVERLAY;
            } UCB$R_DEVDEPEND2_Q_BLOCK;
        variant_struct  {                       /* Tape Mount verification byte
counts */
            unsigned short int UCB$W_TMV_BCNT1; /* Byte count for 1st CRC   */
            unsigned short int UCB$W_TMV_BCNT2; /* ...2nd CRC               */
            unsigned short int UCB$W_TMV_BCNT3; /* ...3rd CRC               */
            unsigned short int UCB$W_TMV_BCNT4; /* ...4th CRC               */
            } UCB$R_TMV_BCNT;
        } UCB$R_DEVDEPEND2_Q_OVERLAY;
    unsigned long int UCB$L_IOQFL;      /*I/O QUEUE LISTHEAD FORWARD LINK   */
    unsigned long int UCB$L_IOQBL;      /*I/O QUEUE LISTHEAD BACKWARD LINK  */
    unsigned short int UCB$W_UNIT;      /*PHYSICAL DEVICE UNIT NUMBER       */
    variant_union  {
        unsigned short int UCB$W_CHARGE; /*MAILBOX BYTE COUNT QUOTA CHARGE  */
        unsigned short int UCB$W_RWAITCNT; /* CLASS DRIVERS -- THREADS WAITING
RESOURCES  */
        variant_struct  {
            unsigned char UCB$B_CM1;    /* LEVEL 1 CONTROLLER ALLOCATION MASK  */
            unsigned char UCB$B_CM2;    /* LEVEL 2 CONTROLLER ALLOCATION MASK  */
            } UCB$R_CTRLR_ALLOC_FIELDS;
        } UCB$R_CHARGE_OVERLAY;
    struct IRPDEF *UCB$L_IRP;		/*CURRENT I/O REQUEST PACKET ADDRESS  */
    unsigned short int UCB$W_REFC;      /*REFERENCE COUNT OF PROCESSES      */
    variant_union  {
        unsigned char UCB$B_DIPL;       /*DEVICE INTERRUPT PRIORITY LEVEL   */
        unsigned char UCB$B_STATE;      /* NET -- LINK STATE FOR NETWORK
TRANSITIONS  */
        } UCB$R_DIPL_OVERLAY;
    unsigned char UCB$B_AMOD;           /*ALLOCATION ACCESS MODE            */
    unsigned long int UCB$L_AMB;        /*ASSOCIATED UNIT CONTROL BLOCK POINTER 
*/
    variant_union  {
        unsigned long int UCB$L_STS;    /*DEVICE UNIT STATUS                */
        unsigned short int UCB$W_STS;
        variant_struct  {
            unsigned UCB$V_TIM : 1;     /* TIME OUT ENABLED (1=YES)         */
            unsigned UCB$V_INT : 1;     /* INTERRUPT EXPECTED (1=YES)       */
            unsigned UCB$V_ERLOGIP : 1; /* ERROR LOG IN PROGRESS ON UNIT (1=YES)
 */
            unsigned UCB$V_CANCEL : 1;  /* CANCEL I/O ON UNIT (1=YES)       */
            unsigned UCB$V_ONLINE : 1;  /* UNIT ONLINE (1=YES)              */
            unsigned UCB$V_POWER : 1;   /* POWER FAILED WHILE UNIT BUSY (1=YES) 
*/
            unsigned UCB$V_TIMOUT : 1;  /* UNIT TIMED OUT (1=YES)           */
            unsigned UCB$V_INTTYPE : 1; /* RECEIVER INTERRUPT IF SET        */
            unsigned UCB$V_BSY : 1;     /* UNIT IS BUSY (1=YES)             */
            unsigned UCB$V_MOUNTING : 1; /* DEVICE IS BEING MOUNTED         */
            unsigned UCB$V_DEADMO : 1;  /* DEALLOCATE AT DISMOUNT           */
            unsigned UCB$V_VALID : 1;   /* VOLUME IS SOFTWARE VALID         */
            unsigned UCB$V_UNLOAD : 1;  /* UNLOAD VOLUME AT DISMOUNT        */
            unsigned UCB$V_TEMPLATE : 1; /* SET IF THIS IS TEMPLATE UCB     */
            unsigned UCB$V_MNTVERIP : 1; /* MOUNT VERIFICATION IN PROGRESS  */
            unsigned UCB$V_WRONGVOL : 1; /* WRONG VOLUME DETECTED DURING MOUNT
VERIFICATION  */
            unsigned UCB$V_DELETEUCB : 1; /* DELETE THIS UCB WHEN REFC REACHES
ZERO */
            unsigned UCB$V_LCL_VALID : 1; /* VOLUME IS VALID ON THE LOCAL NODE */
            unsigned UCB$V_SUPMVMSG : 1; /* IF SET, SUPPRESS SUCCESS TYPE MOUNT
VER. MSGS. */
            unsigned UCB$V_MNTVERPND : 1; /* MOUNT VERIFICATION IS PENDING ON
BUSY DEVICE. */
            unsigned UCB$V_DISMOUNT : 1; /* DISMOUNT IN PROGRESS            */
            unsigned UCB$V_CLUTRAN : 1; /* VAXcluster STATE TRANSITION IN
PROGRESS */
            unsigned UCB$V_WRTLOCKMV : 1; /* Write-locked mount verification in
progress */
            unsigned UCB$V_SVPN_END : 1; /* Last byte used from page mapped by
SVPN */
            unsigned UCB$V_ALTBSY : 1;  /* Unit is busy via alternate startio
path */
            unsigned UCB$V_SNAPSHOT : 1; /*   Restart validation is in progress
*/
            unsigned UCB$V_fill_0 : 6;
            } UCB$R_STS_BITS;
        } UCB$R_STS_OVERLAY;
    variant_union  {
        unsigned short int UCB$W_DEVSTS; /*DEVICE DEPENDENT STATUS          */
        variant_struct  {                       /* Generally used bits          
   */
            unsigned UCB$V_JOB : 1;     /*   Job Controller notified        */
            unsigned UCB$v_devsts_gen_fill : 5;
            unsigned UCB$V_TEMPL_BSY : 1; /*   Template UCB is busy         */
            unsigned UCB$V_fill_1 : 1;
            } UCB$R_DEVSTS_GENERAL_BITS;
        variant_struct  {                       /* Mailbox status bits          
   */
            unsigned UCB$V_PRMMBX : 1;  /*   Permanent mailbox              */
            unsigned UCB$V_DELMBX : 1;  /*   Mailbox marked for delete      */
            unsigned UCB$v_devsts_mb_fill : 1;
            unsigned UCB$V_SHMMBX : 1;  /*   Shared memory mailbox          */
            unsigned UCB$V_fill_2 : 4;
            } UCB$R_DEVSTS_MAILBX_BITS;
        variant_struct  {                       /* Terminal status bits         
   */
            unsigned UCB$v_devsts_tt_fill : 1;
            unsigned UCB$V_TT_TIMO : 1; /*   Terminal read timeout in progress 
*/
            unsigned UCB$V_TT_NOTIF : 1; /*   Terminal user notified of
unsolicted data  */
            unsigned UCB$V_TT_HANGUP : 1; /*   Process hang up              */
            unsigned UCB$V_TT_DEVSTS_FILL : 11; /*   fill to the end the word */
            unsigned UCB$V_TT_NOLOGINS : 1; /* NOLOGINS ALLOWED             */
            } UCB$R_DEVSTS_TERM_BITS;
        variant_struct  {                       /* Network status bits          
   */
            unsigned UCB$v_devsts_net_fill1 : 2;
            unsigned UCB$V_NT_BFROVF : 1; /*   Too many bytes rcvd          */
            unsigned UCB$v_devsts_net_fill2 : 1;
            unsigned UCB$V_NT_NAME : 1; /*   Link has declared a connect name  */
            unsigned UCB$V_NT_BREAK : 1; /*   Link is being broken          */
            unsigned UCB$V_fill_3 : 2;
            } UCB$R_DEVSTS_NET_BITS;
        variant_struct  {                       /* Disk (all disks) status bits 
   */
            unsigned UCB$V_ECC : 1;     /*   ECC correction was made        */
            unsigned UCB$V_DIAGBUF : 1; /*   Diagnostic buffer specified    */
            unsigned UCB$V_NOCNVRT : 1; /*   No LBN to media address conversion
*/
            unsigned UCB$V_DX_WRITE : 1; /*   Console floppy write operation */
            unsigned UCB$V_DATACACHE : 1; /*   Data blocks being cached     */
            unsigned UCB$V_fill_4 : 3;
            } UCB$R_DEVSTS_DISKS;
        variant_struct  {                       /* MSCP class driver bits       
   */
            unsigned UCB$v_byte_fill : 8;
            unsigned UCB$V_MSCP_MNTVERIP : 1; /*   Mount verification in
progress */
            unsigned UCB$V_MSCP_INITING : 1; /*   UCB is being initialized  */
            unsigned UCB$V_MSCP_WAITBMP : 1; /*   RWAITCNT has been bumped  */
            unsigned UCB$V_MSCP_FLOVR : 1; /*   Bit toggled everytime a failover
succeeds. */
            unsigned UCB$V_MSCP_PKACK : 1; /*   Set when a IO$_PACKACK is in
progress. */
            unsigned UCB$V_MSCP_WRTP : 1; /*   Unit MSCP write protected in some
way. */
            unsigned UCB$V_MSCP_IGNSRV : 1; /*   Ignore served paths during
connection failover. */
            unsigned UCB$V_fill_5 : 1;
            } UCB$R_DEVSTS_MSCP_CLASS_BITS;
        variant_struct  {                       /* Disk class driver bits       
   */
            unsigned UCB$v_unused_fill : 3;
            unsigned UCB$V_DU_SHMV_STRTD : 1; /*   Shadowing mount verification
started */
            unsigned UCB$v_skip_datacache : 1;
            unsigned UCB$V_DU_0MNOTE : 1; /*   Zero members message sent    */
            unsigned UCB$V_fill_6 : 2;
            } UCB$R_DEVSTS_DU_CLASS_BITS;
        variant_struct  {                       /* Tape class driver bits       
   */
            unsigned UCB$V_TU_OVRSQCHK : 1; /*   Override sequence checking */
            unsigned UCB$V_TU_TRACEACT : 1; /*   IRP trace table active     */
            unsigned UCB$V_TU_SEQNOP : 1; /*   Sequential NOP tape operation in
progress */
            unsigned UCB$V_TU_1DENS : 1; /*   Single density device         */
            unsigned UCB$V_TU_DENS_DETERMINED : 1; /*   Density already
determined. Basically a */
/*    bit that says that a particular part of                               */
/*    PACKACK processing has already been done                              */
/*    once for this unit.                                                   */
            unsigned UCB$V_fill_7 : 3;
            } UCB$R_DEVSTS_TU_CLASS_BITS;
        variant_struct  {                       /* Shadowing virtual driver bits
   */
            unsigned UCB$v_byte_fill2 : 10;
            unsigned UCB$V_SHD_SEQCMD_HERE : 1; /*   Sequential command in
progress on this node */
            unsigned UCB$V_SHD_SEQCMD_THERE : 1; /*   Sequential command in
progress on another node */
            unsigned UCB$V_SHD_PASSIVE_MV : 1; /*   Passive MV in progress  */
            unsigned UCB$V_fill_8 : 3;
            } UCB$R_DEVSTS_SHD_BITS;
        } UCB$R_DEVSTS_OVERLAY;
    unsigned short int UCB$W_QLEN;      /* Device queue length              */
    unsigned long int UCB$L_DUETIM;     /*DUE TIME FOR I/O COMPLETION       */
    unsigned long int UCB$L_OPCNT;      /*COUNT OF OPERATIONS COMPLETED     */
    variant_union  {
        unsigned long int UCB$L_SVPN;   /*SYSTEM VIRTUAL PAGE/MAP REGISTER
NUMBER  */
        unsigned long int UCB$L_LOGADR; /* MB -- LOGICAL NAME BLOCK ADDRESS  */
        } UCB$R_SVPN_OVERLAY;
    unsigned long int UCB$L_SVAPTE;     /*SYSTEM VIRTUAL ADDRESS OF PTE     */
    unsigned short int UCB$W_BOFF;      /*BYTE OFFSET IN FIRST PAGE         */
    unsigned short int UCB$W_BCNT;      /*BYTE COUNT OF TRANSFER            */
    unsigned char UCB$B_ERTCNT;         /*ERROR LOG DEVICE CURRENT ERROR RETRY
COUNT  */
    unsigned char UCB$B_ERTMAX;         /*ERROR LOG DEVICE MAXIMUM ERROR RETRY
COUNT  */
    unsigned short int UCB$W_ERRCNT;    /*DEVICE ERROR COUNT                */
    unsigned long int UCB$L_PDT;        /*ADDR OF PORT DESCRIPTOR TABLE     */
    unsigned long int UCB$L_DDT;        /*ADDR OF DDT (OPTIONAL BUT PREFERRED) 
*/
    variant_union  {
        unsigned long int UCB$L_MEDIA_ID; /*BIT ENCODED MEDIA IDENTIFICATION  */
        variant_struct  {
            unsigned UCB$V_MEDIA_ID_NN : 7; /* MEDIA NAME NUMBER            */
            unsigned UCB$V_MEDIA_ID_N2 : 5; /* MEDIA NAME CHAR 2            */
            unsigned UCB$V_MEDIA_ID_N1 : 5; /* MEDIA NAME CHAR 1            */
            unsigned UCB$V_MEDIA_ID_N0 : 5; /* MEDIA NAME CHAR 0            */
            unsigned UCB$V_MEDIA_ID_T1 : 5; /* MEDIA TYPE CHAR 1            */
            unsigned UCB$V_MEDIA_ID_T0 : 5; /* MEDIA TYPE CHAR 0            */
            } UCB$R_MEDIA_ID_SUBFIELDS;
        } UCB$R_MEDIA_ID_OVERLAY;
/*                                                                          */
/* ERROR LOG DEVICES (ALL)                                                  */
/*                                                                          */
    unsigned char UCB$B_SLAVE;          /*SLAVE CONTROLLER NUMBER           */
    unsigned char UCB$B_SPR;            /*SPARE UNUSED BYTE                 */
    unsigned char UCB$B_FEX;            /*FUNCTION DISPATCH TABLE INDEX     */
    unsigned char UCB$B_CEX;            /*CASE TABLE FUNCTION EXECUTION INDEX  */
    unsigned long int UCB$L_EMB;        /*ADDRESS OF ERROR MESSAGE BUFFER   */
    short int UCBDEF$$_FILL_1;          /*SPARE UNUSED WORD                 */
    unsigned short int UCB$W_FUNC;      /*I/O FUNCTION MODIFIERS            */
    unsigned long int UCB$L_DPC;        /*SAVED DRIVER SUBROUTINE RETURN ADDRESS
*/
/*                                                                          */
/* DUAL PORTED DEVICES (ALL DISKS AND MOST TAPES)                           */
/*                                                                          */
    variant_union  {
        variant_struct  {
            unsigned long int UCB$L_DP_DDB; /* Pointer to alternate DDB     */
            unsigned long int UCB$L_DP_LINK; /* Address of next UCB for this DDB
 */
            unsigned long int UCB$L_DP_ALTUCB; /* Addr of alternate UCB for this
unit */
            } UCB$R_OLD_DUAL_PATH;
        variant_struct  {
            unsigned long int UCB$L_2P_DDB; /* Pointer to alternate DDB     */
            unsigned long int UCB$L_2P_LINK; /* Address of next UCB for this DDB
 */
            unsigned long int UCB$L_2P_ALTUCB; /* Addr of alternate UCB for this
unit */
            } UCB$R_PREFERED_DUAL_PATH;
        } UCB$R_DUAL_PATH;
/*                                                                          */
/* ALL DISKS AND TAPES                                                      */
/*                                                                          */
    variant_union  {
        unsigned short int UCB$W_DIRSEQ; /* Directory sequence number       */
        variant_struct  {
            unsigned UCB$v_filler : 15;
            unsigned UCB$V_AST_ARMED : 1; /*  Blocking AST armed flag       */
            } UCB$r_fill_10;
        } UCB$r_fill_9;
    unsigned char UCB$B_ONLCNT;         /* Online count                     */
    variant_union  {
        variant_struct  {
            char UCB$b_reserved;
            unsigned long int UCB$L_MAXBLOCK; /* Random access device highest
block */
            unsigned long int UCB$L_MAXBCNT; /* Maximum transfer BCNT       */
            unsigned long int UCB$L_DCCB; /* Pointer to data cache control block
*/
            unsigned long int UCB$L_QLENACC; /* Queue length accumulator    */
            } UCB$R_DISK_FIELDS;
        variant_struct  {
            unsigned char UCB$B_PREV_RECORD; /* Tape position prior at start of
last I/O */
            unsigned long int UCB$L_RECORD; /* Current tape position or frame
counter */
            long int UCB$l_reserved;
            unsigned long int UCB$L_TMV_RECORD; /* Position following last
guaranteed successful I/O */
            unsigned short int UCB$W_TMV_CRC1; /* 1st CRC for Mount Ver's media
validation */
            unsigned short int UCB$W_TMV_CRC2; /* 2nd CRC ...               */
            unsigned short int UCB$W_TMV_CRC3; /* 3rd CRC ...               */
            unsigned short int UCB$W_TMV_CRC4; /* 4th CRC ...               */
            } UCB$R_TAPE_FIELDS;
        } UCB$R_DISKTAPE_OVERLAY;
#pragma standard
/*                                                                          */
/* MSCP DISKS AND TAPES UCB EXTENSION                                       */
/*                                                                          */
    unsigned long int UCB$L_CDDB;       /* Pointer to active CDDB           */
    unsigned long int UCB$L_2P_CDDB;    /* Pointer to alternate CDDB        */
    unsigned long int UCB$L_CDDB_LINK;  /* Pointer to next UCB in CDDB chain */
    unsigned long int UCB$L_CDT;        /* Pointer to active CDT            */
    unsigned long int UCB$L_WAIT_CDDB;  /* Address of CDDB waiting for mnt. ver.
to complete on this UCB */
    unsigned long int UCB$L_PREF_CDDB;  /* CDDB address for preferred path  */
    unsigned int UCB$Q_UNIT_ID [2];     /* Unique MSCP unit identifier      */
    unsigned short int UCB$W_MSCPUNIT;  /* Primary path MSCP unit number    */
    unsigned short int UCB$W_UNIT_FLAGS; /* MSCP unit flags                 */
    unsigned short int UCB$W_LCL_MSCPUNIT; /* MSCP unit number for local
(non-emulated) controllers */
    unsigned short int UCB$W_SRV_MSCPUNIT; /* MSCP unit number for served
(emulated) controllers */
    unsigned long int UCB$L_MSCPDEVPARAM; /* MSCP device-dependent parameters */
    unsigned char UCB$B_FREECAP;        /* Free capacity                    */
    unsigned char UCB$b_reserved2;
    unsigned short int UCB$W_MSCP_RESVDW; /* Reserved for MSCP enhancements */
    unsigned long int UCB$L_SHAD;       /* Virtual Unit Pointer to HBS SHAD */
    } ;
#define __UCBDEF_LOADED 1
#endif /* __UCBDEF_LOADED */
#endif  /* __DECC && __ALPHA */

#if defined (__DECC) && defined (__ALPHA)
#include <ccbdef.h>
#else
#ifndef __CCBDEF_LOADED
/*	  
**  From SMFS' ccbdef.h
*/
/**/
/******************************************************************************/
/**                                                                          **/
/**  Copyright (c) 1991                                                      **/
/**  by DIGITAL Equipment Corporation, Maynard, Mass.                        **/
/**                                                                          **/
/**  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.                 **/
/**                                                                          **/
/******************************************************************************/
/*******************************************************************************
*************************************************/
/* Created 11-OCT-1991 19:58:42 by VAX SDL T3.2-8      Source: 28-FEB-1991
19:12:36 _$254$DUA99:[LIB.LIS]CCBDEF.SDL;1 */
/*******************************************************************************
*************************************************/
 
/*** MODULE $CCBDEF ***/
/*+                                                                         */
/* CCB - CHANNEL CONTROL BLOCK                                              */
/*                                                                          */
/* THERE IS ONE CHANNEL CONTROL BLOCK FOR EACH SOFTWARE CHANNEL THAT A      */
/* PROCESS MAY INITIATE I/O REQUESTS ON. THE NUMBER OF SUCH I/O CHANNELS    */
/* IS DETERMINED BY THE FIXED NUMBER ASSIGNED TO A PROCESS PLUS ANY         */
/* ADDITIONAL CHANNELS REQUIRED BY THE IMAGE CURRENTLY BEING EXECUTED       */
/* BY THE PROCESS.                                                          */
/*                                                                          */
/* **** WARNING ****                                                        */
/*        THE CHANNEL CONTROL BLOCK IS ASSUMED TO BE FOUR LONG WORDS        */
/* THROUGHOUT THE EXEC.  ITS SIZE MAY BE CHANGED BUT ONLY BY POWERS OF 2.   */
/*-                                                                         */
#define CCB$M_AMB 1
#define CCB$M_IMGTMP 2
#define CCB$M_RDCHKDON 4
#define CCB$M_WRTCHKDON 8
#define CCB$M_LOGCHKDON 16
#define CCB$M_PHYCHKDON 32
#define CCB$M_NOREADACC 64
#define CCB$M_NOWRITEACC 128
#define CCB$K_LENGTH 16                 /*LENGTH OF CCB                     */
#define CCB$C_LENGTH 16                 /*LENGTH OF CCB                     */
struct CCBDEF {
    struct UCBDEF *CCB$L_UCB;		/*ADDRESS OF ASSIGNED DEVICE UCB    */
    struct WCBDEF *CCB$L_WIND;		/*ADDRESS OF WINDOW BLOCK           */
    union  {
        unsigned char CCB$B_STS;        /*CHANNEL STATUS                    */
        struct  {
            unsigned CCB$V_AMB : 1;     /* MAILBOX ASSOCIATED WITH CHANNEL  */
            unsigned CCB$V_IMGTMP : 1;  /* IMAGE TEMPORARY                  */
            unsigned CCB$V_RDCHKDON : 1; /* READ PROTECTION CHECK COMPLETED */
            unsigned CCB$V_WRTCHKDON : 1; /* WRITE PROTECTION CHECK COMPLETED */
            unsigned CCB$V_LOGCHKDON : 1; /* LOGICAL I/O ACCESS CHECK DONE  */
            unsigned CCB$V_PHYCHKDON : 1; /* PHYSICAL I/O ACCESS CHECK DONE */
            unsigned CCB$V_NOREADACC : 1; /* READ ACCESS TO DEVICE DISABLED */
            unsigned CCB$V_NOWRITEACC : 1; /* WRITE ACCESS TO DEVICE DISABLED */
            } CCB$R_STS_BITS;
        } CCB$R_STS_OVERLAY;
    unsigned char CCB$B_AMOD;           /*ACCESS MODE THAT ASSIGNED CHANNEL  */
    unsigned short int CCB$W_IOC;       /*NUMBER OF OUTSTANDING I/O REQUESTS ON
CHANNEL  */
    struct IRPDEF *CCB$L_DIRP;		/*DEACCESS I/O REQUEST PACKET ADDRESS  */
    } ;
#define __CCBDEF_LOADED 1
#endif     /* __CCBDEF_LOADED */
#endif  /* __DECC && __ALPHA */
/*	  
**  From SMFS' smfs.h:
*/	  
/*	  
**  smfs.h
*/	  

/*
**++
**  FACILITY:  Sequential Media Filesystem
**
**  MODULE DESCRIPTION:
**
**      Contains general definitions and declarations for SMF.  Included in both
**	the ACP and DCL.
**
**  AUTHORS:
**
**      Dan Kyler
**
**  CREATION DATE:  9 February 1994
**
**  DESIGN ISSUES:
**
**      This file should only contain general support stuff.
**
**
**  MODIFICATION HISTORY:
**
**      9-Feb-1994  DBK	    Original
**--
*/


/*
**
**  MACRO DEFINITIONS
**
*/

#define	SUCCESS(x)	((x)&1)

#define FAILURE(x)	(!((x)&1))

#define MIN(a,b)	((a>b)?b:a)

#define MAX(a,b)	((a<b)?b:a)

/*	  
**  
**  TYPE DEFINITIONS
**
*/	  

typedef struct
{
    unsigned short int	status;
    unsigned short int	len;
    unsigned long int	func_specific;
} IOSBDEF;

typedef struct
{
    unsigned short int	len;
    unsigned short int	code;
    void *		data;
    unsigned short int *retlen;
} ITMLST3;


3702.2FASTTAPE_FUNCTIONS.HSTOWKS::SLUISHans van Sluis -- Storage Engineering Support Europe- DTN 889 9526Mon Mar 24 1997 12:3826
#ifndef FASTTAPE_FUNCTIONS_H
#define FASTTAPE_FUNCTIONS_H
typedef unsigned long int	STATUS_VALUE;

/*----------------------------------------------------------------

   Function prototypes

----------------------------------------------------------------*/

extern STATUS_VALUE rewind_tape (
	     int	    channel);

extern STATUS_VALUE open_channel (
	     char *         device_name,
             int *          channel);

extern STATUS_VALUE close_channel (
	     int	    channel);

extern STATUS_VALUE skip_tape_marks (
    	     int	    channel,
    	     int	    marks_to_skip,
    	     int	    flags,
    	     int *	    marks_skipped);
#endif
3702.3FASTTAPE.CSTOWKS::SLUISHans van Sluis -- Storage Engineering Support Europe- DTN 889 9526Mon Mar 24 1997 12:39962
#ifndef VAX
#pragma standard
#endif

/*
**++
**  FACILITY:  Storage Management Group Products
**
**  MODULE DESCRIPTION:
**
**      Contains routine skip_tape_marks, which uses the fastest possible method
**    to skip tape marks, based on the controller type and capabilities.
**
**  AUTHORS:
**
**      Dan Kyler
**
**  CREATION DATE:  18 May 1994
**
**  DESIGN ISSUES:
**
**      In order to keep the routine general, the address of a SYS$QIOW routine
**    is passed in so that applications may do thread safe I/O in their own
**    way.
**
**    This is most definitely VMS code.
**
**  MODIFICATION HISTORY:
**
**    10-Oct-1996   Holsinger      QAR 977: handle SS$_ILLIOFUNC
**--
*/

/*
**
**  INCLUDE FILES
**
*/
#include <dvidef.h>
#include <iodef.h>
#include <mtdef.h>
#include <ssdef.h>
#include <errno.h>
#include <jpidef.h>
#include <math.h>
#include <rms.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <descrip.h>

#include "fasttape_functions.h"
#include "fasttape.h"
/*
**  Add translations for the hand-crafted v.s. actual system definition files.
**
**  These are simply case translations since the hand-crafted version of the
**  file wanted to be in upcase; for compatibility with COBOL - or something.
*/
#if defined(__DECC) && defined(__ALPHA)
/*
**  Whole structures
*/

#define CCBDEF    	    _ccb		/* channel control block    */
#define UCBDEF    	    _dt_ucb		/* Disk and tape ucb	    */
#define DEVDEF    	    devdef		/* Device definitions	    */

/*
**  Fields
*/

#define CCB$B_AMOD    	ccb$b_amod                             
#define CCB$L_UCB    	ccb$l_ucb                              
#define DEV$V_MSCP    	dev$v_mscp
#define DEV$V_SCSI    	dev$v_scsi
#define UCB$L_RECORD    	ucb$l_record                           
#define UCB$L_DEVDEPEND    	ucb$r_dt_ucb.ucb$l_devdepend           
#endif

#ifndef HSM$ALPHA
globalref char *    CTL$GL_CCBBASE;
#endif

unsigned long int   sys$qiow();
/*
**  Static function prototypes
*/
static unsigned long int get_ucb_record_count (
    	     unsigned short int	channel);

static void set_ucb_record_count (
    	     unsigned short int  channel,
    	     unsigned long  int  position);

static void set_position_lost (
    	    unsigned short int  channel);

static struct UCBDEF * channel_to_ucb (
    		    int		channel);

static STATUS_VALUE scsi_read_position (
	     int		        channel,
    	     unsigned long int *	pos);

static int b2_to_i (
        unsigned char *	bytes);

static STATUS_VALUE scsi_skip_files(
    		    int		    channel,
    		    int		    number,
    		    IOSB *	    iosb);

static STATUS_VALUE scsi_io(
    int                       channel,
    char *                    command,
    int                       cmdlen,
    char *                    response,
    int                       resplen,
    struct sense_data_struct *sense_data);

static STATUS_VALUE scsi_read_sense (
   	     int		channel,
    	     struct sense_data_struct *	sense_data);

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      Performs a rewind of tape.
**
**  FORMAL PARAMETERS:
**
**      channel - the channel number assigned to the device on which to do the
**    I/O to rewind the tape.
**
**  RETURN VALUE:
**
**      The VMS status value indicating success or failure of the operation.
**
**  SIDE EFFECTS:
**
**      Rewinds tape.
**
**  DESIGN:
**
**      VMS specific.
**
**  PRECONDITIONS:
**
**      None
**
**
**--
*/
STATUS_VALUE rewind_tape (
    	    int		    channel)
{
    IOSBDEF         iosb;
    STATUS_VALUE    status;

    status = sys$qiow (0,
    	      channel,
    	      IO$_REWIND,
    	      &iosb,
    	      0,	    /* No AST Routine   */
    	      0,            /* No AST Parameter */
    	      0, 0, 0, 0, 0, 0);
    if (FAILURE(status))
        return status;
    
    return iosb.status;
    

}

STATUS_VALUE open_channel (
    	    char *	    device_name,
    	    int *           channel)
{
    STATUS_VALUE                status;
    struct dsc$descriptor_s	devnam;

    devnam.dsc$w_length = strlen(device_name);
    devnam.dsc$a_pointer = device_name;
    devnam.dsc$b_class = DSC$K_CLASS_S;
    devnam.dsc$b_dtype = DSC$K_DTYPE_T;

    status = sys$assign( &devnam,
    		         channel,
                         0, 0, 0 );
    if (FAILURE(status))
        fprintf( stdout, "Error on opening device %s status code %d\n",
    	 device_name,
    	 status );

    return status;
}

STATUS_VALUE close_channel (
    	    int		    channel)
{
    STATUS_VALUE    status;

    status = sys$dassgn( channel );
    if (FAILURE(status))
        fprintf( stdout, "Error on closing channel %d status code %d\n",
    	 channel,
    	 status );

    return status;
}

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      Does a generic skip tape mark operation based on the controller type and
**    capabilities.  The basic algorithm is:
**
**    if scsi
**    then
**        if read position is supported
**        then
**    	send scsi skip files command directly to controller
**    	send scsi read position command directly to controller
**    	update ucb with result of read position
**        else
**    	issue IO$_SKIPFILE $QIOW
**        endif
**    else if mscp
**    then
**        if detect_leot bit is clear
**        then
**    	issue IO$_SPACEFILE $QIOW
**        else
**    	issue IO$_SKIPFILE $QIOW
**        endif
**    else
**        issue IO$_SKIPFILE $QIOW
**    endif
**
**  FORMAL PARAMETERS:
**
**      channel - the channel number assigned to the device on which to do the
**    I/O to skip file marks.
**
**    marks_to_skip - the number of tape marks to be skipped.
**
**    flags - a longword bitmask containing flags that affect the operation.
**    The currently defined bits are:
**
**        bit #   mask    meaning
**        -----   ----    ---------------------------------------------
**          0	    0001    Detect LEOT.  If set, the search will stop when
**    		    2 consecutive tape marks are detected.  This will
**    		    be slower with some MSCP devices, but necessary to
**    		    find the logical end of tape when its exact tape
**    		    mark position is unknown.
**
**    marks_skipped - the address of an integer to receive the actual number
**    of tape marks that were skipped.
**
**  RETURN VALUE:
**
**      The VMS status value indicating success or failure of the operation.
**
**  SIDE EFFECTS:
**
**      Moves tape.  Directly updates the UCB UCB$L_RECORD field for SCSI
**    devices which support the SCSI read position command.
**
**  DESIGN:
**
**      VMS specific.
**
**  PRECONDITIONS:
**
**      Requires CMKRNL, DIAGNOSE, and PHY_IO privileges.
**
**
**
**--
*/
STATUS_VALUE skip_tape_marks (
    	    int		    channel,
    	    int		    marks_to_skip,
    	    int		    flags,
    	    int *	    marks_skipped)
{
    IOSBDEF         iosb;
    STATUS_VALUE    status;
    STATUS_VALUE    final_status;
    struct
    {
        unsigned long int arg_count;
        unsigned long int arg1;
        unsigned long int arg2;
        unsigned long int arg3;
        unsigned long int arg4;
        unsigned long int arg5;
        unsigned long int arg6;
        unsigned long int arg7;
        unsigned long int arg8;
    } arglist;
    union DEVDEF                devchar2;
    ITMLST3                     dvi_itmlst[2] =
    {
        { sizeof(union DEVDEF),	DVI$_DEVCHAR2,	&devchar2,  0 },
        { 0,			0,		0,	    0 }
    };

    status = sys$getdviw (
    	                   0,
    	                   channel,
    	                   0,
    	                   &dvi_itmlst,
    	                   &iosb,
    	                   0, 0, 0);
    if (FAILURE(status))
        return status;
    if (FAILURE(iosb.status))
        return iosb.status;

    if (devchar2.DEV$V_SCSI)
    {
        unsigned long int scsi_position;
        unsigned long int vms_position;

        status = scsi_read_position (channel, &scsi_position);

        if ((status != SS$_UNSUPPORTED) && 
    	    (status != SS$_ILLIOFUNC))
        {
            if (FAILURE(status))
    	        return status;

            arglist.arg_count = 1;
            arglist.arg1 = channel;
            vms_position = sys$cmkrnl (
                                      get_ucb_record_count,
                                      &arglist);
            if (vms_position != scsi_position)
    	        return SS$_TAPEPOSLOST;

            sys$cmkrnl (
                         set_position_lost,
                        &arglist);
            status = scsi_skip_files (
    		                      	  channel,
    			                      marks_to_skip,
    			                      &iosb);
            if (status != SS$_ENDOFVOLUME)
            {
    	        if (FAILURE(status))
    	            return status;
            }
            if (marks_skipped != NULL)
    	        *marks_skipped = iosb.len;

    	    final_status = status;
            status = scsi_read_position (
    			                         channel,
    			                         &scsi_position);
            if (FAILURE(status))
    	        return status;

            arglist.arg_count = 2;
            arglist.arg2 = scsi_position;
            sys$cmkrnl (
                        set_ucb_record_count,
                        &arglist);

    	    return final_status;
        }
    }

    if (devchar2.DEV$V_MSCP)
    {
        if (!(flags & 1))
        {
            status = sys$qiow (
    		     0,
    		     channel,
    		     IO$_SPACEFILE,
    		     &iosb,
                 0,		   /* No AST Routine   */
                 0,        /* No AST Parameter */
    		     marks_to_skip,
    		     0, 0, 0, 0, 0);
            if (FAILURE(status))
    	        return status;

            if (marks_skipped != NULL)
    	        *marks_skipped = iosb.len;

            return iosb.status;
        }
    }

    status = sys$qiow (
                  0,
                  channel,
                  IO$_SKIPFILE,
                  &iosb,
    			 0,			/* No AST routine    */
                  0,			/* No AST parameter  */
                  marks_to_skip,
                  0, 0, 0, 0, 0);
    if (FAILURE(status))
        return status;

    if (marks_skipped != NULL)
    *marks_skipped = iosb.len;

    return iosb.status;
}

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      {@tbs@}
**
**  FORMAL PARAMETERS:
**
**      {@subtags@}
**
**  RETURN VALUE:
**
**      {@description or none@}
**
**  SIDE EFFECTS:
**
**      {@description or none@}
**
**  DESIGN:
**
**      {@description or none@}
**
**  [@logical properties@]...
**
**  [@optional function tags@]...
**
**--
*/
STATUS_VALUE get_ucb_record_count (
    		unsigned short int	channel)
{
    struct UCBDEF *ucb;

    ucb = channel_to_ucb(channel);
    if (!ucb)
        return 0;

    return ucb -> UCB$L_RECORD;
}

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      {@tbs@}
**
**  FORMAL PARAMETERS:
**
**      {@subtags@}
**
**  RETURN VALUE:
**
**      {@description or none@}
**
**  SIDE EFFECTS:
**
**      {@description or none@}
**
**  DESIGN:
**
**      {@description or none@}
**
**  [@logical properties@]...
**
**  [@optional function tags@]...
**
**--
*/
    void set_ucb_record_count (
    	    unsigned short int  channel,
    	    unsigned long int   position)
{
    struct UCBDEF *ucb;

    ucb = channel_to_ucb(channel);
    if (!ucb)
        return;

    ucb -> UCB$L_RECORD = position;

    ucb -> UCB$L_DEVDEPEND &= ~(MT$M_LOST);
    if (position == 0)
        ucb -> UCB$L_DEVDEPEND |= MT$M_BOT;
    else
        ucb -> UCB$L_DEVDEPEND &= ~(MT$M_BOT);

    return;
}

/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      {@tbs@}
**
**  FORMAL PARAMETERS:
**
**      {@subtags@}
**
**  RETURN VALUE:
**
**      {@description or none@}
**
**  SIDE EFFECTS:
**
**      {@description or none@}
**
**  DESIGN:
**
**      {@description or none@}
**
**  [@logical properties@]...
**
**  [@optional function tags@]...
**
**--
*/
void set_position_lost (
    	    unsigned short int  channel)
{
    struct UCBDEF *ucb;

    ucb = channel_to_ucb(channel);
    if (!ucb)
        return;

    ucb -> UCB$L_DEVDEPEND |= MT$M_LOST;
    return;
}



/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      {@tbs@}
**
**  FORMAL PARAMETERS:
**
**      {@subtags@}
**
**  RETURN VALUE:
**
**      {@description or none@}
**
**  SIDE EFFECTS:
**
**      {@description or none@}
**
**  DESIGN:
**
**      {@description or none@}
**
**  [@logical properties@]...
**
**  [@optional function tags@]...
**
**--
*/
#ifndef HSM$ALPHA
    struct UCBDEF * channel_to_ucb (
    		    int		channel)
{
    struct CCBDEF *ccb;

    ccb = (struct CCBDEF *) (CTL$GL_CCBBASE - channel);
    if (ccb -> CCB$B_AMOD == 0)
        return 0;

    return ccb -> CCB$L_UCB;
}
#else
    struct UCBDEF * channel_to_ucb (
    		    int		channel)
{
    STATUS_VALUE    	    status;
    struct CCBDEF    	    *ccb;

    status = ioc$chan_to_ccb (channel, &ccb);
    if (FAILURE(status) || ccb->ccb$b_amod == 0)
        return 0;

    return ccb->ccb$l_ucb;
}
#endif
/*
**++
**  FUNCTIONAL DESCRIPTION:
**
**      {@tbs@}
**
**  FORMAL PARAMETERS:
**
**      {@subtags@}
**
**  RETURN VALUE:
**
**      {@description or none@}
**
**  SIDE EFFECTS:
**
**      {@description or none@}
**
**  DESIGN:
**
**      {@description or none@}
**
**  [@logical properties@]...
**
**  [@optional function tags@]...
**
**--
*/
STATUS_VALUE scsi_read_position (
   	     int			channel,
    	     unsigned long int *	pos)
{
    int     				 status;
    READPOS_CMD     		 readpos_cmd;
    READPOS_DATA     		 readpos_data;
    struct sense_data_struct sense_data;

    memset (&readpos_cmd, 0, sizeof(readpos_cmd));
    memset (&readpos_data, 0, sizeof(readpos_data));
    readpos_cmd.opcode = READ_POSITION;

    status = scsi_io(channel,
                     (char *) &readpos_cmd,
    	     sizeof(readpos_cmd),
    	     (char *) &readpos_data,
    	     sizeof(readpos_data),
    	     &sense_data);
    if (FAILURE(status))
        return status;
    if (status == -1)
        return SS$_UNSUPPORTED;

    if (readpos_data.BPU)
        return SS$_TAPEPOSLOST;

    *pos = B4_TO_I(readpos_data.first_block);
    return SS$_NORMAL;
}

/*
 *  SCSI numeric data is moved in bytes with the most significant byte
 *  first and the least significant byte last.  This is binary data, not
 *  characters. Note that these bytes form a 2's complement SIGNED number
 *  so we must pay attention to the signs of things
 */

/*
 * convert 2 msb...lsb bytes to 32 bit integer
 */
int b2_to_i(unsigned char *bytes)
{
    int i;

    /*
     * Get the MSB into low order bits of the result
     * We do it this way so the sign will be propagated
     * properly
     */
    i = (int)((char)bytes[0]);
    i = (i << 8) | bytes[1];
    return(i);
}

/*
 *
 * Function description:
 *
 *      scsi_skip_files - skip filemarks on tape
 *
 * Arguments:
 *
 *      channel - open VMS device channel
 *    number - number of filemarks to skip
 *    iosb - I/O status block
 *
 * Return value:
 *
 *      VMS condition code or -1 if SCSI error
 *
 * Side effects:
 *
 *      None
 *
 */
STATUS_VALUE scsi_skip_files(
    		    int		    channel,
    		    int		    number,
    		    IOSB *	    iosb)
{
    space_cdb     			 cmd;
    STATUS_VALUE     		 status;
    unsigned long int     	 position;
    int     				 scsi_sense_info;
    struct sense_data_struct sense_data;
    int     				 at_eov = 0;
    char     				 response;

    memset(iosb, 0, sizeof(*iosb));
    memset (&cmd, 0, sizeof(cmd));
    cmd.opcode = SPACE_COMMAND;
    cmd.subcode = SPACE_FILES_SUBCODE;
    I_TO_B3(number, cmd.count);
    status = scsi_io(channel,
                     (char *) &cmd,
    	             space_cdb_size,
    	             (char *) &response,
    	             1,
    	             &sense_data);
    /*
     * Make the optimistic assumption that we were able to
     * skip all that was asked.
     */
    iosb->bcnt = number;

    scsi_sense_info = B4_TO_I(sense_data.info);

    /*
     * Now check for recoverable errors
     */
    if (status == -1) 
    {
       /*
        * There was an error from which we might be able
        * to recover gracefully.  Need to do further checking
        *
        * First, see if we were spacing forward and hit logical
        * end of data.
        */
        if ((number >= 0) && sense_data.valid &&
           (sense_data.key == SENSE_BLANK_CHECK)) 
    	{
           /*
            * Yup, hit end of data.  Back up over 1 filemark so
            * We're positioned to append.
            * Adjust result skip count to reflect reality, and
            * account for backing up one filemark too
            * scsi_sense_info contains the "residual count", which
            * is the number of filemarks we did NOT skip.
            */
            iosb->bcnt -= scsi_sense_info + 1;

            I_TO_B3(-1, cmd.count);
            status = scsi_io(channel,
    		                (char *) &cmd,
    		                 space_cdb_size,
    		                (char *) &response,
    		                1,
    		                &sense_data);
            at_eov = 1;
    	} 
        else 
        {
    	    if ((number < 0) &&
    	        (sense_data.key == SENSE_NO_SENSE) &&
    	         sense_data.valid && sense_data.eom) 
    	    {
               /*
                * Here we were backspacing and hit the beginning
                * of tape.  Just calculate the number of files
                * we really skipped (as a positive number),
                * and return success
                */
                status = SS$_NORMAL;
                iosb->bcnt = -(number - scsi_sense_info);
            }
        }
    }
    if (at_eov)
    status = SS$_ENDOFVOLUME;
    iosb->status = status;
    return (status);
} /* end scsi_skip_files */


/*
 *
 * Function description:
 *
 *      scsi_io - send a SCSI command via QIO and evaulate the
 *                completion status fields, QIO call, QIO completion
 *    	  and SCSI completion.  If the command fails with
 *                a UNIT_ATTENTION SCSI error, just retry the
 *                the command and report the status for the second
 *                try.  UNIT_ATTENTION errors are normally informational
 *                and caused by a bus reset, door open, or other
 *                interuption and remain pending until the next
 *                SCSI command.
 *
 * Arguments:
 *
 *      channel - Open VMS channel to device
 *
 * Return value:
 *
 *      Completion status, normally VMS condition code or -1 if
 *      SCSI error.
 *
 * Side effects:
 *
 *      Automatically updates sense mode data on SCSI error.
 *
 */
    STATUS_VALUE scsi_io(
    int channel,
    char *command,
    int cmdlen,
    char *response,
    int resplen,
    struct sense_data_struct *sense_data)
{

    int    status;
    struct qio_cmd_struct qio_cmd;
    struct scsi_iosb_struct iosb;

    memset (&qio_cmd, 0, sizeof(qio_cmd));

    qio_cmd.opcode = 1;
    qio_cmd.flags = FLAGS_READ + FLAGS_DISCONNECT;
    qio_cmd.command_adr = command;
    qio_cmd.command_len = cmdlen;
    qio_cmd.data_adr = response;
    qio_cmd.data_len = resplen;
    qio_cmd.phase_tmo = 300;
    qio_cmd.disc_tmo = 360;
    status = sys$qiow( 
    				0, 
    				channel, 
    				IO$_DIAGNOSE, 
    				&iosb,
    	    		        0, 		/* No AST routine   */
    				0,              /* No AST parameter */
    				&qio_cmd, 
    				sizeof(qio_cmd), 
    				0, 0, 0, 0);
    if (FAILURE(status))
        return (status);
    if (FAILURE(iosb.status))
        return (iosb.status);
    if (iosb.scsi_status != 0) 
    {	    /* device reported problem */
        status = scsi_read_sense (
    	    	    channel,
    		        sense_data);  /* get error code from device */
        if (FAILURE(status))
            return (status);
    /* ignore unit attention codes and retry command one time */
        if (sense_data->key == SENSE_UNIT_ATTENTION) 
        {
            status = sys$qiow(
    		                  0, 
    						  channel, 
    						  IO$_DIAGNOSE,
    		                  &iosb, 
    						  0, 
    						  0, 
    						  &qio_cmd,
    		                  sizeof(qio_cmd), 
    						  0, 0, 0, 0);
            if (FAILURE(status))
    	        return (status);
            if (FAILURE(iosb.status))
    	        return (iosb.status);
            if (iosb.scsi_status != 0) 
    		{
    	        status = scsi_read_sense(channel, sense_data);
    	        if (FAILURE(status))
    	            return (status);
            }
        }
    }
    if (iosb.scsi_status != 0) 
        return -1;

    return SS$_NORMAL;
} /* end scsi_io */

/*
 *
 * Function description:
 *
 *      scsi_read_sense - request sense data from device and save in
 *                        module wide fields.
 *
 * Arguments:
 *
 *      channel - channel open to SCSI device
 *
 * Return value:
 *
 *      completion status - VMS status code or -1 for SCSI error
 *
 * Side effects:
 *
 *      Updates fields holding sense data for later retrieval
 *
 */
STATUS_VALUE scsi_read_sense (
    		    int				channel,
    		    struct sense_data_struct *	sense_data)
{
    req_sense_cdb           cmd;
    STATUS_VALUE            status;
    struct qio_cmd_struct   qio_cmd;
    struct scsi_iosb_struct iosb;

    memset (sense_data, 0, sizeof(struct sense_data_struct));
    memset (&cmd, 0, sizeof(cmd));  /* setup CDB */
    cmd.opcode = 0x03;
    cmd.len = sizeof(struct sense_data_struct);

    memset (&qio_cmd, 0, sizeof(qio_cmd)); /* setup P1 block */
    qio_cmd.opcode = 1;
    qio_cmd.flags = FLAGS_READ + FLAGS_DISCONNECT;
    qio_cmd.command_adr = (char *)&cmd;
    qio_cmd.command_len = req_sense_cdb_size;
    qio_cmd.data_adr = (char *)sense_data;
    qio_cmd.data_len = sizeof(struct sense_data_struct);
    qio_cmd.phase_tmo = 300;
    qio_cmd.disc_tmo = 360;
    status = sys$qiow( 
                      0, 
    		      channel, 
    		      IO$_DIAGNOSE, 
    		      &iosb,
    	              0, 
  		      0, 
    		      &qio_cmd, 
    		      sizeof(qio_cmd), 
    		      0, 0, 0, 0);
    if (FAILURE(status))
        return (status);

    if (FAILURE(iosb.status))
        return (iosb.status);

    return SS$_NORMAL;
} /* end scsi_read_sense */
3702.4MAIN.CSTOWKS::SLUISHans van Sluis -- Storage Engineering Support Europe- DTN 889 9526Mon Mar 24 1997 12:44236
#ifndef VAX
#pragma standard
#endif

#include <stdio.h>
#include <string.h>
#include <ssdef.h>
#include <stsdef.h>
#include <descrip.h>
#include <starlet.h>

#include "fasttape_functions.h"

#define NEXT_UNDEFINED		0
#define NEXT_IS_DEVICE		1
#define NEXT_IS_POSITION	2
#define NEXT_IS_CURRENT		3

static void display_error_message (unsigned long int  status);
static void print_message (char * message);

/*
 * Usage : fasttape -device stowks$mkb0 -position 12 [-current 24]
 */

typedef int	date_t[4];

char	*Version = "V1.0";	/* Version number         */
char	DeviceName[256];	/* Device Name            */
int     Position=0; 		/* Required Position      */
int	Current=0;		/* Current Position       */
#define BUFFER_SIZE	256
char	buffer[BUFFER_SIZE]; 	/* General Purpose Buffer */
	
main(int argc, char *argv[])
{
    int		       i,j;
    char               *tmp;
    int		       Next_argv = NEXT_UNDEFINED;
    unsigned long int  status=-1;
    int		       channel=-1;
    int		       MarksSkipped=-1;
    char	       tempbuf[80];

    printf("\nStorageWorks Engineering Support Fast Tape Positioning, %s\n\n",
	   Version );

    if (argc < 5 )
    {
        printf("Usage : fasttape -device <DeviceName> -position <Pos>  OR\n");
        printf("        fasttape -device <DeviceName> -position <Pos> -current
<Pos>\n");
        printf("\n");
        exit(0);
    }

    for (i=1; i< argc; i++)
    {/* Convert each argument to uppercase */
        strcpy(buffer, argv[i]);
        j = 0;
        while (buffer[j] != '\0')
        {
            if (isalpha(buffer[j]))
	    {
                buffer[j] = toupper(buffer[j]);
            }
            j++;
        }
        switch (Next_argv) 
        {
	    case NEXT_UNDEFINED :
		 if ( strstr(buffer, "-D") ) Next_argv = NEXT_IS_DEVICE;
                 if ( strstr(buffer, "-P") ) Next_argv = NEXT_IS_POSITION;
                 if ( strstr(buffer, "-C") ) Next_argv = NEXT_IS_CURRENT;
                 break;
  
            case NEXT_IS_DEVICE :
                 strcpy(DeviceName, buffer);
                 Next_argv = NEXT_UNDEFINED;
                 break;

            case NEXT_IS_POSITION :
                 Position = atoi(buffer);
                 Next_argv = NEXT_UNDEFINED;
                 break;
 
            case NEXT_IS_CURRENT :
                 Current = atoi(buffer);
                 Next_argv = NEXT_UNDEFINED;
                 break;
        };
        
    }

    /*
     * Adjust the position with the current one 
     */
    Position = Position - Current;

    if (Position) Position--;

    sprintf( tempbuf, "Open channel to %s", DeviceName );
    print_message( tempbuf );
    status = open_channel( DeviceName, &channel );
    if (status != SS$_NORMAL) 
    {
	display_error_message (status);
	exit(1);
    }

    if ( ! Current )
    {
        print_message ("Rewind tape");
        status = rewind_tape(channel);
        if (status != SS$_NORMAL) 
        {
	    display_error_message (status);
            (void) close_channel(channel);
    	    exit(1);
        }
    } 
 
    sprintf( tempbuf, "Skip from current position %d to position %d",
                       Current, Position );
    print_message( tempbuf );
    status = skip_tape_marks(channel,
                             Position,
                             0,
                             &MarksSkipped);
    if (status != SS$_NORMAL) 
    {
	display_error_message (status);
        (void) close_channel(channel);
	exit(1);
    }
    
    sprintf( tempbuf, "Close channel to %s", DeviceName );
    print_message( tempbuf );
    status = close_channel(channel);
    if (status != SS$_NORMAL) 
    {
	display_error_message (status);
	exit(1);
    }
    channel = -1;
 
    exit(0);
}

void display_error_message (unsigned long int  status)
{
    int		msg_flag = 0x000f;	    /* Status of system calls     */
    short	out_len;		    /* Output length              */
    char	msg_info[4];		    /* Message info               */
    int         s;

    struct dsc$descriptor_s	out_desc;

    out_desc.dsc$b_dtype = DSC$K_DTYPE_T;
    out_desc.dsc$b_class = DSC$K_CLASS_S;
    out_desc.dsc$w_length = BUFFER_SIZE;
    out_desc.dsc$a_pointer = buffer;

    s = sys$getmsg((int)status,		    /* Error code to be retrieved   */
                   &out_len,		    /* Output length                */
                   &out_desc,               /* Descriptor for output buffer */
                   msg_flag,                /* Message flags                */
                   msg_info);               /* Return information area      */

    switch (s)
    {
        case SS$_NORMAL : 
  	     /* GETMSG directive succeeded, output resultant string */
             buffer[out_len] = '\0';	    /* add string terminator      */
             printf("%s\n",buffer);
             break;
     
        case SS$_BUFFEROVF :
             break;

        case SS$_INSFARG :
             break;

        case SS$_MSGNOTFND :
             break;
        
        default :
             break;
    }
    return;   
}

void print_message( char * message )
{
    date_t	            binary_time;
    int		            status;
    struct dsc$descriptor_s bufdsc;
    short                   ret_len;

    binary_time[0] = 0;
    binary_time[1] = 0;
    binary_time[2] = 0;
    binary_time[3] = 0;

    status = sys$gettim(&binary_time);

    if (status != SS$_NORMAL)
    {
      printf("Error in SYS$GETTIM. Status : %d\n", status);
      printf("%s\n", message);
      return;
    }


    /*
     *  set up the descriptor
     */

    bufdsc.dsc$b_class = DSC$K_CLASS_D;
    bufdsc.dsc$b_dtype = DSC$K_DTYPE_T;
    bufdsc.dsc$w_length = BUFFER_SIZE;
    bufdsc.dsc$a_pointer = buffer;

   status = sys$asctim(&ret_len,&bufdsc,&binary_time,0);
   if (status != SS$_NORMAL)
   {
      printf("Error in SYS$GETTIM. Status : %d\n", status);
      printf("%s\n", message);
      return;
   }
   buffer[ret_len] = 0;   /*  null-terminate the string  */

   printf("%s -- %s\n", buffer, message);

   return;
}
3702.5FASTTAPE_VAX.OPTSTOWKS::SLUISHans van Sluis -- Storage Engineering Support Europe- DTN 889 9526Mon Mar 24 1997 12:4612
[.vax]main.obj
[.vax]fasttape.obj
sys$library:vaxcrtl.olb/lib
sys$library:vaxcrtlg.olb/lib 
sys$library:librtl.exe/share
sys$library:decc$shr.exe/share
sys$library:cma$rtl.exe/share
sys$library:cma$open_rtl.exe/share
sys$library:cma$lib_shr.exe/share
sys$library:cma$tis_shr.exe/share
sys$system:sys.stb/selective_search
sys$share:starlet.olb/library/include=(SYS$P1_VECTOR)
3702.6FASTTAPE_ALPHA.OPTSTOWKS::SLUISHans van Sluis -- Storage Engineering Support Europe- DTN 889 9526Mon Mar 24 1997 12:475
[.alpha]main.obj
[.alpha]fasttape.obj
sys$library:librtl.exe/share
sys$library:sys$public_vectors.exe/share
sys$library:decc$shr.exe/share
3702.7COMPILE.COMSTOWKS::SLUISHans van Sluis -- Storage Engineering Support Europe- DTN 889 9526Mon Mar 24 1997 12:4833
$set noverify
$link_flags = "/NODEBUG/NOTRACE/NOSYSSHR/NOSYSLIB/NOUSERLIB/MAP/CROSS"
$purge/nolog [] /keep=2
$vaxalpha = f$getsyi("arch_name")
$if vaxalpha .eqs. "Alpha" then goto Alpha
$if (f$search("vax.dir") .eqs. "") 
$then
$    crea/directory [.vax] /prot=(s:rwed,o:rwed)
$endif
$purge/nolog [.vax] /keep=2
$cc_flags = "/DECC/DEBUG/G_FLOAT/NOOPTIMIZE/STANDARD=VAXC/MACHINE" + -
	    "/NOMEMBER_ALIGNMENT/DEFINE=(HSM$VAX)"
$set verify
$cc 'cc_flags' main.c     /nowarnings/object=[.vax]main.obj
$cc 'cc_flags' fasttape.c /nowarnings/object=[.vax]fasttape.obj 
$link 'link_flags' fasttape_vax.opt/options /exec=[.vax]fasttape.exe
$goto end
$Alpha:
$if (f$search("alpha.dir") .eqs. "") 
$then
$    crea/directory [.alpha] /prot=(s:rwed,o:rwed)
$endif
$purge/nolog [.alpha] /keep=2
$cc_flags = "/DECC/DEBUG/G_FLOAT/NOOPTIMIZE/STANDARD=VAXC/MACHINE" + -
	    "/NOMEMBER_ALIGNMENT/DEFINE=(HSM$ALPHA)"
$set verify
$cc 'cc_flags' main.c                                    /nowarnings -
               /object=[.alpha]main.obj
$cc 'cc_flags' fasttape.c+SYS$LIBRARY:SYS$LIB_C/LIBRARY  /nowarnings -
               /object=[.alpha]fasttape.obj               
$link 'link_flags' fasttape_alpha.opt/options/sysexe /exec=[.alpha]fasttape.exe
$end:
$set noverify