IBM Tape Driver PROFREF
IBM Tape Driver PROFREF
Programming Reference
GA32-0566-08
IBM Tape Device Drivers
Programming Reference
GA32-0566-08
Note!
Before using this information and the product that it supports, be sure to read the general information under "Notices".
Notices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383
Contents v
vi IBM Tape Device Drivers: Programming Reference
Preface
This publication provides programming reference information for IBM® Ultrium,
TotalStorage, and System Storage® tape drives, medium changers, and library
device drivers.
Note: When the page range is selected for the section you want to print, note that
the print page range is based on the page controls for Adobe Acrobat, not
the page that is printed on the actual document. Enter the Adobe page
numbers to print.
If you want to print one or more separate sections of the manual, follow these
steps.
1. Navigate to the beginning of the section and note the page number.
2. Navigate to the last page in the section and note that page number.
3. Select File > Print, then choose "Pages" and enter the page range for the section.
Only the page range that is entered prints.
4. Repeat these steps to print extra sections.
Related information
Reference material, including the Adobe pdf version of this publication, is available
at:
http://www-01.ibm.com/support/docview.wss?uid=ssg1S7003032.
IBM Tape Device Drivers: Installation and Users Guide, GC27-2130-00, at:
http://www-01.ibm.com/support/docview.wss?uid=ssg1S7002972
AIX
The following URL points to information about IBM System p® (also known
asERserver pSeries) servers:
http://www-1.ibm.com/servers/eserver/pseries
HP-UX
The following URL relates to HP HP-UX systems:
http://www.hp.com
Linux
The following URLs relate to Linux distributions:
http://www.redhat.com
http://www.suse.com
Solaris
The following URL relates to Oracle Solaris systems:
http://www.oracle.com/us/sun/index.htm
Microsoft Windows
The following URL relates to Microsoft Windows systems:
http://www.microsoft.com
Additional information
The following publication contains extra information that is related to the IBM tape
drive, medium changer, and library device drivers:
v American National Standards Institute Small Computer System Interface
X3T9.2/86-109 X3.180, X3B5/91-173C, X3B5/91-305, X3.131-199X Revision 10H,
and X3T9.9/91-11 Revision 1
Media partitioning
There are two types of partitioning: Wrap-wise partitioning (used on TS2250,
TS2260, TS2350, TS2360, and TS1140) and Longitudinal partitioning (maximum 2
partitions) used only on TS1140.
Partition 0
Guard wraps
Partition 1
Partition 2
a2500283
Partition 3
Partition 0 Partition 1
a2500284
Figure 2. Longitudinal partitioning
The ioctls the device drivers provide for tape partitioning are
v Query Partition
The Query Partition ioctl returns the partition information for the current media in
the tape drive. It also returns the current active partition the tape drive is using for
the media.
Note: If the Create Partition ioctl fails, then the Query Partition ioctl does not
return the correct partition information. To get the correct information, the
application must unload and reload the tape again.
v Create Partition
The Create Partition ioctl is used to format the current media in the tape driver to
either 1 or 2 partitions. When two partitions are created, the FDP, SDP, or IDP
partition type is specified by the application. The tape must be positioned at the
beginning of tape (partition 0 logical block id 0) before this ioctl is used or the ioctl
fails.
If the number_of_partitions field to create in the ioctl structure is one partition, all
other fields are ignored and not used. The tape drive formats the media by using
its default partitioning type and size for a single partition.
When the type field in the ioctl structure is set to either FDP or SDP, the size_unit
and size fields in the ioctl structure are not used. When the type field in the ioctl
structure is set to IDP, the size_unit and size fields are used to specify the size for
each partition. One of the two partition sizes for either partition 0 or 1 must be
specified as 0xFFFF to use the remaining capacity. The other partition is created by
using the size_unit and size field for the partition.
v Set Active Partition
The Set Active Partition ioctl is used to position the tape drive to a specific
partition. It becomes the current active partition for subsequent commands and a
specific logical bock id in the partition. To position to the beginning of the
partition, the logical_block_id field in the ioctl structure must be set to 0.
Conditions exist when the drive is in data safe mode an application might want to
explicitly overwrite previously written data by issuing a write, write filemark, or
erase command. These commands are referred to as write type commands. An
application might also want to explicitly partition the tape with the Create
Partition ioctl that issues a format command. The drive supports a new Allow Data
Overwrite SCSI command for this purpose.
The ioctls the device drivers provide for data safe mode are
v Querying and setting data safe mode
All platform device drivers except Windows added a data safe mode parameter to
existing ioctls that are used to query or set tape drive parameters. The Windows
device driver added two new ioctls to query or set data safe mode.
A query ioctl returns the current drive mode, either data safe mode off (normal
mode) or data safe mode on. A set ioctl sets the drive to either data safe mode off
(normal mode) or data safe mode on. Data safe mode can be set whether a tape is
loaded in the drive or not. Data safe mode can be set back to normal mode only
when a tape is not currently loaded in the drive.
v Allow Data Overwrite
The Allow Data Overwrite ioctl is used to allow previously written data on the
tape to be overwritten when data safe mode is enabled on the drive, for a
subsequent write type command, or to allow a format command with the Create
Partition ioctl.
To allow a subsequent write type command, the tape position where the overwrite
occurs must be in the wanted partition and logical block id within the partition
before this ioctl is used. The partition_number and logical_block_id fields in the
ioctl structure must be set to that partition and logical block id. The
allow_format_overwrite field in the ioctl structure must be set to 0.
LTO 5 and later also supports the Locate(16) command that uses 8-byte fields.
This command can either position the tape to a logical block id or a logical
filemark by setting the dest_type field in the Locate(16) SCSI CDB. After the locate
command completes, the tape is positioned at the BOP side of the tape.
The Set Tape Position ioctl issues a Locate(16) command to position the tape in
the current active partition to either a logical block id or logical filemark. The
logical_id_type field in the ioctl structure specifies either a logical block or logical
filemark.
Verify Tape
The ioctl of VERIFY_DATA_TAPE issues the VERIFY command to cause data to be
read from the tape and passed through the drive’s error detection and correction
hardware. This action determines whether data can be recovered from the tape.
Also, whether the protection information is present and validates correctly on
logical block on the medium. The driver returns a failure or success signal if the
VERIFY SCSI command is completed in a Good SCSI status. The Verify command
is supported on all LTO libraries. Verify to EOD (ETD) or verify by filemark (VBF)
is supported on drives that support Logical Block Protection (LBP).
| An application uses the GRAO command to request that the drive generate a
| recommended access order for the User Data Segments that are sent in this
| command. After a GRAO command completes, use the RRAO command to receive the
| results.
| The IOCTL queries the maximum number and size of User Data Segments (UDS)
| that are supported from tape drive and driver for the wanted uds_type. The
| application calls this IOCTL before the GENERATE_RAO and RECEIVE_RAO IOCTLs are
| issued. The return in this IOCTL is to be used by the application to limit the
| number of UDS requested in calls to the GENERATE_RAO IOCTL.
| /* Define for uds_type */
| #define UDS_WITHOUT_GEOMETRY 0
| #define UDS_WITH_GEOMETRY 1
|
| typedef unsigned long long ullong;
|
|
| struct query_rao_info {
| char uds_type; /* [IN] 0: UDS_WITHOUT_GEOMETRY */
| /* 1: UDS_WITH_GEOMETRY */
| char reserved[7];
| ushort max_uds_number; /* [OUT] Max UDS number supported from drive */
| ushort max_uds_size; /* [OUT] Max single UDS size supported from */
| /* drive \in byte */
| ushort max_host_uds_number; /* [OUT] Max UDS number supported from driver */
| }
| GENERATE_RAO
| The IOCTL is called to send a GRAO list to request the drive to generate a
| Recommending Access Order list. The process method is either 1 or 2 to create a
| RAO list, and the type of UDS is either with or without the geometry. The
| uds_number must be not larger than max_host_uds_number in the
| QUERY_RAO_INFO IOCTL. The application allocates a memory with grao_list_leng
| (uds_number * sizeof(struct grao_uds_desc) +8) for the pointer of grao_list.
| struct generate_rao {
| char process; /* [IN] Requested process to generate RAO list */
| /* 0: no reorder UDS and no calculate */
| /* locate time */
| /* (not currently supported by the drive) */
| /* 1: no reorder UDS but calculate locate time */
| /* 2: reorder UDS and calculate locate time */
| char uds_type; /* [IN] 0: UDS_WITHOUT_GEOMETRY */
| /* 1: UDS_WITH_GEOMETRY */
| char reserved1[2];
| uint grao_list_leng; /* [IN] The data length is allocated for GRAO*/
| /* list. */
| char *grao_list; /* [IN] The pointer is allocated to the size */
| /* of grao_list_leng */
| /* (uds_number * sizeof(struct grao_uds_desc) */
| /* + sizeof(struct grao_list_header)) */
| /* and contains the data of GRAO parameter */
| /* list. The uds number isn’t larger than */
| /* max_host_uds_number in QUERY_RAO ioctl. */
| char reserved2[8];
| }
| RECEIVE_RAO
| The grao list, for the generate_rao structure, is in the following format when lists
| are setn or received. The structures for the headers and UDS segments are not
| provided by the device driver but is the responsibility of the calling application.
| -- List Header
| -- UDS Segment Descriptor (first)
| ......
| -- UDS Segment Descriptor (last)
| CAUTION:
| When the rrao_list_leng and grao_list_leng is sent, if the length value does
| not match the memory allocated there can be overflow issues.
|
The standard set of AIX device management commands is available. The chdev,
rmdev, mkdev, and lsdev commands are used to bring the device online or change
the attributes that determine the status of the tape device.
The standard set of AIX device management commands is available. The chdev,
rmdev, mkdev, and lsdev commands are used to bring the device online or change
the attributes that determine the status of the tape system robotic device.
Note:
1. The Rewind on Close special files for the Ultrium tape drives write
filemarks under certain conditions before rewinding. See “Opening the
special file for I/O” on page 12.
2. The Retension on Open special files rewind the tape on open only.
Retensioning is not completed because these tape products run the
retension operation automatically when needed.
3. The Bytes per Inch options are ignored for the tape devices that this
driver supports. The density selection is automatic.
4. The rmt*.10 file bypasses normal close processing, and the tape is left at
the current position.
5. The rmt*.null file is a pseudo device similar to the /dev/null AIX special
file. The IOCTL calls can be issued to this file without a real device that
is attached to it, and the device driver returns a successful completion.
For tape drives with attached SCSI medium changer devices, the rmt*.smc special
file provides a separate path for issuing commands to the medium changer. When
this special file is opened, the application can view the medium changer as a
separate SCSI device.
This special file and the rmt* special file can be opened at the same time. The file
descriptor that results from opening the rmt*.smc special file does not support the
following operations.
v Read
v Write
v Open in diagnostic mode
v Commands that are designed for a tape device
If a tape drive has an attached SCSI medium changer device, all operations
(including the medium changer operations) are supported through the interface to
the rmt* special file.
Table 2 shows the attributes of the special file. The asterisk (*) represents a number
that is assigned to a particular device (such as smc0). The term smc is used for a
SCSI medium changer device. The smc* special file provides a path for issuing
commands to control the medium changer robotic device.
Table 2. Special files
Special file name Description
/dev/smc* Access to the medium changer robotic device
/dev/smc*.null Pseudo medium changer device
Note: The smc*.null file is a pseudo device similar to the /dev/null AIX special
file. The commands can be issued to this file without a real device that is
attached to it, and the device driver returns a successful completion. This
file can be used for application development or debugging problems.
The file descriptor that results from opening the smc special file does not support
the following operations.
v Read
v Write
v Commands that are designed for a tape device
Note: This flag cannot be used with the Retension on Open special files, such
as rmx.2.
If the open system call fails, the errno value contains the error code. See “Return
codes” on page 94 for a description of the errno values.
The O_FLAGS parameter provides the same options that are described in “Opening
the special file for I/O.” The third parameter is always NULL. The E_FLAGS
parameter provides the extended options. The E_FLAGS values can be combined
during an open operation or they can be used with an OR operation.
If the open system call fails, the errno value contains the error code. See “Return
codes” on page 94 for a description of the errno values.
The write operation returns the number of bytes written during the operation. It
can be less than the value in numbytes. If the block size is fixed (block_size≠0), the
numbytes value must be a multiple of the block size. If the block size is variable,
the value that is specified in numbytes is written. If the count is less than zero, the
errno value contains the error code that is returned from the driver.
The writev, writex, and writevx subroutines are also supported. Any values that
are passed in the ext field with the extended write operation are ignored.
The read operation returns the number of bytes read during the operation. It can
be less than the value in numbytes. If the block size is fixed (block_size≠0), the
numbytes value must be a multiple of the block size. If the count is less than zero,
the errno value contains the error code that is returned from the driver.
If the block size is variable, then the value that is specified in numbytes is read. If
the blocks read are smaller than requested, the block is returned up to the
maximum size of one block. If the blocks read are greater than requested, an error
occurs with the error set to ENOMEM.
Reading a filemark returns a value of zero and positions the tape after the
filemark. Continuous reading (after EOM is reached) results in a value of zero and
no further change in the tape position.
Use this parameter with the readx or readvx subroutine that specifies the
TAPE_READ_REVERSE extended parameter.
count=readx(tapefd, buffer, numbytes, TAPE_READ_REVERSE);
The return code from the close operation must be checked by the application. If
the return code is not zero, the errno value is set during a close operation to
indicate that a problem occurred while the special file was closing. The close
subroutine tries to run as many operations as possible even if there are failures
during portions of the close operation. If the device driver cannot terminate the
file correctly with filemarks, it tries to close the connection. If the close operation
fails, consider the device closed and try another open operation to continue
processing the tape. After a close failure, assume that either the data or the tape is
inconsistent.
For tape drives, the result of a close operation depends on the special file that was
used during the open operation and the tape operation that was run while it was
opened. The SCSI commands are issued according to the following logic.
If the last tape operation was a WRITE command
Write 2 filemarks on tape
If special file is Rewind on Close (Example: /dev/rmt0)
Rewind tape
If special file is a No-Rewind on Close (Example: /dev/rmt0.1)
Backward space 1 filemark (tape is positioned to append next file)
If the last tape operation was NOT a READ, WRITE, or WRITE FILEMARK command
This process is separate from error logging. Error logging is routed to the system
error log. Device information logging is sent to a separate file.
See the IBM TotalStorage and System Storage Tape Device Drivers: Installation and
User’s Guide for a description of these parameters.
Log file
The data is logged in the /usr/adm/ras directory. The file name is dependent on
each device so each device has a separate log. An example of the rmt1 device file
is
/usr/adm/ras/Atape.rmt1.log
The files are in binary format. Each entry has a header followed by the raw Log
Sense pages as defined for a particular device.
The first log page is always page 0x00. This page, as defined in the SCSI-2 ANSI
specification, contains all the pages that are supported by the device. Page 0x00 is
followed by all the pages that are specified in page 0x00. The format of each
following page is defined in the SCSI specification and the device manual.
The format of the file is defined by the data structure. The logfile_header is
followed by max_log_size (or a fewer number of entries for each file). The
log_record_header is followed by a log entry.
logfile_header
log_record_header
log_record_entry
v
v
v
v
log_record_header
log_record_entry
Each log_record_entry contains multiple log sense pages. The log pages are placed
in order one after another. Each log page contains a header followed by the page
contents.
The reserve type attribute determines the type of reservation that the device driver
uses for the device. The values can be reserve_6, which is the default for the
device driver or persistent. This attribute can be set by either using the AIX SMIT
menu to Change/Show Characteristics of a Tape Drive or from a command line
with the AIX command
chdev –l rmtx –a reserve_type=persistent or –a reserve_type=reserve_6
The key value can be specified as a 1-8 character ASCII alphanumeric key or a 1-16
hexadecimal key that has the format 0xkey. If fewer than 8 characters are used for
an ASCII key such as hostA, the remaining characters are set to 0x00 (NULL).
Note: If the Data Path Failover (DPF) feature is enabled for a logical device by
setting the alternate_pathing attribute to yes, the configuration reserve_type
attribute is not used and the device driver uses persistent reservation. Either
the user-defined reserve_key value or if not defined the default device
driver host reservation key is used.
Note: This parameter must be used only when the application or user is sure that
the reservation must be cleared.
The SC_PASSTHRU parameter bypasses all commands that are normally issued on
open and close by the device driver. In addition to bypassing the device driver that
reserves on open and releases the device on close, all other open commands except
test unit ready such as mode selects and rewind on close (if applicable) are also
bypassed. A test unit ready is still issued on open to clear any pending unit
attentions from the device. This is the only difference in using the SC_DIAGNOSTIC
parameter.
The SC_DIAGNOSTIC parameter bypasses all commands that are normally issued on
open and close by the device driver. In addition to bypassing the device driver that
reserves on open and releases the device on close, all other open commands such
test unit ready, mode selects, and rewind on close (if applicable) are also bypassed.
The SC_NO_RESERVE parameter bypasses the device driver that issues a reserve on
open only. All other normal open device driver commands are still issued such as
test unit ready and mode selects.
The following two IOCTLs return Persistent Reserve information by using the
SCSI Persistent Reserve In command.
v STPRES_READKEYS
v STPRES_READRES
The following four IOCTLs complete Persistent Reserve functions by using the
SCSI Persistent Reserve Out command.
v STPRES_CLEAR
v STPRES_PREEMPT
v STPRES_PREEMPT_ABORT
v STPRES_REGISTER
The STPRES_READKEYS IOCTL issues the persistent reserve in command with the
read keys service action. The following structure is the argument for this IOCTL.
struct st_pres_in {
ushort version;
ushort allocation_length;
uint generation;
ushort returned_length;
uchar scsi_status;
uchar sense_key;
uchar scsi_asc;
uchar scsi_ascq;
uchar *reservation_info;
}
The allocation_length is the maximum number of bytes of key values that are
returned in the reservation_info buffer. The returned_length value indicates how
many bytes of key values that device reported in the parameter data. Also, it
shows the list of key values that are returned by the device up to
allocation_length bytes. If the returned_length is greater than the
allocation_length, then the application did not provide an allocation_length
large enough for all of the keys the device registered. The device driver does not
consider it an error.
The SYPRES_READRES IOCTL issues the persistent reserve in command with the
read reservations service action. The STPRES_READRES IOCTL uses the same
following IOCTL structure as the STPRES_READKEYS IOCTL.
struct st_pres_in {
ushort version;
ushort allocation_length;
uint generation;
ushort returned_length;
uchar scsi_status;
uchar sense_key;
uchar scsi_asc;
uchar scsi_ascq;
uchar *reservation_info;
}
The STPRES_CLEAR IOCTL issues the persistent reserve out command with the
clear service action. The following structure is the argument for this IOCTL.
struct st_pres_clear {
ushort version;
uchar scsi_status;
The STPRES_PREEMPT IOCTL issues the persistent reserve out command with the
preempt service action. The following structure is the argument for this IOCTL.
struct st_pres_preempt {
ushort version;
unsigned long long preempt_key;
uchar scsi_status;
uchar sense_key;
uchar scsi_asc;
uchar scsi_ascq;
}
The STPRES_REGISTER IOCTL issues the persistent reserve out command with the
register service action. The following structure is the argument for this IOCTL.
Chapter 2. AIX tape and medium changer device driver 21
struct st_pres_register {
ushort version;
uchar scsi_status;
uchar sense_key;
uchar scsi_asc;
uchar scsi_ascq;
}
If a persistent reserve IOCTL fails, the return code is set to -1 and the errno value
is set to one of the following.
v ENOMEM Device driver cannot obtain memory to run the command.
v EFAULT An error occurred while the caller's data buffer was manipulated
v EACCES The device is opened with a reserve_type set to reserve_6
v EINVAL The requested IOCTL is not supported by this version of the device
driver or invalid parameter that is provided in the argument structure
v ENXIO The device indicated that the persistent reserve command is not
supported
v EBUSY The device returned a SCSI status byte of RESERVATION CONFLICT
or BUSY. Or, the reservation for the device was preempted by another host and
the device driver does not issue further commands.
v EIO Unknown I/O failure occurred on the command
The following IOCTLs return Persistent Reserve information by using the SCSI
Persistent Reserve In command.
v STIOC_READ_RESERVEKEYS
v STIOC_READ_RESERVATIONS
v STIOC_READ_RESERVE_FULL_STATUS
The following IOCTLs complete Persistent Reserve functions by using the SCSI
Persistent Reserve Out command.
v STIOC_REGISTER_KEY
v STIOC_REMOVE_REGISTRATION
v STIOC_CLEAR_ALL_REGISTRATIONS
v STIOC_PREEMPT_RESERVATION
v STIOC_PREEMPT_ABORT
v STIOC_CREATE_PERSISTENT_RESERVE
The following IOCTLs are modified to handle both SCSI-2 Reserve 6 and
Persistent Reserve based on the current reserve_type setting.
The STIOC_READ_RESERVEKEYS IOCTL returns the reservation keys from the device.
The argument for this IOCTL is the address of a read_keys structure. If the
reserve_key_list pointer is NULL, then only the generation and length fields are
returned. This action allows an application to first obtain the length of the
reserve_key_list and malloc a return buffer before the IOCTL is issued with a
reserve_key_list pointer to that buffer. If the return length is 0, then no reservation
keys are registered with the device.
struct read_reserves
{
uint generation; /* counter for PERSISTENT RESERVE OUT requests */
uint length; /* number of bytes in the Reservation list */
struct reserve_descriptor* reserve_list; /* list of reservation key descriptors */
};
struct fcp_transport_id
{
uint format_code:2,
rsvd:2,
protocol_id:4;
char reserved1[7];
ullong n_port_name;
char reserved2[8];
};
struct scsi_transport_id
{
uint format_code:2,
rsvd:2,
protocol_id:4;
char reserved1[1];
ushort scsi_address;
ushort obsolete;
ushort target_port_id;
char reserved2[16];
};
struct sas_transport_id
{
uint format_code:2,
rsvd:2,
protocol_id:4;
char reserved1[3];
ullong sas_address;
char reserved2[12];
};
struct status_descriptor
{
ullong key; /* reservation key */
char reserved1[4];
uint rsvd:5,
spc2_r:1, /* future use for SCSI-2 reserve */
all_tg_pt:1, /* all target ports */
r_holder:1; /* reservation holder */
uint scope:4, /* persistent reservation scope */
type:4; /* reservation type */
char reserved2[4];
ushort target_port_id; /* relative target port id */
uint descriptor_length; /* additional descriptor length */
union {
struct transport_id transport_id; /* transport ID */
struct fcp_transport_id fcp_id; /* FCP transport ID */
struct sas_transport_id sas_id; /* SAS transport ID */
struct scsi_transport_id scsi_id; /* SCSI transport ID */
};
};
struct read_full_status
{
uint generation; /* counter for PERSISTENT RESERVE OUT requests */
uint length; /* number of bytes for total status descriptors */
struct status_descriptor *status_list; /* list of reserve status descriptors */
};
The STIOC_REGISTER_KEY IOCTL registers a host reservation key on the device. The
argument for this IOCTL is the address of an unsigned long key that can be 1 - 16
If the host has a current persistent reservation on the device and the key is
different from the current reservation key, the reservation is retained and the host
reservation key is changed to the new key.
If a persistent reserve IOCTL fails, the return code is set to -1 and the errno value
is set to one of the following.
v ENOMEM Device driver cannot obtain memory to complete the command.
v EFAULT An error occurred while the caller's data buffer was manipulated
v EACCES The current open is using a reserve_type set to reserve_6
Overview
The following IOCTL commands are supported.
IOCINFO
Return device information.
STIOCMD
Issue the AIX Pass-through command.
STPASSTHRU
Issue the AIX Pass-through command.
SIOC_PASSTHRU_COMMAND
Issue the Atape Pass-through command.
SIOC_INQUIRY
Return inquiry data.
SIOC_REQSENSE
Return sense data.
SIOC_RESERVE
Reserve the device.
SIOC_RELEASE
Release the device.
SIOC_TEST_UNIT_READY
Issue a SCSI Test Unit Ready command.
SIOC_LOG_SENSE_PAGE
Return log sense data for a specific page.
SIOC_LOG_SENSE10_PAGE
Return log sense data for a specific page and Subpage.
SIOC_MODE_SENSE_PAGE
Return mode sense data for a specific page.
SIOC_MODE_SENSE_SUBPAGE
Return mode sense data for a specific page and subpage.
These IOCTL commands and their associated structures are defined by including
the /usr/include/sys/Atape.h header file in the C program by using the functions.
IOCINFO
This IOCTL command provides access to information about the tape or medium
changer device. It is a standard AIX IOCTL function.
An example of the output data structure for a tape drive rmt* special file is
info.devtype=DD_SCTAPE
info.devsubtype=ATAPE_3590
info.un.scmt.type=DT_STREAM
info.un.scmt.blksize=tape block size (0=variable)
An example of the output data structure for an independent medium changer smc*
special file is
info.devtype=DD_MEDIUM_CHANGER;
info.devsubtype=ATAPE_7337;
See the Atape.h header file for the defined devsubstype values.
STIOCMD
This IOCTL command issues the SCSI Pass-through command. It is used by the
diagnostic and service aid routines. The structure for this command is in the
/usr/include/sys/scsi.h file.
This IOCTL is supported on both SCSI adapter attached devices and FCP adapter
attached devices. For FCP adapter devices, the returned adapter_status field is
converted from the FCP codes that are defined in /usr/include/sys/scsi_buf.h to the
SCSI codes defined in /usr/include/sys/scsi.h, if possible. This action is to provide
downward compatibility with existing applications that use the STIOCMD IOCTL for
SCSI attached devices.
Note: There is no interaction by the device driver with this command. The error
handling and logging functions are disabled. If the command results in a
check condition, the application must issue a Request Sense command to
clear any contingent allegiance with the device.
/* issue inquiry */
sciocmd.scsi_cdb[0]=0x12;
sciocmd.timeout_value=200; /* SECONDS */
sciocmd.command_length=6;
sciocmd.buffer=(char *)&inqdata;
sciocmd.data_length=sizeof(struct inquiry_data);
sciocmd.scsi_cdb[4]=sizeof(struct inquiry_data);
sciocmd.flags=B_READ;
STPASSTHRU
This IOCTL command issues the AIX Pass-through command that is supported by
base AIX tape device drivers. The IOCTL command and structure are defined in
the header files /usr/include/sys/scsi.h and /usr/include/sys/tape.h. Refer to AIX
documentation for information about using the command.
SIOC_PASSTHRU_COMMAND
This IOCTL command issues the Atape device driver Pass-through command. The
data structure that is used on this IOCTL is
struct scsi_passthru_cmd {
uchar command_length; /* Length of SCSI command 6, 10, 12 or 16 */
uchar scsi_cdb[16]; /* SCSI command descriptor block */
uint timeout_value; /* Timeout in seconds or 0 for command default */
uint buffer_length; /* Length of data buffer or 0 */
char *buffer; /* Pointer to data buffer or NULL */
uint number_bytes; /* Number of bytes transfered to/from buffer */
uchar sense_length; /* Number of valid sense bytes */
uchar sense[MAXSENSE]; /* Sense data when sense length > 0 */
uint trace_length; /* Number bytes in buffer to trace, 0 for none */
char read_data_command; /* Input flag, set it to 1 for read type cmds */
char reserved[27];
};
The arg parameter for the IOCTL is the address of a scsi_passthru_cmd structure.
The device driver issues the SCSI command by using the command_length and
scsi_cdb fields. If the command receives data from the device (such as SCSI
Inquiry), then the application must also set the buffer_length and buffer pointer
for the return data along with the read_data_command set to 1. For commands
that send data to the device (such as SCSI Mode Select), the buffer_length and
pointer is set for the send data and the read_data_command set to 0. If the
command has no data transfer, the buffer length is set to 0 and buffer pointer that
is set to NULL.
The specified timeout_value field is used if not 0. If 0, then the device driver
assigns its internal timeout value that is based on the SCSI command.
The trace_length field is normally used only for debug. It specifies the number of
bytes on a data transfer type command that is traced when the AIX Atape device
driver trace is running.
If the SCSI command fails, then the IOCTL returns -1 and errno value is set for the
failing command. If the device returned sense data for the failure, then the
sense_length is set to the number of sense bytes returned in the sense field. If
there was no sense data for the failure, the sense_length is 0.
If the SCSI command transfers data either to or from the device, then the
number_bytes fields indicate how many bytes were transferred.
SIOC_REQSENSE
This IOCTL command returns the device sense data. If the last command resulted
in an input/output error (EIO), the sense data is returned for the error. Otherwise,
a new sense command is issued to the device.
SIOC_RESERVE
This IOCTL command reserves the device to the device driver. The specific SCSI
command that is issued to the device depends on the current reservation type that
is used by the device driver, either a SCSI Reserve or Persistent Reserve.
SIOC_TEST_UNIT_READY
This IOCTL command issues the SCSI Test Unit Ready command to the device.
SIOC_LOG_SENSE_PAGE
This IOCTL command returns a log sense page from the device. The page is
selected by specifying the page_code in the log_sense_page structure. Optionally, a
specific parm pointer, also known as a parm code, and the number of parameter
bytes can be specified with the command.
To obtain the entire log page, the len and parm_pointer fields are set to zero. To
obtain the entire log page that starts at a specific parameter code, set the
parm_pointer field to the wanted code and the len field to zero. To obtain a
specific number of parameter bytes, set the parm_pointer field to the wanted code.
Then, set the len field to the number of parameter bytes plus the size of the log
page header (4 bytes). The first 4 bytes of returned data are always the log page
header.
See the appropriate device manual to determine the supported log pages and
content.
SIOC_LOG_SENSE10_PAGE
This IOCTL command is enhanced to add a subpage variable from
SIOC_LOG_SENSE_PAGE. It returns a log sense page or subpage from the device. The
page is selected by specifying the page_code or subpage_code in the
log_sense10_page structure. Optionally, a specific parm pointer, also known as a
parm code, and the number of parameter bytes can be specified with the
command.
To obtain the entire log page, the len and parm_pointer fields are set to zero. To
obtain the entire log page that starts at a specific parameter code, set the
parm_pointer field to the wanted code and the len field to zero. To obtain a
specific number of parameter bytes, set the parm_pointer field to the wanted code.
Then, set the len field to the number of parameter bytes plus the size of the log
logdata10.page_code = page;
logdata10.subpage_code = subpage;
logdata10.len = len;
logdata10.parm_pointer = parm;
page_header = (struct log_page_header *)logdata10.data;
SIOC_MODE_SENSE_PAGE
This IOCTL command returns a mode sense page from the device. The page is
selected by specifying the page_code in the mode_sense_page structure.
See the appropriate device manual to determine the supported mode pages and
content.
SIOC_MODE_SENSE_SUBPAGE
This IOCTL command returns the whole mode sense data, including header, block
descriptor, and page code for a specific page or subpage from the device. The
wanted page or subpage is inputted by specifying the page_code and
subpage_code in the mode_sense structure.
SIOC_MODE_SELECT_PAGE
This IOCTL command sets device parameters in a specific mode page. The wanted
page is selected by specifying the page_code in the mode_sense_page structure.
See the appropriate device manual to determine the supported mode pages and
parameters that can be modified. The arg parameter for the IOCTL is the address
of a mode_sense_page structure.
This data structure is also used for the SIOC_MODE_SENSE_PAGE IOCTL. The
application must issue the SIOC_MODE_SENSE_PAGE IOCTL, and modify the wanted
bytes in the returned mode_sense_page structure data field. Then, it issues this
IOCTL with the modified fields in the structure.
SIOC_MODE_SELECT_SUBPAGE
This IOCTL command sets device parameters in a specific mode page and
subpage. The wanted page and subpage are selected by specifying the page_code
and subpage_page in the mode_sense_subpage structure. See the appropriate
device manual to determine the supported mode pages, subpages, and parameters
that can be modified. The arg parameter for the IOCTL is the address of a
mode_sense_subpage structure.
This data structure is also used for the SIOC_MODE_SENSE_SUBPAGE IOCTL. The
application must issue the SIOC_MODE_SENSE_SUBPAGE IOCTL, and modify the
wanted bytes in the returned mode_sense_subpage structure data field. Then, it
issues this IOCTL with the modified fields in the structure. If the device supports
setting the sp bit for the mode page to 1, then the sp_bit field can be set to 0 or 1.
If the device does not support the sp bit, then the sp_bit field must be set to 0.
SIOC_QUERY_OPEN
This IOCTL command returns the ID of the process that currently has a device
open. There is no associated data structure. The arg parameter specifies the
address of an int for the return process ID.
If the application opened the device by using the extended open parameter
SC_TMCP, the process ID is returned for any other process that has the device
return errno;
}
SIOC_INQUIRY_PAGE
This IOCTL command returns an inquiry page from the device. The page is
selected by specifying the page_code in the inquiry_page structure.
See the appropriate device manual to determine the supported inquiry pages and
content.
SIOC_DISABLE_PATH
This IOCTL command manually disables (fences) the device driver from using
either the primary or an alternate SCSI path to a device until the SIOC_ENABLE_PATH
command is issued for the same path that is manually disabled. The arg parameter
on the IOCTL command specifies the path to be disabled. The primary path is path
This IOCTL command is valid only if the device has one or more alternate paths
configured. Otherwise, the IOCTL command fails with errno set to EINVAL. The
SIOC_DEVICE_PATHS IOCTL command can be used to determine the paths that are
enabled or manually disabled.
SIOC_ENABLE_PATH
This IOCTL command enables a manually disabled (fenced) path to a device that is
disabled by SIOC_DISABLE_PATH IOCTL. The arg parameter on the IOCTL command
specifies the path to be enabled. The primary path is path 1, the first alternate path
2, the second alternate path 3, and so on. This command can be used concurrently
when the device is already open by another process by using the openx() extended
parameter SC_TMCP.
The SIOC_DEVICE_PATHS IOCTL command can be used to determine the paths that
are enabled or manually disabled.
SIOC_SET_PATH
This IOCTL command explicitly sets the current path to a device that the device
driver uses. The arg parameter on the IOCTL command specifies the path to be set
to the current path. The primary path is path 1, the first alternate path 2, the
second alternate path 3, and so on. This command can be used concurrently when
the device is already open by another process by using the openx() extended
parameter SC_TMCP.
SIOC_DEVICE_PATHS
This IOCTL command returns a device_paths structure. The number of paths are
configured to a device and a device_path_t path structure for each configured
path. The device, HBA, and path information for the primary path are configured
along with all alternate SCSI paths. This IOCTL command must be used instead of
the SIOC_QUERY_PATH IOCTL that is obsolete. This command can be used
concurrently when the device is already open by another process by using the
openx() extended parameter SC_TMCP.
struct device_paths {
int number_paths; /* number of paths configured */
struct device_path_t path[MAX_SCSI_PATH];
};
The arg parameter for the IOCTL is the address of a device_paths structure.
The current_path in the return structures is set to the current path the device uses
for the device. If this IOCTL is issued to a medium changer smc logical driver, the
cpname has the logical rmt name that is the control path drive for each smc logical
path.
SIOC_QUERY_PATH
This IOCTL command returns information about the device and SCSI paths, such
as logical parent, SCSI IDs, and status of the SCSI paths.
Note: This IOCTL is obsolete but still supported. The SIOC_DEVICE_PATHS IOCTL
must be used instead.
int sioc_query_path(void)
{
struct scsi_path path;
return errno;
}
printf("\n");
if (path->alternate_configured)
printf("Primary Path Information:\n");
printf(" Logical Device................. %s\n",path->primary_name);
printf(" SCSI Parent.................... %s\n",path->primary_parent);
if (path->primary_fcp_id_valid)
{
if (path->primary_id_valid)
{
printf(" Target ID...................... %d\n",path->primary_id);
printf(" Logical Unit................... %d\n",path->primary_lun);
printf(" SCSI Bus....................... %d\n",path->primary_bus);
}
printf(" FCP SCSI ID.................... 0x%llx\n",path->primary_fcp_scsi_id);
printf(" FCP Logical Unit............... 0x%llx\n",path->primary_fcp_lun_id);
printf(" FCP World Wide Name............ 0x%llx\n",path->primary_fcp_ww_name);
}
else
{
printf(" Target ID...................... %d\n",path->primary_id);
printf(" Logical Unit................... %d\n",path->primary_lun);
}
if (path->primary_drive_port_valid)
printf(" Drive Port Number.............. %d\n",path->primary_drive_port);
if (path->primary_enabled)
printf(" Path Enabled................... Yes\n");
else
printf(" Path Enabled................... No \n");
if (path->primary_fenced)
printf(" Path Manually Disabled......... Yes\n");
else
printf(" Path Manually Disabled......... No \n");
if (!path->alternate_configured)
printf(" Alternate Path Configured...... No\n");
}
}
This IOCTL command returns the same data structure as the SIOC_QUERY_PATH
IOCTL command with the updated path information for the primary and first
alternate path. See the SIOC_QUERY_PATH IOCTL command for a description of the
data structure and output information. If more than one alternate path is
configured for the device, then the SIOC_DEVICE_PATHS IOCTL must be used to
determine the paths that are enabled.
int sioc_reset_path(void)
{
struct scsi_path path;
return errno;
}
SIOC_RESET_DEVICE
This IOCTL command issues a SCSI target reset to the device if parallel SCSI is
attached or a SCSI lun reset if FCP/SAS is attached to the device. This IOCTL
command can be used to clear a SCSI Reservation that is active on the device. This
command can be used concurrently when the device is already open by another
process by using the openx() extended parameter SC_TMCP.
There is no argument for this IOCTL and the arg parameter is ignored.
SIOC_DRIVER_INFO
This command returns the information about the currently installed Atape driver.
The following data structure is filled out and returned by the driver.
struct driver_info {
uchar dd_name[16]; /* Atape driver name (Atape) */
uchar dd_version[16]; /* Atape driver version e.g. 12.0.8.0 */
uchar os[16]; /* Operating System (AIX) */
uchar os_version[32]; /* Running OS Version e.g. 6.1 */
uchar sys_arch[16]; /* Sys Architecture (POWER or others) */
uchar reserved[32]; /* Reserved for IBM Development Use */
};
int sioc_driver_info()
{
struct driver_info dd_info;
Overview
The following IOCTL commands are supported.
These IOCTL commands and their associated structures are defined in the
/usr/include/sys/Atape.h header file, which is included in the corresponding C
program that uses the functions.
STIOCHGP
This IOCTL command sets the current block size. A block size of zero is a variable
block. Any other value is a fixed block.
stchgp.st_blksize = 512;
if (ioctl(tapefd,STIOCHGP,&stchgp)<0)
{
printf("IOCTL failure. errno=%d",errno);
exit(errno);
}
STIOCTOP
This IOCTL command runs basic tape operations. The st_count variable is used for
many of its operations. Normal error recovery applies to these operations. The
device driver can issue several tries to complete them.
For all space operations, the tape position finishes on the end-of-tape side of the
record or filemark for forward movement and on the beginning-of-tape side of the
record or filemark for backward movement. The only exception occurs for forward
and backward space record operations over a filemark if the device is configured
for the AIX record space mode.
Note: If zero is used for operations that require the count parameter, the command
is not issued to the device, and the device driver returns a successful
completion.
stop.st_op=STWEOF;
stop.st_count=3;
if (ioctl(tapefd,STIOCTOP,&stop)<0)
{
printf("IOCTL failure. errno=%d",errno);
exit(errno);
}
STIOCQRYP or STIOCSETP
The STIOCQRYP IOCTL command allows the program to query the tape device,
device driver, and media parameters. The STIOCSETP IOCTL command allows the
program to change the tape device, device driver, and media parameters. Before
the STIOCSETP IOCTL command is issued, use the STIOCQRYP IOCTL command to
query and fill the fields of the data structure that you do not want to change.
Then, issue the STIOCSETP command to change the selected fields.
The following parameters that are returned by the STIOCQRYP IOCTL command
cannot be changed by the STIOCSETP IOCTL command.
v trace
This parameter is the current setting of the AIX system tracing for channel 0. All
Atape device driver events are traced in channel 0 with other kernel events. If
set to On, device driver tracing is active.
v hkwrd
This parameter is the trace hookword used for Atape events.
v write_protect
The following parameters can be changed with the STIOCSETP IOCTL command.
v blksize
This parameter specifies the effective block size for the tape device.
v autoload
This parameter turns the autoload feature On and Off in the device driver. If set
to On, the cartridge loader is treated as a large virtual tape.
v buffered_mode
This parameter turns the buffered mode write On and Off.
v compression
This parameter turns the hardware compression On and Off.
Note: The tape position must be at the beginning of the tape to change this
parameter from its current value.
v capacity_scaling and capacity_scaling_value
The capacity_scaling parameter queries the capacity or logical length of the
current tape or on a set operation changes the current tape capacity. On a query
operation, this parameter returns the current capacity for the tape. It is one of
the defined values such as SCALE_100, SCALE_75, SCALE_VALUE If the query
returns SCALE_VALUE, then the capacity_scaling_value parameter is the
current capacity. Otherwise, the capacity_scaling parameter is the current
capacity.
On a set operation, if the capacity_scaling parameter is set to SCALE_VALUE
then the capacity_scaling_value parameter is used to set the tape capacity.
Otherwise, one of the other defined values for the capacity_scaling parameter
is used.
Note:
1. The tape position must be at the beginning of the tape to change this
parameter from its current value.
2. Changing this parameter destroys any existing data on the tape.
v retain_reservation
a2500291
BOP EW EOP
PEWZ
STIOCSYNC
This input/output control (IOCTL) command flushes the tape buffers to the tape
immediately.
STIOCDM
This IOCTL command displays and manipulates one or two messages on the
message display. The message that is sent with this call does not always remain on
the display. It depends on the current state of the tape device.
STIOCQRYPOS or STIOCSETPOS
The STIOCQRYPOS IOCTL command queries the position on the tape. The
STIOCSETPOS IOCTL command sets the position on the tape. Only the block_type
and curpos fields are used during a set operation. The tape position is defined as
where the next read or write operation occurs. The query function can be used
independently or with the set function. Also, the set function can be used
independently or with the query function.
The block_type field is set to QP_LOGICAL when a SCSI logical blockid format is
wanted. During a query operation, the curpos field is set to a simple unsigned int.
On IBM 3490 tape drives only, the block_type field can be set to QP_PHYSICAL.
Setting this block_type on any other device is ignored and defaults to
QP_LOGICAL. After a set operation, the position is at the logical block that is
indicated by the curpos field. If the block_type field is set to QP_PHYSICAL, the
curpos field that is returned is a vendor-specific blockid format from the tape
device. When QP_PHYSICAL is used for a query operation, the curpos field is
used only in a subsequent set operation with QP_PHYSICAL. This function
completes a high speed locate operation. Whenever possible, use QP_PHYSICAL
because it is faster. This advantage is obtained only when the set operation uses
the curpos field from the QP_PHYSICAL query.
After a query operation, the lbot field indicates the last block of the data that was
transferred physically to the tape. If the application writes 12 (0 - 11) blocks and
lbot equals 8, then three blocks are in the tape buffer. This field is valid only if the
last command was a write command. This field does not reflect the number of
application write operations. A write operation can translate into multiple blocks.
It reflects tape blocks as indicated by the block size. If an attempt is made to obtain
this information and the last command is not a write command, the value of
LBOT_UNKNOWN is returned.
The driver sets the bot field to TRUE if the tape position is at the beginning of the
tape. Otherwise, it is set to FALSE. The driver sets the eot field to TRUE if the tape
is positioned between the early warning and the physical end of the tape.
Otherwise, it is set to FALSE.
The partition number field that is returned is the current partition of the loaded
tape.
STIOCQRYSENSE
This IOCTL command returns the last sense data that is collected from the tape
device, or it issues a new Request Sense command and returns the collected data.
If LASTERROR is requested, the sense data is valid only if the last tape operation
has an error that issued a sense command to the device. If the sense data is valid,
the IOCTL command completes successfully and the len field is set to a value
greater than zero.
STIOCQRYINQUIRY
This IOCTL command returns the inquiry data from the device. The data is
divided into standard and vendor-specific portions.
BYTE b1;
/* macros for accessing fields of byte 2 */
#define RMB(x) ((x->b1 & 0x80)>>7) /* removable media bit */
#define FIXED 0
BYTE b2;
/* macros for accessing fields of byte 3 */
#define ISO_Version(x) ((x->b2 & 0xC0)>>6)
#define ECMA_Version(x) ((x->b2 & 0x38)>>3)
#define ANSI_Version(x) ((x->b2 & 0x07)
#define NONSTANDARD 0
#define SCSI1 1
#define SCSI2 2
BYTE b3;
/* macros for accessing fields of byte 4 */
#define AENC(x) ((x->b3 & 0x80)>>7) /* asynchronous event notification */
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define TrmIOP(x) ((x->b3 & 0x40)>>6) /* support terminate I/O process message? */
#define Response_Data_Format(x) (x->b3 & 0x0F)
#define SCSI1INQ 0 /* SCSI-1 standard inquiry data format */
#define CCSINQ 1 /* CCS standard inquiry data format */
#define SCSI2INQ 2 /* SCSI-2 standard inquiry data format */
BYTE b7;
/* macros for accessing fields of byte 7 */
#define RelAdr(x) ((x->b7 & 0x80)>>7) /* the following fields are true or false */
#define WBus32(x) ((x->b7 & 0x40)>>6)
#define WBus16(x) ((x->b7 & 0x20)>>5)
#define Sync(x) ((x->b7 & 0x10)>>4)
#define Linked(x) ((x->b7 & 0x08)>>3)
#define CmdQue(x) ((x->b7 & 0x02)>>1)
#define SftRe(x) ((x->b7 & 0x01)
char vendor_identification[8];
char product_identification[16];
char product_revision_level[4];
};
struct st_inquiry
{
struct inq_data_s standard;
BYTE vendor_specific[255-sizeof(struct inq_data_s)];
};
STIOC_LOG_SENSE
This IOCTL command returns the log sense data from the device. If volume
logging is set to On, the log sense data is saved in the tape log file.
if (ioctl(tapefd,STIOC_LOG_SENSE,&logdata)<0)
{
printf("IOCTL failure. errno=%d",errno);
exit(errno);
}
STIOC_RECOVER_BUFFER
This IOCTL command recovers the buffer data from the tape device. It is typically
used after an error occurs during a write operation that prevents the data in the
tape device buffers from being written to tape. The STIOCQRYPOS command can be
used before this IOCTL command to determine the number of blocks and the bytes
of data that is in the device buffers.
Each STIOC_RECOVER_BUFFER IOCTL call returns one block of data from the device.
This ioctl command can be issued multiple times to completely recover all the
buffered data from the device.
After the IOCTL command is completed, the ret_len field contains the number of
bytes returned in the application buffer for the block. If no blocks are in the tape
device buffer, then the ret_len value is set to zero.
if (ioctl(tapefd,STIOC_RECOVER_BUFFER,&bufdata)<0)
{
printf("IOCTL failure. errno=%d",errno);
}
else
{
printf("Returned bytes=%d",bufdata.ret_len);
}
STIOC_LOCATE
This IOCTL command causes the tape to be positioned at the specified block ID.
The block ID used for the command must be obtained with the
STIOC_READ_POSITION command.
STIOC_READ_POSITION
This IOCTL command returns the block ID of the current position of the tape. The
block ID returned from this command can be used with the STIOC_LOCATE
command to set the position of the tape.
STIOC_SET_VOLID
This IOCTL command sets the volume name for the currently mounted tape. The
volume name is used by the device driver for tape volume logging only and is not
written or stored on the tape. The volume name is reset to unknown whenever an
unload command is issued to unload the current tape. The volume name can be
queried and set by using the STIOCQRYP and STIOCSETP IOCTLs.
The argument that is used for this command is a character pointer to a buffer that
contains the name of the volume to be set.
STIOC_DUMP
This IOCTL command forces a dump on the tape device, then stores the dump to
either a host-specified file or in the /var/adm/ras system directory. The device
driver stores up to three dumps in this directory. The first dump that is created is
named Atape.rmtx.dump1, where x is the device number, for example, rmt0. The
second and third dumps are dump2 and dump3. After a third dump file is created,
the next dump starts at dump1 again and overlays the previous dump1 file.
The argument that is used for this command is NULL to dump to the system
directory. Or, it is a character pointer to a buffer that contains the path and file
name for the dump file. The dump can also be stored on a diskette by specifying
/dev/rfd0 for the name.
STIOC_FORCE_DUMP
This IOCTL command forces a dump on the tape device. The dump can be
retrieved from the device by using the STIOC_READ_DUMP IOCTL.
STIOC_READ_DUMP
This IOCTL command reads a dump from the tape device. Then, it stores the
dump to either a host specified file or in the /var/adm/ras system directory. The
device driver stores up to three dumps in this directory. The first dump that is
created is named Atape.rmtx.dump1, where x is the device number, for example
rmt0. The second and third dumps are dump2 and dump3. After a third dump file
is created, the next dump starts at dump1 again and overlays the previous dump1
file.
The argument that is used for this command is NULL to dump to the system
directory. Or, it is a character pointer to a buffer that contains the path and file
name for the dump file. The dump can also be stored on a diskette by specifying
/dev/rfd0 for the name.
STIOC_LOAD_UCODE
This IOCTL command downloads microcode to the device. The argument that is
used for this command is a character pointer to a buffer that contains the path and
file name of the microcode. Microcode can also be loaded from a diskette by
specifying /dev/rfd0 for the name.
STIOC_RESET_DRIVE
This IOCTL command issues a SCSI Send Diagnostic command to reset the tape
drive. There are no arguments for this IOCTL command.
exit(errno);
}
STIOC_PREVENT_MEDIUM_REMOVAL
This IOCTL command prevents an operator from removing medium from the
device until the STIOC_ALLOW_MEDIUM_REMOVAL command is issued or the device is
reset.
STIOC_ALLOW_MEDIUM_REMOVAL
This IOCTL command allows an operator to remove medium from the device. This
command is used normally after an STIOC_PREVENT_MEDIUM_REMOVAL command to
restore the device to the default state.
STIOC_REPORT_DENSITY_SUPPORT
This IOCTL command issues the SCSI Report Density Support command to the
tape device and returns either all supported densities or supported densities for
the currently mounted media. The media field specifies which type of report is
requested. The number_reports field is returned by the device driver and indicates
how many density reports in the reports array field were returned.
The data structures that are used with this IOCTL are
typedef struct density_report
{
uchar primary_density_code; /* primary density code */
uchar secondary_density_code; /* secondary density code */
uint wrtok :1, /* write ok, device can write this format */
dup :1, /* zero if density only reported once */
deflt :1, /* current density is default format */
res_1 :5; /* reserved */
uchar reserved[2]; /* reserved */
uchar bits_per_mm[3]; /*bits per mm */
uint bits_per_mm:24; /* bits per mm */
ushort media_width; /* media width in millimeters */
ushort tracks; /* tracks */
uint capacity; /* capacity in megabytes */
char assigning_org[8]; /* assigning organization in ASCII */
char density_name[8]; /* density name in ASCII */
char description[20]; /* description in ASCII */
};
struct report_density_support
{
uchar media; /* report all or current media as defined above */
ushort number_reports; /* number of density reports returned in array */
struct density_report reports[MAX_DENSITY_REPORTS];
};
int stioc_report_density_support(void)
{
int i;
struct report_density_support density;
density.media = ALL_MEDIA_DENSITY;
if (density.reports[i].wrtok)
printf(" Write OK..............Yes\n");
else
printf(" Write OK..............No\n");
if (density.reports[i].dup)
printf(" Duplicate.............Yes\n");
else
printf(" Duplicate.............No\n");
if (density.reports[i].deflt)
printf(" Default...............Yes\n");
else
printf(" Default............... No\n");
density.media = CURRENT_MEDIA_DENSITY;
if (density.reports[i].wrtok)
printf(" Write OK..............Yes\n");
else
printf(" Write OK..............No\n");
if (density.reports[i].dup)
printf(" Duplicate.............Yes\n");
else
printf(" Duplicate.............No\n");
return errno;
}
The STIOC_SET_DENSITY IOCTL is used to set a new write density format on the
tape drive by using the default and pending density fields. The density code field
is not used and ignored on this IOCTL. The application can specify a new write
density for the current loaded tape only or as a default for all tapes. Refer to the
examples.
The application must get the current density settings first before the current
settings are modified. If the application specifies a new density for the current
loaded tape only, then the application must issue another Set Density IOCTL after
the current tape is unloaded and the next tape is loaded to either the default
maximum density or a new density. This action ensures the tape drive uses the
correct density. If the application specifies a new default density for all tapes, the
setting remains in effect until changed by another set density IOCTL or the tape
drive is closed by the application.
Note:
1. The IOCTLs are only supported on tape drives that can write multiple
density formats. Refer to the Hardware Reference for the specific tape
drive to determine whether multiple write densities are supported. If the
tape drive does not support the IOCTLs, errno EINVAL is returned.
2. The device driver always sets the default maximum write density for the
tape drive on every open system call. Any previous STIOC_SET_DENSITY
IOCTL values from the last open are not used.
3. If the tape drive detects an invalid density code or cannot complete the
operation on the STIOC_SET_DENSITY IOCTL, the errno is returned. Then,
the current drive density settings before the IOCTL are restored.
Examples
struct density_data_t data;
STIOC_CANCEL_ERASE
The STIOC_CANCEL_ERASE IOCTL is used to cancel an erase operation currently in
progress. This action happens when an application issued the STIOCTOP IOCTL
with the st_op field that specifies STERASE_IMM. The application that issued the
erase and is waiting for it to complete then returns immediately with errno
ECANCELLED. This IOCTL always returns 0 whether an erase immediate
operation is in progress or not.
This IOCTL can be issued only when the openx() extended parameter SC_TMCP is
used to open the device. It happens when the application that issued the erase still
has the device currently open. There is no argument for this IOCTL and the arg
parameter is ignored.
GET_ENCRYPTION_STATE
This IOCTL command queries the drive's encryption method and state. The data
structure that is used for this IOCTL is for all of the supported operating systems.
struct encryption_status {
uchar encryption_capable; /* (1)Set this field as a boolean based on the
capability of the drive */
uchar encryption_method; /* (2)Set this field to one of the
#defines METHOD_* below */
#define METHOD_NONE 0 /* Only used in GET_ENCRYPTION_STATE */
#define METHOD_LIBRARY 1 /* Only used in GET_ENCRYPTION_STATE */
#define METHOD_SYSTEM 2 /* Only used in GET_ENCRYPTION_STATE */
uchar[13] reserved;
};
default:
printf("encryption method.......Error\n");
}
switch(encryption_status_t.encryption_state)
{
case STATE_OFF:
printf("encryption state........OFF\n");
break;
case STATE_ON:
printf("encryption state........ON\n");
break;
case STATE_NA:
printf("encryption state........NA\n");
break;
default:
return rc;
}
SET_ENCRYPTION_STATE
This IOCTL command allows set encryption state only for application-managed
encryption. On unload, some of the drive settings can be reset to default. To set the
encryption state, the application must issue this IOCTL after a tape is loaded and
at BOP.
The data structure used for this IOCTL is the same as the one for
GET_ENCRYPTION_STATE. An example of the SET_ENCRYPTION_STATE command is
int set_encryption_state(int option)
{
int rc = 0;
struct encryption_status encryption_status_t;
if(option == 0)
encryption_status_t.encryption_state = STATE_OFF;
else if(option == 1)
encryption_status_t.encryption_state = STATE_ON;
else
{
printf("Invalid parameter.\n");
return -EINVAL;
}
return rc;
}
SET_DATA_KEY
This IOCTL command allows set the data key only for application-managed
encryption. The data structure that is used for this IOCTL is for all of the
supported operating systems.
struct data_key
{
uchar[12 data_key_index;
uchar data_key_index_length;
uchar[15] reserved1;
uchar[32] data_key;
uchar[48] reserved2;
};
READ_TAPE_POSITION
The READ_TAPE_POSITION IOCTL is used to return Read Position command data in
either the short, long, or extended form. The type of data to return is specified by
setting the data_format field to either RP_SHORT_FORM, RP_LONG_FORM, or
RP_EXTENDED_FORM.
The data structures that are used with this IOCTL are
#define RP_SHORT_FORM 0x00
#define RP_LONG_FORM 0x06
#define RP_EXTENDED_FORM 0x08
struct short_data_format {
uint bop:1, /* beginning of partition */
eop:1, / end of partition */
locu:1, /* 1 means num_buffer_logical_obj field is unknown */
bycu:1, /* 1 means the num_buffer_bytes field is unknown */
rsvd :1,
lolu:1, /* 1 means the first and last logical obj position
fields are unknown */
perr: 1, /* 1 means the position fields have overflowed and
can not be reported */
bpew :1; /* beyond programmable early warning */
uchar active_partition; /* current active partition */
char reserved[2];
uint first_logical_obj_position; /* current logical object position */
uint last_logical_obj_position; /* next logical object to be transferred to tape */
uint num_buffer_logical_obj; /* number of logical objects in buffer */
uint num_buffer_bytes; /* number of bytes in buffer */
char reserved1;
};
struct long_data_format {
uint bop:1, /* beginning of partition */
eop:1, /* end of partition */
rsvd1:2,
mpu:1, /* 1 means the logical file id field in unknown */
lonu:1, /* 1 means either the partition number or logical obj
number field are unknown */
rsvd2:1,
bpew :1; /* beyond programmable early warning */
char reserved[6];
uchar active_partition; /* current active partition */
ullong logical_obj_number; /* current logical object position */
ullong logical_file_id; /* number of filemarks from bop and current logical position */
ullong obsolete;
};
struct extended_data_format {
uint bop:1, /* beginning of partition */
eop:1, /* end of partition */
locu:1, /* 1 means num_buffer_logical_obj field is unknown */
bycu:1, /* 1 means the num_buffer_bytes field is unknown */
rsvd :1,
lolu:1, /* 1 means the first and last logical obj position fields
are unknown */
perr: 1, /* 1 means the position fields have overflowed and can not
be reported */
bpew :1; /* beyond programmable early warning */
struct read_tape_position{
uchar data_format; /* Specifies the return data format either short,
long or extended as defined above */
union
{
struct short_data_format rp_short;
struct long_data_format rp_long;
struct extended_data_format rp_extended;
char reserved[64];
} rp_data;
};
if (rpos.rp_data.rp_long.bop)
printf(" Beginning of Partition ..... Yes\n");
else
printf(" Beginning of Partition ..... No\n");
if (rpos.rp_data.rp_long.eop)
printf(" End of Partition ........... Yes\n");
else
printf(" End of Partition ........... No\n");
if (rpos.rp_data.rp_long.bpew)
printf(" Beyond Early Warning ... ... Yes\n");
else
printf(" Beyond Early Warning ....... No\n");
if (rpos.rp_data.rp_long.lonu)
{
printf(" Active Partition ........... UNKNOWN \n");
printf(" Logical Object Number ...... UNKNOWN \n");
}
else
{
printf(" Active Partition ... ....... %u \n",
rpos.rp_data.rp_long.active_partition);
printf(" Logical Object Number ...... %llu \n",
rpos.rp_data.rp_long.logical_obj_number);
}
if (rpos.rp_data.rp_long.mpu)
printf(" Logical File ID ............ UNKNOWN \n");
else
printf(" Logical File ID ............ %llu \n",
rpos.rp_data.rp_long.logical_file_id);
struct set_tape_position{
uchar logical_id_type; /* Block or file as defined above */
ullong logical_id; /* logical object or logical file to position to */
char reserved[32];
};
SET_ACTIVE_PARTITION
The SET_ACTIVE_PARTITION IOCTL is used to position the tape to a specific
partition. Then, it becomes the current active partition for subsequent commands
and a specific logical bock id in the partition. To position to the beginning of the
partition, the logical_block_id field is set to 0.
struct query_partition {
uchar max_partitions; /* Max number of supported partitions */
uchar active_partition; /* current active partition on tape */
uchar number_of_partitions; /* Number of partitions from 1 to max */
uchar size_unit; /* Size unit of partition sizes below */
ushort size[MAX_PARTITIONS]; /* Array of partition sizes in size units */
/* for each partition, 0 to (number - 1) */
uchar partition_method; /* partitioning type */
char reserved [31];
};
CREATE_PARTITION
The CREATE_PARTITION IOCTL is used to format the current media in the tape drive
into 1 or more partitions. The number of partitions to create is specified in the
number_of_partitions field. When more than one partition is created, the type
field specifies the type of partitioning, either FDP, SDP, or IDP. The tape must be
positioned at the beginning of tape (partition 0 logical block id 0) before this
IOCTL is used.
When the type field in the IOCTL structure is set to either FDP or SDP, the
size_unit and size fields in the IOCTL structure are not used. When the type field
in the IOCTL structure is set to IDP, the size_unit with the size fields are used to
specify the size for each partition.
There are two partition types: Wrap-wise Partitioning (Figure 5) optimized for
streaming performance, and Longitudinal Partitioning (Figure 6 on page 73)
optimized for random access performance. Media is always partitioned into 1 by
default. Or, more than one partition where the data partition always exists as
partition 0 and other extra index partition 1 to n can exist.
A WORM media cannot be partitioned and the Format Medium commands are
rejected. Attempts to scale a partitioned media is accepted. However, only if you
use the correct FORMAT field setting, as part of scaling the volume is set to a
single data partition cartridge.
Partition 0
Guard wraps
Partition 1
Partition 2
a2500283
Partition 3
Partition 0 Partition 1
a2500284
Figure 6. Longitudinal partitioning
The following chart lists the maximum number of partitions that the tape drive
supports.
Table 3. Number of supported partitions
Drive type Maximum number of supported partitions
LTO 5 (TS2250 and TS2350) and later 2 in Wrap-wise Partitioning
3592 E07 (TS 1140) 4 in Wrap-wise Partitioning
2 in Longitudinal Partitioning
struct tape_partition {
uchar type; /* Type of tape partition to create */
uchar number_of_partitions; /* Number of partitions to create */
uchar size_unit; /* IDP size unit of partition sizes below */
ushort size[MAX_PARTITIONS]; /* Array of partition sizes in size units */
/* for each partition,0 to (number - 1) */
uchar partition_method; /* partitioning type */
char reserved [31];
};
ALLOW_DATA_OVERWRITE
The ALLOW_DATA_OVERWRITE IOCTL is used to set the drive to allow a subsequent
data write type command at the current position. Or, it allows a CREATE_PARTITION
IOCTL when data safe (append-only) mode is enabled.
/* get current tape position for a subsequent write type command and */
data_overwrite.partition_number = rpos.rp_data.rp_long.active_partition;
data_overwrite.logical_block_id = rpos.rp_data.rp_long.logical_obj_number;
data_overwrite.allow_format_overwrite = 0;
ioctl (fd, ALLOW_DATA_OVERWRITE, &data_overrite;);
data_overwrite.allow_format_overwrite = 1;
ioctl (fd, ALLOW_DATA_OVERWRITE, &data_overwrite);
QUERY_LOGICAL_BLOCK_PROTECTION
The IOCTL queries whether the drive can support this feature, what Logical Block
Protection (LBP) method is used, and where the protection information is included.
The lbp_capable field indicates whether the drive has logical block protection
capability. The lbp_method field displays if LBP is enabled and what the
protection method is. The LBP information length is shown in the lbp_info_length
field. The fields of lbp_w, lbp_r, and rbdp present that the protection information
is included in write, read, or recover buffer data.
The lbp_capable field is ignored in this IOCTL by the Atape driver. If the
lbp_method field is 0 (LBP_DISABLE), all other fields are ignored and not used.
When the lbp_method field is set to a valid non-zero method, all other fields are
used to specify the setup for LBP.
int rc;
struct logical_block_protection lbp_protect;
if (rc)
printf ("Set Logical Block Protection Fails (rc %d)",rc);
else
printf ("Set Logical Block Protection Succeeds");
Note:
1. The drive always expects a CRC attached with a data block when LBP is
enabled for lbp_r and lbp_w. Without the CRC bytes attachment, the
drive fails the Read and Write command. To prevent the CRC block
STIOC_READ_ATTRIBUTE
The IOCTL is issued to read attribute values that belongs to a specific partition
from medium auxiliary memory.
memset(&rd_attr,0,sizeof(struct read_attribute));
rd_attr.service_action=0x00;
rd_attr.partition_number=1;
rd_attr.first_attr_id=0x800;
if (rc)
printf ("Read Attribute failed (rc %d)",rc);
else
{
printf ("Read Attribute Succeeds!");
dump_bytes (rd_attr.data, min(MAX_ATTR_LEN, rd_attr.attr_data_len),
"Attribute Data");
}
STIOC_WRITE_ATTRIBUTE
The IOCTL sets the attributes in medium auxiliary memory at a specific partition.
int rc;
struct write_attribute wr_attr;
memset(&wr_attr,0,sizeof(struct write_attribute));
wr_attr.write_cache=0;
wr_attr.parm_list_len=0x11;
wr_attr.data[3]=0x0D;
wr_attr.data[4]=0x08;
wr_attr.data[6]=0x01;
wr_attr.data[8]=0x08;
wr_attr.data[9]=’I’;
wr_attr.data[10]=’B’;
wr_attr.data[11]=’M’;
wr_attr.data[12]=’ ’;
wr_attr.data[13]=’T’;
wr_attr.data[14]=’E’;
wr_attr.data[15]=’S’;
wr_attr.data[16]=’T’;
if (rc)
printf ("Write Attribute failed (rc %d)",rc);
else
printf ("Write Attribute Succeeds");
VERIFY_TAPE_DATA
The IOCTL issues a VERIFY command. This command causes data to be read from
the tape and passed through the drive’s error detection and correction hardware.
This action determines whether it can be recovered from the tape, whether the
protection information is present, and validates correctly on logical block on the
medium. The driver returns the IOCTL a failure or a success if the VERIFY SCSI
command is completed in a Good SCSI status.
Note:
1. When an application sets the VBF method, it considers the driver’s close
operation in which the driver can write filemarks in its close, which the
application did not explicitly request. For example, some drivers write
two consecutive filemarks that mark the end of data on the tape in its
close, if the last tape operation was a WRITE command.
2. Per the user's or application's request, Atape driver sets the block size in
the field of Block Length in mode block descriptor for Read and Write
commands. Then, it maintains this block size setting in a whole open.
For instance, the tape driver sets a zero in the Block Length field for the
variable block size. This act causes the missing of an overlength
condition on a SILI Read. Block Length must be set to a non-zero value.
int rc;
struct verify_data vrf_data;
memset(&vrf_data,0,sizeof(struct verify_data));
vrf_data.vte=1;
vrf_data.vlbpm=1;
vrf_data.vbf=0;
vrf_data.immed=0;
vrf_data.fixed=0;
vrf_data.verify_length=0;
if (rc)
printf ("Verify Tape Data failed (rc %d)",rc);
else printf
("Verify Tape Data Succeeded!");
| GENERATE_RAO
| The IOCTL is called to send a GRAO list to request the drive to generate a
| Recommending Access Order list.
| The process method is either 1 or 2 to create a RAO list, and the type of UDS is
| either with or without the geometry. The uds_number must be not larger than
| max_host_uds_number in the QUERY_RAO_INFO IOCTL. The application allocates a
| memory with grao_list_leng (uds_number * sizeof(struct grao_uds_desc) +8) for
| the pointer of grao_list. 8 bytes is the size that is needed for the header portion on
| of the return data.
| The grao list is in the format and the parameter data can be generated by using the
| structures that are defined here.
| -- List Header
| -- UDS Segment Descriptor (first)
| ......
| -- UDS Segment Descriptor (last)
|
| struct grao_list_header {
| uchar reserved[4];
| uint addl_data; /* additional data */
| }
|
| struct grao_uds_desc {
| ushort desc_leng; /* descriptor length */
| char reserved[3];
| char uds_name[10]; /* uds name given by application */
| char partition; /* Partition number 0-n to overwrite */
| ullong beginning_loi; /* Beginning logical object ID */
| ullong ending_loi; /* Ending logical object ID */
| }
When an application opens a /dev/rmt special file that is assigned to a drive that
has access to a medium changer, these IOCTL operations are also available. The
interface to the /dev/rmt*.smc special file provides the application access to a
separate medium changer device. When this special file is open, the medium
changer is treated as a separate device. While /dev/rmt*.smc is open, access to the
IOCTL operations is restricted to /dev/rmt*.smc and any attempt to access them
through /dev/rmt* fails.
Overview
The following IOCTL commands are supported.
SMCIOC_ELEMENT_INFO
Obtain the device element information.
SMCIOC_MOVE_MEDIUM
Move a cartridge from one element to another element.
SMCIOC_EXCHANGE_MEDIUM
Exchange a cartridge in an element with another cartridge.
SMCIOC_POS_TO_ELEM
Move the robot to an element.
SMCIOC_INIT_ELEM_STAT
Issue the SCSI Initialize Element Status command.
SMCIOC_INIT_ELEM_STAT_RANGE
Issue the SCSI Initialize Element Status with Range command.
SMCIOC_INVENTORY
Return the information about the four element types.
SMCIOC_LOAD_MEDIUM
Load a cartridge from a slot into the drive.
SMCIOC_UNLOAD_MEDIUM
Unload a cartridge from the drive and return it to a slot.
SMCIOC_PREVENT_MEDIUM_REMOVAL
Prevent medium removal by the operator.
SMCIOC_ALLOW_MEDIUM_REMOVAL
Allow medium removal by the operator.
These IOCTL commands and their associated structures are defined by including
the /usr/include/sys/Atape.h header file in the C program by using the functions.
SMCIOC_ELEMENT_INFO
This IOCTL command obtains the device element information.
SMCIOC_MOVE_MEDIUM
This IOCTL command moves a cartridge from one element to another element.
SMCIOC_EXCHANGE_MEDIUM
This IOCTL command exchanges a cartridge in an element with another cartridge.
This command is equivalent to two SCSI Move Medium commands. The first moves
the cartridge from the source element to the destination1 element. The second
moves the cartridge that was previously in the destination1 element to the
destination2 element. The destination2 element can be the same as the source
element.
exchange_medium.robot = 0;
exchange_medium.invert1 = 0;
exchange_medium.invert2 = 0;
exchange_medium.source = 32; /* slot 32 */
exchange_medium.destination1 = 16; /* drive address 16 */
exchange_medium.destination2 = 35; /* slot 35 */
SMCIOC_POS_TO_ELEM
This IOCTL command moves the robot to an element.
char buf[10];
struct pos_to_elem pos_to_elem;
pos_to_elem.robot = 0;
pos_to_elem.invert = 0;
pos_to_elem.destination = dest;
SMCIOC_INIT_ELEM_STAT
This IOCTL command instructs the medium changer robotic device to issue the
SCSI Initialize Element Status command.
SMCIOC_INIT_ELEM_STAT_RANGE
This IOCTL command issues the SCSI Initialize Element Status with Range
command. It is used to audit specific elements in a library by specifying the
starting element address and number of elements. Use the SMCIOC_INIT_ELEM_STAT
IOCTL to audit all elements.
SMCIOC_INVENTORY
This IOCTL command returns information about the four element types. The
software application processes the input data (the number of elements about which
it requires information). Then, it allocates a buffer large enough to hold the output
for each element type.
struct inventory
{
struct element_status *robot_status; /* medium transport element pages */
struct element_status *slot_status; /* medium storage element pages */
struct element_status *ie_status; /* import/export element pages */
struct element_status *drive_status; /* data-transfer element pages */
};
ushort i;
struct element_status robot_status[1];
struct element_status slot_status[20];
struct element_status ie_status[1];
bzero((caddr_t)robot_status,sizeof(struct element_status));
for (i=0;i<20;i++)
bzero((caddr_t)(&slot_status[i]),sizeof(struct element_status));
bzero((caddr_t)ie_status,sizeof(struct element_status));
bzero((caddr_t)drive_status,sizeof(struct element_status));
smcioc_element_info();
inventory.robot_status = robot_status;
inventory.slot_status = slot_status;
inventory.ie_status = ie_status;
inventory.drive_status = drive_status;
SMCIOC_UNLOAD_MEDIUM
This IOCTL command moves a tape from the drive and returns it to a specific slot.
Or, it moves a tape to the first empty slot in the magazine if the slot address is
specified as zero. If the IOCTL is issued to the /dev/rmt special file, the tape is
automatically rewound and unloaded from the drive first.
SMCIOC_PREVENT_MEDIUM_REMOVAL
This IOCTL command prevents an operator from removing medium from the
device until the SMCIOC_ALLOW_MEDIUM_REMOVAL command is issued or the device is
reset.
SMCIOC_ALLOW_MEDIUM_REMOVAL
This IOCTL command allows an operator to remove medium from the device. This
command is used normally after an SMCIOC_PREVENT_MEDIUM_REMOVAL command to
restore the device to the default state.
SMCIOC_READ_ELEMENT_DEVIDS
This IOCTL command issues the SCSI Read Element Status command with the
device ID (DVCID) bit set and returns the element descriptors for the data transfer
elements. The element_address field specifies the starting address of the first data
transfer element. The number_elements field specifies the number of elements to
return. The application must allocate a return buffer large enough for the
number_elements specified in the input structure.
int smcioc_read_element_devids()
{
int i;
struct element_devid *elem_devid, *elemp;
struct read_element_devids devids;
struct element_info element_info;
if (element_info.drives)
{
elem_devid = malloc(element_info.drives * sizeof(struct element_devid));
if (elem_devid == NULL)
{
errno = ENOMEM;
return errno;
}
bzero((caddr_t)elem_devid,element_info.drives * sizeof(struct element_devid));
devids.drive_devid = elem_devid;
devids.element_address = element_info.drive_addr;
devids.number_elements = element_info.drives;
elemp = elem_devid;
for (i = 0; i < element_info.drives; i++, elemp++)
{
printf("\nDrive Address %d\n",elemp->address);
if (elemp->except)
printf(" Drive State .................... Abnormal\n");
else
printf(" Drive State .................... Normal\n");
if (elemp->asc == 0x81 && elemp->ascq ==0x00)
printf(" ASC/ASCQ ....................... %02X%02X (Drive Present)\n",
elemp->asc,elemp->ascq);
else if (elemp->asc == 0x82 && elemp->ascq ==0x00)
printf(" ASC/ASCQ ....................... %02X%02X (Drive Not Present)\n",
elemp->asc,elemp->ascq);
else
printf(" ASC/ASCQ ....................... %02X%02X\n",
elemp->asc,elemp->ascq);
if (elemp->full)
printf(" Media Present .................. Yes\n");
else
free(elem_devid);
return errno;
}
SMCIOC_READ_CARTIDGE_LOCATION
The SMCIOC_READ_CARTIDGE_LOCATION IOCTL is used to return the cartridge location
information for storage elements in the library. The element_address field specifies
the starting element address to return. The number_elements field specifies how
many storage elements are returned. The data field is a pointer to the buffer for
return data. The buffer must be large enough for the number of elements that are
returned. If the storage element contains a cartridge, then the ASCII identifier
field in return data specifies the location of the cartridge.
The data structures that are used with this IOCTL are
struct cartridge_location_data
{
ushort address; /* element address */
uint :4, /* reserved */
access:1, /* robot access allowed */
except:1, /* abnormal element state */
:1, /* reserved */
full:1; /* element contains medium */
uchar resvd1; /* reserved */
uchar asc; /* additional sense code */
uchar ascq; /* additional sense code qualifier */
uchar resvd2[3]; /* reserved */
uint svalid:1, /* element address valid */
invert:1, /* medium inverted */
struct read_cartridge_location
{
ushort element_address; /* starting element address */
ushort number_elements; /* number of elements */
struct cartridge_location_data *data; /* storage element pages */
char reserved[8]; /* reserved */
};
int i;
struct cartridge_location_data *data, *elemp;
struct read_cartridge_location cart_location;
struct element_info element_info;
if (element_info.slots == 0)
return 0;
elemp = data;
for (i = 0; i < element_info.slots; i++, elemp++)
{
if (elemp->address == 0
) continue;
} free(data);
return 0;
Return codes
This chapter describes the return codes that the device driver generates when an
error occurs during an operation. The standard errno values are in the AIX
/usr/include/sys/errno.h header file.
If the return code is input/output error (EIO), the application can issue the
STIOCQRYSENSE IOCTL command with the LASTERROR option. Or, it can issue the
SIOC_REQSENSE IOCTL command to analyze the sense data and determine why the
error occurred.
open
The open entry point is called to make the driver and device ready for
input/output (I/O). Only one open at a time is allowed for each tape device. More
opens of the same device (whether from the same or a different client system) fail
with an EBUSY error. ATDD supports multiple opens to the medium changer if the
configuration parameter RESERVE is set to 0. To set the configuration parameter,
see the IBM Tape Device Drivers Installation and User's Guide for guidance.
If the open system call fails, it returns -1, and the system errno value contains the
error code as defined in the /usr/include/sys/errno.h header file.
close
The close entry point is called to terminate I/O to the driver and device.
where tape is the open file handle that is returned by the open call. The close
routine normally would not return an error. The exception is related to the fact that
any data buffered on the drive is flushed out to tape before completion of the
close. If any error occurs in flushing the data, an error code is returned by the
close routine.
An application must explicitly issue the close() call when the I/O resource is no
longer necessary or in preparation for termination. The operating system implicitly
issues the close() call for an application that terminates without closing the
resource itself. If an application terminates unexpectedly but leaves behind child
processes that inherited the file descriptor for the open resource, the operating
system does not implicitly close the file descriptor because it believes that it is still
in use.
The close operation behavior depends on which special file was used during the
open operation and which tape operation was last run while it was opened. The
commands are issued to the tape drive during the close operation according to the
following logic and rules.
if last operation was WRITE FILEMARK
WRITE FILEMARK
BACKWARD SPACE 1 FILEMARK
Rules:
read
The read entry point is called to read data from tape. The caller provides a buffer
address and length, and the driver returns data from the tape to the buffer. The
amount of data that is returned never exceeds the length parameter.
if (actual > 0)
printf("Read %d bytes\n", actual);
else if (actual == 0)
printf("Read found file mark\n");
else
{
printf("Error on read\n");
printf("errno = %d\n",errno);
exit (-1);
}
where tape is the open file handle, buf_addr is the address of a buffer in which to
place the data, and bufsize is the number of bytes to be read.
The returned value, actual, is the actual number of bytes read (and zero indicates
a file mark).
When in variable block size mode, the bufsize parameter can be any value valid
to the drive. The amount of data that is returned equals the size of the next record
on the tape or the size requested (bufsize), whichever is less. If bufsize is less
than the actual record size on the tape, the remainder of the record is lost because
the next read starts from the start of the next record.
If the tape drive is configured for fixed block size operation, the bufsize parameter
must be a multiple of the device block size, or an error code (EINVAL) is returned.
If the bufsize parameter is valid, the read command always returns the amount of
data that is requested unless a file mark is encountered. In that case, it returns all
data that occurred before the filemark and actual equals the number of bytes
returned.
write
The write entry point is called to write data to the tape. The caller provides the
address and length of the buffer to be written. Physical limitations of the drive can
cause write to fail (for example, attempting to write past the physical end of tape).
if (actual < 0)
{
printf("Error on write\n");
printf("errno = %d\n",errno);
exit (-1);
}
where tape is the open file handle, buf_addr is the buffer address, and bufsize is
the size of the buffer in bytes.
The bufsize parameter must be a multiple of the block size or an error is returned
(EINVAL). If the write size exceeds the device maximum block size or the
configured buffer size of the tape drive, an error is returned (EINVAL).
ioctl
The ATDD software supports all input/output control (IOCTL) commands that are
supported by the HP-UX native drivers, tape2, and stape. See the following
HP-UX man pages for information.
v mt(7)
v scsi(7)
IOCTL operations
The following sections describe IOCTL operations that are supported by the ATDD.
Usage, syntax, and examples are given.
The IOCTL operations that are supported by the driver are described in
v “General SCSI IOCTL operations”
v “SCSI medium changer IOCTL operations” on page 110
v “SCSI tape drive IOCTL operations” on page 120
v “Base operating system tape drive IOCTL operations” on page 151
v “Service aid IOCTL operations” on page 153
The following files must be included by user programs that issue the IOCTL
commands described in this section to access the tape device driver.
v #include <sys/st.h>
v #include <sys/svc.h>
v #include <sys/smc.h>
v #include <sys/mtio.h>
These commands and associated data structures are defined in the st.h and smc.h
header files in the /usr/include/sys directory. It is installed with the HP-UX
Advanced Tape Device Driver (ATDD) package. Any application program that
issues these commands must include one or both header files.
IOC_TEST_UNIT_READY
This command determines whether the device is ready for operation.
else {
perror ("The IOC_TEST_UNIT_READY ioctl failed");
scsi_request_sense ();
}
IOC_INQUIRY
This command collects the inquiry data from the device.
The following data structure is filled out and returned by the driver.
inquiry_data_t inquiry_data;
else {
perror ("The IOC_INQUIRY ioctl failed");
scsi_request_sense ();
}
IOC_INQUIRY_PAGE
This command returns the inquiry data when a nonzero page code is requested.
For inquiry pages 0x80, data that is mapped by structures inq_pg_80_t is returned
in the data array. Otherwise, an array of data is returned in the data array.
The following data structure for inquiry page x80 is filled out and returned by the
driver.
typedef struct {
uchar page_code; /* page code */
uchar data[253]; /* inquiry parameter List */
} inquiry_page_t;
typedef struct {
inquiry_page_t inquiry_page;
inquiry_page.page_code = (uchar) page;
IOC_REQUEST_SENSE
This command returns the device sense data. If the last command resulted in an
error, the sense data is returned for that error. Otherwise, a new (unsolicited)
Request Sense command is issued to the device.
The following data structure is filled out and returned by the driver.
typedef struct {
uchar valid : 1, /* sense data is valid */
code : 7, /* error code */
uchar segnum; /* segment number */
uchar fm : 1, /* filemark detected */
eom : 1, /* end of media */
ili : 1, /* incorrect length indicator */
: 1, /* reserved */
key : 4; /* sense key */
uchar info[4]; /* information bytes */
uchar addlen; /* additional sense length */
uchar cmdinfo[4]; /* command-specific information */
uchar asc; /* additional sense code */
uchar ascq; /* additional sense code qualifier */
uchar fru; /* field-replaceable unit code */
uchar sksv : 1, /* sense key specific valid */
cd : 1, /* control/data */
: 2, /* reserved */
bpv : 1, /* bit pointer valid */
sim : 3; /* system information message */
uchar field[2]; /* field pointer */
uchar vendor[110]; /* vendor specific (padded to 128) */
} sense_data_t;
sense_data_t sense_data;
IOC_LOG_SENSE_PAGE
This IOCTL command returns a log sense page from the device. The wanted page
is selected by specifying the page_code in the log_sense_page structure.
The structure of a log page consists of the following log page header and log
parameters.
v Log Page
– Log Page Header
- Page Code
- Page Length
– Log Parameter(s) (One or more might exist)
- Parameter Code
- Control Byte
- Parameter Length
- Parameter Value
The following data structure is filled out and returned by the driver.
typedef struct {
uchar page_code; /* page code */
uchar data[MAX_LGPGDATA]; /* log data structure */
}log_sns_pg_t;
IOC_LOG_SENSE10_PAGE
This IOCTL command is enhanced to add a Subpage variable from
IOC_LOG_SENSE_PAGE. It returns a log sense page and Subpage from the device. The
wanted page is selected by specifying the page_code and subpage_code in the
log_sense10_page structure. Optionally, a specific parm pointer, also known as a
parm code, and the number of parameter bytes can be specified with the
command.
To obtain the entire log page, the len and parm_pointer fields must be set to zero.
To obtain the entire log page that starts at a specific parameter code, set the
parm_pointer field to the wanted code and the len field to zero. To obtain a
specific number of parameter bytes, set the parm_pointer field to the wanted code.
Then, set the len field to the number of parameter bytes plus the size of the log
page header (4 bytes). The first 4 bytes of returned data are always the log page
header. See the appropriate device manual to determine the supported log pages
and content. The data structure is
/* log sense page and subpage structure */
typedef struct {
uchar page_code; /* [IN] Log sense page */
uchar subpage_code; /* [IN] Log sense subpage */
uchar reserved[2]; /* unused */
unsigned short len; /* [OUT] number of valid bytes in data
(log_page_header_size + page_length) */
unsigned short parm_pointer; /* [IN] specific parameter number at which
the data begins */
char data[LOGSENSEPAGE]; /* [OUT] log data */
} log_sense10_page_t;
IOC_MODE_SENSE
This command returns a mode sense page from the device. The wanted page is
selected by specifying the page_code in the mode_sns_t structure.
The following data structure is filled out and returned by the driver.
typedef struct {
uchar page_code; /* page code */
uchar cmd_code; /* SCSI command code */
uchar data[253]; /* mode parameter list
}mode_sns_t;
int offset;
mode_sns_t mode_data;
mode_data.page_code = (uchar) page;
IOC_RESERVE
This command persistently reserves the device for exclusive use by the initiator.
The ATDD normally reserves the device in the open operation and releases the
device in the close operation. Issuing this command prevents the driver from
releasing the device during the close operation and the reservation is maintained
after the device is closed. This command is negated by issuing the IOC_RELEASE
IOCTL command.
else {
perror ("The IOC_RESERVE ioctl failed");
scsi_request_sense ();
}
IOC_RELEASE
This command releases the persistent reservation of the device for exclusive use by
the initiator. It negates the result of the IOC_RESERVE IOCTL command that is
issued either from the current or a previous open session.
IOC_PREVENT_MEDIUM_REMOVAL
This command prevents an operator from removing media from the tape drive or
the medium changer.
if (!(ioctl (dev_fd,IOC_PREVENT_MEDIUM_REMOVAL,NULL)))
printf ("The IOC_PREVENT_MEDIUM_REMOVAL ioctl succeeded \n");
else {
perror ("The IOC_PREVENT_MEDIUM_REMOVAL ioctl failed");
scsi_request_sense();
}
IOC_ALLOW_MEDIUM_REMOVAL
This command allows an operator to remove media from the tape drive and the
medium changer. This command is normally used after an
IOC_PREVENT_MEDIUM_REMOVAL command to restore the device to the default state.
if (!(ioctl (dev_fd,IOC_ALLOW_MEDIUM_REMOVAL,NULL)))
printf ("The IOC_ALLOW_MEDIUM_REMOVAL ioctl succeeded \n");
else {
perror ("The IOC_ALLOW_MEDIUM_REMOVAL ioctl failed");
scsi_request_sense();
}
IOC_GET_DRIVER_INFO
This command returns the information of the current installed ATDD.
The following data structure is filled out and returned by the driver.
typedef struct {
char driver_id[64]; /* the name of the tape driver (ATDD) */
char version[25]; /* the version of the tape driver */
} Get_driver_info_t;
get_driver_info_t get_driver_info;
These commands and associated data structures are defined in the smc.h header
file in the /usr/include/sys directory that is installed with the ATDD package. Any
application program that issues these commands must include this header file.
SMCIOC_MOVE_MEDIUM
This command transports a cartridge from one element to another element.
The following data structure is filled out and supplied by the caller.
typedef struct {
ushort robot; /* robot address */
ushort source; /* move from location */
ushort destination; /* move to location */
uchar invert; /* invert medium before insertion */
} move_medium_t;
move_medium_t move_medium;
move_medium.robot = 0;
move_medium.invert = NO_FLIP;
move_medium.source = src;
move_medium.destination = dst;
else {
perror ("The SMCIOC_MOVE_MEDIUM ioctl failed");
scsi_request_sense ();
}
SMCIOC_POS_TO_ELEM
This command moves the robot to an element.
The following data structure is filled out and supplied by the caller.
typedef struct {
ushort robot; /* robot address */
ushort destination; /* move to location */
uchar invert; /* invert medium before insertion */
} pos_to_elem_t;
pos_to_elem_t pos_to_elem;
pos_to_elem.robot = 0;
pos_to_elem.invert = NO_FLIP;
pos_to_elem.destination = dst;
else {
perror ("The SMCIOC_POS_TO_ELEM ioctl failed");
scsi_request_sense ();
}
SMCIOC_ELEMENT_INFO
This command requests the information about the device elements.
There are four types of medium changer elements. (Not all medium changers
support all four types.) The robot elements are associated with the cartridge
transport devices. The cell elements are associated with the cartridge storage slots.
The port elements are associated with the import/export mechanisms. The drive
elements are associated with the data transfer devices. The quantity of each
element type and its starting address is returned by the driver.
The following data structure is filled out and returned by the driver.
typedef struct {
ushort robot_address; /* medium transport element address */
ushort robot_count; /* number medium transport elements */
element_info_t element_info;
else {
perror ("The SMCIOC_ELEMENT_INFO ioctl failed");
scsi_request_sense ();
}
SMCIOC_INVENTORY
This command returns information about the medium changer elements (SCSI Read
Element Status command).
There are four types of medium changer elements. (Not all medium changers
support all four types.) The robot elements are associated with the cartridge
transport devices. The cell elements are associated with the cartridge storage slots.
The port elements are associated with the import/export mechanisms. The drive
elements are associated with the data transfer devices.
Note: The application must allocate buffers large enough to hold the returned
element status data for each element type. The SMCIOC_ELEMENT_INFO IOCTL
is called first to establish the criteria.
The following data structure is filled out and supplied by the caller.
typedef struct {
element_status_t *robot_status; /* medium transport element pages */
element_status_t *cell_status; /* medium storage element pages */
element_status_t *port_status; /* import/export element pages */
element_status_t *drive_status; /* data-transfer element pages */
} inventory_t;
One or more of the following data structures are filled out and returned to the user
buffer by the driver.
typedef struct {
ushort address; /* element address */
uchar : 2, /* reserved */
inenab : 1, /* medium in robot scope */
exenab : 1, /* medium not in robot scope */
access : 1, /* robot access allowed */
except : 1, /* abnormal element state */
impexp : 1, /* medium imported or exported */
full : 1; /* element contains medium */
uchar : 8; /* reserved */
uchar asc; /* additional sense code */
uchar ascq; /* additional sense code qualifier */
uchar notbus : 1, /* element not on same bus as robot */
ushort i;
element_info_t element_info;
inventory_t inventory;
if (!inventory.robot_status || !inventory.cell_status ||
!inventory.port_status || !inventory.drive_status) {
perror ("The SMCIOC_INVENTORY ioctl failed");
return;
}
else {
perror ("The SMCIOC_INVENTORY ioctl failed");
scsi_request_sense ();
}
SMCIOC_AUDIT
This command causes the medium changer device to run an audit of the element
status (SCSI Initialize Element Status command).
else {
perror ("The SMCIOC_AUDIT ioctl failed");
scsi_request_sense ();
}
SMCIOC_LOCK_DOOR
This command locks and unlocks the library access door. Not all IBM medium
changer devices support this operation.
The following data structure is filled out and supplied by the caller.
typedef uchar lock_door_t;
lock_door_t lock_door;
lock_door = LOCK;
else {
perror ("The SMCIOC_LOCK_DOOR ioctl failed");
scsi_request_sense ();
}
if (element_info.drive_count) {
elem_devid = malloc(element_info.drive_count * sizeof(element_devid_t));
if (elem_devid == NULL) {
printf ("The SMCIOC_READ_ELEMENT_DEVIDS ioctl failed:
Memory allocation failure.\n");
return (ENOMEM);
}
bzero(elem_devid, element_info.drive_count * sizeof(element_devid_t));
devids.drive_devid = elem_devid;
devids.element_address = element_info.drive_address;
devids.number_elements = element_info.drive_count;
free (elem_devid);
return (rc);
}
SMCIOC_EXCHANGE_MEDIUM
This IOCTL command exchanges a cartridge in an element with another cartridge.
This command is equivalent to two SCSI Move Medium commands. The first moves
the cartridge from the source element to the destination1 element. The second
moves the cartridge that was previously in the destination1 element to the
destination2 element. The destination2 element can be the same as the source
element.
SMCIOC_READ_CARTRIDGE_LOCATION
The SMCIOC_READ_CARTIDGE_LOCATION IOCTL is used to return the cartridge location
information for storage elements in the library. The element_address field specifies
the starting element address to return and the number_elements field specifies
how many storage elements are returned. The data field is a pointer to the buffer
for return data. The buffer must be large enough for the number of elements that
are returned. If the storage element contains a cartridge, then the ASCII identifier
field in return data specifies the location of the cartridge.
typedef struct
{
ushort element_address; /* starting element address */
ushort number_elements; /* number of elements */
cartridge_location_data_t *data; /* storage element pages */
char reserved[8]; /* reserved */
} read_cartridge_location_t;
int rc;
int available_slots=0;
cartridge_location_data_t *slot_devid;
read_cartridge_location_t slot_devids;
slot_devids.element_address = (ushort)element_address;
slot_devids.number_elements = (ushort)number_elements;
if (rc = ioctl(dev_fd,SMCIOC_ELEMENT_INFO,&element_info))
{
PERROR("SMCIOC_ELEMENT_INFO failed");
PRINTF("\n");
scsi_request_sense();
return (rc);
}
if (element_info.cell_count == 0)
{
printf("No slots found in element information...\n");
errno = EIO;
return errno;
}
available_slots = (element_info.cell_address+element_info.cell_count)
-slot_devids.element_address;
if (available_slots>slot_devids.number_elements)
available_slots=slot_devids.number_elements;
slot_devid = malloc(element_info.cell_count *
sizeof(cartridge_location_data_t));
if (slot_devid == NULL)
{
errno = ENOMEM;
return errno;
}
free(slot_devid);
return rc;
These commands and associated data structures are defined in the st.h header file
in the /usr/include/sys directory that is installed with the ATDD package. Any
application program that issues these commands must include this header file.
STIOC_TAPE_OP
This command runs standard tape drive operations. It is similar to the MTIOCTOP
IOCTL command defined in the/usr/include/sys/mtio.h system header file.
However, the STIOC_TAPE_OP command uses the ST_OP opcodes and the data
structure that is defined in the /usr/include/sys/st.h system header file. Most
STIOC_TAPE_OP IOCTL commands map to the MTIOCTOP IOCTL command. See
“MTIOCTOP” on page 151.
For all space operations, the resulting tape position is at the end-of-tape side of the
record or filemark for forward movement and at the beginning-of-tape side of the
record or filemark for backward movement.
The following data structure is filled out and supplied by the caller.
tape_op_t tape_op;
tape_op.st_op =st_op;
tape_op.st_count =st_count;
if (!(ioctl (dev_fd,STIOC_TAPE_OP,&tape_op))){
printf ("The STIOC_TAPE_OP ioctl succeeded.\n");
}
else {
perror ("The STIOC_TAPE_OP ioctl failed");
scsi_request_sense ();
}
STIOC_GET_DEVICE_STATUS
This command returns status information about the tape drive. It is similar to the
MTIOCGET IOCTL command defined in the /usr/include/sys/mtio.h system header
file. The STIOC_GET_DEVICE_STATUS and MTIOCGET commands both use the data
structure mtget defined in the /usr/include/sys/mtio.h system header file. The
STIOC_GET_DEVICE_STATUS IOCTL command maps to the MTIOCGET IOCTL
command. The two IOCTL commands are interchangeable. See “MTIOCGET” on
page 152.
The mt_flags field, which returns the type of automatic cartridge stacker or loader
that are installed on the tape drive, is set to one of the following values.
STF_ACL
Automatic Cartridge Loader.
STF_RACL
Random Access Cartridge Facility.
device_status_t device_status;
else {
perror ("The STIOC_GET_DEVICE_STATUS ioctl failed");
scsi_request_sense ();
}
device_info_t device_info;
else {
perror ("The STIOC_GET_DEVICE_INFO ioctl failed");
scsi_request_sense ();
}
STIOC_GET_MEDIA_INFO
This command returns information about the currently mounted tape.
The following data structure is filled out and returned by the driver.
typedef struct {
uint media_type; /* type of media loaded */
uint media_format; /* format of media loaded */
uchar write_protect; /* write protect (physical/logical) */
} media_info_t;
The media_type field, which returns the current type of media, is set to one of the
values in st.h.
The media_format field, which returns the current recording format, is set to one
of the values in st.h.
media_info_t media_info;
else {
perror ("The STIOC_GET_MEDIA_INFO ioctl failed");
scsi_request_sense ();
}
STIOC_GET_POSITION
This command returns information about the tape position.
The tape position is defined as where the next read or write operation occurs. The
STIOC_GET_POSITION and STIOC_SET_POSITION commands can be used
independently or with one another.
The following data structure is filled out and supplied by the caller (and also filled
out and returned by the driver).
typedef struct {
uchar block_type; /* block type (logical or physical) */
uchar bot; /* physical beginning of tape */
uchar eot; /* logical end of tape */
uchar partition; /* partition number */
uint position; /* current or new block ID */
uint last_block; /* last block written to tape */
uint block_count; /* blocks remaining in buffer */
uint byte_count; /* bytes remaining in buffer */
} position_data_t;
The block_type field is set to LOGICAL_BLK for standard SCSI logical tape
positions or PHYSICAL_BLK for composite tape positions. They are used for
high-speed locate operations that are implemented by the tape drive. Only the IBM
3490E Magnetic Tape Subsystem and the IBM TotalStorage Enterprise Virtual Tape
Servers (VTS) support the PHYSICAL_BLK type. All devices support the
LOGICAL_BLK type.
The block_type is the only field that must be filled out by the caller. The other
fields are ignored. Tape positions can be obtained with the STIOC_GET_POSITION
command, saved, and used later with the STIOC_SET_POSITION command to quickly
return to the same location on the tape.
The position field returns the current position of the tape (physical or logical).
The last_block field returns the last block of data that was transferred physically to
the tape.
The block_count field returns the number of blocks of data that remains in the
buffer.
The byte_count field returns the number of bytes of data that remains in the
buffer.
The bot and eot fields indicate whether the tape is positioned at the beginning of
tape or the end of tape, respectively.
position_data_t position_data;
position_data.block_type = type;
else {
perror ("The STIOC_GET_POSITION ioctl failed");
scsi_request_sense ();
}
STIOC_SET_POSITION
This command sets the physical position of the tape.
The tape position is defined as where the next read or write operation occurs. The
STIOC_GET_POSITION and STIOC_SET_POSITION commands can be used
independently or with one another.
The following data structure is filled out and supplied by the caller.
typedef struct {
uchar block_type; /* block type (logical or physical) */
uchar bot; /* physical beginning of tape */
uchar eot; /* logical end of tape */
uchar partition; /* partition number */
uint position; /* current or new block ID */
uint last_block; /* last block written to tape */
uint block_count; /* blocks remaining in buffer */
uint byte_count; /* bytes remaining in buffer */
} position_data_t;
The block_type field is set to LOGICAL_BLK for standard SCSI logical tape
positions. Or, it is set to PHYSICAL_BLK for composite tape positions that are
used for high-speed locate operations that are implemented by the tape drive.
Only the IBM 3490E Magnetic Tape Subsystem or a virtual drive in a VTS support
the PHYSICAL_BLK type. All devices support the LOGICAL_BLK type.
The block_type and position fields must be filled out by the caller. The other
fields are ignored. The type of position that is specified in the position field must
correspond with the type specified in the block_type field. Tape positions can be
obtained with the STIOC_GET_POSITION command, saved, and used later with the
STIOC_SET_POSITION command to quickly return to the same location on the tape.
The IBM 3490E Magnetic Tape Subsystem drives in VTSs do not support
set_position to eot.
position_data_t position_data;
position_data.block_type = type;
position_data.position = value;
STIOC_GET_PARM
This command returns the current value of the working parameter for the specified
tape drive. This command is used with the STIOC_SET_PARM command.
The following data structure is filled out and supplied by the caller (and also filled
out and returned by the driver).
typedef struct {
uchar type; /* type of parameter to get or set */
uint value; /* current or new value of parameter */
} parm_data_t;
The value field returns the current value of the specified parameter, within the
ranges that are indicated for the specific type.
The type field, which is filled out by the caller, must be set to one of the following
values.
BLOCKSIZE
Block Size (0–2097152 [2 MB]).
A value of zero indicates variable block size. Only the IBM 3590 Tape
System supports 2 MB maximum block size. All other devices support 256
KB maximum block size.
COMPRESSION
Compression Mode (0 or 1).
If this mode is enabled, data is compressed by the tape device before it is
stored on tape.
BUFFERING
Buffering Mode (0 or 1).
If this mode is enabled, data is stored in hardware buffers in the tape
device and not immediately committed to tape, thus increasing data
throughput performance.
IMMEDIATE
Immediate Mode (0 or 1).
If this mode is enabled, then a rewind command returns with the status
before the completion of the physical rewind operation by the tape drive.
TRAILER
Trailer Label Mode (0 or 1).
If this mode is enabled, then writing records past the early warning mark
on the tape is allowed. The first write operation to detect EOM returns 0.
This write operation does not complete successfully. All subsequent write
operations are allowed to continue despite the check conditions that result
from EOM. When the end of the physical volume is reached, EIO is
returned.
An application that uses the trailer label processing options must stop
normal data writing when LEOM (Logic End of Medium) is reached. Then,
it runs end of volume processing. Such processing typically consists of
Note: Only IBM 3590 and MP 3570 Tape Subsystems recognize the
following values:
v WORM_PROTECT
The tape is logically write protected in WORM mode. When the tape is
protected in this mode, it is permanently write protected. The only
method of returning the tape to a writable state is to format the
cartridge, erasing all data.
v PERS_PROTECT
The tape is logically write protected in PERSISTENT mode. A tape that
is protected in this mode is write protected for all uses (across mounts).
This logical write protection mode can be reset by using the
NO_PROTECT value.
v ASSC_PROTECT
The tape is logically write protected in ASSOCIATED mode. A tape that
is protected in this mode is write protected only while it is associated
with a tape drive (mounted). When the tape is unloaded from the drive,
the associated write protection is reset. This logical write protection
mode can also be reset by using the NO_PROTECT value.
ACFMODE
Automatic Cartridge Facility Mode.
parm_data_t parm_data;
parm_data.type = type;
else {
perror ("The STIOC_GET_PARM ioctl failed");
scsi_request_sense ();
}
STIOC_SET_PARM
This command sets the current value of the working parameter for the specified
tape drive. This command is used with the STIOC_GET_PARM command.
The ATDD ships with default settings for all configuration parameters. Changing
the working parameters dynamically through this STIOC_SET_PARM command affects
the tape drive only during the current open session. The working parameters
revert to the defaults when the tape drive is closed and reopened.
To change the default configuration settings, see the IBM TotalStorage and System
Storage Tape Device Drivers: Installation and User’s Guide.
The following data structure is filled out and supplied by the caller.
The value field specifies the new value of the specified parameter, within the
ranges that are indicated for the specific type.
The type field, which is filled out by the caller, can be set to one of the following
values.
BLOCKSIZE
Block Size (0–2097152 [2 MB]).
A value of zero indicates variable block size. Only the IBM 3590 Tape
System supports 2 MB maximum block size. All other devices support 256
KB maximum block size.
COMPRESSION
Compression Mode (0 or 1).
If this mode is enabled, data is compressed by the tape device before it is
stored on tape.
BUFFERING
Buffering Mode (0 or 1).
If this mode is enabled, data is stored in hardware buffers in the tape
device and not immediately committed to tape, thus increasing data
throughput performance.
IMMEDIATE
Immediate Mode (0 or 1).
If this mode is enabled, then a rewind command returns with the status
before the completion of the physical rewind operation by the tape drive.
TRAILER
Trailer Label Mode (0 or 1).
If this mode is enabled, then writing records past the early warning mark
on the tape is allowed. The first write operation to detect EOM returns
ENOSPC. This write operation does not complete successfully. All
subsequent write operations are allowed to continue despite the check
conditions that result from EOM. When the end of the physical volume is
reached, EIO is returned.
WRITEPROTECT
Write-protect Mode.
This configuration parameter establishes the current write protection status
of the mounted cartridge. The IBM Virtual Tape Server does not support
the write_protect mode to a logical cartridge. The parameter applies only
to the IBM 3590 and MP 3570 Tape Subsystems. The following values are
recognized.
v NO_PROTECT
The tape is not physically or logically write-protected. Operations that
alter the contents of the media are permitted. Setting the tape to this
value resets the PERSISTENT and ASSOCIATED logical write protection
modes. It does not reset the WORM logical or the PHYSICAL write
protection modes.
v WORM_PROTECT
parm_data_t parm_data;
parm_data.type = type;
parm_data.value = value;
else {
perror ("The STIOC_SET_PARM ioctl failed");
scsi_request_sense ();
}
STIOC_DISPLAY_MSG
This command displays and manipulates one or two messages on the tape drive
operator panel.
The message that is sent with this call does not always remain on the display. It
depends on the current drive activity.
Note: All messages must be padded to MSGLEN bytes (8). Otherwise, garbage
characters (meaningless data) are displayed in the message.
The following data structure is filled out and supplied by the caller.
typedef struct {
uchar function; /* message function code */
char msg_0[MSGLEN]; /* message 0 */
char msg_1[MSGLEN]; /* message 1 */
} msg_data_t;
The function field, which is filled out by the caller, is set by combining (by using
logical OR), a Message Type flag and a Message Control flag.
msg_data_t msg_data;
msg_data.function = GENSTATUS | ALTERNATE;
memcpy (msg_data.msg_0, "Hello ", 8);
memcpy (msg_data.msg_1, "World!!!", 8);
else {
perror ("The STIOC_DISPLAY_MSG ioctl failed");
scsi_request_sense ();
}
STIOC_SYNC_BUFFER
This command immediately flushes the drive buffers to the tape (commits the data
to the media).
else {
perror ("The STIOC_SYNC_BUFFER ioctl failed");
scsi_request_sense ();
}
The data structures that are used with this IOCTL are
typedef struct density_report
{
uchar primary_density_code; /* primary density code */
uchar secondary_density_code; /* secondary densuty code */
uchar wrtok : 1, /* write ok, device can write this format */
dup : 1, /* zero if density only reported once */
deflt : 1, /* current density is default format */
res_1 : 5; /* reserved */
uchar reserved1[2]; /* reserved */
uchar bits_per_mm[3]; /* bits per mm */
uchar media_width[2]; /* media width in millimeters */
uchar tracks[2]; /* tracks */
uchar capacity[4]; /* capacity in megabytes */
char assigning_org[8]; /* assigning organization in ASCII */
char density_name[8]; /* density name in ASCII */
char description[20]; /* description in ASCII */
} density_report_t;
int bits_per_mm = 0;
int media_width = 0;
int tracks = 0;
int capacity = 0;
density.media = ALL_MEDIA_DENSITY;
density.number_reports = 0;
printf("\n");
printf(" Density Name................. %0.8s\n",
density.reports[i].density_name);
printf(" Assigning Organization....... %0.8s\n",
density.reports[i].assigning_org);
printf(" Description.................. %0.20s\n",
density.reports[i].description);
printf(" Primary Density Code......... %02X\n",
density.reports[i].primary_density_code);
printf(" Secondary Density Code....... %02X\n",
density.reports[i].secondary_density_code);
if (density.reports[i].wrtok)
printf(" Write OK..................... Yes\n");
else
printf(" Write OK..................... No\n");
if (density.reports[i].dup)
printf(" Duplicate.................... Yes\n");
else
printf(" Duplicate.................... No\n");
if (density.reports[i].deflt)
printf(" Default...................... Yes\n");
else
printf(" Default...................... No\n");
if (interactive) {
printf ("\nHit <enter> to continue...");
getchar ();
}
printf("\n");
printf(" Density Name................. %0.8s\n",
density.reports[i].density_name);
printf(" Assigning Organization....... %0.8s\n",
density.reports[i].assigning_org);
printf(" Description.................. %0.20s\n",
density.reports[i].description);
printf(" Primary Density Code......... %02X\n",
density.reports[i].primary_density_code);
printf(" Secondary Density Code....... %02X\n",
density.reports[i].secondary_density_code);
if (density.reports[i].wrtok)
printf(" Write OK..................... Yes\n");
else
printf(" Write OK..................... No\n");
if (density.reports[i].dup)
printf(" Duplicate.................... Yes\n");
else
printf(" Duplicate.................... No\n");
if (density.reports[i].deflt)
printf(" Default...................... Yes\n");
else
printf(" Default...................... No\n");
if (interactive) {
printf ("\nHit <enter> to continue...");
getchar ();
}
return (rc);
}
The STIOC_SET_DENSITY IOCTL is used to set a new write density format on the
tape drive by using the default and pending density fields. The density code field
is not used and ignored on this IOCTL. The application can specify a new write
density for the current loaded tape only or as a default for all tapes. Refer to the
examples.
The application must get the current density settings first before the current
settings are modified. If the application specifies a new density for the current
loaded tape only, then the application must issue another set density IOCTL. This
action happens after the current tape is unloaded and the next tape is loaded to
either the default maximum density or a new density to ensure the tape drive uses
the correct density. If the application specifies a new default density for all tapes,
the setting remains in effect until changed by another set density IOCTL or the
tape drive is closed by the application.
Note:
1. These IOCTLs are supported only on tape drives that can write multiple
density formats. Refer to the Hardware Reference for the specific tape
drive to determine whether multiple write densities are supported. If the
tape drive does not support the IOCTLs, errno EINVAL is returned.
2. The device driver always sets the default maximum write density for the
tape drive on every open system call. Any previous STIOC_SET_DENSITY
IOCTL values from the last open are not used.
3. If the tape drive detects an invalid density code or cannot run the
operation on the STIOC_SET_DENSITY IOCTL, the errno is returned and the
current drive density settings before the IOCTL is restored.
4. The struct density_data_t defined in the header file is used for both
IOCTLs. The density_code field is not used and ignored on the
STIOC_SET_DENSITY IOCTL.
Examples
struct density_data_t data;
/* set 3592 J1A density format for current loaded tape only */
data.default_density = 0x7F;
data.pending_density = 0x51;
rc = ioctl(fd, STIOC_SET_DENSITY, &data);
/* unload tape */
/* load next tape */
/* set 3592 E05 density format for current loaded tape only */
data.default_density = 0x7F;
data.pending_density = 0x52;
rc = ioctl(fd, STIOC_SET_DENSITY, &data);
/* unload tape */
/* load next tape */
/* set default maximum density for current loaded tape */
data.default_density = 0;
data.pending_density = 0;
rc = ioctl(fd, STIOC_SET_DENSITY, &data);
GET_ENCRYPTION_STATE
This IOCTL command queries the drive's encryption method and state.
The data structure that is used for this IOCTL is as follows on all of the supported
operating systems.
typedef struct encryption_status {
uchar encryption_capable; /* Set this field as a boolean based on the
capability of the drive */
/* encryption_method used for GET ioctl only */
uchar encryption_method; /* Set this field to one of the defines below */
#define METHOD_NONE 0 /* Only used in GET_ENCRYPTION_STATE */
#define METHOD_LIBRARY 1 /* Only used in GET_ENCRYPTION_STATE */
#define METHOD_SYSTEM 2 /* Only used in GET_ENCRYPTION_STATE */
#define METHOD_APPLICATION 3 /* Only used in GET_ENCRYPTION_STATE */
#define METHOD_CUSTOM 4 /* Only used in GET_ENCRYPTION_STATE */
#define METHOD_UNKNOWN 5 /* Only used in GET_ENCRYPTION_STATE */
uchar encryption_state; /* Set this field to one of the defines below */
#define STATE_OFF 0 /* Used in GET/SET_ENCRYPTION_STATE */
#define STATE_ON 1 /* Used in GET/SET_ENCRYPTION_STATE */
#define STATE_NA 2 /* Used in GET_ENCRYPTION_STATE */
uchar reserved[13];
} encryption_status_t;
if(rc == 0) {
if(encryption_status_t.encryption_capable)
printf("encryption capable......Yes\n");
switch(encryption_status_t.encryption_state) {
case STATE_OFF:
printf("encryption state........OFF\n");
break;
case STATE_ON:
printf("encryption state........ON\n");
break;
case STATE_NA:
printf("encryption state........NA\n");
break;
default:
printf("encryption state......Error\n");
}
}
return rc;
}
SET_ENCRYPTION_STATE
This IOCTL command allows setting the encryption state only for
application-managed encryption. On unload, some of the drive settings can be
reset to default. To set the encryption state, the application must issue this IOCTL
after a tape is loaded and at BOP.
The data structure that is used for this IOCTL is the same as the one for
GET_ENCRYPTION_STATE.
return rc;
}
SET_DATA_KEY
This IOCTL command allows setting the data key only for application-managed
encryption.
The data structure that is used for this IOCTL is as follows on all of the supported
operating systems.
struct data_key {
uchar data_key_index[12]; /* The DKi */
uchar data_key_index_length; /* The DKi length */
uchar reserved1[15];
uchar data_key[32]; /* The DK */
uchar reserved2[48];
};
/* fill in your data key here, then issue the following ioctl*/
rc = ioctl(fd, SET_DATA_KEY, &encryption_status_t);
return rc;
}
QUERY_PARTITION
The QUERY_PARTITION IOCTL is used to return partition information for the tape
drive and the current media in the tape drive. The data includes the current active
partition the tape drive is using for the media. The number_of partitions field is
the current number of partitions on the media. The max_partitions is the
maximum partitions that the tape drive supports. The size_unit field can be either
one of the defined values. Or, it can be another value (such as 8) and is used with
the size array field value for each partition to specify the actual size partition sizes.
The partition_method field can be Wrap-wise Partitioning or Longitudinal
Partitioning. Refer to “CREATE_PARTITION” on page 142 for details.
int rc,i;
struct query_partition q_partition;
return rc;
CREATE_PARTITION
The CREATE_PARTITION IOCTL is used to format the current media in the tape drive
into 1 or more partitions. The number of partitions to create is specified in the
When the type field in the IOCTL structure is set to either FDP or SDP, the
size_unit and size fields in the IOCTL structure are not used. When the type field
in the IOCTL structure is set to IDP, the size_unit with the size fields are used to
specify the size for each partition.
There are two partition types in 3592 E07: Wrap-wise Partitioning (Figure 7) same
as LTO 5 optimized for streaming performance and Longitudinal Partitioning
(Figure 8) optimized for random access performance. Media is always partitioned
into 1 by default or more than one partition. The data partition always exists as
partition 0 and other extra index partition 1 to n can exist.
WORM media cannot be partitioned and the Format Medium commands are
rejected. Attempts to scale a partitioned media is accepted. However, only if you
use the correct FORMAT field setting, as part of scaling the volume is set to a
single data partition cartridge.
Partition 0
Guard wraps
Partition 1
Partition 2
a2500283
Partition 3
Guard gap
Partition 0 Partition 1
a2500284
The following chart lists the maximum number of partitions that the tape drive
supports.
2 in Longitudinal Partitioning
SET_ACTIVE_PARTITION
The SET_ACTIVE_PARTITION IOCTL is used to position the tape to a specific
partition. Then, it becomes the current active partition for subsequent commands
and a specific logical bock id in the partition. To position to the beginning of the
partition, the logical_block_id field must be set to 0.
ALLOW_DATA_OVERWRITE
The ALLOW_DATA_OVERWRITE IOCTL is used to set the drive to allow a subsequent
data write type command at the current position. Or, it allows a CREATE_PARTITION
IOCTL when data safe (append-only) mode is enabled.
data_overwrite.allow_format_overwrite = 1;
ioctl (dev_fd, ALLOW_DATA_OVERWRITE, &data_overwrite);
READ_TAPE_POSITION
The READ_TAPE_POSITION IOCTL is used to return Read Position command data in
either the short, long, or extended form. The type of data to return is specified by
setting the data_format field to either RP_SHORT_FORM, RP_LONG_FORM, or
RP_EXTENDED_FORM.
The data structures that are used with this IOCTL are
#define RP_SHORT_FORM 0x00
#define RP_LONG_FORM 0x06
#define RP_EXTENDED_FORM 0x08
struct short_data_format {
uchar bop:1, /* beginning of partition */
eop:1, /* end of partition */
locu:1, /* 1 means num_buffer_logical_obj field is unknown */
bycu:1, /* 1 means the num_buffer_bytes field is unknown */
svd :1,
lolu:1, /* 1 means the first and last logical obj position fields
are unknown */
err: 1, /* 1 means the position fields have overflowed and can not
be reported */
bpew :1; /* beyond programmable early warning */
uchar active_partition; /* current active partition */
char reserved[2];
uint first_logical_obj_position; /* current logical object position */
uint last_logical_obj_position; /* next logical object to be transferred to tape */
uint num_buffer_logical_obj; /* number of logical objects in buffer */
uint num_buffer_bytes; /* number of bytes in buffer */
char reserved1;
};
struct long_data_format {
struct extended_data_format {
uchar bop : 1, /* beginning of partition */
eop : 1, /* end of partition */
locu : 1, /* 1 means num_buffer_logical_obj field */
/* is unknown */
bycu : 1, /* 1 means the num_buffer_bytes field is */
/* unknown */
rsvd : 1,
lolu : 1, /* 1 means the first and last logical */
/* obj position fields are unknown */
perr : 1, /* 1 means the position fields have */
/* overflowed and can not be reported */
bpew : 1; /* beyond programmable early warning */
if (rpos.rp_data.rp_long.bop)
printf(" Beginning of Partition ..... Yes\n");
else
if (rpos.rp_data.rp_long.eop)
printf(" End of Partition ........... Yes\n");
else
printf(" End of Partition ........... No\n");
if (rpos.rp_data.rp_long.bpew)
printf(" Beyond Early Warning ... ... Yes\n");
else
printf(" Beyond Early Warning ....... No\n");
if (rpos.rp_data.rp_long.lonu)
{
printf(" Active Partition ........... UNKNOWN \n");
printf(" Logical Object Number ...... UNKNOWN \n");
}
else
{
printf(" Active Partition ... ....... %u \n",
rpos.rp_data.rp_long.active_partition);
printf(" Logical Object Number ...... %llu \n",
rpos.rp_data.rp_long.logical_obj_number);
}
if (rpos.rp_data.rp_long.mpu)
printf(" Logical File ID ............ UNKNOWN \n");
else
printf(" Logical File ID ............ %llu \n",
rpos.rp_data.rp_long.logical_file_id);
SET_TAPE_POSITION
The SET_TAPE_POSITION IOCTL is used to position the tape in the current active
partition to either a logical block id or logical filemark. The logical_id_type field in
the IOCTL structure specifies either a logical block or logical filemark.
struct set_tape_position{
uchar logical_id_type; /* Block or file as defined above */
ullong logical_id; /* logical object or logical file to position to */
char reserved[32];
};
QUERY_LOGICAL_BLOCK_PROTECTION
The IOCTL queries whether the drive can support this feature, what logical block
protection (LBP) method is used, and where the protection information is included.
SET_LOGICAL_BLOCK_PROTECTION
The IOCTL enables or disables Logical Block Protection, sets up what method is
used, and where the protection information is included.
The lbp_capable field is ignored in this IOCTL by the IBMtape driver. If the
lbp_method field is 0 (LBP_DISABLE), all other fields are ignored and not used.
When the lbp_method field is set to a valid non-zero method, all other fields are
used to specify the setup for LBP.
int rc;
struct logical_block_protection lbp_protect;
if (rc)
printf ("Set Logical Block Protection Fails (rc %d)",rc);
else
printf ("Set Logical Block Protection Succeeds");
Note:
1. The drive always expects a CRC attached with a data block when LBP is
enabled for lbp_r and lbp_w. Without the CRC bytes attachment, the
drive fails the Read and Write command. To prevent the CRC block
transfer between the drive and application, the maximum block size
limit must be determined by application.
2. The LBP setting is controlled by the application and not the device
driver. If an application enables LBP, it must also disable LBP when it
closes the drive, as this action is not done by the device driver.
VERIFY_TAPE_DATA
All parameters are INPUT parameters (specified by the programmer).
vte: verify to end of data
vlbpm: verify logical block protection information
vbf: verify by filemark
immed: return immediately, do not wait for command to complete
bytcmp: unused
fixed: verify the length of each logical block
Upon receiving this IOCTL, the tape drive runs the type of verification that is
specified by the parameters. It returns SUCCESS if data is correct or appropriate
sense data if the data is not correct.
typedef struct verify_data
{
uchar : 2, /* reserved */
} verify_data_t;
#include <sys/st.h>
int rc;
verify_data_t vrf_data;
memset(&vrf_data,0,sizeof(verify_data_t));
vrf_data.vte=1;
vrf_data.vlbpm=1;
vrf_data.vbf=0;
vrf_data.immed=0;
vrf_data.fixed=0;
vrf_data.verify_length=0;
These commands and associated data structures are defined in the mtio.h system
header file in the /usr/include/sys directory. Any application program that issues
these commands must include this header file.
MTIOCTOP
This command runs the magnetic tape drive operations. It is defined in
the/usr/include/sys/mtio.h header file. The MTIOCTOP commands use the MT
opcodes and the data structure that is defined in the mtio.h system header file.
Note: To compile the application code with the mtio.h and st.h on HP-UX 10.20,
the patch PHKL_22286 or later is requested.
For all space operations, the resulting tape position is at the end-of-tape side of the
record or filemark for forward movement. It is at the beginning-of-tape side of the
record or filemark for backward movement.
MTIOCGET
This command returns status information about the tape drive. It is identical to the
STIOC_GET_DEVICE_STATUS IOCTL command defined in the /usr/include/sys/st.h
header file. The STIOC_GET_DEVICE_STATUS and MTIOCGET commands both use the
data structure that is defined in the /usr/include/sys/mtio.h system header file. The
two IOCTL commands are interchangeable. See “STIOC_GET_DEVICE_STATUS”
on page 123.
These commands and associated data structures are defined in the svc.h header file
in the /usr/include/sys directory that is installed with the ATDD. Any application
program that issues these commands must include this header file.
STIOC_DEVICE_SN
This command queries the serial number of the device that is used by the IBM
3494 tape library and the IBM TotalStorage Enterprise Virtual Tape Server.
The following data structure is filled out and returned by the driver.
typedef uint device_sn_t;
device_sn_t device_sn;
STIOC_FORCE_DUMP
This command forces the device to run a diagnostic dump. The IBM 3490E
Magnetic Tape Subsystem and the IBM TotalStorage Enterprise VTS do not support
this command.
else {
perror ("Failure performing device dump");
scsi_request_sense ();
}
STIOC_STORE_DUMP
This command forces the device to write the diagnostic dump to the currently
mounted tape cartridge. The IBM 3490E Magnetic Tape Subsystem and the IBM
TotalStorage Enterprise VTS do not support this command.
else {
perror ("Failure storing dump on tape");
scsi_request_sense ();
}
STIOC_READ_BUFFER
This command reads data from the specified device buffer.
The following data structure is filled out and supplied by the caller.
typedef struct {
uchar mode; /* transfer mode */
uchar id; /* device buffer id */
uint offset; /* buffer offset */
uint size; /* byte count */
uchar *buffer; /* data buffer */
} buffer_io_t;
buffer_io_t buffer_io;
else {
perror ("Failure reading buffer");
scsi_request_sense ();
}
STIOC_WRITE_BUFFER
This command writes data to the specified device buffer.
The following data structure is filled out and supplied by the caller.
typedef struct {
uchar mode; /* transfer mode */
uchar id; /* device buffer id */
uint offset; /* buffer offset */
uint size; /* byte count */
uchar *buffer; /* data buffer */
} buffer_io_t;
buffer_io_t buffer_io;
else {
perror ("Failure writing buffer");
scsi_request_sense ();
}
STIOC_QUERY_PATH
This IOCTL returns the primary path and information for the first alternate path.
scsi_path_t path;
memset(&path, 0, sizeof(scsi_path_t));
printf("Querying SCSI paths...\n");
rc = ioctl(dev_fd, STIOC_QUERY_PATH, &path);
if(rc == 0)
show_path(&path);
#define MAX_SCSI_FAILOVER_PATH_DISPLAY 16
PRINTF("\n");
}
STIOC_ENABLE_PATH
This IOCTL enables the path that is specified by the path special file. This IOCTL
is supported only for a medium changer device.
if ((statbuf.st_rdev)&0xF00)
{
dev_t tempdev=(statbuf.st_rdev)&0xE00;
tempdev>>=1; // this is the same as shift left 1 and 0xF00
(statbuf.st_rdev)&=0xFFFFF0FF;
(statbuf.st_rdev)|=tempdev;
}
devt=statbuf.st_rdev;
STIOC_DISABLE_PATH
This IOCTL disables the path that is specified by the path special file. This IOCTL
is supported only for a medium changer device.
if (stat(path_name, &statbuf)!=0)
{
printf("Unable to stat path.\n");
return -1;
}
if ((statbuf.st_rdev)&0xF00)
{
dev_t tempdev=(statbuf.st_rdev)&0xE00;
tempdev>>=1; // this is the same as shift left 1 and 0xF00
(statbuf.st_rdev)&=0xFFFFF0FF;
(statbuf.st_rdev)|=tempdev;
}
devt=statbuf.st_rdev;
Software interface
Entry points
IBMtape supports the following Linux-defined entry points.
v “open”
v “close”
v “read” on page 162
v “write” on page 162
v “ioctl” on page 163
open
The programmer can access IBMtape devices with one of three access modes: write
only, read only, or read and write.
IBMtape also support the append open flag. When the open function is called with
the append flag set to TRUE, IBMtape attempts to rewind and seek two
consecutive filemarks and place the initial tape position between them. Open
append fails [errno: EIO] if no tape is loaded or there are not two consecutive
filemarks on the loaded tape. Open append does not automatically imply write
access. Therefore, an access mode must accompany the append flag during the
open operation.
The open function issues a SCSI reserve command to the target device. If the
reserve command fails, open fails and errno EBUSY is returned.
close
This entry point is driven explicitly by the close system call and implicitly by the
operating system at application program termination.
For non-rewinding special files, if the last tape command before the close function
is write, but the write fails with sense key 6 (Unit Attention) and ASC/ASCQ
29/00 (Power On, Reset, or Bus Device Reset Occurred) or sense key 6 and
For rewind devices, such as /dev/IBMtape0, if the last command before the close
function was a successful write, IBMtape writes two consecutive filemarks that
mark the end of data and issues a rewind command. If the last command before
the close function successfully wrote one filemark, one extra filemark is written
marking the end of data, and the rewind command is issued. If the write filemark
command fails, no rewind command is issued.
The application writers must be aware that a Unit Attention sense data that is
presented means that the tape medium might be in an indeterminate condition,
and no assumptions can be made about current tape positioning or whether the
medium that was previously in the drive is still in the drive. IBM suggests that
after a Unit Attention is presented, the tape special file be closed and reopened,
label processing/verification be run (to determine that the correct medium is
mounted), and explicit commands be run to locate to the wanted location. Extra
processing might also be needed for particular applications.
If an SIOC_RESERVE ioctl was issued from an application before close, the close
function does not release the device; otherwise, it issues the SCSI release
command. In both situations, the close function attempts to deallocate all resources
that are allocated for the device. If, for some reason, IBMtape is not able to close,
an error code is returned.
Note: The return code for close must always be checked. If close is unsuccessful,
retry is recommended.
read
This entry point is driven by the read system call. The read operation can be
completed when a tape is loaded in the device.
If the read function reaches end of the data on the tape, input/output error (EIO)
is returned and ASC, ASCQ keys (obtained by request sense IOCTLs) indicate the
end of data. IBMtape also conforms to all SCSI standard read operation rules, such
as fixed block versus variable block.
write
This entry point is driven by the write system call. The write operation can be
completed when a tape is loaded in the device.
ioctl
This entry point is driven explicitly by the close system call and implicitly by the
operating system at application program termination.
For non-rewinding special files, if the last tape command before the close function
is write, but the write fails with sense key 6 (Unit Attention) and ASC/ASCQ
29/00 (Power On, Reset, or Bus Device Reset Occurred) or sense key 6 and
ASC/ASCQ 28/00 (Not Ready to Ready Transition, Medium May Have Changed),
IBMtape does not write two consecutive tape file marks that mark the end of data
during close processing. If the last tape command before the close function is
write one file mark and that command fails with one of the above two errors,
IBMtape does not write one extra file mark that marks the end of data during close
processing.
For rewind devices, such as /dev/IBMtape0, if the last command before the close
function was a successful write, IBMtape writes two consecutive filemarks that
mark the end of data and issues a rewind command. If the last command before
the close function successfully wrote one filemark, one extra filemark is written
that marks the end of data, and the rewind command is issued. If the write
filemark command fails, no rewind command is issued.
The application writers must be aware that a Unit Attention sense data that is
presented means that the tape medium might be in an indeterminate condition. No
assumptions can be made about current tape positioning or whether the medium
that was previously in the drive is still in the drive. IBM suggests that after a Unit
Attention is presented, the tape special file be closed and reopened, label
processing/verification be completed (to determine that the correct medium is
mounted), and explicit commands be run to locate to the wanted location. Extra
processing might also be needed for particular applications.
open
This entry point is driven by the open system call. The open function attempts a
SCSI reserve command to the target device. If the reserve command fails, open
fails with errno EBUSY.
close
This entry point is driven explicitly by the close system call and implicitly by the
operating system at program termination. If an SIOC_RESERVE IOCTL was
issued from an application before close, the close function does not release the
device. Otherwise, it issues the SCSI release command. In both situations, the
close function attempts to deallocate all resources that are allocated for the device.
If, for some reason, IBMtape is not able to close, an error code is returned.
ioctl
This entry point provides a set of medium changer and SCSI-specific functions. It
allows Linux applications to access and control the features and attributes of the
robotic device programmatically.
These commands are available for all tape and medium changer devices. They can
be issued to any one of the IBMtape special files.
Overview
The following IOCTL commands are supported.
SIOC_INQUIRY
Return the inquiry data.
SIOC_REQSENSE
Return the sense data.
SIOC_RESERVE
Reserve the device.
SIOC_RELEASE
Release the device.
These IOCTL commands and their associated structures are defined in the
IBM_tape.h header file, which can be found in /usr/include/sys after IBMtape is
installed. The IBM_tape.h header file must be included in the corresponding C
programs that call functions that are provided by IBMtape.
All IOCTL commands require a file descriptor of an open file. Use the open
command to open a device and obtain a valid file descriptor.
SIOC_INQUIRY
This IOCTL command collects the inquiry data from the device.
SIOC_REQSENSE
This IOCTL command returns the device sense data. If the last command resulted
in an error, then the sense data is returned for the error. Otherwise, a new sense
command is issued to the device.
SIOC_RESERVE
This IOCTL command explicitly reserves the device and prevents it from being
released after a close operation.
The IOCTL command can be used for applications that require multiple open and
close processing in a host-sharing environment.
SIOC_RELEASE
This IOCTL command explicitly releases the device and allows other hosts to
access it. The IOCTL command is used with the SIOC_RESERVE IOCTL command for
applications that require multiple open and close processing in a host-sharing
environment.
SIOC_TEST_UNIT_READY
This IOCTL command issues the SCSI Test Unit Ready command to the device.
struct log_sense10_page {
unchar page_code;
| The first two IOCTLs are identical, except if a specific subpage is wanted,
log_sense10_page must be used and subpage_code must be assigned by the user
application.
The IOCTLs are identical, except that if a specific subpage is desired, mode_sense
must be used and subpage_code must be assigned by the user application. Under
the current implementation, cmd_code is not assigned by the user and must be left
with a value 0.
SIOC_INQUIRY_PAGE
This IOCTL command returns an inquiry page from the device. The desired page
is selected by specifying the page_code in the inquiry_page structure. See the
appropriate device manual to determine the supported inquiry pages and content.
SCSI_PASS_THROUGH
This IOCTL command passes the built command data block structure with I/O
buffer pointers to the lower SCSI layer. Status is returned from the lower SCSI
SCSI_DATA_OUT indicates sending data out of the initiator (host bus adapter), also
known as write mode. SCSI_DATA_IN indicates receiving data into the initiator (host
bus adapter), also known as read mode. SCSI_DATA_NONE indicates that no data is
transferred.
else {
printf(" Test Unit Ready failed\n");
if(PassThrough.SenseDataValid)
printf("Sense Key %02x, ASC %02x, ASCQ %02x\n",
PassThrough.SenseKey, PassThrough.ASC,
PassThrough.ASCQ);
}
}
else {
perror ("The SIOC SCSI_PASS_THROUGH ioctl failed");
sioc_request_sense();
}
SIOC_DEVICE_PATHS
This IOCTL command returns the primary path and all of the alternate paths
information for a physical device. This IOCTL supports only the 3592 tape drives.
The data structure for this IOCTL command is
struct device_path_t
{
char name[30]; /* logical device name */
char parent[30]; /* logical parent name */
unchar id_valid; /* SCSI id/lun/bus fields valid */
unchar id; /* SCSI target address of device */
unchar lun; /* SCSI logical unit of device */
unchar bus; /* SCSI bus for device */
struct device_paths
{
int number_paths; /* number of paths configured */
struct device_path_t path[MAX_SCSI_PATH];
};
if (device_path.path[i].id_valid)
{
printf(" SCSI Host ID.............. %d\n",device_path.path[i].host);
printf(" SCSI Channel.............. %d\n",device_path.path[i].bus);
printf(" Target ID................. %d\n",device_path.path[i].id);
printf(" Logical Unit.............. %d\n",device_path.path[i].lun);
}
if (device_path.path[i].enabled)
printf(" Path Enabled................... Yes\n");
else
printf(" Path Enabled................... No \n");
if (device_path.path[i].fenced)
printf(" Path Manually Disabled......... Yes\n");
else
printf(" Path Manually Disabled......... No \n");
printf("\n");
}
SIOC_ENABLE_PATH
This IOCTL enables the path that is specified by the path number. This command
supports only the 3592 tape drives.
SIOC_DISABLE_PATH
This IOCTL disables the path that is specified by the path number. This command
supports only the 3592 tape drives.
Overview
The following IOCTL commands are supported.
STIOCTOP
Run the basic tape operations.
STIOCQRYP
Query the tape device, device driver, and media parameters.
STIOCSETP
Change the tape device, device driver, and media parameters.
STIOCSYNC
Synchronize the tape buffers with the tape.
STIOCDM
Displays and manipulates one or two messages.
STIOCQRYPOS
Query the tape position and the buffered data.
STIOCSETPOS
Set the tape position.
STIOCQRYSENSE
Query the sense data from the tape device.
STIOCQRYINQUIRY
Return the inquiry data.
STIOC_LOCATE
Locate to a certain tape position.
These IOCTL commands and their associated structures are defined in the
IBM_tape.h header file that can be found in the lin_tape source rpm package. This
header must be included in the corresponding C program by using the IOCTL
commands.
STIOCTOP
This IOCTL command runs basic tape operations. The st_count variable is used for
many of its operations. Normal error recovery applies to these operations. The
device driver can issue several tries to complete them. For all forward movement
space operations, the tape position finishes on the end-of-tape side of the record or
filemark, and on the beginning-of-tape side of the record or filemark for backward
movement.
Note: If zero is used for operations that require the st_count parameter, then the
command is not issued to the device. The device driver returns a successful
completion.
STIOCQRYP or STIOCSETP
The STIOCQRYP command allows the program to query the tape device, device
driver, and the media parameters. The STIOCSETP command allows the program to
change the tape device, the device driver, and the media parameters.
Before the STIOCSETP command is issued, use the STIOCQRYP command to query
and fill the fields of the data structure you do not want to change. Then, issue the
STIOCSETP command to change the selected fields. Changing certain fields, such as
buffered_mode, impacts performance. If the buffered_mode field is FALSE, each
record that is written to the tape is immediately transferred to the tape. This
operation guarantees that each record is on the tape, but it impacts performance.
The following parameters that are returned by the STIOCQRYP command cannot be
changed by the STIOCSETP command.
hkwrd
This parameter is accepted but ignored.
logical_write_protect
This parameter sets the type of logical write protection for the tape that is
loaded in the drive.
write_protect
If the currently mounted tape is write protected, this field is set to TRUE.
Otherwise, it is set to FALSE.
min_blksize
This parameter is the minimum block size for the device. The driver gets
this field by issuing the SCSI Read Block Limits command to the device.
max_blksize
This parameter is the maximum block size for the device. The driver gets
this field by issuing the SCSI Read Block Limits command to the device.
retain_reservation
This parameter is accepted but ignored.
medium_type
This parameter is the media type of the currently loaded tape. Some tape
devices support multiple media types and report different values in this
field. See the hardware reference guide for the specific tape device to
determine the possible values.
capacity_scaling
This parameter sets the capacity or logical length of the current tape. By
reducing the capacity of the tape, the tape drive can access data faster.
Capacity Scaling is not currently supported in IBMtape.
density_code
This parameter is the density setting for the currently loaded tape. Some
tape devices support multiple densities and report the current setting in
this field. See the hardware reference guide for the specific tape device to
determine the possible values.
volid This field is always set to zero.
emulate_autoloader
This parameter is accepted but ignored.
record_space_mode
Only SCSI_SPACE_MODE is supported.
read_sili_bit
This parameter is accepted but ignored. SILI bit is not supported due to
Linux system environment limitations.
Changeable parameters
Note: All data on the cartridge is lost when the format is changed.
If you want to set it to the 300 GB format, set capacity_scaling_value to
0x00 and capacity_scaling to SCALE_VALUE. If you want to set it to the 60
GB Fast Access format, set capacity_scaling_value to 0x35 and
capacity_scaling to SCALE_VALUE. Setting capacity_scaling to
SCALE_VALUE is required.
STIOCSYNC
This IOCTL command immediately flushes the tape buffers to the tape. There are
no arguments for this IOCTL command.
STIOCDM
This IOCTL command shows and manipulates one or two messages on the
message display. The message that is sent with this call does not always remain on
the display. It depends on the current state of the tape device. Refer to the IBM
3590 manuals for a description of the message display functions.
STIOCQRYPOS
This command queries the tape position. Tape position is defined as the location
where the next read or write operation occurs. The query function can be used
independently of, or with, the STIOCSETPOS IOCTL command.
After a query operation, the curpos field is set to an unsigned integer that
represents the current position.
The eot field is set to TRUE if the tape is positioned between the early warning
and the physical end of the tape. Otherwise, it is set to FALSE.
The lbot field is valid only if the last command was a write command. If a query
is issued and the last command was not a write, lbot contains the value
LBOT_UNKNOWN.
Note: lbot indicates the last block of data that is transferred to the tape.
The number of blocks and number of bytes currently in the tape device buffers is
returned in the num_blocks and num_bytes fields.
The bot field is set to TRUE if the tape position is at the beginning of the tape.
Otherwise, it is set to FALSE.
The returned partition_number field is the current partition of the loaded tape.
The block ID of the next block of data to be transferred to or from the physical
tape is returned in the tapepos field.
stpos.curpos=oldposition;
stpos.block_type=QP_LOGICAL;
if (ioctl(tapefd,STIOCSETPOS,&stpos)) {
printf("ioctl failure. errno=%d",errno);
exit(errno);
}
STIOCQRYSENSE
This IOCTL command returns the last sense data that is collected from the tape
device. Or, it issues a new Request Sense command and returns the collected data.
If sense_type equals LASTERROR, then the sense data is valid only if the last tape
operation had an error that caused a sense command to be issued to the device. If
the sense data is valid, then the IOCTL command finishes successfully, and the len
field is set to a value greater than zero. The residual_count field contains the
residual count from the last operation.
STIOCQRYINQUIRY
This IOCTL command returns the inquiry data from the device. The data is
divided into standard and vendor-specific portions.
STIOC_LOCATE
This IOCTL command causes the tape to be positioned at the specified block ID.
The block ID used for the command must be obtained by using the
STIOC_READ_POSITION command.
STIOC_READ_POSITION
This IOCTL command returns the block ID of the current position of the tape. The
block ID returned from this command can be used with the STIOC_LOCATE
command to set the position of the tape.
STIOC_PREVENT_MEDIUM_REMOVAL
This IOCTL command prevents an operator from removing media from the device
until the STIOC_ALLOW_MEDIUM_REMOVAL command is issued or the device is reset.
STIOC_ALLOW_MEDIUM_REMOVAL
This IOCTL command allows an operator to remove media from the device. This
command is normally used after the STIOC_PREVENT_MEDIUM_REMOVAL command to
restore the device to the default state.
STIOC_REPORT_DENSITY_SUPPORT
This IOCTL command issues the SCSI Report Density Support command to the
tape device. It returns either ALL supported densities or only supported densities
for the currently mounted media. The media field specifies which type of report is
requested. The number_reports field is returned by the device driver and indicates
how many density reports in the reports array field were returned.
struct report_density_support {
unchar media; /* report all or current media as defined above */
ushort number_reports; /* number of density reports returned in array */
struct density_report reports[MAX_DENSITY_REPORTS];
};
The application must get the current density settings first before the current
settings are modified. If the application specifies a new density for the current
loaded tape only, then the application must issue another set density IOCTL after
the current tape is unloaded and the next tape is loaded to either the default
maximum density or a new density to ensure the tape drive uses the correct
density. If the application specifies a new default density for all tapes, the setting
remains in effect until changed by another set density IOCTL or the tape drive is
closed by the application.
Note:
1. These IOCTLs are supported only on tape drives that can write multiple
density formats. Refer to the Hardware Reference for the specific tape
drive to determine whether multiple write densities are supported. If the
tape drive does not support these IOCTLs, errno EINVAL is returned.
2. The device driver always sets the default maximum write density for the
tape drive on every open system call. Any previous STIOC_SET_DENSITY
IOCTL values from the last open are not used.
3. If the tape drive detects an invalid density code or cannot run the
operation on the STIOC_SET_DENSITY IOCTL, the errno is returned and the
current drive density settings before the IOCTL are restored.
4. The struct density_data_t defined in the header file is used for both
IOCTLs. The density_code field is not used and ignored on the
STIOC_SET_DENSITY IOCTL.
Examples
struct density_data_t data;
GET_ENCRYPTION_STATE
This IOCTL command queries the drive's encryption method and state. The data
structure that is used for this IOCTL is as follows on all of the supported operating
systems
struct encryption_status
{
uchar encryption_capable; /* (1)Set this field as a boolean based on the
capability of the drive */
uchar encryption_method; /* (2)Set this field to one of the following */
#define METHOD_NONE 0 /* Only used in GET_ENCRYPTION_STATE */
#define METHOD_LIBRARY 1 /* Only used in GET_ENCRYPTION_STATE */
#define METHOD_SYSTEM 2 /* Only used in GET_ENCRYPTION_STATE */
#define METHOD_APPLICATION 3 /* Only used in GET_ENCRYPTION_STATE */
#define METHOD_CUSTOM 4 /* Only used in GET_ENCRYPTION_STATE */
#define METHOD_UNKNOWN 5 /* Only used in GET_ENCRYPTION_STATE */
default:
printf("encrption method.......Error\n");
}
switch(encryption_status_t.encryption_state)
{
case STATE_OFF:
printf("encryption state........OFF\n");
break;
case STATE_ON:
printf("encryption state........ON\n");
break;
case STATE_NA:
printf("encryption state........NA\n");
break;
default:
printf("encryption state......Error\n");
}
}
return rc;
}
SET_ENCRYPTION_STATE
This IOCTL command allows setting the encryption state only for
application-managed encryption. On unload, some drive settings might be reset to
default. To set the encryption state, the application must issue this IOCTL after a
tape is loaded and at BOP.
The data structure that is used for this IOCTL is the same as the one for
GET_ENCRYPTION_STATE. An example of the SET_ENCRYPTION_STATE command is
int set_encryption_state(int option)
{
int rc = 0;
struct encryption_status encryption_status_t;
if(option == 0)
encryption_status_t.encryption_state = STATE_OFF;
else if(option == 1)
encryption_status_t.encryption_state = STATE_ON;
else
{
printf("Invalid parameter.\n");
return -EINVAL;
}
return rc;
}
SET_DATA_KEY
This IOCTL command allows set the data key only for application-managed
encryption. The data structure that is used for this IOCTL is as follows on all of
the supported operating systems.
struct data_key
{
uchar[12] data_key_index;
uchar data_key_index_length;
uchar[15] reserved1;
uchar[32] data_key;
uchar[48] reserved2;
};
STIOC_QUERY_PARTITION
This IOCTL queries and displays information for tapes that support partitioning.
The data structure that is used for this IOCTL is
#define MAX_PARTITIONS 255
struct query_partition {
unchar max_partitions;
unchar active_partition;
unchar number_of_partitions;
unchar size_unit;
ushort size[MAX_PARTITIONS];
char reserved[32];
};
if(rc) {
printf("Query partition failed: %d\n", rc);
goto EXIT_LABEL;
} /* if */
EXIT_LABEL:
return rc;
} /* stioc_query_partition() */
STIOC_CREATE_PARTITION
This IOCTL creates partitions on tapes that support partitioning. The data structure
that is used for this IOCTL is
#define IDP_PARTITION (1)
#define SDP_PARTITION (2)
#define FDP_PARTITION (3)
struct tape_partition {
unchar type;
unchar number_of_partitions;
unchar size_unit;
ushort size[MAX_PARTITIONS];
char reserved[32];
};
crt.type = atoi(input);
crt.number_of_partitions = atoi(input);
printf("Issuing IOCTL...\n");
rc = ioctl(fd, STIOC_CREATE_PARTITION, &crt);
if(rc) {
printf("Create partition failed: %d\n", rc);
goto EXIT_LABEL;
} /* if */
EXIT_LABEL:
if(input) free(input);
return rc;
} /* stioc_create_partition() */
STIOC_SET_ACTIVE_PARTITION
This IOCTL allows the user to specify the partition on which to run subsequent
tape operations. The data structure that is used for this IOCTL is
struct set_active_partition {
unchar partition_number;
unsigned long long logical_block_id;
char reserved[32];
};
printf("Issuing IOCTL...\n");
rc = ioctl(fd, STIOC_SET_ACTIVE_PARTITION, &set);
if(rc) {
printf("Set partition failed: %d\n", rc);
EXIT_LABEL:
if(input) free(input);
return rc;
} /* stioc_set_partition() */
STIOC_ALLOW_DATA_OVERWRITE
This IOCTL allows data on the tape to be overwritten when in data safe mode. The
data structure that is used for this IOCTL is
struct allow_data_overwrite {
unchar partition_number;
unsigned long long logical_block_id;
unchar allow_format_overwrite;
char reserved[32];
};
ado.allow_format_overwrite = atoi(&input[0]);
switch(ado.allow_format_overwrite) {
case 0:
memset(input, ’\0’, DEF_BUF_SIZE / 4);
while((input[0] < ’0’ || input[0] > ’9’)
&& (input[0] < ’a’ || input[0] > ’f’)) {
brk = FALSE;
printf("Enter partition in hex (< 0 to cancel): 0x");
fgets(input, DEF_BUF_SIZE / 4, stdin);
while(strlen(input) &&
isspace(input[strlen(input) - 1]))
input[strlen(input) - 1] = ’\0’;
if(!strlen(input)) continue;
} /* while */
ado.partition_number = char_to_hex(input);
while(strlen(input) &&
isspace(input[strlen(input) - 1]))
input[strlen(input) - 1] = ’\0’;
if(!strlen(input)) continue;
} /* while */
ado.logical_block_id = char_to_hex(input);
break;
case 1:
break;
default:
assert(!"Unreachable.");
} /* switch */
printf("Issuing IOCTL...\n");
if(rc) {
printf("Allow data overwrite failed: %d\n", rc);
goto EXIT_LABEL;
} /* if */
EXIT_LABEL:
if(input) free(input);
return rc;
} /* stioc_allow_overwrite() */
STIOC_READ_POSITION_EX
This IOCTL returns tape position with support for the short, long, and extended
formats. The definitions and data structures that are used for this IOCTL follow.
See the READ_POSITION section of your tape drive’s SCSI documentation for
details on the short_data_format, long_data_format, and extended_data_format
structures.
#define RP_SHORT_FORM (0x00)
#define RP_LONG_FORM (0x06)
#define RP_EXTENDED_FORM (0x08)
struct short_data_format {
#if defined __LITTLE_ENDIAN
unchar bpew : 1;
unchar perr : 1;
unchar lolu : 1;
unchar rsvd : 1;
unchar bycu : 1;
unchar locu : 1;
unchar eop : 1;
unchar bop : 1;
#elif defined __BIG_ENDIAN
unchar bop : 1;
unchar eop : 1;
unchar locu : 1;
unchar bycu : 1;unchar rsvd : 1;
unchar lolu : 1;
unchar perr : 1;
unchar bpew : 1;
#else
error
#endif
unchar active_partition;
char reserved[2];
unchar first_logical_obj_position[4];
unchar last_logical_obj_position[4];
unchar num_buffer_logical_obj[4];
unchar num_buffer_bytes[4];
char reserved1;
};
struct long_data_format {
#if defined __LITTLE_ENDIAN
unchar bpew : 1;
unchar rsvd2 : 1;
unchar lonu : 1;
unchar mpu : 1;
unchar rsvd1 : 2;
unchar eop : 1;
unchar bop : 1;
#elif defined __BIG_ENDIAN
unchar bop : 1;
struct extended_data_format {
#if defined __LITTLE_ENDIAN
unchar bpew : 1;
unchar perr : 1;
unchar lolu : 1;
unchar rsvd : 1;
unchar bycu : 1;
unchar locu : 1;
unchar eop : 1;
unchar bop : 1;
#elif defined __BIG_ENDIAN
unchar bop : 1;
unchar eop : 1;
unchar locu : 1;
unchar bycu : 1;
unchar rsvd : 1;
unchar lolu : 1;
unchar perr : 1;
unchar bpew : 1;
#else
error
#endif
unchar active_partition;
unchar additional_length[2];
unchar num_buffer_logical_obj[4];
unchar first_logical_obj_position[8];
unchar last_logical_obj_position[8];
unchar num_buffer_bytes[8];
unchar reserved;
};
struct read_tape_position {
unchar data_format;
union {
struct short_data_format rp_short;
struct long_data_format rp_long;
struct extended_data_format rp_extended;
} rp_data;
};
data_format is the format in which you want to receive your data, as defined here.
It can take the value RP_SHORT_FORM, RP_LONG_FORM, or RP_EXTENDED_FORM. When the
IOCTL finishes, data is returned to the corresponding structure within the rp_data
union.
switch(atoi(input)) {
case 1:
rp.data_format = RP_SHORT_FORM;
break;
case 2:
rp.data_format = RP_LONG_FORM;
break;
case 3:
rp.data_format = RP_EXTENDED_FORM;
break;
default:
rc = EINVAL;
goto EXIT_LABEL;
} /* switch */
if(rc) {
printf("Cannot get position: %d\n", rc = errno);
goto EXIT_LABEL;
} /* if */
print_read_position_ex(&rp);
EXIT_LABEL:
if(input) free(input);
return rc;
} /* stioc_read_position_ex() */
STIOC_LOCATE_16
This IOCTL sets the tape position by using the long tape format. The definitions
and structure that are used for this IOCTL are
#define LOGICAL_ID_BLOCK_TYPE (0x00)
#define LOGICAL_ID_FILE_TYPE (0x01)
struct set_tape_position {
pos.logical_id_type = filetype;
pos.logical_id = (long long) blockid;
STIOC_QUERY_BLK_PROTECTION
This IOCTL queries capability and status of the drive's Logical Block Protection.
The structures and defines are
#define LBP_DISABLE (0x00)
#define REED_SOLOMON_CRC (0x01)
struct logical_block_protection {
unchar lbp_capable;
unchar lbp_method;
unchar lbp_info_length;
unchar lbp_w;
unchar lbp_r;
unchar rbdp;
unchar reserved[26];
};
The lbp_capable is set to True if the drive supports logical block protection, or
False otherwise.
The lbp_w indicates that logical block protection is run for write commands. The
lbp_r indicates that logical block protection is run for read commands. The rbdp
indicates that logical block protection is run for recover buffer data. To use this
IOCTL, issue the following call.
rc = ioctl(fd, STIOC_QUERY_BLK_PROTECTION, &lbp);
STIOC_VERIFY_TAPE_DATA
This IOCTL instructs the tape drive to scan the data on its current tape to check for
errors. The structure is defined as follows.
struct verify_data {
vte instructs the drive to verify from the current tape head position to end of data.
vlbpm instructs the drive to verify that the logical block protection method that is
specified in the Control Data Protection mode page is used for each block.
If vbf is set, then the verify_length field contains the number of filemarks to be
traversed, rather than the number of blocks or bytes.
bytcmp is set to 0.
struct {
char* desc;
int idx;
} table[] = {
{"Verify to EOD", VFY_VTE},
{"Verify Logical Block Protection", VFY_VLBPM},
{"Verify by Filemarks", VFY_VBF},
{"Return immediately", VFY_IMMED},
{"Fixed", VFY_FIXED},
{NULL, 0}
};
printf("\n");
for(i = 0; table[i].desc; i++) {
while(tolower(input[0]) != ’y’ && tolower(input[0]) != ’n’) {
printf("%s (y/n/c to cancel)? ", table[i].desc);
fgets(input, DEF_BUF_SIZE / 16, stdin);
if(tolower(input[0]) == ’c’) {
rc = 0;
goto EXIT_LABEL;
} /* if */
} /* while */
if(tolower(input[0]) == ’y’) {
switch(table[i].idx) {
case VFY_VTE: vfy->vte = 1; break;
case VFY_VLBPM: vfy->vlbpm = 1; break;
case VFY_VBF: vfy->vbf = 1; break;
case VFY_IMMED: vfy->immed = 1; break;
default: break;
} /* switch */
} /* if */
memset(input, ’\0’, DEF_BUF_SIZE / 16);
} /* for */
if(!vfy->vte) {
while(cont) {
cont = FALSE;
if(!strlen(input)) {
cont = TRUE;
if(tolower(input[0]) == ’c’) {
rc = 0;
goto EXIT_LABEL;
} /* if */
} /* while */
len = atoi(input);
vfy->verify_length[0] = (len >> 16) & 0xFF;
vfy->verify_length[1] = (len >> 8) & 0xFF;
vfy->verify_length[2] = len & 0xFF;
} /* if */
EXIT_LABEL:
if(input) free(input);
if(vfy) free(vfy);
return rc;
} /* stioc_verify() */
| STIOC_QUERY_RAO
| The IOCTL is used to query the maximum number and size of User Data Segments
| (UDS) that are supported from tape drive and driver for the wanted uds_type.
| STIOC_GENERATE_RAO
| The IOCTL is called to send a GRAO list to request that the drive generate a
| Recommended Access Order list. The process method is either 1 or 2 to create a
| RAO list, and the type of UDS is either with or without the geometry. The
| uds_number must be not larger than max_host_uds_number in the
| STIOC_QUERY_RAO IOCTL. The application allocates a block of memory with
| grao_list_leng (uds_number*sizeof(struct grao_uds_desc)+8) for the pointer of
| grao_list.
| The grao list header and UDS segments make up the parameter data and are to be
| put in the following order.
| -- List Header
| -- UDS Segment Descriptor (first)
| ......
| -- UDS Segment Descriptor (last)
| The device driver does not supply the header or UDS segment Descriptor
| structures. That structure is to be supplied by the application.
| A sample of STIOC_GENERATE_RAO is
| #include<sys/IBM_tape.h>
|
| int rc;
| struct generate_rao grao;
| bzero(&grao,sizeof(struct generate_rao));
| grao.process=2;
| grao.uds_type=uds_type;
| grao.grao_list_leng=max_host_uds_num * sizeof(struct grao_uds_desc)
| + sizeof(struct grao_list_header);
| if(!(grao.grao_list=malloc(grao.grao_list_leng)))
| {
| perror("Failure allocating memory");
| return (errno);
| }
|
| memset(grao.grao_list, 0, grao.grao_list_leng);
|
| rc=ioctl(fd,GENERATE_RAO,&grao);
|
| if (rc)
| printf("GENERATE_RAO fails with rc%d\n",rc);
| else
| printf("GENERATE_RAO succeeds\n");
|
| free(grao.grao_list);
|
| return rc;
| STIOC_RECEIVE_RAO
| After a STIOC_GENERATE_RAO IOCTL is completed, the application calls the
| STIOC_RECEIVE_RAO IOCTL to receive a recommended access order of UDS from the
| drive. To avoid a system crash, it is important that the application allocates a large
| enough block of memory for the *rrao_list pointer and notifies the driver of the
| allocated size. It is done by indicating the size of the buffer in bytes to the
| rrao_list_leng variable as an input to the receive_rao_list structure.
MTIOCTOP
This IOCTL command is similar in function to the st MTIOCTOP command. It is
provided as a convenience for precompiled programs that call that IOCTL
command. Refer to /usr/include/sys/mtio.h or /usr/include/linux/mtio.h for
information on the MTIOCTOP command.
MTIOCGET
This IOCTL command is similar in function to the st MTIOCGET command. It is
provided as a convenience for precompiled programs that call that IOCTL
command. Refer to /usr/include/sys/mtio.h or /usr/include/linux/mtio.h for
information on the MTIOCGET command.
MTIOCPOS
This IOCTL command is similar in function to the st MTIOCPOS command. It is
provided as a convenience for precompiled programs that call that IOCTL
command. Refer to /usr/include/sys/mtio.h or /usr/include/linux/mtio.h for
information on the MTIOCPOS command.
SMCIOC_ELEMENT_INFO
This IOCTL command obtains the device element information.
SMCIOC_MOVE_MEDIUM
This IOCTL command moves a cartridge from one element to another element.
SMCIOC_EXCHANGE_MEDIUM
This IOCTL command exchanges a cartridge in an element with another cartridge.
This command is equivalent to two SCSI Move Medium commands. The first moves
the cartridge from the source element to the destination1 element. The second
moves the cartridge that was previously in the destination1 element to the
destination 2 element. This function is available only in the IBM 3584 UltraScalable
tape library. The destination2 element can be the same as the source element.
SMCIOC_POS_TO_ELEM
This IOCTL command moves the robot to an element.
SMCIOC_INIT_ELEM_STAT
This IOCTL command instructs the medium changer robotic device to issue the
SCSI Initialize Element Status command.
Note: Use the SMCIOG_INVENTORY IOCTL command to obtain the current version
after this IOCTL command is issued.
SMCIOC_INVENTORY
This IOCTL command returns the information about the four element types. The
software application processes the input data (the number of elements about which
it requires information). Then, it allocates a buffer large enough to hold the output
for each element type.
SMCIOC_UNLOAD_MEDIUM
This IOCTL command moves a tape from the drive and returns it to a specific slot.
Or, it moves a tape to the first empty slot in the magazine if the slot address is
specified as zero. An unload/offline command must be sent to the tape first,
otherwise, this IOCTL command fails with errno EIO.
SMCIOC_PREVENT_MEDIUM_REMOVAL
This IOCTL command prevents an operator from removing medium from the
device until the SMCIOC_ALLOW_MEDIUM_REMOVAL command is issued or the device is
reset. There is no associated data structure.
SMCIOC_ALLOW_MEDIUM_REMOVAL
This IOCTL command allows an operator to remove medium from the device. This
command is normally used after an SMCIOC_PREVENT_MEDIUM_REMOVAL command to
restore the device to the default state. There is no associated data structure.
SMCIOC_READ_ELEMENT_DEVIDS
This IOCTL command issues the SCSI Read Element Status command with the
device ID(DVCID) bit set and returns the element descriptors for the data transfer
elements. The element_address field specifies the starting address of the first data
transfer element. The number_elements field specifies the number of elements to
return. The application must allocate a return buffer large enough for the number
of elements that are specified in the input structure.
Return codes
This chapter describes error codes that are generated by IBMtape when an error
occurs during an operation. On error, the operation returns negative one (-1), and
the external variable errno is set to one of the listed error codes. Errno values are
defined in /usr/include/errno.h (and other files that it includes). Application
programs must include errno.h to interpret the return codes.
Note: For error code EIO, an application can retrieve more information from the
device itself. Issue the STIOCQRYSENSE IOCTL command when the sense_type
equals LASTERROR, or the SIOC_REQSENSE IOCTL command, to retrieve
sense data. Then, analyze the sense data by using the appropriate hardware
or SCSI reference for that device.
[EACCES] The open requires write access when the cartridge loaded in the
drive is physically write-protected.
[EAGAIN] The device was already open when an open was attempted.
[EBUSY] The device was reserved by another initiator or an excessively
busy state was encountered.
[EINVAL] The operation that is requested has invalid parameters or an
invalid combination of parameters, or the device is rejecting open
commands.
The IOCTL operations supported by the Solaris tape and medium changer device
driver support are described in
v “General SCSI IOCTL operations”
v “SCSI medium changer IOCTL operations” on page 234
v “SCSI tape drive IOCTL operations” on page 244
v “Base operating system tape drive IOCTL operations” on page 282
v “Downward compatibility tape drive IOCTL operations” on page 286
v “Service aid IOCTL operations” on page 292
These commands and associated data structures are defined in the st.h and smc.h
header files in the /usr/include/sys directory that is installed with the IBMtape
package. Any application program that issues these commands must include this
header file.
IOC_TEST_UNIT_READY
This command determines whether the device is ready for operation.
else {
perror ("The IOC_TEST_UNIT_READY ioctl failed");
scsi_request_sense ();
}
IOC_INQUIRY
This command collects the inquiry data from the device.
The following data structure is filled out and returned by the driver.
typedef struct {
uchar qual : 3, /* peripheral qualifier */
type : 5; /* device type */
uchar rm : 1, /* removable medium */
mod : 7; /* device type modifier */
uchar iso : 2, /* ISO version */
ecma : 3, /* ECMA version */
ansi : 3; /* ANSI version */
uchar aen : 1, /* asynchronous even notification */
trmiop : 1, /* terminate I/O process message */
: 2, /* reserved */
rdf : 4; /* response data format */
uchar len; /* additional length */
uchar : 8; /* reserved */
uchar : 4, /* reserved */
mchngr : 1, /* medium changer mode */
: 3; /* reserved */
uchar reladr : 1, /* relative addressing */
wbus32 : 1, /* 32-bit wide data transfers */
wbus16 : 1, /* 16-bit wide data transfers */
sync : 1, /* synchronous data transfers */
linked : 1, /* linked commands */
: 1, /* reserved */
cmdque : 1, /* command queueing */
sftre : 1; /* soft reset */
inquiry_data_t inquiry_data;
else {
perror ("The IOC_INQUIRY ioctl failed");
scsi_request_sense ();
}
IOC_INQUIRY_PAGE
This command returns the inquiry data for a special page from the device.
The following data structures for inquiry page x80 are filled out and returned by
the driver.
typedef struct {
uchar page_code; /*page code */
uchar data [253 ]; /*inquiry parameter List */
}inquiry_page_t;
typedef struct {
uchar page_code; /*page code */
uchar data [253 ]; /*inquiry parameter List */
}inquiry_page_t;
typedef struct {
uchar periph_qual :3, /*peripheral qualifier */
periph_type :5; /*peripheral device type */
uchar page_code; /*page code */
uchar reserved_1; /*reserved */
uchar page_len; /*page length */
uchar serial [12 ]; /*serial number */
}inq_pg_80_t;
inquiry_page_t inquiry_page;
inquiry_page.page_code =(uchar)page;
The following data structure is filled out and returned by the driver.
typedef struct {
uchar valid : 1, /* sense data is valid */
code : 7, /* error code */
uchar segnum; /* segment number */
uchar fm : 1, /* filemark detected */
eom : 1, /* end of media */
ili : 1, /* incorrect length indicator */
: 1, /* reserved */
key : 4; /* sense key */
uchar info[4]; /* information bytes */
uchar addlen; /* additional sense length */
uchar cmdinfo[4]; /* command-specific information */
uchar asc; /* additional sense code */
uchar ascq; /* additional sense code qualifier */
uchar fru; /* field-replaceable unit code */
uchar sksv : 1, /* sense key specific valid */
cd : 1, /* control/data */
: 2, /* reserved */
bpv : 1, /* bit pointer valid */
sim : 3; /* system information message */
uchar field[2]; /* field pointer */
uchar vendor[110]; /* vendor specific (padded to 128) */
} sense_data_t;
sense_data_t sense_data;
IOC_LOG_SENSE_PAGE
This IOCTL command returns a log sense page from the device. The page is
selected by specifying the page_code in the log_sense_page structure.
The structure of a log page consists of the following log page header and log
parameters.
Log Page
- Log Page Header
-Page Code
-Page Length
- Log Parameter(s) (One or more may exist)
- Parameter Code
- Control Byte
- Parameter Length
- Parameter Value
The following data structure is filled out and returned by the driver.
226 IBM Tape Device Drivers: Programming Reference
#define IOC_LOG_SENSE_PAGE (_IOWR(’S’,6, log_sns_pg_t)
#define LOGSENSEPAGE 1024 /* The maximum data length which this */
/* ioctl can return, including the */
/* log page header. This value is not */
/* application modifiable. */
typedef struct log_sns_pg_s {
uchar page_code; /* Log page to be returned. */
uchar subpage_code; /* Log subpage to be returned. */
uchar reserved1[1]; /* Reserved for IBM future use. */
uchar reserved2[2]; /* Reserved for IBM future use. */
uchar data[LOGSENSEPAGE]; /* Log page data will be placed here. */
} log_sns_pg_t;
memset((char*)&log_sns_pg,0,sizeof(log_sns_pg_t));
log_sns_pg.page_code = page;
if(!(ioctl(dev_fd, IOC_LOG_SENSE_PAGE,&log_sns_pg))){
| log_data_len = (uint)(((log_page_hdr_p->len[2]<<8) |
| log_page_hdr_p->len[3])+4);
returned_len = MIN(log_data_len,sizeof log_sns_pg.data);
printf ("\n Log Sense Page ioctl succeeded.\n");
printf(" Log Page 0x%X data, length %d(%d returned):
\n",page,log_data_len,returned_len);
dump_bytes((char*)log_page_p,returned_len);
}
else {
perror("The IOC_INQUIRY ioctl failed");
scsi_request_sense(); }
IOC_LOG_SENSE10_PAGE
This IOCTL command is enhanced to add a Subpage variable from
IOC_LOG_SENSE_PAGE. It returns a log sense page or Subpage from the device.
typedef struct {
uchar page_code; /* Log sense page */
uchar subpage_code; /* Log sense subpage */
uchar reserved[2]; /* Reserved for IBM future use. */
ushort len; /* number of valid bytes in data
(log_page_header_size+page_length) */
ushort parm_pointer; /* specific parameter number at which
the data begins */
char data[LOGSENSEPAGE]; /* log data */
}log_sense10_page_t;
if(!(ioctl(dev_fd, IOC_LOG_SENSE10_PAGE,&log_sns_pg))){
| IOC_ENH_LOG_SENSE
| This IOCTL command is enhanced to define the len variable as input and limited
| for available kernel memory from the IOC_LOG_SENSE10_PAGE.
| IOC_MODE_SENSE
This command returns a mode sense page from the device. The page is selected by
specifying the page_code in the mode_sns_t structure.
The following data structure is filled out and returned by the driver.
#define MAX_MSDATA 253 /* The maximum data length which this */
/* ioctl can return, including */
/* headers and block descriptors. */
typedef struct {
uchar page_code; /* Page Code: Set this field with */
/* the desired mode page number */
/* before issuing the ioctl. */
uchar cmd_code; /* SCSI Command Code: Upon return, */
/* this field is set with the */
/* SCSI command code to which */
/* the device responded. */
/* x’5A’ = Mode Sense (10) */
/* x’1A’ = Mode Sense (6) */
uchar data[MAX_MSDATA]; /* Mode Parameter List: Upon return, */
/* this field contains the mode */
/* parameters list, up to the max */
/* length supported by the ioctl. */
} mode_sns_t;
mode_sns_t mode_data;
mode_data.page_code =(uchar)page;
IOC_MODE_SENSE_SUBPAGE
This command returns the mode sense data for a specific page and Subpage from
the device. The page and Subpage are selected by specifying the page_code and
subpage_code in the mode_sns_subpage_t structure.
The following data structure is filled out and returned by the driver.
#define MAX_MS_SUBDATA 10240 /* The maximum subpage data length which */
/* this ioctl can return, including */
/* headers and block descriptors. */
typedef struct {
uchar page_code; /* Page Code: Set this field with */
/* the desired mode page number */
/* before issuing the ioctl */
uchar subpage_code; /* Subpage Code: Set this field with */
/* the desired mode page subpage */
/* number before issuing the ioctl */
uchar cmd_code; /* SCSI Command Code: Upon return, */
/* this field is set with the */
/* SCSI command code to which */
/* the device responded. */
/* x’5A’ = Mode Sense (10) */
int rc;
int header_len;
int blk_dsc_len = 0;
int mode_data_len = 0;
int mode_data_returned_len = 0;
int max_mdsnspg_data_len = 0;
uchar cmd_code;
uchar medium_type;
uchar density_code;
uchar wrt_prot;
char *header_p;
char *blkdsc_p;
void *mode_data_p;
mode_sns_subpage_t mode_subpage;
printf ("\nHeader:\n");
DUMP_BYTES ((char *)(header_p), header_len);
if (blk_dsc_len != 0) {
printf ("\nBlock Descriptor:\n");
DUMP_BYTES ((char *)(blkdsc_p), blk_dsc_len);
}
printf ("\nMode Page:\n");
DUMP_BYTES ((char *)(mode_data_p), (mode_data_returned_len - header_len -
blk_dsc_len));
}
else {
perror ("mode sense subpage");
}
return (rc);
SIOC_MODE_SENSE
This command returns the mode sense data for a specific page and Subpage from
the device. The page and Subpage are selected by specifying the page_code and
subpage_code in the mode_sense_t structure.
#define MAX_MS_SUBDATA 10240 /* The maximum subpage data length which */
/* this ioctl can return, including */
/* headers and block descriptors. */
typedef struct {
uchar page_code; /* mode sense page code */
uchar subpage_code; /* mode sense subpage code */
uchar reserved[6]; /*Reserved for IBM future use.*/
uchar cmd_code; /* SCSI Command Code: this field is set with */
/* SCSI command code which the device responded. */
/* x’5A’ = Mode Sense (10) */
/* x’1A’ = Mode Sense (6) */
char data[MODESENSEPAGE]; /* whole mode sense data include header,
block descriptor and page */
} mode_sense_t;
int header_len;
int blk_dsc_len = 0;
int mode_data_len = 0;
int mode_data_returned_len = 0;
int max_mdsnspg_data_len = 0;
uchar cmd_code;
uchar medium_type;
uchar density_code;
uchar wrt_prot;
char *header_p;
char *blkdsc_p;
void *mode_data_p;
mode_sense_t mode_sns;
mode_sns.page_code = page;
mode_sns.subpage_code = subpage;
IOC_DRIVER_INFO
This command returns the information about the currently installed IBMtape
driver.
The following data structure is filled out and returned by the driver.
typedef struct {
uchar reserved_1[4]; /* Reserved for IBM Development Use */
uchar reserved_2[4]; /* Reserved for IBM Development Use */
uchar reserved_3[4]; /* Reserved for IBM Development Use */
IBMtape_info_t IBMtape_info;
IOC_RESERVE
This command persistently reserves the device for exclusive use by the initiator.
The IBMtape device driver normally reserves the device in the open operation and
releases the device in the close operation. Issuing this command prevents the
driver from releasing the device during the close operation; hence the device
reservation is maintained after the device is closed. This command is negated by
issuing the IOC_RELEASE IOCTL command.
IOC_RELEASE
This command releases the persistent reservation of the device for exclusive use by
the initiator. It negates the result of the IOC_RESERVE IOCTL command that is
issued either from the current or a previous open session.
These commands and associated data structures are defined in the smc.h header
file in the /usr/include/sys directory that is installed with the IBMtape package.
Any application program that issues these commands must include this header file.
SMCIOC_MOVE_MEDIUM
This command transports a cartridge from one element to another element.
The following data structure is filled out and supplied by the caller.
typedef struct {
ushort robot; /* robot address */
ushort source; /* move from location */
ushort destination; /* move to location */
uchar invert; /* invert medium before insertion */
} move_medium_t
move_medium_t move_medium;
move_medium.robot = 0;
move_medium.invert = NO_FLIP;
move_medium.source = src;
move_medium.destination = dst;
else {
perror ("The SMCIOC_MOVE_MEDIUM ioctl failed");
scsi_request_sense ();
}
SMCIOC_EXCHANGE_MEDIUM
This command exchanges a cartridge from one element to another element. This
command is equivalent to two SCSI Move Medium commands. The first moves the
cartridge from the source element to the destination1 element. The second moves
the cartridge that was previously in the destination1 element to the destination2
element. The destination2 element can be the same as the source element.
The following data structure is filled out and supplied by the caller.
typedef struct {
ushort robot; /* robot address */
ushort source; /* move from location */
ushort destination1; /* move to location */
ushort destination2; /* move to location */
uchar invert1; /* invert medium before insert into destination 1 */
uchar invert2; /* invert medium before insert into destination 2 */
} Exchange_medium_t
exchange_medium_t exchange_medium;
exchange_medium.robot = 0;
exchange_medium.invert1 = NO_FLIP;
exchange_medium.invert2 = NO_FLIP;
exchange_medium.source = (short)src;
exchange_medium.destination1 = (short)dst1;
exchange_medium.destination2 = (short)dst2;
SMCIOC_POS_TO_ELEM
This command moves the robot to an element.
The following data structure is filled out and supplied by the caller.
pos_to_elem_t pos_to_elem;
pos_to_elem.robot = 0;
pos_to_elem.invert = NO_FLIP;
pos_to_elem.destination = dst;
else {
perror ("The SMCIOC_POS_TO_ELEM ioctl failed");
scsi_request_sense ();
}
SMCIOC_ELEMENT_INFO
This command requests the information about the device elements.
There are four types of medium changer elements. (Not all medium changers
support all four types.) The robot elements are associated with the cartridge
transport devices. The cell elements are associated with the cartridge storage slots.
The port elements are associated with the import/export mechanisms. The drive
elements are associated with the data-transfer devices. The quantity of each
element type and its starting address is returned by the driver.
The following data structure is filled out and returned by the driver.
typedef struct {
ushort robot_address; /* medium transport element address */
ushort robot_count; /* number medium transport elements */
ushort cell_address; /* medium storage element address */
ushort cell_count; /* number medium storage elements */
ushort port_address; /* import/export element address */
ushort port_count; /* number import/export elements */
ushort drive_address; /* data-transfer element address */
ushort drive_count; /* number data-transfer elements */
} element_info_t;
element_info_t element_info;
else {
perror ("The SMCIOC_ELEMENT_INFO ioctl failed");
scsi_request_sense ();
}
There are four types of medium changer elements. (Not all medium changers
support all four types.) The robot elements are associated with the cartridge
transport devices. The cell elements are associated with the cartridge storage slots.
The port elements are associated with the import/export mechanisms. The drive
elements are associated with the data-transfer devices.
Note: The application must allocate buffers large enough to hold the returned
element status data for each element type. The SMCIOC_ELEMENT_INFO IOCTL
is called first to establish the criteria.
The following data structure is filled out and supplied by the caller.
typedef struct {
element_status_t *robot_status; /* medium transport element pages */
element_status_t *cell_status; /* medium storage element pages */
element_status_t *port_status; /* import/export element pages */
element_status_t *drive_status; /* data-transfer element pages */
} inventory_t;
One or more of the following data structures are filled out and returned to the user
buffer by the driver.
typedef struct {
ushort address; /* element address */
uchar : 2, /* reserved */
inenab : 1, /* medium in robot scope */
exenab : 1, /* medium not in robot scope */
access : 1, /* robot access allowed */
except : 1, /* abnormal element state */
: 1, /* reserved */
full : 1; /* element contains medium */
uchar : 8; /* reserved */
uchar asc; /* additional sense code */
uchar ascq; /* additional sense code qualifier */
uchar notbus : 1, /* element not on same bus as robot */
: 1, /* reserved */
idvalid : 1, /* element address valid */
luvalid : 1, /* logical unit valid */
: 1, /* reserved */
lun : 3; /* logical unit number */
uchar scsi; /* SCSI bus address */
uchar : 8; /* reserved */
uchar svalid : 1, /* element address valid */
invert : 1, /* medium inverted */
: 6; /* reserved */
ushort source; /* source storage element address */
uchar volume[36]; /* primary volume tag */
uchar vendor[80]; /* vendor specific (padded to 128) */
} element_status_t;
ushort i;
element_info_t element_info;
inventory_t inventory;
if (!inventory.robot_status || !inventory.cell_status ||
!inventory.port_status || !inventory.drive_status) {
perror ("The SMCIOC_INVENTORY ioctl failed");
return;
}
if (!(ioctl (dev_fd, SMCIOC_INVENTORY, &inventory))) {
else {
perror ("The SMCIOC_INVENTORY ioctl failed");
scsi_request_sense ();
}
SMCIOC_AUDIT
This command causes the medium changer device to run an audit of the element
status (SCSI Initialize Element Status command).
else {
perror ("The SMCIOC_AUDIT ioctl failed");
scsi_request_sense ();
}
SMCIOC_AUDIT_RANGE
This IOCTL command issues the SCSI Initialize Element Status with Range
command. It is used to audit specific elements in a library by specifying the
starting element address and the number of elements. Use the SMCIOC_AUDIT IOCTL
to audit all elements.
SMCIOC_LOCK_DOOR
This command locks and unlocks the library access door. Not all IBM medium
changer devices support this operation.
The following data structure is filled out and supplied by the caller.
typedef uchar lock_door_t;
lock_door_t lock_door;
lock_door = LOCK;
else {
perror ("The SMCIOC_LOCK_DOOR ioctl failed");
scsi_request_sense ();
}
SMCIOC_READ_CARTRIDGE_LOCATION
The SMCIOC_READ_CARTRIDGE_LOCATION IOCTL is used to return the cartridge
location information for storage elements in the library. The element_address field
specifies the starting element address to return and the number_elements field
specifies how many storage elements are returned. The data field is a pointer to
the buffer for return data. The buffer must be large enough for the number of
elements that are returned. If the storage element contains a cartridge, then the
ASCII identifier field in return data specifies the location of the cartridge.
typedef struct
{
ushort element_address; /* starting element address */
ushort number_elements; /* number of elements */
cartridge_location_data_t *data; /* storage element pages */
char reserved[8]; /* reserved /
} read_cartridge_location_t;
int rc;
int available_slots=0;
cartridge_location_data_t *slot_devid;
read_cartridge_location_t slot_devids;
slot_devids.element_address = (ushort)element_address;
slot_devids.number_elements = (ushort)number_elements;
if (rc = ioctl(dev_fd,SMCIOC_ELEMENT_INFO,&element_info))
{
PERROR("SMCIOC_ELEMENT_INFO failed");
PRINTF("\n");
scsi_request_sense();
return (rc);
}
if (element_info.cell_count == 0)
{
printf("No slots found in element information...\n");
errno = EIO;
return errno;
}
if ((slot_devids.element_address==0) && (slot_devids.number_elements==0))
{
slot_devids.element_address=element_info.cell_address;
slot_devids.number_elements=element_info.cell_count;
printf("Reading all locations...\n");
}
if ((element_info.cell_address > slot_devids.element_address)
|| (slot_devids.element_address >
(element_info.cell_address+element_info.cell_count-1)))
{
printf("Invalid slot address %d\n",element_address);
errno = EINVAL;
return errno;
}
available_slots = (element_info.cell_address+element_info.cell_count)
-slot_devids.element_address;
if (available_slots>slot_devids.number_elements)
available_slots=slot_devids.number_elements;
slot_devid = malloc(element_info.cell_count
* sizeof(cartridge_location_data_t));
if (slot_devid == NULL
) {
errno = ENOMEM;
return errno;
}
free(slot_devid);
return rc;
These commands and associated data structures are defined in the st.h header file
in the /usr/include/sys directory that is installed with the IBMtape package. Any
application program that issues these commands must include this header file.
STIOC_TAPE_OP
This command runs the standard tape drive operations. It is identical to the
MTIOCTOP IOCTL command that is defined in the /usr/include/sys/mtio.h system
header file. The STIOC_TAPE_OP and MTIOCTOP commands both use the same data
structure that is defined in the /usr/include/sys/mtio.h system header file. The
STIOC_TAPE_OP IOCTL command maps to the MTIOCTOP IOCTL command. The two
IOCTL commands are interchangeable. See “MTIOCTOP” on page 283.
For all space operations, the resulting tape position is at the end-of-tape side of the
record or filemark for forward movement. It is at the beginning-of-tape side of the
record or filemark for backward movement.
The following data structure is filled out and supplied by the caller.
/* from st.h */
typedef struct mtop tape_op_t;
tape_op_t tape_op;
tape_op.mt_op = mt_op;
tape_op.mt_count = mt_count;
else {
perror ("The STIOC_TAPE_OP ioctl failed");
scsi_request_sense ();
}
STIOC_GET_DEVICE_STATUS
This command returns the status information about the tape drive. It is identical to
the MTIOCGET IOCTL command that is defined in the /usr/include/sys/mtio.h
system header file. The STIOC_GET_DEVICE_STATUS and MTIOCGET commands both
use the same data structure that is defined in the /usr/include/sys/mtio.h system
header file. The STIOC_GET_DEVICE_STATUS IOCTL command maps to the MTIOCGET
IOCTL command. The two IOCTL commands are interchangeable. See
“MTIOCGET” on page 283.
/* from st.h */
typedef struct mtget device_status_t;
The mt_flags field, which returns the type of automatic cartridge stacker or loader
that are installed on the tape drive, is set to one of the following values.
STF_ACL
Automatic Cartridge Loader.
STF_RACL
Random Access Cartridge Facility.
device_status_t device_status;
else {
perror ("The STIOC_GET_DEVICE_STATUS ioctl failed");
scsi_request_sense ();
}
STIOC_GET_DEVICE_INFO
This command returns the configuration information about the tape drive. It is
identical to the MTIOCGETDRIVETYPE IOCTL command that is defined in the
/usr/include/sys/mtio.h system header file. The STIOC_GET_DEVICE_INFO and
MTIOCGETDRIVETYPE commands both use the same data structure that is defined in
the /usr/include/sys/mtio.h system header file. The STIOC_GET_DEVICE_STATUS
IOCTL command maps to the MTIOCGETDRIVETYPE IOCTL command. The two
IOCTL commands are interchangeable. See “MTIOCGETDRIVETYPE” on page 283.
/* from st.h */
typedef struct mtdrivetype device_info_t;
device_info_t device_info;
else {
perror ("The STIOC_GET_DEVICE_INFO ioctl failed");
scsi_request_sense ();
}
The following data structure is filled out and returned by the driver.
typedef struct {
uint media_type; /* type of media loaded */
uint media_format; /* format of media loaded */
uchar write_protect; /* write protect (physical/logical) */
} media_info_t;
The media_format field, which returns the current recording format, is set to one
of the values in st.h.
media_info_t media_info;
else {
perror ("The STIOC_GET_MEDIA_INFO ioctl failed");
scsi_request_sense ();
}
STIOC_GET_POSITION
This command returns the information about the tape position.
The tape position is defined as where the next read or write operation occurs. The
STIOC_GET_POSITION and STIOC_SET_POSITION commands can be used
independently or with each other.
The following data structure is filled out and supplied by the caller (and also filled
out and returned by the driver).
typedef struct {
uchar block_type; /* block type (logical or physical) */
uchar bot; /* physical beginning of tape */
uchar eot; /* logical end of tape */
uchar partition; /* partition number */
uint position; /* current or new block ID */
uint last_block; /* last block written to tape */
uint block_count; /* blocks remaining in buffer */
uint byte_count; /* bytes remaining in buffer */
} position_data_t;
The block_type field is set to LOGICAL_BLK for standard SCSI logical tape
positions or PHYSICAL_BLK for composite tape positions. They are used for
high-speed locate operations that are implemented by the tape drive. Only the IBM
The block_type is the only field that must be filled out by the caller. The other
fields are ignored. Tape positions can be obtained with the STIOC_GET_POSITION
command, saved, and used later with the STIOC_SET_POSITION command to quickly
return to the same location on the tape.
The position field returns the current position of the tape (physical or logical).
The last_block field returns the last block of data that was transferred physically to
the tape.
The block_count field returns the number of blocks of data that remains in the
buffer.
The byte_count field returns the number of bytes of data that remains in the
buffer.
The bot and eot fields indicate whether the tape is positioned at the beginning of
tape or the end of tape.
position_data_t position_data;
position_data.block_type = type;
else {
perror ("The STIOC_GET_POSITION ioctl failed");
scsi_request_sense ();
}
STIOC_SET_POSITION
This command sets the physical position of the tape.
The tape position is defined as where the next read or write operation occurs. The
STIOC_GET_POSITION and STIOC_SET_POSITION commands can be used
independently or with each other.
The following data structure is filled out and supplied by the caller.
typedef struct {
uchar block_type; /* block type (logical or physical) */
uchar bot; /* physical beginning of tape */
uchar eot; /* logical end of tape */
uchar partition; /* partition number */
uint position; /* current or new block ID */
uint last_block; /* last block written to tape */
uint block_count; /* blocks remaining in buffer */
uint byte_count; /* bytes remaining in buffer */
} position_data_t;
The block_type and position fields must be filled out by the caller. The other
fields are ignored. The type of position that is specified in the position field must
correspond with the type specified in the block_type field. Tape positions can be
obtained with the STIOC_GET_POSITION command, saved, and used later with the
STIOC_SET_POSITION command to quickly return to the same location on the tape.
The IBM 3490E Magnetic Tape Subsystem drives in VTSs do not support position
to end of tape.
position_data_t position_data;
position_data.block_type = type;
position_data.position = value;
else {
perror ("The STIOC_SET_POSITION ioctl failed");
scsi_request_sense ();
}
STIOC_GET_PARM
This command returns the current value of the working parameter for the specified
tape drive. This command is used with the STIOC_SET_PARM command.
The following data structure is filled out and supplied by the caller (and also filled
out and returned by the driver).
typedef struct {
uchar type; /* type of parameter to get or set */
uint value; /* current or new value of parameter */
} parm_data_t;
The value field returns the current value of the specified parameter, within the
ranges that are indicated for the specific type.
The type field, which is filled out by the caller, is set to one of the following
values.
BLOCKSIZE
Block Size (0- [2 MB]/Maximum dma size).
A value of zero indicates variable block size. Only the IBM 359x Tape
System supports 2 MB maximum block size or maximum dma transfer size
that is supported by the host adapter if it is larger than 2 MB. All other
devices support 256 KB maximum block size.
COMPRESSION
Compression Mode (0 or 1).
If this mode is enabled, data is compressed by the tape device before it is
stored on tape.
Chapter 5. Solaris tape and medium changer device driver 251
BUFFERING
Buffering Mode (0 or 1).
If this mode is enabled, data is stored in hardware buffers in the tape
device and not immediately committed to tape, thus increasing data
throughput performance.
IMMEDIATE
Immediate Mode.
v NO_IMMEDIATE (0)
If IMMEDIATE is set to zero, SCSI commands that support the
immediate bit in the CDB run to completion before status is returned.
v GEN_IMMEDIATE (1)
If IMMEDIATE is set to GEN_IMMEDIATE, the SCSI commands Write
FM, Locate, Load-Unload, Erase, and Rewind return with status before the
command actually completes on the tape drive.
v REW_IMMEDIATE (2)
If IMMEDIATE is set to REW_IMMEDIATE, the SCSI rewind command
returns with status before the command actually completes on the tape
drive.
TRAILER
Trailer Label Mode (0 or 1).
This mode affects write behavior after logical end of medium (LEOM) is
reached. See “Writing to a special file” on page 301 for information about
write operations that approach LEOM. With trailer label processing
disabled (TRAILER=0), writing past logical end of medium (LEOM) is not
allowed. After LEOM is reached, all further writes fail, returning -1, with
the errno system variable set to ENOSPC (no space that is left on device).
With trailer label processing enabled (TRAILER=1), writing past logical end
of medium (LEOM) is allowed. After LEOM is reached, all subsequent
writes succeed until physical end of medium (PEOM) is reached. Write
requests for multiple fixed blocks can encounter short writes. See “Writing
to a special file” on page 301 for information about short writes. After
PEOM is reached, all further writes fail, returning -1, with the errno system
variable set to ENOSPC (nospace that is left on device).
An application that uses the trailer label processing option must stop
normal data writing when LEOM is reached, and run end of volume
processing. Such processing typically consists of writing a final data record,
a filemark, and a "trailing" tape label. Finally, two more filemarks are
written to indicate end of data (EOD).
WRITEPROTECT
Write-Protect mode.
This configuration parameter returns the current write protection status of
the mounted cartridge. The following values are recognized.
v NO_PROTECT
The tape is not physically or logically write-protected. Operations that
alter the contents of the media are permitted. Setting the tape to this
value resets the PERSISTENT and ASSOCIATED logical write
protection modes. It does not reset the WORM logical or the PHYSICAL
write protection modes.
v PHYS_PROTECT
Note: Only IBM 359x and Magstar MP 3570 Tape Subsystem recognize
the following values.
v WORM_PROTECT
The tape is logically write protected in WORM mode. When the tape is
protected in this mode, it is permanently write-protected. The only
method to return the tape to a writable state is to format the cartridge,
erasing all data.
v PERS_PROTECT
The tape is logically write protected in PERSISTENT mode. A tape that
is protected in this mode is write-protected for all uses (across mounts).
This logical write protection mode can be reset by using the
NO_PROTECT value.
v ASSC_PROTECT
The tape is logically write protected in ASSOCIATED mode. A tape that
is protected in this mode in write protected only while it is associated
with a tape drive (mounted). When the tape is unloaded from the drive,
the associated write protection is reset. This logical write protection
mode can also be reset by using the NO_PROTECT value.
ACFMODE
Automatic Cartridge Facility mode.
This configuration parameter is read-only. ACF modes can be established
only through the tape drive operator panel. The device driver can query
only the ACF mode; it cannot change it. The ACFMODE parameter applies
only to the IBM 3590 Tape System and the IBM Magstar MP 3570 Tape
Subsystem. The following values are recognized:
v NO_ACF
There is no ACF attached to the tape drive.
v SYSTEM_MODE
The ACF is in the system mode. This mode allows explicit load and
unloads to be issued through the device driver. An unload or offline
command causes the tape drive to unload the cartridge and the ACF to
replace the cartridge in its original magazine slot. A subsequent load
command causes the ACF to load the cartridge from the next sequential
magazine slot into the drive.
v RANDOM_MODE
The ACF is in the random mode. This mode provides random access to
all of the cartridges in the magazine. The ACF operates as a standard
SCSI medium changer device.
v MANUAL_MODE
The ACF is in the manual mode. This mode does not allow ACF control
through the device driver. Cartridge load and unload operations can be
run only through the tape drive operator panel. Cartridges are imported
and exported through the priority slot.
v ACCUM_MODE
The ACF is in the accumulate mode. This mode is similar to the manual
mode. However, rather than cartridges that are exported through the
priority slot, they are put away in the next available magazine slot.
parm_data_t parm_data;
parm_data.type = type;
else {
perror ("The STIOC_GET_PARM ioctl failed");
scsi_request_sense ();
}
STIOC_SET_PARM
This command sets the current value of the working parameter for the specified
tape drive. This command is used with the STIOC_GET_PARM command.
The default values of most of these parameters, in effect when a tape drive is first
opened, are determined by the values in the IBMtape.conf configuration file in the
/usr/kernel/drv directory. Changing the working parameters dynamically through
this STIOC_SET_PARM command affects the tape drive only during the current open
session. The working parameters revert to the defaults when the tape drive is
closed and reopened.
The following data structure is filled out and supplied by the caller.
typedef struct {
uchar type; /* type of parameter to get or set */
uint value; /* current or new value of parameter */
} parm_data_t;
The value field specifies the new value of the specified parameter, within the
ranges that are indicated for the specific type.
The type field, which is filled out by the caller, can be set to one of the following
values.
BLOCKSIZE
Block Size (0-2097152 [2 MB]/Maximum dma size).
A value of zero indicates variable block size. Only the IBM 359x Tape
System supports 2 MB maximum block size or maximum dma transfer size
that is supported by the host adapter if it is larger than 2 MB. All other
devices support 256 KB maximum block size.
COMPRESSION
Compression Mode (0 or 1).
If this mode is enabled, data is compressed by the tape device before it is
stored on tape.
BUFFERING
Buffering Mode (0 or 1).
If this mode is enabled, data is stored in hardware buffers in the tape
device and not immediately committed to tape, thus increasing data
throughput performance.
IMMEDIATE
Immediate Mode.
v NO_IMMEDIATE (0)
If IMMEDIATE is set to zero, SCSI commands that support the
immediate bit in the CDB run to completion before status is returned.
v GEN_IMMEDIATE (1)
If IMMEDIATE is set to GEN_IMMEDIATE, the SCSI commands Write
FM, Locate, Load-Unload, Erase, and Rewind return with status before the
command completes on the tape drive.
v REW_IMMEDIATE (2)
If IMMEDIATE is set to REW_IMMEDIATE, the SCSI rewind command
returns with status before the command actually completes on the tape
drive.
TRAILER
Trailer Label Mode (0 or 1).
parm_data_t parm_data;
parm_data.type = type;
parm_data.value = value;
else {
perror ("The STIOC_SET_PARM ioctl failed");
scsi_request_sense ();
}
STIOC_DISPLAY_MSG
This command displays and manipulates one or two messages on the tape drive
operator panel.
The message that is sent by using this call does not always remain on the display.
It depends on the current drive activity.
Note: All messages must be padded to MSGLEN bytes (8). Otherwise, garbage
characters (meaningless data) can be displayed in the message.
The following data structure is filled out and supplied by the caller.
The function field, which is filled out by the caller, is set by combining (by using
logical OR) a Message Type flag and a Message Control Flag.
msg_data_t msg_data;
msg_data.function = GENSTATUS | ALTERNATE;
memcpy (msg_data.msg_0, "Hello ", 8);
memcpy (msg_data.msg_1, "World!!!", 8);
else {
perror ("The STIOC_DISPLAY_MSG ioctl failed");
scsi_request_sense ();
}
STIOC_SYNC_BUFFER
This command immediately flushes the drive buffers to the tape (commits the data
to the media).
else {
perror ("The STIOC_SYNC_BUFFER ioctl failed");
scsi_request_sense ();
}
STIOC_REPORT_DENSITY_SUPPORT
This IOCTL command issues the SCSI Report Density Support command to the
tape device and returns either all supported densities or supported densities for
the currently mounted media. The media field specifies which type of report is
requested. The number_reports field is returned by the device driver and indicates
how many density reports in the reports array field were returned.
The data structures that are used with this IOCTL are
typedef struct density_report
{
uchar primary_density_code; /* primary density code */
uchar secondary_density_code; /* secondary density code */
uchar wrtok : 1, /* write ok, device can write this format */
dup : 1, /* zero if density only reported once */
deflt : 1, /* current density is default format */
res_1 : 5; /* reserved */
uchar reserved1[2]; /* reserved */
uchar bits_per_mm[3]; /* bits per mm */
uchar media_width[2]; /* media width in millimeters */
uchar tracks[2]; /* tracks */
uchar capacity[4]; /* capacity in megabytes */
char assigning_org[8]; /* assigning organization in ASCII */
char density_name[8]; /* density name in ASCII */
char description[20]; /* description in ASCII */
} density_report_t;
int bits_per_mm = 0;
int media_width = 0;
int tracks = 0;
int capacity = 0;
density.media = ALL_MEDIA_DENSITY;
density.number_reports = 0;
printf("\n");
printf(" Density Name................. %0.8s\n",
density.reports[i].density_name);
printf(" Assigning Organization....... %0.8s\n",
density.reports[i].assigning_org);
printf(" Description.................. %0.20s\n",
density.reports[i].description);
printf(" Primary Density Code......... %02X\n",
density.reports[i].primary_density_code);
printf(" Secondary Density Code....... %02X\n",
density.reports[i].secondary_density_code);
if (density.reports[i].wrtok)
printf(" Write OK..................... Yes\n");
else
printf(" Write OK..................... No\n");
if (density.reports[i].dup)
printf(" Duplicate.................... Yes\n");
if (density.reports[i].deflt)
printf(" Default...................... Yes\n");
else
printf(" Default...................... No\n");
if (interactive) {
printf ("\nHit <ENTER> to continue...");
getchar ();
}
density.media = CURRENT_MEDIA_DENSITY;
density.number_reports = 0;
printf("\n");
printf(" Density Name................. %0.8s\n",
density.reports[i].density_name);
printf(" Assigning Organization....... %0.8s\n",
density.reports[i].assigning_org);
printf(" Description.................. %0.20s\n",
density.reports[i].description);
printf(" Primary Density Code......... %02X\n",
density.reports[i].primary_density_code);
printf(" Secondary Density Code....... %02X\n",
density.reports[i].secondary_density_code);
if (density.reports[i].dup)
printf(" Duplicate.................... Yes\n");
else
printf(" Duplicate.................... No\n");
if (density.reports[i].deflt)
printf(" Default...................... Yes\n");
else
printf(" Default...................... No\n");
if (interactive) {
printf ("\nHit <ENTER> to continue...");
getchar ();
}
}
return (rc);
}
STIOC_GET_DENSITY
STIOC_GET_DENSITY is used to query the current write density format settings on
the tape drive for 3592 E05 or later model drive only.
The density_code field returns the current density of the tape that is loaded in the
tape drive from the block descriptor of Mode sense. The default_density field
returns the default write density in Mode sense (Read/Write Control). The
pending_density field returns the pending write density in Mode sense
(Read/Write Control). An example of the STIOC_SET_DENSITY command is
#include <sys/st.h>
density_data_t density_data;
STIOC_SET_DENSITY
STIOC_SET_DENSITY is used to set a new write density format on the tape drive by
using the default and pending density fields in 3592 E05 or later model drive only.
For example, this command is used if the user wants to write the data to the tape
in 3592 J1A format (0x51) in 3592 E05 drive, not in the default 3592 E05 format
(0x52). The application can specify a new write density for the current loaded tape
only or as a default for all tapes. Refer to the examples.
Note:
1. These IOCTLs are supported only on tape drives that can write multiple
density formats. Refer to the hardware reference for the specific tape
drive to determine whether multiple write densities are supported. If the
tape drive does not support these IOCTLs, errno EINVAL is returned.
2. The device driver always sets the default maximum write density for the
tape drive on every open system call. Any previous STIOC_SET_DENSITY
IOCTL values from the last open are not used.
3. If the tape drive detects an invalid density code or cannot complete the
operation on the STIOC_SET_DENSITY IOCTL, the errno is returned and the
current drive density settings before the IOCTL is restored.
4. The struct density_data_t defined in the header file of st.h is used for
both IOCTLs. The density_code field is not used and ignored on the
STIOC_SET_DENSITY IOCTL.
5. A new write density is allowed only when positioned at BOP (logical
block 0), and is ignored at any other location in the tape drive. The new
density is applied on the next write-type operation (Write, Write
Filemarks (>0), Erase, Format Medium, and so on). It is not reported in
the STIOC_GET_DENSITY IOCTL density_code field before the format is
completed.
Case 1: Set 3592 J1A density format for current loaded tape only.
density_data.default_density = 0x7F;
density_data.pending_density = 0x51;
Case 2: Set 3592 E05 density format for current loaded tape only.
density_data.default_density = 0x7F;
density_data.pending_density = 0x52;
Case 4: Set 3592 J1A density format for current loaded tape and all subsequent
tapes.
density_data.default_density = 0x51;
density_data.pending_density = 0x51;
/* set 3592 J1A density format (0x51) for current loaded tape only */
density_data.default_density = 0x7F;
density_data.pending_density = 0x51;
GET_ENCRYPTION_STATE
This IOCTL command queries the drive's encryption method and state.
The data structure that is used for this IOCTL is as follows on all of the supported
operating systems.
struct encryption_status {
uchar encryption_capable; /* Set this field as a boolean based on the
capability of the drive */
uchar encryption_method; /* Set this field to one of the
defines below */
#define METHOD_NONE 0 /* Only used in
GET_ENCRYPTION_STATE */
#define METHOD_LIBRARY 1 /* Only used in
GET_ENCRYPTION_STATE */
#define METHOD_SYSTEM 2 /* Only used in
GET_ENCRYPTION_STATE */
#define METHOD_APPLICATION 3 /* Only used in
GET_ENCRYPTION_STATE */
#define METHOD_CUSTOM 4 /* Only used in
GET_ENCRYPTION_STATE */
#define METHOD_UNKNOWN 5 /* Only used in
if(rc == 0) {
if(encryption_status_t.encryption_capable)
printf("encryption capable......Yes\n");
else
printf("encryption capable......No\n");
switch(encryption_status_t.encryption_method) {
case METHOD_NONE:
printf("encryption method.......METHOD_NONE\n");
break;
case METHOD_LIBRARY:
printf("encryption method.......METHOD_LIBRARY\n");
break;
case METHOD_SYSTEM:
printf("encryption method.......METHOD_SYSTEM\n");
break;
case METHOD_APPLICATION:
printf("encryption method.......METHOD_APPLICATION\n");
break;
case METHOD_CUSTOM:
printf("encryption method.......METHOD_CUSTOM\n");
break;
case METHOD_UNKNOWN:
printf("encryption method.......METHOD_UNKNOWN\n");
break;
default:
printf("encryption method.......Error\n");
}
switch(encryption_status_t.encryption_state) {
case STATE_OFF:
printf("encryption state........OFF\n");
break;
case STATE_ON:
printf("encryption state........ON\n");
break;
case STATE_NA:
printf("encryption state........NA\n");
break;
default:
printf("encryption state......Error\n");
}
}
return rc;
}
The data structure that is used for this IOCTL is the same as the one for
GET_ENCRYPTION_STATE.
return rc;
}
SET_DATA_KEY
This IOCTL command allows setting the data key only for application-managed
encryption.
The data structure that is used for this IOCTL is as follows on all of the supported
operating systems.
struct data_key {
uchar data_key_index[12]; /* The DKi */
uchar data_key_index_length; /* The DKi length */
uchar reserved1[15];
uchar data_key[32]; /* The DK */
uchar reserved2[48];
};
/* fill in your data key here, then issue the following ioctl*/
rc = ioctl(fd, SET_DATA_KEY, &encryption_status_t);
return rc;
}
struct query_partition {
uchar max_partitions; /* Max number of supported partitions */
uchar active_partition; /* current active partition on tape */
uchar number_of_partitions; /* Number of partitions from 1 to max */
uchar size_unit; /* Size unit of partition sizes below */
ushort size[MAX_PARTITIONS]; /* Array of partition sizes in size units */
/* for each partition, 0 to (number - 1) */
uchar partition_method; /* partitioning type */
char reserved [31];
};
int rc,i;
struct query_partition q_partition;
return rc;
CREATE_PARTITION
The CREATE_PARTITION IOCTL is used to format the current media in the tape drive
into 1 or more partitions. The number of partitions to create is specified in the
number_of_partitions field. When more than one partition is created, the type
field specifies the type of partitioning, either FDP, SDP, or IDP. The tape must be
positioned at the beginning of tape (partition 0 logical block id 0) before this
IOCTL is used.
When the type field in the IOCTL structure is set to either FDP or SDP, the
size_unit and size fields in the IOCTL structure are not used. When the type field
in the IOCTL structure is set to IDP, the size_unit with the size fields are used to
specify the size for each partition.
There are two partition types: Wrap-wise Partitioning (Figure 9 on page 271)
optimized for streaming performance, and Longitudinal Partitioning (Figure 10 on
page 271) optimized for random access performance. Media is always partitioned
into 1 by default or more than one partition where the data partition always exists
as partition 0 and other extra index partition 1 to n might exist.
A WORM media cannot be partitioned and the Format Medium commands are
rejected. Attempts to scale a partitioned media is accepted. However, only if you
use the correct FORMAT field setting, as part of scaling the volume is set to a
single data partition cartridge.
Partition 2
a2500283
Partition 3
Guard gap
Partition 0 Partition 1
a2500284
Figure 10. Longitudinal partitioning
The following chart lists the maximum number of partitions that the tape drive
supports.
Table 5. Number of supported partitions
Drive type Maximum number of supported partitions
LTO 5 (TS2250 and TS2350) and later 2 in Wrap-wise Partitioning
3592 E07 (TS 1140) 4 in Wrap-wise Partitioning
2 in Longitudinal Partitioning
SET_ACTIVE_PARTITION
The SET_ACTIVE_PARTITION IOCTL is used to position the tape to a specific
partition. This partition becomes the current active partition for subsequent
commands and a specific logical block id in the partition. To position to the
beginning of the partition, the logical_block_id field must be set to 0.
ALLOW_DATA_OVERWRITE
The ALLOW_DATA_OVERWRITE IOCTL is used to set the drive to allow a subsequent
data write type command at the current position. Or, allow a CREATE_PARTITION
IOCTL when data safe (append-only) mode is enabled.
/* get current tape position for a subsequent write type command and */
rpos.data_format = RP_LONG_FORM;
if (ioctl (dev_fd, READ_TAPE_POSITION, &rpos) <0)
retun errno;
READ_TAPE_POSITION
The READ_TAPE_POSITION IOCTL is used to return Read Position command data in
either the short, long, or extended form. The type of data to return is specified by
setting the data_format field to either RP_SHORT_FORM, RP_LONG_FORM, or
RP_EXTENDED_FORM.
The data structures that are used with this IOCTL are
#define RP_SHORT_FORM 0x00
#define RP_LONG_FORM 0x06
#define RP_EXTENDED_FORM 0x08
struct short_data_format {
uchar bop:1, /* beginning of partition */
eop:1, /* end of partition */
locu:1, /* 1 means num_buffer_logical_obj field is unknown */
bycu:1, /* 1 means the num_buffer_bytes field is unknown */
rsvd :1,
lolu:1, /* 1 means the first and last logical obj
position fields are unknown */
perr: 1, /* 1 means the position fields have overflowed
and can not be reported */
bpew :1; /* beyond programmable early warning */
uchar active_partition; /* current active partition */
char reserved[2];
uint first_logical_obj_position;/* current logical object position */
uint last_logical_obj_position; /* next logical object to be transferred to tape */
uint num_buffer_logical_obj; /* number of logical objects in buffer */
uint num_buffer_bytes; /* number of bytes in buffer */
char reserved1;
};
struct long_data_format {
uchar bop:1, /* beginning of partition */
eop:1, /* end of partition */
rsvd1:2,
mpu:1, /* 1 means the logical file id field in unknown */
lonu:1, /* 1 means either the partition number or
logical obj number field are unknown */
rsvd2:1,
bpew :1; /* beyond programmable early warning */
char reserved[6];
uchar active_partition; /* current active partition */
ullong logical_obj_number; /* current logical object position */
ullong logical_file_id; /* number of filemarks from bop and
current logical position */
ullong obsolete;
};
struct extended_data_format {
uchar bop:1, /* beginning of partition */
eop:1, /* end of partition */
locu:1, /* 1 means num_buffer_logical_obj field is unknown */
bycu:1, /* 1 means the num_buffer_bytes field is unknown */
rsvd :1,
lolu:1, /* 1 means the first and last logical obj position
fields are unknown */
perr: 1, /* 1 means the position fields have overflowed
and can not be reported */
bpew :1; /* beyond programmable early warning */
uchar active_partition; /* current active partition */
struct read_tape_position{
uchar data_format; /* Specifies the return data format either short,
long or extended as defined above */
union
{
struct short_data_format rp_short;
struct long_data_format rp_long;
struct extended_data_format rp_extended;
char reserved[64];
} rp_data;
};
if (rpos.rp_data.rp_long.bop)
printf(" Beginning of Partition ..... Yes\n");
else
printf(" Beginning of Partition ..... No\n");
if (rpos.rp_data.rp_long.eop)
printf(" End of Partition ........... Yes\n");
else
printf(" End of Partition ........... No\n");
if (rpos.rp_data.rp_long.bpew)
printf(" Beyond Early Warning ... ... Yes\n");
else
printf(" Beyond Early Warning ....... No\n");
if (rpos.rp_data.rp_long.lonu
) {
printf(" Active Partition ........... UNKNOWN \n");
printf(" Logical Object Number ...... UNKNOWN \n");
}
else
{
printf(" Active Partition ... ....... %u \n",
rpos.rp_data.rp_long.active_partition);
printf(" Logical Object Number ...... %llu \n",
rpos.rp_data.rp_long.logical_obj_number);
}
if (rpos.rp_data.rp_long.mpu
) printf(" Logical File ID ............ UNKNOWN \n");
else
printf(" Logical File ID ............ %llu \n",
rpos.rp_data.rp_long.logical_file_id);
struct set_tape_position{
uchar logical_id_type; /* Block or file as defined above */
ullong logical_id; /* logical object or logical file to position to */
char reserved[32];
};
QUERY_LOGICAL_BLOCK_PROTECTION
The IOCTL queries whether the drive can support this feature, what LBP method
is used, and where the protection information is included.
The lbp_capable field indicates whether the drive has logical block protection
(LBP) capability. The lbp_method field displays if LBP is enabled and what the
protection method is. The LBP information length is shown in the lbp_info_length
field. The fields of lbp_w, lbp_r, and rbdp present that the protection information
is included in write, read, or recover buffer data.
int rc;
struct logical_block_protection lbp_protect;
SET_LOGICAL_BLOCK_PROTECTION
The IOCTL enables or disables Logical Block Protection, sets up what method is
used, and where the protection information is included.
The lbp_capable field is ignored in this IOCTL by the IBMtape driver. If the
lbp_method field is 0 (LBP_DISABLE), all other fields are ignored and not used.
When the lbp_method field is set to a valid non-zero method, all other fields are
used to specify the setup for LBP.
int rc;
struct logical_block_protection lbp_protect;
if (rc)
printf ("Set Logical Block Protection Fails (rc %d)",rc);
else
printf ("Set Logical Block Protection Succeeds");
Note:
1. The drive always expects a CRC attached with a data block when LBP is
enabled for lbp_r and lbp_w. Without the CRC bytes attachment, the
drive fails the Read and Write command. To prevent the CRC block
transfer between the drive and application, the maximum block size
limit must be determined by application. Call the STIOC_GET_PARM IOCTL
to get the parameter of MAX_SCSI_XFER (the system maximum block size
limit). Call the STIOC_READ_BLKLIM IOCTL to get the value of
max_blk_lim (the drive maximum block size limit). Then, use the
minimum of the two limits.
2. When a unit attention with a power-on and device reset (Sense
key/Asc-Ascq x6/x2900) occurs, the LBP enable bits (lbp_w, lbp_r, and
rbdp) are reset to OFF by default. The IBMtape tape driver returns EIO
for an IOCTL call in this situation. Once the application determines it is
a reset unit attention in the sense data, it responds to query LBP setup
again and reissues this IOCTL to set up LBP properly.
3. The LBP setting is controlled by the application and not the device
driver. If an application enables LBP, it must also disable LBP when it
closes the drive, as this action is not done by the device driver.
VERIFY_TAPE_DATA
The IOCTL issues a VERIFY command to cause data to be read from the tape and
passed through the drive’s error detection and correction hardware. This action
determines whether it can be recovered from the tape. Or, whether the protection
information is present and validates correctly on logical block on the medium. The
driver returns the IOCTL a failure or a success if the VERIFY SCSI command is
completed in a Good SCSI status.
Note:
1. When an application sets the VBF method, it considers the driver’s close
operation in which the driver can write filemarks in its close that the
application did not explicitly request. For example, some drivers write
two consecutive filemarks that mark the end of data on the tape in its
close, if the last tape operation was a WRITE command.
2. Per the user's or application's request, the IBMtape driver sets the block
size in the field of Block Length in mode block descriptor for Read and
Write commands. Then, it maintains this block size setting in a whole
open. For instance, the tape driver set a zero in the Block Length field
for the variable block size. This act causes the missing of an overlength
condition on a SILI Read (and cause problems for LTFS). Block Length
must be set to a non-zero value.
Before the set Fixed bit ON with VTE or VBF ON in VERIFY IOCTL, the
application is also requested to set the block size in mode block
descriptor. The drive uses it to verify the length of each logical block. For
char buf[60];
verify_data_t vd;
unsigned int vlength=0;
int i;
vd.verify_length = vlength;
printf("Data dump:\n");
| QUERY_RAO
| The IOCTL is used to query the maximum number and size of User Data Segments
| (UDS) that are supported from tape drive and driver for the wanted uds_type.
| The application calls this IOCTL before the GENERATE_RAO and RECEIVE_RAO IOCTLs
| are issued. The application uses the return data to limit the number of UDS
| requested in the GENERATE_RAO IOCTL.
| GENERATE_RAO
| The IOCTL is called to send a GRAO list to request that the drive generate a
| Recommended Access Order list. The process method is either 1 or 2 to create a
| RAO list, and the type of UDS is either with or without the geometry. The
| uds_number must be not larger than max_host_uds_number in the QUERY_RAO
| IOCTL. The application allocates a block of memory with grao_list_leng
| (uds_number*sizeof(struct grao_uds_desc)+8) for the pointer of grao_list.
| The grao list header and UDS segments make up the parameter data and are to be
| put in the following order.
| The device driver does not supply the header or UDS segment Descriptor
| structures. That structure is to be supplied by the application.
| A sample of GENERATE_RAO is
| #include<sys/st.h>
| int rc;
| struct generate_rao grao;
| bzero(&grao,sizeof(struct generate_rao));
| grao.process=2;
| grao.uds_type=uds_type;
| grao.grao_list_leng=max_host_uds_num * sizeof(struct grao_uds_desc)
| + sizeof(struct grao_list_header);
| if(!(grao.grao_list=malloc(grao.grao_list_leng)))
| {
| perror("Failure allocating memory");
| return (errno);
| }
| memset(grao.grao_list, 0, grao.grao_list_leng);
| rc=ioctl(fd,GENERATE_RAO,&grao);
| if (rc)
| printf("GENERATE_RAO fails with rc%d\n",rc);
| RECEIVE_RAO
| After a GENERATE_RAO IOCTL is completed, the application calls the RECEIVE_RAO
| IOCTL to receive a recommended access order of UDS from the drive. To avoid a
| system crash, it is important that the application allocates a large enough block of
| memory for the *rrao_list pointer and notifies the driver of the allocated size. It is
| done by indicating the size of the buffer in bytes to the rrao_list_leng variable as an
| input to the receive_rao_list structure.
These commands and associated data structures are defined in the mtio.h system
header file in the /usr/include/sys directory and in the uscsi.h system header file in
/usr/include/sys/scsi/imple directory. Any application program that issues these
commands must include this header file.
MTIOCTOP
This command runs the magnetic tape drive operations. It is identical to the
STIOC_TAPE_OP IOCTL command that is defined in the /usr/include/sys/st.h header
file. The STIOC_TAPE_OP and MTIOCTOP commands both use the same data structure
that is defined in the /usr/include/sys/mtio.h system header file. The two IOCTL
commands are interchangeable. See “STIOC_TAPE_OP” on page 245.
MTIOCGET
This command returns the status information about the tape drive. It is identical to
the STIOC_GET_DEVICE_STATUS IOCTL command defined in the /usr/include/sys/st.h
header file. The STIOC_GET_DEVICE_STATUS and MTIOCGET commands both use the
same data structure that is defined in the /usr/include/sys/mtio.h system header
file. The two IOCTL commands are interchangeable. See
“STIOC_GET_DEVICE_STATUS” on page 247.
MTIOCGETDRIVETYPE
This command returns the configuration information about the tape drive. It is
identical to the STIOC_GET_DEVICE_INFO IOCTL command defined in the
/usr/include/sys/st.h header file. The STIOC_GET_DEVICE_INFO and MTIOCTOP
commands both use the same data structure that is defined in the
/usr/include/sys/mtio.h system header file. The two IOCTL commands are
interchangeable. See “STIOC_GET_DEVICE_INFO” on page 248.
USCSICMD
This command provides the user a SCSI command interface.
if (device.ultrium)
uscsi_cmd.uscsi_rqlen = 36;
else if (device.t3590 || device.t3570)
uscsi_cmd.uscsi_rqlen = 96;
else if (device.t3490)
uscsi_cmd.uscsi_rqlen = 54;
uscsi_cmd.uscsi_rqbuf = (char *)&rq_buf
return (rc);
Note: This interface is obsolete. It was superseded by the interface that is defined
in the /usr/include/sys/st.h header file. New development efforts must use
the st.h interface to ensure its compatibility with future releases of the
Solaris Tape and Medium Changer Device Driver.
These commands and associated data structures are defined in the oldtape.h
header file in the /usr/include/sys directory that is installed with the IBMtape
package. Any application program that issues these commands must include this
header file.
Note: The oldtape.h header file replaces the Atape.h header file.
Issue the query command to fill the fields of the data structure with the current
data that you do not want to change. Make the changes to the required fields and
issue the set command to process the required changes.
The changes that are made through this IOCTL are effective only during the
current open session. The tape drive reverts to the default working parameters
established by the configuration file at the time of the next open operation.
The following data structure is filled out and supplied by the caller (and also filled
out and returned by the driver).
struct stchgp_s {
int blksize; /* block size */
struct sttrc_s {
boolean trace; /* not used */
ulong hkwrd; /* not used */
} sttrc;
int sync_count; /* OBSOLETE AND UNSUPPORTED */
boolean autoload; /* OBSOLETE AND UNSUPPORTED */
boolean buffered_mode; /* on/off buffered mode */
boolean compression; /* on/off compression mode */
boolean trailer_labels; /* on/off write past EOM mode */
boolean rewind_immediate; /* on/off immediate rewind mode */
boolean reserved[64]; /* reserved */
};
STIOCSYNC
This command immediately flushes the drive buffers to the tape (commits the data
to the media).
STIOCDM
This command displays and manipulates one or two messages on the tape drive
console.
The message that is sent by using this call does not always remain on the display.
It depends on the current drive activity.
The following data structure is filled out and supplied by the caller.
288 IBM Tape Device Drivers: Programming Reference
struct stdm_s {
char dm_func; /* message function codes */
/* Function Selection */
#define DMSTATUSMSG 0x00 /* general status message */
#define DMDVMSG 0x20 /* demount/verify message */
#define DMMIMMED 0x40 /* mount with immediate action */
#define DMDEMIMMED 0xE0 /* demount with immediate action */
/* Message Control */
#define DMMSG0 0x00 /* display message 0 */
#define DMMSG1 0x04 /* display message 1 */
#define DMFLASHMSG0 0x08 /* flash message 0 */
#define DMFLASHMSG1 0x0C /* flash message 1 */
#define DMALTERNATE 0x10 /* alternate messages 0 and 1 */
#define MAXMSGLEN 8
char dm_msg0[MAXMSGLEN]; /* message 0 */
char dm_msg1[MAXMSGLEN]; /* message 1 */
};
STIOCQRYPOS or STIOCSETPOS
These commands allow a program to query and set the physical position on the
tape.
Tape position is defined as where the next read or write operation occurs. The
STIOCQRYPOS command and the STIOCSETPOS command can be used independently
or with each other.
The following data structure is filled out and supplied by the caller (and also filled
out and returned by the driver).
struct stpos_s
{
char block_type; /* format of block ID information */
#define QP_LOGICAL 0
#define QP_PHYSICAL 1
boolean eot; /* early warning EOT */
#define blockid_t unsigned int
blockid_t curpos; /* current or new tape position */
blockid_t lbot; /* last block written to tape */
#define LBOT_NONE 0xFFFFFFFF
#define LBOT_UNKNOWN 0xFFFFFFFE
char reserved[64]; /* reserved */
};
The block_type field is set to QP_LOGICAL for standard SCSI logical tape
positions. It is set to QP_PHYSICAL for composite tape positions that are used for
high-speed locate operations that are implemented by the tape drive.
For STIOCSETPOS commands, the block_type and curpos fields must be filled out
by the caller. The other fields are ignored. The type of position that is specified in
Following a STIOCQRYPOS command, the lbot field indicates the last block of data
that was transferred physically to the tape. For example, if the application wrote to
12 blocks and lbot equals 8, four blocks are in the tape buffer. This field is valid
only if the last command was a write operation. Otherwise, LBOT_UNKNOWN is
returned. It does not reflect the number of application write operations because a
single write operation can translate to multiple blocks.
oldposition = stpos.curpos;
/* do other stuff... */
stpos.curpos = oldposition;
stpos.block_type = QP_PHYSICAL;
STIOCQRYSENSE
This command returns the sense data that is collected from the tape drive.
The following data structure is filled out and supplied by the caller (and also filled
out and returned by the driver).
struct stsense_s {
/* INPUT */
char sense_type; /* new sense or last error sense */
#define FRESH 1
#define LASTERROR 2
/* OUTPUT */
#define MAXSENSE 128
char sense[MAXSENSE]; /* actual sense data */
int len; /* length of sense data returned */
char reserved[64]; /* reserved */
};
If sense_type is set to LASTERROR, the last sense data that is collected from the
device is returned. If it is set to FRESH, a new Request Sense command is issued
and the sense data is returned.
STIOCQRYINQUIRY
This command returns the inquiry data that is collected from the tape drive.
The following data structure is filled out and returned by the driver.
struct inq_data_s {
BYTE b0; /* peripheral device byte */
#define PERIPHERAL_QUALIFIER(x) ((x->b0 & 0xE0)>>5)
#define PERIPHERAL_CONNECTED 0x00
#define PERIPHERAL_NOT_CONNECTED 0x01
#define LUN_NOT_SUPPORTED 0x03
#define PERIPHERAL_DEVICE_TYPE(x) (x->b0 & 0x1F)
#define DIRECT_ACCESS 0x00
#define SEQUENTIAL_DEVICE 0x01
#define PRINTER_DEVICE 0x02
#define PROCESSOR_DEVICE 0x03
#define CD_ROM_DEVICE 0x05
#define OPTICAL_MEMORY_DEVICE 0x07
#define MEDIUM_CHANGER_DEVICE 0x08
#define UNKNOWN 0x1F
BYTE b1; /* removable media/device type byte */
#define RMB(x) ((x->b1 & 0x80)>>7)
#define FIXED 0
#define REMOVABLE 1
#define device_type_qualifier(x) (x->b1 & 0x7F)
BYTE b2; /* standards version byte */
#define ISO_Version(x) ((x->b2 & 0xC0)>>6)
#define ECMA_Version(x) ((x->b2 & 0x38)>>3)
#define ANSI_Version(x) (x->b2 & 0x07)
#define NONSTANDARD 0
#define SCSI1 1
#define SCSI2 2
BYTE b3; /* asynchronous event notification */
#define AENC(x) ((x->b3 & 0x80)>>7)
#define TrmIOP(x) ((x->b3 & 0x40)>>6)
#define Response_Data_Format(x) (x->b3 & 0x0F)
#define SCSI1INQ 0
#define CCSINQ 1
#define SCSI2INQ 2
BYTE additional_length;
BYTE res56[2]; /* reserved bytes */
BYTE b7; /* protocol byte */
#define RelAdr(x) ((x->b7 & 0x80)>>7)
#define WBus32(x) ((x->b7 & 0x40)>>6)
#define WBus16(x) ((x->b7 & 0x20)>>5)
#define Sync(x) ((x->b7 & 0x10)>>4)
#define Linked(x) ((x->b7 & 0x08)>>3)
#define CmdQue(x) ((x->b7 & 0x02)>>1)
#define SftRe(x) (x->b7 & 0x01)
These commands and associated data structures are defined in the svc.h header file
in the /usr/include/sys directory that is installed with the IBMtape package. Any
application program that issues these commands must include this header file.
The following data structure is filled out and returned by the driver.
typedef uint device_sn_t;
device_sn_t device_sn;
else {
perror ("Failure obtaining tape device serial number");
scsi_request_sense ();
}
IOC_FORCE_DUMP
This command forces the device to complete a diagnostic dump.
else {
perror ("Failure performing device dump");
scsi_request_sense ();
}
IOC_STORE_DUMP
This command forces the device to write the diagnostic dump to the currently
mounted tape cartridge. The IBM 3490E Magnetic Tape Subsystem and the IBM
Enterprise Model B18 Virtual Tape Server do not support this command.
else {
perror ("Failure storing dump on tape");
scsi_request_sense ();
}
The following data structure is filled out and supplied by the caller.
typedef struct {
uchar mode; /* transfer mode */
uchar id; /* device buffer id */
uint offset; /* buffer offset */
uint size; /* byte count */
uchar *buffer; /* data buffer */
} buffer_io_t;
buffer_io_t buffer_io;
else {
perror ("Failure reading buffer");
scsi_request_sense ();
}
IOC_WRITE_BUFFER
This command writes data to the specified device buffer.
The following data structure is filled out and supplied by the caller.
typedef struct {
uchar mode; /* transfer mode */
uchar id; /* device buffer id */
uint offset; /* buffer offset */
uint size; /* byte count */
uchar *buffer; /* data buffer */
} buffer_io_t;
else {
perror ("Failure writing buffer");
scsi_request_sense ();
}
IOC_DEVICE_PATH
This command returns the information about the path information for a particular
path or all of the paths for a particular parent device.
The following data structure is filled out and returned by the driver.
typedef struct {
int instance; /* Instance Number of this path */
int tgt; /* SCSI target for this path */
int lun; /* SCSI LUN for this path */
uint64_t wwnn; /* WWNN for this fc path */
uint64_t wwpn; /* WWPN for this fc path */
int path_type; /* primary 0 or
alt 1, 2, 3, ..., 15 */
/* none 0xFF */
int enable; /* path enable 1, disable 0 */
char devpath[125]; /* devices path of this path */
char dev_ser[33]; /* Device serial number */
char ucode_level[32]; /* Device microcode level */
} device_path_t;
typedef struct {
int number_paths; /* number of paths configured */
device_paths_t device_paths;
IOC_CHECK_PATH
This command is used to display the enable or disable information for each path in
the path table.
The following data structure is filled out and returned by the driver.
typedef struct {
int number_paths; /* number of paths configured */
path_enable_t path_enable[MAX_SCSI_PATH];
} check_path_t;
The following data structure is filled out and returned by the driver.
typedef struct {
int path; /* Failover path: primary path: 0 */
/* alternate path: 1, 2, 3, ..., 15 */
/* No failover path : 0xFF */
int enable; /* path enable 1, disable 0 */
} path_enable_t;
check_path_t check_path;
path_enable_t path_enable;
Return codes
The calls to the IBMtape device driver return error codes that describe the outcome
of the call. The returned error codes are defined in the errno.h system header file
in the /usr/include/sys directory.
For the open, close, and IOCTL calls, the return code of the function call is either
0 for success, or -1 for failure. Then, the system global variable errno contains the
error value. For the read and write calls, the return code of the function call
contains the actual number of bytes read or written if the operation was successful.
Or, 0 if no data was transferred due to encountering end of file or end of tape. If
the read or write operation completely failed, the return code is set to -1 and the
error value is stored in the system global variable errno.
The error codes that are returned from IBMtape are described in the following
section.
Note: The EIO return code indicates that a device-related input/output (I/O) error
occurred. Further information about the error can be obtained by using the
IOC_REQUEST_SENSE IOCTL command to retrieve sense data. This sense data
can then be interpreted with the device hardware or SCSI reference.
If the open system call fails, it returns -1, and the system errno value contains the
error code as defined in the /usr/include/sys/errno.h header file.
where:
count is the return code from the write command.
fd is the file descriptor of a previously opened special file.
buffer is a pointer to the source data buffer.
numbytes is the number of bytes requested to be written.
If the device is configured to use a fixed block size, numbytes must be a whole
number multiple of the block size. If the block size is variable, the value that is
specified in numbytes is the size of the block written.
After each call to write is issued, the return code tells how many bytes were
written. Normally, the return code is the same as the number of bytes requested in
the write command. There are some exceptions, however. If the device is
configured to use fixed block size, and a write is for multiple blocks, possibly only
some of the requested blocks can be written. This action is called a short write.
The return code from a short write is less than the number of bytes requested, but
always a whole number multiple of the block size. Applications that write multiple
fixed blocks must be prepared to handle short writes, and calculate from the return
code which blocks were not transferred to tape. Short writes are not an error
condition, and IBMtape does not set a value for the errno system variable.
v A return code of zero indicates that the logical end of medium (LEOM) is
reached. None of the requested bytes were written. A return code of zero is not
an error condition, and IBMtape does not set a value for the errno system
variable.
v If the return code is less than zero, the write operation failed. None of the
requested bytes were written. IBMtape sets an error code in the errno system
variable.
where:
count is the return code from the read command.
fd is the file descriptor of a previously opened special file.
If the device is configured for variable block size, a single block of up to numbytes
bytes is read. However, if the block size on tape is greater than numbytes, the read
fails, with errno set to ENOMEM. This action is called an overlength read
condition.
If the device is configured to use a fixed block size, numbytes must be a whole
number multiple of that block size. If numbytes is not such a multiple, IBMtape
fails the read and sets errno to EINVAL. If the block size on tape does match the
configured block size, whether larger or smaller, the read fails, with errno set to
EIO. This action is called an incorrect length condition.
After the read is issued, if count is less than zero, the read failed, no data is
returned. The system variable errno is set to indicate the type of error. See “Read
error codes” on page 298 for a complete list of errno values and their meanings.
If count equals zero, then the end of medium (EOM) or a filemark was
encountered before any data was read. This issue is not an error condition, and
IBMtape does not set errno. If a second read returns zero, the application infers that
EOM is reached. Otherwise, the application infers that a filemark was encountered.
When a filemark is encountered while reading, the tape is left positioned on the
end of medium (EOM) side of the filemark.
If greater than zero, count reports how many bytes were read from tape. Even
though greater than zero, it can still be less than numbytes. If the device is
configured for variable blocks, count can be any value between 1 and numbytes. If
configured to use a fixed block size, count can always be a whole number multiple
of that block size. In either case, such a condition is called an underlength read or
short read.
Underlength reads are not error conditions, and IBMtape does not set errno.
However, for variable block mode, some overhead processing that is incurred by
underlength reads can be eliminated by setting the SILI parameter to 1. This action
can improve read performance. See “STIOC_GET_PARM” on page 251 for
information on the SILI parameter.
An application explicitly issues the close call when the I/O resource is no longer
necessary, or in preparation for termination. The operating system implicitly issues
the close call for an application that terminates without closing the resource itself.
If an application terminates unexpectedly, but leaves behind child processes that
inherited the file descriptor for the open resource, the operating system does not
implicitly close the file descriptor because it believes that it is still in use.
The close operation behavior depends on which special file was used during the
open operation and which tape operation was last run while it was opened. The
commands are issued to the tape drive during the close operation according to the
following logic and rules.
if last operation was WRITE FILEMARK
WRITE FILEMARK
BACKWARD SPACE 1 FILEMARK
SYNC BUFFER
Rules:
1. Return EIO and release the drive when a unit attention happens before the
close().
2. Fail the command, return EIO and release the drive if a unit attention occurs
during the close().
3. If a SCSI command fails during close processing, only the SCSI RELEASE is
attempted thereafter.
4. If the tape is already unloaded from the driver, no SYNC BUFFER (WFM(0)) or
rewinding (only for rewind-on-close special files) of the tape is done.
5. The return code from the SCSI RELEASE command is ignored.
The fd is the file descriptor that is returned from the open system call. The
command is the value of the IOCTL operation that is defined in the appropriate
header file. Also, buffer is the address of the user memory where data is passed to
the device driver and returned to the application.
The IOCTL operations that are supported by the Solaris Tape and Medium
Changer Device Driver are defined in the following header files. They are included
with the IBMtape package and installed in the /usr/include/sys subdirectory. These
header files must be included by any application source file that requires access the
IOCTL functions that are supported by the IBMtape device driver. (Existing
applications that use the standard Solaris tape drive IOCTL operations that are
defined in the native mtio.h header file in the /usr/include/sys are fully supported
by the IBMtape device driver.)
v st.h (tape drive operations)
v smc.h (medium changer operations)
v svc.h (service aid operations)
v oldtape.h (downward compatible tape drive operations, obsolete)
The programming interface conforms to the standard Microsoft Windows 200x tape
device driver interface. It is detailed in the Microsoft Developer Network (MSDN)
Software Development Kit (SDK), and Driver Development Kit (DDK).
Programs that access the IBM TotalStorage device driver must complete the
following steps:
1. Include the following files in the application.
#include <ntddscsi.h>
#include <ntddchgr.h>
#include <ntddtape.h> /* Modified as indicated below */
2. Add the following lines to ntddtape.h.
| #define LB_ACCESS FILE_READ_ACCESS | FILE_WRITE_ACCESS
| #define M_MTI(x) CTL_CODE(IOCTL_BASE+2,x,METHOD_BUFFERED, LB_ACCESS)
| #define IOCTL_TAPE_OBTAIN_SENSE CTL_CODE(IOCTL_TAPE_BASE, 0x0819,
| METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_TAPE_OBTAIN_VERSION CTL_CODE(IOCTL_TAPE_BASE, 0x081a,
| METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_TAPE_LOG_SELECT CTL_CODE(IOCTL_TAPE_BASE, 0x081c,
| METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
| #define IOCTL_TAPE_LOG_SENSE CTL_CODE(IOCTL_TAPE_BASE, 0x081d,
| METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_TAPE_LOG_SENSE10 CTL_CODE(IOCTL_TAPE_BASE, 0x0833,
| METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_ENH_TAPE_LOG_SENSE10 CTL_CODE(IOCTL_TAPE_BASE, 0x0835, METHOD_BUFFERED,
| FILE_READ_ACCESS )
| #define IOCTL_TAPE_REPORT_MEDIA_DENSITY CTL_CODE(IOCTL_TAPE_BASE, 0x081e,
| METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_TAPE_OBTAIN_MTDEVICE (M_MTI(16))
| #define IOCTL_CREATE_PARTITION CTL_CODE(IOCTL_TAPE_BASE, 0x0826, METHOD_BUFFERED,
| FILE_READ_ACCESS | FILE_WRITE_ACCESS )
| #define IOCTL_QUERY_PARTITION CTL_CODE(IOCTL_TAPE_BASE, 0x0825, METHOD_BUFFERED,
| FILE_READ_ACCESS | FILE_WRITE_ACCESS )
| #define IOCTL_SET_ACTIVE_PARTITION CTL_CODE(IOCTL_TAPE_BASE, 0x0827, METHOD_BUFFERED,
| FILE_READ_ACCESS | FILE_WRITE_ACCESS )
| #define IOCTL_QUERY_DATA_SAFE_MODE CTL_CODE(IOCTL_TAPE_BASE, 0x0823, METHOD_BUFFERED,
| FILE_READ_ACCESS | FILE_WRITE_ACCESS )
| #define IOCTL_SET_DATA_SAFE_MODE CTL_CODE(IOCTL_TAPE_BASE, 0x0824, METHOD_BUFFERED,
| FILE_READ_ACCESS | FILE_WRITE_ACCESS )
| #define IOCTL_ALLOW_DATA_OVERWRITE CTL_CODE(IOCTL_TAPE_BASE, 0x0828, METHOD_BUFFERED,
| FILE_READ_ACCESS | FILE_WRITE_ACCESS )
| #define IOCTL_SET_PEW_SIZE
| CTL_CODE(IOCTL_TAPE_BASE, 0x082C, METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_QUERY_PEW_SIZE
| CTL_CODE(IOCTL_TAPE_BASE, 0x082B, METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_VERIFY_TAPE_DATA
| CTL_CODE(IOCTL_TAPE_BASE, 0x082A, METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_QUERY_RAO_INFO CTL_CODE(IOCTL_TAPE_BASE, 0x082E, METHOD_BUFFERED,
| FILE_READ_ACCESS )
CreateFile
The CreateFile entry point is called to make the driver and device ready for
input/output (I/O). Only one CreateFile at a time is allowed for each LUN on a
TotalStorage device. More opens of the same LUN on a device fails. The following
code fragment illustrates a call to the CreateFile routine:
HANDLE ddHandle0, ddHandle1; // file handle for LUN0 and LUN1
/*
** Open for reading/writing on LUN0,
** where the device special file name is in the form of tapex and
** x is the logical device 0 to n - can be determined from Registry
**
** Open for media mover operations on LUN1,
** where the device special file name is in the form of
** changerx and x is the logical device 0 to n - can be determined from Registry
*/
ddHandle0 = CreateFile(
"\\\\.\\tape0",
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDistribution,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
ddHandle1 = CreateFile(
"\\\\.\\changer0",
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDistribution,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
/* Print msg if open failed for handle 0 or 1 */
if(ddHandlen == INVALID_HANDLE_VALUE)
{
printf("open failed for LUNn\n");
printf("System Error = %d\n",GetLastError());
exit (-1);
}
The CloseHandle entry point is called to stop I/O to the driver and device. The
following code fragment illustrates a call to the CloseHandle routine:
BOOL rc;
rc = CloseHandle(
ddHandle0
);
if (!rc)
{
printf("close failed\n");
printf("System Error = %d\n",GetLastError());
exit (-1);
}
where ddHandle0 is the open file handle returned by the CreateFile call.
See “Variable and fixed block read/write processing” on page 333 for a full
discussion of the read/write processing feature.
rc = ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nBufferSize,
LPDWORD lpBytesRead,
LPOVERLAPPED lpOverlapped
);
if(rc)
{
if (*lpBytesRead > 0)
printf("Read %d bytes\n", *lpBytesRead);
else
printf("Read found file mark\n");
}
else
{
printf("Error on read\n");
printf("System Error = %d\n",GetLastError());
exit (-1);
}
Where hFile is the open file handle, lpBuffer is the address of a buffer in which
to place the data, nBufferSize is the number of bytes to be read, and lpBytesRead
is the number of bytes read.
WriteFile
The WriteFile entry point is called to write data to the tape. The caller provides the
address and length of the buffer to be written to tape. The physical limitations of
the drive can cause the write to fail. One example is attempting to write past the
physical end of the tape.
See “Variable and fixed block read/write processing” on page 333 for a full
discussion of the read/write processing feature.
rc = WriteFile(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nBufferSize,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
);
if (!rc)
{
Where hFile is the open file handle, lpBuffer is the buffer address, and
nBufferSize is the size of the buffer in bytes.
If the function succeeds, the return value rc is nonzero. The application also
verifies that all the requested data was written by examining the
lpNumberOfBytesWritten parameter. See “Write Tapemark” for details on
committing data on the media.
Write Tapemark
Application writers who are using the WriteFile entry point to write data to tape
must understand that the tape device buffers data in its memory and writes that
data to the media as those device buffers fill. Thus, a WriteFile call might return a
successful return code, but the data might not be on the media yet. Calling the
WriteTapemark entry point and receiving a good return code, however, ensures
that data is committed to tape media properly if all previous WriteFile calls were
successful. However, applications that write large amounts of data to tape might
not want to wait until writing a tapemark to know whether previous data was
written to the media properly. For example:
WriteTapemark(
HANDLE hDevice,
DWORD dwTapemarkType,
DWORD dwTapemarkCount,
BOOL bImmediate
);
The WriteTapemark entry point might also be called with the dwTapemarkCount
parameter set to 0 and the bImmediate parameter that is set to FALSE. This action
commits any uncommitted data that is written by previous WriteFile calls (since
the last call to WriteTapemark) to the media. If no error is returned by the
WriteFile calls and the WriteTapemark call, the application can assume that all
data is committed to the media successfully.
SetTapePosition
The SetTapePosition entry point is called to seek to a particular block of media
data. For example:
SetTapePosition(
HANDLE hDevice,
DWORD dwPositionMethod,
DWORD dwPartition,
DWORD dwOffsetLow,
DWORD dwOffsetHigh,
BOOL bImmediate
);
For Magstar devices, there is no difference between the absolute and logical block
addresses.
GetTapePosition
The GetTapePosition entry point is called to retrieve the current tape position. For
example:
GetTapePosition(
HANDLE hDevice,
DWORD dwPositionType,
LPDWORD lpdwPartition,
LPDWORD lpdwOffsetLow,
LPDWORD lpdwOffsetHigh
);
SetTapeParameters
The SetTapeParameters entry point is called to either specify the block size of a
tape or set tape device data compression. The data structures are
struct{ // structure used by operation SET_TAPE_MEDIA_INFORMATION
ULONG BlockSize;
}TAPE_SET_MEDIA_PARAMETERS;
SetTapeParameters(
HANDLE hDevice,
DWORD dwOperation,
LPVOID lpParameters
);
GetTapeParameters
The GetTapeParameters entry point is called to get information that describes the
tape or the tape drive.
rc = GetTapeParameters(
HANDLE hDevice,
DWORD dwOperation,
LPDWORD lpdwSize,
LPVOID lpParameters
);
if (rc)
{
printf("Error on GetTapeParameters\n");
printf("System Error = %d\n",GetLastError());
exit (-1);
}
Where hDevice is the open file handle, dwOperation is the type of information
requested (GET_TAPE_MEDIA_INFORMATION or
GET_TAPE_DRIVE_INFORMATION), and lpParameters is the address of the
returned data parameter structure.
PrepareTape
The PrepareTape entry point is called to prepare the tape for access or removal.
For example,
PrepareTape(
HANDLE hDevice,
DWORD dwOperation,
BOOL bImmediate
);
EraseTape
The EraseTape entry point is called to erase all or a part of a tape. The erase is
completed from the current location. For example:
EraseTape(
HANDLE hDevice,
DWORD dwEraseType,
BOOL bImmediate
);
GetTapeStatus
The GetTapeStatus entry point is called to determine whether the tape device is
ready to process tape commands. For example,
GetTapeStatus(
HANDLE hDevice
);
hDevice is the handle to the device for which to get the device status.
DeviceIoControl
The DeviceIoControl function is described in the Microsoft Developer Network
(MSDN) Software Developer Kit(SDK) and Device Driver Developer Kit (DDK).
An example of the use of SCSI Pass Through is contained in the sample code
SPTI.C in the DDK.
The function call DeviceIoControl is described in the SDK and examples of its use
are shown in the DDK.
IOCTL commands
Not all source or destination addresses, exchanges, moves, or operations are
allowed for a particular IBM Medium Changer. The user must issue an
IOCTL_CHANGER_GET_PARAMETER to determine the type of operations that
are allowed by a specific changer device. Further information on allowable
commands for a particular changer can be found in the IBM hardware reference
for that device. It is recommended that the user have a copy of the hardware
reference before any applications for the changer device are constructed.
The media from the source element is moved to the first destination element. The
medium that previously occupied the first destination element is moved to the
second destination element (the second destination element might be the same as
the source) by sending an ExchangeMedium (0xA6) SCSI command to the device.
The input data is a structure of CHANGER_EXCHANGE_MEDIUM. This
command is not supported by all devices.
IOCTL_CHANGER_GET_ELEMENT_STATUS
IOCTL_CHANGER_GET_PARAMETERS
IOCTL_CHANGER_GET_PRODUCT_DATA
Returns the product data for the changer. The output data is in a structure of
CHANGER_PRODUCT_DATA.
IOCTL_CHANGER_GET_STATUS
IOCTL_CHANGER_INITIALIZE_ELEMENT_STATUS
IOCTL_CHANGER_MOVE_MEDIUM
IOCTL_CHANGER_REINITIALIZE_TRANSPORT
IOCTL_CHANGER_SET_ACCESS
The following ioctl commands are supported by the ibmtp.sys driver through
DeviceIoControl.
| #define LB_ACCESS FILE_READ_ACCESS | FILE_WRITE_ACCESS
| #define M_MTI(x) CTL_CODE(IOCTL_BASE+2,x,METHOD_BUFFERED, LB_ACCESS)
| #define IOCTL_TAPE_OBTAIN_SENSE CTL_CODE(IOCTL_TAPE_BASE, 0x0819,
| METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_TAPE_OBTAIN_VERSION CTL_CODE(IOCTL_TAPE_BASE, 0x081a,
| METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_TAPE_LOG_SELECT CTL_CODE(IOCTL_TAPE_BASE, 0x081c,
| METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
| #define IOCTL_TAPE_LOG_SENSE CTL_CODE(IOCTL_TAPE_BASE, 0x081d,
| METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_TAPE_LOG_SENSE10 CTL_CODE(IOCTL_TAPE_BASE, 0x0833,
| METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_ENH_TAPE_LOG_SENSE10 CTL_CODE(IOCTL_TAPE_BASE, 0x0835, METHOD_BUFFERED,
| FILE_READ_ACCESS )
| #define IOCTL_TAPE_REPORT_MEDIA_DENSITY CTL_CODE(IOCTL_TAPE_BASE, 0x081e,
| METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_TAPE_OBTAIN_MTDEVICE (M_MTI(16))
| #define IOCTL_CREATE_PARTITION CTL_CODE(IOCTL_TAPE_BASE, 0x0826, METHOD_BUFFERED,
| FILE_READ_ACCESS | FILE_WRITE_ACCESS )
| #define IOCTL_QUERY_PARTITION CTL_CODE(IOCTL_TAPE_BASE, 0x0825, METHOD_BUFFERED,
| FILE_READ_ACCESS | FILE_WRITE_ACCESS )
| #define IOCTL_SET_ACTIVE_PARTITION CTL_CODE(IOCTL_TAPE_BASE, 0x0827, METHOD_BUFFERED,
| FILE_READ_ACCESS | FILE_WRITE_ACCESS )
| #define IOCTL_QUERY_DATA_SAFE_MODE CTL_CODE(IOCTL_TAPE_BASE, 0x0823, METHOD_BUFFERED,
| FILE_READ_ACCESS | FILE_WRITE_ACCESS )
| #define IOCTL_SET_DATA_SAFE_MODE CTL_CODE(IOCTL_TAPE_BASE, 0x0824, METHOD_BUFFERED,
| FILE_READ_ACCESS | FILE_WRITE_ACCESS )
| #define IOCTL_ALLOW_DATA_OVERWRITE CTL_CODE(IOCTL_TAPE_BASE, 0x0828, METHOD_BUFFERED,
| FILE_READ_ACCESS | FILE_WRITE_ACCESS )
| #define IOCTL_SET_PEW_SIZE
| CTL_CODE(IOCTL_TAPE_BASE, 0x082C, METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_QUERY_PEW_SIZE
| CTL_CODE(IOCTL_TAPE_BASE, 0x082B, METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_VERIFY_TAPE_DATA
| CTL_CODE(IOCTL_TAPE_BASE, 0x082A, METHOD_BUFFERED, FILE_READ_ACCESS )
| #define IOCTL_QUERY_RAO_INFO CTL_CODE(IOCTL_TAPE_BASE, 0x082E, METHOD_BUFFERED,
| FILE_READ_ACCESS )
| #define IOCTL_GENERATE_RAO CTL_CODE(IOCTL_TAPE_BASE, 0x082F, METHOD_BUFFERED,
| FILE_READ_ACCESS )
| #define IOCTL_RECEIVE_RAO CTL_CODE(IOCTL_TAPE_BASE, 0x0834, METHOD_BUFFERED,
| FILE_READ_ACCESS )
IOCTL_TAPE_OBTAIN_VERSION
Issue this command to obtain the version of the device driver. It is in the form of a
null terminated string.
IOCTL_TAPE_LOG_SELECT
This command resets all log pages that can be reset on the device to their default
values. This IOCTL is only for the tape path.
IOCTL_TAPE_LOG_SENSE
Issue this command to obtain the log data of the requested log page from IBM
Magstar tape device. The data that is returned is formatted according to the IBM
Magstar hardware reference.
DeviceIoControl(hDevice,
IOCTL_TAPE_LOG_SENSE,
&logsense,
(long)sizeof(TAPE_LOG_SENSE_PARAMETERS,
&logsense,
(long)sizeof(TAPE_LOG_SENSE_PARAMETERS,
&cb,
(LPOVERLAPPED) NULL);
IOCTL_TAPE_LOG_SENSE10
Issue this command to obtain the log data of the requested log page/subpage from
IBM Magstar tape device. The data returned is formatted according to the IBM
Magstar hardware reference. This IOCTL is only for the tape path.
| IOCTL_ENH_TAPE_LOG_SENSE10
| Issue this command to obtain the log data of the requested log page/subpage from
| IBM TotalStorage tape device. The data that is returned is formatted according to
| the IBM TotalStorage hardware reference. This IOCTL is only for the tape path and
| is enhanced so the application can set the page length and provide the buffer
| enough to get the data back. The following input/output structure is used by the
| IOCTL_ENH_TAPE_LOG_SENSE10 command.
| typedef struct _ENH_TAPE_LOG_SENSE_PARAMETERS_WITH_SUBPAGE{
| UCHAR PageCode; /* [IN] Log sense page */
| UCHAR SubPageCode; /* [IN] Log sense subpage */
| UCHAR PC; /* [IN] PC bit */
| UCHAR reserved[5]; /* unused */
| ULONG Length; /* [IN][OUT] number of valid bytes in data */
| /* (log_page_header_size+page_length) */
| ULONG parm_pointer; /* [IN] specific parameter number at which */
| /* the data begins */
| CHAR LogData[1]; /* [IN] log sense buffer allocated by */
| /* application */
| /* [OUT] log sense data */
| } ENH_TAPE_LOG_SENSE_PARAMETERS_WITH_SUBPAGE, *PENH_TAPE_LOG_SENSE_PARAMETERS_WITH_SUBPAGE;
| IOCTL_TAPE_REPORT_MEDIA_DENSITY
Issue this command to obtain the media density information on the loaded media
in the drive. If there is no media load, the command fails. This IOCTL is only for
the tape path.
DeviceIoControl (hDevice,
IOCTL_TAPE_REPORT_MEDIA_DENSITY,
NULL,
0,
&tape_reportden,
(long)sizeof(TAPE_REPORT_DENSITY),
&cb,
(LPOVERLAPPED) NULL);
IOCTL_TAPE_OBTAIN_MTDEVICE
Issue this command to obtain the device number of a 3590 TotalStorage device in
an IBM 3494 Enterprise Tape Library. An error is returned if it is issued against a
3570 drive.
*rc_ptr = DeviceIoControl(gp->ddHandle0,
IOCTL_TAPE_OBTAIN_MTDEVICE,
NULL,
0,
&mt_device,
(long)sizeof(TAPE_OBTAIN_MTDEVICE),
&cb,
(LPOVERLAPPED) NULL);
IOCTL_TAPE_GET_DENSITY
The IOCTL code for IOCTL_TAPE_GET_DENSITY is defined as follows.
#define IOCTL_TAPE_GET_DENSITY \
CTL_CODE(IOCTL_TAPE_BASE, 0x000c, METHOD_BUFFERED, \
FILE_READ_ACCESS | FILE_WRITE_ACCESS).
The IOCTL reports density for supported devices by using the following structure.
typedef struct _TAPE_DENSITY
{
UCHAR ucDensityCode;
UCHAR ucDefaultDensity;
UCHAR ucPendingDensity;
} TAPE_DENSITY, *PTAPE_DENSITY;
rc = DeviceIoControl(hDevice,
IOCTL_TAPE_GET_DENSITY,
NULL,
0,
&tape_density,
sizeof(TAPE_DENSITY),
&cb,
(LPOVERLAPPED) NULL);
IOCTL_TAPE_SET_DENSITY
The IOCTL code for IOCTL_TAPE_SET_DENSITY is defined as follows.
#define IOCTL_TAPE_SET_DENSITY \
CTL_CODE(IOCTL_TAPE_BASE, 0x000d, METHOD_BUFFERED, \
FILE_READ_ACCESS | FILE_WRITE_ACCESS)
The IOCTL sets density for supported devices by using the following structure.
typedef struct _TAPE_DENSITY
{
UCHAR ucDensityCode;
UCHAR ucDefaultDensity;
UCHAR ucPendingDensity;
} TAPE_DENSITY, *PTAPE_DENSITY;
rc = DeviceIoControl(hDevice,
IOCTL_TAPE_SET_DENSITY,
&tape_density,
sizeof(TAPE_DENSITY),
IOCTL_TAPE_GET_ENCRYPTION_STATE
This IOCTL command queries the drive's encryption method and state.
The IOCTL gets encryption states for supported devices by using the following
structure.
typedef struct _ENCRYPTION_STATUS
{
UCHAR ucEncryptionCapable; /* (1)Set this field as a boolean based on
the capability of the drive */
UCHAR ucEncryptionMethod; /* (2)Set this field to one of the
defines METHOD_* below */
UCHAR ucEncryptionState; /* (3)Set this field to one of the
#defines STATE_* below */
UCHAR aucReserved[13];
} ENCRYPTION_STATUS, *PENCRYPTION_STATUS;
IOCTL_TAPE_SET_ENCRYPTION_STATE
This IOCTL command allows only set encryption state for application-managed
encryption.
The data structure that is used for this IOCTL is the same as for
IOCTL_GET_ENCRYPTION_STATE.
#define IOCTL_TAPE_SET_ENCRYPTION_STATE CTL_CODE(IOCTL_TAPE_BASE, 0x0821,
METHOD_BUFFERED,
FILE_READ_ACCESS | FILE_WRITE_ACCESS )
IOCTL_TAPE_SET_DATA_KEY
This IOCTL command is used to set the data key only for application-managed
encryption.
The IOCTL sets data keys for supported devices by using the following structure.
#define IOCTL_TAPE_SET_DATA_KEY CTL_CODE(IOCTL_TAPE_BASE, 0x0822,
METHOD_BUFFERED,
FILE_READ_ACCESS | FILE_WRITE_ACCESS )
#define DATA_KEY_INDEX_LENGTH 12
#define DATA_KEY_RESERVED1_LENGTH 15
#define DATA_KEY_LENGTH 32
#define DATA_KEY_RESERVED2_LENGTH 48
typedef struct _DATA_KEY
{
UCHAR aucDataKeyIndex[DATA_KEY_INDEX_LENGTH];
UCHAR ucDataKeyIndexLength;
UCHAR aucReserved1[DATA_KEY_RESERVED1_LENGTH];
UCHAR aucDataKey[DATA_KEY_LENGTH];
UCHAR aucReserved2[DATA_KEY_RESERVED2_LENGTH];
} DATA_KEY, *PDATA_KEY;
IOCTL_CREATE_PARTITION
This command is used to create one or more partitions on the tape. The tape must
be at BOT (partition 0 logical block id 0) before the command is issued or it fails.
The application must either issue this IOCTL_CREATE_PARTITION after a tape is
IOCTL_QUERY_PARTITION
This command returns partition information for the current loaded tape.
IOCTL_SET_ACTIVE_PARTITION
This command is used to set the current active partition that is used on tape and
locate to a specific logical block id within the partition. If the logical block id is 0,
the tape is positioned at BOP. If the partition number specified is 0 along with a
logical block id 0, the tape is positioned at both BOP and BOT.
IOCTL_QUERY_DATA_SAFE_MODE
This command reports if the Data Safe Mode is enabled or disabled.
The structure that is used to enable or disable Data Safe Mode is the same as
IOCTL_QUERY_DATA_SAFE_MODE.
IOCTL_ALLOW_DATA_OVERWRITE
This command allows previously written data on the tape to be overwritten. This
action happens when append only mode is enabled on the drive with either a
write type command or a format command is allowed on the
IOCTL_CREATE_PARTITION. Before this IOCTL is issued, the application must locate
to the partition number and logical block id within the partition where the data
overwrite or format occurs.
IOCTL_READ_TAPE_POSITION
This command returns Position data in either the short, long, or extended form.
The type of data to return is specified by setting the data_format field to either
RP_SHORT_FORM, RP_LONG_FORM, or RP_EXTENDED_FORM.
IOCTL_SET_TAPE_POSITION
This command is used to position the tape in the current active partition to either
a logical block id or logical filemark. The logical_id_type field in the IOCTL
structure specifies either a logical block or logical filemark.
*rc_ptr = DeviceIoControl(gp->ddHandle0,
IOCTL_SET_TAPE_POSITION_LOCATE16,
&tapePosition,
(long)sizeof(SET_TAPE_POSITION)
NULL,
0,
&cb,
(LPOVERLAPPED) NULL);
IOCTL_QUERY_LBP
This command returns logical block protection information. The following output
structure is completed by the IOCTL_QUERY_LBP command.
#define IOCTL_QUERY_LBP CTL_CODE(IOCTL_TAPE_BASE, 0x0831,
METHOD_BUFFERED,
FILE_READ_ACCESS | FILE_WRITE_ACCESS )
typedef struct _LOGICAL_BLOCK_PROTECTION {
IOCTL_SET_LBP
This command sets logical block protection information. The following input
structure is sent to the IOCTL_SET_LBP command.
#define IOCTL_SET_LBP CTL_CODE(IOCTL_TAPE_BASE, 0x0832,
METHOD_BUFFERED,
FILE_READ_ACCESS | FILE_WRITE_ACCESS )
typedef struct _LOGICAL_BLOCK_PROTECTION {
UCHAR lbp_capable; /* [OUTPUT] the capability of lbp for QUERY ioctl only */
UCHAR lbp_method; /* lbp method used for QUERY [OUTPUT] and SET [INPUT]
ioctls */
#define LBP_DISABLE 0x00
#define REED_SOLOMON_CRC 0x01
UCHAR lbp_info_length; /* lbp info length for QUERY [OUTPUT] and SET [INPUT]
ioctls */
UCHAR lbp_w; /* protection info included in write data */
/* a boolean for QUERY [OUTPUT] and SET [INPUT] ioctls */
UCHAR lbp_r; /* protection info included in read data */
/* a boolean for QUERY [OUTPUT] and SET [INPUT] ioctls */
UCHAR rbdp; /* protection info included in recover buffer data */
/* a boolean for QUERY [OUTPUT] and SET [INPUT] ioctls */
UCHAR reserved[26];
}LOGICAL_BLOCK_PROTECTION, *PLOGICAL_BLOCK_PROTECTION;
IOCTL_SET_PEW_SIZE
This command is used to set Programmable Early Warning size.
#define IOCTL_SET_PEW_SIZE
CTL_CODE(IOCTL_TAPE_BASE, 0x082C, METHOD_BUFFERED, FILE_READ_ACCESS )
IOCTL_QUERY_PEW_SIZE
This command is used to query Programmable Early Warning size.
#define IOCTL_QUERY_PEW_SIZE
CTL_CODE(IOCTL_TAPE_BASE, 0x082B, METHOD_BUFFERED, FILE_READ_ACCESS )
IOCTL_VERIFY_TAPE_DATA
This command is used to verify tape data. It uses the drive's error detection and
correction hardware to determine whether it can be recovered from the tape. It also
checks whether the protection information is present and validates correctly on
logical block on the medium. It returns a failure or a success.
#define IOCTL_VERIFY_TAPE_DATA
CTL_CODE(IOCTL_TAPE_BASE, 0x082A, METHOD_BUFFERED, FILE_READ_ACCESS )
| IOCTL_QUERY_RAO_INFO
| This command is used to query the maximum UDS number and UDS size before
| the Recommended Access Order list is generated and received (TS1140 or later).
| The structure for the IOCTL_QUERY_RAO_INFO command is
| #define UDS_WITHOUT_GEOMETRY 0
| #define UDS_WITH_GEOMETRY 1
|
| typedef struct _QUERY_RAO_INF{
| CHAR uds_type; /*[IN] 0: UDS_WITHOUT_GEOMETRY
| 1: UDS_WITH_GEOMETRY */
| CHAR reserved[7];
| USHORT max_uds_number; /* [OUT] Max UDS number supported from drive */
| USHORT max_uds_size; /* [OUT] Max single UDS size supported from drive
| in bytes */
| USHORT max_host_uds_number; /* [OUT] Max UDS number supported from driver */
| } QUERY_RAO_INFO, *PQUERY_RAO_INFO;
| IOCTL_GENERATE_RAO
| This command is used to generate a Recommended Access Order list (TS1140 or
| later). The UDS list is required as input. Use USD_DESCRIPTOR to build this list. The
| structure for the IOCTL_GENERATE_RAO command is
| #define UDS_WITHOUT_GEOMETRY 0
| #define UDS_WITH_GEOMETRY 1
|
| typedef struct _GENERATE_RAO{
| CHAR process; /* [IN] Requested process to generate RAO list */
| /* 0: no reorder UDS and no calculate locate time */
| /* (not currently supported by the drive) */
| /* 1: no reorder UDS but calculate locate time */
| IOCTL_RECEIVE_RAO
| This command is used to receive the generated Recommended Access Order list
| (TS1140 and later).
| IOCTL_CHANGER_OBTAIN_SENSE
Issue this command after an error occurs to obtain sense information that is
associated with the most recent error. To guarantee that the application can obtain
sense information that is associated with an error, the application must issue this
command before other commands are issued to the device. Subsequent operations
(other than IOCTL_CHANGER_OBTAIN_SENSE) reset the sense data field before the
operation is run.
IOCTL_MODE_SENSE
This command is used to get the Mode Sense Page/Subpage.
/**************************** GENERIC SCSI IOCTLS ****************************/
#define IOCTL_IBM_BASE ((’IBM’ << 8) | FILE_DEVICE_SCSI)
If variable block size is wanted, the block size must be set to zero. The
SetTapeParameters function must be called specifying the
SET_TAPE_MEDIA_INFORMATION operation. The function requires the use of a
TAPE_SET_MEDIA_PARAMETERS structure. The BlockSize member of the
structure must be set to the wanted block size. Any block size other than 0 sets the
media parameters to fixed block size. The size of the block is equal to the
BlockSize member.
In fixed block mode, the size of all data buffers used for reading and writing must
be a multiple of the block size. To determine the fixed block size, the
When reading or writing variable sized blocks, the operation cannot exceed the
maximum transfer length of the Host Bus Adapter. This length is the length of
each transfer page (typically 4 K) times the number of transfer pages (the
scatter-gather variable, typically 16-17). Thus the typical maximum transfer length
for variable sized transfers is 64 K. This number can be modified by changing the
scatter-gather variable in the system registry, but this action is not recommended
because it uses up scarce system resources.
Reading a tape that contains variable sized blocks can be accomplished even
without knowing what size the blocks are. If a buffer is large enough to read the
data in a block, then the data is read without any errors. If the buffer is larger than
a block, then only data in a single block is read and the tape is advanced to the
next block.
The size of the block is returned by the read operation in the *pBytesRead
parameter. If a data buffer is too small to contain all of the data in a block, then a
couple of things occur. First, the data buffer contains data from the tape, but the
read operation fails and GetLastError returns ERROR_MORE_DATA. This error
value indicates that there is more data in the block to be read. Second, the tape is
advanced to the next block. To reread the previous block, the tape must be
repositioned to the wanted block and a larger buffer must be specified. It is best to
specify as large a buffer as possible so that this issue does not occur.
If a tape contains fixed size blocks, but the tape media parameters are set to
variable block size, then no assumptions are made regarding the size of the blocks
on the tape. Each read operation behaves as described. The sizes of the blocks on
the tape are treated as variable, but happen to be the same size. If a tape has
variable size blocks, but the tape media parameters are set to fixed block size, then
the size of all blocks on the tape are expected to be the same fixed size. Reading a
block of a tape in this situation fails and GetLastError returns
ERROR_INVALID_BLOCK_LENGTH. The only exception is if the block size in
the media parameters is the same as the size of the variable block and the size of
the read buffer happens to be a multiple of the size of the variable block.
If ReadFile encounters a tapemark, the data up to the tapemark is read and the
function fails. (The GetLastError function returns an error code that indicates that
a tapemark was encountered.) The tape is positioned past the tapemark, and an
application can call ReadFile again to continue reading.
Event log
The Magstar or ibmtpxxx, ibmcgxxx, and Magchgr device drivers log certain data
to the Event Log when exceptions are encountered.
To interpret this event data, the user must be familiar with the following
components:
v Microsoft Event Viewer
Several bytes of "Event Detail" data are logged under Source = Magstar or
Magchgr (for Windows NT), or under Source = ibmtpxxx or ibmcgxxx (for
| Windows 2000; Windows Server 2003, Windows Server 2008, and Windows Server
| 2012).
The user must view the event data in Word format to properly decode the data.
Table 6 and Table 7 on page 336 indicate the hexadecimal offsets, names, and
definitions for Magstar or ibmtpxxx and ibmcgxxx event data. Magchgr event data
has a unique format that appears later in this chapter.
Table 6. Magstar ibmtpxxx, and ibmcgxxx event data
Offset Name Definition
0x00-0x01 DumpDataSize Indicates the size in bytes required for any
DumpData the driver places in the packet.
0x02 RetryCount Indicates how many times the driver tried
the operation and encountered this error.
0x03 MajorFunctionCode Indicates the IRP_MJ_XXX from the driver’s
I/O stack location in the current IRP (from
NTDDK.H).
0x0C-0x0F ErrorCode For the Magstar device driver, it is 0. For
the Magchgr device driver, it is always
0xC00400B
(IO_ERR_CONTROLLER_ERROR, from
NTIOLOGC.H).
0x10-0x13 UniqueErrorValue Reserved
0x14-0x17 FinalStatus Indicates the value that is set in the I/O
status block of the IRP when it was
completed or the STATUS_XXX returned by
a support routine the driver called (from
NTSTATUS.H).
0x1C-0x1F IoControlCode For the Magstar device driver, it indicates
the I/O control code from the driver’s I/O
stack location in the current IRP if the
MajorFunctionCode is
IRP_MJ_DEVICE_CONTROL. Otherwise,
this value is 0. For the Magchgr device
driver, it indicates the I/O control code
from the driver’s I/O stack location in the
current IRP.
0x28 Beginning of Dump The following items are variable in length.
Data See the DDK and SCSI documentation for
details.
For example, ibmcgxxx logs the following error when a move medium is
attempted and the destination element is full. Explanations of selected fields
follow.
0000: 006c000f 00c40001 00000000 c004000b
0010: bcde7f48 c0000284 00000000 00000000
0020: 00000000 00000000 00000000 000052f4
0030: 00000000 00000000 004000c4 02000003
0040: 600c00ff 00000028 00000000 00000258
0050: 00000000 814dac28 00000000 bcde7f48
0060: 81841000 00000000 a5600000 00200010
0070: 00000000 00000000 70000500 00000058
0080: 00000000 3b0dff02 00790000 0000093e
0090: 00000000
Table 8 on page 337 and Table 9 on page 338 contain definitions for event data that
is logged under Magchgr.
For example,
0000: 0018000f 006c0001 00000000 00000000
0010: 00000000 c0000185 00000000 00000000
0020: 00000000 00000000 00000300 0015c402
0030: 00000000 00000000 f50ac607 700b4b00
Parameters
You can set some of the parameters for the header definitions and structure as
follows:
fildes Specifies the file descriptor that is returned from an open system call.
request
Specifies the command that is completed on the device.
arg Specifies the individual operation.
See “3494 Enterprise tape library system calls” on page 350 for information.
The ld is the library file descriptor that is returned for the open_ibmatl command.
If it is successful, the close_ibmatl command returns 0. If it is not successful, this
command returns -1, and the errno variable is set to EBADF. (The library file
descriptor that is passed to the close_ibmatl is not valid.)
Parameters
Certain parameters are set for the library commands, as follows.
342 IBM Tape Device Drivers: Programming Reference
ld Specifies the library file descriptor that is returned from an open_ibmatl
call.
request
Specifies the command that is completed on the device.
arg Specifies the pointer to the data that is associated with the particular
command.
An application that uses the HP-UX 3494 Enterprise Tape Library Driver
commands and functions must also be linked with either the 32-bit
(/usr/lib/libibm.o) or the 64-bit (/usr/lib/libibm64.o) driver interface C object
module that is provided with the lmcpd package, depending on whether the
application is a 32-bit or a 64-bit application. Link a 32-bit application program
with the 3494 object module as follows,
cc -c -o myapp.o myapp.c
cc -o myapp myapp.o /usr/lib/libibm.o
The first cc command compiles the user application but suppresses the link
operation, producing the myapp.o object module. The second cc command links
the libibm.o library object module to the myapp.o object module to create the
executable myapp file.
The two 3494 driver interface C object modules that contain position independent
code (PIC) are also created with the +z or +Z compiler option. An application can
use either the 32 bit (usr/lib/libibmz.o) or the 64 bit (usr/lib/libibm64z.o) in the
lmcpd package. Which one is used to make a shared library with its own PIC
object files depend on whether the application is a 32-bit or a 64-bit application.
Create a 32-bit shared library with the 3494 PIC object module as follows.
ld -b -o lib3494.sl myappz1.o myappz2.o /usr/lib/libibmz.o
The ld command combines the libibmz.o library PIC object module with the
myappz1.o and myappz2.o PIC object modules to build the shared library named
lib3494.sl.
A 64-bit shared library is created by following the instructions for a 32-bit shared
library, except it uses /usr/lib/libibm64z.o instead of /usr/lib/libibmz.o.
The ld is the library file descriptor that is returned for the open_ibmatl command.
If it is successful, the close_ibmatl command returns 0. If it is not successful, this
command returns -1, and the errno variable is set to EBADF. (The library file
descriptor that is passed to the close_ibmatl is not valid.)
Parameters
You can set some parameters on the library commands.
ld Specifies the library file descriptor that is returned from an open_ibmatl
call.
request
Specifies the command that is completed on the device.
arg Specifies the pointer to the data associated with the particular command.
A 32- or 64-bit application that uses the library driver commands and functions
must be linked with the /usr/lib/libibm.o driver interface C object module
provided with the ibmatl package. Link a 32- or 64-bit application program with
the 3494 object module as follows,
cc -c -o myapp.o myapp.c
cc -o myapp myapp.o /usr/lib/libibm.o
Note: libibm.o is a 64-bit object file for Intel IA64 and 64-bit zSeries architectures,
but is a 32-bit object file for the other architectures.
The first cc command compiles the user application but suppresses the link
operation, producing the myapp.o object module. The second cc command links
the libibm.o library object module to the myapp.o object module to create the
executable myapp file.
If you are developing software applications for the IBM Enterprise tape library,
you must include the mtlibio.h header file in your source program by adding the
following line.
#include <sys/mtlibio.h>
In addition, you must include the libibm.o object file when you compile and link
your program. For example:
cc -o myprogram myprogram.c /usr/lib/libibm.o
The libibm.o object file provides the open_ibmatl, ioctl_ibmatl, and close_ibmatl
functions for interfacing with the IBM Enterprise tape library. The function
prototypes are defined mtlibio.h. These functions use the same system call
conventions as open, ioctl, and close. If the function fails, -1 is returned and the
global errno value is set to indicate the error. Otherwise, a nonnegative value is
returned.
int rc,fd;
struct mtdevinfo devices;
/* open a library defined in the ibmatl.conf file */
fd=open_ibmatl(libname);
/* query devices */
rc=ioctl_ibmatl(fd,MTIOCLDEVINFO,&devices);
if(rc<0) rc=errno;
/* close library */
close_ibmatl(fd);
return rc;
}
The ld is the library file descriptor that was returned for the open_ibmatl
command. If it is successful, the close_ibmatl command returns 0. If it is not
successful, this command returns -1, and the errno variable is set to EBADF. (The
library file descriptor that is passed to the close_ibmatl is not valid.)
An application that uses the library driver commands and functions must be
linked with either the 32-bit (/usr/lib/libibm.o) or the 64-bit (/usr/lib/libibm64.o)
driver interface C object module. It is provided with the ibmatl package. Which
one is used depends on whether the application is a 32-bit or a 64-bit application.
Link a 32-bit or a 64-bit application program with the 3494 object module as
follows:
cc -c -o myapp.o myapp.c
cc -o myapp myapp.o /usr/lib/libibm.o
For 64-bit IBM zSeries systems only, link the application program with the 3494
object module as follows:
cc -c -o myapp64.o myapp64.c
cc -o myapp64 myapp64.o /usr/lib/libibm64.o
The first cc command compiles the user application but suppresses the link
operation, producing the myapp.o object module. The second cc command links
the libibm.o library object module to the myapp.o object module to create the
executable myapp file.
The ld is the library file descriptor that was returned for the open_ibmatl
command. If it is successful, the close_ibmatl command returns zero. If it is not
successful, this command returns -1 and the errno variable is set to EBADF. (The
library file descriptor that is passed to the close_ibmatl is not valid.)
Parameters
You can specify some parameters for library commands, as follows.
ld Specifies the library file descriptor that is returned from an open_ibmatl
call.
request
Specifies the command that is completed on the device.
See “3494 Enterprise tape library system calls” on page 350 for commands
that can be issued to the library.
arg Specifies the pointer to the data that is associated with the particular
command.
To link the interface DLL at run time dynamically, locate the executable file of the
application in the same directory of the DLL file. To link the driver interface object
library statically, specify the driver interface object library during the final link of
the application. The following sample can be used as a starting point for an
application that wants to dynamically link to the subroutines in the DLL. The
subroutines must be called through the pointer, rather than their name. For
example:
fd = t_open_ibmatlP("3494b");
static int dynload_lib( );
t_open_ibmatlP = (t_open_ibmatlF)
GetProcAddress( t_mod_handle, T_OPEN_IBMATL );
if ( t_open_ibmatlP == NULL ) /* Handle error */
t_close_ibmatlP = (t_close_ibmatlF)
GetProcAddress( t_mod_handle, T_CLOSE_IBMATL );
if ( t_close_ibmatlP == NULL ) /* Handle error */
t_ioctl_ibmatlP = (t_ioctl_ibmatlF)
The set of library commands available with the base operating system is provided
for compatibility with existing applications. In addition, a set of expanded library
function commands gives applications access to more features of the tape drives.
The following library system calls are accepted by the library device driver only if
the special file that is opened by the calling program is a Library Manager Control
Point.
The remaining library system calls are designed for a user supplied device number
or a zero. If the user supplies a zero, the library support selects a device to
complete the operation that is requested.
If the wait_flg in the input argument indicates that the calling process waits until
the mount is completed, the calling process is put to sleep after the call that
initiates the mount command. The subsystem generates an operation completion
notification to indicate the completion status of the mount. The return information
argument is updated to include the completion status of the mount and the calling
process is awakened.
If the wait_flg in the input argument does not indicate that the calling process
waits until the mount is complete, the initial status is updated in the return
information argument and control is returned to the calling process. If the mount
command is initiated successfully, the completion code in the return information
argument indicates success. If it is not successfully initiated, the completion code
indicates the reason for the failure. After the mount completes, the driver
Passed to this library system call is a return information argument structure. After
the completion of the call and before control is returned to the calling process, the
return information structure is updated to indicate the completion status of the
mount request.
Description
arg Points to the mtlmarg structure.
On Request
The field usage is defined as follows:
resvd This field contains zero.
versn This field contains the version number (zero) of the block structure.
device This field contains the device number of the device on which the operation
is run. See “Library device number” on page 351 for all device fields.
wait_flg
This field indicates whether the process waits for the completion status of
the operation. A value of zero indicates that the process does not wait for
the completion status. A value other than zero indicates that the process
waits for the completion status of the operation.
target_cat
If this field is non_zero, then it specifies a category to which the VOLSER is
assigned.
source_cat
If the field VOLSER contains all blanks, this field specifies the category
from which a volume is mounted. Otherwise, this field is ignored.
volser This field contains the ASCII value of the specific volume serial number to
be mounted. The field is left-aligned and padded with blanks. If this field
is all blanks, the source_cat field is used to identify a volume to be
mounted. In this case, the next volume in the category that is specified is
mounted.
Return Value
When a process does not wait until the mount is complete, the completion code is
set to indicate that the request was accepted for processing. The request ID
indicates the message ID associated with the mount request. This request ID can be
used to query the status of the mount operation.
Description
arg Points to the mtldarg structure.
On Return
The field usage of struct mtldret is defined as follows:
cc This field contains the completion code for the operation. See Table 13 on
page 378 for possible values.
up_comp
This field is reserved for upward compatibility (which is zero).
req_id If the demount operation is completed asynchronously (that is, the
requester does not wait until completion of the command processing), this
field contains the message ID corresponding to the demount request that is
issued.
number_sense
This field contains the number of valid sense bytes.
sense_bytes
This field contains the sense bytes read from the device.
Return Value
See Table 13 on page 378 for possible return values.
When the demount command is run asynchronously, the completion code is set to
indicate the request was accepted for processing. The request ID indicates the
message ID associated with the demount request. This request ID can be used to
query the status of the demount operation.
Description
arg Points to the mtlqarg structure.
On Request
The field usage is defined as follows:
resvd This field contains zero.
versn This field contains the version number (zero) of the block structure.
device This field contains the device number of the device on which to run the
Query Device Data operation. It is ignored for all other query commands.
See “Library device number” on page 351 for all device fields.
cat_seqno
This field contains the category sequence number. This field is used only
for the Category Inventory Data subcommand. The inventory records are
provided from the specified source category after this category sequence
number. If X'0000' or the number is beyond the last volume in the category,
the inventory records start with the first VOLSER in the category. This
number is represented in hexadecimal.
subcmd
This field contains the subcommand that directs the device driver action.
The possible values are
MT_QVD
Query Volume Data. Request information about the presence and
use of the specific volume and its affinity to the subsystem in the
library. The volume subsystem affinity is a prioritized list of
subsystems closest to the physical storage location of the specified
VOLSER.
MT_QLD
Query Library Data. Request information about the current
operational status of the library.
MT_QSD
Query Statistical Data. Request information about the workload
and performance characteristics of the library.
MT_QID
Query Inventory Data. Request information about up to 100
inventory data records for the library. The end of the list is
indicated with a returned VOLSER name of “ ” all blanks. If the
list contains 100 records, the next set is obtained by setting the
VOLSER field in the input/output control (IOCTL) to the last
volume name in the list (number 100). If the VOLSER field in the
IOCTL is set to 0, the first set is returned.
MT_QCID
Query Category Inventory Data. Request information about up to
100 inventory data records for the VOLSERs assigned to the
category specified. The end of the list is indicated with a returned
category of 0. If the list contains 100 records, the next set is
obtained by setting the cat_seqno in the IOCTL to the last category
sequence number in the list (number 100). If the cat_seqno in the
IOCTL is set to 0, the first set is returned.
MT_QDD
Query Device Data. Request information about the device that is
specified in the device field.
On Return
The field usage of struct mtlqret is defined as follows:
Return Value
See Table 13 on page 378 for possible return values.
Description
arg Points to the mtlsvcarg structure.
On Request
The field usage is defined as follows.
resvd This field contains zero.
versn This field contains the version number (zero) of the block structure.
device This field is ignored.
wait_flg
This field indicates whether the process waits for the completion status of
the operation. A value of zero indicates that the process does not wait for
the completion status. A value other than zero indicates that the process
waits for the completion status of the operation. This field is ignored
unless the target category specifies the eject category.
target_cat
This field contains the target category to which the VOLSER is assigned.
source_cat
This field contains the category to which the volume is assigned. This field
must contain X'FF00' if the volume is in the insert category. If this field
contains X'0000', it is ignored.
volser This field contains the volume serial number to be assigned to a category.
The field is left-aligned and padded with blanks.
On Return
The field usage of struct mtlsvcret is defined as follows.
cc This field contains the completion code for the operation. See Table 13 on
page 378 for possible values.
up_comp
This field is reserved for upward compatibility (which is zero).
req_id If the operation is completed asynchronously (that is, the requester does
not wait until the command processing completes), then this field contains
the message ID corresponding to the operation issued. This field is defined
only when the target category specified is an eject category.
device This field is ignored.
number_sense
This field contains the number of valid sense bytes.
sense_bytes
This field contains the sense bytes read from the device.
Return Value
See Table 13 on page 378 for possible return values.
Description
arg Points to the mtlqmidarg structure.
On Request
The field usage is defined as follows.
resvd This field contains zero.
versn This field contains the version number (zero) of the block structure.
device This field is ignored.
req_id This field contains the ID of a request that was previously initiated.
On Return
The field usage of struct mtlqmidret is defined as follows.
cc This field contains the completion code. See Table 13 on page 378 for
possible values.
up_comp
This field is reserved for upward compatibility (which is zero).
device This field is ignored.
number_sense
This field contains the number of valid sense bytes.
sense_bytes
This field contains the sense bytes read from the device.
Return Value
See Table 13 on page 378 for possible return values.
Description
arg Points to the mtlaarg structure.
On Request
The field usage is defined as follows.
resvd This field contains zero.
versn This field contains the version number (zero) of the block structure.
device This field is ignored.
wait_flg
This field indicates whether the process waits for the completion status of
the operation. A value of zero indicates that the process does not wait for
the completion status. A value other than zero indicates that the process
waits for the completion status of the operation.
audit_type
This field contains the type of audit. The only possible value is
VOL_AUDIT.
volser This field contains the volume serial number to be audited. The field is
left-aligned and padded with blanks.
On Return
The field usage of struct mtlaret is defined as follows.
Return Value
See Table 13 on page 378 for possible return values.
Description
arg Points to the mtlcarg structure.
On Request
The field usage is defined as follows.
resvd This field contains zero.
versn This field contains the version number (zero) of the block structure.
device This field is ignored unless the cancel_type field specifies CDLA. This field
contains the device number. See “Library device number” on page 351 for
all device fields.
On Return
The field usage of struct mtlcret is defined as follows.
cc This field contains the completion code. See Table 13 on page 378 for
possible values.
up_comp
This field is reserved for upward compatibility (which is zero).
device This field is ignored.
number_sense
This field contains the number of valid sense bytes.
sense_bytes
This field contains the sense bytes read from the device.
Return Value
See Table 13 on page 378 for possible return values.
Description
arg Points to the mtlsdcarg structure.
On Request
The field usage is defined as follows.
resvd This field contains zero.
versn This field contains the version number (zero) of the block structure.
device This field contains the device number of the device on which the operation
is run. See “Library device number” on page 351 for all device fields.
fill_parm
This field contains the following fill parameters.
MT_ECO(0x40)
Category Order. When it is active, the Library Manager fills the
loader index stack by selecting volumes from the specified category
that is based on how they were assigned to the category.
On Return
The field usage of struct mtlsdcret is defined as follows.
cc This field contains the completion code. See Table 13 on page 378 for
possible values.
up_comp
This field is reserved for upward compatibility (which is zero).
number_sense
This field contains the number of valid sense bytes.
sense_bytes
This field contains the sense bytes read from the device.
Return Value
See Table 13 on page 378 for possible return values.
struct mtlrcret {
int cc; /* completion code */
int up_comp; /* reserved */
int number_sense; /* number of valid sense bytes */
cha sense_bytes[MT_SENSE_LENGTH]; /* sense bytes */
};
On Request
The field usage is defined as follows.
resvd This field contains zero.
versn This field contains the version number (zero) of the block structure.
device This field contains the device number of the device on which the operation
is run. See “Library device number” on page 351 for all device fields.
pad This field contains the pad to maintain alignment.
release_cat
This field contains the category to be released.
hostid This field specifies the host identifier that reserved the category that is
released. Only the same host identifier that reserved the category can
release it.
On Return
The field usage of struct mtlrcret is defined as follows.
cc This field contains the completion code. See Table 13 on page 378 for
possible values.
up_comp
This field is reserved for upward compatibility.
number_sense
This field contains the number of valid sense bytes.
sense_bytes
This field contains the sense bytes.
Description
arg Points to the mtlrscarg structure.
struct reserve_info
{
char atl_seqno[3]; /* library sequence number */
char ident_token[8]; /* token for which categories are reserved */
char count[2]; /* total number of categories in list */
uchar cat[256][2] /* reserved category records */
};
On Request
The field usage is defined as follows.
resvd This field contains zero.
versn This field contains zero.
device This field is ignored.
num_cat
The number of categories to reserve.
category
If the num_cat field = 1, the library attempts to reserve the specified
category.
hostid Eight character host identifier for which the category is reserved.
On Return
The field usage of struct mtlrscret is defined as follows.
cc This field contains the completion code. See Table 13 on page 378 for
possible values.
up_comp
This field is reserved for upward compatibility.
number_sense
This field contains the number of valid sense bytes.
Description
arg Points to the mtlscaarg structure.
struct mtlscaret {
int cc; /* completion code */
int up_comp; /* reserved */
int number_sense; /* number of valid sense bytes */
char sense_bytes[MT_SENSE_LENGTH]; /* sense bytes read */
};
On Request
The field usage is defined as follows.
resvd This field contains zero.
versn This field contains zero.
device This field is ignored.
attr This field describes the attribute. It contains the following value.
MT_SCM (0x01) Set Category Name
category
This field specifies the category.
attr_data
This field contains the 10 character category name.
On Return
The field usage of struct mtdevinfo is defined as follows.
device This field contains the device number. The end of the list is indicated with
a device number equal to -1.
name This field is the name of the device. It consists of 6 bytes for the device
type, 3 bytes for the model number, and 2 bytes for the decimal index
number in the device list array.
Return Value
See Table 13 on page 378 for possible return values.
Example:
The following code is used in the mtlib utility for the -D option:
struct mtdevinfo dinfo;
return(0);
}
On Return
The field usage of struct mtdevinfo is defined as follows.
dev_number
This field contains the device number. The end of the list is indicated with
a device number equal to -1.
type This field contains the device type.
model This field contains the model number of the device.
serial_num
This field contains the serial number of the device.
cuid and dev
These fields contain the library subsystem ID (cuid) and device (dev)
within the subsystem for this device in the library.
vts_library
This field indicates whether the device is in a VTS library, and if so, which
logical VTS library. A value of 0 indicates that the device is not in a VTS
library.
Return Value
See Table 13 on page 378 for possible return values.
Example:
The following code is used in the mtlib utility for the -DE option:
struct mtdevlist dlist;
return(0);
}
struct mtlibaddr {
char library_name[32]; /* Logical name of library */
char host_ident[8]; /* Host identification for library */
char primary_addr[16]; /* Primary address of library */
char primary_status; /* Primary status as defined above */
char alternate_addr[16]; /* Alternate address of library */
char alternate_status; /* Alternate status as defined above */
char reserved[32];
};
On Return
The field usage of struct mtlibaddr is defined as follows.
library_name
This field contains the logical name of the library that is defined in the
ibmatl.conf file.
Return Value
See Table 13 on page 378 for possible return values.
Example:
The following code is used in the mtlib utility for the -A option:
struct mtlibaddr addrlist;
if (addrlist.alternate_status == MT_LIBADDR_ONLINE)
{
printf(" alternate address......%s\n",addrlist.alternate_addr);
printf(" alternate status.......Online\n");
}
else if (addrlist.alternate_status == MT_LIBADDR_OFFLINE)
{
printf(" alternate address......%s\n",addrlist.alternate_addr);
printf(" alternate status.......Offline\n");
}
else
printf(" alternate address......Not configured\n");
return(0);
}
Description
arg Points to the mtlewarg structure.
On Request
The field usage is defined as follows.
resvd This field contains zero.
versn This field contains the version number (zero) of the block structure.
subcmd
This field contains the LEWTIME subcommand. It is returned only when an
error or exception condition is detected or after a timeout occurs
(whichever happens first).
timeout
This field contains the timeout time in seconds. If it is set to zero, no
timeout is completed.
On Return
The field usage of struct mtlewret is defined as follows.
up_comp
This field is reserved for upward compatibility (which is zero).
cc This field contains the completion code. See Table 13 on page 378 for
possible values.
lib_event
This field contains the detected event. The possible values are shown in
Table 11 on page 376.
msg_type
This field contains the type of message if it is reported. The possible values
are:
Return Value
If a library system call is successful, the return code is set to zero. If the library
system call is not successful, the return code is set to -1. If the library system call
is not successful, the errno variable is set to indicate the cause of the failure. The
values in Table 12 are returned in the errno variable.
Table 12. MTIOCLEW errors
Return Code errno cc Value Description
0 ESUCCESS 0 0 Completed successfully.
X'0'
-1 ENOMEM Undefined - Memory allocation failure.
-1 EFAULT Undefined - Memory copy function failure.
-1 EIO MTCC_NO_LMCP 32 The Library Manager Control
Point is not configured.
X'20'
-1 EINVAL MTCC_INVALID_SUBCMD 41 An invalid subcommand is
specified.
X'29'
-1 EIO MTCC_LIB_NOT_CONFIG 42 No library devices are
configured.
X'2A'
X'2B'
Table 13 shows the return codes, the errno variables, and the completion codes for
the library I/O control requests. See mtlibio.h for the code values.
Table 13. Error description for the library I/O control requests
Code errno Value cc Value Description
0 ESUCCESS 0 MTCC_COMPLETE 0 Completed successfully.
X'0'
-1 EIO 5 MTCC_COMPLETE_VISION 1 Completed. Vision system
not operational.
X'1'
-1 EIO 5 MTCC_COMPLETE_NOTREAD 2 Completed. VOLSER not
readable.
X'2'
-1 EIO 5 MTCC_COMPLETE_CAT 3 Completed. Category
assignment that is not
X'3' changed.
-1 EIO 5 MTCC_CANCEL_PROGREQ 4 Canceled program
requested.
X'4'
-1 EIO 5 MTCC_CANCEL_ORDERSEQ 5 Canceled order sequence.
X'5'
-1 EIO 5 MTCC_CANCEL_MANMODE 6 Canceled manual mode.
X'6'
-1 EIO 5 MTCC_FAILED_HARDWARE 7 Failed. Unexpected
hardware failure.
X'7'
-1 EIO 5 MTCC_FAILED_VISION 8 Failed. Vision system not
operational.
X'8'
-1 EIO 5 MTCC_FAILED_NOTREAD 9 Failed. VOLSER not
readable.
X'9'
-1 EIO 5 MTCC_FAILED_INACC 10 Failed. VOLSER
inaccessible.
X'A'
X'C'
-1 EIO 5 MTCC_FAILED_MANEJECT 13 Failed. Volume that is
ejected manually.
X'D'
-1 EIO 5 MTCC_FAILED_INVENTORY 14 Failed. Volume not in
inventory.
X'E'
-1 EIO 5 MTCC_FAILED_NOTAVAIL 15 Failed. Device not
available.
X'F'
-1 EIO 5 MTCC_FAILED_LOADFAIL 16 Failed. Irrecoverable load
failure.
X'10'
-1 EIO 5 MTCC_FAILED_DAMAGED 17 Failed. Cartridge damaged
and queued for eject.
X'11'
-1 EIO 5 MTCC_COMPLETE_DEMOUNT 18 Completed. Demount
signaled before execution.
X'12'
-1 EIO 5 MTCC_NO_LMCP 32 Failed. LMCP not
configured.
X'20'
-1 EINVAL 22 MTCC_NOT_CMDPORT_LMCP 33 Failed. Device not
command-port LMCP.
X'21'
-1 EIO 5 MTCC_NO_DEV 34 Failed. Device not
configured.
X'22'
-1 EIO 5 MTCC_NO_DEVLIB 35 Failed. Device not in
library.
X'23'
-1 ENOMEM 12 MTCC_NO_MEM 36 Failed. Memory failure.
X'24'
-1 EIO 5 MTCC_DEVINUSE 37 Failed. Device in use.
X'25'
-1 EIO 5 MTCC_IO_FAILED 38 Failed. Unexpected I/O
failure.
X'26'
-1 EIO 5 MTCC_DEV_INVALID 39 Failed. Invalid device.
X'27'
-1 EIO 5 MTCC_NOT_NTFPORT_LMCP 40 Failed. Device not
notification-port LMCP.
X'28'
X'2B'
-1 EIO 5 MTCC_INVALID_CANCELTYPE 44 Failed. Invalid cancel type.
X'2C'
-1 EIO 5 MTCC_NOT_LMCP 45 Failed. Not LMCP device.
X'2D'
-1 EIO 5 MTCC_LIB_OFFLINE 46 Failed. Library is offline to
host.
X'2E'
-1 EIO 5 MTCC_DRIVE_UNLOAD 47 Failed. Volume is still
loaded in drive.
X'2F'
-1 ETIMEDOUT 78 MTCC_COMMAND_TIMEOUT 48 Failed. Command that is
timed out by the device
X'30' driver.
-1 EIO 5 MTCC_UNDEFINED -1 Failed. Undefined
completion code.
X'FF'
Any references to an IBM program or other IBM product in this publication is not
intended to state or imply that only IBM’s program or other product may be used.
Any functionally equivalent program that does not infringe any of IBM’s
intellectual property rights may be used instead of the IBM product. Evaluation
and verification of operation in conjunction with other products, except those
expressly designed by IBM, is the user’s responsibility.
IBM may have patents or pending patent applications covering subject matter in
this document. The furnishing of this document does not give you any license to
these patents. You may send license inquiries, in writing, to:
The following paragraph does not apply to the United Kingdom or any other
country (or region) where such provisions are inconsistent with local law:
IBM may use or distribute any of the information you supply in any way it
believes appropriate without incurring any obligation to you.
Intel, Itanium, and Pentium are trademarks of Intel Corporation in the United
States, other countries (or regions), or both.
Java™ and all Java-based trademarks are trademarks of Oracle, Inc. in the United
States, other countries, or both.
Microsoft, Windows, Windows NT, and Windows 2000 are trademarks of Microsoft
Corporation in the United States, other countries (or regions), or both.
UNIX is a registered trademark of The Open Group in the United States and other
countries (or regions).
Other company, product, and service names may be trademarks or service marks
of others.
T
tape device driver 17
Tape drive compatibility IOCTL
operations 210
Tape drive IOCTL operations 176
Tape IOCTL operations 42
tape Media Changer driver entry
points 306, 307, 308, 309, 310, 311, 312
The extended open operation 12
V
variable block read/write
processing 333
Vendor-specific device IOCTLs for
DeviceIoControl 315
W
Windows 200x 305, 306, 307, 308, 309,
310, 311, 312, 313, 315, 333
event log 334
Windows NT 3494 Enterprise library
service 347, 348
Windows NT device driver
event log 334
Write error codes 220, 299
Write Tapemark 309
WriteFile 308
Writing to a special file 301
Writing to the special file 14
Printed in USA
GA32-0566-08
Spine information:
IBM Tape Device Drivers IBM Tape Device Drivers: Programming Reference