/*
 * Promise SuperTrak device driver for Linux, version 1.34
 * 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$
 */

/*
 * 2004-01-13:	Removed legacy code for Linux 2.0 and Linux 2.2,
 * 		Daniel Baumann (daniel.baumann@panthera-systems.net)
 */


/**************************************************************************
 * File: pti_st.h       Driver Declaraitons for pti_st.c. 
 **************************************************************************/

#if 0
#include "i2omstor.h"
#include "i2oexec.h"
#else
#include "i2odef.h"
#endif

#ifndef _pti_st_h
#define _pti_st_h

#ifndef LINUX_VERSION_CODE
#include <linux/version.h>
#endif

/* 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 *);


#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,                                           \
}


#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;

  spinlock_t               spin_lock;
  volatile unsigned char   cpu_lock_count[NR_CPUS];

  /*
   * 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 */
  
  struct pci_dev          *pdev;

  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 */

