Index: README.dc395x =================================================================== RCS file: README.dc395x diff -N README.dc395x --- /dev/null Sun Oct 3 02:13:27 1999 +++ /tmp/cvscbqNSr Sun Feb 13 18:08:55 2000 @@ -0,0 +1,139 @@ +README file for the dc395x_trm SCSI driver +========================================== + +Preliminary. 2000-02-10 Kurt Garloff +$Id: README.dc395x,v 1.5 2000/02/13 16:52:55 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. The kernel/module params are still missing, though. +Currently, you have to change the BIOS' settings, if you need to change the +driver's settings right from the start. (Later, you can do with the +/proc/scsi/dc395x_trm interface.) + +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) + +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 od 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? +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. + +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, I would be very +pleased! + + +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 list. + Index: dc395-integ.diff =================================================================== RCS file: /home/cvsroot/dc395/dc395-integ.diff,v retrieving revision 1.2 retrieving revision 1.3 diff -u -u -r1.2 -r1.3 --- dc395-integ.diff 1999/07/12 15:21:35 1.2 +++ dc395-integ.diff 2000/01/31 21:38:01 1.3 @@ -1,10 +1,12 @@ --- linux/drivers/scsi/Config.in.ORIG Wed Jun 16 23:32:33 1999 +++ linux/drivers/scsi/Config.in Mon Jun 28 21:55:47 1999 -@@ -126,6 +126,7 @@ +@@ -126,6 +126,9 @@ fi dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then -+ dep_tristate 'Tekram DC395/U/UW and DC315/U SCSI support' CONFIG_SCSI_DC395x_TRMS1040 $CONFIG_SCSI ++ 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 @@ -65,7 +67,7 @@ sym53c416.o. +Tekram DC395/U/UW and DC315/U SCSI support -+CONFIG_SCSI_DC395x_TRM1040S ++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 alpha status, Index: dc395-integ20.diff =================================================================== RCS file: /home/cvsroot/dc395/dc395-integ20.diff,v retrieving revision 1.2 retrieving revision 1.3 diff -u -u -r1.2 -r1.3 --- dc395-integ20.diff 1999/08/31 22:01:25 1.2 +++ dc395-integ20.diff 2000/01/31 21:38:01 1.3 @@ -1,10 +1,12 @@ --- linux/drivers/scsi/Config.in.ORIG Mon Jul 12 17:08:37 1999 +++ linux/drivers/scsi/Config.in Mon Jul 12 17:11:42 1999 -@@ -88,6 +88,7 @@ +@@ -88,6 +88,9 @@ fi dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then -+ dep_tristate 'Tekram DC395/U/UW and DC315/U SCSI support' CONFIG_SCSI_DC395x_TRMS1040 $CONFIG_SCSI ++ 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 @@ -75,7 +77,7 @@ and read Documentation/modules.txt. +Tekram DC395/U/UW and DC315/U SCSI support -+CONFIG_SCSI_DC395x_TRM1040S ++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 alpha status, Index: dc395-integ23.diff =================================================================== RCS file: dc395-integ23.diff diff -N dc395-integ23.diff --- /dev/null Sun Oct 3 02:13:27 1999 +++ /tmp/cvs6TKiYn Sun Feb 13 18:08:55 2000 @@ -0,0 +1,89 @@ +--- linux/drivers/scsi/Config.in.orig Wed Dec 15 05:43:56 1999 ++++ linux/drivers/scsi/Config.in Mon Jan 31 22:03:20 2000 +@@ -129,6 +129,9 @@ + fi + dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $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 +--- linux/drivers/scsi/Makefile.orig Thu Dec 30 02:16:30 1999 ++++ linux/drivers/scsi/Makefile Mon Jan 31 22:01:46 2000 +@@ -394,6 +394,14 @@ + endif + endif + ++ifeq ($(CONFIG_SCSI_DC395x_TRMS1040),y) ++L_OBJS += dc395x_trm.o ++else ++ ifeq ($(CONFIG_SCSI_DC395x_TRMS1040),m) ++ M_OBJS += dc395x_trm.o ++ endif ++endif ++ + ifeq ($(CONFIG_SCSI_DC390T),y) + L_OBJS += tmscsim.o + else +--- linux/drivers/scsi/hosts.c.orig Mon Dec 13 08:04:20 1999 ++++ linux/drivers/scsi/hosts.c Mon Jan 31 22:04:29 2000 +@@ -243,6 +243,10 @@ + #include "sym53c416.h" + #endif + ++#ifdef CONFIG_SCSI_DC395x_TRMS1040 ++#include "dc395x_trm.h" ++#endif ++ + #ifdef CONFIG_SCSI_DC390T + #include "dc390.h" + #endif +@@ -562,6 +566,9 @@ + #endif + #ifdef CONFIG_SCSI_EATA + EATA, ++#endif ++#ifdef CONFIG_SCSI_DC395x_TRMS1040 ++ DC395x_TRMS1040, + #endif + #ifdef CONFIG_SCSI_DC390T + DC390_T, +--- linux/Documentation/Configure.help.orig Tue Jan 11 03:25:32 2000 ++++ linux/Documentation/Configure.help Mon Jan 31 22:01:46 2000 +@@ -5045,6 +5045,18 @@ + read Documentation/modules.txt. The module will be called + sym53c416.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 alpha status, ++ so better have a bootable disk and a backup in case of emergency. ++ ++ 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 Documentation/modules.txt. The module will be ++ called dc395x_trm.o. ++ + Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support + CONFIG_SCSI_DC390T + This driver supports PCI SCSI host adapters based on the Am53C974A +--- linux/MAINTAINERS.orig Mon Jan 10 23:19:46 2000 ++++ linux/MAINTAINERS Mon Jan 31 22:01:46 2000 +@@ -255,10 +255,11 @@ + L: linux-hams@vger.rutgers.edu + S: Maintained + +-DC390/AM53C974 SCSI driver ++DC390/AM53C974 and DC395/TRM-S1040 SCSI drivers + P: Kurt Garloff ++M: garloff@suse.de + M: kurt@garloff.de +-W: http://www.garloff.de/kurt/linux/dc390/ ++W: http://www.garloff.de/kurt/linux/ + S: Maintained + + DECnet NETWORK LAYER Index: dc395x_trm.c =================================================================== RCS file: /home/cvsroot/dc395/dc395x_trm.c,v retrieving revision 1.15 retrieving revision 1.35 diff -u -u -r1.15 -r1.35 --- dc395x_trm.c 1999/08/31 22:01:25 1.15 +++ dc395x_trm.c 2000/02/11 18:31:05 1.35 @@ -1,6 +1,6 @@ //*********************************************************************** //* O.S : Linux -//* FILE NAME : dc395x_trm.c +//* FILE NAME : dc395x_trm.c //* BY : C.L. Huang //* Erich Chen //* Description: Device Driver for Tekram DC395U/UW/F ,DC315/U @@ -10,6 +10,7 @@ //*********************************************************************** //* Patches and integration into 2.2+ kernel by //* Kurt Garloff +//* $Id: dc395x_trm.c,v 1.35 2000/02/11 18:31:05 garloff Exp $ //*********************************************************************** //* Tekram PCI SCSI adapter (DC395/U/UW/F or DC315/U) revision history //* @@ -25,7 +26,36 @@ //* 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 dc390-integ20.diff +//* 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. //*********************************************************************** /* ************************************************************************* @@ -57,9 +87,14 @@ */ /* Debugging */ -//#define DC395x_trm_DEBUG_KG -//#define DC395x_trm_DEBUG0 -//#define DC395x_trm_DEBUG1 +//#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 /* DISable features */ //#define DC395x_NO_DISCONNECT @@ -67,8 +102,50 @@ //#define DC395x_NO_SYNC //#define DC395x_NO_WIDE +#ifdef DC395x_DEBUG0 +# define DEBUG0(x) x +#else +# define DEBUG0(x) +#endif -#include +#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_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 704 +# define TRACEPRINTF(x...) \ +do { pSRB->debugpos += sprintf (pSRB->debugtrace+pSRB->debugpos, ## x) - 1; \ + if (pSRB->debugpos >= DEBUGTRACEBUFSZ-16) \ + { pSRB->debugtrace[pSRB->debugpos] = 0; pSRB->debugpos = 128; pSRB->debugtrace[pSRB->debugpos++] = '-'; }; \ + } while (0) +# define TRACEOUT(x...) printk (## x) +#else +# define TRACEPRINTF(x...) do {} while (0) +# define TRACEOUT(x...) do {} while (0) +#endif #ifdef MODULE # include @@ -91,6 +168,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" @@ -100,7 +178,11 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) # include -# include +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30) +# include +# else +# include +# endif /* 2,3,30 */ # define USE_SPINLOCKS 1 #else # define __initfunc(A) A @@ -132,38 +214,78 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) -# define DC395x_TRM_ACB_INITLOCK(pACB) spin_lock_init(&pACB->smp_lock) -# define DC395x_TRM_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_TRM_ACB_UNLOCK(pACB,acb_flags) if(--pACB->lock_level_count[cpuid] == 0) { spin_unlock_irqrestore(&pACB->smp_lock,acb_flags); } +# 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); } -# define DC395x_TRM_SMP_IO_LOCK(irq_flags) spin_lock_irqsave(&io_request_lock,irq_flags) -# define DC395x_TRM_SMP_IO_UNLOCK(irq_flags) spin_unlock_irqrestore(&io_request_lock,irq_flags) +# define DC395x_SMP_IO_LOCK(irq_flags) spin_lock_irqsave(&io_request_lock,irq_flags) +# define DC395x_SMP_IO_UNLOCK(irq_flags) spin_unlock_irqrestore(&io_request_lock,irq_flags) -# define DC395x_TRM_SCSI_DONE_ACB_LOCK spin_lock(&(pACB->smp_lock)) -# define DC395x_TRM_SCSI_DONE_ACB_UNLOCK spin_unlock(&(pACB->smp_lock)) +# 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_TRM_ACB_INITLOCK(pACB) -# define DC395x_TRM_ACB_LOCK(pACB,acb_flags) do { save_flags(acb_flags); cli(); } while (0) -# define DC395x_TRM_ACB_UNLOCK(pACB,acb_flags) do { restore_flags(acb_flags); } while (0) +# 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_TRM_SMP_IO_LOCK(irq_flags) do { save_flags(irq_flags); cli(); } while (0) -# define DC395x_TRM_SMP_IO_UNLOCK(irq_flags) do { restore_flags(irq_flags); } while (0) +# define DC395x_SMP_IO_LOCK(irq_flags) do { save_flags(irq_flags); cli(); } while (0) +# define DC395x_SMP_IO_UNLOCK(irq_flags) do { restore_flags(irq_flags); } while (0) -# define DC395x_TRM_SCSI_DONE_ACB_LOCK -# define DC395x_TRM_SCSI_DONE_ACB_UNLOCK +# define DC395x_SCSI_DONE_ACB_LOCK +# define DC395x_SCSI_DONE_ACB_UNLOCK #endif -# define DC395x_TRM_DRV_LOCK(drv_flags) do { save_flags(drv_flags); cli(); } while (0) -# define DC395x_TRM_DRV_UNLOCK(drv_flags) do { restore_flags(drv_flags); } while (0) +# 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)) + +/* 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 */ @@ -209,13 +331,10 @@ */ struct _SRB { - BYTE CmdBlock[12]; struct _SRB *pNextSRB; struct _DCB *pSRBDCB; - - DWORD PhysSRB; - SGentry SegmentX[DC395x_trm_MAX_SG_LISTENTRY]; + SGentry SegmentX[DC395x_MAX_SG_LISTENTRY]; SGentry SgSenseTemp; /* @@ -226,8 +345,9 @@ PSGE0 SRBSGListPointer; DWORD SRBTotalXferLength; + DWORD Xferred; /* Backup for the already xferred len */ - DWORD SRBSGPhyAddr; /* a segment starting address */ + long SRBSGBusAddr; /* a segment starting address */ WORD SRBState; PBYTE pMsgPtr; @@ -243,20 +363,21 @@ BYTE EndMessage; BYTE TagNumber; - BYTE IORBFlag; /* 81h-Reset, 2-retry */ BYTE SRBStatus; BYTE RetryCnt; - - DWORD Segment0[2]; - DWORD Segment1[2]; - BYTE SRBFlag; - BYTE ScsiCmdLen; + BYTE ScsiPhase; - BYTE Reserved3[1]; /* for dword alignment */ + //BYTE IORBFlag; /* 81h-Reset, 2-retry */ + BYTE padding; + WORD debugpos; +#ifdef DC395x_DEBUGTRACE + char debugtrace[DEBUGTRACEBUFSZ]; +#endif }; typedef struct _SRB DC395X_TRM_SRB, *PSRB; + /* ;----------------------------------------------------------------------- ; Device Control Block @@ -267,40 +388,31 @@ struct _DCB *pNextDCB; struct _ACB *pDCBACB; - PSCSICMD pQIORBhead; - PSCSICMD pQIORBtail; -/* 0x10: */ - PSCSICMD AboIORBhead; - PSCSICMD AboIORBtail; + PSRB pGoingSRB; + PSRB pGoingLast; +/* 0x10: */ PSRB pWaitingSRB; - PSRB pWaitLastSRB; -/* 0x20: */ - WORD QIORBCnt; - WORD AboIORBcnt; - - PSRB pGoingSRB; - PSRB pGoingLastSRB; + PSRB pWaitLast; PSRB pActiveSRB; -/* 0x30: */ 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; -/* 0x40: */ + BYTE InqDataBuf[8]; BYTE CapacityBuf[8]; -/* 0x50: */ +/* 0x3c: */ BYTE AdpMode; BYTE SyncMode; /* 0:async mode */ BYTE MinNegoPeriod; /* for nego. */ @@ -310,10 +422,12 @@ BYTE UnitCtrlFlag; BYTE DCBFlag; BYTE DevType; -/* 0x58: */ + + unsigned long last_derated; /* last time, when features were turned off in abort */ +/* 0x48: */ /* BYTE Reserved2[3]; for dword alignment */ }; -typedef struct _DCB DC395X_TRM_DCB, *PDCB; +typedef struct _DCB DC395x_DCB, *PDCB; /* ;----------------------------------------------------------------------- ; Adapter Control Block @@ -336,27 +450,29 @@ #endif PDCB pLinkDCB; + PDCB pLastDCB; PDCB pDCBRunRobin; PDCB pActiveDCB; - PDCB pDCB_free; PSRB pFreeSRB; PSRB pTmpSRB; + struct timer_list Waiting_Timer; + //struct timer_list Data_Timer; WORD SRBCount; WORD AdapterIndex; /* nth Adapter this driver */ - WORD max_id; - WORD max_lun; + DWORD QueryCnt; + PSCSICMD pQueryHead; + PSCSICMD pQueryTail; - BYTE msgin123[4]; + BYTE msgin123[4]; - - BYTE AdaptSCSIID; /* Adapter SCSI ID */ - BYTE AdaptSCSILUN; /* Adapter SCSI LUN */ BYTE status; - BYTE DeviceCnt; + BYTE DCBCnt; + BYTE sel_timeout; + BYTE dummy; BYTE IRQLevel; BYTE TagMaxNum; @@ -367,14 +483,26 @@ BYTE LUNchk; BYTE scan_devices; BYTE HostID_Bit; + + BYTE DCBmap[DC395x_MAX_SCSI_ID]; - BYTE DCBmap[DC395x_trm_MAX_SCSI_ID]; + DWORD Cmds; + DWORD SelLost; + DWORD SelConn; + DWORD CmdInQ; + DWORD CmdOutOfSRB; - DC395X_TRM_DCB DCB_array[DC395x_trm_MAX_DCB]; /* +74h, Len=3E8 */ + //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 Reserved1[2]; /* for dword alignment */ + BYTE MsgLen; + BYTE DeviceCnt; - DC395X_TRM_SRB SRB_array[DC395x_trm_MAX_SRB_CNT]; /* +45Ch, Len= */ + DC395X_TRM_SRB SRB_array[DC395x_MAX_SRB_CNT]; /* +45Ch, Len= */ DC395X_TRM_SRB TmpSRB; }; typedef struct _ACB DC395X_TRM_ACB, *PACB; @@ -575,22 +703,15 @@ BYTE ProductRev[4]; /* Product Revision */ } SCSI_INQDATA, *PSCSI_INQDATA; /* Inquiry byte 0 masks */ -#define SCSI_DEVTYPE 0x1F /* Peripheral Device Type */ +#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 */ -#define SCSI_DASD 0x00 /* Direct-access Device */ -#define SCSI_SEQACESS 0x01 /* Sequential-access device */ -#define SCSI_PRINTER 0x02 /* Printer device */ -#define SCSI_PROCESSOR 0x03 /* Processor device */ -#define SCSI_WRITEONCE 0x04 /* Write-once device */ -#define SCSI_CDROM 0x05 /* CD-ROM device */ -#define SCSI_SCANNER 0x06 /* Scanner device */ -#define SCSI_OPTICAL 0x07 /* Optical memory device */ -#define SCSI_MEDCHGR 0x08 /* Medium changer device */ -#define SCSI_COMM 0x09 /* Communications device */ -#define SCSI_NODEV 0x1F /* Unknown or no device type */ +/* See include/scsi/scsi.h */ +#define TYPE_NODEV SCSI_DEVTYPE /* Unknown or no device type */ +#define TYPE_PRINTER 0x02 /* Printer device */ +#define TYPE_COMM 0x09 /* Communications device */ /* ** Inquiry flag definitions (Inq data byte 7) */ @@ -655,7 +776,8 @@ #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 latch */ +#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 */ /* **************************************** @@ -714,11 +836,11 @@ ** in the Synchronous Mode register ** are used to transfer data ** at the Fast-20 rate. -** @@ When this bit is reset, +** @@ When this bit is unset, ** the synchronous period bits 2:0 ** in the Synchronous Mode Register ** are used to transfer data -** at the Fast-40 rate. +** 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 @@ -730,38 +852,38 @@ ** For Fast-10 bit ALTPD = 0 and LVDS = 0 ** and bit2,bit1,bit0 is defined as follows : ** -** 000 100ns, 10.0 Mbytes/s -** 001 150ns, 6.6 Mbytes/s -** 010 200ns, 5.0 Mbytes/s -** 011 250ns, 4.0 Mbytes/s -** 100 300ns, 3.3 Mbytes/s -** 101 350ns, 2.8 Mbytes/s -** 110 400ns, 2.5 Mbytes/s -** 111 450ns, 2.2 Mbytes/s +** 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 Mbytes/s -** 001 75ns, 13.3 Mbytes/s -** 010 100ns, 10.0 Mbytes/s -** 011 125ns, 8.0 Mbytes/s -** 100 150ns, 6.6 Mbytes/s -** 101 175ns, 5.7 Mbytes/s -** 110 200ns, 5.0 Mbytes/s -** 111 250ns, 4.0 Mbytes/s +** 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 Mbytes/s -** 001 50ns, 20.0 Mbytes/s -** 010 75ns, 13.3 Mbytes/s -** 011 100ns, 10.0 Mbytes/s -** 100 125ns, 8.0 Mbytes/s -** 101 150ns, 6.6 Mbytes/s -** 110 175ns, 5.7 Mbytes/s -** 111 200ns, 5.0 Mbytes/s +** 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 ****************************************************************** */ @@ -810,6 +932,7 @@ /* ######### */ #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 */ /* **************************************** @@ -903,8 +1026,11 @@ */ #define TRM_S1040_DMA_COMMAND 0xA0 /* DMA Command (R/W) */ /* ######### */ -#define XFERDATAIN 0x0103 /* Transfer data in */ -#define XFERDATAOUT 0x0102 /* Transfer data out */ +#define DMACMD_SG 0x02 /* Enable HW S/G support */ +#define DMACMD_DIR 0x01 /* 1 = read from SCSI write to Host */ +/* ######### */ +#define XFERDATAIN 0x0103 /* Transfer data in w/ SG */ +#define XFERDATAOUT 0x0102 /* Transfer data out w/ SG */ /* **************************************** */ @@ -914,6 +1040,7 @@ */ #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 */ @@ -924,6 +1051,11 @@ #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 */ /* @@ -931,13 +1063,24 @@ */ #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 */ +#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 */ /* **************************************** */ @@ -964,7 +1107,9 @@ */ #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 */ @@ -974,10 +1119,13 @@ #define TRM_S1040_GEN_STATUS 0xD5 /* Global Status */ /* ######### */ #define GTIMEOUT 0x80 /* Global timer reach 0 */ -#define CON5068 0x10 /* External 50/68 pin connected */ -#define CON68 0x08 /* Internal 68 pin connected */ -#define CON50 0x04 /* Internal 50 pin connected */ +#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 /* **************************************** */ @@ -1036,7 +1184,7 @@ BYTE NvramVendorID[2]; /* 5,6 Vendor ID */ BYTE NvramDeviceID[2]; /* 7,8 Device ID */ BYTE NvramReserved; /* 9 Reserved */ - NVRAMTARGETTYPE NvramTarget[DC395x_trm_MAX_SCSI_ID]; + NVRAMTARGETTYPE NvramTarget[DC395x_MAX_SCSI_ID]; /** 10,11,12,13 ** 14,15,16,17 ** .... @@ -1072,14 +1220,16 @@ */ /*------------------------------------------------------------------------------*/ -struct proc_dir_entry DC395x_trm_proc_scsi= +#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_trm_check_eeprom(PNVRAMTYPE pEEpromBuf,WORD scsiIOPort); +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); @@ -1087,83 +1237,88 @@ static void TRM_S1040_write_cmd(WORD scsiIOPort, BYTE bCmd, BYTE bAddr); void TRM_S1040_wait_30us(WORD scsiIOPort); -static void DC395x_trm_DataOutPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_DataInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_CommandPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_StatusPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_MsgOutPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_MsgInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_DataOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_DataInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_CommandPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_StatusPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_MsgOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_MsgInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_Nop0( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_Nop1( PACB pACB, PSRB pSRB, PWORD pscsi_status); -static void DC395x_trm_ResetSCSIBus( PACB pACB ); - int DC395x_trm_initAdapter( PSH psh, DWORD io_port, BYTE Irq, WORD index ); -static void DC395x_trm_DataIO_transfer( PACB pACB, PSRB pSRB, WORD ioDir); -static void DC395x_trm_Disconnect( PACB pACB ); -static void DC395x_trm_Reselect( PACB pACB ); - WORD DC395x_trm_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ); -static void DC395x_trm_BuildSRB(Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB); -static void DC395x_trm_DoingSRB_Done( PACB pACB ); -static void DC395x_trm_ScsiRstDetect( PACB pACB ); -static inline void DC395x_trm_EnableMsgOutAbort1( PACB pACB, PSRB pSRB ); -static inline void DC395x_trm_EnableMsgOutAbort2( PACB pACB, PSRB pSRB ); -static void DC395x_trm_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ); -static void DC395x_trm_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ); -static inline void DC395x_trm_SetXferRate( PACB pACB, PDCB pDCB ); - void DC395x_trm_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ); +static 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_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 ); + WORD DC395x_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ); +static void DC395x_BuildSRB(Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB); +static 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_trm_release(struct Scsi_Host *host); -int DC395x_trm_shutdown (struct Scsi_Host *host); +int DC395x_release(struct Scsi_Host *host); +int DC395x_shutdown (struct Scsi_Host *host); #endif -static PACB DC395x_TRM_pACB_start = NULL; -static PACB DC395x_TRM_pACB_current = NULL; -static PDCB DC395x_TRM_pPrevDCB = NULL; -static WORD DC395x_TRM_adapterCnt = 0; -static WORD DC395x_TRM_CurrSyncOffset = 0; +static PACB DC395x_pACB_start = NULL; +static PACB DC395x_pACB_current = NULL; +static WORD DC395x_adapterCnt = 0; +static WORD DC395x_CurrSyncOffset = 0; +static char in_driver = 0; +static char DC395x_monitor_next_IRQ = 0; + /* ********************************************************* ** -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** DC395x_stateV = (void *) DC395x_SCSI_phase0[phase] ** ********************************************************* */ -static PVOID DC395x_trm_SCSI_phase0[]={ - DC395x_trm_DataOutPhase0, /* phase:0 */ - DC395x_trm_DataInPhase0, /* phase:1 */ - DC395x_trm_CommandPhase0, /* phase:2 */ - DC395x_trm_StatusPhase0, /* phase:3 */ - DC395x_trm_Nop0, /* phase:4 PH_BUS_FREE .. initial phase */ - DC395x_trm_Nop1, /* phase:5 PH_BUS_FREE .. initial phase */ - DC395x_trm_MsgOutPhase0, /* phase:6 */ - DC395x_trm_MsgInPhase0, /* phase:7 */ +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_trm_stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** DC395x_stateV = (void *) DC395x_SCSI_phase1[phase] ** ********************************************************************* */ -static PVOID DC395x_trm_SCSI_phase1[]={ - DC395x_trm_DataOutPhase1, /* phase:0 */ - DC395x_trm_DataInPhase1, /* phase:1 */ - DC395x_trm_CommandPhase1, /* phase:2 */ - DC395x_trm_StatusPhase1, /* phase:3 */ - DC395x_trm_Nop0, /* phase:4 PH_BUS_FREE .. initial phase */ - DC395x_trm_Nop1, /* phase:5 PH_BUS_FREE .. initial phase */ - DC395x_trm_MsgOutPhase1, /* phase:6 */ - DC395x_trm_MsgInPhase1, /* phase:7 */ +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_trm_MAX_ADAPTER_NUM]; +NVRAMTYPE dc395x_trm_eepromBuf[DC395x_MAX_ADAPTER_NUM]; /* **Fast20: 000 50ns, 20.0 MHz ** 001 75ns, 13.3 MHz @@ -1174,7 +1329,7 @@ ** 110 200ns, 5.0 MHz ** 111 250ns, 4.0 MHz ** -**Fast40: 000 25ns, 40.0 MHz +**Fast40(LVDS): 000 25ns, 40.0 MHz ** 001 50ns, 20.0 MHz ** 010 75ns, 13.3 MHz ** 011 100ns, 10.0 MHz @@ -1183,551 +1338,363 @@ ** 110 175ns, 5.7 MHz ** 111 200ns, 5.0 MHz */ -BYTE dc395x_trm_clock_period[] = {12,18,25,31,37,43,50,62}; - /* real period:48ns,72ns,100ns,124ns,148ns,172ns,200ns,248ns */ +//BYTE dc395x_clock_period[] = {12,19,25,31,37,44,50,62}; +/* real period:48ns,76ns,100ns,124ns,148ns,176ns,200ns,248ns */ +BYTE dc395x_clock_period[] = {12,18,25,31,37,43,50,62}; +/* real period:48ns,72ns,100ns,124ns,148ns,172ns,200ns,248ns */ + +/* 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; + } +}; -/* -********************************************************************* -** -** DC395x_trm_queue_command DC395x_trm_DoNextCmd -** -********************************************************************* -*/ -static inline void DC395x_trm_QLinkcmd( PSCSICMD cmd, PDCB pDCB ) +#if 0 +/* Look for a SCSI cmd in a SRB queue */ +static PSRB DC395x_find_cmd_in_SRBq (PSCSICMD cmd, PSRB queue) { - PSCSICMD pcmd; - //DWORD drv_flags=0; - //DC395x_TRM_DRV_LOCK(drv_flags); - - if( !pDCB->QIORBCnt ) + PSRB q = queue; + while (q) { - pDCB->pQIORBhead = cmd; - pDCB->pQIORBtail = cmd; - pDCB->QIORBCnt++; - cmd->next = NULL; + if (q->pcmd == cmd) return q; + q = q->pNextSRB; + if (q == queue) return 0; } + return q; +}; +#endif + + +/* 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 - { - pcmd = pDCB->pQIORBtail; - pcmd->next = cmd; - pDCB->pQIORBtail = cmd; - pDCB->QIORBCnt++; - cmd->next = NULL; - } - //DC395x_TRM_DRV_UNLOCK(drv_flags); + pACB->pQueryTail->next = cmd; + pACB->pQueryTail = cmd; + pACB->QueryCnt++; + pACB->CmdOutOfSRB++; + cmd->next = NULL; } -/* -********************************************************************* -** -** DC395x_trm_queue_command DC395x_trm_DoNextCmd -** -********************************************************************* -*/ -static inline PSCSICMD DC395x_trm_Getcmd( PDCB pDCB ) -{ - PSCSICMD pcmd; - PACB pACB; - //DWORD drv_flags=0; - //DC395x_TRM_DRV_LOCK(drv_flags); - pACB = pDCB->pDCBACB; +/* Return next cmd from Query list */ +static PSCSICMD DC395x_Query_get ( PACB pACB ) +{ + PSCSICMD pcmd; - pcmd = pDCB->pQIORBhead; - pDCB->pQIORBhead = pcmd->next; + 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; - pDCB->QIORBCnt--; - //DC395x_TRM_DRV_UNLOCK(drv_flags); - + if (!pACB->pQueryHead) pACB->pQueryTail = NULL; + pACB->QueryCnt--; return( pcmd ); } -/* -********************************************************************* -** -** DC395x_trm_queue_command DC395x_trm_DoNextCmd -** -********************************************************************* -*/ -static inline PSRB DC395x_trm_GetSRB( PACB pACB ) + +/* Return next free SRB */ +static __inline__ PSRB DC395x_Free_get ( PACB pACB ) { - PSRB pSRB; - //DWORD drv_flags=0; + PSRB pSRB; - //DC395x_TRM_DRV_LOCK(drv_flags); pSRB = pACB->pFreeSRB; + DEBUG0(printk ("DC395x: Get Free SRB %p\n", pSRB);) if( pSRB ) { pACB->pFreeSRB = pSRB->pNextSRB; pSRB->pNextSRB = NULL; } - //DC395x_TRM_DRV_UNLOCK(drv_flags); return( pSRB ); } -/* -********************************************************************* -** -** DC395x_trm_SendSRB -** -** If DC395x_trm_StartSCSI returns 1: -** current interrupt status is interrupt disreenable (?) -** It's said that SCSI processor has more one SRB need to do -** -********************************************************************* -*/ -static inline void DC395x_trm_RewaitSRB0( PDCB pDCB, PSRB pSRB ) +/* Insert SRB oin top of free list */ +static __inline__ void DC395x_Free_insert (PACB pACB, PSRB pSRB) { - PSRB pSRBTemp1; - PACB pACB; - //DWORD drv_flags=0; - //DC395x_TRM_DRV_LOCK(drv_flags); - - pACB = pDCB->pDCBACB; + DEBUG0(printk ("DC395x: Free SRB %p\n", pSRB);) + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; +} - /* $$$$$$$ */ - if( (pSRBTemp1 = pDCB->pWaitingSRB) ) - { - pSRB->pNextSRB = pSRBTemp1; - } - else - { - pSRB->pNextSRB = NULL; - pDCB->pWaitLastSRB = pSRB; - } - pDCB->pWaitingSRB = pSRB; - /* $$$$$$$ */ - //DC395x_TRM_DRV_UNLOCK(drv_flags); - return; +/* 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++; } -/* -********************************************************************* -** -** DC395x_trm_Disconnected DC395x_trm_Reselect -** DC395x_trm_RequestSense DC395x_trm_SRBdone -** -********************************************************************* -*/ -static void DC395x_trm_RewaitSRB( PDCB pDCB, PSRB pSRB ) -{ - PACB pACB; - PSRB pSRBTemp; - //DWORD drv_flags=0; - //DC395x_TRM_DRV_LOCK(drv_flags); -#ifdef DC395x_trm_DEBUG0 - printk(KERN_INFO "DC395x_RewaitSRB..............\n "); -#endif +/* 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; - pACB = pDCB->pDCBACB; + pDCB->pWaitLast = pSRB; + pSRB->pNextSRB = NULL; + pDCB->WaitSRBCnt++; + //pDCB->pDCBACB->CmdInQ++; +} - pDCB->GoingSRBCnt--; - pSRBTemp = pDCB->pGoingSRB; - /* $$$$$$$ */ - if( pSRB == pSRBTemp ) - { - /* - ** current SRB is GoingSRB - ** load next SRB to GoingSRB - */ - pDCB->pGoingSRB = pSRBTemp->pNextSRB; - } +static __inline__ void DC395x_Going_append (PDCB pDCB, PSRB pSRB) +{ + pDCB->GoingSRBCnt++; + 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 - { - /* - ** current SRB is not GoingSRB - ** link the SRB Q and load its NextSRB to NextSRB of GoingSRB - */ - while( pSRB != pSRBTemp->pNextSRB ) - pSRBTemp = pSRBTemp->pNextSRB; - pSRBTemp->pNextSRB = pSRB->pNextSRB; + pDCB->pGoingSRB = pSRB; - if( pSRB == pDCB->pGoingLastSRB ) - pDCB->pGoingLastSRB = pSRBTemp; - } - /* $$$$$$$ */ - if( pDCB->pWaitingSRB != NULL ) - { - /* - ** there was one SRB waiting - */ - pSRB->pNextSRB = pDCB->pWaitingSRB; - pDCB->pWaitingSRB = pSRB; - } - else - { - /* - ** WaitingSRB is NULL - ** point this SRB to WaitLastSRB - */ - pSRB->pNextSRB = NULL; - pDCB->pWaitLastSRB = pSRB; - pDCB->pWaitingSRB = pSRB; - } - - /* $$$$$$$ */ - pDCB->TagMask &= (~(1 << pSRB->TagNumber)); /* Free TAG number */ + pDCB->pGoingLast = pSRB; + /* No next one in sent list */ + pSRB->pNextSRB = NULL; +}; - //DC395x_TRM_DRV_UNLOCK(drv_flags); +static __inline__ void DC395x_Going_remove (PDCB pDCB, PSRB pSRB) +{ + 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 + { + PSRB psrb = pDCB->pGoingSRB; + while (psrb && psrb->pNextSRB != pSRB) + psrb = psrb->pNextSRB; + if (!psrb) + { printk (KERN_ERR "DC395x: Remove non-ex. SRB %p from Going!\n", pSRB); return; } + psrb->pNextSRB = pSRB->pNextSRB; + if (pSRB == pDCB->pGoingLast) + pDCB->pGoingLast = psrb; + } + pDCB->GoingSRBCnt--; +}; - return; +/* 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); + 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);) + pDCB->pWaitingSRB = pSRB->pNextSRB; + pDCB->WaitSRBCnt--; + TRACEPRINTF("WtG *"); + if( !pDCB->pWaitingSRB ) pDCB->pWaitLast = NULL; + DC395x_Going_append (pDCB, pSRB); +} + +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); } -/* -********************************************************************* -** -** DC395x_trm_reset DC395x_trm_Disconnected -** DC395x_trm_ScsiRstDetect -** -********************************************************************* -*/ -static void DC395x_trm_DoWaitingSRB( PACB pACB ) +/* Send the next command from the waiting list to the bus */ +void DC395x_Waiting_process ( PACB pACB ) { - PDCB pDCBTemp, pDCBTemp1; + PDCB ptr, ptr1; PSRB pSRB; - //DWORD drv_flags=0; - //DC395x_TRM_DRV_LOCK(drv_flags); - -#ifdef DC395x_trm_DEBUG0 - printk(KERN_INFO "DC395x_DoWaitingSRB..............\n "); -#endif - if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) ) - { - pDCBTemp = pACB->pDCBRunRobin; - if( !pDCBTemp ) - { - pDCBTemp = pACB->pLinkDCB; - pACB->pDCBRunRobin = pDCBTemp; - } - pDCBTemp1 = pDCBTemp; - for( ;pDCBTemp1; ) - { - pACB->pDCBRunRobin = pDCBTemp1->pNextDCB; - if( !( pDCBTemp1->MaxCommand > pDCBTemp1->GoingSRBCnt ) || !( pSRB = pDCBTemp1->pWaitingSRB ) ) - { - if(pACB->pDCBRunRobin == pDCBTemp) - break; - pDCBTemp1 = pDCBTemp1->pNextDCB; - } + 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 ) + { + ptr = pACB->pLinkDCB; + pACB->pDCBRunRobin = ptr; + } + ptr1 = ptr; + if (!ptr1) return; + do + { + 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 - { - if( !DC395x_trm_StartSCSI(pACB, pDCBTemp1, pSRB) ) - { - /* - ** If DC395x_trm_StartSCSI return 0 : - ** current interrupt status is interrupt enable - ** It's said that SCSI processor is unoccupied - */ - - pDCBTemp1->GoingSRBCnt++; - if( pDCBTemp1->pWaitLastSRB == pSRB ) - { - pDCBTemp1->pWaitingSRB = NULL; - pDCBTemp1->pWaitLastSRB = NULL; - } - else - { - pDCBTemp1->pWaitingSRB = pSRB->pNextSRB; - } - pSRB->pNextSRB = NULL; - if( pDCBTemp1->pGoingSRB ) - pDCBTemp1->pGoingLastSRB->pNextSRB = pSRB; - else - pDCBTemp1->pGoingSRB = pSRB; - - pDCBTemp1->pGoingLastSRB = pSRB; - } - break; - } - } - } - //DC395x_TRM_DRV_UNLOCK(drv_flags); + DC395x_waiting_timer (pACB, HZ/5); + break; + } + } while (ptr1 != ptr); return; } -/* -********************************************************************* -** -** DC395x_trm_SendSRB -** -** -********************************************************************* -*/ -static inline void DC395x_trm_SRBwaiting( PDCB pDCB, PSRB pSRB) +/* Wake up waiting queue */ +void DC395x_waiting_timed_out (unsigned long ptr) { - PACB pACB; - //DWORD drv_flags=0; - //DC395x_TRM_DRV_LOCK(drv_flags); - - pACB = pDCB->pDCBACB; - - - if( pDCB->pWaitingSRB ) - { - pDCB->pWaitLastSRB->pNextSRB = pSRB; - pSRB->pNextSRB = NULL; - } - else - pDCB->pWaitingSRB = pSRB; - - pDCB->pWaitLastSRB = pSRB; + unsigned int flags; + printk ("DC395x: Debug: Waiting queue woken up by timer!\n"); + DC395x_LOCK_IO; + DC395x_Waiting_process ((PACB)ptr); + DC395x_UNLOCK_IO; +} + +/* 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; +}; + - //DC395x_TRM_DRV_UNLOCK(drv_flags); - return; -} +/*********************************************************************** + * Function: static void DC395x_SendSRB (PACB pACB, PSRB pSRB) + * + * Purpose: Send SCSI Request Block (pSRB) to adapter (pACB) + * + ** DC395x_queue_command + ** DC395x_Waiting_process + * + ***********************************************************************/ -/* -********************************************************************* -** -** DC395x_trm_queue_command -** DC395x_trm_DoNextCmd -** -********************************************************************* -*/ -static void DC395x_trm_SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB ) +static void DC395x_SendSRB( PACB pACB, PSRB pSRB ) { PDCB pDCB; - //DWORD drv_flags=0; - //DC395x_TRM_DRV_LOCK(drv_flags); - -#ifdef DC395x_trm_DEBUG0 - printk(KERN_INFO "DC395x_SendSRB..............\n "); -#endif pDCB = pSRB->pSRBDCB; - if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) ) + if( (pDCB->MaxCommand <= pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || + (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) ) { - DC395x_trm_SRBwaiting(pDCB, pSRB); - goto SND_EXIT; + DC395x_Waiting_append (pDCB, pSRB); + DC395x_Waiting_process (pACB); + return; } + +#if 0 if( pDCB->pWaitingSRB ) { - /* - ** there was one SRB waiting at least ,load this SRB for doing - ** load NextSRB to current WaitingSRB of DCB - ** load NULL to current NextSRB of SRB - */ - DC395x_trm_SRBwaiting(pDCB, pSRB); - /* pSRB = GetWaitingSRB(pDCB); */ + 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( !DC395x_trm_StartSCSI(pACB, pDCB, pSRB) ) - { - /* - ** If DC395x_trm_StartSCSI return 0 : - ** current interrupt status is interrupt enable - ** It's said that SCSI processor is unoccupied - */ - pDCB->GoingSRBCnt++; - if( pDCB->pGoingSRB ) - { - /* - ** pDCB->pGoingSRB not null - ** you need Q this SRB in SRB range Q - */ - pDCB->pGoingLastSRB->pNextSRB = pSRB; - pDCB->pGoingLastSRB = pSRB; - } - else - { - /* - ** no SRB range and that pDCB->pGoingSRB is null - ** this SRB's priority is first for doing and is last SRB - */ - pDCB->pGoingSRB = pSRB; - pDCB->pGoingLastSRB = pSRB; - } + if (!pDCB->pWaitingSRB) pDCB->pWaitLast = NULL; } +#endif + + if (!DC395x_StartSCSI(pACB, pDCB, pSRB)) + DC395x_Going_append (pDCB, pSRB); else { - /* - ** If DC395x_trm_StartSCSI return 1 : - ** current interrupt status is interrupt disreenable - ** It's said that SCSI processor has more one SRB need to do - */ - DC395x_trm_RewaitSRB0( pDCB, pSRB ); + DC395x_Waiting_insert (pDCB, pSRB); + DC395x_waiting_timer (pACB, HZ/5); } - -SND_EXIT: - //DC395x_TRM_DRV_UNLOCK(drv_flags); - return; } /* ********************************************************************** +** +** Function: static void DC395x_BuildSRB (Scsi_Cmd *pcmd, PDCB pDCB, PSRB pSRB) ** -** Function : static int DC395x_trm_queue_command -** (Scsi_Cmnd *cmd,void (*done)(Scsi_Cmnd *)) -** Purpose : enqueues a SCSI command (SCSI I/O) -** Inputs : cmd - SCSI command, done - function called on completion, -** with a pointer to the command descriptor. -** Returns : 0 +** Purpose: Prepare SRB for being sent to Device DCB w/ command *pcmd ** ********************************************************************** */ -int DC395x_trm_queue_command(Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) +static void DC395x_BuildSRB (Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB) { - WORD ioport; - Scsi_Cmnd *pcmd; - PACB pACB; - PDCB pDCB; - PSRB pSRB; - //DWORD acb_flags=0; - - pACB = (PACB) cmd->host->hostdata; + int i,max; + PSGE0 sgp; + struct scatterlist *sl; -#ifdef DC395x_trm_DEBUG_KG - printk(KERN_INFO "DC395x_queue_command 0x%02x (pid=%li, target=%i-%i)\n", - cmd->cmnd[0], cmd->pid, cmd->target, cmd->lun); +#ifdef DC395x_DEBUG0 + printk(KERN_INFO "DC395x_BuildSRB..............\n "); #endif - - //DC395x_TRM_ACB_LOCK(pACB,acb_flags); - - ioport = pACB->IOPortBase; + //memset (pSRB, 0, sizeof (DC395X_TRM_SRB)); + pSRB->pSRBDCB = pDCB; + pSRB->pcmd = pcmd; - if( (pACB->scan_devices == DC395x_trm_END_SCAN) && (cmd->cmnd[0] != INQUIRY) ) - { /* if scan device ending than link the head of DCB chain with tail */ - pACB->scan_devices = 0; - DC395x_TRM_pPrevDCB->pNextDCB = pACB->pLinkDCB; - } - else if( (pACB->scan_devices) && (cmd->cmnd[0] == READ_6) ) - { - pACB->scan_devices = 0; - DC395x_TRM_pPrevDCB->pNextDCB = pACB->pLinkDCB; - } - if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) ) - { - //DC395x_TRM_ACB_UNLOCK(pACB,acb_flags); - - printk(KERN_INFO "DC395x: Ignore target %d lun %d\n", cmd->target, cmd->lun); - cmd->result = (DID_BAD_TARGET << 16); - done(cmd); - return( 0 ); - } - if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) - { - if( pACB->DeviceCnt < DC395x_trm_MAX_SCSI_ID ) - { - pACB->DCBmap[cmd->target] |= (1 << cmd->lun); - pDCB = pACB->pDCB_free; - //*************************************************** - //* initial device control block - //*************************************************** - DC395x_trm_initDCB( pACB, pDCB, cmd ); - } - else - { - //DC395x_TRM_ACB_UNLOCK(pACB,acb_flags); - - printk(KERN_INFO "DC395x: Ignore target %d lun %d\n", cmd->target, cmd->lun); - cmd->result = (DID_BAD_TARGET << 16); - done(cmd); - return(0); - } - } - else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) - { - //DC395x_TRM_ACB_UNLOCK(pACB,acb_flags); - printk(KERN_INFO "DC395x: Ignore target %d lun %d\n",cmd->target, cmd->lun); - cmd->result = (DID_BAD_TARGET << 16); - done(cmd); - return(0); - } - else - { - /* - * get a DCB from head of DCB chain - * that had same target_ID and target_lun with upper layer - */ - pDCB = pACB->pLinkDCB; - while( (pDCB->TargetID != cmd->target) || (pDCB->TargetLUN != cmd->lun) ) - pDCB = pDCB->pNextDCB; - } - - cmd->scsi_done = done; - cmd->result = 0; - - if( pDCB->QIORBCnt ) - { - DC395x_trm_QLinkcmd( cmd, pDCB ); - pcmd = DC395x_trm_Getcmd( pDCB ); - } - else - pcmd = cmd; - - pSRB = DC395x_trm_GetSRB( pACB ); - - if( !pSRB ) - { - DC395x_trm_QLinkcmd( pcmd, pDCB ); - //DC395x_TRM_ACB_UNLOCK(pACB,acb_flags); - return(0); - } - DC395x_trm_BuildSRB( pcmd, pDCB, pSRB); - DC395x_trm_SendSRB( pcmd, pACB, pSRB ); - - //DC395x_TRM_ACB_UNLOCK(pACB,acb_flags); - return(0); -} -/* -********************************************************************** -** -** Function: static void DC395x_trm_BuildSRB (Scsi_Cmd *pcmd, PDCB pDCB, PSRB pSRB) -** -** Purpose: Prepare SRB for being sent to Device DCB w/ command *pcmd -** -********************************************************************** -*/ -static void DC395x_trm_BuildSRB(Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB) -{ - int i,max; - PSGE0 sgp; - struct scatterlist *sl; - -#ifdef DC395x_trm_DEBUG0 - printk(KERN_INFO "DC395x_BuildSRB..............\n "); -#endif - pSRB->pSRBDCB = pDCB; - pSRB->pcmd = pcmd; - pSRB->ScsiCmdLen = pcmd->cmd_len; - /* - ** move uper layer's command block to layer of SCSI Request Block - ** for SCSI processor command doing - */ - memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len); - if( pcmd->use_sg ) { + unsigned int len = 0; pSRB->SRBSGCount = pcmd->use_sg; pSRB->SRBSGListPointer=(PSGE0) &pSRB->SegmentX[0]; sgp = pSRB->SRBSGListPointer; sl = (struct scatterlist *) pcmd->request_buffer; - pSRB->SRBTotalXferLength = 0; max = pcmd->use_sg; - if(max > DC395x_trm_MAX_SG_LISTENTRY) + if(max > DC395x_MAX_SG_LISTENTRY) { - printk(KERN_INFO "cmd->use_sg=%4d bigger then dc395x: DC395x_MAX_SG_LISTENTRY=%4d\n",pcmd->use_sg,DC395x_trm_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); } for (i = 0; i < max; i++,sgp++) { - sgp->address = (DWORD) virt_to_phys( sl[i].address ); + sgp->address = (DWORD) virt_to_bus( sl[i].address ); sgp->length = (DWORD) sl[i].length; - pSRB->SRBTotalXferLength += (DWORD) sl[i].length; + len += (DWORD) sl[i].length; } + pSRB->SRBTotalXferLength = len; } else if( pcmd->request_buffer ) { pSRB->SRBSGCount = 1; pSRB->SRBSGListPointer = (PSGE0) &pSRB->SegmentX[0];/* a one entry of S/G list table */ - pSRB->SegmentX[0].address = (DWORD) virt_to_phys( pcmd->request_buffer );/* Actual requested buffer */ + pSRB->SegmentX[0].address = (DWORD) virt_to_bus( pcmd->request_buffer );/* Actual requested buffer */ pSRB->SegmentX[0].length = (DWORD) pcmd->request_bufflen;/* Actual request size */ pSRB->SRBTotalXferLength = (DWORD) pcmd->request_bufflen; } @@ -1736,6 +1703,7 @@ pSRB->SRBSGCount = 0; pSRB->SRBTotalXferLength = 0; } + pSRB->SRBSGIndex = 0; pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; @@ -1743,60 +1711,271 @@ pSRB->SRBStatus = 0; pSRB->SRBFlag = 0; pSRB->SRBState = 0; + pSRB->RetryCnt = 0; + + pSRB->debugpos = 0; + TRACEPRINTF ("pid %li(%li):%02x(%i-%i) *", pcmd->pid, jiffies, + pcmd->cmnd[0], pcmd->target, pcmd->lun); + pSRB->TagNumber = TAG_NONE; pSRB->ScsiPhase = PH_BUS_FREE; /* initial phase */ pSRB->EndMessage = 0; return; -} -/* -********************************************************************* -** -** DC395x_trm_SRBdone -** -********************************************************************* -*/ -static inline void DC395x_trm_DoNextCmd( PACB pACB, PDCB pDCB ) +}; + +/* 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; - //DWORD drv_flags=0; + PSRB pSRB; + PDCB pDCB; -#ifdef DC395x_trm_DEBUG0 - printk(KERN_INFO "DC395x_DoNextCmd..............\n "); -#endif if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) return; - //DC395x_TRM_DRV_LOCK(drv_flags); - pcmd = DC395x_trm_Getcmd( pDCB ); - pSRB = DC395x_trm_GetSRB( pACB ); - if( !pSRB ) - DC395x_trm_QLinkcmd( pcmd, pDCB ); + 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);) + + 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); */ + in_driver--; + //return (1); + done (cmd); + return (0); + } + + if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY) && !(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"); + 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); + in_driver--; + done (cmd); + return (0); + } else { - DC395x_trm_BuildSRB( pcmd, pDCB, pSRB); - DC395x_trm_SendSRB( pcmd, pACB, pSRB ); + 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"); + in_driver--; +#ifdef USE_NEW_EH + return (1); +#else + done (cmd); + return (0); +#endif + }; } - //DC395x_TRM_DRV_UNLOCK(drv_flags); - return; + 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);) + 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_trm_bios_param +** Function : DC395x_bios_param ** Description: Return the disk geometry for the given SCSI device. ********************************************************************** */ -int DC395x_trm_bios_param(Disk *disk, kdev_t devno, int geom[]) +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_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_bios_param..............\n "); #endif pACB = (PACB) disk->device->host->hostdata; @@ -1814,63 +1993,119 @@ 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 + UCHAR pbus = pACB->pbus; + UCHAR pdevfn = pACB->pdevfn; + pcibios_read_config_word (pbus, pdevfn, PCISTATUS, &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->SRBSGListPointer, 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 Signal %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 Cmd %02x SelTO %02x\n", + DC395x_read8 (TRM_S1040_SCSI_INTEN), DC395x_read16 (TRM_S1040_SCSI_CONFIG0), + DC395x_read8 (TRM_S1040_SCSI_COMMAND), DC395x_read8 (TRM_S1040_SCSI_TIMEOUT)); + printk ("DC395x: dump: DMA block\n"); + printk (" Cmd %02x FIFOCnt %02x IRQStat %02x IRQEn %02x Cfg %04x\n", + DC395x_read8 (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 CCtr %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); + +} /* ********************************************************************** ** -** Function : int DC395x_trm_abort (Scsi_Cmnd *cmd) +** 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_trm_abort (Scsi_Cmnd *cmd) +int DC395x_abort (Scsi_Cmnd *cmd) { PACB pACB; - PDCB pDCB, pDCBTemp; - PSRB pSRB, pSRBTemp; + PDCB pDCB; + PSRB pSRB = 0, psrb; WORD count, i; - PSCSICMD pcmd, pcmd1; + PSCSICMD pcmd; int status; //DWORD acb_flags=0; + BYTE lines; pACB = (PACB) cmd->host->hostdata; - printk(KERN_INFO "DC395x_abort: pid=%li, target=%i-%i\n", + printk(KERN_INFO "DC395x_abort: pid=%li, target=%02i-%i\n", cmd->pid, cmd->target, cmd->lun); - pACB = (PACB) cmd->host->hostdata; - - //DC395x_TRM_ACB_LOCK(pACB,acb_flags); + if (in_driver++ > NORM_REC_LVL) printk ("DC395x: %i abort() recursion? (pid=%li)\n", + in_driver, cmd->pid); - pDCB = pACB->pLinkDCB; - pDCBTemp = pDCB; - while( (pDCB->TargetID != cmd->target) || (pDCB->TargetLUN != cmd->lun) ) - { - pDCB = pDCB->pNextDCB; - if( pDCB == pDCBTemp ) - goto NOT_RUN; - } + //DC395x_ACB_LOCK(pACB,acb_flags); - if( pDCB->QIORBCnt ) + /* First scan Query list */ + if( pACB->QueryCnt ) { - pcmd = pDCB->pQIORBhead; + pcmd = pACB->pQueryHead; if( pcmd == cmd ) { - pDCB->pQIORBhead = pcmd->next; + /* Found: Dequeue */ + pACB->pQueryHead = pcmd->next; pcmd->next = NULL; - pDCB->QIORBCnt--; + if (cmd == pACB->pQueryTail) pACB->pQueryTail = NULL; + pACB->QueryCnt--; status = SCSI_ABORT_SUCCESS; goto ABO_X; } - for( count = pDCB->QIORBCnt, i=0; iQueryCnt, i=0; inext == cmd ) { - pcmd1 = pcmd->next; - pcmd->next = pcmd1->next; - pcmd1->next = NULL; - pDCB->QIORBCnt--; + pcmd->next = cmd->next; + cmd->next = NULL; + if (cmd == pACB->pQueryTail) pACB->pQueryTail = NULL; + pACB->QueryCnt--; status = SCSI_ABORT_SUCCESS; goto ABO_X; } @@ -1880,11 +2115,32 @@ } } } + + pDCB = DC395x_findDCB (pACB, cmd->target, cmd->lun); + if( !pDCB ) goto NOT_RUN; + + 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_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + //DC395x_EnableMsgOut_Abort (pACB, pSRB); + pDCB->DCBFlag |= ABORT_DEV_; + pDCB->pActiveSRB = pSRB; + TRACEPRINTF("abort tmp (SN)!*"); + status = SCSI_ABORT_SNOOZE; + goto ABO_X; + } + + //pSRB = pDCB->pActiveSRB; + pSRB = pDCB->pWaitingSRB; if( !pSRB ) - { goto ON_GOING; - } + + /* Now scan Waiting queue */ if( pSRB->pcmd == cmd ) { pDCB->pWaitingSRB = pSRB->pNextSRB; @@ -1892,77 +2148,132 @@ } else { - pSRBTemp = pSRB; - if( !(pSRBTemp->pNextSRB) ) + psrb = pSRB; + if( !(psrb->pNextSRB) ) goto ON_GOING; - - while( pSRBTemp->pNextSRB->pcmd != cmd ) + while( psrb->pNextSRB->pcmd != cmd ) { - pSRBTemp = pSRBTemp->pNextSRB; - if( !(pSRBTemp->pNextSRB) ) + psrb = psrb->pNextSRB; + if( !(psrb->pNextSRB) || psrb == pSRB) goto ON_GOING; - } - pSRB = pSRBTemp->pNextSRB; - pSRBTemp->pNextSRB = pSRB->pNextSRB; - if( pSRB == pDCB->pWaitLastSRB ) - { - pDCB->pWaitLastSRB = pSRBTemp; /* No check for pSRBTemp == NULL ? */ } + pSRB = psrb->pNextSRB; + psrb->pNextSRB = pSRB->pNextSRB; + if( pSRB == pDCB->pWaitLast ) + pDCB->pWaitLast = psrb; IN_WAIT: - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; + TRACEPRINTF("abort (SU)!*"); + pDCB->WaitSRBCnt--; + DC395x_freetag (pDCB, pSRB); + DC395x_Free_insert (pACB, pSRB); cmd->next = NULL; status = SCSI_ABORT_SUCCESS; goto ABO_X; } + /* SRB has already been sent ? */ ON_GOING: pSRB = pDCB->pGoingSRB; + /* Now for the hard part: The command is currently processed */ for( count = pDCB->GoingSRBCnt, i=0; ipcmd != cmd ) pSRB = pSRB->pNextSRB; else { + 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->DevMode & 7) < 7) + { + printk ("DC395x: abort: Lower SyncFreq to for dev %02i-%i!\n", + pDCB->TargetID, pDCB->TargetLUN); + pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarPeriod + = pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarPeriod + + pDCB->DevMode + 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); goto ABO_X; } else { status = SCSI_ABORT_SNOOZE; + TRACEPRINTF("abort (SN)!*"); goto ABO_X; } } } - + NOT_RUN: status = SCSI_ABORT_NOT_RUNNING; ABO_X: - //DC395x_TRM_ACB_UNLOCK(pACB,acb_flags); - + 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) cmd->scsi_done(cmd); +#endif + in_driver--; return( status ); } /* ********************************************************************* ** -** DC395x_trm_reset DC395x_trm_ScsiRstDetect +** DC395x_reset DC395x_ScsiRstDetect ** ********************************************************************* */ -static void DC395x_trm_ResetDevParam( PACB pACB ) +static void DC395x_ResetDevParam( PACB pACB ) { PDCB pDCB, pDCBTemp; PNVRAMTYPE pEEpromBuf; BYTE PeriodIndex; WORD index; -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_ResetDevParam..............\n "); #endif pDCB = pACB->pLinkDCB; @@ -1981,29 +2292,31 @@ pDCB->DevMode = pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarCfg0; pDCB->AdpMode = pEEpromBuf->NvramChannelCfg; PeriodIndex = pEEpromBuf->NvramTarget[pDCB->TargetID].NvmTarPeriod & 0x07; - pDCB->MinNegoPeriod = dc395x_trm_clock_period[ PeriodIndex ] ; - if ((pDCB->DevMode & NTC_DO_WIDE_NEGO) && (pACB->Config & HCC_WIDE_CARD)) - pDCB->SyncMode |= WIDE_NEGO_ENABLE; + 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_trm_ScsiRstDetect +** DC395x_ScsiRstDetect ** ********************************************************************* */ -static void DC395x_trm_RecoverSRB( PACB pACB ) +/* 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_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_RecoverSRB.............\n "); #endif pDCB = pACB->pLinkDCB; @@ -2018,7 +2331,7 @@ { pSRBTemp2 = pSRBTemp; pSRBTemp = pSRBTemp->pNextSRB; - /* DC395x_trm_RewaitSRB( pDCB, pSRBTemp ); */ + /* DC395x_RewaitSRB( pDCB, pSRBTemp ); */ if( pDCBTemp->pWaitingSRB ) { pSRBTemp2->pNextSRB = pDCBTemp->pWaitingSRB; @@ -2027,7 +2340,7 @@ else { pDCBTemp->pWaitingSRB = pSRBTemp2; - pDCBTemp->pWaitLastSRB = pSRBTemp2; + pDCBTemp->pWaitLast = pSRBTemp2; pSRBTemp2->pNextSRB = NULL; } } @@ -2038,140 +2351,224 @@ } while( pDCBTemp != pDCB ); } - +#endif /* ********************************************************************** ** -** Function : int DC395x_trm_reset (Scsi_Cmnd *cmd, ...) +** 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_trm_reset(Scsi_Cmnd *cmd, unsigned int resetFlags) +int DC395x_reset(Scsi_Cmnd *cmd, unsigned int resetFlags) { - WORD ioport; PACB pACB; - WORD i; //DWORD acb_flags=0; pACB = (PACB ) cmd->host->hostdata; printk(KERN_INFO "DC395x: reset requested!\n"); pACB = (PACB) cmd->host->hostdata; + if (in_driver++ > NORM_REC_LVL) printk ("DC395x: %i reset recursion? (pid=%li)\n", + in_driver, cmd->pid); + //DC395x_ACB_LOCK(pACB,acb_flags); - //DC395x_TRM_ACB_LOCK(pACB,acb_flags); - - ioport = pACB->IOPortBase; + if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); + //if (timer_pending (&pACB->Data_Timer)) del_timer (&pACB->Data_Timer); /* - ** disable interrupt + ** disable interrupt */ - outb(0x00,ioport+TRM_S1040_DMA_INTEN); - outb(0x00,ioport+TRM_S1040_SCSI_INTEN); - - DC395x_trm_ResetSCSIBus( pACB ); - for( i=0; i<600; i++ ) - udelay(1000); + 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(1000); + /* We may be in serious trouble. Wait some seconds */ + pACB->pScsiHost->last_reset = jiffies + HZ/2 + 5*HZ; /* ** re-enable interrupt */ - /* Enable SCSI interrupt*/ - outb(0x7F,ioport+TRM_S1040_SCSI_INTEN); - /* Enable DMA interrupt */ - outb(EN_SCSIINTR,ioport+TRM_S1040_DMA_INTEN); - /* Clear DMA FIFO */ - outb(CLRXFIFO,ioport+TRM_S1040_DMA_CONTROL); /* Clear SCSI FIFO */ - outw(DO_CLRFIFO,ioport+TRM_S1040_SCSI_CONTROL); + DC395x_write8(TRM_S1040_DMA_CONTROL, CLRXFIFO); + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + /* Delete pending IRQ */ + DC395x_read8 (TRM_S1040_SCSI_INTSTATUS); + DC395x_basic_config (pACB); - DC395x_trm_ResetDevParam( pACB ); - DC395x_trm_DoingSRB_Done( pACB ); + DC395x_ResetDevParam( pACB ); + DC395x_DoingSRB_Done( pACB, DID_RESET ); pACB->pActiveDCB = NULL; pACB->ACBFlag = 0; /* RESET_DETECT, RESET_DONE ,RESET_DEV */ - DC395x_trm_DoWaitingSRB( pACB ); + DC395x_Waiting_process( pACB ); - //DC395x_TRM_ACB_LOCK(pACB,acb_flags); + //DC395x_ACB_LOCK(pACB,acb_flags); + 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*"); +} + /* ********************************************************************** ** scsiio -** DC395x_trm_DoWaitingSRB DC395x_trm_SRBdone -** DC395x_trm_SendSRB DC395x_trm_RequestSense +** DC395x_DoWaitingSRB DC395x_SRBdone +** DC395x_SendSRB DC395x_RequestSense ** ** ** ********************************************************************* */ -WORD DC395x_trm_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ) +WORD DC395x_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ) { - WORD s_stat2, ioport, return_code; + WORD s_stat2, return_code; BYTE s_stat, scsicommand, i, command, identify_message; PBYTE ptr; -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_StartSCSI..............\n "); #endif - pSRB->TagNumber = 31; /* pACB->TagMaxNum: had error read in eeprom */ - ioport = pACB->IOPortBase; + pSRB->TagNumber = TAG_NONE; /* pACB->TagMaxNum: had error read in eeprom */ - //s_stat = inb (ioport+TRM_S1040_SCSI_SIGNAL); - //s_stat2 = inw (ioport+TRM_S1040_SCSI_STATUS); - if (0 /*s_stat & 0x20*/ /* s_stat2 & 0x02000 */) + 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 0 + if (s_stat & 0x20/* s_stat2 & 0x02000 */) { - printk ("DC395x: StartSCSI: BUSY %02x %04x !\n", s_stat, s_stat2); + printk ("DC395x: Debug: StartSCSI: pid %li(%02i-%i): BUSY %02x %04x\n", + pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN, s_stat, s_stat2); + /* Try anyway! */ return 1; }; - outb(pACB->AdaptSCSIID,ioport+TRM_S1040_SCSI_HOSTID); - outb(pDCB->TargetID,ioport+TRM_S1040_SCSI_TARGETID); - outb(pDCB->SyncPeriod,ioport+TRM_S1040_SCSI_SYNC); - outb(pDCB->SyncOffset,ioport+TRM_S1040_SCSI_OFFSET); - pSRB->ScsiPhase = PH_BUS_FREE;/* initial phase */ +#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 ) + { + DEBUG0(printk ("DC395x: Debug: StartSCSI failed (busy) for pid %li(%02i-%i)\n", + pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN);) + 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)) + { + DEBUG0(printk ("DC395x: We were just reset and don't accept commands yet!\n");) + return 1; + } + /* Flush FIFO */ - outw( DO_CLRFIFO,ioport+TRM_S1040_SCSI_CONTROL); + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + 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; - - if( (pSRB->CmdBlock[0] == INQUIRY) || (pSRB->CmdBlock[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) ) - { - if ( ((pDCB->SyncMode & WIDE_NEGO_ENABLE) && !(pDCB->SyncMode & WIDE_NEGO_DONE)) - || ((pDCB->SyncMode & SYNC_NEGO_ENABLE) && !(pDCB->SyncMode & SYNC_NEGO_DONE)) ) + //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)) { - if( !(pDCB->IdentifyMsg & 7) || (pSRB->CmdBlock[0] != INQUIRY) ) - { - //outb( identify_message,ioport+TRM_S1040_SCSI_FIFO); + pSRB->MsgOutBuf[0] = identify_message; pSRB->MsgCnt = 1; scsicommand = SCMD_SEL_ATNSTOP; pSRB->SRBState = SRB_MSGOUT; - goto polling; - } +#ifndef SYNC_FIRST + if (pDCB->SyncMode & WIDE_NEGO_ENABLE) + { + DC395x_Build_WDTR (pACB, pDCB, pSRB); + goto no_cmd; + } +#endif + if (pDCB->SyncMode & SYNC_NEGO_ENABLE) + { + DC395x_Build_SDTR (pACB, pDCB, pSRB); + goto no_cmd; + } + if (pDCB->SyncMode & WIDE_NEGO_ENABLE) + { + DC395x_Build_WDTR (pACB, pDCB, pSRB); + goto no_cmd; + } + pSRB->MsgCnt = 0; } - /* - ** Send identify message - */ - outb( (identify_message & 0xBF) ,ioport+TRM_S1040_SCSI_FIFO); - scsicommand = SCMD_SEL_ATN; - pSRB->SRBState = SRB_START_; - } - else - { - /* - ** Send identify message - */ - outb(identify_message,ioport+TRM_S1040_SCSI_FIFO); - scsicommand = SCMD_SEL_ATN; - pSRB->SRBState = SRB_START_; + /* + ** 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) - { + if ((pDCB->SyncMode & EN_TAG_QUEUEING) && (identify_message & 0xC0)) + { /* Send Tag message */ - /* - ** Get tag id - */ DWORD tag_mask = 1; BYTE tag_number = 0; - while( tag_mask & pDCB->TagMask ) + while( tag_mask & pDCB->TagMask && tag_number <= pDCB->MaxCommand) { tag_mask = tag_mask << 1; tag_number++; @@ -2181,75 +2578,83 @@ 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 - */ - outb(MSG_SIMPLE_QTAG,ioport+TRM_S1040_SCSI_FIFO); - outb(tag_number,ioport+TRM_S1040_SCSI_FIFO); + ** 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: +//polling: /* ** Send CDB ..command block ......... */ -#ifdef DC395x_trm_DEBUG_KG +#ifdef DC395x_DEBUG_KG printk (KERN_INFO "DC395x: Start_SCSI (pid %li): Tag %i\n", pSRB->pcmd->pid, pSRB->TagNumber); #endif if( pSRB->SRBFlag & AUTO_REQSENSE ) { - outb(REQUEST_SENSE,ioport+TRM_S1040_SCSI_FIFO); - outb((pDCB->IdentifyMsg << 5),ioport+TRM_S1040_SCSI_FIFO); - outb(0,ioport+TRM_S1040_SCSI_FIFO); - outb(0,ioport+TRM_S1040_SCSI_FIFO); - outb(sizeof(pSRB->pcmd->sense_buffer),ioport+TRM_S1040_SCSI_FIFO); - outb(0,ioport+TRM_S1040_SCSI_FIFO); + 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->CmdBlock; - for(i=0; i < pSRB->ScsiCmdLen ; i++) + ptr = (PBYTE) pSRB->pcmd->cmnd; + for(i=0; i < pSRB->pcmd->cmd_len; i++) { command = *ptr++; - outb(command,ioport+TRM_S1040_SCSI_FIFO); + DC395x_write8(TRM_S1040_SCSI_FIFO,command); } } - if( inw( ioport+TRM_S1040_SCSI_STATUS ) & SCSIINTERRUPT ) +no_cmd: + DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); + if( DC395x_read16(TRM_S1040_SCSI_STATUS ) & SCSIINTERRUPT ) { /* - ** If DC395x_trm_StartSCSI return 1 : - ** current interrupt status is interrupt disreenable - ** It's said that SCSI processor has more one SRB need to do, - ** SCSI processor has been occupied by one SRB. + ** If DC395x_StartSCSI return 1: + ** we caught an interrupt: Let's process it first! */ - //outw( DO_CLRFIFO,ioport+TRM_S1040_SCSI_CONTROL); + DEBUG0(printk ("DC395x: Debug: StartSCSI failed (busy) for pid %li(%02i-%i)!\n", + pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN);) + //DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + //DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); pSRB->SRBState = SRB_READY; - pDCB->TagMask &= ~( 1 << pSRB->TagNumber ); + 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_trm_StartSCSI returns 0: + ** If DC395x_StartSCSI returns 0: ** we know that the SCSI processor is free */ + pSRB->ScsiPhase = PH_BUS_FREE;/* initial phase */ - pACB->pActiveDCB = pDCB; pDCB->pActiveSRB = pSRB; + pACB->pActiveDCB = pDCB; return_code = 0; /* it's important for atn stop */ - outw (DO_DATALATCH | DO_HWRESELECT, ioport+TRM_S1040_SCSI_CONTROL); + DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH | DO_HWRESELECT); /* - ** SCSI cammand + ** SCSI command */ - outb (scsicommand,ioport+TRM_S1040_SCSI_COMMAND); + TRACEPRINTF ("%02x *", scsicommand); + DC395x_write8 (TRM_S1040_SCSI_COMMAND, scsicommand); } return( return_code ); } @@ -2257,40 +2662,43 @@ /* ********************************************************************* ** scsiio -** DC395x_trm_initAdapter +** DC395x_initAdapter ** ********************************************************************* */ -inline void DC395x_trm_Interrupt( int irq, void *dev_id, struct pt_regs *regs) +//inline +void DC395x_Interrupt( int irq, void *dev_id, struct pt_regs *regs) { PACB pACB; PDCB pDCB; PSRB pSRB; - WORD phase,i,ioport=0,scsi_status=0; - void (*DC395x_trm_stateV)( PACB, PSRB, PWORD ); - BYTE scsi_intstatus; + 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_TRM_pACB_start; + pACB = DC395x_pACB_start; if( pACB == NULL ) return; - DC395x_LOCK_IO; - -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_Interrupt..............\n "); #endif - pACB = DC395x_TRM_pACB_start; + pACB = DC395x_pACB_start; if( pACB == NULL ) { - printk(KERN_WARNING "DC395x: Interrupt on uninitialized pACB!\n"); + printk(KERN_WARNING "DC395x: Interrupt on uninitialized pACB!\n"); return; } - //DC395x_TRM_DRV_LOCK(drv_flags); + DC395x_LOCK_IO; + + if (in_driver++ > NORM_REC_LVL) printk ("DC395x: %i interrupt recursion?\n", in_driver); + + //DC395x_DRV_LOCK(drv_flags); - for( i=0; i < DC395x_TRM_adapterCnt; i++ ) + for( i=0; i < DC395x_adapterCnt; i++ ) { /* ** find mach correct pACB with same IRQLevel @@ -2299,87 +2707,80 @@ */ if( pACB->IRQLevel == (BYTE) irq ) { - ioport = pACB->IOPortBase; - scsi_status = inw( ioport+TRM_S1040_SCSI_STATUS ); - /* - #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 - */ + scsi_status = DC395x_read16(TRM_S1040_SCSI_STATUS ); + dma_status = DC395x_read8 (TRM_S1040_DMA_STATUS); if( scsi_status & SCSIINTERRUPT ) - { - /* - ** interrupt service request signal - ** is come from this adapter (pACB) - */ break; + if (dma_status) + { + printk ("DC395x: Interrupt from DMA engine: %02x!\n", dma_status); + break; } else - { - /* - ** point to next adapter pACB if no interrupt pending - */ pACB = pACB->pNextACB; - } } else - { - /* - ** point to next adapter pACB - */ pACB = pACB->pNextACB; - } } - //DC395x_TRM_DRV_UNLOCK(drv_flags); + //DC395x_DRV_UNLOCK(drv_flags); if( pACB == (PACB)-1 ) { //printk("DC395x_Interrupt: Spurious interrupt detected!\n"); goto out_unlock; } - scsi_intstatus = inb( ioport+TRM_S1040_SCSI_INTSTATUS ); -#ifdef DC395x_trm_DEBUG0 - printk(KERN_INFO "scsi_intstatus=%02x \n", scsi_intstatus); + /* This acknowledges the IRQ */ + scsi_intstatus = DC395x_read8(TRM_S1040_SCSI_INTSTATUS ); +#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_TRM_ACB_LOCK(pACB,acb_flags); + //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(scsi_intstatus & (INT_SELTIMEOUT | INT_DISCONNECT)) { - DC395x_trm_Disconnect( pACB );/* bus free interrupt */ + DC395x_Disconnect( pACB );/* bus free interrupt */ goto out_unlock; } if(scsi_intstatus & INT_RESELECTED) { - DC395x_trm_Reselect( pACB ); + 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_trm_ScsiRstDetect( pACB ); + 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 ) { if( pDCB->DCBFlag & ABORT_DEV_ ) { -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "MsgOut Abort Device..... "); #endif - DC395x_trm_EnableMsgOutAbort1( pACB, pSRB ); + DC395x_EnableMsgOut_Abort( pACB, pSRB ); } } /* @@ -2390,278 +2791,348 @@ phase = (WORD) pSRB->ScsiPhase; /* ** 62037 or 62137 - ** call DC395x_trm_SCSI_phase0[]... "phase entry" + ** call DC395x_SCSI_phase0[]... "phase entry" ** handle every phase before start transfer */ - /* DC395x_trm_DataOutPhase0, phase:0 */ - /* DC395x_trm_DataInPhase0, phase:1 */ - /* DC395x_trm_CommandPhase0, phase:2 */ - /* DC395x_trm_StatusPhase0, phase:3 */ - /* DC395x_trm_Nop0, phase:4 PH_BUS_FREE .. initial phase */ - /* DC395x_trm_Nop1, phase:5 PH_BUS_FREE .. initial phase */ - /* DC395x_trm_MsgOutPhase0, phase:6 */ - /* DC395x_trm_MsgInPhase0, phase:7 */ - DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase0[phase]; - DC395x_trm_stateV( pACB, pSRB, &scsi_status ); + /* 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 ... prvious DC395x_trm_stateV + ** new scsi_status transfer out from ... previous DC395x_stateV ** **$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ */ pSRB->ScsiPhase = scsi_status & PHASEMASK; phase = (WORD) scsi_status & PHASEMASK; /* - ** call DC395x_trm_SCSI_phase1[]... "phase entry" + ** call DC395x_SCSI_phase1[]... "phase entry" ** handle every phase do transfer */ - /* DC395x_trm_DataOutPhase1, phase:0 */ - /* DC395x_trm_DataInPhase1, phase:1 */ - /* DC395x_trm_CommandPhase1, phase:2 */ - /* DC395x_trm_StatusPhase1, phase:3 */ - /* DC395x_trm_Nop0, phase:4 PH_BUS_FREE .. initial phase */ - /* DC395x_trm_Nop1, phase:5 PH_BUS_FREE .. initial phase */ - /* DC395x_trm_MsgOutPhase1, phase:6 */ - /* DC395x_trm_MsgInPhase1, phase:7 */ - DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase1[phase]; - DC395x_trm_stateV( pACB, pSRB, &scsi_status ); + /* 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: + in_driver--; DC395x_UNLOCK_IO; - //DC395x_TRM_ACB_UNLOCK(pACB,acb_flags); + //printk ("... done\n"); + //DC395x_ACB_UNLOCK(pACB,acb_flags); return; } +#if 0 /* ********************************************************************* ** scsiio -** DC395x_trm_initAdapter -** do_DC390_Interrupt +** DC395x_initAdapter +** do_DC395x_Interrupt ** ********************************************************************* */ -void do_DC395x_trm_Interrupt( int irq, void *dev_id, struct pt_regs *regs) +void do_DC395x_Interrupt( int irq, void *dev_id, struct pt_regs *regs) { - //DWORD irq_flags; - //if( cpuid != 0 ) // return; -#ifdef DC390x_TRM_DEBUG0 - printk (KERN_INFO "irq (%i) SMP_IO_LOCK cpuid=%2x\n",irq,cpuid); -#endif - //DC395x_TRM_SMP_IO_LOCK(irq_flags); - DC395x_trm_Interrupt(irq, dev_id, regs); - //DC395x_TRM_SMP_IO_UNLOCK(irq_flags); -#ifdef DC395x_TRM_DEBUG0 - printk (KERN_INFO "irq (%i) SMP_IO_UNLOCK cpuid=%2x\n",irq,cpuid); -#endif + //DC395x_LOCK_IO; + DC395x_Interrupt(irq, dev_id, regs); + //DC395x_UNLOCK_IO; } +#endif /* ********************************************************************* ** scsiio -** DC395x_trm_MsgOutPhase0: one of DC395x_trm_SCSI_phase0[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** DC395x_MsgOutPhase0: one of DC395x_SCSI_phase0[] vectors +** DC395x_stateV = (void *) DC395x_SCSI_phase0[phase] ** if phase =6 ** ** ********************************************************************* */ -static void DC395x_trm_MsgOutPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +static void DC395x_MsgOutPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) { - WORD ioport; - -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_MsgOutPhase0..... "); #endif - ioport = pACB->IOPortBase; 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_trm_MsgOutPhase1: one of DC395x_trm_SCSI_phase0[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** DC395x_MsgOutPhase1: one of DC395x_SCSI_phase0[] vectors +** DC395x_stateV = (void *) DC395x_SCSI_phase0[phase] ** if phase =6 ** ** ********************************************************************* */ -static void DC395x_trm_MsgOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +static void DC395x_MsgOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) { - WORD ioport, i; + WORD i; PBYTE ptr; PDCB pDCB; -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_MsgOutPhase1..............\n "); #endif - ioport = pACB->IOPortBase; - outw(DO_CLRFIFO, ioport+TRM_S1040_SCSI_CONTROL); + TRACEPRINTF ("MOP1*"); pDCB = pACB->pActiveDCB; + DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); if( !(pSRB->SRBState & SRB_MSGOUT) ) { - if( pSRB->MsgCnt ) - { - ptr = (PBYTE) pSRB->MsgOutBuf; - //printk ("DC395x: MsgOut: "); - for(i=0; i < pSRB->MsgCnt ; i++) - { - outb(*ptr, ioport+TRM_S1040_SCSI_FIFO); - //printk ("%02x ", *ptr); - ptr++; - } - pSRB->MsgCnt = 0; - //printk ("\n"); - if( (pDCB->DCBFlag & ABORT_DEV_) && (pSRB->MsgOutBuf[0] == MSG_ABORT) ) - pSRB->SRBState = SRB_ABORT_SENT; - - } - else - { - if( (pSRB->CmdBlock[0] == INQUIRY ) || (pSRB->CmdBlock[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) ) - { - if( pDCB->SyncMode & SYNC_NEGO_ENABLE ) - goto mop1; - - } - outb(MSG_ABORT, ioport+TRM_S1040_SCSI_FIFO); - } + pSRB->SRBState |= SRB_MSGOUT; + printk ("DC395x: Debug: MsgOut Phase unexpected.\n"); /* So what ? */ } - else + if (!pSRB->MsgCnt) { -mop1: /* message out phase */ - if( !(pSRB->SRBState & SRB_DO_WIDE_NEGO) && (pDCB->SyncMode & WIDE_NEGO_ENABLE) ) - { - - /* - ** WIDE DATA TRANSFER REQUEST code (03h) - */ - pDCB->SyncMode &= ~(SYNC_NEGO_DONE | EN_ATN_STOP ); - outb( (pDCB->IdentifyMsg & 0xBF) ,ioport+TRM_S1040_SCSI_FIFO); - outb( MSG_EXTENDED,ioport+TRM_S1040_SCSI_FIFO); /* (01h) */ - outb( 2,ioport+TRM_S1040_SCSI_FIFO); /* Message length (01h) */ - outb( EXTENDED_WDTR,ioport+TRM_S1040_SCSI_FIFO); /* wide data xfer (03h) */ - outb( 1,ioport+TRM_S1040_SCSI_FIFO); /* width:0(8bit),1(16bit),2(32bit) */ -#ifdef DC395x_trm_DEBUG0 - printk ("DC395x: Send WDTR to target %02i\n", pDCB->TargetID); -#endif - pSRB->SRBState |= SRB_DO_WIDE_NEGO; - } - else if( !(pSRB->SRBState & SRB_DO_SYNC_NEGO) && (pDCB->SyncMode & SYNC_NEGO_ENABLE) ) - { - /* - ** SYNCHRONOUS DATA TRANSFER REQUEST code (01h) - */ - if(!(pDCB->SyncMode & WIDE_NEGO_DONE) ) - outb( (pDCB->IdentifyMsg & 0xBF) ,ioport+TRM_S1040_SCSI_FIFO); - - outb( MSG_EXTENDED,ioport+TRM_S1040_SCSI_FIFO); /* (01h) */ - outb( 3,ioport+TRM_S1040_SCSI_FIFO); /* Message length (03h) */ - outb( EXTENDED_SDTR,ioport+TRM_S1040_SCSI_FIFO); /* SYNCHRONOUS DATA TRANSFER REQUEST code (01h) */ - outb( pDCB->MinNegoPeriod,ioport+TRM_S1040_SCSI_FIFO); /* Transfer period factor */ - outb( SYNC_NEGO_OFFSET,ioport+TRM_S1040_SCSI_FIFO); /* REQ/ACK offset */ - pSRB->SRBState |= SRB_DO_SYNC_NEGO; -#ifdef DC395x_trm_DEBUG0 - printk ("DC395x: Send SDTR to target %02i\n", pDCB->TargetID); -#endif - } + DEBUG0(printk ("DC395x: NOP Msg (no output message there).\n");) + 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; } - outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + 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; + /* - ** SCSI cammand + ** SCSI command */ - outb( SCMD_FIFO_OUT, ioport+TRM_S1040_SCSI_COMMAND); + //TRACEPRINTF (".*"); + DC395x_write8(TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); } /* ********************************************************************* ** scsiio -** DC395x_trm_CommandPhase0: one of DC395x_trm_SCSI_phase0[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** DC395x_CommandPhase0: one of DC395x_SCSI_phase0[] vectors +** DC395x_stateV = (void *) DC395x_SCSI_phase0[phase] ** if phase =2 ** ** ********************************************************************* */ -static void DC395x_trm_CommandPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +static void DC395x_CommandPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) { + TRACEPRINTF("COP0 *"); + DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH); } /* ********************************************************************* ** scsiio -** DC395x_trm_CommandPhase1: one of DC395x_trm_SCSI_phase1[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** DC395x_CommandPhase1: one of DC395x_SCSI_phase1[] vectors +** DC395x_stateV = (void *) DC395x_SCSI_phase1[phase] ** if phase =2 ** ** ********************************************************************* */ -static void DC395x_trm_CommandPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +static void DC395x_CommandPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) { PDCB pDCB; PBYTE ptr; - WORD ioport, i; + WORD i; -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_CommandPhase1..............\n "); #endif - ioport = pACB->IOPortBase; - outw( DO_CLRATN | DO_CLRFIFO , ioport+TRM_S1040_SCSI_CONTROL); + TRACEPRINTF("COP1*"); + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRATN | DO_CLRFIFO ); if( !(pSRB->SRBFlag & AUTO_REQSENSE) ) { - ptr = (PBYTE) pSRB->CmdBlock; - for(i=0; i < pSRB->ScsiCmdLen ; i++) + ptr = (PBYTE) pSRB->pcmd->cmnd; + for(i=0; i < pSRB->pcmd->cmd_len; i++) { - outb(*ptr, ioport+TRM_S1040_SCSI_FIFO); + DC395x_write8(TRM_S1040_SCSI_FIFO, *ptr); ptr++; } } else { - outb(REQUEST_SENSE, ioport+TRM_S1040_SCSI_FIFO); + DC395x_write8(TRM_S1040_SCSI_FIFO, REQUEST_SENSE); pDCB = pACB->pActiveDCB; /* target id */ - outb((pDCB->IdentifyMsg << 5), ioport+TRM_S1040_SCSI_FIFO); - outb(0, ioport+TRM_S1040_SCSI_FIFO); - outb(0, ioport+TRM_S1040_SCSI_FIFO); - outb(sizeof(pSRB->pcmd->sense_buffer), ioport+TRM_S1040_SCSI_FIFO); - outb(0, ioport+TRM_S1040_SCSI_FIFO); - } - pSRB->SRBState = SRB_COMMAND; - /* it's important for atn stop*/ - outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL); - /* - ** SCSI cammand - */ - outb(SCMD_FIFO_OUT, ioport+TRM_S1040_SCSI_COMMAND); + 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->SRBSGListPointer + 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->SRBSGListPointer + 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); } -/* -********************************************************************* -** scsiio -** DC395x_trm_DataOutPhase0: one of DC395x_trm_SCSI_phase0[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase0[phase] -** if phase =0 -** -** -********************************************************************* -*/ -static void DC395x_trm_DataOutPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +#endif + +/* Compute the next Scatter Gather list index and adjust its length + * and address if necessary */ +static void DC395x_update_SGlist (PSRB pSRB, DWORD Left) { - PDCB pDCB; - BYTE TempDMAstatus,SGIndexTemp; - WORD ioport,scsi_status; - PSGE0 psge; - DWORD TempSRBXferredLength,dLeftCounter=0; + PSGE0 psge; + DWORD Xferred; + BYTE Idx; + +#ifdef DC395x_DEBUG0 + printk ("DC395x: Update SG: Total %i, Left %i\n", + pSRB->SRBTotalXferLength, Left); +#endif + DC395x_check_SG (pSRB); + if (pSRB->SRBTotalXferLength != Left) + { + /* data that has already been transferred */ + Xferred = pSRB->SRBTotalXferLength - Left; + //DC395x_check_SG_TX (pSRB, Xferred); + /* Remaining */ + pSRB->SRBTotalXferLength = Left; + /* parsing from last time disconnect SGIndex */ + psge = pSRB->SRBSGListPointer + pSRB->SRBSGIndex; + 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; + break; + } + psge++; + } + DC395x_check_SG (pSRB); + } +} + + /* + * 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 + */ +void static 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) + { + if (!(DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x40)) + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + + if (!(DC395x_read16(TRM_S1040_DMA_FIFOCNT) & 0x8000)) + DC395x_write8(TRM_S1040_DMA_CONTROL, CLRXFIFO); + } + else + { + if (!(DC395x_read16(TRM_S1040_DMA_FIFOCNT) & 0x8000)) + DC395x_write8(TRM_S1040_DMA_CONTROL, CLRXFIFO); + + if (!(DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x40)) + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + + } + //DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH); +} + + + +/* + ********************************************************************* + ** 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) +{ + BYTE TempDMAstatus; + WORD scsi_status; + DWORD dLeftCounter = 0; + PDCB pDCB = pSRB->pSRBDCB; -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_DataOutPhase0..... "); #endif + TRACEPRINTF("DOP0*"); + //if (timer_pending (&pACB->Data_Timer)) del_timer (&pACB->Data_Timer); pDCB = pSRB->pSRBDCB; - ioport = pACB->IOPortBase; scsi_status = *pscsi_status; if( !(pSRB->SRBState & SRB_XFERPAD) ) @@ -2675,15 +3146,13 @@ ** when data transfer from DMA FIFO to SCSI FIFO ** if there was some data left in SCSI FIFO */ - dLeftCounter = (DWORD) (inb(ioport+TRM_S1040_SCSI_FIFOCNT) & 0x1F); - if (pDCB->SyncMode & WIDE_NEGO_ENABLE) - { - /* - ** if WIDE scsi SCSI FIFOCNT unit is word - ** so need to * 2 - */ + dLeftCounter = (DWORD) (DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x1F); + if (pDCB->SyncPeriod & WIDE_SYNC) dLeftCounter <<= 1; - } + /* + ** if WIDE scsi SCSI FIFOCNT unit is word !!! + ** so need to *= 2 + */ } /* ** caculate all the residue data that not yet tranfered @@ -2692,20 +3161,20 @@ ** .....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 + ** The counter is SCSI FIFO offset counter (in units of bytes or words) */ - dLeftCounter += inl(ioport+TRM_S1040_SCSI_COUNTER); + dLeftCounter += DC395x_read32(TRM_S1040_SCSI_COUNTER); if ( dLeftCounter == 1 ) { dLeftCounter = 0; - outw(DO_CLRFIFO,ioport+TRM_S1040_SCSI_CONTROL); + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); } if((dLeftCounter == 0) || (scsi_status & SCSIXFERCNT_2_ZERO) ) { int ctr = 6000000; do { - TempDMAstatus = inb(ioport+TRM_S1040_DMA_STATUS); + TempDMAstatus = DC395x_read8(TRM_S1040_DMA_STATUS); } while( !(TempDMAstatus & DMAXFERCOMP) && --ctr); if (!ctr) printk (KERN_ERR "DC395x: Deadlock in DataOutPhase0 !!\n"); @@ -2718,108 +3187,111 @@ ** there were some data residue in SCSI FIFO or ** SCSI transfer counter not empty */ - if (pSRB->SRBTotalXferLength != dLeftCounter) - { - /* - ** data that had transferred length - */ - TempSRBXferredLength = pSRB->SRBTotalXferLength - dLeftCounter; - /* - ** next time to be transferred length - */ - pSRB->SRBTotalXferLength = dLeftCounter; - /* - ** parsing from last time disconnect SGIndex - */ - psge = pSRB->SRBSGListPointer + pSRB->SRBSGIndex; - for ( SGIndexTemp= pSRB->SRBSGIndex ; SGIndexTemp < pSRB->SRBSGCount; SGIndexTemp++) - { - /* - ** find last time which SG transfer be disconnect - */ - if (TempSRBXferredLength >= psge->length) - TempSRBXferredLength -= psge->length; - else - { - /* - ** update last time disconnected SG list - */ - psge->length -= TempSRBXferredLength; /* residue data length */ - psge->address += TempSRBXferredLength;/* residue data pointer */ - pSRB->SRBSGIndex = SGIndexTemp; - break; - } - psge++; - } - } + DC395x_update_SGlist (pSRB, dLeftCounter); } } +#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_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + //DC395x_write8 (TRM_S1040_DMA_CONTROL, CLRXFIFO | ABORTXFER); + + if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT) { + //printk ("DC395x: Debug: Clean up after Data Out ...\n"); + DC395x_cleanup_after_transfer (pACB, pSRB); + } + TRACEPRINTF(".*"); } /* ********************************************************************* ** scsiio -** DC395x_trm_DataOutPhase1: one of DC395x_trm_SCSI_phase0[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** DC395x_DataOutPhase1: one of DC395x_SCSI_phase0[] vectors +** DC395x_stateV = (void *) DC395x_SCSI_phase0[phase] ** if phase =0 ** ** 62037 ********************************************************************* */ -static void DC395x_trm_DataOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +static void DC395x_DataOutPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) { - WORD ioDir; -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_DataOutPhase1..... "); #endif + //DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + TRACEPRINTF("DOP1*"); /* ** do prepare befor transfer when data out phase */ - ioDir = XFERDATAOUT; - DC395x_trm_DataIO_transfer( pACB, pSRB, ioDir); + DC395x_DataIO_transfer (pACB, pSRB, XFERDATAOUT); + TRACEPRINTF(".*"); } /* ********************************************************************* ** scsiio -** DC395x_trm_DataInPhase0: one of DC395x_trm_SCSI_phase1[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** DC395x_DataInPhase0: one of DC395x_SCSI_phase1[] vectors +** DC395x_stateV = (void *) DC395x_SCSI_phase1[phase] ** if phase =1 ** ** ********************************************************************* */ -static void DC395x_trm_DataInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +void DC395x_DataInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) { - BYTE TempDMAstatus,SGIndexTemp; - WORD ioport,scsi_status; - PSGE0 psge; - DWORD TempSRBXferredLength,dLeftCounter=0; + BYTE TempDMAstatus; + WORD scsi_status; + DWORD dLeftCounter = 0; + //PDCB pDCB = pSRB->pSRBDCB; + //BYTE bval; -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_DataInPhase0..............\n "); #endif - ioport = pACB->IOPortBase; + TRACEPRINTF("DIP0*"); + //if (timer_pending (&pACB->Data_Timer)) del_timer (&pACB->Data_Timer); scsi_status = *pscsi_status; if( !(pSRB->SRBState & SRB_XFERPAD) ) { if( scsi_status & PARITYERROR ) { - printk(KERN_INFO "DC395x: Parity Error (pid %li, target %i-%i)\n", + printk("DC395x: Parity Error (pid %li, target %02i-%i)\n", pSRB->pcmd->pid, pSRB->pcmd->target, pSRB->pcmd->lun); pSRB->SRBStatus |= PARITY_ERROR; + } +#if 0 + // KG: Is this needed also for DataIn? + 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 ... + */ } - dLeftCounter += inl(ioport+TRM_S1040_SCSI_COUNTER); +#endif + // KG: This is always in bytes? + dLeftCounter += DC395x_read32(TRM_S1040_SCSI_COUNTER); + if((dLeftCounter == 0) || (scsi_status & SCSIXFERCNT_2_ZERO) ) { - int ctr = 6000000; + int ctr = 6000000; do { - TempDMAstatus = inb(ioport+TRM_S1040_DMA_STATUS); + TempDMAstatus = DC395x_read8(TRM_S1040_DMA_STATUS); } while( !(TempDMAstatus & DMAXFERCOMP) && --ctr); - if (!ctr) printk (KERN_ERR "DC395x: Deadlock in DataInPhase0 !!\n"); + if (!ctr) printk (KERN_ERR "DC395x: Deadlock in DataInPhase0 waiting for DMA!!\n"); pSRB->SRBTotalXferLength = 0; } else /* phase changed */ @@ -2827,118 +3299,228 @@ /* ** parsing the case: ** when a transfer not yet complete - ** but be disconnected by uper layer + ** but be disconnected by target ** if transfer not yet complete ** there were some data residue in SCSI FIFO or ** SCSI transfer counter not empty */ - if (pSRB->SRBTotalXferLength != dLeftCounter) - { - /* - ** data that had transferred length - */ - TempSRBXferredLength = pSRB->SRBTotalXferLength - dLeftCounter; - /* - ** next time to be transferred length - */ - pSRB->SRBTotalXferLength = dLeftCounter; - /* - ** parsing from last time disconnect SGIndex - */ - psge = pSRB->SRBSGListPointer + pSRB->SRBSGIndex; - for ( SGIndexTemp = pSRB->SRBSGIndex; SGIndexTemp < pSRB->SRBSGCount ; SGIndexTemp++) - { - /* - ** find last time which SG transfer be disconnect - */ - if (TempSRBXferredLength >= psge->length) - TempSRBXferredLength -= psge->length; - else - { - /* - ** update last time disconnected SG list - */ - psge->length -= TempSRBXferredLength; /* residue data length */ - psge->address += TempSRBXferredLength;/* residue data pointer */ - pSRB->SRBSGIndex = SGIndexTemp; - break; - } - psge++; - } - } + 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_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); } } +#endif + //DC395x_write8 (TRM_S1040_DMA_CONTROL, CLRXFIFO | ABORTXFER); + + //DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + //DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH); + TRACEPRINTF(".*"); } /* ********************************************************************* ** scsiio -** DC395x_trm_DataInPhase1: one of DC395x_trm_SCSI_phase0[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** DC395x_DataInPhase1: one of DC395x_SCSI_phase0[] vectors +** DC395x_stateV = (void *) DC395x_SCSI_phase0[phase] ** if phase =1 ** ** ********************************************************************* */ -static void DC395x_trm_DataInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +static void DC395x_DataInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) { - WORD ioDir; - -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_DataInPhase1..... "); #endif + /* FIFO should be cleared, if previous phase was not DataPhase */ + //DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + /* Allow data in! */ + //DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH); + TRACEPRINTF("DIP1:*"); /* - ** do prepare befor transfer when data in phase + ** do prepare before transfer when data in phase */ - ioDir = XFERDATAIN; - DC395x_trm_DataIO_transfer( pACB, pSRB, ioDir); + DC395x_DataIO_transfer (pACB, pSRB, XFERDATAIN); + TRACEPRINTF(".*"); } +#if 0 +void DC395x_data1_timed_out (unsigned long ptr); +/* Sets the timer to wake us up */ +static void DC395x_data1_timer (PSRB pSRB, unsigned long to) +{ + PACB pACB; + PDCB pDCB = pSRB->pSRBDCB; + if (pDCB) pACB = pDCB->pDCBACB; + else { + printk ("DC395x: Data1_Timer_Set: DCB == 0! (pid %li) Oops!\n", + pSRB->pcmd->pid); + return; + } + if (timer_pending (&pACB->Data_Timer)) return; + init_timer (&pACB->Data_Timer); + pACB->Data_Timer.function = DC395x_data1_timed_out; + pACB->Data_Timer.data = (unsigned long)pSRB; + pACB->Data_Timer.expires = jiffies + to; + add_timer (&pACB->Data_Timer); +} + +void DC395x_data1_timed_out (unsigned long ptr) +{ + unsigned long flags; + PSRB pSRB = (PSRB)ptr; + PDCB pDCB = pSRB->pSRBDCB; + PACB pACB; + WORD s_stat; + if (pDCB) pACB = pDCB->pDCBACB; + else { + printk ("DC395x: Data1_Timed_Out: DCB == 0! (pid %li) Oops!\n", + pSRB->pcmd->pid); + return; + } + DC395x_LOCK_IO; + s_stat = DC395x_read16 (TRM_S1040_SCSI_STATUS); + printk ("DC395x: ***** BUG ***** Data1 timed out!\n"); + printk ("DC395x: This means: You are in serious trouble! Lower Sync Offset for tgt %02i!\n", + pDCB->TargetID); + TRACEPRINTF("!*"); + DC395x_dumpinfo (pACB, 0, 0); + /* Try to handle different cases */ + if (s_stat & SEQUENCERACTIVE) + { + DC395x_data1_timer (pSRB, HZ*30); + printk ("DC395x: SCSI Sequencer Active! What now?\n"); + printk ("DC395x: Something weird got your device upset!\n"); + printk ("DC395x: SCSI engine seems to have 0x%05x bytes remaining of 0x%05x\n", + DC395x_read32 (TRM_S1040_SCSI_COUNTER), pSRB->SRBTotalXferLength); + printk ("DC395x: DMA engine at pos 0x%04x + FIFO %02x\n", + DC395x_read32 (TRM_S1040_DMA_CXCNT), DC395x_read8 (TRM_S1040_DMA_FIFOCNT)); + printk ("DC395x: Recover by waiting for the SCSI bus being reset ...\n"); + DC395x_write8 (TRM_S1040_DMA_CONTROL, ABORTXFER | CLRXFIFO); + DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_CMDABORT | DO_CLRFIFO); + /* + udelay (100); + DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_RSTSCSI); + */ + DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); + printk ("DC395x: Trying to abort ...\n"); + pDCB->DCBFlag |= ABORT_DEV_; + //DC395x_EnableMsgOut_Abort (pACB, pSRB); + printk ("DC395x: Read README.dc395x for more info.\n"); + DC395x_UNLOCK_IO; + return; + }; + if ((s_stat & PHASEMASK) != pSRB->ScsiPhase) + { + void (*DC395x_stateV)( PACB, PSRB, PWORD ); + printk ("DC395x: Probably missed a SCSI phase change IRQ: %02x -> %02x\n", + pSRB->ScsiPhase, (s_stat & PHASEMASK)); + /* Try to handle it */ + DC395x_stateV = (void *) DC395x_SCSI_phase0[pSRB->ScsiPhase]; + DC395x_stateV( pACB, pSRB, &s_stat ); + pSRB->ScsiPhase = s_stat & PHASEMASK; + DC395x_stateV = (void *) DC395x_SCSI_phase1[pSRB->ScsiPhase]; + DC395x_stateV( pACB, pSRB, &s_stat ); + DC395x_UNLOCK_IO; + return; + }; + TRACEPRINTF("R*"); + if (s_stat & PH_DATA_IN) + { + DC395x_DataInPhase0 (pACB, pSRB, &s_stat); + DC395x_DataInPhase1 (pACB, pSRB, &s_stat); + } + else + { + DC395x_DataOutPhase0 (pACB, pSRB, &s_stat); + DC395x_DataOutPhase1 (pACB, pSRB, &s_stat); + } + DC395x_UNLOCK_IO; + printk ("DC395x: Data1 restarted (%04x)\n", s_stat); +} +#endif /* ********************************************************************* ** scsiio -** DC395x_trm_DataOutPhase1 -** DC395x_trm_DataInPhase1 +** DC395x_DataOutPhase1 +** DC395x_DataInPhase1 ** ********************************************************************* */ -static void DC395x_trm_DataIO_transfer( PACB pACB, PSRB pSRB, WORD ioDir) +void DC395x_DataIO_transfer( PACB pACB, PSRB pSRB, WORD ioDir) { BYTE bval; - WORD ioport; PDCB pDCB; -#ifdef DC395x_trm_DEBUG0 - printk(KERN_INFO "DC395x_DataIO_transfer..............\n "); +#ifdef DC395x_DEBUG0 + printk(KERN_INFO "DC395x: DataIO_transfer %c (pid %li): len = %i, SG: %i", + (ioDir == XFERDATAOUT? 'w': 'r'), pSRB->pcmd->pid, + pSRB->SRBTotalXferLength, pSRB->SRBSGCount - pSRB->SRBSGIndex); #endif - ioport = pACB->IOPortBase; + TRACEPRINTF("%05x(%i/%i)*", pSRB->SRBTotalXferLength, + pSRB->SRBSGIndex, pSRB->SRBSGCount); pDCB = pSRB->pSRBDCB; if( pSRB->SRBSGIndex < pSRB->SRBSGCount ) { if( pSRB->SRBTotalXferLength != 0 ) { - pSRB->SRBSGPhyAddr = virt_to_phys(pSRB->SRBSGListPointer); + 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_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + pSRB->SRBSGBusAddr = virt_to_bus (pSRB->SRBSGListPointer + pSRB->SRBSGIndex); /* - ** load what physical address of Scatter/Gather list table want to be + ** load what physical address of Scatter/Gather list table want to be ** transfer */ - pSRB->SRBState = SRB_DATA_XFER; - outl( 0, ioport+TRM_S1040_DMA_XHIGHADDR); - outl( ( pSRB->SRBSGPhyAddr + ((DWORD)pSRB->SRBSGIndex << 3) ), ioport+TRM_S1040_DMA_XLOWADDR); + pSRB->SRBState |= SRB_DATA_XFER; + DC395x_write32(TRM_S1040_DMA_XHIGHADDR, 0); + DC395x_write32(TRM_S1040_DMA_XLOWADDR, pSRB->SRBSGBusAddr); /* load how many bytes in the Scatter/Gather list table */ - outl( ((DWORD) (pSRB->SRBSGCount - pSRB->SRBSGIndex) << 3), ioport+TRM_S1040_DMA_XCNT); + DC395x_write32(TRM_S1040_DMA_XCNT, ((DWORD) (pSRB->SRBSGCount - pSRB->SRBSGIndex) << 3)); /* load total transfer length (24bits) max value 16Mbyte */ - outl(pSRB->SRBTotalXferLength, ioport+TRM_S1040_SCSI_COUNTER); + DC395x_write32(TRM_S1040_SCSI_COUNTER, pSRB->SRBTotalXferLength); + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/ + if (ioDir == XFERDATAOUT) { + DC395x_write16(TRM_S1040_DMA_COMMAND, ioDir); + DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_OUT); + } + else + { + DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN); + DC395x_write16(TRM_S1040_DMA_COMMAND, ioDir); + } +#if 0 + /* SCSI command */ + bval = (ioDir == XFERDATAOUT) ? SCMD_DMA_OUT : SCMD_DMA_IN; /* Start DMA transfer */ - outw(ioDir, ioport+TRM_S1040_DMA_COMMAND); - /* outw(STARTDMAXFER, ioport+TRM_S1040_DMA_CONTROL);*/ + DC395x_write16(TRM_S1040_DMA_COMMAND, ioDir); /* Start SCSI transfer */ - outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ - /* - ** SCSI cammand - */ - bval = (ioDir == XFERDATAOUT) ? SCMD_DMA_OUT : SCMD_DMA_IN; - outb(bval, ioport+TRM_S1040_SCSI_COMMAND); + DC395x_write8(TRM_S1040_SCSI_COMMAND, bval); + //DC395x_data1_timer (pSRB, HZ*2); +#endif } else /* xfer pad */ { @@ -2947,102 +3529,418 @@ pSRB->AdaptStatus = H_OVER_UNDER_RUN; pSRB->SRBStatus |= OVER_RUN; } - if (pDCB->SyncMode & WIDE_NEGO_ENABLE) - outl(2,ioport+TRM_S1040_SCSI_COUNTER); + if (pDCB->SyncPeriod & WIDE_SYNC) + DC395x_write32(TRM_S1040_SCSI_COUNTER, 2); else - outl(1,ioport+TRM_S1040_SCSI_COUNTER); + DC395x_write32(TRM_S1040_SCSI_COUNTER, 1); + // KG: despite the fact that we are using 16 bits I/O ops + // the SCSI FIFO is only 8 bits according to the docs (which are probably wrong) if(ioDir == XFERDATAOUT) - outw(0, ioport+TRM_S1040_SCSI_FIFO); + DC395x_write16(TRM_S1040_SCSI_FIFO, 0); else - inw(ioport+TRM_S1040_SCSI_FIFO); + DC395x_read16(TRM_S1040_SCSI_FIFO); pSRB->SRBState |= SRB_XFERPAD; - outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/ /* - ** SCSI cammand + ** SCSI command */ bval = (ioDir == XFERDATAOUT) ? SCMD_FIFO_OUT : SCMD_FIFO_IN; - outb(bval, ioport+TRM_S1040_SCSI_COMMAND); + DC395x_write8(TRM_S1040_SCSI_COMMAND, bval); } } + //DC395x_monitor_next_IRQ = 2; + //printk (" done\n"); } /* ********************************************************************* ** scsiio -** DC395x_trm_StatusPhase0: one of DC395x_trm_SCSI_phase0[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** DC395x_StatusPhase0: one of DC395x_SCSI_phase0[] vectors +** DC395x_stateV = (void *) DC395x_SCSI_phase0[phase] ** if phase =3 ** ** ********************************************************************* */ -static void DC395x_trm_StatusPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +static void DC395x_StatusPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) { - WORD ioport; - -#ifdef DC395x_trm_DEBUG0 - printk(KERN_INFO "DC395x_StatusPhase0..... "); +#ifdef DC395x_DEBUG0 + printk(KERN_INFO "DC395x: StatusPhase0 (pid %li)\n", pSRB->pcmd->pid); #endif - ioport = pACB->IOPortBase; - - pSRB->TargetStatus = inb(ioport+TRM_S1040_SCSI_FIFO); - pSRB->EndMessage = inb(ioport+TRM_S1040_SCSI_FIFO); /* get message */ + 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*/ - outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/ /* - ** SCSI cammand + ** SCSI command */ - outb(SCMD_MSGACCEPT, ioport+TRM_S1040_SCSI_COMMAND); + DC395x_write8(TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT); } /* ********************************************************************* ** scsiio -** DC395x_trm_StatusPhase1: one of DC395x_trm_SCSI_phase1[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** DC395x_StatusPhase1: one of DC395x_SCSI_phase1[] vectors +** DC395x_stateV = (void *) DC395x_SCSI_phase1[phase] ** if phase =3 ** ** ********************************************************************* */ -static void DC395x_trm_StatusPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +static void DC395x_StatusPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) { - WORD ioport; +#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); -#ifdef DC395x_trm_DEBUG0 - printk(KERN_INFO "DC395x_StatusPhase1..............\n "); + 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 - ioport = pACB->IOPortBase; - if (inw(ioport+TRM_S1040_DMA_COMMAND) & 0x0001) - { - if (!(inb(ioport+TRM_S1040_SCSI_FIFOCNT) & 0x40)) - outw(DO_CLRFIFO, ioport+TRM_S1040_SCSI_CONTROL); - if (!(inw(ioport+TRM_S1040_DMA_FIFOCNT) & 0x8000)) - outb(CLRXFIFO, ioport+TRM_S1040_DMA_CONTROL); - } - else - { - if (!(inw(ioport+TRM_S1040_DMA_FIFOCNT) & 0x8000)) - outb(CLRXFIFO, ioport+TRM_S1040_DMA_CONTROL); +/* 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: SDTR got rejected from target %02i\n", + pDCB->TargetID); + 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 %i: 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; - if (!(inb(ioport+TRM_S1040_SCSI_FIFOCNT) & 0x40)) - outw(DO_CLRFIFO, ioport+TRM_S1040_SCSI_CONTROL); + printk (KERN_INFO "DC395x: Target %i: %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); + + 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 + 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");) } - pSRB->SRBState = SRB_STATUS; - outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ - /* - ** SCSI cammand - */ - outb(SCMD_COMP, ioport+TRM_S1040_SCSI_COMMAND); } + +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 %i 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; + //pDCB->SyncMode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); +#ifdef DC395x_DEBUG_KG + printk ("DC395x: Wide transfers (%i bit) negotiated with target %i\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 ) + { + pSRB->SGcount = (UCHAR) 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; + + 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 = (PUCHAR) 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_trm_MsgInPhase0: one of DC395x_trm_SCSI_phase0[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase0[phase] +** DC395x_MsgInPhase0: one of DC395x_SCSI_phase0[] vectors +** DC395x_stateV = (void *) DC395x_SCSI_phase0[phase] ** if phase =7 ** ** extended message codes: @@ -3058,352 +3956,198 @@ ** ********************************************************************* */ -static void DC395x_trm_MsgInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +void DC395x_MsgInPhase0( PACB pACB, PSRB pSRB, PWORD pscsi_status) { - BYTE message_in_code,bIndex,message_in_tag_id; - WORD ioport; PDCB pDCB; - PSRB pSRBTemp; -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_MsgInPhase0..............\n "); #endif - ioport = pACB->IOPortBase; + TRACEPRINTF("MIP0*"); pDCB = pACB->pActiveDCB; - - message_in_code = inb( ioport+TRM_S1040_SCSI_FIFO ); - if( !(pSRB->SRBState & SRB_EXTEND_MSGIN) ) - { - if(message_in_code == MSG_DISCONNECT) - { - pSRB->SRBState = SRB_DISCONNECT; - goto min6; - } - else if( message_in_code == MSG_SAVE_PTR ) - { - goto min6; - } - else if( (message_in_code == MSG_EXTENDED) || ((message_in_code >= MSG_SIMPLE_QTAG) && (message_in_code <= MSG_ORDER_QTAG)) ) - { - pSRB->SRBState |= SRB_EXTEND_MSGIN; - pSRB->MsgInBuf[0] = message_in_code;/* extended message (01h)*/ - pSRB->MsgCnt = 1; - pSRB->pMsgPtr = &pSRB->MsgInBuf[1]; /* extended message length (n)*/ - goto min6; - } - else if(message_in_code == MSG_REJECT_) - { - /* Reject message */ - if (pDCB->SyncMode & WIDE_NEGO_ENABLE) - { /* do wide nego reject */ - pDCB = pSRB->pSRBDCB; - pDCB->SyncMode |= WIDE_NEGO_DONE; - pDCB->SyncMode &= ~(SYNC_NEGO_DONE | EN_ATN_STOP | WIDE_NEGO_ENABLE ); - pSRB->SRBState &= ~(SRB_DO_WIDE_NEGO+SRB_MSGIN); - if ((pDCB->SyncMode & SYNC_NEGO_ENABLE) && !(pDCB->SyncMode & SYNC_NEGO_DONE)) - { - /* Set ATN, in case ATN was clear */ - pSRB->SRBState |= SRB_MSGOUT; - outw(DO_SETATN,ioport+TRM_S1040_SCSI_CONTROL); - } - else - { - /* Clear ATN */ - outw(DO_CLRATN,ioport+TRM_S1040_SCSI_CONTROL); - } - } - else if(pDCB->SyncMode & SYNC_NEGO_ENABLE) - { - /* do sync nego reject */ - outw(DO_CLRATN,ioport+TRM_S1040_SCSI_CONTROL); - if( pSRB->SRBState & SRB_DO_SYNC_NEGO ) - { - pDCB = pSRB->pSRBDCB; - pDCB->SyncMode &= ~(SYNC_NEGO_ENABLE+SYNC_NEGO_DONE); - pDCB->SyncPeriod = 0; - pDCB->SyncOffset = 0; - goto re_prog; - } - } - goto min6; - } - else if(message_in_code == MSG_IGNOREWIDE) - { - outl(1,ioport+TRM_S1040_SCSI_COUNTER); - inb(ioport+TRM_S1040_SCSI_FIFO); - goto min6; - } - else - { - /* Restore data pointer message */ - /* Save data pointer message */ - /* Completion message */ - /* NOP message */ - goto min6; - } - } - else /* when extend message in:pSRB->SRBState = SRB_EXTEND_MSGIN */ - { - /* - ** Parsing incoming extented messages - */ - *pSRB->pMsgPtr = message_in_code; - pSRB->MsgCnt++; - pSRB->pMsgPtr++; -#ifdef DC395x_trm_DEBUG0 - printk(KERN_INFO "pSRB->MsgInBuf: %02x %02x %02x %02x %02x %02x\n ", - pSRB->MsgInBuf[0], pSRB->MsgInBuf[1], pSRB->MsgInBuf[2], - pSRB->MsgInBuf[3], pSRB->MsgInBuf[4], pSRB->MsgInBuf[5]); -#endif - if( (pSRB->MsgInBuf[0] >= MSG_SIMPLE_QTAG) && (pSRB->MsgInBuf[0] <= MSG_ORDER_QTAG) ) - { - /* - ** is QUEUE tag message : - ** - ** byte 0: - ** HEAD QUEUE TAG (20h) - ** ORDERED QUEUE TAG (21h) - ** SIMPLE QUEUE TAG (22h) - ** byte 1: - ** Queue tag (00h - FFh) - */ - if (pSRB->MsgCnt == 2) - { - pSRB->SRBState = 0; - message_in_tag_id = pSRB->MsgInBuf[1]; - pSRB = pDCB->pGoingSRB; - pSRBTemp = pDCB->pGoingLastSRB; - if( pSRB ) - { - for( ;; ) - { - if(pSRB->TagNumber != message_in_tag_id) - { - if( pSRB == pSRBTemp ) - goto mingx0; - - pSRB = pSRB->pNextSRB; - } - else - break; - } - if( pDCB->DCBFlag & ABORT_DEV_ ) - { - pSRB->SRBState = SRB_ABORT_SENT; - DC395x_trm_EnableMsgOutAbort1( pACB, pSRB ); - } - if( !(pSRB->SRBState & SRB_DISCONNECT) ) - goto mingx0; + 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); - pDCB->pActiveSRB = pSRB; - pSRB->SRBState = SRB_DATA_XFER; - } - else - { - mingx0: - pSRB = pACB->pTmpSRB; - pSRB->SRBState = SRB_UNEXPECT_RESEL; - pDCB->pActiveSRB = pSRB; - pSRB->MsgOutBuf[0] = MSG_ABORT_TAG; - DC395x_trm_EnableMsgOutAbort2( pACB, pSRB ); - } - } - } - else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgInBuf[2] == EXTENDED_WDTR) && (pSRB->MsgCnt == 2+pSRB->MsgInBuf[1])) - { - /* - ** is Wide data xfer Extended message : - ** ====================================== - ** WIDE DATA TRANSFER REQUEST - ** ====================================== - ** byte 0 : Extended message (01h) - ** byte 1 : Extended message length (02h) - ** byte 2 : WIDE DATA TRANSFER code (03h) - ** byte 3 : Transfer width exponent - */ - pDCB = pSRB->pSRBDCB; - pSRB->SRBState &= ~(SRB_EXTEND_MSGIN+SRB_DO_WIDE_NEGO); - if( (pSRB->MsgInBuf[1] != 2) ) + /* 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) { - /* Length is wrong, reject it */ - pDCB->SyncMode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); - pSRB->MsgCnt = 1; - pSRB->MsgInBuf[0] = MSG_REJECT_; - outw(DO_SETATN, ioport+TRM_S1040_SCSI_CONTROL); - goto min6; - } - if (pDCB->SyncMode & WIDE_NEGO_ENABLE) - { - /* Do wide negoniation */ - if (pSRB->MsgInBuf[3] > 2) /* > 32 bit */ - { - /* reject_msg: */ - pDCB->SyncMode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); - pSRB->MsgCnt = 1; - pSRB->MsgInBuf[0] = MSG_REJECT_; - outw(DO_SETATN, ioport+TRM_S1040_SCSI_CONTROL); - goto min6; - } - if (pSRB->MsgInBuf[3] == 2) /* == 32 bit */ - pSRB->MsgInBuf[3] = 1; /* do 16 bits */ - else - { - if (!(pDCB->SyncMode & WIDE_NEGO_DONE)) - { - pSRB->SRBState &= ~(SRB_DO_WIDE_NEGO+SRB_MSGIN); - pDCB->SyncMode |= WIDE_NEGO_DONE; - pDCB->SyncMode &= ~(SYNC_NEGO_DONE | EN_ATN_STOP | WIDE_NEGO_ENABLE ); - printk ("DC395x: Target %02i: Wide %i transfer negotiated\n", - pDCB->TargetID, 8<MsgInBuf[3]); - - if (pSRB->MsgInBuf[3] != 0) - { - /* is Wide data xfer */ - pDCB->SyncPeriod |= WIDE_SYNC; - } - } - } + DC395x_MsgIn_set_async (pACB, pSRB); + break; } - else - pSRB->MsgInBuf[3] = 0; - - pSRB->SRBState |= SRB_MSGOUT; - outw( DO_SETATN,ioport+TRM_S1040_SCSI_CONTROL ); - goto min6; - } - else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgInBuf[2] == EXTENDED_SDTR) && (pSRB->MsgCnt == 2+pSRB->MsgInBuf[1]) ) - { - /* - ** is 8bit transfer Extended message : - ** ================================= - ** SYNCHRONOUS DATA TRANSFER REQUEST - ** ================================= - ** byte 0 : Extended message (01h) - ** byte 1 : Extended message length (03) - ** byte 2 : SYNCHRONOUS DATA TRANSFER code (01h) - ** byte 3 : Transfer period factor - ** byte 4 : REQ/ACK offset - */ - pSRB->SRBState &= ~(SRB_EXTEND_MSGIN+SRB_DO_SYNC_NEGO); - if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != 1) ) - { /* reject_msg: */ - pSRB->MsgCnt = 1; - pSRB->MsgInBuf[0] = MSG_REJECT_; - outw(DO_SETATN, ioport+TRM_S1040_SCSI_CONTROL); + /* A wide nego message was rejected ! */ + if (pSRB->SRBState & SRB_DO_WIDE_NEGO) + { + DC395x_MsgIn_set_nowide (pACB, pSRB); + break; } - else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) ) + 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) { - /*set_async*/ - pDCB = pSRB->pSRBDCB; - pDCB->SyncMode &= ~(SYNC_NEGO_ENABLE+SYNC_NEGO_DONE); - pDCB->SyncPeriod = 0; - pDCB->SyncOffset = 0; - goto re_prog; - } - else + DC395x_MsgIn_set_sync (pACB, pSRB); + break; + }; + /* WDTR */ + if (pSRB->MsgInBuf[1] == 2 && pSRB->MsgInBuf[2] == EXTENDED_WDTR + && pSRB->MsgInBuf[3] <= 2) // sanity check ... { - /* set_sync */ - pDCB = pSRB->pSRBDCB; - pDCB->SyncMode |= SYNC_NEGO_ENABLE+SYNC_NEGO_DONE; - pDCB->MinNegoPeriod = pSRB->MsgInBuf[3];/* Transfer period factor */ - pDCB->SyncOffset = pSRB->MsgInBuf[4]; /* REQ/ACK offset */ - for (bIndex = 0; bIndex < 7; bIndex++) - { - if (pSRB->MsgInBuf[3] <= dc395x_trm_clock_period[bIndex]) - break; - } - pDCB->SyncPeriod |= (bIndex | ALT_SYNC); -re_prog: - /* - ** Update period & offset register - */ - outb(pDCB->SyncPeriod, ioport+TRM_S1040_SCSI_SYNC); - outb(pDCB->SyncOffset, ioport+TRM_S1040_SCSI_OFFSET); - printk ("DC395x: Target %02i: Sync transfer %i ns, Offset %i\n", - pDCB->TargetID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]); - DC395x_trm_SetXferRate( pACB, pDCB); - } - } - } -min6: - *pscsi_status = PH_BUS_FREE;/*.. initial phase*/ - outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ - /* - ** SCSI cammand - */ - outb(SCMD_MSGACCEPT, ioport+TRM_S1040_SCSI_COMMAND); + DC395x_MsgIn_set_wide (pACB, pSRB); + break; + }; + DC395x_MsgIn_reject (pACB, pSRB); + break; + + // Discard wide residual + case MSG_IGNOREWIDE: + printk ("DC395x: Ignore Wide Residual!\n"); + DC395x_write32 (TRM_S1040_SCSI_COUNTER, 1); + DC395x_read8 (TRM_S1040_SCSI_FIFO); + break; + + // nothing has to be done + case COMMAND_COMPLETE: break; + + // SAVE POINTER may be ignored as we have the PSRB associated with the + // scsi command. Thanks, Gérard, for pointing it out. + case SAVE_POINTERS: +#ifdef DC395x_DEBUG0 + printk ("DC395x: SAVE POINTER message received (pid %li: rem.%i) ... ignore :-(\n", + pSRB->pcmd->pid, pSRB->SRBTotalXferLength); +#endif + //pSRB->Saved_Ptr = pSRB->TotalXferredLen; + break; + // The device might want to restart transfer with a RESTORE + case RESTORE_POINTERS: + printk ("DC395x: RESTORE POINTER message received ... ignore :-(\n"); + //dc395x_restore_ptr (pACB, pSRB); + break; + case ABORT: + printk ("DC395x: ABORT msg received (pid %li %02i-%i)\n", + pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN); + pDCB->DCBFlag |= ABORT_DEV_; + DC395x_EnableMsgOut_Abort (pACB, pSRB); + break; + // reject unknown messages + default: + if (pSRB->MsgInBuf[0] & IDENTIFY_BASE) + { + printk ("DC395x: Identify Message received?\n"); + //TRACEOUT (" %s\n", pSRB->debugtrace); + pSRB->MsgCnt = 1; pSRB->MsgOutBuf[0] = pDCB->IdentifyMsg; + DC395x_ENABLE_MSGOUT; pSRB->SRBState |= SRB_MSGOUT; + //break; + } + DC395x_MsgIn_reject (pACB, pSRB); + TRACEOUT (" %s\n", pSRB->debugtrace); + } + TRACEPRINTF (".*"); + + /* Clear counter and MsgIn state */ + pSRB->SRBState &= ~SRB_MSGIN; + pACB->MsgLen = 0; + }; + + if ((*pscsi_status & PHASEMASK) != PH_MSG_IN) + DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + *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_trm_MsgInPhase1: one of DC395x_trm_SCSI_phase1[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** DC395x_MsgInPhase1: one of DC395x_SCSI_phase1[] vectors +** DC395x_stateV = (void *) DC395x_SCSI_phase1[phase] ** if phase =7 ** ** ********************************************************************* */ -static void DC395x_trm_MsgInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +static void DC395x_MsgInPhase1( PACB pACB, PSRB pSRB, PWORD pscsi_status) { - - WORD ioport; - -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_MsgInPhase1..............\n "); #endif - ioport = pACB->IOPortBase; - outw(DO_CLRFIFO, ioport+TRM_S1040_SCSI_CONTROL); - outl(1,ioport+TRM_S1040_SCSI_COUNTER); + TRACEPRINTF("MIP1 *"); + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + DC395x_write32(TRM_S1040_SCSI_COUNTER, 1); if( !(pSRB->SRBState & SRB_MSGIN) ) { - pSRB->SRBState &= SRB_DISCONNECT; + pSRB->SRBState &= ~SRB_DISCONNECT; pSRB->SRBState |= SRB_MSGIN; } - outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop */ /* - ** SCSI cammand + ** SCSI command */ - outb(SCMD_FIFO_IN, ioport+TRM_S1040_SCSI_COMMAND); + DC395x_write8(TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN); } /* ********************************************************************* ** scsiio -** DC395x_trm_Nop0: one of DC395x_trm_SCSI_phase1[] ,DC395x_trm_SCSI_phase0[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase0[phase] -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** 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_trm_Nop0( PACB pACB, PSRB pSRB, PWORD pscsi_status) +DC395x_Nop0( PACB pACB, PSRB pSRB, PWORD pscsi_status) { + //TRACEPRINTF("NOP0 *"); } /* ********************************************************************* ** scsiio -** DC395x_trm_Nop1: one of DC395x_trm_SCSI_phase0[] ,DC395x_trm_SCSI_phase1[] vectors -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase0[phase] -** DC395x_trm_stateV = (void *) DC395x_trm_SCSI_phase1[phase] +** 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_trm_Nop1( PACB pACB, PSRB pSRB, PWORD pscsi_status) +static void DC395x_Nop1( PACB pACB, PSRB pSRB, PWORD pscsi_status) { + //TRACEPRINTF("NOP1 *"); } /* ********************************************************************* ** scsiio -** DC395x_trm_MsgInPhase0 +** DC395x_MsgInPhase0 ** ********************************************************************* */ -static void DC395x_trm_SetXferRate( PACB pACB, PDCB pDCB ) +static void DC395x_SetXferRate( PACB pACB, PDCB pDCB ) { BYTE bval; WORD cnt, i; @@ -3415,11 +4159,11 @@ if( !(pDCB->IdentifyMsg & 0x07) ) { if( pACB->scan_devices ) - DC395x_TRM_CurrSyncOffset = pDCB->SyncOffset; + DC395x_CurrSyncOffset = pDCB->SyncOffset; else { pDCBTemp = pACB->pLinkDCB; - cnt = pACB->DeviceCnt; + cnt = pACB->DCBCnt; bval = pDCB->TargetID; for(i=0; ipActiveDCB->pActiveSRB->pcmd->pid); #endif - ioport = pACB->IOPortBase; pDCB = pACB->pActiveDCB; if (!pDCB) { - printk(KERN_ERR "Exception Disconnect pDCB=NULL !!\n "); - j = 400; - while (--j) udelay(1000); - outw((DO_CLRFIFO | DO_HWRESELECT),ioport+TRM_S1040_SCSI_CONTROL); + printk(KERN_ERR "DC395x: Disc: Exception Disconnect pDCB=NULL !!\n "); + udelay (1000); + // Suspend queue for a while + pACB->pScsiHost->last_reset = jiffies + 3 * HZ; + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRFIFO | DO_HWRESELECT); return; } pSRB = pDCB->pActiveSRB; + TRACEPRINTF("DISC *"); pACB->pActiveDCB = 0; pSRB->ScsiPhase = PH_BUS_FREE;/* initial phase */ - outw((DO_CLRFIFO | DO_HWRESELECT),ioport+TRM_S1040_SCSI_CONTROL); + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRFIFO | DO_HWRESELECT); if( pSRB->SRBState & SRB_UNEXPECT_RESEL ) { - printk(KERN_ERR "DC395x: Unexpected Reselection (%i-%i)\n", pDCB->TargetID, pDCB->TargetLUN); + printk(KERN_ERR "DC395x: Disc: Unexpected Reselection (%i-%i)\n", pDCB->TargetID, pDCB->TargetLUN); pSRB->SRBState = 0; - DC395x_trm_DoWaitingSRB( pACB ); + DC395x_Waiting_process ( pACB ); } else if( pSRB->SRBState & SRB_ABORT_SENT ) - { - printk(KERN_ERR "DC395x: SRB_ABORT_SENT\n"); - pDCB->TagMask = 0; - pDCB->DCBFlag = 0; - count= pDCB->GoingSRBCnt; - pDCB->GoingSRBCnt = 0; - pSRB = pDCB->pGoingSRB; - for( i=0; i < count ; i++) - { - pSRBTemp = pSRB->pNextSRB; - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; - pSRB = pSRBTemp; - } - pDCB->pGoingSRB = 0; - DC395x_trm_DoWaitingSRB( pACB ); + { + //PSCSICMD pcmd = pSRB->pcmd; + pDCB->DCBFlag &= ~ABORT_DEV_; + 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 { @@ -3498,33 +4234,55 @@ { /* ** Selection time out - ** - ** SRB_START_ - ** SRB_MSGOUT - ** !SRB_DISCONNECT - ** !SRB_COMPLETED + ** SRB_START_ || SRB_MSGOUT || (!SRB_DISCONNECT && !SRB_COMPLETED) */ - if( !(1/*pACB->scan_devices*/) ) + /* Normal Sel Timeout */ + if (pSRB->SRBState != SRB_START_ && pSRB->SRBState != SRB_MSGOUT) { pSRB->SRBState = SRB_READY; - DC395x_trm_RewaitSRB( pDCB, pSRB); + 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 { - pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT; -#ifdef DC395x_trm_DEBUG_KG - printk (KERN_INFO "DC395x: Selection Timeout (pid %li, target %i-%i)\n", - pSRB->pcmd->pid, pSRB->pcmd->target, pSRB->pcmd->lun); -#endif - goto disc1; + /* Normal selection timeout */ + TRACEPRINTF("SlTO *"); + //printk ("DC395x: Disc: Move SRB (pid=%li) to Waiting\n", pSRB->pcmd->pid); + 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); + DC395x_waiting_timer (pACB, HZ/5); } } else if( pSRB->SRBState & SRB_DISCONNECT ) { + BYTE bval = DC395x_read8 (TRM_S1040_SCSI_SIGNAL); /* - ** SRB_DISCONNECT + ** SRB_DISCONNECT (This is what we expect!) */ - DC395x_trm_DoWaitingSRB( pACB ); + // printk ("DC395x: DoWaitingSRB (pid=%li)\n", pSRB->pcmd->pid); + TRACEPRINTF("+*"); + if (bval & 0x40) + { + printk ("DC395x: Degug: DISC: SCSI bus stat %02x: ACK set! SYNC trouble?\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 ) { @@ -3532,12 +4290,11 @@ /* ** SRB_COMPLETED */ - if(pDCB->MaxCommand > 1) - pDCB->TagMask &= (~(1 << pSRB->TagNumber)); /* free tag mask */ - + DC395x_freetag (pDCB, pSRB); pDCB->pActiveSRB = 0; pSRB->SRBState = SRB_FREE; - DC395x_trm_SRBdone( pACB, pDCB, pSRB); + //printk ("DC395x: done (pid=%li)\n", pSRB->pcmd->pid); + DC395x_SRBdone( pACB, pDCB, pSRB); } } return; @@ -3546,118 +4303,249 @@ /* ********************************************************************* ** scsiio -** DC395x_trm_Reselect +** DC395x_Reselect ** ********************************************************************* */ -static void DC395x_trm_Reselect( PACB pACB ) +void DC395x_Reselect( PACB pACB ) { PDCB pDCB; - PSRB pSRB; - WORD ioport,RselTarLunId; + PSRB pSRB = 0; + WORD RselTarLunId; + BYTE id, lun; + BYTE arblostflag = 0; -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_Reselect..............\n "); #endif - ioport = pACB->IOPortBase; + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + //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 ) ) { - printk(KERN_INFO "Arbitration lost but Reselection win..............\n "); + DEBUG0(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));) + TRACEPRINTF ("ArbLResel!*"); + //TRACEOUT (" %s\n", pSRB->debugtrace); + arblostflag = 1; + //pSRB->SRBState |= SRB_DISCONNECT; + pSRB->SRBState = SRB_READY; - DC395x_trm_RewaitSRB( pDCB, pSRB); + DC395x_freetag (pDCB, pSRB); + DC395x_Going_to_Waiting (pDCB, pSRB); + DC395x_waiting_timer (pACB, HZ/5); + + // return; } } /* Read Reselected Target Id and LUN */ - RselTarLunId = inw(ioport+TRM_S1040_SCSI_TARGETID) & 0x1FFF; - pDCB = pACB->pLinkDCB; - while( RselTarLunId != *((PWORD) &pDCB->TargetID) ) - { - /* get pDCB of the reselect id */ - pDCB = pDCB->pNextDCB; - if( pDCB == pACB->pLinkDCB ) - return; - + 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->SyncMode & EN_TAG_QUEUEING ) + + 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 */ - pSRB= pACB->pTmpSRB; + 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_trm_EnableMsgOutAbort1( pACB, pSRB ); + DC395x_EnableMsgOut_Abort( pACB, pSRB ); } else { if( pDCB->DCBFlag & ABORT_DEV_ ) - { - pSRB->SRBState = SRB_ABORT_SENT; - DC395x_trm_EnableMsgOutAbort1( pACB, pSRB ); + { + //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 *********************************************** - */ - outb((BYTE) RselTarLunId,ioport+TRM_S1040_SCSI_TARGETID); /* target ID */ - outb( pACB->AdaptSCSIID,ioport+TRM_S1040_SCSI_HOSTID); /* host ID */ - outb( pDCB->SyncPeriod,ioport+TRM_S1040_SCSI_SYNC); /* period */ - outb( pDCB->SyncOffset,ioport+TRM_S1040_SCSI_OFFSET); /* offset */ - outw(DO_DATALATCH, ioport+TRM_S1040_SCSI_CONTROL);/* it's important for atn stop*/ - /* - ** SCSI cammand */ - outb( SCMD_MSGACCEPT, ioport+TRM_S1040_SCSI_COMMAND); + 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; + kfree (pDCB); + pACB->DCBCnt--; + /* pACB->DeviceCnt--; */ +}; + + +static inline BYTE +DC395x_tagq_blacklist (char* name) +{ +#ifndef DC395x_NO_TAGQ +#if 0 + BYTE i; + for(i=0; iVers & 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_trm_Disconnected +** DC395x_Disconnected ** Complete execution of a SCSI command ** Signal completion to the generic SCSI driver ** ********************************************************************* */ -static void DC395x_trm_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) +void DC395x_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) { - PSRB pSRBTemp; - BYTE tempcnt,status; + BYTE tempcnt,status,DCB_removed=0; PSCSICMD pcmd; PSCSI_INQDATA ptr; //DWORD drv_flags=0; pcmd = pSRB->pcmd; -#ifdef DC395x_trm_DEBUG_KG - printk(KERN_INFO "DC395x_SRBdone (pid %li, target %i-%i): ", +#ifdef DC395x_DEBUG_KG + printk(KERN_INFO "DC395x: SRBdone (pid %li, target %i-%i): ", pSRB->pcmd->pid, pSRB->pcmd->target, pSRB->pcmd->lun); #endif + TRACEPRINTF("DONE *"); + status = pSRB->TargetStatus; if(pSRB->SRBFlag & AUTO_REQSENSE) { -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "AUTO_REQSENSE1..............\n "); #endif /* @@ -3665,45 +4553,67 @@ */ pSRB->SRBFlag &= ~AUTO_REQSENSE; pSRB->AdaptStatus = 0; - pSRB->TargetStatus = SCSI_STAT_CHECKCOND; - if(status == SCSI_STAT_CHECKCOND) + pSRB->TargetStatus = CHECK_CONDITION << 1; +#ifdef DC395x_DEBUG_KG + switch (pcmd->sense_buffer[2] & 0x0f) + { + case NOT_READY: printk (KERN_INFO "\nDC395x: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, + status, pACB->scan_devices); break; + case UNIT_ATTENTION: printk (KERN_INFO "\nDC395x: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, + status, pACB->scan_devices); break; + case ILLEGAL_REQUEST: printk (KERN_INFO "\nDC395x: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, + status, pACB->scan_devices); break; + case MEDIUM_ERROR: printk (KERN_INFO "\nDC395x: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, + status, pACB->scan_devices); break; + case HARDWARE_ERROR: printk (KERN_INFO "\nDC395x: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, + status, pACB->scan_devices); break; + } +#endif + if (status == (CHECK_CONDITION << 1)) { pcmd->result = DID_BAD_TARGET << 16; goto ckc_e; } -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "AUTO_REQSENSE2..............\n "); #endif - *((PDWORD) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; - *((PDWORD) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1]; - pSRB->SRBTotalXferLength = pSRB->Segment1[1]; + pSRB->SRBTotalXferLength = pSRB->Xferred; pSRB->SegmentX[0].address = pSRB->SgSenseTemp.address; pSRB->SegmentX[0].length = pSRB->SgSenseTemp.length; if( (pSRB->SRBTotalXferLength) && (pSRB->SRBTotalXferLength >= pcmd->underflow) ) - pcmd->result |= (DID_OK << 16); + pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION); + //SET_RES_DID(pcmd->result,DID_OK) else - pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) | SCSI_STAT_CHECKCOND; - + pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION); + goto ckc_e; } + //*********************************************************** if( status ) { /* ** target status.......................... */ - if (status == SCSI_STAT_CHECKCOND) + if( status_byte(status) == CHECK_CONDITION ) { - DC395x_trm_RequestSense( pACB, pDCB, pSRB ); + DC395x_RequestSense( pACB, pDCB, pSRB ); return; } - else if( status == SCSI_STAT_QUEUEFULL ) + else if( status_byte(status) == QUEUE_FULL ) { tempcnt = (BYTE) pDCB->GoingSRBCnt; tempcnt--; pDCB->MaxCommand = tempcnt; - DC395x_trm_RewaitSRB( pDCB, pSRB ); + DC395x_freetag (pDCB, pSRB); + DC395x_Going_to_Waiting ( pDCB, pSRB ); + DC395x_waiting_timer (pACB, HZ/5); pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; return; @@ -3714,10 +4624,20 @@ pSRB->TargetStatus = 0; pcmd->result = DID_NO_CONNECT << 16; } + else if (status_byte(status) == BUSY && + (pSRB->pcmd->cmnd[0] == TEST_UNIT_READY || pSRB->pcmd->cmnd[0] == INQUIRY) && + pACB->scan_devices) + { + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = status; + pcmd->result = MK_RES(0,0,pSRB->EndMessage,/*status*/0); + } else { pSRB->AdaptStatus = 0; - pcmd->result |= (DID_ERROR << 16) | (DWORD) (pSRB->EndMessage << 8) | (DWORD) status; + SET_RES_DID(pcmd->result,DID_ERROR); + SET_RES_MSG(pcmd->result,pSRB->EndMessage); + SET_RES_TARGET(pcmd->result,status); } } else @@ -3729,226 +4649,287 @@ if(status & H_OVER_UNDER_RUN) { pSRB->TargetStatus = 0; - pcmd->result |= (DID_OK << 16) | (pSRB->EndMessage << 8); + SET_RES_DID(pcmd->result,DID_OK); + SET_RES_MSG(pcmd->result,pSRB->EndMessage); } else if( pSRB->SRBStatus & PARITY_ERROR) { - pcmd->result |= (DID_PARITY << 16) | (pSRB->EndMessage << 8); + SET_RES_DID(pcmd->result,DID_PARITY); + SET_RES_MSG(pcmd->result,pSRB->EndMessage); } else /* No error */ { pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; - pcmd->result |= (DID_OK << 16); + SET_RES_DID(pcmd->result,DID_OK); } } ckc_e: if( pACB->scan_devices ) { - if( pSRB->CmdBlock[0] == TEST_UNIT_READY ) + if( pSRB->pcmd->cmnd[0] == TEST_UNIT_READY ) { - 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 ) +#ifdef DC395x_DEBUG0 + printk (KERN_INFO "\nDC395x: Test_Unit_Ready: result: %08x", 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 ) { - pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun); - DC395x_TRM_pPrevDCB->pNextDCB = pACB->pLinkDCB; - if( (pcmd->target == pACB->max_id) && ((pcmd->lun == 0) || (pcmd->lun == pACB->max_lun)) ) - pACB->scan_devices = 0; + /* 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 { - DC395x_TRM_pPrevDCB->pNextDCB = pDCB; - pDCB->pNextDCB = pACB->pLinkDCB; - if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) ) - pACB->scan_devices = DC395x_trm_END_SCAN; + /* 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 */ } } - else if( pSRB->CmdBlock[0] == INQUIRY ) - { - if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) ) - pACB->scan_devices = 0; - - ptr = (PSCSI_INQDATA) (pcmd->request_buffer); - if( pcmd->use_sg ) - ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); - if( (ptr->DevType & SCSI_DEVTYPE) == SCSI_NODEV ) - { - pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun); - DC395x_TRM_pPrevDCB->pNextDCB = pACB->pLinkDCB; - } - else - { - pACB->DeviceCnt++; - DC395x_TRM_pPrevDCB = pDCB; - //printk (KERN_INFO "DC395x: pDCB_free: %p", pACB->pDCB_free); - pACB->pDCB_free += 1; - //printk (" -> %p\n", pACB->pDCB_free); - pDCB->DevType = ptr->DevType & SCSI_DEVTYPE; -#ifndef DC395x_NO_TAGQ - if( (pDCB->DevType == TYPE_DISK) || (pDCB->DevType == TYPE_MOD) ) - { - if( ( ((ptr->Vers & 0x07) >= 2) || ((ptr->RDF & 0x0F) == 2) ) && - (ptr->Flags & SCSI_INQ_CMDQUEUE) && - (pDCB->DevMode & NTC_DO_TAG_QUEUEING) && - (pDCB->DevMode & NTC_DO_DISCONNECT) ) - { - pDCB->MaxCommand = 16; /* Fixed, KG 99/07/18 */ - pDCB->SyncMode |= EN_TAG_QUEUEING; - pDCB->TagMask = 0; - } - } -#endif - }/*bval1 == SCSI_NODEV*/ - }/*pSRB->CmdBlock[0] == INQUIRY*/ - }/* pACB->scan_devices */ - - //DC395x_TRM_DRV_LOCK(drv_flags); - - /* ReleaseSRB( pDCB, pSRB ); */ - if(pSRB == pDCB->pGoingSRB ) - { - /* - ** this SRB is Device's GoingSRB and say that - ** the last SRB had been done - ** you need point this SRB's next SRB to pDCB->pGoingSRB - ** (which SRB next time will be going) - */ - pDCB->pGoingSRB = pSRB->pNextSRB; - } - else - { - /* - ** this SRB had been done you need relink the SRB Q - ** before release this SRB - */ - pSRBTemp = pDCB->pGoingSRB; - while( pSRBTemp->pNextSRB != pSRB ) - pSRBTemp = pSRBTemp->pNextSRB; - - pSRBTemp->pNextSRB = pSRB->pNextSRB; - if( pSRB == pDCB->pGoingLastSRB ) - pDCB->pGoingLastSRB = pSRBTemp; - } - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; - pDCB->GoingSRBCnt--; - - //DC395x_TRM_DRV_UNLOCK(drv_flags); -#ifdef DC395x_trm_DEBUG_KG - printk ("0x%08x\n", pcmd->result); -#endif - - DC395x_trm_DoWaitingSRB( pACB ); - - /* Notify cmd done */ - //DC395x_TRM_SCSI_DONE_ACB_UNLOCK; - pcmd->scsi_done( pcmd ); - //DC395x_TRM_SCSI_DONE_ACB_LOCK; - - if( pDCB->QIORBCnt ) - DC395x_trm_DoNextCmd( pACB, pDCB ); + + //if( pSRB->pcmd->cmnd[0] == INQUIRY && + // (host_byte(pcmd->result) == DID_OK || status_byte(pcmd->result) & CHECK_CONDITION) ) + if( pSRB->pcmd->cmnd[0] == INQUIRY && + (pcmd->result == (DID_OK << 16) || status_byte(pcmd->result) & CHECK_CONDITION) ) + { + ptr = (PSCSI_INQDATA) (pcmd->request_buffer); + if( pcmd->use_sg ) + ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); + if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV) + { + /* 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; + }; + + if (!DCB_removed) DC395x_Going_remove (pDCB, pSRB); + /* Add to free list */ + DC395x_Free_insert (pACB, pSRB); + + DEBUG0(printk (KERN_DEBUG "DC395x: SRBdone: done pid %li\n", pcmd->pid);) +#ifdef DC395x_DEBUG_KG + printk ("0x%08x", pcmd->result); +#endif + TRACEPRINTF("%08x(%li)*", pcmd->result, jiffies); + //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_trm_reset -** +** DC395x_reset +** abort all cmds in our queues ********************************************************************* */ -static void DC395x_trm_DoingSRB_Done( PACB pACB ) +static void DC395x_DoingSRB_Done( PACB pACB, BYTE did_flag ) { - PDCB pDCB, pDCBTemp; - PSRB pSRBTemp, pSRBTemp2; - WORD cnt, i; + PDCB pDCB; + PSRB pSRB, pSRBTemp; + WORD cnt; PSCSICMD pcmd; - printk(KERN_INFO "DC395x_DoingSRB_Done: pids "); pDCB = pACB->pLinkDCB; if (!pDCB) return; - pDCBTemp = pDCB; + printk(KERN_INFO "DC395x_DoingSRB_Done: pids "); do { - cnt = pDCBTemp->GoingSRBCnt; - pSRBTemp = pDCBTemp->pGoingSRB; - for( i=0; ipWaitingSRB; + //PSRB pWaitLast = pDCB->pWaitLast; + WORD WaitSRBCnt = pDCB->WaitSRBCnt; + /* Going queue */ + cnt = pDCB->GoingSRBCnt; + pSRB = pDCB->pGoingSRB; + while (cnt--) { - pSRBTemp2 = pSRBTemp->pNextSRB; - pcmd = pSRBTemp->pcmd; - pcmd->result = DID_RESET << 16; - /* ReleaseSRB( pDCB, pSRB ); */ - pSRBTemp->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRBTemp; - printk ("%li(%i-%i) ", pcmd->pid, pcmd->target, pcmd->lun); - - //DC395x_TRM_SCSI_DONE_ACB_UNLOCK; + 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_Free_insert (pACB, pSRB); + DC395x_freetag (pDCB, pSRB); +#ifndef USE_NEW_EH + /* For new EH, don't give commands back */ + pcmd->result = result; + //DC395x_SCSI_DONE_ACB_UNLOCK; pcmd->scsi_done( pcmd ); - //DC395x_TRM_SCSI_DONE_ACB_LOCK; - - pSRBTemp = pSRBTemp2; + //DC395x_SCSI_DONE_ACB_LOCK; +#endif + pSRB = pSRBTemp; } - pDCBTemp->GoingSRBCnt = 0;; - pDCBTemp->pGoingSRB = NULL; - pDCBTemp->TagMask = 0; - pDCBTemp = pDCBTemp->pNextDCB; + 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; + 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( pDCBTemp != pDCB && pDCBTemp ); + while( pDCB != pACB->pLinkDCB && pDCB ); printk ("\n"); } /* ********************************************************************* ** scsiio -** DC395x_trm_shutdown DC395x_trm_reset +** DC395x_shutdown DC395x_reset ** ********************************************************************* */ -static void DC395x_trm_ResetSCSIBus( PACB pACB ) +static void DC395x_ResetSCSIBus( PACB pACB ) { - WORD ioport; //DWORD drv_flags=0; -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_ResetSCSIBus..............\n "); #endif - //DC395x_TRM_DRV_LOCK(drv_flags); + //DC395x_DRV_LOCK(drv_flags); pACB->ACBFlag |= RESET_DEV; /* RESET_DETECT, RESET_DONE, RESET_DEV */ - ioport = pACB->IOPortBase; - outw(DO_RSTSCSI,ioport+TRM_S1040_SCSI_CONTROL); - while (!( inw(ioport+TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET )); + DC395x_write16(TRM_S1040_SCSI_CONTROL,DO_RSTSCSI); + while (!( DC395x_read8(TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET )); - //DC395x_TRM_DRV_UNLOCK(drv_flags); + //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_trm_Interrupt +** DC395x_Interrupt ** ********************************************************************* */ -static void DC395x_trm_ScsiRstDetect( PACB pACB ) +static void DC395x_ScsiRstDetect( PACB pACB ) { - DWORD msec; - WORD ioport; - printk (KERN_INFO "DC395x_ScsiRstDetect\n"); /* delay half a second */ - { msec = 600; while (--msec) udelay(1000); } + if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); + //if (timer_pending (&pACB->Data_Timer)) del_timer (&pACB->Data_Timer); - ioport = pACB->IOPortBase; + DC395x_write8(TRM_S1040_SCSI_CONTROL, DO_RSTMODULE); + DC395x_write8(TRM_S1040_DMA_CONTROL, DMARESETMODULE); + //DC395x_write8(TRM_S1040_DMA_CONTROL,STOPDMAXFER); + udelay (1000); + // Maybe we locked up the bus? Then lets wait even longer ... + pACB->pScsiHost->last_reset = jiffies + HZ/2 + 6*HZ; - outb(STOPDMAXFER,ioport+TRM_S1040_DMA_CONTROL); + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); + DC395x_basic_config (pACB); - outw(DO_CLRFIFO,ioport+TRM_S1040_SCSI_CONTROL); - if( pACB->ACBFlag & RESET_DEV ) /* RESET_DETECT, RESET_DONE, RESET_DEV */ { pACB->ACBFlag |= RESET_DONE; @@ -3956,12 +4937,12 @@ else { pACB->ACBFlag |= RESET_DETECT; - DC395x_trm_ResetDevParam( pACB ); - DC395x_trm_DoingSRB_Done( pACB ); - DC395x_trm_RecoverSRB( pACB ); + DC395x_ResetDevParam( pACB ); + DC395x_DoingSRB_Done( pACB, DID_RESET ); + //DC395x_RecoverSRB( pACB ); pACB->pActiveDCB = NULL; pACB->ACBFlag = 0; - DC395x_trm_DoWaitingSRB( pACB ); + DC395x_Waiting_process( pACB ); } return; @@ -3970,130 +4951,127 @@ /* ********************************************************************* ** scsiio -** DC395x_trm_SRBdone +** DC395x_SRBdone ** ********************************************************************* */ -static void DC395x_trm_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ) +static void DC395x_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ) { PSCSICMD pcmd; pcmd = pSRB->pcmd; -#ifdef DC395x_trm_DEBUG_KG +#ifdef DC395x_DEBUG_KG printk(KERN_INFO "DC395x_RequestSense for pid %li, target %i-%i\n", pcmd->pid, pcmd->target, pcmd->lun); #endif + TRACEPRINTF ("RqSn*"); pSRB->SRBFlag |= AUTO_REQSENSE; - pSRB->Segment0[0] = *((PDWORD) &(pSRB->CmdBlock[0])); - pSRB->Segment0[1] = *((PDWORD) &(pSRB->CmdBlock[4])); - pSRB->Segment1[0] = (DWORD) ((pSRB->ScsiCmdLen << 8) + pSRB->SRBSGCount); - pSRB->Segment1[1] = pSRB->SRBTotalXferLength; /* ?????????? */ pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; - /* pSRB->SegmentX : a one entry of S/G list table */ - pSRB->SRBTotalXferLength = sizeof(pcmd->sense_buffer); + /* Save some data */ pSRB->SgSenseTemp.address = pSRB->SegmentX[0].address; pSRB->SgSenseTemp.length = pSRB->SegmentX[0].length; - pSRB->SegmentX[0].address = (DWORD) virt_to_phys (pcmd->sense_buffer); + pSRB->Xferred = pSRB->SRBTotalXferLength; + /* pSRB->SegmentX : a one entry of S/G list table */ + pSRB->SRBTotalXferLength = sizeof(pcmd->sense_buffer); + pSRB->SegmentX[0].address = (DWORD) virt_to_bus (pcmd->sense_buffer); pSRB->SegmentX[0].length = sizeof(pcmd->sense_buffer); pSRB->SRBSGListPointer = &pSRB->SegmentX[0]; pSRB->SRBSGCount = 1; pSRB->SRBSGIndex = 0; - pSRB->CmdBlock[0] = REQUEST_SENSE; /*0x00000003;*/ - pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5; - *((PWORD) &(pSRB->CmdBlock[2])) = 0; - *((PWORD) &(pSRB->CmdBlock[4])) = sizeof(pcmd->sense_buffer); - pSRB->ScsiCmdLen = 6; - if( DC395x_trm_StartSCSI( pACB, pDCB, pSRB ) ) + if( DC395x_StartSCSI( pACB, pDCB, pSRB ) ) { - /* - ** If DC395x_trm_StartSCSI returns 1: - ** SCSI chip is busy; let's requeue the SRB - */ - DC395x_trm_RewaitSRB( pDCB, pSRB ); + printk ("DC395x: Request Sense failed for pid %li (%02i-%i)!\n", + pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN); + TRACEPRINTF ("?*"); } + TRACEPRINTF (".*"); } +#if 0 /* ********************************************************************* ** scsiio -** DC395x_trm_MsgInPhase0 DC395x_trm_EnableMsgOutAbort1 +** DC395x_MsgInPhase0 DC395x_EnableMsgOutAbort1 ** ********************************************************************* */ -static void DC395x_trm_EnableMsgOutAbort2( PACB pACB, PSRB pSRB ) +static void DC395x_EnableMsgOutAbort2( PACB pACB, PSRB pSRB ) { - WORD ioport; - -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_EnableMsgOutAbort2..............\n "); #endif - ioport = pACB->IOPortBase; pSRB->MsgCnt = 1; - outw(DO_SETATN, ioport+TRM_S1040_SCSI_CONTROL); + DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_SETATN); } /* ********************************************************************* ** scsiio -** DC395x_trm_Reselect DC395x_trm_Interrupt DC395x_trm_MsgInPhase0 +** DC395x_Reselect DC395x_Interrupt DC395x_MsgInPhase0 ** ********************************************************************* */ -static inline void DC395x_trm_EnableMsgOutAbort1( PACB pACB, PSRB pSRB ) +static inline void DC395x_EnableMsgOutAbort1( PACB pACB, PSRB pSRB ) { -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_EnableMsgOutAbort1..............\n "); #endif pSRB->MsgOutBuf[0] = MSG_ABORT; - DC395x_trm_EnableMsgOutAbort2( pACB, pSRB ); + DC395x_EnableMsgOutAbort2( pACB, pSRB ); } +#endif /* ********************************************************************** -** DC395x_trm_queue_command +** DC395x_queue_command ** -** Function : void DC395x_trm_initDCB +** 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_trm_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ) +void DC395x_initDCB( PACB pACB, PDCB *ppDCB, BYTE target, BYTE lun) { PNVRAMTYPE pEEpromBuf; BYTE PeriodIndex; WORD index; + PDCB pDCB, pDCB2; -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_initDCB..............\n "); #endif - if( pACB->DeviceCnt == 0 ) + pDCB = kmalloc (sizeof(DC395x_DCB), GFP_ATOMIC); + //pDCB = DC395x_findDCB (pACB, target, lun); + *ppDCB = pDCB; pDCB2 = 0; + if (!pDCB) return; + + if( pACB->DCBCnt == 0 ) { pACB->pLinkDCB = pDCB; - /* - ** RunRobin impersonate the role - ** that let each device had good proportion - ** about SCSI command proceeding - */ pACB->pDCBRunRobin = pDCB; - pDCB->pNextDCB = pDCB; - DC395x_TRM_pPrevDCB = pDCB; } else - DC395x_TRM_pPrevDCB->pNextDCB = pDCB; + { + pACB->pLastDCB->pNextDCB = pDCB; + }; + pACB->DCBCnt++; + pDCB->pNextDCB = pACB->pLinkDCB; + pACB->pLastDCB = pDCB; + /* $$$$$$$ */ pDCB->pDCBACB = pACB; - pDCB->QIORBCnt = 0; - pDCB->TargetID = cmd->target; - pDCB->TargetLUN = cmd->lun; + pDCB->TargetID = target; + pDCB->TargetLUN = lun; /* $$$$$$$ */ pDCB->pWaitingSRB = NULL; pDCB->pGoingSRB = NULL; pDCB->GoingSRBCnt = 0; + pDCB->WaitSRBCnt = 0; pDCB->pActiveSRB = NULL; /* $$$$$$$ */ pDCB->TagMask = 0; @@ -4103,29 +5081,30 @@ /* $$$$$$$ */ index = pACB->AdapterIndex; pEEpromBuf = &dc395x_trm_eepromBuf[index]; - pDCB->DevMode = pEEpromBuf->NvramTarget[cmd->target].NvmTarCfg0; + pDCB->DevMode = pEEpromBuf->NvramTarget[target].NvmTarCfg0; pDCB->AdpMode = pEEpromBuf->NvramChannelCfg; pDCB->SyncMode = 0; + pDCB->last_derated = pACB->pScsiHost->last_reset - 2; /* $$$$$$$ */ pDCB->SyncPeriod = 0; pDCB->SyncOffset = 0; - PeriodIndex = pEEpromBuf->NvramTarget[cmd->target].NvmTarPeriod & 0x07; - pDCB->MinNegoPeriod = dc395x_trm_clock_period[ PeriodIndex ] ; - + 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( !(cmd->lun) || DC395x_TRM_CurrSyncOffset ) + if( !(lun) || DC395x_CurrSyncOffset ) pDCB->SyncMode |= SYNC_NEGO_ENABLE; #endif /* $$$$$$$ */ #ifndef DC395x_NO_DISCONNECT - pDCB->IdentifyMsg = IDENTIFY(pDCB->DevMode & NTC_DO_DISCONNECT, cmd->lun); + pDCB->IdentifyMsg = IDENTIFY(pDCB->DevMode & NTC_DO_DISCONNECT, lun); #else - pDCB->IdentifyMsg = IDENTIFY(0, cmd->lun); + pDCB->IdentifyMsg = IDENTIFY(0, lun); #endif /* $$$$$$$ */ if (pDCB->TargetLUN != 0) @@ -4134,7 +5113,7 @@ PDCB prevDCB = pACB->pLinkDCB; while (prevDCB->TargetID != pDCB->TargetID) prevDCB = prevDCB->pNextDCB; -#ifdef DC395x_trm_DEBUG_KG +#ifdef DC395x_DEBUG_KG printk ("DC395x: Copy settings from %02i-%02i to %02i-%02i\n", prevDCB->TargetID, prevDCB->TargetLUN, pDCB->TargetID, pDCB->TargetLUN); @@ -4144,34 +5123,35 @@ pDCB->MinNegoPeriod = prevDCB->MinNegoPeriod; pDCB->SyncOffset = prevDCB->SyncOffset; }; - //pDCB->pNextDCB = pACB->pLinkDCB; + + pACB->DCBmap[target] |= (1 << lun); } /* ********************************************************************** -** DC395x_trm_linkSRB -** DC395x_trm_initACB +** DC395x_linkSRB +** DC395x_initACB ** -** Function : static void DC395x_trm_initSRB +** Function : static void DC395x_initSRB ** Purpose : initialize the internal structures for a given SRB ** Inputs : pSRBTemp - pointer to this scsi request block structure ** ********************************************************************** */ -static inline void DC395x_trm_initSRB( PSRB pSRB ) +static inline void DC395x_initSRB( PSRB pSRB ) { - pSRB->PhysSRB = (DWORD) pSRB; + //pSRB->PhysSRB = virt_to_bus ((DWORD) pSRB); } /* ********************************************************************* ** scsiio -** DC395x_trm_initACB +** DC395x_initACB ** ********************************************************************* */ -__initfunc(void DC395x_trm_linkSRB( PACB pACB )) +void __init DC395x_linkSRB( PACB pACB ) { WORD count, i; @@ -4196,55 +5176,50 @@ /* ** convert and save physical address of SRB to pSRB->PhysSRB */ - DC395x_trm_initSRB( (PSRB) &pACB->SRB_array[i] ); + DC395x_initSRB( (PSRB) &pACB->SRB_array[i] ); } } /* ************************************************************************ -** DC395x_trm_init +** DC395x_init ** -** Function : static void DC395x_trm_initACB +** Function : static void DC395x_initACB ** Purpose : initialize the internal structures for a given SCSI host ** Inputs : psh - pointer to this host adapter's structure ** ************************************************************************ */ -__initfunc(void DC395x_trm_initACB( PSH psh, DWORD io_port, BYTE Irq, WORD index )) +void __init DC395x_initACB( PSH psh, DWORD io_port, BYTE Irq, WORD index ) { PNVRAMTYPE pEEpromBuf; PACB pACB; WORD i; pEEpromBuf = &dc395x_trm_eepromBuf[index]; - psh->can_queue = DC395x_trm_MAX_CMD_QUEUE; - psh->cmd_per_lun = DC395x_trm_MAX_CMD_PER_LUN; + 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; - pACB->max_id = 15; psh->max_id = 16; - if( pACB->max_id == pEEpromBuf->NvramScsiId ) - pACB->max_id--; + if( psh->max_id - 1 == pEEpromBuf->NvramScsiId ) + psh->max_id--; #ifdef CONFIG_SCSI_MULTI_LUN if( pEEpromBuf->NvramChannelCfg & NAC_SCANLUN ) - { psh->max_lun =8; - pACB->max_lun = 7; - } else - { psh->max_lun =1; - pACB->max_lun =0; - } #else psh->max_lun =1; - pACB->max_lun =0; #endif /* ******************************** @@ -4255,39 +5230,43 @@ pACB->pDCBRunRobin = NULL; pACB->pActiveDCB = NULL; pACB->pFreeSRB = pACB->SRB_array; - pACB->SRBCount = DC395x_trm_MAX_SRB_CNT; + pACB->SRBCount = DC395x_MAX_SRB_CNT; pACB->AdapterIndex = index; pACB->status = 0; - pACB->AdaptSCSIID = pEEpromBuf->NvramScsiId; - pACB->HostID_Bit = (1 << pACB->AdaptSCSIID); - pACB->AdaptSCSILUN = 0; - pACB->DeviceCnt = 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 = pEEpromBuf->NvramMaxTag << 2; 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; /* ******************************** */ - pACB->pDCB_free = &pACB->DCB_array[0]; + //pACB->pDCB_free = &pACB->DCB_array[0]; /* ** link all device's SRB Q of this adapter */ - DC395x_trm_linkSRB( pACB ); + DC395x_linkSRB( pACB ); /* - ** temp SRB for Q tag used or abord command used + ** temp SRB for Q tag used or abort command used */ pACB->pTmpSRB = &pACB->TmpSRB; + pACB->TmpSRB.pSRBDCB = 0; /* ** convert and save physical address of SRB to pSRB->PhysSRB */ - DC395x_trm_initSRB( pACB->pTmpSRB ); - for(i=0; i < DC395x_trm_MAX_SCSI_ID; i++) + DC395x_initSRB( pACB->pTmpSRB ); + init_timer (&pACB->Waiting_Timer); + + for (i = 0; i < DC395x_MAX_SCSI_ID; i++) pACB->DCBmap[i] = 0; -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x: pACB = %8x, pDCBmap = %8x, pSRB_array = %8x\n",(UINT) pACB, (UINT) pACB->DCBmap, (UINT) pACB->SRB_array); printk(KERN_INFO "DC395x: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",sizeof(DC395X_TRM_ACB), sizeof(DC395X_TRM_DCB), sizeof(DC395X_TRM_SRB) ); #endif @@ -4297,25 +5276,22 @@ /* ********************************************************************** ** -** DC395x_trm_init +** DC395x_init ** -** Function : static int DC395x_trm_initAdapter +** Function : static int DC395x_initAdapter ** Purpose : initialize the SCSI chip ctrl registers ** Inputs : psh - pointer to this host adapter's structure ** ********************************************************************** */ -__initfunc(int DC395x_trm_initAdapter( PSH psh, DWORD io_port, BYTE Irq, WORD index )) +int __init DC395x_initAdapter( PSH psh, DWORD io_port, BYTE Irq, WORD index ) { PNVRAMTYPE pEEpromBuf; - WORD ioport,wval; - BYTE bval; PACB pACB, pTempACB; WORD used_irq = 0; - DWORD i; pEEpromBuf = &dc395x_trm_eepromBuf[index]; - pTempACB = DC395x_TRM_pACB_start; + pTempACB = DC395x_pACB_start; if( pTempACB != NULL ) { for ( ; (pTempACB != (PACB) -1) ; ) @@ -4353,60 +5329,43 @@ ** before the driver interrupt function is called. */ - if( request_irq(Irq, do_DC395x_trm_Interrupt, SA_SHIRQ, "DC395x_TRM", NULL) ) + if( request_irq(Irq, DC395x_Interrupt, SA_SHIRQ, "DC395x_TRM", NULL) ) { printk(KERN_INFO "DC395x: register IRQ error!\n"); return( -1 ); } } - - ioport = (WORD) io_port; pACB = (PACB) psh->hostdata; + pACB->IOPortBase = io_port; /* selection timeout = 250 ms */ - outb(DC395x_trm_SEL_TIMEOUT,ioport+TRM_S1040_SCSI_TIMEOUT); + pACB->sel_timeout = DC395x_SEL_TIMEOUT; /* Mask all the interrupt */ - outb(0x00,ioport+TRM_S1040_DMA_INTEN); - outb(0x00,ioport+TRM_S1040_SCSI_INTEN); + DC395x_write8(TRM_S1040_DMA_INTEN,0x00); + DC395x_write8(TRM_S1040_SCSI_INTEN,0x00); /* Reset SCSI module */ - outw(DO_RSTMODULE,ioport+TRM_S1040_SCSI_CONTROL); + 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 ( inb(ioport+TRM_S1040_GEN_STATUS) & WIDESCSI ) + 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_PARITY) - bval = PHASELATCH | INITIATOR | BLOCKRST | PARITYCHECK; - else - bval = PHASELATCH | INITIATOR | BLOCKRST ; - - outb(bval,ioport+TRM_S1040_SCSI_CONFIG0); - for( i=0; i<3600; i++ ) - udelay(1000); - - /* program configuration 1 */ - outb(0x13,ioport+TRM_S1040_SCSI_CONFIG1); - /* program Host ID */ - bval = pEEpromBuf->NvramScsiId; - outb(bval,ioport+TRM_S1040_SCSI_HOSTID); - /* set ansynchronous transfer */ - outb(0x00,ioport+TRM_S1040_SCSI_OFFSET); - /* Turn LED control off*/ - wval = inw(ioport+TRM_S1040_GEN_CONTROL) & 0x7F; - outw(wval,ioport+TRM_S1040_GEN_CONTROL); - /* DMA config */ - wval = inw(ioport+TRM_S1040_DMA_CONFIG) | DMA_ENHANCE ; - outw(wval,ioport+TRM_S1040_DMA_CONFIG); - /* Clear pending interrupt status*/ - inb(ioport+TRM_S1040_SCSI_INTSTATUS); - /* Enable SCSI interrupt */ - outb(0x7F,ioport+TRM_S1040_SCSI_INTEN); - outb(EN_SCSIINTR,ioport+TRM_S1040_DMA_INTEN); + if (1 /*pACB->Config & HCC_SCSI_RESET*/) + DC395x_write8 (TRM_S1040_SCSI_CONTROL, DO_RSTSCSI); + //spin_unlock_irq (&io_request_lock); + udelay (1000); + pACB->pScsiHost->last_reset = jiffies + HZ/2 + 3*HZ; + //spin_lock_irq (&io_request_lock); + + DC395x_basic_config (pACB); return(0); } /* ************************************************************************ -** DC395x_trm_check_eeprom +** DC395x_check_eeprom ** **---------------------------------------------------------------------- ** Function : TRM_S1040_write_all @@ -4415,7 +5374,7 @@ ** Output : none ************************************************************************ */ -__initfunc(static void TRM_S1040_write_all(PNVRAMTYPE pEEpromBuf,WORD scsiIOPort)) +static __init void TRM_S1040_write_all(PNVRAMTYPE pEEpromBuf,WORD scsiIOPort) { BYTE *bpEeprom = (BYTE *) pEEpromBuf; BYTE bAddr; @@ -4455,7 +5414,7 @@ ** Output : none *********************************************************************** */ -__initfunc(static void TRM_S1040_set_data(WORD scsiIOPort, BYTE bAddr, BYTE bData)) +static __init void TRM_S1040_set_data(WORD scsiIOPort, BYTE bAddr, BYTE bData) { int i; BYTE bSendData; @@ -4506,7 +5465,7 @@ } /* ************************************************************************ -** DC395x_trm_check_eeprom +** DC395x_check_eeprom ** **---------------------------------------------------------------------- ** Function : TRM_S1040_read_all @@ -4515,7 +5474,7 @@ ** Output : none ************************************************************************ */ -__initfunc(static void TRM_S1040_read_all(PNVRAMTYPE pEEpromBuf, WORD scsiIOPort)) +static __init void TRM_S1040_read_all(PNVRAMTYPE pEEpromBuf, WORD scsiIOPort) { BYTE *bpEeprom = (BYTE *) pEEpromBuf; BYTE bAddr; @@ -4546,7 +5505,7 @@ ** Output : bData - data of SEEPROM ************************************************************************ */ -__initfunc( static BYTE TRM_S1040_get_data(WORD scsiIOPort, BYTE bAddr)) +static __init BYTE TRM_S1040_get_data(WORD scsiIOPort, BYTE bAddr) { int i; BYTE bReadData, bData = 0; @@ -4607,7 +5566,7 @@ ** Output : none ************************************************************************ */ -__initfunc (static void TRM_S1040_write_cmd(WORD scsiIOPort, BYTE bCmd, BYTE bAddr)) +static __init void TRM_S1040_write_cmd(WORD scsiIOPort, BYTE bCmd, BYTE bAddr) { int i; BYTE bSendData; @@ -4646,17 +5605,17 @@ /* ************************************************************************ -** DC395x_trm_init +** DC395x_init ** **---------------------------------------------------------------------- -** Function : DC395x_trm_check_eeprom +** 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 ************************************************************************ */ -__initfunc(static void DC395x_trm_check_eeprom(PNVRAMTYPE pEEpromBuf, WORD scsiIOPort)) +static __init void DC395x_check_eeprom(PNVRAMTYPE pEEpromBuf, WORD scsiIOPort) { WORD *wpEeprom = (WORD *) pEEpromBuf; WORD wAddr, wCheckSum; @@ -4671,6 +5630,7 @@ { /* ** Checksum error, load default */ + printk ("DC395x: EEProm ChkSum error: Load defaults!\n"); pEEpromBuf->NvramSubVendorID[0] = (BYTE) PCI_VendorID_TEKRAM; pEEpromBuf->NvramSubVendorID[1] = (BYTE) (PCI_VendorID_TEKRAM >> 8); pEEpromBuf->NvramSubSysID[0] = (BYTE) PCI_DeviceID_TRMS1040; @@ -4699,72 +5659,111 @@ } return; } + +/* Print connector and termination config */ +static __init void 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)) == (CON5068 | CON50 | CON68)) + printk ("\nDC395x: ERROR: Never use all three connectors !!!\n"); + 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_trm_detect +** DC395x_detect ** -** Function : static int DC395x_trm_init (struct Scsi_Host *host) +** 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. ********************************************************************** */ -__initfunc(static int DC395x_trm_init(PSHT psht, DWORD io_port, BYTE Irq, WORD index)) +static __init PSH DC395x_init(PSHT psht, DWORD io_port, BYTE Irq, WORD index) { PSH psh; PACB pACB; //DWORD acb_flags=0; //$$$$$$$$$$$$$$$$$$$$$$$ EEPROM CHECKSUM $$$$$$$$$$$$$$$$$$$$$$$$$ - DC395x_trm_check_eeprom( &dc395x_trm_eepromBuf[index], (WORD) io_port); + 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( -1 ); + return( 0 ); } printk (KERN_INFO "DC395x: Used settings: AdaptID=%i\n", dc395x_trm_eepromBuf[index].NvramScsiId); pACB = (PACB) psh->hostdata; - //DC395x_TRM_ACB_INITLOCK(pACB); - //DC395x_TRM_ACB_LOCK(pACB,acb_flags); + //DC395x_ACB_INITLOCK(pACB); + //DC395x_ACB_LOCK(pACB,acb_flags); //$$$$$$$$ INITIAL ADAPTER CONTROL BLOCK $$$$$$$$$$$$ - DC395x_trm_initACB( psh, io_port, Irq, index ); + DC395x_initACB( psh, io_port, Irq, index ); + DC395x_print_config (pACB); //$$$$$$$$$$$$$$$$$ INITIAL ADAPTER $$$$$$$$$$$$$$$$$ - if( !DC395x_trm_initAdapter( psh, io_port, Irq, index ) ) + if( !DC395x_initAdapter( psh, io_port, Irq, index ) ) { - if( !DC395x_TRM_pACB_start ) + if( !DC395x_pACB_start ) { - DC395x_TRM_pACB_start = pACB; - DC395x_TRM_pACB_current = pACB; + DC395x_pACB_start = pACB; + DC395x_pACB_current = pACB; pACB->pNextACB = (PACB) -1; } else { - DC395x_TRM_pACB_current->pNextACB = pACB; - DC395x_TRM_pACB_current = pACB; + DC395x_pACB_current->pNextACB = pACB; + DC395x_pACB_current = pACB; pACB->pNextACB = (PACB) -1; } - //DC395x_TRM_ACB_UNLOCK(pACB,acb_flags); - return( 0 ); + //DC395x_ACB_UNLOCK(pACB,acb_flags); + return( psh ); } else { printk(KERN_INFO "DC395x_initAdapter initial ERROR\n"); scsi_unregister( psh ); - //DC395x_TRM_ACB_UNLOCK(pACB,acb_flags); - return( -1 ); + //DC395x_ACB_UNLOCK(pACB,acb_flags); + return( 0 ); } } /* ********************************************************************** ** -** DC395x_trm_set_master +** DC395x_set_master ** Function : ** Purpose : ** Inputs : @@ -4773,7 +5772,7 @@ ********************************************************************** */ #ifndef NEW_PCI -__initfunc(static void DC395x_trm_set_master(BYTE pci_bus,BYTE pci_device_fn)) +static __init void DC395x_set_master(BYTE pci_bus,BYTE pci_device_fn) { WORD cmd; BYTE latency_timer; @@ -4793,10 +5792,12 @@ } } #endif + +#if 0 /* ********************************************************************** ** -** DC395x_trm_set_pci_cfg +** DC395x_set_pci_cfg ** Function : ** Purpose : ** Inputs : @@ -4805,17 +5806,25 @@ ********************************************************************** */ #ifdef NEW_PCI -__initfunc(static void DC395x_trm_set_pci_cfg( struct pci_dev *pPCI_DEVICE )) +static __init void DC395x_set_pci_cfg( struct pci_dev *pPCI_DEVICE ) { - WORD cmd; + WORD cmd, stat; - pci_read_config_word(pPCI_DEVICE,PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO; + 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_write_config_word(pPCI_DEVICE, PCI_STATUS,(PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY) ); + 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 -__initfunc(static void DC395x_trm_set_pci_cfg(BYTE pci_bus,BYTE pci_device_fn)) +static __init void DC395x_set_pci_cfg(BYTE pci_bus,BYTE pci_device_fn) { WORD cmd; @@ -4825,12 +5834,14 @@ 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_trm_detect(Scsi_Host_Template *psht) +** 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. @@ -4892,7 +5903,7 @@ **}; ********************************************************************** */ -__initfunc(int DC395x_trm_detect(Scsi_Host_Template *psht)) +int __init DC395x_detect (Scsi_Host_Template *psht) { #ifdef NEW_PCI struct pci_dev *pPCI_DEVICE = NULL; @@ -4901,15 +5912,16 @@ WORD pci_index = 0; /* Device index to PCI BIOS calls */ int error = 0; #endif - DWORD flags; BYTE irq; UINT io_port; - //DWORD drv_flags=0,irq_flags=0; - - DC395x_LOCK_IO; + +#ifndef USE_NEW_EH + DWORD flags; + DC395x_LOCK_IO; // Don't lock for new EH +#endif - DC395x_TRM_pACB_start = NULL; + DC395x_pACB_start = NULL; /* search DC395x SCSI adapter in each slot */ #ifdef NEW_PCI if(pci_present()) @@ -4923,10 +5935,15 @@ 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_TRM_DRV_LOCK(drv_flags); + //DC395x_DRV_LOCK(drv_flags); #ifdef NEW_PCI +# if LINUX_VERSION_CODE >= KERNEL_VERSION (2,3,10) + io_port = pPCI_DEVICE->resource[0].start & 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); @@ -4938,57 +5955,491 @@ } (WORD) io_port = (WORD) io_port & PCI_BASE_ADDRESS_IO_MASK; #endif -#ifdef DC395x_trm_DEBUG0 +#ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x: IO_PORT=%04x,IRQ=%x\n",(UINT) io_port, irq); #endif - if( !DC395x_trm_init(psht, io_port, irq, DC395x_TRM_adapterCnt) ) + if( (psh = DC395x_init(psht, io_port, irq, DC395x_adapterCnt)) ) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) +#ifdef NEW_PCI pci_set_master(pPCI_DEVICE); - DC395x_trm_set_pci_cfg(pPCI_DEVICE); + ((PACB)(psh->hostdata))->pdev = pPCI_DEVICE; + //DC395x_set_pci_cfg(pPCI_DEVICE); #else - DC395x_trm_set_master(pci_bus,pci_device_fn); - DC395x_trm_set_pci_cfg(pci_bus,pci_device_fn); + 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_TRM_adapterCnt++; + DC395x_adapterCnt++; } - //DC395x_TRM_DRV_UNLOCK(drv_flags); + //DC395x_DRV_UNLOCK(drv_flags); } } else { printk (KERN_ERR "No PCI BIOS found!\n"); } -#ifndef VERSION_ELF_1_2_13 - if(DC395x_TRM_adapterCnt) - psht->proc_dir = &DC395x_trm_proc_scsi; + + 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"); - printk(KERN_INFO "DC395x (TRM-S1040): %i adapters found\n", DC395x_TRM_adapterCnt); - - //DC395x_TRM_SMP_IO_UNLOCK(irq_flags); +#ifndef USE_NEW_EH DC395x_UNLOCK_IO; - return( DC395x_TRM_adapterCnt ); +#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->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; }; + 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); +}; + /* ******************************************************************* ** -** Function: DC395x_trm_set_info() +** Function: DC395x_set_info() ** Purpose: Set adapter info (!) -** Not yet implemented -** -******************************************************************* -*/ -int DC395x_trm_set_info(char *buffer, int length, PACB pACB) +** 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 (varmax) 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; + /* 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_eepromBuf[pACB->AdapterIndex][EE_DELAY], "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; + return (length); + + einv2: + pos = p0; + einv: + /* spin_unlock (strtok_lock); */ + //DC395x_ACB_UNLOCK(acb_flags); + DC395x_UNLOCK_IO; + 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; + }; + return (length); + + dump: + { + DC395x_dumpinfo (pACB, 0, 0); + DC395x_UNLOCK_IO; + }; + 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; + }; + 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; + }; + 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; + }; + 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; + return (-EINVAL); +} + +#if 0 +int DC395x_set_info(char *buffer, int length, PACB pACB) { - return(-EINVAL); + return -ENOSYS; } +#endif +#undef SEARCH +#undef YESNO +#undef SCANF + + /* ******************************************************************* -** Function: DC395x_trm_proc_info(char* buffer, char **start, +** Function: DC395x_proc_info(char* buffer, char **start, ** off_t offset, int length, int hostno, int inout) ** Purpose: return SCSI Adapter/Device Info ** Input: @@ -5014,92 +6465,133 @@ if (YN) SPRINTF(" Yes ");\ else SPRINTF(" No ") -int DC395x_trm_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) +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 acbpnt; - PDCB dcbpnt; + PACB pACB; + PDCB pDCB; DWORD flags; + PSCSICMD pcmd; /* Scsi_Cmnd *ptr; */ - acbpnt = DC395x_TRM_pACB_start; + pACB = DC395x_pACB_start; - while(acbpnt != (PACB)-1) + while(pACB != (PACB)-1) { - shpnt = acbpnt->pScsiHost; + shpnt = pACB->pScsiHost; if (shpnt->host_no == hostno) break; - acbpnt = acbpnt->pNextACB; + pACB = pACB->pNextACB; } - if (acbpnt == (PACB)-1) + if (pACB == (PACB)-1) return(-ESRCH); if(!shpnt) return(-ESRCH); if(inout) /* Has data been written to the file ? */ - return(DC395x_trm_set_info(buffer, length, acbpnt)); + return(DC395x_set_info(buffer, length, pACB)); - SPRINTF(DC395x_BANNER " PCI SCSI Host Adadpter, "); - SPRINTF("Driver Version " DC395x_VERSION "\n"); + SPRINTF(DC395x_BANNER " PCI SCSI Host Adapter\n"); + SPRINTF(" Driver Version " DC395x_VERSION "\n"); DC395x_LOCK_IO; SPRINTF("SCSI Host Nr %i, ", shpnt->host_no); SPRINTF("DC395U/UW/F DC315/U %s Adapter Nr %i\n", - (acbpnt->Config & HCC_WIDE_CARD)? "Wide": "", acbpnt->AdapterIndex); - SPRINTF("IOPortBase 0x%04x, ", acbpnt->IOPortBase); - SPRINTF("IRQLevel 0x%02x\n", acbpnt->IRQLevel); + (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, ",acbpnt->max_id, acbpnt->max_lun); - SPRINTF("AdapterID %i, AdapterLUN %i\n", acbpnt->AdaptSCSIID, acbpnt->AdaptSCSILUN); + SPRINTF("MaxID %i, MaxLUN %i, ", shpnt->max_id, shpnt->max_lun); + SPRINTF("AdapterID %i\n", shpnt->this_id); - SPRINTF("TagMaxNum %i, Status %i\n", acbpnt->TagMaxNum, acbpnt->status); + SPRINTF("TagMaxNum %i, Status %i", pACB->TagMaxNum, pACB->status); + //SPRINTF(", DMA_Status %i\n", DC395x_read8(TRM_S1040_DMA_STATUS)); + SPRINTF (", FilterCfg 0x%02x\n", DC395x_read8(TRM_S1040_SCSI_CONFIG1)); + //SPRINTF("\n"); - SPRINTF("Nr of attached devices: %i\n", acbpnt->DeviceCnt); + 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 SyncSpeed SyncOffs\n"); + SPRINTF("Un ID LUN Prty Sync Wide DsCn SndS TagQ NegoPeriod SyncFreq SyncOffs\n"); - dcbpnt = acbpnt->pLinkDCB; - for (dev = 0; dev < acbpnt->DeviceCnt; dev++) + pDCB = pACB->pLinkDCB; + for (dev = 0; dev < pACB->DCBCnt; dev++) { - SPRINTF("%02i %02i %02i ", dev, dcbpnt->TargetID, dcbpnt->TargetLUN); - YESNO(dcbpnt->DevMode & NTC_DO_PARITY_CHK); - YESNO(dcbpnt->SyncMode & SYNC_NEGO_DONE); - YESNO(dcbpnt->SyncMode & WIDE_NEGO_DONE); - YESNO(dcbpnt->DevMode & NTC_DO_DISCONNECT); - YESNO(dcbpnt->DevMode & NTC_DO_SEND_START); - YESNO(dcbpnt->SyncMode & EN_TAG_QUEUEING); - if (dcbpnt->SyncMode & SYNC_NEGO_DONE) - SPRINTF(" %03i ns ", (dcbpnt->MinNegoPeriod) << 2); + 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)", (dcbpnt->MinNegoPeriod) << 2); + SPRINTF(" (%03i ns)", (pDCB->MinNegoPeriod << 2)); - if (dcbpnt->SyncOffset & 0x0f) + if (pDCB->SyncOffset & 0x0f) { - spd = 1000/(dcbpnt->MinNegoPeriod <<2); - spd1 = 1000%(dcbpnt->MinNegoPeriod <<2); - spd1 = (spd1 * 10)/(dcbpnt->MinNegoPeriod <<2); - SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (dcbpnt->SyncOffset & 0x0f)); + spd = 1000/(NegoPeriod); + spd1 = 1000%(NegoPeriod); + spd1 = (spd1 * 10 + NegoPeriod/2)/(NegoPeriod); + SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (pDCB->SyncOffset & 0x0f)); } else SPRINTF("\n"); /* Add more info ...*/ - dcbpnt = dcbpnt->pNextDCB; + pDCB = pDCB->pNextDCB; } - -#ifdef DC395x_trm_DEBUG_KG - SPRINTF ("DCB list for ACB %p:\n", acbpnt); - dcbpnt = acbpnt->pLinkDCB; - SPRINTF ("%p", dcbpnt); - for (dev = 0; dev < acbpnt->DeviceCnt; dev++, dcbpnt=dcbpnt->pNextDCB) - SPRINTF ("->%p", dcbpnt->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"); - SPRINTF ("Next free DCB: %p\n", acbpnt->pDCB_free); #endif *start = buffer + offset; @@ -5117,35 +6609,56 @@ /* ********************************************************************** -** Function : int DC395x_trm_shutdown (struct Scsi_Host *host) +** 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_trm_shutdown (struct Scsi_Host *host) +int DC395x_shutdown (struct Scsi_Host *host) { - BYTE bval; - WORD ioport; PACB pACB; //DWORD acb_flags=0; pACB = (PACB)(host->hostdata); - ioport = (unsigned int) pACB->IOPortBase; /* pACB->soft_reset(host); */ /* ** disable interrupt */ - bval = 0x00 ; - outb(bval,ioport+TRM_S1040_DMA_INTEN); - outb(bval,ioport+TRM_S1040_SCSI_INTEN); + 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->Data_Timer)) del_timer (&pACB->Data_Timer); - DC395x_trm_ResetSCSIBus( pACB ); + if (pACB->Config & HCC_SCSI_RESET) + DC395x_ResetSCSIBus( pACB ); 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);) + //kfree (pDCB); + DC395x_remove_dev (pACB, pDCB); + printk ("."); + pDCB = nDCB; + } while (pDCB && pACB->pLinkDCB); +}; + /* ********************************************************************* ** @@ -5153,19 +6666,20 @@ ** ********************************************************************* */ -int DC395x_trm_release(struct Scsi_Host *host) +int DC395x_release(struct Scsi_Host *host) { int irq_count; DWORD flags; PACB pACB = (PACB)(host->hostdata); //DWORD acb_flags=0; DC395x_LOCK_IO; - //DC395x_TRM_ACB_LOCK(pACB,acb_flags); - DC395x_trm_shutdown (host); + //DC395x_ACB_LOCK(pACB,acb_flags); + printk ("DC395x: Shutdown ."); + DC395x_shutdown (host); if (host->irq != IRQ_NONE) { - for (irq_count = 0, pACB = DC395x_TRM_pACB_start; + for (irq_count = 0, pACB = DC395x_pACB_start; pACB != (PACB)-1; pACB = pACB->pNextACB) { if ( pACB->IRQLevel == host->irq ) @@ -5175,9 +6689,12 @@ free_irq(host->irq, NULL); } release_region(host->io_port,host->n_io_port); + printk ("."); + DC395x_freeDCBs (host); DC395x_UNLOCK_IO; - //DC395x_TRM_DRV_UNLOCK(drv_flags); + //DC395x_DRV_UNLOCK(drv_flags); + printk ("\n"); return( 1 ); } Index: dc395x_trm.h =================================================================== RCS file: /home/cvsroot/dc395/dc395x_trm.h,v retrieving revision 1.8 retrieving revision 1.19 diff -u -u -r1.8 -r1.19 --- dc395x_trm.h 1999/07/19 13:52:01 1.8 +++ dc395x_trm.h 2000/02/11 18:31:05 1.19 @@ -8,7 +8,7 @@ ** ********************************************************************** */ - +/* $Id: dc395x_trm.h,v 1.19 2000/02/11 18:31:05 garloff Exp $ */ /* ***************************************************** ** Tekram TRM_S1040 for DC395x driver, header file @@ -18,7 +18,7 @@ #define DC395x_trm_H #define DC395x_BANNER "Tekram DC395U/UW/F DC315/U" -#define DC395x_VERSION "1.10, 1999/07/19" +#define DC395x_VERSION "1.23, 2000-02-11" /* Kernel version autodetection */ #include @@ -35,64 +35,97 @@ #define VERSION_2_0_0 #endif -#define DC395x_trm_MAX_CMD_QUEUE 20 -#define DC395x_trm_MAX_QTAGS 32 -#define DC395x_trm_MAX_ADAPTER_NUM 4 -#define DC395x_trm_MAX_SCSI_ID 16 -#define DC395x_trm_MAX_DCB 20 -#define DC395x_trm_MAX_CAN_QUEUE 7 * DC395x_trm_MAX_QTAGS -#define DC395x_trm_MAX_CMD_PER_LUN DC395x_trm_MAX_QTAGS -#define DC395x_trm_MAX_SG_TABLESIZE 64 -#define DC395x_trm_MAX_SG_LISTENTRY 64 -#define DC395x_trm_MAX_SRB_CNT DC395x_trm_MAX_CMD_QUEUE+4 -#define DC395x_trm_END_SCAN 2 -#define DC395x_trm_SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */ +#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 +#define DC395x_MAX_SG_LISTENTRY 64 +#define DC395x_MAX_SRB_CNT DC395x_MAX_CMD_QUEUE+4 +//#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 #if defined(HOSTS_C) || defined(MODULE) # include -extern int DC395x_trm_detect(Scsi_Host_Template *psht); -extern int DC395x_trm_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); -extern int DC395x_trm_abort(Scsi_Cmnd *cmd); -extern int DC395x_trm_reset(Scsi_Cmnd *cmd ,unsigned int resetFlags); -extern int DC395x_trm_bios_param(Disk *disk, kdev_t devno, int geom[]); +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_trm_release(struct Scsi_Host *); +static int DC395x_release(struct Scsi_Host *); # else -# define DC395x_trm_release NULL +# define DC395x_release NULL # endif //-------------- -# ifndef VERSION_ELF_1_2_13 -extern struct proc_dir_entry DC395x_trm_proc_scsi; -extern int DC395x_trm_proc_info(char*, char**, off_t, int, int, int); -# endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,30) +extern struct proc_dir_entry DC395x_proc_scsi; +#endif +extern int DC395x_proc_info(char*, char**, off_t, int, int, int); //-------------- -#if LINUX_VERSION_CODE < KERNEL_VERSION (2,1,70) -# define NO_NEW_EH +//#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 NO_NEW_EH use_new_eh_code: 0, +# define USE_NEW_EH +# define NORM_REC_LVL 0 +# define NEW_EH use_new_eh_code: 1, #endif -#define DC395x_TRMS1040 { \ - proc_dir: &DC395x_trm_proc_scsi, \ - proc_info: DC395x_trm_proc_info, \ - name: DC395x_BANNER " V" DC395x_VERSION, \ - detect: DC395x_trm_detect, \ - release: DC395x_trm_release, \ - queuecommand: DC395x_trm_queue_command, \ - abort: DC395x_trm_abort, \ - reset: DC395x_trm_reset, \ - bios_param: DC395x_trm_bios_param, \ - can_queue: DC395x_trm_MAX_CAN_QUEUE, \ - this_id: 7, \ - sg_tablesize: DC395x_trm_MAX_SG_TABLESIZE, \ - cmd_per_lun: DC395x_trm_MAX_CMD_PER_LUN, \ - NO_NEW_EH \ - unchecked_isa_dma: 0, \ - use_clustering: DISABLE_CLUSTERING \ +#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 +# 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) */ -#endif /* DC395x_trm_H */ +#endif /* DC395x_H */