📄 skscsi.pas
字号:
private
FCompanyName: string;
FFileDescription: string;
FFileVersion: string;
FInternalName: string;
FLegalCopyright: string;
FLegalTradeMarks: string;
FOriginalFilename: string;
FProductName: string;
FProductVersion: string;
FComments: string;
constructor GetVersionInfo(FileName: string);
public
property CompanyName: string read FCompanyName;
property FileDescription: string read FFileDescription;
property FileVersion: string read FFileVersion;
property InternalName: string read FInternalName;
property LegalCopyright: string read FLegalCopyright;
property LegalTradeMarks: string read FLegalTradeMarks;
property OriginalFilename: string read FOriginalFileName;
property ProductName: string read FProductName;
property ProductVersion: string read FProductVersion;
property Comments: string read FComments;
end;
type
{****************************************************************************}
{ SCSI INTERFACE CLASS }
{****************************************************************************}
TInterfaceType = (ifASPI, ifASAPI, ifSPTI);
TskSCSI = class
private
FInitOK: Boolean; // Will be TRUE if Initialization was OK (Handle <> 0)
FifType: TInterfaceType; // The Type of Interface in Use
FosName: ShortString; // The Name of the Operating System
FviASPI: TVersionInfo; // Version Info of ASPI or ASAPI DLL (NIL for SPTI)
public
constructor Create;
destructor Destroy; override;
function ExecCmd(HaId, Target, Lun: Byte; CDB: TCDB; CDBLen: Cardinal;
Flags: Cardinal; Buffer: Pointer; BufferLen: Cardinal): Byte;
function AbortCmd(FSRB_ExecSCSICmd: TSRB_ExecSCSICmd): Boolean;
function InterfaceNameShort: string;
function InterfaceNameLong: string;
function InterfaceDeveloper: string;
property InitOK: Boolean read FInitOK;
property InterfaceType: TInterfaceType read FifType;
property osName: ShortString read FosName;
property viASPI: TVersionInfo read FviASPI;
// Version Info of ASPI or ASAPI DLL (NIL for SPTI)
end;
var
{****************************************************************************}
{ PUBLIC VARIABLES }
{****************************************************************************}
// Public to direct use, Named "ASPI", but we use for ASAPI or SPTI too
GetASPI32SupportInfo: function: DWord; cdecl;
SendASPI32Command: function(LPSRB: Pointer): DWord; cdecl;
implementation
const
{****************************************************************************}
{ CONSTANTS }
{****************************************************************************}
ASPI = 'wnaspi32.dll';
ASAPI = 'asapi.dll';
SPTI = 'skSCSI'; // Dummy for Manager ID and Inquiry Data
var
{****************************************************************************}
{ VARIABLES }
{****************************************************************************}
SCSIHandle: THandle; // DLL Handle if Using ASPI or ASAPI (1 if USING SPTI)
SCSIDrives: TSCSIDRIVES;
TGN: Byte = 0;
inqData: array[0..1024] of Char = SPTI;
{****************************************************************************}
{ SPTI COMMANDS BEGIN }
{****************************************************************************}
function SPTI_GetASPI32SupportInfo: DWord;
begin
if SCSIDrives.numAdapters = 0 then
Result := MAKEWORD(0, SS_NO_ADAPTERS)
else
Result := MAKEWORD(SCSIDrives.numAdapters, SS_COMP);
end;
function SPTI_HaInquiry(FPSRB: Pointer): DWord;
var
PSRB: PSRB_HAInquiry;
begin
PSRB := FPSRB;
PSRB.HA_Count := SCSIDrives.numAdapters;
if PSRB.HaId >= SCSIDrives.numAdapters then
begin
PSRB.Status := SS_INVALID_HA;
Result := SS_INVALID_HA;
Exit;
end;
PSRB.HA_SCSI_ID := 7;
PSRB.HA_ManagerId := SPTI;
PSRB.HA_Identifier := 'SPTI '#0#0#0#0#0#0#0#0#0;
PSRB.HA_Identifier[5] := Char($30 + PSRB.HaId);
FillChar(PSRB.HA_Unique, 13, 0);
PSRB.HA_Unique[0] := #7; // buffer alignment
PSRB.HA_Unique[3] := #8; // scsi targets
PSRB.HA_Unique[4] := #00;
PSRB.HA_Unique[5] := #00;
PSRB.HA_Unique[6] := #$FF;
PSRB.Status := SS_COMP;
Result := SS_COMP;
end;
function SPTI_GetDevIndex(H, T, L: Byte): Byte;
var
i: Byte;
Drv: TSCSIDRIVE;
begin
for i := 2 to 26 do
begin
if SCSIDrives.Drive[i].Used then
begin
Drv := SCSIDrives.Drive[i];
if (Drv.Ha = H) and (Drv.Target = T) and (Drv.Lun = L) then
begin
Result := i;
Exit;
end;
end
end;
Result := 0;
end;
function SPTI_GetDevType(FPSRB: Pointer): DWord;
var
PSRB: PSRB_GDEVBlock;
begin
PSRB := FPSRB;
PSRB.Status := SS_NO_DEVICE;
if SPTI_GetDevIndex(PSRB.HaId, PSRB.Target, PSRB.Lun) <> 0 then
PSRB.Status := SS_COMP;
if PSRB.Status = SS_COMP then
PSRB.DeviceType := DTYPE_CDROM
else
PSRB.DeviceType := DTYPE_UNKNOWN;
Result := PSRB.Status;
end;
function SPTI_GetDiskInfo(FPSRB: Pointer): DWord;
var
PSRB: PSRB_GetDiskInfo;
begin
PSRB := FPSRB;
PSRB.Int13HDriveInfo := SPTI_GetDevIndex(PSRB.HaId, PSRB.Target, PSRB.Lun);
PSRB.Status := SS_COMP;
Result := SS_COMP;
end;
function SPTI_GetDriveHandle(i: Byte): LongWord;
var
Path: string;
begin
Path := '\\.\' + Char(i + 65) + ':'#0;
Result := CreateFile(@Path[1], GENERIC_WRITE or GENERIC_READ, FILE_SHARE_READ
or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if Result = INVALID_HANDLE_VALUE then
Result := CreateFile(@Path[1], GENERIC_READ, FILE_SHARE_READ, nil,
OPEN_EXISTING, 0, 0);
end;
function SPTI_SendASPI32Command_Internal(PSRB: PSRB_ExecSCSICmd; Again:
Boolean): DWord;
var
Status: Boolean;
SPTI_WBUFFER: SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
Length, Returned: Cardinal;
Index: Byte;
label
ExecSCSICmd;
begin
if PSRB = nil then
begin
Result := SS_ERR;
Exit;
end;
case PSRB^.Cmd of
SC_EXEC_SCSI_CMD:
goto ExecSCSICmd;
SC_HA_INQUIRY:
begin
Result := SPTI_HaInquiry(PSRB);
Exit;
end;
SC_GET_DEV_TYPE:
begin
Result := SPTI_GetDevType(PSRB);
Exit;
end;
SC_GET_DISK_INFO:
begin
Result := SPTI_GetDiskInfo(PSRB);
Exit;
end;
else
begin
PSRB^.Status := SS_ERR;
Result := SS_ERR;
Exit;
end;
end;
ExecSCSICmd:
Index := SPTI_GetDevIndex(PSRB^.HaId, PSRB^.Target, PSRB^.Lun);
if Index = 0 then
begin
PSRB^.Status := SS_NO_DEVICE;
Result := SS_NO_DEVICE;
Exit;
end;
if PSRB^.CDBByte[0] = SC_SCSI_INQUIRY then
begin
if PSRB^.HaId >= SCSIDrives.numAdapters then
begin
PSRB^.Status := SS_INVALID_HA;
Result := SS_INVALID_HA;
Exit;
end;
PSRB^.Status := SS_COMP;
Move(SCSIDrives.Drive[Index].inqData, PSRB^.BufPointer[0], 36);
Result := SS_COMP;
Exit;
end;
if (SCSIDrives.Drive[Index].DeviceHandle = INVALID_HANDLE_VALUE) then
SCSIDrives.Drive[Index].DeviceHandle :=
SPTI_GetDriveHandle(SCSIDrives.Drive[Index].Letter);
FillChar(SPTI_WBUFFER, SizeOf(SPTI_WBUFFER), 0);
if PSRB^.Flags and SRB_DIR_IN <> 0 then
SPTI_WBUFFER.SPT.DataIn := SCSI_IOCTL_DATA_IN
else if PSRB^.Flags and SRB_DIR_OUT <> 0 then
SPTI_WBUFFER.SPT.DataIn := SCSI_IOCTL_DATA_OUT
else
SPTI_WBUFFER.SPT.DataIn := SCSI_IOCTL_DATA_UNSPECIFIED;
with SPTI_WBUFFER.SPT do
begin
Length := SizeOf(SCSI_PASS_THROUGH_DIRECT);
CdbLength := PSRB^.CDBLen;
SenseInfoLength := PSRB^.SenseLen;
DataTransferLength := PSRB^.BufLen;
TimeOutValue := 120;
DataBuffer := PSRB^.BufPointer;
SenseInfoOffset := 48;
end;
Move(PSRB^.CDBByte[0], SPTI_WBUFFER.SPT.CDB, PSRB^.CDBLen);
Length := SizeOf(SPTI_WBUFFER);
Status := DeviceIoControl(SCSIDrives.Drive[Index].DeviceHandle,
IOCTL_SCSI_PASS_THROUGH_DIRECT, @SPTI_WBUFFER, Length, @SPTI_WBUFFER,
Length,
Returned, nil);
if ((SPTI_WBUFFER.SPT.SenseInfoLength = 0) or (SPTI_WBUFFER.SPT.SenseInfoLength
= 32))
and (SPTI_WBUFFER.SPT.SCSIStatus = 0) and Status then
PSRB^.Status := SS_COMP
else
begin
PSRB^.Status := SS_ERR;
Move(SPTI_WBUFFER.ucSenseBuf, PSRB^.SenseArea,
SPTI_WBUFFER.SPT.SenseInfoLength);
PSRB^.TargStat := SPTI_WBUFFER.SPT.SCSIStatus;
end;
if SCSIDrives.Drive[Index].DeviceHandle <> INVALID_HANDLE_VALUE then
begin
if CloseHandle(SCSIDrives.Drive[Index].DeviceHandle) then
SCSIDrives.Drive[Index].DeviceHandle := INVALID_HANDLE_VALUE;
end;
Result := PSRB^.Status;
end;
function SPTI_SendASPI32Command(PSRB: PSRB_ExecSCSICmd): DWord;
begin
Result := SPTI_SendASPI32Command_Internal(PSRB, False);
end;
procedure SPTI_GetDriveInfo(i: Byte; var pDrive: TSCSIDRIVE);
var
Handle: THandle;
Buffer: array[0..1023] of Char;
P_SCSI_WBUFFER: PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER;
P_SCSI_ADDRESS: PSCSI_ADDRESS;
Length, Returned: Cardinal;
Status: Boolean;
begin
Handle := SPTI_GetDriveHandle(i);
if (Handle = INVALID_HANDLE_VALUE) then
Exit;
ZeroMemory(@Buffer, 1024);
ZeroMemory(@inqData, SizeOf(inqData));
P_SCSI_WBUFFER := @Buffer;
with P_SCSI_WBUFFER.SPT do
begin
Length := SizeOf(SCSI_PASS_THROUGH);
CDBLength := 6;
SenseInfoLength := 24;
DataIn := SCSI_IOCTL_DATA_IN;
DataTransferLength := 96;
TimeOutValue := 120;
DataBuffer := @inqData;
SenseInfoOffset := 48;
CDB[0] := SC_SCSI_INQUIRY;
CDB[4] := 96;
end;
Length := SizeOf(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
Status := DeviceIoControl(Handle, IOCTL_SCSI_PASS_THROUGH_DIRECT,
P_SCSI_WBUFFER, Length, P_SCSI_WBUFFER, Length, Returned, nil);
if not Status then
begin
CloseHandle(Handle);
Exit;
end;
Move(inqData, pDrive.inqData, 40);
FillChar(Buffer, Sizeof(Buffer), 0);
P_SCSI_ADDRESS := @Buffer;
P_SCSI_ADDRESS.Length := SizeOf(SCSI_ADDRESS);
if DeviceIoControl(Handle, IOCTL_SCSI_GET_ADDRESS, nil, 0, P_SCSI_ADDRESS,
SizeOf(SCSI_ADDRESS), Returned, nil) then
begin
pDrive.Used := True;
pDrive.Ha := P_SCSI_ADDRESS.Ha;
pDrive.Target := P_SCSI_ADDRESS.Target;
pDrive.Lun := P_SCSI_ADDRESS.Lun;
pDrive.Letter := i;
pDrive.DeviceHandle := INVALID_HANDLE_VALUE;
end
else
begin
pDrive.Used := True;
pDrive.Ha := 0;
pDrive.Target := TGN;
pDrive.Lun := 250;
pDrive.Letter := i;
pDrive.DeviceHandle := INVALID_HANDLE_VALUE;
Inc(TGN);
end;
CloseHandle(Handle);
end;
function SPTI_GetNumAdapters: Byte;
var
i, numAdapters: Byte;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -