/sys$common/syshlp/HELPLIB.HLB  —  MRD Library
    Media Robot Driver Library - A programming interface for
    controlling SCSI-2 medium-changers.

                           NOTE

    Function notation in this help file follows the UNIX convention.
    All functions are expressed with the (3mrd) extension.

1  –  Description

    The Media Robot Driver library is a callable interface for
    controlling SCSI-2 medium-changers. The interface consists of
    two include files and an object library which are installed in an
    operating system specific location. The operating system specific
    locations are shown in Library File Locations.

    Table 1-1 Library File Locations

    Windows NT         \Program Files\MRU\mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            SYS$LIBRARY:MRD$RTL.EXE

    The <mrd_common.h> include file defines data structures used to
    provide information about the medium-changer and its elements.
    The <mrd_common.h> file also defines a large number of symbolic
    constants for element type codes, offsets within SCSI structures,
    masks for SCSI bit fields, and other useful structures. The <mrd_
    common.h> file also includes prototype definitions of all the
    medium-changer functions provided in the interface.

    The <mrd_message.h> include file defines constants for each error
    code returned by the MRD interface. Function prototypes are also
    included for routines that will return a string corresponding to
    the error code.

    On Digital UNIX, these strings are retrieved from an I18N message
    catalog that is part of the installed software. Code and routines
    are also included for words and element exception messages that
    might be commonly used by a medium-changer application.

1.1  –  Element Addresses

    The first OpenVMS implementation of MRD supported the TF and TA
    family DLT media-changers. It used Mass Storage Control Protocol
    Display commands to indicate what cartridge should be moved.
    The MSCP uses cartridge address names instead of numbers as SCSI
    does. When SCSI support was added to the MRD, the convention
    of using strings for the address was kept and thus it has been
    since.

    In the common interface example programs, the character strings
    for the addresses are taken directly from the command line
    arguments and no special formatting is necessary. But, in
    practice, a program will probably keep SCSI addresses in
    numeric form and will have to convert those to strings. In the
    MRU command line interface and graphic user interface we use
    sprintf(3) for this:

     int element_number ;
     char element[MRD_NAME_SIZE+1] ;

     element_number = 5 ;

     sprintf(element, "%d", element_number) ;

2  –  MRD Routines

    The media robot driver library routines comprise two categories,
    the common routines and operating system specific routines.

2.1  –  Common Routines

    The following list identifies the common routines.

    o  mrd_eject(3mrd)

    o  mrd_find_cartridge(3mrd)

    o  mrd_home(3mrd)

    o  mrd_initialize(3mrd)

    o  mrd_inject(3mrd)

    o  mrd_load(3mrd)

    o  mrd_lock(3mrd)

    o  mrd_map_element(3mrd)

    o  mrd_move(3mrd)

    o  mrd_position(3mrd)

    o  mrd_ready_inport(3mrd)

    o  mrd_scsi_decode(3mrd)

    o  mrd_startup(3mrd)

    o  mrd_show(3mrd)

    o  mrd_shutdown(3mrd)

    o  mrd_strelement(3mrd)

    o  mrd_strexcept(3mrd)

    o  mrd_unload(3mrd)

    The common routines will open a robot to perform their
    operations. All these routines will close the robot when
    successfully completed, except for mrd_show(3mrd). The mrd_
    show(3mrd) routine closes the robot only when it encounters an
    error.

    The routine mrd_startup(3mrd) is used to open a medium-changer.
    It will fill in a robot_info_t data structure that contains the
    number of elements of each type, their addresses and the medium-
    changer SCSI Inquiry data. Thus, it is unnecessary (and often
    not desirable) to keep the robot open while it is being used.
    The routine mrd_shutdown(3mrd) can be used to close the robot.
    Aside from closing the file and setting the channel field to BAD_
    CHANNEL, it has no effect on the other data in the robot_info_t
    data structure.

    Use the mrd_show(3mrd) routine to obtain information about the
    contents and state of the slots, drive, ports and transports
    of the medium-changer. The mrd_show(3mrd) routine will open a
    robot, but it will also work if the robot is already open when
    the routine is called. For each element requested, an element_
    info_t data structure will be set if the element exists. The
    mrd_show(3mrd) function will accept the address of a robot_info_
    t data structure. If the robot has already been opened by mrd_
    startup(3mrd), this open robot will be used by the routine. If
    the robot isn't open (indicated by the channel field set to BAD_
    CHANNEL), the medium-changer indicated by the robot_name will
    be opened. If the routine completes successfully, the medium-
    changer will remain open. On an error, the medium-changer will be
    closed and the channel field reset to BAD_CHANNEL. By keeping the
    medium-changer open, multiple calls can be made to mrd_show(3mrd)
    without incurring the time to call mrd_startup(3mrd) each time.

    The routine mrd_move(3mrd) is a general interface to the SCSI
    Move Medium command. It allows the specification of source and
    destination elements for the move, whether the medium should be
    inverted and an optional volume tag. On medium-changers which
    have a vision system to read bar-codes, the volume tag can be
    used to verify that the medium in the source slot is the one
    desired.

    The routines mrd_load(3mrd), mrd_unload(3mrd), mrd_inject(3mrd)
    and mrd_eject(3mrd) are specialized interfaces to the SCSI Move
    Medium command. Load will move a medium from a slot to a drive.
    Unload will move a medium from a drive to a slot. Inject moves a
    medium from a port to a slot and Eject from a slot to a port. On
    the TL82x family of libraries, mrd_eject(3mrd) can also be used
    to clear a medium from the Pass-Through Mechanism.

    The routine mrd_lock(3mrd) enables sending a SCSI Prevent/Allow
    Media Removal command. Whether this command is supported, and its
    effect, depends on the robot.

    The routine mrd_initialize(3mrd) sends a SCSI Initialize Element
    Status command. The effect of this command varies among robots,
    but it typically causes complete reinventory of the medium-
    changer.

    The routine mrd_position(3mrd) sends a SCSI Position to Element
    command.

    The routine mrd_ready_inport(3mrd) sends a vendor unique, Ready
    Inport command. On the TL82n family of libraries, this command
    enables the button which opens the Inport/Outport Device inport
    door. Other libraries and loaders may silently ignore this
    command or treat it as an illegal command.

    On medium-changers which keep track of a medium's previous
    element location, the routine mrd_home(3mrd) returns a medium
    to that location.

    On medium-changers with vision systems to read bar-code labels,
    the routine mrd_find_cartridge(3mrd) will search for a specified
    volume tag. The routine will search the entire library, or just a
    subset of elements according to the arguments used.

    The routine mrd_map_element(3mrd) accepts an element's absolute
    address and returns the element type and zero relative address.

    The routine mrd_strstatus(3mrd) accepts an MRD error status code
    and returns the corresponding message text. The routine mrd_
    strelement(3mrd) accepts an MRD_ELEMENT code for various words
    which apply to SCSI-2 medium-changer elements and returns the
    corresponding string. The routine mrd_strexcept(3mrd) accepts the
    Additional Sense Code and Additional Sense Code Qualifier for an
    element with an exception and returns the corresponding message
    text.

2.2  –  OpenVMS Routines

    The following list identifies the operating system specific
    routines.

    o  mrd_initialize_element(3mrd)

    o  mrd_move_medium(3mrd)

    o  mrd_position_to_element(3mrd)

    o  mrd_prevent_allow(3mrd)

    o  mrd_read_element_status(3mrd)

    o  mrd_ready(3mrd)

    o  mrd_request_sense(3mrd)

    o  mrd_test_unit_ready(3mrd)

    The operating system interface routines can be called directly
    and share three common traits.

    Trait 1

    Instead of a medium changer name, they accept a robot_info_t
    data structure that has been opened by mrd_startup(3mrd). This
    allows them to be called without the repeated start-up time of
    mrd_startup(3mrd) and allows keeping the medium changer open by a
    single application.

    Trait 2

    Instead of zero-relative element addresses, these routines all
    use absolute element addresses. These address can be calculated
    by adding the zero-relative address of a specific element to the
    element start address from the robot_info_t structure.

    For example:

     /*
      * Given an robot_info_t initialized with mrd_startup(3mrd)
      * or mrd_show(3mrd), an element type and a relative element
      * address, convert it to an absolute address.
      */
     convert_relative(robot_info_t *robot_info, int type, int element)
     {
      switch( type )
      case SLOT:
       return element + robot_info->slot_start ;
      case TRANSPORT:
       return element + robot_info->transport_start ;
      case DRIVE:
       return element + robot_info->device_start ;
      case PORT:
       return element + robot_info->port_start ;
      default:
       return -1 ;
      }
     }

    The routine mrd_move_medium(3mrd) is used by mrd_move(3mrd),
    mrd_load(3mrd), mrd_unload(3mrd), mrd_eject(3mrd) and mrd_
    inject(3mrd). These routines accepts the absolute transport,
    source and destination element addresses for a Move Medium
    command, as well as a value to indicate whether the medium should
    be inverted when moved.

    The routine mrd_read_element_status(3mrd) is used by mrd_
    show(3mrd) and a variety of internal utility functions. It offers
    direct access to the SCSI Read Element Status command. However,
    the data returned is also uninterpreted Read Element Status data,
    so the application using it must interpret the data for itself.
    Since mrd_show(3mrd) allows keeping the medium changer open as
    well, it is usually easier to use, except for simple requests.

    The routine mrd_position_to_element(3mrd) is used by mrd_
    position(3mrd). It offers direct access to the SCSI Position
    to Element command, accepting absolute element addresses for
    the transport and destination elements. It can also invert the
    transport where this is supported.

    The routine mrd_initialize_element(3mrd) is used by mrd_
    initialize(3mrd). It offers direct access to the SCSI Initialize
    Element Status command.

    The routine mrd_ready(3mrd) is used by mrd_ready_inport(3mrd).
    It offers direct access to the SCSI Position to Element command,
    accepting the absolute addresse of the port to be readied.

    The routine mrd_prevent_allow(3mrd) is used by mrd_lock(3mrd).
    It offers direct access to the SCSI Prevent Allow Media Removal
    command, accepting a value to indicate which is desired.

    The mrd_test_unit_ready(3mrd) routine performs a SCSI Test Unit
    Ready command, or equivalent if some other I/O architecture is
    supported. It is used by the mrd_startup(3mrd) and the OpenVMS
    implementation of mrd_ready(3mrd).

    The mrd_request_sense(3mrd) routine performs a SCSI Request
    Sense command, or equivalent if some other I/O architecture is
    supported. It is used by all MRD API routines to determine the
    cause of a command failure.

    Trait 3

    Finally, these routines accept the address of a dev_status_t
    structure for holding error status, instead of a the log_info
    string used by the other routines. This allows custom formatting
    of 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  –  Return Values

    Upon successful completion, the Media Robot Driver library
    routines that access a medium-changer return the value MRD_
    STATUS_SUCCESS. On a failure, one of the following errors may
    be returned. The Media Robot Driver library will attempt to map
    SCSI failures to one of a small group of error codes, but not all
    errors have been anticipated.

    Many of the MRD routines accept a log_info argument that is a
    character array. When a SCSI error occurs, the the Sense Key,
    additional Sense Code and Additional Sense Code Qualifier are
    formatted into the space provided. If the error is an operating
    system specific error, then the text corresponding to the error
    will be copied into the space provided.

3.1  –  Common Values

    Common return values.

3.1.1  –  MRD_STATUS_PARAM

    This error is returned when a pointer argument passed to an MRD
    routine is NULL, unless the routine is documented as one allowing
    a NULL pointer.

3.1.2  –  MRD_STATUS_CART_INVALID

    For routines that accept a volume_tag argument to perform volume
    tag verification, this error indicates that the volume tag of the
    media doesn't match that passed to the function.

3.1.3  –  MRD_STATUS_CART_NOT_AVAIL

    This error can occur on the TL81n and TL82n family of DLT
    libraries when the source of a move is a drive and the cartridge
    in the drive is still on-line. These robots do not allow moving
    the cartridge until the drive is taken offline.

3.1.4  –  MRD_STATUS_CART_SIDE_INVALID

    For routines that use the cartridge_side argument, this error
    indicates that the value is neither one (1) nor two (2).

3.1.5  –  MRD_STATUS_PORT_INVALID

    This error is returned when the element address for a port is
    less than zero or greater than the number of ports.

3.1.6  –  MRD_STATUS_SLOT_INVALID

    This error is returned when the element address for a slot is
    less than zero or greater than the number of slots.

3.1.7  –  MRD_STATUS_TRANSPORT_INVALID

    This error is returned when the element address for a transport
    is less than zero or greater than the number of transports.

3.1.8  –  MRD_STATUS_INVALID_TYPE

    For routines that allow the specification of an element type
    argument, this error indicates that specified type was not one of
    SLOT, DRIVE, PORT or TRANSPORT.

3.1.9  –  MRD_STATUS_DESTINATION_FULL

    On routines that perform a SCSI Move Medium command, this error
    indicates that the destination element already has a cartridge in
    it.

3.1.10  –  MRD_STATUS_SOURCE_EMPTY

    On routines that perform a SCSI Move Medium command, this error
    indicates that the source element is empty.

3.1.11  –  MRD_STATUS_AUTOCLEAN

    This error occurs when a SCSI command fails with the ASC set
    to 0x30 and the ASCQ set to 0x3. On TL8nn libraries supporting
    Auto-clean, it indicates that a command was attempted while an
    auto-clean was in progress.

3.1.12  –  MRD_STATUS_CART_DAMAGED

    This error occurs when a SCSI command fails with the ASC set
    to 0x30, but the ASCQ is NOT a value of 0x3. The log_info will
    contain the ASCQ.

3.1.13  –  MRD_STATUS_CART_NOT_FOUND

    This error is returned by mrd_find_cartridge(3mrd) when it can't
    find the cartridge with the desired volume tag.

3.1.14  –  MRD_STATUS_ELEMENT_INVALID

    This error occurs when a SCSI command fails with the ASC set to
    0x21. The log_info will contain the ASCQ. This indicates that an
    invalid element address reached the medium-changer. For example,
    specifying the 13th slot when only 12 slots are present.

3.1.15  –  MRD_STATUS_INSFMEM

    The mrd_show(3mrd) and mrd_find_cartridge(3mrd) functions
    allocate virtual memory using malloc(3) to store temporary
    element data. If the attempt to allocate the memory fails, these
    routines will return this error.

3.1.16  –  MRD_STATUS_NO_ELEMENTS

    This error occurs in mrd_show(3mrd), mrd_find_cartridge(3mrd) and
    mrd_home(3mrd) when the medium-changer has no elements within the
    range and type specified by the arguments.

3.1.17  –  MRD_STATUS_NO_VISION

    This error occurs in mrd_find_cartridge(3mrd) when the medium-
    changer has no vision system with which to read bar-code labels.

3.1.18  –  MRD_STATUS_RES_INVALID

    This error occurs in mrd_home(3mrd) when the element data
    returned from mrd_show(3mrd) is not valid.

3.1.19  –  MRD_STATUS_ROBOT_ATTENTION

    This error occurs when a SCSI command fails with the ASC set to
    one of 0x29, 0x2A or 0x2F. The log_info contains the ASCQ. The
    SCSI translations for these error codes are:

    o  0x29 - Power-on, Reset or Bus device reset occurred

    o  0x2A - Mode Parameters Changed

    o  0x2F - Command cleared by another initiator

    This error also occurs when the ASC and ASCQ are zero, but the
    SCSI sense key is 6h.

3.1.20  –  MRD_STATUS_ROBOT_DOOR_OPENED

    This occurs when a SCSI command fails with the ASC set to 0x80
    and the ASCQ set to 0x0. On TL8nn libraries this typically
    indicates that the cabinet door was opened during a command
    operation.

3.1.21  –  MRD_STATUS_ROBOT_ILLEGAL_REQUEST

    This error occurs for a variety of reasons.

    It is used when a sanity check fails in the code that attempts
    to move a cartridge to the Pass-Through Mechanism, when the robot
    type isn't a TL82n.

    It is used in the mrd_lock(3mrd) code when the value is not one
    of ALLOW_REMOVAL or PREVENT_REMOVAL.

    It is used when the medium changer does not support the Prevent
    /Allow Medium Removal command or the lock value is not one or
    zero. The specific cause can be determined by examining the ASC
    /ASCQ values in the status data.

    It is used when a call to mrd_initialize_element(3mrd) is issued
    against a medium changer that does not support the Initialize
    Element Status command.

    It is used when the medium changer does not support the Position
    To Element command. The seven and five slot DLT loaders do not
    support the command, though the TL820 and TL810 family libraries
    do. Some models of TLZ6L and TLZ7L do not support the command and
    may take a long time to fail.

    It is used when the medium changer does not support the Ready
    Inport command. The TL820 family of DLT libraries support this
    command. The TL810 family of DLT libraries allows this command to
    succeed, but it doesn't perform any function.

    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).

3.1.22  –  MRD_STATUS_ROBOT_MECH_ERROR

    This error occurs as the result of a SCSI command failure, when
    the ASC is set to one of:

    o  0x15 - Positioning error.

    o  0x8B - Vendor unique; Pass-through mechanism errors on the
       TL82n

3.1.23  –  MRD_STATUS_SOURCE_INVALID

    This error occurs in mrd_home(3mrd) when the return address in
    the element data isn't valid.

3.1.24  –  MRD_STATUS_VENDOR_UNIQUE_ERROR

    This error occurs when the internal routine used to decode SCSI-
    2 errors encounters an error that it has not been written to
    antipicate.

    This error also returned when the ASC is zero and the ASCQ is not
    one of zero or six, and when ASC/ASCQ are both zero and the key
    is 9h.

3.1.25  –  MRD_STATUS_NO_SENSE

    This error is returned by mrd_scsi_decode(3mrd) when the asc,
    ascq and key values are all zero (0). It is also returned when
    the key value is less than zero or greater than 15.

3.1.26  –  MRD_STATUS_RECOVERED_ERROR

    This error occurs when a SCSI device returns only a sense key
    of 1h. This indicates that although a command successfully
    completed, the target device had performed some internal error
    recovery.

3.1.27  –  MRD_STATUS_MEDIUM_ERROR

    This error occurs when ASC and ASCQ are zero, but the sense key
    is 3h. This occurs when the target encounters a nonrecoverable
    error due to a flaw in the medium.

3.1.28  –  MRD_STATUS_ROBOT_HW_ERROR

    This error occurs when ASC and ASCQ are zero, but the sense key
    is 4h. This occurs when the target encounters a nonrecoverable
    hardware error.

3.1.29  –  MRD_STATUS_DATA_PROTECT

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is seven (7).

3.1.30  –  MRD_STATUS_BLANK_CHECK

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is eight (8).

3.1.31  –  MRD_STATUS_COPY_ABORTED

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero,

3.1.32  –  MRD_STATUS_SENSE_EQUAL

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is Ch (12).

3.1.33  –  MRD_STATUS_VOLUME_OVERFLOW

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is Dh (13).

3.1.34  –  MRD_STATUS_MISCOMPARE

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is Eh (14).

3.1.35  –  MRD_STATUS_SENSE_RESERVED

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is Fh (15).

3.1.36  –  MRD_STATUS_SCSI_CHECK

    The SCSI Check Condition error should never occur. It
    indicates that it is safe to use a Request Sense command
    and that you are likely to get a different error.

3.1.37  –  MRD_STATUS_SCSI_CONDMET

    The SCSI Condition Met status indicates a SCSI command completed
    with the status "Condition Met".

3.1.38  –  MRD_STATUS_SCSI_BUSY

    The SCSI Device is Busy status code indicates a SCSI command
    completed with the status "Busy".  Some TZ87x media changers are
    known to cause this condition.

3.1.39  –  MRD_STATUS_SCSI_INTER

    The SCSI Intermediate Command Completed status code indicates a
    SCSI command completed with the status "Intermediate".

3.1.40  –  MRD_STATUS_SCSI_INTER_CONDMET

    The SCSI Intermediate-Condition Met status code indicates a SCSI
    command completed.

3.1.41  –  MRD_STATUS_SCSI_RESCON

    The SCSI Reservation Conflict status code indicates a SCSI
    command completed with the status "Reservation Conflict".

3.1.42  –  MRD_STATUS_SCSI_TERM

    The SCSI Command Terminated status code indicates a SCSI command
    completed with the status "Terminated".

3.1.43  –  MRD_STATUS_SCSI_QUEUE

    The SCSI Queue Full status code indicates a SCSI command
    completed with the status "Queue Full".

3.1.44  –  MRD_STATUS_SCSI_RESERVED

    The SCSI Status Code Reserved return indicates a SCSI command
    completed with a status that wasn't listed in Chapter 7 of the
    SCSI-2 specification and is "Reserved".

3.1.45  –  MRD_STATUS_INIT_REQUIRED

    LUN not ready, Initializing command required.
    This is for the ASC/ASC code of 4/2.  It occurs
    when commands are sent to a TL810 family library that has
    auto-inventory on power-up turned off.

3.1.46  –  MRD_STATUS_DIAG_FAILED

    Diagnostic failure, component in ASCQ.This is the entire class of
    error codes with the ASC value set to 0x40.

3.1.47  –  MRD_STATUS_IDE

    Initiator detected error message received. This error code occurs
    when the ASC/ASCQ code is 0x48/0.

3.1.48  –  MRD_STATUS_OPERATOR

    Operator request. This error code occurs when the ASC code is
    0x5A and the ASCQ code is 0 or 1.

3.1.49  –  MRD_STATUS_LOG_ERROR

    This error code occurs when the ASC code is
    0x5B and the ASCQ code is 0, 1, 2 or 3.

3.1.50  –  MRD_STATUS_ELOG_OVERFLOW

    Error log overflow.  This error code occurs when the ASC code is
    0xA and the ASCQ code is 0.

3.1.51  –  MRD_STATUS_SYNC_XFER_ERROR

    Synchronous data transfer error.  This error code occurs when the
    ASC code is 0x1B and the ASCQ code is 0.

3.1.52  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

3.1.53  –  MRD_STATUS_DEVICE_INVALID

    This error code is used when an OpenVMS system service fails with
    the status SS$_NOSUCHDEV or SS$_IVDEVNAM. This will typically
    occur in mrd_startup(3mrd) when the caller tries to open a device
    which doesn't exist or uses an invalid device name.

    This error also occurs when the routine is called on behalf of
    a device controlled by the JU driver. The Media Robot Utility no
    longer uses the JU driver.

3.1.54  –  MRD_STATUS_ROBOT_NOT_READY

    Under OpenVMS and Digital UNIX, this error occurs as the result
    of a SCSI command failure, when the ASC is set to one of:

    o  0x80 - When the ASCQ is not zero (0).

    o  0x81 - Vendor unique; gripper errors on the TL82X and TL81X

    o  0x04 - Logical unit not ready

    o  0x3E - Logical unit has not been self configured

    o  0x40 - Diagnostic failure; ASCQ indicates component

    o  0x42 - Power-on self test failure

    o  0x44 - Internal target failure

    o  0x46 - Unsuccessful soft reset

    o  0x4C - Logical unit failed self-configuration

    This status is also returned when the ASC and ASCQ are zero, but
    the key is two (2).

3.1.55  –  MRD_STATUS_ROBOT_CMD_ABORTED

    This error code is used when an OpenVMS system service fails with
    the status SS$_ABORT.

3.1.56  –  MRD_STATUS_NOPRIV

    This error code is used when an OpenVMS system service fails
    with the status SS$_NOPRIV. This will typically occur in mrd_
    startup(3mrd) when the caller doesn't have sufficient privilege
    to assign a channel to the device.

3.1.57  –  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).

3.1.58  –  MRD_STATUS_MOUNTED

    This error code is used when an OpenVMS system service fails with
    the status SS$_NOSUCHDEV or SS$_IVDEVNAM. This will typically
    occur in mrd_startup(3mrd) when the caller tries to open a device
    which doesn't exist or uses an invalid device name.

3.1.59  –  MRD_STATUS_PAGE_CODE

    This error occurs in mrd_startup(3mrd) when a SCSI Mode Sense
    command fails to return the expected data. It uses the SCSI
    Element Address Assignment mode page to fill in the element count
    and base address fields of the robot_info_t structure. If the
    data returned by the medium changer does not have the expected
    page code, this error is returned. This error has been seen when
    medium changers are connected to HS family array controllers
    running V2.7 firmware.

3.1.60  –  MRD_STATUS_EBUSY

    This error code is used when an OpenVMS system service fails
    with the status SS$_DEVALLOC. This generally happens in mrd_
    startup(3mrd) when another process already has the device
    allocated.

3.1.61  –  MRD_STATUS_DEVOFFLINE

    This error code is used when an OpenVMS system service fails with
    the status SS$_DEVOFFLINE and SS$_MEDOFL.

4  –  mrd_eject

    mrd_eject - Move a cartridge from a slot to a port

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_eject(
        const char *robot_name,
        const char *volume_tag,
        const char *slot,
        const char *port,
        char       *log_info) ;

4.1  –  Parameters

    o  robot_name - The name of the robot device to be opened. On
       Digital UNIX, if the leading character of the name is not a
       slash (/), /dev/ will be prepended to the name.

    o  volume_tag - A NULL terminated character string that is the
       expected volume tag on the cartridge to be moved. On robots
       with vision support this string will be compared with the
       volume tag of the cartridge in the source slot and if it
       doesn't match the call will fail. This feature will not be
       used if the volume_tag is NULL or the empty string.

    o  slot - A NULL terminated character string that is the zero
       relative address of the slot which is to be used as the source
       of the move.

    o  port - A NULL terminated character string that is the zero
       relative address of the port which is to be used as the
       destination of the move.

    o  log_info - This is a character array that should be at least
       MRD_MAX_LOG_STRING in length. If this function fails as the
       result of a SCSI error, this will be filled with the formatted
       request sense data. If this function fails as the result
       of an operating system error, the operating system message
       particular to the error will be copied into the array.

4.2  –  Description

    The mrd_eject(3mrd) function is a specialized interface to the
    SCSI Move Medium command. For the robot specified by robot_name,
    the routine will attempt to move the cartridge in the specified
    slot to the specified port. Element addresses are zero based.

    The robot will be opened and the arguments to the function will
    be verified to make sure they are safe and appropriate. The slot
    and port address will be verified they are within the valid range
    of those elements on the robot.

    The cartridge_name argument can be used to perform cartridge
    volume tag verification before the move. If the cartridge volume
    tag at the slot doesn't match that specified by this argument,
    then mrd_eject(3mrd) will fail with the status MRD_STATUS_CART_
    INVALID. If cartridge_name argument is a NULL pointer, an empty
    string or used on a robot without vision support this argument is
    silently ignored and the volume tag check will not be made.

    If the slot string is an empty string and the library is a TL820
    family member, this routine will attempt to move a cartrige on
    the PTM to the port specified by the port argument. This is the
    equivalent of the Eject Port command of the CLI.

4.3  –  Example

    /*
     *   Example mrd_eject(3mrd).
     *
     *   This example is slightly different from the others since it
     *   also demonstrates the Eject Port feature of mrd_eject(3mrd).
     *   This feature can be used on the TL820 family to move a tape
     *   from the Pass-through mechanism (PTM) to the outport.
     *
     *   The command usage is:
     *
     *      mrd_eject robot [ slot port [ volume_tag ] ]
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_eject.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       int   status ;      /* Status from mrd_eject(3mrd) */
       char   *robot ;      /* Name of the robot to use */
       char   *volume_tag = NULL ;   /* Volume tag to check */
       char   *slot ;         /* Source slot */
       char   *port ;         /* Destination port */
       char   log_info[MRD_MAX_LOG_STRING+1] ;   /* Error text */

       /*
        *   Allow the command to only have the robot name specified.
        */
       if( argc < 2 ) {
          printf("usage: %s robot [ slot port [ volume_tag ] ]\n",
             argv[0]) ;

          exit(1) ;
       }
       else
          robot = argv[1] ;

       /*
        *   If the slot and port aren't specified assume that
        *   the target robot is a TL820 and fill in default
        *   values for an Eject Port.  Otherwise take the
        *   desired values directly from the command line.
        */
       if( argc >= 4 ) {
          slot = argv[2] ;
          port = argv[3] ;

          /*
           *   Collect the volume_tag name if the user wants it.
           */
          if( argc > 4 )
             volume_tag = argv[4] ;
       }
       /*
        *   We also observe that this case catches the command:
        *
        *      mrd_eject robot_name address
        *
        *   It can't hurt to let the user specify the outport,
        *   since an invalid one simply won't work.  In this case
        *   the 3rd argument is the port name instead of the slot
        *   name.
        *
        *   The user could get the same affect by using a quoted
        *   empty string for the slot argument on the command line:
        *
        *      robot /dev/mc54 "" 1
        */
       else {
          if( argc == 3 )
             port = argv[2] ;
          else
             port = "1" ;

          slot = "" ;
       }

       /*
        *   Do the operation.
        */
       status = mrd_eject(robot, volume_tag, slot, port, log_info) ;

       if( status == MRD_STATUS_SUCCESS )
          printf("Ejected the media in slot #%d to port #%d.\n",
             slot, port) ;
       else
          printf("Eject failed: %s: %s.\n", mrd_strstatus(status),
             log_info[0] ? log_info : "none") ;

       return 0 ;
    }

4.4  –  Return Values

    Upon successful completion, the mrd_eject(3mrd) function returns
    the value MRD_STATUS_SUCCESS. If the mrd_eject(3mrd) fails the
    returned status value may be set to one of the following values.
    Other values that correspond to specific SCSI errors may also be
    possible, but these are the most likely.

4.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_name, slot, port, or log_info
    are NULL pointers.

4.4.2  –  MRD_STATUS_PORT_INVALID

    This error is returned when the element address for a port is
    less than zero or greater than the number of ports.

4.4.3  –  MRD_STATUS_SLOT_INVALID

    This error is returned when the element address for a slot is
    less than zero or greater than the number of slots.

4.4.4  –  MRD_STATUS_CART_INVALID

    For routines that accept a volume_tag argument to perform volume
    tag verification, this error indicates that the volume tag of the
    media doesn't match that passed to the function.

4.4.5  –  MRD_STATUS_SOURCE_EMPTY

    On routines that perform a SCSI Move Medium command, this error
    indicates that the source element is empty.

4.4.6  –  MRD_STATUS_DESTINATION_FULL

    On routines that perform a SCSI Move Medium command, this error
    indicates that the destination element already has a cartridge in
    it.

4.4.7  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

4.5  –  Related Functions

    Functions:

    o  mrd_move(3mrd)

    o  mrd_load(3mrd)

    o  mrd_unload(3mrd)

    o  mrd_inject(3mrd)

5  –  mrd_find_cartridge

    mrd_find_cartridge - Search for a cartridge by volume tag.

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

        #include <mrd_common.h>
        #include <mrd_message.h>

        int mrd_find_cartridge(
        const char     *robot_name,
        const char     *volume_tag,
        const int       element_type,
        const char     *element_start,
        const int       element_count,
        element_info_t *result,
        char           *result_name,
        int            *result_type,
        char           *log_info);

5.1  –  Parameters

    o  robot_name - The name of the robot device to be opened. On
       Digital UNIX, if the leading character of the name is not a
       slash (/), /dev/ will be prepended to the name.

    o  volume_tag- A NULL terminated character string that is the
       volume tag to search for.

    o  element_type - The type of robot element on which the
       operation takes place. If an element type of zero (0) is used,
       all elements will be searched starting at element 0 of each
       type and searching all the elements of that type on the robot.
       The order of this search is Slot, Drive, Transport and finally
       Ports.

    o  element_start- A NULL terminated character string that is the
       zero relative address of the element where the search should
       be started. This argument is not used when the element_type is
       zero (0).

    o  element_count - A volume tag search in a large library
       can take a long time. Some applications (a graphic user
       interface for example) may want to break up a large search
       into smaller, quicker sub-searches. When a specific element_
       type is specified only a range specified by the element_name
       and element_count will be searched. This argument is ignored
       when the element_type is zero (0).

    o  result_param- If an element matching the volume_tag string is
       found, the element_info_t will copied into the space pointed
       to by result.

    o  result_name- The zero relative element address of the matching
       element will be copied into the space pointed to by result_
       name. This space should be a character array of size MRD_NAME_
       SIZE.

    o  result_type- The element type of the matching element will be
       copied into the space pointed to by result_type.

    o  log_info - This is a character array that should be at least
       MRD_MAX_LOG_STRING in length. If this function fails as the
       result of a SCSI error, this will be filled with the formatted
       request sense data. If this function fails as the result
       of an operating system error, the operating system message
       particular to the error will be copied into the array.

5.2  –  Description

    This routine allows searching for the element location of a piece
    of media using the volume tag as a search key. If the element_
    type value is zero (0), all elements will searched in the order
    Slot, Drive, Transport and Port. The element_name and element_
    count arguments will be ignored in this case.

    When a specific element type is specified, the search will be
    limited to that element type. The element_name will used as the
    starting location for a search and element_count as the number
    of elements from that address to search. Using these arguments
    a search of a large number of elements may be broken up into a
    number of smaller searches.

    When a matching element is found, the element_info_t data for
    that element will copied into the space pointed to by result.
    The zero relative element address and element type will also be
    copied into the space provided.

5.2.1  –  Element Info

    The element_info_t data structure is defined in the include file
    <mrd_common.h>. The fields of this data structure are described
    below:

    o  name - The name field holds the volume tag of the media if
       applicable.

    o  state - The state field can have one of the following values:

          ELEMENT_FULL,
          ELELMENT_EMPTY, or
          ELEMENT_EXCEPT.

    o  port_type - If the element_type parameter specifies PORT, the
       port_type field will have one of the following values:

          IN_OUT_PORT,
          INPORT,
          OUTPORT.

    o  status - The status field can have one of the following
       values:

          MRD_STATUS_SLOT_INVALID,
          MRD_STATUS_DEVICE_INVALID,
          MRD_STATUS_TRANSPORT_INVALID,
          MRD_STATUS_PORT_INVALID, or
          MRD_STATUS_SUCCESS.

    o  flags - Use the ELEMENT_VALID mask on the flags field to
       indicate whether or not the full Read Element Status data
       is valid. The ELEMENT_PVOLTAG and ELEMENT_AVOLTAG indicate
       whether the primary or alternate volume tags of the Read
       Element Status data are valid.

    o  element_addr - This is the address of the element, unadjusted
       for the starting address. The routine mrd_map_element(3mrd)
       can be used to convert an absolute element address to a
       relative address and type. This field will be set to -1 when
       the information is not valid.

    o  source_addr - On most SCSI-2 medium-changers, this is the
       address where a cartridge resided before being moved to its
       current location. The routine mrd_map_element(3mrd) can be
       used to convert an absolute element address to a relative
       address and type. This field will be set to -1 when the
       information is not valid. On some SCSI-2 medium-changers (the
       DLT family loaders) this will be the element address of the
       slot itself.

    o  data - This a copy of the SCSI-2 Read Element Status data
       when the ELEMENT_VALID bit is set in the flags field. A byte-
       order neutral declaration of this data structure is included
       in the <mrd_common.h> include file as the mrd_reades_t data
       structure.

5.3  –  Example

    /*
     *   Example of mrd_find_cartridge(3mrd).  The command usage is:
     *
     *      mrd_find robot_name volume_tag
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_find.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       element_info_t   element ;   /* Element data result */
       int   status ;      /* status from mrd_find_cartridge(3mrd) */
       char   *robot ;      /* Medium changer to search */
       char   *volume_tag ;      /* Volume tag for which to search */
       int   type ;         /* Element type result */
       char   *content ;      /* element content */
       char   *format ;      /* format to print element data */
       char   address[MRD_NAME_SIZE+1] ;   /* Element name result */
       char   log_info[MRD_MAX_LOG_STRING+1] ;   /* error text */
       char   exception[BUFSIZ+1] ;      /* exception buffer */

       /*
        *   There are two required arguments; robot name and volume tag.
        */
       if( argc < 3 ) {
          printf("usage: %s robot volume-tag\n", argv[0]) ;
          exit(1) ;
       }

       robot      = argv[1] ;
       volume_tag = argv[2] ;

       /*
        *   Search all of the elements at the same time.  With the
        *   type set to zero, the values of element_address ("")
        *   and element_count (0), don't matter.
        */
       status = mrd_find_cartridge(robot, volume_tag, 0, "", 0, &element,
             address, &type, log_info) ;

       if( status != MRD_STATUS_SUCCESS )
         printf("Can't find volume %s: %s: %s.\n", mrd_strstatus(status),
             log_info[0] ? log_info : "none") ;

       /*
        *   Need to print out the results of the find.  This is
        *   similar to that used by mrd_show, but is a bit more
        *   extensive to show more features.
        */
       format = "%s\t%s\t%s\n" ;   /* default format */

       if( element.name[0] )
          content = element.name ;
       else if( element.state & ELEMENT_FULL )
          content = "Full" ;
       else if( element.state & ELEMENT_EXCEPT ) {
          format  = "%s\t%s\t%s\t%s\n" ;
          content = "Exception" ;

          (void)mrd_strexcept(element.data.asc, element.data.ascq,
             exception, BUFSIZ) ;
       }
       else
          content = "Empty" ;

       if( element.state & ELEMENT_EXCEPT )
          printf(format, mrd_strelement(type), address, content,
             exception) ;
       else
          printf(format, mrd_strelement(type), address, content) ;

       return 0 ;
    }

5.4  –  Return Values

    Upon successful completion, the mrd_find_cartridge(3mrd)
    function returns the value MRD_STATUS_SUCCESS. If the mrd_find_
    cartridge(3mrd) fails the returned status value may be set to one
    of the following values. This routine may also return any of the
    errors descibed in the mrd_show(3mrd) manual page. Other values
    that correspond to specific SCSI errors may also be possible, but
    the ones below are most likely.

5.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_name, volume_tag, log_info,
    result, result_name, element_start or result_type arguments are
    NULL pointers.

5.4.2  –  MRD_STATUS_NO_VISION

    This error occurs in mrd_find_cartridge(3mrd) when the medium-
    changer has no vision system with which to read bar-code labels.

5.4.3  –  MRD_STATUS_SLOT_INVALID

    This error is returned when the element address for a slot is
    less than zero or greater than the number of slots.

5.4.4  –  MRD_STATUS_PORT_INVALID

    This error is returned when the element address for a port is
    less than zero or greater than the number of ports.

5.4.5  –  MRD_STATUS_TRANSPORT_INVALID

    This error is returned when the element address for a transport
    is less than zero or greater than the number of transports.

5.4.6  –  MRD_STATUS_INVALID_TYPE

    For routines that allow the specification of an element type
    argument, this error indicates that specified type was not one of
    SLOT, DRIVE, PORT or TRANSPORT.

5.4.7  –  MRD_STATUS_INSFMEM

    The mrd_show(3mrd) and mrd_find_cartridge(3mrd) functions
    allocate virtual memory using malloc(3) to store temporary
    element data. If the attempt to allocate the memory fails, these
    routines will return this error.

5.4.8  –  MRD_STATUS_CART_NOT_FOUND

    This error is returned by mrd_find_cartridge(3mrd) when it can't
    find the cartridge with the desired volume tag.

5.4.9  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

5.4.10  –  MRD_STATUS_DEVICE_INVALID

    This error code is used when an OpenVMS system service fails with
    the status SS$_NOSUCHDEV or SS$_IVDEVNAM. This will typically
    occur in mrd_startup(3mrd) when the caller tries to open a device
    which doesn't exist or uses an invalid device name.

    This error also occurs when the routine is called on behalf of
    a device controlled by the JU driver. The Media Robot Utility no
    longer uses the JU driver.

5.5  –  Restrictions

    The SCSI-2 specification includes two commands which allow a
    medium-changer to perform most of the work that this routine
    does by brute force. Unfortunately, a reliable implementation of
    these commands was unavailable at the time MRD V1.2 was written.
    A future version of the API may be able to make use of these
    routines to speed up a search.

    Unlike mrd_show(3mrd) this routine will open and close the robot
    at each iteration.

5.6  –  Related Functions

    Functions:

    o  mrd_show(3mrd)

    o  mrd_map_element(3mrd)

6  –  mrd_home

    mrd_home - Return a cartridge whence it came.

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_home(
        const char   *robot_name,
        const char   *volume_tag,
        const char   *source_name,
        const int     source_type,
        char         *destination_name,
        int          *destination_type,
        char         *log_info) ;

   Restriction

   Strict interpretation of the SCSI-2 specification by devices will
   require that the device only report the address of the last SLOT a
   medium was in.

6.1  –  Parameters

    o  robot_name - The name of the robot device to be opened. On
       Digital UNIX, if the leading character of the name is not a
       slash (/), /dev/ will be prepended to the name.

    o  volume_tag - A NULL terminated character string that is the
       expected volume tag on the cartridge to be moved. On robots
       with vision support this string will be compared with the
       volume tag of the cartridge in the source slot and if it
       doesn't match the call will fail. This feature will not be
       used if the volume_tag is NULL or the empty string.

    o  source_name - A NULL terminated character string that is the
       zero relative address of the element which is to be used as
       the source of the move.

    o  source_type - The source_type is an integer value to indicate
       the type of the source_name address. The <mrd_common.h>
       include file defines constants for different element types;
       SLOT, DRIVE, PORT and TRANSPORT.

    o  destination_name - The address of space where the name of the
       destination address will be written if the move is successful.
       An character array of MRD_NAME_SIZE bytes should be used. If
       the destination_name address is NULL, the address will not be
       returned.

    o  destination_type - The address of space where the type of
       the destination will be copied if the move is successful. If
       the destination_type address is NULL, the type will not be
       returned.

    o  log_info - This is a character array that should be at least
       MRD_MAX_LOG_STRING in length. If this function fails as the
       result of a SCSI error, this will be filled with the formatted
       request sense data. If this function fails as the result
       of an operating system error, the operating system message
       particular to the error will be copied into the array.

6.2  –  Description

    The SCSI-2 specification for medium-changer devices allows an
    element to remember the source element of the current piece
    of media. For example, if a mrd_load(3mrd) is performed from
    slot 17 to drive 2, the element information for drive 2 will
    remember that the media came from slot 17. Where this feature
    is implemented, it allows an application to query an element to
    learn the original source of the media in it and return it.

    The mrd_home(3mrd) function does this. Given a robot name and
    element address it will see if the source address is valid
    and when it is return that media to its original location.
    If the source address is invalid or the element unavailable
    an error will be returned. The routine will also check to see
    if the media was inverted when placed in the current element
    and restore it to its original orientation. When the move is
    complete, the resulting address and element type will be copied
    into destination_name and destination_type.

    If the volume_tag argument is used, the routine will verify that
    a cartridge with the volume tag is present in the element before
    performing the move.

6.3  –  Example

    /*
     *   Example to do slot to slot moves.  The command usage is:
     *
     *      mrd_home robot_name type address [ volume-tag ]
     *
     *   Type can be one of:
     *
     *      slot, port, drive or transport
     *
     *   The optional transport argument can be a transport address
     *   number, the word "default" or an empty string.
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_home.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    /*
     *   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 -1 ;
    }

    main(int argc, char *argv[])
    {
       int   status ;      /* Status from mrd_home(3mrd) */
       char   *robot ;      /* Robot to use */
       char   *element ;      /* Element address */
       char   *volume_tag = NULL ;   /* Optional volume tag */
       int   type ;         /* Element type */
       char   home[MRD_NAME_SIZE+1] ;   /* space for return address */
       int   home_type ;      /* return element type */
       char   log_info[MRD_MAX_LOG_STRING+1] ;   /* error string */

       /*
        *   Three required arguments; robot, element type and address.
        */
       if( argc < 4 ) {
          printf("usage: %s robot type address [ volume_tag ]\n",
             argv[0]) ;

          exit(1) ;
       }

       robot   = argv[1] ;
       type    = convert_type(argv[2]) ;
       element = argv[3] ;

       /*
        *   Optional volume tag.
        */
       if( argc > 4 )
          volume_tag = argv[4] ;

       /*
        *   Do the operation.
        */
       status = mrd_home(robot, volume_tag, element, type,
             home, &home_type, log_info) ;

       if( status != MRD_STATUS_SUCCESS )
          printf("Home failed: %s: %s.\n", mrd_strstatus(status),
             log_info[0] ? log_info : "none") ;
       else
          printf("The cartridge in %s %s was returned to %s %s.\n",
             mrd_strelement(type), element,
             mrd_strelement(home_type), home) ;

       return 0 ;
    }

6.4  –  Return Values

    Upon successful completion, the mrd_home(3mrd) function returns
    the value MRD_STATUS_SUCCESS. If the mrd_home(3mrd) fails the
    returned status value may be set to one of the following values.
    Other values that correspond to specific SCSI errors may also be
    possible, but these are the most likely.

6.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_info, source_name, or log_
    info arguments are NULL pointers.

6.4.2  –  MRD_STATUS_SLOT_INVALID

    This error is returned when the element address for a slot is
    less than zero or greater than the number of slots.

6.4.3  –  MRD_STATUS_PORT_INVALID

    This error is returned when the element address for a port is
    less than zero or greater than the number of ports.

6.4.4  –  MRD_STATUS_TRANSPORT_INVALID

    This error is returned when the element address for a transport
    is less than zero or greater than the number of transports.

6.4.5  –  MRD_STATUS_INVALID_TYPE

    For routines that allow the specification of an element type
    argument, this error indicates that specified type was not one of
    SLOT, DRIVE, PORT or TRANSPORT.

6.4.6  –  MRD_STATUS_RES_INVALID

    This error occurs in mrd_home(3mrd) when the element data
    returned from mrd_show(3mrd) is not valid.

6.4.7  –  MRD_STATUS_SOURCE_INVALID

    This error occurs in mrd_home(3mrd) when the return address in
    the element data isn't valid.

6.4.8  –  MRD_STATUS_CART_INVALID

    For routines that accept a volume_tag argument to perform volume
    tag verification, this error indicates that the volume tag of the
    media doesn't match that passed to the function.

6.4.9  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

6.4.10  –  MRD_STATUS_DEVICE_INVALID

    This error code is used when an OpenVMS system service fails with
    the status SS$_NOSUCHDEV or SS$_IVDEVNAM. This will typically
    occur in mrd_startup(3mrd) when the caller tries to open a device
    which doesn't exist or uses an invalid device name.

    This error also occurs when the routine is called on behalf of
    a device controlled by the JU driver. The Media Robot Utility no
    longer uses the JU driver.

6.5  –  Related Functions

    Functions:

    o  mrd_show(3mrd)

    o  mrd_find_cartridge(3mrd)

    o  mrd_map_element(3mrd)

7  –  mrd_initialize

    mrd_initialize - Send a SCSI Initialize Element Status command.

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_initialize(
        const char   *robot_name,
        char         *log_info) ;

7.1  –  Parameters

    o  robot_name - The name of the robot device to be opened. On
       Digital UNIX, if the leading character of the name is not a
       slash (/), /dev/ will be prepended to the name.

    o  log_info - This is a character array that should be at least
       MRD_MAX_LOG_STRING in length. If this function fails as the
       result of a SCSI error, this will be filled with the formatted
       request sense data. If this function fails as the result
       of an operating system error, the operating system message
       particular to the error will be copied into the array.

7.2  –  Description

    The function sends a SCSI Initialize Element Status command to
    the specified robot. This command is not supported by the TA and
    TF loaders. On robots where this command is supported, it forces
    a physical reinventory of the library or loader. On some library
    systems this may take a long time.

    Most library subsystems will perform an inventory when they are
    powered on or have detected that the configuration may have
    changed (doors opened, panels removed, etc). For this reason,
    this routine is rarely needed.

7.3  –  Example

    /*
     *   Example of mrd_initialize(3mrd).  The command usage is:
     *
     *      mrd_init robot_name
     *
     *   It has been observed on an empty TL820 with all the
     *   bin-packs in place that this command takes just under
     *   23 minutes.
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_init.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>

    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       int   status ;      /* Status from mrd_inject(3mrd) */
       char   *robot ;      /* The name of the robot */
       char   log_info[MRD_MAX_LOG_STRING+1] ;  /* error string */

       /*
        *   Accept one required argument; robot name
        */
       if( argc < 2 ) {
          printf("usage: %s robot\n", argv[0]) ;
          exit(1) ;
       }

       /*
        *   Just use this directly from the command line.
        */
       robot = argv[1] ;

       /*
        *   Because this routine can take a long time we'll
        *   provide some positive feed-back that is doing
        *   something.
        */
       printf("Reinventory library %s...", robot); fflush(stdout) ;

       /*
        *   Call the function.  Because this routine can take a
        */
       status = mrd_initialize(robot, log_info) ;

       /*
        *   Done.
        */
       putchar('\n') ;

       /*
        *   Print an error message if there is a failure.  The
        *   routine mrd_strstatus(3mrd) will accept an MRD
        *   error status and return the corresponding string.
        *   If the log_info data has something other than a
        *   NULL as the first character print it as well.  It
        *   typically be the SCSI sense data or a operating
        *   system specific message for the error.
        */
       if( status != MRD_STATUS_SUCCESS )
          printf("Initialize failed: %s: %s.\n", mrd_strstatus(status),
             log_info[0] ? log_info : "none") ;

       return 0 ;
    }

7.4  –  Return Values

    Upon successful completion, the mrd_initialize(3mrd) function
    returns the value MRD_STATUS_SUCCESS. If the mrd_initialize(3mrd)
    fails the returned status value may be set to one of the
    following values. Other values that correspond to specific SCSI
    errors may also be possible, but these are the most likely.

7.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_name or log_info arguments
    are NULL pointers.

7.4.2  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

7.5  –  Related Functions

    o  mrd(3mrd)

    o  mrd_initialize_element(3mrd)

8  –  mrd_init_element

    mrd_initialize_element - Force a robot inventory operation

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_initialize_element(
        robot_info_t *robot_info,
        dev_status_t *dev_status) ;

8.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  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.

8.2  –  Description

    This routine performs a SCSI Initialize Element Status command.
    It is used by mrd_initialize(3mrd). On supported medium changers
    this typically causes the medium changer to perform a physical
    inventory of its contents. This routine can take a long time to
    complete. The longest time ever observed on a supported medium
    changer was approximately 23 minutes on an empty TL820 with all
    bin-packs in place. The DLT and RDAT changers may take only a few
    seconds.

    The robot_info argument is the address of a robot_info_t that has
    been opened by mrd_startup(3mrd).

    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.

8.3  –  Example

    /*
     *   Example of mrd_initialize_element(3mrd).  The command usage is:
     *
     *   Usage:
     *
     *      mrd_initialize_element robot [ robot... ]
     *      robot_name
     *
     *   It has been observed on an empty TL820 with all the bin-packs
     *   in place that this command takes just under 23 minutes.
     */
    #ifndef   lint
    static char SccsId[] = "@(#)mrd_initialize_element.c 1.3) 6/20/97";
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       int      rc ;
       int      status ;   /* return status */
       char      *robot ;   /* Robot to open */
       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 < 4 ) {
          printf("usage: %s robot [ robot... ]\n", argv[0]) ;
          exit(1) ;
       }

       /*
        *   Initialize the channel field of the robot_info, so
        *   mrd_startup(3mrd) will actually open the robot.
        */
       robot_info.channel = BAD_CHANNEL ;

       for(rc = 1; rc < argc; rc++) {
          /*
           *   Save the current robot name.
           */
          robot = argv[rc] ;

          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") ;

             continue ;
          }

          printf("Initialize Element Status on %s...", robot) ;
          fflush(stdout) ;

          status = mrd_initialize_element(&robot_info, &dev_status) ;

          if( status != MRD_STATUS_SUCCESS )
             printf("Failed: %s.\n", mrd_strstatus(status)) ;
          else
             printf("Success.\n") ;

          (void)mrd_shutdown(&robot_info) ;
       }

       return 0 ;
    }

8.4  –  Return Values

    Upon successful completion mrd_initialize_element(3mrd) will
    return MRD_STATUS_SUCCESS. On a failure, an MRD_STATUS value
    corresponding to the error will be returned. Common errors are:

8.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_info or dev_status arguments
    are NULL pointers. The dev_status structure is unchanged, even if
    a valid address is provided.

8.4.2  –  MRD_STATUS_ROBOT_ILLEGAL_REQUEST

    This error occurs when the medium changer does not support the
    Initialize Element Status command.

    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).

8.4.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).

8.5  –  Related Functions

    Functions:

    mrd_initialize(3mrd)

9  –  mrd_inject

    mrd_inject - Move a cartridge from an inport to a slot

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    include <mrd_common.h>
    include <mrd_message.h>

    int mrd_inject(
        const char *robot_name,
        const char *volume_tag,
        const char *port,
        const char *slot,
        char       *log_info) ;

9.1  –  Parameters

    o  robot_name - The name of the robot device to be opened. On
       Digital UNIX, if the leading character of the name is not a
       slash (/), /dev/ will be prepended to the name.

    o  volume_tag - A NULL terminated character string that is the
       expected volume tag on the cartridge to be moved. On robots
       with vision support this string will be compared with the
       volume tag of the cartridge in the source slot and if it
       doesn't match the call will fail. This feature will not be
       used if the volume_tag is NULL or the empty string.

    o  port - A NULL terminated character string that is the zero
       relative address of the port which is to be used as the
       destination of the move.

    o  slot - A NULL terminated character string that is the zero
       relative address of the slot which is to be used as the source
       of the move.

    o  log_info - This is a character array that should be at least
       MRD_MAX_LOG_STRING in length. If this function fails as the
       result of a SCSI error, this will be filled with the formatted
       request sense data. If this function fails as the result
       of an operating system error, the operating system message
       particular to the error will be copied into the array.

9.2  –  Description

    The mrd_inject(3mrd) function is a specialized interface to the
    SCSI Move Medium command. For the robot specified by robot_name,
    the routine will attempt to move the cartridge in the specified
    port to the specified slot. Element addresses are zero based.

    The robot will be opened and the arguments to the function will
    be verified to make sure they are safe and appropriate. The port
    and slot address will be verified they are within the valid of
    those elements on the robot.

    The volume_tag argument can be used to perform cartridge volume
    tag verification before the move. If the cartridge volume tag at
    the port doesn't match that specified by this argument, then mrd_
    inject(3mrd) will fail with the status MRD_STATUS_CART_INVALID.
    If volume_tag argument is a NULL pointer, an empty string or
    used on a robot without vision support this argument is silently
    ignored and the volume tag check will not be made.

    The TL820 family requires special handling within the mrd_
    inject(3mrd) routine, because of the way the Input/Output Device
    (IOD) works. This routine will explicitly check the specified
    inport to see if it is full. If empty and the robot is a TL820,
    the Pass-through mechanism will then be checked. If the PTM is
    full the source address will be reset to the PTM. If both are
    empty, the routine will send a Ready Inport command to enable the
    IOD. A one minute polling loop will be performed waiting for the
    inport to become full, five seconds between polls. If this first
    loop fails, the Ready Inport will be sent again and the loop
    repeated. This allows the user two minutes to put a tape into the
    inport.

    If volume tag verification is desired on the TL820, the cartridge
    will be moved to the PTM so the volume tag can be read. If the
    check fails, the cartridge will left on the PTM. If the mrd_
    inject(3mrd) is repeated with the correct volume tag or without
    one, the cartridge will be found on the PTM and the Move Medium
    command will proceed from there.

9.3  –  Example

    /*
     *   Example of mrd_inject(3mrd).  The command usage is:
     *
     *      mrd_inject robot_name port slot [ volume_tag ]
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_inject.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       int   status ;      /* Status from mrd_inject(3mrd) */
       char   *robot ;      /* The name of the robot */
       char   *volume_tag = NULL ; /* Optional volume tag to check */
       char   *port ;         /* Source port */
       char   *slot ;         /* Destination slot */
       char   log_info[MRD_MAX_LOG_STRING+1] ;   /* error string */

       /*
        *   Accept three required argument; robot, port and slot.  The
        *   volume tag is optional.
        */
       if( argc < 4 ) {
          printf("usage: %s robot port slot [ volume-tag ]\n", argv[0]);
          exit(1) ;
       }

       /*
        *   Just use these directly from the command line.
        */
       robot = argv[1] ;
       port  = argv[2] ;
       slot  = argv[3] ;

       /*
        *   If the volume tag is present use it.
        */
       if( argc > 4 )
          volume_tag = argv[4] ;

       /*
        *   Call the function.
        */
       status = mrd_inject(robot, volume_tag, port, slot, log_info) ;

       /*
        *   Print an error message if there is a failure.
        */
       if( status != MRD_STATUS_SUCCESS )
          printf("Inject failed: %s: %s.\n", mrd_strstatus(status),
             log_info[0] ? log_info : "none") ;
       else
          printf("Injected media from Port #%s to Slot #%s.\n",
             port, slot) ;

       return 0 ;
    }

9.4  –  Return Values

    Upon successful completion, the mrd_inject(3mrd) function returns
    the value MRD_STATUS_SUCCESS. If the mrd_inject(3mrd) fails the
    returned status value may be set to one of the following values.
    Other values that correspond to specific SCSI errors may also be
    possible, but these are the most likely.

9.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_name, log_info, slot, or port
    arguments are NULL pointers.

9.4.2  –  MRD_STATUS_ROBOT_ILLEGAL_REQUEST

    It is used when a sanity check fails in the code that attempts
    to move a cartridge to the Pass-Through Mechanism, when the robot
    type isn't a TL82n.

    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).

9.4.3  –  MRD_STATUS_PORT_INVALID

    This error is returned when the element address for a port is
    less than zero or greater than the number of ports.

9.4.4  –  MRD_STATUS_SLOT_INVALID

    This error is returned when the element address for a slot is
    less than zero or greater than the number of slots.

9.4.5  –  MRD_STATUS_SOURCE_EMPTY

    On routines that perform a SCSI Move Medium command, this error
    indicates that the source element is empty.

9.4.6  –  MRD_STATUS_DESTINATION_FULL

    On routines that perform a SCSI Move Medium command, this error
    indicates that the destination element already has a cartridge in
    it.

9.4.7  –  MRD_STATUS_CART_INVALID

    For routines that accept a volume_tag argument to perform volume
    tag verification, this error indicates that the volume tag of the
    media doesn't match that passed to the function.

9.4.8  –  MRD_STATUS_ROBOT_MECH_ERROR

    This error occurs as the result of a SCSI command failure, when
    the ASC is set to one of:

    o  0x15 - Positioning error.

    o  0x8B - Vendor unique; Pass-through mechanism errors on the
       TL82n

9.4.9  –  MRD_STATUS_VENDOR_UNIQUE_ERROR

    This error occurs when the internal routine used to decode SCSI-
    2 errors encounters an error that it has not been written to
    antipicate.

    This error also returned when the ASC is zero and the ASCQ is not
    one of zero or six, and when ASC/ASCQ are both zero and the key
    is 9h.

9.4.10  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

9.5  –  Related Functions

    Functions:

    o  mrd_move(3mrd)

    o  mrd_load(3mrd)

    o  mrd_unload(3mrd)

    o  mrd_eject(3mrd)

    o  mrd_ready_inport(3mrd)

10  –  mrd_load

    mrd_load - Move a piece of media from slot to drive.

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_load(
        const char  *robot_name,
        const char  *volume_tag,
        const char  *slot,
        const short  cartridge_side,
        const char  *drive,
        char        *log_info) ;

10.1  –  Parameters

    o  robot_name - The name of the robot device to be opened. On
       Digital UNIX, if the leading character of the name is not a
       slash (/), /dev/ will be prepended to the name.

    o  volume_tag - A NULL terminated character string that is the
       expected volume tag on the cartridge to be moved. On robots
       with vision support this string will be compared with the
       volume tag of the cartridge in the source slot and if it
       doesn't match the call will fail. This feature will not be
       used if the volume_tag is NULL or the empty string.

    o  slot - A NULL terminated character string that is the zero
       relative address of the slot which is to be used as the source
       of the move.

    o  cartridge_side - The cartridge_side indicates whether the
       media should be inverted as it is being to moved to the
       destination element. If the value 1 is used, the media will
       not be inverted. If the value 2 is used the media will be
       inverted.

    o  drive - A NULL terminated character string that is the zero
       relative address of the drive which is to be used as the
       destination of the move.

    o  log_info - This is a character array that should be at least
       MRD_MAX_LOG_STRING in length. If this function fails as the
       result of a SCSI error, this will be filled with the formatted
       request sense data. If this function fails as the result
       of an operating system error, the operating system message
       particular to the error will be copied into the array.

10.2  –  Description

    The mrd_load(3mrd) function is a specialized interface to the
    SCSI Move Medium command (or DSA equivalent). For the robot
    specified by robot_name, the routine will attempt to move the
    cartridge in the specified slot to the specified drive. Element
    addresses are zero based. On subsystems that support inverting a
    cartridge during a move, the cartridge_side argument can be used
    to indicate that the cartridge should be inverted.

    The robot will be opened and the arguments to the function will
    be verified to make sure they are safe and appropriate. The slot
    and drive address will be verified they are within the valid of
    those elements on the robot.

    The volume_tag argument can be used to perform cartridge volume
    tag verification before the move. If the cartridge volume tag at
    the port doesn't match that specified by this argument, then mrd_
    load(3mrd) will fail with the status MRD_STATUS_CART_INVALID. If
    volume_tag argument is a NULL pointer, an empty string or used on
    a robot without vision support this argument is silently ignored
    and the volume tag check will not be made.

10.3  –  Example

    /*
     *   Example of mrd_load(3mrd).  The command usage is:
     *
     *      mrd_load robot_name slot drive [ volume_tag ]
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_load.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       int   status ;      /* Status from mrd_load(3mrd) */
       short   side = 1 ;      /* Only support single sided media */
       char   *robot ;      /* The name of the robot */
       char   *volume_tag = NULL ;   /* Optional volume tag to check */
       char   *slot ;         /* Source slot */
       char   *drive ;      /* Destination drive */
       char   log_info[MRD_MAX_LOG_STRING+1] ;   /* error string */

       /*
        *   Accept three required argument; robot, port and slot.  The
        *   volume tag is optional.
        */
       if( argc < 4 ) {
          printf("usage: %s robot slot drive [ volume-tag ]\n", argv[0]);
          exit(1) ;
       }

       /*
        *   Just use these directly from the command line.
        */
       robot  = argv[1] ;
       slot   = argv[2] ;
       drive  = argv[3] ;

       /*
        *   If the volume tag is present use it.
        */
       if( argc > 4 )
          volume_tag = argv[4] ;

       /*
        *   Call the function.
        */
       status = mrd_load(robot, volume_tag, slot, side, drive, log_info);

       /*
        *   Print an error message if there is a failure.
        */
       if( status != MRD_STATUS_SUCCESS )
          printf("Load failed: %s: %s.\n", mrd_strstatus(status),
             log_info[0] ? log_info : "none") ;
       else
          printf("Loaded media in Slot #%s to Drive #%s\n",
             slot, drive) ;

       return 0 ;
    }

10.4  –  Return Values

    Upon successful completion, the mrd_load(3mrd) function returns
    the value MRD_STATUS_SUCCESS. If the mrd_load(3mrd) fails the
    returned status value may be set to one of the following values.
    Other values that correspond to specific SCSI errors may also be
    possible, but these are the most likely.

10.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_name, log_info, slot, or
    drive arguments are NULL pointers.

10.4.2  –  MRD_STATUS_SLOT_INVALID

    This error is returned when the element address for a slot is
    less than zero or greater than the number of slots.

10.4.3  –  MRD_STATUS_CART_SIDE_INVALID

    For routines that use the cartridge_side argument, this error
    indicates that the value is neither one (1) nor two (2).

10.4.4  –  MRD_STATUS_CART_INVALID

    For routines that accept a volume_tag argument to perform volume
    tag verification, this error indicates that the volume tag of the
    media doesn't match that passed to the function.

10.4.5  –  MRD_STATUS_SOURCE_EMPTY

    On routines that perform a SCSI Move Medium command, this error
    indicates that the source element is empty.

10.4.6  –  MRD_STATUS_DESTINATION_FULL

    On routines that perform a SCSI Move Medium command, this error
    indicates that the destination element already has a cartridge in
    it.

10.4.7  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

10.4.8  –  MRD_STATUS_DEVICE_INVALID

    This error code is used when an OpenVMS system service fails with
    the status SS$_NOSUCHDEV or SS$_IVDEVNAM. This will typically
    occur in mrd_startup(3mrd) when the caller tries to open a device
    which doesn't exist or uses an invalid device name.

    This error also occurs when the routine is called on behalf of
    a device controlled by the JU driver. The Media Robot Utility no
    longer uses the JU driver.

10.5  –  Related Functions

    Functions:

    o  mrd_move(3mrd)

    o  mrd_unload(3mrd)

    o  mrd_inject(3mrd)

    o  mrd_eject(3mrd)

11  –  mrd_lock

    mrd_lock - Send a SCSI Prevent-Allow Media Removal command

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_lock(
        const char *robot_name,
        const int   lock_value,
        char       *log_info) ;

11.1  –  Parameters

    o  robot_name - The name of the robot device to be opened. On
       Digital UNIX, if the leading character of the name is not a
       slash (/), /dev/ will be prepended to the name.

    o  lock_value - This value indicates whether the the routine
       should prevent or allow media removal for the robot. The
       include file <mrd_common.h> defines two constants PREVENT_
       REMOVAL and ALLOW_REMOVAL that will set the correct value.

    o  log_info - This is a character array that should be at least
       MRD_MAX_LOG_STRING in length. If this function fails as the
       result of a SCSI error, this will be filled with the formatted
       request sense data. If this function fails as the result
       of an operating system error, the operating system message
       particular to the error will be copied into the array.

    This routine sends a SCSI Prevent-Allow Media Removal command.
    Some robots have been observed to silently ignore the command,
    others will fail with an illegal request and others will do
    something particular to the robot. This command is not supported
    on the DSA medium-changers (TA and TF drives). SCSI defines this
    a single command where the value of a single bit determines the
    affect.

    On some versions of TL820 firmware, the command with PREVENT_
    REMOVAL will disable Move Medium commands to the outport. Other
    versions will also disable Move Medium commands from the inport.
    Other models will ignore the command entirely. The TL810 family
    of libraries use the command to disable the front panel button
    which allows opening the port door. Please refer to your robot's
    documentation to see what affect this command will have.

11.2  –  Return Values

    Upon successful completion, the mrd_lock(3mrd) function returns
    the value MRD_STATUS_SUCCESS. If the mrd_lock(3mrd) fails the
    returned status value may be set to one of the following values.
    Other values that correspond to specific SCSI errors may also be
    possible, but these are the most likely.

11.2.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_name or log_info arguments
    are NULL pointers.

11.2.2  –  MRD_STATUS_ROBOT_ILLEGAL_REQUEST

    This is used in the mrd_lock(3mrd) code when the value is not one
    of ALLOW_REMOVAL or PREVENT_REMOVAL.

    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).

11.2.3  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

11.3  –  Related Functions

    Functions:

    mrd_prevent_allow(3mrd)

12  –  mrd_map_element

    mrd_map_element - Map an absolute element address to a zero
    relative one.

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_map_element(
        const robot_info_t *robot_info,
        const int           address,
        char               *result) ;

12.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  address - This is the absolute element address that is to be
       mapped.

    o  result - This is the address where the zero relative element
       address is to be written. Like other element addresses used
       by the Media Robot Driver Library, it is a character string. A
       character array of MRD_NAME_SIZE bytes should be used.

12.2  –  Description

    Given a robot_info_t structure and absolute element address,
    this routine figures out the corresponding element type and zero
    relative address. The relative address is formatted into the
    space provided by result and the element type is returned.

    A valid robot_info_t structure can be obtained by using mrd_
    startup(3mrd) or mrd_show(3mrd) to open the robot and fill in the
    robot_info_t structure.

    The SCSI-2 specification allows an absolute address of zero (0)
    to refer to a default transport, when a medium-changer has more
    than one. When handed zero as the absolute address, this routine
    will reflect this convention even if the particular medium-
    changer doesn't.

12.3  –  Example

    /*
     *   For the specified robot, walk through the remainder of
     *   argument list and have mrd_map_element(3mrd) convert
     *   each address to a relative element address and type.
     *
     *      mrd_map_element robot address [ address... ]
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_map_element.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       char      *robot ;   /* Robot for command */
       int      status ;   /* status from mrd_startup(3mrd) */
       int      address ;   /* Input argument */
       int      type ;      /* element type */
       int      i ;      /* index counter */
       robot_info_t   robot_info ;   /* Set by mrd_startup(3mrd) */
       char      result[MRD_NAME_SIZE+1] ;   /* relative address */
       char      log_info[MRD_MAX_LOG_STRING+1] ;   /* error text */

       /*
        *   Two required arguments, many optional ones.
        */
       if( argc < 3 ) {
          printf("usage: %s robot address [ address... ]\n", argv[0]) ;
          exit(1) ;
       }
       else
          robot = argv[1] ;

       /*
        *   Open the robot.  Must set channel to BAD_CHANNEL so
        *   it will really open the robot.
        */
       robot_info.channel = BAD_CHANNEL ;

       status = mrd_startup(robot, &robot_info, log_info) ;

       if( status != MRD_STATUS_SUCCESS ) {
          printf("Can't open robot %s: %s: %s.\n", robot,
             mrd_strstatus(status),
             log_info[0] ? log_info : "none") ;

          exit(1) ;
       }

       /*
        *   We don't need to keep the robot for the remainder of
        *   the example.
        */
       (void)mrd_shutdown(&robot_info) ;

       /*
        *   For each address in the list, call mrd_map_element(3mrd).
        */
       for(i = 2; i < argc; i++) {
          address = atoi(argv[i]) ;

          type = mrd_map_element(&robot_info, address, result) ;

          if( type == 0 )
             printf("Can't map %d on robot %s.\n", address, robot) ;
          else
             printf("Element %d -> %s %s\n", address,
                mrd_strelement(type), result) ;
       }

       return 0 ;
    }

12.4  –  Return Values

    Upon successful completion, the mrd_map_element(3mrd) function
    returns the element type, which is one of SLOT, PORT, DRIVE or
    TRANSPORT. On an error it returns zero (0). The two possible
    errors are the robot_info address being NULL and the address not
    one used by this medium-changer.

12.5  –  Related Functions

    Functions:

    o  mrd_show(3mrd)

    o  mrd_home(3mrd)

    o  mrd_find_cartridge(3mrd)

13  –  mrd_message

    mrd_strstatus

    o  mrd_strelement

    o  mrd_strexcept - I18N MRD messages and strings.

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    char *mrd_strstatus(int code) ;

    char *mrd_strexcept(
          unsigned char  asc,
          unsigned char  ascq,
          char          *buffer,
          size_t         length) ;

    char *mrd_strelement(int code) ;

13.1  –  Parameters

    o  code - For mrd_strstatus(3mrd) this is the status
       code returned from one of the MRD functions. For mrd_
       strelement(3mrd) this is a code number corresponding to a
       number of common strings that may occur in an appliation using
       MRD.

    o  asc - This is the SCSI Additional Sense Code (ASC) in
       the element status data (data.asc) obtained from the mrd_
       show(3mrd) or mrd_find_cartridge(3mrd) functions.

    o  ascq - This is the SCSI Additional Sense Code Qualifer (ASCQ)
       in the element status data (data.ascq) obtained from the mrd_
       show(3mrd) or mrd_find_cartridge(3mrd) functions.

    o  buffer - This is the address of a user supplied buffer, into
       which the message corresponding to the provided ASC/ASCQ code
       will be copied. This message is formatted to include the ASC
       /ASCQ codes in hexadecimal.

    o  length - This is size of the buffer provided. No more than
       length characters will be copied from the internal temporary
       buffer to the user's buffer. The internal buffer is limited to
       BUFSIZ characters.

13.2  –  Description

    These routines offer an interface to convert MRD status codes,
    element exception codes and constants for other common words
    into internationalized text. The message catalogs used by these
    routines are the same ones used by the Media Robot Utility
    command line interface. However, if no message catalog is
    available, a standard default message will be used for each code.

    The routine mrd_strstatus(3mrd) accepts MRD error codes and
    returns the corresponding message string from the catalog.

    The routine mrd_strelement(3mrd) accepts one of the MRD_ELEMENT
    codes defined in <mrd_message.h> and returns the corresponding
    word. An effort has been made to ensure that the first four
    code values correspond to the SCSI element types of SLOT, DRIVE,
    PORT and TRANSPORT, but the routine will remap these values to
    corresponding MRD_ELEMENT codes and return that string.

    The routine mrd_strexcept(3mrd) accepts the ASC/ASCQ code set
    in the element_info_t structure from an mrd_show(3mrd) or mrd_
    find_cartridge(3mrd) when the ELEMENT_EXCEPT bit is set in the
    data.state field. Using the user provided buffer and length
    it will format the corresponding message to include the ASC
    /ASCQ values and return a pointer to the space. Since many
    of these code are vendor specific, we're unable to provide
    translations for all them, but we have made an effort to include
    the translations for many of the exception codes on supported
    medium-changers.

13.3  –  Codes Translated

    The following MRD_ELEMENT codes are those currently supported by
    mrd_strelement(3mrd), with their corresponding default strings.

    The first items listed are self-explanatory.

    o  MRD_ELEMENT_TRANSPORT - Transport

    o  MRD_ELEMENT_SLOT - Slot

    o  MRD_ELEMENT_PORT - Port

    o  MRD_ELEMENT_DRIVE - Drive

    o  MRD_ELEMENT_EMPTY - Empty

    o  MRD_ELEMENT_FULL - Full

    o  MRD_ELEMENT_EXCEPT - Exception

    o  MRD_ELEMENT_ACCESS - Access

    o  MRD_ELEMENT_INPORT - Inport is suitable for use when the
       ELEMENT_IMPENB bit is set in the state and data.state field
       of the element_info_t data.

    o  MRD_ELEMENT_OUTPORT - OUTPORT is suitable for use when the
       ELEMENT_EXPENB bit is set in the state and data.state field of
       the element_info_t data.

    o  MRD_ELEMENT_IOPORT - IOPORT suitable for use when the ELEMENT_
       IMPENB and ELEMENT_EXPENB bits are set in the state and
       data.state field of the element_info_t data.

    o  MRD_ELEMENT_PASS - PassThru suitable in those cases where
       the Pass-through mechanism of the TL820 can be identified.
       Currently, the only way to do this is to know the absolute
       address of the PTM depending on whether the library is in
       Multi-unit Single-LUN (Transport 1) mode or Single-unit
       Single-LUN (Port 2) mode.

    o  MRD_ELEMENT_MYSTERY - This code is suitable when neither
       the ELEMENT_IMPENB nor ELEMENT_EXPENB bits are set in the
       state and data.state field of the element_info_t data. Most
       medium-changers identify their ports, when they have one
       or the other, or both. The MRD engineering team has never
       encountered a (correctly functioning) medium-changer with a
       Mystery Port.
       * We do not expect this text to survive critical
         review of the management, but we tried.

13.4  –  Example

    /*
     *   Illustrate the different mrd_str*(3mrd) functions.  For each
     *   case a code from one the mrd_message.h is selected and the
     *   resulting string printed.  The command doesn't require
     *   any arguments.
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_string.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       /*
        *   This happens to be an obscure VMS system service error code.
        */
       int   status = MRD_STATUS_UNASEFC ;
       /*
        *   The code for the TL820 Pass-through mechanism.
        */
       int   word = MRD_ELEMENT_PASS ;
       /*
        *   The codes for when a TL820 doesn't a have a bin-pack
        *   installed for a certain range of slots.
        */
       char   asc  = 0x80 ;
       char   ascq = 0x2 ;
       /*
        *   Buffer for the message.
        */
       char   buffer[BUFSIZ] ;

       printf("Status:    %s\n", mrd_strstatus(status)) ;
       printf("Word:      %s\n", mrd_strelement(word)) ;
       printf("Exception: %s\n", mrd_strexcept(asc,ascq,buffer,BUFSIZ));

       return 0 ;
    }

13.5  –  Return Values

    These routines try very hard to return the corresponding error
    text, even to the point of formatting the integer value into
    the provided string, into a static buffer or returning a default
    string. These routines should never return NULL, but they rely on
    catgets(3) to do the underlying work of looking the error code in
    the message catalogs.

13.6  –  Related Functions

    Functions:

    o  mrd_move(3mrd)

    o  mrd_load(3mrd)

    o  mrd_unload(3mrd)

    o  mrd_inject(3mrd)

    o  mrd_eject(3mrd)

    o  mrd_show(3mrd)

    o  mrd_ready(3mrd)

    o  mrd_position(3mrd)

    o  mrd_initialize(3mrd)

    o  mrd_home(3mrd)

    o  mrd_find_cartridge(3mrd)

    o  mrd_lock(3mrd)

    o  mrd_unlock(3mrd)

14  –  mrd_move

    mrd_move - Move media from one location to another

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_move(
        const char *robot_name,
        const char *volume_tag,
        const char *source,
        const int   source_type,
        const char *destination,
        const int   destination_type,
        const int   cartridge_side,
        char       *log_info) ;

14.1  –  Parameters

    o  robot_name - The name of the robot device to be opened. On
       Digital UNIX, if the leading character of the name is not a
       slash (/), /dev/ will be prepended to the name.

    o  volume_tag - A NULL terminated character string that is the
       expected volume tag on the cartridge to be moved. On robots
       with vision support this string will be compared with the
       volume tag of the cartridge in the source slot and if it
       doesn't match the call will fail. This feature will not be
       used if the volume_tag is NULL or the empty string.

    o  source - The source is a character string which is the zero
       based element address that is to be used as the source of the
       move.

    o  source_type - The source_type is an integer value to indicate
       the type of the source_name address. The <mrd_common.h>
       include file defines constants for different element types;
       SLOT, DRIVE, PORT and TRANSPORT.

    o  destination - The destination is a character string which
       is the zero based element address that is to be used as the
       destination of the move.

    o  destination_type - The destination_type is an integer value
       to indicate the element type of the destination address. The
       <mrd_common.h> include file defines constants for different
       element types; SLOT, DRIVE, PORT and TRANSPORT.

    o  cartridge_side - The cartridge_side indicates whether the
       media should be inverted as it is being to moved to the
       destination element. If the value 1 is used, the media will
       not be inverted. If the value 2 is used the media will be
       inverted.

    o  log_info - This is a character array that should be at least
       MRD_MAX_LOG_STRING in length. If this function fails as the
       result of a SCSI error, this will be filled with the formatted
       request sense data. If this function fails as the result
       of an operating system error, the operating system message
       particular to the error will be copied into the array.

14.2  –  Description

    The mrd_move(3mrd) function is an interface to the SCSI Move
    Medium command. For the robot specified by robot_name, the
    routine will attempt to move the cartridge in the element
    specified by the source address and type to that specified by
    the destination address and type.

    Element addresses are zero based. On subsystems that support
    inverting a cartridge during a move, the cartridge_side argument
    can be used to indicate that the cartridge should be inverted.

    The robot will be opened and the arguments to the function
    verified that they are appropriate. Element addresses and types
    will be checked that they are within the valid range of elements
    on the robot. The cartridge_side argument will be verified that
    it is either the value one (1) or two (2). All pointer arguments,
    except cartridge_name, are checked to verify they are not NULL
    pointers.

    The cartridge_name argument can be used to perform cartridge
    volume tag verification before the move. If the cartridge volume
    tag at the source doesn't match that specified by this argument,
    then mrd_move(3mrd) will fail with the status MRD_STATUS_CART_
    INVALID. If the cartridge_name argument is a NULL pointer, an
    empty string or used on a robot without vision support this
    argument is silently ignored and the volume tag check will not
    be made.

    On the TL820 family of libraries, the tape will be moved to the
    pass-through read station if the source is a Port. If this move
    fails the status will be appropriate to that of a failed Move
    Medium. Likely error codes are documented in the Return Values
    section.

    After the volume tag check, the destination address is checked
    in the same way the source was. The same error codes are returned
    if the destination address is out of range. With the range checks
    completed the Move Medium command is issued. If successful MRD_
    STATUS_SUCCESS is returned. If the command failed, the SCSI error
    will be mapped to the appropriate MRD_STATUS message.

    The DLT libraries (TL820 and TL810 families) require the host
    issue a SCSI Unload command before a cartridge may be removed
    from the drive. The function mrd_move(3mrd), does not offer
    this feature. Thus, the calling program must do this itself. On
    Digital UNIX this may done with the MTOFFL opcode of the MTIOCTOP
    I/O control.

14.3  –  Example

    /*
     *   Example to do slot to slot moves, using mrd_move(3mrd).  The
     *   reason for only doing slot to slot, is that it simplifies
     *   having to figure out element types.  The mrd_position(3mrd)
     *   example shows how part of this may be done.
     *
     *   The command usage is:
     *
     *      mrd_move source-slot destination-slot [ volume-tag ]
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_move.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       int   status ;      /* Status from mrd_move(3mrd) */
       int   side = 1 ;      /* Only support side one */
       char   *robot ;      /* Name of the robot to use */
       char   *volume_tag = NULL ;   /* Volume tag to check */
       char   *source ;      /* Source slot */
       char   *destination ;      /* Destination slot */
       char   log_info[MRD_MAX_LOG_STRING+1] ;   /* error string */

       /*
        *   Three required arguments; robot name, source slot and
        *   destination slot.
        */
       if( argc < 4 ) {
          printf("usage: %s robot src dest [ volume-tag ]\n", argv[0]) ;
          exit(1) ;
       }

       robot       = argv[1] ;
       source      = argv[2] ;
       destination = argv[3] ;

       /*
        *   Volume tag is optional.
        */
       if( argc > 4 )
          volume_tag = argv[4] ;

       /*
        *   Do the operation.
        */
       status = mrd_move(robot, volume_tag, source, SLOT, destination,
             SLOT, side, log_info) ;

       if( status != MRD_STATUS_SUCCESS )
          printf("Move failed: %s: %s.\n", mrd_strstatus(status),
             log_info[0] ? log_info : "none") ;
       else
          printf("Moved media from Slot #%s to Slot #%s\n",
             source, destination) ;

       return 0 ;
    }

14.4  –  Return Values

    Upon successful completion, the mrd_move(3mrd) function returns
    the value MRD_STATUS_SUCCESS. If mrd_move(3mrd) fails the
    returned status value may be set to one of the following values.
    Other values that correspond to specific SCSI errors may also be
    possible, but these are the most likely.

14.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_name, source, destination, or
    log_info arguments are NULL pointers.

14.4.2  –  MRD_STATUS_CART_SIDE_INVALID

    For routines that use the cartridge_side argument, this error
    indicates that the value is neither one (1) nor two (2).

14.4.3  –  MRD_STATUS_PORT_INVALID

    This error is returned when the element address for a port is
    less than zero or greater than the number of ports.

14.4.4  –  MRD_STATUS_TRANSPORT_INVALID

    This error is returned when the element address for a transport
    is less than zero or greater than the number of transports.

14.4.5  –  MRD_STATUS_INVALID_TYPE

    For routines that allow the specification of an element type
    argument, this error indicates that specified type was not one of
    SLOT, DRIVE, PORT or TRANSPORT.

14.4.6  –  MRD_STATUS_CART_INVALID

    For routines that accept a volume_tag argument to perform volume
    tag verification, this error indicates that the volume tag of the
    media doesn't match that passed to the function.

14.4.7  –  MRD_STATUS_SOURCE_EMPTY

    On routines that perform a SCSI Move Medium command, this error
    indicates that the source element is empty.

14.4.8  –  MRD_STATUS_DESTINATION_FULL

    On routines that perform a SCSI Move Medium command, this error
    indicates that the destination element already has a cartridge in
    it.

14.4.9  –  MRD_STATUS_CART_NOT_AVAIL

    This error can occur on the TL81n and TL82n family of DLT
    libraries when the source of a move is a drive and the cartridge
    in the drive is still on-line. These robots do not allow moving
    the cartridge until the drive is taken offline.

14.4.10  –  MRD_STATUS_SLOT_INVALID

    This error is returned when the element address for a slot is
    less than zero or greater than the number of slots.

14.4.11  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

14.4.12  –  MRD_STATUS_DEVICE_INVALID

    This error code is used when an OpenVMS system service fails with
    the status SS$_NOSUCHDEV or SS$_IVDEVNAM. This will typically
    occur in mrd_startup(3mrd) when the caller tries to open a device
    which doesn't exist or uses an invalid device name.

    This error also occurs when the routine is called on behalf of
    a device controlled by the JU driver. The Media Robot Utility no
    longer uses the JU driver.

14.4.13  –  MRD_STATUS_CART_NOT_AVAIL

    This error can occur on the TL81n and TL82n family of DLT
    libraries when the source of a move is a drive and the cartridge
    in the drive is still on-line. These robots do not allow moving
    the cartridge until the drive is taken offline.

    On OpenVMS this can be done with $DISMOU system service.

14.5  –  Related Functions

    Functions:

    o  mrd_load(3mrd)

    o  mrd_unload(3mrd)

    o  mrd_inject(3mrd)

    o  mrd_eject(3mrd)

    o  mrd_ready(3mrd)

15  –  mrd_move_medium

    mrd_move_medium - Move media from one location to another

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_move_medium(
        robot_info_t *robot_info,
        int           transport,
        int           source,
        int           destination,
        int           invert,
        dev_status_t *dev_status) ;

15.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  transport - The transport is the numeric value of the
       transport which will be moved.

    o  source - The source is an absolute element address.

    o  destination- The destination is an absolute element address.

    o  invert - The invert is a numeric value used to indicate if the
       medium should be inverted when it is moved. A value of one (1)
       is used to indicate that the medium should be inverted.

    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.

15.2  –  Description

    This routine performs a SCSI Move Medium command, or equivalent
    if some other I/O architecture is supported. It is used by mrd_
    move(3mrd), mrd_load(3mrd), mrd_unload(3mrd), mrd_inject(3mrd)
    and mrd_eject(3mrd). Since it accepts a robot_info_t structure
    associated with an open medium changer it can be used to perform
    multiple move commands, without having to re-open the medium
    changer as the other functions that use it do.

    The robot_info argument is the address of a robot_info_t that
    has been opened by mrd_startup(3mrd). If the medium changer isn't
    opened, the Move Medium command will fail with the operating
    system error for trying to use an unopened device. On SCSI medium
    changers, it maps directly to the SCSI Move Medium command.

    The transport address is the absolute address of the transport
    element to be used for the command. Many medium changers allow
    the use of address zero (0) as the default transport, but some
    may require a transport address that is valid for the medium
    changer. For single transport medium changers, the transport
    base address in the robot_info_t structure, transport_start is a
    suitable address.

    The source and destination addresses are absolute addresses to
    be used as the source and destination for the move. The absolute
    address can be calculated from a zero relative address by adding
    it to the base address for the element type. The routine makes
    no checks for the validity of the address, relying on the medium
    changer to do this.

    A invert value of one (1) can be used on medium changers that
    support inverting the media, when this is desired; an optical
    drive with two sided media. Otherwise a value of zero should be
    used.

    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.

15.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:

15.4  –  Example

    /*
     *   This is an example of using mrd_move_medium(3mrd) directly to
     *   move a cartridge from one slot to another.  To simplify the
     *   example, it only supports slot to slot moves, but it shows
     *   how the absolute element addresses are calcuated.  For each
     *   additional destination address given, the previous (successful)
     *   destination address is used as the source.
     *
     *   Usage:
     *
     *      mrd_move_medium robot source dest [ dest... ]
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_move_medium.c   1.4 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       int      i ;      /* counter */
       int      source ;   /* Source address */
       int      dest ;      /* Destination address */
       int      invert = 0 ;   /* Assume it can't invert */
       int      transport ;   /* Transport address */
       int      status ;   /* return status */
       char      *robot ;   /* Robot to open */
       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 < 4 ) {
          printf("usage: %s robot source dest [ dest... ]\n", argv[0]) ;
          exit(1) ;
       }
       else {
          robot  = argv[1] ;
          source = atoi(argv[2]) ;
       }

       /*
        *   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) ;
       }

       /*
        *   Set the transport address.  If there is only one
        *   transport use the correct address.  If there is
        *   more than one assume that the medium changer
        *   supports zero as the default.
        */
       if( robot_info.transport_count == 1 )
          transport = robot_info.transport_start ;
       else
          transport = 0 ;

       /*
        *   Turn the relative slot address into an absolute slot
        *   address by adding the slot start address.
        */
       source += robot_info.slot_start ;

       /*
        *   For each destination address on the command line,
        *   move the the cartridge in the source to the
        *   destination.  After each (successful) move, replace
        *   the previous source with this destination.
        */
       for(i = 3; i < argc; i++) {
          /*
           *   Calculate the absolute address.
           */
          dest = atoi(argv[i]) + robot_info.slot_start ;

          /*
           *   Print an audit as we go.  Since we know these
           *   are slots, convert back to relative addresses
           *   for the audit.
           */
          printf("Move the medium in slot %d to slot %d\n",
             source - robot_info.slot_start,
             dest   - robot_info.slot_start) ;

          status = mrd_move_medium(&robot_info, transport, source,
                dest, invert, &dev_status) ;

          if( status != MRD_STATUS_SUCCESS ) {
             printf("Move failed on %s: %s\n", robot,
                mrd_strstatus(status)) ;

             /*
              *   Since the cartridge didn't move, don't
              *   reset the source, by skipping the remainder
              *   of the loop.
              */
             continue ;
          }

          /*
           *   Make the next source, this destination.
           */
          source = dest ;
       }

       (void)mrd_shutdown(&robot_info) ;

       return 0 ;
    }

15.5  –  Return Values

    Upon successful completion, mrd_move_medium(3mrd) will
    return MRD_STATUS_SUCCESS. On a failure, an MRD_STATUS value
    corresponding to the error will be returned. Common errors are:

15.5.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_info or dev_status arguments
    are NULL pointers.

15.5.2  –  MRD_STATUS_CART_NOT_AVAIL

    This error can occur on the TL81n and TL82n family of DLT
    libraries when the source of a move is a drive and the cartridge
    in the drive is still on-line. These robots do not allow moving
    the cartridge until the drive is taken offline.

15.5.3  –  MRD_STATUS_DESTINATION_FULL

    On routines that perform a SCSI Move Medium command, this error
    indicates that the destination element already has a cartridge in
    it.

15.5.4  –  MRD_STATUS_SOURCE_EMPTY

    On routines that perform a SCSI Move Medium command, this error
    indicates that the source element is empty.

15.5.5  –  MRD_STATUS_ELEMENT_INVALID

    This error occurs when a SCSI command fails with the ASC set to
    0x21. The log_info will contain the ASCQ. This indicates that an
    invalid element address reached the medium-changer. For example,
    specifying the 13th slot when only 12 slots are present.

15.5.6  –  MRD_STATUS_CART_NOT_AVAIL

    This error can occur on the TL81n and TL82n family of DLT
    libraries when the source of a move is a drive and the cartridge
    in the drive is still on-line. These robots do not allow moving
    the cartridge until the drive is taken offline.

    On OpenVMS this can be done with $DISMOU system service.

15.5.7  –  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).

15.6  –  Related Functions

    Functions:

    o  mrd_move(3mrd)

    o  mrd_load(3mrd)

    o  mrd_unload(3mrd)

    o  mrd_inject(3mrd)

    o  mrd_eject(3mrd)

16  –  mrd_position

    mrd_position - Position a transport to an element.

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>
    int mrd_position(
        const char   *robot_name,
        const char   *transport,
        const char   *element,
        const int     element_type,
        const int     cartridge_side,
        char         *log_info) ;

16.1  –  Parameters

    o  robot_name - The name of the robot device to be opened. On
       Digital UNIX, if the leading character of the name is not a
       slash (/), /dev/ will be prepended to the name.

    o  transport - The transport is the numeric value of the
       transport which will be moved.

    o  element A NULL terminated character string that is the zero
       relative address of the element to which the transport is to
       be moved.

    o  element_type The address of space where the type of the
       destination will be copied if the move is successful. If the
       element_type address is NULL, the type will not be returned.

    o  cartridge_side - The cartridge_side indicates whether the
       media should be inverted as it is being to moved to the
       destination element. If the value 1 is used, the media will
       not be inverted. If the value 2 is used the media will be
       inverted.

    o  log_info - This is a character array that should be at least
       MRD_MAX_LOG_STRING in length. If this function fails as the
       result of a SCSI error, this will be filled with the formatted
       request sense data. If this function fails as the result
       of an operating system error, the operating system message
       particular to the error will be copied into the array.

16.2  –  Description

    The mrd_position(3mrd) routine provides access to the SCSI
    Position to Element command. For the robot specified by the
    robot_name, the routine will attempt to position the specified
    transport to the specified element. The transport and element
    addresses are zero based. On subsystems that support inverting a
    cartridge during a move, the cartridge_side argument can be used
    to indicate that the transport should be inverted to invert a
    cartridge.

    The robot will be opened and the arguments to the function
    verified that they are appropriate. The element address and
    type will be checked that they are within the valid range of
    elements on the robot. The cartridge_side argument will be
    verified that it is either the value one (1) or two (2). All
    pointer arguments, except transport, are checked to verify they
    are not NULL pointers.

    Many robot subsystems support an absolute transport address of
    zero for the Position to Element command so that the robot can
    select the appropriate transport if multiple are available. This
    routines allows the default transport address to be specified by
    using a NULL pointer for the transport string.

16.3  –  Example

    /*
     *   Example to do slot to slot moves.  The command usage is:
     *
     *      mrd_position robot_name type address [ transport ]
     *
     *   Type can be one of:
     *
     *      slot, port, drive or transport
     *
     *   The optional transport argument can be a transport address
     *   number, the word "default" or an empty string.
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_position.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #include <mrd_common.h>
    #include <mrd_message.h>

    /*
     *   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 -1 ;
    }

    main(int argc, char *argv[])
    {
       int   status ;
       int   side = 1 ;
       char   *robot ;
       char   *cart = NULL ;
       char   *element ;
       char   *transport ;
       int   type ;
       char   log_info[MRD_MAX_LOG_STRING+1] ;

       if( argc < 4 ) {
          printf("usage: %s robot type address [ transport ]\n",
             argv[0]) ;

          exit(1) ;
       }

       robot   = argv[1] ;
       type    = convert_type(argv[2]) ;
       element = argv[3] ;

       if( argc > 4 ) {
          transport = argv[4] ;

          /*
           *   If "default" or a suitable abbreviation is used
           *   use NULL for the transport name, to indicate that
           *   the SCSI default transport should be used.
           */
    #ifdef   vms
          if( strncmp("default", transport, strlen(transport)) == 0 )
    #else
          if( strncasecmp("default", transport, strlen(transport)) == 0 )
    #endif
             transport = NULL ;
       }
       else
          transport = "0" ;

       status = mrd_position(robot, transport, element, type,
                             side, log_info) ;

       if( status != MRD_STATUS_SUCCESS )
          printf("Position failed: %s: %s.\n", mrd_strstatus(status),
             log_info[0] ? log_info : "none") ;
       else if ( transport == NULL )
          printf("Positioned default Transport to %s #%s\n",
             mrd_strelement(type), element) ;
       else
          printf("Positioned Transport #%s to %s #%s\n",
             mrd_strelement(type), element) ;

       return 0 ;
    }

16.4  –  Return Values

    Upon successful completion, the mrd_position(3mrd) function
    returns the value MRD_STATUS_SUCCESS. If the mrd_position(3mrd)
    fails the returned status value may be set to one of the
    following values. Other values that correspond to specific SCSI
    errors may also be possible, but these are the most likely.

16.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_name, log_info, or element
    arguments are NULL pointers.

16.4.2  –  MRD_STATUS_ROBOT_ILLEGAL_REQUEST

    It is used when the medium changer does not support the Position
    To Element command. The seven and five slot DLT loaders do not
    support the command, though the TL820 and TL810 family libraries
    do. Some models of TLZ6L and TLZ7L do not support the command and
    may take a long time to fail.

    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).

16.4.3  –  MRD_STATUS_CART_SIDE_INVALID

    For routines that use the cartridge_side argument, this error
    indicates that the value is neither one (1) nor two (2).

16.4.4  –  MRD_STATUS_INVALID_TYPE

    For routines that allow the specification of an element type
    argument, this error indicates that specified type was not one of
    SLOT, DRIVE, PORT or TRANSPORT.

16.4.5  –  MRD_STATUS_PORT_INVALID

    This error is returned when the element address for a port is
    less than zero or greater than the number of ports.

16.4.6  –  MRD_STATUS_SLOT_INVALID

    This error is returned when the element address for a slot is
    less than zero or greater than the number of slots.

16.4.7  –  MRD_STATUS_TRANSPORT_INVALID

    This error is returned when the element address for a transport
    is less than zero or greater than the number of transports.

16.4.8  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

16.4.9  –  MRD_STATUS_DEVICE_INVALID

    This error code is used when an OpenVMS system service fails with
    the status SS$_NOSUCHDEV or SS$_IVDEVNAM. This will typically
    occur in mrd_startup(3mrd) when the caller tries to open a device
    which doesn't exist or uses an invalid device name.

    This error also occurs when the routine is called on behalf of
    a device controlled by the JU driver. The Media Robot Utility no
    longer uses the JU driver.

16.5  –  Related Functions

    Functions:

    mrd_position_to_element(3mrd)

17  –  mrd_position_to_element

    mrd_position_to_element - Move transport to specified location

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_position_to_element(
        robot_info_t *robot_info,
        int           transport,
        int           destination,
        int           invert,
        dev_status_t *dev_status) ;

17.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  transport - The transport is the numeric value of the
       transport which will be moved.

    o  destination- The destination is an absolute element address.

    o  invert - The invert is a numeric value used to indicate if the
       medium should be inverted when it is moved. A value of one (1)
       is used to indicate that the medium should be inverted.

    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.

17.2  –  Description

    This routine performs a SCSI Position to Element command. This
    command positions the trasport to the specified destination
    element. It is used by mrd_position(3mrd) function.

    The robot_info argument is the address of a robot_info_t that has
    been opened by mrd_startup(3mrd). This allows multiple position
    commands (and other commands) to be executed without having to
    repeat the startup for each command.

    The transport address is the absolute address of the transport
    element to be used for the command. Many medium changers allow
    the use of address zero (0) as the default transport, but some
    may require a transport address that is valid for the medium
    changer. For single transport medium changers, the transport
    base address of the robot_info_t structure, transport_start is a
    suitable address.

    The destination address is the absolute addresses to be used as
    the destination for the command . The absolute address can be
    calculated from a zero relative address by adding it to the base
    address for the element type. The routine makes no checks for
    the validity of the address, relying on the medium changer to do
    this.

    A invert value of one (1) can be used on medium changers that
    support inverting the transport, when this is desired; an optical
    drive with two sided media. Otherwise a value of zero should be
    used.

    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.

17.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:

     int  slot ;
     robot_info_t robot_info ;

     /*
      * An relative starting address.
      */
     slot = 3 ;

     /*
      * Becoming an absolute address.
      */
     slot += robot_info.slot_start ;

17.4  –  Example

    /*
     *   This is an example of using mrd_position_to_element(3mrd)
     *   to perform multiple Position To Element commands.  For
     *   each pair of arguments after the robot and transport
     *   address, it will position the transport to that location.
     *
     *      mrd_position_to_element robot transport type address
     *
     *   Type can be one of:
     *
     *      slot, port, drive or transport
     *
     *   The optional transport argument can be a transport address
     *   number, the word "default" or an empty string.  To keep the
     *   example as simple as possible, it doesn't try to invert the
     *   transport.
     */
    #ifndef   lint
    static char SccsId[] = "@(#)mrd_position_to_element.c 1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #include <mrd_common.h>
    #include <mrd_message.h>

    /*
     *   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 -1 ;
    }

    main(int argc, char *argv[])
    {
       int      el ;         /* Counter */
       int      status ;      /* Status from MRD calls */
       int      invert = 0 ;      /* Don't invert */
       char      *robot ;      /* Robot name */
       int      type ;         /* Element type */
       int      element ;      /* Relative element addr */
       int      address ;      /* Absolute element addr */
       int      transport ;      /* Transport address */
       char      *transport_name ;   /* Tranport name */
       robot_info_t   robot_info ;
       dev_status_t   dev_status ;
       char      log_info[MRD_MAX_LOG_STRING+1] ;

       if( argc < 5 ) {
          printf("usage: %s robot transport type address ...\n", argv[0]);
          exit(1) ;
       }

       /*
        *   Get the medium changer name.
        */
       robot = argv[1] ;

       /*
        *   Get the transport number.  We'll keep it as a name
        *   so we can detect the default transport.  Once we
        *   know the element addresses, we can add the base
        *   base address if appropriate.
         */
       if( strcmp(argv[2], "default") == 0 )
          transport_name = NULL ;
       else
          transport_name = argv[2] ;

       /*
        *   Make sure there are pairs of arguments left.  There
        *   should be an odd number.
        */
       if((argc % 2) == 0 ) {
          printf("Pairs of arguments are required.\n") ;
          exit(1) ;
       }

       /*
        *   Open the robot.
        */
       robot_info.channel = BAD_CHANNEL ;

       status = mrd_startup(robot, &robot_info, log_info) ;

       if( status != MRD_STATUS_SUCCESS ) {
          fprintf(stderr, "Can't start %s: %s\n", robot,
             mrd_strstatus(status)) ;

          exit(1) ;
       }

       if( transport_name == NULL )
          transport = 0 ;
       else
          transport = atoi(transport_name) + robot_info.transport_start;

       /*
        *   Look at the element addresses in pairs.
        */
       for(el = 3; el < argc; el += 2) {
          type    = convert_type(argv[el]) ;
          element = atoi(argv[el + 1]) ;

          switch( type ) {
          case SLOT:
             address = element + robot_info.slot_start ;
             break ;
          case DRIVE:
             address = element + robot_info.device_start ;
             break ;
          case TRANSPORT:
             address = element + robot_info.transport_start ;
             break ;
          case PORT:
             address = element + robot_info.port_start ;
             break ;
          default:
             printf("Unknown element type: %s %s\n", argv[el],
                argv[el + 1]) ;

             continue ;
          }

          /*
           *   Audit the command.
           */
          printf("Position transport to %s #%d.\n", mrd_strelement(type),
             element) ;

          /*
           *   Do the command.
           */
          status = mrd_position_to_element(&robot_info, transport,
                    address, invert, &dev_status) ;

          if( status != MRD_STATUS_SUCCESS )
             printf("Position to Element failed: %s: %s.\n", robot,
                mrd_strstatus(status)) ;
       }

       (void)mrd_shutdown(&robot_info) ;

       return 0 ;
    }

17.5  –  Return Values

    Upon successful completion, mrd_position_to_element(3mrd) will
    return MRD_STATUS_SUCCESS. On a failure, an MRD_STATUS value
    corresponding to the error will be returned. Common errors are:

17.5.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_info or dev_status arguments
    are NULL pointers.

17.5.2  –  MRD_STATUS_ROBOT_ILLEGAL_REQUEST

    This error occurs when the medium changer does not support the
    Position To Element command. The seven and five slot DLT loaders
    do not support the command, though the TL820 and TL810 family
    libraries do. Some models of TLZ6L and TLZ7L do not support the
    command and may take a long time to fail.

    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).

17.5.3  –  MRD_STATUS_ELEMENT_INVALID

    This error occurs when a SCSI command fails with the ASC set to
    0x21. The log_info will contain the ASCQ. This indicates that an
    invalid element address reached the medium-changer. For example,
    specifying the 13th slot when only 12 slots are present.

17.5.4  –  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).

17.6  –  Related Functions

    Functions:

    mrd_position(3mrd)

18  –  mrd_prevent_allow

    mrd_prevent_allow - Send a Prevent/Allow Media Removal command

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_prevent_allow(
        robot_info_t *robot_info,
        int           lock,
        dev_status_t *dev_status) ;

18.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  lock The lock argument indicates whether media removal should
       be prevented or allowed.

    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.

18.2  –  Description

    This routine performs a SCSI Prevent/Allow Media Removal. It is
    used by mrd_lock(3mrd). The robot_info argument is the address of
    a robot_info_t that has been opened by mrd_startup(3mrd).

    When a lock value of one (1) is specified media removal is
    prevented. When the value zero (0) is used, media removal is
    allowed. If other values for lock are used, the routine will
    create a status which corresponds to an illegal request.

    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.

18.3  –  Example

    /*
     *   This is an example of using mrd_prevent_allow(3mrd) to
     *   prevent or allow media removal, where allowed.  For
     *   robot name on the command line, the desired version
     *   of the command will be used according lock value.
     *   name.
     *
     *   Usage:
     *
     *      mrd_prevent_allow lock-value robot [ robot... ]
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_prevent_allow.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       int      rc ;      /* Counter */
       int      lock ;      /* Lock value */
       int      status ;   /* return status */
       char      *robot ;   /* Robot to open */
       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 < 3 ) {
          printf("usage: %s lock-value robot [ robot... ]\n", argv[0]) ;
          exit(1) ;
       }
       else
          lock  = atoi(argv[1]) ;

       /*
        *   Initialize the channel field of the robot_info, so
        *   mrd_startup(3mrd) will actually open the robot.
        */
       robot_info.channel = BAD_CHANNEL ;

       for(rc = 2; rc < argc; rc++) {
          /*
           *   The robot for this command.
           */
          robot = argv[rc] ;

          status = mrd_startup(robot, &robot_info, log_info) ;

          if( status != MRD_STATUS_SUCCESS ) {
             printf("Startup failed on %s: %s.\n", robot,
                mrd_strstatus(status)) ;

             continue ;
          }

          printf("Lock value %d on %s.\n", lock, robot) ;

          status = mrd_prevent_allow(&robot_info, lock, &dev_status) ;

          if( status != MRD_STATUS_SUCCESS )
             printf("Prevent/Allow failed on %s: %s.\n", robot,
                mrd_strstatus(status)) ;

          (void)mrd_shutdown(&robot_info) ;
       }

       return 0 ;
    }

18.4  –  Return Values

    Upon successful completion, mrd_prevent_allow(3mrd) will return
    MRD_STATUS_SUCCESS. On a failure, one of the following status
    values will be returned.

18.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_info or dev_status arguments
    are NULL pointers.

18.4.2  –  MRD_STATUS_ROBOT_ILLEGAL_REQUEST

    This error occurs when the medium changer does not support the
    Prevent/Allow Medium Removal command or the lock value is not one
    or zero. The specific cause can be determined by examining the
    ASC/ASCQ values in the status data.

    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).

18.4.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).

18.5  –  Related Functions

    Functions:

    mrd_lock(3mrd)

19  –  mrd_ready

    mrd_ready - Send a Ready Inport command

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_ready(
        robot_info_t *robot_info,
        int           port,
        dev_status_t *dev_status) ;

19.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  port  - The absolute integer element address of the port which
       is to be used as the destination of the move.

    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.

19.2  –  Description

    It is used by mrd_ready_inport(3mrd). This command is used by
    the TL820 family of DLT libraries to enable the button on the I/O
    device (IOD) which opens the Inport door.

    The robot_info argument is the address of a robot_info_t that has
    been opened by mrd_startup(3mrd).

    The port argument is the absolute address of the port to be
    readied. On supported TL820 configurations which use a left
    mounted IOD this will always be 64.

    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.

19.3  –  Example

    /*
     *   This is an example of using mrd_move_medium directly to move
     *   a cartridge from one slot to another.  To simplify the
     *   example, it only supports slot to slot moves, but it shows
     *   how the absolute element addresses are calcuated.  For each
     *   additional destination address given, the previous (successful)
     *   destination address is used as the source.
     *
     *   Usage:
     *
     *      mrd_ready robot port [ port... ]
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_ready.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       int      pc ;      /* counter */
       int      port ;      /* Port number */
       int      address ;   /* Port address */
       int      status ;   /* return status */
       char      *robot ;   /* Robot to open */
       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 < 3 ) {
          printf("usage: %s robot port [ port... ]\n", argv[0]) ;
          exit(1) ;
       }
       else
          robot  = argv[1] ;

       /*
        *   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 on %s: %s.\n", robot,
             mrd_strstatus(status)) ;

          exit(1) ;
       }

       /*
        *   For each destination address on the command line,
        *   move the the cartridge in the source to the
        *   destination.  After each (successful) move, replace
        *   the previous source with this destination.
        */
       for(pc = 2; pc < argc; pc++) {
          /*
           *   Get the port number.
           */
          port = atoi(argv[pc]) ;

          /*
           *   Now the absolute address.
           */
          address = port + robot_info.port_start ;

          /*
           *   Print an audit as we go.  Since we know these
           *   are slots, convert back to relative addresses
           *   for the audit.
           */
          printf("Ready Inport #%d of %s\n", port, robot) ;

          status = mrd_ready(&robot_info, address, &dev_status) ;

          if( status != MRD_STATUS_SUCCESS ) {
             printf("Ready Inport failed on %s: %s.\n", robot,
                mrd_strstatus(status)) ;

             /*
              *   Since the cartridge didn't move, don't
              *   reset the source, by skipping the remainder
              *   of the loop.
              */
             continue ;
          }
       }

       (void)mrd_shutdown(&robot_info) ;

       return 0 ;
    }

19.4  –  Return Values

    Upon successful completion, mrd_ready(3mrd) will return MRD_
    STATUS_SUCCESS. On a failure, one of the following status values
    will be returned.

19.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_info or dev_status arguments
    are NULL pointers.

19.4.2  –  MRD_STATUS_ROBOT_ILLEGAL_REQUEST

    This error occurs when the medium changer does not support the
    Ready Inport command. The TL820 family of DLT libraries support
    this command. The TL810 family of DLT libraries allows this
    command to succeed, but it doesn't perform any function.

    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).

19.4.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).

19.5  –  Related Functions

    Functions:

    mrd_ready_inport(3mrd)

20  –  mrd_ready_inport

    mrd_ready_inport - Enable access to the Inport of a TL820

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_ready_inport(
        const char *robot_name,
        const char *inport,
        char       *log_info) ;

20.1  –  Parameters

    o  robot_name - The name of the robot device to be opened. On
       Digital UNIX, if the leading character of the name is not a
       slash (/), /dev/ will be prepended to the name.

    o  inport - This is the address of the character string
       containing a zero based address of the port to be readied.

    o  log_info - This is a character array that should be at least
       MRD_MAX_LOG_STRING in length. If this function fails as the
       result of a SCSI error, this will be filled with the formatted
       request sense data. If this function fails as the result
       of an operating system error, the operating system message
       particular to the error will be copied into the array.

20.2  –  Description

    The TL820 family of libraries uses an Input/Output Device (IOD)
    to allow putting tapes into the library and taking them out. The
    inport part of the IOD holds a single cartridge and has a door on
    top which must be opened before a cartridge can be placed in it.
    A button on the front of the IOD opens the door, but only after
    it has been enabled by a Ready IOD command. This is a vendor
    unique command specific to the TL820 family.

    The mrd_ready_inport(3mrd) routine allows sending a Ready IOD
    command to the robot and port specified by the robot_name
    and inport arguments. For all currently shipping TL820 family
    libraries there is only one Inport, so the inport argument can
    always be "0". On a TL820, when the source for a move in the
    Inport, this routine should be called first and time allowed
    for the operator to place a tape in the inport. The routine mrd_
    move(3mrd) expects the element to be full when it starts.

20.3  –  Example

    /*
     *   Send a Ready Inport command to the robot.  This is specific
     *   the TL82X family and causes the Inport door to be enabled
     *   for one minute (the period the light is on).  A future
     *   version of firmware may allow enableing the button to be
     *   on all the time, making this command obsolete.  The command
     *   usage is:
     *
     *      mrd_ready_inport robot
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_ready_inport.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       int      status ;   /* status from mrd_ready_inport(3mrd) */
       char      *robot ;   /* Robot for command */
       char      log_info[MRD_MAX_LOG_STRING+1] ;   /* error text */

       /*
        *   Only one argument; the robot name.
        */
       if( argc == 1 ) {
          printf("usage: %s robot\n", argv[0]) ;
          exit(1) ;
       }
       else
          robot = argv[1] ;

       /*
        *   While the interface of Ready Inport allows the specification
        *   of any port address, the Inport of the TL820 is always "0",
        *   and this command is very robot specific.
        */
       status = mrd_ready_inport(robot, "0", log_info) ;

       if( status != MRD_STATUS_SUCCESS )
          printf("Ready Inport failed: %s: %s.\n", mrd_strstatus(status),
             log_info[0] ? log_info : "none") ;

       return 0 ;
    }

20.4  –  Return Values

    Upon successful completion, the mrd_ready_inport(3mrd) function
    returns the value MRD_STATUS_SUCCESS. If mrd_ready_inport(3mrd)
    fails the returned status value may be set to one of the
    following values. Other values that correspond to specific SCSI
    errors may also be possible, but these are the most likely.

20.4.1  –  MRD_STATUS_PARAM

    This error is returned if the any of the arguments are NULL
    pointers.

20.4.2  –  MRD_STATUS_PORT_INVALID

    This error is returned when the element address for a port is
    less than zero or greater than the number of ports.

20.4.3  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

20.5  –  Related Functions

    Functions:

    o  mrd_move(3mrd)

    o  mrd_load(3mrd)

    o  mrd_unload(3mrd)

    o  mrd_inject(3mrd)

    o  mrd_eject(3mrd)

21  –  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) ;

21.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.

21.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.

21.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:

21.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 ;
    }

21.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.

21.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.

21.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).

21.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).

21.6  –  Related Functions

    Functions:

    mrd_show(3mrd)

22  –  mrd_request_sense

    mrd_request_sense - Get the status of a medium changer.

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_request_sense(
        robot_info_t *robot_info,
        dev_status_t *dev_status,
        int           os_status);

22.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  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.

    o  os_status - When mrd_request_sense(3mrd) is used directly
       by an application, this argument should be MRD_CHECK_SENSE,
       or the operating system specific error code that indicates a
       device failure. On Digital UNIX this is EIO.

22.2  –  Description

    This routine performs a SCSI Request Sense command, or equivalent
    if some other I/O architecture is supported. It is used by all
    MRD API routines to determine the cause of a command failure.

    The robot_info is the address of a robot_info_t structure that
    has been opened by mrd_startup(3mrd). If the medium changer isn't
    opened, the Request Sense command will fail with the operating
    system error for trying to use an unopened device.

    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.

    In typical usage by MRD, the os_status argument will be an
    operating system specific code. However, The SCSI-2 specification
    allows Request Sense to be used at any time to obtain status
    information about a device. To support this feature, the MRD
    implementation of mrd_reqeust_sense(3mrd) can be called with the
    code MRD_CHECK_SENSE to force a Request Sense command.

22.3  –  Example

    /*
     *   This is an example of using mrd_request_sense(3mrd)
     *   to see what state a medium changer is in.  The MRD
     *   implementation of Request Sense only collects the
     *   Sense Key, Additional Sense Code and Additional Sense
     *   Code Qualifier.
     *
     *   Usage:
     *
     *      mrd_request_sense robot [ more-robots... ]
     */
    #ifndef   lint
    static  char  SccsId[] = "@(#)mrd_request_sense.c   1.1 4/16/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    char   *device_sense = "Sense data for %s: %s (%d,0x%x,0x%x).\n" ;
    char   *sense_failed = "Request Sense failed on %s: %s.\n" ;

    main(int argc, char *argv[])
    {
       int      rc ;      /* counter */
       int      status ;   /* return status */
       char      *robot ;   /* Robot to open */
       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 < 2 ) {
          printf("usage: %s robot [ robot... ]\n", argv[0]) ;
          exit(1) ;
       }

       /*
        *   Initialize the channel field of the robot_info, so
        *   mrd_startup(3mrd) will actually open the robot.
        */
       robot_info.channel = BAD_CHANNEL ;

       for(rc = 1; rc < argc; rc++) {
          /*
           *   The robot for this command.
           */
          robot = argv[rc] ;

          status = mrd_startup(robot, &robot_info, log_info) ;

          if( status != MRD_STATUS_SUCCESS ) {
             printf("Startup failed on %s: %s.\n", robot,
                mrd_strstatus(status)) ;

             continue ;
          }

          memset((void *)&dev_status, 0, sizeof(dev_status)) ;

          /*
           *   mrd_request_sense(3mrd) will never return
           *   MRD_STATUS_SUCCESS.  If no Request Sense data
           *   is available, it will return MRD_STATUS_NO_SENSE.
           */
          status = mrd_request_sense(&robot_info, &dev_status,
                MRD_CHECK_SENSE) ;

          /*
           *   Print the Key/ASC/ASCQ data for device errors.
           */
          if( dev_status.valid )
             printf(device_sense, robot, mrd_strstatus(status),
                dev_status.key, dev_status.asc,
                dev_status.ascq) ;
          /*
           *   Just print the MRD error.
           */
          else
             printf(sense_failed, robot, mrd_strstatus(status)) ;

          (void)mrd_shutdown(&robot_info) ;
       }

       return 0 ;
    }

22.4  –  Return Values

    The routine mrd_request_sense(3mrd) never returns MRD_STATUS_
    SUCCESS. If the os_status isn't the operating system specific
    code that forces a Reqeust Sense command or MRD_CHECK_SENSE,
    mrd_map_os_error(3mrd), is used to map the os_status to an
    MRD status code. Otherwise, a Request Sense (or equivalent) is
    performed and the result mapped to an MRD status code with mrd_
    scsi_decode(3mrd).

22.4.1  –  MRD_STATUS_PARAM

    This error is returned when a pointer argument passed to an MRD
    routine is NULL, unless the routine is documented as one allowing
    a NULL pointer.

22.4.2  –  MRD_STATUS_NO_SENSE

    This error is returned by mrd_scsi_decode(3mrd) when the asc,
    ascq and key values are all zero (0). It is also returned when
    the key value is less than zero or greater than 15.

22.4.3  –  MRD_STATUS_RECOVERED_ERROR

    This error occurs when a SCSI device returns only a sense key
    of 1h. This indicates that although a command successfully
    completed, the target device had performed some internal error
    recovery.

22.4.4  –  MRD_STATUS_MEDIUM_ERROR

    This error occurs when ASC and ASCQ are zero, but the sense key
    is 3h. This occurs when the target encounters a nonrecoverable
    error due to a flaw in the medium.

22.4.5  –  MRD_STATUS_ROBOT_HW_ERROR

    This error occurs when ASC and ASCQ are zero, but the sense key
    is 4h. This occurs when the target encounters a nonrecoverable
    hardware error.

22.4.6  –  MRD_STATUS_ROBOT_ILLEGAL_REQUEST

    This error occurs for a variety of reasons.

    It is used when a sanity check fails in the code that attempts
    to move a cartridge to the Pass-Through Mechanism, when the robot
    type isn't a TL82n.

    It is used in the mrd_lock(3mrd) code when the value is not one
    of ALLOW_REMOVAL or PREVENT_REMOVAL.

    It is used when the medium changer does not support the Prevent
    /Allow Medium Removal command or the lock value is not one or
    zero. The specific cause can be determined by examining the ASC
    /ASCQ values in the status data.

    It is used when a call to mrd_initialize_element(3mrd) is issued
    against a medium changer that does not support the Initialize
    Element Status command.

    It is used when the medium changer does not support the Position
    To Element command. The seven and five slot DLT loaders do not
    support the command, though the TL820 and TL810 family libraries
    do. Some models of TLZ6L and TLZ7L do not support the command and
    may take a long time to fail.

    It is used when the medium changer does not support the Ready
    Inport command. The TL820 family of DLT libraries support this
    command. The TL810 family of DLT libraries allows this command to
    succeed, but it doesn't perform any function.

    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).

22.4.7  –  MRD_STATUS_ROBOT_ATTENTION

    This error occurs when a SCSI command fails with the ASC set to
    one of 0x29, 0x2A or 0x2F. The log_info contains the ASCQ. The
    SCSI translations for these error codes are:

    o  0x29 - Power-on, Reset or Bus device reset occurred

    o  0x2A - Mode Parameters Changed

    o  0x2F - Command cleared by another initiator

    This error also occurs when the ASC and ASCQ are zero, but the
    SCSI sense key is 6h.

22.4.8  –  MRD_STATUS_DATA_PROTECT

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is seven (7).

22.4.9  –  MRD_STATUS_BLANK_CHECK

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is eight (8).

22.4.10  –  MRD_STATUS_VENDOR_UNIQUE_ERROR

    This error occurs when the internal routine used to decode SCSI-
    2 errors encounters an error that it has not been written to
    antipicate.

    This error also returned when the ASC is zero and the ASCQ is not
    one of zero or six, and when ASC/ASCQ are both zero and the key
    is 9h.

22.4.11  –  MRD_STATUS_COPY_ABORTED

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero,

22.4.12  –  MRD_STATUS_SENSE_EQUAL

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is Ch (12).

22.4.13  –  MRD_STATUS_VOLUME_OVERFLOW

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is Dh (13).

22.4.14  –  MRD_STATUS_MISCOMPARE

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is Eh (14).

22.4.15  –  MRD_STATUS_SENSE_RESERVED

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is Fh (15).

22.4.16  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error also occurs as the result of a SCSI command failure,
    when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

22.4.17  –  MRD_STATUS_ROBOT_MECH_ERROR

    This error occurs as the result of a SCSI command failure, when
    the ASC is set to one of:

    o  0x15 - Positioning error.

    o  0x8B - Vendor unique; Pass-through mechanism errors on the
       TL82n

22.4.18  –  MRD_STATUS_AUTOCLEAN

    This error occurs when a SCSI command fails with the ASC set
    to 0x30 and the ASCQ set to 0x3. On TL8nn libraries supporting
    Auto-clean, it indicates that a command was attempted while an
    auto-clean was in progress.

22.4.19  –  MRD_STATUS_CART_DAMAGED

    This error occurs when a SCSI command fails with the ASC set
    to 0x30, but the ASCQ is NOT a value of 0x3. The log_info will
    contain the ASCQ.

22.4.20  –  MRD_STATUS_ELEMENT_INVALID

    This error occurs when a SCSI command fails with the ASC set to
    0x21. The log_info will contain the ASCQ. This indicates that an
    invalid element address reached the medium-changer. For example,
    specifying the 13th slot when only 12 slots are present.

22.4.21  –  MRD_STATUS_CART_NOT_AVAIL

    This error can occur on the TL81n and TL82n family of DLT
    libraries when the source of a move is a drive and the cartridge
    in the drive is still on-line. These robots do not allow moving
    the cartridge until the drive is taken offline.

22.4.22  –  MRD_STATUS_DESTINATION_FULL

    On routines that perform a SCSI Move Medium command, this error
    indicates that the destination element already has a cartridge in
    it.

22.4.23  –  MRD_STATUS_SOURCE_EMPTY

    On routines that perform a SCSI Move Medium command, this error
    indicates that the source element is empty.

22.4.24  –  MRD_STATUS_ROBOT_DOOR_OPENED

    This occurs when a SCSI command fails with the ASC set to 0x80
    and the ASCQ set to 0x0. On TL8nn libraries this typically
    indicates that the cabinet door was opened during a command
    operation.

22.4.25  –  MRD_STATUS_DEVICE_INVALID

    This error code is used when an OpenVMS system service fails with
    the status SS$_NOSUCHDEV or SS$_IVDEVNAM. This will typically
    occur in mrd_startup(3mrd) when the caller tries to open a device
    which doesn't exist or uses an invalid device name.

    This error also occurs when the routine is called on behalf of
    a device controlled by the JU driver. The Media Robot Utility no
    longer uses the JU driver.

22.4.26  –  MRD_STATUS_ROBOT_NOT_READY

    Under OpenVMS and Digital UNIX, this error occurs as the result
    of a SCSI command failure, when the ASC is set to one of:

    o  0x80 - When the ASCQ is not zero (0).

    o  0x81 - Vendor unique; gripper errors on the TL82X and TL81X

    o  0x04 - Logical unit not ready

    o  0x3E - Logical unit has not been self configured

    o  0x40 - Diagnostic failure; ASCQ indicates component

    o  0x42 - Power-on self test failure

    o  0x44 - Internal target failure

    o  0x46 - Unsuccessful soft reset

    o  0x4C - Logical unit failed self-configuration

    This status is also returned when the ASC and ASCQ are zero, but
    the key is two (2).

22.4.27  –  MRD_STATUS_ROBOT_CMD_ABORTED

    This error code is used when an OpenVMS system service fails with
    the status SS$_ABORT.

22.5  –  Related Functions

    Functions:

    o  mrd_move(3mrd)

    o  mrd_load(3mrd)

    o  mrd_unload(3mrd)

    o  mrd_inject(3mrd)

    o  mrd_eject(3mrd)

    o  mrd_show(3mrd)

    o  mrd_ready_inport(3mrd)

    o  mrd_position(3mrd)

    o  mrd_initialize(3mrd)

    o  mrd_home(3mrd)

    o  mrd_find_cartridge(3mrd)

    o  mrd_startup(3mrd)

    o  mrd_shutdown(3mrd)

    o  mrd_lock(3mrd)

23  –  mrd_show

    mrd_show - Obtain information from a media robot

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_show(
        const char     *robot_name,
        robot_info_t   *robot_info,
        int             element_type,
        const char     *element_name,
        int             element_count,
        element_info_t *element_info,
        char           *log_info) ;

23.1  –  Parameters

    o  robot_name - The name of the robot device to be opened. On
       Digital UNIX, if the leading character of the name is not a
       slash (/), /dev/ will be prepended to the name.

    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  element_type - The type of robot element on which the
       operation takes place. If an element type of zero (0) is used,
       all elements will be searched starting at element 0 of each
       type and searching all the elements of that type on the robot.
       The order of this search is Slot, Drive, Transport and finally
       Ports.

    o  element_name - A string used to specify the name of the first
       element about which to obtain information. While SCSI devices
       use integer numbers for element addresses, DSA robots use
       character strings. This allows the same interface to be used
       for both types, where supported.

    o  element_count - A volume tag search in a large library
       can take a long time. Some applications (a graphic user
       interface for example) may want to break up a large search
       into smaller, quicker sub-searches. When a specific element_
       type is specified only a range specified by the element_name
       and element_count will be searched. This argument is ignored
       when the element_type is zero (0).

    o  element_info - The array of element_info_t structures that is
       filled in with information on the type and number of elements
       requested with element_type and element_count. The information
       includes volume tag (if available), state, port type (if PORT
       information is requested), status, and when available a copy
       of the Read Element Status data for the element.

    o  log_info - This is a character array that should be at least
       MRD_MAX_LOG_STRING in length. If this function fails as the
       result of a SCSI error, this will be filled with the formatted
       request sense data. If this function fails as the result
       of an operating system error, the operating system message
       particular to the error will be copied into the array.

23.2  –  Description

    The mrd_show(3mrd) function can be used to obtain information
    about specific element types of a supported Medium-Changer.
    Medium-Changer element types that mrd_show(3mrd) can retrieve
    information about include PORT, DRIVE, SLOT and TRANSPORT. If
    a element_type of ROBOT is specified, the mrd_show(3mrd) is
    equivalent to calling mrd_startup(3mrd) - that is, robot_info
    is filled in.

    The robot_info_t data structure is described in mrd_
    startup(3mrd).

    The element_name parameter specifies the first element of the
    type element_type about which to obtain information. The element_
    count parameter specifies the number of elements of type element_
    type about which information is to be obtained.

23.2.1  –  Element Info

    The element_info_t data structure is defined in the include file
    <mrd_common.h>. The fields of this data structure are described
    below:

    o  name - The name field holds the volume tag of the media if
       applicable.

    o  state - The state field can have one of the following values:

          ELEMENT_FULL,
          ELELMENT_EMPTY, or
          ELEMENT_EXCEPT.

    o  port_type - If the element_type parameter specifies PORT, the
       port_type field will have one of the following values:

          IN_OUT_PORT,
          INPORT,
          OUTPORT.

    o  status - The status field can have one of the following
       values:

          MRD_STATUS_SLOT_INVALID,
          MRD_STATUS_DEVICE_INVALID,
          MRD_STATUS_TRANSPORT_INVALID,
          MRD_STATUS_PORT_INVALID, or
          MRD_STATUS_SUCCESS.

    o  flags - Use the ELEMENT_VALID mask on the flags field to
       indicate whether or not the full Read Element Status data
       is valid. The ELEMENT_PVOLTAG and ELEMENT_AVOLTAG indicate
       whether the primary or alternate volume tags of the Read
       Element Status data are valid.

    o  element_addr - This is the address of the element, unadjusted
       for the starting address. The routine mrd_map_element(3mrd)
       can be used to convert an absolute element address to a
       relative address and type. This field will be set to -1 when
       the information is not valid.

    o  source_addr - On most SCSI-2 medium-changers, this is the
       address where a cartridge resided before being moved to its
       current location. The routine mrd_map_element(3mrd) can be
       used to convert an absolute element address to a relative
       address and type. This field will be set to -1 when the
       information is not valid. On some SCSI-2 medium-changers (the
       DLT family loaders) this will be the element address of the
       slot itself.

    o  data - This a copy of the SCSI-2 Read Element Status data
       when the ELEMENT_VALID bit is set in the flags field. A byte-
       order neutral declaration of this data structure is included
       in the <mrd_common.h> include file as the mrd_reades_t data
       structure.

23.3  –  Example

    /*
     *   Example to do mrd_show(3mrd) on the first element of each type.
     *   The usage of this command is:
     *
     *      mrd_show robot
     *
     *   This examples show keeping the robot open across multiple
     *   calls to mrd_show(3mrd).  In one happens to close it, the
     *   channel will be reset the BAD_CHANNEL and the next one will
     *   open it again.  On some robot subsystems, opening the robot
     *   is fairly time consuming and if multiple "shows" are needed
     *   the time savings can be signficiant.
     *
     *   The subsystems where this is most noticable are HSJ and HSD
     *   connected robots, which aren't supported on Digital UNIX.
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_show.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       robot_info_t   robot_info ;   /* keep the robot open */
       element_info_t   element ;   /* place to put element data */
       int      el ;      /* type index */
       int      status ;   /* status from mrd_show(3mrd) */
       char      *robot ;   /* Robot to use */
       char      *content ;   /* pointer to a content string */
       char      log_info[MRD_MAX_LOG_STRING+1] ;   /* error text */

       /*
        *   Only one argument is used; the robot name.
        */
       if( argc == 1 ) {
          printf("usage: %s robot\n", argv[0]) ;
          exit(1) ;
       }
       else
          robot = argv[1] ;

       /*
        *   The channel number must be set to BAD_CHANNEL before
        *   mrd_startup or mrd_show is called, otherwise it will
        *   assume the robot is already open and not try to open
        *   it again.
        */
       robot_info.channel = BAD_CHANNEL ;

       /*
        *   In this case we want to open the robot once, and then
        *   call mrd_show(3mrd) in turn for each type of element.
        *   If there is an error and it happens to close the robot,
        *   the channel will be reset and the robot opened again on
        *   the next call.
        */
       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) ;
       }

       /*
        *   We rely on the fact that the element numbers are
        *   are 1 through 4.
        */
       for(el = 1; el <= 4; el++) {
          log_info[0] = '\0' ;

          status = mrd_show(robot, &robot_info, el, "0", 1,
                &element, log_info) ;

          if( status != MRD_STATUS_SUCCESS ) {
             printf("Can't show %s 0: %s (%s)\n",
                mrd_strelement(el), mrd_strstatus(status),
                log_info[0] ? log_info : "none") ;

             continue ;
          }

          if( element.status != MRD_STATUS_SUCCESS ) {
             printf("Can't show %s 0: %s\n", mrd_strelement(el),
                mrd_strstatus(element.status)) ;

             continue ;
          }

          if( element.name[0] )
             content = element.name ;
          else if( element.state & ELEMENT_FULL )
             content = "Full" ;
          else if( element.state & ELEMENT_EXCEPT )
             content = "Exception" ;
          else
             content = "Empty" ;

          printf("%-9s 0: %s\n", mrd_strelement(el), content) ;
       }

       /*
        *   Close it when done.
        */
       (void)mrd_shutdown(&robot_info) ;

       return 0 ;
    }

23.4  –  Return Values

    Upon successful completion, the mrd_show(3mrd) function returns
    the value MRD_STATUS_SUCCESS. If mrd_show(3mrd) fails, the
    returned status value will be set to one of the following values.
    Other values that correspond to specific SCSI errors may also be
    possible, but these are the most likely.

23.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_name, log_info, element_name,
    element_info, or robot_info arguments are NULL pointers.

23.4.2  –  MRD_STATUS_RES_FAILED

    The SCSI command Read Element Status failed.

23.4.3  –  MRD_STATUS_ROBOT_ILLEGAL_REQUEST

    This is error is returned when the element_type is not one of
    SLOT, PORT, DRIVE or TRANSPORT. This last case should return MRD_
    STATUS_INVALID_TYPE instead. 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).

23.4.4  –  MRD_STATUS_SLOT_INVALID

    This error is returned when the element address for a slot is
    less than zero or greater than the number of slots.

23.4.5  –  MRD_STATUS_TRANSPORT_INVALID

    This error is returned when the element address for a transport
    is less than zero or greater than the number of transports.

23.4.6  –  MRD_STATUS_NO_ELEMENTS

    This error occurs in mrd_show(3mrd), mrd_find_cartridge(3mrd) and
    mrd_home(3mrd) when the medium-changer has no elements within the
    range and type specified by the arguments.

23.4.7  –  MRD_STATUS_PORT_INVALID

    This error is returned when the element address for a port is
    less than zero or greater than the number of ports.

23.4.8  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

23.4.9  –  MRD_STATUS_ROBOT_NOT_READY

    Under OpenVMS and Digital UNIX, this error occurs as the result
    of a SCSI command failure, when the ASC is set to one of:

    o  0x80 - When the ASCQ is not zero (0).

    o  0x81 - Vendor unique; gripper errors on the TL82X and TL81X

    o  0x04 - Logical unit not ready

    o  0x3E - Logical unit has not been self configured

    o  0x40 - Diagnostic failure; ASCQ indicates component

    o  0x42 - Power-on self test failure

    o  0x44 - Internal target failure

    o  0x46 - Unsuccessful soft reset

    o  0x4C - Logical unit failed self-configuration

    This status is also returned when the ASC and ASCQ are zero, but
    the key is two (2).

23.4.10  –  MRD_STATUS_DEVICE_INVALID

    This error code is used when an OpenVMS system service fails with
    the status SS$_NOSUCHDEV or SS$_IVDEVNAM. This will typically
    occur in mrd_startup(3mrd) when the caller tries to open a device
    which doesn't exist or uses an invalid device name.

    This error also occurs when the routine is called on behalf of
    a device controlled by the JU driver. The Media Robot Utility no
    longer uses the JU driver.

23.4.11  –  MRD_STATUS_INSFMEM

    The mrd_show(3mrd) and mrd_find_cartridge(3mrd) functions
    allocate virtual memory using malloc(3) to store temporary
    element data. If the attempt to allocate the memory fails, these
    routines will return this error.

23.5  –  Related Functions

    Functions:

    o  mrd_shutdown(3mrd)

    o  mrd_startup(3mrd)

    o  mrd_map_element(3mrd)

24  –  mrd_startup

    mrd_startup - Open a medium-changer robot

    mrd_shutdown - Close a medium-changer robot

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_startup(
        const char   *robot_name,
        robot_info_t *robot_info,
        char         *log_info) ;

    void mrd_shutdown(
        robot_info_t *robot_info) ;

24.1  –  Parameters

    o  robot_name - The name of the robot device to be opened. On
       Digital UNIX, if the leading character of the name is not a
       slash (/), /dev/ will be prepended to the name.

    o  robot_info - This is the address of the robot_info_t structure
       when mrd_startup is called. 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  log_info - This is a character array that should be at least
       MRD_MAX_LOG_STRING in length. If this function fails as the
       result of a SCSI error, this will be filled with the formatted
       request sense data. If this function fails as the result
       of an operating system error, the operating system message
       particular to the error will be copied into the array.

24.2  –  Description

    The mrd_startup(3mrd) function can be used to obtain information
    about a supported Medium-Changer. Because the startup time on
    some robots (HSJ connected SCSI robots) can be relatively long,
    this routine can also be used to hold open the robot while mrd_
    show(3mrd) routines are used to collect information about the
    different robot elements.

    The mrd_shutdown(3mrd) routine should be used to close a robot
    before other MRD routines are called. With the exception of
    mrd_show(3mrd) the MRD common routines call mrd_startup(3mrd)
    themselves and can't make use of robot_info_t filled in by mrd_
    startup(3mrd).

    Robot Information
    The robot_info_t data structure is defined in the include file
    <mrd_common.h>. The fields of this data structure are described
    below:

    o  channel - This is the file descriptor, channel number or other
       operating system specific handle assigned to the process for
       the robot, when mrd_startup(3mrd) is successful. It should
       not be used directly and should only be closed through mrd_
       shutdown(3mrd). When mrd_show(3mrd) is provided a robot_info_t
       where the channel is not BAD_CHANNEL, it will assume the robot
       is open and try to use that handle.

    o  robot_name - This is set to the address of the robot_name
       argument provided to mrd_startup(3mrd).

    o  robot_type - MRD attempts to identify a robot using the SCSI
       inquiry data obtained during the startup. This is a value
       to indicate the family or type of medium-changer. Recognized
       types are:

       DLT_ROBOT          TZ857, TZ867, TZ875, TZ877, TZ885, TZ887
       RDAT_ROBOT         TLZ6L, TLZ7L, TLZ9L
       TL820_ROBOT        TL820, TL822, TL826
       TL810_ROBOT        TL810, TL812
       TL800_ROBOT        TL891
       OVERLAND_ROBOT     TKZ6x
       RW5XX_ROBOT        RW500
       UNKNOWN_ROBOT      A type not recognized

    o  arch_type - This indicates the I/O architecture used to
       communicate with the medium-changer. OpenVMS supports SCSI
       (ARCH_SCSI) and DSA (ARCH_DSA) connected medium-changers. HSJ
       and HSD connected robots are considered SCSI robots. Digital
       UNIX and Windows NT only support SCSI connected robots.

    o  vision_present - This flag indicates that the robot supports
       a vision system that can be used to read volume tags. It is
       set in the start-up and should not be changed. Most SCSI
       robots will reject commands asking for volume tags when the
       medium-changer doesn't support them.

    o  robot_device_type - This field is only used by the OpenVMS
       implementation of MRD to indicate the method the host uses
       to communicate with the medium-changer. This value is used
       internally by the OpenVMS MRD code to select the appropriate
       communcation path.

    o  ptm_addr and ptm_type The TL820 family supports a pass-through
       mechanism (PTM) for moving cartridges from the inport to
       the bar-code reader station or from there to the outport. In
       multi-tower configurations the pass-through moves cartridges
       from one tower to another. The MRD uses the PTM to perform
       bar-code verification. Early versions of the TL820 family
       firmware present the PTM as a Import/Export element, while
       later versions may present it as a Transport. These fields are
       used to indicate the address and type.

    o  maxecnt - The OpenVMS drivers used to communicate with medium-
       changers support a limited I/O size that restricts the amount
       of data that can be transferred by a Read Element Status
       command. This field is used by the OpenVMS implementation
       of MRD to know where large transfers must be broken up by the
       software.

    o  element_desc - In addition to knowing the maximum number of
       elements that may be read in a single Read Element Status
       command, the element descriptor size is also needed to
       correctly break-up command. This field stores the element
       descriptor size on all implementations of the MRD.

    The following fields are filled in from Element Address
    Assignment Page obtained via the SCSI Mode Sense command. When
    the robot is not a SCSI connect device, a suitable lie is filled
    by the operating system specific code supporting that type of
    robot.

    o  slot_count - This is the number of storage elements (slots) in
       the medium-changer. Some robots (TLZ7L) will change the number
       of slots presented depending on the type of magazine used. To
       detect changes in the size of the carrier, mrd_startup(3mrd)
       must be called and field checked for a change of value. When
       no magazine is in the drive, it may report 0 slots.

    o  slot_start - This is the element address of the first storage
       element. It is used by MRD to convert zero-relative element
       addresses to the actual element address used by the medium-
       changer.

    o  device_count - This is the number of data transfer elements
       (drives) in the medium-changer. Like storage elements it may
       be subject to change after a robot has been started.

    o  device_start - This is the element address of the first data
       transfer element. It is used by MRD to convert zero-relative
       element addresses to the actual element address used by the
       medium-changer.

    o  port_count - This is the number of import/export elements
       (ports) in the medium-changer. Like storage elements it may be
       subject to change after a robot has been started.

    o  port_start - This is the element address of the first import
       /export element. It is used by MRD to convert zero-relative
       element addresses to the actual element address used by the
       medium-changer.

    o  transport_count - This is the number of medium transport
       elements (transports) in the medium-changer. Like storage
       elements it may be subject to change after a robot has been
       started.

    o  transport_start - This is the element address of the first
       medium transport element. it is used by MRD to convert zero-
       relative element addresses to the actual element address used
       by the medium-changer.

    o  inport_count and outport_count - MRD V1.2 and earlier attempts
       to identify ports according to whether they are used for
       import-only, export-only or both. This is an artifact from
       the time that the TL820 was the only supported medium- changer
       with ports. Even though the TL810 has four ports these fields
       will report it having four inports and four outports.

    o  inport_start and outport_start - MRD V1.2 and earlier assumes
       that the arrangement of ports in the address space of the
       medium-changer has all the inports together and all the
       outports together. However, the two groups may be separated.
       No guarantee is made whether the addressees of the inports
       come before or after the outports. When the starting address
       of both types of ports the same value, it can be safely
       assumed that all the ports within the particular port count
       are both inport and outport elements.

    The following fields are obtained as the result of a SCSI Inquiry
    Command. When the robot isn't a SCSI connected device, a suitable
    lie is filled in by the operating system specific code supporting
    that type of robot.

    o  scsi_info - These are the first eight (8) bytes of the SCSI
       Inquiry data for the robot. MRD doesn't make use of this
       information, but it is available if the calling application
       wants to use it. These bytes will be zero on non-SCSI devices.

    o  inquiry - This is the VendorID, ProductID and
       ProductRevisionLevel fields of the SCSI Inquiry data. They
       are collected as a single NULL terminated string. The data is
       edited to replace any non-printable character with a space.

    These fields are not currently used:

    o  bus

    o  target

    o  lun

    o  devcap

    o  transport_geometry

24.3  –  Example

    /*
     *   Example of using mrd_startup(3mrd) and mrd_shutdown(3mrd).  This
     *   just opens the robot and prints the element counts and Inquiry
     *   string.  The command usage is:
     *
     *      mrd_startup robot
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_startup.c   1.2 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
       robot_info_t   robot_info ;   /* Place to put robot data */
       int      status ;   /* status from mrd_startup(3mrd) */
       char      *robot ;   /* robot name */
       char      log_info[MRD_MAX_LOG_STRING+1] ;   /* error text */

       /*
        *   Only one required argument; the robot name
        */
       if( argc == 1 ) {
          printf("usage: %s robot\n", argv[0]) ;
          exit(1) ;
       }
       else
          robot = argv[1] ;

       /*
        *   The channel number must be set to BAD_CHANNEL before
        *   mrd_startup is called, otherwise it will assume the
        *   robot is already open and not try to open it again.
        */
       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") ;
       else {
          printf("Inquiry: %s\n", robot_info.inquiry) ;
          printf("   Transports: %d\n",  robot_info.transport_count) ;
          printf("   Slots:      %d\n",  robot_info.slot_count) ;
          printf("   Ports:      %d\n",  robot_info.port_count) ;
          printf("   Drives:     %d\n",  robot_info.device_count) ;
       }

       (void)mrd_shutdown(&robot_info) ;

       return 0 ;
    }

24.4  –  Return Values

    Upon successful completion, the mrd_startup(3mrd) and mrd_
    shutdown(3mrd) functions return the value MRD_STATUS_SUCCESS.
    If the mrd_startup(3mrd) fails the returned status value will be
    set to one of the following values. Other values that correspond
    to specific SCSI errors may also be possible, but these are the
    most likely.

24.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_name, log_info, or robot_info
    arguments are NULL pointers.

24.4.2  –  MRD_STATUS_SCSI_CHECK

    The SCSI Check Condition error should never occur, since it
    indicates that it safe to use a Request Sense command and you are
    likely to get a different error.

24.4.3  –  MRD_STATUS_SCSI_CONDMET

    The SCSI Condition Met status indicates a SCSI command completed
    with the status "Condition Met".

24.4.4  –  MRD_STATUS_SCSI_BUSY

    The SCSI Device is Busy status code indicates a SCSI command
    completed with the status "Busy".  Some TZ87x media changers are
    known to cause this condition.

24.4.5  –  MRD_STATUS_SCSI_INTER

    The SCSI Intermediate Command Completed status code indicates a
    SCSI command completed with the status "Intermediate".

24.4.6  –  MRD_STATUS_SCSI_INTER_CONDMET

    The SCSI Intermediate-Condition Met status code indicates a SCSI
    command completed.

24.4.7  –  MRD_STATUS_SCSI_RESCON

    The SCSI Reservation Conflict status code indicates a SCSI
    command completed with the status "Reservation Conflict".

24.4.8  –  MRD_STATUS_SCSI_TERM

    The SCSI Command Terminated status code indicates a SCSI command
    completed with the status "Terminated".

24.4.9  –  MRD_STATUS_SCSI_QUEUE

    The SCSI Queue Full status code indicates a SCSI command
    completed with the status "Queue Full".

24.4.10  –  MRD_STATUS_SCSI_RESERVED

    The SCSI Status Code Reserved return indicates a SCSI command
    completed with a status that wasn't listed in Chapter 7 of the
    SCSI-2 specification and is "Reserved".

24.4.11  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

24.4.12  –  MRD_STATUS_ROBOT_NOT_READY

    Under OpenVMS and Digital UNIX, this error occurs as the result
    of a SCSI command failure, when the ASC is set to one of:

    o  0x80 - When the ASCQ is not zero (0).

    o  0x81 - Vendor unique; gripper errors on the TL82X and TL81X

    o  0x04 - Logical unit not ready

    o  0x3E - Logical unit has not been self configured

    o  0x40 - Diagnostic failure; ASCQ indicates component

    o  0x42 - Power-on self test failure

    o  0x44 - Internal target failure

    o  0x46 - Unsuccessful soft reset

    o  0x4C - Logical unit failed self-configuration

    This status is also returned when the ASC and ASCQ are zero, but
    the key is two (2).

24.4.13  –  MRD_STATUS_NO_SUCH_DEVICE

    This error is returned when a regular file or robot was specified
    without the ":BnTnLn" string.

24.4.14  –  MRD_STATUS_PAGE_CODE

    This error occurs in mrd_startup(3mrd) when a SCSI Mode Sense
    command fails to return the expected data. It uses the SCSI
    Element Address Assignment mode page to fill in the element count
    and base address fields of the robot_info_t structure. If the
    data returned by the medium changer does not have the expected
    page code, this error is returned. This error has been seen when
    medium changers are connected to HS family array controllers
    running V2.7 firmware.

24.4.15  –  MRD_STATUS_INIT_REQUIRED

    LUN not ready, Initializing command required.
    This is for the ASC/ASC code of 4/2.  It occurs
    when commands are sent to a TL810 family library that has
    auto-inventory on power-up turned off.

24.4.16  –  MRD_STATUS_DIAG_FAILED

    Diagnostic failure, component in ASCQ. This is the
    entire class of error codes with the ASC value set to 0x40.

24.4.17  –  MRD_STATUS_IDE

    Initiator detected error message received. This error
    code occurs when the ASC/ASCQ code is 0x48/0.

24.4.18  –  MRD_STATUS_OPERATOR

    Operator request. This error code occurs when the ASC
    code is 0x5A and the ASCQ code is 0 or 1.

24.4.19  –  MRD_STATUS_LOG_ERROR

    Device log error.  This error code occurs when the ASC
    code is 0x5B and the ASCQ code is 0, 1, 2 or 3.

24.4.20  –  MRD_STATUS_ELOG_OVERFLOW

    Error log overflow. This error code occurs when the ASC
    code is 0xA and the ASCQ code is 0.

24.4.21  –  MRD_STATUS_SYNC_XFER_ERROR

    Synchronous data transfer error. This error code occurs
    when the ASC code is 0x1B and the ASCQ code is 0.

24.5  –  Related Functions

    Functions:

    o  mrd_move(3mrd)

    o  mrd_load(3mrd)

    o  mrd_unload(3mrd)

    o  mrd_inject(3mrd)

    o  mrd_eject(3mrd)

    o  mrd_show(3mrd)

    o  mrd_ready(3mrd)

    o  mrd_position(3mrd)

    o  mrd_initialize(3mrd)

    o  mrd_home(3mrd)

    o  mrd_find_cartridge(3mrd)

    o  mrd_error_decode(3mrd)

    o  mrd_strstatus(3mrd)

    o  mrd_map_element(3mrd)

    o  mrd_lock(3mrd)

    o  mrd_unlock(3mrd)

25  –  mrd_test_unit_ready

    mrd_test_unit_ready - Verify a medium changer is ready to accept
    commands

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_test_unit_ready(
        robot_info_t *robot_info,
        dev_status_t *dev_status);

25.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  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.

25.2  –  Description

    This routine performs a SCSI Test Unit Ready command, or
    equivalent if some other I/O architecture is supported. It is
    used by the mrd_startup(3mrd) and the OpenVMS implementation
    of mrd_ready(3mrd). Since it accepts a robot_info_t structure
    associated with an open medium changer it can used to perform
    Test Unit Ready command without having to re-open the medium
    changer each time.

    The robot_info_t is the address of a robot_info_t that has been
    opened by mrd_startup(3mrd). If the medium changer isn't opened,
    the Test Unit Ready Command will fail with the operating system
    error for trying to use an unopened device.

    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.

25.3  –  Example

    /*
     *   This is an example of using mrd_test_unit_ready(3mrd)
     *   to see if a media changer will accept commands.   On
     *   Digital UNIX this particular example will always
     *   succeed whether the robot is ready or not.  See the
     *   Restrictions section of the manual page for more
     *   information.
     *
     *   Usage:
     *
     *      mrd_test_unit_ready robot [ more-robots... ]
     */
    #ifndef   lint
    static char SccsId[] = "@(#)mrd_test_unit_ready.c   1.1 4/16/97" ;
    #endif

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <mrd_common.h>
    #include <mrd_message.h>

    /*
     *   Message string.
     */
    char *tur_failed_dev =
                 "Test unit ready failed on %s: %s (%d,0x%x,0x%x).\n ";
    char *tur_failed_os  = "Test unit ready failed on %s: %s (%d).\n" ;
    char *tur_failed     = "Test unit ready failed on %s: %s.\n" ;

    /*
     *   The MRD can report three types of errors:
     *
     *   o  Device errors - When the "valid" field is set, at least one
     *      of the key, asc and ascq field should have values set from
     *      a SCSI Request Sense data or equivalent.
     *
     *   o  Operating System errors - When the valid field is zero, but
     *      the os_status field is set.  Where possible an MRD error
     *      will be set if one corresponds to the error.  If not, the
     *      MRD status will be MRD_STATUS_OS_ERROR.  The os_status
     *      is the error specific to the operating system.  On Digital
     *      UNIX it is an errno value.  On OpenVMS it is a system
     *      service return value.
     *
     *   o  MRD Errors - The MRD error code is set explicitly.
     */
    print_error(char *robot, int mrd_status, dev_status_t *dp)
    {
       /*
        *   Print the Key/ASC/ASCQ data for device errors.
        */
       if( dp->valid )
          printf(tur_failed_dev, robot, mrd_strstatus(mrd_status),
             dp->key, dp->asc, dp->ascq) ;
       /*
        *   Try to decode the os_status according to the operating
        *   system type.
        */
       else if( dp->os_status == MRD_STATUS_OS_ERROR )
          printf(tur_failed_os, robot, mrd_strstatus(mrd_status),
    #ifdef   unix
             strerror(dp->os_status)) ;
    #endif
    #ifdef   vms
             strerror(EVMSERR, dp->os_status)) ;
    #endif
       /*
        *   Just print the message on others.
        */
       else
          printf(tur_failed, robot, mrd_strstatus(mrd_status)) ;
    }

    main(int argc, char *argv[])
    {
       int      rc ;      /* counter */
       int      status ;   /* return status */
       char      *robot ;   /* Robot to open */
       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 < 2 ) {
          printf("usage: %s robot [ robot... ]\n", argv[0]) ;
          exit(1) ;
       }

       /*
        *   Initialize the channel field of the robot_info, so
        *   mrd_startup(3mrd) will actually open the robot.
        */
       robot_info.channel = BAD_CHANNEL ;

       for(rc = 1; rc < argc; rc++) {
          /*
           *   The robot for this command.
           */
          robot = argv[rc] ;

          status = mrd_startup(robot, &robot_info, log_info) ;

          if( status != MRD_STATUS_SUCCESS ) {
             printf("Startup failed on %s: %s.\n", robot,
                mrd_strstatus(status)) ;

             continue ;
          }

          memset((void *)&dev_status, 0, sizeof(dev_status)) ;

          status = mrd_test_unit_ready(&robot_info, &dev_status) ;

          /*
           *   Do some fancy error printing.
           */
          if( status != MRD_STATUS_SUCCESS )
             print_error(robot, status, &dev_status) ;
          else
             printf("%s is ready.\n", robot) ;

          (void)mrd_shutdown(&robot_info) ;
       }

       return 0 ;
    }

25.4  –  Return Values

    Upon successful completion, the mrd_test_unit_ready(3mrd)
    function returns the value MRD_STATUS_SUCCESS. If the mrd_test_
    unit_ready(3mrd)fails the returned status value may be set to one
    of the following values. Other values that correspond to specific
    SCSI errors may also be possible, but these are the most likely.

25.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_info, or dev_status are NULL
    pointers.

25.4.2  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error code is used when an OpenVMS system service, such as
    $ASSIGN or $QIO, fails with a status of SS$_DRVERR. Generally
    SS$_DRVERR indicates a failure in the underlying device and the
    MRD can get the detailed device failure and return the correct
    MRD status code instead.

    This error is also returned when a SCSI Test Unit Ready command
    fails. The cause of the error can be determined by called mrd_
    request_sense(3mrd). This error also occurs as the result of a
    SCSI command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

25.4.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).

25.4.4  –  MRD_STATUS_DEVICE_INVALID

    This error code is used when an OpenVMS system service fails with
    the status SS$_NOSUCHDEV or SS$_IVDEVNAM. This will typically
    occur in mrd_startup(3mrd) when the caller tries to open a device
    which doesn't exist or uses an invalid device name.

    This error also occurs when the routine is called on behalf of
    a device controlled by the JU driver. The Media Robot Utility no
    longer uses the JU driver.

25.5  –  Related Functions

    Functions:

    mrd_startup(3mrd)

26  –  mrd_unload

    mrd_unload - Move a cartridge from drive to slot

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_unload(
        const char   *robot_name,
        const char   *volume_tag,
        const char   *drive,
        const char   *slot,
        char         *log_info)) ;

26.1  –  Parameters

    o  robot_name - The name of the robot device to be opened. On
       Digital UNIX, if the leading character of the name is not a
       slash (/), /dev/ will be prepended to the name.

    o  volume_tag - A NULL terminated character string that is the
       expected volume tag on the cartridge to be moved. On robots
       with vision support this string will be compared with the
       volume tag of the cartridge in the source slot and if it
       doesn't match the call will fail. This feature will not be
       used if the volume_tag is NULL or the empty string.

    o  drive - A NULL terminated character string that is the zero
       relative address of the drive which is to be used as the
       destination of the move.

    o  slot - A NULL terminated character string that is the zero
       relative address of the slot which is to be used as the source
       of the move.

    o  log_info - This is a character array that should be at least
       MRD_MAX_LOG_STRING in length. If this function fails as the
       result of a SCSI error, this will be filled with the formatted
       request sense data. If this function fails as the result
       of an operating system error, the operating system message
       particular to the error will be copied into the array.

26.2  –  Description

    The mrd_unload(3mrd) function is a specialized interface to the
    SCSI Move Medium command (or DSA equivalent). For the robot
    specified by robot_name, the routine will attempt to move the
    cartridge in the specified drive to the specified slot. Element
    addresses are zero based.

    The robot will be opened and the arguments to the function will
    be verified to make sure they are safe and appropriate. The drive
    and slot address will be verified they are within the valid range
    of those elements on the robot.

    The volume_tag argument can be used to perform cartridge volume
    tag verification before the move. If the cartridge volume tag at
    the port doesn't match that specified by this argument, then mrd_
    unload(3mrd) will fail with the status MRD_STATUS_CART_INVALID.
    If volume_tag argument is a NULL pointer, an empty string or
    used on a robot without vision support this argument is silently
    ignored and the volume tag check will not be made.

    The DLT libraries (TL82X and TL81X families) require the host
    issue a SCSI Unload command before a cartridge may be removed
    from the drive. The function mrd_unload(3mrd), does not offer
    this feature. Thus, the calling program must do this itself. The
    example below shows how this can be done on Digital UNIX.

26.3  –  Example

    This example applies to the OpenVMS operating system.

    /*
     * Example of mrd_unload(3mrd).  The command usage is:
     *
     *  mrd_unload robot_name drive slot [ volume_tag ]
     *
     * This version is VMS specific since it excludes the example
     * for taking a tape drive offline.  That is moderately complicated
     * but something that should be in the VMS documentation.
     */
    #ifndef lint
    static char SccsId[] = "@(#)mrd_unload.c 1.2A (mrd-example) 3/5/97" ;
    #endif

    #include <stdio.h>
    #include <string.h>
    #include <errno.h>
    #include <stdlib.h>

    #include <mrd_common.h>
    #include <mrd_message.h>

    main(int argc, char *argv[])
    {
     int status ;  /* Status from mrd_load(3mrd) */
     char *robot ;  /* The name of the robot */
     char *cart = NULL ;  /* Optional volume tag to check */
     char *slot ;   /* Source slot */
     char *drive ;  /* Destination drive */
     char log_info[MRD_MAX_LOG_STRING+1] ; /* error string */

     /*
      * Accept three required argument; robot, port and slot.  The
      * volume tag and tape drive name are optional.
      */
     if( argc < 4 ) {
      printf("usage: %s robot slot drive [ volume-tag ]\n",
       argv[0]) ;
      exit(1) ;
     }

     /*
      * Just use these directly from the command line.
      */
     robot  = argv[1] ;
     slot   = argv[2] ;
     drive  = argv[3] ;

     /*
      * If there is an extra argument present, assume it is
      * a cartridge name.  The habit of the DECC runtime
      * start-up mapping all characters to lower case,
      * might require special handling of the cartridge
      * name.
      */
     if( argc > 4 )
      cart = argv[4] ;

     /*
      * Call the function.
      */
     status = mrd_unload(robot, cart, slot, drive, log_info) ;

     /*
      * Print an error message if there is a failure.  The
      * routine mrd_strstatus(3mrd) will accept an MRD
      * error status and return the corresponding string.
      * If the log_info data has something other than a
      * NUL as the first character print it as well.  It
      * typically be the SCSI sense data or a operating
      * system specific message for the error.
      */
     if( status != MRD_STATUS_SUCCESS )
      printf("Load failed: %s: %s.\n", mrd_strstatus(status),
       log_info[0] ? log_info : "none") ;
     else
      printf("Unloaded media from Drive #%s to Slot #%s.\n",
       drive, slot) ;

     return 0 ;
    }

26.4  –  Return Values

    Upon successful completion, the mrd_unload(3mrd) function returns
    the value MRD_STATUS_SUCCESS. If the mrd_unload(3mrd) fails the
    returned status value may be set to one of the following values.
    Other values that correspond to specific SCSI errors may also be
    possible, but these are the most likely.

26.4.1  –  MRD_STATUS_PARAM

    This error is returned if the robot_name, drive, slot, or log_
    info arguments are NULL pointers.

26.4.2  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error occurs as the result of a failure to open the
    specified medium-changer. This may occur directly by calling
    mrd_startup(3mrd) or by a routine that calls mrd_startup(3mrd)
    internally. This error also occurs as the result of a SCSI
    command failure, when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

26.4.3  –  MRD_STATUS_SLOT_INVALID

    This error is returned when the element address for a slot is
    less than zero or greater than the number of slots.

26.4.4  –  MRD_STATUS_CART_INVALID

    For routines that accept a volume_tag argument to perform volume
    tag verification, this error indicates that the volume tag of the
    media doesn't match that passed to the function.

26.4.5  –  MRD_STATUS_SOURCE_EMPTY

    On routines that perform a SCSI Move Medium command, this error
    indicates that the source element is empty.

26.4.6  –  MRD_STATUS_DESTINATION_FULL

    On routines that perform a SCSI Move Medium command, this error
    indicates that the destination element already has a cartridge in
    it.

26.4.7  –  MRD_STATUS_CART_NOT_AVAIL

    This error can occur on the TL81n and TL82n family of DLT
    libraries when the source of a move is a drive and the cartridge
    in the drive is still on-line. These robots do not allow moving
    the cartridge until the drive is taken offline.

26.4.8  –  MRD_STATUS_DEVICE_INVALID

    This error code is used when an OpenVMS system service fails with
    the status SS$_NOSUCHDEV or SS$_IVDEVNAM. This will typically
    occur in mrd_startup(3mrd) when the caller tries to open a device
    which doesn't exist or uses an invalid device name.

    This error also occurs when the routine is called on behalf of
    a device controlled by the JU driver. The Media Robot Utility no
    longer uses the JU driver.

26.5  –  Related Functions

    Functions:

    o  mrd_move(3mrd)

    o  mrd_load(3mrd)

    o  mrd_inject(3mrd)

    o  mrd_eject(3mrd)

27  –  mrd_utility

    mrd_scsi_decode, mrd_map_os_error - Various MRD utility functions

    Windows NT         mrd.dll
    UNIX               /usr/lib/libmrd.a
    OpenVMS            MRD$RTL.EXE

    #include <mrd_common.h>
    #include <mrd_message.h>

    int mrd_scsi_decode(dev_status_t *dev_status);

    int mrd_map_os_error(int os_status, char *log_info);

27.1  –  Parameters

    o  dev_status The dev_status is the address of a dev_status_t
       structure. The fields in this structure are examined to map a
       SCSI error to an MRD_STATUS code.

    o  os_status The os_status is an operating system specific
       failure code that is used to find the matching MRD_STATUS
       code.

    o  log_info The log_info is a character array that should be at
       least MRD_MAX_LOG_STRING in length. On returning, it contains
       the operating system status.

27.2  –  Description

    The routine mrd_scsi_decode(3mrd) is used by the low level MRD
    routines to map SCSI device errors to MRD_STATUS codes. It
    uses the Additional Sense Code (asc) and Additional Sense Code
    Qualifier (ascq) of the status structure to find an appropriate
    MRD_STATUS code. If both the asc and ascq are zero (0), the Sense
    Key (key) will be used to determine the code. The resulting MRD_
    STATUS code will be copied to the code field and returned.

    The routine mrd_map_os_error(3mrd) is used to map operating
    system specific failures to MRD_STATUS codes. If the os_status
    isn't recognized, the routine will return MRD_STATUS_OS_ERROR.
    If the log_info argument is a valid pointer, a copy of the
    operating system text for the message will also copied to the
    space provided.

    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.

27.3  –  Example

    /*
     *   This shows how the utility routines are used.  For
     *   mrd_scsi_decode(3mrd), a selected SCSI-2 error will
     *   be filled into the key, asc and ascq fields of a
     *   dev_status_t structure and the resulting MRD status
     *   message printed.  For mrd_map_os_error(3mrd) the
     *   will be done for a selected operating system error.
     *
     *   Usage:
     *
     *      mrd_utility
     */
    #ifndef   lint
    static   char   SccsId[] = "@(#)mrd_utility.c   1.2 3/5/97" ;
    #endif

    #include <stdlib.h>
    #include <errno.h>
    #include <stdio.h>
    #include <math.h>
    #include <time.h>

    #include <mrd_common.h>
    #include <mrd_message.h>

    #ifdef   vms
    #   include   <ssdef.h>
    #endif

    main(int argc, char *argv[])
    {
       dev_status_t   dev_status ;   /* Device status */
       int      status ;
       char      log_info[MRD_MAX_LOG_STRING+1] ;

       /*
        *   Clear this for later.
        */
       log_info[0] = '\0' ;

       /*
        *   First, try mrd_scsi_decode(3mrd).  SCSI-2 happens to
        *   have ASC/ASCQ codes for a cleaning cartridge being
        *   installed somewhere, presumably a drive.  We'll
        *   see what MRD does with it.
        */
       dev_status.valid = SCSI_REQ_SENSE_VALID ;
       dev_status.key   = 1 ;         /* Recovered Error */
       dev_status.asc   = 0x30 ;
       dev_status.ascq  = 3 ;

       status = mrd_scsi_decode(&dev_status) ;

       /*
        *   Now print the result.  As it happens we map this
        *   code to MRD_STATUS_AUTOCLEAN, which is nearly
        *   right.
        */
       printf("Cleaning Cartridge Installed: (%d,%x,%x): %s\n",
          dev_status.key, dev_status.asc,
          dev_status.ascq, mrd_strstatus(status)) ;

       /*
        *   Now do one of completely random values.  Seed the
        *   random number generator just so most get a different
        *   answer.  Most of these are likely to end up as
        *   Vendor Unique errors.
        */
       srand(time(NULL)) ;

       dev_status.key   = rand() % 16 ;   /* 0 - 15 */
       dev_status.asc   = rand() % 256 ;   /* 0 - 255 */
       dev_status.ascq  = rand() % 256 ;   /* 0 - 255 */

       status = mrd_scsi_decode(&dev_status) ;

       /*
        *   Now print the result.
        */
       printf("Random SCSI Decode: (%d,%x,%x): %s\n",
          dev_status.key, dev_status.asc,
          dev_status.ascq, mrd_strstatus(status)) ;

       /*
        *   Now an OS error.  If #ifdef is handle the two example
        *   operating systems.
        */
       dev_status.valid     = 0 ;

    #if   defined(VMS)
       dev_status.os_status = SS$_UNASEFC ;
    #elif   defined(unix)
       dev_status.os_status = EINTR ;
    #else
       dev_status.os_status = rand() % 100 ;
    #endif

       status = mrd_map_os_error(dev_status.os_status, log_info) ;

       if( log_info[0] )
          printf("Map OS Error: %d: %s: %s\n", dev_status.os_status,
             mrd_strstatus(status), log_info) ;
       else
          printf("Map OS Error: %d: %s\n", dev_status.os_status,
             mrd_strstatus(status)) ;

       return 0 ;
    }

27.4  –  Return Values

    The status returned is always a valid MRD_STATUS code
    corresponding to the error given by the status or os_status.
    The errors and their mappings are:

27.4.1  –  MRD_STATUS_PARAM

    This error is returned if the dev_status argument is a NULL
    pointer.

27.4.2  –  MRD_STATUS_NO_SENSE

    This error is returned by mrd_scsi_decode(3mrd) when the asc,
    ascq and key values are all zero (0). It is also returned when
    the key value is less than zero or greater than 15.

27.4.3  –  MRD_STATUS_RECOVERED_ERROR

    This error occurs when a SCSI device returns only a sense key
    of 1h. This indicates that although a command successfully
    completed, the target device had performed some internal error
    recovery.

27.4.4  –  MRD_STATUS_MEDIUM_ERROR

    This error occurs when ASC and ASCQ are zero, but the sense key
    is 3h. This occurs when the target encounters a nonrecoverable
    error due to a flaw in the medium.

27.4.5  –  MRD_STATUS_ROBOT_HW_ERROR

    This error occurs when ASC and ASCQ are zero, but the sense key
    is 4h. This occurs when the target encounters a nonrecoverable
    hardware error.

27.4.6  –  MRD_STATUS_ROBOT_ILLEGAL_REQUEST

    This error occurs for a variety of reasons.

    It is used when a sanity check fails in the code that attempts
    to move a cartridge to the Pass-Through Mechanism, when the robot
    type isn't a TL82n.

    It is used in the mrd_lock(3mrd) code when the value is not one
    of ALLOW_REMOVAL or PREVENT_REMOVAL.

    It is used when the medium changer does not support the Prevent
    /Allow Medium Removal command or the lock value is not one or
    zero. The specific cause can be determined by examining the ASC
    /ASCQ values in the status data.

    It is used when a call to mrd_initialize_element(3mrd) is issued
    against a medium changer that does not support the Initialize
    Element Status command.

    It is used when the medium changer does not support the Position
    To Element command. The seven and five slot DLT loaders do not
    support the command, though the TL820 and TL810 family libraries
    do. Some models of TLZ6L and TLZ7L do not support the command and
    may take a long time to fail.

    It is used when the medium changer does not support the Ready
    Inport command. The TL820 family of DLT libraries support this
    command. The TL810 family of DLT libraries allows this command to
    succeed, but it doesn't perform any function.

    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).

27.4.7  –  MRD_STATUS_ROBOT_ATTENTION

    This error occurs when a SCSI command fails with the ASC set to
    one of 0x29, 0x2A or 0x2F. The log_info contains the ASCQ. The
    SCSI translations for these error codes are:

    o  0x29 - Power-on, Reset or Bus device reset occurred

    o  0x2A - Mode Parameters Changed

    o  0x2F - Command cleared by another initiator

    This error also occurs when the ASC and ASCQ are zero, but the
    SCSI sense key is 6h.

27.4.8  –  MRD_STATUS_DATA_PROTECT

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is seven (7).

27.4.9  –  MRD_STATUS_BLANK_CHECK

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is eight (8).

27.4.10  –  MRD_STATUS_VENDOR_UNIQUE_ERROR

    This error occurs when the internal routine used to decode SCSI-
    2 errors encounters an error that it has not been written to
    antipicate.

    This error also returned when the ASC is zero and the ASCQ is not
    one of zero or six, and when ASC/ASCQ are both zero and the key
    is 9h.

27.4.11  –  MRD_STATUS_COPY_ABORTED

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero,

27.4.12  –  MRD_STATUS_SENSE_EQUAL

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is Ch (12).

27.4.13  –  MRD_STATUS_VOLUME_OVERFLOW

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is Dh (13).

27.4.14  –  MRD_STATUS_MISCOMPARE

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is Eh (14).

27.4.15  –  MRD_STATUS_SENSE_RESERVED

    This error is returned by mrd_scsi_decode(3mrd) when the asc and
    ascq are zero, but the key value is Fh (15).

27.4.16  –  MRD_STATUS_ROBOT_COMM_ERROR

    This error also occurs as the result of a SCSI command failure,
    when the ASC is set to one of:

    o  0x08 - Logical unit communcation errors.

    o  0x43 - Message error

    o  0x45 - Select or Reselect failure

    o  0x47 - SCSI parity error

    o  0x48 - Initiator detected error message received

    o  0x49 - Invalid message error

    o  0x4A - Command phase error

    o  0x4B - Data phase error

    o  0x4E - Overlapped commands attempted

    o  0x54 - SCSI to host system interface failure

27.4.17  –  MRD_STATUS_ROBOT_MECH_ERROR

    This error occurs as the result of a SCSI command failure, when
    the ASC is set to one of:

    o  0x15 - Positioning error.

    o  0x8B - Vendor unique; Pass-through mechanism errors on the
       TL82n

27.4.18  –  MRD_STATUS_AUTOCLEAN

    This error occurs when a SCSI command fails with the ASC set
    to 0x30 and the ASCQ set to 0x3. On TL8nn libraries supporting
    Auto-clean, it indicates that a command was attempted while an
    auto-clean was in progress.

27.4.19  –  MRD_STATUS_CART_DAMAGED

    This error occurs when a SCSI command fails with the ASC set
    to 0x30, but the ASCQ is NOT a value of 0x3. The log_info will
    contain the ASCQ.

27.4.20  –  MRD_STATUS_ELEMENT_INVALID

    This error occurs when a SCSI command fails with the ASC set to
    0x21. The log_info will contain the ASCQ. This indicates that an
    invalid element address reached the medium-changer. For example,
    specifying the 13th slot when only 12 slots are present.

27.4.21  –  MRD_STATUS_CART_NOT_AVAIL

    This error can occur on the TL81n and TL82n family of DLT
    libraries when the source of a move is a drive and the cartridge
    in the drive is still on-line. These robots do not allow moving
    the cartridge until the drive is taken offline.

27.4.22  –  MRD_STATUS_DESTINATION_FULL

    On routines that perform a SCSI Move Medium command, this error
    indicates that the destination element already has a cartridge in
    it.

27.4.23  –  MRD_STATUS_SOURCE_EMPTY

    On routines that perform a SCSI Move Medium command, this error
    indicates that the source element is empty.

27.4.24  –  MRD_STATUS_ROBOT_DOOR_OPENED

    This occurs when a SCSI command fails with the ASC set to 0x80
    and the ASCQ set to 0x0. On TL8nn libraries this typically
    indicates that the cabinet door was opened during a command
    operation.

27.4.25  –  MRD_STATUS_DEVICE_INVALID

    This error code is used when an OpenVMS system service fails with
    the status SS$_NOSUCHDEV or SS$_IVDEVNAM. This will typically
    occur in mrd_startup(3mrd) when the caller tries to open a device
    which doesn't exist or uses an invalid device name.

    This error also occurs when the routine is called on behalf of
    a device controlled by the JU driver. The Media Robot Utility no
    longer uses the JU driver.

27.4.26  –  MRD_STATUS_ROBOT_NOT_READY

    Under OpenVMS and Digital UNIX, this error occurs as the result
    of a SCSI command failure, when the ASC is set to one of:

    o  0x80 - When the ASCQ is not zero (0).

    o  0x81 - Vendor unique; gripper errors on the TL82X and TL81X

    o  0x04 - Logical unit not ready

    o  0x3E - Logical unit has not been self configured

    o  0x40 - Diagnostic failure; ASCQ indicates component

    o  0x42 - Power-on self test failure

    o  0x44 - Internal target failure

    o  0x46 - Unsuccessful soft reset

    o  0x4C - Logical unit failed self-configuration

    This status is also returned when the ASC and ASCQ are zero, but
    the key is two (2).

27.4.27  –  MRD_STATUS_ROBOT_CMD_ABORTED

    This error code is used when an OpenVMS system service fails with
    the status SS$_ABORT.

27.5  –  Related Functions

    Functions:

    o  mrd_move_medium(3mrd)

    o  mrd_read_element_status(3mrd)

    o  mrd_startup(3mrd)

    o  mrd_position_to_element(3mrd)

    o  mrd_initialize_element(3mrd)

    o  mrd_ready(3mrd)

    o  mrd_prevent_allow(3mrd)
Close Help