program scanscsi(input,output); {*** Copyright Notice: This source Code belongs to the book "The SCSI Bus and IDE Interface" from Addison-Wesley. It may be used, ported and modified for non-commercial purposes when this copyright notice is included. Authorisation from the publisher is necessary for commercial purposes. } uses CRT, DOS; const PNAM : string='SCSI Scanner V1.0 rev 003e 18.7.94 (fs)'; {ASPI Specific Constants} ASPI_SRB_LENGHT = $7F; SRB_COMMAND_CODE = $00; SRB_STATUS = $01; SRB_TARGET_ID = $08; SRB_LUN = $09; SRB_DATA_LENGTH = $0A; SRB_BUFFER_OFS = $0F; SRB_BUFFER_SEG = $11; SRB_SCSI_LEN = $17; SRB_HA_STATUS = $18; SRB_TARGET_STATUS= $19; SRB_SCSI_CMD = $40; SRB_X_SCSICMD = $02; {SCSI Specific Constants} SCSI_CMD_LENGTH = 11; {Program specific constants} DATA_LENGTH = $FF; {Messages} ASPI_CONNECTED ='ASPI loaded'; ASPI_OPEN_ERROR ='Error opening ASPI'; type {Generic Types} MemAdress = record Offset: integer; Segment: integer; end; {ASPI-Types} SRBsize= 0..ASPI_SRB_LENGHT; SRBarray = array[SRBsize] of byte; {SCSI-Types} SCSICmdSize = 0..SCSI_CMD_LENGTH; SCSICmd = record Command: array[SCSICmdSize] of byte; Status: byte; ID: byte; LUN: byte; Len: byte; TimeOut: integer; end; BufferLength = 0..DATA_LENGTH; DataBufferType = array[BufferLength] of byte; var CommandBuffer: SCSICmd; DataBuffer : DataBufferType; ID,LUN : byte; AspiEntryPoint: MemAdress; SRB: SRBarray; SCSIConnected: string; {**** Low Level Functions} function FileOpen(FileName:string):integer; const DOS_OPEN_FILE = $3D; var register: registers; begin FileName:=FileName+chr(0); with register do begin ax := DOS_OPEN_FILE shl 8; bx:=0; cx:=0; ds := seg(FileName); dx := ofs(FileName)+1; { because Pascal strings carry their length in byte 0 } end; MSDOS(register); if (register.flags and FCarry) > 0 then FileOpen:=-1 else FileOpen:=register.ax; end; function FileClose(FileHandle:integer):integer; const DOS_CLOSE_FILE = $3E; var register: registers; begin with register do begin ax := DOS_CLOSE_FILE shl 8; bx:=FileHandle; end; MSDOS(register); if (register.flags and FCarry) = 0 then FileClose:=0 else FileClose:=register.ax; end; {**** Miscellanous Generic Functions} {**** SCSI generic functions} function SCSICmdLen(Opcode: byte):byte; begin SCSICmdLen:=0; if Opcode and $E0 = $00 then SCSICmdLen:=6; if Opcode and $E0 = $20 then SCSICmdLen:=10; if Opcode and $E0 = $40 then SCSICmdLen:=10; if Opcode and $E0 = $A0 then SCSICmdLen:=12; end; {**** ASPI-specific functions} procedure GetASPIEntry(FileHandle:integer; var AspiEntry:MemAdress); const ASPI_ENTRY_LENGTH = 4; DOS_IOCTL_READ = $4402; var register: registers; begin with register do begin ax := DOS_IOCTL_READ; bx:=FileHandle; cx:=ASPI_ENTRY_LENGTH; ds := seg(AspiEntry); dx := ofs(AspiEntry); end; MSDOS(register); end; procedure SCSI2SRB(var SRB: SRBarray; Command: SCSICmd; var DataBuffer: DataBufferType); var k:integer; begin for k:=0 to High(SRB) do SRB[k]:=0; SRB[SRB_COMMAND_CODE]:=SRB_X_SCSICMD; with Command do begin SRB[SRB_TARGET_ID]:=ID; SRB[SRB_LUN]:=LUN; SRB[SRB_SCSI_LEN]:=SCSICmdLen(Command[1]); for k:=0 to SRB[SRB_SCSI_LEN]-1 do SRB[SRB_SCSI_CMD+k]:=Command[k]; end; SRB[SRB_DATA_LENGTH]:=lo(DATA_LENGTH); SRB[SRB_DATA_LENGTH+1]:=hi(DATA_LENGTH); SRB[SRB_BUFFER_SEG]:=lo(seg(DataBuffer)); SRB[SRB_BUFFER_SEG+1]:=hi(seg(DataBuffer)); SRB[SRB_BUFFER_OFS]:=lo(ofs(DataBuffer)); SRB[SRB_BUFFER_OFS+1]:=hi(ofs(DataBuffer)); end; procedure SRBexecute(var SRB: SRBarray); var SRBsegment, SRBoffset: integer; begin SRBsegment:=seg(SRB); SRBoffset:=ofs(SRB); asm mov ax, SRBsegment push ax mov ax, SRBoffset push ax LEA BX, AspiEntryPoint call DWORD PTR [bx] add sp,4 end; end; function InitializeASPI(var AspiEntrypoint:MemAdress): boolean; const ASPI_NAME = 'SCSIMGR$'; var result: integer; AspiFileHandle: integer; begin AspiFileHandle:=FileOpen(ASPI_NAME); if AspiFileHandle>-1 then begin GetASPIEntry(AspiFileHandle,AspiEntryPoint); FileClose(AspiFileHandle); InitializeASPI:=true; end else InitializeASPI:=false; end; procedure initialize; var ByteNbr : integer; begin with CommandBuffer do begin for ByteNbr:=0 to SCSI_CMD_LENGTH do Command[ByteNbr]:=0; ID:=0; LUN:=0; Status:=$FF; end; for ByteNbr:=0 to DATA_LENGTH do DataBuffer[ByteNbr]:=0; end; Procedure Inquire(ID,LUN:byte); const INQUIRY : array [SCSICmdSize] of byte = ($12,$0,$0,$0,$ff,$0,$0,$0,$0,$0,$0,$0); var k: integer; Status: byte; begin for k:=0 to SCSI_CMD_LENGTH do CommandBuffer.command[k]:=INQUIRY[k]; CommandBuffer.ID:=ID; CommandBuffer.LUN:=LUN; If LUN=0 then writeln('SCSI ID ',ID,': '); SCSI2SRB(SRB,CommandBuffer,DataBuffer); SRBexecute(SRB); repeat until SRB[SRB_STATUS]<>0; if SRB[SRB_STATUS] = 1 then if SRB[SRB_HA_STATUS]= 0 then begin Status:=DataBuffer[0] and $E0; if Status=0 then begin write(' LUN ',LUN,': '); for k:=8 to 35 do write(chr(DataBuffer[k])); writeln; end; end else if LUN=0 then writeln; end; begin writeln(PNAM); initialize; if InitializeASPI(AspiEntryPoint) then begin writeln(ASPI_CONNECTED); for ID:=0 to 7 do for LUN:=0 to 7 do Inquire(ID,LUN); end else writeln(ASPI_OPEN_ERROR); end.