Taspidev.pas
上传用户:jzxjwgb
上传日期:2007-01-06
资源大小:64k
文件大小:38k
源码类别:

SCSI/ASPI

开发平台:

Delphi

  1. unit TASPIDEV;
  2. // -----------------------------------------------------------------------------
  3. // Project:         CD-ROM and CD-audio Interface Components
  4. // Component Names: TASPIdevice
  5. // Module:          TAspiDev
  6. // Description:     Implements basic-level interface to wnaspi32.dll
  7. //                  and some of fundamental functions for SCSI interface,
  8. //                  that are device-type independent.
  9. // Version:         0.2 early beta
  10. // Date:            25-MAY-1999
  11. // Target:          Win32, Delphi3
  12. // Authors:         Sergey "KSER" Kabikov,   iamkser@hotmail.com
  13. // Copyright        (c) 1999 Sergey Kabikov
  14. // -----------------------------------------------------------------------------
  15. // -----------------------------------------------------------------------------
  16. // Acknowledgements:
  17. // 1. Thanks to Jay A. Key (scsiprog@geocities.com) for his "akrip" program,
  18. //    which sources (http://www.geocities.com/SiliconValley/Byte/7125/)
  19. //    helps to solve many problems.
  20. // -----------------------------------------------------------------------------
  21. interface
  22. uses Windows;
  23.   const      {=======  Possible values of Direction parameter ========}
  24.    SRB_NODIR   = $00;    // Direction determined by SCSI command
  25.    SRB_DIR_IN  = $08;    // Transfer from SCSI target to host
  26.    SRB_DIR_OUT = $10;    // Transfer from host to SCSI target
  27. type
  28.    TScsiDeviceType = (TSDDisk, TSDTape,  TSDPrinter, TSDProcessor,
  29.                       TSDWORM, TSDCDROM, TSDScanner, TSDOptical,
  30.                       TSDChanger, TSDCommunication, TSDInvalid, TSDAny);
  31. var
  32.    TScsiDeviceTypeName : array[TScsiDeviceType] of string = ('Disk Drive',
  33.       'Tape Drive', 'Printer', 'Processor', 'WORM Drive', 'CD-ROM Drive',
  34.       'Scanner', 'Optical Drive', 'Changer', 'Communication Device',
  35.       'Invalid', 'Any Type Device');
  36. type
  37.    TScsiError =     {======== Errors from SRB_Status field ========}
  38.     (Err_None,               Err_Aborted,            Err_InvalidRequest,
  39.      Err_HAerror,            Err_InvalidHostAdapter, Err_NoDevice,
  40.      Err_InvalidSrb,         Err_BufferAlign,        Err_AspiIsBusy,
  41.      Err_BufferTooBig,       Err_Unknown,
  42.                     {======== Errors from SRB_HaStat field ========}
  43.      Err_CommandTimeout,  { transaction time ran out }
  44.      Err_SrbTimeout,      { while waiting to process }
  45.      Err_MessageReject,
  46.      Err_BusReset,
  47.      Err_ParityError,
  48.      Err_RequestSenseFailed,
  49.      Err_SelectionTimeout,
  50.      Err_DataOverrun,         {... or underrun }
  51.      Err_UnexpectedBusFree,
  52.      Err_BusPhaseSequence,    {... failure }
  53.                     {======== Errors from SRB_TargStat field ========}
  54.      Err_CheckCondition,
  55.      Err_TargetBusy,
  56.      Err_TargetReservationConflict,
  57.      Err_TargetQueueFull,
  58.                     {======== Errors of SendScsiCommand ========}
  59.      Err_InvalidDevice, { Trying to exec SCSI command for non-exist device }
  60.      Err_NoEvent,       { Unable to get event handle for notification      }
  61.      Err_NotifyTimeout, { WaitForSingleObject result was unacceptable      }
  62.                     {======== Errors from SRB_Sense area ========}
  63.      Err_SenseUnknown,     // Unknown SRB_Sense.ErrorCode value
  64.      Err_SenseFileMark,
  65.      Err_SenseEndOfMedia,
  66.      Err_SenseIllegalLength,
  67.      Err_SenseIncorrectLength,
  68.      Err_SenseNoSense,        // There is no sense key info to be reported
  69.      Err_SenseRecoveredError, // Last command completed successfully with
  70.                      // some recovery action performed by the target.
  71.      Err_SenseNotReady,       // Unit addressed cannot be accessed.
  72.                               //  Operator intervention may be required.
  73.      Err_SenseMediumError,    // Command terminated with a non-recovered
  74.                      // error condition that was probably caused by a flaw
  75.                      // in the medium or an error in the recorded data.
  76.      Err_SenseHardwareError,  // Non-recoverable hardware failure detected
  77.      Err_SenseIllegalRequest, // Illegal parameter detected in the command
  78.                     // descriptor block or in the additional parameters.
  79.      Err_SenseUnitAttention,  // Removable medium may have been changed or
  80.                               // the target has been reset.
  81.      Err_SenseDataProtect,    // Read/Write Command was applied to the
  82.                     // block that is protected from this operation.
  83.      Err_SenseBlankCheck,     // Write-once device or a sequential-access
  84.                     // device encountered blank medium or end-of-data
  85.                     // indication while reading or a write-once device
  86.                     // encountered a non-blank medium while writing.
  87.      Err_SenseVendorSpecific,
  88.      Err_SenseCopyAborted,    // COPY, COMPARE, or COPY AND VERIFY command
  89.                     // was aborted due to an error condition on the source
  90.                     // device, the destination device, or both.
  91.      Err_SenseAbortedCommand, // Target aborted the command. Host may be
  92.                     // able to recover by trying the command again.
  93.      Err_SenseEqual,     // SEARCH DATA has satisfied an equal comparison.
  94.      Err_SenseVolumeOverflow, // Buffered peripheral device has reached
  95.                     // the end-of-partition and data may remain in the
  96.                     // buffer that has not been written to the medium.
  97.                     // RECOVER BUFFERED DATA command may be issued to read
  98.                     // the unwritten data from the buffer.
  99.      Err_SenseMiscompare,     // Source data did not match the data read
  100.                               // from the medium.
  101.      Err_SenseReserved
  102.      );
  103. var
  104.    ScsiErrorName : array[TScsiError] of string = ('Err_None',
  105.       'Err_Aborted', 'Err_InvalidRequest', 'Err_HAerror',
  106.       'Err_InvalidHostAdapter', 'Err_NoDevice', 'Err_InvalidSrb',
  107.       'Err_BufferAlign', 'Err_AspiIsBusy', 'Err_BufferTooBig',
  108.       'Err_Unknown', 'Err_CommandTimeout', 'Err_SrbTimeout',
  109.       'Err_MessageReject', 'Err_BusReset', 'Err_ParityError',
  110.       'Err_RequestSenseFailed', 'Err_SelectionTimeout',
  111.       'Err_DataOverrun', 'Err_UnexpectedBusFree',
  112.       'Err_BusPhaseSequence', 'Err_CheckCondition', 'Err_TargetBusy',
  113.       'Err_TargetReservationConflict', 'Err_TargetQueueFull',
  114.       'Err_InvalidDevice', 'Err_NoEvent', 'Err_NotifyTimeout',
  115.       'Err_SenseUnknown', 'Err_SenseFileMark', 'Err_SenseEndOfMedia',
  116.       'Err_SenseIllegalLength', 'Err_SenseIncorrectLength',
  117.       'Err_SenseNoSense', 'Err_SenseRecoveredError',
  118.       'Err_SenseNotReady', 'Err_SenseMediumError', 'Err_SenseHardwareError',
  119.       'Err_SenseIllegalRequest', 'Err_SenseUnitAttention',
  120.       'Err_SenseDataProtect', 'Err_SenseBlankCheck',
  121.       'Err_SenseVendorSpecific', 'Err_SenseCopyAborted',
  122.       'Err_SenseAbortedCommand', 'Err_SenseEqual',
  123.       'Err_SenseVolumeOverflow', 'Err_SenseMiscompare', 'Err_SenseReserved');
  124. type
  125.    TdeviceID  = record  Adapter, Target, Lun : byte;   end;
  126.    TscsiSenseInfo = array[0..127] of BYTE;
  127.    TCallBackProc = procedure;
  128.    TScsiDeviceInfo = packed record
  129.         PeripheralQualifier  : BYTE;
  130.           { 000b = Peripheral device type is currently connected to this
  131.                    logical unit. Especially for hot-swap devices. All fixed
  132.                    devices shall also use this peripheral qualifier.
  133.             001b = The target is capable of supporting the peripheral device;
  134.                    however, the physical device is not currently connected.
  135.             010b = Reserved.
  136.             011b = The target is not capable of supporting a physical device
  137.                    on this logical unit. It's illegal LUN for all commands.
  138.             1XXb = Vendor-specific codes.  }
  139.         DeviceType           : BYTE;
  140.           {  00h = Direct-access device (e.g. magnetic disk)
  141.              01h = Sequential-access device (e.g. magnetic tape)
  142.              02h = Printer device
  143.              03h = Processor device
  144.              04h = Write-once device (e.g. some optical disks)
  145.              05h = CD-ROM device
  146.              06h = Scanner device
  147.              07h = Optical memory device (e.g. some optical disks)
  148.              08h = Medium changer device (e.g. jukeboxes)
  149.              09h = Communications device
  150.              0Ah, 0Bh = Defined by ASC IT8 (Graphic arts pre-press devices)
  151.              0Ch..1Eh = Reserved
  152.              1Fh = Unknown or no device type  }
  153.         DeviceTypeModifier   : BYTE;     { Vendor-specific, in SCSI-I only }
  154.         RemovableMedium      : BOOLEAN;  { defines if medium is removable  }
  155.         ISOversion           : BYTE;     {compliance level to the ISO
  156.               version of SCSI (ISO 9316), 0 means no compliance acclaimed }
  157.         ECMAversion          : BYTE;     {compliance level to the ECMA
  158.               version of SCSI (ECMA-111), 0 means no compliance acclaimed }
  159.         ANSIversion          : BYTE;     {compliance level to the ANSI SCSI:
  160.              0 = The device might or might not comply to an ANSI standard,
  161.              1 = The device complies to ANSI SCSI-1,
  162.              2 = The device complies to ANSI SCSI-2, etc. }
  163.         AsyncEventCapability : BOOLEAN;  {indicates that the device supports
  164.              the asynchronous event notification capability. For Processor
  165.              device-type definition ONLY. Reserved for all other types. }
  166.         TerminateIOcapability: BOOLEAN;  {indicates that the device supports
  167.              the TERMINATE I/O PROCESS message }
  168.         ResponseDataFormat   : BYTE; { indicates the INQUIRY data format is:
  169.              0 = as specified in SCSI-1,
  170.              1 = products that were designed prior to the SCSI-2 (i.e. CCS),
  171.              2 = as specified in SCSI-2,
  172.              3..0Fh = reserved.  }
  173.         AdditionalDataLength : BYTE; { specifies the length in bytes of the
  174.              parameters, i.e. (full_record_length - 4). If the record length
  175.              specified here is too small to transfer all of the parameters,
  176.              this value shall not be adjusted to reflect the truncation. }
  177.         WideBus32capability  : BOOLEAN;  {indicates that the device supports
  178.              32-bit wide data transfers  }
  179.         WideBus16capability  : BOOLEAN;  {indicates that the device supports
  180.              16-bit wide data transfers.  If the values of both the WideBus
  181.              flags are false,the device only supports 8-bit data transfers.}
  182.         RelativeAddressingCapability  : BOOLEAN; { If this flag is set, the
  183.              linked (and ONLY linked) commands may use relative addressing }
  184.         SynchronousTransferCapability : BOOLEAN;  {indicates that the device
  185.              supports synchronous data transfers  }
  186.         LinkedCommandsCapability      : BOOLEAN;  {indicates that the device
  187.              supports execution of linked commands for this logical unit.  }
  188.         CommandQueuingCapability      : BOOLEAN;  {indicates that the device
  189.              supports tagged command queuing for this logical unit.        }
  190.         SoftResetCapability  : BOOLEAN;    { FALSE indicates that the device
  191.              responds to the RESET condition with hard RESET alternative,
  192.              TRUE - that it responds with the soft RESET alternative       }
  193.         VendorID             : string[8];
  194.         ProductID            : string[16];
  195.         ProductRevision      : string[4];
  196.         VendorSpecific       : string[20];
  197.            { All this strings are left-aligned ASCII data fields that shall
  198.              contain only graphic codes (i.e. code values 20h through 7Eh),
  199.              and the unused bytes shall be filled with space characters.   }
  200.    end;
  201.    TScsiHAinfo = packed record
  202.         ScsiId            : BYTE;
  203.         MaxTargetCount    : BYTE;
  204.         ResidualSupport   : BOOLEAN;
  205.         MaxTransferLength : DWORD;
  206.         BufferAlignMask   : WORD;
  207.         ScsiManagerId,
  208.         HostAdapterId     : String[16];
  209.    end;
  210.    TASPIDevice = class      { Common ASPI device class }
  211.       private
  212.         fHAcount      : DWORD;
  213.         fLastError    : TScsiError;
  214.         fSense        : TscsiSenseInfo;
  215.         fShortTimeout   : DWORD;
  216.         fMediumTimeout  : DWORD;
  217.         fLongTimeout    : DWORD;
  218.         fAudioTimeout   : DWORD;
  219.         fDeviceID     : TdeviceID;
  220.         fDeviceType   : TScsiDeviceType;
  221.         fDeviceInfo   : TScsiDeviceInfo;
  222.         fHAinfo       : TScsiHAinfo;
  223.       protected
  224.         function  GetAspiError(Status, HaStat, TargStat : BYTE) : BOOLEAN;
  225.         procedure ChangeDevice(Value : TdeviceID); virtual;
  226.         procedure SetDeviceID(Value : TdeviceID);
  227.       public
  228.         constructor Create(AOwner : TObject);
  229.         destructor  Destroy; override;
  230.           {===================== Raw ASPI functions ===================}
  231.         function    ASPIhaInquiry(HaId : BYTE;
  232.                var sh : TScsiHAinfo) : BOOLEAN;        //True if OK
  233.         function  ASPIgetDeviceType(DeviceAddress : TDeviceID;
  234.                var SDeviceType : TScsiDeviceType)               : BOOLEAN;
  235.         function  ASPIsendScsiCommand(Pcdb : pointer; CdbLen : DWORD;
  236.                Pbuf : pointer; BufLen : DWORD;       // Always works with
  237.                Direction, Timeout: DWORD) : BOOLEAN; //  'current' device
  238.         procedure ASPIabortCommand(HaId : BYTE; Psrb : pointer);
  239.         function  ASPIresetDevice : BOOLEAN;   // Resets 'current' device
  240.         function  ASPIgetDriveInt13info(DeviceAddress : TDeviceID;
  241.                var Support, DosSupport : BOOLEAN;
  242.                var DriveNumber, Heads, Sectors : BYTE) : BOOLEAN;
  243.                // NOTE: This command is NOT VALID under WinNT.
  244.                // Support=false -> no int 13 support anyway
  245.                // else if DosSupport=false -> supported on non-DOS basis
  246.                //  else -> supported under DOS control
  247.           {================== Mid-level ASPI functions ================}
  248.         function ASPIsend6(OpCode : BYTE; Lba : DWORD; Byte4 : BYTE;
  249.                Pbuf : pointer; BufLen, Direction,Timeout: DWORD) : BOOLEAN;
  250.         function ASPIsend10(OpCode : BYTE; Byte1 : BYTE;
  251.                Lba : DWORD; Byte6 : BYTE; Word7 : WORD;
  252.                Pbuf : pointer; BufLen, Direction,Timeout: DWORD) : BOOLEAN;
  253.         function ASPIsend12(OpCode : BYTE; Byte1 : BYTE;
  254.                Lba, TLength : DWORD; Byte10 : BYTE;
  255.                Pbuf : pointer; BufLen, Direction,Timeout: DWORD) : BOOLEAN;
  256.         function  GetDeviceInfo(DId : TdeviceID;
  257.                                 var DInfo : TScsiDeviceInfo) : BOOLEAN;
  258.         function  EnumDevices(DType: TScsiDeviceType; CBack: TCallBackProc)
  259.                : integer;   // Returns number of found devices.
  260.                             // Calls CBack() every time when finds one.
  261.         property HAcount      : DWORD      read fHAcount;
  262.         property Sense        : TscsiSenseInfo read fSense;
  263.         property LastError    : TScsiError read fLastError default Err_None;
  264.         property DeviceID     : TdeviceID read fDeviceID  write SetDeviceID;
  265.         property DeviceType   : TScsiDeviceType read fDeviceType;
  266.         property DeviceInfo   : TScsiDeviceInfo read fDeviceInfo;
  267.         property HAinfo       : TScsiHAinfo     read fHAinfo;
  268.       published
  269.         property ShortTimeout : DWORD read fShortTimeout  write fShortTimeout;
  270.         property MediumTimeout: DWORD read fMediumTimeout write fMediumTimeout;
  271.         property LongTimeout  : DWORD read fLongTimeout   write fLongTimeout;
  272.         property AudioTimeout : DWORD read fAudioTimeout  write fAudioTimeout;
  273.            // Set AudioTimeout corresponding to CD-ROM audio control  page
  274.            // parameter IMM. It shall be equal to ShortTimeout when IMM=TRUE
  275.            // and greater then estimated playback time elsewhere.
  276.       end;
  277. function GetASPI32SupportInfo               : DWORD; stdcall;
  278. function SendASPI32Command(LPSRB : pointer) : DWORD; stdcall;
  279. function BigEndianW(Arg : WORD)          : WORD;
  280. function BigEndianD(Arg : DWORD)         : DWORD;
  281. function GatherWORD(b1,b0 : byte) : WORD;
  282. function GatherDWORD(b3,b2,b1,b0 : byte) : DWORD;
  283. implementation
  284. function GetASPI32SupportInfo; external 'WNASPI32' name 'GetASPI32SupportInfo';
  285. function SendASPI32Command;    external 'WNASPI32' name 'SendASPI32Command';
  286. function BigEndianW(Arg : WORD) : WORD;
  287.    begin  result := ((Arg SHL 8) AND $FF00) OR
  288.                     ((Arg SHR 8) AND $00FF);    end;
  289. function BigEndianD(Arg : DWORD) : DWORD;
  290.    begin
  291.       result := ((Arg SHL 24) AND $FF000000) OR
  292.                 ((Arg SHL  8) AND $00FF0000) OR
  293.                 ((Arg SHR  8) AND $0000FF00) OR
  294.                 ((Arg SHR 24) AND $000000FF);
  295.    end;
  296. function GatherWORD(b1,b0 : byte) : WORD;
  297.    begin
  298.       result := ((WORD(b1) SHL 8) AND $FF00) OR
  299.                 ((WORD(b0)      ) AND $00FF);
  300.    end;
  301. function GatherDWORD(b3,b2,b1,b0 : byte) : DWORD;
  302.    begin
  303.       result := ((LongInt(b3) SHL 24) AND $FF000000) OR
  304.                 ((LongInt(b2) SHL 16) AND $00FF0000) OR
  305.                 ((LongInt(b1) SHL  8) AND $0000FF00) OR
  306.                 ((LongInt(b0)       ) AND $000000FF);
  307.    end;
  308. function TASPIDevice.GetAspiError(Status,HaStat,TargStat: BYTE): BOOLEAN;
  309.    begin
  310.       result     := false;
  311.       fLastError := Err_None;
  312.       case Status of
  313.          0,1: result := true;              // No error, all OK
  314.          2,3: fLastError := Err_Aborted;
  315.          $80: fLastError := Err_InvalidRequest;   // This command is
  316.                                     // not supported by ASPI manager
  317.          $81: fLastError := Err_InvalidHostAdapter;
  318.          $82: fLastError := Err_NoDevice;
  319.          $E0: fLastError := Err_InvalidSrb;
  320.          $E1: fLastError := Err_BufferAlign;
  321.          $E5: fLastError := Err_AspiIsBusy;
  322.          $E6: fLastError := Err_BufferTooBig;
  323.          4: case HaStat of
  324.             $09 : fLastError := Err_CommandTimeout;
  325.             $0B : fLastError := Err_SrbTimeout;
  326.             $0D : fLastError := Err_MessageReject;
  327.             $0E : fLastError := Err_BusReset;
  328.             $0F : fLastError := Err_ParityError;
  329.             $10 : fLastError := Err_RequestSenseFailed;
  330.             $11 : fLastError := Err_SelectionTimeout;
  331.             $12 : fLastError := Err_DataOverrun;
  332.             $13 : fLastError := Err_UnexpectedBusFree;
  333.             $14 : fLastError := Err_BusPhaseSequence;
  334.             $00 : case TargStat of
  335.                0,2: fLastError := Err_CheckCondition;
  336.                $08: fLastError := Err_TargetBusy;
  337.                $18: fLastError := Err_TargetReservationConflict;
  338.                $28: fLastError := Err_TargetQueueFull
  339.                else fLastError := Err_Unknown;
  340.               end
  341.             else    fLastError := Err_Unknown;
  342.           end
  343.        else         fLastError := Err_Unknown;
  344.    end; end;
  345. procedure ASPIstrCopy(Src : PChar; var Dst : ShortString; Leng : Integer);
  346.    var i : integer;
  347.    begin
  348.       i := 0;
  349.       while (i < Leng) AND (Src[i] >= ' ') do
  350.         begin  Dst[i+1] := Src[i];   inc(i);   end;
  351.       Dst[0] := CHR(i);
  352.    end;
  353. constructor  TASPIDevice.Create;
  354.    var I : DWORD;
  355.    begin
  356.       inherited Create;
  357.       I := GetASPI32SupportInfo;
  358.       if (I AND $0000FE00) <> 0 then fHAcount := 0
  359.                                 else fHAcount := I AND $000000FF;
  360.       FillChar(fSense, sizeof(fSense), 0);
  361.       fLastError        := Err_None;
  362.       fShortTimeout     := 1000;     // 1 sec
  363.       fMediumTimeout    := 60000;    // 1 min
  364.       fLongTimeout      := 3600000;  // 1 hour
  365.       fAudioTimeout     := fShortTimeout;
  366.       fDeviceID.Adapter := $81;      // Invalid host adapter
  367.       fDeviceID.Target  := 0;
  368.       fDeviceID.Lun     := 0;
  369.       fDeviceType       := TSDInvalid;
  370.    end;
  371. destructor   TASPIDevice.Destroy;
  372.    begin  inherited Destroy;  end;
  373. function TASPIDevice.ASPIhaInquiry(HaId : BYTE;
  374.                var sh : TScsiHAinfo) : BOOLEAN;             //True if OK
  375.    type SRB_Inquiry = packed record
  376.         SRB_Cmd       : BYTE;    // ASPI command code = 0 = SC_HA_INQUIRY
  377.         SRB_Status    : BYTE;    // ASPI command status byte
  378.         SRB_HaId      : BYTE;    // ASPI host adapter number
  379.         SRB_Flags     : BYTE;    // Reserved
  380.         SRB_Hdr_Rsvd  : DWORD;   // Reserved
  381.         SRB_HA_Count  : BYTE;    // same as in GetASPIsupportInfo
  382.         SRB_HA_SCSIID : BYTE;    // SCSI Id of selected host adapter
  383.         SRB_ManagerID,                   // MustBe = 'ASPI for WIN32'
  384.         SRB_AdapterID                    // String describing selected HA
  385.                 : array[0..15] of char;
  386.         SRB_BufAlign  : WORD;  // Buffer alignment mask: 0=byte, 1=word,
  387.                                          // 3=dword, 7=8-byte, etc. 65536 bytes max
  388.         SRB_Residual  : BYTE;    // Bit1 = residual count support flag
  389.         SRB_Targets   : BYTE;    // Max target count for selected HA
  390.         SRB_TransfLen : DWORD;   // Max transfer length in bytes
  391.         SRB_Rsvd : array[0..9] of byte;
  392.      end;
  393.    var Isrb : SRB_Inquiry;
  394.    begin
  395.       FillChar(Isrb, sizeof(Isrb), 0);
  396.       Isrb.SRB_Cmd      := 0;
  397.       Isrb.SRB_HaId     := HaId;
  398.       SendASPI32Command(@Isrb);
  399.       with Isrb do begin
  400.          Result := GetAspiError(SRB_Status, $FF, $FF);
  401.          sh.ScsiId := SRB_HA_SCSIID;
  402.          ASPIstrCopy(SRB_ManagerID, sh.ScsiManagerId, 16);
  403.          ASPIstrCopy(SRB_AdapterID, sh.HostAdapterId, 16);
  404.          sh.BufferAlignMask := SRB_BufAlign;
  405.          sh.ResidualSupport := (SRB_Residual AND 2) <> 0;
  406.          if SRB_Targets = 0 then sh.MaxTargetCount := 8
  407.                             else sh.MaxTargetCount := SRB_Targets;
  408.          sh.MaxTransferLength := SRB_TransfLen;
  409.    end; end;
  410. function TASPIDevice.ASPIgetDeviceType(DeviceAddress : TDeviceID;
  411.                 var SDeviceType : TScsiDeviceType) : BOOLEAN;   //True if OK
  412.    type SRB_GetDeviceType = packed record
  413.         SRB_Cmd       : BYTE;    // ASPI command code = 1 = SC_GET_DEV_TYPE
  414.         SRB_Status    : BYTE;    // ASPI command status byte
  415.         SRB_HaId      : BYTE;    // ASPI host adapter number
  416.         SRB_Flags     : BYTE;    // Reserved
  417.         SRB_Hdr_Rsvd  : DWORD;   // Reserved
  418.         SRB_Target    : BYTE;    // Target number for specified HA
  419.         SRB_Lun       : BYTE;    // Logical unit number of selected target
  420.         SRB_DeviceType: BYTE;    // Selected HA/Target/Lun device type
  421.         SRB_Rsvd      : BYTE;    // Reserved for alignment
  422.      end;
  423.    var Gsrb : SRB_GetDeviceType;
  424.    begin
  425.       FillChar(Gsrb, sizeof(Gsrb), 0);
  426.       Gsrb.SRB_Cmd      := 1;
  427.       Gsrb.SRB_HaId     := DeviceAddress.Adapter;
  428.       Gsrb.SRB_Target   := DeviceAddress.Target;
  429.       Gsrb.SRB_Lun      := DeviceAddress.Lun;
  430.       SendASPI32Command(@Gsrb);
  431.       Result := GetAspiError(Gsrb.SRB_Status, $FF, $FF);
  432.       if Result AND (Gsrb.SRB_DeviceType < ORD(TSDInvalid))
  433.         then SDeviceType := TScsiDeviceType(Gsrb.SRB_DeviceType)
  434.         else SDeviceType := TSDInvalid;
  435.    end;
  436. procedure TASPIDevice.ASPIabortCommand(HaId : BYTE; Psrb : pointer);
  437.    type SRB_Abort = packed record
  438.         SRB_Cmd      : BYTE;    // ASPI command code = 3 = SC_ABORT_SRB
  439.         SRB_Status   : BYTE;    // ASPI command status byte
  440.         SRB_HaId     : BYTE;    // ASPI host adapter number
  441.         SRB_Flags    : BYTE;    // Reserved
  442.         SRB_Hdr_Rsvd : DWORD;   // Reserved
  443.         SRB_ToAbort  : pointer; // Pointer to SRB to abort
  444.      end;
  445.    var  Asrb : SRB_Abort;
  446.    begin
  447.       FillChar(Asrb, sizeof(Asrb), 0);
  448.       Asrb.SRB_Cmd      := 3;
  449.       Asrb.SRB_HaId     := HaId;
  450.       Asrb.SRB_ToAbort  := Psrb;
  451.       SendASPI32Command(@Asrb);
  452.    end;
  453. function TASPIDevice.ASPIsendScsiCommand(Pcdb : pointer; CdbLen : DWORD;
  454.                 Pbuf : pointer; BufLen : DWORD;
  455.                 Direction,      Timeout: DWORD) : BOOLEAN; //True if OK
  456.    type
  457.       SRB_ExecSCSICmd = packed record
  458.          SRB_Cmd      : BYTE;    // ASPI command code= 2 =SC_EXEC_SCSI_CMD
  459.          SRB_Status   : BYTE;    // ASPI command status byte
  460.          SRB_HaId     : BYTE;    // ASPI host adapter number
  461.          SRB_Flags    : BYTE;    // ASPI request flags
  462.          SRB_Hdr_Rsvd : DWORD;   // Reserved
  463.          SRB_Target   : BYTE;    // Target's SCSI ID
  464.          SRB_Lun      : BYTE;    // Target's LUN number
  465.          SRB_Rsvd1    : WORD;    // Reserved for Alignment
  466.          SRB_BufLen   : DWORD;   // Data Allocation Length
  467.          SRB_BufPtr   : POINTER; // Data Buffer Pointer
  468.          SRB_SenseLen : BYTE;    // Sense Allocation Length
  469.          SRB_CDBLen   : BYTE;    // CDB Length
  470.          SRB_HaStat   : BYTE;    // Host Adapter Status
  471.          SRB_TargStat : BYTE;    // Target Status
  472.          SRB_PostProc : THandle; // Post routine
  473.          SRB_Rsvd2    : POINTER; // Reserved
  474.          SRB_Rsvd3    : array[0..15] of BYTE;  // Reserved for alignment
  475.          SRB_CDBByte  : array[0..15] of BYTE;  // SCSI CDB
  476.          SRB_Sense    : TscsiSenseInfo;        // Request Sense buf
  477.       end;
  478. var
  479.    Esrb      : SRB_ExecSCSICmd;
  480.    hEvent    : THandle;
  481.    SenseKeys : BYTE;
  482. begin
  483.    result := false;
  484.    fLastError := Err_None;
  485.    FillChar(fSense, sizeof(fSense), 0);
  486.    if fDeviceType = TSDInvalid then
  487.      begin  fLastError := Err_InvalidDevice;    exit;  end;
  488.    hEvent := CreateEvent(NIL,true,false,NIL); {event to notify completion}
  489.    if hEvent = 0 then begin  fLastError := Err_NoEvent;  exit;  end;
  490.    ResetEvent(hEvent);
  491.    FillChar(Esrb, sizeof(Esrb), 0);        { Scsi Request Block init }
  492.    with Esrb do begin
  493.       SRB_Cmd      := 2;  { SC_EXEC_SCSI_CMD }
  494.       SRB_HaId     := fDeviceID.Adapter;
  495.       SRB_Flags    := Direction OR $40;   { set SRB_EVENT_NOTIFY flag }
  496.       SRB_Target   := fDeviceID.Target;
  497.       SRB_Lun      := fDeviceID.Lun;
  498.       SRB_BufLen   := BufLen;
  499.       SRB_BufPtr   := Pbuf;
  500.       SRB_SenseLen := sizeof(TscsiSenseInfo) - 2;
  501.       if CdbLen > 16 then SRB_CDBLen := 16 else SRB_CDBLen := CdbLen;
  502.       SRB_PostProc := hEvent;
  503.       Move(Pcdb^, SRB_CDBByte, SRB_CDBLen);
  504.    end;
  505.    if SendASPI32Command(@Esrb) = 0 { SS_PENDING } then begin
  506.       if WaitForSingleObject(hEvent,Timeout) <> WAIT_OBJECT_0 then begin
  507.          fLastError := Err_NotifyTimeout;
  508.          ASPIabortCommand(Esrb.SRB_HaId, @Esrb);
  509.       end;
  510.    end else fLastError := Err_NoDevice;  {ASPI DLL says:"No such device"}
  511.    CloseHandle(hEvent);
  512.    if fLastError = Err_None then with Esrb do begin
  513.       fSense := SRB_Sense;
  514.       GetAspiError(SRB_Status, SRB_HaStat, SRB_TargStat);
  515.    end;
  516.    if fLastError = Err_CheckCondition then with Esrb do
  517.     if SRB_Sense[0] = 0
  518.      then fLastError := Err_None
  519.      else if (SRB_Sense[0] AND $7E) <> $70             // recognized values
  520.       then fLastError := Err_SenseUnknown
  521.       else begin
  522.        SenseKeys := SRB_Sense[2];
  523.        case (SenseKeys AND $0F) of
  524.         0: begin                                    // Skey_NoSense
  525.              if (SenseKeys AND $80) <> 0            // FileMark flag
  526.               then fLastError := Err_SenseFileMark
  527.              else if (SenseKeys AND $40) <> 0       // EndOfMedia flag
  528.               then fLastError := Err_SenseEndOfMedia
  529.              else if (SenseKeys AND $20) <> 0       // IllegalLength flag
  530.               then fLastError := Err_SenseIllegalLength
  531.              else if (SRB_Sense[3] AND $80) <> 0    // ResidualCount < 0
  532.               then fLastError := Err_SenseIncorrectLength
  533.              else  fLastError := Err_SenseNoSense;
  534.            end;
  535.         1: fLastError := Err_SenseRecoveredError;  //Skey_RecoveredError
  536.         2: fLastError := Err_SenseNotReady;        //Skey_NotReady
  537.         3: fLastError := Err_SenseMediumError;     //Skey_MediumError
  538.         4: fLastError := Err_SenseHardwareError;   //Skey_HardwareError
  539.         5: fLastError := Err_SenseIllegalRequest;  //Skey_IllegalRequest
  540.         6: fLastError := Err_SenseUnitAttention;   //Skey_UnitAttention
  541.         7: fLastError := Err_SenseDataProtect;     //Skey_DataProtect
  542.         8: fLastError := Err_SenseBlankCheck;      //Skey_BlankCheck
  543.         9: fLastError := Err_SenseVendorSpecific;  // Skey_VendorSpecific
  544.         10:fLastError := Err_SenseCopyAborted;     // Skey_CopyAborted
  545.         11:fLastError := Err_SenseAbortedCommand;  // Skey_AbortedCommand
  546.         12:fLastError := Err_SenseEqual;           // Skey_Equal
  547.         13:fLastError := Err_SenseVolumeOverflow;  // Skey_VolumeOverflow
  548.         14:fLastError := Err_SenseMiscompare;      // Skey_Miscompare
  549.         15:fLastError := Err_SenseReserved;        // Skey_Reserved
  550.    end; end;
  551.    result := (fLastError = Err_None) OR
  552.              (fLastError = Err_SenseRecoveredError);
  553. end;
  554. function TASPIDevice.ASPIsend6(OpCode: BYTE; Lba : DWORD; Byte4 : BYTE;
  555.         Pbuf: pointer; BufLen: DWORD; Direction,Timeout: DWORD) : BOOLEAN;
  556.    var cdb : array[0..5] of BYTE;
  557.    begin
  558.       FillChar(Pbuf^, BufLen, 0);
  559.       cdb[5] := 0;
  560.       cdb[4] := Byte4;
  561.       cdb[3] := BYTE(Lba AND $FF);    Lba := Lba SHR 8;
  562.       cdb[2] := BYTE(Lba AND $FF);    Lba := Lba SHR 8;
  563.       cdb[1] := ((fDeviceID.Lun AND 7) SHL 5) OR BYTE(Lba AND $1F);
  564.       cdb[0] := OpCode;
  565.       result := ASPIsendScsiCommand(@cdb,6,Pbuf,BufLen,Direction,Timeout);
  566.    end;
  567. function TASPIDevice.ASPIsend10(OpCode : BYTE;
  568.         Byte1 : BYTE; Lba : DWORD; Byte6 : BYTE; Word7 : WORD;
  569.         Pbuf: pointer; BufLen: DWORD; Direction,Timeout: DWORD) : BOOLEAN;
  570.    var cdb : array[0..9] of BYTE;
  571.    begin
  572.       FillChar(Pbuf^, BufLen, 0);
  573.       cdb[9] := 0;
  574.       cdb[8] := BYTE(Word7 AND $FF);    Word7 := Word7 SHR 8;
  575.       cdb[7] := BYTE(Word7 AND $FF);
  576.       cdb[6] := Byte6;
  577.       cdb[5] := BYTE(Lba AND $FF);    Lba := Lba SHR 8;
  578.       cdb[4] := BYTE(Lba AND $FF);    Lba := Lba SHR 8;
  579.       cdb[3] := BYTE(Lba AND $FF);    Lba := Lba SHR 8;
  580.       cdb[2] := BYTE(Lba AND $FF);
  581.       cdb[1] := ((fDeviceID.Lun AND 7) SHL 5) OR (Byte1 AND $1F);
  582.       cdb[0] := OpCode;
  583.       result := ASPIsendScsiCommand(@cdb,10,Pbuf,BufLen,Direction,Timeout);
  584.    end;
  585. function TASPIDevice.ASPIsend12(OpCode : BYTE;
  586.       Byte1 : BYTE; Lba : DWORD; TLength : DWORD; Byte10 : BYTE;
  587.       Pbuf : pointer; BufLen : DWORD; Direction,Timeout : DWORD) : BOOLEAN;
  588.    var cdb : array[0..11] of BYTE;
  589.    begin
  590.       FillChar(Pbuf^, BufLen, 0);
  591.       cdb[11]:= 0;
  592.       cdb[10]:= Byte10;
  593.       cdb[9] := BYTE(TLength AND $FF);   TLength := TLength SHR 8;
  594.       cdb[8] := BYTE(TLength AND $FF);   TLength := TLength SHR 8;
  595.       cdb[7] := BYTE(TLength AND $FF);   TLength := TLength SHR 8;
  596.       cdb[6] := BYTE(TLength AND $FF);
  597.       cdb[5] := BYTE(Lba AND $FF);       Lba := Lba SHR 8;
  598.       cdb[4] := BYTE(Lba AND $FF);       Lba := Lba SHR 8;
  599.       cdb[3] := BYTE(Lba AND $FF);       Lba := Lba SHR 8;
  600.       cdb[2] := BYTE(Lba AND $FF);
  601.       cdb[1] := ((fDeviceID.Lun AND 7) SHL 5) OR (Byte1 AND $1F);
  602.       cdb[0] := OpCode;
  603.       result := ASPIsendScsiCommand(@cdb,12,Pbuf,BufLen,Direction,Timeout);
  604.    end;
  605. function TASPIDevice.ASPIresetDevice : BOOLEAN;   // Resets 'current' device
  606.    type
  607.       SRB_ResetDevice = packed record
  608.          SRB_Cmd      : BYTE;    // ASPI command code = 4 = SC_RESET_DEV
  609.          SRB_Status   : BYTE;    // ASPI command status byte
  610.          SRB_HaId     : BYTE;    // ASPI host adapter number
  611.          SRB_Flags    : BYTE;    // Reserved
  612.          SRB_Hdr_Rsvd : DWORD;   // Reserved
  613.          SRB_Target   : BYTE;    // Target's SCSI ID
  614.          SRB_Lun      : BYTE;    // Target's LUN number
  615.          SRB_Rsvd1    : array[0..11] of BYTE; // Reserved for Alignment
  616.          SRB_HaStat   : BYTE;    // Host Adapter Status
  617.          SRB_TargStat : BYTE;    // Target Status
  618.          SRB_PostProc : THandle; // Post routine
  619.          SRB_Rsvd2    : POINTER; // Reserved
  620.          SRB_Rsvd3    : array[0..31] of BYTE;  // Reserved for alignment
  621.       end;
  622. var
  623.    Rsrb   : SRB_ResetDevice;
  624.    hEvent : THandle;
  625. begin
  626.    result := false;
  627.    fLastError := Err_None;
  628.    FillChar(fSense, sizeof(fSense), 0);
  629.    if fDeviceType = TSDInvalid then
  630.      begin  fLastError := Err_InvalidDevice;    exit;  end;
  631.    hEvent := CreateEvent(NIL,true,false,NIL); {event to notify completion}
  632.    if hEvent = 0 then begin  fLastError := Err_NoEvent;  exit;  end;
  633.    ResetEvent(hEvent);
  634.    FillChar(Rsrb, sizeof(Rsrb), 0);
  635.    with Rsrb do begin
  636.       SRB_Cmd      := 4;  { SC_RESET_DEV }
  637.       SRB_HaId     := fDeviceID.Adapter;
  638.       SRB_Target   := fDeviceID.Target;
  639.       SRB_Lun      := fDeviceID.Lun;
  640.       SRB_PostProc := hEvent;
  641.    end;
  642.    if SendASPI32Command(@Rsrb) = 0 { SS_PENDING } then begin
  643.       if WaitForSingleObject(hEvent,fShortTimeout) <> WAIT_OBJECT_0
  644.        then begin
  645.          fLastError := Err_NotifyTimeout;
  646.          ASPIabortCommand(Rsrb.SRB_HaId, @Rsrb);
  647.       end;
  648.    end else fLastError := Err_NoDevice;  {ASPI DLL says:"No such device"}
  649.    CloseHandle(hEvent);
  650.    if fLastError = Err_None then with Rsrb do
  651.       Result := GetAspiError(SRB_Status, SRB_HaStat, SRB_TargStat);
  652. end;
  653. function TASPIDevice.ASPIgetDriveInt13info(DeviceAddress : TDeviceID;
  654.                var Support, DosSupport : BOOLEAN;
  655.                var DriveNumber, Heads, Sectors : BYTE) : BOOLEAN;
  656.    type
  657.       SRB_Int13info = packed record
  658.          SRB_Cmd        : BYTE;  // ASPI command code=6=SC_GET_DIISK_INFO
  659.          SRB_Status     : BYTE;  // ASPI command status byte
  660.          SRB_HaId       : BYTE;  // ASPI host adapter number
  661.          SRB_Flags      : BYTE;  // Reserved
  662.          SRB_Hdr_Rsvd   : DWORD; // Reserved
  663.          SRB_Target     : BYTE;  // Target's SCSI ID
  664.          SRB_Lun        : BYTE;  // Target's LUN number
  665.          SRB_DriveFlags : BYTE;  // Driver flags
  666.          SRB_Int13Drive : BYTE;  // Host Adapter Status
  667.          SRB_Heads      : BYTE;  // Preferred number of heads translation
  668.          SRB_Sectors    : BYTE;  // Preferred number of sectors translation
  669.          SRB_Rsvd       : array[0..9] of BYTE;  // Reserved
  670.       end;
  671.    var Isrb : SRB_Int13info;
  672.    begin
  673.       FillChar(Isrb, sizeof(Isrb), 0);
  674.       Isrb.SRB_Cmd      := 6;
  675.       Isrb.SRB_HaId     := DeviceAddress.Adapter;
  676.       Isrb.SRB_Target   := DeviceAddress.Target;
  677.       Isrb.SRB_Lun      := DeviceAddress.Lun;
  678.       SendASPI32Command(@Isrb);
  679.       with Isrb do begin
  680.          Result := GetAspiError(SRB_Status, $FF, $FF);
  681.          Support    := Result AND ((SRB_DriveFlags AND 3) <> 0);
  682.          DosSupport := Result AND ((SRB_DriveFlags AND 1) <> 0);
  683.          DriveNumber:= SRB_Int13Drive;
  684.          Heads      := SRB_Heads;
  685.          Sectors    := SRB_Sectors;
  686.    end; end;
  687. function  TASPIDevice.GetDeviceInfo(DId : TdeviceID;
  688.                           var DInfo : TScsiDeviceInfo) : BOOLEAN;
  689.    const BufLen = 100;
  690.    type CDdeviceInfo = packed record
  691.           B   : array[0..7]  of byte;
  692.           s1  : array[0..7]  of char;
  693.           s2  : array[0..15] of char;
  694.           s3  : array[0..3]  of char;
  695.           s4  : array[0..19] of char;
  696.           Rest: array[0..BufLen-57] of byte;
  697.       end;
  698.    var
  699.       Buf    : CDdeviceInfo;
  700.       TempID : TdeviceID;
  701.    begin
  702.       TempID    := fDeviceID;
  703.       fDeviceID := DId;
  704.       FillChar(Buf, BufLen, 0);
  705.       result := ASPIsend6($12, 0, BufLen, @Buf, BufLen,
  706.                SRB_DIR_IN, ShortTimeout);        // SCSI Inquiry command
  707.       if LastError = Err_None then with DInfo do begin
  708.          PeripheralQualifier  :=  Buf.B[0] SHR 5;
  709.          DeviceType           :=  Buf.B[0] AND $1F;
  710.          DeviceTypeModifier   :=  Buf.B[0] AND $7F;
  711.          RemovableMedium      := (Buf.B[1] AND $80) <> 0;
  712.          ISOversion           := (Buf.B[2] SHR 6) AND 3;
  713.          ECMAversion          := (Buf.B[2] SHR 3) AND 7;
  714.          ANSIversion          :=  Buf.B[2] AND 7;
  715.          AsyncEventCapability := (Buf.B[3] AND $80) <> 0;
  716.          TerminateIOcapability:= (Buf.B[3] AND $80) <> 0;
  717.          ResponseDataFormat   :=  Buf.B[3] AND $0F;
  718.          AdditionalDataLength :=  Buf.B[4];
  719.          WideBus32capability           := (Buf.B[7] AND $40) <> 0;
  720.          WideBus16capability           := (Buf.B[7] AND $20) <> 0;
  721.          RelativeAddressingCapability  := (Buf.B[7] AND $80) <> 0;
  722.          SynchronousTransferCapability := (Buf.B[7] AND $10) <> 0;
  723.          LinkedCommandsCapability      := (Buf.B[7] AND $08) <> 0;
  724.          CommandQueuingCapability      := (Buf.B[7] AND $02) <> 0;
  725.          SoftResetCapability           := (Buf.B[7] AND $01) <> 0;
  726.          ASPIstrCopy(Buf.s1, VendorID,  8);
  727.          ASPIstrCopy(Buf.s2, ProductID, 16);
  728.          ASPIstrCopy(Buf.s3, ProductRevision, 4);
  729.          ASPIstrCopy(Buf.s4, VendorSpecific, 20);
  730.       end;
  731.       fDeviceID := TempID;
  732.    end;
  733. procedure TASPIDevice.ChangeDevice(Value : TdeviceID);
  734.    begin
  735.       fDeviceID   := Value;
  736.       ASPIgetDeviceType(Value, fDeviceType);
  737.       GetDeviceInfo(Value, fDeviceInfo);
  738.       ASPIhaInquiry(Value.Adapter, fHAinfo);
  739.    end;
  740. procedure TASPIDevice.SetDeviceID(Value : TdeviceID);
  741.    var Dtype : TScsiDeviceType;
  742.    begin
  743.       if ASPIgetDeviceType(Value, Dtype) then   // if device exist
  744.        if Dtype < TSDInvalid then ChangeDevice(Value);
  745.    end;
  746. function  TASPIDevice.EnumDevices(DType : TScsiDeviceType;
  747.                                   CBack : TCallBackProc) : integer;
  748.    var
  749.       TID, DID                : TDeviceID;
  750.       DIDtype                 : TScsiDeviceType;
  751.       Dadapter, Dtarget, Dlun : BYTE;
  752.    begin
  753.       result := 0;
  754.       if fHAcount = 0 then exit;    // no ASPI hosts, no devices
  755.       TID := fDeviceID;
  756.       for Dadapter := 0 to fHAcount-1 do
  757.        if ASPIhaInquiry(Dadapter, fHAinfo) then begin
  758.          DID.Adapter := Dadapter;
  759.          for Dtarget := 0 to fHAinfo.MaxTargetCount-1 do begin
  760.             DID.Target := Dtarget;
  761.             for Dlun := 0 to 7 do begin
  762.                DID.Lun := Dlun;
  763.                if ASPIgetDeviceType(DID, DIDtype) then  // if device exist
  764.                 if (DIDtype = DType) OR                 //  and type match
  765.                   ((DIDtype < TSDInvalid) AND (DType = TSDAny))
  766.                    then begin
  767.                   SetDeviceID(DID);
  768.                   CBack;
  769.                   Inc(result);
  770.                end;   { if }
  771.             end;      { for Dlun }
  772.          end;      { for Dtarget }
  773.       end;        { for Dadapter }
  774.       ChangeDevice(TID);           // even if it has Invalid type !
  775.    end;
  776. end.