Examples: Using the Control Device (QTACTLDV) API
These programs show how to call the Control Device (QTACTLDV) API to issue a diagnostic command to a tape device and to display the firmware level of the tape device.
Note: By using the code examples, you agree to the terms
of the Code license and disclaimer information.
Example 1: Sending a diagnostic command to a tape device
/* Usage example 1 for QTACTLDV API */
/* */
/* */
#include <string.h>
#include <stdio.h>
#include <qtactldv.h>
#include <qusec.h>
/********************************************************************/
/* Typedef structure for QTACTLDV */
/********************************************************************/
typedef struct { /* QTACTLDV command data */
Qta_CTLD0100_t data; /* command data */
char cmd_str[6]; /* command string */
} cmd_struct;
/********************************************************************/
/* Typedef structure for Error code */
/********************************************************************/
typedef struct { /* Error code structure */
Qus_EC_t Edata; /* Error code data */
/* CPF67C8 excp data */
char dev_nam[10]; /* Device name */
char reason_cd[3]; /* Reason code */
char resv1[3]; /* Reserved */
} EC_struct;
/********************************************************************/
/* Constants */
/********************************************************************/
#define SNDRSNS "\x03\x00\x00\x00\x12\x00" /* Request sense */
/* command string */
#define SNDDIAG "\x1D\x04\x00\x00\x00\x00" /* Send diagnostic */
/* command string */
main(int argc,char *argv[])
{
/********************************************************************/
/* */
/* START OF MAINLINE */
/* */
/********************************************************************/
/********************************************************************/
/* Variables for QTACTLDV */
/********************************************************************/
char device[10]; /* device name */
char send_buff[256]; /* send buffer */
int send_buff_len; /* length of send buffer */
char recv_buff[256]; /* receive buffer */
int recv_buff_len; /* length of recv buffer */
int cmd_data_len; /* length of command data */
int i; /* counter variable */
EC_struct EC; /* error code structure */
cmd_struct Cmd; /* struct for QTACTLDV */
memcpy(device,argv[1],10); /* copy device name */
/********************************************************************/
/* OPEN connection */
/********************************************************************/
send_buff_len = 0; /* no send buffer */
recv_buff_len = 0; /* no receive buffer */
cmd_data_len = 0; /* no command data */
EC.Edata.Bytes_Provided = 32; /* No exceptions */
QTACTLDV(device, /* device name */
FUNOPEN, /* requested function */
send_buff, /* send buffer */
send_buff_len, /* length of send buffer */
recv_buff, /* receive buffer */
recv_buff_len, /* length of receive buffer */
CTLD0100, /* command format */
&Cmd, /* command data */
cmd_data_len, /* length of command data */
&EC); /* Error Code */
if (EC.Edata.Bytes_Available>0) /* If there was an error */
{
/* Handle the error */
}
/********************************************************************/
/* Send Diagnostic command */
/********************************************************************/
send_buff_len = 0; /* no send buffer */
recv_buff_len = 0; /* no recv buffer */
cmd_data_len = sizeof(Cmd); /* size of command struct */
EC.Edata.Bytes_Provided = 32; /* No exceptions */
Cmd.data.Data_transfer_direction = XFRNONE; /* No data transfer */
Cmd.data.Requested_transfer_length = 0; /* 0 transfer length */
Cmd.data.Ignore_length_errors = RPTLERR; /* report length errs */
Cmd.data.Command_timeout = 600; /* 10 minute timeout */
Cmd.data.Type_of_command = CMDSCSI; /* SCSI command */
Cmd.data.Offset_to_command_string = 32; /* offset 32 */
Cmd.data.Length_of_command_string = 6; /* 6 byte command */
Cmd.data.Reserved1=0; /* reserved */
memcpy(&Cmd.cmd_str, SNDDIAG, 6); /* command string */
QTACTLDV(device, /* device name */
FUNCMD, /* requested function */
send_buff, /* send buffer */
send_buff_len, /* length of send buffer */
recv_buff, /* receive buffer */
recv_buff_len, /* length of receive buffer */
CTLD0100, /* command format */
&Cmd, /* command data */
cmd_data_len, /* length of command data */
&EC); /* Error code */
if (EC.Edata.Bytes_Available>0) /* If there was an error */
{
/* See what message was returned */
if (strncmp(EC.Edata.Exception_Id,"CPF67C8",7)==0) /* Command
failed msg */
{
/****************************************************************/
/* Check the data returned with CPF67C8 */
/****************************************************************/
if (strncmp(EC.reason_cd,"\x02\xC0", 2) == 0) /* Device detected
error */
{
/* Check the SCSI completion status */
if (EC.reason_cd[2]=='\x02') /* Check condition status */
{
/************************************************************/
/* Send Request Sense command */
/************************************************************/
send_buff_len = 0; /* no send buffer */
recv_buff_len = 18; /* length of recv buffer */
cmd_data_len = sizeof(Cmd); /* size of command struct */
Cmd.data.Data_transfer_direction = XFRRECV; /* receive */
Cmd.data.Requested_transfer_length = 18; /* 18 bytes */
Cmd.data.Ignore_length_errors = IGNLERR; /* ignore length
errors */
Cmd.data.Command_timeout = 60; /* 60 sec timeout */
Cmd.data.Type_of_command = CMDSCSI; /* SCSI command */
Cmd.data.Offset_to_command_string = 32; /* offset 32 */
Cmd.data.Length_of_command_string = 6; /* 6 byte cmd */
Cmd.data.Reserved1=0; /* reserved */
memcpy(&Cmd.cmd_str, SNDRSNS, 6); /* command string */
EC.Edata.Bytes_Provided = 32; /* No exceptions */
QTACTLDV(device, /* device name */
FUNCMD, /* requested function */
send_buff, /* send buffer */
send_buff_len, /* length of send buffer */
recv_buff, /* receive buffer */
recv_buff_len, /* length of receive buffer */
CTLD0100, /* command format */
&Cmd, /* command data */
cmd_data_len, /* length of command data */
&EC); /* Error code */
if (EC.Edata.Bytes_Available>0) /* If there was an error */
{
/* Handle error on request sense command */
}
else
{
/* Parse the request sense data to determine what action */
/* to take. */
}
}
else if (EC.reason_cd[2]=='\x08') /* Busy status */
{
/* Try the command again later */
}
else /* Unexpected completion status */
{
/* Send error message for unexpected completion status */
}
}
else if (strncmp(EC.reason_cd,"\x02\xC1\x00", 3) == 0)
/* Selection timeout */
{
/* Send message that device might be powered off */
}
/* Add else if for the other reason codes here */
else
{
/* Send error message for unexpected reason code */
}
}
else
{
/* Handle other messages */
}
}
else
{
/* No error */
}
/********************************************************************/
/* CLOSE connection */
/********************************************************************/
send_buff_len = 0; /* no send buffer */
recv_buff_len = 0; /* no receive buffer */
cmd_data_len = 0; /* no command data */
EC.Edata.Bytes_Provided = 32; /* No exceptions */
QTACTLDV(device, /* device name */
FUNCLOS, /* requested function */
send_buff, /* send buffer */
send_buff_len, /* length of send buffer */
recv_buff, /* receive buffer */
recv_buff_len, /* length of receive buffer */
CTLD0100, /* command format */
&Cmd, /* command data */
cmd_data_len, /* length of command data */
&EC.Edata); /* Error code */
if (EC.Edata.Bytes_Available>0) /* If there was an error */
{
/* Handle the error */
}
}
Example 2: Displaying the firmware level of a tape device
/* Usage example 2 for QTACTLDV API */
/* */
/* */
#include <qtactldv.h> // Control Device API
#include <qusec.h> // Error code header
#include <string.h> // String Header File
#include <stdio.h> // Standard I/O Header
#include <stdlib.h> // Standard Library Header
#include <except.h> // Exception & cancel declares
/******************************************************************************/
/* Type definitions */
/******************************************************************************/
// Define the command structure for sending commands using the QTACTLDV API.
typedef struct { // Command Structure
Qta_CTLD0100_t hdr; // Header
char cmd_str[6]; // Command String
} ctldv_cmd_t;
/******************************************************************************/
/* Entry point to program. */
/******************************************************************************/
int main (int argc, char *argv[])
{
char device[10]; // Device name to get FM level
int deviceLen; // Length of device name to cop
char send_buff[1]; // Send buffer
int send_buff_len; // Length of send buffer
char recv_buff[50]; // Receive buffer
int recv_buff_len; // Length of receive buffer
ctldv_cmd_t ctldv_cmd; // Command variable
int ctldv_cmd_len; // Length of command string
char tempChar; // Used to conver ASCII to EBCD
Qus_EC_t EC; // Error code for qtactldv
char code[4]; // EBCDIC code level
int i; // Iterator to move ASCII to EB
EC.Bytes_Provided = 0; // Return errors to user
memset(device, ' ', sizeof(device)); // Set to blanks
deviceLen=strlen(argv[1]);
if (deviceLen>10)
deviceLen=10;
memcpy(device, argv[1], deviceLen); // Copy up to 10 chars
memset(code, ' ', sizeof(code)); // Clear code level
/***************************************************************************/
/* Open the pipe. */
/***************************************************************************/
send_buff_len = 0; // No send buffer
recv_buff_len = 0; // No receive buffer
ctldv_cmd_len = 0; // No command
#pragma exception_handler(PipeFailed, 0, 0, _C2_MH_ESCAPE, _CTLA_HANDLE)
QTACTLDV(device, // Device name
FUNOPEN, // Function requested
send_buff, // Send buffer
send_buff_len, // Send buffer length
recv_buff, // Receive buffer
recv_buff_len, // Receive buffer length
CTLD0100, // Command structure
&ctldv_cmd, // Command data
ctldv_cmd_len, // Command data length
&EC); // Error structure
#pragma disable_handler
/***************************************************************************/
/* Get the drive VPD */
/***************************************************************************/
recv_buff_len = 16; // Receive buffer for VPD
send_buff_len = 0; // No send buffer
ctldv_cmd_len = 32 + 6; // Reserve command size
ctldv_cmd.hdr.Command_timeout = 600; // 10 minute timeout
ctldv_cmd.hdr.Type_of_command = 0; // SCSI Command
ctldv_cmd.hdr.Offset_to_command_string = sizeof(ctldv_cmd.hdr); // Offset 32
ctldv_cmd.hdr.Length_of_command_string = 6; // 6 byte command
ctldv_cmd.hdr.Reserved1 = 0; // Reserved
ctldv_cmd.hdr.Data_transfer_direction=XFRRECV; // Receiving inquiry data
ctldv_cmd.hdr.Requested_transfer_length=16; // Number of bytes to transfer
ctldv_cmd.hdr.Ignore_length_errors = RPTLERR; // Report length errors
memset(ctldv_cmd.cmd_str, 0x00, 6); // clear command
ctldv_cmd.cmd_str[0] = 0x12; // set to Inquiry command
ctldv_cmd.cmd_str[1] = 0x01; // set EVPD mode
ctldv_cmd.cmd_str[2] = 0x03; // Set code page - VPD
ctldv_cmd.cmd_str[4] = 0x10; // Allocation length
#pragma exception_handler(PipeClose, 0, 0, _C2_MH_ESCAPE, _CTLA_HANDLE)
QTACTLDV(device, // Device name
FUNCMD, // Function requested
send_buff, // Send buffer
send_buff_len, // Send buffer length
recv_buff, // Receive buffer
recv_buff_len, // Receive buffer length
CTLD0100, // Command structure
&ctldv_cmd, // Command data
ctldv_cmd_len, // Command data length
&EC); // Error structure
#pragma disable_handler
/**************************************************************************/
/* Convert the level to EBCDIC */
/**************************************************************************/
for (i = 0; (i < sizeof(code)); i++)
{
tempChar = recv_buff[12+i]; // Code offest in VPD data
if (tempChar < 0x41) // is it a number?
tempChar = tempChar - 0x30 + 0xF0; // ASCII to EBCDII 0-9
else {
tempChar = tempChar & 0xDF; // Convert to ASCII uppercase
if (tempChar < 0x4A) // is char < J ?
tempChar = tempChar - 0x41 + 0xC1; // ASCII to EBCDII A-I
else if (tempChar < 0x53) // is char < S
tempChar = tempChar - 0x4A + 0xD1; // ASCII to EBCDII J-R
else
tempChar = tempChar - 0x53 + 0xE2; // ASCII to EBCDII S-Z
}
code[i] = tempChar; // Output the EBCDIC char
}
printf("The code level is: %s\n", code);
/**************************************************************************/
/* Close the pipe. */
/**************************************************************************/
PipeClose:
send_buff_len = 0; // No send buffer
recv_buff_len = 0; // No receive buffer
ctldv_cmd_len = 0; // No command
#pragma exception_handler(PipeFailed, 0, 0, _C2_MH_ESCAPE, _CTLA_HANDLE)
QTACTLDV(device, // Device name
FUNCLOS, // Function requested
send_buff, // Send buffer
send_buff_len, // Send buffer length
recv_buff, // Receive buffer
recv_buff_len, // Receive buffer length
CTLD0100, // Command structure
&ctldv_cmd, // Command data
ctldv_cmd_len, // Command data length
&EC); // Error structure
#pragma disable_handler
PipeFailed:
return 0; // return to user
}