/* MTX -- SCSI Tape Attached Medium Control Program

   Copyright 1997-1998 Leonard N. Zubkoff <lnz@dandelion.com>
 
   Changes 1999 Eric Lee Green to add support for multi-drive tape changers.

   $Date: 2001/06/19 21:51:32 $
   $Revision: 1.3 $
   See mtx.c for licensing information. 

*/

#ifndef MTX_H  /* protect against multiple includes... */
#define MTX_H 1

/* surround all the Unix-stuff w/ifndef VMS */
#ifdef VMS
#include "[.vms]defs.h"
#else /* all the Unix stuff:  */

#include "config.h"  /* all the autoconf stuff. */

/* all the general Unix includes: */

#include <stdio.h>
#include <errno.h>

#if HAVE_STDLIB_H
#  include <stdlib.h>
#endif

#if HAVE_FCNTL_H
#  include <fcntl.h>
#endif

#if HAVE_SYS_TYPES_H
#  include <sys/types.h>
#endif

#if HAVE_STRING_H
# include <string.h>
#else
# include <strings.h>
#endif

#if HAVE_UNISTD_H
#  include <unistd.h>
#endif

#if HAVE_STDARG_H
#  include <stdarg.h>
#endif

#if HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif

#if HAVE_SYS_IOCTL_H
#  include <sys/ioctl.h>
#endif

/* Now greately modified to use GNU Autoconf stuff: */
/* If we use the 'sg' interface, like Linux, do this: */
#if HAVE_SCSI_SG_H
#  include <scsi/scsi.h>
#  include <scsi/scsi_ioctl.h>
#  include <scsi/sg.h>
typedef int DEVICE_TYPE; /* the sg interface uses this. */
#  define HAVE_GET_ID_LUN 1  /* signal that we have it... */
#endif

/* The 'cam' interface, like FreeBSD: */
#if HAVE_CAMLIB_H
#  include <camlib.h> /* easy (?) access to the CAM user library. */
#  include <cam/cam_ccb.h>
#  include <cam/scsi/scsi_message.h> /* sigh sigh sigh! */
typedef struct cam_device *DEVICE_TYPE;
#endif


/* the 'uscsi' interface, as used on Solaris: */
#if HAVE_SYS_SCSI_IMPL_USCSI_H
#include <sys/scsi/impl/uscsi.h>
typedef int DEVICE_TYPE;
#endif

/* the scsi_ctl interface, as used on HP/UX: */
#if HAVE_SYS_SCSI_CTL_H
#  include <sys/wsio.h>
#  include <sys/spinlock.h>
#  include <sys/scsi.h>
#  include <sys/scsi_ctl.h>
  typedef int DEVICE_TYPE;
#  ifndef VERSION
#     define VERSION "1.2.12 hbb"
#  endif
#endif


/* The 'tm_buf' interface, as used on AIX. */
#ifdef HAVE_SYS_SCSI_H
#include <sys/scsi.h>
#include <sys/scsi_buf.h>
#include <sys/devinfo.h> /* devinfo. */
typedef struct tm_device_type {
  int filenum;
  int id;
  int lun;
  char *DeviceName;
} *DEVICE_TYPE;
    
#endif

   /* the 'dslib' interface, as used on SGI.  */
#if HAVE_DSLIB_H
#include <dslib.h>
typedef dsreq_t *DEVICE_TYPE; /* 64-bit pointers/32bit int on later sgi? */
#endif


#if ((defined(__alpha) && defined(__osf__)) || \
     defined(ultrix) || defined(__ultrix))
#include "du/defs.h"
#endif


#endif /* VMS protect. */

/* Do a test for LITTLE_ENDIAN_BITFIELDS. Use WORDS_BIGENDIAN as set
 * by configure: 
 */

#if WORDS_BIGENDIAN
# define BIG_ENDIAN_BITFIELDS
#else
# define LITTLE_ENDIAN_BITFIELDS
#endif

/* Get rid of some Hocky Pux defines: */
#ifdef S_NO_SENSE
#undef S_NO_SENSE
#endif
#ifdef S_RECOVERED_ERROR
#undef S_RECOVERED_ERROR
#endif
#ifdef S_NOT_READY
#undef S_NOT_READY
#endif
#ifdef S_MEDIUM_ERROR
#undef S_MEDIUM_ERROR
#endif
#ifdef S_HARDWARE_ERROR
#undef S_HARDWARE_ERROR
#endif
#ifdef S_UNIT_ATTENTION
#undef S_UNIT_ATTENTION
#endif
#ifdef S_BLANK_CHECK
#undef S_BLANK_CHECK
#endif
#ifdef S_VOLUME_OVERFLOW
#undef S_VOLUME_OVERFLOW
#endif

/* Note: These are only used for defaults for when we don't have 
 * the element assignment mode page to tell us real amount...
 */
#define MAX_STORAGE_ELEMENTS 64 /* for the BIG jukeboxes! */
#define MAX_TRANSFER_ELEMENTS 2  /* we just do dual-drive for now :-} */
#define MAX_TRANSPORT_ELEMENTS 1 /* we just do one arm for now... */

/* These are flags used for the READ_ELEMENT_STATUS and MOVE_MEDIUM
 * commands:
 */
typedef struct SCSI_Flags_Struct {
  unsigned char eepos;
  unsigned char invert;
  unsigned char no_attached; /* ignore _attached bit */
  unsigned char no_barcodes;  /* don't try to get barcodes. */
  int numbytes;
  int elementtype;
  int numelements;
  int attached;
  int has_barcodes;
} SCSI_Flags_T;

typedef enum { false, true } boolean;


typedef enum { Input, Output } Direction_T;


typedef unsigned char CDB_T[12];


typedef struct Inquiry
{
#ifdef LITTLE_ENDIAN_BITFIELDS
  unsigned char PeripheralDeviceType:5;			/* Byte 0 Bits 0-4 */
  unsigned char PeripheralQualifier:3;			/* Byte 0 Bits 5-7 */
  unsigned char DeviceTypeModifier:7;			/* Byte 1 Bits 0-6 */
  boolean RMB:1;					/* Byte 1 Bit 7 */
  unsigned char ANSI_ApprovedVersion:3;			/* Byte 2 Bits 0-2 */
  unsigned char ECMA_Version:3;				/* Byte 2 Bits 3-5 */
  unsigned char ISO_Version:2;				/* Byte 2 Bits 6-7 */
  unsigned char ResponseDataFormat:4;			/* Byte 3 Bits 0-3 */
  unsigned char :2;					/* Byte 3 Bits 4-5 */
  boolean TrmIOP:1;					/* Byte 3 Bit 6 */
  boolean AENC:1;					/* Byte 3 Bit 7 */
#else
  unsigned char PeripheralQualifier:3;			/* Byte 0 Bits 5-7 */
  unsigned char PeripheralDeviceType:5;			/* Byte 0 Bits 0-4 */
  boolean RMB:1;					/* Byte 1 Bit 7 */
  unsigned char DeviceTypeModifier:7;			/* Byte 1 Bits 0-6 */
  unsigned char ISO_Version:2;				/* Byte 2 Bits 6-7 */
  unsigned char ECMA_Version:3;				/* Byte 2 Bits 3-5 */
  unsigned char ANSI_ApprovedVersion:3;			/* Byte 2 Bits 0-2 */
  boolean AENC:1;					/* Byte 3 Bit 7 */
  boolean TrmIOP:1;					/* Byte 3 Bit 6 */
  unsigned char :2;					/* Byte 3 Bits 4-5 */
  unsigned char ResponseDataFormat:4;			/* Byte 3 Bits 0-3 */
#endif
  unsigned char AdditionalLength;			/* Byte 4 */
  unsigned char :8;					/* Byte 5 */
#ifdef LITTLE_ENDIAN_BITFIELDS
  boolean ADDR16:1;                                    /* Byte 6 bit 0 */
  boolean Obs6_1:1;                                    /* Byte 6 bit 1 */
  boolean Obs6_2:1; /* obsolete */                     /* Byte 6 bit 2 */
  boolean MChngr:1; /* Media Changer */                /* Byte 6 bit 3 */
  boolean MultiP:1;                                    /* Byte 6 bit 4 */
  boolean VS:1;                                        /* Byte 6 bit 5 */
  boolean EncServ:1;                                   /* Byte 6 bit 6 */
  boolean BQue:1;                                      /* Byte 6 bit 7 */
#else
  boolean BQue:1;                                      /* Byte 6 bit 7 */
  boolean EncServ:1;                                   /* Byte 6 bit 6 */
  boolean VS:1;                                        /* Byte 6 bit 5 */
  boolean MultiP:1;                                    /* Byte 6 bit 4 */
  boolean MChngr:1; /* Media Changer */                /* Byte 6 bit 3 */
  boolean Obs6_2:1; /* obsolete */                     /* Byte 6 bit 2 */
  boolean Obs6_1:1;                                    /* Byte 6 bit 1 */
  boolean ADDR16:1;                                    /* Byte 6 bit 0 */
#endif
#ifdef LITTLE_ENDIAN_BITFIELDS
  boolean SftRe:1;					/* Byte 7 Bit 0 */
  boolean CmdQue:1;					/* Byte 7 Bit 1 */
  boolean :1;						/* Byte 7 Bit 2 */
  boolean Linked:1;					/* Byte 7 Bit 3 */
  boolean Sync:1;					/* Byte 7 Bit 4 */
  boolean WBus16:1;					/* Byte 7 Bit 5 */
  boolean WBus32:1;					/* Byte 7 Bit 6 */
  boolean RelAdr:1;					/* Byte 7 Bit 7 */
#else
  boolean RelAdr:1;					/* Byte 7 Bit 7 */
  boolean WBus32:1;					/* Byte 7 Bit 6 */
  boolean WBus16:1;					/* Byte 7 Bit 5 */
  boolean Sync:1;					/* Byte 7 Bit 4 */
  boolean Linked:1;					/* Byte 7 Bit 3 */
  boolean :1;						/* Byte 7 Bit 2 */
  boolean CmdQue:1;					/* Byte 7 Bit 1 */
  boolean SftRe:1;					/* Byte 7 Bit 0 */
#endif
  unsigned char VendorIdentification[8];		/* Bytes 8-15 */
  unsigned char ProductIdentification[16];		/* Bytes 16-31 */
  unsigned char ProductRevisionLevel[4];		/* Bytes 32-35 */
  unsigned char FullProductRevisionLevel[19];           /* bytes 36-54 */
  unsigned char VendorFlags;                            /* byte 55 */
}
Inquiry_T;

/* Hockey Pux may define these. If so, *UN*define them. */
#ifdef ILI
#undef ILI
#endif

#ifdef EOM
#undef EOM
#endif

typedef struct RequestSense
{
#ifdef LITTLE_ENDIAN_BITFIELDS
  unsigned char ErrorCode:7;				/* Byte 0 Bits 0-6 */
  boolean Valid:1;					/* Byte 0 Bit 7 */
#else
  boolean Valid:1;					/* Byte 0 Bit 7 */
  unsigned char ErrorCode:7;				/* Byte 0 Bits 0-6 */
#endif
  unsigned char SegmentNumber;				/* Byte 1 */
#ifdef LITTLE_ENDIAN_BITFIELDS
  unsigned char SenseKey:4;				/* Byte 2 Bits 0-3 */
  unsigned char :1;					/* Byte 2 Bit 4 */
  boolean ILI:1;					/* Byte 2 Bit 5 */
  boolean EOM:1;					/* Byte 2 Bit 6 */
  boolean Filemark:1;					/* Byte 2 Bit 7 */
#else
  boolean Filemark:1;					/* Byte 2 Bit 7 */
  boolean EOM:1;					/* Byte 2 Bit 6 */
  boolean ILI:1;					/* Byte 2 Bit 5 */
  unsigned char :1;					/* Byte 2 Bit 4 */
  unsigned char SenseKey:4;				/* Byte 2 Bits 0-3 */
#endif
  unsigned char Information[4];				/* Bytes 3-6 */
  unsigned char AdditionalSenseLength;			/* Byte 7 */
  unsigned char CommandSpecificInformation[4];		/* Bytes 8-11 */
  unsigned char AdditionalSenseCode;			/* Byte 12 */
  unsigned char AdditionalSenseCodeQualifier;		/* Byte 13 */
  unsigned char :8;					/* Byte 14 */
#ifdef LITTLE_ENDIAN_BITFIELDS
  unsigned char BitPointer:3;                           /* Byte 15 */
  boolean BPV:1;
  unsigned char :2;
  boolean CommandData :1;
  boolean SKSV:1;      
#else
  boolean SKSV:1;      
  boolean CommandData :1;
  unsigned char :2;
  boolean BPV:1;
  unsigned char BitPointer:3;                           /* Byte 15 */
#endif
  unsigned char FieldData[2];       	 		/* Byte 16,17 */
}
RequestSense_T;

/* Okay, now for the element status mode sense page (0x1d): */

typedef struct ElementModeSensePageHeader {
  unsigned char PageCode;  /* byte 0 */
  unsigned char ParameterLengthList;  /* byte 1; */
  unsigned char MediumTransportStartHi; /* byte 2,3 */
  unsigned char MediumTransportStartLo;
  unsigned char NumMediumTransportHi;   /* byte 4,5 */
  unsigned char NumMediumTransportLo;   /* byte 4,5 */
  unsigned char StorageStartHi;         /* byte 6,7 */
  unsigned char StorageStartLo;         /* byte 6,7 */
  unsigned char NumStorageHi;           /* byte 8,9 */
  unsigned char NumStorageLo;           /* byte 8,9 */
  unsigned char ImportExportStartHi;    /* byte 10,11 */
  unsigned char ImportExportStartLo;    /* byte 10,11 */
  unsigned char NumImportExportHi;      /* byte 12,13 */
  unsigned char NumImportExportLo;      /* byte 12,13 */
  unsigned char DataTransferStartHi;    /* byte 14,15 */
  unsigned char DataTransferStartLo;    /* byte 14,15 */
  unsigned char NumDataTransferHi;      /* byte 16,17 */
  unsigned char NumDataTransferLo;      /* byte 16,17 */
  unsigned char Reserved1;             /* byte 18, 19 */
  unsigned char Reserved2;             /* byte 18, 19 */
} ElementModeSensePage_T;

typedef struct ElementModeSenseHeader {
  int MaxReadElementStatusData; /* 'nuff for all of below. */
  int NumElements;              /* total # of elements. */
  int MediumTransportStart;
  int NumMediumTransport;
  int StorageStart;
  int NumStorage;
  int ImportExportStart;
  int NumImportExport;
  int DataTransferStart;
  int NumDataTransfer;
} ElementModeSense_T;


typedef enum ElementTypeCode
{
  AllElementTypes =		0,
  MediumTransportElement =	1,
  StorageElement =		2,
  ImportExportElement =		3,
  DataTransferElement =		4
}
ElementTypeCode_T;


typedef struct ElementStatusDataHeader
{
  unsigned char FirstElementAddressReported[2];		/* Bytes 0-1 */
  unsigned char NumberOfElementsAvailable[2];		/* Bytes 2-3 */
  unsigned char :8;					/* Byte 4 */
  unsigned char ByteCountOfReportAvailable[3];		/* Bytes 5-7 */
}
ElementStatusDataHeader_T;


typedef struct ElementStatusPage
{
  ElementTypeCode_T ElementTypeCode:8;			/* Byte 0 */
#ifdef LITTLE_ENDIAN_BITFIELDS
  unsigned char :6;					/* Byte 1 Bits 0-5 */
  boolean AVolTag:1;					/* Byte 1 Bit 6 */
  boolean PVolTag:1;					/* Byte 1 Bit 7 */
#else
  boolean PVolTag:1;					/* Byte 1 Bit 7 */
  boolean AVolTag:1;					/* Byte 1 Bit 6 */
  unsigned char :6;					/* Byte 1 Bits 0-5 */
#endif
  unsigned char ElementDescriptorLength[2];		/* Bytes 2-3 */
  unsigned char :8;					/* Byte 4 */
  unsigned char ByteCountOfDescriptorDataAvailable[3];	/* Bytes 5-7 */
}
ElementStatusPage_T;

typedef struct Element2StatusPage
{
  ElementTypeCode_T ElementTypeCode:8;			/* Byte 0 */
  unsigned char VolBits ; /* byte 1 */
#define E2_PVOLTAG 0x80
#define E2_AVOLTAG 0x40
  unsigned char ElementDescriptorLength[2];		/* Bytes 2-3 */
  unsigned char :8;					/* Byte 4 */
  unsigned char ByteCountOfDescriptorDataAvailable[3];	/* Bytes 5-7 */
}
Element2StatusPage_T;



typedef struct TransportElementDescriptorShort
{
  unsigned char ElementAddress[2];			/* Bytes 0-1 */
#ifdef LITTLE_ENDIAN_BITFIELDS
  boolean Full:1;					/* Byte 2 Bit 0 */
  unsigned char :1;					/* Byte 2 Bit 1 */
  boolean Except:1;					/* Byte 2 Bit 2 */
  unsigned char :5;					/* Byte 2 Bits 3-7 */
#else
  unsigned char :5;					/* Byte 2 Bits 3-7 */
  boolean Except:1;					/* Byte 2 Bit 2 */
  unsigned char :1;					/* Byte 2 Bit 1 */
  boolean Full:1;					/* Byte 2 Bit 0 */
#endif
  unsigned char :8;					/* Byte 3 */
  unsigned char AdditionalSenseCode;			/* Byte 4 */
  unsigned char AdditionalSenseCodeQualifier;		/* Byte 5 */
  unsigned char :8;					/* Byte 6 */
  unsigned char :8;					/* Byte 7 */
  unsigned char :8;					/* Byte 8 */
#ifdef LITTLE_ENDIAN_BITFIELDS
  unsigned char :6;					/* Byte 9 Bits 0-5 */
  boolean SValid:1;					/* Byte 9 Bit 6 */
  boolean Invert:1;					/* Byte 9 Bit 7 */
#else
  boolean Invert:1;					/* Byte 9 Bit 7 */
  boolean SValid:1;					/* Byte 9 Bit 6 */
  unsigned char :6;					/* Byte 9 Bits 0-5 */
#endif
  unsigned char SourceStorageElementAddress[2];		/* Bytes 10-11 */
}
TransportElementDescriptorShort_T;


typedef struct TransportElementDescriptor
{
  unsigned char ElementAddress[2];			/* Bytes 0-1 */
#ifdef LITTLE_ENDIAN_BITFIELDS
  boolean Full:1;					/* Byte 2 Bit 0 */
  unsigned char :1;					/* Byte 2 Bit 1 */
  boolean Except:1;					/* Byte 2 Bit 2 */
  unsigned char :5;					/* Byte 2 Bits 3-7 */
#else
  unsigned char :5;					/* Byte 2 Bits 3-7 */
  boolean Except:1;					/* Byte 2 Bit 2 */
  unsigned char :1;					/* Byte 2 Bit 1 */
  boolean Full:1;					/* Byte 2 Bit 0 */
#endif
  unsigned char :8;					/* Byte 3 */
  unsigned char AdditionalSenseCode;			/* Byte 4 */
  unsigned char AdditionalSenseCodeQualifier;		/* Byte 5 */
  unsigned char :8;					/* Byte 6 */
  unsigned char :8;					/* Byte 7 */
  unsigned char :8;					/* Byte 8 */
#ifdef LITTLE_ENDIAN_BITFIELDS
  unsigned char :6;					/* Byte 9 Bits 0-5 */
  boolean SValid:1;					/* Byte 9 Bit 6 */
  boolean Invert:1;					/* Byte 9 Bit 7 */
#else
  boolean Invert:1;					/* Byte 9 Bit 7 */
  boolean SValid:1;					/* Byte 9 Bit 6 */
  unsigned char :6;					/* Byte 9 Bits 0-5 */
#endif
  unsigned char SourceStorageElementAddress[2];		/* Bytes 10-11 */
  unsigned char PrimaryVolumeTag[36];          /* barcode */
  unsigned char AlternateVolumeTag[36];        
}
TransportElementDescriptor_T;



/* Now for element status data; */

typedef unsigned char barcode[37];

typedef struct ElementStatus {

  int StorageElementCount;
  int ImportExportCount;
  int DataTransferElementCount;
  int *DataTransferElementAddress;  /* array. */
  int *DataTransferElementSourceStorageElementNumber; /* array */
  barcode *DataTransferPrimaryVolumeTag; /* array. */
  barcode *DataTransferAlternateVolumeTag; /* array. */
  barcode *PrimaryVolumeTag;  /* array */
  barcode *AlternateVolumeTag; /* array */
  int *StorageElementAddress; /* array */
  boolean *StorageElementIsImportExport; /* array */

  int TransportElementAddress;  /* assume only one of those... */

  boolean *DataTransferElementFull; /* array */
  boolean *StorageElementFull;  /* array */

} ElementStatus_T;


/* Now for the SCSI ID and LUN information: */
typedef struct scsi_id {
  int id;
  int lun;
} scsi_id_t;

#define MEDIUM_CHANGER_TYPE 8  /* what type bits are set for medium changers. */

#endif  /* of multi-include protection. */
