#ifndef _HPREALMSDEV_ // -*-c++-*-
#define _HPREALMSDEV_

//-----------------------------------------------------------------------------
// nsrRMSdv.h
//
// This file contains declarations and definitions for the HP-UX implementation
// of the MSDevice object.
//
// CLASSES:
//
//      hpACDev
//
//-----------------------------------------------------------------------------
// $Source: /projects/HMS/nsr/udfCore/devs/nsrRMSdv.h,v $
// $Revision: 1.13 $    $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/02/02 10:13:58 $
//-----------------------------------------------------------------------------
//      Unpublished Confidential Information of Hewlett-Packard
//      Company. Do not disclose.  Copyright (c) Hewlett-Packard
//      Company 1995. All rights reserved
// 
// The contents of this software are proprietary and confidential to
// the Hewlett- Packard Company, and are limited in distribution to
// those with a direct need to know.  Individuals having access to
// this software are responsible for maintaining the confidentiality
// of the content and for keeping the software secure when not in use.
// Transfer to any party is strictly forbidden other than as expressly
// permitted in writing by Hewlett-Packard Company.  Unauthorized
// transfer to or possession by any unauthorized party may be a
// criminal offense.
//
//                  RESTRICTED RIGHTS LEGEND
//
//      Use,  duplication,  or disclosure by the U. S. Government is
//      subject to restrictions as set forth in subparagraph (c) (1)
//      (ii) in the Rights in Technical Data and Computer Software
//      clause in DFARS 252.227-7013 or any other successor clause.
//
//                      HEWLETT-PACKARD COMPANY
//                      3000 Hanover St.
//                      Palo Alto, CA  94304 U.S.A.
//
//      Rights for non-DOD U.S. Government Departments and Agencies
//      are as set forth in FAR 52.227-19 (c) (1,2) or any other
//      successor clause.
//-----------------------------------------------------------------------------

#include <nsrLib.h>
#include <nsrRSSdv.h>
#include <nsrscsi.h>

// This contains the header information for the AC Device object,
// which is to be declared inside the NSR class.

// Some useful macros

#define SID_T_SPARED            (SID_T_INVALID - 1)
#define SLEEP_MODE_ON           1
#define SLEEP_MODE_OFF          0

//-----------------------------------------------------------------------------
// CLASS:  hpACDev                                              --JKH
//
// This class is a representation of a Hewlett-Packard magneto-optical
// jukebox device.  It provides a simple surface-driver view of the 
// surfaces within the jukebox.
//
// PUBLIC DATA MEMBERS:
//
//      None.
//
// PUBLIC METHODS:
//
// hpACDev()
//      Constructor and copy constructor.
// ~hpACDev()
//      Destructor.
// numSectors()
//      Returns the number of sectors on the specified surface.
// sectorSize()
//      Returns the sector size of the specified surface.
// read()
//      Reads the specified number of byte from a surface at a given
//      sector offset into the user's buffer.
// write()
//      Writes the specified number of bytes to a surface at a given
//      sector offset from the user's buffer.
// writeWOE()
//      Writes the specified number of bytes to a surface at a given
//      sector offset from the user's buffer in write-without-erase mode.
// erase()
//      Erases the specified number of sectors on a surface at a given
//      sector offset.
// verifyMode()
//      Sets and gets the verify mode for a given surface (whether the
//      surface is in write-with-verify mode).
// allocDrive()
//      Allocates a drive resource for a surface and places the surface
//      in the drive.
// freeDrive()
//      Frees a drive resource allocated by a call to allocDrive().
// error()
//      Returns the current error state of the hpACDev object.
// flush()
//      Flushes any cached information. (This is a nop)
// errorClear()
//      Clears the error state of the hpACDev object.  (This is a nop)
// mediaType()
//      Returns the media type (MO or WORM) for the specified surface.
// verifyBlank()
//      Verifies that the specified range of sectors on a surface are
//      blank (i.e., erased, or unwritten for WORM).
// addSurface()
//      Maps a slot/side address of a surface in the jukebox to an sid_t.
// removeSurface()
//      Removes a slot/side <-> sid_t mapping from the hpACDev.
// sleepMode()
//      Gets or sets the sleep mode for a surface.  (Not implemented fully)
// addDriveMap()
//      Maps a device file to one of the drives in the jukebox.
// elementAddresses()
//      Gets element addresses (mode sense) information from the jukebox.
// elementStatus()
//      Gets element status information from the jukebox.
// senseData()
//      Gets SCSI request sense data from the jukebox.
//
// USAGE NOTES:
//
//-----------------------------------------------------------------------------
// COLLABORATORS:
//
//      NSR::SSDevice
//      NSR::Bitmap
//      hpACDev::ACMapEntry
//      hpACDev::ACMapTable
//      hpACDev::ACDriveEntry
//      hpACDev::ACDriveTable
//
// PRIVATE DATA MEMBERS:
//
// NSR::INT32    fd_                    // File descriptor for picker
// NSR::Error    error_                 // Error state of autochanger
// ACMapTable   mapTable_               // Table of sid_t/device file mappings
// ACDriveTable driveTable_             // Table of allocated drives
// NSR::Bitmap  bitmap_                 // For allocating sid's
// NSR::INT32    sleepMode_             // Okay to sleep on drive resource?
// struct element_addresses eltaddr_    // Element addresses information
// struct sense_2_aligned senseData_    // Buffer for sense data
// NSR::UINT32  senseLength_            // Length of available sense data
//
// PRIVATE METHODS:
//
// acCommand()
//      Sends a command through the HP-UX SCSI passthru driver.
// supportedAC()
//      Determines whether the argument device file corresponds to a supported
//      autochanger type (i.e., an HP autochanger).
// getEltAddr()
//      Gets element addresses information.
// getEltStat()
//      Gets element status information.
// testUnitReady()
//      Sends a test unit ready command to the autochanger.
// moveMedium()
//      Issues a move medium command to the autochanger.
// exchangeMedium()
//      Issues an exchange media command to the autochanger.
// makeDriveDevice()
//      Attempts to make a drive device file for one of the autochanger's
//      drives.  Only works if the process is a root process (or otherwise
//      has permission to use the mknod(2) system call).
//
// IMPLEMENTATION NOTES:
//
//-----------------------------------------------------------------------------

class hpACDev : public NSR::MSDevice
{

#ifdef _COMPILER_BUG_PRIVATE_NESTED_CLASSES_
public:
#endif

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

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

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

    struct ACMapTable {
        ACMapEntry *table_;
        NSR::UINT32       size_;

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

    struct ACDriveEntry {
        NSR::sid_t      sid_;
        NSR::SSDevice * drivep_;
        NSR::String *   devfile_;
        NSR::INT32      rmflag_;        // Remove devfile_ on destruction?
        NSR::INT32      tgt_;           // SCSI Target ID
        NSR::INT32      lun_;           // SCSI LUN ID or LU (s800 9.0x)
        NSR::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(*devfile_);
                }
            }
            if(devfile_ != NULL) {
                delete devfile_;
            }
        }
    };

    struct ACDriveTable {
        ACDriveEntry * table_;
        NSR::UINT32          size_;

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

private:

    //
    // Private data members
    //

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

    //
    // Private member functions
    //

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

public:

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

#endif  // _HPREALMSDEV_
