Logo Search packages:      
Sourcecode: cdrkit version File versions  Download package

scsi-wnt.c

/*
 * This file has been modified for the cdrkit suite.
 *
 * The behaviour and appearence of the program code below can differ to a major
 * extent from the version distributed by the original author(s).
 *
 * For details, see Changelog file distributed with the cdrkit package. If you
 * received this file from another source then ask the distributing person for
 * a log of modifications.
 *
 */

/* @(#)scsi-wnt.c 1.45 04/07/19 Copyright 1998-2004 J. Schilling, A.L. Faber, J.A. Key */
/*
 *    Interface for the Win32 ASPI library.
 *          You need wnaspi32.dll and aspi32.sys
 *          Both can be installed from ASPI_ME
 *
 *    Warning: you may change this source, but if you do that
 *    you need to change the _usal_version and _usal_auth* string below.
 *    You may not return "schily" for an SCG_AUTHOR request anymore.
 *    Choose your name instead of "schily" and make clear that the version
 *    string is related to a modified source.
 *
 *    Copyright (c) 1998-2004 J. Schilling
 *    Copyright (c) 1999 A.L. Faber for the first implementation
 *                   of this interface.
 *    TODO:
 *    -     DMA resid handling
 *    -     better handling of maxDMA
 *    -     SCSI reset support
 */
/*
 * This program is free software; you can redistribute it 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 more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; see the file COPYING.  If not, write to the Free Software
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */


/*
 * Include for Win32 ASPI AspiRouter
 *
 * NOTE: aspi-win32.h includes Windows.h and Windows.h includes
 *     Base.h which has a second typedef for BOOL.
 *     We define BOOL to make all local code use BOOL
 *     from Windows.h and use the hidden __SBOOL for
 *     our global interfaces.
 */
#define     BOOL  WBOOL       /* This is the Win BOOL       */
#define     format      __format
#include <usal/aspi-win32.h>
#include <usal/spti-wnt.h>
#undef format

#ifdef      __CYGWIN32__            /* Use dlopen()               */
#include <dlfcn.h>
#endif

/*
 *    Warning: you may change this source, but if you do that
 *    you need to change the _usal_version and _usal_auth* string below.
 *    You may not return "schily" for an SCG_AUTHOR request anymore.
 *    Choose your name instead of "schily" and make clear that the version
 *    string is related to a modified source.
 */
static      char  _usal_trans_version[] = "scsi-wnt.c-1.45";      /* The version for this transport*/
static      char  _usal_itrans_version[] = "SPTI-scsi-wnt.c-1.45";      /* The version for SPTI */

/*
 * Local defines and constants
 */
/*#define DEBUG_WNTASPI*/

#define     MAX_SCG           16    /* Max # of SCSI controllers  */
#define     MAX_TGT           16    /* Max # of SCSI Targets      */
#define     MAX_LUN           8     /* Max # of SCSI LUNs         */

#ifdef DEBUG_WNTASPI
#endif

struct usal_local {
      int   dummy;
      char *filenames[MAX_SCG][MAX_TGT][MAX_LUN];
      char drive_wanted;
};
#define     usallocal(p)      ((struct usal_local *)((p)->local))

/*
 * Local variables
 */
static      int   busses;
static      DWORD (*pfnGetASPI32SupportInfo)(void)          = NULL;
static      DWORD (*pfnSendASPI32Command)(LPSRB)                  = NULL;
static      BOOL  (*pfnGetASPI32Buffer)(PASPI32BUFF)        = NULL;
static      BOOL  (*pfnFreeASPI32Buffer)(PASPI32BUFF)       = NULL;
static      BOOL  (*pfnTranslateASPI32Address)(PDWORD, PDWORD)    = NULL;

static      int   DriverLoaded                  = 0;    /* ASPI or SPTI */
static      HANDLE      hAspiLib                = NULL;     /* Used for Loadlib */

#define     MAX_DMA_WNT (63L*1024L) /* ASPI-Driver  allows up to 64k ??? */

/*
 * Local function prototypes
 */
static      void  exit_func(void);
#ifdef DEBUG_WNTASPI
static      void  DebugScsiSend(SCSI *usalp, SRB_ExecSCSICmd *s, int bDisplayBuffer);
#endif
static      void  copy_sensedata(SRB_ExecSCSICmd *cp, struct usal_cmd *sp);
static      void  set_error(SRB_ExecSCSICmd *cp, struct usal_cmd *sp);
static      BOOL  open_driver(SCSI *usalp);
static      BOOL  load_aspi(SCSI *usalp);
static      BOOL  close_driver(void);
static      int   ha_inquiry(SCSI *usalp, int id, SRB_HAInquiry   *ip);
#ifdef      __USED__
static      int   resetSCSIBus(SCSI *usalp);
#endif
static      int   scsiabort(SCSI *usalp, SRB_ExecSCSICmd *sp);


/* SPTI Start ---------------------------------------------------------------*/
/*
 * From scsipt.c - Copyright (C) 1999 Jay A. Key
 * Homepage: http://akrip.sourceforge.net/
 * Native NT support functions via the SCSI Pass Through interface instead
 * of ASPI.  Although based on information from the NT 4.0 DDK from
 * Microsoft, the information has been sufficiently distilled to allow
 * compilation w/o having the DDK installed.
 * added to scsi-wnt.c by Richard Stemmer, rs@epost.de
 * See http://www.ste-home.de/cdrtools-spti/
 */

#define     PREFER_SPTI 1           /* Prefer SPTI if available, else try ASPI, force ASPI with dev=ASPI: */
/* #define  CREATE_NONSHARED 1 */   /* open CDROM-Device not SHARED if possible */
/* #define  _DEBUG_SCSIPT 1   */
#ifdef _DEBUG_SCSIPT
FILE *usalp_errfile; /* File for SPTI-Debug-Messages */
#endif

#define     SENSE_LEN_SPTI          32    /* Sense length for ASPI is only 14 */
#define     NUM_MAX_NTSCSI_DRIVES   26    /* a: ... z:                  */
#define     NUM_FLOPPY_DRIVES 2
#define     NUM_MAX_NTSCSI_HA NUM_MAX_NTSCSI_DRIVES

#define     NTSCSI_HA_INQUIRY_SIZE  36

#define     SCSI_CMD_INQUIRY  0x12

typedef struct {
      BYTE  ha;               /* SCSI Bus #                 */
      BYTE  tgt;              /* SCSI Target #        */
      BYTE  lun;              /* SCSI Lun #                 */
      BYTE  PortNumber;       /* SCSI Card # (\\.\SCSI%d)   */
      BYTE  PathId;                 /* SCSI Bus/Channel # on card n     */
      BYTE  driveLetter;            /* Win32 drive letter (e.g. c:)     */
      BOOL  bUsed;                  /* Win32 drive letter is used */
      HANDLE      hDevice;          /* Win32 handle for ioctl()   */
      BYTE  inqData[NTSCSI_HA_INQUIRY_SIZE];
} DRIVE;

typedef struct {
      BYTE  numAdapters;
      DRIVE drive[NUM_MAX_NTSCSI_DRIVES];
} SPTIGLOBAL;

static      int   InitSCSIPT(SCSI *usalp);
static      int   DeinitSCSIPT(void);
static      void  GetDriveInformation(BYTE i, DRIVE *pDrive);
static      BYTE  SPTIGetNumAdapters(void);
static      BYTE  SPTIGetDeviceIndex(BYTE ha, BYTE tgt, BYTE lun);
static      DWORD SPTIHandleHaInquiry(LPSRB_HAInquiry lpsrb);
static      DWORD SPTIExecSCSICommand(LPSRB_ExecSCSICmd lpsrb, int sptTimeOutValue, BOOL bBeenHereBefore);
static      HANDLE      GetFileHandle(BYTE i, BOOL openshared);

static      BOOL  bSCSIPTInit = FALSE;
static      SPTIGLOBAL sptiglobal;
static      BOOL  UsingSPTI = FALSE;
static      BOOL  ForceAccess = FALSE;
static      int   sptihamax;
static      USHORT      sptihasortarr[NUM_MAX_NTSCSI_HA];

/*
 * Initialization of SCSI Pass Through Interface code.  Responsible for
 * setting up the array of SCSI devices.  This code will be a little
 * different from the normal code -- it will query each drive letter from
 * C: through Z: to see if it is  a CD.  When we identify a CD, we then
 * send CDB with the INQUIRY command to it -- NT will automagically fill in
 * the PathId, TargetId, and Lun for us.
 */
static int InitSCSIPT(SCSI *usalp) {
      BYTE  i;
      BYTE  j;
      char  buf[4];
      UINT  uDriveType;
      int   retVal = 0;
      USHORT hasortval;
      char adapter_name[20];
      HANDLE      fh;
      ULONG returned;
      BOOL  status;
      char  InquiryBuffer[2048];
      PSCSI_ADAPTER_BUS_INFO  ai;
      BYTE  bus;
      int   id_wanted=-1;

      if (bSCSIPTInit)
            return (0);

      /*
       * Detect all Busses on all SCSI-Adapters
       * Fill up map array that allows us to later assign devices to
       * bus numbers.
       */
      sptihamax = 0;
      i = 0;
      do {
            snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\SCSI%d:", i);
            fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE,
                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
                                    NULL,
                                    OPEN_EXISTING, 0, NULL);
            if (fh != INVALID_HANDLE_VALUE) {
                  status      = DeviceIoControl(fh,
                                    IOCTL_SCSI_GET_INQUIRY_DATA,
                                    NULL,
                                    0,
                                    InquiryBuffer,
                                    2048,
                                    &returned,
                                    FALSE);
                  if (status) {
                        ai = (PSCSI_ADAPTER_BUS_INFO) InquiryBuffer;
                        for (bus = 0; bus < ai->NumberOfBusses; bus++) {
                              sptihasortarr[sptihamax] = ((i<<8) | bus);
                              sptihamax++;
                        }
                  }
                  CloseHandle(fh);
            }
            i++;
      } while (fh != INVALID_HANDLE_VALUE);

      errno = 0;
      memset(&sptiglobal, 0, sizeof (SPTIGLOBAL));
      for (i = 0; i < NUM_MAX_NTSCSI_DRIVES; i++)
            sptiglobal.drive[i].hDevice = INVALID_HANDLE_VALUE;

      for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++) {
            snprintf(buf, sizeof (buf), "%c:\\", (char)('A'+i));
            uDriveType = GetDriveType(buf);
#ifdef      CDROM_ONLY
            if (uDriveType == DRIVE_CDROM) {
#else
            if (TRUE) {
#endif
                  GetDriveInformation(i, &sptiglobal.drive[i]);

                  if (sptiglobal.drive[i].bUsed) {
                        retVal++;
                        hasortval = (sptiglobal.drive[i].PortNumber<<8) | sptiglobal.drive[i].PathId;
                        for (j = 0; j < sptihamax; j++) {
                              if (hasortval <= sptihasortarr[j])
                                    break;
                        }
                        if (j == sptihamax) {
                              sptihasortarr[j] = hasortval;
                              sptihamax++;
                        } else if (hasortval < sptihasortarr[j]) {
                              memmove(&sptihasortarr[j+1], &sptihasortarr[j], (sptihamax-j) * sizeof (USHORT));
                              sptihasortarr[j] = hasortval;
                              sptihamax++;
                        }

                        /* shortcut for device names, remember the hit */
                        if(uDriveType==DRIVE_CDROM && usalp->local) {
                              /* printf("seen, %d at %d, %d, %d\n", sptiglobal.drive[i].driveLetter, sptiglobal.drive[i].ha, sptiglobal.drive[i].tgt, sptiglobal.drive[i].lun); */
                               if(usallocal(usalp)->drive_wanted && *buf==toupper(usallocal(usalp)->drive_wanted))
                                     id_wanted=i;
                               /* don't keep the names, serial search in _natname is sufficient */
                        }
                  }
            }
      }
            /* looks like a workaround for diverging ASPI and SPTI hostadapter numbers,
               most likely an attempt to keep the world of fake numbers
               consistent;
               EB */
      if (sptihamax > 0) {
            for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++)
                  if (sptiglobal.drive[i].bUsed)
                        for (j = 0; j < sptihamax; j++) {
                              if (sptihasortarr[j] == ((sptiglobal.drive[i].PortNumber<<8) | sptiglobal.drive[i].PathId)) {
                                    sptiglobal.drive[i].ha = j;
                                    break;
                              }
                        }
      }
      sptiglobal.numAdapters = SPTIGetNumAdapters();

      bSCSIPTInit = TRUE;
      if(id_wanted>0) {
            usal_scsibus(usalp)=sptiglobal.drive[id_wanted].ha;
            usal_target(usalp) =sptiglobal.drive[id_wanted].tgt;
            usal_lun(usalp)    =sptiglobal.drive[id_wanted].lun;

            //#if 1
            #ifdef _DEBUG_SCSIPT
            fprintf(stderr, "named SCSIPT drive type %d found as %c, choosing %d, %d, %d\n", 
                        uDriveType,
                        'A'+id_wanted, 
                        usal_scsibus(usalp), 
                        usal_target(usalp), 
                        usal_lun(usalp));
            #endif
      }

      if (retVal > 0)
            UsingSPTI = TRUE;

      return (retVal);
}


static int
DeinitSCSIPT(void)
{
      BYTE  i;

      if (!bSCSIPTInit)
            return (0);

      for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++) {
            if (sptiglobal.drive[i].bUsed) {
                  CloseHandle(sptiglobal.drive[i].hDevice);
            }
      }

      sptiglobal.numAdapters = SPTIGetNumAdapters();

      memset(&sptiglobal, 0, sizeof (SPTIGLOBAL));
      bSCSIPTInit = FALSE;
      return (-1);
}


/*
 * Returns the number of "adapters" present.
 */
static BYTE
SPTIGetNumAdapters(void)
{
      BYTE  buf[256];
      WORD  i;
      BYTE  numAdapters = 0;

      memset(buf, 0, 256);

      /*
       * PortNumber 0 should exist, so pre-mark it.  This avoids problems
       * when the primary IDE drives are on PortNumber 0, but can't be opened
       * because of insufficient privelege (ie. non-admin).
       */
      buf[0] = 1;
      for (i = 0; i < NUM_MAX_NTSCSI_DRIVES; i++) {
            if (sptiglobal.drive[i].bUsed)
                  buf[sptiglobal.drive[i].ha] = 1;
      }

      for (i = 0; i <= 255; i++)
            if (buf[i])
                  numAdapters = (BYTE)(i + 1);

/*    numAdapters++; */

      return (numAdapters);
}

#include <ctype.h>
static BOOL
w2k_or_newer(void)
{
      OSVERSIONINFO osver;

      memset(&osver, 0, sizeof (osver));
      osver.dwOSVersionInfoSize = sizeof (osver);
      GetVersionEx(&osver);
      if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
            /*
             * Win2000 is NT-5.0, Win-XP is NT-5.1
             */
            if (osver.dwMajorVersion > 4)
                  return (TRUE);
      }
      return (FALSE);
}

static BOOL
w2kstyle_create(void)
{
      OSVERSIONINFO osver;

/*    return FALSE; */
      memset(&osver, 0, sizeof (osver));
      osver.dwOSVersionInfoSize = sizeof (osver);
      GetVersionEx(&osver);
      if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) {
            /*
             * Win2000 is NT-5.0, Win-XP is NT-5.1
             */
            if (osver.dwMajorVersion > 4)
                  return (TRUE);

            if (osver.dwMajorVersion == 4) {          /* NT-4.x */
                  char  *vers = osver.szCSDVersion;

                  if (strlen(vers) == 0)
                        return (FALSE);

                  /*
                   * Servicepack is installed, skip over non-digit part
                   */
                  while (*vers != '\0' && !isdigit(*vers))
                        vers++;
                  if (*vers == '\0')
                        return (FALSE);

                  if (isdigit(vers[0]) &&
                      (atoi(vers) >= 4 || isdigit(vers[1])))      /* Fom Service Pack 4 */
                        return (TRUE);                      /* same as for W2K */
            }
      }
      return (FALSE);
}


/*
 * Universal function to get a file handle to the CD device.  Since
 * NT 4.0 wants just the GENERIC_READ flag, and Win2K wants both
 * GENERIC_READ and GENERIC_WRITE (why a read-only CD device needs
 * GENERIC_WRITE access is beyond me...), the easist workaround is to just
 * try them both.
 */
static HANDLE
GetFileHandle(BYTE i, BOOL openshared)
{
      char  buf[12];
      HANDLE      fh;
      DWORD dwFlags = GENERIC_READ;
      DWORD dwAccessMode = 0;

      dwAccessMode = FILE_SHARE_READ;
      if (w2kstyle_create()) { /* if Win2K or greater, add GENERIC_WRITE */
            dwFlags |= GENERIC_WRITE;
            dwAccessMode |= FILE_SHARE_WRITE;
#ifdef _DEBUG_SCSIPT
            fprintf(usalp_errfile, "SPTI: GetFileHandle(): Setting for Win2K\n");
#endif
      }
      snprintf(buf, sizeof (buf), "\\\\.\\%c:", (char)('A'+i));
#ifdef CREATE_NONSHARED
      if (openshared) {
            fh = CreateFile(buf, dwFlags, dwAccessMode, NULL,
                                    OPEN_EXISTING, 0, NULL);
      } else {
            fh = CreateFile(buf, dwFlags, 0, NULL,
                                    OPEN_EXISTING, 0, NULL);
      }
      if (!openshared && fh == INVALID_HANDLE_VALUE && GetLastError() == ERROR_SHARING_VIOLATION)
#endif
            fh = CreateFile(buf, dwFlags, dwAccessMode, NULL,
                                    OPEN_EXISTING, 0, NULL);
      if (fh == INVALID_HANDLE_VALUE) {
            /*
             * it went foobar somewhere, so try it with the GENERIC_WRITE
             * bit flipped
             */
            dwFlags ^= GENERIC_WRITE;
            dwAccessMode ^= FILE_SHARE_WRITE;
#ifdef CREATE_NONSHARED
            if (openshared) {
                  fh = CreateFile(buf, dwFlags, dwAccessMode, NULL,
                                    OPEN_EXISTING, 0, NULL);
            } else {
                  fh = CreateFile(buf, dwFlags, 0, NULL,
                                    OPEN_EXISTING, 0, NULL);
            }
            if (!openshared && fh == INVALID_HANDLE_VALUE && GetLastError() == ERROR_SHARING_VIOLATION)
#endif
                  fh = CreateFile(buf, dwFlags, dwAccessMode, NULL,
                                    OPEN_EXISTING, 0, NULL);
      }
#ifdef _DEBUG_SCSIPT
      if (fh == INVALID_HANDLE_VALUE)
            fprintf(usalp_errfile, "SPTI: CreateFile() failed! -> %d\n", GetLastError());
      else
            fprintf(usalp_errfile, "SPTI: CreateFile() returned %d\n", GetLastError());
#endif

      return (fh);
}


/*
 * fills in a pDrive structure with information from a SCSI_INQUIRY
 * and obtains the ha:tgt:lun values via IOCTL_SCSI_GET_ADDRESS
 */
static void GetDriveInformation(BYTE i, DRIVE *pDrive)
{
      HANDLE            fh;
      BOOL        status;
      SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
      SCSI_ADDRESS      scsiAddr;
      ULONG       length;
      ULONG       returned;
      BYTE        inqData[NTSCSI_HA_INQUIRY_SIZE];

#ifdef _DEBUG_SCSIPT
      fprintf(usalp_errfile, "SPTI: Checking drive %c:", 'A'+i);
#endif

      fh = GetFileHandle(i, TRUE);  /* No NONSHARED Create for inquiry */

      if (fh == INVALID_HANDLE_VALUE) {
#ifdef _DEBUG_SCSIPT
            fprintf(usalp_errfile, "       : fh == INVALID_HANDLE_VALUE\n");
#endif
            return;
      }

#ifdef _DEBUG_SCSIPT
      fprintf(usalp_errfile, "       : Index %d: fh == %08X\n", i, fh);
#endif


      /*
       * Get the drive inquiry data
       */
      memset(&swb, 0, sizeof (swb));
      memset(inqData, 0, sizeof (inqData));
      swb.spt.Length          = sizeof (SCSI_PASS_THROUGH_DIRECT);
      swb.spt.CdbLength = 6;
      swb.spt.SenseInfoLength = 24;
      swb.spt.DataIn          = SCSI_IOCTL_DATA_IN;
      swb.spt.DataTransferLength = 100;
      swb.spt.TimeOutValue    = 2;
      swb.spt.DataBuffer      = inqData;
      swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
      swb.spt.Cdb[0]          = SCSI_CMD_INQUIRY;
      swb.spt.Cdb[4]          = NTSCSI_HA_INQUIRY_SIZE;

      length = sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
      status = DeviceIoControl(fh,
                      IOCTL_SCSI_PASS_THROUGH_DIRECT,
                      &swb,
                      sizeof (swb),
                      &swb,
                      sizeof (swb),
                      &returned,
                      NULL);

      if (!status) {
            CloseHandle(fh);
#ifdef _DEBUG_SCSIPT
            fprintf(usalp_errfile, "SPTI: Error DeviceIoControl() -> %d\n", GetLastError());
#endif
            return;
      }

      memcpy(pDrive->inqData, inqData, NTSCSI_HA_INQUIRY_SIZE);

      /*
       * get the address (path/tgt/lun) of the drive via IOCTL_SCSI_GET_ADDRESS
       */
      memset(&scsiAddr, 0, sizeof (SCSI_ADDRESS));
      scsiAddr.Length = sizeof (SCSI_ADDRESS);
      if (DeviceIoControl(fh, IOCTL_SCSI_GET_ADDRESS, NULL, 0,
                  &scsiAddr, sizeof (SCSI_ADDRESS), &returned,
                  NULL)) {
#ifdef _DEBUG_SCSIPT
            fprintf(usalp_errfile, "Device %c: Port=%d, PathId=%d, TargetId=%d, Lun=%d\n",
                  (char)i+'A', scsiAddr.PortNumber, scsiAddr.PathId,
                  scsiAddr.TargetId, scsiAddr.Lun);
#endif
            pDrive->bUsed           = TRUE;
            pDrive->ha        = scsiAddr.PortNumber; /* preliminary */
            pDrive->PortNumber      = scsiAddr.PortNumber;
            pDrive->PathId          = scsiAddr.PathId;
            pDrive->tgt       = scsiAddr.TargetId;
            pDrive->lun       = scsiAddr.Lun;
            pDrive->driveLetter     = i;
            pDrive->hDevice         = INVALID_HANDLE_VALUE;

      } else if (GetLastError() == 50) { /* support USB/FIREWIRE devices where this call is not supported assign drive letter as device ID */
            pDrive->bUsed = TRUE;
            pDrive->ha = i;
            pDrive->PortNumber = i+64; /* hopefully no conflict with other PortNumber */
            pDrive->PathId    = 0;
            pDrive->tgt = 0;
            pDrive->lun = 0;
            pDrive->driveLetter = i;
            pDrive->hDevice = INVALID_HANDLE_VALUE;
#ifdef _DEBUG_SCSIPT
            fprintf(usalp_errfile, "USB/Firewire Device %c: Port=%d, TargetId=%d, Lun=%d\n", (char)i+'A', i, 0, 0);
#endif
      } else {
            pDrive->bUsed     = FALSE;
#ifdef _DEBUG_SCSIPT
            fprintf(usalp_errfile, "SPTI: Device %s: Error DeviceIoControl(): %d\n", (char)i+'A', GetLastError());
#endif
            CloseHandle(fh);
            return;
      }
#ifdef _DEBUG_SCSIPT
      fprintf(usalp_errfile,  "SPTI: Adding drive %c: (%d:%d:%d)\n", 'A'+i,
                              pDrive->ha, pDrive->tgt, pDrive->lun);
#endif
      CloseHandle(fh);
}



static DWORD
SPTIHandleHaInquiry(LPSRB_HAInquiry lpsrb)
{
      DWORD *pMTL;

      lpsrb->HA_Count    = sptiglobal.numAdapters;
      if (lpsrb->SRB_HaId >= sptiglobal.numAdapters) {
            lpsrb->SRB_Status = SS_INVALID_HA;
            return (SS_INVALID_HA);
      }
      lpsrb->HA_SCSI_ID  = 7;             /* who cares... we're not really an ASPI manager */
      memcpy(lpsrb->HA_ManagerId,  "AKASPI v0.000001", 16);
      memcpy(lpsrb->HA_Identifier, "SCSI Adapter    ", 16);
      lpsrb->HA_Identifier[13] = (char)('0'+lpsrb->SRB_HaId);
      memset(lpsrb->HA_Unique, 0, 16);
      lpsrb->HA_Unique[3] = 8;
      pMTL = (LPDWORD)&lpsrb->HA_Unique[4];
      *pMTL = 64 * 1024;

      lpsrb->SRB_Status = SS_COMP;
      return (SS_COMP);
}

/*
 * Looks up the index in the drive array for a given ha:tgt:lun triple
 */
static BYTE
SPTIGetDeviceIndex(BYTE ha, BYTE tgt, BYTE lun)
{
      BYTE  i;

#ifdef _DEBUG_SCSIPT
      fprintf(usalp_errfile,  "SPTI: SPTIGetDeviceIndex, %d, %d, %d\n", ha,
                  tgt, lun);
#endif

      for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++) {
            if (sptiglobal.drive[i].bUsed) {
                  DRIVE *lpd;

                  lpd = &sptiglobal.drive[i];
                  if ((lpd->ha == ha) && (lpd->tgt == tgt) && (lpd->lun == lun))
                        return (i);
            }
      }

      return (0);
}

/*
 * Converts ASPI-style SRB to SCSI Pass Through IOCTL
 */

static DWORD
SPTIExecSCSICommand(LPSRB_ExecSCSICmd lpsrb, int sptTimeOutValue, BOOL bBeenHereBefore)
{
      BOOL  status;
      SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
      ULONG length;
      ULONG returned;
      BYTE  idx;
      BYTE  j;

      idx = SPTIGetDeviceIndex(lpsrb->SRB_HaId, lpsrb->SRB_Target, lpsrb->SRB_Lun);

      if (idx == 0) {
            lpsrb->SRB_Status = SS_NO_DEVICE;
            return (SS_NO_DEVICE);
      }

      if (lpsrb->CDBByte[0] == SCSI_CMD_INQUIRY) {
            lpsrb->SRB_Status = SS_COMP;
            memcpy(lpsrb->SRB_BufPointer, sptiglobal.drive[idx].inqData, NTSCSI_HA_INQUIRY_SIZE);
            return (SS_COMP);
      }

      if (sptiglobal.drive[idx].hDevice == INVALID_HANDLE_VALUE)
            sptiglobal.drive[idx].hDevice = GetFileHandle(sptiglobal.drive[idx].driveLetter, FALSE);

      memset(&swb, 0, sizeof (swb));
      swb.spt.Length          = sizeof (SCSI_PASS_THROUGH);
      swb.spt.CdbLength = lpsrb->SRB_CDBLen;
      if (lpsrb->SRB_Flags & SRB_DIR_IN)
            swb.spt.DataIn    = SCSI_IOCTL_DATA_IN;
      else if (lpsrb->SRB_Flags & SRB_DIR_OUT)
            swb.spt.DataIn    = SCSI_IOCTL_DATA_OUT;
      else
            swb.spt.DataIn    = SCSI_IOCTL_DATA_UNSPECIFIED;
      swb.spt.DataTransferLength = lpsrb->SRB_BufLen;
      swb.spt.TimeOutValue    = sptTimeOutValue;
      swb.spt.SenseInfoLength = lpsrb->SRB_SenseLen;
      swb.spt.DataBuffer      = lpsrb->SRB_BufPointer;
      swb.spt.SenseInfoOffset =  offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
      memcpy(swb.spt.Cdb, lpsrb->CDBByte, lpsrb->SRB_CDBLen);
      length = sizeof (swb);

#ifdef _DEBUG_SCSIPT
      fprintf(usalp_errfile, "SPTI: SPTIExecSCSICmd: calling DeviceIoControl()");
      fprintf(usalp_errfile, "       : cmd == 0x%02X", swb.spt.Cdb[0]);
#endif
      status = DeviceIoControl(sptiglobal.drive[idx].hDevice,
                      IOCTL_SCSI_PASS_THROUGH_DIRECT,
                      &swb,
                      length,
                      &swb,
                      length,
                      &returned,
                      NULL);

      lpsrb->SRB_SenseLen = swb.spt.SenseInfoLength;
      memcpy(lpsrb->SenseArea, swb.ucSenseBuf, lpsrb->SRB_SenseLen);
      if (status && swb.spt.ScsiStatus == 0) {
            lpsrb->SRB_Status = SS_COMP;
#ifdef _DEBUG_SCSIPT
            fprintf(usalp_errfile, "       : SRB_Status == SS_COMP\n");
#endif
      } else {
            DWORD dwErrCode;

            lpsrb->SRB_Status = SS_ERR;
/*          lpsrb->SRB_TargStat =  0x0004;*/
            lpsrb->SRB_TargStat =  swb.spt.ScsiStatus;

            dwErrCode = GetLastError();
#ifdef _DEBUG_SCSIPT
            fprintf(usalp_errfile, "       : error == %d   handle == %08X\n", dwErrCode, sptiglobal.drive[idx].hDevice);
#endif
            /*
             * KLUDGE ALERT! KLUDGE ALERT! KLUDGE ALERT!
             * Whenever a disk changer switches disks, it may render the device
             * handle invalid.  We try to catch these errors here and recover
             * from them.
             */
            if (!bBeenHereBefore &&
                  ((dwErrCode == ERROR_MEDIA_CHANGED) || (dwErrCode == ERROR_INVALID_HANDLE))) {
                  if (dwErrCode != ERROR_INVALID_HANDLE)
                        CloseHandle(sptiglobal.drive[idx].hDevice);
                  GetDriveInformation(idx, &sptiglobal.drive[idx]);
                  if (sptihamax > 0) {
                        if (sptiglobal.drive[idx].bUsed)
                              for (j = 0; j < sptihamax; j++) {
                                    if (sptihasortarr[j] ==
                                        ((sptiglobal.drive[idx].PortNumber << 8) | sptiglobal.drive[idx].PathId)) {
                                          sptiglobal.drive[idx].ha = j;
                                          break;
                                    }
                        }
                  }
#ifdef _DEBUG_SCSIPT
                  fprintf(usalp_errfile, "SPTI: SPTIExecSCSICommand: Retrying after ERROR_MEDIA_CHANGED\n");
#endif
                  return (SPTIExecSCSICommand(lpsrb, sptTimeOutValue, TRUE));
            }
      }
      return (lpsrb->SRB_Status);
}
/* SPTI End -----------------------------------------------------------------*/


static void
exit_func()
{
      if (!close_driver())
            errmsgno(EX_BAD, "Cannot close Win32-ASPI-Driver.\n");
}

/*
 * Return version information for the low level SCSI transport code.
 * This has been introduced to make it easier to trace down problems
 * in applications.
 */
static char *
usalo_version(SCSI *usalp, int what)
{
      if (usalp != (SCSI *)0) {
            switch (what) {

            case SCG_VERSION:
                  if (UsingSPTI)
                        return (_usal_itrans_version);
                  return (_usal_trans_version);
            /*
             * If you changed this source, you are not allowed to
             * return "schily" for the SCG_AUTHOR request.
             */
            case SCG_AUTHOR:
                  return (_usal_auth_cdrkit);
            case SCG_SCCS_ID:
                  return (__sccsid);
            }
      }
      return ((char *)0);
}

static int
usalo_help(SCSI *usalp, FILE *f)
{
      __usal_help(f, "ASPI", "Generic transport independent SCSI",
            "ASPI:", "bus,target,lun", "ASPI:1,2,0", TRUE, FALSE);
      __usal_help(f, "SPTI", "Generic SCSI for Windows NT/2000/XP",
            "SPTI:", "bus,target,lun", "SPTI:1,2,0", TRUE, FALSE);
      return (0);
}

static int
usalo_open(SCSI *usalp, char *device)
{
      int   busno = usal_scsibus(usalp);
      int   tgt   = usal_target(usalp);
      int   tlun  = usal_lun(usalp);

      /*usal_local(usalp)->drive_wanted = NULL;
      for(i=0;i<MAX_SCG*MAX_TGT*MAX_LUN;i++)
            usallocal(usalp)->filenames[i]=NULL;
            */
      usalp->local = calloc(1, sizeof (struct usal_local));
      if (usalp->local == NULL)
            return (0);

      if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN) {
            errno = EINVAL;
            if (usalp->errstr)
                  snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
                        "Illegal value for busno, target or lun '%d,%d,%d'",
                        busno, tgt, tlun);
            return (-1);
      }

      /* Explicite choice of Schilling syntax */
      if (device != NULL && (strcmp(device, "SPTI") == 0 || strcmp(device, "ASPI") == 0))
            goto devok;

      /* use device as drive letter */
      if ((device != NULL && *device != '\0') || (busno == -2 && tgt == -2)) {
/*
            errno = EINVAL;
            if (usalp->errstr)
                  snprintf(usalp->errstr, SCSI_ERRSTR_SIZE,
                        "Open by 'devname' not supported on this OS");
            return (-1);
*/

            UsingSPTI = TRUE;
            usallocal(usalp)->drive_wanted = *device;

            /* not the finest solution but prevents breaking on various
             * places for no good reasons... */
            usal_scsibus(usalp)=0;
            usal_target(usalp)=0;
            usal_lun(usalp)=0;
            goto openbydev;
      }
devok:
      if (DriverLoaded <= 0) {      /* do not change access method on open driver */
            ForceAccess = FALSE;
#ifdef PREFER_SPTI
            UsingSPTI = TRUE;
#else
            UsingSPTI = FALSE;
#endif
            if (!w2k_or_newer())
                  UsingSPTI = FALSE;

            if (usalp->debug > 0) {
                  fprintf((FILE *)usalp->errfile,
                        "usalo_open: Prefered SCSI transport: %s\n",
                              UsingSPTI ? "SPTI":"ASPI");
            }
            if (device != NULL && strcmp(device, "SPTI") == 0) {
                  UsingSPTI = TRUE;
                  ForceAccess = TRUE;
            } else if (device != NULL && strcmp(device, "ASPI") == 0) {
                  UsingSPTI = FALSE;
                  ForceAccess = TRUE;
            }
            if (device != NULL && usalp->debug > 0) {
                  fprintf((FILE *)usalp->errfile,
                        "usalo_open: Selected SCSI transport: %s\n",
                              UsingSPTI ? "SPTI":"ASPI");
            }
      }

      /*
       *  Check if variables are within the range
       */
      if (tgt >= 0 && tgt >= 0 && tlun >= 0) {
            /*
             * This is the non -scanbus case.
             */
            ;
      } else if (tgt == -2 && tgt == -2 &&
                (tgt == -2 || tlun >= 0)) {
            /*
             * This is the dev=ASPI case.
             */
            ;
      } else if (tgt != -1 || tgt != -1 || tlun != -1) {
            errno = EINVAL;
            return (-1);
      }

openbydev:
      /*
       * Try to open ASPI-Router
       */
      if (!open_driver(usalp))
            return (-1);

      /*
       * More than we have ...
       */
      if (busno >= busses) {
            close_driver();
            return (-1);
      }

      /*
       * Install Exit Function which closes the ASPI-Router
       */
      atexit(exit_func);

      /*
       * Success after all
       */
      return (1);
}

static int
usalo_close(SCSI *usalp)
{
      int i;
      /*
      for(i=0;i<MAX_SCG*MAX_TGT*MAX_LUN;i++) {
            if(usallocal(usalp)->filenames[i]) {
                  free(usallocal(usalp)->filenames[i]);
                  usallocal(usalp)->filenames[i]=NULL;
            }
      }
      */
      if(usalp->local) {
             free(usalp->local);
             usalp->local=NULL;
      }
      //printf("closing\n");

      exit_func();
      return (0);
}

static long
usalo_maxdma(SCSI *usalp, long amt)
{
      return (MAX_DMA_WNT);
}

static void *
usalo_getbuf(SCSI *usalp, long amt)
{
      if (usalp->debug > 0) {
            fprintf((FILE *)usalp->errfile,
                        "usalo_getbuf: %ld bytes\n", amt);
      }
      usalp->bufbase = malloc((size_t)(amt));
      return (usalp->bufbase);
}

static void
usalo_freebuf(SCSI *usalp)
{
      if (usalp->bufbase)
            free(usalp->bufbase);
      usalp->bufbase = NULL;
}

static __SBOOL
usalo_havebus(SCSI *usalp, int busno)
{
      if (busno < 0 || busno >= busses)
            return (FALSE);

      return (TRUE);
}

static int
usalo_fileno(SCSI *usalp, int busno, int tgt, int tlun)
{
      if (busno < 0 || busno >= busses ||
          tgt < 0 || tgt >= MAX_TGT ||
          tlun < 0 || tlun >= MAX_LUN)
            return (-1);

      /*
       * Return fake
       */
      return (1);
}


static int
usalo_initiator_id(SCSI *usalp)
{
      SRB_HAInquiry     s;

      if (ha_inquiry(usalp, usal_scsibus(usalp), &s) < 0)
            return (-1);
      return (s.HA_SCSI_ID);
}

static int
usalo_isatapi(SCSI *usalp)
{
      return (-1);      /* XXX Need to add real test */
}


/*
 * XXX usalo_reset not yet tested
 */
static int
usalo_reset(SCSI *usalp, int what)
{

      DWORD             Status = 0;
      DWORD             EventStatus = WAIT_OBJECT_0;
      HANDLE                  Event  = NULL;
      SRB_BusDeviceReset      s;

      if (what == SCG_RESET_NOP) {
            if (UsingSPTI)
                  return (-1);
            else
                  return (0);  /* Can ASPI really reset? */
      }
      if (what != SCG_RESET_BUS) {
            errno = EINVAL;
            return (-1);
      }
      if (UsingSPTI) {
            fprintf((FILE *)usalp->errfile,
                              "Reset SCSI device not implemented with SPTI\n");
            return (-1);
      }

      /*
       * XXX Does this reset TGT or BUS ???
       */
      if (usalp->debug > 0) {
            fprintf((FILE *)usalp->errfile,
                        "Attempting to reset SCSI device\n");
      }

      /*
       * Check if ASPI library is loaded
       */
      if (DriverLoaded <= 0) {
            fprintf((FILE *)usalp->errfile,
                        "error in usalo_reset: ASPI driver not loaded !\n");
            return (-1);
      }

      memset(&s, 0, sizeof (s));    /* Clear SRB_BesDeviceReset structure */

      Event = CreateEvent(NULL, TRUE, FALSE, NULL);

      /*
       * Set structure variables
       */
      s.SRB_Cmd   = SC_RESET_DEV;               /* ASPI command code = SC_RESET_DEV */
      s.SRB_HaId  = usal_scsibus(usalp);        /* ASPI host adapter number         */
      s.SRB_Flags = SRB_EVENT_NOTIFY;           /* Flags                      */
      s.SRB_Target      = usal_target(usalp);         /* Target's SCSI ID                 */
      s.SRB_Lun   = usal_lun(usalp);            /* Target's LUN number              */
      s.SRB_PostProc    = (LPVOID)Event;        /* Post routine                     */

      /*
       * Initiate SCSI command
       */
      Status = pfnSendASPI32Command((LPSRB)&s);

      /*
       * Check status
       */
      if (Status == SS_PENDING) {
            /*
             * Wait till command completes
             */
            EventStatus = WaitForSingleObject(Event, INFINITE);
      }


      /**************************************************/
      /* Reset event to non-signaled state.             */
      /**************************************************/

      if (EventStatus == WAIT_OBJECT_0) {
            /*
             * Clear event
             */
            ResetEvent(Event);
      }

      /*
       * Close the event handle
       */
      CloseHandle(Event);

      /*
       * Check condition
       */
      if (s.SRB_Status != SS_COMP) {
            fprintf((FILE *)usalp->errfile,
                              "ERROR! 0x%08X\n", s.SRB_Status);

            /*
             * Indicate that error has occured
             */
            return (-1);
      }

      if (usalp->debug > 0) {
            fprintf((FILE *)usalp->errfile,
                              "Reset SCSI device completed\n");
      }

      /*
       * Everything went OK
       */
      return (0);
}


#ifdef DEBUG_WNTASPI
static void
DebugScsiSend(SCSI *usalp, SRB_ExecSCSICmd *s, int bDisplayBuffer)
{
      int i;

      fprintf((FILE *)usalp->errfile, "\n\nDebugScsiSend\n");
      fprintf((FILE *)usalp->errfile, "s->SRB_Cmd          = 0x%02x\n", s->SRB_Cmd);
      fprintf((FILE *)usalp->errfile, "s->SRB_HaId         = 0x%02x\n", s->SRB_HaId);
      fprintf((FILE *)usalp->errfile, "s->SRB_Flags        = 0x%02x\n", s->SRB_Flags);
      fprintf((FILE *)usalp->errfile, "s->SRB_Target       = 0x%02x\n", s->SRB_Target);
      fprintf((FILE *)usalp->errfile, "s->SRB_Lun          = 0x%02x\n", s->SRB_Lun);
      fprintf((FILE *)usalp->errfile, "s->SRB_BufLen       = 0x%02x\n", s->SRB_BufLen);
      fprintf((FILE *)usalp->errfile, "s->SRB_BufPointer   = %x\n",        s->SRB_BufPointer);
      fprintf((FILE *)usalp->errfile, "s->SRB_CDBLen       = 0x%02x\n", s->SRB_CDBLen);
      fprintf((FILE *)usalp->errfile, "s->SRB_SenseLen     = 0x%02x\n", s->SRB_SenseLen);
      fprintf((FILE *)usalp->errfile, "s->CDBByte          =");
      for (i = 0; i < min(s->SRB_CDBLen, 16); i++) {
            fprintf((FILE *)usalp->errfile, " %02X ", s->CDBByte[i]);
      }
      fprintf((FILE *)usalp->errfile, "\n");

      /*
      if (bDisplayBuffer != 0 && s->SRB_BufLen >= 8) {

            fprintf((FILE *)usalp->errfile, "s->SRB_BufPointer   =");
            for (i = 0; i < 8; i++) {
                  fprintf((FILE *)usalp->errfile,
                              " %02X ", ((char *)s->SRB_BufPointer)[i]);
            }
            fprintf((FILE *)usalp->errfile, "\n");
      }
*/
      fprintf((FILE *)usalp->errfile, "Debug done\n");
}
#endif

static void
copy_sensedata(SRB_ExecSCSICmd *cp, struct usal_cmd *sp)
{
      sp->sense_count   = cp->SRB_SenseLen;
      if (sp->sense_count > sp->sense_len)
            sp->sense_count = sp->sense_len;

      memset(&sp->u_sense.Sense, 0x00, sizeof (sp->u_sense.Sense));
      memcpy(&sp->u_sense.Sense, cp->SenseArea, sp->sense_count);

      sp->u_scb.cmd_scb[0] = cp->SRB_TargStat;
}

/*
 * Set error flags
 */
static void
set_error(SRB_ExecSCSICmd *cp, struct usal_cmd *sp)
{
      switch (cp->SRB_Status) {

      case SS_COMP:                 /* 0x01 SRB completed without error  */
            sp->error = SCG_NO_ERROR;
            sp->ux_errno = 0;
            break;

      case SS_ERR:                  /* 0x04 SRB completed with error    */
            /*
             * If the SCSI Status byte is != 0, we definitely could send
             * the command to the target. We signal NO transport error.
             */
            sp->error = SCG_NO_ERROR;
            sp->ux_errno = EIO;
            if (cp->SRB_TargStat)
                  break;

      case SS_PENDING:        /* 0x00 SRB being processed       */
            /*
             * XXX Could SS_PENDING happen ???
             */
      case SS_ABORTED:        /* 0x02 SRB aborted               */
      case SS_ABORT_FAIL:           /* 0x03 Unable to abort SRB       */
      default:
            sp->error = SCG_RETRYABLE;
            sp->ux_errno = EIO;
            break;

      case SS_INVALID_CMD:          /* 0x80 Invalid ASPI command      */
      case SS_INVALID_HA:           /* 0x81 Invalid host adapter number */
      case SS_NO_DEVICE:            /* 0x82 SCSI device not installed   */

      case SS_INVALID_SRB:          /* 0xE0 Invalid parameter set in SRB */
      case SS_ILLEGAL_MODE:         /* 0xE2 Unsupported Windows mode    */
      case SS_NO_ASPI:        /* 0xE3 No ASPI managers          */
      case SS_FAILED_INIT:          /* 0xE4 ASPI for windows failed init */
      case SS_MISMATCHED_COMPONENTS:      /* 0xE7 The DLLs/EXEs of ASPI don't */
                              /*    version check               */
      case SS_NO_ADAPTERS:          /* 0xE8 No host adapters to manager */

      case SS_ASPI_IS_SHUTDOWN:     /* 0xEA Call came to ASPI after         */
                              /*    PROCESS_DETACH              */
      case SS_BAD_INSTALL:          /* 0xEB The DLL or other components */
                              /*    are installed wrong         */
            sp->error = SCG_FATAL;
            sp->ux_errno = EINVAL;
            break;

#ifdef      XXX
      case SS_OLD_MANAGER:          /* 0xE1 ASPI manager doesn't support */
                              /*    windows                     */
#endif
      case SS_BUFFER_ALIGN:         /* 0xE1 Buffer not aligned (replaces */
                              /*    SS_OLD_MANAGER in Win32)    */
            sp->error = SCG_FATAL;
            sp->ux_errno = EFAULT;
            break;

      case SS_ASPI_IS_BUSY:         /* 0xE5 No resources available to   */
                              /*    execute command             */
            sp->error = SCG_RETRYABLE;
            sp->ux_errno = EBUSY;
            break;

#ifdef      XXX
      case SS_BUFFER_TO_BIG:        /* 0xE6 Buffer size too big to handle*/
#endif
      case SS_BUFFER_TOO_BIG:       /* 0xE6 Correct spelling of 'too'   */
      case SS_INSUFFICIENT_RESOURCES:     /* 0xE9 Couldn't allocate resources */
                              /*    needed to init              */
            sp->error = SCG_RETRYABLE;
            sp->ux_errno = ENOMEM;
            break;
      }
}


struct aspi_cmd {
      SRB_ExecSCSICmd         s;
      char              pad[32];
};

static int
usalo_send(SCSI *usalp)
{
      struct usal_cmd         *sp = usalp->scmd;
      DWORD             Status = 0;
      DWORD             EventStatus = WAIT_OBJECT_0;
      HANDLE                  Event  = NULL;
      struct aspi_cmd         ac;
      SRB_ExecSCSICmd         *s;

      s = &ac.s;

      /*
       * Check if ASPI library is loaded
       */
      if (DriverLoaded <= 0) {
            errmsgno(EX_BAD, "error in usalo_send: ASPI driver not loaded.\n");
            sp->error = SCG_FATAL;
            return (0);
      }

      if (usalp->fd < 0) {
            sp->error = SCG_FATAL;
            return (-1);
      }

      /*
       * Initialize variables
       */
      sp->error         = SCG_NO_ERROR;
      sp->sense_count         = 0;
      sp->u_scb.cmd_scb[0]    = 0;
      sp->resid         = 0;

      memset(&ac, 0, sizeof (ac));  /* Clear SRB structure */

      /*
       * Check cbd_len > the maximum command pakket that can be handled by ASPI
       */
      if (sp->cdb_len > 16) {
            sp->error = SCG_FATAL;
            sp->ux_errno = EINVAL;
            fprintf((FILE *)usalp->errfile,
                  "sp->cdb_len > sizeof (SRB_ExecSCSICmd.CDBByte). Fatal error in usalo_send, exiting...\n");
            return (-1);
      }
      /*
       * copy cdrecord command into SRB
       */
      movebytes(&sp->cdb, &(s->CDBByte), sp->cdb_len);

      Event = CreateEvent(NULL, TRUE, FALSE, NULL);

      /*
       * Fill ASPI structure
       */
      s->SRB_Cmd   = SC_EXEC_SCSI_CMD;          /* SCSI Command               */
      s->SRB_HaId  = usal_scsibus(usalp);       /* Host adapter number        */
      s->SRB_Flags       = SRB_EVENT_NOTIFY;          /* Flags                */
      s->SRB_Target      = usal_target(usalp);        /* Target SCSI ID       */
      s->SRB_Lun   = usal_lun(usalp);           /* Target SCSI LUN            */
      s->SRB_BufLen      = sp->size;                  /* # of bytes transferred     */
      s->SRB_BufPointer = sp->addr;             /* pointer to data buffer     */
      s->SRB_CDBLen      = sp->cdb_len;               /* SCSI command length        */
      s->SRB_PostProc    = Event;               /* Post proc event            */
      if (UsingSPTI)
            s->SRB_SenseLen   = SENSE_LEN_SPTI; /* Length of sense buffer, SPTI returns SenseInfoLength */
      else
            s->SRB_SenseLen   = SENSE_LEN;            /* fixed length 14 for ASPI */
      /*
       * Do we receive data from this ASPI command?
       */
      if (sp->flags & SCG_RECV_DATA) {

            s->SRB_Flags |= SRB_DIR_IN;
      } else {
            /*
             * Set direction to output
             */
            if (sp->size > 0) {
                  s->SRB_Flags |= SRB_DIR_OUT;
            }
      }

#ifdef DEBUG_WNTASPI
      /*
       * Dump some debug information when enabled
       */
      DebugScsiSend(usalp, s, TRUE);
/*    DebugScsiSend(usalp, s, (s->SRB_Flags&SRB_DIR_OUT) == SRB_DIR_OUT);*/
#endif

      /*
       * ------------ Send SCSI command --------------------------
       */

      ResetEvent(Event);                  /* Clear event handle       */
      if (UsingSPTI) {
#ifdef _DEBUG_SCSIPT
            usalp_errfile = (FILE *)usalp->errfile;
#endif
            Status = SPTIExecSCSICommand(s, sp->timeout, FALSE);
      }
      else
            Status = pfnSendASPI32Command((LPSRB)s); /* Initiate SCSI command */
      if (Status == SS_PENDING) {         /* If in progress     */
            /*
             * Wait untill command completes, or times out.
             */
            EventStatus = WaitForSingleObject(Event, sp->timeout*1000L);
/*          EventStatus = WaitForSingleObject(Event, 10L);*/

            if (EventStatus == WAIT_OBJECT_0)
                  ResetEvent(Event);      /* Clear event, time out    */

            if (s->SRB_Status == SS_PENDING) { /* Check if we got a timeout */
                  if (usalp->debug > 0) {
                        fprintf((FILE *)usalp->errfile,
                                    "Timeout....\n");
                  }
                  scsiabort(usalp, s);
                  ResetEvent(Event);      /* Clear event, time out    */
                  CloseHandle(Event);     /* Close the event handle   */

                  sp->error = SCG_TIMEOUT;
                  return (1);       /* Return error             */
            }
      }
      CloseHandle(Event);                 /* Close the event handle   */

      /*
       * Check ASPI command status
       */
      if (s->SRB_Status != SS_COMP) {
            if (usalp->debug > 0) {
                  fprintf((FILE *)usalp->errfile,
                        "Error in usalo_send: s->SRB_Status is 0x%x\n", s->SRB_Status);
            }

            set_error(s, sp);       /* Set error flags          */
            copy_sensedata(s, sp);        /* Copy sense and status    */

            if (usalp->debug > 0) {
                  fprintf((FILE *)usalp->errfile,
                        "Mapped to: error %d errno: %d\n", sp->error, sp->ux_errno);
            }
            return (1);
      }

      /*
       * Return success
       */
      return (0);
}

/***************************************************************************
 *                                                       *
 *  BOOL open_driver()                                         *
 *                                                       *
 *  Opens the ASPI Router device driver and sets device_handle.            *
 *  Returns:                                                   *
 *    TRUE - Success                                           *
 *    FALSE - Unsuccessful opening of device driver                  *
 *                                                       *
 *  Preconditions: ASPI Router driver has be loaded                  *
 *                                                       *
 ***************************************************************************/
static BOOL
open_driver(SCSI *usalp)
{
      DWORD astatus;
      BYTE  HACount;
      BYTE  ASPIStatus;
      int   i;

#ifdef DEBUG_WNTASPI
      fprintf((FILE *)usalp->errfile, "enter open_driver\n");
#endif

      /*
       * Check if ASPI library is already loaded yet
       */
      if (DriverLoaded > 0) {
            DriverLoaded++;
            return (TRUE);
      }

      /*
       * Load the ASPI library or SPTI
       */
#ifdef _DEBUG_SCSIPT
      usalp_errfile = (FILE *)usalp->errfile;
#endif
#ifdef      PREFER_SPTI
      if (UsingSPTI)
            if (InitSCSIPT(usalp) > 0) DriverLoaded++;
#endif
#ifdef      PREFER_SPTI
      if ((!UsingSPTI || !ForceAccess) && DriverLoaded <= 0) {
#else
      if (!UsingSPTI || !ForceAccess) {
#endif
            if (load_aspi(usalp)) {
                  DriverLoaded++;
                  UsingSPTI = FALSE;
            }
      }

#ifndef     PREFER_SPTI
      if ((UsingSPTI || !ForceAccess) && DriverLoaded <= 0)
            if (InitSCSIPT(usalp) > 0)
                  DriverLoaded++;
#endif      /*PREFER_SPTI*/

      if (DriverLoaded <= 0) {
            if (UsingSPTI) {
                  if (errno == 0)
                        errno = ENOSYS;
            }
            fprintf((FILE *)usalp->errfile, "Can not load %s driver! ",
                                    UsingSPTI ? "SPTI":"ASPI");
            return (FALSE);
      }

      if (UsingSPTI) {
            if (usalp->debug > 0)
                  fprintf((FILE *)usalp->errfile, "using SPTI Transport\n");

            if (!sptiglobal.numAdapters)
                  astatus = (DWORD)(MAKEWORD(0, SS_NO_ADAPTERS));
            else
                  astatus = (DWORD)(MAKEWORD(sptiglobal.numAdapters, SS_COMP));
      } else {
            astatus = pfnGetASPI32SupportInfo();
      }

      ASPIStatus = HIBYTE(LOWORD(astatus));
      HACount    = LOBYTE(LOWORD(astatus));

      if (usalp->debug > 0) {
            fprintf((FILE *)usalp->errfile,
                  "open_driver %lX HostASPIStatus=0x%x HACount=0x%x\n", astatus, ASPIStatus, HACount);
      }

      if (ASPIStatus != SS_COMP && ASPIStatus != SS_NO_ADAPTERS) {
            fprintf((FILE *)usalp->errfile, "Could not find any host adapters\n");
            fprintf((FILE *)usalp->errfile, "ASPIStatus == 0x%02X", ASPIStatus);
            return (FALSE);
      }
      busses = HACount;

#ifdef DEBUG_WNTASPI
      fprintf((FILE *)usalp->errfile, "open_driver HostASPIStatus=0x%x HACount=0x%x\n", ASPIStatus, HACount);
      fprintf((FILE *)usalp->errfile, "leaving open_driver\n");
#endif

      for (i = 0; i < busses; i++) {
            SRB_HAInquiry     s;

            ha_inquiry(usalp, i, &s);
      }

      /*
       * Indicate that library loaded/initialized properly
       */
      return (TRUE);
}

static BOOL
load_aspi(SCSI *usalp)
{
#ifdef      __CYGWIN32__
      hAspiLib = dlopen("WNASPI32", RTLD_NOW);
#else
      hAspiLib = LoadLibrary("WNASPI32");
#endif
      /*
       * Check if ASPI library is loaded correctly
       */
      if (hAspiLib == NULL) {
#ifdef      not_done_later
            fprintf((FILE *)usalp->errfile, "Can not load ASPI driver! ");
#endif
            return (FALSE);
      }

      /*
       * Get a pointer to GetASPI32SupportInfo function
       * and a pointer to SendASPI32Command function
       */
#ifdef      __CYGWIN32__
      pfnGetASPI32SupportInfo = (DWORD(*)(void))dlsym(hAspiLib, "GetASPI32SupportInfo");
      pfnSendASPI32Command = (DWORD(*)(LPSRB))dlsym(hAspiLib, "SendASPI32Command");
#else
      pfnGetASPI32SupportInfo = (DWORD(*)(void))GetProcAddress(hAspiLib, "GetASPI32SupportInfo");
      pfnSendASPI32Command = (DWORD(*)(LPSRB))GetProcAddress(hAspiLib, "SendASPI32Command");
#endif

      if ((pfnGetASPI32SupportInfo == NULL) || (pfnSendASPI32Command == NULL)) {
            fprintf((FILE *)usalp->errfile,
                        "ASPI function not found in library! ");
            return (FALSE);
      }

      /*
       * The following functions are currently not used by libusal.
       * If we start to use them, we need to check whether the founctions
       * could be found in the ASPI library that just has been loaded.
       */
#ifdef      __CYGWIN32__
      pfnGetASPI32Buffer = (BOOL(*)(PASPI32BUFF))dlsym(hAspiLib, "GetASPI32Buffer");
      pfnFreeASPI32Buffer = (BOOL(*)(PASPI32BUFF))dlsym(hAspiLib, "FreeASPI32Buffer");
      pfnTranslateASPI32Address = (BOOL(*)(PDWORD, PDWORD))dlsym(hAspiLib, "TranslateASPI32Address");
#else
      pfnGetASPI32Buffer = (BOOL(*)(PASPI32BUFF))GetProcAddress(hAspiLib, "GetASPI32Buffer");
      pfnFreeASPI32Buffer = (BOOL(*)(PASPI32BUFF))GetProcAddress(hAspiLib, "FreeASPI32Buffer");
      pfnTranslateASPI32Address = (BOOL(*)(PDWORD, PDWORD))GetProcAddress(hAspiLib, "TranslateASPI32Address");
#endif
      return (TRUE);
}

/***************************************************************************
 *                                                       *
 *  BOOL close_driver()                                        *
 *                                                       *
 *  Closes the device driver                                   *
 *  Returns:                                                   *
 *    TRUE - Success                                           *
 *    FALSE - Unsuccessful closing of device driver                  *
 *                                                       *
 *  Preconditions: ASPI Router driver has be opened with open_driver       *
 *                                                       *
 ***************************************************************************/
static BOOL
close_driver()
{
      if (--DriverLoaded > 0)
            return (TRUE);
      /*
       * If library is loaded
       */
      DeinitSCSIPT();
      /*
       * Clear all variables
       */
      if (hAspiLib) {
            pfnGetASPI32SupportInfo = NULL;
            pfnSendASPI32Command    = NULL;
            pfnGetASPI32Buffer      = NULL;
            pfnFreeASPI32Buffer     = NULL;
            pfnTranslateASPI32Address = NULL;

            /*
             * Free ASPI library, we do not need it any longer
             */
#ifdef      __CYGWIN32__
            dlclose(hAspiLib);
#else
            FreeLibrary(hAspiLib);
#endif
            hAspiLib = NULL;
      }

      /*
       * Indicate that shutdown has been finished properly
       */
      return (TRUE);
}

static int
ha_inquiry(SCSI *usalp, int id, SRB_HAInquiry *ip)
{
      DWORD       Status;

      ip->SRB_Cmd  = SC_HA_INQUIRY;
      ip->SRB_HaId       = id;
      ip->SRB_Flags      = 0;
      ip->SRB_Hdr_Rsvd = 0;

      if (UsingSPTI)
            Status = SPTIHandleHaInquiry(ip);
      else
            Status = pfnSendASPI32Command((LPSRB)ip);

      if (usalp->debug > 0) {
            fprintf((FILE *)usalp->errfile, "Status : %ld\n",     Status);
            fprintf((FILE *)usalp->errfile, "hacount: %d\n", ip->HA_Count);
            fprintf((FILE *)usalp->errfile, "SCSI id: %d\n", ip->HA_SCSI_ID);
            fprintf((FILE *)usalp->errfile, "Manager: '%.16s'\n", ip->HA_ManagerId);
            fprintf((FILE *)usalp->errfile, "Identif: '%.16s'\n", ip->HA_Identifier);
            usal_prbytes("Unique:", ip->HA_Unique, 16);
      }
      if (ip->SRB_Status != SS_COMP)
            return (-1);
      return (0);
}

#ifdef      __USED__
static int
resetSCSIBus(SCSI *usalp)
{
      DWORD             Status;
      HANDLE                  Event;
      SRB_BusDeviceReset      s;

      if (UsingSPTI) {
            fprintf((FILE *)usalp->errfile,
                              "Reset SCSI bus not implemented with SPTI\n");
            return (FALSE);
      }

      fprintf((FILE *)usalp->errfile, "Attempting to reset SCSI bus\n");

      Event = CreateEvent(NULL, TRUE, FALSE, NULL);

      memset(&s, 0, sizeof (s));    /* Clear SRB_BesDeviceReset structure */

      /*
       * Set structure variables
       */
      s.SRB_Cmd = SC_RESET_DEV;
      s.SRB_PostProc = (LPVOID)Event;

      /*
       * Clear event
       */
      ResetEvent(Event);

      /*
       * Initiate SCSI command
       */
      Status = pfnSendASPI32Command((LPSRB)&s);

      /*
       * Check status
       */
      if (Status == SS_PENDING) {
            /*
             * Wait till command completes
             */
            WaitForSingleObject(Event, INFINITE);
      }

      /*
       * Close the event handle
       */
      CloseHandle(Event);

      /*
       * Check condition
       */
      if (s.SRB_Status != SS_COMP) {
            fprintf((FILE *)usalp->errfile, "ERROR  0x%08X\n", s.SRB_Status);

            /*
             * Indicate that error has occured
             */
            return (FALSE);
      }

      /*
       * Everything went OK
       */
      return (TRUE);
}
#endif      /* __USED__ */

static int
scsiabort(SCSI *usalp, SRB_ExecSCSICmd *sp)
{
      DWORD             Status = 0;
      SRB_Abort         s;

      if (UsingSPTI) {
            fprintf((FILE *)usalp->errfile,
                              "Abort SCSI not implemented with SPTI\n");
            return (FALSE);
      }

      if (usalp->debug > 0) {
            fprintf((FILE *)usalp->errfile,
                        "Attempting to abort SCSI command\n");
      }

      /*
       * Check if ASPI library is loaded
       */
      if (DriverLoaded <= 0) {
            fprintf((FILE *)usalp->errfile,
                        "error in scsiabort: ASPI driver not loaded !\n");
            return (FALSE);
      }

      /*
       * Set structure variables
       */
      s.SRB_Cmd   = SC_ABORT_SRB;               /* ASPI command code = SC_ABORT_SRB */
      s.SRB_HaId  = usal_scsibus(usalp);        /* ASPI host adapter number         */
      s.SRB_Flags = 0;                    /* Flags                      */
      s.SRB_ToAbort     = (LPSRB)&sp;                 /* sp                         */

      /*
       * Initiate SCSI abort
       */
      Status = pfnSendASPI32Command((LPSRB)&s);

      /*
       * Check condition
       */
      if (s.SRB_Status != SS_COMP) {
            fprintf((FILE *)usalp->errfile, "Abort ERROR! 0x%08X\n", s.SRB_Status);

            /*
             * Indicate that error has occured
             */
            return (FALSE);
      }

      if (usalp->debug > 0)
            fprintf((FILE *)usalp->errfile, "Abort SCSI command completed\n");

      /*
       * Everything went OK
       */
      return (TRUE);
}


#define HAVE_NAT_NAMES
static char * usalo_natname(SCSI *usalp, int busno, int tgt, int tlun) {
      int i;
      static char name[3];
      printf("hm, %d, %d, %d\n", busno, tgt, tlun);
      if (busno >= MAX_SCG || tgt >= MAX_TGT || tlun >= MAX_LUN)
            return "BADID";
      for (i = NUM_FLOPPY_DRIVES; i < NUM_MAX_NTSCSI_DRIVES; i++) {
            if(sptiglobal.drive[i].bUsed &&
                        tlun == sptiglobal.drive[i].lun &&
                        tgt == sptiglobal.drive[i].tgt && 
                        busno == sptiglobal.drive[i].ha)
            {
                  snprintf(name, 3, "%c:", 'A'+sptiglobal.drive[i].driveLetter);
                  return name;
            }
      }
      return "BADID";
}


Generated by  Doxygen 1.6.0   Back to index