scsipt.c
资源名称:xtractor.zip [点击查看]
上传用户:xmgzy123
上传日期:2007-01-07
资源大小:373k
文件大小:14k
源码类别:
SCSI/ASPI
开发平台:
WINDOWS
- /*
- * scsipt.c - Copyright (C) 1999 Jay A. Key
- *
- * 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.
- *
- * Implements the following functions:
- * DWORD SPTIGetASPI32SupportInfo(void);
- * DWORD SPTISendASPI32Command(LPSRB);
- * which are equivalents to their ASPI counterparts. Additionally implements
- * int InitSCSIPT( void );
- * int DeinitSCSIPT( void );
- *
- **********************************************************************
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published
- * by the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- **********************************************************************
- *
- * $Id: scsipt.c,v 1.2 2000/02/25 10:47:37 akey Exp $
- * $Date: &
- * $Locker: $
- * $Log: scsipt.c,v $
- * Revision 1.2 2000/02/25 10:47:37 akey
- * sync'ed with akrip32.dll v0.94
- *
- * Revision 1.6 2000/02/25 10:13:26 akey
- * Added SPTIOpenCDHandle for scsi pass through
- *
- * Revision 1.5 2000/02/25 07:50:38 akey
- * CreateFile now tries both with/without the GENERIC_WRITE flag
- *
- * Revision 1.4 2000/02/14 09:56:25 akey
- * cleaned up #ifdef _DEBUG code considerably
- *
- * Revision 1.3 2000/01/31 15:35:40 akey
- * v0.93: added CDDBGetServerList and fixed problem with Win2000 scsi pass through code
- *
- * Revision 1.2 2000/01/17 11:11:29 akey
- * Put debug code in #ifdef
- *
- * Revision 1.1 2000/01/12 10:06:05 akey
- * Minimal SCSI passthrough IOCTL support
- *
- *
- */
- #include <windows.h>
- #include <stdio.h>
- #include <stddef.h>
- #include "myaspi32.h"
- #include "scsidefs.h"
- #include "aspilib.h"
- #include "akrip32.h"
- #include "scsipt.h"
- typedef struct {
- BYTE ha;
- BYTE tgt;
- BYTE lun;
- BYTE driveLetter;
- BOOL bUsed;
- HANDLE hDevice;
- BYTE inqData[36];
- } DRIVE;
- typedef struct {
- BYTE numAdapters;
- DRIVE drive[26];
- } SPTIGLOBAL;
- void GetDriveInformation( BYTE i, DRIVE *pDrive );
- BYTE SPTIGetNumAdapters( void );
- BYTE SPTIGetDeviceIndex( BYTE ha, BYTE tgt, BYTE lun );
- DWORD SPTIHandleHaInquiry( LPSRB_HAInquiry lpsrb );
- DWORD SPTIGetDeviceType( LPSRB_GDEVBlock lpsrb );
- DWORD SPTIExecSCSICommand( LPSRB_ExecSCSICmd lpsrb, BOOL bBeenHereBefore );
- HANDLE GetFileHandle( BYTE i );
- static BOOL bSCSIPTInit = FALSE;
- static SPTIGLOBAL sptiglobal;
- static BOOL bUsingSCSIPT = FALSE;
- /*
- * 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.
- */
- int InitSCSIPT( void )
- {
- BYTE i;
- char buf[4];
- UINT uDriveType;
- int retVal = 0;
- if ( bSCSIPTInit )
- return 0;
- ZeroMemory( &sptiglobal, sizeof(SPTIGLOBAL) );
- for( i = 0; i < 26; i++ )
- sptiglobal.drive[i].hDevice = INVALID_HANDLE_VALUE;
- for( i = 2; i < 26; i++ )
- {
- wsprintf( buf, "%c:\", (char)('A'+i) );
- uDriveType = GetDriveType( buf );
- if ( uDriveType == DRIVE_CDROM )
- {
- GetDriveInformation( i, &sptiglobal.drive[i] );
- if ( sptiglobal.drive[i].bUsed )
- retVal++;
- }
- }
- sptiglobal.numAdapters = SPTIGetNumAdapters( );
- bSCSIPTInit = TRUE;
- if ( retVal > 0 )
- bUsingSCSIPT = TRUE;
- return retVal;
- }
- int DeinitSCSIPT( void )
- {
- BYTE i;
- if ( !bSCSIPTInit )
- return 0;
- for( i = 2; i < 26; i++ )
- {
- if ( sptiglobal.drive[i].bUsed )
- {
- CloseHandle( sptiglobal.drive[i].hDevice );
- }
- }
- sptiglobal.numAdapters = SPTIGetNumAdapters( );
- ZeroMemory( &sptiglobal, sizeof(SPTIGLOBAL) );
- bSCSIPTInit = TRUE;
- return -1;
- }
- BYTE SPTIGetNumAdapters( void )
- {
- BYTE buf[256];
- WORD i;
- BYTE numAdapters = 0;
- ZeroMemory( buf, 256 );
- for( i = 0; i < 26; i++ )
- {
- if ( sptiglobal.drive[i].bUsed )
- buf[sptiglobal.drive[i].ha] = 1;
- }
- for( i = 0; i <= 255; i++ )
- if ( buf[i] )
- numAdapters++;
- return numAdapters;
- }
- DWORD SPTIGetASPI32SupportInfo( void )
- {
- DWORD retVal;
- #ifdef _DEBUG_SCSIPT
- dbprintf( "AKRip32: SPTIGetASPI32SupportInfo" );
- #endif
- if ( !sptiglobal.numAdapters )
- retVal = (DWORD)(MAKEWORD(0,SS_NO_ADAPTERS));
- else
- retVal = (DWORD)(MAKEWORD(sptiglobal.numAdapters,SS_COMP));
- return retVal;
- }
- /*
- * Needs to call the appropriate function for the lpsrb->SRB_Cmd specified.
- * Valid types are SC_HA_INQUIRY, SC_GET_DEV_TYPE, SC_EXEC_SCSI_CMD,
- * and SC_RESET_DEV.
- */
- DWORD SPTISendASPI32Command( LPSRB lpsrb )
- {
- if ( !lpsrb )
- return SS_ERR;
- switch( lpsrb->SRB_Cmd )
- {
- case SC_HA_INQUIRY:
- return SPTIHandleHaInquiry( (LPSRB_HAInquiry)lpsrb );
- case SC_GET_DEV_TYPE:
- return SPTIGetDeviceType( (LPSRB_GDEVBlock)lpsrb );
- case SC_EXEC_SCSI_CMD:
- return SPTIExecSCSICommand( (LPSRB_ExecSCSICmd)lpsrb, FALSE );
- case SC_RESET_DEV:
- default:
- lpsrb->SRB_Status = SS_ERR;
- return SS_ERR;
- }
- return SS_ERR; // should never get to here...
- }
- /*
- * 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.
- */
- HANDLE GetFileHandle( BYTE i )
- {
- char buf[12];
- HANDLE fh;
- OSVERSIONINFO osver;
- DWORD dwFlags;
- ZeroMemory( &osver, sizeof(osver) );
- osver.dwOSVersionInfoSize = sizeof(osver);
- GetVersionEx( &osver );
- // if Win2K or greater, add GENERIC_WRITE
- dwFlags = GENERIC_READ;
- if ( (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
- (osver.dwMajorVersion > 4) )
- {
- dwFlags |= GENERIC_WRITE;
- #ifdef _DEBUG_SCSIPT
- dbprintf( "AKRip32: SCSIPT: GetFileHandle(): Setting for Win2K" );
- #endif
- }
- wsprintf( buf, "\\.\%c:", (char)('A'+i) );
- fh = CreateFile( buf, dwFlags, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, 0, NULL );
- if ( fh == INVALID_HANDLE_VALUE )
- {
- dwFlags ^= GENERIC_WRITE;
- fh = CreateFile( buf, dwFlags, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, 0, NULL );
- }
- #ifdef _DEBUG_SCSIPT
- dbprintf( "akrip32: scsipt: CreateFile() failed! -> %d", GetLastError() );
- #endif
- return fh;
- }
- void GetDriveInformation( BYTE i, DRIVE *pDrive )
- {
- HANDLE fh;
- //char buf[12];
- BOOLEAN status;
- SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
- ULONG length, returned;
- BYTE inqData[100];
- #ifdef _DEBUG_SCSIPT
- dbprintf( "AKRip32: SCSIPT: Checking drive %c:", 'A'+i );
- #endif
- fh = GetFileHandle( i );
- if ( fh == INVALID_HANDLE_VALUE )
- {
- #ifdef _DEBUG_SCSIPT
- dbprintf( " : fh == INVALID_HANDLE_VALUE" );
- #endif
- return;
- }
- #ifdef _DEBUG_SCSIPT
- dbprintf( " : Index %d: fh == %08X", i, fh );
- #endif
- ZeroMemory( &swb, sizeof(swb) );
- ZeroMemory( inqData, 100 );
- swb.spt.Length = sizeof(SCSI_PASS_THROUGH);
- 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] = 0x12;
- swb.spt.Cdb[4] = 100;
- length = sizeof(swb);
- #ifdef _DEBUG_SCSIPT
- dbprintf( "AKRip32: GetDriveInformation: Calling DeviceIoControl" );
- #endif
- status = DeviceIoControl( fh,
- IOCTL_SCSI_PASS_THROUGH_DIRECT,
- &swb,
- length,
- &swb,
- length,
- &returned,
- NULL );
- if ( !status )
- {
- CloseHandle( fh );
- #ifdef _DEBUG_SCSIPT
- dbprintf( "AKRip32: SCSIPT: Error DeviceIoControl() -> %d",
- GetLastError() );
- #endif
- return;
- }
- #ifdef _DEBUG_SCSIPT
- dbprintf( "AKRip32: SPTI: Adding drive %c: (%d:%d:%d)", 'A'+i,
- swb.spt.PathId, swb.spt.TargetId, swb.spt.Lun );
- #endif
- pDrive->bUsed = TRUE;
- pDrive->ha = swb.spt.PathId;
- pDrive->tgt = swb.spt.TargetId;
- pDrive->lun = swb.spt.Lun;
- pDrive->driveLetter = i;
- pDrive->hDevice = INVALID_HANDLE_VALUE;
- memcpy( pDrive->inqData, inqData, 36 );
- CloseHandle( fh );
- }
- 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);
- ZeroMemory( lpsrb->HA_Unique, 16 );
- lpsrb->HA_Unique[3] = 8;
- pMTL = (LPDWORD)&lpsrb->HA_Unique[4];
- *pMTL = 64 * 1024;
- lpsrb->SRB_Status = SS_COMP;
- return SS_COMP;
- }
- /*
- * Scans through the drive array and returns DTYPE_CDROM type for all items
- * found, and DTYPE_UNKNOWN for all others.
- */
- DWORD SPTIGetDeviceType( LPSRB_GDEVBlock lpsrb )
- {
- #ifdef _DEBUG_SCSIPT
- dbprintf( "AKRip32: SPTIGetDeviceType( %d:%d:%d )",lpsrb->SRB_HaID, lpsrb->SRB_Target, lpsrb->SRB_Lun );
- #endif
- lpsrb->SRB_Status = SS_NO_DEVICE;
- if ( SPTIGetDeviceIndex( lpsrb->SRB_HaID, lpsrb->SRB_Target, lpsrb->SRB_Lun ) )
- lpsrb->SRB_Status = SS_COMP;
- if ( lpsrb->SRB_Status == SS_COMP )
- lpsrb->SRB_DeviceType = DTYPE_CDROM;
- else
- lpsrb->SRB_DeviceType = DTYPE_UNKNOWN;
- return lpsrb->SRB_Status;
- }
- BYTE SPTIGetDeviceIndex( BYTE ha, BYTE tgt, BYTE lun )
- {
- BYTE i;
- #ifdef _DEBUG_SCSIPT
- dbprintf( "AKRip32: SPTIGetDeviceIndex" );
- #endif
- for( i = 2; i < 26; 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
- */
- DWORD SPTIExecSCSICommand( LPSRB_ExecSCSICmd lpsrb, BOOL bBeenHereBefore )
- {
- BOOLEAN status;
- SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
- ULONG length, returned;
- //BYTE i;
- BYTE idx;
- idx = SPTIGetDeviceIndex( lpsrb->SRB_HaID, lpsrb->SRB_Target, lpsrb->SRB_Lun );
- if ( idx == 0 )
- {
- lpsrb->SRB_Status = SS_ERR;
- return SS_ERR;
- }
- if ( lpsrb->CDBByte[0] == 0x12 ) // is it an INQUIRY?
- {
- lpsrb->SRB_Status = SS_COMP;
- memcpy( lpsrb->SRB_BufPointer, sptiglobal.drive[idx].inqData, 36 );
- return SS_COMP;
- }
- if ( sptiglobal.drive[idx].hDevice == INVALID_HANDLE_VALUE )
- sptiglobal.drive[idx].hDevice = GetFileHandle( sptiglobal.drive[idx].driveLetter );
- ZeroMemory( &swb, 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 = 5;
- 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
- dbprintf( "AKRip32: SPTIExecSCSICmd: calling DeviceIoControl()" );
- dbprintf( " : 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 );
- if ( status )
- {
- lpsrb->SRB_Status = SS_COMP;
- OutputDebugString( " : SRB_Status == SS_COMP" );
- }
- else
- {
- DWORD dwErrCode;
- lpsrb->SRB_Status = SS_ERR;
- lpsrb->SRB_TargStat = 0x0004;
- dwErrCode = GetLastError();
- #ifdef _DEBUG_SCSIPT
- dbprintf( " : error == %d handle == %08X", 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] );
- #ifdef _DEBUG_SCSIPT
- dbprintf( "AKRip32: SPTIExecSCSICommand: Retrying after ERROR_MEDIA_CHANGED" );
- #endif
- return SPTIExecSCSICommand( lpsrb, TRUE );
- }
- }
- return lpsrb->SRB_Status;
- }
- BOOL UsingSCSIPT( void )
- {
- return bUsingSCSIPT;
- }
- /*
- * Calls GetFileHandle for the CD refered to by ha:tgt:lun to open it for
- * use
- */
- void SPTIOpenCDHandle( BYTE ha, BYTE tgt, BYTE lun )
- {
- BYTE idx;
- idx = SPTIGetDeviceIndex( ha, tgt, lun );
- if ( idx && sptiglobal.drive[idx].hDevice == INVALID_HANDLE_VALUE )
- sptiglobal.drive[idx].hDevice = GetFileHandle( sptiglobal.drive[idx].driveLetter );
- }