Imported Upstream version 1.3.11
[debian/mtx] / mtxl.c
diff --git a/mtxl.c b/mtxl.c
index c92c3480403e32d60441a7235a7772bd49ecd524..f3beea343aa7abc484a24e9359466d9d8a2c8c3f 100644 (file)
--- a/mtxl.c
+++ b/mtxl.c
@@ -1,34 +1,40 @@
 /*  MTX -- SCSI Tape Attached Medium Changer Control Program
 
-  Copyright 1997-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
+       Copyright 1997-1998 by Leonard N. Zubkoff.
+       Copyright 1999-2006 by Eric Lee Green.
+       Copyright 2007 by Robert Nelson <robertn@the-nelsons.org>
 
-$Date: 2002/09/27 17:23:28 $
-$Revision: 1.8.2.7 $
+       $Date: 2007-03-24 18:14:01 -0700 (Sat, 24 Mar 2007) $
+       $Revision: 166 $
 
-  This file created Feb 2000 by Eric Lee Green <eric@badtux.org> from pieces
-  extracted from mtx.c, plus some additional routines. 
+       This file created Feb 2000 by Eric Lee Green <eric@badtux.org> from pieces
+       extracted from mtx.c, plus a near total re-write of most of the beast.
 
-  This program is free software; you may redistribute and/or modify it under
-  the terms of the GNU General Public License Version 2 as published by the
-  Free Software Foundation.
+       This program is free software; you may redistribute and/or modify it under
+       the terms of the GNU General Public License Version 2 as published by the
+       Free Software Foundation.
 
-  This program is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
-  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-  for complete details.
+       This program is distributed in the hope that it will be useful, but
+       WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
+       or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+       for complete details.
 */
 
 
-/* FatalError: changed Feb. 2000 elg@estinc.com to eliminate a buffer
-   overflow :-(. That could be important if mtxl is SUID for some reason. 
+/*
+ *     FatalError: changed Feb. 2000 elg@badtux.org to eliminate a buffer
+ *     overflow :-(. That could be important if mtxl is SUID for some reason. 
 */
 
 #include "mtx.h"
 #include "mtxl.h"
 
+/* #define DEBUG_NSM 1 */
+
 /* #define DEBUG_MODE_SENSE 1 */
 /* #define DEBUG */
 /* #define DEBUG_SCSI */
+#define __WEIRD_CHAR_SUPPRESS 1 
 
 /* zap the following define when we finally add real import/export support */
 #define IMPORT_EXPORT_HACK 1 /* for the moment, import/export == storage */
@@ -37,774 +43,1063 @@ $Revision: 1.8.2.7 $
 
 /* the camlib is used on FreeBSD. */
 #if HAVE_CAMLIB_H
-#  include "scsi_freebsd.c"
+#      include "scsi_freebsd.c"
 #endif
 
 /* the scsi_ctl interface is used on HP/UX. */
 #if HAVE_SYS_SCSI_CTL_H
-#  include "scsi_hpux.c"
+#      include "scsi_hpux.c"
 #endif
 
 /* the 'sg' interface is used on Linux. */
 #if HAVE_SCSI_SG_H
-#  include "scsi_linux.c"
+#      include "scsi_linux.c"
+#endif
+
+/* the IOCTL_SCSI_PASSTHROUGH interface is used on Windows. */
+#if HAVE_DDK_NTDDSCSI_H || defined(_MSC_VER)
+#      include "scsi_win32.c"
 #endif
 
 /* The 'uscsi' interface is used on Solaris. */
 #if HAVE_SYS_SCSI_IMPL_USCSI_H
-#  include "scsi_sun.c"
+#      include "scsi_sun.c"
 #endif
 
-/* The 'tm_buf' interface, as used on AIX. */
-#ifdef HAVE_SYS_SCSI_H
-#  include "scsi_aix.c"
+/* The 'gsc' interface, is used on AIX. */
+#if HAVE_SYS_GSCDDS_H
+#      include "scsi_aix.c"
 #endif
 
 /* The 'dslib' interface is used on SGI. */
 #if HAVE_DSLIB_H
-#  include "scsi_sgi.c"
+#      include "scsi_sgi.c"
 #endif
 
 /* Hmm, dunno what to do about Digital Unix at the moment. */
 #ifdef DIGITAL_UNIX
-#include "du/scsi.c"
+#      include "du/scsi.c"
 #endif
 
-
 #ifdef VMS
-#include "[.vms]scsi.c"
+#      include "[.vms]scsi.c"
 #endif
 
 extern char *argv0; /* something to let us do good error messages. */
 
+/* create a global RequestSenseT value. */
+RequestSense_T scsi_error_sense;
+
 /* Now for some low-level SCSI stuff: */
 
-Inquiry_T *RequestInquiry(DEVICE_TYPE fd, RequestSense_T *RequestSense) {
-  Inquiry_T *Inquiry;
-  CDB_T CDB;
-
-  Inquiry = (Inquiry_T *) xmalloc(sizeof(Inquiry_T));  
-  
-  CDB[0] = 0x12;               /* INQUIRY */
-  CDB[1] = 0;                  /* EVPD = 0 */
-  CDB[2] = 0;                  /* Page Code */
-  CDB[3] = 0;                  /* Reserved */
-  CDB[4] = sizeof(Inquiry_T);  /* Allocation Length */
-  CDB[5] = 0;                  /* Control */
-
-  /* set us a very short timeout, sigh... */
-  SCSI_Set_Timeout(30); /* 30 seconds, sigh! */
-
-  if (SCSI_ExecuteCommand(fd, Input, &CDB, 6,
-                         Inquiry, sizeof(Inquiry_T), RequestSense) != 0)
-    {
-      free(Inquiry);
-      return NULL;  /* sorry! */
-    }
-  return Inquiry;
+Inquiry_T *RequestInquiry(DEVICE_TYPE fd, RequestSense_T *RequestSense)
+{
+       Inquiry_T *Inquiry;
+       CDB_T CDB;
+
+       Inquiry = (Inquiry_T *) xmalloc(sizeof(Inquiry_T));  
+
+       CDB[0] = 0x12;          /* INQUIRY */
+       CDB[1] = 0;                     /* EVPD = 0 */
+       CDB[2] = 0;                     /* Page Code */
+       CDB[3] = 0;                     /* Reserved */
+       CDB[4] = sizeof(Inquiry_T);     /* Allocation Length */
+       CDB[5] = 0;                     /* Control */
+
+       /* set us a very short timeout, sigh... */
+       SCSI_Set_Timeout(30); /* 30 seconds, sigh! */
+
+       if (SCSI_ExecuteCommand(fd, Input, &CDB, 6,
+               Inquiry, sizeof(Inquiry_T), RequestSense) != 0)
+       {
+#ifdef DEBUG
+               fprintf(stderr, "SCSI Inquiry Command failed\n");
+#endif
+               free(Inquiry);
+               return NULL;  /* sorry! */
+       }
+       return Inquiry;
 }
 
 
-int BigEndian16(unsigned char *BigEndianData)
+#if defined(DEBUG_NSM) || defined(DEBUG_EXCHANGE)
+/* DEBUG */
+static void dump_cdb(unsigned char *CDB, int len)
 {
-  return (BigEndianData[0] << 8) + BigEndianData[1];
+       fprintf(stderr,"CDB:");
+       PrintHex(1, CDB, len);
 }
+#endif
 
 
-int BigEndian24(unsigned char *BigEndianData)
+#if defined(DEBUG_NSM) || defined(DEBUG_ADIC)
+/* DEBUG */
+static void dump_data(unsigned char *data, int len)
 {
-  return (BigEndianData[0] << 16) + (BigEndianData[1] << 8) + BigEndianData[2];
+       if (!len)
+       {
+               fprintf(stderr,"**NO DATA**\n");
+               return;
+       }
+
+       fprintf(stderr,"DATA:");
+       PrintHex(1, data, len);
 }
+#endif
 
 
+int BigEndian16(unsigned char *BigEndianData)
+{
+       return (BigEndianData[0] << 8) + BigEndianData[1];
+}
 
 
+int BigEndian24(unsigned char *BigEndianData)
+{
+       return (BigEndianData[0] << 16) + (BigEndianData[1] << 8) + BigEndianData[2];
+}
+
 
 void FatalError(char *ErrorMessage, ...)
 {
 #define FORMAT_BUF_LEN 1024
-  char FormatBuffer[FORMAT_BUF_LEN];
-  char *SourcePointer;
-  char *TargetPointer = FormatBuffer;
-  int Character, LastCharacter = '\0';
-  int numchars = 0;
-
-  va_list ArgumentPointer;
-  va_start(ArgumentPointer, ErrorMessage);
-  /*  SourcePointer = "mtx: "; */
-  sprintf(TargetPointer,"%s: ",argv0);
-  numchars=strlen(TargetPointer);
-  
-  /* while ((Character = *SourcePointer++) != '\0') { */
-  /*  *TargetPointer++ = Character;                   */
-  /*  numchars++;                                     */
-  /*   }                                              */
-  
-  while ((Character = *ErrorMessage++) != '\0')
-    if (LastCharacter == '%')
-      {
-       if (Character == 'm')
-         {
-           SourcePointer = strerror(errno);
-           while ((Character = *SourcePointer++) != '\0') {
-             *TargetPointer++ = Character;
-             numchars++;
-             if (numchars==FORMAT_BUF_LEN-1) break;  
-           }
-           if (numchars==FORMAT_BUF_LEN-1) break;  /* break outer loop... */
-         }
-       else
-         {
-           *TargetPointer++ = '%';
-           *TargetPointer++ = Character;
-           numchars++;
-           if (numchars==FORMAT_BUF_LEN-1) break;
-         }
-       LastCharacter = '\0';
-      }
-    else
-      {
-       if (Character != '%') {
-         *TargetPointer++ = Character;
-         numchars++;
-         if (numchars==FORMAT_BUF_LEN-1) break;
+
+       char    FormatBuffer[FORMAT_BUF_LEN];
+       char    *SourcePointer;
+       char    *TargetPointer = FormatBuffer;
+       char    Character, LastCharacter = '\0';
+       int             numchars = 0;
+
+       va_list ArgumentPointer;
+       va_start(ArgumentPointer, ErrorMessage);
+       /*  SourcePointer = "mtx: "; */
+       sprintf(TargetPointer,"%s: ",argv0);
+       numchars=strlen(TargetPointer);
+
+       while ((Character = *ErrorMessage++) != '\0')
+       {
+               if (LastCharacter == '%')
+               {
+                       if (Character == 'm')
+                       {
+                               SourcePointer = strerror(errno);
+                               while ((Character = *SourcePointer++) != '\0')
+                               {
+                                       *TargetPointer++ = Character;
+                                       numchars++;
+                                       if (numchars == FORMAT_BUF_LEN - 1)
+                                       {
+                                               break;
+                                       }
+                               }
+                               if (numchars == FORMAT_BUF_LEN - 1)
+                               {
+                                       break;  /* break outer loop... */
+                               }
+                       }
+                       else
+                       {
+                               *TargetPointer++ = '%';
+                               *TargetPointer++ = Character;
+                               numchars++;
+                               if (numchars == FORMAT_BUF_LEN - 1)
+                               {
+                                       break;
+                               }
+                       }
+                       LastCharacter = '\0';
+               }
+               else
+               {
+                       if (Character != '%')
+                       {
+                               *TargetPointer++ = Character;
+                               numchars++;
+                               if (numchars == FORMAT_BUF_LEN-1)
+                               {
+                                       break;
+                               }
+                       }
+                       LastCharacter = Character;
+               }
        }
-       LastCharacter = Character;
-      }
-  *TargetPointer = '\0';  /* works even if we had to break from above... */
-  vfprintf(stderr, FormatBuffer, ArgumentPointer);
-  va_end(ArgumentPointer);
+
+       *TargetPointer = '\0';  /* works even if we had to break from above... */
+       vfprintf(stderr, FormatBuffer, ArgumentPointer);
+       va_end(ArgumentPointer);
+
 #ifndef VMS
-  exit(1);
+       exit(1);
 #else
-  sys$exit(VMS_ExitCode);
+       sys$exit(VMS_ExitCode);
 #endif
 }
 
 /* This is a really slow and stupid 'bzero' implementation'... */
-void slow_bzero(char *buffer, int numchars) {
-  while (numchars--) *buffer++ = 0;
+void slow_bzero(char *buffer, int numchars)
+{
+       while (numchars--)
+       {
+               *buffer++ = 0;
+       }
 }
 
-
 /* malloc some memory while checking for out-of-memory conditions. */
 void *xmalloc(size_t Size)
 {
-  void *Result = (void *) malloc(Size);
-  if (Result == NULL)
-    FatalError("cannot allocate %d bytes of memory\n", Size);
-  return Result;
+       void *Result = (void *) malloc(Size);
+       if (Result == NULL)
+       {
+               FatalError("cannot allocate %d bytes of memory\n", Size);
+       }
+       return Result;
 }
 
 /* malloc some memory, zeroing it too: */
 void *xzmalloc(size_t Size)
 {
-  void *Result=(void *)xmalloc(Size);
-  
-  slow_bzero(Result,Size);
-  return Result;
+       void *Result = (void *)xmalloc(Size);
+
+       slow_bzero(Result, Size);
+       return Result;
 }
 
 
 int min(int x, int y)
 {
-  return (x < y ? x : y);
+       return (x < y ? x : y);
 }
 
 
 int max(int x, int y)
 {
-  return (x > y ? x : y);
+       return (x > y ? x : y);
+}
+
+
+/* Okay, this is a hack for the NSM modular jukebox series, which
+ * uses the "SEND DIAGNOSTIC" command to do shit. 
+ */
+
+int SendNSMHack(DEVICE_TYPE MediumChangerFD, NSM_Param_T *nsm_command, 
+               int param_len, int timeout)
+{
+       CDB_T CDB;
+       int list_len = param_len + sizeof(NSM_Param_T) - 2048;
+
+       /* Okay, now for the command: */
+       CDB[0] = 0x1D;
+       CDB[1] = 0x10;
+       CDB[2] = 0;
+       CDB[3] = (unsigned char)(list_len >> 8);
+       CDB[4] = (unsigned char)list_len;
+       CDB[5] = 0;
+
+#ifdef DEBUG_NSM
+       dump_cdb(&CDB,6);
+       dump_data(nsm_command,list_len);
+#endif
+       fflush(stderr);
+       /* Don't set us any timeout unless timeout is > 0 */
+       if (timeout > 0)
+       {
+               SCSI_Set_Timeout(timeout); /* 30 minutes, sigh! */
+       }
+
+       /* Now send the command: */
+       if (SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 6, nsm_command, list_len, &scsi_error_sense))
+       {
+               return -1; /* we failed */
+       }
+       return 0; /* Did it! */
 }
 
+NSM_Result_T *RecNSMHack(      DEVICE_TYPE MediumChangerFD,
+                                                       int param_len, int timeout)
+{
+       CDB_T CDB;
+
+       NSM_Result_T *retval = (NSM_Result_T *)xzmalloc(sizeof(NSM_Result_T));
+
+       int list_len = param_len + sizeof(NSM_Result_T) - 0xffff;
+
+       /* Okay, now for the command: */
+       CDB[0] = 0x1C;
+       CDB[1] = 0x00;
+       CDB[2] = 0;
+       CDB[3] = (unsigned char)(list_len >> 8);
+       CDB[4] = (unsigned char)list_len;
+       CDB[5] = 0;
+
+#ifdef DEBUG_NSM
+       dump_cdb(&CDB,6);
+#endif
+
+       /* Don't set us any timeout unless timeout is > 0 */
+       if (timeout > 0)
+       {
+               SCSI_Set_Timeout(timeout);
+       }
+
+       /* Now send the command: */
+       if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 6, retval, list_len, &scsi_error_sense))
+       {
+               return NULL; /* we failed */
+       }
+
+#ifdef DEBUG_NSM
+       fprintf(stderr,
+                       "page_code=%02x page_len=%d command_code=%s\n",
+                       retval->page_code,
+                       (int) ((retval->page_len_msb << 8) + retval->page_len_lsb),
+       retval->command_code);
+#endif
+
+       return retval; /* Did it! (maybe!)*/
+}
 
 /* Routine to inventory the library. Needed by, e.g., some Breece Hill
  * loaders. Sends an INITIALIZE_ELEMENT_STATUS command. This command
  * has no parameters, such as a range to scan :-(. 
  */
 
-int Inventory(DEVICE_TYPE MediumChangerFD) {
-  CDB_T CDB;
-  RequestSense_T RequestSense;
-  /* okay, now for the command: */
-  CDB[0]=0x07; 
-  CDB[1]=CDB[2]=CDB[3]=CDB[4]=CDB[5]=0;
-
-  /* set us a very long timeout, sigh... */
-  SCSI_Set_Timeout(30*60); /* 30 minutes, sigh! */
-  
-  if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,NULL,0,&RequestSense) != 0) {
-    return -1;  /* could not do! */
-  }
-  return 0; /* did do! */
-}
+int Inventory(DEVICE_TYPE MediumChangerFD)
+{
+       CDB_T   CDB;
 
-/* Routine to send an UNLOAD from the SSC spec to a device. This can be
- * used either to eject a tape (when sent to a tape drive), or to eject
- * a magzine (on some Seagate changers, when sent to LUN 1 ). 
- */
+       /* okay, now for the command: */
+       CDB[0] = 0x07; 
+       CDB[1] = CDB[2] = CDB[3] = CDB[4] = CDB[5] = 0;
 
-int Eject(DEVICE_TYPE fd) {
-  CDB_T CDB;
-  RequestSense_T RequestSense;
-  /* okay, now for the command: */
-  
-  CDB[0]=0x1b;
-  CDB[1]=CDB[2]=CDB[3]=CDB[4]=CDB[5]=0;
-  
-  if (SCSI_ExecuteCommand(fd,Input,&CDB,6,NULL,0,&RequestSense) != 0) {
-    return -1;  /* could not do! */
-  }
-  return 0; /* did do! */
-}  
+       /* set us a very long timeout, sigh... */
+       SCSI_Set_Timeout(30 * 60); /* 30 minutes, sigh! */
+
+       if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,NULL,0,&scsi_error_sense) != 0)
+       {
+#ifdef DEBUG
+               PrintRequestSense(&scsi_error_sense);
+               fprintf(stderr, "Initialize Element Status (0x07) failed\n");
+#endif
+               return -1;  /* could not do! */
+       }
+       return 0; /* did do! */
+}
 
 /* Routine to read the Mode Sense Element Address Assignment Page */
 /* We try to read the page. If we can't read the page, we return NULL.
  * Our caller really isn't too worried about why we could not read the
  * page, it will simply default to some kind of default values. 
  */ 
-ElementModeSense_T *ReadAssignmentPage(DEVICE_TYPE MediumChangerFD) {
-  CDB_T CDB;
-  ElementModeSense_T *retval;  /* processed SCSI. */
-  unsigned char input_buffer[136];
-  ElementModeSensePage_T *sense_page; /* raw SCSI. */
-  RequestSense_T RequestSense;       /* see what retval of raw SCSI was... */
-  
-  /* okay, now for the command: */
-  CDB[0]=0x1a; /* Mode Sense(6) */
-  CDB[1]=0; 
-  CDB[2]=0x1d; /* Mode Sense Element Address Assignment Page */
-  CDB[3]=0;
-  CDB[4]=136; /* allocation_length... */
-  CDB[5]=0;
-
-  /* clear the data buffer: */
-  slow_bzero((char *)&RequestSense,sizeof(RequestSense_T));
-  slow_bzero((char *)input_buffer,sizeof(input_buffer));
-
-  if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,
-                         &input_buffer,sizeof(input_buffer),&RequestSense) != 0) {
+ElementModeSense_T *ReadAssignmentPage(DEVICE_TYPE MediumChangerFD)
+{
+       CDB_T CDB;
+       ElementModeSense_T *retval;  /* processed SCSI. */
+       unsigned char input_buffer[136];
+       ElementModeSensePage_T *sense_page; /* raw SCSI. */
+
+       /* okay, now for the command: */
+       CDB[0] = 0x1A; /* Mode Sense(6) */
+       CDB[1] = 0x08; 
+       CDB[2] = 0x1D; /* Mode Sense Element Address Assignment Page */
+       CDB[3] = 0;
+       CDB[4] = 136; /* allocation_length... */
+       CDB[5] = 0;
+
+       /* clear the data buffer: */
+       slow_bzero((char *)&scsi_error_sense, sizeof(RequestSense_T));
+       slow_bzero((char *)input_buffer, sizeof(input_buffer));
+
+       if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 6,
+                                                       &input_buffer, sizeof(input_buffer), &scsi_error_sense) != 0)
+       {
+               PrintRequestSense(&scsi_error_sense);
+               fprintf(stderr,"Mode sense (0x1A) for Page 0x1D failed\n");
+               fflush(stderr);
+               return NULL; /* sorry, couldn't do it. */
+       }
+
+       /* Could do it, now build return value: */
+
 #ifdef DEBUG_MODE_SENSE
-    fprintf(stderr,"Could not execute mode sense...\n");
-    fflush(stderr);
+       PrintHex(0, input_buffer, 30);
 #endif
-    return NULL; /* sorry, couldn't do it. */
-  }
 
-  /* Could do it, now build return value: */
+       /* first, skip past: mode data header, and block descriptor header if any */
+       sense_page=(ElementModeSensePage_T *)(input_buffer+4+input_buffer[3]);
 
 #ifdef DEBUG_MODE_SENSE
-  {
-    int i;
-    for (i=0;i<30;i+=3) {
-      fprintf(stderr,"ib[%d]=%d ib[%d]=%d ib[%d]=%d\n",
-             i,input_buffer[i],i+1,input_buffer[i+1],
-             i+2,input_buffer[i+2]);
-      /*  fprintf(stderr,"input_buffer[0]=%d input_buffer[3]=%d\n",
-       *         input_buffer[0], input_buffer[3]);
-       */
-    }
-    fflush(stderr);
-  }
-#endif
-  /* first, skip past: mode data header, and block descriptor header if any */
-  sense_page=(ElementModeSensePage_T *)(input_buffer+4+input_buffer[3]);
+       fprintf(stderr,"*sense_page=%x  %x\n",*((unsigned char *)sense_page),sense_page->PageCode);
+       fflush(stderr);
+#endif
 
-#ifdef DEBUG_MODE_SENSE
-  fprintf(stderr,"*sense_page=%x  %x\n",*((unsigned char *)sense_page),sense_page->PageCode);
-  fflush(stderr);
-#endif  
+       retval = (ElementModeSense_T *)xzmalloc(sizeof(ElementModeSense_T));
 
-  retval=(ElementModeSense_T *) xzmalloc(sizeof(ElementModeSense_T));
+       /* Remember that all SCSI values are big-endian: */
+       retval->MediumTransportStart =
+               (((int)sense_page->MediumTransportStartHi) << 8) +
+               sense_page->MediumTransportStartLo;
 
-  /* Remember that all SCSI values are big-endian: */
-  retval->MediumTransportStart=(((int)sense_page->MediumTransportStartHi)<<8) +
-    sense_page->MediumTransportStartLo;
-  retval->NumMediumTransport=(((int)(sense_page->NumMediumTransportHi))<<8) +
-    sense_page->NumMediumTransportLo;
+       retval->NumMediumTransport =
+               (((int)(sense_page->NumMediumTransportHi))<<8) +
+               sense_page->NumMediumTransportLo;
 
-  /* HACK! Some HP autochangers don't report NumMediumTransport right! */
-  /* ARG! TAKE OUT THE %#@!# HACK! */
+       /* HACK! Some HP autochangers don't report NumMediumTransport right! */
+       /* ARG! TAKE OUT THE %#@!# HACK! */
 #ifdef STUPID_DUMB_IDIOTIC_HP_LOADER_HACK
-  if (!retval->NumMediumTransport) {
-    retval->NumMediumTransport=1;
-  }
+       if (!retval->NumMediumTransport)
+       {
+               retval->NumMediumTransport = 1;
+       }
 #endif
 
 #ifdef DEBUG_MODE_SENSE
-  fprintf(stderr,"rawNumStorage= %d %d    rawNumImportExport= %d %d\n",
-         sense_page->NumStorageHi,sense_page->NumStorageLo,
-         sense_page->NumImportExportHi, sense_page->NumImportExportLo);
-  fprintf(stderr,"rawNumTransport=%d %d  rawNumDataTransfer=%d %d\n",
-         sense_page->NumMediumTransportHi,sense_page->NumMediumTransportLo,
-         sense_page->NumDataTransferHi,sense_page->NumDataTransferLo);
-  fflush(stderr);
-#endif
-
-  retval->StorageStart=(((int)(sense_page->StorageStartHi))<<8) +
-    sense_page->StorageStartLo;
-  retval->NumStorage=(((int)(sense_page->NumStorageHi))<<8) + 
-    sense_page->NumStorageLo;
-  retval->ImportExportStart=(((int)(sense_page->ImportExportStartHi))<<8)+
-    sense_page->ImportExportStartLo; 
-  retval->NumImportExport=(((int)(sense_page->NumImportExportHi))<<8)+
-    sense_page->NumImportExportLo;
-  retval->DataTransferStart=(((int)(sense_page->DataTransferStartHi))<<8)+
-    sense_page->DataTransferStartLo;
-  retval->NumDataTransfer=(((int)(sense_page->NumDataTransferHi))<<8)+
-    sense_page->NumDataTransferLo;
-
-  /* allocate a couple spares 'cause some HP autochangers and maybe others
-   * don't properly report the robotics arm(s) count here... 
-   */
-  retval->NumElements=retval->NumStorage+retval->NumImportExport+
-    retval->NumDataTransfer+retval->NumMediumTransport;
-
-  retval->MaxReadElementStatusData=(sizeof(ElementStatusDataHeader_T) +
-                                   4 * sizeof(ElementStatusPage_T) +
-                                   (retval->NumElements) *
-                                     sizeof(TransportElementDescriptor_T));
+       fprintf(stderr, "rawNumStorage= %d %d    rawNumImportExport= %d %d\n",
+                       sense_page->NumStorageHi, sense_page->NumStorageLo,
+                       sense_page->NumImportExportHi, sense_page->NumImportExportLo);
+       fprintf(stderr, "rawNumTransport=%d %d  rawNumDataTransfer=%d %d\n",
+                       sense_page->NumMediumTransportHi, sense_page->NumMediumTransportLo,
+                       sense_page->NumDataTransferHi, sense_page->NumDataTransferLo);
+       fflush(stderr);
+#endif
+
+       retval->StorageStart =
+               ((int)sense_page->StorageStartHi << 8) + sense_page->StorageStartLo;
+
+       retval->NumStorage =
+               ((int)sense_page->NumStorageHi << 8) + sense_page->NumStorageLo;
+
+       retval->ImportExportStart =
+               ((int)sense_page->ImportExportStartHi << 8) + sense_page->ImportExportStartLo; 
+
+       retval->NumImportExport =
+               ((int)sense_page->NumImportExportHi << 8) + sense_page->NumImportExportLo;
 
+       retval->DataTransferStart =
+               ((int)sense_page->DataTransferStartHi << 8) + sense_page->DataTransferStartLo;
+
+       retval->NumDataTransfer =
+               ((int)sense_page->NumDataTransferHi << 8) + sense_page->NumDataTransferLo;
+
+       /* allocate a couple spares 'cause some HP autochangers and maybe others
+       * don't properly report the robotics arm(s) count here... 
+       */
+       retval->NumElements =
+               retval->NumStorage+retval->NumImportExport +
+               retval->NumDataTransfer+retval->NumMediumTransport;
+
+       retval->MaxReadElementStatusData =
+               (sizeof(ElementStatusDataHeader_T) +
+               4 * sizeof(ElementStatusPage_T) +
+               retval->NumElements * sizeof(TransportElementDescriptor_T));
 
 #ifdef IMPORT_EXPORT_HACK
-  retval->NumStorage=retval->NumStorage+retval->NumImportExport;
+       retval->NumStorage = retval->NumStorage+retval->NumImportExport;
 #endif
 
 #ifdef DEBUG_MODE_SENSE
-  fprintf(stderr,"NumMediumTransport=%d\n",retval->NumMediumTransport);
-  fprintf(stderr,"NumStorage=%d\n",retval->NumStorage);
-  fprintf(stderr,"NumImportExport=%d\n",retval->NumImportExport);
-  fprintf(stderr,"NumDataTransfer=%d\n",retval->NumDataTransfer);
-  fprintf(stderr,"MaxReadElementStatusData=%d\n",retval->MaxReadElementStatusData);
-  fprintf(stderr,"NumElements=%d\n",retval->NumElements);
-  fflush(stderr);
-#endif
-  
-  return retval;
+       fprintf(stderr, "NumMediumTransport=%d\n", retval->NumMediumTransport);
+       fprintf(stderr, "NumStorage=%d\n", retval->NumStorage);
+       fprintf(stderr, "NumImportExport=%d\n", retval->NumImportExport);
+       fprintf(stderr, "NumDataTransfer=%d\n", retval->NumDataTransfer);
+       fprintf(stderr, "MaxReadElementStatusData=%d\n", retval->MaxReadElementStatusData);
+       fprintf(stderr, "NumElements=%d\n", retval->NumElements);
+       fflush(stderr);
+#endif
+
+       return retval;
 }
 
 static void FreeElementData(ElementStatus_T *data)
 {
-  free(data->DataTransferElementAddress);
-  free(data->DataTransferElementSourceStorageElementNumber);
-  free(data->DataTransferPrimaryVolumeTag);
-  free(data->DataTransferAlternateVolumeTag);
-  free(data->PrimaryVolumeTag);
-  free(data->AlternateVolumeTag);
-  free(data->StorageElementAddress);
-  free(data->StorageElementIsImportExport);
-  free(data->StorageElementFull);
-  free(data->DataTransferElementFull);
+       free(data->DataTransferElementAddress);
+       free(data->DataTransferElementSourceStorageElementNumber);
+       free(data->DataTransferPrimaryVolumeTag);
+       free(data->DataTransferAlternateVolumeTag);
+       free(data->PrimaryVolumeTag);
+       free(data->AlternateVolumeTag);
+       free(data->StorageElementAddress);
+       free(data->StorageElementIsImportExport);
+       free(data->StorageElementFull);
+       free(data->DataTransferElementFull);
 }
-  
-       
+
 
 /* allocate data  */
 
-static ElementStatus_T *AllocateElementData(ElementModeSense_T *mode_sense) {
-  ElementStatus_T *retval;
-
-  retval=(ElementStatus_T *) xzmalloc(sizeof(ElementStatus_T));
-
-  /* now for the invidual component arrays.... */
-
-  retval->DataTransferElementAddress = (int *) xzmalloc(sizeof(int)*
-                                    (mode_sense->NumDataTransfer + 1));
-  retval->DataTransferElementSourceStorageElementNumber = 
-    (int *) xzmalloc(sizeof(int)*(mode_sense->NumDataTransfer+1));
-  retval->DataTransferPrimaryVolumeTag=
-    (barcode *)xzmalloc(sizeof(barcode)*(mode_sense->NumDataTransfer+1));
-  retval->DataTransferAlternateVolumeTag=
-    (barcode *)xzmalloc(sizeof(barcode)*(mode_sense->NumDataTransfer+1));
-  retval->PrimaryVolumeTag=
-    (barcode *)xzmalloc(sizeof(barcode)*(mode_sense->NumStorage+1));
-  retval->AlternateVolumeTag=
-    (barcode *)xzmalloc(sizeof(barcode)*(mode_sense->NumStorage+1));
-  retval->StorageElementAddress=
-    (int *)xzmalloc(sizeof(int)*(mode_sense->NumStorage+1));
-  retval->StorageElementIsImportExport=
-    (boolean *)xzmalloc(sizeof(boolean)*(mode_sense->NumStorage+1));    
-  retval->StorageElementFull=
-    (boolean *)xzmalloc(sizeof(boolean)*(mode_sense->NumStorage+1));    
-  retval->DataTransferElementFull=
-    (boolean *)xzmalloc(sizeof(boolean)*(mode_sense->NumDataTransfer+1));
-  
-  return retval; /* sigh! */
+static ElementStatus_T *AllocateElementData(ElementModeSense_T *mode_sense)
+{
+       ElementStatus_T *retval;
+
+       retval = (ElementStatus_T *)xzmalloc(sizeof(ElementStatus_T));
+
+       /* now for the invidual component arrays.... */
+
+       retval->DataTransferElementAddress =
+               (int *)xzmalloc(sizeof(int) * (mode_sense->NumDataTransfer + 1));
+       retval->DataTransferElementSourceStorageElementNumber = 
+               (int *)xzmalloc(sizeof(int) * (mode_sense->NumDataTransfer + 1));
+       retval->DataTransferPrimaryVolumeTag =
+               (barcode *)xzmalloc(sizeof(barcode) * (mode_sense->NumDataTransfer + 1));
+       retval->DataTransferAlternateVolumeTag =
+               (barcode *)xzmalloc(sizeof(barcode) * (mode_sense->NumDataTransfer + 1));
+       retval->PrimaryVolumeTag =
+               (barcode *)xzmalloc(sizeof(barcode) * (mode_sense->NumStorage + 1));
+       retval->AlternateVolumeTag =
+               (barcode *)xzmalloc(sizeof(barcode) * (mode_sense->NumStorage + 1));
+       retval->StorageElementAddress =
+               (int *)xzmalloc(sizeof(int) * (mode_sense->NumStorage + 1));
+       retval->StorageElementIsImportExport =
+               (boolean *)xzmalloc(sizeof(boolean) * (mode_sense->NumStorage + 1));
+       retval->StorageElementFull =
+               (boolean *)xzmalloc(sizeof(boolean) * (mode_sense->NumStorage + 1));
+       retval->DataTransferElementFull =
+               (boolean *)xzmalloc(sizeof(boolean) * (mode_sense->NumDataTransfer + 1));
+
+       return retval; /* sigh! */
 }
 
 
-void copy_barcode(unsigned char *src, unsigned char *dest) {
-  int i;
-  
-  for (i=0; i < 36; i++) {
-    *dest=*src++;
-#ifdef __WEIRD_CHAR_SUPPRESS
-    if ((*dest < 32) || (*dest > 127))
-       *dest = '\0';
-#endif
-     dest++;
-  }
-  dest=0; /* null-terminate, sigh. */ 
-}
+void copy_barcode(unsigned char *src, unsigned char *dest)
+{
+       int i;
+
+       for (i=0; i < 36; i++)
+       {
+               *dest = *src++;
 
+               if ((*dest < 32) || (*dest > 127))
+               {
+                       *dest = '\0';
+               }
+
+               dest++;
+       }
+       *dest = 0; /* null-terminate */ 
+}
 
 /* This #%!@# routine has more parameters than I can count! */
-unsigned char *SendElementStatusRequest(DEVICE_TYPE MediumChangerFD,
+static unsigned char *SendElementStatusRequestActual(
+                                       DEVICE_TYPE MediumChangerFD,
                                        RequestSense_T *RequestSense,
                                        Inquiry_T *inquiry_info, 
                                        SCSI_Flags_T *flags,
                                        int ElementStart,
                                        int NumElements,
                                        int NumBytes
-                                       ) {
-
-  CDB_T CDB;
-  boolean is_attached = false;
+                                       )
+{
+       CDB_T CDB;
+       boolean is_attached = false;
 
-  unsigned char *DataBuffer; /* size of data... */
+       unsigned char *DataBuffer; /* size of data... */
 
 #ifdef HAVE_GET_ID_LUN
-  scsi_id_t *scsi_id;
+       scsi_id_t *scsi_id;
 #endif
-  if ((inquiry_info->MChngr) && (inquiry_info->PeripheralDeviceType != MEDIUM_CHANGER_TYPE)) {
-    is_attached=true;
-  }
-  if (flags->no_attached) { /* override, sigh */ 
-    is_attached=false;
-  }
+       if (inquiry_info->MChngr && 
+               inquiry_info->PeripheralDeviceType != MEDIUM_CHANGER_TYPE)
+       {
+               is_attached = true;
+       }
+
+       if (flags->no_attached)
+       {
+               /* override, sigh */ 
+               is_attached = false;
+       }
+
+       DataBuffer = (unsigned char *)xzmalloc(NumBytes + 1);
 
-  DataBuffer=(unsigned char *) xmalloc(NumBytes+1);
+       slow_bzero((char *)RequestSense, sizeof(RequestSense_T));
 
-  slow_bzero((char *)RequestSense,sizeof(RequestSense_T));
 #ifdef HAVE_GET_ID_LUN
-  scsi_id = SCSI_GetIDLun(MediumChangerFD);
+       scsi_id = SCSI_GetIDLun(MediumChangerFD);
 #endif
 
+       CDB[0] = 0xB8;          /* READ ELEMENT STATUS */
+
+       if (is_attached)
+       {
+               CDB[0] = 0xB4;  /* whoops, READ_ELEMENT_STATUS_ATTACHED! */ 
+       }
 
-  CDB[0] = 0xB8;               /* READ ELEMENT STATUS */
-  if (is_attached) {
-    CDB[0] = 0xB4;  /* whoops, READ_ELEMENT_STATUS_ATTACHED! */ 
-  }
 #ifdef HAVE_GET_ID_LUN
-  CDB[1] = (scsi_id->lun << 5) | ((flags->no_barcodes) ? 0 : 0x10) | flags->elementtype;  /* Lun + VolTag + Type code */
-  free(scsi_id);
+       CDB[1] = (scsi_id->lun << 5) | ((flags->no_barcodes) ? 
+               0 : 0x10) | flags->elementtype;  /* Lun + VolTag + Type code */
+       free(scsi_id);
 #else
-  CDB[1] = ((flags->no_barcodes) ? 0 : 0x10) | flags->elementtype;             /* Element Type Code = 0, VolTag = 1 */
+       /* Element Type Code = 0, VolTag = 1 */
+       CDB[1] = (unsigned char)((flags->no_barcodes ? 0 : 0x10) | flags->elementtype);
 #endif
-  CDB[2] = (ElementStart >> 8) & 0xff; /* Starting Element Address MSB */
-  CDB[3] = ElementStart & 0xff;                /* Starting Element Address LSB */
+       /* Starting Element Address */
+       CDB[2] = (unsigned char)(ElementStart >> 8);
+       CDB[3] = (unsigned char)ElementStart;
+
+       /* Number Of Elements */
+       CDB[4]= (unsigned char)(NumElements >> 8);
+       CDB[5]= (unsigned char)NumElements;
+
+       CDB[6] = 0;                     /* Reserved */
+
+       /* allocation length */
+       CDB[7]= (unsigned char)(NumBytes >> 16);
+       CDB[8]= (unsigned char)(NumBytes >> 8);
+       CDB[9]= (unsigned char)NumBytes;
+
+       CDB[10] = 0;                    /* Reserved */
+       CDB[11] = 0;                    /* Control */
 
+#ifdef DEBUG_BARCODE
+       fprintf(stderr,"CDB:\n");
+       PrintHex(2, CDB, 12);
+#endif
 
-  CDB[4]= (NumElements >> 8) & 0xff;     /* Number Of Elements MSB */
-  CDB[5]= NumElements & 0xff ;        /* Number of elements LSB */
+       if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 12,
+               DataBuffer,NumBytes, RequestSense) != 0)
+       {
 
-  /*  CDB[5]=127; */ /* test */
 #ifdef DEBUG
-  fprintf(stderr,"CDB[5]=%d\n" , CDB[5]);
+               fprintf(stderr, "Read Element Status (0x%02X) failed\n", CDB[0]);
 #endif
-  CDB[6] = 0;                  /* Reserved */
 
-  CDB[7]= (NumBytes >> 16) & 0xff; /* allocation length MSB */
-  CDB[8]= (NumBytes >> 8) & 0xff;
-  CDB[9]= NumBytes & 0xff;   /* allocation length LSB */
+               /*
+                       First see if we have sense key of 'illegal request',
+                       additional sense code of '24', additional sense qualfier of 
+                       '0', and field in error of '4'. This means that we issued a request
+                       w/bar code reader and did not have one, thus must re-issue the request
+                       w/out barcode :-(.
+               */
+
+               /*
+                       Most autochangers and tape libraries set a sense key here if
+                       they do not have a bar code reader. For some reason, the ADIC DAT
+                       uses a different sense key? Let's retry w/o bar codes for *ALL*
+                       sense keys.
+               */
+
+               if (RequestSense->SenseKey > 1)
+               {
+                       /* we issued a code requesting bar codes, there is no bar code reader? */
+                       /* clear out our sense buffer first... */
+                       slow_bzero((char *)RequestSense, sizeof(RequestSense_T));
 
-  CDB[10] = 0;                 /* Reserved */
-  CDB[11] = 0;                 /* Control */
+                       CDB[1] &= ~0x10; /* clear bar code flag! */
 
 #ifdef DEBUG_BARCODE
-  {
-    int i;
-    fprintf(stderr,"CDB= ");
-    for (i=0;i<12;i++) {
-      fprintf(stderr,"%x ",CDB[i]);
-    }
-    fprintf(stderr,"\n");
-    fflush(stderr);
-  }
-#endif
-
-  if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 12,
-                         DataBuffer,NumBytes, RequestSense) != 0){
-    /* okay, first see if we have sense key of 'illegal request',
-       additional sense code of '24', additional sense qualfier of 
-       '0', and field in error of '4'. This means that we issued a request
-       w/bar code reader and did not have one, thus must re-issue the request
-       w/out barcode :-(.
-    */
-    
-    /* Okay, most autochangers and tape libraries set a sense key here if
-     * they do not have a bar code reader. For some reason, the ADIC DAT
-     * uses a different sense key? Let's retry w/o bar codes for *ALL*
-     * sense keys, sigh sigh sigh. 
-     */
-    
-    if ( RequestSense->SenseKey > 1 ) {
-      /* we issued a code requesting bar codes, there is no bar code reader? */
-      /* clear out our sense buffer first... */
-      slow_bzero((char *)RequestSense,sizeof(RequestSense_T));
-
-      CDB[1] &= ~0x10; /* clear bar code flag! */
+                       fprintf(stderr,"CDB:\n");
+                       PrintHex(2, CDB, 12);
+#endif
 
-#ifdef DEBUG_BARCODE
-      {
-       int i;
-       fprintf(stderr,"CDB= ");
-       for (i=0;i<12;i++) {
-         fprintf(stderr,"%x ",CDB[i]);
+                       if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 12,
+                                                                       DataBuffer, NumBytes, RequestSense) != 0)
+                       {
+                               free(DataBuffer);
+                               return NULL;
+                       }
+               }
+               else
+               {
+                       free(DataBuffer);
+                       return NULL;
+               }
        }
-       fprintf(stderr,"\n");
-       fflush(stderr);
-      }
-#endif
-      
-      if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 12,
-                             DataBuffer, NumBytes, RequestSense) != 0){
-       free(DataBuffer);
-       return NULL;
-      }
-    } else {
-      free(DataBuffer);
-      return NULL;
-    }
-  }
 
 #ifdef DEBUG_BARCODE
-  /* print a bunch of extra debug data :-(.  */
-  PrintRequestSense(RequestSense); /* see what it sez :-(. */
-  {
-    int i;
-    fprintf(stderr,"Data:");
-    for (i=0;i<40;i++) {
-      fprint(stderr,"%02x ",DataBuffer[i]);
-    }
-    fprintf(stderr,"\n");
-  }
+       /* print a bunch of extra debug data :-(.  */
+       PrintRequestSense(RequestSense); /* see what it sez :-(. */
+       fprintf(stderr,"Data:\n");
+       PrintHex(2, DataBuffer, 40);
 #endif  
-  return DataBuffer; /* we succeeded! */
+       return DataBuffer; /* we succeeded! */
+}
+
+
+unsigned char *SendElementStatusRequest(DEVICE_TYPE MediumChangerFD,
+                                                                               RequestSense_T *RequestSense,
+                                                                               Inquiry_T *inquiry_info, 
+                                                                               SCSI_Flags_T *flags,
+                                                                               int ElementStart,
+                                                                               int NumElements,
+                                                                               int NumBytes
+                                                                               )
+{
+       unsigned char *DataBuffer; /* size of data... */
+       int real_numbytes;
+
+       DataBuffer = SendElementStatusRequestActual(MediumChangerFD,
+                                                                                               RequestSense,
+                                                                                               inquiry_info,
+                                                                                               flags,
+                                                                                               ElementStart,
+                                                                                               NumElements,
+                                                                                               NumBytes
+                                                                                               );
+       /*
+               One weird loader wants either 8 or BYTE_COUNT_OF_REPORT
+               values for the ALLOCATION_LENGTH. Give it what it wants
+               if we get an Sense Key of 05 Illegal Request with a 
+               CDB position of 7 as the field in error.
+       */
+
+       if (DataBuffer == NULL &&
+               RequestSense->SenseKey == 5 &&
+               RequestSense->CommandData &&
+               RequestSense->BitPointer == 7)
+       {
+               NumBytes=8; /* send an 8 byte request */
+               DataBuffer=SendElementStatusRequestActual(      MediumChangerFD,
+                                                                                                       RequestSense,
+                                                                                                       inquiry_info,
+                                                                                                       flags,
+                                                                                                       ElementStart,
+                                                                                                       NumElements,
+                                                                                                       NumBytes
+                                                                                                       );
+       }
+
+       /* the above code falls thru into this: */
+       if (DataBuffer != NULL)
+       {
+               /* see if we need to retry with a bigger NumBytes: */
+               real_numbytes = ((int)DataBuffer[5] << 16) +
+                                               ((int)DataBuffer[6] << 8) +
+                                                (int)DataBuffer[7] + 8;
+
+               if (real_numbytes > NumBytes)
+               {
+                       /* uh-oh, retry! */
+                       free(DataBuffer); /* solve memory leak */
+                       DataBuffer = SendElementStatusRequestActual(MediumChangerFD,
+                                                                                                               RequestSense,
+                                                                                                               inquiry_info,
+                                                                                                               flags,
+                                                                                                               ElementStart,
+                                                                                                               NumElements,
+                                                                                                               real_numbytes
+                                                                                                               );
+               }
+       }
+
+       return DataBuffer;
 }
 
+
+
 /******************* ParseElementStatus ***********************************/
 /* This does the actual grunt work of parsing element status data. It fills
  * in appropriate pieces of its input data. It may be called multiple times
  * while we are gathering element status.
  */
 
-static void ParseElementStatus(int *EmptyStorageElementAddress,
-                              int *EmptyStorageElementCount,
-                              unsigned char *DataBuffer,
-                              ElementStatus_T *ElementStatus,
-                              ElementModeSense_T *mode_sense
-
-                              )   {
-    
-    unsigned char *DataPointer=DataBuffer;
-    TransportElementDescriptor_T TEBuf;
-    TransportElementDescriptor_T *TransportElementDescriptor;
-    ElementStatusDataHeader_T *ElementStatusDataHeader;
-    Element2StatusPage_T *ElementStatusPage;
-    Element2StatusPage_T ESBuf;
-    int ElementCount;
-    int TransportElementDescriptorLength;
-    int BytesAvailable; 
-    
-    ElementStatusDataHeader = (ElementStatusDataHeader_T *) DataBuffer;
-
-    
-
-  ElementStatusDataHeader = (ElementStatusDataHeader_T *) DataPointer;
-  DataPointer += sizeof(ElementStatusDataHeader_T);
-  ElementCount =
-    BigEndian16(ElementStatusDataHeader->NumberOfElementsAvailable);
+static void ParseElementStatus(        int *EmptyStorageElementAddress,
+                                                               int *EmptyStorageElementCount,
+                                                               unsigned char *DataBuffer,
+                                                               ElementStatus_T *ElementStatus,
+                                                               ElementModeSense_T *mode_sense,
+                                                               int *pNextElement
+                                                               )
+{
+       unsigned char *DataPointer = DataBuffer;
+       TransportElementDescriptor_T TEBuf;
+       TransportElementDescriptor_T *TransportElementDescriptor;
+       ElementStatusDataHeader_T *ElementStatusDataHeader;
+       Element2StatusPage_T *ElementStatusPage;
+       Element2StatusPage_T ESBuf;
+       int ElementCount;
+       int TransportElementDescriptorLength;
+       int BytesAvailable;
+       int ImportExportIndex;
+
+       ElementStatusDataHeader = (ElementStatusDataHeader_T *) DataPointer;
+       DataPointer += sizeof(ElementStatusDataHeader_T);
+       ElementCount =
+               BigEndian16(ElementStatusDataHeader->NumberOfElementsAvailable);
+
 #ifdef DEBUG
-      fprintf(stderr,"ElementCount=%d\n",ElementCount);
-      fflush(stderr);
+       fprintf(stderr,"ElementCount=%d\n",ElementCount);
+       fflush(stderr);
+#endif
+
+       while (ElementCount > 0)
+       {
+#ifdef DEBUG
+               int got_element_num=0;
+
+               fprintf(stderr,"Working on element # %d Element Count %d\n",got_element_num,ElementCount);
+               got_element_num++;
 #endif
-  while (ElementCount > 0)
-    {
+
+               memcpy(&ESBuf, DataPointer, sizeof(ElementStatusPage_T));
+               ElementStatusPage = &ESBuf;
+               DataPointer += sizeof(ElementStatusPage_T);
+
+               TransportElementDescriptorLength =
+                       BigEndian16(ElementStatusPage->ElementDescriptorLength);
+
+               if (TransportElementDescriptorLength <
+                       sizeof(TransportElementDescriptorShort_T))
+               {
+                       /* Foo, Storage Element Descriptors can be 4 bytes?! */
+                       if ((ElementStatusPage->ElementTypeCode != MediumTransportElement &&
+                               ElementStatusPage->ElementTypeCode != StorageElement &&
+                               ElementStatusPage->ElementTypeCode != ImportExportElement ) ||
+                               TransportElementDescriptorLength < 4)
+                       {
 #ifdef DEBUG
-      int got_element_num=0;
-      
-      fprintf(stderr,"Working on element # %d Element Count %d\n",got_element_num,ElementCount);
-      got_element_num++;
-#endif
-
-      memcpy(&ESBuf, DataPointer, sizeof(ElementStatusPage_T));
-      ElementStatusPage = &ESBuf;
-      DataPointer += sizeof(ElementStatusPage_T);
-      TransportElementDescriptorLength =
-       BigEndian16(ElementStatusPage->ElementDescriptorLength);
-      if (TransportElementDescriptorLength <
-         sizeof(TransportElementDescriptorShort_T)) {
-
-       /* Foo, Storage Element Descriptors can be 4 bytes?! */
-       if ( (ElementStatusPage->ElementTypeCode != MediumTransportElement &&
-             ElementStatusPage->ElementTypeCode != StorageElement &&
-             ElementStatusPage->ElementTypeCode != ImportExportElement ) ||
-            TransportElementDescriptorLength < 4) {
+                               fprintf(stderr,"boom! ElementTypeCode=%d\n",ElementStatusPage->ElementTypeCode);
+#endif
+                               FatalError("Transport Element Descriptor Length too short: %d\n", TransportElementDescriptorLength);
+                       }
+               }
 #ifdef DEBUG
-         fprintf(stderr,"boom! ElementTypeCode=%d\n",ElementStatusPage->ElementTypeCode);
+               fprintf(stderr,"Transport Element Descriptor Length=%d\n",TransportElementDescriptorLength);
 #endif
-         FatalError("Transport Element Descriptor Length too short: %d\n",TransportElementDescriptorLength);
-       } 
-       
-      }
+               BytesAvailable =
+                       BigEndian24(ElementStatusPage->ByteCountOfDescriptorDataAvailable);
 #ifdef DEBUG
-      fprintf(stderr,"Transport Element Descriptor Length=%d\n",TransportElementDescriptorLength);
-#endif
-      BytesAvailable =
-       BigEndian24(ElementStatusPage->ByteCountOfDescriptorDataAvailable);
-      if (BytesAvailable <= 0) {
-             ElementCount--;
-      }
-      while (BytesAvailable > 0)
-       {
-         /* TransportElementDescriptor =
-            (TransportElementDescriptor_T *) DataPointer; */
-          memcpy(&TEBuf, DataPointer, 
-                       (TransportElementDescriptorLength <= sizeof(TEBuf)) ?
-                               TransportElementDescriptorLength  :
-                               sizeof(TEBuf));
-          TransportElementDescriptor = &TEBuf;
-
-         DataPointer += TransportElementDescriptorLength;
-         BytesAvailable -= TransportElementDescriptorLength;
-         ElementCount--;
-         switch (ElementStatusPage->ElementTypeCode)
-           {
-           case MediumTransportElement:
-             ElementStatus->TransportElementAddress = BigEndian16(TransportElementDescriptor->ElementAddress);
+               fprintf(stderr,"%d bytes of descriptor data available in descriptor\n",
+                               BytesAvailable);
+#endif
+               /* work around a bug in ADIC DAT loaders */
+               if (BytesAvailable <= 0)
+               {
+                       ElementCount--; /* sorry :-( */
+               }
+               while (BytesAvailable > 0)
+               {
+                       /* TransportElementDescriptor =
+                       (TransportElementDescriptor_T *) DataPointer; */
+                       memcpy(&TEBuf, DataPointer, 
+                               (TransportElementDescriptorLength <= sizeof(TEBuf)) ?
+                                       TransportElementDescriptorLength  :
+                                       sizeof(TEBuf));
+                       TransportElementDescriptor = &TEBuf;
+
+                       if (pNextElement != NULL)
+                       {
+                               if (BigEndian16(TransportElementDescriptor->ElementAddress) != 0 || *pNextElement == 0)
+                               {
+                                       (*pNextElement) = BigEndian16(TransportElementDescriptor->ElementAddress) + 1;
+                               }
+                               else
+                               {
+                                       return;
+                               }
+                       }
+
+                       DataPointer += TransportElementDescriptorLength;
+                       BytesAvailable -= TransportElementDescriptorLength;
+                       ElementCount--;
+
+                       switch (ElementStatusPage->ElementTypeCode)
+                       {
+                       case MediumTransportElement:
+                               ElementStatus->TransportElementAddress = BigEndian16(TransportElementDescriptor->ElementAddress);
 #ifdef DEBUG
-             fprintf(stderr,"TransportElementAddress=%d\n",ElementStatus->TransportElementAddress); 
-#endif
-             break;
-             /* we treat ImportExport elements as if they were normal
-              * storage elements now, sigh...
-              */
-           case ImportExportElement:
-             ElementStatus->ImportExportCount++;
+                               fprintf(stderr,"TransportElementAddress=%d\n",ElementStatus->TransportElementAddress); 
+#endif
+                               break;
+
+                       /* we treat ImportExport elements as if they were normal
+                       * storage elements now, sigh...
+                       */
+                       case ImportExportElement:
 #ifdef DEBUG
-             fprintf(stderr,"ImportExportElement=%d\n",ElementStatus->StorageElementCount);
+                               fprintf(stderr,"ImportExportElement=%d\n",ElementStatus->StorageElementCount);
 #endif
-             ElementStatus->StorageElementIsImportExport[ElementStatus->StorageElementCount] = 1;
-             /* WARNING: DO *NOT* PUT A 'break' STATEMENT HERE, it is supposed
-              * to run on into the case for a Storage Element! 
-              */
-           case StorageElement:
+                               if (ElementStatus->ImportExportCount >= mode_sense->NumImportExport)
+                               {
+                                       fprintf(stderr,"Warning:Too Many Import/Export Elements Reported (expected %d, now have %d\n",
+                                       mode_sense->NumImportExport,
+                                       ElementStatus->ImportExportCount + 1);
+                                       fflush(stderr);
+                                       return; /* we're done :-(. */
+                               }
+
+                               ImportExportIndex = mode_sense->NumStorage - mode_sense->NumImportExport + ElementStatus->ImportExportCount;
+
+                               ElementStatus->StorageElementAddress[ImportExportIndex] =
+                                       BigEndian16(TransportElementDescriptor->ElementAddress);
+                               ElementStatus->StorageElementFull[ImportExportIndex] =
+                                       TransportElementDescriptor->Full;
+
+                               if ( (TransportElementDescriptorLength > 11) && 
+                                       (ElementStatusPage->VolBits & E2_AVOLTAG))
+                               {
+                                       copy_barcode(TransportElementDescriptor->AlternateVolumeTag,
+                                               ElementStatus->AlternateVolumeTag[ImportExportIndex]);
+                               }
+                               else
+                               {
+                                       ElementStatus->AlternateVolumeTag[ImportExportIndex][0] = 0;  /* null string. */;
+                               } 
+                               if ((TransportElementDescriptorLength > 11) && 
+                                       (ElementStatusPage->VolBits & E2_PVOLTAG))
+                               {
+                                       copy_barcode(TransportElementDescriptor->PrimaryVolumeTag,
+                                               ElementStatus->PrimaryVolumeTag[ImportExportIndex]);
+                               }
+                               else
+                               {
+                                       ElementStatus->PrimaryVolumeTag[ImportExportIndex][0]=0; /* null string. */
+                               }
+
+                               ElementStatus->StorageElementIsImportExport[ImportExportIndex] = 1;
+
+                               ElementStatus->ImportExportCount++;
+                               break;
+
+                       case StorageElement:
 #ifdef DEBUG
-             fprintf(stderr,"StorageElementCount=%d  ElementAddress = %d ",ElementStatus->StorageElementCount,BigEndian16(TransportElementDescriptor->ElementAddress));
+                               fprintf(stderr,"StorageElementCount=%d  ElementAddress = %d ",ElementStatus->StorageElementCount,BigEndian16(TransportElementDescriptor->ElementAddress));
 #endif
-             ElementStatus->StorageElementAddress[ElementStatus->StorageElementCount] =
-               BigEndian16(TransportElementDescriptor->ElementAddress);
-             ElementStatus->StorageElementFull[ElementStatus->StorageElementCount] =
-               TransportElementDescriptor->Full;
+                               /* ATL/Exabyte kludge -- skip slots that aren't installed :-( */
+                               if (TransportElementDescriptor->AdditionalSenseCode==0x83 && 
+                                       TransportElementDescriptor->AdditionalSenseCodeQualifier==0x02) 
+                                       continue;
+
+                               ElementStatus->StorageElementAddress[ElementStatus->StorageElementCount] =
+                                       BigEndian16(TransportElementDescriptor->ElementAddress);
+                               ElementStatus->StorageElementFull[ElementStatus->StorageElementCount] =
+                                       TransportElementDescriptor->Full;
 #ifdef DEBUG
-             fprintf(stderr,"TransportElement->Full = %d\n",TransportElementDescriptor->Full);
+                               if (TransportElementDescriptor->Except)
+                                       fprintf(stderr,"ASC,ASCQ = 0x%x,0x%x ",TransportElementDescriptor->AdditionalSenseCode,TransportElementDescriptor->AdditionalSenseCodeQualifier);
+                               fprintf(stderr,"TransportElement->Full = %d\n",TransportElementDescriptor->Full);
 #endif
-             if (!TransportElementDescriptor->Full)
-               {
-                 EmptyStorageElementAddress[(*EmptyStorageElementCount)++] =
-                   ElementStatus->StorageElementCount; /* slot idx. */
-                   /*   ElementStatus->StorageElementAddress[ElementStatus->StorageElementCount]; */
+                               if (!TransportElementDescriptor->Full)
+                               {
+                                       EmptyStorageElementAddress[(*EmptyStorageElementCount)++] =
+                                               ElementStatus->StorageElementCount; /* slot idx. */
+                                       /*   ElementStatus->StorageElementAddress[ElementStatus->StorageElementCount]; */
+                               }
+                               if ((TransportElementDescriptorLength >  11) && 
+                                       (ElementStatusPage->VolBits & E2_AVOLTAG))
+                               {
+                                       copy_barcode(TransportElementDescriptor->AlternateVolumeTag,
+                                               ElementStatus->AlternateVolumeTag[ElementStatus->StorageElementCount]);
+                               }
+                               else
+                               {
+                                       ElementStatus->AlternateVolumeTag[ElementStatus->StorageElementCount][0]=0;  /* null string. */;
+                               } 
+                               if ((TransportElementDescriptorLength > 11) && 
+                                       (ElementStatusPage->VolBits & E2_PVOLTAG))
+                               {
+                                       copy_barcode(TransportElementDescriptor->PrimaryVolumeTag,
+                                               ElementStatus->PrimaryVolumeTag[ElementStatus->StorageElementCount]);
+                               }
+                               else
+                               {
+                                       ElementStatus->PrimaryVolumeTag[ElementStatus->StorageElementCount][0]=0; /* null string. */
+                               }
+
+                               ElementStatus->StorageElementCount++;
+                               /*
+                                       Note that the original mtx had no check here for 
+                                       buffer overflow, though some drives might mistakingly
+                                       do one... 
+                               */
+
+                               if (ElementStatus->StorageElementCount > mode_sense->NumStorage)
+                               {
+                                       fprintf(stderr,"Warning:Too Many Storage Elements Reported (expected %d, now have %d\n",
+                                                       mode_sense->NumStorage,
+                                                       ElementStatus->StorageElementCount);
+                                       fflush(stderr);
+                                       return; /* we're done :-(. */
+                               }
+                               break;
+
+                       case DataTransferElement:
+                               /* tape drive not installed, go back to top of loop */
+
+                               /* if (TransportElementDescriptor->Except) continue ; */
+
+                               /* Note: This is for Exabyte tape libraries that improperly
+                               report that they have a 2nd tape drive when they don't. We
+                               could generalize this in an ideal world, but my attempt to
+                               do so failed with dual-drive Exabyte tape libraries that
+                               *DID* have the second drive. Sigh. 
+                               */
+                               if (TransportElementDescriptor->AdditionalSenseCode==0x83 && 
+                                       TransportElementDescriptor->AdditionalSenseCodeQualifier==0x04)
+                               {
+                                       continue;
+                               }
+
+                               /*      generalize it. Does it work? Let's try it! */
+                               /*      
+                                       No, dammit, following does not work on dual-drive Exabyte
+                                       'cause if a tape is in the drive, it sets the AdditionalSense
+                                       code to something (sigh).
+                               */
+                               /* if (TransportElementDescriptor->AdditionalSenseCode!=0)
+                                       continue;
+                               */ 
+
+                               ElementStatus->DataTransferElementAddress[ElementStatus->DataTransferElementCount] =
+                                       BigEndian16(TransportElementDescriptor->ElementAddress);
+                               ElementStatus->DataTransferElementFull[ElementStatus->DataTransferElementCount] = 
+                                       TransportElementDescriptor->Full;
+                               ElementStatus->DataTransferElementSourceStorageElementNumber[ElementStatus->DataTransferElementCount] =
+                                       BigEndian16(TransportElementDescriptor->SourceStorageElementAddress);
+
+#if DEBUG
+                               fprintf(stderr, "%d: ElementAddress = %d, Full = %d, SourceElement = %d\n", 
+                                               ElementStatus->DataTransferElementCount,
+                                               ElementStatus->DataTransferElementAddress[ElementStatus->DataTransferElementCount],
+                                               ElementStatus->DataTransferElementFull[ElementStatus->DataTransferElementCount],
+                                               ElementStatus->DataTransferElementSourceStorageElementNumber[ElementStatus->DataTransferElementCount]);
+#endif
+                               if (ElementStatus->DataTransferElementCount >= mode_sense->NumDataTransfer)
+                               {
+                                       FatalError("Too many Data Transfer Elements Reported\n");
+                               }
+
+                               if (ElementStatusPage->VolBits & E2_PVOLTAG)
+                               {
+                                       copy_barcode(TransportElementDescriptor->PrimaryVolumeTag,
+                                       ElementStatus->DataTransferPrimaryVolumeTag[ElementStatus->DataTransferElementCount]);
+                               }
+                               else
+                               {
+                                       ElementStatus->DataTransferPrimaryVolumeTag[ElementStatus->DataTransferElementCount][0]=0; /* null string */
+                               }
+
+                               if (ElementStatusPage->VolBits & E2_AVOLTAG)
+                               {
+                                       copy_barcode(TransportElementDescriptor->AlternateVolumeTag,
+                                       ElementStatus->DataTransferAlternateVolumeTag[ElementStatus->DataTransferElementCount]);
+                               }
+                               else
+                               {
+                                       ElementStatus->DataTransferAlternateVolumeTag[ElementStatus->DataTransferElementCount][0]=0; /* null string */
+                               }
+
+                               ElementStatus->DataTransferElementCount++;
+
+                               /* 0 actually is a usable element address */
+                               /* if (DataTransferElementAddress == 0) */
+                               /*      FatalError( */
+                               /*  "illegal Data Transfer Element Address %d reported\n", */
+                               /* DataTransferElementAddress); */
+                               break;
+
+                       default:
+                               FatalError("illegal Element Type Code %d reported\n",
+                                                       ElementStatusPage->ElementTypeCode);
+                       }
                }
-             if ( (TransportElementDescriptorLength >  11) && 
-                  (ElementStatusPage->VolBits & E2_AVOLTAG)) {
-               copy_barcode(TransportElementDescriptor->AlternateVolumeTag,
-                            ElementStatus->AlternateVolumeTag[ElementStatus->StorageElementCount]);
-             } else {
-               ElementStatus->AlternateVolumeTag[ElementStatus->StorageElementCount][0]=0;  /* null string. */;
-             } 
-             if ( (TransportElementDescriptorLength > 11) && 
-                  (ElementStatusPage->VolBits & E2_PVOLTAG)) {
-               copy_barcode(TransportElementDescriptor->PrimaryVolumeTag,
-                            ElementStatus->PrimaryVolumeTag[ElementStatus->StorageElementCount]);
-             } else {
-               ElementStatus->PrimaryVolumeTag[ElementStatus->StorageElementCount][0]=0; /* null string. */
-             }
-             
-             ElementStatus->StorageElementCount++;
-             /* Note that the original mtx had no check here for 
-                buffer overflow, though some drives might mistakingly
-                do one... 
-             */ 
-             if (ElementStatus->StorageElementCount > mode_sense->NumStorage) {
-               fprintf(stderr,"Warning:Too Many Storage Elements Reported (expected %d, now have %d\n",
-                       mode_sense->NumStorage,
-                       ElementStatus->StorageElementCount);
-               fflush(stderr);
-               return; /* we're done :-(. */
-             }
-
-
-             break;
-
-
-           case DataTransferElement:
-             /* tape drive not installed, go back to top of loop */
-
-             /* if (TransportElementDescriptor->Except) continue ; */
-
-             /* Note: This is for Exabyte tape libraries that improperly
-                report that they have a 2nd tape drive when they don't. We
-                could generalize this in an ideal world, but my attempt to
-                do so failed with dual-drive Exabyte tape libraries that
-                *DID* have the second drive. Sigh. 
-             */
-             /* No longer need this test due to code restructuring? */
-             /* if (TransportElementDescriptor->AdditionalSenseCode==0x83 && 
-                 TransportElementDescriptor->AdditionalSenseCodeQualifier==0x04) 
-               continue;
-             */ 
-             /* generalize it. Does it work? Let's try it! */
-             /* No, dammit, following does not work on dual-drive Exabyte
-                'cause if a tape is in the drive, it sets the AdditionalSense
-                 code to something (sigh).
-             */
-             /* if (TransportElementDescriptor->AdditionalSenseCode!=0)
-               continue;
-             */ 
-             
-
-                 
-             ElementStatus->DataTransferElementAddress[ElementStatus->DataTransferElementCount] =
-               BigEndian16(TransportElementDescriptor->ElementAddress);
-             ElementStatus->DataTransferElementFull[ElementStatus->DataTransferElementCount] = 
-               TransportElementDescriptor->Full;
-             ElementStatus->DataTransferElementSourceStorageElementNumber[ElementStatus->DataTransferElementCount] =
-               BigEndian16(TransportElementDescriptor
-                           ->SourceStorageElementAddress);
-
-             if (ElementStatus->DataTransferElementCount >= mode_sense->NumDataTransfer) {
-               FatalError("Too many Data Transfer Elements Reported\n");
-             }
-             if (ElementStatusPage->VolBits & E2_PVOLTAG) {
-               copy_barcode(TransportElementDescriptor->PrimaryVolumeTag,
-                            ElementStatus->DataTransferPrimaryVolumeTag[ElementStatus->DataTransferElementCount]);
-             } else {
-               ElementStatus->DataTransferPrimaryVolumeTag[ElementStatus->DataTransferElementCount][0]=0; /* null string */
-             }
-             if (ElementStatusPage->VolBits & E2_AVOLTAG) {
-               copy_barcode(TransportElementDescriptor->AlternateVolumeTag,
-                            ElementStatus->DataTransferAlternateVolumeTag[ElementStatus->DataTransferElementCount]);
-             } else {
-               ElementStatus->DataTransferAlternateVolumeTag[ElementStatus->DataTransferElementCount][0]=0; /* null string */
-             }
-             ElementStatus->DataTransferElementCount++;
-             /* 0 actually is a usable element address */
-             /* if (DataTransferElementAddress == 0) */
-             /*        FatalError( */
-             /*  "illegal Data Transfer Element Address %d reported\n", */
-             /* DataTransferElementAddress); */
-             break;
-           default:
-             FatalError("illegal Element Type Code %d reported\n",
-                        ElementStatusPage->ElementTypeCode);
-           }
        }
-    }
+
+#ifdef DEBUG
+       if (pNextElement)
+               fprintf(stderr,"Next start element will be %d\n",*pNextElement);
+#endif
 }
 
+
 /********************* Real ReadElementStatus ********************* */
 
 /*
@@ -824,510 +1119,744 @@ static void ParseElementStatus(int *EmptyStorageElementAddress,
 
 */
 
-ElementStatus_T *ReadElementStatus(DEVICE_TYPE MediumChangerFD, RequestSense_T *RequestSense, Inquiry_T *inquiry_info, SCSI_Flags_T *flags) {
-  ElementStatus_T *ElementStatus;
-  
-  unsigned char *DataBuffer; /* size of data... */
-  
-  int EmptyStorageElementCount=0;
-  int *EmptyStorageElementAddress; /* [MAX_STORAGE_ELEMENTS]; */
-  
-  int empty_idx=0;
-  int invalid_sources=0;
-  boolean is_attached = false;
-  int i,j;
-  
-  ElementModeSense_T *mode_sense = NULL;
-  
-  if ((inquiry_info->MChngr) && (inquiry_info->PeripheralDeviceType != MEDIUM_CHANGER_TYPE)) {
-    is_attached=true;
-  }
-  if (flags->no_attached) { /* override, sigh */ 
-    is_attached=false;
-  }
-  if (!is_attached) {
-    mode_sense=ReadAssignmentPage(MediumChangerFD);
-  }
-  if (!mode_sense) {
-    mode_sense=(ElementModeSense_T *) xmalloc(sizeof(ElementModeSense_T));
-    mode_sense->NumMediumTransport=MAX_TRANSPORT_ELEMENTS;
-    mode_sense->NumStorage=MAX_STORAGE_ELEMENTS;
-    mode_sense->NumDataTransfer=MAX_TRANSFER_ELEMENTS;
-    mode_sense->MaxReadElementStatusData=  (sizeof(ElementStatusDataHeader_T)
-                                           + 3 * sizeof(ElementStatusPage_T)
-                                           + (MAX_STORAGE_ELEMENTS+MAX_TRANSFER_ELEMENTS+MAX_TRANSPORT_ELEMENTS)
-                                           * sizeof(TransportElementDescriptor_T));
-    
-    /* don't care about the others anyhow at the moment... */
-  }
-  
-  ElementStatus=AllocateElementData(mode_sense);
-
-  /* Now to initialize it (sigh).  */
-  ElementStatus->StorageElementCount = 0;
-  ElementStatus->DataTransferElementCount=0;
-    
-  
-  /* first, allocate some empty storage stuff: Note that we pass this
-   * down to ParseElementStatus (sigh!) 
-   */
-  
-  EmptyStorageElementAddress=(int *)xzmalloc((mode_sense->NumStorage+1)*sizeof(int));
-  for (i=0;i<mode_sense->NumStorage;i++) {
-    EmptyStorageElementAddress[i]=-1;
-  }
-  
-  /* Okay, now to send some requests for the various types of stuff: */
-
-  /* -----------STORAGE ELEMENTS---------------- */
-  /* Let's start with storage elements: */
-
-  for (i=0;i<mode_sense->NumDataTransfer;i++) {
-    /* initialize them to an illegal # so that we can fix later... */
-    ElementStatus->DataTransferElementSourceStorageElementNumber[i] = -1; 
-  }
-  
-
-  flags->elementtype=StorageElement; /* sigh! */
-  DataBuffer=SendElementStatusRequest(MediumChangerFD,RequestSense,
-                                     inquiry_info,flags,
-                                     mode_sense->StorageStart,
-                                     /* adjust for import/export. */
-                                     mode_sense->NumStorage-mode_sense->NumImportExport,
-                                     mode_sense->MaxReadElementStatusData);
-  if (!DataBuffer) {
-    /* darn. Free up stuff and return. */
-    /****FIXME**** do a free on element data! */
-    FreeElementData(ElementStatus);
-    return NULL; 
-  } 
-
-  ParseElementStatus(EmptyStorageElementAddress,&EmptyStorageElementCount,
-                    DataBuffer,ElementStatus,mode_sense);
-
-  free(DataBuffer); /* sigh! */
-
-  /* --------------IMPORT/EXPORT--------------- */
-  /* Next let's see if we need to do Import/Export: */
-  if (mode_sense->NumImportExport > 0) {
-    flags->elementtype=ImportExportElement;
-    DataBuffer=SendElementStatusRequest(MediumChangerFD,RequestSense,
-                                       inquiry_info,flags,
-                                       mode_sense->ImportExportStart,
-                                       mode_sense->NumImportExport,
-                                       mode_sense->MaxReadElementStatusData);
-    
-    if (!DataBuffer) {
-      /* darn. Free up stuff and return. */
-      /****FIXME**** do a free on element data! */
-      FreeElementData(ElementStatus);
-      return NULL; 
-    } 
-    ParseElementStatus(EmptyStorageElementAddress,&EmptyStorageElementCount,
-                    DataBuffer,ElementStatus,mode_sense);
-
-  }
-  
-
-
-  /* ----------------- DRIVES ---------------------- */
-
-
-  flags->elementtype=DataTransferElement; /* sigh! */
-  DataBuffer=SendElementStatusRequest(MediumChangerFD,RequestSense,
-                                     inquiry_info,flags,
-                                     mode_sense->DataTransferStart,
-                                     mode_sense->NumDataTransfer,
-                                     mode_sense->MaxReadElementStatusData);
-  if (!DataBuffer) {
-    /* darn. Free up stuff and return. */
-    /****FIXME**** do a free on element data! */
-    FreeElementData(ElementStatus);
-    return NULL; 
-  } 
-
-  ParseElementStatus(EmptyStorageElementAddress,&EmptyStorageElementCount,
-                    DataBuffer,ElementStatus,mode_sense);
-
-  free(DataBuffer); /* sigh! */
-
-
-  /* ----------------- Robot Arm(s) -------------------------- */
-
-    /* grr, damned brain dead HP doesn't report that it has any! */
-  if (!mode_sense->NumMediumTransport) { 
-    ElementStatus->TransportElementAddress=0; /* default it sensibly :-(. */
-  } else {
-     flags->elementtype=MediumTransportElement; /* sigh! */
-     DataBuffer=SendElementStatusRequest(MediumChangerFD,RequestSense,
-                                     inquiry_info,flags,
-                                     mode_sense->MediumTransportStart,
-                                     1, /* only get 1, sigh. */
-                                     mode_sense->MaxReadElementStatusData);
-     if (!DataBuffer) {
-       /* darn. Free up stuff and return. */
-       /****FIXME**** do a free on element data! */
-       FreeElementData(ElementStatus);
-       return NULL; 
-     } 
-   
-     ParseElementStatus(EmptyStorageElementAddress,&EmptyStorageElementCount,
-                    DataBuffer,ElementStatus,mode_sense);
-
-     free(DataBuffer); /* sigh! */
-  }
-
-  /*---------------------- Sanity Checking ------------------- */
-
-  if (!ElementStatus->DataTransferElementCount)
-    FatalError("no Data Transfer Element reported\n");
-  if (ElementStatus->StorageElementCount == 0)
-    FatalError("no Storage Elements reported\n");
-
-
-  /* ---------------------- Reset SourceStorageElementNumbers ------- */
-
-  /* okay, re-write the SourceStorageElementNumber code  *AGAIN*.
-   * Pass1:
-   *   Translate from raw element # to our translated # (if possible).
-   * First, check the SourceStorageElementNumbers against the list of 
-   * filled slots. If the slots indicated are empty, we accept that list as
-   * valid. Otherwise decide the SourceStorageElementNumbers are invalid.
-   *
-   * Pass2:
-   *
-   * If we had some invalid (or unknown) SourceStorageElementNumbers
-   * then we must search for free slots, and assign SourceStorageElementNumbers
-   * to those free slots. We happen to already built a list of free
-   * slots as part of the process of reading the storage element numbers
-   * from the tape. So that's easy enough to do! 
-   */
+ElementStatus_T *ReadElementStatus(DEVICE_TYPE MediumChangerFD, RequestSense_T *RequestSense, Inquiry_T *inquiry_info, SCSI_Flags_T *flags)
+{
+       ElementStatus_T *ElementStatus;
 
-#ifdef DEBUG_TAPELIST
-  fprintf(stderr,"empty slots: %d\n",EmptyStorageElementCount);
-  if (EmptyStorageElementCount) {
-     for (i=0; i<EmptyStorageElementCount; i++) {
-         fprintf(stderr,"empty: %d\n",EmptyStorageElementAddress[i]);
-     }
-  }
-#endif
-
-  /* Okay, now we re-assign origin slots if the "real" origin slot
-   * is obviously defective: 
-   */
-  /* pass one: */
-  invalid_sources=0; /* no invalid sources yet! */
-  for (i=0;i<ElementStatus->DataTransferElementCount;i++) {
-    int elnum;
-    int translated_elnum = -1;
-    /* if we have an element, then ... */
-    if (ElementStatus->DataTransferElementFull[i]) {
-      elnum=ElementStatus->DataTransferElementSourceStorageElementNumber[i];
-      /* if we have an element number, then ... */
-      if (elnum >= 0) {
-         /* Now to translate the elnum: */
-        for (j=0; j<ElementStatus->StorageElementCount; j++) {
-            if (elnum == ElementStatus->StorageElementAddress[j]) {
-                translated_elnum=j; 
-            }
-        }
-      /* now see if the element # is already occupied: */
-       if (ElementStatus->StorageElementFull[translated_elnum]) {
-         invalid_sources=1;
-         break; /* break out of the loop! */
-       } else {
-          /* properly set the source... */
-       ElementStatus->DataTransferElementSourceStorageElementNumber[i]=
-               translated_elnum;
+       unsigned char *DataBuffer; /* size of data... */
+
+       int EmptyStorageElementCount=0;
+       int *EmptyStorageElementAddress; /* [MAX_STORAGE_ELEMENTS]; */
+
+       int empty_idx = 0;
+       boolean is_attached = false;
+       int i,j;
+
+       ElementModeSense_T *mode_sense = NULL;
+
+       if (inquiry_info->MChngr && inquiry_info->PeripheralDeviceType != MEDIUM_CHANGER_TYPE)
+       {
+               is_attached = true;
+       }
+
+       if (flags->no_attached)
+       {
+               /* override, sigh */ 
+               is_attached = false;
+       }
+
+       if (!is_attached)
+       {
+               mode_sense = ReadAssignmentPage(MediumChangerFD);
+       }
+
+       if (!mode_sense)
+       {
+               mode_sense = (ElementModeSense_T *)xmalloc(sizeof(ElementModeSense_T));
+               mode_sense->NumMediumTransport = MAX_TRANSPORT_ELEMENTS;
+               mode_sense->NumStorage = MAX_STORAGE_ELEMENTS;
+               mode_sense->NumDataTransfer = MAX_TRANSFER_ELEMENTS;
+               mode_sense->MaxReadElementStatusData =
+                       (sizeof(ElementStatusDataHeader_T) + 3 * sizeof(ElementStatusPage_T) +
+                       (MAX_STORAGE_ELEMENTS+MAX_TRANSFER_ELEMENTS+MAX_TRANSPORT_ELEMENTS) *
+                               sizeof(TransportElementDescriptor_T));
+
+               /* don't care about the others anyhow at the moment... */
+       }
+
+       ElementStatus = AllocateElementData(mode_sense);
+
+       /* Now to initialize it (sigh).  */
+       ElementStatus->StorageElementCount = 0;
+       ElementStatus->DataTransferElementCount = 0;
+
+       /* first, allocate some empty storage stuff: Note that we pass this
+       * down to ParseElementStatus (sigh!) 
+       */
+
+       EmptyStorageElementAddress = (int *)xzmalloc((mode_sense->NumStorage+1)*sizeof(int));
+       for (i = 0; i < mode_sense->NumStorage; i++)
+       {
+               EmptyStorageElementAddress[i] = -1;
+       }
+
+       /* Okay, now to send some requests for the various types of stuff: */
+
+       /* -----------STORAGE ELEMENTS---------------- */
+       /* Let's start with storage elements: */
+
+       for (i = 0; i < mode_sense->NumDataTransfer; i++)
+       {
+               /* initialize them to an illegal # so that we can fix later... */
+               ElementStatus->DataTransferElementSourceStorageElementNumber[i] = -1; 
        }
-                
-      } else {
-       /* if element # was not >=0, then we had an invalid source anyhow! */
-       invalid_sources=1;
-      }
-    }
-  }
+
+       if (flags->querytype == MTX_ELEMENTSTATUS_ORIGINAL)
+       {
+#ifdef DEBUG
+               fprintf(stderr,"Using original element status polling method (storage, import/export, drivers etc independantly)\n");
+#endif
+               flags->elementtype = StorageElement; /* sigh! */
+               DataBuffer = SendElementStatusRequest(  MediumChangerFD, RequestSense,
+                                                                                               inquiry_info, flags,
+                                                                                               mode_sense->StorageStart,
+                                                                                               /* adjust for import/export. */
+                                                                                               mode_sense->NumStorage - mode_sense->NumImportExport,
+                                                                                               mode_sense->MaxReadElementStatusData);
+
+               if (!DataBuffer)
+               {
+#ifdef DEBUG
+                       fprintf(stderr,"Had no elements!\n");
+#endif
+                       /* darn. Free up stuff and return. */
+#ifdef DEBUG_MODE_SENSE
+                       PrintRequestSense(RequestSense);
+#endif
+                       FreeElementData(ElementStatus);
+                       return NULL; 
+               }
+
+#ifdef DEBUG
+               fprintf(stderr, "Parsing storage elements\n");
+#endif
+               ParseElementStatus(EmptyStorageElementAddress, &EmptyStorageElementCount,
+                       DataBuffer,ElementStatus,mode_sense,NULL);
+
+               free(DataBuffer); /* sigh! */
+
+               /* --------------IMPORT/EXPORT--------------- */
+               /* Next let's see if we need to do Import/Export: */
+               if (mode_sense->NumImportExport > 0)
+               {
+#ifdef DEBUG
+                       fprintf(stderr,"Sending request for Import/Export status\n");
+#endif
+                       flags->elementtype = ImportExportElement;
+                       DataBuffer = SendElementStatusRequest(  MediumChangerFD,RequestSense,
+                                                                                                       inquiry_info, flags,
+                                                                                                       mode_sense->ImportExportStart,
+                                                                                                       mode_sense->NumImportExport,
+                                                                                                       mode_sense->MaxReadElementStatusData);
+
+                       if (!DataBuffer)
+                       {
+#ifdef DEBUG
+                               fprintf(stderr,"Had no input/export element!\n");
+#endif
+                               /* darn. Free up stuff and return. */
+#ifdef DEBUG_MODE_SENSE
+                               PrintRequestSense(RequestSense);
+#endif
+                               FreeElementData(ElementStatus);
+                               return NULL;
+                       }
+#ifdef DEBUG
+                       fprintf(stderr,"Parsing inport/export element status\n");
+#endif
+#ifdef DEBUG_ADIC
+                       dump_data(DataBuffer, 100);             /* dump some data :-(. */
+#endif
+                       ParseElementStatus(     EmptyStorageElementAddress, &EmptyStorageElementCount,
+                                                               DataBuffer, ElementStatus, mode_sense, NULL);
+
+                       ElementStatus->StorageElementCount += ElementStatus->ImportExportCount;
+               }
+
+               /* ----------------- DRIVES ---------------------- */
+
+#ifdef DEBUG
+               fprintf(stderr,"Sending request for data transfer element (drive) status\n");
+#endif
+               flags->elementtype = DataTransferElement; /* sigh! */
+               DataBuffer = SendElementStatusRequest(  MediumChangerFD, RequestSense,
+                                                                                               inquiry_info, flags,
+                                                                                               mode_sense->DataTransferStart,
+                                                                                               mode_sense->NumDataTransfer,
+                                                                                               mode_sense->MaxReadElementStatusData);
+               if (!DataBuffer)
+               {
+#ifdef DEBUG
+                       fprintf(stderr,"No data transfer element status.");
+#endif
+                       /* darn. Free up stuff and return. */
+#ifdef DEBUG_MODE_SENSE
+                       PrintRequestSense(RequestSense);
+#endif
+                       FreeElementData(ElementStatus);
+                       return NULL; 
+               }
+
+#ifdef DEBUG
+               fprintf(stderr,"Parsing data for data transfer element (drive) status\n");
+#endif
+               ParseElementStatus(     EmptyStorageElementAddress, &EmptyStorageElementCount,
+                                                       DataBuffer,ElementStatus, mode_sense, NULL);
+
+               free(DataBuffer); /* sigh! */
+
+               /* ----------------- Robot Arm(s) -------------------------- */
+
+               /* grr, damned brain dead HP doesn't report that it has any! */
+               if (!mode_sense->NumMediumTransport)
+               { 
+                       ElementStatus->TransportElementAddress = 0; /* default it sensibly :-(. */
+               }
+               else
+               {
+#ifdef DEBUG
+                       fprintf(stderr,"Sending request for robot arm status\n");
+#endif
+                       flags->elementtype = MediumTransportElement; /* sigh! */
+                       DataBuffer = SendElementStatusRequest(  MediumChangerFD, RequestSense,
+                                                                                                       inquiry_info, flags,
+                                                                                                       mode_sense->MediumTransportStart,
+                                                                                                       1, /* only get 1, sigh. */
+                                                                                                       mode_sense->MaxReadElementStatusData);
+                       if (!DataBuffer)
+                       {
+#ifdef DEBUG
+                               fprintf(stderr,"Loader reports no robot arm!\n");
+#endif
+                               /* darn. Free up stuff and return. */
+#ifdef DEBUG_MODE_SENSE
+                               PrintRequestSense(RequestSense);
+#endif
+                               FreeElementData(ElementStatus);
+                               return NULL; 
+                       } 
+#ifdef DEBUG
+                       fprintf(stderr,"Parsing robot arm data\n");
+#endif
+                       ParseElementStatus(     EmptyStorageElementAddress, &EmptyStorageElementCount,
+                                                               DataBuffer, ElementStatus, mode_sense, NULL);
+
+                       free(DataBuffer);
+               }
+       }
+       else
+       {
+               int nLastEl=-1, nNextEl=0;
+
+#ifdef DEBUG
+               fprintf(stderr,"Using alternative element status polling method (all elements)\n");
+#endif
+               /* ----------------- ALL Elements ---------------------- */
+               /*      Just keep asking for elements till no more are returned 
+                       - increment our starting address as we go acording to the 
+                       number of elements returned from the last call
+               */
+
+               while(nLastEl!=nNextEl)
+               {
+                       flags->elementtype = AllElementTypes;//StorageElement; /* sigh! */ /*XL1B2 firewire changer does not seem to respond to specific types so just use all elements*/
+                       DataBuffer = SendElementStatusRequest(  MediumChangerFD,
+                                                                                                       RequestSense,
+                                                                                                       inquiry_info,
+                                                                                                       flags,
+                                                                                                       nNextEl,//mode_sense->StorageStart,
+                                                                                                       /* adjust for import/export. */
+                                                                                                       mode_sense->NumStorage - mode_sense->NumImportExport,//FIX ME:this should be a more sensible value
+                                                                                                       mode_sense->MaxReadElementStatusData);
+                       if (!DataBuffer)
+                       {
+                               if (RequestSense->AdditionalSenseCode == 0x21 && 
+                               RequestSense->AdditionalSenseCodeQualifier == 0x01)
+                               {
+                                       /* Error is invalid element address, we've probably just hit the end */
+                                       break;
+                               }
+
+                               /* darn. Free up stuff and return. */
+                               FreeElementData(ElementStatus);
+                               return NULL; 
+                       } 
+
+                       nLastEl = nNextEl;
+
+                       ParseElementStatus(     EmptyStorageElementAddress, &EmptyStorageElementCount,
+                                                               DataBuffer, ElementStatus, mode_sense, &nNextEl);
+
+                       free(DataBuffer); /* sigh! */
+               }
+
+               ElementStatus->StorageElementCount += ElementStatus->ImportExportCount;
+       }
+
+       /*---------------------- Sanity Checking ------------------- */
+
+       if (ElementStatus->DataTransferElementCount == 0)
+               FatalError("no Data Transfer Element reported\n");
+
+       if (ElementStatus->StorageElementCount == 0)
+               FatalError("no Storage Elements reported\n");
+
+
+       /* ---------------------- Reset SourceStorageElementNumbers ------- */
+
+       /*
+        * Re-write the SourceStorageElementNumber code  *AGAIN*.
+        *
+        * Pass1:
+        *      Translate from raw element # to our translated # (if possible).
+        *      First, check the SourceStorageElementNumbers against the list of 
+        *      filled slots. If the slots indicated are empty, we accept that list as
+        *      valid. Otherwise decide the SourceStorageElementNumbers are invalid.
+        *
+        * Pass2:
+        *      If we had some invalid (or unknown) SourceStorageElementNumbers
+        *      then we must search for free slots, and assign SourceStorageElementNumbers
+        *      to those free slots. We happen to already built a list of free
+        *      slots as part of the process of reading the storage element numbers
+        *      from the tape. So that's easy enough to do! 
+        */
 
 #ifdef DEBUG_TAPELIST
-   fprintf(stderr,"invalid_sources=%d\n",invalid_sources);
-#endif
-
-  /* Pass2: */
-  /* okay, we have invalid sources, so let's see what they should be: */
-  /* Note: If EmptyStorageElementCount is < # of drives, the leftover
-   * drives will be assigned a -1 (see the initialization loop for
-   * EmptyStorageElementAddress above), which will be reported as "slot 0"
-   * by the user interface. This is an invalid value, but more useful for us
-   * to have than just crapping out here :-(. 
-   */ 
-  if (invalid_sources) {
-    empty_idx=0;
-    for (i=0;i<ElementStatus->DataTransferElementCount;i++) {
-      if (ElementStatus->DataTransferElementFull[i]) {
+       fprintf(stderr, "empty slots: %d\n", EmptyStorageElementCount);
+       if (EmptyStorageElementCount)
+       {
+               for (i = 0; i < EmptyStorageElementCount; i++)
+               {
+                       fprintf(stderr, "empty: %d\n", EmptyStorageElementAddress[i]);
+               }
+       }
+#endif
+
+       /*
+        *      Now we re-assign origin slots if the "real" origin slot
+        *      is obviously defective: 
+        */
+       /* pass one: */
+       for (i = 0; i < ElementStatus->DataTransferElementCount; i++)
+       {
+               int elnum;
+
+               /* if we have an element, then ... */
+               if (ElementStatus->DataTransferElementFull[i])
+               {
+                       elnum = ElementStatus->DataTransferElementSourceStorageElementNumber[i];
+                       /* if we have an element number, then ... */
+                       if (elnum >= 0)
+                       {
+                               /* Now to translate the elnum: */
+                               ElementStatus->DataTransferElementSourceStorageElementNumber[i] = -1;
+                               for (j = 0; j < ElementStatus->StorageElementCount; j++)
+                               {
+                                       if (elnum == ElementStatus->StorageElementAddress[j])
+                                       {
+                                               /* now see if the element # is already occupied:*/
+                                               if (!ElementStatus->StorageElementFull[j])
+                                               {
+                                                       /* properly set the source... */
+                                                       ElementStatus->DataTransferElementSourceStorageElementNumber[i] = j;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* Pass2: */
+       /*      We have invalid sources, so let's see what they should be: */
+       /*      Note: If EmptyStorageElementCount is < # of drives, the leftover
+        *      drives will be assigned a -1 (see the initialization loop for
+        *      EmptyStorageElementAddress above), which will be reported as "slot 0"
+        *      by the user interface. This is an invalid value, but more useful for us
+        *      to have than just crapping out here :-(. 
+       */
+       empty_idx=0;
+       for (i = 0; i < ElementStatus->DataTransferElementCount; i++)
+       {
+               if (ElementStatus->DataTransferElementFull[i] && 
+                       ElementStatus->DataTransferElementSourceStorageElementNumber[i] < 0)
+               {
 #ifdef DEBUG_TAPELIST
-        fprintf(stderr,"for drive %d, changing source %d to %d (empty slot #%d)\n",
-            i,
-            ElementStatus->DataTransferElementSourceStorageElementNumber[i],
-             EmptyStorageElementAddress[empty_idx],
-             empty_idx);
-#endif
-              
-       ElementStatus->DataTransferElementSourceStorageElementNumber[i]=
-         EmptyStorageElementAddress[empty_idx++];
-      }
-    }
-  }
-
-  /* and done! */      
-  free(mode_sense);
-  free(EmptyStorageElementAddress);
-  return ElementStatus;
-  
+                       fprintf(stderr,"for drive %d, changing to %d (empty slot #%d)\n",
+                                       i,
+                                       EmptyStorageElementAddress[empty_idx],
+                                       empty_idx);
+#endif
+                       ElementStatus->DataTransferElementSourceStorageElementNumber[i] =
+                               EmptyStorageElementAddress[empty_idx++];
+               }
+       }
+
+       /* and done! */
+       free(mode_sense);
+       free(EmptyStorageElementAddress);
+       return ElementStatus;
 }
 
 /*************************************************************************/
 
+RequestSense_T *PositionElement(DEVICE_TYPE MediumChangerFD,
+               int DestinationAddress,
+               ElementStatus_T *ElementStatus)
+{
+       RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T));
+       CDB_T CDB;
+
+       CDB[0] = 0x2b;
+       CDB[1] = 0;
+       CDB[2] = (unsigned char)(ElementStatus->TransportElementAddress >> 8);
+       CDB[3] = (unsigned char)ElementStatus->TransportElementAddress;
+       CDB[4] = (unsigned char)(DestinationAddress >> 8);
+       CDB[5] = (unsigned char)DestinationAddress;
+       CDB[6] = 0;
+       CDB[7] = 0;
+       CDB[8] = 0;
+       CDB[9] = 0;
+
+       if(SCSI_ExecuteCommand( MediumChangerFD, Output, &CDB, 10,
+                                                       NULL, 0, RequestSense) != 0)
+       {
+               return RequestSense;
+       }
+       free(RequestSense);
+       return NULL; /* success */
+}
 
 
 /* Now the actual media movement routine! */
-RequestSense_T *MoveMedium(DEVICE_TYPE MediumChangerFD, int SourceAddress,
-                      int DestinationAddress, 
-                      ElementStatus_T *ElementStatus,
-                      Inquiry_T *inquiry_info, SCSI_Flags_T *flags)
+RequestSense_T *MoveMedium(    DEVICE_TYPE MediumChangerFD, int SourceAddress,
+                                                       int DestinationAddress, 
+                                                       ElementStatus_T *ElementStatus,
+                                                       Inquiry_T *inquiry_info, SCSI_Flags_T *flags)
+{
+       RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T));
+       CDB_T CDB;
+
+       if (inquiry_info->MChngr && inquiry_info->PeripheralDeviceType != MEDIUM_CHANGER_TYPE)
+       {
+               /* if using the ATTACHED API */
+               CDB[0] = 0xA7;          /* MOVE_MEDIUM_ATTACHED */
+       }
+       else
+       {
+               CDB[0] = 0xA5;          /* MOVE MEDIUM */
+       }
+
+       CDB[1] = 0;                     /* Reserved */
+
+       /* Transport Element Address */
+       CDB[2] = (unsigned char)(ElementStatus->TransportElementAddress >> 8);
+       CDB[3] = (unsigned char)ElementStatus->TransportElementAddress;
+
+       /* Source Address */
+       CDB[4] = (unsigned char)(SourceAddress >> 8);
+       CDB[5] = (unsigned char)SourceAddress;
+
+       /* Destination Address */
+       CDB[6] = (unsigned char)(DestinationAddress >> 8);
+       CDB[7] = (unsigned char)DestinationAddress;
+
+       CDB[8] = 0;                     /* Reserved */
+       CDB[9] = 0;                     /* Reserved */
+
+       if (flags->invert)
+       {
+               CDB[10] = 1;                    /* Reserved */
+       }
+       else
+       {
+               CDB[10] = 0;
+       }
+       /* eepos controls the tray for import/export elements, sometimes. */
+       CDB[11] = flags->eepos << 6;                    /* Control */
+
+       if (SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 12,
+                                                       NULL, 0, RequestSense) != 0)
+       {
+#ifdef DEBUG
+               fprintf(stderr, "Move Medium (0x%02X) failed\n", CDB[0]);
+#endif
+               return RequestSense;
+       }
+
+       free(RequestSense);
+       return NULL; /* success! */
+}
+
+
+/* Now the actual Exchange Medium routine! */
+RequestSense_T *ExchangeMedium(        DEVICE_TYPE MediumChangerFD, int SourceAddress,
+                                                               int DestinationAddress, int Dest2Address,
+                                                               ElementStatus_T *ElementStatus,
+                                                               SCSI_Flags_T *flags)
 {
-  RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T));
-  CDB_T CDB;
-  if ((inquiry_info->MChngr) && (inquiry_info->PeripheralDeviceType != MEDIUM_CHANGER_TYPE)) {  /* if using the ATTACHED API */
-    CDB[0]=0xA7;   /* MOVE_MEDIUM_ATTACHED */
-  } else {
-    CDB[0] = 0xA5;             /* MOVE MEDIUM */
-  }
-  CDB[1] = 0;                  /* Reserved */
-  CDB[2] = (ElementStatus->TransportElementAddress >> 8) & 0xFF;  /* Transport Element Address MSB */
-  CDB[3] = (ElementStatus->TransportElementAddress) & 0xff;   /* Transport Element Address LSB */
-  CDB[4] = (SourceAddress >> 8) & 0xFF;        /* Source Address MSB */
-  CDB[5] = SourceAddress & 0xFF; /* Source Address MSB */
-  CDB[6] = (DestinationAddress >> 8) & 0xFF; /* Destination Address MSB */
-  CDB[7] = DestinationAddress & 0xFF; /* Destination Address MSB */
-  CDB[8] = 0;                  /* Reserved */
-  CDB[9] = 0;                  /* Reserved */
-  if (flags->invert) {
-    CDB[10] = 1;                       /* Reserved */
-  } else {
-    CDB[10] = 0;
-  }
-  /* eepos controls the tray for import/export elements, sometimes. */
-  CDB[11] = 0 | (flags->eepos <<6);                    /* Control */
-  
-  if (SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 12,
-                         NULL, 0, RequestSense) != 0) {
-    return RequestSense;
-  }
-  free(RequestSense);
-  return NULL; /* success! */
+       RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T));
+       CDB_T CDB;
+
+       CDB[0] = 0xA6;          /* EXCHANGE MEDIUM */
+       CDB[1] = 0;                     /* Reserved */
+
+       /* Transport Element Address */
+       CDB[2] = (unsigned char)(ElementStatus->TransportElementAddress >> 8);
+       CDB[3] = (unsigned char)ElementStatus->TransportElementAddress;
+
+       /* Source Address */
+       CDB[4] = (unsigned char)(SourceAddress >> 8);
+       CDB[5] = (unsigned char)SourceAddress;
+
+       /* Destination Address */
+       CDB[6] = (unsigned char)(DestinationAddress >> 8);
+       CDB[7] = (unsigned char)DestinationAddress;
+
+       /* move destination back to source? */
+       CDB[8] = (unsigned char)(Dest2Address >> 8);
+       CDB[9] = (unsigned char)Dest2Address;
+       CDB[10] = 0;
+
+       if (flags->invert)
+       {
+               CDB[10] |= 2;                   /* INV2 */
+       }
+
+       if (flags->invert2)
+       {
+               CDB[1] |= 1;                    /* INV1 */
+       }
+
+       /* eepos controls the tray for import/export elements, sometimes. */
+       CDB[11] = flags->eepos << 6;                    /* Control */
+
+#ifdef DEBUG_EXCHANGE
+       dump_cdb(&CDB,12);
+#endif  
+
+       if (SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 12,
+                                                       NULL, 0, RequestSense) != 0)
+       {
+               return RequestSense;
+       }
+       free(RequestSense);
+       return NULL; /* success! */
 }
 
-/* for Linux, this creates a way to do a short erase... the @#$%@ st.c
+
+/*
+ * for Linux, this creates a way to do a short erase... the @#$%@ st.c
  * driver defaults to doing a long erase!
  */
 
-RequestSense_T *Erase(DEVICE_TYPE MediumChangerFD) {
-  RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T));
-  CDB_T CDB;
-
-  CDB[0]=0x19;
-  CDB[1]=0;  /* Short! */
-  CDB[2]=CDB[3]=CDB[4]=CDB[5]=0;
-
-  if (SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 6,
-                         NULL, 0, RequestSense) != 0) {
-    return RequestSense;
-  }
-  free(RequestSense);
-  return NULL;  /* Success! */
-}  
-
-
-#ifdef LONG_PRINT_REQUEST_SENSE
-
-static char *sense_keys[] = {
-  "No Sense",  /* 00 */
-  "Recovered Error", /* 01 */
-  "Not Ready",  /* 02 */
-  "Medium Error",  /* 03 */
-  "Hardware Error",  /* 04 */
-  "Illegal Request",  /* 05 */
-  "Unit Attention", /* 06 */
-  "Data Protect",   /* 07 */
-  "Blank Check", /* 08 */
-  "0x09",   /* 09 */
-  "0x0a",   /* 0a */
-  "Aborted Command", /* 0b */
-  "0x0c",  /* 0c */
-  "Volume Overflow", /* 0d */
-  "Miscompare",   /* 0e */
-  "0x0f"  /* 0f */
-};
+RequestSense_T *Erase(DEVICE_TYPE MediumChangerFD)
+{
+       RequestSense_T *RequestSense = xmalloc(sizeof(RequestSense_T));
+       CDB_T CDB;
 
-static char Yes[]="yes";
-static char No[]="no";
+       CDB[0] = 0x19;
+       CDB[1] = 0;  /* Short! */
+       CDB[2] = CDB[3] = CDB[4] = CDB[5] = 0;
 
-void PrintRequestSense(RequestSense_T *RequestSense)
-{
-  char *msg;
-
-  fprintf(stderr, "mtx: Request Sense: Long Report=yes\n");
-  fprintf(stderr, "mtx: Request Sense: Valid Residual=%s\n", RequestSense->Valid ? Yes : No);
-  if (RequestSense->ErrorCode==0x70) { 
-    msg = "Current" ;
-  } else if (RequestSense->ErrorCode==0x71) { 
-    msg = "Deferred" ;
-  } else {
-    msg = "Unknown?!" ;
-  }
-  fprintf(stderr, "mtx: Request Sense: Error Code=%0x (%s)\n",RequestSense->ErrorCode,msg);
-  fprintf(stderr, "mtx: Request Sense: Sense Key=%s\n",sense_keys[RequestSense->SenseKey]);
-  fprintf(stderr, "mtx: Request Sense: FileMark=%s\n", RequestSense->Filemark ? Yes : No);
-  fprintf(stderr, "mtx: Request Sense: EOM=%s\n", RequestSense->EOM ? Yes : No);
-  fprintf(stderr, "mtx: Request Sense: ILI=%s\n", RequestSense->ILI ? Yes : No);
-  if (RequestSense->Valid) {
-    fprintf(stderr, "mtx: Request Sense: Residual = %02X %02X %02X %02X\n",RequestSense->Information[0],RequestSense->Information[1],RequestSense->Information[2],RequestSense->Information[3]);
-  } 
-  fprintf(stderr,"mtx: Request Sense: Additional Sense Code = %02X\n", RequestSense->AdditionalSenseCode);
-  fprintf(stderr,"mtx: Request Sense: Additional Sense Qualifier = %02X\n", RequestSense->AdditionalSenseCodeQualifier);
-  if (RequestSense->SKSV) {
-    fprintf(stderr,"mtx: Request Sense: Field in Error = %02X\n",RequestSense->BitPointer);
-  }
-  fprintf(stderr,"mtx: Request Sense: BPV=%s\n",RequestSense->BPV ? Yes : No);
-  fprintf(stderr,"mtx: Request Sense: Error in CDB=%s\n",RequestSense->CommandData ? Yes : No);
-  fprintf(stderr,"mtx: Request Sense: SKSV=%s\n",RequestSense->SKSV ? Yes : No);
-  fflush(stderr);
-  if (RequestSense->BPV || RequestSense -> SKSV) {
-    fprintf(stderr,"mtx: Request Sense: Field Pointer = %02X %02X\n",RequestSense->FieldData[0],RequestSense->FieldData[1]);
-  }
+       if (SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 6,
+                                                       NULL, 0, RequestSense) != 0)
+       {
+#ifdef DEBUG
+               fprintf(stderr, "Erase (0x19) failed\n");
+#endif
+               return RequestSense;
+       }
+
+       free(RequestSense);
+       return NULL;            /* Success! */
 }
 
+/* Routine to send an LOAD/UNLOAD from the MMC/SSC spec to a device. 
+ * For tapes and changers this can be used either to eject a tape 
+ * or to eject a magazine (on some Seagate changers, when sent to LUN 1 ).
+ * For CD/DVDs this is used to Load or Unload a disc which is required by
+ * some media changers.
+ */
 
-#else
-void PrintRequestSense(RequestSense_T *RequestSense)
+int LoadUnload(DEVICE_TYPE fd, int bLoad)
 {
-  int i;
-  fprintf(stderr, "mtx: Request Sense: %02X",
-         ((unsigned char *) RequestSense)[0]);
-  for (i = 1; i < sizeof(RequestSense_T); i++)
-    fprintf(stderr, " %02X", ((unsigned char *) RequestSense)[i]);
-  fprintf(stderr, "\n");
+       CDB_T CDB;
+       /* okay, now for the command: */
+
+       CDB[0] = 0x1B;
+       CDB[4] = bLoad ? 3 : 2;
+       CDB[1] = CDB[2] = CDB[3] = CDB[5] = 0;
+
+       if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, NULL, 0, &scsi_error_sense) != 0)
+       {
+#ifdef DEBUG_MODE_SENSE
+               PrintRequestSense(&scsi_error_sense);
+               fprintf(stderr, "Eject (0x1B) failed\n");
+#endif
+               return -1;  /* could not do! */
+       }
+       return 0; /* did do! */
 }
 
+/* Routine to send an START/STOP from the MMC/SSC spec to a device. 
+ * For tape drives this may be required prior to using the changer 
+ * Load or Unload commands.
+ * For CD/DVD drives this is used to Load or Unload a disc which may be
+ * required by some media changers.
+ */
+
+int StartStop(DEVICE_TYPE fd, int bStart)
+{
+       CDB_T CDB;
+       /* okay, now for the command: */
+
+       CDB[0] = 0x1B;
+       CDB[4] = bStart ? 1 : 0;
+       CDB[1] = CDB[2] = CDB[3] = CDB[5] = 0;
+
+       if (SCSI_ExecuteCommand(fd, Input, &CDB, 6,NULL, 0, &scsi_error_sense) != 0)
+       {
+#ifdef DEBUG_MODE_SENSE
+               PrintRequestSense(&scsi_error_sense);
+               fprintf(stderr, "Eject (0x1B) failed\n");
 #endif
+               return -1;  /* could not do! */
+       }
+       return 0; /* did do! */
+}
 
-/* $Date: 2002/09/27 17:23:28 $
- * $Log: mtxl.c,v $
- * Revision 1.8.2.7  2002/09/27 17:23:28  elgreen
- * Don't dereference pointer in barcode stuff
- *
- * Revision 1.8.2.6  2002/09/27 17:20:18  elgreen
- * doh, get rid of the + from the patch process!
- *
- * Revision 1.8.2.5  2002/09/27 17:17:13  elgreen
- * fix copy_barcode
- *
- * Revision 1.8.2.4  2002/09/27 16:49:43  elgreen
- * copy_barcode was off by one (sigh!)
- *
- * Revision 1.8.2.3  2002/02/05 16:51:11  elgreen
- * mtx 1.2.16pre3
- *
- * Revision 1.8.2.2  2002/01/22 16:27:47  elgreen
- * Handle too-big transport element descriptor lengths
- *
- * Revision 1.8.2.1  2002/01/17 22:24:35  elgreen
- * Handle ADIC silliness of saying that it has 1 import/export element whose
- * descriptor is 0 bytes in length
- *
- * Revision 1.8  2001/06/25 23:06:22  elgreen
- * Readying this for 1.2.13 release
- *
- * Revision 1.7  2001/06/25 04:56:35  elgreen
- * Kai to the rescue *again* :-)
- *
- * Revision 1.6  2001/06/24 07:02:01  elgreen
- * Kai's fix was better than mine.
- *
- * Revision 1.5  2001/06/24 06:59:19  elgreen
- * Kai found bug in the barcode backoff.
- *
- * Revision 1.4  2001/06/15 18:56:54  elgreen
- * Arg, it doesn't help to check for 0 robot arms if you force it to 1!
- *
- * Revision 1.3  2001/06/15 14:26:09  elgreen
- * Fixed brain-dead case of HP loaders that report they have no robot arms.
- *
- * Revision 1.2  2001/06/09 17:26:26  elgreen
- * Added 'nobarcode' command to mtx (to skip the initial request asking for
- * barcodes for mtx status purposes).
- *
- * Revision 1.1.1.1  2001/06/05 17:10:25  elgreen
- * Initial import into SourceForge
- *
- * Revision 1.29  2001/05/01 01:39:23  eric
- * Remove the Exabyte special case code, which seemed to be barfing me :-(.
- *
- * Revision 1.28  2001/04/28 00:03:10  eric
- * update for 1.2.12.
- *
- * Revision 1.27  2001/04/18 19:27:39  eric
- * whoops, move ImportExport parser into the $#%!@ ImportExport test :-(.
- *
- * Revision 1.26  2001/04/18 18:55:44  eric
- * turn too many storage elements into a warning rather than a fatal error (sigh!)
- *
- * Revision 1.25  2001/04/18 18:46:54  eric
- * $%!@# "C" precedence rules.
- *
- * Revision 1.24  2001/04/18 17:58:04  eric
- * initialize EmptyStorageElementCount (sigh)
- *
- * Revision 1.23  2001/04/18 16:55:03  eric
- * hopefully get the initialization for element status straigtened out.
- *
- * Revision 1.22  2001/04/18 16:32:59  eric
- * Cleaned up all -Wall messages.
- *
- * Revision 1.21  2001/04/18 16:08:08  eric
- * after re-arranging & fixing bugs
- *
- * Revision 1.20  2001/04/17 21:28:43  eric
- * mtx 1.2.11
- *
- * Revision 1.19  2001/04/02 20:12:48  eric
- * checkin, mtx 1.2.11pre6
- *
- * Revision 1.18  2001/03/06 01:37:05  eric
- * Solaris changes
- *
- * Revision 1.17  2001/02/26 20:56:12  eric
- * added debugging, removed Makefile
- *
- * Revision 1.16  2001/02/19 23:22:28  eric
- * Add E2 bits
- *
- * Revision 1.15  2001/02/19 23:02:04  eric
- * Apply SPARC patch.
- *
- * Revision 1.14  2001/01/26 15:58:10  eric
- * Make work on solaris?
- *
- * Revision 1.13  2001/01/17 19:39:01  eric
- * Changed mtx.h and mtxl.c to use autoconf stuff to figure out which SCSI
- * routines to use (this way, if we ever port to an OS that has an identical
- * SCSI interface to one of the supported OS's, we don't have to do anything
- * special!).
- *
- * Revision 1.12  2001/01/17 16:36:26  eric
- * added date & revision strings as needed
- *
- * Revision 1.11  2000/11/30 20:35:18  eric
- * Added Erase command.
- *
+/* Routine to send a LOCK/UNLOCK from the SSC/MMC spec to a device. 
+ * This can be used to prevent or allow the Tape or CD/DVD from being
+ * removed. 
  */
+
+int LockUnlock(DEVICE_TYPE fd, int bLock)
+{
+       CDB_T CDB;
+       /* okay, now for the command: */
+
+       CDB[0] = 0x1E;
+       CDB[1] = CDB[2] = CDB[3] = CDB[5] = 0;
+       CDB[4] = (char)bLock;
+
+       if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, NULL, 0, &scsi_error_sense) != 0)
+       {
+#ifdef DEBUG_MODE_SENSE
+               PrintRequestSense(&scsi_error_sense);
+               fprintf(stderr, "Eject (0x1B) failed\n");
+#endif
+               return -1;  /* could not do! */
+       }
+       return 0; /* did do! */
+}
+
+static char Spaces[] = "                                                            ";
+
+void PrintHex(int Indent, unsigned char *Buffer, int Length)
+{
+       int             idxBuffer;
+       int             idxAscii;
+       int             PadLength;
+       char    cAscii;
+
+       for (idxBuffer = 0; idxBuffer < Length; idxBuffer++)
+       {
+               if ((idxBuffer % 16) == 0)
+               {
+                       if (idxBuffer > 0)
+                       {
+                               fputc('\'', stderr);
+
+                               for (idxAscii = idxBuffer - 16; idxAscii < idxBuffer; idxAscii++)
+                               {
+                                       cAscii = Buffer[idxAscii] >= 0x20 && Buffer[idxAscii] < 0x7F ? Buffer[idxAscii] : '.';
+                                       fputc(cAscii, stderr);
+                               }
+                               fputs("'\n", stderr);
+                       }
+                       fprintf(stderr, "%.*s%04X: ", Indent, Spaces, idxBuffer);
+               }
+               fprintf(stderr, "%02X ", (unsigned char)Buffer[idxBuffer]);
+       }
+
+       PadLength = 16 - (Length % 16);
+
+       if (PadLength > 0)
+       {
+               fprintf(stderr, "%.*s'", 3 * PadLength, Spaces);
+
+               for (idxAscii = idxBuffer - (16 - PadLength); idxAscii < idxBuffer; idxAscii++)
+               {
+                       cAscii = Buffer[idxAscii] >= 0x20 && Buffer[idxAscii] < 0x80 ? Buffer[idxAscii] : '.';
+                       fputc(cAscii, stderr);
+               }
+               fputs("'\n", stderr);
+       }
+
+       fflush(stderr);
+}
+
+static char *sense_keys[] =
+{
+       "No Sense",                     /* 00 */
+       "Recovered Error",      /* 01 */
+       "Not Ready",            /* 02 */
+       "Medium Error",         /* 03 */
+       "Hardware Error",       /* 04 */
+       "Illegal Request",      /* 05 */
+       "Unit Attention",       /* 06 */
+       "Data Protect",         /* 07 */
+       "Blank Check",          /* 08 */
+       "0x09",                         /* 09 */
+       "0x0a",                         /* 0a */
+       "Aborted Command",      /* 0b */
+       "0x0c",                         /* 0c */
+       "Volume Overflow",      /* 0d */
+       "Miscompare",           /* 0e */
+       "0x0f"                          /* 0f */
+};
+
+static char Yes[] = "yes";
+static char No[] = "no";
+
+void PrintRequestSense(RequestSense_T *RequestSense)
+{
+       char *msg;
+
+       fprintf(stderr, "mtx: Request Sense: Long Report=yes\n");
+       fprintf(stderr, "mtx: Request Sense: Valid Residual=%s\n", RequestSense->Valid ? Yes : No);
+
+       if (RequestSense->ErrorCode == 0x70)
+       { 
+               msg = "Current" ;
+       }
+       else if (RequestSense->ErrorCode == 0x71)
+       {
+               msg = "Deferred" ;
+       }
+       else
+       {
+               msg = "Unknown?!" ;
+       }
+
+       fprintf(stderr, "mtx: Request Sense: Error Code=%0x (%s)\n", RequestSense->ErrorCode, msg);
+       fprintf(stderr, "mtx: Request Sense: Sense Key=%s\n", sense_keys[RequestSense->SenseKey]);
+       fprintf(stderr, "mtx: Request Sense: FileMark=%s\n", RequestSense->Filemark ? Yes : No);
+       fprintf(stderr, "mtx: Request Sense: EOM=%s\n", RequestSense->EOM ? Yes : No);
+       fprintf(stderr, "mtx: Request Sense: ILI=%s\n", RequestSense->ILI ? Yes : No);
+
+       if (RequestSense->Valid)
+       {
+               fprintf(stderr, "mtx: Request Sense: Residual = %02X %02X %02X %02X\n",RequestSense->Information[0],RequestSense->Information[1],RequestSense->Information[2],RequestSense->Information[3]);
+       }
+
+       fprintf(stderr,"mtx: Request Sense: Additional Sense Code = %02X\n", RequestSense->AdditionalSenseCode);
+       fprintf(stderr,"mtx: Request Sense: Additional Sense Qualifier = %02X\n", RequestSense->AdditionalSenseCodeQualifier);
+
+       if (RequestSense->SKSV)
+       {
+               fprintf(stderr,"mtx: Request Sense: Field in Error = %02X\n", RequestSense->BitPointer);
+       }
+
+       fprintf(stderr, "mtx: Request Sense: BPV=%s\n", RequestSense->BPV ? Yes : No);
+       fprintf(stderr, "mtx: Request Sense: Error in CDB=%s\n", RequestSense->CommandData ? Yes : No);
+       fprintf(stderr, "mtx: Request Sense: SKSV=%s\n", RequestSense->SKSV ? Yes : No);
+
+       if (RequestSense->BPV || RequestSense -> SKSV)
+       {
+               fprintf(stderr, "mtx: Request Sense: Field Pointer = %02X %02X\n",
+                               RequestSense->FieldData[0], RequestSense->FieldData[1]);
+       }
+
+       fflush(stderr);
+}