diff options
Diffstat (limited to 'libusal/scsi-wnt.c')
-rw-r--r-- | libusal/scsi-wnt.c | 1848 |
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"; +} + |