/sys$common/syshlp/HELPLIB.HLB  —  MRD Library, mrd_read_elem_stat
    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)
Close Help