HP OpenVMS I/O User’s Reference Manual: OpenVMS Version 8.4 > Chapter 3 Magnetic Tape Drivers

3.5 Magnetic Tape Drive Programming Examples

This section presents magnetic tape driver programming examples.

Example 3-2 shows the recommended sequence for changing a device characteristic. It retrieves the current characteristics using an IO$_SENSEMODE request, sets the new characteristics bits, and then uses IO$_SETMODE to set the new characteristics.

Example 3-3 shows ways of specifying sense mode and set mode, both with and without a user buffer specified, and with user buffers of different lengths.

In addition, Example 3-4 shows how data is written to and read from magnetic tape through the magnetic tape ACP.

Example 3-2 Device Characteristic Program Example

$QIOW_S -                                ; Get current characteristics.
        FUNC      = #IO$_SENSEMODE,-     ; - Sense mode
        CHAN      = CHANNEL,-            ; - Channel
        IOSB      = IO_STATUS,-          ; - IOSB
        P1        = BUFFER,-             ; - User buffer supplied
        P2        = #12                  ; - Buffer length = 12
        .
        .
        .
(Check for errors)
        .
        .
        .
(Set desired characteristics bits)
        .
        .
        .

$QIOW_S -                                ; Set new characteristics.
        FUNC      = #IO$_SETMODE,-       ; - Set Mode
        CHAN      = CHANNEL,-            ; - Channel
        IOSB      = IO_STATUS,-          ; - IOSB
        P1        = BUFFER,-             ; - User buffer address
        P2        = #12                  ; - Buffer length = 12
        .
        .
        .
(Check for errors)
        .
        .
        .

Example 3-3 Set Mode and Sense Mode Program Example

        .PSECT        IMPURE, NOEXE, NOSHR

        $IODEF


DEVICE_NAME:                                  ; Name of device
        .ASCID        /MUA0/                  ;

CHANNEL:                                      ; Channel to device
        .WORD        0                        ;
           
BUFFER: .BLKL        3                        ; Set/Sense characteristics
                                              ;  buffer

IO_STATUS:                                    ; Final I/O status
        .QUAD        0                        ;


        .PSECT        CODE, RD, NOWRT, EXE

        .ENTRY        MAIN,^M
$ASSIGN_S -                           ; Assign a channel to device
          DEVNAM      = DEVICE_NAME,-   ;
          CHAN        = CHANNEL         ;

BSBW    ERR_CHECK2                    ; Check for errors

$QIOW_S -                             ; Get current characteristics
          FUNC        = #IO$_SENSEMODE,-; No user buffer supplied
          CHAN        = CHANNEL,-       ;
          IOSB        = IO_STATUS       ;

BSBW      ERR_CHECK                     ; Check for errors


$QIOW_S -                             ; Get current characteristics
         FUNC        = #IO$_SENSEMODE,-; User buffer supplied, length
         CHAN        = CHANNEL,-       ;  defaulted
         IOSB        = IO_STATUS,-     ;
         P1          = BUFFER          ;

BSBW     ERR_CHECK                     ; Check for errors

$QIOW_S -                             ; Get current characteristics
         FUNC        = #IO$_SENSEMODE,-; User buffer supplied, length
         CHAN        = CHANNEL,-       ;  = 8
         IOSB        = IO_STATUS,-     ;
          P1          = BUFFER,-        ;
          P2          = #8              ;

BSBW    ERR_CHECK                     ; Check for errors


$QIOW_S -                             ; Get extended characteristics
        FUNC        = #IO$_SENSEMODE,-; User buffer supplied, length
        CHAN        = CHANNEL,-       ;  = 12
        IOSB        = IO_STATUS,-     ;
        P1        = BUFFER,-          ;
        P2        = #12               ;

BSBW    ERR_CHECK                     ; Check for errors

$QIOW_S 
         FUNC        = #IO$_SETMODE,-  ; Length defaulted
         CHAN        = CHANNEL,-       ;
         IOSB        = IO_STATUS,-     ;
         P1          = BUFFER          ;

BSBW    ERR_CHECK                     ; Check for errors


$QIOW_S -                             ; Set new characteristics
         FUNC        = #IO$_SETMODE,-  ; Length = 8
         CHAN        = CHANNEL,-       ;
         IOSB        = IO_STATUS,-     ;
         P1          = BUFFER,-        ;
         P2          = #8              ;

BSBW    ERR_CHECK                     ; Check for errors


$QIOW_S -                             ; Set extended characteristics
        FUNC        = #IO$_SETMODE,-  ; Length = 12
        CHAN        = CHANNEL,-       ;
        IOSB        = IO_STATUS,-     ;
        P1        = BUFFER,-          ;
        P2        = #12               ;

BSBW    ERR_CHECK                     ; Check for errors


RET


        .ENABLE LSB

ERR_CHECK:
        BLBS    IO_STATUS,ERR_CHECK2          ; Continue if good IOSB
        MOVZWL  IO_STATUS,-(SP)               ; Otherwise, set up for stop
        BRB     10$                           ; Branch to common code

ERR_CHECK2:
        BLBS    R0,20$                        ; Continue if good status
        PUSHL   R0                            ; Otherwise, set up for stop
10$:    CALLS        #1,G^LIB$STOP            ; Stop execution

20$:    RSB

        .DISABLE LSB


        .END        MAIN

Example 3-4 MAGNETIC_TAPE.MAR Device Characteristic Program Example

; *********************************************************************
;

        .TITLE  MAGTAPE PROGRAMMING EXAMPLE
        .IDENT  /01/

;
; Define necessary symbols.
;

        $FIBDEF                         ;Define file information block
                                        ;symbols
        $IODEF                          ;Define I/O function codes
;
; Allocate storage for the necessary data structures.
;

;
; Allocate magtape device name string and descriptor.
;



TAPENAME:                               ;
        .LONG   20$-10$                 ;Length of name string
        .LONG   10$                     ;Address of name string
10$:    .ASCII  /TAPE/                  ;Name string
20$:                                    ;Reference label

;
; Allocate space to store assigned channel number.
;

TAPECHAN:                               ;
        .BLKW   1                       ;Tape channel number
;
; Allocate space for the I/O status quadword.
;

IOSTATUS:                               ;
        .BLKQ   1                       ;I/O status quadword
;
; Allocate storage for the input/output buffer.
;

BUFFER:                                 ;
        .REPT   256                     ;Initialize buffer to
        .ASCII  /A/                     ;contain 'A'
        .ENDR                           ;
;
; Now define the file information block (FIB), which the ACP uses
; in accessing and deaccessing the file.  Both the user and the ACP
; supply the information required in the FIB to perform these
; functions.
;

FIB_DESCR:                              ;Start of FIB
        .LONG   ENDFIB-FIB              ;Length of FIB
        .LONG   FIB                     ;Address of FIB
FIB:    .LONG   FIB$M_WRITE!FIB$M_NOWRITE ;Read/write access allowed
        .WORD   0,0,0                   ;File ID
        .WORD   0,0,0                   ;Directory ID
        .LONG   0                       ;Context
        .WORD   0                       ;Name flags
        .WORD   0                       ;Extend control
ENDFIB:                                 ;Reference label



;
; Now define the file name string and descriptor.
;

NAME_DESCR:                             ;
        .LONG   END_NAME-NAME           ;File name descriptor
        .LONG   NAME                    ;Address of name string
NAME:   .ASCII  "MYDATA.DAT;1"          ;File name string
END_NAME:                               ;Reference label
;
; *********************************************************************
;
;                        Start Program
;
; *********************************************************************
;

; The program first assigns a channel to the magnetic tape unit and
; then performs an access function to create and access a file called
; MYDATA.DAT.  Next, the program writes 26 blocks of data (the letters
; of the alphabet) to the tape.  The first block contains all A's, the
; next, all B's, and so forth.  The program starts by writing a block of
; 256 bytes, that is, the block of A's.  Each subsequent block is reduced
; in size by two bytes so that by the time the block of Z's is written,
; the size is only 206 bytes.  The magtape ACP does not allow the reading
; of a file that has been written until one of three events occurs:
;       1. The file is deaccessed.
;       2. The file is rewound.
;       3. The file is backspaced.
; In this example the file is backspaced zero blocks and then read in
; reverse (incrementing the block size every block); the data is
; checked against the data that is supposed to be there.  If no data
; errors are detected, the file is deaccessed and the program exits.
;

        .ENTRY  MAGTAPE_EXAMPLE,^M,R4,R5,R6,R7,R8>

;
; First, assign a channel to the tape unit.
;

        $ASSIGN_S TAPENAME,TAPECHAN     ;Assign tape unit
        CMPW    #SS$_NORMAL,R0          ;Success?
        BSBW    ERRCHECK                ;Find out



;
; Now create and access the file MYDATA.DAT.
;

        $QIOW_S CHAN=TAPECHAN,-         ;Channel is magtape
                FUNC=#IO$_CREATE!IO$M_ACCESS!IO$M_CREATE,-;Function
                -                       ;is create
                IOSB=IOSTATUS,-         ;Address of I/O status
                -                       ;word
                P1=FIB_DESCR,-          ;FIB descriptor
                P2=#NAME_DESCR          ;Name descriptor
        CMPW    #SS$_NORMAL,R0          ;Success?
        BSBW    ERRCHECK                ;Find out

;
; LOOP1 consists of writing the alphabet to the tape (see previous
; description).
;

        MOVL    #26,R5                  ;Set up loop count
        MOVL    #256,R3                 ;Set up initial byte count
                                        ;in R3
LOOP1:                                  ;Start of loop
        $QIOW_S CHAN=TAPECHAN,-         ;Perform QIOW to tape channel
                FUNC=#IO$_WRITEVBLK,-   ;Function is write virtual
                -                       ;block
                P1=BUFFER,-             ;Buffer address
                P2=R3                   ;Byte count
        CMPW    #SS$_NORMAL,R0          ;Success?
        BSBW    ERRCHECK                ;Find out
;
; Now decrement the byte count in preparation for the next write
; operation and set up a loop count for updating the character
; written; LOOP2 performs the update.

        SUBL2   #2,R3                   ;Decrement byte count for
                                        ;next write
        MOVL    R3,R8                   ;Copy byte count to R8 for
                                        ;LOOP2 count
        MOVAL   BUFFER,R7               ;Get buffer address in R7
LOOP2:  INCB    (R7)+                   ;Increment character
        SOBGTR  R8,LOOP2                ;Until finished
        SOBGTR  R5,LOOP1                ;Repeat LOOP1 until alphabet
                                        ;complete



;
; The alphabet is now complete.  Fall through LOOP1 and update the
; byte count so that it reflects the actual size of the last block
; written to tape.
;

        ADDL2   #2,R3                   ;Update byte count

;
; The tape is now read, but first the program must perform one of
; the three functions described previously before the ACP allows
; read access.  The program performs an ACP control function,
; specifying skip zero blocks.  This is a special case of skip reverse
; and causes the ACP to allow read access.
;

        CLRL    FIB+FIB$L_CNTRLVAL      ;Set up to space zero blocks
        MOVW    #FIB$C_SPACE,FIB+FIB$W_CNTRLFUNC ;Set up for space
                                        ;function
        $QIOW_S CHAN=TAPECHAN,-         ;Perform QIOW to tape channel
                FUNC=#IO$_ACPCONTROL,-  ;Perform an ACP control
                -                       ;function
                P1=FIB_DESCR            ;Define the FIB
        CMPW    #SS$_NORMAL,R0          ;Success?
        BSBW    ERRCHECK                ;Find out

;
; Read the file in reverse.
;

        MOVL    #26,R5                            ;Set up loop count
        MOVB    #^A/Z/,R6                         ;Get first character in R6
LOOP3:                                            ;
        MOVAL   BUFFER,R7                         ;And buffer address to R7
        $QIOW_S CHAN=TAPECHAN,-                   ;Channel is magtape
                FUNC=#IO$_READVBLK!IO$M_REVERSE,- ;Function is read
                -                                 ;reverse
                IOSB=IOSTATUS,-                   ;Define I/O status quadword
                P1=BUFFER,-                       ;And buffer address
                P2=R3                             ;R3 bytes
        CMPW    #SS$_NORMAL,R0                    ;Success?
        BSBW    ERRCHECK                          ;Find out



;
; Check the data read to verify that it matches the data written.
;

        MOVL    R3,R4                   ;Copy R3 to R4 for loop count
CHECKDATA:                              ;
        CMPB    (R7)+,R6                ;Check each character
        BNEQ    MISMATCH                ;If error, print message
        SOBGTR  R4,CHECKDATA            ;Continue until finished
        DECB    R6                      ;Go through alphabet in reverse
        ADDL2   #2,R3                   ;Update byte count by 2 for
                                        ;next block
        SOBGTR  R5,LOOP3                ;Read next block
;
; Now deaccess the file.
;

        $QIOW_S CHAN=TAPECHAN,-         ;Channel is magtape
                FUNC=#IO$_DEACCESS,-    ;Deaccess function
                P1=FIB_DESCR,-          ;File information block (required)
                IOSB=IOSTATUS           ;I/O status

;
; Deassign the channel and exit.
;

EXIT:   $DASSGN_S CHAN=TAPECHAN         ;Deassign channel
        RET                             ;Exit

;
; If an error had been detected, a program would normally
; generate an error message here.  But for this example the
; program simply exits.
;

MISMATCH:                               ;
        BRB     EXIT                    ;Exit

ERRCHECK:                               ;
        BNEQ    EXIT                    ;If not success, exit
        RSB                             ;Otherwise, return

        .END    MAGTAPE_EXAMPLE