📄 taspidev.pas
字号:
property ShortTimeout : DWORD read fShortTimeout write fShortTimeout;
property MediumTimeout: DWORD read fMediumTimeout write fMediumTimeout;
property LongTimeout : DWORD read fLongTimeout write fLongTimeout;
property AudioTimeout : DWORD read fAudioTimeout write fAudioTimeout;
// Set AudioTimeout corresponding to CD-ROM audio control page
// parameter IMM. It shall be equal to ShortTimeout when IMM=TRUE
// and greater then estimated playback time elsewhere.
end;
function GetASPI32SupportInfo : DWORD; stdcall;
function SendASPI32Command(LPSRB : pointer) : DWORD; stdcall;
function BigEndianW(Arg : WORD) : WORD;
function BigEndianD(Arg : DWORD) : DWORD;
function GatherWORD(b1,b0 : byte) : WORD;
function GatherDWORD(b3,b2,b1,b0 : byte) : DWORD;
implementation
function GetASPI32SupportInfo; external 'WNASPI32' name 'GetASPI32SupportInfo';
function SendASPI32Command; external 'WNASPI32' name 'SendASPI32Command';
function BigEndianW(Arg : WORD) : WORD;
begin result := ((Arg SHL 8) AND $FF00) OR
((Arg SHR 8) AND $00FF); end;
function BigEndianD(Arg : DWORD) : DWORD;
begin
result := ((Arg SHL 24) AND $FF000000) OR
((Arg SHL 8) AND $00FF0000) OR
((Arg SHR 8) AND $0000FF00) OR
((Arg SHR 24) AND $000000FF);
end;
function GatherWORD(b1,b0 : byte) : WORD;
begin
result := ((WORD(b1) SHL 8) AND $FF00) OR
((WORD(b0) ) AND $00FF);
end;
function GatherDWORD(b3,b2,b1,b0 : byte) : DWORD;
begin
result := ((LongInt(b3) SHL 24) AND $FF000000) OR
((LongInt(b2) SHL 16) AND $00FF0000) OR
((LongInt(b1) SHL 8) AND $0000FF00) OR
((LongInt(b0) ) AND $000000FF);
end;
function TASPIDevice.GetAspiError(Status,HaStat,TargStat: BYTE): BOOLEAN;
begin
result := false;
fLastError := Err_None;
case Status of
0,1: result := true; // No error, all OK
2,3: fLastError := Err_Aborted;
$80: fLastError := Err_InvalidRequest; // This command is
// not supported by ASPI manager
$81: fLastError := Err_InvalidHostAdapter;
$82: fLastError := Err_NoDevice;
$E0: fLastError := Err_InvalidSrb;
$E1: fLastError := Err_BufferAlign;
$E5: fLastError := Err_AspiIsBusy;
$E6: fLastError := Err_BufferTooBig;
4: case HaStat of
$09 : fLastError := Err_CommandTimeout;
$0B : fLastError := Err_SrbTimeout;
$0D : fLastError := Err_MessageReject;
$0E : fLastError := Err_BusReset;
$0F : fLastError := Err_ParityError;
$10 : fLastError := Err_RequestSenseFailed;
$11 : fLastError := Err_SelectionTimeout;
$12 : fLastError := Err_DataOverrun;
$13 : fLastError := Err_UnexpectedBusFree;
$14 : fLastError := Err_BusPhaseSequence;
$00 : case TargStat of
0,2: fLastError := Err_CheckCondition;
$08: fLastError := Err_TargetBusy;
$18: fLastError := Err_TargetReservationConflict;
$28: fLastError := Err_TargetQueueFull
else fLastError := Err_Unknown;
end
else fLastError := Err_Unknown;
end
else fLastError := Err_Unknown;
end; end;
procedure ASPIstrCopy(Src : PChar; var Dst : ShortString; Leng : Integer);
var i : integer;
begin
i := 0;
while (i < Leng) AND (Src[i] >= ' ') do
begin Dst[i+1] := Src[i]; inc(i); end;
Dst[0] := CHR(i);
end;
constructor TASPIDevice.Create;
var I : DWORD;
begin
inherited Create;
I := GetASPI32SupportInfo;
if (I AND $0000FE00) <> 0 then fHAcount := 0
else fHAcount := I AND $000000FF;
FillChar(fSense, sizeof(fSense), 0);
fLastError := Err_None;
fShortTimeout := 1000; // 1 sec
fMediumTimeout := 60000; // 1 min
fLongTimeout := 3600000; // 1 hour
fAudioTimeout := fShortTimeout;
fDeviceID.Adapter := $81; // Invalid host adapter
fDeviceID.Target := 0;
fDeviceID.Lun := 0;
fDeviceType := TSDInvalid;
end;
destructor TASPIDevice.Destroy;
begin inherited Destroy; end;
function TASPIDevice.ASPIhaInquiry(HaId : BYTE;
var sh : TScsiHAinfo) : BOOLEAN; //True if OK
type SRB_Inquiry = packed record
SRB_Cmd : BYTE; // ASPI command code = 0 = SC_HA_INQUIRY
SRB_Status : BYTE; // ASPI command status byte
SRB_HaId : BYTE; // ASPI host adapter number
SRB_Flags : BYTE; // Reserved
SRB_Hdr_Rsvd : DWORD; // Reserved
SRB_HA_Count : BYTE; // same as in GetASPIsupportInfo
SRB_HA_SCSIID : BYTE; // SCSI Id of selected host adapter
SRB_ManagerID, // MustBe = 'ASPI for WIN32'
SRB_AdapterID // String describing selected HA
: array[0..15] of char;
SRB_BufAlign : WORD; // Buffer alignment mask: 0=byte, 1=word,
// 3=dword, 7=8-byte, etc. 65536 bytes max
SRB_Residual : BYTE; // Bit1 = residual count support flag
SRB_Targets : BYTE; // Max target count for selected HA
SRB_TransfLen : DWORD; // Max transfer length in bytes
SRB_Rsvd : array[0..9] of byte;
end;
var Isrb : SRB_Inquiry;
begin
FillChar(Isrb, sizeof(Isrb), 0);
Isrb.SRB_Cmd := 0;
Isrb.SRB_HaId := HaId;
SendASPI32Command(@Isrb);
with Isrb do begin
Result := GetAspiError(SRB_Status, $FF, $FF);
sh.ScsiId := SRB_HA_SCSIID;
ASPIstrCopy(SRB_ManagerID, sh.ScsiManagerId, 16);
ASPIstrCopy(SRB_AdapterID, sh.HostAdapterId, 16);
sh.BufferAlignMask := SRB_BufAlign;
sh.ResidualSupport := (SRB_Residual AND 2) <> 0;
if SRB_Targets = 0 then sh.MaxTargetCount := 8
else sh.MaxTargetCount := SRB_Targets;
sh.MaxTransferLength := SRB_TransfLen;
end; end;
function TASPIDevice.ASPIgetDeviceType(DeviceAddress : TDeviceID;
var SDeviceType : TScsiDeviceType) : BOOLEAN; //True if OK
type SRB_GetDeviceType = packed record
SRB_Cmd : BYTE; // ASPI command code = 1 = SC_GET_DEV_TYPE
SRB_Status : BYTE; // ASPI command status byte
SRB_HaId : BYTE; // ASPI host adapter number
SRB_Flags : BYTE; // Reserved
SRB_Hdr_Rsvd : DWORD; // Reserved
SRB_Target : BYTE; // Target number for specified HA
SRB_Lun : BYTE; // Logical unit number of selected target
SRB_DeviceType: BYTE; // Selected HA/Target/Lun device type
SRB_Rsvd : BYTE; // Reserved for alignment
end;
var Gsrb : SRB_GetDeviceType;
begin
FillChar(Gsrb, sizeof(Gsrb), 0);
Gsrb.SRB_Cmd := 1;
Gsrb.SRB_HaId := DeviceAddress.Adapter;
Gsrb.SRB_Target := DeviceAddress.Target;
Gsrb.SRB_Lun := DeviceAddress.Lun;
SendASPI32Command(@Gsrb);
Result := GetAspiError(Gsrb.SRB_Status, $FF, $FF);
if Result AND (Gsrb.SRB_DeviceType < ORD(TSDInvalid))
then SDeviceType := TScsiDeviceType(Gsrb.SRB_DeviceType)
else SDeviceType := TSDInvalid;
end;
procedure TASPIDevice.ASPIabortCommand(HaId : BYTE; Psrb : pointer);
type SRB_Abort = packed record
SRB_Cmd : BYTE; // ASPI command code = 3 = SC_ABORT_SRB
SRB_Status : BYTE; // ASPI command status byte
SRB_HaId : BYTE; // ASPI host adapter number
SRB_Flags : BYTE; // Reserved
SRB_Hdr_Rsvd : DWORD; // Reserved
SRB_ToAbort : pointer; // Pointer to SRB to abort
end;
var Asrb : SRB_Abort;
begin
FillChar(Asrb, sizeof(Asrb), 0);
Asrb.SRB_Cmd := 3;
Asrb.SRB_HaId := HaId;
Asrb.SRB_ToAbort := Psrb;
SendASPI32Command(@Asrb);
end;
function TASPIDevice.ASPIsendScsiCommand(Pcdb : pointer; CdbLen : DWORD;
Pbuf : pointer; BufLen : DWORD;
Direction, Timeout: DWORD) : BOOLEAN; //True if OK
type
SRB_ExecSCSICmd = packed record
SRB_Cmd : BYTE; // ASPI command code= 2 =SC_EXEC_SCSI_CMD
SRB_Status : BYTE; // ASPI command status byte
SRB_HaId : BYTE; // ASPI host adapter number
SRB_Flags : BYTE; // ASPI request flags
SRB_Hdr_Rsvd : DWORD; // Reserved
SRB_Target : BYTE; // Target's SCSI ID
SRB_Lun : BYTE; // Target's LUN number
SRB_Rsvd1 : WORD; // Reserved for Alignment
SRB_BufLen : DWORD; // Data Allocation Length
SRB_BufPtr : POINTER; // Data Buffer Pointer
SRB_SenseLen : BYTE; // Sense Allocation Length
SRB_CDBLen : BYTE; // CDB Length
SRB_HaStat : BYTE; // Host Adapter Status
SRB_TargStat : BYTE; // Target Status
SRB_PostProc : THandle; // Post routine
SRB_Rsvd2 : POINTER; // Reserved
SRB_Rsvd3 : array[0..15] of BYTE; // Reserved for alignment
SRB_CDBByte : array[0..15] of BYTE; // SCSI CDB
SRB_Sense : TscsiSenseInfo; // Request Sense buf
end;
var
Esrb : SRB_ExecSCSICmd;
hEvent : THandle;
SenseKeys : BYTE;
begin
result := false;
fLastError := Err_None;
FillChar(fSense, sizeof(fSense), 0);
if fDeviceType = TSDInvalid then
begin fLastError := Err_InvalidDevice; exit; end;
hEvent := CreateEvent(NIL,true,false,NIL); {event to notify completion}
if hEvent = 0 then begin fLastError := Err_NoEvent; exit; end;
ResetEvent(hEvent);
FillChar(Esrb, sizeof(Esrb), 0); { Scsi Request Block init }
with Esrb do begin
SRB_Cmd := 2; { SC_EXEC_SCSI_CMD }
SRB_HaId := fDeviceID.Adapter;
SRB_Flags := Direction OR $40; { set SRB_EVENT_NOTIFY flag }
SRB_Target := fDeviceID.Target;
SRB_Lun := fDeviceID.Lun;
SRB_BufLen := BufLen;
SRB_BufPtr := Pbuf;
SRB_SenseLen := sizeof(TscsiSenseInfo) - 2;
if CdbLen > 16 then SRB_CDBLen := 16 else SRB_CDBLen := CdbLen;
SRB_PostProc := hEvent;
Move(Pcdb^, SRB_CDBByte, SRB_CDBLen);
end;
if SendASPI32Command(@Esrb) = 0 { SS_PENDING } then begin
if WaitForSingleObject(hEvent,Timeout) <> WAIT_OBJECT_0 then begin
fLastError := Err_NotifyTimeout;
ASPIabortCommand(Esrb.SRB_HaId, @Esrb);
end;
end else fLastError := Err_NoDevice; {ASPI DLL says:"No such device"}
CloseHandle(hEvent);
if fLastError = Err_None then with Esrb do begin
fSense := SRB_Sense;
GetAspiError(SRB_Status, SRB_HaStat, SRB_TargStat);
end;
if fLastError = Err_CheckCondition then with Esrb do
if SRB_Sense[0] = 0
then fLastError := Err_None
else if (SRB_Sense[0] AND $7E) <> $70 // recognized values
then fLastError := Err_SenseUnknown
else begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -