diff -Nru linux/Documentation/Configure.help linux-2.4.19-pre5-mjc/Documentation/Configure.help
--- linux/Documentation/Configure.help	Mon Apr  8 22:26:52 2002
+++ linux-2.4.19-pre5-mjc/Documentation/Configure.help	Mon Apr  8 22:36:09 2002
@@ -8103,6 +8103,19 @@
   say M here and read <file:Documentation/modules.txt>.  The module
   will be called sim710.o.
 
+Tekram DC395/U/UW and DC315/U SCSI support
+CONFIG_SCSI_DC395x_TRMS1040
+  This driver supports the PCI SCSI host adapters baseds on Tekram's
+  ASIC TRM-S1040 chip, i.e. Tekram DC315 and DC395 variants.
+  This driver does work, but please note that it is still beta status,
+  so better have a bootable disk and a backup in case of emergency.
+  Please read the file <file:drivers/scsi/README.dc395x>.
+  
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read <file:Documentation/modules.txt>. The module will be
+  called dc395x_trm.o.
+
 Tekram DC390(T) and Am53/79C974 SCSI support
 CONFIG_SCSI_DC390T
   This driver supports PCI SCSI host adapters based on the Am53C974A
diff -Nru linux/MAINTAINERS linux-2.4.19-pre5-mjc/MAINTAINERS
--- linux/MAINTAINERS	Mon Apr  8 22:35:07 2002
+++ linux-2.4.19-pre5-mjc/MAINTAINERS	Mon Apr  8 22:36:09 2002
@@ -421,10 +421,12 @@
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
-DC390/AM53C974 SCSI driver
+DC390/AM53C974 and DC395/TRM-S1040 SCSI drivers
 P:	Kurt Garloff
 M:	garloff@suse.de
-W:	http://www.garloff.de/kurt/linux/dc390/
+M:	kurt@garloff.de
+W:	http://www.garloff.de/kurt/linux/
+L:	linux-scsi@vger.kernel.org
 S:	Maintained
 
 DECnet NETWORK LAYER
diff -Nru linux/drivers/scsi/Config.in linux-2.4.19-pre5-mjc/drivers/scsi/Config.in
--- linux/drivers/scsi/Config.in	Mon Feb 25 14:38:04 2002
+++ linux-2.4.19-pre5-mjc/drivers/scsi/Config.in	Mon Apr  8 22:36:09 2002
@@ -189,6 +189,9 @@
 dep_tristate 'Simple 53c710 SCSI support (Compaq, NCR machines)' CONFIG_SCSI_SIM710 $CONFIG_SCSI
 dep_tristate 'Symbios 53c416 SCSI support' CONFIG_SCSI_SYM53C416 $CONFIG_SCSI
 if [ "$CONFIG_PCI" = "y" ]; then
+   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+     dep_tristate 'Tekram DC395/U/UW and DC315/U SCSI support' CONFIG_SCSI_DC395x_TRMS1040 $CONFIG_SCSI
+   fi
    dep_tristate 'Tekram DC390(T) and Am53/79C974 SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI
    if [ "$CONFIG_SCSI_DC390T" != "n" ]; then
       bool '  _omit_ support for non-DC390 adapters' CONFIG_SCSI_DC390T_NOGENSUPP
diff -Nru linux/drivers/scsi/Makefile linux-2.4.19-pre5-mjc/drivers/scsi/Makefile
--- linux/drivers/scsi/Makefile	Mon Feb 25 14:38:04 2002
+++ linux-2.4.19-pre5-mjc/drivers/scsi/Makefile	Mon Apr  8 22:36:09 2002
@@ -104,6 +104,7 @@
 obj-$(CONFIG_SCSI_IBMMCA)	+= ibmmca.o
 obj-$(CONFIG_SCSI_EATA)		+= eata.o
 obj-$(CONFIG_SCSI_DC390T)	+= tmscsim.o
+obj-$(CONFIG_SCSI_DC395x_TRMS1040)	+= dc395x_trm.o
 obj-$(CONFIG_SCSI_AM53C974)	+= AM53C974.o
 obj-$(CONFIG_SCSI_MEGARAID)	+= megaraid.o
 obj-$(CONFIG_SCSI_ACARD)	+= atp870u.o
diff -Nru linux/drivers/scsi/README.dc395x linux-2.4.19-pre5-mjc/drivers/scsi/README.dc395x
--- linux/drivers/scsi/README.dc395x	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/drivers/scsi/README.dc395x	Mon Apr  8 22:36:09 2002
@@ -0,0 +1,282 @@
+README file for the dc395x_trm SCSI driver
+==========================================
+
+Preliminary. 2000-02-14 Kurt Garloff <garloff@suse.de>
+$Id: README.dc395x,v 1.16 2002/02/13 10:23:58 garloff Exp $
+
+This driver is similar to the DC390/AM53c974 driver (tmscsim), so you might
+want to have a look into the README.tmscsim.
+The tmscsim has undergone a lot of development since the 1.10 version, most
+notably the configuration via parameters and /proc/scsi/tmscsim/?.
+
+These features are now almost completely implemented for the dc395x_trm
+driver, too.
+
+Status
+------
+The dc395x_trm is BETA. This means that it might crash your hard disk or
+fail to read your CD-Rom.
+It seems to basically work for a lot of cases and success reports have been
+sent to me. On the other hand, I have a few failure reports, which I was not
+yet able to resolve. So, don't rely on this driver. Not yet.
+
+It is a good idea, to have a BACKUP, if you have valuable data on your disk.
+If you can't do it, print at least your partition table or save it to a safe
+place and have a boot floppy ready.
+
+Status (2)
+----------
+The driver works perfectly for my Fireball harddisk but fails sometimes on
+my IBM DORS and on my IBM DCAS drive and on my Plextor UltraPlex.
+I have no clue at all, why it happens. 
+I spent a couple of days investigating, creating a driver with extensive
+sanity checks and debugging possibilities. To no avail! I will look into
+this again, when I get good docu from Tekram. The one I have currently is
+lousy.
+The driver now at least works partially.
+The following things seem to help:
+Disallowing disconnection, Sync transfers for the device in question or
+lowering the Sync speed. Sync speeds of 10MHz or lower seem to work all the
+time for me.
+
+It seems to be related to Sync transfers done via the S/G DMA. The tests
+being done lead to no conclusion, though. If you find some pattern, please
+let me know.
+More hints: The data integrity checks within the driver all succeed.
+
+The transfers normally succeed until after some reselections, the device
+does not finish the DataIn phase. The SCSI Counter says that a certain
+number of bytes have been transfered (and this number seems to be equal to
+0x1000 or at least a multiple of 0x200) successfully and the SCSI FIFO is
+empty. The DMA engine seems also to approach a block boundary: A Current
+TransferCtr of 0x208 with a FIFO counter of 0x08 is a typical value.
+(That happens with reading from the DORS.) The bus is locked up (probably
+the dev. is waiting for some more ACKs).
+
+If the S/G support is limited to one segment, preventing the above to
+happen, the bus seems to be locked up after a Disconnection, so the next
+command being sent (TagQ is enabled) fails.
+
+Status (3)
+----------
+It seems to be a matter of the quality of your SCSI bus and the quality of
+the lnie drivers of the DC395. While the NCR53C8xx drives a bus with 2.5m
+length and 7 devices without problems at 20MHz, the DC395UW locks up the
+bus, if driven with more than 10MHz. Using 10MHz max. Sync Frequency, I
+could not produce problems.
+
+Reducing the bus to 1.2m and 3 devices, the DC395UW happily does 13.3MHz.
+The 20MHz are still not perfect, and I could watch a problem once. (Whereas
+the bus now should really be perfect for doing high speed transfers.)
+
+It's also completely unclear to me, why this problem does not occur, if
+disconnection is turned off for the fast devices. Then, I can do 20MHz with
+the DC395UW on the long bus setup.
+
+Maybe the chip is extremely sensitive to timing issues, maybe the line
+drivers are not very good, maybe its input filters are not very good.
+
+I did play a little bit with the filter cfg. of the Tekram, but without too
+much success. Disabling the Active Negation _Enhance_ feature gave a little
+bit better results, so I did disable it for the driver.
+You may want to play with the FilterCfg setting yourself, the /proc
+interface allows to change it.
+(Bits: 0: Always 1, 1: Active Negation, 2: Fast Filter enable, 3: Data
+ Filter disable, 4: Active Negation enhance)
+
+Status (4)
+----------
+Part of the above said has to be taken back. The driver did still have one
+serious bug which -- for timing reasons -- only showed on fast transfers and
+a busy SCSI bus. A FIFO was cleared at the wrong place.
+Now, the driver seems to work with 20MHz on my system reliably.
+The hardware is not quite well supporting more than one initiator controller
+on the bus: If the bus is busy and the TRM_S1040 tries to arbitrate and 
+select a device, it does not always generate an interrupt (which would
+indicate Disconnection, Selection Timeout, Reselection or -- in the best
+case -- a phase change). The driver takes this into account now and does not
+even try. Instead the waiting queue will be woken up by a timer a 50 ms
+later to try again.
+
+
+Exception handling and automatic downgrading
+--------------------------------------------
+For the positive side:
+The exception handling procedure (invoked from mid-level SCSI code) does its
+job pretty well in most of the cases, so your transfers proceed after the
+SCSI bus has been reset. (No, this won't make you happy, if you are
+writing to tapes or CDRs, but otherwise, you may be lucky.) In spite of the
+bus lock ups, I did not loose any data on my harddisks.
+The driver is clever enough to reduce the settings for the device which
+caused the bus lockup, so after a few resets the driver will have found the
+maximum possible speed of your drive. So even with a bad bus, you will be
+able to use this driver in slow mode. (Use the /proc/scsi interface to try
+to change the settings again. You may choose to disable disconnections
+instead of lowering the speed of sync transfers.)
+
+
+Usage
+-----
+I would currently not suggest to use this driver, if you are dealing with
+important data, which you don't have a backup of! YOU RISK DATA LOSS!
+
+OK, you want to use it anyway?
+Start with read-only access of your data. catting or dding it to /dev/null
+is a good start. Proceed with read-only filesystem checks (e2fsck -nfF).
+Produce concurrent load on your SCSI bus. Still no trouble? What does the
+badblocks program say? (Take care: With -w it will overwrite your data!)
+Go on, mount rw an unused partition and run bonnie a couple of times.
+Run it twice concurrently. If you have not seen any problems by now, you
+might want to take the risk and use it on your normal filesystems.
+If you find any trouble, you can reduce the Sync Speed and try again. That
+way, you may find the best safe settings for your bus.
+
+Please note that the driver spits out some debug messages from time to time.
+Those start with "DC395x: Debug:" and are certainly no reason to worry.
+
+If you find trouble, you can contact me, of course. Please, don't bother
+sending useless bug reports saying: It does not work. You should at least be
+able to provide some details about your SCSI setup, the messages written to
+the syslog and the outputs of /proc/scsi/scsi and /proc/scsi/dc395x_trm/?.
+
+If your driver crashes badly, log via network or a serial console. (The
+latter is what I do during driver development.)
+
+If you can provide me with exact observations and logs of failures, I would
+be very pleased! 
+
+
+Parameters
+----------
+The driver uses the settings from the EEPROM set in the SCSI BIOS 
+setup.
+If there is no EEPROM, the driver uses default values.
+Both can be overriden by command line parameters (module or kernel
+parameters). [This is new; formerly the EEprom could not be overriden.]
+
+The syntax is as follows:
+ dc395x_trm = AdapterID, SpeedIdx, DevMode, AdaptMode, Tags, DelayReset
+
+AdapterID : Host Adapter SCSI ID
+SpeedIdx  : 0,1,...7 = 20,13.3,10,8,6.7,5.8,5,4 MHz               [ 7]
+DevMode   : Bitmap for Dev Cfg                                    [63]
+AdaptMode : Bitmap for Adapter Cfg                                [47]
+Tags      : The number of tags is 1<<x, if x has been specified   [ 4]
+DelayReset: The seconds to not accept commands after a SCSI Reset [ 1]
+
+DevMode bit definition:
+   Bit Val(hex) Val(dec)  Meaning
+   *0	 0x01	    1	  Parity check
+   *1	 0x02	    2	  Synchronous Negotiation
+   *2	 0x04	    4	  Disconnection
+   *3	 0x08	    8	  Send Start command on startup. (Not used)
+   *4	 0x10	   16	  Tagged Command Queueing
+   *5	 0x20	   32	  Wide Negotiation
+
+AdaptMode bit definition
+   Bit Val(hex) Val(dec)  Meaning
+   *0	 0x01	    1	  Support more than two drives. (Not used)
+   *1	 0x02	    2	  Use DOS compatible mapping for HDs greater than 1GB.
+   *2	 0x04	    4	  Reset SCSI Bus on startup.
+   *3	 0x08	    8	  Active Negation: Improves SCSI Bus noise immunity.
+    4	 0x10	   16	  Immediate return on BIOS seek command. (Not used)
+ (*)5	 0x20	   32	  Check for LUNs >= 1.
+
+If you set AdapterID to -1, the adapter will use conservative ("safe")
+default settings instead; more precisely, dc395x_trm=-1 is a shortcut for
+dc395x_trm=7,4,9,15,2,10
+
+If you specify -2 for a value, it will be ignored. You don't need to specify
+all six parameters.
+
+Note, that you can also influence the behaviour of the host adapter at
+runtime by echoing values to /proc/scsi/dc395x_trm/?. Have a look at
+README.tmscsim for explanation and examples. The syntax is the same, except
+for the added "Wide" setting.
+
+
+Installation
+------------
+As long as this driver is not yet integrated into the mainstream kernel, you
+have to do some handwork to install the driver. 
+IF YOU NEVER COMPILED A KERNEL YOURSELF BEFORE, YOU SHOULD NOW BETTER GO AND
+READ SOME DOCUMENTATION ABOUT IT. YOU ARE LIKELY TO SCREW YOURSELF, OTHERWISE.
+FIRST COMPILE A KERNEL WITHOUT THIS DRIVER AND GET IT TO WORK.
+Maybe you Linux distributor will be nice enough to include the driver in its
+distribution, so you don't have to do it yourself.
+
+OK, if you want to do it: Get the driver distribution dc395-1??.tar.gz.
+Unpack it: 
+> tar xvzf dc395-1??.tar.gz
+Copy the driver files to the linux source tree:
+> cp -p dc395/dc395x_trm.? /usr/src/linux/drivers/scsi/
+> cp -p dc395/README.dc395x /usr/src/linux/drivers/scsi/
+and apply the appropriate patch to your kernel source tree. Depending on
+your kernel version, this is dc395-integ20.diff, dc395-integ22.diff or
+dc395-integ24.diff. (Replace XX by 20, 22, 23 or 24)
+> patch -p1 -d /usr/src/linux <dc395/dc395-integXX.diff
+The patches have been built against a 2.0.38, a 2.2.13, a 2.3.48 
+and a 2.4.6 kernel.
+Note that you might get rejections, if you use different kernels, but those
+should be easy to fix manually. 
+Look out for the .rej files (find . -name "*.rej")
+Note: If you use a SuSE kernel source tree from SuSE 6.2 or later, you don't
+need to apply the kernel patch, as those come with some version of the
+dc395x driver. SuSE 6.2/6.3 kernels lack the init/main.c part of the patch,
+though, so you can't use boot time params for a DC315, then. Of course, you
+can isolate the diff part to init/main.c and apply it to make this work ...
+
+Now you have to reconfigure your kernel (make oldconfig or make menuconfig),
+enable the DC395x driver (compiled into the kernel or as a module; note that
+you need to enable CONFIG_EXPERIMENTAL to be able to select the DC395
+driver; of course you need it in the kernel, if your root fs resides on a
+partition connected to the DC395 and you don't do advanced INITRD tricks)
+and recompile your kernel and your modules:
+> cd /usr/src/linux
+> make oldconfig  (enable CONFIG_SCSI_DC395x_TRMS1040)
+> make bzlilo
+> make modules
+> make modules_install
+> depmod -ae
+
+NEW: You may be able to skip compilation of the kernel by just using the
+Makefile. For 2.4 kernels, if you compile outside the kernel source tree,
+you don't even need to apply a patch to your kernel any more.
+
+I will provide a complete patch which makes kernel integration easier and
+will ask to apply it to the main tree, as soon as I got enough reports about
+the stability of the driver.
+Currently, there are still too many problems left :-(
+
+
+Copyright
+---------
+The driver is free software. It is protected by the GNU General Public
+License (GPL). Please read it, before using this driver. It should be
+included in your kernel sources and with your distribution. It carries the
+filename COPYING. If you don't have it, please ask me to send you one by
+email.
+Note: The GNU GPL says also something about warranty and liability. 
+Please be aware the following: While I do my best to provide a working and
+reliable driver, there is a chance, that it will kill your valuable data. 
+I refuse to take any responsibility for that. The driver is provided as-is
+and YOU USE IT AT YOUR OWN RESPONSIBILITY.
+
+
+Updates
+-------
+Resources for this driver can be found on
+http://www.garloff.de/kurt/linux/dc395/
+ftp://ftp.suse.com/pub/people/garloff/linux/dc395/
+(and mirrors, of course)
+Announcements will be sent to the linux-scsi@vger.kernel.org list.
+
+
+Acknowledgements
+----------------
+I'd like to thank SuSE GmbH, Nuremberg, to allow me working on this driver
+during my working hours for them.
+Thanks to all the people that took the risk to install the driver in its
+alpha stage and sent detailed bug reports to me, sometimes. Without them,
+the driver would now not approach stability. They are the reason why free
+software rules.
diff -Nru linux/drivers/scsi/dc395x_trm.c linux-2.4.19-pre5-mjc/drivers/scsi/dc395x_trm.c
--- linux/drivers/scsi/dc395x_trm.c	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/drivers/scsi/dc395x_trm.c	Mon Apr  8 22:36:09 2002
@@ -0,0 +1,7674 @@
+//***********************************************************************
+//*      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.79 2002/03/11 02:34:37 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
+//***********************************************************************
+/*
+*************************************************************************
+**
+**
+** 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
+
+/* 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"
+#include "constants.h"
+#include "sd.h"
+#include "dc395x_trm.h"
+
+#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)			\
+	(inb (pACB->IOPortBase + (address)))
+
+#define DC395x_read8_(address, base)		\
+	(inb ((USHORT)(base) + (address)))
+
+#define DC395x_read16(address)			\
+	(inw (pACB->IOPortBase + (address)))
+
+#define DC395x_read32(address)			\
+	(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)
+#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 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 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_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);
+static void DC395x_ScsiRstDetect( PACB pACB );
+//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)
+void __init 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 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
+    pSRB->debugpos = 0;
+    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 %04x IRQStat %02x IRQEn %02x Cfg %04x\n",
+		DC395x_read16 (TRM_S1040_DMA_COMMAND), DC395x_read16 (TRM_S1040_DMA_FIFOCNT),
+		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);
+
+		
+}
+
+
+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;
+	}
+}
+
+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);
+}
+  
+/*
+**********************************************************************
+**
+** 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_write16 (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 );
+}
+
+/*
+*********************************************************************
+**
+**		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
+
+/*
+**********************************************************************
+**
+** 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 );
+    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 *");
+}
+
+
+/* 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);
+}	
+
+
+/*
+**********************************************************************
+** 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 & 0xC0))
+    {
+	    /* 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
+	
+    pACB = DC395x_pACB_start;
+    if( pACB == NULL )
+    {
+	printk(KERN_WARNING "DC395x: Interrupt on uninitialized pACB!\n");
+	return;
+    }
+
+    DC395x_LOCK_IO(pACB->pScsiHost);
+
+    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_write16 (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_unlock;
+    }
+    /* 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:
+    DEBUGRECURSION(in_driver--;)
+    DC395x_UNLOCK_IO(pACB->pScsiHost);
+    //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_read16(TRM_S1040_DMA_FIFOCNT) & 0x8000))
+			DC395x_write8(TRM_S1040_DMA_CONTROL, CLRXFIFO);
+	}
+	else
+	{	/* write */
+		if (!(DC395x_read16(TRM_S1040_DMA_FIFOCNT) & 0x8000))
+			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: %04x, SCSI_FCNT: %02x, CTR %06x, stat %04x, Tot: %06x\n",
+	    DC395x_read16 (TRM_S1040_DMA_FIFOCNT),
+	    DC395x_read8  (TRM_S1040_SCSI_FIFOCNT), 
+	    DC395x_read32 (TRM_S1040_SCSI_COUNTER), 
+	    scsi_status, pSRB->SRBTotalXferLength);
+    //DC395x_dumpinfo(pACB, pDCB, pSRB);
+#endif
+    DC395x_write16 (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, DMA CTR %08x\n",
+		    DC395x_read16 (TRM_S1040_DMA_FIFOCNT),
+		    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_read16 (TRM_S1040_DMA_FIFOCNT) & 0x8000)) {
+#if 0
+	    int ctr = 6000000;
+	    printk ("DC395x: DIP0: Wait for DMA FIFO to flush ...\n");
+	    //DC395x_write16 (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_FIFOCNT) & 0x8000) && --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: %04x\n",
+		    DC395x_read16 (TRM_S1040_DMA_FIFOCNT));
+#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 %04x, DMA CTR %08x\n",
+		DC395x_read16 (TRM_S1040_DMA_FIFOCNT),
+		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=%04x, SCSI_FIFO=%02x\n",
+		dLeftCounter, DC395x_read16 (TRM_S1040_DMA_FIFOCNT),
+		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, Grard, 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);
+	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);
+};
+
+
+/*
+*********************************************************************
+** 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
+	/* 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;
+	/*
+	** 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);
+    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);
+    }
+    //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 )
+{
+    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;
+	    pSRBTemp = pSRB->pNextSRB;
+	    pcmd = pSRB->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)");
+#ifndef 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);
+#ifndef USE_NEW_EH
+	    /* For new EH, don't give commands back */
+	    pcmd->result = result;
+	    //DC395x_SCSI_DONE_ACB_UNLOCK;
+	    // TODO: PCI_UNMAP
+	    pcmd->scsi_done( pcmd );
+	    //DC395x_SCSI_DONE_ACB_LOCK;
+#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)");
+#ifndef 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);
+
+#ifndef USE_NEW_EH
+	    /* For new EH, don't give commands back */
+	    pcmd->result = result;
+	    //DC395x_SCSI_DONE_ACB_UNLOCK;
+	    // TODO: PCI_UNMAP
+	    pcmd->scsi_done( pcmd );
+	    //DC395x_SCSI_DONE_ACB_LOCK;
+#endif
+	    pSRB = pSRBTemp;
+	}
+	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 );
+	//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);
+	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;
+    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);
+	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 != 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
diff -Nru linux/drivers/scsi/dc395x_trm.h linux-2.4.19-pre5-mjc/drivers/scsi/dc395x_trm.h
--- linux/drivers/scsi/dc395x_trm.h	Wed Dec 31 19:00:00 1969
+++ linux-2.4.19-pre5-mjc/drivers/scsi/dc395x_trm.h	Mon Apr  8 22:36:09 2002
@@ -0,0 +1,135 @@
+/*
+**********************************************************************
+**	File Name : dc395x_trm.h
+**				
+**  TEKRAM DC395U/UW/F ,DC315/U
+**  PCI SCSI Bus Master Host AdapterDevice Driver
+**  (SCSI chip set used Tekram ASIC TRM-S1040)
+**		    				 
+**********************************************************************
+*/
+/* $Id: dc395x_trm.h,v 1.39 2002/03/11 02:34:37 garloff Exp $ */
+/*
+*****************************************************
+**    Tekram TRM_S1040 for DC395x driver, header file
+*****************************************************
+*/
+#ifndef DC395x_trm_H
+#define DC395x_trm_H
+
+#include <linux/config.h>
+
+#define DC395x_BANNER "Tekram DC395U/UW/F DC315/U"
+#define DC395x_VERSION "1.38, 2002-03-11"
+
+/* Kernel version autodetection */
+#include <linux/version.h>
+#ifndef KERNEL_VERSION
+# define KERNEL_VERSION(V, P, S)	(((V) << 16) + ((P) << 8) + (S))
+#endif
+
+//-----------------------------------------------------
+#if LINUX_VERSION_CODE < KERNEL_VERSION(1,3,50)
+       #define VERSION_ELF_1_2_13
+#elseif LINUX_VERSION_CODE < KERNEL_VERSION(1,3,95)
+       #define VERSION_1_3_85
+#else
+       #define VERSION_2_0_0
+#endif
+
+#if defined(__SMP__) && !defined(CONFIG_SMP)
+# define CONFIG_SMP
+#endif
+
+#define DC395x_MAX_CMD_QUEUE	32
+//#define DC395x_MAX_QTAGS	32
+#define DC395x_MAX_QTAGS	16
+#define DC395x_MAX_ADAPTER_NUM	4
+#define DC395x_MAX_SCSI_ID	16
+#define DC395x_MAX_CMD_PER_LUN	DC395x_MAX_QTAGS 
+#define DC395x_MAX_SG_TABLESIZE	64	/* HW limitation */
+#define DC395x_MAX_SG_LISTENTRY	64	/* Must be equal or lower to previous item */
+#define DC395x_MAX_SRB_CNT	63
+//#define DC395x_MAX_CAN_QUEUE	7 * DC395x_MAX_QTAGS
+#define DC395x_MAX_CAN_QUEUE	DC395x_MAX_SRB_CNT
+#define DC395x_END_SCAN		2
+#define DC395x_SEL_TIMEOUT	153	/* 250 ms selection timeout (@ 40 MHz) */
+#define DC395x_MAX_RETRIES	3
+
+//#define SYNC_FIRST
+
+/* We don't have eh_abort_handler, eh_device_reset_handler, 
+ * eh_bus_reset_handler, eh_host_reset_handler yet! 
+ * So long: Use old exception handling :-( */
+#define OLD_EH
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION (2,1,70)) || defined(OLD_EH)
+# define NEW_EH
+# define NORM_REC_LVL 1
+#else
+# define USE_NEW_EH
+# define NORM_REC_LVL 0
+# define NEW_EH use_new_eh_code: 1,
+#endif
+
+#if defined(HOSTS_C) || defined(MODULE) || LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99)
+
+# include <scsi/scsicam.h>
+
+extern  int DC395x_detect(Scsi_Host_Template *psht);
+extern  int DC395x_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
+extern  int DC395x_abort(Scsi_Cmnd *cmd);
+extern  int DC395x_reset(Scsi_Cmnd *cmd ,unsigned int resetFlags);
+extern  int DC395x_bios_param(Disk *disk, kdev_t devno, int geom[]);
+//--------------
+# ifdef  MODULE
+static  int DC395x_release(struct Scsi_Host *);
+# else
+#  define DC395x_release NULL
+# endif
+//--------------
+extern  int DC395x_proc_info(char*, char**, off_t, int, int, int);
+//--------------
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
+# define DC395x_TRMS1040  {					\
+		proc_name:	"dc395x_trm",			\
+		proc_info:	DC395x_proc_info,		\
+		name:		DC395x_BANNER " V" DC395x_VERSION,\
+		detect:		DC395x_detect,			\
+		release:	DC395x_release,			\
+		queuecommand:	DC395x_queue_command,		\
+		abort:		DC395x_abort,			\
+		reset:		DC395x_reset,			\
+		bios_param:	DC395x_bios_param,		\
+		can_queue:	DC395x_MAX_CAN_QUEUE,		\
+		this_id:	7,				\
+		sg_tablesize:	DC395x_MAX_SG_TABLESIZE,	\
+		cmd_per_lun:	DC395x_MAX_CMD_PER_LUN,		\
+		NEW_EH						\
+		unchecked_isa_dma: 0,				\
+		use_clustering:	DISABLE_CLUSTERING		\
+		}
+#else
+extern  struct proc_dir_entry DC395x_proc_scsi;
+# define DC395x_TRMS1040  {					\
+		proc_dir:	&DC395x_proc_scsi,		\
+		proc_info:	DC395x_proc_info,		\
+		name:		DC395x_BANNER " V" DC395x_VERSION,\
+		detect:		DC395x_detect,			\
+		release:	DC395x_release,			\
+		queuecommand:	DC395x_queue_command,		\
+		abort:		DC395x_abort,			\
+		reset:		DC395x_reset,			\
+		bios_param:	DC395x_bios_param,		\
+		can_queue:	DC395x_MAX_CAN_QUEUE,		\
+		this_id:	7,				\
+		sg_tablesize:	DC395x_MAX_SG_TABLESIZE,	\
+		cmd_per_lun:	DC395x_MAX_CMD_PER_LUN,		\
+		NEW_EH						\
+		unchecked_isa_dma: 0,				\
+		use_clustering:	DISABLE_CLUSTERING		\
+		}
+#endif /* 2,3,30 */
+#endif /* defined(HOSTS_C) || defined(MODULE) || LINUX_VERSION_CODE > 2,3,99 */
+#endif /* DC395x_H */
