mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 01:08:03 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
4
drivers/scsi/sym53c8xx_2/Makefile
Normal file
4
drivers/scsi/sym53c8xx_2/Makefile
Normal 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
|
215
drivers/scsi/sym53c8xx_2/sym53c8xx.h
Normal file
215
drivers/scsi/sym53c8xx_2/sym53c8xx.h
Normal 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 */
|
792
drivers/scsi/sym53c8xx_2/sym_defs.h
Normal file
792
drivers/scsi/sym53c8xx_2/sym_defs.h
Normal 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 */
|
554
drivers/scsi/sym53c8xx_2/sym_fw.c
Normal file
554
drivers/scsi/sym53c8xx_2/sym_fw.c
Normal 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);
|
||||
}
|
||||
};
|
||||
}
|
205
drivers/scsi/sym53c8xx_2/sym_fw.h
Normal file
205
drivers/scsi/sym53c8xx_2/sym_fw.h
Normal 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 */
|
1790
drivers/scsi/sym53c8xx_2/sym_fw1.h
Normal file
1790
drivers/scsi/sym53c8xx_2/sym_fw1.h
Normal file
File diff suppressed because it is too large
Load diff
1875
drivers/scsi/sym53c8xx_2/sym_fw2.h
Normal file
1875
drivers/scsi/sym53c8xx_2/sym_fw2.h
Normal file
File diff suppressed because it is too large
Load diff
2082
drivers/scsi/sym53c8xx_2/sym_glue.c
Normal file
2082
drivers/scsi/sym53c8xx_2/sym_glue.c
Normal file
File diff suppressed because it is too large
Load diff
270
drivers/scsi/sym53c8xx_2/sym_glue.h
Normal file
270
drivers/scsi/sym53c8xx_2/sym_glue.h
Normal 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 */
|
5842
drivers/scsi/sym53c8xx_2/sym_hipd.c
Normal file
5842
drivers/scsi/sym53c8xx_2/sym_hipd.c
Normal file
File diff suppressed because it is too large
Load diff
1226
drivers/scsi/sym53c8xx_2/sym_hipd.h
Normal file
1226
drivers/scsi/sym53c8xx_2/sym_hipd.h
Normal file
File diff suppressed because it is too large
Load diff
378
drivers/scsi/sym53c8xx_2/sym_malloc.c
Normal file
378
drivers/scsi/sym53c8xx_2/sym_malloc.c
Normal 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;
|
||||
}
|
190
drivers/scsi/sym53c8xx_2/sym_misc.h
Normal file
190
drivers/scsi/sym53c8xx_2/sym_misc.h
Normal 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 */
|
779
drivers/scsi/sym53c8xx_2/sym_nvram.c
Normal file
779
drivers/scsi/sym53c8xx_2/sym_nvram.c
Normal 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";
|
||||
}
|
||||
}
|
214
drivers/scsi/sym53c8xx_2/sym_nvram.h
Normal file
214
drivers/scsi/sym53c8xx_2/sym_nvram.h
Normal 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 */
|
Loading…
Add table
Add a link
Reference in a new issue