scsipt.c
上传用户:xmgzy123
上传日期:2007-01-07
资源大小:373k
文件大小:14k
源码类别:

SCSI/ASPI

开发平台:

WINDOWS

  1. /*
  2.  * scsipt.c - Copyright (C) 1999 Jay A. Key
  3.  *
  4.  * Native NT support functions via the SCSI Pass Through interface instead
  5.  * of ASPI.  Although based on information from the NT 4.0 DDK from 
  6.  * Microsoft, the information has been sufficiently distilled to allow
  7.  * compilation w/o having the DDK installed.
  8.  *
  9.  * Implements the following functions:
  10.  *   DWORD SPTIGetASPI32SupportInfo(void);
  11.  *   DWORD SPTISendASPI32Command(LPSRB);
  12.  * which are equivalents to their ASPI counterparts.  Additionally implements
  13.  *   int InitSCSIPT( void );
  14.  *   int DeinitSCSIPT( void );
  15.  *
  16.  **********************************************************************
  17.  *
  18.  * This program is free software; you can redistribute it and/or modify
  19.  * it under the terms of the GNU Lesser General Public License as published
  20.  * by the Free Software Foundation; either version 2 of the License, or
  21.  * (at your option) any later version.
  22.  *
  23.  * This program is distributed in the hope that it will be useful,
  24.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26.  * GNU General Public License for more details.
  27.  *
  28.  * You should have received a copy of the GNU Lesser General Public License
  29.  * along with this program; if not, write to the Free Software
  30.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  31.  *
  32.  **********************************************************************
  33.  *
  34.  * $Id: scsipt.c,v 1.2 2000/02/25 10:47:37 akey Exp $
  35.  * $Date: &
  36.  * $Locker:  $
  37.  * $Log: scsipt.c,v $
  38.  * Revision 1.2  2000/02/25 10:47:37  akey
  39.  * sync'ed with akrip32.dll v0.94
  40.  *
  41.  * Revision 1.6  2000/02/25 10:13:26  akey
  42.  * Added SPTIOpenCDHandle for scsi pass through
  43.  *
  44.  * Revision 1.5  2000/02/25 07:50:38  akey
  45.  * CreateFile now tries both with/without the GENERIC_WRITE flag
  46.  *
  47.  * Revision 1.4  2000/02/14 09:56:25  akey
  48.  * cleaned up #ifdef _DEBUG code considerably
  49.  *
  50.  * Revision 1.3  2000/01/31 15:35:40  akey
  51.  * v0.93: added CDDBGetServerList and fixed problem with Win2000 scsi pass through code
  52.  *
  53.  * Revision 1.2  2000/01/17 11:11:29  akey
  54.  * Put debug code in #ifdef
  55.  *
  56.  * Revision 1.1  2000/01/12 10:06:05  akey
  57.  * Minimal SCSI passthrough IOCTL support
  58.  *
  59.  *
  60.  */
  61. #include <windows.h>
  62. #include <stdio.h>
  63. #include <stddef.h>
  64. #include "myaspi32.h"
  65. #include "scsidefs.h"
  66. #include "aspilib.h"
  67. #include "akrip32.h"
  68. #include "scsipt.h"
  69. typedef struct {
  70.   BYTE ha;
  71.   BYTE tgt;
  72.   BYTE lun;
  73.   BYTE driveLetter;
  74.   BOOL bUsed;
  75.   HANDLE hDevice;
  76.   BYTE inqData[36];
  77. } DRIVE;
  78. typedef struct {
  79.   BYTE numAdapters;
  80.   DRIVE drive[26];
  81. } SPTIGLOBAL;
  82. void GetDriveInformation( BYTE i, DRIVE *pDrive );
  83. BYTE SPTIGetNumAdapters( void );
  84. BYTE SPTIGetDeviceIndex( BYTE ha, BYTE tgt, BYTE lun );
  85. DWORD SPTIHandleHaInquiry( LPSRB_HAInquiry lpsrb );
  86. DWORD SPTIGetDeviceType( LPSRB_GDEVBlock lpsrb );
  87. DWORD SPTIExecSCSICommand( LPSRB_ExecSCSICmd lpsrb, BOOL bBeenHereBefore );
  88. HANDLE GetFileHandle( BYTE i );
  89. static BOOL bSCSIPTInit = FALSE;
  90. static SPTIGLOBAL sptiglobal;
  91. static BOOL bUsingSCSIPT = FALSE;
  92. /*
  93.  * Initialization of SCSI Pass Through Interface code.  Responsible for
  94.  * setting up the array of SCSI devices.  This code will be a little
  95.  * different from the normal code -- it will query each drive letter from
  96.  * C: through Z: to see if it is  a CD.  When we identify a CD, we then 
  97.  * send CDB with the INQUIRY command to it -- NT will automagically fill in
  98.  * the PathId, TargetId, and Lun for us.
  99.  */
  100. int InitSCSIPT( void )
  101. {
  102.   BYTE i;
  103.   char buf[4];
  104.   UINT uDriveType;
  105.   int retVal = 0;
  106.   if ( bSCSIPTInit )
  107.     return 0;
  108.   ZeroMemory( &sptiglobal, sizeof(SPTIGLOBAL) );
  109.   for( i = 0; i < 26; i++ )
  110.     sptiglobal.drive[i].hDevice = INVALID_HANDLE_VALUE;
  111.   for( i = 2; i < 26; i++ )
  112.     {
  113.       wsprintf( buf, "%c:\", (char)('A'+i) );
  114.       uDriveType = GetDriveType( buf );
  115.       if ( uDriveType == DRIVE_CDROM )
  116. {
  117.   GetDriveInformation( i, &sptiglobal.drive[i] );
  118.   if ( sptiglobal.drive[i].bUsed )
  119.     retVal++;
  120. }
  121.     }
  122.   sptiglobal.numAdapters = SPTIGetNumAdapters( );
  123.   bSCSIPTInit = TRUE;
  124.   if ( retVal > 0 )
  125.     bUsingSCSIPT = TRUE;
  126.   return retVal;
  127. }
  128. int DeinitSCSIPT( void )
  129. {
  130.   BYTE i;
  131.   if ( !bSCSIPTInit )
  132.     return 0;
  133.   for( i = 2; i < 26; i++ )
  134.     {
  135.       if ( sptiglobal.drive[i].bUsed )
  136. {
  137.   CloseHandle( sptiglobal.drive[i].hDevice );
  138. }
  139.     }
  140.   sptiglobal.numAdapters = SPTIGetNumAdapters( );
  141.   ZeroMemory( &sptiglobal, sizeof(SPTIGLOBAL) );
  142.   bSCSIPTInit = TRUE;
  143.   return -1;
  144. }
  145. BYTE SPTIGetNumAdapters( void )
  146. {
  147.   BYTE buf[256];
  148.   WORD i;
  149.   BYTE numAdapters = 0;
  150.   ZeroMemory( buf, 256 );
  151.   for( i = 0; i < 26; i++ )
  152.     {
  153.       if ( sptiglobal.drive[i].bUsed )
  154. buf[sptiglobal.drive[i].ha] = 1;
  155.     }
  156.   for( i = 0; i <= 255; i++ )
  157.     if ( buf[i] )
  158.       numAdapters++;
  159.   return numAdapters;
  160. }
  161. DWORD SPTIGetASPI32SupportInfo( void )
  162. {
  163.   DWORD retVal;
  164. #ifdef _DEBUG_SCSIPT
  165.   dbprintf( "AKRip32: SPTIGetASPI32SupportInfo" );
  166. #endif
  167.   if ( !sptiglobal.numAdapters )
  168.     retVal = (DWORD)(MAKEWORD(0,SS_NO_ADAPTERS));
  169.   else
  170.     retVal = (DWORD)(MAKEWORD(sptiglobal.numAdapters,SS_COMP));
  171.   return retVal;
  172. }
  173. /*
  174.  * Needs to call the appropriate function for the lpsrb->SRB_Cmd specified.
  175.  * Valid types are SC_HA_INQUIRY, SC_GET_DEV_TYPE, SC_EXEC_SCSI_CMD,
  176.  * and SC_RESET_DEV.
  177.  */
  178. DWORD SPTISendASPI32Command( LPSRB lpsrb )
  179. {
  180.   if ( !lpsrb )
  181.     return SS_ERR;
  182.   switch( lpsrb->SRB_Cmd )
  183.     {
  184.     case SC_HA_INQUIRY:
  185.       return SPTIHandleHaInquiry( (LPSRB_HAInquiry)lpsrb );
  186.     case SC_GET_DEV_TYPE:
  187.       return SPTIGetDeviceType( (LPSRB_GDEVBlock)lpsrb );
  188.     case SC_EXEC_SCSI_CMD:
  189.       return SPTIExecSCSICommand( (LPSRB_ExecSCSICmd)lpsrb, FALSE );
  190.     case SC_RESET_DEV:
  191.     default:
  192.       lpsrb->SRB_Status = SS_ERR;
  193.       return SS_ERR;
  194.     }
  195.   return SS_ERR;  // should never get to here...
  196. }
  197. /*
  198.  * Universal function to get a file handle to the CD device.  Since
  199.  * NT 4.0 wants just the GENERIC_READ flag, and Win2K wants both
  200.  * GENERIC_READ and GENERIC_WRITE (why a read-only CD device needs
  201.  * GENERIC_WRITE access is beyond me...), the easist workaround is to just
  202.  * try them both.
  203.  */
  204. HANDLE GetFileHandle( BYTE i )
  205. {
  206.   char buf[12];
  207.   HANDLE fh;
  208.   OSVERSIONINFO osver;
  209.   DWORD dwFlags;
  210.   ZeroMemory( &osver, sizeof(osver) );
  211.   osver.dwOSVersionInfoSize = sizeof(osver);
  212.   GetVersionEx( &osver );
  213.   // if Win2K or greater, add GENERIC_WRITE
  214.   dwFlags = GENERIC_READ;
  215.   if ( (osver.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
  216.        (osver.dwMajorVersion > 4) )
  217.     {
  218.       dwFlags |= GENERIC_WRITE;
  219. #ifdef _DEBUG_SCSIPT
  220.       dbprintf( "AKRip32: SCSIPT: GetFileHandle(): Setting for Win2K" );
  221. #endif
  222.     }
  223.   wsprintf( buf, "\\.\%c:", (char)('A'+i) );
  224.   fh = CreateFile( buf, dwFlags, FILE_SHARE_READ, NULL,
  225.    OPEN_EXISTING, 0, NULL );
  226.   if ( fh == INVALID_HANDLE_VALUE )
  227.     {
  228.       dwFlags ^= GENERIC_WRITE;
  229.       fh = CreateFile( buf, dwFlags, FILE_SHARE_READ, NULL,
  230.        OPEN_EXISTING, 0, NULL );
  231.     }
  232. #ifdef _DEBUG_SCSIPT
  233.   dbprintf( "akrip32: scsipt: CreateFile() failed! -> %d", GetLastError() );
  234. #endif
  235.   return fh;
  236. }
  237. void GetDriveInformation( BYTE i, DRIVE *pDrive )
  238. {
  239.   HANDLE fh;
  240.   //char buf[12];
  241.   BOOLEAN status;
  242.   SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
  243.   ULONG length, returned;
  244.   BYTE inqData[100];
  245. #ifdef _DEBUG_SCSIPT
  246.   dbprintf( "AKRip32: SCSIPT: Checking drive %c:", 'A'+i );
  247. #endif
  248.   fh = GetFileHandle( i );
  249.   if ( fh == INVALID_HANDLE_VALUE )
  250.     {
  251. #ifdef _DEBUG_SCSIPT
  252.       dbprintf( "       : fh == INVALID_HANDLE_VALUE" );
  253. #endif
  254.       return;
  255.     }
  256. #ifdef _DEBUG_SCSIPT
  257.   dbprintf( "       : Index %d: fh == %08X", i, fh );
  258. #endif
  259.   ZeroMemory( &swb, sizeof(swb) );
  260.   ZeroMemory( inqData, 100 );
  261.   swb.spt.Length          = sizeof(SCSI_PASS_THROUGH);
  262.   swb.spt.CdbLength       = 6;
  263.   swb.spt.SenseInfoLength = 24;
  264.   swb.spt.DataIn          = SCSI_IOCTL_DATA_IN;
  265.   swb.spt.DataTransferLength = 100;
  266.   swb.spt.TimeOutValue    = 2;
  267.   swb.spt.DataBuffer      = inqData;
  268.   swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER,ucSenseBuf );
  269.   swb.spt.Cdb[0]          = 0x12;
  270.   swb.spt.Cdb[4]          = 100;
  271.   length = sizeof(swb);
  272. #ifdef _DEBUG_SCSIPT
  273.   dbprintf( "AKRip32: GetDriveInformation: Calling DeviceIoControl" );
  274. #endif
  275.   status = DeviceIoControl( fh,
  276.     IOCTL_SCSI_PASS_THROUGH_DIRECT,
  277.     &swb,
  278.     length,
  279.     &swb,
  280.     length,
  281.     &returned,
  282.     NULL );
  283.   if ( !status )
  284.     {
  285.       CloseHandle( fh );
  286. #ifdef _DEBUG_SCSIPT
  287.       dbprintf( "AKRip32: SCSIPT: Error DeviceIoControl() -> %d",
  288. GetLastError() );
  289. #endif
  290.       return;
  291.     }
  292. #ifdef _DEBUG_SCSIPT
  293.   dbprintf( "AKRip32: SPTI: Adding drive %c: (%d:%d:%d)", 'A'+i,
  294.     swb.spt.PathId, swb.spt.TargetId, swb.spt.Lun );
  295. #endif
  296.   pDrive->bUsed     = TRUE;
  297.   pDrive->ha        = swb.spt.PathId;
  298.   pDrive->tgt       = swb.spt.TargetId;
  299.   pDrive->lun       = swb.spt.Lun;
  300.   pDrive->driveLetter = i;
  301.   pDrive->hDevice   = INVALID_HANDLE_VALUE;
  302.   memcpy( pDrive->inqData, inqData, 36 );
  303.   CloseHandle( fh );
  304. }
  305. DWORD SPTIHandleHaInquiry( LPSRB_HAInquiry lpsrb )
  306. {
  307.   DWORD *pMTL;
  308.   lpsrb->HA_Count    = sptiglobal.numAdapters;
  309.   if ( lpsrb->SRB_HaID >= sptiglobal.numAdapters )
  310.     {
  311.       lpsrb->SRB_Status = SS_INVALID_HA;
  312.       return SS_INVALID_HA;
  313.     }
  314.   lpsrb->HA_SCSI_ID  = 7;  // who cares... we're not really an ASPI manager
  315.   memcpy( lpsrb->HA_ManagerId,  "AKASPI v0.000001", 16 );
  316.   memcpy( lpsrb->HA_Identifier, "SCSI Adapter    ", 16 );
  317.   lpsrb->HA_Identifier[13] = (char)('0'+lpsrb->SRB_HaID);
  318.   ZeroMemory( lpsrb->HA_Unique, 16 );
  319.   lpsrb->HA_Unique[3] = 8;
  320.   pMTL = (LPDWORD)&lpsrb->HA_Unique[4];
  321.   *pMTL = 64 * 1024;
  322.   lpsrb->SRB_Status = SS_COMP;
  323.   return SS_COMP;
  324. }
  325. /*
  326.  * Scans through the drive array and returns DTYPE_CDROM type for all items
  327.  * found, and DTYPE_UNKNOWN for all others.
  328.  */
  329. DWORD SPTIGetDeviceType( LPSRB_GDEVBlock lpsrb )
  330. {
  331. #ifdef _DEBUG_SCSIPT
  332.   dbprintf( "AKRip32: SPTIGetDeviceType( %d:%d:%d )",lpsrb->SRB_HaID, lpsrb->SRB_Target, lpsrb->SRB_Lun );
  333. #endif
  334.   lpsrb->SRB_Status = SS_NO_DEVICE;
  335.   if ( SPTIGetDeviceIndex( lpsrb->SRB_HaID, lpsrb->SRB_Target, lpsrb->SRB_Lun ) )
  336.     lpsrb->SRB_Status = SS_COMP;
  337.   if ( lpsrb->SRB_Status == SS_COMP )
  338.     lpsrb->SRB_DeviceType = DTYPE_CDROM;
  339.   else
  340.     lpsrb->SRB_DeviceType = DTYPE_UNKNOWN;
  341.   return lpsrb->SRB_Status;
  342. }
  343. BYTE SPTIGetDeviceIndex( BYTE ha, BYTE tgt, BYTE lun )
  344. {
  345.   BYTE i;
  346. #ifdef _DEBUG_SCSIPT
  347.   dbprintf( "AKRip32: SPTIGetDeviceIndex" );
  348. #endif
  349.   for( i = 2; i < 26; i++ )
  350.     {
  351.       if ( sptiglobal.drive[i].bUsed )
  352. {
  353.   DRIVE *lpd;
  354.   lpd = &sptiglobal.drive[i];
  355.   if ( (lpd->ha == ha) && (lpd->tgt == tgt) && (lpd->lun == lun) )
  356.     return i;
  357. }
  358.     }
  359.   return 0;
  360. }
  361. /*
  362.  * Converts ASPI-style SRB to SCSI Pass Through IOCTL
  363.  */
  364. DWORD SPTIExecSCSICommand( LPSRB_ExecSCSICmd lpsrb, BOOL bBeenHereBefore )
  365. {
  366.   BOOLEAN status;
  367.   SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
  368.   ULONG length, returned;
  369.   //BYTE i;
  370.   BYTE idx;
  371.   idx = SPTIGetDeviceIndex( lpsrb->SRB_HaID, lpsrb->SRB_Target, lpsrb->SRB_Lun );
  372.   if ( idx == 0 )
  373.     {
  374.       lpsrb->SRB_Status = SS_ERR;
  375.       return SS_ERR;
  376.     }
  377.   if ( lpsrb->CDBByte[0] == 0x12 ) // is it an INQUIRY?
  378.     {
  379.       lpsrb->SRB_Status = SS_COMP;
  380.       memcpy( lpsrb->SRB_BufPointer, sptiglobal.drive[idx].inqData, 36 );
  381.       return SS_COMP;
  382.     }
  383.   if ( sptiglobal.drive[idx].hDevice == INVALID_HANDLE_VALUE )
  384.     sptiglobal.drive[idx].hDevice = GetFileHandle( sptiglobal.drive[idx].driveLetter );
  385.   ZeroMemory( &swb, sizeof(swb) );
  386.   swb.spt.Length            = sizeof(SCSI_PASS_THROUGH);
  387.   swb.spt.CdbLength         = lpsrb->SRB_CDBLen;
  388.   if ( lpsrb->SRB_Flags & SRB_DIR_IN )
  389.     swb.spt.DataIn          = SCSI_IOCTL_DATA_IN;
  390.   else if ( lpsrb->SRB_Flags & SRB_DIR_OUT )
  391.     swb.spt.DataIn          = SCSI_IOCTL_DATA_OUT;
  392.   else
  393.     swb.spt.DataIn          = SCSI_IOCTL_DATA_UNSPECIFIED;
  394.   swb.spt.DataTransferLength = lpsrb->SRB_BufLen;
  395.   swb.spt.TimeOutValue      = 5;
  396.   swb.spt.DataBuffer        = lpsrb->SRB_BufPointer;
  397.   swb.spt.SenseInfoOffset   =
  398.     offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf );
  399.   memcpy( swb.spt.Cdb, lpsrb->CDBByte, lpsrb->SRB_CDBLen );
  400.   length = sizeof(swb);
  401. #ifdef _DEBUG_SCSIPT
  402.   dbprintf( "AKRip32: SPTIExecSCSICmd: calling DeviceIoControl()" );
  403.   dbprintf( "       : cmd == 0x%02X", swb.spt.Cdb[0] );
  404. #endif
  405.   status = DeviceIoControl( sptiglobal.drive[idx].hDevice,
  406.     IOCTL_SCSI_PASS_THROUGH_DIRECT,
  407.     &swb,
  408.     length,
  409.     &swb,
  410.     length,
  411.     &returned,
  412.     NULL );
  413.   if ( status )
  414.     {
  415.       lpsrb->SRB_Status = SS_COMP;
  416.       OutputDebugString( "       : SRB_Status == SS_COMP" );
  417.     }
  418.   else
  419.     {
  420.       DWORD dwErrCode;
  421.       lpsrb->SRB_Status = SS_ERR;
  422.       lpsrb->SRB_TargStat = 0x0004;
  423.       dwErrCode = GetLastError();
  424. #ifdef _DEBUG_SCSIPT
  425.       dbprintf( "       : error == %d   handle == %08X", dwErrCode, sptiglobal.drive[idx].hDevice );
  426. #endif
  427.       /*
  428.        * KLUDGE ALERT! KLUDGE ALERT! KLUDGE ALERT!
  429.        * Whenever a disk changer switches disks, it may render the device
  430.        * handle invalid.  We try to catch these errors here and recover
  431.        * from them.
  432.        */
  433.       if ( !bBeenHereBefore &&
  434.    ((dwErrCode == ERROR_MEDIA_CHANGED) || (dwErrCode == ERROR_INVALID_HANDLE)) )
  435. {
  436.   if ( dwErrCode != ERROR_INVALID_HANDLE )
  437.     CloseHandle( sptiglobal.drive[idx].hDevice );
  438.   GetDriveInformation( idx, &sptiglobal.drive[idx] );
  439. #ifdef _DEBUG_SCSIPT
  440.   dbprintf( "AKRip32: SPTIExecSCSICommand: Retrying after ERROR_MEDIA_CHANGED" );
  441. #endif
  442.   return SPTIExecSCSICommand( lpsrb, TRUE );
  443. }
  444.     }
  445.   return lpsrb->SRB_Status;
  446. }
  447. BOOL UsingSCSIPT( void )
  448. {
  449.   return bUsingSCSIPT;
  450. }
  451. /*
  452.  * Calls GetFileHandle for the CD refered to by ha:tgt:lun to open it for
  453.  * use
  454.  */
  455. void SPTIOpenCDHandle( BYTE ha, BYTE tgt, BYTE lun )
  456. {
  457.   BYTE idx;
  458.   idx = SPTIGetDeviceIndex( ha, tgt, lun );
  459.   if ( idx && sptiglobal.drive[idx].hDevice == INVALID_HANDLE_VALUE )
  460.     sptiglobal.drive[idx].hDevice = GetFileHandle( sptiglobal.drive[idx].driveLetter );  
  461. }