USB Tape Client Device Driver

Purpose

Supports the Universal Serial Bus (USB) protocol for sequential access tape device driver.

Syntax

#include <sys/devinfo.h>
#include <sys/usb.h>
#include <sys/tape.h>
#include <sys/usbdi.h>

Device-dependent subroutines

Most of the tape operations are implemented by using the open, close, read, and write subroutines. However, the openx subroutine must be used if the device must be opened in the Diagnostic mode.

open and close subroutines

The openx subroutine is primarily used for the diagnostic commands and utilities. Appropriate authority is required for to run the subroutine. If you run the openx subroutine without the required authority, the subroutine returns a value of -1 and sets the errno global variable to a value of EPERM.

The openx subroutine enables the Diagnostic mode for the device driver and disables command-retry logic. This action allows the ioctl operations that perform special functions that are associated with diagnostic processing. The openx subroutine can also force-open and retain reservations.

The open subroutine applies a reservation policy that is based on the Object Data Manager (ODM) reserve_policy attribute. The USB tape devices might not support Small Computer System Interface (SCSI) reservation command and therefore, these commands might be ignored.

The ext parameter that is passed to the openx subroutine selects the operation to be used for the target device. The /usr/include/sys/scsi.h file defines the possible values for the ext parameter.

The ext parameter can contain any logical combination of the following flag values:

Item Description
SC_FORCED_OPEN Forces access to a device by removing any type of reservation on the device that can inhibit access. The type of action to remove the reservation depends upon the specific type of the established reservation. If this flag is specified, a mass storage reset command is issued for a USB tape, which is a mass storage bulk device.
SC_DIAGNOSTIC Places the selected device in the Diagnostic mode. This mode is singularly entrant. It means when a device is in the Diagnostic mode, SCSI operations are performed during the open or close operations, and error logging is disabled. In the Diagnostic mode, only the close and ioctl operations are accepted. All other device-supported subroutines return a value of -1 and set the errno global variable to a value of EACCES.

A device can be opened in the Diagnostic mode only if the target device is not currently opened. If you open a device in the Diagnostic mode and the target device is already open, the subroutine returns a value of -1 and sets the errno global variable to a value of EACCES.

ioctl subroutine

The following ioctl operations are supported on USB tape devices:

Operation Description
IOCINFO Populates the devinfo argument that is passed by the caller with the following values:
        devinfo.devtype           = DD_SCTAPE;
        devinfo.flags             = 0;
        devinfo.devsubtype        = 0x00;
        devinfo.un.scmt.type      = DT_STREAM;
        devinfo.un.scmt.blksize   = Block Size Set for the Tape Device;
STIOCTOP Specifies the address of a stop structure that is defined in the src/bos/usr/include/sys/tape.h file. The operation that is found in the st_op field in the stop structure is run st_count times, except for rewind, erase, and retention operations.

This ioctl command supports the following operations with the respective implementation details:

STREW
Issues the REWIND command to the tape device to rewind the tape.
STERASE
Issues the SCSI ERASE command to erase the contents of the tape media. Erase is not allowed with a read-only tape.
STRETEN or STINSRT
Issues the SCSI LOAD command with Load and Reten bits that are set in byte 4 of the command.
STWEOF
Writes the end-of-file mark to the tape. The Write End-of-Filemark operation is not allowed with a read-only tape.  
STDEOF
Disables the end-of-tape checking command.
STFSF
Issues the Forward Space File command. The st_count field specifies the number of file marks that the tape advances.
STFSR
Issues the Forward Space Record command. The st_count field is the number of records that the tape advances.
STRSF
Issues the Reverse Space File command. The st_count field is the number of file marks that the tape reverses.
STRSR
Issues the Reverse Space Record command. The st_count field is the number of records that the tape reverses.
STOFFL or STEJECT
Ejects the tape from the tape drive. This operation issues the SCSI LOAD command with Load bit in byte 4 of Command Descriptor Block (CDB) that is set to zero.
STIOCHGP
Defines the ioctl command to dynamically change the block size for this tape device. The block size is changed for the length of the open operation and is returned to the original values on the next open operation. The tape is forced to BOT (beginning-of-tape) when this operation is performed.

The parameter to this ioctl command specifies the address of a stchgp structure that is defined in the src/bos/usr/include/sys/tape.h file. The st_blksize field in the structure specifies the block size value to be set.

STIOCTOP (continued)
STIOCMD
When the device is successfully opened, the STIOCMD operation issues an SCSI command to the specified tape device.

The SCSI status byte and the adapter status bytes are returned through the arg parameter that contains the address of a scsi_iocmd structure. This structure is defined in the /usr/include/sys/scsi_buf.h file. The STIOCMD operation receives the SCSI command in the scsi_cdb section of the scsi_iocmd structure and issues it to the USB tape device. If the STIOCMD operation fails, the subroutine returns a value of -1 and sets the errno global variable to a nonzero value. In this case, the caller must evaluate the returned status bytes to determine the cause of operation failure and the recovery actions.

The version, command_length, and timeout_value values that are passed by the user is validated and error value EINVAL is returned if they are not valid.

If you transfer more than 1 MB of the maximum I/O transfer size, the subroutine returns a value of -1 and sets the errno global variable to a value of EINVAL.

On a check condition, the following error status values are set in the sc_passthru structure:

    status_validity  = SC_SCSI_ERROR
    scsi_bus_status = SC_CHECK_CONDITION
    adap_set_flags will have SC_AUTOSENSE_DATA_VALID flag set.

The following example is a pseudo code to issue the STIOCMD operation to the USB tape to issue an INQUIRY SCSI command:

    struct scsi_iocmd cmd;
    char inq_data[255];
    char sense_data[255];
..
    fd = open(“/dev/rmt0”, O_RDWR);
..
    memset(&cmd, '\0', sizeof(struct sc_passthru));
    cmd.version = SCSI_VERSION_1;
    cmd.timeout_value = 30;
    cmd.command_length = 6;
    cmd.autosense_length = 255;
    cmd.autosense_buffer_ptr = &sense_data[0];
    cmd.data_length = 0xFF;
    cmd.buffer = inq_data;

   cmd.flags = B_READ;

   cmd.scsi_cdb[0] = SCSI_INQUIRY;
    cmd.scsi_cdb[1] = (0x00 | vpd);  /* Standard Inquiry – vpd=1 
                 for Extended Inquiry */
    cmd.scsi_cdb[2] = page_code;    /* Page Code – valid if vpd=1 */
    cmd.scsi_cdb[3] = 0x00;
    cmd.scsi_cdb[4] = 0xFF;
    cmd.scsi_cdb[5] = 0x00;

   if ((rc=ioctl(fd, STIOCMD, &cmd)) != 0){
         if (cmd.adap_set_flags & SC_AUTOSENSE_DATA_VALID) { 
        /* look at sense data */
         } /* end SC_AUTOSENSE_DATA_VALID */

         printf("STPASSTHRU: Ioctl FAIL errno %d\n",errno);
         printf("status_validity: %x, scsi_status: %x, adapter_status:%x\n", 
      cmd.status_validity, cmd.scsi_bus_status, cmd.adapter_status);
         printf("Residual: %x\n", cmd.residual);
         exit(-1);
     } else {
         printf("STPASSTHRU : Ioctl PASS\n");
         printf("status_validity: %x, scsi_status: %x, adapter_status:%x\n", 
      cmd.status_validity, cmd.scsi_bus_status, cmd.adapter_status);     }
STPASSTHRU Takes the SCSI command in the scsi_cdb section of the sc_passthru structure and issues it to the USB tape driver. This operation is similar to the STIOCMD ioctl operation with the only exception of additional informative fields in the sc_passthru structure that provides more information on the error.

The following example is a pseudo code to issue the STPASSTHRU operation to the USB tape to issue an INQUIRY SCSI command:

    struct sc_passthru cmd;
    char inq_data[255];
    char sense_data[255];
..
    fd = open(“/dev/rmt0”, O_RDWR);
..
    memset(&cmd, '\0', sizeof(struct sc_passthru));
    cmd.version = SCSI_VERSION_1;
    cmd.timeout_value = 30;
    cmd.command_length = 6;
    cmd.autosense_length = 255;
    cmd.autosense_buffer_ptr = &sense_data[0];
    cmd.data_length = 0xFF;
    cmd.buffer = inq_data;

   cmd.flags = B_READ;

   cmd.scsi_cdb[0] = SCSI_INQUIRY;
    cmd.scsi_cdb[1] = (0x00 | vpd);  /* Standard Inquiry – vpd=1
                                 for Extended Inquiry */
    cmd.scsi_cdb[2] = page_code;      /* Page Code – valid if vpd=1 */
    cmd.scsi_cdb[3] = 0x00;
    cmd.scsi_cdb[4] = 0xFF;
    cmd.scsi_cdb[5] = 0x00;

   if ((rc=ioctl(fd, STPASSTHRU, &cmd)) != 0){
       if (cmd.adap_set_flags & SC_AUTOSENSE_DATA_VALID) {
             /* look at sense data */
         } /* end SC_AUTOSENSE_DATA_VALID */

         printf("STPASSTHRU: Ioctl FAIL errno %d\n",errno);
         printf("status_validity: %x, scsi_status: %x, adapter_status:%x\n", 
       cmd.status_validity, cmd.scsi_bus_status, cmd.adapter_status);
         printf("Residual: %x\n", cmd.residual);
         exit(-1);
     } else {
         printf("STPASSTHRU : Ioctl PASS\n");
         printf("status_validity: %x, scsi_status: %x, adapter_status:%x\n", 
       cmd.status_validity, cmd.scsi_bus_status, cmd.adapter_status);
     }