123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- #include <stdio.h>
- #include <stddef.h>
- #include "NTScsi.h"
- typedef struct {
- BYTE ha;
- BYTE tgt;
- BYTE lun;
- BYTE driveLetter;
- BOOL bUsed;
- HANDLE hDevice;
- BYTE inqData[36];
- } NTSCSIDRIVE;
- typedef struct
- {
- BYTE numAdapters;
- NTSCSIDRIVE drive[26];
- } NTSCSIDRIVES;
- void GetDriveInformation( BYTE i, NTSCSIDRIVE *pDrive );
- static HANDLE GetFileHandle( BYTE i );
- static BOOL bNtScsiAvailable = FALSE;
- static NTSCSIDRIVES NtScsiDrives;
- static BOOL bUseNtScsi = 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 NtScsiInit( void )
- {
- BYTE i;
- wchar_t buf[4] = {0};
- UINT uDriveType;
- int retVal = 0;
- if ( bNtScsiAvailable )
- {
- for( i = 2; i < 26; i++ ) if ( NtScsiDrives.drive[i].bUsed ) retVal++;
- bUseNtScsi = (retVal > 0 );
- return retVal;
- }
- memset( &NtScsiDrives, 0x00, sizeof(NtScsiDrives) );
- for( i = 0; i < 26; i++ )
- {
- NtScsiDrives.drive[i].hDevice = INVALID_HANDLE_VALUE;
- }
- for( i = 2; i < 26; i++ )
- {
- wsprintf( buf, L"%c:\\", (wchar_t)('A'+i) );
- uDriveType = GetDriveType( buf );
- /* check if this is a CDROM drive */
- if ( uDriveType == DRIVE_CDROM )
- {
- GetDriveInformation( i, &NtScsiDrives.drive[i] );
- if ( NtScsiDrives.drive[i].bUsed )
- retVal++;
- }
- }
- NtScsiDrives.numAdapters = NtScsiGetNumAdapters( );
- bNtScsiAvailable = TRUE;
- if ( retVal > 0 )
- {
- bUseNtScsi = TRUE;
- }
- return retVal;
- }
- int NtScsiDeInit( void )
- {
- BYTE i;
- if ( !bNtScsiAvailable )
- return 0;
- for( i = 2; i < 26; i++ )
- {
- if ( NtScsiDrives.drive[i].bUsed )
- {
- CloseHandle( NtScsiDrives.drive[i].hDevice );
- }
- }
- NtScsiDrives.numAdapters = NtScsiGetNumAdapters( );
- ZeroMemory( &NtScsiDrives, sizeof(NtScsiDrives) );
- bNtScsiAvailable = FALSE;
- return -1;
- }
- /*
- * Returns the number of "adapters" present.
- */
- BYTE NtScsiGetNumAdapters( void )
- {
- BYTE buf[256] = {0};
- WORD i;
- BYTE numAdapters = 0;
- // 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 < 26; i++ )
- {
- if ( NtScsiDrives.drive[i].bUsed )
- buf[NtScsiDrives.drive[i].ha] = 1;
- }
- for( i = 0; i <= 255; i++ )
- {
- if ( buf[i] )
- numAdapters++;
- }
- return numAdapters;
- }
- /*
- * Replacement for GetASPI32SupportInfo from wnaspi32.dll
- */
- DWORD NtScsiGetASPI32SupportInfo( void )
- {
- DWORD retVal;
- if ( !NtScsiDrives.numAdapters )
- retVal = (DWORD)(MAKEWORD(0,SS_NO_ADAPTERS));
- else
- retVal = (DWORD)(MAKEWORD(NtScsiDrives.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 NtScsiSendASPI32Command( LPSRB lpsrb )
- {
- if ( !lpsrb )
- return SS_ERR;
- switch( lpsrb->SRB_Cmd )
- {
- case SC_HA_INQUIRY:
- return NtScsiHandleHaInquiry( (LPSRB_HAINQUIRY)lpsrb );
- break;
- case SC_GET_DEV_TYPE:
- return NtScsiGetDeviceType( (LPSRB_GDEVBLOCK)lpsrb );
- break;
- case SC_EXEC_SCSI_CMD:
- return NtScsiExecSCSICommand( (LPSRB_EXECSCSICMD)lpsrb, FALSE );
- break;
- case SC_RESET_DEV:
- default:
- lpsrb->SRB_Status = SS_ERR;
- return SS_ERR;
- break;
- }
- 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.
- */
- static HANDLE GetFileHandle( BYTE i )
- {
- wchar_t buf[12] = {0};
- HANDLE fh = NULL;
- OSVERSIONINFO osver;
- DWORD dwFlags;
- memset( &osver, 0x00, 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;
- }
- wsprintf( buf, L"\\\\.\\%c:", (wchar_t)('A'+i) );
- fh = CreateFile( buf, dwFlags, FILE_SHARE_READ|FILE_SHARE_WRITE, 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;
- fh = CreateFile( buf, dwFlags, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
- }
- if ( fh == INVALID_HANDLE_VALUE )
- {
- }
- else
- {
- }
- 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
- */
- void GetDriveInformation( BYTE i, NTSCSIDRIVE *pDrive )
- {
- HANDLE fh;
- char buf[2048] = {0};
- BOOL status;
- PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER pswb;
- PSCSI_ADDRESS pscsiAddr;
- ULONG length, returned;
- BYTE inqData[100] = {0};
- fh = GetFileHandle( i );
- if ( fh == INVALID_HANDLE_VALUE )
- {
- return;
- }
- /*
- * Get the drive inquiry data
- */
- ZeroMemory( &buf, 2048 );
- ZeroMemory( inqData, 100 );
- pswb = (PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)buf;
- pswb->spt.Length = sizeof(SCSI_PASS_THROUGH_DIRECT);
- pswb->spt.CdbLength = 6;
- pswb->spt.SenseInfoLength = 24;
- pswb->spt.DataIn = SCSI_IOCTL_DATA_IN;
- pswb->spt.DataTransferLength = 100;
- pswb->spt.TimeOutValue = 2;
- pswb->spt.DataBuffer = inqData;
- pswb->spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER,ucSenseBuf );
- pswb->spt.Cdb[0] = 0x12;
- pswb->spt.Cdb[4] = 100;
- length = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
- status = DeviceIoControl( fh,
- IOCTL_SCSI_PASS_THROUGH_DIRECT,
- pswb,
- length,
- pswb,
- length,
- &returned,
- NULL );
- if ( !status )
- {
- CloseHandle( fh );
- return;
- }
- memcpy( pDrive->inqData, inqData, 36 );
- /*
- * get the address (path/tgt/lun) of the drive via IOCTL_SCSI_GET_ADDRESS
- */
- ZeroMemory( &buf, 2048 );
- pscsiAddr = (PSCSI_ADDRESS)buf;
- pscsiAddr->Length = sizeof(SCSI_ADDRESS);
- if ( DeviceIoControl( fh, IOCTL_SCSI_GET_ADDRESS, NULL, 0,
- pscsiAddr, sizeof(buf), &returned,
- NULL ) )
- {
- pDrive->bUsed = TRUE;
- pDrive->ha = pscsiAddr->PortNumber;
- pDrive->tgt = pscsiAddr->TargetId;
- pDrive->lun = pscsiAddr->Lun;
- pDrive->driveLetter = i;
- pDrive->hDevice = INVALID_HANDLE_VALUE;
- }
- else if (50 == GetLastError()) // usb/firewire
- {
- pDrive->bUsed = TRUE;
- pDrive->ha = i;
- pDrive->tgt = 0;
- pDrive->lun = 0;
- pDrive->driveLetter = i;
- pDrive->hDevice = INVALID_HANDLE_VALUE;
- }
- else
- {
- pDrive->bUsed = FALSE;
- }
- CloseHandle( fh );
- }
- DWORD NtScsiHandleHaInquiry( LPSRB_HAINQUIRY lpsrb )
- {
- DWORD *pMTL;
- lpsrb->HA_Count = NtScsiDrives.numAdapters;
- if ( lpsrb->SRB_HaId >= NtScsiDrives.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, "blahblahblahblah", 16 );
- memcpy( lpsrb->HA_Identifier, "blahblahblahblah", 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 NtScsiGetDeviceType( LPSRB_GDEVBLOCK lpsrb )
- {
- lpsrb->SRB_Status = SS_NO_DEVICE;
- if ( NtScsiGetDeviceIndex( lpsrb->SRB_HaId, lpsrb->SRB_Target, lpsrb->SRB_Lun ) )
- lpsrb->SRB_Status = SS_COMP;
- if ( lpsrb->SRB_Status == SS_COMP )
- lpsrb->SRB_DeviceType = DTC_CDROM;
- else
- lpsrb->SRB_DeviceType = DTC_UNKNOWN;
- return lpsrb->SRB_Status;
- }
- /*
- * Looks up the index in the drive array for a given ha:tgt:lun triple
- */
- BYTE NtScsiGetDeviceIndex( BYTE ha, BYTE tgt, BYTE lun )
- {
- BYTE i;
- for( i = 2; i < 26; i++ )
- {
- if ( NtScsiDrives.drive[i].bUsed )
- {
- NTSCSIDRIVE *lpd;
- lpd = &NtScsiDrives.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 NtScsiExecSCSICommand( LPSRB_EXECSCSICMD lpsrb, BOOL bBeenHereBefore )
- {
- BOOL status;
- SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
- ULONG length, returned;
- BYTE idx;
- idx = NtScsiGetDeviceIndex( 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, NtScsiDrives.drive[idx].inqData, 36 );
- return SS_COMP;
- }
- if ( NtScsiDrives.drive[idx].hDevice == INVALID_HANDLE_VALUE )
- NtScsiDrives.drive[idx].hDevice = GetFileHandle( NtScsiDrives.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);
- status = DeviceIoControl( NtScsiDrives.drive[idx].hDevice,
- IOCTL_SCSI_PASS_THROUGH_DIRECT,
- &swb,
- length,
- &swb,
- length,
- &returned,
- NULL );
- if ( status )
- {
- lpsrb->SRB_Status = SS_COMP;
- }
- else
- {
- DWORD dwErrCode;
- lpsrb->SRB_Status = SS_ERR;
- lpsrb->SRB_TargStat = 0x0004;
- dwErrCode = GetLastError();
- /*
- * 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( NtScsiDrives.drive[idx].hDevice );
- GetDriveInformation( idx, &NtScsiDrives.drive[idx] );
- return NtScsiExecSCSICommand( lpsrb, TRUE );
- }
- }
- return lpsrb->SRB_Status;
- }
- BOOL UsingSCSIPT( void )
- {
- return bUseNtScsi;
- }
- /*
- * Calls GetFileHandle for the CD refered to by ha:tgt:lun to open it for
- * use
- */
- void NtScsiOpenCDHandle( BYTE ha, BYTE tgt, BYTE lun )
- {
- BYTE idx;
- idx = NtScsiGetDeviceIndex( ha, tgt, lun );
- if ( idx && NtScsiDrives.drive[idx].hDevice == INVALID_HANDLE_VALUE )
- NtScsiDrives.drive[idx].hDevice = GetFileHandle( NtScsiDrives.drive[idx].driveLetter );
- }
|