home *** CD-ROM | disk | FTP | other *** search
- unit CAM;
-
- {$A-}
-
- { This Turbo Pascal 6.0 unit is an object-oriented interface to
- BallardSynergy's CAMpatible SCSI drivers, Version 1.302.
- Please note that the CAM specification is still in flux
- so these bindings may need to change to accommodate changes
- in the interface. }
-
- { Turbo Pascal bindings Copyright (C) 1991 by Brett Glass, All Rights Reserved.
- Original C bindings, sample code, and assembly language Copyright (C) 1990
- by BallardSynergy, All Rights Reserved. Used with permission. }
-
- interface
-
- function CAMPresent : Boolean; { Return TRUE if a CAM driver is installed }
-
- { This enumerated type gives the CAM function codes for the BallardSynergy
- implementation of CAM, version 1.302. The numbering is different from
- that found in the CAM UNIX bindings and in Microsoft's LADDR spec. }
-
- type CAMFunctionCode = (
- FUNC_UNUSED_00,
- FUNC_ABORT_SCSI_COMMAND,
- FUNC_EXECUTE_SCSI_IO,
- FUNC_GET_DEVICE_TYPE,
- FUNC_UNUSED_04,
- FUNC_PATH_INQUIRY,
- FUNC_RELEASE_SIM_QUEUE,
- FUNC_RESET_SCSI_BUS,
- FUNC_RESET_SCSI_DEVICE,
- FUNC_SET_ASYNC_CALLBACK,
- FUNC_SET_DEVICE_TYPE,
- FUNC_SET_HBA_PARAMETERS,
- {Create dummy names to reserve unused function numbers}
- FUNC_UNUSED_0C, FUNC_UNUSED_0D, FUNC_UNUSED_0E, FUNC_UNUSED_0F,
- FUNC_UNUSED_10, FUNC_UNUSED_11, FUNC_UNUSED_12, FUNC_UNUSED_13,
- FUNC_UNUSED_14, FUNC_UNUSED_15, FUNC_UNUSED_16, FUNC_UNUSED_17,
- FUNC_UNUSED_18, FUNC_UNUSED_19, FUNC_UNUSED_1A, FUNC_UNUSED_1B,
- FUNC_UNUSED_1C, FUNC_UNUSED_1D, FUNC_UNUSED_1E, FUNC_UNUSED_1F,
- FUNC_CHANGE_OS2_NAME,
- FUNC_ROM_DEBUGS);
-
- type
- SCSIid = 0..7;
-
- { This abstract superclass is the "father" of all classes of CAM
- Control Blocks (CCBs). }
-
- type CCB = object
- ccbLen : Word; {Length of CAM Control Block (CCB)}
- funcCode : CAMFunctionCode; {XPT Function Code}
- camStatus : Byte; {Returned CAM subsystem status}
- scsiStatus : Byte; {Returned SCSI status}
- pathId : Byte; {Adapter to do request}
- camFlags : Longint; {Flags containing transaction parameters}
-
- {Note: CCB.Setup is called by the constructors of the child
- classes of CCB, but is *not* a constructor itself. If
- it were, a VMT pointer would be allocated between the
- fields of this parent class and the fields of child classes,
- causing everything to be misaligned. It's OK for the
- child classes to have constructors. }
-
- procedure Setup(func : CAMFunctionCode; len : Word);
- procedure Submit;
- end;
-
- type CCBAddr = ^CCB;
-
- { Constants for the CAM flags in the BallardSynergy implementation.
- These are different from the UNIX definitions that appear in the
- CAM spec. }
-
- const
- CAM_DATA_DIRECTION = $C0000000; { BITS 30 & 31 }
- CAM_DISABLE_AUTOSENSE = $20000000; { BIT 29 }
- CAM_DATAPTR_IS_SG_LIST_PTR = $10000000; { BIT 28 }
- CAM_DO_NOT_CALLBACK = $08000000; { BIT 27 }
- CAM_LINKED_COMMAND = $04000000; { BIT 26 }
- CAM_QUEUE_ACTION_SPECIFIED = $02000000; { BIT 25 }
- CAM_CDB_FIELD_IS_CDB_PTR = $01000000; { BIT 24 }
- CAM_DO_NOT_ALLOW_DISCONNECT = $00800000; { BIT 23 }
- CAM_INIT_SYNC_TRANSFERS = $00400000; { BIT 22 }
- CAM_DISABLE_SYNC_TRAN = $00200000; { BIT 21 }
- CAM_CDBPTR_IS_PHYS_ADDR = $00004000; { BIT 14 }
- CAM_DATAPTR_IS_PHYS_ADDR = $00002000; { BIT 13 }
- CAM_SENSEPTR_IS_PHYS_ADDR = $00001000; { BIT 12 }
- CAM_MSGPTR_IS_PHYS_ADDR = $00000800; { BIT 11 }
- CAM_LINKPTR_IS_PHYS_ADDR = $00000400; { BIT 10 }
- CAM_CALLBACKPTR_IS_PHYS_ADDR = $00000200; { BIT 9 }
- CAM_DATA_BUFFER_VALID = $00000080; { BIT 7 }
- CAM_STATUS_VALID = $00000040; { BIT 6 }
- CAM_MESSAGE_BUFFER_VALID = $00000020; { BIT 5 }
- CAM_RESERVED_BITS = $001F811F; { BITS 1-4,8,14-20 }
-
- CAM_DATA_DIRECTION_CLEAR = $3FFFFFFF; { BITS 30 & 31 }
-
- CAM_DIR_DATA_IN = $40000000;
- CAM_DIR_DATA_OUT = $80000000;
- CAM_DIR_NO_DATA = $C0000000;
-
- DATA_IN = 1;
- DATA_OUT = 0;
-
- { Status codes returned by CAM }
-
- const
- STAT_REQUEST_IN_PROGRESS = $00;
- STAT_REQUEST_DONE_NO_ERROR = $01;
- STAT_ABORTED_BY_HOST = $02;
- STAT_UNABLE_TO_ABORT = $03;
- STAT_COMPLETE_WITH_ERROR = $04;
- STAT_CAM_BUSY = $05;
- STAT_INVALID_REQUEST = $06;
- STAT_INVALID_PATH_ID = $07;
- STAT_SCSI_DEVICE_NOT_INSTALLED = $08;
- STAT_WAIT_FOR_TIMEOUT = $09;
- STAT_SELECTION_TIMEOUT = $0A;
- STAT_COMMAND_TIMEOUT = $0B;
- STAT_SCSI_BUS_BUSY = $0C;
- STAT_MESSAGE_REJECT_RECIEVED = $0D;
- STAT_SCSI_BUS_RESET = $0E;
- STAT_UNCORRECTED_PARITY_ERROR = $0F;
- STAT_REQUEST_SENSE_FAILED = $10;
- STAT_NO_HBA_DETECTED_ERROR = $11;
- STAT_DATA_OVERRUN_OR_UNDERRUN = $12;
- STAT_UNEXPECTED_BUS_FREE = $13;
- STAT_PHASE_SEQUENCE_FAILURE = $14;
- STAT_CCB_LENGTH_INADEQUATE = $15;
- STAT_CANNOT_PROVIDE_CAPABILITY = $16;
- STAT_INVALID_LUN = $20;
- STAT_INVALID_TARGET_ID = $21;
- STAT_FUNCTION_NOT_IMPLEMENTED = $22;
- STAT_NEXUS_NOT_ESTABLISHED = $23;
- STAT_INVALID_INTIATOR_ID = $24;
- STAT_INVALID_DATA_BUFFER = $25;
-
- { Values for flags that appear at top of status code }
-
- const
- FLAG_SIM_QUEUE_FROZEN = $40;
- FLAG_AUTOSENSE_DATA_VALID = $80;
-
- const
- INQUIRY_DATA_LEN = 36; {Length of data returned from device
- inquiry. Defined by SCSI-1 and unlikely
- to change in the future...}
-
- type
- InquiryData = array [0..Pred(INQUIRY_DATA_LEN)] of Byte;
- InquiryDataAddr = ^InquiryData;
-
- type AbortXPTRequestCCB = object(CCB)
- ccbPtr : CCBAddr;
- constructor Init;
- end;
-
- type GetDeviceTypeCCB = object(CCB)
- targetID : SCSIid;
- lun : Byte;
- deviceType : Byte;
- inquiryDataPtr : InquiryDataAddr;
- constructor Init;
- end;
-
- type SetDeviceTypeCCB = object(CCB)
- targetID : SCSIid;
- lun : Byte;
- deviceType : Byte;
- constructor Init;
- end;
-
- type ResetSCSIBusCCB = object(CCB)
- constructor Init;
- end;
-
- type ResetSCSIDeviceCCB = object(CCB)
- targetID : SCSIid;
- hostStatus : Byte;
- targetStatus : Byte;
- constructor Init;
- end;
-
- type ReleaseSIMQueueCCB = object(CCB)
- targetID : SCSIid;
- lun : Byte;
- constructor Init;
- end;
-
- const
- SIM_ID_LEN = 16;
- HBA_ID_LEN = 16;
- VU_HBA_LEN = 16;
-
- type
- SIMid = array [0..Pred(SIM_ID_LEN)] of Char;
- HBAid = array [0..Pred(HBA_ID_LEN)] of Char;
- VUhba = array [0..Pred(VU_HBA_LEN)] of Char;
-
- const
- FEAT_SOFT_RESET_SUPPORTED = $01;
- FEAT_COMMAND_QUEUING_SUPPORTED = $02;
- FEAT_LINKED_COMMANDS_SUPPORTED = $08;
- FEAT_SYNCHRONOUS_TRANSFER_SUPPORTED = $01;
- FEAT_SCSI_BUS_SUPPORTED_16_BIT = $02;
- FEAT_SCSI_BUS_SUPPORTED_32_BIT = $04;
- FEAT_RELATIVE_ADDRESSING_SUPPORTED = $08;
-
- type PathInquiryCCB = object(CCB)
- featureList : Longint;
- highestPathID : Byte;
- initiatorID : SCSIid;
- simVendorName : SIMid;
- hbaVendorName : HBAid;
- vendorUnique : VUhba;
- privateDataSize : Longint;
- OSD : Pointer;
- constructor Init;
- end;
-
- type SetHBAParametersCCB = object(CCB)
- featureList : Longint;
- constructor Init;
- end;
-
- type Proc = Procedure;
- type ProcPtr = ^Proc;
-
- type AENFlag = (
- AEN_UNSOLICITED_SCSI_BUS_RESET,
- AEN_UNSOLICITED_RESELECTION,
- AEN_RECOVERED_FROM_PARITY_ERROR,
- AEN_SCSI_ASYNCRONOUS_EVENT_NOTIFY);
-
- type AENFlagSet = set of AENFlag;
-
- type AsyncCallbackCCB = object(CCB)
- targetID : SCSIid;
- lun : Byte;
- aenFlags : AENFlagSet;
- callbackPtr : ProcPtr;
- constructor Init;
- end;
-
- const
- CDB_LEN = 16;
-
- type CDBType = array [0..Pred(CDB_LEN)] of Byte;
-
- const
- SCSI_REQUEST_FILL_SIZE = 113;
-
- type SCSIRequestCCB = object(CCB)
- targetID : SCSIid;
- lun : Byte;
- queueAction : Byte;
- vendorFlags : Word;
- cdbLength : Word;
- senseLength : Word;
- messageLength : Word;
- sgListLength : Word;
- dataLength : Longint;
- timeOut : Longint;
- dataPtr : Pointer;
- sensePtr : Pointer;
- messagePtr : Pointer;
- linkPtr : CCBAddr;
- peripheralPtr : Pointer;
- callBackPtr : ProcPtr;
- unused : array [1..2] of Pointer;
- cdb : CDBType;
- filler : array [1..SCSI_REQUEST_FILL_SIZE] of Byte;
- constructor Init;
- end;
-
-
- implementation
-
- uses DOS; {For type Registers}
-
- procedure CCB.Setup(func : CAMFunctionCode; len : Word);
- begin
- FillChar(self, len, 0); {Zero out the CCB}
- funcCode := func; {Set the function code and length}
- ccbLen := len;
- end;
-
- procedure CCB.Submit;
- var
- regs : Registers;
- begin
- regs.bx := Ofs(self);
- regs.es := Seg(self);
- regs.ax := $C3D4; {Sentinel}
- Intr($4B,regs);
- end;
-
- constructor AbortXPTRequestCCB.Init;
- begin
- CCB.Setup(FUNC_ABORT_SCSI_COMMAND, Sizeof(self));
- end;
-
- constructor GetDeviceTypeCCB.Init;
- begin
- CCB.Setup(FUNC_GET_DEVICE_TYPE, Sizeof(self));
- end;
-
- constructor SetDeviceTypeCCB.Init;
- begin
- CCB.Setup(FUNC_SET_DEVICE_TYPE, Sizeof(self));
- end;
-
- constructor ResetSCSIBusCCB.Init;
- begin
- CCB.Setup(FUNC_RESET_SCSI_BUS, Sizeof(self));
- end;
-
- constructor ResetSCSIDeviceCCB.Init;
- begin
- CCB.Setup(FUNC_RESET_SCSI_DEVICE, Sizeof(self));
- end;
-
- constructor ReleaseSIMQueueCCB.Init;
- begin
- CCB.Setup(FUNC_RELEASE_SIM_QUEUE, Sizeof(self));
- end;
-
- constructor PathInquiryCCB.Init;
- begin
- CCB.Setup(FUNC_PATH_INQUIRY, Sizeof(self));
- end;
-
- constructor SetHBAParametersCCB.Init;
- begin
- CCB.Setup(FUNC_SET_HBA_PARAMETERS, Sizeof(self));
- end;
-
- constructor AsyncCallbackCCB.Init;
- begin
- CCB.Setup(FUNC_SET_ASYNC_CALLBACK, Sizeof(self));
- end;
-
- constructor SCSIRequestCCB.Init;
- begin
- CCB.Setup(FUNC_EXECUTE_SCSI_IO, Sizeof(self));
- end;
-
- function CAMPresent : Boolean;
- { This function tests for the presence of a CAM driver. It's
- taken directly from the code in BallardSynergy's CAM Development
- Kit. Turbo's inline assembler makes it unnecessary to do the
- assembly as a separate step. }
- label
- no_cam;
- begin
- CAMPresent := FALSE;
- asm
- xor ax,ax
- mov es,ax
- mov bx,$012C
- les bx,dword ptr es:[bx]
- add bx,8
- cmp byte ptr es:[bx],'S'
- jne no_cam
- cmp byte ptr es:[bx+1],'C'
- jne no_cam
- cmp byte ptr es:[bx+2],'S'
- jne no_cam
- cmp byte ptr es:[bx+3],'I'
- jne no_cam
- cmp byte ptr es:[bx+4],'_'
- jne no_cam
- cmp byte ptr es:[bx+5],'C'
- jne no_cam
- cmp byte ptr es:[bx+6],'A'
- jne no_cam
- cmp byte ptr es:[bx+7],'M'
- jne no_cam
- mov byte ptr @Result,TRUE
- no_cam:
- end;
- end;
-
- begin {Module init code}
- if not CAMPresent then
- begin
- Writeln('CAM driver not present in system');
- Halt
- end;
- end.
-