diff options
Diffstat (limited to 'drivers/scsi/ncr53c8xx.c')
-rw-r--r-- | drivers/scsi/ncr53c8xx.c | 1916 |
1 files changed, 998 insertions, 918 deletions
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index a029cef95..e62795b11 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -40,7 +40,7 @@ */ /* -** 16 April 1997, version 1.18e +** 9 May 1997, version 2.1b ** ** Supported SCSI-II features: ** Synchronous negotiation @@ -56,7 +56,7 @@ ** 53C820 (Wide, NCR BIOS in flash bios required) ** 53C825 (Wide, ~53C820 with on board rom BIOS) ** 53C860 (Narrow fast 20, BIOS required) -** 53C875 (Wide fast 40 with on board rom BIOS) +** 53C875 (Wide fast 20 with on board rom BIOS) ** 53C895 (Ultra2 80 MB/s with on board rom BIOS) ** ** Other features: @@ -65,7 +65,6 @@ ** Shared IRQ (since linux-1.3.72) */ -#define SCSI_NCR_DEBUG #define SCSI_NCR_DEBUG_FLAGS (0) #define NCR_DATE "pl24 96/12/14" @@ -103,6 +102,11 @@ #include <linux/time.h> #include <linux/timer.h> #include <linux/stat.h> +#ifdef __mips__ +#include <asm/bootinfo.h> +#include <asm/pgtable.h> +#include <asm/sni.h> +#endif /* __mips__ */ #include <linux/version.h> #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) @@ -111,6 +115,17 @@ #include "../block/blk.h" #endif +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35) +#include <linux/init.h> +#else +#ifndef __initdata +#define __initdata +#endif +#ifndef __initfunc +#define __initfunc(__arginit) __arginit +#endif +#endif + #include "scsi.h" #include "hosts.h" #include "constants.h" @@ -133,15 +148,6 @@ typedef u32 u_int32; */ /* -** Proc info and user command support -*/ - -#ifdef SCSI_NCR_PROC_INFO_SUPPORT -#define SCSI_NCR_PROFILE -#define SCSI_NCR_USER_COMMAND -#endif - -/* ** SCSI address of this device. ** The boot routines should have set it. ** If not, use this. @@ -212,8 +218,6 @@ typedef u32 u_int32; #if defined(SCSI_NCR_IOMAPPED) #define NCR_IOMAPPED -#else -#define NCR_MEMORYMAPPED #endif /* @@ -264,6 +268,8 @@ typedef int vm_size_t; ** In the original Bsd driver, vtophys() is called to translate ** data addresses to IO bus addresses. In order to minimize ** change, I decide to define vtophys() as virt_to_bus(). +* +* FIXME: Bus addresses are _not_ physical addresses. */ #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) @@ -292,6 +298,7 @@ static inline vm_offset_t remap_pci_mem(u_long base, u_long size) return (vm_offset_t) (page_remapped ? (page_remapped + page_offs) : 0UL); } + static inline void unmap_pci_mem(vm_offset_t vaddr, u_long size) { if (vaddr) @@ -422,6 +429,8 @@ static int guess_xfer_direction(int opcode); ** Head of list of NCR boards ** ** Host is retrieved by its irq level. +** If interrupts are shared, the internal host control block +** address (struct ncb) is used as device id. */ static struct Scsi_Host *first_host = NULL; @@ -470,6 +479,7 @@ struct ncr_driver_setup { unsigned ultra_scsi : 2; unsigned force_sync_nego: 1; unsigned reverse_probe: 1; + unsigned pci_fix_up: 2; u_char verbose; u_char default_tags; u_short default_sync; @@ -482,8 +492,13 @@ struct ncr_driver_setup { u_char irqm; }; -static struct ncr_driver_setup driver_setup = SCSI_NCR_DRIVER_SETUP; -static struct ncr_driver_setup driver_safe_setup= SCSI_NCR_DRIVER_SAFE_SETUP; +static struct ncr_driver_setup + driver_setup = SCSI_NCR_DRIVER_SETUP; + +#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT +static struct ncr_driver_setup + driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP; +#endif /* ** Other Linux definitions @@ -503,7 +518,8 @@ static void ncr53c8xx_intr(int irq, struct pt_regs * regs); static void ncr53c8xx_timeout(unsigned long np); -#define bootverbose (driver_setup.verbose) +//#define bootverbose (driver_setup.verbose) +#define bootverbose 2 /*========================================================== ** @@ -531,7 +547,7 @@ static void ncr53c8xx_timeout(unsigned long np); ** Can be changed at runtime too. */ -#ifdef SCSI_NCR_DEBUG +#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT #define DEBUG_FLAGS ncr_debug #else #define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS @@ -572,54 +588,54 @@ static void ncr53c8xx_timeout(unsigned long np); ** IO mapped input / ouput */ -#define IOM_INB(r) inb (np->port + offsetof(struct ncr_reg, r)) -#define IOM_INB_OFF(o) inb (np->port + (o)) -#define IOM_INW(r) inw (np->port + offsetof(struct ncr_reg, r)) -#define IOM_INL(r) inl (np->port + offsetof(struct ncr_reg, r)) -#define IOM_INL_OFF(o) inl (np->port + (o)) +#define IOM_INB(r) inb (np->port + offsetof(struct ncr_reg, r)) +#define IOM_INB_OFF(o) inb (np->port + (o)) +#define IOM_INW(r) inw (np->port + offsetof(struct ncr_reg, r)) +#define IOM_INL(r) inl (np->port + offsetof(struct ncr_reg, r)) +#define IOM_INL_OFF(o) inl (np->port + (o)) -#define IOM_OUTB(r, val) outb ((val), np->port+offsetof(struct ncr_reg,r)) -#define IOM_OUTW(r, val) outw ((val), np->port+offsetof(struct ncr_reg,r)) -#define IOM_OUTL(r, val) outl ((val), np->port+offsetof(struct ncr_reg,r)) -#define IOM_OUTL_OFF(o, val) outl ((val), np->port + (o)) +#define IOM_OUTB(r, val) outb ((val), np->port+offsetof(struct ncr_reg,r)) +#define IOM_OUTW(r, val) outw ((val), np->port+offsetof(struct ncr_reg,r)) +#define IOM_OUTL(r, val) outl ((val), np->port+offsetof(struct ncr_reg,r)) +#define IOM_OUTL_OFF(o, val) outl ((val), np->port + (o)) /* ** MEMORY mapped IO input / output */ -#define MMIO_INB(r) readb(&np->reg->r) -#define MMIO_INB_OFF(o) readb((char *)np->reg + (o)) -#define MMIO_INW(r) readw(&np->reg->r) -#define MMIO_INL(r) readl(&np->reg->r) -#define MMIO_INL_OFF(o) readl((char *)np->reg + (o)) +#define MMIO_INB(r) (*(volatile u8 *)(&np->reg->r)) +#define MMIO_INB_OFF(o) (*(volatile u8 *)((char *)np->reg + (o))) +#define MMIO_INW(r) (*(volatile u16 *)(&np->reg->r)) +#define MMIO_INL(r) (*(volatile u32 *)(&np->reg->r)) +#define MMIO_INL_OFF(o) (*(volatile u32 *)((char *)np->reg + (o))) -#define MMIO_OUTB(r, val) writeb((val), &np->reg->r) -#define MMIO_OUTW(r, val) writew((val), &np->reg->r) -#define MMIO_OUTL(r, val) writel((val), &np->reg->r) -#define MMIO_OUTL_OFF(o, val) writel((val), (char *)np->reg + (o)) +#define MMIO_OUTB(r, val) (*(volatile u8 *) &np->reg->r = (val)) +#define MMIO_OUTW(r, val) (*(volatile u16 *) &np->reg->r = (val)) +#define MMIO_OUTL(r, val) (*(volatile u32 *) &np->reg->r = (val)) +#define MMIO_OUTL_OFF(o, val) (*(volatile u32 *) ((char *)np->reg + (o)) = (val)) /* -** IO mapped only input / output +** IO mapped input / output */ #if defined(NCR_IOMAPPED) -#define INB(r) IOM_INB(r) -#define INB_OFF(o) IOM_INB_OFF(o) -#define INW(r) IOM_INW(r) -#define INL(r) IOM_INL(r) -#define INL_OFF(o) IOM_INL_OFF(o) +#define INB(r) IOM_INB(r) +#define INB_OFF(o) IOM_INB_OFF(o) +#define INW(r) IOM_INW(r) +#define INL(r) IOM_INL(r) +#define INL_OFF(o) IOM_INL_OFF(o) -#define OUTB(r, val) IOM_OUTB(r, val) -#define OUTW(r, val) IOM_OUTW(r, val) -#define OUTL(r, val) IOM_OUTL(r, val) -#define OUTL_OFF(o, val) IOM_OUTL_OFF(o, val) +#define OUTB(r, val) IOM_OUTB(r, val) +#define OUTW(r, val) IOM_OUTW(r, val) +#define OUTL(r, val) IOM_OUTL(r, val) +#define OUTL_OFF(o, val) IOM_OUTL_OFF(o, val) /* ** MEMORY mapped only input / output */ -#elif defined(NCR_MEMORYMAPPED) +#else #define INB(r) MMIO_INB(r) #define INB_OFF(o) MMIO_INB_OFF(o) @@ -632,23 +648,6 @@ static void ncr53c8xx_timeout(unsigned long np); #define OUTL(r, val) MMIO_OUTL(r, val) #define OUTL_OFF(o, val) MMIO_OUTL_OFF(o, val) -/* -** IO mapped or MEMORY mapped -*/ - -#else - -#define INB(r) (np->reg ? MMIO_INB(r) : IOM_INB(r)) -#define INB_OFF(o) (np->reg ? MMIO_INB_OFF(o) : IOM_INB_OFF(o)) -#define INW(r) (np->reg ? MMIO_INW(r) : IOM_INW(r)) -#define INL(r) (np->reg ? MMIO_INL(r) : IOM_INL(r)) -#define INL_OFF(o) (np->reg ? MMIO_INL_OFF(o) : IOM_INL_OFF(o)) - -#define OUTB(r, val) (np->reg ? MMIO_OUTB(r, val) : IOM_OUTB(r, val)) -#define OUTW(r, val) (np->reg ? MMIO_OUTW(r, val) : IOM_OUTW(r, val)) -#define OUTL(r, val) (np->reg ? MMIO_OUTL(r, val) : IOM_OUTL(r, val)) -#define OUTL_OFF(o, val) (np->reg ? MMIO_OUTL_OFF(o, val) : IOM_OUTL_OFF(o, val)) - #endif /* @@ -657,6 +656,10 @@ static void ncr53c8xx_timeout(unsigned long np); #define OUTONB(r, m) OUTB(r, INB(r) | (m)) #define OUTOFFB(r, m) OUTB(r, INB(r) & ~(m)) +#define OUTONW(r, m) OUTW(r, INW(r) | (m)) +#define OUTOFFW(r, m) OUTW(r, INW(r) & ~(m)) +#define OUTONL(r, m) OUTL(r, INL(r) | (m)) +#define OUTOFFL(r, m) OUTL(r, INL(r) & ~(m)) /*========================================================== ** @@ -700,7 +703,8 @@ static void ncr53c8xx_timeout(unsigned long np); #define SIR_IGN_RESIDUE (11) #define SIR_MISSING_SAVE (12) #define SIR_DATA_IO_IS_OUT (13) -#define SIR_MAX (13) +#define SIR_DATA_IO_IS_IN (14) +#define SIR_MAX (14) /*========================================================== ** @@ -798,6 +802,10 @@ struct usrcmd { #define UC_SETFLAG 15 #define UC_CLEARPROF 16 +#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT +#define UC_DEBUG_ERROR_RECOVERY 17 +#endif + #define UF_TRACE (0x01) #define UF_NODISC (0x02) @@ -813,7 +821,6 @@ struct tstamp { u_long end; u_long select; u_long command; - u_long data; u_long status; u_long disconnect; u_long reselect; @@ -1340,13 +1347,20 @@ struct ncb { **----------------------------------------------- */ int unit; /* Unit number */ - int chip; /* Chip number */ + char chip_name[8]; /* Chip name */ + char inst_name[16]; /* Instance name */ + u_int features; /* Chip features map */ struct timer_list timer; /* Timer link header */ int ncr_cache; /* Cache test variable */ Scsi_Cmnd *waiting_list; /* Waiting list header for commands */ /* that we can't put into the squeue */ u_long settle_time; /* Reset in progess */ u_char release_stage; /* Synchronisation stage on release */ +#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT + u_char debug_error_recovery; + u_char stalling; + u_char assert_atn; +#endif /*----------------------------------------------- ** Added field to support differences @@ -1359,9 +1373,6 @@ struct ncb { */ u_short device_id; u_char revision_id; -#define ChipDevice ((np)->device_id) -#define ChipVersion ((np)->revision_id & 0xf0) - u_char sv_scntl3; u_char sv_dmode; u_char sv_dcntl; @@ -1370,6 +1381,7 @@ struct ncb { u_char sv_ctest5; u_char sv_gpcntl; u_char sv_stest2; + u_char sv_stest4; u_char rv_dmode; u_char rv_dcntl; @@ -1377,6 +1389,9 @@ struct ncb { u_char rv_ctest4; u_char rv_ctest5; u_char rv_stest2; + + u_char maxburst; + u_char scsi_mode; u_char multiplier; /*----------------------------------------------- @@ -1616,8 +1631,8 @@ struct script { ncrcmd resel_tmp [ 5]; ncrcmd resel_lun [ 18]; ncrcmd resel_tag [ 24]; - ncrcmd data_io [ 2]; /* MUST be just before data_in */ - ncrcmd data_in [MAX_SCATTER * 4 + 7]; + ncrcmd data_io [ 6]; + ncrcmd data_in [MAX_SCATTER * 4 + 4]; }; /* @@ -1642,7 +1657,7 @@ struct scripth { ncrcmd getcc2 [ 14]; #endif ncrcmd getcc3 [ 10]; - ncrcmd data_out [MAX_SCATTER * 4 + 7]; + ncrcmd data_out [MAX_SCATTER * 4 + 4]; ncrcmd aborttag [ 4]; ncrcmd abort [ 22]; ncrcmd snooptest [ 9]; @@ -1664,10 +1679,10 @@ static void ncr_exception (ncb_p np); static void ncr_free_ccb (ncb_p np, ccb_p cp, u_long t, u_long l); static void ncr_getclock (ncb_p np, int mult); static void ncr_selectclock (ncb_p np, u_char scntl3); -static void ncr_save_bios_setting (ncb_p np); static ccb_p ncr_get_ccb (ncb_p np, u_long t,u_long l); static void ncr_init (ncb_p np, char * msg, u_long code); -static int ncr_intr (ncb_p np); +static int ncr_int_sbmc (ncb_p np); +static int ncr_int_par (ncb_p np); static void ncr_int_ma (ncb_p np); static void ncr_int_sir (ncb_p np); static void ncr_int_sto (ncb_p np); @@ -1675,7 +1690,7 @@ static u_long ncr_lookup (char* id); static void ncr_negotiate (struct ncb* np, struct tcb* tp); static void ncr_opennings (ncb_p np, lcb_p lp, Scsi_Cmnd * xp); -#ifdef SCSI_NCR_PROFILE +#ifdef SCSI_NCR_PROFILE_SUPPORT static void ncb_profile (ncb_p np, ccb_p cp); #endif @@ -1694,12 +1709,12 @@ static void ncr_timeout (ncb_p np); static void ncr_wakeup (ncb_p np, u_long code); static void ncr_start_reset (ncb_p np, int settle_delay); -#ifdef SCSI_NCR_USER_COMMAND +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT static void ncr_usercmd (ncb_p np); #endif -static int ncr_attach (Scsi_Host_Template *tpnt, int unit, u_short device_id, - u_char revision_id, int chip, u_int base, u_int io_port, +static int ncr_attach (Scsi_Host_Template *tpnt, int unit, + ncr_chip *chip, u_int base, u_int io_port, int irq, int bus, u_char device_fn); static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd); @@ -1720,24 +1735,13 @@ static void process_waiting_list(ncb_p np, int sts); **========================================================== */ -#ifdef SCSI_NCR_DEBUG +#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT static int ncr_debug = SCSI_NCR_DEBUG_FLAGS; #endif -/*========================================================== -** -** -** Global static data: auto configure -** -** -**========================================================== -*/ - -static char *ncr_name (ncb_p np) +static inline char *ncr_name (ncb_p np) { - static char name[16]; - sprintf(name, "ncr53c%d-%d", np->chip, np->unit); - return (name); + return np->inst_name; } @@ -1783,10 +1787,10 @@ static char *ncr_name (ncb_p np) * Kernel variables referenced in the scripts. * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY. */ -static void *script_kvars[] = +static void *script_kvars[] __initdata = { (void *)&jiffies }; -static struct script script0 = { +static struct script script0 __initdata = { /*--------------------------< START >-----------------------*/ { /* ** Claim to be still alive ... @@ -1881,7 +1885,7 @@ static struct script script0 = { ** patch the launch field. ** should look like an idle process. */ - SCR_COPY (4), + SCR_COPY_F (4), RADDR (dsa), PADDR (skip2), SCR_COPY (8), @@ -1987,7 +1991,7 @@ static struct script script0 = { ** We patch the address part of a ** COPY command with the DSA-register. */ - SCR_COPY (4), + SCR_COPY_F (4), RADDR (dsa), PADDR (loadpos), /* @@ -2376,7 +2380,7 @@ static struct script script0 = { /* ** and copy back the header to the ccb. */ - SCR_COPY (4), + SCR_COPY_F (4), RADDR (dsa), PADDR (cleanup0), SCR_COPY (sizeof (struct head)), @@ -2482,7 +2486,7 @@ static struct script script0 = { ** ** CAUTION: only little endian architectures supported! XXX */ - SCR_COPY (1), + SCR_COPY_F (1), NADDR (header.savep), PADDR (disconnect0), }/*-------------------------< DISCONNECT0 >--------------*/,{ @@ -2491,7 +2495,7 @@ static struct script script0 = { /* ** neither this */ - SCR_COPY (1), + SCR_COPY_F (1), NADDR (header.goalp), PADDR (disconnect1), }/*-------------------------< DISCONNECT1 >--------------*/,{ @@ -2587,7 +2591,7 @@ static struct script script0 = { ** This NOP will be patched with LED OFF ** SCR_REG_REG (gpreg, SCR_OR, 0x01) */ - SCR_JUMP ^ IFFALSE (0), + SCR_NO_OP, 0, /* ** make the DSA invalid. @@ -2609,7 +2613,7 @@ static struct script script0 = { ** This NOP will be patched with LED ON ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) */ - SCR_JUMP ^ IFFALSE (0), + SCR_NO_OP, 0, /* ** ... zu nichts zu gebrauchen ? @@ -2635,7 +2639,7 @@ static struct script script0 = { ** This NOP will be patched with LED ON ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) */ - SCR_JUMP ^ IFFALSE (0), + SCR_NO_OP, 0, /* ** If it's not connected :( @@ -2758,10 +2762,14 @@ static struct script script0 = { ** to low-level scsi drivers, we must trust the target ** for actual data direction when we cannot guess it. ** The programmed interrupt patches savep, lastp, goalp, -** etc.., and restarts the scsi script at data_out. +** etc.., and restarts the scsi script at data_out/in. */ SCR_INT ^ IFTRUE (WHEN (SCR_DATA_OUT)), SIR_DATA_IO_IS_OUT, + SCR_INT ^ IFTRUE (WHEN (SCR_DATA_IN)), + SIR_DATA_IO_IS_IN, + SCR_JUMP, + PADDR (no_data), }/*-------------------------< DATA_IN >--------------------*/,{ /* @@ -2769,15 +2777,7 @@ static struct script script0 = { ** #define MAX_SCATTER parameter, ** it is filled in at runtime. ** -** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), -** PADDR (no_data), -** SCR_COPY (sizeof (u_long)), -** KVAR(SCRIPT_KVAR_JIFFIES), -** NADDR (header.stamp.data), -** SCR_MOVE_TBL ^ SCR_DATA_IN, -** offsetof (struct dsb, data[ 0]), -** -** ##===========< i=1; i<MAX_SCATTER >========= +** ##===========< i=0; i<MAX_SCATTER >========= ** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)), ** || PADDR (checkatn), ** || SCR_MOVE_TBL ^ SCR_DATA_IN, @@ -2793,7 +2793,7 @@ static struct script script0 = { }/*--------------------------------------------------------*/ }; -static struct scripth scripth0 = { +static struct scripth scripth0 __initdata = { /*-------------------------< TRYLOOP >---------------------*/{ /* ** Load an entry of the start queue into dsa @@ -3109,7 +3109,7 @@ static struct scripth scripth0 = { ** We patch the address part of a COPY command ** with the address of the dsa register ... */ - SCR_COPY (4), + SCR_COPY_F (4), RADDR (dsa), PADDRH (getcc1), /* @@ -3247,15 +3247,7 @@ static struct scripth scripth0 = { ** #define MAX_SCATTER parameter, ** it is filled in at runtime. ** -** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT)), -** PADDR (no_data), -** SCR_COPY (sizeof (u_long)), -** KVAR(SCRIPT_KVAR_JIFFIES), -** NADDR (header.stamp.data), -** SCR_MOVE_TBL ^ SCR_DATA_OUT, -** offsetof (struct dsb, data[ 0]), -** -** ##===========< i=1; i<MAX_SCATTER >========= +** ##===========< i=0; i<MAX_SCATTER >========= ** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)), ** || PADDR (dispatch), ** || SCR_MOVE_TBL ^ SCR_DATA_OUT, @@ -3269,7 +3261,7 @@ static struct scripth scripth0 = { ** **--------------------------------------------------------- */ -0 /* was (u_long)&ident ? */ +0 }/*-------------------------< ABORTTAG >-------------------*/,{ /* ** Abort a bad reselection. @@ -3343,7 +3335,9 @@ static struct scripth scripth0 = { **========================================================== */ +__initfunc( void ncr_script_fill (struct script * scr, struct scripth * scrh) +) { int i; ncrcmd *p; @@ -3363,15 +3357,7 @@ void ncr_script_fill (struct script * scr, struct scripth * scrh) p = scr->data_in; - *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)); - *p++ =PADDR (no_data); - *p++ =SCR_COPY (sizeof (u_long)); - *p++ =KVAR(SCRIPT_KVAR_JIFFIES); - *p++ =NADDR (header.stamp.data); - *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN; - *p++ =offsetof (struct dsb, data[ 0]); - - for (i=1; i<MAX_SCATTER; i++) { + for (i=0; i<MAX_SCATTER; i++) { *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)); *p++ =PADDR (checkatn); *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN; @@ -3387,15 +3373,7 @@ void ncr_script_fill (struct script * scr, struct scripth * scrh) p = scrh->data_out; - *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT)); - *p++ =PADDR (no_data); - *p++ =SCR_COPY (sizeof (u_long)); - *p++ =KVAR(SCRIPT_KVAR_JIFFIES); - *p++ =NADDR (header.stamp.data); - *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT; - *p++ =offsetof (struct dsb, data[ 0]); - - for (i=1; i<MAX_SCATTER; i++) { + for (i=0; i<MAX_SCATTER; i++) { *p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)); *p++ =PADDR (dispatch); *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT; @@ -3419,11 +3397,14 @@ void ncr_script_fill (struct script * scr, struct scripth * scrh) **========================================================== */ +__initfunc( static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len) +) { ncrcmd opcode, new, old, tmp1, tmp2; ncrcmd *start, *end; int relocs; + int opchanged = 0; start = src; end = src + len/4; @@ -3470,6 +3451,14 @@ static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int le ncr_name(np), (int) (src-start-1)); DELAY (1000000); } + /* + ** If PREFETCH feature not enabled, remove + ** the NO FLUSH bit if present. + */ + if ((opcode & SCR_NO_FLUSH) && !(np->features & _F_PFEN)) { + dst[-1] = (opcode & ~SCR_NO_FLUSH); + ++opchanged; + } break; case 0x0: @@ -3546,6 +3535,9 @@ static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int le *dst++ = *src++; }; + if (bootverbose > 1 && opchanged) + printf("%s: NO FLUSH bit removed from %d script instructions\n", + ncr_name(np), opchanged); } /*========================================================== @@ -3595,6 +3587,218 @@ static void PRINT_ADDR(Scsi_Cmnd *cmd) if (np) PRINT_LUN(np, cmd->target, cmd->lun); } +/*=============================================================== +** +** Prepare io register values used by ncr_init() according +** to selected and supported features. +** +** NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 +** transfers. 32,64,128 are only supported by 875 and 895 chips. +** We use log base 2 (burst length) as internal code, with +** value 0 meaning "burst disabled". +** +**=============================================================== +*/ + +/* + * Burst length from burst code. + */ +#define burst_length(bc) (!(bc))? 0 : 1 << (bc) + +/* + * Burst code from io register bits. + */ +#define burst_code(dmode, ctest4, ctest5) \ + (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1 + +/* + * Set initial io register bits from burst code. + */ +static inline void ncr_init_burst(ncb_p np, u_char bc) +{ + np->rv_ctest4 &= ~0x80; + np->rv_dmode &= ~(0x3 << 6); + np->rv_ctest5 &= ~0x4; + + if (!bc) { + np->rv_ctest4 |= 0x80; + } + else { + --bc; + np->rv_dmode |= ((bc & 0x3) << 6); + np->rv_ctest5 |= (bc & 0x4); + } +} + +__initfunc( +static int ncr_prepare_setting(ncb_p np) +) +{ + u_char burst_max; + + /* + ** Save assumed BIOS setting + */ + + np->sv_scntl3 = INB(nc_scntl3) & 0x07; + np->sv_dmode = INB(nc_dmode) & 0xce; + np->sv_dcntl = INB(nc_dcntl) & 0xa8; + np->sv_ctest3 = INB(nc_ctest3) & 0x01; + np->sv_ctest4 = INB(nc_ctest4) & 0x80; + np->sv_ctest5 = INB(nc_ctest5) & 0x24; + np->sv_gpcntl = INB(nc_gpcntl); + np->sv_stest2 = INB(nc_stest2) & 0x20; + np->sv_stest4 = INB(nc_stest4); + + /* + ** Get the frequency of the chip's clock. + ** Find the right value for scntl3. + */ + + if (np->features & _F_QUAD) + np->multiplier = 4; + else if (np->features & _F_DBLR) + np->multiplier = 2; + else + np->multiplier = 1; + + np->clock_khz = (np->features & _F_CLK80)? 80000 : 40000; + np->clock_khz *= np->multiplier; + + if (np->clock_khz != 40000) + ncr_getclock(np, np->multiplier); + + if (np->clock_khz <= 25000) np->rv_scntl3 = 0x01; + else if (np->clock_khz <= 37500) np->rv_scntl3 = 0x02; + else if (np->clock_khz <= 50000) np->rv_scntl3 = 0x03; + else if (np->clock_khz <= 75000) np->rv_scntl3 = 0x04; + else if (np->clock_khz <= 100000) np->rv_scntl3 = 0x05; + else if (np->clock_khz <= 150000) np->rv_scntl3 = 0x06; + else np->rv_scntl3 = 0x07; + + /* + ** Get on-board RAM bus address when supported + */ + if (np->features & _F_RAM) { + OUTONB(nc_ctest2, 0x8); + np->paddr2 = INL(nc_scr0); + OUTOFFB(nc_ctest2, 0x8); + } + + /* + ** Prepare initial value of other IO registers + */ +#if defined SCSI_NCR_TRUST_BIOS_SETTING + np->rv_dmode = np->sv_dmode; + np->rv_dcntl = np->sv_dcntl; + np->rv_ctest3 = np->sv_ctest3; + np->rv_ctest4 = np->sv_ctest4; + np->rv_ctest5 = np->sv_ctest5; + burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5); +#else + np->rv_dmode = 0; + np->rv_dcntl = 0; + np->rv_ctest3 = 0; + np->rv_ctest4 = 0; + np->rv_ctest5 = 0; + np->rv_stest2 = 0; + + /* + ** Select burst length (dwords) + */ + burst_max = driver_setup.burst_max; + if (burst_max == 255) + burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5); + if (burst_max > 7) + burst_max = 7; + if (burst_max > np->maxburst) + burst_max = np->maxburst; + + /* + ** Select all supported special features + */ + if (np->features & _F_ERL) + np->rv_dmode |= ERL; /* Enable Read Line */ + if (np->features & _F_BOF) + np->rv_dmode |= BOF; /* Burst Opcode Fetch */ + if (np->features & _F_ERMP) + np->rv_dmode |= ERMP; /* Enable Read Multiple */ + if (np->features & _F_PFEN) + np->rv_dcntl |= PFEN; /* Prefetch Enable */ + if (np->features & _F_CLSE) + np->rv_dcntl |= CLSE; /* Cache Line Size Enable */ + if (np->features & _F_WRIE) + np->rv_ctest3 |= WRIE; /* Write and Invalidate */ + if (np->features & _F_DFS) + np->rv_ctest5 |= DFS; /* Dma Fifo Size */ + + /* + ** Select some other + */ + if (driver_setup.master_parity) + np->rv_ctest4 |= MPEE; /* Master parity checking */ + +#endif /* SCSI_NCR_TRUST_BIOS_SETTING */ + + /* + * Prepare initial io register bits for burst length + */ + ncr_init_burst(np, burst_max); + + /* + ** Set differential mode. + */ + switch(driver_setup.diff_support) { + case 3: + if (INB(nc_gpreg) & 0x08) + break; + case 2: + np->rv_stest2 |= 0x20; + break; + case 1: + np->rv_stest2 |= (np->sv_stest2 & 0x20); + break; + default: + break; + } + + /* + ** Set irq mode. + */ + switch(driver_setup.irqm) { + case 2: + np->rv_dcntl |= IRQM; + break; + case 1: + np->rv_stest2 |= (np->sv_dcntl & IRQM); + break; + default: + break; + } + + /* + ** Announce all that stuff to user. + */ + if (bootverbose > 1) { + printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n", + ncr_name(np), np->sv_scntl3, np->rv_scntl3); + printf ("%s: initial value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n", + ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5); + printf ("%s: final value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n", + ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5); + if (np->rv_stest2 & 0x20) + printf ("%s: DIFF mode set\n", ncr_name(np)); + } + + if (bootverbose && np->paddr2) + printf ("%s: on-board RAM at 0x%lx\n", ncr_name(np), np->paddr2); + + if (bootverbose && np->ns_sync < 25) + printf ("%s: Ultra%s SCSI support enabled\n", ncr_name(np), + np->ns_sync < 12 ? "-2": ""); + + return 0; +} /* ** Host attach and initialisations. @@ -3602,25 +3806,23 @@ static void PRINT_ADDR(Scsi_Cmnd *cmd) ** Allocate host data and ncb structure. ** Request IO region and remap MMIO region. ** Do chip initialization. -** Try with mmio. -** If mmio not possible (misconfigured cache), -** retry with io mapped. ** If all is OK, install interrupt handling and ** start the timer daemon. */ -static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ushort device_id, - u_char revision_id, int chip, u_int base, u_int io_port, +__initfunc( +static int ncr_attach (Scsi_Host_Template *tpnt, int unit, + ncr_chip *chip, u_int base, u_int io_port, int irq, int bus, u_char device_fn) - +) { struct host_data *host_data; ncb_p np; struct Scsi_Host *instance = 0; u_long flags = 0; -printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n", - unit, chip, revision_id, base, io_port, irq); +printf("ncr53c8xx: unit=%d chip=%s rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n", + unit, chip->name, chip->revision_id, base, io_port, irq); /* ** Allocate host_data structure @@ -3645,10 +3847,21 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n", np->ccb = (ccb_p) (((u_long) &host_data->_ccb_data) & CCB_ALIGN_MASK); bzero (np->ccb, sizeof (*np->ccb)); - np->unit = unit; - np->chip = chip; - np->device_id = device_id; - np->revision_id = revision_id; + /* + ** Store input informations in the host data structure. + */ + strncpy(np->chip_name, chip->name, sizeof(np->chip_name) - 1); + np->unit = unit; + sprintf(np->inst_name, "ncr53c%s-%d", np->chip_name, np->unit); + np->device_id = chip->device_id; + np->revision_id = chip->revision_id; + np->features = chip->features; + np->maxwide = (np->features & _F_WIDE)? 1 : 0; + np->ns_sync = 25; + np->clock_khz = 40000; + np->clock_divn = chip->nr_divisor; + np->maxoffs = chip->offset_max; + np->maxburst = chip->burst_max; np->script0 = (struct script *) (((u_long) &host_data->script_data) & SCR_ALIGN_MASK); @@ -3673,9 +3886,7 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n", np->vaddr = remap_pci_mem((u_long) base, (u_long) 128); if (!np->vaddr) { printf("%s: can't map memory mapped IO region\n", ncr_name(np)); -#ifdef NCR_MEMORYMAPPED goto attach_error; -#endif } else if (bootverbose > 1) @@ -3699,97 +3910,16 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n", np->port = io_port; /* - ** Save initial value of some io registers. - */ - - ncr_save_bios_setting(np); - - /* ** Do chip dependent initialization. */ - - np->maxwide = 0; - np->rv_scntl3 = 0x13; /* default: 40MHz clock */ - np->ns_sync = 25; - np->clock_khz = 40000; - np->clock_divn = 4; - np->maxoffs = 8; - np->multiplier = 1; - - /* - ** Get the frequency of the chip's clock. - ** Find the right value for scntl3. - */ - - switch (device_id) { - case PCI_DEVICE_ID_NCR_53C825: - np->maxwide = 1; - break; - case PCI_DEVICE_ID_NCR_53C860: - if (driver_setup.ultra_scsi) { - np->rv_scntl3 = 0x15; - np->clock_khz = 80000; - np->ns_sync = 12; - } - else - np->rv_scntl3 = 0x35; /* always assume 80MHz clock for 860 */ - np->clock_divn = 5; - break; - case PCI_DEVICE_ID_NCR_53C875: - case PCI_DEVICE_ID_NCR_53C885: - np->maxwide = 1; - if (driver_setup.special_features) - np->maxoffs = 16; - np->clock_divn = 5; - if (device_id == PCI_DEVICE_ID_NCR_53C875) - ncr_getclock(np, revision_id >= 2 ? 2 : 1); - else - ncr_getclock(np, 2); - break; - case PCI_DEVICE_ID_NCR_53C895: - case PCI_DEVICE_ID_NCR_53C896: - np->maxwide = 1; - if (driver_setup.special_features) - np->maxoffs = 31; - np->clock_divn = 7; - ncr_getclock(np, 4); - break; - } - - /* - ** Get on-board RAM bus address when supported - */ - switch (device_id) { - case PCI_DEVICE_ID_NCR_53C825: - if (revision_id < 0x10) - break; - case PCI_DEVICE_ID_NCR_53C875: - case PCI_DEVICE_ID_NCR_53C885: - case PCI_DEVICE_ID_NCR_53C895: - case PCI_DEVICE_ID_NCR_53C896: - if (driver_setup.special_features) { - OUTONB(nc_ctest2, 0x8); - np->paddr2 = INL(nc_scr0); - OUTOFFB(nc_ctest2, 0x8); - } - break; - } - - if (bootverbose && np->paddr2) - printf ("%s: on-board RAM at 0x%lx\n", ncr_name(np), np->paddr2); - - if (bootverbose && np->ns_sync < 25) - printf ("%s: Ultra%s SCSI support enabled\n", ncr_name(np), - np->ns_sync < 12 ? "-2": ""); + (void)ncr_prepare_setting(np); #ifndef NCR_IOMAPPED if (np->paddr2 && sizeof(struct script) <= 4096) { np->vaddr2 = remap_pci_mem((u_long) np->paddr2, (u_long) 4096); if (!np->vaddr2) { printf("%s: can't map memory mapped IO region\n", ncr_name(np)); -#ifdef NCR_MEMORYMAPPED goto attach_error; -#endif } else if (bootverbose > 1) @@ -3831,16 +3961,23 @@ printf("ncr53c8xx: unit=%d chip=%d rev=0x%x base=0x%x, io_port=0x%x, irq=%d\n", np->ccb->p_ccb = vtophys (np->ccb); /* + ** Patch the script for LED support. + */ + + if (driver_setup.led_pin & (~np->sv_gpcntl) & 0x01) { + np->features |= _F_LED0; + np->script0->reselect[0] = SCR_REG_REG(gpreg, SCR_OR, 0x01); + np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe); + np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe); + } + + /* ** init data structure */ np->jump_tcb.l_cmd = SCR_JUMP; np->jump_tcb.l_paddr = NCB_SCRIPTH_PHYS (np, abort); -#if !defined(NCR_IOMAPPED) && !defined(NCR_MEMORYMAPPED) -retry_chip_init: -#endif - /* ** Get SCSI addr of host adapter (set by bios?). */ @@ -3864,14 +4001,6 @@ retry_chip_init: */ if (ncr_snooptest (np)) { -#if !defined(NCR_IOMAPPED) && !defined(NCR_MEMORYMAPPED) - if (np->reg) { -printf("%s: cache misconfigured, retrying with IO mapped at 0x%lx\n", - ncr_name(np), (u_long) np->port); - np->reg = 0; - goto retry_chip_init; - } -#endif printf ("CACHE INCORRECTLY CONFIGURED.\n"); goto attach_error; }; @@ -3962,18 +4091,25 @@ printf("%s: cache misconfigured, retrying with IO mapped at 0x%lx\n", attach_error: if (!instance) return -1; + printf("%s: detaching...\n", ncr_name(np)); #ifndef NCR_IOMAPPED if (np->vaddr) { +#ifdef DEBUG_NCR53C8XX printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128); +#endif unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128); } if (np->vaddr2) { +#ifdef DEBUG_NCR53C8XX printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096); +#endif unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096); } #endif if (np->port) { +#ifdef DEBUG_NCR53C8XX printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128); +#endif release_region(np->port, 128); } scsi_unregister(instance); @@ -3984,47 +4120,6 @@ attach_error: /*========================================================== ** ** -** Process pending device interrupts. -** -** -**========================================================== -*/ -int ncr_intr(np) - ncb_p np; -{ - int n = 0; - u_long flags; - - save_flags(flags); cli(); - - if (DEBUG_FLAGS & DEBUG_TINY) printf ("["); - -#ifdef SCSI_NCR_PARANOIA - if (INB(nc_istat) & (INTF|SIP|DIP)) { - /* - ** Repeat until no outstanding ints - */ - do { -#endif - ncr_exception (np); -#ifdef SCSI_NCR_PARANOIA - } while (INB(nc_istat) & (INTF|SIP|DIP)); - - n=1; - np->ticks = 5 * HZ; - }; -#endif - - if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n"); - - restore_flags(flags); - - return (n); -} - -/*========================================================== -** -** ** Start execution of a SCSI command. ** This is called from the generic SCSI driver. ** @@ -4107,7 +4202,7 @@ int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) ** **---------------------------------------------------- */ -#ifdef SCSI_NCR_PROFILE +#ifdef SCSI_NCR_PROFILE_SUPPORT bzero (&cp->phys.header.stamp, sizeof (struct tstamp)); cp->phys.header.stamp.start = jiffies; #endif @@ -4337,25 +4432,30 @@ int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) */ cp->segments = segments; + if (!cp->data_len) + xfer_direction = XferNone; switch (xfer_direction) { + u_long endp; default: case XferBoth: - cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io); - cp->phys.header.goalp = cp->phys.header.savep +8 +20 +segments*16; - break; + cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_io); + cp->phys.header.goalp = cp->phys.header.savep; + break; case XferIn: - cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_in); - cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16; - break; + endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16; + cp->phys.header.goalp = endp + 8; + cp->phys.header.savep = endp - segments*16; + break; case XferOut: - cp->phys.header.savep = NCB_SCRIPTH_PHYS (np, data_out); - cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16; - break; + endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16; + cp->phys.header.goalp = endp + 8; + cp->phys.header.savep = endp - segments*16; + break; case XferNone: - cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data); - cp->phys.header.goalp = cp->phys.header.savep; - break; + cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data); + cp->phys.header.goalp = cp->phys.header.savep; + break; } cp->phys.header.lastp = cp->phys.header.savep; @@ -4463,6 +4563,9 @@ int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) ** Script processor may be waiting for reselect. ** Wake it up. */ +#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT + if (!np->stalling) +#endif OUTB (nc_istat, SIGP); /* @@ -4530,6 +4633,11 @@ int ncr_reset_bus (Scsi_Cmnd *cmd, int sync_reset) u_long flags; int found; +#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT + if (np->stalling) + np->stalling = 0; +#endif + save_flags(flags); cli(); /* * Return immediately if reset is in progress. @@ -4607,6 +4715,11 @@ static int ncr_abort_command (Scsi_Cmnd *cmd) int found; int retv; +#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT + if (np->stalling == 2) + np->stalling = 0; +#endif + save_flags(flags); cli(); /* * First, look for the scsi command in the waiting list @@ -4663,6 +4776,9 @@ static int ncr_abort_command (Scsi_Cmnd *cmd) ** processor will sleep on SEL_WAIT_RESEL. ** Let's wake it up, since it may have to work. */ +#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT + if (!np->stalling) +#endif OUTB (nc_istat, SIGP); restore_flags(flags); @@ -4697,7 +4813,7 @@ static int ncr_detach(ncb_p np, int irq) ** Set release_stage to 1 and wait that ncr_timeout() set it to 2. */ -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printf("%s: stopping the timer\n", ncr_name(np)); #endif np->release_stage = 1; @@ -4710,7 +4826,7 @@ static int ncr_detach(ncb_p np, int irq) ** Disable chip interrupts */ -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printf("%s: disabling chip interrupts\n", ncr_name(np)); #endif OUTW (nc_sien , 0); @@ -4720,7 +4836,7 @@ static int ncr_detach(ncb_p np, int irq) ** Free irq */ -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printf("%s: freeing irq %d\n", ncr_name(np), irq); #endif #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) @@ -4758,17 +4874,17 @@ static int ncr_detach(ncb_p np, int irq) */ #ifndef NCR_IOMAPPED -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128); #endif unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128); -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096); #endif unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096); #endif -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128); #endif release_region(np->port, 128); @@ -4783,7 +4899,7 @@ static int ncr_detach(ncb_p np, int irq) printf("%s: shall free an active ccb (host_status=%d)\n", ncr_name(np), cp->host_status); } -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printf("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp); #endif m_free(cp, sizeof(*cp)); @@ -4798,7 +4914,7 @@ static int ncr_detach(ncb_p np, int irq) for (lun = 0 ; lun < MAX_LUN ; lun++) { lp = tp->lp[lun]; if (lp) { -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printf("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp); #endif m_free(lp, sizeof(*lp)); @@ -4851,7 +4967,7 @@ void ncr_complete (ncb_p np, ccb_p cp) ** timestamp ** Optional, spare some CPU time */ -#ifdef SCSI_NCR_PROFILE +#ifdef SCSI_NCR_PROFILE_SUPPORT ncb_profile (np, cp); #endif @@ -5158,46 +5274,6 @@ void ncr_wakeup (ncb_p np, u_long code) }; } -/*=============================================================== -** -** NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 -** transfers. 32,64,128 are only supported by 875 and 895 chips. -** We use log base 2 (burst length) as internal code, with -** value 0 meaning "burst disabled". -** -**=============================================================== -*/ - -/* - * Burst length from burst code. - */ -#define burst_length(bc) (!(bc))? 0 : 1 << (bc) - -/* - * Burst code from io register bits. - */ -#define burst_code(dmode, ctest4, ctest5) \ - (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1 - -/* - * Set initial io register bits from burst code. - */ -static void ncr_init_burst(ncb_p np, u_char bc) -{ - np->rv_ctest4 &= ~0x80; - np->rv_dmode &= ~(0x3 << 6); - np->rv_ctest5 &= ~0x4; - - if (!bc) { - np->rv_ctest4 |= 0x80; - } - else { - --bc; - np->rv_dmode |= ((bc & 0x3) << 6); - np->rv_ctest5 |= (bc & 0x4); - } -} - /*========================================================== ** ** @@ -5212,7 +5288,6 @@ void ncr_init (ncb_p np, char * msg, u_long code) int i; u_long usrsync; u_char usrwide; - u_char burst_max; /* ** Reset chip. @@ -5236,7 +5311,6 @@ void ncr_init (ncb_p np, char * msg, u_long code) /* ** Start at first entry. */ - np->squeueput = 0; np->script0->startpos[0] = NCB_SCRIPTH_PHYS (np, tryloop); np->script0->start0 [0] = SCR_INT ^ IFFALSE (0); @@ -5249,161 +5323,30 @@ void ncr_init (ncb_p np, char * msg, u_long code) /* ** Init chip. */ -#if defined SCSI_NCR_TRUST_BIOS_SETTING - np->rv_dmode = np->sv_dmode; - np->rv_dcntl = np->sv_dcntl; - np->rv_ctest3 = np->sv_ctest3; - np->rv_ctest4 = np->sv_ctest4; - np->rv_ctest5 = np->sv_ctest5; - burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5); -#else - np->rv_dmode = 0; - np->rv_dcntl = 0; - np->rv_ctest3 = 0; - np->rv_ctest4 = 0; - burst_max = driver_setup.burst_max; - if (burst_max == 255) - burst_max = burst_code(np->sv_dmode, np->sv_ctest4, np->sv_ctest5); - if (burst_max > 7) - burst_max = 7; - -/** NCR53C810 **/ - if (ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion == 0) { - burst_max = burst_max < 4 ? burst_max : 4; - if (driver_setup.special_features) - np->rv_dmode = ERL; /* read line */ - } - else -/** NCR53C815 **/ - if (ChipDevice == PCI_DEVICE_ID_NCR_53C815) { - burst_max = burst_max < 4 ? burst_max : 4; - if (driver_setup.special_features) - np->rv_dmode = BOF | ERL; /* burst opcode fetch, read line */ - } - else -/** NCR53C825 **/ - if (ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion == 0) { - burst_max = burst_max < 4 ? burst_max : 4; - if (driver_setup.special_features) - np->rv_dmode = BOF | ERL; /* burst opcode fetch, read line */ - } - else -/** NCR53C810A or NCR53C860 **/ - if ((ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion >= 0x10) || - ChipDevice == PCI_DEVICE_ID_NCR_53C860) { - burst_max = burst_max < 4 ? burst_max : 4; - if (driver_setup.special_features) { - np->rv_dmode = BOF | ERMP | ERL; - /* burst op-code fetch, read multiple */ - /* read line */ - np->rv_dcntl = PFEN | CLSE; - /* prefetch, cache line size */ - np->rv_ctest3 = WRIE; /* write and invalidate */ - } - } - else -/** NCR53C825A or NCR53C875 or NCR53C885 or NCR53C895 or NCR53C896 **/ - if ((ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion >= 0x10) || - ChipDevice == PCI_DEVICE_ID_NCR_53C875 || - ChipDevice == PCI_DEVICE_ID_NCR_53C885 || - ChipDevice == PCI_DEVICE_ID_NCR_53C895 || - ChipDevice == PCI_DEVICE_ID_NCR_53C896) { - if (!driver_setup.special_features) - burst_max = burst_max < 4 ? burst_max : 4; - else { - burst_max = burst_max < 7 ? burst_max : 7; - np->rv_dmode = BOF | ERMP | ERL; - /* burst op-code fetch, read multiple */ - /* read line, burst 128 (ctest5&4) */ - np->rv_dcntl = PFEN | CLSE; - /* prefetch, cache line size */ - np->rv_ctest3 = WRIE; /* write and invalidate */ - np->rv_ctest5 = DFS; /* large dma fifo (0x20) */ - } - } -/** OTHERS **/ - else { - burst_max = burst_max < 4 ? burst_max : 4; - } -#endif /* SCSI_NCR_TRUST_BIOS_SETTING */ - /* - * Prepare initial io register bits for burst length - */ - ncr_init_burst(np, burst_max); - - /* - ** Set differential mode. - */ - switch(driver_setup.diff_support) { - case 3: - if (INB(nc_gpreg) & 0x08) - break; - case 2: - np->rv_stest2 |= 0x20; - break; - case 1: - np->rv_stest2 |= (np->sv_stest2 & 0x20); - break; - default: - break; - } - - /* - ** Set irq mode. - */ - switch(driver_setup.irqm) { - case 2: - np->rv_dcntl |= IRQM; - break; - case 1: - np->rv_stest2 |= (np->sv_dcntl & IRQM); - break; - default: - break; - } - - if (bootverbose > 1) { - printf ("%s: initial value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n", - ncr_name(np), np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5); - } - if (bootverbose > 1) { - printf ("%s: final value of dmode/dcntl/ctest3/4/5 = (hex) %02x/%02x/%02x/%02x/%02x\n", - ncr_name(np), np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5); - if (np->rv_stest2 & 0x20) - printf ("%s: setting up differential mode\n", ncr_name(np)); - } - - OUTB (nc_istat, 0x00 ); /* Remove Reset, abort ... */ + OUTB (nc_istat, 0x00 ); /* Remove Reset, abort */ if (driver_setup.scsi_parity) - OUTB (nc_scntl0, 0xca ); /* full arb., ena parity, par->ATN */ + OUTB (nc_scntl0, 0xca); /* full arb., ena parity, par->ATN */ else - OUTB (nc_scntl0, 0xc0 ); /* full arb., (no parity) */ + OUTB (nc_scntl0, 0xc0); /* full arb., (no parity) */ - OUTB (nc_scntl1, 0x00 ); /* odd parity, and remove CRST!! */ + OUTB (nc_scntl1, 0x00); /* odd parity, and remove CRST!! */ - ncr_selectclock(np, np->rv_scntl3); + ncr_selectclock(np, np->rv_scntl3); /* Select SCSI clock */ - OUTB (nc_scid , RRE|np->myaddr);/* host adapter SCSI address */ - OUTW (nc_respid, 1ul<<np->myaddr);/* id to respond to */ - OUTB (nc_istat , SIGP ); /* Signal Process */ - OUTB (nc_dmode , np->rv_dmode); /* Burst length = 2 .. 16 transfers */ + OUTB (nc_scid , RRE|np->myaddr); /* Adapter SCSI address */ + OUTW (nc_respid, 1ul<<np->myaddr); /* Id to respond to */ + OUTB (nc_istat , SIGP ); /* Signal Process */ + OUTB (nc_dmode , np->rv_dmode); /* Burst length, dma mode */ + OUTB (nc_ctest5, np->rv_ctest5); /* Large fifo + large burst */ - if (driver_setup.special_features && np->rv_ctest5) - OUTB (nc_ctest5, np->rv_ctest5); /* large fifo + large burst */ + OUTB (nc_dcntl , NOCOM|np->rv_dcntl); /* Protect SFBR */ + OUTB (nc_ctest3, np->rv_ctest3); /* Write and invalidate */ + OUTB (nc_ctest4, np->rv_ctest4); /* Master parity checking */ - OUTB (nc_dcntl , NOCOM|np->rv_dcntl);/* no single step mode, protect SFBR*/ - OUTB (nc_ctest3, np->rv_ctest3); /* write and invalidate */ - - if (driver_setup.master_parity) - OUTB (nc_ctest4, MPEE|np->rv_ctest4); /* enable master parity checking */ - else - OUTB (nc_ctest4, 0x00|np->rv_ctest4); /* disable master parity checking */ - - OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */ - OUTB (nc_stest3, TE ); /* TolerANT enable */ - OUTB (nc_stime0, 0x0d ); /* HTH = disable STO = 0.4 sec. */ - /* 0.25 sec recommended for scsi 1 */ + OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */ + OUTB (nc_stest3, TE); /* TolerANT enable */ + OUTB (nc_stime0, 0x0d ); /* HTH disabled STO 0.4 sec. */ /* ** Reinitialize usrsync. @@ -5436,31 +5379,11 @@ void ncr_init (ncb_p np, char * msg, u_long code) np->disc = 0; /* - ** Fill in target structure. + ** Enable GPIO0 pin for writing if LED support. */ - for (i=0;i<MAX_TARGET;i++) { - tcb_p tp = &np->target[i]; - - tp->sval = 0; - tp->wval = np->rv_scntl3; - - tp->usrsync = usrsync; - tp->usrwide = usrwide; - - ncr_negotiate (np, tp); - } - - /* - ** Enable GPIO0 pin for writing. - ** Patch the script for LED support. - */ - - if (driver_setup.led_pin & (~np->sv_gpcntl) & 0x01) { + if (np->features & _F_LED0) { OUTOFFB (nc_gpcntl, 0x01); - np->script0->reselect[0] = SCR_REG_REG(gpreg, SCR_OR, 0x01); - np->script0->reselect1[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe); - np->script0->reselect2[0] = SCR_REG_REG(gpreg, SCR_AND, 0xfe); } /* @@ -5480,6 +5403,31 @@ void ncr_init (ncb_p np, char * msg, u_long code) OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID); /* + ** For 895/6 enable SBMC interrupt and save current SCSI bus mode. + */ + if (np->features & _F_ULTRA2) { + OUTONW (nc_sien, SBMC); + np->scsi_mode = INB (nc_stest4) & SMODE; + } + + /* + ** Fill in target structure. + ** Prepare sync negotiation according to actual SCSI bus mode. + */ + + for (i=0;i<MAX_TARGET;i++) { + tcb_p tp = &np->target[i]; + + tp->sval = 0; + tp->wval = np->rv_scntl3; + + tp->usrsync = usrsync; + tp->usrwide = usrwide; + + ncr_negotiate (np, tp); + } + + /* ** Start script processor. */ @@ -5502,14 +5450,12 @@ static void ncr_negotiate (struct ncb* np, struct tcb* tp) u_long minsync = tp->usrsync; - if (driver_setup.ultra_scsi >= 2) { - if (minsync < 10) minsync=10; - } - else if (driver_setup.ultra_scsi == 1) { - if (minsync < 12) minsync=12; - } - else { - if (minsync < 25) minsync=25; + /* + ** SCSI bus mode limit + */ + + if (np->scsi_mode && np->scsi_mode == SMODE_SE) { + if (minsync < 12) minsync = 12; } /* @@ -5628,7 +5574,7 @@ static int ncr_getsync(ncb_p np, u_char fac, u_char *fakp, u_char *scntl3p) *fakp = fak - 4; *scntl3p = ((idiv+1) << 4) + (fac < 25 ? ULTRA : 0); -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printf("fac=%d idiv=%d per=%d fak=%x ", fac, idiv, per, *fakp); #endif @@ -5867,7 +5813,7 @@ static void ncr_settags (tcb_p tp, lcb_p lp) **---------------------------------------------------- */ -#ifdef SCSI_NCR_USER_COMMAND +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT static void ncr_usercmd (ncb_p np) { @@ -5897,7 +5843,7 @@ static void ncr_usercmd (ncb_p np) break; case UC_SETDEBUG: -#ifdef SCSI_NCR_DEBUG +#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT ncr_debug = np->user.data; #endif break; @@ -5929,12 +5875,106 @@ static void ncr_usercmd (ncb_p np) case UC_CLEARPROF: bzero(&np->profile, sizeof(np->profile)); break; +#ifdef UC_DEBUG_ERROR_RECOVERY + case UC_DEBUG_ERROR_RECOVERY: + np->debug_error_recovery = np->user.data; + break; +#endif } np->user.cmd=0; } #endif +/*===================================================================== +** +** Embedded error recovery debugging code. +** +**===================================================================== +** +** This code is conditionned by SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT. +** It only can be enabled after boot-up with a control command. +** +** Every 30 seconds the timer handler of the driver decides to +** change the behaviour of the driver in order to trigger errors. +** +** If last command was "debug_error_recovery sge", the driver +** sets sync offset of all targets that use sync transfers to 2, +** and so hopes a SCSI gross error at the next read operation. +** +** If last command was "debug_error_recovery abort", the driver +** does not signal new scsi commands to the script processor, until +** it is asked to abort or reset a command by the mid-level driver. +** +** If last command was "debug_error_recovery reset", the driver +** does not signal new scsi commands to the script processor, until +** it is asked to reset a command by the mid-level driver. +** +** If last command was "debug_error_recovery parity", the driver +** will assert ATN on the next DATA IN phase mismatch, and so will +** behave as if a parity error had been detected. +** +** The command "debug_error_recovery none" makes the driver behave +** normaly. +** +**===================================================================== +*/ + +#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT +static void ncr_trigger_errors (ncb_p np) +{ + /* + ** If np->debug_error_recovery is not zero, we want to + ** simulate common errors in order to test error recovery. + */ + do { + static u_long last = 0l; + + if (!np->debug_error_recovery) + break; + if (!last) + last = jiffies; + else if (jiffies < last + 30*HZ) + break; + last = jiffies; + /* + * This one triggers SCSI gross errors. + */ + if (np->debug_error_recovery == 1) { + int i; + printf("%s: testing error recovery from SCSI gross error...\n", ncr_name(np)); + for (i = 0 ; i < MAX_TARGET ; i++) { + if (np->target[i].sval & 0x1f) { + np->target[i].sval &= ~0x1f; + np->target[i].sval += 2; + } + } + } + /* + * This one triggers abort from the mid-level driver. + */ + else if (np->debug_error_recovery == 2) { + printf("%s: testing error recovery from mid-level driver abort()...\n", ncr_name(np)); + np->stalling = 2; + } + /* + * This one triggers reset from the mid-level driver. + */ + else if (np->debug_error_recovery == 3) { + printf("%s: testing error recovery from mid-level driver reset()...\n", ncr_name(np)); + np->stalling = 3; + } + /* + * This one set ATN on phase mismatch in DATA IN phase and so + * will behave as on scsi parity error detected. + */ + else if (np->debug_error_recovery == 4) { + printf("%s: testing data in parity error...\n", ncr_name(np)); + np->assert_atn = 1; + } + } while (0); +} +#endif /*========================================================== ** @@ -5977,6 +6017,10 @@ static void ncr_timeout (ncb_p np) add_timer(&np->timer); +#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT + ncr_trigger_errors (np); +#endif + /* ** If we are resetting the ncr, wait for settle_time before ** clearing it. Then command processing will be resumed. @@ -6084,6 +6128,9 @@ static void ncr_timeout (ncb_p np) */ ncr_complete (np, cp); +#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT + if (!np->stalling) +#endif OUTB (nc_istat, SIGP); } restore_flags(flags); @@ -6138,6 +6185,7 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat) { u_int32 dsp; int script_ofs; + int script_size; char *script_name; u_char *script_base; int i; @@ -6146,11 +6194,13 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat) if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) { script_ofs = dsp - np->p_script; + script_size = sizeof(struct script); script_base = (u_char *) np->script; script_name = "script"; } else { script_ofs = dsp - np->p_scripth; + script_size = sizeof(struct scripth); script_base = (u_char *) np->scripth; script_name = "scripth"; } @@ -6162,7 +6212,7 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat) (unsigned)INL (nc_dbc)); if (((script_ofs & 3) == 0) && - (unsigned)script_ofs < sizeof(struct script)) { + (unsigned)script_ofs < script_size) { printf ("%s: script cmd = %08x\n", ncr_name(np), (int) *(ncrcmd *)(script_base + script_ofs)); } @@ -6173,13 +6223,36 @@ static void ncr_log_hard_error(ncb_p np, u_short sist, u_char dstat) printf (".\n"); } -/*========================================================== -** +/*============================================================ ** ** ncr chip exception handler. ** +**============================================================ ** -**========================================================== +** In normal cases, interrupt conditions occur one at a +** time. The ncr is able to stack in some extra registers +** other interrupts that will occurs after the first one. +** But severall interrupts may occur at the same time. +** +** We probably should only try to deal with the normal +** case, but it seems that multiple interrupts occur in +** some cases that are not abnormal at all. +** +** The most frequent interrupt condition is Phase Mismatch. +** We should want to service this interrupt quickly. +** A SCSI parity error may be delivered at the same time. +** The SIR interrupt is not very frequent in this driver, +** since the INTFLY is likely used for command completion +** signaling. +** The Selection Timeout interrupt may be triggered with +** IID and/or UDC. +** The SBMC interrupt (SCSI Bus Mode Change) may probably +** occur at any time. +** +** This handler try to deal as cleverly as possible with all +** the above. +** +**============================================================ */ void ncr_exception (ncb_p np) @@ -6193,14 +6266,23 @@ void ncr_exception (ncb_p np) */ while ((istat = INB (nc_istat)) & INTF) { if (DEBUG_FLAGS & DEBUG_TINY) printf ("F "); +#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT + if (np->stalling) + OUTB (nc_istat, INTF); + else +#endif OUTB (nc_istat, (istat & SIGP) | INTF); np->profile.num_fly++; ncr_wakeup (np, 0); }; - if (!(istat & (SIP|DIP))) { + if (!(istat & (SIP|DIP))) return; - } + + np->profile.num_int++; + + if (istat & CABRT) + OUTB (nc_istat, CABRT); /* ** Steinbach's Guideline for Systems Programming: @@ -6209,7 +6291,6 @@ void ncr_exception (ncb_p np) sist = (istat & SIP) ? INW (nc_sist) : 0; dstat = (istat & DIP) ? INB (nc_dstat) : 0; - np->profile.num_int++; if (DEBUG_FLAGS & DEBUG_TINY) printf ("<%d|%x:%x|%x:%x>", @@ -6217,234 +6298,121 @@ void ncr_exception (ncb_p np) dstat,sist, (unsigned)INL(nc_dsp), (unsigned)INL(nc_dbc)); - if ((dstat==DFE) && (sist==PAR)) return; -/*========================================================== -** -** First the normal cases. -** -**========================================================== -*/ - /*------------------------------------------- - ** SCSI reset - **------------------------------------------- - */ - - if (sist & RST) { - ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET); - return; - }; - - /*------------------------------------------- - ** selection timeout + /*======================================================== + ** First, interrupts we want to service cleanly. ** - ** IID excluded from dstat mask! - ** (chip bug) - **------------------------------------------- - */ - - if ((sist & STO) && - !(sist & (GEN|HTH|MA|SGE|UDC|RST|PAR)) && - !(dstat & (MDPE|BF|ABRT|SIR))) { - ncr_int_sto (np); - return; - }; - - /*------------------------------------------- - ** Phase mismatch. - **------------------------------------------- - */ - - if ((sist & MA) && - !(sist & (STO|GEN|HTH|SGE|UDC|RST|PAR)) && - !(dstat & (MDPE|BF|ABRT|SIR|IID))) { - ncr_int_ma (np); + ** Phase mismatch is the most frequent interrupt, and + ** so we have to service it as quickly and as cleanly + ** as possible. + ** Programmed interrupts are rarely used in this driver, + ** but we must handle them cleanly anyway. + ** We try to deal with PAR and SBMC combined with + ** some other interrupt(s). + **========================================================= + */ + + if (!(sist & (STO|GEN|HTH|SGE|UDC|RST)) && + !(dstat & (MDPE|BF|ABRT|IID))) { + if ((sist & SBMC) && ncr_int_sbmc (np)) + return; + if ((sist & PAR) && ncr_int_par (np)) + return; + if (sist & MA) { + ncr_int_ma (np); + return; + } + if (dstat & SIR) { + ncr_int_sir (np); + return; + } + if (!(sist & (SBMC|PAR)) && !(dstat & SSI)) + printf("%s: unknown interrupt(s) ignored sist=%x dstat=%x\n", + ncr_name(np), sist, dstat); + OUTONB (nc_dcntl, (STD|NOCOM)); return; }; - /*---------------------------------------- - ** move command with length 0 - **---------------------------------------- + /*======================================================== + ** Now, interrupts that need some fixing up. + ** Order and multiple interrupts is so less important. + ** + ** If SRST has been asserted, we just reset the chip. + ** + ** Selection is intirely handled by the chip. If the + ** chip says STO, we trust it. Seems some other + ** interrupts may occur at the same time (UDC, IID), so + ** we ignore them. In any case we do enough fix-up + ** in the service routine. + ** We just exclude some fatal dma errors. + **========================================================= */ - if ((dstat & IID) && - !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) && - !(dstat & (MDPE|BF|ABRT|SIR)) && - ((INL(nc_dbc) & 0xf8000000) == SCR_MOVE_TBL)) { - /* - ** Target wants more data than available. - ** The "no_data" script will do it. - */ - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, no_data)); + if (sist & RST) { + ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET); return; }; - /*------------------------------------------- - ** Programmed interrupt - **------------------------------------------- - */ - - if ((dstat & SIR) && - !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) && - !(dstat & (MDPE|BF|ABRT|IID)) && - (INB(nc_dsps) <= SIR_MAX)) { - ncr_int_sir (np); + if ((sist & STO) && + !(dstat & (MDPE|BF|ABRT))) { + ncr_int_sto (np); return; }; - /*======================================== - ** do the register dump - **======================================== + /*========================================================= + ** Now, interrupts we are not able to recover cleanly. + ** (At least for the moment). + ** + ** Do the register dump. + ** Log message for real hard errors. + ** Clear all fifos. + ** For MDPE, BF, ABORT, IID, SGE and HTH we reset the + ** BUS and the chip. + ** We are more soft for UDC. + **========================================================= */ if (jiffies - np->regtime > 10*HZ) { - int i; np->regtime = jiffies; - for (i=0; i<sizeof(np->regdump); i++) + for (i = 0; i<sizeof(np->regdump); i++) ((char*)&np->regdump)[i] = INB_OFF(i); np->regdump.nc_dstat = dstat; np->regdump.nc_sist = sist; }; - /*========================================= - ** log message for real hard errors - **========================================= - */ ncr_log_hard_error(np, sist, dstat); - /*---------------------------------------- - ** clean up the dma fifo - **---------------------------------------- - */ - - if ( (INB(nc_sstat0) & (ILF|ORF|OLF) ) || - (INB(nc_sstat1) & (FF3210) ) || - (INB(nc_sstat2) & (ILF1|ORF1|OLF1)) || /* wide .. */ - !(dstat & DFE)) { - printf ("%s: have to clear fifos.\n", ncr_name (np)); - OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ - OUTONB (nc_ctest3, CLF); /* clear dma fifo */ - } - - /*---------------------------------------- - ** handshake timeout - **---------------------------------------- - */ - - if (sist & HTH) { - printf ("%s: handshake timeout\n", ncr_name(np)); - OUTB (nc_scntl1, CRST); - DELAY (1000); - OUTB (nc_scntl1, 0x00); - OUTB (nc_scr0, HS_FAIL); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup)); - return; - } - - /*---------------------------------------- - ** unexpected disconnect - **---------------------------------------- - */ + printf ("%s: have to clear fifos.\n", ncr_name (np)); + OUTB (nc_stest3, TE|CSF); + OUTONB (nc_ctest3, CLF); - if ((sist & UDC) && - !(sist & (STO|GEN|HTH|MA|SGE|RST|PAR)) && - !(dstat & (MDPE|BF|ABRT|SIR|IID))) { - OUTB (nc_scr0, HS_UNEXPECTED); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup)); + if ((sist & (SGE)) || + (dstat & (MDPE|BF|ABORT|IID))) { + ncr_start_reset(np, 2); return; }; - /*---------------------------------------- - ** cannot disconnect - **---------------------------------------- - */ - - if ((dstat & IID) && - !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) && - !(dstat & (MDPE|BF|ABRT|SIR)) && - ((INL(nc_dbc) & 0xf8000000) == SCR_WAIT_DISC)) { - /* - ** Unexpected data cycle while waiting for disconnect. - ** LDSC and CON bits may help in order to understand - ** what really happened. Print some info message and let - ** the reset function reset the BUS and the NCR. - */ - printf("%s:%d: data cycle while waiting for disconnect, LDSC=%d CON=%d\n", - ncr_name (np), (int)(INB(nc_ctest0)&0x0f), - (0!=(INB(nc_sstat2)&LDSC)), (0!=(INB(nc_scntl1)&ISCON))); - }; - - /*---------------------------------------- - ** single step - **---------------------------------------- - */ - - if ((dstat & SSI) && - !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) && - !(dstat & (MDPE|BF|ABRT|SIR|IID))) { - OUTONB (nc_dcntl, (STD|NOCOM)); + if (sist & HTH) { + printf ("%s: handshake timeout\n", ncr_name(np)); + ncr_start_reset(np, 2); return; }; -/* -** @RECOVER@ HTH, SGE, ABRT. -** -** We should try to recover from these interrupts. -** They may occur if there are problems with synch transfers, or -** if targets are switched on or off while the driver is running. -*/ - - if (sist & SGE) { - OUTONB (nc_ctest3, CLF); /* clear scsi offsets */ - } - - /* - ** Freeze controller to be able to read the messages. - */ - - if (DEBUG_FLAGS & DEBUG_FREEZE) { - unsigned char val; - for (i=0; i<0x60; i++) { - switch (i%16) { - - case 0: - printf ("%s: reg[%d0]: ", - ncr_name(np),i/16); - break; - case 4: - case 8: - case 12: - printf (" "); - break; - }; - val = INB_OFF(i); - printf (" %x%x", val/16, val%16); - if (i%16==15) printf (".\n"); - } - - del_timer(&np->timer); - - printf ("%s: halted!\n", ncr_name(np)); - /* - ** don't restart controller ... - */ - OUTB (nc_istat, SRST); + if (sist & UDC) { + printf ("%s: unexpected disconnect\n", ncr_name(np)); + if (INB (nc_scr1) != 0xff) { + OUTB (nc_scr1, HS_UNEXPECTED); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup)); + }; + ncr_start_reset(np, 2); return; }; -#ifdef NCR_FREEZE - /* - ** Freeze system to be able to read the messages. - */ - printf ("ncr: fatal error: system halted - press reset to reboot ..."); - cli(); - for (;;); -#endif - - /* - ** sorry, have to kill ALL jobs ... + /*========================================================= + ** We just miss the cause of the interrupt. :( + ** Print a message. The timeout will do the real work. + **========================================================= */ - - ncr_start_reset(np, 2); + printf ("%s: unknown interrupt\n", ncr_name(np)); } /*========================================================== @@ -6503,6 +6471,70 @@ void ncr_int_sto (ncb_p np) /*========================================================== ** +** ncr chip exception handler for SCSI bus mode change +** +**========================================================== +** +** I'm not quite sure of what is to be done in such a +** situation. +** For now, +** Reset the bus if some devices use too fast sync transfers. +** Otherwise, just try to renegotiate sync with targets. +** +**---------------------------------------------------------- +*/ + +static int ncr_int_sbmc (ncb_p np) +{ + u_char scsi_mode = INB (nc_stest4) & SMODE; + int i; + int oversync; + + printf("%s: SCSI bus mode change from %x to %x\n", ncr_name(np), + np->scsi_mode, scsi_mode); + + if (scsi_mode == np->scsi_mode) + return 0; + + np->scsi_mode = scsi_mode; + oversync = 0; + for (i = 0; i < MAX_TARGET; i++) { + tcb_p tp = &np->target[i]; + + if (np->ns_sync < 12 && tp->maxoffs && tp->usrsync < 12) { + if (scsi_mode != SMODE_SE) + ncr_negotiate(np, tp); + else + ++oversync; + } + } + + if (oversync) + ncr_start_reset(np, 2); + + return oversync; +} + +/*========================================================== +** +** ncr chip exception handler for SCSI parity error. +** +**========================================================== +** +** SCSI parity errors are handled by the SCSI script. +** So, we just print some message. +** +**---------------------------------------------------------- +*/ + +static int ncr_int_par (ncb_p np) +{ + printf("%s: SCSI parity error detected\n", ncr_name(np)); + return 0; +} + +/*========================================================== +** ** ** ncr chip exception handler for phase errors. ** @@ -6538,22 +6570,18 @@ static void ncr_int_ma (ncb_p np) /* ** Take into account dma fifo and various buffers and latches, - ** only if the interrupted phase in an OUTPUT phase. + ** only if the interrupted phase was DATA OUT. */ - if ((cmd & 1) == 0) { + if ((cmd & 7) == 0) { u_char ctest5, ss0, ss2; u_short delta; - if (!(INB(nc_dstat) & DFE)) { - ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0; - if (ctest5 & DFS) - delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff; - else - delta=(INB (nc_dfifo) - rest) & 0x7f; - } else { - delta = 0; - } + ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0; + if (ctest5 & DFS) + delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff; + else + delta=(INB (nc_dfifo) - rest) & 0x7f; /* ** The data in the dma fifo has not been transfered to @@ -6582,9 +6610,10 @@ static void ncr_int_ma (ncb_p np) } else { if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) printf ("P%x%x RL=%d ", cmd&7, sbcl&7, rest); - if (!(INB(nc_dstat) & DFE)) - printf("INPUT phase mismatch with DMA fifo not empty, P%x%x RL=%d\n", - cmd&7, sbcl&7, rest); + if ((cmd & 7) != 1) { + OUTONB (nc_ctest3, CLF ); + OUTB (nc_stest3, TE|CSF); + } } /* @@ -6660,7 +6689,7 @@ static void ncr_int_ma (ncb_p np) }; /* - ** if old phase not dataphase, leave here. + ** check cmd against assumed interrupted script command. */ if (cmd != (vdsp[0] >> 24)) { @@ -6670,6 +6699,18 @@ static void ncr_int_ma (ncb_p np) return; } + +#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT + if ((cmd & 7) == 1 && np->assert_atn) { + np->assert_atn = 0; + OUTONB(nc_socl, CATN); + } +#endif + + /* + ** if old phase not dataphase, leave here. + */ + if (cmd & 0x06) { PRINT_ADDR(cp->cmd); printf ("phase change %x-%x %d@%08x resid=%d.\n", @@ -6712,7 +6753,10 @@ static void ncr_int_ma (ncb_p np) */ np->profile.num_break++; OUTL (nc_temp, vtophys (newcmd)); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch)); + if ((cmd & 7) == 0) + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch)); + else + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, checkatn)); } /*========================================================== @@ -6778,15 +6822,24 @@ void ncr_int_sir (ncb_p np) } switch (num) { + u_long endp; case SIR_DATA_IO_IS_OUT: + case SIR_DATA_IO_IS_IN: /* -** We did not guess the direction of transfer. We assumed DATA IN, -** but the the target drove DATA OUT. -** We have to patch the script context with DATA OUT context and -** restart processing at data out script address. -*/ - cp->phys.header.savep = NCB_SCRIPTH_PHYS (np, data_out); - cp->phys.header.goalp = cp->phys.header.savep +20 +cp->segments*16; +** We did not guess the direction of transfer. We have to wait for +** actual data direction driven by the target before setting +** pointers. We must patch the global header too. +*/ + if (num == SIR_DATA_IO_IS_OUT) { + endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16; + cp->phys.header.goalp = endp + 8; + cp->phys.header.savep = endp - cp->segments*16; + } else { + endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16; + cp->phys.header.goalp = endp + 8; + cp->phys.header.savep = endp - cp->segments*16; + } + cp->phys.header.lastp = cp->phys.header.savep; np->header.savep = cp->phys.header.savep; np->header.goalp = cp->phys.header.goalp; @@ -7276,6 +7329,7 @@ void ncr_int_sir (ncb_p np) (unsigned) np->header.goalp); break; +#if 0 /* This stuff does not work */ /*-------------------------------------------------------------------- ** ** Processing of a "S_QUEUE_FULL" status. @@ -7353,6 +7407,7 @@ void ncr_int_sir (ncb_p np) printf ("%s: queue empty.\n", ncr_name (np)); np->script->start1[0] = SCR_INT ^ IFFALSE (0); break; +#endif /* This stuff does not work */ }; out: @@ -7362,7 +7417,7 @@ out: /*========================================================== ** ** -** Acquire a control block +** Aquire a control block ** ** **========================================================== @@ -7496,10 +7551,10 @@ static void ncr_alloc_ccb (ncb_p np, u_long target, u_long lun) tp->jump_tcb.l_cmd = (SCR_JUMP^IFFALSE (DATA (0x80 + target))); tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr; - tp->getscr[0] = SCR_COPY (1); + tp->getscr[0] = (np->features & _F_PFEN)? SCR_COPY(1) : SCR_COPY_F(1); tp->getscr[1] = vtophys (&tp->sval); tp->getscr[2] = np->paddr + offsetof (struct ncr_reg, nc_sxfer); - tp->getscr[3] = SCR_COPY (1); + tp->getscr[3] = (np->features & _F_PFEN)? SCR_COPY(1) : SCR_COPY_F(1); tp->getscr[4] = vtophys (&tp->wval); tp->getscr[5] = np->paddr + offsetof (struct ncr_reg, nc_scntl3); @@ -7712,12 +7767,15 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd) int segment = 0; int use_sg = (int) cmd->use_sg; +#if 0 bzero (cp->phys.data, sizeof (cp->phys.data)); +#endif data = cp->phys.data; cp->data_len = 0; if (!use_sg) { if (cmd->request_bufflen) { + data = &data[MAX_SCATTER - 1]; data[0].addr = vtophys(cmd->request_buffer); data[0].size = cmd->request_bufflen; cp->data_len = data[0].size; @@ -7727,6 +7785,7 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd) else if (use_sg <= MAX_SCATTER) { struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; + data = &data[MAX_SCATTER - use_sg]; while (segment < use_sg) { data[segment].addr = vtophys(scatter[segment].address); data[segment].size = scatter[segment].length; @@ -7753,7 +7812,9 @@ static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd) */ #ifndef NCR_IOMAPPED +__initfunc( static int ncr_regtest (struct ncb* np) +) { register volatile u_long data; /* @@ -7777,7 +7838,9 @@ static int ncr_regtest (struct ncb* np) } #endif +__initfunc( static int ncr_snooptest (struct ncb* np) +) { u_long ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc, err=0; int i; @@ -7801,6 +7864,7 @@ static int ncr_snooptest (struct ncb* np) /* ** Start script (exchange values) */ +flush_cache_all(); OUTL (nc_dsp, pc); /* ** Wait 'til done (with timeout) @@ -7871,7 +7935,7 @@ static int ncr_snooptest (struct ncb* np) **========================================================== */ -#ifdef SCSI_NCR_PROFILE +#ifdef SCSI_NCR_PROFILE_SUPPORT /* ** Compute the difference in jiffies ticks. @@ -7883,7 +7947,7 @@ static int ncr_snooptest (struct ncb* np) #define PROFILE cp->phys.header.stamp static void ncb_profile (ncb_p np, ccb_p cp) { - int co, da, st, en, di, se, post,work,disc; + int co, st, en, di, se, post,work,disc; u_long diff; PROFILE.end = jiffies; @@ -7891,9 +7955,6 @@ static void ncb_profile (ncb_p np, ccb_p cp) st = ncr_delta (PROFILE.start,PROFILE.status); if (st<0) return; /* status not reached */ - da = ncr_delta (PROFILE.start,PROFILE.data); - if (da<0) return; /* No data transfer phase */ - co = ncr_delta (PROFILE.start,PROFILE.command); if (co<0) return; /* command not executed */ @@ -7930,7 +7991,7 @@ static void ncb_profile (ncb_p np, ccb_p cp) } #undef PROFILE -#endif /* SCSI_NCR_PROFILE */ +#endif /* SCSI_NCR_PROFILE_SUPPORT */ /*========================================================== ** @@ -7991,7 +8052,7 @@ static u_long ncr_lookup(char * id) /*========================================================== ** ** Determine the ncr's clock frequency. -** This is important for the negotiation +** This is essential for the negotiation ** of the synchronous transfer rate. ** **========================================================== @@ -7999,20 +8060,53 @@ static u_long ncr_lookup(char * id) ** Note: we have to return the correct value. ** THERE IS NO SAVE DEFAULT VALUE. ** -** We assume that all NCR based boards are delivered -** with a 40Mhz clock. Because we have to divide -** by an integer value greater than 3, only clock -** frequencies of 40Mhz (/4) or 50MHz (/5) permit -** the FAST-SCSI rate of 10MHz. +** Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock. +** 53C860 and 53C875 rev. 1 support fast20 transfers but +** do not have a clock doubler and so are provided with a +** 80 MHz clock. All other fast20 boards incorporate a doubler +** and so should be delivered with a 40 MHz clock. +** The future fast40 chips (895/895) use a 40 Mhz base clock +** and provide a clock quadrupler (160 Mhz). The code below +** tries to deal as cleverly as possible with all this stuff. ** **---------------------------------------------------------- */ /* + * Select NCR SCSI clock frequency + */ +static void ncr_selectclock(ncb_p np, u_char scntl3) +{ + if (np->multiplier < 2) { + OUTB(nc_scntl3, scntl3); + return; + } + + if (bootverbose >= 2) + printf ("%s: enabling clock multiplier\n", ncr_name(np)); + + OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */ + if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */ + int i = 20; + while (!(INB(nc_stest4) & LCKFRQ) && --i > 0) + DELAY(20); + if (!i) + printf("%s: the chip cannot lock the frequency\n", ncr_name(np)); + } else /* Wait 20 micro-seconds for doubler */ + DELAY(20); + OUTB(nc_stest3, HSC); /* Halt the scsi clock */ + OUTB(nc_scntl3, scntl3); + OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ + OUTB(nc_stest3, 0x00); /* Restart scsi clock */ +} + + +/* * calculate NCR SCSI clock frequency (in KHz) */ -static unsigned -ncrgetfreq (ncb_p np, int gen) +__initfunc( +static unsigned ncrgetfreq (ncb_p np, int gen) +) { unsigned ms = 0; @@ -8058,38 +8152,11 @@ ncrgetfreq (ncb_p np, int gen) } /* - * Select NCR SCSI clock frequency - */ -static void ncr_selectclock(ncb_p np, u_char scntl3) -{ - if (np->multiplier < 2) { - OUTB(nc_scntl3, scntl3); - return; - } - - if (bootverbose >= 2) - printf ("%s: enabling clock multiplier\n", ncr_name(np)); - - OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */ - if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */ - int i = 20; - while (!(INB(nc_stest4) & 0x20) && --i > 0) - DELAY(20); - if (!i) - printf("%s: the chip cannot lock the frequency\n", ncr_name(np)); - } else /* Wait 20 micro-seconds for doubler */ - DELAY(20); - OUTB(nc_stest3, 0x20); /* Halt the scsi clock */ - OUTB(nc_scntl3, scntl3); - OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ - OUTB(nc_stest3, 0x00); /* Restart scsi clock */ -} - - -/* * Get/probe NCR SCSI clock frequency */ +__initfunc( static void ncr_getclock (ncb_p np, int mult) +) { unsigned char scntl3 = INB(nc_scntl3); unsigned char stest1 = INB(nc_stest1); @@ -8151,58 +8218,14 @@ static void ncr_getclock (ncb_p np, int mult) np->ns_sync = 25; if (f1 >= 160000) { - if (driver_setup.ultra_scsi) np->ns_sync = 10; - np->rv_scntl3 = 7; + if (np->features & _F_ULTRA2) np->ns_sync = 10; + else if (np->features & _F_ULTRA) np->ns_sync = 12; } else if (f1 >= 80000) { - if (driver_setup.ultra_scsi) np->ns_sync = 12; - np->rv_scntl3 = 5; - } - else { - np->rv_scntl3 = 3; - } - - if (bootverbose > 1) { - printf ("%s: initial value of SCNTL3 = %02x, final = %02x\n", - ncr_name(np), scntl3, np->rv_scntl3); + if (np->features & _F_ULTRA) np->ns_sync = 12; } } -/* -** Save some features set by bios -** -** DMODE 0xce -** 0x02 burst op-code fetch -** 0x04 enable read multiple -** 0x08 enable read line -** 0xc0 burst length 16/8/2 -** DCNTL 0xa8 -** 0x08 totem pole irq -** 0x20 enable pre-fetch -** 0x80 enable cache line size -** CTEST3 0x01 -** 0x01 set write and invalidate -** CTEST4 0x80 -** 0x80 burst disabled -** CTEST5 0x24 -** 0x20 large dma fifo (875 and 895 only) -** 0x04 burst len 32/64/128 (875 and 895 only) -** GPCNTL general purpose control register -** STEST2 0x20 differential mode -*/ - -static void ncr_save_bios_setting(ncb_p np) -{ - np->sv_scntl3 = INB(nc_scntl3) & 0x07; - np->sv_dmode = INB(nc_dmode) & 0xce; - np->sv_dcntl = INB(nc_dcntl) & 0xa8; - np->sv_ctest3 = INB(nc_ctest3) & 0x01; - np->sv_ctest4 = INB(nc_ctest4) & 0x80; - np->sv_ctest5 = INB(nc_ctest5) & 0x24; - np->sv_gpcntl = INB(nc_gpcntl); - np->sv_stest2 = INB(nc_stest2) & 0x20; -} - /*===================== LINUX ENTRY POINTS SECTION ==========================*/ #ifndef uchar @@ -8224,8 +8247,11 @@ static void ncr_save_bios_setting(ncb_p np) ** --------------------------------------------------------------------- */ +__initfunc( void ncr53c8xx_setup(char *str, int *ints) +) { +#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT char *cur = str; char *pv; int val; @@ -8295,6 +8321,8 @@ void ncr53c8xx_setup(char *str, int *ints) driver_setup.diff_support= val; else if (!strncmp(cur, "irqm:", 5)) driver_setup.irqm = val; + else if (!strncmp(cur, "pcifix:", 7)) + driver_setup.pci_fix_up = val; else if (!strncmp(cur, "safe:", 5) && val) memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup)); @@ -8302,34 +8330,11 @@ void ncr53c8xx_setup(char *str, int *ints) if ((cur = strchr(cur, ',')) != NULL) ++cur; } +#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */ } -static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int chip, - uchar bus, uchar device_fn, int options); - -/* -** NCR53C8XX devices description table -*/ - -static struct { - ushort pci_device_id; - int chip; - int max_revision; - int min_revision; -} pci_chip_ids[] = { - {PCI_DEVICE_ID_NCR_53C810, 810, -1, -1}, -/* {PCI_DEVICE_ID_NCR_53C810AP, 810, -1, -1}, */ - {PCI_DEVICE_ID_NCR_53C815, 815, -1, -1}, - {PCI_DEVICE_ID_NCR_53C820, 820, -1, -1}, - {PCI_DEVICE_ID_NCR_53C825, 825, -1, -1}, - {PCI_DEVICE_ID_NCR_53C860, 860, -1, -1}, - {PCI_DEVICE_ID_NCR_53C875, 875, -1, -1}, - {PCI_DEVICE_ID_NCR_53C885, 885, -1, -1}, - {PCI_DEVICE_ID_NCR_53C895, 895, -1, -1}, - {PCI_DEVICE_ID_NCR_53C896, 896, -1, -1} -}; - -#define NPCI_CHIP_IDS (sizeof (pci_chip_ids) / sizeof(pci_chip_ids[0])) +static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, + uchar bus, uchar device_fn); /* ** Linux entry point for NCR53C8XX devices detection routine. @@ -8343,16 +8348,12 @@ static struct { ** Returns the number of boards successfully attached. */ -int ncr53c8xx_detect(Scsi_Host_Template *tpnt) +__initfunc( +static void ncr_print_driver_setup(void) +) { - int i, j; - int count = 0; /* Number of boards detected */ - uchar pci_bus, pci_device_fn; - short pci_index; /* Device index to PCI BIOS calls */ - #define YesNo(y) y ? 'y' : 'n' - if (bootverbose >= 2) { - printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n", + printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n", YesNo(driver_setup.disconnection), YesNo(driver_setup.special_features), YesNo(driver_setup.ultra_scsi), @@ -8361,7 +8362,7 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt) driver_setup.burst_max, YesNo(driver_setup.max_wide), driver_setup.diff_support); - printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n", + printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n", YesNo(driver_setup.master_parity), YesNo(driver_setup.scsi_parity), YesNo(driver_setup.force_sync_nego), @@ -8370,10 +8371,30 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt) YesNo(driver_setup.led_pin), driver_setup.settle_delay, driver_setup.irqm); - } #undef YesNo +} -#ifdef SCSI_NCR_DEBUG +/* +** NCR53C8XX devices description table and chip ids list. +*/ + +static ncr_chip ncr_chip_table[] __initdata = SCSI_NCR_CHIP_TABLE; +static ushort ncr_chip_ids[] __initdata = SCSI_NCR_CHIP_IDS; + +__initfunc( +int ncr53c8xx_detect(Scsi_Host_Template *tpnt) +) +{ + int i, j; + int chips; + int count = 0; + uchar bus, device_fn; + short index; + + if (bootverbose >= 2) + ncr_print_driver_setup(); + +#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT ncr_debug = driver_setup.debug; #endif @@ -8384,21 +8405,21 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt) # endif #endif - if (pcibios_present()) { - for (j = 0; j < NPCI_CHIP_IDS; ++j) { - i = driver_setup.reverse_probe ? NPCI_CHIP_IDS-1 - j : j; - for (pci_index = 0; - !pcibios_find_device(PCI_VENDOR_ID_NCR, - pci_chip_ids[i].pci_device_id, pci_index, &pci_bus, - &pci_device_fn); - ++pci_index) - if (!ncr53c8xx_pci_init(tpnt, count, 0, pci_chip_ids[i].chip, - pci_bus, pci_device_fn, /* no options */ 0)) - ++count; - } - } + if (!pcibios_present()) + return 0; - return count; + chips = sizeof(ncr_chip_ids) / sizeof(ncr_chip_ids[0]); + for (j = 0; j < chips ; ++j) { + i = driver_setup.reverse_probe ? chips-1 - j : j; + for (index = 0; ; index++) { + if (pcibios_find_device(PCI_VENDOR_ID_NCR, ncr_chip_ids[i], + index, &bus, &device_fn)) + break; + if (!ncr53c8xx_pci_init(tpnt, count, bus, device_fn)) + ++count; + } + } + return count; } @@ -8440,6 +8461,17 @@ static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int pcibios_strerror(error)); return -1; } +#ifdef CONFIG_SNI_RM200_PCI + /* + * The onboard NCR bypasses the normal PCI interrupt system. + */ + if (mips_machgroup == MACH_GROUP_SNI_RM + && mips_machtype == MACH_SNI_RM200_PCI + && bus == 0 && device_fn == PCI_DEVFN(0, 1)) + irq = PCIMT_IRQ_SCSI; +printk("ncr53c8xx_pci_init() #1: bus == %d, device_fn == %d\n", bus, device_fn); +#endif + if (vendor_id != PCI_VENDOR_ID_NCR) { printk("ncr53c8xx: not initializing, 0x%04x is not NCR vendor ID\n", (int) vendor_id); @@ -8527,7 +8559,7 @@ static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_de device->queue_depth = 1; #endif -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n", device->id, device->lun, device->queue_depth); #endif @@ -8543,19 +8575,19 @@ printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n", int ncr53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { int sts; -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printk("ncr53c8xx_queue_command\n"); #endif if ((sts = ncr_queue_command(cmd, done)) != DID_OK) { cmd->result = ScsiResult(sts, 0); done(cmd); -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printk("ncr53c8xx : command not queued - result=%d\n", sts); #endif return sts; } -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printk("ncr53c8xx : command successfully queued\n"); #endif return sts; @@ -8573,8 +8605,14 @@ static void ncr53c8xx_intr(int irq, struct pt_regs * regs) { struct Scsi_Host *host; struct host_data *host_data; +#if 0 + u_long flags; -#ifdef DEBUG + save_flags(flags); cli(); +#endif + +printk("Yow, an NCR interrupt!\n"); +#ifdef DEBUG_NCR53C8XX printk("ncr53c8xx : interrupt received\n"); #endif @@ -8583,12 +8621,20 @@ printk("ncr53c8xx : interrupt received\n"); host_data = (struct host_data *) host->hostdata; #if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) # ifdef SCSI_NCR_SHARE_IRQ - if (dev_id == host_data->ncb) + if (dev_id == host_data->ncb) { +#else + if (1) { # endif #endif - ncr_intr(host_data->ncb); + if (DEBUG_FLAGS & DEBUG_TINY) printf ("["); + ncr_exception(host_data->ncb); + if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n"); + } } } +#if 0 + restore_flags(flags); +#endif } /* @@ -8696,7 +8742,7 @@ int ncr53c8xx_abort(Scsi_Cmnd *cmd) int ncr53c8xx_release(struct Scsi_Host *host) { struct host_data *host_data; -#ifdef DEBUG +#ifdef DEBUG_NCR53C8XX printk("ncr53c8xx : release\n"); #endif @@ -8847,6 +8893,8 @@ static int guess_xfer_direction(int opcode) **========================================================================= */ +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT + #define is_digit(c) ((c) >= '0' && (c) <= '9') #define digit_to_bin(c) ((c) - '0') #define is_space(c) ((c) == ' ' || (c) == '\t') @@ -8928,6 +8976,10 @@ static int ncr_user_command(ncb_p np, char *buffer, int length) uc->cmd = UC_SETFLAG; else if ((arg_len = is_keyword(ptr, len, "clearprof")) != 0) uc->cmd = UC_CLEARPROF; +#ifdef UC_DEBUG_ERROR_RECOVERY + else if ((arg_len = is_keyword(ptr, len, "debug_error_recovery")) != 0) + uc->cmd = UC_DEBUG_ERROR_RECOVERY; +#endif else arg_len = 0; @@ -9028,13 +9080,30 @@ printf("ncr_user_command: data=%ld\n", uc->data); ptr += arg_len; len -= arg_len; } break; +#ifdef UC_DEBUG_ERROR_RECOVERY + case UC_DEBUG_ERROR_RECOVERY: + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "sge"))) + uc->data = 1; + else if ((arg_len = is_keyword(ptr, len, "abort"))) + uc->data = 2; + else if ((arg_len = is_keyword(ptr, len, "reset"))) + uc->data = 3; + else if ((arg_len = is_keyword(ptr, len, "parity"))) + uc->data = 4; + else if ((arg_len = is_keyword(ptr, len, "none"))) + uc->data = 0; + else + return -EINVAL; + ptr += arg_len; len -= arg_len; + break; +#endif default: break; } if (len) return -EINVAL; -#ifdef SCSI_NCR_USER_COMMAND else { long flags; @@ -9042,10 +9111,13 @@ printf("ncr_user_command: data=%ld\n", uc->data); ncr_usercmd (np); restore_flags(flags); } -#endif return length; } +#endif /* SCSI_NCR_USER_COMMAND_SUPPORT */ + +#ifdef SCSI_NCR_USER_INFO_SUPPORT + struct info_str { char *buffer; @@ -9104,7 +9176,7 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) info.pos = 0; copy_info(&info, "General information:\n"); - copy_info(&info, " Chip NCR53C%03d, ", np->chip); + copy_info(&info, " Chip NCR53C%s, ", np->chip_name); copy_info(&info, "device id 0x%x, ", np->device_id); copy_info(&info, "revision id 0x%x\n", np->revision_id); @@ -9124,7 +9196,7 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) copy_info(&info, "verbosity level %d\n", driver_setup.verbose); } -#ifdef SCSI_NCR_PROFILE +#ifdef SCSI_NCR_PROFILE_SUPPORT copy_info(&info, "Profiling information:\n"); copy_info(&info, " %-12s = %lu\n", "num_trans",np->profile.num_trans); copy_info(&info, " %-12s = %lu\n", "num_kbytes",np->profile.num_kbytes); @@ -9141,6 +9213,8 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) return info.pos > info.offset? info.pos - info.offset : 0; } +#endif /* SCSI_NCR_USER_INFO_SUPPORT */ + /* ** Entry point of the scsi proc fs of the driver. ** - func = 0 means read (returns profile data) @@ -9171,20 +9245,26 @@ printf("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func); return -EINVAL; if (func) { +#ifdef SCSI_NCR_USER_COMMAND_SUPPORT retv = ncr_user_command(ncb, buffer, length); -#ifdef DEBUG_PROC_INFO -printf("ncr_user_command: retv=%d\n", retv); +#else + retv = -EINVAL; #endif } else { if (start) *start = buffer; +#ifdef SCSI_NCR_USER_INFO_SUPPORT retv = ncr_host_info(ncb, buffer, offset, length); +#else + retv = -EINVAL; +#endif } return retv; } + /*========================================================================= ** End of proc file system stuff **========================================================================= |