--- /dev/null
+Index: README.win32
+===================================================================
+--- /dev/null Sat Jul 29 14:54:52 2006
++++ README.win32 Sat Jul 29 14:46:45 2006
+@@ -0,0 +1,22 @@
++CHANGES FROM UNIX
++=================
++
++The only difference is in the naming of devices. On Linux the changer is
++accessed using /dev/sg<N>, on Windows you use Changer<N>.
++
++On Linux the tape drive is referenced using /dev/nst<N>, on Windows you use
++Tape<N>.
++
++There is one exception in the case where there isn't a driver loaded for the
++device. This is usually only the case on Windows 2000 or if the Windows XP or
++Windows Server 2003 system supplied driver has been disabled.
++
++In the case where there is no driver loaded you can access the device directly
++through the SCSI driver using the following notation:
++
++ <port>:<bus>:<target>:<lun>
++
++ Port is the adapter number
++ Bus is the SCSI bus number relative to the adapter
++ Target is the SCSI device's target ID
++ LUN is the SCSI device's logical unit number
+Index: scsi_win32.c
+===================================================================
+--- /dev/null Sat Jul 29 14:55:00 2006
++++ scsi_win32.c Sat Jul 29 14:54:08 2006
+@@ -0,0 +1,353 @@
++/* Copyright 2006 Robert Nelson <robertn@the-nelsons.org>
++
++$Date: 2006-07-30 06:32:36 -0700 (Sun, 30 Jul 2006) $
++$Revision: 3200 $
++
++ 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.
++
++*/
++
++/* These are the SCSI commands for Microsoft Windows. This is derived from
++ * the file scsi_linux.c substituting Windows specific emulation of the Linux
++ * behaviour.
++ */
++
++#include <stdio.h>
++#include <windows.h>
++
++#ifdef _MSC_VER
++#include <ntddscsi.h>
++#else
++#include <ddk/ntddscsi.h>
++#endif
++
++#ifndef HZ
++#define HZ 1000
++#endif
++
++/* These are copied out of BRU 16.1, with all the boolean masks changed
++ * to our bitmasks.
++*/
++#define S_NO_SENSE(s) ((s)->SenseKey == 0x0)
++#define S_RECOVERED_ERROR(s) ((s)->SenseKey == 0x1)
++
++#define S_NOT_READY(s) ((s)->SenseKey == 0x2)
++#define S_MEDIUM_ERROR(s) ((s)->SenseKey == 0x3)
++#define S_HARDWARE_ERROR(s) ((s)->SenseKey == 0x4)
++#define S_UNIT_ATTENTION(s) ((s)->SenseKey == 0x6)
++#define S_BLANK_CHECK(s) ((s)->SenseKey == 0x8)
++#define S_VOLUME_OVERFLOW(s) ((s)->SenseKey == 0xd)
++
++#define DEFAULT_TIMEOUT 3 * 60 /* 3 minutes here */
++
++/* Sigh, the T-10 SSC spec says all of the following is needed to
++ * detect a short read while in variable block mode, and that even
++ * though we got a BLANK_CHECK or MEDIUM_ERROR, it's still a valid read.
++ */
++
++#define HIT_FILEMARK(s) (S_NO_SENSE((s)) && (s)->Filemark && (s)->Valid)
++#define SHORT_READ(s) (S_NO_SENSE((s)) && (s)->ILI && (s)->Valid && (s)->AdditionalSenseCode==0 && (s)->AdditionalSenseCodeQualifier==0)
++#define HIT_EOD(s) (S_BLANK_CHECK((s)) && (s)->Valid)
++#define HIT_EOP(s) (S_MEDIUM_ERROR((s)) && (s)->EOM && (s)->Valid)
++#define HIT_EOM(s) ((s)->EOM && (s)->Valid)
++
++#define STILL_A_VALID_READ(s) (HIT_FILEMARK(s) || SHORT_READ(s) || HIT_EOD(s) || HIT_EOP(s) || HIT_EOM(s))
++
++#define SCSI_DEFAULT_TIMEOUT 60 /* 1 minute */
++#define SCSI_MAX_TIMEOUT 108 /* 1 minute 48 seconds */
++
++typedef struct _HANDLE_ENTRY {
++ HANDLE hDevice;
++ UCHAR PortId;
++ UCHAR PathId;
++ UCHAR TargetId;
++ UCHAR Lun;
++} HANDLE_ENTRY, *PHANDLE_ENTRY;
++
++PHANDLE_ENTRY HandleTable = NULL;
++int nEntries = 0;
++
++DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
++{
++ int DeviceIndex;
++ TCHAR szDevicePath[256];
++
++ int nColons = 0;
++ int index;
++
++ int port, path, target, lun;
++
++ for (DeviceIndex = 0; DeviceIndex < nEntries; DeviceIndex++)
++ {
++ if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE)
++ break;
++ }
++
++ if (DeviceIndex >= nEntries)
++ {
++ PHANDLE_ENTRY pNewTable;
++
++ nEntries += 4;
++
++ if (HandleTable == NULL)
++ {
++ pNewTable = (PHANDLE_ENTRY)malloc(nEntries * sizeof(HANDLE_ENTRY));
++ }
++ else
++ {
++ pNewTable = (PHANDLE_ENTRY)realloc(HandleTable, nEntries * sizeof(HANDLE_ENTRY));
++ }
++
++ if (pNewTable == NULL)
++ {
++ FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
++ }
++
++ HandleTable = pNewTable;
++ }
++
++ for (index = 0; DeviceName[index] != '\0'; index++)
++ {
++ if (DeviceName[index] == ':')
++ nColons++;
++ else if (DeviceName[index] < '0' || DeviceName[index] > '9')
++ break;
++ }
++
++ if (DeviceName[index] == '\0' && nColons == 3 &&
++ sscanf(DeviceName, "%d:%d:%d:%d", &port, &path, &target, &lun) == 4) {
++
++ HandleTable[DeviceIndex].PortId = (UCHAR)port;
++ HandleTable[DeviceIndex].PathId = (UCHAR)path;
++ HandleTable[DeviceIndex].TargetId = (UCHAR)target;
++ HandleTable[DeviceIndex].Lun = (UCHAR)lun;
++
++ sprintf(szDevicePath, "\\\\.\\scsi%d:", port);
++ }
++ else
++ {
++ int nPrefixLength = 0;
++
++ if (DeviceName[0] != '\\') {
++ memcpy(szDevicePath, "\\\\.\\", 4 * sizeof(TCHAR));
++ nPrefixLength = 4;
++ }
++
++ HandleTable[DeviceIndex].PortId = 0;
++ HandleTable[DeviceIndex].PathId = 0;
++ HandleTable[DeviceIndex].TargetId = 0;
++ HandleTable[DeviceIndex].Lun = 0;
++
++ strncpy( &szDevicePath[nPrefixLength],
++ DeviceName,
++ sizeof(szDevicePath) / sizeof(TCHAR) - nPrefixLength - 1);
++
++ szDevicePath[sizeof(szDevicePath) / sizeof(TCHAR) - 1] = '\0';
++ }
++
++ HandleTable[DeviceIndex].hDevice = CreateFile(szDevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
++
++ if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE)
++ {
++ DWORD dwError = GetLastError();
++
++#if DEBUG
++ LPSTR lpszMessage;
++
++ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL);
++ fputs(lpszMessage, stderr);
++#endif
++
++ switch (dwError) {
++ case ERROR_FILE_NOT_FOUND:
++ case ERROR_PATH_NOT_FOUND:
++ errno = ENOENT;
++ break;
++
++ case ERROR_TOO_MANY_OPEN_FILES:
++ errno = EMFILE;
++ break;
++
++ default:
++ case ERROR_ACCESS_DENIED:
++ case ERROR_SHARING_VIOLATION:
++ case ERROR_LOCK_VIOLATION:
++ case ERROR_INVALID_NAME:
++ errno = EACCES;
++ break;
++
++ case ERROR_FILE_EXISTS:
++ errno = EEXIST;
++ break;
++
++ case ERROR_INVALID_PARAMETER:
++ errno = EINVAL;
++ break;
++ }
++
++ FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
++ }
++
++ return DeviceIndex;
++}
++
++static int scsi_timeout = SCSI_DEFAULT_TIMEOUT;
++
++void SCSI_Set_Timeout(int secs)
++{
++ if (secs > SCSI_MAX_TIMEOUT) {
++ secs = SCSI_MAX_TIMEOUT;
++ }
++ scsi_timeout = secs * HZ;
++}
++
++void SCSI_Default_Timeout(void)
++{
++ scsi_timeout = SCSI_DEFAULT_TIMEOUT * HZ;
++}
++
++void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
++{
++ if (DeviceFD < nEntries)
++ {
++ CloseHandle(HandleTable[DeviceFD].hDevice);
++ HandleTable[DeviceFD].hDevice = INVALID_HANDLE_VALUE;
++ }
++ else
++ {
++ errno = EBADF;
++ FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
++ }
++}
++
++
++/* Added by Eric Green <eric@estinc.com> to deal with burping
++ * Seagate autoloader (hopefully!).
++ */
++/* Get the SCSI ID and LUN... */
++scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd) {
++ scsi_id_t * retval;
++
++ SCSI_ADDRESS ScsiAddress;
++ BOOL bResult;
++ DWORD dwBytesReturned;
++
++ if (fd < nEntries) {
++ retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
++ retval->id = HandleTable[fd].TargetId;
++ retval->lun = HandleTable[fd].Lun;
++
++#ifdef DEBUG
++ fprintf(stderr,"SCSI:ID=%d LUN=%d\n", retval->id, retval->lun);
++#endif
++ return retval;
++ } else {
++ errno = EBADF;
++ FatalError("cannot close SCSI device - %m\n");
++ }
++
++ memset(&ScsiAddress, 0, sizeof(ScsiAddress));
++
++ ScsiAddress.Length = sizeof(ScsiAddress);
++
++ bResult = DeviceIoControl(HandleTable[fd].hDevice,
++ IOCTL_SCSI_GET_ADDRESS,
++ &ScsiAddress, sizeof(ScsiAddress),
++ &ScsiAddress, sizeof(ScsiAddress),
++ &dwBytesReturned,
++ NULL);
++
++ if (!bResult) {
++ return NULL;
++ }
++
++ retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
++ retval->id = ScsiAddress.TargetId;
++ retval->lun = ScsiAddress.Lun;
++
++#ifdef DEBUG
++ fprintf(stderr,"SCSI:ID=%d LUN=%d\n",retval->id,retval->lun);
++#endif
++ return retval;
++}
++
++int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
++ Direction_T Direction,
++ CDB_T *CDB,
++ int CDB_Length,
++ void *DataBuffer,
++ int DataBufferLength,
++ RequestSense_T *RequestSense)
++{
++ PSCSI_PASS_THROUGH_DIRECT ScsiPassThrough;
++
++ const DWORD dwBufferSize = sizeof(SCSI_PASS_THROUGH_DIRECT) + sizeof(RequestSense_T);
++ BOOL bResult;
++ DWORD dwBytesReturned;
++
++ if (DeviceFD >= nEntries || HandleTable[DeviceFD].hDevice == INVALID_HANDLE_VALUE)
++ {
++ errno = EBADF;
++ return -1;
++ }
++
++ ScsiPassThrough = (PSCSI_PASS_THROUGH_DIRECT)malloc(dwBufferSize);
++
++ memset(ScsiPassThrough, 0, dwBufferSize);
++
++ ScsiPassThrough->Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
++
++ ScsiPassThrough->PathId = HandleTable[DeviceFD].PathId;
++ ScsiPassThrough->TargetId = HandleTable[DeviceFD].TargetId;
++ ScsiPassThrough->Lun = HandleTable[DeviceFD].Lun;
++ ScsiPassThrough->CdbLength = (UCHAR)CDB_Length;
++ ScsiPassThrough->SenseInfoLength = sizeof(RequestSense_T);
++ ScsiPassThrough->DataIn = Direction == Input;
++ ScsiPassThrough->DataTransferLength = DataBufferLength;
++ ScsiPassThrough->TimeOutValue = scsi_timeout;
++ ScsiPassThrough->DataBuffer = DataBuffer;
++ ScsiPassThrough->SenseInfoOffset = sizeof(SCSI_PASS_THROUGH_DIRECT);
++
++ memcpy(ScsiPassThrough->Cdb, CDB, CDB_Length);
++ dwBytesReturned = 0;
++
++ bResult = DeviceIoControl(HandleTable[DeviceFD].hDevice,
++ IOCTL_SCSI_PASS_THROUGH_DIRECT,
++ ScsiPassThrough, sizeof(SCSI_PASS_THROUGH_DIRECT),
++ ScsiPassThrough, dwBufferSize,
++ &dwBytesReturned,
++ NULL);
++ if (bResult) {
++ if (ScsiPassThrough->ScsiStatus != 0) {
++ memcpy(RequestSense, &ScsiPassThrough[1], sizeof(RequestSense_T));
++#if DEBUG
++ fprintf(stderr, "Command failed - ScsiStatus = %d\n", ScsiPassThrough->ScsiStatus);
++ PrintRequestSense(RequestSense);
++#endif
++ bResult = false;
++ }
++ }
++ else
++ {
++#if DEBUG
++ DWORD dwError = GetLastError();
++ LPSTR lpszMessage;
++
++ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL);
++ fputs(lpszMessage, stderr);
++#endif
++
++ memset(RequestSense, 0, sizeof(RequestSense_T));
++ }
++
++ free(ScsiPassThrough);
++
++ return bResult ? 0 : -1;
++}
+Index: tapeinfo.c
+===================================================================
+--- tapeinfo.c (revision 139)
++++ tapeinfo.c (revision 147)
+@@ -211,25 +211,18 @@
+ unsigned int partition1_size;
+ } TapeCapacity;
+
++#if defined(DEBUG)
+ /* DEBUG */
+ static void dump_data(unsigned char *data, int len) {
+- int i;
+ if (!len) {
+ fprintf(stderr,"**NO DATA**\n");
+ return;
+ }
+
+- for (i=0;i<len;i++) {
+- if ((i % 10) == 0) {
+- if (i) {
+- fprintf(stderr,"\n");
+- }
+- fprintf(stderr,"DATA:");
+- }
+- fprintf(stderr,"%02x ",(unsigned int)*data++);
+- }
+- fprintf(stderr,"\n");
++ fprintf(stderr,"DATA:");
++ PrintHex(1, data, len);
+ }
++#endif
+
+
+
+@@ -243,7 +236,7 @@
+
+ unsigned char buffer[TAPEALERT_SIZE]; /* Overkill, but ... */
+
+- slow_bzero(buffer,TAPEALERT_SIZE); /*zero it... */
++ slow_bzero((char *)buffer,TAPEALERT_SIZE); /*zero it... */
+
+ /* now to create the CDB block: */
+ CDB[0]=0x4d; /* Log Sense */
+@@ -325,7 +318,7 @@
+ unsigned char buffer[TAPEALERT_SIZE];
+ unsigned char *walkptr;
+
+- slow_bzero(buffer,TAPEALERT_SIZE); /*zero it... */
++ slow_bzero((char *)buffer,TAPEALERT_SIZE); /*zero it... */
+
+ /* now to create the CDB block: */
+ CDB[0]=0x4d; /* Log Sense */
+@@ -676,7 +669,7 @@
+ the sernum field, and bytes 4 onward are the serial #. */
+
+ lim=(int)buffer[3];
+- bufptr= &(buffer[4]);
++ bufptr=(char *)&(buffer[4]);
+
+ printf("SerialNumber: '");
+ for (i=0;i<lim;i++) {
+@@ -702,7 +695,7 @@
+ CDB[4]=0;
+ CDB[5]=0;
+
+- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T));
++ slow_bzero((char *)&sense,sizeof(RequestSense_T));
+ if (SCSI_ExecuteCommand(fd,Input,&CDB,6,buffer,6,&sense)!=0){
+ return;
+ }
+@@ -735,7 +728,7 @@
+ CDB[8]=0;
+ CDB[9]=0;
+
+- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T));
++ slow_bzero((char *)&sense,sizeof(RequestSense_T));
+
+ /* set the timeout: */
+ SCSI_Set_Timeout(2); /* set timeout to 2 seconds! */
+@@ -789,7 +782,7 @@
+ CDB[4]=0;
+ CDB[5]=0;
+
+- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T));
++ slow_bzero((char *)&sense,sizeof(RequestSense_T));
+ if (SCSI_ExecuteCommand(fd,Input,&CDB,6,buffer,0,&sense)!=0){
+ printf("Ready: no\n");
+ return 0;
+@@ -817,7 +810,7 @@
+ CDB[5]=0;
+
+ /* we really don't care if this command works or not, sigh. */
+- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T));
++ slow_bzero((char *)&sense,sizeof(RequestSense_T));
+ if (SCSI_ExecuteCommand(fd,Input,&CDB,6,buffer,0,&sense)!=0){
+ return 1;
+ }
+Index: mtx.c
+===================================================================
+--- mtx.c (revision 139)
++++ mtx.c (revision 147)
+@@ -623,7 +623,7 @@
+ "illegal <drive-number> argument '%d' to 'unload' command\n",
+ arg2);
+ }
+- if (ElementStatus->DataTransferElementFull[arg2] < 0 ) {
++ if (!ElementStatus->DataTransferElementFull[arg2]) {
+ FatalError("Data Transfer Element %d is Empty\n", arg2);
+ }
+ /* Now see if something already lives where we wanna go... */
+@@ -715,7 +715,7 @@
+ }
+ ElementStatus = ReadElementStatus(MediumChangerFD,&RequestSense,inquiry_info,&SCSI_Flags);
+ if (!ElementStatus) {
+- PrintRequestSense(&RequestSense);
++ PrintRequestSense(&RequestSense);
+ FatalError("READ ELEMENT STATUS Command Failed\n");
+ }
+ }
+@@ -813,9 +813,6 @@
+
+ argv0=argv[0];
+
+-
+-
+-
+ parse_args(); /* also executes them as it sees them, sigh. */
+
+ #ifndef VMS
+Index: scsitape.c
+===================================================================
+--- scsitape.c (revision 139)
++++ scsitape.c (revision 147)
+@@ -41,11 +41,26 @@
+ #include "mtx.h"
+ #include "mtxl.h"
+
++#if HAVE_UNISTD_H
+ #include <unistd.h>
++#endif
++
++#if HAVE_SYS_TYPES_H
+ #include <sys/types.h>
++#endif
++
++#if HAVE_SYS_IOCTL_H
+ #include <sys/ioctl.h>
++#endif
++
++#if HAVE_SYS_MTIO_H
+ #include <sys/mtio.h> /* will try issuing some ioctls for Solaris, sigh. */
++#endif
+
++#ifdef _MSC_VER
++#include <io.h>
++#endif
++
+ void Usage(void) {
+ FatalError("Usage: scsitape -f <generic-device> <command> where <command> is:\n setblk <n> | fsf <n> | bsf <n> | eod | rewind | eject | mark <n> |\n seek <n> | read [<blksize> [<numblocks]] | write [<blocksize>] \n");
+ }
+@@ -54,7 +69,7 @@
+ static int arg[4]; /* the argument for the command, sigh. */
+
+ /* the device handle we're operating upon, sigh. */
+-static unsigned char *device; /* the text of the device thingy. */
++static char *device; /* the text of the device thingy. */
+ static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) 0;
+
+
+@@ -96,43 +111,7 @@
+
+ char *argv0;
+
+-/* A table for printing out the peripheral device type as ASCII. */
+-static char *PeripheralDeviceType[32] = {
+- "Disk Drive",
+- "Tape Drive",
+- "Printer",
+- "Processor",
+- "Write-once",
+- "CD-ROM",
+- "Scanner",
+- "Optical",
+- "Medium Changer",
+- "Communications",
+- "ASC IT8",
+- "ASC IT8",
+- "RAID Array",
+- "Enclosure Services",
+- "OCR/W",
+- "Bridging Expander", /* 0x10 */
+- "Reserved", /* 0x11 */
+- "Reserved", /* 0x12 */
+- "Reserved", /* 0x13 */
+- "Reserved", /* 0x14 */
+- "Reserved", /* 0x15 */
+- "Reserved", /* 0x16 */
+- "Reserved", /* 0x17 */
+- "Reserved", /* 0x18 */
+- "Reserved", /* 0x19 */
+- "Reserved", /* 0x1a */
+- "Reserved", /* 0x1b */
+- "Reserved", /* 0x1c */
+- "Reserved", /* 0x1d */
+- "Reserved", /* 0x1e */
+- "Unknown" /* 0x1f */
+-};
+
+-
+-
+ /* open_device() -- set the 'fh' variable.... */
+ void open_device(void) {
+
+@@ -301,7 +280,7 @@
+ CDB[5]=0;
+
+ /* we really don't care if this command works or not, sigh. */
+- slow_bzero((unsigned char *)&RequestSense,sizeof(RequestSense_T));
++ slow_bzero((char *)&RequestSense,sizeof(RequestSense_T));
+ if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&RequestSense)!=0){
+ PrintRequestSense(&RequestSense);
+ return 1;
+@@ -324,7 +303,7 @@
+ CDB[5]=0;
+
+ /* we really don't care if this command works or not, sigh. */
+- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T));
++ slow_bzero((char *)&sense,sizeof(RequestSense_T));
+ if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&sense)!=0){
+ PrintRequestSense(&sense);
+ return 1;
+@@ -349,7 +328,7 @@
+ CDB[5]=0;
+
+ /* we really don't care if this command works or not, sigh. */
+- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T));
++ slow_bzero((char *)&sense,sizeof(RequestSense_T));
+ if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&sense)!=0){
+ PrintRequestSense(&sense);
+ return 1;
+@@ -392,7 +371,7 @@
+ CDB[5]=0;
+
+ /* we really don't care if this command works or not, sigh. */
+- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T));
++ slow_bzero((char *)&sense,sizeof(RequestSense_T));
+ if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&sense)!=0){
+ PrintRequestSense(&sense);
+ return 1;
+@@ -422,7 +401,7 @@
+ CDB[9]=0;
+
+ /* we really don't care if this command works or not, sigh. */
+- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T));
++ slow_bzero((char *)&sense,sizeof(RequestSense_T));
+ if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,10,buffer,0,&sense)!=0){
+ PrintRequestSense(&sense);
+ return 1;
+@@ -462,7 +441,7 @@
+ static int S_setblk(void) {
+ RequestSense_T sense;
+ CDB_T CDB;
+- unsigned char buffer[12];
++ char buffer[12];
+ unsigned int count = (unsigned int) arg1;
+
+
+@@ -473,7 +452,7 @@
+ CDB[4]=12; /* length of data */
+ CDB[5]=0;
+
+- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T));
++ slow_bzero((char *)&sense,sizeof(RequestSense_T));
+ slow_bzero(buffer,12);
+
+ /* Now to set the mode page header: */
+@@ -679,9 +658,9 @@
+
+ /* S_write is not implemented yet! */
+ static int S_write(void) {
+- unsigned char *buffer; /* the buffer we're gonna read/write out of. */
++ char *buffer; /* the buffer we're gonna read/write out of. */
+ int buffersize;
+- int len; /* the length of the data in the buffer */
++ unsigned int len; /* the length of the data in the buffer */
+ int blocksize=arg[0];
+ int numblocks=arg[1];
+ int varsize=0; /* variable size block flag */
+@@ -755,9 +734,9 @@
+
+
+ static int S_read(void) {
+- unsigned char *buffer; /* the buffer we're going to be reading out of */
++ char *buffer; /* the buffer we're going to be reading out of */
+ int buffersize;
+- int len; /* the length of the data in the buffer */
++ unsigned int len; /* the length of the data in the buffer */
+ int blocksize=arg[0];
+ int numblocks=arg[1];
+ int varsize=0; /* variable size block flag. */
+Index: mtx.h
+===================================================================
+--- mtx.h (revision 139)
++++ mtx.h (working copy)
+@@ -18,7 +18,11 @@
+ #include "[.vms]defs.h"
+ #else /* all the Unix stuff: */
+
++#ifdef _MSC_VER
++#include "msvc/config.h" /* all the autoconf stuff. */
++#else
+ #include "config.h" /* all the autoconf stuff. */
++#endif
+
+ /* all the general Unix includes: */
+
+@@ -59,7 +63,7 @@
+ # include <sys/ioctl.h>
+ #endif
+
+-/* Now greately modified to use GNU Autoconf stuff: */
++/* Now greatly modified to use GNU Autoconf stuff: */
+ /* If we use the 'sg' interface, like Linux, do this: */
+ #if HAVE_SCSI_SG_H
+ # include <scsi/scsi.h>
+@@ -69,6 +73,27 @@
+ # define HAVE_GET_ID_LUN 1 /* signal that we have it... */
+ #endif
+
++/* Windows Native programs built using MinGW */
++#if HAVE_DDK_NTDDSCSI_H
++# include <windows.h>
++# include <ddk/ntddscsi.h>
++# undef DEVICE_TYPE
++
++typedef int DEVICE_TYPE;
++# define HAVE_GET_ID_LUN 1 /* signal that we have it... */
++#endif
++
++/* Windows Native programs built using Microsoft Visual C */
++#ifdef _MSC_VER
++# include <windows.h>
++# include <winioctl.h>
++# include <ntddscsi.h>
++# undef DEVICE_TYPE
++
++typedef int DEVICE_TYPE;
++# define HAVE_GET_ID_LUN 1 /* signal that we have it... */
++#endif
++
+ /* The 'cam' interface, like FreeBSD: */
+ #if HAVE_CAMLIB_H
+ # include <camlib.h> /* easy (?) access to the CAM user library. */
+@@ -176,10 +201,23 @@
+ unsigned char invert2; /* used for EXCHANGE command, sigh. */
+ } SCSI_Flags_T;
+
++#ifdef _MSC_VER
++typedef unsigned char boolean;
++
++#define false 0
++#define true 1
++
++
++typedef unsigned char Direction_T;
++
++#define Input 0
++#define Output 1
++#else
+ typedef enum { false, true } boolean;
+
+
+ typedef enum { Input, Output } Direction_T;
++#endif
+
+
+ typedef unsigned char CDB_T[12];
+@@ -354,6 +392,15 @@
+ } ElementModeSense_T;
+
+
++#ifdef _MSC_VER
++typedef char ElementTypeCode_T;
++
++#define AllElementTypes 0
++#define MediumTransportElement 1
++#define StorageElement 2
++#define ImportExportElement 3
++#define DataTransferElement 4
++#else
+ typedef enum ElementTypeCode
+ {
+ AllElementTypes = 0,
+@@ -363,6 +410,7 @@
+ DataTransferElement = 4
+ }
+ ElementTypeCode_T;
++#endif
+
+
+ typedef struct ElementStatusDataHeader
+Index: nsmhack.c
+===================================================================
+--- nsmhack.c (revision 139)
++++ nsmhack.c (revision 147)
+@@ -33,13 +33,13 @@
+
+ #include "mtxl.h" /* get the SCSI routines out of the main file */
+
+-/*****************************************************************
++/****************************************************************/
+ /* Variables: */
+ /****************************************************************/
+
+ /* the device handle we're operating upon, sigh. */
+-static unsigned char *device; /* the text of the device thingy. */
+-static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) 0;
++static char *device; /* the text of the device thingy. */
++static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) -1;
+ char *argv0;
+ int arg[4]; /* arguments for the command. */
+ #define arg1 (arg[0]) /* for backward compatibility, sigh */
+@@ -74,7 +74,7 @@
+ /* open_device() -- set the 'fh' variable.... */
+ void open_device(void) {
+
+- if (MediumChangerFD) {
++ if (MediumChangerFD != -1) {
+ SCSI_CloseDevice("Unknown",MediumChangerFD); /* close it, sigh... new device now! */
+ }
+
+@@ -101,7 +101,7 @@
+ /* if the device is not already open, then open it from the
+ * environment.
+ */
+- if (!MediumChangerFD) {
++ if (MediumChangerFD == -1) {
+ /* try to get it from STAPE or TAPE environment variable... */
+ device=getenv("STAPE");
+ if (device==NULL) {
+@@ -302,7 +302,7 @@
+ }
+
+ static int S_tongue_in(void) {
+-
++ return 0;
+ }
+
+ /* okay, stick our tongue out. We need a slot ID to grab a caddy from. */
+@@ -326,6 +326,7 @@
+ }
+
+ /* Okay, we have element status, so now let's assume that */
++ return 0;
+ }
+
+ /* See parse_args for the scoop. parse_args does all. */
+Index: mtxl.h
+===================================================================
+--- mtxl.h (revision 139)
++++ mtxl.h (revision 147)
+@@ -27,6 +27,9 @@
+
+ #include "mtx.h"
+
++#undef min
++#undef max
++
+ void FatalError(char *ErrorMessage, ...);
+ void *xmalloc(size_t Size);
+ void *xzmalloc(size_t Size);
+Index: config.h
+===================================================================
+--- ../release/mtx-1.3.9/config.h.in 2003-09-29 19:43:20.000000000 -0700
++++ config.h 2006-07-30 00:42:37.000000000 -0700
+@@ -1,3 +1,4 @@
++/* config.h. Generated by configure. */
+ /* Copyright 2001 Enhanced Software Technologies Inc.
+ * Released under GNU General Public License V2 or Above
+ * See http://www.gnu.org for more information about the terms of
+@@ -10,10 +11,10 @@
+ #define CONFIG_H 1
+
+ /* autoconf changes these. */
+-#define HAVE_STRING_H 0
+-#define HAVE_UNISTD_H 0
+-#define HAVE_STDLIB_H 0
+-#define HAVE_STDARG_H 0
++#define HAVE_STRING_H 1
++#define HAVE_UNISTD_H 1
++#define HAVE_STDLIB_H 1
++#define HAVE_STDARG_H 1
+ #define HAVE_SCSI_SCSI_H 0
+ #define HAVE_SCSI_SCSI_IOCTL_H 0
+ #define HAVE_SCSI_SG_H 0
+@@ -23,10 +24,12 @@
+ #define HAVE_SYS_SCSI_CTL_H 0
+ #define HAVE_DSLIB_H 0
+ #define HAVE_DU_DEFS_H 0
+-#define HAVE_SYS_STAT_H 0
+-#define HAVE_SYS_TYPES_H 0
+-#define HAVE_FCNTL_H 0
++#define HAVE_SYS_STAT_H 1
++#define HAVE_SYS_TYPES_H 1
++#define HAVE_FCNTL_H 1
+ #define HAVE_SYS_IOCTL_H 0
++#define HAVE_SYS_MTIO_H 0
++#define HAVE_DDK_NTDDSCSI_H 1
+
+ #define WORDS_BIGENDIAN 0
+
+Index: mtxl.c
+===================================================================
+--- ../release/mtx-1.3.9/mtxl.c 2003-10-02 23:03:20.000000000 -0700
++++ mtxl.c 2006-07-30 00:49:31.000000000 -0700
+@@ -53,6 +53,11 @@
+ # 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"
+@@ -78,6 +83,7 @@
+ #include "[.vms]scsi.c"
+ #endif
+
++void PrintHex(int Indent, unsigned char *Buffer, int Length);
+ extern char *argv0; /* something to let us do good error messages. */
+
+ /* create a global RequestSenseT value. */
+@@ -104,6 +110,9 @@
+ 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! */
+ }
+@@ -111,36 +120,27 @@
+ }
+
+
++#if defined(DEBUG_NSM) || defined(DEBUG_EXCHANGE)
+ /* DEBUG */
+ static void dump_cdb(unsigned char *CDB, int len) {
+- int i;
+ fprintf(stderr,"CDB:");
+- for (i=0;i<len;i++) {
+- fprintf(stderr,"%02x ",CDB[i]);
+- }
+- fprintf(stderr,"\n");
++ PrintHex(1, CDB, len);
+ }
++#endif
+
+
++#if defined(DEBUG_NSM) || defined(DEBUG_ADIC)
+ /* DEBUG */
+ static void dump_data(unsigned char *data, int len) {
+- int i;
+ if (!len) {
+ fprintf(stderr,"**NO DATA**\n");
+ return;
+ }
+
+- for (i=0;i<len;i++) {
+- if ((i % 10) == 0) {
+- if (i) {
+- fprintf(stderr,"\n");
+- }
+- fprintf(stderr,"DATA:");
+- }
+- fprintf(stderr,"%02x ",(unsigned int)*data++);
+- }
+- fprintf(stderr,"\n");
++ fprintf(stderr,"DATA:");
++ PrintHex(1, data, len);
+ }
++#endif
+
+
+ int BigEndian16(unsigned char *BigEndianData)
+@@ -255,7 +255,7 @@
+
+
+ /* Okay, this is a hack for the NSM modular jukebox series, which
+- * uses the "SEND DIAGNOSTIC" command do to shit.
++ * uses the "SEND DIAGNOSTIC" command to do shit.
+ */
+
+ int SendNSMHack(DEVICE_TYPE MediumChangerFD, NSM_Param_T *nsm_command,
+@@ -346,6 +346,10 @@
+ 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! */
+@@ -364,6 +368,10 @@
+ CDB[1]=CDB[2]=CDB[3]=CDB[4]=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! */
+@@ -396,7 +404,8 @@
+ if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,
+ &input_buffer,sizeof(input_buffer),&scsi_error_sense) != 0) {
+ #ifdef DEBUG_MODE_SENSE
+- fprintf(stderr,"Could not execute mode sense...\n");
++ PrintRequestSense(&scsi_error_sense);
++ fprintf(stderr,"Mode sense (0x1A) for Page 0x1D failed\n");
+ fflush(stderr);
+ #endif
+ return NULL; /* sorry, couldn't do it. */
+@@ -405,18 +414,7 @@
+ /* Could do it, now build return value: */
+
+ #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);
+- }
++ PrintHex(0, input_buffer, 30);
+ #endif
+ /* first, skip past: mode data header, and block descriptor header if any */
+ sense_page=(ElementModeSensePage_T *)(input_buffer+4+input_buffer[3]);
+@@ -444,11 +442,11 @@
+
+ #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);
++ 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);
++ sense_page->NumMediumTransportHi,sense_page->NumMediumTransportLo,
++ sense_page->NumDataTransferHi,sense_page->NumDataTransferLo);
+ fflush(stderr);
+ #endif
+
+@@ -620,19 +618,16 @@
+ CDB[11] = 0; /* Control */
+
+ #ifdef DEBUG_BARCODE
+- {
+- int i;
+- fprintf(stderr,"CDB= ");
+- for (i=0;i<12;i++) {
+- fprintf(stderr,"%x ",CDB[i]);
+- }
+- fprintf(stderr,"\n");
+- fflush(stderr);
+- }
++ fprintf(stderr,"CDB:\n");
++ PrintHex(2, CDB, 12);
+ #endif
+
+ if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 12,
+ DataBuffer,NumBytes, RequestSense) != 0){
++
++#ifdef DEBUG
++ fprintf(stderr, "Read Element Status (0x%02X) failed\n", CDB[0]);
++#endif
+ /* 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
+@@ -654,15 +649,8 @@
+ 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);
+- }
++ fprintf(stderr,"CDB:\n");
++ PrintHex(2, CDB, 12);
+ #endif
+
+ if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 12,
+@@ -679,14 +667,8 @@
+ #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++) {
+- fprintf(stderr,"%02x ",DataBuffer[i]);
+- }
+- fprintf(stderr,"\n");
+- }
++ fprintf(stderr,"Data:\n");
++ PrintHex(2, DataBuffer, 40);
+ #endif
+ return DataBuffer; /* we succeeded! */
+ }
+@@ -703,7 +685,7 @@
+ ) {
+
+ unsigned char *DataBuffer; /* size of data... */
+- unsigned int real_numbytes;
++ int real_numbytes;
+
+
+ DataBuffer=SendElementStatusRequestActual(MediumChangerFD,
+@@ -950,34 +932,42 @@
+ 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);
+- }
+- }
++#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);
++ }
+ }
++ }
+ }
+
+ /********************* Real ReadElementStatus ********************* */
+@@ -1008,7 +998,6 @@
+ int *EmptyStorageElementAddress; /* [MAX_STORAGE_ELEMENTS]; */
+
+ int empty_idx=0;
+- int invalid_sources=0;
+ boolean is_attached = false;
+ int i,j;
+
+@@ -1049,7 +1038,7 @@
+
+ EmptyStorageElementAddress=(int *)xzmalloc((mode_sense->NumStorage+1)*sizeof(int));
+ for (i=0;i<mode_sense->NumStorage;i++) {
+- EmptyStorageElementAddress[i]=-1;
++ EmptyStorageElementAddress[i] = -1;
+ }
+
+ /* Okay, now to send some requests for the various types of stuff: */
+@@ -1076,6 +1065,9 @@
+ #endif
+ /* darn. Free up stuff and return. */
+ /****FIXME**** do a free on element data! */
++#ifdef DEBUG_MODE_SENSE
++ PrintRequestSense(RequestSense);
++#endif
+ FreeElementData(ElementStatus);
+ return NULL;
+ }
+@@ -1107,6 +1099,9 @@
+ #endif
+ /* darn. Free up stuff and return. */
+ /****FIXME**** do a free on element data! */
++#ifdef DEBUG_MODE_SENSE
++ PrintRequestSense(RequestSense);
++#endif
+ FreeElementData(ElementStatus);
+ return NULL;
+ }
+@@ -1138,6 +1133,9 @@
+ #endif
+ /* darn. Free up stuff and return. */
+ /****FIXME**** do a free on element data! */
++#ifdef DEBUG_MODE_SENSE
++ PrintRequestSense(RequestSense);
++#endif
+ FreeElementData(ElementStatus);
+ return NULL;
+ }
+@@ -1172,6 +1170,9 @@
+ #endif
+ /* darn. Free up stuff and return. */
+ /****FIXME**** do a free on element data! */
++#ifdef DEBUG_MODE_SENSE
++ PrintRequestSense(RequestSense);
++#endif
+ FreeElementData(ElementStatus);
+ return NULL;
+ }
+@@ -1223,34 +1224,24 @@
+ * 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;
+- }
+-
+- } else {
+- /* if element # was not >=0, then we had an invalid source anyhow! */
+- invalid_sources=1;
++ /* 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;
++ }
++ }
++ }
+ }
+ }
+ }
+@@ -1267,21 +1258,19 @@
+ * 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]) {
++ 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);
++ 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++];
+- }
+ }
+ }
+
+@@ -1337,9 +1326,9 @@
+ 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[5] = SourceAddress & 0xFF; /* Source Address LSB */
+ CDB[6] = (DestinationAddress >> 8) & 0xFF; /* Destination Address MSB */
+- CDB[7] = DestinationAddress & 0xFF; /* Destination Address MSB */
++ CDB[7] = DestinationAddress & 0xFF; /* Destination Address LSB */
+ CDB[8] = 0; /* Reserved */
+ CDB[9] = 0; /* Reserved */
+ if (flags->invert) {
+@@ -1351,7 +1340,11 @@
+ CDB[11] = 0 | (flags->eepos <<6); /* Control */
+
+ if (SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 12,
+- NULL, 0, RequestSense) != 0) {
++ NULL, 0, RequestSense) != 0) {
++
++#ifdef DEBUG
++ fprintf(stderr, "Move Medium (0x%02X) failed\n", CDB[0]);
++#endif
+ return RequestSense;
+ }
+ free(RequestSense);
+@@ -1372,9 +1365,9 @@
+ 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[5] = SourceAddress & 0xFF; /* Source Address LSB */
+ CDB[6] = (DestinationAddress >> 8) & 0xFF; /* Destination Address MSB */
+- CDB[7] = DestinationAddress & 0xFF; /* Destination Address MSB */
++ CDB[7] = DestinationAddress & 0xFF; /* Destination Address LSB */
+ CDB[8] = (Dest2Address>>8) & 0xFF; /* move destination back to source? */
+ CDB[9] = Dest2Address & 0xFF; /* move destination back to source? */
+ CDB[10]=0;
+@@ -1418,12 +1411,53 @@
+
+ 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! */
+ }
+
++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);
++}
+
+ #ifdef LONG_PRINT_REQUEST_SENSE
+
+@@ -1488,12 +1522,9 @@
+ #else
+ void PrintRequestSense(RequestSense_T *RequestSense)
+ {
+- 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");
++ fprintf(stderr, "mtx: Request Sense: %02X\n",
++ ((unsigned char *) RequestSense)[0]);
++ PrintHex(2, (char *)RequestSense, sizeof(RequestSense_T));
+ }
+
+ #endif
+Index: Makefile
+===================================================================
+--- ../release/mtx-1.3.9/Makefile.in 2006-02-20 13:42:10.000000000 -0800
++++ Makefile 2006-07-30 01:22:00.000000000 -0700
+@@ -11,26 +11,28 @@
+ # Version # for 'make dist'...
+ VERSION=1.3.9
+
+-BINS = mtx tapeinfo loaderinfo scsitape nsmhack
++BINS = mtx.exe tapeinfo.exe loaderinfo.exe scsitape.exe nsmhack.exe
++DBGS := $(BINS:%.exe=%.dbg)
+
+-TARGET = @TARGET@
+-CPU = @CPU@
+-CC = @CC@
+-INSTALL = @INSTALL@
+-
+-CFLAGS = @CFLAGS@
+-CPPFLAGS = @CPPFLAGS@ -DVERSION="\"$(VERSION)\""
+-LDFLAGS = @LDFLAGS@
+-LIBS = @LIBS@
++TARGET = mingw
++CPU = 386
++CC = mingw32-gcc
++INSTALL = install -c
++
++CFLAGS = -g -O2
++CPPFLAGS = -DVERSION="\"$(VERSION)\""
++LDFLAGS =
++LIBS =
++USE_OBJCOPY = yes
+
+ INSTALL_DOC = $(INSTALL) -m 644
+ INSTALL_BIN = $(INSTALL) -m 755
+ INSTALL_DIR = $(INSTALL) -m 755 -d
+
+-prefix = @prefix@
+-exec_prefix = @exec_prefix@
+-sbindir = @sbindir@
+-mandir = @mandir@
++prefix = dummy
++exec_prefix = ${prefix}
++sbindir = ${exec_prefix}/bin
++mandir = ${prefix}/man
+
+ #
+ # Linux on x86...
+@@ -40,6 +42,11 @@
+ CPPFLAGS += -I/usr/src/linux/include -DLONG_PRINT_REQUEST_SENSE=1
+ endif
+
++ifeq ($(TARGET),mingw)
++CFLAGS += -Wall
++CPPFLAGS += -DLONG_PRINT_REQUEST_SENSE=1
++endif
++
+ #
+ # FreeBSD on x86...
+ #
+@@ -82,12 +89,22 @@
+ See vms/000readme for information.
+ endif
+
++%.dbg : %.exe
++ifeq ($(USE_OBJCOPY),yes)
++ mingw32-objcopy --only-keep-debug $< $@
++ mingw32-objcopy --strip-debug $<
++ mingw32-objcopy --add-gnu-debuglink=$@ $<
++else
++ strip $< -o $@
++endif
++
+ all: $(BINS)
+
+-install: $(BINS)
++dbgs: $(DBGS)
++
++install: $(BINS) $(DBGS)
+ $(INSTALL_DIR) $(sbindir)
+ for file in $(BINS); do \
+- strip "$$file" ; \
+ $(INSTALL_BIN) "$$file" $(sbindir) ; \
+ done
+ $(INSTALL_DIR) $(mandir) $(mandir)/man1
+@@ -98,7 +115,9 @@
+ clean:
+ rm -f *.o *~
+ rm -f $(BINS)
+- rm -f mam2debug mam2debug2
++ rm -f $(DBGS)
++ rm -f mam2debug.exe mam2debug2.exe
++ rm -rf autom4te.cache
+
+ distclean: clean
+ rm -f Makefile config.log config.cache config.status
+@@ -106,27 +125,26 @@
+ dist: distclean
+ ./makedist $(VERSION)
+
+-loaderinfo: loaderinfo.o mtxl.o mtxl.h mtx.h $(EXTRA)
+- $(CC) $(LDFLAGS) -o loaderinfo loaderinfo.o mtxl.o $(EXTRA) $(LIBS)
+-
++loaderinfo.exe: loaderinfo.o mtxl.o mtxl.h mtx.h $(EXTRA)
++ $(CC) $(LDFLAGS) -o $@ loaderinfo.o mtxl.o $(EXTRA) $(LIBS)
+
+-nsmhack: nsmhack.o mtxl.o $(EXTRA)
+- $(CC) $(LDFLAGS) -o nsmhack nsmhack.o mtxl.o $(EXTRA) $(LIBS)
++nsmhack.exe: nsmhack.o mtxl.o $(EXTRA)
++ $(CC) $(LDFLAGS) -o $@ nsmhack.o mtxl.o $(EXTRA) $(LIBS)
+
+-mtx: mtx.o mtxl.o mtxl.h mtx.h $(EXTRA)
+- $(CC) $(LDFLAGS) -o mtx mtx.o mtxl.o $(EXTRA) $(LIBS)
++mtx.exe: mtx.o mtxl.o mtxl.h mtx.h $(EXTRA)
++ $(CC) $(LDFLAGS) -o $@ mtx.o mtxl.o $(EXTRA) $(LIBS)
+
+-mam2debug: mtxl.o mam2debug.o mtx.h $(EXTRA)
+- $(CC) $(LDFLAGS) -o mam2debug mtxl.o mam2debug.o $(EXTRA) $(LIBS)
++mam2debug.exe: mtxl.o mam2debug.o mtx.h $(EXTRA)
++ $(CC) $(LDFLAGS) -o $@ mtxl.o mam2debug.o $(EXTRA) $(LIBS)
+
+-tapeinfo: tapeinfo.o mtxl.o mtx.h mtxl.h $(EXTRA)
+- $(CC) $(LDFLAGS) -o tapeinfo tapeinfo.o mtxl.o $(EXTRA) $(LIBS)
++tapeinfo.exe: tapeinfo.o mtxl.o mtx.h mtxl.h $(EXTRA)
++ $(CC) $(LDFLAGS) -o $@ tapeinfo.o mtxl.o $(EXTRA) $(LIBS)
+
+-mam2debug2: mtxl.o mam2debug2.o mtx.h $(EXTRA)
+- $(CC) $(LDFLAGS) -o mam2debug2 mtxl.o mam2debug2.o $(EXTRA) $(LIBS)
++mam2debug2.exe: mtxl.o mam2debug2.o mtx.h $(EXTRA)
++ $(CC) $(LDFLAGS) -o $@ mtxl.o mam2debug2.o $(EXTRA) $(LIBS)
+
+-scsitape: scsitape.o mtxl.o mtxl.h mtx.h $(EXTRA)
+- $(CC) $(LDFLAGS) -o scsitape scsitape.o mtxl.o $(EXTRA) $(LIBS)
++scsitape.exe: scsitape.o mtxl.o mtxl.h mtx.h $(EXTRA)
++ $(CC) $(LDFLAGS) -o $@ scsitape.o mtxl.o $(EXTRA) $(LIBS)
+
+ scsitape.o: scsitape.c mtx.h mtxl.h
+
+@@ -140,6 +158,6 @@
+
+ mtx.o: mtx.c mtx.h mtxl.h
+
+-mtxl.o: mtxl.c mtx.h mtxl.h scsi_linux.c
++mtxl.o: mtxl.c mtx.h mtxl.h scsi_linux.c scsi_win32.c
+
+ nsmhack.o: nsmhack.c mtxl.h mtx.h