summaryrefslogtreecommitdiff
path: root/libusal/scsi-wnt.c
diff options
context:
space:
mode:
Diffstat (limited to 'libusal/scsi-wnt.c')
-rw-r--r--libusal/scsi-wnt.c1848
1 files changed, 1848 insertions, 0 deletions
diff --git a/libusal/scsi-wnt.c b/libusal/scsi-wnt.c
new file mode 100644
index 0000000..ddce64b
--- /dev/null
+++ b/libusal/scsi-wnt.c
@@ -0,0 +1,1848 @@
+/*
+ * 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";
+}
+