                UDF Software Developer's Kit Device Interfaces
                -----------------------------------------------

INTRODUCTION

     The UDF SDK provides a virtual base class interface to allow developers
to implement their own autochanger and drive device control code and smoothly
fit into the SDK infrastructure.  The single-surface library (SSLIB) requires
developers to implement a disk-device object based upon the abstract base
class SSDevice.  The multi-surface library (MSLIB) requires both an SSDevice
subclass as well as a class derived from the MSDevice base class, which 
provides I/O access to multiple volumes.  


/*****************************************************************************
                           SSDevice Class Description
*****************************************************************************/

CLASS

SSDevice

     The SSDevice class is a purely virtual base class whose purpose is to
define the disk device interface which is used by the SSLIB objects.  
Developers using the SDK need to create their own disk device class derived
from the SSDevice base class.  Following is a listing of the methods defined
in the SSDevice class, their interfaces, and the expected semantics.

COLLABORATORS 

none

PUBLIC METHODS

~SSDevice()
     Virtual destructor for the SSDevice class.

numSectors()
     This method returns the number of sectors on the media currently in the 
physical disk drive associated with the SSDevice object.

sectorSize()
     This method returns the sector size, in bytes, of the media in the
current physical disk drive associated with the SSDevice object.

read(UINT32 start,UINT32 nsectors,const ByteArrayRef& arr,Error& err)
read(UINT32 start,UINT32 nbytes,BYTE *buf,Error& err)
     These methods read data from disk into the argument BYTE * array or
ByteAraryRef.

write(UINT32 start,UINT32 nsectors,const ByteArrayRef& arr,Error& err)
write(UINT32 start,UINT32 nbytes,BYTE *buf,Error& err)
     These methods write data to disk from the argument BYTE * array or
ByteAraryRef.

writeWOE(UINT32 start,UINT32 nsectors,const ByteArrayRef& arr,Error& err)
writeWOE(UINT32 start,UINT32 nbytes,BYTE *buf,Error& err)
     These methods write data to disk from the argument BYTE * array or
ByteAraryRef using write-without-erase mode.

verifyMode(INT32 newmode)
     This method sets the verify mode of the drive.  If newmode is nonzero,
any subsequent writes will be performed in verify mode; otherwise writes
will be performed without verify (default).

verifyMode()
     This method returns the current verify mode of the drive.

erase(UINT32 start,UINT32 nsectors,Error& err)
     This method erases the specified number of sectors on the media currently
in the drive.

error()
     This method returns the current error state of the object.

checkValidity()
     This method returns an Error value indicating whether the drive device
is able to service any kind of I/O request.

mediaType()
     This method returns the media type of the disk currently in the drive
(enum MediaType = { media_Worm, media_Rewritable}).

DISCUSSION

     Since there are methods in the SSDevice class that are
declared as pure virtual methods, users cannot instantiate SSDevice objects
but must instead derive their own classes from the SSDevice class. 
Users may, of course, add additional methods to their subclasses, but the
UDF SSLIB and MSLIB toolkits require that the user's SSDevice subclass 
objects provide minimally all methods and interfaces declared in class 
SSDevice.  In the following Examples section we present a declaration of
an SSDevice subclass intended for use on HP-UX series 700 platform systems.

EXAMPLES

class DriveDevice : public SSDevice {

private:

    INT32               fd_;            // File descriptor for drive device
    ErrorCodeType       dderror_;       // Error state
    UINT32              sectorSize_;    // Size of a sector in bytes
    UINT32              numSectors_;    // Number of sectors in device
    INT32               verifyMode_;    // If non-zero, use write-with-verify

    Boolean     isBlankCheck(void);
    void        setWWOE(INT32 which);
    INT32       setVMode(INT32 which);

public:

                        DriveDevice(const String& devfile);
    virtual             ~DriveDevice();
    virtual UINT32      numSectors() const { return numSectors_; }
    virtual UINT32      sectorSize() const { return sectorSize_; }
    virtual INT32       read(UINT32 startsector,UINT32 nsectors,
                             const ByteArrayRef& arr,Error& err);
    virtual INT32       read(UINT32 startsector,UINT32 nbytes,BYTE *buf,
                             Error& err);
    virtual INT32       write(UINT32 startsector,UINT32 nsectors,
                              const ByteArrayRef& arr,Error& err);
    virtual INT32       write(UINT32 startsector,UINT32 nbytes,BYTE *buf,
                              Error& err);
    virtual INT32       writeWOE(UINT32 startsector,UINT32 nsectors,
                                 const ByteArrayRef& arr,Error& err);
    virtual INT32       writeWOE(UINT32 startsector,UINT32 nbytes,BYTE *buf,
                                 Error& err);
    virtual INT32       verifyMode(INT32 newmode) {
                            INT32 oldmode = verifyMode_;
                            verifyMode_ = (newmode ? 1 : 0);
                            return oldmode;
                        }
    virtual INT32       verifyMode(void) {
                            return verifyMode_;
                        }
    virtual INT32       erase(UINT32 start,UINT32 nsectors,Error& err);
    virtual Error       error(void) const;
    virtual Error       checkValidity(void) const;
    virtual MediaType   mediaType(void) ;
};

/*****************************************************************************
                          SSDevice Method Descriptions
*****************************************************************************/
--
METHOD
virtual SSDevice::~SSDevice()

Virtual destructor for the SSDevice class.

ARGUMENTS
None.

RETURNS
None.

PRECONDITIONS
None.

POSTCONDITIONS
Any resources in use by the SSDevice will be freed.

ERRORS
None.

DISCUSSION

EXAMPLES

--
METHOD
virtual UINT32 SSDevice::numSectors() const

This method returns the number of sectors on the media currently in the
drive associated with the SSDevice.

ARGUMENTS
None

RETURNS

On success, returns the number of sectors on the media currently in the
drive associated with the SSDevice.  On failure, returns 0.

PRECONDITIONS

The SSDevice object was successfully constructed.

POSTCONDITIONS

See return values

ERRORS

None; does not affect the error state of the SSDevice.

DISCUSSION

EXAMPLES

--
METHOD
virtual UINT32 SSDevice::sectorSize() const

This method returns the sector size, in bytes, of the media currently in
the device associated with the SSDevice object.

ARGUMENTS
None

RETURNS
On success, this method returns the sector size, in bytes, of the media 
currently in the device associated with the SSDevice object.  On failure,
returns 0.

PRECONDITIONS
The SSDevice object was successfully constructed.

POSTCONDITIONS
See return values.

ERRORS
None; does not affect the error state of the SSDevice.

DISCUSSION

EXAMPLES

--
METHOD
virtual INT32 SSDevice::read(UINT32 start,UINT32 nsectors,
                             const ByteArrayRef& arr,Error& err)

This method reads data from disk into the user's ByteArrayRef.  

ARGUMENTS
start(in)
        The starting sector address for the read.
nsectors(in)
        The maximum number of sectors that will be read.
arr(out)
        Reference to the buffer to store the read data.
err(out)
        Error object to contain the results of the operation.

RETURNS
This method returns the number of bytes actually read.  If -1 is returned,
no valid data was stored in the user's buffer and indicates that an I/O error
occurred.  A "short count" will be returned (i.e., a number less than the
length of the argument ByteArrayRef) if the read encountered a blank sector,
if the read request went beyond the logical boundaries of the media as
specified by the start and nsectors parameters, or if the read request went
beyond the physical end of media.

PRECONDITIONS
The SSDevice object was successfully constructed and contains media.
The start parameter is in the range [ 0, number of sectors )
The nsectors parameter satisfies the following:
        start + nsectors < number of sectors

POSTCONDITIONS
The number of bytes specified in the length field of the argument ByteArrayRef
will be read from disk and stored in the memory referred to by buf.

ERRORS

error_None:  Function completed successfully
error_No_free_store:  Could not allocate memory for buffering.
error_Empty_path_element:  Argument buffer is invalid.
error_Drive_blank_check:  A blank sector was encountered during the read.
error_Read_EOM:  Attempted to read past physical EOM.
error_Read_EOLM:  Attempted to read past logical EOM.
error_Drive_read:  Generic I/O failure on read.

DISCUSSION

The start and nsectors parameters specify a logical media extent to be used
for the read.  Start is the starting sector address for the read (sectors
are assumed to be numbered starting with 0); nsectors is the number of sectors
which can be used for the read.  If the size, in bytes, given by buf.length()
of the read request is greater than the number of bytes available by the
nsectors parameter, the read will read up to nsectors * sectorsize bytes, and
will return error_Read_EOLM.  

EXAMPLES

--
METHOD
virtual INT32 SSDevice::read(UINT32 start,UINT32 nbytes,BYTE *buf,Error& err)

This method is an alternate read() interface.  It is primarily used by the 
MSDevice class.

ARGUMENTS
start(in)
        The starting sector address for the read.
nbytes(in)
        The number of bytes to read.
buf(out)
        The buffer to store the data.
err(out)
        Error object to contain the results of the operation.

RETURNS
This method returns the number of bytes actually read.  If -1 is returned,
no valid data was stored in the user's buffer and indicates that an I/O error
occurred.  A "short count" will be returned (i.e., a number less than the
nbytes parameter) if the read encountered a blank sector, or if the read 
request went beyond the physical end of media.

PRECONDITIONS
The SSDevice object was successfully constructed and contains media.
The start parameter is in the range [ 0, number of sectors )

POSTCONDITIONS
The number of bytes specified by the nbytes parameter will be read from disk 
and stored in the memory referred to by buf.

ERRORS

error_None:  Function completed successfully
error_No_free_store:  Could not allocate memory for buffering.
error_Empty_path_element:  Argument buffer is invalid.
error_Drive_blank_check:  A blank sector was encountered during the read.
error_Read_EOM:  Attempted to read past physical EOM.
error_Drive_read:  Generic I/O failure on read.

DISCUSSION


EXAMPLES

--
METHOD
virtual INT32 SSDevice::write(UINT32 start,UINT32 nsectors,
                              const ByteArrayRef& arr,Error& err)

This method writes data to disk from the user's ByteArrayRef.  

ARGUMENTS
start(in)
        The starting sector address for the write.
nsectors(in)
        The maximum number of sectors that will be written.
arr(in)
        Reference to the buffer to supply the write data.
err(out)
        Error object to contain the results of the operation.

RETURNS
This method returns the number of bytes actually written.  If -1 is returned,
no valid data was stored in the user's buffer and indicates that an I/O error
occurred.  A "short count" will be returned (i.e., a number less than the
length of the argument ByteArrayRef) if the write request went beyond the 
logical boundaries of the media as specified by the start and nsectors 
parameters, or if the write request went beyond the physical end of media.

PRECONDITIONS
The SSDevice object was successfully constructed and contains media.
The start parameter is in the range [ 0, number of sectors )
The nsectors parameter satisfies the following:
        start + nsectors < number of sectors

POSTCONDITIONS
The number of bytes specified in the length field of the argument ByteArrayRef
will be writte to disk from the memory referred to by buf.

ERRORS

error_None:  Function completed successfully
error_No_free_store:  Could not allocate memory for buffering.
error_Empty_path_element:  Argument buffer is invalid.
error_Write_EOM:  Attempted to write past physical EOM.
error_Write_EOLM:  Attempted to write past logical EOM.
error_Drive_write:  Generic I/O failure on write.
error_Set_verify_failed:  Unable to put device into verify mode.

DISCUSSION

The start and nsectors parameters specify a logical media extent to be used
for the write.  Start is the starting sector address for the write (sectors
are assumed to be numbered starting with 0); nsectors is the number of sectors
which can be used for the write.  If the size, in bytes, given by buf.length()
of the write request is greater than the number of bytes available by the
nsectors parameter, the write will read up to nsectors * sectorsize bytes, and
will return error_Write_EOLM.  

EXAMPLES

--
METHOD
virtual INT32 SSDevice::write(UINT32 start,UINT32 nbytes,BYTE *buf,Error& err)

This method is an alternate write() interface.  It is primarily used by the 
MSDevice class.

ARGUMENTS
start(in)
        The starting sector address for the write.
bytes(in)
        The number of bytes to write.
buf(in)
        The buffer to supply the data.
err(out)
        Error object to contain the results of the operation.

RETURNS
This method returns the number of bytes actually written.  If -1 is returned,
no valid data was written and indicates that an I/O error occurred.  A "short 
count" will be returned (i.e., a number less than the length of the argument 
ByteArrayRef) if the read request went beyond the physical end of media.

PRECONDITIONS
The SSDevice object was successfully constructed and contains media.
The start parameter is in the range [ 0, number of sectors )

POSTCONDITIONS
The number of bytes specified by the nbytes parameter will be read from disk 
and stored in the memory referred to by buf.

ERRORS

error_None:  Function completed successfully
error_No_free_store:  Could not allocate memory for buffering.
error_Empty_path_element:  Argument buffer is invalid.
error_Write_EOM:  Attempted to write past physical EOM.
error_Drive_write:  Generic I/O failure on write.
error_Set_verify_failed:  Unable to put device into verify mode.

DISCUSSION


EXAMPLES

--
METHOD
virtual INT32 SSDevice::writeWOE(UINT32 start,UINT32 nsectors,
                                 const ByteArrayRef& arr,Error& err)

This method writes data to disk from the user's ByteArrayRef using 
write-without-erase mode.

ARGUMENTS
start(in)
        The starting sector address for the write.
nsectors(in)
        The maximum number of sectors that will be written.
arr(out)
        Reference to the buffer to supply the write data.
err(out)
        Error object to contain the results of the operation.

RETURNS
This method returns the number of bytes actually written.  If -1 is returned,
no valid data was stored in the user's buffer and indicates that an I/O error
occurred.  A "short count" will be returned (i.e., a number less than the
length of the argument ByteArrayRef) if the write request went beyond the 
logical boundaries of the media as specified by the start and nsectors 
parameters, or if the write request went beyond the physical end of media.

PRECONDITIONS
The SSDevice object was successfully constructed and contains media.
The start parameter is in the range [ 0, number of sectors )
The nsectors parameter satisfies the following:
        start + nsectors < number of sectors

POSTCONDITIONS
The number of bytes specified in the length field of the argument ByteArrayRef
will be writte to disk from the memory referred to by buf.

ERRORS

error_None:  Function completed successfully
error_No_free_store:  Could not allocate memory for buffering.
error_Empty_path_element:  Argument buffer is invalid.
error_Write_EOM:  Attempted to write past physical EOM.
error_Write_EOLM:  Attempted to write past logical EOM.
error_Drive_write:  Generic I/O failure on write.
error_Set_verify_failed:  Unable to put device into verify mode.

DISCUSSION

The start and nsectors parameters specify a logical media extent to be used
for the write.  Start is the starting sector address for the write (sectors
are assumed to be numbered starting with 0); nsectors is the number of sectors
which can be used for the write.  If the size, in bytes, given by buf.length()
of the write request is greater than the number of bytes available by the
nsectors parameter, the write will read up to nsectors * sectorsize bytes, and
will return error_Write_EOLM.  

EXAMPLES

--
METHOD
virtual INT32 SSDevice::writeWOE(UINT32 start,UINT32 nbytes,BYTE *buf,
                                 Error& err)

This method is an alternate writeWOE() interface.  It is primarily used by the 
MSDevice class.

ARGUMENTS
start(in)
        The starting sector address for the write.
bytes(in)
        The number of bytes to write.
buf(out)
        The buffer to store the data.
err(out)
        Error object to contain the results of the operation.

RETURNS
This method returns the number of bytes actually written.  If -1 is returned,
no valid data was written and indicates that an I/O error occurred.  A "short 
count" will be returned (i.e., a number less than the length of the argument 
ByteArrayRef) if the read request went beyond the physical end of media.

PRECONDITIONS
The SSDevice object was successfully constructed and contains media.
The start parameter is in the range [ 0, number of sectors )

POSTCONDITIONS
The number of bytes specified by the nbytes parameter will be read from disk 
and stored in the memory referred to by buf.

ERRORS

error_None:  Function completed successfully
error_No_free_store:  Could not allocate memory for buffering.
error_Empty_path_element:  Argument buffer is invalid.
error_Write_EOM:  Attempted to write past physical EOM.
error_Drive_write:  Generic I/O failure on write.
error_Set_verify_failed:  Unable to put device into verify mode.

DISCUSSION


EXAMPLES

--
METHOD
virtual INT32 SSDevice::verifyMode(INT32 newmode)

Sets the verify mode of the SSDevice.  

ARGUMENTS
newmode(in)
        If nonzero, sets the verify mode to ON; otherwise verify mode is
set to OFF.

RETURNS
Returns the previous verify mode of the SSDevice.

PRECONDITIONS
None

POSTCONDITIONS
See above

ERRORS
None; does not affect the error state of the SSDevice.

DISCUSSION
The verify mode is applied to any call to write() or writeWOE().  By default,
verify mode is OFF.  Note that, if verify mode is ON and the SSDevice is
unable to put the physical device into write-with-verify mode, any calls to
write() or writeWOE() will fail with the error error_Set_verify_failed.

EXAMPLES

--
METHOD
virtual INT32 SSDevice::verifyMode()

Returns the current verify mode of the SSDevice.  

ARGUMENTS
None.

RETURNS
Returns the current verify mode of the SSDevice.  0 indicates verify mode is
OFF; any other value indicates verify mode is ON.

PRECONDITIONS
None

POSTCONDITIONS
See above

ERRORS
None; does not affect the error state of the SSDevice.

DISCUSSION

EXAMPLES

--
METHOD
virtual INT32 SSDevice::erase(UINT32 start,UINT32 nsectors,Error& err)

ARGUMENTS
start(in)
        The starting sector to erase.
nsectors(in)
        The number of sectors to erase.
error(out)
        Error object to contain the results of the operation.

RETURNS
        Returns 0 on success, -1 on failure.

PRECONDITIONS
The SSDevice object was successfully created and contains media.
The media is erasable (e.g., not a hard disk, not WORM).

POSTCONDITIONS
The sectors specified by the start and nsectors parameters will be erased.

ERRORS
error_None:  Function completed successfully.
error_Erase_failed:  The erase failed due to an I/O error.

DISCUSSION

EXAMPLES

--
METHOD
Error SSDevice::error() const

Returns an Error value corresponding to the results of the last call to the
read(), write(), writeWOE(), or erase() methods, or construction.

ARGUMENTS
None

RETURNS
See above

PRECONDITIONS
None

POSTCONDITIONS
None

ERRORS
None; does not affect the state of the SSDevice object.

DISCUSSION

EXAMPLES

--
Error SSDevice::checkValidity() const

This method checks whether the SSDevice object in question is valid--i.e.,
it was successfully constructed.

ARGUMENTS
None

RETURNS
Returns an Error value specifying the state of the object.  If the Error is
not error_None, the object is not in a valid state and will not respond to
any calls to read(), write(), writeWOE(), or erase() until the condition
is corrected.  One of the following values is returned:

error_None:  object is valid.
error_Empty_path_element:  construction failed because the argument String
                           to the constructor was invalid.
error_File_not_found:  construction failed; could not find specified device
                       file.
error_Capacity_failed:  construction failed; could not get capacity 
                        information.

PRECONDITIONS
None

POSTCONDITIONS
None

ERRORS
None; does not affect the state of the SSDevice object.

DISCUSSION

EXAMPLES

--
MediaType SSDevice::mediaType() 

This method determines the media type of the disk in the SSDevice 
(NSR::media_Worm or NSR::media_Rewritable).

ARGUMENTS
None

RETURNS
Returns True if the disk is WORM, False otherwise.

PRECONDITIONS
The SSDevice was successfully constructed.

POSTCONDITIONS
None

ERRORS
None; does not affect the state of the SSDevice object.

DISCUSSION

EXAMPLES

--
/*****************************************************************************
                           MSDevice Class Description
*****************************************************************************/

CLASS

MSDevice

     The MSDevice class is a purely virtual base class whose purpose is to
define the multisurface (autochanger) device interface which is used by the 
MSLIB objects.  Developers using the SDK need to create their own multisurface 
device class derived from the MSDevice base class.  Following is a listing of 
the methods defined in the MSDevice class, their interfaces, and the expected 
semantics.

COLLABORATORS 

none

PUBLIC METHODS

~hpACDev()
     Virtual destructor for the SSDevice class.

numSectors(sid_t sid)
     This method returns the number of sectors on the media indicated by
the specified surface identifier sid.

sectorSize(sid_t sid)
     This method returns the size, in bytes, of the sectors on the media
indicated by the specified surface identifier sid.

read(sid_t sid,UINT32 start,UINT32 nbytes,BYTE *buf)
     This method reads nbytes of data from the media specified by sid into the 
user's data buffer buf.

write(sid_t sid,UINT32 start,UINT32 nbytes,BYTE *buf)
     This method writes nbytes of data to the media specified by sid from the 
user's data buffer buf.

error(void) const
     Returns the result of the most recent call to any of the functions
of the MSDevice.

flush(void)
     Flush any cached data to media.  Note that if the MSDevice subclass
does not perform caching, this method, while it must be defined, can be
defined as a no-operation method.

errorClear(void)
     Clear the error state of the MSDevice to error_None.

writeWOE(sid_t sid,UINT32 start,UINT32 nbytes,BYTE *buf)
     This method writes nbytes of data to the media specified by sid from the 
user's data buffer buf using write-without-erase mode.  

erase(sid_t sid,UINT32 start,UINT32 nsectos)
     This method erases the specified number of sectors on the media indicated
by the surface specifier sid.

verifyMode(sid_t sid,INT32 newmode)
     This method sets the verify mode of the media specified by sid.

verifyMode(sid_t sid)
     This method returns the current verify mode of the media specified by sid.

allocDrive(sid_t sid)
     This method allocates a drive resource to the media specified by sid and
returns a pointer to an SSDevice object corresponding to the allocated drive.

freeDrive(SSDevice *drivep)
     This method frees a drive resource allocated by a previous call to
allocDrive().

mediaType(sid_t sid)
     This method determines the media type of the given surface.

DISCUSSION

     All methods in the MSDevice class are declared as virtual.  However,
only seven of the methods are pure virtual, and hence are absolutely mandatory
that users of the MSLIB toolkit implement them.  The remaining methods are
optional, but if they are implemented, they must follow the interfaces
specified by the virtual function declarations.  They are provided in case
developers wish to use SSLIB toolkit code with MSDevice objects (e.g., using
the single-surface library in an autochanger environment).  Users may, of 
course, add additional methods to their subclasses of MSDevice.  In the 
following Examples section we present a declaration of an MSDevice subclass 
intended for use on HP-UX series 700 platform systems.  The example MSDevice
subclass provides substantially more functionally than is required by the
MSLIB code.

     Following is a list of the seven mandatory methods.  They are declared
as pure virtual functions.

     virtual UINT32 numsectors(sid_t sid) = 0
     virtual UINT32 sectorSize(sid_t sid) = 0
     virtual INT32  read(sid_t sid,UINT32 start,UINT32 nbytes,BYTE *buf) = 0
     virtual INT32  write(sid_t sid,UINT32 start,UINT32 nbytes,BYTE *buf) = 0
     virtual Error  error(void) const = 0
     virtual void   flush(void) = 0
     virtual void   errorClear(void) = 0

     All other methods are optional if developers are only using MSLIB.  They
must be implemented according to the following specifications if the MSDevice
subclass is to be used with SSLIB code.

EXAMPLES

     The example hpACDev class is considerably more functional than the
bare minimum requirements for the MSLIB toolkit.  It is explained in greater
detail in udfhpdev.txt

class hpACDev : public MSDevice
{

private:

    //
    // Some private structures used for internal data handling
    //

    struct ACMapEntry {
        sid_t   sid_;
        UINT32  slot_;
        UINT32  side_;                  // 0 = side A, 1 = side B
        UINT32  numSectors_;
        UINT32  sectorSize_;
        INT32   verifyMode_;

        ACMapEntry(void) : sid_(SID_T_INVALID),
                           slot_(0),
                           side_(0),
                           numSectors_(0),
                           sectorSize_(0),
                           verifyMode_(VERIFY_MODE_OFF) {}
    };

    struct ACMapTable {
        ACMapEntry *table_;
        UINT32       size_;

        ACMapTable() : table_(NULL), size_(0) {}
        ~ACMapTable() { 
            if(table_ != NULL) {
                delete [] table_;
            }
            size_ = 0;
        }
        INT32 resize(UINT32 newsize);
        ACMapEntry *lookup(sid_t sid);
    };

    struct ACDriveEntry {
        sid_t           sid_;
        SSDevice *      drivep_;
        String *        devfile_;
        INT32           rmflag_;        // Delete devfile_ on destruction?
        INT32           tgt_;           // SCSI Target ID
        INT32           lun_;           // SCSI LUN ID 
        INT32           element_;       // Element ID in jukebox

        ACDriveEntry(void) : sid_(SID_T_INVALID),
                             drivep_(NULL),
                             devfile_(NULL),
                             rmflag_(0),
                             tgt_(-1),
                             lun_(-1),
                             element_(-1) {} 
        
        ~ACDriveEntry() {

            // Don't delete drivep_ in case someone's using it

            if(rmflag_) {
                if(devfile_ != NULL) {
                    unlink((char *) *devfile_);
                }
            }
            if(devfile_ != NULL) {
                delete devfile_;
            }
        }
    };

    struct ACDriveTable {
        ACDriveEntry * table_;
        UINT32          size_;

        ACDriveTable() : table_(NULL), size_(0) {}
        ~ACDriveTable() { 
            if(table_ != NULL) {
                delete [] table_;
            }
        }
        INT32 resize(UINT32 newsize);
        ACDriveEntry *lookup(sid_t sid);
        ACDriveEntry *findFree(void);
    };

    //
    // Private data members
    //

    INT32        fd_;                   // File descriptor for picker
    Error        error_;                // Error state of autochanger
    ACMapTable   mapTable_;             // Table of sid_t/device file mappings
    ACDriveTable driveTable_;           // Table of allocated drives
    Bitmap       bitmap_;               // For allocating sid's
    INT32        sleepMode_;            // Okay to sleep on drive resource?
    struct element_addresses eltaddr_;  // Element addresses information
    struct sense_2_aligned senseData_;  // Buffer for sense data
    UINT32       senseLength_;          // Length of available sense data

    //
    // Private member functions
    //

    INT32            acCommand(struct sctl_io *);
    INT32            supportedAC(void);
    INT32            getEltAddr(void);   
    INT32            getEltStatus(INT32 element,struct element_status *esp);
    INT32            testUnitReady(INT32 howmany);
    INT32            moveMedium(INT32 transport,INT32 source,INT32 dest,
                                INT32 flip);
    INT32            exchangeMedia(INT32 transport,INT32 src,INT32 dst1,
                                   INT32 dst2,INT32 flip1,INT32 flip2);
    SSDevice *       makeDriveDevice(ACDriveEntry *dptr,Error& err);

public:

                     hpACDev(const String& devfile);
    virtual          ~hpACDev(void);
    virtual UINT32   numSectors(sid_t sid) ;
    virtual UINT32   sectorSize(sid_t sid) ;
    virtual INT32    read(sid_t sid,UINT32 start,UINT32 nbytes,BYTE *barr);
    virtual INT32    write(sid_t sid,UINT32 start,UINT32 nbytes,BYTE *barr);
    virtual INT32    writeWOE(sid_t sid,UINT32 start,UINT32 nbytes,
                              BYTE *barr);
    virtual INT32    erase(sid_t sid,UINT32 start,UINT32 nsectors);
    virtual INT32    verifyMode(sid_t sid,INT32 newmode);
    virtual INT32    verifyMode(sid_t sid) ;
    virtual SSDevice *allocDrive(sid_t sid);
    virtual INT32    freeDrive(SSDevice *drivep);
    virtual Error    error(void) const { return error_; }
    virtual void     flush(void) {}
    virtual MediaType mediaType(sid_t sid);
            sid_t    addSurface(UINT32 slot,UINT32 side);
            INT32    removeSurface(sid_t sid);
            INT32    sleepMode(INT32 newmode);
            INT32    sleepMode(void) const;
            INT32    addDriveMap(INT32 id,INT32 lun,const String& devfile);
            INT32    elementAddresses(struct element_addresses& eltaddr);
            INT32    elementStatus(INT32 element,struct element_status& es);
            UINT32   senseData(struct sense_2_aligned& sense);
#ifdef DEBUG
            void     print(UINT32 indent,const String& str);
#endif
};

/*****************************************************************************
                          MSDevice Method Descriptions
*****************************************************************************/

--
METHOD
MSDevice::~MSDevice()

Virtual destructor for the MSDevice class.

ARGUMENTS
None.

RETURNS
None.

PRECONDITIONS
None.

POSTCONDITIONS
Any resources in use by the MSDevice will be freed.

ERRORS
None.

DISCUSSION

EXAMPLES

--
METHOD
hpACDev::numSectors(sid_t sid)

Returns the number of sectors on the specified surface.  Returns 0 on error.

ARGUMENTS
sid(in)
        Surface identifier

RETURNS
Returns the number of sectors on the specified surface.  Returns 0 on error.

PRECONDITIONS
The MSDevice object was successfully constructed.
The argument sid is valid.

POSTCONDITIONS
See returns.

ERRORS
error_None:  Operation completed successfully.
error_Invalid_sid:  Invalid sid parameter specified.
error_Drive_not_available:  No drive resource available.
error_Move_failed:  Move operation failed.
error_Exchange_failed:  Exchange operation failed.

DISCUSSION

EXAMPLES

--
METHOD
MSDevice::sectorSize(sid_t sid)

Returns the size, in bytes, of a sector on the specified surface.

ARGUMENTS
sid(in)
        Surface identifier

RETURNS
Returns the size, in bytes, of a sector on the specified surface.  Returns 0
on error.

PRECONDITIONS
The MSDevice object was successfully constructed.
The argument sid is valid.

POSTCONDITIONS
See returns

ERRORS
error_None:  Operation completed successfully.
error_Invalid_sid:  Invalid sid parameter specified.
error_Drive_not_available:  No drive resource available.
error_Move_failed:  Move operation failed.
error_Exchange_failed:  Exchange operation failed.

DISCUSSION

EXAMPLES

--
METHOD
MSDevice::read(sid_t sid,UINT32 start,UINT32 nbytes,BYTE *buf)

     Reads data into the user's buffer from the specified surface.

ARGUMENTS
sid(in)
        Surface specifier.
start(in)
        The starting sector address for the read.
nbytes(in)
        The number of bytes to read.
buf(out)
        The buffer to store the data.

RETURNS
This method returns the number of bytes actually read.  If -1 is returned,
no valid data was stored in the user's buffer and indicates that an I/O error
occurred.  A "short count" will be returned (i.e., a number less than the
nbytes parameter) if the read encountered a blank sector, or if the read 
request went beyond the physical end of media.

PRECONDITIONS
The MSDevice object was successfully constructed and contains media.
The start parameter is in the range [ 0, number of sectors ).
The argument sid is valid.

POSTCONDITIONS
The number of bytes specified by the nbytes parameter will be read from the
specified surface and stored in the memory referred to by buf.

ERRORS

error_None:  Function completed successfully
error_Invalid_sid:  Invalid sid parameter specified.
error_Drive_not_available:  No drive resource available.
error_Move_failed:  Move operation failed.
error_Exchange_failed:  Exchange operation failed.
error_No_free_store:  Could not allocate memory for buffering.
error_Empty_path_element:  Argument buffer is invalid.
error_Drive_blank_check:  A blank sector was encountered during the read.
error_Read_EOM:  Attempted to read past physical EOM.
error_Drive_read:  Generic I/O failure on read.

DISCUSSION


EXAMPLES

--
METHOD
MSDevice::write(sid_t sid,UINT32 start,UINT32 nbytes,BYTE *buf)

     Writes data from the user's buffer to the specified surface.

ARGUMENTS
sid(in)
        Surface specifier.
start(in)
        The starting sector address for the write.
nbytes(in)
        The number of bytes to write.
buf(in)
        The buffer to supply the data.

RETURNS
This method returns the number of bytes actually written.  If -1 is returned,
no valid data was stored in the user's buffer and indicates that an I/O error
occurred.  A "short count" will be returned (i.e., a number less than the
nbytes parameter) if the write request went beyond the physical end of media.

PRECONDITIONS
The MSDevice object was successfully constructed and contains media.
The start parameter is in the range [ 0, number of sectors ).
The argument sid is valid.
The specified surface is writable.

POSTCONDITIONS
The number of bytes specified by the nbytes parameter will be written from the
memory referred to by buf to the specified surface.

ERRORS

error_None:  Function completed successfully
error_Invalid_sid:  Invalid sid parameter specified.
error_Drive_not_available:  No drive resource available.
error_Move_failed:  Move operation failed.
error_Exchange_failed:  Exchange operation failed.
error_No_free_store:  Could not allocate memory for buffering.
error_Empty_path_element:  Argument buffer is invalid.
error_Write_EOM:  Attempted to write past physical EOM.
error_Drive_write:  Generic I/O failure on write.

DISCUSSION


EXAMPLES

--
METHOD
Error MSDevice::error() const

Returns an Error value corresponding to the results of the last call to any
of the MSDevice public methods.

ARGUMENTS
None

RETURNS
See above

PRECONDITIONS
None

POSTCONDITIONS
None

ERRORS
None; does not affect the state of the MSDevice object.

DISCUSSION

EXAMPLES

--
METHOD
MSDevice::flush(void)

Any cached data, if any, will be flushed to media.

ARGUMENTS
None

RETURNS
Returns 0 on success, -1 on failure

PRECONDITIONS
The MSDevice was successfully constructed.

POSTCONDITIONS
Any cached data, if any, will be flushed to media.

ERRORS
<any; not spec'ed>

DISCUSSION

EXAMPLES

--
METHOD
MSDevice::mediaType(sid_t sid)

Determines whether the given surface is WORM media.

ARGUMENTS
sid_t  sid  IN  Surface identifier

RETURNS
Returns True if the surface is WORM, False otherwise.

PRECONDITIONS
The MSDevice was successfully constructed.

POSTCONDITIONS

ERRORS
<any; not spec'ed>

DISCUSSION

EXAMPLES

--
METHOD
MSDevice::writeWOE(sid_t sid,UINT32 start,UINT32 nbytes,BYTE *buf)

     Writes data from the user's buffer to the specified surface using
write-without-erase mode .

ARGUMENTS
sid(in)
        Surface specifier.
start(in)
        The starting sector address for the write.
nbytes(in)
        The number of bytes to write.
buf(in)
        The buffer to supply the data.

RETURNS
This method returns the number of bytes actually written.  If -1 is returned,
no valid data was stored in the user's buffer and indicates that an I/O error
occurred.  A "short count" will be returned (i.e., a number less than the
nbytes parameter) if the write request went beyond the physical end of media.

PRECONDITIONS
The MSDevice object was successfully constructed and contains media.
The start parameter is in the range [ 0, number of sectors ).
The argument sid is valid.
The specified surface is writable.

POSTCONDITIONS
The number of bytes specified by the nbytes parameter will be written from the
memory referred to by buf to the specified surface.

ERRORS

error_None:  Function completed successfully
error_Invalid_sid:  Invalid sid parameter specified.
error_Drive_not_available:  No drive resource available.
error_Move_failed:  Move operation failed.
error_Exchange_failed:  Exchange operation failed.
error_No_free_store:  Could not allocate memory for buffering.
error_Empty_path_element:  Argument buffer is invalid.
error_Write_EOM:  Attempted to write past physical EOM.
error_Drive_write:  Generic I/O failure on write.

DISCUSSION


EXAMPLES

--
METHOD
MSDevice::erase(sid_t sid,UINT32 start,UINT32 nsectors)

     Erases the specified sectors on the media indicated by sid.

ARGUMENTS
sid(in)
        Surface identifier
start(in)
        Starting sector for erase request
nsectors(in)
        Number of sectors to erase

RETURNS
Returns 0 on success, -1 on failure.

PRECONDITIONS
The MSDevice object was successfully constructed and contains media.
The start parameter is in the range [ 0, number of sectors ).
The argument sid is valid.

POSTCONDITIONS
The specified sectors on the media will be erased.

ERRORS
error_None:  Function completed successfully.
error_Invalid_sid:  Invalid sid parameter specified.
error_Drive_not_available:  No drive resource available.
error_Move_failed:  Move operation failed.
error_Exchange_failed:  Exchange operation failed.
error_Erase_failed:  The erase failed due to an I/O error.

DISCUSSION

EXAMPLES

--
METHOD
MSDevice::verifyMode(sid_t sid,INT32 newmode)

Sets the verify mode of the specified surface.

ARGUMENTS
sid(in)
        Surface identifier.
newmode(in)
        If nonzero, sets the verify mode to ON; otherwise verify mode is
set to OFF.

RETURNS
Returns the previous verify mode of the specified surface.

PRECONDITIONS
The MSDevice object was successfully constructed and contains media.
The argument sid is valid.

POSTCONDITIONS
See returns

ERRORS
error_None:  Function completed successfully.
error_Invalid_sid:  Invalid sid parameter specified.
error_Drive_not_available:  No drive resource available.
error_Move_failed:  Move operation failed.
error_Exchange_failed:  Exchange operation failed.

DISCUSSION
The verify mode is applied to any call to write() or writeWOE().  By default,
verify mode is OFF.  Note that, if verify mode is ON and the MSDevice is
unable to put the physical device into write-with-verify mode, any calls to
write() or writeWOE() will fail with the error error_Set_verify_failed.
Note that verify mode is set per surface.

EXAMPLES

--
METHOD
MSDevice::verifyMode(sid_t sid)

Returns the current verify mode of the specified surface.

ARGUMENTS
sid(in)
        Surface identifier.

RETURNS
Returns the current verify mode of the specified surface.

PRECONDITIONS
The MSDevice object was successfully constructed and contains media.
The argument sid is valid.

POSTCONDITIONS
See returns

ERRORS
error_None:  Function completed successfully.

DISCUSSION

EXAMPLES

--
METHOD
MSDevice::allocDrive(sid_t sid)

Allocates an SSDevice object for the specified surface.

ARGUMENTS
sid(in)
        Surface identifier

RETURNS
On success, returns a pointer to an SSDevice object.  On error, returns NULL.

PRECONDITIONS
The MSDevice was succesfully constructed.
The argument sid is valid.

POSTCONDITIONS
If a drive resource is available, a pointer to an SSDevice corresponding to
the drive containing the specified surface will be returned.  

ERRORS
error_None:  Function completed successfully.
error_Invalid_sid:  Invalid sid parameter specified.
error_Drive_not_available:  No drive resource available.
error_Move_failed:  Move operation failed.
error_Exchange_failed:  Exchange operation failed.

DISCUSSION
Allocation of a drive resource to a specific sid requires that, until the
drive resource is freed by a call to freeDrive(), the surface specified by
the sid must remain on-line and accessible via the SSDevice pointer returned
from allocDrive().  NOTE:  The user must NOT delete the SSDevice returned
by this call!  When the user no longer needs it, the user must call 
freeDrive(), which will take care of deallocating the SSDevice object.

EXAMPLES

--
METHOD

MSDevice::freeDrive(SSDevice *drivep)

Frees a drive resource allocated by a previous call to allocDrive().

ARGUMENTS
drivep(in)
        Pointer to an SSDevice allocated by a previous call to allocDrive().

RETURNS
On success, returns 0; on error, returns -1.

PRECONDITIONS
The MSDevice was succesfully constructed.
The argument SSDevice was allocated by a call to allocDrive() (to the same
MSDevice object!)

POSTCONDITIONS
The drive resource will be freed and made available for further allocation.

ERRORS
error_None:  Function completed successfully.
error_Invalid_sid:  Invalid sid parameter specified.
error_Drive_not_available:  No drive resource available.
error_Move_failed:  Move operation failed.
error_Exchange_failed:  Exchange operation failed.

DISCUSSION

EXAMPLES

--
