skSCSI.pas
上传用户:wanyu_2000
上传日期:2021-02-21
资源大小:527k
文件大小:36k
源码类别:

DVD

开发平台:

Delphi

  1. {==============================================================================|
  2. | SCSI Header for ASPI, ASAPI and SPTI/IOCTL                                   |
  3. |==============================================================================|
  4. |                                                                              |
  5. | Author: Kalman Speier                                                        |
  6. |   Mail: mail@speier.hu                                                       |
  7. |   Home: www.speier.hu                                                        |
  8. |  Legal: Copyright (c) 2002-2005 Speier Software                              |
  9. |         All Rights Reserved                                                  |
  10. |                                                                              |
  11. |==============================================================================|
  12. |                                                                              |
  13. | Definitions:                                                                 |
  14. |   SCSI = Small Computer System Interface                                     |
  15. |   ASPI = Advanced SCSI Programming Interface (Developed by Adaptec)          |
  16. |  ASAPI = Advanced ASPI Programming Interface (Developed by VOB/Pinnacle)     |
  17. |   SPTI = SCSI Passthrough Interface (MS Replacement of ASPI on NT/2k/XP/2k3) |
  18. |  IOCTL = Device Input/Output Control (WinAPI Command is DeviceIOControl)     |
  19. |                                                                              |
  20. |==============================================================================|
  21. |                                                                              |
  22. | Used Sources and Docs:                                                       |
  23. |  Adaptec Software Developer's Kit (SDK) v2.4                                 |
  24. |  SPC & MMC Drafts from T10.org (www.t10.org)                                 |
  25. |  ASPI & SCSI Programming by Alvise Valsecchi (www.hochfeiler.it/alvise)      |
  26. |                                                                              |
  27. | Thanx to:                                                                    |
  28. |  daNIL for WNASPI32 & SCSIDEFS 'C' Headers Translation (Project Jedi)        |
  29. |  Sergey "KSER" Kabikov for his Delphi ASPI Library                           |
  30. |  Farshid Mossaiby for ASPI Spy                                               |
  31. |  Jay A. Key for AKRip                                                        |
  32. |  Additional programming by Dancemammal                                       |
  33. |==============================================================================}
  34. unit skSCSI;
  35. interface
  36. uses
  37.   Windows,
  38.   SysUtils;
  39. const
  40.   {****************************************************************************}
  41.   {  ASPI COMMAND CONSTANTS                                                    }
  42.   {****************************************************************************}
  43.   SENSE_LEN = 14; // Default sense buffer length
  44.   SRB_DIR_SCSI = $00; // Direction determined by SCSI command
  45.   SRB_DIR_IN = $08; // Transfer from SCSI target to host
  46.   SRB_DIR_OUT = $10; // Transfer from host to SCSI target
  47.   SRB_POSTING = $01; // Enable ASPI posting
  48.   SRB_EVENT_NOTIFY = $40; // Enable ASPI event notification
  49.   SRB_ENABLE_RESIDUAL_COUNT = $04; // Enable residual byte count reporting
  50.   SRB_DATA_SG_LIST = $02; // Data buffer points to scatter-gather list
  51.   WM_ASPIPOST = $4D42; // ASPI Post message
  52.   DTYPE_CDROM = $05; // CD-ROM device type
  53.   DTYPE_UNKNOWN = $1F; // Unknown or no device type
  54.   {****************************************************************************}
  55.   {  ASPI COMMAND DEFINITIONS                                                  }
  56.   {****************************************************************************}
  57.   SC_HA_INQUIRY = $00; // Host adapter inquiry
  58.   SC_GET_DEV_TYPE = $01; // Get device type
  59.   SC_EXEC_SCSI_CMD = $02; // Execute SCSI command
  60.   SC_ABORT_SRB = $03; // Abort an SRB
  61.   SC_RESET_DEV = $04; // SCSI bus device reset
  62.   SC_GET_DISK_INFO = $06; // Get Disk information
  63.   SC_SCSI_INQUIRY = $12; // SCSI inquiry
  64.   {****************************************************************************}
  65.   {  SRB STATUS                                                                }
  66.   {****************************************************************************}
  67.   SS_PENDING = $00; // SRB being processed
  68.   SS_COMP = $01; // SRB completed without error
  69.   SS_ABORTED = $02; // SRB aborted
  70.   SS_ABORT_FAIL = $03; // Unable to abort SRB
  71.   SS_ERR = $04; // SRB completed with error
  72.   SS_INVALID_CMD = $80; // Invalid ASPI command
  73.   SS_INVALID_HA = $81; // Invalid host adapter number
  74.   SS_NO_DEVICE = $82; // SCSI device not installed
  75.   SS_INVALID_SRB = $E0; // Invalid parameter set in SRB
  76.   SS_FAILED_INIT = $E4; // ASPI for windows failed init
  77.   SS_ASPI_IS_BUSY = $E5; // No resources available to execute cmd
  78.   SS_BUFFER_TO_BIG = $E6; // Buffer size to big to handle!
  79.   SS_NO_ADAPTERS = $E8; // No host adapters to manage
  80.   {****************************************************************************}
  81.   {  HOST ADAPTER STATUS                                                       }
  82.   {****************************************************************************}
  83.   HASTAT_OK = $00; // Host adapter did not detect an error
  84.   HASTAT_SEL_TO = $11; // Selection Timeout
  85.   HASTAT_DO_DU = $12; // Data overrun data underrun
  86.   HASTAT_BUS_FREE = $13; // Unexpected bus free
  87.   HASTAT_PHASE_ERR = $14; // Target bus phase sequence failure
  88.   HASTAT_TIMEOUT = $09; // Timed out while SRB was waiting to be processed
  89.   HASTAT_COMMAND_TIMEOUT = $0B;
  90.   // While processing the SRB, the adapter is timed out
  91.   HASTAT_MESSAGE_REJECT = $0D;
  92.   // While processing SRB, the adapter received a MESSAGE REJECT
  93.   HASTAT_BUS_RESET = $0E; // A bus reset was detected
  94.   HASTAT_PARITY_ERROR = $0F; // A parity error was detected
  95.   HASTAT_REQUEST_SENSE_FAILED = $10;
  96.   // The adapter failed in issuing REQUEST SENSE
  97. type
  98.   TCDB = array[0..15] of Byte; // SCSI Command Descriptor Block (Max 16 bytes)
  99. type
  100.   {****************************************************************************}
  101.   {  HOST ADAPTER INQUIRY - SC_HA_INQUIRY                                      }
  102.   {****************************************************************************}
  103.   TSRB_HAInquiry = packed record
  104.     Cmd, // ASPI command code = SC_HA_INQUIRY
  105.     Status, // ASPI command status byte
  106.     HaId, // ASPI host adapter number
  107.     Flags: BYTE; // ASPI request flags
  108.     Hdr_Rsvd: DWORD; // Reserved, MUST = 0
  109.     HA_Count, // Number of host adapters present
  110.     HA_SCSI_ID: BYTE; // SCSI ID of host adapter
  111.     HA_ManagerId, // String describing the manager
  112.     HA_Identifier, // String describing the host adapter
  113.     HA_Unique: array[0..15] of CHAR; // Host Adapter Unique parameters
  114.     HA_Rsvd1: WORD;
  115.   end;
  116.   PSRB_HAInquiry = ^TSRB_HAInquiry;
  117.   {****************************************************************************}
  118.   {  GET DEVICE TYPE - SC_GET_DEV_TYPE                                         }
  119.   {****************************************************************************}
  120.   TSRB_GDEVBlock = packed record
  121.     Cmd, // ASPI command code = SC_GET_DEV_TYPE
  122.     Status, // ASPI command status byte
  123.     HaId, // ASPI host adapter number
  124.     Flags: BYTE; // Reserved
  125.     Hdr_Rsvd: DWORD; // Reserved
  126.     Target, // Target's SCSI ID
  127.     Lun, // Target's LUN number
  128.     DeviceType, // Target's peripheral device type
  129.     Rsvd1: BYTE;
  130.   end;
  131.   PSRB_GDEVBlock = ^TSRB_GDEVBlock;
  132.   {****************************************************************************}
  133.   {  REQUES SENSE DATA FORMAT                                                  }
  134.   {****************************************************************************}
  135.   TSenseArea = packed record
  136.     ErrorCode,
  137.       SegmentNum,
  138.       SenseKey,
  139.       InfoByte0,
  140.       InfoByte1,
  141.       InfoByte2,
  142.       InfoByte3,
  143.       AddSenLen,
  144.       ComSpecInf0,
  145.       ComSpecInf1,
  146.       ComSpecInf2,
  147.       ComSpecInf3,
  148.       AddSenseCode,
  149.       AddSenQual,
  150.       FieldRepUCode,
  151.       SenKeySpec15,
  152.       SenKeySpec16,
  153.       SenKeySpec17: Byte;
  154.     AddSenseBytes: array[18..$20] of Byte;
  155.   end;
  156.   {****************************************************************************}
  157.   {  EXECUTE SCSI COMMAND - SC_EXEC_SCSI_CMD                                   }
  158.   {****************************************************************************}
  159.   TSRB_ExecSCSICmd = packed record
  160.     Cmd, // ASPI command code = SC_EXEC_SCSI_CMD
  161.     Status, // ASPI command status byte
  162.     HaId, // ASPI host adapter number
  163.     Flags: BYTE; // ASPI request flags
  164.     Hdr_Rsvd: DWORD; // Reserved
  165.     Target, // Target's SCSI ID
  166.     Lun: BYTE; // Target's LUN number
  167.     Rsvd1: WORD; // Reserved for Alignment
  168.     BufLen: DWORD; // Data Allocation Length
  169.     BufPointer: PCHAR; // Data Buffer Pointer
  170.     SenseLen, // Sense Allocation Length
  171.     CDBLen, // CDB Length
  172.     HaStat, // Host Adapter Status
  173.     TargStat: BYTE; // Target Status
  174.     PostProc: THANDLE; // Post routine
  175.     Rsvd2: POINTER; // Reserved
  176.     Rsvd3, // Reserved for alignment
  177.     CDBByte: TCDB; // SCSI CDB
  178.     SenseArea: TSenseArea; // Request Sense buffer
  179.   end;
  180.   PSRB_ExecSCSICmd = ^TSRB_ExecSCSICmd;
  181.   {****************************************************************************}
  182.   {  ABORT AN SRB - SC_ABORT_SRB                                               }
  183.   {****************************************************************************}
  184.   TSRB_Abort = packed record
  185.     Cmd, // ASPI command code = SC_EXEC_SCSI_CMD
  186.     Status, // ASPI command status byte
  187.     HaId, // ASPI host adapter number
  188.     Flags: BYTE; // Reserved
  189.     Hdr_Rsvd: DWORD; // Reserved
  190.     ToAbort: POINTER; // Pointer to SRB to abort
  191.   end;
  192.   {****************************************************************************}
  193.   {  BUS DEVICE RESET - SC_RESET_DEV                                           }
  194.   {****************************************************************************}
  195.   TSRB_BusDeviceReset = packed record
  196.     Cmd, // ASPI command code = SC_EXEC_SCSI_CMD
  197.     Status, // ASPI command status byte
  198.     HaId, // ASPI host adapter number
  199.     Flags: BYTE; // Reserved
  200.     Hdr_Rsvd: DWORD; // Reserved
  201.     Target, // Target's SCSI ID
  202.     Lun: BYTE; // Target's LUN number
  203.     Rsvd1: array[0..11] of BYTE; // Reserved for Alignment
  204.     HaStat, // Host Adapter Status
  205.     TargStat: BYTE; // Target Status
  206.     PostProc: THANDLE; // Post routine
  207.     Rsvd2: POINTER; // Reserved
  208.     Rsvd3, // Reserved
  209.     CDBByte: array[0..15] of BYTE; // SCSI CDB
  210.   end;
  211.   {****************************************************************************}
  212.   {  GET DISK INFORMATION - SC_GET_DISK_INFO                                   }
  213.   {****************************************************************************}
  214.   TSRB_GetDiskInfo = packed record
  215.     Cmd, // ASPI command code = SC_EXEC_SCSI_CMD
  216.     Status, // ASPI command status byte
  217.     HaId, // ASPI host adapter number
  218.     Flags: BYTE; // Reserved
  219.     Hdr_Rsvd: DWORD; // Reserved
  220.     Target, // Target's SCSI ID
  221.     Lun, // Target's LUN number
  222.     DriveFlags, // Driver flags
  223.     Int13HDriveInfo, // Host Adapter Status
  224.     Heads, // Preferred number of heads translation
  225.     Sectors: BYTE; // Preferred number of sectors translation
  226.     Rsvd1: array[0..9] of BYTE; // Reserved
  227.   end;
  228.   PSRB_GetDiskInfo = ^TSRB_GetDiskInfo;
  229. const
  230.   {****************************************************************************}
  231.   {  SPTI/IOCTL CONSTANTS                                                      }
  232.   {****************************************************************************}
  233.   (* method codes *)
  234.   METHOD_BUFFERED = 0;
  235.   METHOD_IN_DIRECT = 1;
  236.   METHOD_OUT_DIRECT = 2;
  237.   METHOD_NEITHER = 3;
  238.   (* file access values *)
  239.   FILE_ANY_ACCESS = 0;
  240.   FILE_READ_ACCESS = $0001;
  241.   FILE_WRITE_ACCESS = $0002;
  242.   IOCTL_CDROM_BASE = $00000002;
  243.   IOCTL_SCSI_BASE = $00000004;
  244.   (* constants for DataIn member of SCSI_PASS_THROUGH structures *)
  245.   SCSI_IOCTL_DATA_OUT = 0;
  246.   SCSI_IOCTL_DATA_IN = 1;
  247.   SCSI_IOCTL_DATA_UNSPECIFIED = 2;
  248.   (* standard IOCTL codes *)
  249.   IOCTL_CDROM_READ_TOC = $24000;
  250.   IOCTL_CDROM_GET_LAST_SESSION = $24038;
  251.   IOCTL_SCSI_PASS_THROUGH = $4D004;
  252.   IOCTL_SCSI_MINIPORT = $4D008;
  253.   IOCTL_SCSI_GET_INQUIRY_DATA = $4100C;
  254.   IOCTL_SCSI_GET_CAPABILITIES = $41010;
  255.   IOCTL_SCSI_PASS_THROUGH_DIRECT = $4D014;
  256.   IOCTL_SCSI_GET_ADDRESS = $41018;
  257. type
  258.   {****************************************************************************}
  259.   {  STRUCT DEFINITIONS FOR SPTI                                               }
  260.   {****************************************************************************}
  261.   SCSI_PASS_THROUGH = record
  262.     Length: Word;
  263.     SCSIStatus: Byte;
  264.     PathId: Byte;
  265.     Target: Byte;
  266.     Lun: Byte;
  267.     CDBLength: Byte;
  268.     SenseInfoLength: Byte;
  269.     DataIn: Byte;
  270.     DataTransferLength: ULONG;
  271.     TimeOutValue: ULONG;
  272.     DataBufferOffset: ULONG;
  273.     SenseInfoOffset: ULONG;
  274.     CDB: array[0..16 - 1] of Byte;
  275.   end;
  276.   PSCSI_PASS_THROUGH = ^SCSI_PASS_THROUGH;
  277.   PVOID = Pointer;
  278.   SCSI_PASS_THROUGH_DIRECT = record
  279.     Length: Word;
  280.     SCSIStatus: Byte;
  281.     PathID: Byte;
  282.     Target: Byte;
  283.     Lun: Byte;
  284.     CDBLength: Byte;
  285.     SenseInfoLength: Byte;
  286.     DataIn: Byte;
  287.     DataTransferLength: ULONG;
  288.     TimeOutValue: ULONG;
  289.     DataBuffer: PVOID;
  290.     SenseInfoOffset: ULONG;
  291.     CDB: array[0..16 - 1] of Byte;
  292.   end;
  293.   PSCSI_PASS_THROUGH_DIRECT = ^SCSI_PASS_THROUGH_DIRECT;
  294.   SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER = record
  295.     SPT: SCSI_PASS_THROUGH_DIRECT;
  296.     Filler: ULONG;
  297.     ucSenseBuf: array[0..32 - 1] of Byte;
  298.   end;
  299.   PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER = ^SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
  300.   TSCSIDRIVE = record
  301.     HA, Target, Lun,
  302.       Letter: Byte;
  303.     Used: Boolean;
  304.     DeviceHandle: THANDLE;
  305.     inqData: array[0..64] of Char;
  306.   end;
  307.   TSCSIDRIVES = record
  308.     numAdapters: Byte;
  309.     Drive: array[0..26] of TSCSIDRIVE;
  310.   end;
  311.   (* SCSI ADDRESS HA/TargetID/Lun *)
  312.   SCSI_ADDRESS = record
  313.     Length: LongInt;
  314.     HA: Byte;
  315.     PathID: Byte;
  316.     Target: Byte;
  317.     Lun: Byte;
  318.   end;
  319.   PSCSI_ADDRESS = ^SCSI_ADDRESS;
  320. type
  321.   {****************************************************************************}
  322.   {  VERSION INFO CLASS                                                        }
  323.   {****************************************************************************}
  324.   TVersionInfo = class
  325.   private
  326.     FCompanyName: string;
  327.     FFileDescription: string;
  328.     FFileVersion: string;
  329.     FInternalName: string;
  330.     FLegalCopyright: string;
  331.     FLegalTradeMarks: string;
  332.     FOriginalFilename: string;
  333.     FProductName: string;
  334.     FProductVersion: string;
  335.     FComments: string;
  336.     constructor GetVersionInfo(FileName: string);
  337.   public
  338.     property CompanyName: string read FCompanyName;
  339.     property FileDescription: string read FFileDescription;
  340.     property FileVersion: string read FFileVersion;
  341.     property InternalName: string read FInternalName;
  342.     property LegalCopyright: string read FLegalCopyright;
  343.     property LegalTradeMarks: string read FLegalTradeMarks;
  344.     property OriginalFilename: string read FOriginalFileName;
  345.     property ProductName: string read FProductName;
  346.     property ProductVersion: string read FProductVersion;
  347.     property Comments: string read FComments;
  348.   end;
  349. type
  350.   {****************************************************************************}
  351.   {  SCSI INTERFACE CLASS                                                      }
  352.   {****************************************************************************}
  353.   TInterfaceType = (ifASPI, ifASAPI, ifSPTI);
  354.   TskSCSI = class
  355.   private
  356.     FInitOK: Boolean; // Will be TRUE if Initialization was OK (Handle <> 0)
  357.     FifType: TInterfaceType; // The Type of Interface in Use
  358.     FosName: ShortString; // The Name of the Operating System
  359.     FviASPI: TVersionInfo; // Version Info of ASPI or ASAPI DLL (NIL for SPTI)
  360.   public
  361.     constructor Create;
  362.     destructor Destroy; override;
  363.     function ExecCmd(HaId, Target, Lun: Byte; CDB: TCDB; CDBLen: Cardinal;
  364.       Flags: Cardinal; Buffer: Pointer; BufferLen: Cardinal): Byte;
  365.     function AbortCmd(FSRB_ExecSCSICmd: TSRB_ExecSCSICmd): Boolean;
  366.     function InterfaceNameShort: string;
  367.     function InterfaceNameLong: string;
  368.     function InterfaceDeveloper: string;
  369.     property InitOK: Boolean read FInitOK;
  370.     property InterfaceType: TInterfaceType read FifType;
  371.     property osName: ShortString read FosName;
  372.     property viASPI: TVersionInfo read FviASPI;
  373.     // Version Info of ASPI or ASAPI DLL (NIL for SPTI)
  374.   end;
  375. var
  376.   {****************************************************************************}
  377.   {  PUBLIC VARIABLES                                                          }
  378.   {****************************************************************************}
  379.   // Public to direct use, Named "ASPI", but we use for ASAPI or SPTI too
  380.   GetASPI32SupportInfo: function: DWord; cdecl;
  381.   SendASPI32Command: function(LPSRB: Pointer): DWord; cdecl;
  382. implementation
  383. const
  384.   {****************************************************************************}
  385.   {  CONSTANTS                                                                 }
  386.   {****************************************************************************}
  387.   ASPI = 'wnaspi32.dll';
  388.   ASAPI = 'asapi.dll';
  389.   SPTI = 'skSCSI'; // Dummy for Manager ID and Inquiry Data
  390. var
  391.   {****************************************************************************}
  392.   {  VARIABLES                                                                 }
  393.   {****************************************************************************}
  394.   SCSIHandle: THandle; // DLL Handle if Using ASPI or ASAPI (1 if USING SPTI)
  395.   SCSIDrives: TSCSIDRIVES;
  396.   TGN: Byte = 0;
  397.   inqData: array[0..1024] of Char = SPTI;
  398.   {****************************************************************************}
  399.   {  SPTI COMMANDS BEGIN                                                       }
  400.   {****************************************************************************}
  401. function SPTI_GetASPI32SupportInfo: DWord;
  402. begin
  403.   if SCSIDrives.numAdapters = 0 then
  404.     Result := MAKEWORD(0, SS_NO_ADAPTERS)
  405.   else
  406.     Result := MAKEWORD(SCSIDrives.numAdapters, SS_COMP);
  407. end;
  408. function SPTI_HaInquiry(FPSRB: Pointer): DWord;
  409. var
  410.   PSRB: PSRB_HAInquiry;
  411. begin
  412.   PSRB := FPSRB;
  413.   PSRB.HA_Count := SCSIDrives.numAdapters;
  414.   if PSRB.HaId >= SCSIDrives.numAdapters then
  415.   begin
  416.     PSRB.Status := SS_INVALID_HA;
  417.     Result := SS_INVALID_HA;
  418.     Exit;
  419.   end;
  420.   PSRB.HA_SCSI_ID := 7;
  421.   PSRB.HA_ManagerId := SPTI;
  422.   PSRB.HA_Identifier := 'SPTI  '#0#0#0#0#0#0#0#0#0;
  423.   PSRB.HA_Identifier[5] := Char($30 + PSRB.HaId);
  424.   FillChar(PSRB.HA_Unique, 13, 0);
  425.   PSRB.HA_Unique[0] := #7; // buffer alignment
  426.   PSRB.HA_Unique[3] := #8; // scsi targets
  427.   PSRB.HA_Unique[4] := #00;
  428.   PSRB.HA_Unique[5] := #00;
  429.   PSRB.HA_Unique[6] := #$FF;
  430.   PSRB.Status := SS_COMP;
  431.   Result := SS_COMP;
  432. end;
  433. function SPTI_GetDevIndex(H, T, L: Byte): Byte;
  434. var
  435.   i: Byte;
  436.   Drv: TSCSIDRIVE;
  437. begin
  438.   for i := 2 to 26 do
  439.   begin
  440.     if SCSIDrives.Drive[i].Used then
  441.     begin
  442.       Drv := SCSIDrives.Drive[i];
  443.       if (Drv.Ha = H) and (Drv.Target = T) and (Drv.Lun = L) then
  444.       begin
  445.         Result := i;
  446.         Exit;
  447.       end;
  448.     end
  449.   end;
  450.   Result := 0;
  451. end;
  452. function SPTI_GetDevType(FPSRB: Pointer): DWord;
  453. var
  454.   PSRB: PSRB_GDEVBlock;
  455. begin
  456.   PSRB := FPSRB;
  457.   PSRB.Status := SS_NO_DEVICE;
  458.   if SPTI_GetDevIndex(PSRB.HaId, PSRB.Target, PSRB.Lun) <> 0 then
  459.     PSRB.Status := SS_COMP;
  460.   if PSRB.Status = SS_COMP then
  461.     PSRB.DeviceType := DTYPE_CDROM
  462.   else
  463.     PSRB.DeviceType := DTYPE_UNKNOWN;
  464.   Result := PSRB.Status;
  465. end;
  466. function SPTI_GetDiskInfo(FPSRB: Pointer): DWord;
  467. var
  468.   PSRB: PSRB_GetDiskInfo;
  469. begin
  470.   PSRB := FPSRB;
  471.   PSRB.Int13HDriveInfo := SPTI_GetDevIndex(PSRB.HaId, PSRB.Target, PSRB.Lun);
  472.   PSRB.Status := SS_COMP;
  473.   Result := SS_COMP;
  474. end;
  475. function SPTI_GetDriveHandle(i: Byte): LongWord;
  476. var
  477.   Path: string;
  478. begin
  479.   Path := '\.' + Char(i + 65) + ':'#0;
  480.   Result := CreateFile(@Path[1], GENERIC_WRITE or GENERIC_READ, FILE_SHARE_READ
  481.     or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  482.   if Result = INVALID_HANDLE_VALUE then
  483.     Result := CreateFile(@Path[1], GENERIC_READ, FILE_SHARE_READ, nil,
  484.       OPEN_EXISTING, 0, 0);
  485. end;
  486. function SPTI_SendASPI32Command_Internal(PSRB: PSRB_ExecSCSICmd; Again:
  487.   Boolean): DWord;
  488. var
  489.   Status: Boolean;
  490.   SPTI_WBUFFER: SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
  491.   Length, Returned: Cardinal;
  492.   Index: Byte;
  493. label
  494.   ExecSCSICmd;
  495. begin
  496.   if PSRB = nil then
  497.   begin
  498.     Result := SS_ERR;
  499.     Exit;
  500.   end;
  501.   case PSRB^.Cmd of
  502.     SC_EXEC_SCSI_CMD:
  503.       goto ExecSCSICmd;
  504.     SC_HA_INQUIRY:
  505.       begin
  506.         Result := SPTI_HaInquiry(PSRB);
  507.         Exit;
  508.       end;
  509.     SC_GET_DEV_TYPE:
  510.       begin
  511.         Result := SPTI_GetDevType(PSRB);
  512.         Exit;
  513.       end;
  514.     SC_GET_DISK_INFO:
  515.       begin
  516.         Result := SPTI_GetDiskInfo(PSRB);
  517.         Exit;
  518.       end;
  519.   else
  520.     begin
  521.       PSRB^.Status := SS_ERR;
  522.       Result := SS_ERR;
  523.       Exit;
  524.     end;
  525.   end;
  526.   ExecSCSICmd:
  527.   Index := SPTI_GetDevIndex(PSRB^.HaId, PSRB^.Target, PSRB^.Lun);
  528.   if Index = 0 then
  529.   begin
  530.     PSRB^.Status := SS_NO_DEVICE;
  531.     Result := SS_NO_DEVICE;
  532.     Exit;
  533.   end;
  534.   if PSRB^.CDBByte[0] = SC_SCSI_INQUIRY then
  535.   begin
  536.     if PSRB^.HaId >= SCSIDrives.numAdapters then
  537.     begin
  538.       PSRB^.Status := SS_INVALID_HA;
  539.       Result := SS_INVALID_HA;
  540.       Exit;
  541.     end;
  542.     PSRB^.Status := SS_COMP;
  543.     Move(SCSIDrives.Drive[Index].inqData, PSRB^.BufPointer[0], 36);
  544.     Result := SS_COMP;
  545.     Exit;
  546.   end;
  547.   if (SCSIDrives.Drive[Index].DeviceHandle = INVALID_HANDLE_VALUE) then
  548.     SCSIDrives.Drive[Index].DeviceHandle :=
  549.       SPTI_GetDriveHandle(SCSIDrives.Drive[Index].Letter);
  550.   FillChar(SPTI_WBUFFER, SizeOf(SPTI_WBUFFER), 0);
  551.   if PSRB^.Flags and SRB_DIR_IN <> 0 then
  552.     SPTI_WBUFFER.SPT.DataIn := SCSI_IOCTL_DATA_IN
  553.   else if PSRB^.Flags and SRB_DIR_OUT <> 0 then
  554.     SPTI_WBUFFER.SPT.DataIn := SCSI_IOCTL_DATA_OUT
  555.   else
  556.     SPTI_WBUFFER.SPT.DataIn := SCSI_IOCTL_DATA_UNSPECIFIED;
  557.   with SPTI_WBUFFER.SPT do
  558.   begin
  559.     Length := SizeOf(SCSI_PASS_THROUGH_DIRECT);
  560.     CdbLength := PSRB^.CDBLen;
  561.     SenseInfoLength := PSRB^.SenseLen;
  562.     DataTransferLength := PSRB^.BufLen;
  563.     TimeOutValue := 120;
  564.     DataBuffer := PSRB^.BufPointer;
  565.     SenseInfoOffset := 48;
  566.   end;
  567.   Move(PSRB^.CDBByte[0], SPTI_WBUFFER.SPT.CDB, PSRB^.CDBLen);
  568.   Length := SizeOf(SPTI_WBUFFER);
  569.   Status := DeviceIoControl(SCSIDrives.Drive[Index].DeviceHandle,
  570.     IOCTL_SCSI_PASS_THROUGH_DIRECT, @SPTI_WBUFFER, Length, @SPTI_WBUFFER,
  571.       Length,
  572.     Returned, nil);
  573.   if ((SPTI_WBUFFER.SPT.SenseInfoLength = 0) or (SPTI_WBUFFER.SPT.SenseInfoLength
  574.     = 32))
  575.     and (SPTI_WBUFFER.SPT.SCSIStatus = 0) and Status then
  576.     PSRB^.Status := SS_COMP
  577.   else
  578.   begin
  579.     PSRB^.Status := SS_ERR;
  580.     Move(SPTI_WBUFFER.ucSenseBuf, PSRB^.SenseArea,
  581.       SPTI_WBUFFER.SPT.SenseInfoLength);
  582.     PSRB^.TargStat := SPTI_WBUFFER.SPT.SCSIStatus;
  583.   end;
  584.   if SCSIDrives.Drive[Index].DeviceHandle <> INVALID_HANDLE_VALUE then
  585.   begin
  586.     if CloseHandle(SCSIDrives.Drive[Index].DeviceHandle) then
  587.       SCSIDrives.Drive[Index].DeviceHandle := INVALID_HANDLE_VALUE;
  588.   end;
  589.   Result := PSRB^.Status;
  590. end;
  591. function SPTI_SendASPI32Command(PSRB: PSRB_ExecSCSICmd): DWord;
  592. begin
  593.   Result := SPTI_SendASPI32Command_Internal(PSRB, False);
  594. end;
  595. procedure SPTI_GetDriveInfo(i: Byte; var pDrive: TSCSIDRIVE);
  596. var
  597.   Handle: THandle;
  598.   Buffer: array[0..1023] of Char;
  599.   P_SCSI_WBUFFER: PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
  600.   P_SCSI_ADDRESS: PSCSI_ADDRESS;
  601.   Length, Returned: Cardinal;
  602.   Status: Boolean;
  603. begin
  604.   Handle := SPTI_GetDriveHandle(i);
  605.   if (Handle = INVALID_HANDLE_VALUE) then
  606.     Exit;
  607.   ZeroMemory(@Buffer, 1024);
  608.   ZeroMemory(@inqData, SizeOf(inqData));
  609.   P_SCSI_WBUFFER := @Buffer;
  610.   with P_SCSI_WBUFFER.SPT do
  611.   begin
  612.     Length := SizeOf(SCSI_PASS_THROUGH);
  613.     CDBLength := 6;
  614.     SenseInfoLength := 24;
  615.     DataIn := SCSI_IOCTL_DATA_IN;
  616.     DataTransferLength := 96;
  617.     TimeOutValue := 120;
  618.     DataBuffer := @inqData;
  619.     SenseInfoOffset := 48;
  620.     CDB[0] := SC_SCSI_INQUIRY;
  621.     CDB[4] := 96;
  622.   end;
  623.   Length := SizeOf(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
  624.   Status := DeviceIoControl(Handle, IOCTL_SCSI_PASS_THROUGH_DIRECT,
  625.     P_SCSI_WBUFFER, Length, P_SCSI_WBUFFER, Length, Returned, nil);
  626.   if not Status then
  627.   begin
  628.     CloseHandle(Handle);
  629.     Exit;
  630.   end;
  631.   Move(inqData, pDrive.inqData, 40);
  632.   FillChar(Buffer, Sizeof(Buffer), 0);
  633.   P_SCSI_ADDRESS := @Buffer;
  634.   P_SCSI_ADDRESS.Length := SizeOf(SCSI_ADDRESS);
  635.   if DeviceIoControl(Handle, IOCTL_SCSI_GET_ADDRESS, nil, 0, P_SCSI_ADDRESS,
  636.     SizeOf(SCSI_ADDRESS), Returned, nil) then
  637.   begin
  638.     pDrive.Used := True;
  639.     pDrive.Ha := P_SCSI_ADDRESS.Ha;
  640.     pDrive.Target := P_SCSI_ADDRESS.Target;
  641.     pDrive.Lun := P_SCSI_ADDRESS.Lun;
  642.     pDrive.Letter := i;
  643.     pDrive.DeviceHandle := INVALID_HANDLE_VALUE;
  644.   end
  645.   else
  646.   begin
  647.     pDrive.Used := True;
  648.     pDrive.Ha := 0;
  649.     pDrive.Target := TGN;
  650.     pDrive.Lun := 250;
  651.     pDrive.Letter := i;
  652.     pDrive.DeviceHandle := INVALID_HANDLE_VALUE;
  653.     Inc(TGN);
  654.   end;
  655.   CloseHandle(Handle);
  656. end;
  657. function SPTI_GetNumAdapters: Byte;
  658. var
  659.   i, numAdapters: Byte;
  660. begin
  661.   numAdapters := 0;
  662.   for i := 1 to 26 do
  663.   begin
  664.     if numAdapters < SCSIDrives.Drive[i].Ha then
  665.       numAdapters := SCSIDrives.Drive[i].Ha;
  666.   end;
  667.   Inc(numAdapters);
  668.   Result := numAdapters;
  669.   Exit;
  670. end;
  671. function InitSPTI: Byte;
  672. var
  673.   s: string;
  674.   i, uDriveType, Return: Byte;
  675. begin
  676.   Return := 0;
  677.   TGN := 0;
  678.   FillChar(SCSIDrives, SizeOf(SCSIDrives), 0);
  679.   for i := 2 to 26 do
  680.     SCSIDrives.Drive[i].DeviceHandle := INVALID_HANDLE_VALUE;
  681.   for i := 2 to 26 do
  682.   begin
  683.     s := Char(65 + i) + ':';
  684.     uDriveType := GetDriveType(@s[1]);
  685.     if uDriveType = DRIVE_CDROM then
  686.     begin
  687.       SPTI_GetDriveInfo(i, SCSIDrives.Drive[i]);
  688.       if SCSIDrives.Drive[i].Used then
  689.         Inc(Return);
  690.     end;
  691.   end;
  692.   SCSIDrives.numAdapters := SPTI_GetNumAdapters;
  693.   if TGN <> 0 then
  694.   begin
  695.     for i := 2 to 26 do
  696.     begin
  697.       if SCSIDrives.Drive[i].Used then
  698.         if ScsiDrives.drive[i].Lun = 250 then
  699.         begin
  700.           SCSIDrives.Drive[i].Lun := 0;
  701.           SCSIDrives.Drive[i].Ha := SCSIDrives.numAdapters;
  702.         end;
  703.     end;
  704.     SCSIDrives.numAdapters := SPTI_GetNumAdapters;
  705.   end;
  706.   Result := Return;
  707. end;
  708. function DeInitSPTI: Integer;
  709. var
  710.   i: integer;
  711. begin
  712.   for i := 2 to 26 do
  713.     if (SCSIDrives.Drive[i].Used) then
  714.       if SCSIDrives.Drive[i].DeviceHandle <> INVALID_HANDLE_VALUE then
  715.         CloseHandle(SCSIDrives.Drive[i].DeviceHandle);
  716.   SCSIDrives.numAdapters := SPTI_GetNumAdapters();
  717.   FillChar(SCSIDrives, SizeOf(SCSIDrives), 0);
  718.   Result := -1;
  719. end;
  720. {******************************************************************************}
  721. {  GetVersionInfo to Determine the Currently Using ASPI/ASAPI Layer's Version  }
  722. {******************************************************************************}
  723. constructor TVersionInfo.GetVersionInfo(FileName: string);
  724. type
  725.   TTranslation = record
  726.     LangID, Charset: Word;
  727.   end;
  728. var
  729.   VerInfo: Pointer;
  730.   VerInfoSize, Dummy: DWord;
  731.   VerValue: Pointer;
  732.   VerValueSize: DWord;
  733.   VerTrans: TTranslation;
  734.   Lang, From: string;
  735.   function GetValue(Value: string): string;
  736.   begin
  737.     if VerQueryValue(VerInfo, PChar(From + Value), VerValue, VerValueSize) then
  738.       Result := PChar(VerValue)
  739.     else
  740.       Result := '';
  741.   end;
  742. begin
  743.   inherited Create;
  744.   VerInfoSize := GetFileVersionInfoSize(PChar(FileName), Dummy);
  745.   GetMem(VerInfo, VerInfoSize);
  746.   if GetFileVersionInfo(PChar(FileName), 0, VerInfoSize, VerInfo) then
  747.   begin
  748.     VerQueryValue(VerInfo, 'VarFileInfoTranslation', VerValue, VerValueSize);
  749.     Move(VerValue^, VerTrans, VerValueSize);
  750.     Lang := IntToHex(VerTrans.LangID, 4) + IntToHex(VerTrans.Charset, 4);
  751.     From := 'StringFileInfo' + Lang + '';
  752.     FCompanyName := GetValue('CompanyName');
  753.     FFileDescription := GetValue('FileDescription');
  754.     FFileVersion := GetValue('FileVersion');
  755.     FInternalName := GetValue('InternalName');
  756.     FLegalCopyright := GetValue('LegalCopyright');
  757.     FLegalTradeMarks := GetValue('LegalTrademarks');
  758.     FOriginalFilename := GetValue('OriginalFilename');
  759.     FProductName := GetValue('ProductName');
  760.     FProductVersion := GetValue('ProductVersion');
  761.     FComments := GetValue('Comments');
  762.     MessageBox(0, PChar(FFileVersion), '', MB_ICONINFORMATION);
  763.   end;
  764.   FreeMem(VerInfo);
  765. end;
  766. {******************************************************************************}
  767. {  GET THE PLATFORM AND EXACT, NAME, VERSION AND BUID OF THE CURRENT OS        }
  768. {******************************************************************************}
  769. function GetOS(var osName: string): DWord;
  770. var
  771.   OS: TOSVersionInfo;
  772.   dwMM: array[0..1] of DWord;
  773.   szMM: array[0..511] of Char;
  774.   Build, Ver, SP: string;
  775. begin
  776.   ZeroMemory(@OS, SizeOf(OS));
  777.   OS.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
  778.   GetVersionEx(OS);
  779.   Result := OS.dwPlatformId;
  780.   dwMM[0] := OS.dwMajorVersion;
  781.   dwMM[1] := OS.dwMinorVersion;
  782.   wvsprintf(szMM, '%d.%d', PChar(@dwMM));
  783.   if OS.dwPlatformId = VER_PLATFORM_WIN32_NT then
  784.     Build := IntToHex(OS.dwBuildNumber, 4)
  785.   else
  786.     Build := IntToHex(Word(OS.dwBuildNumber), 4);
  787.   Ver := ' (' + szMM + '.' + Build + ')';
  788.   if OS.szCSDVersion <> '' then
  789.     SP := ' ' + OS.szCSDVersion;
  790.   // Default for Unknown or Newest Windows Versions
  791.   osName := 'Windows' + SP + Ver;
  792.   // Try to Determine Known OS Names and Versions
  793.   case OS.dwPlatformId of
  794.     VER_PLATFORM_WIN32s: osName := 'Windows 3.1' + Ver;
  795.     VER_PLATFORM_WIN32_WINDOWS:
  796.       case OS.dwMinorVersion of
  797.         0:
  798.           if OS.szCSDVersion = ' C' then
  799.             osName := 'Windows 95 OSR2' + Ver
  800.           else
  801.             osName := 'Windows 95' + Ver;
  802.         10:
  803.           if OS.szCSDVersion = ' A' then
  804.             osName := 'Windows 98 SE' + Ver
  805.           else
  806.             osName := 'Windows 98' + Ver;
  807.         90: osName := 'Windows Me' + Ver;
  808.       end;
  809.     VER_PLATFORM_WIN32_NT:
  810.       case OS.dwMajorVersion of
  811.         3 or 4: osName := 'Windows NT ' + IntToHex(OS.dwMajorVersion, 8) + SP +
  812.           Ver;
  813.         5: case OS.dwMinorVersion of
  814.             0: osName := 'Windows 2000' + SP + Ver;
  815.             1: osName := 'Windows XP' + SP + Ver;
  816.             2: osName := 'Windows Server 2003' + SP + Ver;
  817.           end;
  818.       end;
  819.   end;
  820. end;
  821. {******************************************************************************}
  822. {  EXECUTES A SCSI COMMAND                                                     }
  823. {******************************************************************************}
  824. function TskSCSI.ExecCmd(HaId, Target, Lun: Byte; CDB: TCDB; CDBLen: Cardinal;
  825.   Flags: Cardinal; Buffer: Pointer; BufferLen: Cardinal): Byte;
  826. var
  827.   SRB_ExecSCSICmd: TSRB_ExecSCSICmd;
  828.   SRBPointer: PSRB_ExecSCSICmd;
  829.   FEvent: THandle;
  830.   EventNotify: Boolean;
  831. begin
  832.   FillChar(SRB_ExecSCSICmd, SizeOf(SRB_ExecSCSICmd), 0);
  833.   EventNotify := Flags and $40 = $40;
  834.   FEvent := CreateEvent(nil, True, False, nil);
  835.   if EventNotify then
  836.   begin
  837.     ResetEvent(FEvent);
  838.     SRB_ExecSCSICmd.PostProc := FEvent
  839.   end
  840.   else
  841.     SRB_ExecSCSICmd.PostProc := 0;
  842.   SRB_ExecSCSICmd.Cmd := SC_EXEC_SCSI_CMD;
  843.   SRB_ExecSCSICmd.Flags := Flags;
  844.   SRB_ExecSCSICmd.HaId := HaId;
  845.   SRB_ExecSCSICmd.Target := Target;
  846.   SRB_ExecSCSICmd.Lun := Lun;
  847.   SRB_ExecSCSICmd.BufLen := BufferLen;
  848.   SRB_ExecSCSICmd.BufPointer := Buffer;
  849.   SRB_ExecSCSICmd.SenseLen := SENSE_LEN;
  850.   SRB_ExecSCSICmd.CDBLen := CDBLen;
  851.   SRB_ExecSCSICmd.CDBByte := CDB;
  852.   { for i := 0 to CDBLen - 1 do
  853.       CDBByte[i] := CDB[i];}
  854.   SRB_ExecSCSICmd.CDBByte[1] := ((Lun and 7) shl 5) or
  855.     (SRB_ExecSCSICmd.CDBByte[1] and $1F);
  856.   SRBPointer := @SRB_ExecSCSICmd;
  857.   if SRB_ExecSCSICmd.CDBByte[0] <> $FF then
  858.     SendASPI32Command(SRBPointer)
  859.   else
  860.     SRB_ExecSCSICmd.Status := SS_COMP;
  861.   if EventNotify then
  862.   begin
  863.     if SRB_ExecSCSICmd.Status = SS_PENDING then
  864.       WaitForSingleObject(FEvent, INFINITE);
  865.   end;
  866.   if SRB_ExecSCSICmd.Status = SS_PENDING then
  867.   begin
  868.     if EventNotify then
  869.     begin
  870.       CloseHandle(FEvent);
  871.       ResetEvent(FEvent);
  872.     end;
  873.     AbortCmd(SRB_ExecSCSICmd);
  874.     SRB_ExecSCSICmd.Status := SS_ERR;
  875.     SRB_ExecSCSICmd.HaStat := HASTAT_TIMEOUT;
  876.   end
  877.   else
  878.   begin
  879.     CloseHandle(FEvent);
  880.   end;
  881.   Result := SRB_ExecSCSICmd.Status;
  882. end;
  883. {******************************************************************************}
  884. {  ABORTS AN EXECUTED SCSI COMMAND                                             }
  885. {******************************************************************************}
  886. function TskSCSI.AbortCmd(FSRB_ExecSCSICmd: TSRB_ExecSCSICmd): Boolean;
  887. var
  888.   SRB_Abort: TSRB_Abort;
  889. begin
  890.   FillChar(SRB_Abort, SizeOf(TSRB_Abort), 0);
  891.   with SRB_Abort do
  892.   begin
  893.     Cmd := SC_ABORT_SRB;
  894.     HaId := FSRB_ExecSCSICmd.HaId;
  895.     ToAbort := @FSRB_ExecSCSICmd;
  896.   end;
  897.   Result := SRB_Abort.Status = 1;
  898. end;
  899. {******************************************************************************}
  900. {  INTERFACE INFORMATION ROUTINES                                              }
  901. {******************************************************************************}
  902. function TskSCSI.InterfaceNameShort: string;
  903. begin
  904.   case FifType of
  905.     ifASPI: Result := 'ASPI';
  906.     ifASAPI: Result := 'ASAPI';
  907.     ifSPTI: Result := 'SPTI';
  908.   end;
  909. end;
  910. function TskSCSI.InterfaceNameLong: string;
  911. begin
  912.   case FifType of
  913.     ifASPI: Result := 'Advanced SCSI Programming Interface';
  914.     ifASAPI: Result := 'Advanced ASPI Programming Interface';
  915.     ifSPTI: Result := 'SCSI Passthrough Interface';
  916.   end;
  917. end;
  918. function TskSCSI.InterfaceDeveloper: string;
  919. begin
  920.   case FifType of
  921.     ifASPI: Result := 'Adaptec';
  922.     ifASAPI: Result := 'VOB/Pinnacle';
  923.     ifSPTI: Result := 'Microsoft';
  924.   end;
  925. end;
  926. {******************************************************************************}
  927. {  CONSTRUCTOR (LOAD ASPI OR ASAPI DLL OR USE SPTI UNDER NT/2K/XP)             }
  928. {******************************************************************************}
  929. constructor TskSCSI.Create;
  930. var
  931.   dwPlatformID: DWord;
  932.   osName: string;
  933. begin
  934.   inherited Create;
  935.   SCSIHandle := 0;
  936.   FviASPI := nil;
  937.   dwPlatformID := GetOS(osName);
  938.   FosName := osName;
  939.   (* if NT/2k/XP/2003 then use SPTI *)
  940.   if dwPlatformID = VER_PLATFORM_WIN32_NT then
  941.   begin
  942.     InitSPTI;
  943.     SCSIHandle := 1;
  944.     FifType := ifSPTI;
  945.     @GetASPI32SupportInfo := @SPTI_GetASPI32SupportInfo;
  946.     @SendASPI32Command := @SPTI_SendASPI32Command;
  947.   end;
  948.   (* if 9x/Me then use ASPI or ASAPI if any *)
  949.   if dwPlatformId = VER_PLATFORM_WIN32_WINDOWS then
  950.   begin
  951.     (* 1st try to initalize ASPI ... *)
  952.     SCSIHandle := LoadLibrary(ASPI);
  953.     if SCSIHandle <> 0 then
  954.     begin
  955.       @GetASPI32SupportInfo := GetProcAddress(SCSIHandle,
  956.         'GetASPI32SupportInfo');
  957.       @SendASPI32Command := GetProcAddress(SCSIHandle, 'SendASPI32Command');
  958.       FviASPI := TVersionInfo.GetVersionInfo(ASPI);
  959.       FifType := ifASPI;
  960.     end
  961.     else
  962.     begin
  963.       (* ... 2nd try to initalize ASAPI *)
  964.       SCSIHandle := LoadLibrary(ASAPI);
  965.       if SCSIHandle <> 0 then
  966.       begin
  967.         @GetASPI32SupportInfo := GetProcAddress(SCSIHandle,
  968.           'GetASAPI32SupportInfo');
  969.         @SendASPI32Command := GetProcAddress(SCSIHandle, 'SendASAPI32Command');
  970.         FviASPI := TVersionInfo.GetVersionInfo(ASAPI);
  971.         FifType := ifASAPI;
  972.       end;
  973.     end;
  974.   end;
  975.   if SCSIHandle <> 0 then
  976.     FInitOK := True;
  977. end;
  978. {******************************************************************************}
  979. {  DESTRUCTOR                                                                  }
  980. {******************************************************************************}
  981. destructor TskSCSI.Destroy;
  982. begin
  983.   if FifType = ifSPTI then
  984.     DeInitSPTI;
  985.   inherited Destroy;
  986. end;
  987. end.