mrd_read_element_status - Obtain information about elements. Windows NT mrd.dll UNIX /usr/lib/libmrd.a OpenVMS MRD$RTL.EXE #include <mrd_common.h> #include <mrd_message.h> int mrd_read_element_status( robot_info_t *robot_info, int type, int start, int count, unsigned char *data, int length, dev_status_t *dev_status) ;
1 – Parameters
o robot_info - This is the address of a robot_info_t structure initialized using mrd_startup(3mrd) or mrd_show(3mrd). This data structure contains the element starting address and counts for each type of element, which are needed to map an absolute element to the correct zero relative address and type. o type - This is the element type code about which information is desired. The mrd_common.h include file defines the constants SLOT, PORT, DRIVE and TRANSPORT which may be used. o start - The absolute element address of the first element for which information is desired. o count - The number of elements for which the information is desired. o data - This is the address of an array of unsigned characters where the element status data will be written. Interpretation of the data is left to the caller. o length - This is the amount of element_status data, in bytes, available for the Read Element Status request. If the requested number of elements requires more space only data for as many elements as will fit will be copied. o dev_status - The dev_status is the address of a dev_status_ t structure, which is used to pass back detailed error information in the event of a command failure.
2 – Description
This routine performs a SCSI Read Element Status command, or equivalent if some other I/O architecture is supported. It is used by mrd_show(3mrd) and the routines doing volume tag checks. However, since it provides uninterpreted Read Element Status data, mrd_show(3mrd) will nearly always be easier to use. It requires that the medium changer be opened by mrd_ startup(3mrd) and uses absolute element addresses. On SCSI medium changers, it maps directly to the SCSI Read Element Status command. Since it uses a robot_info_t structure for an open robot, it is suitable in applications where it is desirable to hold the robot open and not incur the robot startup time on each command. The type argument specifies the type of element about which information is to be obtained. It should be one of SLOT, TRANSPORT, PORT or DRIVE as defined in mrd_common.h. The start argument is the absolute address of the first element and count the number of elements for which data is to be obtained. The data argument is an array of unsigned characters where the resulting data will be copied. The length is the amount of space available. If more data is required than there is space available, the device will only data for as many element as will fit into length bytes. Medium Changers which are SCSI-2 compliant support Read Element Status commands which request only eight bytes of data. In this case the returned data will indicate how many bytes of data are needed for the entire request. This feature allows an application to find how much space is needed for a specific request, allocate that much and then request all of it. This routine uses the dev_status_t structure for handing errors. The dev_status_t structure includes the code, os_status, and SCSI error fields. The following describes how to decode errors with the dev_status_t structure. SCSI Errors SCSI errors are indicated when the value of the valid field of the SCSI error is not equal to 0. The key, asc, and ascq fields provide additional information to help determine the cause of the error. The code usually maps the Additional Sense Code and Additional Sense Code Qualifier (ASC/ASCQ) values to an MRD error. The asc and ascq values are copied from the request sense data returned by the target. The Additional Sense Code (asc) indicates further information related to the error or exception condition reported in the sense key field. The Additional Sense Code Qualifier (ascq) indicates detailed information related to the additional sense code. For more information, consult the SCSI-2 Specification. Operating System Errors Operating system errors are indicated when the value of the valid field of the SCSI error is equal to 0 and the value of the os_ status field is not equal to 0. This result is most likely caused by an operating system error, and probably has a mapped error in MRD. MRD Errors MRD errors are indicated when the value of the os_status field is 0, and the value of the valid field of the SCSI error is 0. This result is most likely caused when MRD encounters its own failure.
3 – Absolute Addresses
The operating system interface routines use absolute SCSI element addresses, instead of zero relative address as used by the higher level functions. A zero based element address can be converted to an absolute address by adding the element base address from the robot_info_t structure. For example, the absolute slot address can be found by adding slot_start to the relative slot address:
4 – Example
/* * This is an example of using mrd_read_element_status(3mrd). * * Due to the complexity of the SCSI Read Element Status data * all this example will do is format the headers found in the * data. It won't try to format the element data. It also * calls mrd_read_element_status(3mrd) twice, once to determine * the needed data size for the remaining data and again to get * the actual data. * * Usage: * * mrd_read_element_status robot type start count * * If an unrecognized element type is used, the routine will use * a type of zero, which is allowed by the SCSI-2 specification. */ #ifndef lint static char SccsId[] = "@(#)mrd_read_element_status.c 1.3 (mrd-example) 3/5/97" ; #endif #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <mrd_common.h> #include <mrd_message.h> /* * The SCSI specification says that a request size of 8 * bytes will have the underlying device only return a * header indicating the number of bytes needed for the * command. */ #define SCSI_RES_MIN (8) /* * Given a string, resembling one of the element types, * return the SCSI type code for it. */ struct { int code ; char *string ; } etypes[] = { TRANSPORT, "transport", SLOT, "slot", DRIVE, "drive", PORT, "port", } ; convert_type(char *etype) { register i ; /* * For each entry in the array. */ for(i = 0; i < sizeof(etypes)/sizeof(etypes[0]); i++) /* * Do a case insensitive comparison, allowing * abbreviations. Return as soon as a match is * found. Return -1 if one isn't found. */ #ifdef vms if( strncmp(etypes[i].string, etype, strlen(etype)) == 0 ) #else if( strncasecmp(etypes[i].string, etype, strlen(etype)) == 0 ) #endif return etypes[i].code ; return 0 ; } /* * When an 8 byte Read Element Status command is handed * to a compliant medium changer, it is supposed to fill * enough of the header section to say how much data is * needed for the full command. We that here, if we get * a reasonable value, allocate sufficient space for the * real command and return the pointer to it. If there * is an error or command returns a zero byte report * return NULL. */ unsigned char * res_size(robot_info_t *robot_info, int type, int start, int count, size_t *bytes) { unsigned char data[SCSI_RES_MIN] ; /* minimum data */ int status ; /* command status */ dev_status_t dev_status ; /* In case of error */ unsigned char *report ; /* Data space */ /* * Read Element Status commands rarely fail, they just * succeed, but return no data. Clear all the fields * so we'll have an easier time seeing if any data was * returned. */ memset((void *)data, 0, SCSI_RES_MIN) ; status = mrd_read_element_status(robot_info, type, start, count, data, SCSI_RES_MIN, &dev_status) ; /* * But sometimes they do fail. */ if( status != MRD_STATUS_SUCCESS ) { printf("Size Read Element Status failed on %s: %s.\n", robot_info->robot_name, mrd_strstatus(status)) ; return NULL ; } /* * Calculate the report size. */ *bytes = (data[RES_REPORT_MSB] << 16) | (data[RES_REPORT_ISB] << 8) | data[RES_REPORT_LSB] ; /* * The report size doesn't include the 8 bytes needed for * the first headers. */ *bytes += RES_DATA_HEADER ; if( *bytes == 0 ) { printf("The report size is zero on %s.\n", robot_info->robot_name) ; return NULL ; } if((report = (unsigned char *)malloc(*bytes)) == NULL ) printf("Can't allocate %ld bytes for %s: %s.\n", *bytes, robot_info->robot_name, strerror(errno)) ; return report ; } /* * Print out the Read Element Status data headers. There * is an 8 byte data header, that describes the remaining * data, which is zero or more Status Pages, one for each * element type. * * Each Element Status Page consists of an 8 byte header * for the element type described by that page and then * element descriptors. */ print_res_data(robot_info_t *robot_info, unsigned char *dp) { int first ; /* First element reported */ int elements ; /* Number of elements reported */ int report ; /* Bytes in the total report */ int descriptor ; /* Each element descriptor size */ int bytes ; /* The per-element report size */ /* * The first two bytes of the overall header is the * first element reported. */ first = (dp[RES_FIRST_MSB] << 8) | dp[RES_FIRST_LSB] ; /* * The next two bytes are the number of elements in * the report. */ elements = (dp[RES_COUNT_MSB] << 8) | dp[RES_COUNT_LSB] ; /* * Three of the remaining bytes are the total report size. */ report = (dp[RES_REPORT_MSB] << 16) | (dp[RES_REPORT_ISB] << 8) | dp[RES_REPORT_LSB] ; printf("RES Data Header:\n") ; printf(" First Element Address: %d\n", first) ; printf(" Number of Elements: %d\n", elements) ; printf(" Byte Count of Report: %d\n", report) ; /* * As long as bytes of report remaining, print each * element type header. * * Here we play a curious pointer game. The RES_ * constants defined in mrd_common.h for the element * header assume a single element type with offsets * from the beginning of the data. But real Read * Element Status Data can have multiple element * types in it. For successive element type we'll * add the per-element report size to the address * of the base data. This should put the per-element * header at the right relative place. */ report -= RES_DATA_HEADER ; while( report > 0 ) { /* * Calculate the descriptor size. */ descriptor = (dp[RES_DESC_MSB] << 8) | dp[RES_DESC_LSB] ; /* * And the per element report. */ bytes = (dp[RES_BYTES_MSB] << 16) | (dp[RES_BYTES_ISB] << 8) | dp[RES_BYTES_LSB] ; printf(" Descriptor Header:\n") ; printf(" Element Type: %s\n", mrd_strelement(dp[RES_TYPE])) ; printf(" Primary Volume Tag: %x\n", dp[RES_TAGS] & ELEMENT_PVOLTAG) ; printf(" Alternate Volume Tag: %x\n", dp[RES_TAGS] & ELEMENT_AVOLTAG) ; printf(" Descriptor Length: %d\n", descriptor) ; printf(" Descriptor Report: %d", bytes) ; /* * Include the number of elements of this type. */ if( descriptor ) printf(" (%d)\n", bytes / descriptor) ; else putchar('\n') ; /* * Protection against the odd insane loader. */ if( bytes == 0 ) break ; /* * Go to the next header. Formatting the element * data is left as an exercise to the reader. */ dp += (bytes + RES_DATA_PAGE) ; /* * Lose some bytes... */ report -= (bytes + RES_DATA_PAGE) ; } } main(int argc, char *argv[]) { int status ; /* return status */ int type ; /* Element type */ int start ; /* First element */ int count ; /* Number of elements */ size_t bytes ; /* Bytes of data */ char *robot ; /* Robot to open */ unsigned char *data ; /* Element Status data */ robot_info_t robot_info ; /* Robot data */ dev_status_t dev_status ; /* Device status */ char log_info[MRD_MAX_LOG_STRING+1] ; /* * Check that there are enough arguments. */ if( argc < 5 ) { printf("usage: %s robot type start count\n", argv[0]) ; exit(1) ; } else { robot = argv[1] ; type = convert_type(argv[2]) ; start = atoi(argv[3]) ; count = atoi(argv[4]) ; } /* * Initialize the channel field of the robot_info, so * mrd_startup(3mrd) will actually open the robot. */ robot_info.channel = BAD_CHANNEL ; status = mrd_startup(robot, &robot_info, log_info) ; if( status != MRD_STATUS_SUCCESS ) { printf("Startup failed: %s: %s.\n", mrd_strstatus(status), log_info[0] ? log_info : "none") ; exit(1) ; } if( type == 0 ) printf("Data size needed for all elements %d - %d...", start, start + count) ; else printf("Data size needed for %s %d - %d...", mrd_strelement(type), start, start + count) ; fflush(stdout) ; switch( type ) { case SLOT: start += robot_info.slot_start ; break ; case PORT: start += robot_info.port_start ; break ; case TRANSPORT: start += robot_info.transport_start ; break ; case DRIVE: start += robot_info.device_start ; break ; } /* * Allocate sufficient space for the command. This * function prints its own error messages, so we can * just exit. */ data = res_size(&robot_info, type, start, count, &bytes) ; if( data == NULL ) exit(1) ; printf("%d bytes.\n", bytes) ; /* * Now do the full Read Element Status command. */ status = mrd_read_element_status(&robot_info, type, start, count, data, bytes, &dev_status) ; if( status != MRD_STATUS_SUCCESS ) { printf("Read Element Status failed on %s: %s.\n", robot, mrd_strstatus(status)) ; free(data) ; exit(1) ; } /* * We appear to have valid Read Element Status data. Print * out the results. */ print_res_data(&robot_info, data) ; (void)mrd_shutdown(&robot_info) ; return 0 ; }
5 – Return Values
Upon successful completion, mrd_read_element_status(3mrd) will return MRD_STATUS_SUCCESS. On a failure, one of the following status values will be returned. Experience has shown that Read Element Status rarely fails on the supported SCSI-2 medium changers. When the command is unable to obtain the requested data it simply arranges for the element and byte counts of the report to contain no data.
5.1 – MRD_STATUS_PARAM
This error is returned if the robot_info, data or dev_status arguments are are NULL pointers. The status structure is unchanged, even if a valid address is provided.
5.2 – MRD_STATUS_ROBOT_ILLEGAL_REQUEST
This error occurs when robot_info structure indicates that the medium changer supports volume tags, when it doesn't. When mrd_ startup(3mrd) opens the robot, it determines whether volume tags are support and sets up the structure appropriately. So, this error is only likely to occur when the structure has been changed. It is also used for a SCSI command failure, when the ASC is set to one of: o 0x1A - Parameter list length error o 0x20 - Invalid command operation code o 0x22 - Unsupported command o 0x24 - Illegal field in CDB o 0x25 - Logical unit not supported o 0x26 - Threshold parameters not supported o 0x28 - Import or Export element accessed o 0x2C - Command sequence error o 0x39 - Saving parameters not supported o 0x3D - Invalid bits in Identify message o 0x53 - Medium removal prevented This status is also returned when the ASC and ASCQ are zero, but the key is five (5).
5.3 – MRD_STATUS_IVCHAN
This error code is used when an OpenVMS system service fails with the status SS$_IVCHAN. It is likely when an operating system specific routine is used on a device that hasn't been opened by mrd_startup(3mrd).
6 – Related Functions
Functions: mrd_show(3mrd)