MiTec/Common/MiTeC_WnASPI32.pas

369 lines
15 KiB
ObjectPascal
Raw Normal View History

2024-01-02 00:01:59 +01:00
{*******************************************************}
{ MiTeC Common Routines }
{ Windows ASPI32 }
{ }
{ }
{ Copyright (c) by 1997-2016 Michal Mutl }
{ }
{*******************************************************}
{$INCLUDE Compilers.inc}
unit MiTeC_WnASPI32;
interface
uses {$IFDEF RAD9PLUS}
WinAPI.Windows, System.SysUtils, System.Classes;
{$ELSE}
Windows, SysUtils, Classes;
{$ENDIF}
type
TASPIConfig = record
AdapterCount: integer;
Host,LUN,ID,Vendor,Model,Typ,Status,Extra,Revision: TStringList;
end;
function InitASPI: Boolean;
procedure FreeASPI;
function ExecuteASPI32Test(var ASPIConfig: TASPIConfig): Cardinal;
type
TGetASPI32SupportInfo = function :Cardinal; cdecl;
TSendASPI32Command = function (ASPI32CommandPointer: Pointer): Cardinal; cdecl;
var
GetASPI32SupportInfo: TGetASPI32SupportInfo = nil;
SendASPI32Command: TSendASPI32Command = nil;
const
ASPI_DLL = 'wnaspi32.dll';
// SCSI MISCELLANEOUS EQUATES
MAX_ADAPTER = 16; { Maximum number of adapters supported by ASPI }
MAX_TARGET = 7; { Maximum number of targets per adapter supported by ASPI }
MAX_TARGET_WIDE = 15; { Maximum number of targets per adapter (wide SCSI enabled) supported by ASPI }
MAX_LUN = 64; { Maximum number of logical units supported by ASPI }
SENSE_LEN = 14; { Default sense buffer length }
SRB_DIR_SCSI = $00; { Direction determined by SCSI }
SRB_POSTING = $01; { Enable ASPI posting }
SRB_ENABLE_RESIDUAL_COUNT = $04; { Enable residual byte count reporting }
SRB_DIR_IN = $08; { Transfer from SCSI target to host }
SRB_DIR_OUT = $10; { Transfer from host to SCSI target }
SRB_EVENT_NOTIFY = $40; { Enable ASPI event notification }
RESIDUAL_COUNT_SUPPORTED = $02; { Extended buffer flag }
MAX_SRB_TIMEOUT = 108000; { 30 hour maximum timeout in half seconds }
DEFAULT_SRB_TIMEOUT = 108000; { Max timeout by default }
// ASPI Command Definitions
SC_HA_INQUIRY = $00; { Host adapter inquiry }
SC_GET_DEV_TYPE = $01; { Get device type }
SC_EXEC_SCSI_CMD = $02; { Execute SCSI command }
SC_ABORT_SRB = $03; { Abort an SRB }
SC_RESET_DEV = $04; { SCSI bus device reset }
SC_SET_HA_PARMS = $05; { Set HA parameters }
SC_GET_DISK_INFO = $06; { Get Disk information }
SC_RESCAN_SCSI_BUS = $07; { ReBuild SCSI device map }
SC_GETSET_TIMEOUTS = $08; { Get/Set target timeouts }
// SRB Status
SS_PENDING = $00; { SRB being processed }
SS_COMP = $01; { SRB completed without error }
SS_ABORTED = $02; { SRB aborted }
SS_ABORT_FAIL = $03; { Unable to abort SRB }
SS_ERR = $04; { SRB completed with error }
SS_INVALID_CMD = $80; { Invalid ASPI command }
SS_INVALID_HA = $81; { Invalid host adapter number }
SS_NO_DEVICE = $82; { SCSI device not installed }
SS_INVALID_SRB = $E0; { Invalid parameter set in SRB }
SS_OLD_MANAGER = $E1; { ASPI manager doesn't support Windows }
SS_BUFFER_ALIGN = $E1; { Buffer not aligned (replaces OLD_MANAGER in Win32) }
SS_ILLEGAL_MODE = $E2; { Unsupported Windows mode }
SS_NO_ASPI = $E3; { No ASPI managers resident }
SS_FAILED_INIT = $E4; { ASPI for windows failed init }
SS_ASPI_IS_BUSY = $E5; { No resources available to execute cmd }
SS_BUFFER_TO_BIG = $E6; { Buffer size to big to handle! }
SS_MISMATCHED_COMPONENTS = $E7; { The DLLs/EXEs of ASPI don't version check }
SS_NO_ADAPTERS = $E8; { No host adapters to manage }
SS_INSUFFICIENT_RESOURCES = $E9; { Couldn't allocate resources needed to init }
SS_ASPI_IS_SHUTDOWN = $EA; { Call came to ASPI after PROCESS_DETACH }
SS_BAD_INSTALL = $EB; { The DLL or other components are installed wrong }
// Host Adapter Status
HASTAT_OK = $00; { Host adapter did not detect an error }
HASTAT_SEL_TO = $11; { Selection Timeout }
HASTAT_DO_DU = $12; { Data overrun data underrun }
HASTAT_BUS_FREE = $13; { Unexpected bus free }
HASTAT_PHASE_ERR = $14; { Target bus phase sequence failure }
HASTAT_TIMEOUT = $09; { Timed out while SRB was waiting to beprocessed }
HASTAT_COMMAND_TIMEOUT = $0B; { Adapter timed out processing SRB }
HASTAT_MESSAGE_REJECT = $0D; { While processing SRB, the adapter received a MESSAGE }
HASTAT_BUS_RESET = $0E; { A bus reset was detected }
HASTAT_PARITY_ERROR = $0F; { A parity error was detected }
HASTAT_REQUEST_SENSE_FAILED = $10; { The adapter failed in issuing }
type
// SRB - HOST ADAPTER INQUIRY - SC_HA_INQUIRY (0)
{TSRB_HAInquiry record will be passed to ASPI Mgr to retreive information about
ASPI state on the machine, number of installed ASPI adapters etc.}
PTSRB_HAInquiry = ^TSRB_HAInquiry;
TSRB_HAInquiry = packed record
SRB_Cmd : BYTE; { 00/000 ASPI command code = SC_HA_INQUIRY }
SRB_Status : BYTE; { 01/001 ASPI command status byte }
SRB_HaId : BYTE; { 02/002 ASPI host adapter number }
SRB_Flags : BYTE; { 03/003 ASPI request flags }
SRB_Hdr_Rsvd : Cardinal; { 04/004 Reserved, MUST = 0 }
HA_Count : BYTE; { 08/008 Number of host adapters present }
HA_SCSI_ID : BYTE; { 09/009 SCSI ID of host adapter }
HA_ManagerId : array [0..15] of BYTE; { 0A/010 String describing the manager }
HA_Identifier : array [0..15] of BYTE; { 1A/026 String describing the host adapter }
HA_Unique : array [0..15] of BYTE; { 2A/042 Host Adapter Unique parameters }
HA_Rsvd1 : WORD; { 3A/058 Reserved, MUST = 0 }
end;
// SRB - GET DEVICE TYPE - SC_GET_DEV_TYPE (1)
{TSRB_GDEVBlock record will be passed to ASPI Mgr to retreive information about device.}
PTSRB_GDEVBlock = ^TSRB_GDEVBlock;
TSRB_GDEVBlock = packed record
SRB_Cmd : BYTE; { 00/000 ASPI command code = SC_GET_DEV_TYPE }
SRB_Status : BYTE; { 01/001 ASPI command status byte }
SRB_HaId : BYTE; { 02/002 ASPI host adapter number }
SRB_Flags : BYTE; { 03/003 Reserved, MUST = 0 }
SRB_Hdr_Rsvd : Cardinal; { 04/004 Reserved, MUST = 0 }
SRB_Target : BYTE; { 08/008 Target's SCSI ID }
SRB_Lun : BYTE; { 09/009 Target's LUN number }
SRB_DeviceType : BYTE; { 0A/010 Target's peripheral device type }
SRB_Rsvd1 : BYTE; { 0B/011 Reserved, MUST = 0 }
end;
// SRB - EXECUTE SCSI COMMAND - SC_EXEC_SCSI_CMD (2)
{TSRB_ExecSCSICmd record will be passed to ASPI Mgr to execute SCSI command on SCSI device.}
PTSRB_ExecSCSICmd = ^TSRB_ExecSCSICmd;
TSRB_ExecSCSICmd = packed record
SRB_Cmd : BYTE; { 00/000 ASPI command code = SC_EXEC_SCSI_CMD }
SRB_Status : BYTE; { 01/001 ASPI command status byte }
SRB_HaId : BYTE; { 02/002 ASPI host adapter number }
SRB_Flags : BYTE; { 03/003 ASPI request flags }
SRB_Hdr_Rsvd : Cardinal; { 04/004 Reserved }
SRB_Target : BYTE; { 08/008 Target's SCSI ID }
SRB_Lun : BYTE; { 09/009 Target's LUN number }
SRB_Rsvd1 : WORD; { 0A/010 Reserved for Alignment }
SRB_BufLen : Cardinal; { 0C/012 Data Allocation Length }
SRB_BufPointer : Pointer; { 10/016 Data Buffer Pointer }
SRB_SenseLen : BYTE; { 14/020 Sense Allocation Length }
SRB_CDBLen : BYTE; { 15/021 CDB Length }
SRB_HaStat : BYTE; { 16/022 Host Adapter Status }
SRB_TargStat : BYTE; { 17/023 Target Status }
SRB_PostProc : Pointer; { 18/024 Post routine }
SRB_Rsvd2 : array [0..19] of BYTE; { 1C/028 Reserved, MUST = 0 }
CDBByte : array [0..15] of BYTE; { 30/048 SCSI CDB }
SenseArea : array [0..(SENSE_LEN+1)] of BYTE; { 50/064 Request Sense buffer }
end;
// SRB - ABORT AN SRB - SC_ABORT_SRB (3)
PTSRB_Abort = ^TSRB_Abort;
TSRB_Abort = packed record
SRB_Cmd : BYTE; { 00/000 ASPI command code = SC_ABORT_SRB }
SRB_Status : BYTE; { 01/001 ASPI command status byte }
SRB_HaId : BYTE; { 02/002 ASPI host adapter number }
SRB_Flags : BYTE; { 03/003 Reserved }
SRB_Hdr_Rsvd : Cardinal; { 04/004 Reserved }
SRB_ToAbort : Pointer; { PVOID } { 08/008 Pointer to SRB to abort }
end;
// SRB - RESCAN SCSI BUS(ES) ON SCSIPORT
{TSRB_RescanPort record will be passed to ASPI Mgr to initiate SCSI bus rescan on the port.}
PTSRB_RescanPort = ^TSRB_RescanPort;
TSRB_RescanPort = packed record
SRB_Cmd : BYTE; { 00/000 ASPI command code = SC_RESCAN_SCSI_BUS }
SRB_Status : BYTE; { 01/001 ASPI command status byte }
SRB_HaId : BYTE; { 02/002 ASPI host adapter number }
SRB_Flags : BYTE; { 03/003 Reserved, MUST = 0 }
SRB_Hdr_Rsvd : Cardinal; { 04/004 Reserved, MUST = 0 }
end;
// SRB - GET/SET TARGET TIMEOUTS
{TSRB_GetSetTimeouts record will be passed to ASPI Mgr to get/set timeouts on SCSI device.}
PTSRB_GetSetTimeouts = ^TSRB_GetSetTimeouts;
TSRB_GetSetTimeouts = packed record
SRB_Cmd : BYTE; { 00/000 ASPI command code = SC_GETSET_TIMEOUTS }
SRB_Status : BYTE; { 01/001 ASPI command status byte }
SRB_HaId : BYTE; { 02/002 ASPI host adapter number }
SRB_Flags : BYTE; { 03/003 ASPI request flags }
SRB_Hdr_Rsvd : Cardinal; { 04/004 Reserved, MUST = 0 }
SRB_Target : BYTE; { 08/008 Target's SCSI ID }
SRB_Lun : BYTE; { 09/009 Target's LUN number }
SRB_Timeout : Cardinal; { 0A/010 Timeout in half seconds }
end;
TAspiDeviceIDflag = (ADIDmodeSense6, ADIDmodeSenseDBD);
TScsiDeviceType = (TSDDisk, TSDTape, TSDPrinter, TSDProcessor,
TSDWORM, TSDCDROM, TSDScanner, TSDOptical,
TSDChanger, TSDCommunication,
TSDInvalid, TSDAny, TSDOther);
implementation
var
ASPIHandle: THandle;
UnloadASPI: boolean;
function InitASPI: Boolean;
begin
ASPIHandle:=GetModuleHandle(ASPI_DLL);
UnloadASPI:=ASPIHandle=0;
if ASPIHandle=0 then
ASPIHandle:=LoadLibrary(ASPI_DLL);
if ASPIHandle<>0 then begin
@GetASPI32SupportInfo:=getprocaddress(ASPIHandle,PAnsiChar('GetASPI32SupportInfo'));
@SendASPI32Command:=getprocaddress(ASPIHandle,PAnsiChar('SendASPI32Command'));
end;
result:=(ASPIHandle<>0) and Assigned(GetASPI32SupportInfo);
end;
procedure FreeASPI;
begin
if (ASPIHandle<>0) and UnloadASPI then begin
if not FreeLibrary(ASPIHandle) then
raise Exception.Create(Format('Unload Error: %s - 0x%x',[ASPI_DLL,GetModuleHandle(ASPI_DLL)]))
else
ASPIHandle:=0;
end;
end;
function ExecuteASPI32Test;
var
ASPI32SupportInfo: Cardinal;
i,j: ULONG;
SRB_HaInquiry: TSRB_HaInquiry;
SRB_GDEVBlock: TSRB_GDEVBlock;
SRB_ExecSCSICmd: TSRB_ExecSCSICmd;
Status: Cardinal;
Storage: array[0..127] of BYTE;
h: THandle;
Inquiry: array[0..99] of BYTE;
begin
Result:=0;
if not InitASPI then
Exit;
ASPIConfig.Host.Clear;
ASPIConfig.LUN.Clear;
ASPIConfig.ID.Clear;
ASPIConfig.Vendor.Clear;
ASPIConfig.Typ.Clear;
ASPIConfig.Model.Clear;
ASPIConfig.Status.Clear;
ASPIConfig.Revision.Clear;
ASPIConfig.Extra.Clear;
ASPI32SupportInfo:=GetASPI32SupportInfo;
Result:=ASPI32SupportInfo;
if HIBYTE(LOWORD(ASPI32SupportInfo))=SS_COMP then begin
ASPIConfig.AdapterCount:=LOBYTE(LOWORD(ASPI32SupportInfo));
for i:=0 to ASPIConfig.AdapterCount-1 do begin
FillChar(SRB_HaInquiry,SizeOf(TSRB_HaInquiry),0);
SRB_HaInquiry.SRB_Cmd:=SC_HA_INQUIRY;
SRB_HaInquiry.SRB_HaId:=Byte(i);
Status:=SendASPI32Command(Pointer(@SRB_HaInquiry));
if Status=SS_COMP then begin
FillChar(Storage,SizeOf(Storage),0);
MoveMemory(@Storage,@SRB_HaInquiry.HA_ManagerId,SizeOf(SRB_HaInquiry.HA_ManagerId));
FillChar(Storage,SizeOf(Storage),0);
MoveMemory(@Storage,@SRB_HaInquiry.HA_Identifier[0],SizeOf(SRB_HaInquiry.HA_Identifier));
for j:=0 to MAX_TARGET_WIDE do begin
FillChar(SRB_GDEVBlock,SizeOf(SRB_GDEVBlock),0);
SRB_GDEVBlock.SRB_Cmd:=SC_GET_DEV_TYPE;
SRB_GDEVBlock.SRB_HaId:=Byte(i);
SRB_GDEVBlock.SRB_Target:=BYTE(j);
Status:=SendASPI32Command(Pointer(@SRB_GDEVBlock));
if Status=SS_COMP then begin
ASPIConfig.Host.Add(IntToStr(i));
ASPIConfig.ID.Add(IntToStr(j));
ASPIConfig.LUN.Add(IntToStr(SRB_GDEVBlock.SRB_Lun));
ASPIConfig.Typ.Add(IntToStr(SRB_GDEVBlock.SRB_DeviceType));
ASPIConfig.Status.Add('');
ASPIConfig.Vendor.Add('');
ASPIConfig.Model.Add('');
ASPIConfig.Revision.Add('');
ASPIConfig.Extra.Add('');
h:=Cardinal(CreateEvent(nil,True,False,nil));
if h<>0 then begin
FillChar(SRB_ExecSCSICmd,SizeOf(SRB_ExecSCSICmd),0);
SRB_ExecSCSICmd.SRB_Cmd:=SC_EXEC_SCSI_CMD;
SRB_ExecSCSICmd.SRB_HaId:=Byte(i);
SRB_ExecSCSICmd.SRB_Flags:=SRB_EVENT_NOTIFY;
SRB_ExecSCSICmd.SRB_Target:=BYTE(j);
SRB_ExecSCSICmd.SRB_SenseLen:=SENSE_LEN;
SRB_ExecSCSICmd.SRB_PostProc:=Pointer(h);
SRB_ExecSCSICmd.SRB_CDBLen:=6;
Status:=SendASPI32Command(Pointer(@SRB_ExecSCSICmd));
if Status=SS_PENDING then
WaitForSingleObject(h,INFINITE);
ASPIConfig.Status[ASPIConfig.Status.Count-1]:=IntToStr(SRB_ExecSCSICmd.SRB_Status);
ResetEvent(h);
FillChar(SRB_ExecSCSICmd,SizeOf(SRB_ExecSCSICmd),0);
FillChar(Inquiry,SizeOf(Inquiry),0);
SRB_ExecSCSICmd.SRB_Cmd:=SC_EXEC_SCSI_CMD;
SRB_ExecSCSICmd.SRB_HaId := BYTE(i);
SRB_ExecSCSICmd.SRB_Flags:=SRB_EVENT_NOTIFY or SRB_DIR_IN;
SRB_ExecSCSICmd.SRB_Target:=Byte(j);
SRB_ExecSCSICmd.SRB_SenseLen:=SENSE_LEN;
SRB_ExecSCSICmd.SRB_PostProc:=Pointer(h);
SRB_ExecSCSICmd.SRB_CDBLen:=6;
SRB_ExecSCSICmd.SRB_BufLen:=SizeOf(Inquiry);
SRB_ExecSCSICmd.SRB_BufPointer:=Pointer(@Inquiry[0]);
SRB_ExecSCSICmd.CDBByte[0]:=$12; // SCSI inquiry
SRB_ExecSCSICmd.CDBByte[4]:=SizeOf(Inquiry);
Status:=SendASPI32Command(Pointer(@SRB_ExecSCSICmd));
if Status=SS_PENDING then
WaitForSingleObject(h,INFINITE);
ASPIConfig.Status[ASPIConfig.Status.Count-1]:=IntToStr(SRB_ExecSCSICmd.SRB_Status);
if SRB_ExecSCSICmd.SRB_Status=SS_COMP then begin
FillChar(Storage,SizeOf(Storage),0);
MoveMemory(@Storage,Pointer(@Inquiry[8]),8);
ASPIConfig.Vendor[ASPIConfig.Vendor.Count-1]:=string(PAnsiChar(@Storage[0]));
FillChar(Storage,SizeOf(Storage),0);
MoveMemory(@Storage,Pointer(@Inquiry[16]),16);
ASPIConfig.Model[ASPIConfig.Model.Count-1]:=string(PAnsiChar(@Storage[0]));
FillChar(Storage,SizeOf(Storage),0);
MoveMemory(@Storage,Pointer(@Inquiry[32]),4);
ASPIConfig.Revision[ASPIConfig.Revision.Count-1]:=string(PAnsiChar(@Storage[0]));
FillChar(Storage,SizeOf(Storage),0);
MoveMemory(@Storage,Pointer(@Inquiry[36]),20);
ASPIConfig.Extra[ASPIConfig.Extra.Count-1]:=string(PAnsiChar(@Storage[0]));
end;
CloseHandle(h);
end;
end;
end;
end;
end;
end;
end;
initialization
ASPIHandle:=0;
finalization
FreeASPI;
end.