Submitted By: Daniel Baumann Date: 2004-01-12 Initial Package Version: 2.4.24 Origin: http://www.kernel.org/ Description: Adds Promise SX6000 support, driver version 1.34 diff -Naur linux-2.4.24.original/Documentation/Configure.help linux-2.4.24/Documentation/Configure.help --- linux-2.4.24.original/Documentation/Configure.help 2003-11-28 19:26:19.000000000 +0100 +++ linux-2.4.24/Documentation/Configure.help 2004-01-12 22:32:36.000000000 +0100 @@ -1339,6 +1339,16 @@ CONFIG_PDC202XX_FORCE For FastTrak enable overriding BIOS. +CONFIG_SCSI_PTI_ST + This driver supports the Promise SX6000 hardware ATA-RAID controller. + This is a Promise maintained driver version 1.34, see http://www.promise.com/. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + . The module will be called + pti_st.o. + SiS5513 chipset support CONFIG_BLK_DEV_SIS5513 This driver ensures (U)DMA support for SIS5513 chipset family based diff -Naur linux-2.4.24.original/arch/i386/defconfig linux-2.4.24/arch/i386/defconfig --- linux-2.4.24.original/arch/i386/defconfig 2003-11-28 19:26:19.000000000 +0100 +++ linux-2.4.24/arch/i386/defconfig 2004-01-12 22:34:37.000000000 +0100 @@ -360,6 +360,7 @@ # CONFIG_SCSI_PCI2000 is not set # CONFIG_SCSI_PCI2220I is not set # CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_PTI_ST is not set # CONFIG_SCSI_QLOGIC_FAS is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set diff -Naur linux-2.4.24.original/drivers/scsi/Config.in linux-2.4.24/drivers/scsi/Config.in --- linux-2.4.24.original/drivers/scsi/Config.in 2003-11-28 19:26:20.000000000 +0100 +++ linux-2.4.24/drivers/scsi/Config.in 2004-01-12 22:32:36.000000000 +0100 @@ -178,6 +178,7 @@ dep_tristate 'PCI2000 support' CONFIG_SCSI_PCI2000 $CONFIG_SCSI dep_tristate 'PCI2220i support' CONFIG_SCSI_PCI2220I $CONFIG_SCSI dep_tristate 'PSI240i support' CONFIG_SCSI_PSI240I $CONFIG_SCSI +dep_tristate 'Promise SX6000 support' CONFIG_SCSI_PTI_ST $CONFIG_SCSI dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI diff -Naur linux-2.4.24.original/drivers/scsi/Makefile linux-2.4.24/drivers/scsi/Makefile --- linux-2.4.24.original/drivers/scsi/Makefile 2003-11-28 19:26:20.000000000 +0100 +++ linux-2.4.24/drivers/scsi/Makefile 2004-01-12 22:34:06.000000000 +0100 @@ -59,6 +59,7 @@ obj-$(CONFIG_SCSI_PCI2000) += pci2000.o obj-$(CONFIG_SCSI_PCI2220I) += pci2220i.o obj-$(CONFIG_SCSI_PSI240I) += psi240i.o +obj-$(CONFIG_SCSI_PTI_ST) += pti_st.o obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o obj-$(CONFIG_SCSI_DPT_I2O) += dpt_i2o.o obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o diff -Naur linux-2.4.24.original/drivers/scsi/i2odef.h linux-2.4.24/drivers/scsi/i2odef.h --- linux-2.4.24.original/drivers/scsi/i2odef.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.24/drivers/scsi/i2odef.h 2004-01-12 22:32:36.000000000 +0100 @@ -0,0 +1,1119 @@ + +#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; + + +/****************************************************************************/ + +/* I2O BSA Control Flags */ + +typedef U16 I2O_BSA_CTL_FLAGS; + +/* I2O BSA Cache Flush Message Frame */ + +typedef struct _I2O_BSA_CACHE_FLUSH_MESSAGE { + I2O_MESSAGE_FRAME StdMessageFrame; + I2O_TRANSACTION_CONTEXT TransactionContext; + I2O_BSA_CTL_FLAGS ControlFlags; + U8 TimeMultiplier; + U8 Reserved; +} I2O_BSA_CACHE_FLUSH_MESSAGE, *PI2O_BSA_CACHE_FLUSH_MESSAGE; + + +/****************************************************************************/ + + +/* 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 -Naur linux-2.4.24.original/drivers/scsi/pti_st.c linux-2.4.24/drivers/scsi/pti_st.c --- linux-2.4.24.original/drivers/scsi/pti_st.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.24/drivers/scsi/pti_st.c 2004-01-12 22:32:36.000000000 +0100 @@ -0,0 +1,3792 @@ +/*+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 +#include + +#ifdef MODULE +#include +#endif + +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(x,y,z) (((x)<<16)+((y)<<8)+(z)) +#endif + +#if defined(MODULE) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0) +#include +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +#include +#endif +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) +#include +#include /* for kmalloc() */ +#else +#include /* for kmalloc() */ +#endif +#include +#include /* for CONFIG_PCI */ +#include +#include +#include +#include + +#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 +#else +# include +#endif +# include +# define cpuid smp_processor_id() + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0) + +# 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); + +#else /* < KERNEL_VERSION(2,4,0) */ + +#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__ */ + +#endif /* < KERNEL(VERSION(2,4,0) */ + +#include + +#include "sd.h" +#include "scsi.h" +#include "hosts.h" + +#include "pti_st.h" +#include "pti_stdev.h" + +#define PTI_ST_VERBOSE_DEBUGGING + +#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}; + +/* + * The following are used for Buffer Flush in ioctl + */ +static struct timer_list bufflsh_timer; +static struct timer_list priv_msg_timer; + +#define FLUSHCACHE_TIMEOUT_DEFULT 60 + + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,4,0) + static DECLARE_WAIT_QUEUE_HEAD(WaitQ); + static DECLARE_WAIT_QUEUE_HEAD(PrivMsgWaitQ); +#else + static struct wait_queue *WaitQ=NULL; + static struct wait_queue *PrivMsgWaitQ=NULL; +#endif + + +#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) " + +#ifdef MODULE +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18) +MODULE_LICENSE("GPL"); +#endif +#endif + + +static int pti_st_install(Scsi_Host_Template *, struct pci_dev *, int *); +static int 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); +static int pti_st_flushcache(int); +static void pti_st_flushcache_respond(Scsi_Cmnd *); +static void pti_st_wait_flushcache(unsigned long); +static int pti_st_send_flushcache_cmd(struct pti_st_host *, struct pti_st_scb *, Scsi_Cmnd *, 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: %ld", + 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%lx\n", + pti_st_hostp[i]->IopStatus.ExpectedLCTSize); + ADDTOPROCBUFFER(my_buffer, tmp_buffer); + sprintf(tmp_buffer, "\tMaxInboundMFrames: 0x%lx", + pti_st_hostp[i]->IopStatus.MaxInboundMFrames); + ADDTOPROCBUFFER(my_buffer, tmp_buffer); + sprintf(tmp_buffer, "\tInitialInboundMFrames: 0x%lx\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%lx", + pti_st_hostp[i]->LctEntryTable[j].ChangeIndicator); + ADDTOPROCBUFFER(my_buffer, tmp_buffer); + sprintf(tmp_buffer, "\tDeviceFlags: 0x%lx\n", + pti_st_hostp[i]->LctEntryTable[j].DeviceFlags); + ADDTOPROCBUFFER(my_buffer, tmp_buffer); + sprintf(tmp_buffer, "\tSubClassInfo: 0x%lx", + 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%lx\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; + U32 tmp; + + 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; + // we handle ioctl scsi command here, the command is sent by the + // InitiatorContext of standard message frame, we send the message + // in pti_st_send_private_message_code_cmd function. + tmp = rmfp->TransactionContext; + if(scb_index == 0xfd && tmp ){ + cmd = (Scsi_Cmnd *)tmp; + if(cmd->scsi_done && cmd->cmnd[0] == 0xfd){ + cmd->scsi_done(cmd); + } + else{ + printk("cmd->scsi_done is NULL in pti_st_isr.\n"); + } + /* return MFA to outbound free Q*/ + p->p_atu->OutQueue = phyAddrMsg; + /* any more msgs? */ + phyAddrMsg = p->p_atu->OutQueue; + continue; + } + /////////////////////////////////////// + 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; + + /* + * On some new SMP motherboard, there are some problem when huge + * data are readed/written, so we should reduce the limit of request + * from 32 to 16 + */ +#if 0 + host->can_queue = PTI_ST_MAXSCB; +#else +// host->can_queue = 16; + host->can_queue = 12; +#endif + + 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; + + // printk("pti_st.c: PCI bios is present, checking for devices ...\n"); + +#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_INTEL_i960 && /* ST100 */ + pdev->device != PCI_DEVICE_ID_INTEL_i962)) /* 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; iuse_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; + unsigned long cpuflags; + + 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; + } + + spin_lock_irqsave(&p->spin_lock, cpuflags); + + 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); + spin_unlock_irqrestore(&p->spin_lock, cpuflags); + scbq_insert_head(p, &p->scb_data->free_scbs, scb); + 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; + + spin_unlock_irqrestore(&p->spin_lock, cpuflags); + + 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; + volatile 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++; + } + +} + +/* + * 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 int 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; + int i=0; + + while(i < 10){ + msgOffset = hostp->p_atu->InQueue; + if(msgOffset != -1){ + break; + } + ++i; + } + if( i >= 10) return -1; + 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; + /* + `a* 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; + return 0; +} + + +/**************************************************************************** + Misc functions. +****************************************************************************/ +/* + * + */ +static void ZeroMemory(unsigned long *zeroBuffer, unsigned int count) +{ + count = count >> 2; // count/4 + while(count--) + { + * zeroBuffer = 0; + zeroBuffer ++; + } +} + +static void pti_st_flushcache_respond(Scsi_Cmnd *cmd) +{ + cmd->result = DID_OK; + wake_up(&WaitQ); + return; +} + +static void pti_st_wait_flushcache(unsigned long data) +{ + struct pti_st_scb *scb; + Scsi_Cmnd *cmd; + + scb = (struct pti_st_scb *)data; + cmd = scb->cmd; + + cmd->result = DID_ERROR; + + wake_up(&WaitQ); + + return; +} + +static int pti_st_send_flushcache_cmd(struct pti_st_host *p, + struct pti_st_scb *scb, + Scsi_Cmnd *cmd, + int time) +{ + unsigned long pBaseAddrReg; + unsigned long msgoffset; + PI2O_BSA_CACHE_FLUSH_MESSAGE mfp; + unsigned long cpuflags; + + spin_lock_irqsave(&p->spin_lock, cpuflags); + + pBaseAddrReg = (U32)p->maddr; + msgoffset = * (U32 *)(pBaseAddrReg+INBOUNDQPORT); + if (msgoffset == 0xFFFFFFFF) + { + spin_unlock_irqrestore(&p->spin_lock, cpuflags); + scbq_insert_head(p, &p->scb_data->free_scbs, scb); + printk("pti_st_send_flushcache_cmd: Couldn't get a free MF from inboundqport on scsi No. %d.\n", p->host_no); + return(-1); + } + + 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 = pti_st_flushcache_respond; + cmd->result = DID_OK; + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + cmd->host_scribble = NULL; + + scb->flags |= SCB_ACTIVE; + + mfp = (PI2O_BSA_CACHE_FLUSH_MESSAGE)(pBaseAddrReg + msgoffset); + + memset((unsigned long *)mfp, 0, sizeof(I2O_BSA_CACHE_FLUSH_MESSAGE)+0x10); + + /* Fill the message frame */ + mfp->StdMessageFrame.Function = I2O_BSA_CACHE_FLUSH; + mfp->StdMessageFrame.VersionOffset = 0x01; + mfp->StdMessageFrame.MsgFlags = 0; + mfp->StdMessageFrame.MessageSize = sizeof(I2O_BSA_CACHE_FLUSH_MESSAGE) >> 2; + mfp->StdMessageFrame.TargetAddress = p->I2ODisk[cmd->target].LocalTID; + mfp->StdMessageFrame.InitiatorAddress = 0x01; + mfp->StdMessageFrame.InitiatorContext = scb->tag; + mfp->TransactionContext = cmd->serial_number; + mfp->ControlFlags = 0; + mfp->TimeMultiplier = 0; + + /* Start timer for timeout */ + init_timer(&bufflsh_timer); + bufflsh_timer.expires = (jiffies + time*HZ); + bufflsh_timer.data = (unsigned long)scb; + bufflsh_timer.function=pti_st_wait_flushcache; + + /* modified for shutdown flag */ + mfp->Reserved = cmd->cmnd[2]; + + /* send the message */ + * (U32 *)(pBaseAddrReg+INBOUNDQPORT) = msgoffset; + + spin_unlock_irqrestore(&p->spin_lock, cpuflags); + + add_timer(&bufflsh_timer); + interruptible_sleep_on(&WaitQ); + + del_timer(&bufflsh_timer); + + if(cmd->result != DID_OK) + return(-1); + else + return (0); + +} + +static int pti_st_flushcache(int time) +{ + struct pti_st_host *p; + struct pti_st_scb *scb; + static Scsi_Cmnd scsicmd = {0}; + int err = 0; + int i, ret; + + for(i = 0, err = 0; i < MAX_ADAPTORS; i++) + { + p = (struct pti_st_host *) pti_st_hostp[i]; + if(!p) + continue; + + scb = scbq_remove_head(p, &p->scb_data->free_scbs); + + if (scb == NULL) + { + err++; + continue; + } + + scsicmd.cmnd[0] = 0xfe; + scsicmd.cmnd[2] = 0xfe; + scsicmd.serial_number = 0xfe; + if(p->TotalDiskCount <= 0 || p->I2ODisk[0].present != TRUE) + { + continue; + } else { + /* + * if raid exist, raid 0 should be exist + * because raid is sorted from 0 + */ + scsicmd.target = 0; + } + + ret = pti_st_send_flushcache_cmd(p, scb, &scsicmd, time); + + if(ret) { + err++; + continue; + } + } + + return(err); + + +} + +/************************************************************ + * 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) +{ + unsigned long cpuflags; + + 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); + + spin_lock_irqsave(&p->spin_lock, cpuflags); + if(pti_st_hostp[aptno]->counter != 0) { + spin_unlock_irqrestore(&p->spin_lock, cpuflags); + return(-EBUSY); + } + pti_st_hostp[aptno]->counter++; + spin_unlock_irqrestore(&p->spin_lock, cpuflags); + MOD_INC_USE_COUNT; + return(0); +} + +int pti_stdev_release(struct inode *inodep, struct file *filep) +{ + int aptno = MINOR(inodep->i_rdev); + struct pti_st_host *p = pti_st_hostp[aptno]; + unsigned long cpuflags; + + if(!pti_st_hostp[aptno] || + pti_st_hostp[aptno]->major <= 0 || + pti_st_hostp[aptno]->major != MAJOR(inodep->i_rdev)) + return(-ENODEV); + + spin_lock_irqsave(&p->spin_lock, cpuflags); + if(pti_st_hostp[aptno]->counter <= 0) { + spin_unlock_irqrestore(&p->spin_lock, cpuflags); + return(-EBADF); + } + pti_st_hostp[aptno]->counter = 0; + spin_unlock_irqrestore(&p->spin_lock, cpuflags); + + MOD_DEC_USE_COUNT; + return(0); +} +//------------------ added by dingo, 2002/8/14 -------------------- +static void pti_st_private_message_code_respond(Scsi_Cmnd *cmd) +{ + cmd->result = DID_OK; + del_timer(&priv_msg_timer); + wake_up(&PrivMsgWaitQ); + return; +} + +static void pti_st_private_message_code_wait(unsigned long data) +{ + Scsi_Cmnd *cmd; + + del_timer(&priv_msg_timer); + cmd = (Scsi_Cmnd *) data; + cmd->result = DID_ERROR; + wake_up(&PrivMsgWaitQ); + return; +} + +static int pti_st_send_private_message_code_cmd(struct pti_st_host *p, + int time, + ULONG TargetTID, + U16 XFunctionCode, + U16 OrganizationID, + ULONG InputCount, + UCHAR *InputAddr, + ULONG OutputCount, + UCHAR *OutputAddr) +{ + unsigned long pBaseAddrReg; + unsigned long msgoffset; + PI2O_BSA_CACHE_FLUSH_MESSAGE mfp; + static Scsi_Cmnd scsicmd = {0}; + Scsi_Cmnd *cmd; + unsigned long cpu_flags; + + cmd = &scsicmd; + scsicmd.cmnd[0] = 0xfd; + scsicmd.cmnd[2] = 0xfd; + scsicmd.serial_number = 0xfd; + + cmd->scsi_done = pti_st_private_message_code_respond; + cmd->result = DID_OK; + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + cmd->host_scribble = NULL; + + spin_lock_irqsave(&p->spin_lock, cpu_flags); + /* Start timer for timeout */ + init_timer(&priv_msg_timer); + priv_msg_timer.expires = (jiffies + time*HZ); + priv_msg_timer.data = (unsigned long)cmd; + priv_msg_timer.function= pti_st_private_message_code_wait; + // we send the cmd variable by a standard message frame directly. + if (PTI_PrivateMessageCall(p, TargetTID, XFunctionCode, OrganizationID, InputCount, + InputAddr, OutputCount, OutputAddr, (U32)scsicmd.cmnd[0], (U32)cmd)) + { + spin_unlock_irqrestore(&p->spin_lock, cpu_flags); + printk("pti_st_send_private_message_code_cmd Couldn't get a free MF from inboundqport on scsi No. %d.\n", p->host_no); + return(-1); + } + add_timer(&priv_msg_timer); + spin_unlock_irqrestore(&p->spin_lock, cpu_flags); + + interruptible_sleep_on(&PrivMsgWaitQ); + + if(cmd->result != DID_OK) + return(-1); + else + return (0); + +} + +int counter =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: + case IOCTL_FLUSH_CACHE_REQUEST: + 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 ***/ + retval = pti_st_send_private_message_code_cmd(pti_st_hostp[aptno], 20, *TargetTIDp, + *XFunctionCodep, *OrganizationIDp, + 0x800, InputAddr, 0x800, OutputAddr); + 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 (-EIO); + + case IOCTL_PARAMS_GET_REQUEST: + return (-EIO); + 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); + } + + case IOCTL_FLUSH_CACHE_REQUEST: + if(srbp->TimeOut) { + ret = pti_st_flushcache(srbp->TimeOut); + } else { + ret = pti_st_flushcache(FLUSHCACHE_TIMEOUT_DEFULT); + } + } + 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. + */ + +//------------- Added by dingo, 2002/7/22 ------------- +static int power_off_notifier_func(struct notifier_block *pnb, + unsigned long code, void *unused) +{ + pti_st_flushcache(FLUSHCACHE_TIMEOUT_DEFULT); + return NOTIFY_DONE; +} + +static struct notifier_block pti_power_off_nb={ + power_off_notifier_func, NULL, 0 +}; +//----------------------------------------------------- + +#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_this_scsi_driver(void) +{ + int major, i; + pti_st_driver_template.module = THIS_MODULE; + scsi_register_module(MODULE_SCSI_HA, &pti_st_driver_template); + + pti_st_fops.owner= THIS_MODULE; + if (!pti_st_driver_template.present || + (major = register_chrdev(0, PTCNTL_DEV_NAME, (struct file_operations *)&pti_st_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; + } + } + //------------ added by dingo, 2002/7/22 ------------ + if(register_reboot_notifier(&pti_power_off_nb)){ + printk(KERN_ERR"pti_st: Can not register power notifer notifer!\n"); + return -1; + } + //--------------------------------------------------- + + return (0); + +} + +static void __exit exit_this_scsi_driver(void) +{ + int i; + + unregister_reboot_notifier(&pti_power_off_nb); // added by dingo, 2002/7/22 + + 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_chrdev(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_this_scsi_driver); +module_exit(exit_this_scsi_driver); + +#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_chrdev(0, PTCNTL_DEV_NAME, (struct file_operations *)&pti_st_fops)) < 0) +#else + (major = register_chrdev(0, PTCNTL_DEV_NAME, (struct file_operations *)&pti_st_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; + } + } + //------------ added by dingo, 2002/7/22 ------------ + if(register_reboot_notifier(&pti_power_off_nb)){ + printk(KERN_ERR"pti_st: Can not register power notifer notifer!\n"); + return -1; + } + //--------------------------------------------------- + + return (0); +} + +void cleanup_module(void) +{ + int i; + + unregister_reboot_notifier(&pti_power_off_nb); // added by dingo, 2002/7/22 + + 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_chrdev(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 diff -Naur linux-2.4.24.original/drivers/scsi/pti_st.h linux-2.4.24/drivers/scsi/pti_st.h --- linux-2.4.24.original/drivers/scsi/pti_st.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.24/drivers/scsi/pti_st.h 2004-01-12 22:32:36.000000000 +0100 @@ -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 +#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: 12, \ + this_id: -1, \ + sg_tablesize: 0, \ + cmd_per_lun: 3, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: 0, \ + 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: 12, /* 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: 0 \ +} +#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 (0x0022) + +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 -Naur linux-2.4.24.original/drivers/scsi/pti_stdev.h linux-2.4.24/drivers/scsi/pti_stdev.h --- linux-2.4.24.original/drivers/scsi/pti_stdev.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.24/drivers/scsi/pti_stdev.h 2004-01-12 22:32:36.000000000 +0100 @@ -0,0 +1,264 @@ +/*+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 + +#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<= 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 */ +