This chapter describes the ways in which you can 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:
Using FFIO
Using System Calls: read and write
Using System Calls: ioctl
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 MIPSpro 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 |
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.
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.
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 |
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.
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 |
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 );
} |
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.10).
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.
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 |
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.
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 |
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 );
} |
Information is available about end-of-file, end-of-data, and error 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.
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.
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.
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 for IRIX systems and /usr/include/tmf/mtio.h for Linux systems (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 (IRIX systems); /usr/include/tmf/mtio.h (Linux systems) | 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. |
The following ioctl(2) requests are defined in the tmfctl.h file:
Status ioctl(2) requests
TMF daemon request or reply ioctl (2) 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.
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
The following requests control positioning:
Rewind positioning
Block positioning
File positioning
Absolute positioning
Volume index positioning
Volume name 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);
} |
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);
} |
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);
} |
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_SGI 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);
} |
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);
}
} |
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);
} |
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.
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.
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);
} |
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);
} |
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:
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);
} |
TMF supports the tape ioctl(2) requests defined in the /usr/include/sys/mtio.h file for IRIX systems and the /usr/include/tmf/mtio.h file for Linux systems. This file does not involve tape movement or the setting of certain attributes that must be controlled by TMF. It supports the following 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 | |
| MTIOCGET_SGI | Returns tape status | |
| MTIOCGET | Returns Linux tape status | |
| MTIOCGETEXT | Returns extended 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 |
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 for IRIX systems and the /usr/include/tmf/mtio.h file for Linux systems.
On the reply, the mt_subtype field returns the device type. Valid device types are defined in the /usr/include/sys/invent.h file (IRIX systems) and the /usr/include/tmf/invent.h file (Linux systems) 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 for IRIX systems and the /usr/include/tmf/mtio.h file for Linux systems.
| Note: The Linux location for all of the .h files is in /usr/include/tmf, rather than in /usr/include/sys (which is the IRIX location). |
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 for IRIX systems and the /usr/include/tmf/mtio.h file for Linux systems.
| Note: The Linux location for all of the .h files is in /usr/include/tmf, rather than in /usr/include/sys (which is the IRIX location). |
The MTIOCGET_SGI ioctl request returns tape status. The argument to this request is a pointer to the mtget_sgi structure. The MTIOCGET_SGI 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 (IRIX systems) and the /usr/include/tmf/mtio.h file (Linux systems):
| ||||||||||||||||||||||||||||||||||||||||||||||||||||
| mt_dsreg | Last device status represented by a set of flags. The device status flags are in the /usr/include/sys/tpsc.h file (IRIX systems) and the /usr/include/tmf/tpsc.h file (Linux systems):
| ||||||||||||||||||||||||||||||||||||||||||||||||||||
| mt_erreg | Last device error status. The device status flags are in the /usr/include/sys/tpsc.h file (IRIX systems) and the /usr/include/tmf/tpsc.h file (Linux systems):
| ||||||||||||||||||||||||||||||||||||||||||||||||||||
| mt_resid | Residual count. This field contains the difference between what was requested and what has completed, in bytes, blocks, files, or records, depending on the command. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| mt_fileno | Not supported. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| mt_blkno | Block number (returned from the device). |
| Note: The Linux location for all of the .h files is in /usr/include/tmf, rather than in /usr/include/sys (which is the IRIX location). |
The MTIOCGET ioctl request returns tape status on Linux systems. The argument to this request is a pointer to the Linux mtget structure. The MTIOCGET ioctl returns the following values:
| Field | Description | |||||||||||||||||||||||||||||||||||||||||||
| mt_type | Controller type. This value is either MT_ISSCSI1 or MT_ISSCSI2. | |||||||||||||||||||||||||||||||||||||||||||
| mt_resid | Residual count. This field contains the difference between what was requested and what has completed, in bytes, blocks, files, or records, depending on the command. | |||||||||||||||||||||||||||||||||||||||||||
| mt_dsreg | Drive status register, containing block size and density status. | |||||||||||||||||||||||||||||||||||||||||||
| mt_gstat | Generic (device independent) status, represented by a set of flags defined in the /usr/include/linux/mtio.h file, as follows:
| |||||||||||||||||||||||||||||||||||||||||||
| mt_erreg | Error register. Contains the last device error status. | |||||||||||||||||||||||||||||||||||||||||||
| mt_fileno | File number. Contains the number of the current file on the tape. | |||||||||||||||||||||||||||||||||||||||||||
| mt_blkno | Block number. Contains the number of the current block on the tape. |
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 (IRIX systems) and the /usr/include/tmf/mtio.h file (Linux systems). 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 (IRIX systems) and the /usr/include/tmf/tpsc.h file (Linux systems). 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 (IRIX systems) and the /usr/include/tmf/tpsc.h file (Linux systems). The ts_erreg[0] error status is represented by the upper 16 bits of the following status flags:
The ts_erreg[1] error status is represented by the status following flags:
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 (IRIX systems) and the /usr/include/tmf/mtio.h file (Linux systems):
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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 (IRIX systems) and the /usr/include/tmf/invent.h file (Linux systems) 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 (IRIX systems) and the /usr/include/tmf/mtio.h file (Linux systems). |
| Note: The Linux location for all of the .h files is in /usr/include/tmf, rather than in /usr/include/sys (which is the IRIX location). |
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.
| Note: The Linux location for all of the .h files is in /usr/include/tmf, rather than in /usr/include/sys (which is the IRIX location). |
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.
| Note: The Linux location for all of the .h files is in /usr/include/tmf, rather than in /usr/include/sys (which is the IRIX location). |
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 (IRIX systems) and the /usr/include/tmf/tpsc.h file (Linux systems). For an explanation of the sense data, see the device product manual for the device from which the sense information is required.
| Note: The Linux location for all of the .h files is in /usr/include/tmf, rather than in /usr/include/sys (which is the IRIX location). |
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 (IRIX systems) and the /usr/include/tmf/tpsc.h file (Linux systems). For an explanation of the inquiry data, see the device product manual for the device from which the device information is required.
| Note: The Linux location for all of the .h files is in /usr/include/tmf, rather than in /usr/include/sys (which is the IRIX location). |
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.
| Note: The Linux location for all of the .h files is in /usr/include/tmf, rather than in /usr/include/sys (which is the IRIX location). |