Index: README.dc395x =================================================================== RCS file: /home/cvsroot/dc395/README.dc395x,v retrieving revision 1.15 retrieving revision 1.16 diff -u -u -r1.15 -r1.16 --- README.dc395x 2001/11/14 00:19:38 1.15 +++ README.dc395x 2002/02/13 10:23:58 1.16 @@ -2,7 +2,7 @@ ========================================== Preliminary. 2000-02-14 Kurt Garloff -$Id: README.dc395x,v 1.15 2001/11/14 00:19:38 garloff Exp $ +$Id: README.dc395x,v 1.16 2002/02/13 10:23:58 garloff Exp $ This driver is similar to the DC390/AM53c974 driver (tmscsim), so you might want to have a look into the README.tmscsim. @@ -227,10 +227,11 @@ can isolate the diff part to init/main.c and apply it to make this work ... Now you have to reconfigure your kernel (make oldconfig or make menuconfig), -enable the DC395x driver (compiled into the kernel or as a module; of course -you need it in the kernel, if your root fs resides on a partition connected -to the DC395 and you don't do advanced INITRD tricks) and recompile your -kernel and your modules: +enable the DC395x driver (compiled into the kernel or as a module; note that +you need to enable CONFIG_EXPERIMENTAL to be able to select the DC395 +driver; of course you need it in the kernel, if your root fs resides on a +partition connected to the DC395 and you don't do advanced INITRD tricks) +and recompile your kernel and your modules: > cd /usr/src/linux > make oldconfig (enable CONFIG_SCSI_DC395x_TRMS1040) > make bzlilo Index: dc395-integ24.diff =================================================================== RCS file: /home/cvsroot/dc395/dc395-integ24.diff,v retrieving revision 1.2 retrieving revision 1.3 diff -u -u -r1.2 -r1.3 --- dc395-integ24.diff 2001/07/09 19:33:54 1.2 +++ dc395-integ24.diff 2002/02/28 04:54:11 1.3 @@ -1,9 +1,9 @@ -diff -uNr linux-2.4.6.vanilla/Documentation/Configure.help linux-2.4.6.dc395/Documentation/Configure.help ---- linux-2.4.6.vanilla/Documentation/Configure.help Mon Jul 2 23:07:55 2001 -+++ linux-2.4.6.dc395/Documentation/Configure.help Mon Jul 9 21:31:28 2001 -@@ -6498,6 +6498,19 @@ - say M here and read Documentation/modules.txt. The module will be - called sim710.o. +diff -uNr linux-2.4.17.S12.5.nodc395/Documentation/Configure.help linux-2.4.17.S12.5.dc395-136/Documentation/Configure.help +--- linux-2.4.17.S12.5.nodc395/Documentation/Configure.help Thu Feb 28 05:47:12 2002 ++++ linux-2.4.17.S12.5.dc395-136/Documentation/Configure.help Thu Feb 28 05:51:03 2002 +@@ -8146,6 +8146,19 @@ + say M here and read . The module + will be called sim710.o. +Tekram DC395/U/UW and DC315/U SCSI support +CONFIG_SCSI_DC395x_TRMS1040 @@ -11,20 +11,20 @@ + ASIC TRM-S1040 chip, i.e. Tekram DC315 and DC395 variants. + This driver does work, but please note that it is still beta status, + so better have a bootable disk and a backup in case of emergency. -+ Please read the file drivers/scsi/README.dc395x. ++ Please read the file . + + 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 ++ say M here and read . The module will be + called dc395x_trm.o. + - Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support + Tekram DC390(T) and Am53/79C974 SCSI support CONFIG_SCSI_DC390T This driver supports PCI SCSI host adapters based on the Am53C974A -diff -uNr linux-2.4.6.vanilla/MAINTAINERS linux-2.4.6.dc395/MAINTAINERS ---- linux-2.4.6.vanilla/MAINTAINERS Wed Jun 27 22:59:32 2001 -+++ linux-2.4.6.dc395/MAINTAINERS Mon Jul 9 21:33:07 2001 -@@ -343,10 +343,12 @@ +diff -uNr linux-2.4.17.S12.5.nodc395/MAINTAINERS linux-2.4.17.S12.5.dc395-136/MAINTAINERS +--- linux-2.4.17.S12.5.nodc395/MAINTAINERS Thu Feb 28 05:47:12 2002 ++++ linux-2.4.17.S12.5.dc395-136/MAINTAINERS Thu Feb 28 05:49:35 2002 +@@ -399,10 +399,12 @@ L: linux-hams@vger.kernel.org S: Maintained @@ -39,10 +39,10 @@ S: Maintained DECnet NETWORK LAYER -diff -uNr linux-2.4.6.vanilla/drivers/scsi/Config.in linux-2.4.6.dc395/drivers/scsi/Config.in ---- linux-2.4.6.vanilla/drivers/scsi/Config.in Sun Mar 4 23:30:18 2001 -+++ linux-2.4.6.dc395/drivers/scsi/Config.in Mon Jul 9 21:31:28 2001 -@@ -159,6 +159,9 @@ +diff -uNr linux-2.4.17.S12.5.nodc395/drivers/scsi/Config.in linux-2.4.17.S12.5.dc395-136/drivers/scsi/Config.in +--- linux-2.4.17.S12.5.nodc395/drivers/scsi/Config.in Thu Feb 28 05:47:12 2002 ++++ linux-2.4.17.S12.5.dc395-136/drivers/scsi/Config.in Thu Feb 28 05:49:35 2002 +@@ -207,6 +207,9 @@ dep_tristate 'Simple 53c710 SCSI support (Compaq, NCR machines)' CONFIG_SCSI_SIM710 $CONFIG_SCSI dep_tristate 'Symbios 53c416 SCSI support' CONFIG_SCSI_SYM53C416 $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then @@ -52,10 +52,10 @@ dep_tristate 'Tekram DC390(T) and Am53/79C974 SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI if [ "$CONFIG_SCSI_DC390T" != "n" ]; then bool ' _omit_ support for non-DC390 adapters' CONFIG_SCSI_DC390T_NOGENSUPP -diff -uNr linux-2.4.6.vanilla/drivers/scsi/Makefile linux-2.4.6.dc395/drivers/scsi/Makefile ---- linux-2.4.6.vanilla/drivers/scsi/Makefile Sat May 5 00:16:28 2001 -+++ linux-2.4.6.dc395/drivers/scsi/Makefile Mon Jul 9 21:31:28 2001 -@@ -101,6 +101,7 @@ +diff -uNr linux-2.4.17.S12.5.nodc395/drivers/scsi/Makefile linux-2.4.17.S12.5.dc395-136/drivers/scsi/Makefile +--- linux-2.4.17.S12.5.nodc395/drivers/scsi/Makefile Thu Feb 28 05:47:12 2002 ++++ linux-2.4.17.S12.5.dc395-136/drivers/scsi/Makefile Thu Feb 28 05:49:35 2002 +@@ -113,6 +113,7 @@ obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o obj-$(CONFIG_SCSI_EATA) += eata.o obj-$(CONFIG_SCSI_DC390T) += tmscsim.o Index: dc395-integ25.diff =================================================================== RCS file: dc395-integ25.diff diff -N dc395-integ25.diff --- /dev/null Mon Nov 26 22:41:03 2001 +++ /tmp/cvsJ5xNUN Thu Feb 28 12:28:07 2002 @@ -0,0 +1,64 @@ +diff -uNr linux-2.5.5-dj2/MAINTAINERS linux-2.5.5-dj2-dc395/MAINTAINERS +--- linux-2.5.5-dj2/MAINTAINERS Wed Feb 27 12:22:08 2002 ++++ linux-2.5.5-dj2-dc395/MAINTAINERS Thu Feb 28 06:03:55 2002 +@@ -402,10 +402,12 @@ + L: linux-hams@vger.kernel.org + S: Maintained + +-DC390/AM53C974 SCSI driver ++DC390/AM53C974 and DC395/TRM-S1040 SCSI drivers + P: Kurt Garloff + M: garloff@suse.de +-W: http://www.garloff.de/kurt/linux/dc390/ ++M: kurt@garloff.de ++W: http://www.garloff.de/kurt/linux/ ++L: linux-scsi@vger.kernel.org + S: Maintained + + DECnet NETWORK LAYER +diff -uNr linux-2.5.5-dj2/drivers/scsi/Config.help linux-2.5.5-dj2-dc395/drivers/scsi/Config.help +--- linux-2.5.5-dj2/drivers/scsi/Config.help Wed Feb 27 12:22:09 2002 ++++ linux-2.5.5-dj2-dc395/drivers/scsi/Config.help Thu Feb 28 06:03:39 2002 +@@ -1137,6 +1137,18 @@ + say M here and read . The module + will be called sim710.o. + ++CONFIG_SCSI_DC395x_TRMS1040 ++ This driver supports the PCI SCSI host adapters baseds on Tekram's ++ ASIC TRM-S1040 chip, i.e. Tekram DC315 and DC395 variants. ++ This driver does work, but please note that it is still beta status, ++ so better have a bootable disk and a backup in case of emergency. ++ Please read the file . ++ ++ 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 . The module will be ++ called dc395x_trm.o. ++ + CONFIG_SCSI_DC390T + This driver supports PCI SCSI host adapters based on the Am53C974A + chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard +diff -uNr linux-2.5.5-dj2/drivers/scsi/Config.in linux-2.5.5-dj2-dc395/drivers/scsi/Config.in +--- linux-2.5.5-dj2/drivers/scsi/Config.in Wed Feb 27 12:22:09 2002 ++++ linux-2.5.5-dj2-dc395/drivers/scsi/Config.in Thu Feb 28 06:03:55 2002 +@@ -185,6 +185,9 @@ + dep_tristate 'Simple 53c710 SCSI support (Compaq, NCR machines)' CONFIG_SCSI_SIM710 $CONFIG_SCSI + dep_tristate 'Symbios 53c416 SCSI support' CONFIG_SCSI_SYM53C416 $CONFIG_SCSI + if [ "$CONFIG_PCI" = "y" ]; then ++ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ dep_tristate 'Tekram DC395/U/UW and DC315/U SCSI support' CONFIG_SCSI_DC395x_TRMS1040 $CONFIG_SCSI ++ fi + dep_tristate 'Tekram DC390(T) and Am53/79C974 SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI + if [ "$CONFIG_SCSI_DC390T" != "n" ]; then + bool ' _omit_ support for non-DC390 adapters' CONFIG_SCSI_DC390T_NOGENSUPP +diff -uNr linux-2.5.5-dj2/drivers/scsi/Makefile linux-2.5.5-dj2-dc395/drivers/scsi/Makefile +--- linux-2.5.5-dj2/drivers/scsi/Makefile Wed Feb 27 12:22:09 2002 ++++ linux-2.5.5-dj2-dc395/drivers/scsi/Makefile Thu Feb 28 06:03:55 2002 +@@ -104,6 +104,7 @@ + obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o + obj-$(CONFIG_SCSI_EATA) += eata.o + obj-$(CONFIG_SCSI_DC390T) += tmscsim.o ++obj-$(CONFIG_SCSI_DC395x_TRMS1040) += dc395x_trm.o + obj-$(CONFIG_SCSI_AM53C974) += AM53C974.o + obj-$(CONFIG_SCSI_MEGARAID) += megaraid.o + obj-$(CONFIG_SCSI_ACARD) += atp870u.o Index: dc395x_trm.c =================================================================== RCS file: /home/cvsroot/dc395/dc395x_trm.c,v retrieving revision 1.73 retrieving revision 1.77 diff -u -u -r1.73 -r1.77 --- dc395x_trm.c 2001/12/11 17:57:33 1.73 +++ dc395x_trm.c 2002/02/28 11:18:37 1.77 @@ -12,7 +12,7 @@ //* Kurt Garloff //* (C) 1999-2000 Kurt Garloff //* License: GNU GPL -//* $Id: dc395x_trm.c,v 1.73 2001/12/11 17:57:33 garloff Exp $ +//* $Id: dc395x_trm.c,v 1.77 2002/02/28 11:18:37 garloff Exp $ //*********************************************************************** //* Tekram PCI SCSI adapter (DC395/U/UW/F or DC315/U) revision history //* @@ -93,6 +93,14 @@ //* Try to work around extraneous 2 DOP bytes. //* Merge SG segments if possible. //* 1.35 01/12/06 KG Fix residual calculation. Add MODULE_LICENSE. +//* 1.35a 02/02/08 KG Ignore DMA errors; don't try stupid loop +//* to drain buffers. Set max_cmd_len to 24. +//* 1.36 02/02/27 KG Use pci_map() instead of virt_to_bus(). +//* Linux 2.5 Scsi_Host->host_lock locking +//* Slight variation of chip bug worked around :-( +//* 1.37 02/02/28 KG Free SRB's SG lists on module exit +//* Alloc in many chunks instead of one big +//* and don't waste memory by alignment. //*********************************************************************** /* ************************************************************************* @@ -188,7 +196,7 @@ # define TRACEOUTALL(x...) do {} while (0) #endif #ifdef DC395x_DEBUGTRACE -# define DEBUGTRACEBUFSZ 704 +# define DEBUGTRACEBUFSZ 512 char DC395x_tracebuf[64]; char DC395x_traceoverflow[8] = {0,0,0,0,0,0,0,0}; # define TRACEPRINTF(x...) \ @@ -270,11 +278,16 @@ #endif #ifdef USE_SPINLOCKS -# define DC395x_LOCK_IO spin_lock_irqsave (&io_request_lock, flags) -# define DC395x_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, flags) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) +# define DC395x_LOCK_IO(dev) spin_lock_irqsave (((struct Scsi_Host *)dev)->host_lock, flags) +# define DC395x_UNLOCK_IO(dev) spin_unlock_irqrestore (((struct Scsi_Host *)dev)->host_lock, flags) +# else +# define DC395x_LOCK_IO(dev) spin_lock_irqsave (&io_request_lock, flags) +# define DC395x_UNLOCK_IO(dev) spin_unlock_irqrestore (&io_request_lock, flags) +# endif #else -# define DC395x_LOCK_IO save_flags (flags); cli () -# define DC395x_UNLOCK_IO restore_flags (flags) +# define DC395x_LOCK_IO(dev) save_flags (flags); cli () +# define DC395x_UNLOCK_IO(dev) restore_flags (flags) #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) @@ -283,11 +296,15 @@ # 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_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_SCSI_DONE_ACB_LOCK spin_lock(&(pACB->smp_lock)) -# define DC395x_SCSI_DONE_ACB_UNLOCK spin_unlock(&(pACB->smp_lock)) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) +# define DC395x_SMP_IO_LOCK(dev,irq_flags) spin_lock_irqsave(((struct Scsi_Host *)dev)->host_lock,irq_flags) +# define DC395x_SMP_IO_UNLOCK(dev,irq_flags) spin_unlock_irqrestore(((struct Scsi_Host *)dev)->host_lock,irq_flags) +# else +# define DC395x_SMP_IO_LOCK(dev,irq_flags) spin_lock_irqsave(&io_request_lock,irq_flags) +# define DC395x_SMP_IO_UNLOCK(dev,irq_flags) spin_unlock_irqrestore(&io_request_lock,irq_flags) +# endif +# define DC395x_SCSI_DONE_ACB_LOCK spin_lock(&(pACB->smp_lock)) +# define DC395x_SCSI_DONE_ACB_UNLOCK spin_unlock(&(pACB->smp_lock)) #else @@ -295,16 +312,16 @@ # define DC395x_ACB_LOCK(pACB,acb_flags) do { save_flags(acb_flags); cli(); } while (0) # define DC395x_ACB_UNLOCK(pACB,acb_flags) do { restore_flags(acb_flags); } while (0) -# define DC395x_SMP_IO_LOCK(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_SMP_IO_LOCK(dev,irq_flags) do { save_flags(irq_flags); cli(); } while (0) +# define DC395x_SMP_IO_UNLOCK(dev,irq_flags) do { restore_flags(irq_flags); } while (0) # define DC395x_SCSI_DONE_ACB_LOCK # define DC395x_SCSI_DONE_ACB_UNLOCK #endif -# define DC395x_DRV_LOCK(drv_flags) do { save_flags(drv_flags); cli(); } while (0) -# define DC395x_DRV_UNLOCK(drv_flags) do { restore_flags(drv_flags); } while (0) +# define DC395x_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))) @@ -330,6 +347,42 @@ #define DC395x_write32(address,value) \ outl ((value), pACB->IOPortBase + (address)) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,16) +# define PCI_MAP_SINGLE(hw,ptr,sz,dir) pci_map_single(hw,ptr,sz,dir) +# define PCI_UNMAP_SINGLE(hw,dma,sz,dir) pci_unmap_single(hw,dma,sz,dir) +# define PCI_MAP_SG(hw,sg,n,dir) pci_map_sg(hw,sg,n,dir) +# define PCI_UNMAP_SG(hw,sg,n,dir) pci_unmap_sg(hw,sg,n,dir) +# define PCI_DMA_SYNC_SINGLE(hw,dma,sz,dir) pci_dma_sync_single(hw,dma,sz,dir) +# define PCI_DMA_SYNC_SG(hw,sg,n,dir) pci_dma_sync_sg(hw,sg,n,dir) +# define BUS_ADDR(sg) ((sg).dma_address) +# define CPU_ADDR(sg) (page_address((sg).page)+(sg).offset) +# define SET_DIR(dir,pcmd) dir = scsi_to_pci_dma_dir((pcmd)->sc_data_direction) +#else +# ifndef PCI_DMA_NONE +# define PCI_DMA_BIDIRECTIONAL 0 +# define PCI_DMA_TODEVICE 1 +# define PCI_DMA_FROMDEVICE 2 +# define PCI_DMA_NONE 3 +# endif +# define PCI_MAP_SINGLE(hw,ptr,sz,dir) virt_to_bus(ptr) +# define PCI_UNMAP_SINGLE(hw,dma,sz,dir) +# define PCI_MAP_SG(hw,sg,n,dir) +# define PCI_UNMAP_SG(hw,sg,n,dir) +# define PCI_DMA_SYNC_SINGLE(hw,dma,sz,dir) +# define PCI_DMA_SYNC_SG(hw,sg,n,dir) +# define BUS_ADDR(sg) (virt_to_bus((sg).address)) +# define CPU_ADDR(sg) ((sg).address) +# define SET_DIR(dir,pcmd) dir = PCI_DMA_BIDIRECTIONAL +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) +# define PAGE_ADDRESS(sg) page_address((sg)->page) +#else LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,16) +# define PAGE_ADDRESS(sg) (sg)->address +#endif + + /* cmd->result */ #define RES_TARGET 0x000000FF /* Target State */ #define RES_TARGET_LNX STATUS_MASK /* Only official ... */ @@ -386,7 +439,7 @@ /*-----------------------------------------------------------------------*/ typedef struct _SGentry { - DWORD address; + DWORD address; /* bus! address */ DWORD length; } SGentry, *PSGE0; @@ -397,48 +450,50 @@ */ struct _SRB { - struct _SRB *pNextSRB; - struct _DCB *pSRBDCB; + struct _SRB *pNextSRB; + struct _DCB *pSRBDCB; + + /* HW scatter list (up to 64 entries) */ + PSGE0 SegmentX; + PSCSICMD pcmd; + + /* Offset 0x20/0x10 */ + unsigned char* virt_addr; /* set by DC395x_update_SGlist */ - SGentry SegmentX[DC395x_MAX_SG_LISTENTRY]; + DWORD SRBTotalXferLength; + DWORD Xferred; /* Backup for the already xferred len */ - SGentry SgSenseTemp; - /* - ** make a one entry of S/G list table - ** use it as use_sg case when at request_buffer case - */ - PSCSICMD pcmd; - PSGE0 SRBSGListPointer; - - DWORD SRBTotalXferLength; - DWORD Xferred; /* Backup for the already xferred len */ - - long SRBSGBusAddr; /* a segment starting address */ - - WORD SRBState; - PBYTE pMsgPtr; - - BYTE SRBSGCount; - BYTE SRBSGIndex; - BYTE MsgInBuf[6]; - BYTE MsgOutBuf[6]; - - BYTE AdaptStatus; - BYTE TargetStatus; - BYTE MsgCnt; - BYTE EndMessage; - - BYTE TagNumber; - BYTE SRBStatus; - BYTE RetryCnt; - BYTE SRBFlag; - - BYTE ScsiPhase; - //BYTE IORBFlag; /* 81h-Reset, 2-retry */ - BYTE padding; - WORD debugpos; + DWORD SRBSGBusAddr; /* bus address of DC395x scatterlist */ + + WORD SRBState; + BYTE SRBSGCount; + BYTE SRBSGIndex; + + /* Offset 0x38/0x24 */ + BYTE MsgInBuf[6]; + BYTE MsgOutBuf[6]; + + BYTE AdaptStatus; + BYTE TargetStatus; + BYTE MsgCnt; + BYTE EndMessage; + + /* Offset 0x48/0x34 */ + PBYTE pMsgPtr; + + BYTE TagNumber; + BYTE SRBStatus; + BYTE RetryCnt; + BYTE SRBFlag; + + BYTE ScsiPhase; + //BYTE IORBFlag; /* 81h-Reset, 2-retry */ + BYTE padding; + WORD debugpos; + /* Offset 0x58/0x40 */ #ifdef DC395x_DEBUGTRACE - char debugtrace[DEBUGTRACEBUFSZ]; + char *debugtrace; + /* Offset 0x60/0x44 */ #endif }; typedef struct _SRB DC395X_TRM_SRB, *PSRB; @@ -566,7 +621,8 @@ BYTE MsgLen; BYTE DeviceCnt; - DC395X_TRM_SRB SRB_array[DC395x_MAX_SRB_CNT]; /* +45Ch, Len= */ + /* As every SRB is 768 bytes, don't use too many */ + DC395X_TRM_SRB SRB_array[40]; DC395X_TRM_SRB TmpSRB; }; typedef struct _ACB DC395X_TRM_ACB, *PACB; @@ -1096,8 +1152,10 @@ #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 */ +#define XFERDATAIN_SG 0x0103 /* Transfer data in w/ SG */ +#define XFERDATAOUT_SG 0x0102 /* Transfer data out w/ SG */ +#define XFERDATAIN 0x0101 /* Transfer data in w/o SG */ +#define XFERDATAOUT 0x0100 /* Transfer data out w/o SG */ /* **************************************** */ @@ -1516,6 +1574,9 @@ dc395x_trm[i] = ints[i+1]; /* DC395x_checkparams (); */ }; +#if 0 // For the editor's indenting :-) +} +#endif # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13) __setup("dc395x_trm=", DC395x_trm_setup); @@ -1837,12 +1898,13 @@ void DC395x_waiting_timed_out (unsigned long ptr) { unsigned int flags; + const PACB pACB = (PACB)ptr; #ifdef DC395x_DEBUG_KG printk ("DC395x: Debug: Waiting queue woken up by timer.\n"); #endif - DC395x_LOCK_IO; - DC395x_Waiting_process ((PACB)ptr); - DC395x_UNLOCK_IO; + DC395x_LOCK_IO(pACB->pScsiHost); + DC395x_Waiting_process (pACB); + DC395x_UNLOCK_IO(pACB->pScsiHost); } /* Get the DCB for a given ID/LUN combination */ @@ -1920,6 +1982,7 @@ PSGE0 sgp; struct scatterlist *sl; DWORD request_size; + int dir; #ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x_BuildSRB..............\n "); @@ -1927,13 +1990,16 @@ //memset (pSRB, 0, sizeof (DC395X_TRM_SRB)); pSRB->pSRBDCB = pDCB; pSRB->pcmd = pcmd; + // Find out about direction + SET_DIR(dir,pcmd); - if( pcmd->use_sg ) + if( pcmd->use_sg && dir != PCI_DMA_NONE) { unsigned int len = 0; + PCI_MAP_SG(pDCB->pDCBACB->pdev, (struct scatterlist*)pcmd->request_buffer, + pcmd->use_sg, dir); pSRB->SRBSGCount = pcmd->use_sg; - pSRB->SRBSGListPointer=(PSGE0) &pSRB->SegmentX[0]; - sgp = pSRB->SRBSGListPointer; + sgp = pSRB->SegmentX; request_size = pcmd->request_bufflen; #ifdef DC395x_SGPARANOIA printk(KERN_INFO "DC395x: BuildSRB: Bufflen = %d, buffer = %p, use_sg = %d\n", @@ -1946,9 +2012,10 @@ printk(KERN_INFO "DC395x: cmd->use_sg=%4d bigger then DC395x_MAX_SG_LISTENTRY=%4d for pid %li\n", pcmd->use_sg,DC395x_MAX_SG_LISTENTRY,pcmd->pid); } + pSRB->virt_addr = PAGE_ADDRESS(sl); for (i = 0; i < max; i++, sgp++) - { - DWORD busaddr = (DWORD) virt_to_bus (sl[i].address); + { + DWORD busaddr = (DWORD) BUS_ADDR(sl[i]); DWORD seglen = (DWORD) sl[i].length; if (i > 0 && ((sgp-1)->address + (sgp-1)->length) == busaddr && (sgp-1)->length + seglen <= 131072) { @@ -1988,23 +2055,39 @@ sgp->length++; } pSRB->SRBTotalXferLength = len; //? + /* Hopefully this does not cross a page boundary ... */ + pSRB->SRBSGBusAddr = PCI_MAP_SINGLE(pDCB->pDCBACB->pdev, pSRB->SegmentX, + sizeof(SGentry)*DC395x_MAX_SG_LISTENTRY, + PCI_DMA_TODEVICE); } - else if( pcmd->request_buffer ) + else if( pcmd->request_buffer && dir != PCI_DMA_NONE) { DWORD len = pcmd->request_bufflen; /* Actual request size */ pSRB->SRBSGCount = 1; - pSRB->SRBSGListPointer = (PSGE0) &pSRB->SegmentX[0];/* a one entry of S/G list table */ - pSRB->SegmentX[0].address = (DWORD) virt_to_bus( pcmd->request_buffer );/* Actual requested buffer */ + pSRB->SegmentX[0].address = PCI_MAP_SINGLE(pDCB->pDCBACB->pdev, + pcmd->request_buffer, len, dir); /* WIDE padding */ if (pDCB->SyncPeriod & WIDE_SYNC && len%2) len++; pSRB->SegmentX[0].length = len; pSRB->SRBTotalXferLength = len; + pSRB->virt_addr = pcmd->request_buffer; + pSRB->SRBSGBusAddr = 0; +#ifdef DC395x_SGPARANOIA + printk(KERN_INFO "DC395x: BuildSRB: len = %d, buffer = %p, use_sg = %d, map %08x\n", + len, pcmd->request_buffer, pcmd->use_sg, pSRB->SegmentX[0].address); +#endif } else { pSRB->SRBSGCount = 0; pSRB->SRBTotalXferLength = 0; + pSRB->SRBSGBusAddr = 0; + pSRB->virt_addr = 0; +#ifdef DC395x_SGPARANOIA + printk(KERN_INFO "DC395x: BuildSRB: buflen = %d, buffer = %p, use_sg = %d, NOMAP %08x\n", + pcmd->bufflen, pcmd->request_buffer, pcmd->use_sg, pSRB->SegmentX[0].address); +#endif } pSRB->SRBSGIndex = 0; @@ -2328,7 +2411,7 @@ 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->SegmentX, pSRB->SRBSGCount, pSRB->SRBSGIndex, pSRB->SRBTotalXferLength); printk (" State %04x Status %02x Phase %02x (%sconn.)\n", pSRB->SRBState, pSRB->SRBStatus, pSRB->ScsiPhase, @@ -2372,7 +2455,7 @@ if (/*lines & */1) { /* read */ - //DC395x_write8 (TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); + //DC395x_write8 (TRM_S1040_SCSI_CONTNTROL, DO_HWRESELECT | DO_DATALATCH); while (--ctr && !(DC395x_read16 (TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT)) { DC395x_write8(TRM_S1040_SCSI_SIGNAL, 0x48); @@ -2586,8 +2669,11 @@ 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); +#ifndef USE_NEW_EH + if (status == SCSI_ABORT_SUCCESS) { + // TODO: PCI_UNMAP + cmd->scsi_done(cmd); + } #endif DEBUGRECURSION(in_driver--;) return( status ); @@ -2818,11 +2904,11 @@ printk ("DC395x: ... but no cmd pending? Oops!\n"); return; } - DC395x_LOCK_IO; + DC395x_LOCK_IO(pACB->pScsiHost); pSRB = pACB->pActiveDCB->pActiveSRB; TRACEPRINTF("N/TO *"); DC395x_Disconnect (pACB); - DC395x_UNLOCK_IO; + DC395x_UNLOCK_IO(pACB->pScsiHost); } @@ -3080,7 +3166,7 @@ return; } - DC395x_LOCK_IO; + DC395x_LOCK_IO(pACB->pScsiHost); DEBUGRECURSION(if (in_driver++ > NORM_REC_LVL) printk ("DC395x: %i interrupt recursion?\n", in_driver);) @@ -3102,6 +3188,7 @@ if (dma_status & 0x20) { printk ("DC395x: Interrupt from DMA engine: %02x!\n", dma_status); +#if 0 printk ("DC395x: This means DMA error! Try to handle ...\n"); if (pACB->pActiveDCB) { @@ -3111,6 +3198,11 @@ } DC395x_write16 (TRM_S1040_DMA_CONTROL, ABORTXFER | CLRXFIFO); break; +#else + printk ("DC395x: Ignore and hope for the best ...\n"); + pACB = (PACB)-1; + break; +#endif } else pACB = pACB->pNextACB; @@ -3230,7 +3322,7 @@ } out_unlock: DEBUGRECURSION(in_driver--;) - DC395x_UNLOCK_IO; + DC395x_UNLOCK_IO(pACB->pScsiHost); //printk ("... done\n"); //DC395x_ACB_UNLOCK(pACB,acb_flags); return; @@ -3248,9 +3340,9 @@ { //if( cpuid != 0 ) // return; - //DC395x_LOCK_IO; + //DC395x_LOCK_IO(pACB->pScsiHost); DC395x_Interrupt(irq, dev_id, regs); - //DC395x_UNLOCK_IO; + //DC395x_UNLOCK_IO(pACB->pScsiHost); } #endif /* @@ -3276,6 +3368,7 @@ pSRB->SRBState &= ~SRB_MSGOUT; TRACEPRINTF ("MOP0 *"); } + /* ********************************************************************* ** scsiio @@ -3410,7 +3503,7 @@ { unsigned Length = 0; unsigned Idx = pSRB->SRBSGIndex; - PSGE0 psge = pSRB->SRBSGListPointer + Idx; + PSGE0 psge = pSRB->SegmentX + Idx; for ( ; Idx < pSRB->SRBSGCount; psge++, Idx++) Length += psge->length; if (Length != pSRB->SRBTotalXferLength) @@ -3427,7 +3520,7 @@ { PACB pACB = pSRB->pSRBDCB->pDCBACB; DWORD len = 0; - PSGE0 psge = pSRB->SRBSGListPointer + pSRB->SRBSGIndex; + PSGE0 psge = pSRB->SegmentX + pSRB->SRBSGIndex; unsigned dma_idx = DC395x_read32 (TRM_S1040_DMA_CXCNT) >> 3; while (dma_idx-- > 0) { len += psge->length; psge++; } if (tx < len || tx > (len + psge->length)) @@ -3440,27 +3533,30 @@ #endif /* Compute the next Scatter Gather list index and adjust its length - * and address if necessary */ + * and address if necessary; also compute virt_addr */ void DC395x_update_SGlist (PSRB pSRB, DWORD Left) { PSGE0 psge; - DWORD Xferred; + DWORD Xferred = 0; BYTE Idx; + PSCSICMD pcmd = pSRB->pcmd; + struct scatterlist *sg; + int segment = pcmd->use_sg; #ifdef DC395x_DEBUG_KG printk ("DC395x: Update SG: Total %i, Left %i\n", pSRB->SRBTotalXferLength, Left); #endif DC395x_check_SG (pSRB); + psge = pSRB->SegmentX + pSRB->SRBSGIndex; + /* data that has already been transferred */ + Xferred = pSRB->SRBTotalXferLength - Left; if (pSRB->SRBTotalXferLength != Left) { - /* 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 */ @@ -3472,12 +3568,43 @@ psge->length -= Xferred; /* residue data length */ psge->address += Xferred; /* residue data pointer */ pSRB->SRBSGIndex = Idx; + PCI_DMA_SYNC_SINGLE(pSRB->pSRBDCB->pDCBACB->pdev, + pSRB->SRBSGBusAddr, + sizeof(SGentry)*DC395x_MAX_SG_LISTENTRY, + PCI_DMA_TODEVICE); break; } psge++; } DC395x_check_SG (pSRB); } + /* We need the corresponding virtual address sg_to_virt */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,16) + pSRB->virt_addr = bus_to_virt (psge->address); + return; +#else + //printk ("DC395x: sg_to_virt: bus %08x -> virt ", psge->address); + if (!segment) { + pSRB->virt_addr += Xferred; + //printk ("%p\n", pSRB->virt_addr); + return; + } + /* We have to walk the scatterlist to find it */ + sg = (struct scatterlist*) pcmd->request_buffer; + while (segment--) { + //printk ("(%08x)%p ", BUS_ADDR(*sg), PAGE_ADDRESS(sg)); + unsigned long mask = ~((unsigned long)sg->length-1) & PAGE_MASK; + if ((BUS_ADDR(*sg) & mask) == (psge->address & mask)) { + pSRB->virt_addr = (PAGE_ADDRESS(sg) + + psge->address - (psge->address & PAGE_MASK)); + //printk ("%p\n", pSRB->virt_addr); + return; + } + ++sg; + } + printk ("DC395x: sg_to_virt failed!\n"); + pSRB->virt_addr = 0; +#endif } /* @@ -3512,7 +3639,7 @@ //1.25 DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH); } - + /* Those no of bytes will be transfered w/ PIO through the SCSI FIFO * * Seems to be needed for unknown reasons; could be a hardware bug :-( */ @@ -3545,7 +3672,7 @@ * This means telling the DMA to push the rest into SCSI, telling * SCSI to push the rest to the bus. * However, the device might have been the one to stop us (phase - * change), the the data in transit just needs to be accounted so + * change), and the data in transit just needs to be accounted so * it can be retransmitted.) */ /* @@ -3553,11 +3680,12 @@ * If we need more data, the DMA SG list will be freshly set up, anyway */ #ifdef DC395x_DEBUGPIO - printk ("DC395x: DOP1: DMA_FCNT: %04x, SCSI_FCNT: %02x, CTR %06x, stat %04x, Tot: %06x\n", + printk ("DC395x: DOP0: DMA_FCNT: %04x, SCSI_FCNT: %02x, CTR %06x, stat %04x, Tot: %06x\n", DC395x_read16 (TRM_S1040_DMA_FIFOCNT), - DC395x_read8 (TRM_S1040_SCSI_FIFOCNT), + DC395x_read8 (TRM_S1040_SCSI_FIFOCNT), DC395x_read32 (TRM_S1040_SCSI_COUNTER), scsi_status, pSRB->SRBTotalXferLength); + //DC395x_dumpinfo(pACB, pDCB, pSRB); #endif DC395x_write16 (TRM_S1040_DMA_CONTROL, STOPDMAXFER | CLRXFIFO); @@ -3645,15 +3773,20 @@ ** there were some data residue in SCSI FIFO or ** SCSI transfer counter not empty */ + long oldXferred = pSRB->SRBTotalXferLength - dLeftCounter; + const int diff = (pDCB->SyncPeriod & WIDE_SYNC)? 2: 1; DC395x_update_SGlist (pSRB, dLeftCounter); /* KG: Most ugly hack! Apparently, this works around a chip bug */ - if (pDCB->SyncPeriod & WIDE_SYNC && - pSRB->SRBSGListPointer[pSRB->SRBSGIndex].length == 2 && - pSRB->SRBSGIndex + 2 == pSRB->SRBSGCount) { - printk ("DC395x: Work around chip bug?\n"); - //dLeftCounter -= 2; - pSRB->SRBTotalXferLength -= 2; - pSRB->SRBSGIndex++; + if ( (pSRB->SegmentX[pSRB->SRBSGIndex].length == diff && pSRB->pcmd->use_sg) + || ((oldXferred & ~PAGE_MASK) == (PAGE_SIZE-diff)) + ) { + printk ("DC395x: Work around chip bug (%i)?\n", diff); + dLeftCounter = pSRB->SRBTotalXferLength - diff; + DC395x_update_SGlist (pSRB, dLeftCounter); + //pSRB->SRBTotalXferLength -= diff; + //pSRB->virt_addr += diff; + //if (pSRB->pcmd->use_sg) + // pSRB->SRBSGIndex++; } } } @@ -3746,7 +3879,7 @@ // the DMA FIFO to become empty? How do we know, that the device not already // sent data to the FIFO in a MsgIn phase, eg.? if (!(DC395x_read16 (TRM_S1040_DMA_FIFOCNT) & 0x8000)) { -#if 1 +#if 0 int ctr = 6000000; printk ("DC395x: DIP0: Wait for DMA FIFO to flush ...\n"); //DC395x_write16 (TRM_S1040_DMA_CONTROL, STOPDMAXFER); @@ -3784,15 +3917,13 @@ /* KG: Less than or equal to 4 bytes can not be transfered via DMA, it seems. */ if (dLeftCounter && pSRB->SRBTotalXferLength <= DC395x_LASTPIO) { - //DWORD addr = (pSRB->SRBSGListPointer[pSRB->SRBSGIndex].address); - char *ptr; - DC395x_update_SGlist (pSRB, dLeftCounter); - ptr = bus_to_virt(pSRB->SRBSGListPointer[pSRB->SRBSGIndex].address); + //DWORD addr = (pSRB->SegmentX[pSRB->SRBSGIndex].address); + //DC395x_update_SGlist (pSRB, dLeftCounter); DEBUGPIO( printk ("DC395x: DIP0: PIO (%i %s) to %p for remaining %i bytes:", DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x1f, (pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC)? "words": "bytes", - ptr, pSRB->SRBTotalXferLength); + pSRB->virt_addr, pSRB->SRBTotalXferLength); ) if (pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC) @@ -3801,13 +3932,13 @@ while (DC395x_read8(TRM_S1040_SCSI_FIFOCNT) != 0x40) { BYTE byte = DC395x_read8 (TRM_S1040_SCSI_FIFO); - *ptr++ = byte; DEBUGPIO(printk (" %02x", byte);) - pSRB->SRBTotalXferLength--; - pSRB->SRBSGListPointer[pSRB->SRBSGIndex].length--; - if (pSRB->SRBTotalXferLength && !pSRB->SRBSGListPointer[pSRB->SRBSGIndex].length) { + *(pSRB->virt_addr)++ = byte; DEBUGPIO(printk (" %02x", byte);) + pSRB->SRBTotalXferLength--; dLeftCounter--; + pSRB->SegmentX[pSRB->SRBSGIndex].length--; + if (pSRB->SRBTotalXferLength && !pSRB->SegmentX[pSRB->SRBSGIndex].length) { DEBUGPIO(printk (" (next segment)");) pSRB->SRBSGIndex++; - ptr = bus_to_virt(pSRB->SRBSGListPointer[pSRB->SRBSGIndex].address); + DC395x_update_SGlist (pSRB, dLeftCounter); } } if (pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC) @@ -3816,7 +3947,7 @@ if (pSRB->SRBTotalXferLength > 0) { BYTE byte = DC395x_read8 (TRM_S1040_SCSI_FIFO); - *ptr++ = byte; pSRB->SRBTotalXferLength--; + *(pSRB->virt_addr)++ = byte; pSRB->SRBTotalXferLength--; DEBUGPIO(printk (" %02x", byte);) } #endif @@ -3956,7 +4087,7 @@ #ifdef DC395x_DEBUG0 printk(KERN_INFO "DC395x: DataIO_transfer %c (pid %li): len = %i, SG: %i/%i\n", - (ioDir == XFERDATAOUT? 'w': 'r'), pSRB->pcmd->pid, + ((ioDir & DMACMD_DIR)? 'r': 'w'), pSRB->pcmd->pid, pSRB->SRBTotalXferLength, pSRB->SRBSGIndex, pSRB->SRBSGCount); #endif TRACEPRINTF("%05x(%i/%i)*", pSRB->SRBTotalXferLength, @@ -3979,34 +4110,38 @@ DC395x_write8 (TRM_S1040_DMA_CONTROL, CLRXFIFO); } //DC395x_clrfifo (pACB, "IO"); - pSRB->SRBSGBusAddr = virt_to_bus (pSRB->SRBSGListPointer + pSRB->SRBSGIndex); /* ** load what physical address of Scatter/Gather list table want to be ** transfer */ pSRB->SRBState |= SRB_DATA_XFER; DC395x_write32(TRM_S1040_DMA_XHIGHADDR, 0); - DC395x_write32(TRM_S1040_DMA_XLOWADDR, pSRB->SRBSGBusAddr); - /* load how many bytes in the Scatter/Gather list table */ - DC395x_write32(TRM_S1040_DMA_XCNT, ((DWORD) (pSRB->SRBSGCount - pSRB->SRBSGIndex) << 3)); + if (pSRB->pcmd->use_sg) { /* with S/G */ + ioDir |= DMACMD_SG; + DC395x_write32(TRM_S1040_DMA_XLOWADDR, pSRB->SRBSGBusAddr+sizeof(SGentry)*pSRB->SRBSGIndex); + /* load how many bytes in the Scatter/Gather list table */ + DC395x_write32(TRM_S1040_DMA_XCNT, ((DWORD) (pSRB->SRBSGCount - pSRB->SRBSGIndex) << 3)); + } else { /* without S/G */ + ioDir &= ~DMACMD_SG; + DC395x_write32(TRM_S1040_DMA_XLOWADDR, pSRB->SegmentX[0].address); + DC395x_write32(TRM_S1040_DMA_XCNT, pSRB->SegmentX[0].length); + } /* load total transfer length (24bits) max value 16Mbyte */ DC395x_write32(TRM_S1040_SCSI_COUNTER, pSRB->SRBTotalXferLength); DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/ - if (ioDir == XFERDATAOUT) { - DC395x_write16(TRM_S1040_DMA_COMMAND, ioDir); - DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_OUT); - } - else - { + if (ioDir & DMACMD_DIR) /* read */ { DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN); DC395x_write16(TRM_S1040_DMA_COMMAND, ioDir); + } else { + DC395x_write16(TRM_S1040_DMA_COMMAND, ioDir); + DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_OUT); } + } #if DC395x_LASTPIO else if (pSRB->SRBTotalXferLength > 0) { /* The last four bytes: Do PIO */ //DC395x_clrfifo (pACB, "IO"); - pSRB->SRBSGBusAddr = virt_to_bus (pSRB->SRBSGListPointer + pSRB->SRBSGIndex); /* ** load what physical address of Scatter/Gather list table want to be ** transfer @@ -4015,23 +4150,24 @@ /* load total transfer length (24bits) max value 16Mbyte */ DC395x_write32(TRM_S1040_SCSI_COUNTER, pSRB->SRBTotalXferLength); DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH);/* it's important for atn stop*/ - if (ioDir == XFERDATAOUT) { - char *ptr = bus_to_virt (pSRB->SRBSGListPointer[pSRB->SRBSGIndex].address); + if (ioDir & DMACMD_DIR) { /* read */ + DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN); + } else { /* write */ int ln = pSRB->SRBTotalXferLength; if (pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC) DC395x_write8 (TRM_S1040_SCSI_CONFIG2, CFG2_WIDEFIFO); DEBUGPIO(printk ("DC395x: DOP1: PIO %i bytes from %p:", - pSRB->SRBTotalXferLength, ptr);) + pSRB->SRBTotalXferLength, pSRB->virt_addr);) while (pSRB->SRBTotalXferLength) { - DEBUGPIO(printk (" %02x", (unsigned char)*ptr);) - DC395x_write8 (TRM_S1040_SCSI_FIFO, *ptr++); + DEBUGPIO(printk (" %02x", (unsigned char)*(pSRB->virt_addr));) + DC395x_write8 (TRM_S1040_SCSI_FIFO, *(pSRB->virt_addr)++); pSRB->SRBTotalXferLength--; - pSRB->SRBSGListPointer[pSRB->SRBSGIndex].length--; - if (pSRB->SRBTotalXferLength && !pSRB->SRBSGListPointer[pSRB->SRBSGIndex].length) { + pSRB->SegmentX[pSRB->SRBSGIndex].length--; + if (pSRB->SRBTotalXferLength && !pSRB->SegmentX[pSRB->SRBSGIndex].length) { DEBUGPIO(printk (" (next segment)");) pSRB->SRBSGIndex++; - ptr = bus_to_virt (pSRB->SRBSGListPointer[pSRB->SRBSGIndex].address); + DC395x_update_SGlist (pSRB, pSRB->SRBTotalXferLength); } } if (pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC) { @@ -4045,10 +4181,6 @@ DEBUGPIO(printk ("\n");) DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); } - else - { - DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN); - } } #endif /* DC395x_LASTPIO */ else /* xfer pad */ @@ -4066,17 +4198,15 @@ { DC395x_write32(TRM_S1040_SCSI_COUNTER, 2); DC395x_write8 (TRM_S1040_SCSI_CONFIG2, CFG2_WIDEFIFO); - /* Danger, Robinson: If you find KGs scattered over the wide - * disk, the driver or chip is to blame :-( */ - if (ioDir == XFERDATAOUT) { - DC395x_write8 (TRM_S1040_SCSI_FIFO, 'K'); - DC395x_write8 (TRM_S1040_SCSI_FIFO, 'G'); - } - else - { + if (ioDir & DMACMD_DIR) /* read */ { data = DC395x_read8(TRM_S1040_SCSI_FIFO); data2 = DC395x_read8(TRM_S1040_SCSI_FIFO); //printk ("DC395x: DataIO: Xfer pad: %02x %02x\n", data, data2); + } else { + /* Danger, Robinson: If you find KGs scattered over the wide + * disk, the driver or chip is to blame :-( */ + DC395x_write8 (TRM_S1040_SCSI_FIFO, 'K'); + DC395x_write8 (TRM_S1040_SCSI_FIFO, 'G'); } DC395x_write8 (TRM_S1040_SCSI_CONFIG2, 0); } @@ -4085,12 +4215,11 @@ DC395x_write32(TRM_S1040_SCSI_COUNTER, 1); /* Danger, Robinson: If you find a collection of Ks on your disk * something broke :-( */ - if (ioDir == XFERDATAOUT) - DC395x_write8(TRM_S1040_SCSI_FIFO, 'K'); - else - { + if (ioDir & DMACMD_DIR) { /* read */ data = DC395x_read8(TRM_S1040_SCSI_FIFO); //printk ("DC395x: DataIO: Xfer pad: %02x\n", data); + } else { + DC395x_write8(TRM_S1040_SCSI_FIFO, 'K'); } } pSRB->SRBState |= SRB_XFERPAD; @@ -4098,7 +4227,7 @@ /* ** SCSI command */ - bval = (ioDir == XFERDATAOUT) ? SCMD_FIFO_OUT : SCMD_FIFO_IN; + bval = (ioDir & DMACMD_DIR) ? SCMD_FIFO_IN : SCMD_FIFO_OUT; DC395x_write8(TRM_S1040_SCSI_COMMAND, bval); } } @@ -4465,6 +4594,7 @@ pSRB->pSegmentList++; psgl = pSRB->pSegmentList; + /* And here we have to use the pci map ! */ pSRB->SGBusAddr = virt_to_bus( psgl->address ); pSRB->SGToBeXferLen = (ULONG) psgl->length; } @@ -5112,13 +5242,15 @@ PSCSICMD pcmd; PSCSI_INQDATA ptr; //DWORD drv_flags=0; + int dir; pcmd = pSRB->pcmd; TRACEPRINTF("DONE *"); + SET_DIR(dir,pcmd); ptr = (PSCSI_INQDATA) (pcmd->request_buffer); if( pcmd->use_sg ) - ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); + ptr = (PSCSI_INQDATA) CPU_ADDR(*(PSGL)ptr); #ifdef DC395x_SGPARANOIA printk (KERN_INFO "DC395x: SRBdone SG=%i (%i/%i), req_buf = %p, adr = %p\n", pcmd->use_sg, pSRB->SRBSGIndex, pSRB->SRBSGCount, pcmd->request_buffer, ptr); @@ -5133,13 +5265,16 @@ #ifdef DC395x_DEBUG0 printk(KERN_INFO "AUTO_REQSENSE1..............\n "); #endif + /* Unmap sense buffer */ + PCI_UNMAP_SINGLE(pACB->pdev, pSRB->SegmentX[0].address, + pSRB->SegmentX[0].length, PCI_DMA_FROMDEVICE); /* ** target status.......................... */ pSRB->SRBFlag &= ~AUTO_REQSENSE; pSRB->AdaptStatus = 0; pSRB->TargetStatus = CHECK_CONDITION << 1; -#ifdef DC395x_DEBUG_KG +#ifdef DC395x_DEBUG_KG switch (pcmd->sense_buffer[2] & 0x0f) { case NOT_READY: printk ("\nDC395x: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", @@ -5179,9 +5314,9 @@ #endif // Restore SG stuff //printk ("Auto_ReqSense finished: Restore Counters ...\n"); - pSRB->SRBTotalXferLength = pSRB->Xferred; - pSRB->SegmentX[0].address = pSRB->SgSenseTemp.address; - pSRB->SegmentX[0].length = pSRB->SgSenseTemp.length; + pSRB->SRBTotalXferLength = pSRB->Xferred; + pSRB->SegmentX[0].address = pSRB->SegmentX[DC395x_MAX_SG_LISTENTRY-1].address; + pSRB->SegmentX[0].length = pSRB->SegmentX[DC395x_MAX_SG_LISTENTRY-1].length; if( (pSRB->SRBTotalXferLength) && (pSRB->SRBTotalXferLength >= pcmd->underflow) ) pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,pSRB->EndMessage,CHECK_CONDITION); @@ -5264,10 +5399,17 @@ } } + if (pcmd->use_sg && dir != PCI_DMA_NONE) + PCI_DMA_SYNC_SG(pACB->pdev, (struct scatterlist*)pcmd->request_buffer, + pcmd->use_sg, dir); + else if (pcmd->request_buffer && dir != PCI_DMA_NONE) + PCI_DMA_SYNC_SINGLE(pACB->pdev, pSRB->SegmentX[0].address, + pcmd->request_bufflen, dir); if ((pcmd->result & RES_DID) == 0 && pcmd->cmnd[0] == INQUIRY && pcmd->cmnd[2] == 0 && pcmd->request_bufflen >= 8 && + dir != PCI_DMA_NONE && ptr && (ptr->Vers & 0x07) >= 2) pDCB->Inquiry7 = ptr->Flags; @@ -5374,6 +5516,17 @@ printk (" 0x%08x\n", pcmd->result); #endif TRACEPRINTF("%08x(%li)*", pcmd->result, jiffies); + if (pcmd->use_sg && dir != PCI_DMA_NONE) { + /* unmap DC395x SG list */ + PCI_UNMAP_SINGLE(pACB->pdev, pSRB->SRBSGBusAddr, + sizeof(SGentry)*DC395x_MAX_SG_LISTENTRY, PCI_DMA_TODEVICE); + /* unmap the sg segments */ + PCI_UNMAP_SG(pACB->pdev, (struct scatterlist*)pcmd->request_buffer, + pcmd->use_sg, dir); + } + else if (pcmd->request_buffer && dir != PCI_DMA_NONE) + PCI_UNMAP_SINGLE(pACB->pdev, pSRB->SegmentX[0].address, + pcmd->request_bufflen, dir); //DC395x_UNLOCK_ACB_NI; pcmd->scsi_done (pcmd); //DC395x_LOCK_ACB_NI; @@ -5431,6 +5584,7 @@ /* For new EH, don't give commands back */ pcmd->result = result; //DC395x_SCSI_DONE_ACB_UNLOCK; + // TODO: PCI_UNMAP pcmd->scsi_done( pcmd ); //DC395x_SCSI_DONE_ACB_LOCK; #endif @@ -5468,6 +5622,7 @@ /* For new EH, don't give commands back */ pcmd->result = result; //DC395x_SCSI_DONE_ACB_UNLOCK; + // TODO: PCI_UNMAP pcmd->scsi_done( pcmd ); //DC395x_SCSI_DONE_ACB_LOCK; #endif @@ -5609,19 +5764,21 @@ pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; + /* KG: Can this prevent crap sense data ? */ + memset (pcmd->sense_buffer, 0, sizeof(pcmd->sense_buffer)); + /* Save some data */ - pSRB->SgSenseTemp.address = pSRB->SegmentX[0].address; - pSRB->SgSenseTemp.length = pSRB->SegmentX[0].length; + pSRB->SegmentX[DC395x_MAX_SG_LISTENTRY-1].address = pSRB->SegmentX[0].address; + pSRB->SegmentX[DC395x_MAX_SG_LISTENTRY-1].length = pSRB->SegmentX[0].length; pSRB->Xferred = pSRB->SRBTotalXferLength; /* pSRB->SegmentX : a one entry of S/G list table */ - pSRB->SRBTotalXferLength = sizeof(pcmd->sense_buffer); - pSRB->SegmentX[0].address = (DWORD) virt_to_bus (pcmd->sense_buffer); - pSRB->SegmentX[0].length = sizeof(pcmd->sense_buffer); - pSRB->SRBSGListPointer = &pSRB->SegmentX[0]; + pSRB->SRBTotalXferLength = sizeof(pcmd->sense_buffer); + pSRB->SegmentX[0].length = sizeof(pcmd->sense_buffer); + /* Map sense buffer */ + pSRB->SegmentX[0].address = PCI_MAP_SINGLE(pACB->pdev, pcmd->sense_buffer, + sizeof(pcmd->sense_buffer), PCI_DMA_FROMDEVICE); pSRB->SRBSGCount = 1; pSRB->SRBSGIndex = 0; - /* KG: Can this prevent crap sense data ? */ - memset (pcmd->sense_buffer, 0, sizeof(pcmd->sense_buffer)); if( DC395x_StartSCSI( pACB, pDCB, pSRB ) ) { /* Should only happen, if sb. else grabs the bus */ @@ -5774,6 +5931,85 @@ } +/* Dynamically allocated memory handling */ + +#ifdef DC395x_DEBUGTRACE +/* Memory for trace buffers */ +void DC395x_free_tracebufs (PACB pACB, int SRBIdx) +{ + int srbidx; + const unsigned bufs_per_page = PAGE_SIZE/DEBUGTRACEBUFSZ; + for (srbidx = 0; srbidx < SRBIdx; srbidx += bufs_per_page) + kfree (pACB->SRB_array[srbidx].debugtrace); +} + +int DC395x_alloc_tracebufs (PACB pACB) +{ + const unsigned mem_needed = (DC395x_MAX_SRB_CNT + 1) * DEBUGTRACEBUFSZ; + int pages = (mem_needed + (PAGE_SIZE-1)) / PAGE_SIZE; + const unsigned bufs_per_page = PAGE_SIZE/DEBUGTRACEBUFSZ; + int SRBIdx = 0; unsigned i = 0; + unsigned char *ptr; + //printk ("DC395x: Alloc %i pages for tracebufs\n", pages); + while (pages--) { + ptr = kmalloc (PAGE_SIZE, GFP_KERNEL); + if (!ptr) { + DC395x_free_tracebufs (pACB, SRBIdx); + return 1; + } + i = 0; + while (i < bufs_per_page && SRBIdx < DC395x_MAX_SRB_CNT) + pACB->SRB_array[SRBIdx++].debugtrace + = ptr + (i++*DEBUGTRACEBUFSZ); + } + if (i < bufs_per_page) + pACB->TmpSRB.debugtrace = ptr + (i*DEBUGTRACEBUFSZ); + else + printk ("DC395x: No space for tmpSRB tracebuf reserved?!\n"); + return 0; +} +#endif + +/* Free SG tables */ +void DC395x_free_SG_tables (PACB pACB, int SRBIdx) +{ + int srbidx; + const unsigned SRBs_per_page = PAGE_SIZE/(DC395x_MAX_SG_LISTENTRY * sizeof(SGentry)); + for (srbidx = 0; srbidx < SRBIdx; srbidx += SRBs_per_page) + kfree (pACB->SRB_array[srbidx].SegmentX); +} + +/* Allocate SG tables; as we have to pci_map them, an SG list (PSGE0) + * should never cross a page boundary */ +int DC395x_alloc_SG_tables (PACB pACB) +{ + const unsigned mem_needed = (DC395x_MAX_SRB_CNT + 1) + * DC395x_MAX_SG_LISTENTRY * sizeof(SGentry); + int pages = (mem_needed + (PAGE_SIZE-1)) / PAGE_SIZE; + const unsigned SRBs_per_page = PAGE_SIZE + / (DC395x_MAX_SG_LISTENTRY * sizeof(SGentry)); + int SRBIdx = 0; unsigned i = 0; + PSGE0 ptr; + //printk ("DC395x: Alloc %i pages for SG tables\n", pages); + while (pages--) { + ptr = (PSGE0)kmalloc (PAGE_SIZE, GFP_KERNEL); + if (!ptr) { + DC395x_free_SG_tables (pACB, SRBIdx); + return 1; + } + i = 0; + while (i < SRBs_per_page && SRBIdx < DC395x_MAX_SRB_CNT) + pACB->SRB_array[SRBIdx++].SegmentX + = ptr + (i++*DC395x_MAX_SG_LISTENTRY); + } + if (i < SRBs_per_page) + pACB->TmpSRB.SegmentX = ptr + (i*DC395x_MAX_SG_LISTENTRY); + else + printk ("DC395x: No space for tmpSRB SG table reserved?!\n"); + return 0; +} + + /* ********************************************************************* ** scsiio @@ -5802,13 +6038,16 @@ ** ************************************************************************ */ -void __init DC395x_initACB( PSH psh, DWORD io_port, BYTE Irq, WORD index ) +int __init DC395x_initACB( PSH psh, DWORD io_port, BYTE Irq, WORD index ) { PNVRAMTYPE pEEpromBuf; PACB pACB; WORD i; pEEpromBuf = &dc395x_trm_eepromBuf[index]; +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30) + psh->max_cmd_len = 24; +#endif psh->can_queue = DC395x_MAX_CMD_QUEUE; psh->cmd_per_lun = DC395x_MAX_CMD_PER_LUN; psh->this_id = (int) pEEpromBuf->NvramScsiId; @@ -5858,7 +6097,19 @@ pACB->LUNchk = 1; /* ** link all device's SRB Q of this adapter - */ + */ + + if (DC395x_alloc_SG_tables (pACB)) { + printk ("DC395x: SG table allocation failed!\n"); + return 1; + } +#ifdef DC395x_DEBUGTRACE + if (DC395x_alloc_tracebufs (pACB)) { + printk ("DC395x: SG trace buffer allocation failed!\n"); + DC395x_free_SG_tables (pACB, DC395x_MAX_SRB_CNT); + return 1; + } +#endif DC395x_linkSRB( pACB ); pACB->pFreeSRB = pACB->SRB_array; /* @@ -5871,12 +6122,13 @@ for (i = 0; i < DC395x_MAX_SCSI_ID; i++) pACB->DCBmap[i] = 0; -#ifdef DC395x_DEBUG0 +#if 1//def DC395x_DEBUG0 printk(KERN_INFO "DC395x: pACB = %p, pDCBmap = %p, pSRB_array = %p\n", pACB, pACB->DCBmap, pACB->SRB_array); printk(KERN_INFO "DC395x: ACB size= %04x, DCB size= %04x, SRB size= %04x\n", sizeof(DC395X_TRM_ACB), sizeof(DC395X_TRM_DCB), sizeof(DC395X_TRM_SRB) ); #endif + return 0; } @@ -6363,7 +6615,11 @@ //DC395x_ACB_INITLOCK(pACB); //DC395x_ACB_LOCK(pACB,acb_flags); //$$$$$$$$ INITIAL ADAPTER CONTROL BLOCK $$$$$$$$$$$$ - DC395x_initACB( psh, io_port, Irq, index ); + if (DC395x_initACB( psh, io_port, Irq, index )) { + scsi_unregister (psh); + //DC395x_ACB_UNLOCK(pACB,acb_flags); + return 0; + } DC395x_print_config (pACB); //$$$$$$$$$$$$$$$$$ INITIAL ADAPTER $$$$$$$$$$$$$$$$$ if( !DC395x_initAdapter( psh, io_port, Irq, index ) ) @@ -6550,7 +6806,7 @@ #ifndef USE_NEW_EH DWORD flags; - DC395x_LOCK_IO; // Don't lock for new EH + //DC395x_LOCK_IO; // Don't lock for new EH #endif DC395x_pACB_start = NULL; @@ -6626,7 +6882,7 @@ //printk (KERN_WARNING "DC395x: *** WARNING: This driver is not completely stable! ***\n"); #ifndef USE_NEW_EH - DC395x_UNLOCK_IO; + //DC395x_UNLOCK_IO; #endif return( DC395x_adapterCnt ); } @@ -6713,7 +6969,22 @@ pDCB->TargetID, pDCB->TargetLUN); DC395x_queue_command (cmd, DC395x_inquiry_done); }; - + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) +static char *DC395x_strtok_ptr; +static char* DC395x_strtok (char* init, char* sep) +{ + char* ptr; + if (init) + DC395x_strtok_ptr = init; + do { + ptr = strsep (&DC395x_strtok_ptr, sep); + } while (ptr && *ptr == 0); + return ptr; +} +# define strtok DC395x_strtok +#endif + /* ******************************************************************* ** @@ -6812,7 +7083,7 @@ unsigned long flags; pos[length] = 0; - DC395x_LOCK_IO; + DC395x_LOCK_IO(pACB->pScsiHost); /* UPPERCASE */ /* Don't use kernel toupper, because of 2.0.x bug: ctmp unexported */ while (*pos) @@ -6986,7 +7257,7 @@ //DC395x_ACB_UNLOCK(acb_flags); if (needs_inquiry) { DC395x_updateDCB (pACB, pDCB); DC395x_inquiry (pACB, pDCB); }; - DC395x_UNLOCK_IO; + DC395x_UNLOCK_IO(pACB->pScsiHost); return (length); einv2: @@ -6994,7 +7265,7 @@ einv: /* spin_unlock (strtok_lock); */ //DC395x_ACB_UNLOCK(acb_flags); - DC395x_UNLOCK_IO; + DC395x_UNLOCK_IO(pACB->pScsiHost); printk (KERN_WARNING "DC395x: parse error near \"%s\"\n", (pos? pos: "NULL")); return (-EINVAL); @@ -7004,14 +7275,14 @@ printk (KERN_WARNING "DC395x: Driver reset requested!\n"); //DC395x_ACB_UNLOCK(acb_flags); DC395x_reset (&cmd, 0); - DC395x_UNLOCK_IO; + DC395x_UNLOCK_IO(pACB->pScsiHost); }; return (length); dump: { DC395x_dumpinfo (pACB, 0, 0); - DC395x_UNLOCK_IO; + DC395x_UNLOCK_IO(pACB->pScsiHost); }; return length; @@ -7025,7 +7296,7 @@ dev, pDCB->TargetID, pDCB->TargetLUN); //DC395x_ACB_UNLOCK(acb_flags); DC395x_inquiry (pACB, pDCB); - DC395x_UNLOCK_IO; + DC395x_UNLOCK_IO(pACB->pScsiHost); }; return (length); @@ -7040,7 +7311,7 @@ /* TO DO: We should make sure no pending commands are left */ DC395x_remove_dev (pACB, pDCB); //DC395x_ACB_UNLOCK(acb_flags); - DC395x_UNLOCK_IO; + DC395x_UNLOCK_IO(pACB->pScsiHost); }; return (length); @@ -7055,7 +7326,7 @@ DC395x_initDCB (pACB, &pDCB, id, lun); //DC395x_ACB_UNLOCK(acb_flags); DC395x_inquiry (pACB, pDCB); - DC395x_UNLOCK_IO; + DC395x_UNLOCK_IO(pACB->pScsiHost); }; return (length); @@ -7063,7 +7334,7 @@ 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; + DC395x_UNLOCK_IO(pACB->pScsiHost); return (-EINVAL); } @@ -7140,7 +7411,7 @@ SPRINTF(DC395x_BANNER " PCI SCSI Host Adapter\n"); SPRINTF(" Driver Version " DC395x_VERSION "\n"); - DC395x_LOCK_IO; + DC395x_LOCK_IO(pACB->pScsiHost); SPRINTF("SCSI Host Nr %i, ", shpnt->host_no); SPRINTF("DC395U/UW/F DC315/U %s Adapter Nr %i\n", @@ -7239,7 +7510,7 @@ #endif *start = buffer + offset; - DC395x_UNLOCK_IO; + DC395x_UNLOCK_IO(pACB->pScsiHost); if (pos - buffer < offset) return 0; @@ -7281,6 +7552,10 @@ DC395x_ResetSCSIBus( pACB ); DC395x_read8 (TRM_S1040_SCSI_INTSTATUS); +#ifdef DC395x_DEBUGTRACE + DC395x_free_tracebufs (pACB, DC395x_MAX_SRB_CNT); +#endif + DC395x_free_SG_tables (pACB, DC395x_MAX_SRB_CNT); return( 0 ); } @@ -7319,7 +7594,7 @@ DWORD flags; PACB pACB = (PACB)(host->hostdata); //DWORD acb_flags=0; - DC395x_LOCK_IO; + DC395x_LOCK_IO(pACB->pScsiHost); //DC395x_ACB_LOCK(pACB,acb_flags); printk ("DC395x: Shutdown ."); DC395x_shutdown (host); @@ -7337,7 +7612,7 @@ } release_region(host->io_port,host->n_io_port); - DC395x_UNLOCK_IO; + DC395x_UNLOCK_IO(pACB->pScsiHost); //DC395x_DRV_UNLOCK(drv_flags); return( 1 ); } Index: dc395x_trm.h =================================================================== RCS file: /home/cvsroot/dc395/dc395x_trm.h,v retrieving revision 1.34 retrieving revision 1.38 diff -u -u -r1.34 -r1.38 --- dc395x_trm.h 2001/12/06 20:46:02 1.34 +++ dc395x_trm.h 2002/02/28 11:18:37 1.38 @@ -8,7 +8,7 @@ ** ********************************************************************** */ -/* $Id: dc395x_trm.h,v 1.34 2001/12/06 20:46:02 garloff Exp $ */ +/* $Id: dc395x_trm.h,v 1.38 2002/02/28 11:18:37 garloff Exp $ */ /* ***************************************************** ** Tekram TRM_S1040 for DC395x driver, header file @@ -20,7 +20,7 @@ #include #define DC395x_BANNER "Tekram DC395U/UW/F DC315/U" -#define DC395x_VERSION "1.35, 2001-12-06" +#define DC395x_VERSION "1.37, 2002-02-28" /* Kernel version autodetection */ #include @@ -47,9 +47,9 @@ #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_SG_TABLESIZE 64 /* HW limitation */ +#define DC395x_MAX_SG_LISTENTRY 64 /* Must be equal or lower to previous item */ +#define DC395x_MAX_SRB_CNT 63 //#define DC395x_MAX_CAN_QUEUE 7 * DC395x_MAX_QTAGS #define DC395x_MAX_CAN_QUEUE DC395x_MAX_SRB_CNT #define DC395x_END_SCAN 2