diff -ruN linux-2.4.20-orig/drivers/scsi/Config.in linux-2.4.20/drivers/scsi/Config.in
--- linux-2.4.20-orig/drivers/scsi/Config.in	2002-11-28 18:53:14.000000000 -0500
+++ linux-2.4.20/drivers/scsi/Config.in	2003-01-21 19:22:00.000000000 -0500
@@ -253,6 +253,9 @@
 #      bool 'GVP Turbo 040/060 SCSI support (EXPERIMENTAL)' CONFIG_GVP_TURBO_SCSI
    fi
 fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   dep_tristate 'Promise SuperTrak SX6000 (EXPERIMENTAL)' CONFIG_SCSI_PTI_ST $CONFIG_SCSI $CONFIG_PCI
+fi
 
 endmenu
 
diff -ruN linux-2.4.20-orig/drivers/scsi/Makefile linux-2.4.20/drivers/scsi/Makefile
--- linux-2.4.20-orig/drivers/scsi/Makefile	2002-11-28 18:53:14.000000000 -0500
+++ linux-2.4.20/drivers/scsi/Makefile	2003-01-21 19:22:00.000000000 -0500
@@ -17,7 +17,7 @@
 CFLAGS_aha152x.o =   -DAHA152X_STAT -DAUTOCONF
 CFLAGS_gdth.o    = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
 CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
-
+CFLAGS_pti_st.o  =   -I.
 
 O_TARGET := scsidrv.o
 
@@ -127,6 +127,7 @@
 obj-$(CONFIG_SCSI_FCAL)		+= fcal.o
 obj-$(CONFIG_SCSI_CPQFCTS)	+= cpqfc.o
 obj-$(CONFIG_SCSI_LASI700)	+= lasi700.o 53c700.o
+obj-$(CONFIG_SCSI_PTI_ST)	+= pti_st.o
 
 subdir-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi
 obj-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi/acorn-scsi.o
@@ -215,3 +216,7 @@
 	mv script.h 53c700_d.h
 
 53c700.o: 53c700_d.h
+
+pti_st.o: pti_st.c pti_st.h pti_stdev.h i2odef.h
+	$(CC) $(CFLAGS) $(CFLAGS_pti_st.o) -c -o pti_st.o pti_st.c
+
diff -ruN linux-2.4.20-orig/drivers/scsi/i2odef.h linux-2.4.20/drivers/scsi/i2odef.h
--- linux-2.4.20-orig/drivers/scsi/i2odef.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.4.20/drivers/scsi/i2odef.h	2003-01-21 19:22:00.000000000 -0500
@@ -0,0 +1,1102 @@
+
+#if !defined(_I2ODEF_H_)
+
+#define	_I2ODEF_H
+
+#if !defined(_I2OTYPES_)
+
+#define	_I2OTYPES_
+
+/*
+ * Pragma macros. These are to assure appropriate alignment between
+ * host/IOP as defined by the I2O Specification. Each one of the shared
+ * header files includes these macros.
+ */
+
+#define PRAGMA_ALIGN_PUSH \
+#pragma align 4
+#define PRAGMA_ALIGN_POP \
+#pragma align 0
+#define PRAGMA_PACK_PUSH \
+#pragma pack 1
+#define PRAGMA_PACK_POP \
+#pragma pack 0
+
+/* Setup the basics */
+
+typedef    char   S8;
+typedef    short  S16;
+
+typedef    unsigned char  U8;
+typedef    unsigned short U16;
+
+//typedef    unsigned int   U32;
+//typedef    int            S32;
+typedef	   unsigned long U32;
+typedef	   long		 S32;
+
+/* Bitfields */
+
+typedef    U32  BF;
+
+
+/* VOID */
+
+#ifndef __VOID
+typedef    void  VOID;
+#define __VOID
+#endif
+
+
+/* Boolean */
+
+#ifndef __BOOL
+#define __BOOL
+
+#ifdef FALSE
+#undef FALSE
+#undef TRUE
+#endif
+
+typedef enum
+        {
+        FALSE = 0,
+	TRUE  = 1
+	} BOOL;
+#endif
+
+/**************************************************************************/
+
+/* 64 bit defines */
+
+typedef struct _S64 {
+   U32                         LowPart;
+   S32                         HighPart;
+} S64;
+
+typedef struct _U64 {
+   U32                         LowPart;
+   U32                         HighPart;
+} U64;
+
+/* Pointer to Basics */
+
+typedef    VOID                *PVOID;
+typedef    S8                  *PS8;
+typedef    S16                 *PS16;
+typedef    S32                 *PS32;
+typedef    S64                 *PS64;
+
+/* Pointer to Unsigned Basics */
+
+typedef    U8                  *PU8;
+typedef    U16                 *PU16;
+typedef    U32                 *PU32;
+typedef    U64                 *PU64;
+
+/* misc */
+
+typedef S32             I2O_ARG;
+typedef U32             I2O_COUNT;
+typedef U32             I2O_USECS;
+typedef U32             I2O_ADDR32;
+typedef U32             I2O_SIZE;
+
+#endif	/* _I2OTYPES_ */
+
+/**************************************************************************/
+
+/* I2O BSA Block Read Message Control Flags */
+
+typedef U16     I2O_BSA_READ_FLAGS;
+#define I2O_BSA_RD_FLAG_DONT_RETRY      0x0001
+#define I2O_BSA_RD_FLAG_SOLO            0x0002
+#define I2O_BSA_RD_FLAG_CACHE_READ      0x0004
+#define I2O_BSA_RD_FLAG_READ_PREFETCH   0x0008
+#define I2O_BSA_RD_FLAG_CACHE_DATA      0x0010
+
+/* I2O BSA Block Write Message Control Flags */
+
+typedef U16     I2O_BSA_WRITE_FLAGS;
+#define I2O_BSA_WR_FLAG_DONT_RETRY      0x0001
+#define I2O_BSA_WR_FLAG_SOLO            0x0002
+#define I2O_BSA_WR_FLAG_DONT_CACHE      0x0004
+#define I2O_BSA_WR_FLAG_WRITE_THRU      0x0008
+#define I2O_BSA_WR_FLAG_WRITE_TO        0x0010
+
+/****************************************************************************/
+
+typedef    U32        I2O_INITIATOR_CONTEXT;
+typedef    U32        I2O_TRANSACTION_CONTEXT;
+
+typedef    U32        I2O_PARAMETER_TID;
+
+/****************************************************************************/
+/* Message Frame defines and structures  */
+
+/*   Defines for the Version_Status field. */
+
+#define    I2O_VERSION_10                              0x00
+#define    I2O_VERSION_11                              0x01
+
+#define    I2O_VERSION_OFFSET_NUMBER_MASK              0x07
+#define    I2O_VERSION_OFFSET_SGL_TRL_OFFSET_MASK      0xF0
+
+/*   Defines for the Message Flags Field. */
+/*   Please Note the the FAIL bit is only set in the Transport Fail Message. */
+#define    I2O_MESSAGE_FLAGS_STATIC                    0x01
+#define    I2O_MESSAGE_FLAGS_64BIT_CONTEXT             0x02
+#define    I2O_MESSAGE_FLAGS_MULTIPLE                  0x10
+#define    I2O_MESSAGE_FLAGS_FAIL                      0x20
+#define    I2O_MESSAGE_FLAGS_LAST                      0x40
+#define    I2O_MESSAGE_FLAGS_REPLY                     0x80
+
+/* Defines for Request Status Codes:  Table 3-1 Reply Status Codes.  */
+
+#define    I2O_REPLY_STATUS_SUCCESS                    0x00
+#define    I2O_REPLY_STATUS_ABORT_DIRTY                0x01
+#define    I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER     0x02
+#define    I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER     0x03
+#define    I2O_REPLY_STATUS_ERROR_DIRTY                0x04
+#define    I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER     0x05
+#define    I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER     0x06
+#define    I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY        0x08
+#define    I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER   0x09
+#define    I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER   0x0A
+#define    I2O_REPLY_STATUS_TRANSACTION_ERROR          0x0B
+#define    I2O_REPLY_STATUS_PROGRESS_REPORT            0x80
+
+/* DetailedStatusCode defines for ALL messages: Table 3-2 Detailed Status Codes.  */
+
+#define    I2O_DETAIL_STATUS_SUCCESS                        0x0000
+#define    I2O_DETAIL_STATUS_BAD_KEY                        0x0002
+#define    I2O_DETAIL_STATUS_TCL_ERROR                      0x0003
+#define    I2O_DETAIL_STATUS_REPLY_BUFFER_FULL              0x0004
+#define    I2O_DETAIL_STATUS_NO_SUCH_PAGE                   0x0005
+#define    I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_SOFT     0x0006
+#define    I2O_DETAIL_STATUS_INSUFFICIENT_RESOURCE_HARD     0x0007
+#define    I2O_DETAIL_STATUS_CHAIN_BUFFER_TOO_LARGE         0x0009
+#define    I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION           0x000A
+#define    I2O_DETAIL_STATUS_DEVICE_LOCKED                  0x000B
+#define    I2O_DETAIL_STATUS_DEVICE_RESET                   0x000C
+#define    I2O_DETAIL_STATUS_INAPPROPRIATE_FUNCTION         0x000D
+#define    I2O_DETAIL_STATUS_INVALID_INITIATOR_ADDRESS      0x000E
+#define    I2O_DETAIL_STATUS_INVALID_MESSAGE_FLAGS          0x000F
+#define    I2O_DETAIL_STATUS_INVALID_OFFSET                 0x0010
+#define    I2O_DETAIL_STATUS_INVALID_PARAMETER              0x0011
+#define    I2O_DETAIL_STATUS_INVALID_REQUEST                0x0012
+#define    I2O_DETAIL_STATUS_INVALID_TARGET_ADDRESS         0x0013
+#define    I2O_DETAIL_STATUS_MESSAGE_TOO_LARGE              0x0014
+#define    I2O_DETAIL_STATUS_MESSAGE_TOO_SMALL              0x0015
+#define    I2O_DETAIL_STATUS_MISSING_PARAMETER              0x0016
+#define    I2O_DETAIL_STATUS_TIMEOUT                        0x0017
+#define    I2O_DETAIL_STATUS_UNKNOWN_ERROR                  0x0018
+#define    I2O_DETAIL_STATUS_UNKNOWN_FUNCTION               0x0019
+#define    I2O_DETAIL_STATUS_UNSUPPORTED_VERSION            0x001A
+#define    I2O_DEATIL_STATUS_DEVICE_BUSY                    0x001B
+#define    I2O_DETAIL_STATUS_DEVICE_NOT_AVAILABLE           0x001C
+
+/* Common I2O Field sizes  */
+
+#define    I2O_TID_SZ                                  12
+#define    I2O_FUNCTION_SZ                             8
+#define    I2O_UNIT_ID_SZ                              16
+#define    I2O_SEGMENT_NUMBER_SZ                       12
+
+#define    I2O_IOP_ID_SZ                               12
+#define    I2O_GROUP_ID_SZ                             16
+#define    I2O_IOP_STATE_SZ                            8
+#define    I2O_MESSENGER_TYPE_SZ                       8
+
+#define    I2O_CLASS_ID_SZ                             12
+#define    I2O_CLASS_ORGANIZATION_ID_SZ                16
+
+#define    I2O_4BIT_VERSION_SZ                         4
+#define    I2O_8BIT_FLAGS_SZ                           8
+#define    I2O_COMMON_LENGTH_FIELD_SZ                  16
+
+
+#define    I2O_DEVID_DESCRIPTION_SZ                    16
+#define    I2O_DEVID_VENDOR_INFO_SZ                    16
+#define    I2O_DEVID_PRODUCT_INFO_SZ                   16
+#define    I2O_DEVID_REV_LEVEL_SZ                      8
+#define    I2O_MODULE_NAME_SZ                          24
+
+#define    I2O_BIOS_INFO_SZ                            8
+
+#define    I2O_RESERVED_4BITS                          4
+#define    I2O_RESERVED_8BITS                          8
+#define    I2O_RESERVED_12BITS                         12
+#define    I2O_RESERVED_16BITS                         16
+#define    I2O_RESERVED_20BITS                         20
+#define    I2O_RESERVED_24BITS                         24
+#define    I2O_RESERVED_28BITS                         28
+
+/****************************************************************************/
+
+/* Common functions accross all classes. */
+
+#define    I2O_PRIVATE_MESSAGE                         0xFF
+
+/****************************************************************************/
+/* Class ID and Code Assignments */
+
+
+#define    I2O_CLASS_VERSION_10                        0x00
+#define    I2O_CLASS_VERSION_11                        0x01
+
+/*    Class Code Names:  Table 6-1 Class Code Assignments. */
+#define    I2O_CLASS_EXECUTIVE                         0x000
+#define    I2O_CLASS_DDM                               0x001
+#define    I2O_CLASS_RANDOM_BLOCK_STORAGE              0x010
+#define    I2O_CLASS_SEQUENTIAL_STORAGE                0x011
+#define    I2O_CLASS_LAN                               0x020
+#define    I2O_CLASS_WAN                               0x030
+#define    I2O_CLASS_FIBRE_CHANNEL_PORT                0x040
+#define    I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL          0x041
+#define    I2O_CLASS_SCSI_PERIPHERAL                   0x051
+#define    I2O_CLASS_ATE_PORT                          0x060
+#define    I2O_CLASS_ATE_PERIPHERAL                    0x061
+#define    I2O_CLASS_FLOPPY_CONTROLLER                 0x070
+#define    I2O_CLASS_FLOPPY_DEVICE                     0x071
+#define    I2O_CLASS_BUS_ADAPTER_PORT                  0x080
+/* Class Codes 0x090 - 0x09f are reserved for Peer-to-Peer classes */
+#define    I2O_CLASS_MATCH_ANYCLASS                    0xffffffff
+
+#define    I2O_SUBCLASS_i960                           0x001
+#define    I2O_SUBCLASS_HDM                            0x020
+#define    I2O_SUBCLASS_ISM                            0x021
+
+
+/*********************************************************************/
+
+#define    I2O_MAX_SERIAL_NUMBER_SZ                    256
+
+/****************************************************************************/
+
+/* I2O Message Frame common for all messages  */
+
+typedef struct _I2O_MESSAGE_FRAME {
+   U8                          VersionOffset;
+   U8                          MsgFlags;
+   U16                         MessageSize;
+   BF                          TargetAddress:I2O_TID_SZ;
+   BF                          InitiatorAddress:I2O_TID_SZ;
+   BF                          Function:I2O_FUNCTION_SZ;
+   I2O_INITIATOR_CONTEXT       InitiatorContext;
+} I2O_MESSAGE_FRAME, *PI2O_MESSAGE_FRAME;
+
+
+/****************************************************************************/
+
+/* I2O Successful Single Transaction Reply Message Frame structure. */
+
+typedef struct _I2O_SINGLE_REPLY_MESSAGE_FRAME {
+   I2O_MESSAGE_FRAME           StdMessageFrame;
+   I2O_TRANSACTION_CONTEXT     TransactionContext;
+   U16                         DetailedStatusCode;
+   U8                          reserved;
+   U8                          ReqStatus;
+/*                             ReplyPayload        */
+} I2O_SINGLE_REPLY_MESSAGE_FRAME, *PI2O_SINGLE_REPLY_MESSAGE_FRAME;
+
+
+/****************************************************************************/
+
+/* I2O Private Message Frame structure. */
+typedef struct _I2O_PRIVATE_MESSAGE_FRAME {
+   I2O_MESSAGE_FRAME           StdMessageFrame;
+   I2O_TRANSACTION_CONTEXT     TransactionContext;
+   U16                         XFunctionCode;
+   U16                         OrganizationID;
+/*                             PrivatePayload[]        */
+} I2O_PRIVATE_MESSAGE_FRAME, *PI2O_PRIVATE_MESSAGE_FRAME;
+
+/****************************************************************************/
+
+/*
+    Random Block Storage Class specific functions
+    
+    Although the names are block storage class specific, the values 
+    assigned are common with other classes when applicable.
+*/
+
+#define     I2O_BSA_BLOCK_READ              0x30
+#define     I2O_BSA_BLOCK_REASSIGN          0x71
+#define     I2O_BSA_BLOCK_WRITE             0x31
+#define     I2O_BSA_BLOCK_WRITE_VERIFY      0x33
+#define     I2O_BSA_CACHE_FLUSH             0x37
+#define     I2O_BSA_DEVICE_RESET            0x27
+#define     I2O_BSA_MEDIA_EJECT             0x43
+#define     I2O_BSA_MEDIA_FORMAT            0x45
+#define     I2O_BSA_MEDIA_LOCK              0x49
+#define     I2O_BSA_MEDIA_MOUNT             0x41
+#define     I2O_BSA_MEDIA_UNLOCK            0x4B
+#define     I2O_BSA_MEDIA_VERIFY            0x35
+#define     I2O_BSA_POWER_MANAGEMENT        0x70
+#define     I2O_BSA_STATUS_CHECK            0x25
+
+/****************************************************************************/
+
+/* Memory Addressing structures and defines. */
+
+/* SglFlags defines. */
+
+#define    I2O_SGL_FLAGS_LAST_ELEMENT                  0x80
+#define    I2O_SGL_FLAGS_END_OF_BUFFER                 0x40
+
+#define    I2O_SGL_FLAGS_IGNORE_ELEMENT                0x00
+#define    I2O_SGL_FLAGS_TRANSPORT_ELEMENT             0x04
+#define    I2O_SGL_FLAGS_BIT_BUCKET_ELEMENT            0x08
+#define    I2O_SGL_FLAGS_IMMEDIATE_DATA_ELEMENT        0x0C
+#define    I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT        0x10
+#define    I2O_SGL_FLAGS_PAGE_LIST_ADDRESS_ELEMENT     0x20
+#define    I2O_SGL_FLAGS_CHAIN_POINTER_ELEMENT         0x30
+#define    I2O_SGL_FLAGS_LONG_TRANSACTION_ELEMENT      0x40
+#define    I2O_SGL_FLAGS_SHORT_TRANSACTION_ELEMENT     0x70
+#define    I2O_SGL_FLAGS_SGL_ATTRIBUTES_ELEMENT        0x7C
+
+#define    I2O_SGL_FLAGS_BC0                           0x01
+#define    I2O_SGL_FLAGS_BC1                           0x02
+#define    I2O_SGL_FLAGS_DIR                           0x04
+#define    I2O_SGL_FLAGS_LOCAL_ADDRESS                 0x08
+
+#define    I2O_SGL_FLAGS_CONTEXT_COUNT_MASK            0x03
+#define    I2O_SGL_FLAGS_ADDRESS_MODE_MASK             0x3C
+#define    I2O_SGL_FLAGS_NO_CONTEXT                    0x00
+
+/* 32 Bit Context Field defines */
+
+#define    I2O_SGL_FLAGS_CONTEXT32_NULL                0x00
+#define    I2O_SGL_FLAGS_CONTEXT32_U32                 0x01
+#define    I2O_SGL_FLAGS_CONTEXT32_U64                 0x02
+#define    I2O_SGL_FLAGS_CONTEXT32_U96                 0x03
+
+#define    I2O_SGL_FLAGS_CONTEXT32_NULL_SZ             0x00
+#define    I2O_SGL_FLAGS_CONTEXT32_U32_SZ              0x04
+#define    I2O_SGL_FLAGS_CONTEXT32_U64_SZ              0x08
+#define    I2O_SGL_FLAGS_CONTEXT32_U96_SZ              0x0C
+
+/* 64 Bit Context Field defines */
+
+#define    I2O_SGL_FLAGS_CONTEXT64_NULL                0x00
+#define    I2O_SGL_FLAGS_CONTEXT64_U64                 0x01
+#define    I2O_SGL_FLAGS_CONTEXT64_U128                0x02
+#define    I2O_SGL_FLAGS_CONTEXT64_U192                0x03
+
+#define    I2O_SGL_FLAGS_CONTEXT64_NULL_SZ             0x00
+#define    I2O_SGL_FLAGS_CONTEXT64_U64_SZ              0x08
+#define    I2O_SGL_FLAGS_CONTEXT64_U128_SZ             0x10
+#define    I2O_SGL_FLAGS_CONTEXT64_U192_SZ             0x18
+
+/* SGL Attribute Element defines */
+
+#define    I2O_SGL_ATTRIBUTE_FLAGS_BIT_BUCKET_HINT     0x0400
+#define    I2O_SGL_ATTRIBUTE_FLAGS_IMMEDIATE_DATA_HINT 0x0200
+#define    I2O_SGL_ATTRIBUTE_FLAGS_LOCAL_ADDRESS_HINT  0x0100
+#define    I2O_SGL_ATTRIBUTE_FLAGS_32BIT_TRANSACTION   0x0000
+#define    I2O_SGL_ATTRIBUTE_FLAGS_64BIT_TRANSACTION   0x0004
+#define    I2O_SGL_ATTRIBUTE_FLAGS_32BIT_LOCAL_ADDRESS 0x0000
+
+/* SG Size defines */
+
+#define    I2O_SG_COUNT_SZ                             24
+#define    I2O_SG_FLAGS_SZ                             8
+
+/* Standard Flags and Count fields for SG Elements */
+
+typedef struct _I2O_FLAGS_COUNT {
+   BF                          Count:I2O_SG_COUNT_SZ;
+   BF                          Flags:I2O_SG_FLAGS_SZ;
+} I2O_FLAGS_COUNT, *PI2O_FLAGS_COUNT;
+
+/* Bit Bucket Element */
+typedef struct _I2O_SGE_BIT_BUCKET_ELEMENT {
+   I2O_FLAGS_COUNT             FlagsCount;
+   U32                         BufferContext;
+} I2O_SGE_BIT_BUCKET_ELEMENT, *PI2O_SGE_BIT_BUCKET_ELEMENT;
+
+/* Chain Addressing Scatter-Gather Element */
+
+typedef struct _I2O_SGE_CHAIN_ELEMENT {
+   I2O_FLAGS_COUNT             FlagsCount;
+   U32                         PhysicalAddress;
+} I2O_SGE_CHAIN_ELEMENT, *PI2O_SGE_CHAIN_ELEMENT;
+
+/* Chain Addressing with Context Scatter-Gather Element */
+
+typedef struct _I2O_SGE_CHAIN_CONTEXT_ELEMENT {
+   I2O_FLAGS_COUNT             FlagsCount;
+   U32                         Context[1];
+   U32                         PhysicalAddress;
+} I2O_SGE_CHAIN_CONTEXT_ELEMENT, *PI2O_SGE_CHAIN_CONTEXT_ELEMENT;
+
+/* Ignore Scatter-Gather Element */
+
+typedef struct _I2O_SGE_IGNORE_ELEMENT {
+   I2O_FLAGS_COUNT             FlagsCount;
+} I2O_SGE_IGNORE_ELEMENT, *PI2O_SGE_IGNORE_ELEMENT;
+
+/* Immediate Data Element */
+
+typedef struct _I2O_SGE_IMMEDIATE_DATA_ELEMENT {
+   I2O_FLAGS_COUNT             FlagsCount;
+} I2O_SGE_IMMEDIATE_DATA_ELEMENT, *PI2O_SGE_IMMEDIATE_DATA_ELEMENT;
+
+/* Immediate Data with Context Element */
+
+typedef struct _I2O_SGE_IMMEDIATE_DATA_CONTEXT_ELEMENT {
+   I2O_FLAGS_COUNT             FlagsCount;
+   U32                         BufferContext;
+} I2O_SGE_IMMEDIATE_DATA_CONTEXT_ELEMENT, *PI2O_SGE_IMMEDIATE_DATA_CONTEXT_ELEMENT;
+
+/* Long Transaction Parameters Element */
+
+typedef struct _I2O_SGE_LONG_TRANSACTION_ELEMENT {
+   BF                          LongElementLength:I2O_SG_COUNT_SZ;
+   BF                          Flags:I2O_SG_FLAGS_SZ;
+   U32                         BufferContext;
+} I2O_SGE_LONG_TRANSACTION_ELEMENT, *PI2O_SGE_LONG_TRANSACTION_ELEMENT;
+
+/* Page List Scatter-Gather Element */
+
+typedef struct _I2O_SGE_PAGE_ELEMENT {
+   I2O_FLAGS_COUNT             FlagsCount;
+   U32                         PhysicalAddress[1];
+} I2O_SGE_PAGE_ELEMENT , *PI2O_SGE_PAGE_ELEMENT ;
+
+/* Page List with Context Scatter-Gather Element */
+
+typedef struct _I2O_SGE_PAGE_CONTEXT_ELEMENT {
+   I2O_FLAGS_COUNT             FlagsCount;
+   U32                         BufferContext[1];
+   U32                         PhysicalAddress[1];
+} I2O_SGE_PAGE_CONTEXT_ELEMENT, *PI2O_SGE_PAGE_CONTEXT_ELEMENT;
+
+/* SGL Attribute Element */
+
+typedef struct _I2O_SGE_SGL_ATTRIBUTES_ELEMENT {
+   U16                         SglAttributeFlags;
+   U8                          ElementLength;
+   U8                          Flags;
+   U32                         PageFrameSize;
+} I2O_SGE_SGL_ATTRIBUTES_ELEMENT, *PI2O_SGE_SGL_ATTRIBUTES_ELEMENT;
+
+/* Short Transaction Parameters Element */
+
+typedef struct _I2O_SGE_SHORT_TRANSACTION_ELEMENT {
+   U16                         ClassFields;
+   U8                          ElementLength;
+   U8                          Flags;
+   U32                         BufferContext;
+} I2O_SGE_SHORT_TRANSACTION_ELEMENT, *PI2O_SGE_SHORT_TRANSACTION_ELEMENT;
+
+/* Simple Addressing Scatter-Gather Element */
+
+typedef struct _I2O_SGE_SIMPLE_ELEMENT {
+   I2O_FLAGS_COUNT             FlagsCount;
+   U32                         PhysicalAddress;
+} I2O_SGE_SIMPLE_ELEMENT, *PI2O_SGE_SIMPLE_ELEMENT;
+
+/* Simple Addressing with Context Scatter-Gather Element */
+
+typedef struct _I2O_SGE_SIMPLE_CONTEXT_ELEMENT {
+   I2O_FLAGS_COUNT             FlagsCount;
+   U32                         BufferContext[1];
+   U32                         PhysicalAddress;
+} I2O_SGE_SIMPLE_CONTEXT_ELEMENT, *PI2O_SGE_SIMPLE_CONTEXT_ELEMENT;
+
+/* Transport Detail Element */
+
+typedef struct _I2O_SGE_TRANSPORT_ELEMENT {
+   BF                          LongElementLength:I2O_SG_COUNT_SZ;
+   BF                          Flags:I2O_SG_FLAGS_SZ;
+} I2O_SGE_TRANSPORT_ELEMENT, *PI2O_SGE_TRANSPORT_ELEMENT;
+
+
+typedef struct _I2O_SG_ELEMENT {
+   union {
+       /* Bit Bucket Element */
+       I2O_SGE_BIT_BUCKET_ELEMENT          BitBucket;
+
+       /* Chain Addressing Element */
+       I2O_SGE_CHAIN_ELEMENT               Chain;
+
+       /* Chain Addressing with Context Element */
+       I2O_SGE_CHAIN_CONTEXT_ELEMENT       ChainContext;
+
+       /* Ignore Scatter-Gather Element */
+       I2O_SGE_IGNORE_ELEMENT              Ignore;
+
+       /* Immediate Data Element */
+       I2O_SGE_IMMEDIATE_DATA_ELEMENT      ImmediateData;
+
+       /* Immediate Data with Context Element */
+       I2O_SGE_IMMEDIATE_DATA_CONTEXT_ELEMENT  ImmediateDataContext;
+
+       /* Long Transaction Parameters Element */
+       I2O_SGE_LONG_TRANSACTION_ELEMENT    LongTransaction;
+
+       /* Page List Element */
+       I2O_SGE_PAGE_ELEMENT                Page;
+
+       /* Page List with Context Element */
+       I2O_SGE_PAGE_CONTEXT_ELEMENT        PageContext;
+
+       /* SGL Attribute Element */
+       I2O_SGE_SGL_ATTRIBUTES_ELEMENT      SGLAttribute;
+
+       /* Short Transaction Parameters Element */
+       I2O_SGE_SHORT_TRANSACTION_ELEMENT   ShortTransaction;
+
+       /* Simple Addressing Element */
+       I2O_SGE_SIMPLE_ELEMENT              Simple[1];
+
+       /* Simple Addressing with Context Element */
+       I2O_SGE_SIMPLE_CONTEXT_ELEMENT      SimpleContext[1];
+
+       /* Transport Detail Element */
+       I2O_SGE_TRANSPORT_ELEMENT           Transport;
+   }u;
+} I2O_SG_ELEMENT, *PI2O_SG_ELEMENT;
+
+/* I2O BSA Block Read Message Frame */
+typedef struct _I2O_BSA_READ_MESSAGE {
+    I2O_MESSAGE_FRAME       StdMessageFrame;
+    I2O_TRANSACTION_CONTEXT TransactionContext;
+    I2O_BSA_READ_FLAGS      ControlFlags;
+    U8                      TimeMultiplier;
+    U8                      FetchAhead;
+    U32                     TransferByteCount;
+    U64                     LogicalByteAddress;
+    I2O_SG_ELEMENT          SGL;
+} I2O_BSA_READ_MESSAGE, *PI2O_BSA_READ_MESSAGE;
+
+
+/***********************************************************************/
+
+/* Class ID Block */
+
+typedef struct _I2O_CLASS_ID {
+   BF                          Class:I2O_CLASS_ID_SZ;
+   BF                          Version:I2O_4BIT_VERSION_SZ;
+   BF                          OrganizationID:I2O_CLASS_ORGANIZATION_ID_SZ;
+} I2O_CLASS_ID, *PI2O_CLASS_ID;
+
+
+/****************************************************************************/
+/* Logical Configuration Table  */
+/****************************************************************************/
+
+/* I2O Logical Configuration Table structures. */
+
+#define    I2O_IDENTITY_TAG_SZ                         8
+
+/* I2O Logical Configuration Table Device Flags */
+
+#define    I2O_LCT_DEVICE_FLAGS_CONF_DIALOG_REQUEST            0x01
+#define    I2O_LCT_DEVICE_FLAGS_MORE_THAN_1_USER               0x02
+#define    I2O_LCT_DEVICE_FLAGS_PEER_SERVICE_DISABLED          0x10
+#define    I2O_LCT_DEVICE_FLAGS_MANAGEMENT_SERVICE_DISABLED    0x20
+
+/* LCT Entry Block */
+
+typedef struct _I2O_LCT_ENTRY {
+   BF                          TableEntrySize:I2O_COMMON_LENGTH_FIELD_SZ;
+   BF                          LocalTID:I2O_TID_SZ;
+   BF                          reserved:I2O_4BIT_VERSION_SZ;
+   U32                         ChangeIndicator;
+   U32                         DeviceFlags;
+   I2O_CLASS_ID                ClassID;
+   U32                         SubClassInfo;
+   BF                          UserTID:I2O_TID_SZ;
+   BF                          ParentTID:I2O_TID_SZ;
+   BF                          BiosInfo:I2O_BIOS_INFO_SZ;
+   U8                          IdentityTag[I2O_IDENTITY_TAG_SZ];
+   U32                         EventCapabilities;
+} I2O_LCT_ENTRY, *PI2O_LCT_ENTRY;
+
+/* I2O Logical Configuration Table structure. */
+typedef struct _I2O_LCT {
+   BF                          TableSize:I2O_COMMON_LENGTH_FIELD_SZ;
+   BF                          BootDeviceTID:I2O_TID_SZ;
+   BF                          LctVer:I2O_4BIT_VERSION_SZ;
+   U32                         IopFlags;
+   U32                         CurrentChangeIndicator;
+   I2O_LCT_ENTRY               LCTEntry[1];
+} I2O_LCT, *PI2O_LCT;
+
+
+/****************************************************************************/
+
+/*  I2O Executive Function Codes.  */
+
+#define    I2O_EXEC_ADAPTER_ASSIGN                     0xB3
+#define    I2O_EXEC_ADAPTER_READ                       0xB2
+#define    I2O_EXEC_ADAPTER_RELEASE                    0xB5
+#define    I2O_EXEC_BIOS_INFO_SET                      0xA5
+#define    I2O_EXEC_BOOT_DEVICE_SET                    0xA7
+#define    I2O_EXEC_CONFIG_VALIDATE                    0xBB
+#define    I2O_EXEC_CONN_SETUP                         0xCA
+#define    I2O_EXEC_DDM_DESTROY                        0xB1
+#define    I2O_EXEC_DDM_ENABLE                         0xD5
+#define    I2O_EXEC_DDM_QUIESCE                        0xC7
+#define    I2O_EXEC_DDM_RESET                          0xD9
+#define    I2O_EXEC_DDM_SUSPEND                        0xAF
+#define    I2O_EXEC_DEVICE_ASSIGN                      0xB7
+#define    I2O_EXEC_DEVICE_RELEASE                     0xB9
+#define    I2O_EXEC_HRT_GET                            0xA8
+#define    I2O_EXEC_IOP_CLEAR                          0xBE
+#define    I2O_EXEC_IOP_CONNECT                        0xC9
+#define    I2O_EXEC_IOP_RESET                          0xBD
+#define    I2O_EXEC_LCT_NOTIFY                         0xA2
+#define    I2O_EXEC_OUTBOUND_INIT                      0xA1
+#define    I2O_EXEC_PATH_ENABLE                        0xD3
+#define    I2O_EXEC_PATH_QUIESCE                       0xC5
+#define    I2O_EXEC_PATH_RESET                         0xD7
+#define    I2O_EXEC_STATIC_MF_CREATE                   0xDD
+#define    I2O_EXEC_STATIC_MF_RELEASE                  0xDF
+#define    I2O_EXEC_STATUS_GET                         0xA0
+#define    I2O_EXEC_SW_DOWNLOAD                        0xA9
+#define    I2O_EXEC_SW_UPLOAD                          0xAB
+#define    I2O_EXEC_SW_REMOVE                          0xAD
+#define    I2O_EXEC_SYS_ENABLE                         0xD1
+#define    I2O_EXEC_SYS_MODIFY                         0xC1
+#define    I2O_EXEC_SYS_QUIESCE                        0xC3
+#define    I2O_EXEC_SYS_TAB_SET                        0xA3
+
+
+/* I2O Get Status State values */
+
+#define    I2O_IOP_STATE_INITIALIZING                  0x01
+#define    I2O_IOP_STATE_RESET                         0x02
+#define    I2O_IOP_STATE_HOLD                          0x04
+#define    I2O_IOP_STATE_READY                         0x05
+#define    I2O_IOP_STATE_OPERATIONAL                   0x08
+#define    I2O_IOP_STATE_FAILED                        0x10
+#define    I2O_IOP_STATE_FAULTED                       0x11
+
+
+#define    I2O_EXEC_STATUS_GET_RESERVED_SZ             16
+
+/* ExecStatusGet Function Message Frame structure. */
+
+typedef struct _I2O_EXEC_STATUS_GET_MESSAGE {
+   U8                          VersionOffset;
+   U8                          MsgFlags;
+   U16                         MessageSize;
+   BF                          TargetAddress:I2O_TID_SZ;
+   BF                          InitiatorAddress:I2O_TID_SZ;
+   BF                          Function:I2O_FUNCTION_SZ;
+   U8                          Reserved[I2O_EXEC_STATUS_GET_RESERVED_SZ];
+   U32                         ReplyBufferAddressLow;
+   U32                         ReplyBufferAddressHigh;
+   U32                         ReplyBufferLength;
+} I2O_EXEC_STATUS_GET_MESSAGE, *PI2O_EXEC_STATUS_GET_MESSAGE;
+
+
+#define    I2O_IOP_STATUS_PROD_ID_STR_SZ               24
+#define    I2O_EXEC_STATUS_GET_REPLY_RESERVED_SZ       6
+
+/* ExecStatusGet reply Structure */
+
+#define    I2O_IOP_CAP_CONTEXT_32_ONLY                 0x00000000
+#define    I2O_IOP_CAP_CONTEXT_64_ONLY                 0x00000001
+#define    I2O_IOP_CAP_CONTEXT_32_64_NOT_CURRENTLY     0x00000002
+#define    I2O_IOP_CAP_CONTEXT_32_64_CURRENTLY         0x00000003
+#define    I2O_IOP_CAP_CURRENT_CONTEXT_NOT_CONFIG      0x00000000
+#define    I2O_IOP_CAP_CURRENT_CONTEXT_32_ONLY         0x00000004
+#define    I2O_IOP_CAP_CURRENT_CONTEXT_64_ONLY         0x00000008
+#define    I2O_IOP_CAP_CURRENT_CONTEXT_32_64           0x0000000C
+#define    I2O_IOP_CAP_INBOUND_PEER_SUPPORT            0x00000010
+#define    I2O_IOP_CAP_OUTBOUND_PEER_SUPPORT           0x00000020
+#define    I2O_IOP_CAP_PEER_TO_PEER_SUPPORT            0x00000040
+
+typedef struct _I2O_EXEC_STATUS_GET_REPLY {
+   U16                         OrganizationID;
+   U16                         reserved;
+   BF                          IOP_ID:I2O_IOP_ID_SZ;
+   BF                          reserved1:I2O_RESERVED_4BITS;
+   BF                          HostUnitID:I2O_UNIT_ID_SZ;
+   BF                          SegmentNumber:I2O_SEGMENT_NUMBER_SZ;
+   BF                          I2oVersion:I2O_4BIT_VERSION_SZ;
+   BF                          IopState:I2O_IOP_STATE_SZ;
+   BF                          MessengerType:I2O_MESSENGER_TYPE_SZ;
+   U16                         InboundMFrameSize;
+   U8                          InitCode;
+   U8                          reserved2;
+   U32                         MaxInboundMFrames;
+   U32                         CurrentInboundMFrames;
+   U32                         MaxOutboundMFrames;
+   U8                          ProductIDString[I2O_IOP_STATUS_PROD_ID_STR_SZ];
+   U32                         ExpectedLCTSize;
+   U32                         IopCapabilities;
+   U32                         DesiredPrivateMemSize;
+   U32                         CurrentPrivateMemSize;
+   U32                         CurrentPrivateMemBase;
+   U32                         DesiredPrivateIOSize;
+   U32                         CurrentPrivateIOSize;
+   U32                         CurrentPrivateIOBase;
+   U8                          reserved3[3];
+   U8                          SyncByte;
+} I2O_EXEC_STATUS_GET_REPLY, *PI2O_EXEC_STATUS_GET_REPLY;
+
+
+/***************************************************************************/
+
+/* ExecSysTabSet (System Table) Function Message Frame structure. */
+
+#define I2O_EXEC_SYS_TAB_IOP_ID_LOCAL_IOP           0x000
+#define I2O_EXEC_SYS_TAB_IOP_ID_LOCAL_HOST          0x001
+#define I2O_EXEC_SYS_TAB_IOP_ID_UNKNOWN_IOP         0xFFF
+#define I2O_EXEC_SYS_TAB_HOST_UNIT_ID_LOCAL_UNIT    0x0000
+#define I2O_EXEC_SYS_TAB_HOST_UNIT_ID_UNKNOWN_UNIT  0xffff
+#define I2O_EXEC_SYS_TAB_SEG_NUMBER_LOCAL_SEGMENT   0x000
+#define I2O_EXEC_SYS_TAB_SEG_NUMBER_UNKNOWN_SEGMENT 0xfff
+
+typedef struct _I2O_EXEC_SYS_TAB_SET_MESSAGE {
+   I2O_MESSAGE_FRAME           StdMessageFrame;
+   I2O_TRANSACTION_CONTEXT     TransactionContext;
+   BF                          IOP_ID:I2O_IOP_ID_SZ;
+   BF                          reserved:I2O_RESERVED_4BITS;
+   BF                          HostUnitID:I2O_UNIT_ID_SZ;
+   BF                          SegmentNumber:I2O_SEGMENT_NUMBER_SZ;
+   BF                          reserved2:I2O_RESERVED_20BITS;
+   I2O_SG_ELEMENT              SGL;
+} I2O_EXEC_SYS_TAB_SET_MESSAGE, *PI2O_EXEC_SYS_TAB_SET_MESSAGE;
+
+
+/****************************************************************************/
+
+/* Operation Function Numbers */
+
+#define   I2O_PARAMS_OPERATION_FIELD_GET               0x0001
+#define   I2O_PARAMS_OPERATION_LIST_GET                0x0002
+#define   I2O_PARAMS_OPERATION_MORE_GET                0x0003
+#define   I2O_PARAMS_OPERATION_SIZE_GET                0x0004
+#define   I2O_PARAMS_OPERATION_TABLE_GET               0x0005
+#define   I2O_PARAMS_OPERATION_FIELD_SET               0x0006
+#define   I2O_PARAMS_OPERATION_LIST_SET                0x0007
+#define   I2O_PARAMS_OPERATION_ROW_ADD                 0x0008
+#define   I2O_PARAMS_OPERATION_ROW_DELETE              0x0009
+#define   I2O_PARAMS_OPERATION_TABLE_CLEAR             0x000A
+
+/* Operations List Header */
+
+typedef struct _I2O_PARAM_OPERATIONS_LIST_HEADER {
+   U16                         OperationCount;
+   U16                         Reserved;
+} I2O_PARAM_OPERATIONS_LIST_HEADER, *PI2O_PARAM_OPERATIONS_LIST_HEADER;
+
+/* Results List Header */
+
+typedef struct _I2O_PARAM_RESULTS_LIST_HEADER {
+   U16                         ResultCount;
+   U16                         Reserved;
+} I2O_PARAM_RESULTS_LIST_HEADER, *PI2O_PARAM_RESULTS_LIST_HEADER;
+
+/* Read Operation Result Block Template Structure */
+
+typedef struct _I2O_PARAM_READ_OPERATION_RESULT {
+   U16                         BlockSize;
+   U8                          BlockStatus;
+   U8                          ErrorInfoSize;
+   /*                          Operations Results          */
+   /*                          Pad (if any)                */
+   /*                          ErrorInformation (if any)   */
+} I2O_PARAM_READ_OPERATION_RESULT, *PI2O_PARAM_READ_OPERATION_RESULT;
+
+/* Operation Template for Specific Fields */
+
+typedef struct _I2O_PARAM_OPERATION_SPECIFIC_TEMPLATE {
+   U16                         Operation;
+   U16                         GroupNumber;
+   U16                         FieldCount;
+   U16                         FieldIdx[1];
+   /*                          Pad (if any)                    */
+} I2O_PARAM_OPERATION_SPECIFIC_TEMPLATE, *PI2O_PARAM_OPERATION_SPECIFIC_TEMPLATE;
+
+/* Operation Template for All Fields */
+
+typedef struct _I2O_PARAM_OPERATION_ALL_TEMPLATE {
+   U16                         Operation;
+   U16                         GroupNumber;
+   U16                         FieldCount;
+   /*                          Pad (if any)                    */
+} I2O_PARAM_OPERATION_ALL_TEMPLATE, *PI2O_PARAM_OPERATION_ALL_TEMPLATE;
+
+/****************************************************************************/
+
+/* Utility Message class functions. */
+
+#define    I2O_UTIL_NOP                                0x00
+#define    I2O_UTIL_ABORT                              0x01
+#define    I2O_UTIL_CLAIM                              0x09
+#define    I2O_UTIL_CLAIM_RELEASE                      0x0B
+#define    I2O_UTIL_CONFIG_DIALOG                      0x10
+#define    I2O_UTIL_DEVICE_RESERVE                     0x0D
+#define    I2O_UTIL_DEVICE_RELEASE                     0x0F
+#define    I2O_UTIL_EVENT_ACKNOWLEDGE                  0x14
+#define    I2O_UTIL_EVENT_REGISTER                     0x13
+#define    I2O_UTIL_LOCK                               0x17
+#define    I2O_UTIL_LOCK_RELEASE                       0x19
+#define    I2O_UTIL_PARAMS_GET                         0x06
+#define    I2O_UTIL_PARAMS_SET                         0x05
+#define    I2O_UTIL_REPLY_FAULT_NOTIFY                 0x15
+
+/****************************************************************************/
+
+/* UtilNOP Function Message Frame structure. */
+
+typedef struct _I2O_UTIL_NOP_MESSAGE {
+    I2O_MESSAGE_FRAME          StdMessageFrame;
+} I2O_UTIL_NOP_MESSAGE, *PI2O_UTIL_NOP_MESSAGE;
+
+
+/*************************************************************************/
+
+/* UtilParamsGet Message Frame structure. */
+
+typedef struct _I2O_UTIL_PARAMS_GET_MESSAGE {
+    I2O_MESSAGE_FRAME          StdMessageFrame;
+    I2O_TRANSACTION_CONTEXT    TransactionContext;
+    U32                        OperationFlags;
+    I2O_SG_ELEMENT             SGL;
+} I2O_UTIL_PARAMS_GET_MESSAGE, *PI2O_UTIL_PARAMS_GET_MESSAGE;
+
+
+/****************************************************************************/
+/* GROUP Parameter Groups */
+/****************************************************************************/
+
+/* GROUP Configuration and Operating Structures and Defines */
+
+/* Groups Numbers */
+
+#define    I2O_UTIL_PARAMS_DESCRIPTOR_GROUP_NO          0xF000
+#define    I2O_UTIL_PHYSICAL_DEVICE_TABLE_GROUP_NO      0xF001
+#define    I2O_UTIL_CLAIMED_TABLE_GROUP_NO              0xF002
+#define    I2O_UTIL_USER_TABLE_GROUP_NO                 0xF003
+#define    I2O_UTIL_PRIVATE_MESSAGE_EXTENSIONS_GROUP_NO 0xF005
+#define    I2O_UTIL_AUTHORIZED_USER_TABLE_GROUP_NO      0xF006
+#define    I2O_UTIL_DEVICE_IDENTITY_GROUP_NO            0xF100
+#define    I2O_UTIL_DDM_IDENTITY_GROUP_NO               0xF101
+#define    I2O_UTIL_USER_INFORMATION_GROUP_NO           0xF102
+#define    I2O_UTIL_SGL_OPERATING_LIMITS_GROUP_NO       0xF103
+#define    I2O_UTIL_SENSORS_GROUP_NO                    0xF200
+
+/* UTIL Group F000h - GROUP DESCRIPTORS Parameter Group */
+
+#define    I2O_UTIL_GROUP_PROPERTIES_GROUP_TABLE       0x01
+#define    I2O_UTIL_GROUP_PROPERTIES_ROW_ADDITION      0x02
+#define    I2O_UTIL_GROUP_PROPERTIES_ROW_DELETION      0x04
+#define    I2O_UTIL_GROUP_PROPERTIES_CLEAR_OPERATION   0x08
+
+/* UTIL Group F100h - Device Identity Parameter Group */
+
+typedef struct _I2O_UTIL_DEVICE_IDENTITY_SCALAR {
+   U32                         ClassID;
+   U16                         OwnerTID;
+   U16                         ParentTID;
+   U8                          VendorInfo[I2O_DEVID_VENDOR_INFO_SZ];
+   U8                          ProductInfo[I2O_DEVID_PRODUCT_INFO_SZ];
+   U8                          Description[I2O_DEVID_DESCRIPTION_SZ];
+   U8                          ProductRevLevel[I2O_DEVID_REV_LEVEL_SZ];
+   U8                          SNFormat;
+   U8                          SerialNumber[I2O_MAX_SERIAL_NUMBER_SZ];
+} I2O_UTIL_DEVICE_IDENTITY_SCALAR, *PI2O_UTIL_DEVICE_IDENTITY_SCALAR;
+
+/* UTIL Group F101h - DDM Identity Parameter Group */
+
+typedef struct _I2O_UTIL_DDM_IDENTITY_SCALAR {
+   U16                         DdmTID;
+   U8                          ModuleName[I2O_MODULE_NAME_SZ];
+   U8                          ModuleRevLevel[I2O_DEVID_REV_LEVEL_SZ];
+   U8                          SNFormat;
+   U8                          SerialNumber[I2O_MAX_SERIAL_NUMBER_SZ];
+} I2O_UTIL_DDM_IDENTITY_SCALAR, *PI2O_UTIL_DDM_IDENTITY_SCALAR;
+
+/****************************************************************************/
+
+/* Block Storage Parameter Groups */
+
+#define     I2O_BSA_DEVICE_INFO_GROUP_NO                0x0000
+#define     I2O_BSA_OPERATIONAL_CONTROL_GROUP_NO        0x0001
+#define     I2O_BSA_POWER_CONTROL_GROUP_NO              0x0002
+#define     I2O_BSA_CACHE_CONTROL_GROUP_NO              0x0003
+#define     I2O_BSA_MEDIA_INFO_GROUP_NO                 0x0004
+#define     I2O_BSA_ERROR_LOG_GROUP_NO                  0x0005
+
+/***************************************************************************/
+
+/* I2O Block Storage Reply Message Frame Template */
+
+typedef struct _I2O_BSA_REPLY_MESSAGE_FRAME {
+    I2O_MESSAGE_FRAME           StdMessageFrame;
+    I2O_TRANSACTION_CONTEXT     TransactionContext;
+    U16                         DetailedStatusCode;
+    U8                          RetryCount;
+    U8                          ReqStatus;
+/*                              ReplyPayload        */
+} I2O_BSA_REPLY_MESSAGE_FRAME, *PI2O_BSA_REPLY_MESSAGE_FRAME;
+
+/**************************************************************************/
+
+/* Block Storage Group 0000h - Device Information Parameter Group */
+
+typedef struct _I2O_BSA_DEVICE_INFO_SCALAR {
+    U8          DeviceType;
+    U8          NumberOfPaths;
+    U16         PowerState;     
+    U32         BlockSize;
+    U64         DeviceCapacity;
+    U32         DeviceCapabilitySupport;
+    U32         DeviceState;
+} I2O_BSA_DEVICE_INFO_SCALAR, *PI2O_BSA_DEVICE_INFO_SCALAR;
+
+
+/****************************************************************************/
+
+
+/* ExecOutboundInit Function Message Frame structure. */
+
+typedef struct _I2O_EXEC_OUTBOUND_INIT_MESSAGE {
+   I2O_MESSAGE_FRAME           StdMessageFrame;
+   I2O_TRANSACTION_CONTEXT     TransactionContext;
+   U32                         HostPageFrameSize;
+   U8                          InitCode;
+   U8                          reserved;
+   U16                         OutboundMFrameSize;
+   I2O_SG_ELEMENT              SGL;
+} I2O_EXEC_OUTBOUND_INIT_MESSAGE, *PI2O_EXEC_OUTBOUND_INIT_MESSAGE;
+
+
+#define    I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS          0x01
+#define    I2O_EXEC_OUTBOUND_INIT_REJECTED             0x02
+#define    I2O_EXEC_OUTBOUND_INIT_FAILED               0x03
+#define    I2O_EXEC_OUTBOUND_INIT_COMPLETE             0x04
+
+#define    I2O_EXEC_OUTBOUND_INIT_RESERVED_SZ          3
+
+
+typedef struct _I2O_EXEC_OUTBOUND_INIT_STATUS {
+   U8                          InitStatus;
+   U8                          reserved[I2O_EXEC_OUTBOUND_INIT_RESERVED_SZ];
+} I2O_EXEC_OUTBOUND_INIT_STATUS, *PI2O_EXEC_OUTBOUND_INIT_STATUS;
+
+
+typedef struct _I2O_EXEC_OUTBOUND_INIT_RECLAIM_LIST {
+   U32                         MFACount;
+   U32                         MFAReleaseCount;
+   U32                         MFAAddress[1];
+} I2O_EXEC_OUTBOUND_INIT_RECLAIM_LIST, *PI2O_EXEC_OUTBOUND_INIT_RECLAIM_LIST;
+
+/****************************************************************************/
+
+
+/* ExecSysEnable Function Message Frame structure. */
+
+typedef struct _I2O_EXEC_SYS_ENABLE_MESSAGE {
+   I2O_MESSAGE_FRAME           StdMessageFrame;
+   I2O_TRANSACTION_CONTEXT     TransactionContext;
+} I2O_EXEC_SYS_ENABLE_MESSAGE, *PI2O_EXEC_SYS_ENABLE_MESSAGE;
+
+
+/****************************************************************************/
+
+/* ExecLCTNotify Function Message Frame structure. */
+
+typedef struct _I2O_EXEC_LCT_NOTIFY_MESSAGE {
+   I2O_MESSAGE_FRAME           StdMessageFrame;
+   I2O_TRANSACTION_CONTEXT     TransactionContext;
+   U32                         ClassIdentifier;
+   U32                         LastReportedChangeIndicator;
+   I2O_SG_ELEMENT              SGL;
+} I2O_EXEC_LCT_NOTIFY_MESSAGE, *PI2O_EXEC_LCT_NOTIFY_MESSAGE;
+
+/****************************************************************************/
+
+/* ExecSysTabSet (System Table) Header Reply structure. */
+
+#define    I2O_SET_SYSTAB_RESERVED_SZ                  8
+
+typedef struct _I2O_SET_SYSTAB_HEADER {
+   U8                          NumberEntries;
+   U8                          SysTabVersion;
+   U16                         reserved;
+   U32                         CurrentChangeIndicator;
+   U8                          reserved1[I2O_SET_SYSTAB_RESERVED_SZ];
+/*    I2O_SYSTAB_ENTRY    SysTabEntry[1]; */
+} I2O_SET_SYSTAB_HEADER, *PI2O_SET_SYSTAB_HEADER;
+
+
+#define    I2O_RESOURCE_MANAGER_VERSION        0
+
+typedef struct _MESSENGER_INFO {
+   U32                         InboundMessagePortAddressLow;
+   U32                         InboundMessagePortAddressHigh;
+   } I2O_MESSENGER_INFO, *PI2O_MESSENGER_INFO;
+
+/* ExecSysTabSet IOP Descriptor Entry structure. */
+
+typedef struct _I2O_IOP_ENTRY {
+   U16                         OrganizationID;
+   U16                         reserved;
+   BF                          IOP_ID:I2O_IOP_ID_SZ;
+   BF                          reserved1:I2O_RESERVED_20BITS;
+   BF                          SegmentNumber:I2O_SEGMENT_NUMBER_SZ;
+   BF                          I2oVersion:I2O_4BIT_VERSION_SZ;
+   BF                          IopState:I2O_IOP_STATE_SZ;
+   BF                          MessengerType:I2O_MESSENGER_TYPE_SZ;
+   U16                         InboundMessageFrameSize;
+   U16                         reserved2;
+   U32                         LastChanged;
+   U32                         IopCapabilities;
+   I2O_MESSENGER_INFO          MessengerInfo;              
+} I2O_IOP_ENTRY, *PI2O_IOP_ENTRY;
+
+
+/****************************************************************************/
+
+
+#define    I2O_EXEC_IOP_RESET_RESERVED_SZ              16
+
+#define    I2O_EXEC_IOP_RESET_IN_PROGRESS              0x01
+#define    I2O_EXEC_IOP_RESET_REJECTED                 0x02
+
+#define    I2O_EXEC_IOP_RESET_STATUS_RESERVED_SZ       3
+
+typedef struct _I2O_EXEC_IOP_RESET_STATUS {
+   U8                          ResetStatus;
+   U8                          reserved[I2O_EXEC_IOP_RESET_STATUS_RESERVED_SZ];
+} I2O_EXEC_IOP_RESET_STATUS, *PI2O_EXEC_IOP_RESET_STATUS;
+
+
+/* ExecIopReset Function Message Frame structure. */
+
+typedef struct _I2O_EXEC_IOP_RESET_MESSAGE {
+   U8                          VersionOffset;
+   U8                          MsgFlags;
+   U16                         MessageSize;
+   BF                          TargetAddress:I2O_TID_SZ;
+   BF                          InitiatorAddress:I2O_TID_SZ;
+   BF                          Function:I2O_FUNCTION_SZ;
+   U8                          Reserved[I2O_EXEC_IOP_RESET_RESERVED_SZ];
+   U32                         StatusWordLowAddress;
+   U32                         StatusWordHighAddress;
+} I2O_EXEC_IOP_RESET_MESSAGE, *PI2O_EXEC_IOP_RESET_MESSAGE;
+
+
+/****************************************************************************/
+/* EXEC Group 0001h - IOP Message Interface Parameter Group */
+
+/* InitCode defines */
+#define    I2O_MESSAGE_IF_INIT_CODE_NO_OWNER           0x00
+#define    I2O_MESSAGE_IF_INIT_CODE_BIOS               0x10
+#define    I2O_MESSAGE_IF_INIT_CODE_OEM_BIOS_EXTENSION 0x20
+#define    I2O_MESSAGE_IF_INIT_CODE_ROM_BIOS_EXTENSION 0x30
+#define    I2O_MESSAGE_IF_INIT_CODE_OS                 0x80
+
+/****************************************************************************/
+
+#endif	/* _I2ODEF_H_ */
diff -ruN linux-2.4.20-orig/drivers/scsi/pti_st.c linux-2.4.20/drivers/scsi/pti_st.c
--- linux-2.4.20-orig/drivers/scsi/pti_st.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.4.20/drivers/scsi/pti_st.c	2003-01-21 19:22:00.000000000 -0500
@@ -0,0 +1,3527 @@
+/*+M*************************************************************************
+ * Promise SuperTrak device driver for Linux.
+ *
+ * Copyright (c) 2001  Promise Technology, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * --------------------------------------------------------------------------  
+ * Copyright (c) 1999-2001 Promise Technology, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *    $Id: pti_st.c,v 1.1 2001/06/27 15:37:18 Jack Hu Email: jackhu@sohu.com$
+ *-M*************************************************************************/
+
+#include <linux/string.h>
+#include <linux/errno.h>
+
+//#ifdef MODULE
+#include <linux/module.h>
+//#endif
+
+#if defined(MODULE)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)
+#include <linux/init.h>
+#endif
+#endif
+
+#include <stdarg.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/proc_fs.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+#include <linux/fs.h>
+#endif
+#include <linux/blk.h>
+#include <linux/blkdev.h>
+#include <linux/tqueue.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+#include <linux/tasks.h>
+#endif
+#include <linux/stat.h>
+// #include <linux/malloc.h>        /* for kmalloc() */
+#include <linux/slab.h>        /* for kmalloc() */
+#include <linux/config.h>        /* for CONFIG_PCI */
+#include <asm/segment.h>
+
+#ifdef mb
+#  undef mb
+#endif
+#define mb() \
+   __asm__ __volatile__("lock ; addl $0,0(%%esp)": : :"memory")
+     
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,16)
+#  include <asm/spinlock.h>
+#else
+#  include <linux/spinlock.h>
+#endif
+#  include <linux/smp.h>
+#  define cpuid smp_processor_id()
+
+#if defined(__SMP__)
+#  if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+#    define DRIVER_LOCK_INIT \
+       spin_lock_init(&p->spin_lock);
+#    define DRIVER_LOCK \
+       if(!p->cpu_lock_count[cpuid]) { \
+         spin_lock_irqsave(&p->spin_lock, cpu_flags); \
+         p->cpu_lock_count[cpuid]++; \
+       } else { \
+         p->cpu_lock_count[cpuid]++; \
+       }
+#    define DRIVER_UNLOCK \
+       if(--p->cpu_lock_count[cpuid] == 0) \
+         spin_unlock_irqrestore(&p->spin_lock, cpu_flags);
+#  else
+#    define DRIVER_LOCK_INIT	spin_lock_init(&p->spin_lock);
+#    define DRIVER_LOCK		spin_lock(&p->spin_lock);
+#    define DRIVER_UNLOCK	spin_unlock(&p->spin_lock);
+#  endif
+#else	/* __SMP__ */
+#define DRIVER_LOCK_INIT
+#define DRIVER_LOCK	
+#define DRIVER_UNLOCK
+#endif /* __SMP__ */
+     
+#include <asm/uaccess.h>
+
+#include <sd.h>
+#include <scsi.h>
+#include <hosts.h>
+
+#include "pti_st.h"
+#include "pti_stdev.h"
+
+#define PTI_ST_VERBOSE_DEBUGGING
+
+// Deprecated - created device ids in include/linux/pci_ids.h and included
+//  in our include list
+//#define PCI_DEVICE_ID_INTEL_i960 0x1960
+//#define PCI_DEVICE_ID_INTEL_i962 0x1962
+
+#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
+
+#ifdef MODULE 
+
+struct proc_dir_entry proc_root = 
+{
+  PROC_ROOT_INO,
+                             /* 
+                              * Inode number - ignore, it will be filled by 
+                              * proc_register[_dynamic] 
+                              */
+  4,            
+                             /* 
+                              * Length of the proc-file name 
+                              */ 
+  "proc",             
+                             /* 
+                              * The proc-file name 
+                              */
+  S_IFREG | S_IRUGO,     
+                             /* 
+                              * File mode - this is a regular 
+                              * file which can be read by its 
+                              * owner, its group, and everybody
+                              * else
+                              */
+  1,                         
+                             /* 
+                              * Number of links (directories where the 
+                              * file is referenced)
+                              */
+  0, 0,                      
+                             /* 
+                              * The uid and gid for the file - we give it 
+                              * to root 
+                              */
+  0,                        
+                             /* 
+                              * The size of the file reported by ls. 
+                              */
+  NULL,                      
+                             /*
+                              * functions which can be done on the inode 
+                              * (linking, removing, etc.) - we don't 
+                              * support any. 
+                              */
+  NULL, //    procfile_read,
+                             /*
+                              * The read function for this file, 
+                              * the function called when somebody 
+                              * tries to read something from it. 
+                              */
+  NULL  
+                             /*
+                              * We could have here a function to fill the 
+                              * file's inode, to enable us to play with 
+                              * permissions, ownership, etc. 
+                              */
+}; 
+
+#endif
+
+struct proc_dir_entry proc_scsi_pti_st = 
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+  PROC_SCSI_NOT_PRESENT,
+#else
+  0,
+                             /* 
+                              * Inode number - ignore, it will be filled by 
+                              * proc_register[_dynamic] 
+                              */
+#endif
+  6,           
+                             /* 
+                              * Length of the proc-file name 
+                              */ 
+  "pti_st",             
+                             /* 
+                              * The proc-file name 
+                              */
+  S_IFDIR | S_IRUGO | S_IXUGO,     
+                             /* 
+                              * File mode - this is a regular 
+                              * file which can be read by its 
+                              * owner, its group, and everybody
+                              * else
+                              */
+  2,                         
+                             /* 
+                              * Number of links (directories where the 
+                              * file is referenced)
+                              */
+  0, 0,                  
+                             /* 
+                              * The uid and gid for the file - we give it 
+                              * to root 
+                              */
+  0,                        
+                             /* 
+                              * The size of the file reported by ls. 
+                              */
+  NULL,                      
+                             /*
+                              * functions which can be done on the inode 
+                              * (linking, removing, etc.) - we don't 
+                              * support any. 
+                              */
+  NULL,
+                             /*
+                              * The read function for this file, 
+                              * the function called when somebody 
+                              * tries to read something from it. 
+                              */
+  NULL
+                             /*
+                              * We could have here a function to fill the 
+                              * file's inode, to enable us to play with 
+                              * permissions, ownership, etc. 
+                              */
+}; 
+
+#define ALL_TARGETS  -1
+#define ALL_CHANNELS -1
+#define ALL_LUNS     -1
+
+#define MAX_ARRAYS    8
+
+#define MAX_LUNS      MAX_ARRAYS
+
+#define PTI_ST_CMDS_PER_LUN 24
+
+/*
+ * The position of the SCSI commands scb within the scb array.
+ */
+#define pti_st_position(cmd)        ((cmd)->SCp.have_data_in)
+
+/* This variable is global and very important, control all module !!! */
+struct pti_st_host *pti_st_hostp[MAX_ADAPTORS] = {0};
+
+#define CTL_OF_CMD(cmd) ((cmd->channel) & 0x01), \
+                        ((cmd->target) & 0x0f), \
+                        ((cmd->lun) & 0x07)
+
+/*
+ * A nice little define to make doing our printks a little easier
+ */
+
+#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) "
+#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) "
+
+#if 0
+#ifdef MODULE
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,18)
+MODULE_PARM(pti_st, "s");
+#endif
+#endif
+#endif
+
+
+static int pti_st_install(Scsi_Host_Template  *, struct pci_dev *, int *);
+static void PTI_PrivateMessageCall(struct pti_st_host *, ULONG, U16, U16, ULONG, UCHAR *, ULONG, UCHAR *, UCHAR, ULONG);
+
+/*
+ * Declaration for EXECUTIVE Class Message 
+ */
+static unsigned int GetStatusCall(struct pti_st_host *, void *);
+static void OutboundInitCall(struct pti_st_host *);
+static void SysTabSetCall(struct pti_st_host *, PI2O_EXEC_SYS_TAB_SET_MESSAGE, void *);
+static int IOP_init(struct pti_st_host *);
+static void EnableSysCall(struct pti_st_host *);
+static void LCTNotifyCall(struct pti_st_host *);
+
+static unsigned long CreatSysTable(struct pti_st_host *, void *, PI2O_EXEC_STATUS_GET_REPLY);
+static void ExecIOPReset(struct pti_st_host *);
+static void PTI_UtilParamsGet(struct pti_st_host *, ULONG, ULONG, UCHAR, ULONG, UCHAR *);
+
+/*
+ * Declare Utility Message Functions:
+ */
+static unsigned long pti_st_waitreplymsg(struct pti_st_host *);
+static void PTI_UtilParamGetCall(struct pti_st_host *,
+			PI2O_UTIL_PARAMS_GET_MESSAGE,
+			void *, void *, PI2ODISK);
+static void UtilNOPCall(struct pti_st_host *);
+
+static int  ComposeDiskInfo(struct pti_st_host *, void *, void *, PI2ODISK);
+static void GetInfoFromLCT(struct pti_st_host *, void *, PI2ODISK, unsigned int *);
+static void ZeroMemory(unsigned long *, unsigned int);
+ 
+#define ADDTOPROCBUFFER(d, s) { if((strlen(d)+strlen(s)) < 4095) strcat(d, s); else goto proc_out; }
+
+/*
+ * PTI_procfile_read:
+ * inout : decides on the direction of the dataflow and the meaning of the
+ *         variables
+ * buffer: If inout==FALSE data is being written to it else read from it
+ * *start: If inout==FALSE start of the valid data in the buffer
+ * offset: If inout==FALSE offset from the beginning of the imaginary file
+ *         from which we start writing into the buffer
+ * length: If inout==FALSE max number of bytes to be written into the buffer
+ *         else number of bytes in the buffer
+ */
+int PTI_procfile_read(char *buffer, 
+                  char **buffer_location, 
+                  off_t offset, 
+                  int buffer_length, 
+                  int hostno,
+		  int inout)
+{
+  /* 
+   * The number of bytes actually used 
+   */
+  int len;        
+
+  /* 
+   * This is static so it will still be in memory 
+   * when we leave this function 
+   */
+  static char my_buffer[4096] = {0};  
+  char tmp_buffer[256] = {0};
+  char *ptr = my_buffer;
+  int i, j;
+
+  /* 
+   * We give all of our information in one go, so if the 
+   * user asks us if we have more information the 
+   * answer should always be no. 
+   *
+   * This is important because the standard read 
+   * function from the library would continue to issue 
+   * the read system call until the kernel replies
+   * that it has no more information, or until its 
+   * buffer is filled.
+   */
+  if (offset > 0)
+    return 0;
+
+  /* 
+   * Fill the buffer and get its length 
+   */
+  sprintf(ptr,"***** SuperTrak SX6000 Driver Version %2d.%2d *****\n", VERSIONHI, VERSIONLO);
+  ptr += strlen(ptr);
+  sprintf(ptr,"***** Copyright 1999-2001 by Promise Technology, Inc.   *****\n\n");
+  ptr += strlen(ptr);
+
+  for(i = 0; i < MAX_ADAPTORS && (len = strlen(my_buffer)) < 4095; i++) {
+	if(!pti_st_hostp[i])
+		continue;
+	sprintf(tmp_buffer, "\n\tIOP Number: %d\n", i);
+	ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+	sprintf(tmp_buffer, "\tCapabilities: %d",
+			 pti_st_hostp[i]->IopStatus.IopCapabilities);
+	ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+	sprintf(tmp_buffer, "\t\tState: %d\n",
+			pti_st_hostp[i]->IopStatus.IopState);
+	ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+	sprintf(tmp_buffer, "\tI2OVersion: %d",
+			pti_st_hostp[i]->IopStatus.I2oVersion);
+	ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+	sprintf(tmp_buffer, "\t\t\tMessengerType: 0x%x\n", 
+			pti_st_hostp[i]->IopStatus.MessengerType);
+	ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+	sprintf(tmp_buffer, "\tMaxMessageFrameSize: 0x%x",
+			pti_st_hostp[i]->IopStatus.InboundMFrameSize);
+	ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+	sprintf(tmp_buffer, "\tExpectedLCTSize: 0x%x\n",
+			pti_st_hostp[i]->IopStatus.ExpectedLCTSize);
+	ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+	sprintf(tmp_buffer, "\tMaxInboundMFrames: 0x%x",
+			pti_st_hostp[i]->IopStatus.MaxInboundMFrames);
+	ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+	sprintf(tmp_buffer, "\tInitialInboundMFrames: 0x%x\n",
+			pti_st_hostp[i]->IopStatus.CurrentInboundMFrames);
+	ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+	sprintf(tmp_buffer, "\n\tLCT Entry:\n");
+	ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+
+	j = 0;
+	while(pti_st_hostp[i]->LctEntryTable[j].TableEntrySize == 0x09)
+        {
+		sprintf(tmp_buffer, "\n\tClass: 0x%x",
+				pti_st_hostp[i]->LctEntryTable[j].ClassID.Class);
+		ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+		sprintf(tmp_buffer, "\t\tVersion: %d\n",
+				pti_st_hostp[i]->LctEntryTable[j].ClassID.Version);
+		ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+		sprintf(tmp_buffer, "\tOrganizationID: 0x%x",
+				pti_st_hostp[i]->LctEntryTable[j].ClassID.Version);
+		ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+		sprintf(tmp_buffer, "\tLocalTID: 0x%x\n",
+				pti_st_hostp[i]->LctEntryTable[j].LocalTID);
+		ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+		sprintf(tmp_buffer, "\tChangeIndicator: 0x%x",
+				pti_st_hostp[i]->LctEntryTable[j].ChangeIndicator);
+		ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+		sprintf(tmp_buffer, "\tDeviceFlags: 0x%x\n",
+				pti_st_hostp[i]->LctEntryTable[j].DeviceFlags);
+		ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+		sprintf(tmp_buffer, "\tSubClassInfo: 0x%x",
+				pti_st_hostp[i]->LctEntryTable[j].SubClassInfo);
+		ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+		sprintf(tmp_buffer, "\tUserTID: 0x%x\n",
+				pti_st_hostp[i]->LctEntryTable[j].UserTID);
+		ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+		sprintf(tmp_buffer, "\tParentTID: 0x%x",
+				pti_st_hostp[i]->LctEntryTable[j].ParentTID);
+		ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+		sprintf(tmp_buffer, "\t\tBiosInfo: 0x%x\n",
+				pti_st_hostp[i]->LctEntryTable[j].BiosInfo);
+		ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+		sprintf(tmp_buffer, "\tEventCapabilities: 0x%x\n",
+				pti_st_hostp[i]->LctEntryTable[j].EventCapabilities);
+		ADDTOPROCBUFFER(my_buffer, tmp_buffer);
+		j++;
+	}
+  }
+
+proc_out:
+  /* 
+   * Tell the function which called us where the 
+   * buffer is 
+   */
+  len = strlen(my_buffer);
+  if(len < buffer_length)
+	buffer_length = len;
+  else if(len >= buffer_length) {
+	my_buffer[buffer_length-1] = 0;
+	len = buffer_length - 1;
+  }
+
+  *buffer_location =  my_buffer;
+
+  /* 
+   * Return the length 
+   */
+  return len;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   PTI_ST_info
+ *
+ * Description:
+ *   Return a string describing the driver.
+ *-F*************************************************************************/
+const char *PTI_ST_info(struct Scsi_Host *dooh)
+{
+  static char buffer[256];
+  char *bp;
+
+  bp = &buffer[0];
+  memset(bp, 0, sizeof(buffer));
+  strcpy(bp, "PROMISE SuperTrak SX6000 Driver");
+  return(bp);
+}
+
+
+/*++
+
+Routine Description:
+
+    This routine will write data specified by Buffer to PCIConfig Space 
+	at Offset
+
+Arguments:
+
+    
+Return Values:
+
+	Length of data which has been written
+    
+--*/
+
+static ULONG PTI_ST_SetBusDataByOffset(
+    ULONG BusNumber,
+    ULONG DeviceNumber,
+    ULONG FunctionNumber,
+    void  *Buffer,
+    ULONG Offset,
+    ULONG Length
+)
+{
+	ULONG cr;
+
+	cr = 0x80000000 | 
+		(BusNumber << 16) | 
+		(DeviceNumber<<11) |
+		(FunctionNumber<<8) |
+		(Offset & 0xFC);
+
+	outl(cr, 0xCf8);
+
+	if (Length == 4)
+		outl(*((ULONG *)Buffer), 0xcfc);
+	else if (Length == 2)
+	{
+		ULONG data;
+
+		data = (inl(0xCfC) & (Offset&0x3 ? 0xFFFF : 0xFFFF0000));
+		data |= (((ULONG)(*(USHORT *)Buffer)) << (Offset&0x3 ? 16 : 0));
+		outl(data, 0xcfc);
+	}
+	else
+		return(0);
+
+	return(Length);
+
+}
+
+
+/*
+ * Function:    scbq_init(volatile scb_queue_type *queue)
+ * Description: SCB queue initialization.
+ */   
+static void
+scbq_init(volatile scb_queue_type *queue)
+{
+  queue->head = NULL;
+  queue->tail = NULL;
+}
+
+/*
+ * Function:    scbq_insert_head(volatile scb_queue_type, struct pti_st_scb)
+ * Description: Add an SCB to the head of the list.
+ */
+static inline void
+scbq_insert_head(struct pti_st_host *p, volatile scb_queue_type *queue, struct pti_st_scb *scb)
+{
+  DRIVER_LOCK
+  scb->q_next = queue->head;
+  queue->head = scb;
+  if (queue->tail == NULL)       /* If list was empty, update tail. */
+    queue->tail = queue->head;
+  DRIVER_UNLOCK
+}
+
+/*
+ * Function:    scbq_remove_head(volatile scb_queue_type)
+ * Description: Remove an SCB from the head of the list.
+ */
+static inline struct pti_st_scb *
+scbq_remove_head(struct pti_st_host *p, volatile scb_queue_type *queue)
+{
+  struct pti_st_scb * scbp;
+
+  DRIVER_LOCK
+  scbp = queue->head;
+  if (queue->head != NULL)
+    queue->head = queue->head->q_next;
+  if (queue->head == NULL)       /* If list is now empty, update tail. */
+    queue->tail = NULL;
+  DRIVER_UNLOCK
+  return(scbp);
+}
+
+/*
+ * Function:    scbq_remove(volatile scb_queue_type, struct pti_st_scb)
+ * Description: Removes an SCB from the list.
+ */
+static inline void
+scbq_remove(struct pti_st_host *p, volatile scb_queue_type *queue, struct pti_st_scb *scb)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
+  if (queue->head == scb)
+  {
+    /* At beginning of queue, remove from head. */
+    scbq_remove_head(p, queue);
+  }
+  else
+  {
+    struct pti_st_scb *curscb = queue->head;
+
+    /*
+     * Search until the next scb is the one we're looking for, or
+     * we run out of queue.
+     */
+    while ((curscb != NULL) && (curscb->q_next != scb))
+    {
+      curscb = curscb->q_next;
+    }
+    if (curscb != NULL)
+    {
+      /* Found it. */
+      curscb->q_next = scb->q_next;
+      if (scb->q_next == NULL)
+      {
+        /* Update the tail when removing the tail. */
+        queue->tail = curscb;
+      }
+    }
+  }
+  DRIVER_UNLOCK
+}
+
+/*
+ * Function:    scbq_insert_tail(volatile scb_queue_type, struct pti_st_scb)
+ * Description: Add an SCB at the tail of the list.
+ */
+static inline void
+scbq_insert_tail(struct pti_st_host *p, volatile scb_queue_type *queue, struct pti_st_scb *scb)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags;
+#endif
+
+  DRIVER_LOCK
+  scb->q_next = NULL;
+  if (queue->tail != NULL)       /* Add the scb at the end of the list. */
+    queue->tail->q_next = scb;
+  queue->tail = scb;             /* Update the tail. */
+  if (queue->head == NULL)       /* If list was empty, update head. */
+    queue->head = queue->tail;
+  DRIVER_UNLOCK
+}
+
+/*
+ * Function:    pti_st_allocate_scb(struct pti_st_host *, struct pti_st_scb *)
+ * Description: Free the scb and insert into the free scb list.
+ */
+static int
+pti_st_allocate_scb(struct pti_st_host *p)
+{
+  struct pti_st_scb   *scbp = NULL;
+  int scb_size = sizeof(struct pti_st_scb);
+  int i;
+  unsigned long scb_count = 0;
+  struct pti_st_scb *scb_ap;
+
+  scb_count = p->scb_data->maxscbs;
+  scb_ap = (struct pti_st_scb *)kmalloc(scb_size * scb_count, GFP_ATOMIC);
+  if (scb_ap != NULL)
+  {
+    memset(scb_ap, 0, scb_count * scb_size);
+    for (i=0; i < scb_count; i++)
+    {
+      scbp = &scb_ap[i];
+      scbp->mf = NULL;
+      scbp->tag = i;
+
+      /*
+       * Place in the scb array; never is removed
+       */
+      p->scb_data->scb_array[i] = scbp;
+      scbq_insert_head(p, &p->scb_data->free_scbs, scbp);
+    }
+    scbp->kmalloc_ptr = scb_ap;
+  }
+  else
+  {
+    return(0);
+  }
+  return(scb_count);
+}
+
+/*
+ * Function:    pti_st_queue_cmd_complete(struct pti_st_host *, Scsi_Cmnd *)
+ * Description: Due to race conditions present in the SCSI subsystem, it is 
+ *              easier to queue completed commands, then call scsi_done() on
+ *              them when we're finished.  
+ *              This function queues the completed commands.
+ */
+static void
+pti_st_queue_cmd_complete(struct pti_st_host *p, Scsi_Cmnd *cmd)
+{
+  cmd->host_scribble = (char *)p->completeq.head;
+  p->completeq.head = cmd;
+}
+
+/*
+ * Function:    pti_st_done_cmds_complete(struct pti_st_host *)
+ * Description: Process the completed command queue.
+ */
+static void
+pti_st_done_cmds_complete(struct pti_st_host *p)
+{
+  Scsi_Cmnd *cmd;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned int cpu_flags = 0;
+  
+  DRIVER_LOCK
+  while (p->completeq.head != NULL)
+  {
+    cmd = p->completeq.head;
+    p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
+    cmd->host_scribble = NULL;
+    sti();
+    cmd->scsi_done(cmd);
+    cli();
+  }
+  DRIVER_UNLOCK
+
+#else
+
+  while (p->completeq.head != NULL)
+  {
+    cmd = p->completeq.head;
+    p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
+    cmd->host_scribble = NULL;
+    cmd->scsi_done(cmd);
+  }
+
+#endif	
+}
+
+/*
+ * Function:    pti_st_free_scb(struct pti_st_host *, struct pti_st_scb *)
+ * Description: Free the scb and insert into the free scb list.
+ */
+static void
+pti_st_free_scb(struct pti_st_host *p, struct pti_st_scb *scb)
+{
+
+  scb->flags = SCB_FREE;
+  scb->cmd = NULL;
+  scb->sg_count = 0;
+  scb->sg_length = 0;
+
+//  scb->mf->target_channel_lun = SCB_LIST_NULL;
+
+  scbq_insert_head(p, &p->scb_data->free_scbs, scb);
+}
+
+/*
+ * Function:    pti_st_done(struct pti_st_host *, struct pti_st_scb *)
+ * Description: Calls the higher level scsi done function and frees the scb.
+ */
+static void
+pti_st_done(struct pti_st_host *p, struct pti_st_scb *scb)
+{
+  Scsi_Cmnd *cmd = scb->cmd;
+
+  if (scb->flags & SCB_RESET)
+  {
+    cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
+  }
+  else if (scb->flags & SCB_ABORT)
+  {
+    cmd->result = (DID_RESET << 16) | (cmd->result & 0xffff);
+  }
+
+  pti_st_free_scb(p, scb);
+  pti_st_queue_cmd_complete(p, cmd);
+}
+
+/*
+ * Function:    pti_st_run_done_queue(struct pti_st_host *, int)
+ * Description: Calls the pti_st_done() for the Scsi_Cmnd of each scb in the
+ *              aborted list, and adds each scb to the free list.  If complete
+ *              is TRUE, we also process the commands complete list.
+ */
+static void
+pti_st_run_done_queue(struct pti_st_host *p, int complete)
+{
+  struct pti_st_scb *scb;
+  int i;
+
+  for (i = 0; i < p->scb_data->maxscbs; i++)
+  {
+    scb = p->scb_data->scb_array[i];
+    if (scb->flags & SCB_QUEUED_FOR_DONE)
+      pti_st_done(p, scb);
+  }
+  if (complete)
+  {
+    pti_st_done_cmds_complete(p);
+  }
+}
+
+/*
+ * Function:    pti_st_isr(int, void, struct pt_regs)
+ * Description: i960 controller interrupt handler.
+ */   
+static void
+pti_st_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+    volatile U32 phyAddrMsg = 0xffffffff;
+    U32 scb_index;
+    Scsi_Cmnd *cmd;
+    struct pti_st_host *p;
+    struct pti_st_scb *scbp;
+    PI2O_BSA_REPLY_MESSAGE_FRAME rmfp = NULL;
+    int testtime = 0;
+    int i;
+
+    p = (struct pti_st_host *)dev_id;
+    if(!p) 
+	return;
+
+    for(i = 0; i < MAX_ADAPTORS; i++)
+	if(pti_st_hostp[i] == p)
+		break;
+
+   if(i >= MAX_ADAPTORS || !p->p_atu)
+	return;
+
+    phyAddrMsg = p->p_atu->OutQueue;
+
+    while (TRUE)
+    {
+	for(testtime = 1;
+	    (phyAddrMsg == 0xffffffff) && (testtime < 3);
+	    testtime++)
+	{
+    		phyAddrMsg = p->p_atu->OutQueue;
+	}
+
+	if(phyAddrMsg == 0xffffffff) {
+		return;
+	}
+
+        rmfp = (PI2O_BSA_REPLY_MESSAGE_FRAME)(bus_to_virt(phyAddrMsg));
+
+        scb_index = rmfp->StdMessageFrame.InitiatorContext;
+        scbp = p->scb_data->scb_array[scb_index];
+        if (!scbp)
+        {
+          /* return MFA to outbound free Q*/
+          p->p_atu->OutQueue = phyAddrMsg;
+    
+          /* any more msgs? */
+          phyAddrMsg = p->p_atu->OutQueue;    
+          continue;
+        }
+        
+        cmd = scbp->cmd;
+
+        //printk("return cmd= 0x%x, mfp= 0x%x, sno= 0x%x tag= 0x%x ind= 0x%x scb= 0x%x\n",
+        //        cmd, rmfp, cmd->serial_number, scbp->tag, scb_index, scbp);
+        if (cmd->serial_number != rmfp->TransactionContext)
+        {
+          printk("Error in cmd%2x, mismatch sn 0x%x, mfp 0x%x scbi= %x\n",
+		cmd->cmnd[0], (int)cmd->serial_number,
+                (int)rmfp->TransactionContext,
+                (int)scb_index); 
+          /* return MFA to outbound free Q*/
+          p->p_atu->OutQueue = phyAddrMsg;
+    
+          /* any more msgs? */
+          phyAddrMsg = p->p_atu->OutQueue;
+          continue;
+        }
+
+        if (rmfp->ReqStatus != I2O_REPLY_STATUS_SUCCESS) {
+          cmd->result = DID_ERROR; 
+#if defined(DEBUG)
+	  printk("pti_st_isr: Reply Status Fail, ReqStatus[%x], DetailedStatus[%x]\n", rmfp->ReqStatus, rmfp->DetailedStatusCode);
+#endif
+	}
+        
+        pti_st_free_scb(p, scbp);
+        pti_st_queue_cmd_complete(p, cmd);
+        /* return MFA to outbound free Q*/
+        p->p_atu->OutQueue = phyAddrMsg;
+    
+        /* any more msgs? */
+        phyAddrMsg = p->p_atu->OutQueue;
+    }
+
+    return;
+}
+
+/*
+ * Function:    do_pti_st_isr(int, void *, struct pt_regs *)
+ * Description:
+ *   This is a gross hack to solve a problem in linux kernels 2.1.85 and
+ *   above.  Please, children, do not try this at home, and if you ever see
+ *   anything like it, please inform the Gross Hack Police immediately
+ */
+void do_pti_st_isr( int irq, void *dev_id, struct pt_regs * regs )
+{
+  unsigned long cpu_flags = 0;
+  struct pti_st_host *p;
+  U32 OutIntStat;
+  int i;
+    
+  p = (struct pti_st_host *)dev_id;
+  if(!p)
+    return;
+
+  for(i = 0; i < MAX_ADAPTORS; i++)
+	if(p == pti_st_hostp[i])
+		break;
+
+  if(i >= MAX_ADAPTORS)
+	return;
+
+  OutIntStat = p->p_atu->OutIntStat;
+
+  if (OutIntStat==0)
+    	return;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,95)
+  if(test_and_set_bit(PSTC_IN_ISR_BIT, &p->flags))
+  {
+    return;
+  }
+  spin_lock_irqsave(&io_request_lock, cpu_flags);
+  pti_st_isr(irq, dev_id, regs);
+  pti_st_done_cmds_complete(p);
+  clear_bit(PSTC_IN_ISR_BIT, &p->flags);
+  spin_unlock_irqrestore(&io_request_lock, cpu_flags);
+#else
+  if(set_bit(PSTC_IN_ISR_BIT, (int *)&p->flags))
+  {
+    return;
+  }
+  DRIVER_LOCK
+  pti_st_isr(irq, dev_id, regs);
+  DRIVER_UNLOCK
+  pti_st_done_cmds_complete(p);
+  clear_bit(PSTC_IN_ISR_BIT, (int *)&p->flags);    
+#endif
+}
+
+/*
+ * Function:    pti_st_register(Scsi_Host_Template *, struct pti_st_host *)
+ * Description: Register i960 controller with the kernel.
+ */
+static int
+pti_st_register(Scsi_Host_Template *template, struct pti_st_host *p)
+{
+  int result;
+  struct Scsi_Host *host;
+
+  host = p->host;
+
+  p->scb_data->maxscbs = PTI_ST_MAXSCB;
+  host->can_queue = PTI_ST_MAXSCB;
+  host->cmd_per_lun = 3;
+  host->sg_tablesize = PTI_ST_MAX_SG;
+  host->this_id = p->scsi_id;
+  host->irq = p->pci_irq;
+
+  p->host = host;
+  p->host_no = host->host_no;
+  p->completeq.head = NULL;
+  p->completeq.tail = NULL;
+
+  /* 
+   * Initialize the Super Track hardware controler, procedure as the 
+   * typical system initialization of I2O
+   */
+  p->maddr = ioremap(p->mbase, 4*1024*1024);
+  if(!(p->maddr))
+  {
+    p->pci_irq = 0; 
+    return (0);
+  }
+  
+  p->p_atu = (PATU)p->maddr;
+  p->LinBaseAddr = (PU8)p->maddr;
+  
+  p->outboundBufferp = (outboundBuff_t *)kmalloc((16*1024+256+32*32*4), GFP_ATOMIC);
+  if(p->outboundBufferp == NULL) {
+    p->pci_irq = 0;
+    printk("Allocating buffer fails!\n");
+    return(0);
+  }
+  p->replyBufferp = (PU8)((PU8)p->outboundBufferp + 32*32*4);
+  p->messageBufferp = p->replyBufferp + (16*1024);
+
+  p->outMsgBlockPhyAddr = virt_to_bus(p->outboundBufferp);
+  p->pLinOutMsgBlock = (PU8)(p->outboundBufferp); 
+
+  /*
+   * Allocate the  set of scbs for this controller.  This is to stream-
+   * line code elsewhere in the driver.  If we have to check for the existence
+   * of scbs in certain code sections, it slows things down.  However, as
+   * soon as we register the IRQ for this card, we could get an interrupt that
+   * includes possibly the SCSI_RSTI interrupt.  If we catch that interrupt
+   * then we are likely to segfault if we don't have at least one chunk of
+   * SCBs allocated or add checks all through the reset code to make sure
+   * that the SCBs have been allocated which is an invalid running condition
+   * and therefore I think it's preferable to simply pre-allocate the first
+   * chunk of SCBs.
+   */
+
+  result = pti_st_allocate_scb(p);
+  if(!result) 
+  {
+    p->pci_irq = 0;
+    printk("Allocating scbs fails!\n");
+    return(0);
+  }
+
+  /*
+   *  Disable interrupt
+   */
+   p->p_atu->OutIntMask = 0xffffffff;
+
+  if(!IOP_init(p)) 
+  {
+    p->pci_irq = 0;
+    return (0);
+  }
+ 
+  /*
+   * Clear out any possible pending interrupts, again.
+   */
+  /*  pti_st_clear_intstat(p); */
+
+  /*
+   * Register IRQ with the kernel.  Only allow sharing IRQs with
+   * PCI devices.
+   */
+  result = (request_irq(p->pci_irq, do_pti_st_isr, SA_SHIRQ, "pti_st", p));
+  if(result < 0)
+  {
+  	result = (request_irq(p->pci_irq, do_pti_st_isr,
+			(SA_INTERRUPT | SA_SHIRQ), "pti_st", p));
+  }
+ 
+  if (result < 0)
+  {
+    printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring "
+           "controller.\n", p->host_no, p->pci_irq);
+    p->pci_irq = 0;
+    return (0);
+  } else {
+    /*
+     *  Enable interrupt
+     */
+    p->p_atu->OutIntMask = 0x00000000;
+ }
+
+  host->max_id = MAX_ARRAYS;
+  host->max_channel = 0;
+  host->max_lun = p->max_lun = 1; 
+ 
+  return (1);
+}
+
+/*
+ * Function:    pti_st_free(struct pti_st_host *)
+ * Description: Frees and releases all resources associated with an instance of
+ *              the driver (struct pti_st_host *).
+ */
+static void
+pti_st_free(struct pti_st_host *p)
+{
+  int i;
+
+  if (p->scb_data != NULL)
+  {
+  
+     /*
+     * Free the driver SCBs.  These were allocated on an as-need
+     * basis.  We allocated these in groups depending on how many
+     * we could fit into a given amount of RAM.  The tail SCB for
+     * these allocations has a pointer to the alloced area.
+     */
+    for (i = 0; i < p->scb_data->maxscbs; i++)
+    {
+      if (p->scb_data->scb_array[i]->kmalloc_ptr != NULL)
+        kfree(p->scb_data->scb_array[i]->kmalloc_ptr);
+      p->scb_data->scb_array[i] = NULL;
+    }
+  
+    /*
+     * Free the SCB data area.
+     */
+    kfree(p->scb_data);
+  }
+}
+
+/*
+ * Function:    pti_st_release(struct Scsi_Host *)
+ * Description: Free the passed in Scsi_Host memory structures prior to 
+ *              unloading the module.
+ */
+int
+pti_st_release(struct Scsi_Host *host)
+{
+  struct pti_st_host *p = (struct pti_st_host *) host->hostdata;
+  int i;
+
+  for(i = 0; i < MAX_ADAPTORS; i++)
+	if(p == pti_st_hostp[i])
+		break;
+
+  if(!p || i >= MAX_ADAPTORS)
+	return(-1);
+
+  if(p->pci_irq) {
+    free_irq(p->pci_irq, p);
+    p->pci_irq = 0;
+    /*
+     *  Disbale interrupt
+     */
+    p->p_atu->OutIntMask = 0x000000fc;
+  }
+  if(p->maddr)
+  {
+    iounmap((void *) (((unsigned long) p->maddr)));
+    p->maddr = 0;
+  }
+  if(p->outboundBufferp) {
+     kfree(p->outboundBufferp);
+     p->outboundBufferp = NULL;
+  }
+  if(p->pti_stdev_bufferp) {
+    kfree(p->pti_stdev_bufferp);
+    p->pti_stdev_bufferp = NULL;
+  }
+  pti_st_free(p);
+  pti_st_hostp[i] = NULL;
+  return(0);
+}
+
+/*
+ * Function:    pti_st_alloc(Scsi_Host_Template *, struct pti_st_host *)
+ * Description: Allocate and initialize a host structure.  
+ *              Returns NULL upon error and a pointer to a pti_st_host struct
+ *              upon success.
+ */
+static struct pti_st_host *
+pti_st_alloc(Scsi_Host_Template *sht, struct pti_st_host *temp)
+{
+  struct pti_st_host *p = NULL;
+  struct Scsi_Host *host;
+
+  /*
+   * Allocate a storage area by registering us with the mid-level
+   * SCSI layer.
+   */
+  host = scsi_register(sht, sizeof(struct pti_st_host));
+
+  if (host != NULL)
+  {
+    p = (struct pti_st_host *) host->hostdata;
+    memset(p, 0, sizeof(struct pti_st_host));
+    *p = *temp;
+    p->host = host;
+    p->scsi_id = -1;
+    p->host_no = host->host_no;
+    p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
+    if (p->scb_data != NULL)
+    {
+      memset(p->scb_data, 0, sizeof(scb_data_type));
+      scbq_init (&p->scb_data->free_scbs);
+    }
+    else
+    {
+      /*
+       * For some reason we don't have enough memory.  Free the
+       * allocated memory for the pti_st_host struct, and return NULL.
+       */
+      scsi_unregister(host);
+      return(NULL);
+    }
+    p->pti_stdev_bufferp = kmalloc(sizeof(PTI_STDEV_INBUFFER), GFP_ATOMIC);
+    if(p->pti_stdev_bufferp != NULL)
+    {
+	memset(p->pti_stdev_bufferp, 0, sizeof(PTI_STDEV_INBUFFER));
+    } else {
+      scsi_unregister(host);
+      return(NULL);
+    }
+  }
+  return (p);
+}
+
+
+/*
+ * Function:    pti_st_detect(Scsi_Host_Template *)
+ * Description: Try to detect and register i960 controller.
+ *              This should really be called pti_st_probe().  A sequence of
+ *              probe(), attach()/detach(), and init() makes more sense than
+ *              one do-it-all function.  This may be useful when (and if) the
+ *              mid-level SCSI code is overhauled.
+ */
+int pti_st_detect(Scsi_Host_Template  *template)
+{   
+  struct pci_dev *pdev;
+  int found = 0;
+    
+  if (!pci_present())
+  	return 0;
+
+    
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+  pci_for_each_dev(pdev)
+#else
+  for(pdev = pci_devices, found = 0;
+		found < MAX_ADAPTORS && pdev != NULL;
+		pdev = pdev->next)
+#endif
+  {
+	if(pdev->vendor != PCI_VENDOR_ID_INTEL ||
+		(pdev->device != PCI_DEVICE_ID_PROMISE_ST100 &&		/* ST100 */
+	         pdev->device != PCI_DEVICE_ID_PROMISE_ST100SX6))	/* ST100SX6 */
+  			continue;
+	
+	pti_st_install(template, pdev, &found);
+  }
+
+  return(found);
+}
+
+static int pti_st_install(Scsi_Host_Template  *template, struct pci_dev *pdev, int *aptno)
+{
+  struct pti_st_host *p = NULL;
+  struct pti_st_host *temp_p = NULL;
+  unsigned short command;
+  unsigned long cmd;
+  unsigned long devicenumber, functionnumber;
+		
+  devicenumber = PCI_SLOT(pdev->devfn);
+  functionnumber = 0;
+
+  /*
+   * Expose the ship behind i960 for initialization, or it will failed
+   */
+  cmd = 0x0000;
+  PTI_ST_SetBusDataByOffset(pdev->bus->number,
+		 	devicenumber,
+			functionnumber,
+			&cmd,
+			0x42,
+			sizeof(U16));
+
+  template->sg_tablesize = PTI_ST_MAX_SG;
+  template->proc_dir = &proc_scsi_pti_st;
+  template->proc_info = PTI_procfile_read;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+  if(!template->proc_name) {
+	if(template->name)
+		template->proc_name = (char *)template->name;
+  	else 
+  		template->proc_name = "pti_st";
+  }
+#endif
+    
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+     pci_enable_device(pdev);
+#endif
+
+  if ( !(temp_p = kmalloc(sizeof(struct pti_st_host), GFP_ATOMIC))) 
+  {
+      printk("pti_st_host data structure memory alloc error!!!\n");
+      cmd = 0x03ff;
+      PTI_ST_SetBusDataByOffset(pdev->bus->number,
+			 	devicenumber,
+				functionnumber,
+				&cmd,
+				0x42,
+				sizeof(U16));
+      return(0);
+  }
+  memset(temp_p, 0, sizeof(struct pti_st_host));
+ 
+  temp_p->pci_irq = pdev->irq;
+  temp_p->pdev = pdev;
+  temp_p->pci_bus = pdev->bus->number;
+  temp_p->pci_device_fn = pdev->devfn;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+  temp_p->mbase = pci_resource_start(pdev, 0);
+  template->name = "pti_st";
+#else
+  temp_p->mbase = pdev->base_address[0];
+#endif
+  pci_read_config_word(pdev, PCI_COMMAND, &command);
+
+  command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+  pci_write_config_word(pdev, PCI_COMMAND, command);
+
+  temp_p->mbase &= PCI_BASE_ADDRESS_MEM_MASK;
+    
+  printk("Found PTI SuperTrak at mbase: %#x, irq %d.\n",
+          temp_p->mbase, temp_p->pci_irq);
+
+  pti_st_hostp[*aptno] = p = pti_st_alloc(template, temp_p);
+
+  if (p != NULL)
+  {
+    DRIVER_LOCK_INIT
+    (*aptno)++;    
+    if (!pti_st_register(template, p))
+    {
+      pti_st_release(p->host);
+      scsi_unregister(p->host);
+      (*aptno)--;
+      pti_st_hostp[*aptno] = NULL;
+    }
+  }
+
+  cmd = 0x03ff;
+  PTI_ST_SetBusDataByOffset(pdev->bus->number,
+			 	devicenumber,
+				functionnumber,
+				&cmd,
+				0x42,
+				sizeof(U16));
+
+  kfree(temp_p);
+  return (*aptno);
+}
+
+/*
+ * Function:    pti_st_copy_internal_data(Scsi_Cmnd *, char *, unsigned short)
+ * Description: Queue a SCB to the controller.
+ */
+static void
+pti_st_copy_internal_data(Scsi_Cmnd *scp, char *buffer, unsigned short count)
+{
+  unsigned short cpcount,i;
+  unsigned short cpsum,cpnow;
+  struct scatterlist *sl;
+
+  cpcount = count<=(ushort)scp->bufflen ? count:(ushort)scp->bufflen;
+  if (scp->use_sg) 
+  {
+    sl = (struct scatterlist *)scp->request_buffer;
+    for (i=0,cpsum=0; i<scp->use_sg; ++i,++sl) 
+    {
+      cpnow = (ushort)sl->length;
+      if (cpsum+cpnow > cpcount) 
+        cpnow = cpcount - cpsum;
+      cpsum += cpnow;
+      memcpy((char*)sl->address,buffer,cpnow);
+      if (cpsum == cpcount)
+        break;
+      buffer += cpnow;
+    }
+  } 
+  else 
+  {
+    memcpy((char*)scp->request_buffer,buffer,cpcount);
+  }
+}
+
+
+/*
+ * Function:    pti_st_rw_cmd(Scsi_Cmnd *, void (*fn)(Scsi_Cmnd *)) * Description: Translate Scsi Command to I2O Message Frame.
+ */
+static int
+pti_st_rw_cmd(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
+{
+  struct pti_st_host *p;
+  struct pti_st_scb *scb;
+  unsigned long msgoffset;
+  unsigned long blk_nr = 0;
+  unsigned long blk_count = 0;
+  PI2O_BSA_RW_MESSAGE mfp;
+  unsigned char *cmnd;
+  unsigned long pBaseAddrReg;
+  int i;
+
+  p = (struct pti_st_host *) cmd->host->hostdata;
+
+  for(i = 0; i < MAX_ADAPTORS; i++)
+	if(p == pti_st_hostp[i])
+		break;
+
+  if(i >= MAX_ADAPTORS || !p) {
+    cmd->result = (DID_BAD_TARGET << 16);
+    fn(cmd);
+    return 0;
+  }
+
+  scb = scbq_remove_head(p, &p->scb_data->free_scbs);
+
+  if (scb == NULL)
+  {
+    cmd->result = (DID_BUS_BUSY << 16);
+    printk(WARN_LEAD"Couldn't get a free SCB.\n", p->host_no,
+           CTL_OF_CMD(cmd));
+    fn(cmd);
+    return 0;
+  }
+
+  if (cmd->target >= MAX_DRIVES || p->I2ODisk[cmd->target].present != TRUE)
+  {
+    cmd->result = (DID_BAD_TARGET << 16);
+    fn(cmd);
+    return 0;
+  }
+
+  DRIVER_LOCK
+
+  pBaseAddrReg = (U32)p->maddr;
+  msgoffset = * (U32 *)(pBaseAddrReg+INBOUNDQPORT);
+  if (msgoffset == 0xFFFFFFFF)
+  {
+    printk(INFO_LEAD"Couldn't get a free MF from inboundqport.\n",
+           p->host_no, CTL_OF_CMD(cmd));
+    cmd->result = (DID_BUS_BUSY << 16);
+/*
+ *  DRIVER_LOCK
+ */
+    scbq_insert_head(p, &p->scb_data->free_scbs, scb);
+    DRIVER_UNLOCK
+    fn(cmd);
+    return 0;    
+  }      
+  scb->cmd = cmd;
+  pti_st_position(cmd) = scb->tag;
+  
+  p->scb_data->scb_array[scb->tag] = scb;
+
+  /*
+   * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
+   * is set up properly, and the parity error flag is reset, then send
+   * the SCB to the sequencer and watch the fun begin.
+   */
+  cmd->scsi_done = fn;
+  cmd->result = DID_OK;
+  memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+  cmd->host_scribble = NULL;
+
+  scb->flags |= SCB_ACTIVE;
+  mfp = (PI2O_BSA_RW_MESSAGE)(pBaseAddrReg + msgoffset);
+  memset((char *)mfp, 0, sizeof(I2O_BSA_READ_MESSAGE));
+  cmnd = (unsigned char *)cmd->cmnd;
+  switch (*cmnd) 
+  {
+    case READ_6:
+      {
+        blk_nr = cmnd[3] + (cmnd[2] << 8) + ((cmnd[1] & 0x1f) << 16);
+        blk_count = cmnd[4];
+      }
+      mfp->StdMessageFrame.Function = I2O_BSA_BLOCK_READ;
+      mfp->FetchAhead = 0;
+      break;
+    
+    case READ_10:
+      {
+        blk_nr = ntohl(*(PU32)&cmnd[2]);
+        blk_count = cmnd[8] + (cmnd[7] << 8);
+      }
+      mfp->StdMessageFrame.Function = I2O_BSA_BLOCK_READ;
+      mfp->FetchAhead = 0;
+      break;
+
+    case WRITE_6:      
+      {
+        blk_nr = cmnd[3] + (cmnd[2] << 8) + ((cmnd[1] & 0x1f) << 16);
+        blk_count = cmnd[4];
+      }
+      mfp->StdMessageFrame.Function = I2O_BSA_BLOCK_WRITE;
+      break;
+
+    case WRITE_10:
+      {
+        blk_nr = ntohl(*(PU32)&cmnd[2]);
+        blk_count = cmnd[8] + (cmnd[7] << 8);
+      }
+      mfp->StdMessageFrame.Function = I2O_BSA_BLOCK_WRITE;
+      break;
+  }
+  mfp->LogicalByteAddress.HighPart = blk_nr >> (32 - 9);
+  mfp->LogicalByteAddress.LowPart = blk_nr << 9;
+  mfp->TransferByteCount = blk_count << 9;
+  mfp->TransactionContext = cmd->serial_number;
+  mfp->StdMessageFrame.InitiatorContext = scb->tag;
+  mfp->StdMessageFrame.VersionOffset=0x81;  
+  mfp->StdMessageFrame.MsgFlags=0;
+  mfp->StdMessageFrame.MessageSize=sizeof(I2O_BSA_READ_MESSAGE)>>2;
+  mfp->StdMessageFrame.TargetAddress=p->I2ODisk[cmd->target].LocalTID; 
+  mfp->StdMessageFrame.InitiatorAddress = 0x01;
+  mfp->ControlFlags = 0;
+  mfp->TimeMultiplier = 0x31;    /*0;*/
+
+  {
+      //printk("Issue cmd= %x, mfp 0x%x, sno= 0x%x tag= 0x%x scb=0x%x\n",
+      //    cmd, mfp, cmd->serial_number, scb->tag, scb);
+  }
+  /*
+   * The interpretation of request_buffer and request_bufflen
+   * changes depending on whether or not use_sg is zero; a
+   * non-zero use_sg indicates the number of elements in the
+   * scatter-gather array.
+   */
+
+  if (cmd->use_sg)
+  {
+    struct scatterlist *sg;  /* Must be mid-level SCSI code scatterlist */
+
+    /*
+     * We must build an SG list in I2O SGL format, as the kernel's SG list
+     * cannot be used directly 
+     */
+    int i;
+
+    sg = (struct scatterlist *)cmd->request_buffer;
+    /*
+     * Copy the segments into the SG array.  NOTE!!! - We used to
+     * have the first entry both in the data_pointer area and the first
+     * SG element.  That has changed somewhat.  We still have the first
+     * entry in both places, but now we download the address of
+     * scb->sg_list[1] instead of 0 to the sg pointer in the mf.
+     */
+    for (i = 0; i < (cmd->use_sg); i++)
+    {
+      mfp->SGL.u.Simple[i].FlagsCount.Count = cpu_to_le32(sg[i].length);
+      mfp->SGL.u.Simple[i].FlagsCount.Flags = 
+                              (I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT);
+      mfp->SGL.u.Simple[i].PhysicalAddress = 
+                              cpu_to_le32(VIRT_TO_BUS(sg[i].address));
+    }
+    mfp->SGL.u.Simple[cmd->use_sg - 1].FlagsCount.Flags |= 
+                          ( I2O_SGL_FLAGS_LAST_ELEMENT |
+                            I2O_SGL_FLAGS_END_OF_BUFFER);
+  }
+  else
+  {
+      mfp->SGL.u.Simple[0].FlagsCount.Count =
+                        cpu_to_le32(cmd->request_bufflen);
+      mfp->SGL.u.Simple[0].FlagsCount.Flags = 
+                        ( I2O_SGL_FLAGS_LAST_ELEMENT |
+                          I2O_SGL_FLAGS_END_OF_BUFFER |
+			  I2O_SGL_FLAGS_TRANSPORT_ELEMENT |
+                          I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT);
+      mfp->SGL.u.Simple[0].PhysicalAddress = 
+                        cpu_to_le32(VIRT_TO_BUS(cmd->request_buffer));
+  }
+
+  * (U32 *)(pBaseAddrReg+INBOUNDQPORT) = msgoffset;
+
+  DRIVER_UNLOCK
+
+  return (0);
+}
+
+/*
+ * Function:    pti_st_internal_cmd(Scsi_Cmnd *, void (*fn)(Scsi_Cmnd *))
+ * Description: Excuting TEST_UNIT_READY, INQUIRY, READ_CAPACITY, etc. 
+ *              scsi command.
+ */
+static int
+pti_st_internal_cmd(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
+{
+  struct pti_st_host *p;
+
+  // struct pti_st_scb *scb;
+  // unsigned long cpu_flags = 0;
+  pti_inq_data inq;
+  pti_rdcap_data rdc;
+  int i;
+
+  p = (struct pti_st_host *) cmd->host->hostdata;
+
+  for(i = 0; i < MAX_ADAPTORS; i++)
+	if(p == pti_st_hostp[i])
+		break;
+
+  if(i >= MAX_ADAPTORS) {
+    cmd->result = (DID_BAD_TARGET << 16);
+    fn(cmd);
+    return 0;
+  }
+
+  switch (cmd->cmnd[0]) 
+  {
+    case TEST_UNIT_READY:
+      cmd->result = DID_OK << 16;
+      break;
+
+    case INQUIRY:
+      memset((void *)&inq, 0, sizeof(inq));
+      inq.type_qual = TYPE_DISK;
+      /* 
+       * you can here set all disks to removable, if you want to do
+       * a flush using the ALLOW_MEDIUM_REMOVAL command 
+       */
+      inq.modif_rmb = 0x00;
+      inq.version   = 2;
+      inq.resp_aenc = 2;
+      inq.add_length= 32;
+      strcpy(inq.vendor,"PTI    ");
+      strcpy(inq.product,"SuperTrak");
+      strcpy(inq.revision,"   ");
+      if(cmd->target < MAX_DRIVES && p->I2ODisk[cmd->target].present == TRUE)
+      {
+      	pti_st_copy_internal_data(cmd,(char*)&inq, sizeof(pti_inq_data));
+      	cmd->result = DID_OK << 16;
+      } else {
+      	pti_st_copy_internal_data(cmd,(char*)&inq, sizeof(pti_inq_data));
+      	cmd->result = DID_BAD_TARGET << 16;
+      }
+      break;
+
+#if 0
+    case REQUEST_SENSE:
+      sd.errorcode = 0x70;
+      sd.segno     = 0x00;
+      sd.key       = NO_SENSE;
+      sd.info      = 0;
+      sd.add_length= 0;
+      pti_copy_internal_data(scp,(char*)&sd,sizeof(gdth_sense_data));
+      cmd->result = DID_OK << 16;
+      break;
+    case MODE_SENSE:
+      memset((char*)&mpd,0,sizeof(gdth_modep_data));
+      mpd.hd.data_length = sizeof(gdth_modep_data);
+      mpd.hd.dev_par     = (ha->id[b][t].devtype&2) ? 0x80:0;
+      mpd.hd.bd_length   = sizeof(mpd.bd);
+      mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16;
+      mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8;
+      mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff);
+      pti_copy_internal_data(scp,(char*)&mpd,sizeof(gdth_modep_data));
+      cmd->result = DID_OK << 16;
+      break;
+#endif
+
+    case READ_CAPACITY:
+      if(cmd->target < MAX_DRIVES && p->I2ODisk[cmd->target].present)
+      {
+         rdc.last_block_no = ntohl(p->I2ODisk[cmd->target].lastLBA);
+         rdc.block_length = ntohl(SECTOR_SIZE);
+         pti_st_copy_internal_data(cmd,(char*)&rdc, sizeof(pti_rdcap_data));
+         cmd->result = DID_OK << 16;
+      } else {
+	 cmd->result = DID_BAD_TARGET;
+      }
+      break;
+
+    default:
+      printk("!!!!!!!!PTI: Unknown SCSI command 0x%x to cache service !\n",
+             cmd->cmnd[0]);
+      cmd->result = DID_ABORT << 16;
+      break;
+  }   
+ 
+  fn(cmd);
+  return 0;
+}
+
+/*
+ * Function:    pti_st_queue(Scsi_Cmnd *, void (*fn)(Scsi_Cmnd *))
+ * Description: Queue a SCB to the controller.
+ */  
+int
+pti_st_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
+{
+  int ret;
+
+  switch (cmd->cmnd[0]) 
+  {
+    case READ_6:
+    case READ_10:
+    case WRITE_6:
+    case WRITE_10:
+//    case VERIFY:
+      ret = pti_st_rw_cmd(cmd, fn);         
+      return(ret);         
+    case TEST_UNIT_READY:
+    case INQUIRY:
+    case READ_CAPACITY:
+      return(pti_st_internal_cmd(cmd, fn));
+//    case VERIFY:
+//    case START_STOP:
+//    case REQUEST_SENSE:
+//    case MODE_SENSE:
+
+    default:
+      break;
+  }
+  printk("PTI: Unknown SCSI command 0x%x to cache service!\n", cmd->cmnd[0]);
+  cmd->result = DID_ABORT << 16;
+  fn(cmd);
+  return 0;
+}
+
+/*
+ * Function: pti_st_abort(Scsi_Cmnd *)
+ * Description: Abort the current SCSI command(s).
+ */   
+int
+pti_st_abort(Scsi_Cmnd *cmd)
+{
+  struct pti_st_scb  *scb = NULL;
+  struct pti_st_host *p;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
+  Scsi_Cmnd *cmd_next, *cmd_prev;
+  int i;
+
+  p = (struct pti_st_host *) cmd->host->hostdata;
+  for(i = 0; i < MAX_ADAPTORS; i++)
+	if(p == pti_st_hostp[i])
+		break;
+
+  if(i >= MAX_ADAPTORS || !p) {
+  	return(SCSI_ABORT_NOT_RUNNING);
+  }
+
+  scb = (p->scb_data->scb_array[pti_st_position(cmd)]);
+
+
+  DRIVER_LOCK
+
+/*
+ *  Run the isr to grab any command in the QOUTFIFO and any other misc.
+ *  assundry tasks.  This should also set up the bh handler if there is
+ *  anything to be done, but it won't run until we are done here since
+ *  we are following a straight code path without entering the scheduler
+ *  code.
+ */
+
+  {
+    pti_st_isr(p->pci_irq, p, (void *)NULL);
+    pti_st_done_cmds_complete(p);
+  }
+
+  if ((scb == NULL) || (cmd->serial_number != cmd->serial_number_at_timeout))
+                      /*  Totally bogus cmd since it points beyond our  */
+  {                   /*  valid SCB range or doesn't even match it's own*/
+                      /*  timeout serial number.                        */
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_NOT_RUNNING);
+  }
+
+  if (scb->cmd != cmd)  /*  Hmmm...either this SCB is currently free with a */
+  {                     /*  NULL cmd pointer (NULLed out when freed) or it  */
+                        /*  has already been recycled for another command   */
+                        /*  Either way, this SCB has nothing to do with this*/
+                        /*  command and we need to deal with cmd without    */
+                        /*  touching the SCB.                               */
+                        /*  The theory here is to return a value that will  */
+                        /*  make the queued for complete command actually   */
+                        /*  finish successfully, or to indicate that we     */
+                        /*  don't have this cmd any more and the mid level  */
+                        /*  code needs to find it.                          */
+    cmd_next = p->completeq.head;
+    cmd_prev = NULL;
+    while (cmd_next != NULL) 
+    {
+      if (cmd_next == cmd) 
+      {
+//        if (pti_st_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "Abort called for command "
+          "on completeq, completing.\n", p->host_no, CTL_OF_CMD(cmd));
+        if ( cmd_prev == NULL )
+          p->completeq.head = (Scsi_Cmnd *)cmd_next->host_scribble;
+        else
+          cmd_prev->host_scribble = cmd_next->host_scribble;
+        cmd_next->scsi_done(cmd_next);
+        DRIVER_UNLOCK
+
+        return(SCSI_ABORT_NOT_RUNNING); /* It's already back as a successful
+                                         * completion */
+      }                                  
+      cmd_prev = cmd_next;
+      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+    }
+    
+//    if (pti_st_verbose & VERBOSE_ABORT_MID)
+      printk(INFO_LEAD "Abort called for already completed"
+        " command.\n", p->host_no, CTL_OF_CMD(cmd));
+    DRIVER_UNLOCK
+    return(SCSI_ABORT_NOT_RUNNING);
+  }
+           
+/*
+ *  Hmmm...completeq, QOUTFIFO, QINFIFO, WAITING_SCBH, waitingq all checked.
+ *  OK...the sequencer's paused, interrupts are off, and we haven't found the
+ *  command anyplace where it could be easily aborted.  Time for the hard
+ *  work.  We also know the command is valid.  This essentially means the
+ *  command is disconnected, or connected but not into any phases yet, which
+ *  we know due to the tests we ran earlier on the current active scb phase.
+ *  At this point we can queue the abort tag and go on with life.
+ */
+  if (scb->flags & SCB_WAITINGQ)
+  {
+     scbq_remove(p, &p->waiting_scbs, scb);
+  }
+  scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
+  scb->flags |= SCB_ABORT;
+  pti_st_done(p, scb);
+  pti_st_done_cmds_complete(p);
+//  pti_st_run_waiting_queues(p);
+  DRIVER_UNLOCK
+
+/*
+ *  On the return value.  If we found the command and aborted it, then we know
+ *  it's already sent back and there is no reason for a further timeout, so
+ *  we use SCSI_ABORT_SUCCESS.  On the queued abort side, we aren't so certain
+ *  there hasn't been a bus hang or something that might keep the abort from
+ *  from completing.  Therefore, we use SCSI_ABORT_PENDING.  The first time 
+this
+ *  is passed back, the timeout on the command gets extended, the second time
+ *  we pass this back, the mid level SCSI code calls our reset function, which
+ *  would shake loose a hung bus.
+ */
+  return(SCSI_ABORT_SUCCESS);
+}
+
+/*
+ * Function:    pti_st_reset(Scsi_Cmnd *, unsigned int)
+ * Description: Resetting the bus always succeeds - is has to, otherwise the
+ *              kernel will panic! Try a surgical technique: sending ARRAY 
+ *              RESET message frame 
+ */
+int
+pti_st_reset(Scsi_Cmnd *cmd, unsigned int flags)
+{
+  struct pti_st_scb *scb = NULL;
+  struct pti_st_host *p;
+  int    i;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
+  unsigned long cpu_flags = 0;
+#endif
+  Scsi_Cmnd *cmd_prev, *cmd_next;
+
+
+  if ( cmd == NULL )
+  {
+    return(SCSI_RESET_SNOOZE);
+  }
+
+  p = (struct pti_st_host *) cmd->host->hostdata;
+  for(i = 0; i < MAX_ADAPTORS; i++)
+	if(p == pti_st_hostp[i])
+		break;
+
+  if(!p || i >= MAX_ADAPTORS)
+        return(SCSI_RESET_NOT_RUNNING);
+
+  scb = (p->scb_data->scb_array[pti_st_position(cmd)]);
+
+  DRIVER_LOCK
+
+  pti_st_isr(p->pci_irq, p, (void *)NULL );
+  pti_st_done_cmds_complete(p);
+
+  if (scb == NULL)
+  {
+//    if (pti_st_verbose & VERBOSE_RESET_MID)
+      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
+           "->SCB mapping, improvising.\n", p->host_no, CTL_OF_CMD(cmd));
+  }
+  else if (scb->cmd != cmd) 
+  {
+//    if (pti_st_verbose & VERBOSE_RESET_MID)
+    printk(INFO_LEAD "Reset called with recycled SCB "
+        "for cmd.\n", p->host_no, CTL_OF_CMD(cmd));
+    cmd_prev = NULL;
+    cmd_next = p->completeq.head;
+    while ( cmd_next != NULL )
+    {
+      if (cmd_next == cmd)
+      {
+//        if (pti_st_verbose & VERBOSE_RESET_RETURN)
+          printk(INFO_LEAD "Reset, found cmd on completeq"
+          ", completing.\n", p->host_no, CTL_OF_CMD(cmd));
+        DRIVER_UNLOCK
+        return(SCSI_RESET_NOT_RUNNING);
+      }
+      cmd_prev = cmd_next;
+      cmd_next = (Scsi_Cmnd *)cmd_next->host_scribble;
+    }
+  }
+/*
+ *  By this point, we want to already know what we are going to do and
+ *  only have the following code implement our course of action.
+ */
+  for (i = 0; i < p->scb_data->maxscbs; i++)
+  {
+    scb = p->scb_data->scb_array[i];
+    if (scb->flags & SCB_ACTIVE)
+    {
+      scb->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+      scb->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+    }
+  }
+  scbq_init(&p->waiting_scbs);
+  pti_st_run_done_queue(p, TRUE);
+      /*  We can't rely on run_waiting_queues to unpause the sequencer for
+       *  PCI based controllers since we use AAP */
+  DRIVER_UNLOCK
+  return (SCSI_RESET_SUCCESS);
+}
+
+/*
+ * Function:    pti_st_biosparam(Disk *, kdev_t, int[])
+ * Description: Return the disk geometry for the given SCSI device.
+ */   
+int
+pti_st_biosparam(Disk *disk, kdev_t dev, int geom[])
+{
+  int heads;
+  int sectors;
+  int cylinders;
+  struct pti_st_host *p;
+
+  p = (struct pti_st_host *) disk->device->host->hostdata;
+
+  /*
+   * XXX - if I could portably find the card's configuration
+   *       information, then this could be autodetected instead
+   *       of left to a boot-time switch.
+   */
+  heads = 64;
+  sectors = 32;
+  cylinders = disk->capacity / (heads * sectors);
+
+  geom[0] = heads;
+  geom[1] = sectors;
+  geom[2] = cylinders;
+
+  return (0);
+}
+
+
+
+
+/***************************************************************************
+   Hardware Interface Functions             
+****************************************************************************/
+
+/*
+ * Function   : static int IOP_init(struct pti_st_host *);
+ * Description: just initialize the hardware, fetch parameters from PCI. 
+ */
+static int IOP_init(struct pti_st_host *hostp)
+{
+  int index;
+  int IopStatus;
+  unsigned long pBaseAddrReg = (U32)hostp->maddr;
+  unsigned long pMFA_Inbound;
+
+  // printk("Initializing i960!  pBaseAddrReg :%lx\n", pBaseAddrReg);
+
+  // Until the Inbound Queue is available:
+  pMFA_Inbound = *(U32 *)(pBaseAddrReg+INBOUNDQPORT);
+  while (((U32) pMFA_Inbound == -1)) 
+    pMFA_Inbound = * (U32 *)(pBaseAddrReg+INBOUNDQPORT);
+  UtilNOPCall(hostp);
+
+  ExecIOPReset(hostp);
+  
+  IopStatus = GetStatusCall(hostp, (void *)hostp->replyBufferp);
+
+  OutboundInitCall(hostp);  
+
+  UtilNOPCall(hostp);
+  IopStatus = GetStatusCall(hostp, (void *)hostp->replyBufferp);
+
+  /* Outbound Queue is now available! */
+  
+  SysTabSetCall(hostp, (PI2O_EXEC_SYS_TAB_SET_MESSAGE)hostp->messageBufferp, 
+                (void *)hostp->replyBufferp);  
+  if (pti_st_waitreplymsg(hostp) != I2O_REPLY_STATUS_SUCCESS)
+  {
+    printk("!BAD reply after sending ExecSysTabSet Message!\n");
+    return(FALSE);
+  }
+
+  IopStatus = GetStatusCall(hostp, (void *)hostp->replyBufferp);
+ 
+  if (IopStatus == I2O_IOP_STATE_READY)
+  {
+    /*
+     *    Send ExecSysEnable message, wait for reply
+     *
+     */
+    EnableSysCall(hostp);
+    if (pti_st_waitreplymsg(hostp) != I2O_REPLY_STATUS_SUCCESS)
+    {
+	printk("!BAD reply after sending ExecSysEnable Message!\n");
+	return(FALSE);
+    }
+    if (GetStatusCall(hostp, (void *)hostp->replyBufferp) != I2O_IOP_STATE_OPERATIONAL)
+	return(FALSE);
+
+  }
+
+  
+  /* IOP is in OPERATIONAL state! */
+
+  LCTNotifyCall(hostp);
+  if (pti_st_waitreplymsg(hostp) != I2O_REPLY_STATUS_SUCCESS)
+  {
+    printk("!BAD reply after sending ExecLctNotify Message!\n");
+    return(FALSE);
+  }
+
+
+  /* IOP is now initialized! */
+ 
+  GetInfoFromLCT(hostp,
+		 (void *)hostp->replyBufferp,
+                 (PI2ODISK)hostp->I2ODisk, 
+                 (unsigned int *)&hostp->TotalDiskCount);
+
+  for (index = 0; index < hostp->TotalDiskCount; index++)
+  {
+    ComposeDiskInfo(hostp,
+		    (PI2O_UTIL_PARAMS_GET_MESSAGE)hostp->messageBufferp, 
+                    (void *)hostp->replyBufferp,
+                    (PI2ODISK)&hostp->I2ODisk[index] );
+    hostp->I2ODisk[index].present = TRUE;
+  }
+  
+  return(TRUE);
+}
+
+/*
+ * Function:    unsigned int GetStatusCall(void *)
+ * Description: get IOP's state. 
+ * Return :     IOP's current state.
+ */
+static unsigned int GetStatusCall(struct pti_st_host *hostp, void * replyBuffer)
+{
+  int i;
+  volatile int state;
+  U32 timeout; 
+  U32 msgOffset;
+  unsigned long pBaseAddrReg = (U32)hostp->maddr;
+  PI2O_EXEC_STATUS_GET_MESSAGE pMsg;
+  PI2O_EXEC_STATUS_GET_REPLY reply = 
+    (PI2O_EXEC_STATUS_GET_REPLY)replyBuffer;
+
+  msgOffset = hostp->p_atu->InQueue;
+  pMsg = (PI2O_EXEC_STATUS_GET_MESSAGE)(hostp->LinBaseAddr + msgOffset);
+
+  memset((void *)reply, 0, sizeof(PI2O_EXEC_STATUS_GET_REPLY)); 
+ 
+  pMsg->ReplyBufferLength=0x100;
+  pMsg->ReplyBufferAddressLow = virt_to_bus(reply); 
+  pMsg->VersionOffset=0x01;
+  pMsg->MsgFlags=0;                            /* No flag to set */
+  pMsg->MessageSize=(sizeof(I2O_EXEC_STATUS_GET_MESSAGE)>>2);
+  pMsg->TargetAddress=0;
+  pMsg->InitiatorAddress=0x1;                  /* from host */
+  pMsg->Function=I2O_EXEC_STATUS_GET;
+
+  *(U32 *)(pBaseAddrReg+INBOUNDQPORT) = msgOffset; /* YBM: ... = pMFA_Inbound;*/
+
+  timeout = 100000;
+  while(1)
+  {
+    for (i=0; i<1000; i++)      /* please don't hog the bus! */
+      ;    
+    if ((state=reply->IopState) != 0)
+      break;            
+    if (!timeout--)
+    {
+      printk(" Timeout wait for IOP Status Get Ready!\n");
+      return -1;
+    }
+  }
+
+  memcpy((void *)(&hostp->IopStatus),
+         (void *)reply,
+         sizeof(I2O_EXEC_STATUS_GET_REPLY));
+
+  return (unsigned int) reply->IopState;  
+}
+
+
+/*
+** =========================================================================
+** SendI2OOutboundQInitMsg()
+**
+** =========================================================================
+*/
+/*
+static int 
+SendI2OOutboundQInitMsg(PPAB pPab)
+{
+    U32 msgOffset, timeout, phyOutQFrames, i;
+    volatile PU32 pMsg;
+    volatile PU32 p32;
+    
+    
+    
+    msgOffset = pPab->p_atu->InQueue;
+
+    
+    if (msgOffset == 0xFFFFFFFF)
+    {
+#ifdef DEBUG
+        kprintf("SendI2OOutboundQInitMsg(): Inbound Free Q empty!\n");
+#endif
+        return RC_RTN_FREE_Q_EMPTY;
+    }
+    
+    
+    pMsg = (PU32)(pPab->pPci45LinBaseAddr + msgOffset);
+
+#ifdef DEBUG
+    kprintf("SendI2OOutboundQInitMsg - pMsg = 0x%08.8ulx, InQ msgOffset = 0x%08.8ulx\n", pMsg, msgOffset);
+#endif 
+
+    pMsg[0] = EIGHT_WORD_MSG_SIZE | TRL_OFFSET_6;
+    pMsg[1] = I2O_EXEC_OUTBOUND_INIT << 24 | I2O_HOST_TID << 12 | I2O_IOP_TID;
+    pMsg[2] = DEFAULT_RECV_INIT_CONTEXT;
+    pMsg[3] = 0x106; 
+    pMsg[4] = 4096; 
+    pMsg[5] = MSG_FRAME_SIZE  << 16 | 0x80; 
+    pMsg[6] = 0xD0000004;       
+    pMsg[7] = pPab->outMsgBlockPhyAddr - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB); 
+
+    p32 = (PU32)(pPab->pLinOutMsgBlock - ADAPTER_BLOCK_RESERVED_SPACE + sizeof(PAB));
+    p32[0] = 0;
+    
+    pPab->p_atu->InQueue = msgOffset;
+    
+    timeout = 100000;
+    while(1)
+    {
+        for (i = 0; i < 1000; i++) 
+            ;
+            
+        if (p32[0])
+            break;
+            
+        if (!timeout--)
+        {
+#ifdef DEBUG
+            kprintf("Timeout wait for InitOutQ InPrgress status from IOP\n");
+#endif 
+            return RC_RTN_NO_I2O_STATUS;
+        }
+    }
+
+    timeout = 100000;
+    while(1)
+    {
+        for (i = 0; i < 1000; i++)     
+            ;
+            
+        if (p32[0] == I2O_EXEC_OUTBOUND_INIT_COMPLETE)
+            break;
+
+        if (!timeout--)
+        {
+#ifdef DEBUG
+            kprintf("Timeout wait for InitOutQ Complete status from IOP\n");
+#endif
+            return RC_RTN_NO_I2O_STATUS;
+        }
+    }
+
+    phyOutQFrames = pPab->outMsgBlockPhyAddr;
+
+    for (i = 0; i < NMBR_MSG_FRAMES; i++)
+    {
+        pPab->p_atu->OutQueue = phyOutQFrames;
+        phyOutQFrames += MSG_FRAME_SIZE;
+    }
+    return RC_RTN_NO_ERROR;
+}
+*/
+
+/*
+ *
+ */
+static void OutboundInitCall(struct pti_st_host *hostp)
+{
+  U32 i;
+  U32 x;
+  U32 msgOffset;
+  U32 timeout;
+  PI2O_EXEC_OUTBOUND_INIT_MESSAGE pMsg;
+  unsigned long pBaseAddrReg = (U32)hostp->maddr;
+  unsigned long pMFA_Outbound = 0;
+
+  msgOffset = hostp->p_atu->InQueue;
+  pMsg = (PI2O_EXEC_OUTBOUND_INIT_MESSAGE)(hostp->LinBaseAddr+msgOffset);
+
+  memset((void *)hostp->replyBufferp, 0, 16*1024);
+  
+  pMsg->StdMessageFrame.VersionOffset=0x61;      // 32 bit frame
+  pMsg->StdMessageFrame.MsgFlags=0;
+  pMsg->StdMessageFrame.MessageSize=sizeof(I2O_EXEC_OUTBOUND_INIT_MESSAGE)>>2;
+  
+  pMsg->StdMessageFrame.TargetAddress=0;         // IXWork
+  pMsg->StdMessageFrame.InitiatorAddress = 0x01; // from Host
+  pMsg->StdMessageFrame.Function = I2O_EXEC_OUTBOUND_INIT;
+  pMsg->HostPageFrameSize = 4096;      
+  pMsg->InitCode = I2O_MESSAGE_IF_INIT_CODE_NO_OWNER;
+  pMsg->OutboundMFrameSize = 0x20;               //each frame 32 * 4 bytes
+  // the sgl for OutboundInitStatus Word, only 4 bytes.
+  pMsg->SGL.u.Simple[0].FlagsCount.Count=4;
+  pMsg->SGL.u.Simple[0].FlagsCount.Flags=(I2O_SGL_FLAGS_LAST_ELEMENT |
+                                         I2O_SGL_FLAGS_END_OF_BUFFER |
+                                         I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT);
+
+  pMsg->SGL.u.Simple[0].PhysicalAddress=virt_to_bus(hostp->replyBufferp);
+  
+  * (U32 *)(pBaseAddrReg+INBOUNDQPORT) = msgOffset; // YBM: ... = pMFA_Inbound;
+                                       
+  // wait for response:
+  timeout = 0x100000;
+  while(1)
+  {
+    for (i=0; i<1000; i++)      // please don't hog the bus!!!
+      ;    
+    if (*((U8*)hostp->replyBufferp) != 0)
+      break;
+            
+    if (!timeout--)
+    {
+      printk("Timeout wait for I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS status!\n");
+      return;
+    }
+  }
+
+  timeout = 100000;
+  while(1)
+  {
+    for (i= 0; i<1000; i++)      // please don't hog the bus!!!
+      ;
+    if (*((U8*)hostp->replyBufferp) == I2O_EXEC_OUTBOUND_INIT_COMPLETE)
+      break;
+
+    if (!timeout--)
+    {
+      printk("Timeout wait for I2O_EXEC_OUTBOUND_INIT_COMPLETE status!\n");
+      return;
+    }
+  }
+  
+  for(x=0; x < 32; x++)
+  {
+    pMFA_Outbound = (U32)&(hostp->outboundBufferp->outboundBuff[x]);
+    *((U32 *)(pBaseAddrReg+OUTBOUNDQPORT))=virt_to_bus((void *)pMFA_Outbound);
+    for (i=0; i<1000; i++) // just for waitting!
+      ;
+    if (DEBUG)
+    {
+      printk("Write to Outbound port, MFAs are : \n");
+      printk("%lx", pMFA_Outbound);
+    }
+  }
+  // printk(" DONE!\n");
+}
+
+/*
+ *
+ */
+static void SysTabSetCall(struct pti_st_host *hostp,
+			PI2O_EXEC_SYS_TAB_SET_MESSAGE MF,
+			void *lsgl)
+{
+  U8 tempMemPool[0x200];
+  int  count=0x200;
+  void *tlsgl = lsgl;
+  unsigned long pBaseAddrReg = (U32)hostp->maddr;
+  unsigned long pMFA_Inbound;
+  
+  PI2O_EXEC_STATUS_GET_REPLY ptReplyMemPool =
+    (PI2O_EXEC_STATUS_GET_REPLY)tempMemPool;
+  
+  PI2O_SGE_SIMPLE_ELEMENT ptsgl =
+    (PI2O_SGE_SIMPLE_ELEMENT)MF->SGL.u.Simple;
+
+  while(count--)
+     tempMemPool[count] = ((char*)tlsgl)[count];
+  
+  pMFA_Inbound = * (U32 *)(pBaseAddrReg+INBOUNDQPORT);
+
+  ZeroMemory((U32*) MF, sizeof(I2O_EXEC_SYS_TAB_SET_MESSAGE)+0x10);
+  ZeroMemory((U32*) lsgl, 0x200);
+  
+  MF->StdMessageFrame.VersionOffset=0x61;      // 32 bit frame
+  MF->StdMessageFrame.MsgFlags=0;
+  MF->StdMessageFrame.MessageSize=sizeof(I2O_EXEC_SYS_TAB_SET_MESSAGE) >> 2;
+  
+  MF->StdMessageFrame.TargetAddress=0;         // IXWork    
+  MF->StdMessageFrame.InitiatorAddress = 0x01; // from Host 
+  MF->StdMessageFrame.Function = I2O_EXEC_SYS_TAB_SET;
+
+  MF->IOP_ID = MY_IOP_ID;     //I2O_EXEC_SYS_TAB_IOP_ID_LOCAL_HOST;
+  MF->HostUnitID = I2O_EXEC_SYS_TAB_HOST_UNIT_ID_LOCAL_UNIT;
+  MF->SegmentNumber = I2O_EXEC_SYS_TAB_SEG_NUMBER_LOCAL_SEGMENT;
+  
+  MF->SGL.u.Simple[0].FlagsCount.Count=
+    CreatSysTable(hostp, lsgl, (PI2O_EXEC_STATUS_GET_REPLY)tempMemPool);
+
+  // 1st element: YBM: need I2O_SGL_FLAGS_END_OF_BUFFER ?
+  ptsgl->FlagsCount.Flags = (I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT | 
+                             I2O_SGL_FLAGS_END_OF_BUFFER) ;
+
+  MF->SGL.u.Simple[0].PhysicalAddress = (U32)(virt_to_bus(lsgl));
+  
+  // 2nd element: YBM: need I2O_SGL_FLAGS_END_OF_BUFFER ?
+  ptsgl++;                
+  ptsgl->FlagsCount.Flags = (I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT | 
+                             I2O_SGL_FLAGS_END_OF_BUFFER) ;
+  ptsgl->FlagsCount.Count = ptReplyMemPool->CurrentPrivateMemSize;
+  ptsgl->PhysicalAddress = ptReplyMemPool->CurrentPrivateMemBase;
+
+  // 3rd element:
+#if defined(MYDEBUG) && 0
+  MF->SGL.u.SimpleContext[0].FlagsCount.Count=
+		 ptReplyMemPool->CurrentPrivateIOSize;
+
+  MF->SGL.u.SimpleContext[0].FlagsCount.Flags =
+		(I2O_SGL_FLAGS_LAST_ELEMENT | 
+		 I2O_SGL_FLAGS_END_OF_BUFFER | 
+		 I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT);
+
+  MF->SGL.u.SimpleContext[0].PhysicalAddress = ptReplyMemPool->CurrentPrivateIOBase;
+#else
+  ptsgl++;
+  ptsgl->FlagsCount.Count=
+		 ptReplyMemPool->CurrentPrivateIOSize;
+
+  ptsgl->FlagsCount.Flags =
+		(I2O_SGL_FLAGS_LAST_ELEMENT | 
+		 I2O_SGL_FLAGS_END_OF_BUFFER | 
+		 I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT);
+
+  ptsgl->PhysicalAddress = ptReplyMemPool->CurrentPrivateIOBase;
+#endif
+
+  memcpy( (void *)(pMFA_Inbound+pBaseAddrReg), (void *)MF, 
+          (sizeof(I2O_EXEC_OUTBOUND_INIT_MESSAGE)+
+          (sizeof(I2O_SGE_SIMPLE_ELEMENT) * 2)) );
+  
+  * (U32 *)(pBaseAddrReg+INBOUNDQPORT) = pMFA_Inbound;
+
+}
+
+/*
+ *
+ */
+static void EnableSysCall(struct pti_st_host *hostp)
+{
+  U32 msgOffset;
+  PI2O_EXEC_SYS_ENABLE_MESSAGE pMsg;
+
+  msgOffset = hostp->p_atu->InQueue;
+
+  pMsg = (PI2O_EXEC_SYS_ENABLE_MESSAGE)(hostp->LinBaseAddr + msgOffset);
+
+  pMsg->StdMessageFrame.VersionOffset=0x1;  
+  pMsg->StdMessageFrame.MsgFlags=0;
+  pMsg->StdMessageFrame.MessageSize=sizeof(I2O_EXEC_SYS_ENABLE_MESSAGE) >> 2;
+  
+  pMsg->StdMessageFrame.TargetAddress=0;           // IXWork
+  pMsg->StdMessageFrame.InitiatorAddress = 0x01;   // from Host
+  pMsg->StdMessageFrame.Function = I2O_EXEC_SYS_ENABLE;
+
+  *(U32 *)(hostp->LinBaseAddr+INBOUNDQPORT) = msgOffset; // YBM: ... = pMFA_Inbound;
+}
+
+/*
+ *
+ */
+static void LCTNotifyCall(struct pti_st_host *hostp)
+{
+  U32 msgOffset;
+  PI2O_EXEC_LCT_NOTIFY_MESSAGE pMsg;
+  unsigned long pBaseAddrReg = (U32)hostp->maddr;
+
+  msgOffset = hostp->p_atu->InQueue;
+
+  pMsg = (PI2O_EXEC_LCT_NOTIFY_MESSAGE)(hostp->LinBaseAddr + msgOffset);
+  pMsg->StdMessageFrame.VersionOffset=0x61;  
+  pMsg->StdMessageFrame.MsgFlags=0;
+  pMsg->StdMessageFrame.MessageSize=sizeof(I2O_EXEC_LCT_NOTIFY_MESSAGE)>>2;
+  
+  pMsg->StdMessageFrame.TargetAddress=0;         // IXWork
+  pMsg->StdMessageFrame.InitiatorAddress = 0x01; // from Host
+  pMsg->StdMessageFrame.Function = I2O_EXEC_LCT_NOTIFY;
+  pMsg->ClassIdentifier = 0xffffffff;            // all class
+                                           // I2O_CLASS_RANDOM_BLOCK_STORAGE;
+  pMsg->LastReportedChangeIndicator = 0;
+  pMsg->SGL.u.Simple[0].FlagsCount.Count=0x1000;
+  pMsg->SGL.u.Simple[0].FlagsCount.Flags=(I2O_SGL_FLAGS_LAST_ELEMENT | 
+                                         I2O_SGL_FLAGS_END_OF_BUFFER | 
+                                         I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT);
+  pMsg->SGL.u.Simple[0].PhysicalAddress=virt_to_bus(hostp->replyBufferp);
+
+  * (U32 *)(pBaseAddrReg+INBOUNDQPORT) = msgOffset; // YBM: ... = pMFA_Inbound;
+}
+
+/*
+ *
+ */
+static U32 CreatSysTable(struct pti_st_host *hostp,
+				void *llsgl,
+				PI2O_EXEC_STATUS_GET_REPLY ltMemPool)
+{
+  PI2O_SET_SYSTAB_HEADER pPacket = (PI2O_SET_SYSTAB_HEADER) llsgl;
+  PI2O_IOP_ENTRY pEntry = (PI2O_IOP_ENTRY) ((U8 *) llsgl + sizeof(PI2O_SET_SYSTAB_HEADER));
+
+  pPacket->NumberEntries=0x1;
+  pPacket->SysTabVersion=I2O_RESOURCE_MANAGER_VERSION;
+  pPacket->CurrentChangeIndicator=0;
+
+  // pEntry->OrganizationID = ltMemPool->OrganizationID;
+  pEntry->OrganizationID = PROMISE_ORG_ID;
+  pEntry->IOP_ID = MY_IOP_ID;   //ltMemPool->IOP_ID;
+  pEntry->SegmentNumber = ltMemPool->SegmentNumber;
+  pEntry->I2oVersion = ltMemPool->I2oVersion;
+  pEntry->IopState = ltMemPool->IopState;
+  pEntry->MessengerType = ltMemPool->MessengerType;
+  pEntry->InboundMessageFrameSize = ltMemPool->InboundMFrameSize;
+  pEntry->LastChanged = 0;
+  pEntry->IopCapabilities = ltMemPool->IopCapabilities;
+  pEntry->MessengerInfo.InboundMessagePortAddressLow = (U32)hostp->maddr;
+  pEntry->MessengerInfo.InboundMessagePortAddressHigh = 0;
+
+  return sizeof(I2O_IOP_ENTRY)+sizeof(I2O_SET_SYSTAB_HEADER);  
+}
+
+
+/*****************************************************************************
+  I2O EXECUTIVE CLASS MESSAGE
+*****************************************************************************/
+
+/*
+ *
+ */
+static void ExecIOPReset(struct pti_st_host *hostp)
+{
+  U32 msgOffset;
+  U32 timeout;
+  PI2O_EXEC_IOP_RESET_MESSAGE pMsg;
+  volatile PU32 p32;
+  unsigned long pBaseAddrReg = (U32)hostp->maddr;
+
+  msgOffset = hostp->p_atu->InQueue;
+  
+  pMsg = (PI2O_EXEC_IOP_RESET_MESSAGE)(hostp->LinBaseAddr + msgOffset);
+  memset((void *)hostp->replyBufferp, 0, 16*1024);
+
+  pMsg->VersionOffset=0x01;  
+  pMsg->MsgFlags=0;
+  pMsg->MessageSize= sizeof(I2O_EXEC_IOP_RESET_MESSAGE) >> 2;
+  
+  pMsg->TargetAddress=0;              // IXWork   
+  pMsg->InitiatorAddress = 0x01;      // from Host
+  pMsg->Function = I2O_EXEC_IOP_RESET;
+
+  pMsg->StatusWordHighAddress = 0;
+  pMsg->StatusWordLowAddress = 
+    (U32)(virt_to_bus((void *)hostp->replyBufferp));
+
+  p32 = (volatile PU32)hostp->replyBufferp;
+
+  *(U32 *)(pBaseAddrReg+INBOUNDQPORT) = msgOffset;
+
+  /* wait for response: */
+  timeout = 1000000;
+  while(1)
+  {
+    int i;
+    for (i=0; i<1000; i++)      /* please don't hog the bus ! */
+      ;
+    if(p32[0] || p32[1])
+      break;
+    if (!timeout--)
+    {
+      printk("Timeout while Resetting IOP !\n");
+      return;
+    }
+  }
+}
+
+static void PTI_StringCutBlank(char * strBuffer, U32 strLength)
+{
+        U32 i = strLength - 2;
+
+        while (i >= 0 && strBuffer[i] == ' ')
+        {
+                strBuffer[i] = '\0';
+                i--;
+        }
+}
+
+/*
+ *
+ */
+static void GetInfoFromLCT(struct pti_st_host *hostp,
+				void *lMemPool,
+				PI2ODISK pmydisk,
+				unsigned int *diskcount)
+{
+  PI2O_LCT pTable = (PI2O_LCT)lMemPool;
+  PI2O_LCT_ENTRY pLCTEntry;
+  PI2O_LCT_ENTRY HeadpLCTEntry = pTable->LCTEntry;
+  U16 ParentID=0xffff;
+
+  int i;
+
+  *diskcount = 0;               // initial count
+  memset((void *)hostp->LctEntryTable, 0, (sizeof(I2O_LCT_ENTRY) * MAX_LCT_ENTRY));
+
+  while(pTable->TableSize==0)   // wait ready
+    ;
+  pLCTEntry=HeadpLCTEntry;
+  
+  /* get ISM: */
+  while (pLCTEntry->TableEntrySize==0x9) 
+  {
+    if(pLCTEntry->ClassID.Class==I2O_CLASS_DDM && 
+       pLCTEntry->SubClassInfo==I2O_SUBCLASS_ISM) 
+    {
+      ParentID=(U16) pLCTEntry->LocalTID;
+      break;
+    }
+    pLCTEntry++;
+  }
+
+  if (ParentID == 0xffff) 
+  {
+    printk("ISM DDM ID not found!\n");
+    return;
+  }
+
+  /* scan all ISM children first: */
+  pLCTEntry=HeadpLCTEntry;
+  i = 0;
+
+  while(pLCTEntry->TableEntrySize == 0x9) 
+  {  
+     /*
+      * Insert the LCT Entry to LCT Entry Description
+      */
+     memcpy((void*)&hostp->LctEntryTable[i],
+                           (void *)pLCTEntry,
+                           sizeof(I2O_LCT_ENTRY));
+
+    if((pLCTEntry->ClassID.Class==I2O_CLASS_RANDOM_BLOCK_STORAGE) &&
+       (pLCTEntry->ParentTID==ParentID))
+    {
+      pmydisk->LocalTID = (unsigned int) pLCTEntry->LocalTID;
+      pmydisk++;
+      (*diskcount)++;
+    }
+    pLCTEntry++;
+    i++;
+  }
+
+  /* if no ISM child: */
+  if(*diskcount == 0) 
+  { /* parent not exist */
+    pLCTEntry = HeadpLCTEntry;
+    while(pLCTEntry->TableEntrySize == 0x9) 
+    {
+      if(pLCTEntry->ClassID.Class==I2O_CLASS_RANDOM_BLOCK_STORAGE) 
+      {
+        pmydisk->LocalTID = (unsigned int) pLCTEntry->LocalTID;
+        pmydisk++;
+        (*diskcount)++;
+      }
+      pLCTEntry++;   
+    }
+  }
+
+}
+
+/*
+ * Starting lMemBuf = 0
+ *   0 ~ 3 bytes -- Request Header (0-1) Op Cnt (2-3) Res
+ *   4 ~ 9 bytes -- first operation list 
+ *   a ~10 bytes -- second operation list
+ *
+ * Result starts at lMemBuf+4+6+6
+ *   0 ~ 3 -- result header (0-1) Result Cnt
+ *   4 ~ n -- first result (first 4 byte, byte cnt in result+status)
+ */
+static int ComposeDiskInfo(struct pti_st_host *hostp,
+			   void *MF,
+			   void *lMemBuf,
+			   PI2ODISK pmydisk)
+{
+  PI2O_UTIL_DEVICE_IDENTITY_SCALAR pResult1;
+  PI2O_BSA_DEVICE_INFO_SCALAR pResult2;
+  PI2O_PARAM_READ_OPERATION_RESULT pOpResult;
+  PI2O_PARAM_RESULTS_LIST_HEADER pResHeader = 
+    (PI2O_PARAM_RESULTS_LIST_HEADER) (((U8 *) lMemBuf)+8+4);
+
+  void * ptMemBuf = lMemBuf;
+  PI2O_PARAM_OPERATION_ALL_TEMPLATE ptsgl =
+    (PI2O_PARAM_OPERATION_ALL_TEMPLATE) (((U8*) lMemBuf) + 4);
+
+  U32 wSize;
+  unsigned int Hd;
+  unsigned int Sctr = 0x3f;
+
+  /*
+   * Note:General and Specific parameter get must invoke separately
+   * General Parameter Get 
+   */
+  ZeroMemory(lMemBuf, 0x200);
+
+  *((unsigned int *) ptMemBuf) = 0x1;  
+  ptsgl->Operation = I2O_PARAMS_OPERATION_FIELD_GET;
+  ptsgl->GroupNumber = I2O_UTIL_DEVICE_IDENTITY_GROUP_NO;
+  ptsgl->FieldCount = 0xffff;
+
+  PTI_UtilParamGetCall(hostp,
+		   (PI2O_UTIL_PARAMS_GET_MESSAGE) MF, 
+                   (void *) ptMemBuf,
+                   (void *) (((U8 *) ptMemBuf)+0x4+0x8), 
+                   pmydisk);
+  if (pti_st_waitreplymsg(hostp) != I2O_REPLY_STATUS_SUCCESS)
+  {
+    printk("!BAD reply after sending UtilParamsGetMessage!\n");
+    return(FALSE);
+  }
+
+  pOpResult = (PI2O_PARAM_READ_OPERATION_RESULT) (++pResHeader);
+  if(pOpResult->ErrorInfoSize != 0)
+  {
+    return(FALSE); /* Error Action */
+  }
+  pResult1 = (PI2O_UTIL_DEVICE_IDENTITY_SCALAR) (++pOpResult);
+
+  memcpy( &(pmydisk->Vendor), &(pResult1->VendorInfo),
+          I2O_DEVID_VENDOR_INFO_SZ );
+
+  pmydisk->Vendor[I2O_DEVID_VENDOR_INFO_SZ] = (char) 0;
+
+  PTI_StringCutBlank(pmydisk->Vendor, I2O_DEVID_VENDOR_INFO_SZ);
+
+  memcpy( &(pmydisk->DiskModel), &(pResult1->ProductInfo),
+          I2O_DEVID_PRODUCT_INFO_SZ );
+
+  pmydisk->DiskModel[I2O_DEVID_PRODUCT_INFO_SZ] = (char) 0;
+  
+  PTI_StringCutBlank(pmydisk->DiskModel, I2O_DEVID_PRODUCT_INFO_SZ);
+
+  memcpy( &(pmydisk->ProductRevLevel), &(pResult1->ProductRevLevel),
+                        I2O_DEVID_REV_LEVEL_SZ );
+  pmydisk->ProductRevLevel[I2O_DEVID_REV_LEVEL_SZ] = '\0';
+
+  PTI_StringCutBlank(pmydisk->ProductRevLevel, I2O_DEVID_REV_LEVEL_SZ);
+
+  /*
+   * Device Information (Storage Parameter Get)  
+   */
+  ZeroMemory(lMemBuf, 0x200);
+  
+  *((unsigned int *) ptMemBuf) = 0x1;
+  
+  ptsgl->Operation = I2O_PARAMS_OPERATION_FIELD_GET;
+  ptsgl->GroupNumber = I2O_BSA_DEVICE_INFO_GROUP_NO;
+  ptsgl->FieldCount = 0xffff;
+  
+  PTI_UtilParamGetCall(hostp,
+		   (PI2O_UTIL_PARAMS_GET_MESSAGE) MF, 
+                   (void *) ptMemBuf,
+                   (void *) (((U8 *) ptMemBuf)+0x4+0x8), 
+                   pmydisk);
+  if (pti_st_waitreplymsg(hostp) != I2O_REPLY_STATUS_SUCCESS)
+  {
+    printk("!BAD reply after sending UtilParamsGetMessage!\n");
+    return(FALSE);
+  }
+
+  pResHeader=(PI2O_PARAM_RESULTS_LIST_HEADER) (((U8 *) lMemBuf)+8+4);  
+  pOpResult = (PI2O_PARAM_READ_OPERATION_RESULT) (++pResHeader);
+  if(pOpResult->ErrorInfoSize != 0) 
+  {
+    return(FALSE); // Error Action
+  }
+  pResult2 = (PI2O_BSA_DEVICE_INFO_SCALAR) (++pOpResult);
+
+  wSize = (long) ((pResult2->DeviceCapacity.HighPart << (32-9)) |
+                  (pResult2->DeviceCapacity.LowPart >> 9));
+  
+  pmydisk->lastLBA = (U32) wSize - 1;
+
+  // convert LBA to CHS
+  if(wSize <= (U32) 0x3f*0x10*0x400) 
+  {
+    Hd = 0x10;
+    while((wSize/(Hd*Sctr) > 0x400) && (Hd < 0x80)) 
+      Hd <<=1;
+  }
+  else if (wSize <= (U32) (0x3fl*0x20l*0x400l)) Hd = 0x20;
+    else if (wSize <= (U32) (0x3fl*0x40l*0x400l)) Hd = 0x40;
+      else if (wSize <= (U32) (0x3fl*0x80l*0x400l)) Hd = 0x80;
+        else Hd = 0xff;
+
+  pmydisk->lastcyl = (unsigned int) ((wSize/ (Hd*Sctr)) - 1);/*starting from 0*/
+  pmydisk->lasthead = (U8) (Hd - 1);  	 /*starting from 0*/
+  pmydisk->sector = (U8) Sctr;  	 /*starting from 0*/
+  
+  return(TRUE);
+}
+ 
+/*
+ * Function:    unsigned long pti_st_waitreplymsg(struct pti_st_host *)
+ * Description: wait reply message from i960. 
+ * Return :     Error code (0 represent I2O_REPLY_STATUS_SUCCESS)
+ */
+unsigned long pti_st_waitreplymsg(struct pti_st_host *hostp)
+{ 
+  U8  ReqStatus;
+  U32 timeout=0;
+  int i;
+  PI2O_SINGLE_REPLY_MESSAGE_FRAME replyPointer;
+  unsigned long pBaseAddrReg = (U32)hostp->maddr;
+  unsigned long pMFA_Outbound;
+  
+  // wait for response:
+  timeout = 0x1000000;
+  while(1)
+  {
+    for (i=0; i<1000; i++)      // please don't hog the bus!!!
+      ;    
+    if((pMFA_Outbound=(*(volatile U32 *)(pBaseAddrReg+OUTBOUNDQPORT)))!=-1)
+      break;
+            
+    if (!timeout--)
+    {
+      printk("Timeout wait for Reply Message from IOP!\n");
+      return -1;
+    }
+  }
+  
+  replyPointer=(PI2O_SINGLE_REPLY_MESSAGE_FRAME)(bus_to_virt(pMFA_Outbound));
+
+  ReqStatus = replyPointer->ReqStatus;
+
+  * (U32 *)(pBaseAddrReg+OUTBOUNDQPORT) = pMFA_Outbound;
+
+  return (unsigned long) ReqStatus;
+}
+
+
+/*****************************************************************************
+  I2O UTILITY CLASS MESSAGE
+*****************************************************************************/
+/*
+ * THis is used for ComposeDiskInfo()
+ */
+static void PTI_UtilParamGetCall(struct pti_st_host *hostp,
+			PI2O_UTIL_PARAMS_GET_MESSAGE MF,
+             		void     *req,
+               		void     *buf,
+               		PI2ODISK mydisk)
+{
+  PI2O_SGE_SIMPLE_ELEMENT sglentry = 
+    (PI2O_SGE_SIMPLE_ELEMENT)MF->SGL.u.Simple;      // YBM: )&MF->SGL.u.Simple;
+  unsigned long pBaseAddrReg = (U32)hostp->maddr;
+  unsigned long pMFA_Inbound = * (U32 *)(pBaseAddrReg+INBOUNDQPORT);
+
+  ZeroMemory((U32*) MF, sizeof(I2O_UTIL_PARAMS_GET_MESSAGE)+0x10);
+  
+  MF->StdMessageFrame.VersionOffset=0x51;  
+  MF->StdMessageFrame.MsgFlags=0;
+  MF->StdMessageFrame.MessageSize= 
+    (sizeof(I2O_UTIL_PARAMS_GET_MESSAGE)+sizeof(I2O_SG_ELEMENT)) >> 2;
+  
+  MF->StdMessageFrame.TargetAddress=mydisk->LocalTID; 
+  MF->StdMessageFrame.InitiatorAddress = 0x01;      // from Host
+  MF->StdMessageFrame.Function = I2O_UTIL_PARAMS_GET;
+
+  MF->OperationFlags = 0; // reserved
+
+  // First buffer:
+  sglentry->FlagsCount.Flags = (I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT |
+                                I2O_SGL_FLAGS_END_OF_BUFFER );
+  sglentry->FlagsCount.Count = 0x0c ;
+  sglentry->PhysicalAddress = (U32)(virt_to_bus(req)); // YBM: *(U32 *)req ;
+
+  // Sencond buffer:
+  sglentry++;
+  sglentry->FlagsCount.Flags = (I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT |
+                                I2O_SGL_FLAGS_LAST_ELEMENT |
+                                I2O_SGL_FLAGS_END_OF_BUFFER );
+  sglentry->FlagsCount.Count = 0x100; 
+  //sizeof(I2O_UTIL_DEVICE_IDENTITY_SCALAR);
+  sglentry->PhysicalAddress = (U32)(virt_to_bus(buf)); // YBM: *(U32 *)buf;
+  
+  memcpy( (void *)(pMFA_Inbound+pBaseAddrReg), (void *)MF, 
+          (sizeof(I2O_UTIL_PARAMS_GET_MESSAGE)+16) );
+
+  * (U32 *)(pBaseAddrReg+INBOUNDQPORT) = pMFA_Inbound;
+}
+
+
+/*
+ * This is used for pti_stdev_ioctl()
+ *
+ * Routine Description:
+ *
+ *	message allows parameter values to be retrieved from
+ *	device parameter groups.
+ */
+static void PTI_UtilParamsGet(
+	struct pti_st_host *hostp,
+	ULONG LocalTID,
+	ULONG FieldCount,
+	UCHAR SrbTag,
+	ULONG SrbID,
+	UCHAR *Address
+)
+{
+	PI2O_UTIL_PARAMS_GET_MESSAGE MsgPtr;
+	PI2O_SGE_SIMPLE_ELEMENT SGLPtr;
+	ULONG msgOffset;
+	ULONG ParamOffset = 0;
+
+
+	msgOffset = hostp->p_atu->InQueue;
+	MsgPtr = (PI2O_UTIL_PARAMS_GET_MESSAGE)(hostp->LinBaseAddr+msgOffset);
+	memset((ULONG *)MsgPtr,0,sizeof(I2O_UTIL_PARAMS_GET_MESSAGE)+0x10);
+	SGLPtr = (PI2O_SGE_SIMPLE_ELEMENT)MsgPtr->SGL.u.Simple;
+
+	ParamOffset = sizeof(I2O_PARAM_SCALAR_OPERATION);
+	if (FieldCount != (USHORT)-1)	
+		ParamOffset = ParamOffset + (FieldCount-1)*sizeof(USHORT);
+
+	/*
+	 * fill the message frame
+	 */
+	MsgPtr->StdMessageFrame.VersionOffset = 0x51;
+	MsgPtr->StdMessageFrame.MsgFlags = 0;
+	MsgPtr->StdMessageFrame.MessageSize =
+			(sizeof(I2O_UTIL_PARAMS_GET_MESSAGE)+sizeof(I2O_SG_ELEMENT)) >> 2;
+	MsgPtr->StdMessageFrame.TargetAddress = LocalTID;
+	MsgPtr->StdMessageFrame.InitiatorAddress = 0x01;	/* from Host */
+	MsgPtr->StdMessageFrame.Function = I2O_UTIL_PARAMS_GET;
+	MsgPtr->StdMessageFrame.InitiatorContext = SrbTag;
+	
+	MsgPtr->TransactionContext = SrbID;
+	MsgPtr->OperationFlags = 0;		/* reserved */
+
+	/*
+	 * fill the SGL frame
+	 * the first buffer contains the operation list that
+	 * identifies which parameters are to be returned
+	 */
+	SGLPtr->FlagsCount.Flags = (I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT |
+                                I2O_SGL_FLAGS_END_OF_BUFFER );
+	SGLPtr->FlagsCount.Count = ParamOffset;
+	SGLPtr->PhysicalAddress =  cpu_to_le32(VIRT_TO_BUS(Address));
+
+	/* the second buffer is for target to place the results */
+	SGLPtr++;
+	SGLPtr->FlagsCount.Flags = (I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT |
+                                I2O_SGL_FLAGS_LAST_ELEMENT |
+                                I2O_SGL_FLAGS_END_OF_BUFFER );
+	SGLPtr->FlagsCount.Count = 0x100;
+	SGLPtr->PhysicalAddress = cpu_to_le32(VIRT_TO_BUS(Address+ParamOffset));
+	
+	/*
+	 * send the message
+	 */
+	hostp->p_atu->InQueue = msgOffset;
+}
+
+
+/*
+ *
+ */
+static void UtilNOPCall(struct pti_st_host *hostp)
+{
+  U32 msgOffset;
+  PI2O_UTIL_NOP_MESSAGE pMsg;
+
+  msgOffset = hostp->p_atu->InQueue;
+
+  pMsg = (PI2O_UTIL_NOP_MESSAGE)(hostp->LinBaseAddr + msgOffset);
+  pMsg->StdMessageFrame.VersionOffset=0x1;  
+  pMsg->StdMessageFrame.MsgFlags=0;
+  pMsg->StdMessageFrame.MessageSize= sizeof(I2O_UTIL_NOP_MESSAGE) >> 2;
+  pMsg->StdMessageFrame.TargetAddress=0; 
+  pMsg->StdMessageFrame.InitiatorAddress = 0x1;     // from Host
+  pMsg->StdMessageFrame.Function = I2O_UTIL_NOP;
+
+  hostp->p_atu->InQueue = msgOffset;
+  
+}
+
+/********************************************************************
+ *
+ *	Private Messages
+ *
+ ********************************************************************/
+
+static void PTI_PrivateMessageCall(
+	struct pti_st_host *hostp,
+	ULONG TargetTID,
+	U16 XFunctionCode,
+	U16 OrganizationID,
+	ULONG InputCount,
+	UCHAR *InputAddr,
+	ULONG OutputCount,
+	UCHAR *OutputAddr,
+	UCHAR SrbTag,
+	ULONG SrbID
+)
+{
+	PPTI_ST_PRIVATE_MESSAGE MsgPtr;
+	unsigned long msgOffset;
+
+	msgOffset = hostp->p_atu->InQueue;
+	MsgPtr = (PPTI_ST_PRIVATE_MESSAGE)(hostp->LinBaseAddr+msgOffset);
+	memset((UCHAR *)MsgPtr,0,sizeof(PTI_ST_PRIVATE_MESSAGE)+0x10);
+
+	/*
+	 * Fill the message frame
+	 */
+	MsgPtr->MyStandMsg.StdMessageFrame.VersionOffset = 0x1;  
+	MsgPtr->MyStandMsg.StdMessageFrame.MsgFlags = 0;
+	MsgPtr->MyStandMsg.StdMessageFrame.MessageSize = (sizeof(PTI_ST_PRIVATE_MESSAGE) >> 2);
+	
+	MsgPtr->MyStandMsg.StdMessageFrame.TargetAddress = TargetTID; /* IXWork */
+	MsgPtr->MyStandMsg.StdMessageFrame.InitiatorAddress = 0x01; 
+	MsgPtr->MyStandMsg.StdMessageFrame.Function = I2O_PRIVATE_MESSAGE;
+	MsgPtr->MyStandMsg.StdMessageFrame.InitiatorContext = SrbTag;
+
+	MsgPtr->MyStandMsg.XFunctionCode = (U16)(((XFunctionCode >> 8) & 0x00ff) | ((XFunctionCode << 8) & 0xff00));
+	
+	MsgPtr->MyStandMsg.OrganizationID = (U16)(((OrganizationID >> 8) & 0x00ff) | ((OrganizationID << 8) & 0xff00));
+	
+	MsgPtr->MyStandMsg.TransactionContext = SrbID;
+	/*
+	 * Fill the private Payload
+	 */
+	MsgPtr->InSGL.FlagsCount.Count = InputCount;
+	MsgPtr->InSGL.FlagsCount.Flags = I2O_SGL_FLAGS_PAGE_LIST_ADDRESS_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER;
+	MsgPtr->InSGL.PhysicalAddress[0] = 
+				cpu_to_le32(VIRT_TO_BUS(InputAddr));
+	
+	MsgPtr->OutSGL.FlagsCount.Count = OutputCount;
+	MsgPtr->OutSGL.FlagsCount.Flags = I2O_SGL_FLAGS_PAGE_LIST_ADDRESS_ELEMENT | I2O_SGL_FLAGS_LAST_ELEMENT | I2O_SGL_FLAGS_END_OF_BUFFER;
+	MsgPtr->OutSGL.PhysicalAddress[0] =
+				cpu_to_le32(VIRT_TO_BUS(OutputAddr));
+
+	/*
+	 * send the message
+	 */
+	hostp->p_atu->InQueue = msgOffset;
+}
+	
+
+/****************************************************************************
+    Misc functions.
+****************************************************************************/
+/*
+ *
+ */
+static void ZeroMemory(unsigned long  *zeroBuffer, unsigned int count)
+{
+  count = count >> 2;     // count/4
+  while(count--)
+  {
+    * zeroBuffer = 0;
+    zeroBuffer ++;
+  }  
+}
+
+/************************************************************
+ *          Device File Function                            *
+ ************************************************************/
+
+static int pti_stdev_strncmp(char *s, char *d, int n) 
+{
+	/* check null */
+	if(!s) {
+		if(!d)
+			return(0);
+		else
+			return(-1);
+	} else {
+		if(!d)
+			return(1);
+	}
+	/* both not null */ 
+
+	/* check length 0 */
+	if(!s[0]) {
+		if(!d[0])
+			return(0);
+		else
+			return(-1);
+	} else {
+		if(!d[0])
+			return(-1);
+	}
+
+	/* both length not 0 */
+
+	return(strncmp(s,d,n));
+}
+
+/*
+ *
+ */
+int pti_stdev_open(struct inode *inodep, struct file *filep)
+{
+	int aptno = MINOR(inodep->i_rdev);
+#if defined(__SMP__)
+	struct pti_st_host *p = pti_st_hostp[aptno];
+#endif
+
+	if(!pti_st_hostp[aptno] || 
+	   pti_st_hostp[aptno]->major <= 0 ||
+	   pti_st_hostp[aptno]->major != MAJOR(inodep->i_rdev))
+		return(-ENODEV);
+
+	DRIVER_LOCK
+	if(pti_st_hostp[aptno]->counter != 0) {
+		DRIVER_UNLOCK
+		return(-EBUSY);
+	}
+	pti_st_hostp[aptno]->counter++;
+	DRIVER_UNLOCK
+	
+#ifdef MODULE
+	MOD_INC_USE_COUNT; 
+#endif
+	return(0);
+}
+
+int pti_stdev_release(struct inode *inodep, struct file *filep)
+{
+	int aptno = MINOR(inodep->i_rdev);
+#if defined(__SMP__)
+	struct pti_st_host *p = pti_st_hostp[aptno];
+#endif
+
+	if(!pti_st_hostp[aptno] ||
+	   pti_st_hostp[aptno]->major <= 0 ||
+	   pti_st_hostp[aptno]->major != MAJOR(inodep->i_rdev))
+		return(-ENODEV);
+
+	DRIVER_LOCK
+	if(pti_st_hostp[aptno]->counter <= 0) {
+		DRIVER_UNLOCK
+		return(-EBADF);
+	}
+	pti_st_hostp[aptno]->counter = 0;
+
+	DRIVER_UNLOCK
+
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+	return(0);
+}
+
+int pti_stdev_ioctl(struct inode *inodep,
+		struct file *filep,
+		unsigned int req,
+		unsigned long arg)
+{
+	SRB_IO_CONTROL *usr_srbp = (SRB_IO_CONTROL *)arg;
+	PTI_STDEV_GET_CONFIG_BUFFER *usr_confbufp =
+			(PTI_STDEV_GET_CONFIG_BUFFER *)arg;
+	PTI_STDEV_INBUFFER *usr_inbufp = (PTI_STDEV_INBUFFER *)arg;
+
+	SRB_IO_CONTROL *srbp = NULL;
+	PTI_STDEV_GET_CONFIG_BUFFER *confbufp = NULL;
+	PTI_STDEV_INBUFFER *inbufp = NULL;
+
+	PI2O_CONFIG_QUERY ConfigQuyPtr = NULL;
+	PI2O_DEVICE_DESCRIPTOR DevDescriptorPtr = NULL;
+	PI2O_PARAM_SCALAR_OPERATION ParamScalarPtr = NULL;
+	USHORT 	*TargetTIDp = NULL;
+	USHORT	*OrganizationIDp = NULL;
+	USHORT	*XFunctionCodep = NULL;
+	UCHAR	*InputAddr = NULL;
+	UCHAR	*OutputAddr = NULL;
+	
+	void *bufferp = NULL;
+	unsigned long offset;
+	unsigned long ret;
+	int i, retval;
+	int aptno = MINOR(inodep->i_rdev);
+	struct pti_st_host *p = pti_st_hostp[aptno];
+
+	if(!pti_st_hostp[aptno] ||
+	   pti_st_hostp[aptno]->major <= 0 ||
+	   pti_st_hostp[aptno]->major != MAJOR(inodep->i_rdev))
+		return(-ENODEV);
+
+	if(pti_st_hostp[aptno]->counter <= 0) {
+		return(-EIO);
+	}
+
+	bufferp = pti_st_hostp[aptno]->pti_stdev_bufferp;
+	memset(bufferp, 0, sizeof(PTI_STDEV_INBUFFER));
+
+	srbp = (SRB_IO_CONTROL *)bufferp;
+
+	switch (req) {
+	case IOCTL_SUPERTRAK_GETVERSION:
+		ret = copy_from_user(srbp,
+				usr_srbp,
+				sizeof(SRB_IO_CONTROL));
+		if(ret)
+			return(-EFAULT);
+		break;
+
+	case IOCTL_GET_CONFIG_INFO:
+		confbufp = (PTI_STDEV_GET_CONFIG_BUFFER *)bufferp;
+
+		ret = copy_from_user(confbufp,
+				usr_confbufp,
+				sizeof(PTI_STDEV_GET_CONFIG_BUFFER));
+		if(ret)
+			return(-EFAULT);
+
+		break;
+
+	case IOCTL_PRIVATE_MESSAGE_CODE:
+	case IOCTL_PARAMS_GET_REQUEST:
+		inbufp = (PTI_STDEV_INBUFFER *)bufferp;
+
+		ret = copy_from_user(inbufp,
+				usr_inbufp,
+				sizeof(PTI_STDEV_INBUFFER));
+		if(ret)
+			return(-EFAULT);
+
+		break;
+
+	default:
+		return(-EINVAL);
+	}
+
+	if(pti_stdev_strncmp(srbp->Signature, SUPERTRAK_SIGNATURE, SUPERTRAK_SIG_LEN))
+		return(-EINVAL);
+
+	switch (req) {
+	case IOCTL_SUPERTRAK_GETVERSION:
+		srbp->ControlCode = (VERSIONHI | (VERSIONLO << 16));
+		ret = copy_to_user(usr_srbp,
+				srbp,
+				sizeof(SRB_IO_CONTROL));
+		if(ret)
+			return(-EINVAL);
+		else
+			return(0);
+
+	case IOCTL_GET_CONFIG_INFO:
+		ConfigQuyPtr = (PI2O_CONFIG_QUERY)((UCHAR *)confbufp+sizeof(SRB_IO_CONTROL));
+		DevDescriptorPtr = (PI2O_DEVICE_DESCRIPTOR)((UCHAR *)confbufp+
+					+ sizeof(SRB_IO_CONTROL)
+					+ sizeof(I2O_CONFIG_QUERY));
+
+                /*
+                 * fill the I2O_DEVICE_DESCRIPTOR structure
+                 */
+
+                i = 0;
+		while(pti_st_hostp[aptno]->LctEntryTable[i].TableEntrySize == 0x09)
+		{
+                     if (pti_st_hostp[aptno]->LctEntryTable[i].ClassID.Class==ConfigQuyPtr->ClassID.Class &&
+                         pti_st_hostp[aptno]->LctEntryTable[i].SubClassInfo==ConfigQuyPtr->SubClassID)
+                     {
+                             /*
+                              * fill the LCT structure
+                              */
+                             memcpy((void*)&DevDescriptorPtr->LCT,
+                                    (void*)&pti_st_hostp[aptno]->LctEntryTable[i],
+                                    sizeof(I2O_LCT_ENTRY));
+                                        break;
+                     }
+                     else
+                           i++;
+		}
+
+                /*
+                 * Get IOP Description
+                 */
+                DevDescriptorPtr->IOP.IOPNumber = ConfigQuyPtr->IOPNumber;
+                DevDescriptorPtr->IOP.IOPCapabilities = pti_st_hostp[aptno]->IopStatus.IopCapabilities;
+                DevDescriptorPtr->IOP.IOPState = pti_st_hostp[aptno]->IopStatus.IopState;
+                DevDescriptorPtr->IOP.I2OVersion = pti_st_hostp[aptno]->IopStatus.I2oVersion;
+                DevDescriptorPtr->IOP.MessengerType = pti_st_hostp[aptno]->IopStatus.MessengerType;
+                DevDescriptorPtr->IOP.MaxMessageFrameSize = pti_st_hostp[aptno]->IopStatus.InboundMFrameSize;
+                DevDescriptorPtr->IOP.ExpectedLCTSize = pti_st_hostp[aptno]->IopStatus.ExpectedLCTSize;
+                DevDescriptorPtr->IOP.MaxInboundMFrames = pti_st_hostp[aptno]->IopStatus.MaxInboundMFrames;
+                DevDescriptorPtr->IOP.InitialInboundMFrames = pti_st_hostp[aptno]->IopStatus.CurrentInboundMFrames;
+                DevDescriptorPtr->IOP.Reserved = pti_st_hostp[aptno]->IopStatus.reserved;
+
+		ret = copy_to_user(usr_confbufp,
+				confbufp,
+				sizeof(PTI_STDEV_GET_CONFIG_BUFFER));
+		if(ret)
+			return(-EINVAL);
+		else
+			return(0);
+
+	case IOCTL_PRIVATE_MESSAGE_CODE:
+		/*
+		 * read the TargetTID, OrganizationID and XFunctionCode
+		 */
+		offset = sizeof(SRB_IO_CONTROL) + sizeof(ULONG);
+		TargetTIDp = (USHORT *)((UCHAR *)inbufp + offset);
+
+		offset += sizeof(USHORT);
+		OrganizationIDp = (USHORT *) ((UCHAR *)inbufp + offset);
+
+		offset += sizeof(USHORT);
+		XFunctionCodep = (USHORT *) ((UCHAR *)inbufp + offset);
+
+		offset += sizeof(USHORT);
+		InputAddr = (UCHAR *)inbufp + offset;
+		OutputAddr = InputAddr + 0x800;
+
+		/*
+		 * Send Private Message
+		 */
+
+
+		for(ret = 0; ret < 5; ret++) 
+		{
+			for(i = 0; i < p->scb_data->maxscbs; i++)
+        			if(p->scb_data->scb_array[i]->flags&SCB_ACTIVE)
+					break;
+			if(i >= p->scb_data->maxscbs) { /* card is idel */
+				DRIVER_LOCK
+				break;
+			}
+		}
+
+		if(ret >= 5) {	/* the cards is busy */
+			return(-EIO);
+		}
+
+		/*
+		 * Disable interrupt
+		 */
+		pti_st_hostp[aptno]->p_atu->OutIntMask = 0x000000fc;
+
+		PTI_PrivateMessageCall(pti_st_hostp[aptno],
+					*TargetTIDp,
+					*XFunctionCodep,
+					*OrganizationIDp, 
+					0x800, InputAddr,
+					0x800, OutputAddr,
+					-1,
+					-1);
+		if (pti_st_waitreplymsg(pti_st_hostp[aptno])
+						!= I2O_REPLY_STATUS_SUCCESS)
+		{
+			printk("!BAD reply after sending UtilParamsGetMessage!\n");
+			retval = -EIO;
+		}
+		else
+			retval = 0;
+
+		/* 
+		 * Enable interrupt
+		 */
+		pti_st_hostp[aptno]->p_atu->OutIntMask = 0x00000000;
+
+		DRIVER_UNLOCK
+
+		if(retval == 0) {
+			ret = copy_to_user(usr_inbufp, 
+					inbufp,
+					sizeof(PTI_STDEV_INBUFFER));
+			if(ret)
+				return(-EINVAL);
+			else
+				return(0);
+		} else {
+			return(retval);
+		}
+
+	case IOCTL_PARAMS_GET_REQUEST:
+		offset = sizeof(SRB_IO_CONTROL) + sizeof(ULONG);
+		TargetTIDp = (USHORT *)((UCHAR *)inbufp + offset);
+
+		offset += sizeof(USHORT);
+		ParamScalarPtr = (PI2O_PARAM_SCALAR_OPERATION)((UCHAR *)inbufp + offset);
+			
+		InputAddr = (UCHAR *)((UCHAR *)inbufp + offset);
+
+		for(ret = 0; ret < 5; ret++) 
+		{
+			for(i = 0; i < p->scb_data->maxscbs; i++)
+        			if(p->scb_data->scb_array[i]->flags&SCB_ACTIVE)
+					break;
+			if(i >= p->scb_data->maxscbs) { /* card is idel */
+				DRIVER_LOCK
+				break;
+			}
+		}
+
+		if(ret >= 5) {	/* the cards is busy */
+			return(-EIO);
+		}
+
+		DRIVER_LOCK
+
+		/*
+		 * Disable interrupt
+		 */
+		pti_st_hostp[aptno]->p_atu->OutIntMask = 0x000000fc;
+
+		PTI_UtilParamsGet(pti_st_hostp[aptno],
+				*TargetTIDp,
+				ParamScalarPtr->OpBlock.FieldCount,
+				-1,
+				-1,
+				InputAddr);
+		if (pti_st_waitreplymsg(pti_st_hostp[aptno])
+						!= I2O_REPLY_STATUS_SUCCESS)
+		{
+			printk("!BAD reply after sending UtilParamsGetMessage!\n");
+			retval = -EIO;
+		}
+		else
+			retval = 0;
+
+		/* 
+		 * Enable interrupt
+		 */
+		pti_st_hostp[aptno]->p_atu->OutIntMask = 0x00000000;
+
+		DRIVER_UNLOCK
+
+		if(retval == 0) {
+			ret = copy_to_user(usr_inbufp, 
+					inbufp,
+					sizeof(PTI_STDEV_INBUFFER));
+			if(ret)
+				return(-EINVAL);
+			else
+				return(0);
+		} else {
+			return(retval);
+		}
+
+	}
+	return(0);
+}
+
+// #ifdef MODULE
+
+/*
+ * Support for loading low-level scsi drivers using the linux kernel loadable
+ * module interface.
+ *
+ * To use, the host adapter should first define and initialize the variable
+ * driver_template (datatype Scsi_Host_Template), and then include this file.
+ * This should also be wrapped in a #ifdef MODULE/#endif.
+ *
+ * The low -level driver must also define a release function which will
+ * free any irq assignments, release any dma channels, release any I/O
+ * address space that might be reserved, and otherwise clean up after itself.
+ * The idea is that the same driver should be able to be reloaded without
+ * any difficulty.  This makes debugging new drivers easier, as you should
+ * be able to load the driver, test it, unload, modify and reload.
+ *
+ * One *very* important caveat.  If the driver may need to do DMA on the
+ * ISA bus, you must have unchecked_isa_dma set in the device template,
+ * even if this might be changed during the detect routine.  This is
+ * because the shpnt structure will be allocated in a special way so that
+ * it will be below the appropriate DMA limit - thus if your driver uses
+ * the hostdata field of shpnt, and the board must be able to access this
+ * via DMA, the shpnt structure must be in a DMA accessible region of
+ * memory.  This comment would be relevant for something like the buslogic
+ * driver where there are many boards, only some of which do DMA onto the
+ * ISA bus.  There is no convenient way of specifying whether the host
+ * needs to be in a ISA DMA accessible region of memory when you call
+ * scsi_register.
+ */
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0)	/*  > 2.4.0 */
+
+static Scsi_Host_Template pti_st_driver_template = PTI_ST;
+
+static int __init init_pti_st(void)
+{
+	int major, i;
+// Ideally, we should change this from the example THIS_MODULE to a unique 
+// name
+	pti_st_driver_template.module = THIS_MODULE;
+
+	scsi_register_module(MODULE_SCSI_HA, &pti_st_driver_template);
+
+  	if (!pti_st_driver_template.present ||
+      		(major = register_blkdev(0, PTCNTL_DEV_NAME, (struct block_device_operations *)&pti_stdev_fops)) < 0)
+  	{
+ 	   if(pti_st_driver_template.present)
+    		scsi_unregister_module(MODULE_SCSI_HA, &pti_st_driver_template);
+	   return(-ENODEV);
+  	}
+
+	for(i = 0; i < MAX_ADAPTORS; i++)
+	{
+		if(pti_st_hostp[i])
+		{
+  			pti_st_hostp[i]->counter = 0;
+  			pti_st_hostp[i]->major = major;
+		}
+  	}
+
+	return (0);
+
+}
+
+static void __exit exit_pti_st(void)
+{
+  int i;
+
+  for(i = 0; i < MAX_ADAPTORS; i++)
+	if(pti_st_hostp[i])
+		break;
+
+  if(i < MAX_ADAPTORS) {
+	if(pti_st_hostp[i]->major > 0)
+  		unregister_blkdev(pti_st_hostp[i]->major,PTCNTL_DEV_NAME);
+	if(pti_st_hostp[i]) {
+		scsi_unregister_module(MODULE_SCSI_HA, &pti_st_driver_template);
+	}
+  }
+	
+}
+
+module_init(init_pti_st);
+module_exit(exit_pti_st);
+
+#else /* > 2.4.0 */
+
+Scsi_Host_Template pti_st_driver_template = PTI_ST;
+
+int init_module(void) 
+{
+  int major, i;
+  pti_st_driver_template.module = &__this_module;
+  scsi_register_module(MODULE_SCSI_HA, &pti_st_driver_template);
+
+  if (!pti_st_driver_template.present ||
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+      (major = register_blkdev(0, PTCNTL_DEV_NAME, (struct file_operations *)&pti_stdev_fops)) < 0)
+#else
+      (major = register_blkdev(0, PTCNTL_DEV_NAME, (struct block_device_operations *)&pti_stdev_fops)) < 0)
+#endif
+  {
+    if(pti_st_driver_template.present)
+    	scsi_unregister_module(MODULE_SCSI_HA, &pti_st_driver_template);
+    return -1;
+  }
+
+  for(i = 0; i < MAX_ADAPTORS; i++)
+  {
+	if(pti_st_hostp[i])
+	{
+  		pti_st_hostp[i]->counter = 0;
+  		pti_st_hostp[i]->major = major;
+	}
+  }
+
+  return (0);
+}
+
+void cleanup_module(void) 
+{
+  int i;
+
+  for(i = 0; i < MAX_ADAPTORS; i++)
+	if(pti_st_hostp[i])
+		break;
+
+  if(i < MAX_ADAPTORS) {
+	if(pti_st_hostp[i]->major > 0)
+  		unregister_blkdev(pti_st_hostp[i]->major,PTCNTL_DEV_NAME);
+	if(pti_st_hostp[i]) {
+  		scsi_unregister_module(MODULE_SCSI_HA, &pti_st_driver_template);
+	}
+  }
+	
+}
+
+#endif /* > 2.4.0 */
+
+// #endif /* MODULE */
diff -ruN linux-2.4.20-orig/drivers/scsi/pti_st.h linux-2.4.20/drivers/scsi/pti_st.h
--- linux-2.4.20-orig/drivers/scsi/pti_st.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.4.20/drivers/scsi/pti_st.h	2003-01-21 21:29:04.000000000 -0500
@@ -0,0 +1,577 @@
+/*+M*************************************************************************
+ * Promise SuperTrak device driver for Linux.
+ *
+ * Copyright (c) 2001  Promise Technology, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * --------------------------------------------------------------------------  
+ * Copyright (c) 1999-2001 Promise Technology, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *   		$Id: pti_st.c,v 1.1 2001/06/27 15:37:18 Jack Hu 	$
+ *-M*************************************************************************/
+
+/**************************************************************************
+ * File: pti_st.h       Driver Declaraitons for pti_st.c. 
+ **************************************************************************/
+
+#if 0
+#include "i2omstor.h"
+#include "i2oexec.h"
+#else
+#include "i2odef.h"
+#endif
+
+#ifndef _pti_st_h
+#define _pti_st_h
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+//#ifndef KERNEL_VERSION
+//#define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z))
+//#endif
+
+/* INQUIRY data format */
+typedef struct 
+{
+  unchar  type_qual;
+  unchar  modif_rmb;
+  unchar  version;
+  unchar  resp_aenc;
+  unchar  add_length;
+  unchar  reserved1;
+  unchar  reserved2;
+  unchar  misc;
+  unchar  vendor[8];
+  unchar  product[16];
+  unchar  revision[4];
+}pti_inq_data;
+
+/* READ_CAPACITY data format */
+typedef struct 
+{
+  u32  last_block_no;
+  u32  block_length;
+}pti_rdcap_data;
+
+/* REQUEST_SENSE data format */
+typedef struct 
+{
+  unchar  errorcode;
+  unchar  segno;
+  unchar  key;
+  u32     info;
+  unchar  add_length;
+  u32     cmd_info;
+  unchar  adsc;
+  unchar  adsq;
+  unchar  fruc;
+  unchar  key_spec[3];
+}pti_sense_data;
+
+/* MODE_SENSE data format */
+typedef struct 
+{
+  struct 
+  {
+    unchar  data_length;
+    unchar  med_type;
+    unchar  dev_par;
+    unchar  bd_length;
+  }hd;
+  struct 
+  {
+    unchar  dens_code;
+    unchar  block_count[3];
+    unchar  reserved;
+    unchar  block_length[3];
+  }bd;
+}pti_modep_data;
+
+extern int PTI_procfile_read(char *, char **, off_t, int, int, int);
+extern const char *PTI_ST_info(struct Scsi_Host *);
+extern int pti_st_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+extern int pti_st_biosparam(Disk *, kdev_t, int[]);
+extern int pti_st_detect(Scsi_Host_Template *);
+extern int pti_st_reset(Scsi_Cmnd *, unsigned int);
+extern int pti_st_abort(Scsi_Cmnd *);
+
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,65)
+#define PTI_ST {                                                  \
+    next: NULL,                                                   \
+    module: NULL,                                                 \
+    proc_dir: NULL,                                               \
+    proc_info: PTI_procfile_read,                                 \
+    name: NULL,                                                   \
+    detect: pti_st_detect,                                        \
+    release: pti_st_release,                                      \
+    info: PTI_ST_info,                                            \
+    command: NULL,                                                \
+    queuecommand: pti_st_queue,                                   \
+    eh_strategy_handler: NULL,                                    \
+    eh_abort_handler: NULL,                                       \
+    eh_device_reset_handler: NULL,                                \
+    eh_bus_reset_handler: NULL,                                   \
+    eh_host_reset_handler: NULL,                                  \
+    abort: pti_st_abort,                                          \
+    reset: pti_st_reset,                                          \
+    slave_attach: NULL,                                           \
+    bios_param: pti_st_biosparam,                                 \
+    can_queue: 32,                                                \
+    this_id: -1,                                                  \
+    sg_tablesize: 0,                                              \
+    cmd_per_lun: 3,                                               \
+    present: 0,                                                   \
+    unchecked_isa_dma: 0,                                         \
+    use_clustering: ENABLE_CLUSTERING,                            \
+    use_new_eh_code: 0                                            \
+}
+#else
+#define PTI_ST  {                                                 \
+    next: NULL,                                                   \
+    usage_count: NULL,                                            \
+    proc_dir: NULL,                                               \
+    proc_info: PTI_procfile_read,                                 \
+    name: NULL,                                                   \
+    detect: pti_st_detect,                                        \
+    release: pti_st_release,                                      \
+    info: PTI_ST_info,                                            \
+    command: NULL,                                                \
+    queuecommand: pti_st_queue,                                   \
+    abort: pti_st_abort,                                          \
+    reset: pti_st_reset,                                          \
+    slave_attach: NULL,                                           \
+    bios_param: pti_st_biosparam,                                 \
+    can_queue: 32,               /* max simultaneous cmds      */ \
+    this_id: -1,                 /* scsi id of host adapter    */ \
+    sg_tablesize: 0,             /* max scatter-gather cmds    */ \
+    cmd_per_lun: 3,              /* cmds per lun (linked cmds) */ \
+    present: 0,                  /* number of 7xxx's present   */ \
+    unchecked_isa_dma: 0,        /* no memory DMA restrictions */ \
+    use_clustering: ENABLE_CLUSTERING                             \
+}
+#endif
+
+
+#ifdef  NULL
+#undef  NULL
+#endif
+#define NULL ((void *) 0)
+ 
+#define DEBUG (FALSE)
+
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define ABSDIFF(x, y) (((x) > (y)) ? ((x) - (y)) : ((y) - (x)))
+#define APOGEE(this,max) ((this>max) ? max : this)
+
+#if !defined(MAX_ADAPTORS)
+#define MAX_ADAPTORS	 4
+#endif
+
+#define MAX_DRIVES       (8)
+#define SECTOR_SIZE      (0x200) 
+// 512 byte sectors
+
+// Promise Organization ID
+#define MY_IOP_ID        0x10
+#define PROMISE_ORG_ID   0x91
+ 
+// ISM String Identity 
+#define PTI_RAID  'I2O RAID DEVICE'
+#define PTI_IDE   'IDE DEVICE'      
+
+#define VERSIONHI  (0x0001)
+#define VERSIONLO  (0x000B) 
+
+typedef struct _DRIVE 
+{
+  char  present;          // boolean set if drive present
+  unsigned long sectors;  // LBA drive size in sectors
+}DRIVE, *ptrDRIVE;
+
+typedef  struct _I2ODISK 
+{
+  int present;	/* TRUE / FALSE */
+  char DiskModel[I2O_DEVID_PRODUCT_INFO_SZ+4];
+  char Vendor[I2O_DEVID_VENDOR_INFO_SZ+4];
+  char ProductRevLevel[I2O_DEVID_REV_LEVEL_SZ+4];
+  unsigned int  LocalTID;
+  unsigned int  lastcyl;  // total cyl cnt - 1 = last cyl position
+  unsigned char lasthead; // total head cnt - 1 = last head position
+  unsigned char sector;   // sector starts at position 1
+  unsigned short resvered; // Padding with two bytes
+  unsigned long lastLBA;  // total LBA cnt - 1 = last LBA position
+  unsigned long DeviceFlag;
+}I2ODISK, *PI2ODISK;
+
+typedef struct _I2OARRAY 
+{
+  unsigned int  RaidMode;
+}I2OARRAY, *PI2OARRAY;
+
+/* PTI_ST Private Message Structure */
+typedef struct _PTI_ST_PRIVATE_MESSAGE {
+        I2O_PRIVATE_MESSAGE_FRAME       MyStandMsg;
+        I2O_SGE_PAGE_ELEMENT            InSGL;
+        I2O_SGE_PAGE_ELEMENT            OutSGL;
+} PTI_ST_PRIVATE_MESSAGE, *PPTI_ST_PRIVATE_MESSAGE;
+
+/*
+ * Maximum number of SG segments these cards can support.
+ */
+#define PTI_ST_MAX_SG      12	/* 16 */
+#define	PTI_ST_MAXSCB      32
+
+#define PTI_ST_RESET_DELAY 5
+
+typedef PI2O_BSA_READ_MESSAGE  PI2O_BSA_RW_MESSAGE;
+
+typedef enum 
+{
+  SCB_FREE                = 0x0000,
+  SCB_WAITINGQ            = 0x0002,
+  SCB_ACTIVE              = 0x0004,
+  SCB_SENSE               = 0x0008,
+  SCB_ABORT               = 0x0010,
+  SCB_DEVICE_RESET        = 0x0020,
+  SCB_RESET               = 0x0040,
+  SCB_RECOVERY_SCB        = 0x0080,
+  SCB_WAS_BUSY            = 0x0100,
+  SCB_MSGOUT_SENT         = 0x0200,
+  SCB_MSGOUT_SDTR         = 0x0400,
+  SCB_MSGOUT_WDTR         = 0x0800,
+  SCB_MSGOUT_BITS         = SCB_MSGOUT_SENT | 
+                            SCB_MSGOUT_SDTR |
+                            SCB_MSGOUT_WDTR,
+  SCB_QUEUED_ABORT        = 0x1000,
+  SCB_QUEUED_FOR_DONE     = 0x2000
+} scb_flag_type;
+
+
+struct pti_st_scb 
+{
+  PI2O_MESSAGE_FRAME     *mf;        /* corresponding hardware scb */
+  Scsi_Cmnd              *cmd;       /* Scsi_Cmnd for this scb */
+  struct pti_st_scb      *q_next;    /* next scb in queue */
+  volatile scb_flag_type flags;      /* current state of scb */
+  unsigned char	         tag;
+  unsigned char	         sg_count;
+  unsigned char          sense_cmd[6]; /*
+                                        * Allocate 6 characters for
+                                        * sense command.
+                                        */
+  unsigned int           sg_length;  /* We init this during buildscb so we
+                                      * don't have to calculate anything
+                                      * during underflow/overflow/stat 
+                                      * code
+                                      */
+  void                   *kmalloc_ptr;
+};
+
+typedef struct 
+{
+  struct pti_st_scb *head;
+  struct pti_st_scb *tail;
+} scb_queue_type;
+
+typedef struct 
+{
+  scb_queue_type free_scbs;        /*
+                                    * SCBs assigned to free slot on
+                                    * card (no paging required)
+                                    */
+  struct pti_st_scb   *scb_array[PTI_ST_MAXSCB];
+  unsigned char  maxmfs;           /* hardware scbs */
+  unsigned char  maxscbs;          /* max scbs including pageable scbs */
+} scb_data_type;
+
+
+/*
+ *  Message Unit CSR definitions for RedCreek PCI45 board
+ */
+typedef struct tag_atu 
+{
+  volatile unsigned long APICRegSel;  /* APIC Register Select */
+  volatile unsigned long reserved0;
+  volatile unsigned long APICWinReg;  /* APIC Window Register */
+  volatile unsigned long reserved1;
+  volatile unsigned long InMsgReg0;   /* inbound message register 0 */
+  volatile unsigned long InMsgReg1;   /* inbound message register 1 */
+  volatile unsigned long OutMsgReg0;  /* outbound message register 0 */
+  volatile unsigned long OutMsgReg1;  /* outbound message register 1 */
+  volatile unsigned long InDoorReg;   /* inbound doorbell register */
+  volatile unsigned long InIntStat;   /* inbound interrupt status register */
+  volatile unsigned long InIntMask;   /* inbound interrupt mask register */
+  volatile unsigned long OutDoorReg;  /* outbound doorbell register */
+  volatile unsigned long OutIntStat;  /* outbound interrupt status register */
+  volatile unsigned long OutIntMask;  /* outbound interrupt mask register */
+  volatile unsigned long reserved2;
+  volatile unsigned long reserved3;
+  volatile unsigned long InQueue;     /* inbound queue port */
+  volatile unsigned long OutQueue;    /* outbound queue port */
+  volatile unsigned long reserved4;
+  volatile unsigned long reserver5;
+  /* RedCreek extension */
+  volatile unsigned long EtherMacLow;
+  volatile unsigned long EtherMacHi;
+  volatile unsigned long IPaddr;
+  volatile unsigned long IPmask;
+} ATU, *PATU;
+
+typedef enum 
+{
+  PSTC_FNONE                 = 0x00000000,
+  PSTC_PAGESCBS              = 0x00000001,
+  PSTC_CHANNEL_B_PRIMARY     = 0x00000002,
+  PSTC_USEDEFAULTS           = 0x00000004,
+  PSTC_INDIRECT_PAGING       = 0x00000008,
+  PSTC_CHNLB                 = 0x00000020,
+  PSTC_CHNLC                 = 0x00000040,
+  PSTC_EXTEND_TRANS_A        = 0x00000100,
+  PSTC_EXTEND_TRANS_B        = 0x00000200,
+  PSTC_TERM_ENB_A            = 0x00000400,
+  PSTC_TERM_ENB_SE_LOW       = 0x00000400,
+  PSTC_TERM_ENB_B            = 0x00000800,
+  PSTC_TERM_ENB_SE_HIGH      = 0x00000800,
+  PSTC_HANDLING_REQINITS     = 0x00001000,
+#define PSTC_IN_IOCTL_BIT	PSTC_HANDLING_REQINITS
+  PSTC_TARGETMODE            = 0x00002000,
+  PSTC_NEWEEPROM_FMT         = 0x00004000,
+ /*
+  *  Here ends the FreeBSD defined flags and here begins the linux defined
+  *  flags.  NOTE: I did not preserve the old flag name during this change
+  *  specifically to force me to evaluate what flags were being used properly
+  *  and what flags weren't.  This way, I could clean up the flag usage on
+  *  a use by use basis.  Doug Ledford
+  */
+  PSTC_RESET_DELAY           = 0x00080000,
+  PSTC_A_SCANNED             = 0x00100000,
+  PSTC_B_SCANNED             = 0x00200000,
+  PSTC_MULTI_CHANNEL         = 0x00400000,
+  PSTC_BIOS_ENABLED          = 0x00800000,
+  PSTC_SEEPROM_FOUND         = 0x01000000,
+  PSTC_TERM_ENB_LVD          = 0x02000000,
+  PSTC_ABORT_PENDING         = 0x04000000,
+  PSTC_RESET_PENDING         = 0x08000000,
+#define PSTC_IN_ISR_BIT      28
+  PSTC_IN_ISR                = 0x10000000,
+  PSTC_IN_ABORT              = 0x20000000,
+  PSTC_IN_RESET              = 0x40000000,
+  PSTC_EXTERNAL_SRAM         = 0x80000000
+} pstc_flag_type;
+
+#define MAX_LCT_ENTRY 32
+
+typedef struct _outboundBuff_t {
+  U8		outboundBuff[32][32*4];
+} outboundBuff_t;
+
+struct pti_st_host 
+{
+  /*
+   *  This is the first 64 bytes in the host struct
+   */
+
+  /*
+   * We are grouping things here....first, items that get either read or
+   * written with nearly every interrupt
+   */
+  volatile pstc_flag_type  flags; 
+  unsigned int             mbase;             /* card base address */
+  volatile unsigned char  *maddr;
+  PATU                     p_atu;             /* ptr to  ATU register block */
+  PU8                      LinBaseAddr;
+#if defined(MYDEBUG) && 0
+  U8                       replyBuffer[16*1024];
+  U8                       messageBuffer[256];
+  U8                       outboundBuffer[32][32*4];
+#else
+  outboundBuff_t           *outboundBufferp;
+  U8			   *replyBufferp;
+  U8                       *messageBufferp;
+#endif
+  PU8                      pLinOutMsgBlock;
+  U32                      outMsgBlockPhyAddr; 
+  scb_data_type           *scb_data;
+  struct pti_st_cmd_queue 
+  {
+    Scsi_Cmnd *head;
+    Scsi_Cmnd *tail;
+  } completeq;
+
+  volatile scb_queue_type  waiting_scbs;
+
+  /*
+   * Things read/written on nearly every entry into pti_st_queue()
+   */
+  volatile unsigned char   activescbs;       /* active scbs */
+  volatile unsigned char   max_activescbs;
+  int max_lun;
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
+  spinlock_t               spin_lock;
+  volatile unsigned char   cpu_lock_count[NR_CPUS];
+#endif
+
+  /*
+   * We put the less frequently used host structure items after the more
+   * frequently used items to try and ease the burden on the cache subsystem.
+   * These entries are not *commonly* accessed, whereas the preceding entries
+   * are accessed very often.  The only exceptions are the qinfifo, qoutfifo,
+   * and untagged_scbs array.  But, they are often accessed only once and each
+   * access into these arrays is likely to blow a cache line, so they are put
+   * down here so we can minimize the number of cache lines required to hold
+   * the preceeding entries.
+   */
+
+  unsigned char            pci_irq;          /* IRQ for this adapter */
+  int                      scsi_id;          /* host adapter SCSI ID */
+  
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
+  struct pci_dev          *pdev;
+#endif
+
+  unsigned char            pci_bus;
+  unsigned char            pci_device_fn;
+  struct Scsi_Host        *host;             /* pointer to scsi host */
+  int                      host_no;          /* SCSI host number */
+
+  I2O_LCT_ENTRY LctEntryTable[MAX_LCT_ENTRY];
+  I2O_EXEC_STATUS_GET_REPLY IopStatus;
+
+  int TotalDiskCount;
+  I2ODISK I2ODisk[MAX_DRIVES];
+
+  /* PTI_STCNTL device Variable */
+  void  	*pti_stdev_bufferp;
+  int                   major;            /* control device's major */
+  int                   counter;          /*counter of using control device*/
+};
+
+extern struct pti_st_host *pti_st_hostp[MAX_ADAPTORS];
+
+
+//---------------------------------------------------------------------------
+// I960RP Memory-Mapper Register PCI Addressing Offset 
+#define ARSR_OFFSET   0       //APICReg
+#define AWR_OFFSET    0x08    //APCIWinReg
+#define IMR0_OFFSET   0x10    //InboundMsgReg0
+#define IMR1_OFFSET   0x14    //InboundMsgReg1
+#define OMR0_OFFSET   0x18    //OutboundMsgReg0
+#define OMR1_OFFSET   0x1c    //OutboundMsgReg1
+#define IDR_OFFSET    0x20    //InboundDBellReg
+#define IISR_OFFSET   0x24    //InboundIntStatusReg
+#define IIMR_OFFSET   0x28    //InboundIntMaskReg
+#define ODR_OFFSET    0x2c    //OutboundDBellReg
+#define OISR_OFFSET   0x30    //OutboundIntStatusReg
+#define OIMR_OFFSET   0x34    //OutboundIntMaskReg
+#define INBOUNDQPORT  0x40
+#define OUTBOUNDQPORT 0x44
+#define MUCR_OFFSET   0x50    //MUConfReg
+#define QBAR_OFFSET   0x54    //QueueBaseAddReg
+
+//---------------------------------------------------------------------------
+// Bit Definition for InboundIntStatusReg (IISR)
+#define APICW_Status      0x100  //APIC Window Interrupt (R/C)
+#define APICR_Status      0x80   //APIC Register Select Interrupt (R/C)
+#define IR_Status         0x40   //Index Register Interrupt (R/C)
+#define OBFQ_OF_Status    0x20   //Outbound Free Queue OverFlow Interrupt (R/C)
+#define IBPQ_Status       0x10   //Inbound Post Queue Interrupt (R/C)
+#define NMI_DB_Status     0x08   //NMI Doorbell Interrupt (R/O)
+#define IB_DB_Status      0x04   //Inbound Doorbell Interrupt (R/O)
+#define IB_MSG1_Status    0x02   //Inbound Message 1 Interrupt (R/C)
+#define IB_MSG0_Status    0x01   //Inbound Message 0 Interrupt (R/C)
+
+// Bit Definition for InboundIntMaskReg (IIMR)
+#define APICW_Mask        0x100  //APIC Windows Interrupt Mask (R/W)
+#define APICRSI_Mask      0x80   //APIC Register Select Interrupt Mask (R/W)
+#define IR_Mask           0x40   //Index Register Interrupt Mask (R/W)
+#define OBFQ_OF_Mask      0x20   //Outbound Free Queue Overflow Interrupt Mask (R/W)
+#define IBPQ_Mask         0x10   //Inbound Post Queue Interrupt Mask (R/W)
+#define NMI_DB_Mask       0x08   //NMI Doorbell Interrupt Mask (R/W)
+#define IB_DB_Mask        0x04   //Inbound DoorbellInterrupt Mask (R/W)
+#define IB_MSG1_Mask      0x02   //Inbound Message 1 Interrupt Mask (R/W)
+#define IB_MSG0_Mask      0x01   //Inbound Message 0 Interrupt Mask (R/W)
+
+// Bit Definition for Outbound Interrupt Status Register (OISR)
+#define PCI_INT_D_Status  0x80   //PCI Interrupt D (RO)
+#define PCI_INT_C_Status  0x40   //PCI Interrupt C (RO)
+#define PCI_INT_B_Status  0x20   //PCI Interrupt B (RO)
+#define PCI_INT_A_Status  0x10   //PCI Interrupt A (RO)
+#define OBPQ_INT_Status   0x08   //Outbound Post Queue Interrupt (RO)
+#define OBDB_INT_Status   0x04   //Outbound Doorbell Interrupt (RO)
+#define OBMSG1_INT_Status 0x02   //Outbound Message 1 Interrupt (PCI R/C)
+#define OBMSG0_INT_Status 0x01   //Outbound Message 0 Interrupt (PCI R/C)
+
+// Bit Definition for Outbound Interrupt Mask Register
+#define PCI_INT_D_Mask    0x80   //PCI Interrupt D (RW)
+#define PCI_INT_C_Mask    0x40   //PCI Interrupt C (RW)
+#define PCI_INT_B_Mask    0x20   //PCI Interrupt B (RW)
+#define PCI_INT_A_Mask    0x10   //PCI Interrupt A (RW)
+#define OBPQ_INT_Mask     0x08   //Outbound Post Queue Interrupt Mask (RW)
+#define OBDB_INT_Mask     0x04   //Outbound Doorbell Interrupt Mask (RW)
+#define OBMSG1_INT_Mask   0x02   //Outbound Message 1 Interrupt Mask (RW)
+#define OBMSG0_INT_Mask   0x01   //Outbound Message 0 Interrupt Mask (RW)
+
+//---------------------------------------------------------------------------
+// IOP Status
+#define IOPSTATE_INIT     0x01
+#define IOPSTATE_RESET    0x02
+#define IOPSTATE_HOLD     0x04
+#define IOPSTATE_READY    0x05
+#define IOPSTATE_OP       0x08
+#define IOPSTATE_FAILED   0x10
+#define IOPSTATE_FAULTED  0x11
+
+
+
+#endif /* _pti_st_h */
+
diff -ruN linux-2.4.20-orig/drivers/scsi/pti_stdev.h linux-2.4.20/drivers/scsi/pti_stdev.h
--- linux-2.4.20-orig/drivers/scsi/pti_stdev.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.4.20/drivers/scsi/pti_stdev.h	2003-01-21 19:22:00.000000000 -0500
@@ -0,0 +1,255 @@
+/*+M*************************************************************************
+ * Promise SuperTrak device driver for Linux.
+ *
+ * Copyright (c) 2001  Promise Technology, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * --------------------------------------------------------------------------  
+ * Copyright (c) 1999-2001 Promise Technology, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *   		$Id: pti_st.c,v 1.1 2001/06/27 15:37:18 Jack Hu 	$
+ *-M*************************************************************************/
+
+/**************************************************************************
+ * File: pti_stdev.h       Device Declaraitons for pti_st.c. 
+ **************************************************************************/
+#include <linux/ioctl.h>
+
+#if !defined(PTI_STDEV_H)
+#define	PTI_STDEV_H
+
+#if !defined(__KERNEL__)
+#if 0
+#include "i2omsg.h"
+#else /* 0 */
+#include "i2odef.h"
+#endif /* 0 */
+#endif /* __KERNEL__ */
+
+#if !defined(ULOG)
+#define	ULONG	unsigned long
+#endif
+
+#if !defined(USHORT)
+#define	USHORT	unsigned short
+#endif
+
+#if !defined(UCHAR)
+#define UCHAR	unsigned char
+#endif
+
+/*
+ * I2O IOP Descriptor
+ */
+
+typedef struct  _I2O_IOP_DESCRIPTOR {
+    ULONG        IOPNumber;
+    ULONG        IOPCapabilities;
+    ULONG        IOPState;
+    ULONG        I2OVersion;
+    ULONG        MessengerType;
+    ULONG        MaxMessageFrameSize;
+    ULONG        ExpectedLCTSize;
+    ULONG        MaxInboundMFrames;
+    ULONG        InitialInboundMFrames;
+    ULONG        Reserved;
+} I2O_IOP_DESCRIPTOR, *PI2O_IOP_DESCRIPTOR;
+
+/*
+ * I2O IOP and LCT Configuration data
+ */
+
+typedef struct _I2O_DEVICE_DESCRIPTOR {
+    ULONG                   ChangeIndicator;
+    I2O_LCT_ENTRY           LCT;
+    I2O_IOP_DESCRIPTOR      IOP;
+} I2O_DEVICE_DESCRIPTOR, *PI2O_DEVICE_DESCRIPTOR;
+
+/*
+ *      I2O Query Configuration Record structure
+ */
+
+#define I2O_CLASS_MATCH_ANY_BITS  (((1<<I2O_CLASS_ID_SZ)-1) & I2O_CLASS_MATCH_ANYCLASS)
+
+typedef struct _I2O_CONFIG_QUERY {
+    ULONG          IOPNumber;
+    I2O_CLASS_ID   ClassID;
+    ULONG          SubClassID;
+    ULONG          Index;
+} I2O_CONFIG_QUERY, *PI2O_CONFIG_QUERY;
+
+typedef struct _I2O_IOCTL_GET_CONFIG {
+	I2O_CONFIG_QUERY	config_query;
+	I2O_DEVICE_DESCRIPTOR	device_descriptor;
+} I2O_IOCTL_GET_CONFIG, *PI2O_IOCTL_GET_CONFIG;
+
+/*
+ * Useful define in get/set operations
+ */
+
+typedef struct _I2O_PARAM_SCALAR_OPERATION {
+    I2O_PARAM_OPERATIONS_LIST_HEADER      OpList;
+    I2O_PARAM_OPERATION_SPECIFIC_TEMPLATE OpBlock;
+} I2O_PARAM_SCALAR_OPERATION, *PI2O_PARAM_SCALAR_OPERATION;
+
+/*
+ * Defines for the interface to the I2OExec driver.
+ */
+
+#if 0
+#define I2O_GET_CONFIG_INFO        0xBA0
+#define I2O_PRIVATE_MESSAGE_CODE   0xBB0
+#define I2O_EXEC_REQUEST           0xBC0
+#define I2O_PARAMS_GET_REQUEST     0xBD0
+#define I2O_PARAMS_SET_REQUEST     0xBE0
+#define I2O_GET_LCT                0xBF0
+#define I2O_GET_IOPCOUNT           0xC00
+#define I2O_GET_CONFIGDIALOG       0xC10
+#else
+#define I2O_GET_CONFIG_INFO        0xBA
+#define I2O_PRIVATE_MESSAGE_CODE   0xBB
+#define I2O_EXEC_REQUEST           0xBC
+#define I2O_PARAMS_GET_REQUEST     0xBD
+#define I2O_PARAMS_SET_REQUEST     0xBE
+#define I2O_GET_LCT                0xBF
+#define I2O_GET_IOPCOUNT           0xC0
+#define I2O_GET_CONFIGDIALOG       0xC1
+#endif
+
+/**************************************************
+ *        THe following are for IOCTL             *
+ **************************************************/
+
+#define SUPERTRAK_GETVERSION       0x01
+
+/*
+ *
+ */
+#define SUPERTRAK_SIGNATURE             "SUPRTRAK"
+#define SUPERTRAK_SIG_LEN               0x8
+
+/*
+ * The following are for IOCTL data buffer
+ */
+typedef struct _SRB_IO_CONTROL {
+        ULONG HeaderLength;
+        UCHAR Signature[8];
+        ULONG TimeOut;
+        ULONG ControlCode;
+        ULONG ReturnCode;
+        ULONG Length; 
+} SRB_IO_CONTROL, *PSRB_IO_CONTROL;
+
+/*
+ * Parameter structure for Get/Set Parameters call.
+ */
+
+typedef struct _I2O_PARAM_BLOCK {
+    ULONG           IOP;
+    USHORT          TargetTID;
+    UCHAR           ParamData[1];
+} I2O_PARAM_BLOCK, *PI2O_PARAM_BLOCK;
+
+/*
+ * The structure is for IOCTL_GET_CONFIG_INFO
+ */
+typedef struct _PTI_STDEV_GET_CONFIG_BUFFER {
+    SRB_IO_CONTROL buf;
+    char payload[sizeof(I2O_CONFIG_QUERY)+sizeof(I2O_DEVICE_DESCRIPTOR)];
+} PTI_STDEV_GET_CONFIG_BUFFER;
+
+/*
+ * The stucture is for IOCTL_PARAMS_GET_REQUEST and IOCTL_PRIVATE_MESSAGE
+ */
+typedef struct _PTI_STDEV_INBUFFER {
+    SRB_IO_CONTROL srb;
+    I2O_PARAM_BLOCK block;
+    char payload[4096-1];
+} PTI_STDEV_INBUFFER;
+
+#if !defined(MAX_ADAPTORS)
+#define MAX_ADAPTORS	 4
+#endif
+
+/*
+ * The following are the definition of ioctl command
+ */
+#define	PTI_ST_MAGIC	's'
+
+#define IOCTL_SUPERTRAK_GETVERSION _IOR(PTI_ST_MAGIC, SUPERTRAK_GETVERSION, SRB_IO_CONTROL)
+
+#define IOCTL_GET_CONFIG_INFO	_IOR(PTI_ST_MAGIC, I2O_GET_CONFIG_INFO, PTI_STDEV_GET_CONFIG_BUFFER)
+
+#define IOCTL_PRIVATE_MESSAGE_CODE _IOWR(PTI_ST_MAGIC, I2O_PRIVATE_MESSAGE_CODE, PTI_STDEV_INBUFFER)
+
+#define IOCTL_PARAMS_GET_REQUEST _IOWR(PTI_ST_MAGIC, I2O_PARAMS_GET_REQUEST, PTI_STDEV_INBUFFER)
+
+#if defined(__KERNEL__)
+
+#define	PTCNTL_DEV_NAME		"pti_st"
+
+int pti_stdev_open(struct inode *, struct file *);
+int pti_stdev_release(struct inode *, struct file *);
+int pti_stdev_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+struct block_device_operations pti_stdev_fops = {
+	open:		pti_stdev_open, 
+	release:	pti_stdev_release, 
+	ioctl:		pti_stdev_ioctl,
+};
+#else
+struct file_operations pti_stdev_fops = {
+	NULL, NULL, NULL, NULL, NULL, pti_stdev_ioctl, NULL,
+	pti_stdev_open, NULL, pti_stdev_release, NULL, NULL, NULL, NULL};
+#endif
+
+#endif	/* __KERNEL__ */
+
+#endif          /* PTI_STDEV_H */
+
diff -ruN linux-2.4.20-orig/include/linux/pci_ids.h linux-2.4.20/include/linux/pci_ids.h
--- linux-2.4.20-orig/include/linux/pci_ids.h	2002-11-28 18:53:15.000000000 -0500
+++ linux-2.4.20/include/linux/pci_ids.h	2003-01-21 19:22:00.000000000 -0500
@@ -621,6 +621,8 @@
 #define PCI_DEVICE_ID_PROMISE_20276	0x5275
 #define PCI_DEVICE_ID_PROMISE_20277	0x7275
 #define PCI_DEVICE_ID_PROMISE_5300	0x5300
+#define PCI_DEVICE_ID_PROMISE_ST100	0x1960
+#define PCI_DEVICE_ID_PROMISE_ST100SX6	0x1962
 
 #define PCI_VENDOR_ID_N9		0x105d
 #define PCI_DEVICE_ID_N9_I128		0x2309
