Index: 2035-scsi-singlelun.diff =================================================================== RCS file: 2035-scsi-singlelun.diff diff -N 2035-scsi-singlelun.diff --- /tmp/cvsJhhG65 Wed Dec 20 02:07:27 2000 +++ /dev/null Thu Aug 24 01:06:10 2000 @@ -1,45 +0,0 @@ -From: Edgar Toernig -Subject: [PATCH] 2.0.35 scsi.c single_lun flag - -Hi, - -as I (or better Derrick) noticed, the fix for the single_lun flag never -made it to the 2.0 kernels. It's already present in the 2.1 kernels -since 2.1.75 and in my 2.0 kernel for over a year now. - -This patch is required by some CD-changers. Without it, you may get -spurious scsi lockups when accessing multiple LUNs at the same time. - -Ciao, ET. - ---- /usr/src/linux-2.0.35/drivers/scsi/scsi.c.orig Fri Aug 7 02:21:37 1998 -+++ /usr/src/linux-2.0.35/drivers/scsi/scsi.c Fri Aug 7 02:24:12 1998 -@@ -750,6 +750,13 @@ - SDpnt->borken = 0; - -+ /* -+ * If we want to only allow I/O to one of the luns attached to this device -+ * at a time, then we set this flag. -+ */ -+ if (bflags & BLIST_SINGLELUN) -+ SDpnt->single_lun = 1; -+ - /* - * These devices need this "key" to unlock the devices so we can use it - */ - if ((bflags & BLIST_KEY) != 0) { -@@ -790,13 +797,6 @@ - */ - if (bflags & BLIST_NOLUN) - return 0; /* break; */ - -- /* -- * If we want to only allow I/O to one of the luns attached to this device -- * at a time, then we set this flag. -- */ -- if (bflags & BLIST_SINGLELUN) -- SDpnt->single_lun = 1; -- - /* - * If this device is known to support sparse multiple units, override the - Index: Makefile =================================================================== RCS file: Makefile diff -N Makefile --- /dev/null Thu Aug 24 01:06:10 2000 +++ /tmp/cvsuhnBI1 Wed Dec 20 02:07:27 2000 @@ -0,0 +1,30 @@ +# Makefile for the tmscsim (AM53C974 chip on Tekram DC390) driver +# (w) 5/2000, garloff@suse.de + +KDIR := /usr/src/linux + +TARGETS := Rules.make arch tmscsim.o +.PHONY: tmscsim.o + +default: $(TARGETS) + + +Rules.make: $(KDIR)/Rules.make + cp -pf $(KDIR)/Rules.make . + +arch: $(KDIR)/arch + rm -f arch + ln -s $(KDIR)/arch . + +clean: + rm -f $(TARGETS) + +tmscsim.o: + $(MAKE) -f Makefile.dc390 KDIR=$(KDIR) + +install: + $(MAKE) -f Makefile.dc390 KDIR=$(KDIR) install_mod + +load: + $(MAKE) -f Makefile.dc390 KDIR=$(KDIR) load_module + Index: Makefile.dc390 =================================================================== RCS file: Makefile.dc390 diff -N Makefile.dc390 --- /dev/null Thu Aug 24 01:06:10 2000 +++ /tmp/cvsTVXk9W Wed Dec 20 02:07:27 2000 @@ -0,0 +1,57 @@ +# Makefile for dc395x_trm to be called by master Makefile that +# does the preparation work (setting up links, copying Rules.make ...) +# (w) 5/2000 garloff@suse.de + +TARGET = tmscsim.o +TARGETMODDIR = scsi + +default: $(TARGET) + +TOPDIR := $(KDIR) +include $(KDIR)/.config +include $(KDIR)/Makefile +TOPDIR := $(KDIR) + +CFLAGS := -I. -I $(KDIR)/drivers/scsi -I $(KDIR)/include $(CFLAGS) -DMODULE + +ifdef CONFIG_MODVERSIONS +CFLAGS += -DMODVERSIONS -include $(KDIR)/include/linux/modversions.h +endif + +tmscsim.o: dc390.h tmscsim.h scsiiom.c tmscsim.c arch Rules.make + +# 2.4 and later define PERL in the Makefile +#ifdef PERL +ifeq ($(PATCHLEVEL),4) +MODLIB := $(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE)/kernel/drivers +else +MODLIB := $(DESTDIR)$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) +endif + +install_mod: $(MODLIB)/$(TARGETMODDIR)/tmscsim.o + +$(MODLIB)/$(TARGETMODDIR)/tmscsim.o: tmscsim.o + @if test $(shell id -u) = 0; then \ + echo "Install tmscsim"; install -o root -g root -d $(MODLIB)/$(TARGETMODDIR); \ + install -o root -g root -m 0644 tmscsim.o $(MODLIB)/$(TARGETMODDIR)/; \ + echo "depmod -a $(KERNELRELEASE)"; depmod -a $(KERNELRELEASE); \ + else \ + echo "Give root password for installation of kernel module"; \ + su -c \ + 'echo "Install tmscsim"; install -o root -g root -d $(MODLIB)/$(TARGETMODDIR); \ + install -o root -g root -m 0644 tmscsim.o $(MODLIB)/$(TARGETMODDIR)/; \ + echo "depmod -a $(KERNELRELEASE)"; depmod -a $(KERNELRELEASE)'; \ + fi + +load_module: install_mod + @if test $(shell id -u) = 0; then \ + if test ! -z "$(shell lsmod | grep tmscsim)"; then echo "Remove tmscsim"; \ + rmmod tmscsim; fi; \ + echo "Load tmscsim"; modprobe tmscsim; \ + else \ + echo "Give root password for loading of kernel module"; \ + su -c \ + 'if test ! -z "$(shell lsmod | grep tmscsim)"; then echo "Remove tmscsim"; \ + rmmod tmscsim; fi; \ + echo "Load tmscsim"; modprobe tmscsim'; \ + fi Index: README.tmscsim =================================================================== RCS file: /home/cvsroot/dc390/README.tmscsim,v retrieving revision 2.9 retrieving revision 2.25.2.7 diff -u -r2.9 -r2.25.2.7 --- README.tmscsim 1998/12/25 18:04:20 2.9 +++ README.tmscsim 2000/12/20 01:07:12 2.25.2.7 @@ -9,6 +9,7 @@ 6. Potential improvements 7. Bug reports, debugging and updates 8. Acknowledgements +9. Copyright 1. Purpose and history @@ -25,7 +26,7 @@ Tekram DC390(T) adapter. This is where the name comes from: tm = Tekram scsi = SCSI driver, m = AMD (?) as opposed to w for the DC390W/U/F (NCR53c8X5, X=2/7) driver. Yes, there was also a driver for the latter, -tmscsimw, which supported DC390W/U/F adapters. It's not maintained any more, +tmscsiw, which supported DC390W/U/F adapters. It's not maintained any more, as the ncr53c8xx is perfectly supporting these adpaters since some time. The driver first appeared in April 1996, exclusively supported the DC390 @@ -56,10 +57,13 @@ driver. Of course you have to choose to compile SCSI support and DC390(T) support into your kernel or as module when configuring your kernel for compiling. +NEW: You may as well compile this module outside your kernel, using the +supplied Makefile. If you got an old kernel (pre 2.1.127, pre 2.0.37p1) with an old version of this driver: Get dc390-21125-20b.diff.gz or dc390-2036p21-20b1.diff.gz from - my website and apply the patch. + my web page and apply the patch. Apply further patches to upgrade to the + latest version of the driver. If you want to do it manually, you should copy the files (dc390.h, tmscsim.h, tmscsim.c, scsiiom.c and README.tmscsim) from this directory to @@ -91,6 +95,8 @@ tune2fs -e remount-ro /dev/sd?? * have copies of your SCSI disk's partition tables on some safe location: dd if=/dev/sda of=/mnt/floppy/sda bs=512 count=1 + or just print it with: + fdisk -l | lpr * make sure you are able to boot Linux (e.g. from floppy disk using InitRD) if your SCSI disk gets corrupted. You can use ftp://student.physik.uni-dortmund.de/pub/linux/kernel/bootdisk.gz @@ -102,7 +108,7 @@ than the 33.33 MHz being in the PCI spec. If you want to share the IRQ with another device and the driver refuses to -do, you might succeed with changing the DC390_IRQ type in tmscsim.c to +do so, you might succeed with changing the DC390_IRQ type in tmscsim.c to SA_SHIRQ | SA_INTERRUPT. @@ -121,11 +127,12 @@ * Dynamically configurable by writing to /proc/scsi/tmscsim/? * Dynamic allocation of resources * SMP support: Locking on io_request lock (Linux 2.1/2.2) or adapter - specific locks (Linux 2.3) + specific locks (Linux 2.5?) * Uniform source code for Linux-2.x.y * Support for dyn. addition/removal of devices via add/remove-single-device - (Try: echo "scsi add-single-device H C I L" >/proc/scsi/scsi - H = Host, C = Channel, I = SCSI ID, L = SCSI LUN.) Use with care! + (Try: echo "scsi add-single-device C B T U" >/proc/scsi/scsi + C = Controller, B = Bus, T = Target SCSI ID, U = Unit SCSI LUN.) + Use with care! * Try to use the partition table for the determination of the mapping @@ -139,20 +146,21 @@ the attached devices and their settings. Here's an example: -garloff@kg1:/home/garloff > cat /proc/scsi/tmscsim/0 -Tekram DC390/AM53C974 PCI SCSI Host Adapter, Driver Version 1.20s, 1998/08/20 -SCSI Host Nr 0, AM53C974 Adapter Nr 0 -IOPortBase 0x6200, IRQLevel 0x09 -MaxID 7, MaxLUN 8, AdapterID 7, SelTimeout 250 ms -TagMaxNum 16, Status 0, ACBFlag 0, GlitchEater 24 ns -Statistics: Nr of Cmnds 39563, Cmnds not sent directly 0, Out of SRB conds 0 - Nr of lost arbitrations 17 +garloff@kurt:/home/garloff > cat /proc/scsi/tmscsim/0 +Tekram DC390/AM53C974 PCI SCSI Host Adapter, Driver Version 2.0e7 2000-11-28 +SCSI Host Nr 1, AM53C974 Adapter Nr 0 +IOPortBase 0xb000, IRQ 10 +MaxID 8, MaxLUN 8, AdapterID 6, SelTimeout 250 ms, DelayReset 1 s +TagMaxNum 16, Status 0x00, ACBFlag 0x00, GlitchEater 24 ns +Statistics: Cmnds 1470165, Cmnds not sent directly 0, Out of SRB conds 0 + Lost arbitrations 587, Sel. connected 0, Connected: No Nr of attached devices: 4, Nr of DCBs: 4 -Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs -00 00 00 Yes Yes Yes Yes Yes No 100 ns 10.0 M 15 -01 01 00 Yes Yes Yes Yes Yes No 100 ns 10.0 M 15 -02 03 00 Yes Yes Yes Yes No No 100 ns 10.0 M 15 -03 05 00 Yes No Yes Yes No No (200 ns) +Map of attached LUNs: 01 00 00 03 01 00 00 00 +Idx ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs MaxCmd +00 00 00 Yes Yes Yes Yes Yes 100 ns 10.0 M 15 16 +01 03 00 Yes Yes Yes Yes No 100 ns 10.0 M 15 01 +02 03 01 Yes Yes Yes Yes No 100 ns 10.0 M 15 01 +03 04 00 Yes Yes Yes Yes No 100 ns 10.0 M 15 01 Note that the settings MaxID and MaxLUN are not zero- but one-based, which means that a setting MaxLUN=4, will result in the support of LUNs 0..3. This @@ -178,9 +186,8 @@ The last values are only shown, if Sync is enabled. (NegoPeriod is still displayed in brackets to show the values which will be used after enabling Sync.) -The STOP parameter is for testing/debugging purposes only and should bet set -to No. Please don't fiddle with it, unless you want to get rid of the -contents of your disk. +MaxCmd ist the number of commands (=tags) which can be processed at the same +time by the device. If you want to change a setting, you can do that by writing to /proc/scsi/tmscsim/?. Basically you have to imitate the output of driver. @@ -196,8 +203,8 @@ echo "MaxLUN=8 seltimeout 200" >/proc/scsi/tmscsim/0 Note that you can only change MaxID, MaxLUN, AdapterID, SelTimeOut, - TagMaxNum, ACBFlag and GlitchEater. Don't change ACBFlag unless you - want to see what happens, if the driver hangs. + TagMaxNum, ACBFlag, GlitchEater and DelayReset. Don't change ACBFlag + unless you want to see what happens, if the driver hangs. (2) Change device settings: You write a config line to the driver. The Nr must match the ID and LUN given. If you give "-" as parameter, it is @@ -207,8 +214,8 @@ an INQUIRY on the device if necessary to check if it is capable to operate with the given settings (Sync, TagQ). Examples: - echo "0 0 0 y y y - y - 10" >/proc/scsi/tmscsim/0 - echo "3 5 0 y n y" >/proc/scsi/tmscsim/0 + echo "0 0 0 y y y - y - 10 " >/proc/scsi/tmscsim/0 + echo "3 5 0 y n y " >/proc/scsi/tmscsim/0 To give a short explanation of the first example: The first three numbers, "0 0 0" (Device index 0, SCSI ID 0, SCSI LUN 0), @@ -223,22 +230,26 @@ discussed above. The values used in this example will result in maximum performance. -(3) Special commands: You can force a SCSI bus reset, an INQUIRY command and - the removal of a device's DCB. +(3) Special commands: You can force a SCSI bus reset, an INQUIRY command, the + removal or the addition of a device's DCB and a SCSI register dump. This is only used for debugging when you meet problems. The parameter of - the INQUIRY and remove command is the device index as shown by the + the INQUIRY and REMOVE commands is the device index as shown by the output of /proc/scsi/tmscsim/? in the device listing in the first column - (Idx). + (Idx). ADD takes the SCSI ID and LUN. Examples: echo "reset" >/proc/scsi/tmscsim/0 echo "inquiry 1" >/proc/scsi/tmscsim/0 echo "remove 2" >/proc/scsi/tmscsim/1 + echo "add 2 3" >/proc/scsi/tmscsim/? + echo "dump" >/proc/scsi/tmscsim/0 - Note that you will meet problems when you remove a device's DCB with the + Note that you will meet problems when you REMOVE a device's DCB with the remove command if it contains partitions which are mounted. Only use it after unmounting its partitions, telling the SCSI mid-level code to remove it (scsi remove-single-device) and you really need a few bytes of memory. + The ADD command allows you to configure a device before you tell the + mid-level code to try detection. I'd suggest reviewing the output of /proc/scsi/tmscsim/? after changing @@ -247,18 +258,20 @@ 5. Configuration via boot/module parameters ------------------------------------------- -With the DC390, the driver reads its EEPROM settings and IGNORES boot / -module parameters. If you want to override the EEPROM settings of a DC390, -you have to use the /proc/scsi/tmscsim/? interface described in the above -chapter. - -However, if you do have another AM53C974 based adapter you might want to -adjust some settings before you are able to write to the /proc/scsi/tmscsim/? -pseudo-file, e.g. if you want to use another adapter ID than 7. (Note that -the log message "DC390: No EEPROM found!" is normal without a DC390.) +With the DC390, the driver reads its EEPROM settings and tries to use them. +But you may want to override the settings prior to being able to change the +driver configuration via /proc/scsi/tmscsim/?. +If you do have another AM53C974 based adapter, that's even the only +possibility to adjust settings before you are able to write to the +/proc/scsi/tmscsim/? pseudo-file, e.g. if you want to use another +adapter ID than 7. +(BTW, the log message "DC390: No EEPROM found!" is normal without a DC390.) For this purpose, you can pass options to the driver before it is initialised by using kernel or module parameters. See lilo(8) or modprobe(1) manual pages on how to pass params to the kernel or a module. +[NOTE: Formerly, it was not possible to override the EEPROM supplied + settings of the DC390 with cmd line parameters. This has changed since + 2.0e7] The syntax of the params is much shorter than the syntax of the /proc/... interface. This makes it a little bit more difficult to use. However, long @@ -269,7 +282,7 @@ DC390 EEPROM, the settings are given in a DC390 BIOS' way. Here's the syntax: -tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds +tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds,DelayReset Each of the parameters is a number, containing the described information: @@ -278,7 +291,7 @@ * SpdIdx: The index of the maximum speed as in the DC390 BIOS. The values 0..7 mean 10, 8.0, 6.7, 5.7, 5.0, 4.0, 3.1 and 2 MHz resp. Default is - 1 (8.0 MHz). + 0 (10.0 MHz). * DevMode is a bit mapped value describing the per-device features. It applies to all devices. (Sync, Disc and TagQ will only apply, if the @@ -289,7 +302,7 @@ *1 0x02 2 Synchronous Negotiation *2 0x04 4 Disconnection *3 0x08 8 Send Start command on startup. (Not used) - *4 0x10 16 Tagged Queueing + *4 0x10 16 Tagged Command Queueing As usual, the desired value is obtained by adding the wanted values. If you want to enable all values, e.g., you would use 31(0x1f). Default is 31. @@ -315,18 +328,23 @@ *3 16 4 32 +* DelayReset is the time in seconds (minus 0.5s), the adapter waits, after a + bus reset. Default is 1 (corresp. to 1.5s). + Example: modprobe tmscsim tmscsim=6,2,31 would set the adapter ID to 6, max. speed to 6.7 MHz, enable all device -features and leave the adapter features and the number of Tagged Commands -to the defaults. - -As you can see, you don't need to specify all of the five params. +features and leave the adapter features, the number of Tagged Commands +and the Delay after a reset to the defaults. -The defaults (7,1,31,15,3) are aggressive to allow good performance. You can -use tmscsim=7,0,31,63,4 for maximum performance, if your SCSI chain is -perfect. If you meet problems, you can use tmscsim=-1 which is a shortcut -for tmscsim=7,4,9,15,2. +As you can see, you don't need to specify all of the six params. +If you want values to be ignored (i.e. the EEprom settings or the defaults +will be used), you may pass -2 (not 0!) at the corresponding position. + +The defaults (7,0,31,15,3,1) are aggressive to allow good performance. You +can use tmscsim=7,0,31,63,4,0 for maximum performance, if your SCSI chain +allows it. If you meet problems, you can use tmscsim=-1 which is a shortcut +for tmscsim=7,4,9,15,2,10. 6. Potential improvements @@ -334,42 +352,47 @@ Most of the intended work on the driver has been done. Here are a few ideas to further improve its usability: +* Cleanly separate per-Target and per-LUN properties (DCB) * More intelligent abort() routine -* Implement new_eh code (Linux-2.1+) -* Have the mid-level code (and not the driver) handle more of the various - conditions. -* Rework command queueing in the driver +* Use new_eh code (Linux-2.1+) +* Have the mid-level (ML) code (and not the driver) handle more of the + various conditions. +* Command queueing in the driver: Eliminate Query list and use ML instead. * More user friendly boot/module param syntax Further investigation on these problems: * Driver hangs with sync readcdda (xcdroast) (most probably VIA PCI error) -Known problems: +Known problems: +Please see http://www.garloff.de/kurt/linux/dc390/problems.html -* There was a report that with a certain Scanner, the last SCSI command - won't be finished correctly. This might be a command queueing bug or a bug - in SCSI implementation of the scanner. Issueing another command to the - scanner seems to help. (Try echo "INQUIRY x" >/proc/scsi/tmscsim/?, where - x is the index (not the SCSI ID!) of the scanner. See 4.(3).) +* Changing the parameters of multi-lun by the tmscsim/? interface will + cause problems, cause these settings are mostly per Target and not per LUN + and should be updated accordingly. To be fixed for 2.0d24. +* CDRs (eg Yam CRW4416) not recognized, because some buggy devices don't + recover from a SCSI reset in time. Use a higher delay or don't issue + a SCSI bus reset on driver initialization. See problems page. + For the CRW4416S, this seems to be solved with firmware 1.0g (reported by + Jean-Yves Barbier). +* TEAC CD-532S not being recognized. (Works with 1.11). +* Scanners (eg. Astra UMAX 1220S) don't work: Disable Sync Negotiation. + If this does not help, try echo "INQUIRY t" >/proc/scsi/tmscsim/? (t + replaced by the dev index of your scanner). You may try to reset your SCSI + bus afterwards (echo "RESET" >/proc/scsi/tmscsim/?). + The problem seems to be solved as of 2.0d18, thanks to Andreas Rick. * If there is a valid partition table, the driver will use it for determing - the mapping. Other operating systems may not like this mapping, though + the mapping. If there's none, a reasonable mapping (Symbios-like) will be + assumed. Other operating systems may not like this mapping, though it's consistent with the BIOS' behaviour. Old DC390 drivers ignored the partition table and used a H/S = 64/32 or 255/63 translation. So if you want to be compatible to those, use this old mapping when creating - partition tables. -* In some situations, the driver will get stuck in an abort loop. Please - disable DsCn, if you meet this problem. Please contact me for further - debugging. -* 2.1.115+: Linux misses locks in sr_ioctl.c and scsi_ioctl.c - There used to be a patch included here, which partially solved the - problem. I suggest you contact Chiaki Ishikawa , - Richard Waltham or Doug Ledford - , if you want to help further debugging it. -* 2.0.35: CD changers (e.g. NAKAMICHI MBR-7.{0,2}) have problems because - the mid-level code doesn't handle BLIST_SINGLELUN correctly. There used - to be a patch included here to fix this, but I was told that it is fixed - in 2.0.36. + partition tables. Even worse, on bootup the DC390 might complain if other + mappings are found, so auto rebooting may fail. +* In some situations, the driver will get stuck in an abort loop. This is a + bad interaction between the Mid-Layer of Linux' SCSI code and the driver. + Try to disable DsCn, if you meet this problem. Please contact me for + further debugging. 7. Bug reports, debugging and updates @@ -382,7 +405,7 @@ maybe the DC390 log messages to the report. Bug reports should be send to me (Kurt Garloff ) as well -as to the linux-scsi list (), as sometimes bugs +as to the linux-scsi list (), as sometimes bugs are caused by the SCSI mid-level code. I will ask you for some more details and probably I will also ask you to @@ -394,25 +417,33 @@ The latest version of the driver can be found at: http://www.garloff.de/kurt/linux/dc390/ -and - ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/ -(The latter might shut down some day.) + ftp://ftp.suse.com/pub/people/garloff/linux/dc390/ 8. Acknowledgements ------------------- -Thanks to Linus Torvalds, Alan Cox, David Miller, Rik v. Riel, the FSF -people, the XFree86 team and all the others for the wonderful OS and -software. +Thanks to Linus Torvalds, Alan Cox, the FSF people, the XFree86 team and +all the others for the wonderful OS and software. Thanks to C.L. Huang and Philip Giang (Tekram) for the initial driver release and support. -Thanks to Doug Ledford, Gerard Roudier for support with SCSI coding. +Thanks to Doug Ledford, Gérard Roudier for support with SCSI coding. Thanks to a lot of people (espec. Chiaki Ishikawa, Andreas Haumer, Hubert Tonneau) for intensively testing the driver (and even risking data loss -doing this during early revisions). +doing this during early revisions). +Recently, SuSE GmbH, Nuernberg, FRG, has been paying me for the driver +development and maintenance. Special thanks! + +9. Copyright +------------ + This driver is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + If you want to use any later version of the GNU GPL, you will probably + be allowed to, but you have to ask me and Tekram + before. ------------------------------------------------------------------------- Written by Kurt Garloff 1998/06/11 -Last updated 1998/12/25, driver revision 2.0d -$Id: README.tmscsim,v 2.9 1998/12/25 18:04:20 garloff Exp $ +Last updated 2000/11/28, driver revision 2.0e7 +$Id: README.tmscsim,v 2.25.2.7 2000/12/20 01:07:12 garloff Exp $ Index: dc390-120-kernel.diff =================================================================== RCS file: /home/cvsroot/dc390/dc390-120-kernel.diff,v retrieving revision 2.3 retrieving revision 2.5 diff -u -r2.3 -r2.5 --- dc390-120-kernel.diff 1998/12/25 18:04:20 2.3 +++ dc390-120-kernel.diff 1999/06/01 22:20:02 2.5 @@ -1,6 +1,6 @@ # dc390-kernel.diff # patches against 2.1.125 kernel for DC390/AM53C974 driver integration -# $Id: dc390-120-kernel.diff,v 2.3 1998/12/25 18:04:20 garloff Exp $ # +# $Id: dc390-120-kernel.diff,v 2.5 1999/06/01 22:20:02 garloff Exp $ # 8<---------------------------------------------------------------------- Patch for allowing omission of the non DC390 parts of the driver: Index: dc390.h =================================================================== RCS file: /home/cvsroot/dc390/dc390.h,v retrieving revision 2.12 retrieving revision 2.43.2.22 diff -u -r2.12 -r2.43.2.22 --- dc390.h 1998/12/25 17:33:27 2.12 +++ dc390.h 2000/12/20 00:39:36 2.43.2.22 @@ -4,10 +4,8 @@ * Description: Device Driver for Tekram DC-390(T) PCI SCSI * * Bus Master Host Adapter * ***********************************************************************/ -/* $Id: dc390.h,v 2.12 1998/12/25 17:33:27 garloff Exp $ */ +/* $Id: dc390.h,v 2.43.2.22 2000/12/20 00:39:36 garloff Exp $ */ -#include - /* * DC390/AMD 53C974 driver, header file */ @@ -15,13 +13,28 @@ #ifndef DC390_H #define DC390_H +#include +#ifndef KERNEL_VERSION +# define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + #define DC390_BANNER "Tekram DC390/AM53C974" -#define DC390_VERSION "2.0d 1998/12/25" +#define DC390_VERSION "2.0f 2000-12-20" -#if defined(HOSTS_C) || defined(MODULE) +/* 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 -#include +#if LINUX_VERSION_CODE < KERNEL_VERSION (2,1,70) || defined (OLD_EH) +# define NEW_EH +#else +# define NEW_EH use_new_eh_code: 1, +# define USE_NEW_EH +#endif +#if defined(HOSTS_C) || defined(MODULE) || LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99) + extern int DC390_detect(Scsi_Host_Template *psht); extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); extern int DC390_abort(Scsi_Cmnd *cmd); @@ -34,9 +47,29 @@ # define DC390_release NULL #endif -extern struct proc_dir_entry DC390_proc_scsi_tmscsim; extern int DC390_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30) +#define DC390_T { \ + proc_name: "tmscsim", \ + proc_info: DC390_proc_info, \ + name: DC390_BANNER " V" DC390_VERSION, \ + detect: DC390_detect, \ + release: DC390_release, \ + queuecommand: DC390_queue_command, \ + abort: DC390_abort, \ + reset: DC390_reset, \ + bios_param: DC390_bios_param, \ + can_queue: 42, \ + this_id: 7, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 16, \ + NEW_EH \ + unchecked_isa_dma: 0, \ + use_clustering: DISABLE_CLUSTERING \ + } +#else +extern struct proc_dir_entry DC390_proc_scsi_tmscsim; #define DC390_T { \ proc_dir: &DC390_proc_scsi_tmscsim, \ proc_info: DC390_proc_info, \ @@ -47,13 +80,15 @@ abort: DC390_abort, \ reset: DC390_reset, \ bios_param: DC390_bios_param, \ - can_queue: 17, \ + can_queue: 42, \ this_id: 7, \ sg_tablesize: SG_ALL, \ - cmd_per_lun: 8, \ + cmd_per_lun: 16, \ + NEW_EH \ + unchecked_isa_dma: 0, \ use_clustering: DISABLE_CLUSTERING \ } - +#endif #endif /* defined(HOSTS_C) || defined(MODULE) */ #endif /* DC390_H */ Index: scsiiom.c =================================================================== RCS file: /home/cvsroot/dc390/scsiiom.c,v retrieving revision 2.15 retrieving revision 2.55.2.17 diff -u -r2.15 -r2.55.2.17 --- scsiiom.c 1998/12/25 17:33:27 2.15 +++ scsiiom.c 2000/12/20 00:39:37 2.55.2.17 @@ -4,16 +4,40 @@ * Description: Device Driver for Tekram DC-390 (T) PCI SCSI * * Bus Master Host Adapter * ***********************************************************************/ -/* $Id: scsiiom.c,v 2.15 1998/12/25 17:33:27 garloff Exp $ */ +/* $Id: scsiiom.c,v 2.55.2.17 2000/12/20 00:39:37 garloff Exp $ */ +static void __inline__ +dc390_freetag (PDCB pDCB, PSRB pSRB) +{ + if (pSRB->TagNumber < 255) { + pDCB->TagMask &= ~(1 << pSRB->TagNumber); /* free tag mask */ + pSRB->TagNumber = 255; + } +}; + + UCHAR dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ) { - USHORT wlval; - UCHAR bval, bval1; + UCHAR cmd; UCHAR disc_allowed, try_sync_nego; + + pSRB->ScsiPhase = SCSI_NOP0; - pSRB->TagNumber = 31; - DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID); + if (pACB->Connected) + { + // Should not happen normally + printk (KERN_WARNING "DC390: Can't select when connected! (%08x,%02x)\n", + pSRB->SRBState, pSRB->SRBFlag); + pSRB->SRBState = SRB_READY; + pACB->SelConn++; + return 1; + } + if (time_before (jiffies, pACB->pScsiHost->last_reset)) + { + DEBUG0(printk ("DC390: We were just reset and don't accept commands yet!\n");) + return 1; + } + DC390_write8 (Scsi_Dest_ID, pDCB->TargetID); DC390_write8 (Sync_Period, pDCB->SyncPeriod); DC390_write8 (Sync_Offset, pDCB->SyncOffset); DC390_write8 (CtrlReg1, pDCB->CtrlR1); @@ -21,151 +45,105 @@ DC390_write8 (CtrlReg4, pDCB->CtrlR4); DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); /* Flush FIFO */ DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\ - pSRB->CmdBlock[0], pDCB->SyncMode);) - pSRB->ScsiPhase = SCSI_NOP0; - //pSRB->MsgOutBuf[0] = MSG_NOP; - //pSRB->MsgCnt = 0; - bval = pDCB->IdentifyMsg; - if( !(pDCB->SyncMode & EN_ATN_STOP) ) /* Don't always try send Extended messages on arbitration */ - { - if( (pSRB->CmdBlock[0] == INQUIRY) || - (pSRB->CmdBlock[0] == REQUEST_SENSE) || - (pSRB->SRBFlag & AUTO_REQSENSE) ) - { - bval &= 0xBF; /* No DisConn */ - DC390_write8 (ScsiFifo, bval); - bval1 = SEL_W_ATN; - pSRB->SRBState = SRB_START_; - DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);) - if( pDCB->SyncMode & SYNC_ENABLE ) - { - if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ - (pSRB->CmdBlock[0] != INQUIRY) ) - { - bval1 = SEL_W_ATN_STOP; /* Try to establish SYNC nego */ - pSRB->SRBState = SRB_MSGOUT; - } - } - } - else /* TagQ ? */ - { - DC390_write8 (ScsiFifo, bval); - if(pDCB->SyncMode & EN_TAG_QUEUEING) - { - DC390_write8 (ScsiFifo, MSG_SIMPLE_QTAG); - DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);) - bval = 0; wlval = 1; - while (wlval & pDCB->TagMask) - { bval++; wlval <<= 1; }; - pDCB->TagMask |= wlval; - DC390_write8 (ScsiFifo, bval); - pSRB->TagNumber = bval; - DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);) - bval1 = SEL_W_ATN3; - pSRB->SRBState = SRB_START_; - } - else /* No TagQ */ - { - bval1 = SEL_W_ATN; - DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);) - pSRB->SRBState = SRB_START_; - } - } + pSRB->pcmd->cmnd[0], pDCB->SyncMode);) + disc_allowed = pDCB->DevMode & EN_DISCONNECT_; try_sync_nego = 0; + /* Don't disconnect on AUTO_REQSENSE, cause it might be an + * Contingent Allegiance Condition (6.6), where no tags should be used. + * All other have to be allowed to disconnect to prevent Incorrect + * Initiator Connection (6.8.2/6.5.2) */ + /* Changed KG, 99/06/06 */ + if( /*(((pSRB->pcmd->cmnd[0] == INQUIRY) || (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || + * (pSRB->pcmd->cmnd[0] == TEST_UNIT_READY)) && pACB->scan_devices) + ||*/ (pSRB->SRBFlag & AUTO_REQSENSE) ) + disc_allowed = 0; + if ( (pDCB->SyncMode & SYNC_ENABLE) && (pDCB->TargetLUN == 0) && (pDCB->Inquiry7 & 0x10) && + ( ( ( (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) ) + && !(pDCB->SyncMode & SYNC_NEGO_DONE) ) || (pSRB->pcmd->cmnd[0] == INQUIRY) ) ) + try_sync_nego = 1; + + pSRB->MsgCnt = 0; cmd = SEL_W_ATN; + DC390_write8 (ScsiFifo, IDENTIFY(disc_allowed, pDCB->TargetLUN)); + /* Change 99/05/31: Don't use tags when not disconnecting (BUSY) */ + if ((pDCB->SyncMode & EN_TAG_QUEUEING) && disc_allowed) + { + UCHAR tag_no = 0; + while ((1 << tag_no) & pDCB->TagMask) tag_no++; + if (tag_no >= sizeof (pDCB->TagMask)*8 || tag_no >= pDCB->MaxCommand) { + printk (KERN_WARNING "DC390: Out of tags for Dev. %02x %02x\n", pDCB->TargetID, pDCB->TargetLUN); + return 1; + //goto no_tag; + }; + DC390_write8 (ScsiFifo, SIMPLE_QUEUE_TAG); + pDCB->TagMask |= (1 << tag_no); pSRB->TagNumber = tag_no; + DC390_write8 (ScsiFifo, tag_no); + DEBUG1(printk (KERN_DEBUG "DC390: Select w/DisCn for Cmd %li (SRB %p), Using Tag %02x\n", pSRB->pcmd->pid, pSRB, tag_no);) + cmd = SEL_W_ATN3; + } + else /* No TagQ */ + { +// no_tag: + DEBUG1(printk (KERN_DEBUG "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", (disc_allowed?"":"o"), pSRB->pcmd->pid, pSRB);) + }; - } - else /* ATN_STOP: Always try to establish Sync nego */ - { - if( (pSRB->CmdBlock[0] == INQUIRY) || - (pSRB->CmdBlock[0] == REQUEST_SENSE) || - (pSRB->SRBFlag & AUTO_REQSENSE) ) - { - bval &= 0xBF; /* No DisConn */ - DC390_write8 (ScsiFifo, bval); - bval1 = SEL_W_ATN; - DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);) - pSRB->SRBState = SRB_START_; - /* ??? */ - if( pDCB->SyncMode & SYNC_ENABLE ) - { - if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ - (pSRB->CmdBlock[0] != INQUIRY) ) - { - bval1 = SEL_W_ATN_STOP; /* Try to establish Sync nego */ - pSRB->SRBState = SRB_MSGOUT; - } - } - } - else /* TagQ ? */ - { - DC390_write8 (ScsiFifo, bval); - if(pDCB->SyncMode & EN_TAG_QUEUEING) - { - pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG; - DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);) - bval = 0; wlval = 1; - while (wlval & pDCB->TagMask) - { bval++; wlval <<= 1; }; - pDCB->TagMask |= wlval; - pSRB->TagNumber = bval; - DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);) - pSRB->MsgOutBuf[1] = bval; - pSRB->MsgCnt = 2; - bval1 = SEL_W_ATN_STOP; - pSRB->SRBState = SRB_START_; /* ?? */ - } - else /* No TagQ */ - { - pSRB->MsgOutBuf[0] = MSG_NOP; - pSRB->MsgCnt = 1; - pSRB->SRBState = SRB_START_; - bval1 = SEL_W_ATN_STOP; - DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);) - }; - } - } - if (bval1 != SEL_W_ATN_STOP) - { /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */ + pSRB->SRBState = SRB_START_; + + if (try_sync_nego) + { + UCHAR Sync_Off = pDCB->SyncOffset; + DEBUG0(printk (KERN_INFO "DC390: NEW Sync Nego code triggered (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN);) + pSRB->MsgOutBuf[0] = EXTENDED_MESSAGE; + pSRB->MsgOutBuf[1] = 3; + pSRB->MsgOutBuf[2] = EXTENDED_SDTR; + pSRB->MsgOutBuf[3] = pDCB->NegoPeriod; + if (!(Sync_Off & 0x0f)) Sync_Off = SYNC_NEGO_OFFSET; + pSRB->MsgOutBuf[4] = Sync_Off; + pSRB->MsgCnt = 5; + //pSRB->SRBState = SRB_MSGOUT_; + pSRB->SRBState |= DO_SYNC_NEGO; + cmd = SEL_W_ATN_STOP; + }; + + /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */ + if (cmd != SEL_W_ATN_STOP) + { if( pSRB->SRBFlag & AUTO_REQSENSE ) { - bval = 0; DC390_write8 (ScsiFifo, REQUEST_SENSE); - DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5); - DC390_write8 (ScsiFifo, bval); - DC390_write8 (ScsiFifo, bval); + DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5); + DC390_write8 (ScsiFifo, 0); + DC390_write8 (ScsiFifo, 0); DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); - DC390_write8 (ScsiFifo, bval); + DC390_write8 (ScsiFifo, 0); DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n");) } else /* write cmnd to bus */ { PUCHAR ptr; UCHAR i; - ptr = (PUCHAR) pSRB->CmdBlock; - for (i=0; iScsiCmdLen; i++) + ptr = (PUCHAR) pSRB->pcmd->cmnd; + for (i=0; ipcmd->cmd_len; i++) DC390_write8 (ScsiFifo, *(ptr++)); }; } - - /* Check if we can't win arbitration */ + DEBUG0(if (pACB->pActiveDCB) \ + printk (KERN_WARNING "DC390: ActiveDCB != 0\n");) + DEBUG0(if (pDCB->pActiveSRB) \ + printk (KERN_WARNING "DC390: ActiveSRB != 0\n");) + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); if (DC390_read8 (Scsi_Status) & INTERRUPT) { + dc390_freetag (pDCB, pSRB); + DEBUG0(printk ("DC390: Interrupt during Start SCSI (pid %li, target %02i-%02i)\n", + pSRB->pcmd->pid, pSRB->pcmd->target, pSRB->pcmd->lun);) pSRB->SRBState = SRB_READY; - pDCB->TagMask &= ~( 1 << pSRB->TagNumber ); - DEBUG0(printk (KERN_WARNING "DC390: Interrupt during StartSCSI!\n");) + //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + pACB->SelLost++; return 1; - } - else - { - pSRB->ScsiPhase = SCSI_NOP1; - DEBUG0(if (pACB->pActiveDCB) \ - printk (KERN_WARNING "DC390: ActiveDCB != 0\n");) - DEBUG0(if (pDCB->pActiveSRB) \ - printk (KERN_WARNING "DC390: ActiveSRB != 0\n");) - pACB->pActiveDCB = pDCB; - pDCB->pActiveSRB = pSRB; - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); - DC390_write8 (ScsiCmd, bval1); - return 0; - } + }; + DC390_write8 (ScsiCmd, cmd); + pACB->pActiveDCB = pDCB; pDCB->pActiveSRB = pSRB; + pACB->Connected = 1; + pSRB->ScsiPhase = SCSI_NOP1; + return 0; } //#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/ @@ -198,7 +176,7 @@ }; if (dstate & DMA_XFER_DONE) { - ULONG residual, xferCnt; int ctr = 5000000; + UINT residual, xferCnt; int ctr = 6000000; if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION)) { do @@ -236,47 +214,34 @@ void __inline__ DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) { - PACB pACB; + PACB pACB, pACB2; PDCB pDCB; PSRB pSRB; UCHAR sstatus=0; - UCHAR phase, i; + UCHAR phase; void (*stateV)( PACB, PSRB, PUCHAR ); UCHAR istate, istatus; #if DMA_INT UCHAR dstatus; #endif - DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS - - pACB = dc390_pACB_start; + DC390_AFLAGS DC390_IFLAGS //DC390_DFLAGS - if (pACB == 0) + pACB = (PACB)dev_id; + for (pACB2 = dc390_pACB_start; (pACB2 && pACB2 != pACB); pACB2 = pACB2->pNextACB); + if (!pACB2) { - printk(KERN_WARNING "DC390: Interrupt on uninitialized adapter!\n"); + printk ("DC390: IRQ called with foreign dev_id %p!\n", pACB); return; } - DC390_LOCK_DRV; + + //DC390_LOCK_DRV; - for( i=0; i < dc390_adapterCnt; i++ ) - { - if( pACB->IRQLevel == (UCHAR) irq ) - { - sstatus = DC390_read8 (Scsi_Status); - if( sstatus & INTERRUPT ) - break; - else - pACB = pACB->pNextACB; - } - else - { - pACB = pACB->pNextACB; - } - } + sstatus = DC390_read8 (Scsi_Status); + if( !(sstatus & INTERRUPT) ) + { /*DC390_UNLOCK_DRV;*/ return; }; DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);) - if( !pACB ) { DC390_UNLOCK_DRV; return; }; - #if DMA_INT DC390_LOCK_IO; DC390_LOCK_ACB; @@ -288,7 +253,7 @@ if (! (dstatus & SCSI_INTERRUPT)) { DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n");) - DC390_UNLOCK_DRV; + //DC390_UNLOCK_DRV; return; }; #else @@ -299,7 +264,7 @@ DC390_LOCK_IO; DC390_LOCK_ACB; - DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */ + //DC390_UNLOCK_DRV_NI; /* Allow _other_ CPUs to process IRQ (useful for shared IRQs) */ istate = DC390_read8 (Intern_State); istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */ @@ -310,23 +275,42 @@ if (sstatus & ILLEGAL_OP_ERR) { - printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus); + printk ("DC390: Illegal Operation detected (%08x)!\n", dc390_laststatus); dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB); - }; + } - if(istatus & DISCONNECTED) + else if (istatus & INVALID_CMD) + { + printk ("DC390: Invalid Command detected (%08x)!\n", dc390_laststatus); + dc390_InvalidCmd( pACB ); + goto unlock; + } + + if (istatus & SCSI_RESET) + { + dc390_ScsiRstDetect( pACB ); + goto unlock; + } + + if (istatus & DISCONNECTED) { dc390_Disconnect( pACB ); goto unlock; } - if(istatus & RESELECTED) + if (istatus & RESELECTED) { dc390_Reselect( pACB ); goto unlock; } + + else if (istatus & (SELECTED | SEL_ATTENTION)) + { + printk (KERN_ERR "DC390: Target mode not supported!\n"); + goto unlock; + } - if( istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) ) + if (istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) ) { pDCB = pACB->pActiveDCB; if (!pDCB) @@ -351,23 +335,11 @@ goto unlock; } - if(istatus & INVALID_CMD) - { - dc390_InvalidCmd( pACB ); - goto unlock; - } - - if(istatus & SCSI_RESET) - { - dc390_ScsiRstDetect( pACB ); - goto unlock; - } - unlock: - DC390_LOCK_DRV_NI; + //DC390_LOCK_DRV_NI; DC390_UNLOCK_ACB; DC390_UNLOCK_IO; - DC390_UNLOCK_DRV; /* Restore initial flags */ + //DC390_UNLOCK_DRV; /* Restore initial flags */ } void @@ -384,7 +356,7 @@ { UCHAR sstatus; PSGL psgl; - ULONG ResidCnt, xferCnt; + UINT ResidCnt, xferCnt; UCHAR dstate = 0; sstatus = *psstatus; @@ -396,7 +368,7 @@ if( sstatus & COUNT_2_ZERO ) { - int ctr = 5000000; /* only try for about a tenth of a second */ + int ctr = 6000000; /* only try for about a second */ while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ); if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24; @@ -415,10 +387,10 @@ } else { - ResidCnt = (ULONG) DC390_read8 (Current_Fifo) & 0x1f; - ResidCnt |= (ULONG) DC390_read8 (CtcReg_High) << 16; - ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid) << 8; - ResidCnt += (ULONG) DC390_read8 (CtcReg_Low); + ResidCnt = (UINT) DC390_read8 (Current_Fifo) & 0x1f; + ResidCnt |= (UINT) DC390_read8 (CtcReg_High) << 16; + ResidCnt |= (UINT) DC390_read8 (CtcReg_Mid) << 8; + ResidCnt += (UINT) DC390_read8 (CtcReg_Low); xferCnt = pSRB->SGToBeXferLen - ResidCnt; pSRB->SGBusAddr += xferCnt; @@ -426,7 +398,11 @@ pSRB->SGToBeXferLen = ResidCnt; } } - DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + if ((*psstatus & 7) != SCSI_DATA_OUT) + { + DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + } } void @@ -434,7 +410,8 @@ { UCHAR sstatus, residual, bval; PSGL psgl; - ULONG ResidCnt, xferCnt, i; + UINT ResidCnt, i; + ULONG xferCnt; PUCHAR ptr; sstatus = *psstatus; @@ -446,7 +423,7 @@ if( sstatus & COUNT_2_ZERO ) { - int ctr = 5000000; /* only try for about a tenth of a second */ + int ctr = 6000000; /* only try for about a second */ int dstate = 0; while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ); if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr)); @@ -455,7 +432,7 @@ DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16) \ + ((ULONG) DC390_read8 (CtcReg_Mid) << 8) \ + ((ULONG) DC390_read8 (CtcReg_Low));) - DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);) + DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%i,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);) DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ @@ -509,12 +486,12 @@ //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24; - DEBUG1(printk (KERN_DEBUG "Blast: Read %li times DMA_Status %02x", 0xa000-i, bval);) - ResidCnt = (ULONG) DC390_read8 (CtcReg_High); + DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval);) + ResidCnt = (UINT) DC390_read8 (CtcReg_High); ResidCnt <<= 8; - ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid); + ResidCnt |= (UINT) DC390_read8 (CtcReg_Mid); ResidCnt <<= 8; - ResidCnt |= (ULONG) DC390_read8 (CtcReg_Low); + ResidCnt |= (UINT) DC390_read8 (CtcReg_Low); xferCnt = pSRB->SGToBeXferLen - ResidCnt; pSRB->SGBusAddr += xferCnt; @@ -535,6 +512,11 @@ } } + if ((*psstatus & 7) != SCSI_DATA_IN) + { + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ + } } static void @@ -593,7 +575,7 @@ static void __inline__ dc390_MsgIn_reject (PACB pACB, PSRB pSRB) { - pSRB->MsgOutBuf[0] = MSG_REJECT_; + pSRB->MsgOutBuf[0] = MESSAGE_REJECT; pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; DEBUG0 (printk (KERN_INFO "DC390: Reject message\n");) } @@ -602,7 +584,7 @@ static void __inline__ dc390_EnableMsgOut_Abort ( PACB pACB, PSRB pSRB ) { - pSRB->MsgOutBuf[0] = MSG_ABORT; + pSRB->MsgOutBuf[0] = ABORT; pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_; } @@ -640,7 +622,7 @@ pSRB = pACB->pTmpSRB; pSRB->SRBState = SRB_UNEXPECT_RESEL; pDCB->pActiveSRB = pSRB; - pSRB->MsgOutBuf[0] = MSG_ABORT_TAG; + pSRB->MsgOutBuf[0] = ABORT_TAG; pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; } return pSRB; @@ -653,7 +635,7 @@ { PDCB pDCB = pSRB->pSRBDCB; if (!(pSRB->SRBState & DO_SYNC_NEGO)) - printk ("DC390: Target %i initiates Non-Sync?\n", pDCB->UnitSCSIID); + printk (KERN_INFO "DC390: Target %i initiates Non-Sync?\n", pDCB->TargetID); pSRB->SRBState &= ~DO_SYNC_NEGO; pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE); pDCB->SyncPeriod = 0; @@ -677,8 +659,8 @@ if (!(pSRB->SRBState & DO_SYNC_NEGO)) { - printk ("DC390: Target %i initiates Sync: %ins %i ... answer ...\n", - pDCB->UnitSCSIID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]); + printk (KERN_INFO "DC390: Target %i initiates Sync: %ins %i ... answer ...\n", + pDCB->TargetID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]); /* reject */ //dc390_MsgIn_reject (pACB, pSRB); @@ -687,12 +669,12 @@ /* Reply with corrected SDTR Message */ if (pSRB->MsgInBuf[4] > 15) { - printk ("DC390: Lower Sync Offset to 15\n"); + printk (KERN_INFO "DC390: Lower Sync Offset to 15\n"); pSRB->MsgInBuf[4] = 15; } if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod) { - printk ("DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2); + printk (KERN_INFO "DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2); pSRB->MsgInBuf[3] = pDCB->NegoPeriod; }; memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5); @@ -728,10 +710,10 @@ pDCB->CtrlR3 = bval; pDCB->SyncPeriod = (UCHAR)wval1; - if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->UnitSCSILUN == 0) + if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->TargetLUN == 0) { if (! (bval & FAST_SCSI)) wval1++; - printk ("DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->UnitSCSIID, + printk (KERN_INFO "DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->TargetID, 40/wval1, ((40%wval1)*10+wval1/2)/wval1, pDCB->SyncOffset & 0x0f); } @@ -739,6 +721,56 @@ }; +/* handle RESTORE_PTR */ +static void +dc390_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 "DC390: 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 "DC390: Pointer restored. Total %li, Bus %p\n", + pSRB->Saved_Ptr, pSRB->Segmentx.address); + } + else + { + pSRB->SGcount = 0; + printk (KERN_INFO "DC390: RESTORE_PTR message for Transfer without Scatter-Gather ??\n"); + }; + + pSRB->TotalXferredLen = pSRB->Saved_Ptr; +}; + + /* According to the docs, the AM53C974 reads the message and * generates a Succesful Operation IRQ before asserting ACK for * the last byte (how does it know whether it's the last ?) */ @@ -749,15 +781,15 @@ /* Check if the message is complete */ static UCHAR __inline__ -dc390_MsgIn_complete (UCHAR *msgbuf, ULONG len) +dc390_MsgIn_complete (UCHAR *msgbuf, UINT len) { - if (*msgbuf == MSG_EXTENDED) - { - if (len < 2) return 0; - if (len < msgbuf[1] + 2) return 0; - } + 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; + if (len < 2) return 0; return 1; } @@ -781,23 +813,23 @@ /* Now eval the msg */ switch (pSRB->MsgInBuf[0]) { - case MSG_DISCONNECT: + case DISCONNECT: pSRB->SRBState = SRB_DISCONNECT; break; - case MSG_SIMPLE_QTAG: - case MSG_HEAD_QTAG: - case MSG_ORDER_QTAG: + case SIMPLE_QUEUE_TAG: + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: pSRB = dc390_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]); break; - case MSG_REJECT_: + case MESSAGE_REJECT: DC390_write8 (ScsiCmd, RESET_ATN_CMD); pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ if( pSRB->SRBState & DO_SYNC_NEGO) dc390_MsgIn_set_async (pACB, pSRB); break; - case MSG_EXTENDED: + case EXTENDED_MESSAGE: /* reject every extended msg but SDTR */ if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR) dc390_MsgIn_reject (pACB, pSRB); @@ -810,15 +842,18 @@ }; // nothing has to be done - case MSG_COMPLETE: break; + case COMMAND_COMPLETE: break; - // SAVE POINTER my be ignored as we have the PSRB associated with the + // SAVE POINTER may be ignored as we have the PSRB associated with the // scsi command. Thanks, Gerard, for pointing it out. - case MSG_SAVE_PTR: break; + case SAVE_POINTERS: + pSRB->Saved_Ptr = pSRB->TotalXferredLen; + break; // The device might want to restart transfer with a RESTORE - case MSG_RESTORE_PTR: - printk ("DC390: RESTORE POINTER message received ... reject\n"); - // fall through + case RESTORE_POINTERS: + DEBUG0(printk ("DC390: RESTORE POINTER message received ... try to handle\n");) + dc390_restore_ptr (pACB, pSRB); + break; // reject unknown messages default: dc390_MsgIn_reject (pACB, pSRB); @@ -840,7 +875,18 @@ { PSGL psgl; ULONG lval; + PDCB pDCB = pACB->pActiveDCB; + if (pSRB == pACB->pTmpSRB) + { + if (pDCB) printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", + pDCB->TargetID, pDCB->TargetLUN); + else printk (KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n"); + dc390_EnableMsgOut_Abort (pACB, pSRB); + if (pDCB) pDCB->DCBFlag |= ABORT_DEV; + return; + } + if( pSRB->SGIndex < pSRB->SGcount ) { DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */); @@ -852,7 +898,7 @@ DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.");) } lval = pSRB->SGToBeXferLen; - DEBUG1(printk (KERN_DEBUG " DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);) + DEBUG1(printk (KERN_DEBUG " DC390: Start transfer: %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);) DC390_write8 (CtcReg_Low, (UCHAR) lval); lval >>= 8; DC390_write8 (CtcReg_Mid, (UCHAR) lval); @@ -918,8 +964,8 @@ DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); if( !(pSRB->SRBFlag & AUTO_REQSENSE) ) { - cnt = (UCHAR) pSRB->ScsiCmdLen; - ptr = (PUCHAR) pSRB->CmdBlock; + cnt = (UCHAR) pSRB->pcmd->cmd_len; + ptr = (PUCHAR) pSRB->pcmd->cmnd; for(i=0; i < cnt; i++) DC390_write8 (ScsiFifo, *(ptr++)); } @@ -928,11 +974,12 @@ UCHAR bval = 0; DC390_write8 (ScsiFifo, REQUEST_SENSE); pDCB = pACB->pActiveDCB; - DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5); + DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5); DC390_write8 (ScsiFifo, bval); DC390_write8 (ScsiFifo, bval); DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); DC390_write8 (ScsiFifo, bval); + DEBUG0(printk(KERN_DEBUG "DC390: AutoReqSense (CmndPhase)!\n");) } pSRB->SRBState = SRB_COMMAND; DC390_write8 (ScsiCmd, INFO_XFER_CMD); @@ -966,14 +1013,14 @@ DC390_write8 (ScsiFifo, *(ptr++)); pSRB->MsgCnt = 0; if( (pDCB->DCBFlag & ABORT_DEV_) && - (pSRB->MsgOutBuf[0] == MSG_ABORT) ) + (pSRB->MsgOutBuf[0] == ABORT) ) pSRB->SRBState = SRB_ABORT_SENT; } else { - bval = MSG_ABORT; /* ??? MSG_NOP */ - if( (pSRB->CmdBlock[0] == INQUIRY ) || - (pSRB->CmdBlock[0] == REQUEST_SENSE) || + bval = ABORT; /* ??? MSG_NOP */ + if( (pSRB->pcmd->cmnd[0] == INQUIRY ) || + (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) ) { if( pDCB->SyncMode & SYNC_ENABLE ) @@ -986,8 +1033,8 @@ else { mop1: - //printk ("DC390: Send SDTR message to %i %i ... \n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN); - DC390_write8 (ScsiFifo, MSG_EXTENDED); + printk (KERN_ERR "DC390: OLD Sync Nego code triggered! (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN); + DC390_write8 (ScsiFifo, EXTENDED_MESSAGE); DC390_write8 (ScsiFifo, 3); /* ;length of extended msg */ DC390_write8 (ScsiFifo, EXTENDED_SDTR); /* ; sync nego */ DC390_write8 (ScsiFifo, pDCB->NegoPeriod); @@ -1030,20 +1077,16 @@ UCHAR bval, i, cnt; PDCB ptr; - if( !(pDCB->IdentifyMsg & 0x07) ) + if( !(pDCB->TargetLUN) ) { - if( pACB->scan_devices ) - { - dc390_CurrSyncOffset = pDCB->SyncOffset; - } - else + if( !pACB->scan_devices ) { ptr = pACB->pLinkDCB; cnt = pACB->DCBCnt; - bval = pDCB->UnitSCSIID; + bval = pDCB->TargetID; for(i=0; iUnitSCSIID == bval ) + if( ptr->TargetID == bval ) { ptr->SyncPeriod = pDCB->SyncPeriod; ptr->SyncOffset = pDCB->SyncOffset; @@ -1068,25 +1111,27 @@ DEBUG0(printk(KERN_INFO "DISC,");) + if (!pACB->Connected) printk(KERN_ERR "DC390: Disconnect not-connected bus?\n"); + pACB->Connected = 0; pDCB = pACB->pActiveDCB; if (!pDCB) { int j = 400; - DEBUG0(printk(KERN_WARNING "ACB:%08lx->ActiveDCB:%08lx IOPort:%04x IRQ:%02x !\n",\ - (ULONG)pACB,(ULONG)pDCB,pACB->IOPortBase,pACB->IRQLevel);) + DEBUG0(printk(KERN_ERR "ACB:%p->ActiveDCB:%p IOPort:%04x IRQ:%02x !\n",\ + pACB, pDCB, pACB->IOPortBase, pACB->IRQLevel);) while (--j) udelay (1000); DC390_read8 (INT_Status); /* Reset Pending INT */ DC390_write8 (ScsiCmd, EN_SEL_RESEL); return; } + DC390_write8 (ScsiCmd, EN_SEL_RESEL); pSRB = pDCB->pActiveSRB; pACB->pActiveDCB = 0; pSRB->ScsiPhase = SCSI_NOP0; - DC390_write8 (ScsiCmd, EN_SEL_RESEL); if( pSRB->SRBState & SRB_UNEXPECT_RESEL ) { pSRB->SRBState = 0; - dc390_DoWaitingSRB( pACB ); + dc390_Waiting_process ( pACB ); } else if( pSRB->SRBState & SRB_ABORT_SENT ) { @@ -1098,22 +1143,24 @@ for( i=0; i < cnt; i++) { psrb = pSRB->pNextSRB; - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; + dc390_Free_insert (pACB, pSRB); pSRB = psrb; } pDCB->pGoingSRB = 0; - dc390_DoWaitingSRB( pACB ); + dc390_Query_to_Waiting (pACB); + dc390_Waiting_process (pACB); } else { if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) || !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) ) { /* Selection time out */ - if( !(pACB->scan_devices) ) + if( !(1/*pACB->scan_devices*/) ) { pSRB->SRBState = SRB_READY; - dc390_RewaitSRB( pDCB, pSRB); + dc390_freetag (pDCB, pSRB); + dc390_Going_to_Waiting (pDCB, pSRB); + dc390_waiting_timer (pACB, HZ/5); } else { @@ -1123,15 +1170,12 @@ } else if( pSRB->SRBState & SRB_DISCONNECT ) { - dc390_DoWaitingSRB( pACB ); + dc390_Waiting_process ( pACB ); } else if( pSRB->SRBState & SRB_COMPLETED ) { disc1: - if(pDCB->MaxCommand > 1) - { - pDCB->TagMask &= (~(1 << pSRB->TagNumber)); /* free tag mask */ - } + dc390_freetag (pDCB, pSRB); pDCB->pActiveSRB = 0; pSRB->SRBState = SRB_FREE; dc390_SRBdone( pACB, pDCB, pSRB); @@ -1146,43 +1190,48 @@ { PDCB pDCB; PSRB pSRB; - USHORT wval; - UCHAR bval; + UCHAR id, lun; DEBUG0(printk(KERN_INFO "RSEL,");) + pACB->Connected = 1; pDCB = pACB->pActiveDCB; if( pDCB ) { /* Arbitration lost but Reselection won */ - DEBUG0(printk ("(ActiveDCB != 0)");) + DEBUG0(printk ("DC390: (ActiveDCB != 0: Arb. lost but resel. won)!\n");) pSRB = pDCB->pActiveSRB; if( !( pACB->scan_devices ) ) { pSRB->SRBState = SRB_READY; - dc390_RewaitSRB( pDCB, pSRB); + dc390_freetag (pDCB, pSRB); + dc390_Going_to_Waiting ( pDCB, pSRB); + dc390_waiting_timer (pACB, HZ/5); } } - bval = DC390_read8 (ScsiFifo); /* get ID */ - DEBUG0(printk ("Dev %02x,", bval);) - bval ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */ - wval = 0; - while (bval >>= 1) wval++; - wval |= ( (USHORT) DC390_read8 (ScsiFifo) & 7) << 8; /* get LUN */ - DEBUG0(printk ("(ID %02x, LUN %02x),", wval & 0xff, (wval & 0xff00) >> 8);) - pDCB = pACB->pLinkDCB; - while( wval != *((PUSHORT) &pDCB->UnitSCSIID) ) + /* Get ID */ + lun = DC390_read8 (ScsiFifo); + DEBUG0(printk ("Dev %02x,", lun);) + if (!(lun & (1 << pACB->pScsiHost->this_id))) + printk (KERN_ERR "DC390: Reselection must select host adapter: %02x!\n", lun); + else + lun ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */ + id = 0; while (lun >>= 1) id++; + /* Get LUN */ + lun = DC390_read8 (ScsiFifo); + if (!(lun & IDENTIFY_BASE)) printk (KERN_ERR "DC390: Resel: Expect identify message!\n"); + lun &= 7; + DEBUG0(printk ("(%02i-%i),", id, lun);) + pDCB = dc390_findDCB (pACB, id, lun); + if (!pDCB) { - pDCB = pDCB->pNextDCB; - if( pDCB == pACB->pLinkDCB ) - { - printk (KERN_ERR "DC390: Reselect from non existing device (ID %02x, LUN %02x)\n", - wval & 0xff, (wval & 0xff00) >> 8); - return; - } + printk (KERN_ERR "DC390: Reselect from non existing device (%02i-%i)\n", + id, lun); + return; } pACB->pActiveDCB = pDCB; + /* TagQ: We expect a message soon, so never mind the exact SRB */ if( pDCB->SyncMode & EN_TAG_QUEUEING ) { - pSRB = pACB->pTmpSRB; /* ?? */ + pSRB = pACB->pTmpSRB; pDCB->pActiveSRB = pSRB; } else @@ -1192,8 +1241,8 @@ { pSRB= pACB->pTmpSRB; pSRB->SRBState = SRB_UNEXPECT_RESEL; - printk (KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n", - wval & 0xff, (wval & 0xff00) >> 8); + printk (KERN_ERR "DC390: Reselect without outstanding cmnd (%02i-%i)\n", + id, lun); pDCB->pActiveSRB = pSRB; dc390_EnableMsgOut_Abort ( pACB, pSRB ); } @@ -1202,8 +1251,8 @@ if( pDCB->DCBFlag & ABORT_DEV_ ) { pSRB->SRBState = SRB_ABORT_SENT; - printk (KERN_INFO "DC390: Reselect: Abort (ID %02x, LUN %02x)\n", - wval & 0xff, (wval & 0xff00) >> 8); + printk (KERN_INFO "DC390: Reselect: Abort (%02i-%i)\n", + id, lun); dc390_EnableMsgOut_Abort( pACB, pSRB ); } else @@ -1213,7 +1262,7 @@ DEBUG1(printk (KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);) pSRB->ScsiPhase = SCSI_NOP0; - DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID); + DC390_write8 (Scsi_Dest_ID, pDCB->TargetID); DC390_write8 (Sync_Period, pDCB->SyncPeriod); DC390_write8 (Sync_Offset, pDCB->SyncOffset); DC390_write8 (CtrlReg1, pDCB->CtrlR1); @@ -1228,30 +1277,36 @@ { PDCB pPrevDCB = pACB->pLinkDCB; - pACB->DCBmap[pDCB->UnitSCSIID] &= ~(1 << pDCB->UnitSCSILUN); if (pDCB->GoingSRBCnt > 1) { DCBDEBUG(printk (KERN_INFO "DC390: Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n",\ - pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB, pDCB->GoingSRBCnt);) + pDCB->TargetID, pDCB->TargetLUN, (int)pDCB, pDCB->GoingSRBCnt);) return; }; + pACB->DCBmap[pDCB->TargetID] &= ~(1 << pDCB->TargetLUN); + // The first one if (pDCB == pACB->pLinkDCB) - { - if (pDCB->pNextDCB == pDCB) pDCB->pNextDCB = 0; + { + // The last one + if (pACB->pLastDCB == pDCB) { + pDCB->pNextDCB = 0; pACB->pLastDCB = 0; + } pACB->pLinkDCB = pDCB->pNextDCB; - pACB->pLastDCB->pNextDCB = 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 "DC390: Driver about to free DCB (ID %i, LUN %i): 0x%08x\n",\ - pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);) - kfree (pDCB); if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0; + DCBDEBUG(printk (KERN_INFO "DC390: 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--; */ }; @@ -1280,21 +1335,12 @@ || (pDCB->DevType == TYPE_MOD)) &&*/ !dc390_tagq_blacklist (((char*)ptr)+8) ) { - pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum; + if (pDCB->MaxCommand ==1) pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum; pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */; - pDCB->TagMask = 0; + //pDCB->TagMask = 0; } else - { - /* Do we really need to check for DevType here ? */ - if ( 0 /*(pDCB->DevMode & EN_DISCONNECT_)*/ - /* && ((pDCB->DevType == TYPE_DISK) - || (pDCB->DevType == TYPE_MOD))*/ ) - pDCB->SyncMode |= EN_ATN_STOP; - else - //pDCB->SyncMode &= ~EN_ATN_STOP; - pDCB->SyncMode &= ~0; - } + pDCB->MaxCommand = 1; } }; @@ -1312,60 +1358,62 @@ void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) { - PSRB psrb; - UCHAR bval, status, i; + UCHAR bval, status, i, DCB_removed; PSCSICMD pcmd; PSCSI_INQDATA ptr; PSGL ptr2; ULONG swlval; - pcmd = pSRB->pcmd; + pcmd = pSRB->pcmd; DCB_removed = 0; status = pSRB->TargetStatus; + ptr = (PSCSI_INQDATA) (pcmd->request_buffer); + if( pcmd->use_sg ) + ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); + DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\ pSRB, pcmd->pid);) if(pSRB->SRBFlag & AUTO_REQSENSE) { /* Last command was a Request Sense */ pSRB->SRBFlag &= ~AUTO_REQSENSE; pSRB->AdaptStatus = 0; - pSRB->TargetStatus = SCSI_STAT_CHECKCOND; + pSRB->TargetStatus = CHECK_CONDITION << 1; #ifdef DC390_REMOVABLEDEBUG switch (pcmd->sense_buffer[2] & 0x0f) { case NOT_READY: printk (KERN_INFO "DC390: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, status, pACB->scan_devices); break; case UNIT_ATTENTION: printk (KERN_INFO "DC390: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, status, pACB->scan_devices); break; case ILLEGAL_REQUEST: printk (KERN_INFO "DC390: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, status, pACB->scan_devices); break; case MEDIUM_ERROR: printk (KERN_INFO "DC390: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, status, pACB->scan_devices); break; case HARDWARE_ERROR: printk (KERN_INFO "DC390: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i)\n", - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN, + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN, status, pACB->scan_devices); break; } #endif - //pcmd->result = DRIVER_SENSE << 24 | DID_OK << 16 | status; - if(status == SCSI_STAT_CHECKCOND) + //pcmd->result = MK_RES(DRIVER_SENSE,DID_OK,0,status); + if (status == (CHECK_CONDITION << 1)) { - pcmd->result = DID_BAD_TARGET << 16; + pcmd->result = MK_RES_LNX(0,DID_BAD_TARGET,0,/*CHECK_CONDITION*/0); goto ckc_e; } if(pSRB->RetryCnt == 0) { - (ULONG)(pSRB->CmdBlock[0]) = pSRB->Segment0[0]; - pSRB->TotalXferredLen = pSRB->Segment1[1]; + //(UINT)(pSRB->pcmd->cmnd[0]) = pSRB->Segment0[0]; + pSRB->TotalXferredLen = pSRB->SavedTotXLen; if( (pSRB->TotalXferredLen) && (pSRB->TotalXferredLen >= pcmd->underflow) ) - pcmd->result |= (DID_OK << 16); + SET_RES_DID(pcmd->result,DID_OK) else - pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) | - SCSI_STAT_CHECKCOND; - REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\ - (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);) + pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION); + REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->pcmd->cmnd[0],\ + (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);) goto ckc_e; } else /* Retry */ @@ -1373,20 +1421,20 @@ pSRB->RetryCnt--; pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; - *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; - *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1]; + //*((PUINT) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; + //*((PUINT) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1]; /* Don't retry on TEST_UNIT_READY */ - if( pSRB->CmdBlock[0] == TEST_UNIT_READY /* || pSRB->CmdBlock[0] == START_STOP */) + if( pSRB->pcmd->cmnd[0] == TEST_UNIT_READY /* || pSRB->pcmd->cmnd[0] == START_STOP */) { - pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) - | SCSI_STAT_CHECKCOND; - REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[0],\ + pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION); + REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->pcmd->cmnd[0],\ (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);) goto ckc_e; } - pcmd->result |= (DRIVER_SENSE << 24); - pSRB->SGcount = (UCHAR) pSRB->Segment1[0]; - pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8); + SET_RES_DRV(pcmd->result,DRIVER_SENSE); + pSRB->SGcount = (UCHAR) pSRB->SavedSGCount; + //pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8); + DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->target, pcmd->lun);) pSRB->SGIndex = 0; pSRB->TotalXferredLen = 0; pSRB->SGToBeXferLen = 0; @@ -1397,18 +1445,20 @@ pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; pSRB->Segmentx.length = pcmd->request_bufflen; + } + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) { + dc390_Going_to_Waiting ( pDCB, pSRB ); + dc390_waiting_timer (pACB, HZ/5); } - if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) - dc390_RewaitSRB( pDCB, pSRB ); return; } } if( status ) { - if( status == SCSI_STAT_CHECKCOND) + if( status_byte(status) == CHECK_CONDITION ) { - REMOVABLEDEBUG(printk (KERN_INFO "DC390: Scsi_Stat_CheckCond (Cmd %02x, Id %02x, LUN %02x)\n",\ - pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) + REMOVABLEDEBUG(printk (KERN_INFO "DC390: Check_Condition (Cmd %02x, Id %02x, LUN %02x)\n",\ + pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN);) if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) ) { bval = pSRB->SGcount; @@ -1425,12 +1475,14 @@ dc390_RequestSense( pACB, pDCB, pSRB ); return; } - else if( status == SCSI_STAT_QUEUEFULL ) + else if( status_byte(status) == QUEUE_FULL ) { bval = (UCHAR) pDCB->GoingSRBCnt; bval--; pDCB->MaxCommand = bval; - dc390_RewaitSRB( pDCB, pSRB ); + dc390_freetag (pDCB, pSRB); + dc390_Going_to_Waiting ( pDCB, pSRB ); + dc390_waiting_timer (pACB, HZ/5); pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; return; @@ -1439,23 +1491,23 @@ { pSRB->AdaptStatus = H_SEL_TIMEOUT; pSRB->TargetStatus = 0; - pcmd->result = DID_BAD_TARGET << 16; + pcmd->result = MK_RES(0,DID_NO_CONNECT,0,0); /* Devices are removed below ... */ } - else if (status == SCSI_STAT_BUSY && - (pSRB->CmdBlock[0] == TEST_UNIT_READY || pSRB->CmdBlock[0] == INQUIRY) && + else if (status_byte(status) == BUSY && + (pcmd->cmnd[0] == TEST_UNIT_READY || pcmd->cmnd[0] == INQUIRY) && pACB->scan_devices) { pSRB->AdaptStatus = 0; pSRB->TargetStatus = status; - pcmd->result = (ULONG) (pSRB->EndMessage << 8) - /* | (ULONG) status */; + pcmd->result = MK_RES(0,0,pSRB->EndMessage,/*status*/0); } else { /* Another error */ pSRB->AdaptStatus = 0; if( pSRB->RetryCnt ) { /* Retry */ + //printk ("DC390: retry\n"); pSRB->RetryCnt--; pSRB->TargetStatus = 0; pSRB->SGIndex = 0; @@ -1469,14 +1521,18 @@ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; pSRB->Segmentx.length = pcmd->request_bufflen; } - if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) - dc390_RewaitSRB( pDCB, pSRB ); - return; + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) { + dc390_Going_to_Waiting ( pDCB, pSRB ); + dc390_waiting_timer (pACB, HZ/5); + } + return; } else { /* Report error */ - pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) | - (ULONG) status; + //pcmd->result = MK_RES(0, DID_ERROR, pSRB->EndMessage, status); + SET_RES_DID(pcmd->result,DID_ERROR); + SET_RES_MSG(pcmd->result,pSRB->EndMessage); + SET_RES_TARGET(pcmd->result,status); } } } @@ -1486,38 +1542,52 @@ 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); + //pcmd->result = MK_RES(0,DID_PARITY,pSRB->EndMessage,0); + 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); } } + if ((pcmd->result & RES_DID) == 0 && + pcmd->cmnd[0] == INQUIRY && + pcmd->cmnd[2] == 0 && + pcmd->request_bufflen >= 8 && + ptr && + (ptr->Vers & 0x07) >= 2) + pDCB->Inquiry7 = ptr->Flags; ckc_e: if( pACB->scan_devices ) { - if( pSRB->CmdBlock[0] == TEST_UNIT_READY ) + if( pcmd->cmnd[0] == TEST_UNIT_READY || + pcmd->cmnd[0] == INQUIRY) { #ifdef DC390_DEBUG0 - printk (KERN_INFO "DC390: Test_Unit_Ready: result: %08x", pcmd->result); - if (pcmd->result & DRIVER_SENSE << 24) printk (" (sense: %02x %02x %02x %02x)\n", + printk (KERN_INFO "DC390: %s: result: %08x", + (pcmd->cmnd[0] == INQUIRY? "INQUIRY": "TEST_UNIT_READY"), + pcmd->result); + if (pcmd->result & (DRIVER_SENSE << 24)) printk (" (sense: %02x %02x %02x %02x)\n", pcmd->sense_buffer[0], pcmd->sense_buffer[1], pcmd->sense_buffer[2], pcmd->sense_buffer[3]); else printk ("\n"); #endif - if((pcmd->result != (DID_OK << 16) && !(pcmd->result & SCSI_STAT_CHECKCOND) && !(pcmd->result & SCSI_STAT_BUSY)) || - ((pcmd->result & DRIVER_SENSE << 24) && (pcmd->sense_buffer[0] & 0x70) == 0x70 && - (pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || pcmd->result & DID_ERROR << 16) + if( (host_byte(pcmd->result) != DID_OK && !(status_byte(pcmd->result) & CHECK_CONDITION) && !(status_byte(pcmd->result) & BUSY)) || + ((driver_byte(pcmd->result) & DRIVER_SENSE) && (pcmd->sense_buffer[0] & 0x70) == 0x70 && + (pcmd->sense_buffer[2] & 0xf) == ILLEGAL_REQUEST) || host_byte(pcmd->result) & DID_ERROR ) { /* device not present: remove */ - dc390_remove_dev (pACB, pDCB); + //dc390_Going_remove (pDCB, pSRB); + dc390_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)) ) @@ -1534,16 +1604,17 @@ } } - if( pSRB->CmdBlock[0] == INQUIRY && - (pcmd->result == DID_OK << 16 || pcmd->result & SCSI_STAT_CHECKCOND) ) + //if( pSRB->pcmd->cmnd[0] == INQUIRY && + // (host_byte(pcmd->result) == DID_OK || status_byte(pcmd->result) & CHECK_CONDITION) ) + if( pcmd->cmnd[0] == INQUIRY && + (pcmd->result == (DID_OK << 16) || status_byte(pcmd->result) & CHECK_CONDITION) ) { - ptr = (PSCSI_INQDATA) (pcmd->request_buffer); - if( pcmd->use_sg ) - ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); - if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV) + if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV && !DCB_removed) { + //printk ("DC390: Type = nodev! (%02i-%i)\n", pcmd->target, pcmd->lun); /* device not present: remove */ - dc390_remove_dev (pACB, pDCB); + //dc390_Going_remove (pDCB, pSRB); + dc390_remove_dev (pACB, pDCB); DCB_removed = 1; } else { @@ -1555,40 +1626,29 @@ (pcmd->lun == pACB->pScsiHost->max_lun - 1) ) pACB->scan_devices = 0; }; -/* dc390_ReleaseSRB( pDCB, pSRB ); */ - if(pSRB == pDCB->pGoingSRB ) - { - pDCB->pGoingSRB = pSRB->pNextSRB; - } - else - { - psrb = pDCB->pGoingSRB; - while( psrb->pNextSRB != pSRB ) - psrb = psrb->pNextSRB; - psrb->pNextSRB = pSRB->pNextSRB; - if( pSRB == pDCB->pGoingLast ) - pDCB->pGoingLast = psrb; - } - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; - pDCB->GoingSRBCnt--; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,30) + pcmd->resid = pcmd->request_bufflen - pSRB->TotalXferredLen; +#endif - dc390_DoWaitingSRB( pACB ); + if (!DCB_removed) dc390_Going_remove (pDCB, pSRB); + /* Add to free list */ + dc390_Free_insert (pACB, pSRB); + DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->pid);) DC390_UNLOCK_ACB_NI; - pcmd->scsi_done( pcmd ); + pcmd->scsi_done (pcmd); DC390_LOCK_ACB_NI; - if( pDCB->QIORBCnt ) - dc390_DoNextCmd( pACB, pDCB ); + dc390_Query_to_Waiting (pACB); + dc390_Waiting_process (pACB); return; } -/* Remove all SRBs and tell midlevel code DID_RESET */ +/* Remove all SRBs from Going list and inform midlevel */ void -dc390_DoingSRB_Done( PACB pACB ) +dc390_DoingSRB_Done( PACB pACB, PSCSICMD cmd ) { PDCB pDCB, pdcb; PSRB psrb, psrb2; @@ -1605,16 +1665,21 @@ { psrb2 = psrb->pNextSRB; pcmd = psrb->pcmd; - pcmd->result = DID_RESET << 16; + dc390_Free_insert (pACB, psrb); +#ifndef USE_NEW_EH + /* New EH will crash on being given timed out cmnds */ + if (pcmd == cmd) + pcmd->result = MK_RES(0,DID_ABORT,0,0); + else + pcmd->result = MK_RES(0,DID_RESET,0,0); /* ReleaseSRB( pDCB, pSRB ); */ - psrb->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = psrb; - + DEBUG0(printk (KERN_DEBUG "DC390: DoingSRB_Done: done pid %li\n", pcmd->pid);) DC390_UNLOCK_ACB_NI; pcmd->scsi_done( pcmd ); DC390_LOCK_ACB_NI; +#endif psrb = psrb2; } pdcb->GoingSRBCnt = 0;; @@ -1622,21 +1687,21 @@ pdcb->TagMask = 0; pdcb = pdcb->pNextDCB; } while( pdcb != pDCB ); + dc390_Query_to_Waiting (pACB); } static void dc390_ResetSCSIBus( PACB pACB ) { - pACB->ACBFlag |= RESET_DEV; - - DC390_write8 (ScsiCmd, RST_DEVICE_CMD); - udelay (250); - DC390_write8 (ScsiCmd, NOP_CMD); + //DC390_write8 (ScsiCmd, RST_DEVICE_CMD); + //udelay (250); + //DC390_write8 (ScsiCmd, NOP_CMD); DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD); + pACB->Connected = 0; return; } @@ -1644,27 +1709,31 @@ static void dc390_ScsiRstDetect( PACB pACB ) { - printk ("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus); + printk ("DC390: Rst_Detect: laststat = %08x\n", dc390_laststatus); //DEBUG0(printk(KERN_INFO "RST_DETECT,");) + if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); /* Unlock before ? */ - /* delay a second */ - { unsigned int msec = 1*1000; while (--msec) udelay(1000); } + /* delay half a second */ + udelay (1000); DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + pACB->pScsiHost->last_reset = jiffies + 5*HZ/2 + + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; + pACB->Connected = 0; if( pACB->ACBFlag & RESET_DEV ) pACB->ACBFlag |= RESET_DONE; else - { + { /* Reset was issued by sb else */ pACB->ACBFlag |= RESET_DETECT; dc390_ResetDevParam( pACB ); -/* dc390_DoingSRB_Done( pACB ); ???? */ - dc390_RecoverSRB( pACB ); + dc390_DoingSRB_Done( pACB, 0 ); + //dc390_RecoverSRB( pACB ); pACB->pActiveDCB = NULL; pACB->ACBFlag = 0; - dc390_DoWaitingSRB( pACB ); + dc390_Waiting_process( pACB ); } return; } @@ -1676,15 +1745,17 @@ PSCSICMD pcmd; REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\ - pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) + pSRB->pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN);) pSRB->SRBFlag |= AUTO_REQSENSE; - pSRB->Segment0[0] = (ULONG) pSRB->CmdBlock[0]; - pSRB->Segment0[1] = (ULONG) pSRB->CmdBlock[4]; - pSRB->Segment1[0] = (ULONG) ((pSRB->ScsiCmdLen << 8) + pSRB->SGcount); - pSRB->Segment1[1] = pSRB->TotalXferredLen; + //pSRB->Segment0[0] = (UINT) pSRB->CmdBlock[0]; + //pSRB->Segment0[1] = (UINT) pSRB->CmdBlock[4]; + //pSRB->Segment1[0] = ((UINT)(pSRB->pcmd->cmd_len) << 8) + pSRB->SGcount; + //pSRB->Segment1[1] = pSRB->TotalXferredLen; + pSRB->SavedSGCount = pSRB->SGcount; + pSRB->SavedTotXLen = pSRB->TotalXferredLen; pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; /* SCSI_STAT_CHECKCOND; */ + pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */ pcmd = pSRB->pcmd; @@ -1694,16 +1765,18 @@ pSRB->SGcount = 1; pSRB->SGIndex = 0; - pSRB->CmdBlock[0] = REQUEST_SENSE; - pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5; - (USHORT) pSRB->CmdBlock[2] = 0; - (USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer); - pSRB->ScsiCmdLen = 6; + //pSRB->CmdBlock[0] = REQUEST_SENSE; + //pSRB->CmdBlock[1] = pDCB->TargetLUN << 5; + //(USHORT) pSRB->CmdBlock[2] = 0; + //(USHORT) pSRB->CmdBlock[4] = sizeof(pcmd->sense_buffer); + //pSRB->ScsiCmdLen = 6; pSRB->TotalXferredLen = 0; pSRB->SGToBeXferLen = 0; - if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) - dc390_RewaitSRB( pDCB, pSRB ); + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) { + dc390_Going_to_Waiting ( pDCB, pSRB ); + dc390_waiting_timer (pACB, HZ/5); + } } Index: tmscsim.c =================================================================== RCS file: /home/cvsroot/dc390/tmscsim.c,v retrieving revision 2.16 retrieving revision 2.60.2.30 diff -u -r2.16 -r2.60.2.30 --- tmscsim.c 1998/12/25 17:54:44 2.16 +++ tmscsim.c 2000/12/20 01:07:12 2.60.2.30 @@ -5,11 +5,11 @@ * Bus Master Host Adapter * * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. * ***********************************************************************/ -/* (C) Copyright: put under GNU GPL in 10/96 * +/* (C) Copyright: put under GNU GPL in 10/96 (see README.tmscsim) * *************************************************************************/ -/* $Id: tmscsim.c,v 2.16 1998/12/25 17:54:44 garloff Exp $ */ +/* $Id: tmscsim.c,v 2.60.2.30 2000/12/20 01:07:12 garloff Exp $ */ /* Enhancements and bugfixes by * - * Kurt Garloff * + * Kurt Garloff * ***********************************************************************/ /* HISTORY: * * * @@ -95,8 +95,75 @@ * 2.0c 98/11/19 KG Cleaned up detect/init for SMP boxes, * * Write Erase DMA (1.20t) caused problems * * 2.0d 98/12/25 KG Christmas release ;-) Message handling * - * competely reworked. Handle target ini- * + * completely reworked. Handle target ini- * * tiated SDTR correctly. * + * 2.0d1 99/01/25 KG Try to handle RESTORE_PTR * + * 2.0d2 99/02/08 KG Check for failure of kmalloc, correct * + * inclusion of scsicam.h, DelayReset * + * 2.0d3 99/05/31 KG DRIVER_OK -> DID_OK, DID_NO_CONNECT, * + * detect Target mode and warn. * + * pcmd->result handling cleaned up. * + * 2.0d4 99/06/01 KG Cleaned selection process. Found bug * + * which prevented more than 16 tags. Now: * + * 24. SDTR cleanup. Cleaner multi-LUN * + * handling. Don't modify ControlRegs/FIFO * + * when connected. * + * 2.0d5 99/06/01 KG Clear DevID, Fix INQUIRY after cfg chg. * + * 2.0d6 99/06/02 KG Added ADD special command to allow cfg. * + * before detection. Reset SYNC_NEGO_DONE * + * after a bus reset. * + * 2.0d7 99/06/03 KG Fixed bugs wrt add,remove commands * + * 2.0d8 99/06/04 KG Removed copying of cmnd into CmdBlock. * + * Fixed Oops in _release(). * + * 2.0d9 99/06/06 KG Also tag queue INQUIRY, T_U_R, ... * + * Allow arb. no. of Tagged Cmnds. Max 32 * + * 2.0d1099/06/20 KG TagMaxNo changes now honoured! Queueing * + * clearified (renamed ..) TagMask handling* + * cleaned. * + * 2.0d1199/06/28 KG cmd->result now identical to 2.0d2 * + * 2.0d1299/07/04 KG Changed order of processing in IRQ * + * 2.0d1399/07/05 KG Don't update DCB fields if removed * + * 2.0d1499/07/05 KG remove_dev: Move kfree() to the end * + * 2.0d1599/07/12 KG use_new_eh_code: 0, ULONG -> UINT where * + * appropriate * + * 2.0d1699/07/13 KG Reenable StartSCSI interrupt, Retry msg * + * 2.0d1799/07/15 KG Remove debug msg. Disable recfg. when * + * there are queued cmnds * + * 2.0d1899/07/18 KG Selection timeout: Don't requeue * + * 2.0d1999/07/18 KG Abort: Only call scsi_done if dequeued * + * 2.0d2099/07/19 KG Rst_Detect: DoingSRB_Done * + * 2.0d2199/08/15 KG dev_id for request/free_irq, cmnd[0] for* + * RETRY, SRBdone does DID_ABORT for the * + * cmd passed by DC390_reset() * + * 2.0d2299/08/25 KG dev_id fixed. can_queue: 42 * + * 2.0d2399/08/25 KG Removed some debugging code. dev_id * + * now is set to pACB. Use u8,u16,u32. * + * 2.0d2499/11/14 KG Unreg. I/O if failed IRQ alloc. Call * + * done () w/ DID_BAD_TARGET in case of * + * missing DCB. We are old EH!! * + * 2.0d2500/01/15 KG 2.3.3x compat from Andreas Schultz * + * set unique_id. Disable RETRY message. * + * 2.0d2600/01/29 KG Go to new EH. * + * 2.0d2700/01/31 KG ... but maintain 2.0 compat. * + * and fix DCB freeing * + * 2.0d2800/02/14 KG Queue statistics fixed, dump special cmd* + * Waiting_Timer for failed StartSCSI * + * New EH: Don't return cmnds to ML on RST * + * Use old EH (don't have new EH fns yet) * + * Reset: Unlock, but refuse to queue * + * 2.3 __setup function * + * 2.0e 00/05/22 KG Return residual for 2.3 * + * 2.0e1 00/05/25 KG Compile fixes for 2.3.99 * + * 2.0e2 00/05/27 KG Jeff Garzik's pci_enable_device() * + * 2.0e3 00/09/29 KG Some 2.4 changes. Don't try Sync Nego * + * before INQUIRY has reported ability. * + * Recognise INQUIRY as scanning command. * + * 2.0e4 00/10/13 KG Allow compilation into 2.4 kernel * + * 2.0e5 00/11/17 KG Store Inq.flags in DCB * + * 2.0e6 00/11/22 KG 2.4 init function (Thx to O.Schumann) * + * 2.4 PCI device table (Thx to A.Richter) * + * 2.0e7 00/11/28 KG Allow overriding of BIOS settings * + * 2.0f 00/12/20 KG Handle failed INQUIRYs during scan * ***********************************************************************/ /* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */ @@ -108,6 +175,7 @@ //#define DC390_DCBDEBUG //#define DC390_PARSEDEBUG //#define DC390_REMOVABLEDEBUG +//#define DC390_LOCKDEBUG /* Debug definitions */ #ifdef DC390_DEBUG0 @@ -159,12 +227,14 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" #include "constants.h" #include "sd.h" #include +#include #include "dc390.h" @@ -174,8 +244,7 @@ /* Note: Starting from 2.1.9x, the mid-level scsi code issues a * spinlock_irqsave (&io_request_lock) before calling the driver's - * routines, so we don't need to lock. - * TODO: Verify, if we are locked in every case! + * routines, so we don't need to lock, except in the IRQ handler. * The policy 3, let the midlevel scsi code do the io_request_locks * and us locking on a driver specific lock, shouldn't hurt anybody; it * just causes a minor performance degradation for setting the locks. @@ -188,31 +257,46 @@ * undef : traditional save_flags; cli; restore_flags; */ -//#define DEBUG_SPINLOCKS 2 /* Set to 0, 1 or 2 in include/asm/spinlock.h */ +//#define DEBUG_SPINLOCKS 2 /* Set to 0, 1 or 2 in include/linux/spinlock.h */ -#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) - -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) # include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30) +# include +#else # include #endif +#endif -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93) # define USE_SPINLOCKS 1 # define NEW_PCI 1 #else # undef NEW_PCI -# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) # define USE_SPINLOCKS 2 # endif #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,99) +static struct pci_device_id tmscsim_pci_tbl[] __initdata = { + { + vendor: PCI_VENDOR_ID_AMD, + device: PCI_DEVICE_ID_AMD53C974, + subvendor: PCI_ANY_ID, + subdevice: PCI_ANY_ID, + }, + { } /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, tmscsim_pci_tbl); +#endif + #ifdef USE_SPINLOCKS # if USE_SPINLOCKS == 3 /* both */ -# if defined (__SMP__) || DEBUG_SPINLOCKS > 0 +# if defined (CONFIG_SMP) || DEBUG_SPINLOCKS > 0 # define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; }; # else # define DC390_LOCKA_INIT @@ -319,7 +403,11 @@ # define PCI_PRESENT pci_present () # define PCI_SET_MASTER pci_set_master (pdev) # define PCI_FIND_DEVICE(vend, id) (pdev = pci_find_device (vend, id, pdev)) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,10) +# define PCI_GET_IO_AND_IRQ io_port = pci_resource_start (pdev, 0); irq = pdev->irq +#else # define PCI_GET_IO_AND_IRQ io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; irq = pdev->irq +#endif #else # include # define PDEV pbus, pdevfn @@ -368,7 +456,7 @@ void dc390_Disconnect( PACB pACB ); void dc390_Reselect( PACB pACB ); void dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ); -void dc390_DoingSRB_Done( PACB pACB ); +void dc390_DoingSRB_Done( PACB pACB, PSCSICMD cmd ); static void dc390_ScsiRstDetect( PACB pACB ); static void dc390_ResetSCSIBus( PACB pACB ); static void __inline__ dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ); @@ -378,7 +466,7 @@ void do_DC390_Interrupt( int, void *, struct pt_regs *); int dc390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, UCHAR index ); -void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd ); +void dc390_initDCB( PACB pACB, PDCB *ppDCB, UCHAR id, UCHAR lun); void dc390_updateDCB (PACB pACB, PDCB pDCB); #ifdef MODULE @@ -392,31 +480,19 @@ //static PSH dc390_pSH_current = NULL; static PACB dc390_pACB_start= NULL; static PACB dc390_pACB_current = NULL; -static UCHAR dc390_adapterCnt = 0; -static UCHAR dc390_CurrSyncOffset = 0; static ULONG dc390_lastabortedpid = 0; -static ULONG dc390_laststatus = 0; +static UINT dc390_laststatus = 0; +static UCHAR dc390_adapterCnt = 0; -#ifndef CONFIG_SCSI_DC390T_NOGENSUPP /* Startup values, to be overriden on the commandline */ -int tmscsim[] = {7, 1 /* 8MHz */, - PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_ - | SYNC_NEGO_ | TAG_QUEUEING_, - MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION - /* | NO_SEEK */ -# ifdef CONFIG_SCSI_MULTI_LUN - | LUN_CHECK -# endif - , 3 /* 16 Tags per LUN */}; +int tmscsim[] = {-2, -2, -2, -2, -2, -2}; -# if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) -MODULE_PARM(tmscsim, "1-5i"); -MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1)"); +# if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) +MODULE_PARM(tmscsim, "1-6i"); +MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1), DelayReset (s)"); # endif - -#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */ -#if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +#if defined(MODULE) && LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,30) MODULE_AUTHOR("C.L. Huang / Kurt Garloff"); MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters"); MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); @@ -481,12 +557,14 @@ static char* dc390_adapname = "DC390"; UCHAR dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN]; UCHAR dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20}; +UCHAR dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20}; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,30) struct proc_dir_entry DC390_proc_scsi_tmscsim ={ PROC_SCSI_DC390T, 7 ,"tmscsim", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; - +#endif /*********************************************************************** * Functions for access to DC390 EEPROM @@ -510,59 +588,107 @@ udelay(160); } -#ifndef CONFIG_SCSI_DC390T_NOGENSUPP -static void __init dc390_EEpromDefaults (UCHAR index) + +/* Override EEprom values with explicitly set values */ +static void __init dc390_EEprom_Override (UCHAR index) { PUCHAR ptr; UCHAR id; ptr = (PUCHAR) dc390_eepromBuf[index]; /* Adapter Settings */ - ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */ - ptr[EE_MODE2] = (UCHAR)tmscsim[3]; - ptr[EE_DELAY] = 0; /* ?? */ - ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Comds */ + if (tmscsim[0] != -2) + ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */ + if (tmscsim[3] != -2) + ptr[EE_MODE2] = (UCHAR)tmscsim[3]; + if (tmscsim[5] != -2) + ptr[EE_DELAY] = tmscsim[5]; /* Reset delay */ + if (tmscsim[4] != -2) + ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Cmds */ /* Device Settings */ for (id = 0; id < MAX_SCSI_ID; id++) { - ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */ - ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */ + if (tmscsim[2] != -2) + ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */ + if (tmscsim[1] != -2) + ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */ }; - dc390_adapname = "AM53C974"; } -static void __init dc390_checkparams (void) +/* Handle "-1" case */ +static void __init dc390_check_for_safe_settings (void) { - PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x\n", tmscsim[0],\ - tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4]);) - if (tmscsim[0] < 0 || tmscsim[0] > 7) /* modules-2.0.0 passes -1 as string */ + if (tmscsim[0] == -1 || tmscsim[0] > 15) /* modules-2.0.0 passes -1 as string */ { - tmscsim[0] = 7; tmscsim[1] = 4; - tmscsim[2] = 9; tmscsim[3] = 15; - tmscsim[4] = 2; + tmscsim[0] = 7; tmscsim[1] = 4; + tmscsim[2] = 0x09; tmscsim[3] = 0x0f; + tmscsim[4] = 2; tmscsim[5] = 10; printk (KERN_INFO "DC390: Using safe settings.\n"); } - else +} + + +#ifndef CONFIG_SCSI_DC390T_NOGENSUPP +int __initdata tmscsim_def[] = {7, 0 /* 10MHz */, + PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_ + | SYNC_NEGO_ | TAG_QUEUEING_, + MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION + /* | NO_SEEK */ +# ifdef CONFIG_SCSI_MULTI_LUN + | LUN_CHECK +# endif + , 3 /* 16 Tags per LUN */, 1 /* s delay after Reset */ }; + +/* Copy defaults over set values where missing */ +static void __init dc390_fill_with_defaults (void) +{ + int i; + PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x %08x\n", tmscsim[0],\ + tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4], tmscsim[5]);) + for (i = 0; i < 6; i++) { - /* if (tmscsim[0] < 0 || tmscsim[0] > 7) tmscsim[0] = 7; */ - if (tmscsim[1] < 0 || tmscsim[1] > 7) tmscsim[1] = 4; - if (tmscsim[4] < 0 || tmscsim[4] > 5) tmscsim[4] = 4; - }; + if (tmscsim[i] < 0 || tmscsim[i] > 255) + tmscsim[i] = tmscsim_def[i]; + } + /* Sanity checks */ + if (tmscsim[0] > 7) tmscsim[0] = 7; + if (tmscsim[1] > 7) tmscsim[1] = 4; + if (tmscsim[4] > 5) tmscsim[4] = 4; + if (tmscsim[5] > 180) tmscsim[5] = 180; }; +#endif + /* Override defaults on cmdline: * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped) */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) +void __init dc390_setup (char *str) +{ + int ints[8]; + int i, im; + (void)get_options (str, ARRAY_SIZE(ints), ints); +#else void __init dc390_setup (char *str, int *ints) { - int i; - for (i = 0; i < ints[0]; i++) - tmscsim[i] = ints[i+1]; - if (ints[0] > 5) + int i, im; +#endif + im = ints[0]; + if (im > 6) + { printk (KERN_NOTICE "DC390: ignore extra params!\n"); + im = 6; + }; + for (i = 0; i < im; i++) + tmscsim[i] = ints[i+1]; /* dc390_checkparams (); */ }; -#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,13) +#ifndef MODULE +__setup("tmscsim=", dc390_setup); +#endif +#endif static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry ) @@ -651,6 +777,12 @@ } +static void __init dc390_interpret_delay (UCHAR index) +{ + char interpd [] = {1,3,5,10,16,30,60,120}; + dc390_eepromBuf[index][EE_DELAY] = interpd [dc390_eepromBuf[index][EE_DELAY]]; +}; + static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index ) { UCHAR i; @@ -661,6 +793,8 @@ memcpy (dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID); memcpy (&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID], &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID); + dc390_interpret_delay (index); + wval = 0; for(i=0; i<0x40; i++, ptr++) wval += *ptr; @@ -673,65 +807,94 @@ * (DCBs, SRBs, Queueing) * **********************************************************************/ -static PDCB __inline__ dc390_findDCB ( PACB pACB, Scsi_Cmnd *cmd) +static PDCB __inline__ dc390_findDCB ( PACB pACB, UCHAR id, UCHAR lun) { PDCB pDCB = pACB->pLinkDCB; if (!pDCB) return 0; - while (pDCB->UnitSCSIID != cmd->target || pDCB->UnitSCSILUN != cmd->lun) + while (pDCB->TargetID != id || pDCB->TargetLUN != lun) { pDCB = pDCB->pNextDCB; if (pDCB == pACB->pLinkDCB) { - printk (KERN_WARNING "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n", - (int)pDCB, cmd->target, pACB->DCBmap[cmd->target]); + DCBDEBUG(printk (KERN_WARNING "DC390: DCB not found (DCB=%p, DCBmap[%2x]=%2x)\n", + pDCB, id, pACB->DCBmap[id]);) return 0; } }; - DCBDEBUG1( printk (KERN_DEBUG "DCB %08x (%02x,%02x) found.\n", \ - (int)pDCB, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) + DCBDEBUG1( printk (KERN_DEBUG "DCB %p (%02x,%02x) found.\n", \ + pDCB, pDCB->TargetID, pDCB->TargetLUN);) return pDCB; }; -static void dc390_QLinkcmd( PSCSICMD cmd, PDCB pDCB ) -{ - PSCSICMD pcmd; +/* 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 + */ + - if( !pDCB->QIORBCnt ) +#if 0 +/* Look for a SCSI cmd in a SRB queue */ +static PSRB dc390_find_cmd_in_SRBq (PSCSICMD cmd, PSRB queue) +{ + 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 dc390_Query_append( PSCSICMD cmd, PACB pACB ) +{ + DEBUG0(printk ("DC390: 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; - } + pACB->pQueryTail->next = cmd; + pACB->pQueryTail = cmd; + pACB->QueryCnt++; + pACB->CmdOutOfSRB++; + cmd->next = NULL; } -static __inline__ PSCSICMD dc390_Getcmd( PDCB pDCB ) +/* Return next cmd from Query list */ +static PSCSICMD dc390_Query_get ( PACB pACB ) { PSCSICMD pcmd; - pcmd = pDCB->pQIORBhead; - pDCB->pQIORBhead = pcmd->next; + pcmd = pACB->pQueryHead; + if (!pcmd) return pcmd; + DEBUG0(printk ("DC390: Get cmd %li from Query\n", pcmd->pid);) + pACB->pQueryHead = pcmd->next; pcmd->next = NULL; - pDCB->QIORBCnt--; - + if (!pACB->pQueryHead) pACB->pQueryTail = NULL; + pACB->QueryCnt--; return( pcmd ); } -static __inline__ PSRB dc390_GetSRB( PACB pACB ) +/* Return next free SRB */ +static __inline__ PSRB dc390_Free_get ( PACB pACB ) { PSRB pSRB; pSRB = pACB->pFreeSRB; + DEBUG0(printk ("DC390: Get Free SRB %p\n", pSRB);) if( pSRB ) { pACB->pFreeSRB = pSRB->pNextSRB; @@ -741,130 +904,174 @@ return( pSRB ); } - -static __inline__ void dc390_RewaitSRB0( PDCB pDCB, PSRB pSRB ) +/* Insert SRB oin top of free list */ +static __inline__ void dc390_Free_insert (PACB pACB, PSRB pSRB) { - PSRB psrb1; + DEBUG0(printk ("DC390: Free SRB %p\n", pSRB);) + pSRB->pNextSRB = pACB->pFreeSRB; + pACB->pFreeSRB = pSRB; +} - if( (psrb1 = pDCB->pWaitingSRB) ) - { - pSRB->pNextSRB = psrb1; - } - else - { - pSRB->pNextSRB = NULL; + +/* Inserts a SRB to the top of the Waiting list */ +static __inline__ void dc390_Waiting_insert ( PDCB pDCB, PSRB pSRB ) +{ + DEBUG0(printk ("DC390: 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++; } -static void dc390_RewaitSRB( PDCB pDCB, PSRB pSRB ) +/* Queue SRB to waiting list */ +static __inline__ void dc390_Waiting_append ( PDCB pDCB, PSRB pSRB) { - PSRB psrb1; - UCHAR bval; - - pDCB->GoingSRBCnt--; pDCB->pDCBACB->SelLost++; - DEBUG0(printk(KERN_INFO "DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);) - psrb1 = pDCB->pGoingSRB; - if( pSRB == psrb1 ) - { - pDCB->pGoingSRB = psrb1->pNextSRB; - } + DEBUG0(printk ("DC390: Append pSRB %p cmd %li to Waiting\n", pSRB, pSRB->pcmd->pid);) + if( pDCB->pWaitingSRB ) + pDCB->pWaitLast->pNextSRB = pSRB; else - { - while( pSRB != psrb1->pNextSRB ) - psrb1 = psrb1->pNextSRB; - psrb1->pNextSRB = pSRB->pNextSRB; - if( pSRB == pDCB->pGoingLast ) - pDCB->pGoingLast = psrb1; - } - if( (psrb1 = pDCB->pWaitingSRB) ) - { - pSRB->pNextSRB = psrb1; pDCB->pWaitingSRB = pSRB; - } + + pDCB->pWaitLast = pSRB; + pSRB->pNextSRB = NULL; + pDCB->WaitSRBCnt++; + pDCB->pDCBACB->CmdInQ++; +} + +static __inline__ void dc390_Going_append (PDCB pDCB, PSRB pSRB) +{ + pDCB->GoingSRBCnt++; + DEBUG0(printk("DC390: Append SRB %p to Going\n", pSRB);) + /* Append to the list of Going commands */ + if( pDCB->pGoingSRB ) + pDCB->pGoingLast->pNextSRB = pSRB; else - { - pSRB->pNextSRB = NULL; - pDCB->pWaitingSRB = pSRB; - pDCB->pWaitLast = pSRB; - } + pDCB->pGoingSRB = pSRB; + + pDCB->pGoingLast = pSRB; + /* No next one in sent list */ + pSRB->pNextSRB = NULL; +}; + +static __inline__ void dc390_Going_remove (PDCB pDCB, PSRB pSRB) +{ + DEBUG0(printk("DC390: Remove SRB %p from Going\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 "DC390: Remove non-ex. SRB %p from Going!\n", pSRB); return; } + psrb->pNextSRB = pSRB->pNextSRB; + if (pSRB == pDCB->pGoingLast) + pDCB->pGoingLast = psrb; + } + pDCB->GoingSRBCnt--; +}; + +/* Moves SRB from Going list to the top of Waiting list */ +static void dc390_Going_to_Waiting ( PDCB pDCB, PSRB pSRB ) +{ + DEBUG0(printk(KERN_INFO "DC390: Going_to_Waiting (SRB %p) pid = %li\n", pSRB, pSRB->pcmd->pid);) + /* Remove SRB from Going */ + dc390_Going_remove (pDCB, pSRB); + /* Insert on top of Waiting */ + dc390_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 dc390_Waiting_to_Going ( PDCB pDCB, PSRB pSRB ) +{ + /* Remove from waiting list */ + DEBUG0(printk("DC390: Remove SRB %p from head of Waiting\n", pSRB);) + pDCB->pWaitingSRB = pSRB->pNextSRB; + if( !pDCB->pWaitingSRB ) pDCB->pWaitLast = NULL; + pDCB->WaitSRBCnt--; + dc390_Going_append (pDCB, pSRB); +} + +/* 2.0 timer compatibility */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,30) + static inline int timer_pending(struct timer_list * timer) + { + return timer->prev != NULL; + } + #define time_after(a,b) ((long)(b) - (long)(a) < 0) + #define time_before(a,b) time_after(b,a) +#endif - bval = pSRB->TagNumber; - pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */ +void DC390_waiting_timed_out (unsigned long ptr); +/* Sets the timer to wake us up */ +static void dc390_waiting_timer (PACB pACB, unsigned long to) +{ + if (timer_pending (&pACB->Waiting_Timer)) return; + init_timer (&pACB->Waiting_Timer); + pACB->Waiting_Timer.function = DC390_waiting_timed_out; + pACB->Waiting_Timer.data = (unsigned long)pACB; + if (time_before (jiffies + to, pACB->pScsiHost->last_reset)) + pACB->Waiting_Timer.expires = pACB->pScsiHost->last_reset + 1; + else + pACB->Waiting_Timer.expires = jiffies + to + 1; + add_timer (&pACB->Waiting_Timer); } -static void dc390_DoWaitingSRB( PACB pACB ) +/* Send the next command from the waiting list to the bus */ +static void dc390_Waiting_process ( PACB pACB ) { PDCB ptr, ptr1; PSRB pSRB; - if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) ) - { - ptr = pACB->pDCBRunRobin; - if( !ptr ) - { - ptr = pACB->pLinkDCB; - pACB->pDCBRunRobin = ptr; - } - ptr1 = ptr; - for( ;ptr1; ) - { - pACB->pDCBRunRobin = ptr1->pNextDCB; - if( !( ptr1->MaxCommand > ptr1->GoingSRBCnt ) || - !( pSRB = ptr1->pWaitingSRB ) ) - { - if(pACB->pDCBRunRobin == ptr) - break; - ptr1 = ptr1->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( !dc390_StartSCSI(pACB, ptr1, pSRB) ) + dc390_Waiting_to_Going (ptr1, pSRB); else - { - if( !dc390_StartSCSI(pACB, ptr1, pSRB) ) - { - ptr1->GoingSRBCnt++; - if( ptr1->pWaitLast == pSRB ) - { - ptr1->pWaitingSRB = NULL; - ptr1->pWaitLast = NULL; - } - else - { - ptr1->pWaitingSRB = pSRB->pNextSRB; - } - pSRB->pNextSRB = NULL; - - if( ptr1->pGoingSRB ) - ptr1->pGoingLast->pNextSRB = pSRB; - else - ptr1->pGoingSRB = pSRB; - ptr1->pGoingLast = pSRB; - } - break; - } - } - } + dc390_waiting_timer (pACB, HZ/5); + break; + } + } while (ptr1 != ptr); return; } - -static __inline__ void dc390_SRBwaiting( PDCB pDCB, PSRB pSRB) +/* Wake up waiting queue */ +void DC390_waiting_timed_out (unsigned long ptr) { - if( pDCB->pWaitingSRB ) - { - pDCB->pWaitLast->pNextSRB = pSRB; - pSRB->pNextSRB = NULL; - } - else - { - pDCB->pWaitingSRB = pSRB; - } - pDCB->pWaitLast = pSRB; + PACB pACB = (PACB)ptr; + DC390_IFLAGS + DC390_AFLAGS + DEBUG0(printk ("DC390: Debug: Waiting queue woken up by timer!\n");) + DC390_LOCK_IO; + DC390_LOCK_ACB; + dc390_Waiting_process (pACB); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; } - /*********************************************************************** * Function: static void dc390_SendSRB (PACB pACB, PSRB pSRB) * @@ -877,41 +1084,33 @@ PDCB pDCB; pDCB = pSRB->pSRBDCB; - if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || + if( (pDCB->MaxCommand <= pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) ) { - dc390_SRBwaiting(pDCB, pSRB); - goto SND_EXIT; + dc390_Waiting_append (pDCB, pSRB); + dc390_Waiting_process (pACB); + return; } +#if 0 if( pDCB->pWaitingSRB ) { - dc390_SRBwaiting(pDCB, pSRB); + dc390_Waiting_append (pDCB, pSRB); /* pSRB = GetWaitingSRB(pDCB); */ /* non-existent */ pSRB = pDCB->pWaitingSRB; + /* Remove from waiting list */ pDCB->pWaitingSRB = pSRB->pNextSRB; pSRB->pNextSRB = NULL; + if (!pDCB->pWaitingSRB) pDCB->pWaitLast = NULL; } - - if( !dc390_StartSCSI(pACB, pDCB, pSRB) ) - { - pDCB->GoingSRBCnt++; - if( pDCB->pGoingSRB ) - { - pDCB->pGoingLast->pNextSRB = pSRB; - pDCB->pGoingLast = pSRB; - } - else - { - pDCB->pGoingSRB = pSRB; - pDCB->pGoingLast = pSRB; - } - } - else - dc390_RewaitSRB0( pDCB, pSRB ); - -SND_EXIT: - return; +#endif + + if (!dc390_StartSCSI(pACB, pDCB, pSRB)) + dc390_Going_append (pDCB, pSRB); + else { + dc390_Waiting_insert (pDCB, pSRB); + dc390_waiting_timer (pACB, HZ/5); + }; } /*********************************************************************** @@ -926,8 +1125,8 @@ { pSRB->pSRBDCB = pDCB; pSRB->pcmd = pcmd; - pSRB->ScsiCmdLen = pcmd->cmd_len; - memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len); + //pSRB->ScsiCmdLen = pcmd->cmd_len; + //memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len); if( pcmd->use_sg ) { @@ -960,9 +1159,40 @@ pSRB->SGToBeXferLen = 0; pSRB->ScsiPhase = 0; pSRB->EndMessage = 0; + pSRB->TagNumber = 255; }; +/* Put cmnd from Query to Waiting list and send next Waiting cmnd */ +static void dc390_Query_to_Waiting (PACB pACB) +{ + Scsi_Cmnd *pcmd; + PSRB pSRB; + PDCB pDCB; + + if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) + return; + while (pACB->QueryCnt) + { + pSRB = dc390_Free_get ( pACB ); + if (!pSRB) return; + pcmd = dc390_Query_get ( pACB ); + if (!pcmd) { dc390_Free_insert (pACB, pSRB); return; }; /* should not happen */ + pDCB = dc390_findDCB (pACB, pcmd->target, pcmd->lun); + if (!pDCB) + { + dc390_Free_insert (pACB, pSRB); + printk (KERN_ERR "DC390: Command in queue to non-existing device!\n"); + pcmd->result = MK_RES(DRIVER_ERROR,DID_ERROR,0,0); + DC390_UNLOCK_ACB_NI; + pcmd->done (pcmd); + DC390_LOCK_ACB_NI; + }; + dc390_BuildSRB (pcmd, pDCB, pSRB); + dc390_Waiting_append ( pDCB, pSRB ); + } +} + /*********************************************************************** * Function : static int DC390_queue_command (Scsi_Cmnd *cmd, * void (*done)(Scsi_Cmnd *)) @@ -984,7 +1214,6 @@ int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { - Scsi_Cmnd *pcmd; PDCB pDCB; PSRB pSRB; DC390_AFLAGS @@ -992,7 +1221,7 @@ DEBUG0(/* if(pACB->scan_devices) */ \ - printk(KERN_INFO "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\ + printk(KERN_INFO "DC390: Queue Cmd=%02x,Tgt=%d,LUN=%d (pid=%li)\n",\ cmd->cmnd[0],cmd->target,cmd->lun,cmd->pid);) DC390_LOCK_ACB; @@ -1013,25 +1242,32 @@ if ( ( cmd->target >= pACB->pScsiHost->max_id ) || (cmd->lun >= pACB->pScsiHost->max_lun) ) { -/* printk("DC390: Ignore target %d lun %d\n", +/* printk ("DC390: Ignore target %d lun %d\n", cmd->target, cmd->lun); */ DC390_UNLOCK_ACB; - done(cmd); - return( 0 ); + //return (1); + done (cmd); + return (0); } - if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) + if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY || cmd->cmnd[0] == INQUIRY) && + !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) { - pACB->DCBmap[cmd->target] |= (1 << cmd->lun); pACB->scan_devices = 1; - dc390_initDCB( pACB, &pDCB, cmd ); + dc390_initDCB( pACB, &pDCB, cmd->target, cmd->lun ); if (!pDCB) { - printk (KERN_ERR "DC390: kmalloc for DCB failed, ID=%2x\n", cmd->target); + printk (KERN_ERR "DC390: kmalloc for DCB failed, target %02x lun %02x\n", + cmd->target, cmd->lun); DC390_UNLOCK_ACB; - done(cmd); - return(0); + printk ("DC390: No DCB in queue_command!\n"); +#ifdef USE_NEW_EH + return (1); +#else + done (cmd); + return (0); +#endif }; } @@ -1040,71 +1276,73 @@ printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n", cmd->target, cmd->lun); DC390_UNLOCK_ACB; - done(cmd); - return(0); + //return (1); + done (cmd); + return (0); } else { - pDCB = dc390_findDCB (pACB, cmd); + pDCB = dc390_findDCB (pACB, cmd->target, cmd->lun); if (!pDCB) { /* should never happen */ + printk (KERN_ERR "DC390: no DCB failed, target %02x lun %02x\n", + cmd->target, cmd->lun); DC390_UNLOCK_ACB; - done(cmd); - return(0); + printk ("DC390: No DCB in queuecommand (2)!\n"); +#ifdef USE_NEW_EH + return (1); +#else + done (cmd); + return (0); +#endif }; } pACB->Cmds++; cmd->scsi_done = done; cmd->result = 0; + + dc390_Query_to_Waiting (pACB); - if( pDCB->QIORBCnt ) /* Unsent commands ? */ + if( pACB->QueryCnt ) /* Unsent commands ? */ { - dc390_QLinkcmd( cmd, pDCB ); - pcmd = dc390_Getcmd( pDCB ); /* Get first command */ - pACB->CmdInQ++; + DEBUG0(printk ("DC390: QueryCnt != 0\n");) + dc390_Query_append ( cmd, pACB ); + dc390_Waiting_process (pACB); } - else - pcmd = cmd; - - pSRB = dc390_GetSRB( pACB ); - - if( !pSRB ) + else if (pDCB->pWaitingSRB) { - dc390_QLinkcmd( pcmd, pDCB ); /* Queue command at the end */ - pACB->CmdOutOfSRB++; - DC390_UNLOCK_ACB; - return(0); + pSRB = dc390_Free_get ( pACB ); + DEBUG0(if (!pSRB) printk ("DC390: No free SRB but Waiting\n"); else printk ("DC390: Free SRB w/ Waiting\n");) + if (!pSRB) dc390_Query_append (cmd, pACB); + else + { + dc390_BuildSRB (cmd, pDCB, pSRB); + dc390_Waiting_append (pDCB, pSRB); + } + dc390_Waiting_process (pACB); } - - dc390_BuildSRB (pcmd, pDCB, pSRB); - dc390_SendSRB( pACB, pSRB ); + else + { + pSRB = dc390_Free_get ( pACB ); + DEBUG0(if (!pSRB) printk ("DC390: No free SRB w/o Waiting\n"); else printk ("DC390: Free SRB w/o Waiting\n");) + if (!pSRB) + { + dc390_Query_append (cmd, pACB); + dc390_Waiting_process (pACB); + } + else + { + dc390_BuildSRB (cmd, pDCB, pSRB); + dc390_SendSRB (pACB, pSRB); + }; + }; DC390_UNLOCK_ACB; - DEBUG1(printk (KERN_DEBUG " ... command (%02x) queued successfully.\n", pcmd->cmnd[0]);) + DEBUG1(printk (KERN_DEBUG " ... command (pid %li) queued successfully.\n", cmd->pid);) return(0); } - -static void dc390_DoNextCmd( PACB pACB, PDCB pDCB ) -{ - Scsi_Cmnd *pcmd; - PSRB pSRB; - - if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) - return; - - pcmd = dc390_Getcmd( pDCB ); - pSRB = dc390_GetSRB( pACB ); - if( !pSRB ) - dc390_QLinkcmd( pcmd, pDCB ); - else - { - dc390_BuildSRB (pcmd, pDCB, pSRB); - dc390_SendSRB( pACB, pSRB ); - }; -} - /* We ignore mapping problems, as we expect everybody to respect * valid partition tables. Waiting for complaints ;-) */ @@ -1241,15 +1479,17 @@ void dc390_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB) { USHORT pstat; PDEVDECL1; + if (!pDCB) pDCB = pACB->pActiveDCB; + if (!pSRB && pDCB) pSRB = pDCB->pActiveSRB; if (pSRB) { - printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08lx, Phase %02x\n", + printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08x, Phase %02x\n", pSRB->TotalXferredLen, pSRB->SGToBeXferLen, pSRB->SRBState, pSRB->ScsiPhase); printk ("DC390: AdpaterStatus: %02x, SRB Status %02x\n", pSRB->AdaptStatus, pSRB->SRBStatus); }; - printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08lx\n", dc390_laststatus); + printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08x\n", dc390_laststatus); printk ("DC390: Register dump: SCSI block:\n"); printk ("DC390: XferCnt Cmd Stat IntS IRQS FFIS Ctl1 Ctl2 Ctl3 Ctl4\n"); printk ("DC390: %06x %02x %02x %02x", @@ -1259,6 +1499,12 @@ DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1), DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4)); DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT); + if (DC390_read8(Current_Fifo) & 0x1f) + { + printk ("DC390: FIFO:"); + while (DC390_read8(Current_Fifo) & 0x1f) printk (" %02x", DC390_read8(ScsiFifo)); + printk ("\n"); + }; printk ("DC390: Register dump: DMA engine:\n"); printk ("DC390: Cmd STrCnt SBusA WrkBC WrkAC Stat SBusCtrl\n"); printk ("DC390: %02x %08x %08x %08x %08x %02x %08x\n", @@ -1288,44 +1534,40 @@ { PDCB pDCB; PSRB pSRB, psrb; - ULONG count, i; - PSCSICMD pcmd, pcmd1; + UINT count, i; + PSCSICMD pcmd; int status; - ULONG sbac; + //ULONG sbac; DC390_AFLAGS PACB pACB = (PACB) cmd->host->hostdata; DC390_LOCK_ACB; - - pDCB = dc390_findDCB (pACB, cmd); - /* abort() is too buggy at the moment. If it's called we are in trouble anyway. - * so let's dump some info into the syslog at least. (KG, 98/08/20) */ - if (pDCB) pSRB = pDCB->pActiveSRB; else pSRB = 0; - printk ("DC390: Abort command (pid %li, DCB %p, SRB %p)\n", - cmd->pid, pDCB, pSRB); - dc390_dumpinfo (pACB, pDCB, pSRB); - if( !pDCB ) goto NOT_RUN; + printk ("DC390: Abort command (pid %li, Device %02i-%02i)\n", + cmd->pid, cmd->target, cmd->lun); - 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; } @@ -1336,14 +1578,21 @@ } } + pDCB = dc390_findDCB (pACB, cmd->target, cmd->lun); + if( !pDCB ) goto NOT_RUN; + /* Added 98/07/02 KG */ + /* pSRB = pDCB->pActiveSRB; if (pSRB && pSRB->pcmd == cmd ) goto ON_GOING; - + */ + pSRB = pDCB->pWaitingSRB; if( !pSRB ) goto ON_GOING; + + /* Now scan Waiting queue */ if( pSRB->pcmd == cmd ) { pDCB->pWaitingSRB = pSRB->pNextSRB; @@ -1363,16 +1612,21 @@ pSRB = psrb->pNextSRB; psrb->pNextSRB = pSRB->pNextSRB; if( pSRB == pDCB->pWaitLast ) - pDCB->pWaitLast = psrb; /* No check for psrb == NULL ? */ + pDCB->pWaitLast = psrb; IN_WAIT: - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; + dc390_Free_insert (pACB, pSRB); + pDCB->WaitSRBCnt--; cmd->next = NULL; status = SCSI_ABORT_SUCCESS; goto ABO_X; } + /* SRB has already been sent ! */ ON_GOING: + /* abort() is too stupid for already sent commands at the moment. + * If it's called we are in trouble anyway, so let's dump some info + * into the syslog at least. (KG, 98/08/20,99/06/20) */ + dc390_dumpinfo (pACB, pDCB, pSRB); pSRB = pDCB->pGoingSRB; pDCB->DCBFlag |= ABORT_DEV_; /* Now for the hard part: The command is currently processed */ @@ -1403,12 +1657,13 @@ ABO_X: cmd->result = DID_ABORT << 16; printk(KERN_INFO "DC390: Aborted pid %li with status %i\n", cmd->pid, status); +#if 0 if (cmd->pid == dc390_lastabortedpid) /* repeated failure ? */ { /* Let's do something to help the bus getting clean again */ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); DC390_write8 (ScsiCmd, DMA_COMMAND); - //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); //DC390_write8 (ScsiCmd, RESET_ATN_CMD); DC390_write8 (ScsiCmd, NOP_CMD); //udelay (10000); @@ -1433,10 +1688,13 @@ sbac = DC390_read32 (DMA_ScsiBusCtrl); printk ("%08lx\n", sbac); }; +#endif dc390_lastabortedpid = cmd->pid; DC390_UNLOCK_ACB; //do_DC390_Interrupt (pACB->IRQLevel, 0, 0); - cmd->scsi_done(cmd); +#ifndef USE_NEW_EH + if (status == SCSI_ABORT_SUCCESS) cmd->scsi_done(cmd); +#endif return( status ); } @@ -1453,20 +1711,24 @@ pDCB->SyncMode &= ~SYNC_NEGO_DONE; pDCB->SyncPeriod = 0; pDCB->SyncOffset = 0; + pDCB->TagMask = 0; pDCB->CtrlR3 = FAST_CLK; pDCB->CtrlR4 &= NEGATE_REQACKDATA | CTRL4_RESERVED | NEGATE_REQACK; pDCB->CtrlR4 |= pACB->glitch_cfg; pDCB = pDCB->pNextDCB; } while( pdcb != pDCB ); -} + pACB->ACBFlag &= ~(RESET_DEV | RESET_DONE | RESET_DETECT); +} +#if 0 +/* Moves all SRBs from Going to Waiting for all DCBs */ static void dc390_RecoverSRB( PACB pACB ) { PDCB pDCB, pdcb; PSRB psrb, psrb2; - ULONG cnt, i; + UINT cnt, i; pDCB = pACB->pLinkDCB; if( !pDCB ) return; @@ -1498,7 +1760,7 @@ pdcb = pdcb->pNextDCB; } while( pdcb != pDCB ); } - +#endif /*********************************************************************** * Function : int DC390_reset (Scsi_Cmnd *cmd, ...) @@ -1506,34 +1768,37 @@ * Purpose : perform a hard reset on the SCSI bus * * Inputs : cmd - command which caused the SCSI RESET + * resetFlags - how hard to try * * Returns : 0 on success. ***********************************************************************/ -int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags) +int DC390_reset (Scsi_Cmnd *cmd, unsigned int resetFlags) { UCHAR bval; - ULONG i; DC390_AFLAGS PACB pACB = (PACB) cmd->host->hostdata; printk(KERN_INFO "DC390: RESET ... "); DC390_LOCK_ACB; + if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); bval = DC390_read8 (CtrlReg1); bval |= DIS_INT_ON_SCSI_RST; - DC390_write8 (CtrlReg1, bval); /* disable interrupt */ + DC390_write8 (CtrlReg1, bval); /* disable IRQ on bus reset */ + pACB->ACBFlag |= RESET_DEV; dc390_ResetSCSIBus( pACB ); - /* Unlock ? */ - for( i=0; i<600; i++ ) - udelay(1000); + dc390_ResetDevParam( pACB ); + udelay (1000); + pACB->pScsiHost->last_reset = jiffies + 3*HZ/2 + + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); DC390_read8 (INT_Status); /* Reset Pending INT */ - dc390_ResetDevParam( pACB ); - dc390_DoingSRB_Done( pACB ); + dc390_DoingSRB_Done( pACB, cmd ); /* dc390_RecoverSRB (pACB); */ pACB->pActiveDCB = NULL; @@ -1542,10 +1807,10 @@ bval &= ~DIS_INT_ON_SCSI_RST; DC390_write8 (CtrlReg1, bval); /* re-enable interrupt */ - dc390_DoWaitingSRB( pACB ); + dc390_Waiting_process( pACB ); - DC390_UNLOCK_ACB; printk("done\n"); + DC390_UNLOCK_ACB; return( SCSI_RESET_SUCCESS ); } @@ -1555,22 +1820,22 @@ /*********************************************************************** * Function : static void dc390_initDCB() * - * Purpose : initialize the internal structures for a given DCB + * Purpose : initialize the internal structures for a DCB (to be malloced) * - * Inputs : cmd - pointer to this scsi cmd request block structure + * Inputs : SCSI id and lun ***********************************************************************/ -void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd ) +void dc390_initDCB( PACB pACB, PDCB *ppDCB, UCHAR id, UCHAR lun ) { PEEprom prom; UCHAR index; - PDCB pDCB; + PDCB pDCB, pDCB2; pDCB = kmalloc (sizeof(DC390_DCB), GFP_ATOMIC); - DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): 0x%08x\n", \ - cmd->target, cmd->lun, (int)pDCB);) + DCBDEBUG(printk (KERN_INFO "DC390: alloc mem for DCB (ID %i, LUN %i): %p\n" \ + id, lun, pDCB);) - *ppDCB = pDCB; + *ppDCB = pDCB; pDCB2 = 0; if (!pDCB) return; if( pACB->DCBCnt == 0 ) { @@ -1584,37 +1849,58 @@ pACB->DCBCnt++; - pACB->pLastDCB = pDCB; pDCB->pNextDCB = pACB->pLinkDCB; + pACB->pLastDCB = pDCB; pDCB->pDCBACB = pACB; - pDCB->QIORBCnt = 0; - pDCB->UnitSCSIID = cmd->target; - pDCB->UnitSCSILUN = cmd->lun; + pDCB->TargetID = id; + pDCB->TargetLUN = lun; pDCB->pWaitingSRB = NULL; pDCB->pGoingSRB = NULL; pDCB->GoingSRBCnt = 0; + pDCB->WaitSRBCnt = 0; pDCB->pActiveSRB = NULL; pDCB->TagMask = 0; pDCB->MaxCommand = 1; index = pACB->AdapterIndex; pDCB->DCBFlag = 0; - prom = (PEEprom) &dc390_eepromBuf[index][cmd->target << 2]; - pDCB->DevMode = prom->EE_MODE1; + /* Is there a corresp. LUN==0 device ? */ + if (lun != 0) + pDCB2 = dc390_findDCB (pACB, id, 0); + prom = (PEEprom) &dc390_eepromBuf[index][id << 2]; + /* Some values are for all LUNs: Copy them */ + /* In a clean way: We would have an own structure for a SCSI-ID */ + if (pDCB2) + { + pDCB->DevMode = pDCB2->DevMode; + pDCB->SyncMode = pDCB2->SyncMode; + pDCB->SyncPeriod = pDCB2->SyncPeriod; + pDCB->SyncOffset = pDCB2->SyncOffset; + pDCB->NegoPeriod = pDCB2->NegoPeriod; + + pDCB->CtrlR3 = pDCB2->CtrlR3; + pDCB->CtrlR4 = pDCB2->CtrlR4; + pDCB->Inquiry7 = pDCB2->Inquiry7; + } + else + { + pDCB->DevMode = prom->EE_MODE1; + pDCB->SyncMode = 0; + pDCB->SyncPeriod = 0; + pDCB->SyncOffset = 0; + pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2; + + pDCB->CtrlR3 = FAST_CLK; + + pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED; + if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) + pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK; + pDCB->Inquiry7 = 0; + } - pDCB->SyncMode = 0; + pACB->DCBmap[id] |= (1 << lun); dc390_updateDCB(pACB, pDCB); - - pDCB->SyncPeriod = 0; - pDCB->SyncOffset = 0; - pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2; - - pDCB->CtrlR3 = FAST_CLK; - - pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED; - if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) - pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK; } /*********************************************************************** @@ -1625,24 +1911,26 @@ void dc390_updateDCB (PACB pACB, PDCB pDCB) { - pDCB->IdentifyMsg = IDENTIFY (pDCB->DevMode & EN_DISCONNECT_, pDCB->UnitSCSILUN); - - if (pDCB->DevMode & TAG_QUEUEING_) pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE | EN_ATN_STOP; - else pDCB->SyncMode &= SYNC_NEGO_DONE | EN_ATN_STOP; - - if( pDCB->DevMode & SYNC_NEGO_ && (!(pDCB->UnitSCSILUN) || dc390_CurrSyncOffset) ) - pDCB->SyncMode |= SYNC_ENABLE; - else - { + pDCB->SyncMode &= EN_TAG_QUEUEING | SYNC_NEGO_DONE /*| EN_ATN_STOP*/; + if (pDCB->DevMode & TAG_QUEUEING_) { + //if (pDCB->SyncMode & EN_TAG_QUEUEING) pDCB->MaxCommand = pACB->TagMaxNum; + } else { + pDCB->SyncMode &= ~EN_TAG_QUEUEING; + pDCB->MaxCommand = 1; + }; + + if( pDCB->DevMode & SYNC_NEGO_ ) + pDCB->SyncMode |= SYNC_ENABLE; + else { pDCB->SyncMode &= ~(SYNC_NEGO_DONE | SYNC_ENABLE); pDCB->SyncOffset &= ~0x0f; - }; - - if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP; - + }; + + //if (! (pDCB->DevMode & EN_DISCONNECT_)) pDCB->SyncMode &= ~EN_ATN_STOP; + pDCB->CtrlR1 = pACB->pScsiHost->this_id; if( pDCB->DevMode & PARITY_CHK_ ) - pDCB->CtrlR1 |= PARITY_ERR_REPO; + pDCB->CtrlR1 |= PARITY_ERR_REPO; }; @@ -1656,7 +1944,7 @@ { int i; PDCB pDCB = pACB->pLinkDCB; - for (i = 0; i < pACB->DeviceCnt; i++) + for (i = 0; i < pACB->DCBCnt; i++) { dc390_updateDCB (pACB, pDCB); pDCB = pDCB->pNextDCB; @@ -1680,12 +1968,12 @@ void dc390_linkSRB( PACB pACB ) { - ULONG count, i; + UINT count, i; count = pACB->SRBCount; - for( i=0; i< count; i++) + for( i=0; iSRB_array[i].pNextSRB = &pACB->SRB_array[i+1]; else pACB->SRB_array[i].pNextSRB = NULL; @@ -1715,7 +2003,15 @@ psh->io_port = io_port; psh->n_io_port = 0x80; psh->irq = Irq; - +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,50) + psh->base = io_port; +#else + psh->base = (char*)io_port; +#endif + psh->unique_id = io_port; + psh->dma_channel = -1; + psh->last_reset = jiffies; + pACB = (PACB) psh->hostdata; DC390_LOCKA_INIT; DC390_LOCK_ACB; @@ -1740,6 +2036,8 @@ pACB->pActiveDCB = NULL; pACB->pFreeSRB = pACB->SRB_array; pACB->SRBCount = MAX_SRB_CNT; + pACB->QueryCnt = 0; + pACB->pQueryHead = NULL; pACB->AdapterIndex = index; pACB->status = 0; psh->this_id = dc390_eepromBuf[index][EE_ADAPT_SCSI_ID]; @@ -1758,7 +2056,9 @@ pACB->DCBmap[i] = 0; pACB->sel_timeout = SEL_TIMEOUT; pACB->glitch_cfg = EATER_25NS; - pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = pACB->SelLost = 0; + pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = 0; + pACB->SelLost = pACB->SelConn = 0; + init_timer (&pACB->Waiting_Timer); } @@ -1776,22 +2076,11 @@ int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) { PACB pACB, pACB2; - UCHAR used_irq = 0, dstate; + UCHAR dstate; int i; pACB = (PACB) psh->hostdata; - for ( pACB2 = dc390_pACB_start; pACB2 ; ) - { - if( pACB2->IRQLevel == Irq ) - { - used_irq = 1; - break; - } - else - pACB2 = pACB2->pNextACB; - } - if (check_region (io_port, psh->n_io_port)) { printk(KERN_ERR "DC390: register IO ports error!\n"); @@ -1802,14 +2091,12 @@ DC390_read8_ (INT_Status, io_port); /* Reset Pending INT */ - if( !used_irq ) - { - if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", NULL) )) - { - printk(KERN_ERR "DC390: register IRQ error!\n"); - return( -1 ); - } - } + if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", pACB) )) + { + printk(KERN_ERR "DC390: register IRQ error!\n"); + release_region (io_port, psh->n_io_port); + return( -1 ); + } if( !dc390_pACB_start ) { @@ -1831,9 +2118,13 @@ if (pACB->Gmode2 & RST_SCSI_BUS) { dc390_ResetSCSIBus( pACB ); - /* Unlock before ? */ - for( i=0; i<600; i++ ) + udelay (1000); + pACB->pScsiHost->last_reset = jiffies + HZ/2 + + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; + /* + for( i=0; i<(500 + 1000*dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]); i++ ) udelay(1000); + */ }; pACB->ACBFlag = 0; DC390_read8 (INT_Status); /* Reset Pending INT */ @@ -1845,6 +2136,7 @@ DC390_write8 (CtrlReg3, FAST_CLK); /* fast clock */ DC390_write8 (CtrlReg4, pACB->glitch_cfg | /* glitch eater */ (dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ? NEGATE_REQACKDATA : 0); /* Negation */ + DC390_write8 (CtcReg_High, 0); /* Clear Transfer Count High: ID */ DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT); @@ -1884,18 +2176,24 @@ printk (KERN_ERR "DC390_init: No EEPROM found!\n"); return( -1 ); #else - int period; - printk (KERN_INFO "DC390_init: No EEPROM found!\n"); - printk (KERN_INFO "DC390_init: Trying default EEPROM settings:\n"); - dc390_checkparams (); - period = dc390_clock_period1[tmscsim[1]]; + int speed; + dc390_adapname = "AM53C974"; + printk (KERN_INFO "DC390_init: No EEPROM found! Trying default settings ...\n"); + dc390_check_for_safe_settings (); + dc390_fill_with_defaults (); + dc390_EEprom_Override (index); + speed = dc390_clock_speed[tmscsim[1]]; printk (KERN_INFO "DC390: Used defaults: AdaptID=%i, SpeedIdx=%i (%i.%i MHz)," - " DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i)\n", tmscsim[0], tmscsim[1], - 40 / period, ((40%period)*10 + period/2) / period, - (UCHAR)tmscsim[2], (UCHAR)tmscsim[3], tmscsim[4], 2 << (tmscsim[4])); - dc390_EEpromDefaults (index); + " DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i), DelayReset=%is\n", + tmscsim[0], tmscsim[1], speed/10, speed%10, + (UCHAR)tmscsim[2], (UCHAR)tmscsim[3], tmscsim[4], 2 << (tmscsim[4]), tmscsim[5]); #endif - }; + } + else + { + dc390_check_for_safe_settings (); + dc390_EEprom_Override (index); + } psh = scsi_register( psht, sizeof(DC390_ACB) ); if( !psh ) return( -1 ); @@ -1999,7 +2297,8 @@ PDEVDECL0; UCHAR irq; UINT io_port; - DC390_IFLAGS DC390_DFLAGS + //DC390_IFLAGS + DC390_DFLAGS DC390_LOCK_DRV; //dc390_pSHT_start = psht; @@ -2008,7 +2307,11 @@ if ( PCI_PRESENT ) while (PCI_FIND_DEVICE (PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974)) { - DC390_LOCK_IO; /* Remove this when going to new eh */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,30) + if (pci_enable_device (pdev)) + continue; +#endif + //DC390_LOCK_IO; /* Remove this when going to new eh */ PCI_GET_IO_AND_IRQ; DEBUG0(printk(KERN_INFO "DC390(%i): IO_PORT=%04x,IRQ=%x\n", dc390_adapterCnt, (UINT) io_port, irq);) @@ -2018,14 +2321,17 @@ dc390_set_pci_cfg (PDEV); dc390_adapterCnt++; }; - DC390_UNLOCK_IO; /* Remove when going to new eh */ + //DC390_UNLOCK_IO; /* Remove when going to new eh */ } else printk (KERN_ERR "DC390: No PCI BIOS found!\n"); if (dc390_adapterCnt) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30) + psht->proc_name = "tmscsim"; +#else psht->proc_dir = &DC390_proc_scsi_tmscsim; - +#endif printk(KERN_INFO "DC390: %i adapters found\n", dc390_adapterCnt); DC390_UNLOCK_DRV; return( dc390_adapterCnt ); @@ -2047,7 +2353,7 @@ if (cmd->result) { PACB pACB = (PACB)cmd->host->hostdata; - PDCB pDCB = dc390_findDCB (pACB, cmd); + PDCB pDCB = dc390_findDCB (pACB, cmd->target, cmd->lun); printk ("DC390: Unsetting DsCn, Sync and TagQ!\n"); if (pDCB) { @@ -2055,7 +2361,6 @@ dc390_updateDCB (pACB, pDCB); }; }; - kfree (cmd->buffer); kfree (cmd); }; @@ -2063,20 +2368,21 @@ { char* buffer; Scsi_Cmnd* cmd; - buffer = kmalloc (256, GFP_ATOMIC); - cmd = kmalloc (sizeof (Scsi_Cmnd), GFP_ATOMIC); + cmd = kmalloc (sizeof(Scsi_Cmnd) + 256, GFP_ATOMIC); + if (!cmd) { printk ("DC390: kmalloc failed in inquiry!\n"); return; }; + buffer = (char*)cmd + sizeof(Scsi_Cmnd); - memset (buffer, 0, 256); - memset (cmd, 0, sizeof(Scsi_Cmnd)); + memset (cmd, 0, sizeof(Scsi_Cmnd) + 256); cmd->cmnd[0] = INQUIRY; - cmd->cmnd[1] = (pDCB->UnitSCSILUN << 5) & 0xe0; + 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->UnitSCSIID; - cmd->lun = pDCB->UnitSCSILUN; + cmd->target = pDCB->TargetID; + cmd->lun = pDCB->TargetLUN; cmd->serial_number = 1; + cmd->pid = 390; cmd->bufflen = 128; cmd->buffer = buffer; cmd->request_bufflen = 128; @@ -2087,11 +2393,62 @@ cmd->request.rq_status = RQ_SCSI_BUSY; + pDCB->SyncMode &= ~SYNC_NEGO_DONE; printk (KERN_INFO "DC390: Queue INQUIRY command to dev ID %02x LUN %02x\n", - pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + pDCB->TargetID, pDCB->TargetLUN); DC390_queue_command (cmd, dc390_inquiry_done); }; +/*********************************************************************** + * Functions: dc390_sendstart(), dc390_sendstart_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 dc390_sendstart_done (Scsi_Cmnd* cmd) +{ + printk (KERN_INFO "DC390: SENDSTART (ID %02x LUN %02x) returned %08x\n", + cmd->target, cmd->lun, cmd->result); + kfree (cmd); +}; + +void dc390_sendstart (PACB pACB, PDCB pDCB) +{ + char* buffer; + Scsi_Cmnd* cmd; + cmd = kmalloc (sizeof(Scsi_Cmnd) + 256, GFP_ATOMIC); + if (!cmd) { printk ("DC390: kmalloc failed in sendstart!\n"); return; }; + buffer = (char*)cmd + sizeof(Scsi_Cmnd); + + memset (cmd, 0, sizeof(Scsi_Cmnd) + 256); + cmd->cmnd[0] = 0x1b; /* START_STOP_UNIT */ + cmd->cmnd[1] = (pDCB->TargetLUN << 5) & 0xe0; + cmd->cmnd[4] = 0x01; /* START */ + + 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 = 310; + cmd->bufflen = 128; + cmd->buffer = buffer; + cmd->request_bufflen = 128; + cmd->request_buffer = &buffer[128]; + cmd->done = dc390_sendstart_done; + cmd->scsi_done = dc390_sendstart_done; + cmd->timeout_per_command = 5*HZ; + + cmd->request.rq_status = RQ_SCSI_BUSY; + + pDCB->SyncMode &= ~SYNC_NEGO_DONE; + printk (KERN_INFO "DC390: Queue SEND_START command to dev ID %02x LUN %02x\n", + pDCB->TargetID, pDCB->TargetLUN); + DC390_queue_command (cmd, dc390_sendstart_done); +}; + /******************************************************************** * Function: dc390_set_info() * @@ -2209,6 +2566,9 @@ 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, "START", 5)) goto start; + else if (!memcmp (pos, "DUMP", 4)) goto dump; if (isdigit (*pos)) { @@ -2225,13 +2585,20 @@ pDCB = pACB->pLinkDCB; for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; /* Sanity Check */ - if (pDCB->UnitSCSIID != id || pDCB->UnitSCSILUN != lun) + if (pDCB->TargetID != id || pDCB->TargetLUN != lun) { printk (KERN_ERR "DC390: no such device: Idx=%02i ID=%02i LUN=%02i\n", dev, id, lun); goto einv2; }; + if (pDCB->pWaitingSRB || pDCB->pGoingSRB) + { + printk ("DC390: Cannot change dev (%i-%i) cfg: Pending requests\n", + pDCB->TargetID, pDCB->TargetLUN); + goto einv; + }; + olddevmode = pDCB->DevMode; YESNO (pos, pDCB->DevMode, PARITY_CHK_); needs_inquiry++; @@ -2244,8 +2611,7 @@ needs_inquiry++; YESNO (pos, pDCB->DevMode, TAG_QUEUEING_); if ((olddevmode & TAG_QUEUEING_) == (pDCB->DevMode & TAG_QUEUEING_)) needs_inquiry--; - YESNO (pos, pDCB->SyncMode, EN_ATN_STOP); - + dc390_updateDCB (pACB, pDCB); if (!pos) goto ok; @@ -2265,7 +2631,7 @@ else pos = strtok (0, " \t\n:=,;."); if (!pos) goto ok; - /* Speed: NegoPeriod */ + /* Sync Speed in MHz */ if (*pos != '-') { SCANF (pos, p0, dum, 1, 13); @@ -2280,11 +2646,11 @@ for (; p0-pos > 1; p0--) dum /= 10; pDCB->NegoPeriod = (100000/(100*dumold + dum)) >> 2; if (pDCB->NegoPeriod < 19) pDCB->NegoPeriod = 19; - if (pDCB->NegoPeriod != olddevmode) needs_inquiry++; pos = strtok (0, " \t\n:=,;"); if (!pos) goto ok; }; if (*pos == 'M') pos = strtok (0, " \t\n:=,;"); + if (pDCB->NegoPeriod != olddevmode) needs_inquiry++; } else pos = strtok (0, " \t\n:=,;"); /* dc390_updateDCB (pACB, pDCB); */ @@ -2299,28 +2665,49 @@ if (pDCB->SyncOffset > olddevmode) needs_inquiry++; } else pos = strtok (0, " \t\n:=,;"); + if (!pos) goto ok; dc390_updateDCB (pACB, pDCB); + + //olddevmode = pDCB->MaxCommand; + /* MaxCommand (Tags) */ + if (*pos != '-') + { + SCANF (pos, p0, dum, 1, 32 /*pACB->TagMaxNum*/); + if (pDCB->SyncMode & EN_TAG_QUEUEING) + pDCB->MaxCommand = dum; + else printk (KERN_INFO "DC390: Can't set MaxCmd larger than one without Tag Queueing!\n"); + } + else pos = strtok (0, " \t\n:=,;"); + } else { - char* p1 = pos; UCHAR dum; + char* p1 = pos; UCHAR dum, newadaptid; PARSEDEBUG(printk (KERN_INFO "DC390: chg adapt cfg \"%s\"\n", prstr (pos, &buffer[length]));) dum = GLITCH_TO_NS (pACB->glitch_cfg); /* Adapter setting */ SEARCH (pos, p0, pACB->pScsiHost->max_id, "MAXID", 8); SEARCH (pos, p0, pACB->pScsiHost->max_lun, "MAXLUN", 8); - SEARCH (pos, p0, pACB->pScsiHost->this_id, "ADAPTERID", 7); + SEARCH (pos, p0, newadaptid, "ADAPTERID", 7); SEARCH (pos, p0, pACB->TagMaxNum, "TAGMAXNUM", 32); SEARCH (pos, p0, pACB->ACBFlag, "ACBFLAG", 255); SEARCH3 (pos, p0, dum, "GLITCHEATER", 40, 1000, "NS"); SEARCH3 (pos, p0, pACB->sel_timeout, "SELTIMEOUT", 400, 163, "MS"); + SEARCH3 (pos, p0, dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY], "DELAYRESET", 180, 100, "S"); ok2: pACB->glitch_cfg = NS_TO_GLITCH (dum); if (pACB->sel_timeout < 60) pACB->sel_timeout = 60; - dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++; - pACB->TagMaxNum &= (1 << --dum); - if (pos == p1) goto einv; + DC390_write8 (Scsi_TimeOut, pACB->sel_timeout); + if (newadaptid != pACB->pScsiHost->this_id) + { + pACB->pScsiHost->this_id = newadaptid; + dc390_ResetDevParam (pACB); + } + //dum = 0; while (1 << dum <= pACB->TagMaxNum) dum ++; + //pACB->TagMaxNum &= (1 << --dum); dc390_updateDCBs (pACB); + // All devs should be INQUIRED now + if (pos == p1) goto einv; } if (pos) goto next; @@ -2350,7 +2737,15 @@ DC390_UNLOCK_IO; }; return (length); - + + dump: + { + dc390_dumpinfo (pACB, 0, 0); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + } + return (length); + inquiry: { pos = strtok (0, " \t\n.:;="); if (!pos) goto einv; @@ -2358,7 +2753,7 @@ if (dev >= pACB->DCBCnt) goto einv_dev; for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; printk (KERN_NOTICE " DC390: Issue INQUIRY command to Dev(Idx) %i SCSI ID %i LUN %i\n", - dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + dev, pDCB->TargetID, pDCB->TargetLUN); DC390_UNLOCK_ACB; dc390_inquiry (pACB, pDCB); DC390_UNLOCK_IO; @@ -2372,13 +2767,45 @@ if (dev >= pACB->DCBCnt) goto einv_dev; for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; printk (KERN_NOTICE " DC390: Remove DCB for Dev(Idx) %i SCSI ID %i LUN %i\n", - dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + dev, pDCB->TargetID, pDCB->TargetLUN); + /* TO DO: We should make sure no pending commands are left */ dc390_remove_dev (pACB, pDCB); DC390_UNLOCK_ACB; DC390_UNLOCK_IO; }; return (length); + add: + { + int id, lun; + pos = strtok (0, " \t\n.:;="); + if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv; + if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv; + pDCB = dc390_findDCB (pACB, id, lun); + if (pDCB) { printk ("DC390: ADD: Device already existing\n"); goto einv; }; + dc390_initDCB (pACB, &pDCB, id, lun); + DC390_UNLOCK_ACB; + dc390_inquiry (pACB, pDCB); + DC390_UNLOCK_IO; + }; + return (length); + + start: + { + int id, lun; + pos = strtok (0, " \t\n.:;="); + if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv; + if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv; + pDCB = dc390_findDCB (pACB, id, lun); + if (pDCB) printk ("DC390: SendStart: Device already existing ...\n"); + else dc390_initDCB (pACB, &pDCB, id, lun); + DC390_UNLOCK_ACB; + dc390_sendstart (pACB, pDCB); + dc390_inquiry (pACB, pDCB); + DC390_UNLOCK_IO; + }; + return (length); + einv_dev: printk (KERN_WARNING "DC390: Ignore cmnd to illegal Dev(Idx) %i. Valid range: 0 - %i.\n", dev, pACB->DCBCnt - 1); @@ -2428,6 +2855,7 @@ PSH shpnt; PACB pACB; PDCB pDCB; + PSCSICMD pcmd; DC390_AFLAGS pACB = dc390_pACB_start; @@ -2453,46 +2881,87 @@ SPRINTF("SCSI Host Nr %i, ", shpnt->host_no); SPRINTF("%s Adapter Nr %i\n", dc390_adapname, pACB->AdapterIndex); SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase); - SPRINTF("IRQLevel 0x%02x\n", pACB->IRQLevel); + SPRINTF("IRQ %02i\n", pACB->IRQLevel); SPRINTF("MaxID %i, MaxLUN %i, ", shpnt->max_id, shpnt->max_lun); - SPRINTF("AdapterID %i, SelTimeout %i ms\n", - shpnt->this_id, (pACB->sel_timeout*164)/100); + SPRINTF("AdapterID %i, SelTimeout %i ms, DelayReset %i s\n", + shpnt->this_id, (pACB->sel_timeout*164)/100, + dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]); - SPRINTF("TagMaxNum %i, Status %i, ACBFlag %i, GlitchEater %i ns\n", + SPRINTF("TagMaxNum %i, Status 0x%02x, ACBFlag 0x%02x, GlitchEater %i ns\n", pACB->TagMaxNum, pACB->status, pACB->ACBFlag, GLITCH_TO_NS(pACB->glitch_cfg)*12); - SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %li, Out of SRB conds %li\n", + SPRINTF("Statistics: Cmnds %li, Cmnds not sent directly %i, Out of SRB conds %i\n", pACB->Cmds, pACB->CmdInQ, pACB->CmdOutOfSRB); - SPRINTF(" Lost arbitrations %li\n", pACB->SelLost); + SPRINTF(" Lost arbitrations %i, Sel. connected %i, Connected: %s\n", + pACB->SelLost, pACB->SelConn, pACB->Connected? "Yes": "No"); 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("Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs\n"); + SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs MaxCmd\n"); pDCB = pACB->pLinkDCB; for (dev = 0; dev < pACB->DCBCnt; dev++) { - SPRINTF("%02i %02i %02i ", dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + SPRINTF("%02i %02i %02i ", dev, pDCB->TargetID, pDCB->TargetLUN); YESNO(pDCB->DevMode & PARITY_CHK_); YESNO(pDCB->SyncMode & SYNC_NEGO_DONE); YESNO(pDCB->DevMode & EN_DISCONNECT_); - //YESNO(pDCB->SyncMode & EN_ATN_STOP); YESNO(pDCB->DevMode & SEND_START_); YESNO(pDCB->SyncMode & EN_TAG_QUEUEING); - YESNO(pDCB->SyncMode & EN_ATN_STOP); if (pDCB->SyncOffset & 0x0f) { int sp = pDCB->SyncPeriod; if (! (pDCB->CtrlR3 & FAST_SCSI)) sp++; SPRINTF(" %03i ns ", (pDCB->NegoPeriod) << 2); spd = 40/(sp); spd1 = 40%(sp); spd1 = (spd1 * 10 + sp/2) / (sp); - SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (pDCB->SyncOffset & 0x0f)); + SPRINTF(" %2i.%1i M %02i", spd, spd1, (pDCB->SyncOffset & 0x0f)); } - else SPRINTF(" (%03i ns)\n", (pDCB->NegoPeriod) << 2); + else SPRINTF(" (%03i ns) ", (pDCB->NegoPeriod) << 2); /* Add more info ...*/ + SPRINTF (" %02i\n", pDCB->MaxCommand); pDCB = pDCB->pNextDCB; } + SPRINTF ("Commands in Queues: Query: %li:", 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) +#if 0 //def DC390_DEBUGTRACE + SPRINTF(" %s\n ", pSRB->debugtrace); +#else + SPRINTF(" %li", pSRB->pcmd->pid); +#endif + if (pDCB->WaitSRBCnt || pDCB->GoingSRBCnt) SPRINTF ("\n"); + pDCB = pDCB->pNextDCB; + } + +#ifdef DC390_DEBUGDCB + SPRINTF ("DCB list for ACB %p:\n", pACB); + pDCB = pACB->pLinkDCB; + SPRINTF ("%p", pDCB); + for (dev = 0; dev < pACB->DCBCnt; dev++, pDCB=pDCB->pNextDCB) + SPRINTF ("->%p", pDCB->pNextDCB); + SPRINTF("\n"); +#endif + DC390_UNLOCK_ACB; *start = buffer + offset; @@ -2527,13 +2996,14 @@ printk(KERN_INFO "DC390: shutdown\n"); - pACB->ACBFlag = RESET_DONE; + pACB->ACBFlag = RESET_DEV; bval = DC390_read8 (CtrlReg1); bval |= DIS_INT_ON_SCSI_RST; DC390_write8 (CtrlReg1, bval); /* disable interrupt */ if (pACB->Gmode2 & RST_SCSI_BUS) dc390_ResetSCSIBus (pACB); + if (timer_pending (&pACB->Waiting_Timer)) del_timer (&pACB->Waiting_Timer); return( 0 ); } @@ -2547,41 +3017,30 @@ do { nDCB = pDCB->pNextDCB; - DCBDEBUG(printk (KERN_INFO "DC390: Free DCB (ID %i, LUN %i): 0x%08x\n",\ - pDCB->UnitSCSIID, pDCB->UnitSCSILUN, (int)pDCB);) - kfree (pDCB); + DCBDEBUG(printk (KERN_INFO "DC390: Free DCB (ID %i, LUN %i): %p\n",\ + pDCB->TargetID, pDCB->TargetLUN, pDCB);) + //kfree (pDCB); + dc390_remove_dev (pACB, pDCB); pDCB = nDCB; - } while (pDCB && pDCB != pACB->pLinkDCB); + } while (pDCB && pACB->pLinkDCB); }; -int DC390_release(struct Scsi_Host *host) +int DC390_release (struct Scsi_Host *host) { - int irq_count; - PACB pACB; DC390_AFLAGS DC390_IFLAGS -#if USE_SPINLOCKS > 1 PACB pACB = (PACB)(host->hostdata); -#endif DC390_LOCK_IO; DC390_LOCK_ACB; + /* TO DO: We should check for outstanding commands first. */ dc390_shutdown (host); if (host->irq != IRQ_NONE) { - for (irq_count = 0, pACB = dc390_pACB_start; - pACB; pACB = pACB->pNextACB) - { - if ( pACB->IRQLevel == host->irq ) - ++irq_count; - } - if (irq_count == 1) - { - DEBUG0(printk(KERN_INFO "DC390: Free IRQ %i\n",host->irq);) - free_irq(host->irq,NULL); - } + DEBUG0(printk(KERN_INFO "DC390: Free IRQ %i\n",host->irq);) + free_irq (host->irq, pACB); } release_region(host->io_port,host->n_io_port); @@ -2590,7 +3049,12 @@ DC390_UNLOCK_IO; return( 1 ); } +#endif /* def MODULE */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99) +static Scsi_Host_Template driver_template = DC390_T; +#include "scsi_module.c" +#elif defined(MODULE) Scsi_Host_Template driver_template = DC390_T; #include "scsi_module.c" -#endif /* def MODULE */ +#endif Index: tmscsim.h =================================================================== RCS file: /home/cvsroot/dc390/tmscsim.h,v retrieving revision 2.4 retrieving revision 2.15.2.3 diff -u -r2.4 -r2.15.2.3 --- tmscsim.h 1998/12/25 17:33:27 2.4 +++ tmscsim.h 2000/11/17 20:52:27 2.15.2.3 @@ -3,33 +3,47 @@ ;* TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter * ;* Device Driver * ;***********************************************************************/ -/* $Id: tmscsim.h,v 2.4 1998/12/25 17:33:27 garloff Exp $ */ +/* $Id: tmscsim.h,v 2.15.2.3 2000/11/17 20:52:27 garloff Exp $ */ #ifndef _TMSCSIM_H #define _TMSCSIM_H +#include +#include +/* 2.0 compat */ +#if defined(__SMP__) && !defined(CONFIG_SMP) +# if LINUX_VERSION_CODE < KERNEL_VERSION (2,2,0) +# define CONFIG_SMP +# else +# error __SMP__ defined but not CONFIG_SMP +# endif +#endif + + #define IRQ_NONE 255 #define MAX_ADAPTER_NUM 4 -#define MAX_SG_LIST_BUF 16 -#define MAX_CMD_PER_LUN 8 -#define MAX_CMD_QUEUE 2*MAX_CMD_PER_LUN+1 +#define MAX_SG_LIST_BUF 16 /* Not used */ +#define MAX_CMD_PER_LUN 32 +#define MAX_CMD_QUEUE MAX_CMD_PER_LUN+MAX_CMD_PER_LUN/2+1 #define MAX_SCSI_ID 8 #define MAX_SRB_CNT MAX_CMD_QUEUE+1 /* Max number of started commands */ -#define END_SCAN 2 #define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */ -typedef unsigned char UCHAR; -typedef unsigned short USHORT; -typedef unsigned long ULONG; -typedef unsigned int UINT; +#define END_SCAN 2 + +typedef u8 UCHAR; /* 8 bits */ +typedef u16 USHORT; /* 16 bits */ +typedef u32 UINT; /* 32 bits */ +typedef unsigned long ULONG; /* 32/64 bits */ typedef UCHAR *PUCHAR; typedef USHORT *PUSHORT; +typedef UINT *PUINT; typedef ULONG *PULONG; -typedef Scsi_Host_Template *PSHT; -typedef struct Scsi_Host *PSH; +typedef Scsi_Host_Template *PSHT; +typedef struct Scsi_Host *PSH; typedef Scsi_Device *PSCSIDEV; typedef Scsi_Cmnd *PSCSICMD; typedef void *PVOID; @@ -72,48 +86,49 @@ */ struct _SRB { -UCHAR CmdBlock[12]; +//UCHAR CmdBlock[12]; struct _SRB *pNextSRB; struct _DCB *pSRBDCB; PSCSICMD pcmd; PSGL pSegmentList; -ULONG Segment0[2]; -ULONG Segment1[2]; +/* 0x10: */ +SGL Segmentx; /* make a one entry of S/G list table */ -/* 0x2c:*/ -ULONG TotalXferredLen; +/* 0x1c: */ ULONG SGBusAddr; /*;a segment starting address as seen by AM53C974A*/ ULONG SGToBeXferLen; /*; to be xfer length */ -ULONG SRBState; - -/* 0x3c: */ -UCHAR MsgInBuf[6]; -UCHAR MsgOutBuf[6]; - -/* 0x48: */ -SGL Segmentx; /* make a one entry of S/G list table */ - -UCHAR ScsiCmdLen; -UCHAR ScsiPhase; +ULONG TotalXferredLen; +ULONG SavedTotXLen; +UINT SRBState; +/* 0x30: */ +UCHAR SRBStatus; +UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */ + /*; b4-settimeout,b5-Residual valid */ UCHAR AdaptStatus; UCHAR TargetStatus; -/* 0x58: */ +UCHAR ScsiPhase; +UCHAR TagNumber; +UCHAR SGIndex; +UCHAR SGcount; + +/* 0x38: */ UCHAR MsgCnt; UCHAR EndMessage; UCHAR RetryCnt; -UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */ - /*; b4-settimeout,b5-Residual valid */ -UCHAR TagNumber; -UCHAR SGcount; -UCHAR SGIndex; -UCHAR SRBStatus; - //UCHAR IORBFlag; /*;81h-Reset, 2-retry */ +UCHAR SavedSGCount; + +ULONG Saved_Ptr; + +/* 0x40: */ +UCHAR MsgInBuf[6]; +UCHAR MsgOutBuf[6]; -/* 0x60: */ +//UCHAR IORBFlag; /*;81h-Reset, 2-retry */ +/* 0x4c: */ }; @@ -129,48 +144,47 @@ struct _DCB *pNextDCB; struct _ACB *pDCBACB; -PSCSICMD pQIORBhead; -PSCSICMD pQIORBtail; -PSCSICMD AboIORBhead; -PSCSICMD AboIORBtail; -ULONG QIORBCnt; -ULONG AboIORBcnt; +/* Aborted Commands */ +//PSCSICMD AboIORBhead; +//PSCSICMD AboIORBtail; +//ULONG AboIORBcnt; -/* 0x20: */ +/* 0x08: */ +/* Queued SRBs */ PSRB pWaitingSRB; PSRB pWaitLast; PSRB pGoingSRB; PSRB pGoingLast; PSRB pActiveSRB; +UCHAR WaitSRBCnt; /* Not used */ UCHAR GoingSRBCnt; -UCHAR WaitSRBCnt; /* ??? */ + UCHAR DevType; UCHAR MaxCommand; -/* 0x38: */ -ULONG TagMask; +/* 0x20: */ +UINT TagMask; -UCHAR UnitSCSIID; /*; SCSI Target ID (SCSI Only) */ -UCHAR UnitSCSILUN; /*; SCSI Log. Unit (SCSI Only) */ +UCHAR TargetID; /*; SCSI Target ID (SCSI Only) */ +UCHAR TargetLUN; /*; SCSI Log. Unit (SCSI Only) */ UCHAR DevMode; -UCHAR IdentifyMsg; +UCHAR DCBFlag; UCHAR CtrlR1; UCHAR CtrlR3; UCHAR CtrlR4; +UCHAR Inquiry7; -UCHAR DCBFlag; - -/* 0x44: */ +/* 0x2c: */ UCHAR SyncMode; /*; 0:async mode */ UCHAR NegoPeriod; /*;for nego. */ UCHAR SyncPeriod; /*;for reg. */ UCHAR SyncOffset; /*;for reg. and nego.(low nibble) */ -/* 0x48:*/ +/* 0x30:*/ //UCHAR InqDataBuf[8]; //UCHAR CapacityBuf[8]; -/* 0x58: */ +///* 0x40: */ }; typedef struct _DCB DC390_DCB, *PDCB; @@ -201,16 +215,24 @@ PDCB pLinkDCB; PDCB pLastDCB; PDCB pDCBRunRobin; + PDCB pActiveDCB; PSRB pFreeSRB; PSRB pTmpSRB; /* 0x2c: */ +ULONG QueryCnt; +PSCSICMD pQueryHead; +PSCSICMD pQueryTail; +/* 0x38: */ UCHAR msgin123[4]; UCHAR DCBmap[MAX_SCSI_ID]; +UCHAR Connected; +UCHAR pad; -#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(__SMP__) || DEBUG_SPINLOCKS > 0) +/* 0x3c: */ +#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(CONFIG_SMP) || DEBUG_SPINLOCKS > 0) spinlock_t lock; #endif UCHAR sel_timeout; @@ -220,18 +242,20 @@ UCHAR Ignore_IRQ; /* Not used */ PDEVDECL1; /* Pointer to PCI cfg. space */ -/* 0x40/0x3c: */ +/* 0x4c/0x48: */ ULONG Cmds; -ULONG CmdInQ; -ULONG CmdOutOfSRB; -ULONG SelLost; - +UINT SelLost; +UINT SelConn; +UINT CmdInQ; +UINT CmdOutOfSRB; -/* 0x50/0x4c: */ +/* 0x60/0x5c: */ +struct timer_list Waiting_Timer; +/* 0x74/0x70: */ DC390_SRB TmpSRB; -/* 0xb4/0xb0: */ -DC390_SRB SRB_array[MAX_SRB_CNT]; /* 18 SRBs */ -/* 0x7bc/0x7b8: */ +/* 0xd8/0xd4: */ +DC390_SRB SRB_array[MAX_SRB_CNT]; /* 50 SRBs */ +/* 0xfb0/0xfac: */ }; typedef struct _ACB DC390_ACB, *PACB; @@ -339,21 +363,29 @@ #define H_BAD_CCB_OR_SG 0x1A #define H_ABORT 0x0FF -/*; SCSI Status byte codes*/ /* Twice the values defined in scsi/scsi.h */ -#define SCSI_STAT_GOOD 0x0 /*; Good status */ -#define SCSI_STAT_CHECKCOND 0x02 /*; SCSI Check Condition */ -#define SCSI_STAT_CONDMET 0x04 /*; Condition Met */ -#define SCSI_STAT_BUSY 0x08 /*; Target busy status */ -#define SCSI_STAT_INTER 0x10 /*; Intermediate status */ -#define SCSI_STAT_INTERCONDMET 0x14 /*; Intermediate condition met */ -#define SCSI_STAT_RESCONFLICT 0x18 /*; Reservation conflict */ -#define SCSI_STAT_CMDTERM 0x22 /*; Command Terminated */ -#define SCSI_STAT_QUEUEFULL 0x28 /*; Queue Full */ +/*; SCSI Status byte codes*/ +/* The values defined in include/scsi/scsi.h, to be shifted << 1 */ #define SCSI_STAT_UNEXP_BUS_F 0xFD /*; Unexpect Bus Free */ #define SCSI_STAT_BUS_RST_DETECT 0xFE /*; Scsi Bus Reset detected */ #define SCSI_STAT_SEL_TIMEOUT 0xFF /*; Selection Time out */ +/* 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; } + /*;---Sync_Mode */ #define SYNC_DISABLE 0 #define SYNC_ENABLE BIT0 @@ -374,32 +406,9 @@ #define SCSI_NOP1 5 #define SCSI_MSG_OUT 6 #define SCSI_MSG_IN 7 - -/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */ -#define MSG_COMPLETE 0x00 -#define MSG_EXTENDED 0x01 -#define MSG_SAVE_PTR 0x02 -#define MSG_RESTORE_PTR 0x03 -#define MSG_DISCONNECT 0x04 -#define MSG_INITIATOR_ERROR 0x05 -#define MSG_ABORT 0x06 -#define MSG_REJECT_ 0x07 -#define MSG_NOP 0x08 -#define MSG_PARITY_ERROR 0x09 -#define MSG_LINK_CMD_COMPL 0x0A -#define MSG_LINK_CMD_COMPL_FLG 0x0B -#define MSG_BUS_RESET 0x0C -#define MSG_ABORT_TAG 0x0D -#define MSG_SIMPLE_QTAG 0x20 -#define MSG_HEAD_QTAG 0x21 -#define MSG_ORDER_QTAG 0x22 -#define MSG_IDENTIFY 0x80 -#define MSG_HOST_ID 0x0C0 -/* cmd->result */ -#define STATUS_MASK_ 0xFF -#define MSG_MASK 0xFF00 -#define RETURN_MASK 0xFF0000 +/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */ /* One is missing ! */ +#define ABORT_TAG 0x0d /* ** Inquiry Data format @@ -439,8 +448,12 @@ /* Peripheral Device Type definitions */ /* see include/scsi/scsi.h for the rest */ -#define TYPE_PRINTER 0x02 /* Printer device */ -#define TYPE_COMM 0x09 /* Communications device */ +#ifndef TYPE_PRINTER +# define TYPE_PRINTER 0x02 /* Printer device */ +#endif +#ifndef TYPE_COMM +# define TYPE_COMM 0x09 /* Communications device */ +#endif /* ** Inquiry flag definitions (Inq data byte 7)