Document revision date: 30 March 2001

## OpenVMS I/O User's Reference Manual

Previous | Contents | Index

### 2.4.3 Sense Mode

Sense mode operations obtain current disk device-dependent characteristics that are returned to the caller in the second longword of the I/O status block (see Figure 2-8). The operating system provides the following function codes:

- IO$_SENSEMODE---Sense characteristics
- IO$_SENSECHAR---Sense characteristics

IO$_SENSEMODE is a logical function. IO$_SENSECHAR is a physical I/O function and requires the access privilege necessary to perform physical I/O. No device- or function-dependent arguments are used with either function.

### 2.4.4 Set Density

The set density function assigns a new density to an entire RX02 floppy diskette. The diskette is also reformatted: new data address marks are written (single or double density) and all data fields are zeroed. Set density is a physical I/O function and requires the access privilege necessary to perform physical I/O. The following function code is provided:

> IO$_FORMAT

IO$_FORMAT takes the following function-dependent argument:

> P1---The density at which the diskette is reformatted:

> > 0 = single density (default)
> > 1 = single density
> > 2 = double density

The set density operation should not be interrupted before it is completed (about 15 seconds). If the operation is interrupted, the resulting diskette might contain illegal data address marks in both densities. The diskette must then be completely reformatted and the function reissued.

### 2.4.5 Search

The search function positions a TU58 magnetic tape to the block specified. Search is a physical I/O function and requires the access privilege necessary to perform physical I/O. The operating system provides a single function code:

> IO$_SEARCH

This function code takes the following function-dependent argument:

> P1---Specifies the block where the read/write head will be positioned. The low byte contains the sector number in the range 0 to 127; the high byte contains the track number in the range 0 to 3.

IO$_SEARCH can save time between read and write operations. For example, nearly 30 seconds are required to completely rewind a tape. If the last read or write operation is near the end of the tape and the next operation is near the beginning of the tape, the search operation can begin after the last operation completes, and the tape will rewind while the process is otherwise occupied. (The search QIO is not completed until the search is completed. Consequently, if a $QIOW system service request is issued, the process will be held up until the search is completed.)

### 2.4.6 Pack Acknowledge

The pack acknowledge function sets the volume valid bit for all disk devices. Pack acknowledge is a physical I/O function and requires the access privilege to perform physical I/O. If directed to an RX02 disk, pack acknowledge also determines the diskette density and updates the device-dependent information returned by $GETDVI item codes DVI$_CYLINDERS, DVI$_TRACKS, DVI$_SECTORS, DVI$_DEVTYPE, DVI$_CLASS, and DVI$_MAXBLOCK. If directed to a DSA disk, pack acknowledge also sends the online packet to the controller. The following function code is provided:

> IO$_PACKACK

This function code takes no function-dependent arguments.

IO$_PACKACK must be the first function issued when a volume (pack, cartridge, or diskette) is placed in a disk drive. IO$_PACKACK is issued automatically when the DCL commands INITIALIZE or MOUNT are issued.

For DSA disks, the IO$_PACKACK function locks the drive's port selector on the port that initiated the pack acknowledge function.

In addition, the IO$_PACKACK function updates device-dependent information about DSA disks returned by $GETDVI.

### 2.4.7 Unload

The unload function clears the volume valid bit for all disk drives, makes DSA disks available, and issues an unload command to the drive (spins down the volume). The unload function reverses the function performed by pack acknowledge (see Section 2.4.6). The following function code is provided:

> IO$_UNLOAD

This function takes no function-dependent arguments.

### 2.4.8 Available

The available function clears the volume valid bit for all disk drives; that is, it reverses the function performed by pack acknowledge (see Section 2.4.6). No unload function is issued to the drive. Therefore, those drives capable of spinning down do not spin down. The following function code is provided:

> IO$_AVAILABLE

This function takes no function-dependent arguments.

### 2.4.9 Seek

The seek function directs the read/write heads to move to the cylinder specified in the P1 argument (see Sections 2.2.8 and 2.4, and Figure 2-6).

### 2.4.10 Write Check

The write check function verifies that data was written to disk correctly. The data to be checked is addressed using physical disk addressing (sector, track, and cylinder) (see Figure 2-5). If the request is directed to a DSA disk, you must specify a logical block number, even though IO$_WRITECHECK is a physical I/O function. The following function code is provided:

> IO$_WRITECHECK

A write QIO must be used to write data to disk before you enter this command. IO$_WRITECHECK then reads the same block of data and compares it with the data in the specified buffer. Three function-dependent arguments are used with this code: P1, P2, and P3. These arguments are described in Section 2.4.

IO$_WRITECHECK is similar to the IO$M_DATACHECK function modifier for write QIOs, except that IO$_WRITECHECK does not write the data to disk; it is specified after data is written by a separate write QIO. Nonprivileged processes can use the IO$M_DATACHECK modifier with IO$_WRITEVBLK (which does not require access privilege) to determine whether data is written correctly. The RX01 and RX02 drivers do not support the write check function.

The write check function and the data check function modifier to a TU58 can return six error codes in the I/O status block: SS$_NORMAL, SS$_CTRLERR, SS$_DRVERR, SS$_MEDOFL, SS$_NONEXDRV, and SS$_WRTLCK.

### 2.4.11 Set Preferred Path

The set preferred path function specifies a preferred path for DSA disks. This includes RA-series disks and disks accessed through the MSCP server. If a preferred path is specified for a disk, the MSCP disk class drivers (DUDRIVER and DSDRIVER) use the path as their first attempt to locate the disk and bring it on line as a result of a DCL command MOUNT or failover of an already mounted disk. In addition, you can initiate failover of a mounted disk in order to force the disk to the preferred path, or to use load-balancing information for disks accessed through MSCP servers.

The function code is:

> IO$_SETPRFPATH

The following is the function modifier:

> IO$M_FORCEPATH---Causes the disk class driver to select the server path with the highest load available rating.

The P1 parameter contains the address of a counted ASCII string (.ASCIC). This string is the node name of the HSC or system that is the preferred path. The node name must match an existing node that is known to the local node and if the node is a VAX or Alpha system, it must be running the MSCP server. This function does not move the disk to the preferred path.

The PHYS_IO privilege is required for IO$_SETPRFPATH and IO$M_FORCEPATH.

The following example shows the use of IO$_SETPRFPATH:

            $assigndef
            $qiodef
            $iodef
            $exitdef

    dev:    .ascid  /$254$DUA48:/

    chnl:   .word   0

    node:   .ascic  /HSC001/

            .entry  start,0

            $assign_s       devnam=dev,-
                            chan=chnl
            blbc    r0,done

            $qiow_s         chan=chnl,-
                            func=#IO$_SETPRFPATH,-
                            p1=node

    done:
            $exit_s r0

            .end  start

This updates the local node I/O database to indicate that node HSC001 is the preferred path for DUA48.

#### 2.4.11.1 Forcing a Path Change

You can move a disk that is already mounted to its preferred path by specifying the IO$M_FORCEPATH modifier. If a preferred path has not been specified for a disk that is accessed through the MSCP server, the IO$M_FORCEPATH function causes the disk class driver to use load-balancing information to select the server path with the highest-load-available rating.

IO$M_FORCEPATH does not accept any arguments. If you intend to move a disk to its preferred path, you must specify the preferred path in a separate $QIO function.

The following example shows use of the IO$M_FORCEPATH function modifier:

            $assigndef
            $qiodef
            $iodef
            $exitdef

    dev:    .ascid  /$254$DUA197:/

    chnl:   .word   0

            .entry  start,0

            $assign_s       devnam=dev,-
                            chan=chnl
            blbc    r0,done

            $qiow_s         chan=chnl,-
                            func=#<IO$_SETPRFPATH!IO$M_FORCEPATH>

    done:
            $exit_s r0

            .end    start

Note that forcing a path change places the disk in mount verification. New I/O requests are suspended until mount verification is complete.

#### 2.4.11.2 Using IO$_SETPRFPATH with Disks Dual-Pathed Between HSCs

You can use the IO$_SETPRFPATH and IO$M_FORCEPATH functions to load balance disks that are dual-pathed between HSCs. The IO$M_FORCEPATH function initiates failover of the disk on all nodes that have it mounted and that have a direct path to the HSCs. Since the node that issues the IO$M_FORCEPATH might not be the first one to attempt failover of the disk, it is essential that all nodes with direct connections to the HSCs specify the same preferred path for the disk. Only one node should issue the IO$M_FORCEPATH request.

#### 2.4.11.3 Using IO$_SETPRFPATH with Disks Dual-Pathed Between Systems

You can use IO$M_FORCEPATH to load balance RA-series disks that are dual-pathed between systems running the MSCP server. Both serving nodes should specify the same preferred path. In order to move the disk between systems, the system that currently has the disk on line through its local controller should issue the IO$M_FORCEPATH request. The disk must be mounted on both serving nodes.

#### 2.4.11.4 Using IO$_SETPRFPATH with Disks Accessed Through MSCP Servers

You can specify a preferred path for disks that are accessed through MSCP servers. However, this specification overrides any load-balancing decisions.

Note that if a disk can be accessed through both HSC and MSCP servers, you need not specify the HSC as a preferred path. HSC paths are always preferred to server paths.

Using IO$M_FORCEPATH without a preferred path causes the disk class driver to move the disk to the server with the highest available capacity.

#### 2.4.11.5 Using IO$_SETPRFPATH with Phase I Volume Shadowing

You can specify IO$_SETPRFPATH for shadow set members, but not for virtual units. IO$M_FORCEPATH is not supported for shadow set members or virtual units.

#### 2.4.11.6 Using IO$_SETPRFPATH with Phase II Volume Shadowing

IO$_SETPRFPATH and IO$M_FORCEPATH are supported for shadow set members but not for virtual units.

## 2.5 I/O Status Block

Figure 2-7 shows the I/O status block (IOSB) for all disk device QIO functions except sense mode. Figure 2-8 shows the I/O status block for the sense mode function. Appendix A lists the status messages for all functions and devices. (The OpenVMS system messages documentation provides explanations and suggested user actions for these messages.)

Figure 2-7 IOSB Contents

The byte count is a 32-bit integer that gives the actual number of bytes transferred to or from the process buffer.

Figure 2-8 IOSB Contents for the Sense Mode Function

The second longword of the I/O status block for the sense mode function returns information about the cylinder, track, and sector configurations for the particular device.

## 2.6 Disk Driver Programming Example

A sample VAX MACRO disk driver program, DISK_DRIVER.MAR, is shown in Example 2-1. This sample program provides an example of optimizing access time to a disk file. The program creates a file using Record Management Services (RMS), stores information concerning the file, and closes the file. The program then accesses the file and reads and writes to the file using the Queue I/O ($QIO) system service.

Example 2-1 DISK_DRIVER.MAR Disk Driver Programming Example

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

            .TITLE  Disk Driver Programming Example
            .IDENT  /01/

    ;
    ; Define necessary symbols.
    ;

            $FIBDEF                 ;Define file information block Offsets
            $IODEF                  ;Define I/O function codes
            $RMSDEF                 ;Define RMS-32 Return Status Values
    ;
    ; Local storage
    ;
    ; Define number of records to be processed.
    ;

    NUM_RECS=100                    ;One hundred records

    ;
    ; Allocate storage for necessary data structures.
    ;
    ; Allocate File Access Block.
    ;
    ;       A file access block is required by RMS-32 to open and close a
    ;       file.
    ;
    FAB_BLOCK:                              ;
            $FAB    ALQ = 100,-             ;Initial file size is to be
                    -                       ;100 blocks
                    FAC = PUT,-             ;File Access Type is output
                    FNA = FILE_NAME,-       ;File name string address
                    FNS = FILE_SIZE,-       ;File name string size
                    FOP = CTG,-             ;File is to be contiguous
                    MRS = 512,-             ;Maximum record size is 512
                    -                       ;bytes
                    NAM = NAM_BLOCK,-       ;File name block address
                    ORG = SEQ,-             ;File organization is to be
                    -                       ;sequential
                    REM = FIX               ;Record format is fixed length
    ;
    ; Allocate file information block.
    ;
    ;       A file information block is required as an argument in the
    ;       Queue I/O system service call that accesses a file.
    ;
    FIB_BLOCK:                              ;
            .BLKB   FIB$K_LENGTH            ;

    ;
    ; Allocate file information block descriptor.
    ;

    FIB_DESCR:                              ;
            .LONG   FIB$K_LENGTH            ;Length of the file
                                            ;information block
            .LONG   FIB_BLOCK               ;Address of the file
                                            ;information block
    ;
    ; Allocate File Name Block
    ;
    ;       A file name block is required by RMS-32 to return information
    ;       concerning a file (for example, the resultant file name string
    ;       after logical name translation and defaults have been applied).
    ;

    NAM_BLOCK:                              ;
            $NAM                            ;

    ;
    ; Allocate Record Access Block
    ;
    ;       A record access block is required by RMS-32 for record
    ;       operations on a file.
    ;
    RAB_BLOCK:
            $RAB    FAB = FAB_BLOCK,-       ;File access block address
                    RAC = SEQ,-             ;Record access is to be
                    -                       ;sequential
                    RBF = RECORD_BUFFER,-   ;Record buffer address
                    RSZ = 512               ;Record buffer size
    ;
    ; Allocate direct address buffer
    ;

    BLOCK_BUFFER:
            .BLKB   1024                    ;Direct access buffer is 1024
                                            ;bytes

    ;
    ; Allocate space to store channel number returned by the $ASSIGN
    ; Channel system service.
    ;
    DEVICE_CHANNEL:                         ;
            .BLKW   1                       ;

    ;
    ; Allocate device name string and descriptor.
    ;

    DEVICE_DESCR:                           ;
            .LONG   20$-10$                 ;Length of device name string
            .LONG   10$                     ;Address of device name string
    10$:    .ASCII  /SYS$DISK/              ;Device on which created file
                                            ;will reside
    20$:                                    ;Reference label to calculate
                                            ;length
    ;
    ; Allocate file name string and define string length symbol.
    ;

    FILE_NAME:                              ;
            .ASCII  /SYS$DISK:MYDATAFIL.DAT/        ;File name string

    FILE_SIZE=.-FILE_NAME                   ;File name string length

    ;
    ; Allocate I/O status quadword storage.
    ;

    IO_STATUS:                              ;
            .BLKQ   1                       ;
    ;
    ; Allocate output record buffer.
    ;

    RECORD_BUFFER:                          ;
            .BLKB   512                     ;Record buffer is 512 bytes
    ;
    ; ********************************************************************
    ;
    ;                       Start Program
    ;
    ; ********************************************************************

    ;
    ; The purpose of the program is to create a file called MYDATAFIL.DAT
    ; using RMS-32; store information concerning the file; write 100
    ; records, each containing its record number in every byte;
    ; close the file; and then access, read, and write the file directly,
    ; using the Queue I/O system service.  If any errors are detected, the
    ; program returns to its caller with the final error status in
    ; register R0.

            .ENTRY  DISK_EXAMPLE,^M<R2,R3,R4,R5,R6>  ;Program starting
                                                     ;address

    ;
    ; First create the file and open it, using RMS-32.
    ;
    PART_1:                                 ;First part of example
            $CREATE FAB = FAB_BLOCK         ;Create and open file
            BLBC    R0,20$                  ;If low bit = 0, creation
                                            ;failure

    ;
    ; Second, connect the record access block to the created file.
    ;

            $CONNECT RAB = RAB_BLOCK        ;Connect the record access
                                            ;block
            BLBC    R0,30$                  ;If low bit = 0, creation
                                            ;failure
    ;
    ; Now write 100 records, each containing its record number.
    ;

            MOVZBL  #NUM_RECS,R6            ;Set record write loop count

    ;
    ; Fill each byte of the record to be written with its record number.
    ;

    10$:    SUBB3   R6,#NUM_RECS+1,R5       ;Calculate record number

            MOVC5   #0,(R6),R5,#512,RECORD_BUFFER  ;Fill record buffer

    ;
    ; Now use RMS-32 to write the record into the newly created file.
    ;

            $PUT    RAB = RAB_BLOCK         ;Put record in file
            BLBC    R0,30$                  ;If low bit = 0, put failure
            SOBGTR  R6,10$                  ;Any more records to write?
    ;
    ; The file creation part of the example is almost complete.  All that
    ; remains to be done is to store the file information returned by
    ; RMS-32 and close the file.
    ;

            MOVW    NAM_BLOCK+NAM$W_FID,FIB_BLOCK+FIB$W_FID  ;Save file
                                            ;identification
            MOVW    NAM_BLOCK+NAM$W_FID+2,FIB_BLOCK+FIB$W_FID+2  ;Save
                                            ;sequence number
            MOVW    NAM_BLOCK+NAM$W_FID+4,FIB_BLOCK+FIB$W_FID+4  ;Save
                                            ;relative volume
            $CLOSE  FAB = FAB_BLOCK         ;Close file
            BLBS    R0,PART_2               ;If low bit set, successful
                                            ;close
    20$     RET                             ;Return with RMS error status
    ;
    ; Record stream connection or put record failure.
    ;
    ; Close file and return status.
    ;
    30$:    PUSHL   R0                      ;Save error status
            $CLOSE  FAB = FAB_BLOCK         ;Close file
            POPL    R0                      ;Retrieve error status
            RET                             ;Return with RMS error status
    ;
    ; The second part of the example illustrates accessing the previously
    ; created file directly using the Queue I/O system service, randomly
    ; reading and writing various parts of the file, and then deaccessing
    ; the file.
    ;
    ; First, assign a channel to the appropriate device and access the
    ; file.
    PART_2:                                 ;
            $ASSIGN_S DEVNAM = DEVICE_DESCR,-  ;Assign a channel to file
                    CHAN = DEVICE_CHANNEL   ;device
            BLBC    R0,20$                  ;If low bit = 0, assign
                                            ;failure
            MOVL    #FIB$M_NOWRITE!FIB$M_WRITE,- ;Set for read/write
                    FIB_BLOCK+FIB$L_ACCTL   ;access
            $QIOW_S CHAN = DEVICE_CHANNEL,- ;Access file on device channel
                    FUNC = #IO$_ACCESS!IO$M_ACCESS,- ;I/O function is
                    -                       ;access file
                    IOSB = IO_STATUS,-      ;Address of I/O status
                    -                       ;quadword
                    P1 = FIB_DESCR          ;Address of information block
                                            ;descriptor
            BLBC    R0,10$                  ;If low bit = 0, access
                                            ;failure
            MOVZWL  IO_STATUS,R0            ;Get final I/O completion
                                            ;status

            BLBS    R0,30$                  ;If low bit set, successful
                                            ;I/O function
    10$:    PUSHL   R0                      ;Save error status
            $DASSGN_S CHAN = DEVICE_CHANNEL ;Deassign file device channel
            POPL    R0                      ;Retrieve error status
    20$:    RET                             ;Return with I/O error status
    ;
    ; The file is now ready to be read and written randomly.  Since the
    ; records are fixed length and exactly one block long, the record
    ; number corresponds to the virtual block number of the record in the
    ; file. Thus a particular record can be read or written simply by
    ; specifying its record number in the file.
    ;
    ; The following code reads two records at a time and checks to see
    ; that they contain their respective record numbers in every byte.
    ; The records are then written back into the file in reverse order.
    ; This results in record 1 having the old contents of record 2 and
    ; record 2 having the old contents of record 1, and so forth. After
    ; the example has been run, it is suggested that the file dump
    ; utility be used to verify the change in data positioning.
    ;

    30$     MOVZBL  #1,R6                   ;Set starting record (block)
                                            ;number
    ;
    ; Read next two records into block buffer.
    ;

    40$:    $QIO_S  CHAN = DEVICE_CHANNEL,- ;Read next two records from
                    -                       ;file channel
                    FUNC = #IO$_READVBLK,-  ;I/O function is read virtual
                    -                       ;block
                    IOSB = IO_STATUS,-      ;Address of I/O status
                    -                       ;quadword
                    P1 = BLOCK_BUFFER,-     ;Address of I/O buffer
                    P2 = #1024,-            ;Size of I/O buffer
                    P3 = R6                 ;Starting virtual block of
                                            ;transfer
            BSBB    50$                     ;Check I/O completion status
    ;
    ; Check each record to make sure it contains the correct data.
    ;

            SKPC    R6,#512,BLOCK_BUFFER    ;Skip over equal record
                                            ;numbers in data

            BNEQ    60$                     ;If not equal, data match
                                            ;failure
            ADDL3   #1,R6,R5                ;Calculate even record number

            SKPC    R5,#512,BLOCK_BUFFER+512 ;Skip over equal record
                                            ;numbers in data
            BNEQ    60$                     ;If not equal, data match
                                            ;failure
    ;
    ; Record data matches.
    ;
    ; Write records in reverse order in file.
    ;

            $QIOW_S CHAN = DEVICE_CHANNEL,- ;Write even-numbered record in
                    -                       ;odd slot
                    FUNC = #IO$_WRITEVBLK,- ;I/O function is write virtual
                    -                       ;block
                    IOSB = IO_STATUS,-      ;Address of I/O status
                    -                       ;quadword
                    P1 = BLOCK_BUFFER+512,- ;Address of even record buffer
                    P2 = #512,-             ;Length of even record buffer
                    P3 = R6                 ;Record number of odd record
            BSBB    50$                     ;Check I/O completion status
            ADDL3   #1,R6,R5                ;Calculate even record number
            $QIOW_S CHAN = DEVICE_CHANNEL,- ;Write odd numbered record in
                    -                       ;even slot
                    FUNC = #IO$_WRITEVBLK,- ;I/O function is write virtual
                    -                       ;block
                    IOSB = IO_STATUS,-      ;Address of I/O status
                    -                       ;quadword
                    P1 = BLOCK_BUFFER,-     ;Address of odd record buffer
                    P2 = #512,-             ;Length of odd record buffer
                    P3 = R5                 ;Record number of even record
            BSBB    50$                     ;Check I/O completion status
            ACBB    #NUM_RECS-1,#2,R6,40$   ;Any more records to be read?

            BRB     70$                     ;

    ;
    ; Check I/O completion status.
    ;

    50$:    BLBC    R0,70$                  ;If low bit = 0, service
                                            ;failure
            MOVZWL  IO_STATUS,R0            ;Get final I/O completion
                                            ;status
            BLBC    R0,70$                  ;If low bit = 0, I/O function
            RSB                             ;failure
    ;
    ; Record number mismatch in data.
    ;

    60$:    MNEGL   #4,R0                   ;Set dummy error status value

    ;
    ; All records have been read, verified, and odd/even pairs inverted
    ;
    70$:    PUSHL   R0                      ;Save final status
            $QIOW_S CHAN = DEVICE_CHANNEL,- ;Deaccess file
                    FUNC = #IO$_DEACCESS    ;I/O function is deaccess file
            $DASSGN_S CHAN = DEVICE_CHANNEL ;Deassign file device channel
            POPL    R0                      ;Retrieve final status
            RET                             ;

            .END    DISK_EXAMPLE

Previous | Next | Contents | Index

| privacy and legal statement |
6136PRO_009.HTML