patch-2.3.20 linux/drivers/scsi/sym53c8xx.c

Next file: linux/drivers/scsi/sym53c8xx.h
Previous file: linux/drivers/scsi/sim710_u.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.19/linux/drivers/scsi/sym53c8xx.c linux/drivers/scsi/sym53c8xx.c
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-1999  Gerard Roudier <groudier@club-internet.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
@@ -55,7 +55,7 @@
 */
 
 /*
-**	April 2 1999, sym53c8xx version 1.3c
+**	Sep 10 1999, sym53c8xx 1.5e
 **
 **	Supported SCSI features:
 **	    Synchronous data transfers
@@ -64,13 +64,14 @@
 **	    Tagged command queuing
 **	    SCSI Parity checking
 **
-**	Supported NCR chips:
+**	Supported NCR/SYMBIOS chips:
 **		53C810A	  (8 bits, Fast 10,	 no rom BIOS) 
 **		53C825A	  (Wide,   Fast 10,	 on-board rom BIOS)
 **		53C860	  (8 bits, Fast 20,	 no rom BIOS)
 **		53C875	  (Wide,   Fast 20,	 on-board rom BIOS)
 **		53C876	  (Wide,   Fast 20 Dual, on-board rom BIOS)
 **		53C895	  (Wide,   Fast 40,	 on-board rom BIOS)
+**		53C895A	  (Wide,   Fast 40,	 on-board rom BIOS)
 **		53C896	  (Wide,   Fast 40 Dual, on-board rom BIOS)
 **
 **	Other features:
@@ -82,7 +83,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.3c"
+#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.5e"
 
 /* #define DEBUG_896R1 */
 #define SCSI_NCR_OPTIMIZE_896
@@ -109,8 +110,10 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
 #include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#include <asm/spinlock.h>
 #endif
 #include <linux/delay.h>
 #include <linux/signal.h>
@@ -130,13 +133,13 @@
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
 #include <linux/init.h>
-#else
-#ifndef	__initdata
-#define	__initdata
 #endif
+
 #ifndef	__init
 #define	__init
 #endif
+#ifndef	__initdata
+#define	__initdata
 #endif
 
 #if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
@@ -314,26 +317,34 @@
 #endif
 
 /*
-**    TAGS are actually limited to 64 tags/lun.
-**    We need to deal with power of 2, for alignment constraints.
+**    TAGS are actually unlimited (256 tags/lun).
+**    But Linux only supports 255. :)
 */
-#if	SCSI_NCR_MAX_TAGS > 64
-#undef	SCSI_NCR_MAX_TAGS
-#define	SCSI_NCR_MAX_TAGS (64)
+#if	SCSI_NCR_MAX_TAGS > 255
+#define	MAX_TAGS	255
+#else
+#define	MAX_TAGS SCSI_NCR_MAX_TAGS
 #endif
 
-#define NO_TAG	(255)
-
 /*
-**	Choose appropriate type for tag bitmap.
+**    Since the ncr chips only have a 8 bit ALU, we try to be clever 
+**    about offset calculation in the TASK TABLE per LUN that is an 
+**    array of DWORDS = 4 bytes.
 */
-#if	SCSI_NCR_MAX_TAGS > 32
-typedef u_int64 tagmap_t;
+#if	MAX_TAGS > (512/4)
+#define MAX_TASKS  (1024/4)
+#elif	MAX_TAGS > (256/4) 
+#define MAX_TASKS  (512/4)
 #else
-typedef u_int32 tagmap_t;
+#define MAX_TASKS  (256/4)
 #endif
 
 /*
+**    This one means 'NO TAG for this job'
+*/
+#define NO_TAG	(256)
+
+/*
 **    Number of targets supported by the driver.
 **    n permits target numbers 0..n-1.
 **    Default is 16, meaning targets #0..#15.
@@ -354,7 +365,7 @@
 */
 
 #ifdef SCSI_NCR_MAX_LUN
-#define MAX_LUN    SCSI_NCR_MAX_LUN
+#define MAX_LUN    64
 #else
 #define MAX_LUN    (1)
 #endif
@@ -377,51 +388,34 @@
 #ifdef SCSI_NCR_CAN_QUEUE
 #define MAX_START   (SCSI_NCR_CAN_QUEUE + 4)
 #else
-#define MAX_START   (MAX_TARGET + 7 * SCSI_NCR_MAX_TAGS)
+#define MAX_START   (MAX_TARGET + 7 * MAX_TAGS)
+#endif
+
+/*
+**    We donnot want to allocate more than 1 PAGE for the 
+**    the start queue and the done queue. We hard-code entry 
+**    size to 8 in order to let cpp do the checking.
+**    Allows 512-4=508 pending IOs for i386 but Linux seems for 
+**    now not able to provide the driver with this amount of IOs.
+*/
+#if	MAX_START > PAGE_SIZE/8
+#undef	MAX_START
+#define MAX_START (PAGE_SIZE/8)
 #endif
 
 /*
 **    The maximum number of segments a transfer is split into.
 **    We support up to 127 segments for both read and write.
-**    Since we try to avoid phase mismatches by testing the PHASE 
-**    before each MOV, the both DATA_IN and DATA_OUT scripts do 
-**    not fit in the 4K on-chip RAM. For this reason, the data 
-**    scripts are broken into 2 sub-scripts.
-**    80 (MAX_SCATTERL) segments are moved from a sub-script 
-**    in on-chip RAM. This makes data transfers shorter than 
-**    80k (assuming 1k fs) as fast as possible.
-**    The 896 allows to handle phase mismatches from SCRIPTS.
-**    So, for this chip, we use a simple array of MOV's.
-**    Perhaps, using a simple array of MOV's and going with 
-**    the phase mismatch interrupt is also the best solution 
-**    for the 895 in Ultra2-mode, since the PHASE test + MOV 
-**    latency may be enough to fill the SCSI offset for very  
-**    fast disks like the Cheatah Wide LVD and so, may waste 
-**    SCSI BUS bandwitch.
 */
 
 #define MAX_SCATTER (SCSI_NCR_MAX_SCATTER)
-
-#ifdef	SCSI_NCR_OPTIMIZE_896
 #define	SCR_SG_SIZE	(2)
-#define MAX_SCATTERL	MAX_SCATTER
-#define MAX_SCATTERH	0
-#else
-#if (MAX_SCATTER > 80)
-#define	SCR_SG_SIZE	(4)
-#define MAX_SCATTERL	80
-#define	MAX_SCATTERH	(MAX_SCATTER - MAX_SCATTERL)
-#else
-#define MAX_SCATTERL	MAX_SCATTER
-#define	MAX_SCATTERH	0
-#endif
-#endif	/* SCSI_NCR_OPTIMIZE_896 */
 
 /*
 **    Io mapped or memory mapped.
 */
 
-#if defined(SCSI_NCR_IOMAPPED)
+#if defined(SCSI_NCR_IOMAPPED) || defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
 #define NCR_IOMAPPED
 #endif
 
@@ -464,17 +458,14 @@
 
 #define DEBUG_ALLOC    (0x0001)
 #define DEBUG_PHASE    (0x0002)
-#define DEBUG_POLL     (0x0004)
 #define DEBUG_QUEUE    (0x0008)
 #define DEBUG_RESULT   (0x0010)
-#define DEBUG_SCATTER  (0x0020)
+#define DEBUG_POINTER  (0x0020)
 #define DEBUG_SCRIPT   (0x0040)
 #define DEBUG_TINY     (0x0080)
 #define DEBUG_TIMING   (0x0100)
 #define DEBUG_NEGO     (0x0200)
 #define DEBUG_TAGS     (0x0400)
-#define DEBUG_FREEZE   (0x0800)
-#define DEBUG_RESTART  (0x1000)
 
 /*
 **    Enable/Disable debug messages.
@@ -569,12 +560,19 @@
 #endif
 
 #ifdef __sparc__
-#define pcivtobus(p)			((p) & pci_dvma_mask)
-#else	/* __sparc__ */
-#define pcivtobus(p)			(p)
+#  define ioremap(base, size)	((u_long) __va(base))
+#  define iounmap(vaddr)
+#  define pcivtobus(p)			((p) & pci_dvma_mask)
+#  define memcpy_to_pci(a, b, c)	memcpy_toio((u_long) (a), (b), (c))
+#elif defined(__alpha__)
+#  define pcivtobus(p)			((p) & 0xfffffffful)
+#  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
+#else	/* others */
+#  define pcivtobus(p)			(p)
+#  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
 #endif
 
-#if !defined(NCR_IOMAPPED) || defined(__i386__)
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 static u_long __init remap_pci_mem(u_long base, u_long size)
 {
 	u_long page_base	= ((u_long) base) & PAGE_MASK;
@@ -589,7 +587,8 @@
 	if (vaddr)
 		iounmap((void *) (vaddr & PAGE_MASK));
 }
-#endif	/* !NCR_IOMAPPED || __i386__ */
+
+#endif /* not def SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
 
 /*
 **	Insert a delay in micro-seconds and milli-seconds.
@@ -760,7 +759,7 @@
 	NCR_UNLOCK_DRIVER(flags);
 
 	if (DEBUG_FLAGS & DEBUG_ALLOC)
-		printk ("new %s[%d] @%p.\n", name, size, p);
+		printk ("new %-10s[%4d] @%p.\n", name, size, p);
 
 	if (p)
 		memset(p, 0, size);
@@ -775,13 +774,26 @@
 	u_long flags;
 
 	if (DEBUG_FLAGS & DEBUG_ALLOC)
-		printk ("freeing %s[%d] @%p.\n", name, size, ptr);
+		printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
 
 	NCR_LOCK_DRIVER(flags);
 	__m_free(ptr, size);
 	NCR_UNLOCK_DRIVER(flags);
 }
 
+static void ncr_print_hex(u_char *p, int n)
+{
+	while (n-- > 0)
+		printk (" %x", *p++);
+}
+
+static void ncr_printl_hex(char *label, u_char *p, int n)
+{
+	printk("%s", label);
+	ncr_print_hex(p, n);
+	printk (".\n");
+}
+
 /*
 **	Transfer direction
 **
@@ -831,34 +843,6 @@
 **	This structure is initialized from linux config options.
 **	It can be overridden at boot-up by the boot command line.
 */
-#define SCSI_NCR_MAX_EXCLUDES 8
-struct ncr_driver_setup {
-	u_char	master_parity;
-	u_char	scsi_parity;
-	u_char	disconnection;
-	u_char	special_features;
-	u_char	ultra_scsi;
-	u_char	force_sync_nego;
-	u_char	reverse_probe;
-	u_char	pci_fix_up;
-	u_char	use_nvram;
-	u_char	verbose;
-	u_char	default_tags;
-	u_short	default_sync;
-	u_short	debug;
-	u_char	burst_max;
-	u_char	led_pin;
-	u_char	max_wide;
-	u_char	settle_delay;
-	u_char	diff_support;
-	u_char	irqm;
-	u_char	bus_check;
-	u_char	optimize;
-	u_char	recovery;
-	u_int	excludes[SCSI_NCR_MAX_EXCLUDES];
-	char	tag_ctrl[100];
-};
-
 static struct ncr_driver_setup
 	driver_setup			= SCSI_NCR_DRIVER_SETUP;
 
@@ -888,134 +872,7 @@
 #define bootverbose (np->verbose)
 
 #ifdef SCSI_NCR_NVRAM_SUPPORT
-/*
-**	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 */
-	u_int32	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_devives;	/* 0x00 */
-	u_char	rsvd;
-
-/* 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_NVRAM_ADDRESS 0
-
-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;
-
 static u_char Tekram_sync[12] __initdata = {25,31,37,43,50,62,75,125,12,15,18,21};
-
 #endif /* SCSI_NCR_NVRAM_SUPPORT */
 
 /*
@@ -1282,36 +1139,38 @@
 
 #define	SIR_BAD_STATUS		(1)
 #define	SIR_SEL_ATN_NO_MSG_OUT	(2)
-#define	SIR_NEGO_SYNC		(3)
-#define	SIR_NEGO_WIDE		(4)
+#define	SIR_MSG_RECEIVED	(3)
+#define	SIR_MSG_WEIRD		(4)
 #define	SIR_NEGO_FAILED		(5)
 #define	SIR_NEGO_PROTO		(6)
-#define	SIR_REJECT_RECEIVED	(7)
+#define	SIR_SCRIPT_STOPPED	(7)
 #define	SIR_REJECT_TO_SEND	(8)
-#define	SIR_IGN_RESIDUE		(9)
-#define	SIR_MISSING_SAVE	(10)
+#define	SIR_SWIDE_OVERRUN	(9)
+#define	SIR_SODL_UNDERRUN	(10)
 #define	SIR_RESEL_NO_MSG_IN	(11)
 #define	SIR_RESEL_NO_IDENTIFY	(12)
 #define	SIR_RESEL_BAD_LUN	(13)
-#define	SIR_UNUSED_14		(14)
+#define	SIR_TARGET_SELECTED	(14)
 #define	SIR_RESEL_BAD_I_T_L	(15)
 #define	SIR_RESEL_BAD_I_T_L_Q	(16)
-#define	SIR_UNUSED_17		(17)
+#define	SIR_ABORT_SENT		(17)
 #define	SIR_RESEL_ABORTED	(18)
 #define	SIR_MSG_OUT_DONE	(19)
-#define	SIR_MAX			(19)
+#define	SIR_AUTO_SENSE_DONE	(20)
+#define	SIR_DUMMY_INTERRUPT	(21)
+#define	SIR_MAX			(21)
 
 /*==========================================================
 **
-**	Extended error codes.
+**	Extended error bits.
 **	xerr_status field of struct ccb.
 **
 **==========================================================
 */
 
-#define	XE_OK		(0)
-#define	XE_EXTRA_DATA	(1)	/* unexpected data phase */
-#define	XE_BAD_PHASE	(2)	/* illegal phase (4/5)   */
+#define	XE_EXTRA_DATA	(1)	/* unexpected data phase	 */
+#define	XE_BAD_PHASE	(2)	/* illegal phase (4/5)		 */
+#define	XE_PARITY_ERR	(4)	/* unrecovered SCSI parity error */
 
 /*==========================================================
 **
@@ -1334,9 +1193,6 @@
 */
 
 #define	QUIRK_AUTOSAVE	(0x01)
-#define	QUIRK_NOMSG	(0x02)
-#define QUIRK_NOSYNC	(0x10)
-#define QUIRK_NOWIDE16	(0x20)
 
 /*==========================================================
 **
@@ -1400,6 +1256,8 @@
 #define UC_SETFLAG	15
 #define UC_CLEARPROF	16
 #define UC_SETVERBOSE	17
+#define UC_RESETDEV	18
+#define UC_CLEARDEV	19
 
 #define	UF_TRACE	(0x01)
 #define	UF_NODISC	(0x02)
@@ -1443,8 +1301,11 @@
 	*/
 	u_int32		*luntbl;	/* lcbs bus address table	*/
 	u_int32		b_luntbl;	/* bus address of this table	*/
-	lcb_p		lp[MAX_LUN];	/* The lcb's of this tcb	*/
-
+	u_int32		b_lun0;		/* bus address of lun0		*/
+	lcb_p		l0p;		/* lcb of LUN #0 (normal case)	*/
+#if MAX_LUN > 1
+	lcb_p		*lmp;		/* Other lcb's [1..MAX_LUN]	*/
+#endif
 	/*----------------------------------------------------------------
 	**	Target capabilities.
 	**----------------------------------------------------------------
@@ -1453,6 +1314,12 @@
 	u_char		inq_byte7;	/* Contains these capabilities	*/
 
 	/*----------------------------------------------------------------
+	**	Some flags.
+	**----------------------------------------------------------------
+	*/
+	u_char		to_reset;	/* This target is to be reset	*/
+
+	/*----------------------------------------------------------------
 	**	Pointer to the ccb used for negotiation.
 	**	Prevent from starting a negotiation for all queued commands 
 	**	when tagged command queuing is enabled.
@@ -1488,8 +1355,8 @@
 	*/
 	u_char	usrsync;
 	u_char	usrwide;
-	u_char	usrtags;
 	u_char	usrflag;
+	u_short	usrtags;
 };
 
 /*========================================================================
@@ -1526,11 +1393,11 @@
 	*/
 	XPT_QUEHEAD	busy_ccbq;	/* Queue of busy CCBs		*/
 	XPT_QUEHEAD	wait_ccbq;	/* Queue of waiting for IO CCBs	*/
-	u_char		busyccbs;	/* CCBs busy for this lun	*/
-	u_char		queuedccbs;	/* CCBs queued to the controller*/
-	u_char		queuedepth;	/* Queue depth for this lun	*/
-	u_char		scdev_depth;	/* SCSI device queue depth	*/
-	u_char		maxnxs;		/* Max possible nexuses		*/
+	u_short		busyccbs;	/* CCBs busy for this lun	*/
+	u_short		queuedccbs;	/* CCBs queued to the controller*/
+	u_short		queuedepth;	/* Queue depth for this lun	*/
+	u_short		scdev_depth;	/* SCSI device queue depth	*/
+	u_short		maxnxs;		/* Max possible nexuses		*/
 
 	/*----------------------------------------------------------------
 	**	Control of tagged command queuing.
@@ -1538,22 +1405,23 @@
 	**	This avoids using a loop for tag allocation.
 	**----------------------------------------------------------------
 	*/
-	u_char		ia_tag;		/* Tag allocation index		*/
-	u_char		if_tag;		/* Tag release index		*/
-	u_char cb_tags[SCSI_NCR_MAX_TAGS]; /* Circular tags buffer	*/
+	u_short		ia_tag;		/* Tag allocation index		*/
+	u_short		if_tag;		/* Tag release index		*/
+	u_char		*cb_tags;	/* Circular tags buffer		*/
+	u_char		inq_byte7;	/* Store unit CmdQ capability	*/
 	u_char		usetags;	/* Command queuing is active	*/
-	u_char		maxtags;	/* Max NR of tags asked by user	*/
-	u_char		numtags;	/* Current number of tags	*/
-	u_char		inq_byte7;	/* Store unit CmdQ capabitility	*/
+	u_char		to_clear;	/* User wants to clear all tasks*/
+	u_short		maxtags;	/* Max NR of tags asked by user	*/
+	u_short		numtags;	/* Current number of tags	*/
 
 	/*----------------------------------------------------------------
 	**	QUEUE FULL and ORDERED tag control.
 	**----------------------------------------------------------------
 	*/
 	u_short		num_good;	/* Nr of GOOD since QUEUE FULL	*/
-	tagmap_t	tags_umap;	/* Used tags bitmap		*/
-	tagmap_t	tags_smap;	/* Tags in use at 'tag_stime'	*/
-	u_long		tags_stime;	/* Last time we set smap=umap	*/
+	u_short		tags_sum[2];	/* Tags sum counters		*/
+	u_char		tags_si;	/* Current index to tags sum	*/
+	u_long		tags_stime;	/* Last time we switch tags_sum	*/
 };
 
 /*========================================================================
@@ -1641,6 +1509,18 @@
 };
 
 /*
+**	LUN control block lookup.
+**	We use a direct pointer for LUN #0, and a table of pointers 
+**	which is only allocated for devices that support LUN(s) > 0.
+*/
+#if MAX_LUN <= 1
+#define ncr_lp(np, tp, lun) (!lun) ? (tp)->l0p : 0
+#else
+#define ncr_lp(np, tp, lun) \
+	(!lun) ? (tp)->l0p : (tp)->lmp ? (tp)->lmp[(lun)] : 0
+#endif
+
+/*
 **	The status bytes are used by the host and the script processor.
 **
 **	The last four bytes (status[4]) are copied to the scratchb register
@@ -1683,10 +1563,14 @@
 #define HF_IN_PM1	(1u<<1)
 #define HF_ACT_PM	(1u<<2)
 #define HF_DP_SAVED	(1u<<3)
-#define HF_PAR_ERR	(1u<<4)
+#define HF_AUTO_SENSE	(1u<<4)
 #define HF_DATA_ST	(1u<<5)
 #define HF_PM_TO_C	(1u<<6)
 
+#ifdef SCSI_NCR_IARB_SUPPORT
+#define HF_HINT_IARB	(1u<<7)
+#endif
+
 /*
 **	First four bytes (script)
 */
@@ -1731,6 +1615,7 @@
 
 	struct scr_tblsel  select;
 	struct scr_tblmove smsg  ;
+	struct scr_tblmove smsg_ext ;
 	struct scr_tblmove cmd   ;
 	struct scr_tblmove sense ;
 	struct scr_tblmove data [MAX_SCATTER];
@@ -1744,6 +1629,12 @@
 	struct pm_ctx pm0;
 	struct pm_ctx pm1;
 
+	/*
+	**	Extra bytes count transferred 
+	**	in case of data overrun.
+	*/
+	u_int32	extra_bytes;
+
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 	/*
 	**	Disconnection counter
@@ -1774,8 +1665,8 @@
 	**----------------------------------------------------------------
 	*/
 	Scsi_Cmnd	*cmd;		/* SCSI command 		*/
-	u_long		tlimit;		/* Deadline for this job	*/
 	int		data_len;	/* Total data length		*/
+	int		segments;	/* Number of SG segments	*/
 
 	/*----------------------------------------------------------------
 	**	Message areas.
@@ -1791,21 +1682,34 @@
 	u_char		scsi_smsg2[8];
 
 	/*----------------------------------------------------------------
+	**	Saved info for auto-sense
+	**----------------------------------------------------------------
+	*/
+	u_char		sv_scsi_status;
+	u_char		sv_xerr_status;
+
+	/*----------------------------------------------------------------
 	**	Other fields.
 	**----------------------------------------------------------------
 	*/
 	u_long		p_ccb;		/* BUS address of this CCB	*/
 	u_char		sensecmd[6];	/* Sense command		*/
-	u_char		tag;		/* Tag for this transfer	*/
-					/*  255 means no tag		*/
+	u_char		to_abort;	/* This CCB is to be aborted	*/
+	u_short		tag;		/* Tag for this transfer	*/
+					/*  NO_TAG means no tag		*/
+	u_char		tags_si;	/* Lun tags sum index (0,1)	*/
+
 	u_char		target;
 	u_char		lun;
-	u_char		queued;
-	u_char		auto_sense;
+	u_short		queued;
 	ccb_p		link_ccb;	/* Host adapter CCB chain	*/
 	ccb_p		link_ccbh;	/* Host adapter CCB hash chain	*/
 	XPT_QUEHEAD	link_ccbq;	/* Link to unit CCB queue	*/
 	u_int32		startp;		/* Initial data pointer		*/
+	u_int32		lastp0;		/* Initial 'lastp'		*/
+	int		ext_sg;		/* Extreme data pointer, used	*/
+	int		ext_ofs;	/*  to calculate the residual.	*/
+	int		resid;
 };
 
 #define CCB_PHYS(cp,lbl)	(cp->p_ccb + offsetof(struct ccb, lbl))
@@ -1899,11 +1803,15 @@
 	**	Virtual and physical bus addresses of the chip.
 	**----------------------------------------------------------------
 	*/
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 	u_long		base_va;	/* MMIO base virtual address	*/
+	u_long		base2_va;	/* On-chip RAM virtual address	*/
+#endif
 	u_long		base_ba;	/* MMIO base bus address	*/
 	u_long		base_io;	/* IO space base address	*/
 	u_long		base_ws;	/* (MM)IO window size		*/
-	u_long		base2_ba;	/* On-chip RAM bus address.	*/
+	u_long		base2_ba;	/* On-chip RAM bus address	*/
+	u_long		base2_ws;	/* On-chip RAM window size	*/
 	u_int		irq;		/* IRQ number			*/
 	volatile			/* Pointer to volatile for 	*/
 	struct ncr_reg	*reg;		/*  memory mapped IO.		*/
@@ -1912,7 +1820,7 @@
 	**	SCRIPTS virtual and physical bus addresses.
 	**	'script'  is loaded in the on-chip RAM if present.
 	**	'scripth' stays in main memory for all chips except the 
-	**	53C896 that provides 8K on-chip RAM.
+	**	53C895A and 53C896 that provide 8K on-chip RAM.
 	**----------------------------------------------------------------
 	*/
 	struct script	*script0;	/* Copies of script and scripth	*/
@@ -2004,6 +1912,24 @@
 	XPT_QUEHEAD	free_ccbq;	/* Queue of available CCBs	*/
 
 	/*----------------------------------------------------------------
+	**	IMMEDIATE ARBITRATION (IARB) control.
+	**	We keep track in 'last_cp' of the last CCB that has been 
+	**	queued to the SCRIPTS processor and clear 'last_cp' when 
+	**	this CCB completes. If last_cp is not zero at the moment 
+	**	we queue a new CCB, we set a flag in 'last_cp' that is 
+	**	used by the SCRIPTS as a hint for setting IARB.
+	**	We donnot set more than 'iarb_max' consecutive hints for 
+	**	IARB in order to leave devices a chance to reselect.
+	**	By the way, any non zero value of 'iarb_max' is unfair. :)
+	**----------------------------------------------------------------
+	*/
+#ifdef SCSI_NCR_IARB_SUPPORT
+	struct ccb	*last_cp;	/* Last queud CCB used for IARB	*/
+	u_short		iarb_max;	/* Max. # consecutive IARB hints*/
+	u_short		iarb_count;	/* Actual # of these hints	*/
+#endif
+
+	/*----------------------------------------------------------------
 	**	We need the LCB in order to handle disconnections and 
 	**	to count active CCBs for task management. So, we use 
 	**	a unique CCB for LUNs we donnot have the LCB yet.
@@ -2019,6 +1945,17 @@
 	int (*scatter) (ccb_p, Scsi_Cmnd *);
 
 	/*----------------------------------------------------------------
+	**	Command abort handling.
+	**	We need to synchronize tightly with the SCRIPTS 
+	**	processor in order to handle things correctly.
+	**----------------------------------------------------------------
+	*/
+	u_char		abrt_msg[4];	/* Message to send buffer	*/
+	struct scr_tblmove abrt_tbl;	/* Table for the MOV of it 	*/
+	struct scr_tblsel  abrt_sel;	/* Sync params for selection	*/
+	u_char		istat_sem;	/* Tells the chip to stop (SEM)	*/
+
+	/*----------------------------------------------------------------
 	**	Fields that should be removed or changed.
 	**----------------------------------------------------------------
 	*/
@@ -2053,34 +1990,53 @@
 
 /*
 **	Script fragments which are loaded into the on-chip RAM 
-**	of 825A, 875, 876, 895 and 896 chips.
+**	of 825A, 875, 876, 895, 895A and 896 chips.
 */
 struct script {
-	ncrcmd	start		[ 10];
+	ncrcmd	start		[ 18];
 	ncrcmd	getjob_begin	[  4];
 	ncrcmd	getjob_end	[  4];
-	ncrcmd	select		[  4];
+	ncrcmd	select		[  8];
 	ncrcmd	wf_sel_done	[  2];
 	ncrcmd	send_ident	[  2];
-	ncrcmd	select2		[  6];
+#ifdef SCSI_NCR_IARB_SUPPORT
+	ncrcmd	select2		[  8];
+#else
+	ncrcmd	select2		[  2];
+#endif
 	ncrcmd  command		[  2];
-	ncrcmd  dispatch	[ 26];
+	ncrcmd  dispatch	[ 28];
 	ncrcmd  sel_no_cmd	[ 10];
 	ncrcmd  init		[  6];
 	ncrcmd  clrack		[  4];
-	ncrcmd  databreak	[  2];
+	ncrcmd  disp_msg_in	[  2];
+	ncrcmd  disp_status	[  4];
+	ncrcmd  datai_done	[ 16];
+	ncrcmd  datao_done	[ 10];
+	ncrcmd  ign_i_w_r_msg	[  4];
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 	ncrcmd  dataphase	[  4];
 #else
 	ncrcmd  dataphase	[  2];
 #endif
-	ncrcmd  status		[  8];
 	ncrcmd  msg_in		[  2];
-	ncrcmd  msg_in2		[ 16];
-	ncrcmd  msg_bad		[  6];
+	ncrcmd  msg_in2		[ 10];
+#ifdef SCSI_NCR_IARB_SUPPORT
+	ncrcmd  status		[ 14];
+#else
+	ncrcmd  status		[ 10];
+#endif
 	ncrcmd  complete	[  8];
-	ncrcmd  complete2	[  6];
+#ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+	ncrcmd  complete2	[ 12];
+#else
+	ncrcmd  complete2	[ 10];
+#endif
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+	ncrcmd	done		[ 18];
+#else
 	ncrcmd	done		[ 14];
+#endif
 	ncrcmd	done_end	[  2];
 	ncrcmd  save_dp		[  8];
 	ncrcmd  restore_dp	[  4];
@@ -2089,57 +2045,64 @@
 #else
 	ncrcmd  disconnect	[ 20];
 #endif
+#ifdef SCSI_NCR_IARB_SUPPORT
+	ncrcmd  idle		[  4];
+#else
 	ncrcmd  idle		[  2];
+#endif
+#ifdef SCSI_NCR_IARB_SUPPORT
+	ncrcmd  ungetjob	[  6];
+#else
 	ncrcmd  ungetjob	[  4];
+#endif
 	ncrcmd	reselect	[  4];
-	ncrcmd	reselected	[ 44];
+	ncrcmd	reselected	[ 48];
+#if   MAX_TASKS*4 > 512
+	ncrcmd	resel_tag	[ 16];
+#elif MAX_TASKS*4 > 256
+	ncrcmd	resel_tag	[ 10];
+#else
 	ncrcmd	resel_tag	[  6];
+#endif
 	ncrcmd	resel_go	[  6];
 	ncrcmd	resel_notag	[  4];
 	ncrcmd	resel_dsa	[  8];
-	ncrcmd  data_in		[MAX_SCATTERL * SCR_SG_SIZE];
+	ncrcmd  data_in		[MAX_SCATTER * SCR_SG_SIZE];
 	ncrcmd  data_in2	[  4];
-	ncrcmd  data_out	[MAX_SCATTERL * SCR_SG_SIZE];
+	ncrcmd  data_out	[MAX_SCATTER * SCR_SG_SIZE];
 	ncrcmd  data_out2	[  4];
 	ncrcmd  pm0_data	[ 16];
 	ncrcmd  pm1_data	[ 16];
-
-	/* Data area */
-	ncrcmd	saved_dsa	[  1];
-	ncrcmd	done_pos	[  1];
-	ncrcmd	startpos	[  1];
-	ncrcmd	targtbl		[  1];
 };
 
 /*
 **	Script fragments which stay in main memory for all chips 
-**	except for the 896 that support 8K on-chip RAM.
+**	except for the 895A and 896 that support 8K on-chip RAM.
 */
 struct scripth {
 	ncrcmd	start64		[  2];
-	ncrcmd	select_no_atn	[  4];
+	ncrcmd	sel_for_abort	[ 18];
+	ncrcmd	sel_for_abort_1	[  2];
+	ncrcmd	select_no_atn	[  8];
 	ncrcmd	wf_sel_done_no_atn [ 4];
-	ncrcmd	cancel		[  4];
-	ncrcmd	msg_reject	[  8];
-	ncrcmd	msg_ign_residue	[ 24];
-	ncrcmd  msg_extended	[ 10];
-	ncrcmd  msg_ext_2	[ 10];
-	ncrcmd	msg_wdtr	[ 14];
+
+	ncrcmd	msg_in_etc	[ 14];
+	ncrcmd	msg_received	[  4];
+	ncrcmd	msg_weird_seen	[  4];
+	ncrcmd	msg_extended	[ 20];
+	ncrcmd  msg_bad		[  6];
+	ncrcmd	msg_weird	[  4];
+	ncrcmd	msg_weird1	[  8];
+
+	ncrcmd	wdtr_resp	[  6];
 	ncrcmd	send_wdtr	[  4];
-	ncrcmd  msg_ext_3	[ 10];
-	ncrcmd	msg_sdtr	[ 14];
+	ncrcmd	sdtr_resp	[  6];
 	ncrcmd	send_sdtr	[  4];
 	ncrcmd	nego_bad_phase	[  4];
 	ncrcmd	msg_out_abort	[ 12];
 	ncrcmd	msg_out		[  6];
 	ncrcmd	msg_out_done	[  4];
-	ncrcmd	no_data		[ 16];
-#if	MAX_SCATTERH != 0
-	ncrcmd  hdata_in	[MAX_SCATTERH * SCR_SG_SIZE];
-	ncrcmd  hdata_in2	[  2];
-	ncrcmd  hdata_out	[MAX_SCATTERH * SCR_SG_SIZE];
-	ncrcmd  hdata_out2	[  2];
-#endif
+	ncrcmd	no_data		[ 28];
 	ncrcmd	abort_resel	[ 16];
 	ncrcmd	resend_ident	[  4];
 	ncrcmd	ident_break	[  4];
@@ -2156,22 +2119,39 @@
 	ncrcmd	pm_handle	[ 20];
 	ncrcmd	pm_handle1	[  4];
 	ncrcmd	pm_save		[  4];
-	ncrcmd	pm0_save	[ 10];
-	ncrcmd	pm1_save	[ 10];
+	ncrcmd	pm0_save	[ 14];
+	ncrcmd	pm1_save	[ 14];
+
+	/* SWIDE handling */
+	ncrcmd	swide_ma_32	[  4];
+	ncrcmd	swide_ma_64	[  6];
+	ncrcmd	swide_scr_64	[ 26];
+	ncrcmd	swide_scr_64_1	[ 12];
+	ncrcmd	swide_com_64	[  6];
+	ncrcmd	swide_common	[ 10];
+	ncrcmd	swide_fin_32	[ 24];
 
 	/* Data area */
+	ncrcmd	zero		[  1];
+	ncrcmd	scratch		[  1];
+	ncrcmd	scratch1	[  1];
 	ncrcmd	pm0_data_addr	[  1];
 	ncrcmd	pm1_data_addr	[  1];
+	ncrcmd	saved_dsa	[  1];
+	ncrcmd	saved_drs	[  1];
+	ncrcmd	done_pos	[  1];
+	ncrcmd	startpos	[  1];
+	ncrcmd	targtbl		[  1];
 	/* End of data area */
 
+#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 	ncrcmd	start_ram	[  1];
 	ncrcmd	script0_ba	[  4];
-
 	ncrcmd	start_ram64	[  3];
 	ncrcmd	script0_ba64	[  3];
 	ncrcmd	scripth0_ba64	[  6];
 	ncrcmd	ram_seg64	[  1];
-
+#endif
 	ncrcmd	snooptest	[  6];
 	ncrcmd	snoopend	[  2];
 };
@@ -2195,6 +2175,7 @@
 static	lcb_p	ncr_setup_lcb	(ncb_p np, u_char tn, u_char ln,
 				 u_char *inq_data);
 static	void	ncr_getclock	(ncb_p np, int mult);
+static	u_int	ncr_getpciclock (ncb_p np);
 static	void	ncr_selectclock	(ncb_p np, u_char scntl3);
 static	ccb_p	ncr_get_ccb	(ncb_p np, u_char tn, u_char ln);
 static	void	ncr_init	(ncb_p np, int reset, char * msg, u_long code);
@@ -2204,8 +2185,8 @@
 static	void	ncr_int_sir	(ncb_p np);
 static  void    ncr_int_sto     (ncb_p np);
 static  void    ncr_int_udc     (ncb_p np);
-static	u_long	ncr_lookup	(char* id);
-static	void	ncr_negotiate	(struct ncb* np, struct tcb* tp);
+static	void	ncr_negotiate	(ncb_p np, tcb_p tp);
+static	int	ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr);
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 static	void	ncb_profile	(ncb_p np, ccb_p cp);
 #endif
@@ -2219,6 +2200,7 @@
 static	void	ncr_setup_tags	(ncb_p np, u_char tn, u_char ln);
 static	void	ncr_setwide	(ncb_p np, ccb_p cp, u_char wide, u_char ack);
 static	int	ncr_show_msg	(u_char * msg);
+static	void	ncr_print_msg	(ccb_p cp, char *label, u_char * msg);
 static	int	ncr_snooptest	(ncb_p np);
 static	void	ncr_timeout	(ncb_p np);
 static  void    ncr_wakeup      (ncb_p np, u_long code);
@@ -2228,6 +2210,7 @@
 static	void	ncr_soft_reset	(ncb_p np);
 static	void	ncr_start_reset	(ncb_p np);
 static	int	ncr_reset_scsi_bus (ncb_p np, int enab_int, int settle_delay);
+static	int	ncr_compute_residual (ncb_p np, ccb_p cp);
 
 #ifdef SCSI_NCR_USER_COMMAND_SUPPORT
 static	void	ncr_usercmd	(ncb_p np);
@@ -2328,6 +2311,25 @@
 	*/
 	SCR_FROM_REG (ctest2),
 		0,
+
+	/*
+	**	Stop here if the C code wants to perform 
+	**	some error recovery procedure manually.
+	**	(Indicate this by setting SEM in ISTAT)
+	*/
+	SCR_FROM_REG (istat),
+		0,
+	SCR_JUMPR ^ IFFALSE (MASK (SEM, SEM)),
+		16,
+	/*
+	**	Report to the C code the next position in 
+	**	the start queue the SCRIPTS will schedule.
+	*/
+	SCR_LOAD_ABS (scratcha, 4),
+		PADDRH (startpos),
+	SCR_INT,
+		SIR_SCRIPT_STOPPED,
+
 	/*
 	**	Start the next job.
 	**
@@ -2343,14 +2345,14 @@
 	**	and the the next queue position points to the next JOB.
 	*/
 	SCR_LOAD_ABS (scratcha, 4),
-		PADDR (startpos),
+		PADDRH (startpos),
 	SCR_LOAD_ABS (dsa, 4),
-		PADDR (startpos),
+		PADDRH (startpos),
 	SCR_LOAD_REL (temp, 4),
 		4,
 }/*-------------------------< GETJOB_BEGIN >------------------*/,{
 	SCR_STORE_ABS (temp, 4),
-		PADDR (startpos),
+		PADDRH (startpos),
 	SCR_LOAD_REL (dsa, 4),
 		0,
 }/*-------------------------< GETJOB_END >--------------------*/,{
@@ -2407,6 +2409,19 @@
 	**	So we have to wait immediately for the next phase 
 	**	or the selection to complete or time-out.
 	*/
+
+	/*
+	**      load the savep (saved pointer) into
+	**      the actual data pointer.
+	*/
+	SCR_LOAD_REL (temp, 4),
+		offsetof (struct ccb, phys.header.savep),
+	/*
+	**      Initialize the status registers
+	*/
+	SCR_LOAD_REL (scr0, 4),
+		offsetof (struct ccb, phys.header.status),
+
 }/*-------------------------< WF_SEL_DONE >----------------------*/,{
 	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
 		SIR_SEL_ATN_NO_MSG_OUT,
@@ -2419,17 +2434,18 @@
 	SCR_MOVE_TBL ^ SCR_MSG_OUT,
 		offsetof (struct dsb, smsg),
 }/*-------------------------< SELECT2 >----------------------*/,{
+#ifdef SCSI_NCR_IARB_SUPPORT
 	/*
-	**      load the savep (saved pointer) into
-	**      the actual data pointer.
-	*/
-	SCR_LOAD_REL (temp, 4),
-		offsetof (struct ccb, phys.header.savep),
-	/*
-	**      Initialize the status registers
+	**	Set IMMEDIATE ARBITRATION if we have been given 
+	**	a hint to do so. (Some job to do after this one).
 	*/
-	SCR_LOAD_REL (scr0, 4),
-		offsetof (struct ccb, phys.header.status),
+	SCR_FROM_REG (HF_REG),
+		0,
+	SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)),
+		8,
+	SCR_REG_REG (scntl1, SCR_OR, IARB),
+		0,
+#endif
 	/*
 	**	Anticipate the COMMAND phase.
 	**	This is the PHASE we expect at this point.
@@ -2465,7 +2481,9 @@
 	/*
 	**      Discard one illegal phase byte, if required.
 	*/
-	SCR_LOAD_REG (scratcha, XE_BAD_PHASE),
+	SCR_LOAD_REL (scratcha, 1),
+		offsetof (struct ccb, xerr_status),
+	SCR_REG_REG (scratcha, SCR_OR, XE_BAD_PHASE),
 		0,
 	SCR_STORE_REL (scratcha, 1),
 		offsetof (struct ccb, xerr_status),
@@ -2517,7 +2535,7 @@
 	SCR_FROM_REG (sstat0),
 		0,
 	SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)),
-		-8,
+		-16,
 	SCR_JUMP,
 		PADDR (start),
 }/*-------------------------< CLRACK >----------------------*/,{
@@ -2529,37 +2547,115 @@
 	SCR_JUMP,
 		PADDR (dispatch),
 
-}/*-------------------------< DATABREAK >-------------------*/,{
+}/*-------------------------< DISP_MSG_IN >----------------------*/,{
 	/*
-	**	Jump to dispatcher.
+	**	Anticipate MSG_IN phase then STATUS phase.
+	**
+	**	May spare 2 SCRIPTS instructions when we have 
+	**	completed the OUTPUT of the data and the device 
+	**	goes directly to STATUS phase.
 	*/
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR (msg_in),
+
+}/*-------------------------< DISP_STATUS >----------------------*/,{
+	/*
+	**	Anticipate STATUS phase.
+	**
+	**	Does spare 3 SCRIPTS instructions when we have 
+	**	completed the INPUT of the data.
+	*/
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)),
+		PADDR (status),
 	SCR_JUMP,
 		PADDR (dispatch),
 
-}/*-------------------------< DATAPHASE >------------------*/,{
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	SCR_REG_REG (HF_REG, SCR_OR, HF_DATA_ST),
+}/*-------------------------< DATAI_DONE >-------------------*/,{
+	/*
+	**	If the SWIDE is not full, jump to dispatcher.
+	**	We anticipate a STATUS phase.
+	**	If we get later an IGNORE WIDE RESIDUE, we 
+	**	will alias it as a MODIFY DP (-1).
+	*/
+	SCR_FROM_REG (scntl2),
 		0,
-#endif
-	SCR_RETURN,
- 		0,
-
-}/*-------------------------< STATUS >--------------------*/,{
+	SCR_JUMP ^ IFFALSE (MASK (WSR, WSR)),
+		PADDR (disp_status),
 	/*
-	**	get the status
+	**	The SWIDE is full.
+	**	Clear this condition.
 	*/
-	SCR_MOVE_ABS (1) ^ SCR_STATUS,
-		NADDR (scratch),
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
 	/*
-	**	save status to scsi_status.
-	**	mark as complete.
+	**	Since the device is required to send any 
+	**	IGNORE WIDE RESIDUE message prior to any
+	**	other information, we just snoop the SCSI 
+	**	BUS to check for such a message.
 	*/
-	SCR_TO_REG (SS_REG),
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (disp_status),
+	SCR_FROM_REG (sbdl),
 		0,
-	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+	SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+		PADDR (disp_status),
+	/*
+	**	We have been ODD at the end of the transfer, 
+	**	but the device hasn't be so.
+	**	Signal a DATA OVERRUN condition to the C code.
+	*/
+	SCR_INT,
+		SIR_SWIDE_OVERRUN,
+	SCR_JUMP,
+		PADDR (dispatch),
+
+}/*-------------------------< DATAO_DONE >-------------------*/,{
+	/*
+	**	If the SODL is not full jump to dispatcher.
+	**	We anticipate a MSG IN phase or a STATUS phase.
+	*/
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)),
+		PADDR (disp_msg_in),
+	/*
+	**	The SODL is full, clear this condition.
+	*/
+	SCR_REG_REG (scntl2, SCR_OR, WSS),
 		0,
+	/*
+	**	And signal a DATA UNDERRUN condition 
+	**	to the C code.
+	*/
+	SCR_INT,
+		SIR_SODL_UNDERRUN,
 	SCR_JUMP,
 		PADDR (dispatch),
+
+}/*-------------------------< IGN_I_W_R_MSG >--------------*/,{
+	/*
+	**	We jump here from the phase mismatch interrupt, 
+	**	When we have a SWIDE and the device has presented 
+	**	a IGNORE WIDE RESIDUE message on the BUS.
+	**	We just have to throw away this message and then 
+	**	to jump to dispatcher.
+	*/
+	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+		NADDR (scratch),
+	/*
+	**	Clear ACK and jump to dispatcher.
+	*/
+	SCR_JUMP,
+		PADDR (clrack),
+
+}/*-------------------------< DATAPHASE >------------------*/,{
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+	SCR_REG_REG (HF_REG, SCR_OR, HF_DATA_ST),
+		0,
+#endif
+	SCR_RETURN,
+ 		0,
+
 }/*-------------------------< MSG_IN >--------------------*/,{
 	/*
 	**	Get the first byte of the message.
@@ -2571,7 +2667,8 @@
 		NADDR (msgin[0]),
 }/*-------------------------< MSG_IN2 >--------------------*/,{
 	/*
-	**	Handle this message.
+	**	Check first against 1 byte messages 
+	**	that we handle from SCRIPTS.
 	*/
 	SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
 		PADDR (complete),
@@ -2581,31 +2678,47 @@
 		PADDR (save_dp),
 	SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
 		PADDR (restore_dp),
-	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
-		PADDRH (msg_extended),
-	SCR_JUMP ^ IFTRUE (DATA (M_NOOP)),
-		PADDR (clrack),
-	SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
-		PADDRH (msg_reject),
-	SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)),
-		PADDRH (msg_ign_residue),
 	/*
-	**	Rest of the messages left as
-	**	an exercise ...
-	**
-	**	Unimplemented messages:
-	**	fall through to MSG_BAD.
+	**	We handle all other messages from the 
+	**	C code, so no need to waste on-chip RAM 
+	**	for those ones.
 	*/
-}/*-------------------------< MSG_BAD >------------------*/,{
+	SCR_JUMP,
+		PADDRH (msg_in_etc),
+
+}/*-------------------------< STATUS >--------------------*/,{
 	/*
-	**	unimplemented message - reject it.
+	**	get the status
 	*/
-	SCR_INT,
-		SIR_REJECT_TO_SEND,
-	SCR_SET (SCR_ATN),
+	SCR_MOVE_ABS (1) ^ SCR_STATUS,
+		NADDR (scratch),
+#ifdef SCSI_NCR_IARB_SUPPORT
+	/*
+	**	If STATUS is not GOOD, clear IMMEDIATE ARBITRATION, 
+	**	since we may have to tamper the start queue from 
+	**	the C code.
+	*/
+	SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)),
+		8,
+	SCR_REG_REG (scntl1, SCR_AND, ~IARB),
 		0,
+#endif
+	/*
+	**	save status to scsi_status.
+	**	mark as complete.
+	*/
+	SCR_TO_REG (SS_REG),
+		0,
+	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+		0,
+	/*
+	**	Anticipate the MESSAGE PHASE for 
+	**	the TASK COMPLETE message.
+	*/
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR (msg_in),
 	SCR_JUMP,
-		PADDR (clrack),
+		PADDR (dispatch),
 
 }/*-------------------------< COMPLETE >-----------------*/,{
 	/*
@@ -2642,6 +2755,18 @@
 	SCR_STORE_REL (scr0, 4),
 		offsetof (struct ccb, phys.header.status),
 
+#ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+	/*
+	**	Some bridges may reorder DMA writes to memory.
+	**	We donnot want the CPU to deal with completions  
+	**	without all the posted write having been flushed 
+	**	to memory. This DUMMY READ should flush posted 
+	**	buffers prior to the CPU having to deal with 
+	**	completions.
+	*/
+	SCR_LOAD_REL (scr0, 4),	/* DUMMY READ */
+		offsetof (struct ccb, phys.header.status),
+#endif
 	/*
 	**	If command resulted in not GOOD status,
 	**	call the C code if needed.
@@ -2651,7 +2776,35 @@
 	SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
 		PADDRH (bad_status),
 
+	/*
+	**	If we performed an auto-sense, call 
+	**	the C code to synchronyze task aborts 
+	**	with UNIT ATTENTION conditions.
+	*/
+	SCR_FROM_REG (HF_REG),
+		0,
+	SCR_INT ^ IFTRUE (MASK (HF_AUTO_SENSE, HF_AUTO_SENSE)),
+		SIR_AUTO_SENSE_DONE,
+
 }/*------------------------< DONE >-----------------*/,{
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+	/*
+	**	It seems that some bridges flush everything 
+	**	when the INTR line is raised. For these ones, 
+	**	we can just ensure that the INTR line will be 
+	**	raised before each completion. So, if it happens 
+	**	that we have been faster that the CPU, we just 
+	**	have to synchronize with it. A dummy programmed 
+	**	interrupt will do the trick.
+	**	Note that we overlap at most 1 IO with the CPU 
+	**	in this situation and that the IRQ line must not 
+	**	be shared.
+	*/
+	SCR_FROM_REG (istat),
+		0,
+	SCR_INT ^ IFTRUE (MASK (INTF, INTF)),
+		SIR_DUMMY_INTERRUPT,
+#endif
 	/*
 	**	Copy the DSA to the DONE QUEUE and 
 	**	signal completion to the host.
@@ -2660,11 +2813,11 @@
 	**	the completed CCB will be lost.
 	*/
 	SCR_STORE_ABS (dsa, 4),
-		PADDR (saved_dsa),
+		PADDRH (saved_dsa),
 	SCR_LOAD_ABS (dsa, 4),
-		PADDR (done_pos),
+		PADDRH (done_pos),
 	SCR_LOAD_ABS (scratcha, 4),
-		PADDR(saved_dsa),
+		PADDRH (saved_dsa),
 	SCR_STORE_REL (scratcha, 4),
 		0,
 	/*
@@ -2679,7 +2832,7 @@
 	SCR_INT_FLY,
 		0,
 	SCR_STORE_ABS (temp, 4),
-		PADDR (done_pos),
+		PADDRH (done_pos),
 }/*------------------------< DONE_END >-----------------*/,{
 	SCR_JUMP,
 		PADDR (start),
@@ -2791,9 +2944,22 @@
 	*/
 	SCR_NO_OP,
 		0,
+#ifdef SCSI_NCR_IARB_SUPPORT
+	SCR_JUMPR,
+		8,
+#endif
 }/*-------------------------< UNGETJOB >-----------------*/,{
+#ifdef SCSI_NCR_IARB_SUPPORT
 	/*
-	**	We are not able to restart the SCRIPTS if we are 
+	**	Set IMMEDIATE ARBITRATION, for the next time.
+	**	This will give us better chance to win arbitration 
+	**	for the job we just wanted to do.
+	*/
+	SCR_REG_REG (scntl1, SCR_OR, IARB),
+		0,
+#endif
+	/*
+	**	We are not able to restart the SCRIPTS if we are 
 	**	interrupted and these instruction haven't been 
 	**	all executed. BTW, this is very unlikely to 
 	**	happen, but we check that from the C code.
@@ -2801,7 +2967,7 @@
 	SCR_LOAD_REG (dsa, 0xff),
 		0,
 	SCR_STORE_ABS (scratcha, 4),
-		PADDR (startpos),
+		PADDRH (startpos),
 }/*-------------------------< RESELECT >--------------------*/,{
 	/*
 	**	make the host status invalid.
@@ -2834,7 +3000,7 @@
 	**	load the target control block address
 	*/
 	SCR_LOAD_ABS (dsa, 4),
-		PADDR (targtbl),
+		PADDRH (targtbl),
 	SCR_SFBR_REG (dsa, SCR_SHL, 0),
 		0,
 	SCR_REG_REG (dsa, SCR_SHL, 0),
@@ -2870,12 +3036,13 @@
 	/*
 	**	It is an IDENTIFY message,
 	**	Load the LUN control block address.
-	**	Avoid nasty address calculation if LUN #0.
+	**	If LUN 0, avoid a PCI BUS ownership by loading 
+	**	directly 'b_lun0' from the TCB.
 	*/
+	SCR_JUMPR ^ IFTRUE (MASK (0x0, 0x3f)),
+		48,
 	SCR_LOAD_REL (dsa, 4),
 		offsetof(struct tcb, b_luntbl),
-	SCR_JUMPR ^ IFTRUE (MASK (0x0, 0x3f)),
-		24,
 	SCR_SFBR_REG (dsa, SCR_SHL, 0),
 		0,
 	SCR_REG_REG (dsa, SCR_SHL, 0),
@@ -2884,6 +3051,14 @@
 		0,
 	SCR_LOAD_REL (dsa, 4),
 		0,
+	SCR_JUMPR,
+		8,
+	/*
+	**	LUN 0 special case (but usual one :))
+	*/
+	SCR_LOAD_REL (dsa, 4),
+		offsetof(struct tcb, b_lun0),
+
 	/*
 	**	Load the reselect task action for this LUN.
 	**	Load the tasks DSA array for this LUN.
@@ -2914,6 +3089,23 @@
 	*/
 	SCR_REG_SFBR (sidl, SCR_SHL, 0),
 		0,
+#if MAX_TASKS*4 > 512
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 2),
+		0,
+	SCR_REG_REG (sfbr, SCR_SHL, 0),
+		0,
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 1),
+		0,
+#elif MAX_TASKS*4 > 256
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 1),
+		0,
+#endif
 	/*
 	**	Retrieve the DSA of this task.
 	**	JUMP indirectly to the restart point of the CCB.
@@ -2966,13 +3158,11 @@
 }/*-------------------------< DATA_IN >--------------------*/,{
 /*
 **	Because the size depends on the
-**	#define MAX_SCATTERL parameter,
+**	#define MAX_SCATTER parameter,
 **	it is filled in at runtime.
 **
-**  ##===========< i=0; i<MAX_SCATTERL >=========
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
-**  ||		PADDR (databreak),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_IN,
+**  ##===========< i=0; i<MAX_SCATTER >=========
+**  ||	SCR_CHMOV_TBL ^ SCR_DATA_IN,
 **  ||		offsetof (struct dsb, data[ i]),
 **  ##==========================================
 **
@@ -2981,19 +3171,17 @@
 0
 }/*-------------------------< DATA_IN2 >-------------------*/,{
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (datai_done),
 	SCR_JUMP,
 		PADDRH (no_data),
 }/*-------------------------< DATA_OUT >--------------------*/,{
 /*
 **	Because the size depends on the
-**	#define MAX_SCATTERL parameter,
+**	#define MAX_SCATTER parameter,
 **	it is filled in at runtime.
 **
-**  ##===========< i=0; i<MAX_SCATTERL >=========
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-**  ||		PADDR (databreak),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+**  ##===========< i=0; i<MAX_SCATTER >=========
+**  ||	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
 **  ||		offsetof (struct dsb, data[ i]),
 **  ##==========================================
 **
@@ -3002,7 +3190,7 @@
 0
 }/*-------------------------< DATA_OUT2 >-------------------*/,{
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (datao_done),
 	SCR_JUMP,
 		PADDRH (no_data),
 
@@ -3019,11 +3207,11 @@
 	*/
 	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
 		16,
-	SCR_MOVE_TBL ^ SCR_DATA_IN,
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
 		offsetof (struct ccb, phys.pm0.sg),
 	SCR_JUMPR,
 		8,
-	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
 		offsetof (struct ccb, phys.pm0.sg),
 	/*
 	**	Clear the flag that told we were in 
@@ -3053,11 +3241,11 @@
 	*/
 	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
 		16,
-	SCR_MOVE_TBL ^ SCR_DATA_IN,
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
 		offsetof (struct ccb, phys.pm1.sg),
 	SCR_JUMPR,
 		8,
-	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
 		offsetof (struct ccb, phys.pm1.sg),
 	/*
 	**	Clear the flag that told we were in 
@@ -3074,27 +3262,76 @@
 		offsetof (struct ccb, phys.pm1.ret),
 	SCR_RETURN,
 		0,
-
-}/*-------------------------< SAVED_DSA >-------------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< DONE_POS >--------------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< STARTPOS >--------------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< TARGTBL >---------------------*/,{
-	SCR_DATA_ZERO,
-}/*--------------------------------------------------------*/
+}/*---------------------------------------------------------*/
 };
 
 static	struct scripth scripth0 __initdata = {
 /*------------------------< START64 >-----------------------*/{
 	/*
-	**	SCRIPT entry point for the 896.
+	**	SCRIPT entry point for the 895A and the 896.
 	**	For now, there is no specific stuff for that 
 	**	chip at this point, but this may come.
 	*/
 	SCR_JUMP,
 		PADDR (init),
+
+}/*-----------------------< SEL_FOR_ABORT >------------------*/,{
+	/*
+	**	We are jumped here by the C code, if we have 
+	**	some target to reset or some disconnected 
+	**	job to abort. Since error recovery is a serious 
+	**	busyness, we will really reset the SCSI BUS, if 
+	**	case of a SCSI interrupt occuring in this path.
+	*/
+
+	/*
+	**	Set initiator mode.
+	*/
+	SCR_CLR (SCR_TRG),
+		0,
+	/*
+	**      And try to select this target.
+	*/
+	SCR_SEL_TBL_ATN ^ offsetof (struct ncb, abrt_sel),
+		PADDR (reselect),
+
+	/*
+	**	Wait for the selection to complete or 
+	**	the selection to time out.
+	*/
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		-8,
+	/*
+	**	Call the C code.
+	*/
+	SCR_INT,
+		SIR_TARGET_SELECTED,
+	/*
+	**	The C code should let us continue here. 
+	**	Send the 'kiss of death' message.
+	**	We expect an immediate disconnect once 
+	**	the target has eaten the message.
+	*/
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_MOVE_TBL ^ SCR_MSG_OUT,
+		offsetof (struct ncb, abrt_tbl),
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	SCR_WAIT_DISC,
+		0,
+	/*
+	**	Tell the C code that we are done.
+	*/
+	SCR_INT,
+		SIR_ABORT_SENT,
+}/*-----------------------< SEL_FOR_ABORT_1 >--------------*/,{
+	/*
+	**	Jump at scheduler.
+	*/
+	SCR_JUMP,
+		PADDR (start),
+
 }/*------------------------< SELECT_NO_ATN >-----------------*/,{
 	/*
 	**	Set Initiator mode.
@@ -3105,6 +3342,18 @@
 		0,
 	SCR_SEL_TBL ^ offsetof (struct dsb, select),
 		PADDR (ungetjob),
+	/*
+	**      load the savep (saved pointer) into
+	**      the actual data pointer.
+	*/
+	SCR_LOAD_REL (temp, 4),
+		offsetof (struct ccb, phys.header.savep),
+	/*
+	**      Initialize the status registers
+	*/
+	SCR_LOAD_REL (scr0, 4),
+		offsetof (struct ccb, phys.header.status),
+
 }/*------------------------< WF_SEL_DONE_NO_ATN >-----------------*/,{
 	/*
 	**	Wait immediately for the next phase or 
@@ -3115,129 +3364,111 @@
 	SCR_JUMP,
 		PADDR (select2),
 
-}/*-------------------------< CANCEL >------------------------*/,{
+}/*-------------------------< MSG_IN_ETC >--------------------*/,{
 	/*
-	**	Load the host status.
+	**	If it is an EXTENDED (variable size message)
+	**	Handle it.
 	*/
-	SCR_LOAD_REG (HS_REG, HS_ABORTED),
-		0,
-	SCR_JUMP,
-		PADDR (complete2),
-
-}/*-------------------------< MSG_REJECT >---------------*/,{
+	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
+		PADDRH (msg_extended),
 	/*
-	**	If a negotiation was in progress,
-	**	negotiation failed.
-	**	Otherwise just make host log this message
+	**	Let the C code handle any other 
+	**	1 byte message.
 	*/
-	SCR_FROM_REG (HS_REG),
+	SCR_JUMP ^ IFTRUE (MASK (0x00, 0xf0)),
+		PADDRH (msg_received),
+	SCR_JUMP ^ IFTRUE (MASK (0x10, 0xf0)),
+		PADDRH (msg_received),
+	/*
+	**	We donnot handle 2 bytes messages from SCRIPTS.
+	**	So, let the C code deal with these ones too.
+	*/
+	SCR_JUMP ^ IFFALSE (MASK (0x20, 0xf0)),
+		PADDRH (msg_weird_seen),
+	SCR_CLR (SCR_ACK),
 		0,
-	SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)),
-		SIR_REJECT_RECEIVED,
-	SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
-		SIR_NEGO_FAILED,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[1]),
 	SCR_JUMP,
-		PADDR (clrack),
+		PADDRH (msg_received),
+
+}/*-------------------------< MSG_RECEIVED >--------------------*/,{
+	SCR_LOAD_REL (scratcha, 4),	/* DUMMY READ */
+		0,
+	SCR_INT,
+		SIR_MSG_RECEIVED,
+
+}/*-------------------------< MSG_WEIRD_SEEN >------------------*/,{
+	SCR_LOAD_REL (scratcha1, 4),	/* DUMMY READ */
+		0,
+	SCR_INT,
+		SIR_MSG_WEIRD,
 
-}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{
+}/*-------------------------< MSG_EXTENDED >--------------------*/,{
 	/*
-	**	Terminate cycle
+	**	Clear ACK and get the next byte 
+	**	assumed to be the message length.
 	*/
 	SCR_CLR (SCR_ACK),
 		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get residue size.
-	*/
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
 		NADDR (msgin[1]),
 	/*
-	**	Size is 0 .. ignore message.
+	**	Try to catch some unlikely situations as 0 length 
+	**	or too large the length.
 	*/
 	SCR_JUMP ^ IFTRUE (DATA (0)),
-		PADDR (clrack),
-	/*
-	**	Size is not 1 .. have to interrupt.
-	*/
-	SCR_JUMPR ^ IFFALSE (DATA (1)),
-		40,
-	/*
-	**	Check for residue byte in swide register
-	*/
-	SCR_FROM_REG (scntl2),
+		PADDRH (msg_weird_seen),
+	SCR_TO_REG (scratcha),
 		0,
-	SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
-		16,
+	SCR_REG_REG (sfbr, SCR_ADD, (256-8)),
+		0,
+	SCR_JUMP ^ IFTRUE (CARRYSET),
+		PADDRH (msg_weird_seen),
 	/*
-	**	There IS data in the swide register.
-	**	Discard it.
+	**	We donnot handle extended messages from SCRIPTS.
+	**	Read the amount of data correponding to the 
+	**	message length and call the C code.
 	*/
-	SCR_REG_REG (scntl2, SCR_OR, WSR),
+	SCR_STORE_REL (scratcha, 1),
+		offsetof (struct dsb, smsg_ext.size),
+	SCR_CLR (SCR_ACK),
 		0,
+	SCR_MOVE_TBL ^ SCR_MSG_IN,
+		offsetof (struct dsb, smsg_ext),
 	SCR_JUMP,
-		PADDR (clrack),
+		PADDRH (msg_received),
+
+}/*-------------------------< MSG_BAD >------------------*/,{
 	/*
-	**	Load again the size to the sfbr register.
+	**	unimplemented message - reject it.
 	*/
-	SCR_FROM_REG (scratcha),
-		0,
 	SCR_INT,
-		SIR_IGN_RESIDUE,
+		SIR_REJECT_TO_SEND,
+	SCR_SET (SCR_ATN),
+		0,
 	SCR_JUMP,
 		PADDR (clrack),
 
-}/*-------------------------< MSG_EXTENDED >-------------*/,{
+}/*-------------------------< MSG_WEIRD >--------------------*/,{
 	/*
-	**	Terminate cycle
+	**	weird message received
+	**	ignore all MSG IN phases and reject it.
 	*/
-	SCR_CLR (SCR_ACK),
+	SCR_INT,
+		SIR_REJECT_TO_SEND,
+	SCR_SET (SCR_ATN),
 		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get length.
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[1]),
-	/*
-	*/
-	SCR_JUMP ^ IFTRUE (DATA (3)),
-		PADDRH (msg_ext_3),
-	SCR_JUMP ^ IFFALSE (DATA (2)),
-		PADDR (msg_bad),
-}/*-------------------------< MSG_EXT_2 >----------------*/,{
+}/*-------------------------< MSG_WEIRD1 >--------------------*/,{
 	SCR_CLR (SCR_ACK),
 		0,
 	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
 		PADDR (dispatch),
-	/*
-	**	get extended message code.
-	*/
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[2]),
-	SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)),
-		PADDRH (msg_wdtr),
-	/*
-	**	unknown extended message
-	*/
+		NADDR (scratch),
 	SCR_JUMP,
-		PADDR (msg_bad)
-}/*-------------------------< MSG_WDTR >-----------------*/,{
-	SCR_CLR (SCR_ACK),
-		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get data bus width
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[3]),
-	/*
-	**	let the host do the real work.
-	*/
-	SCR_INT,
-		SIR_NEGO_WIDE,
+		PADDRH (msg_weird1),
+}/*-------------------------< WDTR_RESP >----------------*/,{
 	/*
 	**	let the target fetch our answer.
 	*/
@@ -3257,39 +3488,7 @@
 	SCR_JUMP,
 		PADDRH (msg_out_done),
 
-}/*-------------------------< MSG_EXT_3 >----------------*/,{
-	SCR_CLR (SCR_ACK),
-		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get extended message code.
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[2]),
-	SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)),
-		PADDRH (msg_sdtr),
-	/*
-	**	unknown extended message
-	*/
-	SCR_JUMP,
-		PADDR (msg_bad)
-
-}/*-------------------------< MSG_SDTR >-----------------*/,{
-	SCR_CLR (SCR_ACK),
-		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get period and offset
-	*/
-	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
-		NADDR (msgin[3]),
-	/*
-	**	let the host do the real work.
-	*/
-	SCR_INT,
-		SIR_NEGO_SYNC,
+}/*-------------------------< SDTR_RESP >-------------*/,{
 	/*
 	**	let the target fetch our answer.
 	*/
@@ -3372,7 +3571,9 @@
 	**	or in the wrong direction.
 	**      Remember that in extended error.
 	*/
-	SCR_LOAD_REG (scratcha, XE_EXTRA_DATA),
+	SCR_LOAD_REL (scratcha, 1),
+		offsetof (struct ccb, xerr_status),
+	SCR_REG_REG (scratcha, SCR_OR, XE_EXTRA_DATA),
 		0,
 	SCR_STORE_REL (scratcha, 1),
 		offsetof (struct ccb, xerr_status),
@@ -3388,57 +3589,28 @@
 	SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
 		NADDR (scratch),
 	/*
+	**	Count this byte.
+	**	This will allow to return a positive 
+	**	residual to user.
+	*/
+	SCR_LOAD_REL (scratcha, 4),
+		offsetof (struct ccb, phys.extra_bytes),
+	SCR_REG_REG (scratcha,  SCR_ADD,  0x01),
+		0,
+	SCR_REG_REG (scratcha1, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (scratcha2, SCR_ADDC, 0),
+		0,
+	SCR_STORE_REL (scratcha, 4),
+		offsetof (struct ccb, phys.extra_bytes),
+	/*
 	**      .. and repeat as required.
 	*/
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (dispatch),
 	SCR_JUMP,
 		PADDRH (no_data),
 
-#if	MAX_SCATTERH != 0
-
-}/*-------------------------< HDATA_IN >-------------------*/,{
-/*
-**	Because the size depends on the
-**	#define MAX_SCATTERH parameter,
-**	it is filled in at runtime.
-**
-**  ##==< i=MAX_SCATTERL; i<MAX_SCATTERL+MAX_SCATTERH >==
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
-**  ||		PADDR (databreak),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_IN,
-**  ||		offsetof (struct dsb, data[ i]),
-**  ##===================================================
-**
-**---------------------------------------------------------
-*/
-0
-}/*-------------------------< HDATA_IN2 >------------------*/,{
-	SCR_JUMP,
-		PADDR (data_in),
-
-}/*-------------------------< HDATA_OUT >-------------------*/,{
-/*
-**	Because the size depends on the
-**	#define MAX_SCATTERH parameter,
-**	it is filled in at runtime.
-**
-**  ##==< i=MAX_SCATTERL; i<MAX_SCATTERL+MAX_SCATTERH >==
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-**  ||		PADDR (databreak),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
-**  ||		offsetof (struct dsb, data[ i]),
-**  ##===================================================
-**
-**---------------------------------------------------------
-*/
-0
-}/*-------------------------< HDATA_OUT2 >------------------*/,{
-	SCR_JUMP,
-		PADDR (data_out),
-
-#endif	/* MAX_SCATTERH */
-
 }/*-------------------------< ABORT_RESEL >----------------*/,{
 	SCR_SET (SCR_ATN),
 		0,
@@ -3482,10 +3654,10 @@
 	SCR_JUMP,
 		PADDR (select2),
 }/*-------------------------< SDATA_IN >-------------------*/,{
-	SCR_MOVE_TBL ^ SCR_DATA_IN,
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
 		offsetof (struct dsb, sense),
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (dispatch),
 	SCR_JUMP,
 		PADDRH (no_data),
 
@@ -3588,7 +3760,7 @@
 	**	call the C code.
 	*/
 	SCR_LOAD_ABS (scratcha, 4),
-		PADDR (startpos),
+		PADDRH (startpos),
 	SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)),
 		SIR_BAD_STATUS,
 	SCR_INT ^ IFTRUE (DATA (S_CHECK_COND)),
@@ -3690,6 +3862,17 @@
 	SCR_JUMP ^ IFTRUE (MASK (HF_ACT_PM, HF_ACT_PM)),
 		PADDRH (pm1_save),
 }/*-------------------------< PM0_SAVE >-------------------*/,{
+	SCR_STORE_REL (ia, 4),
+		offsetof(struct ccb, phys.pm0.ret),
+	/*
+	**	If WSR bit is set, either UA and RBC may 
+	**	have to be changed whatever the device wants 
+	**	to ignore this residue ot not.
+	*/
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
+		PADDRH (swide_scr_64),
 	/*
 	**	Save the remaining byte count, the updated 
 	**	address and the return address.
@@ -3698,16 +3881,25 @@
 		offsetof(struct ccb, phys.pm0.sg.size),
 	SCR_STORE_REL (ua, 4),
 		offsetof(struct ccb, phys.pm0.sg.addr),
-	SCR_STORE_REL (ia, 4),
-		offsetof(struct ccb, phys.pm0.ret),
 	/*
 	**	Set the current pointer at the PM0 DATA mini-script.
 	*/
 	SCR_LOAD_ABS (temp, 4),
 		PADDRH (pm0_data_addr),
 	SCR_JUMP,
-		PADDR (databreak),
+		PADDR (dispatch),
 }/*-------------------------< PM1_SAVE >-------------------*/,{
+	SCR_STORE_REL (ia, 4),
+		offsetof(struct ccb, phys.pm1.ret),
+	/*
+	**	If WSR bit is set, either UA and RBC may 
+	**	have been changed whatever the device wants 
+	**	to ignore this residue or not.
+	*/
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
+		PADDRH (swide_scr_64),
 	/*
 	**	Save the remaining byte count, the updated 
 	**	address and the return address.
@@ -3716,49 +3908,267 @@
 		offsetof(struct ccb, phys.pm1.sg.size),
 	SCR_STORE_REL (ua, 4),
 		offsetof(struct ccb, phys.pm1.sg.addr),
-	SCR_STORE_REL (ia, 4),
-		offsetof(struct ccb, phys.pm1.ret),
 	/*
 	**	Set the current pointer at the PM1 DATA mini-script.
 	*/
 	SCR_LOAD_ABS (temp, 4),
 		PADDRH (pm1_data_addr),
 	SCR_JUMP,
-		PADDR (databreak),
-}/*-------------------------< PM0_DATA_ADDR >---------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< PM1_DATA_ADDR >---------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< START_RAM >-------------------*/,{
+		PADDR (dispatch),
+
+}/*--------------------------< SWIDE_MA_32 >-----------------------*/,{
 	/*
-	**	Load the script into on-chip RAM, 
-	**	and jump to start point.
+	**	Handling of the SWIDE for 32 bit chips.
+	**
+	**	We jump here from the C code with SCRATCHA 
+	**	containing the address to write the SWIDE.
+	**	- Save 32 bit address in <scratch>.
 	*/
-	SCR_COPY (sizeof (struct script)),
-}/*-------------------------< SCRIPT0_BA >--------------------*/,{
-		0,
-		PADDR (start),
+	SCR_STORE_ABS (scratcha, 4),
+		PADDRH (scratch),
 	SCR_JUMP,
-		PADDR (init),
-
-}/*-------------------------< START_RAM64 >--------------------*/,{
+		PADDRH (swide_common),
+}/*--------------------------< SWIDE_MA_64 >-----------------------*/,{
 	/*
-	**	Load the RAM and start for 64 bit PCI (896).
-	**	Both scripts (script and scripth) are loaded into 
-	**	the RAM which is 8K (4K for 825A/875/895).
-	**	We also need to load some 32-63 bit segments 
-	**	address of the SCRIPTS processor.
-	**	LOAD/STORE ABSOLUTE always refers to on-chip RAM 
-	**	in our implementation. The main memory is 
-	**	accessed using LOAD/STORE DSA RELATIVE.
+	**	Handling of the SWIDE for 64 bit chips when the 
+	**	hardware handling of phase mismatch is disabled.
+	**
+	**	We jump here from the C code with SCRATCHA 
+	**	containing the address to write the SWIDE and 
+	**	SBR containing bit 32..39 of this address.
+	**	- Save 32 bit address in <scratch>.
+	**	- Move address bit 32..39 to SFBR.
 	*/
-	SCR_LOAD_REL (mmws, 4),
-		offsetof (struct ncb, scr_ram_seg),
-	SCR_COPY (sizeof(struct script)),
-}/*-------------------------< SCRIPT0_BA64 >--------------------*/,{
+	SCR_STORE_ABS (scratcha, 4),
+		PADDRH (scratch),
+	SCR_FROM_REG (sbr),
 		0,
-		PADDR (start),
-	SCR_COPY (sizeof(struct scripth)),
+	SCR_JUMP,
+		PADDRH (swide_com_64),
+}/*--------------------------< SWIDE_SCR_64 >-----------------------*/,{
+	/*
+	**	Handling of the SWIDE for 64 bit chips when 
+	**	hardware phase mismatch is enabled.
+	**	We are entered with a SCR_CALL from PMO_SAVE 
+	**	and PM1_SAVE sub-scripts.
+	**
+	**	Snoop the SCSI BUS in case of the device 
+	**	willing to ignore this residue.
+	**	If it does, we must only increment the RBC, 
+	**	since this register does reflect all bytes 
+	**	received from the SCSI BUS including the SWIDE.
+	*/
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDRH (swide_scr_64_1),
+	SCR_FROM_REG (sbdl),
+		0,
+	SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+		PADDRH (swide_scr_64_1),
+	SCR_REG_REG (rbc, SCR_ADD, 1),
+		0,
+	SCR_REG_REG (rbc1, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (rbc2, SCR_ADDC, 0),
+		0,
+	/*
+	**	Save UA and RBC, since the PM0/1_SAVE 
+	**	sub-scripts haven't moved them to the 
+	**	context yet and the below MOV may just 
+	**	change their value.
+	*/
+	SCR_STORE_ABS (ua, 4),
+		PADDRH (scratch),
+	SCR_STORE_ABS (rbc, 4),
+		PADDRH (scratch1),
+	/*
+	**	Throw away the IGNORE WIDE RESIDUE message.
+	**	since we just did take care of it.
+	*/
+	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+		NADDR (scratch),
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	**	Restore UA and RBC registers and return.
+	*/
+	SCR_LOAD_ABS (ua, 4),
+		PADDRH (scratch),
+	SCR_LOAD_ABS (rbc, 4),
+		PADDRH (scratch1),
+	SCR_RETURN,
+		0,
+}/*--------------------------< SWIDE_SCR_64_1 >---------------------*/,{
+	/*
+	**	We must grab the SWIDE and move it to 
+	**	memory.
+	**
+	**	- Save UA (32 bit address) in <scratch>.
+	**	- Move address bit 32..39 to SFBR.
+	**	- Increment UA (updated address).
+	*/
+	SCR_STORE_ABS (ua, 4),
+		PADDRH (scratch),
+	SCR_FROM_REG (rbc3),
+		0,
+	SCR_REG_REG (ua, SCR_ADD, 1),
+		0,
+	SCR_REG_REG (ua1, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (ua2, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (ua3, SCR_ADDC, 0),
+		0,
+}/*--------------------------< SWIDE_COM_64 >-----------------------*/,{
+	/*
+	**	- Save DRS.
+	**	- Load DRS with address bit 32..39 of the
+	**	  location to write the SWIDE.
+	**	  SFBR has been loaded with these bits.
+	**	  (Look above).
+	*/
+	SCR_STORE_ABS (drs, 4),
+		PADDRH (saved_drs),
+	SCR_LOAD_ABS (drs, 4),
+		PADDRH (zero),
+	SCR_TO_REG (drs),
+		0,
+}/*--------------------------< SWIDE_COMMON >-----------------------*/,{
+	/*
+	**	- Save current DSA
+	**	- Load DSA with bit 0..31 of the memory 
+	**	  location to write the SWIDE.
+	*/
+	SCR_STORE_ABS (dsa, 4),
+		PADDRH (saved_dsa),
+	SCR_LOAD_ABS (dsa, 4),
+		PADDRH (scratch),
+	/*
+	**	Move the SWIDE to memory.
+	**	Clear the WSR bit.
+	*/
+	SCR_STORE_REL (swide, 1),
+		0,
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
+	/*
+	**	Restore the original DSA.
+	*/
+	SCR_LOAD_ABS (dsa, 4),
+		PADDRH (saved_dsa),
+}/*--------------------------< SWIDE_FIN_32 >-----------------------*/,{
+	/*
+	**	For 32 bit chip, the following SCRIPTS 
+	**	instruction is patched with a JUMP to dispatcher.
+	**	(Look into the C code).
+	*/
+	SCR_LOAD_ABS (drs, 4),
+		PADDRH (saved_drs),
+	/*
+	**	64 bit chip only.
+	**	If PM handling from SCRIPTS, we are just 
+	**	a helper for the C code, so jump to 
+	**	dispatcher now.
+	*/
+	SCR_FROM_REG (ccntl0),
+		0,
+	SCR_JUMP ^ IFFALSE (MASK (ENPMJ, ENPMJ)),
+		PADDR (dispatch),
+	/*
+	**	64 bit chip with hardware PM handling enabled.
+	**
+	**	Since we are paranoid:), we donnot want 
+	**	a SWIDE followed by a CHMOV(1) to lead to 
+	**	a CHMOV(0) in our PM context.
+	**	We check against such a condition.
+	**	Also does the C code.
+	*/
+	SCR_FROM_REG (rbc),
+		0,
+	SCR_RETURN ^ IFFALSE (DATA (0)),
+		0,
+	SCR_FROM_REG (rbc1),
+		0,
+	SCR_RETURN ^ IFFALSE (DATA (0)),
+		0,
+	SCR_FROM_REG (rbc2),
+		0,
+	SCR_RETURN ^ IFFALSE (DATA (0)),
+		0,
+	/*
+	**	If we are there, RBC(0..23) is zero, 
+	**	and we just have to load the current 
+	**	DATA SCRIPTS address (register TEMP) 
+	**	with the IA and go to dispatch.
+	**	No PM context is needed.
+	*/
+	SCR_STORE_ABS (ia, 4),
+		PADDRH (scratch),
+	SCR_LOAD_ABS (temp, 4),
+		PADDRH (scratch),
+	SCR_JUMP,
+		PADDR (dispatch),
+
+}/*-------------------------< ZERO >------------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SCRATCH >---------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SCRATCH1 >--------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< PM0_DATA_ADDR >---------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< PM1_DATA_ADDR >---------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SAVED_DSA >-------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SAVED_DRS >-------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< DONE_POS >--------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< STARTPOS >--------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< TARGTBL >---------------------*/,{
+	SCR_DATA_ZERO,
+
+
+/*
+** We may use MEMORY MOVE instructions to load the on chip-RAM,
+** if it happens that mapping PCI memory is not possible.
+** But writing the RAM from the CPU is the preferred method, 
+** since PCI 2.2 seems to disallow PCI self-mastering.
+*/
+
+#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+
+}/*-------------------------< START_RAM >-------------------*/,{
+	/*
+	**	Load the script into on-chip RAM, 
+	**	and jump to start point.
+	*/
+	SCR_COPY (sizeof (struct script)),
+}/*-------------------------< SCRIPT0_BA >--------------------*/,{
+		0,
+		PADDR (start),
+	SCR_JUMP,
+		PADDR (init),
+
+}/*-------------------------< START_RAM64 >--------------------*/,{
+	/*
+	**	Load the RAM and start for 64 bit PCI (895A,896).
+	**	Both scripts (script and scripth) are loaded into 
+	**	the RAM which is 8K (4K for 825A/875/895).
+	**	We also need to load some 32-63 bit segments 
+	**	address of the SCRIPTS processor.
+	**	LOAD/STORE ABSOLUTE always refers to on-chip RAM 
+	**	in our implementation. The main memory is 
+	**	accessed using LOAD/STORE DSA RELATIVE.
+	*/
+	SCR_LOAD_REL (mmws, 4),
+		offsetof (struct ncb, scr_ram_seg),
+	SCR_COPY (sizeof(struct script)),
+}/*-------------------------< SCRIPT0_BA64 >--------------------*/,{
+		0,
+		PADDR (start),
+	SCR_COPY (sizeof(struct scripth)),
 }/*-------------------------< SCRIPTH0_BA64 >--------------------*/,{
 		0,
 		PADDRH  (start64),
@@ -3768,6 +4178,9 @@
 		PADDRH (start64),
 }/*-------------------------< RAM_SEG64 >--------------------*/,{
 		0,
+
+#endif /* SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
+
 }/*-------------------------< SNOOPTEST >-------------------*/,{
 	/*
 	**	Read the variable.
@@ -3801,50 +4214,17 @@
 	int	i;
 	ncrcmd	*p;
 
-#if	MAX_SCATTERH != 0
-	p = scrh->hdata_in;
-	for (i=0; i<MAX_SCATTERH; i++) {
-#if	SCR_SG_SIZE == 4
-		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
-		*p++ =PADDR (databreak);
-#endif
-		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
-		*p++ =offsetof (struct dsb, data[i]);
-	};
-	assert ((u_long)p == (u_long)&scrh->hdata_in + sizeof (scrh->hdata_in));
-#endif
-
 	p = scr->data_in;
-	for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
-#if	SCR_SG_SIZE == 4
-		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
-		*p++ =PADDR (databreak);
-#endif
-		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
+	for (i=0; i<MAX_SCATTER; i++) {
+		*p++ =SCR_CHMOV_TBL ^ SCR_DATA_IN;
 		*p++ =offsetof (struct dsb, data[i]);
 	};
-	assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
 
-#if	MAX_SCATTERH != 0
-	p = scrh->hdata_out;
-	for (i=0; i<MAX_SCATTERH; i++) {
-#if	SCR_SG_SIZE == 4
-		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
-		*p++ =PADDR (databreak);
-#endif
-		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
-		*p++ =offsetof (struct dsb, data[i]);
-	};
-	assert ((u_long)p==(u_long)&scrh->hdata_out + sizeof (scrh->hdata_out));
-#endif
+	assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
 
 	p = scr->data_out;
-	for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
-#if SCR_SG_SIZE == 4
-		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
-		*p++ =PADDR (databreak);
-#endif
-		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
+	for (i=0; i<MAX_SCATTER; i++) {
+		*p++ =SCR_CHMOV_TBL ^ SCR_DATA_OUT;
 		*p++ =offsetof (struct dsb, data[i]);
 	};
 
@@ -3860,7 +4240,8 @@
 **==========================================================
 */
 
-static void __init ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len)
+static void __init 
+ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len)
 {
 	ncrcmd  opcode, new, old, tmp1, tmp2;
 	ncrcmd	*start, *end;
@@ -3950,11 +4331,22 @@
 
 		case 0x0:
 			/*
-			**	MOVE (absolute address)
+			**	MOVE/CHMOV (absolute address)
 			*/
+			if (!(np->features & FE_WIDE))
+				dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
 			relocs = 1;
 			break;
 
+		case 0x1:
+			/*
+			**	MOVE/CHMOV (table indirect)
+			*/
+			if (!(np->features & FE_WIDE))
+				dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
+			relocs = 0;
+			break;
+
 		case 0x8:
 			/*
 			**	JUMP / CALL
@@ -4016,6 +4408,7 @@
 				}
 				/* fall through */
 			default:
+				new = 0;	/* For 'cc' not to complain */
 				panic("ncr_script_copy_and_bind: "
 				      "weird relocation %x\n", old);
 				break;
@@ -4083,9 +4476,16 @@
 **	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 825A, 875, 895 
-**	and 896 chips.
+**	NCR/SYMBIOS chips allow burst lengths of 2, 4, 8, 16, 32, 64,
+**	128 transfers. All chips support at least 16 transfers bursts. 
+**	The 825A, 875 and 895 chips support bursts of up to 128 
+**	transfers and the 895A and 896 support bursts of up to 64 
+**	transfers. All other chips support up to 16 transfers bursts.
+**
+**	For PCI 32 bit data transfers each transfer is a DWORD (4 bytes).
+**	It is a QUADWORD (8 bytes) for PCI 64 bit data transfers.
+**	Only the 896 is able to perform 64 bit data transfers.
+**
 **	We use log base 2 (burst length) as internal code, with 
 **	value 0 meaning "burst disabled".
 **
@@ -4128,8 +4528,8 @@
 **	Get target set-up from Symbios format NVRAM.
 */
 
-static void __init
-	ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
+static void __init 
+ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
 {
 	tcb_p tp = &np->target[target];
 	Symbios_target *tn = &nvram->target[target];
@@ -4137,7 +4537,7 @@
 	tp->usrsync = tn->sync_period ? (tn->sync_period + 3) / 4 : 255;
 	tp->usrwide = tn->bus_width == 0x10 ? 1 : 0;
 	tp->usrtags =
-		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SCSI_NCR_MAX_TAGS : 0;
+		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? MAX_TAGS : 0;
 
 	if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
 		tp->usrflag |= UF_NODISC;
@@ -4150,7 +4550,7 @@
 */
 
 static void __init
-	ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram)
+ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram)
 {
 	tcb_p tp = &np->target[target];
 	struct Tekram_target *tn = &nvram->target[target];
@@ -4261,7 +4661,7 @@
 	np->maxsync = period > 2540 ? 254 : period / 10;
 
 	/*
-	**	64 bit (53C896) ?
+	**	64 bit (53C895A or 53C896) ?
 	*/
 	if (np->features & FE_64BIT)
 #if BITS_PER_LONG > 32
@@ -4271,8 +4671,8 @@
 #endif
 
 	/*
-	**	Phase mismatch handled by SCRIPTS (53C896) ?
-	*/
+	**	Phase mismatch handled by SCRIPTS (53C895A or 53C896) ?
+  	*/
 	if (np->features & FE_NOPM)
 		np->rv_ccntl0	|= (ENPMJ);
 
@@ -4383,28 +4783,50 @@
 	ncr_init_burst(np, burst_max);
 
 	/*
-	**	Set differential mode and LED support.
-	**	Ignore these features for boards known to use a 
-	**	specific GPIO wiring (Tekram only for now) and 
-	**	for the 896 that drives the LED directly.
-	**	Probe initial setting of GPREG and GPCNTL for 
-	**	other ones.
-	*/
-	if (!nvram || nvram->type != SCSI_NCR_TEKRAM_NVRAM) {
+	**	Set SCSI BUS mode.
+	**
+	**	- ULTRA2 chips (895/895A/896) report the current 
+	**	  BUS mode through the STEST4 IO register.
+	**	- For previous generation chips (825/825A/875), 
+	**	  user has to tell us how to check against HVD, 
+	**	  since a 100% safe algorithm is not possible.
+	*/
+	np->scsi_mode = SMODE_SE;
+	if	(np->features & FE_ULTRA2)
+		np->scsi_mode = (np->sv_stest4 & SMODE);
+	else if	(np->features & FE_DIFF) {
 		switch(driver_setup.diff_support) {
-		case 3:
+		case 4:	/* Trust previous settings if present, then GPIO3 */
+			if (np->sv_scntl3) {
+				if (np->sv_stest2 & 0x20)
+					np->scsi_mode = SMODE_HVD;
+				break;
+			}
+		case 3:	/* SYMBIOS controllers report HVD through GPIO3 */
+			if (nvram && nvram->type != SCSI_NCR_SYMBIOS_NVRAM)
+				break;
 			if (INB(nc_gpreg) & 0x08)
+				break;
+		case 2:	/* Set HVD unconditionally */
+			np->scsi_mode = SMODE_HVD;
+		case 1:	/* Trust previous settings for HVD */
+			if (np->sv_stest2 & 0x20)
+				np->scsi_mode = SMODE_HVD;
 			break;
-		case 2:
-			np->rv_stest2	|= 0x20;
-			break;
-		case 1:
-			np->rv_stest2	|= (np->sv_stest2 & 0x20);
-			break;
-		default:
+		default:/* Don't care about HVD */	
 			break;
 		}
 	}
+	if (np->scsi_mode == SMODE_HVD)
+		np->rv_stest2 |= 0x20;
+
+	/*
+	**	Set LED support from SCRIPTS.
+	**	Ignore this feature for boards known to use a 
+	**	specific GPIO wiring and for the 895A or 896 
+	**	that drive the LED directly.
+	**	Also probe initial setting of GPIO0 as output.
+	*/
 	if ((driver_setup.led_pin ||
 	     (nvram && nvram->type == SCSI_NCR_SYMBIOS_NVRAM)) &&
 	    !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01))
@@ -4457,7 +4879,7 @@
 #endif
 			tp->usrsync = driver_setup.default_sync;
 			tp->usrwide = driver_setup.max_wide;
-			tp->usrtags = SCSI_NCR_MAX_TAGS;
+			tp->usrtags = MAX_TAGS;
 			if (!driver_setup.disconnection)
 				np->target[i].usrflag = UF_NODISC;
 		}
@@ -4587,7 +5009,8 @@
 **	start the timer daemon.
 */
 
-static int __init ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
+static int __init 
+ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
 {
         struct host_data *host_data;
 	ncb_p np = 0;
@@ -4758,6 +5181,19 @@
 	(void) ncr_prepare_setting(np, nvram);
 
 	/*
+	**	Check the PCI clock frequency.
+	**	Must be done after prepare_setting since it 
+	**	destroys STEST1 that is used to probe for 
+	**	the clock doubler.
+	*/
+	i = (int) ncr_getpciclock(np);
+	if (i > 37000) {
+		printk(KERN_ERR "%s: PCI clock seems too high (%u KHz).\n",
+		       ncr_name(np), i);
+		goto attach_error;
+	}
+
+	/*
 	**	Patch script to physical addresses
 	*/
 	ncr_script_fill (&script0, &scripth0);
@@ -4769,17 +5205,36 @@
 	if (np->base2_ba) {
 		np->p_script	= pcivtobus(np->base2_ba);
 		if (np->features & FE_RAM8K) {
+			np->base2_ws = 8192;
 			np->p_scripth = np->p_script + 4096;
 #if BITS_PER_LONG > 32
 			np->scr_ram_seg = cpu_to_scr(np->base2_ba >> 32);
 #endif
 		}
+		else
+			np->base2_ws = 4096;
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+		np->base2_va = remap_pci_mem(np->base2_ba, np->base2_ws);
+		if (!np->base2_va) {
+			printk(KERN_ERR "%s: can't map PCI MEMORY region\n",
+			       ncr_name(np));
+			goto attach_error;
+		}
+#endif
 	}
 
 	ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script));
 	ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth));
 
 	/*
+	**	If not 64 bit chip, patch some places in SCRIPTS.
+	*/
+	if (!(np->features & FE_64BIT)) {
+		np->scripth0->swide_fin_32[0] = cpu_to_scr(SCR_JUMP);
+		np->scripth0->swide_fin_32[1] = 
+				cpu_to_scr(NCB_SCRIPT_PHYS(np, dispatch));
+	}
+	/*
 	**	Patch some variables in SCRIPTS
 	*/
 	np->scripth0->pm0_data_addr[0] = 
@@ -4787,11 +5242,12 @@
 	np->scripth0->pm1_data_addr[0] = 
 			cpu_to_scr(NCB_SCRIPT_PHYS(np, pm1_data));
 
+#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 	np->scripth0->script0_ba[0]	= cpu_to_scr(vtobus(np->script0));
 	np->scripth0->script0_ba64[0]	= cpu_to_scr(vtobus(np->script0));
 	np->scripth0->scripth0_ba64[0]	= cpu_to_scr(vtobus(np->scripth0));
 	np->scripth0->ram_seg64[0]	= np->scr_ram_seg;
-
+#endif
 	/*
 	**	Prepare the idle and invalid task actions.
 	*/
@@ -4827,10 +5283,11 @@
 	/*
 	**	Prepare the target bus address array.
 	*/
-	np->script0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl));
+	np->scripth0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl));
 	for (i = 0 ; i < MAX_TARGET ; i++) {
 		np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i]));
 		np->target[i].b_luntbl = cpu_to_scr(vtobus(np->badluntbl));
+		np->target[i].b_lun0   = cpu_to_scr(vtobus(&np->resel_badlun));
 	}
 
 	/*
@@ -4846,6 +5303,23 @@
 				cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
 	}
 
+#ifdef SCSI_NCR_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 (!(driver_setup.iarb & 1))
+		np->script0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
+	/*
+	**    If user wants IARB to be set when we win arbitration 
+	**    and have other jobs, compute the max number of consecutive 
+	**    settings of IARB hint before we leave devices a chance to 
+	**    arbitrate for reselection.
+	*/
+	np->iarb_max = (driver_setup.iarb >> 4);
+#endif
+
 	/*
 	**	DEL 472 - 53C896 Rev 1 - Part Number 609-0393055 - ITEM 5.
 	*/
@@ -4890,14 +5364,20 @@
 
 	/*
 	**	Install the interrupt handler.
+	**	If we synchonize the C code with SCRIPTS on interrupt, 
+	**	we donnot want to share the INTR line at all.
 	*/
 	if (request_irq(device->slot.irq, sym53c8xx_intr,
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+			((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT),
+#else
 			((driver_setup.irqm & 0x10) ? 0 : SA_SHIRQ) |
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0)
 			((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT),
 #else
 			0,
 #endif
+#endif
 			NAME53C8XX, np)) {
 		printk(KERN_ERR "%s: request irq %d failure\n",
 			ncr_name(np), device->slot.irq);
@@ -4957,8 +5437,9 @@
 	**	and return success.
 	*/
 	instance->max_channel	= 0;
+	instance->this_id	= np->myaddr;
 	instance->max_id	= np->maxwide ? 16 : 8;
-	instance->max_lun	= SCSI_NCR_MAX_LUN;
+	instance->max_lun	= MAX_LUN;
 #ifndef NCR_IOMAPPED
 	instance->base		= (char *) np->reg;
 #endif
@@ -4967,6 +5448,9 @@
 	instance->io_port	= np->base_io;
 	instance->n_io_port	= np->base_ws;
 	instance->dma_channel	= 0;
+	instance->cmd_per_lun	= MAX_TAGS;
+	instance->can_queue	= (MAX_START-4);
+	
 	instance->select_queue_depths = sym53c8xx_select_queue_depths;
 
 	NCR_UNLOCK_NCB(np, flags);
@@ -5002,9 +5486,11 @@
 		free_irq(np->irq, np);
 	if (np->base_io)
 		release_region(np->base_io, np->base_ws);
-#ifndef NCR_IOMAPPED
+#ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 	if (np->base_va)
 		unmap_pci_mem(np->base_va, np->base_ws);
+	if (np->base2_va)
+		unmap_pci_mem(np->base2_va, np->base2_ws);
 #endif
 	if (np->scripth0)
 		m_free(np->scripth0, sizeof(struct scripth), "SCRIPTH");
@@ -5026,13 +5512,19 @@
 	for (target = 0; target < MAX_TARGET ; target++) {
 		tp = &np->target[target];
 		for (lun = 0 ; lun < MAX_LUN ; lun++) {
-			lp = tp->lp[lun];
+			lp = ncr_lp(np, tp, lun);
 			if (!lp)
 				continue;
 			if (lp->tasktbl != &lp->tasktbl_0)
-				m_free(lp->tasktbl, 256, "TASKTBL");
+				m_free(lp->tasktbl, MAX_TASKS*4, "TASKTBL");
+			if (lp->cb_tags)
+				m_free(lp->cb_tags, MAX_TAGS, "CB_TAGS");
 			m_free(lp, sizeof(*lp), "LCB");
 		}
+#if MAX_LUN > 1
+		if (tp->lmp)
+			m_free(tp->lmp, MAX_LUN * sizeof(lcb_p), "LMP");
+#endif 
 	}
 
 	m_free(np, sizeof(*np), "NCB");
@@ -5074,6 +5566,81 @@
 	}
 }
 
+/*==========================================================
+**
+**
+**	Prepare the next negotiation message if needed.
+**
+**	Fill in the part of message buffer that contains the 
+**	negotiation and the nego_status field of the CCB.
+**	Returns the size of the message in bytes.
+**
+**
+**==========================================================
+*/
+
+static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr)
+{
+	tcb_p tp = &np->target[cp->target];
+	int msglen = 0;
+	int nego = 0;
+
+	if (tp->inq_done) {
+
+		/*
+		**	negotiate wide transfers ?
+		*/
+
+		if (!tp->widedone) {
+			if (tp->inq_byte7 & INQ7_WIDE16) {
+				nego = NS_WIDE;
+			} else
+				tp->widedone=1;
+		};
+
+		/*
+		**	negotiate synchronous transfers?
+		*/
+
+		if (!nego && !tp->period) {
+			if (tp->inq_byte7 & INQ7_SYNC) {
+				nego = NS_SYNC;
+			} else {
+				tp->period  =0xffff;
+				PRINT_TARGET(np, cp->target);
+				printk ("target did not report SYNC.\n");
+			};
+		};
+	};
+
+	switch (nego) {
+	case NS_SYNC:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 3;
+		msgptr[msglen++] = M_X_SYNC_REQ;
+		msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
+		msgptr[msglen++] = tp->maxoffs;
+		break;
+	case NS_WIDE:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 2;
+		msgptr[msglen++] = M_X_WIDE_REQ;
+		msgptr[msglen++] = tp->usrwide;
+		break;
+	};
+
+	cp->nego_status = nego;
+
+	if (nego) {
+		tp->nego_cp = cp;
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			ncr_print_msg(cp, nego == NS_WIDE ?
+					  "wide msgout":"sync_msgout", msgptr);
+		};
+	};
+
+	return msglen;
+}
 
 /*==========================================================
 **
@@ -5088,12 +5655,12 @@
 {
 /*	Scsi_Device        *device    = cmd->device; */
 	tcb_p tp                      = &np->target[cmd->target];
-	lcb_p lp		      = tp->lp[cmd->lun];
+	lcb_p lp		      = ncr_lp(np, tp, cmd->lun);
 	ccb_p cp;
 
 	int	segments;
-	u_char	nego, idmsg, *msgptr;
-	u_int  msglen;
+	u_char	idmsg, *msgptr;
+	u_int   msglen;
 	int	direction;
 	u_int32	lastp, goalp;
 
@@ -5138,9 +5705,10 @@
 	**
 	**----------------------------------------------------
 	*/
-	if (np->settle_time && cmd->timeout_per_command >= HZ &&
-		np->settle_time > jiffies + cmd->timeout_per_command - HZ) {
-		np->settle_time = jiffies + cmd->timeout_per_command - HZ;
+	if (np->settle_time && cmd->timeout_per_command >= HZ) {
+		u_long tlimit = ktime_get(cmd->timeout_per_command - HZ);
+		if (ktime_dif(np->settle_time, tlimit) > 0)
+			np->settle_time = tlimit;
 	}
 
         if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
@@ -5166,85 +5734,39 @@
 	cp->phys.num_disc = 0;
 #endif
 
-	/*---------------------------------------------------
+	/*----------------------------------------------------
 	**
-	**	negotiation required?
+	**	Build the identify / tag / sdtr message
 	**
-	**---------------------------------------------------
+	**----------------------------------------------------
 	*/
 
-	nego = 0;
+	idmsg = M_IDENTIFY | cp->lun;
+
+	if (cp ->tag != NO_TAG || (lp && !(tp->usrflag & UF_NODISC)))
+		idmsg |= 0x40;
+
+	msgptr = cp->scsi_smsg;
+	msglen = 0;
+	msgptr[msglen++] = idmsg;
 
-	if ((!tp->widedone || !tp->period) && !tp->nego_cp && tp->inq_done && lp) {
+	if (cp->tag != NO_TAG) {
+		char order = np->order;
 
 		/*
-		**	negotiate wide transfers ?
+		**	Force ordered tag if necessary to avoid timeouts 
+		**	and to preserve interactivity.
 		*/
-
-		if (!tp->widedone) {
-			if (tp->inq_byte7 & INQ7_WIDE16) {
-				nego = NS_WIDE;
-			} else
-				tp->widedone=1;
-		};
-
-		/*
-		**	negotiate synchronous transfers?
-		*/
-
-		if (!nego && !tp->period) {
-			if (tp->inq_byte7 & INQ7_SYNC) {
-				nego = NS_SYNC;
-			} else {
-				tp->period  =0xffff;
-				PRINT_TARGET(np, cp->target);
-				printk ("target did not report SYNC.\n");
-			};
-		};
-
-		/*
-		**	remember nego is pending for the target.
-		**	Avoid to start a nego for all queued commands 
-		**	when tagged command queuing is enabled.
-		*/
-
-		if (nego)
-			tp->nego_cp = cp;
-	};
-
-	/*----------------------------------------------------
-	**
-	**	Build the identify / tag / sdtr message
-	**
-	**----------------------------------------------------
-	*/
-
-	idmsg = M_IDENTIFY | cp->lun;
-
-	if (cp ->tag != NO_TAG || (lp && !(tp->usrflag & UF_NODISC)))
-		idmsg |= 0x40;
-
-	msgptr = cp->scsi_smsg;
-	msglen = 0;
-	msgptr[msglen++] = idmsg;
-
-	if (cp->tag != NO_TAG) {
-		char order = np->order;
-
-		/*
-		**	Force ordered tag if necessary to avoid timeouts 
-		**	and to preserve interactivity.
-		*/
-		if (lp && lp->tags_stime + (3*HZ) <= jiffies) {
-			if (lp->tags_smap) {
+		if (lp && ktime_exp(lp->tags_stime)) {
+			lp->tags_si = !(lp->tags_si);
+			if (lp->tags_sum[lp->tags_si]) {
 				order = M_ORDERED_TAG;
-				if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ 
+				if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>0){ 
 					PRINT_ADDR(cmd);
 					printk("ordered tag forced.\n");
 				}
 			}
-			lp->tags_stime = jiffies;
-			lp->tags_smap = lp->tags_umap;
+			lp->tags_stime = ktime_get(3*HZ);
 		}
 
 		if (order == 0) {
@@ -5263,41 +5785,19 @@
 		}
 		msgptr[msglen++] = order;
 		/*
-		**	Actual tags are numbered 1,3,5,..2*MAXTAGS+1,
-		**	since we may have to deal with devices that have 
-		**	problems with #TAG 0 or too great #TAG numbers.
+		**	For less than 128 tags, actual tags are numbered 
+		**	1,3,5,..2*MAXTAGS+1,since we may have to deal 
+		**	with devices that have problems with #TAG 0 or too 
+		**	great #TAG numbers. For more tags (up to 256), 
+		**	we use directly our tag number.
 		*/
+#if MAX_TASKS > (512/4)
+		msgptr[msglen++] = cp->tag;
+#else
 		msgptr[msglen++] = (cp->tag << 1) + 1;
+#endif
 	}
 
-	switch (nego) {
-	case NS_SYNC:
-		msgptr[msglen++] = M_EXTENDED;
-		msgptr[msglen++] = 3;
-		msgptr[msglen++] = M_X_SYNC_REQ;
-		msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
-		msgptr[msglen++] = tp->maxoffs;
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgout: ");
-			ncr_show_msg (&cp->scsi_smsg [msglen-5]);
-			printk (".\n");
-		};
-		break;
-	case NS_WIDE:
-		msgptr[msglen++] = M_EXTENDED;
-		msgptr[msglen++] = 2;
-		msgptr[msglen++] = M_X_WIDE_REQ;
-		msgptr[msglen++] = tp->usrwide;
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide msgout: ");
-			ncr_show_msg (&cp->scsi_smsg [msglen-4]);
-			printk (".\n");
-		};
-		break;
-	};
-
 	cp->host_flags	= 0;
 
 	/*----------------------------------------------------
@@ -5307,7 +5807,7 @@
 	**----------------------------------------------------
 	*/
 
-	segments = np->scatter (cp, cp->cmd);
+	cp->segments = segments = np->scatter (cp, cp->cmd);
 
 	if (segments < 0) {
 		ncr_free_ccb(np, cp);
@@ -5357,16 +5857,8 @@
 	*/
 	if (direction & XFER_OUT) {
 		goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
-#if	MAX_SCATTERH != 0
-		if (segments <= MAX_SCATTERL)
-			lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-		else {
-			lastp = NCB_SCRIPTH_PHYS (np, hdata_out2);
-			lastp -= (segments - MAX_SCATTERL) * (SCR_SG_SIZE*4);
-		}
-#else
 		lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-#endif
+
 		/*
 		**	If actual data direction is unknown, save pointers 
 		**	in header. The SCRIPTS will swap them to current 
@@ -5383,16 +5875,7 @@
 	*/
 	if (direction & XFER_IN) {
 		goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
-#if	MAX_SCATTERH != 0
-		if (segments <= MAX_SCATTERL)
-			lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-		else {
-			lastp = NCB_SCRIPTH_PHYS (np, hdata_in2);
-			lastp -= (segments - MAX_SCATTERL) * (SCR_SG_SIZE*4);
-		}
-#else
 		lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-#endif
 	}
 
 	/*
@@ -5411,8 +5894,26 @@
 	/*
 	**	Save the initial data pointer in order to be able 
 	**	to redo the command.
+	**	We also have to save the initial lastp, since it 
+	**	will be changed to DATA_IO if we don't know the data 
+	**	direction and the device completes the command with 
+	**	QUEUE FULL status (without entering the data phase).
 	*/
 	cp->startp = cp->phys.header.savep;
+	cp->lastp0 = cp->phys.header.lastp;
+
+	/*---------------------------------------------------
+	**
+	**	negotiation required?
+	**
+	**	(nego_status is filled by ncr_prepare_nego())
+	**
+	**---------------------------------------------------
+	*/
+
+	cp->nego_status = 0;
+	if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp)
+		msglen += ncr_prepare_nego (np, cp, msgptr + msglen);
 
 	/*----------------------------------------------------
 	**
@@ -5439,24 +5940,30 @@
 	/*
 	**	message
 	*/
-	cp->phys.smsg.addr		= cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
-	cp->phys.smsg.size		= cpu_to_scr(msglen);
+	cp->phys.smsg.addr	= cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
+	cp->phys.smsg.size	= cpu_to_scr(msglen);
 
 	/*
 	**	command
 	*/
-	cp->phys.cmd.addr		= cpu_to_scr(vtobus (&cmd->cmnd[0]));
-	cp->phys.cmd.size		= cpu_to_scr(cmd->cmd_len);
+	cp->phys.cmd.addr	= cpu_to_scr(vtobus (&cmd->cmnd[0]));
+	cp->phys.cmd.size	= cpu_to_scr(cmd->cmd_len);
 
 	/*
 	**	status
 	*/
-	cp->actualquirks		= tp->quirks;
-	cp->host_status			= nego ? HS_NEGOTIATE : HS_BUSY;
-	cp->scsi_status			= S_ILLEGAL;
+	cp->actualquirks	= tp->quirks;
+	cp->host_status		= cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
+	cp->scsi_status		= S_ILLEGAL;
+	cp->xerr_status		= 0;
+	cp->phys.extra_bytes	= 0;
 
-	cp->xerr_status			= XE_OK;
-	cp->nego_status			= nego;
+	/*
+	**	extreme data pointer.
+	**	shall be positive, so -1 is lower than lowest.:)
+	*/
+	cp->ext_sg  = -1;
+	cp->ext_ofs = 0;
 
 	/*----------------------------------------------------
 	**
@@ -5469,17 +5976,10 @@
 	**	activate this job.
 	*/
 
-	/* Compute a time limit greater than the middle-level driver one */
-	if (cmd->timeout_per_command > 0)
-		cp->tlimit	= jiffies + cmd->timeout_per_command + HZ;
-	else
-		cp->tlimit	= jiffies + 86400 * HZ;/* No timeout=24 hours */
-
 	/*
 	**	insert next CCBs into start queue.
 	**	2 max at a time is enough to flush the CCB wait queue.
 	*/
-	cp->auto_sense = 0;
 	if (lp)
 		ncr_start_next_ccb(np, lp, 2);
 	else
@@ -5525,6 +6025,24 @@
 {
 	u_short	qidx;
 
+#ifdef SCSI_NCR_IARB_SUPPORT
+	/*
+	**	If the previously queued CCB is not yet done, 
+	**	set the IARB hint. The SCRIPTS will go with IARB 
+	**	for this job when starting the previous one.
+	**	We leave devices a chance to win arbitration by 
+	**	not using more than 'iarb_max' consecutive 
+	**	immediate arbitrations.
+	*/
+	if (np->last_cp && np->iarb_count < np->iarb_max) {
+		np->last_cp->host_flags |= HF_HINT_IARB;
+		++np->iarb_count;
+	}
+	else
+		np->iarb_count = 0;
+	np->last_cp = cp;
+#endif
+	
 	/*
 	**	insert into start queue.
 	*/
@@ -5546,7 +6064,7 @@
 	**	Wake it up.
 	*/
 	MEMORY_BARRIER();
-	OUTB (nc_istat, SIGP);
+	OUTB (nc_istat, SIGP|np->istat_sem);
 }
 
 
@@ -5593,7 +6111,6 @@
 **
 **
 **	Start reset process.
-**	If reset in progress do nothing.
 **	The interrupt handler will reinitialize the chip.
 **	The timeout handler will wait for settle_time before 
 **	clearing it and so resuming command processing.
@@ -5603,17 +6120,15 @@
 */
 static void ncr_start_reset(ncb_p np)
 {
-	if (!np->settle_time) {
-		(void) ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay);
- 	}
- }
+	(void) ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay);
+}
  
 static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay)
 {
 	u_int32 term;
 	int retv = 0;
 
-	np->settle_time	= jiffies + settle_delay * HZ;
+	np->settle_time	= ktime_get(settle_delay * HZ);
 
 	if (bootverbose > 1)
 		printk("%s: resetting, "
@@ -5747,8 +6262,6 @@
 {
 /*	Scsi_Device        *device    = cmd->device; */
 	ccb_p cp;
-	int found;
-	int retv;
 
 /*
  * First, look for the scsi command in the waiting list
@@ -5762,58 +6275,41 @@
 /*
  * Then, look in the wakeup list
  */
-	for (found=0, cp=np->ccbc; cp; cp=cp->link_ccb) {
+	for (cp=np->ccbc; cp; cp=cp->link_ccb) {
 		/*
 		**	look for the ccb of this command.
 		*/
 		if (cp->host_status == HS_IDLE) continue;
-		if (cp->cmd == cmd) {
-			found = 1;
+		if (cp->cmd == cmd)
 			break;
-		}
 	}
 
-	if (!found) {
+	if (!cp) {
 		return SCSI_ABORT_NOT_RUNNING;
 	}
 
-	if (np->settle_time) {
-		return SCSI_ABORT_SNOOZE;
-	}
-
 	/*
-	**	If the CCB is active, patch schedule jumps for the 
-	**	script to abort the command.
+	**	Keep track we have to abort this job.
 	*/
+	cp->to_abort = 1;
 
-	cp->tlimit = 0;
-	switch(cp->host_status) {
-	case HS_BUSY:
-	case HS_NEGOTIATE:
-		printk ("%s: abort ccb=%p (cancel)\n", ncr_name (np), cp);
-			cp->phys.header.go.start =
-				cpu_to_scr(NCB_SCRIPTH_PHYS (np, cancel));
-		retv = SCSI_ABORT_PENDING;
-		break;
-	case HS_DISCONNECT:
-		cp->phys.header.go.restart =
-				cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q));
-		retv = SCSI_ABORT_PENDING;
-		break;
-	default:
-		retv = SCSI_ABORT_NOT_RUNNING;
-		break;
-
-	}
+	/*
+	**	Tell the SCRIPTS processor to stop 
+	**	and synchronize with us.
+	*/
+	np->istat_sem = SEM;
 
 	/*
 	**      If there are no requests, the script
 	**      processor will sleep on SEL_WAIT_RESEL.
 	**      Let's wake it up, since it may have to work.
 	*/
-	OUTB (nc_istat, SIGP);
+	OUTB (nc_istat, SIGP|SEM);
 
-	return retv;
+	/*
+	**	Tell user we are working for him.
+	*/
+	return SCSI_ABORT_PENDING;
 }
 
 /*==========================================================
@@ -5917,7 +6413,7 @@
 	cmd = cp->cmd;
 	cp->cmd = NULL;
 	tp = &np->target[cp->target];
-	lp = tp->lp[cp->lun];
+	lp = ncr_lp(np, tp, cp->lun);
 
 	/*
 	**	We donnot queue more than 1 ccb per target 
@@ -5928,41 +6424,47 @@
 	if (cp == tp->nego_cp)
 		tp->nego_cp = 0;
 
+#ifdef SCSI_NCR_IARB_SUPPORT
 	/*
-	**	If auto-sense performed, change scsi status.
+	**	We just complete the last queued CCB.
+	**	Clear this info that is no more relevant.
 	*/
-	if (cp->auto_sense) {
-		cp->scsi_status = cp->auto_sense;
-	}
+	if (cp == np->last_cp)
+		np->last_cp = 0;
+#endif
 
 	/*
-	**	Check for parity errors.
+	**	If auto-sense performed, change scsi status, 
+	**	Otherwise, compute the residual.
 	*/
-
-	if (cp->host_flags & HF_PAR_ERR) {
-		PRINT_ADDR(cmd);
-		printk ("unrecovered SCSI parity error.\n");
-		if (cp->host_status==HS_COMPLETE)
-			cp->host_status = HS_FAIL;
+	if (cp->host_flags & HF_AUTO_SENSE) {
+		cp->scsi_status = cp->sv_scsi_status;
+		cp->xerr_status = cp->sv_xerr_status;
+	}
+	else {
+		cp->resid = 0;
+		if (cp->phys.header.lastp != cp->phys.header.goalp)
+			cp->resid = ncr_compute_residual(np, cp);
 	}
 
 	/*
 	**	Check for extended errors.
 	*/
 
-	if (cp->xerr_status != XE_OK) {
-		PRINT_ADDR(cmd);
-		switch (cp->xerr_status) {
-		case XE_EXTRA_DATA:
+	if (cp->xerr_status) {
+		if (cp->xerr_status & XE_PARITY_ERR) {
+			PRINT_ADDR(cp->cmd);
+			printk ("unrecovered SCSI parity error.\n");
+		}
+		if (cp->xerr_status & XE_EXTRA_DATA) {
+			PRINT_ADDR(cp->cmd);
 			printk ("extraneous data discarded.\n");
-			break;
-		case XE_BAD_PHASE:
+		}
+		if (cp->xerr_status & XE_BAD_PHASE) {
+			PRINT_ADDR(cp->cmd);
 			printk ("illegal scsi phase (4/5).\n");
-			break;
-		default:
-			printk ("extended error %d.\n", cp->xerr_status);
-			break;
 		}
+
 		if (cp->host_status==HS_COMPLETE)
 			cp->host_status = HS_FAIL;
 	}
@@ -5971,10 +6473,13 @@
 	**	Print out any error for debugging purpose.
 	*/
 	if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
-		if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD) {
+		if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD ||
+		    cp->resid) {
 			PRINT_ADDR(cmd);
-			printk ("ERROR: cmd=%x host_status=%x scsi_status=%x\n",
-				cmd->cmnd[0], cp->host_status, cp->scsi_status);
+			printk ("ERROR: cmd=%x host_status=%x scsi_status=%x "
+				"data_len=%d residual=%d\n",
+				cmd->cmnd[0], cp->host_status, cp->scsi_status,
+				cp->data_len, -cp->resid);
 		}
 	}
 
@@ -5992,13 +6497,6 @@
 		SetScsiResult(cmd, DID_OK, cp->scsi_status);
 
 		/*
-		**	@RESID@
-		**	Could dig out the correct value for resid,
-		**	but it would be quite complicated.
-		*/
-		/* if (cp->phys.header.lastp != cp->phys.header.goalp) */
-
-		/*
 		**	Allocate the lcb if not yet.
 		*/
 		if (!lp)
@@ -6038,12 +6536,8 @@
 		SetScsiResult(cmd, DID_OK, S_CHECK_COND);
 
 		if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
-			u_char * p = (u_char*) & cmd->sense_buffer;
-			int i;
 			PRINT_ADDR(cmd);
-			printk ("sense data:");
-			for (i=0; i<14; i++) printk (" %x", *p++);
-			printk (".\n");
+			ncr_printl_hex("sense data:", cmd->sense_buffer, 14);
 		}
 
 	} else if ((cp->host_status == HS_COMPLETE)
@@ -6078,6 +6572,7 @@
 		SetScsiResult(cmd, DID_ABORT, cp->scsi_status);
 
 	} else {
+		int did_status;
 
 		/*
 		**  Other protocol messes
@@ -6086,7 +6581,11 @@
 		printk ("COMMAND FAILED (%x %x) @%p.\n",
 			cp->host_status, cp->scsi_status, cp);
 
-		SetScsiResult(cmd, DID_ERROR, cp->scsi_status);
+		did_status = DID_ERROR;
+		if (cp->xerr_status & XE_PARITY_ERR)
+			did_status = DID_PARITY;
+
+		SetScsiResult(cmd, did_status, cp->scsi_status);
 	}
 
 	/*
@@ -6094,12 +6593,9 @@
 	*/
 
 	if (tp->usrflag & UF_TRACE) {
-		u_char * p;
-		int i;
 		PRINT_ADDR(cmd);
 		printk (" CMD:");
-		p = (u_char*) &cmd->cmnd[0];
-		for (i=0; i<cmd->cmd_len; i++) printk (" %x", *p++);
+		ncr_print_hex(cmd->cmnd, cmd->cmd_len);
 
 		if (cp->host_status==HS_COMPLETE) {
 			switch (cp->scsi_status) {
@@ -6108,9 +6604,7 @@
 				break;
 			case S_CHECK_COND:
 				printk ("  SENSE:");
-				p = (u_char*) &cmd->sense_buffer;
-				for (i=0; i<14; i++)
-					printk (" %x", *p++);
+				ncr_print_hex(cmd->sense_buffer, 14);
 				break;
 			default:
 				printk ("  STAT: %x\n", cp->scsi_status);
@@ -6250,7 +6744,7 @@
 	**	Start at first entry.
 	*/
 	np->squeueput = 0;
-	np->script0->startpos[0] = cpu_to_scr(phys);
+	np->scripth0->startpos[0] = cpu_to_scr(phys);
 
 	/*
 	**	Clear Done Queue
@@ -6265,7 +6759,7 @@
 	/*
 	**	Start at first entry.
 	*/
-	np->script0->done_pos[0] = cpu_to_scr(phys);
+	np->scripth0->done_pos[0] = cpu_to_scr(phys);
 	np->dqueueget = 0;
 
 	/*
@@ -6313,7 +6807,7 @@
 		np->rv_ccntl0 |= DPR;
 
 	/*
-	**	If 64 bit (53C896) enable 40 bit address table 
+	**	If 64 bit (53C895A or 53C896) enable 40 bit address table 
 	**	indirect addressing for MOVE.
 	*/
 
@@ -6322,7 +6816,7 @@
 	}
 
 	/*
-	**	If phase mismatch handled by scripts (53C896),
+	**	If phase mismatch handled by scripts (53C895A or 53C896),
 	**	set PM jump addresses.
 	*/
 
@@ -6370,6 +6864,8 @@
 	for (i=0;i<MAX_TARGET;i++) {
 		tcb_p tp = &np->target[i];
 
+		tp->to_reset = 0;
+
 		tp->sval    = 0;
 		tp->wval    = np->rv_scntl3;
 
@@ -6390,21 +6886,41 @@
 	}
 
 	/*
-	**    Start script processor.
+	**    Download SCSI SCRIPTS to on-chip RAM if present,
+	**    and start script processor.
+	**    We do the download preferently from the CPU.
+	**    For platforms that may not support PCI memory mapping,
+	**    we use a simple SCRIPTS that performs MEMORY MOVEs.
 	*/
 	MEMORY_BARRIER();
 	if (np->base2_ba) {
 		if (bootverbose)
 			printk ("%s: Downloading SCSI SCRIPTS.\n",
 				ncr_name(np));
-		if (np->features & FE_RAM8K)
+#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+		if (np->base2_ws == 8192)
 			phys = NCB_SCRIPTH0_PHYS (np, start_ram64);
 		else
 			phys = NCB_SCRIPTH_PHYS (np, start_ram);
+#else
+		if (np->base2_ws == 8192) {
+			memcpy_to_pci(np->base2_va + 4096,
+					np->scripth0, sizeof(struct scripth));
+			OUTL (nc_mmws, np->scr_ram_seg);
+			OUTL (nc_mmrs, np->scr_ram_seg);
+			OUTL (nc_sfs,  np->scr_ram_seg);
+			phys = NCB_SCRIPTH_PHYS (np, start64);
+		}
+		else
+			phys = NCB_SCRIPT_PHYS (np, init);
+		memcpy_to_pci(np->base2_va, np->script0, sizeof(struct script));
+#endif /* SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
 	}
 	else
 		phys = NCB_SCRIPT_PHYS (np, init);
 
+	np->istat_sem = 0;
+
 	OUTL (nc_dsa, vtobus(np));
 	OUTL (nc_dsp, phys);
 }
@@ -6609,7 +7125,11 @@
 
 	/*
 	**	Bells and whistles   ;-)
+	**	Donnot announce negotiations due to auto-sense, 
+	**	unless user really want us to be verbose. :)
 	*/
+	if (bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE))
+		goto next;
 	PRINT_TARGET(np, target);
 	if (sxfer & 0x01f) {
 		unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0);
@@ -6634,7 +7154,7 @@
 			mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f);
 	} else
 		printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
-
+next:
 	/*
 	**	set actual value and sync_status
 	**	patch ALL ccbs of this target.
@@ -6705,8 +7225,8 @@
 static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln)
 {
 	tcb_p tp = &np->target[tn];
-	lcb_p lp = tp->lp[ln];
-	u_char   reqtags, maxdepth;
+	lcb_p lp = ncr_lp(np, tp, ln);
+	u_short reqtags, maxdepth;
 
 	/*
 	**	Just in case ...
@@ -6800,35 +7320,12 @@
 {
 	u_char t;
 	tcb_p tp;
+	int ln;
+	u_long size;
 
 	switch (np->user.cmd) {
-
 	case 0: return;
 
-	case UC_SETSYNC:
-		for (t=0; t<MAX_TARGET; t++) {
-			if (!((np->user.target>>t)&1)) continue;
-			tp = &np->target[t];
-			tp->usrsync = np->user.data;
-			ncr_negotiate (np, tp);
-		};
-		break;
-
-	case UC_SETTAGS:
-		for (t=0; t<MAX_TARGET; t++) {
-			int ln;
-			if (!((np->user.target>>t)&1)) continue;
-			np->target[t].usrtags = np->user.data;
-			for (ln = 0; ln < MAX_LUN; ln++) {
-				lcb_p lp = np->target[t].lp[ln];
-				if (!lp)
-					continue;
-				lp->maxtags = lp->numtags = np->user.data;
-				ncr_setup_tags (np, t, ln);
-			}
-		};
-		break;
-
 	case UC_SETDEBUG:
 #ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 		ncr_debug = np->user.data;
@@ -6843,31 +7340,73 @@
 		np->verbose = np->user.data;
 		break;
 
-	case UC_SETWIDE:
-		for (t=0; t<MAX_TARGET; t++) {
-			u_long size;
-			if (!((np->user.target>>t)&1)) continue;
-			tp = &np->target[t];
-			size = np->user.data;
-			if (size > np->maxwide) size=np->maxwide;
-			tp->usrwide = size;
-			ncr_negotiate (np, tp);
-		};
-		break;
-
-	case UC_SETFLAG:
-		for (t=0; t<MAX_TARGET; t++) {
-			if (!((np->user.target>>t)&1)) continue;
-			tp = &np->target[t];
-			tp->usrflag = np->user.data;
-		};
-		break;
-
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 	case UC_CLEARPROF:
 		bzero(&np->profile, sizeof(np->profile));
 		break;
 #endif
+	default:
+		/*
+		**	We assume that other commands apply to targets.
+		**	This should always be the case and avoid the below 
+		**	4 lines to be repeated 5 times.
+		*/
+		for (t = 0; t < MAX_TARGET; t++) {
+			if (!((np->user.target >> t) & 1))
+				continue;
+			tp = &np->target[t];
+
+			switch (np->user.cmd) {
+
+			case UC_SETSYNC:
+				tp->usrsync = np->user.data;
+				ncr_negotiate (np, tp);
+				break;
+
+			case UC_SETWIDE:
+				size = np->user.data;
+				if (size > np->maxwide)
+					size=np->maxwide;
+				tp->usrwide = size;
+				ncr_negotiate (np, tp);
+				break;
+
+			case UC_SETTAGS:
+				tp->usrtags = np->user.data;
+				for (ln = 0; ln < MAX_LUN; ln++) {
+					lcb_p lp;
+					lp = ncr_lp(np, tp, ln);
+					if (!lp)
+						continue;
+					lp->numtags = np->user.data;
+					lp->maxtags = lp->numtags;
+					ncr_setup_tags (np, t, ln);
+				}
+				break;
+
+			case UC_RESETDEV:
+				tp->to_reset = 1;
+				np->istat_sem = SEM;
+				OUTB (nc_istat, SIGP|SEM);
+				break;
+
+			case UC_CLEARDEV:
+				for (ln = 0; ln < MAX_LUN; ln++) {
+					lcb_p lp;
+					lp = ncr_lp(np, tp, ln);
+					if (lp)
+						lp->to_clear = 1;
+				}
+				np->istat_sem = SEM;
+				OUTB (nc_istat, SIGP|SEM);
+				break;
+
+			case UC_SETFLAG:
+				tp->usrflag = np->user.data;
+				break;
+			}
+		}
+		break;
 	}
 	np->user.cmd=0;
 }
@@ -6889,7 +7428,7 @@
 
 static void ncr_timeout (ncb_p np)
 {
-	u_long	thistime = jiffies;
+	u_long	thistime = ktime_get(0);
 
 	/*
 	**	If release process in progress, let's go
@@ -6902,7 +7441,11 @@
 		return;
 	}
 
-	np->timer.expires = jiffies + SCSI_NCR_TIMER_INTERVAL;
+#ifdef SCSI_NCR_PCIQ_BROKEN_INTR
+	np->timer.expires = ktime_get((HZ+9)/10);
+#else
+	np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL);
+#endif
 	add_timer(&np->timer);
 
 	/*
@@ -6926,7 +7469,19 @@
 		np->lasttime = thistime;
 	}
 
-#ifdef SCSI_NCR_BROKEN_INTR
+#ifdef SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS
+	/*
+	**	Some way-broken PCI bridges may lead to 
+	**	completions being lost when the clearing 
+	**	of the INTFLY flag by the CPU occurs 
+	**	concurrently with the chip raising this flag.
+	**	If this ever happen, lost completions will 
+	**	be reaped here.
+	*/
+	ncr_wakeup_done(np);
+#endif
+
+#ifdef SCSI_NCR_PCIQ_BROKEN_INTR
 	if (INB(nc_istat) & (INTF|SIP|DIP)) {
 
 		/*
@@ -6936,7 +7491,7 @@
 		ncr_exception (np);
 		if (DEBUG_FLAGS & DEBUG_TINY) printk ("}");
 	}
-#endif /* SCSI_NCR_BROKEN_INTR */
+#endif /* SCSI_NCR_PCIQ_BROKEN_INTR */
 }
 
 /*==========================================================
@@ -6963,7 +7518,7 @@
 **		dsp:	script adress (relative to start of script).
 **		dbc:	first word of script command.
 **
-**	First 16 register of the chip:
+**	First 24 register of the chip:
 **		r0..rf
 **
 **==========================================================
@@ -7012,7 +7567,7 @@
 	}
 
         printk ("%s: regdump:", ncr_name(np));
-        for (i=0; i<16;i++)
+        for (i=0; i<24;i++)
             printk (" %02x", (unsigned)INB_OFF(i));
         printk (".\n");
 }
@@ -7119,7 +7674,7 @@
 	**	with my 895 that unfortunately suffers of the MA int.).
 	*/
 	if (driver_setup.optimize & 1) {
-		OUTB(nc_istat, (INTF | SIGP));
+		OUTB(nc_istat, (INTF | SIGP | np->istat_sem));
 		if (ncr_wakeup_done (np)) {
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 			++np->profile.num_fly;
@@ -7131,10 +7686,17 @@
 
 	/*
 	**	interrupt on the fly ?
+	**
+	**	For bridges that donnot flush posted writes 
+	**	in the reverse direction on read, a dummy read 
+	**	may help not to miss completions.
 	*/
 	istat = INB (nc_istat);
 	if (istat & INTF) {
-		OUTB (nc_istat, (istat & SIGP) | INTF);
+		OUTB (nc_istat, (istat & SIGP) | INTF | np->istat_sem);
+#ifdef SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM
+		istat = INB (nc_istat);		/* DUMMY READ */
+#endif
 		if (DEBUG_FLAGS & DEBUG_TINY) printk ("F ");
 		(void)ncr_wakeup_done (np);
 #ifdef SCSI_NCR_PROFILE_SUPPORT
@@ -7252,8 +7814,8 @@
 	**	Reset everything.
 	**=========================================================
 	*/
-	if (jiffies - np->regtime > 10*HZ) {
-		np->regtime = jiffies;
+	if (ktime_exp(np->regtime)) {
+		np->regtime = ktime_get(10*HZ);
 		for (i = 0; i<sizeof(np->regdump); i++)
 			((char*)&np->regdump)[i] = INB_OFF(i);
 		np->regdump.nc_dstat = dstat;
@@ -7315,17 +7877,9 @@
 {
 	u_int32	dsp	= INL (nc_dsp);
 	u_int32	dsa	= INL (nc_dsa);
-	u_char	scntl1	= INB (nc_scntl1);
 	ccb_p cp	= ncr_ccb_from_dsa(np, dsa);
 
 	/*
-	**	If we are connected to the SCSI BUS, we only 
-	**	can reset the BUS.
-	*/
-	if (scntl1 & ISCON)
-		goto reset_all;
-
-	/*
 	**	If we haven't been interrupted inside the SCRIPTS 
 	**	critical pathes, we can safely restart the SCRIPTS 
 	**	and trust the DSA value if it matches a CCB.
@@ -7334,6 +7888,8 @@
 	       dsp < NCB_SCRIPT_PHYS (np, getjob_end) + 1)) &&
 	    (!(dsp > NCB_SCRIPT_PHYS (np, ungetjob) &&
 	       dsp < NCB_SCRIPT_PHYS (np, reselect) + 1)) &&
+	    (!(dsp > NCB_SCRIPTH_PHYS (np, sel_for_abort) &&
+	       dsp < NCB_SCRIPTH_PHYS (np, sel_for_abort_1) + 1)) &&
 	    (!(dsp > NCB_SCRIPT_PHYS (np, done) &&
 	       dsp < NCB_SCRIPT_PHYS (np, done_end) + 1))) {
 		if (cp) {
@@ -7377,7 +7933,6 @@
 	if (DEBUG_FLAGS & DEBUG_TINY) printk ("T");
 
 	if (dsp == NCB_SCRIPT_PHYS (np, wf_sel_done) + 8 ||
-	    dsp == NCB_SCRIPTH_PHYS (np, wf_sel_done_no_atn) + 8 ||
 	    !(driver_setup.recovery & 1))
 		ncr_recover_scsi_int(np, HS_SEL_TIMEOUT);
 	else
@@ -7429,7 +7984,7 @@
 	**	Suspend command processing for 1 second and 
 	**	reinitialize all except the chip.
 	*/
-	np->settle_time	= jiffies + HZ;
+	np->settle_time	= ktime_get(1*HZ);
 	ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET);
 }
 
@@ -7455,8 +8010,8 @@
 **	  The chip will then interrupt with both PAR and MA 
 **	  conditions set.
 **
-**	- A phase mismatch occurs before the MOV finished 
-**	  and phase errors are to be handled by SCRIPTS (896).
+**	- A phase mismatch occurs before the MOV finished and 
+**	  phase errors are to be handled by SCRIPTS (895A or 896).
 **	  The chip will load the DSP with the phase mismatch 
 **	  JUMP address and interrupt the host processor.
 **
@@ -7472,6 +8027,7 @@
 	u_char	sbcl	= INB (nc_sbcl);
 	u_char	cmd	= dbc >> 24;
 	int phase	= cmd & 7;
+	ccb_p	cp	= ncr_ccb_from_dsa(np, dsa);
 
 	printk("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n",
 		ncr_name(np), hsts, dbc, sbcl);
@@ -7491,7 +8047,7 @@
 	**	If the nexus is not clearly identified, reset the bus.
 	**	We will try to do better later.
 	*/
-	if (!ncr_ccb_from_dsa(np, dsa))
+	if (!cp)
 		goto reset_all;
 
 	/*
@@ -7504,7 +8060,7 @@
 	/*
 	**	Keep track of the parity error.
 	*/
-	OUTONB (HF_PRT, HF_PAR_ERR);
+	cp->xerr_status |= XE_PARITY_ERR;
 
 	/*
 	**	Prepare the message to send to the device.
@@ -7528,7 +8084,7 @@
 		/* No phase mismatch occurred */
 		else {
 			OUTL (nc_temp, dsp);
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, databreak));
+			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
 		}
 	}
 	else 
@@ -7590,8 +8146,9 @@
 
 	/*
 	**	Donnot take into account dma fifo and various buffers in 
-	**	DATA IN phase since the chip flushes everything before 
+	**	INPUT phase since the chip flushes everything before 
 	**	raising the MA interrupt for interrupted INPUT phases.
+	**	For DATA IN phase, we will check for the SWIDE later.
 	*/
 	if ((cmd & 7) != 1) {
 		u_int32 dfifo;
@@ -7633,7 +8190,7 @@
 		*/
 		OUTB (nc_ctest3, np->rv_ctest3 | CLF);	/* dma fifo  */
 		OUTB (nc_stest3, TE|CSF);		/* scsi fifo */
-	};
+	}
 
 	/*
 	**	log the information
@@ -7732,8 +8289,8 @@
 	**
 	**	Look at the PM_SAVE SCRIPT if you want to understand 
 	**	this stuff. The equivalent code is implemented in 
-	**	SCRIPTS for the 896 that is able to handle PM from 
-	**	the SCRIPTS processor.
+	**	SCRIPTS for the 895A and 896 that are able to handle 
+	**	PM from the SCRIPTS processor.
 	*/
 
 	hflags0 = INB (HF_PRT);
@@ -7770,6 +8327,53 @@
 	pm->sg.size = cpu_to_scr(rest);
 	pm->ret     = cpu_to_scr(nxtdsp);
 
+	/*
+	**	If we have a SWIDE,
+	**	- prepare the address to write the SWIDE from SCRIPTS,
+	**	- compute the SCRIPTS address to restart from,
+	**	- move current data pointer context by one byte.
+	*/
+	nxtdsp = NCB_SCRIPT_PHYS (np, dispatch);
+	if ((cmd & 7) == 1 && cp && (cp->phys.select.sel_scntl3 & EWS) &&
+	    (INB (nc_scntl2) & WSR)) {
+		/*
+		**	Hmmm... The device may want to also ignore 
+		**	this residue but it must send immediately the
+		**	appropriate message. We snoop the SCSI BUS 
+		**	and will just throw away this message from 
+		**	SCRIPTS if the SWIDE is to be ignored.
+		*/
+		if ((INB (nc_sbcl) & 7) == 7 && 
+		    INB (nc_sbdl) == M_IGN_RESIDUE) {
+			nxtdsp = NCB_SCRIPT_PHYS (np, ign_i_w_r_msg);
+		}
+		/*
+		**	We must grab the SWIDE.
+		**	We will use some complex SCRIPTS for that.
+		*/
+		else {
+			OUTL (nc_scratcha, pm->sg.addr);
+			nxtdsp = NCB_SCRIPTH_PHYS (np, swide_ma_32);
+			if (np->features & FE_64BIT) {
+				OUTB (nc_sbr, (pm->sg.size >> 24));
+				nxtdsp = NCB_SCRIPTH_PHYS (np, swide_ma_64);
+			}
+			/*
+			**	Adjust our data pointer context.
+			*/
+			++pm->sg.addr;
+			--pm->sg.size;
+			/*
+			**	Hmmm... Could it be possible that a SWIDE that 
+			**	is followed by a 1 byte CHMOV would lead to 
+			**	a CHMOV(0). Anyway, we handle it by just 
+			**	skipping context that would attempt a CHMOV(0).
+			*/
+			if (!pm->sg.size)
+				newcmd = pm->ret;
+		}
+	}
+
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
 		PRINT_ADDR(cp->cmd);
 		printk ("PM %x %x %x / %x %x %x.\n",
@@ -7780,12 +8384,11 @@
 	}
 
 	/*
-	**	fake the return address (to the patch).
-	**	and restart script processor at dispatcher.
+	**	Restart the SCRIPTS processor.
 	*/
 
 	OUTL (nc_temp, newcmd);
-	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, databreak));
+	OUTL (nc_dsp,  nxtdsp);
 	return;
 
 	/*
@@ -7889,6 +8492,10 @@
 **	requeue the CCB that failed in front of the LUN queue.
 **	I just hope this not to be performed too often. :)
 **
+**	If we are using IMMEDIATE ARBITRATION, we clear the 
+**	IARB hint for every commands we encounter in order not 
+**	to be stuck with a won arbitration and no job to queue 
+**	to a device.
 **----------------------------------------------------------
 */
 
@@ -7896,11 +8503,12 @@
 {
 	Scsi_Cmnd *cmd	= cp->cmd;
 	tcb_p tp	= &np->target[cp->target];
-	lcb_p lp	= tp->lp[cp->lun];
+	lcb_p lp	= ncr_lp(np, tp, cp->lun);
 	ccb_p		cp2;
 	int		busyccbs = 1;
 	u_int32		startp;
 	u_char		s_status = INB (SS_PRT);
+	int		msglen;
 
 	/*
 	**	Remove all CCBs queued to the chip for that LUN and put 
@@ -7923,6 +8531,11 @@
 				continue;
 			if (cp2->target != cp->target || cp2->lun != cp->lun)
 				continue;
+#ifdef SCSI_NCR_IARB_SUPPORT
+			cp2->host_flags &= ~HF_HINT_IARB;
+			if (cp2 == np->last_cp)
+				np->last_cp = 0;
+#endif
 			xpt_remque(&cp2->link_ccbq);
 			xpt_insque_head(&cp2->link_ccbq, &lp->wait_ccbq);
 			--lp->queuedccbs;
@@ -7935,11 +8548,21 @@
 		**	Requeue the interrupted CCB in front of 
 		**	the LUN CCB wait queue.
 		*/
+#ifdef SCSI_NCR_IARB_SUPPORT
+		cp->host_flags &= ~HF_HINT_IARB;
+		if (cp == np->last_cp)
+			np->last_cp = 0;
+#endif
 		xpt_remque(&cp->link_ccbq);
 		xpt_insque_head(&cp->link_ccbq, &lp->wait_ccbq);
 		--lp->queuedccbs;
 		cp->queued = 0;
 
+#ifdef SCSI_NCR_IARB_SUPPORT
+		if (np->last_cp)
+			np->last_cp->host_flags &= ~HF_HINT_IARB;
+#endif
+
 		/*
 		**	Repair the startqueue if necessary.
 		*/
@@ -7992,10 +8615,13 @@
 		/*
 		**	Repair the offending CCB.
 		*/
-		cp->phys.header.savep = cp->startp;
-		cp->host_status = HS_BUSY;
-		cp->scsi_status = S_ILLEGAL;
-		cp->host_flags	&= HF_PM_TO_C;
+		cp->phys.header.savep	= cp->startp;
+		cp->phys.header.lastp	= cp->lastp0;
+		cp->host_status 	= HS_BUSY;
+		cp->scsi_status 	= S_ILLEGAL;
+		cp->xerr_status		= 0;
+		cp->phys.extra_bytes	= 0;
+		cp->host_flags		&= HF_PM_TO_C;
 
 		break;
 
@@ -8004,12 +8630,20 @@
 		/*
 		**	If we were requesting sense, give up.
 		*/
-		if (cp->auto_sense) {
+		if (cp->host_flags & HF_AUTO_SENSE) {
 			ncr_complete(np, cp);
 			break;
 		}
 
 		/*
+		**	Save SCSI status and extended error.
+		**	Compute the data residual now.
+		*/
+		cp->sv_scsi_status = cp->scsi_status;
+		cp->sv_xerr_status = cp->xerr_status;
+		cp->resid = ncr_compute_residual(np, cp);
+
+		/*
 		**	Device returned CHECK CONDITION status.
 		**	Prepare all needed data strutures for getting 
 		**	sense data.
@@ -8019,8 +8653,29 @@
 		**	identify message
 		*/
 		cp->scsi_smsg2[0]	= M_IDENTIFY | cp->lun;
+		msglen = 1;
+
+		/*
+		**	If we are currently using anything different from 
+		**	async. 8 bit data transfers with that target,
+		**	start a negotiation, since the device may want 
+		**	to report us a UNIT ATTENTION condition due to 
+		**	a cause we currently ignore, and we donnot want 
+		**	to be stuck with WIDE and/or SYNC data transfer.
+		**
+		**	cp->nego_status is filled by ncr_prepare_nego().
+		*/
+		ncr_negotiate(np, tp);
+		cp->nego_status = 0;
+		if ((tp->wval & EWS) || (tp->sval & 0x1f))
+			msglen +=
+			    ncr_prepare_nego (np, cp, &cp->scsi_smsg2[msglen]);
+
+		/*
+		**	Message table indirect structure.
+		*/
 		cp->phys.smsg.addr	= cpu_to_scr(CCB_PHYS (cp, scsi_smsg2));
-		cp->phys.smsg.size	= cpu_to_scr(1);
+		cp->phys.smsg.size	= cpu_to_scr(msglen);
 
 		/*
 		**	sense command
@@ -8038,6 +8693,7 @@
 		/*
 		**	sense data
 		*/
+		bzero(cmd->sense_buffer, sizeof(cmd->sense_buffer));
 		cp->phys.sense.addr	=
 				cpu_to_scr(vtobus (&cmd->sense_buffer[0]));
 		cp->phys.sense.size	=
@@ -8046,30 +8702,22 @@
 		/*
 		**	requeue the command.
 		*/
-		startp = cpu_to_scr(NCB_SCRIPTH_PHYS (np, sdata_in));
+		startp = NCB_SCRIPTH_PHYS (np, sdata_in);
 
-		cp->phys.header.savep	= startp;
-		cp->phys.header.goalp	= startp + 24;
-		cp->phys.header.lastp	= startp;
-		cp->phys.header.wgoalp	= startp + 24;
-		cp->phys.header.wlastp	= startp;
+		cp->phys.header.savep	= cpu_to_scr(startp);
+		cp->phys.header.goalp	= cpu_to_scr(startp + 16);
+		cp->phys.header.lastp	= cpu_to_scr(startp);
+		cp->phys.header.wgoalp	= cpu_to_scr(startp + 16);
+		cp->phys.header.wlastp	= cpu_to_scr(startp);
 
-		cp->host_status = HS_BUSY;
+		cp->host_status	= cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
 		cp->scsi_status = S_ILLEGAL;
-		cp->host_flags	= 0;
-		cp->auto_sense	= s_status;
+		cp->host_flags	= HF_AUTO_SENSE;
 
 		cp->phys.header.go.start =
 			cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
 
 		/*
-		**	Select without ATN for quirky devices.
-		*/
-		if (tp->quirks & QUIRK_NOMSG)
-			cp->phys.header.go.start =
-			cpu_to_scr(NCB_SCRIPTH_PHYS (np, select_no_atn));
-
-		/*
 		**	If lp not yet allocated, requeue the command.
 		*/
 		if (!lp)
@@ -8086,107 +8734,755 @@
 	return;
 }
 
-
-/*==========================================================
-**
-**
-**      ncr chip exception handler for programmed interrupts.
-**
+/*----------------------------------------------------------
 **
-**==========================================================
+**	After a device has accepted some management message 
+**	as BUS DEVICE RESET, ABORT TASK, etc ..., or when 
+**	a device signals a UNIT ATTENTION condition, some 
+**	tasks are thrown away by the device. We are required 
+**	to reflect that on our tasks list since the device 
+**	will never complete these tasks.
+**
+**	This function completes all disconnected CCBs for a 
+**	given target that matches the following criteria:
+**	- lun=-1  means any logical UNIT otherwise a given one.
+**	- task=-1 means any task, otherwise a given one.
+**----------------------------------------------------------
 */
-
-static int ncr_show_msg (u_char * msg)
+static int ncr_clear_tasks(ncb_p np, u_char hsts, 
+			   int target, int lun, int task)
 {
-	u_char i;
-	printk ("%x",*msg);
-	if (*msg==M_EXTENDED) {
-		for (i=1;i<8;i++) {
-			if (i-1>msg[1]) break;
-			printk ("-%x",msg[i]);
-		};
-		return (i+1);
-	} else if ((*msg & 0xf0) == 0x20) {
-		printk ("-%x",msg[1]);
-		return (2);
-	};
-	return (1);
-}
+	int i = 0;
+	ccb_p cp;
 
+	for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+		if (cp->host_status != HS_DISCONNECT)
+			continue;
+		if (cp->target != target)
+			continue;
+		if (lun != -1 && cp->lun != lun)
+			continue;
+		if (task != -1 && cp->tag != NO_TAG && cp->scsi_smsg[2] != task)
+			continue;
+		cp->host_status = hsts;
+		cp->scsi_status = S_ILLEGAL;
+		ncr_complete(np, cp);
+		++i;
+	}
+	return i;
+}
 
-void ncr_int_sir (ncb_p np)
+/*==========================================================
+**
+**	ncr chip handler for TASKS recovery.
+**
+**==========================================================
+**
+**	We cannot safely abort a command, while the SCRIPTS 
+**	processor is running, since we just would be in race 
+**	with it.
+**
+**	As long as we have tasks to abort, we keep the SEM 
+**	bit set in the ISTAT. When this bit is set, the 
+**	SCRIPTS processor interrupts (SIR_SCRIPT_STOPPED) 
+**	each time it enters the scheduler.
+**
+**	If we have to reset a target, clear tasks of a unit,
+**	or to perform the abort of a disconnected job, we 
+**	restart the SCRIPTS for selecting the target. Once 
+**	selected, the SCRIPTS interrupts (SIR_TARGET_SELECTED).
+**	If it loses arbitration, the SCRIPTS will interrupt again 
+**	the next time it will enter its scheduler, and so on ...
+**
+**	On SIR_TARGET_SELECTED, we scan for the more 
+**	appropriate thing to do:
+**
+**	- If nothing, we just sent a M_ABORT message to the 
+**	  target to get rid of the useless SCSI bus ownership.
+**	  According to the specs, no tasks shall be affected.
+**	- If the target is to be reset, we send it a M_RESET 
+**	  message.
+**	- If a logical UNIT is to be cleared , we send the 
+**	  IDENTIFY(lun) + M_ABORT.
+**	- If an untagged task is to be aborted, we send the 
+**	  IDENTIFY(lun) + M_ABORT.
+**	- If a tagged task is to be aborted, we send the 
+**	  IDENTIFY(lun) + task attributes + M_ABORT_TAG.
+**
+**	Once our 'kiss of death' :) message has been accepted 
+**	by the target, the SCRIPTS interrupts again 
+**	(SIR_ABORT_SENT). On this interrupt, we complete 
+**	all the CCBs that should have been aborted by the 
+**	target according to our message.
+**	
+**----------------------------------------------------------
+*/
+static void ncr_sir_task_recovery(ncb_p np, int num)
 {
-	u_char scntl3;
-	u_char chg, ofs, per, fak, wide;
-	u_char num = INB (nc_dsps);
-	ccb_p	cp=0;
-	u_long	dsa    = INL (nc_dsa);
-	u_char	target = INB (nc_sdid) & 0x0f;
-	tcb_p	tp     = &np->target[target];
+	ccb_p cp;
+	tcb_p tp;
+	int target=-1, lun=-1, task;
+	int i, k;
+	u_char *p;
 
-	if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
+	switch(num) {
+	/*
+	**	The SCRIPTS processor stopped before starting
+	**	the next command in order to allow us to perform 
+	**	some task recovery.
+	*/
+	case SIR_SCRIPT_STOPPED:
 
-	switch (num) {
-	case SIR_SEL_ATN_NO_MSG_OUT:
 		/*
-		**	The device didn't go to MSG OUT phase after having 
-		**	been selected with ATN. We donnot want to handle 
-		**	that.
+		**	Do we have any target to reset or unit to clear ?
 		*/
-		printk ("%s:%d: No MSG OUT phase after selection with ATN.\n",
-			ncr_name (np), target);
-		goto out_stuck;
-	case SIR_RESEL_NO_MSG_IN:
-	case SIR_RESEL_NO_IDENTIFY:
+		for (i = 0 ; i < MAX_TARGET ; i++) {
+			tp = &np->target[i];
+			if (tp->to_reset || (tp->l0p && tp->l0p->to_clear)) {
+				target = i;
+				break;
+			}
+			if (!tp->lmp)
+				continue;
+			for (k = 1 ; k < MAX_LUN ; k++) {
+				if (tp->lmp[k] && tp->lmp[k]->to_clear) {
+					target	= i;
+					break;
+				}
+			}
+			if (target != -1)
+				break;
+		}
+
 		/*
-		**	If devices reselecting without sending an IDENTIFY 
-		**	message still exist, this should help.
-		**	We just assume lun=0, 1 CCB, no tag.
+		**	If not, look at the CCB list for any 
+		**	disconnected CCB to be aborted.
 		*/
-		if (tp->lp[0]) { 
-			OUTL (nc_dsa, scr_to_cpu(tp->lp[0]->tasktbl[0]));
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, resel_go));
+		if (target == -1) {
+			for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+				if (cp->host_status != HS_DISCONNECT)
+					continue;
+				if (cp->to_abort) {
+					target = cp->target;
+					break;
+				}
+			}
+		}
+
+		/*
+		**	If some target is to be selected, 
+		**	prepare and start the selection.
+		*/
+		if (target != -1) {
+			tp = &np->target[target];
+			np->abrt_sel.sel_id	= target;
+			np->abrt_sel.sel_scntl3 = tp->wval;
+			np->abrt_sel.sel_sxfer  = tp->sval;
+			OUTL(nc_dsa, vtobus(np));
+			OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sel_for_abort));
 			return;
 		}
-	case SIR_RESEL_BAD_LUN:
-		np->msgout[0] = M_RESET;
-		goto out;
-	case SIR_RESEL_BAD_I_T_L:
-		np->msgout[0] = M_ABORT;
-		goto out;
-	case SIR_RESEL_BAD_I_T_L_Q:
-		np->msgout[0] = M_ABORT_TAG;
-		goto out;
-	case SIR_RESEL_ABORTED:
-		np->lastmsg = np->msgout[0];
-		np->msgout[0] = M_NOOP;
-		printk ("%s:%d: message %d sent on bad reselection.\n",
-			ncr_name (np), target, np->lastmsg);
-		goto out;
-	case SIR_MSG_OUT_DONE:
-		np->lastmsg = np->msgout[0];
-		np->msgout[0] = M_NOOP;
-		/* Should we really care of that */
-		if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR)
-			OUTOFFB (HF_PRT, HF_PAR_ERR);
-		goto out;
-	case SIR_BAD_STATUS:
-		cp = ncr_ccb_from_dsa(np, dsa);
-		if (!cp)
-			goto out;
-		ncr_sir_to_redo(np, num, cp);
-		return;
-	default:
+
 		/*
-		**	lookup the ccb
+		**	Nothing is to be selected, so we donnot need 
+		**	to synchronize with the SCRIPTS anymore.
+		**	Remove the SEM flag from the ISTAT.
+		*/
+		np->istat_sem = 0;
+		OUTB (nc_istat, SIGP);
+
+		/*
+		**	Now look at CCBs to abort that haven't started yet.
+		**	Remove all those CCBs from the start queue and 
+		**	complete them with appropriate status.
+		**	Btw, the SCRIPTS processor is still stopped, so 
+		**	we are not in race.
+		*/
+		for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+			if (cp->host_status != HS_BUSY &&
+			    cp->host_status != HS_NEGOTIATE)
+				continue;
+			if (!cp->to_abort)
+				continue;
+#ifdef SCSI_NCR_IARB_SUPPORT
+			/*
+			**    If we are using IMMEDIATE ARBITRATION, we donnot 
+			**    want to cancel the last queued CCB, since the 
+			**    SCRIPTS may have anticipated the selection.
+			*/
+			if (cp == np->last_cp) {
+				cp->to_abort = 0;
+				continue;
+			}
+#endif
+			/*
+			**	Compute index of next position in the start 
+			**	queue the SCRIPTS will schedule.
+			*/
+			i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4;
+
+			/*
+			**	Remove the job from the start queue.
+			*/
+			k = -1;
+			while (1) {
+				if (i == np->squeueput)
+					break;
+				if (k == -1) {		/* Not found yet */
+					if (cp == ncr_ccb_from_dsa(np,
+						     scr_to_cpu(np->squeue[i])))
+						k = i;	/* Found */
+				}
+				else {
+					/*
+					**    Once found, we have to move 
+					**    back all jobs by 1 position.
+					*/
+					np->squeue[k] = np->squeue[i];
+					k += 2;
+					if (k >= MAX_START*2)
+						k = 0;
+				}
+
+				i += 2;
+				if (i >= MAX_START*2)
+					i = 0;
+			}
+			assert(k != -1);
+			if (k != 1) {
+				np->squeue[k] = np->squeue[i]; /* Idle task */
+				cp->host_status = HS_ABORTED;
+				cp->scsi_status = S_ILLEGAL;
+				ncr_complete(np, cp);
+			}
+		}
+		break;
+	/*
+	**	The SCRIPTS processor has selected a target 
+	**	we may have some manual recovery to perform for.
+	*/
+	case SIR_TARGET_SELECTED:
+		target = (INB (nc_sdid) & 0xf);
+		tp = &np->target[target];
+
+		np->abrt_tbl.addr = vtobus(np->abrt_msg);
+
+		/*
+		**	If the target is to be reset, prepare a 
+		**	M_RESET message and clear the to_reset flag 
+		**	since we donnot expect this operation to fail.
 		*/
-		cp = ncr_ccb_from_dsa(np, dsa);
-		if (!cp)
-			goto out;
+		if (tp->to_reset) {
+			np->abrt_msg[0] = M_RESET;
+			np->abrt_tbl.size = 1;
+			tp->to_reset = 0;
+			break;
+		}
+
+		/*
+		**	Otherwise, look for some logical unit to be cleared.
+		*/
+		if (tp->l0p && tp->l0p->to_clear)
+			lun = 0;
+		else if (tp->lmp) {
+			for (k = 1 ; k < MAX_LUN ; k++) {
+				if (tp->lmp[k] && tp->lmp[k]->to_clear) {
+					lun = k;
+					break;
+				}
+			}
+		}
+
+		/*
+		**	If a logical unit is to be cleared, prepare 
+		**	an IDENTIFY(lun) + ABORT MESSAGE.
+		*/
+		if (lun != -1) {
+			lcb_p lp = ncr_lp(np, tp, lun);
+			lp->to_clear = 0; /* We donnot expect to fail here */
+			np->abrt_msg[0] = M_IDENTIFY | lun;
+			np->abrt_msg[1] = M_ABORT;
+			np->abrt_tbl.size = 2;
+			break;
+		}
+
+		/*
+		**	Otherwise, look for some disconnected job to 
+		**	abort for this target.
+		*/
+		for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+			if (cp->host_status != HS_DISCONNECT)
+				continue;
+			if (cp->target != target)
+				continue;
+			if (cp->to_abort)
+				break;
+		}
+
+		/*
+		**	If we have none, probably since the device has 
+		**	completed the command before we won abitration,
+		**	send a M_ABORT message without IDENTIFY.
+		**	According to the specs, the device must just 
+		**	disconnect the BUS and not abort any task.
+		*/
+		if (!cp) {
+			np->abrt_msg[0] = M_ABORT;
+			np->abrt_tbl.size = 1;
+			break;
+		}
+
+		/*
+		**	We have some task to abort.
+		**	Set the IDENTIFY(lun)
+		*/
+		np->abrt_msg[0] = M_IDENTIFY | cp->lun;
+
+		/*
+		**	If we want to abort an untagged command, we 
+		**	will send a IDENTIFY + M_ABORT.
+		**	Otherwise (tagged command), we will send 
+		**	a IDENTITFY + task attributes + ABORT TAG.
+		*/
+		if (cp->tag == NO_TAG) {
+			np->abrt_msg[1] = M_ABORT;
+			np->abrt_tbl.size = 2;
+		}
+		else {
+			np->abrt_msg[1] = cp->scsi_smsg[1];
+			np->abrt_msg[2] = cp->scsi_smsg[2];
+			np->abrt_msg[3] = M_ABORT_TAG;
+			np->abrt_tbl.size = 4;
+		}
+		cp->to_abort = 0; /* We donnot expect to fail here */
+		break;
+
+	/*
+	**	The target has accepted our message and switched 
+	**	to BUS FREE phase as we expected.
+	*/
+	case SIR_ABORT_SENT:
+		target = (INB (nc_sdid) & 0xf);
+		tp = &np->target[target];
+		
+		/*
+		**	If we didn't abort anything, leave here.
+		*/
+		if (np->abrt_msg[0] == M_ABORT)
+			break;
+
+		/*
+		**	If we sent a M_RESET, then a hardware reset has 
+		**	been performed by the target.
+		**	- Reset everything to async 8 bit
+		**	- Tell ourself to negotiate next time :-)
+		**	- Prepare to clear all disconnected CCBs for 
+		**	  this target from our task list (lun=task=-1)
+		*/
+		lun = -1;
+		task = -1;
+		if (np->abrt_msg[0] == M_RESET) {
+			tp->sval = 0;
+			tp->wval = np->rv_scntl3;
+			ncr_set_sync_wide_status(np, target);
+			ncr_negotiate(np, tp);
+		}
+
+		/*
+		**	Otherwise, check for the LUN and TASK(s) 
+		**	concerned by the cancelation.
+		**	If it is not ABORT_TAG then it is CLEAR_QUEUE 
+		**	or an ABORT message :-)
+		*/
+		else {
+			lun = np->abrt_msg[0] & 0x3f;
+			if (np->abrt_msg[1] == M_ABORT_TAG)
+				task = np->abrt_msg[2];
+		}
+
+		/*
+		**	Complete all the CCBs the device should have 
+		**	aborted due to our 'kiss of death' message.
+		*/
+		(void) ncr_clear_tasks(np, HS_ABORTED, target, lun, task);
+		break;
+
+	/*
+	**	We have performed a auto-sense that succeeded.
+	**	If the device reports a UNIT ATTENTION condition 
+	**	due to a RESET condition, we must complete all 
+	**	disconnect CCBs for this unit since the device 
+	**	shall have thrown them away.
+	**	Since I haven't time to guess what the specs are 
+	**	expecting for other UNIT ATTENTION conditions, I 
+	**	decided to only care about RESET conditions. :)
+	*/
+	case SIR_AUTO_SENSE_DONE:
+		cp = ncr_ccb_from_dsa(np, INL (nc_dsa));
+		p  = &cp->cmd->sense_buffer[0];
+
+		if (p[0] != 0x70 || p[2] != 0x6 || p[12] != 0x29)
+			break;
+		(void) ncr_clear_tasks(np, HS_RESET, cp->target, cp->lun, -1);
+		break;
+	}
+
+	/*
+	**	Print to the log the message we intend to send.
+	*/
+	if (num == SIR_TARGET_SELECTED) {
+		PRINT_TARGET(np, target);
+		ncr_printl_hex("control msgout:", np->abrt_msg,
+			      np->abrt_tbl.size);
+		np->abrt_tbl.size = cpu_to_scr(np->abrt_tbl.size);
+	}
+
+	/*
+	**	Let the SCRIPTS processor continue.
+	*/
+	OUTONB (nc_dcntl, (STD|NOCOM));
+}
+
+
+/*==========================================================
+**
+**	Gérard's alchemy:) that deals with with the data 
+**	pointer for both MDP and the residual calculation.
+**
+**==========================================================
+**
+**	I didn't want to bloat the code by more than 200 
+**	lignes for the handling of both MDP and the residual.
+**	This has been achieved by using a data pointer 
+**	representation consisting in an index in the data 
+**	array (dp_sg) and a negative offset (dp_ofs) that 
+**	have the following meaning:
+**
+**	- dp_sg = MAX_SCATTER
+**	  we are at the end of the data script.
+**	- dp_sg < MAX_SCATTER
+**	  dp_sg points to the next entry of the scatter array 
+**	  we want to transfer.
+**	- dp_ofs < 0
+**	  dp_ofs represents the residual of bytes of the 
+**	  previous entry scatter entry we will send first.
+**	- dp_ofs = 0
+**	  no residual to send first.
+**
+**	The function ncr_evaluate_dp() accepts an arbitray 
+**	offset (basically from the MDP message) and returns 
+**	the corresponding values of dp_sg and dp_ofs.
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_evaluate_dp(ncb_p np, ccb_p cp, u_int32 scr, int *ofs)
+{
+	u_int32	dp_scr;
+	int	dp_ofs, dp_sg, dp_sgmin;
+	int	tmp;
+	struct pm_ctx *pm;
+
+	/*
+	**	Compute the resulted data pointer in term of a script 
+	**	address within some DATA script and a signed byte offset.
+	*/
+	dp_scr = scr;
+	dp_ofs = *ofs;
+	if	(dp_scr == NCB_SCRIPT_PHYS (np, pm0_data))
+		pm = &cp->phys.pm0;
+	else if (dp_scr == NCB_SCRIPT_PHYS (np, pm1_data))
+		pm = &cp->phys.pm1;
+	else
+		pm = 0;
+
+	if (pm) {
+		dp_scr  = pm->ret;
+		dp_ofs -= pm->sg.size;
+	}
+
+	/*
+	**	Deduce the index of the sg entry.
+	**	Keep track of the index of the first valid entry.
+	**	If result is dp_sg = MAX_SCATTER, then we are at the 
+	**	end of the data.
+	*/
+	tmp = scr_to_cpu(cp->phys.header.goalp);
+	dp_sg = MAX_SCATTER - (tmp - 8 - (int)dp_scr) / (SCR_SG_SIZE*4);
+	dp_sgmin = MAX_SCATTER - cp->segments;
+
+	/*
+	**	Move to the sg entry the data pointer belongs to.
+	**
+	**	If we are inside the data area, we expect result to be:
+	**
+	**	Either,
+	**	    dp_ofs = 0 and dp_sg is the index of the sg entry
+	**	    the data pointer belongs to (or the end of the data)
+	**	Or,
+	**	    dp_ofs < 0 and dp_sg is the index of the sg entry 
+	**	    the data pointer belongs to + 1.
+	*/
+	if (dp_ofs < 0) {
+		int n;
+		while (dp_sg > dp_sgmin) {
+			--dp_sg;
+			tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+			n = dp_ofs + (tmp & 0xffffff);
+			if (n > 0) {
+				++dp_sg;
+				break;
+			}
+			dp_ofs = n;
+		}
+	}
+	else if (dp_ofs > 0) {
+		while (dp_sg < MAX_SCATTER) {
+			++dp_sg;
+			tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+			dp_ofs -= (tmp & 0xffffff);
+			if (dp_ofs <= 0)
+				break;
+		}
+	}
+
+	/*
+	**	Make sure the data pointer is inside the data area.
+	**	If not, return some error.
+	*/
+	if	(dp_sg < dp_sgmin || (dp_sg == dp_sgmin && dp_ofs < 0))
+		goto out_err;
+	else if	(dp_sg > MAX_SCATTER || (dp_sg == MAX_SCATTER && dp_ofs > 0))
+		goto out_err;
+
+	/*
+	**	Save the extreme pointer if needed.
+	*/
+	if (dp_sg > cp->ext_sg ||
+            (dp_sg == cp->ext_sg && dp_ofs < cp->ext_ofs)) {
+		cp->ext_sg  = dp_sg;
+		cp->ext_ofs = dp_ofs;
+	}
+
+	/*
+	**	Return data.
+	*/
+	*ofs = dp_ofs;
+	return dp_sg;
+
+out_err:
+	return -1;
+}
+
+/*==========================================================
+**
+**	ncr chip handler for MODIFY DATA POINTER MESSAGE
+**
+**==========================================================
+**
+**	We also call this function on IGNORE WIDE RESIDUE 
+**	messages that do not match a SWIDE full condition.
+**	Btw, we assume in that situation that such a message 
+**	is equivalent to a MODIFY DATA POINTER (offset=-1).
+**
+**----------------------------------------------------------
+*/
+
+static void ncr_modify_dp(ncb_p np, tcb_p tp, ccb_p cp, int ofs)
+{
+	int dp_ofs	= ofs;
+	u_int32 dp_scr	= INL (nc_temp);
+	u_int32	dp_ret;
+	u_char	hflags;
+	int	dp_sg;
+	struct pm_ctx *pm;
+
+	/*
+	**	Not supported for auto_sense;
+	*/
+	if (cp->host_flags & HF_AUTO_SENSE)
+		goto out_reject;
+
+	/*
+	**	Apply our alchemy:) (see comments in ncr_evaluate_dp()), 
+	**	to the resulted data pointer.
+	*/
+	dp_sg = ncr_evaluate_dp(np, cp, dp_scr, &dp_ofs);
+	if (dp_sg < 0)
+		goto out_reject;
+
+	/*
+	**	And our alchemy:) allows to easily calculate the data 
+	**	script address we want to return for the next data phase.
+	*/
+	dp_ret = cpu_to_scr(cp->phys.header.goalp);
+	dp_ret = dp_ret - 8 - (MAX_SCATTER - dp_sg) * (SCR_SG_SIZE*4);
+
+	/*
+	**	If offset / scatter entry is zero we donnot need 
+	**	a context for the new current data pointer.
+	*/
+	if (dp_ofs == 0) {
+		dp_scr = dp_ret;
+		goto out_ok;
+	}
+
+	/*
+	**	Get a context for the new current data pointer.
+	*/
+	hflags = INB (HF_PRT);
+
+	if (hflags & HF_DP_SAVED)
+		hflags ^= HF_ACT_PM;
+
+	if (!(hflags & HF_ACT_PM)) {
+		pm  = &cp->phys.pm0;
+		dp_scr = NCB_SCRIPT_PHYS (np, pm0_data);
+	}
+	else {
+		pm = &cp->phys.pm1;
+		dp_scr = NCB_SCRIPT_PHYS (np, pm1_data);
+	}
+
+	hflags &= ~(HF_DP_SAVED);
+
+	OUTB (HF_PRT, hflags);
+
+	/*
+	**	Set up the new current data pointer.
+	**	ofs < 0 there, and for the next data phase, we 
+	**	want to transfer part of the data of the sg entry 
+	**	corresponding to index dp_sg-1 prior to returning 
+	**	to the main data script.
+	*/
+	pm->ret = cpu_to_scr(dp_ret);
+	pm->sg.addr = cp->phys.data[dp_sg-1].addr + dp_ofs;
+	pm->sg.size = cp->phys.data[dp_sg-1].size - dp_ofs;
+
+out_ok:
+	OUTL (nc_temp, dp_scr);
+	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+	return;
+
+out_reject:
+	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+}
+
+
+/*==========================================================
+**
+**	ncr chip calculation of the data residual.
+**
+**==========================================================
+**
+**	As I used to say, the requirement of data residual 
+**	in SCSI is broken, useless and cannot be achieved 
+**	without huge complexity.
+**	But most OSes and even the official CAM require it.
+**	When stupidity happens to be so widely spread inside 
+**	a community, it gets hard to convince.
+**
+**	Anyway, I don't care, since I am not going to use 
+**	any software that considers this data residual as 
+**	a relevant information. :)
+**	
+**----------------------------------------------------------
+*/
+
+static int ncr_compute_residual(ncb_p np, ccb_p cp)
+{
+	int dp_sg, dp_sgmin, resid, tmp;
+	int dp_ofs = 0;
+
+	/*
+	**	Should have been checked by the caller.
+	*/
+	if (cp->phys.header.lastp == cp->phys.header.goalp)
+		return 0;
+
+	/*
+	**	If the last data pointer is data_io (direction 
+	**	unknown), then no data transfer should have 
+	**	taken place.
+	*/
+	if (cp->phys.header.lastp == NCB_SCRIPTH_PHYS (np, data_io))
+		return -cp->data_len;
+
+	/*
+	**	If the device asked for more data than available, 
+	**	return a positive residual value.
+	*/
+	if (cp->phys.extra_bytes)
+		return scr_to_cpu(cp->phys.extra_bytes);
+
+	/*
+	**	Evaluate the pointer saved on message COMPLETE.
+	**	According to our alchemy:), the extreme data 
+	**	pointer will also be updated if needed.
+	**	On error, assume no data transferred (this may 
+	**	happen if the data direction is unknown).
+	*/
+	tmp = cpu_to_scr(cp->phys.header.lastp);
+	if (ncr_evaluate_dp(np, cp, tmp, &dp_ofs) < 0)
+		return -cp->data_len;
+
+	/*
+	**	We are now full comfortable in the computation 
+	**	of the data residual (2's complement).
+	*/
+	dp_sgmin = MAX_SCATTER - cp->segments;
+	resid = cp->ext_ofs;
+	for (dp_sg = cp->ext_sg; dp_sg < MAX_SCATTER; ++dp_sg) {
+		tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+		resid -= (tmp & 0xffffff);
 	}
 
-	switch (num) {
-/*-----------------------------------------------------------------------------
+	/*
+	**	Hopefully, the result is not too wrong.
+	*/
+	return resid;
+}
+
+/*==========================================================
+**
+**	Print out the containt of a SCSI message.
+**
+**==========================================================
+*/
+
+static int ncr_show_msg (u_char * msg)
+{
+	u_char i;
+	printk ("%x",*msg);
+	if (*msg==M_EXTENDED) {
+		for (i=1;i<8;i++) {
+			if (i-1>msg[1]) break;
+			printk ("-%x",msg[i]);
+		};
+		return (i+1);
+	} else if ((*msg & 0xf0) == 0x20) {
+		printk ("-%x",msg[1]);
+		return (2);
+	};
+	return (1);
+}
+
+static void ncr_print_msg (ccb_p cp, char *label, u_char *msg)
+{
+	if (cp)
+		PRINT_ADDR(cp->cmd);
+	if (label)
+		printk ("%s: ", label);
+
+	(void) ncr_show_msg (msg);
+	printk (".\n");
+}
+
+/*===================================================================
+**
+**	Negotiation for WIDE and SYNCHRONOUS DATA TRANSFER.
+**
+**===================================================================
 **
 **	Was Sie schon immer ueber transfermode negotiation wissen wollten ...
 **
@@ -8199,8 +9495,8 @@
 **	The host status field is set to HS_NEGOTIATE to mark this
 **	situation.
 **
-**	If the target doesn't answer this message immidiately
-**	(as required by the standard), the SIR_NEGO_FAIL interrupt
+**	If the target doesn't answer this message immediately
+**	(as required by the standard), the SIR_NEGO_FAILED interrupt
 **	will be raised eventually.
 **	The handler removes the HS_NEGOTIATE status, and sets the
 **	negotiated value to the default (async / nowide).
@@ -8218,375 +9514,532 @@
 **
 **	If the target doesn't fetch the answer (no message out phase),
 **	we assume the negotiation has failed, and fall back to default
-**	settings.
+**	settings (SIR_NEGO_PROTO interrupt).
 **
 **	When we set the values, we adjust them in all ccbs belonging 
 **	to this target, in the controller's register, and in the "phys"
 **	field of the controller's struct ncb.
 **
-**	Possible cases:		   hs  sir   msg_in value  send   goto
-**	We try to negotiate:
-**	-> target doesnt't msgin   NEG FAIL  noop   defa.  -      dispatch
-**	-> target rejected our msg NEG FAIL  reject defa.  -      dispatch
-**	-> target answered  (ok)   NEG SYNC  sdtr   set    -      clrack
-**	-> target answered (!ok)   NEG SYNC  sdtr   defa.  REJ--->msg_bad
-**	-> target answered  (ok)   NEG WIDE  wdtr   set    -      clrack
-**	-> target answered (!ok)   NEG WIDE  wdtr   defa.  REJ--->msg_bad
-**	-> any other msgin	   NEG FAIL  noop   defa.  -      dispatch
-**
-**	Target tries to negotiate:
-**	-> incoming message	   --- SYNC  sdtr   set    SDTR   -
-**	-> incoming message	   --- WIDE  wdtr   set    WDTR   -
-**      We sent our answer:
-**	-> target doesn't msgout   --- PROTO ?      defa.  -      dispatch
-**
-**-----------------------------------------------------------------------------
+**---------------------------------------------------------------------
 */
 
-	case SIR_NEGO_FAILED:
-		/*-------------------------------------------------------
-		**
-		**	Negotiation failed.
-		**	Target doesn't send an answer message,
-		**	or target rejected our message.
-		**
-		**      Remove negotiation request.
-		**
-		**-------------------------------------------------------
-		*/
-		OUTB (HS_PRT, HS_BUSY);
-
-		/* fall through */
-
-	case SIR_NEGO_PROTO:
-		/*-------------------------------------------------------
-		**
-		**	Negotiation failed.
-		**	Target doesn't fetch the answer message.
-		**
-		**-------------------------------------------------------
-		*/
-
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("negotiation failed sir=%x status=%x.\n",
-				num, cp->nego_status);
-		};
-
-		/*
-		**	any error in negotiation:
-		**	fall back to default mode.
-		*/
-		switch (cp->nego_status) {
-
-		case NS_SYNC:
-			ncr_setsync (np, cp, 0, 0xe0);
-			break;
-
-		case NS_WIDE:
-			ncr_setwide (np, cp, 0, 0);
-			break;
-
-		};
-		np->msgin [0] = M_NOOP;
-		np->msgout[0] = M_NOOP;
-		cp->nego_status = 0;
-		break;
+/*==========================================================
+**
+**	ncr chip handler for SYNCHRONOUS DATA TRANSFER 
+**	REQUEST (SDTR) message.
+**
+**==========================================================
+**
+**	Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_sync_nego(ncb_p np, tcb_p tp, ccb_p cp)
+{
+	u_char	scntl3;
+	u_char	chg, ofs, per, fak;
 
-	case SIR_NEGO_SYNC:
-		/*
-		**	Synchronous request message received.
-		*/
+	/*
+	**	Synchronous request message received.
+	*/
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgin: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
-		};
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "sync msg in", np->msgin);
+	};
 
-		/*
-		**	get requested values.
-		*/
+	/*
+	**	get requested values.
+	*/
 
-		chg = 0;
-		per = np->msgin[3];
-		ofs = np->msgin[4];
-		if (ofs==0) per=255;
+	chg = 0;
+	per = np->msgin[3];
+	ofs = np->msgin[4];
+	if (ofs==0) per=255;
 
-		/*
-		**      if target sends SDTR message,
-		**	      it CAN transfer synch.
-		*/
+	/*
+	**      if target sends SDTR message,
+	**	      it CAN transfer synch.
+	*/
 
-		if (ofs)
-			tp->inq_byte7 |= INQ7_SYNC;
+	if (ofs)
+		tp->inq_byte7 |= INQ7_SYNC;
 
-		/*
-		**	check values against driver limits.
-		*/
+	/*
+	**	check values against driver limits.
+	*/
 
-		if (per < np->minsync)
-			{chg = 1; per = np->minsync;}
-		if (per < tp->minsync)
-			{chg = 1; per = tp->minsync;}
-		if (ofs > tp->maxoffs)
-			{chg = 1; ofs = tp->maxoffs;}
+	if (per < np->minsync)
+		{chg = 1; per = np->minsync;}
+	if (per < tp->minsync)
+		{chg = 1; per = tp->minsync;}
+	if (ofs > tp->maxoffs)
+		{chg = 1; ofs = tp->maxoffs;}
 
-		/*
-		**	Check against controller limits.
-		*/
+	/*
+	**	Check against controller limits.
+	*/
+	fak	= 7;
+	scntl3	= 0;
+	if (ofs != 0) {
+		ncr_getsync(np, per, &fak, &scntl3);
+		if (fak > 7) {
+			chg = 1;
+			ofs = 0;
+		}
+	}
+	if (ofs == 0) {
 		fak	= 7;
+		per	= 0;
 		scntl3	= 0;
-		if (ofs != 0) {
-			ncr_getsync(np, per, &fak, &scntl3);
-			if (fak > 7) {
-				chg = 1;
-				ofs = 0;
-			}
-		}
-		if (ofs == 0) {
-			fak	= 7;
-			per	= 0;
-			scntl3	= 0;
-			tp->minsync = 0;
-		}
-
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
-				per, scntl3, ofs, fak, chg);
-		}
+		tp->minsync = 0;
+	}
 
-		if (INB (HS_PRT) == HS_NEGOTIATE) {
-			OUTB (HS_PRT, HS_BUSY);
-			switch (cp->nego_status) {
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		PRINT_ADDR(cp->cmd);
+		printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
+			per, scntl3, ofs, fak, chg);
+	}
 
-			case NS_SYNC:
+	if (INB (HS_PRT) == HS_NEGOTIATE) {
+		OUTB (HS_PRT, HS_BUSY);
+		switch (cp->nego_status) {
+		case NS_SYNC:
+			/*
+			**      This was an answer message
+			*/
+			if (chg) {
 				/*
-				**      This was an answer message
+				**	Answer wasn't acceptable.
 				*/
-				if (chg) {
-					/*
-					**	Answer wasn't acceptable.
-					*/
-					ncr_setsync (np, cp, 0, 0xe0);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
-				} else {
-					/*
-					**	Answer is ok.
-					*/
-					ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
-				};
-				return;
-
-			case NS_WIDE:
-				ncr_setwide (np, cp, 0, 0);
-				break;
+				ncr_setsync (np, cp, 0, 0xe0);
+				OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+			} else {
+				/*
+				**	Answer is ok.
+				*/
+				ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+				OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
 			};
+			return;
+
+		case NS_WIDE:
+			ncr_setwide (np, cp, 0, 0);
+			break;
 		};
+	};
 
-		/*
-		**	It was a request. Set value and
-		**      prepare an answer message
-		*/
+	/*
+	**	It was a request. Set value and
+	**      prepare an answer message
+	*/
 
-		ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+	ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
 
-		np->msgout[0] = M_EXTENDED;
-		np->msgout[1] = 3;
-		np->msgout[2] = M_X_SYNC_REQ;
-		np->msgout[3] = per;
-		np->msgout[4] = ofs;
+	np->msgout[0] = M_EXTENDED;
+	np->msgout[1] = 3;
+	np->msgout[2] = M_X_SYNC_REQ;
+	np->msgout[3] = per;
+	np->msgout[4] = ofs;
 
-		cp->nego_status = NS_SYNC;
+	cp->nego_status = NS_SYNC;
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgout: ");
-			(void) ncr_show_msg (np->msgout);
-			printk (".\n");
-		}
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "sync msgout", np->msgout);
+	}
 
-		if (!ofs) {
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
-			return;
-		}
-		np->msgin [0] = M_NOOP;
+	np->msgin [0] = M_NOOP;
 
-		break;
+	if (!ofs)
+		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+	else
+		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sdtr_resp));
+}
 
-	case SIR_NEGO_WIDE:
-		/*
-		**	Wide request message received.
-		*/
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide msgin: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
-		};
+/*==========================================================
+**
+**	ncr chip handler for WIDE DATA TRANSFER REQUEST 
+**	(WDTR) message.
+**
+**==========================================================
+**
+**	Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_wide_nego(ncb_p np, tcb_p tp, ccb_p cp)
+{
+	u_char	chg, wide;
 
-		/*
-		**	get requested values.
-		*/
+	/*
+	**	Wide request message received.
+	*/
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "wide msgin", np->msgin);
+	};
 
-		chg  = 0;
-		wide = np->msgin[3];
+	/*
+	**	get requested values.
+	*/
 
-		/*
-		**      if target sends WDTR message,
-		**	      it CAN transfer wide.
-		*/
+	chg  = 0;
+	wide = np->msgin[3];
 
-		if (wide)
-			tp->inq_byte7 |= INQ7_WIDE16;
+	/*
+	**      if target sends WDTR message,
+	**	      it CAN transfer wide.
+	*/
 
-		/*
-		**	check values against driver limits.
-		*/
+	if (wide)
+		tp->inq_byte7 |= INQ7_WIDE16;
 
-		if (wide > tp->usrwide)
-			{chg = 1; wide = tp->usrwide;}
+	/*
+	**	check values against driver limits.
+	*/
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide: wide=%d chg=%d.\n", wide, chg);
-		}
+	if (wide > tp->usrwide)
+		{chg = 1; wide = tp->usrwide;}
 
-		if (INB (HS_PRT) == HS_NEGOTIATE) {
-			OUTB (HS_PRT, HS_BUSY);
-			switch (cp->nego_status) {
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		PRINT_ADDR(cp->cmd);
+		printk ("wide: wide=%d chg=%d.\n", wide, chg);
+	}
 
-			case NS_WIDE:
+	if (INB (HS_PRT) == HS_NEGOTIATE) {
+		OUTB (HS_PRT, HS_BUSY);
+		switch (cp->nego_status) {
+		case NS_WIDE:
+			/*
+			**      This was an answer message
+			*/
+			if (chg) {
 				/*
-				**      This was an answer message
+				**	Answer wasn't acceptable.
 				*/
-				if (chg) {
-					/*
-					**	Answer wasn't acceptable.
-					*/
-					ncr_setwide (np, cp, 0, 1);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
-				} else {
-					/*
-					**	Answer is ok.
-					*/
-					ncr_setwide (np, cp, wide, 1);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
-				};
-				return;
-
-			case NS_SYNC:
-				ncr_setsync (np, cp, 0, 0xe0);
-				break;
+				ncr_setwide (np, cp, 0, 1);
+				OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+			} else {
+				/*
+				**	Answer is ok.
+				*/
+				ncr_setwide (np, cp, wide, 1);
+				OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
 			};
+			return;
+
+		case NS_SYNC:
+			ncr_setsync (np, cp, 0, 0xe0);
+			break;
 		};
+	};
 
-		/*
-		**	It was a request, set value and
-		**      prepare an answer message
-		*/
+	/*
+	**	It was a request, set value and
+	**      prepare an answer message
+	*/
 
-		ncr_setwide (np, cp, wide, 1);
+	ncr_setwide (np, cp, wide, 1);
 
-		np->msgout[0] = M_EXTENDED;
-		np->msgout[1] = 2;
-		np->msgout[2] = M_X_WIDE_REQ;
-		np->msgout[3] = wide;
+	np->msgout[0] = M_EXTENDED;
+	np->msgout[1] = 2;
+	np->msgout[2] = M_X_WIDE_REQ;
+	np->msgout[3] = wide;
 
-		np->msgin [0] = M_NOOP;
+	np->msgin [0] = M_NOOP;
 
-		cp->nego_status = NS_WIDE;
+	cp->nego_status = NS_WIDE;
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide msgout: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
-		}
-		break;
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "wide msgout", np->msgout);
+	}
 
-/*--------------------------------------------------------------------
-**
-**	Processing of special messages
-**
-**--------------------------------------------------------------------
+	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, wdtr_resp));
+}
+
+/*
+**	Reset SYNC or WIDE to default settings.
+**	Called when a negotiation does not succeed either 
+**	on rejection or on protocol error.
 */
+static void ncr_nego_default(ncb_p np, tcb_p tp, ccb_p cp)
+{
+	/*
+	**	any error in negotiation:
+	**	fall back to default mode.
+	*/
+	switch (cp->nego_status) {
 
-	case SIR_REJECT_RECEIVED:
-		/*-----------------------------------------------
-		**
-		**	We received a M_REJECT message.
-		**
-		**-----------------------------------------------
-		*/
+	case NS_SYNC:
+		ncr_setsync (np, cp, 0, 0xe0);
+		break;
 
-		PRINT_ADDR(cp->cmd);
-		printk ("M_REJECT received (%x:%x).\n",
-			(unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]);
+	case NS_WIDE:
+		ncr_setwide (np, cp, 0, 0);
 		break;
 
-	case SIR_REJECT_TO_SEND:
-		/*-----------------------------------------------
-		**
-		**	We received an unknown message
-		**
-		**-----------------------------------------------
-		*/
+	};
+	np->msgin [0] = M_NOOP;
+	np->msgout[0] = M_NOOP;
+	cp->nego_status = 0;
+}
+
+/*==========================================================
+**
+**	ncr chip handler for MESSAGE REJECT received for 
+**	a WIDE or SYNCHRONOUS negotiation.
+**
+**==========================================================
+**
+**	Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_nego_rejected(ncb_p np, tcb_p tp, ccb_p cp)
+{
+	ncr_nego_default(np, tp, cp);
+	OUTB (HS_PRT, HS_BUSY);
+}
 
-		PRINT_ADDR(cp->cmd);
-		printk ("M_REJECT to send for ");
-		(void) ncr_show_msg (np->msgin);
-		printk (".\n");
-		np->msgout[0] = M_REJECT;
-		break;
 
-/*--------------------------------------------------------------------
+/*==========================================================
+**
+**
+**      ncr chip exception handler for programmed interrupts.
 **
-**	Processing of special messages
 **
-**--------------------------------------------------------------------
+**==========================================================
 */
 
-	case SIR_IGN_RESIDUE:
-		/*-----------------------------------------------
-		**
-		**	We received an IGNORE RESIDUE message,
-		**	which couldn't be handled by the script.
-		**
-		**-----------------------------------------------
-		*/
+void ncr_int_sir (ncb_p np)
+{
+	u_char	num	= INB (nc_dsps);
+	u_long	dsa	= INL (nc_dsa);
+	ccb_p	cp	= ncr_ccb_from_dsa(np, dsa);
+	u_char	target	= INB (nc_sdid) & 0x0f;
+	tcb_p	tp	= &np->target[target];
+	int	tmp;
 
-		PRINT_ADDR(cp->cmd);
-		printk ("M_IGN_RESIDUE received, but not yet implemented.\n");
-		break;
-#if 0
-	case SIR_MISSING_SAVE:
-		/*-----------------------------------------------
-		**
-		**	We received an DISCONNECT message,
-		**	but the datapointer wasn't saved before.
-		**
-		**-----------------------------------------------
-		*/
+	if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
 
-		PRINT_ADDR(cp->cmd);
-		printk ("M_DISCONNECT received, but datapointer not saved: "
-			"data=%x save=%x goal=%x.\n",
-			(unsigned) INL (nc_temp),
-			(unsigned) scr_to_cpu(np->header.savep),
-			(unsigned) scr_to_cpu(np->header.goalp));
-		break;
+	switch (num) {
+	/*
+	**	See comments in the SCRIPTS code.
+	*/
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+	case SIR_DUMMY_INTERRUPT:
+		goto out;
 #endif
+	/*
+	**	The C code is currently trying to recover from something.
+	**	Typically, user want to abort some command.
+	*/
+	case SIR_SCRIPT_STOPPED:
+	case SIR_TARGET_SELECTED:
+	case SIR_ABORT_SENT:
+		ncr_sir_task_recovery(np, num);
+		return;
+	/*
+	**	The device didn't go to MSG OUT phase after having 
+	**	been selected with ATN. We donnot want to handle 
+	**	that.
+	*/
+	case SIR_SEL_ATN_NO_MSG_OUT:
+		printk ("%s:%d: No MSG OUT phase after selection with ATN.\n",
+			ncr_name (np), target);
+		goto out_stuck;
+	/*
+	**	The device didn't switch to MSG IN phase after 
+	**	having reseleted the initiator.
+	*/
+	case SIR_RESEL_NO_MSG_IN:
+	/*
+	**	After reselection, the device sent a message that wasn't 
+	**	an IDENTIFY.
+	*/
+	case SIR_RESEL_NO_IDENTIFY:
+		/*
+		**	If devices reselecting without sending an IDENTIFY 
+		**	message still exist, this should help.
+		**	We just assume lun=0, 1 CCB, no tag.
+		*/
+		if (tp->l0p) { 
+			OUTL (nc_dsa, scr_to_cpu(tp->l0p->tasktbl[0]));
+			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, resel_go));
+			return;
+		}
+	/*
+	**	The device reselected a LUN we donnot know of.
+	*/
+	case SIR_RESEL_BAD_LUN:
+		np->msgout[0] = M_RESET;
+		goto out;
+	/*
+	**	The device reselected for an untagged nexus and we 
+	**	haven't any.
+	*/
+	case SIR_RESEL_BAD_I_T_L:
+		np->msgout[0] = M_ABORT;
+		goto out;
+	/*
+	**	The device reselected for a tagged nexus that we donnot 
+	**	have.
+	*/
+	case SIR_RESEL_BAD_I_T_L_Q:
+		np->msgout[0] = M_ABORT_TAG;
+		goto out;
+	/*
+	**	The SCRIPTS let us know that the device has grabbed 
+	**	our message and will abort the job.
+	*/
+	case SIR_RESEL_ABORTED:
+		np->lastmsg = np->msgout[0];
+		np->msgout[0] = M_NOOP;
+		printk ("%s:%d: message %x sent on bad reselection.\n",
+			ncr_name (np), target, np->lastmsg);
+		goto out;
+	/*
+	**	The SCRIPTS let us know that a message has been 
+	**	successfully sent to the device.
+	*/
+	case SIR_MSG_OUT_DONE:
+		np->lastmsg = np->msgout[0];
+		np->msgout[0] = M_NOOP;
+		/* Should we really care of that */
+		if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) {
+			if (cp)
+				cp->xerr_status &= ~XE_PARITY_ERR;
+		}
+		goto out;
+	/*
+	**	The device didn't send a GOOD SCSI status.
+	**	We may have some work to do prior to allow 
+	**	the SCRIPTS processor to continue.
+	*/
+	case SIR_BAD_STATUS:
+		if (!cp)
+			goto out;
+		ncr_sir_to_redo(np, num, cp);
+		return;
+	/*
+	**	We are asked by the SCRIPTS to prepare a 
+	**	REJECT message.
+	*/
+	case SIR_REJECT_TO_SEND:
+		ncr_print_msg(cp, "M_REJECT to send for ", np->msgin);
+		np->msgout[0] = M_REJECT;
+		goto out;
+	/*
+	**	We have been ODD at the end of a DATA IN 
+	**	transfer and the device didn't send a 
+	**	IGNORE WIDE RESIDUE message.
+	**	It is a data overrun condition.
+	*/
+	case SIR_SWIDE_OVERRUN:
+		if (cp)
+			cp->xerr_status |= XE_EXTRA_DATA;
+		goto out;
+	/*
+	**	We have been ODD at the end of a DATA OUT 
+	**	transfer.
+	**	It is a data underrun condition.
+	*/
+	case SIR_SODL_UNDERRUN:
+		if (cp)
+			cp->xerr_status |= XE_EXTRA_DATA;
+		goto out;
+	/*
+	**	We received a message.
+	*/
+	case SIR_MSG_RECEIVED:
+		if (!cp)
+			goto out_stuck;
+		switch (np->msgin [0]) {
+		/*
+		**	We received an extended message.
+		**	We handle MODIFY DATA POINTER, SDTR, WDTR 
+		**	and reject all other extended messages.
+		*/
+		case M_EXTENDED:
+			switch (np->msgin [2]) {
+			case M_X_MODIFY_DP:
+				if (DEBUG_FLAGS & DEBUG_POINTER)
+					ncr_print_msg(cp,"modify DP",np->msgin);
+				tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) + 
+				      (np->msgin[5]<<8)  + (np->msgin[6]);
+				ncr_modify_dp(np, tp, cp, tmp);
+				return;
+			case M_X_SYNC_REQ:
+				ncr_sync_nego(np, tp, cp);
+				return;
+			case M_X_WIDE_REQ:
+				ncr_wide_nego(np, tp, cp);
+				return;
+			default:
+				goto out_reject;
+			}
+			break;
+		/*
+		**	We received a 1/2 byte message not handled from SCRIPTS.
+		**	We are only expecting MESSAGE REJECT and IGNORE WIDE 
+		**	RESIDUE messages that haven't been anticipated by 
+		**	SCRIPTS on SWIDE full condition. Unanticipated IGNORE 
+		**	WIDE RESIDUE messages are aliased as MODIFY DP (-1).
+		*/
+		case M_IGN_RESIDUE:
+			if (DEBUG_FLAGS & DEBUG_POINTER)
+				ncr_print_msg(cp,"ign wide residue", np->msgin);
+			ncr_modify_dp(np, tp, cp, -1);
+			return;
+		case M_REJECT:
+			if (INB (HS_PRT) == HS_NEGOTIATE)
+				ncr_nego_rejected(np, tp, cp);
+			else {
+				PRINT_ADDR(cp->cmd);
+				printk ("M_REJECT received (%x:%x).\n",
+					scr_to_cpu(np->lastmsg), np->msgout[0]);
+			}
+			goto out_clrack;
+			break;
+		default:
+			goto out_reject;
+		}
+		break;
+	/*
+	**	We received an unknown message.
+	**	Ignore all MSG IN phases and reject it.
+	*/
+	case SIR_MSG_WEIRD:
+		ncr_print_msg(cp, "WEIRD message received", np->msgin);
+		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_weird));
+		return;
+	/*
+	**	Negotiation failed.
+	**	Target does not send us the reply.
+	**	Remove the HS_NEGOTIATE status.
+	*/
+	case SIR_NEGO_FAILED:
+		OUTB (HS_PRT, HS_BUSY);
+	/*
+	**	Negotiation failed.
+	**	Target does not want answer message.
+	*/
+	case SIR_NEGO_PROTO:
+		ncr_nego_default(np, tp, cp);
+		goto out;
 	};
 
 out:
 	OUTONB (nc_dcntl, (STD|NOCOM));
+	return;
+out_reject:
+	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+	return;
+out_clrack:
+	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+	return;
 out_stuck:
 }
 
+
 /*==========================================================
 **
 **
@@ -8599,8 +10052,8 @@
 static	ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln)
 {
 	tcb_p tp = &np->target[tn];
-	lcb_p lp = tp->lp[ln];
-	u_char tag = NO_TAG;
+	lcb_p lp = ncr_lp(np, tp, ln);
+	u_short tag = NO_TAG;
 	XPT_QUEHEAD *qp;
 	ccb_p cp = (ccb_p) 0;
 
@@ -8644,9 +10097,10 @@
 			if (lp->busyccbs < lp->maxnxs) {
 				tag = lp->cb_tags[lp->ia_tag];
 				++lp->ia_tag;
-				if (lp->ia_tag == SCSI_NCR_MAX_TAGS)
+				if (lp->ia_tag == MAX_TAGS)
 					lp->ia_tag = 0;
-				lp->tags_umap |= (((tagmap_t) 1) << tag);
+				cp->tags_si = lp->tags_si;
+				++lp->tags_sum[cp->tags_si];
 			}
 			else
 				goto out_free;
@@ -8663,6 +10117,7 @@
 	/*
 	**	Remember all informations needed to free this CCB.
 	*/
+	cp->to_abort = 0;
 	cp->tag	   = tag;
 	cp->target = tn;
 	cp->lun    = ln;
@@ -8691,7 +10146,7 @@
 static void ncr_free_ccb (ncb_p np, ccb_p cp)
 {
 	tcb_p tp = &np->target[cp->target];
-	lcb_p lp = tp->lp[cp->lun];
+	lcb_p lp = ncr_lp(np, tp, cp->lun);
 
 	if (DEBUG_FLAGS & DEBUG_TAGS) {
 		PRINT_LUN(np, cp->target, cp->lun);
@@ -8706,10 +10161,9 @@
 	if (lp) {
 		if (cp->tag != NO_TAG) {
 			lp->cb_tags[lp->if_tag++] = cp->tag;
-			if (lp->if_tag == SCSI_NCR_MAX_TAGS)
+			if (lp->if_tag == MAX_TAGS)
 				lp->if_tag = 0;
-			lp->tags_umap &= ~(((tagmap_t) 1) << cp->tag);
-			lp->tags_smap &= lp->tags_umap;
+			--lp->tags_sum[cp->tags_si];
 			lp->tasktbl[cp->tag] = cpu_to_scr(np->p_bad_i_t_l_q);
 		} else {
 			lp->tasktbl[0] = cpu_to_scr(np->p_bad_i_t_l);
@@ -8770,6 +10224,11 @@
 	cp->phys.header.go.restart = cpu_to_scr(NCB_SCRIPTH_PHYS(np,bad_i_t_l));
 
 	/*
+	**	Initilialyze some other fields.
+	*/
+	cp->phys.smsg_ext.addr = cpu_to_scr(vtobus(&np->msgin[2]));
+
+	/*
 	**	Chain into wakeup list and free ccb queue.
 	*/
 	cp->link_ccb	= np->ccbc;
@@ -8820,25 +10279,6 @@
 */
 static void ncr_init_tcb (ncb_p np, u_char tn)
 {
-	tcb_p tp = &np->target[tn];
-
-	/*
-	**	Already bone.
-	*/
-	if (tp->luntbl)
-		return;
-	/*
-	**	Allocate the lcb bus address array.
-	*/
-	tp->luntbl = m_calloc(256, "LUNTBL", MEMO_WARN);
-	if (!tp->luntbl)
-		return;
-
-	/*
-	**	Compute the bus address of this table.
-	*/
-	tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl));
-
 	/*
 	**	Check some alignments required by the chip.
 	*/	
@@ -8858,7 +10298,7 @@
 static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln)
 {
 	tcb_p tp = &np->target[tn];
-	lcb_p lp = tp->lp[ln];
+	lcb_p lp = ncr_lp(np, tp, ln);
 
 	/*
 	**	Already done, return.
@@ -8870,21 +10310,46 @@
 	**	Initialize the target control block if not yet.
 	*/
 	ncr_init_tcb(np, tn);
-	if (!tp->luntbl)
-		goto fail;
 
 	/*
-	**	Allocate the lcb.
+	**	Allocate the lcb bus address array.
+	**	Compute the bus address of this table.
 	*/
-	lp = m_calloc(sizeof(struct lcb), "LCB", MEMO_WARN);
-	if (!lp)
-		goto fail;
-	tp->lp[ln] = lp;
+	if (ln && !tp->luntbl) {
+		int i;
+
+		tp->luntbl = m_calloc(256, "LUNTBL", MEMO_WARN);
+		if (!tp->luntbl)
+			goto fail;
+		for (i = 0 ; i < 64 ; i++)
+			tp->luntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun));
+		tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl));
+	}
+
+	/*
+	**	Allocate the table of pointers for LUN(s) > 0, if needed.
+	*/
+	if (ln && !tp->lmp) {
+		tp->lmp = m_calloc(MAX_LUN * sizeof(lcb_p), "LMP", MEMO_WARN);
+		if (!tp->lmp)
+			goto fail;
+	}
 
 	/*
+	**	Allocate the lcb.
 	**	Make it available to the chip.
 	*/
-	tp->luntbl[ln] = cpu_to_scr(vtobus(lp));
+	lp = m_calloc(sizeof(struct lcb), "LCB", MEMO_WARN);
+	if (!lp)
+		goto fail;
+	if (ln) {
+		tp->lmp[ln] = lp;
+		tp->luntbl[ln] = cpu_to_scr(vtobus(lp));
+	}
+	else {
+		tp->l0p = lp;
+		tp->b_lun0 = cpu_to_scr(vtobus(lp));
+	}
 
 	/*
 	**	Initialize the CCB queue headers.
@@ -8924,7 +10389,7 @@
 static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data)
 {
 	tcb_p tp = &np->target[tn];
-	lcb_p lp = tp->lp[ln];
+	lcb_p lp = ncr_lp(np, tp, ln);
 	u_char inq_byte7;
 	int i;
 
@@ -8934,14 +10399,16 @@
 	if (!lp && !(lp = ncr_alloc_lcb(np, tn, ln)))
 		goto fail;
 
+#if 0	/* No more used. Left here as provision */
 	/*
-	**	Get device quirks from a speciality table.
+	**	Get device quirks.
 	*/
-	tp->quirks = ncr_lookup (inq_data);
+	tp->quirks = 0;
 	if (tp->quirks && bootverbose) {
 		PRINT_LUN(np, tn, ln);
 		printk ("quirks=%x.\n", tp->quirks);
 	}
+#endif
 
 	/*
 	**	Evaluate trustable target/unit capabilities.
@@ -8984,18 +10451,23 @@
 	**	initialyze the task table if not yet.
 	*/
 	if ((inq_byte7 & INQ7_QUEUE) && lp->tasktbl == &lp->tasktbl_0) {
-		lp->tasktbl = m_calloc(256, "TASKTBL", MEMO_WARN);
+		lp->tasktbl = m_calloc(MAX_TASKS*4, "TASKTBL", MEMO_WARN);
 		if (!lp->tasktbl) {
 			lp->tasktbl = &lp->tasktbl_0;
 			goto fail;
 		}
 		lp->b_tasktbl = cpu_to_scr(vtobus(lp->tasktbl));
-		for (i = 0 ; i < 64 ; i++)
+		for (i = 0 ; i < MAX_TASKS ; i++)
 			lp->tasktbl[i] = cpu_to_scr(np->p_notask);
-		for (i = 0 ; i < SCSI_NCR_MAX_TAGS ; i++)
+
+		lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS", MEMO_WARN);
+		if (!lp->cb_tags)
+			goto fail;
+		for (i = 0 ; i < MAX_TAGS ; i++)
 			lp->cb_tags[i] = i;
-		lp->maxnxs = SCSI_NCR_MAX_TAGS;
-		lp->tags_stime = jiffies;
+
+		lp->maxnxs = MAX_TAGS;
+		lp->tags_stime = ktime_get(3*HZ);
 	}
 
 	/*
@@ -9043,7 +10515,7 @@
 /*
 **	For 64 bit systems, we use the 8 upper bits of the size field 
 **	to provide bus address bits 32-39 to the SCRIPTS processor.
-**	This allows the 896 to access up to 1 tera-bytes of memory.
+**	This allows the 895A and 896 to address up to 1 TB of memory.
 **	For 32 bit chips on 64 bit systems, we must be provided with 
 **	memory addresses that fit into the first 32 bit bus address 
 **	range and so, this does not matter and we expect an error from 
@@ -9325,62 +10797,6 @@
 
 /*==========================================================
 **
-**
-**	Device lookup.
-**
-**	@GENSCSI@ should be integrated to scsiconf.c
-**
-**
-**==========================================================
-*/
-
-struct table_entry {
-	char *	manufacturer;
-	char *	model;
-	char *	version;
-	u_long	info;
-};
-
-static struct table_entry device_tab[] =
-{
-#if 0
-	{"", "", "", QUIRK_NOMSG},
-#endif
-	{"SONY", "SDT-5000", "3.17", QUIRK_NOMSG},
-	{"WangDAT", "Model 2600", "01.7", QUIRK_NOMSG},
-	{"WangDAT", "Model 3200", "02.2", QUIRK_NOMSG},
-	{"WangDAT", "Model 1300", "02.4", QUIRK_NOMSG},
-	{"", "", "", 0} /* catch all: must be last entry. */
-};
-
-static u_long ncr_lookup(char * id)
-{
-	struct table_entry * p = device_tab;
-	char *d, *r, c;
-
-	for (;;p++) {
-
-		d = id+8;
-		r = p->manufacturer;
-		while ((c=*r++)) if (c!=*d++) break;
-		if (c) continue;
-
-		d = id+16;
-		r = p->model;
-		while ((c=*r++)) if (c!=*d++) break;
-		if (c) continue;
-
-		d = id+32;
-		r = p->version;
-		while ((c=*r++)) if (c!=*d++) break;
-		if (c) continue;
-
-		return (p->info);
-	}
-}
-
-/*==========================================================
-**
 **	Determine the ncr's clock frequency.
 **	This is essential for the negotiation
 **	of the synchronous transfer rate.
@@ -9395,7 +10811,7 @@
 **	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 recent fast40 chips (895/896) use a 40 Mhz base clock 
+**	The recent fast40 chips (895/896/895A) 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.
 **
@@ -9436,7 +10852,8 @@
  */
 static unsigned __init ncrgetfreq (ncb_p np, int gen)
 {
-	unsigned ms = 0;
+	unsigned int ms = 0;
+	unsigned int f;
 
 	/*
 	 * Measure GEN timer delay in order 
@@ -9453,7 +10870,6 @@
 	 * performed trust the higher delay 
 	 * (lower frequency returned).
 	 */
-	OUTB (nc_stest1, 0);	/* make sure clock doubler is OFF */
 	OUTW (nc_sien , 0);	/* mask all scsi interrupts */
 	(void) INW (nc_sist);	/* clear pending scsi interrupt */
 	OUTB (nc_dien , 0);	/* mask all dma interrupts */
@@ -9471,12 +10887,28 @@
  	 */
  	OUTB (nc_scntl3, 0);
 
-	if (bootverbose >= 2)
-		printk ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms);
   	/*
  	 * adjust for prescaler, and convert into KHz 
   	 */
-	return ms ? ((1 << gen) * 4340) / ms : 0;
+	f = ms ? ((1 << gen) * 4340) / ms : 0;
+
+	if (bootverbose >= 2)
+		printk ("%s: Delay (GEN=%d): %u msec, %u KHz\n",
+			ncr_name(np), gen, ms, f);
+
+	return f;
+}
+
+static unsigned __init ncr_getfreq (ncb_p np)
+{
+	u_int f1, f2;
+	int gen = 11;
+
+	(void) ncrgetfreq (np, gen);	/* throw away first result */
+	f1 = ncrgetfreq (np, gen);
+	f2 = ncrgetfreq (np, gen);
+	if (f1 > f2) f1 = f2;		/* trust lower result	*/
+	return f1;
 }
 
 /*
@@ -9492,7 +10924,7 @@
 	f1 = 40000;
 
 	/*
-	**	True with 875/895/896 with clock multiplier selected
+	**	True with 875/895/896/895A with clock multiplier selected
 	*/
 	if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {
 		if (bootverbose >= 2)
@@ -9506,16 +10938,11 @@
 	**	Otherwise trust scntl3 BIOS setting.
 	*/
 	if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
-		unsigned f2;
-
-		(void) ncrgetfreq (np, 11);	/* throw away first result */
-		f1 = ncrgetfreq (np, 11);
-		f2 = ncrgetfreq (np, 11);
+		OUTB (nc_stest1, 0);		/* make sure doubler is OFF */
+		f1 = ncr_getfreq (np);
 
 		if (bootverbose)
-			printk ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2);
-
-		if (f1 > f2) f1 = f2;		/* trust lower result	*/
+			printk ("%s: NCR clock is %uKHz\n", ncr_name(np), f1);
 
 		if	(f1 <	45000)		f1 =  40000;
 		else if (f1 <	55000)		f1 =  50000;
@@ -9541,6 +10968,21 @@
 	np->clock_khz	= f1;
 }
 
+/*
+ *	Get/probe PCI clock frequency
+ */
+static u_int __init ncr_getpciclock (ncb_p np)
+{
+	static u_int f = 0;
+
+	if (!f) {
+		OUTB (nc_stest1, SCLK);	/* Use the PCI clock as SCSI clock */
+		f = ncr_getfreq (np);
+		OUTB (nc_stest1, 0);
+	}
+	return f;
+}
+
 /*===================== LINUX ENTRY POINTS SECTION ==========================*/
 
 #ifndef uchar
@@ -9592,6 +11034,11 @@
 #define OPT_SAFE_SETUP		22
 #define OPT_USE_NVRAM		23
 #define OPT_EXCLUDE		24
+#define OPT_HOST_ID		25
+
+#ifdef SCSI_NCR_IARB_SUPPORT
+#define OPT_IARB		26
+#endif
 
 static char setup_token[] __initdata = 
 	"tags:"   "mpar:"
@@ -9606,7 +11053,11 @@
 	"buschk:" "optim:"
 	"recovery:"
 	"safe:"   "nvram:"
-	"excl:";
+	"excl:"   "hostid:"
+#ifdef SCSI_NCR_IARB_SUPPORT
+	"iarb:"
+#endif
+	;	/* DONNOT REMOVE THIS ';' */
 
 #ifdef MODULE
 #define	ARG_SEP	' '
@@ -9631,7 +11082,7 @@
 }
 
 
-void __init sym53c8xx_setup(char *str, int *ints)
+int __init sym53c8xx_setup(char *str)
 {
 #ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
 	char *cur = str;
@@ -9736,6 +11187,14 @@
 			if (xi < SCSI_NCR_MAX_EXCLUDES)
 				driver_setup.excludes[xi++] = val;
 			break;
+		case OPT_HOST_ID:
+			driver_setup.host_id = val;
+			break;
+#ifdef SCSI_NCR_IARB_SUPPORT
+		case OPT_IARB:
+			driver_setup.iarb = val;
+			break;
+#endif
 		default:
 			printk("sym53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
 			break;
@@ -9745,8 +11204,15 @@
 			++cur;
 	}
 #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
+	return 0;
 }
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#ifndef MODULE
+__setup("sym53c8xx=", sym53c8xx_setup);
+#endif
+#endif
+
 static int sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
 	     uchar bus, uchar device_fn, ncr_device *device);
 
@@ -9893,7 +11359,7 @@
 
 #if	defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
 if (sym53c8xx)
-	sym53c8xx_setup(sym53c8xx, (int *) 0);
+	sym53c8xx_setup(sym53c8xx);
 #endif
 #ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 	ncr_debug = driver_setup.debug;
@@ -9945,8 +11411,16 @@
 			continue;
 		}
 		++index;
+		/* Some HW as the HP LH4 may report twice PCI devices */
+		for (i = 0; i < count ; i++) {
+			if (devtbl[i].slot.bus	     == bus && 
+			    devtbl[i].slot.device_fn == device_fn)
+				break;
+		}
+		if (i != count)	/* Ignore this device if we already have it */
+			continue;
 		devp = &devtbl[count];
-		devp->host_id = 255;
+		devp->host_id = driver_setup.host_id;
 		devp->attach_done = 0;
 		if (sym53c8xx_pci_init(tpnt, bus, device_fn, devp)) {
 			continue;
@@ -10050,7 +11524,7 @@
 **===================================================================
 */
 #if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
-static int  __init
+static int __init 
 pci_read_base_address(u_char bus, u_char device_fn, int offset, u_long *base)
 {
 	u_int32 tmp;
@@ -10067,18 +11541,27 @@
 	}
 	return offset;
 }
-#else	/* LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) */
-static int __init
+#elif	LINUX_VERSION_CODE <= LinuxVersionCode(2,3,12)
+static int __init 
 pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
 {
-	/* FIXME! This is just unbelieably horrible backwards compatibility code */
-	struct resource *res = pdev->resource + index;
-
-	*base = res->start | (res->flags & 0xf);
-	if ((res->flags & 0x7) == 0x4) {
+	*base = pdev->base_address[index++];
+	if ((*base & 0x7) == 0x4) {
+#if BITS_PER_LONG > 32
+		*base |= (((u_long)pdev->base_address[index]) << 32);
+#endif
 		++index;
 	}
-	return index+1;
+	return index;
+}
+#else	/* LINUX_VERSION_CODE > LinuxVersionCode(2,3,12) */
+static int __init 
+pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
+{
+	*base = pdev->resource[index].start;
+	if ((pdev->resource[index].flags & 0x7) == 0x4)
+		++index;
+	return ++index;
 }
 #endif
 
@@ -10094,6 +11577,7 @@
 	u_short vendor_id, device_id, command;
 	u_char cache_line_size, latency_timer;
 	u_char suggested_cache_line_size = 0;
+	u_char pci_fix_up;
 	u_char revision;
 #if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92)
 	struct pci_dev *pdev;
@@ -10173,18 +11657,18 @@
 		if (revision > ncr_chip_table[i].revision_id)
 			continue;
 		if (!(ncr_chip_table[i].features & FE_LDSTR))
-			continue;
+			break;
 		chip = &device->chip;
 		memcpy(chip, &ncr_chip_table[i], sizeof(*chip));
 		chip->revision_id = revision;
 		break;
 	}
 
-#if defined(__i386__)
 	/*
 	**	Ignore Symbios chips controlled by SISL RAID controller.
 	**	This controller sets value 0x52414944 at RAM end - 16.
 	*/
+#if defined(__i386__) && !defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED)
 	if (chip && (base_2 & PCI_BASE_ADDRESS_MEM_MASK)) {
 		unsigned int ram_size, ram_val;
 		u_long ram_ptr;
@@ -10206,7 +11690,7 @@
 			}
 		}
 	}
-#endif
+#endif /* i386 and PCI MEMORY accessible */
 
 	if (!chip) {
 		printk(NAME53C8XX ": not initializing, device not supported\n");
@@ -10267,6 +11751,9 @@
 	**    coherent with hardware and software resource identifications.
 	**    This is fairly simple, but seems still too complex for Sparc.
 	*/
+	base = __pa(base);
+	base_2 = __pa(base_2);
+
 	if (!cache_line_size)
 		suggested_cache_line_size = 16;
 
@@ -10290,9 +11777,16 @@
 	/*
 	**    Check availability of IO space, memory space.
 	**    Enable master capability if not yet.
+	**
+	**    We shouldn't have to care about the IO region when 
+	**    we are using MMIO. But calling check_region() from 
+	**    both the ncr53c8xx and the sym53c8xx drivers prevents 
+	**    from attaching devices from the both drivers.
+	**    If you have a better idea, let me know.
 	*/
-#ifdef NCR_IOMAPPED
-	if (!(command & PCI_COMMAND_IO) || !(io_port & 1)) { 
+/* #ifdef NCR_IOMAPPED */
+#if 1
+	if (!(command & PCI_COMMAND_IO)) { 
 		printk(NAME53C8XX ": I/O base address (0x%lx) disabled.\n",
 			(long) io_port);
 		io_port = 0;
@@ -10307,7 +11801,8 @@
 	base	&= PCI_BASE_ADDRESS_MEM_MASK;
 	base_2	&= PCI_BASE_ADDRESS_MEM_MASK;
 
-#ifdef NCR_IOMAPPED
+/* #ifdef NCR_IOMAPPED */
+#if 1
 	if (io_port && check_region (io_port, 128)) {
 		printk(NAME53C8XX ": IO region 0x%lx[0..127] is in use\n",
 			(long) io_port);
@@ -10315,7 +11810,8 @@
 	}
 	if (!io_port)
 		return -1;
-#else
+#endif
+#ifndef NCR_IOMAPPED
 	if (!base) {
 		printk(NAME53C8XX ": MMIO base address disabled.\n");
 		return -1;
@@ -10354,11 +11850,24 @@
 	if (!driver_setup.max_wide)
 		chip->features &= ~FE_WIDE;
 
+	/*
+	**	Some features are required to be enabled in order to 
+	**	work around some chip problems. :) ;)
+	**	(ITEM 12 of a DEL about the 896 I haven't yet).
+	**	We must ensure the chip will use WRITE AND INVALIDATE.
+	**	The revision number limit is for now arbitrary.
+	*/
+	pci_fix_up = driver_setup.pci_fix_up;
+	if (device_id == PCI_DEVICE_ID_NCR_53C896 && revision <= 0x10) {
+		chip->features	|= (FE_WRIE | FE_CLSE);
+		pci_fix_up	|=  3;	/* Force appropriate PCI fix-up */
+	}
+
 #ifdef	SCSI_NCR_PCI_FIX_UP_SUPPORT
 	/*
 	**    Try to fix up PCI config according to wished features.
 	*/
-	if ((driver_setup.pci_fix_up & 1) && (chip->features & FE_CLSE) && 
+	if ((pci_fix_up & 1) && (chip->features & FE_CLSE) && 
 	    !cache_line_size && suggested_cache_line_size) {
 		cache_line_size = suggested_cache_line_size;
 		pcibios_write_config_byte(bus, device_fn,
@@ -10367,7 +11876,7 @@
 			cache_line_size);
 	}
 
-	if ((driver_setup.pci_fix_up & 2) && cache_line_size &&
+	if ((pci_fix_up & 2) && cache_line_size &&
 	    (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
 		printk(NAME53C8XX": setting PCI_COMMAND_INVALIDATE (fix-up)\n");
 		command |= PCI_COMMAND_INVALIDATE;
@@ -10379,7 +11888,7 @@
 	**    (latency timer >= burst length + 6, we add 10 to be quite sure)
 	*/
 
-	if ((driver_setup.pci_fix_up & 4) && chip->burst_max) {
+	if ((pci_fix_up & 4) && chip->burst_max) {
 		uchar lt = (1 << chip->burst_max) + 6 + 10;
 		if (latency_timer < lt) {
 			latency_timer = lt;
@@ -10532,7 +12041,7 @@
 
 		np = ((struct host_data *) host->hostdata)->ncb;
 		tp = &np->target[device->id];
-		lp = tp->lp[device->lun];
+		lp = ncr_lp(np, tp, device->lun);
 
 		/*
 		**	Select queue depth from driver setup.
@@ -10548,8 +12057,8 @@
 		device->queue_depth = numtags;
 		if (device->queue_depth < 2)
 			device->queue_depth = 2;
-		if (device->queue_depth > SCSI_NCR_MAX_TAGS)
-			device->queue_depth = SCSI_NCR_MAX_TAGS;
+		if (device->queue_depth > MAX_TAGS)
+			device->queue_depth = MAX_TAGS;
 
 		/*
 		**	Since the queue depth is not tunable under Linux,
@@ -10973,8 +12482,14 @@
 		uc->cmd = UC_SETDEBUG;
 	else if	((arg_len = is_keyword(ptr, len, "setflag")) != 0)
 		uc->cmd = UC_SETFLAG;
+	else if	((arg_len = is_keyword(ptr, len, "resetdev")) != 0)
+		uc->cmd = UC_RESETDEV;
+	else if	((arg_len = is_keyword(ptr, len, "cleardev")) != 0)
+		uc->cmd = UC_CLEARDEV;
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	else if	((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
 		uc->cmd = UC_CLEARPROF;
+#endif
 	else
 		arg_len = 0;
 
@@ -10991,6 +12506,8 @@
 	case UC_SETTAGS:
 	case UC_SETWIDE:
 	case UC_SETFLAG:
+	case UC_RESETDEV:
+	case UC_CLEARDEV:
 		SKIP_SPACES(1);
 		if ((arg_len = is_keyword(ptr, len, "all")) != 0) {
 			ptr += arg_len; len -= arg_len;
@@ -11034,14 +12551,12 @@
 				uc->data |= DEBUG_ALLOC;
 			else if	((arg_len = is_keyword(ptr, len, "phase")))
 				uc->data |= DEBUG_PHASE;
-			else if	((arg_len = is_keyword(ptr, len, "poll")))
-				uc->data |= DEBUG_POLL;
 			else if	((arg_len = is_keyword(ptr, len, "queue")))
 				uc->data |= DEBUG_QUEUE;
 			else if	((arg_len = is_keyword(ptr, len, "result")))
 				uc->data |= DEBUG_RESULT;
-			else if	((arg_len = is_keyword(ptr, len, "scatter")))
-				uc->data |= DEBUG_SCATTER;
+			else if	((arg_len = is_keyword(ptr, len, "pointer")))
+				uc->data |= DEBUG_POINTER;
 			else if	((arg_len = is_keyword(ptr, len, "script")))
 				uc->data |= DEBUG_SCRIPT;
 			else if	((arg_len = is_keyword(ptr, len, "tiny")))
@@ -11052,10 +12567,6 @@
 				uc->data |= DEBUG_NEGO;
 			else if	((arg_len = is_keyword(ptr, len, "tags")))
 				uc->data |= DEBUG_TAGS;
-			else if	((arg_len = is_keyword(ptr, len, "freeze")))
-				uc->data |= DEBUG_FREEZE;
-			else if	((arg_len = is_keyword(ptr, len, "restart")))
-				uc->data |= DEBUG_RESTART;
 			else
 				return -EINVAL;
 			ptr += arg_len; len -= arg_len;
@@ -11167,7 +12678,7 @@
 		                  (u_long) np->reg);
 #endif
 	copy_info(&info, "  Synchronous period factor %d, ", (int) np->minsync);
-	copy_info(&info, "max commands per lun %d\n", SCSI_NCR_MAX_TAGS);
+	copy_info(&info, "max commands per lun %d\n", MAX_TAGS);
 
 	if (driver_setup.debug || driver_setup.verbose > 1) {
 		copy_info(&info, "  Debug flags 0x%x, ", driver_setup.debug);
@@ -11350,8 +12861,8 @@
 	nvram_stop(np, &gpreg);
 	
 #ifdef SCSI_NCR_DEBUG_NVRAM
-printk("sym53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
-	nvram->start_marker,
+printk("sym53c8xx: NvRAM type=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
+	nvram->type,
 	nvram->trailer[0], nvram->trailer[1], nvram->trailer[2],
 	nvram->trailer[3], nvram->trailer[4], nvram->trailer[5],
 	nvram->byte_count, sizeof(*nvram) - 12,
@@ -11375,7 +12886,8 @@
 /*
  * Read Symbios NvRAM data and compute checksum.
  */
-static u_short __init nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
+static u_short __init 
+nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
 {
 	int	x;
 	u_short	csum;
@@ -11404,7 +12916,8 @@
  * 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 __init nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
+static void __init 
+nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
 {
 	int x;
 	
@@ -11418,7 +12931,8 @@
  * 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 __init nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
+static void __init 
+nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
 {
 	int x;
 	u_char read_bit;
@@ -11436,7 +12950,8 @@
  * Output an ACK to the NVRAM after reading,
  * change GPIO0 to output and when done back to an input
  */
-static void __init nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
+static void __init 
+nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
 {
 	OUTB (nc_gpcntl, *gpcntl & 0xfe);
 	nvram_doBit(np, 0, write_bit, gpreg);
@@ -11447,7 +12962,8 @@
  * Input an ACK from NVRAM after writing,
  * change GPIO0 to input and when done back to an output
  */
-static void __init nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
+static void __init 
+nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
 {
 	OUTB (nc_gpcntl, *gpcntl | 0x01);
 	nvram_doBit(np, read_bit, 1, gpreg);
@@ -11458,7 +12974,8 @@
  * Read or write a bit to the NVRAM,
  * read if GPIO0 input else write if GPIO0 output
  */
-static void __init nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
+static void __init 
+nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
 {
 	nvram_setBit(np, write_bit, gpreg, SET_BIT);
 	nvram_setBit(np, 0, gpreg, SET_CLK);
@@ -11480,7 +12997,8 @@
 /*
  * Set/clear data/clock bit in GPIO0
  */
-static void __init nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
+static void __init 
+nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
 {
 	UDELAY (5);
 	switch (bit_mode){
@@ -11566,7 +13084,8 @@
 /*
  * Read Tekram NvRAM data and compute checksum.
  */
-static u_short __init Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
+static u_short __init 
+Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
 {
 	u_char	read_bit;
 	u_short	csum;
@@ -11591,7 +13110,8 @@
 /*
  * Send read command and address to NVRAM
  */
-static void __init Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
+static void __init 
+Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
 {
 	int x;
 
@@ -11605,7 +13125,8 @@
 /*
  * READ a byte from the NVRAM
  */
-static void __init Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
+static void __init 
+Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
 {
 	int x;
 	u_char read_bit;
@@ -11624,7 +13145,8 @@
 /* 
  * Read bit from NVRAM
  */
-static void __init Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
+static void __init 
+Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
 {
 	UDELAY (2);
 	Tnvram_Clk(np, gpreg);
@@ -11634,7 +13156,8 @@
 /*
  * Write bit to GPIO0
  */
-static void __init Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
+static void __init 
+Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
 {
 	if (write_bit & 0x01)
 		*gpreg |= 0x02;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)