Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,4 @@
# Makefile for the NCR/SYMBIOS/LSI 53C8XX PCI SCSI controllers driver.
sym53c8xx-objs := sym_fw.o sym_glue.o sym_hipd.o sym_malloc.o sym_nvram.o
obj-$(CONFIG_SCSI_SYM53C8XX_2) := sym53c8xx.o

View file

@ -0,0 +1,215 @@
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
*
* Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
*
* This driver is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-2000 Gerard Roudier
*
* The sym53c8xx driver is derived from the ncr53c8xx driver that had been
* a port of the FreeBSD ncr driver to Linux-1.2.13.
*
* The original ncr driver has been written for 386bsd and FreeBSD by
* Wolfgang Stanglmeier <wolf@cologne.de>
* Stefan Esser <se@mi.Uni-Koeln.de>
* Copyright (C) 1994 Wolfgang Stanglmeier
*
* Other major contributions:
*
* NVRAM detection and reading.
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
*
* 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
*/
#ifndef SYM53C8XX_H
#define SYM53C8XX_H
/*
* DMA addressing mode.
*
* 0 : 32 bit addressing for all chips.
* 1 : 40 bit addressing when supported by chip.
* 2 : 64 bit addressing when supported by chip,
* limited to 16 segments of 4 GB -> 64 GB max.
*/
#define SYM_CONF_DMA_ADDRESSING_MODE CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE
/*
* NVRAM support.
*/
#if 1
#define SYM_CONF_NVRAM_SUPPORT (1)
#endif
/*
* These options are not tunable from 'make config'
*/
#if 1
#define SYM_LINUX_PROC_INFO_SUPPORT
#define SYM_LINUX_USER_COMMAND_SUPPORT
#define SYM_LINUX_USER_INFO_SUPPORT
#define SYM_LINUX_DEBUG_CONTROL_SUPPORT
#endif
/*
* Also handle old NCR chips if not (0).
*/
#define SYM_CONF_GENERIC_SUPPORT (1)
/*
* Allow tags from 2 to 256, default 8
*/
#ifndef CONFIG_SCSI_SYM53C8XX_MAX_TAGS
#define CONFIG_SCSI_SYM53C8XX_MAX_TAGS (8)
#endif
#if CONFIG_SCSI_SYM53C8XX_MAX_TAGS < 2
#define SYM_CONF_MAX_TAG (2)
#elif CONFIG_SCSI_SYM53C8XX_MAX_TAGS > 256
#define SYM_CONF_MAX_TAG (256)
#else
#define SYM_CONF_MAX_TAG CONFIG_SCSI_SYM53C8XX_MAX_TAGS
#endif
#ifndef CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS
#define CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS SYM_CONF_MAX_TAG
#endif
/*
* Anyway, we configure the driver for at least 64 tags per LUN. :)
*/
#if SYM_CONF_MAX_TAG <= 64
#define SYM_CONF_MAX_TAG_ORDER (6)
#elif SYM_CONF_MAX_TAG <= 128
#define SYM_CONF_MAX_TAG_ORDER (7)
#else
#define SYM_CONF_MAX_TAG_ORDER (8)
#endif
/*
* Max number of SG entries.
*/
#define SYM_CONF_MAX_SG (96)
/*
* Driver setup structure.
*
* This structure is initialized from linux config options.
* It can be overridden at boot-up by the boot command line.
*/
struct sym_driver_setup {
u_short max_tag;
u_char burst_order;
u_char scsi_led;
u_char scsi_diff;
u_char irq_mode;
u_char scsi_bus_check;
u_char host_id;
u_char verbose;
u_char settle_delay;
u_char use_nvram;
u_long excludes[8];
};
#define SYM_SETUP_MAX_TAG sym_driver_setup.max_tag
#define SYM_SETUP_BURST_ORDER sym_driver_setup.burst_order
#define SYM_SETUP_SCSI_LED sym_driver_setup.scsi_led
#define SYM_SETUP_SCSI_DIFF sym_driver_setup.scsi_diff
#define SYM_SETUP_IRQ_MODE sym_driver_setup.irq_mode
#define SYM_SETUP_SCSI_BUS_CHECK sym_driver_setup.scsi_bus_check
#define SYM_SETUP_HOST_ID sym_driver_setup.host_id
#define boot_verbose sym_driver_setup.verbose
/*
* Initial setup.
*
* Can be overriden at startup by a command line.
*/
#define SYM_LINUX_DRIVER_SETUP { \
.max_tag = CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS, \
.burst_order = 7, \
.scsi_led = 1, \
.scsi_diff = 1, \
.irq_mode = 0, \
.scsi_bus_check = 1, \
.host_id = 7, \
.verbose = 0, \
.settle_delay = 3, \
.use_nvram = 1, \
}
extern struct sym_driver_setup sym_driver_setup;
extern unsigned int sym_debug_flags;
#define DEBUG_FLAGS sym_debug_flags
/*
* Max number of targets.
* Maximum is 16 and you are advised not to change this value.
*/
#ifndef SYM_CONF_MAX_TARGET
#define SYM_CONF_MAX_TARGET (16)
#endif
/*
* Max number of logical units.
* SPI-2 allows up to 64 logical units, but in real life, target
* that implements more that 7 logical units are pretty rare.
* Anyway, the cost of accepting up to 64 logical unit is low in
* this driver, thus going with the maximum is acceptable.
*/
#ifndef SYM_CONF_MAX_LUN
#define SYM_CONF_MAX_LUN (64)
#endif
/*
* Max number of IO control blocks queued to the controller.
* Each entry needs 8 bytes and the queues are allocated contiguously.
* Since we donnot want to allocate more than a page, the theorical
* maximum is PAGE_SIZE/8. For safety, we announce a bit less to the
* access method. :)
* When not supplied, as it is suggested, the driver compute some
* good value for this parameter.
*/
/* #define SYM_CONF_MAX_START (PAGE_SIZE/8 - 16) */
/*
* Support for Immediate Arbitration.
* Not advised.
*/
/* #define SYM_CONF_IARB_SUPPORT */
/*
* Only relevant if IARB support configured.
* - Max number of successive settings of IARB hints.
* - Set IARB on arbitration lost.
*/
#define SYM_CONF_IARB_MAX 3
#define SYM_CONF_SET_IARB_ON_ARB_LOST 1
/*
* Returning wrong residuals may make problems.
* When zero, this define tells the driver to
* always return 0 as transfer residual.
* Btw, all my testings of residuals have succeeded.
*/
#define SYM_SETUP_RESIDUAL_SUPPORT 1
#endif /* SYM53C8XX_H */

View file

@ -0,0 +1,792 @@
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
*
* Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
*
* This driver is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-2000 Gerard Roudier
*
* The sym53c8xx driver is derived from the ncr53c8xx driver that had been
* a port of the FreeBSD ncr driver to Linux-1.2.13.
*
* The original ncr driver has been written for 386bsd and FreeBSD by
* Wolfgang Stanglmeier <wolf@cologne.de>
* Stefan Esser <se@mi.Uni-Koeln.de>
* Copyright (C) 1994 Wolfgang Stanglmeier
*
* Other major contributions:
*
* NVRAM detection and reading.
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
*
* 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
*/
#ifndef SYM_DEFS_H
#define SYM_DEFS_H
#define SYM_VERSION "2.2.3"
#define SYM_DRIVER_NAME "sym-" SYM_VERSION
/*
* SYM53C8XX device features descriptor.
*/
struct sym_chip {
u_short device_id;
u_short revision_id;
char *name;
u_char burst_max; /* log-base-2 of max burst */
u_char offset_max;
u_char nr_divisor;
u_char lp_probe_bit;
u_int features;
#define FE_LED0 (1<<0)
#define FE_WIDE (1<<1) /* Wide data transfers */
#define FE_ULTRA (1<<2) /* Ultra speed 20Mtrans/sec */
#define FE_ULTRA2 (1<<3) /* Ultra 2 - 40 Mtrans/sec */
#define FE_DBLR (1<<4) /* Clock doubler present */
#define FE_QUAD (1<<5) /* Clock quadrupler present */
#define FE_ERL (1<<6) /* Enable read line */
#define FE_CLSE (1<<7) /* Cache line size enable */
#define FE_WRIE (1<<8) /* Write & Invalidate enable */
#define FE_ERMP (1<<9) /* Enable read multiple */
#define FE_BOF (1<<10) /* Burst opcode fetch */
#define FE_DFS (1<<11) /* DMA fifo size */
#define FE_PFEN (1<<12) /* Prefetch enable */
#define FE_LDSTR (1<<13) /* Load/Store supported */
#define FE_RAM (1<<14) /* On chip RAM present */
#define FE_VARCLK (1<<15) /* Clock frequency may vary */
#define FE_RAM8K (1<<16) /* On chip RAM sized 8Kb */
#define FE_64BIT (1<<17) /* 64-bit PCI BUS interface */
#define FE_IO256 (1<<18) /* Requires full 256 bytes in PCI space */
#define FE_NOPM (1<<19) /* Scripts handles phase mismatch */
#define FE_LEDC (1<<20) /* Hardware control of LED */
#define FE_ULTRA3 (1<<21) /* Ultra 3 - 80 Mtrans/sec DT */
#define FE_66MHZ (1<<22) /* 66MHz PCI support */
#define FE_CRC (1<<23) /* CRC support */
#define FE_DIFF (1<<24) /* SCSI HVD support */
#define FE_DFBC (1<<25) /* Have DFBC register */
#define FE_LCKFRQ (1<<26) /* Have LCKFRQ */
#define FE_C10 (1<<27) /* Various C10 core (mis)features */
#define FE_U3EN (1<<28) /* U3EN bit usable */
#define FE_DAC (1<<29) /* Support PCI DAC (64 bit addressing) */
#define FE_ISTAT1 (1<<30) /* Have ISTAT1, MBOX0, MBOX1 registers */
#define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP)
#define FE_CACHE0_SET (FE_CACHE_SET & ~FE_ERL)
};
/*
* SYM53C8XX IO register data structure.
*/
struct sym_reg {
/*00*/ u8 nc_scntl0; /* full arb., ena parity, par->ATN */
/*01*/ u8 nc_scntl1; /* no reset */
#define ISCON 0x10 /* connected to scsi */
#define CRST 0x08 /* force reset */
#define IARB 0x02 /* immediate arbitration */
/*02*/ u8 nc_scntl2; /* no disconnect expected */
#define SDU 0x80 /* cmd: disconnect will raise error */
#define CHM 0x40 /* sta: chained mode */
#define WSS 0x08 /* sta: wide scsi send [W]*/
#define WSR 0x01 /* sta: wide scsi received [W]*/
/*03*/ u8 nc_scntl3; /* cnf system clock dependent */
#define EWS 0x08 /* cmd: enable wide scsi [W]*/
#define ULTRA 0x80 /* cmd: ULTRA enable */
/* bits 0-2, 7 rsvd for C1010 */
/*04*/ u8 nc_scid; /* cnf host adapter scsi address */
#define RRE 0x40 /* r/w:e enable response to resel. */
#define SRE 0x20 /* r/w:e enable response to select */
/*05*/ u8 nc_sxfer; /* ### Sync speed and count */
/* bits 6-7 rsvd for C1010 */
/*06*/ u8 nc_sdid; /* ### Destination-ID */
/*07*/ u8 nc_gpreg; /* ??? IO-Pins */
/*08*/ u8 nc_sfbr; /* ### First byte received */
/*09*/ u8 nc_socl;
#define CREQ 0x80 /* r/w: SCSI-REQ */
#define CACK 0x40 /* r/w: SCSI-ACK */
#define CBSY 0x20 /* r/w: SCSI-BSY */
#define CSEL 0x10 /* r/w: SCSI-SEL */
#define CATN 0x08 /* r/w: SCSI-ATN */
#define CMSG 0x04 /* r/w: SCSI-MSG */
#define CC_D 0x02 /* r/w: SCSI-C_D */
#define CI_O 0x01 /* r/w: SCSI-I_O */
/*0a*/ u8 nc_ssid;
/*0b*/ u8 nc_sbcl;
/*0c*/ u8 nc_dstat;
#define DFE 0x80 /* sta: dma fifo empty */
#define MDPE 0x40 /* int: master data parity error */
#define BF 0x20 /* int: script: bus fault */
#define ABRT 0x10 /* int: script: command aborted */
#define SSI 0x08 /* int: script: single step */
#define SIR 0x04 /* int: script: interrupt instruct. */
#define IID 0x01 /* int: script: illegal instruct. */
/*0d*/ u8 nc_sstat0;
#define ILF 0x80 /* sta: data in SIDL register lsb */
#define ORF 0x40 /* sta: data in SODR register lsb */
#define OLF 0x20 /* sta: data in SODL register lsb */
#define AIP 0x10 /* sta: arbitration in progress */
#define LOA 0x08 /* sta: arbitration lost */
#define WOA 0x04 /* sta: arbitration won */
#define IRST 0x02 /* sta: scsi reset signal */
#define SDP 0x01 /* sta: scsi parity signal */
/*0e*/ u8 nc_sstat1;
#define FF3210 0xf0 /* sta: bytes in the scsi fifo */
/*0f*/ u8 nc_sstat2;
#define ILF1 0x80 /* sta: data in SIDL register msb[W]*/
#define ORF1 0x40 /* sta: data in SODR register msb[W]*/
#define OLF1 0x20 /* sta: data in SODL register msb[W]*/
#define DM 0x04 /* sta: DIFFSENS mismatch (895/6 only) */
#define LDSC 0x02 /* sta: disconnect & reconnect */
/*10*/ u8 nc_dsa; /* --> Base page */
/*11*/ u8 nc_dsa1;
/*12*/ u8 nc_dsa2;
/*13*/ u8 nc_dsa3;
/*14*/ u8 nc_istat; /* --> Main Command and status */
#define CABRT 0x80 /* cmd: abort current operation */
#define SRST 0x40 /* mod: reset chip */
#define SIGP 0x20 /* r/w: message from host to script */
#define SEM 0x10 /* r/w: message between host + script */
#define CON 0x08 /* sta: connected to scsi */
#define INTF 0x04 /* sta: int on the fly (reset by wr)*/
#define SIP 0x02 /* sta: scsi-interrupt */
#define DIP 0x01 /* sta: host/script interrupt */
/*15*/ u8 nc_istat1; /* 896 only */
#define FLSH 0x04 /* sta: chip is flushing */
#define SCRUN 0x02 /* sta: scripts are running */
#define SIRQD 0x01 /* r/w: disable INT pin */
/*16*/ u8 nc_mbox0; /* 896 only */
/*17*/ u8 nc_mbox1; /* 896 only */
/*18*/ u8 nc_ctest0;
/*19*/ u8 nc_ctest1;
/*1a*/ u8 nc_ctest2;
#define CSIGP 0x40
/* bits 0-2,7 rsvd for C1010 */
/*1b*/ u8 nc_ctest3;
#define FLF 0x08 /* cmd: flush dma fifo */
#define CLF 0x04 /* cmd: clear dma fifo */
#define FM 0x02 /* mod: fetch pin mode */
#define WRIE 0x01 /* mod: write and invalidate enable */
/* bits 4-7 rsvd for C1010 */
/*1c*/ u32 nc_temp; /* ### Temporary stack */
/*20*/ u8 nc_dfifo;
/*21*/ u8 nc_ctest4;
#define BDIS 0x80 /* mod: burst disable */
#define MPEE 0x08 /* mod: master parity error enable */
/*22*/ u8 nc_ctest5;
#define DFS 0x20 /* mod: dma fifo size */
/* bits 0-1, 3-7 rsvd for C1010 */
/*23*/ u8 nc_ctest6;
/*24*/ u32 nc_dbc; /* ### Byte count and command */
/*28*/ u32 nc_dnad; /* ### Next command register */
/*2c*/ u32 nc_dsp; /* --> Script Pointer */
/*30*/ u32 nc_dsps; /* --> Script pointer save/opcode#2 */
/*34*/ u8 nc_scratcha; /* Temporary register a */
/*35*/ u8 nc_scratcha1;
/*36*/ u8 nc_scratcha2;
/*37*/ u8 nc_scratcha3;
/*38*/ u8 nc_dmode;
#define BL_2 0x80 /* mod: burst length shift value +2 */
#define BL_1 0x40 /* mod: burst length shift value +1 */
#define ERL 0x08 /* mod: enable read line */
#define ERMP 0x04 /* mod: enable read multiple */
#define BOF 0x02 /* mod: burst op code fetch */
/*39*/ u8 nc_dien;
/*3a*/ u8 nc_sbr;
/*3b*/ u8 nc_dcntl; /* --> Script execution control */
#define CLSE 0x80 /* mod: cache line size enable */
#define PFF 0x40 /* cmd: pre-fetch flush */
#define PFEN 0x20 /* mod: pre-fetch enable */
#define SSM 0x10 /* mod: single step mode */
#define IRQM 0x08 /* mod: irq mode (1 = totem pole !) */
#define STD 0x04 /* cmd: start dma mode */
#define IRQD 0x02 /* mod: irq disable */
#define NOCOM 0x01 /* cmd: protect sfbr while reselect */
/* bits 0-1 rsvd for C1010 */
/*3c*/ u32 nc_adder;
/*40*/ u16 nc_sien; /* -->: interrupt enable */
/*42*/ u16 nc_sist; /* <--: interrupt status */
#define SBMC 0x1000/* sta: SCSI Bus Mode Change (895/6 only) */
#define STO 0x0400/* sta: timeout (select) */
#define GEN 0x0200/* sta: timeout (general) */
#define HTH 0x0100/* sta: timeout (handshake) */
#define MA 0x80 /* sta: phase mismatch */
#define CMP 0x40 /* sta: arbitration complete */
#define SEL 0x20 /* sta: selected by another device */
#define RSL 0x10 /* sta: reselected by another device*/
#define SGE 0x08 /* sta: gross error (over/underflow)*/
#define UDC 0x04 /* sta: unexpected disconnect */
#define RST 0x02 /* sta: scsi bus reset detected */
#define PAR 0x01 /* sta: scsi parity error */
/*44*/ u8 nc_slpar;
/*45*/ u8 nc_swide;
/*46*/ u8 nc_macntl;
/*47*/ u8 nc_gpcntl;
/*48*/ u8 nc_stime0; /* cmd: timeout for select&handshake*/
/*49*/ u8 nc_stime1; /* cmd: timeout user defined */
/*4a*/ u16 nc_respid; /* sta: Reselect-IDs */
/*4c*/ u8 nc_stest0;
/*4d*/ u8 nc_stest1;
#define SCLK 0x80 /* Use the PCI clock as SCSI clock */
#define DBLEN 0x08 /* clock doubler running */
#define DBLSEL 0x04 /* clock doubler selected */
/*4e*/ u8 nc_stest2;
#define ROF 0x40 /* reset scsi offset (after gross error!) */
#define EXT 0x02 /* extended filtering */
/*4f*/ u8 nc_stest3;
#define TE 0x80 /* c: tolerAnt enable */
#define HSC 0x20 /* c: Halt SCSI Clock */
#define CSF 0x02 /* c: clear scsi fifo */
/*50*/ u16 nc_sidl; /* Lowlevel: latched from scsi data */
/*52*/ u8 nc_stest4;
#define SMODE 0xc0 /* SCSI bus mode (895/6 only) */
#define SMODE_HVD 0x40 /* High Voltage Differential */
#define SMODE_SE 0x80 /* Single Ended */
#define SMODE_LVD 0xc0 /* Low Voltage Differential */
#define LCKFRQ 0x20 /* Frequency Lock (895/6 only) */
/* bits 0-5 rsvd for C1010 */
/*53*/ u8 nc_53_;
/*54*/ u16 nc_sodl; /* Lowlevel: data out to scsi data */
/*56*/ u8 nc_ccntl0; /* Chip Control 0 (896) */
#define ENPMJ 0x80 /* Enable Phase Mismatch Jump */
#define PMJCTL 0x40 /* Phase Mismatch Jump Control */
#define ENNDJ 0x20 /* Enable Non Data PM Jump */
#define DISFC 0x10 /* Disable Auto FIFO Clear */
#define DILS 0x02 /* Disable Internal Load/Store */
#define DPR 0x01 /* Disable Pipe Req */
/*57*/ u8 nc_ccntl1; /* Chip Control 1 (896) */
#define ZMOD 0x80 /* High Impedance Mode */
#define DDAC 0x08 /* Disable Dual Address Cycle */
#define XTIMOD 0x04 /* 64-bit Table Ind. Indexing Mode */
#define EXTIBMV 0x02 /* Enable 64-bit Table Ind. BMOV */
#define EXDBMV 0x01 /* Enable 64-bit Direct BMOV */
/*58*/ u16 nc_sbdl; /* Lowlevel: data from scsi data */
/*5a*/ u16 nc_5a_;
/*5c*/ u8 nc_scr0; /* Working register B */
/*5d*/ u8 nc_scr1;
/*5e*/ u8 nc_scr2;
/*5f*/ u8 nc_scr3;
/*60*/ u8 nc_scrx[64]; /* Working register C-R */
/*a0*/ u32 nc_mmrs; /* Memory Move Read Selector */
/*a4*/ u32 nc_mmws; /* Memory Move Write Selector */
/*a8*/ u32 nc_sfs; /* Script Fetch Selector */
/*ac*/ u32 nc_drs; /* DSA Relative Selector */
/*b0*/ u32 nc_sbms; /* Static Block Move Selector */
/*b4*/ u32 nc_dbms; /* Dynamic Block Move Selector */
/*b8*/ u32 nc_dnad64; /* DMA Next Address 64 */
/*bc*/ u16 nc_scntl4; /* C1010 only */
#define U3EN 0x80 /* Enable Ultra 3 */
#define AIPCKEN 0x40 /* AIP checking enable */
/* Also enable AIP generation on C10-33*/
#define XCLKH_DT 0x08 /* Extra clock of data hold on DT edge */
#define XCLKH_ST 0x04 /* Extra clock of data hold on ST edge */
#define XCLKS_DT 0x02 /* Extra clock of data set on DT edge */
#define XCLKS_ST 0x01 /* Extra clock of data set on ST edge */
/*be*/ u8 nc_aipcntl0; /* AIP Control 0 C1010 only */
/*bf*/ u8 nc_aipcntl1; /* AIP Control 1 C1010 only */
#define DISAIP 0x08 /* Disable AIP generation C10-66 only */
/*c0*/ u32 nc_pmjad1; /* Phase Mismatch Jump Address 1 */
/*c4*/ u32 nc_pmjad2; /* Phase Mismatch Jump Address 2 */
/*c8*/ u8 nc_rbc; /* Remaining Byte Count */
/*c9*/ u8 nc_rbc1;
/*ca*/ u8 nc_rbc2;
/*cb*/ u8 nc_rbc3;
/*cc*/ u8 nc_ua; /* Updated Address */
/*cd*/ u8 nc_ua1;
/*ce*/ u8 nc_ua2;
/*cf*/ u8 nc_ua3;
/*d0*/ u32 nc_esa; /* Entry Storage Address */
/*d4*/ u8 nc_ia; /* Instruction Address */
/*d5*/ u8 nc_ia1;
/*d6*/ u8 nc_ia2;
/*d7*/ u8 nc_ia3;
/*d8*/ u32 nc_sbc; /* SCSI Byte Count (3 bytes only) */
/*dc*/ u32 nc_csbc; /* Cumulative SCSI Byte Count */
/* Following for C1010 only */
/*e0*/ u16 nc_crcpad; /* CRC Value */
/*e2*/ u8 nc_crccntl0; /* CRC control register */
#define SNDCRC 0x10 /* Send CRC Request */
/*e3*/ u8 nc_crccntl1; /* CRC control register */
/*e4*/ u32 nc_crcdata; /* CRC data register */
/*e8*/ u32 nc_e8_;
/*ec*/ u32 nc_ec_;
/*f0*/ u16 nc_dfbc; /* DMA FIFO byte count */
};
/*-----------------------------------------------------------
*
* Utility macros for the script.
*
*-----------------------------------------------------------
*/
#define REGJ(p,r) (offsetof(struct sym_reg, p ## r))
#define REG(r) REGJ (nc_, r)
/*-----------------------------------------------------------
*
* SCSI phases
*
*-----------------------------------------------------------
*/
#define SCR_DATA_OUT 0x00000000
#define SCR_DATA_IN 0x01000000
#define SCR_COMMAND 0x02000000
#define SCR_STATUS 0x03000000
#define SCR_DT_DATA_OUT 0x04000000
#define SCR_DT_DATA_IN 0x05000000
#define SCR_MSG_OUT 0x06000000
#define SCR_MSG_IN 0x07000000
/* DT phases are illegal for non Ultra3 mode */
#define SCR_ILG_OUT 0x04000000
#define SCR_ILG_IN 0x05000000
/*-----------------------------------------------------------
*
* Data transfer via SCSI.
*
*-----------------------------------------------------------
*
* MOVE_ABS (LEN)
* <<start address>>
*
* MOVE_IND (LEN)
* <<dnad_offset>>
*
* MOVE_TBL
* <<dnad_offset>>
*
*-----------------------------------------------------------
*/
#define OPC_MOVE 0x08000000
#define SCR_MOVE_ABS(l) ((0x00000000 | OPC_MOVE) | (l))
/* #define SCR_MOVE_IND(l) ((0x20000000 | OPC_MOVE) | (l)) */
#define SCR_MOVE_TBL (0x10000000 | OPC_MOVE)
#define SCR_CHMOV_ABS(l) ((0x00000000) | (l))
/* #define SCR_CHMOV_IND(l) ((0x20000000) | (l)) */
#define SCR_CHMOV_TBL (0x10000000)
#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
/* We steal the `indirect addressing' flag for target mode MOVE in scripts */
#define OPC_TCHMOVE 0x08000000
#define SCR_TCHMOVE_ABS(l) ((0x20000000 | OPC_TCHMOVE) | (l))
#define SCR_TCHMOVE_TBL (0x30000000 | OPC_TCHMOVE)
#define SCR_TMOV_ABS(l) ((0x20000000) | (l))
#define SCR_TMOV_TBL (0x30000000)
#endif
struct sym_tblmove {
u32 size;
u32 addr;
};
/*-----------------------------------------------------------
*
* Selection
*
*-----------------------------------------------------------
*
* SEL_ABS | SCR_ID (0..15) [ | REL_JMP]
* <<alternate_address>>
*
* SEL_TBL | << dnad_offset>> [ | REL_JMP]
* <<alternate_address>>
*
*-----------------------------------------------------------
*/
#define SCR_SEL_ABS 0x40000000
#define SCR_SEL_ABS_ATN 0x41000000
#define SCR_SEL_TBL 0x42000000
#define SCR_SEL_TBL_ATN 0x43000000
#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
#define SCR_RESEL_ABS 0x40000000
#define SCR_RESEL_ABS_ATN 0x41000000
#define SCR_RESEL_TBL 0x42000000
#define SCR_RESEL_TBL_ATN 0x43000000
#endif
struct sym_tblsel {
u_char sel_scntl4; /* C1010 only */
u_char sel_sxfer;
u_char sel_id;
u_char sel_scntl3;
};
#define SCR_JMP_REL 0x04000000
#define SCR_ID(id) (((u32)(id)) << 16)
/*-----------------------------------------------------------
*
* Waiting for Disconnect or Reselect
*
*-----------------------------------------------------------
*
* WAIT_DISC
* dummy: <<alternate_address>>
*
* WAIT_RESEL
* <<alternate_address>>
*
*-----------------------------------------------------------
*/
#define SCR_WAIT_DISC 0x48000000
#define SCR_WAIT_RESEL 0x50000000
#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
#define SCR_DISCONNECT 0x48000000
#endif
/*-----------------------------------------------------------
*
* Bit Set / Reset
*
*-----------------------------------------------------------
*
* SET (flags {|.. })
*
* CLR (flags {|.. })
*
*-----------------------------------------------------------
*/
#define SCR_SET(f) (0x58000000 | (f))
#define SCR_CLR(f) (0x60000000 | (f))
#define SCR_CARRY 0x00000400
#define SCR_TRG 0x00000200
#define SCR_ACK 0x00000040
#define SCR_ATN 0x00000008
/*-----------------------------------------------------------
*
* Memory to memory move
*
*-----------------------------------------------------------
*
* COPY (bytecount)
* << source_address >>
* << destination_address >>
*
* SCR_COPY sets the NO FLUSH option by default.
* SCR_COPY_F does not set this option.
*
* For chips which do not support this option,
* sym_fw_bind_script() will remove this bit.
*
*-----------------------------------------------------------
*/
#define SCR_NO_FLUSH 0x01000000
#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n))
#define SCR_COPY_F(n) (0xc0000000 | (n))
/*-----------------------------------------------------------
*
* Register move and binary operations
*
*-----------------------------------------------------------
*
* SFBR_REG (reg, op, data) reg = SFBR op data
* << 0 >>
*
* REG_SFBR (reg, op, data) SFBR = reg op data
* << 0 >>
*
* REG_REG (reg, op, data) reg = reg op data
* << 0 >>
*
*-----------------------------------------------------------
*
* On 825A, 875, 895 and 896 chips the content
* of SFBR register can be used as data (SCR_SFBR_DATA).
* The 896 has additionnal IO registers starting at
* offset 0x80. Bit 7 of register offset is stored in
* bit 7 of the SCRIPTS instruction first DWORD.
*
*-----------------------------------------------------------
*/
#define SCR_REG_OFS(ofs) ((((ofs) & 0x7f) << 16ul) + ((ofs) & 0x80))
#define SCR_SFBR_REG(reg,op,data) \
(0x68000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul))
#define SCR_REG_SFBR(reg,op,data) \
(0x70000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul))
#define SCR_REG_REG(reg,op,data) \
(0x78000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul))
#define SCR_LOAD 0x00000000
#define SCR_SHL 0x01000000
#define SCR_OR 0x02000000
#define SCR_XOR 0x03000000
#define SCR_AND 0x04000000
#define SCR_SHR 0x05000000
#define SCR_ADD 0x06000000
#define SCR_ADDC 0x07000000
#define SCR_SFBR_DATA (0x00800000>>8ul) /* Use SFBR as data */
/*-----------------------------------------------------------
*
* FROM_REG (reg) SFBR = reg
* << 0 >>
*
* TO_REG (reg) reg = SFBR
* << 0 >>
*
* LOAD_REG (reg, data) reg = <data>
* << 0 >>
*
* LOAD_SFBR(data) SFBR = <data>
* << 0 >>
*
*-----------------------------------------------------------
*/
#define SCR_FROM_REG(reg) \
SCR_REG_SFBR(reg,SCR_OR,0)
#define SCR_TO_REG(reg) \
SCR_SFBR_REG(reg,SCR_OR,0)
#define SCR_LOAD_REG(reg,data) \
SCR_REG_REG(reg,SCR_LOAD,data)
#define SCR_LOAD_SFBR(data) \
(SCR_REG_SFBR (gpreg, SCR_LOAD, data))
/*-----------------------------------------------------------
*
* LOAD from memory to register.
* STORE from register to memory.
*
* Only supported by 810A, 860, 825A, 875, 895 and 896.
*
*-----------------------------------------------------------
*
* LOAD_ABS (LEN)
* <<start address>>
*
* LOAD_REL (LEN) (DSA relative)
* <<dsa_offset>>
*
*-----------------------------------------------------------
*/
#define SCR_REG_OFS2(ofs) (((ofs) & 0xff) << 16ul)
#define SCR_NO_FLUSH2 0x02000000
#define SCR_DSA_REL2 0x10000000
#define SCR_LOAD_R(reg, how, n) \
(0xe1000000 | how | (SCR_REG_OFS2(REG(reg))) | (n))
#define SCR_STORE_R(reg, how, n) \
(0xe0000000 | how | (SCR_REG_OFS2(REG(reg))) | (n))
#define SCR_LOAD_ABS(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2, n)
#define SCR_LOAD_REL(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2, n)
#define SCR_LOAD_ABS_F(reg, n) SCR_LOAD_R(reg, 0, n)
#define SCR_LOAD_REL_F(reg, n) SCR_LOAD_R(reg, SCR_DSA_REL2, n)
#define SCR_STORE_ABS(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2, n)
#define SCR_STORE_REL(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2,n)
#define SCR_STORE_ABS_F(reg, n) SCR_STORE_R(reg, 0, n)
#define SCR_STORE_REL_F(reg, n) SCR_STORE_R(reg, SCR_DSA_REL2, n)
/*-----------------------------------------------------------
*
* Waiting for Disconnect or Reselect
*
*-----------------------------------------------------------
*
* JUMP [ | IFTRUE/IFFALSE ( ... ) ]
* <<address>>
*
* JUMPR [ | IFTRUE/IFFALSE ( ... ) ]
* <<distance>>
*
* CALL [ | IFTRUE/IFFALSE ( ... ) ]
* <<address>>
*
* CALLR [ | IFTRUE/IFFALSE ( ... ) ]
* <<distance>>
*
* RETURN [ | IFTRUE/IFFALSE ( ... ) ]
* <<dummy>>
*
* INT [ | IFTRUE/IFFALSE ( ... ) ]
* <<ident>>
*
* INT_FLY [ | IFTRUE/IFFALSE ( ... ) ]
* <<ident>>
*
* Conditions:
* WHEN (phase)
* IF (phase)
* CARRYSET
* DATA (data, mask)
*
*-----------------------------------------------------------
*/
#define SCR_NO_OP 0x80000000
#define SCR_JUMP 0x80080000
#define SCR_JUMP64 0x80480000
#define SCR_JUMPR 0x80880000
#define SCR_CALL 0x88080000
#define SCR_CALLR 0x88880000
#define SCR_RETURN 0x90080000
#define SCR_INT 0x98080000
#define SCR_INT_FLY 0x98180000
#define IFFALSE(arg) (0x00080000 | (arg))
#define IFTRUE(arg) (0x00000000 | (arg))
#define WHEN(phase) (0x00030000 | (phase))
#define IF(phase) (0x00020000 | (phase))
#define DATA(D) (0x00040000 | ((D) & 0xff))
#define MASK(D,M) (0x00040000 | (((M ^ 0xff) & 0xff) << 8ul)|((D) & 0xff))
#define CARRYSET (0x00200000)
/*-----------------------------------------------------------
*
* SCSI constants.
*
*-----------------------------------------------------------
*/
/*
* Messages
*/
#define M_COMPLETE COMMAND_COMPLETE
#define M_EXTENDED EXTENDED_MESSAGE
#define M_SAVE_DP SAVE_POINTERS
#define M_RESTORE_DP RESTORE_POINTERS
#define M_DISCONNECT DISCONNECT
#define M_ID_ERROR INITIATOR_ERROR
#define M_ABORT ABORT_TASK_SET
#define M_REJECT MESSAGE_REJECT
#define M_NOOP NOP
#define M_PARITY MSG_PARITY_ERROR
#define M_LCOMPLETE LINKED_CMD_COMPLETE
#define M_FCOMPLETE LINKED_FLG_CMD_COMPLETE
#define M_RESET TARGET_RESET
#define M_ABORT_TAG ABORT_TASK
#define M_CLEAR_QUEUE CLEAR_TASK_SET
#define M_INIT_REC INITIATE_RECOVERY
#define M_REL_REC RELEASE_RECOVERY
#define M_TERMINATE (0x11)
#define M_SIMPLE_TAG SIMPLE_QUEUE_TAG
#define M_HEAD_TAG HEAD_OF_QUEUE_TAG
#define M_ORDERED_TAG ORDERED_QUEUE_TAG
#define M_IGN_RESIDUE IGNORE_WIDE_RESIDUE
#define M_X_MODIFY_DP EXTENDED_MODIFY_DATA_POINTER
#define M_X_SYNC_REQ EXTENDED_SDTR
#define M_X_WIDE_REQ EXTENDED_WDTR
#define M_X_PPR_REQ EXTENDED_PPR
/*
* PPR protocol options
*/
#define PPR_OPT_IU (0x01)
#define PPR_OPT_DT (0x02)
#define PPR_OPT_QAS (0x04)
#define PPR_OPT_MASK (0x07)
/*
* Status
*/
#define S_GOOD SAM_STAT_GOOD
#define S_CHECK_COND SAM_STAT_CHECK_CONDITION
#define S_COND_MET SAM_STAT_CONDITION_MET
#define S_BUSY SAM_STAT_BUSY
#define S_INT SAM_STAT_INTERMEDIATE
#define S_INT_COND_MET SAM_STAT_INTERMEDIATE_CONDITION_MET
#define S_CONFLICT SAM_STAT_RESERVATION_CONFLICT
#define S_TERMINATED SAM_STAT_COMMAND_TERMINATED
#define S_QUEUE_FULL SAM_STAT_TASK_SET_FULL
#define S_ILLEGAL (0xff)
#endif /* defined SYM_DEFS_H */

View file

@ -0,0 +1,554 @@
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
*
* Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
*
* This driver is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-2000 Gerard Roudier
*
* The sym53c8xx driver is derived from the ncr53c8xx driver that had been
* a port of the FreeBSD ncr driver to Linux-1.2.13.
*
* The original ncr driver has been written for 386bsd and FreeBSD by
* Wolfgang Stanglmeier <wolf@cologne.de>
* Stefan Esser <se@mi.Uni-Koeln.de>
* Copyright (C) 1994 Wolfgang Stanglmeier
*
* Other major contributions:
*
* NVRAM detection and reading.
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
*
* 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
*/
#include "sym_glue.h"
/*
* Macros used for all firmwares.
*/
#define SYM_GEN_A(s, label) ((short) offsetof(s, label)),
#define SYM_GEN_B(s, label) ((short) offsetof(s, label)),
#define SYM_GEN_Z(s, label) ((short) offsetof(s, label)),
#define PADDR_A(label) SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label)
#define PADDR_B(label) SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label)
#if SYM_CONF_GENERIC_SUPPORT
/*
* Allocate firmware #1 script area.
*/
#define SYM_FWA_SCR sym_fw1a_scr
#define SYM_FWB_SCR sym_fw1b_scr
#define SYM_FWZ_SCR sym_fw1z_scr
#include "sym_fw1.h"
static struct sym_fwa_ofs sym_fw1a_ofs = {
SYM_GEN_FW_A(struct SYM_FWA_SCR)
};
static struct sym_fwb_ofs sym_fw1b_ofs = {
SYM_GEN_FW_B(struct SYM_FWB_SCR)
};
static struct sym_fwz_ofs sym_fw1z_ofs = {
SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
};
#undef SYM_FWA_SCR
#undef SYM_FWB_SCR
#undef SYM_FWZ_SCR
#endif /* SYM_CONF_GENERIC_SUPPORT */
/*
* Allocate firmware #2 script area.
*/
#define SYM_FWA_SCR sym_fw2a_scr
#define SYM_FWB_SCR sym_fw2b_scr
#define SYM_FWZ_SCR sym_fw2z_scr
#include "sym_fw2.h"
static struct sym_fwa_ofs sym_fw2a_ofs = {
SYM_GEN_FW_A(struct SYM_FWA_SCR)
};
static struct sym_fwb_ofs sym_fw2b_ofs = {
SYM_GEN_FW_B(struct SYM_FWB_SCR)
SYM_GEN_B(struct SYM_FWB_SCR, start64)
SYM_GEN_B(struct SYM_FWB_SCR, pm_handle)
};
static struct sym_fwz_ofs sym_fw2z_ofs = {
SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
};
#undef SYM_FWA_SCR
#undef SYM_FWB_SCR
#undef SYM_FWZ_SCR
#undef SYM_GEN_A
#undef SYM_GEN_B
#undef SYM_GEN_Z
#undef PADDR_A
#undef PADDR_B
#if SYM_CONF_GENERIC_SUPPORT
/*
* Patch routine for firmware #1.
*/
static void
sym_fw1_patch(struct Scsi_Host *shost)
{
struct sym_hcb *np = sym_get_hcb(shost);
struct sym_fw1a_scr *scripta0;
struct sym_fw1b_scr *scriptb0;
scripta0 = (struct sym_fw1a_scr *) np->scripta0;
scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
/*
* Remove LED support if not needed.
*/
if (!(np->features & FE_LED0)) {
scripta0->idle[0] = cpu_to_scr(SCR_NO_OP);
scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP);
scripta0->start[0] = cpu_to_scr(SCR_NO_OP);
}
#ifdef SYM_CONF_IARB_SUPPORT
/*
* If user does not want to use IMMEDIATE ARBITRATION
* when we are reselected while attempting to arbitrate,
* patch the SCRIPTS accordingly with a SCRIPT NO_OP.
*/
if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
#endif
/*
* Patch some data in SCRIPTS.
* - start and done queue initial bus address.
* - target bus address table bus address.
*/
scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba);
scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba);
scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba);
}
#endif /* SYM_CONF_GENERIC_SUPPORT */
/*
* Patch routine for firmware #2.
*/
static void
sym_fw2_patch(struct Scsi_Host *shost)
{
struct sym_data *sym_data = shost_priv(shost);
struct pci_dev *pdev = sym_data->pdev;
struct sym_hcb *np = sym_data->ncb;
struct sym_fw2a_scr *scripta0;
struct sym_fw2b_scr *scriptb0;
scripta0 = (struct sym_fw2a_scr *) np->scripta0;
scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
/*
* Remove LED support if not needed.
*/
if (!(np->features & FE_LED0)) {
scripta0->idle[0] = cpu_to_scr(SCR_NO_OP);
scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP);
scripta0->start[0] = cpu_to_scr(SCR_NO_OP);
}
#if SYM_CONF_DMA_ADDRESSING_MODE == 2
/*
* Remove useless 64 bit DMA specific SCRIPTS,
* when this feature is not available.
*/
if (!use_dac(np)) {
scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP);
scripta0->is_dmap_dirty[1] = 0;
scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP);
scripta0->is_dmap_dirty[3] = 0;
}
#endif
#ifdef SYM_CONF_IARB_SUPPORT
/*
* If user does not want to use IMMEDIATE ARBITRATION
* when we are reselected while attempting to arbitrate,
* patch the SCRIPTS accordingly with a SCRIPT NO_OP.
*/
if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
#endif
/*
* Patch some variable in SCRIPTS.
* - start and done queue initial bus address.
* - target bus address table bus address.
*/
scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba);
scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba);
scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba);
/*
* Remove the load of SCNTL4 on reselection if not a C10.
*/
if (!(np->features & FE_C10)) {
scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP);
scripta0->resel_scntl4[1] = cpu_to_scr(0);
}
/*
* Remove a couple of work-arounds specific to C1010 if
* they are not desirable. See `sym_fw2.h' for more details.
*/
if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_66 &&
pdev->revision < 0x1 &&
np->pciclk_khz < 60000)) {
scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP);
scripta0->datao_phase[1] = cpu_to_scr(0);
}
if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 /* &&
pdev->revision < 0xff */)) {
scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP);
scripta0->sel_done[1] = cpu_to_scr(0);
}
/*
* Patch some other variables in SCRIPTS.
* These ones are loaded by the SCRIPTS processor.
*/
scriptb0->pm0_data_addr[0] =
cpu_to_scr(np->scripta_ba +
offsetof(struct sym_fw2a_scr, pm0_data));
scriptb0->pm1_data_addr[0] =
cpu_to_scr(np->scripta_ba +
offsetof(struct sym_fw2a_scr, pm1_data));
}
/*
* Fill the data area in scripts.
* To be done for all firmwares.
*/
static void
sym_fw_fill_data (u32 *in, u32 *out)
{
int i;
for (i = 0; i < SYM_CONF_MAX_SG; i++) {
*in++ = SCR_CHMOV_TBL ^ SCR_DATA_IN;
*in++ = offsetof (struct sym_dsb, data[i]);
*out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT;
*out++ = offsetof (struct sym_dsb, data[i]);
}
}
/*
* Setup useful script bus addresses.
* To be done for all firmwares.
*/
static void
sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw)
{
u32 *pa;
u_short *po;
int i;
/*
* Build the bus address table for script A
* from the script A offset table.
*/
po = (u_short *) fw->a_ofs;
pa = (u32 *) &np->fwa_bas;
for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++)
pa[i] = np->scripta_ba + po[i];
/*
* Same for script B.
*/
po = (u_short *) fw->b_ofs;
pa = (u32 *) &np->fwb_bas;
for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++)
pa[i] = np->scriptb_ba + po[i];
/*
* Same for script Z.
*/
po = (u_short *) fw->z_ofs;
pa = (u32 *) &np->fwz_bas;
for (i = 0 ; i < sizeof(np->fwz_bas)/sizeof(u32) ; i++)
pa[i] = np->scriptz_ba + po[i];
}
#if SYM_CONF_GENERIC_SUPPORT
/*
* Setup routine for firmware #1.
*/
static void
sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw)
{
struct sym_fw1a_scr *scripta0;
struct sym_fw1b_scr *scriptb0;
scripta0 = (struct sym_fw1a_scr *) np->scripta0;
scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
/*
* Fill variable parts in scripts.
*/
sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
/*
* Setup bus addresses used from the C code..
*/
sym_fw_setup_bus_addresses(np, fw);
}
#endif /* SYM_CONF_GENERIC_SUPPORT */
/*
* Setup routine for firmware #2.
*/
static void
sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw)
{
struct sym_fw2a_scr *scripta0;
struct sym_fw2b_scr *scriptb0;
scripta0 = (struct sym_fw2a_scr *) np->scripta0;
scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
/*
* Fill variable parts in scripts.
*/
sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
/*
* Setup bus addresses used from the C code..
*/
sym_fw_setup_bus_addresses(np, fw);
}
/*
* Allocate firmware descriptors.
*/
#if SYM_CONF_GENERIC_SUPPORT
static struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic");
#endif /* SYM_CONF_GENERIC_SUPPORT */
static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based");
/*
* Find the most appropriate firmware for a chip.
*/
struct sym_fw *
sym_find_firmware(struct sym_chip *chip)
{
if (chip->features & FE_LDSTR)
return &sym_fw2;
#if SYM_CONF_GENERIC_SUPPORT
else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC)))
return &sym_fw1;
#endif
else
return NULL;
}
/*
* Bind a script to physical addresses.
*/
void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len)
{
u32 opcode, new, old, tmp1, tmp2;
u32 *end, *cur;
int relocs;
cur = start;
end = start + len/4;
while (cur < end) {
opcode = *cur;
/*
* If we forget to change the length
* in scripts, a field will be
* padded with 0. This is an illegal
* command.
*/
if (opcode == 0) {
printf ("%s: ERROR0 IN SCRIPT at %d.\n",
sym_name(np), (int) (cur-start));
++cur;
continue;
};
/*
* We use the bogus value 0xf00ff00f ;-)
* to reserve data area in SCRIPTS.
*/
if (opcode == SCR_DATA_ZERO) {
*cur++ = 0;
continue;
}
if (DEBUG_FLAGS & DEBUG_SCRIPT)
printf ("%d: <%x>\n", (int) (cur-start),
(unsigned)opcode);
/*
* We don't have to decode ALL commands
*/
switch (opcode >> 28) {
case 0xf:
/*
* LOAD / STORE DSA relative, don't relocate.
*/
relocs = 0;
break;
case 0xe:
/*
* LOAD / STORE absolute.
*/
relocs = 1;
break;
case 0xc:
/*
* COPY has TWO arguments.
*/
relocs = 2;
tmp1 = cur[1];
tmp2 = cur[2];
if ((tmp1 ^ tmp2) & 3) {
printf ("%s: ERROR1 IN SCRIPT at %d.\n",
sym_name(np), (int) (cur-start));
}
/*
* If PREFETCH feature not enabled, remove
* the NO FLUSH bit if present.
*/
if ((opcode & SCR_NO_FLUSH) &&
!(np->features & FE_PFEN)) {
opcode = (opcode & ~SCR_NO_FLUSH);
}
break;
case 0x0:
/*
* MOVE/CHMOV (absolute address)
*/
if (!(np->features & FE_WIDE))
opcode = (opcode | OPC_MOVE);
relocs = 1;
break;
case 0x1:
/*
* MOVE/CHMOV (table indirect)
*/
if (!(np->features & FE_WIDE))
opcode = (opcode | OPC_MOVE);
relocs = 0;
break;
#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
case 0x2:
/*
* MOVE/CHMOV in target role (absolute address)
*/
opcode &= ~0x20000000;
if (!(np->features & FE_WIDE))
opcode = (opcode & ~OPC_TCHMOVE);
relocs = 1;
break;
case 0x3:
/*
* MOVE/CHMOV in target role (table indirect)
*/
opcode &= ~0x20000000;
if (!(np->features & FE_WIDE))
opcode = (opcode & ~OPC_TCHMOVE);
relocs = 0;
break;
#endif
case 0x8:
/*
* JUMP / CALL
* don't relocate if relative :-)
*/
if (opcode & 0x00800000)
relocs = 0;
else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/
relocs = 2;
else
relocs = 1;
break;
case 0x4:
case 0x5:
case 0x6:
case 0x7:
relocs = 1;
break;
default:
relocs = 0;
break;
};
/*
* Scriptify:) the opcode.
*/
*cur++ = cpu_to_scr(opcode);
/*
* If no relocation, assume 1 argument
* and just scriptize:) it.
*/
if (!relocs) {
*cur = cpu_to_scr(*cur);
++cur;
continue;
}
/*
* Otherwise performs all needed relocations.
*/
while (relocs--) {
old = *cur;
switch (old & RELOC_MASK) {
case RELOC_REGISTER:
new = (old & ~RELOC_MASK) + np->mmio_ba;
break;
case RELOC_LABEL_A:
new = (old & ~RELOC_MASK) + np->scripta_ba;
break;
case RELOC_LABEL_B:
new = (old & ~RELOC_MASK) + np->scriptb_ba;
break;
case RELOC_SOFTC:
new = (old & ~RELOC_MASK) + np->hcb_ba;
break;
case 0:
/*
* Don't relocate a 0 address.
* They are mostly used for patched or
* script self-modified areas.
*/
if (old == 0) {
new = old;
break;
}
/* fall through */
default:
new = 0;
panic("sym_fw_bind_script: "
"weird relocation %x\n", old);
break;
}
*cur++ = cpu_to_scr(new);
}
};
}

View file

@ -0,0 +1,205 @@
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
*
* Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
*
* This driver is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-2000 Gerard Roudier
*
* The sym53c8xx driver is derived from the ncr53c8xx driver that had been
* a port of the FreeBSD ncr driver to Linux-1.2.13.
*
* The original ncr driver has been written for 386bsd and FreeBSD by
* Wolfgang Stanglmeier <wolf@cologne.de>
* Stefan Esser <se@mi.Uni-Koeln.de>
* Copyright (C) 1994 Wolfgang Stanglmeier
*
* Other major contributions:
*
* NVRAM detection and reading.
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
*
* 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
*/
#ifndef SYM_FW_H
#define SYM_FW_H
/*
* Macro used to generate interfaces for script A.
*/
#define SYM_GEN_FW_A(s) \
SYM_GEN_A(s, start) SYM_GEN_A(s, getjob_begin) \
SYM_GEN_A(s, getjob_end) \
SYM_GEN_A(s, select) SYM_GEN_A(s, wf_sel_done) \
SYM_GEN_A(s, send_ident) \
SYM_GEN_A(s, dispatch) SYM_GEN_A(s, init) \
SYM_GEN_A(s, clrack) SYM_GEN_A(s, complete_error) \
SYM_GEN_A(s, done) SYM_GEN_A(s, done_end) \
SYM_GEN_A(s, idle) SYM_GEN_A(s, ungetjob) \
SYM_GEN_A(s, reselect) \
SYM_GEN_A(s, resel_tag) SYM_GEN_A(s, resel_dsa) \
SYM_GEN_A(s, resel_no_tag) \
SYM_GEN_A(s, data_in) SYM_GEN_A(s, data_in2) \
SYM_GEN_A(s, data_out) SYM_GEN_A(s, data_out2) \
SYM_GEN_A(s, pm0_data) SYM_GEN_A(s, pm1_data)
/*
* Macro used to generate interfaces for script B.
*/
#define SYM_GEN_FW_B(s) \
SYM_GEN_B(s, no_data) \
SYM_GEN_B(s, sel_for_abort) SYM_GEN_B(s, sel_for_abort_1) \
SYM_GEN_B(s, msg_bad) SYM_GEN_B(s, msg_weird) \
SYM_GEN_B(s, wdtr_resp) SYM_GEN_B(s, send_wdtr) \
SYM_GEN_B(s, sdtr_resp) SYM_GEN_B(s, send_sdtr) \
SYM_GEN_B(s, ppr_resp) SYM_GEN_B(s, send_ppr) \
SYM_GEN_B(s, nego_bad_phase) \
SYM_GEN_B(s, ident_break) SYM_GEN_B(s, ident_break_atn) \
SYM_GEN_B(s, sdata_in) SYM_GEN_B(s, resel_bad_lun) \
SYM_GEN_B(s, bad_i_t_l) SYM_GEN_B(s, bad_i_t_l_q) \
SYM_GEN_B(s, wsr_ma_helper)
/*
* Macro used to generate interfaces for script Z.
*/
#define SYM_GEN_FW_Z(s) \
SYM_GEN_Z(s, snooptest) SYM_GEN_Z(s, snoopend)
/*
* Generates structure interface that contains
* offsets within script A, B and Z.
*/
#define SYM_GEN_A(s, label) s label;
#define SYM_GEN_B(s, label) s label;
#define SYM_GEN_Z(s, label) s label;
struct sym_fwa_ofs {
SYM_GEN_FW_A(u_short)
};
struct sym_fwb_ofs {
SYM_GEN_FW_B(u_short)
SYM_GEN_B(u_short, start64)
SYM_GEN_B(u_short, pm_handle)
};
struct sym_fwz_ofs {
SYM_GEN_FW_Z(u_short)
};
/*
* Generates structure interface that contains
* bus addresses within script A, B and Z.
*/
struct sym_fwa_ba {
SYM_GEN_FW_A(u32)
};
struct sym_fwb_ba {
SYM_GEN_FW_B(u32)
SYM_GEN_B(u32, start64);
SYM_GEN_B(u32, pm_handle);
};
struct sym_fwz_ba {
SYM_GEN_FW_Z(u32)
};
#undef SYM_GEN_A
#undef SYM_GEN_B
#undef SYM_GEN_Z
/*
* Let cc know about the name of the controller data structure.
* We need this for function prototype declarations just below.
*/
struct sym_hcb;
/*
* Generic structure that defines a firmware.
*/
struct sym_fw {
char *name; /* Name we want to print out */
u32 *a_base; /* Pointer to script A template */
int a_size; /* Size of script A */
struct sym_fwa_ofs
*a_ofs; /* Useful offsets in script A */
u32 *b_base; /* Pointer to script B template */
int b_size; /* Size of script B */
struct sym_fwb_ofs
*b_ofs; /* Useful offsets in script B */
u32 *z_base; /* Pointer to script Z template */
int z_size; /* Size of script Z */
struct sym_fwz_ofs
*z_ofs; /* Useful offsets in script Z */
/* Setup and patch methods for this firmware */
void (*setup)(struct sym_hcb *, struct sym_fw *);
void (*patch)(struct Scsi_Host *);
};
/*
* Macro used to declare a firmware.
*/
#define SYM_FW_ENTRY(fw, name) \
{ \
name, \
(u32 *) &fw##a_scr, sizeof(fw##a_scr), &fw##a_ofs, \
(u32 *) &fw##b_scr, sizeof(fw##b_scr), &fw##b_ofs, \
(u32 *) &fw##z_scr, sizeof(fw##z_scr), &fw##z_ofs, \
fw##_setup, fw##_patch \
}
/*
* Macros used from the C code to get useful
* SCRIPTS bus addresses.
*/
#define SCRIPTA_BA(np, label) (np->fwa_bas.label)
#define SCRIPTB_BA(np, label) (np->fwb_bas.label)
#define SCRIPTZ_BA(np, label) (np->fwz_bas.label)
/*
* Macros used by scripts definitions.
*
* HADDR_1 generates a reference to a field of the controller data.
* HADDR_2 generates a reference to a field of the controller data
* with offset.
* RADDR_1 generates a reference to a script processor register.
* RADDR_2 generates a reference to a script processor register
* with offset.
* PADDR_A generates a reference to another part of script A.
* PADDR_B generates a reference to another part of script B.
*
* SYM_GEN_PADDR_A and SYM_GEN_PADDR_B are used to define respectively
* the PADDR_A and PADDR_B macros for each firmware by setting argument
* `s' to the name of the corresponding structure.
*
* SCR_DATA_ZERO is used to allocate a DWORD of data in scripts areas.
*/
#define RELOC_SOFTC 0x40000000
#define RELOC_LABEL_A 0x50000000
#define RELOC_REGISTER 0x60000000
#define RELOC_LABEL_B 0x80000000
#define RELOC_MASK 0xf0000000
#define HADDR_1(label) (RELOC_SOFTC | offsetof(struct sym_hcb, label))
#define HADDR_2(label,ofs) (RELOC_SOFTC | \
(offsetof(struct sym_hcb, label)+(ofs)))
#define RADDR_1(label) (RELOC_REGISTER | REG(label))
#define RADDR_2(label,ofs) (RELOC_REGISTER | ((REG(label))+(ofs)))
#define SYM_GEN_PADDR_A(s, label) (RELOC_LABEL_A | offsetof(s, label))
#define SYM_GEN_PADDR_B(s, label) (RELOC_LABEL_B | offsetof(s, label))
#define SCR_DATA_ZERO 0xf00ff00f
#endif /* SYM_FW_H */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,270 @@
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
*
* Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
*
* This driver is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-2000 Gerard Roudier
*
* The sym53c8xx driver is derived from the ncr53c8xx driver that had been
* a port of the FreeBSD ncr driver to Linux-1.2.13.
*
* The original ncr driver has been written for 386bsd and FreeBSD by
* Wolfgang Stanglmeier <wolf@cologne.de>
* Stefan Esser <se@mi.Uni-Koeln.de>
* Copyright (C) 1994 Wolfgang Stanglmeier
*
* Other major contributions:
*
* NVRAM detection and reading.
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
*
* 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
*/
#ifndef SYM_GLUE_H
#define SYM_GLUE_H
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/types.h>
#include <asm/io.h>
#ifdef __sparc__
# include <asm/irq.h>
#endif
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_transport_spi.h>
#include <scsi/scsi_host.h>
#include "sym53c8xx.h"
#include "sym_defs.h"
#include "sym_misc.h"
/*
* Configuration addendum for Linux.
*/
#define SYM_CONF_TIMER_INTERVAL ((HZ+1)/2)
#undef SYM_OPT_HANDLE_DEVICE_QUEUEING
#define SYM_OPT_LIMIT_COMMAND_REORDERING
/*
* Print a message with severity.
*/
#define printf_emerg(args...) printk(KERN_EMERG args)
#define printf_alert(args...) printk(KERN_ALERT args)
#define printf_crit(args...) printk(KERN_CRIT args)
#define printf_err(args...) printk(KERN_ERR args)
#define printf_warning(args...) printk(KERN_WARNING args)
#define printf_notice(args...) printk(KERN_NOTICE args)
#define printf_info(args...) printk(KERN_INFO args)
#define printf_debug(args...) printk(KERN_DEBUG args)
#define printf(args...) printk(args)
/*
* A 'read barrier' flushes any data that have been prefetched
* by the processor due to out of order execution. Such a barrier
* must notably be inserted prior to looking at data that have
* been DMAed, assuming that program does memory READs in proper
* order and that the device ensured proper ordering of WRITEs.
*
* A 'write barrier' prevents any previous WRITEs to pass further
* WRITEs. Such barriers must be inserted each time another agent
* relies on ordering of WRITEs.
*
* Note that, due to posting of PCI memory writes, we also must
* insert dummy PCI read transactions when some ordering involving
* both directions over the PCI does matter. PCI transactions are
* fully ordered in each direction.
*/
#define MEMORY_READ_BARRIER() rmb()
#define MEMORY_WRITE_BARRIER() wmb()
/*
* IO functions definition for big/little endian CPU support.
* For now, PCI chips are only supported in little endian addressing mode,
*/
#ifdef __BIG_ENDIAN
#define readw_l2b readw
#define readl_l2b readl
#define writew_b2l writew
#define writel_b2l writel
#else /* little endian */
#define readw_raw readw
#define readl_raw readl
#define writew_raw writew
#define writel_raw writel
#endif /* endian */
#ifdef SYM_CONF_CHIP_BIG_ENDIAN
#error "Chips in BIG ENDIAN addressing mode are not (yet) supported"
#endif
/*
* If the CPU and the chip use same endian-ness addressing,
* no byte reordering is needed for script patching.
* Macro cpu_to_scr() is to be used for script patching.
* Macro scr_to_cpu() is to be used for getting a DWORD
* from the script.
*/
#define cpu_to_scr(dw) cpu_to_le32(dw)
#define scr_to_cpu(dw) le32_to_cpu(dw)
/*
* These ones are used as return code from
* error recovery handlers under Linux.
*/
#define SCSI_SUCCESS SUCCESS
#define SCSI_FAILED FAILED
/*
* System specific target data structure.
* None for now, under Linux.
*/
/* #define SYM_HAVE_STCB */
/*
* System specific lun data structure.
*/
#define SYM_HAVE_SLCB
struct sym_slcb {
u_short reqtags; /* Number of tags requested by user */
u_short scdev_depth; /* Queue depth set in select_queue_depth() */
};
/*
* System specific command data structure.
* Not needed under Linux.
*/
/* struct sym_sccb */
/*
* System specific host data structure.
*/
struct sym_shcb {
/*
* Chip and controller identification.
*/
int unit;
char inst_name[16];
char chip_name[8];
struct Scsi_Host *host;
void __iomem * ioaddr; /* MMIO kernel io address */
void __iomem * ramaddr; /* RAM kernel io address */
struct timer_list timer; /* Timer handler link header */
u_long lasttime;
u_long settle_time; /* Resetting the SCSI BUS */
u_char settle_time_valid;
};
/*
* Return the name of the controller.
*/
#define sym_name(np) (np)->s.inst_name
struct sym_nvram;
/*
* The IO macros require a struct called 's' and are abused in sym_nvram.c
*/
struct sym_device {
struct pci_dev *pdev;
unsigned long mmio_base;
unsigned long ram_base;
struct {
void __iomem *ioaddr;
void __iomem *ramaddr;
} s;
struct sym_chip chip;
struct sym_nvram *nvram;
u_char host_id;
};
/*
* Driver host data structure.
*/
struct sym_data {
struct sym_hcb *ncb;
struct completion *io_reset; /* PCI error handling */
struct pci_dev *pdev;
};
static inline struct sym_hcb * sym_get_hcb(struct Scsi_Host *host)
{
return ((struct sym_data *)host->hostdata)->ncb;
}
#include "sym_fw.h"
#include "sym_hipd.h"
/*
* Set the status field of a CAM CCB.
*/
static inline void
sym_set_cam_status(struct scsi_cmnd *cmd, int status)
{
cmd->result &= ~(0xff << 16);
cmd->result |= (status << 16);
}
/*
* Get the status field of a CAM CCB.
*/
static inline int
sym_get_cam_status(struct scsi_cmnd *cmd)
{
return host_byte(cmd->result);
}
/*
* Build CAM result for a successful IO and for a failed IO.
*/
static inline void sym_set_cam_result_ok(struct sym_ccb *cp, struct scsi_cmnd *cmd, int resid)
{
scsi_set_resid(cmd, resid);
cmd->result = (((DID_OK) << 16) + ((cp->ssss_status) & 0x7f));
}
void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid);
void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *ccb);
#define sym_print_addr(cmd, arg...) dev_info(&cmd->device->sdev_gendev , ## arg)
void sym_xpt_async_bus_reset(struct sym_hcb *np);
int sym_setup_data_and_start (struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp);
void sym_log_bus_error(struct Scsi_Host *);
void sym_dump_registers(struct Scsi_Host *);
#endif /* SYM_GLUE_H */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,378 @@
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
*
* Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
*
* This driver is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-2000 Gerard Roudier
*
* The sym53c8xx driver is derived from the ncr53c8xx driver that had been
* a port of the FreeBSD ncr driver to Linux-1.2.13.
*
* The original ncr driver has been written for 386bsd and FreeBSD by
* Wolfgang Stanglmeier <wolf@cologne.de>
* Stefan Esser <se@mi.Uni-Koeln.de>
* Copyright (C) 1994 Wolfgang Stanglmeier
*
* Other major contributions:
*
* NVRAM detection and reading.
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
*
* 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
*/
#include "sym_glue.h"
/*
* Simple power of two buddy-like generic allocator.
* Provides naturally aligned memory chunks.
*
* This simple code is not intended to be fast, but to
* provide power of 2 aligned memory allocations.
* Since the SCRIPTS processor only supplies 8 bit arithmetic,
* this allocator allows simple and fast address calculations
* from the SCRIPTS code. In addition, cache line alignment
* is guaranteed for power of 2 cache line size.
*
* This allocator has been developed for the Linux sym53c8xx
* driver, since this O/S does not provide naturally aligned
* allocations.
* It has the advantage of allowing the driver to use private
* pages of memory that will be useful if we ever need to deal
* with IO MMUs for PCI.
*/
static void *___sym_malloc(m_pool_p mp, int size)
{
int i = 0;
int s = (1 << SYM_MEM_SHIFT);
int j;
void *a;
m_link_p h = mp->h;
if (size > SYM_MEM_CLUSTER_SIZE)
return NULL;
while (size > s) {
s <<= 1;
++i;
}
j = i;
while (!h[j].next) {
if (s == SYM_MEM_CLUSTER_SIZE) {
h[j].next = (m_link_p) M_GET_MEM_CLUSTER();
if (h[j].next)
h[j].next->next = NULL;
break;
}
++j;
s <<= 1;
}
a = h[j].next;
if (a) {
h[j].next = h[j].next->next;
while (j > i) {
j -= 1;
s >>= 1;
h[j].next = (m_link_p) (a+s);
h[j].next->next = NULL;
}
}
#ifdef DEBUG
printf("___sym_malloc(%d) = %p\n", size, (void *) a);
#endif
return a;
}
/*
* Counter-part of the generic allocator.
*/
static void ___sym_mfree(m_pool_p mp, void *ptr, int size)
{
int i = 0;
int s = (1 << SYM_MEM_SHIFT);
m_link_p q;
unsigned long a, b;
m_link_p h = mp->h;
#ifdef DEBUG
printf("___sym_mfree(%p, %d)\n", ptr, size);
#endif
if (size > SYM_MEM_CLUSTER_SIZE)
return;
while (size > s) {
s <<= 1;
++i;
}
a = (unsigned long)ptr;
while (1) {
if (s == SYM_MEM_CLUSTER_SIZE) {
#ifdef SYM_MEM_FREE_UNUSED
M_FREE_MEM_CLUSTER((void *)a);
#else
((m_link_p) a)->next = h[i].next;
h[i].next = (m_link_p) a;
#endif
break;
}
b = a ^ s;
q = &h[i];
while (q->next && q->next != (m_link_p) b) {
q = q->next;
}
if (!q->next) {
((m_link_p) a)->next = h[i].next;
h[i].next = (m_link_p) a;
break;
}
q->next = q->next->next;
a = a & b;
s <<= 1;
++i;
}
}
/*
* Verbose and zeroing allocator that wrapps to the generic allocator.
*/
static void *__sym_calloc2(m_pool_p mp, int size, char *name, int uflags)
{
void *p;
p = ___sym_malloc(mp, size);
if (DEBUG_FLAGS & DEBUG_ALLOC) {
printf ("new %-10s[%4d] @%p.\n", name, size, p);
}
if (p)
memset(p, 0, size);
else if (uflags & SYM_MEM_WARN)
printf ("__sym_calloc2: failed to allocate %s[%d]\n", name, size);
return p;
}
#define __sym_calloc(mp, s, n) __sym_calloc2(mp, s, n, SYM_MEM_WARN)
/*
* Its counter-part.
*/
static void __sym_mfree(m_pool_p mp, void *ptr, int size, char *name)
{
if (DEBUG_FLAGS & DEBUG_ALLOC)
printf ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
___sym_mfree(mp, ptr, size);
}
/*
* Default memory pool we donnot need to involve in DMA.
*
* With DMA abstraction, we use functions (methods), to
* distinguish between non DMAable memory and DMAable memory.
*/
static void *___mp0_get_mem_cluster(m_pool_p mp)
{
void *m = sym_get_mem_cluster();
if (m)
++mp->nump;
return m;
}
#ifdef SYM_MEM_FREE_UNUSED
static void ___mp0_free_mem_cluster(m_pool_p mp, void *m)
{
sym_free_mem_cluster(m);
--mp->nump;
}
#else
#define ___mp0_free_mem_cluster NULL
#endif
static struct sym_m_pool mp0 = {
NULL,
___mp0_get_mem_cluster,
___mp0_free_mem_cluster
};
/*
* Methods that maintains DMAable pools according to user allocations.
* New pools are created on the fly when a new pool id is provided.
* They are deleted on the fly when they get emptied.
*/
/* Get a memory cluster that matches the DMA constraints of a given pool */
static void * ___get_dma_mem_cluster(m_pool_p mp)
{
m_vtob_p vbp;
void *vaddr;
vbp = __sym_calloc(&mp0, sizeof(*vbp), "VTOB");
if (!vbp)
goto out_err;
vaddr = sym_m_get_dma_mem_cluster(mp, vbp);
if (vaddr) {
int hc = VTOB_HASH_CODE(vaddr);
vbp->next = mp->vtob[hc];
mp->vtob[hc] = vbp;
++mp->nump;
}
return vaddr;
out_err:
return NULL;
}
#ifdef SYM_MEM_FREE_UNUSED
/* Free a memory cluster and associated resources for DMA */
static void ___free_dma_mem_cluster(m_pool_p mp, void *m)
{
m_vtob_p *vbpp, vbp;
int hc = VTOB_HASH_CODE(m);
vbpp = &mp->vtob[hc];
while (*vbpp && (*vbpp)->vaddr != m)
vbpp = &(*vbpp)->next;
if (*vbpp) {
vbp = *vbpp;
*vbpp = (*vbpp)->next;
sym_m_free_dma_mem_cluster(mp, vbp);
__sym_mfree(&mp0, vbp, sizeof(*vbp), "VTOB");
--mp->nump;
}
}
#endif
/* Fetch the memory pool for a given pool id (i.e. DMA constraints) */
static inline m_pool_p ___get_dma_pool(m_pool_ident_t dev_dmat)
{
m_pool_p mp;
for (mp = mp0.next;
mp && !sym_m_pool_match(mp->dev_dmat, dev_dmat);
mp = mp->next);
return mp;
}
/* Create a new memory DMAable pool (when fetch failed) */
static m_pool_p ___cre_dma_pool(m_pool_ident_t dev_dmat)
{
m_pool_p mp = __sym_calloc(&mp0, sizeof(*mp), "MPOOL");
if (mp) {
mp->dev_dmat = dev_dmat;
mp->get_mem_cluster = ___get_dma_mem_cluster;
#ifdef SYM_MEM_FREE_UNUSED
mp->free_mem_cluster = ___free_dma_mem_cluster;
#endif
mp->next = mp0.next;
mp0.next = mp;
return mp;
}
return NULL;
}
#ifdef SYM_MEM_FREE_UNUSED
/* Destroy a DMAable memory pool (when got emptied) */
static void ___del_dma_pool(m_pool_p p)
{
m_pool_p *pp = &mp0.next;
while (*pp && *pp != p)
pp = &(*pp)->next;
if (*pp) {
*pp = (*pp)->next;
__sym_mfree(&mp0, p, sizeof(*p), "MPOOL");
}
}
#endif
/* This lock protects only the memory allocation/free. */
static DEFINE_SPINLOCK(sym53c8xx_lock);
/*
* Actual allocator for DMAable memory.
*/
void *__sym_calloc_dma(m_pool_ident_t dev_dmat, int size, char *name)
{
unsigned long flags;
m_pool_p mp;
void *m = NULL;
spin_lock_irqsave(&sym53c8xx_lock, flags);
mp = ___get_dma_pool(dev_dmat);
if (!mp)
mp = ___cre_dma_pool(dev_dmat);
if (!mp)
goto out;
m = __sym_calloc(mp, size, name);
#ifdef SYM_MEM_FREE_UNUSED
if (!mp->nump)
___del_dma_pool(mp);
#endif
out:
spin_unlock_irqrestore(&sym53c8xx_lock, flags);
return m;
}
void __sym_mfree_dma(m_pool_ident_t dev_dmat, void *m, int size, char *name)
{
unsigned long flags;
m_pool_p mp;
spin_lock_irqsave(&sym53c8xx_lock, flags);
mp = ___get_dma_pool(dev_dmat);
if (!mp)
goto out;
__sym_mfree(mp, m, size, name);
#ifdef SYM_MEM_FREE_UNUSED
if (!mp->nump)
___del_dma_pool(mp);
#endif
out:
spin_unlock_irqrestore(&sym53c8xx_lock, flags);
}
/*
* Actual virtual to bus physical address translator
* for 32 bit addressable DMAable memory.
*/
dma_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m)
{
unsigned long flags;
m_pool_p mp;
int hc = VTOB_HASH_CODE(m);
m_vtob_p vp = NULL;
void *a = (void *)((unsigned long)m & ~SYM_MEM_CLUSTER_MASK);
dma_addr_t b;
spin_lock_irqsave(&sym53c8xx_lock, flags);
mp = ___get_dma_pool(dev_dmat);
if (mp) {
vp = mp->vtob[hc];
while (vp && vp->vaddr != a)
vp = vp->next;
}
if (!vp)
panic("sym: VTOBUS FAILED!\n");
b = vp->baddr + (m - a);
spin_unlock_irqrestore(&sym53c8xx_lock, flags);
return b;
}

View file

@ -0,0 +1,190 @@
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
*
* Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
*
* This driver is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-2000 Gerard Roudier
*
* The sym53c8xx driver is derived from the ncr53c8xx driver that had been
* a port of the FreeBSD ncr driver to Linux-1.2.13.
*
* The original ncr driver has been written for 386bsd and FreeBSD by
* Wolfgang Stanglmeier <wolf@cologne.de>
* Stefan Esser <se@mi.Uni-Koeln.de>
* Copyright (C) 1994 Wolfgang Stanglmeier
*
* Other major contributions:
*
* NVRAM detection and reading.
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
*
* 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
*/
#ifndef SYM_MISC_H
#define SYM_MISC_H
/*
* A la VMS/CAM-3 queue management.
*/
typedef struct sym_quehead {
struct sym_quehead *flink; /* Forward pointer */
struct sym_quehead *blink; /* Backward pointer */
} SYM_QUEHEAD;
#define sym_que_init(ptr) do { \
(ptr)->flink = (ptr); (ptr)->blink = (ptr); \
} while (0)
static inline struct sym_quehead *sym_que_first(struct sym_quehead *head)
{
return (head->flink == head) ? 0 : head->flink;
}
static inline struct sym_quehead *sym_que_last(struct sym_quehead *head)
{
return (head->blink == head) ? 0 : head->blink;
}
static inline void __sym_que_add(struct sym_quehead * new,
struct sym_quehead * blink,
struct sym_quehead * flink)
{
flink->blink = new;
new->flink = flink;
new->blink = blink;
blink->flink = new;
}
static inline void __sym_que_del(struct sym_quehead * blink,
struct sym_quehead * flink)
{
flink->blink = blink;
blink->flink = flink;
}
static inline int sym_que_empty(struct sym_quehead *head)
{
return head->flink == head;
}
static inline void sym_que_splice(struct sym_quehead *list,
struct sym_quehead *head)
{
struct sym_quehead *first = list->flink;
if (first != list) {
struct sym_quehead *last = list->blink;
struct sym_quehead *at = head->flink;
first->blink = head;
head->flink = first;
last->flink = at;
at->blink = last;
}
}
static inline void sym_que_move(struct sym_quehead *orig,
struct sym_quehead *dest)
{
struct sym_quehead *first, *last;
first = orig->flink;
if (first != orig) {
first->blink = dest;
dest->flink = first;
last = orig->blink;
last->flink = dest;
dest->blink = last;
orig->flink = orig;
orig->blink = orig;
} else {
dest->flink = dest;
dest->blink = dest;
}
}
#define sym_que_entry(ptr, type, member) container_of(ptr, type, member)
#define sym_insque(new, pos) __sym_que_add(new, pos, (pos)->flink)
#define sym_remque(el) __sym_que_del((el)->blink, (el)->flink)
#define sym_insque_head(new, head) __sym_que_add(new, head, (head)->flink)
static inline struct sym_quehead *sym_remque_head(struct sym_quehead *head)
{
struct sym_quehead *elem = head->flink;
if (elem != head)
__sym_que_del(head, elem->flink);
else
elem = NULL;
return elem;
}
#define sym_insque_tail(new, head) __sym_que_add(new, (head)->blink, head)
static inline struct sym_quehead *sym_remque_tail(struct sym_quehead *head)
{
struct sym_quehead *elem = head->blink;
if (elem != head)
__sym_que_del(elem->blink, head);
else
elem = 0;
return elem;
}
/*
* This one may be useful.
*/
#define FOR_EACH_QUEUED_ELEMENT(head, qp) \
for (qp = (head)->flink; qp != (head); qp = qp->flink)
/*
* FreeBSD does not offer our kind of queue in the CAM CCB.
* So, we have to cast.
*/
#define sym_qptr(p) ((struct sym_quehead *) (p))
/*
* Simple bitmap operations.
*/
#define sym_set_bit(p, n) (((u32 *)(p))[(n)>>5] |= (1<<((n)&0x1f)))
#define sym_clr_bit(p, n) (((u32 *)(p))[(n)>>5] &= ~(1<<((n)&0x1f)))
#define sym_is_bit(p, n) (((u32 *)(p))[(n)>>5] & (1<<((n)&0x1f)))
/*
* The below round up/down macros are to be used with a constant
* as argument (sizeof(...) for example), for the compiler to
* optimize the whole thing.
*/
#define _U_(a,m) (a)<=(1<<m)?m:
/*
* Round up logarithm to base 2 of a 16 bit constant.
*/
#define _LGRU16_(a) \
( \
_U_(a, 0)_U_(a, 1)_U_(a, 2)_U_(a, 3)_U_(a, 4)_U_(a, 5)_U_(a, 6)_U_(a, 7) \
_U_(a, 8)_U_(a, 9)_U_(a,10)_U_(a,11)_U_(a,12)_U_(a,13)_U_(a,14)_U_(a,15) \
16)
#endif /* SYM_MISC_H */

View file

@ -0,0 +1,779 @@
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
*
* Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
*
* This driver is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-2000 Gerard Roudier
*
* The sym53c8xx driver is derived from the ncr53c8xx driver that had been
* a port of the FreeBSD ncr driver to Linux-1.2.13.
*
* The original ncr driver has been written for 386bsd and FreeBSD by
* Wolfgang Stanglmeier <wolf@cologne.de>
* Stefan Esser <se@mi.Uni-Koeln.de>
* Copyright (C) 1994 Wolfgang Stanglmeier
*
* Other major contributions:
*
* NVRAM detection and reading.
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
*
* 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
*/
#include "sym_glue.h"
#include "sym_nvram.h"
#ifdef SYM_CONF_DEBUG_NVRAM
static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120};
#endif
/*
* Get host setup from NVRAM.
*/
void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram)
{
/*
* Get parity checking, host ID, verbose mode
* and miscellaneous host flags from NVRAM.
*/
switch (nvram->type) {
case SYM_SYMBIOS_NVRAM:
if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE))
np->rv_scntl0 &= ~0x0a;
np->myaddr = nvram->data.Symbios.host_id & 0x0f;
if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS)
np->verbose += 1;
if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO)
shost->reverse_ordering = 1;
if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET)
np->usrflags |= SYM_AVOID_BUS_RESET;
break;
case SYM_TEKRAM_NVRAM:
np->myaddr = nvram->data.Tekram.host_id & 0x0f;
break;
#ifdef CONFIG_PARISC
case SYM_PARISC_PDC:
if (nvram->data.parisc.host_id != -1)
np->myaddr = nvram->data.parisc.host_id;
if (nvram->data.parisc.factor != -1)
np->minsync = nvram->data.parisc.factor;
if (nvram->data.parisc.width != -1)
np->maxwide = nvram->data.parisc.width;
switch (nvram->data.parisc.mode) {
case 0: np->scsi_mode = SMODE_SE; break;
case 1: np->scsi_mode = SMODE_HVD; break;
case 2: np->scsi_mode = SMODE_LVD; break;
default: break;
}
#endif
default:
break;
}
}
/*
* Get target set-up from Symbios format NVRAM.
*/
static void
sym_Symbios_setup_target(struct sym_tcb *tp, int target, Symbios_nvram *nvram)
{
Symbios_target *tn = &nvram->target[target];
if (!(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED))
tp->usrtags = 0;
if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
tp->usrflags &= ~SYM_DISC_ENABLED;
if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME))
tp->usrflags |= SYM_SCAN_BOOT_DISABLED;
if (!(tn->flags & SYMBIOS_SCAN_LUNS))
tp->usrflags |= SYM_SCAN_LUNS_DISABLED;
tp->usr_period = (tn->sync_period + 3) / 4;
tp->usr_width = (tn->bus_width == 0x8) ? 0 : 1;
}
static const unsigned char Tekram_sync[16] = {
25, 31, 37, 43, 50, 62, 75, 125, 12, 15, 18, 21, 6, 7, 9, 10
};
/*
* Get target set-up from Tekram format NVRAM.
*/
static void
sym_Tekram_setup_target(struct sym_tcb *tp, int target, Tekram_nvram *nvram)
{
struct Tekram_target *tn = &nvram->target[target];
if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
tp->usrtags = 2 << nvram->max_tags_index;
}
if (tn->flags & TEKRAM_DISCONNECT_ENABLE)
tp->usrflags |= SYM_DISC_ENABLED;
if (tn->flags & TEKRAM_SYNC_NEGO)
tp->usr_period = Tekram_sync[tn->sync_index & 0xf];
tp->usr_width = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0;
}
/*
* Get target setup from NVRAM.
*/
void sym_nvram_setup_target(struct sym_tcb *tp, int target, struct sym_nvram *nvp)
{
switch (nvp->type) {
case SYM_SYMBIOS_NVRAM:
sym_Symbios_setup_target(tp, target, &nvp->data.Symbios);
break;
case SYM_TEKRAM_NVRAM:
sym_Tekram_setup_target(tp, target, &nvp->data.Tekram);
break;
default:
break;
}
}
#ifdef SYM_CONF_DEBUG_NVRAM
/*
* Dump Symbios format NVRAM for debugging purpose.
*/
static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
{
int i;
/* display Symbios nvram host data */
printf("%s: HOST ID=%d%s%s%s%s%s%s\n",
sym_name(np), nvram->host_id & 0x0f,
(nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"",
(nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"",
(nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"",
(nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"",
(nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET" :"",
(nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :"");
/* display Symbios nvram drive data */
for (i = 0 ; i < 15 ; i++) {
struct Symbios_target *tn = &nvram->target[i];
printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
sym_name(np), i,
(tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "",
(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "",
(tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "",
(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "",
tn->bus_width,
tn->sync_period / 4,
tn->timeout);
}
}
/*
* Dump TEKRAM format NVRAM for debugging purpose.
*/
static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram)
{
int i, tags, boot_delay;
char *rem;
/* display Tekram nvram host data */
tags = 2 << nvram->max_tags_index;
boot_delay = 0;
if (nvram->boot_delay_index < 6)
boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
switch ((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
default:
case 0: rem = ""; break;
case 1: rem = " REMOVABLE=boot device"; break;
case 2: rem = " REMOVABLE=all"; break;
}
printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
sym_name(np), nvram->host_id & 0x0f,
(nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"",
(nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"",
(nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"",
(nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"",
(nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"",
(nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"",
(nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"",
(nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"",
rem, boot_delay, tags);
/* display Tekram nvram drive data */
for (i = 0; i <= 15; i++) {
int sync, j;
struct Tekram_target *tn = &nvram->target[i];
j = tn->sync_index & 0xf;
sync = Tekram_sync[j];
printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
sym_name(np), i,
(tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "",
(tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "",
(tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "",
(tn->flags & TEKRAM_START_CMD) ? " START" : "",
(tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "",
(tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "",
sync);
}
}
#else
static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void)np; (void)nvram; }
static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { (void)np; (void)nvram; }
#endif /* SYM_CONF_DEBUG_NVRAM */
/*
* 24C16 EEPROM reading.
*
* GPOI0 - data in/data out
* GPIO1 - clock
* Symbios NVRAM wiring now also used by Tekram.
*/
#define SET_BIT 0
#define CLR_BIT 1
#define SET_CLK 2
#define CLR_CLK 3
/*
* Set/clear data/clock bit in GPIO0
*/
static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg,
int bit_mode)
{
udelay(5);
switch (bit_mode) {
case SET_BIT:
*gpreg |= write_bit;
break;
case CLR_BIT:
*gpreg &= 0xfe;
break;
case SET_CLK:
*gpreg |= 0x02;
break;
case CLR_CLK:
*gpreg &= 0xfd;
break;
}
OUTB(np, nc_gpreg, *gpreg);
INB(np, nc_mbox1);
udelay(5);
}
/*
* Send START condition to NVRAM to wake it up.
*/
static void S24C16_start(struct sym_device *np, u_char *gpreg)
{
S24C16_set_bit(np, 1, gpreg, SET_BIT);
S24C16_set_bit(np, 0, gpreg, SET_CLK);
S24C16_set_bit(np, 0, gpreg, CLR_BIT);
S24C16_set_bit(np, 0, gpreg, CLR_CLK);
}
/*
* Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
*/
static void S24C16_stop(struct sym_device *np, u_char *gpreg)
{
S24C16_set_bit(np, 0, gpreg, SET_CLK);
S24C16_set_bit(np, 1, gpreg, SET_BIT);
}
/*
* Read or write a bit to the NVRAM,
* read if GPIO0 input else write if GPIO0 output
*/
static void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_bit,
u_char *gpreg)
{
S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
S24C16_set_bit(np, 0, gpreg, SET_CLK);
if (read_bit)
*read_bit = INB(np, nc_gpreg);
S24C16_set_bit(np, 0, gpreg, CLR_CLK);
S24C16_set_bit(np, 0, gpreg, CLR_BIT);
}
/*
* Output an ACK to the NVRAM after reading,
* change GPIO0 to output and when done back to an input
*/
static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg,
u_char *gpcntl)
{
OUTB(np, nc_gpcntl, *gpcntl & 0xfe);
S24C16_do_bit(np, NULL, write_bit, gpreg);
OUTB(np, nc_gpcntl, *gpcntl);
}
/*
* Input an ACK from NVRAM after writing,
* change GPIO0 to input and when done back to an output
*/
static void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg,
u_char *gpcntl)
{
OUTB(np, nc_gpcntl, *gpcntl | 0x01);
S24C16_do_bit(np, read_bit, 1, gpreg);
OUTB(np, nc_gpcntl, *gpcntl);
}
/*
* WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
* GPIO0 must already be set as an output
*/
static void S24C16_write_byte(struct sym_device *np, u_char *ack_data, u_char write_data,
u_char *gpreg, u_char *gpcntl)
{
int x;
for (x = 0; x < 8; x++)
S24C16_do_bit(np, NULL, (write_data >> (7 - x)) & 0x01, gpreg);
S24C16_read_ack(np, ack_data, gpreg, gpcntl);
}
/*
* READ a byte from the NVRAM and then send an ACK to say we have got it,
* GPIO0 must already be set as an input
*/
static void S24C16_read_byte(struct sym_device *np, u_char *read_data, u_char ack_data,
u_char *gpreg, u_char *gpcntl)
{
int x;
u_char read_bit;
*read_data = 0;
for (x = 0; x < 8; x++) {
S24C16_do_bit(np, &read_bit, 1, gpreg);
*read_data |= ((read_bit & 0x01) << (7 - x));
}
S24C16_write_ack(np, ack_data, gpreg, gpcntl);
}
#ifdef SYM_CONF_NVRAM_WRITE_SUPPORT
/*
* Write 'len' bytes starting at 'offset'.
*/
static int sym_write_S24C16_nvram(struct sym_device *np, int offset,
u_char *data, int len)
{
u_char gpcntl, gpreg;
u_char old_gpcntl, old_gpreg;
u_char ack_data;
int x;
/* save current state of GPCNTL and GPREG */
old_gpreg = INB(np, nc_gpreg);
old_gpcntl = INB(np, nc_gpcntl);
gpcntl = old_gpcntl & 0x1c;
/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
OUTB(np, nc_gpreg, old_gpreg);
OUTB(np, nc_gpcntl, gpcntl);
/* this is to set NVRAM into a known state with GPIO0/1 both low */
gpreg = old_gpreg;
S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
/* now set NVRAM inactive with GPIO0/1 both high */
S24C16_stop(np, &gpreg);
/* NVRAM has to be written in segments of 16 bytes */
for (x = 0; x < len ; x += 16) {
do {
S24C16_start(np, &gpreg);
S24C16_write_byte(np, &ack_data,
0xa0 | (((offset+x) >> 7) & 0x0e),
&gpreg, &gpcntl);
} while (ack_data & 0x01);
S24C16_write_byte(np, &ack_data, (offset+x) & 0xff,
&gpreg, &gpcntl);
for (y = 0; y < 16; y++)
S24C16_write_byte(np, &ack_data, data[x+y],
&gpreg, &gpcntl);
S24C16_stop(np, &gpreg);
}
/* return GPIO0/1 to original states after having accessed NVRAM */
OUTB(np, nc_gpcntl, old_gpcntl);
OUTB(np, nc_gpreg, old_gpreg);
return 0;
}
#endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */
/*
* Read 'len' bytes starting at 'offset'.
*/
static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data, int len)
{
u_char gpcntl, gpreg;
u_char old_gpcntl, old_gpreg;
u_char ack_data;
int retv = 1;
int x;
/* save current state of GPCNTL and GPREG */
old_gpreg = INB(np, nc_gpreg);
old_gpcntl = INB(np, nc_gpcntl);
gpcntl = old_gpcntl & 0x1c;
/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
OUTB(np, nc_gpreg, old_gpreg);
OUTB(np, nc_gpcntl, gpcntl);
/* this is to set NVRAM into a known state with GPIO0/1 both low */
gpreg = old_gpreg;
S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
/* now set NVRAM inactive with GPIO0/1 both high */
S24C16_stop(np, &gpreg);
/* activate NVRAM */
S24C16_start(np, &gpreg);
/* write device code and random address MSB */
S24C16_write_byte(np, &ack_data,
0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
if (ack_data & 0x01)
goto out;
/* write random address LSB */
S24C16_write_byte(np, &ack_data,
offset & 0xff, &gpreg, &gpcntl);
if (ack_data & 0x01)
goto out;
/* regenerate START state to set up for reading */
S24C16_start(np, &gpreg);
/* rewrite device code and address MSB with read bit set (lsb = 0x01) */
S24C16_write_byte(np, &ack_data,
0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
if (ack_data & 0x01)
goto out;
/* now set up GPIO0 for inputting data */
gpcntl |= 0x01;
OUTB(np, nc_gpcntl, gpcntl);
/* input all requested data - only part of total NVRAM */
for (x = 0; x < len; x++)
S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl);
/* finally put NVRAM back in inactive mode */
gpcntl &= 0xfe;
OUTB(np, nc_gpcntl, gpcntl);
S24C16_stop(np, &gpreg);
retv = 0;
out:
/* return GPIO0/1 to original states after having accessed NVRAM */
OUTB(np, nc_gpcntl, old_gpcntl);
OUTB(np, nc_gpreg, old_gpreg);
return retv;
}
#undef SET_BIT
#undef CLR_BIT
#undef SET_CLK
#undef CLR_CLK
/*
* Try reading Symbios NVRAM.
* Return 0 if OK.
*/
static int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
{
static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
u_char *data = (u_char *) nvram;
int len = sizeof(*nvram);
u_short csum;
int x;
/* probe the 24c16 and read the SYMBIOS 24c16 area */
if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len))
return 1;
/* check valid NVRAM signature, verify byte count and checksum */
if (nvram->type != 0 ||
memcmp(nvram->trailer, Symbios_trailer, 6) ||
nvram->byte_count != len - 12)
return 1;
/* verify checksum */
for (x = 6, csum = 0; x < len - 6; x++)
csum += data[x];
if (csum != nvram->checksum)
return 1;
return 0;
}
/*
* 93C46 EEPROM reading.
*
* GPOI0 - data in
* GPIO1 - data out
* GPIO2 - clock
* GPIO4 - chip select
*
* Used by Tekram.
*/
/*
* Pulse clock bit in GPIO0
*/
static void T93C46_Clk(struct sym_device *np, u_char *gpreg)
{
OUTB(np, nc_gpreg, *gpreg | 0x04);
INB(np, nc_mbox1);
udelay(2);
OUTB(np, nc_gpreg, *gpreg);
}
/*
* Read bit from NVRAM
*/
static void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg)
{
udelay(2);
T93C46_Clk(np, gpreg);
*read_bit = INB(np, nc_gpreg);
}
/*
* Write bit to GPIO0
*/
static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gpreg)
{
if (write_bit & 0x01)
*gpreg |= 0x02;
else
*gpreg &= 0xfd;
*gpreg |= 0x10;
OUTB(np, nc_gpreg, *gpreg);
INB(np, nc_mbox1);
udelay(2);
T93C46_Clk(np, gpreg);
}
/*
* Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
*/
static void T93C46_Stop(struct sym_device *np, u_char *gpreg)
{
*gpreg &= 0xef;
OUTB(np, nc_gpreg, *gpreg);
INB(np, nc_mbox1);
udelay(2);
T93C46_Clk(np, gpreg);
}
/*
* Send read command and address to NVRAM
*/
static void T93C46_Send_Command(struct sym_device *np, u_short write_data,
u_char *read_bit, u_char *gpreg)
{
int x;
/* send 9 bits, start bit (1), command (2), address (6) */
for (x = 0; x < 9; x++)
T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
*read_bit = INB(np, nc_gpreg);
}
/*
* READ 2 bytes from the NVRAM
*/
static void T93C46_Read_Word(struct sym_device *np,
unsigned short *nvram_data, unsigned char *gpreg)
{
int x;
u_char read_bit;
*nvram_data = 0;
for (x = 0; x < 16; x++) {
T93C46_Read_Bit(np, &read_bit, gpreg);
if (read_bit & 0x01)
*nvram_data |= (0x01 << (15 - x));
else
*nvram_data &= ~(0x01 << (15 - x));
}
}
/*
* Read Tekram NvRAM data.
*/
static int T93C46_Read_Data(struct sym_device *np, unsigned short *data,
int len, unsigned char *gpreg)
{
int x;
for (x = 0; x < len; x++) {
unsigned char read_bit;
/* output read command and address */
T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg);
if (read_bit & 0x01)
return 1; /* Bad */
T93C46_Read_Word(np, &data[x], gpreg);
T93C46_Stop(np, gpreg);
}
return 0;
}
/*
* Try reading 93C46 Tekram NVRAM.
*/
static int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram)
{
u_char gpcntl, gpreg;
u_char old_gpcntl, old_gpreg;
int retv = 1;
/* save current state of GPCNTL and GPREG */
old_gpreg = INB(np, nc_gpreg);
old_gpcntl = INB(np, nc_gpcntl);
/* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
1/2/4 out */
gpreg = old_gpreg & 0xe9;
OUTB(np, nc_gpreg, gpreg);
gpcntl = (old_gpcntl & 0xe9) | 0x09;
OUTB(np, nc_gpcntl, gpcntl);
/* input all of NVRAM, 64 words */
retv = T93C46_Read_Data(np, (u_short *) nvram,
sizeof(*nvram) / sizeof(short), &gpreg);
/* return GPIO0/1/2/4 to original states after having accessed NVRAM */
OUTB(np, nc_gpcntl, old_gpcntl);
OUTB(np, nc_gpreg, old_gpreg);
return retv;
}
/*
* Try reading Tekram NVRAM.
* Return 0 if OK.
*/
static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram)
{
u_char *data = (u_char *) nvram;
int len = sizeof(*nvram);
u_short csum;
int x;
switch (np->pdev->device) {
case PCI_DEVICE_ID_NCR_53C885:
case PCI_DEVICE_ID_NCR_53C895:
case PCI_DEVICE_ID_NCR_53C896:
x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
data, len);
break;
case PCI_DEVICE_ID_NCR_53C875:
x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
data, len);
if (!x)
break;
default:
x = sym_read_T93C46_nvram(np, nvram);
break;
}
if (x)
return 1;
/* verify checksum */
for (x = 0, csum = 0; x < len - 1; x += 2)
csum += data[x] + (data[x+1] << 8);
if (csum != 0x1234)
return 1;
return 0;
}
#ifdef CONFIG_PARISC
/*
* Host firmware (PDC) keeps a table for altering SCSI capabilities.
* Many newer machines export one channel of 53c896 chip as SE, 50-pin HD.
* Also used for Multi-initiator SCSI clusters to set the SCSI Initiator ID.
*/
static int sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *pdc)
{
struct hardware_path hwpath;
get_pci_node_path(np->pdev, &hwpath);
if (!pdc_get_initiator(&hwpath, pdc))
return 0;
return SYM_PARISC_PDC;
}
#else
static inline int sym_read_parisc_pdc(struct sym_device *np,
struct pdc_initiator *x)
{
return 0;
}
#endif
/*
* Try reading Symbios or Tekram NVRAM
*/
int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp)
{
if (!sym_read_Symbios_nvram(np, &nvp->data.Symbios)) {
nvp->type = SYM_SYMBIOS_NVRAM;
sym_display_Symbios_nvram(np, &nvp->data.Symbios);
} else if (!sym_read_Tekram_nvram(np, &nvp->data.Tekram)) {
nvp->type = SYM_TEKRAM_NVRAM;
sym_display_Tekram_nvram(np, &nvp->data.Tekram);
} else {
nvp->type = sym_read_parisc_pdc(np, &nvp->data.parisc);
}
return nvp->type;
}
char *sym_nvram_type(struct sym_nvram *nvp)
{
switch (nvp->type) {
case SYM_SYMBIOS_NVRAM:
return "Symbios NVRAM";
case SYM_TEKRAM_NVRAM:
return "Tekram NVRAM";
case SYM_PARISC_PDC:
return "PA-RISC Firmware";
default:
return "No NVRAM";
}
}

View file

@ -0,0 +1,214 @@
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
*
* Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
*
* This driver is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-2000 Gerard Roudier
*
* The sym53c8xx driver is derived from the ncr53c8xx driver that had been
* a port of the FreeBSD ncr driver to Linux-1.2.13.
*
* The original ncr driver has been written for 386bsd and FreeBSD by
* Wolfgang Stanglmeier <wolf@cologne.de>
* Stefan Esser <se@mi.Uni-Koeln.de>
* Copyright (C) 1994 Wolfgang Stanglmeier
*
* Other major contributions:
*
* NVRAM detection and reading.
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
*
* 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
*/
#ifndef SYM_NVRAM_H
#define SYM_NVRAM_H
#include "sym53c8xx.h"
/*
* Symbios NVRAM data format
*/
#define SYMBIOS_NVRAM_SIZE 368
#define SYMBIOS_NVRAM_ADDRESS 0x100
struct Symbios_nvram {
/* Header 6 bytes */
u_short type; /* 0x0000 */
u_short byte_count; /* excluding header/trailer */
u_short checksum;
/* Controller set up 20 bytes */
u_char v_major; /* 0x00 */
u_char v_minor; /* 0x30 */
u32 boot_crc;
u_short flags;
#define SYMBIOS_SCAM_ENABLE (1)
#define SYMBIOS_PARITY_ENABLE (1<<1)
#define SYMBIOS_VERBOSE_MSGS (1<<2)
#define SYMBIOS_CHS_MAPPING (1<<3)
#define SYMBIOS_NO_NVRAM (1<<3) /* ??? */
u_short flags1;
#define SYMBIOS_SCAN_HI_LO (1)
u_short term_state;
#define SYMBIOS_TERM_CANT_PROGRAM (0)
#define SYMBIOS_TERM_ENABLED (1)
#define SYMBIOS_TERM_DISABLED (2)
u_short rmvbl_flags;
#define SYMBIOS_RMVBL_NO_SUPPORT (0)
#define SYMBIOS_RMVBL_BOOT_DEVICE (1)
#define SYMBIOS_RMVBL_MEDIA_INSTALLED (2)
u_char host_id;
u_char num_hba; /* 0x04 */
u_char num_devices; /* 0x10 */
u_char max_scam_devices; /* 0x04 */
u_char num_valid_scam_devices; /* 0x00 */
u_char flags2;
#define SYMBIOS_AVOID_BUS_RESET (1<<2)
/* Boot order 14 bytes * 4 */
struct Symbios_host{
u_short type; /* 4:8xx / 0:nok */
u_short device_id; /* PCI device id */
u_short vendor_id; /* PCI vendor id */
u_char bus_nr; /* PCI bus number */
u_char device_fn; /* PCI device/function number << 3*/
u_short word8;
u_short flags;
#define SYMBIOS_INIT_SCAN_AT_BOOT (1)
u_short io_port; /* PCI io_port address */
} host[4];
/* Targets 8 bytes * 16 */
struct Symbios_target {
u_char flags;
#define SYMBIOS_DISCONNECT_ENABLE (1)
#define SYMBIOS_SCAN_AT_BOOT_TIME (1<<1)
#define SYMBIOS_SCAN_LUNS (1<<2)
#define SYMBIOS_QUEUE_TAGS_ENABLED (1<<3)
u_char rsvd;
u_char bus_width; /* 0x08/0x10 */
u_char sync_offset;
u_short sync_period; /* 4*period factor */
u_short timeout;
} target[16];
/* Scam table 8 bytes * 4 */
struct Symbios_scam {
u_short id;
u_short method;
#define SYMBIOS_SCAM_DEFAULT_METHOD (0)
#define SYMBIOS_SCAM_DONT_ASSIGN (1)
#define SYMBIOS_SCAM_SET_SPECIFIC_ID (2)
#define SYMBIOS_SCAM_USE_ORDER_GIVEN (3)
u_short status;
#define SYMBIOS_SCAM_UNKNOWN (0)
#define SYMBIOS_SCAM_DEVICE_NOT_FOUND (1)
#define SYMBIOS_SCAM_ID_NOT_SET (2)
#define SYMBIOS_SCAM_ID_VALID (3)
u_char target_id;
u_char rsvd;
} scam[4];
u_char spare_devices[15*8];
u_char trailer[6]; /* 0xfe 0xfe 0x00 0x00 0x00 0x00 */
};
typedef struct Symbios_nvram Symbios_nvram;
typedef struct Symbios_host Symbios_host;
typedef struct Symbios_target Symbios_target;
typedef struct Symbios_scam Symbios_scam;
/*
* Tekram NvRAM data format.
*/
#define TEKRAM_NVRAM_SIZE 64
#define TEKRAM_93C46_NVRAM_ADDRESS 0
#define TEKRAM_24C16_NVRAM_ADDRESS 0x40
struct Tekram_nvram {
struct Tekram_target {
u_char flags;
#define TEKRAM_PARITY_CHECK (1)
#define TEKRAM_SYNC_NEGO (1<<1)
#define TEKRAM_DISCONNECT_ENABLE (1<<2)
#define TEKRAM_START_CMD (1<<3)
#define TEKRAM_TAGGED_COMMANDS (1<<4)
#define TEKRAM_WIDE_NEGO (1<<5)
u_char sync_index;
u_short word2;
} target[16];
u_char host_id;
u_char flags;
#define TEKRAM_MORE_THAN_2_DRIVES (1)
#define TEKRAM_DRIVES_SUP_1GB (1<<1)
#define TEKRAM_RESET_ON_POWER_ON (1<<2)
#define TEKRAM_ACTIVE_NEGATION (1<<3)
#define TEKRAM_IMMEDIATE_SEEK (1<<4)
#define TEKRAM_SCAN_LUNS (1<<5)
#define TEKRAM_REMOVABLE_FLAGS (3<<6) /* 0: disable; */
/* 1: boot device; 2:all */
u_char boot_delay_index;
u_char max_tags_index;
u_short flags1;
#define TEKRAM_F2_F6_ENABLED (1)
u_short spare[29];
};
typedef struct Tekram_nvram Tekram_nvram;
typedef struct Tekram_target Tekram_target;
#ifndef CONFIG_PARISC
struct pdc_initiator { int dummy; };
#endif
/*
* Union of supported NVRAM formats.
*/
struct sym_nvram {
int type;
#define SYM_SYMBIOS_NVRAM (1)
#define SYM_TEKRAM_NVRAM (2)
#define SYM_PARISC_PDC (3)
#if SYM_CONF_NVRAM_SUPPORT
union {
Symbios_nvram Symbios;
Tekram_nvram Tekram;
struct pdc_initiator parisc;
} data;
#endif
};
#if SYM_CONF_NVRAM_SUPPORT
void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram);
void sym_nvram_setup_target (struct sym_tcb *tp, int target, struct sym_nvram *nvp);
int sym_read_nvram (struct sym_device *np, struct sym_nvram *nvp);
char *sym_nvram_type(struct sym_nvram *nvp);
#else
static inline void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram) { }
static inline void sym_nvram_setup_target(struct sym_tcb *tp, struct sym_nvram *nvram) { }
static inline int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp)
{
nvp->type = 0;
return 0;
}
static inline char *sym_nvram_type(struct sym_nvram *nvp)
{
return "No NVRAM";
}
#endif
#endif /* SYM_NVRAM_H */