











Symbios Logic Validation software (TAZ)
Core Code Documentation


Table of Contents
1. OVERVIEW OF CORE FUNCTIONS	
1.1. GENERIC PCI FUNCTIONS (PCI.C)	
1.2. GENERIC LOW-LEVEL FUNCTIONS (GEN_TOOL.C):	
1.3. 8XX SPECIFIC PCI FUNCTIONS 8XX_PCI.C:	
1.4. 8XX SPECIFIC FUNCTIONS (8XX_TOOL.C):	
1.5. SCSI SPECIFIC FUNCTIONS (8XX_SCSI.C):	
2. DATA STRUCTURES AND MACROS	
2.1. VALTYPES.H	
2.1.1. #defines	
2.2. PCI.H	
2.2.1. #defines	
2.2.2. Structures/types	
2.3. GEN_TOOL.H	
2.3.1. #defines	
2.4. 8XX_PCI.H	
2.4.1. #defines	
2.5. 8XX_TOOL.H	
2.5.1. #defines	
2.5.2. Structures/types	
2.6. 8XX_SCSI.H	
2.6.1. #defines	
2.6.2. Structures/types	
2.6.2.1. maint_table_offsets	
2.6.2.2. rw_table_offsets	
2.6.2.3. scsimaint	
2.6.2.4. scsirw	
2.6.2.5. scsidev_record	
3. FUNCTION DESCRIPTIONS AND EXAMPLES	
3.1. FILE: PCI.C	
3.1.1. Function: PCI_FindSYMDevice	
3.1.2. Function: PCI_SetConfigRegister	
3.1.3. Function: PCI_GetConfigRegister	
3.1.4. Function: PCI_GetPCIBIOSVersion	
3.1.5. Function: PCI_check_pci_bios	
3.2. FILE: GEN_TOOL.C	
3.2.1. Function: getPhysAddr	
3.2.2. Function: IORead8	
3.2.3. Function: IOWrite8	
3.2.4. Function: IORead32	
3.2.5. Function: IOWrite32	
3.2.6. Function: ByteAlignBuffer	
3.2.7. Function: CacheAlignBuffer	
3.2.8. Function: InitBuffer	
3.2.9. Function: Get_Time	
3.2.10. Function: HasTimeElapsed	
3.2.11. Function: WriteLog	
3.3. FILE: GEN_TOOL.H	
3.3.1. Macro Function: RMWon	
3.3.2. Macro Function: RMWoff	
3.4. FILE: 8XX_PCI.C	
3.4.1. Function: C8XX_DevID2Str	
3.4.2. Function: C8XX_BuildPCIDeviceList	
3.4.3. Function: C8XX_ChoosePCIDevice	
3.4.4. Function: GetMemBase	
3.4.5. Function: GetIOBase	
3.4.6. Function: GetRAMBase	
3.4.7. Function: PCI_print_config	
3.5. FILE: 8XX_TOOL.C	
3.5.1. Function: init_8XX	
3.5.2. Function: align_script	
3.5.3. Function: PollISTAT	
3.5.4. Function: CopyToScRam	
3.5.5. Function: WriteScRam	
3.5.6. Function: ReadScRam	
3.5.7. Function: WriteLongScRam	
3.5.8. Function: ReadLongScRam	
3.5.9. Function: GenRandSG	
3.5.10. Function: C8XX_GetChipType	
3.5.11. Function: C8XX_SetBurstSize	
3.6. FILE: 8XX_TOOL.H	
3.6.1. Macro Function: iowriteDSP	
3.7. FILE: 8XX_SCSI.C	
3.7.1. Function: init_gpscripts	
3.7.2. Function:  init_scsi	
3.7.3. Function:  do_tur	
3.7.4. Function:  do_RqSense	
3.7.5. Function:  do_Inquiry	
3.7.6. Function:  do_RdCap	
3.7.7. Function:  do_StartStopUnit	
3.7.8. Function:  do_SyncNeg	
3.7.9. Function:  do_WideNeg	
3.7.10. Function: do_Read6	
3.7.11. Function: do_Read10	
3.7.12. Function: do_Write6	
3.7.13. Function: do_Write10	
3.7.14. Function: do_rw	
3.7.15. Function: Fill_SG_Entries	
3.7.16. Function: HandleDataInPM	
3.7.17. Function: HandleDataOutPM	
3.7.18. Function: Fail_SCSI	
3.7.19. Function: Bitbucket	
3.8. FILE: VALIDATE.C	
3.8.1. Function: main	

Revision History:

Document Rev.		Date					Covers Core Version
1.0				11/95					1.01.00

2.0				3/96					1.02.00


Overview of core functions
Generic PCI functions (pci.c)
*PCI_FindSYMDevice - Determines if a given Symbios device is present in the system
PCI_SetConfigRegister - Writes the config register of a given Symbios device
PCI_GetConfigRegister - Read the config register of a given Symbios device
PCI_GetPCIBIOSVersion - Returns the Version of the PCI system bios in the system
*PCI_check_pci_bios - Checks for PCI system bios and prints out info on it
Generic Low-Level Functions (gen_tool.c):
getPhysAddr - Converts Virtual to Physical address
IORead8 - Read a chip register (1-byte)
IOWrite8 - Writes a chip register (1-byte)
IORead32 - Read a Dword chip register (4-bytes)
IOWrite32 - Write a Dword chip register (4-bytes)
ByteAlignBuffer - Aligns a buffer to a particular byte boundary
CacheAlignBuffer - Aligns a buffer to a particular cache boundary
InitBuffer - Initializes a given buffer to a known state
Get_Time - Gets the current time from CMOS
HasTimeElapsed - Used to implement time-out mechanisms by using Get_Time
WriteLog - Used to write to a log file or standard out depending on command line switches
RMWon - Turns a bit or bits on in a register
RMWoff - Turns a bit or bits off in a register
8XX Specific PCI Functions 8xx_pci.c:
C8XX_DevID2Str - Converts a given device id/rev id to a printable device name string
*C8XX_GetMemBase - Gets the register memory base address of the 8xx part
*C8XX_GetIOBase - Gets the register IO base address of the 8xx part
*C8XX_GetRAMBase - Gets the Script RAM memory base address of the 8xx part
*C8XX_BuildPCIDeviceList - Builds a list of 8XX devices found in the system
*C8XX_ChoosePCIDevice - Allows the user to choose a specific 8xx part to test
*PCI_print_config - Prints out config information to the screen or the log file
8XX Specific Functions (8xx_tool.c):
init_8XX - Initializes chip to a known configuration
IOWriteDSP - Specialized IO Write to start script operation
PollISTAT - Polls for an interrupt and returns the type and vector
GenRandSG - Generates a random Scatter Gather List
CopyToScRAM - Copies Script to Script RAM
ReadScRAM - Reads a byte from Script RAM
WriteScRAM - Writes a byte to Script RAM
ReadLongScRAM - Reads a Dword from Script RAM
WriteLongScRAM - Writes a Dword to Script RAM
SCSI Specific functions (8xx_scsi.c):
do_TUR - Does a Test Unit Ready and returns status
do_RqSense - Does a Request Sense
do_RdCap - Does a Read Capacity
do_Inquiry - Does an Inquiry
do_SyncNeg - Does a Synchronous Negotiation
do_WideNeg - Does a wide negotiation
do_Read6 - Does a 6 byte Read, TCQ, Sync., Wide & Disc. supported
do_Write6 - Does a 6 byte Write, TCQ, Sync., Wide & Disc. supported
do_Read10 - Does a 10 byte Read, TCQ, Sync., Wide & Disc. supported
do_Write10 - Does a 10 byte Write, TCQ, Sync., Wide & Disc. supported

* - Generally these functions should not be called by the test writer as they are specific tools used by the core code and are of little or no use to the test writer
Data structures and Macros
VALTYPES.H
#defines
VCHAR - char
VBYTE - char
VUBYTE - unsigned char
VINT - int
VUINT - unsigned int
VLONG - long
VULONG - unsigned long

PCI.H
#defines
PCI_BIOS_INT - System Bios Interrupt Vector (0x1A)
PCI_FUNCTION_ID - Function for PCI system bios call (0xB1)
PCI_SYM_VENDOR_ID - Symbios Logic's vendor ID (0x1000)
PCI_BIOS_PRESENT - Used to make PCI bios present call (0x01)
PCI_FIND_DEVICE - Used to make PCI find device call (0x02)
PCI_READ_CONFIG_DWORD - Used to make PCI read config dword call (0x0A)
PCI_WRITE_CONFIG_DWORD - Used to make PCI write config dword call (0x0D)
PCI_DEVICE_FOUND - Returned by FindSYMDevice indicating that the requested PCI device was found
PCI_NO_DEVICE_FOUND - Returned by FindSYMDevice indicating that the requested PCI device was not found
PCI_BIOS_REV_1X - Returned by PCI_GetPCIBIOSVersion to indicate the PCI bios version is 1.X
PCI_BIOS_REV_2X - Returned by PCI_GetPCIBIOSVersion to indicate the PCI bios version is 2.X
PCI_UNKNOWN_BIOS - Returned by PCI_GetPCIBIOSVersion to indicate the PCI bios version is unknown
PCI_NO_BIOS - Returned by PCI_GetPCIBIOSVersion to indicate that a PCI bios is not present in the system

PCI Configuration Register dword offsets
PCI_CONFIG_REG_VENID - Vendor ID	
PCI_CONFIG_REG_DEVID - Device ID
PCI_CONFIG_REG_CMD - Command register
PCI_CONFIG_REG_STAT - Status register
PCI_CONFIG_REG_REVID - Revision ID	
PCI_CONFIG_REG_CLASS - Class code register	
PCI_CONFIG_REG_CLS - Cache line size register
PCI_CONFIG_REG_LAT - Latency timer	
PCI_CONFIG_REG_HDRT - Header type
PCI_CONFIG_REG_BIST - Built in self test
PCI_CONFIG_REG_CIS - Card Info Serv. ptr.	
PCI_CONFIG_REG_SUBV - Subsystem vend ID
PCI_CONFIG_REG_SUBID - Subsystem dev ID	
PCI_CONFIG_REG_ROM - Exp. ROM BAR
PCI_CONFIG_REG_INTL - Interrupt line reg
PCI_CONFIG_REG_INTP - Interrupt pin register	
PCI_CONFIG_REG_MGNT - Min grant register	
PCI_CONFIG_REG_MLAT - Max latency register	
Structures/types
pcidev_record - Type used to hold PCI config information.  This structure is returned by PCI_FindSYMDevice.  This structure is passed to the TEST function for the device being tested.

typedef struct {
			VUINT  bus_num;
			VUINT  device_num;
			VUINT  function;
			VUINT  device_id;
			VUINT  device_index;
			VUBYTE rev_id;
			VUBYTE CLS;
			VUBYTE latency;
			VUINT  command;
			VULONG base_addr1;
			VULONG base_addr2;
			VULONG base_addr3;
			VULONG base_addr4;
			VULONG base_addr5;
			VULONG base_addr6;
			VULONG CIS;
			VUINT  sub_id;
			VUINT  sub_ven_id;
			VULONG ROM_base_addr;
			VUBYTE intl;
			VUBYTE intp;

} pcidev_record;

*bus_num - the bus number the PCI device resides on
*device_num - the PCI device number of the PCI device
*function - the function number of the PCI device
*device_id - the device ID of the PCI device
*device_index - the index number of the PCI device
*rev_id - the revision id of the PCI device
*CLS - the cache line size register of the PCI device
*latency - the latency timer of the PCI device
*command - the command register of the PCI device
base_addr1 - BAR1 (8XX Register Memory base)
*base_addr2 - BAR2 (8XX Register IO base)
*base_addr3 - BAR3 (8XX Script RAM base 825A/875 only)
base_addr4 - BAR4
base_addr5 - BAR5
base_addr6 - BAR6
CIS - Cardbus CIS pointer
sub_id - Subsystem ID of the PCI Device
sub_ven_id - Subsystem vendor ID of the PCI device
*ROM_base_addr - ROM base address of the PCI device
*intl - Interrupt line of the PCI device
*intp - Interrupt pin of the PCI device

* - These variables are currently filled in by the Core code when initializing PCI devices
Note that if a PCI config register is changed then the corresponding information in this data structure should be changed also

pci_bios_info - structure returned by PCI_GetPCIBIOSVersion.  Contains information about PCI system bios.

typedef struct {
			VUBYTE access_mech;
			VUINT interface_lvl;
			VUBYTE last_bus;
} pci_bios_info;

access_mech - Bit 0 set, Hardware mech #1 supported/ Bit 1 set, Hardware mech #2 supported
interface_lvl - Upper byte = major version, lower byte = minor version
last_bus - Last PCI bus number in system

GEN_TOOL.H
#defines
LOG_BASIC - Used in Writelog function to indicate a basic log entry
LOG_DETAIL - Used in Writelog function to indicate a detail log entry
LOG_PASS - Used in Writelog function to indicate a PASSing test log entry
LOG_FAIL - Used in Writelog function to indicate a FAILing test log entry

8XX_PCI.H
#defines
Device/Version IDs
C810_DEVICE_ID
C810A_DEVICE_ID
C810_VERSION_ID
C810A_VERSION_ID
C810ALV_VERSION_ID
C810AP_DEVICE_ID
C810AP_VERSION_ID
C815_DEVICE_ID
C815_VERSION_ID
C820_DEVICE_ID
C820_VERSION_ID
C825_DEVICE_ID
C825A_DEVICE_ID
C825_VERSION_ID
C825A_VERSION_ID
C860_DEVICE_ID
C860LV_DEVICE_ID
C860_VERSION_ID
C860LV_VERSION_ID
C875_DEVICE_ID
C875_VERSION_ID
C885_DEVICE_ID
C885_VERSION_ID
C895_DEVICE_ID
C895_VERSION_ID
C896_DEVICE_ID
C896_VERSION_ID
NULL_DEVICE_ID

Return values from functions
C8XX_GOOD - Returned by any function in C8XX_PCI.C which successfully completed
C8XX_NO_BASE - Returned by C8XX_GetIOBase, C8XX_GetMEMBase and C8XX_GetRAMBase to indicate that no base address was assigned to the respective register

8XX Base address offsets 
C8XX_CONFIG_REG_IOB - Register IO Base address config register offset
C8XX_CONFIG_REG_MEMB - Register Memory Base address config register offset
C8XX_CONFIG_REG_RAMB - Script RAM Memory Base address config register offset


8XX_TOOL.H
#defines
Return values from functions
C8XX_GOOD - Returned by any function in C8XX_TOOL.C which successfully completed
C8XX_COPYCOMPLETE - Internal return code used when copying to and from script RAM, will not be returned by test accessible function
C8XX_POLLTO - Returned by PollISTAT to indicate no chip interrupt was detected in the allotted time
C8XX_RAMCOPYFAILURE - Returned by CopyToScRam to indicate the script copy to Script RAM failed
C8XX_RAMWRITEFAILURE - Returned by WriteScRam and WriteLongScRam to indicate the write to the script RAM failed
C8XX_RAMREADFAILURE - Returned by ReadScRam and ReadLongScRam to indicate the Read of the script RAM failed

53C8XX Interrupt bits
C8XX_INT_DIP - DMA interrupt pending (ISTAT)
C8XX_INT_SIP - SCSI interrupt pending (ISTAT)
C8XX_INT_MDPE - Master parity error (DSTAT)
C8XX_INT_BF - Bus Fault (DSTAT)
C8XX_INT_ABRT - Scripts aborted (DSTAT)
C8XX_INT_SSI - Script Step interrupt (DSTAT)
C8XX_INT_SIR - Script Interrupt instruction (DSTAT)
C8XX_INT_MA - Phase Mismatch (SIST)
C8XX_INT_CMP - Function Complete (SIST)
C8XX_INT_SEL - Selected (SIST)
C8XX_INT_RSL - Reselected (SIST)
C8XX_INT_SGE - SCSI Gross error (SIST)
C8XX_INT_UDC - Unexpected disconnect (SIST)
C8XX_INT_RST - SCSI Reset received (SIST)
C8XX_INT_PAR - SCSI Parity error (SIST)
C8XX_INT_STO - SCSI Selection time-out (SIST)
C8XX_INT_GEN - General purpose timer int (SIST)
C8XX_INT_HTH - Handshake to Handshake int (SIST)

53C8XX Device listing for the c8xxdev_record.device field
C8XX_53C810
C8XX_53C810A
C8XX_53C810ALV
C8XX_53C815
C8XX_53C825
C8XX_53C825A
C8XX_53C860
C8XX_53C860LV
C8XX_53C875
C8XX_53C885
C8XX_53C895
C8XX_53C896
C8XX_UNKNOWN_DEVICE

Feature masks for c8xxdev_record below
C8XX_WIDE_SCSI - Device supports Wide SCSI transfers
C8XX_ROM_IF - Device has ROM interface
C8XX_DIFF_SCSI - Device supports Differential SCSI
C8XX_BRST_OP - Device supports burst op code fetch
C8XX_PREFETCH - Device supports Script Prefetch
C8XX_SRAM - Device has Scripts RAM
C8XX_CACHE - Device supports PCI Cache commands
C8XX_SSAID - Device supports SSAID register
C8XX_EX_TIMER - Device supports expanded H2H and Gen timers
C8XX_EX_SLPAR - Device supports expanded SLPAR
C8XX_EN_RMOVE - Device supports Enhanced register move
C8XX_IRQ_DIS - Device supports IRQ disable
C8XX_LD_STR - Device supports Load Store script instruction
C8XX_FAST20 - Device supports Fast-20
C8XX_32SCRATCH - Device supports additional 32 scratch registers
C8XX_CLK_DBLR - Device has SCSI clock doubler
C8XX_FAST40 - Device supports Fast-40
C8XX_64BITPCI - Device supports 64-bit pci

Burst Sizes for Feature sets below and for calls to C8XX_SetBurstSize
C8XX_BURST_2
C8XX_BURST_4 
C8XX_BURST_8   
C8XX_BURST_16
C8XX_BURST_32 
C8XX_BURST_64
C8XX_BURST_128 

Feature info for all devices for c8xxdev_record
C8XX_53C8XX_FEAT - Device features (as defined above)
C8XX_53C8XX_FIFO_A - Small (compatible) fifo size
C8XX_53C8XX_FIFO_B - Large (incompatible) fifo size
C8XX_53C8XX_BRST_A - Max burst at Fifo size A
C8XX_53C8XX_BRST_B - Max burst at Fifo size B
C8XX_53C8XX_OFFSET - Max SCSI Sync offset

53C8XX register set
All registers are #defined as they appear in the 53C8XX data manuals
Structures/types
ti_entry - Used for creating Script table indirect entries.

typedef struct {
	VULONG count;
	VULONG address;
} ti_entry;

count - Either a byte count in the Block Move Table Indirect entry or Selection information in a Select Table Indirect entry.  The select information format is as follows (0x) SCNTL3:SDID:SXFER:00.  
address - This is the destination/source data address in a Block Move Table Indirect entry.  This field is not used in a Select Table Indirect entry and must be set to 0.


c8xxdev_record - Used to store device feature information

typedef struct {
	VINT device;
	VINT fifo_size_a;
	VINT fifo_size_b;
	VINT max_burst_a;
	VINT max_burst_b;
	VINT max_offset;
	VULONG features;
} c8xxdev_record;

device - This is the type of device being tested.  This value is #defined for all known devices above
features - indicates the particular features that a 8xx device supports
	The bit definitions are as follows:
		Bit 0 - Device supports Wide SCSI data transfers
		Bit 1 - Device has a back end ROM interface
		Bit 2 - Device supports differential
		Bit 3 - Device supports burst op code fetch
		Bit 4 - Device supports instruction prefetch
		Bit 5 - Device has Scripts RAM
		Bit 6 - Device supports Cache Line Size and Cache 			Commands
		Bit 7 - Device supports SSAID register
		Bit 8 - Device supports expanded timers
		Bit 9 - Device supports expanded SLPAR register
		Bit 10 - Device supports enhanced register move script 			instruction
		Bit 11 - Device supports IRQ disable
		Bit 12 - Device supports LOAD/STORE script instructions
		Bit 13 - Device supports Fast-20 transfers
		Bit 14 - Device supports additional 32 Scratch registers
		Bit 15 - Device supports Clock Doubler
		Bit 16 - Device supports Fast-40 transfers
		The remaining bit definitions are reserved for future use.
fifo_size_a - This is the power up fifo size of the device
fifo_size_b - If the device supports a larger programmable fifo size This will contain that size.  It will be zero if the device does not support another fifo size;
max_burst_a - This is the maximum burst size that the device will support given that the fifo size is at fifo_size_a above
max_burst_b - This is the maximum burst size that the device will support given that the fifo size is at fifo_size_b above.  If the device does not support fifo_size_b then this will be zero
max_offset - This is the maximum synchronous offset the device will support

8XX_SCSI.H
#defines
Core script information
MAINT_TABLE_SIZE - Script maint table indirect size
RW_TABLE_SIZE - Script RW table indirect size
MAX_SG_ENTRIES - Maximum SG entries script can service at one time
INITSCSI_MAX_RETRIES - Maximum retries to clear a check condition in the init_scsi routine

Phases of the scsi bus as reported by socl and sbcl
SCSI_MSGO_PHASE
SCSI_MSGI_PHASE
SCSI_STATUS_PHASE
SCSI_CMD_PHASE
SCSI_DATAI_PHASE
SCSI_DATAO_PHASE

Return values from functions
SCSI_GOOD - Returned by any function in 8XX_SCSI.C which completes successfully
SCSI_SELECTTO - Returned by any of the do_ functions where there was a selection time-out
SCSI_MSGREJECT - Returned by do_syncneg or do_wideneg to indicate that the device has rejected the sync or wide negotiation attempt
SCSI_COMMANDFAILED - Returned by any of the do_ functions where a SCSI command failed but the SCSI bus is no longer in use
SCSI_CON_COMMANDFAILED - Returned by any of the do_ functions where a SCSI command failed and the target that was being accessed is still connected to the bus.
SCSI_ILLEGAL_INT - Returned by any of the do_ maintenance functions (do_tur, do_rqsense, do_inquiry, do_rdcap, do_syncneg, and do_wideneg) where an illegal interrupting condition occurred
SCSI_POLLTO - Returned by any of the do_ maintenance functions where there was no interrupt in the specified time-out period
SCSI_UNKNOWN - Returned by any of the do_ maintenance functions where there was an unknown error condition.

Structures/types
maint_table_offsets
Enumerated list for use with the core maintenance table indirect script.  Should not be used by the test function.

enum maint_table_offsets {
		MAINT_SCSI_ID = 0,
		MAINT_MSGO_BUF,
		MAINT_CMD_BUF,
		MAINT_STAT_BUF,
		MAINT_MSGI_BUF,
		MAINT_EMSGI_BUF,
		MAINT_DATA_BUF
};
rw_table_offsets
Enumerated list for use with the core read/write table indirect script.  Should not be used by the test function.

enum rw_table_offsets {
		  RW_SCSI_ID = 0,
		  RW_ID_BUF,
		  RW_CMD_BUF,
		  RW_STAT_BUF,
		  RW_MSGI_BUF,
		  RW_DATA_BUF1,
		  RW_DATA_BUF2,
		  RW_DATA_BUF3,
		  RW_DATA_BUF4,
		  RW_DATA_BUF5,
		  RW_DATA_BUF6,
		  RW_DATA_BUF7,
		  RW_DATA_BUF8,
		  RW_DATA_BUF9,
		  RW_DATA_BUF10,
		  RW_DATA_BUF11,
		  RW_DATA_BUF12,
		  RW_DATA_BUF13,
		  RW_DATA_BUF14,
		  RW_DATA_BUF15,
		  RW_DATA_BUF16
};
scsimaint
Structure required by the maintenance scsi functions (do_tur, do_rqsense, do_inquiry, do_readcap, do_syncneq, and do_wideneg) All items marked input must be filled in depending on the function called.

typedef struct {
		VULONG sel_info;          	/* input/output */
		VULONG data_length;    	/* input/output */
		VUBYTE msgo_buf[6];   	/* input */
		VUBYTE cmd_buf[12];   	/* output */
		VUBYTE stat_buf;       	/* output */
		VUBYTE msgi_buf;       	/* output */
		VUBYTE emsgi_buf[4];   	/* output */
		VUBYTE *data_buf;      	/* input/output */
} scsimaint;

sel_info - A select table indirect entry which contains the appropriate information for the device being selected.  This is required to be filled in for all maintenance functions.  This field is modified by the do_syncneg and do_wideneg to reflect the proper sxfer and scntl3 values for the respective negotiation that took place.
data_length - This field must be filled in to indicate the amount of data desire for the do_rqsense and do_inquiry functions.  Upon return from those functions this field contains the actual amount of data that was sent from the target during the command.
msgo_buf - Array item 0 of this field must be filled in with the appropriate identify message (0x8X or 0xCX).  The remaining array items can be filled in with a tag message or in the case of do_syncneg or do_wideneg must be filled in with the appropriate negotiation messages.  Tag messages are not allowed when doing sync or wide negotiation.
cmd_buf - This array field is filled in by the maintenance function.  It is not necessary to fill in this field.  Upon return from the function the actual scsi command used will be in this array.
stat_buf - This field is filled in by the maintenance function.  Upon return from the function the status byte received from the target will be located here.
msgi_buf - This field is filled in by the maintenance function.  Upon return from the function the msg in byte from the target at the completion of the command will be stored here.
emsgi_buf - This array field is filled in by the do_syncneg and do_wideneg with the return negotiation message.  It is not necessary to use this information to program the chip for wide or sync operation as the do_wideneg and do_syncneg functions perform this operation and place the appropriate values in the sel_info field above.
data_buf - This pointer must be assigned to a valid data buffer when executing a do_rqsense, do_inquiry, or do_rdcap function.  The buffer must be large enough to hold the maximum amount of data requested (i.e. it must be at least "data_length" in size or 10 bytes in the case of a read capacity)
scsirw
Structure required by the read/write scsi functions (do_read6, do_read10, do_write6, do_write10, and do_rw) All items marked input must be filled in.

typedef struct {
	ti_entry *sg_entry;     		/* input */
	VULONG sel_info;        		/* input */
	VULONG lba;             		/* input */
	VULONG blk_count;       		/* input */
	VINT id_count;          		/* input */
	VINT sg_count;          		/* input */
	VUBYTE enable_auto_rqs;	/* input */
	VUBYTE id_buf[3];       		/* input */
	VUBYTE cmd_buf[12];		/* output */
	VUBYTE sense_length;		/* output */
	VUBYTE sense_buf[18];		/* output */
	VUBYTE IO_major_status;	/* output */
	VUBYTE IO_minor_status;	/* output */
	VUBYTE Xfer_status;		/* output */
	VUBYTE stat_buf;        		/* output */
	VUBYTE msgi_buf;        		/* output */
	VUBYTE resel_msg_buf[3];	/* output */
} scsirw;

sg_entry - This is a pointer to a scatter gather list.  This pointer must be assigned to a valid scatter gather list.  Note that even if scatter gather is not used (i.e. only on data Table indirect entry) this pointer must be assigned to that single entry as this is the sole mechanism for passing byte count and address information to the function.
sel_info - This is the standard selection table indirect entry.  It must be filled in with the appropriate sync, wide and destination id information in the correct format.  See the ti_entry data structure description for the Select Table Indirect entry format.
lba - This is the starting Logical Block Address on the for the read or write transfer.  This value should not exceed the maximum LBA as reported by the target device.
blk_count - This is the block count for the read or write transfer.  This value plus the LBA must also not exceed the maximum LBA as reported by the target device.
id_count - This is the number of initial message bytes that should be sent to the target device.  It will generally be 1 or 3, 1 indicating only an identify message should be sent and 3 indicated an identify plus tag message should be sent.
sg_count - This is the number of scatter gather entries for this IO.  Note that non scatter gather IO's should initialize this value to one as all IO's are considered to be scatter gather, non-scatter gather IO's will just have an sg_count of 1.
enable_auto_rqs - Enable Auto Request Sense.  If the IO completes with a check condition the a request sense will be issued automatically if this flag is set.  Otherwise no request sense will be issued.
id_buf - This field should be filled in with the identify message for the IO and optionally a tag message for tagged command queuing.
cmd_buf - This field hold the actual command of the read or write.  It is not necessary to fill in this field except for the do_rw function.  Upon return from the read or write function this command will contain the command sent to the target device.  If the do_rw function is being called this field must be filled in with a read or write type command that is compatible with the do_rw function.
sense_length - If the IO completed with a check condition then this field will contain the number of request sense byte in the sense buffer
sense_buf - If the IO completes with a check condition then this buffer will contain the sense data from an auto request sense.
IO_major_status - This contains the major status of the IO on return. This indicatates the general cause of a failure if there is in fact a failure. See the above list of status values for all possible return values.
IO_minor_status - This contains the minor status of the IO on return. This indicates the specific cause of a failure if thare is in fact a failure. See the above list of status values for all possible return values.
Xfer_status - This status byte indicates if the transfer completed or not. See the above list for Xfer_status values.
stat_buf - Upon successful return this field will contain the status byte from the target at the end IO.
msgi_buf - Upon successful return this field will contain message in byte from the target at the end of the IO.
resel_msg_buf - This field is used to hold the reselection identify message and option tag from the target device after a reselection.  Upon successful return of a disconnecting IO this field will contain the last identify and tag message the target device sent.  If the IO is not disconnecting this field is undefined.
scsidev_record
This structure is returned as a linked list by the init_scsi routine.  It contains information about each device that was found on the SCSI bus.

typedef struct _scsidev_record  {
	VUBYTE id_type;
	VUBYTE flags;                    /* 0-sync,1-wide,2-cmdq,3-remove */
	VULONG sel_info;
	VULONG maxlba;
	VULONG blksize;
	struct _scsidev_record *nxt_dev;
} scsidev_record;

id_type - This field contains the target id of the device found and the type of the device as report in the inquiry data.
flags - This field contains certain flags indicating certain capabilities of the device.  Bit 0 indicates sync capability, bit 1 indicates wide capability, bit 2 indicates tag command queuing capability, and bit 3 indicates if the medium is removable.  Note that these flags only indicate capability, they do not indicate the current state of the device.
sel_info - This is the standard selection table indirect entry.  It must be filled in with the appropriate sync, wide and destination id information in the correct format.  See the ti_entry data structure description for the Select Table Indirect entry format.
maxlba - This is the Maximum Logical Block address allowed by the device as reported by the Read Capacity command.
blksize - This is the Block size of the device in bytes as reported in the Read Capacity command.
nxt_dev - This is a pointer to the next device in the linked list.

Function descriptions and examples
FILE: PCI.C 
Function: PCI_FindSYMDevice
	Prototype: VINT PCI_FindSYMDevice(pcidev_record *PCIDevice)
	Purpose : To determine if a given Symbios Logic device is installed in
		 	the PCI system.
	Input: Structure pcidev_record with the following entries filled in:
			device_id       The device id being searched for
			device_index    The index of the device being searched for
	Output: This function fills in the rest of the PCIDevice data structure
			if a device is found and returns PCI_DEVICE_FOUND.
			If no device was found with that ID and INDEX then
			PCI_NO_DEVICE_FOUND is returned with the PCIDevice structure
			unmodified.
	Assumptions: None
	Other functions called: 	PCI_GetPCIBIOSVersion to make sure there's a PCI BIOS
				PCI_GetConfigRegister to fill in the device rev id

Calling Example:
	/* look for devices */
	while (ID_Array[i] != NULL_DEVICE_ID) 
	{
		PCIDevice[NumPCIDevices]->device_id = ID_Array[i];
		PCIDevice[NumPCIDevices]->device_index = 0;
		/* find all devices with a particular device id */
		while (PCI_FindSYMDevice(PCIDevice[NumPCIDevices]) != PCI_NO_DEVICE_FOUND)
		{
			NumPCIDevices++;
			/* did we run out of space to store devices, if yes return */
			if (NumPCIDevices == Max_PCIDevices) return(NumPCIDevices+1);
			PCIDevice[NumPCIDevices]->device_index =
				 PCIDevice[NumPCIDevices-1]->device_index+1;
		}
		i++;
	}
Function: PCI_SetConfigRegister
	Prototype: void PCI_SetConfigRegister(pcidev_record *PCIDevice, VUINT offset, VULONG value)
	Purpose: To write a particular device's configuration register
	Input: pcidev_record data structure indicating the device to write to
			 offset - the dword offset in config space to write
			 value - the value to write to the config register
	Output: Nothing
	Assumptions: None
	Restrictions: Only dword writes to config space are allowed
	Other functions called: PCI_GetPCIBIOSVersion to make sure there's a PCI BIOS
Calling Example:
value = 0x11223344;
offset = 0x0C;
PCI_SetConfigRegister(PCIDevice, offset, value);

 Function: PCI_GetConfigRegister
	Prototype: VULONG PCI_GetConfigRegister(pcidev_record *PCIDevice, VUINT offset)
	Purpose: To read a particular devices configuration register
	Input: pcidev_record data structure indicating the device to read from
		offset - the dword offset in config space to read
	Output: Dword config register value
	Assumptions: None
	Restrictions: Only dword reads to config space are allowed
	Other functions called: PCI_GetPCIBIOSVersion to make sure there's a PCI BIOS
Calling Example:
offset = 0x0C;
value = PCI_GetConfigRegister(PCIDevice, offset);
Function: PCI_GetPCIBIOSVersion
	Prototype: VUINT PCI_GetPCIBIOSVersion(pci_bios_info *pcibios)
	Purpose: To determine what (if any) PCI BIOS version is out there
	Input: pointer to pci_bios_info data structure
		If this pointer is null then no attempt is made to fill in the
		structure (can be used for just assuring the existance of a PCI BIOS),
		if it is a valid pointer then info on the PCI BIOS is returned.
		This includes the Interface Version, Access Mechanism's supported
		and the last pci bus in the system.
	Output: 	PCI_BIOS_REV_1X - PCI BIOS version 1.x found
		PCI_BIOS_REV_2X - PCI BIOS version 2.x found
		PCI_UNKNOWN_BIOS - PCI BIOS found but unknown version
		PCI_NO_BIOS - No PCI BIOS present in the system
		If pcibios != NULL then BIOS info is filled in and returned in the
			structure.
	Assumptions: None
	Restrictions: None
	Other functions called: None
Calling Example:
	CALLED WITH POINTER TO PCI_BIOS_INFO STRUCTURE
	/* Check for PCI bios existance */
	if (PCI_GetPCIBIOSVersion(pcibios) == PCI_NO_BIOS) {
		WriteLog(LOG_FAIL, LOG_DETAIL, "\nNo PCI Bios found!!!", NULL);
		exit(1);
	}
	
	CALLED WITHOUT POINTER TO PCI_BIOS_INFO STRUCTURE
	pci_version = PCI_GetPCIBIOSVersion(NULL);

	/* make sure there is a PCI bios present */
	if (pci_version == PCI_NO_BIOS) {
		return(0xFFFFFFFFl);
	}
Function: PCI_check_pci_bios
	Prototype: void PCI_check_pci_bios(pci_bios_info *pcibios)
	Purpose: To check for the existance of a PCI system bios and print
		 out information about that bios.
	Input: pointer to pci_bios_info data structure
	Output: If no PCI bios is found this function prints an error and
		exits the entire program.  If a PCI bios is found then
		the information in the pcibios data structure is filled
		in via a call to PCI_GetPCIBIOSVersion and is printed.
	Assumptions: A valid pointer to the pcibios structure is passed
		     into the function.
	Restrictions: None
	Other functions called: 	PCI_GetPCIBIOSVersion to determine the 
					existance of a PCI bios and fill in the
					pcibios data structure
				Writelog to output information to a file
					or the screen depending on command line 
					switches
				sprintf to format a string for Writelog
Calling Example:
	PCI_check_pci_bios(&pcibios);


FILE: GEN_TOOL.C
Function: getPhysAddr
	Prototype: VULONG getPhysAddr(void far * addr) 
	Purpose: To determine the physical address of a given pointer
	Input: far pointer to a data buffer
	Output: Physical address of the pointer
	Assumptions: Executable is currently running in DOS real mode.
	Restrictions: This function will not work properly unless it is 
		      running in DOS real mode.  This does not include
		      a Windows DOS shell or any other type of DOS
		      shell running under a protected mode Operating system
	Other functions called: none
Calling Example:
	rw_buffer_table[RW_ID_BUF].address = getPhysAddr(rw->id_buf);

Function: IORead8
	Prototype: VUBYTE IORead8(VULONG IO_Addr)
	Purpose: To read a byte from an io port
	Input: IO address of byte to be read
	Output: byte read from io port
	Assumptions: That the IO port actually exists
	Restrictions: Although IO_Addr is defined as a VULONG it must not
		      exceed 16 bits in length as this is the maximum
		      IO address the X86 archtecture can produce
	Other functions called: inportb to read the io port
Calling Example:
	data = IORead8(PCIDevice->base_addr2+ISTAT);
Function: IOWrite8
	Prototype: void IOWrite8(VULONG IO_Addr, VUBYTE value)
	Purpose: To write a byte out to an IO port
	Input: Value to be written and IO port address
	Output: None
	Assumptions: That the IO port actually exists
	Restrictions: Although IO_Addr is defined as a VULONG it must not
		      exceed 16 bits in length as this is the maximum
		      IO address the X86 archtecture can produce
	Other functions called: outportb to write to the io port
Calling Example:
	data = 0x25;
	IOWrite8(PCIDevice->base_addr2+DCNTL, data);
Function: IORead32
	Prototype: VULONG IORead32(VULONG IO_Addr)
	Purpose: To read a dword (32 bits) from an io port 
	Input: IO address of dword to be read
	Output: dword read from io port
	Assumptions: That the IO port actually exists
	Restrictions: Although IO_Addr is defined as a VULONG it must not
		      exceed 16 bits in length as this is the maximum
		      IO address the X86 archtecture can produce
	Other functions called: none
Calling Example:
	long_data = IORead32(PCIDevice->base_addr2+DSPS);
Function: IOWrite32
	Prototype: void IOWrite32(VULONG IO_Addr, VULONG value)
	Purpose: To write a dword (32 bits) out to an IO port
	Input: Value to be written and IO port address
	Output: None
	Assumptions: That the IO port actually exists
	Restrictions: Although IO_Addr is defined as a VULONG it must not
		      exceed 16 bits in length as this is the maximum
		      IO address the X86 archtecture can produce
	Other functions called: none
Calling Example:
	long_data = 0x11223344;
	IOWrite32(PCIDevice->base_addr2+SCRATCHA, long_data);
Function: ByteAlignBuffer
	Prototype: void far *ByteAlignBuffer(void far *buffer, VINT alignment)
	Purpose: To align a buffer to a given byte alignment
	Input: Pointer to buffer to be aligned. Buffer should be 3 bytes 
	       	larger than it's desired size.
	       	Desired alignment of the given buffer.
		 	0 = dword (32-bit) aligned
			1 = byte (8-bit) aligned
		 	2 = word (16-bit) aligned
		 	3 = 3byte (24-bit) aligned
	Output: Pointer to requested buffer alignment.  The pointer will
		be as close to the buffer start address as possible.
	Assumptions: Executable is currently running in DOS real mode.
	Restrictions: This function will not work properly unless it is 
		      running in DOS real mode.  This does not include
		      a Windows DOS shell or any other type of DOS
		      shell running under a protected mode Operating system
	Other functions called: FP_SEG to get buffer segment
				FP_OFF to get buffer offset
				MK_FP to create a new far pointer to the
				requested buffer alignment
Calling Example:
	VUBYTE buffer[43];
	buffer = ByteAlignBuffer(buffer, 0);	/* align buffer to dword boundary */
Function: CacheAlignBuffer
	Prototype: void far *CacheAlignBuffer(void far *buffer, VINT cls, VINT offset)
	Purpose: To align a buffer to a given cache alignment
	Input: pointer to data buffer to be aligned.  Buffer should be a 
	       cache line size larger than the desired buffer size.
	       The cache line size to be aligned to.  This does not have
	       to be the cache line size of the system.
	       An offset from the cache line boundary
	Output: A pointer to the cache line boundary plus the offset based
		on the provided cache line size.  The pointer will be as
		close to the begining of the buffer as possible.
	Assumptions: Executable is currently running in DOS real mode.
	Restrictions: This function will not work properly unless it is 
		      running in DOS real mode.  This does not include
		      a Windows DOS shell or any other type of DOS
		      shell running under a protected mode Operating system
	Other functions called: FP_SEG to get buffer segment
				FP_OFF to get buffer offset
				MK_FP to create a new far pointer to the
				requested buffer alignment
Calling Example:
	VUBYTE buffer[160];
	buffer = CacheAlignBuffer(buffer, 8, 0); 	/* align buffer to 8 dword cache boundary */
Function: InitBuffer
	Prototype: void InitBuffer(VUBYTE far *buffer, VUINT size, VINT operation,VUBYTE fill_val)
	Purpose: To initialize a buffer to a known value
	Input: Far pointer to a byte data buffer.
	       	The size of the data buffer.
	      	The fill/increment value for the buffer
	       	The operation to be performed on the buffer
		  0 - fill buffer with fill value
		  1 - fill buffer with incrementing pattern, increment by
		      the fill value and start at 0.
		  2 - fill buffer with a random pattern.
	Output: Initialized buffer
	Assumptions: none
	Restrictions: Buffer size cannot exceed 64k
	Other functions called: none
Calling Example:
	VUBYTE buffer[43];
	InitBuffer(buffer, sizeof(buffer), 0, 0x5A);	/* fill buffer with 0x5A's */
Function: Get_Time
	Prototype: VULONG Get_Time(void)
	Purpose: Gets the current timer tick value from the system bios 
		 data area.  The timer ticks 18.2 times every second.
	Input: none
	Output: Current value of the timer
	Assumptions: None
	Restrictions: None
	Other functions called: MK_FP to create a pointer to the timer tick
				memory location
				enable to enable interrupts
				disable to disable interrupts
Calling Example:
	time = Get_Time();
Function: HasTimeElapsed
	Prototype: VINT HasTimeElapsed(VULONG StartTime, VINT Seconds)
	Purpose: To determine if a given amount of time in seconds has elapsed
	Input: A start time for a given time period to be measured
	       	The number of seconds to have elapsed
	Output: True (1) if the number of seconds has elapsed
		False (0) if not
	Assumptions: The system timers is ticking at 18.2 ticks per second.
		     To reduce complexity the ticks per second is rounded up
		     to 19.  This results in slightly higher actual elapsed
		     time periods but it is felt this will not pose a 
		     substantial problem as this function will be mainly
		     used as a watchdog type timer.
	Restrictions: None
	Other functions called: Get_Time to get the current time.
Calling Example:
	start_time = Get_Time();
	if (HasTimeElapsed(start_time, 5)) {
		break;
	}
Function: WriteLog
	Prototype: VINT WriteLog( VINT P_F, VINT B_D, VCHAR *Str1, VCHAR *Str2)
	Purpose: To write a standard string out to an output file. If
		 the log file is an actual file (not stdout) then the 
		 file is opened appended to and closed to prevent any
		 loss of information do to some hardware failure.
	Input: P_F - indicates a passing or failing log entry
		   (The macros LOG_PASS and LOG_FAIL in gen_tool.h can be
		    used for this parameter)
	       B_D - indicates a basic or detail log entry
		   (The macros LOG_BASIC and LOG_DETAIL in gen_tool.h can be
		    used for this parameter)
	       Str1 - Test name in a basic log entry & entire output string
		      in a detail entry.
	       Str2 - Parameter list in a basic entry, not used in detail entry
	       logfilename_ptr - This is a global pointer that points to
				 the name of the log file name.  If it is null
				 then the strings above are written to stdout
	Output:  Given the two parameter P_F and B_D four different strings
		 are written to either the log file or stdout or both.  The
		 following chart spells out the variations.
		 LOG_BASIC, LOG_PASS - "PASS Test:(Str1) Par:(Str2)\n"
		 LOG_BASIC, LOG_FAIL - "FAIL Test:(Str1) Par:(Str2)\n"
		 LOG_DETAIL, LOG_PASS - "(Str1)"
		 LOG_DETAIL, LOG_FAIL - "(Str1)"
			(Note that the final option (DETAIL, FAIL) is written
			 to both the log file and stderr if necessary, all
			 other options go to just the log file or stdout)
	Assumptions: logfilename_ptr is properly assigned
	Restrictions: Str1 and Str2 must not contain the newline symbol (\n)
	Other functions called: fopen to open the log file (if not stdout)
				fclose to close the log file (if not stdout)
				fprintf to print the strings
Calling Example:
	sprintf(string,"Device ID: %02X", PCIDevice->device_id);
	WriteLog(LOG_PASS, LOG_DETAIL, string, NULL);

FILE: GEN_TOOL.H
Macro Function: RMWon
	Prototype: RMWon (reg, mask)
	Purpose: Used to turn on a bits in an 8 bit register
	Input: IO port address and mask indicating which bits to turn on
		 1 indicating turn bit on and 0 indicating leave bit alone.
	Output: None
	Assumptions: That the IO port actually exists
	Restrictions: Although IO_Addr is defined as a VULONG it must not
			exceed 16 bits in length as this is the maximum
			IO address the X86 archtecture can produce
	Other functions called: IOWrite8 and IORead8 to write and read to the io port
	Calling Example:
		RMWon(PCIDevice->base_addr2+DMODE, 0xC0);
Macro Function: RMWoff
	Prototype: RMWoff (reg, mask)
	Purpose: Used to turn off a bits in an 8 bit register
	Input: IO port address and mask indicating which bits to turn off
			 1 indicating turn bit off and 0 indicating leave bit alone.
	Output: None
	Assumptions: That the IO port actually exists
	Restrictions: Although IO_Addr is defined as a VULONG it must not
				exceed 16 bits in length as this is the maximum
				IO address the X86 archtecture can produce
	Other functions called: IOWrite8 and IORead8 to write and read to the io port
	Calling Example:
		RMWoff (PCIDevice->base_addr2+DMODE, 0xC0);

FILE: 8XX_PCI.C
Function: C8XX_DevID2Str
	Prototype: VCHAR *C8XX_DevID2Str(VINT id, VUBYTE rev_id)
	Purpose : Returns 53C8XX Device Name string given a 53C8XX Device ID
	Input:  Valid 53C8XX device ID
	Output:	Descriptor string of 53C8xx device
		"Unknown Symbios SCSI Device" if the ID pass in is not known
	Assumptions: None
	Other functions called: None
Calling Example:
		sprintf(string,"\nDevice Name: %s", C8XX_DevID2Str(PCIDevice->device_id,
			PCIDevice->rev_id));
Function: C8XX_BuildPCIDeviceList
	Prototype: VINT C8XX_BuildPCIDeviceList(pcidev_record *PCIDevice[], VINT Max_PCIDevices)
	Purpose : Builds a list of 53C8XX devices found in the system
	Input:  Pointer to an array of pcidev_record structures and a limit
			  Max_PCIDevices indicating how big the pcidev_record array is.
	Output:	This function fills the PCIDevice data structure by calling
			the PCI_FindSYMDevice function for all possible ID's.
			If Max_PCIDevices is reached then the function returns immediately
			with a return value = Max_PCIDevices, otherwise it returns the
			number of devices found.
	Assumptions: That enough PCIDevice structures have been allocated to fill in
			 Max_PCIDevices structures
	Other functions called: PCI_FindSYMDevice
Calling Example:
		NumPCIDevices = C8XX_BuildPCIDeviceList(&PCIDevice_ptr, MAX_DEVICES);
Function: C8XX_ChoosePCIDevice
	Prototype: VINT C8XX_ChoosePCIDevice(pcidev_record *PCIDevice[], VINT NumPCIDevices)
	Purpose : Allows the selection of a particular 8xx device in the system
			 Displays all devices and prompts for a selection
	Input:  Array of pcidev_records (for all devices in the system) and the
		  actual number of devices in the system
	Output:	Returns the index of the selected device used to index into the
			PCIDevice array
	Assumptions: That NumPCIDevices gives the proper number of devices in the
			 PCIDevice array
	Other functions called: C8XX_DeviceID2Str
Calling Example:
		SelPCIDevice = C8XX_ChoosePCIDevice(&PCIDevice_ptr, NumPCIDevices);
Function: GetMemBase
	Prototype: VUINT C8XX_GetMemBase(pcidev_record *PCIDevice)
	Purpose : Fills in the PCIDevice structure with the Memory Base address
			 of the 53C8XX device
	Input: Pointer to Structure pcidev_record PCIDevice which indicates which
		 device to get the Memory base address for
	Output: Fills in the PCIDevice->base_addr1 field and returns C8XX_GOOD status
		  if the value read is non-zero.  Returns C8XX_NO_BASE if the value
		  read is zero
	Assumptions: Pointer to device structure is valid.
	Other functions called: PCI_GetConfigRegister
Calling Example:
		if (C8XX_GetMemBase(PCIDevice) != C8XX_GOOD)
		{
			WriteLog(LOG_FAIL, LOG_DETAIL, "\nError: device not mapped to Mem space!!", NULL);
			WriteLog(LOG_FAIL, LOG_DETAIL, "Cannot proceed with tests!!", NULL);
			exit(1);
		}
Function: GetIOBase
	Prototype: VUINT C8XX_GetIOBase(pcidev_record *PCIDevice)
	Purpose : Fills in the PCIDevice structure with the IO Base address
 			 of the 53C8XX device
	Input: Pointer to Structure pcidev_record PCIDevice which indicates which
		 device to get the IO base address for
	Output: Fills in the PCIDevice->base_addr2 field and returns C8XX_GOOD status
		  if the value read is non-zero.  Returns C8XX_NO_BASE if the value
		  read is zero
	Assumptions: Pointer to device structure is valid.
	Other functions called: PCI_GetConfigRegister
Calling Example:
		if (C8XX_GetIOBase(PCIDevice) != C8XX_GOOD)
		{
			WriteLog(LOG_FAIL, LOG_DETAIL, "\nError: device was not mapped to IO space!!", NULL);
			WriteLog(LOG_FAIL, LOG_DETAIL, "Cannot proceed with tests!!", NULL);
			exit(1);
		}
Function: GetRAMBase
	Prototype: VUINT C8XX_GetRAMBase(pcidev_record *PCIDevice)
	Purpose : Fills in the PCIDevice structure with the SCRIPT RAM Base address
			 of the 53C825A or 875 device
	Input: Pointer to Structure pcidev_record PCIDevice which indicates which
		 device to get the SCRIPT RAM base address for
	Output: Fills in the PCIDevice->base_addr3 field and returns C8XX_GOOD status
		  if the value read is non-zero.  Returns C8XX_NO_BASE if the value
		  read is zero
	Assumptions: Pointer to device structure is valid and the device is a 53C825A
			 or a 53C875.
	Other functions called: PCI_GetConfigRegister
Calling Example:
		if (C8XX_GetRAMBase(PCIDevice) != C8XX_GOOD)
		{
			WriteLog(LOG_FAIL, LOG_DETAIL, "\nWarning: device's Script RAM not mapped!!", NULL);
		}
Function: PCI_print_config
	Prototype: void PCI_print_config(pcidev_record *PCIDevice)
	Purpose : To output configurtion information about a PCI device
	Input: Pointer to Structure pcidev_record PCIDevice.  This structure
		 contains the config information to be output.
	Output: PCI config information either to the screen or to a file
	Assumptions: none
	Other functions called: sprintf to format string for Writelog
			         WriteLog to output information to file or screen
Calling Example:
	PCI_print_config(PCIDevice);

FILE: 8XX_TOOL.C
Function: init_8XX
	Prototype: void init_8XX(pcidev_record *PCIDevice)
	Purpose: To initialize a 53C8xx device to a known state
	Input: A pointer to the pcidev_record structure. 
		  The base_addr2 and device_id fields of this structure
		  are used in this routine.
	Output: Nothing
	Assumptions: SCSI Scripts are currently not executing
	Restrictions:  None
	Other functions called: IOWrite8 to write initialization values to
			         	chip registers
			         RMWon to turn on single bits in registers
			         WriteLog to output exactly what is being
			         	initialized to a log file
			         sprintf to format a string for WriteLog
			         delay to hold the SCSI bus reset assertion
Calling Example:
		init_8XX(PCIDevice);								  
Function: align_script
	Prototype: VULONG *align_script(VULONG *original_script, VUINT size)
	Purpose: To align a SCSI Script to a dword boundary
	Input: A pointer to the original script array           
	       	The size of the script array
	Output: A pointer to an aligned script array.  If the original
		array is already aligned then no memory is allocated.
		If not, new memory is allocated and aligned and the
		script is copied into this aligned memory and a pointer
		to this array is returned. If memory cannot be allocated
		an error is printed and the program will exit.
	Assumptions: none
	Restrictions:  none
	Other functions called: FP_OFF to get offset of script array
			         malloc to allocate a new array if necessary
			         _fmemcpy to copy script array
			         printf to print error message if memory
			     	cannot be allocated
Calling Example:
	 	script = align_script(MAINT_SCRIPT, sizeof(MAINT_SCRIPT));
	 	/* did we get the memory, if it was necessary to relocate the script */
	 	if (script == NULL) return(SCSI_COMMANDFAILED);									  
Function: PollISTAT
	Prototype: VINT PollISTAT(VULONG IO_Base, VULONG *vector, VUBYTE *dstat,
					VUBYTE *istat, VUINT *sist, VUINT timeout)
	Purpose: Poll the ISTAT register until an interrupt is detected or 
		 a timeout occurs.  This function will clear all interrupts
		 including stacked ones.
	Input: The IO Base address of the 53C8XX part           
	       	Pointers to variables to hold the values of dstat, istat, sist
	       	and an interrupt vector
	       	A timeout period in seconds, a timeout of 0 equals no timeout.
	Output: If a timeout occurs and no interrupt is detected then the
		function returns C8XX_POLLTO.
		If an interrupt is detected then the dstat, istat, sist and 
		if necessary vector variables are filled in and the function
		returns C8XX_GOOD.
	Assumptions:   none
	Restrictions:  none
	Other functions called: IORead8 to read the ISTAT register and
				dstat register
			         IORead32 to read the vector regiser and
				the sist register
			         Get_Time to get the current time
			         HasTimeElapsed to determine if the timeout
				has expired
Calling Example:
		/* wait for interrupt to complete */
		int_return = PollISTAT(PCIDevice->base_addr2, &vector, &dstat, &istat, &sist, 2);									  
Function: CopyToScRam
	Prototype: VINT CopyToScRam (pcidev_record *PCIDevice, VULONG far *script, VUINT size)
	Purpose: Copy a script to script ram.  This function uses a memory
		 	to memory move to copy the script to script ram
	Input: A pointer to the pcidev_record data structure           
		  The base_addr2 and 3 fields are used in this structure
	           A pointer to the script to be copied
	           The size of the script being copied
	Output: C8XX_GOOD upon successful completion of the copy
		C8XX_RAMCOPYFAILURE upon failure of the copy
	Assumptions: SCSI Scripts are currently not executing
		     	The device being accessed currently has scripts ram
		     	available.
	Restrictions:  Do not call this function while scripts are executing
	Other functions called: Bytealignbuffer to align the mem to mem
				move script
			         iowriteDSP to start the mem to mem script
			         pollISTAT to wait for an interrupt for
				completion of mem to mem move
Calling Example:
		ret = CopyToScRam(PCIDevice, script, 512);
		if (ret == C8XX_RAMCOPYFAILURE) {
			printf("Ram copy failed\n");
		}
Function: WriteScRam
	Prototype: VINT WriteScRam(pcidev_record *PCIDevice, VUBYTE byte, VINT offset)
	Purpose: write a byte to script ram.  This function uses a memory
		 to memory move to write to script ram
	Input: A pointer to the pcidev_record data structure           
		  The base_addr2 and 3 fields are used in this structure
	       	The value of the byte to be written
	       	The offset in scripts ram where the byte is to be written
	Output: C8XX_GOOD upon successful completion of the write
		C8XX_RAMWRITEFAILURE upon failure of the write
	Assumptions: SCSI Scripts are currently not executing
		     	The device being accessed currently has scripts ram
	Restrictions:  Do not call this function while scripts are executing
	Other functions called: Bytealignbuffer to align the mem to mem
				move script
			         iowriteDSP to start the mem to mem script
			         pollISTAT to wait for an interrupt for
				completion of mem to mem move
Calling Example:
		WriteScRam(PCIDevice, 0, offset);									  
Function: ReadScRam
	Prototype: VINT ReadScRam(pcidev_record *PCIDevice, VUBYTE *byte, VINT offset)
	Purpose: read a byte from script ram.  This function uses a memory
		 to memory move to read from script ram
	Input: A pointer to the pcidev_record data structure           
		The base_addr2 and 3 fields are used in this structure
	       	A pointer to the variable to recieve the byte
	       	The offset of the byte to be read
	Output: C8XX_GOOD upon successful completion of the read
		C8XX_RAMREADFAILURE upon failure of the read
	Assumptions: SCSI Scripts are currently not executing
		     	The device being accessed currently has scripts ram
	Restrictions:  Do not call this function while scripts are executing
	Other functions called: Bytealignbuffer to align the mem to mem
				move script
			         iowriteDSP to start the mem to mem script
			         pollISTAT to wait for an interrupt for
				completion of mem to mem move
Calling Example:
		ReadScRam(PCIDevice, &byte, offset);								  
Function: WriteLongScRam
	Prototype: VINT WriteLongScRam(pcidev_record *PCIDevice, VULONG dword, VINT offset)
	Purpose: write a dword to script ram.  This function uses a memory
		 to memory move to write to script ram
	Input: A pointer to the pcidev_record data structure           
		The base_addr2 and 3 fields are used in this structure
	       	The value of the dword to be written
	       	The offset in scripts ram where the dword is to be written
	Output: C8XX_GOOD upon successful completion of the write
		C8XX_RAMWRITEFAILURE upon failure of the write
	Assumptions: SCSI Scripts are currently not executing
		     	The device being accessed currently has scripts ram
	Restrictions:  Do not call this function while scripts are executing
	Other functions called: Bytealignbuffer to align the mem to mem
				move script
			         iowriteDSP to start the mem to mem script
			         pollISTAT to wait for an interrupt for
				completion of mem to mem move
Calling Example:
		WriteLongScRam(PCIDevice, 0x11223344, offset);	  
Function: ReadLongScRam
	Prototype: VINT ReadLongScRam(pcidev_record *PCIDevice, VULONG *dword, VINT offset)
	Purpose: read a dword from script ram.  This function uses a memory
		 to memory move to read script ram
	Input: A pointer to the pcidev_record data structure           
		The base_addr2 and 3 fields are used in this structure
	       	A pointer to the variable to recieve the dword
	       	The offset of the dword to be read
	Output: C8XX_GOOD upon successful completion of the read
		C8XX_RAMREADFAILURE upon failure of the read
	Assumptions: SCSI Scripts are currently not executing
		     	The device being accessed currently has scripts ram
	Restrictions:  Do not call this function while scripts are executing
	Other functions called: Bytealignbuffer to align the mem to mem
				move script
			         iowriteDSP to start the mem to mem script
			         pollISTAT to wait for an interrupt for
				completion of mem to mem move
Calling Example:
		ReadLongScRam(PCIDevice, &dword, offset);	  
Function: GenRandSG
	Prototype: VINT GenRandSG(VUBYTE far *buf, VUINT size, ti_entry *sg_list, VINT num_entries)
	Purpose: Generate a random scatter gather list.  The list is generated
		 in scripts table indirect format.  The function generates
		 random entries by dividing the buffer up into equal slices
		 and then generating a random number within each slice.  The
		 byte count for entry x then is equal to to the distance
		 to the slice boundary for entry x-1 plus some random number
		 between 0 and the slice.  This allows for relatively equal
		 distribution of scatter gather entries while maintaining a
		 relatively high amount of randomness.
	Input: A pointer to the buffer for which the list is to be generated           
	       	The size of the buffer
	       	A pointer to a scatter gather table (table indirect entries)
	       	The number of scatter gather entries desired
	Output: This function always returns C8XX_GOOD
	Assumptions: The number of entries is <= the size of the buffer
		     	The function randomize was called prior to calling this
		     	function
	Restrictions: The number of entries must be <= the size of the buffer
			Only call randomize once during the execution of the code
		      	(i.e. do not repeatedly call randomize as this will 
		       	cause not random numbers to be generated)
	Other functions called: getPhysAddr to get the physical address of the
				buffer
			         rand to generate random numbers
Calling Example:			  
		vubyte buffer[16000];
		ti_entry sg_list[10];
		GenRandSG(buffer, sizeof(buffer), sg_list, 10);

Function: C8XX_GetChipType
Prototype: VINT C8XX_GetChipType (pcidev_record *PCIDevice, c8xxdev_record *C8XXDevice) 
Purpose: Return the device type that is being tested
Input:  Pointer to PCIDevice data structure and Pointer to C8XXDevice data
	  structure
Output: Filled in C8XXDevice data structure if the device is recognized and C8XX_GOOD 
	is returned. 
	If not, C8XXDevice is unknown and UNKNOWN_DEVICE_TYPE is returned.
Assumptions: none
Restrictions: none
Other functions called: none
Calling Example:
c8xxdev_record C8XXDevice;
/* make sure this is a device we recognize */
if (C8XX_GetChipType(PCIDevice, &C8XXDevice) != C8XX_GOOD)
	return(NULL);

Function: C8XX_SetBurstSize
Prototype: void C8XX_SetBurstSize(pcidev_record *PCIDevice, VINT burst)
Purpose: Set the burst size of the device being tested
Input: A pointer to the PCIDevice data structure and the desired burst
	 size.  Burst size macros C8XX_BURST_N should be used for the
	 burst parameter to insure compatibility.
Output: Sets the burst size for the device pointed to by PCIDevice
Assumptions: That the burst is valid for this device
Restrictions: It would not be wise to call this function with a burst
		  size that is invalid for the device.
Other functions called: RMWoff/on to set and clear bits in regs
Calling Example:
C8XX_SetBurstSize(PCIDevice, C8XX_BURST_16);




FILE: 8XX_TOOL.H
Macro Function: iowriteDSP
	Prototype: iowriteDSP(IO_Base, value)
	Purpose: To write to DSP register to start script execution
	Input: The IO Base address of the 53C8XX part           
	       The value to be written to the DSP
	Output: Nothing
	Assumptions: SCSI Scripts are currently not executing
	Restrictions:  Do not call this macro while scripts are executing
	Other functions called: IOWrite32 to write the DSP
	Calling Example:
		iowriteDSP(PCIDevice->base_addr2, getPhysAddr(script));

FILE: 8XX_SCSI.C
Function: init_gpscripts
	Prototype: VINT init_gpscripts(void)
	Purpose : To initialize the maintenance and read/write scripts.  This
		  function is called by the core validation code and need not
		  be called by the test writer.
	Input: Nothing
	Output: On successful alignment and script initialization the function
		returns SCSI_GOOD.  If there are any memory allocation problems
		then the function returns SCSI_COMMANDFAILED.
	Assumptions: none
	Other functions called: malloc to allocate memory for ti tables 
			         ByteAlignBuffer to align ti tables
			         align_script to ensure script dword alignment
			         sizeof to get size of script arrays
			         getPhysAddr to initialize script buffers.
Calling Example:
		if (init_gpscripts() != SCSI_GOOD)
Function:  init_scsi
	Prototype: scsidev_record *init_scsi(pcidev_record *PCIDevice, VINT do_sync, VINT do_wide)
	Purpose : Find and initialize all scsi devices on the bus optionally
		  negotiating sync and wide.
	Input:  Pointer to pcidev_record structure to indicate the PCI device
		whose scsi bus to initialize.
		Flag do_sync to indicate whether or not to do sync negotiation
		or not (0 don't do sync neg., 1 do sync neg.)  The function
		will negotiate for the fastest the PCI device can transfer data.
		Flag do_wide to indicate whether or not to do wide negotiation
		or not (0 don't do wide neg., 1 do wide neg.)
	Output: A pointer to a linked list of scsidev_record strutures.  Each
		entry in the list represents a device located on the scsi bus.
		All important information about the device is contained in this
		structure.  See 8xx_scsi.h for a detailed description of the
		scsidev_record structure.
	Assumptions:  none
	Restrictions: If a device hangs the bus during this function it will
					  no longer function properly.
	Other functions called: SCSI routines are called in this order:
				do_tur, do_rqsense, do_inquiry, do_rdcap
				and optionally do_wideneg and do_syncneg
				IORead8 to read chip registers
				malloc to get memory for scsi device entry
				sizeof to get size of scsi device record
	Notes: This function will attempt to clear all check conditions prior
		to continuing to look at a device.  This includes clearing power on
		reset or issuing a start unit to spin the device up.
		This function will reset the SCSI bus.
		This function will only do wide negotiation if requested, the drive
		supports it and the chip supports it.
		If the 8xx device being used is not recognized this function will
		return NULL.
		This function will not scan the device's scsi id, it will skip
		that id.
Calling Example:
		scsidev_record *SCSIDevice;
		SCSIDevice = NULL;
		SCSIDevice = init_scsi(PCIDevice, 0, 0);

		if (SCSIDevice == NULL) printf("No SCSI devices found...\n");
		else {
			current_dev = SCSIDevice;
			while (current_dev != NULL) {
				printf("id_type: %02x\n",current_dev->id_type);
				printf("flags: %02x\n",current_dev->flags);
				printf("Sel info: %08lx\n", current_dev->sel_info);
				printf("maxlba: %08lx\n", current_dev->maxlba);
				printf("block size: %08lx\n", current_dev->blksize);
				current_dev = current_dev->nxt_dev;
			}
		}
Function:  do_tur
	Prototype: VINT do_TUR(pcidev_record *PCIDevice, scsimaint *maint)
	Purpose :  To execute a Test Unit Ready to a device on the SCSI bus
	Input:  A pointer to the pcidev_record data structure and the scsimaint
		  data structure.  The following variables in the scsimaint structure
		  must be initialized for do_tur to function properly:
			sel_info must have a valid table indirect selection entry
				remember ordering of the dword is (SCNTL3|SDID|SXFER|00)
		  All other variables in the structure need not be initialized.
	Output: Upon successful completion do_tur returns SCSI_GOOD.
		Upon an ISTAT polling timeout (no interrupt) do_tur returns SCSI_POLLTO
		Upon a selection timeout do_tur returns SCSI_SELECTTO
		Upon any other type of interrupt do_tur returns SCSI_ILLEGAL_INT
		Upon any other error condition do_tur returns SCSI_UNKNOWN
		The following variables in the scsimaint data structure will be
		  modified:
			cmd_buf will contain the TUR command
			msgo_buf[0] will contain the identify message 0x80
			stat_buf will contain the status from the target
			msgi_buf will contain the final message in byte from the target
	Assumptions: none
	Restrictions: Disconnects are not allowed with this command.
	Other functions called:  IOWriteDSP to start the Script engine
			          IOWrite32 to initialize the DSA register
			          pollISTAT to look for an interrupt
			          getPhysAddr to patch TI entries
			          Fail_SCSI to clean up on an error condition
Calling Example:
		if ((PCIDevice->device_id == C875_DEVICE_ID) ||
		 	(PCIDevice->device_id == C860_DEVICE_ID)) {
				maint.sel_info = 0x35000000l;
		}
		else {
			maint.sel_info = 0x33000000l;
		}

		ret = do_tur(PCIDevice, &maint);

		if (ret == SCSI_SELECTTO) printf("Select Timeout\n");
		else if (ret == SCSI_GOOD) {
			printf("Command completed status = %x\n", maint.stat_buf);
		}
Function:  do_RqSense
	Prototype: VINT do_RqSense(pcidev_record *PCIDevice, scsimaint *maint)
	Purpose :  To execute a Request Sense or Inquiry to a device on the SCSI bus
	Input:  A pointer to the pcidev_record data structure and the scsimaint
		data structure.  The following variables in the scsimaint structure
		must be initialized for do_RqSense to function properly:
			sel_info must have a valid table indirect selection entry
				remember ordering of the dword is (SCNTL3|SDID|SXFER|00)
			data_length must be set to the desired amount of bytes to be
				recieved (Note this can be set to 0xFF to receive the maximum
				bytes the drive will give)
			data_buf must be initialized to point to a valid data buffer
				this buffer must be at least 'data_length' in size
			All other variables in the structure need not be initialized.
			The Rqsns_or_Inquiry variable is set to the command byte of one
				or the other commands.
	Output: Upon successful completion do_rqsense returns SCSI_GOOD.
		Upon an ISTAT polling timeout (no interrupt) do_rqsense returns SCSI_POLLTO
		Upon a selection timeout do_rqsense returns SCSI_SELECTTO
		Upon any other type of interrupt do_rqsense returns SCSI_ILLEGAL_INT
		Upon any other error condition do_rqsense returns SCSI_UNKNOWN
		The following variables in the scsimaint data structure will be
		  modified:
			cmd_buf will contain the Request Sense or Inquiry command
			msgo_buf[0] will contain the identify message 0x80
			data_buf will be filled with the Rq Snse or Inquiry data
			data_length will reflect the actual amount of data received
			stat_buf will contain the status from the target
			msgi_buf will contain the final message in byte from the target
	Assumptions: none
	Restrictions: Disconnects are not allowed with this command.
	Other functions called:  IOWriteDSP to start the Script engine
			          IOWrite32 to initialize the DSA register
			          pollISTAT to look for an interrupt
			          getPhysAddr to patch TI entries
			          Fail_SCSI to clean up on an error condition
Calling Example:
		VUBYTE test2[0xFF];
		if ((PCIDevice->device_id == C875_DEVICE_ID) ||
		 	(PCIDevice->device_id == C860_DEVICE_ID)) {
				maint.sel_info = 0x35000000l;
		}
		else {
			maint.sel_info = 0x33000000l;
		}

		maint.data_length = 0xff;
		maint.data_buf = test2;

		ret = do_RqSense(PCIDevice, &maint);

		if (ret == SCSI_SELECTTO) printf("Select Timeout\n");
		else if (ret == SCSI_GOOD) {
			printf("Command completed status = %x\n", maint.stat_buf);
			printf("Sense data:\n");
			for (i=0; i<maint.data_length; i++) {
				printf("%02x ", test2[i]);
				if (!((i+1)%8)) printf("\n");
			}
		}
Function:  do_Inquiry
	Prototype: VINT do_Inquiry(pcidev_record *PCIDevice, scsimaint *maint)
	Purpose :  To execute an Inquiry to a device on the SCSI bus
	Input:  A pointer to the pcidev_record data structure and the scsimaint
		data structure.  The following variables in the scsimaint structure
		  must be initialized for do_inquiry to function properly:
			sel_info must have a valid table indirect selection entry
				remember ordering of the dword is (SCNTL3|SDID|SXFER|00)
			data_length must be set to the desired amount of bytes to be
				recieved (Note this can be set to 0xFF to receive the maximum
				bytes the drive will give)
			data_buf must be initialized to point to a valid data buffer
				this buffer must be at least 'data_length' in size
			All other variables in the structure need not be initialized.
	Output: Upon successful completion do_inquiry returns SCSI_GOOD.
		Upon an ISTAT polling timeout (no interrupt) do_inquiry returns SCSI_POLLTO
		Upon a selection timeout do_inquiry returns SCSI_SELECTTO
		Upon any other type of interrupt do_inquiry returns SCSI_ILLEGAL_INT
		Upon any other error condition do_inquiry returns SCSI_UNKNOWN
		The following variables in the scsimaint data structure will be
		  modified:
			cmd_buf will contain Inquiry command
			msgo_buf[0] will contain the identify message 0x80
			data_buf will be filled with the Inquiry data
			data_length will reflect the actual amount of data received
			stat_buf will contain the status from the target
			msgi_buf will contain the final message in byte from the target
	Assumptions: none
	Restrictions: Disconnects are not allowed with this command.
	Other functions called:  IOWriteDSP to start the Script engine
			          IOWrite32 to initialize the DSA register
			          pollISTAT to look for an interrupt
			          getPhysAddr to patch TI entries
			          Fail_SCSI to clean up on an error condition

Calling Example:
		VUBYTE test2[0xFF];
		if ((PCIDevice->device_id == C875_DEVICE_ID) ||
		 	(PCIDevice->device_id == C860_DEVICE_ID)) {
				maint.sel_info = 0x35000000l;
		}
		else {
			maint.sel_info = 0x33000000l;
		}

		maint.data_length = 0xff;
		maint.data_buf = test2;

		ret = do_Inquiry(PCIDevice, &maint);

		if (ret == SCSI_SELECTTO) printf("Select Timeout\n");
		else if (ret == SCSI_GOOD) {
			printf("Command completed status = %x\n", maint.stat_buf);
			printf("Inquiry data:\n");
			for (i=0; i<maint.data_length; i++) {
				printf("%02x ", test2[i]);
				if (!((i+1)%8)) printf("\n");
			}
		}
Function:  do_RdCap
	Prototype: VINT do_RdCap(pcidev_record *PCIDevice, scsimaint *maint)
	Purpose :  To execute a Read Capicity to a device on the SCSI bus
	Input:  A pointer to the pcidev_record data structure and the scsimaint
		data structure.  The following variables in the scsimaint structure
		  must be initialized for do_RdCap to function properly:
			sel_info must have a valid table indirect selection entry
				remember ordering of the dword is (SCNTL3|SDID|SXFER|00)
			data_buf must be initialized to point to a valid data buffer
				this buffer must be at least 8 bytes in size
			All other variables in the structure need not be initialized.
	Output: Upon successful completion do_RdCap returns SCSI_GOOD.
		Upon an ISTAT polling timeout (no interrupt) do_RdCap returns SCSI_POLLTO
		Upon a selection timeout do_RdCap returns SCSI_SELECTTO
		Upon any other type of interrupt do_RdCap returns SCSI_ILLEGAL_INT
		Upon any other error condition do_RdCap returns SCSI_UNKNOWN
		The following variables in the scsimaint data structure will be
		  modified:
			cmd_buf will contain the Read Capacity command
			msgo_buf[0] will contain the identify message 0x80
			data_buf will be filled with the 8 bytes of Read Capacity data
			stat_buf will contain the status from the target
			msgi_buf will contain the final message in byte from the target
	Assumptions: none
	Restrictions: Disconnects are not allowed with this command.
	Other functions called:  IOWriteDSP to start the Script engine
			          IOWrite32 to initialize the DSA register
			          pollISTAT to look for an interrupt
			          getPhysAddr to patch TI entries
			          Fail_SCSI to clean up on an error condition
Calling Example:
		VUBYTE test2[0xFF];
		if ((PCIDevice->device_id == C875_DEVICE_ID) ||
		 	(PCIDevice->device_id == C860_DEVICE_ID)) {
				maint.sel_info = 0x35000000l;
		}
		else {
			maint.sel_info = 0x33000000l;
		}

		maint.data_buf = test2;

		ret = do_RdCap(PCIDevice, &maint);

		if (ret == SCSI_SELECTTO) printf("Select Timeout\n");
		else if (ret == SCSI_GOOD) {
			printf("Command completed status = %x\n", maint.stat_buf);
			printf("Read Capacity data:\n");
			for (i=0; i<8; i++) {
				printf("%02x ", test2[i]);
				if (!((i+1)%8)) printf("\n");
			}
		}


Function:  do_StartStopUnit
	Prototype: VINT do_StartStopUnit(pcidev_record *PCIDevice, scsimaint *maint)
	Purpose :  To execute a Start or Stop Unit to a device on the SCSI bus
	Input:  A pointer to the pcidev_record data structure and the scsimaint
		data structure.  The following variables in the scsimaint structure
		must be initialized for do_tur to function properly:
			cmd_buf[4] must contain a valid start or stop command.
			sel_info must have a valid table indirect selection entry
				remember ordering of the dword is (SCNTL3|SDID|SXFER|00)
			All other variables in the structure need not be initialized.
	Output: Upon successful completion do_StartStopUnit returns SCSI_GOOD.
		Upon an ISTAT polling timeout (no interrupt) do_StartStopUnit
		  returns SCSI_POLLTO
		Upon a selection timeout do_StartStopUnit returns SCSI_SELECTTO
		Upon any other type of interrupt do_StartStopUnit returns SCSI_ILLEGAL_INT
		Upon any other error condition do_StartStopUnit returns SCSI_UNKNOWN
		The following variables in the scsimaint data structure will be
		  modified:
			cmd_buf will contain the Start or Stop unit command
			msgo_buf[0] will contain the identify message 0x80
			stat_buf will contain the status from the target
			msgi_buf will contain the final message in byte from the target
	Assumptions: none
	Restrictions: Disconnects are not allowed with this command.
	Other functions called:  IOWriteDSP to start the Script engine
				 IOWrite32 to initialize the DSA register
				 pollISTAT to look for an interrupt
				 getPhysAddr to patch TI entries
				 Fail_SCSI to clean up on an error condition
Calling Example:
	maint.sel_info = 0x05050000
		maint.cmd_buf[4] = 0x01;
		if (do_StartStopUnit(PCIDevice, &maint) != SCSI_GOOD)
			error = 1;
Function:  do_SyncNeg
	Prototype: VINT do_SyncNeg(pcidev_record *PCIDevice, scsimaint *maint)
	Purpose :  To perform sync negotiation via a tur to a device on the SCSI bus
	Input:  A pointer to the pcidev_record data structure and the scsimaint
		data structure.  The following variables in the scsimaint structure
		must be initialized for do_SyncNeg to function properly:
			sel_info must have a valid table indirect selection entry
				remember ordering of the dword is (SCNTL3|SDID|SXFER|00)
			msgo_buf[4] must have the Sync Negotiation period as defined by
				the SCSI spec
			msgo_buf[5] must have the Sync Neqotiation offset as defined by
				the SCSI spec
			All other variables in the structure need not be initialized.
	Output: Upon successful completion do_SyncNeg returns SCSI_GOOD.
		Upon a Message Reject of the negotiation do_SyncNeg returns SCSI_MSGREJECT
		Upon an ISTAT polling timeout (no interrupt) do_SyncNeg returns SCSI_POLLTO
		Upon a selection timeout do_SyncNeg returns SCSI_SELECTTO
		Upon any other type of interrupt do_SyncNeg returns SCSI_ILLEGAL_INT
		Upon any other error condition do_SyncNeg returns SCSI_UNKNOWN
		The following variables in the scsimaint data structure will be
		  modified:
			cmd_buf will contain the TUR command
			msgo_buf[0] will contain the identify message 0x80
			msgo_buf[1-3] will contain the sync neg message [0x01,0x03,0x01]
			emsgi_buf[0-3] will contain the sync neg reply from the target
			stat_buf will contain the status from the target
			msgi_buf will contain the final message in byte from the target
			sel_info SCNTL3 an SXFER values will be modified to meet the
				clock divider requirement of the negotiated sync offset and
				transfer rate
	Assumptions: none
	Restrictions: Disconnects are not allowed with this command.
			Remember negotiation ordering should always be Wide then Sync
			as Wide negotiation resets Sync values to Async.
	Other functions called:  IOWriteDSP to start the Script engine
			          IOWrite32 to initialize the DSA register
			          pollISTAT to look for an interrupt
			          getPhysAddr to patch TI entries
			          Fail_SCSI to clean up on an error condition
Calling Example:
		maint.msgo_buf[4] = 0x19;
		maint.msgo_buf[5] = 0x08;

		ret = do_SyncNeg(PCIDevice, &maint);

		if (ret == SCSI_SELECTTO) printf("Select Timeout\n");
		else if (ret == SCSI_GOOD) {
			printf("Command completed status = %x\n", maint.stat_buf);
			printf("Sync values from drive:");
			for (i=0; i<4; i++) {
				if (!((1+i)%8)) printf("\n");
				printf("%02x ", maint.emsgi_buf[i]);
			}
		}
		else if (ret == SCSI_MSGREJECT) printf("Sync Message Reject\n");
Function:  do_WideNeg
	Prototype: VINT do_WideNeg(pcidev_record *PCIDevice, scsimaint *maint)
	Purpose :  To perform wide negotiation via a tur to a device on the SCSI bus
	Input:  A pointer to the pcidev_record data structure and the scsimaint
		data structure.  The following variables in the scsimaint structure
		must be initialized for do_WideNeg to function properly:
			sel_info must have a valid table indirect selection entry
				remember ordering of the dword is (SCNTL3|SDID|SXFER|00)
			msgo_buf[4] must have the Wide Negotiation value as defined by
				the SCSI spec (0=8-bit, 1=16-bit, 2=32-bit)
		  	All other variables in the structure need not be initialized.
	Output: Upon successful completion do_WideNeg returns SCSI_GOOD.
		Upon a Message Reject of the negotiation do_WideNeg returns SCSI_MSGREJECT
		Upon an ISTAT polling timeout (no interrupt) do_WideNeg returns SCSI_POLLTO
		Upon a selection timeout do_WideNeg returns SCSI_SELECTTO
		Upon any other type of interrupt do_WideNeg returns SCSI_ILLEGAL_INT
		Upon any other error condition do_WideNeg returns SCSI_UNKNOWN
		The following variables in the scsimaint data structure will be
		  modified:
			cmd_buf will contain the TUR command
			msgo_buf[0] will contain the identify message 0x80
			msgo_buf[1-3] will contain the wide neg message [0x01,0x02,0x03]
			emsgi_buf[0-2] will contain the wide neg reply from the target
			stat_buf will contain the status from the target
			msgi_buf will contain the final message in byte from the target
			sel_info SCNTL3 values will be modified to so that the EWS bit
				is set appropriately.  SXFER values will be reset to 0x00
		  		so that the chip will be reset to async as required in SCSI.

	Assumptions: none
	Restrictions: Disconnects are not allowed with this command.
			Remember negotiation ordering should always be Wide then Sync
				as Wide negotiation resets Sync values to Async.
			do_wide will reset sync values (in SCNTL3 and SXFER) as
				required in the scsi spec.
	Other functions called:  IOWriteDSP to start the Script engine
			          IOWrite32 to initialize the DSA register
			          pollISTAT to look for an interrupt
			          getPhysAddr to patch TI entries
			          Fail_SCSI to clean up on an error condition
Calling Example:
		maint.msgo_buf[4] = 0x01;

		ret = do_WideNeg(PCIDevice, &maint);

		if (ret == SCSI_SELECTTO) printf("Select Timeout\n");
		else if (ret == SCSI_GOOD) {
			printf("Command completed status = %x\n", maint.stat_buf);
			printf("Wide values from drive:");
			for (i=0; i<3; i++) {
				if (!((i+1)%8)) printf("\n");
				printf("%02x ", maint.emsgi_buf[i]);
			}
		}
		else if (ret == SCSI_MSGREJECT) printf("Wide Message Reject\n");
Function: do_Read6
	Prototype: VINT do_Read6(pcidev_record *PCIDevice, scsirw *rw)
	Purpose : To execute a 6 byte read to a SCSI device
	Input: A pointer to the pcidev_record structure and a pointer to the
	       	scsirw data structure.  The follow variables in the scsirw 
	       	structure must be initialized:
			sel_info must have a valid table indirect selection entry
				remember ordering of the dword is (SCNTL3|SDID|SXFER|00)
			lba must be initialized to a valid target logical block address
			blk_count must have a valid block count for the read
			id_count must be 1 or 3 depending on whether or not tagged
				command queuing is used (1 for no TCQ 3 for TCQ)
			id_buf[0-2] must be initilized with a valid identify message and
				optionally a 2 byte TCQ message
			sg_count must be initialized to the number of scatter gather entries
				NOTE: If scatter gather is not being used this variable should
				be set to 1.
			sg_entry should point to a valid scatter gather list in table 
				indirect format.  NOTE: If scatter gather is not being used
				this pointer should point to the single table indirect
				entry for the io.  The scatter gather list pointed to by
				sg_entry should match sg_count in length exactly.
			All other variables in the structure need not be initialized.
	Output:  do_Read6 returns the return value from the do_rw function.
			please see the do_rw function for a detailed description of
			return values.
		do_Read6 modifies the following variables in the scsirw data structure:
			cmd_buf is set to the appropriate read command given the
				settings of lba and blk_count.
			Other variables are modified by the do_rw function.  Please see that
				function description for a listing of other variables modified.
	Assumptions:  None
	Restrictions: None
	Other functions called:  do_rw to actually execute the read io to the 
				target. 
Calling Example:
		rw.sel_info = maint.sel_info;
		rw.id_count =3;
		rw.id_buf[0] = 0xC0;
		rw.id_buf[1] = 0x20;
		rw.id_buf[2] = 0x35;
		rw.sg_entry = sg_list;

		rw.sg_count = 10;
		rw.blk_count = 32;
		rw.lba = 0;
		GenRandSG(test3, rw.blk_count*512, sg_list, rw.sg_count);
		printf("Read6, LBA: %lx, #SG: %d, #Blk: %d\n", rw.lba, rw.sg_count, rw.blk_count);
		ret = do_Read6(PCIDevice, &rw);
		if (ret != SCSI_GOOD)
		{
			printf("Read6 FAIL LBA: %lx, #SG: %d, #Blk: %d\n", rw.lba, rw.sg_count, rw.blk_count);
		}
Function: do_Read10
	Prototype: VINT do_Read10(pcidev_record *PCIDevice, scsirw *rw)
	Purpose : To execute a 10 byte read to a SCSI device
	Input: A pointer to the pcidev_record structure and a pointer to the
	       	scsirw data structure.  The follow variables in the scsirw 
	       	structure must be initialized:
			sel_info must have a valid table indirect selection entry
				remember ordering of the dword is (SCNTL3|SDID|SXFER|00)
			lba must be initialized to a valid target logical block address
			blk_count must have a valid block count for the read
			id_count must be 1 or 3 depending on whether or not tagged
				command queuing is used (1 for no TCQ 3 for TCQ)
			id_buf[0-2] must be initilized with a valid identify message and
				optionally a 2 byte TCQ message
			sg_count must be initialized to the number of scatter gather entries
				NOTE: If scatter gather is not being used this variable should
				be set to 1.
			sg_entry should point to a valid scatter gather list in table 
				indirect format.  NOTE: If scatter gather is not being used
				this pointer should point to the single table indirect
				entry for the io.  The scatter gather list pointed to by
				sg_entry should match sg_count in length exactly.
			All other variables in the structure need not be initialized.


	Output:  do_Read10 returns the return value from the do_rw function.
			please see the do_rw function for a detailed description of
			return values.
		 do_Read10 modifies the following variables in the scsirw data structure:
			cmd_buf is set to the appropriate read command given the
				settings of lba and blk_count.
		 Other variables are modified by the do_rw function.  Please see that
			function description for a listing of other variables modified.
	Assumptions:  None
	Restrictions: None
	Other functions called:  do_rw to actually execute the read io to the 
				target. 
Calling Example:
		rw.sel_info = maint.sel_info;
		rw.id_count =3;
		rw.id_buf[0] = 0xC0;
		rw.id_buf[1] = 0x20;
		rw.id_buf[2] = 0x35;
		rw.sg_entry = sg_list;

		rw.sg_count = 10;
		rw.blk_count = 32;
		rw.lba = 0;
		GenRandSG(test3, rw.blk_count*512, sg_list, rw.sg_count);
		printf("Read10, LBA: %lx, #SG: %d, #Blk: %d\n", rw.lba, rw.sg_count, rw.blk_count);
		ret = do_Read10(PCIDevice, &rw);
		if (ret != SCSI_GOOD)
		{
			printf("Read10 FAIL LBA: %lx, #SG: %d, #Blk: %d\n", rw.lba, rw.sg_count, rw.blk_count);
		}
Function: do_Write6                  
	Prototype: VINT do_Write6(pcidev_record *PCIDevice, scsirw *rw)
	Purpose : To execute a 6 byte write to a SCSI device
	Input: A pointer to the pcidev_record structure and a pointer to the
	       	scsirw data structure.  The follow variables in the scsirw 
	       	structure must be initialized:
			sel_info must have a valid table indirect selection entry
				remember ordering of the dword is (SCNTL3|SDID|SXFER|00)
			lba must be initialized to a valid target logical block address
			blk_count must have a valid block count for the write
			id_count must be 1 or 3 depending on whether or not tagged
				command queuing is used (1 for no TCQ 3 for TCQ)
			id_buf[0-2] must be initilized with a valid identify message and
				optionally a 2 byte TCQ message
			sg_count must be initialized to the number of scatter gather entries
				NOTE: If scatter gather is not being used this variable should
				be set to 1.
			sg_entry should point to a valid scatter gather list in table 
				indirect format.  NOTE: If scatter gather is not being used
				this pointer should point to the single table indirect
				entry for the io.  The scatter gather list pointed to by
				sg_entry should match sg_count in length exactly.
			All other variables in the structure need not be initialized.
	Output:  do_Write6 returns the return value from the do_rw function.
			please see the do_rw function for a detailed description of
			return values.
		do_Write6 modifies the following variables in the scsirw data structure:
			cmd_buf is set to the appropriate write command given the
				settings of lba and blk_count.
		Other variables are modified by the do_rw function.  Please see that
			function description for a listing of other variables modified.
	Assumptions:  None
	Restrictions: None
	Other functions called:  do_rw to actually execute the write io to the 
				target. 
Calling Example:
		rw.sel_info = maint.sel_info;
		rw.id_count =3;
		rw.id_buf[0] = 0xC0;
		rw.id_buf[1] = 0x20;
		rw.id_buf[2] = 0x35;
		rw.sg_entry = sg_list;

		rw.sg_count = 10;
		rw.blk_count = 32;
		rw.lba = 0;
		GenRandSG(test3, rw.blk_count*512, sg_list, rw.sg_count);
		printf("Write6, LBA: %lx, #SG: %d, #Blk: %d\n", rw.lba, rw.sg_count, rw.blk_count);
		ret = do_Write6(PCIDevice, &rw);
		if (ret != SCSI_GOOD)
		{
			printf("Write6 FAIL LBA: %lx, #SG: %d, #Blk: %d\n", rw.lba, rw.sg_count, rw.blk_count);
		}
Function: do_Write10                  
	Prototype: VINT do_Write10(pcidev_record *PCIDevice, scsirw *rw)
	Purpose : To execute a 10 byte write to a SCSI device
	Input: A pointer to the pcidev_record structure and a pointer to the
		scsirw data structure.  The follow variables in the scsirw 
		structure must be initialized:
			sel_info must have a valid table indirect selection entry
				remember ordering of the dword is (SCNTL3|SDID|SXFER|00)
			lba must be initialized to a valid target logical block address
			blk_count must have a valid block count for the write
			id_count must be 1 or 3 depending on whether or not tagged
				command queuing is used (1 for no TCQ 3 for TCQ)
			id_buf[0-2] must be initilized with a valid identify message and
				optionally a 2 byte TCQ message
			sg_count must be initialized to the number of scatter gather entries
				NOTE: If scatter gather is not being used this variable should
				be set to 1.
			sg_entry should point to a valid scatter gather list in table 
				indirect format.  NOTE: If scatter gather is not being used
				this pointer should point to the single table indirect
				entry for the io.  The scatter gather list pointed to by
				sg_entry should match sg_count in length exactly.
			All other variables in the structure need not be initialized.
	Output:  do_Write10 returns the return value from the do_rw function.
			please see the do_rw function for a detailed description of
			return values.
		do_Write10 modifies the following variables in the scsirw data structure:
			cmd_buf is set to the appropriate write command given the
				settings of lba and blk_count.
		Other variables are modified by the do_rw function.  Please see that
			function description for a listing of other variables modified.
	Assumptions:  None
	Restrictions: None
	Other functions called:  do_rw to actually execute the write io to the 
				target. 
Calling Example:
 		rw.sel_info = maint.sel_info;
		rw.id_count =3;
		rw.id_buf[0] = 0xC0;
		rw.id_buf[1] = 0x20;
		rw.id_buf[2] = 0x35;
		rw.sg_entry = sg_list;

		rw.sg_count = 10;
		rw.blk_count = 32;
		rw.lba = 0;
		GenRandSG(test3, rw.blk_count*512, sg_list, rw.sg_count);
		printf("Write10, LBA: %lx, #SG: %d, #Blk: %d\n", rw.lba, rw.sg_count, rw.blk_count);
		ret = do_Write10(PCIDevice, &rw);
		if (ret != SCSI_GOOD)
		{
			printf("Write10 FAIL LBA: %lx, #SG: %d, #Blk: %d\n", rw.lba, rw.sg_count, rw.blk_count);
		}
Function: do_rw                  
	Prototype: VINT do_rw(pcidev_record *PCIDevice, scsirw *rw)
	Purpose : To execute a read or write type command to a SCSI device
	Input: A pointer to the pcidev_record structure and a pointer to the
		 scsirw data structure.  The follow variables in the scsirw
		 structure must be initialized:
			sel_info must have a valid table indirect selection entry
			  remember ordering of the dword is (SCNTL3|SDID|SXFER|00)
			id_count must be 1 or 3 depending on whether or not tagged
			  command queuing is used (1 for no TCQ 3 for TCQ)
			id_buf[0-2] must be initilized with a valid identify message and
			  optionally a 2 byte TCQ message
			sg_count must be initialized to the number of scatter gather entries
			  NOTE: If scatter gather is not being used this variable should
			  be set to 1.
			sg_entry should point to a valid scatter gather list in table
			  indirect format.  NOTE: If scatter gather is not being used
			  this pointer should point to the single table indirect
			  entry for the io.  The scatter gather list pointed to by
			  sg_entry should match sg_count in length exactly.
			cmd_buf must be initialized with a valid read or write type command
			enable_auto_rqs must be initialized to either 0 to disable auto
			  request sense or 1 (non-zero) to enable auto req. sense.
			All other variables in the structure need not be initialized.
	Output: Upon successful completion do_rw returns SCSI_GOOD.
		  Upon an ISTAT polling timeout (no interrupt) do_rw returns SCSI_POLLTO
		  Upon a selection timeout do_rw returns SCSI_SELECTTO
		  Upon a phase mismatch during Status, Command or Message In
			phase do_rw returns SCSI_COMMANDFAILED or SCSI_CON_COMMANDFAILED
			depending on the state of the scsi bus after trying to clear it
			up with the bitbucket routine in the Fail_SCSI function
		  Upon any SCSI interrupts other that Phase Mismatch or Select TO
			do_rw returns SCSI_COMMANDFAILED or SCSI_CON_COMMANDFAILED
		  Upon any DMA interrupt other than SIR do_rw will return
			SCSI_COMMANDFAILED or SCSI_CON_COMMANDFAILED
		  Upon any DMA SIR interrupt other than Command_Complete, Need_More_SG
			or SWIDE_byte_moved vectors do_rw will return SCSI_COMMANDFAILED
			or SCSI_CON_COMMANDFAILED
		  Upon a SCSI CHECK CONDITION status do_rw will return
			SCSI_COMMANDFAILED or SCSI_CON_COMMANDFAILED
		The following variables in the scsirw data structure are modified by
		  the do_rw function:
			The data buffers pointed to by the sg_entry TI entries
				will be filled with the data from the target on
				a read operation.
			stat_buf will contain the status from the target
			msgi_buf will contain the final message in byte from the target
			resel_msg_buf will contain the final reselection identify and
				TCQ message (if used) if disconnects were allowed on
				this IO.
			If auto request sense is enabled and a SCSI CHECK CONDITION
				occurs during the IO then the sense_length will contain
				the number of valid sense bytes and sense_buffer will
				contain the sense data from the request sense.
			Three other Status values, IO_Major_Status, IO_Minor_Status and
			 Xfer_status will be filled in with various status values.
			The values are #defined in 8XX_SCSI.H. The following is a
			 description on how those statuses will be filled in:
				Xfer_status will be a 1 if all data was transferred or a 0 if
				 all data was not transferred.  This is independant of whether
				 or not the IO completed succesfully or not.
				Upon an Illegal SCSI interrupt:
				  IO_Major_Status will contain SCSI_ILLEGAL_SCSI_INTERRUPT
				  IO_Minor_Status will indicate the specific interrupt
				Upon an Illegal DMA interrupt:
				  IO_Major_Status will contain SCSI_ILLEGAL_DMA_INTERRUPT
				  IO_Minor_Status will indicate the specific interrupt
				Upon an Illegal SCRIPT interrupt:
				  IO_Major_Status will contain SCSI_ILLEGAL_SCRIPT_INTERRUPT
				  IO_Minor_Status will indicate the specific interrupt
				Upon a succesful SCSI read or write:
				  IO_Major_Status will contain SCSI_COMMAND_COMPLETE
				  IO_Minor_Status will contain SCSI_NO_STATUS
				Upon a SCSI check condition status:
				  IO_Major_Status will contain SCSI_CHECK_CONDITION
				  IO_Minor_Status will indicate whether or not the request
				   sense data is valid.  If enable_auto_rqs is 0 then this
				   will always indicate invalid sense data.
				All of the conditions below will only have the IO_Major_Status
				 set.  IO_Minor_Status will be set to SCSI_NO_STATUS.
					Upon a interrupt polling time out:
					  IO_Major_Status will contain SCSI_CHECK_CONDITION
					Upon a SCSI Select Time Out:
					  IO_Major_Status will contain SCSI_SELECTTO
	Assumptions:  That the byte counts pointed to be sg_entry add up to the
				blk_count * the Block Size (i.e. the number of bytes requested
				from the target = the number of bytes to be moved by the part)
				If this is not the case then the IO will die a miserable death
	Restrictions: This function is designed to do read or write type io's to
			SCSI block devices only.  The author does not gaurantee it's
			functionality if any other type of scsi command is used.
	Other functions called: IORead8/32 and IOWrite32 to Read and Write chip registers
				IOWriteDSP to start Scripts engine
				getPhysAddr to patch TI entries for IO
				HandleDataInPM to clean up after a Data In phase mismatch
				HandleDataOutPM to clean up after a Data Out phase mismatch
				Fill_SG_Entries to set up scatter gather entries for
					the io
				PollISTAT to look for interrupts during the IO
				Fail_SCSI to clean up on any failing condition.
Calling Example:
		rw.sel_info = maint.sel_info;
		rw.id_count =3;
		rw.id_buf[0] = 0xC0;
		rw.id_buf[1] = 0x20;
		rw.id_buf[2] = 0x35;
		rw.sg_entry = sg_list;

		rw.sg_count = 10;
		rw.blk_count = 32;
		rw.lba = 0;
		GenRandSG(test3, rw.blk_count*512, sg_list, rw.sg_count);
		printf("Write10, LBA: %lx, #SG: %d, #Blk: %d\n", rw.lba, rw.sg_count, rw.blk_count);

		rw.cmd_count = 0x0000000A;

		/* set up the command */
		rw->cmd_buf[0] = 0x28;
		rw->cmd_buf[1] = 0x00;
		rw->cmd_buf[2] = (VUBYTE) ((rw.lba >> 24) & 0xFF);
		rw->cmd_buf[3] = (VUBYTE) ((rw.lba >> 16) & 0xFF);
		rw->cmd_buf[4] = (VUBYTE) ((rw.lba >> 8) & 0xFF);
		rw->cmd_buf[5] = (VUBYTE) rw.lba;
		rw->cmd_buf[6] = 0x00;
		rw->cmd_buf[7] = (VUBYTE) (rw.blk_count >> 8);
		rw->cmd_buf[8] = (VUBYTE) rw.blk_count;
		rw->cmd_buf[9] = 0x00;

		return(do_rw(PCIDevice, rw));
Function: Fill_SG_Entries
	Prototype: void Fill_SG_Entries(pcidev_record *PCIDevice, scsirw *rw, VINT *NextSGEntry)
	Purpose : To set up Scatter Gather entries in the RW script.  The
		  Script can handle up to MAX_SG_ENTRIES scatter gather entries 
		  before interrupting.  This routine is called initially to set
		  up up to 16 entries in the Script and is called again
		  for each 16 entries there are from there on.
	Input:  A pointer the pcidev_record and scsirw structures.  And 
		a pointer to an integer indicating the next Scatter Gather
		entry to be set up.
	Output: The rw_buffer_table scatter gather entries are initialized for
			the current set of scatter gather entries.
		NextSGEntry is set to the next SG entry number that is not set up
			if more than 16 entries were left to be serviced.
			It is set to -1 if no more entries are to be serviced.
	Assumptions:  None 
	Restrictions: None
	Other functions called: RMWon/off to set or clear the bit in the SBR
				register that the script checks to determine
				if there are more scatter gather entries to
				be serviced.
Calling Example:
		/* do the initial set up of the Scatter Gather entries */
		NextSGEntry = 0;
		Fill_SG_Entries(PCIDevice, rw, &NextSGEntry);
Function: HandleDataInPM
	Prototype: static void HandleDataInPM(pcidev_record *PCIDevice, VINT *Current_SG_Entry)
	Purpose : To handle clean up after a Phase Mismatch during Data In phase
	Input:  A pointer the pcidev_record and a pointer to a variable which
		  will indicate the Scatter Gather entry that was executing when
		  the PM occured, this is needed by the do_re function if there
		  was a byte in the SWIDE register.
	Output: Current_SG_Entry is filled in with the SG entry that was being
		  serviced.
	Assumptions:  That a phase mismatch has actully occured during data in.
	Restrictions: None
	Other functions called: IORead32 to read chip info
				iowriteDSP to start the script
	Calling Example:
		HandleDataInPM(PCIDevice, &Current_SG_Entry);
Function: HandleDataOutPM
	Prototype: static void HandleDataOutPM(pcidev_record *PCIDevice)
	Purpose : To handle clean up after a Phase Mismatch during Data Out phase
	Input:  A pointer the pcidev_record.
	Output: None
	Assumptions:  That a phase mismatch has actully occured during data out.
	Restrictions: None
	Other functions called: IORead32/8 to read chip info
			RMWon to set bits in chip regiters
			iowriteDSP to start the script
	Calling Example:
		HandleDataOutPM(PCIDevice);
Function: Fail_SCSI
	Prototype: VINT Fail_SCSI(pcidev_record *PCIDevice, VUBYTE istat, VUBYTE dstat,
				 VUINT sist, VULONG vector, VINT fail_type)
	Purpose : To fail a SCSI io and attempt to clear the scsi bus to a bus
		  free condition
	Input:  A pointer to the pcidev_record data structure.  The interrupt
		registers so that they can be printed out.  The failure type
		which is one of the following:
			SCSI_ILLEGAL_INT - an illegal interrupting condition
			SCSI_POLLTO - a interrupt polling timeout has occured
	Output: Fail_SCSI returns SCSI_COMMANDFAILED if the chip is not
			connected to the SCSI bus upon exit of the routine
		Fail_SCSI returns SCSI_CON_COMMANDFAILED if the chip is
			connected to the SCSI bus upon exit of the routine.
	Assumptions: Scripts are not currently running at the time
	Restrictions: This routine should only be called in catastophic failure
				conditions.
	Other functions called:  BitBucket to attempt to clear the scsi bus to
					bus free.
			          IORead8 to check the connected status of the chip
			          printf to print the error and interrupt regs
	Calling Example:
		return(Fail_SCSI(PCIDevice, istat, dstat, sist, vector, SCSI_ILLEGAL_INT));
Function: Bitbucket
	Prototype: VINT Bitbucket(pcidev_record *PCIDevice)
	Purpose : To clear any addtional bytes from the SCSI bus and a
		  failing io situation.
	Input: A pointer to the pcidev_record structure. 
	Output:  If it is possible to clear the scsi bus to a bus free
		 condition then SCSI_COMMANDFAILED is returned.
		 If it is not possible to clear the scsi bus to a bus free
		 condition then SCSI_CON_COMMANDFAILED is returned.
	Assumptions: That scripts are not currently running 
	Restrictions: This function can only attempt to clear the scsi bus
		      	if it is currently in a scsi input phase (i.e. STATUS,
		      	MSG_IN, or DATA_IN) if it is not in one of those phases
		      	then this routine cannot attempt to clear the bus.
	Other functions called:  RMWon to clear the fifos
			          IORead8 to check connected status
			          PollISTAT to look for an interrupt from the chip
Calling Example:
		/* attempt to clear the scsi bus to bus free */
		return(Bitbucket(PCIDevice));


FILE: VALIDATE.C
Function: main
	Prototype: void main(VINT argc, VCHAR **argv)
	Purpose : To initialize devices and standard data structures.  It
		  also calls the parsecmdline function to parse the command
		  line options and lastly calls the test function to execute
		  the specific test implemented.
	Input: Argc and argv which contain the command line parameters
	Output: Nothing
	Assumptions: none
	Restrictions: none
	Other functions called: strncpy to copy the default file name to a string
				WriteLog to output various device information
				sprintf to format strings for WriteLog
				fprintf to output things only to the screen
				exit to exit the program on errors
				
				The following initialization routines are called in this order:
				parsecmdline to parse command line parameters
				pci_check_pci_bios to ensure the existance of
					a pci bios
				C8XX_BuildDeviceList to build a list of C8XX
					devices in the system
				C8XX_ChoosePCIDevice to allow the user to 
					select a specific pci device to be
					used for testing
				C8XXGetChipType to get chip specific info
				C8XX_GetIOBase to get the IO Base address of
					a 53C8XX device
				C8XX_GetRAMBase to get the Script RAM Base
					Address of a 53C8XX device
				PCI_print_config to output the config registers
					of a specific device.
				init_8XX to initialize a 53C8XX device to a
					known state
				test to execute the programs specific chip test
Validation Core Code Documentation		Rev. 2.0							




Page  62 of 62


