home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mega CD-ROM 1
/
megacd_rom_1.zip
/
megacd_rom_1
/
MAGAZINE
/
PROGJOUR
/
PJ_9_3.ZIP
/
CAM.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1991-04-16
|
11KB
|
393 lines
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.