{=========================================================================== Program Name : n/a System Name : Atari ST and TT Program Author : Copyright (c) 1991 ICD Inc. All rights reserved Language : Personal Pascal (Pascal Plus) Module Name : DMA.I Purpose : This is the header file for DMA.O. It contains routines for direct hard drive access as well as an interface to tables within the ICD hard disk driver (ICDBOOT.PRG). ===========================================================================} { This revision posted 6-6-1991. A number of significant changes have been made. The FSCSI and SFSCSI commands are gone. Full scsi commands are now indicated by a bit in a FLAGS word. SCSI ID is no longer embedded in the command frame. SCSI ID's can now range from 0 to 15. 0 to 7 will reference devices connected to the DMA port on ST and TT. 8 through 15 reference devices connected to the TT internal SCSI bus. } { Structures kept within the ICDBOOT hard disk driver ----------------------------------------------------------------} const read_dir = 0; write_dir = 1; fullscsi = 2; one_second = 150000; type bios_block = record recsiz: integer; { # bytes/sector } clsiz: integer; { # sectors/cluster } clsizb: integer; { # bytes/cluster } rdlen: integer; { # sectors/dir } fsiz: integer; { # sectors/FAT } fatrec: integer; { sector # of 2nd FAT } datrec: integer; { sector # of first data cluster } numcl: integer; { # data clusters } bflags: integer; { bits/FAT entry flag: 1=16 bit? } end; drive_parameters = record units: integer; { # SCSI IDs online } id: packed array [0..15] of byte; lun: packed array [0..15] of byte; start: array [0..15] of long_integer; bpb: array [0..15] of bios_block; change:packed array [0..15] of byte; sizes: array [0..15] of long_integer; end; p_drive_parameters = ^drive_parameters; barray = packed array[0..0] of byte; bptr = ^barray; { generic byte pointer } Com_Rec = record case integer of 1: (data: packed array[1..16] of byte); 2: (buf: barray); end; Dat_rec = record case integer of 1: (bytes: Packed Array [0..511] of Byte); 2: (words: Packed Array [0..255] of Integer); 3: (longs: Packed Array [0..127] of Long_Integer); 4: (buf: barray); end; var ID,LUN: integer; { global SCSI ID/LUN } Command: Com_Rec; { global SCSI command buffer } SecBuf: Dat_Rec; { global sector buffer } {========================================================================== Interface to ICDBOOT.PRG ------------------------ ICDBOOT: return ptr to drive parameter block return: NIL = Driver is not present !NIL = ptr to parameter block ICDHEAD: return ptr to beginning of ICDBOOT image. This is used by internal ICD utilities and the exact structure is undocumented. return: NIL = Driver is not present !NIL = ptr to beginning of driver RELOG: Rescan all partitions and reset all internal tables return: TRUE: = success FALSE: = driver not present or bad version of ICDBOOT COLDBOOT: reboot system } Function ICDBOOT: p_drive_parameters; external; Function ICDHEAD: bptr; external; Function RELOG: boolean; external; { rescan all partitions } Procedure COLDBOOT; external; {========================================================================== Calls to perform SCSI commands ------------------------------ DMA: Perform SCSI command (no retries, no REQUEST on error). in: ID = SCSI ID of device (LUN is embedded in COM_FRAME; see below) COM_FRAME = command bytes (packed byte array) DATA_FRAME= data buffer (packed byte array) FLAGS = 16 bits as follows: bit[0]=DMA direction. bit[1]=FULL SCSI. bits[2]-[15] are RESERVED at this time. DMA transfer direction bit: 0 = read data from drive, 1 = write data to drive. FULL SCSI bit: 0 = ACSI format COM_FRAME is always 6 bytes long. COMMAND BYTE is byte[1] LUN is top 3 bits of byte[2] 1 = SCSI format COM_FRAME length is variable; length in byte[1] COMMAND BYTE is byte[2] LUN is top 3 bits of byte[3] BLOCKS = number 512 byte blocks to transfer (round up for non-512 byte multiples) TIMEOUT = timeout value used for command completion (not SCSI selection timeout - selection is fixed at 100 ms). 150000 is one second and is NOT dependent on cpu or speed return: 0 = success 2 = indicates an error (do a REQUEST to get actual error sense code) -1 = timeout after sending command (drive is not responding) -2 = timeout while sending command -3 = this ID skipped by ICDBOOT XDMA: Performs DMA with retries. No retries are performed if the drive timed out. Retries are performed only when DMA returns a code 2, in which case XDMA does a REQUEST and tries DMA again. in: same as DMA return: 0 = success -1 = timeout after sending command (drive is not responding) -2 = timeout while sending command -3 = this ID skipped by ICDBOOT 127 = REQUEST fails (parity error?) 1-126 = sense code from drive 128-252 = more sense codes (not used by most SCSI devices) SXDMA: Performs XDMA but is used when a non-multiple of 16 bytes needs to be returned from the SCSI device. (For example doing a MODESENSE). The ST DMA chip has a bug where the FIFO will not flush its data when not full in receive mode. This function compensates for this by performing the command 4 times without resetting the DMA chip. USE ON READ COMMANDS ONLY. in: same as DMA return: same as XDMA REQUEST: Performs a REQUEST SENSE on the SCSI device. in: id = SCSI ID of device lun = LUN of device return: 0 = success -1 = timeout after sending command (drive is not responding) -2 = timeout while sending command -3 = this ID skipped by ICDBOOT 127 = REQUEST fails (parity error?) 1-126 = sense code from drive 128-252 = more sense codes (not used by most SCSI devices) } Function DMA (id:integer;var com_frame,data_frame: barray; flags,blocks: integer; timeout: long_integer): Integer; External; Function XDMA (id:integer;var com_frame,data_frame: barray; flags,blocks: integer; timeout: long_integer): Integer; External; Function SXDMA (id:integer;var com_frame,data_frame: barray; flags,blocks: integer; timeout: long_integer): Integer; External; Function REQUEST (id,lun:integer): Integer; External; {=========================================================================== Some examples of DMA type calls ------------------------------- } {examples of ACSI format commands} Function Read_Sector (var buffer: barray; secno: Long_integer; blocks: integer): integer; begin Command.Data [1] := $08; Command.Data [2] := (secno & $FF0000) DIV $10000 + $20*LUN; Command.Data [3] := (secno & $00FF00) DIV $100; Command.Data [4] := secno & $0000FF; Command.Data [5] := blocks; Command.Data [6] := 0; Read_sector := XDMA (ID,command.buf,buffer,Read_Dir,blocks,30*one_second); end; Function Write_Sector (var buffer: barray; secno : Long_integer; blocks: integer): integer; begin Command.Data [1] := $0A; Command.Data [2] := (secno & $FF0000) DIV $10000 + $20*LUN; Command.Data [3] := (secno & $00FF00) DIV $100; Command.Data [4] := secno & $0000FF; Command.Data [5] := blocks; Command.Data [6] := 0; Write_sector := XDMA (ID,command.buf,buffer,Write_Dir,blocks,30*one_second); end; { example of a FULL SCSI command} Function Read_Capacity: Long_Integer; var i: integer; begin Command.Data [1] := 10; { 10 bytes in command frame } Command.Data [2] := $25; { read capacity command } Command.Data [3] := $20*LUN; for i:=4 to 11 do Command.Data [i] := 0; if SXDMA(ID,command.buf,SecBuf.buf,Read_Dir+fullscsi,1,3*one_second)=0 then Read_Capacity := SecBuf.longs[0] else Read_Capacity := 0; end;