Chapter 4. Writing C Applications Using Tapes

This chapter describes the ways in which you may work with TMF from within C programs.

Before you can access TMF for file processing, you must reserve the required number of tape drives for each device type needed. After you have reserved the tape drives, you may specify the tape volume in which the files to be processed are located.

After you have the volumes mounted and positioned, you can begin processing the tape files. When processing is complete, release the reserved tape drives.

There are two levels of access to TMF. The recommended and easiest to use is the C library level, using flexible file I/O (FFIO) library routines. The second level is to use system calls, which requires much greater detail than the C library level. At this level, access is via the read(2) and write(2) system calls or the ioctl(2) system call.

This chapter contains the following sections:

4.1. Using FFIO

The flexible file I/O (FFIO) routines provide another way to perform tape I/O with the ease of use of system calls. The FFIO routines automatically recognize tape devices and use the appropriate buffering.

The C library routines ffopen(3), ffread(3), ffwrite(3), ffseek(3), ffbksp(3), ffclose(3), and ffweof(3) provide the capability to read and write records to tape, rewind the tape and backspace records, and read and write filemarks.

For IBM compatible devices, the ffread(3) and ffwrite(3) routines provide an interface that is sensitive to block boundaries and that returns information on tape block boundaries on request. With the FFIO layer, a rewind operation can be performed simply with a call to ffseek(3). Filemarks can be written with ffweof(3), and filemarks can be read with ffread(3). A call to ffwrite(3) can write a tape block of a designated number of bytes on a tape. A call to ffread(3) can read up to one tape block from a tape. Explicit information about tape block boundaries and the ability to read and write partial tape blocks is available through the use of optional parameters on ffread(3) and ffwrite(3).

When you use byte-stream mode, end-of-volume processing, user filemarks, and some positioning functionality are not available with the FFIO tape layer. When you use block mode and the FFIO tape layer, each record written must be the same size as specified on the -b option of the tmmnt(1) command. An exception to this rule is the last record written before a filemark or the end-of-file.

Example 4-1 illustrates how you can use C library routines in a program and Example 4-2, shows how you execute the program. For more information on the C library routines, see the Application Programmer's I/O Guide.

Example 4-1. C Library Routine Usage

The program, called cexam.c., demonstrates how C library routines can be used.

#include <fcntl.h>
#include <sys/types.h>
#include <foreign.h>
#include <errno.h>
main()
{
   int ffd;
   int i,j;
   int buf[2000];
   int ret;
   ffd = ffopen("mytape", O_RDWR);
   if (ffd<0){
      printf("open failed, error = %d\n",errno)
      exit(1);
   }

	   /************** Write 10 records, a filemark, and 10 more records to tape */

	   for (j = 0; j < 2; j++){
      for (i = 0; i < 10; i++){
         ret = ffwrite(ffd, buf, 800);
         if (ret < 800){
         printf("ffwrite returned %d\n",ret);
         printf("error = %d\n",errno);
         }
      }

	   /************** Write a filemark */

      ret = ffweof(ffd);
      if (ret < 0)
         printf("ffweof failed, error = %d\n",errno);
   }

   	/************** Rewind the tape */

   	ret = ffseek(ffd,0,0);
   	if (ret != 0)
      printf("ffseek failed, error = %d\n",errno);

  	/************** Read the tape until the first filemark is reached. */

	   for (;;)   {
      ret = ffread(ffd, buf, 16000);
      if (ret < 0) {
         printf("ffread failed, error = %d\n",errno);
         break;
      }
      else if (ret == 0)
         break;

   /* Just read a filemark */

      else
         printf("We read %d bytes\n",ret);
   }

   	/************** Close the file */

	   ffclose(ffd);
}


Example 4-2. Executing cexam.c

The following commands show how to execute the cexam.c program.

cc cexam.c -lffio
tmrsv CART 1
tmmnt -v ISCSL -l sl -p mytape -g CART -r in -n -T
assign -F tmf mytape
./a.out
tmrls -a


4.2. Using System Calls: read and write

TMF supports two kinds of unbuffered, synchronous I/O:

  • Variable-block I/O, which is supported for all devices with this capability

  • Fixed-block I/O, which is supported for all devices

I/O requests are issued with the read(2) and write(2) system calls.

4.2.1. Variable-block I/O

Variable-block I/O is the default I/O type. Each read(2) request transfers one block into your I/O buffer, and each write(2) transfers one block from your I/O buffer.

The size specified on the I/O request can vary. However, the request size must be within the driver limits, which can be obtained with the MTIOCGETBLKINFO ioctl request (see Section 4.3.2.2). The write size is also limited by the maximum block size specified on the tmmnt(1) command with option -b. On a write(2) system call, the request size cannot exceed this value. On a read(2) system call, the request size must be larger than or equal to the size of the next block on tape.

Procedure 4-1 and Procedure 4-2, show you write and read to a tape file, respectively.

Procedure 4-1. Writing to a Tape File

Shows you how to write a tape file using variable-block I/O.

  1. Specify the maximum block size as 98304 bytes on your tmmnt(1) command:

    tmrsv CART 1
    tmmnt -v 004141 -l sl -p tapefile -n -g CART -b 98304

  2. Issue the write(2) requests:

    #include <fcntl.h>
    
    void
    main( int argc, char **argv ) {
    
          char     buf[98304];
          int      fd;
          int      bytes;
    
          fd = open( "tapefile", O_WRONLY );
          bytes = write( fd, buf, 98304 );
          bytes = write( fd, buf, 32768 );
    }

    Procedure 4-2. Reading a Tape File

    Read 98304 bytes followed by another read(2) request of 98304 bytes from a tape file that has a maximum block size of 98304 bytes. If you are reading the data just written in the previous example, the first read request will return 98304 bytes and the second 32768 bytes.

    1. Specify the maximum block size as 98304 bytes on your tmmnt(1) command:

      tmrsv CART 1
      tmmnt -v 004141 -l sl -p tapefile -g CART -b 98304

    2. Issue the read(2) requests:

      #include <fcntl.h>
      
      void
      main( int argc, char **argv ) {
      
            char     buf[98304];
            int      fd;
            int      bytes;
      
           fd = open( "tapefile", O_RDONLY );
           bytes = read( fd, buf, 98304 );
           bytes = read( fd, buf, 98304 );
      }

      4.2.2. Fixed-block I/O

      To request fixed-block I/O, specify the -B option on the tmmnt(1) command. The block size is specified with the -b option on the tmmnt(1) command or with MTSPECOP ioctl request (see Section 4.3.2.9).

      TMF sets the block size when processing the tmmnt(1) command. If a block size other than what is specified on the tmmnt(1) command is required, a MTSPECOP ioctl request must be used to modify the block size. The tape must be positioned at the beginning of the tape or at the beginning of the file to be able to modify the block size. The block size must be within the drive limits and cannot exceed the maximum block size specified on the tmmnt(1) command.

      Multiple blocks can be requested on each read(2) or write(2) request. The write request size must be a multiple of the block size. The read request size must be at least as large as the block size. Procedure 4-3 and Procedure 4-4, show how you write and read to a tape file, respectively.

      Procedure 4-3. Writing to a Tape File

      Write a tape file using fixed-block I/O. The first write(2) request writes 3 blocks each of size 32768 bytes. The second write request writes one 32768 byte block. The block size is set by TMF to 32768 bytes when tmmnt(1) request is processed.

      1. Specify the maximum block size as 32768 bytes on your tmmnt(1) command:

        tmrsv CART 1
        tmmnt -v 004141 -l sl -p tapefile -n -g CART -b 32768

      2. Issue the write(2) requests:

        #include <fcntl.h>
        
        void
        main( int argc, char **argv ) {
        
                char   buf[98304];
                int    fd;
                int    bytes;
        
                fd = open( "tapefile", O_WRONLY );
                bytes = write( fd, buf, 98304 );
                bytes = write( fd, buf, 32768 );
        }

        Procedure 4-4. Reading a Tape File

        Read 3 blocks, each 32768 bytes in length, followed by another read(2) request which returns one block of size 32768 bytes.

        1. Specify the maximum block size as 32768 bytes on your tmmnt(1) command:

          tmrsv CART 1
          tmmnt -v 004141 -l sl -p tapefile -g CART -b 32768

        2. Issue the read(2) requests:

          #include <fcntl.h>
          
          void
          main( int argc, char **argv ) {
          
               char    buf[100000];
               int     fd;
               int     bytes;
          
                 fd = open( "tapefile", O_RDONLY );
                 bytes = read( fd, buf, 100000);
                 bytes = read( fd, buf, 32768 );
          }

          4.2.3. Status

          Information is available about end-of-file, end-of-data, and error status.

          4.2.3.1. End-of-File Status

          If a filemark is detected on a read(2) request, the request returns a short count if data was read and the filemark is processed on the next I/O request. If no data was read, TMF determines if the filemark is embedded in data or indicates an end of the dataset.

          If the filemark detected is embedded in data and the user has permission to process these filemarks, the tape is left positioned after the filemark and zero is returned to notify you of the filemark status. Permission to process filemarks is requested with the -T option on the tmmnt(1) command.

          Otherwise, if the user does not have permission to process filemarks embedded in data, the user's request is terminated and no further requests other than a close(2) request is accepted. On the read(2) request, -1 is returned to notify you of the error.

          4.2.3.2. End-of-Data Status

          If a filemark is detected on a read(2) request and the filemark terminates the dataset, the tape is left positioned before the filemark. All further read requests return the filemark status; that is, the zero byte count.

          To distinguish between an end-of-file and an end-of-data status, use a ioctl(2) system call with a TMFC_EOD request (see Section 4.3.1.1). This request returns 0 if the filemark indicates the end of the data, and -1 if the filemark is a user filemark. Otherwise, since a filemark status will continue to be returned once the end-of-data is detected, a count of the number of consecutive filemarks detected can be used.

          4.2.3.3. Error Status

          If an error is detected on a read(2) request or write(2) request, the I/O request returns a short count or -1 if no data was input or output. If a short count is returned, the next I/O request returns -1 to notify you of the error.

          If a negative byte count is returned, errno is set to identify the error. Additional information relating to the error is also available in the user's message file, which is specified when the user reserves resources with the tmrsv(1) command.

          4.3. Using System Calls: ioctl

          TMF supports ioctl(2) requests, which perform tape device operations, set certain device attributes, provide TMF status information and device information, and perform user end-of-volume (EOV) special processing. The ioctl(2) request codes, structures, and field values are defined in the TMF ioctl definition file, /usr/include/tmf/sys/tmfctl.h, and the tape ioctl definition file, /usr/include/sys/mtio.h (see Section 4.3.2). Table 4-1, describes these files:

          Table 4-1. ioctl Definition Files

          File

          Description

          /usr/include/tmf/sys/tmfctl.h

          The ioctl(2) requests defined in the tmfctl.h file either return TMF status information or perform tape device operations via the TMF daemon and its child processes.

          /usr/include/sys/mtio.h

          The ioctl(2) requests defined in this file are primarily for users who are not using TMF to access tape devices, but are instead using the tpsc tape interface (see the tpsc(7M) man page.

          TMF users can access mtio.h requests that do no not involve tape movement or the setting of attributes.

          TMF controls the other tape operations, which users can request using the TMF ioctl interface defined in tmfctl.h.


          4.3.1. tmfctl.h ioctl Requests

          The following ioctl(2) requests are defined in the tmfctl.h file:

          • Status ioctl(2) requests

          • TMF daemon request or reply ioctl(2) requests

          4.3.1.1. Status ioctl Requests

          Using the ioctl(2) system call with the TMFC_DAEMON and TMFC_EOD requests provides status information.

          TMFC_DAEMON returns TMF status. The ioctl(2) system call returns an exit code of 0 if TMF is up; otherwise, an exit status of -1 is returned.

          TMFC_EOD returns the state of a tape file. If the tape is positioned at the end-of-data, 0 is returned; otherwise, -1 is returned.

          4.3.1.2. TMF Daemon Request or Reply ioctl Requests

          The ioctl(2) system call supports the TMFC_DMNREQ and TMFC_DMNREP requests, which provide positioning and related status information.

          TMFC_DMNREQ issues requests to TMF daemon. These requests include tape positioning requests, user end-of-volume (EOV) special processing requests, filemark writes, and informational requests. The TMFC_DMNREQ request can be sent synchronously or asynchronously.

          TMFC_DMNREP obtains the status of an asynchronous TMF daemon request.

          On synchronous requests, a reply is not sent until TMF daemon completes the request.

          On asynchronous requests, a reply to the TMFC_DMNREQ request is returned after TMF daemon has been forwarded the request. Once the TMF daemon has completed the request, the status of the request can be obtained with the TMFC_DMNREP request. If the TMFC_DMNREP request is issued before the request completes, TMF waits for the request to complete before replying to the user.

          The TMF daemon request consists of a header and, for those requests which require additional information, a request body. The header has the following format:

          typedef struct  tmfreqhdr {
                  int     request;
                  int     length;
                  int     reply;
                  int     residual;
                  int     async;
          } tmfreqhdr_t;

          Structures for requests which require more information than what is provided in tmfreqhdr_t are also defined in tmfctl.h. These structures consist of the request header, tmfreqhdr_t, followed by information specific to the request.

          The following tmfreqhdr_t values must be set in the request:

          Value 

          Description

          request 

          TMF request type

          length 

          Size of the request excluding the header

          async 

          Asynchronous processing enabled

          The following TMF daemon requests are supported:

          Request 

          Description

          TR_CLV 

          Closes the current tape volume

          TR_EOV 

          Selects or deselects user end-of-volume (EOV) processing

          TR_INFO 

          Returns TMF stream information

          TR_PABS 

          Performs absolute positioning

          TR_PBLKS 

          Performs block positioning

          TR_PFMS 

          Performs file positioning

          TR_PVOL 

          Performs volume positioning using an index

          TR_PVSN 

          Performs volume positioning using a volume name

          TR_RWD 

          Rewinds the tape file

          TR_WFM 

          Writes a filemark

          On synchronous requests, TMF returns the status of the request in the reply field, and a residual in the residual field. The reply status values are defined in the /usr/include/tmf/tmferr.h file. TMFC_DMNREQ and TMFC_DMNREP return the following tmferr.h values.

          Value 

          Description

          ETBOF 

          The beginning of the file was detected.

          ETBOT 

          The beginning of the tape was detected.

          ETBRQ 

          An invalid request was sent to the tape device.

          ETEOD 

          The end of recorded data was detected.

          ETEOF 

          The end-of-file was detected.

          ETEOM 

          The end-of-media was detected.

          ETFMNA 

          Filemark processing is not permitted.

          ETFMS 

          The filemark was detected.

          ETIVSN 

          An invalid VSN was specified.

          ETLBL 

          An invalid label structure or sequence was used.

          ETLOADF 

          A volume load failure occurred.

          ETMEDIA 

          A media error occurred.

          ETNDY 

          The device is not ready,

          ETNOP 

          The device is not operational.

          ETNVS 

          The VSN was not found.

          ETOFF 

          An invalid VSN offset was specified.

          ETRST 

          The device was reset.

          ETUDE 

          An unrecoverable data error occurred.

          The residual value is that portion of the request which did not complete. This field is valid only for block and file positioning requests and write filemark requests.

          TMFC_DMNREP is used to obtain the status of a TMF daemon request that was issued asynchronously. The argument to the TMFC_DMNREP request is a pointer to the tmfrep_t data structure:

          typedef  struct   tmfrep {
                   int      reply;
                   int      residual;
                   int      datalen;
                   void     *databuf;
          } tmfrep_t;  

          For requests that return data, you set the following tmfrep_t values in the requests:

          Value 

          Description

          databuf 

          Pointer to a data buffer to which information gathered by TMF will be copied

          datalen 

          Length of the data buffer

          The reply and residual fields are returned by TMF and return the same values as in the TMF_DMNREQ request.

          TMF supports the following types of requests:

          • Positioning requests

          • User end-of-volume (EOV) positioning requests

          • Write filemark requests

          • Information requests

          • Positioning requests

          • User end-of-volume (EOV) positioning requests

          • Write filemark requests

          • Information requests

          4.3.1.3. Positioning Requests

          The following requests control positioning:

          • Rewind positioning

          • Block positioning

          • File positioning

          • Absolute positioning

          • Volume index positioning

          • Volume name positioning

          4.3.1.3.1. Rewind Positioning

          The rewind request positions a tape to the beginning of the current file as shown in Example 4-3.

          Example 4-3. Synchronous Rewind Request

          If the beginning of the file is on a volume which is not currently mounted, TMF mounts the correct volume before positioning to the beginning of file. If the file is a concatenated file, TMF positions to the beginning of the first file of the concatenated set. If this request is issued after a write(2) request, the volume is terminated before positioning the tape.

          The argument to the rewind request is a pointer to the tmfreqhdr_t structure with the request code set to TR_RWD.

          #include <errno.h>
          #include <sys/fcntl.h>
          #include <tmf/sys/tmfctl.h>
          
          void
          main( int argc, char **argv ) {
          
              tmfpblk_t  req;
              int fd;
              int c;
          
              /*
               *   Open the TMF path.  "tmfpath" is the path name specified on
               *   the tmmnt command.
               */
          
              fd = open( "tmfpath", O_RDWR );
              if ( fd < 0 ) {
                   printf( "Unable to open file tmfpath (errno = %d)\n",
                                                               errno );
                   exit(errno);
              }
          
              /*
               *   Create and send the TMF rewind request.
               */
          
               req.request = TR_RWD;
               req.async   = 0;
               req.length  = 0;
               req.reply   = 0;
               c = ioctl( fd, TMFC_DMNREQ, &req );
               if ( c < 0 ) {
                   printf( "Unable to issue the TMF rewind request (errno=%d)\n",
                   errno );
                   exit(errno);
               }
          
              /*
               *   Check the status of the rewind request.
               */
          
               if (req.reply ) {
                   printf( "Error %d on the TMF rewind request\n", req.reply);
                   exit(EIO);
               }
               exit(0);
          }


          4.3.1.3.2. Block Positioning

          The block positioning request positions forward or backward by blocks.

          Block positioning can span volumes for multivolume or concatenated files. TMF mounts the next volume in a volume set if the end-of-volume (EOV) is detected on forward positioning requests. Positioning then continues at the beginning of the file section on the next volume. TMF mounts the previous volume if the beginning-of-volume (BOV) is detected on a backward positioning request. Positioning then continues at the end of the file section on this volume.

          Example 4-4 illustrates a synchronous block positioning request. If this request is issued after a write(2) request, the volume is terminated before positioning the tape.

          Example 4-4. Synchronous Block Positioning Request

          The argument to the block positioning request is a pointer to the tmfpblk_t structure with the request code set to TR_PBLKS. The count field of the tmfpblk_t structure specifies the number of blocks to position.

          A positive count value, N, positions the tape forward. The tape is left positioned after the Nth block on the end-of-tape (EOT) side of the block.

          A negative count value, N, positions the tape backwards. The tape is left positioned on the beginning-of-tape (BOT) side of the Nth block. A count value of zero, positions the tape backward one block and then forward one block, leaving the tape at the same position.

          The error status is returned in the reply field of the tmfreqhdr_t or tmfrep_t structure. If one of the following error conditions is detected, block positioning is terminated and the error returned.

          #include <errno.h>
          #include <stdlib.h>
          #include <sys/fcntl.h>
          #include <tmf/sys/tmfctl.h>
          
          void
          main( int argc, char **argv ) {
          
              tmfpblk_t  req;
              int  fd;
              int  c;
          
              /*
               *   Open the TMF path.  "tmfpath" is the path name specified on
               *   the tmmnt command.
               */
          
              fd = open( "tmfpath", O_RDWR );
              if ( fd < 0 ) {
                 printf( "Unable to open file tmfpath (errno = %d)\n", errno );
                          exit(errno);
              }
          
              /*
               *   Create and send a request to position forward 5 blocks.
               */
          
              req.rh.request  = TR_PBLKS;
              req.rh.length   = sizeof(tmfpblk_t) - sizeof(tmfreqhdr_t);
              req.rh.async    = 0;
              req.rh.reply    = 0;
              req.rh.residual = 0;
              req.count       = 5;
              c = ioctl( fd, TMFC_DMNREQ, &req );
              if ( c < 0 ) {
                 printf("Unable to issue the block position request (errno=%d)\n",
                                                      errno );
                 exit(errno);
              }
          
              /*
               *   Check the status of the block positioning request.
               */
          
              if ( req.rh.reply ) {
                 printf("Error %d on the block position request\n", req.rh.reply );
                 printf("%d blocks of the requested %d blocks were positioned\n",
                          abs(req.count) - req.rh.residual, abs(req.count) );
                 exit(EIO);
              }
              exit(0);
          }


          4.3.1.3.3. File Positioning

          The file positioning request positions forward or backward by filemarks.

          File positioning can span volumes for multivolume or concatenated files. TMF mounts the next volume in a volume set if the end-of-volume (EOV) is detected on forward positioning requests. Positioning then continues at the beginning of the file section on the next volume. TMF mounts the previous volume if the beginning-of-volume is detected on a backward positioning request. Positioning then continues at the end of the file section on this volume.

          If this request is issued after a write(2) request, the volume is terminated before positioning the tape.

          To perform file positioning, you enable filemark processing with the -T option on the tmmnt(1) command.

          Example 4-5 illustrates a synchronous file positioning request.

          Example 4-5. Synchronous File Positioning Request

          The argument to the block positioning request is a pointer to the tmfpfm_t structure with the request code set to TR_PFMS. The count field of the tmfpfm_t structure specifies the number of files to position.

          A positive count value, N, positions the tape forward. The tape is left positioned after the Nth file on the end-of-tape (EOT) side of the filemark.

          A negative count value, N, positions the tape backwards. The tape is left positioned on the beginning-of-tape (BOT) side of the Nth filemark.

          A count value of zero does not change the tape position.

          #include <errno.h>
          #include <stdlib.h>
          #include <sys/fcntl.h>
          #include <tmf/sys/tmfctl.h>
          
          void
          main( int argc, char **argv ) {
          
             tmfpfm_t  req;
             int  fd;
             intc;
          
              /*
               *  Open the TMF path.  "tmfpath" is the path name specified on
               *   the tmmnt command.
               */
          
             fd = open( "tmfpath", O_RDWR );
             if ( fd < 0 ) {
                  printf( "Unable to open file tmfpath (errno = %d)\n", errno );
                  exit(errno);
             }
          
             /*
              *   Create and send a request to position backward 7 filemarks.
              */
          
             req.rh.request  = TR_PFMS;
             req.rh.length   = sizeof(tmfpfm_t) - sizeof(tmfreqhdr_t);
             req.rh.async    = 0;
             req.rh.reply    = 0;
             req.rh.residual = 0;
             req.count       = -7;
             c = ioctl( fd, TMFC_DMNREQ, &req );
             if ( c < 0 ) {
                  printf("Unable to issue the file position request (errno=%d)\n",
                                                                 errno );
                  exit(errno);
             }
          
             /*
              *   Check the status of the file positioning request.
              */
          
             if ( req.rh.reply ) {
                  printf("Error %d on the file position request\n", req.rh.reply );
                  printf("%d files of the requested %d files were positioned\n",
                           abs(req.count) - req.rh.residual, abs(req.count) );
                  exit(EIO);
             }
             exit(0);
          }


          4.3.1.3.4. Absolute Positioning

          The absolute positioning request moves the tape to a specified address. This request can only be performed by tape administrators.

          If this request is issued after a write(2) request, the volume is terminated before positioning the tape.

          Example 4-6 illustrates a synchronous absolute positioning request.

          Example 4-6. Synchronous Absolute Positioning Request

          The argument to the absolute positioning request is a pointer to the tmfpabs_t structure with the request code set to TR_PABS. The blkaddr field of the tmfpabs_t structure specifies the address of the block to position to. You can obtain the address of a block with a MTIOCGET or MTIOCGETEXT ioctl call (see Section 4.3.2.3). The address is returned in the mt_blkno field of these requests.

          #include <errno.h>
          #include <sys/fctnl.h>
          #include <tmf/sys/tmfctl.h>
          
          void
          main( int argc, char **argv )
          {
             tmfpabs_t  req;
             intfd;
             intc;
          
             /*
              *   Open the TMF path.  "tmfpath" is the path name specified on
              *   the tmmnt command.
              */
          
             fd = open( "tmfpath", O_RDWR );
             if ( fd < 0 ) {
                  printf( "Unable to open file tmfpath (errno = %d)\n", errno );
                   exit(errno);
             }
          
             /*
              *   Create and send a request to position to the specified block.
              *   The block location is obtained with the MTIOCGET or MTIOCGETEXT
              *   ioctl.
              */
          
             req.rh.request = TR_PABS;
             req.rh.length  = sizeof(tmfpabs_t) - sizeof(tmfreqhdr_t);
             req.rh.async   = 0;
             req.rh.reply   = 0;
             req.blkaddr    = block-address;
             c = ioctl( fd, TMFC_DMNREQ, &req );
             if ( c < 0 ) {
                  printf("Unable to issue the absolute positioning request (errno=%d)\n",
                                                                 errno );
                  exit(errno);
             }
          
             /*
              *   Check the status of the absolute positioning request.
              */
          
             if ( req.rh.reply ) {
                  printf("Error %d on the absolute positioning request\n",
                                                                req.rh.reply );
                  exit(EIO);
             }
             exit(0);
          }


          4.3.1.3.5. Volume Index

          The volume index positioning request positions to the beginning-of-volume (BOV) of the volume with the specified offset in the volume identifier list as shown in Example 4-7. It illustrates a synchronous volume positioning request using an index.

          Example 4-7. Synchronous Volume Positioning Request

          The argument to the volume index positioning request is a pointer to the tmfpvol_t structure with the request code set to TR_PVOL. The index field of the tmfpvol_t structure specifies the index of the volume to position to. 1 specifies the first volume in the volume list, 2 specifies the second volume, and so on.

          You specify the volume list with the tmmnt(1) command. In this example, if the volume list on the tmmnt(1) command is specified as follows, then an index of 4 positions to the beginning-of-volume 004143.

          tmmnt -v 00410:004141:004142:004143 -1 sl -p tmfpath ...

          #include <errno.h>
          #include <sys/fcntl.h>
          #include <tmf/sys/tmfctl.h>
          
          void
          main( int argc, char **argv )
          {
              tmfpvol_t  req;
              int     fd;
              int     c;
          
              /*
               *   Open the TMF path.  "tmfpath" is the path name specified on
               *   the tmmnt command.
               */
          
              fd = open( "tmfpath", O_RDWR );
              if ( fd < 0 ) {
                   printf( "Unable to open file tmfpath (errno = %d)\n", errno );
                   exit(errno);
              }
          
              /*
               *   Create and send a request to position to the beginning of the
               *   volume with an index of 2 in the volume list.
               */
          
              req.rh.request  = TR_PVOL;
              req.rh.length   = sizeof(tmfpvol_t) - sizeof(tmfreqhdr_t);
              req.rh.async    = 0;
              req.rh.reply    = 0;
              req.index       = 2;
              c = ioctl( fd, TMFC_DMNREQ, &req );
              if ( c < 0 ) {
                   printf("Unable to issue the volume positioning request (errno=%d)\n",
                                                                  errno );
                   exit(errno);
              }
          
              /*
               *   Check the status of the volume positioning request.
               */
          
              if ( req.rh.reply ) {
                   printf("Error %d on the volume positioning request\n",
                                                                 req.rh.reply );
                   exit(EIO);
              }
          }


          4.3.1.3.6. Volume Name

          The volume name positioning request positions to the beginning-of-volume of the volume with the specified external volume identifier. Example 4-8 illustrates a synchronous volume positioning request using a volume identifier.

          Example 4-8. Synchronous Volume Positioning Request (Volume Identifier)

          The argument to the volume index positioning request is a pointer to the tmfpvsn_t structure with the request code set to TR_PVSN. The evsn field of the tmfpvsn_t structure specifies the external volume identifier of the volume to position to. The fvsn field of the tmfpvsn_t structure specifies the format identifier of the volume to position to.


          Note: The fvsn field is only applicable to devices which support format identifiers and support for these devices is deferred.


          #include <errno.h>
          #include <sys/fcntl.h>
          #include <tmf/sys/tmfctl.h>
          
          void
          main( int argc, char **argv )
          {
             tmfpvsn_t  req;
             intfd;
             intc;
          
             /*
              *   Open the TMF path.  "tmfpath" is the path name specified on
              *   the tmmnt command.
              */
          
             fd = open( "tmfpath", O_RDWR );
             if ( fd < 0 ) {
                  printf( "Unable to open file tmfpath (errno = %d)\n", errno );
                  exit(errno);
             }
          
             /*
              *   Create and send a request to position to the beginning of the
              *   volume with the external volume identifier of "004141".
              */
          
             req.rh.request  = TR_PVSN;
             req.rh.length   = sizeof(tmfpvsn_t) - sizeof(tmfreqhdr_t);
             req.rh.async    = 0;
             req.rh.reply    = 0;
             strcpy( req.evsn, "004141" );
             c = ioctl( fd, TMFC_DMNREQ, &req );
             if ( c < 0 ) {
                  printf("Unable to issue the volume positioning request (errno=%d)\n",
                                                                 errno );
                  exit(errno);
             }
          
             /*
              *   Check the status of the volume positioning request.
              */
          
             if ( req.rh.reply ) {
                  printf("Error %d on the volume positioning request\n",
                                                                 req.rh.reply );
                  exit(EIO);
             }
             exit(0);
          }


          4.3.1.4. User End-of-Volume Processing Requests

          User end-of-volume (EOV) processing allows a user to close a volume or gain control when the end-of-tape (EOT) or EOV is detected. The following are EOV processing requests:

          • Selection and deselection

          • Close volume

          Example 4-9 illustrates a synchronous user EOV selection and deselection request as well as a close volume request.

          4.3.1.4.1. Selection and Deselection

          The user end-of-volume (EOV) selection request controls when the EOT is detected on a write(2) request or when the EOV is detected on a read(2) request. The default action is to terminate the current volume and then mount the next volume when the EOT is detected or to mount the next volume when the EOV is detected.

          Obtaining control at the EOT or EOV allows a user to determine how much data is written at the EOT by either reading back data or writing additional data, to terminate a volume with the user's own volume termination data, to write the user's own volume header information after the next volume is mounted, or to perform any other additional processing before the next volume is mounted.

          4.3.1.4.2. Close Volume

          The close volume request closes the current volume and mounts the next volume of the volume set. If data was being output, the request terminates the current volume before mounting the next volume. If user EOV processing is selected and the EOT is detected before the close volume request is issued, the volume is terminated regardless of the type of I/O taking place between the EOT detection and the close volume request.

          For example, if, after the EOT is detected, the tape is positioned backward five blocks before a close volume request is issued, the file is terminated at this point and the five blocks are lost.

          Example 4-9. EOV Selection and Deselection Request, and Close Request

          The argument to the TMF user EOV selection or deselection request is a pointer to the tmfeov_t structure with the request code set to TR_EOV. The select field of the tmfeov_tstructure is set to a nonzero value to select user EOV processing and is set to zero to deselect user EOV processing.

          The argument to the close volume request is a pointer to the tmfreqhdr_t structure with the request code set to TR_CLV.

          #include <errno.h>
          #include <stdlib.h>
          #include <sys/fcntl.h>
          #include <tmf/sys/tmfctl.h>
          
          void
          closev( int );
          void
          eov( int, int );
          int  wrttape( int, char *, int *, int * );
          
          *define BUFSIZE  98304
          
          void
          main( int argc, char **argv ) {
          
             charbuf[BUFSIZE];
             int  count=0
             int  datalen;
             int  fd, c, i;
          
             /*
              *   Open the TMF path. "tmfpath" is the path name specified on
              *   the tmmnt command.
              */
          
             fd = open( "tmfpath", O_RDWR );
             if ( fd < 0 ) {
                  printf( "Unable to open file tmfpath (errno = %d)\n", errno);
                  exit(errno);
             }
          
             /*
              *   Create and send a request to select user end-of-volume processing.
              */
          
             eov(fd,1);
          
             /*
              *   Write until EOT.
              */
          
             while ( !wrttape( fd, buf, &count, &datalen ) );
          
             /*
              *   Complete the last block.
              */
          
             if ( datalen ) {
                  c = write( fd, buf+datalen, BUFSIZE-datalen );
                  if ( c != BUFSIZE-datalen )
                           exit(EIO);
             }
          
             /*
              *   Close the volume.
              */
          
             closev(fd);
          
             /*
              *   Deselect user end-of-volume processing.
              */
          
             eov(fd,0);
          
             /*
              *   Output additional data on the next volume.
              */
          
             for ( i=0; i , 5; i++ ) {
                  wrttape( fd, buf, &count, &datalen );
             }
             exit(0);
          }
          
          /*
           *   closev
           *
           *   Terminate the current volume and mount the next.
           *
           */
          
          void
          closev( int fd ) {
          
             tmfreqhdr_t  req;
             int  c;
          
             req.request = TR_CLV;
             req.length  = 0;
             req.async   = 0;
             req.reply   = 0;
             c = ioctl( fd, TMFC_DMNREQ, &req );
             if (c < 0 ) {
                  printf( "Unable to issue the close volume request (errno=%d)\n",
                                                                errno );
                  exit(errno);
             }
          
             /*
              *   Check the status of the close volume request.
              */
          
             if ( req.reply ) {
                  printf( "Error %d on the close volume request\n", req.reply );
                  exit(EIO);
             }
          }
          
          /*
           *  eov
           *
           *  Select or deselect user end-of-volume processing.
           *
           */
          
          void
          eov( int fd, int value ) {
              tmfeov_t req;
              int c;
          
              req.rh.request = TR_EOV;
              req.rh.length  = sizeof(tmfeov_t) - sizeof(tmfreqhdr_t);
              req.rh.async   = 0;
              req.rh.reply   = 0;
              req.select     = value;
              c = ioctl( fd, TMFC_DMNREQ, &req );
              if ( c < 0 ) {
                   printf( "Unable to issue the eov request (errno=%d)\n", errno );
                   exit(errno);
              }
          
              /*
               *   Check the status of the eov request.
               */
          
              if ( req.rh.reply ) {
                   printf('Error %d on the eov request\n", req.rh.reply );
                   exit(EIO);
              }
          }
          
          /*  wrttape
           *
           *  Returns;
           *    0        No error
           *    1        EOT
           *
           */
          
          int
          wrttape( int fd, char *buf, int *count, int *datalen ) {
          
              char *bp = buf;
              int  *bpw = (int *)buf;
              int  nbytes, len;
          
              len    = BUFSIZE;
              bpw[0] = *count;
              while ( len ) {
                   nbytes = write( fd, bp, len );
                   if ( nbytes < 0 ) {
          
          /* Error on write */
          
                        if ( errno == ENOSPC )
                             return(1);
          
                                 /* At End-of-Tape */
          
                        printf( "Unrecoverable write error (errno = %d)\n", errno );
                        exit(1);
                   }
                   *datalen = len - nbytes;
                   bp  += nbytes;
                   len -= nbytes;
               }
               (*count)++;
               return(0);
          }


          4.3.1.5. Write Filemark Requests

          The write filemark requests allow you to output one or more filemarks to tape. You enable filemark writes with the -T option on the tmmnt(1) command. Example 4-10 illustrates a synchronous write filemark request.

          Example 4-10. Synchronous Write Filemark Request

          The argument to a write filemark request is a pointer to the tmfwfm_t structure with the request code set to TR_WFM. The count field of the tmfwfm_t structure specifies the number of filemarks to write.

          #include <errno.h>
          #include <sys/fcntl.h>
          #include <tmf/sys/tmfctl.h>
          
          void
          main( int argc, char **argv )
          {
             tmfwfm_t  req;
             intfd;
             intc;
          
             /*
              *   Open the TMF path.  "tmfpath" is the path name specified on
              *   the tmmnt command.
              */
          
             fd = open( "tmfpath", O_RDWR );
             if ( fd < 0 ) {
                  printf( "Unable to open file tmfpath (errno = %d)\n", errno );
                  exit(errno);
             }
          
             /*
              *   Create and send a request to write 2 filemarks.
              */
          
             req.rh.request  = TR_WFM;
             req.rh.length   = sizeof(tmfwfm_t) - sizeof(tmfreqhdr_t);
             req.rh.async    = 0;
             req.rh.reply    = 0;
             req.rh.residual = 0;
             req.count       = 2;
             c = ioctl( fd, TMFC_DMNREQ, &req );
             if ( c < 0 ) {
                  printf("Unable to issue the write filemark request (errno=%d)\n",
                                                                 errno );
                  exit(errno);
             }
          
             /*
              *   Check the status of the write filemark request.
              */
          
             if ( req.rh.reply ) {
                  printf("Error %d on the write filemark request\n", req.rh.reply );
                  printf("%d filemarks of the requested %d filemarks were written\n",
                               req.count - req.rh.residual, req.count );
                  exit(EIO);
             }
          
             exit(0);
          }


          4.3.1.6. Information Requests

          The information requests return tape stream information. These requests return information such as the current block size, maximum block size, label type, device type, device name, current VSN, file expiration date, VSN list, and the last device function and status.

          The argument to an information request is a pointer to the tmfinfo_t structure with the request code set to TR_INFO. The details differ for synchronous and asynchronous requests:

          TMF returns the stream information data in the tsdata_t structure followed by a list of 8 character volume names. tsdata_t is defined in the /usr/include/tmf/tmfreq.h include file; this structure contains the following fields:

          Field 

          Description

          ts_ba 

          Block attribute of the tape dataset. On new files, you define this value with the -F option on the tmmnt(1) command. On old files, you obtain this value from the tape label. The following are valid values:

          Value

          Description

          B

          Blocked

          S

          Spanned, for variable-length records

          S

          Standard, for fixed-length records

          R

          Blocked and spanned records, if variable length

          R

          Blocked and standard records, if fixed length

          ts_block 

          File block number. This value includes user filemarks as well as blocks. If absolute positioning takes place, this value is no longer valid.

          ts_blocksize 

          File block size. This value is valid only for fixed block-length files.

          ts_bnum 

          Block number relative to the last user filemark written.

          ts_cvsn 

          Index in the volume identifier list of the current volume. 0 is the first volume in the volume list; 1 is the second volume and so on.

          ts_day 

          Current day in the year. Valid values are 1 through 366.

          ts_den 

          Requested density value. The following are valid values:

          Value

          Description

          DEN_800

          800 bpi

          DEN_1600

          1600 bpi

          DEN_3200

          3200 bpi

          DEN_4000

          4000 bpi

          DEN_7000

          7000 bpi

          DEN_8200

          8200 bpi

          DEN_8500

          8500 bpi

          ts_dev 

          Major or minor device number of the assigned tape device.

          ts_dgn 

          Resource name of the assigned device.

          ts_dst 

          Last device status represented by a set of flags. The following device status flags are in the /usr/include/sys/tpsc.h file:

          Flag 

          Description

          CT_EOM 

          At end-of-media.

          CT_BOT 

          At beginning-of-tape (BOT).

          CT_WRP 

          Write protected volume.

          CT_EW 

          At end-of-tape.

          CT_GETBLKLEN 

          Block length request is pending.

          CT_MOTION 

          Last command moved the tape.

          CT_ONL 

          Device is online.

          CT_QIC24 

          Low density tape on Viper 150 device.

          CT_QIC120 

          High density tape on Viper 150 device.

          CT_OPEN 

          Tape device is open.

          CT_READ 

          Last tape movement request was a read(2) request.

          CT_WRITE 

          Last tape movement request was a write(2) request.

          CT_CHG 

          Unit attention occurred

          CT_DIDIO 

          A tape movement request has been done since the device is open.

          CT_EOD 

          At end of recorded data.

          CT_FM 

          At filemark.

          ts_dty 

          Type of the assigned device. Valid device types are defined in the /usr/include/sys/invent.h file beginning with the TPUNKNOWN value.

          ts_dvn 

          Name of the assigned device.

          ts_eov 

          User end-of-volume selection state. The following are valid values:

          Value

          Description

          0

          User end-of-processing is not selected.

          1

          User end-of-processing is selected.

          ts_eovproc 

          User end-of-volume processing state. The following are valid values:

          Value

          Description

          0

          No user end-of-processing.

          1

          In user end-of-processing; that is, the EOT or EOV was detected, and a new volume has not yet been mounted.

          ts_erreg 

          Last device error status. The device status flags can be found in the /usr/include/sys/tpsc.h file.

          The ts_erreg[0] error status is represented by the upper 16 bits of the following flags:

          Flag 

          Description

          CT_NEEDBOT 

          Positioning is required before I/O.

          CT_LOADED 

          Tape has been loaded.

          CT_ANSI 

          I/O is permitted after EOT.

          CT_SMK 

          Drive is at a setmark.

          CT_AUDIO 

          Drive is in audio mode.

          CT_AUD_MED 

          Media is recorded in audio format.

          CT_MULTPART 

          Multi-partitioned volume is loaded.

          CT_SEEKING 

          Seek request is pending.

          CT_HITFMSHORT 

          Filemark was detected, but the status has not yet been returned to the user.

          CT_INCOMPAT_MEDIA 

          Media is incompatible with the device.

          CT_CLEANHEADS 

          Device needs to be cleaned.

          CT_COMPRESS 

          Device is in compression mode.

          CT_MEDIA_ERR 

          Media error has been detected.

          CT_EOD 

          At end of recorded data.

          CT_FM 

          At filemark.

          The ts_erreg[1] error status is represented by the upper 16 bits of the following flags:

          Flag 

          Description

          CT_BAD_REQT 

          An invalid request was issued to the device.

          CT_LARGE_BLK 

          The block on tape is larger than the requested read byte count.

          CT_LOAD_ERR 

          Volume load failed.

          CT_HWERR 

          Hardware error occurred.

          CT_NOT_READY 

          Device is not ready.

          CT_BLKLEN 

          Actual recorded block size differs from the set size.

          The remaining ts_erreg statuses are undefined.

          ts_fcn 

          Last user request issued. The following user request codes are defined in the /usr/include/sys/mtio.h file:

          Code 

          Description

          MTR_READ 

          read(2) request

          MTR_WRITE 

          write(2) request

          MTR_WFM 

          Write filemark(s)

          MTR_SRB 

          Skip records backward

          MTR_SRF 

          Skip records forward

          MTR_SFB 

          Skip filemarks backward

          MTR_SFF 

          Skip filemarks forward

          MTR_SEOD 

          Space to the end-of-data

          MTR_SEOM 

          Space to the end-of-media

          MTR_FORMAT 

          Volume format

          MTR_PART 

          Position to a partition

          MTR_SSM 

          Skip filemarks

          MTR_WSM 

          Write filemarks

          MTR_MODEAUD 

          Enable or disable audio mode

          MTR_REW 

          Rewind

          MTR_ERASE 

          Erase from current position to the EOT

          MTR_RETEN 

          Retention

          MTR_UNLOAD 

          Unload

          MTR_PABS 

          Position to an absolute address

          MTR_PAUDIO 

          Audio position

          MTR_GAUDIO 

          Get audio position

          MTR_RDLOG 

          Read log

          MTR_ATTR 

          Set attribute

          MTR_SPOS 

          Set vendor specific position

          MTR_GPOS 

          Get vendor specific position

          ts_ffseq 

          File sequence number of first file on a volume. 1 is the first file of a volume set, 2, the second, and so on.

          ts_fid 

          File identifier.

          ts_first 

          Index of a volume in the volume identifier list of the volume in which a file begins. 1 is the first volume in the volume identifier list.

          ts_fmdir 

          Direction from the last user filemark. The following are valid values:

          Value

          Description

          0

          After filemark

          1

          Before filemark

          ts_fsec 

          File section number, that is, the number of the volume of the dataset. 1 is the first volume of the volume set.

          ts_fseq 

          File sequence number. 1 is the first file residing on the volume set.

          ts_fst 

          File status. The following are valid values:

          Value

          Description

          FST_NEW

          New file status

          FST_OLD

          Old file status

          FST_APP

          Append file status

          ts_h1 

          HDR1 label.

          ts_h2 

          HDR2 label.

          ts_lb 

          Label type. The following are valid values:

          Value

          Description

          LBL_NS

          Label type is not specified on the tmmnt(1) command.

          LBL_NL

          Nonlabeled.

          LBL_AL

          ANSI labeled tape.

          LBL_SL

          IBM standard label.

          LBL_BLP

          Bypass label processing.

          FST_ST

          Single filemark format.

          FST_ULP

          User label processing.

          ts_mbs 

          Maximum block size.

          ts_numvsn 

          Number of volumes in a volume set.

          ts_ord 

          Stream ordinal.

          ts_path 

          Stream path.

          ts_rf 

          Record format of the tape dataset. On new files, you define this value with the-F option on the tmmnt(1) command. On old files, you obtain it from the tape label. The following are valid values:

          Value

          Description

          D

          Variable length

          F

          Fixed length

          S

          Spanned

          U

          Undefined length

          ts_ring 

          Write ring status. The following are valid values:

          Value

          Description

          0

          Ring out

          1

          Ring in

          ts_rl 

          Record length is defined with the -L option on the tmmnt(1) command.

          ts_urwfm 

          Set if user read or write of filemarks is permitted.

          ts_vl 

          VOL1 label.

          ts_vsnoff 

          Offset to the VSN list from the beginning of the tsdata structure.

          ts_xday 

          File expiration day. Valid values are 1 through 366.

          ts_xyear 

          File expiration year. Valid values are 00 through 99.

          ts_year 

          Current year. Valid values are 00 through 99.

          Example 4-11 illustrates a synchronous information request.

          Example 4-11. Synchronous Information Request

          include # <errno.h>
          #include <sys/fcntl.h>
          #include <tmf/sys/tmfctl.h>
          #include <tmf/tmfreq.h>
          
          void
          main( int argc, char **argv )
          {
          
             tmfinfo_t  req;
             tsdata_t   *ts;
             cha     *vsnp;
             int     fd;
             int     c;
             int     i;
          
             /*
              *   Open the TMF path.  "tmfpath" is the path name specified on
              *   the tmmnt command.
              */
          
             fd = open( "tmfpath", O_RDWR );
             if ( fd < 0 ) {
                  printf( "Unable to open file tmfpath (errno = %d)\n", errno );
                  exit(errno);
             }
          
             /*
              *   Create and send a request for tape stream information.
              */
          
             req.rh.request  = TR_INFO;
             req.rh.length   = sizeof(tmfinfo_t) - sizeof(tmfreqhdr_t);
             req.rh.async    = 0;
             req.rh.reply    = 0;
             req.datalen     = sizeof(tsdata_t) + MAXVSN * L_MAXVSN;
             req.databuf     = (void *)calloc( 1, req.datalen );
             c = ioctl( fd, TMFC_DMNREQ, &req );
             if ( c < 0 ) {
                  printf("Unable to issue an information request (errno=%d)\n",
                                                                errno );
                  exit(errno);
             }
          
             /*
              *   Check the status of the stream information request.
              */
          
             if ( req.rh.reply ) {
                  printf("Error %d on the stream information request\n",
                                                                req.rh.reply );
                  exit(EIO);
             }
          
             /*
              *   Output selected fields from the returned information.
              */
          
             ts = (tsdata_t *)req.databuf;
             printf( "Stream Ordinal ........ %d\n",   ts->ts_ord    );
             printf( "Stream Path ........... %s\n",   ts->ts_path   );
             printf( "File Identifier ....... %s\n",   ts->ts_fid    );
             printf( "Device Name ........... %s\n",   ts->ts_dvn    );
             printf( "Device Type ........... %d\n",   ts->ts_dty    );
             printf( "Label Type ............ %d\n",   ts->ts_lb     );
             printf( "Maximum Block Size .... %d\n",   ts->ts_mbs    );
             printf( "Number of VSNs ........ %d\n",   ts->ts_numvsn );
          
             vsnp = (char *)req.databuf + ts->ts_vsnoff;
             printf( "VSN List\n");
             for ( i=0;  i < ts->ts_numvsn;  i++, vsnp+=L_MAXVSN ) {
                  printf("  %s\n", vsnp );
             }
          
             exit(0);
          }


          4.3.2. mtio.h ioctl Requests

          TMF supports the tape ioctl(2) requests defined in the /usr/include/sys/mtio.h file, which do not involve tape movement or the setting of certain attributes that must be controlled by TMF. It supports eight of these mtio.h requests:

          Request 

          Description

          MTCAPABILITY 

          Returns the device type and capabilities for a device

          MTIOCGETBLKINFO 

          Returns device block size information: the minimum, maximum, current, and recommended block size

          MTIOCGETEXT 

          Returns tape status

          MTIOCGETEXTL 

          Returns the last tape status

          MTSCI_RDLOG 

          Returns statistical information maintained by a device

          MTSCISI_SENSE 

          Returns the sense data from the last device command that terminated with a SCSI Check Condition or Command Terminated status

          MTSCSIINQ 

          Returns device parameter information

          MTSPECOP 

          Sets the block size for fixed-length I/O

          4.3.2.1. MTCAPABILITY

          The MTCAPABILITY ioctl request returns the device type and capabilities for a device. The argument to this request is a pointer to the mt_capablity structure defined in the /usr/include/sys/mtio.h file.

          On the reply, the mt_subtype field returns the device type. Valid device types are defined in the /usr/include/sys/invent.h file beginning with value TPUNKNOWN. The mt_capablity field returns the set of capabilities for a device. The capabilities are a set of flags, the MTCAN* status flags, which are also defined in the /usr/include/sys/mtio.h file.

          4.3.2.2. MTIOCGETBLKINFO

          The MTIOCGETBLKINFO ioctl request returns device block size information: the minimum, maximum, current, and recommended block size. The argument to this request is a pointer to the mtblkinfo structure, which is defined in the /usr/include/sys/mtio.h file.

          4.3.2.3. MTIOCGET

          The MTIOCGET ioctl request returns tape status. The argument to this request is a pointer to the mtget structure. The MTIOCGET ioctl returns the following values:

          Field 

          Description

          mt_type 

          Controller type. This value is always MT_ISSCI.

          mt_dposn 

          Tape position status. The following state flags are in the /usr/include/sys/mtio.h file:

          Flag 

          Description

          MT_EOM 

          At end-of-media.

          MT_BOT 

          At beginning-of-tape (BOT).

          MT_WPROT 

          Write protected volume.

          MT_EW 

          At end-of-tape.

          MT_ONL 

          Device is online.

          MT_EOD 

          At end of recorded data.

          MT_FMK 

          At filemark.

          mt_dsreg 

          Last device status represented by a set of flags. The device status flags are in the /usr/include/sys/tpsc.h file:

          Flag 

          Description

          CT_EOM 

          At end-of-media.

          CT_BOT 

          At beginning-of-tape (BOT).

          CT_WRP 

          Write protected volume.

          CT_EW 

          At end-of-tape (EOT).

          CT_GETBLKLEN 

          Block length request is pending.

          CT_MOTION 

          Last command moved the tape.

          CT_ONL 

          Device is online.

          CT_QIC24 

          Low density tape is on Viper 150 device.

          CT_QIC120 

          High density tape is on Viper 150 device.

          CT_OPEN 

          Tape device is open.

          CT_READ 

          Last tape movement request was a read(2) request.

          CT_WRITE 

          Last tape movement request was a write(2) request.

          CT_CHG 

          Unit attention occurred.

          CT_DIDIO 

          Tape movement request has been done since device open.

          CT_BOD 

          At end of recorded data.

          CT_FM 

          At filemark.

          mt_erreg 

          Last device error status. The device status flags are in the /usr/include/sys/tpsc.h file:

          Flag 

          Description

          CT_NEEDBOT 

          Positioning is required before I/O.

          CT_LOADER 

          Tape has been loaded.

          CT_ANSI 

          I/O after end-of-tape (EOT) is permitted.

          CT_SMK 

          Drive is at a setmark.

          CT_AUDIO 

          Drive is in audio mode.

          CT_AUD_MED 

          Media is recorded in audio format.

          CT_MULTPART 

          Multi-partitioned volume is loaded.

          CT_SEEKING 

          Seek request is pending.

          CT_HITFMSHORT 

          Filemark was detected, but the status has not yet been returned to the user.

          CT_INCOMPAT_MEDIA 

          Media is incompatible with the device.

          CT_CLEANHEADS 

          Device needs to be cleaned.

          CT_COMPRESS 

          Device is in compression mode.

          CT_MEDIA_ERR 

          Media error has been detected.

          CT_EOD 

          At end of recorded data.

          mt_resid 

          Partition number.

          mt_fileno 

          Not supported.

          mt_blkno 

          Block number (returned from the device).

          4.3.2.4. MTIOCGETEXT

          The MTIOCGETEXT ioctl returns the tape status. The argument to this request is a pointer to the mtgetext structure. The MTIOCGETEXT ioctl returns the following values:

          Field 

          Description

          mt_type 

          Controller type. This value is always MT_ISSCI.

          mt_dposn 

          Tape position status. The status flags are in the /usr/include/sys/mtio.h file. See Section 4.3.2.3, for a list of the mt_dposn values.

          mt_dsreg 

          Last device status represented by a set of flags. The device status flags are in the /usr/include/sys/tpsc.h file. See Section 4.3.2.3, for a list of the mt_dposn values.

          mt_erreg 

          Last device error status. The device status flags can be found in the /usr/include/sys/tpsc.h file.

          The ts_erreg[0] error status is represented by the upper 16 bits of the following status flags:

          Flag 

          Description

          CT_NEEDBOT 

          Positioning is required before I/O.

          CT_LOADER 

          Tape has been loaded.

          CT_ANSI 

          I/O after end-of-tape (EOT) is permitted.

          CT_SMK 

          Drive is at a setmark.

          CT_AUDIO 

          Drive is in audio mode.

          CT_AUD_MED 

          Media is recorded in audio format.

          CT_MULTPART 

          Multi-partitioned volume is loaded.

          CT_SEEKING 

          Seek request is pending.

          CT_HITFMSHORT 

          Filemark was detected, but the status has not yet been returned to the user.

          CT_INCOMPAT_MEDIA 

          Media is incompatible with the device.

          CT_CLEANHEADS 

          Device needs to be cleaned.

          CT_COMPRESS 

          Device is in compression mode.

          CT_MEDIA_ERR 

          Media error has been detected.

          CT_EOD 

          At end of recorded data.

          The ts_erreg[1] error status is represented by the status following flags:

          Flag 

          Description

          CT_BAD_REQT 

          An invalid request was issued to the device.

          CT_LARGE_LBLK 

          The block on tape is larger than the requested read byte count.

          CT_LOAD_ERR 

          Volume load failed.

          CT_HWERR 

          Hardware error occurred.

          CT_NOT_READY 

          Device is not ready.

          CT_BLKLEN 

          Actual recorded block size differs from the set size.

          The remaining ts_erreg statuses are undefined.

          mt_resid 

          Difference between what was requested and what has completed, in bytes or blocks depending on the command.

          mt_fileno 

          Not supported.

          mt_blkno 

          Block address (returned from the device).

          mt_partno 

          Partition number for those devices supporting partitions.

          mt_cblkno 

          Block number calculated by the driver. This value includes filemarks as well as blocks and becomes invalid if absolute positioning occurs.

          mt_lastreq 

          Last user request issued. The user request codes are defined in the /usr/include/sys/mtio.h file:

          Flag 

          Description

          MTR_READ 

          read(2) request

          MTR_WRITE 

          write(2) request

          MTR_WFM 

          Write filemark(s)

          MTR_SRB 

          Skip records backward

          MTR_SRF 

          Skip records forward

          MTR_SFB 

          Skip filemarks backwards

          MTR_SFF 

          Skip filemarks forward

          MTR_SEOD 

          Space to the end-of-data

          MTR_SEOM 

          Space to the end-of-media

          MTR_FORMAT 

          Volume format

          MTR_PART 

          Position to a partition

          MTR_SSM 

          Skip setmarks

          MTR_WSM 

          Write setmarks

          MTR_MODEAUD 

          Enable or disable audio mode

          MTR_REW 

          Rewind

          MTR_ERASE 

          Erase from current position to the EOT

          MTR_RETEN 

          Retention

          MTR_UNLOAD 

          Unload

          MTR_PABS 

          Position to an absolute address

          MTR_PAUDIO 

          Audio position

          MTR_GAUDIO 

          Get audio position

          MTR_RDLOG 

          Read log

          MTR_ATTR 

          Set attribute

          MTR_SPOS 

          Set vendor specific position

          MTR_GPOS 

          Get vendor specific position

          mt_ilimode 

          State of illegal length mode reporting for variable-block I/O. If mt_ilimode is set and a read(2) request is less than the size of the block on tape, an error is returned.

          mt_buffmode 

          State of filemark buffering. If mt_buffmode is set, filemarks are buffered.

          mt_subtype 

          Device type. Valid device types are defined in the /usr/include/sys/invent.h file beginning with the TPUNKNOWN value.

          mt_capability 

          Device capabilities. The capabilities are set of flags, the MTCAN* status flags, which are defined in the /usr/include/sys/mtio.h file.

          4.3.2.5. MTIOCGETEXTL

          The MTIOCGETEXTL ioctl request returns the last tape status. The argument to this request is a pointer to the mtgetext structure. The MTIOCGETEXTL ioctl request returns the same information as the MTIOCGETEXT ioctl request. It differs from the MTIOCGETEXT ioctl request in that it does not seek updated status information from the device.

          4.3.2.6. MTSCI_RDLOG

          The MTSCI_RDLOG ioctl request returns statistical information maintained by a device. The argument to this request is a pointer to the mtscsi_rdlog structure. The following values are set on the request:

          Field 

          Description

          mtppc 

          Parameter pointer control

          mtsp 

          Save parameters

          mtpc 

          Page control

          mtpage 

          Page code of the requested page

          mtparam 

          Parameter from which to begin transferring information

          mtlen 

          Size of the buffer to receive the device log

          mtarg 

          Pointer to a buffer to receive the device log

          For a more detailed explanation of the mtppc, mtsp, mtpage, and mtparam fields, see the device product manual for the device from which log information is required.

          4.3.2.7. MTSCISI_SENSE

          The MTSCISI_SENSE ioctl request returns the sense data from the last device command that terminated with a SCSI Check Condition or Command Terminated status. The argument to this request is a pointer to a buffer large enough to receive the sense data, at least MAX_SENSE_DATA bytes. MAX_SENSE_DATA is defined in the /usr/include/sys/tpsc.h file. For an explanation of the sense data, see the device product manual for the device from which the sense information is required.

          4.3.2.8. MTSCSIINQ

          The MTSCSIINQ ioctl request returns device parameter information, such as the vendor identification, product identification, and revision level. The argument to this request is a pointer to a buffer large enough to receive the inquiry information, at least as large as the ct_g0ing_data_t structure, defined in the /usr/include/sys/tpsc.h file. For an explanation of the inquiry data, see the device product manual for the device from which the device information is required.

          4.3.2.9. MTSPECOP

          The MTSPECOP ioctl request sets the block size for fixed-length I/O. You request fixed-length I/O with the -B option on the tmmnt(1) command. The argument to the MTSPECOP ioctl request is a pointer to the mtop structure. The mt_op field must be set to MTSCSI_SETFIXED and mt_count to the block size.