Taspidev.pas
资源名称:tcdrom.zip [点击查看]
上传用户:jzxjwgb
上传日期:2007-01-06
资源大小:64k
文件大小:38k
源码类别:
SCSI/ASPI
开发平台:
Delphi
- unit TASPIDEV;
- // -----------------------------------------------------------------------------
- // Project: CD-ROM and CD-audio Interface Components
- // Component Names: TASPIdevice
- // Module: TAspiDev
- // Description: Implements basic-level interface to wnaspi32.dll
- // and some of fundamental functions for SCSI interface,
- // that are device-type independent.
- // Version: 0.2 early beta
- // Date: 25-MAY-1999
- // Target: Win32, Delphi3
- // Authors: Sergey "KSER" Kabikov, iamkser@hotmail.com
- // Copyright (c) 1999 Sergey Kabikov
- // -----------------------------------------------------------------------------
- // -----------------------------------------------------------------------------
- // Acknowledgements:
- // 1. Thanks to Jay A. Key (scsiprog@geocities.com) for his "akrip" program,
- // which sources (http://www.geocities.com/SiliconValley/Byte/7125/)
- // helps to solve many problems.
- // -----------------------------------------------------------------------------
- interface
- uses Windows;
- const {======= Possible values of Direction parameter ========}
- SRB_NODIR = $00; // Direction determined by SCSI command
- SRB_DIR_IN = $08; // Transfer from SCSI target to host
- SRB_DIR_OUT = $10; // Transfer from host to SCSI target
- type
- TScsiDeviceType = (TSDDisk, TSDTape, TSDPrinter, TSDProcessor,
- TSDWORM, TSDCDROM, TSDScanner, TSDOptical,
- TSDChanger, TSDCommunication, TSDInvalid, TSDAny);
- var
- TScsiDeviceTypeName : array[TScsiDeviceType] of string = ('Disk Drive',
- 'Tape Drive', 'Printer', 'Processor', 'WORM Drive', 'CD-ROM Drive',
- 'Scanner', 'Optical Drive', 'Changer', 'Communication Device',
- 'Invalid', 'Any Type Device');
- type
- TScsiError = {======== Errors from SRB_Status field ========}
- (Err_None, Err_Aborted, Err_InvalidRequest,
- Err_HAerror, Err_InvalidHostAdapter, Err_NoDevice,
- Err_InvalidSrb, Err_BufferAlign, Err_AspiIsBusy,
- Err_BufferTooBig, Err_Unknown,
- {======== Errors from SRB_HaStat field ========}
- Err_CommandTimeout, { transaction time ran out }
- Err_SrbTimeout, { while waiting to process }
- Err_MessageReject,
- Err_BusReset,
- Err_ParityError,
- Err_RequestSenseFailed,
- Err_SelectionTimeout,
- Err_DataOverrun, {... or underrun }
- Err_UnexpectedBusFree,
- Err_BusPhaseSequence, {... failure }
- {======== Errors from SRB_TargStat field ========}
- Err_CheckCondition,
- Err_TargetBusy,
- Err_TargetReservationConflict,
- Err_TargetQueueFull,
- {======== Errors of SendScsiCommand ========}
- Err_InvalidDevice, { Trying to exec SCSI command for non-exist device }
- Err_NoEvent, { Unable to get event handle for notification }
- Err_NotifyTimeout, { WaitForSingleObject result was unacceptable }
- {======== Errors from SRB_Sense area ========}
- Err_SenseUnknown, // Unknown SRB_Sense.ErrorCode value
- Err_SenseFileMark,
- Err_SenseEndOfMedia,
- Err_SenseIllegalLength,
- Err_SenseIncorrectLength,
- Err_SenseNoSense, // There is no sense key info to be reported
- Err_SenseRecoveredError, // Last command completed successfully with
- // some recovery action performed by the target.
- Err_SenseNotReady, // Unit addressed cannot be accessed.
- // Operator intervention may be required.
- Err_SenseMediumError, // Command terminated with a non-recovered
- // error condition that was probably caused by a flaw
- // in the medium or an error in the recorded data.
- Err_SenseHardwareError, // Non-recoverable hardware failure detected
- Err_SenseIllegalRequest, // Illegal parameter detected in the command
- // descriptor block or in the additional parameters.
- Err_SenseUnitAttention, // Removable medium may have been changed or
- // the target has been reset.
- Err_SenseDataProtect, // Read/Write Command was applied to the
- // block that is protected from this operation.
- Err_SenseBlankCheck, // Write-once device or a sequential-access
- // device encountered blank medium or end-of-data
- // indication while reading or a write-once device
- // encountered a non-blank medium while writing.
- Err_SenseVendorSpecific,
- Err_SenseCopyAborted, // COPY, COMPARE, or COPY AND VERIFY command
- // was aborted due to an error condition on the source
- // device, the destination device, or both.
- Err_SenseAbortedCommand, // Target aborted the command. Host may be
- // able to recover by trying the command again.
- Err_SenseEqual, // SEARCH DATA has satisfied an equal comparison.
- Err_SenseVolumeOverflow, // Buffered peripheral device has reached
- // the end-of-partition and data may remain in the
- // buffer that has not been written to the medium.
- // RECOVER BUFFERED DATA command may be issued to read
- // the unwritten data from the buffer.
- Err_SenseMiscompare, // Source data did not match the data read
- // from the medium.
- Err_SenseReserved
- );
- var
- ScsiErrorName : array[TScsiError] of string = ('Err_None',
- 'Err_Aborted', 'Err_InvalidRequest', 'Err_HAerror',
- 'Err_InvalidHostAdapter', 'Err_NoDevice', 'Err_InvalidSrb',
- 'Err_BufferAlign', 'Err_AspiIsBusy', 'Err_BufferTooBig',
- 'Err_Unknown', 'Err_CommandTimeout', 'Err_SrbTimeout',
- 'Err_MessageReject', 'Err_BusReset', 'Err_ParityError',
- 'Err_RequestSenseFailed', 'Err_SelectionTimeout',
- 'Err_DataOverrun', 'Err_UnexpectedBusFree',
- 'Err_BusPhaseSequence', 'Err_CheckCondition', 'Err_TargetBusy',
- 'Err_TargetReservationConflict', 'Err_TargetQueueFull',
- 'Err_InvalidDevice', 'Err_NoEvent', 'Err_NotifyTimeout',
- 'Err_SenseUnknown', 'Err_SenseFileMark', 'Err_SenseEndOfMedia',
- 'Err_SenseIllegalLength', 'Err_SenseIncorrectLength',
- 'Err_SenseNoSense', 'Err_SenseRecoveredError',
- 'Err_SenseNotReady', 'Err_SenseMediumError', 'Err_SenseHardwareError',
- 'Err_SenseIllegalRequest', 'Err_SenseUnitAttention',
- 'Err_SenseDataProtect', 'Err_SenseBlankCheck',
- 'Err_SenseVendorSpecific', 'Err_SenseCopyAborted',
- 'Err_SenseAbortedCommand', 'Err_SenseEqual',
- 'Err_SenseVolumeOverflow', 'Err_SenseMiscompare', 'Err_SenseReserved');
- type
- TdeviceID = record Adapter, Target, Lun : byte; end;
- TscsiSenseInfo = array[0..127] of BYTE;
- TCallBackProc = procedure;
- TScsiDeviceInfo = packed record
- PeripheralQualifier : BYTE;
- { 000b = Peripheral device type is currently connected to this
- logical unit. Especially for hot-swap devices. All fixed
- devices shall also use this peripheral qualifier.
- 001b = The target is capable of supporting the peripheral device;
- however, the physical device is not currently connected.
- 010b = Reserved.
- 011b = The target is not capable of supporting a physical device
- on this logical unit. It's illegal LUN for all commands.
- 1XXb = Vendor-specific codes. }
- DeviceType : BYTE;
- { 00h = Direct-access device (e.g. magnetic disk)
- 01h = Sequential-access device (e.g. magnetic tape)
- 02h = Printer device
- 03h = Processor device
- 04h = Write-once device (e.g. some optical disks)
- 05h = CD-ROM device
- 06h = Scanner device
- 07h = Optical memory device (e.g. some optical disks)
- 08h = Medium changer device (e.g. jukeboxes)
- 09h = Communications device
- 0Ah, 0Bh = Defined by ASC IT8 (Graphic arts pre-press devices)
- 0Ch..1Eh = Reserved
- 1Fh = Unknown or no device type }
- DeviceTypeModifier : BYTE; { Vendor-specific, in SCSI-I only }
- RemovableMedium : BOOLEAN; { defines if medium is removable }
- ISOversion : BYTE; {compliance level to the ISO
- version of SCSI (ISO 9316), 0 means no compliance acclaimed }
- ECMAversion : BYTE; {compliance level to the ECMA
- version of SCSI (ECMA-111), 0 means no compliance acclaimed }
- ANSIversion : BYTE; {compliance level to the ANSI SCSI:
- 0 = The device might or might not comply to an ANSI standard,
- 1 = The device complies to ANSI SCSI-1,
- 2 = The device complies to ANSI SCSI-2, etc. }
- AsyncEventCapability : BOOLEAN; {indicates that the device supports
- the asynchronous event notification capability. For Processor
- device-type definition ONLY. Reserved for all other types. }
- TerminateIOcapability: BOOLEAN; {indicates that the device supports
- the TERMINATE I/O PROCESS message }
- ResponseDataFormat : BYTE; { indicates the INQUIRY data format is:
- 0 = as specified in SCSI-1,
- 1 = products that were designed prior to the SCSI-2 (i.e. CCS),
- 2 = as specified in SCSI-2,
- 3..0Fh = reserved. }
- AdditionalDataLength : BYTE; { specifies the length in bytes of the
- parameters, i.e. (full_record_length - 4). If the record length
- specified here is too small to transfer all of the parameters,
- this value shall not be adjusted to reflect the truncation. }
- WideBus32capability : BOOLEAN; {indicates that the device supports
- 32-bit wide data transfers }
- WideBus16capability : BOOLEAN; {indicates that the device supports
- 16-bit wide data transfers. If the values of both the WideBus
- flags are false,the device only supports 8-bit data transfers.}
- RelativeAddressingCapability : BOOLEAN; { If this flag is set, the
- linked (and ONLY linked) commands may use relative addressing }
- SynchronousTransferCapability : BOOLEAN; {indicates that the device
- supports synchronous data transfers }
- LinkedCommandsCapability : BOOLEAN; {indicates that the device
- supports execution of linked commands for this logical unit. }
- CommandQueuingCapability : BOOLEAN; {indicates that the device
- supports tagged command queuing for this logical unit. }
- SoftResetCapability : BOOLEAN; { FALSE indicates that the device
- responds to the RESET condition with hard RESET alternative,
- TRUE - that it responds with the soft RESET alternative }
- VendorID : string[8];
- ProductID : string[16];
- ProductRevision : string[4];
- VendorSpecific : string[20];
- { All this strings are left-aligned ASCII data fields that shall
- contain only graphic codes (i.e. code values 20h through 7Eh),
- and the unused bytes shall be filled with space characters. }
- end;
- TScsiHAinfo = packed record
- ScsiId : BYTE;
- MaxTargetCount : BYTE;
- ResidualSupport : BOOLEAN;
- MaxTransferLength : DWORD;
- BufferAlignMask : WORD;
- ScsiManagerId,
- HostAdapterId : String[16];
- end;
- TASPIDevice = class { Common ASPI device class }
- private
- fHAcount : DWORD;
- fLastError : TScsiError;
- fSense : TscsiSenseInfo;
- fShortTimeout : DWORD;
- fMediumTimeout : DWORD;
- fLongTimeout : DWORD;
- fAudioTimeout : DWORD;
- fDeviceID : TdeviceID;
- fDeviceType : TScsiDeviceType;
- fDeviceInfo : TScsiDeviceInfo;
- fHAinfo : TScsiHAinfo;
- protected
- function GetAspiError(Status, HaStat, TargStat : BYTE) : BOOLEAN;
- procedure ChangeDevice(Value : TdeviceID); virtual;
- procedure SetDeviceID(Value : TdeviceID);
- public
- constructor Create(AOwner : TObject);
- destructor Destroy; override;
- {===================== Raw ASPI functions ===================}
- function ASPIhaInquiry(HaId : BYTE;
- var sh : TScsiHAinfo) : BOOLEAN; //True if OK
- function ASPIgetDeviceType(DeviceAddress : TDeviceID;
- var SDeviceType : TScsiDeviceType) : BOOLEAN;
- function ASPIsendScsiCommand(Pcdb : pointer; CdbLen : DWORD;
- Pbuf : pointer; BufLen : DWORD; // Always works with
- Direction, Timeout: DWORD) : BOOLEAN; // 'current' device
- procedure ASPIabortCommand(HaId : BYTE; Psrb : pointer);
- function ASPIresetDevice : BOOLEAN; // Resets 'current' device
- function ASPIgetDriveInt13info(DeviceAddress : TDeviceID;
- var Support, DosSupport : BOOLEAN;
- var DriveNumber, Heads, Sectors : BYTE) : BOOLEAN;
- // NOTE: This command is NOT VALID under WinNT.
- // Support=false -> no int 13 support anyway
- // else if DosSupport=false -> supported on non-DOS basis
- // else -> supported under DOS control
- {================== Mid-level ASPI functions ================}
- function ASPIsend6(OpCode : BYTE; Lba : DWORD; Byte4 : BYTE;
- Pbuf : pointer; BufLen, Direction,Timeout: DWORD) : BOOLEAN;
- function ASPIsend10(OpCode : BYTE; Byte1 : BYTE;
- Lba : DWORD; Byte6 : BYTE; Word7 : WORD;
- Pbuf : pointer; BufLen, Direction,Timeout: DWORD) : BOOLEAN;
- function ASPIsend12(OpCode : BYTE; Byte1 : BYTE;
- Lba, TLength : DWORD; Byte10 : BYTE;
- Pbuf : pointer; BufLen, Direction,Timeout: DWORD) : BOOLEAN;
- function GetDeviceInfo(DId : TdeviceID;
- var DInfo : TScsiDeviceInfo) : BOOLEAN;
- function EnumDevices(DType: TScsiDeviceType; CBack: TCallBackProc)
- : integer; // Returns number of found devices.
- // Calls CBack() every time when finds one.
- property HAcount : DWORD read fHAcount;
- property Sense : TscsiSenseInfo read fSense;
- property LastError : TScsiError read fLastError default Err_None;
- property DeviceID : TdeviceID read fDeviceID write SetDeviceID;
- property DeviceType : TScsiDeviceType read fDeviceType;
- property DeviceInfo : TScsiDeviceInfo read fDeviceInfo;
- property HAinfo : TScsiHAinfo read fHAinfo;
- published
- 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
- SenseKeys := SRB_Sense[2];
- case (SenseKeys AND $0F) of
- 0: begin // Skey_NoSense
- if (SenseKeys AND $80) <> 0 // FileMark flag
- then fLastError := Err_SenseFileMark
- else if (SenseKeys AND $40) <> 0 // EndOfMedia flag
- then fLastError := Err_SenseEndOfMedia
- else if (SenseKeys AND $20) <> 0 // IllegalLength flag
- then fLastError := Err_SenseIllegalLength
- else if (SRB_Sense[3] AND $80) <> 0 // ResidualCount < 0
- then fLastError := Err_SenseIncorrectLength
- else fLastError := Err_SenseNoSense;
- end;
- 1: fLastError := Err_SenseRecoveredError; //Skey_RecoveredError
- 2: fLastError := Err_SenseNotReady; //Skey_NotReady
- 3: fLastError := Err_SenseMediumError; //Skey_MediumError
- 4: fLastError := Err_SenseHardwareError; //Skey_HardwareError
- 5: fLastError := Err_SenseIllegalRequest; //Skey_IllegalRequest
- 6: fLastError := Err_SenseUnitAttention; //Skey_UnitAttention
- 7: fLastError := Err_SenseDataProtect; //Skey_DataProtect
- 8: fLastError := Err_SenseBlankCheck; //Skey_BlankCheck
- 9: fLastError := Err_SenseVendorSpecific; // Skey_VendorSpecific
- 10:fLastError := Err_SenseCopyAborted; // Skey_CopyAborted
- 11:fLastError := Err_SenseAbortedCommand; // Skey_AbortedCommand
- 12:fLastError := Err_SenseEqual; // Skey_Equal
- 13:fLastError := Err_SenseVolumeOverflow; // Skey_VolumeOverflow
- 14:fLastError := Err_SenseMiscompare; // Skey_Miscompare
- 15:fLastError := Err_SenseReserved; // Skey_Reserved
- end; end;
- result := (fLastError = Err_None) OR
- (fLastError = Err_SenseRecoveredError);
- end;
- function TASPIDevice.ASPIsend6(OpCode: BYTE; Lba : DWORD; Byte4 : BYTE;
- Pbuf: pointer; BufLen: DWORD; Direction,Timeout: DWORD) : BOOLEAN;
- var cdb : array[0..5] of BYTE;
- begin
- FillChar(Pbuf^, BufLen, 0);
- cdb[5] := 0;
- cdb[4] := Byte4;
- cdb[3] := BYTE(Lba AND $FF); Lba := Lba SHR 8;
- cdb[2] := BYTE(Lba AND $FF); Lba := Lba SHR 8;
- cdb[1] := ((fDeviceID.Lun AND 7) SHL 5) OR BYTE(Lba AND $1F);
- cdb[0] := OpCode;
- result := ASPIsendScsiCommand(@cdb,6,Pbuf,BufLen,Direction,Timeout);
- end;
- function TASPIDevice.ASPIsend10(OpCode : BYTE;
- Byte1 : BYTE; Lba : DWORD; Byte6 : BYTE; Word7 : WORD;
- Pbuf: pointer; BufLen: DWORD; Direction,Timeout: DWORD) : BOOLEAN;
- var cdb : array[0..9] of BYTE;
- begin
- FillChar(Pbuf^, BufLen, 0);
- cdb[9] := 0;
- cdb[8] := BYTE(Word7 AND $FF); Word7 := Word7 SHR 8;
- cdb[7] := BYTE(Word7 AND $FF);
- cdb[6] := Byte6;
- cdb[5] := BYTE(Lba AND $FF); Lba := Lba SHR 8;
- cdb[4] := BYTE(Lba AND $FF); Lba := Lba SHR 8;
- cdb[3] := BYTE(Lba AND $FF); Lba := Lba SHR 8;
- cdb[2] := BYTE(Lba AND $FF);
- cdb[1] := ((fDeviceID.Lun AND 7) SHL 5) OR (Byte1 AND $1F);
- cdb[0] := OpCode;
- result := ASPIsendScsiCommand(@cdb,10,Pbuf,BufLen,Direction,Timeout);
- end;
- function TASPIDevice.ASPIsend12(OpCode : BYTE;
- Byte1 : BYTE; Lba : DWORD; TLength : DWORD; Byte10 : BYTE;
- Pbuf : pointer; BufLen : DWORD; Direction,Timeout : DWORD) : BOOLEAN;
- var cdb : array[0..11] of BYTE;
- begin
- FillChar(Pbuf^, BufLen, 0);
- cdb[11]:= 0;
- cdb[10]:= Byte10;
- cdb[9] := BYTE(TLength AND $FF); TLength := TLength SHR 8;
- cdb[8] := BYTE(TLength AND $FF); TLength := TLength SHR 8;
- cdb[7] := BYTE(TLength AND $FF); TLength := TLength SHR 8;
- cdb[6] := BYTE(TLength AND $FF);
- cdb[5] := BYTE(Lba AND $FF); Lba := Lba SHR 8;
- cdb[4] := BYTE(Lba AND $FF); Lba := Lba SHR 8;
- cdb[3] := BYTE(Lba AND $FF); Lba := Lba SHR 8;
- cdb[2] := BYTE(Lba AND $FF);
- cdb[1] := ((fDeviceID.Lun AND 7) SHL 5) OR (Byte1 AND $1F);
- cdb[0] := OpCode;
- result := ASPIsendScsiCommand(@cdb,12,Pbuf,BufLen,Direction,Timeout);
- end;
- function TASPIDevice.ASPIresetDevice : BOOLEAN; // Resets 'current' device
- type
- SRB_ResetDevice = packed record
- SRB_Cmd : BYTE; // ASPI command code = 4 = SC_RESET_DEV
- 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's SCSI ID
- SRB_Lun : BYTE; // Target's LUN number
- SRB_Rsvd1 : array[0..11] of BYTE; // Reserved for Alignment
- SRB_HaStat : BYTE; // Host Adapter Status
- SRB_TargStat : BYTE; // Target Status
- SRB_PostProc : THandle; // Post routine
- SRB_Rsvd2 : POINTER; // Reserved
- SRB_Rsvd3 : array[0..31] of BYTE; // Reserved for alignment
- end;
- var
- Rsrb : SRB_ResetDevice;
- hEvent : THandle;
- 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(Rsrb, sizeof(Rsrb), 0);
- with Rsrb do begin
- SRB_Cmd := 4; { SC_RESET_DEV }
- SRB_HaId := fDeviceID.Adapter;
- SRB_Target := fDeviceID.Target;
- SRB_Lun := fDeviceID.Lun;
- SRB_PostProc := hEvent;
- end;
- if SendASPI32Command(@Rsrb) = 0 { SS_PENDING } then begin
- if WaitForSingleObject(hEvent,fShortTimeout) <> WAIT_OBJECT_0
- then begin
- fLastError := Err_NotifyTimeout;
- ASPIabortCommand(Rsrb.SRB_HaId, @Rsrb);
- end;
- end else fLastError := Err_NoDevice; {ASPI DLL says:"No such device"}
- CloseHandle(hEvent);
- if fLastError = Err_None then with Rsrb do
- Result := GetAspiError(SRB_Status, SRB_HaStat, SRB_TargStat);
- end;
- function TASPIDevice.ASPIgetDriveInt13info(DeviceAddress : TDeviceID;
- var Support, DosSupport : BOOLEAN;
- var DriveNumber, Heads, Sectors : BYTE) : BOOLEAN;
- type
- SRB_Int13info = packed record
- SRB_Cmd : BYTE; // ASPI command code=6=SC_GET_DIISK_INFO
- 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's SCSI ID
- SRB_Lun : BYTE; // Target's LUN number
- SRB_DriveFlags : BYTE; // Driver flags
- SRB_Int13Drive : BYTE; // Host Adapter Status
- SRB_Heads : BYTE; // Preferred number of heads translation
- SRB_Sectors : BYTE; // Preferred number of sectors translation
- SRB_Rsvd : array[0..9] of BYTE; // Reserved
- end;
- var Isrb : SRB_Int13info;
- begin
- FillChar(Isrb, sizeof(Isrb), 0);
- Isrb.SRB_Cmd := 6;
- Isrb.SRB_HaId := DeviceAddress.Adapter;
- Isrb.SRB_Target := DeviceAddress.Target;
- Isrb.SRB_Lun := DeviceAddress.Lun;
- SendASPI32Command(@Isrb);
- with Isrb do begin
- Result := GetAspiError(SRB_Status, $FF, $FF);
- Support := Result AND ((SRB_DriveFlags AND 3) <> 0);
- DosSupport := Result AND ((SRB_DriveFlags AND 1) <> 0);
- DriveNumber:= SRB_Int13Drive;
- Heads := SRB_Heads;
- Sectors := SRB_Sectors;
- end; end;
- function TASPIDevice.GetDeviceInfo(DId : TdeviceID;
- var DInfo : TScsiDeviceInfo) : BOOLEAN;
- const BufLen = 100;
- type CDdeviceInfo = packed record
- B : array[0..7] of byte;
- s1 : array[0..7] of char;
- s2 : array[0..15] of char;
- s3 : array[0..3] of char;
- s4 : array[0..19] of char;
- Rest: array[0..BufLen-57] of byte;
- end;
- var
- Buf : CDdeviceInfo;
- TempID : TdeviceID;
- begin
- TempID := fDeviceID;
- fDeviceID := DId;
- FillChar(Buf, BufLen, 0);
- result := ASPIsend6($12, 0, BufLen, @Buf, BufLen,
- SRB_DIR_IN, ShortTimeout); // SCSI Inquiry command
- if LastError = Err_None then with DInfo do begin
- PeripheralQualifier := Buf.B[0] SHR 5;
- DeviceType := Buf.B[0] AND $1F;
- DeviceTypeModifier := Buf.B[0] AND $7F;
- RemovableMedium := (Buf.B[1] AND $80) <> 0;
- ISOversion := (Buf.B[2] SHR 6) AND 3;
- ECMAversion := (Buf.B[2] SHR 3) AND 7;
- ANSIversion := Buf.B[2] AND 7;
- AsyncEventCapability := (Buf.B[3] AND $80) <> 0;
- TerminateIOcapability:= (Buf.B[3] AND $80) <> 0;
- ResponseDataFormat := Buf.B[3] AND $0F;
- AdditionalDataLength := Buf.B[4];
- WideBus32capability := (Buf.B[7] AND $40) <> 0;
- WideBus16capability := (Buf.B[7] AND $20) <> 0;
- RelativeAddressingCapability := (Buf.B[7] AND $80) <> 0;
- SynchronousTransferCapability := (Buf.B[7] AND $10) <> 0;
- LinkedCommandsCapability := (Buf.B[7] AND $08) <> 0;
- CommandQueuingCapability := (Buf.B[7] AND $02) <> 0;
- SoftResetCapability := (Buf.B[7] AND $01) <> 0;
- ASPIstrCopy(Buf.s1, VendorID, 8);
- ASPIstrCopy(Buf.s2, ProductID, 16);
- ASPIstrCopy(Buf.s3, ProductRevision, 4);
- ASPIstrCopy(Buf.s4, VendorSpecific, 20);
- end;
- fDeviceID := TempID;
- end;
- procedure TASPIDevice.ChangeDevice(Value : TdeviceID);
- begin
- fDeviceID := Value;
- ASPIgetDeviceType(Value, fDeviceType);
- GetDeviceInfo(Value, fDeviceInfo);
- ASPIhaInquiry(Value.Adapter, fHAinfo);
- end;
- procedure TASPIDevice.SetDeviceID(Value : TdeviceID);
- var Dtype : TScsiDeviceType;
- begin
- if ASPIgetDeviceType(Value, Dtype) then // if device exist
- if Dtype < TSDInvalid then ChangeDevice(Value);
- end;
- function TASPIDevice.EnumDevices(DType : TScsiDeviceType;
- CBack : TCallBackProc) : integer;
- var
- TID, DID : TDeviceID;
- DIDtype : TScsiDeviceType;
- Dadapter, Dtarget, Dlun : BYTE;
- begin
- result := 0;
- if fHAcount = 0 then exit; // no ASPI hosts, no devices
- TID := fDeviceID;
- for Dadapter := 0 to fHAcount-1 do
- if ASPIhaInquiry(Dadapter, fHAinfo) then begin
- DID.Adapter := Dadapter;
- for Dtarget := 0 to fHAinfo.MaxTargetCount-1 do begin
- DID.Target := Dtarget;
- for Dlun := 0 to 7 do begin
- DID.Lun := Dlun;
- if ASPIgetDeviceType(DID, DIDtype) then // if device exist
- if (DIDtype = DType) OR // and type match
- ((DIDtype < TSDInvalid) AND (DType = TSDAny))
- then begin
- SetDeviceID(DID);
- CBack;
- Inc(result);
- end; { if }
- end; { for Dlun }
- end; { for Dtarget }
- end; { for Dadapter }
- ChangeDevice(TID); // even if it has Invalid type !
- end;
- end.