//***********************************************************************
//*      O.S   : Linux
//* FILE NAME  : dc395x_trm.c
//*      BY    : C.L.  Huang  <ching@tekram.com.tw>	
//*              Erich Chen	  <erich@tekram.com.tw>
//*	Description: Device Driver for Tekram DC395U/UW/F ,DC315/U 
//*		         PCI SCSI Bus Master Host Adapter	
//*		         (SCSI chip set used Tekram ASIC TRM-S1040)
//* (C)Copyright 1995-1999 Tekram Technology Co., Ltd.		       
//***********************************************************************
//* Lots of bugfixes and integration into 2.2+ kernels by
//* Kurt Garloff <garloff@suse.de>
//* (C) 1999-2000 Kurt Garloff
//* License: GNU GPL
//* $Id: dc395x_trm.c,v 1.87 2002/06/21 14:48:06 garloff Exp $
//***********************************************************************
//*	Tekram PCI SCSI adapter (DC395/U/UW/F or DC315/U) revision history
//*								 
//*	REV#	DATE	NAME	        DESCRIPTION			
//*	1.00  99/02/28	Erich  Chen     First release			
//*	1.01  99/06/28	Kurt Garloff	SMP fixes for 2.2 (locking),
//*					cleanup
//*	1.06  99/06/30	Erich  Chen	Modify for linux SMP kernel 2.2.5 
//*					include spinlock.h
//*	1.07  99/07/12	Kurt Garloff	Merge of 1.01 and 1.06
//*	1.08  99/07/15	Kurt Garloff	Fix Oopses, Message Handling,
//*					Copy SyncMode to LUNs
//*	1.09  99/07/18	Kurt Garloff	Fix Oops. Fix recognition of devs.
//*					Fixed TagQ: MaxCommand limit!
//*	1.10  99/07/19	KG		Defines for switching off features.
//*	1.10a  99/08/31	KG		Fix typo in dc395-integ20.diff
//*	1.11  99/10/14	KG		Remove some debug statements.
//*	1.12  00/01/31	KG		Tell ML that we only handle 16 tags. 
//*					2.3 compat.
//*	1.13  00/02/03	KG		Hunt bugs. Use DC395x_READ/WRITE macros
//*	1.14  00/02/06	KG		Complete rewrite of message handling
//*					(merge from tmscsim)
//*	1.15  00/02/07	KG		Rewrite of queueing code
//*					(merge from tmscsim)
//*	1.16  00/02/07	KG		dynamic DCB handling merge from 
//*					tmscsim
//*	1.17  00/02/07	KG		TRACEPRINTF debugging
//*	1.18  00/02/07	KG		Clean DevMode, SyncMode handling
//*					Dynamic config via proc if
//*	1.19  00/02/08	KG		2 Timers per ACB: Waiting, DIP1
//*					Clean SDTR/WDTR dynamic handling
//*					DC395x_dump (proc if)
//*					Partial SG transfer debug
//*					.. without success! Sigh!
//*	1.20  00/02/09	KG		biosparm: scsicam
//*					reading seems semi-stable
//*					writing half-way
//*	1.21  00/02/10	KG		exception handling does its job
//*					and recovers from most trouble
//*	1.22  00/02/10	KG		Fixed FIFO settings (clear, latch ..)
//*					DC395x_cleanup_after_transfer !
//*					seems to be the long searched for 
//*					solution
//*	1.23  00/02/11	KG		Automatically lower speed etc. in abort
//*					Remove CmdBlock copy.
//*	1.24  00/02/14	KG		Try to really abort in case of bus lock
//*					Fix bug wrt to lowering of sync speed
//*					Boot params for BIOS-less adapters
//*					Respect reset cfg but not on shutdown
//*	1.25  00/02/16	KG		There was one CLRFIFO too much ...
//*					The TRM_S1040 does not reliably send an IRQ
//*					in caise of a failed selection/arbitration
//*					DEBUGTRACE now safe. New DEBUGFIFO option
//*	1.26  00/02/25	KG		__init cleanup. IRQ sharing. dev_id for 
//*					irq_req. 2.0 compatibility (timer)
//*					Avoid DMA for up to 4 bytes (=:PIO)
//*					DOP1: Don't rely on CTR being zero, as
//*					FIFO may be non-empty.
//*	1.27  00/05/23	KG		Linux 2.3 and 2.0 compatibility
//*					Cleanups
//*					Timer for chip flaw (misses SelTO),
//*					(but disabled, as it does fail smtms)
//*					Connector cfg output changed
//*					No clrfifo after MIP1
//*	1.28  00/09/29	KG		Only try sync/wide nego, if device reports
//*					to be capable of doing so. 2.4 fixes:
//*					New scanning sequence ... Fix typo
//*	1.29  00/10/12	KG		Allow in kernel compilation w/ 2.4
//*	1.30  00/11/22	KG		Use DCB field for reported INQ flags
//*					2.4: Use get_options(). Add pci_dev_tbl[].
//*	1.31  00/11/24	KG		Fix another NULL ptr. Allow overriding of
//*					BIOS settings by cmd ln params.
//*	1.32  00/12/02	KG		Another 2.4 fix: Remove TYPE_NODEV devices
//*	1.33  01/07/09	KG		Compile fixes for newer gccs (preproc.)
//*	1.34  01/11/14	KG		Fix SG list length != sum length segments (!)
//*					case (contributed by Dag Nygren <dag@newtech.fi>)
//*					Cleanup DOP0/DIP0 handling a bit.
//*					Try to work around extraneous 2 DOP bytes.
//*					Merge SG segments if possible.
//*     1.35  01/12/06  KG              Fix residual calculation. Add MODULE_LICENSE.
//*	1.35a 02/02/08	KG		Ignore DMA errors; don't try stupid loop
//*					to drain buffers. Set max_cmd_len to 24.
//*	1.36  02/02/27	KG		Use pci_map() instead of virt_to_bus().
//*					Linux 2.5 Scsi_Host->host_lock locking
//*					Slight variation of chip bug worked around :-(
//*	1.37  02/02/28	KG		Free SRB's SG lists on module exit
//*					Alloc in many chunks instead of one big
//*					and don't waste memory by alignment.
//*	1.38  02/03/11	KG		Fix pci_map stuff for 2.4 kernels 
//*					(sg.address vs. page_address(sg.page) + sg.offset)
//*					Correctly clean up SG list after REQUEST_SENSE.
//*					kfree() DCBs on module exit.
//*					Fix inconsistency SRB_array[] size vs. DC395x_MAX_SRB_CNT
//*	1.39 02/04/24	KG		PAGE_ADDRESS for pre2.4.16 kernels
//*					Locking in IRQ handler (thx to Paul Rolland)
//*	1.40 02/05/10	KG		Init tmpSRB debugtrace buffer, fix double free of DCBs
//*	1.40a02/05/12	KG		Doug Gilbert: Support new EH
//*	1.41 02/06/21	KG		Keith Owens: Avoid unaligned acceses (iA64)
//*					Add DC395x_eh_abort() handler.
//*					Clean up pci mappings in abort/SRBdone.
//*	1.42 03/05/19	Oscar		Fix "using tag command during AUTO Reqsense" bug. 
//***********************************************************************
/*
*************************************************************************
**
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
**    notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
**    notice, this list of conditions and the following disclaimer in the
**    documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
**    derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
*************************************************************************
*/

/* Debugging */
//#define DC395x_DEBUG_KG 
//#define DC395x_DEBUG0
//#define DC395x_DEBUG1
//#define DC395x_DEBUGDCB
#define DC395x_DEBUGTRACE
//#define DC395x_DEBUGTRACEALL
//#define DC395x_DEBUGPARSE
//#define DC395x_SGPARANOIA
//#define DC395x_DEBUGFIFO
//#define DC395x_DEBUGRECURSION
//#define DC395x_DEBUGPIO
//#define DC395x_DEBUGMALLOC

/* DISable features */
//#define DC395x_NO_DISCONNECT
//#define DC395x_NO_TAGQ
//#define DC395x_NO_SYNC
//#define DC395x_NO_WIDE

#ifdef DC395x_DEBUG0
# define DEBUG0(x) x
#else
# define DEBUG0(x) 
#endif

#ifdef DC395x_DEBUG1
# define DEBUG1(x) x
#else
# define DEBUG1(x) 
#endif

#ifdef DC395x_DEBUGDCB
# define DCBDEBUG(x) x
#else
# define DCBDEBUG(x)
#endif

#ifdef DC395x_DEBUGPARSE
# define PARSEDEBUG(x) x
#else
# define PARSEDEBUG(x)
#endif

#ifdef DC395x_DEBUGRECURSION
# define DEBUGRECURSION(x) x
#else
# define DEBUGRECURSION(x) 
#endif

#ifdef DC395x_DEBUGPIO
# define DEBUGPIO(x) x
#else
# define DEBUGPIO(x)
#endif

/* Here comes the joker of all debugging facilities! */
#ifdef DC395x_DEBUGTRACEALL
# ifndef DC395x_DEBUGTRACE
#  define DC395x_DEBUGTRACE
# endif
# define TRACEOUTALL(x...) printk ( x)
#else
# define TRACEOUTALL(x...) do {} while (0)
#endif
#ifdef DC395x_DEBUGTRACE
# define DEBUGTRACEBUFSZ 512
char DC395x_tracebuf[64];
char DC395x_traceoverflow[8] = {0,0,0,0,0,0,0,0};
# define TRACEPRINTF(x...) \
do { int ln = sprintf (DC395x_tracebuf, x); \
     if (pSRB->debugpos + ln >= DEBUGTRACEBUFSZ) \
     { pSRB->debugtrace[pSRB->debugpos] = 0; pSRB->debugpos = DEBUGTRACEBUFSZ/5; pSRB->debugtrace[pSRB->debugpos++] = '>'; }; \
     sprintf (pSRB->debugtrace + pSRB->debugpos, "%s", DC395x_tracebuf); \
     pSRB->debugpos += ln - 1; \
   } while (0)
# define TRACEOUT(x...) printk ( x)
#else
# define TRACEPRINTF(x...) do {} while (0)
# define TRACEOUT(x...) do {} while (0)
#endif

#ifdef MODULE
# include <linux/module.h>
#endif

#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
#include <linux/delay.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/mm.h>
#include <linux/config.h>
#include <linux/version.h>
#include <linux/blk.h>
#include <linux/timer.h>

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,16)
# include <asm/page.h>
#endif
#include "scsi.h"
#include "hosts.h"
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,21)
# include "constants.h"
#endif
#include "sd.h"
#include "dc395x_trm.h"

#ifdef USE_NEW_EH
static int DC395x_reset(Scsi_Cmnd *cmd, unsigned int resetFlags);
#endif

#ifdef DC395x_DEBUGMALLOC
inline void* dc395x_kmalloc (size_t sz, int fl)
{
	void *ptr = kmalloc (sz, fl);
	printk (KERN_DEBUG "DC395x: Alloc %i bytes @ %p w/ fl %08x\n",
		sz, ptr, fl);
	return ptr;
}
inline void dc395x_kfree (const void* adr)
{
	printk (KERN_DEBUG "DC395x: Free mem @ %p\n",
		adr);
	kfree (adr);
}
# define KMALLOC(sz,fl) dc395x_kmalloc(sz,fl)
# define KFREE(adr) dc395x_kfree(adr)
#else
# define KMALLOC(sz,fl) kmalloc(sz,fl)
# define KFREE(adr) kfree(adr)
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93)
# include <linux/init.h>
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
#  include <linux/spinlock.h>
# else
#  include <asm/spinlock.h>
# endif /* 2,3,30 */
# define USE_SPINLOCKS 1
#else
# define __initfunc(A) A
# define __initdata
# define __init
# include <linux/bios32.h>
#endif

#define PCI_VendorID_TEKRAM           	0x1DE1	/* Vendor ID	*/
#define PCI_DeviceID_TRMS1040        	0x0391	/* Device ID	*/

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,99)
static struct pci_device_id dc395x_pci_tbl[] __initdata = {
	{
		vendor: PCI_VendorID_TEKRAM,
		device: PCI_DeviceID_TRMS1040,
		subvendor: PCI_ANY_ID,
		subdevice: PCI_ANY_ID,
	},
	{ }		/* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, dc395x_pci_tbl);
#endif


#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,70)
# define NEW_PCI 1
#endif

#ifdef USE_SPINLOCKS
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
#  define DC395x_LOCK_IO(dev)   spin_lock_irqsave (((struct Scsi_Host *)dev)->host_lock, flags)
#  define DC395x_UNLOCK_IO(dev) spin_unlock_irqrestore (((struct Scsi_Host *)dev)->host_lock, flags)
# else
#  define DC395x_LOCK_IO(dev)   spin_lock_irqsave (&io_request_lock, flags)
#  define DC395x_UNLOCK_IO(dev) spin_unlock_irqrestore (&io_request_lock, flags)
# endif
#else
# define DC395x_LOCK_IO(dev)   save_flags (flags); cli ()
# define DC395x_UNLOCK_IO(dev) restore_flags (flags)
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93)

# define DC395x_ACB_INITLOCK(pACB)		spin_lock_init(&pACB->smp_lock)
# define DC395x_ACB_LOCK(pACB,acb_flags)	if(!pACB->lock_level_count[cpuid]) { spin_lock_irqsave(&pACB->smp_lock,acb_flags); pACB->lock_level_count[cpuid]++; } else { pACB->lock_level_count[cpuid]++; }
# define DC395x_ACB_UNLOCK(pACB,acb_flags)	if(--pACB->lock_level_count[cpuid] == 0) { spin_unlock_irqrestore(&pACB->smp_lock,acb_flags); }

# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
#  define DC395x_SMP_IO_LOCK(dev,irq_flags)     spin_lock_irqsave(((struct Scsi_Host *)dev)->host_lock,irq_flags)
#  define DC395x_SMP_IO_UNLOCK(dev,irq_flags)   spin_unlock_irqrestore(((struct Scsi_Host *)dev)->host_lock,irq_flags)
# else
#  define DC395x_SMP_IO_LOCK(dev,irq_flags)     spin_lock_irqsave(&io_request_lock,irq_flags)
#  define DC395x_SMP_IO_UNLOCK(dev,irq_flags)   spin_unlock_irqrestore(&io_request_lock,irq_flags)
# endif
# define DC395x_SCSI_DONE_ACB_LOCK	 spin_lock(&(pACB->smp_lock))
# define DC395x_SCSI_DONE_ACB_UNLOCK	 spin_unlock(&(pACB->smp_lock))

#else

# define DC395x_ACB_INITLOCK(pACB)  
# define DC395x_ACB_LOCK(pACB,acb_flags)	do { save_flags(acb_flags); cli(); } while (0)
# define DC395x_ACB_UNLOCK(pACB,acb_flags)	do { restore_flags(acb_flags); } while (0)

# define DC395x_SMP_IO_LOCK(dev,irq_flags)	do { save_flags(irq_flags); cli(); } while (0)
# define DC395x_SMP_IO_UNLOCK(dev,irq_flags)    do { restore_flags(irq_flags); } while (0)

# define DC395x_SCSI_DONE_ACB_LOCK   
# define DC395x_SCSI_DONE_ACB_UNLOCK  

#endif

# define DC395x_DRV_LOCK(drv_flags)	 do { save_flags(drv_flags); cli(); } while (0)
# define DC395x_DRV_UNLOCK(drv_flags)	 do { restore_flags(drv_flags); } while (0)

#define DC395x_read8(address)			\
	(u8)(inb (pACB->IOPortBase + (address)))

#define DC395x_read8_(address, base)		\
	(u8)(inb ((USHORT)(base) + (address)))

#define DC395x_read16(address)			\
	(u16)(inw (pACB->IOPortBase + (address)))

#define DC395x_read32(address)			\
	(u32)(inl (pACB->IOPortBase + (address)))

#define DC395x_write8(address,value)		\
	outb ((value), pACB->IOPortBase + (address))

#define DC395x_write8_(address,value,base)	\
	outb ((value), (USHORT)(base) + (address))

#define DC395x_write16(address,value)		\
	outw ((value), pACB->IOPortBase + (address))

#define DC395x_write32(address,value)		\
	outl ((value), pACB->IOPortBase + (address))


#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,16)
# define PCI_MAP_SINGLE(hw,ptr,sz,dir)		pci_map_single(hw,ptr,sz,dir)
# define PCI_UNMAP_SINGLE(hw,dma,sz,dir)	pci_unmap_single(hw,dma,sz,dir)
# define PCI_MAP_SG(hw,sg,n,dir)		pci_map_sg(hw,sg,n,dir)
# define PCI_UNMAP_SG(hw,sg,n,dir)		pci_unmap_sg(hw,sg,n,dir)
# define PCI_DMA_SYNC_SINGLE(hw,dma,sz,dir)	pci_dma_sync_single(hw,dma,sz,dir)
# define PCI_DMA_SYNC_SG(hw,sg,n,dir)		pci_dma_sync_sg(hw,sg,n,dir)
# define BUS_ADDR(sg)				sg_dma_address(&(sg))
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
# define CPU_ADDR(sg)			(page_address((sg).page)+(sg).offset)
# define PAGE_ADDRESS(sg)		page_address((sg)->page)
#else
# define CPU_ADDR(sg)			((sg).address? (sg).address: page_address((sg).page)+(sg).offset)
# define PAGE_ADDRESS(sg)		((sg)->address? (sg)->address /*& ~PAGE_MASK*/: page_address((sg)->page))
#endif
# define SET_DIR(dir,pcmd)		dir = scsi_to_pci_dma_dir((pcmd)->sc_data_direction)
#else
# ifndef PCI_DMA_NONE
#  define PCI_DMA_BIDIRECTIONAL   0
#  define PCI_DMA_TODEVICE        1
#  define PCI_DMA_FROMDEVICE      2
#  define PCI_DMA_NONE            3
# endif
# define PCI_MAP_SINGLE(hw,ptr,sz,dir)		virt_to_bus(ptr)
# define PCI_UNMAP_SINGLE(hw,dma,sz,dir)
# define PCI_MAP_SG(hw,sg,n,dir) 		n
# define PCI_UNMAP_SG(hw,sg,n,dir)
# define PCI_DMA_SYNC_SINGLE(hw,dma,sz,dir)
# define PCI_DMA_SYNC_SG(hw,sg,n,dir)
# define BUS_ADDR(sg)			(virt_to_bus((sg).address))
# define CPU_ADDR(sg)			((sg).address)
# define PAGE_ADDRESS(sg)		((sg)->address)
# define SET_DIR(dir,pcmd)		dir = PCI_DMA_BIDIRECTIONAL
#endif


/* cmd->result */
#define RES_TARGET		0x000000FF	/* Target State */
#define RES_TARGET_LNX		STATUS_MASK	/* Only official ... */
#define RES_ENDMSG		0x0000FF00	/* End Message */
#define RES_DID			0x00FF0000	/* DID_ codes */
#define RES_DRV			0xFF000000	/* DRIVER_ codes */

#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt))
#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)<<1)

#define SET_RES_TARGET(who,tgt) { who &= ~RES_TARGET; who |= (int)(tgt); }
#define SET_RES_TARGET_LNX(who,tgt) { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; }
#define SET_RES_MSG(who,msg) { who &= ~RES_ENDMSG; who |= (int)(msg) << 8; }
#define SET_RES_DID(who,did) { who &= ~RES_DID; who |= (int)(did) << 16; }
#define SET_RES_DRV(who,drv) { who &= ~RES_DRV; who |= (int)(drv) << 24; }

/*
**************************************************************************
*/
#define SCSI_IRQ_NONE 255
#define TAG_NONE 255

typedef unsigned char		BYTE;	 /* 8  bits */
typedef unsigned short		WORD;    /* 16 bits */
typedef unsigned int		DWORD;   /* 32 bits */
typedef unsigned int		UINT;    /* 32 bits */
typedef BYTE	        	*PBYTE;
typedef WORD			*PWORD;
typedef DWORD       		*PDWORD;
typedef Scsi_Host_Template	*PSHT;
typedef struct Scsi_Host	*PSH;
typedef Scsi_Device     	*PSCSIDEV;
typedef Scsi_Cmnd       	*PSCSICMD;
typedef void	        	*PVOID;
typedef struct scatterlist	*PSGL, SGL;

/*
 **struct scatterlist
 **{
	 **    char *  address;    // Location data is to be transferred to
	 **    char * alt_address; // Location of actual if address is a dma indirect buffer.  NULL otherwise 
	 **    unsigned int length;
 **};
 */
/*-----------------------------------------------------------------------*/
typedef  struct  _SyncMsg
{
   BYTE		ExtendMsg;
   BYTE		ExtMsgLen;
   BYTE		SyncXferReq;
   BYTE		Period;
   BYTE		ReqOffset;
} SyncMsg;
/*-----------------------------------------------------------------------*/
typedef  struct  _SGentry
{
   DWORD	address;	/* bus! address */
   DWORD	length;
} SGentry, *PSGE0;

/*
;-----------------------------------------------------------------------
; SCSI Request Block
;-----------------------------------------------------------------------
*/
struct	_SRB
{
	struct _SRB *pNextSRB;
	struct _DCB *pSRBDCB;

	/* HW scatter list (up to 64 entries) */
	PSGE0	SegmentX;
	PSCSICMD pcmd;
	
	/* Offset 0x20/0x10 */
	unsigned char*	virt_addr;		/* set by DC395x_update_SGlist */

	DWORD	SRBTotalXferLength;
	DWORD	Xferred; 		/* Backup for the already xferred len */

	DWORD	SRBSGBusAddr;		/* bus address of DC395x scatterlist */
			       
	WORD	SRBState;
	BYTE	SRBSGCount;
	BYTE	SRBSGIndex;
	
	/* Offset 0x38/0x24 */
	BYTE	MsgInBuf[6];
	BYTE	MsgOutBuf[6];

	BYTE	AdaptStatus;
	BYTE	TargetStatus;
	BYTE	MsgCnt;
	BYTE	EndMessage;

	/* Offset 0x48/0x34 */
	PBYTE	pMsgPtr;
	
	BYTE	TagNumber;
	BYTE	SRBStatus;
	BYTE	RetryCnt;
	BYTE	SRBFlag;	    

	BYTE	ScsiPhase;
	//BYTE	IORBFlag;	    /* 81h-Reset, 2-retry         */
	BYTE	padding;
	WORD	debugpos;
	/* Offset 0x58/0x40 */
#ifdef DC395x_DEBUGTRACE
	char	*debugtrace;
	/* Offset 0x60/0x44 */
#endif
};
typedef  struct  _SRB	 DC395X_TRM_SRB, *PSRB;


/*
;-----------------------------------------------------------------------
; Device Control Block
;-----------------------------------------------------------------------
*/
struct	_DCB
{
    struct _DCB	*pNextDCB;
    struct _ACB	*pDCBACB;

    PSRB	pGoingSRB;
    PSRB	pGoingLast;

/* 0x10: */
    PSRB	pWaitingSRB;
    PSRB	pWaitLast;

    PSRB	pActiveSRB;
    DWORD	TagMask;

/* 0x20: */
    WORD	MaxCommand;
    BYTE	AdaptIndex;		/* UnitInfo struc start        */
    BYTE	UnitIndex;		/* nth Unit on this card       */

    WORD	GoingSRBCnt;
    WORD	WaitSRBCnt;
    BYTE	TargetID;		/* SCSI Target ID  (SCSI Only) */
    BYTE	TargetLUN;		/* SCSI Log.  Unit (SCSI Only) */
    BYTE	IdentifyMsg;
    BYTE	DevMode;

/* 0x2c: */
  //BYTE	AdpMode;
    BYTE	Inquiry7;		/* To store Inquiry flags */
    BYTE	SyncMode;		/* 0:async mode */
    BYTE	MinNegoPeriod;		/* for nego. */
    BYTE	SyncPeriod;		/* for reg.  */

    BYTE	SyncOffset;		/* for reg. and nego.(low nibble) */
    BYTE	UnitCtrlFlag;
    BYTE	DCBFlag;
    BYTE	DevType;
    
    unsigned long last_derated;		/* last time, when features were turned off in abort */
/* 0x38: */
    /* BYTE	Reserved2[3];	 for dword alignment */
};
typedef  struct  _DCB	 DC395X_TRM_DCB, *PDCB;
/*
;-----------------------------------------------------------------------
; Adapter Control Block
;-----------------------------------------------------------------------
*/
struct	_ACB
{
    PSH			pScsiHost;
    struct _ACB		*pNextACB;

    WORD		IOPortBase;
    WORD		Revxx1; 
	
#if 0
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93)
    spinlock_t		smp_lock;	/* Lock for SMP threading       */
    volatile unsigned char  lock_level_count[NR_CPUS];
#endif
#endif

    PDCB		pLinkDCB;
    PDCB		pLastDCB;
    PDCB		pDCBRunRobin;

    PDCB		pActiveDCB;

    PSRB		pFreeSRB;
    PSRB		pTmpSRB;
    struct timer_list	Waiting_Timer;
    struct timer_list	SelTO_Timer;

    WORD		SRBCount;
    WORD		AdapterIndex;	/* nth Adapter this driver */

    DWORD		QueryCnt;
    PSCSICMD		pQueryHead;
    PSCSICMD		pQueryTail;

    BYTE		msgin123[4];    

    BYTE		status;
    BYTE		DCBCnt;
    BYTE		sel_timeout;
    BYTE		dummy;

    BYTE		IRQLevel;
    BYTE		TagMaxNum;
    BYTE		ACBFlag;
    BYTE		Gmode2;

    BYTE		Config;
    BYTE		LUNchk;
    BYTE		scan_devices;
    BYTE		HostID_Bit;

    BYTE		DCBmap[DC395x_MAX_SCSI_ID];

    DWORD		Cmds;
    DWORD		SelLost;
    DWORD		SelConn;
    DWORD		CmdInQ;
    DWORD		CmdOutOfSRB;

    //DC395X_TRM_DCB	DCB_array[DC395x_MAX_DCB];	/*  +74h, Len=3E8  */
#ifdef NEW_PCI
    struct pci_dev	*pdev;
#else
    BYTE pbus; 	BYTE pdevfn;
#endif

    BYTE		MsgLen;
    BYTE		DeviceCnt;

    DC395X_TRM_SRB	SRB_array[DC395x_MAX_SRB_CNT];
    DC395X_TRM_SRB	TmpSRB;
};
typedef  struct  _ACB	 DC395X_TRM_ACB, *PACB;

/*-----------------------------------------------------------------------*/

#define BIT31	0x80000000
#define BIT30	0x40000000
#define BIT29	0x20000000
#define BIT28	0x10000000
#define BIT27	0x08000000
#define BIT26	0x04000000
#define BIT25	0x02000000
#define BIT24	0x01000000
#define BIT23	0x00800000
#define BIT22	0x00400000
#define BIT21	0x00200000
#define BIT20	0x00100000
#define BIT19	0x00080000
#define BIT18	0x00040000
#define BIT17	0x00020000
#define BIT16	0x00010000
#define BIT15	0x00008000
#define BIT14	0x00004000
#define BIT13	0x00002000
#define BIT12	0x00001000
#define BIT11	0x00000800
#define BIT10	0x00000400
#define BIT9	0x00000200
#define BIT8	0x00000100
#define BIT7	0x00000080
#define BIT6	0x00000040
#define BIT5	0x00000020
#define BIT4	0x00000010
#define BIT3	0x00000008
#define BIT2	0x00000004
#define BIT1	0x00000002
#define BIT0	0x00000001

/*---UnitCtrlFlag */
#define UNIT_ALLOCATED			BIT0
#define UNIT_INFO_CHANGED		BIT1
#define FORMATING_MEDIA			BIT2
#define UNIT_RETRY              	BIT3

/*---UnitFlags */
#define DASD_SUPPORT            	BIT0
#define SCSI_SUPPORT            	BIT1
#define ASPI_SUPPORT            	BIT2

/*----SRBState machine definition */
#define SRB_FREE                  	0x0000
#define SRB_WAIT                  	0x0001
#define SRB_READY                	0x0002
#define SRB_MSGOUT                	0x0004	/*arbitration+msg_out 1st byte*/
#define SRB_MSGIN                 	0x0008
#define SRB_EXTEND_MSGIN		0x0010
#define SRB_COMMAND             	0x0020
#define SRB_START_                	0x0040	/*arbitration+msg_out+command_out*/
#define SRB_DISCONNECT            	0x0080
#define SRB_DATA_XFER             	0x0100
#define SRB_XFERPAD              	0x0200
#define SRB_STATUS              	0x0400
#define SRB_COMPLETED             	0x0800
#define SRB_ABORT_SENT           	0x1000
#define SRB_DO_SYNC_NEGO           	0x2000
#define SRB_DO_WIDE_NEGO		0x4000
#define SRB_UNEXPECT_RESEL		0x8000
/*
**********************************************************************
**
**      ACB Config	
**
**********************************************************************
*/
#define HCC_WIDE_CARD	        	0x20
#define HCC_SCSI_RESET	        	0x10
#define HCC_PARITY	            	0x08
#define HCC_AUTOTERM	        	0x04
#define HCC_LOW8TERM	        	0x02
#define HCC_UP8TERM			0x01
/*---ACBFlag */
#define RESET_DEV                  	BIT0
#define RESET_DETECT              	BIT1
#define RESET_DONE	                BIT2

/*---DCBFlag */
#define ABORT_DEV_              	BIT0

/*---SRBstatus */
#define SRB_OK	                  	BIT0
#define ABORTION                  	BIT1
#define OVER_RUN                	BIT2
#define UNDER_RUN               	BIT3
#define PARITY_ERROR             	BIT4
#define SRB_ERROR               	BIT5

/*---SRBFlag */
#define DATAOUT                 	BIT7
#define DATAIN	                	BIT6
#define RESIDUAL_VALID          	BIT5
#define ENABLE_TIMER             	BIT4
#define RESET_DEV0              	BIT2
#define ABORT_DEV               	BIT1
#define AUTO_REQSENSE             	BIT0

/*---Adapter status */
#define H_STATUS_GOOD           	0
#define H_SEL_TIMEOUT           	0x11
#define H_OVER_UNDER_RUN            	0x12
#define H_UNEXP_BUS_FREE            	0x13
#define H_TARGET_PHASE_F            	0x14
#define H_INVALID_CCB_OP            	0x16
#define H_LINK_CCB_BAD	            	0x17
#define H_BAD_TARGET_DIR            	0x18
#define H_DUPLICATE_CCB             	0x19
#define H_BAD_CCB_OR_SG             	0x1A
#define H_ABORT 	                0x0FF

/* SCSI BUS Status byte codes*/
#define SCSI_STAT_GOOD			0x0	/*  Good status */
#define SCSI_STAT_CHECKCOND		0x02	/*  SCSI Check Condition */
#define SCSI_STAT_CONDMET		0x04	/*  Condition Met */
#define SCSI_STAT_BUSY			0x08	/*  Target busy status */
#define SCSI_STAT_INTER			0x10	/*  Intermediate status */
#define SCSI_STAT_INTERCONDMET		0x14	/*  Intermediate condition met */
#define SCSI_STAT_RESCONFLICT	 	0x18	/*  Reservation conflict */
#define SCSI_STAT_CMDTERM	 	0x22	/*  Command Terminated */
#define SCSI_STAT_QUEUEFULL		0x28	/*  Queue Full */
#define SCSI_STAT_UNEXP_BUS_F		0xFD	/*  Unexpect Bus Free */
#define SCSI_STAT_BUS_RST_DETECT	0xFE	/*  Scsi Bus Reset detected */
#define SCSI_STAT_SEL_TIMEOUT		0xFF	/*  Selection Time out */

/*---Sync_Mode */
#define SYNC_WIDE_TAG_ATNT_DISABLE	0
#define SYNC_NEGO_ENABLE		BIT0
#define SYNC_NEGO_DONE			BIT1
#define WIDE_NEGO_ENABLE		BIT2
#define WIDE_NEGO_DONE			BIT3
#define WIDE_NEGO_STATE			BIT4
#define EN_TAG_QUEUEING			BIT5
#define EN_ATN_STOP			BIT6

#define SYNC_NEGO_OFFSET		15

/*----SCSI MSG BYTE*/
#define MSG_COMPLETE		0x00
#define MSG_EXTENDED		0x01
#define MSG_SAVE_PTR		0x02
#define MSG_RESTORE_PTR		0x03
#define MSG_DISCONNECT		0x04
#define MSG_INITIATOR_ERROR	0x05
#define MSG_ABORT		0x06
#define MSG_REJECT_		0x07
#define MSG_NOP			0x08
#define MSG_PARITY_ERROR	0x09
#define MSG_LINK_CMD_COMPL	0x0A
#define MSG_LINK_CMD_COMPL_FLG	0x0B
#define MSG_BUS_RESET		0x0C
#define MSG_ABORT_TAG		0x0D
#define MSG_SIMPLE_QTAG		0x20
#define MSG_HEAD_QTAG		0x21
#define MSG_ORDER_QTAG		0x22
#define MSG_IGNOREWIDE		0x23
#define MSG_IDENTIFY		0x80
#define MSG_HOST_ID		0xC0

/*----SCSI STATUS BYTE*/
#define STATUS_GOOD		0x00
#define CHECK_CONDITION_	0x02
#define STATUS_BUSY		0x08
#define STATUS_INTERMEDIATE	0x10
#define RESERVE_CONFLICT	0x18

/* cmd->result */
#define STATUS_MASK_		0xFF
#define MSG_MASK		0xFF00
#define RETURN_MASK		0xFF0000

/*
**  Inquiry Data format
*/

typedef struct	_SCSIInqData { /* INQ */
	BYTE	DevType;	/* Periph Qualifier & Periph Dev Type	*/
	BYTE	RMB_TypeMod;	/* rem media bit & Dev Type Modifier	*/
	BYTE	Vers;		/* ISO, ECMA, & ANSI versions		*/
	BYTE	RDF;		/* AEN, TRMIOP, & response data format	*/
	BYTE	AddLen;		/* length of additional data		*/
	BYTE	Res1;		/* reserved				*/
	BYTE	Res2;		/* reserved				*/
	BYTE	Flags;		/* RelADr,Wbus32,Wbus16,Sync,etc.	*/
	BYTE	VendorID[8];	/* Vendor Identification		*/
	BYTE	ProductID[16];	/* Product Identification		*/
	BYTE	ProductRev[4];	/* Product Revision			*/
} SCSI_INQDATA, *PSCSI_INQDATA;
/*  Inquiry byte 0 masks */
#define SCSI_DEVTYPE		0x1F	/* Peripheral Device Type 	*/
#define SCSI_PERIPHQUAL		0xE0	/* Peripheral Qualifier		*/
/*  Inquiry byte 1 mask */
#define SCSI_REMOVABLE_MEDIA	0x80	/* Removable Media bit (1=removable)  */
/*  Peripheral Device Type definitions */
/* See include/scsi/scsi.h */
#define TYPE_NODEV		SCSI_DEVTYPE    /* Unknown or no device type    */
#ifndef TYPE_PRINTER
# define TYPE_PRINTER		 0x02	   /* Printer device		   */
#endif
#ifndef TYPE_COMM
# define TYPE_COMM		 0x09	   /* Communications device	   */
#endif

/*
** Inquiry flag definitions (Inq data byte 7)
*/
#define SCSI_INQ_RELADR		0x80	/* device supports relative addressing	*/
#define SCSI_INQ_WBUS32		0x40	/* device supports 32 bit data xfers	*/
#define SCSI_INQ_WBUS16		0x20	/* device supports 16 bit data xfers	*/
#define SCSI_INQ_SYNC		0x10	/* device supports synchronous xfer	*/
#define SCSI_INQ_LINKED		0x08	/* device supports linked commands	*/
#define SCSI_INQ_CMDQUEUE	0x02	/* device supports command queueing	*/
#define SCSI_INQ_SFTRE		0x01	/* device supports soft resets		*/
/*--------------------------*/
#define ENABLE_CE	1
#define DISABLE_CE	0
#define EEPROM_READ	0x80
/*------------------------------------------------------------------------------*/
/*
***********************************************************************
* The PCI configuration register offset for TRM_S1040			
***********************************************************************
*/
#define TRM_S1040_ID		0x00	/* Vendor and Device ID		*/
#define TRM_S1040_COMMAND  	0x04	/* PCI command register		*/
#define TRM_S1040_IOBASE   	0x10	/* I/O Space base address	*/
#define TRM_S1040_ROMBASE  	0x30	/* Expansion ROM Base Address	*/
#define TRM_S1040_INTLINE  	0x3C	/* Interrupt line		*/

/*
***********************************************************************
**
** The SCSI register offset for TRM_S1040		
**
***********************************************************************
*/
#define TRM_S1040_SCSI_STATUS		0x80	/* SCSI Status (R)		*/
/* ######### */
#define  COMMANDPHASEDONE	0x2000	/* SCSI command phase done		*/
#define  SCSIXFERDONE		0x0800	/* SCSI SCSI transfer done		*/
#define  SCSIXFERCNT_2_ZERO	0x0100	/* SCSI SCSI transfer count to zero	*/
#define  SCSIINTERRUPT		0x0080	/* SCSI interrupt pending		*/
#define  COMMANDABORT		0x0040	/* SCSI command abort			*/
#define  SEQUENCERACTIVE	0x0020	/* SCSI sequencer active		*/
#define  PHASEMISMATCH		0x0010	/* SCSI phase mismatch			*/
#define  PARITYERROR		0x0008	/* SCSI parity error			*/

#define PHASEMASK		0x0007	/* Phase MSG/CD/IO			*/
#define  PH_DATA_OUT		0x00	/* Data out phase	              	*/
#define  PH_DATA_IN		0x01	/* Data in phase	            	*/
#define  PH_COMMAND		0x02	/* Command phase	              	*/
#define  PH_STATUS		0x03	/* Status phase		            	*/
#define  PH_BUS_FREE		0x05	/* Invalid phase used as bus free	*/
#define  PH_MSG_OUT		0x06	/* Message out phase	        	*/
#define  PH_MSG_IN		0x07	/* Message in phase	            	*/

/*
****************************************
*/
#define TRM_S1040_SCSI_CONTROL		0x80	/* SCSI Control (W)		*/
/* ######### */
#define  DO_CLRATN		0x0400	/* Clear ATN	             		*/
#define  DO_SETATN		0x0200	/* Set ATN				*/
#define  DO_CMDABORT		0x0100	/* Abort SCSI command         		*/
#define  DO_RSTMODULE		0x0010	/* Reset SCSI chip          		*/
#define  DO_RSTSCSI		0x0008	/* Reset SCSI bus	            	*/
#define  DO_CLRFIFO		0x0004	/* Clear SCSI transfer FIFO	       	*/
#define  DO_DATALATCH		0x0002	/* Enable SCSI bus data input (latched)	*/
//#define  DO_DATALATCH		0x0000	/* KG: DISable SCSI bus data latch   	*/
#define  DO_HWRESELECT		0x0001	/* Enable hardware reselection  	*/
/*
****************************************
*/
#define TRM_S1040_SCSI_FIFOCNT		0x82	/* SCSI FIFO Counter 5bits(R)	*/
/*
****************************************
*/
#define TRM_S1040_SCSI_SIGNAL		0x83	/* SCSI low level signal (R/W)	*/
/*
****************************************
*/
#define TRM_S1040_SCSI_INTSTATUS	0x84	/* SCSI Interrupt Status (R)	*/
/* ######### */
#define  INT_SCAM		0x80	/* SCAM selection interrupt     	*/
#define  INT_SELECT		0x40	/* Selection interrupt	        	*/
#define  INT_SELTIMEOUT		0x20	/* Selection timeout interrupt   	*/
#define  INT_DISCONNECT		0x10	/* Bus disconnected interrupt   	*/
#define  INT_RESELECTED		0x08	/* Reselected interrupt	        	*/
#define  INT_SCSIRESET		0x04	/* SCSI reset detected interrupt	*/
#define  INT_BUSSERVICE		0x02	/* Bus service interrupt        	*/
#define  INT_CMDDONE		0x01	/* SCSI command done interrupt   	*/
/*
****************************************
*/
#define TRM_S1040_SCSI_OFFSET		0x84	/* SCSI Offset Count (W)	*/
/*
**   Bit		Name	        Definition
**   07-05	0	RSVD	        Reversed. Always 0.
**   04 	0	OFFSET4	        Reversed for LVDS. Always 0.
**   03-00	0	OFFSET[03:00]	Offset number from 0 to 15
*/
/*
****************************************
*/
#define TRM_S1040_SCSI_SYNC		0x85	/* SCSI Synchronous Control (R/W) */
/* ######### */
#define  LVDS_SYNC		0x20	/* Enable LVDS synchronous		*/
#define  WIDE_SYNC		0x10	/* Enable WIDE synchronous		*/
#define  ALT_SYNC		0x08	/* Enable Fast-20 alternate synchronous */
/*
******************************************************************
** SYNCM	7    6	  5	   4	3   	2   	1   	0
** Name 	RSVD RSVD LVDS WIDE	ALTPERD	PERIOD2	PERIOD1	PERIOD0
** Default	0	 0	  0	   0	0	    0	    0	    0
**
**
** Bit		    Name                	Definition
** 07-06	0	RSVD                	Reversed. Always read 0
** 05   	0	LVDS                	Reversed. Always read 0
** 04   	0	WIDE/WSCSI          	Enable wide (16-bits) SCSI transfer.
** 03   	0	ALTPERD/ALTPD	        Alternate (Sync./Period) mode. 
**
**                                      @@ When this bit is set,
**                                         the synchronous period bits 2:0 
**                                         in the Synchronous Mode register
**                                         are used to transfer data 
**                                         at the Fast-20 rate.
**                                      @@ When this bit is unset,
**                                         the synchronous period bits 2:0 
**                                         in the Synchronous Mode Register
**                                         are used to transfer data 
**                                         at the Fast-10 rate (or Fast-40 w/ LVDS).
**
** 02-00	0	PERIOD[2:0]/SXPD[02:00]	Synchronous SCSI Transfer Rate.
**                                      These 3 bits specify 
**                                      the Synchronous SCSI Transfer Rate
**                                      for Fast-20 and Fast-10.
**                                      These bits are also reset
**                                      by a SCSI Bus reset.
**
** For Fast-10 bit ALTPD = 0 and LVDS = 0 
**     and bit2,bit1,bit0 is defined as follows :
**
**  	      000	100ns, 10.0 MHz
**   	      001	150ns,  6.6 MHz
**  	      010	200ns,  5.0 MHz
**  	      011	250ns,  4.0 MHz
**   	      100	300ns,  3.3 MHz
**  	      101	350ns,  2.8 MHz
**	      110	400ns,  2.5 MHz
**	      111	450ns,  2.2 MHz
**
** For Fast-20 bit ALTPD = 1 and LVDS = 0 
**     and bit2,bit1,bit0 is defined as follows :
**
**	       000	 50ns, 20.0 MHz
**	       001	 75ns, 13.3 MHz
**	       010	100ns, 10.0 MHz
**	       011	125ns,  8.0 MHz
**	       100	150ns,  6.6 MHz
**	       101	175ns,  5.7 MHz
**	       110	200ns,  5.0 MHz
 **	       111	250ns,  4.0 MHz   KG: Maybe 225ns, 4.4 MHz 
**
** For Fast-40 bit ALTPD = 0 and LVDS = 1
**     and bit2,bit1,bit0 is defined as follows :
**
**	       000	 25ns, 40.0 MHz
**	       001	 50ns, 20.0 MHz
**	       010	 75ns, 13.3 MHz
**	       011	100ns, 10.0 MHz
**	       100	125ns,  8.0 MHz
**	       101	150ns,  6.6 MHz
**	       110	175ns,  5.7 MHz
**	       111	200ns,  5.0 MHz
******************************************************************
*/

/*
****************************************
*/
#define TRM_S1040_SCSI_TARGETID		0x86	/* SCSI Target ID (R/W)		*/
/*
****************************************
*/
#define TRM_S1040_SCSI_IDMSG		0x87	/* SCSI Identify Message (R)	*/
/*
****************************************
*/
#define TRM_S1040_SCSI_HOSTID		0x87	/* SCSI Host ID (W)		*/
/*
****************************************
*/
#define TRM_S1040_SCSI_COUNTER		0x88	/* SCSI Transfer Counter 24bits(R/W) */
/*
****************************************
*/
#define TRM_S1040_SCSI_INTEN		0x8C	/* SCSI Interrupt Enable (R/W)	*/
/* ######### */
#define  EN_SCAM		0x80	/* Enable SCAM selection interrupt	*/
#define  EN_SELECT		0x40	/* Enable selection interrupt		*/
#define  EN_SELTIMEOUT		0x20	/* Enable selection timeout interrupt	*/
#define  EN_DISCONNECT		0x10	/* Enable bus disconnected interrupt	*/
#define  EN_RESELECTED		0x08	/* Enable reselected interrupt		*/
#define  EN_SCSIRESET		0x04	/* Enable SCSI reset detected interrupt */
#define  EN_BUSSERVICE		0x02	/* Enable bus service interrupt		*/
#define  EN_CMDDONE		0x01	/* Enable SCSI command done interrupt	*/
/*
****************************************
*/
#define TRM_S1040_SCSI_CONFIG0		0x8D	/* SCSI Configuration 0 (R/W)	*/
/* ######### */
#define  PHASELATCH	        0x40	/* Enable phase latch	        	*/
#define  INITIATOR	        0x20	/* Enable initiator mode        	*/
#define  PARITYCHECK	        0x10	/* Enable parity check	        	*/
#define  BLOCKRST	        0x01	/* Disable SCSI reset1	        	*/
/*
****************************************
*/
#define TRM_S1040_SCSI_CONFIG1		0x8E	/* SCSI Configuration 1 (R/W)	*/
/* ######### */
#define  ACTIVE_NEGPLUS		0x10	/* Enhance active negation		*/
#define  FILTER_DISABLE		0x08	/* Disable SCSI data filter		*/
#define  FAST_FILTER		0x04	/* ? */
#define  ACTIVE_NEG		0x02	/* Enable active negation		*/
/*
****************************************
*/
#define TRM_S1040_SCSI_CONFIG2		0x8F	/* SCSI Configuration 2 (R/W)	*/
#define CFG2_WIDEFIFO		0x02
/*
****************************************
*/
#define TRM_S1040_SCSI_COMMAND		0x90	/* SCSI Command (R/W)		*/
/* ######### */
#define  SCMD_COMP		0x12	/* Command complete			*/
#define  SCMD_SEL_ATN		0x60	/* Selection with ATN			*/
#define  SCMD_SEL_ATN3		0x64	/* Selection with ATN3			*/
#define  SCMD_SEL_ATNSTOP	0xB8	/* Selection with ATN and Stop		*/
#define  SCMD_FIFO_OUT		0xC0	/* SCSI FIFO transfer out		*/
#define  SCMD_DMA_OUT		0xC1	/* SCSI DMA transfer out		*/
#define  SCMD_FIFO_IN		0xC2	/* SCSI FIFO transfer in		*/
#define  SCMD_DMA_IN		0xC3	/* SCSI DMA transfer in			*/
#define  SCMD_MSGACCEPT		0xD8	/* Message accept			*/
/*
**  Code	Command Description
**
**  02		Enable reselection with FIFO
**  40		Select without ATN with FIFO
**  60		Select with ATN with FIFO
**  64		Select with ATN3 with FIFO
**  A0		Select with ATN and stop with FIFO
**  C0		Transfer information out with FIFO
**  C1		Transfer information out with DMA
**  C2		Transfer information in with FIFO
**  C3		Transfer information in with DMA
**  12		Initiator command complete with FIFO
**  50		Initiator transfer information out sequence without ATN with FIFO
**  70		Initiator transfer information out sequence with ATN with FIFO
**  74		Initiator transfer information out sequence with ATN3 with FIFO
**  52		Initiator transfer information in sequence without ATN with FIFO
**  72		Initiator transfer information in sequence with ATN with FIFO
**  76		Initiator transfer information in sequence with ATN3 with FIFO
**  90		Initiator transfer information out command complete with FIFO
**  92		Initiator transfer information in command complete with FIFO
**  D2		Enable selection
**  08		Reselection
**  48		Disconnect command with FIFO
**  88		Terminate command with FIFO
**  C8		Target command complete with FIFO
**  18		SCAM Arbitration/ Selection
**  5A		Enable reselection
**  98		Select without ATN with FIFO
**  B8		Select with ATN with FIFO
**  D8		Message Accepted
**  58		NOP
*/
/*
****************************************
*/
#define TRM_S1040_SCSI_TIMEOUT		0x91	/* SCSI Time Out Value (R/W)	*/
/*
****************************************
*/
#define TRM_S1040_SCSI_FIFO		0x98	/* SCSI FIFO (R/W)		*/
/*
****************************************
*/
#define TRM_S1040_SCSI_TCR0		0x9C	/* SCSI Target Control 0 (R/W)	*/
/* ######### */
#define  TCR0_WIDE_NEGO_DONE	0x8000	/* Wide nego done			*/
#define  TCR0_SYNC_NEGO_DONE	0x4000	/* Synchronous nego done		*/
#define  TCR0_ENABLE_LVDS	0x2000	/* Enable LVDS synchronous		*/
#define  TCR0_ENABLE_WIDE	0x1000	/* Enable WIDE synchronous		*/
#define  TCR0_ENABLE_ALT	0x0800	/* Enable alternate synchronous		*/
#define  TCR0_PERIOD_MASK	0x0700	/* Transfer rate			*/

#define  TCR0_DO_WIDE_NEGO	0x0080	/* Do wide NEGO				*/
#define  TCR0_DO_SYNC_NEGO	0x0040	/* Do sync NEGO				*/
#define  TCR0_DISCONNECT_EN	0x0020	/* Disconnection enable			*/
#define  TCR0_OFFSET_MASK	0x001F	/* Offset number			*/
/*
****************************************
*/
#define TRM_S1040_SCSI_TCR1		0x9E	/* SCSI Target Control 1 (R/W)	*/
/* ######### */
#define  MAXTAG_MASK		0x7F00	/* Maximum tags (127)			*/
#define  NON_TAG_BUSY		0x0080	/* Non tag command active		*/
#define  ACTTAG_MASK		0x007F	/* Active tags				*/
/*
***********************************************************************
**
** The DMA register offset for TRM_S1040				
**
***********************************************************************
*/
#define TRM_S1040_DMA_COMMAND		0xA0	/* DMA Command (R/W)		*/
/* ######### */
#define	 DMACMD_SG		0x02	/* Enable HW S/G support		*/
#define  DMACMD_DIR		0x01	/* 1 = read from SCSI write to Host	*/
/* ######### */
#define  XFERDATAIN_SG		0x0103	/* Transfer data in  w/  SG		*/
#define  XFERDATAOUT_SG		0x0102	/* Transfer data out w/  SG		*/
#define  XFERDATAIN		0x0101	/* Transfer data in  w/o SG		*/
#define  XFERDATAOUT		0x0100	/* Transfer data out w/o SG		*/
/*
****************************************
*/
#define TRM_S1040_DMA_FIFOCNT		0xA1	/* DMA FIFO Counter (R)		*/
/*
****************************************
*/
#define TRM_S1040_DMA_CONTROL		0xA1	/* DMA Control (W)		*/
/* ######### */
#define  DMARESETMODULE		0x10	/* Reset PCI/DMA module 		*/
#define  STOPDMAXFER		0x08	/* Stop  DMA transfer			*/
#define  ABORTXFER		0x04	/* Abort DMA transfer			*/
#define  CLRXFIFO		0x02	/* Clear DMA transfer FIFO		*/
#define  STARTDMAXFER		0x01	/* Start DMA transfer			*/
/*
****************************************
*/
#define TRM_S1040_DMA_FIFOSTAT		0xA2	/* DMA FIFO Status (R)		*/
/*
****************************************
*/
#define TRM_S1040_DMA_STATUS		0xA3	/* DMA Interrupt Status (R/W)	*/
/* ######### */
#define  XFERPENDING		0x80	/* Transfer pending			*/
#define  SCSIBUSY		0x40	/* SCSI busy 				*/
#define  GLOBALINT		0x20	/* DMA_INTEN bit 0-4 set		*/
#define  FORCEDMACOMP		0x10	/* Force DMA transfer complete		*/
#define  DMAXFERERROR		0x08	/* DMA transfer error			*/
#define  DMAXFERABORT		0x04	/* DMA transfer abort			*/
#define  DMAXFERCOMP		0x02	/* Bus Master XFER Complete status	*/
#define  SCSICOMP		0x01	/* SCSI complete interrupt		*/
/*
****************************************
*/
#define TRM_S1040_DMA_INTEN		0xA4	/* DMA Interrupt Enable (R/W)	*/
/* ######### */
#define  EN_FORCEDMACOMP	0x10	/* Force DMA transfer complete		*/
#define  EN_DMAXFERERROR	0x08	/* DMA transfer error			*/
#define  EN_DMAXFERABORT	0x04	/* DMA transfer abort			*/
#define  EN_DMAXFERCOMP		0x02	/* Bus Master XFER Complete status	*/
#define  EN_SCSIINTR		0x01	/* Enable SCSI complete interrupt	*/
/*
****************************************
*/
#define TRM_S1040_DMA_CONFIG		0xA6	/* DMA Configuration (R/W)	*/
/* ######### */
#define  DMA_ENHANCE		0x8000	/* Enable DMA enhance feature (SG?)	*/
#define  DMA_PCI_DUAL_ADDR	0x4000
#define  DMA_CFG_RES		0x2000	/* Always 1 */
#define  DMA_AUTO_CLR_FIFO	0x1000	/* DISable DMA auto clear FIFO */
#define  DMA_MEM_MULTI_READ	0x0800
#define  DMA_MEM_WRITE_INVAL	0x0400	/* Memory write and invalidate */
#define  DMA_FIFO_CTRL		0x0300	/* Control FIFO operation with DMA */
#define   DMA_FIFO_HALF_HALF	0x0200	/* Keep half filled on both read and write */
/*
****************************************
*/
#define TRM_S1040_DMA_XCNT		0xA8	/* DMA Transfer Counter (R/W), 24bits */
/*
****************************************
*/
#define TRM_S1040_DMA_CXCNT		0xAC	/* DMA Current Transfer Counter (R) */
/*
****************************************
*/
#define TRM_S1040_DMA_XLOWADDR		0xB0	/* DMA Transfer Physical Low Address */
/*
****************************************
*/
#define TRM_S1040_DMA_XHIGHADDR		0xB4	/* DMA Transfer Physical High Address */

/*
***********************************************************************
**
** The general register offset for TRM_S1040	
**
***********************************************************************
*/
#define TRM_S1040_GEN_CONTROL		0xD4	/* Global Control		*/
/* ######### */
#define  CTRL_LED		0x80	/* Control onboard LED */
#define  EN_EEPROM		0x10	/* Enable EEPROM programming		*/
#define  DIS_TERM		0x08	/* Disable onboard termination		*/
#define  AUTOTERM		0x04	/* Enable Auto SCSI terminator		*/
#define  LOW8TERM		0x02	/* Enable Lower 8 bit SCSI terminator	*/
#define  UP8TERM		0x01	/* Enable Upper 8 bit SCSI terminator	*/
/*
****************************************
*/
#define TRM_S1040_GEN_STATUS		0xD5	/* Global Status		*/
/* ######### */
#define  GTIMEOUT		0x80	/* Global timer reach 0      		*/
#define  EXT68HIGH		0x40	/* Higher 8 bit connected externally	*/
#define  INT68HIGH		0x20	/* Higher 8 bit connected internally	*/
#define  CON5068		0x10	/* External 50/68 pin connected (low) 	*/
#define  CON68			0x08	/* Internal 68 pin connected (low)   	*/
#define  CON50			0x04	/* Internal 50 pin connected (low!)     */
#define  WIDESCSI		0x02	/* Wide SCSI card	            	*/
#define  STATUS_LOAD_DEFAULT	0x01
/*
****************************************
*/
#define TRM_S1040_GEN_NVRAM		0xD6	/* Serial NON-VOLATILE RAM port	*/
/* ######### */
#define  NVR_BITOUT		0x08	/* Serial data out			*/
#define  NVR_BITIN		0x04	/* Serial data in			*/
#define  NVR_CLOCK		0x02	/* Serial clock				*/
#define  NVR_SELECT		0x01	/* Serial select			*/
/*
****************************************
*/
#define TRM_S1040_GEN_EDATA		0xD7	/* Parallel EEPROM data port	*/
/*
****************************************
*/
#define TRM_S1040_GEN_EADDRESS		0xD8	/* Parallel EEPROM address	*/
/*
****************************************
*/
#define TRM_S1040_GEN_TIMER		0xDB	/* Global timer			*/

/*
***********************************************************************
** The SEEPROM structure for TRM_S1040 
***********************************************************************
*/
typedef struct NVRAM_TARGET_STRUCT
{
	BYTE	NvmTarCfg0;		/* Target configuration byte 0	*/
	BYTE	NvmTarPeriod;		/* Target period	        */
	BYTE	NvmTarCfg2;		/* Target configuration byte 2	*/
	BYTE	NvmTarCfg3;		/* Target configuration byte 3	*/
} NVRAMTARGETTYPE;
/*   NvmTarCfg0: Target configuration byte 0 :..pDCB->DevMode */
#define NTC_DO_WIDE_NEGO	0x20	/* Wide negotiate		*/
#define NTC_DO_TAG_QUEUEING	0x10	/* Enable SCSI tag queuing	*/
#define NTC_DO_SEND_START	0x08	/* Send start command SPINUP	*/
#define NTC_DO_DISCONNECT	0x04	/* Enable SCSI disconnect	*/
#define NTC_DO_SYNC_NEGO	0x02	/* Sync negotiation		*/
#define NTC_DO_PARITY_CHK	0x01	/* (it sould define at NAC )
					   Parity check enable		*/

/*
**********************************************************************
**
**
**
**********************************************************************
*/
typedef struct NVRAM_STRUC
{
	BYTE		NvramSubVendorID[2];	/* 0,1  Sub Vendor ID	*/
	BYTE		NvramSubSysID[2];	/* 2,3  Sub System ID	*/
	BYTE		NvramSubClass;		/* 4    Sub Class	*/
	BYTE		NvramVendorID[2];	/* 5,6  Vendor ID	*/
	BYTE		NvramDeviceID[2];	/* 7,8  Device ID	*/
	BYTE		NvramReserved;		/* 9    Reserved	*/
	NVRAMTARGETTYPE	NvramTarget[DC395x_MAX_SCSI_ID];
						/** 10,11,12,13
						 ** 14,15,16,17
						 ** ....
						 ** ....
						 ** 70,71,72,73
						 */
	BYTE		NvramScsiId;		/* 74 Host Adapter SCSI ID	*/
	BYTE		NvramChannelCfg;	/* 75 Channel configuration	*/
	BYTE		NvramDelayTime;		/* 76 Power on delay time	*/
	BYTE		NvramMaxTag;		/* 77 Maximum tags		*/
	BYTE		NvramReserved0;		/* 78  */
	BYTE		NvramBootTarget;	/* 79  */
	BYTE		NvramBootLun;		/* 80  */
	BYTE		NvramReserved1;		/* 81  */
	WORD		Reserved[22];		/* 82,..125 */
	WORD		NvramCheckSum;		/* 126,127 */
} NVRAMTYPE,*PNVRAMTYPE;
#if 0
/* Nvram Initiater bits definition */
#define MORE2_DRV		BIT0
#define GREATER_1G		BIT1
#define RST_SCSI_BUS		BIT2
#define ACTIVE_NEGATION		BIT3
#define NO_SEEK			BIT4
#define LUN_CHECK		BIT5
#endif
/* Nvram Adapter Cfg bits definition */
#define NAC_SCANLUN		0x20	/* Include LUN as BIOS device	*/
#define NAC_POWERON_SCSI_RESET	0x04	/* Power on reset enable	*/
#define NAC_GREATER_1G		0x02	/* > 1G support enable		*/
#define NAC_GT2DRIVES		0x01	/* Support more than 2 drives	*/
/*
**#define NAC_DO_PARITY_CHK	0x08	// Parity check enable
*/
/*------------------------------------------------------------------------------*/

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,30)
struct proc_dir_entry	DC395x_proc_scsi=
{
	PROC_SCSI_DC395X_TRMS1040, 
	10, "dc395x_trm",
	S_IFDIR | S_IRUGO | S_IXUGO, 2
};
#endif

static void   DC395x_check_eeprom(PNVRAMTYPE pEEpromBuf,WORD scsiIOPort);
static void   TRM_S1040_read_all(PNVRAMTYPE pEEpromBuf,WORD scsiIOPort);
static BYTE   TRM_S1040_get_data(WORD scsiIOPort, BYTE bAddr);
static void   TRM_S1040_write_all(PNVRAMTYPE pEEpromBuf,WORD scsiIOPort);
static void   TRM_S1040_set_data(WORD scsiIOPort, BYTE bAddr, BYTE bData);
static void   TRM_S1040_write_cmd(WORD scsiIOPort, BYTE bCmd, BYTE bAddr);
static void   TRM_S1040_wait_30us(WORD scsiIOPort);

       void   DC395x_DataOutPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status);
       void   DC395x_DataInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status);
static void   DC395x_CommandPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status);
static void   DC395x_StatusPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status);
static void   DC395x_MsgOutPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status);
       void   DC395x_MsgInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status);
static void   DC395x_DataOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status);
static void   DC395x_DataInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status);
static void   DC395x_CommandPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status);
static void   DC395x_StatusPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status);
static void   DC395x_MsgOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status);
static void   DC395x_MsgInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status);
static void   DC395x_Nop0( PACB pACB, PSRB pSRB, PWORD pscsi_status);
static void   DC395x_Nop1( PACB pACB, PSRB pSRB, PWORD pscsi_status);
static void   DC395x_basic_config (PACB pACB);
static void   DC395x_cleanup_after_transfer (PACB pACB, PSRB pSRB);
static void   DC395x_ResetSCSIBus( PACB pACB );
       int    DC395x_initAdapter( PSH psh, DWORD io_port, BYTE Irq, WORD index );
       void   DC395x_DataIO_transfer( PACB pACB, PSRB pSRB, WORD ioDir);
       void	DC395x_Disconnect( PACB pACB );
       void	DC395x_Reselect( PACB pACB );
       BYTE DC395x_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB );
static void DC395x_BuildSRB(Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB);
       void DC395x_DoingSRB_Done( PACB pACB, BYTE did_code, Scsi_Cmnd* pcmd, BYTE force);
static void DC395x_ScsiRstDetect( PACB pACB );
static void DC395x_pci_unmap (PACB pACB, PSRB pSRB);
static void DC395x_pci_unmap_sense (PACB pACB, PSRB pSRB);
//static void DC395x_printMsg (BYTE *MsgBuf, DWORD len);
static inline void DC395x_EnableMsgOut_Abort ( PACB pACB, PSRB pSRB );
//static inline void DC395x_EnableMsgOutAbort1( PACB pACB, PSRB pSRB );
//static inline void DC395x_EnableMsgOutAbort2( PACB pACB, PSRB pSRB );
       void DC395x_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB );
static void DC395x_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
static inline void DC395x_SetXferRate( PACB pACB, PDCB pDCB );
       void DC395x_initDCB( PACB pACB, PDCB *ppDCB, BYTE target, BYTE lun );

#ifdef MODULE
int    DC395x_release(struct Scsi_Host *host);
int    DC395x_shutdown (struct Scsi_Host *host);
#endif

static PACB	DC395x_pACB_start = NULL;
static PACB	DC395x_pACB_current = NULL;
static WORD	DC395x_adapterCnt = 0;
static WORD	DC395x_CurrSyncOffset = 0;

DEBUGRECURSION(static char in_driver = 0;)
static char DC395x_monitor_next_IRQ = 0;

/* 
*********************************************************
**
**          DC395x_stateV = (void *) DC395x_SCSI_phase0[phase]
**
*********************************************************
*/
static PVOID DC395x_SCSI_phase0[]={
       DC395x_DataOutPhase0,	/* phase:0 */
       DC395x_DataInPhase0,	/* phase:1 */
       DC395x_CommandPhase0,	/* phase:2 */
       DC395x_StatusPhase0,	/* phase:3 */
       DC395x_Nop0,		/* phase:4 PH_BUS_FREE .. initial phase */
       DC395x_Nop0,		/* phase:5 PH_BUS_FREE .. initial phase */
       DC395x_MsgOutPhase0,	/* phase:6 */
       DC395x_MsgInPhase0,	/* phase:7 */
       };
/*
*********************************************************************
**
**	DC395x_stateV = (void *) DC395x_SCSI_phase1[phase]
**
*********************************************************************
*/
static PVOID DC395x_SCSI_phase1[]={
       DC395x_DataOutPhase1,	/* phase:0 */
       DC395x_DataInPhase1,	/* phase:1 */
       DC395x_CommandPhase1,	/* phase:2 */
       DC395x_StatusPhase1,	/* phase:3 */
       DC395x_Nop1,		/* phase:4 PH_BUS_FREE .. initial phase */
       DC395x_Nop1,		/* phase:5 PH_BUS_FREE .. initial phase */
       DC395x_MsgOutPhase1,	/* phase:6 */
       DC395x_MsgInPhase1,	/* phase:7 */
       };

NVRAMTYPE  dc395x_trm_eepromBuf[DC395x_MAX_ADAPTER_NUM];
/*
**Fast20:	000	 50ns, 20.0 MHz
**		001	 75ns, 13.3 MHz
**		010	100ns, 10.0 MHz
**		011	125ns,  8.0 MHz
**		100	150ns,  6.6 MHz
**		101	175ns,  5.7 MHz
**		110	200ns,  5.0 MHz
**		111	250ns,  4.0 MHz
**
**Fast40(LVDS):	000	 25ns, 40.0 MHz
**		001	 50ns, 20.0 MHz
**		010	 75ns, 13.3 MHz
**		011	100ns, 10.0 MHz
**		100	125ns,  8.0 MHz
**		101	150ns,  6.6 MHz
**		110	175ns,  5.7 MHz
**		111	200ns,  5.0 MHz
*/
//static BYTE	dc395x_clock_period[] = {12,19,25,31,37,44,50,62};
/* real period:48ns,76ns,100ns,124ns,148ns,176ns,200ns,248ns */
static BYTE	dc395x_clock_period[] = { 12, 18, 25, 31, 37, 43, 50, 62};
static WORD	dc395x_clock_speed[]  = {200,133,100, 80, 67, 58, 50, 40};
/* real period:48ns,72ns,100ns,124ns,148ns,172ns,200ns,248ns */

/* Override defaults on cmdline:
 * dc395x_trm = AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped), Tags (log2-1), DelayReset
 */
int dc395x_trm[] = {-2, -2, -2, -2, -2, -2};

# if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30)
MODULE_PARM(dc395x_trm, "1-6i");
MODULE_PARM_DESC(dc395x_trm, "Host SCSI ID, Speed (0=20MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1), DelayReset (s)");
# endif

#if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30)
MODULE_AUTHOR("C.L. Huang / Erich Chen / Kurt Garloff");
MODULE_DESCRIPTION("SCSI host adapter driver for Tekram TRM-S1040 based adapters: Tekram DC395 and DC315 series");
MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
#endif

#ifdef MODULE_LICENSE
MODULE_LICENSE("GPL");
#endif

/* Delaying after a reset */
static char __initdata DC395x_interpd [] = {1,3,5,10,16,30,60,120};
/* Convert EEprom value to seconds */
static void __init DC395x_interpret_delay (PNVRAMTYPE pEEpromBuf)
{
    //printk ("DC395x: Debug: Delay: %i\n", pEEpromBuf->NvramDelayTime);
    pEEpromBuf->NvramDelayTime = DC395x_interpd[pEEpromBuf->NvramDelayTime];
};
/* seconds to EEProm value */
static int __init DC395x_uninterpret_delay (int delay)
{
    BYTE idx = 0;
    while (idx < 7 && DC395x_interpd[idx] < delay) idx++;
    return idx;
};


/* Handle "-1" case */
static void __init DC395x_check_for_safe_settings (void)
{
	if (dc395x_trm[0] == -1 || dc395x_trm[0] > 15) /* modules-2.0.0 passes -1 as string */
	{
		dc395x_trm[0] = 7; dc395x_trm[1] = 4; 
		dc395x_trm[2] = 0x09; dc395x_trm[3] = 0x0f;
		dc395x_trm[4] = 2; dc395x_trm[5] = 10;
		printk (KERN_INFO "DC395x: Using safe settings.\n");
	}
}

/* Defaults, to be overriden by (a) BIOS and (b) Cmnd line (kernel/module) args */
int __initdata dc395x_def[] = {7, 1 /* 13.3MHz */,
		NTC_DO_PARITY_CHK | NTC_DO_DISCONNECT | NTC_DO_SYNC_NEGO
		| NTC_DO_WIDE_NEGO | NTC_DO_TAG_QUEUEING | NTC_DO_SEND_START,
		NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET
		/* | NAC_ACTIVE_NEG */
#ifdef CONFIG_SCSI_MULTI_LUN
		| NAC_SCANLUN
#endif
		, 3 /* 16 Tags per LUN */, 1 /* s delay after Reset */ 
};

/* Copy defaults over set values where missing */
static void __init DC395x_fill_with_defaults (void)
{
	int i;
	PARSEDEBUG(printk(KERN_INFO "DC395x: setup %08x %08x %08x %08x %08x %08x\n", dc395x_trm[0],\
		      dc395x_trm[1], dc395x_trm[2], dc395x_trm[3], dc395x_trm[4], dc395x_trm[5]);)
	for (i = 0; i < 6; i++)
	{
		if (dc395x_trm[i] < 0 || dc395x_trm[i] > 255)
			dc395x_trm[i] = dc395x_def[i];
	}
	/* Sanity checks */
	if (dc395x_trm[0] >  15) dc395x_trm[0] =   7;
	if (dc395x_trm[1] >   7) dc395x_trm[1] =   4;
	if (dc395x_trm[4] >   5) dc395x_trm[4] =   4;
	if (dc395x_trm[5] > 180) dc395x_trm[5] = 180;
};


/* Read the parameters from the command line */
#if !defined(MODULE)
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13)
static int DC395x_trm_setup (char *str)
{
	int i, im;
	int ints[8];
	(void)get_options (str, ARRAY_SIZE(ints), ints);
# else
void __init DC395x_trm_setup (char *str, int *ints)
{
	int i, im;
# endif	
	im = ints[0];
	if (im > 6)
	{
		printk (KERN_NOTICE "DC395x: ignore extra params!\n");
		im = 6;
	};
	for (i = 0; i < im; i++)
		dc395x_trm[i] = ints[i+1];
	/* DC395x_checkparams (); */
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13)
	return 1;
#endif	
};
#if 0	// For the editor's indenting :-)
}
#endif

# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13)
__setup("dc395x_trm=", DC395x_trm_setup);
# endif

#endif /* !MODULE */

/* Overrride BIOS values with the set ones */
static void __init DC395x_EEprom_Override (PNVRAMTYPE pEEpromBuf)
{
    BYTE  id;
    
    /* Adapter Settings */
    if (dc395x_trm[0] != -2)
	pEEpromBuf->NvramScsiId	= (BYTE)dc395x_trm[0];	/* Adapter ID */
    if (dc395x_trm[3] != -2)
	pEEpromBuf->NvramChannelCfg	= (BYTE)dc395x_trm[3];
    if (dc395x_trm[5] != -2)
	pEEpromBuf->NvramDelayTime	= DC395x_uninterpret_delay (dc395x_trm[5]);	/* Reset delay */
    if (dc395x_trm[4] != -2)
	pEEpromBuf->NvramMaxTag	= (BYTE)dc395x_trm[4];	/* Tagged Cmds */
    
    /* Device Settings */
    for (id = 0; id < DC395x_MAX_SCSI_ID; id++)
    {
	if (dc395x_trm[2] != -2)
		pEEpromBuf->NvramTarget[id].NvmTarCfg0	= (BYTE)dc395x_trm[2];	/* Cfg0 */
	if (dc395x_trm[1] != -2)
		pEEpromBuf->NvramTarget[id].NvmTarPeriod= (BYTE)dc395x_trm[1];	/* Speed */
    };
}

	
/* Queueing philosphy:
 * There are a couple of lists:
 * - Query: Contains the Scsi Commands not yet turned into SRBs (per ACB)
 *   (Note: For new EH, it is unecessary!)
 * - Waiting: Contains a list of SRBs not yet sent (per DCB)
 * - Free: List of free SRB slots
 * 
 * If there are no waiting commands for the DCB, the new one is sent to the bus
 * otherwise the oldest one is taken from the Waiting list and the new one is 
 * queued to the Waiting List
 * 
 * Lists are managed using two pointers and eventually a counter
 */

/* Nomen est omen ... */
static inline void
DC395x_freetag (PDCB pDCB, PSRB pSRB)
{
	if (pSRB->TagNumber < 255) {
		pDCB->TagMask &= ~(1 << pSRB->TagNumber);   /* free tag mask */
		pSRB->TagNumber = 255;
	}
};

/* Find cmd in SRB list */
inline static PSRB DC395x_find_cmd (PSCSICMD pcmd, PSRB start)
{
	PSRB psrb = start;
	if (!start) return 0;
	do
	{
		if (psrb->pcmd == pcmd) return psrb;
		psrb = psrb->pNextSRB;
	} while (psrb && psrb != start);
	return 0;
}

/* Append to Query List */
static void DC395x_Query_append( PSCSICMD cmd, PACB pACB )
{
	DEBUG0(printk ("DC395x: Append cmd %li to Query\n", cmd->pid);)
	if( !pACB->QueryCnt )
		pACB->pQueryHead = cmd;
	else
		pACB->pQueryTail->next = cmd;

	pACB->pQueryTail = cmd;
	pACB->QueryCnt++;
	pACB->CmdOutOfSRB++;
	cmd->next = NULL;
}


/* Return next cmd from Query list */
static PSCSICMD DC395x_Query_get ( PACB pACB )
{
	PSCSICMD  pcmd;

	pcmd = pACB->pQueryHead;
	if (!pcmd) return pcmd;
	DEBUG0(printk ("DC395x: Get cmd %li from Query\n", pcmd->pid);)
	pACB->pQueryHead = pcmd->next;
	pcmd->next = NULL;
	if (!pACB->pQueryHead) pACB->pQueryTail = NULL;
	pACB->QueryCnt--;
	return( pcmd );
}


/* Return next free SRB */
static __inline__ PSRB DC395x_Free_get ( PACB pACB )
{
	PSRB   pSRB;

	//DC395x_Free_integrity (pACB);
	pSRB = pACB->pFreeSRB;
	if (!pSRB) printk ("DC395x: Out of Free SRBs :-(\n");
	if (pSRB)
	{
		pACB->pFreeSRB = pSRB->pNextSRB;
		pSRB->pNextSRB = NULL;
	}

	return pSRB;
}

/* Insert SRB oin top of free list */
static __inline__ void DC395x_Free_insert (PACB pACB, PSRB pSRB)
{
	DEBUG0(printk ("DC395x: Free SRB %p\n", pSRB);)
	pSRB->pNextSRB = pACB->pFreeSRB;
	pACB->pFreeSRB = pSRB;
}


/* Inserts a SRB to the top of the Waiting list */
static __inline__ void DC395x_Waiting_insert ( PDCB pDCB, PSRB pSRB )
{
	DEBUG0(printk ("DC395x: Insert pSRB %p cmd %li to Waiting\n", pSRB, pSRB->pcmd->pid);)
	pSRB->pNextSRB = pDCB->pWaitingSRB;
	if (!pDCB->pWaitingSRB)
		pDCB->pWaitLast = pSRB;
	pDCB->pWaitingSRB = pSRB; 
	pDCB->WaitSRBCnt++;
}


/* Queue SRB to waiting list */
static __inline__ void DC395x_Waiting_append ( PDCB pDCB, PSRB pSRB)
{
	DEBUG0(printk ("DC395x: Append pSRB %p cmd %li to Waiting\n", pSRB, pSRB->pcmd->pid);)
	if( pDCB->pWaitingSRB )
		pDCB->pWaitLast->pNextSRB = pSRB;
	else
		pDCB->pWaitingSRB = pSRB;
	
	pDCB->pWaitLast = pSRB;
	/* No next one in waiting list */
	pSRB->pNextSRB = NULL;
	pDCB->WaitSRBCnt++;
	//pDCB->pDCBACB->CmdInQ++;
}

static __inline__ void DC395x_Going_append (PDCB pDCB, PSRB pSRB)
{
	DEBUG0(printk("DC395x: Append SRB %p to Going\n", pSRB);)
	/* Append to the list of Going commands */
	if( pDCB->pGoingSRB )
		pDCB->pGoingLast->pNextSRB = pSRB;
	else
		pDCB->pGoingSRB = pSRB;
	
	pDCB->pGoingLast = pSRB;
	/* No next one in sent list */
	pSRB->pNextSRB = NULL;
	pDCB->GoingSRBCnt++;
};

/* Find predecessor SRB */
inline static PSRB DC395x_find_SRBpre (PSRB pSRB, PSRB start)
{
	PSRB srb = start;
	if (!start) return 0;
	do
	{
		if (srb->pNextSRB == pSRB) return srb;
		srb = srb->pNextSRB;
	} while (srb && srb != start);
	return 0;
}

/* Remove SRB from SRB queue */
inline static PSRB DC395x_rmv_SRB (PSRB pSRB, PSRB pre)
{
	if (pre->pNextSRB != pSRB)
		pre = DC395x_find_SRBpre (pSRB, pre);
	if (!pre) 
	{
		printk ("DC395x: Internal ERROR: SRB to rmv not found in Q!\n");
		return 0;
	}
	pre->pNextSRB = pSRB->pNextSRB;
	//pSRB->pNextSRB = 0;
	return pre;
}

/* Remove SRB from Going queue */
static void DC395x_Going_remove (PDCB pDCB, PSRB pSRB, PSRB hint)
{
	PSRB pre = 0;
	DEBUG0(printk("DC395x: Remove SRB %p from Going\n", pSRB);)
		if (!pSRB) printk ("DC395x: Going_remove %p!\n", pSRB);
	if (pSRB == pDCB->pGoingSRB)
		pDCB->pGoingSRB = pSRB->pNextSRB;
	else if (hint && hint->pNextSRB == pSRB)
		pre = DC395x_rmv_SRB (pSRB, hint);
	else
		pre = DC395x_rmv_SRB (pSRB, pDCB->pGoingSRB);
	if (pSRB == pDCB->pGoingLast)
		pDCB->pGoingLast = pre;
	pDCB->GoingSRBCnt--;
}

/* Remove SRB from Waiting queue */
static void DC395x_Waiting_remove (PDCB pDCB, PSRB pSRB, PSRB hint)
{
	PSRB pre = 0;
	DEBUG0(printk("DC395x: Remove SRB %p from Waiting\n", pSRB);)
		if (!pSRB) printk ("DC395x: Waiting_remove %p!\n", pSRB);
	if (pSRB == pDCB->pWaitingSRB)
		pDCB->pWaitingSRB = pSRB->pNextSRB;
	else if (hint && hint->pNextSRB == pSRB)
		pre = DC395x_rmv_SRB (pSRB, hint);
	else
		pre = DC395x_rmv_SRB (pSRB, pDCB->pWaitingSRB);
	if (pSRB == pDCB->pWaitLast)
		pDCB->pWaitLast = pre;
	pDCB->WaitSRBCnt--;
}

/* Moves SRB from Going list to the top of Waiting list */
static void DC395x_Going_to_Waiting ( PDCB pDCB, PSRB pSRB )
{
	DEBUG0(printk(KERN_INFO "DC395x: Going_to_Waiting (SRB %p) pid = %li\n", pSRB, pSRB->pcmd->pid);)
	/* Remove SRB from Going */
	DC395x_Going_remove (pDCB, pSRB, 0);
	TRACEPRINTF("GtW *");
	/* Insert on top of Waiting */
	DC395x_Waiting_insert (pDCB, pSRB);
	/* Tag Mask must be freed elsewhere ! (KG, 99/06/18) */
}

/* Moves first SRB from Waiting list to Going list */
static __inline__ void DC395x_Waiting_to_Going ( PDCB pDCB, PSRB pSRB )
{	
	/* Remove from waiting list */
	DEBUG0(printk("DC395x: Remove SRB %p from head of Waiting\n", pSRB);)
	DC395x_Waiting_remove (pDCB, pSRB, 0);
	TRACEPRINTF("WtG *");
	DC395x_Going_append (pDCB, pSRB);
}

/* 2.0 timer compatibility */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,30)
 static inline int timer_pending(struct timer_list * timer)
 {
	return timer->prev != NULL;
 }
 #define time_after(a,b)         ((long)(b) - (long)(a) < 0)
 #define time_before(a,b)        time_after(b,a)
#endif

void DC395x_waiting_timed_out (unsigned long ptr);
/* Sets the timer to wake us up */
static void DC395x_waiting_timer (PACB pACB, unsigned long to)
{
	if (timer_pending (&pACB->Waiting_Timer)) return;
	init_timer (&pACB->Waiting_Timer);
	pACB->Waiting_Timer.function = DC395x_waiting_timed_out;
	pACB->Waiting_Timer.data = (unsigned long)pACB;
	if (time_before (jiffies + to, pACB->pScsiHost->last_reset - HZ/2))
		pACB->Waiting_Timer.expires = pACB->pScsiHost->last_reset - HZ/2 + 1;
	else
		pACB->Waiting_Timer.expires = jiffies + to + 1;
	add_timer (&pACB->Waiting_Timer);
}

/* Send the next command from the waiting list to the bus */
void DC395x_Waiting_process ( PACB pACB )
{
	PDCB   ptr, ptr1;
	PSRB   pSRB;
	
	if( (pACB->pActiveDCB) || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) )
		return;
	if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer);
	ptr = pACB->pDCBRunRobin;
	if( !ptr )
	{	/* This can happen! */
		ptr = pACB->pLinkDCB;
		pACB->pDCBRunRobin = ptr;
	}
	ptr1 = ptr;
	if (!ptr1) return;
	do 
	{
		/* Make sure, the next another device gets scheduled ... */
		pACB->pDCBRunRobin = ptr1->pNextDCB;
		if( !( pSRB = ptr1->pWaitingSRB ) ||
		   ( ptr1->MaxCommand <= ptr1->GoingSRBCnt ))
			ptr1 = ptr1->pNextDCB;
		else
		{
			/* Try to send to the bus */
			if( !DC395x_StartSCSI(pACB, ptr1, pSRB) )
				DC395x_Waiting_to_Going (ptr1, pSRB);
			else
				DC395x_waiting_timer (pACB, HZ/50);
			break;
		}
	} while (ptr1 != ptr);
	return;
}

/* Wake up waiting queue */
void DC395x_waiting_timed_out (unsigned long ptr)
{
	unsigned int flags;
	const PACB pACB = (PACB)ptr;
#ifdef DC395x_DEBUG_KG
	printk ("DC395x: Debug: Waiting queue woken up by timer.\n");
#endif
	DC395x_LOCK_IO(pACB->pScsiHost);
	DC395x_Waiting_process (pACB);
	DC395x_UNLOCK_IO(pACB->pScsiHost);
}

/* Get the DCB for a given ID/LUN combination */
static inline PDCB DC395x_findDCB ( PACB pACB, BYTE id, BYTE lun)
{
	PDCB pDCB = pACB->pLinkDCB; 
	if (!pDCB) return 0;
	do 
	{
		if (pDCB->TargetID == id && pDCB->TargetLUN == lun)
			return pDCB;
		pDCB = pDCB->pNextDCB;
	} while (pDCB != pACB->pLinkDCB);
	return 0;
};
 

/***********************************************************************
 * Function: static void DC395x_SendSRB (PACB pACB, PSRB pSRB)
 *
 * Purpose: Send SCSI Request Block (pSRB) to adapter (pACB)
 *
 **            DC395x_queue_command
 **            DC395x_Waiting_process
 *
 ***********************************************************************/

static void DC395x_SendSRB( PACB pACB, PSRB pSRB )
{
    PDCB   pDCB;

    pDCB = pSRB->pSRBDCB;
    if( (pDCB->MaxCommand <= pDCB->GoingSRBCnt) || (pACB->pActiveDCB) ||
	(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) )
    {
	DC395x_Waiting_append (pDCB, pSRB);
	DC395x_Waiting_process (pACB);
	return;
    }

#if 0
    if( pDCB->pWaitingSRB )
    {
	DC395x_Waiting_append (pDCB, pSRB);
/*	pSRB = GetWaitingSRB(pDCB); */	/* non-existent */
	pSRB = pDCB->pWaitingSRB;
	/* Remove from waiting list */
	pDCB->pWaitingSRB = pSRB->pNextSRB;
	pSRB->pNextSRB = NULL;
	if (!pDCB->pWaitingSRB) pDCB->pWaitLast = NULL;
    }
#endif
	
    if (!DC395x_StartSCSI(pACB, pDCB, pSRB))
	DC395x_Going_append (pDCB, pSRB);
    else
    {
	DC395x_Waiting_insert (pDCB, pSRB);
	DC395x_waiting_timer (pACB, HZ/50);
    }
}

/*
**********************************************************************
**
** Function: static void DC395x_BuildSRB (Scsi_Cmd *pcmd, PDCB pDCB, PSRB pSRB)
**
**  Purpose: Prepare SRB for being sent to Device DCB w/ command *pcmd
**
**********************************************************************
*/
static void DC395x_BuildSRB (Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB)
{
    int	    i,max;
    PSGE0   sgp;
    struct  scatterlist *sl;
    DWORD   request_size;
    int	    dir;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_BuildSRB..............\n ");
#endif
    //memset (pSRB, 0, sizeof (DC395X_TRM_SRB));
    pSRB->pSRBDCB = pDCB;
    pSRB->pcmd = pcmd;
    // Find out about direction
    SET_DIR(dir,pcmd);

    if (pcmd->use_sg && dir != PCI_DMA_NONE) {
	unsigned int len = 0;
	/* TODO: In case usg_sg and the no of segments differ, things
	 * will probably go wrong. */
	pSRB->SRBSGCount = PCI_MAP_SG(pDCB->pDCBACB->pdev, (struct scatterlist*)pcmd->request_buffer,
				      pcmd->use_sg, dir);
	sgp = pSRB->SegmentX;
	request_size = pcmd->request_bufflen;
#ifdef DC395x_SGPARANOIA
	printk(KERN_INFO "DC395x: BuildSRB: Bufflen = %d, buffer = %p, use_sg = %d\n", 
	       pcmd->request_bufflen, pcmd->request_buffer, pcmd->use_sg);
	printk(KERN_INFO "DC395x: Mapped %i Segments to %i\n",
	       pcmd->use_sg, pSRB->SRBSGCount);
#endif
	sl = (struct scatterlist *) pcmd->request_buffer;
	max = pcmd->use_sg;
	if (max > DC395x_MAX_SG_LISTENTRY) {
	    printk(KERN_INFO "DC395x: cmd->use_sg=%4d bigger then DC395x_MAX_SG_LISTENTRY=%4d for pid %li\n",
		   pcmd->use_sg,DC395x_MAX_SG_LISTENTRY,pcmd->pid);
	}
	pSRB->virt_addr = PAGE_ADDRESS((struct scatterlist*)sl);
	for (i = 0; i < max; i++, sgp++) {
	    DWORD busaddr = (DWORD) BUS_ADDR(sl[i]);
	    DWORD seglen  = (DWORD) sl[i].length;
	    if (i > 0 && ((sgp-1)->address + (sgp-1)->length) == busaddr &&
		(sgp-1)->length + seglen <= 131072) {
		    sgp--;
#if defined(DC395x_DEBUG_KG) || defined (DC395x_SGPARANOIA)
		    printk (KERN_INFO "DC395x: Merge SG segment %i(%08x) to %i(%08x) (%d->%d)\n",
			    i, busaddr, i-1, sgp->address,
			    sgp->length, sgp->length+seglen);
#endif
		    sgp->length += seglen;
		    len += seglen;
		    pSRB->SRBSGCount--;
	    } else {
		    sgp->address = busaddr;
		    sgp->length = seglen;
		    len += seglen;
	    }
#ifdef DC395x_SGPARANOIA
	    printk(KERN_INFO "DC395x: Setting up sgp %d, address = 0x%08x, length = %d, tot len = %d\n",
		   i, busaddr, seglen, len);
#endif
	}
	sgp--;
	/* Fixup for last buffer too big as it is allocated on even page boundaries */
	if (len > request_size) {
#if defined(DC395x_DEBUG_KG) || defined (DC395x_SGPARANOIA)
		printk(KERN_INFO "DC395x: Fixup SG total length: %d->%d, last seg %d->%d\n",
		       len, request_size, sgp->length, sgp->length - (len - request_size));
#endif
		sgp->length -= (len - request_size);
		len = request_size;
	}
	/* WIDE padding */
	if (pDCB->SyncPeriod & WIDE_SYNC && len%2) {
		len++;
		sgp->length++;
	}
	pSRB->SRBTotalXferLength = len; //?
	/* Hopefully this does not cross a page boundary ... */
	pSRB->SRBSGBusAddr = PCI_MAP_SINGLE(pDCB->pDCBACB->pdev, pSRB->SegmentX,
					    sizeof(SGentry)*DC395x_MAX_SG_LISTENTRY,
					    PCI_DMA_TODEVICE);
#ifdef DC395x_SGPARANOIA
	printk("DC395x: Map SG descriptor list %p (%05x) to %08x\n",
	       pSRB->SegmentX, sizeof(SGentry)*DC395x_MAX_SG_LISTENTRY, 
	       pSRB->SRBSGBusAddr);
#endif	    
    } else if (pcmd->request_buffer && dir != PCI_DMA_NONE) {
	DWORD len = pcmd->request_bufflen; /* Actual request size */
	pSRB->SRBSGCount = 1;
	pSRB->SegmentX[0].address = PCI_MAP_SINGLE(pDCB->pDCBACB->pdev, 
						   pcmd->request_buffer, len, dir);
	/* WIDE padding */
	if (pDCB->SyncPeriod & WIDE_SYNC && len%2)
		len++;
	pSRB->SegmentX[0].length = len;
	pSRB->SRBTotalXferLength = len;
	pSRB->virt_addr = pcmd->request_buffer;
	pSRB->SRBSGBusAddr = 0;
#ifdef DC395x_SGPARANOIA
	printk(KERN_INFO "DC395x: BuildSRB: len = %d, buffer = %p, use_sg = %d, map %08x\n",
	       len, pcmd->request_buffer, pcmd->use_sg, pSRB->SegmentX[0].address);
#endif
    } else {
	pSRB->SRBSGCount = 0;
	pSRB->SRBTotalXferLength = 0;
	pSRB->SRBSGBusAddr = 0;
	pSRB->virt_addr = 0;
#ifdef DC395x_SGPARANOIA
	printk(KERN_INFO "DC395x: BuildSRB: buflen = %d, buffer = %p, use_sg = %d, NOMAP %08x\n",
	       pcmd->bufflen, pcmd->request_buffer, pcmd->use_sg, pSRB->SegmentX[0].address);
#endif
    }

    pSRB->SRBSGIndex = 0;
    pSRB->AdaptStatus = 0;
    pSRB->TargetStatus = 0;
    pSRB->MsgCnt = 0;
    pSRB->SRBStatus = 0;
    pSRB->SRBFlag = 0;
    pSRB->SRBState = 0;
    pSRB->RetryCnt = 0;

#if DC395x_SGPARANOIA	
    if ((unsigned long)pSRB->debugtrace & (DEBUGTRACEBUFSZ-1))
	printk ("DC395x: SRB %i (%p): debugtrace %p corrupt!\n",
		(pSRB - pDCB->pDCBACB->SRB_array) / sizeof(DC395X_TRM_SRB),
		pSRB, pSRB->debugtrace);
#endif
#ifdef DC395x_TRACEDEBUG	
    pSRB->debugpos = 0; pSRB->debugtrace = 0;
#endif
    TRACEPRINTF ("pid %li(%li):%02x %02x..(%i-%i) *", pcmd->pid, jiffies,
		 pcmd->cmnd[0], pcmd->cmnd[1], pcmd->target, pcmd->lun);
    pSRB->TagNumber = TAG_NONE;

    pSRB->ScsiPhase = PH_BUS_FREE; /* initial phase */
    pSRB->EndMessage = 0;
    return;
};

/* Put cmnd from Query to Waiting list and send next Waiting cmnd */
static void DC395x_Query_to_Waiting (PACB pACB)
{
    Scsi_Cmnd *pcmd;
    PSRB   pSRB;
    PDCB   pDCB;

    if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) )
	return;

    while (pACB->QueryCnt)
    {
	pSRB = DC395x_Free_get ( pACB );
	if (!pSRB) return;
	pcmd = DC395x_Query_get ( pACB );
	if (!pcmd) { DC395x_Free_insert (pACB, pSRB); return; }; /* should not happen */
	pDCB = DC395x_findDCB (pACB, pcmd->target, pcmd->lun);
	if (!pDCB) 
	{ 
		DC395x_Free_insert (pACB, pSRB);
		printk (KERN_ERR "DC395x: Command in queue to non-existing device!\n");
		pcmd->result = MK_RES(DRIVER_ERROR,DID_ERROR,0,0);
		//DC395x_UNLOCK_ACB_NI;
		pcmd->done (pcmd);
		//DC395x_LOCK_ACB_NI;
	};
	DC395x_BuildSRB (pcmd, pDCB, pSRB);
	DC395x_Waiting_append ( pDCB, pSRB );
    }
}

/***********************************************************************
 * Function : static int DC395x_queue_command (Scsi_Cmnd *cmd,
 *					       void (*done)(Scsi_Cmnd *))
 *
 * Purpose : enqueues a SCSI command
 *
 * Inputs : cmd - SCSI command, done - callback function called on 
 *	    completion, with a pointer to the command descriptor.
 *
 * Returns : (depending on kernel version)
 * 2.0.x: always return 0
 * 2.1.x: old model: (use_new_eh_code == 0): like 2.0.x
 *	  new model: return 0 if successful
 *	  	     return 1 if command cannot be queued (queue full)
 *		     command will be inserted in midlevel queue then ...
 *
 ***********************************************************************/

int DC395x_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *))
{
    PDCB   pDCB;
    PSRB   pSRB;
    PACB   pACB = (PACB) cmd->host->hostdata;


    DEBUG0(/*  if(pACB->scan_devices) */	\
	printk(KERN_INFO "DC395x: Queue Cmd=%02x,Tgt=%d,LUN=%d (pid=%li)\n",\
		cmd->cmnd[0],cmd->target,cmd->lun,cmd->pid);)

    DEBUGRECURSION(if (in_driver++ > NORM_REC_LVL) printk ("DC395x: %i queue_command () recursion? (pid=%li)\n",
			   in_driver, cmd->pid);)
    
    /* Assume BAD_TARGET; will be cleared later */
    cmd->result = DID_BAD_TARGET << 16;
   
    /* TODO: Change the policy: Alway accept TEST_UNIT_READY or INQUIRY 
     * commands and alloc a DCB for the device if not yet there. DCB will
     * be removed in DC39x_SRBdone if SEL_TIMEOUT */

    if( (pACB->scan_devices == DC395x_END_SCAN) && (cmd->cmnd[0] != INQUIRY) )
	pACB->scan_devices = 0;

    else if( (pACB->scan_devices) && (cmd->cmnd[0] == READ_6) )
	pACB->scan_devices = 0;

    if ( ( cmd->target >= pACB->pScsiHost->max_id ) || 
	 (cmd->lun >= pACB->pScsiHost->max_lun) )
    {
/*	printk ("DC390: Ignore target %d lun %d\n",
		cmd->target, cmd->lun); */
	DEBUGRECURSION(in_driver--;)
	//return (1);
	done (cmd);
	return (0);
    }

    if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY || cmd->cmnd[0] == INQUIRY)
       && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
    {
        pACB->scan_devices = 1;

	DC395x_initDCB( pACB, &pDCB, cmd->target, cmd->lun );
	if (!pDCB)
	  {
	    printk (KERN_ERR "DC395x: kmalloc for DCB failed, target %02x lun %02x\n", 
		    cmd->target, cmd->lun);
	    printk ("DC395x: No DCB in queuecommand!\n");
	    DEBUGRECURSION(in_driver--;)
#ifdef USE_NEW_EH
	    return (1);
#else
	    done (cmd);
	    return (0);
#endif
	  };
            
    }
    else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) )
    {
	printk(KERN_INFO "DC395x: Ignore target %02x lun %02x\n",
		cmd->target, cmd->lun); 
	//return (1);
	DEBUGRECURSION(in_driver--;)
	done (cmd);
	return (0);
    }
    else
    {
	pDCB = DC395x_findDCB (pACB, cmd->target, cmd->lun);
	if (!pDCB)
	 {  /* should never happen */
	    printk (KERN_ERR "DC395x: no DCB failed, target %02x lun %02x\n", 
		    cmd->target, cmd->lun);
	    printk ("DC395x: No DCB in queuecommand (2)!\n");
	    DEBUGRECURSION(in_driver--;)
#ifdef USE_NEW_EH
	    return (1);
#else
	    done (cmd);
	    return (0);
#endif
	 };
    }

    pACB->Cmds++;
    cmd->scsi_done = done;
    cmd->result = 0;
	
    DC395x_Query_to_Waiting (pACB);

    if( pACB->QueryCnt ) /* Unsent commands ? */
    {
	DEBUG0(printk ("DC395x: QueryCnt != 0\n");)
	DC395x_Query_append ( cmd, pACB );
	DC395x_Waiting_process (pACB);
    }
    else if (pDCB->pWaitingSRB)
    {
 	pSRB = DC395x_Free_get ( pACB );
	DEBUG0(if (!pSRB) printk ("DC395x: No free SRB but Waiting\n"); else printk ("DC395x: Free SRB w/ Waiting\n");)
	if (!pSRB) DC395x_Query_append (cmd, pACB);
	else 
	  {
	    DC395x_BuildSRB (cmd, pDCB, pSRB);
	    DC395x_Waiting_append (pDCB, pSRB);
	  }
	DC395x_Waiting_process (pACB);
    }
    else
    {
	pSRB = DC395x_Free_get ( pACB );
	DEBUG0(if (!pSRB) printk ("DC395x: No free SRB w/o Waiting\n"); else printk ("DC395x: Free SRB w/o Waiting\n");)
	if (!pSRB)
	{
	    DC395x_Query_append (cmd, pACB);
	    DC395x_Waiting_process (pACB);
	}
	else 
	{
	    DC395x_BuildSRB (cmd, pDCB, pSRB);
	    DC395x_SendSRB (pACB, pSRB);
	};
    };

    //DC395x_ACB_LOCK(pACB,acb_flags);
    DEBUG1(printk (KERN_DEBUG " ... command (pid %li) queued successfully.\n", cmd->pid);)
    DEBUGRECURSION(in_driver--;)
    return(0);
}

/***********************************************************************
 * Function : static void DC395_updateDCB()
 *
 * Purpose :  Set the configuration dependent DCB parameters
 ***********************************************************************/

void DC395x_updateDCB (PACB pACB, PDCB pDCB)
{
  /* Prevent disconnection of narrow devices if this_id > 7 */
  if (!(pDCB->DevMode & NTC_DO_WIDE_NEGO) && pACB->pScsiHost->this_id > 7)
	pDCB->DevMode &= ~NTC_DO_DISCONNECT;
	
  /* TagQ w/o DisCn is impossible */
  if (!(pDCB->DevMode & NTC_DO_DISCONNECT)) pDCB->DevMode &= ~NTC_DO_TAG_QUEUEING;
  pDCB->IdentifyMsg = IDENTIFY ((pDCB->DevMode & NTC_DO_DISCONNECT), pDCB->TargetLUN);
		
  pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE | WIDE_NEGO_DONE/*| EN_ATN_STOP*/;
  if (pDCB->DevMode & NTC_DO_TAG_QUEUEING) {
	if (pDCB->SyncMode & EN_TAG_QUEUEING) 
		pDCB->MaxCommand = pACB->TagMaxNum;
  } else {
	pDCB->SyncMode &= ~EN_TAG_QUEUEING;
	pDCB->MaxCommand = 1;
  };

  if( pDCB->DevMode & NTC_DO_SYNC_NEGO )
	pDCB->SyncMode |= SYNC_NEGO_ENABLE;
  else {
	pDCB->SyncMode &= ~(SYNC_NEGO_DONE | SYNC_NEGO_ENABLE);
	pDCB->SyncOffset &= ~0x0f;
  };

  if( pDCB->DevMode & NTC_DO_WIDE_NEGO && pACB->Config & HCC_WIDE_CARD)
	pDCB->SyncMode |= WIDE_NEGO_ENABLE;
  else {
	pDCB->SyncMode &= ~(WIDE_NEGO_DONE | WIDE_NEGO_ENABLE);
	pDCB->SyncPeriod &= ~WIDE_SYNC;
  };
  //if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP; 
};  


/***********************************************************************
 * Function : static void DC395x_updateDCBs ()
 *
 * Purpose :  Set the configuration dependent DCB params for all DCBs
 ***********************************************************************/

static void DC395x_updateDCBs (PACB pACB)
{
  int i;
  PDCB pDCB = pACB->pLinkDCB;
  for (i = 0; i < pACB->DCBCnt; i++)
    {
      DC395x_updateDCB (pACB, pDCB);
      pDCB = pDCB->pNextDCB;
    };
};
  

/*
**********************************************************************
**
** Function   : DC395x_bios_param
** Description: Return the disk geometry for the given SCSI device.
**********************************************************************
*/
int DC395x_bios_param(Disk *disk, kdev_t devno, int geom[])
{
#ifdef CONFIG_SCSI_DC395x_TRMS1040_TRADMAP
    int  heads, sectors, cylinders;
    PACB pACB;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_bios_param..............\n ");
#endif
    pACB = (PACB) disk->device->host->hostdata;
    heads = 64;
    sectors = 32;
    cylinders = disk->capacity / (heads * sectors);

    if ( (pACB->Gmode2 & NAC_GREATER_1G) && (cylinders > 1024) )
    {
	heads = 255;
	sectors = 63;
	cylinders = disk->capacity / (heads * sectors);
    }
    geom[0] = heads;
    geom[1] = sectors;
    geom[2] = cylinders;
    return (0);
#else
    return scsicam_bios_param (disk, devno, geom);
#endif	
};


/* DC395x register dump */
void DC395x_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB)
{
	WORD pstat;
#ifdef NEW_PCI
	struct pci_dev *pdev = pACB->pdev;
	pci_read_config_word (pdev, PCI_STATUS, &pstat);
#else
	BYTE pbus = pACB->pbus; 
	BYTE pdevfn = pACB->pdevfn;
	pcibios_read_config_word (pbus, pdevfn, PCI_STATUS, &pstat);
#endif
	if (!pDCB) pDCB = pACB->pActiveDCB;
	if (!pSRB && pDCB) pSRB = pDCB->pActiveSRB;
	if (pSRB)
	{
		if (!(pSRB->pcmd))
			printk ("DC395x: dump: SRB %p: cmd %p OOOPS!\n",
				pSRB, pSRB->pcmd);
		else
			printk   ("DC395x: dump: SRB %p: cmd %p pid %li: %02x (%02i-%i)\n",
				  pSRB, pSRB->pcmd, pSRB->pcmd->pid, pSRB->pcmd->cmnd[0],
				  pSRB->pcmd->target, pSRB->pcmd->lun);
		printk   ("              SGList %p Cnt %i Idx %i Len %i\n",
			  pSRB->SegmentX, pSRB->SRBSGCount, pSRB->SRBSGIndex,
			  pSRB->SRBTotalXferLength);
		printk   ("              State %04x Status %02x Phase %02x (%sconn.)\n",
			  pSRB->SRBState, pSRB->SRBStatus, pSRB->ScsiPhase,
			  (pACB->pActiveDCB)? "": "not");
		TRACEOUT ("        %s\n", pSRB->debugtrace);
	}
	printk ("DC395x: dump: SCSI block\n");
	printk ("              Status %04x FIFOCnt %02x Signals %02x IRQStat %02x\n",
		DC395x_read16 (TRM_S1040_SCSI_STATUS), DC395x_read8 (TRM_S1040_SCSI_FIFOCNT),
		DC395x_read8 (TRM_S1040_SCSI_SIGNAL), DC395x_read8 (TRM_S1040_SCSI_INTSTATUS));
	printk ("              Sync %02x Target %02x RSelID %02x SCSICtr %08x\n",
		DC395x_read8 (TRM_S1040_SCSI_SYNC), DC395x_read8 (TRM_S1040_SCSI_TARGETID),
		DC395x_read8 (TRM_S1040_SCSI_IDMSG), DC395x_read32 (TRM_S1040_SCSI_COUNTER));
	printk ("              IRQEn %02x Config %04x Cfg2 %02x Cmd %02x SelTO %02x\n",
		DC395x_read8 (TRM_S1040_SCSI_INTEN), DC395x_read16 (TRM_S1040_SCSI_CONFIG0),
		DC395x_read8 (TRM_S1040_SCSI_CONFIG2),
		DC395x_read8 (TRM_S1040_SCSI_COMMAND), DC395x_read8 (TRM_S1040_SCSI_TIMEOUT));
	printk ("DC395x: dump: DMA block\n");
	printk ("              Cmd %04x FIFOCnt %02x FStat %02x IRQStat %02x IRQEn %02x Cfg %04x\n",
		DC395x_read16 (TRM_S1040_DMA_COMMAND), DC395x_read8 (TRM_S1040_DMA_FIFOCNT),
		DC395x_read8 (TRM_S1040_DMA_FIFOSTAT), DC395x_read8 (TRM_S1040_DMA_STATUS),
		DC395x_read8 (TRM_S1040_DMA_INTEN), DC395x_read16 (TRM_S1040_DMA_CONFIG));
	printk ("              TCtr %08x CTCtr %08x Addr %08x%08x\n",
		DC395x_read32 (TRM_S1040_DMA_XCNT), DC395x_read32 (TRM_S1040_DMA_CXCNT),
		DC395x_read32 (TRM_S1040_DMA_XHIGHADDR), DC395x_read32 (TRM_S1040_DMA_XLOWADDR));
	printk ("DC395x: dump: Misc: GCtrl %02x GStat %02x GTmr %02x\n",
		DC395x_read8 (TRM_S1040_GEN_CONTROL), DC395x_read8 (TRM_S1040_GEN_STATUS),
		DC395x_read8 (TRM_S1040_GEN_TIMER));
	printk ("DC395x: dump: PCI Status %04x\n", pstat);

		
}


#ifdef OLD_EH
static int DC395x_recover (PACB pACB, PDCB pDCB, PSRB pSRB)
{
	int ctr = 4097;
	//unsigned char lines = DC395x_read8 (TRM_S1040_SCSI_SIGNAL);
	DC395x_EnableMsgOut_Abort (pACB, pSRB);
	DC395x_cleanup_after_transfer (pACB, pSRB);
	if (/*lines & */1)
	{
		/* read */
		//DC395x_write8 (TRM_S1040_SCSI_CONTNTROL, DO_HWRESELECT | DO_DATALATCH);
		while (--ctr && !(DC395x_read16 (TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT))
		{
			DC395x_write8(TRM_S1040_SCSI_SIGNAL, 0x48);
			udelay (1);
			DC395x_write8(TRM_S1040_SCSI_SIGNAL, 0x08);
			udelay (1);
		}
		return ctr;
		DC395x_write8 (TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH);
	}
	else
	{
		/* write */
		while (--ctr && !(DC395x_read16 (TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT))
		{
			int ctr2 = 16;
			DC395x_write32 (TRM_S1040_SCSI_COUNTER, ctr2);
			while (ctr2--) DC395x_write8 (TRM_S1040_SCSI_FIFO, 0);
			DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
		}
		return ctr;
	}
}
#endif /* OLD_EH */

static inline void DC395x_clrfifo (PACB pACB, char *txt)
{
#ifdef DC395x_DEBUGFIFO	
	BYTE lines = DC395x_read8(TRM_S1040_SCSI_SIGNAL);
	BYTE fifocnt = DC395x_read8 (TRM_S1040_SCSI_FIFOCNT);
	if (!(fifocnt & 0x40))
		printk ("DC395x: Clr FIFO (%i bytes) on phase %02x in %s\n", 
			fifocnt & 0x3f, lines, txt);
#endif
	if (pACB->pActiveDCB && pACB->pActiveDCB->pActiveSRB) {
		PSRB pSRB = pACB->pActiveDCB->pActiveSRB;
		TRACEPRINTF ("#*");
	}
	DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
}
  
#ifdef OLD_EH
/*
**********************************************************************
**
** Function : int DC395x_abort (Scsi_Cmnd *cmd)
** Purpose  : Abort an errant SCSI command
** Inputs   : cmd - command to abort
** Returns  : 0 on success, -1 on failure.
**********************************************************************
*/
int DC395x_abort (Scsi_Cmnd *cmd)
{
    PACB      pACB;
    PDCB      pDCB;
    PSRB      pSRB = 0;
    //PSRB	psrb;
    WORD      count, i;
    PSCSICMD  pcmd;
    int       status;
    //DWORD     acb_flags=0;
    //BYTE      lines;

    pACB = (PACB) cmd->host->hostdata;
    printk(KERN_INFO "DC395x_abort: pid=%li, target=%02i-%i\n", 
	   cmd->pid, cmd->target, cmd->lun);
    DEBUGRECURSION(if (in_driver++ > NORM_REC_LVL) printk ("DC395x: %i abort() recursion? (pid=%li)\n",
			     in_driver, cmd->pid);)

    //DC395x_ACB_LOCK(pACB,acb_flags);

    /* First scan Query list */
    if( pACB->QueryCnt )
    {
	pcmd = pACB->pQueryHead;
	if( pcmd == cmd )
	{
	    /* Found: Dequeue */
	    pACB->pQueryHead = pcmd->next;
	    pcmd->next = NULL;
	    if (cmd == pACB->pQueryTail) pACB->pQueryTail = NULL;
	    pACB->QueryCnt--;
	    status = SCSI_ABORT_SUCCESS;
	    goto  ABO_X;
	}
	for( count = pACB->QueryCnt, i=0; i<count-1; i++)
	{
	    if( pcmd->next == cmd )
	    {
		pcmd->next = cmd->next;
		cmd->next = NULL;
		if (cmd == pACB->pQueryTail) pACB->pQueryTail = NULL;
		pACB->QueryCnt--;
		status = SCSI_ABORT_SUCCESS;
		goto  ABO_X;
	    }
	    else
	    {
		pcmd = pcmd->next;
	    }
	}
    }

    pDCB = DC395x_findDCB (pACB, cmd->target, cmd->lun);
    if( !pDCB ) goto  NOT_RUN;

#if 0	
    lines = DC395x_read8 (TRM_S1040_SCSI_SIGNAL);
    if (lines & 0x20 && !pACB->pActiveDCB)
    {
	/* We are not connected, but the device is ? */
	pSRB = pACB->pTmpSRB;
	printk ("DC395x: Device is busy, but we are not connected!\n");
	DC395x_clrfifo (pACB, "abort");
	//DC395x_EnableMsgOut_Abort (pACB, pSRB);
	pDCB->DCBFlag |= ABORT_DEV_;
	pDCB->pActiveSRB = pSRB;
        TRACEPRINTF("abort tmp (SN)!*");
	status = SCSI_ABORT_SNOOZE;
	goto ABO_X;
    }
#endif
    /* Handle waiting queue */
    pSRB = DC395x_find_cmd (cmd, pDCB->pWaitingSRB);
    if (pSRB)
    {
	DC395x_Waiting_remove (pDCB, pSRB, 0);
        TRACEPRINTF("abort (SU)!*");
	DC395x_freetag (pDCB, pSRB);
	DC395x_Free_insert (pACB, pSRB);
	//cmd->next = NULL;
	status = SCSI_ABORT_SUCCESS;
	goto  ABO_X;
    }

    /* Handle Going queue */
    pSRB = DC395x_find_cmd (cmd, pDCB->pGoingSRB);
    if (pSRB)
    {
	    PNVRAMTYPE	pEEpromBuf =  &dc395x_trm_eepromBuf[pACB->AdapterIndex];
	    /* The command has already been sent: Send MSG_ABORT on the next occasion !
	     * This will abort all cmnds for this initiator on the device
	     */
	    pDCB->DCBFlag |= ABORT_DEV_;
	    //This would disallow Sync transfers ...
	    //pDCB->DevMode &= ~(NTC_DO_SYNC_NEGO);
	    if (time_before (pDCB->last_derated, pACB->pScsiHost->last_reset))
	    {
		if ((pDCB->SyncPeriod & 7) < 7)
		{
			printk ("DC395x: abort: Lower SyncFreq to for dev %02i-%i!\n",
				pDCB->TargetID, pDCB->TargetLUN);
			pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarPeriod
				= pDCB->SyncPeriod + 1;
		}
		else if (pDCB->DevMode & NTC_DO_SYNC_NEGO)
		{
			printk ("DC395x: abort: Disable sync transfers for dev %02i-%i!\n",
				pDCB->TargetID, pDCB->TargetLUN);
			pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarCfg0 &= ~NTC_DO_SYNC_NEGO;
		}
		else if (pDCB->DevMode & NTC_DO_WIDE_NEGO)
		{
			printk ("DC395x: abort: Disable wide transfers for dev %02i-%i!\n",
				pDCB->TargetID, pDCB->TargetLUN);
			pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarCfg0 &= ~NTC_DO_WIDE_NEGO;
		}
		else if (pDCB->DevMode & NTC_DO_DISCONNECT)
		{
			printk ("DC395x: abort: Disable disconnection for dev %02i-%i!\n",
				pDCB->TargetID, pDCB->TargetLUN);
			pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarCfg0 &= ~NTC_DO_DISCONNECT;
		}
		else printk ("DC395x: abort: All features already disabled for dev %02i-%i!\n",
			     pDCB->TargetID, pDCB->TargetLUN);
		pDCB->last_derated = jiffies;
		//DC395x_updateDCB (pACB, pDCB);
	    }
			 
	    //DC395x_write8 (TRM_S1040_DMA_STATUS, FORCEDMACOMP);
	    //DC395x_write8 (TRM_S1040_DMA_CONTROL, DMARESETMODULE);
	    //DC395x_basic_config (pACB);
	    if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) )
	    {
		status = SCSI_ABORT_BUSY;
		TRACEPRINTF("abort (BU)!*");
		printk ("DC395x: Abort current command (pid %li, SRB %p)\n",
			cmd->pid, pSRB);
		DC395x_dumpinfo (pACB, pDCB, pSRB);
		//DC395x_EnableMsgOut_Abort (pACB, pSRB);
		if (DC395x_recover (pACB, pDCB, pSRB)) {
			printk ("DC395x: abort() seemed to be successful!\n");
			status = SCSI_ABORT_SNOOZE;
		}
		goto  ABO_X;
	    }
	    else
	    {
		status = SCSI_ABORT_SNOOZE;
		TRACEPRINTF("abort (SN)!*");
		goto  ABO_X;
	    }
    }

NOT_RUN:       
    /* If we get here, the cmnd is not in our queues! */
    printk ("DC395x: Abort non-ex. command pid %li (%02i-%i)?",
	    cmd->pid, cmd->target, cmd->lun);
    status = SCSI_ABORT_NOT_RUNNING;

ABO_X:
    if (pSRB) TRACEOUT (KERN_WARNING "  %s\n", pSRB->debugtrace);
    TRACEOUT (" TmpSRB: %s\n", pACB->pTmpSRB->debugtrace);
    cmd->result = DID_ABORT << 16;
    printk(KERN_INFO "DC395x: Aborted pid %li with status %i\n", cmd->pid, status);
#ifndef USE_NEW_EH
    if (status == SCSI_ABORT_SUCCESS) {
	    // TODO: PCI_UNMAP
	    cmd->scsi_done(cmd);
    }
#endif
    DEBUGRECURSION(in_driver--;)
    return( status );
}
#endif

/*
*********************************************************************
**
**		DC395x_reset      DC395x_ScsiRstDetect
**
*********************************************************************
*/
static void DC395x_ResetDevParam( PACB pACB )
{
    PDCB	pDCB, pDCBTemp;
    PNVRAMTYPE	pEEpromBuf;
    BYTE	PeriodIndex;
    WORD	index;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_ResetDevParam..............\n ");
#endif
    pDCB = pACB->pLinkDCB;
    if( pDCB == NULL )
	return;

    pDCBTemp = pDCB;
    do
    {
	pDCB->SyncMode &= ~(SYNC_NEGO_DONE + WIDE_NEGO_DONE);
	pDCB->SyncPeriod = 0;
	pDCB->SyncOffset = 0;
	index = pACB->AdapterIndex;
	pEEpromBuf = &dc395x_trm_eepromBuf[index];

	pDCB->DevMode = pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarCfg0;
	//pDCB->AdpMode = pEEpromBuf->NvramChannelCfg;
	PeriodIndex = pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarPeriod & 0x07;
	pDCB->MinNegoPeriod = dc395x_clock_period[ PeriodIndex ];
	if (!(pDCB->DevMode & NTC_DO_WIDE_NEGO) || !(pACB->Config & HCC_WIDE_CARD))
	    pDCB->SyncMode &= ~WIDE_NEGO_ENABLE;

	pDCB = pDCB->pNextDCB;
    }
    while( pDCBTemp != pDCB && pDCB != NULL );
}

#if 0
/*
*********************************************************************
**
**		DC395x_ScsiRstDetect
**
*********************************************************************
*/
/* Moves all SRBs from Going to Waiting for all DCBs */
static void DC395x_RecoverSRB( PACB pACB )
{
    PDCB   pDCB, pDCBTemp;
    PSRB   pSRBTemp, pSRBTemp2;
    WORD cnt, i;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_RecoverSRB.............\n ");
#endif
    pDCB = pACB->pLinkDCB;
    if( pDCB == NULL )
	return;
    pDCBTemp = pDCB;
    do
    {
	cnt = pDCBTemp->GoingSRBCnt;
	pSRBTemp = pDCBTemp->pGoingSRB;
	for (i=0; i<cnt; i++)
	{
	    pSRBTemp2 = pSRBTemp;
	    pSRBTemp = pSRBTemp->pNextSRB;
	    /* DC395x_RewaitSRB( pDCB, pSRBTemp ); */
	    if( pDCBTemp->pWaitingSRB )
	    {
		pSRBTemp2->pNextSRB = pDCBTemp->pWaitingSRB;
		pDCBTemp->pWaitingSRB = pSRBTemp2;
	    }
	    else
	    {
		pDCBTemp->pWaitingSRB = pSRBTemp2;
		pDCBTemp->pWaitLast = pSRBTemp2;
		pSRBTemp2->pNextSRB = NULL;
	    }
	}
	pDCBTemp->GoingSRBCnt = 0;
	pDCBTemp->pGoingSRB = NULL;
	pDCBTemp->TagMask = 0;
	pDCBTemp = pDCBTemp->pNextDCB;
    }
    while( pDCBTemp != pDCB );
}
#endif

#ifdef USE_NEW_EH
/*
**********************************************************************
**
** Function : int DC395x_eh_bus_reset(Scsi_Cmnd *cmd)
** Purpose  : perform a hard reset on the SCSI bus
** Inputs   : cmd - some command for this host (for fetching hooks)
** Returns  : SUCCESS (0x2002) on success, else FAILED (0x2003).
**********************************************************************
*/
int DC395x_eh_bus_reset(Scsi_Cmnd *cmd)
{
    PACB        pACB;
    //DWORD         acb_flags=0;

    pACB = (PACB ) cmd->host->hostdata;
    printk(KERN_INFO "DC395x: reset requested!\n");
    pACB = (PACB) cmd->host->hostdata;
    /* mid level guarantees no recursion */
    //DC395x_ACB_LOCK(pACB,acb_flags);

    if (timer_pending (&pACB->Waiting_Timer)) 
	del_timer (&pACB->Waiting_Timer);
    /*
    ** disable interrupt    
    */
    DC395x_write8(TRM_S1040_DMA_INTEN, 0x00);
    DC395x_write8(TRM_S1040_SCSI_INTEN, 0x00);
    DC395x_write8(TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
    DC395x_write8(TRM_S1040_DMA_CONTROL, DMARESETMODULE);

    DC395x_ResetSCSIBus( pACB );
    udelay(500);
    /* We may be in serious trouble. Wait some seconds */
    pACB->pScsiHost->last_reset = jiffies + 3*HZ/2 + 
    	HZ * dc395x_trm_eepromBuf[pACB->AdapterIndex].NvramDelayTime;
    /*
    ** re-enable interrupt      
    */
    /* Clear SCSI FIFO		*/
    DC395x_write8(TRM_S1040_DMA_CONTROL, CLRXFIFO);
    DC395x_clrfifo (pACB, "reset");
    /* Delete pending IRQ */
    DC395x_read8 (TRM_S1040_SCSI_INTSTATUS);
    DC395x_basic_config (pACB);

    DC395x_ResetDevParam( pACB );
    DC395x_DoingSRB_Done( pACB, DID_RESET, cmd, 0 );

    pACB->pActiveDCB = NULL;

    pACB->ACBFlag = 0; /* RESET_DETECT, RESET_DONE ,RESET_DEV */
    DC395x_Waiting_process( pACB );

    //DC395x_ACB_LOCK(pACB,acb_flags);
    return SUCCESS;
}

/*
**********************************************************************
**
** Function : int DC395x_eh_abort(Scsi_Cmnd *cmd)
** Purpose  : abort an errant SCSI command
** Inputs   : cmd - command to be aborted
** Returns  : SUCCESS (0x2002) on success, else FAILED (0x2003).
**********************************************************************
*/
int DC395x_eh_abort(Scsi_Cmnd *cmd)
{
	// Look into our command queues: If it has not been sent already,
	// we remove it and return success. Otherwise fail.
	// First check the Query Queues, then the Waiting ones
	PACB pACB = (PACB) cmd->host->hostdata;
	PDCB pDCB; PSRB pSRB;
	int cnt = pACB->QueryCnt;
	PSCSICMD pcmd, last = 0;
	printk ("DC395x_eh_abort: cmd %p (pid %li, %02i-%i) ",
		cmd, cmd->pid, cmd->target, cmd->lun);
	for (pcmd = pACB->pQueryHead; cnt--; last = pcmd, pcmd = pcmd->next) {
		if (pcmd == cmd) {
			// unqueue
			if (last) {
				last->next = pcmd->next;
				if (!pcmd->next)
					pACB->pQueryTail = last;
			} else {
				pACB->pQueryHead = pcmd->next;
				if (!pcmd->next)
					pACB->pQueryTail = 0;
			}
			printk ("found in Query queue :-)\n");
			pACB->QueryCnt--;
			cmd->result = DID_ABORT << 16;
			return SUCCESS;
		}
	}
	pDCB = DC395x_findDCB (pACB, cmd->target, cmd->lun);
	if (!pDCB) {
		printk ("no DCB !\n");
		return FAILED;
	}
	
	pSRB = DC395x_find_cmd (cmd, pDCB->pWaitingSRB);
	if (pSRB) {
		DC395x_Waiting_remove (pDCB, pSRB, 0);
		DC395x_pci_unmap_sense (pACB, pSRB);
		DC395x_pci_unmap (pACB, pSRB);
		DC395x_freetag (pDCB, pSRB);
		DC395x_Free_insert (pACB, pSRB);
		printk ("found in waiting queue :-)\n");
		cmd->result = DID_ABORT << 16;
		return SUCCESS;
	}
	pSRB = DC395x_find_cmd (cmd, pDCB->pGoingSRB);
	if (pSRB)
		printk ("found in going queue :-(\n");
	else
		printk ("not found!\n");
	return FAILED;
}

/* TODO (new EH):
 * int (*eh_device_reset_handler)(Scsi_Cmnd *);
 * int (*eh_host_reset_handler)(Scsi_Cmnd *);
 * 
 * remove Query Queue
 * investigate whether/which commands need to be ffed back to mid-layer
 * in _eh_reset()
 */
#endif /* end of USE_NEW_EH */

/*
**********************************************************************
**
** Function : int DC395x_reset (Scsi_Cmnd *cmd, ...)
** Purpose  : perform a hard reset on the SCSI bus
** Inputs   : cmd - command which caused the SCSI RESET
** Returns  : 0 on success.
**********************************************************************
*/
int DC395x_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
{
    PACB        pACB;
    //DWORD         acb_flags=0;

    pACB = (PACB ) cmd->host->hostdata;
    printk(KERN_INFO "DC395x: reset requested!\n");
    pACB = (PACB) cmd->host->hostdata;
    DEBUGRECURSION(if (in_driver++ > NORM_REC_LVL) printk ("DC395x: %i reset recursion? (pid=%li)\n",
			     in_driver, cmd->pid);)
    //DC395x_ACB_LOCK(pACB,acb_flags);

    if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer);
    /*
    ** disable interrupt    
    */
    DC395x_write8(TRM_S1040_DMA_INTEN, 0x00);
    DC395x_write8(TRM_S1040_SCSI_INTEN, 0x00);
    DC395x_write8(TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
    DC395x_write8(TRM_S1040_DMA_CONTROL, DMARESETMODULE);

    DC395x_ResetSCSIBus( pACB );
    udelay(500);
    /* We may be in serious trouble. Wait some seconds */
    pACB->pScsiHost->last_reset = jiffies + 3*HZ/2 + 
    	HZ * dc395x_trm_eepromBuf[pACB->AdapterIndex].NvramDelayTime;
    /*
    ** re-enable interrupt      
    */
    /* Clear SCSI FIFO		*/
    DC395x_write8(TRM_S1040_DMA_CONTROL, CLRXFIFO);
    DC395x_clrfifo (pACB, "reset");
    /* Delete pending IRQ */
    DC395x_read8 (TRM_S1040_SCSI_INTSTATUS);
    DC395x_basic_config (pACB);

    DC395x_ResetDevParam( pACB );
    DC395x_DoingSRB_Done( pACB, DID_RESET, cmd, 1 );
    pACB->pActiveDCB = NULL;

    pACB->ACBFlag = 0; /* RESET_DETECT, RESET_DONE ,RESET_DEV */
    DC395x_Waiting_process( pACB );

    //DC395x_ACB_LOCK(pACB,acb_flags);
    DEBUGRECURSION(in_driver--;)
    return( SCSI_RESET_SUCCESS );
}

/* SDTR */
static void DC395x_Build_SDTR (PACB pACB, PDCB pDCB, PSRB pSRB)
{
	PBYTE ptr = pSRB->MsgOutBuf + pSRB->MsgCnt;
	if (pSRB->MsgCnt > 1)
	{
		printk ("DC395x: Build_SDTR: MsgOutBuf BUSY (%i: %02x %02x)\n",
			pSRB->MsgCnt, pSRB->MsgOutBuf[0], pSRB->MsgOutBuf[1]);
		return;
	}
	if (!(pDCB->DevMode & NTC_DO_SYNC_NEGO)) {
		pDCB->SyncOffset = 0;
		pDCB->MinNegoPeriod = 200 >> 2;
	}
	else if (pDCB->SyncOffset == 0)
		pDCB->SyncOffset = SYNC_NEGO_OFFSET;

	*ptr++ = MSG_EXTENDED;	/* (01h) */
	*ptr++ = 3;			/* length */
	*ptr++ = EXTENDED_SDTR;	/* (01h) */
	*ptr++ = pDCB->MinNegoPeriod;	/* Transfer period (in 4ns) */
	*ptr++ = pDCB->SyncOffset;	/* Transfer period (max. REQ/ACK dist) */
	pSRB->MsgCnt += 5;
	pSRB->SRBState |= SRB_DO_SYNC_NEGO;
	TRACEPRINTF("S *");
}

/* SDTR */
static void DC395x_Build_WDTR (PACB pACB, PDCB pDCB, PSRB pSRB)
{
	BYTE wide = ((pDCB->DevMode & NTC_DO_WIDE_NEGO) & (pACB->Config & HCC_WIDE_CARD))? 1: 0;
	PBYTE ptr = pSRB->MsgOutBuf + pSRB->MsgCnt;
	if (pSRB->MsgCnt > 1)
	{
		printk ("DC395x: Build_WDTR: MsgOutBuf BUSY (%i: %02x %02x)\n",
			pSRB->MsgCnt, pSRB->MsgOutBuf[0], pSRB->MsgOutBuf[1]);
		return;
	}
	*ptr++ = MSG_EXTENDED;	/* (01h) */
	*ptr++ = 2;			/* length */
	*ptr++ = EXTENDED_WDTR;	/* (03h) */
	*ptr++ = wide;
	pSRB->MsgCnt += 4;
	pSRB->SRBState |= SRB_DO_WIDE_NEGO;
	TRACEPRINTF("W *");
}


#if 0
/* Timer to work around chip flaw: When selecting and the bus is 
 * busy, we sometimes miss a Selection timeout IRQ */
void DC395x_selection_timeout_missed (unsigned long ptr);
/* Sets the timer to wake us up */
static void DC395x_selto_timer (PACB pACB)
{
	if (timer_pending (&pACB->SelTO_Timer)) return;
	init_timer (&pACB->SelTO_Timer);
	pACB->SelTO_Timer.function = DC395x_selection_timeout_missed;
	pACB->SelTO_Timer.data = (unsigned long)pACB;
	if (time_before (jiffies + HZ, pACB->pScsiHost->last_reset + HZ/2))
		pACB->SelTO_Timer.expires = pACB->pScsiHost->last_reset + HZ/2 + 1;
	else
		pACB->SelTO_Timer.expires = jiffies + HZ + 1;
	add_timer (&pACB->SelTO_Timer);
}

void DC395x_selection_timeout_missed (unsigned long ptr)
{
	unsigned int flags;
	PACB pACB = (PACB)ptr; PSRB pSRB;
	printk ("DC395x: Debug: Chip forgot to produce SelTO IRQ!\n");
	if (!pACB->pActiveDCB || !pACB->pActiveDCB->pActiveSRB) {
		printk ("DC395x: ... but no cmd pending? Oops!\n");
		return;
	}
	DC395x_LOCK_IO(pACB->pScsiHost);
	pSRB = pACB->pActiveDCB->pActiveSRB;
	TRACEPRINTF("N/TO *");
	DC395x_Disconnect (pACB);
	DC395x_UNLOCK_IO(pACB->pScsiHost);
}	
#endif

/*
**********************************************************************
** scsiio
**		DC395x_DoWaitingSRB    DC395x_SRBdone 
**		DC395x_SendSRB         DC395x_RequestSense
**
**
**
*********************************************************************
*/
BYTE DC395x_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
{
    WORD   s_stat2, return_code;
    BYTE   s_stat, scsicommand, i, identify_message;
    PBYTE  ptr;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_StartSCSI..............\n ");
#endif
    pSRB->TagNumber = TAG_NONE;	/* pACB->TagMaxNum: had error read in eeprom */

    s_stat = DC395x_read8 (TRM_S1040_SCSI_SIGNAL); s_stat2 = 0;
    s_stat2 = DC395x_read16 (TRM_S1040_SCSI_STATUS);	
    TRACEPRINTF("Start %02x *", s_stat);
#if 1
    if (s_stat & 0x20/* s_stat2 & 0x02000 */)
    {
#ifdef DC395x_DEBUG_KG	    
	printk ("DC395x: Debug: StartSCSI: pid %li(%02i-%i): BUSY %02x %04x\n",
		       pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN, s_stat, s_stat2);
#endif
	/* Try anyway? */
	/* We could, BUT: Sometimes the TRM_S1040 misses to produce a Selection
	 * Timeout, a Disconnect or a Reselction IRQ, so we would be screwed!
	 * (This is likely to be a bug in the hardware. Obviously, most people
	 *  only have one initiator per SCSI bus.)
	 * Instead let this fail and have the timer make sure the command is 
	 * tried again after a short time */
        TRACEPRINTF ("^*");
	//DC395x_selto_timer (pACB);
	//DC395x_monitor_next_IRQ = 1;
	return 1;
    };
#endif
    if (pACB->pActiveDCB)
    {
	printk ("DC395x: We try to start a SCSI command (%li)!\n", pSRB->pcmd->pid);
	printk ("DC395x: While another one (%li) is active!!\n", 
		(pACB->pActiveDCB->pActiveSRB? pACB->pActiveDCB->pActiveSRB->pcmd->pid: 0));
	TRACEOUT (" %s\n", pSRB->debugtrace);
	if (pACB->pActiveDCB->pActiveSRB)
		TRACEOUT (" %s\n", pACB->pActiveDCB->pActiveSRB->debugtrace);
	return 1;
    }
    if( DC395x_read16(TRM_S1040_SCSI_STATUS ) & SCSIINTERRUPT )
    {
#ifdef DC395x_DEBUG_KG
	printk ("DC395x: Debug: StartSCSI failed (busy) for pid %li(%02i-%i)\n",
		       pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN);
#endif
        TRACEPRINTF ("°*");
	return 1;
    }
    /* Allow starting of SCSI commands half a second before we allow the mid-level
     * to queue them again after a reset */
    if (time_before (jiffies, pACB->pScsiHost->last_reset - HZ/2))
    {
#ifdef DC395x_DEBUG_KG
	printk ("DC395x: We were just reset and don't accept commands yet!\n");
#endif
	return 1;
    }
	    
    /* Flush FIFO */
    DC395x_clrfifo (pACB, "Start");
    DC395x_write8(TRM_S1040_SCSI_HOSTID,pACB->pScsiHost->this_id);
    DC395x_write8(TRM_S1040_SCSI_TARGETID,pDCB->TargetID);
    DC395x_write8(TRM_S1040_SCSI_SYNC,pDCB->SyncPeriod);
    DC395x_write8(TRM_S1040_SCSI_OFFSET,pDCB->SyncOffset);
    pSRB->ScsiPhase = PH_BUS_FREE;/* initial phase */

    identify_message = pDCB->IdentifyMsg;
    //DC395x_TRM_write8(TRM_S1040_SCSI_IDMSG, identify_message);
    /* Don't allow disconnection for AUTO_REQSENSE: Cont.All.Cond.! */
    if (pSRB->SRBFlag & AUTO_REQSENSE)
	identify_message &= 0xBF;

    if( ( (pSRB->pcmd->cmnd[0] == INQUIRY) || (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) )
        && ( ((pDCB->SyncMode & WIDE_NEGO_ENABLE) && !(pDCB->SyncMode & WIDE_NEGO_DONE))
	     || ((pDCB->SyncMode & SYNC_NEGO_ENABLE) && !(pDCB->SyncMode & SYNC_NEGO_DONE)) )
        && (pDCB->TargetLUN == 0) )
	{
		pSRB->MsgOutBuf[0] = identify_message; pSRB->MsgCnt = 1;
		scsicommand = SCMD_SEL_ATNSTOP;
		pSRB->SRBState = SRB_MSGOUT;
#ifndef SYNC_FIRST		
		if (pDCB->SyncMode & WIDE_NEGO_ENABLE && 
		    pDCB->Inquiry7 & SCSI_INQ_WBUS16)
		{
			DC395x_Build_WDTR (pACB, pDCB, pSRB);
			goto no_cmd;
		}
#endif
		if (pDCB->SyncMode & SYNC_NEGO_ENABLE && 
		    pDCB->Inquiry7 & SCSI_INQ_SYNC)
		{
			DC395x_Build_SDTR (pACB, pDCB, pSRB);
			goto no_cmd;
		}
		if (pDCB->SyncMode & WIDE_NEGO_ENABLE && 
		    pDCB->Inquiry7 & SCSI_INQ_WBUS16)
		{
			DC395x_Build_WDTR (pACB, pDCB, pSRB);
			goto no_cmd;
		}
		pSRB->MsgCnt = 0;
	}
    /* 
     ** Send identify message	
     */
    DC395x_write8(TRM_S1040_SCSI_FIFO,identify_message);

    scsicommand = SCMD_SEL_ATN;
    pSRB->SRBState = SRB_START_;
#ifndef DC395x_NO_TAGQ
    if ((pDCB->SyncMode & EN_TAG_QUEUEING) && (identify_message & 0x40))
    {
	    /* Send Tag message	*/
	    DWORD  tag_mask = 1;
	    BYTE tag_number = 0;
	    while( tag_mask & pDCB->TagMask && tag_number <= pDCB->MaxCommand)
	    {
		tag_mask = tag_mask << 1;
		tag_number++;
	    }
	    if (tag_number >= pDCB->MaxCommand)
	    {
		printk (KERN_WARNING "DC395x: Start_SCSI: Out of tags for pid %li (%i-%i)\n", 
			pSRB->pcmd->pid, pSRB->pcmd->target, pSRB->pcmd->lun);
		pSRB->SRBState = SRB_READY;
		DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_HWRESELECT);
		return 1;
	    };
	    /* 
	     ** Send Tag id
	     */
	    DC395x_write8(TRM_S1040_SCSI_FIFO,MSG_SIMPLE_QTAG);
	    DC395x_write8(TRM_S1040_SCSI_FIFO,tag_number);
	    pDCB->TagMask |= tag_mask;
	    pSRB->TagNumber = tag_number;
	    TRACEPRINTF("Tag %i *", tag_number);

	    scsicommand = SCMD_SEL_ATN3;
	    pSRB->SRBState = SRB_START_;
	}
#endif
//polling:
    /*
    ** 	 Send CDB ..command block .........			
    */
#ifdef DC395x_DEBUG_KG
    printk (KERN_INFO "DC395x: StartSCSI (pid %li) %02x (%i-%i): Tag %i\n",
	    pSRB->pcmd->pid, pSRB->pcmd->cmnd[0], pSRB->pcmd->target,
	    pSRB->pcmd->lun, pSRB->TagNumber);
#endif
    if( pSRB->SRBFlag & AUTO_REQSENSE )
    {
	DC395x_write8(TRM_S1040_SCSI_FIFO,REQUEST_SENSE);
	DC395x_write8(TRM_S1040_SCSI_FIFO,(pDCB->TargetLUN << 5));
	DC395x_write8(TRM_S1040_SCSI_FIFO,0);
	DC395x_write8(TRM_S1040_SCSI_FIFO,0);
	DC395x_write8(TRM_S1040_SCSI_FIFO,sizeof(pSRB->pcmd->sense_buffer));
	DC395x_write8(TRM_S1040_SCSI_FIFO,0);
    }
    else
    {
	ptr = (PBYTE) pSRB->pcmd->cmnd;
	for(i=0; i < pSRB->pcmd->cmd_len; i++)
	    DC395x_write8(TRM_S1040_SCSI_FIFO, *ptr++);
    }
no_cmd:	
    DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH);
    if( DC395x_read16(TRM_S1040_SCSI_STATUS ) & SCSIINTERRUPT )
    {
	/* 
	** If DC395x_StartSCSI return 1:
	** we caught an interrupt (must be reset or reselection ... )
	** : Let's process it first!
	*/
	DEBUG0(printk ("DC395x: Debug: StartSCSI failed (busy) for pid %li(%02i-%i)!\n", 
		       pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN);)
        //DC395x_clrfifo (pACB, "Start2");
	//DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH);
	pSRB->SRBState = SRB_READY;
	DC395x_freetag (pDCB, pSRB);
	pSRB->MsgCnt = 0;
	return_code = 1;
	/* This IRQ should NOT get lost, as we did not acknowledge it */
    }
    else
    {
	/* 
	** If DC395x_StartSCSI returns 0:
	** we know that the SCSI processor is free
	*/

	pSRB->ScsiPhase  = PH_BUS_FREE;/* initial phase */
	pDCB->pActiveSRB = pSRB;
	pACB->pActiveDCB = pDCB;
	return_code = 0;
	/* it's important for atn stop */
	DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH | DO_HWRESELECT);
	/*
	** SCSI command
	*/
	TRACEPRINTF ("%02x *", scsicommand);
	DC395x_write8 (TRM_S1040_SCSI_COMMAND, scsicommand);
    }
    return( return_code );
}

/*
*********************************************************************
** scsiio
**		DC395x_initAdapter
**
*********************************************************************
*/
//inline 
void DC395x_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
{
    PACB        pACB;
    PDCB        pDCB;
    PSRB        pSRB;
    WORD        phase,i,scsi_status=0;
    void        (*DC395x_stateV)( PACB, PSRB, PWORD );
    BYTE        scsi_intstatus, dma_status;
    DWORD	flags;
    //DWORD           acb_flags=0,drv_flags=0;
    pACB = DC395x_pACB_start;
    if( pACB == NULL )
	return;
    
#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_Interrupt..............\n ");
#endif
	
    if( pACB == NULL )
    {
	printk(KERN_WARNING "DC395x: Interrupt on uninitialized pACB!\n");
	return;
    }

    DEBUGRECURSION(if (in_driver++ > NORM_REC_LVL) printk ("DC395x: %i interrupt recursion?\n", in_driver);)
	
    //DC395x_DRV_LOCK(drv_flags);

    for( i=0; i < DC395x_adapterCnt; i++ )
    { 
	/* 
	** find mach correct pACB with same IRQLevel 
	** and request SCSI interrupt service
	** :...search which pACB->IRQLevel is matching with irq 
	*/
	if( pACB->IRQLevel == (BYTE) irq )
	{
	    scsi_status = DC395x_read16(TRM_S1040_SCSI_STATUS );
	    dma_status = DC395x_read8 (TRM_S1040_DMA_STATUS);
	    if( scsi_status & SCSIINTERRUPT )
		break;  
	    if (dma_status & 0x20)
	    {
		    printk ("DC395x: Interrupt from DMA engine: %02x!\n", dma_status);
#if 0
		    printk ("DC395x: This means DMA error! Try to handle ...\n");
		    if (pACB->pActiveDCB)
		    {
			    pACB->pActiveDCB->DCBFlag |= ABORT_DEV_;
			    if (pACB->pActiveDCB->pActiveSRB)
				    DC395x_EnableMsgOut_Abort (pACB, pACB->pActiveDCB->pActiveSRB);
		    }
		    DC395x_write8 (TRM_S1040_DMA_CONTROL, ABORTXFER | CLRXFIFO);
		    break;
#else
		    printk ("DC395x: Ignore and hope for the best ...\n");
		    pACB = (PACB)-1;
		    break;
#endif
	    }
	    else
		pACB = pACB->pNextACB;
	}
	else
	    pACB = pACB->pNextACB;
    }
    //DC395x_DRV_UNLOCK(drv_flags);

    if( pACB == (PACB)-1 )
    {
	//printk("DC395x_Interrupt: Spurious interrupt detected!\n");
	goto out;
    }
    DC395x_LOCK_IO(pACB->pScsiHost);

    /* This acknowledges the IRQ */
    scsi_intstatus = DC395x_read8(TRM_S1040_SCSI_INTSTATUS );
    if ((scsi_status & 0x2007) == 0x2002)
	printk ("DC395x: COP after COP completed? %04x\n", scsi_status);
#if 1//def DC395x_DEBUG0
    if (DC395x_monitor_next_IRQ) {
	    printk(KERN_INFO "DC395x: status=%04x intstatus=%02x\n", scsi_status, scsi_intstatus);
	    DC395x_monitor_next_IRQ--;
    }
#endif
    //DC395x_ACB_LOCK(pACB,acb_flags);
#ifdef DC395x_DEBUG_KG	
    if (scsi_intstatus & INT_SELTIMEOUT)
	printk (KERN_INFO "DC395x: Sel Timeout IRQ\n");
#endif
    //printk ("DC395x_IRQ: intstatus = %02x ", scsi_intstatus);

    if (timer_pending (&pACB->SelTO_Timer))
	    del_timer (&pACB->SelTO_Timer);

    if(scsi_intstatus &  (INT_SELTIMEOUT | INT_DISCONNECT))
    {
	DC395x_Disconnect( pACB );/* bus free interrupt  */
	goto out_unlock;
    }
    if(scsi_intstatus &  INT_RESELECTED)
    {
	DC395x_Reselect( pACB );
	goto out_unlock;
    }
    if(scsi_intstatus & INT_SELECT)
    {
	printk (KERN_INFO "DC395x: Host does not support target mode!\n");
	goto out_unlock;
    }
    if(scsi_intstatus &  INT_SCSIRESET)
    {
	DC395x_ScsiRstDetect( pACB );
	goto out_unlock;
    }
    if( scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE) )
    {
	pDCB = pACB->pActiveDCB;
	if (!pDCB) {
		printk ("DC395x: Oops: BusService (%04x %02x) w/o ActiveDCB!\n",
			scsi_status, scsi_intstatus);
		goto out_unlock;
	}
	pSRB = pDCB->pActiveSRB;
	if( pDCB->DCBFlag & ABORT_DEV_ )
	{
#ifdef DC395x_DEBUG0
		printk(KERN_INFO "MsgOut Abort Device..... ");
#endif
		DC395x_EnableMsgOut_Abort( pACB, pSRB );
	}
	/*
	 ************************************************************
	 **              software sequential machine
	 ************************************************************
	 */
	phase = (WORD) pSRB->ScsiPhase;
	/* 
	** 62037 or 62137
	** call  DC395x_SCSI_phase0[]... "phase entry"
	** handle every phase before start transfer
	*/
	/* DC395x_DataOutPhase0,     phase:0 */
	/* DC395x_DataInPhase0,      phase:1 */
	/* DC395x_CommandPhase0,     phase:2 */
	/* DC395x_StatusPhase0,      phase:3 */
	/* DC395x_Nop0,              phase:4 PH_BUS_FREE .. initial phase */
	/* DC395x_Nop0,              phase:5 PH_BUS_FREE .. initial phase */
	/* DC395x_MsgOutPhase0,      phase:6 */
	/* DC395x_MsgInPhase0,       phase:7 */
	DC395x_stateV = (void *) DC395x_SCSI_phase0[phase];
	DC395x_stateV( pACB, pSRB, &scsi_status );
	/* 
	**$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 
	**
	**        if there were any exception occured
	**        scsi_status will be modify to bus free phase
	** new scsi_status transfer out from ... previous DC395x_stateV
	**
	**$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 
	*/ 
	pSRB->ScsiPhase = scsi_status & PHASEMASK;
	phase = (WORD) scsi_status & PHASEMASK;
	/* 
	** call  DC395x_SCSI_phase1[]... "phase entry"
	** handle every phase do transfer
	*/
	/* DC395x_DataOutPhase1,     phase:0 */
	/* DC395x_DataInPhase1,      phase:1 */
	/* DC395x_CommandPhase1,     phase:2 */
	/* DC395x_StatusPhase1,      phase:3 */
	/* DC395x_Nop1,              phase:4 PH_BUS_FREE .. initial phase */
	/* DC395x_Nop1,              phase:5 PH_BUS_FREE .. initial phase */
	/* DC395x_MsgOutPhase1,      phase:6 */
	/* DC395x_MsgInPhase1,       phase:7 */
	DC395x_stateV = (void *) DC395x_SCSI_phase1[phase];
	DC395x_stateV( pACB, pSRB, &scsi_status );
    }
 out_unlock:
    DC395x_UNLOCK_IO(pACB->pScsiHost);
 out:	
    DEBUGRECURSION(in_driver--;)
    //printk ("... done\n");
    //DC395x_ACB_UNLOCK(pACB,acb_flags);
    return;
}
#if 0
/*
*********************************************************************
** scsiio
**		DC395x_initAdapter
**		do_DC395x_Interrupt
**
*********************************************************************
*/
void do_DC395x_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
{
    //if( cpuid != 0 )
    //	return;
    //DC395x_LOCK_IO(pACB->pScsiHost);
    DC395x_Interrupt(irq, dev_id, regs);
    //DC395x_UNLOCK_IO(pACB->pScsiHost);
}
#endif
/*
*********************************************************************
** scsiio
**	DC395x_MsgOutPhase0: one of DC395x_SCSI_phase0[] vectors
**	 DC395x_stateV = (void *) DC395x_SCSI_phase0[phase]
**			           if phase =6
**
**
*********************************************************************
*/
static void DC395x_MsgOutPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{
#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_MsgOutPhase0..... ");
#endif
    if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) )
    {
	*pscsi_status = PH_BUS_FREE;/*.. initial phase*/
    }
    DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/
    pSRB->SRBState &= ~SRB_MSGOUT;
    TRACEPRINTF ("MOP0 *");
}

/*
*********************************************************************
** scsiio
**	DC395x_MsgOutPhase1: one of DC395x_SCSI_phase0[] vectors
**	 DC395x_stateV = (void *) DC395x_SCSI_phase0[phase]
**					if phase =6	    
**
**
*********************************************************************
*/
static void DC395x_MsgOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{
    WORD    i;
    PBYTE   ptr;
    PDCB    pDCB;
	
#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_MsgOutPhase1..............\n ");
#endif
    TRACEPRINTF ("MOP1*");
    pDCB = pACB->pActiveDCB;
    DC395x_clrfifo (pACB, "MOP1");
    if( !(pSRB->SRBState & SRB_MSGOUT) )
    {
	pSRB->SRBState |= SRB_MSGOUT;
	printk ("DC395x: Debug: pid %li: MsgOut Phase unexpected.\n",
		pSRB->pcmd->pid); /* So what ? */
    }
    if (!pSRB->MsgCnt)
    {
	DEBUG0(printk ("DC395x: Debug: pid %li: NOP Msg (no output message there).\n",
		       pSRB->pcmd->pid);)
	DC395x_write8( TRM_S1040_SCSI_FIFO, MSG_NOP);
	DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/
	DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
	TRACEPRINTF ("\\*");
	TRACEOUT (" %s\n", pSRB->debugtrace);
	return;
    }
    ptr = (PBYTE) pSRB->MsgOutBuf;
    TRACEPRINTF("(*");
    //printk ("DC395x: Send msg: "); DC395x_printMsg (ptr, pSRB->MsgCnt);
    //printk ("DC395x: MsgOut: ");
    for(i=0; i < pSRB->MsgCnt ; i++) {
	TRACEPRINTF ("%02x *", *ptr);
	DC395x_write8 (TRM_S1040_SCSI_FIFO, *ptr++);
    }
    TRACEPRINTF(")*");
    pSRB->MsgCnt = 0;
    //printk ("\n");
    if( /*(pDCB->DCBFlag & ABORT_DEV_) && */ (pSRB->MsgOutBuf[0] == MSG_ABORT) )
	pSRB->SRBState = SRB_ABORT_SENT;

    //1.25
    //DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/
    /*
    ** SCSI command 
    */
    //TRACEPRINTF (".*");
    DC395x_write8(TRM_S1040_SCSI_COMMAND,  SCMD_FIFO_OUT);
}
/*
*********************************************************************
** scsiio
**	DC395x_CommandPhase0: one of DC395x_SCSI_phase0[] vectors
**	 DC395x_stateV = (void *) DC395x_SCSI_phase0[phase]
**				if phase =2 
**
**
*********************************************************************
*/
static void DC395x_CommandPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{
	TRACEPRINTF("COP0 *");
	//1.25
	//DC395x_clrfifo (pACB, COP0);
	DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
}
/*
*********************************************************************
** scsiio
**	DC395x_CommandPhase1: one of DC395x_SCSI_phase1[] vectors
**	 DC395x_stateV = (void *) DC395x_SCSI_phase1[phase]
**				if phase =2    	 
**
**
*********************************************************************
*/
static void DC395x_CommandPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{
    PDCB   pDCB;
    PBYTE  ptr;
    WORD   i;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_CommandPhase1..............\n ");
#endif
    TRACEPRINTF("COP1*");
    DC395x_clrfifo (pACB, "COP1");
    DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRATN);
    if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
    {
	ptr = (PBYTE) pSRB->pcmd->cmnd;
	for(i=0; i < pSRB->pcmd->cmd_len; i++)
	{  
	    DC395x_write8(TRM_S1040_SCSI_FIFO, *ptr);
	    ptr++;
	}
    }
    else
    {  
	DC395x_write8(TRM_S1040_SCSI_FIFO, REQUEST_SENSE);
	pDCB = pACB->pActiveDCB;
	/* target id */
	DC395x_write8(TRM_S1040_SCSI_FIFO, (pDCB->TargetLUN << 5));
	DC395x_write8(TRM_S1040_SCSI_FIFO, 0);
	DC395x_write8(TRM_S1040_SCSI_FIFO, 0);
	DC395x_write8(TRM_S1040_SCSI_FIFO, sizeof(pSRB->pcmd->sense_buffer));
	DC395x_write8(TRM_S1040_SCSI_FIFO, 0);
    }
    pSRB->SRBState |= SRB_COMMAND;
    /* it's important for atn stop */
    DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
    /* SCSI command */
    TRACEPRINTF(".*");
    DC395x_write8(TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
}

/* Do sanity checks for S/G list */
#ifdef DC395x_SGPARANOIA 
static inline void DC395x_check_SG (PSRB pSRB)
{
	unsigned Length = 0;
	unsigned Idx = pSRB->SRBSGIndex;
	PSGE0 psge = pSRB->SegmentX + Idx;
	for ( ; Idx < pSRB->SRBSGCount; psge++, Idx++)
		Length += psge->length;
	if (Length != pSRB->SRBTotalXferLength)
		printk ("DC395x: Inconsistent SRB S/G lengths (Tot=%i, Count=%i) !!\n",
			pSRB->SRBTotalXferLength, Length);
};
#else
static inline void DC395x_check_SG (PSRB pSRB) {};
#endif

#if 0
/* Check DMA to SCSI block consistency */
static void DC395x_check_SG_TX (PSRB pSRB, DWORD tx)
{
	PACB  pACB = pSRB->pSRBDCB->pDCBACB;
	DWORD len = 0;
	PSGE0 psge = pSRB->SegmentX + pSRB->SRBSGIndex;
	unsigned dma_idx = DC395x_read32 (TRM_S1040_DMA_CXCNT) >> 3;
	while (dma_idx-- > 0) { len += psge->length; psge++; }
	if (tx < len || tx > (len + psge->length))
		printk (KERN_DEBUG "DC395x: DMA read between %i and %i bytes, SCSI read %i!!\n",
			len, len + psge->length, tx);
	else
		printk (KERN_DEBUG "DC395x: Congrats: DMA (%i--%i) and SCSI (%i) agree on transferred data!\n",
			len, len + psge->length, tx);
}
#endif

/* Compute the next Scatter Gather list index and adjust its length
 * and address if necessary; also compute virt_addr */
void DC395x_update_SGlist (PSRB pSRB, DWORD Left)
{
	PSGE0 psge;
	DWORD Xferred = 0;
	BYTE  Idx;
	PSCSICMD pcmd = pSRB->pcmd;
	struct scatterlist *sg;
	int segment = pcmd->use_sg;
	
#ifdef DC395x_DEBUG_KG
	printk ("DC395x: Update SG: Total %i, Left %i\n",
		pSRB->SRBTotalXferLength, Left);
#endif
	DC395x_check_SG (pSRB);
	psge = pSRB->SegmentX + pSRB->SRBSGIndex;
	/* data that has already been transferred */
	Xferred = pSRB->SRBTotalXferLength - Left;
	if (pSRB->SRBTotalXferLength != Left)
	{
		//DC395x_check_SG_TX (pSRB, Xferred);
		/* Remaining */
		pSRB->SRBTotalXferLength = Left;
		/* parsing from last time disconnect SGIndex */
		for ( Idx = pSRB->SRBSGIndex; Idx < pSRB->SRBSGCount ; Idx++)
		{
			/* Complete SG entries done */
			if (Xferred >= psge->length)
				Xferred -= psge->length;
			/* Partial SG entries done */
			else
			{
				psge->length  -= Xferred;	/* residue data length  */
				psge->address += Xferred;	/* residue data pointer */
				pSRB->SRBSGIndex = Idx;
				PCI_DMA_SYNC_SINGLE(pSRB->pSRBDCB->pDCBACB->pdev,
						    pSRB->SRBSGBusAddr,
						    sizeof(SGentry)*DC395x_MAX_SG_LISTENTRY,
						    PCI_DMA_TODEVICE);
				break;
			} 
			psge++;
		}
		DC395x_check_SG (pSRB);
	}
	/* We need the corresponding virtual address sg_to_virt */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,16)
	pSRB->virt_addr = bus_to_virt (psge->address);
	return;
#else
	//printk ("DC395x: sg_to_virt: bus %08x -> virt ", psge->address);
	if (!segment) {
		pSRB->virt_addr += Xferred;
		//printk ("%p\n", pSRB->virt_addr);
		return;
	}
	/* We have to walk the scatterlist to find it */
	sg = (struct scatterlist*) pcmd->request_buffer;
	while (segment--) {
		//printk ("(%08x)%p ", BUS_ADDR(*sg), PAGE_ADDRESS(sg));
		unsigned long mask = ~((unsigned long)sg->length-1) & PAGE_MASK;
		if ((BUS_ADDR(*sg) & mask) == (psge->address & mask)) {
			pSRB->virt_addr = (PAGE_ADDRESS(sg) 
					   + psge->address - (psge->address & PAGE_MASK));
			//printk ("%p\n", pSRB->virt_addr);
			return;
		}
		++sg;
	}
	printk ("DC395x: sg_to_virt failed!\n");
	pSRB->virt_addr = 0;
#endif
}

 /* 
  * DC395x_cleanup_after_transfer
  * 
  * Makes sure, DMA and SCSI engine are empty, after the transfer has finished
  * KG: Currently called from  StatusPhase1 ()
  * Should probably also be called from other places
  * Best might be to call it in DataXXPhase0, if new phase will differ 
  */
static void DC395x_cleanup_after_transfer (PACB pACB, PSRB pSRB)
{
	TRACEPRINTF (" Cln*");
	//DC395x_write8 (TRM_S1040_DMA_STATUS, FORCEDMACOMP);
	if (DC395x_read16(TRM_S1040_DMA_COMMAND) & 0x0001)
	{	/* read */
		if (!(DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x40))
			DC395x_clrfifo (pACB, "ClnIn");
		
		if (!(DC395x_read8(TRM_S1040_DMA_FIFOSTAT) & 0x80))
			DC395x_write8(TRM_S1040_DMA_CONTROL, CLRXFIFO);
	}
	else
	{	/* write */
		if (!(DC395x_read8(TRM_S1040_DMA_FIFOSTAT) & 0x80))
			DC395x_write8(TRM_S1040_DMA_CONTROL, CLRXFIFO);
		
		if (!(DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x40))
			DC395x_clrfifo (pACB, "ClnOut");
		
	}
	//1.25
	DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
}

  
/* Those no of bytes will be transfered w/ PIO through the SCSI FIFO   *
 * Seems to be needed for unknown reasons; could be a hardware bug :-( */
#define DC395x_LASTPIO 4
/*
 *********************************************************************
 ** scsiio
 **	DC395x_DataOutPhase0: one of DC395x_SCSI_phase0[] vectors
 **	 DC395x_stateV = (void *) DC395x_SCSI_phase0[phase]
 **				if phase =0 
 **
 **
 *********************************************************************
 */
void DC395x_DataOutPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{
    WORD    scsi_status;
    DWORD   dLeftCounter = 0;
    PDCB    pDCB = pSRB->pSRBDCB;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_DataOutPhase0.....\n ");
#endif
    TRACEPRINTF("DOP0*");
    pDCB = pSRB->pSRBDCB;
    scsi_status = *pscsi_status;

    /*
     * KG: We need to drain the buffers before we draw any conclusions!
     * This means telling the DMA to push the rest into SCSI, telling
     * SCSI to push the rest to the bus.
     * However, the device might have been the one to stop us (phase
     * change), and the data in transit just needs to be accounted so
     * it can be retransmitted.)
     */
    /* 
     * KG: Stop DMA engine pushing more data into the SCSI FIFO
     * If we need more data, the DMA SG list will be freshly set up, anyway
     */
#ifdef DC395x_DEBUGPIO
    printk ("DC395x: DOP0: DMA_FCNT: %02x, DMA_FSTAT: %02x, SCSI_FCNT: %02x, CTR %06x, stat %04x, Tot: %06x\n",
	    DC395x_read8  (TRM_S1040_DMA_FIFOCNT),
	    DC395x_read8  (TRM_S1040_DMA_FIFOSTAT),
	    DC395x_read8  (TRM_S1040_SCSI_FIFOCNT), 
	    DC395x_read32 (TRM_S1040_SCSI_COUNTER), 
	    scsi_status, pSRB->SRBTotalXferLength);
    //DC395x_dumpinfo(pACB, pDCB, pSRB);
#endif
    DC395x_write8 (TRM_S1040_DMA_CONTROL, STOPDMAXFER | CLRXFIFO);

    if( !(pSRB->SRBState & SRB_XFERPAD) )
    {
	if( scsi_status & PARITYERROR )
	    pSRB->SRBStatus |= PARITY_ERROR;

	/* KG: Right, we can't just rely on the SCSI_COUNTER, because this
	 * is the no of bytes it got from the DMA engine not the no it 
	 * transferred successfully to the device. (And the difference could
	 * be as much as the FIFO size, I guess ...) */
	if (!(scsi_status & SCSIXFERDONE))
	{
	    /*
	    ** when data transfer from DMA FIFO to SCSI FIFO
	    ** if there was some data left in SCSI FIFO
	    */
	    dLeftCounter = (DWORD) (DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x1F);
	    if (pDCB->SyncPeriod & WIDE_SYNC)
		dLeftCounter <<= 1;
	    
#ifdef DC395x_DEBUG_KG		
	    printk ("DC395x: Debug: SCSI FIFO contains %i %s in DOP0\n",
		    DC395x_read8(TRM_S1040_SCSI_FIFOCNT), 
		    (pDCB->SyncPeriod & WIDE_SYNC)? "words": "bytes");
	    printk ("DC395x: SCSI FIFOCNT %02x, SCSI CTR %08x\n",
		    DC395x_read8 (TRM_S1040_SCSI_FIFOCNT),
		    DC395x_read32 (TRM_S1040_SCSI_COUNTER));
	    printk ("DC395x: DMA FIFOCNT %04x, FIFOSTAT %02x, DMA CTR %08x\n",
		    DC395x_read8  (TRM_S1040_DMA_FIFOCNT),
		    DC395x_read8  (TRM_S1040_DMA_FIFOSTAT),
		    DC395x_read32 (TRM_S1040_DMA_CXCNT));
#endif
	    /*
	     ** if WIDE scsi SCSI FIFOCNT unit is word !!!
	     ** so need to *= 2
	     */
	}
	/*
	** calculate all the residue data that not yet tranfered
	** SCSI transfer counter + left in SCSI FIFO data
	**
	** .....TRM_S1040_SCSI_COUNTER (24bits)
	** The counter always decrement by one for every SCSI byte transfer.
	** .....TRM_S1040_SCSI_FIFOCNT ( 5bits)
	** The counter is SCSI FIFO offset counter (in units of bytes or! words)
	*/
	if (pSRB->SRBTotalXferLength > DC395x_LASTPIO)
		dLeftCounter += DC395x_read32(TRM_S1040_SCSI_COUNTER);
	TRACEPRINTF ("%06x *", dLeftCounter);
	
	/* Is this a good idea? */
	//DC395x_clrfifo (pACB, "DOP1");
	/* KG: What is this supposed to be useful for? WIDE padding stuff? */
	if ( dLeftCounter == 1 && 
	     pDCB->SyncPeriod & WIDE_SYNC && 
	     pSRB->pcmd->request_bufflen % 2)
	{
	    dLeftCounter = 0;
	    printk ("DC395x: DOP0: Discard 1 byte. (%02x)\n", scsi_status);
	}
	/* KG: Oops again. Same thinko as above: The SCSI might have been
	 * faster than the DMA engine, so that it ran out of data.
	 * In that case, we have to do just nothing! 
	 * But: Why the interrupt: No phase change. No XFERCNT_2_ZERO. Or? */
	 
	/* KG: This is nonsense: We have been WRITING data to the bus
	 * If the SCSI engine has no bytes left, how should the DMA engine? */
	if ((dLeftCounter == 0) /*|| (scsi_status & SCSIXFERCNT_2_ZERO) )*/)
	{   /*
	    int ctr = 6000000; BYTE TempDMAstatus;
	    do
	    {
		TempDMAstatus = DC395x_read8(TRM_S1040_DMA_STATUS);
	    } while( !(TempDMAstatus & DMAXFERCOMP) && --ctr);
	    if (ctr < 6000000-1) printk ("DC395x: DMA should be complete ... in DOP1\n");
	    if (!ctr) printk (KERN_ERR "DC395x: Deadlock in DataOutPhase0 !!\n");
	     */
	    pSRB->SRBTotalXferLength = 0;
	}
	else  /* Update SG list		*/
	{
	    /*
	    ** if transfer not yet complete
	    ** there were some data residue in SCSI FIFO or
	    ** SCSI transfer counter not empty
	    */
	    long    oldXferred = pSRB->SRBTotalXferLength - dLeftCounter;
	    const int diff = (pDCB->SyncPeriod & WIDE_SYNC)? 2: 1;
	    DC395x_update_SGlist (pSRB, dLeftCounter);
	    /* KG: Most ugly hack! Apparently, this works around a chip bug */
	    if ( (pSRB->SegmentX[pSRB->SRBSGIndex].length == diff && pSRB->pcmd->use_sg)
		|| ((oldXferred & ~PAGE_MASK) == (PAGE_SIZE-diff))
		) {
		    printk ("DC395x: Work around chip bug (%i)?\n", diff);
		    dLeftCounter = pSRB->SRBTotalXferLength - diff;
		    DC395x_update_SGlist (pSRB, dLeftCounter);
		    //pSRB->SRBTotalXferLength -= diff;
		    //pSRB->virt_addr += diff;
		    //if (pSRB->pcmd->use_sg)
		    //	    pSRB->SRBSGIndex++;
	    }
	}
    }
#if 0
    if (!(DC395x_read8 (TRM_S1040_SCSI_FIFOCNT) &  0x40))
	printk ("DC395x: DOP0(%li): %i bytes in SCSI FIFO! (Clear!)\n",
		pSRB->pcmd->pid, DC395x_read8 (TRM_S1040_SCSI_FIFOCNT) & 0x1f);
#endif
    //DC395x_clrfifo (pACB, "DOP0");
    //DC395x_write8 (TRM_S1040_DMA_CONTROL, CLRXFIFO | ABORTXFER);
#if 1
    if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT) {
	//printk ("DC395x: Debug: Clean up after Data Out ...\n");
	DC395x_cleanup_after_transfer (pACB, pSRB);
    }
#endif
    TRACEPRINTF(".*");
}
/*
*********************************************************************
** scsiio
**	DC395x_DataOutPhase1: one of DC395x_SCSI_phase0[] vectors
**	 DC395x_stateV = (void *) DC395x_SCSI_phase0[phase]
**				if phase =0    
**
**		62037
*********************************************************************
*/
static void DC395x_DataOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_DataOutPhase1.....\n");
#endif
    //1.25
    TRACEPRINTF("DOP1*");
    DC395x_clrfifo (pACB, "DOP1");
    /*
    ** do prepare befor transfer when data out phase
    */
    DC395x_DataIO_transfer (pACB, pSRB, XFERDATAOUT);
    TRACEPRINTF(".*");
}


/*
*********************************************************************
** scsiio
**	DC395x_DataInPhase0: one of DC395x_SCSI_phase1[] vectors
**	 DC395x_stateV = (void *) DC395x_SCSI_phase1[phase]
**				if phase =1  
**
**
*********************************************************************
*/
void DC395x_DataInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{
    WORD   scsi_status;
    DWORD  dLeftCounter = 0;
    //PDCB   pDCB = pSRB->pSRBDCB;
    //BYTE bval;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_DataInPhase0..............\n ");
#endif
    TRACEPRINTF("DIP0*");
    scsi_status = *pscsi_status;
	
    /* KG: DataIn is much more tricky than DataOut. When the device is finished
     * and switches to another phase, the SCSI engine should be finished too.
     * But: There might still be bytes left in its FIFO to be fetched by the DMA
     * engine and transferred to memory.
     * We should wait for the FIFOs to be emptied by that (is there any way to 
     * enforce this?) and then stop the DMA engine, because it might think, that
     * there are more bytes to follow. Yes, the device might disconnect prior to
     * having all bytes transferred! 
     * Also we should make sure that all data from the DMA engine buffer's really
     * made its way to the system memory! Some documentation on this would not
     * seem to be a bad idea, actually.
     */

    if( !(pSRB->SRBState & SRB_XFERPAD) ) {
	if( scsi_status & PARITYERROR ) {
	    printk("DC395x: Parity Error (pid %li, target %02i-%i)\n", 
		   pSRB->pcmd->pid, pSRB->pcmd->target, pSRB->pcmd->lun);
	    pSRB->SRBStatus |= PARITY_ERROR;
	}
	// KG: We should wait for the DMA FIFO to be empty ...
	// but: it would be better to wait first for the SCSI FIFO and then the
	// the DMA FIFO to become empty? How do we know, that the device not already
	// sent data to the FIFO in a MsgIn phase, eg.?
	if (!(DC395x_read8 (TRM_S1040_DMA_FIFOSTAT) & 0x80)) {
#if 0
	    int ctr = 6000000;
	    printk ("DC395x: DIP0: Wait for DMA FIFO to flush ...\n");
	    //DC395x_write8  (TRM_S1040_DMA_CONTROL, STOPDMAXFER);
	    //DC395x_write32 (TRM_S1040_SCSI_COUNTER, 7);
	    //DC395x_write8  (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN);
	    while (!(DC395x_read16 (TRM_S1040_DMA_FIFOSTAT) & 0x80) && --ctr);
	    if (ctr < 6000000-1) printk ("DC395x: Debug: DIP0: Had to wait for DMA ...\n");
	    if (!ctr) printk (KERN_ERR "DC395x: Deadlock in DIP0 waiting for DMA FIFO empty!!\n");
	    //DC395x_write32 (TRM_S1040_SCSI_COUNTER, 0);
#endif
#ifdef DC395x_DEBUG_KG
	    printk ("DC395x: DIP0: DMA_FIFO: %02x %02x\n",
		    DC395x_read8 (TRM_S1040_DMA_FIFOCNT),
		    DC395x_read8 (TRM_S1040_DMA_FIFOSTAT));
#endif
	}
	/* Now: Check remainig data: The SCSI counters should tell us ... */
	dLeftCounter = DC395x_read32 (TRM_S1040_SCSI_COUNTER)
		     + ((DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x1f) 
		     << ((pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC)? 1: 0));
	    
#ifdef DC395x_DEBUG_KG		
	printk ("DC395x: Debug: SCSI FIFO contains %i %s in DIP0\n",
		DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x1f,
		(pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC)? "words": "bytes");
	printk ("DC395x: SCSI FIFOCNT %02x, SCSI CTR %08x\n",
		DC395x_read8 (TRM_S1040_SCSI_FIFOCNT),
		DC395x_read32 (TRM_S1040_SCSI_COUNTER));
	printk ("DC395x: DMA FIFOCNT %02x,%02x DMA CTR %08x\n",
		DC395x_read8  (TRM_S1040_DMA_FIFOCNT),
		DC395x_read8  (TRM_S1040_DMA_FIFOSTAT),
		DC395x_read32 (TRM_S1040_DMA_CXCNT));
	printk ("DC395x: Remaining: TotXfer: %i, SCSI FIFO+Ctr: %i\n",
		pSRB->SRBTotalXferLength, dLeftCounter);
#endif
#if DC395x_LASTPIO
	/* KG: Less than or equal to 4 bytes can not be transfered via DMA, it seems. */
	if (dLeftCounter && pSRB->SRBTotalXferLength <= DC395x_LASTPIO)
	{
		//DWORD addr = (pSRB->SegmentX[pSRB->SRBSGIndex].address);
		//DC395x_update_SGlist (pSRB, dLeftCounter);
		DEBUGPIO(
		printk ("DC395x: DIP0: PIO (%i %s) to %p for remaining %i bytes:",
			DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x1f, 
			(pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC)? "words": "bytes",
			pSRB->virt_addr, pSRB->SRBTotalXferLength);
		)
		
		if (pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC)
			DC395x_write8 (TRM_S1040_SCSI_CONFIG2, CFG2_WIDEFIFO);
			
		while (DC395x_read8(TRM_S1040_SCSI_FIFOCNT) != 0x40)
		{
			BYTE byte = DC395x_read8 (TRM_S1040_SCSI_FIFO);
			*(pSRB->virt_addr)++ = byte; DEBUGPIO(printk (" %02x", byte);)
			pSRB->SRBTotalXferLength--; dLeftCounter--;
			pSRB->SegmentX[pSRB->SRBSGIndex].length--;
			if (pSRB->SRBTotalXferLength && !pSRB->SegmentX[pSRB->SRBSGIndex].length) {
				DEBUGPIO(printk (" (next segment)");)
				pSRB->SRBSGIndex++;
				DC395x_update_SGlist (pSRB, dLeftCounter);
			}					  
		}
		if (pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC)
		{
#if 1 /* Read the last byte ... */
			if (pSRB->SRBTotalXferLength > 0)
			{ 
				BYTE byte = DC395x_read8 (TRM_S1040_SCSI_FIFO);
				*(pSRB->virt_addr)++ = byte;  pSRB->SRBTotalXferLength--; 
				DEBUGPIO(printk (" %02x", byte);)
			}
#endif			
			DC395x_write8 (TRM_S1040_SCSI_CONFIG2, 0);
		}			
		//printk (" %08x", *(DWORD*)(bus_to_virt (addr)));
		//pSRB->SRBTotalXferLength = 0;
		DEBUGPIO(printk ("\n");)
	}
#endif /* DC395x_LASTPIO */

#if 0
	// KG: This was in DATAOUT. Does it also belong here?
	// Nobody seems to know what counter and fifo_cnt count exactly ...
	if (!(scsi_status & SCSIXFERDONE))
	{
	    /*
	    ** when data transfer from DMA FIFO to SCSI FIFO
	    ** if there was some data left in SCSI FIFO
	    */
	    dLeftCounter = (DWORD) (DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x1F);
	    if (pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC)
		dLeftCounter <<= 1;
	    /*
	     ** if WIDE scsi SCSI FIFOCNT unit is word !!!
	     ** so need to *= 2
	     ** KG: Seems to be correct ...
	     */
	}
#endif

	//dLeftCounter += DC395x_read32(TRM_S1040_SCSI_COUNTER);
#if 0
	printk ("DC395x: DIP0: ctr=%08x, DMA_FIFO=%02x,%02x SCSI_FIFO=%02x\n",
		dLeftCounter, DC395x_read8 (TRM_S1040_DMA_FIFOCNT),
		DC395x_read8 (TRM_S1040_DMA_FIFOSTAT), DC395x_read8 (TRM_S1040_SCSI_FIFOCNT));
	printk ("DC395x: DIP0: DMAStat %02x\n",
		DC395x_read8 (TRM_S1040_DMA_STATUS));
#endif

	// KG: This should not be needed any more!
	if((dLeftCounter == 0) || (scsi_status & SCSIXFERCNT_2_ZERO) )
	{
#if 0		
	    int ctr = 6000000; 
	    BYTE   TempDMAstatus;
	    do {
		TempDMAstatus = DC395x_read8(TRM_S1040_DMA_STATUS);
	    } while( !(TempDMAstatus & DMAXFERCOMP) && --ctr);
	    if (!ctr) printk (KERN_ERR "DC395x: Deadlock in DataInPhase0 waiting for DMA!!\n");
	    pSRB->SRBTotalXferLength = 0;
#endif
#if 0 //def DC395x_DEBUG_KG		
	    printk ("DC395x: DIP0: DMA not yet ready: %02x: %i -> %i bytes\n",
		    DC395x_read8(TRM_S1040_DMA_STATUS), pSRB->SRBTotalXferLength, dLeftCounter);
#endif
	    pSRB->SRBTotalXferLength = dLeftCounter;
	}
	else	/* phase changed */
	{  
	    /*
	    ** parsing the case:
	    ** when a transfer not yet complete 
	    ** but be disconnected by target
	    ** if transfer not yet complete
	    ** there were some data residue in SCSI FIFO or
	    ** SCSI transfer counter not empty
	    */
	    DC395x_update_SGlist (pSRB, dLeftCounter);
	}
    }
    /* KG: The target may decide to disconnect: Empty FIFO before! */
    if ((*pscsi_status & PHASEMASK) != PH_DATA_IN) {
	//printk ("DC395x: Debug: Clean up after Data In  ...\n");
	DC395x_cleanup_after_transfer (pACB, pSRB);
    }

#if 0
    /* KG: Make sure, no previous transfers are pending! */
    bval = DC395x_read8 (TRM_S1040_SCSI_FIFOCNT);
    if (!(bval & 0x40))
    {
	bval &= 0x1f;
	printk ("DC395x: DIP0(%li): %i bytes in SCSI FIFO (stat %04x) (left %08x)!!\n",
		pSRB->pcmd->pid, bval & 0x1f, scsi_status, dLeftCounter);
	if((dLeftCounter == 0) || (scsi_status & SCSIXFERCNT_2_ZERO) ) {
		printk ("DC395x: Clear FIFO!\n");
		DC395x_clrfifo (pACB, "DIP0");
	}
    }
#endif
    //DC395x_write8 (TRM_S1040_DMA_CONTROL, CLRXFIFO | ABORTXFER);

    //DC395x_clrfifo (pACB, "DIP0");
    //DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
    TRACEPRINTF(".*");
}
/*
*********************************************************************
** scsiio
**	DC395x_DataInPhase1: one of DC395x_SCSI_phase0[] vectors
**	 DC395x_stateV = (void *) DC395x_SCSI_phase0[phase]
**				if phase =1 
**
**
*********************************************************************
*/
static void DC395x_DataInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{
#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_DataInPhase1..... ");
#endif
    /* FIFO should be cleared, if previous phase was not DataPhase */
    //DC395x_clrfifo (pACB, "DIP1");
    /* Allow data in! */
    //DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
    TRACEPRINTF("DIP1:*");
    /*
     ** do prepare before transfer when data in phase
     */
    DC395x_DataIO_transfer (pACB, pSRB, XFERDATAIN);
    TRACEPRINTF(".*");
}

/*
*********************************************************************
** scsiio
**		DC395x_DataOutPhase1
**		DC395x_DataInPhase1
**
*********************************************************************
*/
void DC395x_DataIO_transfer( PACB pACB, PSRB pSRB, WORD ioDir)
{
    BYTE   bval;
    PDCB   pDCB;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x: DataIO_transfer %c (pid %li): len = %i, SG: %i/%i\n",
	   ((ioDir & DMACMD_DIR)? 'r': 'w'), pSRB->pcmd->pid,
	   pSRB->SRBTotalXferLength, pSRB->SRBSGIndex, pSRB->SRBSGCount);
#endif
    TRACEPRINTF("%05x(%i/%i)*", pSRB->SRBTotalXferLength, 
		pSRB->SRBSGIndex, pSRB->SRBSGCount);
    pDCB = pSRB->pSRBDCB; 
    if (pSRB == pACB->pTmpSRB)
    {
	printk ("DC395x: ERROR! Using TmpSRB in DataPhase!\n");
    }
    if( pSRB->SRBSGIndex < pSRB->SRBSGCount )
    {
	if( pSRB->SRBTotalXferLength > DC395x_LASTPIO )
	{
	    BYTE dma_status = DC395x_read8 (TRM_S1040_DMA_STATUS);
	    /* KG: What should we do: Use SCSI Cmd 0x90/0x92? */
	    /* Maybe, even ABORTXFER would be appropriate */
	    if (dma_status & XFERPENDING) {
		printk ("DC395x: Xfer pending! Expect trouble!!\n");
		DC395x_dumpinfo (pACB, pDCB, pSRB);
	    	DC395x_write8 (TRM_S1040_DMA_CONTROL, CLRXFIFO);
	    }
	    //DC395x_clrfifo (pACB, "IO");
	    /* 
	    ** load what physical address of Scatter/Gather list table want to be
	    ** transfer 
	    */
	    pSRB->SRBState |= SRB_DATA_XFER;
	    DC395x_write32(TRM_S1040_DMA_XHIGHADDR, 0);
	    if (pSRB->pcmd->use_sg) { /* with S/G */
		    ioDir |= DMACMD_SG;
		    DC395x_write32(TRM_S1040_DMA_XLOWADDR, pSRB->SRBSGBusAddr + sizeof(SGentry)*pSRB->SRBSGIndex);
		    /* load how many bytes in the Scatter/Gather list table */
		    DC395x_write32(TRM_S1040_DMA_XCNT, ((DWORD) (pSRB->SRBSGCount - pSRB->SRBSGIndex) << 3));
	    } else { /* without S/G */
		    ioDir &= ~DMACMD_SG;
		    DC395x_write32(TRM_S1040_DMA_XLOWADDR, pSRB->SegmentX[0].address);
		    DC395x_write32(TRM_S1040_DMA_XCNT, pSRB->SegmentX[0].length);
	    }
	    /* load total transfer length (24bits) max value 16Mbyte */
	    DC395x_write32(TRM_S1040_SCSI_COUNTER, pSRB->SRBTotalXferLength);
	    DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/
	    if (ioDir & DMACMD_DIR) /* read */ {
		    DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN);
		    DC395x_write16(TRM_S1040_DMA_COMMAND,  ioDir);
	    } else {
		    DC395x_write16(TRM_S1040_DMA_COMMAND,  ioDir);
		    DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_OUT);
	    }
		    
	}
#if DC395x_LASTPIO
	else if (pSRB->SRBTotalXferLength > 0)
	{	/* The last four bytes: Do PIO */
	    //DC395x_clrfifo (pACB, "IO");
	    /* 
	    ** load what physical address of Scatter/Gather list table want to be
	    ** transfer 
	    */
	    pSRB->SRBState |= SRB_DATA_XFER;
	    /* load total transfer length (24bits) max value 16Mbyte */
	    DC395x_write32(TRM_S1040_SCSI_COUNTER, pSRB->SRBTotalXferLength);
	    DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/
	    if (ioDir & DMACMD_DIR) { /* read */
		    DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN);
	    } else { /* write */
		    int ln = pSRB->SRBTotalXferLength;
		    if (pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC)
			    DC395x_write8 (TRM_S1040_SCSI_CONFIG2, CFG2_WIDEFIFO);
		    DEBUGPIO(printk ("DC395x: DOP1: PIO %i bytes from %p:", 
				     pSRB->SRBTotalXferLength, pSRB->virt_addr);)
		    while (pSRB->SRBTotalXferLength)
		    {
			    DEBUGPIO(printk (" %02x", (unsigned char)*(pSRB->virt_addr));)
			    DC395x_write8 (TRM_S1040_SCSI_FIFO, *(pSRB->virt_addr)++);
			    pSRB->SRBTotalXferLength--;
			    pSRB->SegmentX[pSRB->SRBSGIndex].length--;
			    if (pSRB->SRBTotalXferLength && !pSRB->SegmentX[pSRB->SRBSGIndex].length) {
				    DEBUGPIO(printk (" (next segment)");)
				    pSRB->SRBSGIndex++;
				    DC395x_update_SGlist (pSRB, pSRB->SRBTotalXferLength);
			    }
		    }
		    if (pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC) {
			    if (ln % 2) {
				    DC395x_write8 (TRM_S1040_SCSI_FIFO, 0);
				    DEBUGPIO(printk (" |00");)
			    }
			    DC395x_write8 (TRM_S1040_SCSI_CONFIG2, 0);
		    }
		    //DC395x_write32(TRM_S1040_SCSI_COUNTER, ln);
		    DEBUGPIO(printk ("\n");)
		    DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
	    }
	}
#endif /* DC395x_LASTPIO */
	else    /* xfer pad */
	{
	    BYTE data = 0, data2 = 0;
	    if( pSRB->SRBSGCount )
	    {
		pSRB->AdaptStatus = H_OVER_UNDER_RUN;
		pSRB->SRBStatus |= OVER_RUN;
	    }
	    // KG: despite the fact that we are using 16 bits I/O ops
	    // the SCSI FIFO is only 8 bits according to the docs
	    // (we can set bit 1 in 0x8f to serialize FIFO access ...)
	    if (pDCB->SyncPeriod & WIDE_SYNC)
	    {
		DC395x_write32(TRM_S1040_SCSI_COUNTER, 2);
		DC395x_write8 (TRM_S1040_SCSI_CONFIG2, CFG2_WIDEFIFO);
		if (ioDir & DMACMD_DIR) /* read */ {
			data = DC395x_read8(TRM_S1040_SCSI_FIFO);
			data2 = DC395x_read8(TRM_S1040_SCSI_FIFO);
			//printk ("DC395x: DataIO: Xfer pad: %02x %02x\n", data, data2);
		} else { 
			/* Danger, Robinson: If you find KGs scattered over the wide
			 * disk, the driver or chip is to blame :-( */
			DC395x_write8 (TRM_S1040_SCSI_FIFO, 'K');
			DC395x_write8 (TRM_S1040_SCSI_FIFO, 'G');
		}
		DC395x_write8 (TRM_S1040_SCSI_CONFIG2, 0);
	    }
	    else
	    {
		DC395x_write32(TRM_S1040_SCSI_COUNTER, 1);
		/* Danger, Robinson: If you find a collection of Ks on your disk
		 * something broke :-( */
		if (ioDir & DMACMD_DIR) { /* read */
			data = DC395x_read8(TRM_S1040_SCSI_FIFO);
			//printk ("DC395x: DataIO: Xfer pad: %02x\n", data);
		} else {
			DC395x_write8(TRM_S1040_SCSI_FIFO, 'K');
		}
	    }
	    pSRB->SRBState |= SRB_XFERPAD;
	    DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/
	    /*
	    ** SCSI command 
	    */
	    bval = (ioDir & DMACMD_DIR) ?  SCMD_FIFO_IN : SCMD_FIFO_OUT;
	    DC395x_write8(TRM_S1040_SCSI_COMMAND, bval);
	}
    }
    //DC395x_monitor_next_IRQ = 2;
    //printk (" done\n");
}
/*
*********************************************************************
** scsiio
**	DC395x_StatusPhase0: one of DC395x_SCSI_phase0[] vectors
**	 DC395x_stateV = (void *) DC395x_SCSI_phase0[phase]
**				if phase =3  
**
**
*********************************************************************
*/
static void DC395x_StatusPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{
#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x: StatusPhase0 (pid %li)\n", pSRB->pcmd->pid);
#endif
    TRACEPRINTF("STP0 *");
    pSRB->TargetStatus = DC395x_read8(TRM_S1040_SCSI_FIFO);
    pSRB->EndMessage = DC395x_read8(TRM_S1040_SCSI_FIFO);	/* get message */
    pSRB->SRBState = SRB_COMPLETED;
    *pscsi_status = PH_BUS_FREE;    /*.. initial phase*/
    //1.25
    //DC395x_clrfifo (pACB, "STP0");
    DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/
    /*
    ** SCSI command 
    */
    DC395x_write8(TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
}
/*
*********************************************************************
** scsiio
**	DC395x_StatusPhase1: one of DC395x_SCSI_phase1[] vectors
**	 DC395x_stateV = (void *) DC395x_SCSI_phase1[phase]
**				if phase =3 
**
**
*********************************************************************
*/
static void DC395x_StatusPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{
#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x: StatusPhase1 (pid=%li)\n", pSRB->pcmd->pid);
#endif
    TRACEPRINTF("STP1 *");
    /* Cleanup is now done at the end of DataXXPhase0 */
    //DC395x_cleanup_after_transfer (pACB, pSRB);

    pSRB->SRBState = SRB_STATUS;
    DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/
    /*
    ** SCSI command 
    */
    DC395x_write8(TRM_S1040_SCSI_COMMAND, SCMD_COMP);
}

/* Message handling */

#if 0
/* Print received message */
static void
DC395x_printMsg (BYTE *MsgBuf, DWORD len)
{
  int i;
  printk (" %02x", MsgBuf[0]);
  for (i = 1; i < len; i++)
    printk (" %02x", MsgBuf[i]);
  printk ("\n");
};
#endif

/* Check if the message is complete */
static inline BYTE
DC395x_MsgIn_complete (BYTE *msgbuf, DWORD len)
{ 
  if (*msgbuf == EXTENDED_MESSAGE)
  {
	if (len < 2) return 0;
	if (len < msgbuf[1] + 2) return 0;
  }
  else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages
	if (len < 2) return 0;
  return 1;
}

#define DC395x_ENABLE_MSGOUT \
 DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_SETATN); \
 pSRB->SRBState |= SRB_MSGOUT

/* reject_msg */
static inline void
DC395x_MsgIn_reject (PACB pACB, PSRB pSRB)
{
  pSRB->MsgOutBuf[0] = MESSAGE_REJECT;
  pSRB->MsgCnt = 1; DC395x_ENABLE_MSGOUT; 
  pSRB->SRBState &= ~SRB_MSGIN; pSRB->SRBState |= SRB_MSGOUT;
  printk (KERN_INFO "DC395x: Reject message %02x from %02i-%i\n",
	  pSRB->MsgInBuf[0], pSRB->pSRBDCB->TargetID, pSRB->pSRBDCB->TargetLUN);
  TRACEPRINTF("\\*");
}

/* abort command */
static inline void
DC395x_EnableMsgOut_Abort ( PACB pACB, PSRB pSRB )
{
    pSRB->MsgOutBuf[0] = ABORT; 
    pSRB->MsgCnt = 1; DC395x_ENABLE_MSGOUT;
    pSRB->SRBState &= ~SRB_MSGIN; pSRB->SRBState |= SRB_MSGOUT;
    /*
    if (pSRB->pSRBDCB)
	pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
     */
    TRACEPRINTF("#*");
}

static PSRB
DC395x_MsgIn_QTag (PACB pACB, PDCB pDCB, BYTE tag)
{
  PSRB lastSRB = pDCB->pGoingLast;
  PSRB pSRB = pDCB->pGoingSRB;
#ifdef DC395x_DEBUG0
  printk ("DC395x: QTag Msg (SRB %p): %i ", pSRB, tag);
#endif
  if (!(pDCB->TagMask & (1 << tag)))
	printk ("DC395x: MsgIn_QTag: TagMask (%08x) does not reserve tag %i!\n",
		pDCB->TagMask, tag);
	
  if (!pSRB) goto mingx0;
  while (pSRB)
  {
	if (pSRB->TagNumber == tag) break;
	if (pSRB == lastSRB) goto mingx0;
	pSRB = pSRB->pNextSRB;
  }
#ifdef DC395x_DEBUG0
  printk ("pid %li (%i-%i)\n", pSRB->pcmd->pid, 
	  pSRB->pSRBDCB->TargetID, pSRB->pSRBDCB->TargetLUN);
#endif
  if( pDCB->DCBFlag & ABORT_DEV_ )
  {
	//pSRB->SRBState = SRB_ABORT_SENT;
	DC395x_EnableMsgOut_Abort( pACB, pSRB );
  }

  if( !(pSRB->SRBState & SRB_DISCONNECT) )
    goto  mingx0;

  /* Tag found */
  TRACEPRINTF("[%s]*", pDCB->pActiveSRB->debugtrace);
  TRACEPRINTF("RTag*");
  /* Just for debugging ... */
  lastSRB = pSRB; pSRB = pDCB->pActiveSRB; 
  TRACEPRINTF("Found.*");
  pSRB = lastSRB;
   
  memcpy (pSRB->MsgInBuf, pDCB->pActiveSRB->MsgInBuf, pACB->MsgLen);
  pSRB->SRBState |= pDCB->pActiveSRB->SRBState;
  pSRB->SRBState |= SRB_DATA_XFER;
  pDCB->pActiveSRB = pSRB;
  /* How can we make the DORS happy? */
  return pSRB;

 mingx0:
  pSRB = pACB->pTmpSRB;
  pSRB->SRBState = SRB_UNEXPECT_RESEL;
  pDCB->pActiveSRB = pSRB;
  pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
  pSRB->MsgCnt = 1; DC395x_ENABLE_MSGOUT;
  TRACEPRINTF ("?*");
  printk ("DC395x: Unknown tag received: %i: abort !!\n", tag);
  return pSRB;
}
 
/* Reprogram registers */
static inline void
DC395x_reprog (PACB pACB, PDCB pDCB)
{
  DC395x_write8 (TRM_S1040_SCSI_TARGETID, pDCB->TargetID);
  DC395x_write8 (TRM_S1040_SCSI_SYNC, pDCB->SyncPeriod);
  DC395x_write8 (TRM_S1040_SCSI_OFFSET, pDCB->SyncOffset);
  DC395x_SetXferRate (pACB, pDCB);
};


/* set async transfer mode */
static void 
DC395x_MsgIn_set_async (PACB pACB, PSRB pSRB)
{
  PDCB pDCB = pSRB->pSRBDCB;
  printk ("DC395x: Target %02i: No sync transfers\n",
	  pDCB->TargetID);
  TRACEPRINTF("!S *");
  pDCB->SyncMode &= ~(SYNC_NEGO_ENABLE); pDCB->SyncMode |= SYNC_NEGO_DONE;
  //pDCB->SyncPeriod &= 0;
  pDCB->SyncOffset = 0;
  pDCB->MinNegoPeriod = 200 >> 2; /* 200ns <=> 5 MHz */
  pSRB->SRBState &= ~SRB_DO_SYNC_NEGO;
  DC395x_reprog (pACB, pDCB);
  if ((pDCB->SyncMode & WIDE_NEGO_ENABLE) && !(pDCB->SyncMode & WIDE_NEGO_DONE))
  {
	DC395x_Build_WDTR (pACB, pDCB, pSRB);
	DC395x_ENABLE_MSGOUT;
	DEBUG0(printk ("DC395x: SDTR(rej): Try WDTR anyway ...\n");)
  }
}

/* set sync transfer mode */
static void
DC395x_MsgIn_set_sync (PACB pACB, PSRB pSRB)
{
  BYTE bval; int fact;
  PDCB pDCB = pSRB->pSRBDCB;
  //BYTE oldsyncperiod = pDCB->SyncPeriod;
  //BYTE oldsyncoffset = pDCB->SyncOffset;

#ifdef DC395x_DEBUG1	
  printk (KERN_INFO "DC395x: Target %02i: Sync: %ins (%02i.%01i MHz) Offset %i\n",
	  pDCB->TargetID, pSRB->MsgInBuf[3]<<2, 
	  (250/pSRB->MsgInBuf[3]), ((250%pSRB->MsgInBuf[3])*10)/pSRB->MsgInBuf[3],
	  pSRB->MsgInBuf[4]);
#endif

  if (pSRB->MsgInBuf[4] > 15)
	pSRB->MsgInBuf[4] = 15;
  if (!(pDCB->DevMode & NTC_DO_SYNC_NEGO))
	pDCB->SyncOffset = 0;
  else if (pDCB->SyncOffset == 0)
	pDCB->SyncOffset = pSRB->MsgInBuf[4];
  if (pSRB->MsgInBuf[4] > pDCB->SyncOffset)
	pSRB->MsgInBuf[4] = pDCB->SyncOffset;
  else
	pDCB->SyncOffset = pSRB->MsgInBuf[4];
  bval = 0;
  while ( bval < 7 && 
	 (pSRB->MsgInBuf[3] > dc395x_clock_period[bval] ||
	  pDCB->MinNegoPeriod > dc395x_clock_period[bval]) )
		bval++;
  if (pSRB->MsgInBuf[3] < dc395x_clock_period[bval])
	printk (KERN_INFO "DC395x: Increase sync nego period to %ins\n", 
		dc395x_clock_period[bval] << 2);
  pSRB->MsgInBuf[3] = dc395x_clock_period[bval];
  pDCB->SyncPeriod &= 0xf0;
  pDCB->SyncPeriod |= ALT_SYNC | bval;
  pDCB->MinNegoPeriod = pSRB->MsgInBuf[3];
  
  if (pDCB->SyncPeriod & WIDE_SYNC) fact = 500;
  else fact = 250;

  printk (KERN_INFO "DC395x: Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n",
	  pDCB->TargetID, (fact == 500)? "Wide16" :"", pDCB->MinNegoPeriod<<2,
	  pDCB->SyncOffset, (fact/pDCB->MinNegoPeriod), 
	  ((fact%pDCB->MinNegoPeriod)*10+pDCB->MinNegoPeriod/2)/pDCB->MinNegoPeriod);

  TRACEPRINTF("S%i *", pDCB->MinNegoPeriod << 2);
  if (!(pSRB->SRBState & SRB_DO_SYNC_NEGO))
  {
      /* Reply with corrected SDTR Message */
      printk ("DC395x: .. answer w/  %ins %i\n", 
	      pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
      
      memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5);
      pSRB->MsgCnt = 5; 
      DC395x_ENABLE_MSGOUT;
      pDCB->SyncMode |= SYNC_NEGO_DONE;
  }
  else
  {
	if ((pDCB->SyncMode & WIDE_NEGO_ENABLE) && !(pDCB->SyncMode & WIDE_NEGO_DONE))
	{
		DC395x_Build_WDTR (pACB, pDCB, pSRB);
		DC395x_ENABLE_MSGOUT;
		DEBUG0 (printk ("DC395x: SDTR: Also try WDTR ...\n");)
	}
  }
  pSRB->SRBState &= ~SRB_DO_SYNC_NEGO;
  pDCB->SyncMode |= SYNC_NEGO_DONE | SYNC_NEGO_ENABLE;

  DC395x_reprog (pACB, pDCB);
};


static inline void
DC395x_MsgIn_set_nowide (PACB pACB, PSRB pSRB)
{
    PDCB pDCB = pSRB->pSRBDCB;
#ifdef DC395x_DEBUG_KG	
    printk ("DC395x: WDTR got rejected from target %02i\n",
	    pDCB->TargetID);
#endif
    TRACEPRINTF("!W *");
    pDCB->SyncPeriod &= ~WIDE_SYNC;
    pDCB->SyncMode &= ~(WIDE_NEGO_ENABLE); pDCB->SyncMode |= WIDE_NEGO_DONE;
    pSRB->SRBState &= ~SRB_DO_WIDE_NEGO;
    DC395x_reprog (pACB, pDCB);
    if ((pDCB->SyncMode & SYNC_NEGO_ENABLE) && !(pDCB->SyncMode & SYNC_NEGO_DONE))
    {
	DC395x_Build_SDTR (pACB, pDCB, pSRB);
	DC395x_ENABLE_MSGOUT;
	DEBUG0(printk ("DC395x: WDTR(rej): Try SDTR anyway ...\n");)
    }
}

static void
DC395x_MsgIn_set_wide (PACB pACB, PSRB pSRB)
{
    PDCB pDCB = pSRB->pSRBDCB;
    BYTE wide = (pDCB->DevMode & NTC_DO_WIDE_NEGO && pACB->Config & HCC_WIDE_CARD)? 1 : 0;
    if (pSRB->MsgInBuf[3] > wide)
	pSRB->MsgInBuf[3] = wide;
    /* Completed */
    if (!(pSRB->SRBState & SRB_DO_WIDE_NEGO))
    {
	printk ("DC395x: Target %02i initiates Wide Nego ...\n", pDCB->TargetID);
	memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 4);
	pSRB->MsgCnt = 4; pSRB->SRBState |= SRB_DO_WIDE_NEGO;
	DC395x_ENABLE_MSGOUT; 
    }

    pDCB->SyncMode |=  (WIDE_NEGO_ENABLE | WIDE_NEGO_DONE);
    if (pSRB->MsgInBuf[3] > 0) pDCB->SyncPeriod |= WIDE_SYNC;
    else pDCB->SyncPeriod &= ~WIDE_SYNC;
    pSRB->SRBState &= ~SRB_DO_WIDE_NEGO;
    TRACEPRINTF("W%i *", (pDCB->SyncPeriod & WIDE_SYNC? 1: 0));
    //pDCB->SyncMode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE);
#ifdef DC395x_DEBUG_KG
    printk ("DC395x: Wide transfers (%i bit) negotiated with target %02i\n",
		(8 << pSRB->MsgInBuf[3]), pDCB->TargetID);
#endif
    DC395x_reprog (pACB, pDCB);
    if ((pDCB->SyncMode & SYNC_NEGO_ENABLE) && !(pDCB->SyncMode & SYNC_NEGO_DONE))
    {
	DC395x_Build_SDTR (pACB, pDCB, pSRB);
	DC395x_ENABLE_MSGOUT;
	DEBUG0(printk ("DC395x: WDTR: Also try SDTR ...\n");)
    }
}


#if 0
/* handle RESTORE_PTR */
static void 
DC395x_restore_ptr (PACB pACB, PSRB pSRB)
{
  PSGL psgl;
  pSRB->TotalXferredLen = 0;
  pSRB->SGIndex = 0;
  if( pSRB->pcmd->use_sg )
    {
      /* NOTE: This is wrong, since we have segment merging nowadays ... */
      pSRB->SGcount = (BYTE) pSRB->pcmd->use_sg;
      pSRB->pSegmentList = (PSGL) pSRB->pcmd->request_buffer;
      psgl = pSRB->pSegmentList;
      while (pSRB->TotalXferredLen + (ULONG) psgl->length < pSRB->Saved_Ptr)
	{
	  pSRB->TotalXferredLen += (ULONG) psgl->length;
	  pSRB->SGIndex++;
	  if( pSRB->SGIndex < pSRB->SGcount )
	    {
	      pSRB->pSegmentList++;
	      psgl = pSRB->pSegmentList;
	      
	      /* And here we have to use the pci map ! */
	      pSRB->SGBusAddr = virt_to_bus( psgl->address );
	      pSRB->SGToBeXferLen = (ULONG) psgl->length;
	    }
	  else
	    pSRB->SGToBeXferLen = 0;
	}
      pSRB->SGToBeXferLen -= (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
      pSRB->SGBusAddr += (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
      printk (KERN_INFO "DC395x: Pointer restored. Segment %i, Total %li, Bus %08lx\n", pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr);
    }
    else if( pSRB->pcmd->request_buffer )
    {
	pSRB->SGcount = 1;
	pSRB->pSegmentList = (PSGL) &pSRB->Segmentx;
	pSRB->Segmentx.address = (PBYTE) pSRB->pcmd->request_buffer + pSRB->Saved_Ptr;
	pSRB->Segmentx.length = pSRB->pcmd->request_bufflen - pSRB->Saved_Ptr;
	printk (KERN_INFO "DC395x: Pointer restored. Total %li, Bus %p\n",
		pSRB->Saved_Ptr, pSRB->Segmentx.address);
    }
     else
       {
	 pSRB->SGcount = 0;
	 printk (KERN_INFO "DC395x: RESTORE_PTR message for Transfer without Scatter-Gather ??\n");
       };

  pSRB->TotalXferredLen = pSRB->Saved_Ptr;
}
#endif

/*
*********************************************************************
** scsiio
**	DC395x_MsgInPhase0: one of DC395x_SCSI_phase0[] vectors
**	 DC395x_stateV = (void *) DC395x_SCSI_phase0[phase]
**				if phase =7   
**
** extended message codes:
**
**	code	description
**
**	02h	Reserved
**	00h	MODIFY DATA  POINTER
**	01h	SYNCHRONOUS DATA TRANSFER REQUEST
**	03h	WIDE DATA TRANSFER REQUEST
**   04h - 7Fh	Reserved
**   80h - FFh	Vendor specific
**  
*********************************************************************
*/
void DC395x_MsgInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{
    PDCB   pDCB;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_MsgInPhase0..............\n ");
#endif
    TRACEPRINTF("MIP0*");
    pDCB = pACB->pActiveDCB;

    pSRB->MsgInBuf[pACB->MsgLen++] = DC395x_read8 (TRM_S1040_SCSI_FIFO);
    if (DC395x_MsgIn_complete (pSRB->MsgInBuf, pACB->MsgLen))
    {
	TRACEPRINTF("(%02x)*", pSRB->MsgInBuf[0]);
	//printk (KERN_INFO "DC395x: MsgIn:"); 
	//DC395x_printMsg (pSRB->MsgInBuf, pACB->MsgLen);

	/* Now eval the msg */
	switch (pSRB->MsgInBuf[0]) 
	  {
	  case DISCONNECT:
	    pSRB->SRBState = SRB_DISCONNECT; break;
	    
	  case SIMPLE_QUEUE_TAG:
	  case HEAD_OF_QUEUE_TAG:
	  case ORDERED_QUEUE_TAG:
	    TRACEPRINTF("(%02x)*", pSRB->MsgInBuf[1]);
	    pSRB = DC395x_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]);
	    break;
	    
	  case MESSAGE_REJECT: 
	    DC395x_write16(TRM_S1040_SCSI_CONTROL,DO_CLRATN | DO_DATALATCH);
	    /* A sync nego message was rejected ! */
	    if (pSRB->SRBState & SRB_DO_SYNC_NEGO)
	    {
	      	    DC395x_MsgIn_set_async (pACB, pSRB);
		    break;
	    }
	    /* A wide nego message was rejected ! */
	    if (pSRB->SRBState & SRB_DO_WIDE_NEGO)
	    {
		    DC395x_MsgIn_set_nowide (pACB, pSRB);
		    break;
	    }
	    DC395x_EnableMsgOut_Abort (pACB, pSRB);
	    //pSRB->SRBState |= SRB_ABORT_SENT;
	    break;
	    
	  case EXTENDED_MESSAGE:
	    TRACEPRINTF("(%02x)*", pSRB->MsgInBuf[2]);
	    /* SDTR */
	    if (pSRB->MsgInBuf[1] == 3 && pSRB->MsgInBuf[2] == EXTENDED_SDTR)
	    {
		  DC395x_MsgIn_set_sync (pACB, pSRB);
		break;
	    };
	    /* WDTR */
	    if (pSRB->MsgInBuf[1] == 2 && pSRB->MsgInBuf[2] == EXTENDED_WDTR
		&& pSRB->MsgInBuf[3] <= 2) // sanity check ...
	    {
		DC395x_MsgIn_set_wide (pACB, pSRB);
		break;
	    };
	    DC395x_MsgIn_reject (pACB, pSRB);
	    break;

	    // Discard  wide residual
	  case MSG_IGNOREWIDE:
	    DEBUG0(printk ("DC395x: Ignore Wide Residual!\n");)
	    //DC395x_write32 (TRM_S1040_SCSI_COUNTER, 1);
	    //DC395x_read8 (TRM_S1040_SCSI_FIFO);
	    break;
		  
	    // nothing has to be done
	  case COMMAND_COMPLETE: break;
	    
	    // SAVE POINTER may be ignored as we have the PSRB associated with the
	    // scsi command. Thanks, Gérard, for pointing it out.
	  case SAVE_POINTERS:
#ifdef DC395x_DEBUG0
	    printk ("DC395x: SAVE POINTER message received (pid %li: rem.%i) ... ignore :-(\n",
		    pSRB->pcmd->pid, pSRB->SRBTotalXferLength);
#endif
	    //pSRB->Saved_Ptr = pSRB->TotalXferredLen;
	    break;
	    // The device might want to restart transfer with a RESTORE
	  case RESTORE_POINTERS:
	    printk ("DC395x: RESTORE POINTER message received ... ignore :-(\n");
	    //dc395x_restore_ptr (pACB, pSRB);
	    break;
	  case ABORT:
	    printk ("DC395x: ABORT msg received (pid %li %02i-%i)\n",
		    pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN);
	    pDCB->DCBFlag |= ABORT_DEV_;
	     DC395x_EnableMsgOut_Abort (pACB, pSRB);
	    break;
	    // reject unknown messages
	  default: 
		  if (pSRB->MsgInBuf[0] & IDENTIFY_BASE)
		  {
			  printk ("DC395x: Identify Message received?\n");
			  //TRACEOUT (" %s\n", pSRB->debugtrace);
			  pSRB->MsgCnt = 1; pSRB->MsgOutBuf[0] = pDCB->IdentifyMsg;
			  DC395x_ENABLE_MSGOUT; pSRB->SRBState |= SRB_MSGOUT;
			  //break;
		  }
		  DC395x_MsgIn_reject (pACB, pSRB);
		  TRACEOUT (" %s\n", pSRB->debugtrace);
	  }
	TRACEPRINTF (".*");
	    
	/* Clear counter and MsgIn state */
	pSRB->SRBState &= ~SRB_MSGIN;
	pACB->MsgLen = 0;
    };

    //1.25
    if ((*pscsi_status & PHASEMASK) != PH_MSG_IN)
#if 0	
		DC395x_clrfifo (pACB, "MIP0_");
#else
    		TRACEPRINTF("N/Cln *");
#endif
    *pscsi_status = PH_BUS_FREE;
    DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important ... you know! */
    DC395x_write8  (TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
}

/*
*********************************************************************
** scsiio
**	DC395x_MsgInPhase1: one of DC395x_SCSI_phase1[] vectors
**	 DC395x_stateV = (void *) DC395x_SCSI_phase1[phase]
**				if phase =7	   
**
**
*********************************************************************
*/
static void DC395x_MsgInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{
#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_MsgInPhase1..............\n ");
#endif
    TRACEPRINTF("MIP1 *");
    DC395x_clrfifo (pACB, "MIP1");
    DC395x_write32(TRM_S1040_SCSI_COUNTER, 1);
    if( !(pSRB->SRBState & SRB_MSGIN) )
    {
	pSRB->SRBState &= ~SRB_DISCONNECT;
	pSRB->SRBState |= SRB_MSGIN;
    }
    DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop */
    /*
    ** SCSI command 
    */
    DC395x_write8(TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN);
}

/*
*********************************************************************
** scsiio
**	DC395x_Nop0: one of DC395x_SCSI_phase1[] ,DC395x_SCSI_phase0[] vectors
**	 DC395x_stateV = (void *) DC395x_SCSI_phase0[phase]
**	 DC395x_stateV = (void *) DC395x_SCSI_phase1[phase]
**				if phase =4 ..PH_BUS_FREE
**
**
*********************************************************************
*/
static void
DC395x_Nop0( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{
	//TRACEPRINTF("NOP0 *");
}
/*
*********************************************************************
** scsiio
**	DC395x_Nop1: one of DC395x_SCSI_phase0[] ,DC395x_SCSI_phase1[] vectors
**	 DC395x_stateV = (void *) DC395x_SCSI_phase0[phase]
**	 DC395x_stateV = (void *) DC395x_SCSI_phase1[phase]
**				if phase =5
**
**
*********************************************************************
*/
static void DC395x_Nop1( PACB pACB, PSRB pSRB, PWORD pscsi_status)
{
	//TRACEPRINTF("NOP1 *");
}
/*
*********************************************************************
** scsiio
**		DC395x_MsgInPhase0
**
*********************************************************************
*/
static void DC395x_SetXferRate( PACB pACB, PDCB pDCB )
{
    BYTE   bval;
    WORD   cnt, i;
    PDCB   pDCBTemp;

    /*
    ** set all lun device's  period , offset
    */
    if( !(pDCB->IdentifyMsg & 0x07) )
    {
	if( pACB->scan_devices )
	    DC395x_CurrSyncOffset = pDCB->SyncOffset;
	else
	{
	    pDCBTemp = pACB->pLinkDCB;
	    cnt = pACB->DCBCnt;
	    bval = pDCB->TargetID;
	    for(i=0; i<cnt; i++)
	    {
		if( pDCBTemp->TargetID == bval )
		{
		    pDCBTemp->SyncPeriod = pDCB->SyncPeriod;
		    pDCBTemp->SyncOffset = pDCB->SyncOffset;
		    pDCBTemp->SyncMode   = pDCB->SyncMode;
		    pDCBTemp->MinNegoPeriod = pDCB->MinNegoPeriod;
		}
		pDCBTemp = pDCBTemp->pNextDCB;
	    }
	}
    }
    return;
}

/*
*********************************************************************
** scsiio
**		DC395x_Interrupt
**
*********************************************************************
*/
void DC395x_Disconnect ( PACB pACB )
{
    PDCB   pDCB;
    PSRB   pSRB;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x: Disconnect (pid=%li)\n",
	   pACB->pActiveDCB->pActiveSRB->pcmd->pid);
#endif
    pDCB = pACB->pActiveDCB;
    if (!pDCB)
    {
	printk(KERN_ERR "DC395x: Disc: Exception Disconnect pDCB=NULL !!\n ");
	udelay (500);
	// Suspend queue for a while
	pACB->pScsiHost->last_reset = jiffies + HZ/2 + 
		HZ * dc395x_trm_eepromBuf[pACB->AdapterIndex].NvramDelayTime;
	DC395x_clrfifo (pACB, "DiscEx");
	DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_HWRESELECT);
	return;
    }
    pSRB = pDCB->pActiveSRB;
    pACB->pActiveDCB = 0;
    TRACEPRINTF("DISC *");

    pSRB->ScsiPhase = PH_BUS_FREE;/* initial phase */
    DC395x_clrfifo (pACB, "Disc");
    DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_HWRESELECT);
    if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
    {
	printk(KERN_ERR "DC395x: Disc: Unexpected Reselection (%i-%i)\n", pDCB->TargetID, pDCB->TargetLUN);
	pSRB->SRBState = 0;
	DC395x_Waiting_process ( pACB );
    }
    else if( pSRB->SRBState & SRB_ABORT_SENT )
    {
	//PSCSICMD pcmd = pSRB->pcmd;
	pDCB->DCBFlag &= ~ABORT_DEV_;
	pACB->pScsiHost->last_reset = jiffies + HZ/2 + 1;
	printk(KERN_ERR "DC395x: Disc: SRB_ABORT_SENT!\n");
	DC395x_DoingSRB_Done (pACB, DID_ABORT, pSRB->pcmd, 1);
	DC395x_Query_to_Waiting (pACB);
	DC395x_Waiting_process (pACB);
    }
    else
    {
	if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) || !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) )
	{	
	    /*
	    ** Selection time out 
	    ** SRB_START_ || SRB_MSGOUT || (!SRB_DISCONNECT && !SRB_COMPLETED)
	    */
	    /* Unexp. Disc / Sel Timeout */
	    if (pSRB->SRBState != SRB_START_ && pSRB->SRBState != SRB_MSGOUT)
	    {
		pSRB->SRBState = SRB_READY;
		printk ("DC395x: Unexpected Disconnection (pid %li)!\n", pSRB->pcmd->pid);
		pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
		TRACEPRINTF("UnExpD *");
		TRACEOUT ("%s\n", pSRB->debugtrace);
		goto disc1;
	    }
	    else
	    {
		/* Normal selection timeout */
		TRACEPRINTF("SlTO *");
#ifdef DC395x_DEBUG_KG
		printk ("DC395x: Disc: SelTO (pid=%li) for dev %02i-%i\n", pSRB->pcmd->pid,
			pDCB->TargetID, pDCB->TargetLUN);
#endif
		if (pSRB->RetryCnt++ > DC395x_MAX_RETRIES || pACB->scan_devices)
		{
			pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
			goto disc1;
		}
		DC395x_freetag (pDCB, pSRB);
		DC395x_Going_to_Waiting (pDCB, pSRB);
#ifdef DC395x_DEBUG_KG
		printk ("DC395x: Retry pid %li ...\n", pSRB->pcmd->pid);
#endif
		DC395x_waiting_timer (pACB, HZ/20);
	    }
	}
	else if( pSRB->SRBState & SRB_DISCONNECT )
	{
	    BYTE bval = DC395x_read8 (TRM_S1040_SCSI_SIGNAL);
	    /*
	    ** SRB_DISCONNECT (This is what we expect!)
	    */
	    // printk ("DC395x: DoWaitingSRB (pid=%li)\n", pSRB->pcmd->pid);
	    TRACEPRINTF("+*");
	    if (bval & 0x40)
	    {
		DEBUG0(printk ("DC395x: Debug: DISC: SCSI bus stat %02x: ACK set! Other controllers?\n",
			bval);)
		// It could come from another initiator, therefore don't do much !
		TRACEPRINTF("ACK(%02x) *", bval);
		//DC395x_dumpinfo (pACB, pDCB, pSRB);
		//TRACEOUT (" %s\n", pSRB->debugtrace);
		//pDCB->DCBFlag |= ABORT_DEV_;
		//DC395x_EnableMsgOut_Abort (pACB, pSRB);
		//DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO | DO_CLRATN | DO_HWRESELECT);
	    }
	    else
		DC395x_Waiting_process ( pACB );
	}
	else if( pSRB->SRBState & SRB_COMPLETED )  
	{
disc1:
	    /*
	    ** SRB_COMPLETED
	    */
	    DC395x_freetag (pDCB, pSRB);
	    pDCB->pActiveSRB = 0;
	    pSRB->SRBState = SRB_FREE;
	    //printk ("DC395x: done (pid=%li)\n", pSRB->pcmd->pid);
	    DC395x_SRBdone( pACB, pDCB, pSRB);
	}
    }
    return;
}

/*
*********************************************************************
** scsiio
**		DC395x_Reselect
**
*********************************************************************
*/
void DC395x_Reselect( PACB pACB )
{
    PDCB   pDCB;
    PSRB   pSRB = 0;
    WORD   RselTarLunId;
    BYTE   id, lun;
    BYTE   arblostflag = 0;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_Reselect..............\n ");
#endif

    DC395x_clrfifo (pACB, "Resel");
    //DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH);
    /* Read Reselected Target ID and LUN */
    RselTarLunId = DC395x_read16(TRM_S1040_SCSI_TARGETID);
    pDCB = pACB->pActiveDCB;
    if( pDCB )
    {	/* Arbitration lost but Reselection win */
	pSRB = pDCB->pActiveSRB;
	if (!pSRB) {
		printk ("DC395x: Arb lost Resel won, but pActiveSRB == 0!\n");
		DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/
		return;
	}
	/* Why the if ? */
	if( !( pACB->scan_devices ) )
	{
#ifdef DC395x_DEBUG_KG		
	    printk ("DC395x: Arb lost but Resel win pid %li (%02i-%i) Rsel %04x Stat %04x\n",
		    pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN, 
		    RselTarLunId, DC395x_read16 (TRM_S1040_SCSI_STATUS));
#endif
	    TRACEPRINTF ("ArbLResel!*");
	    //TRACEOUT (" %s\n", pSRB->debugtrace);
	    arblostflag = 1;
	    //pSRB->SRBState |= SRB_DISCONNECT;
	    
	    pSRB->SRBState = SRB_READY;
	    DC395x_freetag (pDCB, pSRB);
	    DC395x_Going_to_Waiting (pDCB, pSRB);
	    DC395x_waiting_timer (pACB, HZ/20);

	    // return;
	}
    }
    /* Read Reselected Target Id and LUN */
    if (!(RselTarLunId & (IDENTIFY_BASE << 8)))
	printk ("DC395x: Resel expects identify msg! Got %04x!\n", RselTarLunId);
    id = RselTarLunId & 0xff;
    lun = (RselTarLunId >> 8) & 7;
    pDCB = DC395x_findDCB (pACB, id, lun);
    if( !pDCB ) {
	printk (KERN_ERR "DC395x: Reselect from non existing device (%02i-%i)\n",
		id, lun);
	DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/
	return;
    }

    pACB->pActiveDCB = pDCB;

    if (!(pDCB->DevMode & NTC_DO_DISCONNECT))
	printk ("DC395x: Reselection in spite of forbidden disconnection? (%02i-%i)\n",
		pDCB->TargetID, pDCB->TargetLUN);

    if( (pDCB->SyncMode & EN_TAG_QUEUEING) /*&& !arblostflag*/)
    { 
	PSRB oldSRB = pSRB;
	pSRB = pACB->pTmpSRB;
#ifdef DC395x_DEBUGTRACE
	pSRB->debugpos = 0; pSRB->debugtrace[0] = 0;
#endif
	pDCB->pActiveSRB = pSRB;
	if (oldSRB) TRACEPRINTF ("ArbLResel(%li):*", oldSRB->pcmd->pid);
	//if (arblostflag) printk ("DC395x: Reselect: Wait for Tag ... \n");
    }
    else
    {
	/* There can be only one! */
	pSRB = pDCB->pActiveSRB;
	if (pSRB) 
		TRACEPRINTF("RSel *");
	if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) )
	{
	    /*
	    ** abort command
	    */
	    printk ("DC395x: Reselected w/o disconnected cmds from %02i-%i?\n",
		    pDCB->TargetID, pDCB->TargetLUN);
	    pSRB = pACB->pTmpSRB;
	    pSRB->SRBState = SRB_UNEXPECT_RESEL;
	    pDCB->pActiveSRB = pSRB;
	    DC395x_EnableMsgOut_Abort( pACB, pSRB );
	}
	else
	{
	    if( pDCB->DCBFlag & ABORT_DEV_ )
 	    {
		//pSRB->SRBState = SRB_ABORT_SENT;
		DC395x_EnableMsgOut_Abort( pACB, pSRB );
	    }
	    else
		pSRB->SRBState = SRB_DATA_XFER;

	}
        //if (arblostflag) TRACEOUT (" %s\n", pSRB->debugtrace);
    }
    pSRB->ScsiPhase = PH_BUS_FREE;/* initial phase */
    /* 
    ***********************************************
    ** Program HA ID, target ID, period and offset
    ***********************************************
    */
    DC395x_write8(TRM_S1040_SCSI_HOSTID, pACB->pScsiHost->this_id);	/* host   ID */
    DC395x_write8(TRM_S1040_SCSI_TARGETID, pDCB->TargetID);	/* target ID */
    DC395x_write8(TRM_S1040_SCSI_OFFSET, pDCB->SyncOffset);	/* offset    */
    DC395x_write8(TRM_S1040_SCSI_SYNC, pDCB->SyncPeriod);	/* sync period, wide */
    DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/
    /* SCSI command */
    DC395x_write8(TRM_S1040_SCSI_COMMAND,  SCMD_MSGACCEPT);
}


/* Dynamic device handling */

/* Remove dev (and DCB) */
static void 
DC395x_remove_dev (PACB pACB, PDCB pDCB)
{
   PDCB pPrevDCB = pACB->pLinkDCB;

   if (pDCB->GoingSRBCnt > 1)
     {
	DCBDEBUG(printk (KERN_INFO "DC395x: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n",\
		pDCB->TargetID, pDCB->TargetLUN, (int)pDCB, pDCB->GoingSRBCnt);)
	return;
     };
   pACB->DCBmap[pDCB->TargetID] &= ~(1 << pDCB->TargetLUN);
   
   // The first one
   if (pDCB == pACB->pLinkDCB) 
   {
	// The last one
	if (pACB->pLastDCB == pDCB) {
		pDCB->pNextDCB = 0; pACB->pLastDCB = 0;
	}
	pACB->pLinkDCB = pDCB->pNextDCB;
   }
   else
   {
	while (pPrevDCB->pNextDCB != pDCB) pPrevDCB = pPrevDCB->pNextDCB;
	pPrevDCB->pNextDCB = pDCB->pNextDCB;
	if (pDCB == pACB->pLastDCB) pACB->pLastDCB = pPrevDCB;
   }

   DCBDEBUG(\
	    printk (KERN_INFO "DC395x: Driver about to free DCB (ID %i, LUN %i): %p\n",\
	   pDCB->TargetID, pDCB->TargetLUN, pDCB);\
   )
   if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0;
   if (pDCB == pACB->pLinkDCB) pACB->pLinkDCB = pDCB->pNextDCB;
   if (pDCB == pACB->pDCBRunRobin) pACB->pDCBRunRobin = pDCB->pNextDCB;
   pACB->DCBCnt--;
   KFREE (pDCB); 
   /* pACB->DeviceCnt--; */
};


static inline BYTE
DC395x_tagq_blacklist (char* name)
{
#ifndef DC395x_NO_TAGQ
#if 0	
   BYTE i;
   for(i=0; i<BADDEVCNT; i++)
     if (memcmp (name, DC395x_baddevname1[i], 28) == 0)
	return 1;
#endif
   return 0;
#else
   return 1;
#endif  
};

static void 
DC395x_disc_tagq_set (PDCB pDCB, PSCSI_INQDATA ptr)
{
   /* Check for SCSI format (ANSI and Response data format) */
   if ( (ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2 )
   {
	if ( (ptr->Flags & SCSI_INQ_CMDQUEUE) &&
	    (pDCB->DevMode & NTC_DO_TAG_QUEUEING) &&
	    //(pDCB->DevMode & NTC_DO_DISCONNECT)
	    /* ((pDCB->DevType == TYPE_DISK) 
		|| (pDCB->DevType == TYPE_MOD)) &&*/
	    !DC395x_tagq_blacklist (((char*)ptr)+8) )
	  {
	     if (pDCB->MaxCommand ==1) 
		pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum;
	     pDCB->SyncMode |= EN_TAG_QUEUEING;
	     //pDCB->TagMask = 0;
	  }
	else
	     pDCB->MaxCommand = 1;
     }
};

static void 
DC395x_add_dev (PACB pACB, PDCB pDCB, PSCSI_INQDATA ptr)
{
   BYTE bval1 = ptr->DevType & SCSI_DEVTYPE;
   pDCB->DevType = bval1;
   /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */
   DC395x_disc_tagq_set (pDCB, ptr);
};

/* 
*********************************************************************
** unmap mapped pci regions from SRB
*********************************************************************
 */
static void DC395x_pci_unmap (PACB pACB, PSRB pSRB)
{
	int dir;
	PSCSICMD pcmd = pSRB->pcmd;
	SET_DIR(dir,pcmd);
	if (pcmd->use_sg && dir != PCI_DMA_NONE) {
		/* unmap DC395x SG list */
#ifdef DC395x_SGPARANOIA
		printk ("DC395x: Unmap SG descriptor list %08x (%05x)\n",
			pSRB->SRBSGBusAddr, sizeof(SGentry)*DC395x_MAX_SG_LISTENTRY);
#endif
		PCI_UNMAP_SINGLE(pACB->pdev, pSRB->SRBSGBusAddr,
				 sizeof(SGentry)*DC395x_MAX_SG_LISTENTRY, PCI_DMA_TODEVICE);
#ifdef DC395x_SGPARANOIA
		printk ("DC395x: Unmap %i SG segments from %p\n",
			pcmd->use_sg, pcmd->request_buffer);
#endif
		/* unmap the sg segments */
		PCI_UNMAP_SG(pACB->pdev, (struct scatterlist*)pcmd->request_buffer,
			     pcmd->use_sg, dir);
	}
	else if (pcmd->request_buffer && dir != PCI_DMA_NONE) {
#ifdef DC395x_SGPARANOIA
		printk ("DC395x: Unmap buffer at %08x (%05x)\n",
			pSRB->SegmentX[0].address, pcmd->request_bufflen);
#endif	    
		PCI_UNMAP_SINGLE(pACB->pdev, pSRB->SegmentX[0].address,
				 pcmd->request_bufflen, dir);
	}
}
		
/* 
*********************************************************************
** unmap mapped pci sense buffer from SRB
*********************************************************************
 */
static void DC395x_pci_unmap_sense (PACB pACB, PSRB pSRB)
{
	if (!(pSRB->SRBFlag & AUTO_REQSENSE))
		return;
	/* Unmap sense buffer */
#ifdef DC395x_SGPARANOIA
	printk ("DC395x: Unmap sense buffer from %08x (%05x)\n",
		pSRB->SegmentX[0].address, sizeof(pcmd->sense_buffer));
#endif
	PCI_UNMAP_SINGLE(pACB->pdev, pSRB->SegmentX[0].address,
			 pSRB->SegmentX[0].length, PCI_DMA_FROMDEVICE);
	// Restore SG stuff
	//printk ("Auto_ReqSense finished: Restore Counters ...\n");
	pSRB->SRBTotalXferLength  = pSRB->Xferred;
	pSRB->SegmentX[0].address = pSRB->SegmentX[DC395x_MAX_SG_LISTENTRY-1].address;
	pSRB->SegmentX[0].length  = pSRB->SegmentX[DC395x_MAX_SG_LISTENTRY-1].length;
}
		
		
/*
*********************************************************************
** scsiio
**		DC395x_Disconnected
**	Complete execution of a SCSI command
**	Signal completion to the generic SCSI driver  
**
*********************************************************************
*/
void DC395x_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB )
{
    BYTE               tempcnt,status,DCB_removed=0;
    PSCSICMD           pcmd;
    PSCSI_INQDATA      ptr;
    //DWORD              drv_flags=0;
    int dir;

    pcmd = pSRB->pcmd;
    TRACEPRINTF("DONE *");

    SET_DIR(dir,pcmd);
    ptr = (PSCSI_INQDATA) (pcmd->request_buffer);
    if( pcmd->use_sg )
	ptr = (PSCSI_INQDATA) CPU_ADDR(*(PSGL)ptr);
#ifdef DC395x_SGPARANOIA
    printk (KERN_INFO "DC395x: SRBdone SG=%i (%i/%i), req_buf = %p, adr = %p\n",
	    pcmd->use_sg, pSRB->SRBSGIndex, pSRB->SRBSGCount, pcmd->request_buffer, ptr);
#endif
#ifdef DC395x_DEBUG_KG
    printk(KERN_INFO "DC395x: SRBdone (pid %li, target %02i-%i): ",
	   pSRB->pcmd->pid, pSRB->pcmd->target, pSRB->pcmd->lun);
#endif
    status = pSRB->TargetStatus;
    if(pSRB->SRBFlag & AUTO_REQSENSE)
    {
#ifdef DC395x_DEBUG0
	printk(KERN_INFO "AUTO_REQSENSE1..............\n ");
#endif
	DC395x_pci_unmap_sense (pACB, pSRB);
	/*
	** target status..........................
	*/
	pSRB->SRBFlag &= ~AUTO_REQSENSE;
	pSRB->AdaptStatus = 0;
	pSRB->TargetStatus = CHECK_CONDITION << 1;
#ifdef DC395x_DEBUG_KG
	switch (pcmd->sense_buffer[2] & 0x0f)
	{	    
	 case NOT_READY: printk ("\nDC395x:  ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ",
				 pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN,
				 status, pACB->scan_devices); break;
	 case UNIT_ATTENTION: printk ("\nDC395x:  ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ",
				      pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN,
				      status, pACB->scan_devices); break;
	 case ILLEGAL_REQUEST: printk ("\nDC395x:  ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ",
				       pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN,
				       status, pACB->scan_devices); break;
	 case MEDIUM_ERROR: printk ("\nDC395x:  ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ",
				    pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN,
				    status, pACB->scan_devices); break;
	 case HARDWARE_ERROR: printk ("\nDC395x:  ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ",
				      pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN,
				      status, pACB->scan_devices); break;
	}
	if (pcmd->sense_buffer[7] >= 6)
		printk ("\nDC395x:  Sense=%02x, ASC=%02x, ASCQ=%02x (%08x %08x) ",
			pcmd->sense_buffer[2], pcmd->sense_buffer[12],
			pcmd->sense_buffer[13], 
			*((unsigned int*)(pcmd->sense_buffer+3)),
			*((unsigned int*)(pcmd->sense_buffer+8)));
	 else
		printk ("\nDC395x:  Sense=%02x, No ASC/ASCQ (%08x) ",
			pcmd->sense_buffer[2],
			*((unsigned int*)(pcmd->sense_buffer+3)));
#endif

	if (status == (CHECK_CONDITION << 1))
	{
	    pcmd->result = DID_BAD_TARGET << 16;
	    goto ckc_e;
	}
#ifdef DC395x_DEBUG0
	printk(KERN_INFO "AUTO_REQSENSE2..............\n ");
#endif
    
	if( (pSRB->SRBTotalXferLength) && (pSRB->SRBTotalXferLength >= pcmd->underflow) )
	    pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,pSRB->EndMessage,CHECK_CONDITION);
	    //SET_RES_DID(pcmd->result,DID_OK)
	else
	    pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,pSRB->EndMessage,CHECK_CONDITION);
	    
	goto ckc_e;
    }

//***********************************************************
    if( status )
    {
	/*
	** target status..........................
	*/
	if( status_byte(status) == CHECK_CONDITION )
	{
	    DC395x_RequestSense( pACB, pDCB, pSRB );
	    return;
	}
	else if( status_byte(status) == QUEUE_FULL )
	{
	    tempcnt = (BYTE) pDCB->GoingSRBCnt;
	    printk ("\nDC395x:  QUEUE_FULL for dev %02i-%i with %i cmnds\n",
		    pDCB->TargetID, pDCB->TargetLUN, tempcnt);
	    if (tempcnt > 1) tempcnt--;
	    pDCB->MaxCommand = tempcnt;
	    DC395x_freetag (pDCB, pSRB);
	    DC395x_Going_to_Waiting ( pDCB, pSRB );
	    DC395x_waiting_timer (pACB, HZ/20);
	    pSRB->AdaptStatus = 0;
	    pSRB->TargetStatus = 0;
	    return;
	}
	else if(status == SCSI_STAT_SEL_TIMEOUT)
	{
	    pSRB->AdaptStatus = H_SEL_TIMEOUT;
	    pSRB->TargetStatus = 0;
	    pcmd->result = DID_NO_CONNECT << 16;
	}
	else if (status_byte(status) == BUSY && 
		 (pcmd->cmnd[0] == TEST_UNIT_READY || pcmd->cmnd[0] == INQUIRY) &&
		 pACB->scan_devices)
	{
	    pSRB->AdaptStatus = 0;
	    pSRB->TargetStatus = status;
	    pcmd->result = MK_RES(0,0,pSRB->EndMessage,status);
	}
	else
	{
	    pSRB->AdaptStatus = 0;
	    SET_RES_DID(pcmd->result,DID_ERROR);
	    SET_RES_MSG(pcmd->result,pSRB->EndMessage);
	    SET_RES_TARGET(pcmd->result,status);
	} 
    }
    else
    {
	/*
	** process initiator status..........................
	*/
	status = pSRB->AdaptStatus;
	if(status & H_OVER_UNDER_RUN)
	{
	    pSRB->TargetStatus = 0;
	    SET_RES_DID(pcmd->result,DID_OK);
	    SET_RES_MSG(pcmd->result,pSRB->EndMessage);
	}
	else if( pSRB->SRBStatus & PARITY_ERROR)
	{
	    SET_RES_DID(pcmd->result,DID_PARITY);
	    SET_RES_MSG(pcmd->result,pSRB->EndMessage);
	}
	else  /* No error */
	{
	    pSRB->AdaptStatus = 0;
	    pSRB->TargetStatus = 0;
	    SET_RES_DID(pcmd->result,DID_OK);
	}
    }

    if (pcmd->use_sg && dir != PCI_DMA_NONE)
	    PCI_DMA_SYNC_SG(pACB->pdev, (struct scatterlist*)pcmd->request_buffer,
			    pcmd->use_sg, dir);
    else if (pcmd->request_buffer && dir != PCI_DMA_NONE)
	    PCI_DMA_SYNC_SINGLE(pACB->pdev, pSRB->SegmentX[0].address,
			    pcmd->request_bufflen, dir);
    if ((pcmd->result & RES_DID) == 0 &&
	pcmd->cmnd[0] == INQUIRY && 
	pcmd->cmnd[2] == 0 &&
	pcmd->request_bufflen >= 8 &&
	dir != PCI_DMA_NONE &&
	ptr &&
	(ptr->Vers & 0x07) >= 2)
		pDCB->Inquiry7 = ptr->Flags;
/* Check Error Conditions */
ckc_e:
    if( pACB->scan_devices )
    {
	if( pcmd->cmnd[0] == TEST_UNIT_READY ||
	    pcmd->cmnd[0] == INQUIRY)
	{
#ifdef DC395x_DEBUG_KG
	    printk ("\nDC395x:  %s: result: %08x",
		    (pcmd->cmnd[0] == INQUIRY? "INQUIRY": "TEST_UNIT_READY"),
		    pcmd->result);
	    if (pcmd->result & (DRIVER_SENSE << 24)) printk (" (sense: %02x %02x %02x %02x)\n",
				   pcmd->sense_buffer[0], pcmd->sense_buffer[1],
				   pcmd->sense_buffer[2], pcmd->sense_buffer[3]);
	    else printk ("\n");
#endif
	    if( (!(host_byte(pcmd->result) == DID_OK) && 
		 !(status_byte(pcmd->result) & CHECK_CONDITION) && 
		 !(status_byte(pcmd->result) & BUSY))
	       ||
	       ((driver_byte(pcmd->result) & DRIVER_SENSE) && 
	        (pcmd->sense_buffer[0] & 0x70) == 0x70 &&
		(pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) 
	       || host_byte(pcmd->result) & DID_ERROR )
	    {
	       /* device not present: remove */ 
	       DC395x_remove_dev (pACB, pDCB); DCB_removed = 1;
	       
	       if( (pcmd->target == pACB->pScsiHost->max_id - 1) &&
		  ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1)) )
		 pACB->scan_devices = 0;
	    }
	    else
	    {
	        /* device present: add */
		if( (pcmd->target == pACB->pScsiHost->max_id - 1) && 
		    (pcmd->lun == pACB->pScsiHost->max_lun - 1) )
		    pACB->scan_devices = DC395x_END_SCAN ;
	        /* pACB->DeviceCnt++; */ /* Dev is added on INQUIRY */
	    }
	}
    }
   
    //if( pSRB->pcmd->cmnd[0] == INQUIRY && 
    //  (host_byte(pcmd->result) == DID_OK || status_byte(pcmd->result) & CHECK_CONDITION) )
    if( pcmd->cmnd[0] == INQUIRY && 
	(pcmd->result == (DID_OK << 16) || status_byte(pcmd->result) & CHECK_CONDITION) )
     {
	DEBUG0(int i;)
#ifdef DC395x_DEBUG0
	printk ("DC395x:  Inquiry result:");
	for (i = 0; i < 8; i++) 
		printk (" %02x", ((PBYTE)ptr)[i]);
	((PBYTE)ptr)[96] = 0;
	printk ("DC395x:  %s\n", (char*)ptr + 8);
#endif
	if ( (ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2 )
		pDCB->Inquiry7 = ptr->Flags;
	if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV && !DCB_removed)
	  {
#ifdef DC395x_DEBUG_KG		  
	     printk ("\nDC395x:  Device %02i-%i: TYPE_NODEV?\n",
		     pDCB->TargetID, pDCB->TargetLUN);
#endif
	     /* device not present: remove */
	     DC395x_remove_dev (pACB, pDCB);
	     DCB_removed = 1;
	  }
	else
	  {
	     /* device found: add */ 
	     DC395x_add_dev (pACB, pDCB, ptr);
	     if (pACB->scan_devices) pACB->DeviceCnt++;
	  }
	if( (pcmd->target == pACB->pScsiHost->max_id - 1) &&
	    (pcmd->lun == pACB->pScsiHost->max_lun - 1) )
	  pACB->scan_devices = 0;
     };

    /* Here is the info for Doug Gilbert's sg3 ... */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,30)
    pcmd->resid = pSRB->SRBTotalXferLength;
#endif
    /* This may be interpreted by sb. or not ... */
    pcmd->SCp.this_residual = pSRB->SRBTotalXferLength;
    pcmd->SCp.buffers_residual = 0;
#ifdef DC395x_DEBUG_KG
    if (pSRB->SRBTotalXferLength && !DCB_removed)
	printk ("\nDC395x:  pid %li: %02x (%02i-%i): Missed %i bytes\n",
		pcmd->pid, pcmd->cmnd[0], pcmd->target, pcmd->lun, pSRB->SRBTotalXferLength);
#endif
    if (!DCB_removed) DC395x_Going_remove (pDCB, pSRB, 0);
    /* Add to free list */
    if (pSRB == pACB->pTmpSRB)
	printk ("\nDC395x:  ERROR! Completed Cmnd with TmpSRB!\n");
    else
	DC395x_Free_insert (pACB, pSRB);

    DEBUG0(printk (KERN_DEBUG "DC395x:  SRBdone: done pid %li\n", pcmd->pid);)
#ifdef DC395x_DEBUG_KG
    printk (" 0x%08x\n", pcmd->result);
#endif
    TRACEPRINTF("%08x(%li)*", pcmd->result, jiffies);
    DC395x_pci_unmap (pACB, pSRB);
    //DC395x_UNLOCK_ACB_NI;
    pcmd->scsi_done (pcmd);
    //DC395x_LOCK_ACB_NI;
    TRACEOUTALL (KERN_INFO " %s\n", pSRB->debugtrace);

    DC395x_Query_to_Waiting (pACB);
    DC395x_Waiting_process (pACB);
    return;
}

/*
*********************************************************************
** scsiio
**		DC395x_reset
** abort all cmds in our queues
*********************************************************************
*/
void DC395x_DoingSRB_Done( PACB pACB, BYTE did_flag, 
			   Scsi_Cmnd *cmd, BYTE force )
{
    PDCB     pDCB;
    PSRB     pSRB, pSRBTemp;
    WORD     cnt;
    PSCSICMD pcmd;

    pDCB = pACB->pLinkDCB;
    if (!pDCB) return;
    printk(KERN_INFO "DC395x_DoingSRB_Done: pids ");
    do
    {
	/* As the ML may queue cmnds again, cache old values */
	PSRB pWaitingSRB = pDCB->pWaitingSRB;
	//PSRB pWaitLast = pDCB->pWaitLast;
	WORD WaitSRBCnt = pDCB->WaitSRBCnt;
	/* Going queue */
	cnt = pDCB->GoingSRBCnt;
	pSRB = pDCB->pGoingSRB;
	while (cnt--)
	{
	    int result;
	    int dir;
	    pSRBTemp = pSRB->pNextSRB;
	    pcmd = pSRB->pcmd;
	    SET_DIR(dir,pcmd);
	    result = MK_RES(0,did_flag,0,0);
	    //result = MK_RES(0,DID_RESET,0,0);
	    TRACEPRINTF ("Reset(%li):%08x*", jiffies, result);
	    printk (" (G)");
#if 1//ndef DC395x_DEBUGTRACE
	    printk ("%li(%02i-%i) ", pcmd->pid, pcmd->target, pcmd->lun);
#endif
	    TRACEOUT ("%s\n", pSRB->debugtrace);
	    pDCB->pGoingSRB = pSRBTemp;  pDCB->GoingSRBCnt--;
	    if (!pSRBTemp) pDCB->pGoingLast = NULL;
	    DC395x_freetag (pDCB, pSRB);
	    DC395x_Free_insert (pACB, pSRB);
	    pcmd->result = result;
	    DC395x_pci_unmap_sense (pACB, pSRB);
	    DC395x_pci_unmap (pACB, pSRB);
#ifdef USE_NEW_EH
	    if (force) {
	    /* For new EH, we normally don't need to give commands back,
	     * as they all complete or all time out */
#endif
	    /* do we need the aic7xxx hack and conditionally decrease retry ? */
	    //DC395x_SCSI_DONE_ACB_UNLOCK;
	    pcmd->scsi_done( pcmd );
	    //DC395x_SCSI_DONE_ACB_LOCK;
#ifdef USE_NEW_EH
	    }
#endif
	    pSRB = pSRBTemp;
	}
	if (pDCB->pGoingSRB) 
		printk ("DC395x: How could the ML send cmnds to the Going queue? (%02i-%i)!!\n",
			pDCB->TargetID, pDCB->TargetLUN);
	if (pDCB->TagMask)
		printk ("DC395x: TagMask for %02i-%i should be empty, is %08x!\n",
			pDCB->TargetID, pDCB->TargetLUN, pDCB->TagMask);
	//pDCB->GoingSRBCnt = 0;;
	//pDCB->pGoingSRB = NULL; pDCB->pGoingLast = NULL;

	/* Waiting queue */
	cnt = WaitSRBCnt;
	pSRB = pWaitingSRB;
	while (cnt--)
	{
	    int result;
	    pSRBTemp = pSRB->pNextSRB;
	    pcmd = pSRB->pcmd;
	    result = MK_RES(0,did_flag,0,0);
	    TRACEPRINTF ("Reset(%li):%08x*", jiffies, result);
	    printk (" (W)");
#if 1//ndef DC395x_DEBUGTRACE
	    printk ("%li(%i-%i)", pcmd->pid, pcmd->target, pcmd->lun);
#endif
	    TRACEOUT ("%s\n", pSRB->debugtrace);
	    pDCB->pWaitingSRB = pSRBTemp; pDCB->WaitSRBCnt--;
	    if (!pSRBTemp) pDCB->pWaitLast = NULL;
	    DC395x_Free_insert (pACB, pSRB);

	    pcmd->result = result;
	    DC395x_pci_unmap_sense (pACB, pSRB);
	    DC395x_pci_unmap (pACB, pSRB);
#ifdef USE_NEW_EH
	    if (force) {
	    /* For new EH, we normally don't need to give commands back,
	     * as they all complete or all time out */
#endif
	    /* do we need the aic7xxx hack and conditionally decrease retry ? */
	    //DC395x_SCSI_DONE_ACB_UNLOCK;
	    pcmd->scsi_done( pcmd );
	    //DC395x_SCSI_DONE_ACB_LOCK;
	    pSRB = pSRBTemp;
#ifdef USE_NEW_EH		    
	    }
#endif
	}
	if (pDCB->WaitSRBCnt) 
		printk ("\nDC395x: Debug: ML queued %i cmnds again to %02i-%i\n",
			pDCB->WaitSRBCnt, pDCB->TargetID, pDCB->TargetLUN);
	/* The ML could have queued the cmnds again! */
	//pDCB->WaitSRBCnt = 0;;
	//pDCB->pWaitingSRB = NULL; pDCB->pWaitLast = NULL;
	pDCB->DCBFlag &= ~ABORT_DEV_;
	pDCB = pDCB->pNextDCB;
    }
    while( pDCB != pACB->pLinkDCB && pDCB );
    printk ("\n");
}

/*
*********************************************************************
** scsiio
**		DC395x_shutdown   DC395x_reset
**
*********************************************************************
*/
static void DC395x_ResetSCSIBus( PACB pACB )
{
    //DWORD  drv_flags=0;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_ResetSCSIBus..............\n ");
#endif
    
    //DC395x_DRV_LOCK(drv_flags);
    pACB->ACBFlag |= RESET_DEV; /* RESET_DETECT, RESET_DONE, RESET_DEV */
 
    DC395x_write16(TRM_S1040_SCSI_CONTROL,DO_RSTSCSI);
    while (!( DC395x_read8(TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET ));
	
    //DC395x_DRV_UNLOCK(drv_flags);
    return;
}

/* Set basic config */
static void DC395x_basic_config (PACB pACB)
{
    BYTE bval; WORD wval;
    DC395x_write8 (TRM_S1040_SCSI_TIMEOUT, pACB->sel_timeout);
    if (pACB->Config & HCC_PARITY)
	bval = PHASELATCH | INITIATOR | BLOCKRST | PARITYCHECK;
    else
	bval = PHASELATCH | INITIATOR | BLOCKRST;

    DC395x_write8 (TRM_S1040_SCSI_CONFIG0, bval);

    /* program configuration 1: Act_Neg (+ Act_Neg_Enh? + Fast_Filter? + DataDis?) */
    DC395x_write8(TRM_S1040_SCSI_CONFIG1, 0x03); /* was 0x13: default */
    /* program Host ID		        */
    DC395x_write8(TRM_S1040_SCSI_HOSTID, pACB->pScsiHost->this_id);
    /* set ansynchronous transfer	*/
    DC395x_write8(TRM_S1040_SCSI_OFFSET, 0x00);
    /* Turn LED control off*/
    wval = DC395x_read16 (TRM_S1040_GEN_CONTROL) & 0x7F;
    DC395x_write16(TRM_S1040_GEN_CONTROL, wval);
    /* DMA config          */
    wval = DC395x_read16(TRM_S1040_DMA_CONFIG) & ~DMA_FIFO_CTRL;
    wval |= DMA_FIFO_HALF_HALF | DMA_ENHANCE /*| DMA_MEM_MULTI_READ*/;
    //printk ("DC395: DMA_Config: %04x\n", wval);
    DC395x_write16(TRM_S1040_DMA_CONFIG,wval); 
    /* Clear pending interrupt status*/
    DC395x_read8(TRM_S1040_SCSI_INTSTATUS);
    /* Enable SCSI interrupt	*/
    DC395x_write8(TRM_S1040_SCSI_INTEN,0x7F); 
    DC395x_write8(TRM_S1040_DMA_INTEN, EN_SCSIINTR | EN_DMAXFERERROR /*| EN_DMAXFERABORT | EN_DMAXFERCOMP | EN_FORCEDMACOMP */);
}

/*
*********************************************************************
** scsiio
**		DC395x_Interrupt
**
*********************************************************************
*/
static void DC395x_ScsiRstDetect( PACB pACB )
{
    printk (KERN_INFO "DC395x_ScsiRstDetect\n");
    /* delay half a second */
    if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer);

    DC395x_write8(TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
    DC395x_write8(TRM_S1040_DMA_CONTROL, DMARESETMODULE);
    //DC395x_write8(TRM_S1040_DMA_CONTROL,STOPDMAXFER);
    udelay (500);
    // Maybe we locked up the bus? Then lets wait even longer ...
    pACB->pScsiHost->last_reset = jiffies + 5*HZ/2 +
		HZ * dc395x_trm_eepromBuf[pACB->AdapterIndex].NvramDelayTime;

    DC395x_clrfifo (pACB, "RstDet");
    DC395x_basic_config (pACB);
    //1.25
    //DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_HWRESELECT);

    if( pACB->ACBFlag & RESET_DEV ) /* RESET_DETECT, RESET_DONE, RESET_DEV */
    {
	pACB->ACBFlag |= RESET_DONE;
    }
    else
    {
	pACB->ACBFlag |= RESET_DETECT;
	DC395x_ResetDevParam( pACB );
	DC395x_DoingSRB_Done( pACB, DID_RESET, 0, 1 );
	//DC395x_RecoverSRB( pACB );
	pACB->pActiveDCB = NULL;
	pACB->ACBFlag = 0;
	DC395x_Waiting_process( pACB );
    }

    return;
}

/*
*********************************************************************
** scsiio
**		DC395x_SRBdone
** 
*********************************************************************
*/
static void DC395x_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB )
{
    PSCSICMD  pcmd;

    pcmd = pSRB->pcmd;
#ifdef DC395x_DEBUG_KG
    printk(KERN_INFO "DC395x_RequestSense for pid %li, target %02i-%i\n",
	   pcmd->pid, pcmd->target, pcmd->lun);
#endif
    TRACEPRINTF ("RqSn*");
    pSRB->SRBFlag |= AUTO_REQSENSE;
    pSRB->AdaptStatus = 0;
    pSRB->TargetStatus = 0;

    /* KG: Can this prevent crap sense data ? */
    memset (pcmd->sense_buffer, 0, sizeof(pcmd->sense_buffer));

    /* Save some data */
    pSRB->SegmentX[DC395x_MAX_SG_LISTENTRY-1].address = pSRB->SegmentX[0].address;
    pSRB->SegmentX[DC395x_MAX_SG_LISTENTRY-1].length  = pSRB->SegmentX[0].length;
    pSRB->Xferred = pSRB->SRBTotalXferLength;
    /* pSRB->SegmentX : a one entry of S/G list table */
    pSRB->SRBTotalXferLength  = sizeof(pcmd->sense_buffer);
    pSRB->SegmentX[0].length  = sizeof(pcmd->sense_buffer);
    /* Map sense buffer */
    pSRB->SegmentX[0].address = PCI_MAP_SINGLE(pACB->pdev, pcmd->sense_buffer,
					       sizeof(pcmd->sense_buffer), PCI_DMA_FROMDEVICE);
#ifdef DC395x_SGPARANOIA
    printk ("DC395x: Map sense buffer at %p (%05x) to %08x\n",
	    pcmd->sense_buffer, sizeof(pcmd->sense_buffer), 
	    pSRB->SegmentX[0].address);
#endif
    pSRB->SRBSGCount = 1;
    pSRB->SRBSGIndex = 0;

    if( DC395x_StartSCSI( pACB, pDCB, pSRB ) )
    {	/* Should only happen, if sb. else grabs the bus */
	printk ("DC395x: Request Sense failed for pid %li (%02i-%i)!\n",
		pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN);
	TRACEPRINTF ("?*");
	DC395x_Going_to_Waiting (pDCB, pSRB);
	DC395x_waiting_timer (pACB, HZ/100);
    }
    TRACEPRINTF (".*");
}

#if 0
/*
*********************************************************************
** scsiio
**		DC395x_MsgInPhase0   DC395x_EnableMsgOutAbort1
**
*********************************************************************
*/
static void DC395x_EnableMsgOutAbort2( PACB pACB, PSRB pSRB )
{
#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_EnableMsgOutAbort2..............\n ");
#endif
    pSRB->MsgCnt = 1;
    DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_SETATN);
}

/*
*********************************************************************
** scsiio
**	DC395x_Reselect DC395x_Interrupt DC395x_MsgInPhase0
**
*********************************************************************
*/
static inline void DC395x_EnableMsgOutAbort1( PACB pACB, PSRB pSRB )
{
#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_EnableMsgOutAbort1..............\n ");
#endif
    pSRB->MsgOutBuf[0] = MSG_ABORT;
    DC395x_EnableMsgOutAbort2( pACB, pSRB );
}
#endif

/*
**********************************************************************
**		DC395x_queue_command
**
** Function : void DC395x_initDCB
**  Purpose : initialize the internal structures for a given DCB
**   Inputs : cmd - pointer to this scsi cmd request block structure
**
**********************************************************************
*/
void DC395x_initDCB( PACB pACB, PDCB *ppDCB, BYTE target, BYTE lun)
{
    PNVRAMTYPE	pEEpromBuf;
    BYTE	PeriodIndex;
    WORD	index;
    PDCB pDCB, pDCB2;

#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x_initDCB..............\n ");
#endif
    pDCB = KMALLOC (sizeof(DC395X_TRM_DCB), GFP_ATOMIC);
    //pDCB = DC395x_findDCB (pACB, target, lun);
    *ppDCB = pDCB; pDCB2 = 0;
    if (!pDCB) return;

    if( pACB->DCBCnt == 0 )
    {
	pACB->pLinkDCB = pDCB;
	pACB->pDCBRunRobin = pDCB;
    }
    else
    {
	pACB->pLastDCB->pNextDCB = pDCB;
    };

    pACB->DCBCnt++;
    pDCB->pNextDCB = pACB->pLinkDCB;
    pACB->pLastDCB = pDCB;
	
    /* $$$$$$$ */
    pDCB->pDCBACB = pACB;
    pDCB->TargetID = target;
    pDCB->TargetLUN = lun;
    /* $$$$$$$ */
    pDCB->pWaitingSRB = NULL;
    pDCB->pGoingSRB = NULL;
    pDCB->GoingSRBCnt = 0;
    pDCB->WaitSRBCnt = 0;
    pDCB->pActiveSRB = NULL;
    /* $$$$$$$ */
    pDCB->TagMask = 0;
    pDCB->DCBFlag = 0;
    pDCB->MaxCommand = 1;
    pDCB->AdaptIndex = pACB->AdapterIndex;
    /* $$$$$$$ */
    index = pACB->AdapterIndex;
    pEEpromBuf = &dc395x_trm_eepromBuf[index];
    pDCB->DevMode = pEEpromBuf->NvramTarget[target].NvmTarCfg0;
    //pDCB->AdpMode = pEEpromBuf->NvramChannelCfg;
    pDCB->Inquiry7 = 0;
    pDCB->SyncMode = 0;
    pDCB->last_derated = pACB->pScsiHost->last_reset - 2;
    /* $$$$$$$ */
    pDCB->SyncPeriod = 0;
    pDCB->SyncOffset = 0;
    PeriodIndex = pEEpromBuf->NvramTarget[target].NvmTarPeriod & 0x07;
    pDCB->MinNegoPeriod = dc395x_clock_period[ PeriodIndex ] ;
	
#ifndef DC395x_NO_WIDE
    if ((pDCB->DevMode & NTC_DO_WIDE_NEGO) && (pACB->Config & HCC_WIDE_CARD))
	pDCB->SyncMode |= WIDE_NEGO_ENABLE;
#endif
#ifndef DC395x_NO_SYNC
    if (pDCB->DevMode & NTC_DO_SYNC_NEGO)
	if( !(lun) || DC395x_CurrSyncOffset )
		pDCB->SyncMode |= SYNC_NEGO_ENABLE;
#endif
    /* $$$$$$$ */
#ifndef DC395x_NO_DISCONNECT
    pDCB->IdentifyMsg = IDENTIFY(pDCB->DevMode & NTC_DO_DISCONNECT, lun);
#else
    pDCB->IdentifyMsg = IDENTIFY(0, lun);
#endif
    /* $$$$$$$ */
    if (pDCB->TargetLUN != 0)
    {
	/* Copy settings */
	PDCB prevDCB = pACB->pLinkDCB;
	while (prevDCB->TargetID != pDCB->TargetID) 
	    prevDCB = prevDCB->pNextDCB;
#ifdef DC395x_DEBUG_KG
        printk ("DC395x: Copy settings from %02i-%02i to %02i-%02i\n",
		prevDCB->TargetID, prevDCB->TargetLUN,
		pDCB->TargetID, pDCB->TargetLUN);
#endif
	pDCB->SyncMode   = prevDCB->SyncMode;
	pDCB->SyncPeriod = prevDCB->SyncPeriod;
	pDCB->MinNegoPeriod = prevDCB->MinNegoPeriod;
	pDCB->SyncOffset = prevDCB->SyncOffset;
	pDCB->Inquiry7 = prevDCB->Inquiry7;
    };

    pACB->DCBmap[target] |= (1 << lun);
}


/* Dynamically allocated memory handling */

#ifdef DC395x_DEBUGTRACE
/* Memory for trace buffers */
void DC395x_free_tracebufs (PACB pACB, int SRBIdx)
{
	int srbidx;
	const unsigned bufs_per_page = PAGE_SIZE/DEBUGTRACEBUFSZ;
	for (srbidx = 0; srbidx < SRBIdx; srbidx += bufs_per_page) {
		//printk ("DC395x: Free tracebuf %p (for %i)\n",
		//	pACB->SRB_array[srbidx].debugtrace, srbidx);
		KFREE (pACB->SRB_array[srbidx].debugtrace);
	}
}

int DC395x_alloc_tracebufs (PACB pACB)
{
	const unsigned mem_needed = (DC395x_MAX_SRB_CNT + 1) * DEBUGTRACEBUFSZ;
	int pages = (mem_needed + (PAGE_SIZE-1)) / PAGE_SIZE;
	const unsigned bufs_per_page = PAGE_SIZE/DEBUGTRACEBUFSZ;
	int SRBIdx = 0; unsigned i = 0;
	unsigned char *ptr;
	//printk ("DC395x: Alloc %i pages for tracebufs\n", pages);
	while (pages--) {
		ptr = KMALLOC (PAGE_SIZE, GFP_KERNEL);
		if (!ptr) {
			DC395x_free_tracebufs (pACB, SRBIdx);
			return 1;
		}
		//printk ("DC395x: Alloc %li bytes at %p for tracebuf %i\n",
		//	PAGE_SIZE, ptr, SRBIdx);
		i = 0;
		while (i < bufs_per_page && SRBIdx < DC395x_MAX_SRB_CNT)
			pACB->SRB_array[SRBIdx++].debugtrace
				= ptr + (i++*DEBUGTRACEBUFSZ);
	}
	if (i < bufs_per_page) {
		pACB->TmpSRB.debugtrace = ptr + (i*DEBUGTRACEBUFSZ);
		pACB->TmpSRB.debugtrace[0] = 0;
	} else
		printk ("DC395x: No space for tmpSRB tracebuf reserved?!\n");
	return 0;
}
#endif

/* Free SG tables */
void DC395x_free_SG_tables (PACB pACB, int SRBIdx)
{
	int srbidx;
	const unsigned SRBs_per_page = PAGE_SIZE/(DC395x_MAX_SG_LISTENTRY * sizeof(SGentry));
	for (srbidx = 0; srbidx < SRBIdx; srbidx += SRBs_per_page) {
		//printk ("DC395x: Free SG segs %p (for %i)\n",
		//	pACB->SRB_array[srbidx].SegmentX, srbidx);
		KFREE (pACB->SRB_array[srbidx].SegmentX);
	}
}

/* Allocate SG tables; as we have to pci_map them, an SG list (PSGE0)
 * should never cross a page boundary */
int DC395x_alloc_SG_tables (PACB pACB)
{
	const unsigned mem_needed = (DC395x_MAX_SRB_CNT + 1) 
		* DC395x_MAX_SG_LISTENTRY * sizeof(SGentry);
	int pages = (mem_needed + (PAGE_SIZE-1)) / PAGE_SIZE;
	const unsigned SRBs_per_page = PAGE_SIZE 
		/ (DC395x_MAX_SG_LISTENTRY * sizeof(SGentry));
	int SRBIdx = 0; unsigned i = 0;
	PSGE0 ptr;
	//printk ("DC395x: Alloc %i pages for SG tables\n", pages);
	while (pages--) {
		ptr = (PSGE0) KMALLOC (PAGE_SIZE, GFP_KERNEL);
		if (!ptr) {
			DC395x_free_SG_tables (pACB, SRBIdx);
			return 1;
		}
		//printk ("DC395x: Alloc %li bytes at %p for SG segments %i\n",
		//	PAGE_SIZE, ptr, SRBIdx);
		i = 0;
		while (i < SRBs_per_page && SRBIdx < DC395x_MAX_SRB_CNT)
			pACB->SRB_array[SRBIdx++].SegmentX 
				= ptr + (i++*DC395x_MAX_SG_LISTENTRY);
	}
	if (i < SRBs_per_page)
		pACB->TmpSRB.SegmentX = ptr + (i*DC395x_MAX_SG_LISTENTRY);
	else
		printk ("DC395x: No space for tmpSRB SG table reserved?!\n");
	return 0;
}


/*
*********************************************************************
** scsiio
**		DC395x_initACB
**
*********************************************************************
*/
void __init DC395x_linkSRB( PACB pACB )
{
    int i;

    for( i=0; i < pACB->SRBCount - 1; i++)
	pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1];
    pACB->SRB_array[i].pNextSRB = NULL;
    //DC395x_Free_integrity (pACB);	
}


/*
************************************************************************
**		DC395x_init
**
** Function : static void DC395x_initACB
**  Purpose :  initialize the internal structures for a given SCSI host
**   Inputs : psh - pointer to this host adapter's structure
**
************************************************************************
*/
int __init DC395x_initACB( PSH psh, DWORD io_port, BYTE Irq, WORD index )
{
    PNVRAMTYPE pEEpromBuf;
    PACB       pACB;
    WORD       i;

    pEEpromBuf = &dc395x_trm_eepromBuf[index];
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
    psh->max_cmd_len = 24;
#endif
    psh->can_queue = DC395x_MAX_CMD_QUEUE;
    psh->cmd_per_lun = DC395x_MAX_CMD_PER_LUN;
    psh->this_id = (int) pEEpromBuf->NvramScsiId;
    psh->io_port = io_port;
    psh->n_io_port = 0x80;
    psh->dma_channel = -1;
    psh->unique_id = io_port;
    psh->irq = Irq;
    psh->last_reset = jiffies;
	
    pACB = (PACB) psh->hostdata;

    psh->max_id = 16;
    if( psh->max_id - 1 == pEEpromBuf->NvramScsiId )
	psh->max_id--;
#ifdef	CONFIG_SCSI_MULTI_LUN
    if( pEEpromBuf->NvramChannelCfg & NAC_SCANLUN )
	psh->max_lun =8;
    else
	psh->max_lun =1;
#else 
    psh->max_lun =1;
#endif
    /*
     ********************************
     */
    pACB->pScsiHost = psh;
    pACB->IOPortBase = (WORD) io_port;
    pACB->pLinkDCB = NULL;
    pACB->pDCBRunRobin = NULL;
    pACB->pActiveDCB = NULL;
    pACB->SRBCount = DC395x_MAX_SRB_CNT;
    pACB->AdapterIndex = index;
    pACB->status = 0;
    pACB->pScsiHost->this_id = pEEpromBuf->NvramScsiId;
    pACB->HostID_Bit = (1 << pACB->pScsiHost->this_id);
    //pACB->pScsiHost->this_lun = 0;
    pACB->DCBCnt = 0; pACB->DeviceCnt = 0;
    pACB->IRQLevel = Irq;
    pACB->TagMaxNum = 1 << pEEpromBuf->NvramMaxTag;
    if (pACB->TagMaxNum > 30) pACB->TagMaxNum = 30;
    pACB->ACBFlag = 0;  /* RESET_DETECT, RESET_DONE, RESET_DEV */
    pACB->scan_devices = 1;
    pACB->MsgLen = 0;
    pACB->Gmode2 = pEEpromBuf->NvramChannelCfg;
    if( pEEpromBuf->NvramChannelCfg & NAC_SCANLUN )
	pACB->LUNchk = 1;
    /* 
     ** link all device's SRB Q of this adapter 
     */	

    if (DC395x_alloc_SG_tables (pACB)) {
	    printk ("DC395x: SG table allocation failed!\n");
	    return 1;
    }
#ifdef DC395x_DEBUGTRACE
    if (DC395x_alloc_tracebufs (pACB)) {
	    printk ("DC395x: SG trace buffer allocation failed!\n");
	    DC395x_free_SG_tables (pACB, DC395x_MAX_SRB_CNT);
	    return 1;
    }
#endif
    DC395x_linkSRB( pACB );
    pACB->pFreeSRB = pACB->SRB_array;
    /* 
     ** temp SRB for Q tag used or abort command used 
     */
    pACB->pTmpSRB = &pACB->TmpSRB;
    pACB->TmpSRB.pSRBDCB = 0;
    pACB->TmpSRB.pNextSRB = 0;
    init_timer (&pACB->Waiting_Timer);

    for (i = 0; i < DC395x_MAX_SCSI_ID; i++)
	pACB->DCBmap[i] = 0;
#ifdef DC395x_DEBUG0
    printk(KERN_INFO "DC395x: pACB = %p, pDCBmap = %p, pSRB_array = %p\n", 
	   pACB, pACB->DCBmap, pACB->SRB_array);
    printk(KERN_INFO "DC395x: ACB size= %04lx, DCB size= %04lx, SRB size= %04lx\n",
	   sizeof(DC395X_TRM_ACB), sizeof(DC395X_TRM_DCB), sizeof(DC395X_TRM_SRB) );
#endif
    return 0;
}


/*
**********************************************************************
** 
**		DC395x_init
**
** Function : static int DC395x_initAdapter
** Purpose  : initialize the SCSI chip ctrl registers
** Inputs   : psh - pointer to this host adapter's structure
**
**********************************************************************
*/
int __init DC395x_initAdapter( PSH psh, DWORD io_port, BYTE Irq, WORD index )
{
    PNVRAMTYPE pEEpromBuf;
    PACB       pACB, pTempACB;
    WORD       used_irq = 0;

    pEEpromBuf = &dc395x_trm_eepromBuf[index];
    pTempACB = DC395x_pACB_start;
    if( pTempACB != NULL )
    {
	for ( ; (pTempACB != (PACB) -1) ; )
	{
	    if( pTempACB->IRQLevel == Irq )
	    {
		used_irq = 1;
		break;
	    }
	    else
		pTempACB = pTempACB->pNextACB;
	}
    }
    if (check_region (io_port, psh->n_io_port))
    {
	printk(KERN_ERR "DC395x: register IO ports error!\n");
	return( -1 );
    }
    else
    {
	/* %%%%%%%%%%%%% */
	request_region(io_port,psh->n_io_port,"DC395x_TRM");
	/* %%%%%%%%%%%%% */
    }

    if( !used_irq )
    {
	/*
	** If request_irq() fails with the SA_INTERRUPT flag set,
	** then try again without the SA_INTERRUPT flag set. This
	** allows IRQ sharing to work even with other drivers that
	** do not set the SA_INTERRUPT flag.
	**
	** If SA_INTERRUPT is not set, then interrupts are enabled
	** before the driver interrupt function is called.
	*/

	if( request_irq(Irq, DC395x_Interrupt, SA_SHIRQ, "DC395x_TRM", (void*)psh->hostdata) )
	{
	    printk(KERN_INFO "DC395x: register IRQ error!\n");
	    return( -1 );
	}
    }
    pACB = (PACB) psh->hostdata;
    pACB->IOPortBase = io_port;
    /* selection timeout = 250 ms	*/
    pACB->sel_timeout = DC395x_SEL_TIMEOUT;
    /* Mask all the interrupt       */
    DC395x_write8(TRM_S1040_DMA_INTEN,0x00);    
    DC395x_write8(TRM_S1040_SCSI_INTEN,0x00);     
    /* Reset SCSI module		*/
    DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
    /* Reset PCI/DMA module		*/
    DC395x_write8 (TRM_S1040_DMA_CONTROL, DMARESETMODULE);
    udelay (20);
    /* program configuration 0	*/
    pACB->Config = HCC_AUTOTERM | HCC_PARITY;
    if ( DC395x_read8(TRM_S1040_GEN_STATUS) & WIDESCSI )
	pACB->Config |= HCC_WIDE_CARD;
    if (pEEpromBuf->NvramChannelCfg & NAC_POWERON_SCSI_RESET)
	pACB->Config |= HCC_SCSI_RESET;
    if (pACB->Config & HCC_SCSI_RESET)
    {
	printk (KERN_INFO "DC395: Performing initial SCSI bus reset\n");
	DC395x_write8 (TRM_S1040_SCSI_CONTROL, DO_RSTSCSI);
	//while (!( DC395x_read8(TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET ));
	//spin_unlock_irq (&io_request_lock);
	udelay (500);
	pACB->pScsiHost->last_reset = jiffies + HZ/2 + 
		HZ * dc395x_trm_eepromBuf[pACB->AdapterIndex].NvramDelayTime;
	//spin_lock_irq (&io_request_lock);
    }
    DC395x_basic_config (pACB);
    return(0);
}
/*
************************************************************************
**		DC395x_check_eeprom
**
**----------------------------------------------------------------------
** Function	    : TRM_S1040_write_all			
** Description	    : write pEEpromBuf 128 bytes to seeprom	
** Input	    : scsiIOPort - chip's base address		
** Output	    : none						
************************************************************************
*/
static void __init TRM_S1040_write_all(PNVRAMTYPE pEEpromBuf,WORD scsiIOPort)
{
    BYTE		*bpEeprom = (BYTE *) pEEpromBuf;
    BYTE		bAddr;

    /* Enable SEEPROM */
    outb( (inb(scsiIOPort+TRM_S1040_GEN_CONTROL) | EN_EEPROM) , scsiIOPort+TRM_S1040_GEN_CONTROL);
    /*
    ** Write enable
    */
    TRM_S1040_write_cmd(scsiIOPort, 0x04, 0xFF);
    outb( 0 , scsiIOPort+TRM_S1040_GEN_NVRAM );
    TRM_S1040_wait_30us(scsiIOPort);
    for (bAddr = 0; bAddr < 128; bAddr++, bpEeprom++)
    { 
	TRM_S1040_set_data(scsiIOPort, bAddr, *bpEeprom);
    }
    /* 
    ** Write disable
    */
    TRM_S1040_write_cmd(scsiIOPort, 0x04, 0x00);
    outb( 0 , scsiIOPort+TRM_S1040_GEN_NVRAM );
    TRM_S1040_wait_30us(scsiIOPort);
    /* Disable SEEPROM */
    outb( (inb(scsiIOPort+TRM_S1040_GEN_CONTROL) & ~EN_EEPROM) , scsiIOPort+TRM_S1040_GEN_CONTROL);
    return;
}
/*
***********************************************************************
**		TRM_S1040_write_all
**
**---------------------------------------------------------------------
** Function	    : TRM_S1040_set_data					
** Description	    : write one byte to seeprom
** Input	    : scsiIOPort - chip's base address	
**			bAddr - address of SEEPROM		
** 			bData - data of SEEPROM	
** Output   	    : none				
***********************************************************************
*/
static void __init TRM_S1040_set_data(WORD scsiIOPort, BYTE bAddr, BYTE bData)
{
    int		i;
    BYTE	bSendData;
    /* 
    ** Send write command & address	
    */
    TRM_S1040_write_cmd(scsiIOPort, 0x05, bAddr);
    /* 
    ** Write data 
    */
    for (i = 0; i < 8; i++, bData <<= 1)
    {
	bSendData = NVR_SELECT;
	if (bData & 0x80)		/* Start from bit 7	*/
	    bSendData |= NVR_BITOUT;

	outb( bSendData , scsiIOPort+TRM_S1040_GEN_NVRAM );
	TRM_S1040_wait_30us(scsiIOPort);
	outb( (bSendData | NVR_CLOCK) , scsiIOPort+TRM_S1040_GEN_NVRAM);
	TRM_S1040_wait_30us(scsiIOPort);
    }
    outb( NVR_SELECT , scsiIOPort+TRM_S1040_GEN_NVRAM);
    TRM_S1040_wait_30us(scsiIOPort);
    /*
    ** Disable chip select 
    */
    outb( 0 , scsiIOPort+TRM_S1040_GEN_NVRAM);
    TRM_S1040_wait_30us(scsiIOPort);
    outb( NVR_SELECT ,scsiIOPort+TRM_S1040_GEN_NVRAM);
    TRM_S1040_wait_30us(scsiIOPort);
    /* 
    ** Wait for write ready	
    */
    while (1)
    {
	outb( (NVR_SELECT | NVR_CLOCK) , scsiIOPort+TRM_S1040_GEN_NVRAM);
	TRM_S1040_wait_30us(scsiIOPort);
	outb( NVR_SELECT , scsiIOPort+TRM_S1040_GEN_NVRAM);
	TRM_S1040_wait_30us(scsiIOPort);
	if (inb(scsiIOPort+TRM_S1040_GEN_NVRAM) & NVR_BITIN)
	    break;
    }
    /* 
    ** Disable chip select 
    */
    outb( 0 , scsiIOPort+TRM_S1040_GEN_NVRAM);
    return;
}
/*
************************************************************************
**		DC395x_check_eeprom
**
**----------------------------------------------------------------------
** Function 	: TRM_S1040_read_all					
** Description	: read seeprom 128 bytes to pEEpromBuf
** Input    	: pEEpromBuf,scsiIOPort - chip's base address		
** Output    	: none						
************************************************************************
*/
static void __init TRM_S1040_read_all(PNVRAMTYPE pEEpromBuf, WORD scsiIOPort)
{
    BYTE	*bpEeprom = (BYTE *) pEEpromBuf;
    BYTE	bAddr;
    
    /*
    ** Enable SEEPROM 
    */
    outb( (inb(scsiIOPort+TRM_S1040_GEN_CONTROL) | EN_EEPROM) , scsiIOPort+TRM_S1040_GEN_CONTROL);
    for (bAddr = 0; bAddr < 128; bAddr++, bpEeprom++)
    {
	*bpEeprom = TRM_S1040_get_data(scsiIOPort, bAddr);
    }
    /* 
    ** Disable SEEPROM 
    */
    outb( (inb(scsiIOPort+TRM_S1040_GEN_CONTROL) & ~EN_EEPROM) , scsiIOPort+TRM_S1040_GEN_CONTROL );
    return;
}
/*
************************************************************************
**		TRM_S1040_read_all
**
**----------------------------------------------------------------------
** Function	: TRM_S1040_get_data						
** Description	: read one byte from seeprom	
** Input    	: scsiIOPort - chip's base address
**			bAddr - address of SEEPROM		
** Output   	: bData - data of SEEPROM		
************************************************************************
*/
static BYTE __init TRM_S1040_get_data(WORD scsiIOPort, BYTE bAddr)
{
    int		i;
    BYTE	bReadData, bData = 0;
    /* 
    ** Send read command & address
    */
    TRM_S1040_write_cmd(scsiIOPort, 0x06, bAddr);
				
    for (i = 0; i < 8; i++)
    {	/* 
	** Read data
	*/
	outb( (NVR_SELECT | NVR_CLOCK) , scsiIOPort+TRM_S1040_GEN_NVRAM);
	TRM_S1040_wait_30us(scsiIOPort);
	outb( NVR_SELECT , scsiIOPort+TRM_S1040_GEN_NVRAM);
	/* 
	** Get data bit while falling edge 
	*/
	bReadData = inb(scsiIOPort+TRM_S1040_GEN_NVRAM);
	bData <<= 1;
	if (bReadData & NVR_BITIN)
	    bData |= 1;

	TRM_S1040_wait_30us(scsiIOPort);
    }
    /* 
    ** Disable chip select 
    */
    outb( 0 , scsiIOPort+TRM_S1040_GEN_NVRAM);
    return (bData);
}
/*
************************************************************************
**
** Function	: TRM_S1040_wait_30us					
** Description	: wait 30 us						
** Input    	: scsiIOPort - chip's base address			
** Output   	: none							
************************************************************************
*/
static void __init TRM_S1040_wait_30us(WORD scsiIOPort)
{
    /*    ScsiPortStallExecution(30);	 wait 30 us	*/
    outb( 5 , scsiIOPort+TRM_S1040_GEN_TIMER);
    while (!(inb(scsiIOPort+TRM_S1040_GEN_STATUS) & GTIMEOUT));
    return;
}
/*
************************************************************************
**		TRM_S1040_get_data  TRM_S1040_write_all
**		TRM_S1040_set_data
**----------------------------------------------------------------------
** Function	: TRM_S1040_write_cmd						
** Description	: write SB and Op Code into seeprom	
** Input	: scsiIOPort ... chip's base address			
**			bCmd       ... SB + Op Code				
**			bAddr      ... address of SEEPROM		
** Output    	: none					
************************************************************************
*/
static void __init TRM_S1040_write_cmd(WORD scsiIOPort, BYTE bCmd, BYTE bAddr)
{
    int		i;
    BYTE	bSendData;

					
    for (i = 0; i < 3; i++, bCmd <<= 1)
    {	/* 
	** Program SB+OP code		
	*/
	bSendData = NVR_SELECT;
	if (bCmd & 0x04)		/* Start from bit 2		*/
	    bSendData |= NVR_BITOUT;

	outb( bSendData , scsiIOPort+TRM_S1040_GEN_NVRAM);
	TRM_S1040_wait_30us(scsiIOPort);
	outb( (bSendData | NVR_CLOCK) , scsiIOPort+TRM_S1040_GEN_NVRAM);
	TRM_S1040_wait_30us(scsiIOPort);
    }
				
    for (i = 0; i < 7; i++, bAddr <<= 1)
    {  	/* 
	** Program address		
	*/
	bSendData = NVR_SELECT;
	if (bAddr & 0x40)		/* Start from bit 6		*/
	    bSendData |= NVR_BITOUT;

	outb( bSendData , scsiIOPort+TRM_S1040_GEN_NVRAM);
	TRM_S1040_wait_30us(scsiIOPort);
	outb( (bSendData | NVR_CLOCK) , scsiIOPort+TRM_S1040_GEN_NVRAM);
	TRM_S1040_wait_30us(scsiIOPort);
    }
    outb( NVR_SELECT , scsiIOPort+TRM_S1040_GEN_NVRAM);
    TRM_S1040_wait_30us(scsiIOPort);
}

/*
************************************************************************
**		DC395x_init
**
**----------------------------------------------------------------------
** Function 	: DC395x_check_eeprom				
** Description	: read seeprom 128 bytes to pEEpromBuf and check
**			checksum. If it is worong, updated with default value
** Input    	: eeprom,scsiIOPort - chip's base address		
** Output	: none					
************************************************************************
*/
static void __init DC395x_check_eeprom(PNVRAMTYPE pEEpromBuf, WORD scsiIOPort)
{
    WORD    	*wpEeprom = (WORD *) pEEpromBuf;
    WORD    	wAddr, wCheckSum;
    DWORD   	dAddr, *dpEeprom;

    TRM_S1040_read_all(pEEpromBuf,scsiIOPort);
    wCheckSum = 0;
    for (wAddr = 0, wpEeprom = (WORD *) pEEpromBuf; wAddr < 64; wAddr++, wpEeprom++)
	wCheckSum += *wpEeprom;

    if (wCheckSum != 0x1234)
    {   /* 
	 ** Checksum error, load default	
	 */
	printk ("DC395x: EEProm ChkSum error: Use defaults/options!\n");
	pEEpromBuf->NvramSubVendorID[0]	= (BYTE) PCI_VendorID_TEKRAM;
	pEEpromBuf->NvramSubVendorID[1]	= (BYTE) (PCI_VendorID_TEKRAM >> 8);
	pEEpromBuf->NvramSubSysID[0]	= (BYTE) PCI_DeviceID_TRMS1040;
	pEEpromBuf->NvramSubSysID[1]	= (BYTE) (PCI_DeviceID_TRMS1040 >> 8);
	pEEpromBuf->NvramSubClass	= 0x00;
	pEEpromBuf->NvramVendorID[0]	= (BYTE) PCI_VendorID_TEKRAM;
	pEEpromBuf->NvramVendorID[1]	= (BYTE) (PCI_VendorID_TEKRAM >> 8);
	pEEpromBuf->NvramDeviceID[0]	= (BYTE) PCI_DeviceID_TRMS1040;
	pEEpromBuf->NvramDeviceID[1]	= (BYTE) (PCI_DeviceID_TRMS1040 >> 8);
	pEEpromBuf->NvramReserved	= 0x00;

	for (dAddr = 0, dpEeprom = (DWORD *) pEEpromBuf->NvramTarget; dAddr < 16; dAddr++, dpEeprom++)
	    *dpEeprom = 0x00000077;/* NvmTarCfg3,NvmTarCfg2,NvmTarPeriod,NvmTarCfg0 */

	*dpEeprom++ = 0x04000F07;/*    NvramMaxTag,NvramDelayTime,NvramChannelCfg,NvramScsiId    */
	*dpEeprom++ = 0x00000015;/* NvramReserved1,NvramBootLun  ,NvramBootTarget,NvramReserved0 */
	for (dAddr = 0; dAddr < 12; dAddr++, dpEeprom++)
	    *dpEeprom = 0x00;

	/* Now load defaults (maybe set by boot/module params) */
	DC395x_check_for_safe_settings ();
	DC395x_fill_with_defaults ();
	DC395x_EEprom_Override (pEEpromBuf);
	    
	pEEpromBuf->NvramCheckSum	= 0x00;
	for (wAddr = 0, wCheckSum = 0, wpEeprom = (WORD *) pEEpromBuf; wAddr < 63; wAddr++, wpEeprom++)
	    wCheckSum += *wpEeprom;

	*wpEeprom = 0x1234 - wCheckSum;
	TRM_S1040_write_all(pEEpromBuf,scsiIOPort);
	pEEpromBuf->NvramDelayTime = dc395x_trm[5];
    }
    else
    {
	DC395x_check_for_safe_settings ();
	DC395x_interpret_delay (pEEpromBuf);
	DC395x_EEprom_Override (pEEpromBuf);
    }
    return;
}

/* Print connector and termination config */
static void __init DC395x_print_config (PACB pACB)
{    
	BYTE bval;

	bval = DC395x_read8(TRM_S1040_GEN_STATUS);
	printk ("DC395%c: Connectors: ",
		((bval & WIDESCSI)? 'W': ' '));
	if (!(bval & CON5068)) { 
		printk ("ext");
		if (!(bval & EXT68HIGH)) printk ("68 ");
		else printk ("50 ");
	}
	if (!(bval & CON68)) {
		printk ("int68");
		if (!(bval & INT68HIGH)) printk (" ");
		else printk ("(50) ");
	}
	if (!(bval & CON50))
		printk ("int50 ");
	if ((bval & (CON5068 | CON50 | CON68)) == 0 /*(CON5068 | CON50 | CON68)*/)
		printk (" Oops! (All 3?) ");
	bval = DC395x_read8(TRM_S1040_GEN_CONTROL);
	printk (" Termination: ");
	if (bval & DIS_TERM)
		printk ("Disabled\n");
	else {
		if (bval & AUTOTERM)
			printk ("Auto ");
		if (bval & LOW8TERM)
			printk ("Low ");
		if (bval & UP8TERM)
			printk ("High ");
		printk ("\n");
	}
}
  
/*
**********************************************************************
**
**			DC395x_detect
**
**      Function : static int DC395x_init (struct Scsi_Host *host)
**       Purpose : initialize the internal structures for a given SCSI host
**        Inputs : host - pointer to this host adapter's structure/
** Preconditions : when this function is called, the chip_type
**		   field of the pACB structure MUST have been set.
**********************************************************************
*/
static PSH __init DC395x_init(PSHT psht, DWORD io_port, BYTE Irq, WORD index)
{
    PSH   psh;
    PACB  pACB;
    //DWORD acb_flags=0;
    
    //$$$$$$$$$$$$$$$$$$$$$$$  EEPROM CHECKSUM  $$$$$$$$$$$$$$$$$$$$$$$$$
    DC395x_check_eeprom(  &dc395x_trm_eepromBuf[index], (WORD) io_port);
    //$$$$$$$$$$$  MEMORY ALLOCATE FOR ADAPTER CONTROL BLOCK $$$$$$$$$$$$
    psh = scsi_register( psht, sizeof(DC395X_TRM_ACB) );
    if( !psh )
    {
	printk(KERN_INFO "DC395x_init : pSH scsi_register ERROR\n");
	return( 0 );
    }
    printk (KERN_INFO "DC395x: Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), DevMode=0x%02x\n",
	    dc395x_trm_eepromBuf[index].NvramScsiId,
	    dc395x_trm_eepromBuf[index].NvramTarget[0].NvmTarPeriod,
	    dc395x_clock_speed[dc395x_trm_eepromBuf[index].NvramTarget[0].NvmTarPeriod]/10,
	    dc395x_clock_speed[dc395x_trm_eepromBuf[index].NvramTarget[0].NvmTarPeriod]%10,
	    dc395x_trm_eepromBuf[index].NvramTarget[0].NvmTarCfg0);
    printk (KERN_INFO "DC395x:      AdaptMode=0x%02x, Tags=%i(%02i), DelayReset=%is\n",
	    dc395x_trm_eepromBuf[index].NvramChannelCfg,
	    dc395x_trm_eepromBuf[index].NvramMaxTag,
	    1 << dc395x_trm_eepromBuf[index].NvramMaxTag,
	    dc395x_trm_eepromBuf[index].NvramDelayTime);

    pACB = (PACB) psh->hostdata;
    //DC395x_ACB_INITLOCK(pACB);
    //DC395x_ACB_LOCK(pACB,acb_flags);
    //$$$$$$$$ INITIAL ADAPTER CONTROL BLOCK $$$$$$$$$$$$
    if (DC395x_initACB( psh, io_port, Irq, index )) {
	    scsi_unregister (psh);
	    //DC395x_ACB_UNLOCK(pACB,acb_flags);
	    return 0;
    }
    DC395x_print_config (pACB);
    //$$$$$$$$$$$$$$$$$ INITIAL ADAPTER $$$$$$$$$$$$$$$$$
    if( !DC395x_initAdapter( psh, io_port, Irq, index  ) )
    {
	if( !DC395x_pACB_start )
	{
	    DC395x_pACB_start = pACB;
	    DC395x_pACB_current = pACB;
	    pACB->pNextACB = (PACB) -1;
	}
	else
	{
	    DC395x_pACB_current->pNextACB = pACB;
	    DC395x_pACB_current = pACB;
	    pACB->pNextACB = (PACB) -1;
	}
	//DC395x_ACB_UNLOCK(pACB,acb_flags);
	return( psh );
    }
    else
    {
	printk(KERN_INFO "DC395x_initAdapter initial ERROR\n");
	scsi_unregister( psh );
	//DC395x_ACB_UNLOCK(pACB,acb_flags);
	return( 0 );
    }
}

/*
**********************************************************************
**
**		DC395x_set_master
**      Function : 
**       Purpose : 
**        Inputs : 
** Preconditions : 
**          	   
**********************************************************************
*/
#ifndef NEW_PCI
static void __init DC395x_set_master(BYTE pci_bus,BYTE pci_device_fn)
{
    WORD  cmd;
    BYTE  latency_timer;
    
    pcibios_read_config_word(pci_bus,pci_device_fn,PCI_COMMAND, &cmd);
    if (! (cmd & PCI_COMMAND_MASTER))
    {	
	printk(KERN_INFO "PCI: Enabling bus mastering for device %02x:%02x\n",pci_bus,pci_device_fn);
	cmd |= PCI_COMMAND_MASTER;
	pcibios_write_config_word(pci_bus,pci_device_fn, PCI_COMMAND, cmd);
    }
    pcibios_read_config_byte(pci_bus,pci_device_fn,PCI_LATENCY_TIMER, &latency_timer);
    if (latency_timer < 16 /* || latency_timer == 255 */)
    {
	printk(KERN_INFO "PCI: Setting latency timer of device %02x:%02x from %i to 64\n", pci_bus,pci_device_fn, latency_timer);
	pcibios_write_config_byte(pci_bus,pci_device_fn, PCI_LATENCY_TIMER,  64);
    }
}
#endif

#if 0
/*
**********************************************************************
**
**		DC395x_set_pci_cfg
**      Function :
**       Purpose : 
**        Inputs :
** Preconditions : 
**          	   
**********************************************************************
*/
#ifdef NEW_PCI
static void __init DC395x_set_pci_cfg( struct pci_dev *pPCI_DEVICE )
{
    WORD cmd, stat;

    pci_read_config_word(pPCI_DEVICE, PCI_COMMAND, &cmd);
    printk ("DC395x: PCI_COMMAND: %04x", cmd);
    cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO | PCI_COMMAND_INVALIDATE;
    pci_write_config_word(pPCI_DEVICE, PCI_COMMAND, cmd);
    pci_read_config_word(pPCI_DEVICE, PCI_COMMAND, &cmd);
    printk ("->%04x", cmd);
    pci_read_config_word(pPCI_DEVICE, PCI_STATUS, &stat);
    printk (", PCI_STATUS: %04x", stat);
    stat |= (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY);
    pci_write_config_word(pPCI_DEVICE, PCI_STATUS, stat);
    pci_read_config_word(pPCI_DEVICE, PCI_STATUS, &stat);
    printk ("->%04x\n", stat);    
}
#else
static void __init DC395x_set_pci_cfg(BYTE pci_bus,BYTE pci_device_fn)
{
    WORD cmd;

    pcibios_read_config_word(pci_bus, pci_device_fn,PCI_COMMAND, &cmd);
    cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO;
    pcibios_write_config_word(pci_bus, pci_device_fn, PCI_COMMAND, cmd);
    pcibios_write_config_word(pci_bus, pci_device_fn, PCI_STATUS,(PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY) );
}
#endif	
#endif
  
/*
**********************************************************************
**
**		SCSI driver entry of Linux 
**
** Function : int DC395x_detect(Scsi_Host_Template *psht)
** Purpose  : detects and initializes TRM S1040 SCSI chips
**		that were autoprobed, overridden on the LILO command line,
**		or specified at compile time.
** Inputs   : psht - template for this SCSI adapter
** Returns  : number of host adapters detected
**
** There is one pci_dev structure for each slot-number/function-number
** combination:
**
** struct pci_dev {
**	struct pci_bus	      *bus;		    // bus this device is on 
**	struct pci_dev	      *sibling;  	// next device on this bus 
**	struct pci_dev 	      *next;		// chain of all devices 
**
**	void	              *sysdata;	    // hook for sys-specific extension 
**	struct proc_dir_entry *procent;	    // device entry in /proc/bus/pci 
**
**	unsigned int	      devfn;		// encoded device & function index 
**	unsigned short	      vendor;
**	unsigned short	      device;
**	unsigned int	      class;	    // 3 bytes: (base,sub,prog-if) 
**	unsigned int	      hdr_type;	    // PCI header type 
**	unsigned int	      master : 1;	// set if device is master capable 
**	
**	// In theory, the irq level can be read from configuration
**	// space and all would be fine.  However, old PCI chips don't
**	// support these registers and return 0 instead.  For example,
**	// the Vision864-P rev 0 chip can uses INTA, but returns 0 in
**	// the interrupt line and pin registers.  pci_init()
**	// initializes this field with the value at PCI_INTERRUPT_LINE
**	// and it is the job of pcibios_fixup() to change it if
**	// necessary.  The field must not be 0 unless the device
**	// cannot generate interrupts at all.
**	 
**	unsigned int	      irq;		    // irq generated by this device 
**
**	// Base registers for this device, can be adjusted by
**	// pcibios_fixup() as necessary.
**	 
**	unsigned long	      base_address[6];
**	unsigned long	      rom_address;
**};
**
**struct pci_bus {
**	struct pci_bus	      *parent;	    // parent bus this bridge is on 
**	struct pci_bus	      *children;    // chain of P2P bridges on this bus 
**	struct pci_bus	      *next;		// chain of all PCI buses 
**
**	struct pci_dev	      *self;		// bridge device as seen by parent 
**	struct pci_dev	      *devices;	    // devices behind this bridge 
**
**	void		          *sysdata;	    // hook for sys-specific extension 
**	struct proc_dir_entry *procdir;	    // directory entry in /proc/bus/pci 
**
**	unsigned char	      number;		// bus number 
**	unsigned char	      primary;	    // number of primary bridge 
**	unsigned char	      secondary;	// number of secondary bridge 
**	unsigned char	      subordinate;	// max number of subordinate buses 
**};
**********************************************************************
*/
int __init DC395x_detect (Scsi_Host_Template *psht)
{
#ifdef NEW_PCI
    struct pci_dev  *pPCI_DEVICE = NULL;
#else
    BYTE  pci_bus, pci_device_fn;
    WORD  pci_index = 0;	/* Device index to PCI BIOS calls */
    int     error = 0;
#endif

    BYTE    irq;
    UINT    io_port;

#ifndef USE_NEW_EH
    //DWORD flags;
    //DC395x_LOCK_IO;	// Don't lock for new EH
#endif

    DC395x_pACB_start  = NULL;
    /* search DC395x SCSI adapter in each slot */
#ifdef NEW_PCI
    if(pci_present())
    {  
	printk (KERN_INFO "DC395x (TRM-S1040) SCSI driver %s\n", DC395x_VERSION);
	while( (pPCI_DEVICE = pci_find_device( PCI_VendorID_TEKRAM,PCI_DeviceID_TRMS1040, pPCI_DEVICE) ) )
#else
    if(pcibios_present())
    {
	printk (KERN_INFO "DC395x_TRM (TRM-S1040) driver %s\n", DC395x_VERSION);
	while( !pcibios_find_device( PCI_VendorID_TEKRAM, PCI_DeviceID_TRMS1040, pci_index++, &pci_bus, &pci_device_fn) )
#endif
	{    
	  PSH   psh;
	  /* get adapter io_port ,irq */
	  //DC395x_DRV_LOCK(drv_flags); 
#ifdef NEW_PCI
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,30)
	  if (pci_enable_device (pPCI_DEVICE))
		continue;
	  io_port = pci_resource_start (pPCI_DEVICE, 0) & PCI_BASE_ADDRESS_IO_MASK;
# else
	  io_port = pPCI_DEVICE->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
# endif
	  irq = pPCI_DEVICE->irq;
#else
	  error = pcibios_read_config_dword(pci_bus, pci_device_fn,PCI_BASE_ADDRESS_0, &io_port);
	  error |= pcibios_read_config_byte(pci_bus, pci_device_fn,PCI_INTERRUPT_LINE, &irq);
	  if( error )
	  {
	      printk(KERN_INFO "DC395x/DC315x: ERROR reading PCI config registers !\n");
	      continue;
	  }
	  (WORD) io_port = (WORD) io_port & PCI_BASE_ADDRESS_IO_MASK;
#endif
#ifdef DC395x_DEBUG0
	  printk(KERN_INFO "DC395x: IO_PORT=%04x,IRQ=%x\n",(UINT) io_port, irq);
#endif
	  if( (psh = DC395x_init(psht, io_port, irq, DC395x_adapterCnt)) )
	  {
#ifdef NEW_PCI
	      pci_set_master(pPCI_DEVICE);
	      ((PACB)(psh->hostdata))->pdev = pPCI_DEVICE;
	      //DC395x_set_pci_cfg(pPCI_DEVICE);
#else
	      DC395x_set_master(pci_bus,pci_device_fn);
	      ((PACB)(psh->hostdata))->pbus = pci_bus;
	      ((PACB)(psh->hostdata))->pdevfn = pci_device_fn;
	      //DC395x_set_pci_cfg(pci_bus,pci_device_fn);
#endif
	      DC395x_adapterCnt++;
	  }
	  //DC395x_DRV_UNLOCK(drv_flags);
	}
    }
    else
    {
	printk (KERN_ERR "No PCI BIOS found!\n");
    }

    if(DC395x_adapterCnt)
    {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
	psht->proc_name = "dc395x_trm";
#else		    
	psht->proc_dir = &DC395x_proc_scsi;
#endif
    }
    printk (KERN_INFO "DC395x (TRM-S1040): %i adapters found\n", DC395x_adapterCnt);
    //printk (KERN_WARNING "DC395x: *** WARNING: This driver is not completely stable! ***\n");

#ifndef USE_NEW_EH
    //DC395x_UNLOCK_IO;
#endif
    return( DC395x_adapterCnt );
}


/***********************************************************************
 * Functions: DC395x_inquiry(), DC395x_inquiry_done()
 *
 * Purpose: When changing speed etc., we have to issue an INQUIRY
 *	    command to make sure, we agree upon the nego parameters
 *	    with the device
 ***********************************************************************/

static void DC395x_inquiry_done (Scsi_Cmnd* cmd)
{
   PACB pACB = (PACB)cmd->host->hostdata;
   PDCB pDCB = DC395x_findDCB (pACB, cmd->target, cmd->lun);
#ifdef DC395x_DEBUGTRACE
   PSRB pSRB = pACB->pFreeSRB;
#endif
   printk (KERN_INFO "DC395x: INQUIRY (%02i-%i) returned %08x: %02x %02x %02x %02x ...\n",
	   cmd->target, cmd->lun, cmd->result, 
	   ((PBYTE)cmd->request_buffer)[0], ((PBYTE)cmd->request_buffer)[1], 
	   ((PBYTE)cmd->request_buffer)[2], ((PBYTE)cmd->request_buffer)[3]);
   //TRACEOUT ("%s\n", pSRB->debugtrace);
   if (cmd->result)
   {
	printk ("DC395x: Unsetting Wide, Sync and TagQ!\n");
	if (pDCB)
	{
		TRACEOUT ("%s\n", pSRB->debugtrace);
		pDCB->DevMode &= ~(NTC_DO_SYNC_NEGO | NTC_DO_WIDE_NEGO | NTC_DO_TAG_QUEUEING);
		DC395x_updateDCB (pACB, pDCB);
	};
   };
   if (pDCB)
   {
	   if (!(pDCB->SyncMode & SYNC_NEGO_DONE))
	   { pDCB->SyncOffset = 0; /*pDCB->SyncMode &= ~SYNC_NEGO_ENABLE;*/ };
	   if (!(pDCB->SyncMode & WIDE_NEGO_DONE))
	   { pDCB->SyncPeriod &= ~WIDE_SYNC; pDCB->SyncMode &= ~WIDE_NEGO_ENABLE; };
   }
   else
   {
	   printk ("DC395x: ERROR! No DCB existent for %02i-%i ?\n",
		   cmd->target, cmd->lun);
   }
   KFREE (cmd);
};

/* Perform INQUIRY */	
void DC395x_inquiry (PACB pACB, PDCB pDCB)
{
   char* buffer;
   Scsi_Cmnd* cmd;
   cmd = KMALLOC (sizeof(Scsi_Cmnd) + 256, GFP_ATOMIC);
   if (!cmd) { printk ("DC395x: kmalloc failed in inquiry!\n"); return; };
   buffer = (char*)cmd + sizeof(Scsi_Cmnd);

   memset (cmd, 0, sizeof(Scsi_Cmnd) + 256);
   cmd->cmnd[0] = INQUIRY;
   cmd->cmnd[1] = (pDCB->TargetLUN << 5) & 0xe0;
   cmd->cmnd[4] = 0xff;
   
   cmd->cmd_len = 6; cmd->old_cmd_len = 6;
   cmd->host = pACB->pScsiHost;
   cmd->target = pDCB->TargetID;
   cmd->lun = pDCB->TargetLUN; 
   cmd->serial_number = 1;
   cmd->pid = 395;
   cmd->bufflen = 128;
   cmd->buffer = buffer;
   cmd->request_bufflen = 128;
   cmd->request_buffer = &buffer[128];
   cmd->done = DC395x_inquiry_done;
   cmd->scsi_done = DC395x_inquiry_done;
   cmd->timeout_per_command = HZ;

   cmd->request.rq_status = RQ_SCSI_BUSY;

   pDCB->SyncMode &= ~SYNC_NEGO_DONE; pDCB->SyncMode |= SYNC_NEGO_ENABLE;
   pDCB->SyncMode &= ~WIDE_NEGO_DONE; pDCB->SyncMode |= WIDE_NEGO_ENABLE;
   printk (KERN_INFO "DC395x: Queue INQUIRY command to dev %02i-%i\n",
	   pDCB->TargetID, pDCB->TargetLUN);
   DC395x_queue_command (cmd, DC395x_inquiry_done);
};

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1)
static char *DC395x_strtok_ptr;
static char* DC395x_strtok (char* init, char* sep)
{
	char* ptr;
	if (init) 
		DC395x_strtok_ptr = init;
	do {
		ptr = strsep (&DC395x_strtok_ptr, sep);
	} while (ptr && *ptr == 0);
	return ptr;
}
# define strtok DC395x_strtok
#endif

/*
*******************************************************************
**
** Function: DC395x_set_info()
**  Purpose: Set adapter info (!)
** Strings are parsed similar to the output of tmscsim_proc_info ()
** '-' means no change
********************************************************************/

static int DC395x_scanf (char** p1, char** p2, int* var)
{
   *p2 = *p1;
   *var = simple_strtoul (*p2, p1, 10);
   if (*p2 == *p1) return -1;
   *p1 = strtok (0, " \t\n:=,;.");
   return 0;
};

#define SCANF(p1, p2, var, min, max)		\
if (DC395x_scanf (&p1, &p2, &var)) goto einv;	\
else if (var<min || var>max) goto einv2

static int DC395x_yesno (char** p, char* var, char bmask)
{
   switch (**p)
     {
      case 'Y': *var |= bmask; break;
      case 'N': *var &= ~bmask; break;
      case '-': break;
      default: return -1;
     }
   *p = strtok (0, " \t\n:=,;");
   return 0;
};

#define YESNO(p, var, bmask)			\
if (DC395x_yesno (&p, &var, bmask)) goto einv;	\
else DC395x_updateDCB (pACB, pDCB);		\
if (!p) goto ok

static int DC395x_search (char **p1, char **p2, char *var, char* txt, int max, int scale, char* ign)
{
   int dum;
   if (! memcmp (*p1, txt, strlen(txt)))
     {
	*p2 = strtok (0, " \t\n:=,;");
	if (!*p2) return -1;
	dum = simple_strtoul (*p2, p1, 10);
	if (*p2 == *p1) return -1;
	if (dum >= 0 && dum <= max) 
	  { *var = (dum * 100) / scale; }
	else return -2;
	*p1 = strtok (0, " \t\n:=,;");
	if (*ign && *p1 && strlen(*p1) >= strlen(ign) && 
	    !(memcmp (*p1, ign, strlen(ign)))) 
		*p1 = strtok (0, " \t\n:=,;");

     }
   return 0;
};

#define SEARCH(p1, p2, var, txt, max)						\
if (DC395x_search (&p1, &p2, (PBYTE)(&var), txt, max, 100, "")) goto einv2;	\
else if (!p1) goto ok2

#define SEARCH2(p1, p2, var, txt, max, scale)					\
if (DC395x_search (&p1, &p2, &var, txt, max, scale, "")) goto einv2; 		\
else if (!p1) goto ok2

#define SEARCH3(p1, p2, var, txt, max, scale, ign)				\
if (DC395x_search (&p1, &p2, &var, txt, max, scale, ign)) goto einv2;		\
else if (!p1) goto ok2


#ifdef DC395x_PARSEDEBUG
static char _prstr[256];
char* prstr (char* p, char* e)
{
   char* c = _prstr;
   while (p < e)
     if (*p == 0) { *c++ = ':'; p++; }
     else if (*p == 10) { *c++ = '\\'; *c++ = 'n'; p++; }
     else *c++ = *p++;
   *c = 0;
   return _prstr;
};
#endif

int DC395x_set_info(char *buffer, int length, PACB pACB)
{
  char *pos = buffer, *p0 = buffer;
  char needs_inquiry = 0;
  char dev;
  int dum = 0;
  PDCB pDCB = pACB->pLinkDCB;
  unsigned long flags;
  pos[length] = 0;

  DC395x_LOCK_IO(pACB->pScsiHost);
  /* UPPERCASE */ 
  /* Don't use kernel toupper, because of 2.0.x bug: ctmp unexported */
  while (*pos) 
    { if (*pos >='a' && *pos <= 'z') *pos = *pos + 'A' - 'a'; pos++; };
  
  /* We should protect __strtok ! */
  /* spin_lock (strtok_lock); */

  /* Remove WS */
  pos = strtok (buffer, " \t:\n=,;");
  if (!pos) goto ok;
   
 next:
  if (!memcmp (pos, "RESET", 5)) goto reset;
  else if (!memcmp (pos, "INQUIRY", 7)) goto inquiry;
  else if (!memcmp (pos, "REMOVE", 6)) goto remove;
  else if (!memcmp (pos, "ADD", 3)) goto add;
  else if (!memcmp (pos, "DUMP", 4)) goto dump;
  
  if (isdigit (*pos))
    {
      /* Device config line */
      int dev, id, lun; char* pdec;
      char olddevmode;
      
      SCANF (pos, p0, dev, 0, pACB->DCBCnt-1);
      if (pos) { SCANF (pos, p0, id, 0, 15); } else goto einv;
      if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
      if (!pos) goto einv;
      
      PARSEDEBUG(printk (KERN_INFO "DC395x: config line %i %i %i:\"%s\"\n", dev, id, lun, prstr (pos, &buffer[length]));)
      pDCB = pACB->pLinkDCB;
      for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
      /* Sanity Check */
      if (pDCB->TargetID != id || pDCB->TargetLUN != lun) 
	 {
	    printk (KERN_ERR "DC395x: no such device: Idx=%02i ID=%02i LUN=%02i\n",
		    dev, id, lun);
	    goto einv2;
	 };

      /*
      if (pDCB->pWaitingSRB || pDCB->pGoingSRB)
      {
	  printk ("DC395x: Cannot change dev (%i-%i) cfg: Pending requests\n",
		  pDCB->TargetID, pDCB->TargetLUN);
	  goto einv;
      };
       */
	    
      olddevmode = pDCB->DevMode;
      YESNO (pos, pDCB->DevMode, NTC_DO_PARITY_CHK);
      needs_inquiry++;
      YESNO (pos, pDCB->DevMode, NTC_DO_SYNC_NEGO);
      if ((olddevmode & NTC_DO_SYNC_NEGO) == (pDCB->DevMode & NTC_DO_SYNC_NEGO)) needs_inquiry--;
      needs_inquiry++;
      YESNO (pos, pDCB->DevMode, NTC_DO_WIDE_NEGO);
      if ((olddevmode & NTC_DO_WIDE_NEGO) == (pDCB->DevMode & NTC_DO_WIDE_NEGO)) needs_inquiry--;
      needs_inquiry++;
      YESNO (pos, pDCB->DevMode, NTC_DO_DISCONNECT);
      if ((olddevmode & NTC_DO_DISCONNECT) == (pDCB->DevMode & NTC_DO_DISCONNECT)) needs_inquiry--;
      YESNO (pos, pDCB->DevMode, NTC_DO_SEND_START);
      needs_inquiry++;
      YESNO (pos, pDCB->DevMode, NTC_DO_TAG_QUEUEING);
      if ((olddevmode & NTC_DO_TAG_QUEUEING) == (pDCB->DevMode & NTC_DO_TAG_QUEUEING)) needs_inquiry--;

      DC395x_updateDCB (pACB, pDCB);
      if (!pos) goto ok;
       
      olddevmode = pDCB->MinNegoPeriod;
      /* Look for decimal point (Speed) */
      pdec = pos; 
      while (pdec++ < &buffer[length]) if (*pdec == '.') break;
      /* NegoPeriod */
      if (*pos != '-')
	{
	  SCANF (pos, p0, dum, 48, 800); 
	  pDCB->MinNegoPeriod = dum >> 2;
	  if (pDCB->MinNegoPeriod != olddevmode) needs_inquiry++;
	  if (!pos) goto ok;
	  if (memcmp (pos, "NS", 2) == 0) pos = strtok (0, " \t\n:=,;.");
	}
      else pos = strtok (0, " \t\n:=,;.");
      if (!pos) goto ok;
      
      /* Sync Speed in MHz */
      if (*pos != '-')
	{
	  SCANF (pos, p0, dum, 1, 21);
	  pDCB->MinNegoPeriod = (1000/dum) >> 2;
	  if (pDCB->MinNegoPeriod != olddevmode && !pos) needs_inquiry++;
	  if (!pos) goto ok;
	  /* decimal */
	  if (pos-1 == pdec)
	     {
		int dumold = dum;
		dum = simple_strtoul (pos, &p0, 10) * 10;
		for (; p0-pos > 1; p0--) dum /= 10;
		pDCB->MinNegoPeriod = (100000/(100*dumold + dum)) >> 2;
		if (pDCB->MinNegoPeriod < 12) pDCB->MinNegoPeriod = 12;
		pos = strtok (0, " \t\n:=,;");
		if (!pos) goto ok;
	     };
	  if (*pos == 'M') pos = strtok (0, " \t\n:=,;");
	  if (pDCB->MinNegoPeriod != olddevmode) needs_inquiry++;
	}
      else pos = strtok (0, " \t\n:=,;");
      /* dc395x_updateDCB (pACB, pDCB); */
      if (!pos) goto ok;

      olddevmode = pDCB->SyncOffset;
      /* SyncOffs */
      if (*pos != '-')
	{
	  SCANF (pos, p0, dum, 0, 0x0f); 
	  pDCB->SyncOffset = dum;
	  if (pDCB->SyncOffset > olddevmode) needs_inquiry++;
	}
      else pos = strtok (0, " \t\n:=,;");
      if (!pos) goto ok;
      DC395x_updateDCB (pACB, pDCB);

      //olddevmode = pDCB->MaxCommand;
      /* MaxCommand (Tags) */
      if (*pos != '-')
	{
	  SCANF (pos, p0, dum, 1, 30 /*pACB->TagMaxNum*/);
	  if (pDCB->SyncMode & EN_TAG_QUEUEING)
		pDCB->MaxCommand = dum;
	  else printk (KERN_INFO "DC395x: Can't set MaxCmd larger than one without Tag Queueing!\n");
	}
      else pos = strtok (0, " \t\n:=,;");

    }
  else
    {
      char* p1 = pos; char newadaptid = pACB->pScsiHost->this_id;
      BYTE filtercfg = DC395x_read8(TRM_S1040_SCSI_CONFIG1);
      PARSEDEBUG(printk (KERN_INFO "DC395x: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));)
      /* Adapter setting */
      SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 16); 
      SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8); 
      SEARCH (pos, p0, newadaptid, "ADAPTERID", 15);
      SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 30);
      SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255);
      SEARCH (pos, p0, filtercfg, "FILTERCFG", 255);
      SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS");
      SEARCH3 (pos, p0, dc395x_trm_eepromBuf[pACB->AdapterIndex].NvramDelayTime, "DELAYRESET", 180, 100, "S");
    ok2:
      if (pACB->sel_timeout < 60) pACB->sel_timeout = 60;
      DC395x_write8 (TRM_S1040_SCSI_TIMEOUT, pACB->sel_timeout);
      if (newadaptid != pACB->pScsiHost->this_id)
      {
	pACB->pScsiHost->this_id = newadaptid;
	DC395x_write8 (TRM_S1040_SCSI_HOSTID, newadaptid);
	DC395x_ResetDevParam (pACB);
      }
      DC395x_write8 (TRM_S1040_SCSI_CONFIG1, filtercfg);
      //dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++;
      //pACB->TagMaxNum &= (1 << --dum);
      DC395x_updateDCBs (pACB);
      //We should INQUIRY all now!
      //OTOH: If we changed AdaptID to a new one, we will get UNIT_ATTNETION and
      // will renegotiate on AUTO_REQSENSE
      if (pos == p1) goto einv;
    }
  if (pos) goto next;
      
 ok:
  /* spin_unlock (strtok_lock); */
  //DC395x_ACB_UNLOCK(acb_flags);
  if (needs_inquiry) 
     { DC395x_updateDCB (pACB, pDCB); DC395x_inquiry (pACB, pDCB); };
  DC395x_UNLOCK_IO(pACB->pScsiHost);
  return (length);

 einv2:
  pos = p0;
 einv:
  /* spin_unlock (strtok_lock); */
  //DC395x_ACB_UNLOCK(acb_flags);
  DC395x_UNLOCK_IO(pACB->pScsiHost);
  printk (KERN_WARNING "DC395x: parse error near \"%s\"\n", (pos? pos: "NULL"));
  return (-EINVAL);
   
 reset:
     {
	Scsi_Cmnd cmd; cmd.host = pACB->pScsiHost;
	printk (KERN_WARNING "DC395x: Driver reset requested!\n");
	//DC395x_ACB_UNLOCK(acb_flags);
	DC395x_reset (&cmd, 0);
	DC395x_UNLOCK_IO(pACB->pScsiHost);
     };
  return (length);
  
 dump:
     {
	DC395x_dumpinfo (pACB, 0, 0);
	DC395x_UNLOCK_IO(pACB->pScsiHost);
     };
  return length;

 inquiry:
     {
	pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
	dev = simple_strtoul (pos, &p0, 10);
	if (dev >= pACB->DCBCnt) goto einv_dev;
	for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
	printk (KERN_NOTICE " DC395x: Issue INQUIRY command to Dev(Idx) %i SCSI ID %i LUN %i\n",
		dev, pDCB->TargetID, pDCB->TargetLUN);
	//DC395x_ACB_UNLOCK(acb_flags);
	DC395x_inquiry (pACB, pDCB);
	DC395x_UNLOCK_IO(pACB->pScsiHost);
     };
   return (length);

 remove:
     {
	pos = strtok (0, " \t\n.:;="); if (!pos) goto einv;
	dev = simple_strtoul (pos, &p0, 10);
	if (dev >= pACB->DCBCnt) goto einv_dev;
	for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB;
	printk (KERN_NOTICE " DC395x: Remove DCB for Dev(Idx) %i SCSI ID %i LUN %i\n",
		dev, pDCB->TargetID, pDCB->TargetLUN);
	/* TO DO: We should make sure no pending commands are left */
	DC395x_remove_dev (pACB, pDCB);
	//DC395x_ACB_UNLOCK(acb_flags);
	DC395x_UNLOCK_IO(pACB->pScsiHost);
     };
   return (length);

 add:
     {
	int id, lun;
	pos = strtok (0, " \t\n.:;=");
	if (pos) { SCANF (pos, p0, id, 0, 15); } else goto einv;
	if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv;
	pDCB = DC395x_findDCB (pACB, id, lun);
	if (pDCB) { printk ("DC395x: ADD: Device already existing\n"); goto einv; };
	DC395x_initDCB (pACB, &pDCB, id, lun);
	//DC395x_ACB_UNLOCK(acb_flags);
	DC395x_inquiry (pACB, pDCB);
	DC395x_UNLOCK_IO(pACB->pScsiHost);
     };
   return (length);

 einv_dev:
   printk (KERN_WARNING "DC395x: Ignore cmnd to illegal Dev(Idx) %i. Valid range: 0 - %i.\n", 
	   dev, pACB->DCBCnt - 1);
   //DC395x_ACB_UNLOCK(acb_flags);
   DC395x_UNLOCK_IO(pACB->pScsiHost);
   return (-EINVAL);
}

#if 0
int DC395x_set_info(char *buffer, int length, PACB pACB)
{
  return -ENOSYS;
}
#endif

#undef SEARCH
#undef YESNO
#undef SCANF


/*
*******************************************************************
** Function: DC395x_proc_info(char* buffer, char **start,
**			 off_t offset, int length, int hostno, int inout)
**  Purpose: return SCSI Adapter/Device Info
**    Input:
**          buffer: Pointer to a buffer where to write info
**		 start :
**		 offset:
**		 hostno: Host adapter index
**		 inout : Read (=0) or set(!=0) info
**   Output:
**          buffer: contains info length 
**		         
**    return value: length of info in buffer
**
*******************************************************************
*/

/* KG: proc_info taken from driver aha152x.c */

#undef SPRINTF
#define SPRINTF(args...) pos += sprintf(pos, args)

#define YESNO(YN) \
 if (YN) SPRINTF(" Yes ");\
 else SPRINTF(" No  ")

int DC395x_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
{
    int    dev, spd, spd1;
    char   *pos = buffer;
    PSH    shpnt = NULL;
    PACB   pACB;
    PDCB   pDCB;
    DWORD  flags;
    PSCSICMD pcmd;
    
    /*  Scsi_Cmnd *ptr; */

    pACB = DC395x_pACB_start;
    
    while(pACB != (PACB)-1)
    {
	shpnt = pACB->pScsiHost;
	if (shpnt->host_no == hostno)
	    break;
	pACB = pACB->pNextACB;
    }
    if (pACB == (PACB)-1)
	return(-ESRCH);

    if(!shpnt)
	return(-ESRCH);

    if(inout) /* Has data been written to the file ? */
	return(DC395x_set_info(buffer, length, pACB));

    SPRINTF(DC395x_BANNER " PCI SCSI Host Adapter\n");
    SPRINTF(" Driver Version " DC395x_VERSION "\n");
    
    DC395x_LOCK_IO(pACB->pScsiHost);

    SPRINTF("SCSI Host Nr %i, ", shpnt->host_no);
    SPRINTF("DC395U/UW/F DC315/U %s Adapter Nr %i\n", 
	    (pACB->Config & HCC_WIDE_CARD)? "Wide": "", pACB->AdapterIndex);
    SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase);
    SPRINTF("IRQLevel 0x%02x, ", pACB->IRQLevel);
    SPRINTF(" SelTimeout %ims\n", (1638*pACB->sel_timeout)/1000);
    
    SPRINTF("MaxID %i, MaxLUN %i, ", shpnt->max_id, shpnt->max_lun);
    SPRINTF("AdapterID %i\n", shpnt->this_id);
    
    SPRINTF("TagMaxNum %i, Status %i", pACB->TagMaxNum, pACB->status);
    //SPRINTF(", DMA_Status %i\n", DC395x_read8(TRM_S1040_DMA_STATUS));
    SPRINTF (", FilterCfg 0x%02x", DC395x_read8(TRM_S1040_SCSI_CONFIG1));
    SPRINTF (", DelayReset %is\n", dc395x_trm_eepromBuf[pACB->AdapterIndex].NvramDelayTime);
    //SPRINTF("\n");
    
    SPRINTF("Nr of attached devices: %i, Nr of DCBs: %i\n", pACB->DeviceCnt, pACB->DCBCnt);
    SPRINTF("Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n",
	    pACB->DCBmap[0], pACB->DCBmap[1], pACB->DCBmap[2], pACB->DCBmap[3], 
	    pACB->DCBmap[4], pACB->DCBmap[5], pACB->DCBmap[6], pACB->DCBmap[7]);
    SPRINTF("                      %02x %02x %02x %02x %02x %02x %02x %02x\n",
	    pACB->DCBmap[8], pACB->DCBmap[9], pACB->DCBmap[10], pACB->DCBmap[11],
	    pACB->DCBmap[12], pACB->DCBmap[13], pACB->DCBmap[14], pACB->DCBmap[15]);

    SPRINTF("Un ID LUN Prty Sync Wide DsCn SndS TagQ NegoPeriod SyncFreq SyncOffs MaxCmd\n");

    pDCB = pACB->pLinkDCB;
    for (dev = 0; dev < pACB->DCBCnt; dev++)
    {
	int NegoPeriod;
	SPRINTF("%02i %02i  %02i ", dev, pDCB->TargetID, pDCB->TargetLUN);
	YESNO(pDCB->DevMode & NTC_DO_PARITY_CHK);
	YESNO(pDCB->SyncOffset);
	YESNO(pDCB->SyncPeriod & WIDE_SYNC );
	YESNO(pDCB->DevMode & NTC_DO_DISCONNECT);
	YESNO(pDCB->DevMode & NTC_DO_SEND_START);
	YESNO(pDCB->SyncMode & EN_TAG_QUEUEING);
	NegoPeriod = dc395x_clock_period[pDCB->SyncPeriod & 0x07] << 2;
	if (pDCB->SyncOffset)
	    SPRINTF("  %03i ns ", NegoPeriod);
	else
	    SPRINTF(" (%03i ns)", (pDCB->MinNegoPeriod << 2));

	if (pDCB->SyncOffset & 0x0f)
	{
	    spd =  1000/(NegoPeriod);
	    spd1 = 1000%(NegoPeriod);
	    spd1 = (spd1 * 10 + NegoPeriod/2)/(NegoPeriod);
	    SPRINTF("   %2i.%1i M     %02i ", spd, spd1, (pDCB->SyncOffset & 0x0f));
	}
	else
	    SPRINTF("                 ");

	/* Add more info ...*/
        SPRINTF ("     %02i\n", pDCB->MaxCommand);
	pDCB = pDCB->pNextDCB;
    }
	
    SPRINTF ("Commands in Queues: Query: %i:", pACB->QueryCnt);
    for (pcmd = pACB->pQueryHead; pcmd; pcmd = pcmd->next)
	SPRINTF (" %li", pcmd->pid);
    if (timer_pending(&pACB->Waiting_Timer)) SPRINTF ("Waiting queue timer running\n");
    else SPRINTF ("\n");
    pDCB = pACB->pLinkDCB;
	
    for (dev = 0; dev < pACB->DCBCnt; dev++)
    {
	PSRB pSRB;
	if (pDCB->WaitSRBCnt) 
		    SPRINTF ("DCB (%02i-%i): Waiting: %i:", pDCB->TargetID, pDCB->TargetLUN,
			     pDCB->WaitSRBCnt);
	for (pSRB = pDCB->pWaitingSRB; pSRB; pSRB = pSRB->pNextSRB)
		SPRINTF(" %li", pSRB->pcmd->pid);
	if (pDCB->GoingSRBCnt) 
		    SPRINTF ("\nDCB (%02i-%i): Going  : %i:", pDCB->TargetID, pDCB->TargetLUN,
			     pDCB->GoingSRBCnt);
	for (pSRB = pDCB->pGoingSRB; pSRB; pSRB = pSRB->pNextSRB)
#ifdef DC395x_DEBUGTRACE
		SPRINTF("\n  %s", pSRB->debugtrace);
#else
		SPRINTF(" %li", pSRB->pcmd->pid);
#endif
	if (pDCB->WaitSRBCnt || pDCB->GoingSRBCnt
	    ) SPRINTF ("\n");
	pDCB = pDCB->pNextDCB;
    }
	
#ifdef DC395x_DEBUGDCB
    SPRINTF ("DCB list for ACB %p:\n", pACB);
    pDCB = pACB->pLinkDCB;
    SPRINTF ("%p", pDCB);
    for (dev = 0; dev < pACB->DCBCnt; dev++, pDCB=pDCB->pNextDCB)
	SPRINTF ("->%p", pDCB->pNextDCB);
    SPRINTF("\n");
#endif
  
    *start = buffer + offset;
    DC395x_UNLOCK_IO(pACB->pScsiHost);

    if (pos - buffer < offset)
	return 0;
    else if (pos - buffer - offset < length)
	return pos - buffer - offset;
    else
	return length;
}

#ifdef MODULE

/*
**********************************************************************
** Function : int DC395x_shutdown (struct Scsi_Host *host)
**  Purpose : does a clean (we hope) shutdown of the SCSI chip.
**		Use prior to dumping core, unloading the driver, etc.
**  Returns : 0 on success
**********************************************************************
*/
int DC395x_shutdown (struct Scsi_Host *host)
{
    PACB     pACB;
    //DWORD    acb_flags=0;
    
    pACB = (PACB)(host->hostdata);
    
    /*  pACB->soft_reset(host); */
    /*
    ** disable interrupt
    */
    DC395x_write8(TRM_S1040_DMA_INTEN, 0);
    DC395x_write8(TRM_S1040_SCSI_INTEN, 0);
    if (timer_pending (&pACB->Waiting_Timer))
	    del_timer (&pACB->Waiting_Timer);
    if (timer_pending (&pACB->SelTO_Timer))
	    del_timer (&pACB->SelTO_Timer);
    
    if (1 || pACB->Config & HCC_SCSI_RESET)
	DC395x_ResetSCSIBus( pACB );

    DC395x_read8 (TRM_S1040_SCSI_INTSTATUS);
#ifdef DC395x_DEBUGTRACE
    DC395x_free_tracebufs (pACB, DC395x_MAX_SRB_CNT);
#endif	
    DC395x_free_SG_tables (pACB, DC395x_MAX_SRB_CNT);
    return( 0 );
}


/* Free all DCBs */
void DC395x_freeDCBs (struct Scsi_Host *host)
{
    PDCB pDCB, nDCB;
    PACB pACB = (PACB)(host->hostdata);

    DCBDEBUG (printk (KERN_INFO "DC395x: Free %i DCBs\n", pACB->DCBCnt);)
    pDCB = pACB->pLinkDCB;
    if (!pDCB) return;
    do
    {
	nDCB = pDCB->pNextDCB;
	DCBDEBUG(printk (KERN_INFO "DC395x: Free DCB (ID %i, LUN %i): %p\n",\
			pDCB->TargetID, pDCB->TargetLUN, pDCB);)
	DC395x_remove_dev (pACB, pDCB); // includes a KFREE (pDCB);	
	printk (".");
	pDCB = nDCB;
    } while (pDCB && pACB->pLinkDCB);
};

/*
*********************************************************************
**
**
**
*********************************************************************
*/
int DC395x_release(struct Scsi_Host *host)
{
    int			irq_count;
    DWORD		flags;
    PACB		pACB = (PACB)(host->hostdata);
    //DWORD		acb_flags=0;
    DC395x_LOCK_IO(pACB->pScsiHost);
    //DC395x_ACB_LOCK(pACB,acb_flags);
    printk ("DC395x: Shutdown .");
    DC395x_shutdown (host);
    DC395x_freeDCBs (host);
    
    if (host->irq != SCSI_IRQ_NONE)
    {
	for (irq_count = 0, pACB = DC395x_pACB_start; 
	     pACB != (PACB)-1; pACB = pACB->pNextACB)
	{
		if ( pACB->IRQLevel == host->irq )
			++irq_count;
	}
	if (irq_count == 1)
		free_irq(host->irq, DC395x_pACB_start);
    }
    release_region(host->io_port,host->n_io_port);
	
    DC395x_UNLOCK_IO(pACB->pScsiHost);
    //DC395x_DRV_UNLOCK(drv_flags);
    return( 1 );
}
#endif /* def MODULE */

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99)
static Scsi_Host_Template driver_template = DC395x_TRMS1040;
# include "scsi_module.c"
#elif defined (MODULE) 
Scsi_Host_Template driver_template = DC395x_TRMS1040;
# include "scsi_module.c"
#endif
