patch-2.1.108 linux/drivers/scsi/ncr53c8xx.c

Next file: linux/drivers/scsi/ncr53c8xx.h
Previous file: linux/drivers/scsi/hosts.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.107/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c
@@ -63,11 +63,17 @@
 **  August 18 1997 by Cort <cort@cs.nmt.edu>:
 **     Support for Power/PC (Big Endian).
 **
+**  June 20 1998 by Gerard Roudier <groudier@club-internet.fr>:
+**     Support for up to 64 tags per lun.
+**     O(1) everywhere (C and SCRIPTS) for normal cases.
+**     Low PCI traffic for command handling when on-chip RAM is present.
+**     Aggressive SCSI SCRIPTS optimizations.
+**
 *******************************************************************************
 */
 
 /*
-**	2 January 1998, version 2.5f
+**	28 June 1998, version 3.0e
 **
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
@@ -92,9 +98,7 @@
 **		Shared IRQ (since linux-1.3.72)
 */
 
-#define SCSI_NCR_DEBUG_FLAGS	(0)		
-
-#define NCR_GETCC_WITHMSG
+#define SCSI_NCR_DEBUG_FLAGS	(0)
 
 /*==========================================================
 **
@@ -112,7 +116,9 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
 #include <asm/spinlock.h>
+#endif
 #include <linux/delay.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -127,16 +133,11 @@
 #include <linux/stat.h>
 
 #include <linux/version.h>
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
 #include <linux/blk.h>
-#else
-#include "../block/blk.h"
-#endif
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
 #include <linux/init.h>
 #else
-#include <linux/bios32.h>
 #ifndef	__initdata
 #define	__initdata
 #endif
@@ -145,6 +146,10 @@
 #endif
 #endif
 
+#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
+#include <linux/bios32.h>
+#endif
+
 #include "scsi.h"
 #include "hosts.h"
 #include "constants.h"
@@ -161,6 +166,159 @@
 
 /*==========================================================
 **
+**	A la VMS/CAM-3 queue management.
+**	Implemented from linux list management.
+**
+**==========================================================
+*/
+
+typedef struct xpt_quehead {
+	struct xpt_quehead *flink;	/* Forward  pointer */
+	struct xpt_quehead *blink;	/* Backward pointer */
+} XPT_QUEHEAD;
+
+#define xpt_que_init(ptr) do { \
+	(ptr)->flink = (ptr); (ptr)->blink = (ptr); \
+} while (0)
+
+static inline void __xpt_que_add(struct xpt_quehead * new,
+	struct xpt_quehead * blink,
+	struct xpt_quehead * flink)
+{
+	flink->blink	= new;
+	new->flink	= flink;
+	new->blink	= blink;
+	blink->flink	= new;
+}
+
+static inline void __xpt_que_del(struct xpt_quehead * blink,
+	struct xpt_quehead * flink)
+{
+	flink->blink = blink;
+	blink->flink = flink;
+}
+
+static inline int xpt_que_empty(struct xpt_quehead *head)
+{
+	return head->flink == head;
+}
+
+static inline void xpt_que_splice(struct xpt_quehead *list,
+	struct xpt_quehead *head)
+{
+	struct xpt_quehead *first = list->flink;
+
+	if (first != list) {
+		struct xpt_quehead *last = list->blink;
+		struct xpt_quehead *at   = head->flink;
+
+		first->blink = head;
+		head->flink  = first;
+
+		last->flink = at;
+		at->blink   = last;
+	}
+}
+
+#define xpt_que_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+
+#define xpt_insque(new, pos)		__xpt_que_add(new, pos, (pos)->flink)
+
+#define xpt_remque(el)			__xpt_que_del((el)->blink, (el)->flink)
+
+#define xpt_insque_head(new, head)	__xpt_que_add(new, head, (head)->flink)
+
+static inline struct xpt_quehead *xpt_remque_head(struct xpt_quehead *head)
+{
+	struct xpt_quehead *elem = head->flink;
+
+	if (elem != head)
+		__xpt_que_del(head, elem->flink);
+	else
+		elem = 0;
+	return elem;
+}
+
+#define xpt_insque_tail(new, head)	__xpt_que_add(new, (head)->blink, head)
+
+static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head)
+{
+	struct xpt_quehead *elem = head->blink;
+
+	if (elem != head)
+		__xpt_que_del(elem->blink, head);
+	else
+		elem = 0;
+	return elem;
+}
+
+/*==========================================================
+**
+**	The CCB done queue uses an array of CCB virtual 
+**	addresses. Empty entries are flagged using the bogus 
+**	virtual address 0xffffffff.
+**
+**	Since PCI ensures that only aligned DWORDs are accessed 
+**	atomically, 64 bit little-endian architecture requires 
+**	to test the high order DWORD of the entry to determine 
+**	if it is empty or valid.
+**
+**	BTW, I will make things differently as soon as I will 
+**	have a better idea, but this is simple and should work.
+**
+**==========================================================
+*/
+ 
+#define SCSI_NCR_CCB_DONE_SUPPORT
+#ifdef  SCSI_NCR_CCB_DONE_SUPPORT
+
+#define MAX_DONE 24
+#define CCB_DONE_EMPTY 0xffffffffUL
+
+/* All 32 bit architectures */
+#if (~0UL) == 0xffffffffUL
+#define CCB_DONE_VALID(cp)  (((u_long) cp) != CCB_DONE_EMPTY)
+
+/* All > 32 bit (64 bit) architectures regardless endian-ness */
+#else
+#define CCB_DONE_VALID(cp)  \
+	((((u_long) cp) & 0xffffffff00000000ul) && 	\
+	 (((u_long) cp) & 0xfffffffful) != CCB_DONE_EMPTY)
+#endif
+
+#endif /* SCSI_NCR_CCB_DONE_SUPPORT */
+
+/*==========================================================
+**
+**	On x86 architecture, write buffers management does 
+**	not reorder writes to memory. So, using compiler 
+**	optimization barriers is enough to guarantee some 
+**	ordering when the CPU is writing data accessed by 
+**	the NCR.
+**	On Alpha architecture, explicit memory barriers have 
+**	to be used.
+**	Other architectures are defaulted to mb() macro if  
+**	defined, otherwise use compiler barrier.
+**
+**==========================================================
+*/
+
+#if defined(__i386__)
+#define MEMORY_BARRIER()	barrier()
+#elif defined(__alpha__)
+#define MEMORY_BARRIER()	mb()
+#else
+#  ifdef mb
+#  define MEMORY_BARRIER()	mb()
+#  else
+#  define MEMORY_BARRIER()	barrier()
+#  endif
+#endif
+
+/*==========================================================
+**
 **	Configuration and Debugging
 **
 **==========================================================
@@ -182,13 +340,44 @@
 */
 
 #ifndef SCSI_NCR_MAX_TAGS
-#define SCSI_NCR_MAX_TAGS    (4)
+#define SCSI_NCR_MAX_TAGS    (8)
+#endif
+
+/*
+**    TAGS are actually limited to 64 tags/lun.
+**    We need to deal with power of 2, for alignment constraints.
+*/
+#if	SCSI_NCR_MAX_TAGS > 64
+#undef	SCSI_NCR_MAX_TAGS
+#define	SCSI_NCR_MAX_TAGS (64)
+#endif
+
+#define NO_TAG	(255)
+
+/*
+**    For more than 32 TAGS support, we do some address calculation 
+**    from the SCRIPTS using 2 additionnal SCR_COPY's and a fiew 
+**    bit handling on 64 bit integers. For these reasons, support for 
+**    32 up to 64 TAGS is compiled conditionnaly.
+*/
+
+#if	SCSI_NCR_MAX_TAGS <= 32
+struct nlink {
+	ncrcmd	l_cmd;
+	ncrcmd	l_paddr;
+};
+#else
+struct nlink {
+	ncrcmd	l_paddr;
+};
+typedef u64 u_int64;
 #endif
 
+
 /*
 **    Number of targets supported by the driver.
 **    n permits target numbers 0..n-1.
-**    Default is 7, meaning targets #0..#6.
+**    Default is 16, meaning targets #0..#15.
 **    #7 .. is myself.
 */
 
@@ -234,10 +423,23 @@
 
 /*
 **    The maximum number of segments a transfer is split into.
+**    We support up to 127 segments for both read and write.
+**    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.
 */
 
 #define MAX_SCATTER (SCSI_NCR_MAX_SCATTER)
 
+#if (MAX_SCATTER > 80)
+#define MAX_SCATTERL	80
+#define	MAX_SCATTERH	(MAX_SCATTER - MAX_SCATTERL)
+#else
+#define MAX_SCATTERL	(MAX_SCATTER-1)
+#define	MAX_SCATTERH	1
+#endif
+
 /*
 **    Io mapped or memory mapped.
 */
@@ -267,7 +469,6 @@
  **	Obvious definitions
  */
 
-#define printf		printk
 #define u_char		unsigned char
 #define u_short		unsigned short
 #define u_int		unsigned int
@@ -282,25 +483,77 @@
 #ifndef bzero
 #define bzero(d, n)	memset((d), 0, (n))
 #endif
-
+ 
 #ifndef offsetof
 #define offsetof(t, m)	((size_t) (&((t *)0)->m))
 #endif
 
 /*
+**	SMP threading.
+**
+**	Assuming that SMP systems are generally high end systems and may 
+**	use several SCSI adapters, we are using one lock per controller 
+**	instead of some global one. For the moment (linux-2.1.95), driver's 
+**	entry points are called with the 'io_request_lock' lock held, so:
+**	- We are uselessly loosing a couple of micro-seconds to lock the 
+**	  controller data structure.
+**	- But the driver is not broken by design for SMP and so can be 
+**	  more resistant to bugs or bad changes in the IO sub-system code.
+**	- A small advantage could be that the interrupt code is grained as 
+**	  wished (e.g.: threaded by controller).
+*/
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+
+#if 0	/* not yet needed */
+static spinlock_t driver_lock;
+#define	NCR_LOCK_DRIVER(flags)     spin_lock_irqsave(&driver_lock, flags)
+#define	NCR_UNLOCK_DRIVER(flags)   spin_unlock_irqrestore(&driver_lock, flags)
+#endif
+
+#define NCR_INIT_LOCK_NCB(np)      spin_lock_init(&np->smp_lock);
+#define	NCR_LOCK_NCB(np, flags)    spin_lock_irqsave(&np->smp_lock, flags)
+#define	NCR_UNLOCK_NCB(np, flags)  spin_unlock_irqrestore(&np->smp_lock, flags)
+
+#	if LINUX_VERSION_CODE < LinuxVersionCode(2,3,99)
+
+#	define	NCR_LOCK_SCSI_DONE(np, flags) \
+		spin_lock_irqsave(&io_request_lock, flags)
+#	define	NCR_UNLOCK_SCSI_DONE(np, flags) \
+		spin_unlock_irqrestore(&io_request_lock, flags)
+
+#	else
+
+#	define	NCR_LOCK_SCSI_DONE(np, flags)    do {;} while (0)
+#	define	NCR_UNLOCK_SCSI_DONE(np, flags)  do {;} while (0)
+
+#	endif
+
+#else
+
+#if 0	/* not yet needed */
+#define	NCR_LOCK_DRIVER(flags)     do {;} while (0)
+#define	NCR_UNLOCK_DRIVER(flags)   do {;} while (0)
+#endif
+
+#define	NCR_INIT_LOCK_NCB(np)      do { } while (0)
+#define	NCR_LOCK_NCB(np, flags)    do { save_flags(flags); cli(); } while (0)
+#define	NCR_UNLOCK_NCB(np, flags)  do { restore_flags(flags); } while (0)
+
+#define	NCR_LOCK_SCSI_DONE(np, flags)    do {;} while (0)
+#define	NCR_UNLOCK_SCSI_DONE(np, flags)  do {;} while (0)
+
+#endif
+
+/*
 **	Address translation
 **
-**	On Linux 1.3.X, virt_to_bus() must be used to translate
-**	virtual memory addresses of the kernel data segment into
-**	IO bus adresses.
-**	On i386 architecture, IO bus addresses match the physical
-**	addresses. But on other architectures they can be different.
-**	In the original Bsd driver, vtophys() is called to translate
-**	data addresses to IO bus addresses. In order to minimize
-**	change, I decide to define vtophys() as virt_to_bus().
+**	The driver has to provide physical memory addresses to 
+**	the script processor. Because some architectures use 
+**	different physical addresses from the PCI BUS, we must 
+**	use virt_to_bus instead of virt_to_phys.
 */
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
 #define vtophys(p)	virt_to_bus(p)
 
 /*
@@ -314,12 +567,18 @@
 **	architecture.
 */
 
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0)
+#define ioremap vremap
+#define iounmap vfree
+#endif
+
 #ifdef __sparc__
 #define remap_pci_mem(base, size)	((vm_offset_t) __va(base))
 #define unmap_pci_mem(vaddr, size)
 #define pcivtophys(p)			((p) & pci_dvma_mask)
 #else	/* __sparc__ */
 #define pcivtophys(p)			(p)
+
 #ifndef NCR_IOMAPPED
 __initfunc(
 static vm_offset_t remap_pci_mem(u_long base, u_long size)
@@ -327,13 +586,9 @@
 {
 	u_long page_base	= ((u_long) base) & PAGE_MASK;
 	u_long page_offs	= ((u_long) base) - page_base;
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
 	u_long page_remapped	= (u_long) ioremap(page_base, page_offs+size);
-#else
-	u_long page_remapped	= (u_long) vremap(page_base, page_offs+size);
-#endif
 
-	return (vm_offset_t) (page_remapped ? (page_remapped + page_offs) : 0UL);
+	return (vm_offset_t) (page_remapped? (page_remapped + page_offs) : 0UL);
 }
 
 __initfunc(
@@ -341,52 +596,41 @@
 )
 {
 	if (vaddr)
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0)
 		iounmap((void *) (vaddr & PAGE_MASK));
-#else
-		vfree((void *) (vaddr & PAGE_MASK));
-#endif
 }
 #endif	/* !NCR_IOMAPPED */
 #endif	/* __sparc__ */
 
-#else /* linux-1.2.13 */
-
 /*
-**	Linux 1.2.X assumes that addresses (virtual, physical, bus)
-**	are the same.
-**
-**	I have not found how to do MMIO. It seems that only processes can
-**	map high physical pages to virtual (Xservers can do MMIO).
+**	Insert a delay in micro-seconds and milli-seconds.
+**	-------------------------------------------------
+**	Under Linux, udelay() is restricted to delay < 1 milli-second.
+**	In fact, it generally works for up to 1 second delay.
+**	Since 2.1.105, the mdelay() function is provided for delays 
+**	in milli-seconds.
+**	Under 2.0 kernels, udelay() is an inline function that is very 
+**	inaccurate on Pentium processors.
 */
 
-#define vtophys(p)	((u_long) (p))
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,105)
+#define UDELAY udelay
+#define MDELAY mdelay
+#else
+static void UDELAY(long us) { udelay(us); }
+static void MDELAY(long ms) { while (ms--) UDELAY(1000); }
 #endif
 
 /*
-**	Insert a delay in micro-seconds.
-*/
-
-static void DELAY(long us)
-{
-	for (;us>1000;us-=1000) udelay(1000);
-	if (us) udelay(us);
-}
-
-/*
 **	Internal data structure allocation.
 **
 **	Linux scsi memory poor pool is adjusted for the need of
 **	middle-level scsi driver.
 **	We allocate our control blocks in the kernel memory pool
 **	to avoid scsi pool shortage.
-**	I notice that kmalloc() returns NULL during host attach under
-**	Linux 1.2.13. But this ncr driver is reliable enough to
-**	accomodate with this joke.
 **
-**	kmalloc() only ensure 8 bytes boundary alignment.
+**	kmalloc() only ensures 8 bytes boundary alignment.
 **	The NCR need better alignment for cache line bursting.
-**	The global header is moved betewen the NCB and CCBs and need 
+**	The global header is moved between the NCB and CCBs and needs 
 **	origin and destination addresses to have same lower four bits.
 **
 **	We use 32 boundary alignment for NCB and CCBs and offset multiple 
@@ -396,17 +640,9 @@
 #define ALIGN_SIZE(shift)	(1UL << shift)
 #define ALIGN_MASK(shift)	(~(ALIGN_SIZE(shift)-1))
 
-#define NCB_ALIGN_SHIFT		5
-#define CCB_ALIGN_SHIFT		5
-#define LCB_ALIGN_SHIFT		5
-#define SCR_ALIGN_SHIFT		5
-
-#define NCB_ALIGN_SIZE		ALIGN_SIZE(NCB_ALIGN_SHIFT)
-#define NCB_ALIGN_MASK		ALIGN_MASK(NCB_ALIGN_SHIFT)
-#define CCB_ALIGN_SIZE		ALIGN_SIZE(CCB_ALIGN_SHIFT)
-#define CCB_ALIGN_MASK		ALIGN_MASK(CCB_ALIGN_SHIFT)
-#define SCR_ALIGN_SIZE		ALIGN_SIZE(SCR_ALIGN_SHIFT)
-#define SCR_ALIGN_MASK		ALIGN_MASK(SCR_ALIGN_SHIFT)
+#define CACHE_LINE_SHIFT	5
+#define CACHE_LINE_SIZE		ALIGN_SIZE(CACHE_LINE_SHIFT)
+#define CACHE_LINE_MASK		ALIGN_MASK(CACHE_LINE_SHIFT)
 
 static void *m_alloc(int size, int a_shift)
 {
@@ -460,11 +696,8 @@
 **	be able to transfer data in the direction choosen by the target. 
 */
 
-#define XferNone	0
-#define XferIn		1
-#define XferOut		2
-#define XferBoth	3
-static int guess_xfer_direction(int opcode);
+#define XFER_IN		(1)
+#define XFER_OUT	(2)
 
 /*
 **	Head of list of NCR boards
@@ -482,45 +715,30 @@
 **	/proc directory entry and proc_info function
 */
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
 struct proc_dir_entry proc_scsi_ncr53c8xx = {
     PROC_SCSI_NCR53C8XX, 9, "ncr53c8xx",
     S_IFDIR | S_IRUGO | S_IXUGO, 2
 };
-# ifdef SCSI_NCR_PROC_INFO_SUPPORT
+#ifdef SCSI_NCR_PROC_INFO_SUPPORT
 int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset,
 			int length, int hostno, int func);
-# endif
 #endif
 
 /*
-**	Table of target capabilities.
-**
-**	This bitmap is anded with the byte 7 of inquiry data on completion of
-**	INQUIRY command.
-** 	The driver never see zeroed bits and will ignore the corresponding
-**	capabilities of the target.
-*/
-
-static struct {
-	unsigned char and_map[MAX_TARGET];
-} target_capabilities[SCSI_NCR_MAX_HOST] = { NCR53C8XX_TARGET_CAPABILITIES };
-
-/*
 **	Driver setup.
 **
 **	This structure is initialized from linux config options.
 **	It can be overridden at boot-up by the boot command line.
 */
 struct ncr_driver_setup {
-	unsigned master_parity	: 1;
-	unsigned scsi_parity	: 1;
-	unsigned disconnection	: 1;
-	unsigned special_features : 2;
-	unsigned ultra_scsi	: 2;
-	unsigned force_sync_nego: 1;
-	unsigned reverse_probe: 1;
-	unsigned pci_fix_up: 4;
+	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;
@@ -533,6 +751,7 @@
 	u_char	diff_support;
 	u_char	irqm;
 	u_char	bus_check;
+	char	tag_ctrl[100];
 };
 
 static struct ncr_driver_setup
@@ -552,17 +771,9 @@
 
 #define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f))
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
-static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist);
-#endif
-
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
+static void ncr53c8xx_select_queue_depths(
+	struct Scsi_Host *host, struct scsi_device *devlist);
 static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
-static void do_ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
-#else
-static void ncr53c8xx_intr(int irq, struct pt_regs * regs);
-#endif
-
 static void ncr53c8xx_timeout(unsigned long np);
 
 #define initverbose (driver_setup.verbose)
@@ -589,6 +800,7 @@
 #define SYMBIOS_SCAM_ENABLE	(1)
 #define SYMBIOS_PARITY_ENABLE	(1<<1)
 #define SYMBIOS_VERBOSE_MSGS	(1<<2)
+#define SYMBIOS_CHS_MAPPING	(1<<3)
 	u_short	flags1;
 #define SYMBIOS_SCAN_HI_LO	(1)
 	u_short	word10;		/* 0x00 */
@@ -685,7 +897,7 @@
 	int	irq;
 /* port and reg fields to use INB, OUTB macros */
 	u_long	port;
-	volatile struct	ncr_reg	*reg;
+	volatile struct ncr_reg	*reg;
 } ncr_slot;
 
 typedef struct {
@@ -758,7 +970,7 @@
 
 #define	assert(expression) { \
 	if (!(expression)) { \
-		(void)printf(\
+		(void)printk(KERN_ERR \
 			"assertion \"%s\" failed: file \"%s\", line %d\n", \
 			#expression, \
 			__FILE__, __LINE__); \
@@ -821,7 +1033,12 @@
 **
 **	Access to the controller chip.
 **
-**	If NCR_IOMAPPED is defined, only IO are used by the driver.
+**	If NCR_IOMAPPED is defined, the driver will use 
+**	normal IOs instead of the MEMORY MAPPED IO method  
+**	recommended by PCI specifications.
+**	If all PCI bridges, host brigdes and architectures 
+**	would have been correctly designed for PCI, this 
+**	option would be useless.
 **
 **==========================================================
 */
@@ -941,15 +1158,31 @@
 #define HS_NEGOTIATE	(2)	/* sync/wide data transfer*/
 #define HS_DISCONNECT	(3)	/* Disconnected by target */
 
-#define HS_COMPLETE	(4)
-#define HS_SEL_TIMEOUT	(5)	/* Selection timeout      */
-#define HS_RESET	(6)	/* SCSI reset	     */
-#define HS_ABORTED	(7)	/* Transfer aborted       */
-#define HS_TIMEOUT	(8)	/* Software timeout       */
-#define HS_FAIL		(9)	/* SCSI or PCI bus errors */
-#define HS_UNEXPECTED	(10)	/* Unexpected disconnect  */
+#define HS_DONEMASK	(0x80)
+#define HS_COMPLETE	(4|HS_DONEMASK)
+#define HS_SEL_TIMEOUT	(5|HS_DONEMASK)	/* Selection timeout      */
+#define HS_RESET	(6|HS_DONEMASK)	/* SCSI reset	          */
+#define HS_ABORTED	(7|HS_DONEMASK)	/* Transfer aborted       */
+#define HS_TIMEOUT	(8|HS_DONEMASK)	/* Software timeout       */
+#define HS_FAIL		(9|HS_DONEMASK)	/* SCSI or PCI bus errors */
+#define HS_UNEXPECTED	(10|HS_DONEMASK)/* Unexpected disconnect  */
+
+/*
+**	Invalid host status values used by the SCRIPTS processor 
+**	when the nexus is not fully identified.
+**	Shall never appear in a CCB.
+*/
 
-#define HS_DONEMASK	(0xfc)
+#define HS_INVALMASK	(0x40)
+#define	HS_SELECTING	(0|HS_INVALMASK)
+#define	HS_IN_RESELECT	(1|HS_INVALMASK)
+#define	HS_STARTING	(2|HS_INVALMASK)
+
+/*
+**	Flags set by the SCRIPT processor for commands 
+**	that have been skipped.
+*/
+#define HS_SKIPMASK	(0x20)
 
 /*==========================================================
 **
@@ -958,21 +1191,24 @@
 **==========================================================
 */
 
-#define	SIR_SENSE_RESTART	(1)
-#define	SIR_SENSE_FAILED	(2)
-#define	SIR_STALL_RESTART	(3)
-#define	SIR_STALL_QUEUE		(4)
-#define	SIR_NEGO_SYNC		(5)
-#define	SIR_NEGO_WIDE		(6)
-#define	SIR_NEGO_FAILED		(7)
-#define	SIR_NEGO_PROTO		(8)
-#define	SIR_REJECT_RECEIVED	(9)
-#define	SIR_REJECT_SENT		(10)
-#define	SIR_IGN_RESIDUE		(11)
-#define	SIR_MISSING_SAVE	(12)
-#define	SIR_DATA_IO_IS_OUT	(13)
-#define	SIR_DATA_IO_IS_IN	(14)
-#define	SIR_MAX			(14)
+#define	SIR_BAD_STATUS		(1)
+#define	SIR_XXXXXXXXXX		(2)
+#define	SIR_NEGO_SYNC		(3)
+#define	SIR_NEGO_WIDE		(4)
+#define	SIR_NEGO_FAILED		(5)
+#define	SIR_NEGO_PROTO		(6)
+#define	SIR_REJECT_RECEIVED	(7)
+#define	SIR_REJECT_SENT		(8)
+#define	SIR_IGN_RESIDUE		(9)
+#define	SIR_MISSING_SAVE	(10)
+#define	SIR_RESEL_NO_MSG_IN	(11)
+#define	SIR_RESEL_NO_IDENTIFY	(12)
+#define	SIR_RESEL_BAD_LUN	(13)
+#define	SIR_RESEL_BAD_TARGET	(14)
+#define	SIR_RESEL_BAD_I_T_L	(15)
+#define	SIR_RESEL_BAD_I_T_L_Q	(16)
+#define	SIR_DONE_OVERFLOW	(17)
+#define	SIR_MAX			(17)
 
 /*==========================================================
 **
@@ -1010,7 +1246,6 @@
 #define	QUIRK_NOMSG	(0x02)
 #define QUIRK_NOSYNC	(0x10)
 #define QUIRK_NOWIDE16	(0x20)
-#define	QUIRK_UPDATE	(0x80)
 
 /*==========================================================
 **
@@ -1069,10 +1304,7 @@
 #define UC_SETWIDE	14
 #define UC_SETFLAG	15
 #define UC_CLEARPROF	16
-
-#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-#define UC_DEBUG_ERROR_RECOVERY 17
-#endif
+#define UC_SETVERBOSE	17
 
 #define	UF_TRACE	(0x01)
 #define	UF_NODISC	(0x02)
@@ -1085,10 +1317,11 @@
 **---------------------------------------
 */
 
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+
 struct tstamp {
 	u_long start;
 	u_long end;
-	u_long select;
 	u_long command;
 	u_long status;
 	u_long disconnect;
@@ -1112,263 +1345,262 @@
 	u_long	ms_disc;
 	u_long	ms_post;
 };
+#endif
 
-/*==========================================================
+/*========================================================================
 **
 **	Declaration of structs:		target control block
 **
-**==========================================================
+**========================================================================
 */
-
 struct tcb {
-	/*
-	**	during reselection the ncr jumps to this point
-	**	with SFBR set to the encoded target number
-	**	with bit 7 set.
+	/*----------------------------------------------------------------
+	**	During reselection the ncr jumps to this point with SFBR 
+	**	set to the encoded target number with bit 7 set.
 	**	if it's not this target, jump to the next.
 	**
-	**	JUMP  IF (SFBR != #target#)
-	**	@(next tcb)
+	**	JUMP  IF (SFBR != #target#), @(next tcb)
+	**----------------------------------------------------------------
 	*/
-
 	struct link   jump_tcb;
 
-	/*
-	**	load the actual values for the sxfer and the scntl3
+	/*----------------------------------------------------------------
+	**	Load the actual values for the sxfer and the scntl3
 	**	register (sync/wide mode).
 	**
-	**	SCR_COPY (1);
-	**	@(sval field of this tcb)
-	**	@(sxfer register)
-	**	SCR_COPY (1);
-	**	@(wval field of this tcb)
-	**	@(scntl3 register)
+	**	SCR_COPY (1), @(sval field of this tcb), @(sxfer  register)
+	**	SCR_COPY (1), @(wval field of this tcb), @(scntl3 register)
+	**----------------------------------------------------------------
 	*/
-
 	ncrcmd	getscr[6];
 
-	/*
-	**	if next message is "identify"
-	**	then load the message to SFBR,
-	**	else load 0 to SFBR.
+	/*----------------------------------------------------------------
+	**	Get the IDENTIFY message and load the LUN to SFBR.
 	**
-	**	CALL
-	**	<RESEL_LUN>
+	**	CALL, <RESEL_LUN>
+	**----------------------------------------------------------------
 	*/
-
 	struct link   call_lun;
 
-	/*
-	**	now look for the right lun.
+	/*----------------------------------------------------------------
+	**	Now look for the right lun.
 	**
-	**	JUMP
-	**	@(first ccb of this lun)
-	*/
-
-	struct link   jump_lcb;
-
-	/*
-	**	pointer to interrupted getcc ccb
-	*/
-
-	ccb_p   hold_cp;
-
-	/*
-	**	pointer to ccb used for negotiating.
-	**	Avoid to start a nego for all queued commands 
+	**	For i = 0 to 3
+	**		SCR_JUMP ^ IFTRUE(MASK(i, 3)), @(first lcb mod. i)
+	**
+	**	Recent chips will prefetch the 4 JUMPS using only 1 burst.
+	**	It is kind of hashcoding.
+	**----------------------------------------------------------------
+	*/
+	struct link     jump_lcb[4];	/* JUMPs for reselection	*/
+	lcb_p		lp[MAX_LUN];	/* The lcb's of this tcb	*/
+	u_char		inq_done;	/* Target capabilities received	*/
+	u_char		inq_byte7;	/* Contains these capabilities	*/
+
+	/*----------------------------------------------------------------
+	**	Pointer to the ccb used for negotiation.
+	**	Prevent from starting a negotiation for all queued commands 
 	**	when tagged command queuing is enabled.
+	**----------------------------------------------------------------
 	*/
-
 	ccb_p   nego_cp;
 
-	/*
+	/*----------------------------------------------------------------
 	**	statistical data
+	**----------------------------------------------------------------
 	*/
-
 	u_long	transfers;
 	u_long	bytes;
 
-	/*
-	**	user settable limits for sync transfer
-	**	and tagged commands.
-	**	These limits are read from the NVRAM if present.
-	*/
-
-	u_char	usrsync;
-	u_char	usrwide;
-	u_char	usrtags;
-	u_char	usrflag;
-
-	u_char	numtags;
-	u_char	maxtags;
-	u_short	num_good;
-
-	/*
-	**	negotiation of wide and synch transfer.
-	**	device quirks.
+	/*----------------------------------------------------------------
+	**	negotiation of wide and synch transfer and device quirks.
+	**----------------------------------------------------------------
 	*/
-
 /*0*/	u_char	minsync;
 /*1*/	u_char	sval;
 /*2*/	u_short	period;
 /*0*/	u_char	maxoffs;
-
 /*1*/	u_char	quirks;
-
 /*2*/	u_char	widedone;
 /*3*/	u_char	wval;
-	/*
-	**	inquire data
-	*/
-#define MAX_INQUIRE 36
-	u_char	inqdata[MAX_INQUIRE];
 
-	/*
-	**	the lcb's of this tcb
+	/*----------------------------------------------------------------
+	**	User settable limits and options.
+	**	These limits are read from the NVRAM if present.
+	**----------------------------------------------------------------
 	*/
-
-	lcb_p   lp[MAX_LUN];
+	u_char	usrsync;
+	u_char	usrwide;
+	u_char	usrtags;
+	u_char	usrflag;
 };
 
-/*==========================================================
+/*========================================================================
 **
 **	Declaration of structs:		lun control block
 **
-**==========================================================
+**========================================================================
 */
-
 struct lcb {
-	/*
-	**	during reselection the ncr jumps to this point
+	/*----------------------------------------------------------------
+	**	During reselection the ncr jumps to this point
 	**	with SFBR set to the "Identify" message.
 	**	if it's not this lun, jump to the next.
 	**
-	**	JUMP  IF (SFBR != #lun#)
-	**	@(next lcb of this target)
-	*/
-
-	struct link	jump_lcb;
-
-	/*
-	**	if next message is "simple tag",
-	**	then load the tag to SFBR,
-	**	else load 0 to SFBR.
+	**	JUMP  IF (SFBR != #lun#), @(next lcb of this target)
 	**
-	**	CALL
-	**	<RESEL_TAG>
-	*/
-
-	struct link	call_tag;
-
-	/*
-	**	now look for the right ccb.
+	**	It is this lun. Load TEMP with the nexus jumps table 
+	**	address and jump to RESEL_TAG (or RESEL_NOTAG).
 	**
-	**	JUMP
-	**	@(first ccb of this lun)
-	*/
-
-	struct link	jump_ccb;
-
-	/*
-	**	start of the ccb chain
-	*/
-
-	ccb_p	next_ccb;
-
-	/*
-	**	Control of tagged queueing
-	*/
-
-	u_char		reqccbs;
-	u_char		actccbs;
-	u_char		reqlink;
-	u_char		actlink;
-	u_char		usetags;
-	u_char		lasttag;
-
-	/*
-	**	Linux specific fields:
-	**	Number of active commands and current credit.
-	**	Should be managed by the generic scsi driver
+	**		SCR_COPY (4), p_jump_ccb, TEMP,
+	**		SCR_JUMP, <RESEL_TAG>
+	**----------------------------------------------------------------
 	*/
+	struct link	jump_lcb;
+	ncrcmd		load_jump_ccb[3];
+	struct link	jump_tag;
+	ncrcmd		p_jump_ccb;	/* Jump table bus address	*/
+
+	/*----------------------------------------------------------------
+	**	Jump table used by the script processor to directly jump 
+	**	to the CCB corresponding to the reselected nexus.
+	**	Address is allocated on 256 bytes boundary in order to 
+	**	allow 8 bit calculation of the tag jump entry for up to 
+	**	64 possible tags.
+	**----------------------------------------------------------------
+	*/
+	struct nlink	jump_ccb_0;	/* Default table if no tags	*/
+	struct nlink	*jump_ccb;	/* Virtual address		*/
+
+	/*----------------------------------------------------------------
+	**	CCB queue management.
+	**----------------------------------------------------------------
+	*/
+	XPT_QUEHEAD	free_ccbq;	/* Queue of available CCBs	*/
+	XPT_QUEHEAD	busy_ccbq;	/* Queue of busy CCBs		*/
+	XPT_QUEHEAD	wait_ccbq;	/* Queue of waiting for IO CCBs	*/
+	XPT_QUEHEAD	skip_ccbq;	/* Queue of skipped CCBs	*/
+	u_char		actccbs;	/* Number of allocated 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		*/
+
+	/*----------------------------------------------------------------
+	**	Control of tagged command queuing.
+	**	Tags allocation is performed using a circular buffer.
+	**	This avoids using a loop for tag allocation.
+	**----------------------------------------------------------------
+	*/
+	u_char		ia_tag;		/* Allocation index		*/
+	u_char		if_tag;		/* Freeing index		*/
+#if SCSI_NCR_MAX_TAGS <= 32
+	u_char		cb_tags[32];	/* Circular tags buffer		*/
+#else
+	u_char		cb_tags[64];	/* Circular tags buffer		*/
+#endif
+	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	*/
+
+	/*----------------------------------------------------------------
+	**	QUEUE FULL control and ORDERED tag control.
+	**----------------------------------------------------------------
+	*/
+	u_short		num_good;	/* Nr of GOOD since QUEUE FULL	*/
+#if SCSI_NCR_MAX_TAGS <= 32
+	u_int		tags_umap;	/* Used tags bitmap		*/
+	u_int		tags_smap;	/* Tags in use at 'tag_stime'	*/
+#else
+	u_int64		tags_umap;	/* Used tags bitmap		*/
+	u_int64		tags_smap;	/* Tags in use at 'tag_stime'	*/
+#endif
+	u_long		tags_stime;	/* Last time we set smap=umap	*/
+	ccb_p		held_ccb;	/* CCB held for QUEUE FULL	*/
+};
 
-	u_char		active;
-	u_char		opennings;
-
-	/*-----------------------------------------------
-	**	Flag to force M_ORDERED_TAG on next command
-	**	in order to avoid spurious timeout when
-	**	M_SIMPLE_TAG is used for all operations.
-	**-----------------------------------------------
+/*========================================================================
+**
+**      Declaration of structs:     the launch script.
+**
+**========================================================================
+**
+**	It is part of the CCB and is called by the scripts processor to 
+**	start or restart the data structure (nexus).
+**	This 6 DWORDs mini script makes use of prefetching.
+**
+**------------------------------------------------------------------------
+*/
+struct launch {
+	/*----------------------------------------------------------------
+	**	SCR_COPY(4),	@(p_phys), @(dsa register)
+	**	SCR_JUMP,	@(scheduler_point)
+	**----------------------------------------------------------------
 	*/
-	u_char	force_ordered_tag;
-#define NCR_TIMEOUT_INCREASE	(5*HZ)
+	ncrcmd		setup_dsa[3];	/* Copy 'phys' address to dsa	*/
+	struct link	schedule;	/* Jump to scheduler point	*/
+	ncrcmd		p_phys;		/* 'phys' header bus address	*/
 };
 
-/*==========================================================
+/*========================================================================
 **
-**      Declaration of structs:     COMMAND control block
+**      Declaration of structs:     global HEADER.
 **
-**==========================================================
+**========================================================================
 **
-**	This substructure is copied from the ccb to a
-**	global address after selection (or reselection)
-**	and copied back before disconnect.
+**	This substructure is copied from the ccb to a global address after 
+**	selection (or reselection) and copied back before disconnect.
 **
 **	These fields are accessible to the script processor.
 **
-**----------------------------------------------------------
+**------------------------------------------------------------------------
 */
 
 struct head {
-	/*
-	**	Execution of a ccb starts at this point.
-	**	It's a jump to the "SELECT" label
-	**	of the script.
-	**
-	**	After successful selection the script
-	**	processor overwrites it with a jump to
-	**	the IDLE label of the script.
-	*/
-
-	struct link	launch;
-
-	/*
+	/*----------------------------------------------------------------
 	**	Saved data pointer.
-	**	Points to the position in the script
-	**	responsible for the actual transfer
-	**	of data.
-	**	It's written after reception of a
-	**	"SAVE_DATA_POINTER" message.
-	**	The goalpointer points after
-	**	the last transfer command.
+	**	Points to the position in the script responsible for the
+	**	actual transfer transfer of data.
+	**	It's written after reception of a SAVE_DATA_POINTER message.
+	**	The goalpointer points after the last transfer command.
+	**----------------------------------------------------------------
 	*/
-
 	u_int32		savep;
 	u_int32		lastp;
 	u_int32		goalp;
 
-	/*
-	**	The virtual address of the ccb
-	**	containing this header.
+	/*----------------------------------------------------------------
+	**	Alternate data pointer.
+	**	They are copied back to savep/lastp/goalp by the SCRIPTS 
+	**	when the direction is unknown and the device claims data out.
+	**----------------------------------------------------------------
+	*/
+	u_int32		wlastp;
+	u_int32		wgoalp;
+
+	/*----------------------------------------------------------------
+	**	The virtual address of the ccb containing this header.
+	**----------------------------------------------------------------
 	*/
-
 	ccb_p	cp;
 
-	/*
-	**	space for some timestamps to gather
-	**	profiling data about devices and this driver.
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+	/*----------------------------------------------------------------
+	**	Space for some timestamps to gather profiling data.
+	**----------------------------------------------------------------
 	*/
-
 	struct tstamp	stamp;
+#endif
 
-	/*
-	**	status fields.
-	*/
-
-	u_char		scr_st[4];	/* script status */
-	u_char		status[4];	/* host status. Must be the last */
-					/* DWORD of the CCB header */
+	/*----------------------------------------------------------------
+	**	Status fields.
+	**----------------------------------------------------------------
+	*/
+	u_char		scr_st[4];	/* script status		*/
+	u_char		status[4];	/* host status. must be the 	*/
+					/*  last DWORD of the header.	*/
 };
 
 /*
@@ -1401,6 +1633,7 @@
 #define  HS_REG	scr1
 #define  HS_PRT	nc_scr1
 #define  SS_REG	scr2
+#define  SS_PRT	nc_scr2
 #define  PS_REG	scr3
 
 /*
@@ -1423,9 +1656,12 @@
 **	First four bytes (host)
 */
 #define  xerr_status   phys.xerr_st
-#define  sync_status   phys.sync_st
 #define  nego_status   phys.nego_st
+
+#if 0
+#define  sync_status   phys.sync_st
 #define  wide_status   phys.wide_st
+#endif
 
 /*==========================================================
 **
@@ -1447,9 +1683,6 @@
 
 	/*
 	**	Header.
-	**	Has to be the first entry,
-	**	because it's jumped to by the
-	**	script processor
 	*/
 
 	struct head	header;
@@ -1460,403 +1693,276 @@
 
 	struct scr_tblsel  select;
 	struct scr_tblmove smsg  ;
-	struct scr_tblmove smsg2 ;
 	struct scr_tblmove cmd   ;
-	struct scr_tblmove scmd  ;
 	struct scr_tblmove sense ;
 	struct scr_tblmove data [MAX_SCATTER];
 };
 
-/*==========================================================
+
+/*========================================================================
 **
 **      Declaration of structs:     Command control block.
 **
-**==========================================================
-**
-**	During execution of a ccb by the script processor,
-**	the DSA (data structure address) register points
-**	to this substructure of the ccb.
-**	This substructure contains the header with
-**	the script-processor-changable data and then
-**	data blocks for the indirect move commands.
-**
-**----------------------------------------------------------
+**========================================================================
 */
-
-
 struct ccb {
-	/*
-	**	This field forces 32 bytes alignement for phys.header,
-	**	in order to use cache line bursting when copying it 
-	**	to the ncb.
-	*/
-
-	struct link		filler[2];
-
-	/*
-	**	during reselection the ncr jumps to this point.
-	**	If a "SIMPLE_TAG" message was received,
-	**	then SFBR is set to the tag.
-	**	else SFBR is set to 0
-	**	If looking for another tag, jump to the next ccb.
-	**
-	**	JUMP  IF (SFBR != #TAG#)
-	**	@(next ccb of this lun)
-	*/
-
-	struct link		jump_ccb;
-
-	/*
-	**	After execution of this call, the return address
-	**	(in  the TEMP register) points to the following
-	**	data structure block.
-	**	So copy it to the DSA register, and start
-	**	processing of this data structure.
-	**
-	**	CALL
-	**	<RESEL_TMP>
-	*/
-
-	struct link		call_tmp;
-
-	/*
-	**	This is the data structure which is
-	**	to be executed by the script processor.
+	/*----------------------------------------------------------------
+	**	This is the data structure which is pointed by the DSA 
+	**	register when it is executed by the script processor.
+	**	It must be the first entry because it contains the header 
+	**	as first entry that must be cache line aligned.
+	**----------------------------------------------------------------
+	*/
+	struct dsb	phys;
+
+	/*----------------------------------------------------------------
+	**	Mini-script used at CCB execution start-up.
+	**	Load the DSA with the data structure address (phys) and 
+	**	jump to SELECT. Jump to CANCEL if CCB is to be canceled.
+	**----------------------------------------------------------------
+	*/
+	struct launch	start;
+
+	/*----------------------------------------------------------------
+	**	Mini-script used at CCB relection to restart the nexus.
+	**	Load the DSA with the data structure address (phys) and 
+	**	jump to RESEL_DSA. Jump to ABORT if CCB is to be aborted.
+	**----------------------------------------------------------------
 	*/
+	struct launch	restart;
 
-	struct dsb		phys;
-
-	/*
+	/*----------------------------------------------------------------
 	**	If a data transfer phase is terminated too early
 	**	(after reception of a message (i.e. DISCONNECT)),
 	**	we have to prepare a mini script to transfer
 	**	the rest of the data.
+	**----------------------------------------------------------------
 	*/
+	ncrcmd		patch[8];
 
-	ncrcmd			patch[8];
-
-	/*
+	/*----------------------------------------------------------------
 	**	The general SCSI driver provides a
 	**	pointer to a control block.
+	**----------------------------------------------------------------
 	*/
-
-	Scsi_Cmnd	*cmd;
-	int data_len;
-
-	/*
-	**	We prepare a message to be sent after selection,
-	**	and a second one to be sent after getcc selection.
+	Scsi_Cmnd	*cmd;		/* SCSI command 		*/
+	u_long		tlimit;		/* Deadline for this job	*/
+	int		data_len;	/* Total data length		*/
+
+	/*----------------------------------------------------------------
+	**	Message areas.
+	**	We prepare a message to be sent after selection.
+	**	We may use a second one if the command is rescheduled 
+	**	due to GETCC or QFULL.
 	**      Contents are IDENTIFY and SIMPLE_TAG.
 	**	While negotiating sync or wide transfer,
-	**	a SDTM or WDTM message is appended.
-	*/
-
-	u_char			scsi_smsg [8];
-	u_char			scsi_smsg2[8];
-
-	/*
-	**	Lock this ccb.
-	**	Flag is used while looking for a free ccb.
-	*/
-
-	u_long		magic;
-
-	/*
-	**	Physical address of this instance of ccb
-	*/
-
-	u_long		p_ccb;
-
-	/*
-	**	Completion time out for this job.
-	**	It's set to time of start + allowed number of seconds.
-	*/
-
-	u_long		tlimit;
-
-	/*
-	**	All ccbs of one hostadapter are chained.
-	*/
-
-	ccb_p		link_ccb;
-
-	/*
-	**	All ccbs of one target/lun are chained.
-	*/
-
-	ccb_p		next_ccb;
-
-	/*
-	**	Sense command
-	*/
-
-	u_char		sensecmd[6];
-
-	/*
-	**	Tag for this transfer.
-	**	It's patched into jump_ccb.
-	**	If it's not zero, a SIMPLE_TAG
-	**	message is included in smsg.
+	**	a SDTR or WDTR message is appended.
+	**----------------------------------------------------------------
 	*/
+	u_char		scsi_smsg [8];
+	u_char		scsi_smsg2[8];
 
-	u_char			tag;
-
-	/*
-	**	Number of segments of the scatter list.
-	**	Used for recalculation of savep/goalp/lastp on 
-	**	SIR_DATA_IO_IS_OUT interrupt.
-	*/
-	
-	u_char			segments;
+	/*----------------------------------------------------------------
+	**	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		target;
+	u_char		lun;
+	u_char		queued;
+	u_char		auto_sense;
+	ccb_p		link_ccb;	/* Host adapter CCB chain	*/
+	XPT_QUEHEAD	link_ccbq;	/* Link to unit CCB queue	*/
+	u_int32		startp;		/* Initial data pointer		*/
+	u_long		magic;		/* Free / busy  CCB flag	*/
 };
 
 #define CCB_PHYS(cp,lbl)	(cp->p_ccb + offsetof(struct ccb, lbl))
 
-/*==========================================================
+
+/*========================================================================
 **
 **      Declaration of structs:     NCR device descriptor
 **
-**==========================================================
+**========================================================================
 */
-
 struct ncb {
-	/*
+	/*----------------------------------------------------------------
 	**	The global header.
-	**	Accessible to both the host and the
-	**	script-processor.
-	**	Is 32 bytes aligned since ncb is, in order to 
-	**	allow cache line bursting when copying it from or 
-	**	to ccbs.
+	**	It is accessible to both the host and the script processor.
+	**	Must be cache line size aligned (32 for x86) in order to 
+	**	allow cache line bursting when it is copied to/from CCB.
+	**----------------------------------------------------------------
 	*/
 	struct head     header;
 
-	/*-----------------------------------------------
-	**	Specific Linux fields
-	**-----------------------------------------------
-	*/
-	int    unit;			/* Unit number                       */
-	char   chip_name[8];		/* Chip name                         */
-	char   inst_name[16];		/* Instance name                     */
-	struct timer_list timer;	/* Timer link header                 */
-	int	ncr_cache;		/* Cache test variable               */
-	Scsi_Cmnd *waiting_list;	/* Waiting list header for commands  */
-					/* that we can't put into the squeue */
-	u_long	settle_time;		/* Reset in progess		     */
-	u_char	release_stage;		/* Synchronisation stage on release  */
-	u_char	verbose;		/* Boot verbosity for this controller*/
-#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-	u_char	debug_error_recovery;
-	u_char	stalling;
-	u_char	assert_atn;
-#endif
-
-	/*-----------------------------------------------
-	**	Added field to support differences
-	**	between ncr chips.
-	**	sv_xxx are some io register bit value at start-up and
-	**	so assumed to have been set by the sdms bios.
-	**	rv_xxx are the bit fields of io register that will keep 
-	**	the features used by the driver.
-	**-----------------------------------------------
-	*/
-	u_short	device_id;
-	u_char	revision_id;
-
-	u_char	sv_scntl0;
-	u_char	sv_scntl3;
-	u_char	sv_dmode;
-	u_char	sv_dcntl;
-	u_char	sv_ctest3;
-	u_char	sv_ctest4;
-	u_char	sv_ctest5;
-	u_char	sv_gpcntl;
-	u_char	sv_stest2;
-	u_char	sv_stest4;
-
-	u_char	rv_scntl0;
-	u_char	rv_scntl3;
-	u_char	rv_dmode;
-	u_char	rv_dcntl;
-	u_char	rv_ctest3;
-	u_char	rv_ctest4;
-	u_char	rv_ctest5;
-	u_char	rv_stest2;
-
-	u_char	scsi_mode;
-
-	/*-----------------------------------------------
-	**	Scripts ..
-	**-----------------------------------------------
-	**
-	**	During reselection the ncr jumps to this point.
+	/*----------------------------------------------------------------
+	**	CCBs management queues.
+	**----------------------------------------------------------------
+	*/
+	Scsi_Cmnd	*waiting_list;	/* Commands waiting for a CCB	*/
+					/*  when lcb is not allocated.	*/
+	Scsi_Cmnd	*done_list;	/* Commands waiting for done()  */
+					/* callback to be invoked.      */ 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+	spinlock_t	smp_lock;	/* Lock for SMP threading       */
+#endif
+
+	/*----------------------------------------------------------------
+	**	Chip and controller indentification.
+	**----------------------------------------------------------------
+	*/
+	int		unit;		/* Unit number			*/
+	char		chip_name[8];	/* Chip name			*/
+	char		inst_name[16];	/* ncb instance name		*/
+
+	/*----------------------------------------------------------------
+	**	Initial value of some IO register bits.
+	**	These values are assumed to have been set by BIOS, and may 
+	**	be used for probing adapter implementation differences.
+	**----------------------------------------------------------------
+	*/
+	u_char	sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4,
+		sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4;
+
+	/*----------------------------------------------------------------
+	**	Actual initial value of IO register bits used by the 
+	**	driver. They are loaded at initialisation according to  
+	**	features that are to be enabled.
+	**----------------------------------------------------------------
+	*/
+	u_char	rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4, 
+		rv_ctest5, rv_stest2;
+
+	/*----------------------------------------------------------------
+	**	Targets management.
+	**	During reselection the ncr jumps to jump_tcb.
 	**	The SFBR register is loaded with the encoded target id.
+	**	For i = 0 to 3
+	**		SCR_JUMP ^ IFTRUE(MASK(i, 3)), @(next tcb mod. i)
 	**
-	**	Jump to the first target.
-	**
-	**	JUMP
-	**	@(next tcb)
-	*/
-	struct link     jump_tcb;
-
-	/*-----------------------------------------------
-	**	Configuration ..
-	**-----------------------------------------------
-	**
-	**	virtual and physical addresses
-	**	of the 53c810 chip.
-	*/
-	vm_offset_t     vaddr;
-	vm_offset_t     paddr;
-
-	vm_offset_t     vaddr2;
-	vm_offset_t     paddr2;
-
-	/*
-	**	pointer to the chip's registers.
-	*/
-	volatile
-	struct ncr_reg* reg;
-
-	/*
-	**	A copy of the scripts, relocated for this ncb.
-	*/
-	struct script	*script0;
-	struct scripth	*scripth0;
-
-	/*
-	**	Scripts instance virtual address.
-	*/
-	struct script	*script;
-	struct scripth	*scripth;
-
-	/*
-	**	Scripts instance physical address.
-	*/
-	u_long		p_script;
-	u_long		p_scripth;
-
-	/*
-	**	The SCSI address of the host adapter.
-	*/
-	u_char	  myaddr;
-
-	/*
-	**	Max dwords burst supported by the adapter.
-	*/
+	**	Recent chips will prefetch the 4 JUMPS using only 1 burst.
+	**	It is kind of hashcoding.
+	**----------------------------------------------------------------
+	*/
+	struct link     jump_tcb[4];	/* JUMPs for reselection	*/
+	struct tcb  target[MAX_TARGET];	/* Target data			*/
+
+	/*----------------------------------------------------------------
+	**	Virtual and physical bus addresses of the chip.
+	**----------------------------------------------------------------
+	*/
+	vm_offset_t	vaddr;		/* Virtual and bus address of	*/
+	vm_offset_t     paddr;		/*  chip's IO registers.	*/
+	vm_offset_t     paddr2;		/* On-chip RAM bus address.	*/
+	volatile			/* Pointer to volatile for 	*/
+	struct ncr_reg	*reg;		/*  memory mapped IO.		*/
+
+	/*----------------------------------------------------------------
+	**	SCRIPTS virtual and physical bus addresses.
+	**	'script'  is loaded in the on-chip RAM if present.
+	**	'scripth' stays in main memory.
+	**----------------------------------------------------------------
+	*/
+	struct script	*script0;	/* Copies of script and scripth	*/
+	struct scripth	*scripth0;	/*  relocated for this ncb.	*/
+	struct scripth	*scripth;	/* Actual scripth virt. address	*/
+	u_long		p_script;	/* Actual script and scripth	*/
+	u_long		p_scripth;	/*  bus addresses.		*/
+
+	/*----------------------------------------------------------------
+	**	General controller parameters and configuration.
+	**----------------------------------------------------------------
+	*/
+	u_short		device_id;	/* PCI device id		*/
+	u_char		revision_id;	/* PCI device revision id	*/
+	u_long		port;		/* IO space base address	*/
+	u_int		irq;		/* IRQ level			*/
+	u_int		features;	/* Chip features map		*/
+	u_char		myaddr;		/* SCSI id of the adapter	*/
 	u_char		maxburst;	/* log base 2 of dwords burst	*/
-
-	/*
-	**	timing parameters
-	*/
+	u_char		maxwide;	/* Maximum transfer width	*/
 	u_char		minsync;	/* Minimum sync period factor	*/
 	u_char		maxsync;	/* Maximum sync period factor	*/
 	u_char		maxoffs;	/* Max scsi offset		*/
 	u_char		multiplier;	/* Clock multiplier (1,2,4)	*/
 	u_char		clock_divn;	/* Number of clock divisors	*/
 	u_long		clock_khz;	/* SCSI clock frequency in KHz	*/
-	u_int		features;	/* Chip features map		*/
-
-
-	/*-----------------------------------------------
-	**	Link to the generic SCSI driver
-	**-----------------------------------------------
-	*/
-
-	/* struct scsi_link	sc_link; */
-
-	/*-----------------------------------------------
-	**	Job control
-	**-----------------------------------------------
-	**
-	**	Commands from user
-	*/
-	struct usrcmd	user;
-	u_char		order;
-
-	/*
-	**	Target data
-	*/
-	struct tcb	target[MAX_TARGET];
 
-	/*
-	**	Start queue.
-	*/
-	u_int32		squeue [MAX_START];
-	u_short		squeueput;
-	u_short		actccbs;
-
-	/*
-	**	Timeout handler
+	/*----------------------------------------------------------------
+	**	Start queue management.
+	**	It is filled up by the host processor and accessed by the 
+	**	SCRIPTS processor in order to start SCSI commands.
+	**----------------------------------------------------------------
+	*/
+	u_short		squeueput;	/* Next free slot of the queue	*/
+	u_short		actccbs;	/* Number of allocated CCBs	*/
+	u_short		queuedccbs;	/* Number of CCBs in start queue*/
+	u_short		queuedepth;	/* Start queue depth		*/
+
+	/*----------------------------------------------------------------
+	**	Timeout handler.
+	**----------------------------------------------------------------
 	*/
-#if 0
-	u_long		heartbeat;
-	u_short		ticks;
-	u_short		latetime;
-#endif
+	struct timer_list timer;	/* Timer handler link header	*/
 	u_long		lasttime;
+	u_long		settle_time;	/* Resetting the SCSI BUS	*/
 
-	/*-----------------------------------------------
-	**	Debug and profiling
-	**-----------------------------------------------
-	**
-	**	register dump
-	*/
-	struct ncr_reg	regdump;
-	u_long		regtime;
-
-	/*
-	**	Profiling data
+	/*----------------------------------------------------------------
+	**	Debugging and profiling.
+	**----------------------------------------------------------------
 	*/
-	struct profile	profile;
-	u_int		disc_phys;
+	struct ncr_reg	regdump;	/* Register dump		*/
+	u_long		regtime;	/* Time it has been done	*/
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+	struct profile	profile;	/* Profiling data		*/
+	u_int		disc_phys;	/* Disconnection counters 	*/
 	u_int		disc_ref;
+#endif
 
-	/*
-	**	The global control block.
-	**	It's used only during the configuration phase.
-	**	A target control block will be created
-	**	after the first successful transfer.
-	*/
-	struct ccb      *ccb;
-
-	/*
-	**	message buffers.
-	**	Should be longword aligned,
-	**	because they're written with a
-	**	COPY script command.
-	*/
-	u_char		msgout[8];
-	u_char		msgin [8];
-	u_int32		lastmsg;
-
-	/*
-	**	Buffer for STATUS_IN phase.
-	*/
-	u_char		scratch;
-
-	/*
-	**	controller chip dependent maximal transfer width.
-	*/
-	u_char		maxwide;
-
-	/*
-	**	option for M_IDENTIFY message: enables disconnecting
-	*/
-	u_char		disc;
-
-	/*
-	**	address of the ncr control registers in io space
-	*/
-	u_long		port;
-
-	/*
-	**	irq level
-	*/
-	u_int		irq;
+	/*----------------------------------------------------------------
+	**	Miscellaneous buffers accessed by the scripts-processor.
+	**	They shall be DWORD aligned, because they may be read or 
+	**	written with a SCR_COPY script command.
+	**----------------------------------------------------------------
+	*/
+	u_char		msgout[8];	/* Buffer for MESSAGE OUT 	*/
+	u_char		msgin [8];	/* Buffer for MESSAGE IN	*/
+	u_int32		lastmsg;	/* Last SCSI message sent	*/
+	u_char		scratch;	/* Scratch for SCSI receive	*/
+
+	/*----------------------------------------------------------------
+	**	Miscellaneous configuration and status parameters.
+	**----------------------------------------------------------------
+	*/
+	u_char		disc;		/* Diconnection allowed		*/
+	u_char		scsi_mode;	/* Current SCSI BUS mode	*/
+	u_char		order;		/* Tag order to use		*/
+	u_char		verbose;	/* Verbosity for this controller*/
+	int		ncr_cache;	/* Used for cache test at init.	*/
+
+	/*----------------------------------------------------------------
+	**	Command completion handling.
+	**----------------------------------------------------------------
+	*/
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+	struct ccb	*(ccb_done[MAX_DONE]);
+	int		ccb_done_ic;
+#endif
+	/*----------------------------------------------------------------
+	**	Fields that should be removed or changed.
+	**----------------------------------------------------------------
+	*/
+	struct ccb	*ccb;		/* Global CCB			*/
+	struct usrcmd	user;		/* Command from user		*/
+	u_char		release_stage;	/* Synchronisation stage on release  */
 };
 
 #define NCB_SCRIPT_PHYS(np,lbl)	 (np->p_script  + offsetof (struct script, lbl))
-#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth, lbl))
+#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth,lbl))
 
 /*==========================================================
 **
@@ -1874,84 +1980,137 @@
 **	we reach them (for forward jumps).
 **	Therefore we declare a struct here.
 **	If you make changes inside the script,
-**	DON'T FORGET TO CHANGE THE LENGTHS HERE!
+**	DONT FORGET TO CHANGE THE LENGTHS HERE!
 **
 **----------------------------------------------------------
 */
 
 /*
-**	Script fragments which are loaded into the on-board RAM 
+**	Script fragments which are loaded into the on-chip RAM 
 **	of 825A, 875 and 895 chips.
 */
 struct script {
-	ncrcmd	start		[  4];
-	ncrcmd	start0		[  2];
-	ncrcmd	start1		[  3];
+	ncrcmd	start		[  5];
 	ncrcmd  startpos	[  1];
-	ncrcmd  trysel		[  8];
-	ncrcmd	skip		[  8];
-	ncrcmd	skip2		[  3];
-	ncrcmd  idle		[  2];
-	ncrcmd	select		[ 22];
-	ncrcmd	prepare		[  4];
-	ncrcmd	loadpos		[ 14];
-	ncrcmd	prepare2	[ 24];
-	ncrcmd	setmsg		[  5];
-	ncrcmd  clrack		[  2];
-	ncrcmd  dispatch	[ 38];
+	ncrcmd	select		[  6];
+	ncrcmd	select2		[  7];
+	ncrcmd	loadpos		[  4];
+	ncrcmd	send_ident	[  7];
+	ncrcmd	prepare		[  6];
+	ncrcmd	prepare2	[  7];
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+	ncrcmd  command		[  9];
+#else
+	ncrcmd  command		[  6];
+#endif
+	ncrcmd  dispatch	[ 32];
+	ncrcmd  clrack		[  4];
 	ncrcmd	no_data		[ 17];
-	ncrcmd  checkatn	[ 10];
-	ncrcmd  command		[ 15];
-	ncrcmd  status		[ 27];
-	ncrcmd  msg_in		[ 26];
-	ncrcmd  msg_bad		[  6];
-	ncrcmd  complete	[ 13];
-	ncrcmd	cleanup		[ 12];
-	ncrcmd	cleanup0	[ 11];
-	ncrcmd	signal		[ 10];
-	ncrcmd  save_dp		[  5];
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+	ncrcmd  status		[ 11];
+#else
+	ncrcmd  status		[  8];
+#endif
+	ncrcmd  msg_in		[  2];
+	ncrcmd  msg_in2		[ 16];
+	ncrcmd  msg_bad		[  4];
+	ncrcmd	setmsg		[  7];
+	ncrcmd	cleanup		[  6];
+	ncrcmd  complete	[  9];
+	ncrcmd	cleanup_ok	[  8];
+	ncrcmd	cleanup0	[  1];
+#ifndef SCSI_NCR_CCB_DONE_SUPPORT
+	ncrcmd	signal		[ 12];
+#else
+	ncrcmd	signal		[  9];
+	ncrcmd	done_pos	[  1];
+	ncrcmd	done_plug	[  2];
+	ncrcmd	done_end	[  7];
+#endif
+	ncrcmd  save_dp		[  7];
 	ncrcmd  restore_dp	[  5];
-	ncrcmd  disconnect	[ 12];
-	ncrcmd  disconnect0	[  5];
-	ncrcmd  disconnect1	[ 23];
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+	ncrcmd  disconnect	[ 28];
+#else
+	ncrcmd  disconnect	[ 17];
+#endif
 	ncrcmd	msg_out		[  9];
 	ncrcmd	msg_out_done	[  7];
-	ncrcmd  badgetcc	[  6];
+	ncrcmd  idle		[  2];
 	ncrcmd	reselect	[  8];
-	ncrcmd	reselect1	[  8];
-	ncrcmd	reselect2	[  8];
-	ncrcmd	resel_tmp	[  5];
-	ncrcmd  resel_lun	[ 18];
-	ncrcmd	resel_tag	[ 24];
-	ncrcmd  data_io		[  6];
-	ncrcmd  data_in		[MAX_SCATTER * 4 + 4];
+	ncrcmd	reselected	[  8];
+	ncrcmd	resel_dsa	[  6];
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+	ncrcmd	loadpos1	[  7];
+#else
+	ncrcmd	loadpos1	[  4];
+#endif
+	ncrcmd  resel_lun	[  6];
+#if SCSI_NCR_MAX_TAGS <= 32
+	ncrcmd	resel_tag	[  8];
+#else
+	ncrcmd	resel_tag	[  6];
+	ncrcmd	jump_to_nexus	[  4];
+	ncrcmd	nexus_indirect	[  4];
+#endif
+#if SCSI_NCR_MAX_TAGS <= 32
+	ncrcmd	resel_notag	[  4];
+#else
+	ncrcmd	resel_notag	[  4];
+#endif
+	ncrcmd  data_in		[MAX_SCATTERL * 4];
+	ncrcmd  data_in2	[  4];
+	ncrcmd  data_out	[MAX_SCATTERL * 4];
+	ncrcmd  data_out2	[  4];
 };
 
 /*
 **	Script fragments which stay in main memory for all chips.
 */
 struct scripth {
-	ncrcmd  tryloop		[MAX_START*5+2];
-	ncrcmd  msg_parity	[  6];
+	ncrcmd  tryloop		[MAX_START*2];
+	ncrcmd  tryloop2	[  2];
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+	ncrcmd  done_queue	[MAX_DONE*5];
+	ncrcmd  done_queue2	[  2];
+#endif
+	ncrcmd	select_no_atn	[  8];
+	ncrcmd	cancel		[  4];
+	ncrcmd	skip		[  9];
+	ncrcmd	skip2		[ 19];
+	ncrcmd	par_err_data_in	[  6];
+	ncrcmd	par_err_other	[  4];
 	ncrcmd	msg_reject	[  8];
-	ncrcmd	msg_ign_residue	[ 32];
-	ncrcmd  msg_extended	[ 18];
-	ncrcmd  msg_ext_2	[ 18];
-	ncrcmd	msg_wdtr	[ 27];
-	ncrcmd  msg_ext_3	[ 18];
-	ncrcmd	msg_sdtr	[ 27];
+	ncrcmd	msg_ign_residue	[ 24];
+	ncrcmd  msg_extended	[ 10];
+	ncrcmd  msg_ext_2	[ 10];
+	ncrcmd	msg_wdtr	[ 14];
+	ncrcmd	send_wdtr	[  7];
+	ncrcmd  msg_ext_3	[ 10];
+	ncrcmd	msg_sdtr	[ 14];
+	ncrcmd	send_sdtr	[  7];
 	ncrcmd	msg_out_abort	[ 10];
-	ncrcmd  getcc		[  4];
-	ncrcmd  getcc1		[  5];
-#ifdef NCR_GETCC_WITHMSG
-	ncrcmd	getcc2		[ 33];
-#else
-	ncrcmd	getcc2		[ 14];
-#endif
-	ncrcmd	getcc3		[ 10];
-	ncrcmd  data_out	[MAX_SCATTER * 4 + 4];
+	ncrcmd  hdata_in	[MAX_SCATTERH * 4];
+	ncrcmd  hdata_in2	[  2];
+	ncrcmd  hdata_out	[MAX_SCATTERH * 4];
+	ncrcmd  hdata_out2	[  2];
+	ncrcmd	reset		[  4];
 	ncrcmd	aborttag	[  4];
-	ncrcmd	abort		[ 22];
+	ncrcmd	abort		[  2];
+	ncrcmd	abort_resel	[ 20];
+	ncrcmd	resend_ident	[  4];
+	ncrcmd	clratn_go_on	[  3];
+	ncrcmd	nxtdsp_go_on	[  1];
+	ncrcmd	sdata_in	[  8];
+	ncrcmd  data_io		[ 18];
+	ncrcmd	bad_identify	[ 12];
+	ncrcmd	bad_i_t_l	[  4];
+	ncrcmd	bad_i_t_l_q	[  4];
+	ncrcmd	bad_target	[  8];
+	ncrcmd	bad_status	[  8];
+	ncrcmd	start_ram	[  4];
+	ncrcmd	start_ram0	[  4];
+	ncrcmd	sto_restart	[  5];
 	ncrcmd	snooptest	[  9];
 	ncrcmd	snoopend	[  2];
 };
@@ -1965,14 +2124,19 @@
 **==========================================================
 */
 
-static	void	ncr_alloc_ccb	(ncb_p np, u_long t, u_long l);
+static	void	ncr_alloc_ccb	(ncb_p np, u_char tn, u_char ln);
 static	void	ncr_complete	(ncb_p np, ccb_p cp);
 static	void	ncr_exception	(ncb_p np);
-static	void	ncr_free_ccb	(ncb_p np, ccb_p cp, u_long t, u_long l);
+static	void	ncr_free_ccb	(ncb_p np, ccb_p cp);
+static	void	ncr_init_ccb	(ncb_p np, ccb_p cp);
+static	void	ncr_init_tcb	(ncb_p np, u_char tn);
+static	lcb_p	ncr_alloc_lcb	(ncb_p np, u_char tn, u_char ln);
+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	void	ncr_selectclock	(ncb_p np, u_char scntl3);
-static	ccb_p	ncr_get_ccb	(ncb_p np, u_long t,u_long l);
-static	void	ncr_init	(ncb_p np, char * msg, u_long code);
+static	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);
 static	int	ncr_int_sbmc	(ncb_p np);
 static	int	ncr_int_par	(ncb_p np);
 static	void	ncr_int_ma	(ncb_p np);
@@ -1980,7 +2144,6 @@
 static  void    ncr_int_sto     (ncb_p np);
 static	u_long	ncr_lookup	(char* id);
 static	void	ncr_negotiate	(struct ncb* np, struct tcb* tp);
-static	void	ncr_opennings	(ncb_p np, lcb_p lp, Scsi_Cmnd * xp);
 
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 static	void	ncb_profile	(ncb_p np, ccb_p cp);
@@ -1993,13 +2156,16 @@
 static	void	ncr_setmaxtags	(ncb_p np, tcb_p tp, u_long numtags);
 static	void	ncr_getsync	(ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p);
 static	void	ncr_setsync	(ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer);
-static	void	ncr_settags     (tcb_p tp, lcb_p lp);
+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	int	ncr_snooptest	(ncb_p np);
 static	void	ncr_timeout	(ncb_p np);
 static  void    ncr_wakeup      (ncb_p np, u_long code);
-static	void	ncr_start_reset	(ncb_p np, int settle_delay);
+static  void    ncr_wakeup_done (ncb_p np);
+static	void	ncr_start_next_ccb (ncb_p np, lcb_p lp, int maxn);
+static	void	ncr_put_start_queue(ncb_p np, ccb_p cp);
+static	void	ncr_start_reset	(ncb_p np);
 static	int	ncr_reset_scsi_bus (ncb_p np, int enab_int, int settle_delay);
 
 #ifdef SCSI_NCR_USER_COMMAND_SUPPORT
@@ -2088,38 +2254,17 @@
 
 static	struct script script0 __initdata = {
 /*--------------------------< START >-----------------------*/ {
-#if 0
 	/*
-	**	Claim to be still alive ...
+	**	This NOP will be patched with LED ON
+	**	SCR_REG_REG (gpreg, SCR_AND, 0xfe)
 	*/
-	SCR_COPY (sizeof (((struct ncb *)0)->heartbeat)),
-		KVAR(SCRIPT_KVAR_JIFFIES),
-		NADDR (heartbeat),
-#endif
+	SCR_NO_OP,
+		0,
 	/*
-	**      Make data structure address invalid.
-	**      clear SIGP.
+	**      Clear SIGP.
 	*/
-	SCR_LOAD_REG (dsa, 0xff),
-		0,
 	SCR_FROM_REG (ctest2),
 		0,
-}/*-------------------------< START0 >----------------------*/,{
-	/*
-	**	Hook for interrupted GetConditionCode.
-	**	Will be patched to ... IFTRUE by
-	**	the interrupt handler.
-	*/
-	SCR_INT ^ IFFALSE (0),
-		SIR_SENSE_RESTART,
-
-}/*-------------------------< START1 >----------------------*/,{
-	/*
-	**	Hook for stalled start queue.
-	**	Will be patched to IFTRUE by the interrupt handler.
-	*/
-	SCR_INT ^ IFFALSE (0),
-		SIR_STALL_RESTART,
 	/*
 	**	Then jump to a certain point in tryloop.
 	**	Due to the lack of indirect addressing the code
@@ -2128,76 +2273,6 @@
 	SCR_JUMP,
 }/*-------------------------< STARTPOS >--------------------*/,{
 		PADDRH(tryloop),
-}/*-------------------------< TRYSEL >----------------------*/,{
-	/*
-	**	Now:
-	**	DSA: Address of a Data Structure
-	**	or   Address of the IDLE-Label.
-	**
-	**	TEMP:	Address of a script, which tries to
-	**		start the NEXT entry.
-	**
-	**	Save the TEMP register into the SCRATCHA register.
-	**	Then copy the DSA to TEMP and RETURN.
-	**	This is kind of an indirect jump.
-	**	(The script processor has NO stack, so the
-	**	CALL is actually a jump and link, and the
-	**	RETURN is an indirect jump.)
-	**
-	**	If the slot was empty, DSA contains the address
-	**	of the IDLE part of this script. The processor
-	**	jumps to IDLE and waits for a reselect.
-	**	It will wake up and try the same slot again
-	**	after the SIGP bit becomes set by the host.
-	**
-	**	If the slot was not empty, DSA contains
-	**	the address of the phys-part of a ccb.
-	**	The processor jumps to this address.
-	**	phys starts with head,
-	**	head starts with launch,
-	**	so actually the processor jumps to
-	**	the lauch part.
-	**	If the entry is scheduled for execution,
-	**	then launch contains a jump to SELECT.
-	**	If it's not scheduled, it contains a jump to IDLE.
-	*/
-	SCR_COPY (4),
-		RADDR (temp),
-		RADDR (scratcha),
-	SCR_COPY (4),
-		RADDR (dsa),
-		RADDR (temp),
-	SCR_RETURN,
-		0
-
-}/*-------------------------< SKIP >------------------------*/,{
-	/*
-	**	This entry has been canceled.
-	**	Next time use the next slot.
-	*/
-	SCR_COPY (4),
-		RADDR (scratcha),
-		PADDR (startpos),
-	/*
-	**	patch the launch field.
-	**	should look like an idle process.
-	*/
-	SCR_COPY_F (4),
-		RADDR (dsa),
-		PADDR (skip2),
-	SCR_COPY (8),
-		PADDR (idle),
-}/*-------------------------< SKIP2 >-----------------------*/,{
-		0,
-	SCR_JUMP,
-		PADDR(start),
-}/*-------------------------< IDLE >------------------------*/,{
-	/*
-	**	Nothing to do?
-	**	Wait for reselect.
-	*/
-	SCR_JUMP,
-		PADDR(reselect),
 
 }/*-------------------------< SELECT >----------------------*/,{
 	/*
@@ -2214,7 +2289,7 @@
 
 	SCR_CLR (SCR_TRG),
 		0,
-	SCR_LOAD_REG (HS_REG, 0xff),
+	SCR_LOAD_REG (HS_REG, HS_SELECTING),
 		0,
 
 	/*
@@ -2223,6 +2298,7 @@
 	SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
 		PADDR (reselect),
 
+}/*-------------------------< SELECT2 >----------------------*/,{
 	/*
 	**	Now there are 4 possibilities:
 	**
@@ -2235,50 +2311,22 @@
 	**	Then the script processor takes the jump
 	**	to the RESELECT label.
 	**
-	**	(3) The ncr completes the selection.
-	**	Then it will execute the next statement.
-	**
-	**	(4) There is a selection timeout.
-	**	Then the ncr should interrupt the host and stop.
-	**	Unfortunately, it seems to continue execution
-	**	of the script. But it will fail with an
-	**	IID-interrupt on the next WHEN.
+	**	(3) The ncr wins arbitration.
+	**	Then it will execute SCRIPTS instruction until 
+	**	the next instruction that checks SCSI phase.
+	**	Then will stop and wait for selection to be 
+	**	complete or selection time-out to occur.
+	**	As a result the SCRIPTS instructions until 
+	**	LOADPOS + 2 should be executed in parallel with 
+	**	the SCSI core performing selection.
 	*/
 
-	SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_IN)),
-		0,
-
-	/*
-	**	Save target id to ctest0 register
-	*/
-
-	SCR_FROM_REG (sdid),
-		0,
-	SCR_TO_REG (ctest0),
-		0,
-	/*
-	**	Send the IDENTIFY and SIMPLE_TAG messages
-	**	(and the M_X_SYNC_REQ message)
-	*/
-	SCR_MOVE_TBL ^ SCR_MSG_OUT,
-		offsetof (struct dsb, smsg),
-#ifdef undef /* XXX better fail than try to deal with this ... */
-	SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_OUT)),
-		-16,
-#endif
-	SCR_CLR (SCR_ATN),
-		0,
-	SCR_COPY (1),
-		RADDR (sfbr),
-		NADDR (lastmsg),
 	/*
-	**	Selection complete.
 	**	Next time use the next slot.
 	*/
 	SCR_COPY (4),
-		RADDR (scratcha),
+		RADDR (temp),
 		PADDR (startpos),
-}/*-------------------------< PREPARE >----------------------*/,{
 	/*
 	**      The ncr doesn't have an indirect load
 	**	or store command. So we have to
@@ -2298,22 +2346,30 @@
 	/*
 	**	continued after the next label ...
 	*/
-
 }/*-------------------------< LOADPOS >---------------------*/,{
 		0,
 		NADDR (header),
 	/*
-	**      Mark this ccb as not scheduled.
+	**	Wait for the next phase or the selection
+	**	to complete or time-out.
 	*/
-	SCR_COPY (8),
-		PADDR (idle),
-		NADDR (header.launch),
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		PADDR (prepare),
+
+}/*-------------------------< SEND_IDENT >----------------------*/,{
 	/*
-	**      Set a time stamp for this selection
+	**	Selection complete.
+	**	Send the IDENTIFY and SIMPLE_TAG messages
+	**	(and the M_X_SYNC_REQ message)
 	*/
-	SCR_COPY (sizeof (u_long)),
-		KVAR(SCRIPT_KVAR_JIFFIES),
-		NADDR (header.stamp.select),
+	SCR_MOVE_TBL ^ SCR_MSG_OUT,
+		offsetof (struct dsb, smsg),
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+		PADDRH (resend_ident),
+	SCR_COPY (1),
+		RADDR (sfbr),
+		NADDR (lastmsg),
+}/*-------------------------< PREPARE >----------------------*/,{
 	/*
 	**      load the savep (saved pointer) into
 	**      the TEMP register (actual pointer)
@@ -2327,74 +2383,61 @@
 	SCR_COPY (4),
 		NADDR (header.status),
 		RADDR (scr0),
-
 }/*-------------------------< PREPARE2 >---------------------*/,{
 	/*
-	**      Load the synchronous mode register
-	*/
-	SCR_COPY (1),
-		NADDR (sync_st),
-		RADDR (sxfer),
-	/*
-	**      Load the wide mode and timing register
-	*/
-	SCR_COPY (1),
-		NADDR (wide_st),
-		RADDR (scntl3),
-	/*
-	**	Initialize the msgout buffer with a NOOP message.
+	**	Initialize the msgout buffer with a NOOP message.
 	*/
 	SCR_LOAD_REG (scratcha, M_NOOP),
 		0,
 	SCR_COPY (1),
 		RADDR (scratcha),
 		NADDR (msgout),
+#if 0
 	SCR_COPY (1),
 		RADDR (scratcha),
 		NADDR (msgin),
+#endif
 	/*
-	**	Message in phase ?
+	**	Anticipate the COMMAND phase.
+	**	This is the normal case for initial selection.
 	*/
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)),
 		PADDR (dispatch),
+
+}/*-------------------------< COMMAND >--------------------*/,{
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	/*
-	**	Extended or reject message ?
+	**	... set a timestamp ...
 	*/
-	SCR_FROM_REG (sbdl),
-		0,
-	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
-		PADDR (msg_in),
-	SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
-		PADDRH (msg_reject),
+	SCR_COPY (sizeof (u_long)),
+		KVAR(SCRIPT_KVAR_JIFFIES),
+		NADDR (header.stamp.command),
+#endif
 	/*
-	**	normal processing
+	**	... and send the command
 	*/
-	SCR_JUMP,
-		PADDR (dispatch),
-}/*-------------------------< SETMSG >----------------------*/,{
-	SCR_COPY (1),
-		RADDR (scratcha),
-		NADDR (msgout),
-	SCR_SET (SCR_ATN),
-		0,
-}/*-------------------------< CLRACK >----------------------*/,{
+	SCR_MOVE_TBL ^ SCR_COMMAND,
+		offsetof (struct dsb, cmd),
 	/*
-	**	Terminate possible pending message phase.
+	**	If status is still HS_NEGOTIATE, negotiation failed.
+	**	We check this here, since we want to do that 
+	**	only once.
 	*/
-	SCR_CLR (SCR_ACK),
-		0,
-
-}/*-----------------------< DISPATCH >----------------------*/,{
 	SCR_FROM_REG (HS_REG),
 		0,
 	SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
 		SIR_NEGO_FAILED,
+
+}/*-----------------------< DISPATCH >----------------------*/,{
 	/*
-	**	remove bogus output signals
+	**	MSG_IN is the only phase that shall be 
+	**	entered at least once for each (re)selection.
+	**	So we test it first.
 	*/
-	SCR_REG_REG (socl, SCR_AND, CACK|CATN),
-		0,
-	SCR_RETURN ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR (msg_in),
+
+	SCR_RETURN ^ IFTRUE (IF (SCR_DATA_OUT)),
 		0,
 	/*
 	**	DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 4.
@@ -2409,16 +2452,13 @@
 		RADDR (scratcha),
 		RADDR (scratcha),
 	SCR_RETURN,
-		0,
-
-	SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
-		PADDR (msg_out),
-	SCR_JUMP ^ IFTRUE (IF (SCR_MSG_IN)),
-		PADDR (msg_in),
-	SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
-		PADDR (command),
+ 		0,
 	SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
 		PADDR (status),
+	SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
+		PADDR (command),
+	SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
+		PADDR (msg_out),
 	/*
 	**      Discard one illegal phase byte, if required.
 	*/
@@ -2438,6 +2478,15 @@
 	SCR_JUMP,
 		PADDR (dispatch),
 
+}/*-------------------------< CLRACK >----------------------*/,{
+	/*
+	**	Terminate possible pending message phase.
+	*/
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP,
+		PADDR (dispatch),
+
 }/*-------------------------< NO_DATA >--------------------*/,{
 	/*
 	**	The target wants to tranfer too much data
@@ -2467,116 +2516,31 @@
 		PADDR (dispatch),
 	SCR_JUMP,
 		PADDR (no_data),
-}/*-------------------------< CHECKATN >--------------------*/,{
-	/*
-	**	If AAP (bit 1 of scntl0 register) is set
-	**	and a parity error is detected,
-	**	the script processor asserts ATN.
-	**
-	**	The target should switch to a MSG_OUT phase
-	**	to get the message.
-	*/
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFFALSE (MASK (CATN, CATN)),
-		PADDR (dispatch),
-	/*
-	**	count it
-	*/
-	SCR_REG_REG (PS_REG, SCR_ADD, 1),
-		0,
-	/*
-	**	Prepare a M_ID_ERROR message
-	**	(initiator detected error).
-	**	The target should retry the transfer.
-	*/
-	SCR_LOAD_REG (scratcha, M_ID_ERROR),
-		0,
-	SCR_JUMP,
-		PADDR (setmsg),
-
-}/*-------------------------< COMMAND >--------------------*/,{
-	/*
-	**	If this is not a GETCC transfer ...
-	*/
-	SCR_FROM_REG (SS_REG),
-		0,
-/*<<<*/	SCR_JUMPR ^ IFTRUE (DATA (S_CHECK_COND)),
-		28,
-	/*
-	**	... set a timestamp ...
-	*/
-	SCR_COPY (sizeof (u_long)),
-		KVAR(SCRIPT_KVAR_JIFFIES),
-		NADDR (header.stamp.command),
-	/*
-	**	... and send the command
-	*/
-	SCR_MOVE_TBL ^ SCR_COMMAND,
-		offsetof (struct dsb, cmd),
-	SCR_JUMP,
-		PADDR (dispatch),
-	/*
-	**	Send the GETCC command
-	*/
-/*>>>*/	SCR_MOVE_TBL ^ SCR_COMMAND,
-		offsetof (struct dsb, scmd),
-	SCR_JUMP,
-		PADDR (dispatch),
 
 }/*-------------------------< STATUS >--------------------*/,{
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	/*
 	**	set the timestamp.
 	*/
 	SCR_COPY (sizeof (u_long)),
 		KVAR(SCRIPT_KVAR_JIFFIES),
 		NADDR (header.stamp.status),
-	/*
-	**	If this is a GETCC transfer,
-	*/
-	SCR_FROM_REG (SS_REG),
-		0,
-/*<<<*/	SCR_JUMPR ^ IFFALSE (DATA (S_CHECK_COND)),
-		40,
+#endif
 	/*
 	**	get the status
 	*/
 	SCR_MOVE_ABS (1) ^ SCR_STATUS,
 		NADDR (scratch),
 	/*
-	**	Save status to scsi_status.
-	**	Mark as complete.
-	**	And wait for disconnect.
-	*/
-	SCR_TO_REG (SS_REG),
-		0,
-	SCR_REG_REG (SS_REG, SCR_OR, S_SENSE),
-		0,
-	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
-		0,
-	SCR_JUMP,
-		PADDR (checkatn),
-	/*
-	**	If it was no GETCC transfer,
-	**	save the status to scsi_status.
+	**	save status to scsi_status.
+	**	mark as complete.
 	*/
-/*>>>*/	SCR_MOVE_ABS (1) ^ SCR_STATUS,
-		NADDR (scratch),
 	SCR_TO_REG (SS_REG),
 		0,
-	/*
-	**	if it was no check condition ...
-	*/
-	SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)),
-		PADDR (checkatn),
-	/*
-	**	... mark as complete.
-	*/
 	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
 		0,
 	SCR_JUMP,
-		PADDR (checkatn),
-
+		PADDR (dispatch),
 }/*-------------------------< MSG_IN >--------------------*/,{
 	/*
 	**	Get the first byte of the message
@@ -2587,28 +2551,18 @@
 	*/
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
 		NADDR (msgin[0]),
+}/*-------------------------< MSG_IN2 >--------------------*/,{
 	/*
-	**	Check for message parity error.
-	*/
-	SCR_TO_REG (scratcha),
-		0,
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDRH (msg_parity),
-	SCR_FROM_REG (scratcha),
-		0,
-	/*
-	**	Parity was ok, handle this message.
+	**	Handle this message.
 	*/
 	SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
 		PADDR (complete),
+	SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
+		PADDR (disconnect),
 	SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)),
 		PADDR (save_dp),
 	SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
 		PADDR (restore_dp),
-	SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
-		PADDR (disconnect),
 	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
 		PADDRH (msg_extended),
 	SCR_JUMP ^ IFTRUE (DATA (M_NOOP)),
@@ -2632,24 +2586,42 @@
 		SIR_REJECT_SENT,
 	SCR_LOAD_REG (scratcha, M_REJECT),
 		0,
+}/*-------------------------< SETMSG >----------------------*/,{
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (msgout),
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_JUMP,
+		PADDR (clrack),
+}/*-------------------------< CLEANUP >-------------------*/,{
+	/*
+	**      dsa:    Pointer to ccb
+	**	      or xxxxxxFF (no ccb)
+	**
+	**      HS_REG:   Host-Status (<>0!)
+	*/
+	SCR_FROM_REG (dsa),
+		0,
+	SCR_JUMP ^ IFTRUE (DATA (0xff)),
+		PADDR (start),
+	/*
+	**      dsa is valid.
+	**	complete the cleanup.
+	*/
 	SCR_JUMP,
-		PADDR (setmsg),
+		PADDR (cleanup_ok),
 
 }/*-------------------------< COMPLETE >-----------------*/,{
 	/*
 	**	Complete message.
 	**
-	**	If it's not the get condition code,
-	**	copy TEMP register to LASTP in header.
+	**	Copy TEMP register to LASTP in header.
 	*/
-	SCR_FROM_REG (SS_REG),
-		0,
-/*<<<*/	SCR_JUMPR ^ IFTRUE (MASK (S_SENSE, S_SENSE)),
-		12,
 	SCR_COPY (4),
 		RADDR (temp),
 		NADDR (header.lastp),
-/*>>>*/	/*
+	/*
 	**	When we terminate the cycle by clearing ACK,
 	**	the target may disconnect immediately.
 	**
@@ -2669,20 +2641,9 @@
 	*/
 	SCR_WAIT_DISC,
 		0,
-}/*-------------------------< CLEANUP >-------------------*/,{
-	/*
-	**      dsa:    Pointer to ccb
-	**	      or xxxxxxFF (no ccb)
-	**
-	**      HS_REG:   Host-Status (<>0!)
-	*/
-	SCR_FROM_REG (dsa),
-		0,
-	SCR_JUMP ^ IFTRUE (DATA (0xff)),
-		PADDR (signal),
+}/*-------------------------< CLEANUP_OK >----------------*/,{
 	/*
-	**      dsa is valid.
-	**	save the status registers
+	**	Save host status to header.
 	*/
 	SCR_COPY (4),
 		RADDR (scr0),
@@ -2697,43 +2658,32 @@
 		NADDR (header),
 }/*-------------------------< CLEANUP0 >--------------------*/,{
 		0,
-
+}/*-------------------------< SIGNAL >----------------------*/,{
 	/*
-	**	If command resulted in "check condition"
-	**	status and is not yet completed,
-	**	try to get the condition code.
+	**	if job not completed ...
 	*/
 	SCR_FROM_REG (HS_REG),
 		0,
-/*<<<*/	SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)),
-		16,
-	SCR_FROM_REG (SS_REG),
-		0,
-	SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)),
-		PADDRH(getcc2),
 	/*
-	**	And make the DSA register invalid.
+	**	... start the next command.
 	*/
-/*>>>*/	SCR_LOAD_REG (dsa, 0xff), /* invalid */
-		0,
-}/*-------------------------< SIGNAL >----------------------*/,{
+	SCR_JUMP ^ IFTRUE (MASK (0, (HS_DONEMASK|HS_SKIPMASK))),
+		PADDR(start),
 	/*
-	**	if status = queue full,
-	**	reinsert in startqueue and stall queue.
+	**	If command resulted in not GOOD status,
+	**	call the C code if needed.
 	*/
 	SCR_FROM_REG (SS_REG),
 		0,
-	SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)),
-		SIR_STALL_QUEUE,
-	/*
-	**	if job completed ...
-	*/
-	SCR_FROM_REG (HS_REG),
-		0,
+	SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
+		PADDRH (bad_status),
+
+#ifndef	SCSI_NCR_CCB_DONE_SUPPORT
+
 	/*
 	**	... signal completion to the host
 	*/
-	SCR_INT_FLY ^ IFFALSE (MASK (0, HS_DONEMASK)),
+	SCR_INT_FLY,
 		0,
 	/*
 	**	Auf zu neuen Schandtaten!
@@ -2741,6 +2691,28 @@
 	SCR_JUMP,
 		PADDR(start),
 
+#else	/* defined SCSI_NCR_CCB_DONE_SUPPORT */
+
+	/*
+	**	... signal completion to the host
+	*/
+	SCR_JUMP,
+}/*------------------------< DONE_POS >---------------------*/,{
+		PADDRH (done_queue),
+}/*------------------------< DONE_PLUG >--------------------*/,{
+	SCR_INT,
+		SIR_DONE_OVERFLOW,
+}/*------------------------< DONE_END >---------------------*/,{
+	SCR_INT_FLY,
+		0,
+	SCR_COPY (4),
+		RADDR (temp),
+		PADDR (done_pos),
+	SCR_JUMP,
+		PADDR (start),
+
+#endif	/* SCSI_NCR_CCB_DONE_SUPPORT */
+
 }/*-------------------------< SAVE_DP >------------------*/,{
 	/*
 	**	SAVE_DP message:
@@ -2749,8 +2721,10 @@
 	SCR_COPY (4),
 		RADDR (temp),
 		NADDR (header.savep),
+	SCR_CLR (SCR_ACK),
+		0,
 	SCR_JUMP,
-		PADDR (clrack),
+		PADDR (dispatch),
 }/*-------------------------< RESTORE_DP >---------------*/,{
 	/*
 	**	RESTORE_DP message:
@@ -2764,56 +2738,6 @@
 
 }/*-------------------------< DISCONNECT >---------------*/,{
 	/*
-	**	If QUIRK_AUTOSAVE is set,
-	**	do an "save pointer" operation.
-	*/
-	SCR_FROM_REG (QU_REG),
-		0,
-/*<<<*/	SCR_JUMPR ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)),
-		12,
-	/*
-	**	like SAVE_DP message:
-	**	Copy TEMP register to SAVEP in header.
-	*/
-	SCR_COPY (4),
-		RADDR (temp),
-		NADDR (header.savep),
-/*>>>*/	/*
-	**	Check if temp==savep or temp==goalp:
-	**	if not, log a missing save pointer message.
-	**	In fact, it's a comparison mod 256.
-	**
-	**	Hmmm, I hadn't thought that I would be urged to
-	**	write this kind of ugly self modifying code.
-	**
-	**	It's unbelievable, but the ncr53c8xx isn't able
-	**	to subtract one register from another.
-	*/
-	SCR_FROM_REG (temp),
-		0,
-	/*
-	**	You are not expected to understand this ..
-	**
-	**	CAUTION: only little endian architectures supported! XXX
-	*/
-	SCR_COPY_F (1),
-		NADDR (header.savep),
-		PADDR (disconnect0),
-}/*-------------------------< DISCONNECT0 >--------------*/,{
-/*<<<*/	SCR_JUMPR ^ IFTRUE (DATA (1)),
-		20,
-	/*
-	**	neither this
-	*/
-	SCR_COPY_F (1),
-		NADDR (header.goalp),
-		PADDR (disconnect1),
-}/*-------------------------< DISCONNECT1 >--------------*/,{
-	SCR_INT ^ IFFALSE (DATA (1)),
-		SIR_MISSING_SAVE,
-/*>>>*/
-
-	/*
 	**	DISCONNECTing  ...
 	**
 	**	disable the "unexpected disconnect" feature,
@@ -2828,6 +2752,7 @@
 	*/
 	SCR_WAIT_DISC,
 		0,
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	/*
 	**	Profiling:
 	**	Set a time stamp,
@@ -2838,19 +2763,35 @@
 		NADDR (header.stamp.disconnect),
 	SCR_COPY (4),
 		NADDR (disc_phys),
-		RADDR (temp),
-	SCR_REG_REG (temp, SCR_ADD, 0x01),
+		RADDR (scratcha),
+	SCR_REG_REG (scratcha, SCR_ADD, 0x01),
 		0,
 	SCR_COPY (4),
-		RADDR (temp),
+		RADDR (scratcha),
 		NADDR (disc_phys),
+#endif
 	/*
 	**	Status is: DISCONNECTED.
 	*/
 	SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
 		0,
+	/*
+	**	If QUIRK_AUTOSAVE is set,
+	**	do an "save pointer" operation.
+	*/
+	SCR_FROM_REG (QU_REG),
+		0,
+	SCR_JUMP ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)),
+		PADDR (cleanup_ok),
+	/*
+	**	like SAVE_DP message:
+	**	Copy TEMP register to SAVEP in header.
+	*/
+	SCR_COPY (4),
+		RADDR (temp),
+		NADDR (header.savep),
 	SCR_JUMP,
-		PADDR (cleanup),
+		PADDR (cleanup_ok),
 
 }/*-------------------------< MSG_OUT >-------------------*/,{
 	/*
@@ -2886,23 +2827,16 @@
 	*/
 	SCR_JUMP,
 		PADDR (dispatch),
-}/*------------------------< BADGETCC >---------------------*/,{
-	/*
-	**	If SIGP was set, clear it and try again.
-	*/
-	SCR_FROM_REG (ctest2),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)),
-		PADDRH (getcc2),
-	SCR_INT,
-		SIR_SENSE_FAILED,
-}/*-------------------------< RESELECT >--------------------*/,{
+}/*-------------------------< IDLE >------------------------*/,{
 	/*
+	**	Nothing to do?
+	**	Wait for reselect.
 	**	This NOP will be patched with LED OFF
 	**	SCR_REG_REG (gpreg, SCR_OR, 0x01)
 	*/
 	SCR_NO_OP,
 		0,
+}/*-------------------------< RESELECT >--------------------*/,{
 	/*
 	**	make the DSA invalid.
 	*/
@@ -2910,6 +2844,8 @@
 		0,
 	SCR_CLR (SCR_TRG),
 		0,
+	SCR_LOAD_REG (HS_REG, HS_IN_RESELECT),
+		0,
 	/*
 	**	Sleep waiting for a reselection.
 	**	If SIGP is set, special treatment.
@@ -2917,8 +2853,8 @@
 	**	Zu allem bereit ..
 	*/
 	SCR_WAIT_RESEL,
-		PADDR(reselect2),
-}/*-------------------------< RESELECT1 >--------------------*/,{
+		PADDR(start),
+}/*-------------------------< RESELECTED >------------------*/,{
 	/*
 	**	This NOP will be patched with LED ON
 	**	SCR_REG_REG (gpreg, SCR_AND, 0xfe)
@@ -2940,38 +2876,51 @@
 	*/
 	SCR_REG_SFBR (ssid, SCR_AND, 0x8F),
 		0,
-	SCR_TO_REG (ctest0),
+	SCR_TO_REG (sdid),
 		0,
 	SCR_JUMP,
 		NADDR (jump_tcb),
-}/*-------------------------< RESELECT2 >-------------------*/,{
+
+}/*-------------------------< RESEL_DSA >-------------------*/,{
 	/*
-	**	This NOP will be patched with LED ON
-	**	SCR_REG_REG (gpreg, SCR_AND, 0xfe)
+	**	Ack the IDENTIFY or TAG previously received.
 	*/
-	SCR_NO_OP,
+	SCR_CLR (SCR_ACK),
 		0,
 	/*
-	**	If it's not connected :(
-	**	-> interrupted by SIGP bit.
-	**	Jump to start.
+	**      The ncr doesn't have an indirect load
+	**	or store command. So we have to
+	**	copy part of the control block to a
+	**	fixed place, where we can access it.
+	**
+	**	We patch the address part of a
+	**	COPY command with the DSA-register.
+	*/
+	SCR_COPY_F (4),
+		RADDR (dsa),
+		PADDR (loadpos1),
+	/*
+	**	then we do the actual copy.
+	*/
+	SCR_COPY (sizeof (struct head)),
+	/*
+	**	continued after the next label ...
 	*/
-	SCR_FROM_REG (ctest2),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)),
-		PADDR (start),
-	SCR_JUMP,
-		PADDR (reselect),
 
-}/*-------------------------< RESEL_TMP >-------------------*/,{
+}/*-------------------------< LOADPOS1 >-------------------*/,{
+		0,
+		NADDR (header),
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	/*
-	**	The return address in TEMP
-	**	is in fact the data structure address,
-	**	so copy it to the DSA register.
+	**      Set a time stamp for this reselection
+	*/
+	SCR_COPY (sizeof (u_long)),
+		KVAR(SCRIPT_KVAR_JIFFIES),
+		NADDR (header.stamp.reselect),
+#endif
+	/*
+	**	The DSA contains the data structure address.
 	*/
-	SCR_COPY (4),
-		RADDR (temp),
-		RADDR (dsa),
 	SCR_JUMP,
 		PADDR (prepare),
 
@@ -2981,133 +2930,123 @@
 	**	to get an IDENTIFY message
 	**	Wait for a msg_in phase.
 	*/
-/*<<<*/	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		48,
+	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		SIR_RESEL_NO_MSG_IN,
 	/*
-	**	message phase
-	**	It's not a sony, it's a trick:
-	**	read the data without acknowledging it.
+	**	message phase.
+	**	Read the data directly from the BUS DATA lines.
+	**	This helps to support very old SCSI devices that 
+	**	may reselect without sending an IDENTIFY.
 	*/
 	SCR_FROM_REG (sbdl),
 		0,
-/*<<<*/	SCR_JUMPR ^ IFFALSE (MASK (M_IDENTIFY, 0x98)),
-		32,
 	/*
-	**	It WAS an Identify message.
-	**	get it and ack it!
+	**	It should be an Identify message.
 	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin),
-	SCR_CLR (SCR_ACK),
-		0,
-	/*
-	**	Mask out the lun.
-	*/
-	SCR_REG_REG (sfbr, SCR_AND, 0x07),
-		0,
-	SCR_RETURN,
-		0,
-	/*
-	**	No message phase or no IDENTIFY message:
-	**	return 0.
-	*/
-/*>>>*/	SCR_LOAD_SFBR (0),
-		0,
 	SCR_RETURN,
 		0,
-
 }/*-------------------------< RESEL_TAG >-------------------*/,{
 	/*
-	**	come back to this point
-	**	to get a SIMPLE_TAG message
-	**	Wait for a MSG_IN phase.
+	**	Read IDENTIFY + SIMPLE + TAG using a single MOVE.
+	**	Agressive optimization, is'nt it?
+	**	No need to test the SIMPLE TAG message, since the 
+	**	driver only supports conformant devices for tags. ;-)
 	*/
-/*<<<*/	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		64,
+	SCR_MOVE_ABS (3) ^ SCR_MSG_IN,
+		NADDR (msgin),
 	/*
-	**	message phase
-	**	It's a trick - read the data
-	**	without acknowledging it.
+	**	Read the TAG from the SIDL.
+	**	Still an aggressive optimization. ;-)
 	*/
-	SCR_FROM_REG (sbdl),
+	SCR_FROM_REG (sidl),
 		0,
-/*<<<*/	SCR_JUMPR ^ IFFALSE (DATA (M_SIMPLE_TAG)),
-		48,
 	/*
-	**	It WAS a SIMPLE_TAG message.
-	**	get it and ack it!
+	**	JUMP indirectly to the restart point of the CCB.
 	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin),
-	SCR_CLR (SCR_ACK),
+#if SCSI_NCR_MAX_TAGS <= 32
+	SCR_SFBR_REG (temp, SCR_AND, 0xf8),
 		0,
-	/*
-	**	Wait for the second byte (the tag)
-	*/
-/*<<<*/	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		24,
-	/*
-	**	Get it and ack it!
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin),
-	SCR_CLR (SCR_ACK|SCR_CARRY),
+	SCR_RETURN,
+		0,
+#else
+	SCR_SFBR_REG (temp, SCR_AND, 0xfc),
+		0,
+}/*-------------------------< JUMP_TO_NEXUS >-------------------*/,{
+	SCR_COPY_F (4),
+		RADDR (temp),
+		PADDR (nexus_indirect),
+	SCR_COPY (4),
+}/*-------------------------< NEXUS_INDIRECT >-------------------*/,{
 		0,
+		RADDR (temp),
 	SCR_RETURN,
 		0,
+#endif
+}/*-------------------------< RESEL_NOTAG >-------------------*/,{
 	/*
-	**	No message phase or no SIMPLE_TAG message
-	**	or no second byte: return 0.
+	**	No tag expected.
+	**	Read an throw away the IDENTIFY.
 	*/
-/*>>>*/	SCR_LOAD_SFBR (0),
-		0,
-	SCR_SET (SCR_CARRY),
-		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin),
+#if SCSI_NCR_MAX_TAGS <= 32
 	SCR_RETURN,
 		0,
-
-}/*-------------------------< DATA_IO >--------------------*/,{
-/*
-**	Because Linux does not provide xfer data direction 
-**	to low-level scsi drivers, we must trust the target 
-**	for actual data direction when we cannot guess it.
-**	The programmed interrupt patches savep, lastp, goalp,
-**	etc.., and restarts the scsi script at data_out/in.
-*/
-	SCR_INT ^ IFTRUE (WHEN (SCR_DATA_OUT)),
-		SIR_DATA_IO_IS_OUT,
-	SCR_INT ^ IFTRUE (WHEN (SCR_DATA_IN)),
-		SIR_DATA_IO_IS_IN,
+#else
 	SCR_JUMP,
-		PADDR (no_data),
-
+		PADDR (jump_to_nexus),
+#endif
 }/*-------------------------< DATA_IN >--------------------*/,{
 /*
 **	Because the size depends on the
-**	#define MAX_SCATTER parameter,
+**	#define MAX_SCATTERL parameter,
 **	it is filled in at runtime.
 **
-**  ##===========< i=0; i<MAX_SCATTER >=========
+**  ##===========< i=0; i<MAX_SCATTERL >=========
 **  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
-**  ||		PADDR (checkatn),
+**  ||		PADDR (dispatch),
 **  ||	SCR_MOVE_TBL ^ SCR_DATA_IN,
 **  ||		offsetof (struct dsb, data[ i]),
 **  ##==========================================
 **
-**	SCR_CALL,
-**		PADDR (checkatn),
-**	SCR_JUMP,
-**		PADDR (no_data),
+**---------------------------------------------------------
+*/
+0
+}/*-------------------------< DATA_IN2 >-------------------*/,{
+	SCR_CALL,
+		PADDR (dispatch),
+	SCR_JUMP,
+		PADDR (no_data),
+}/*-------------------------< DATA_OUT >--------------------*/,{
+/*
+**	Because the size depends on the
+**	#define MAX_SCATTERL parameter,
+**	it is filled in at runtime.
+**
+**  ##===========< i=0; i<MAX_SCATTERL >=========
+**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+**  ||		PADDR (dispatch),
+**  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+**  ||		offsetof (struct dsb, data[ i]),
+**  ##==========================================
+**
+**---------------------------------------------------------
 */
 0
+}/*-------------------------< DATA_OUT2 >-------------------*/,{
+	SCR_CALL,
+		PADDR (dispatch),
+	SCR_JUMP,
+		PADDR (no_data),
 }/*--------------------------------------------------------*/
 };
 
 static	struct scripth scripth0 __initdata = {
 /*-------------------------< TRYLOOP >---------------------*/{
 /*
-**	Load an entry of the start queue into dsa
-**	and try to start it by jumping to TRYSEL.
+**	Start the next entry.
+**	Called addresses point to the launch script in the CCB.
+**	They are patched by the main processor.
 **
 **	Because the size depends on the
 **	#define MAX_START parameter, it is filled
@@ -3116,32 +3055,142 @@
 **-----------------------------------------------------------
 **
 **  ##===========< I=0; i<MAX_START >===========
-**  ||	SCR_COPY (4),
-**  ||		NADDR (squeue[i]),
-**  ||		RADDR (dsa),
 **  ||	SCR_CALL,
-**  ||		PADDR (trysel),
+**  ||		PADDR (idle),
 **  ##==========================================
 **
-**	SCR_JUMP,
-**		PADDRH(tryloop),
+**-----------------------------------------------------------
+*/
+0
+}/*------------------------< TRYLOOP2 >---------------------*/,{
+	SCR_JUMP,
+		PADDRH(tryloop),
+
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+
+}/*------------------------< DONE_QUEUE >-------------------*/,{
+/*
+**	Copy the CCB address to the next done entry.
+**	Because the size depends on the
+**	#define MAX_DONE parameter, it is filled
+**	in at runtime.
+**
+**-----------------------------------------------------------
+**
+**  ##===========< I=0; i<MAX_DONE >===========
+**  ||	SCR_COPY (sizeof(ccb_p)),
+**  ||		NADDR (header.cp),
+**  ||		NADDR (ccb_done[i]),
+**  ||	SCR_CALL,
+**  ||		PADDR (done_end),
+**  ##==========================================
 **
 **-----------------------------------------------------------
 */
 0
-},/*-------------------------< MSG_PARITY >---------------*/{
+}/*------------------------< DONE_QUEUE2 >------------------*/,{
+	SCR_JUMP,
+		PADDRH (done_queue),
+
+#endif /* SCSI_NCR_CCB_DONE_SUPPORT */
+}/*------------------------< SELECT_NO_ATN >-----------------*/,{
 	/*
-	**	count it
+	**	Set Initiator mode.
+	**      And try to select this target without ATN.
 	*/
-	SCR_REG_REG (PS_REG, SCR_ADD, 0x01),
+
+	SCR_CLR (SCR_TRG),
+		0,
+	SCR_LOAD_REG (HS_REG, HS_SELECTING),
+		0,
+	SCR_SEL_TBL ^ offsetof (struct dsb, select),
+		PADDR (reselect),
+	SCR_JUMP,
+		PADDR (select2),
+
+}/*-------------------------< CANCEL >------------------------*/,{
+
+	SCR_LOAD_REG (scratcha, HS_ABORTED),
+		0,
+	SCR_JUMPR,
+		8,
+}/*-------------------------< SKIP >------------------------*/,{
+	SCR_LOAD_REG (scratcha, 0),
 		0,
 	/*
-	**	send a "message parity error" message.
+	**	This entry has been canceled.
+	**	Next time use the next slot.
 	*/
-	SCR_LOAD_REG (scratcha, M_PARITY),
+	SCR_COPY (4),
+		RADDR (temp),
+		PADDR (startpos),
+	/*
+	**      The ncr doesn't have an indirect load
+	**	or store command. So we have to
+	**	copy part of the control block to a
+	**	fixed place, where we can access it.
+	**
+	**	We patch the address part of a
+	**	COPY command with the DSA-register.
+	*/
+	SCR_COPY_F (4),
+		RADDR (dsa),
+		PADDRH (skip2),
+	/*
+	**	then we do the actual copy.
+	*/
+	SCR_COPY (sizeof (struct head)),
+	/*
+	**	continued after the next label ...
+	*/
+}/*-------------------------< SKIP2 >---------------------*/,{
 		0,
+		NADDR (header),
+	/*
+	**      Initialize the status registers
+	*/
+	SCR_COPY (4),
+		NADDR (header.status),
+		RADDR (scr0),
+	/*
+	**	Force host status.
+	*/
+	SCR_FROM_REG (scratcha),
+		0,
+	SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)),
+		16,
+	SCR_REG_REG (HS_REG, SCR_OR, HS_SKIPMASK),
+		0,
+	SCR_JUMPR,
+		8,
+	SCR_TO_REG (HS_REG),
+		0,
+	SCR_LOAD_REG (SS_REG, S_GOOD),
+		0,
+	SCR_JUMP,
+		PADDR (cleanup_ok),
+
+},/*-------------------------< PAR_ERR_DATA_IN >---------------*/{
+	/*
+	**	Ignore all data in byte, until next phase
+	*/
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+		PADDRH (par_err_other),
+	SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
+		NADDR (scratch),
+	SCR_JUMPR,
+		-24,
+},/*-------------------------< PAR_ERR_OTHER >------------------*/{
+	/*
+	**	count it.
+	*/
+	SCR_REG_REG (PS_REG, SCR_ADD, 0x01),
+		0,
+	/*
+	**	jump to dispatcher.
+	*/
 	SCR_JUMP,
-		PADDR (setmsg),
+		PADDR (dispatch),
 }/*-------------------------< MSG_REJECT >---------------*/,{
 	/*
 	**	If a negotiation was in progress,
@@ -3173,17 +3222,6 @@
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
 		NADDR (msgin[1]),
 	/*
-	**	Check for message parity error.
-	*/
-	SCR_TO_REG (scratcha),
-		0,
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDRH (msg_parity),
-	SCR_FROM_REG (scratcha),
-		0,
-	/*
 	**	Size is 0 .. ignore message.
 	*/
 	SCR_JUMP ^ IFTRUE (DATA (0)),
@@ -3191,14 +3229,14 @@
 	/*
 	**	Size is not 1 .. have to interrupt.
 	*/
-/*<<<*/	SCR_JUMPR ^ IFFALSE (DATA (1)),
+	SCR_JUMPR ^ IFFALSE (DATA (1)),
 		40,
 	/*
 	**	Check for residue byte in swide register
 	*/
 	SCR_FROM_REG (scntl2),
 		0,
-/*<<<*/	SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
+	SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
 		16,
 	/*
 	**	There IS data in the swide register.
@@ -3211,9 +3249,9 @@
 	/*
 	**	Load again the size to the sfbr register.
 	*/
-/*>>>*/	SCR_FROM_REG (scratcha),
+	SCR_FROM_REG (scratcha),
 		0,
-/*>>>*/	SCR_INT,
+	SCR_INT,
 		SIR_IGN_RESIDUE,
 	SCR_JUMP,
 		PADDR (clrack),
@@ -3232,17 +3270,6 @@
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
 		NADDR (msgin[1]),
 	/*
-	**	Check for message parity error.
-	*/
-	SCR_TO_REG (scratcha),
-		0,
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDRH (msg_parity),
-	SCR_FROM_REG (scratcha),
-		0,
-	/*
 	*/
 	SCR_JUMP ^ IFTRUE (DATA (3)),
 		PADDRH (msg_ext_3),
@@ -3258,17 +3285,6 @@
 	*/
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
 		NADDR (msgin[2]),
-	/*
-	**	Check for message parity error.
-	*/
-	SCR_TO_REG (scratcha),
-		0,
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDRH (msg_parity),
-	SCR_FROM_REG (scratcha),
-		0,
 	SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)),
 		PADDRH (msg_wdtr),
 	/*
@@ -3286,10 +3302,6 @@
 	*/
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
 		NADDR (msgin[3]),
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDRH (msg_parity),
 	/*
 	**	let the host do the real work.
 	*/
@@ -3303,15 +3315,15 @@
 	SCR_CLR (SCR_ACK),
 		0,
 
+/* CHECK THE SOURCE FOR 'send_wdtr' IF YOU INTEND TO CHANGE SOMETHING HERE */
 	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
 		SIR_NEGO_PROTO,
+}/*-------------------------< SEND_WDTR >----------------*/,{
 	/*
 	**	Send the M_X_WIDE_REQ
 	*/
 	SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
 		NADDR (msgout),
-	SCR_CLR (SCR_ATN),
-		0,
 	SCR_COPY (1),
 		RADDR (sfbr),
 		NADDR (lastmsg),
@@ -3328,17 +3340,6 @@
 	*/
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
 		NADDR (msgin[2]),
-	/*
-	**	Check for message parity error.
-	*/
-	SCR_TO_REG (scratcha),
-		0,
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDRH (msg_parity),
-	SCR_FROM_REG (scratcha),
-		0,
 	SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)),
 		PADDRH (msg_sdtr),
 	/*
@@ -3357,10 +3358,6 @@
 	*/
 	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
 		NADDR (msgin[3]),
-	SCR_FROM_REG (socl),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)),
-		PADDRH (msg_parity),
 	/*
 	**	let the host do the real work.
 	*/
@@ -3374,15 +3371,15 @@
 	SCR_CLR (SCR_ACK),
 		0,
 
+/* CHECK THE SOURCE FOR 'send_sdtr' IF YOU INTEND TO CHANGE SOMETHING HERE */
 	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
 		SIR_NEGO_PROTO,
+}/*-------------------------< SEND_SDTR >-------------*/,{
 	/*
 	**	Send the M_X_SYNC_REQ
 	*/
 	SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
 		NADDR (msgout),
-	SCR_CLR (SCR_ATN),
-		0,
 	SCR_COPY (1),
 		RADDR (sfbr),
 		NADDR (lastmsg),
@@ -3409,203 +3406,259 @@
 	SCR_JUMP,
 		PADDR (cleanup),
 
-}/*-------------------------< GETCC >-----------------------*/,{
+}/*-------------------------< 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 (dispatch),
+**  ||	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 (dispatch),
+**  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+**  ||		offsetof (struct dsb, data[ i]),
+**  ##===================================================
+**
+**---------------------------------------------------------
+*/
+0
+}/*-------------------------< HDATA_OUT2 >------------------*/,{
+	SCR_JUMP,
+		PADDR (data_out),
+
+}/*-------------------------< RESET >----------------------*/,{
 	/*
-	**	The ncr doesn't have an indirect load
-	**	or store command. So we have to
-	**	copy part of the control block to a
-	**	fixed place, where we can modify it.
-	**
-	**	We patch the address part of a COPY command
-	**	with the address of the dsa register ...
+	**      Send a M_RESET message if bad IDENTIFY 
+	**	received on reselection.
 	*/
-	SCR_COPY_F (4),
-		RADDR (dsa),
-		PADDRH (getcc1),
+	SCR_LOAD_REG (scratcha, M_ABORT_TAG),
+		0,
+	SCR_JUMP,
+		PADDRH (abort_resel),
+}/*-------------------------< ABORTTAG >-------------------*/,{
 	/*
-	**	... then we do the actual copy.
+	**      Abort a wrong tag received on reselection.
 	*/
-	SCR_COPY (sizeof (struct head)),
-}/*-------------------------< GETCC1 >----------------------*/,{
+	SCR_LOAD_REG (scratcha, M_ABORT_TAG),
 		0,
-		NADDR (header),
+	SCR_JUMP,
+		PADDRH (abort_resel),
+}/*-------------------------< ABORT >----------------------*/,{
 	/*
-	**	Initialize the status registers
+	**      Abort a reselection when no active CCB.
 	*/
-	SCR_COPY (4),
-		NADDR (header.status),
-		RADDR (scr0),
-}/*-------------------------< GETCC2 >----------------------*/,{
+	SCR_LOAD_REG (scratcha, M_ABORT),
+		0,
+}/*-------------------------< ABORT_RESEL >----------------*/,{
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (msgout),
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
 	/*
-	**	Get the condition code from a target.
-	**
-	**	DSA points to a data structure.
-	**	Set TEMP to the script location
-	**	that receives the condition code.
-	**
-	**	Because there is no script command
-	**	to load a longword into a register,
-	**	we use a CALL command.
+	**	and send it.
+	**	we expect an immediate disconnect
 	*/
-/*<<<*/	SCR_CALLR,
-		24,
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+		NADDR (msgout),
+	SCR_COPY (1),
+		RADDR (sfbr),
+		NADDR (lastmsg),
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	SCR_WAIT_DISC,
+		0,
+	SCR_JUMP,
+		PADDR (start),
+}/*-------------------------< RESEND_IDENT >-------------------*/,{
 	/*
-	**	Get the condition code.
+	**	The target stays in MSG OUT phase after having acked 
+	**	Identify [+ Tag [+ Extended message ]]. Targets shall
+	**	behave this way on parity error.
+	**	We must send it again all the messages.
 	*/
+	SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the  */
+		0,         /* 1rst ACK = 90 ns. Hope the NCR is'nt too fast */
+	SCR_JUMP,
+		PADDR (send_ident),
+}/*-------------------------< CLRATN_GO_ON >-------------------*/,{
+	SCR_CLR (SCR_ATN),
+		0,
+	SCR_JUMP,
+}/*-------------------------< NXTDSP_GO_ON >-------------------*/,{
+		0,
+}/*-------------------------< SDATA_IN >-------------------*/,{
+	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
+		PADDR (dispatch),
 	SCR_MOVE_TBL ^ SCR_DATA_IN,
 		offsetof (struct dsb, sense),
-	/*
-	**	No data phase may follow!
-	*/
 	SCR_CALL,
-		PADDR (checkatn),
+		PADDR (dispatch),
 	SCR_JUMP,
 		PADDR (no_data),
-/*>>>*/
-
+}/*-------------------------< DATA_IO >--------------------*/,{
 	/*
-	**	The CALL jumps to this point.
-	**	Prepare for a RESTORE_POINTER message.
-	**	Save the TEMP register into the saved pointer.
+	**	We jump here if the data direction was unknown at the 
+	**	time we had to queue the command to the scripts processor.
+	**	Pointers had been set as follow in this situation:
+	**	  savep   -->   DATA_IO
+	**	  lastp   -->   start pointer when DATA_IN
+	**	  goalp   -->   goal  pointer when DATA_IN
+	**	  wlastp  -->   start pointer when DATA_OUT
+	**	  wgoalp  -->   goal  pointer when DATA_OUT
+	**	This script sets savep/lastp/goalp according to the 
+	**	direction chosen by the target.
 	*/
-	SCR_COPY (4),
-		RADDR (temp),
-		NADDR (header.savep),
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+		32,
 	/*
-	**	Load scratcha, because in case of a selection timeout,
-	**	the host will expect a new value for startpos in
-	**	the scratcha register.
+	**	Direction is DATA IN.
+	**	Warning: we jump here, even when phase is DATA OUT.
 	*/
 	SCR_COPY (4),
-		PADDR (startpos),
-		RADDR (scratcha),
-#ifdef NCR_GETCC_WITHMSG
-	/*
-	**	If QUIRK_NOMSG is set, select without ATN.
-	**	and don't send a message.
-	*/
-	SCR_FROM_REG (QU_REG),
-		0,
-	SCR_JUMP ^ IFTRUE (MASK (QUIRK_NOMSG, QUIRK_NOMSG)),
-		PADDRH(getcc3),
-	/*
-	**	Then try to connect to the target.
-	**	If we are reselected, special treatment
-	**	of the current job is required before
-	**	accepting the reselection.
-	*/
-	SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
-		PADDR(badgetcc),
-	/*
-	**	save target id.
-	*/
-	SCR_FROM_REG (sdid),
-		0,
-	SCR_TO_REG (ctest0),
-		0,
+		NADDR (header.lastp),
+		NADDR (header.savep),
+
 	/*
-	**	Send the IDENTIFY message.
-	**	In case of short transfer, remove ATN.
+	**	Jump to the SCRIPTS according to actual direction.
 	*/
-	SCR_MOVE_TBL ^ SCR_MSG_OUT,
-		offsetof (struct dsb, smsg2),
-	SCR_CLR (SCR_ATN),
+	SCR_COPY (4),
+		NADDR (header.savep),
+		RADDR (temp),
+	SCR_RETURN,
 		0,
 	/*
-	**	save the first byte of the message.
+	**	Direction is DATA OUT.
 	*/
-	SCR_COPY (1),
-		RADDR (sfbr),
-		NADDR (lastmsg),
+	SCR_COPY (4),
+		NADDR (header.wlastp),
+		NADDR (header.lastp),
+	SCR_COPY (4),
+		NADDR (header.wgoalp),
+		NADDR (header.goalp),
+	SCR_JUMPR,
+		-64,
+}/*-------------------------< BAD_IDENTIFY >---------------*/,{
+	/*
+	**	If message phase but not an IDENTIFY,
+	**	get some help from the C code.
+	**	Old SCSI device may behave so.
+	*/
+	SCR_JUMPR ^ IFTRUE (MASK (0x80, 0x80)),
+		16,
+	SCR_INT,
+		SIR_RESEL_NO_IDENTIFY,
 	SCR_JUMP,
-		PADDR (prepare2),
-
-#endif
-}/*-------------------------< GETCC3 >----------------------*/,{
+		PADDRH (reset),
 	/*
-	**	Try to connect to the target.
-	**	If we are reselected, special treatment
-	**	of the current job is required before
-	**	accepting the reselection.
-	**
-	**	Silly target won't accept a message.
-	**	Select without ATN.
+	**	Message is an IDENTIFY, but lun is unknown.
+	**	Read the message, since we got it directly 
+	**	from the SCSI BUS data lines.
+	**	Signal problem to C code for logging the event.
+	**	Send a M_ABORT to clear all pending tasks.
 	*/
-	SCR_SEL_TBL ^ offsetof (struct dsb, select),
-		PADDR(badgetcc),
+	SCR_INT,
+		SIR_RESEL_BAD_LUN,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin),
+	SCR_JUMP,
+		PADDRH (abort),
+}/*-------------------------< BAD_I_T_L >------------------*/,{
 	/*
-	**	save target id.
+	**	We donnot have a task for that I_T_L.
+	**	Signal problem to C code for logging the event.
+	**	Send a M_ABORT message.
 	*/
-	SCR_FROM_REG (sdid),
-		0,
-	SCR_TO_REG (ctest0),
-		0,
+	SCR_INT,
+		SIR_RESEL_BAD_I_T_L,
+	SCR_JUMP,
+		PADDRH (abort),
+}/*-------------------------< BAD_I_T_L_Q >----------------*/,{
 	/*
-	**	Force error if selection timeout
+	**	We donnot have a task that matches the tag.
+	**	Signal problem to C code for logging the event.
+	**	Send a M_ABORTTAG message.
 	*/
-	SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_IN)),
-		0,
+	SCR_INT,
+		SIR_RESEL_BAD_I_T_L_Q,
+	SCR_JUMP,
+		PADDRH (aborttag),
+}/*-------------------------< BAD_TARGET >-----------------*/,{
 	/*
-	**	don't negotiate.
+	**	We donnot know the target that reselected us.
+	**	Grab the first message if any (IDENTIFY).
+	**	Signal problem to C code for logging the event.
+	**	M_RESET message.
 	*/
+	SCR_INT,
+		SIR_RESEL_BAD_TARGET,
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		8,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin),
 	SCR_JUMP,
-		PADDR (prepare2),
-
-}/*-------------------------< DATA_OUT >-------------------*/,{
-/*
-**	Because the size depends on the
-**	#define MAX_SCATTER parameter,
-**	it is filled in at runtime.
-**
-**  ##===========< i=0; i<MAX_SCATTER >=========
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-**  ||		PADDR (dispatch),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
-**  ||		offsetof (struct dsb, data[ i]),
-**  ##==========================================
-**
-**	SCR_CALL,
-**		PADDR (dispatch),
-**	SCR_JUMP,
-**		PADDR (no_data),
-**
-**---------------------------------------------------------
-*/
-0
-}/*-------------------------< ABORTTAG >-------------------*/,{
+		PADDRH (reset),
+}/*-------------------------< BAD_STATUS >-----------------*/,{
 	/*
-	**      Abort a bad reselection.
-	**	Set the message to ABORT vs. ABORT_TAG
+	**	If command resulted in either QUEUE FULL,
+	**	CHECK CONDITION or COMMAND TERMINATED,
+	**	call the C code.
 	*/
-	SCR_LOAD_REG (scratcha, M_ABORT_TAG),
-		0,
-	SCR_JUMPR ^ IFFALSE (CARRYSET),
-		8,
-}/*-------------------------< ABORT >----------------------*/,{
-	SCR_LOAD_REG (scratcha, M_ABORT),
+	SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)),
+		SIR_BAD_STATUS,
+	SCR_INT ^ IFTRUE (DATA (S_CHECK_COND)),
+		SIR_BAD_STATUS,
+	SCR_INT ^ IFTRUE (DATA (S_TERMINATED)),
+		SIR_BAD_STATUS,
+	SCR_RETURN,
 		0,
-	SCR_COPY (1),
+}/*-------------------------< START_RAM >-------------------*/,{
+	/*
+	**	Load the script into on-chip RAM, 
+	**	and jump to start point.
+	*/
+	SCR_COPY_F (4),
 		RADDR (scratcha),
-		NADDR (msgout),
-	SCR_SET (SCR_ATN),
-		0,
-	SCR_CLR (SCR_ACK),
+		PADDRH (start_ram0),
+	SCR_COPY (sizeof (struct script)),
+}/*-------------------------< START_RAM0 >--------------------*/,{
 		0,
+		PADDR (start),
+	SCR_JUMP,
+		PADDR (start),
+}/*-------------------------< STO_RESTART >-------------------*/,{
 	/*
-	**	and send it.
-	**	we expect an immediate disconnect
+	**
+	**	Repair start queue (e.g. next time use the next slot) 
+	**	and jump to start point.
 	*/
-	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
-		0,
-	SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
-		NADDR (msgout),
-	SCR_COPY (1),
-		RADDR (sfbr),
-		NADDR (lastmsg),
-	SCR_CLR (SCR_ACK|SCR_ATN),
-		0,
-	SCR_WAIT_DISC,
-		0,
+	SCR_COPY (4),
+		RADDR (temp),
+		PADDR (startpos),
 	SCR_JUMP,
 		PADDR (start),
 }/*-------------------------< SNOOPTEST >-------------------*/,{
@@ -3654,48 +3707,63 @@
 
 	p = scrh->tryloop;
 	for (i=0; i<MAX_START; i++) {
-		*p++ =SCR_COPY (4);
-		*p++ =NADDR (squeue[i]);
-		*p++ =RADDR (dsa);
 		*p++ =SCR_CALL;
-		*p++ =PADDR (trysel);
+		*p++ =PADDR (idle);
 	};
-	*p++ =SCR_JUMP;
-	*p++ =PADDRH(tryloop);
 
 	assert ((u_long)p == (u_long)&scrh->tryloop + sizeof (scrh->tryloop));
 
-	p = scr->data_in;
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+
+	p = scrh->done_queue;
+	for (i = 0; i<MAX_DONE; i++) {
+		*p++ =SCR_COPY (sizeof(ccb_p));
+		*p++ =NADDR (header.cp);
+		*p++ =NADDR (ccb_done[i]);
+		*p++ =SCR_CALL;
+		*p++ =PADDR (done_end);
+	}
+
+	assert ((u_long)p ==(u_long)&scrh->done_queue+sizeof(scrh->done_queue));
 
-	for (i=0; i<MAX_SCATTER; i++) {
+#endif /* SCSI_NCR_CCB_DONE_SUPPORT */
+
+	p = scrh->hdata_in;
+	for (i=0; i<MAX_SCATTERH; i++) {
 		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
-		*p++ =PADDR (checkatn);
+		*p++ =PADDR (dispatch);
 		*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));
 
-	*p++ =SCR_CALL;
-	*p++ =PADDR (checkatn);
-	*p++ =SCR_JUMP;
-	*p++ =PADDR (no_data);
-
+	p = scr->data_in;
+	for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
+		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
+		*p++ =PADDR (dispatch);
+		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
+		*p++ =offsetof (struct dsb, data[i]);
+	};
 	assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
 
-	p = scrh->data_out;
-
-	for (i=0; i<MAX_SCATTER; i++) {
+	p = scrh->hdata_out;
+	for (i=0; i<MAX_SCATTERH; i++) {
 		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
 		*p++ =PADDR (dispatch);
 		*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));
 
-	*p++ =SCR_CALL;
-	*p++ =PADDR (dispatch);
-	*p++ =SCR_JUMP;
-	*p++ =PADDR (no_data);
+	p = scr->data_out;
+	for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
+		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
+		*p++ =PADDR (dispatch);
+		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
+		*p++ =offsetof (struct dsb, data[i]);
+	};
 
-	assert ((u_long)p == (u_long)&scrh->data_out + sizeof (scrh->data_out));
+	assert ((u_long)p == (u_long)&scr->data_out + sizeof (scr->data_out));
 }
 
 /*==========================================================
@@ -3732,13 +3800,13 @@
 		*/
 
 		if (opcode == 0) {
-			printf ("%s: ERROR0 IN SCRIPT at %d.\n",
+			printk (KERN_ERR "%s: ERROR0 IN SCRIPT at %d.\n",
 				ncr_name(np), (int) (src-start-1));
-			DELAY (1000000);
+			MDELAY (1000);
 		};
 
 		if (DEBUG_FLAGS & DEBUG_SCRIPT)
-			printf ("%p:  <%x>\n",
+			printk (KERN_DEBUG "%p:  <%x>\n",
 				(src-1), (unsigned)opcode);
 
 		/*
@@ -3758,9 +3826,9 @@
 			if ((tmp2 & RELOC_MASK) == RELOC_KVAR)
 				tmp2 = 0;
 			if ((tmp1 ^ tmp2) & 3) {
-				printf ("%s: ERROR1 IN SCRIPT at %d.\n",
+				printk (KERN_ERR"%s: ERROR1 IN SCRIPT at %d.\n",
 					ncr_name(np), (int) (src-start-1));
-				DELAY (1000000);
+				MDELAY (1000);
 			}
 			/*
 			**	If PREFETCH feature not enabled, remove 
@@ -3782,7 +3850,7 @@
 		case 0x8:
 			/*
 			**	JUMP / CALL
-			**	don't relocate if relative :-)
+			**	dont't relocate if relative :-)
 			*/
 			if (opcode & 0x00800000)
 				relocs = 0;
@@ -3847,9 +3915,6 @@
 			*dst++ = cpu_to_scr(*src++);
 
 	};
-	if (bootverbose > 1 && opchanged)
-		printf("%s: NO FLUSH bit removed from %d script instructions\n",
-			ncr_name(np), opchanged); 
 }
 
 /*==========================================================
@@ -3872,31 +3937,37 @@
 struct host_data {
      struct ncb *ncb;
 
-     char ncb_align[NCB_ALIGN_SIZE-1];	/* Filler for alignment */
+     char ncb_align[CACHE_LINE_SIZE-1]; /* Filler for alignment */
      struct ncb _ncb_data;
 
-     char ccb_align[CCB_ALIGN_SIZE-1];	/* Filler for alignment */
+     char ccb_align[CACHE_LINE_SIZE-1]; /* Filler for alignment */
      struct ccb _ccb_data;
 
-     char scr_align[SCR_ALIGN_SIZE-1];	/* Filler for alignment */
+     char scr_align[CACHE_LINE_SIZE-1]; /* Filler for alignment */
      struct script script_data;
 
      struct scripth scripth_data;
 };
 
 /*
-**	Print something which allow to retrieve the controler type, unit,
+**	Print something which allows to retrieve the controler type, unit,
 **	target, lun concerned by a kernel message.
 */
 
-#define PRINT_LUN(np, target, lun) \
-printf(KERN_INFO "%s-<%d,%d>: ", ncr_name(np), (int) (target), (int) (lun))
+static void PRINT_TARGET(ncb_p np, int target)
+{
+	printk(KERN_INFO "%s-<%d,*>: ", ncr_name(np), target);
+}
+
+static void PRINT_LUN(ncb_p np, int target, int lun)
+{
+	printk(KERN_INFO "%s-<%d,%d>: ", ncr_name(np), target, lun);
+}
 
 static void PRINT_ADDR(Scsi_Cmnd *cmd)
 {
 	struct host_data *host_data = (struct host_data *) cmd->host->hostdata;
-	ncb_p np                    = host_data->ncb;
-	if (np) PRINT_LUN(np, cmd->target, cmd->lun);
+	PRINT_LUN(host_data->ncb, cmd->target, cmd->lun);
 }
 
 /*==========================================================
@@ -4003,8 +4074,6 @@
 
 	if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
 		tp->usrtags = 2 << nvram->max_tags_index;
-		if (tp->usrtags > SCSI_NCR_MAX_TAGS)
-			tp->usrtags = SCSI_NCR_MAX_TAGS;
 	}
 
 	if (!(tn->flags & TEKRAM_DISCONNECT_ENABLE))
@@ -4067,8 +4136,7 @@
 	 * Divisor to be used for async (timer pre-scaler).
 	 */
 	i = np->clock_divn - 1;
-	while (i >= 0) {
-		--i;
+	while (--i >= 0) {
 		if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz > div_10M[i]) {
 			++i;
 			break;
@@ -4271,7 +4339,7 @@
 	*/
 
 	i = nvram ? nvram->type : 0;
-	printf(KERN_INFO "%s: %sID %d, Fast-%d%s%s\n", ncr_name(np),
+	printk(KERN_INFO "%s: %sID %d, Fast-%d%s%s\n", ncr_name(np),
 		i  == SCSI_NCR_SYMBIOS_NVRAM ? "Symbios format NVRAM, " :
 		(i == SCSI_NCR_TEKRAM_NVRAM  ? "Tekram format NVRAM, " : ""),
 		np->myaddr,
@@ -4280,19 +4348,19 @@
 		(np->rv_stest2 & 0x20)	? ", Differential"	: "");
 
 	if (bootverbose > 1) {
-		printf ("%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
+		printk (KERN_INFO "%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
 			"(hex) %02x/%02x/%02x/%02x/%02x/%02x\n",
 			ncr_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl,
 			np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
 
-		printf ("%s: final   SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
+		printk (KERN_INFO "%s: final   SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
 			"(hex) %02x/%02x/%02x/%02x/%02x/%02x\n",
 			ncr_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl,
 			np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
 	}
 
 	if (bootverbose && np->paddr2)
-		printf (KERN_INFO "%s: on-board RAM at 0x%lx\n",
+		printk (KERN_INFO "%s: on-chip RAM at 0x%lx\n",
 			ncr_name(np), np->paddr2);
 
 	return 0;
@@ -4308,17 +4376,18 @@
 	int i;
 
 	/* display Symbios nvram host data */
-	printf("%s: HOST ID=%d%s%s%s%s\n",
+	printk(KERN_DEBUG "%s: HOST ID=%d%s%s%s%s%s\n",
 		ncr_name(np), nvram->host_id & 0x0f,
 		(nvram->flags  & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
 		(nvram->flags  & SYMBIOS_PARITY_ENABLE)	? " PARITY"	:"",
-		(nvram->flags  & SYMBIOS_VERBOSE_MSGS)	? " VERSBOSE"	:"", 
+		(nvram->flags  & SYMBIOS_VERBOSE_MSGS)	? " VERBOSE"	:"", 
+		(nvram->flags  & SYMBIOS_CHS_MAPPING)	? " CHS_ALT"	:"", 
 		(nvram->flags1 & SYMBIOS_SCAN_HI_LO)	? " HI_LO"	:"");
 
 	/* display Symbios nvram drive data */
 	for (i = 0 ; i < 15 ; i++) {
 		struct Symbios_target *tn = &nvram->target[i];
-		printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
+		printk(KERN_DEBUG "%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
 		ncr_name(np), i,
 		(tn->flags & SYMBIOS_DISCONNECT_ENABLE)	? " DISC"	: "",
 		(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)	? " SCAN_BOOT"	: "",
@@ -4351,7 +4420,8 @@
 	case 2: rem = " REMOVABLE=all";		break;
 	}
 
-	printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
+	printk(KERN_DEBUG
+		"%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
 		ncr_name(np), nvram->host_id & 0x0f,
 		(nvram->flags1 & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
 		(nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES"	:"",
@@ -4369,7 +4439,7 @@
 		struct Tekram_target *tn = &nvram->target[i];
 		j = tn->sync_index & 0xf;
 		sync = j < 12 ? Tekram_sync[j] : 255;
-		printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
+		printk(KERN_DEBUG "%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
 		ncr_name(np), i,
 		(tn->flags & TEKRAM_PARITY_CHECK)	? " PARITY"	: "",
 		(tn->flags & TEKRAM_SYNC_NEGO)		? " SYNC"	: "",
@@ -4401,17 +4471,18 @@
         struct Scsi_Host *instance = 0;
 	u_long flags = 0;
 	ncr_nvram *nvram = device->nvram;
+	int i;
 
 #ifdef __sparc__
-printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=0x%x\n",
+printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=0x%x\n",
 	device->chip.name, unit, device->chip.revision_id, device->slot.base,
 	device->slot.io_port, device->slot.irq);
 #else
-printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n",
+printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n",
 	device->chip.name, unit, device->chip.revision_id, device->slot.base,
 	device->slot.io_port, device->slot.irq);
 #endif
-
+ 
 	/*
 	**	Allocate host_data structure
 	*/
@@ -4422,17 +4493,16 @@
 	**	Initialize structure.
 	*/
 	host_data = (struct host_data *) instance->hostdata;
+	bzero (host_data, sizeof(*host_data));
 
 	/*
 	**	Align np and first ccb to 32 boundary for cache line 
 	**	bursting when copying the global header.
 	*/
-	np        = (ncb_p) (((u_long) &host_data->_ncb_data) & NCB_ALIGN_MASK);
+	np = (ncb_p) (((u_long) &host_data->_ncb_data) & CACHE_LINE_MASK);
+	NCR_INIT_LOCK_NCB(np);
 	host_data->ncb = np;
-	bzero (np, sizeof (*np));
-
-	np->ccb   = (ccb_p) (((u_long) &host_data->_ccb_data) & CCB_ALIGN_MASK);
-	bzero (np->ccb, sizeof (*np->ccb));
+	np->ccb = (ccb_p) (((u_long) &host_data->_ccb_data) & CACHE_LINE_MASK);
 
 	/*
 	**	Store input informations in the host data structure.
@@ -4448,8 +4518,8 @@
 	np->maxoffs	= device->chip.offset_max;
 	np->maxburst	= device->chip.burst_max;
 
-	np->script0  =
-	(struct script *) (((u_long) &host_data->script_data) & SCR_ALIGN_MASK);
+	np->script0  = (struct script *)
+		(((u_long) &host_data->script_data) & CACHE_LINE_MASK);
 	np->scripth0 = &host_data->scripth_data;
 
 	/*
@@ -4471,12 +4541,14 @@
 #ifndef NCR_IOMAPPED
 	np->vaddr = remap_pci_mem((u_long) np->paddr, (u_long) 128);
 	if (!np->vaddr) {
-		printf("%s: can't map memory mapped IO region\n", ncr_name(np));
+		printk(KERN_ERR
+			"%s: can't map memory mapped IO region\n",ncr_name(np));
 		goto attach_error;
 	}
 	else
 		if (bootverbose > 1)
-			printf("%s: using memory mapped IO at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr);
+			printk(KERN_INFO
+				"%s: using memory mapped IO at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr);
 
 	/*
 	**	Make the controller's registers available.
@@ -4511,7 +4583,7 @@
 		default:
 			nvram = 0;
 #ifdef SCSI_NCR_DEBUG_NVRAM
-			printf("%s: NVRAM: None or invalid data.\n", ncr_name(np));
+			printk(KERN_DEBUG "%s: NVRAM: None or invalid data.\n", ncr_name(np));
 #endif
 		}
 	}
@@ -4522,37 +4594,27 @@
 	*/
 	(void)ncr_prepare_setting(np, nvram);
 
-#ifndef NCR_IOMAPPED
-	if (np->paddr2 && sizeof(struct script) <= 4096) {
-		np->vaddr2 = remap_pci_mem((u_long) np->paddr2, (u_long) 4096);
-		if (!np->vaddr2) {
-			printf("%s: can't map memory mapped IO region\n", ncr_name(np));
-			goto attach_error;
-		}
-		else
-			if (bootverbose > 1)
-				printf("%s: on-board ram mapped at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr2);
+	if (np->paddr2 && sizeof(struct script) > 4096) {
+		np->paddr2 = 0;
+		printk(KERN_WARNING "%s: script too large, NOT using on chip RAM.\n",
+			ncr_name(np));
 	}
-#endif /* !defined NCR_IOMAPPED */
 
 	/*
 	**	Fill Linux host instance structure
 	*/
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
 	instance->max_channel	= 0;
 	instance->max_id	= np->maxwide ? 16 : 8;
 	instance->max_lun	= SCSI_NCR_MAX_LUN;
-#endif
 #ifndef NCR_IOMAPPED
 	instance->base		= (char *) np->reg;
 #endif
 	instance->irq		= device->slot.irq;
+	instance->unique_id	= device->slot.io_port;
 	instance->io_port	= device->slot.io_port;
 	instance->n_io_port	= 128;
 	instance->dma_channel	= 0;
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
 	instance->select_queue_depths = ncr53c8xx_select_queue_depths;
-#endif
 
 	/*
 	**	Patch script to physical addresses
@@ -4562,8 +4624,7 @@
 	np->scripth	= np->scripth0;
 	np->p_scripth	= vtophys(np->scripth);
 
-	np->script	= (np->vaddr2) ? (struct script *) np->vaddr2 : np->script0;
-	np->p_script	= (np->vaddr2) ? pcivtophys(np->paddr2) : vtophys(np->script0);
+	np->p_script	= (np->paddr2) ? pcivtophys(np->paddr2) : vtophys(np->script0);
 
 	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));
@@ -4574,27 +4635,32 @@
 	*/
 
 	if (np->features & FE_LED0) {
-		np->script0->reselect[0]  =
+		np->script0->idle[0]  =
 				cpu_to_scr(SCR_REG_REG(gpreg, SCR_OR,  0x01));
-		np->script0->reselect1[0] =
+		np->script0->reselected[0] =
 				cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
-		np->script0->reselect2[0] =
+		np->script0->start[0] =
 				cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
 	}
 
 	/*
-	**	init data structure
-	*/
-
-	np->jump_tcb.l_cmd	= cpu_to_scr(SCR_JUMP);
-	np->jump_tcb.l_paddr	= cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
+	**	Look for the target control block of this nexus.
+	**	For i = 0 to 3
+	**		JUMP ^ IFTRUE (MASK (i, 3)), @(next_lcb)
+	*/
+	for (i = 0 ; i < 4 ; i++) {
+		np->jump_tcb[i].l_cmd   =
+				cpu_to_scr((SCR_JUMP ^ IFTRUE (MASK (i, 3))));
+		np->jump_tcb[i].l_paddr =
+				cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_target));
+	}
 
 	/*
 	**	Reset chip.
 	*/
 
 	OUTB (nc_istat,  SRST);
-	DELAY (1000);
+	UDELAY (100);
 	OUTB (nc_istat,  0   );
 
 	/*
@@ -4602,34 +4668,35 @@
 	*/
 
 	if (ncr_snooptest (np)) {
-		printf ("CACHE INCORRECTLY CONFIGURED.\n");
+		printk (KERN_ERR "CACHE INCORRECTLY CONFIGURED.\n");
 		goto attach_error;
 	};
 
 	/*
 	**	Install the interrupt handler.
 	*/
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
-#ifdef SCSI_NCR_SHARE_IRQ
+#ifdef	SCSI_NCR_SHARE_IRQ
+#define	NCR_SA_INTERRUPT_FLAGS (SA_INTERRUPT | SA_SHIRQ)
 	if (bootverbose > 1)
-		printf("%s: requesting shared irq %d (dev_id=0x%lx)\n",
+		printk(KERN_INFO "%s: requesting shared irq %d (dev_id=0x%lx)\n",
 		        ncr_name(np), device->slot.irq, (u_long) np);
-	if (request_irq(device->slot.irq, do_ncr53c8xx_intr,
-			SA_INTERRUPT|SA_SHIRQ, "ncr53c8xx", np)) {
 #else
-	if (request_irq(device->slot.irq, do_ncr53c8xx_intr,
-			SA_INTERRUPT, "ncr53c8xx", np)) {
+#define	NCR_SA_INTERRUPT_FLAGS SA_INTERRUPT
 #endif
-#else
 	if (request_irq(device->slot.irq, ncr53c8xx_intr,
-			SA_INTERRUPT, "ncr53c8xx")) {
-#endif
-		printf("%s: request irq %d failure\n", ncr_name(np), device->slot.irq);
+			NCR_SA_INTERRUPT_FLAGS, "ncr53c8xx", np)) {
+		printk(KERN_ERR "%s: request irq %d failure\n",
+			ncr_name(np), device->slot.irq);
 		goto attach_error;
 	}
 	np->irq = device->slot.irq;
 
 	/*
+	**	Initialize the fixed part of the default ccb.
+	*/
+	ncr_init_ccb(np, np->ccb);
+
+	/*
 	**	After SCSI devices have been opened, we cannot
 	**	reset the bus safely, so we do it here.
 	**	Interrupt handler does the real work.
@@ -4637,41 +4704,26 @@
 	**	if interrupts are not enabled yet.
 	**	Then enable disconnects.
 	*/
-	save_flags(flags); cli();
-	do {
-		if (ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay) != 0) {
-			printf("%s: FATAL ERROR: CHECK SCSI BUS - CABLES, "
-			       "TERMINATION, DEVICE POWER etc.!\n",
-			       ncr_name(np));
-			restore_flags(flags);
-			goto attach_error;
-		}
+	NCR_LOCK_NCB(np, flags);
+	if (ncr_reset_scsi_bus(np, 0, driver_setup.settle_delay) != 0) {
+		printk(KERN_ERR "%s: FATAL ERROR: CHECK SCSI BUS - CABLES, TERMINATION, DEVICE POWER etc.!\n", ncr_name(np));
 
-		/*
-		** On Ultra/AXi, the NCR53C876 sometimes does not get the
-		** RST bit set in SIST the first time, so retry resetting
-		** the SCSI bus until the chip is properly initialized.
-		*/
-		np->disc = 1;
-		ncr_exception (np);
-		if (np->disc) {
-			printk("%s: Chip not responding to CRST, retrying\n",
-			       ncr_name(np));
-		}
-	} while (np->disc);
-	restore_flags(flags);
+		NCR_UNLOCK_NCB(np, flags);
+		goto attach_error;
+	}
+	ncr_exception (np);
 
 	np->disc = 1;
 
 	/*
 	**	The middle-level SCSI driver does not
-	**	wait devices to settle.
+	**	wait for devices to settle.
 	**	Wait synchronously if more than 2 seconds.
 	*/
 	if (driver_setup.settle_delay > 2) {
-		printf("%s: waiting %d seconds for scsi devices to settle...\n",
+		printk(KERN_INFO "%s: waiting %d seconds for scsi devices to settle...\n",
 			ncr_name(np), driver_setup.settle_delay);
-		DELAY(1000000UL * driver_setup.settle_delay);
+		MDELAY (1000 * driver_setup.settle_delay);
 	}
 
 	/*
@@ -4700,46 +4752,80 @@
         	first_host = instance;
 	}
 
+	NCR_UNLOCK_NCB(np, flags);
+
 	return 0;
 
 attach_error:
 	if (!instance) return -1;
-	printf("%s: detaching...\n", ncr_name(np));
+	printk(KERN_INFO "%s: detaching...\n", ncr_name(np));
 #ifndef NCR_IOMAPPED
 	if (np->vaddr) {
 #ifdef DEBUG_NCR53C8XX
-		printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
+		printk(KERN_DEBUG "%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
 #endif
 		unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
 	}
-	if (np->vaddr2) {
-#ifdef DEBUG_NCR53C8XX
-		printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
-#endif
-		unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
-	}
-#endif
+#endif /* !NCR_IOMAPPED */
 	if (np->port) {
 #ifdef DEBUG_NCR53C8XX
-		printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+		printk(KERN_DEBUG "%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
 #endif
 		release_region(np->port, 128);
 	}
 	if (np->irq) {
 #ifdef DEBUG_NCR53C8XX
-		printf("%s: freeing irq %d\n", ncr_name(np), np->irq);
-#endif
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
-		free_irq(np->irq, np);
+#ifdef __sparc__
+	printk(KERN_INFO "%s: freeing irq 0x%x\n", ncr_name(np), np->irq);
 #else
-		free_irq(np->irq);
+	printk(KERN_INFO "%s: freeing irq %d\n", ncr_name(np), np->irq);
+#endif
 #endif
+		free_irq(np->irq, np);
 	}
 	scsi_unregister(instance);
 
         return -1;
  }
 
+
+/*==========================================================
+**
+**
+**	Done SCSI commands list management.
+**
+**	We donnot enter the scsi_done() callback immediately 
+**	after a command has been seen as completed but we 
+**	insert it into a list which is flushed outside any kind 
+**	of driver critical section.
+**	This allows to do minimal stuff under interrupt and 
+**	inside critical sections and to also avoid locking up 
+**	on recursive calls to driver entry points under SMP.
+**	In fact, the only kernel point which is entered by the 
+**	driver with a driver lock set is kmalloc(GFP_ATOMIC) 
+**	that shall not reenter the driver under any circumstances,
+**	AFAIK.
+**
+**==========================================================
+*/
+static inline void ncr_queue_done_cmd(ncb_p np, Scsi_Cmnd *cmd)
+{
+	cmd->host_scribble = (char *) np->done_list;
+	np->done_list = cmd;
+}
+
+static inline void ncr_flush_done_cmds(Scsi_Cmnd *lcmd)
+{
+	Scsi_Cmnd *cmd;
+
+	while (lcmd) {
+		cmd = lcmd;
+		lcmd = (Scsi_Cmnd *) cmd->host_scribble;
+		cmd->scsi_done(cmd);
+	}
+}
+
+
 /*==========================================================
 **
 **
@@ -4749,27 +4835,18 @@
 **
 **==========================================================
 */
-int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
+int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
 {
-        struct Scsi_Host   *host      = cmd->host;
 /*	Scsi_Device        *device    = cmd->device; */
-	struct host_data   *host_data = (struct host_data *) host->hostdata;
-	ncb_p np                      = host_data->ncb;
 	tcb_p tp                      = &np->target[cmd->target];
-
+	lcb_p lp		      = tp->lp[cmd->lun];
 	ccb_p cp;
-	lcb_p lp;
 
 	int	segments;
-	u_char	qidx, nego, idmsg, *msgptr;
-	u_int  msglen, msglen2;
-	u_long	flags;
-	int	xfer_direction;
-
-	cmd->scsi_done     = done;
-	cmd->host_scribble = NULL;
-	cmd->SCp.ptr       = NULL;
-	cmd->SCp.buffer    = NULL;
+	u_char	nego, idmsg, *msgptr;
+	u_int  msglen;
+	int	direction;
+	u_int32	lastp, goalp;
 
 	/*---------------------------------------------
 	**
@@ -4799,7 +4876,7 @@
 
 	if (DEBUG_FLAGS & DEBUG_TINY) {
 		PRINT_ADDR(cmd);
-		printf ("CMD=%x ", cmd->cmnd[0]);
+		printk ("CMD=%x ", cmd->cmnd[0]);
 	}
 
 	/*---------------------------------------------------
@@ -4812,8 +4889,6 @@
 	**
 	**----------------------------------------------------
 	*/
-	save_flags(flags); cli();
-
 	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;
@@ -4821,7 +4896,6 @@
 
         if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
 		insert_into_waiting_list(np, cmd);
-		restore_flags(flags);
 		return(DID_OK);
 	}
 	cp->cmd = cmd;
@@ -4832,10 +4906,12 @@
 	**
 	**----------------------------------------------------
 	*/
-	if (!tp->usrtags && cmd->device && cmd->device->tagged_queue) {
-		tp->usrtags = SCSI_NCR_MAX_TAGS;
-		ncr_setmaxtags (np, tp, SCSI_NCR_MAX_TAGS);
+#if 0	/* This stuff was only usefull for linux-1.2.13 */
+	if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) {
+		lp->numtags = tp->usrtags;
+		ncr_setup_tags (np, cmd->target, cmd->lun);
 	}
+#endif
 
 	/*---------------------------------------------------
 	**
@@ -4848,47 +4924,23 @@
 	cp->phys.header.stamp.start = jiffies;
 #endif
 
-	/*----------------------------------------------------
-	**
-	**	Get device quirks from a speciality table.
-	**
-	**	@GENSCSI@
-	**	This should be a part of the device table
-	**	in "scsi_conf.c".
-	**
-	**----------------------------------------------------
-	*/
-	if (tp->quirks & QUIRK_UPDATE) {
-		tp->quirks = ncr_lookup ((char*) &tp->inqdata[0]);
-#ifndef NCR_GETCC_WITHMSG
-		if (tp->quirks) {
-			PRINT_ADDR(cmd);
-			printf ("quirks=%x.\n", tp->quirks);
-		}
-#endif
-	}
-
 	/*---------------------------------------------------
 	**
 	**	negotiation required?
 	**
-	**	Only SCSI-II devices.
-	**	To negotiate with SCSI-I devices is dangerous, since
-	**	Synchronous Negotiation protocol is optional, and
-	**	INQUIRY data do not contains capabilities in byte 7.
-	**----------------------------------------------------
+	**---------------------------------------------------
 	*/
 
 	nego = 0;
 
-	if (cmd->lun == 0 && !tp->nego_cp && 
-	    (tp->inqdata[2] & 0x7) >= 2 && tp->inqdata[7]) {
+	if ((!tp->widedone || !tp->period) && !tp->nego_cp && tp->inq_done) {
+
 		/*
 		**	negotiate wide transfers ?
 		*/
 
 		if (!tp->widedone) {
-			if (tp->inqdata[7] & INQ7_WIDE16) {
+			if (tp->inq_byte7 & INQ7_WIDE16) {
 				nego = NS_WIDE;
 			} else
 				tp->widedone=1;
@@ -4899,17 +4951,13 @@
 		*/
 
 		if (!nego && !tp->period) {
-			if ( 1
-#if defined (CDROM_ASYNC)
-			    && ((tp->inqdata[0] & 0x1f) != 5)
-#endif
-			    && (tp->inqdata[7] & INQ7_SYNC)) {
+			if (tp->inq_byte7 & INQ7_SYNC) {
 				nego = NS_SYNC;
 			} else {
 				tp->period  =0xffff;
 				tp->sval = 0xe0;
-				PRINT_ADDR(cmd);
-				printf ("asynchronous.\n");
+				PRINT_TARGET(np, cmd->target);
+				printk ("SYNC transfers not supported.\n");
 			};
 		};
 
@@ -4923,33 +4971,6 @@
 			tp->nego_cp = cp;
 	};
 
-	/*---------------------------------------------------
-	**
-	**	choose a new tag ...
-	**
-	**----------------------------------------------------
-	*/
-
-	if ((lp = tp->lp[cmd->lun]) && (lp->usetags)) {
-		/*
-		**	assign a tag to this ccb!
-		*/
-		while (!cp->tag) {
-			ccb_p cp2 = lp->next_ccb;
-			lp->lasttag = lp->lasttag % 255 + 1;
-			while (cp2 && cp2->tag != lp->lasttag)
-				cp2 = cp2->next_ccb;
-			if (cp2) continue;
-			cp->tag=lp->lasttag;
-			if (DEBUG_FLAGS & DEBUG_TAGS) {
-				PRINT_ADDR(cmd);
-				printf ("using tag #%d.\n", cp->tag);
-			}
-		}
-	} else {
-		cp->tag=0;
-	}
-
 	/*----------------------------------------------------
 	**
 	**	Build the identify / tag / sdtr message
@@ -4959,44 +4980,54 @@
 
 	idmsg = M_IDENTIFY | cmd->lun;
 
-	if (cp != np->ccb && ((np->disc && !(tp->usrflag & UF_NODISC)) || cp->tag))
+	if (cp ->tag != NO_TAG ||
+		(cp != np->ccb && np->disc && !(tp->usrflag & UF_NODISC)))
 		idmsg |= 0x40;
 
 	msgptr = cp->scsi_smsg;
 	msglen = 0;
 	msgptr[msglen++] = idmsg;
 
-	if (cp->tag) {
-	    char tag;
+	if (cp->tag != NO_TAG) {
+		char order = np->order;
 
-	    tag = np->order;
-	    if (tag == 0) {
 		/*
-		**	Ordered write ops, unordered read ops.
+		**	Force ordered tag if necessary to avoid timeouts 
+		**	and to preserve interactivity.
 		*/
-		switch (cmd->cmnd[0]) {
-		case 0x08:  /* READ_SMALL (6) */
-		case 0x28:  /* READ_BIG  (10) */
-		case 0xa8:  /* READ_HUGE (12) */
-		    tag = M_SIMPLE_TAG;
-		    break;
-		default:
-		    tag = M_ORDERED_TAG;
+		if (lp && lp->tags_stime + (3*HZ) <= jiffies) {
+			if (lp->tags_smap) {
+				order = M_ORDERED_TAG;
+				if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ 
+					PRINT_ADDR(cmd);
+					printk("ordered tag forced.\n");
+				}
+			}
+			lp->tags_stime = jiffies;
+			lp->tags_smap = lp->tags_umap;
 		}
-	    }
-	    /*
-	    **	Have to force ordered tag to avoid timeouts
-	    */
-	    if ((lp = tp->lp[cmd->lun]) && (lp->force_ordered_tag)) {
-		tag = M_ORDERED_TAG;
-		lp->force_ordered_tag = 0;
-		if (DEBUG_FLAGS & DEBUG_TAGS) {
-			PRINT_ADDR(cmd);
-			printf ("Ordered Queue Tag forced\n");
+
+		if (order == 0) {
+			/*
+			**	Ordered write ops, unordered read ops.
+			*/
+			switch (cmd->cmnd[0]) {
+			case 0x08:  /* READ_SMALL (6) */
+			case 0x28:  /* READ_BIG  (10) */
+			case 0xa8:  /* READ_HUGE (12) */
+				order = M_SIMPLE_TAG;
+				break;
+			default:
+				order = M_ORDERED_TAG;
+			}
 		}
-	    }
-	    msgptr[msglen++] = tag;
-	    msgptr[msglen++] = cp -> tag;
+		msgptr[msglen++] = order;
+#if SCSI_NCR_MAX_TAGS <= 32
+		msgptr[msglen++] = (cp->tag << 3) + 1;
+#else
+		msgptr[msglen++] = (cp->tag << 2) + 1;
+#endif
+
 	}
 
 	switch (nego) {
@@ -5008,9 +5039,9 @@
 		msgptr[msglen++] = tp->maxoffs;
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
 			PRINT_ADDR(cp->cmd);
-			printf ("sync msgout: ");
+			printk ("sync msgout: ");
 			ncr_show_msg (&cp->scsi_smsg [msglen-5]);
-			printf (".\n");
+			printk (".\n");
 		};
 		break;
 	case NS_WIDE:
@@ -5020,25 +5051,15 @@
 		msgptr[msglen++] = tp->usrwide;
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
 			PRINT_ADDR(cp->cmd);
-			printf ("wide msgout: ");
+			printk ("wide msgout: ");
 			ncr_show_msg (&cp->scsi_smsg [msglen-4]);
-			printf (".\n");
+			printk (".\n");
 		};
 		break;
 	};
 
 	/*----------------------------------------------------
 	**
-	**	Build the identify message for getcc.
-	**
-	**----------------------------------------------------
-	*/
-
-	cp -> scsi_smsg2 [0] = idmsg;
-	msglen2 = 1;
-
-	/*----------------------------------------------------
-	**
 	**	Build the data descriptors
 	**
 	**----------------------------------------------------
@@ -5047,8 +5068,7 @@
 	segments = ncr_scatter (cp, cp->cmd);
 
 	if (segments < 0) {
-		ncr_free_ccb(np, cp, cmd->target, cmd->lun);
-		restore_flags(flags);
+		ncr_free_ccb(np, cp);
 		return(DID_ERROR);
 	}
 
@@ -5059,20 +5079,24 @@
 	**
 	**----------------------------------------------------
 	*/
-	switch((int) cmd->cmnd[0]) {
-	case 0x08:  /*	READ(6)				08 */
-	case 0x28:  /*	READ(10)			28 */
-	case 0xA8:  /*	READ(12)			A8 */
-		xfer_direction = XferIn;
-		break;
-	case 0x0A:  /*	WRITE(6)			0A */
-	case 0x2A:  /*	WRITE(10)			2A */
-	case 0xAA:  /*	WRITE(12)			AA */
-		xfer_direction = XferOut;
-		break;
-	default:
-		xfer_direction = guess_xfer_direction((int) cmd->cmnd[0]);
-		break;
+	if (!cp->data_len)
+		direction = 0;
+	else {
+		switch((int) cmd->cmnd[0]) {
+		case 0x08:  /*	READ(6)				08 */
+		case 0x28:  /*	READ(10)			28 */
+		case 0xA8:  /*	READ(12)			A8 */
+			direction = XFER_IN;
+			break;
+		case 0x0A:  /*	WRITE(6)			0A */
+		case 0x2A:  /*	WRITE(10)			2A */
+		case 0xAA:  /*	WRITE(12)			AA */
+			direction = XFER_OUT;
+			break;
+		default:
+			direction = (XFER_IN|XFER_OUT);
+			break;
+		}
 	}
 
 	/*----------------------------------------------------
@@ -5082,36 +5106,64 @@
 	**----------------------------------------------------
 	*/
 
-	cp->segments = segments;
-	if (!cp->data_len)
-		xfer_direction = XferNone;
+	/*
+	**	Default to no data transfer.
+	*/
+	lastp = goalp = NCB_SCRIPT_PHYS (np, no_data);
 
-	switch (xfer_direction) {
-		u_long endp;
-	default:
-	case XferBoth:
-		cp->phys.header.savep =
-			cpu_to_scr(NCB_SCRIPT_PHYS (np, data_io));
-		cp->phys.header.goalp = cp->phys.header.savep;
-		break;
-	case XferIn:
-		endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16;
-		cp->phys.header.goalp = cpu_to_scr(endp + 8);
-		cp->phys.header.savep = cpu_to_scr(endp - segments*16);
-		break;
-	case XferOut:
-		endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
-		cp->phys.header.goalp = cpu_to_scr(endp + 8);
-		cp->phys.header.savep = cpu_to_scr(endp - segments*16);
-		break;
-	case XferNone:
-		cp->phys.header.savep =
-			cpu_to_scr(NCB_SCRIPT_PHYS (np, no_data));
-		cp->phys.header.goalp = cp->phys.header.savep;
-		break;
+	/*
+	**	Compute data out pointers, if needed.
+	*/
+	if (direction & XFER_OUT) {
+		goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
+		if (segments <= MAX_SCATTERL)
+			lastp = goalp - 8 - (segments * 16);
+		else {
+			lastp = NCB_SCRIPTH_PHYS (np, hdata_out2);
+			lastp -= (segments - MAX_SCATTERL) * 16;
+		}
+		/*
+		**	If actual data direction is unknown, save pointers 
+		**	in header. The SCRIPTS will swap them to current 
+		**	if target decision will be data out.
+		*/
+		if (direction & XFER_IN) {
+			cp->phys.header.wgoalp	= cpu_to_scr(goalp);
+			cp->phys.header.wlastp	= cpu_to_scr(lastp);
+		}
+	}
+
+	/*
+	**	Compute data in pointers, if needed.
+	*/
+	if (direction & XFER_IN) {
+		goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
+		if (segments <= MAX_SCATTERL)
+			lastp = goalp - 8 - (segments * 16);
+		else {
+			lastp = NCB_SCRIPTH_PHYS (np, hdata_in2);
+			lastp -= (segments - MAX_SCATTERL) * 16;
+		}
 	}
 
-	cp->phys.header.lastp = cp->phys.header.savep;
+	/*
+	**	Set all pointers values needed by SCRIPTS.
+	**	If direction is unknown, start at data_io.
+	*/
+	cp->phys.header.lastp = cpu_to_scr(lastp);
+	cp->phys.header.goalp = cpu_to_scr(goalp);
+
+	if ((direction & (XFER_IN|XFER_OUT)) == (XFER_IN|XFER_OUT))
+		cp->phys.header.savep = 
+			cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io));
+	else
+		cp->phys.header.savep= cpu_to_scr(lastp);
+
+	/*
+	**	Save the initial data pointer in order to be able 
+	**	to redo the command.
+	*/
+	cp->startp = cp->phys.header.savep;
 
 	/*----------------------------------------------------
 	**
@@ -5123,13 +5175,12 @@
 	**	physical -> virtual backlink
 	**	Generic SCSI command
 	*/
-	cp->phys.header.cp		= cp;
+
 	/*
 	**	Startqueue
 	*/
-	cp->phys.header.launch.l_paddr	=
-			cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
-	cp->phys.header.launch.l_cmd	= cpu_to_scr(SCR_JUMP);
+	cp->start.schedule.l_paddr   = cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
+	cp->restart.schedule.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_dsa));
 	/*
 	**	select
 	*/
@@ -5142,30 +5193,12 @@
 	cp->phys.smsg.addr		= cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
 	cp->phys.smsg.size		= cpu_to_scr(msglen);
 
-	cp->phys.smsg2.addr		= cpu_to_scr(CCB_PHYS (cp, scsi_smsg2));
-	cp->phys.smsg2.size		= cpu_to_scr(msglen2);
 	/*
 	**	command
 	*/
 	cp->phys.cmd.addr		= cpu_to_scr(vtophys (&cmd->cmnd[0]));
 	cp->phys.cmd.size		= cpu_to_scr(cmd->cmd_len);
-	/*
-	**	sense command
-	*/
-	cp->phys.scmd.addr		= cpu_to_scr(CCB_PHYS (cp, sensecmd));
-	cp->phys.scmd.size		= cpu_to_scr(6);
-	/*
-	**	patch requested size into sense command
-	*/
-	cp->sensecmd[0]			= 0x03;
-	cp->sensecmd[1]			= cmd->lun << 5;
-	cp->sensecmd[4]			= sizeof(cmd->sense_buffer);
-	/*
-	**	sense data
-	*/
-	cp->phys.sense.addr		=
-			cpu_to_scr(vtophys (&cmd->sense_buffer[0]));
-	cp->phys.sense.size		= cpu_to_scr(sizeof(cmd->sense_buffer));
+
 	/*
 	**	status
 	*/
@@ -5175,9 +5208,11 @@
 	cp->parity_status		= 0;
 
 	cp->xerr_status			= XE_OK;
-	cp->sync_status			= tp->sval;
 	cp->nego_status			= nego;
+#if 0
+	cp->sync_status			= tp->sval;
 	cp->wide_status			= tp->wval;
+#endif
 
 	/*----------------------------------------------------
 	**
@@ -5187,56 +5222,96 @@
 	*/
 
 	/*
-	**	reselect pattern and activate this job.
+	**	activate this job.
 	*/
 
-	cp->jump_ccb.l_cmd	=
-		cpu_to_scr((SCR_JUMP ^ IFFALSE (DATA (cp->tag))));
-
 	/* Compute a time limit greater than the middle-level driver one */
 	if (cmd->timeout_per_command > 0)
-		cp->tlimit	= jiffies + cmd->timeout_per_command + NCR_TIMEOUT_INCREASE;
+		cp->tlimit	= jiffies + cmd->timeout_per_command + HZ;
 	else
-		cp->tlimit	= jiffies + 3600 * HZ; /* No timeout=one hour */
+		cp->tlimit	= jiffies + 86400 * HZ;/* No timeout=24 hours */
 	cp->magic		= CCB_MAGIC;
 
 	/*
+	**	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
+		ncr_put_start_queue(np, cp);
+
+	/*
+	**	Command is successfully queued.
+	*/
+
+	return(DID_OK);
+}
+
+
+/*==========================================================
+**
+**
+**	Insert a CCB into the start queue and wake up the 
+**	SCRIPTS processor.
+**
+**
+**==========================================================
+*/
+
+static void ncr_start_next_ccb(ncb_p np, lcb_p lp, int maxn)
+{
+	XPT_QUEHEAD *qp;
+	ccb_p cp;
+
+	if (lp->held_ccb)
+		return;
+
+	while (maxn-- && lp->queuedccbs < lp->queuedepth) {
+		qp = xpt_remque_head(&lp->wait_ccbq);
+		if (!qp)
+			break;
+		++lp->queuedccbs;
+		cp = xpt_que_entry(qp, struct ccb, link_ccbq);
+		xpt_insque_tail(qp, &lp->busy_ccbq);
+		lp->jump_ccb[cp->tag == NO_TAG ? 0 : cp->tag].l_paddr =
+			cpu_to_scr(cp->p_ccb + offsetof(struct ccb, restart));
+		ncr_put_start_queue(np, cp);
+	}
+}
+
+static void ncr_put_start_queue(ncb_p np, ccb_p cp)
+{
+	u_short	qidx;
+
+	/*
 	**	insert into start queue.
 	*/
+	if (!np->squeueput) np->squeueput = 1;
+	qidx = np->squeueput + 2;
+	if (qidx >= MAX_START + MAX_START) qidx = 1;
+
+	np->scripth->tryloop [qidx] = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
+	MEMORY_BARRIER();
+	np->scripth->tryloop [np->squeueput] = cpu_to_scr(CCB_PHYS (cp, start));
 
-	qidx = np->squeueput + 1;
-	if (qidx >= MAX_START) qidx=0;
-	np->squeue [qidx	 ] = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
-	np->squeue [np->squeueput] = cpu_to_scr(CCB_PHYS (cp, phys));
 	np->squeueput = qidx;
+	++np->queuedccbs;
+	cp->queued = 1;
 
-	if(DEBUG_FLAGS & DEBUG_QUEUE)
-		printf ("%s: queuepos=%d tryoffset=%d.\n", ncr_name (np),
-		np->squeueput,
-		(unsigned)(scr_to_cpu(np->script->startpos[0]) - 
-			   (NCB_SCRIPTH_PHYS (np, tryloop))));
+	if (DEBUG_FLAGS & DEBUG_QUEUE)
+		printk ("%s: queuepos=%d.\n", ncr_name (np), np->squeueput);
 
 	/*
 	**	Script processor may be waiting for reselect.
 	**	Wake it up.
 	*/
-#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-	if (!np->stalling)
-#endif
+	MEMORY_BARRIER();
 	OUTB (nc_istat, SIGP);
-
-	/*
-	**	and reenable interrupts
-	*/
-	restore_flags(flags);
-
-	/*
-	**	Command is successfully queued.
-	*/
-
-	return(DID_OK);
 }
 
+
 /*==========================================================
 **
 **
@@ -5249,18 +5324,13 @@
 **
 **==========================================================
 */
-static void ncr_start_reset(ncb_p np, int settle_delay)
+static void ncr_start_reset(ncb_p np)
 {
-	u_long flags;
-
-	save_flags(flags); cli();
-
 	if (!np->settle_time) {
-		(void) ncr_reset_scsi_bus(np, 1, settle_delay);
-	}
-	restore_flags(flags);
-}
-
+		(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;
@@ -5269,17 +5339,24 @@
 	np->settle_time	= jiffies + settle_delay * HZ;
 
 	if (bootverbose > 1)
-		printf("%s: resetting, "
+		printk("%s: resetting, "
 			"command processing suspended for %d seconds\n",
 			ncr_name(np), settle_delay);
 
 	OUTB (nc_istat, SRST);
-	DELAY (1000);
+	UDELAY (100);
 	OUTB (nc_istat, 0);
+	UDELAY (2000);	/* The 895 needs time for the bus mode to settle */
 	if (enab_int)
 		OUTW (nc_sien, RST);
+	/*
+	**	Enable Tolerant, reset IRQD if present and 
+	**	properly set IRQ mode, prior to resetting the bus.
+	*/
+	OUTB (nc_stest3, TE);
+	OUTB (nc_dcntl, (np->rv_dcntl & IRQM));
 	OUTB (nc_scntl1, CRST);
-	DELAY (100);
+	UDELAY (200);
 
 	if (!driver_setup.bus_check)
 		goto out;
@@ -5299,9 +5376,9 @@
 		term &= 0x3ffff;
 
 	if (term != (2<<7)) {
-		printf("%s: suspicious SCSI data while resetting the BUS.\n",
+		printk("%s: suspicious SCSI data while resetting the BUS.\n",
 			ncr_name(np));
-		printf("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = "
+		printk("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = "
 			"0x%lx, expecting 0x%lx\n",
 			ncr_name(np),
 			(np->features & FE_WIDE) ? "dp1,d15-8," : "",
@@ -5323,27 +5400,16 @@
 **
 **==========================================================
 */
-int ncr_reset_bus (Scsi_Cmnd *cmd, int sync_reset)
+int ncr_reset_bus (ncb_p np, Scsi_Cmnd *cmd, int sync_reset)
 {
-        struct Scsi_Host   *host      = cmd->host;
 /*	Scsi_Device        *device    = cmd->device; */
-	struct host_data   *host_data = (struct host_data *) host->hostdata;
-	ncb_p np                      = host_data->ncb;
 	ccb_p cp;
-	u_long flags;
 	int found;
 
-#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-	if (np->stalling)
-		np->stalling = 0;
-#endif
-
-	save_flags(flags); cli();
 /*
  * Return immediately if reset is in progress.
  */
 	if (np->settle_time) {
-		restore_flags(flags);
 		return SCSI_RESET_PUNT;
 	}
 /*
@@ -5352,7 +5418,7 @@
  * Commands will now be queued in the waiting list until a settle 
  * delay of 2 seconds will be completed.
  */
-	ncr_start_reset(np, driver_setup.settle_delay);
+	ncr_start_reset(np);
 /*
  * First, look in the wakeup list
  */
@@ -5387,11 +5453,9 @@
  */
 	if (!found && sync_reset && !retrieve_from_waiting_list(0, np, cmd)) {
 		cmd->result = ScsiResult(DID_RESET, 0);
-		cmd->scsi_done(cmd);
+		ncr_queue_done_cmd(np, cmd);
 	}
 
-	restore_flags(flags);
-
 	return SCSI_RESET_SUCCESS;
 }
 
@@ -5404,30 +5468,19 @@
 **
 **==========================================================
 */
-static int ncr_abort_command (Scsi_Cmnd *cmd)
+static int ncr_abort_command (ncb_p np, Scsi_Cmnd *cmd)
 {
-        struct Scsi_Host   *host      = cmd->host;
 /*	Scsi_Device        *device    = cmd->device; */
-	struct host_data   *host_data = (struct host_data *) host->hostdata;
-	ncb_p np                      = host_data->ncb;
 	ccb_p cp;
-	u_long flags;
 	int found;
 	int retv;
 
-#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-	if (np->stalling == 2)
-		np->stalling = 0;
-#endif
-
-	save_flags(flags); cli();
 /*
  * First, look for the scsi command in the waiting list
  */
 	if (remove_from_waiting_list(np, cmd)) {
 		cmd->result = ScsiResult(DID_ABORT, 0);
-		cmd->scsi_done(cmd);
-		restore_flags(flags);
+		ncr_queue_done_cmd(np, cmd);
 		return SCSI_ABORT_SUCCESS;
 	}
 
@@ -5446,45 +5499,45 @@
 	}
 
 	if (!found) {
-		restore_flags(flags);
 		return SCSI_ABORT_NOT_RUNNING;
 	}
 
 	if (np->settle_time) {
-		restore_flags(flags);
 		return SCSI_ABORT_SNOOZE;
 	}
 
 	/*
-	**	Disable reselect.
-	**      Remove it from startqueue.
-	**	Set cp->tlimit to 0. The ncr_timeout() handler will use 
-	**	this condition in order to complete the canceled command 
-	**	after the script skipped the ccb, if necessary.
-	*/
-	cp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP);
-	if (cp->phys.header.launch.l_paddr ==
-		cpu_to_scr(NCB_SCRIPT_PHYS (np, select))) {
-		printf ("%s: abort ccb=%p (skip)\n", ncr_name (np), cp);
-		cp->phys.header.launch.l_paddr =
-			cpu_to_scr(NCB_SCRIPT_PHYS (np, skip));
-	}
+	**	If the CCB is active, patch schedule jumps for the 
+	**	script to abort the command.
+	*/
 
 	cp->tlimit = 0;
-	retv = SCSI_ABORT_PENDING;
+	switch(cp->host_status) {
+	case HS_BUSY:
+	case HS_NEGOTIATE:
+		printk ("%s: abort ccb=%p (cancel)\n", ncr_name (np), cp);
+			cp->start.schedule.l_paddr =
+				cpu_to_scr(NCB_SCRIPTH_PHYS (np, cancel));
+		retv = SCSI_ABORT_PENDING;
+		break;
+	case HS_DISCONNECT:
+		cp->restart.schedule.l_paddr =
+				cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
+		retv = SCSI_ABORT_PENDING;
+		break;
+	default:
+		retv = SCSI_ABORT_NOT_RUNNING;
+		break;
+
+	}
 
 	/*
 	**      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.
 	*/
-#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-	if (!np->stalling)
-#endif
 	OUTB (nc_istat, SIGP);
 
-	restore_flags(flags);
-
 	return retv;
 }
 
@@ -5508,7 +5561,7 @@
 	int target, lun;
 	int i;
 
-	printf("%s: releasing host resources\n", ncr_name(np));
+	printk("%s: releasing host resources\n", ncr_name(np));
 
 /*
 **	Stop the ncr_timeout process
@@ -5516,12 +5569,12 @@
 */
 
 #ifdef DEBUG_NCR53C8XX
-	printf("%s: stopping the timer\n", ncr_name(np));
+	printk("%s: stopping the timer\n", ncr_name(np));
 #endif
 	np->release_stage = 1;
-	for (i = 50 ; i && np->release_stage != 2 ; i--) DELAY(100000);
+	for (i = 50 ; i && np->release_stage != 2 ; i--) MDELAY (100);
 	if (np->release_stage != 2)
-		printf("%s: the timer seems to be already stopped\n", ncr_name(np));
+		printk("%s: the timer seems to be already stopped\n", ncr_name(np));
 	else np->release_stage = 2;
 
 /*
@@ -5529,7 +5582,7 @@
 */
 
 #ifdef DEBUG_NCR53C8XX
-	printf("%s: disabling chip interrupts\n", ncr_name(np));
+	printk("%s: disabling chip interrupts\n", ncr_name(np));
 #endif
 	OUTW (nc_sien , 0);
 	OUTB (nc_dien , 0);
@@ -5539,26 +5592,18 @@
 */
 
 #ifdef DEBUG_NCR53C8XX
-#ifdef __sparc__
-	printf("%s: freeing irq 0x%x\n", ncr_name(np), np->irq);
-#else
-	printf("%s: freeing irq %d\n", ncr_name(np), np->irq);
-#endif
+	printk("%s: freeing irq %d\n", ncr_name(np), np->irq);
 #endif
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
 	free_irq(np->irq, np);
-#else
-	free_irq(np->irq);
-#endif
 
 	/*
 	**	Reset NCR chip
 	**	Restore bios setting for automatic clock detection.
 	*/
 
-	printf("%s: resetting chip\n", ncr_name(np));
+	printk("%s: resetting chip\n", ncr_name(np));
 	OUTB (nc_istat,  SRST);
-	DELAY (1000);
+	UDELAY (100);
 	OUTB (nc_istat,  0   );
 
 	OUTB(nc_dmode,	np->sv_dmode);
@@ -5577,17 +5622,13 @@
 
 #ifndef NCR_IOMAPPED
 #ifdef DEBUG_NCR53C8XX
-	printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
+	printk("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128);
 #endif
 	unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128);
-#ifdef DEBUG_NCR53C8XX
-	printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096);
-#endif
-	unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096);
-#endif
+#endif /* !NCR_IOMAPPED */
 
 #ifdef DEBUG_NCR53C8XX
-	printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
+	printk("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128);
 #endif
 	release_region(np->port, 128);
 
@@ -5598,11 +5639,11 @@
 	while ((cp=np->ccb->link_ccb) != NULL) {
 		np->ccb->link_ccb = cp->link_ccb;
 		if (cp->host_status) {
-		printf("%s: shall free an active ccb (host_status=%d)\n",
+		printk("%s: shall free an active ccb (host_status=%d)\n",
 			ncr_name(np), cp->host_status);
 		}
 #ifdef DEBUG_NCR53C8XX
-	printf("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp);
+	printk("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp);
 #endif
 		m_free(cp, sizeof(*cp));
 	}
@@ -5617,14 +5658,16 @@
 			lp = tp->lp[lun];
 			if (lp) {
 #ifdef DEBUG_NCR53C8XX
-	printf("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
+	printk("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
 #endif
+				if (lp->maxnxs > 1)
+					m_free(lp->jump_ccb, 256);
 				m_free(lp, sizeof(*lp));
 			}
 		}
 	}
 
-	printf("%s: host resources successfully released\n", ncr_name(np));
+	printk("%s: host resources successfully released\n", ncr_name(np));
 
 	return 1;
 }
@@ -5650,20 +5693,8 @@
 	**	Sanity check
 	*/
 
-	if (!cp || (cp->magic!=CCB_MAGIC) || !cp->cmd) return;
-	cp->magic = 1;
-	cp->tlimit= 0;
-	cmd = cp->cmd;
-
-	/*
-	**	No Reselect anymore.
-	*/
-	cp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP);
-
-	/*
-	**	No starting.
-	*/
-	cp->phys.header.launch.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
+	if (!cp || cp->magic != CCB_MAGIC || !cp->cmd)
+		return;
 
 	/*
 	**	timestamp
@@ -5674,9 +5705,13 @@
 #endif
 
 	if (DEBUG_FLAGS & DEBUG_TINY)
-		printf ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp & 0xfff,
+		printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp & 0xfff,
 			cp->host_status,cp->scsi_status);
 
+	/*
+	**	Get command, target and lun pointers.
+	*/
+
 	cmd = cp->cmd;
 	cp->cmd = NULL;
 	tp = &np->target[cmd->target];
@@ -5692,17 +5727,32 @@
 		tp->nego_cp = 0;
 
 	/*
+	**	If auto-sense performed, change scsi status.
+	*/
+	if (cp->auto_sense) {
+		cp->scsi_status = cp->auto_sense;
+	}
+
+	/*
+	**	If we were recovering from queue full or performing 
+	**	auto-sense, requeue skipped CCBs to the wait queue.
+	*/
+
+	if (lp && lp->held_ccb) {
+		if (cp == lp->held_ccb) {
+			xpt_que_splice(&lp->skip_ccbq, &lp->wait_ccbq);
+			xpt_que_init(&lp->skip_ccbq);
+			lp->held_ccb = 0;
+		}
+	}
+
+	/*
 	**	Check for parity errors.
 	*/
 
-	if (cp->parity_status) {
+	if (cp->parity_status > 1) {
 		PRINT_ADDR(cmd);
-		printf ("%d parity error(s), fallback.\n", cp->parity_status);
-		/*
-		**	fallback to asynch transfer.
-		*/
-		tp->usrsync=255;
-		tp->period =  0;
+		printk ("%d parity error(s).\n",cp->parity_status);
 	}
 
 	/*
@@ -5713,13 +5763,13 @@
 		PRINT_ADDR(cmd);
 		switch (cp->xerr_status) {
 		case XE_EXTRA_DATA:
-			printf ("extraneous data discarded.\n");
+			printk ("extraneous data discarded.\n");
 			break;
 		case XE_BAD_PHASE:
-			printf ("illegal scsi phase (4/5).\n");
+			printk ("illegal scsi phase (4/5).\n");
 			break;
 		default:
-			printf ("extended error %d.\n", cp->xerr_status);
+			printk ("extended error %d.\n", cp->xerr_status);
 			break;
 		}
 		if (cp->host_status==HS_COMPLETE)
@@ -5727,95 +5777,69 @@
 	}
 
 	/*
+	**	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) {
+			PRINT_ADDR(cmd);
+			printk ("ERROR: cmd=%x host_status=%x scsi_status=%x\n",
+				cmd->cmnd[0], cp->host_status, cp->scsi_status);
+		}
+	}
+
+	/*
 	**	Check the status.
 	*/
 	if (   (cp->host_status == HS_COMPLETE)
 		&& (cp->scsi_status == S_GOOD ||
 		    cp->scsi_status == S_COND_MET)) {
-		/*
+                /*
 		**	All went well (GOOD status).
 		**	CONDITION MET status is returned on 
-		**	`Pre-Fetch' or `Search data' success.
-		*/
+                **	`Pre-Fetch' or `Search data' success.
+                */
 		cmd->result = ScsiResult(DID_OK, cp->scsi_status);
 
 		/*
-		** if (cp->phys.header.lastp != cp->phys.header.goalp)...
-		**
 		**	@RESID@
 		**	Could dig out the correct value for resid,
 		**	but it would be quite complicated.
-		**
-		**	The ah1542.c driver sets it to 0 too ...
 		*/
+		/* if (cp->phys.header.lastp != cp->phys.header.goalp) */
 
 		/*
-		**	Try to assign a ccb to this nexus
+		**	Allocate the lcb if not yet.
 		*/
-		ncr_alloc_ccb (np, cmd->target, cmd->lun);
+		if (!lp)
+			ncr_alloc_lcb (np, cmd->target, cmd->lun);
 
 		/*
-		**	On inquire cmd (0x12) save some data.
-		**	Clear questionnable capacities.
+		**	On standard INQUIRY response (EVPD and CmDt 
+		**	not set), setup logical unit according to 
+		**	announced capabilities.
 		*/
-		if (cmd->lun == 0 && cmd->cmnd[0] == 0x12) {
-			if (np->unit < SCSI_NCR_MAX_HOST) {
-				if (driver_setup.force_sync_nego)
-					((char *) cmd->request_buffer)[7] |= INQ7_SYNC;
-				else
-					((char *) cmd->request_buffer)[7] &=
-					(target_capabilities[np->unit].and_map[cmd->target]);
-			}
-			bcopy (	cmd->request_buffer,
-				&tp->inqdata,
-				sizeof (tp->inqdata));
-
-			/*
-			**	set number of tags
-			*/
-				ncr_setmaxtags (np, tp, driver_setup.default_tags);
-			/*
-			**	prepare negotiation of synch and wide.
-			*/
-			ncr_negotiate (np, tp);
-
-			/*
-			**	force quirks update before next command start
-			*/
-			tp->quirks |= QUIRK_UPDATE;
+		if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3)) {
+			ncr_setup_lcb (np, cmd->target, cmd->lun,
+				       (char *) cmd->request_buffer);
 		}
 
-		/*
-		**	Announce changes to the generic driver.
-		*/
-		if (lp) {
-			ncr_settags (tp, lp);
-			if (lp->reqlink != lp->actlink)
-				ncr_opennings (np, lp, cmd);
-		};
-
 		tp->bytes     += cp->data_len;
 		tp->transfers ++;
 
 		/*
 		**	If tags was reduced due to queue full,
-		**	increase tags if 100 good status received.
+		**	increase tags if 1000 good status received.
 		*/
-		if (tp->numtags < tp->maxtags) {
-			++tp->num_good;
-			if (tp->num_good >= 100) {
-				tp->num_good = 0;
-				++tp->numtags;
-				if (tp->numtags == 1) {
-					PRINT_ADDR(cmd);
-					printf("tagged command queueing resumed\n");
-				}
+		if (lp && lp->numtags < lp->maxtags) {
+			++lp->num_good;
+			if (lp->num_good >= 1000) {
+				lp->num_good = 0;
+				++lp->numtags;
+				ncr_setup_tags (np, cmd->target, cmd->lun);
 			}
 		}
 	} else if ((cp->host_status == HS_COMPLETE)
-		&& (cp->scsi_status == (S_SENSE|S_GOOD) ||
-		    cp->scsi_status == (S_SENSE|S_CHECK_COND))) {
-
+		&& (cp->scsi_status == S_CHECK_COND)) {
 		/*
 		**   Check condition code
 		*/
@@ -5824,49 +5848,20 @@
 		if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
 			u_char * p = (u_char*) & cmd->sense_buffer;
 			int i;
-			printf ("\n%s: sense data:", ncr_name (np));
-			for (i=0; i<14; i++) printf (" %x", *p++);
-			printf (".\n");
+			printk ("\n%s: sense data:", ncr_name (np));
+			for (i=0; i<14; i++) printk (" %x", *p++);
+			printk (".\n");
 		}
 
 	} else if ((cp->host_status == HS_COMPLETE)
 		&& (cp->scsi_status == S_BUSY ||
-		    cp->scsi_status == S_CONFLICT)) {
+		    cp->scsi_status == S_QUEUE_FULL)) {
 
 		/*
 		**   Target is busy.
 		*/
 		cmd->result = ScsiResult(DID_OK, cp->scsi_status);
 
-	} else if ((cp->host_status == HS_COMPLETE)
-		&& (cp->scsi_status == S_QUEUE_FULL)) {
-
-		/*
-		**   Target is stuffed.
-		*/
-		cmd->result = ScsiResult(DID_OK, cp->scsi_status);
-
-		/*
-		**  Suspend tagged queuing and start good status counter.
-		**  Announce changes to the generic driver.
-		*/
-		if (tp->numtags) {
-			/*
-			 * Decrease tp->maxtags (ecd, 980110)
-			 */
-			tp->maxtags = tp->numtags - 1;
-
-			PRINT_ADDR(cmd);
-			printf("QUEUE FULL! suspending tagged command queueing (setting maxtags to %d)\n", tp->maxtags);
-
-			tp->numtags	= 0;
-			tp->num_good	= 0;
-			if (lp) {
-				ncr_settags (tp, lp);
-				if (lp->reqlink != lp->actlink)
-					ncr_opennings (np, lp, cmd);
-			};
-		}
 	} else if ((cp->host_status == HS_SEL_TIMEOUT)
 		|| (cp->host_status == HS_TIMEOUT)) {
 
@@ -5895,7 +5890,7 @@
 		**  Other protocol messes
 		*/
 		PRINT_ADDR(cmd);
-		printf ("COMMAND FAILED (%x %x) @%p.\n",
+		printk ("COMMAND FAILED (%x %x) @%p.\n",
 			cp->host_status, cp->scsi_status, cp);
 
 		cmd->result = ScsiResult(DID_ERROR, cp->scsi_status);
@@ -5909,43 +5904,51 @@
 		u_char * p;
 		int i;
 		PRINT_ADDR(cmd);
-		printf (" CMD:");
+		printk (" CMD:");
 		p = (u_char*) &cmd->cmnd[0];
-		for (i=0; i<cmd->cmd_len; i++) printf (" %x", *p++);
+		for (i=0; i<cmd->cmd_len; i++) printk (" %x", *p++);
 
 		if (cp->host_status==HS_COMPLETE) {
 			switch (cp->scsi_status) {
 			case S_GOOD:
-				printf ("  GOOD");
+				printk ("  GOOD");
 				break;
 			case S_CHECK_COND:
-				printf ("  SENSE:");
+				printk ("  SENSE:");
 				p = (u_char*) &cmd->sense_buffer;
 				for (i=0; i<14; i++)
-					printf (" %x", *p++);
+					printk (" %x", *p++);
 				break;
 			default:
-				printf ("  STAT: %x\n", cp->scsi_status);
+				printk ("  STAT: %x\n", cp->scsi_status);
 				break;
 			}
-		} else printf ("  HOSTERROR: %x", cp->host_status);
-		printf ("\n");
+		} else printk ("  HOSTERROR: %x", cp->host_status);
+		printk ("\n");
 	}
 
 	/*
 	**	Free this ccb
 	*/
-	ncr_free_ccb (np, cp, cmd->target, cmd->lun);
+	ncr_free_ccb (np, cp);
+
+	/*
+	**	requeue awaiting scsi commands for this lun.
+	*/
+	if (lp && lp->queuedccbs < lp->queuedepth &&
+	    !xpt_que_empty(&lp->wait_ccbq))
+		ncr_start_next_ccb(np, lp, 2);
 
 	/*
-	**	requeue awaiting scsi commands
+	**	requeue awaiting scsi commands for this controller.
 	*/
-	if (np->waiting_list) requeue_waiting_list(np);
+	if (np->waiting_list)
+		requeue_waiting_list(np);
 
 	/*
 	**	signal completion to generic driver.
 	*/
-	cmd->scsi_done (cmd);
+	ncr_queue_done_cmd(np, cmd);
 }
 
 /*==========================================================
@@ -5957,41 +5960,92 @@
 **==========================================================
 */
 
-void ncr_wakeup (ncb_p np, u_long code)
+/*
+**	This CCB has been skipped by the NCR.
+**	Queue it in the correponding unit queue.
+*/
+void ncr_ccb_skipped(ncb_p np, ccb_p cp)
 {
-	/*
-	**	Starting at the default ccb and following
-	**	the links, complete all jobs with a
-	**	host_status greater than "disconnect".
-	**
-	**	If the "code" parameter is not zero,
-	**	complete all jobs that are not IDLE.
-	*/
+	tcb_p tp = &np->target[cp->target];
+	lcb_p lp = tp->lp[cp->lun];
 
-	ccb_p cp = np->ccb;
-	while (cp) {
-		switch (cp->host_status) {
+	if (lp && cp != np->ccb) {
+		cp->host_status &= ~HS_SKIPMASK;
+		cp->start.schedule.l_paddr = 
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
+		xpt_remque(&cp->link_ccbq);
+		xpt_insque_tail(&cp->link_ccbq, &lp->skip_ccbq);
+		if (cp->queued) {
+			--lp->queuedccbs;
+		}
+	}
+	if (cp->queued) {
+		--np->queuedccbs;
+		cp->queued = 0;
+	}
+}
+
+/*
+**	The NCR has completed CCBs.
+**	Look at the DONE QUEUE if enabled, otherwise scan all CCBs
+*/
+void ncr_wakeup_done (ncb_p np)
+{
+	ccb_p cp;
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+	int i, j;
+
+	i = np->ccb_done_ic;
+	while (1) {
+		j = i+1;
+		if (j >= MAX_DONE)
+			j = 0;
 
-		case HS_IDLE:
+		cp = np->ccb_done[j];
+		if (!CCB_DONE_VALID(cp))
 			break;
 
-		case HS_DISCONNECT:
-			if(DEBUG_FLAGS & DEBUG_TINY) printf ("D");
-			/* fall through */
-
-		case HS_BUSY:
-		case HS_NEGOTIATE:
-			if (!code) break;
-			cp->host_status = code;
+		np->ccb_done[j] = (ccb_p) CCB_DONE_EMPTY;
+		np->scripth->done_queue[5*j + 4] =
+				cpu_to_scr(NCB_SCRIPT_PHYS (np, done_plug));
+		MEMORY_BARRIER();
+		np->scripth->done_queue[5*i + 4] =
+				cpu_to_scr(NCB_SCRIPT_PHYS (np, done_end));
 
-			/* fall through */
+		if (cp->host_status & HS_DONEMASK)
+			ncr_complete (np, cp);
+		else if (cp->host_status & HS_SKIPMASK)
+			ncr_ccb_skipped (np, cp);
 
-		default:
+		i = j;
+	}
+	np->ccb_done_ic = i;
+#else
+	cp = np->ccb;
+	while (cp) {
+		if (cp->host_status & HS_DONEMASK)
 			ncr_complete (np, cp);
-			break;
-		};
-		cp = cp -> link_ccb;
-	};
+		else if (cp->host_status & HS_SKIPMASK)
+			ncr_ccb_skipped (np, cp);
+		cp = cp->link_ccb;
+	}
+#endif
+}
+
+/*
+**	Complete all active CCBs.
+*/
+void ncr_wakeup (ncb_p np, u_long code)
+{
+	ccb_p cp = np->ccb;
+
+	while (cp) {
+		if (cp->host_status != HS_IDLE) {
+			cp->host_status = code;
+			ncr_complete (np, cp);
+		}
+		cp = cp->link_ccb;
+	}
 }
 
 /*==========================================================
@@ -6003,35 +6057,59 @@
 **==========================================================
 */
 
-void ncr_init (ncb_p np, char * msg, u_long code)
+void ncr_init (ncb_p np, int reset, char * msg, u_long code)
 {
-	int	i;
-
-	/*
-	**	Reset chip.
-	*/
+ 	int	i;
 
-	OUTB (nc_istat,  SRST);
-	DELAY (10000);
+ 	/*
+	**	Reset chip if asked, otherwise just clear fifos.
+ 	*/
 
+	if (reset) {
+		OUTB (nc_istat,  SRST);
+		UDELAY (100);
+	}
+	else {
+		OUTB (nc_stest3, TE|CSF);
+		OUTONB (nc_ctest3, CLF);
+	}
+ 
 	/*
 	**	Message.
 	*/
 
-	if (msg) printf (KERN_INFO "%s: restart (%s).\n", ncr_name (np), msg);
+	if (msg) printk (KERN_INFO "%s: restart (%s).\n", ncr_name (np), msg);
 
 	/*
 	**	Clear Start Queue
 	*/
-	for (i=0;i<MAX_START;i++)
-		np -> squeue [i] = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
+	np->queuedepth = MAX_START - 1;	/* 1 entry needed as end marker */
+	for (i = 1; i < MAX_START + MAX_START; i += 2)
+		np->scripth0->tryloop[i] =
+				cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
 
 	/*
 	**	Start at first entry.
 	*/
 	np->squeueput = 0;
 	np->script0->startpos[0] = cpu_to_scr(NCB_SCRIPTH_PHYS (np, tryloop));
-	np->script0->start0  [0] = cpu_to_scr(SCR_INT ^ IFFALSE (0));
+
+	/*
+	**	Clear Done Queue
+	*/
+	for (i = 0; i < MAX_DONE; i++) {
+		np->ccb_done[i] = (ccb_p) CCB_DONE_EMPTY;
+		np->scripth0->done_queue[5*i + 4] =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, done_end));
+	}
+
+	/*
+	**	Start at first entry.
+	*/
+	np->script0->done_pos[0] = cpu_to_scr(NCB_SCRIPTH_PHYS (np,done_queue));
+	np->ccb_done_ic = MAX_DONE-1;
+	np->scripth0->done_queue[5*(MAX_DONE-1) + 4] =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, done_plug));
 
 	/*
 	**	Wakeup all pending jobs.
@@ -6043,6 +6121,8 @@
 	*/
 
 	OUTB (nc_istat,  0x00   );	/*  Remove Reset, abort */
+	UDELAY (2000);	/* The 895 needs time for the bus mode to settle */
+
 	OUTB (nc_scntl0, np->rv_scntl0 | 0xc0);
 					/*  full arb., ena parity, par->ATN  */
 	OUTB (nc_scntl1, 0x00);		/*  odd parity, and remove CRST!! */
@@ -6061,7 +6141,7 @@
 
 	OUTB (nc_stest2, EXT|np->rv_stest2);	/* Extended Sreq/Sack filtering */
 	OUTB (nc_stest3, TE);			/* TolerANT enable */
-	OUTB (nc_stime0, 0x0d	);		/* HTH disabled  STO 0.4 sec. */
+	OUTB (nc_stime0, 0x0c	);		/* HTH disabled  STO 0.25 sec */
 
 	/*
 	**	Disable disconnects.
@@ -6078,23 +6158,10 @@
 	}
 
 	/*
-	**    Upload the script into on-board RAM
-	*/
-	if (np->vaddr2) {
-		if (bootverbose)
-			printf ("%s: copying script fragments into the on-board RAM ...\n", ncr_name(np));
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
-		memcpy_toio(np->script, np->script0, sizeof(struct script));
-#else
-		memcpy(np->script, np->script0, sizeof(struct script));
-#endif
-	}
-
-	/*
 	**      enable ints
 	*/
 
-	OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST);
+	OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR);
 	OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID);
 
 	/*
@@ -6137,8 +6204,16 @@
 	/*
 	**    Start script processor.
 	*/
-
-	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+	MEMORY_BARRIER();
+	if (np->paddr2) {
+		if (bootverbose)
+			printk ("%s: Downloading SCSI SCRIPTS.\n",
+				ncr_name(np));
+		OUTL (nc_scratcha, vtophys(np->script0));
+		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, start_ram));
+	}
+	else
+		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
 }
 
 /*==========================================================
@@ -6166,14 +6241,6 @@
 	}
 
 	/*
-	**	if not scsi 2
-	**	don't believe FAST!
-	*/
-
-	if ((minsync < 50) && (tp->inqdata[2] & 0x0f) < 2)
-		minsync=50;
-
-	/*
 	**	our limit ..
 	*/
 
@@ -6249,7 +6316,7 @@
 	/*
 	**	Why not to try the immediate lower divisor and to choose 
 	**	the one that allows the fastest output speed ?
-	**	We don't want input speed too much greater than output speed.
+	**	We dont want input speed too much greater than output speed.
 	*/
 	if (div >= 1 && fak < 8) {
 		u_long fak2, per2;
@@ -6300,8 +6367,12 @@
 	for (cp = np->ccb; cp; cp = cp->link_ccb) {
 		if (!cp->cmd) continue;
 		if (cp->cmd->target != target) continue;
+#if 0
 		cp->sync_status = tp->sval;
 		cp->wide_status = tp->wval;
+#endif
+		cp->phys.select.sel_scntl3 = tp->wval;
+		cp->phys.select.sel_sxfer  = tp->sval;
 	};
 }
 
@@ -6316,15 +6387,15 @@
 {
 	Scsi_Cmnd *cmd;
 	tcb_p tp;
-	u_char target = INB (nc_ctest0) & 0x0f;
+	u_char target = INB (nc_sdid) & 0x0f;
 	u_char idiv;
 
-	assert (cp);
+	assert (cp && cp->cmd);
 	if (!cp) return;
 
 	cmd = cp->cmd;
-	assert (cmd);
 	if (!cmd) return;
+
 	assert (target == (cmd->target & 0xf));
 
 	tp = &np->target[target];
@@ -6354,7 +6425,7 @@
 	/*
 	**	Bells and whistles   ;-)
 	*/
-	PRINT_ADDR(cmd);
+	PRINT_TARGET(np, target);
 	if (sxfer & 0x01f) {
 		unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0);
 		unsigned mb10 = (f10 + tp->period/2) / tp->period;
@@ -6373,11 +6444,11 @@
 		else if	(tp->period < 2000)	scsi = "FAST-10";
 		else				scsi = "FAST-5";
 
-		printf ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
+		printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
 			tp->widedone > 1 ? "WIDE " : "",
 			mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f);
 	} else
-		printf ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
+		printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
 
 	/*
 	**	set actual value and sync_status
@@ -6399,17 +6470,17 @@
 static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack)
 {
 	Scsi_Cmnd *cmd;
-	u_short target = INB (nc_ctest0) & 0x0f;
+	u_short target = INB (nc_sdid) & 0x0f;
 	tcb_p tp;
 	u_char	scntl3;
 	u_char	sxfer;
 
-	assert (cp);
+	assert (cp && cp->cmd);
 	if (!cp) return;
 
 	cmd = cp->cmd;
-	assert (cmd);
 	if (!cmd) return;
+
 	assert (target == (cmd->target & 0xf));
 
 	tp = &np->target[target];
@@ -6429,11 +6500,11 @@
 	**	Bells and whistles   ;-)
 	*/
 	if (bootverbose >= 2) {
-		PRINT_ADDR(cmd);
+		PRINT_TARGET(np, target);
 		if (scntl3 & EWS)
-			printf ("WIDE SCSI (16 bit) enabled.\n");
+			printk ("WIDE SCSI (16 bit) enabled.\n");
 		else
-			printf ("WIDE SCSI disabled.\n");
+			printk ("WIDE SCSI disabled.\n");
 	}
 
 	/*
@@ -6452,71 +6523,107 @@
 
 static void ncr_setmaxtags (ncb_p np, tcb_p tp, u_long numtags)
 {
-	int l;
 	if (numtags > tp->usrtags)
 		numtags = tp->usrtags;
-	tp->numtags = numtags;
-	tp->maxtags = numtags;
 
-	for (l=0; l<MAX_LUN; l++) {
-		lcb_p lp;
-		u_char wastags;
+	if (tp) {
+		int ln;
+		for (ln = 0; ln < MAX_LUN; ln++) {
+			lcb_p lp = tp->lp[ln];
 
-		if (!tp) break;
-		lp=tp->lp[l];
-		if (!lp) continue;
-
-		wastags = lp->usetags;
-		ncr_settags (tp, lp);
-
-		if (numtags > 1 && lp->reqccbs > 1) {
-			PRINT_LUN(np, tp - np->target, l);
-			printf("using tagged command queueing, up to %ld cmds/lun\n", numtags);
-		}
-		else if (numtags <= 1 && wastags) {
-			PRINT_LUN(np, tp - np->target, l);
-			printf("disabling tagged command queueing\n");
+			if (!lp)
+				continue;
+			lp->maxtags = lp->numtags = numtags;
+			ncr_setup_tags (np, (tp - np->target), ln);
 		}
-	};
+	}
 }
 
-static void ncr_settags (tcb_p tp, lcb_p lp)
+static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln)
 {
-	u_char reqtags, tmp;
+	tcb_p tp = &np->target[tn];
+	lcb_p lp = tp->lp[ln];
+	u_char   reqtags, maxdepth;
+
+	/*
+	**	Just in case ...
+	*/
+	if ((!tp) || (!lp))
+		return;
+
+	/*
+	**	If SCSI device queue depth is not yet set, leave here.
+	*/
+	if (!lp->scdev_depth)
+		return;
 
-	if ((!tp) || (!lp)) return;
+	/*
+	**	Donnot allow more tags than the SCSI driver can queue 
+	**	for this device.
+	**	Donnot allow more tags than we can handle.
+	*/
+	maxdepth = lp->scdev_depth;
+	if (maxdepth > lp->maxnxs)	maxdepth    = lp->maxnxs;
+	if (lp->maxtags > maxdepth)	lp->maxtags = maxdepth;
+	if (lp->numtags > maxdepth)	lp->numtags = maxdepth;
 
 	/*
 	**	only devices conformant to ANSI Version >= 2
-	**	only devices capable of tagges commands
-	**	only disk devices
+	**	only devices capable of tagged commands
 	**	only if enabled by user ..
 	*/
-	if ((  tp->inqdata[2] & 0x7) >= 2 &&
-	    (  tp->inqdata[7] & INQ7_QUEUE) && ((tp->inqdata[0] & 0x1f)==0x00)
-		&& tp->numtags > 1) {
-		reqtags = tp->numtags;
-		if (lp->actlink <= 1)
-			lp->usetags=reqtags;
+	if ((lp->inq_byte7 & INQ7_QUEUE) && lp->numtags > 1) {
+		reqtags = lp->numtags;
 	} else {
 		reqtags = 1;
-		if (lp->actlink <= 1)
-			lp->usetags=0;
 	};
 
 	/*
-	**	don't announce more than available.
+	**	Update max number of tags
+	*/
+	lp->numtags = reqtags;
+	if (lp->numtags > lp->maxtags)
+		lp->maxtags = lp->numtags;
+
+	/*
+	**	If we want to switch tag mode, we must wait 
+	**	for no CCB to be active.
+	*/
+	if	(reqtags > 1 && lp->usetags) {	 /* Stay in tagged mode    */
+		if (lp->queuedepth == reqtags)	 /* Already announced	   */
+			return;
+		lp->queuedepth	= reqtags;
+	}
+	else if	(reqtags <= 1 && !lp->usetags) { /* Stay in untagged mode  */
+		lp->queuedepth	= reqtags;
+		return;
+	}
+	else {					 /* Want to switch tag mode */
+		if (lp->busyccbs)		 /* If not yet safe, return */
+			return;
+		lp->queuedepth	= reqtags;
+		lp->usetags	= reqtags > 1 ? 1 : 0;
+	}
+
+	/*
+	**	Patch the lun mini-script, according to tag mode.
 	*/
-	tmp = lp->actccbs;
-	if (tmp > reqtags) tmp = reqtags;
-	lp->reqlink = tmp;
+	lp->jump_tag.l_paddr = lp->usetags?
+			cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_tag)) :
+			cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_notag));
 
 	/*
-	**	don't discard if announced.
+	**	Announce change to user.
 	*/
-	tmp = lp->actlink;
-	if (tmp < reqtags) tmp = reqtags;
-	lp->reqccbs = tmp;
+	if (bootverbose) {
+		PRINT_LUN(np, tn, ln);
+		if (lp->usetags) {
+			printk("tagged command queue depth set to %d\n", reqtags);
+		}
+		else {
+			printk("tagged command queueing disabled\n");
+		}
+	}
 }
 
 /*----------------------------------------------------
@@ -6547,8 +6654,6 @@
 		break;
 
 	case UC_SETTAGS:
-		if (np->user.data > SCSI_NCR_MAX_TAGS)
-			np->user.data = SCSI_NCR_MAX_TAGS;
 		for (t=0; t<MAX_TARGET; t++) {
 			if (!((np->user.target>>t)&1)) continue;
 			np->target[t].usrtags = np->user.data;
@@ -6566,6 +6671,10 @@
 		np->order = np->user.data;
 		break;
 
+	case UC_SETVERBOSE:
+		np->verbose = np->user.data;
+		break;
+
 	case UC_SETWIDE:
 		for (t=0; t<MAX_TARGET; t++) {
 			u_long size;
@@ -6586,110 +6695,16 @@
 		};
 		break;
 
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	case UC_CLEARPROF:
 		bzero(&np->profile, sizeof(np->profile));
 		break;
-#ifdef	UC_DEBUG_ERROR_RECOVERY
-	case UC_DEBUG_ERROR_RECOVERY:
-		np->debug_error_recovery = np->user.data;
-		break;
 #endif
 	}
 	np->user.cmd=0;
 }
 #endif
 
-
-/*=====================================================================
-**
-**    Embedded error recovery debugging code.
-**
-**=====================================================================
-**
-**    This code is conditionned by SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT.
-**    It only can be enabled after boot-up with a control command.
-**
-**    Every 30 seconds the timer handler of the driver decides to 
-**    change the behaviour of the driver in order to trigger errors.
-**
-**    If last command was "debug_error_recovery sge", the driver 
-**    sets sync offset of all targets that use sync transfers to 2, 
-**    and so hopes a SCSI gross error at the next read operation.
-**
-**    If last command was "debug_error_recovery abort", the driver 
-**    does not signal new scsi commands to the script processor, until 
-**    it is asked to abort or reset a command by the mid-level driver.
-**
-**    If last command was "debug_error_recovery reset", the driver 
-**    does not signal new scsi commands to the script processor, until 
-**    it is asked to reset a command by the mid-level driver.
-**
-**    If last command was "debug_error_recovery parity", the driver 
-**    will assert ATN on the next DATA IN phase mismatch, and so will 
-**    behave as if a parity error had been detected.
-**
-**    The command "debug_error_recovery none" makes the driver behave 
-**    normaly.
-**
-**=====================================================================
-*/
-
-#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-static void ncr_trigger_errors (ncb_p np)
-{
-	/*
-	** 	If np->debug_error_recovery is not zero, we want to 
-	**	simulate common errors in order to test error recovery.
-	*/
-	do {
-		static u_long last = 0l;
-
-		if (!np->debug_error_recovery)
-			break;
-		if (!last)
-			last = jiffies;
-		else if (jiffies < last + 30*HZ)
-			break;
-		last = jiffies;
-		/*
-		 * This one triggers SCSI gross errors.
-		 */
-		if (np->debug_error_recovery == 1) {
-			int i;
-			printf("%s: testing error recovery from SCSI gross error...\n", ncr_name(np));
-			for (i = 0 ; i < MAX_TARGET ; i++) {
-				if (np->target[i].sval & 0x1f) {
-					np->target[i].sval &= ~0x1f;
-					np->target[i].sval += 2;
-				}
-			}
-		}
-		/*
-		 * This one triggers abort from the mid-level driver.
-		 */
-		else if (np->debug_error_recovery == 2) {
-			printf("%s: testing error recovery from mid-level driver abort()...\n", ncr_name(np));
-			np->stalling = 2;
-		}
-		/*
-		 * This one triggers reset from the mid-level driver.
-		 */
-		else if (np->debug_error_recovery == 3) {
-			printf("%s: testing error recovery from mid-level driver reset()...\n", ncr_name(np));
-			np->stalling = 3;
-		}
-		/*
-		 * This one set ATN on phase mismatch in DATA IN phase and so 
-		 * will behave as on scsi parity error detected.
-		 */
-		else if (np->debug_error_recovery == 4) {
-			printf("%s: testing data in parity error...\n", ncr_name(np));
-			np->assert_atn = 1;
-		}
-	} while (0);
-}
-#endif
-
 /*==========================================================
 **
 **
@@ -6707,9 +6722,6 @@
 static void ncr_timeout (ncb_p np)
 {
 	u_long	thistime = jiffies;
-	u_long	count = 0;
-	ccb_p cp;
-	u_long flags;
 
 	/*
 	**	If release process in progress, let's go
@@ -6722,18 +6734,9 @@
 		return;
 	}
 
-	np->timer.expires =
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
-			jiffies +
-#endif
-			SCSI_NCR_TIMER_INTERVAL;
-
+	np->timer.expires = jiffies + SCSI_NCR_TIMER_INTERVAL;
 	add_timer(&np->timer);
 
-#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-	ncr_trigger_errors (np);
-#endif
-
 	/*
 	**	If we are resetting the ncr, wait for settle_time before 
 	**	clearing it. Then command processing will be resumed.
@@ -6741,12 +6744,10 @@
 	if (np->settle_time) {
 		if (np->settle_time <= thistime) {
 			if (bootverbose > 1)
-				printf("%s: command processing resumed\n", ncr_name(np));
-			save_flags(flags); cli();
+				printk("%s: command processing resumed\n", ncr_name(np));
 			np->settle_time	= 0;
 			np->disc	= 1;
 			requeue_waiting_list(np);
-			restore_flags(flags);
 		}
 		return;
 	}
@@ -6756,99 +6757,20 @@
 	**	to perform abort of a command, we must look at ccbs about 
 	**	every 0.25 second.
 	*/
-	if (np->lasttime + (HZ>>2) <= thistime) {
+	if (np->lasttime + 4*HZ < thistime) {
 		/*
 		**	block ncr interrupts
 		*/
-		save_flags(flags); cli();
-
 		np->lasttime = thistime;
 
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 		/*
 		**	Reset profile data to avoid ugly overflow
 		**	(Limited to 1024 GB for 32 bit architecture)
 		*/
 		if (np->profile.num_kbytes > (~0UL >> 2))
 			bzero(&np->profile, sizeof(np->profile));
-
-		/*----------------------------------------------------
-		**
-		**	handle ncr chip timeouts
-		**
-		**	Assumption:
-		**	We have a chance to arbitrate for the
-		**	SCSI bus at least every 10 seconds.
-		**
-		**----------------------------------------------------
-		*/
-#if 0
-		if (thistime < np->heartbeat + HZ + HZ)
-			np->latetime = 0;
-		else
-			np->latetime++;
-#endif
-
-		/*----------------------------------------------------
-		**
-		**	handle ccb timeouts
-		**
-		**----------------------------------------------------
-		*/
-
-		for (cp=np->ccb; cp; cp=cp->link_ccb) {
-			/*
-			**	look for timed out ccbs.
-			*/
-			if (!cp->host_status) continue;
-			count++;
-			/*
-			**	Have to force ordered tag to avoid timeouts
-			*/
-			if (cp->cmd && cp->tlimit && cp->tlimit <= 
-				thistime + NCR_TIMEOUT_INCREASE + SCSI_NCR_TIMEOUT_ALERT) {
-				lcb_p lp;
-				lp = np->target[cp->cmd->target].lp[cp->cmd->lun];
-				if (lp && !lp->force_ordered_tag) {
-					lp->force_ordered_tag = 1;
-				}
-			}
-			/*
-			**	ncr_abort_command() cannot complete canceled 
-			**	commands immediately. It sets tlimit to zero 
-			**	and ask the script to skip the scsi process if 
-			**	necessary. We have to complete this work here.
-			*/
-
-			if (cp->tlimit) continue;
-
-			switch (cp->host_status) {
-
-			case HS_BUSY:
-			case HS_NEGOTIATE:
-				/*
-				** still in start queue ?
-				*/
-				if (cp->phys.header.launch.l_paddr ==
-					cpu_to_scr(NCB_SCRIPT_PHYS (np, skip)))
-					continue;
-
-				/* fall through */
-			case HS_DISCONNECT:
-				cp->host_status=HS_ABORTED;
-			};
-			cp->tag = 0;
-
-			/*
-			**	wakeup this ccb.
-			*/
-			ncr_complete (np, cp);
-
-#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-			if (!np->stalling)
 #endif
-			OUTB (nc_istat, SIGP);
-		}
-		restore_flags(flags);
 	}
 
 #ifdef SCSI_NCR_BROKEN_INTR
@@ -6857,11 +6779,9 @@
 		/*
 		**	Process pending interrupts.
 		*/
-		save_flags(flags); cli();
-		if (DEBUG_FLAGS & DEBUG_TINY) printf ("{");
+		if (DEBUG_FLAGS & DEBUG_TINY) printk ("{");
 		ncr_exception (np);
-		if (DEBUG_FLAGS & DEBUG_TINY) printf ("}");
-		restore_flags(flags);
+		if (DEBUG_FLAGS & DEBUG_TINY) printk ("}");
 	}
 #endif /* SCSI_NCR_BROKEN_INTR */
 }
@@ -6910,14 +6830,14 @@
 	if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) {
 		script_ofs	= dsp - np->p_script;
 		script_size	= sizeof(struct script);
-		script_base	= (u_char *) np->script;
+		script_base	= (u_char *) np->script0;
 		script_name	= "script";
 	}
 	else if (np->p_scripth < dsp && 
 		 dsp <= np->p_scripth + sizeof(struct scripth)) {
 		script_ofs	= dsp - np->p_scripth;
 		script_size	= sizeof(struct scripth);
-		script_base	= (u_char *) np->scripth;
+		script_base	= (u_char *) np->scripth0;
 		script_name	= "scripth";
 	} else {
 		script_ofs	= dsp;
@@ -6926,22 +6846,22 @@
 		script_name	= "mem";
 	}
 
-	printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n",
-		ncr_name (np), (unsigned)INB (nc_ctest0)&0x0f, dstat, sist,
+	printk ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n",
+		ncr_name (np), (unsigned)INB (nc_sdid)&0x0f, dstat, sist,
 		(unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), (unsigned)INB (nc_sbdl),
 		(unsigned)INB (nc_sxfer),(unsigned)INB (nc_scntl3), script_name, script_ofs,
 		(unsigned)INL (nc_dbc));
 
 	if (((script_ofs & 3) == 0) &&
 	    (unsigned)script_ofs < script_size) {
-		printf ("%s: script cmd = %08x\n", ncr_name(np),
+		printk ("%s: script cmd = %08x\n", ncr_name(np),
 			(int) *(ncrcmd *)(script_base + script_ofs));
 	}
 
-        printf ("%s: regdump:", ncr_name(np));
+        printk ("%s: regdump:", ncr_name(np));
         for (i=0; i<16;i++)
-            printf (" %02x", (unsigned)INB_OFF(i));
-        printf (".\n");
+            printk (" %02x", (unsigned)INB_OFF(i));
+        printk (".\n");
 }
 
 /*============================================================
@@ -6987,23 +6907,25 @@
 	**	Since the global header may be copied back to a CCB 
 	**	using a posted PCI memory write, the last operation on 
 	**	the istat register is a READ in order to flush posted 
-	**	PCI commands (Btw, the 'do' loop is probably useless).
+	**	PCI write commands.
 	*/
 	istat = INB (nc_istat);
 	if (istat & INTF) {
-		do {
-			OUTB (nc_istat, (istat & SIGP) | INTF);
-			istat = INB (nc_istat);
-		} while (istat & INTF);
-		if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
+		OUTB (nc_istat, (istat & SIGP) | INTF);
+		istat = INB (nc_istat);
+		if (DEBUG_FLAGS & DEBUG_TINY) printk ("F ");
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 		np->profile.num_fly++;
-		ncr_wakeup (np, 0);
+#endif
+		ncr_wakeup_done (np);
 	};
 
 	if (!(istat & (SIP|DIP)))
 		return;
 
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	np->profile.num_int++;
+#endif
 
 	if (istat & CABRT)
 		OUTB (nc_istat, CABRT);
@@ -7017,7 +6939,7 @@
 	dstat = (istat & DIP) ? INB (nc_dstat) : 0;
 
 	if (DEBUG_FLAGS & DEBUG_TINY)
-		printf ("<%d|%x:%x|%x:%x>",
+		printk ("<%d|%x:%x|%x:%x>",
 			(int)INB(nc_scr0),
 			dstat,sist,
 			(unsigned)INL(nc_dsp),
@@ -7054,12 +6976,11 @@
 		**  DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 2.
 		*/
 		if (!(sist & (SBMC|PAR)) && !(dstat & SSI)) {
-			printf(	"%s: unknown interrupt(s) ignored, "
+			printk(	"%s: unknown interrupt(s) ignored, "
 				"ISTAT=%x DSTAT=%x SIST=%x\n",
 				ncr_name(np), istat, dstat, sist);
 			return;
 		}
-
 		OUTONB (nc_dcntl, (STD|NOCOM));
 		return;
 	};
@@ -7080,7 +7001,7 @@
 	*/
 
 	if (sist & RST) {
-		ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET);
+		ncr_init (np, 1, bootverbose ? "scsi reset" : NULL, HS_RESET);
 		return;
 	};
 
@@ -7117,29 +7038,26 @@
 
 	ncr_log_hard_error(np, sist, dstat);
 
-	printf ("%s: have to clear fifos.\n", ncr_name (np));
+	printk ("%s: have to clear fifos.\n", ncr_name (np));
 	OUTB (nc_stest3, TE|CSF);
 	OUTONB (nc_ctest3, CLF);
 
 	if ((sist & (SGE)) ||
 		(dstat & (MDPE|BF|ABORT|IID))) {
-		ncr_start_reset(np, driver_setup.settle_delay);
+		ncr_start_reset(np);
 		return;
 	};
 
 	if (sist & HTH) {
-		printf ("%s: handshake timeout\n", ncr_name(np));
-		ncr_start_reset(np, driver_setup.settle_delay);
+		printk ("%s: handshake timeout\n", ncr_name(np));
+		ncr_start_reset(np);
 		return;
 	};
 
 	if (sist & UDC) {
-		printf ("%s: unexpected disconnect\n", ncr_name(np));
-		if (INB (nc_scr1) != 0xff) {
-			OUTB (nc_scr1, HS_UNEXPECTED);
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
-		};
-		ncr_start_reset(np, driver_setup.settle_delay);
+		printk ("%s: unexpected disconnect\n", ncr_name(np));
+		OUTB (HS_PRT, HS_UNEXPECTED);
+		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup));
 		return;
 	};
 
@@ -7148,7 +7066,7 @@
 	**	Print a message. The timeout will do the real work.
 	**=========================================================
 	*/
-	printf ("%s: unknown interrupt\n", ncr_name(np));
+	printk ("%s: unknown interrupt\n", ncr_name(np));
 }
 
 /*==========================================================
@@ -7169,9 +7087,9 @@
 
 void ncr_int_sto (ncb_p np)
 {
-	u_long dsa, scratcha, diff;
+	u_long dsa;
 	ccb_p cp;
-	if (DEBUG_FLAGS & DEBUG_TINY) printf ("T");
+	if (DEBUG_FLAGS & DEBUG_TINY) printk ("T");
 
 	/*
 	**	look for ccb and set the status.
@@ -7188,21 +7106,11 @@
 	};
 
 	/*
-	**	repair start queue
+	**	repair start queue and jump to start point.
 	*/
 
-	scratcha = INL (nc_scratcha);
-	diff = scratcha - NCB_SCRIPTH_PHYS (np, tryloop);
-
-/*	assert ((diff <= MAX_START * 20) && !(diff % 20));*/
-
-	if ((diff <= MAX_START * 20) && !(diff % 20)) {
-		np->script->startpos[0] = cpu_to_scr(scratcha);
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
-		return;
-	};
-	ncr_init (np, "selection timeout", HS_FAIL);
-	np->disc = 1;
+	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sto_restart));
+	return;
 }
 
 /*==========================================================
@@ -7226,13 +7134,22 @@
 {
 	u_char scsi_mode = INB (nc_stest4) & SMODE;
 
-	printf("%s: SCSI bus mode change from %x to %x, resetting ...\n",
-		ncr_name(np), np->scsi_mode, scsi_mode);
+	if (scsi_mode != np->scsi_mode) {
+		printk("%s: SCSI bus mode change from %x to %x.\n",
+			ncr_name(np), np->scsi_mode, scsi_mode);
 
-	np->scsi_mode = scsi_mode;
-	ncr_start_reset(np, driver_setup.settle_delay);
+		np->scsi_mode = scsi_mode;
 
-	return 1;
+
+		/*
+		**	Suspend command processing for 1 second and 
+		**	reinitialize all except the chip.
+		*/
+		np->settle_time	= jiffies + HZ;
+		ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET);
+		return 1;
+	}
+	return 0;
 }
 
 /*==========================================================
@@ -7241,16 +7158,73 @@
 **
 **==========================================================
 **
-**	SCSI parity errors are handled by the SCSI script.
-**	So, we just print some message.
 **
 **----------------------------------------------------------
 */
 
 static int ncr_int_par (ncb_p np)
 {
-	printf("%s: SCSI parity error detected\n", ncr_name(np));
-	return 0;
+	u_char	hsts	= INB (HS_PRT);
+	u_int32	dbc	= INL (nc_dbc);
+	u_char	sstat1	= INB (nc_sstat1);
+	int phase	= -1;
+	int msg		= -1;
+	u_int32 jmp;
+
+	printk("%s: SCSI parity error detected: SCR1=%d DBC=%x SSTAT1=%x\n",
+		ncr_name(np), hsts, dbc, sstat1);
+
+	/*
+	 *	Ignore the interrupt if the NCR is not connected 
+	 *	to the SCSI bus, since the right work should have  
+	 *	been done on unexpected disconnection handling.
+	 */
+	if (!(INB (nc_scntl1) & ISCON))
+		return 0;
+
+	/*
+	 *	If the nexus is not clearly identified, reset the bus.
+	 *	We will try to do better later.
+	 */
+	if (hsts & HS_INVALMASK)
+		goto reset_all;
+
+	/*
+	 *	If the SCSI parity error occurs in MSG IN phase, prepare a 
+	 *	MSG PARITY message. Otherwise, prepare a INITIATOR DETECTED 
+	 *	ERROR message and let the device decide to retry the command 
+	 *	or to terminate with check condition. If we were in MSG IN 
+	 *	phase waiting for the response of a negotiation, we will 
+	 *	get SIR_NEGO_FAILED at dispatch.
+	 */
+	if (!(dbc & 0xc0000000))
+		phase = (dbc >> 24) & 7;
+	if (phase == 7)
+		msg = M_PARITY;
+	else
+		msg = M_ID_ERROR;
+
+	/*
+	 *	If the NCR stopped on a MOVE ^ DATA_IN, we jump to a 
+	 *	script that will ignore all data in bytes until phase 
+	 *	change, since we are not sure the chip will wait the phase 
+	 *	change prior to delivering the interrupt.
+	 */
+	if (phase == 1)
+		jmp = NCB_SCRIPTH_PHYS (np, par_err_data_in);
+	else
+		jmp = NCB_SCRIPTH_PHYS (np, par_err_other);
+
+	OUTONB (nc_ctest3, CLF );	/* clear dma fifo  */
+	OUTB (nc_stest3, TE|CSF);	/* clear scsi fifo */
+
+	np->msgout[0] = msg;
+	OUTL (nc_dsp, jmp);
+	return 1;
+
+reset_all:
+	ncr_start_reset(np);
+	return 1;
 }
 
 /*==========================================================
@@ -7320,72 +7294,89 @@
 			if (ss2 & ORF1) rest++;
 		};
 
-		OUTONB (nc_ctest3, CLF );	/* clear dma fifo  */
-		OUTB (nc_stest3, TE|CSF);	/* clear scsi fifo */
-
 		if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
-			printf ("P%x%x RL=%d D=%d SS0=%x ", cmd&7, sbcl&7,
+			printk ("P%x%x RL=%d D=%d SS0=%x ", cmd&7, sbcl&7,
 				(unsigned) rest, (unsigned) delta, ss0);
 
 	} else	{
 		if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
-			printf ("P%x%x RL=%d ", cmd&7, sbcl&7, rest);
-		if ((cmd & 7) != 1) {
-			OUTONB (nc_ctest3, CLF );
-			OUTB (nc_stest3, TE|CSF);
-		}
+			printk ("P%x%x RL=%d ", cmd&7, sbcl&7, rest);
 	}
 
 	/*
-	**	locate matching cp
+	**	Clear fifos.
 	*/
-	dsa = INL (nc_dsa);
-	cp  = np->ccb;
-	while (cp && (CCB_PHYS (cp, phys) != dsa))
-		cp = cp->link_ccb;
+	OUTONB (nc_ctest3, CLF );	/* clear dma fifo  */
+	OUTB (nc_stest3, TE|CSF);	/* clear scsi fifo */
 
-	if (!cp) {
-	    printf ("%s: SCSI phase error fixup: CCB already dequeued (0x%08lx)\n", 
-		    ncr_name (np), (u_long) np->header.cp);
-	    return;
-	}
-	if (cp != np->header.cp) {
-	    printf ("%s: SCSI phase error fixup: CCB address mismatch (0x%08lx != 0x%08lx)\n", 
-		    ncr_name (np), (u_long) cp, (u_long) np->header.cp);
-/*	    return;*/
+	/*
+	**	locate matching cp.
+	**	if the interrupted phase is DATA IN or DATA OUT,
+	**	trust the global header.
+	*/
+	dsa = INL (nc_dsa);
+	if (!(cmd & 6)) {
+		cp = np->header.cp;
+		if (CCB_PHYS(cp, phys) != dsa)
+			cp = 0;
+	} else {
+		cp  = np->ccb;
+		while (cp && (CCB_PHYS (cp, phys) != dsa))
+			cp = cp->link_ccb;
 	}
 
 	/*
-	**	find the interrupted script command,
+	**	try to find the interrupted script command,
 	**	and the address at which to continue.
 	*/
-
-	if (dsp == vtophys (&cp->patch[2])) {
-		vdsp = &cp->patch[0];
-		nxtdsp = scr_to_cpu(vdsp[3]);
-	} else if (dsp == vtophys (&cp->patch[6])) {
-		vdsp = &cp->patch[4];
-		nxtdsp = scr_to_cpu(vdsp[3]);
-	} else if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) {
-		vdsp = (u_int32 *) ((char*)np->script - np->p_script + dsp -8);
+	vdsp	= 0;
+	nxtdsp	= 0;
+	if	(dsp >  np->p_script &&
+		 dsp <= np->p_script + sizeof(struct script)) {
+		vdsp = (u_int32 *)((char*)np->script0 + (dsp-np->p_script-8));
 		nxtdsp = dsp;
-	} else {
-		vdsp = (u_int32 *) ((char*)np->scripth - np->p_scripth + dsp -8);
+	}
+	else if	(dsp >  np->p_scripth &&
+		 dsp <= np->p_scripth + sizeof(struct scripth)) {
+		vdsp = (u_int32 *)((char*)np->scripth0 + (dsp-np->p_scripth-8));
 		nxtdsp = dsp;
-	};
+	}
+	else if (cp) {
+		if	(dsp == vtophys (&cp->patch[2])) {
+			vdsp = &cp->patch[0];
+			nxtdsp = scr_to_cpu(vdsp[3]);
+		}
+		else if (dsp == vtophys (&cp->patch[6])) {
+			vdsp = &cp->patch[4];
+			nxtdsp = scr_to_cpu(vdsp[3]);
+		}
+	}
 
 	/*
 	**	log the information
 	*/
 
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
-		printf ("\nCP=%p CP2=%p DSP=%x NXT=%x VDSP=%p CMD=%x ",
+		printk ("\nCP=%p CP2=%p DSP=%x NXT=%x VDSP=%p CMD=%x ",
 			cp, np->header.cp,
 			(unsigned)dsp,
 			(unsigned)nxtdsp, vdsp, cmd);
 	};
 
 	/*
+	**	cp=0 means that the DSA does not point to a valid control 
+	**	block. This should not happen since we donnot use multi-byte 
+	**	move while we are being reselected ot after command complete.
+	**	We are not able to recover from such a phase error.
+	*/
+	if (!cp) {
+		printk ("%s: SCSI phase error fixup: "
+			"CCB already dequeued (0x%08lx)\n", 
+			ncr_name (np), (u_long) np->header.cp);
+		goto reset_all;
+	}
+
+	/*
 	**	get old startaddress and old length.
 	*/
 
@@ -7401,7 +7392,7 @@
 	};
 
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
-		printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n",
+		printk ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n",
 			(unsigned) (scr_to_cpu(vdsp[0]) >> 24),
 			tblp,
 			(unsigned) olen,
@@ -7414,71 +7405,285 @@
 
 	if (cmd != (scr_to_cpu(vdsp[0]) >> 24)) {
 		PRINT_ADDR(cp->cmd);
-		printf ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
+		printk ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
 			(unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24);
-		
+
+		goto reset_all;
+	}
+
+	/*
+	**	cp != np->header.cp means that the header of the CCB 
+	**	currently being processed has not yet been copied to 
+	**	the global header area. That may happen if the device did 
+	**	not accept all our messages after having been selected.
+	*/
+	if (cp != np->header.cp) {
+		printk ("%s: SCSI phase error fixup: "
+			"CCB address mismatch (0x%08lx != 0x%08lx)\n", 
+			ncr_name (np), (u_long) cp, (u_long) np->header.cp);
+	}
+
+	/*
+	**	if old phase not dataphase, leave here.
+	*/
+
+	if (cmd & 0x06) {
+		PRINT_ADDR(cp->cmd);
+		printk ("phase change %x-%x %d@%08x resid=%d.\n",
+			cmd&7, sbcl&7, (unsigned)olen,
+			(unsigned)oadr, (unsigned)rest);
+		goto unexpected_phase;
+	};
+
+	/*
+	**	choose the correct patch area.
+	**	if savep points to one, choose the other.
+	*/
+
+	newcmd = cp->patch;
+	if (cp->phys.header.savep == cpu_to_scr(vtophys (newcmd))) newcmd+=4;
+
+	/*
+	**	fillin the commands
+	*/
+
+	newcmd[0] = cpu_to_scr(((cmd & 0x0f) << 24) | rest);
+	newcmd[1] = cpu_to_scr(oadr + olen - rest);
+	newcmd[2] = cpu_to_scr(SCR_JUMP);
+	newcmd[3] = cpu_to_scr(nxtdsp);
+
+	if (DEBUG_FLAGS & DEBUG_PHASE) {
+		PRINT_ADDR(cp->cmd);
+		printk ("newcmd[%d] %x %x %x %x.\n",
+			(int) (newcmd - cp->patch),
+			(unsigned)scr_to_cpu(newcmd[0]),
+			(unsigned)scr_to_cpu(newcmd[1]),
+			(unsigned)scr_to_cpu(newcmd[2]),
+			(unsigned)scr_to_cpu(newcmd[3]));
+	}
+	/*
+	**	fake the return address (to the patch).
+	**	and restart script processor at dispatcher.
+	*/
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+	np->profile.num_break++;
+#endif
+	OUTL (nc_temp, vtophys (newcmd));
+	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
+	return;
+
+	/*
+	**	Unexpected phase changes that occurs when the current phase 
+	**	is not a DATA IN or DATA OUT phase are due to error conditions.
+	**	Such event may only happen when the SCRIPTS is using a 
+	**	multibyte SCSI MOVE.
+	**
+	**	Phase change		Some possible cause
+	**
+	**	COMMAND  --> MSG IN	SCSI parity error detected by target.
+	**	COMMAND  --> STATUS	Bad command or refused by target.
+	**	MSG OUT  --> MSG IN     Message rejected by target.
+	**	MSG OUT  --> COMMAND    Bogus target that discards extended
+	**				negotiation messages.
+	**
+	**	The code below does not care of the new phase and so 
+	**	trusts the target. Why to annoy it ?
+	**	If the interrupted phase is COMMAND phase, we restart at
+	**	dispatcher.
+	**	If a target does not get all the messages after selection, 
+	**	the code assumes blindly that the target discards extended 
+	**	messages and clears the negotiation status.
+	**	If the target does not want all our response to negotiation,
+	**	we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids 
+	**	bloat for such a should_not_happen situation).
+	**	In all other situation, we reset the BUS.
+	**	Are these assumptions reasonnable ? (Wait and see ...)
+	*/
+unexpected_phase:
+	dsp -= 8;
+	nxtdsp = 0;
+
+	switch (cmd & 7) {
+	case 2:	/* COMMAND phase */
+		nxtdsp = NCB_SCRIPT_PHYS (np, dispatch);
+		break;
+#if 0
+	case 3:	/* STATUS  phase */
+		nxtdsp = NCB_SCRIPT_PHYS (np, dispatch);
+		break;
+#endif
+	case 6:	/* MSG OUT phase */
+		np->scripth->nxtdsp_go_on[0] = cpu_to_scr(dsp + 8);
+		if	(dsp == NCB_SCRIPT_PHYS (np, send_ident)) {
+			cp->host_status = HS_BUSY;
+			nxtdsp = NCB_SCRIPTH_PHYS (np, clratn_go_on);
+		}
+		else if	(dsp == NCB_SCRIPTH_PHYS (np, send_wdtr) ||
+			 dsp == NCB_SCRIPTH_PHYS (np, send_sdtr)) {
+			nxtdsp = dsp - 8; /* Should raise SIR_NEGO_PROTO */
+		}
+		break;
+#if 0
+	case 7:	/* MSG IN  phase */
+		nxtdsp = NCB_SCRIPT_PHYS (np, clrack);
+		break;
+#endif
+	}
+
+	if (nxtdsp) {
+		OUTL (nc_dsp, nxtdsp);
 		return;
 	}
 
-#ifdef	SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT
-	if ((cmd & 7) == 1 && np->assert_atn) {
-		np->assert_atn = 0;
-		OUTONB(nc_socl, CATN);
-	}
-#endif
+reset_all:
+	ncr_start_reset(np);
+}
+
+
+static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp)
+{
+	Scsi_Cmnd *cmd	= cp->cmd;
+	tcb_p tp	= &np->target[cmd->target];
+	lcb_p lp	= tp->lp[cmd->lun];
+	XPT_QUEHEAD	*qp;
+	ccb_p		cp2;
+	int		disc_cnt = 0;
+	int		busy_cnt = 0;
+	u_int32		startp;
+	u_char		s_status = INB (SS_PRT);
+
+	/*
+	**	Let the SCRIPTS processor skip all not yet started CCBs,
+	**	and count disconnected CCBs. Since the busy queue is in 
+	**	the same order as the chip start queue, disconnected CCBs 
+	**	are before cp and busy ones after.
+	*/
+	if (lp) {
+		qp = lp->busy_ccbq.blink;
+		while (qp != &lp->busy_ccbq) {
+			cp2 = xpt_que_entry(qp, struct ccb, link_ccbq);
+			qp  = qp->blink;
+			++busy_cnt;
+			if (cp2 == cp)
+				break;
+			cp2->start.schedule.l_paddr =
+			cpu_to_scr(NCB_SCRIPTH_PHYS (np, skip));
+		}
+		lp->held_ccb = cp;	/* Requeue when this one completes */
+		disc_cnt = lp->queuedccbs - busy_cnt;
+	}
+
+	switch(s_status) {
+	default:	/* Just for safety, should never happen */
+	case S_QUEUE_FULL:
+		/*
+		**	Decrease number of tags to the number of 
+		**	disconnected commands.
+		*/
+		if (!lp)
+			goto out;
+		if (bootverbose >= 1) {
+			PRINT_ADDR(cmd);
+			printk ("QUEUE FULL! %d busy, %d disconnected CCBs\n",
+				busy_cnt, disc_cnt);
+		}
+		if (disc_cnt < lp->numtags) {
+			lp->numtags	= disc_cnt > 2 ? disc_cnt : 2;
+			lp->num_good	= 0;
+			ncr_setup_tags (np, cmd->target, cmd->lun);
+		}
+		/*
+		**	Requeue the command to the start queue.
+		**	If any disconnected commands,
+		**		Clear SIGP.
+		**		Jump to reselect.
+		*/
+		cp->phys.header.savep = cp->startp;
+		cp->host_status = HS_BUSY;
+		cp->scsi_status = S_ILLEGAL;
+
+		ncr_put_start_queue(np, cp);
+		if (disc_cnt)
+			INB (nc_ctest2);		/* Clear SIGP */
+		OUTL (nc_dsp,	NCB_SCRIPT_PHYS (np, reselect));
+		return;
+	case S_TERMINATED:
+	case S_CHECK_COND:
+		/*
+		**	If we were requesting sense, give up.
+		*/
+		if (cp->auto_sense)
+			goto out;
+
+		/*
+		**	Device returned CHECK CONDITION status.
+		**	Prepare all needed data strutures for getting 
+		**	sense data.
+		**
+		**	identify message
+		*/
+		cp->scsi_smsg2[0]	= M_IDENTIFY | cmd->lun;
+		cp->phys.smsg.addr	= cpu_to_scr(CCB_PHYS (cp, scsi_smsg2));
+		cp->phys.smsg.size	= cpu_to_scr(1);
+
+		/*
+		**	sense command
+		*/
+		cp->phys.cmd.addr	= cpu_to_scr(CCB_PHYS (cp, sensecmd));
+		cp->phys.cmd.size	= cpu_to_scr(6);
+
+		/*
+		**	patch requested size into sense command
+		*/
+		cp->sensecmd[0]		= 0x03;
+		cp->sensecmd[1]		= cmd->lun << 5;
+		cp->sensecmd[4]		= sizeof(cmd->sense_buffer);
 
-	/*
-	**	if old phase not dataphase, leave here.
-	*/
+		/*
+		**	sense data
+		*/
+		cp->phys.sense.addr	=
+				cpu_to_scr(vtophys (&cmd->sense_buffer[0]));
+		cp->phys.sense.size	=
+				cpu_to_scr(sizeof(cmd->sense_buffer));
 
-	if (cmd & 0x06) {
-		PRINT_ADDR(cp->cmd);
-		printf ("phase change %x-%x %d@%08x resid=%d.\n",
-			cmd&7, sbcl&7, (unsigned)olen,
-			(unsigned)oadr, (unsigned)rest);
+		/*
+		**	requeue the command.
+		*/
+		startp = cpu_to_scr(NCB_SCRIPTH_PHYS (np, sdata_in));
 
-		OUTONB (nc_dcntl, (STD|NOCOM));
-		return;
-	};
+		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;
 
-	/*
-	**	choose the correct patch area.
-	**	if savep points to one, choose the other.
-	*/
+		cp->host_status = HS_BUSY;
+		cp->scsi_status = S_ILLEGAL;
+		cp->auto_sense	= s_status;
 
-	newcmd = cp->patch;
-	if (cp->phys.header.savep == cpu_to_scr(vtophys (newcmd))) newcmd+=4;
+		cp->start.schedule.l_paddr =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
 
-	/*
-	**	fillin the commands
-	*/
+		/*
+		**	Select without ATN for quirky devices.
+		*/
+		if (tp->quirks & QUIRK_NOMSG)
+			cp->start.schedule.l_paddr =
+			cpu_to_scr(NCB_SCRIPTH_PHYS (np, select_no_atn));
 
-	newcmd[0] = cpu_to_scr(((cmd & 0x0f) << 24) | rest);
-	newcmd[1] = cpu_to_scr(oadr + olen - rest);
-	newcmd[2] = cpu_to_scr(SCR_JUMP);
-	newcmd[3] = cpu_to_scr(nxtdsp);
+		ncr_put_start_queue(np, cp);
 
-	if (DEBUG_FLAGS & DEBUG_PHASE) {
-		PRINT_ADDR(cp->cmd);
-		printf ("newcmd[%d] %x %x %x %x.\n",
-			(int) (newcmd - cp->patch),
-			(unsigned)scr_to_cpu(newcmd[0]),
-			(unsigned)scr_to_cpu(newcmd[1]),
-			(unsigned)scr_to_cpu(newcmd[2]),
-			(unsigned)scr_to_cpu(newcmd[3]));
+		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
+		return;
 	}
-	/*
-	**	fake the return address (to the patch).
-	**	and restart script processor at dispatcher.
-	*/
-	np->profile.num_break++;
-	OUTL (nc_temp, vtophys (newcmd));
-	if ((cmd & 7) == 0)
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
-	else
-		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, checkatn));
+
+out:
+	OUTONB (nc_dcntl, (STD|NOCOM));
+	return;
 }
 
+
 /*==========================================================
 **
 **
@@ -7491,159 +7696,79 @@
 static int ncr_show_msg (u_char * msg)
 {
 	u_char i;
-	printf ("%x",*msg);
+	printk ("%x",*msg);
 	if (*msg==M_EXTENDED) {
 		for (i=1;i<8;i++) {
 			if (i-1>msg[1]) break;
-			printf ("-%x",msg[i]);
+			printk ("-%x",msg[i]);
 		};
 		return (i+1);
 	} else if ((*msg & 0xf0) == 0x20) {
-		printf ("-%x",msg[1]);
+		printk ("-%x",msg[1]);
 		return (2);
 	};
 	return (1);
 }
 
+
 void ncr_int_sir (ncb_p np)
 {
 	u_char scntl3;
 	u_char chg, ofs, per, fak, wide;
 	u_char num = INB (nc_dsps);
 	ccb_p	cp=0;
-	u_long	dsa;
-	u_char	target = INB (nc_ctest0) & 0x0f;
+	u_long	dsa    = INL (nc_dsa);
+	u_char	target = INB (nc_sdid) & 0x0f;
 	tcb_p	tp     = &np->target[target];
-	int     i;
-	if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num);
+
+	if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
 
 	switch (num) {
-	case SIR_SENSE_RESTART:
-	case SIR_STALL_RESTART:
-		break;
-	case SIR_STALL_QUEUE:	/* Ignore, just restart the script */
+	case SIR_RESEL_NO_MSG_IN:
+	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->lp[0]) { 
+			OUTL (nc_dsp, tp->lp[0]->jump_ccb[0].l_paddr);
+			return;
+		}
+	case SIR_RESEL_BAD_TARGET:	/* Will send a TARGET RESET message */
+	case SIR_RESEL_BAD_LUN:		/* Will send a TARGET RESET message */
+	case SIR_RESEL_BAD_I_T_L_Q:	/* Will send an ABORT TAG message   */
+	case SIR_RESEL_BAD_I_T_L:	/* Will send an ABORT message	    */
+		printk ("%s:%d: SIR %d, "
+			"incorrect nexus identification on reselection\n",
+			ncr_name (np), target, num);
 		goto out;
-
+	case SIR_DONE_OVERFLOW:
+		printk ("%s:%d: SIR %d, "
+			"CCB done queue overflow\n",
+			ncr_name (np), target, num);
+		goto out;
+	case SIR_BAD_STATUS:
+		cp = np->header.cp;
+		if (!cp || CCB_PHYS (cp, phys) != dsa)
+			goto out;
+		ncr_sir_to_redo(np, num, cp);
+		return;
 	default:
 		/*
 		**	lookup the ccb
 		*/
-		dsa = INL (nc_dsa);
 		cp = np->ccb;
 		while (cp && (CCB_PHYS (cp, phys) != dsa))
 			cp = cp->link_ccb;
 
-		assert (cp);
-		if (!cp)
-			goto out;
-		assert (cp == np->header.cp);
-		if (cp != np->header.cp)
+		assert (cp && cp == np->header.cp);
+
+		if (!cp || cp != np->header.cp)
 			goto out;
 	}
 
 	switch (num) {
-		u_long endp;
-	case SIR_DATA_IO_IS_OUT:
-	case SIR_DATA_IO_IS_IN:
-/*
-**	We did not guess the direction of transfer. We have to wait for 
-**	actual data direction driven by the target before setting 
-**	pointers. We must patch the global header too.
-*/
-		if (num == SIR_DATA_IO_IS_OUT) {
-			endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16;
-			cp->phys.header.goalp = cpu_to_scr(endp + 8);
-			cp->phys.header.savep =
-				cpu_to_scr(endp - cp->segments*16);
-		} else {
-			endp = NCB_SCRIPT_PHYS (np, data_in)  + MAX_SCATTER*16;
-			cp->phys.header.goalp = cpu_to_scr(endp + 8);
-			cp->phys.header.savep =
-				cpu_to_scr(endp - cp->segments*16);
-		}
-
-		cp->phys.header.lastp	= cp->phys.header.savep;
-		np->header.savep	= cp->phys.header.savep;
-		np->header.goalp	= cp->phys.header.goalp;
-		np->header.lastp	= cp->phys.header.lastp;
-
-		OUTL (nc_temp,	scr_to_cpu(np->header.savep));
-		OUTL (nc_dsp,	scr_to_cpu(np->header.savep));
-		return;
-		/* break; */
-
-/*--------------------------------------------------------------------
-**
-**	Processing of interrupted getcc selects
-**
-**--------------------------------------------------------------------
-*/
-
-	case SIR_SENSE_RESTART:
-		/*------------------------------------------
-		**	Script processor is idle.
-		**	Look for interrupted "check cond"
-		**------------------------------------------
-		*/
-
-		if (DEBUG_FLAGS & DEBUG_RESTART)
-			printf ("%s: int#%d",ncr_name (np),num);
-		cp = (ccb_p) 0;
-		for (i=0; i<MAX_TARGET; i++) {
-			if (DEBUG_FLAGS & DEBUG_RESTART) printf (" t%d", i);
-			tp = &np->target[i];
-			if (DEBUG_FLAGS & DEBUG_RESTART) printf ("+");
-			cp = tp->hold_cp;
-			if (!cp) continue;
-			if (DEBUG_FLAGS & DEBUG_RESTART) printf ("+");
-			if ((cp->host_status==HS_BUSY) &&
-				(cp->scsi_status==S_CHECK_COND))
-				break;
-			if (DEBUG_FLAGS & DEBUG_RESTART) printf ("- (remove)");
-			tp->hold_cp = cp = (ccb_p) 0;
-		};
-
-		if (cp) {
-			if (DEBUG_FLAGS & DEBUG_RESTART)
-				printf ("+ restart job ..\n");
-			OUTL (nc_dsa, CCB_PHYS (cp, phys));
-			OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, getcc));
-			return;
-		};
-
-		/*
-		**	no job, resume normal processing
-		*/
-		if (DEBUG_FLAGS & DEBUG_RESTART) printf (" -- remove trap\n");
-		np->script->start0[0] =  cpu_to_scr(SCR_INT ^ IFFALSE (0));
-		break;
-
-	case SIR_SENSE_FAILED:
-		/*-------------------------------------------
-		**	While trying to select for
-		**	getting the condition code,
-		**	a target reselected us.
-		**-------------------------------------------
-		*/
-		if (DEBUG_FLAGS & DEBUG_RESTART) {
-			PRINT_ADDR(cp->cmd);
-			printf ("in getcc reselect by t%d.\n",
-				(int)INB(nc_ssid) & 0x0f);
-		}
-
-		/*
-		**	Mark this job
-		*/
-		cp->host_status = HS_BUSY;
-		cp->scsi_status = S_CHECK_COND;
-		np->target[cp->cmd->target].hold_cp = cp;
-
-		/*
-		**	And patch code to restart it.
-		*/
-		np->script->start0[0] =  cpu_to_scr(SCR_INT);
-		break;
-
 /*-----------------------------------------------------------------------------
 **
 **	Was Sie schon immer ueber transfermode negotiation wissen wollten ...
@@ -7727,7 +7852,7 @@
 
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
 			PRINT_ADDR(cp->cmd);
-			printf ("negotiation failed sir=%x status=%x.\n",
+			printk ("negotiation failed sir=%x status=%x.\n",
 				num, cp->nego_status);
 		};
 
@@ -7750,7 +7875,8 @@
 		np->msgout[0] = M_NOOP;
 		cp->nego_status = 0;
 		OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
-		break;
+		return;
+/*		break;	*/
 
 	case SIR_NEGO_SYNC:
 		/*
@@ -7759,9 +7885,9 @@
 
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
 			PRINT_ADDR(cp->cmd);
-			printf ("sync msgin: ");
+			printk ("sync msgin: ");
 			(void) ncr_show_msg (np->msgin);
-			printf (".\n");
+			printk (".\n");
 		};
 
 		/*
@@ -7779,7 +7905,7 @@
 		*/
 
 		if (ofs)
-			tp->inqdata[7] |= INQ7_SYNC;
+			tp->inq_byte7 |= INQ7_SYNC;
 
 		/*
 		**	check values against driver limits.
@@ -7813,7 +7939,7 @@
 
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
 			PRINT_ADDR(cp->cmd);
-			printf ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
+			printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
 				per, scntl3, ofs, fak, chg);
 		}
 
@@ -7847,20 +7973,6 @@
 		};
 
 		/*
-		**	It was a request.
-		**      Check against the table of target capabilities.
-		**      If target not capable force M_REJECT and asynchronous.
-		*/
-		if (np->unit < SCSI_NCR_MAX_HOST) {
-			tp->inqdata[7] &=
-				(target_capabilities[np->unit].and_map[target]);
-			if (!(tp->inqdata[7] & INQ7_SYNC)) {
-				ofs = 0;
-				fak = 7;
-			}
-		}
-
-		/*
 		**	It was a request. Set value and
 		**      prepare an answer message
 		*/
@@ -7877,9 +7989,9 @@
 
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
 			PRINT_ADDR(cp->cmd);
-			printf ("sync msgout: ");
+			printk ("sync msgout: ");
 			(void) ncr_show_msg (np->msgout);
-			printf (".\n");
+			printk (".\n");
 		}
 
 		if (!ofs) {
@@ -7896,9 +8008,9 @@
 		*/
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
 			PRINT_ADDR(cp->cmd);
-			printf ("wide msgin: ");
+			printk ("wide msgin: ");
 			(void) ncr_show_msg (np->msgin);
-			printf (".\n");
+			printk (".\n");
 		};
 
 		/*
@@ -7914,7 +8026,7 @@
 		*/
 
 		if (wide)
-			tp->inqdata[7] |= INQ7_WIDE16;
+			tp->inq_byte7 |= INQ7_WIDE16;
 
 		/*
 		**	check values against driver limits.
@@ -7925,7 +8037,7 @@
 
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
 			PRINT_ADDR(cp->cmd);
-			printf ("wide: wide=%d chg=%d.\n", wide, chg);
+			printk ("wide: wide=%d chg=%d.\n", wide, chg);
 		}
 
 		if (INB (HS_PRT) == HS_NEGOTIATE) {
@@ -7975,9 +8087,9 @@
 
 		if (DEBUG_FLAGS & DEBUG_NEGO) {
 			PRINT_ADDR(cp->cmd);
-			printf ("wide msgout: ");
+			printk ("wide msgout: ");
 			(void) ncr_show_msg (np->msgin);
-			printf (".\n");
+			printk (".\n");
 		}
 		break;
 
@@ -7997,7 +8109,7 @@
 		*/
 
 		PRINT_ADDR(cp->cmd);
-		printf ("M_REJECT received (%x:%x).\n",
+		printk ("M_REJECT received (%x:%x).\n",
 			(unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]);
 		break;
 
@@ -8010,9 +8122,9 @@
 		*/
 
 		PRINT_ADDR(cp->cmd);
-		printf ("M_REJECT sent for ");
+		printk ("M_REJECT sent for ");
 		(void) ncr_show_msg (np->msgin);
-		printf (".\n");
+		printk (".\n");
 		break;
 
 /*--------------------------------------------------------------------
@@ -8032,9 +8144,9 @@
 		*/
 
 		PRINT_ADDR(cp->cmd);
-		printf ("M_IGN_RESIDUE received, but not yet implemented.\n");
+		printk ("M_IGN_RESIDUE received, but not yet implemented.\n");
 		break;
-
+#if 0
 	case SIR_MISSING_SAVE:
 		/*-----------------------------------------------
 		**
@@ -8045,92 +8157,13 @@
 		*/
 
 		PRINT_ADDR(cp->cmd);
-		printf ("M_DISCONNECT received, but datapointer not saved: "
+		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;
-
-#if 0   /* This stuff does not work */
-/*--------------------------------------------------------------------
-**
-**	Processing of a "S_QUEUE_FULL" status.
-**
-**	The current command has been rejected,
-**	because there are too many in the command queue.
-**	We have started too many commands for that target.
-**
-**	If possible, reinsert at head of queue.
-**	Stall queue until there are no disconnected jobs
-**	(ncr is REALLY idle). Then restart processing.
-**
-**	We should restart the current job after the controller
-**	has become idle. But this is not yet implemented.
-**
-**--------------------------------------------------------------------
-*/
-	case SIR_STALL_QUEUE:
-		/*-----------------------------------------------
-		**
-		**	Stall the start queue.
-		**
-		**-----------------------------------------------
-		*/
-		PRINT_ADDR(cp->cmd);
-		printf ("queue full.\n");
-
-		np->script->start1[0] =  cpu_to_scr(SCR_INT);
-
-		/*
-		**	Try to disable tagged transfers.
-		*/
-		ncr_setmaxtags (np, &np->target[target], 0);
-
-		/*
-		** @QUEUE@
-		**
-		**	Should update the launch field of the
-		**	current job to be able to restart it.
-		**	Then prepend it to the start queue.
-		*/
-
-		/* fall through */
-
-	case SIR_STALL_RESTART:
-		/*-----------------------------------------------
-		**
-		**	Enable selecting again,
-		**	if NO disconnected jobs.
-		**
-		**-----------------------------------------------
-		*/
-		/*
-		**	Look for a disconnected job.
-		*/
-		cp = np->ccb;
-		while (cp && cp->host_status != HS_DISCONNECT)
-			cp = cp->link_ccb;
-
-		/*
-		**	if there is one, ...
-		*/
-		if (cp) {
-			/*
-			**	wait for reselection
-			*/
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, reselect));
-			return;
-		};
-
-		/*
-		**	else remove the interrupt.
-		*/
-
-		printf ("%s: queue empty.\n", ncr_name (np));
-		np->script->start1[0] =  cpu_to_scr(SCR_INT ^ IFFALSE (0));
-		break;
-#endif   /* This stuff does not work */
+#endif
 	};
 
 out:
@@ -8146,48 +8179,65 @@
 **==========================================================
 */
 
-static	ccb_p ncr_get_ccb
-	(ncb_p np, u_long target, u_long lun)
+static	ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln)
 {
-	lcb_p lp;
+	tcb_p tp = &np->target[tn];
+	lcb_p lp = tp->lp[ln];
+	u_char tag = NO_TAG;
 	ccb_p cp = (ccb_p) 0;
 
 	/*
 	**	Lun structure available ?
 	*/
+	if (lp) {
+		XPT_QUEHEAD *qp;
+		/*
+		**	Allocate a new CCB if needed.
+		*/
+		if (xpt_que_empty(&lp->free_ccbq))
+			ncr_alloc_ccb(np, tn, ln);
 
-	lp = np->target[target].lp[lun];
-
-	if (lp && lp->opennings && (!lp->active || lp->active < lp->reqlink)) {
-
-		cp = lp->next_ccb;
-
+		/*
+		**	Tune tag mode if asked by user.
+		*/
+		if (lp->queuedepth != lp->numtags) {
+			ncr_setup_tags(np, tn, ln);
+		}
+			
 		/*
 		**	Look for free CCB
 		*/
-
-		while (cp && cp->magic) cp = cp->next_ccb;
+		qp = xpt_remque_head(&lp->free_ccbq);
+		if (qp) {
+			cp = xpt_que_entry(qp, struct ccb, link_ccbq);
+			if (cp->magic) {
+				PRINT_LUN(np, tn, ln);
+				printk ("ccb free list corrupted (@%p)\n", cp);
+				cp = 0;
+			}
+			else {
+				xpt_insque_tail(qp, &lp->wait_ccbq);
+				++lp->busyccbs;
+			}
+		}
 
 		/*
-		**	Increment active commands and decrement credit.
+		**	If a CCB is available,
+		**	Get a tag for this nexus if required.
 		*/
-
 		if (cp) {
-			++lp->active;
-			--lp->opennings;
+			if (lp->usetags)
+				tag = lp->cb_tags[lp->ia_tag];
 		}
+		else if (lp->actccbs > 0)
+			return (ccb_p) 0;
 	}
 
 	/*
 	**	if nothing available, take the default.
-	**	DANGEROUS, because this ccb is not suitable for
-	**	reselection.
-	**	If lp->actccbs > 0 wait for a suitable ccb to be free.
 	*/
-	if ((!cp) && lp && lp->actccbs > 0)
-		return ((ccb_p) 0);
-
-	if (!cp) cp = np->ccb;
+	if (!cp)
+		cp = np->ccb;
 
 	/*
 	**	Wait until available.
@@ -8204,7 +8254,40 @@
 		return ((ccb_p) 0);
 
 	cp->magic = 1;
-	return (cp);
+
+	/*
+	**	Move to next available tag if tag used.
+	*/
+	if (lp) {
+		if (tag != NO_TAG) {
+			++lp->ia_tag;
+#if SCSI_NCR_MAX_TAGS <= 32
+			if (lp->ia_tag == 32)
+#else
+			if (lp->ia_tag == 64)
+#endif
+				lp->ia_tag = 0;
+#if SCSI_NCR_MAX_TAGS <= 32
+			lp->tags_umap |= (1u << tag);
+#else
+			lp->tags_umap |= (((u_int64) 1) << tag);
+#endif
+		}
+	}
+
+	/*
+	**	Remember all informations needed to free this CCB.
+	*/
+	cp->tag	   = tag;
+	cp->target = tn;
+	cp->lun    = ln;
+
+	if (DEBUG_FLAGS & DEBUG_TAGS) {
+		PRINT_LUN(np, tn, ln);
+		printk ("ccb @%p using tag %d.\n", cp, tag);
+	}
+
+	return cp;
 }
 
 /*==========================================================
@@ -8216,32 +8299,154 @@
 **==========================================================
 */
 
-void ncr_free_ccb (ncb_p np, ccb_p cp, u_long target, u_long lun)
+static void ncr_free_ccb (ncb_p np, ccb_p cp)
 {
-	lcb_p lp;
+	tcb_p tp = &np->target[cp->target];
+	lcb_p lp = tp->lp[cp->lun];
+
+	if (DEBUG_FLAGS & DEBUG_TAGS) {
+		PRINT_LUN(np, cp->target, cp->lun);
+		printk ("ccb @%p freeing tag %d.\n", cp, cp->tag);
+	}
+
+	/*
+	**	If lun control block available,
+	**	decrement active commands and increment credit, 
+	**	free the tag if any and remove the JUMP for reselect.
+	*/
+	if (lp) {
+		if (cp->tag != NO_TAG) {
+			lp->cb_tags[lp->if_tag++] = cp->tag;
+#if SCSI_NCR_MAX_TAGS <= 32
+			if (lp->if_tag == 32)
+#else
+			if (lp->if_tag == 64)
+#endif
+				lp->if_tag = 0;
+#if SCSI_NCR_MAX_TAGS <= 32
+			lp->tags_umap &= ~(1u << cp->tag);
+#else
+			lp->tags_umap &= ~(((u_int64) 1) << cp->tag);
+#endif
+			lp->tags_smap &= lp->tags_umap;
+			lp->jump_ccb[cp->tag].l_paddr =
+				cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l_q));
+		} else {
+			lp->jump_ccb[0].l_paddr =
+				cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l));
+		}
+	}
+
+	/*
+	**	Make this CCB available.
+	*/
+
+	if (lp) {
+		if (cp != np->ccb) {
+			xpt_remque(&cp->link_ccbq);
+			xpt_insque_head(&cp->link_ccbq, &lp->free_ccbq);
+		}
+		--lp->busyccbs;
+		if (cp->queued) {
+			--lp->queuedccbs;
+		}
+	}
+	cp -> host_status = HS_IDLE;
+	cp -> magic = 0;
+	if (cp->queued) {
+		--np->queuedccbs;
+		cp->queued = 0;
+	}
+
+#if 0
+	if (cp == np->ccb)
+		wakeup ((caddr_t) cp);
+#endif
+}
+
+
+#define ncr_reg_bus_addr(r) \
+	(pcivtophys(np->paddr) + offsetof (struct ncr_reg, r))
+
+/*------------------------------------------------------------------------
+**	Initialize the fixed part of a CCB structure.
+**------------------------------------------------------------------------
+**------------------------------------------------------------------------
+*/
+static void ncr_init_ccb(ncb_p np, ccb_p cp)
+{
+	ncrcmd copy_4 = np->features & FE_PFEN ? SCR_COPY(4) : SCR_COPY_F(4);
+
+	/*
+	**	Remember virtual and bus address of this ccb.
+	*/
+	cp->p_ccb 	   = vtophys(cp);
+	cp->phys.header.cp = cp;
+
+	/*
+	**	This allows xpt_remque to work for the default ccb.
+	*/
+	xpt_que_init(&cp->link_ccbq);
+
+	/*
+	**	Initialyze the start and restart launch script.
+	**
+	**	COPY(4) @(...p_phys), @(dsa)
+	**	JUMP @(sched_point)
+	*/
+	cp->start.setup_dsa[0]	 = cpu_to_scr(copy_4);
+	cp->start.setup_dsa[1]	 = cpu_to_scr(vtophys(&cp->start.p_phys));
+	cp->start.setup_dsa[2]	 = cpu_to_scr(ncr_reg_bus_addr(nc_dsa));
+	cp->start.schedule.l_cmd = cpu_to_scr(SCR_JUMP);
+	cp->start.p_phys	 = vtophys(&cp->phys);
+
+	bcopy(&cp->start, &cp->restart, sizeof(cp->restart));
+
+	cp->start.schedule.l_paddr   = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
+	cp->restart.schedule.l_paddr = cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
+}
+
+
+/*------------------------------------------------------------------------
+**	Allocate a CCB and initialize its fixed part.
+**------------------------------------------------------------------------
+**------------------------------------------------------------------------
+*/
+static void ncr_alloc_ccb(ncb_p np, u_char tn, u_char ln)
+{
+	tcb_p tp = &np->target[tn];
+	lcb_p lp = tp->lp[ln];
+	ccb_p cp = 0;
+
+	/*
+	**	Allocate memory for this CCB.
+	*/
+	cp = m_alloc(sizeof(struct ccb), 5);
+	if (!cp)
+		return;
+
+	if (DEBUG_FLAGS & DEBUG_ALLOC) {
+		PRINT_LUN(np, tn, ln);
+		printk ("new ccb @%p.\n", cp);
+	}
 
 	/*
-	**    sanity
+	**	Count it and initialyze it.
 	*/
-
-	assert (cp != NULL);
+	lp->actccbs++;
+	np->actccbs++;
+	bzero (cp, sizeof (*cp));
+	ncr_init_ccb(np, cp);
 
 	/*
-	**	Decrement active commands and increment credit.
+	**	Chain into wakeup list and free ccb queue and take it 
+	**	into account for tagged commands.
 	*/
+	cp->link_ccb      = np->ccb->link_ccb;
+	np->ccb->link_ccb = cp;
 
-	lp = np->target[target].lp[lun];
-	if (lp) {
-			--lp->active;
-			++lp->opennings;
-	}
-
-	cp -> host_status = HS_IDLE;
-	cp -> magic = 0;
-#if 0
-	if (cp == np->ccb)
-		wakeup ((caddr_t) cp);
-#endif
+	xpt_insque_head(&cp->link_ccbq, &lp->free_ccbq);
+	ncr_setup_tags (np, tn, ln);
 }
 
 /*==========================================================
@@ -8253,215 +8458,279 @@
 **==========================================================
 */
 
-static	void ncr_alloc_ccb (ncb_p np, u_long target, u_long lun)
-{
-	tcb_p tp;
-	lcb_p lp;
-	ccb_p cp;
-
-	assert (np != NULL);
-
-	if (target>=MAX_TARGET) return;
-	if (lun   >=MAX_LUN   ) return;
-
-	tp=&np->target[target];
 
-	if (!tp->jump_tcb.l_cmd) {
-		/*
-		**	initialize it.
-		*/
-		tp->jump_tcb.l_cmd   =
-			cpu_to_scr((SCR_JUMP^IFFALSE (DATA (0x80 + target))));
-		tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr;
-
-		tp->getscr[0] =	(np->features & FE_PFEN) ?
-			cpu_to_scr(SCR_COPY(1)):cpu_to_scr(SCR_COPY_F(1));
-		tp->getscr[1] = cpu_to_scr(vtophys (&tp->sval));
-		tp->getscr[2] =
-		cpu_to_scr(pcivtophys(np->paddr) + offsetof (struct ncr_reg, nc_sxfer));
+/*------------------------------------------------------------------------
+**	Target control block initialisation.
+**------------------------------------------------------------------------
+**	This data structure is fully initialized after a SCSI command 
+**	has been successfully completed for this target.
+**	It contains a SCRIPT that is called on target reselection.
+**------------------------------------------------------------------------
+*/
+static void ncr_init_tcb (ncb_p np, u_char tn)
+{
+	tcb_p tp = &np->target[tn];
+	ncrcmd copy_1 = np->features & FE_PFEN ? SCR_COPY(1) : SCR_COPY_F(1);
+	int th = tn & 3;
+	int i;
 
-		tp->getscr[3] =	(np->features & FE_PFEN) ?
-			cpu_to_scr(SCR_COPY(1)):cpu_to_scr(SCR_COPY_F(1));
-		tp->getscr[4] = cpu_to_scr(vtophys (&tp->wval));
-		tp->getscr[5] =
-		cpu_to_scr(pcivtophys(np->paddr) + offsetof (struct ncr_reg, nc_scntl3));
+	/*
+	**	Jump to next tcb if SFBR does not match this target.
+	**	JUMP  IF (SFBR != #target#), @(next tcb)
+	*/
+	tp->jump_tcb.l_cmd   =
+		cpu_to_scr((SCR_JUMP ^ IFFALSE (DATA (0x80 + tn))));
+	tp->jump_tcb.l_paddr = np->jump_tcb[th].l_paddr;
 
-		assert (( (offsetof(struct ncr_reg, nc_sxfer) ^
-			offsetof(struct tcb    , sval    )) &3) == 0);
-		assert (( (offsetof(struct ncr_reg, nc_scntl3) ^
-			offsetof(struct tcb    , wval    )) &3) == 0);
+	/*
+	**	Load the synchronous transfer register.
+	**	COPY @(tp->sval), @(sxfer)
+	*/
+	tp->getscr[0] =	cpu_to_scr(copy_1);
+	tp->getscr[1] = cpu_to_scr(vtophys (&tp->sval));
+	tp->getscr[2] = cpu_to_scr(ncr_reg_bus_addr(nc_sxfer));
+  
+	/*
+	**	Load the timing register.
+	**	COPY @(tp->wval), @(scntl3)
+	*/
+	tp->getscr[3] =	cpu_to_scr(copy_1);
+	tp->getscr[4] = cpu_to_scr(vtophys (&tp->wval));
+	tp->getscr[5] = cpu_to_scr(ncr_reg_bus_addr(nc_scntl3));
 
-		tp->call_lun.l_cmd   = cpu_to_scr(SCR_CALL);
-		tp->call_lun.l_paddr =
-			cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_lun));
+	/*
+	**	Get the IDENTIFY message and the lun.
+	**	CALL @script(resel_lun)
+	*/
+	tp->call_lun.l_cmd   = cpu_to_scr(SCR_CALL);
+	tp->call_lun.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_lun));
 
-		tp->jump_lcb.l_cmd   = cpu_to_scr(SCR_JUMP);
-		tp->jump_lcb.l_paddr = cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
-		np->jump_tcb.l_paddr = cpu_to_scr(vtophys (&tp->jump_tcb));
+	/*
+	**	Look for the lun control block of this nexus.
+	**	For i = 0 to 3
+	**		JUMP ^ IFTRUE (MASK (i, 3)), @(next_lcb)
+	*/
+	for (i = 0 ; i < 4 ; i++) {
+		tp->jump_lcb[i].l_cmd   =
+				cpu_to_scr((SCR_JUMP ^ IFTRUE (MASK (i, 3))));
+		tp->jump_lcb[i].l_paddr =
+				cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_identify));
 	}
 
 	/*
-	**	Logic unit control block
+	**	Link this target control block to the JUMP chain.
 	*/
-	lp = tp->lp[lun];
-	if (!lp) {
-		/*
-		**	Allocate a lcb
-		*/
-		lp = (lcb_p) m_alloc (sizeof (struct lcb), LCB_ALIGN_SHIFT);
-		if (!lp) return;
+	np->jump_tcb[th].l_paddr = cpu_to_scr(vtophys (&tp->jump_tcb));
 
-		if (DEBUG_FLAGS & DEBUG_ALLOC) {
-			PRINT_LUN(np, target, lun);
-			printf ("new lcb @%p.\n", lp);
-		}
-
-		/*
-		**	Initialize it
-		*/
-		bzero (lp, sizeof (*lp));
-		lp->jump_lcb.l_cmd   =
-			cpu_to_scr(SCR_JUMP ^ IFFALSE (DATA (lun)));
-		lp->jump_lcb.l_paddr = tp->jump_lcb.l_paddr;
-
-		lp->call_tag.l_cmd   = cpu_to_scr(SCR_CALL);
-		lp->call_tag.l_paddr =
-			cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_tag));
-
-		lp->jump_ccb.l_cmd   = cpu_to_scr(SCR_JUMP);
-		lp->jump_ccb.l_paddr =
-			cpu_to_scr(NCB_SCRIPTH_PHYS (np, aborttag));
-
-		lp->actlink = 1;
+	/*
+	**	These assert's should be moved at driver initialisations.
+	*/
+	assert (( (offsetof(struct ncr_reg, nc_sxfer) ^
+		offsetof(struct tcb    , sval    )) &3) == 0);
+	assert (( (offsetof(struct ncr_reg, nc_scntl3) ^
+		offsetof(struct tcb    , wval    )) &3) == 0);
+}
 
-		lp->active  = 1;
 
-		/*
-		**   Chain into LUN list
-		*/
-		tp->jump_lcb.l_paddr = cpu_to_scr(vtophys (&lp->jump_lcb));
-		tp->lp[lun] = lp;
+/*------------------------------------------------------------------------
+**	Reselection JUMP table initialisation.
+**------------------------------------------------------------------------
+**	The SCRIPTS processor jumps on reselection to the entry 
+**	corresponding to the CCB using the tag as offset.
+**------------------------------------------------------------------------
+*/
+static void ncr_setup_jump_ccb(ncb_p np, lcb_p lp)
+{
+	int i;
 
-		ncr_setmaxtags (np, tp, driver_setup.default_tags);
+	lp->p_jump_ccb = vtophys(lp->jump_ccb);
+	for (i = 0 ; i < lp->maxnxs ; i++) {
+#if SCSI_NCR_MAX_TAGS <= 32
+		lp->jump_ccb[i].l_cmd   = cpu_to_scr(SCR_JUMP);
+#endif
+		lp->jump_ccb[i].l_paddr =
+			cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q));
+		lp->cb_tags[i] = i;
 	}
+}
 
-	/*
-	**	Allocate ccbs up to lp->reqccbs.
-	*/
+/*------------------------------------------------------------------------
+**	Lun control block allocation and initialization.
+**------------------------------------------------------------------------
+**	This data structure is allocated and initialized after a SCSI 
+**	command has been successfully completed for this target/lun.
+**------------------------------------------------------------------------
+*/
+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];
+	ncrcmd copy_4 = np->features & FE_PFEN ? SCR_COPY(4) : SCR_COPY_F(4);
+	int lh = ln & 3;
 
 	/*
-	**	Limit possible number of ccbs.
-	**
-	**	If tagged command queueing is enabled,
-	**	can use more than one ccb.
+	**	Already done, return.
 	*/
-	if (np->actccbs >= MAX_START-2) return;
-	if (lp->actccbs && (lp->actccbs >= lp->reqccbs))
-		return;
+	if (lp)
+		return lp;
 
 	/*
-	**	Allocate a ccb
+	**	Allocate the lcb.
 	*/
-	cp = (ccb_p) m_alloc (sizeof (struct ccb), CCB_ALIGN_SHIFT);
-	if (!cp)
-		return;
+	lp = m_alloc(sizeof(struct lcb), 3);
+	if (!lp)
+		goto fail;
+	bzero(lp, sizeof(*lp));
+	tp->lp[ln] = lp;
 
 	if (DEBUG_FLAGS & DEBUG_ALLOC) {
-		PRINT_LUN(np, target, lun);
-		printf ("new ccb @%p.\n", cp);
+		PRINT_LUN(np, tn, ln);
+		printk ("new lcb @%p.\n", lp);
 	}
 
 	/*
-	**	Count it
+	**	Initialize the target control block if not yet.
 	*/
-	lp->actccbs++;
-	np->actccbs++;
+	if (!tp->jump_tcb.l_cmd)
+		ncr_init_tcb(np, tn);
 
 	/*
-	**	Initialize it
+	**	Initialize the CCB queue headers.
 	*/
-	bzero (cp, sizeof (*cp));
+	xpt_que_init(&lp->free_ccbq);
+	xpt_que_init(&lp->busy_ccbq);
+	xpt_que_init(&lp->wait_ccbq);
+	xpt_que_init(&lp->skip_ccbq);
 
 	/*
-	**	Fill in physical addresses
+	**	Set max CCBs to 1 and use the default jump table 
+	**	by default.
 	*/
-
-	cp->p_ccb	     = vtophys (cp);
+	lp->maxnxs = 1;
+	lp->jump_ccb = &lp->jump_ccb_0;
+	ncr_setup_jump_ccb(np, lp);
 
 	/*
-	**	Chain into reselect list
+	**	Initilialyze the reselect script:
+	**
+	**	Jump to next lcb if SFBR does not match this lun.
+	**	Load TEMP with the CCB direct jump table bus address.
+	**	Get the SIMPLE TAG message and the tag.
+	**
+	**	JUMP  IF (SFBR != #lun#), @(next lcb)
+	**	COPY @(lp->p_jump_ccb),	  @(temp)
+	**	JUMP @script(resel_notag)
 	*/
-	cp->jump_ccb.l_cmd   = cpu_to_scr(SCR_JUMP);
-	cp->jump_ccb.l_paddr = lp->jump_ccb.l_paddr;
-	lp->jump_ccb.l_paddr = cpu_to_scr(CCB_PHYS (cp, jump_ccb));
-	cp->call_tmp.l_cmd   = cpu_to_scr(SCR_CALL);
-	cp->call_tmp.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_tmp));
+	lp->jump_lcb.l_cmd   =
+		cpu_to_scr((SCR_JUMP ^ IFFALSE (MASK (0x80+ln, 0xff))));
+	lp->jump_lcb.l_paddr = tp->jump_lcb[lh].l_paddr;
+
+	lp->load_jump_ccb[0] = cpu_to_scr(copy_4);
+	lp->load_jump_ccb[1] = cpu_to_scr(vtophys (&lp->p_jump_ccb));
+	lp->load_jump_ccb[2] = cpu_to_scr(ncr_reg_bus_addr(nc_temp));
+
+	lp->jump_tag.l_cmd   = cpu_to_scr(SCR_JUMP);
+	lp->jump_tag.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_notag));
 
 	/*
-	**	Chain into wakeup list
+	**	Link this lun control block to the JUMP chain.
 	*/
-	cp->link_ccb      = np->ccb->link_ccb;
-	np->ccb->link_ccb = cp;
+	tp->jump_lcb[lh].l_paddr = cpu_to_scr(vtophys (&lp->jump_lcb));
 
 	/*
-	**	Chain into CCB list
+	**	Initialize command queuing control.
 	*/
-	cp->next_ccb	= lp->next_ccb;
-	lp->next_ccb	= cp;
+	lp->busyccbs	= 1;
+	lp->queuedccbs	= 1;
+	lp->queuedepth	= 1;
+fail:
+	return lp;
 }
 
-/*==========================================================
-**
-**
-**	Announce the number of ccbs/tags to the scsi driver.
-**
-**
-**==========================================================
-*/
 
-static void ncr_opennings (ncb_p np, lcb_p lp, Scsi_Cmnd * cmd)
+/*------------------------------------------------------------------------
+**	Lun control block setup on INQUIRY data received.
+**------------------------------------------------------------------------
+**	We only support WIDE, SYNC for targets and CMDQ for logical units.
+**	This setup is done on each INQUIRY since we are expecting user 
+**	will play with CHANGE DEFINITION commands. :-)
+**------------------------------------------------------------------------
+*/
+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];
+	u_char inq_byte7;
+
 	/*
-	**	want to reduce the number ...
+	**	If no lcb, try to allocate it.
 	*/
-	if (lp->actlink > lp->reqlink) {
+	if (!lp && !(lp = ncr_alloc_lcb(np, tn, ln)))
+		goto fail;
 
-		/*
-		**	Try to  reduce the count.
-		**	We assume to run at splbio ..
-		*/
-		u_char diff = lp->actlink - lp->reqlink;
-
-		if (!diff) return;
+	/*
+	**	Get device quirks from a speciality table.
+	*/
+	tp->quirks = ncr_lookup (inq_data);
+	if (tp->quirks && bootverbose) {
+		PRINT_LUN(np, tn, ln);
+		printk ("quirks=%x.\n", tp->quirks);
+	}
 
-		if (diff > lp->opennings)
-			diff = lp->opennings;
+	/*
+	**	Evaluate trustable target/unit capabilities.
+	**	We only believe device version >= SCSI-2 that 
+	**	use appropriate response data format.
+	*/
+	inq_byte7 = 0;
+	if ((inq_data[2] & 0x7) >= 2 && (inq_data[3] & 0x7) >= 2)
+		inq_byte7 = inq_data[7];
 
-		lp->opennings	-= diff;
+	/*
+	**	If user is wanting SYNC, force this feature.
+	*/
+	if (driver_setup.force_sync_nego)
+		inq_byte7 |= INQ7_SYNC;
 
-		lp->actlink	-= diff;
-		if (DEBUG_FLAGS & DEBUG_TAGS)
-			printf ("%s: actlink: diff=%d, new=%d, req=%d\n",
-				ncr_name(np), diff, lp->actlink, lp->reqlink);
-		return;
-	};
+	/*
+	**	Prepare negotiation if SIP capabilities have changed.
+	*/
+	tp->inq_done = 1;
+	if ((inq_byte7 ^ tp->inq_byte7) & (INQ7_SYNC | INQ7_WIDE16)) {
+		tp->inq_byte7 = inq_byte7;
+		ncr_negotiate(np, tp);
+	}
 
 	/*
-	**	want to increase the number ?
+	**	If unit supports tagged commands, allocate the 
+	**	CCB JUMP table if not yet.
 	*/
-	if (lp->reqlink > lp->actlink) {
-		u_char diff = lp->reqlink - lp->actlink;
+	if ((inq_byte7 & INQ7_QUEUE) && lp->maxnxs < 2) {
+		struct nlink *jumps;
+		jumps = m_alloc(256, 8);
+		if (!jumps)
+			goto fail;
+#if SCSI_NCR_MAX_TAGS <= 32
+		lp->maxnxs   = 32;
+#else
+		lp->maxnxs   = 64;
+#endif
+		lp->jump_ccb = jumps;
+		ncr_setup_jump_ccb(np, lp);
+		lp->tags_stime	= jiffies;
+	}
 
-		lp->opennings	+= diff;
+	/*
+	**	Adjust tagged queueing status if needed.
+	*/
+	if ((inq_byte7 ^ lp->inq_byte7) & INQ7_QUEUE) {
+		lp->inq_byte7 = inq_byte7;
+		lp->numtags   = tp->usrtags;
+		ncr_setup_tags (np, tn, ln);
+	}
 
-		lp->actlink	+= diff;
-#if 0
-		wakeup ((caddr_t) xp->sc_link);
-#endif
-		if (DEBUG_FLAGS & DEBUG_TAGS)
-			printf ("%s: actlink: diff=%d, new=%d, req=%d\n",
-				ncr_name(np), diff, lp->actlink, lp->reqlink);
-	};
+fail:
+	return lp;
 }
 
 /*==========================================================
@@ -8499,9 +8768,6 @@
 	int segment	= 0;
 	int use_sg	= (int) cmd->use_sg;
 
-#if 0
-	bzero (cp->phys.data, sizeof (cp->phys.data));
-#endif
 	data		= cp->phys.data;
 	cp->data_len	= 0;
 
@@ -8550,7 +8816,7 @@
 static int ncr_regtest (struct ncb* np)
 )
 {
-	register volatile u_long data;
+	register volatile u_int32 data;
 	/*
 	**	ncr registers may NOT be cached.
 	**	write 0xffffffff to a read only register area,
@@ -8564,7 +8830,7 @@
 #else
 	if ((data & 0xe2f0fffd) != 0x02000080) {
 #endif
-		printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n",
+		printk ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n",
 			(unsigned) data);
 		return (0x10);
 	};
@@ -8576,8 +8842,8 @@
 static int ncr_snooptest (struct ncb* np)
 )
 {
-	u_long	ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc, err=0;
-	int	i;
+	u_int32	ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc;
+	int	i, err=0;
 #ifndef NCR_IOMAPPED
 	if (np->reg) {
             err |= ncr_regtest (np);
@@ -8619,22 +8885,22 @@
 	**	Reset ncr chip
 	*/
 	OUTB (nc_istat,  SRST);
-	DELAY (1000);
+	UDELAY (100);
 	OUTB (nc_istat,  0   );
 	/*
 	**	check for timeout
 	*/
 	if (i>=NCR_SNOOP_TIMEOUT) {
-		printf ("CACHE TEST FAILED: timeout.\n");
+		printk ("CACHE TEST FAILED: timeout.\n");
 		return (0x20);
 	};
 	/*
 	**	Check termination position.
 	*/
 	if (pc != NCB_SCRIPTH_PHYS (np, snoopend)+8) {
-		printf ("CACHE TEST FAILED: script execution failed.\n");
-		printf ("start=%08lx, pc=%08lx, end=%08lx\n", 
-			(u_long) NCB_SCRIPTH_PHYS (np, snooptest), pc,
+		printk ("CACHE TEST FAILED: script execution failed.\n");
+		printk ("start=%08lx, pc=%08lx, end=%08lx\n", 
+			(u_long) NCB_SCRIPTH_PHYS (np, snooptest), (u_long) pc,
 			(u_long) NCB_SCRIPTH_PHYS (np, snoopend) +8);
 		return (0x40);
 	};
@@ -8642,17 +8908,17 @@
 	**	Show results.
 	*/
 	if (host_wr != ncr_rd) {
-		printf ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n",
+		printk ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n",
 			(int) host_wr, (int) ncr_rd);
 		err |= 1;
 	};
 	if (host_rd != ncr_wr) {
-		printf ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n",
+		printk ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n",
 			(int) ncr_wr, (int) host_rd);
 		err |= 2;
 	};
 	if (ncr_bk != ncr_wr) {
-		printf ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n",
+		printk ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n",
 			(int) ncr_wr, (int) ncr_bk);
 		err |= 4;
 	};
@@ -8680,7 +8946,7 @@
 #define PROFILE  cp->phys.header.stamp
 static	void ncb_profile (ncb_p np, ccb_p cp)
 {
-	long co, st, en, di, se, post, work, disc;
+	long co, st, en, di, re, post, work, disc;
 	u_int diff;
 
 	PROFILE.end = jiffies;
@@ -8693,14 +8959,14 @@
 
 	en = ncr_delta (PROFILE.start,PROFILE.end),
 	di = ncr_delta (PROFILE.start,PROFILE.disconnect),
-	se = ncr_delta (PROFILE.start,PROFILE.select);
+	re = ncr_delta (PROFILE.start,PROFILE.reselect);
 	post = en - st;
 
 	/*
 	**	@PROFILE@  Disconnect time invalid if multiple disconnects
 	*/
 
-	if (di>=0) disc = se-di; else  disc = 0;
+	if (di>=0) disc = re - di; else  disc = 0;
 
 	work = (st - co) - disc;
 
@@ -8746,13 +9012,13 @@
 
 static struct table_entry device_tab[] =
 {
-#ifdef NCR_GETCC_WITHMSG
+#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},
-#endif
 	{"", "", "", 0} /* catch all: must be last entry. */
 };
 
@@ -8816,17 +9082,17 @@
 	}
 
 	if (bootverbose >= 2)
-		printf ("%s: enabling clock multiplier\n", ncr_name(np));
+		printk ("%s: enabling clock multiplier\n", ncr_name(np));
 
 	OUTB(nc_stest1, DBLEN);	   /* Enable clock multiplier		  */
 	if (np->multiplier > 2) {  /* Poll bit 5 of stest4 for quadrupler */
 		int i = 20;
 		while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
-			DELAY(20);
+			UDELAY (20);
 		if (!i)
-			printf("%s: the chip cannot lock the frequency\n", ncr_name(np));
+			printk("%s: the chip cannot lock the frequency\n", ncr_name(np));
 	} else			/* Wait 20 micro-seconds for doubler	*/
-		DELAY(20);
+		UDELAY (20);
 	OUTB(nc_stest3, HSC);		/* Halt the scsi clock		*/
 	OUTB(nc_scntl3,	scntl3);
 	OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier	*/
@@ -8867,7 +9133,7 @@
 	OUTB (nc_stime1, 0);	/* disable general purpose timer */
 	OUTB (nc_stime1, gen);	/* set to nominal delay of 1<<gen * 125us */
 	while (!(INW(nc_sist) & GEN) && ms++ < 100000)
-		DELAY(1000);	/* count ms */
+		UDELAY (1000);	/* count ms */
 	OUTB (nc_stime1, 0);	/* disable general purpose timer */
  	/*
  	 * set prescaler to divide by whatever 0 means
@@ -8877,7 +9143,7 @@
  	OUTB (nc_scntl3, 0);
 
 	if (bootverbose >= 2)
-		printf ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms);
+		printk ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms);
   	/*
  	 * adjust for prescaler, and convert into KHz 
   	 */
@@ -8903,7 +9169,7 @@
 	*/
 	if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {
 		if (bootverbose >= 2)
-			printf ("%s: clock multiplier found\n", ncr_name(np));
+			printk ("%s: clock multiplier found\n", ncr_name(np));
 		np->multiplier = mult;
 	}
 
@@ -8915,14 +9181,14 @@
 	if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
 		unsigned f2;
 
-		OUTB(nc_istat, SRST); DELAY(5); OUTB(nc_istat, 0);
+		OUTB(nc_istat, SRST); UDELAY (5); OUTB(nc_istat, 0);
 
 		(void) ncrgetfreq (np, 11);	/* throw away first result */
 		f1 = ncrgetfreq (np, 11);
 		f2 = ncrgetfreq (np, 11);
 
 		if (bootverbose)
-			printf ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2);
+			printk ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2);
 
 		if (f1 > f2) f1 = f2;		/* trust lower result	*/
 
@@ -8932,7 +9198,7 @@
 
 		if (f1 < 80000 && mult > 1) {
 			if (bootverbose >= 2)
-				printf ("%s: clock multiplier assumed\n", ncr_name(np));
+				printk ("%s: clock multiplier assumed\n", ncr_name(np));
 			np->multiplier	= mult;
 		}
 	} else {
@@ -8971,6 +9237,12 @@
 ** ---------------------------------------------------------------------
 */
 
+#ifdef MODULE
+#define	ARG_SEP	' '
+#else
+#define	ARG_SEP	','
+#endif
+
 __initfunc(
 void ncr53c8xx_setup(char *str, int *ints)
 )
@@ -8983,33 +9255,33 @@
 	int c;
 
 	while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+		char *pe;
+
 		val = 0;
 		pv = pc;
 		c = *++pv;
+
 		if	(c == 'n')
 			val = 0;
 		else if	(c == 'y')
 			val = 1;
 		else {
 			base = 0;
-#if 0
-			if	(c == '0') {
-				c = *pv++;
-				base = 8;
-			}
-			if	(c == 'x') {
-				++pv;
-				base = 16;
+			val = (int) simple_strtoul(pv, &pe, base);
+		}
+		if	(!strncmp(cur, "tags:", 5)) {
+			int i;
+			driver_setup.default_tags = val;
+			if (pe && *pe == '/') {
+				i = 0;
+				while (*pe && *pe != ARG_SEP && 
+					i < sizeof(driver_setup.tag_ctrl)-1) {
+					driver_setup.tag_ctrl[i++] = *pe++;
+				}
+				driver_setup.tag_ctrl[i] = '\0';
 			}
-			else if (c >= '0' && c <= '9')
-				base = 10;
-			else
-				break;
-#endif
-			val = (int) simple_strtoul(pv, NULL, base);
 		}
-
-		if	(!strncmp(cur, "mpar:", 5))
+		else if	(!strncmp(cur, "mpar:", 5))
 			driver_setup.master_parity	= val;
 		else if	(!strncmp(cur, "spar:", 5))
 			driver_setup.scsi_parity	= val;
@@ -9023,11 +9295,6 @@
 			driver_setup.force_sync_nego	= val;
 		else if	(!strncmp(cur, "revprob:", 8))
 			driver_setup.reverse_probe	= val;
-		else if	(!strncmp(cur, "tags:", 5)) {
-			if (val > SCSI_NCR_MAX_TAGS)
-				val = SCSI_NCR_MAX_TAGS;
-			driver_setup.default_tags	= val;
-			}
 		else if	(!strncmp(cur, "sync:", 5))
 			driver_setup.default_sync	= val;
 		else if	(!strncmp(cur, "verb:", 5))
@@ -9058,13 +9325,9 @@
 		else if	(!strncmp(cur, "safe:", 5) && val)
 			memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup));
 		else
-			printf("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
+			printk("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
 
-#ifdef MODULE
-		if ((cur = strchr(cur, ' ')) != NULL)
-#else
-		if ((cur = strchr(cur, ',')) != NULL)
-#endif
+		if ((cur = strchr(cur, ARG_SEP)) != NULL)
 			++cur;
 	}
 #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
@@ -9093,24 +9356,31 @@
 )
 {
 #define YesNo(y)	y ? 'y' : 'n'
-	printk("ncr53c8xx: setup=disc:%c,specf:%d,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
-			YesNo(driver_setup.disconnection),
-			driver_setup.special_features,
-			YesNo(driver_setup.ultra_scsi),
-			driver_setup.default_tags,
-			driver_setup.default_sync,
-			driver_setup.burst_max,
-			YesNo(driver_setup.max_wide),
-			driver_setup.diff_support);
-	printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n",
-			YesNo(driver_setup.master_parity),
-			YesNo(driver_setup.scsi_parity),
-			YesNo(driver_setup.force_sync_nego),
-			driver_setup.verbose,
-			driver_setup.debug,
-			YesNo(driver_setup.led_pin),
-			driver_setup.settle_delay,
-			driver_setup.irqm);
+	printk ("ncr53c8xx: setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d,"
+		"burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n",
+		YesNo(driver_setup.disconnection),
+		driver_setup.special_features,
+		driver_setup.ultra_scsi,
+		driver_setup.default_tags,
+		driver_setup.default_sync,
+		driver_setup.burst_max,
+		YesNo(driver_setup.max_wide),
+		driver_setup.diff_support,
+		YesNo(driver_setup.reverse_probe),
+		driver_setup.bus_check);
+
+	printk ("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,"
+		"led:%c,settle:%d,irqm:%d,nvram:0x%x,pcifix:0x%x\n",
+		YesNo(driver_setup.master_parity),
+		YesNo(driver_setup.scsi_parity),
+		YesNo(driver_setup.force_sync_nego),
+		driver_setup.verbose,
+		driver_setup.debug,
+		YesNo(driver_setup.led_pin),
+		driver_setup.settle_delay,
+		driver_setup.irqm,
+		driver_setup.use_nvram,
+		driver_setup.pci_fix_up);
 #undef YesNo
 }
 
@@ -9145,13 +9415,13 @@
 			if (nvram_index == -1)
 				nvram_index = i;
 #ifdef SCSI_NCR_DEBUG_NVRAM
-			printf("ncr53c8xx: NVRAM: Symbios format Boot Block, 53c%s, PCI bus %d, device %d, function %d\n",
+			printk("ncr53c8xx: NVRAM: Symbios format Boot Block, 53c%s, PCI bus %d, device %d, function %d\n",
 				devp->chip.name, devp->slot.bus, 
 				(int) (devp->slot.device_fn & 0xf8) >> 3, 
 				(int) devp->slot.device_fn & 7);
 			for (j = 0 ; j < 4 ; j++) {
 				Symbios_host *h = &nvram->data.Symbios.host[j];
-			printf("ncr53c8xx: BOOT[%d] device_id=%04x vendor_id=%04x device_fn=%02x io_port=%04x %s\n",
+			printk("ncr53c8xx: BOOT[%d] device_id=%04x vendor_id=%04x device_fn=%02x io_port=%04x %s\n",
 				j,		h->device_id,	h->vendor_id,
 				h->device_fn,	h->io_port,
 				(h->flags & SYMBIOS_INIT_SCAN_AT_BOOT) ? "SCAN AT BOOT" : "");
@@ -9159,7 +9429,7 @@
 		}
 		else if (nvram->type == SCSI_NCR_TEKRAM_NVRAM) {
 			/* display Tekram nvram data */
-			printf("ncr53c8xx: NVRAM: Tekram format data, 53c%s, PCI bus %d, device %d, function %d\n",
+			printk("ncr53c8xx: NVRAM: Tekram format data, 53c%s, PCI bus %d, device %d, function %d\n",
 				devp->chip.name, devp->slot.bus, 
 				(int) (devp->slot.device_fn & 0xf8) >> 3, 
 				(int) devp->slot.device_fn & 7);
@@ -9226,18 +9496,14 @@
 #ifdef SCSI_NCR_NVRAM_SUPPORT
 	int nvram_index = 0;
 #endif
-	if (initverbose >= 2)
-		ncr_print_driver_setup();
 
 #ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 	ncr_debug = driver_setup.debug;
 #endif
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
      tpnt->proc_dir = &proc_scsi_ncr53c8xx;
-# ifdef SCSI_NCR_PROC_INFO_SUPPORT
+#ifdef SCSI_NCR_PROC_INFO_SUPPORT
      tpnt->proc_info = ncr53c8xx_proc_info;
-# endif
 #endif
 
 #if	defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
@@ -9245,6 +9511,9 @@
 	ncr53c8xx_setup(ncr53c8xx, (int *) 0);
 #endif
 
+	if (initverbose >= 2)
+		ncr_print_driver_setup();
+
 	/* 
 	** Detect all 53c8xx hosts and then attach them.
 	**
@@ -9256,7 +9525,11 @@
 	** the order they are detected.
 	*/
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,92)
 	if (!pci_present())
+#else
+	if (!pcibios_present())
+#endif
 		return 0;
 
 	chips	= sizeof(ncr_chip_ids)	/ sizeof(ncr_chip_ids[0]);
@@ -9304,7 +9577,7 @@
 				}
 			}
 #endif
-			printf(KERN_INFO "ncr53c8xx: 53c%s detected %s\n",
+			printk(KERN_INFO "ncr53c8xx: 53c%s detected %s\n",
 				device[count].chip.name, msg);
 			++count;
 		}
@@ -9320,7 +9593,7 @@
 	for (i= 0; i < count; i++) {
 		if (!device[i].attach_done && 
 		    !ncr_attach (tpnt, attach_count, &device[i])) {
- 			attach_count++;
+			attach_count++;
 		}
 	}
 
@@ -9341,16 +9614,13 @@
 	ushort vendor_id, device_id, command;
 	uchar cache_line_size, latency_timer;
 	uchar revision;
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,85)
+#if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92)
 	struct pci_dev *pdev;
 	ulong base, base_2, io_port; 
 	uint irq;
-#elif LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) 
-	uchar irq;
-	uint base, base_2, io_port; 
 #else
 	uchar irq;
-	ulong base, base_2, io_port; 
+	uint base, base_2, io_port; 
 #endif
 	int i;
 
@@ -9374,7 +9644,7 @@
 					PCI_DEVICE_ID, &device_id);
 	(void) pcibios_read_config_word(bus, device_fn,
 					PCI_COMMAND, &command);
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,85)
+#if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92)
 	pdev = pci_find_slot(bus, device_fn);
 	io_port = pdev->base_address[0];
 	base = pdev->base_address[1];
@@ -9417,6 +9687,10 @@
 	}
 
 #ifdef __powerpc__
+	/*
+	 *	Several fix-up for power/pc.
+	 *	Should not be performed by the driver.
+	 */
 	if (!(command & PCI_COMMAND_MASTER)) {
 		printk("ncr53c8xx: attempting to force PCI_COMMAND_MASTER...");
 		command |= PCI_COMMAND_MASTER;
@@ -9470,7 +9744,8 @@
 			pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_2, base_2);
 		}
 	}
-#endif
+#endif	/* __powerpc__ */
+
 #ifdef __sparc__
 	/*
 	 *	Severall fix-ups for sparc.
@@ -9517,7 +9792,7 @@
 		pcibios_read_config_byte(bus, device_fn,
 					 PCI_LATENCY_TIMER, &latency_timer);
 	}
-#endif
+#endif	/* __sparc__ */
 
 	/*
 	 * Check availability of IO space, memory space and master capability.
@@ -9603,6 +9878,7 @@
 		switch(boot_cpu_data.x86) {
 #endif
 		case 4:	cache_line_size = 4; break;
+		case 6:
 		case 5:	cache_line_size = 8; break;
 		}
 		if (cache_line_size)
@@ -9738,35 +10014,106 @@
 	return 0;     
 }
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0)
 /*
 **   Linux select queue depths function
 */
+
+#define DEF_DEPTH	(driver_setup.default_tags)
+#define ALL_TARGETS	-2
+#define NO_TARGET	-1
+#define ALL_LUNS	-2
+#define NO_LUN		-1
+
+static int device_queue_depth(ncb_p np, int target, int lun)
+{
+	int c, h, t, u, v;
+	char *p = driver_setup.tag_ctrl;
+	char *ep;
+
+	h = -1;
+	t = NO_TARGET;
+	u = NO_LUN;
+	while ((c = *p++) != 0) {
+		v = simple_strtoul(p, &ep, 0);
+		switch(c) {
+		case '/':
+			++h;
+			t = ALL_TARGETS;
+			u = ALL_LUNS;
+			break;
+		case 't':
+			if (t != target)
+				t = (target == v) ? v : NO_TARGET;
+			u = ALL_LUNS;
+			break;
+		case 'u':
+			if (u != lun)
+				u = (lun == v) ? v : NO_LUN;
+			break;
+		case 'q':
+			if (h == np->unit &&
+				(t == ALL_TARGETS || t == target) &&
+				(u == ALL_LUNS    || u == lun))
+				return v;
+			break;
+		case '-':
+			t = ALL_TARGETS;
+			u = ALL_LUNS;
+			break;
+		default:
+			break;
+		}
+		p = ep;
+	}
+	return DEF_DEPTH;
+}
+
 static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist)
 {
 	struct scsi_device *device;
 
 	for (device = devlist; device; device = device->next) {
-		if (device->host == host) {
-#if SCSI_NCR_MAX_TAGS > 1
-			if (device->tagged_supported) {
-				device->queue_depth = SCSI_NCR_MAX_TAGS;
-			}
-			else {
-				device->queue_depth = 2;
-			}
-#else
-			device->queue_depth = 1;
-#endif
+		ncb_p np;
+		tcb_p tp;
+		lcb_p lp;
+
+		if (device->host != host)
+			continue;
+
+		np = ((struct host_data *) host->hostdata)->ncb;
+		tp = &np->target[device->id];
+		lp = tp->lp[device->lun];
+
+		/*
+		**	Donnot use more than our maximum.
+		**	Select queue depth from driver setup.
+		**	Donnot use more than configured by user.
+		**	Use 2 for devices that donnot support tags.
+		**	Use at least 2.
+		*/
+		device->queue_depth = SCSI_NCR_MAX_TAGS;
+		device->queue_depth =
+			device_queue_depth(np, device->id, device->lun);
+		if (device->queue_depth > tp->usrtags)
+			device->queue_depth = tp->usrtags;
+		if (!device->tagged_supported || device->queue_depth < 2)
+			device->queue_depth = 2;
+
+		/*
+		**	Since the queue depth is not tunable under Linux,
+		**	we need to know this value in order not to 
+		**	announce stupid things to user.
+		*/
+		if (lp)
+			lp->scdev_depth = device->queue_depth;
+		ncr_setup_tags (np, device->id, device->lun);
 
 #ifdef DEBUG_NCR53C8XX
-printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n",
-	device->id, device->lun, device->queue_depth);
+printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
+	np->unit, device->id, device->lun, device->queue_depth);
 #endif
-		}
 	}
 }
-#endif
 
 /*
 **   Linux entry point of queuecommand() function
@@ -9774,78 +10121,96 @@
 
 int ncr53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
 {
+     ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb;
+     unsigned long flags;
      int sts;
+
 #ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx_queue_command\n");
 #endif
 
-     if ((sts = ncr_queue_command(cmd, done)) != DID_OK) {
+     cmd->scsi_done     = done;
+     cmd->host_scribble = NULL;
+     cmd->SCp.ptr       = NULL;
+     cmd->SCp.buffer    = NULL;
+
+     NCR_LOCK_NCB(np, flags);
+
+     if ((sts = ncr_queue_command(np, cmd)) != DID_OK) {
 	  cmd->result = ScsiResult(sts, 0);
-	  done(cmd);
 #ifdef DEBUG_NCR53C8XX
 printk("ncr53c8xx : command not queued - result=%d\n", sts);
 #endif
-          return sts;
      }
 #ifdef DEBUG_NCR53C8XX
+     else
 printk("ncr53c8xx : command successfully queued\n");
 #endif
+
+     NCR_UNLOCK_NCB(np, flags);
+
+     if (sts != DID_OK)
+          done(cmd);
+
      return sts;
 }
 
 /*
 **   Linux entry point of the interrupt handler.
-**   Fort linux versions > 1.3.70, we trust the kernel for 
+**   Since linux versions > 1.3.70, we trust the kernel for 
 **   passing the internal host descriptor as 'dev_id'.
 **   Otherwise, we scan the host list and call the interrupt 
 **   routine for each host that uses this IRQ.
 */
 
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
 static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
 {
+     unsigned long flags;
+     ncb_p np = (ncb_p) dev_id;
+     Scsi_Cmnd *done_list;
+
 #ifdef DEBUG_NCR53C8XX
      printk("ncr53c8xx : interrupt received\n");
 #endif
 
-     if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
-     ncr_exception((ncb_p) dev_id);
-     if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
-}
-
-static void do_ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
-     unsigned long flags;
-
-     spin_lock_irqsave(&io_request_lock, flags);
-     ncr53c8xx_intr(irq, dev_id, regs);
-     spin_unlock_irqrestore(&io_request_lock, flags);
-}
-
-#else
-static void ncr53c8xx_intr(int irq, struct pt_regs * regs)
-{
-     struct Scsi_Host *host;
-     struct host_data *host_data;
+     if (DEBUG_FLAGS & DEBUG_TINY) printk ("[");
 
-     for (host = first_host; host; host = host->next) {
-	  if (host->hostt == the_template && host->irq == irq) {
-	       host_data = (struct host_data *) host->hostdata;
-               if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
-               ncr_exception(host_data->ncb);
-               if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n");
-	  }
+     NCR_LOCK_NCB(np, flags);
+     ncr_exception(np);
+     done_list     = np->done_list;
+     np->done_list = 0;
+     NCR_UNLOCK_NCB(np, flags);
+
+     if (DEBUG_FLAGS & DEBUG_TINY) printk ("]\n");
+
+     if (done_list) {
+          NCR_LOCK_SCSI_DONE(np, flags);
+          ncr_flush_done_cmds(done_list);
+          NCR_UNLOCK_SCSI_DONE(np, flags);
      }
 }
-#endif
 
 /*
 **   Linux entry point of the timer handler
 */
 
-static void ncr53c8xx_timeout(unsigned long np)
+static void ncr53c8xx_timeout(unsigned long npref)
 {
+     ncb_p np = (ncb_p) npref;
+     unsigned long flags;
+     Scsi_Cmnd *done_list;
+
+     NCR_LOCK_NCB(np, flags);
      ncr_timeout((ncb_p) np);
+     done_list     = np->done_list;
+     np->done_list = 0;
+     NCR_UNLOCK_NCB(np, flags);
+
+     if (done_list) {
+          NCR_LOCK_SCSI_DONE(np, flags);
+          ncr_flush_done_cmds(done_list);
+          NCR_UNLOCK_SCSI_DONE(np, flags);
+     }
 }
 
 /*
@@ -9853,16 +10218,24 @@
 */
 
 #if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
-
 int ncr53c8xx_reset(Scsi_Cmnd *cmd, unsigned int reset_flags)
+#else
+int ncr53c8xx_reset(Scsi_Cmnd *cmd)
+#endif
 {
+	ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb;
 	int sts;
 	unsigned long flags;
+	Scsi_Cmnd *done_list;
 
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
 	printk("ncr53c8xx_reset: pid=%lu reset_flags=%x serial_number=%ld serial_number_at_timeout=%ld\n",
 		cmd->pid, reset_flags, cmd->serial_number, cmd->serial_number_at_timeout);
+#else
+	printk("ncr53c8xx_reset: command pid %lu\n", cmd->pid);
+#endif
 
-	save_flags(flags); cli();
+	NCR_LOCK_NCB(np, flags);
 
 	/*
 	 * We have to just ignore reset requests in some situations.
@@ -9880,8 +10253,13 @@
 	 * before returning SCSI_RESET_SUCCESS.
 	 */
 
-	sts = ncr_reset_bus(cmd,
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
+	sts = ncr_reset_bus(np, cmd,
 	(reset_flags & (SCSI_RESET_SYNCHRONOUS | SCSI_RESET_ASYNCHRONOUS)) == SCSI_RESET_SYNCHRONOUS);
+#else
+	sts = ncr_reset_bus(np, cmd, 0);
+#endif
+
 	/*
 	 * Since we always reset the controller, when we return success, 
 	 * we add this information to the return code.
@@ -9892,33 +10270,36 @@
 #endif
 
 out:
-	restore_flags(flags);
+	done_list     = np->done_list;
+	np->done_list = 0;
+	NCR_UNLOCK_NCB(np, flags);
+
+	ncr_flush_done_cmds(done_list);
+
 	return sts;
 }
-#else
-int ncr53c8xx_reset(Scsi_Cmnd *cmd)
-{
-	printk("ncr53c8xx_reset: command pid %lu\n", cmd->pid);
-	return ncr_reset_bus(cmd, 1);
-}
-#endif
 
 /*
 **   Linux entry point of abort() function
 */
 
-#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
-
 int ncr53c8xx_abort(Scsi_Cmnd *cmd)
 {
+	ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb;
 	int sts;
 	unsigned long flags;
+	Scsi_Cmnd *done_list;
 
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
 	printk("ncr53c8xx_abort: pid=%lu serial_number=%ld serial_number_at_timeout=%ld\n",
 		cmd->pid, cmd->serial_number, cmd->serial_number_at_timeout);
+#else
+	printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid);
+#endif
 
-	save_flags(flags); cli();
+	NCR_LOCK_NCB(np, flags);
 
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
 	/*
 	 * We have to just ignore abort requests in some situations.
 	 */
@@ -9926,19 +10307,19 @@
 		sts = SCSI_ABORT_NOT_RUNNING;
 		goto out;
 	}
+#endif
 
-	sts = ncr_abort_command(cmd);
+	sts = ncr_abort_command(np, cmd);
 out:
-	restore_flags(flags);
+	done_list     = np->done_list;
+	np->done_list = 0;
+	NCR_UNLOCK_NCB(np, flags);
+
+	ncr_flush_done_cmds(done_list);
+
 	return sts;
 }
-#else
-int ncr53c8xx_abort(Scsi_Cmnd *cmd)
-{
-	printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid);
-	return ncr_abort_command(cmd);
-}
-#endif
+
 
 #ifdef MODULE
 int ncr53c8xx_release(struct Scsi_Host *host)
@@ -9973,7 +10354,7 @@
 	Scsi_Cmnd *wcmd;
 
 #ifdef DEBUG_WAITING_LIST
-	printf("%s: cmd %lx inserted into waiting list\n", ncr_name(np), (u_long) cmd);
+	printk("%s: cmd %lx inserted into waiting list\n", ncr_name(np), (u_long) cmd);
 #endif
 	cmd->next_wcmd = 0;
 	if (!(wcmd = np->waiting_list)) np->waiting_list = cmd;
@@ -9996,7 +10377,7 @@
 				cmd->next_wcmd = 0;
 			}
 #ifdef DEBUG_WAITING_LIST
-	printf("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd);
+	printk("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd);
 #endif
 			return cmd;
 		}
@@ -10012,70 +10393,29 @@
 	np->waiting_list = 0;
 
 #ifdef DEBUG_WAITING_LIST
-	if (waiting_list) printf("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts);
+	if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts);
 #endif
 	while ((wcmd = waiting_list) != 0) {
 		waiting_list = (Scsi_Cmnd *) wcmd->next_wcmd;
 		wcmd->next_wcmd = 0;
 		if (sts == DID_OK) {
 #ifdef DEBUG_WAITING_LIST
-	printf("%s: cmd %lx trying to requeue\n", ncr_name(np), (u_long) wcmd);
+	printk("%s: cmd %lx trying to requeue\n", ncr_name(np), (u_long) wcmd);
 #endif
-			sts = ncr_queue_command(wcmd, wcmd->scsi_done);
+			sts = ncr_queue_command(np, wcmd);
 		}
 		if (sts != DID_OK) {
 #ifdef DEBUG_WAITING_LIST
-	printf("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts);
+	printk("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts);
 #endif
 			wcmd->result = ScsiResult(sts, 0);
-			wcmd->scsi_done(wcmd);
+			ncr_queue_done_cmd(np, wcmd);
 		}
 	}
 }
 
 #undef next_wcmd
 
-/*
-**	Returns data transfer direction for common op-codes.
-*/
-
-static int guess_xfer_direction(int opcode)
-{
-	int d;
-
-	switch(opcode) {
-	case 0x12:  /*	INQUIRY				12 */
-	case 0x4D:  /*	LOG SENSE			4D */
-	case 0x5A:  /*	MODE SENSE(10)			5A */
-	case 0x1A:  /*	MODE SENSE(6)			1A */
-	case 0x3C:  /*	READ BUFFER			3C */
-	case 0x1C:  /*	RECEIVE DIAGNOSTIC RESULTS	1C */
-	case 0x03:  /*	REQUEST SENSE			03 */
-		d = XferIn;
-		break;
-	case 0x39:  /*	COMPARE				39 */
-	case 0x3A:  /*	COPY AND VERIFY			3A */
-	case 0x18:  /*	COPY				18 */
-	case 0x4C:  /*	LOG SELECT			4C */
-	case 0x55:  /*	MODE SELECT(10)			55 */
-	case 0x3B:  /*	WRITE BUFFER			3B */
-	case 0x1D:  /*	SEND DIAGNOSTIC			1D */
-	case 0x40:  /*	CHANGE DEFINITION		40 */
-	case 0x15:  /*	MODE SELECT(6)			15 */
-		d = XferOut;
-		break;
-	case 0x00:  /*	TEST UNIT READY			00 */
-		d = XferNone;
-		break;
-	default:
-		d = XferBoth;
-		break;
-	}
-
-	return d;
-}
-
-
 #ifdef SCSI_NCR_PROC_INFO_SUPPORT
 
 /*=========================================================================
@@ -10163,6 +10503,8 @@
 		uc->cmd = UC_SETTAGS;
 	else if	((arg_len = is_keyword(ptr, len, "setorder")) != 0)
 		uc->cmd = UC_SETORDER;
+	else if	((arg_len = is_keyword(ptr, len, "setverbose")) != 0)
+		uc->cmd = UC_SETVERBOSE;
 	else if	((arg_len = is_keyword(ptr, len, "setwide")) != 0)
 		uc->cmd = UC_SETWIDE;
 	else if	((arg_len = is_keyword(ptr, len, "setdebug")) != 0)
@@ -10171,15 +10513,11 @@
 		uc->cmd = UC_SETFLAG;
 	else if	((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
 		uc->cmd = UC_CLEARPROF;
-#ifdef	UC_DEBUG_ERROR_RECOVERY
-	else if	((arg_len = is_keyword(ptr, len, "debug_error_recovery")) != 0)
-		uc->cmd = UC_DEBUG_ERROR_RECOVERY;
-#endif
 	else
 		arg_len = 0;
 
 #ifdef DEBUG_PROC_INFO
-printf("ncr_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd);
+printk("ncr_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd);
 #endif
 
 	if (!arg_len)
@@ -10199,20 +10537,21 @@
 			GET_INT_ARG(target);
 			uc->target = (1<<target);
 #ifdef DEBUG_PROC_INFO
-printf("ncr_user_command: target=%ld\n", target);
+printk("ncr_user_command: target=%ld\n", target);
 #endif
 		}
 		break;
 	}
 
 	switch(uc->cmd) {
+	case UC_SETVERBOSE:
 	case UC_SETSYNC:
 	case UC_SETTAGS:
 	case UC_SETWIDE:
 		SKIP_SPACES(1);
 		GET_INT_ARG(uc->data);
 #ifdef DEBUG_PROC_INFO
-printf("ncr_user_command: data=%ld\n", uc->data);
+printk("ncr_user_command: data=%ld\n", uc->data);
 #endif
 		break;
 	case UC_SETORDER:
@@ -10260,7 +10599,7 @@
 			ptr += arg_len; len -= arg_len;
 		}
 #ifdef DEBUG_PROC_INFO
-printf("ncr_user_command: data=%ld\n", uc->data);
+printk("ncr_user_command: data=%ld\n", uc->data);
 #endif
 		break;
 	case UC_SETFLAG:
@@ -10275,24 +10614,6 @@
 			ptr += arg_len; len -= arg_len;
 		}
 		break;
-#ifdef	UC_DEBUG_ERROR_RECOVERY
-	case UC_DEBUG_ERROR_RECOVERY:
-		SKIP_SPACES(1);
-		if	((arg_len = is_keyword(ptr, len, "sge")))
-			uc->data = 1;
-		else if	((arg_len = is_keyword(ptr, len, "abort")))
-			uc->data = 2;
-		else if	((arg_len = is_keyword(ptr, len, "reset")))
-			uc->data = 3;
-		else if	((arg_len = is_keyword(ptr, len, "parity")))
-			uc->data = 4;
-		else if	((arg_len = is_keyword(ptr, len, "none")))
-			uc->data = 0;
-		else
-			return -EINVAL;
-		ptr += arg_len; len -= arg_len;
-		break;
-#endif
 	default:
 		break;
 	}
@@ -10302,9 +10623,9 @@
 	else {
 		long flags;
 
-		save_flags(flags); cli();
+		NCR_LOCK_NCB(np, flags);
 		ncr_usercmd (np);
-		restore_flags(flags);
+		NCR_UNLOCK_NCB(np, flags);
 	}
 	return length;
 }
@@ -10425,7 +10746,7 @@
 	int retv;
 
 #ifdef DEBUG_PROC_INFO
-printf("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func);
+printk("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func);
 #endif
 
 	for (host = first_host; host; host = host->next) {
@@ -10563,7 +10884,7 @@
 	nvram_stop(np, &gpreg);
 	
 #ifdef SCSI_NCR_DEBUG_NVRAM
-printf("ncr53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
+printk("ncr53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n",
 	nvram->start_marker,
 	nvram->trailer[0], nvram->trailer[1], nvram->trailer[2],
 	nvram->trailer[3], nvram->trailer[4], nvram->trailer[5],
@@ -10713,7 +11034,7 @@
 static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
 )
 {
-	DELAY(5);
+	UDELAY (5);
 	switch (bit_mode){
 	case SET_BIT:
 		*gpreg |= write_bit;
@@ -10730,7 +11051,7 @@
 
 	}
 	OUTB (nc_gpreg, *gpreg);
-	DELAY(5);
+	UDELAY (5);
 }
 
 #undef SET_BIT 0
@@ -10867,7 +11188,7 @@
 static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
 )
 {
-	DELAY(2);
+	UDELAY (2);
 	Tnvram_Clk(np, gpreg);
 	*read_bit = INB (nc_gpreg);
 }
@@ -10887,7 +11208,7 @@
 	*gpreg |= 0x10;
 		
 	OUTB (nc_gpreg, *gpreg);
-	DELAY(2);
+	UDELAY (2);
 
 	Tnvram_Clk(np, gpreg);
 }
@@ -10901,7 +11222,7 @@
 {
 	*gpreg &= 0xef;
 	OUTB (nc_gpreg, *gpreg);
-	DELAY(2);
+	UDELAY (2);
 
 	Tnvram_Clk(np, gpreg);
 }
@@ -10914,7 +11235,7 @@
 )
 {
 	OUTB (nc_gpreg, *gpreg | 0x04);
-	DELAY(2);
+	UDELAY (2);
 	OUTB (nc_gpreg, *gpreg);
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov