# dc390-kernel.diff # patches against 2.1.125 kernel for DC390/AM53C974 driver integration # $Id: dc390-120-kernel.diff,v 2.2 1998/10/24 10:14:54 garloff Exp $ # 8<---------------------------------------------------------------------- Patch for allowing omission of the non DC390 parts of the driver: 8<---------------------------------------------------------------------- --- linux/drivers/scsi/Config.in.orig Tue Oct 20 23:21:27 1998 +++ linux/drivers/scsi/Config.in Sat Oct 24 11:40:17 1998 @@ -104,8 +104,11 @@ dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI fi dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI -if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_AM53C974" != "y" ]; then - dep_tristate 'Tekram DC-390(T) (AMD PCscsi) SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI +if [ "$CONFIG_PCI" = "y" ]; then + dep_tristate 'Tekram DC390(T) and Am53/79C974 SCSI support' CONFIG_SCSI_DC390T $CONFIG_SCSI + if [ "$CONFIG_SCSI_DC390T" != "n" ]; then + bool ' _omit_ support for non-DC390 adapters' CONFIG_SCSI_DC390T_NOGENSUPP + fi fi dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI 8<---------------------------------------------------------------------- Patch to allow kernel boot parameters to be passed to the driver: 8<---------------------------------------------------------------------- --- linux/init/main.c.orig Wed Oct 21 09:52:43 1998 +++ linux/init/main.c Sat Oct 24 11:13:32 1998 @@ -194,6 +194,7 @@ extern void in2000_setup(char *str, int *ints); extern void NCR53c406a_setup(char *str, int *ints); extern void wd7000_setup(char *str, int *ints); +extern void dc390_setup(char* str, int *ints); extern void scsi_luns_setup(char *str, int *ints); extern void scsi_logging_setup(char *str, int *ints); extern void sound_setup(char *str, int *ints); @@ -704,6 +705,9 @@ #endif #ifdef CONFIG_SCSI_IBMMCA { "ibmmcascsi=", ibmmca_scsi_setup }, +#endif +#if defined(CONFIG_SCSI_DC390T) && ! defined(CONFIG_SCSI_DC390T_NOGENSUPP) + { "tmscsim=", dc390_setup }, #endif #ifdef CONFIG_BLK_DEV_XD { "xd=", xd_setup }, 8<---------------------------------------------------------------------- Patch to update Documentation: 8<---------------------------------------------------------------------- --- linux/Documentation/Configure.help.orig Wed Oct 21 00:23:16 1998 +++ linux/Documentation/Configure.help Sat Oct 24 11:59:44 1998 @@ -4040,24 +4040,46 @@ say M here and read Documentation/modules.txt. The module will be called NCR53c406.o. -Tekram DC390(T) (AMD PCscsi) SCSI support +Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support CONFIG_SCSI_DC390T - This driver supports the Tekram DC390(T) PCI SCSI host adapter with - the Am53C974A chip, and perhaps other cards using the same chip. - This driver does _not_ support the DC390W/U/F adaptor with the - NCR/Symbios chips; use "NCR53C8XX SCSI support" for that one. + This driver supports PCI SCSI host adapters based on the Am53C974A + chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard + PCscsi/PCnet (Am53/79C974) solutions. + Documentation can be found in linux/drivers/scsi/README.tmscsim. + + Note that this driver does NOT support Tekram DC390W/U/F, which are + based on NCR/Symbios chips. Use the NCR53C8XX driver for those. + Also note, that there is another generic Am53C974 driver. If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read Documentation/modules.txt. The module will be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt. The module will be called tmscsim.o. +Skip support for other Am53/79C974 based SCSI adapters +CONFIG_SCSI_DC390T_NOGENSUPP + Normally, the DC390(T) SCSI driver relies on the DC390 EEPROM to get + initial values for its settings, such as speed, termination, etc. + If it can't find this EEPROM, it will use defaults or the user + supplied boot/module parameters. For details on driver configuration + see linux/drivers/scsi/README.tmscsim. + + With this option set, if no EEPROM is found, the driver gives up and + thus only supports Tekram DC390(T) adapters. This can be useful if + you have a DC390(T) and another Am53C974 based adapter, which, for + some reason, you want to drive with the other AM53C974 driver. + + If unsure, say N. + AM53/79C974 PCI SCSI support CONFIG_SCSI_AM53C974 This is support for the AM53/79C974 SCSI host adapters. Please read drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO, available via FTP (user: anonymous) at - ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, is for you. + ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, is for you. + + Note that there is another driver for AM53C974 based adapters: The + Tekram DC390(T) driver. If you want to compile this driver as a module ( = code which can be inserted in and removed from the running kernel whenever you want), 8<---------------------------------------------------------------------- I do maintain this driver ... 8<---------------------------------------------------------------------- --- linux/MAINTAINERS.orig Wed Oct 21 00:23:16 1998 +++ linux/MAINTAINERS Sat Oct 24 11:13:33 1998 @@ -186,6 +186,12 @@ L: linux-hams@vger.rutgers.edu S: Maintained +DC390/AM53C974 SCSI driver +P: Kurt Garloff +M: K.Garloff@ping.de +W: ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/ +S: Maintained + DECnet NETWORK LAYER P: Steven Whitehouse M: SteveW@ACM.org 8<---------------------------------------------------------------------- And now for the files in linux/drivers/scsi/ 8<---------------------------------------------------------------------- --- /dev/null Mon Dec 22 21:49:24 1997 +++ linux/drivers/scsi/README.tmscsim Sat Oct 24 10:48:45 1998 @@ -0,0 +1,413 @@ +The tmscsim driver +================== + +1. Purpose and history +2. Installation +3. Features +4. Configuration via /proc/scsi/tmscsim/? +5. Configuration via boot/module params +6. Potential improvements +7. Bug reports, debugging and updates +8. Acknowledgements + + +1. Purpose and history +---------------------- +The tmscsim driver supports PCI SCSI Host Adapters based on the AM53C974 +chip. AM53C974 based SCSI adapters include: + Tekram DC390, DC390T + Dawicontrol 2974 + some on-board adapters +(This is most probably not a complete list) + +It has originally written by C.L. Huang from the Tekram corp. to support the +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, +as the ncr53c8xx is perfectly supporting these adpaters since some time. + +The driver first appeared in April 1996, exclusively supported the DC390 +and has been enhanced since then in various steps. In May 1998 support for +general AM53C974 based adapters and some possibilities to configure it were +added. The non-DC390 support works by assuming some values for the data +normally taken from the DC390 EEPROM. See below (chapter 5) for details. + +When using the DC390, the configuration is still be done using the DC390 +BIOS setup. The DC390 EEPROM is read and used by the driver, any boot or +module parameters (chapter 5) are ignored! However, you can change settings +dynamically, as described in chapter 4. + +For a more detailed description of the driver's history, see the first lines +of tmscsim.c. +The numbering scheme isn't consistent. The first versions went from 1.00 to +1.12, then 1.20a to 1.20t. Finally I decided to use the ncr53c8xx scheme. So +the next revisions will be 2.0a to 2.0X (stable), 2.1a to 2.1X (experimental), +2.2a to 2.2X (stable, again) etc. (X = anything between a and z.) If I send +fixes to people for testing, those will have a digit appended, e.g. 2.0a1. + + +2. Installation +--------------- +If you got any recent kernel with this driver and document included in +linux/drivers/scsi, you basically have to do nothing special to use this +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. + +If you got an older kernel with an old version of this driver included, you +should copy the files (dc390.h, tmscsim.h, tmscsim.c, scsiiom.c and +README.tmscsim) from this directory to linux/drivers/scsi. You have to +recompile your kernel/module of course. + +You should apply the three patches included in dc390-20-kernel.diff +(Applying them: cd /usr/src; patch -p0 <~/dc390-20-kernel.diff) +The patches are against 2.1.103, so you might have to manually resolve +rejections when applying to another kernel version. + +The patches will update the kernel startup code to allow boot parameters to +be passed to the driver, update the Documentation and finally offer you the +possibility to omit the non-DC390 parts of the driver. +(By selecting "Omit support for non DC390" you basically disable the +emulation of a DC390 EEPROM for non DC390 adapters. This saves a few bytes +of memory.) + +If you got a very old kernel without the tmscsim driver (pre 2.0.31) +I recommend upgrading your kernel. However, if you don't want to, please +contact me to get the appropriate patches. + +Testing a SCSI driver is always a delicate thing to do. The 2.0 driver has +proven stable on many systems, but it's still a good idea to take some +precautions. In an ideal world you would have a full backup of your disks. +The world isn't ideal and most people don't have full backups (me neither). +So take at least the following two measures: +* make your kernel remount the FS read-only on detecting an error: + 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 +* 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 + +One more warning: I used to overclock my PCI bus to 41.67 MHz. My Tekram +DC390F (Sym53c875) accepted this as well as my Millenium. But the Am53C974 +produced errors and started to corrupt my disks. So don't do that! A 37.50 +MHz PCI bus works for me, though, but I don't recommend using higher clocks +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 +SA_SHIRQ | SA_INTERRUPT. + + +3.Features +---------- +- SCSI + * Tagged queueing + * Sync speed up to 10 MHz + * Disconnection + * Multiple LUNs + +- General / Linux interface + * Support for up to 4 adapters. + * DC390 EEPROM usage or boot/module params + * Information via cat /proc/scsi/tmscsim/? + * Dynamically configurable by writing to /proc/scsi/tmscsim/? + * Dynamic allocation of resources + * SMP support: Adapter specific locks (Linux 2.1.x) + * 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 to use the partition table for the determination of the mapping + + +4. Configuration via /proc/scsi/tmscsim/? +----------------------------------------- +First of all look at the output of /proc/scsi/tmscsim/? by typing + cat /proc/scsi/tmscsim/? +The "?" should be replaced by the SCSI host number. (The shell might do this +for you.) +You will see some info regarding the adapter and, at the end, a listing of +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 +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) + +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 +is somehow inconvenient, but the way the mid-level SCSI code expects it to be. + +ACB and DCB are acronyms for Adapter Control Block and Device Control Block. +These are data structures of the driver containing information about the +adapter and the connected SCSI devices respectively. + +Idx is the device index (just a consecutive number for the driver), ID and +LUN are the SCSI ID and LUN, Prty means Parity checking, Sync synchronous +negotiation, DsCn Disconnection, SndS Send Start command on startup (not +used by the driver) and TagQ Tagged Command Queueing. NegoPeriod and +SyncSpeed are somehow redundant, because they are reciprocal values +(1 / 112 ns = 8.9 MHz). At least in theory. The driver is able to adjust the +NegoPeriod more accurate (4ns) than the SyncSpeed (1 / 25ns). I don't know +if certain devices will have problems with this discrepancy. Max. speed is +10 MHz corresp. to a min. NegoPeriod of 100 ns. +(The driver allows slightly higher speeds if the devices (Ultra SCSI) accept +it, but that's out of adapter spec, on your own risk and unlikely to improve +performance. You're likely to crash your disks.) +SyncOffs is the offset used for synchronous negotiations; max. is 15. +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. + +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. +(Don't use the brackets for NegoPeriod on Sync disabled devices.) +You don't have to care about capitalisation. The driver will accept space, +tab, comma, = and : as separators. + +There are three kinds of changes: + +(1) Change driver settings: + You type the names of the parameters and the params following it. + Example: + 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. + +(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 + ignored and the corresponding setting won't be changed. + You can use "y" or "n" instead of "Yes" and "No" if you want to. + You don't need to specify a full line. The driver automatically performs + 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 + + 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), + select the device to which the following parameters apply. Note that it + would be sufficient to use the index or both SCSI ID and LUN, but I chose + to require all three to have a syntax similar to the output. + The following "y y y - y" enables Parity checking, enables Synchronous + transfers, Disconnection, leaves Send Start (not used) untouched and + enables Tagged Command Queueing for the selected device. The "-" skips + the Negotiation Period setting but the "10" sets the max sync. speed to + 10 MHz. It's useless to specify both NegoPeriod and SyncSpeed as + 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. + 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 + output of /proc/scsi/tmscsim/? in the device listing in the first column + (Idx). + Examples: + echo "reset" >/proc/scsi/tmscsim/0 + echo "inquiry 1" >/proc/scsi/tmscsim/0 + echo "remove 2" >/proc/scsi/tmscsim/1 + + 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. + + +I'd suggest reviewing the output of /proc/scsi/tmscsim/? after changing +settings to see if everything changed as requested. + + +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.) +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. + +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 +parameter lines have the risk to be misinterpreted and the length of kernel +parameters is limited. + +As the support for non-DC390 adapters works by simulating the values of the +DC390 EEPROM, the settings are given in a DC390 BIOS' way. + +Here's the syntax: +tmscsim=AdaptID,SpdIdx,DevMode,AdaptMode,TaggedCmnds + +Each of the parameters is a number, containing the described information: + +* AdaptID: The SCSI ID of the host adapter. Must be in the range 0..7 + Default is 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). + +* 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 + device supports it.) The meaning of the bits (* = default): + + Bit Val(hex) Val(dec) Meaning + *0 0x01 1 Parity check + *1 0x02 2 Synchronous Negotiation + *2 0x04 4 Disconnection + *3 0x08 8 Send Start command on startup. (Not used) + *4 0x10 16 Tagged 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. + +* AdaptMode is a bit mapped value describing the enabled adapter features. + + Bit Val(hex) Val(dec) Meaning + *0 0x01 1 Support more than two drives. (Not used) + *1 0x02 2 Use DOS compatible mapping for HDs greater than 1GB. + *2 0x04 4 Reset SCSI Bus on startup. + *3 0x08 8 Active Negation: Improves SCSI Bus noise immunity. + 4 0x10 16 Immediate return on BIOS seek command. (Not used) + (*)5 0x20 32 Check for LUNs >= 1. + + The default for LUN Check depends on CONFIG_SCSI_MULTI_LUN. + +* TaggedCmnds is a number indicating the maximum number of Tagged Commands. + It is the binary logarithm - 1 of the actual number. Max is 4 (32). + Value Number of Tagged Commands + 0 2 + 1 4 + 2 8 + *3 16 + 4 32 + +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. + +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. + + +6. Potential improvements +------------------------- +Most of the intended work on the driver has been done. Here are a few ideas +to further improve its usability: + +* 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 +* More user friendly boot/module param syntax + +Further investigation on these problems: + +* TagQ and Disconnection (Resel: SRB Tag Seleection) +* Problems with IRQ sharing (IO-APIC on SMP Systems) (??) +* Driver crashes with readcdda (xcdroast) + +Known problems: + +* 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).) +* 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 + 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. Apply + the patch 2035-scsi-singlelun.diff. Thanks to Chiaki Ishikawa. + I was told that this fix will be in 2.0.36, so you don't need it for + 2.0.36. +[The patch file is contained in the dc390-XXX.tar.gz files which can be found +on the ftp server. See below.] + + +7. Bug reports, debugging and updates +------------------------------------- +Whenever you have problems with the driver, you are invited to ask the +author for help. However, I'd suggest reading the docs and trying to solve +the problem yourself, first. +If you find something, which you believe to be a bug, please report it to me. +Please append the output of /proc/scsi/scsi, /proc/scsi/tmscsim/? and +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 +are caused by the SCSI mid-level code. + +I will ask you for some more details and probably I will also ask you to +enable some of the DEBUG options in the driver (tmscsim.c:DC390_DEBUGXXX +defines). The driver will produce some data for the syslog facility then. +Beware: If your syslog gets written to a SCSI disk connected to your +AM53C974, the logging might produce log output again, and you might end +having your box spending most of its time doing the logging. + +The latest version of the driver can be found at: +ftp://student.physik.uni-dortmund.de/pub/linux/kernel/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 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 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). + + +------------------------------------------------------------------------- +Written by Kurt Garloff 1998/06/11 +Last updated 1998/10/15, driver revision 2.0b +$Id: README.tmscsim,v 2.4 1998/10/24 08:45:02 garloff Exp $ --- linux/drivers/scsi/tmscsim.c.old Thu May 21 23:24:09 1998 +++ linux/drivers/scsi/tmscsim.c Sat Oct 24 10:51:53 1998 @@ -5,35 +5,132 @@ * Bus Master Host Adapter * * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. * ***********************************************************************/ -/* Minor enhancements and bugfixes by * +/* $Id: tmscsim.c,v 2.4 1998/10/24 08:50:47 garloff Exp $ */ +/* Enhancements and bugfixes by * * Kurt Garloff * ***********************************************************************/ /* HISTORY: * * * * REV# DATE NAME DESCRIPTION * - * 1.00 04/24/96 CLH First release * - * 1.01 06/12/96 CLH Fixed bug of Media Change for Removable * + * 1.00 96/04/24 CLH First release * + * 1.01 96/06/12 CLH Fixed bug of Media Change for Removable * * Device, scan all LUN. Support Pre2.0.10 * - * 1.02 06/18/96 CLH Fixed bug of Command timeout ... * - * 1.03 09/25/96 KG Added tmscsim_proc_info() * - * 1.04 10/11/96 CLH Updating for support KV 2.0.x * - * 1.05 10/18/96 KG Fixed bug in DC390_abort(null ptr deref)* - * 1.06 10/25/96 KG Fixed module support * - * 1.07 11/09/96 KG Fixed tmscsim_proc_info() * - * 1.08 11/18/96 KG Fixed null ptr in DC390_Disconnect() * - * 1.09 11/30/96 KG Added register the allocated IO space * - * 1.10 12/05/96 CLH Modified tmscsim_proc_info(), and reset * + * 1.02 96/06/18 CLH Fixed bug of Command timeout ... * + * 1.03 96/09/25 KG Added tmscsim_proc_info() * + * 1.04 96/10/11 CLH Updating for support KV 2.0.x * + * 1.05 96/10/18 KG Fixed bug in DC390_abort(null ptr deref)* + * 1.06 96/10/25 KG Fixed module support * + * 1.07 96/11/09 KG Fixed tmscsim_proc_info() * + * 1.08 96/11/18 KG Fixed null ptr in DC390_Disconnect() * + * 1.09 96/11/30 KG Added register the allocated IO space * + * 1.10 96/12/05 CLH Modified tmscsim_proc_info(), and reset * * pending interrupt in DC390_detect() * - * 1.11 02/05/97 KG/CLH Fixeds problem with partitions greater * - * than 1GB * - * 1.12 15/02/98 MJ Rewritten PCI probing * + * 1.11 97/02/05 KG/CLH Fixeds problem with partitions greater * + * than 1GB * + * 1.12 98/02/15 MJ Rewritten PCI probing * + * 1.13 98/04/08 KG Support for non DC390, __initfunc decls,* + * changed max devs from 10 to 16 * + * 1.14a 98/05/05 KG Dynamic DCB allocation, add-single-dev * + * for LUNs if LUN_SCAN (BIOS) not set * + * runtime config using /proc interface * + * 1.14b 98/05/06 KG eliminated cli (); sti (); spinlocks * + * 1.14c 98/05/07 KG 2.0.x compatibility * + * 1.20a 98/05/07 KG changed names of funcs to be consistent * + * DC390_ (entry points), dc390_ (internal)* + * reworked locking * + * 1.20b 98/05/12 KG bugs: version, kfree, _ctmp * + * debug output * + * 1.20c 98/05/12 KG bugs: kfree, parsing, EEpromDefaults * + * 1.20d 98/05/14 KG bugs: list linkage, clear flag after * + * reset on startup, code cleanup * + * 1.20e 98/05/15 KG spinlock comments, name space cleanup * + * pLastDCB now part of ACB structure * + * added stats, timeout for 2.1, TagQ bug * + * RESET and INQUIRY interface commands * + * 1.20f 98/05/18 KG spinlocks fixes, max_lun fix, free DCBs * + * for missing LUNs, pending int * + * 1.20g 98/05/19 KG Clean up: Avoid short * + * 1.20h 98/05/21 KG Remove AdaptSCSIID, max_lun ... * + * 1.20i 98/05/21 KG Aiiie: Bug with TagQMask * + * 1.20j 98/05/24 KG Handle STAT_BUSY, handle pACB->pLinkDCB * + * == 0 in remove_dev and DoingSRB_Done * + * 1.20k 98/05/25 KG DMA_INT (experimental) * + * 1.20l 98/05/27 KG remove DMA_INT; DMA_IDLE cmds added; * + * 1.20m 98/06/10 KG glitch configurable; made some global * + * vars part of ACB; use DC390_readX * + * 1.20n 98/06/11 KG startup params * + * 1.20o 98/06/15 KG added TagMaxNum to boot/module params * + * Device Nr -> Idx, TagMaxNum power of 2 * + * 1.20p 98/06/17 KG Docu updates. Reset depends on settings * + * pci_set_master added; 2.0.xx: pcibios_* * + * used instead of MechNum things ... * + * 1.20q 98/06/23 KG Changed defaults. Added debug code for * + * removable media and fixed it. TagMaxNum * + * fixed for DC390. Locking: ACB, DRV for * + * better IRQ sharing. Spelling: Queueing * + * Parsing and glitch_cfg changes. Display * + * real SyncSpeed value. Made DisConn * + * functional (!) * + * 1.20r 98/06/30 KG Debug macros, allow disabling DsCn, set * + * BIT4 in CtrlR4, EN_PAGE_INT, 2.0 module * + * param -1 fixed. * + * 1.20s 98/08/20 KG Debug info on abort(), try to check PCI,* + * phys_to_bus instead of phys_to_virt, * + * fixed sel. process, fixed locking, * + * added MODULE_XXX infos, changed IRQ * + * request flags, disable DMA_INT * + * 1.20t 98/09/07 KG TagQ report fixed; Write Erase DMA Stat;* + * initfunc -> __init; better abort; * + * Timeout for XFER_DONE & BLAST_COMPLETE; * + * Allow up to 33 commands being processed * + * 2.0a 98/10/14 KG Max Cmnds back to 17. DMA_Stat clearing * + * all flags. Clear within while() loops * + * in DataIn_0/Out_0. Null ptr in dumpinfo * + * for pSRB==0. Better locking during init.* + * bios_param() now respects part. table. * + * 2.0b 98/10/24 KG Docu fixes. Timeout Msg in DMA Blast. * + * Disallow illegal idx in INQUIRY/REMOVE * ***********************************************************************/ +/* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */ +#define DC390_IRQ SA_SHIRQ /* | SA_INTERRUPT */ -#define DC390_DEBUG +/* DEBUG options */ +//#define DC390_DEBUG0 +//#define DC390_DEBUG1 +//#define DC390_DCBDEBUG +//#define DC390_PARSEDEBUG +//#define DC390_REMOVABLEDEBUG -#define SCSI_MALLOC +/* Debug definitions */ +#ifdef DC390_DEBUG0 +# define DEBUG0(x) x; +#else +# define DEBUG0(x) +#endif +#ifdef DC390_DEBUG1 +# define DEBUG1(x) x; +#else +# define DEBUG1(x) +#endif +#ifdef DC390_DCBDEBUG +# define DCBDEBUG(x) x; +#else +# define DCBDEBUG(x) +#endif +#ifdef DC390_PARSEDEBUG +# define PARSEDEBUG(x) x; +#else +# define PARSEDEBUG(x) +#endif +#ifdef DC390_REMOVABLEDEBUG +# define REMOVABLEDEBUG(x) x; +#else +# define REMOVABLEDEBUG(x) +#endif +#define DCBDEBUG1(x) +/* Includes */ #ifdef MODULE # include #endif @@ -41,7 +138,6 @@ #include #include #include -#include #include #include #include @@ -51,14 +147,14 @@ #include #include #include +#include #include #include -#include +#include #include #include "scsi.h" #include "hosts.h" -#include "tmscsim.h" #include "constants.h" #include "sd.h" #include @@ -67,107 +163,350 @@ #define PCI_DEVICE_ID_AMD53C974 PCI_DEVICE_ID_AMD_SCSI -struct proc_dir_entry proc_scsi_tmscsim ={ - PROC_SCSI_DC390T, 7 ,"tmscsim", - S_IFDIR | S_IRUGO | S_IXUGO, 2 - }; +/* Locking */ -static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ); -static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); -static void DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus); - -static void SetXferRate( PACB pACB, PDCB pDCB ); -static void DC390_Disconnect( PACB pACB ); -static void DC390_Reselect( PACB pACB ); -static void SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ); -static void DoingSRB_Done( PACB pACB ); -static void DC390_ScsiRstDetect( PACB pACB ); -static void DC390_ResetSCSIBus( PACB pACB ); -static void RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ); -static void EnableMsgOut2( PACB pACB, PSRB pSRB ); -static void EnableMsgOut( PACB pACB, PSRB pSRB ); -static void DC390_InvalidCmd( PACB pACB ); +/* 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! + * 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. + */ + +/* spinlock things + * level 3: lock on both adapter specific locks and (global) io_request_lock + * level 2: lock on adapter specific locks only + * level 1: rely on the locking of the mid level code (io_request_lock) + * undef : traditional save_flags; cli; restore_flags; + */ + +//#define DEBUG_SPINLOCKS 2 /* Set to 0, 1 or 2 in include/asm/spinlock.h */ + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +# include +# include +#endif -int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index ); -void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ); + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) +# define USE_SPINLOCKS 1 +# define NEW_PCI 1 +#else +# undef NEW_PCI +# if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,30) +# define USE_SPINLOCKS 2 +# endif +#endif + +#ifdef USE_SPINLOCKS + +# if USE_SPINLOCKS == 3 /* both */ + +# if defined (__SMP__) || DEBUG_SPINLOCKS > 0 +# define DC390_LOCK_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; }; +# else +# define DC390_LOCK_INIT +# endif + spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED; + +# define DC390_AFLAGS unsigned long aflags; +# define DC390_IFLAGS unsigned long iflags; +# define DC390_DFLAGS unsigned long dflags; + +# define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags) +# define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags) + +# define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags) +# define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags) +# define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock) +# define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock) + +# define DC390_LOCK_ACB spin_lock_irqsave (&(pACB->lock), aflags) +# define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags) +# define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock)) +# define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock)) +//# define DC390_LOCK_INIT spin_lock_init (&(pACB->lock)) + +# else + +# if USE_SPINLOCKS == 2 /* adapter specific locks */ + +# if defined (__SMP__) || DEBUG_SPINLOCKS > 0 +# define DC390_LOCK_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; }; +# else +# define DC390_LOCK_INIT +# endif + spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED; +# define DC390_AFLAGS unsigned long aflags; +# define DC390_IFLAGS +# define DC390_DFLAGS unsigned long dflags; +# define DC390_LOCK_IO /* spin_lock_irqsave (&io_request_lock, iflags) */ +# define DC390_UNLOCK_IO /* spin_unlock_irqrestore (&io_request_lock, iflags) */ +# define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags) +# define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags) +# define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock) +# define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock) +# define DC390_LOCK_ACB spin_lock_irqsave (&(pACB->lock), aflags) +# define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags) +# define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock)) +# define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock)) +//# define DC390_LOCK_INIT spin_lock_init (&(pACB->lock)) + +# else /* USE_SPINLOCKS == 1: global lock io_request_lock */ + +# define DC390_AFLAGS +# define DC390_IFLAGS unsigned long iflags; +# define DC390_DFLAGS unsigned long dflags; + spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED; +# define DC390_LOCK_IO spin_lock_irqsave (&io_request_lock, iflags) +# define DC390_UNLOCK_IO spin_unlock_irqrestore (&io_request_lock, iflags) +# define DC390_LOCK_DRV spin_lock_irqsave (&dc390_drvlock, dflags) +# define DC390_UNLOCK_DRV spin_unlock_irqrestore (&dc390_drvlock, dflags) +# define DC390_LOCK_DRV_NI spin_lock (&dc390_drvlock) +# define DC390_UNLOCK_DRV_NI spin_unlock (&dc390_drvlock) +# define DC390_LOCK_ACB /* DC390_LOCK_IO */ +# define DC390_UNLOCK_ACB /* DC390_UNLOCK_IO */ +# define DC390_LOCK_ACB_NI /* spin_lock (&(pACB->lock)) */ +# define DC390_UNLOCK_ACB_NI /* spin_unlock (&(pACB->lock)) */ +# define DC390_LOCK_INIT /* DC390_LOCK_INIT */ + +# endif /* 2 */ +# endif /* 3 */ + +#else /* USE_SPINLOCKS undefined */ + +# define DC390_AFLAGS unsigned long aflags; +# define DC390_IFLAGS unsigned long iflags; +# define DC390_DFLAGS unsigned long dflags; +# define DC390_LOCK_IO save_flags (iflags); cli () +# define DC390_UNLOCK_IO restore_flags (iflags) +# define DC390_LOCK_DRV save_flags (dflags); cli () +# define DC390_UNLOCK_DRV restore_flags (dflags) +# define DC390_LOCK_DRV_NI +# define DC390_UNLOCK_DRV_NI +# define DC390_LOCK_ACB save_flags (aflags); cli () +# define DC390_UNLOCK_ACB restore_flags (aflags) +# define DC390_LOCK_ACB_NI +# define DC390_UNLOCK_ACB_NI +# define DC390_LOCK_INIT +#endif /* def */ + + +/* These macros are used for uniform access to 2.0.x and 2.1.x PCI config space*/ + +#ifdef NEW_PCI +# define PDEV pdev +# define PDEVDECL struct pci_dev *pdev +# define PDEVDECL0 struct pci_dev *pdev = NULL +# define PDEVDECL1 struct pci_dev *pdev +# define PDEVSET pACB->pdev=pdev +# define PDEVSET1 pdev=pACB->pdev +# define PCI_WRITE_CONFIG_BYTE(pd, rv, bv) pci_write_config_byte (pd, rv, bv) +# define PCI_READ_CONFIG_BYTE(pd, rv, bv) pci_read_config_byte (pd, rv, bv) +# define PCI_WRITE_CONFIG_WORD(pd, rv, bv) pci_write_config_word (pd, rv, bv) +# define PCI_READ_CONFIG_WORD(pd, rv, bv) pci_read_config_word (pd, rv, bv) +# define PCI_BUS_DEV pdev->bus->number, pdev->devfn +# 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)) +# define PCI_GET_IO_AND_IRQ io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; irq = pdev->irq +#else +# include +# define PDEV pbus, pdevfn +# define PDEVDECL UCHAR pbus, UCHAR pdevfn +# define PDEVDECL0 UCHAR pbus = 0; UCHAR pdevfn = 0; USHORT pci_index = 0; int error +# define PDEVDECL1 UCHAR pbus; UCHAR pdevfn /*; USHORT pci_index */ +# define PDEVSET pACB->pbus=pbus; pACB->pdevfn=pdevfn /*; pACB->pci_index=pci_index */ +# define PDEVSET1 pbus=pACB->pbus; pdevfn=pACB->pdevfn /*; pci_index=pACB->pci_index */ +# define PCI_WRITE_CONFIG_BYTE(pd, rv, bv) pcibios_write_config_byte (pd, rv, bv) +# define PCI_READ_CONFIG_BYTE(pd, rv, bv) pcibios_read_config_byte (pd, rv, bv) +# define PCI_WRITE_CONFIG_WORD(pd, rv, bv) pcibios_write_config_word (pd, rv, bv) +# define PCI_READ_CONFIG_WORD(pd, rv, bv) pcibios_read_config_word (pd, rv, bv) +# define PCI_BUS_DEV pbus, pdevfn +# define PCI_PRESENT pcibios_present () +# define PCI_SET_MASTER dc390_set_master (pbus, pdevfn) +# define PCI_FIND_DEVICE(vend, id) (!pcibios_find_device (vend, id, pci_index++, &pbus, &pdevfn)) +# define PCI_GET_IO_AND_IRQ error = pcibios_read_config_dword (pbus, pdevfn, PCI_BASE_ADDRESS_0, &io_port); \ + error |= pcibios_read_config_byte (pbus, pdevfn, PCI_INTERRUPT_LINE, &irq); \ + io_port &= 0xfffe; \ + if (error) { printk (KERN_ERR "DC390_detect: Error reading PCI config registers!\n"); continue; } +#endif + +#include "tmscsim.h" + +#ifndef __init +# define __init +#endif + +UCHAR dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ); +void dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +void dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +void dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +void dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +void dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); +static void dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus); + +static void dc390_SetXferRate( PACB pACB, PDCB pDCB ); +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 ); +static void dc390_ScsiRstDetect( PACB pACB ); +static void dc390_ResetSCSIBus( PACB pACB ); +static void __inline__ dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ); +static void __inline__ dc390_EnableMsgOut2( PACB pACB, PSRB pSRB ); +static void __inline__ dc390_EnableMsgOut( PACB pACB, PSRB pSRB ); +static void __inline__ dc390_InvalidCmd( PACB pACB ); +static void dc390_remove_dev (PACB pACB, PDCB pDCB); +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_updateDCB (PACB pACB, PDCB pDCB); #ifdef MODULE -static int DC390_release(struct Scsi_Host *host); -static int DC390_shutdown (struct Scsi_Host *host); + static int DC390_release(struct Scsi_Host *host); + static int dc390_shutdown (struct Scsi_Host *host); #endif -static PSHT pSHT_start = NULL; -static PSH pSH_start = NULL; -static PSH pSH_current = NULL; -static PACB pACB_start= NULL; -static PACB pACB_current = NULL; -static PDCB pPrevDCB = NULL; -static USHORT adapterCnt = 0; -static USHORT InitialTime = 0; -static USHORT CurrSyncOffset = 0; - -static PVOID DC390_phase0[]={ - DC390_DataOut_0, - DC390_DataIn_0, - DC390_Command_0, - DC390_Status_0, - DC390_Nop_0, - DC390_Nop_0, - DC390_MsgOut_0, - DC390_MsgIn_0, - DC390_Nop_1 - }; +//static PSHT dc390_pSHT_start = NULL; +//static PSH dc390_pSH_start = NULL; +//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; + +#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 */}; + +# 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)"); +# endif + +#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */ + +#if defined(MODULE) && LINUX_VERSION_CODE >= LinuxVersionCode(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"); +#endif -static PVOID DC390_phase1[]={ - DC390_DataOutPhase, - DC390_DataInPhase, - DC390_CommandPhase, - DC390_StatusPhase, - DC390_Nop_0, - DC390_Nop_0, - DC390_MsgOutPhase, - DC390_MsgInPhase, - DC390_Nop_1, +static PVOID dc390_phase0[]={ + dc390_DataOut_0, + dc390_DataIn_0, + dc390_Command_0, + dc390_Status_0, + dc390_Nop_0, + dc390_Nop_0, + dc390_MsgOut_0, + dc390_MsgIn_0, + dc390_Nop_1 }; -UCHAR eepromBuf[MAX_ADAPTER_NUM][128]; - +static PVOID dc390_phase1[]={ + dc390_DataOutPhase, + dc390_DataInPhase, + dc390_CommandPhase, + dc390_StatusPhase, + dc390_Nop_0, + dc390_Nop_0, + dc390_MsgOutPhase, + dc390_MsgInPhase, + dc390_Nop_1 + }; -UCHAR clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20}; +#ifdef DC390_DEBUG1 +static char* dc390_p0_str[] = { + "dc390_DataOut_0", + "dc390_DataIn_0", + "dc390_Command_0", + "dc390_Status_0", + "dc390_Nop_0", + "dc390_Nop_0", + "dc390_MsgOut_0", + "dc390_MsgIn_0", + "dc390_Nop_1" + }; + +static char* dc390_p1_str[] = { + "dc390_DataOutPhase", + "dc390_DataInPhase", + "dc390_CommandPhase", + "dc390_StatusPhase", + "dc390_Nop_0", + "dc390_Nop_0", + "dc390_MsgOutPhase", + "dc390_MsgInPhase", + "dc390_Nop_1" + }; +#endif -UCHAR baddevname1[2][28] ={ +/* Devices erroneously pretending to be able to do TagQ */ +UCHAR dc390_baddevname1[2][28] ={ "SEAGATE ST3390N 9546", "HP C3323-300 4269"}; - #define BADDEVCNT 2 +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}; + +struct proc_dir_entry DC390_proc_scsi_tmscsim ={ + PROC_SCSI_DC390T, 7 ,"tmscsim", + S_IFDIR | S_IRUGO | S_IXUGO, 2 + }; /*********************************************************************** * * * **********************************************************************/ -static void -QLinkcmd( PSCSICMD cmd, PDCB pDCB ) +static PDCB __inline__ dc390_findDCB ( PACB pACB, Scsi_Cmnd *cmd) { - ULONG flags; - PSCSICMD pcmd; + PDCB pDCB = pACB->pLinkDCB; if (!pDCB) return 0; + while (pDCB->UnitSCSIID != cmd->target || pDCB->UnitSCSILUN != cmd->lun) + { + pDCB = pDCB->pNextDCB; + if (pDCB == pACB->pLinkDCB) + { + printk (KERN_ERR "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n", + (int)pDCB, cmd->target, pACB->DCBmap[cmd->target]); + return 0; + } + }; + DCBDEBUG1( printk (KERN_DEBUG "DCB %08x (%02x,%02x) found.\n", \ + (int)pDCB, pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) + return pDCB; +}; - save_flags(flags); - cli(); +static void dc390_QLinkcmd( PSCSICMD cmd, PDCB pDCB ) +{ + PSCSICMD pcmd; if( !pDCB->QIORBCnt ) { @@ -185,83 +524,61 @@ cmd->next = NULL; } - restore_flags(flags); } -static PSCSICMD -Getcmd( PDCB pDCB ) +static __inline__ PSCSICMD dc390_Getcmd( PDCB pDCB ) { - ULONG flags; PSCSICMD pcmd; - save_flags(flags); - cli(); - pcmd = pDCB->pQIORBhead; pDCB->pQIORBhead = pcmd->next; pcmd->next = NULL; pDCB->QIORBCnt--; - restore_flags(flags); return( pcmd ); } -static PSRB -GetSRB( PACB pACB ) +static __inline__ PSRB dc390_GetSRB( PACB pACB ) { - ULONG flags; PSRB pSRB; - save_flags(flags); - cli(); - pSRB = pACB->pFreeSRB; if( pSRB ) { pACB->pFreeSRB = pSRB->pNextSRB; pSRB->pNextSRB = NULL; } - restore_flags(flags); + return( pSRB ); } -static void -RewaitSRB0( PDCB pDCB, PSRB pSRB ) +static __inline__ void dc390_RewaitSRB0( PDCB pDCB, PSRB pSRB ) { PSRB psrb1; - ULONG flags; - - save_flags(flags); - cli(); if( (psrb1 = pDCB->pWaitingSRB) ) { pSRB->pNextSRB = psrb1; - pDCB->pWaitingSRB = pSRB; } else { pSRB->pNextSRB = NULL; - pDCB->pWaitingSRB = pSRB; pDCB->pWaitLast = pSRB; } - restore_flags(flags); + pDCB->pWaitingSRB = pSRB; } -static void -RewaitSRB( PDCB pDCB, PSRB pSRB ) +static void dc390_RewaitSRB( PDCB pDCB, PSRB pSRB ) { PSRB psrb1; - ULONG flags; UCHAR bval; - save_flags(flags); - cli(); - pDCB->GoingSRBCnt--; + pDCB->GoingSRBCnt--; pDCB->pDCBACB->SelLost++; + DEBUG0(printk("DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);) psrb1 = pDCB->pGoingSRB; if( pSRB == psrb1 ) { @@ -289,20 +606,14 @@ bval = pSRB->TagNumber; pDCB->TagMask &= (~(1 << bval)); /* Free TAG number */ - restore_flags(flags); } -static void -DoWaitingSRB( PACB pACB ) +static void dc390_DoWaitingSRB( PACB pACB ) { - ULONG flags; PDCB ptr, ptr1; PSRB pSRB; - save_flags(flags); - cli(); - if( !(pACB->pActiveDCB) && !(pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) ) { ptr = pACB->pDCBRunRobin; @@ -324,7 +635,7 @@ } else { - if( !DC390_StartSCSI(pACB, ptr1, pSRB) ) + if( !dc390_StartSCSI(pACB, ptr1, pSRB) ) { ptr1->GoingSRBCnt++; if( ptr1->pWaitLast == pSRB ) @@ -348,55 +659,47 @@ } } } - restore_flags(flags); return; } -static void -SRBwaiting( PDCB pDCB, PSRB pSRB) +static __inline__ void dc390_SRBwaiting( PDCB pDCB, PSRB pSRB) { if( pDCB->pWaitingSRB ) { pDCB->pWaitLast->pNextSRB = pSRB; - pDCB->pWaitLast = pSRB; pSRB->pNextSRB = NULL; } else { pDCB->pWaitingSRB = pSRB; - pDCB->pWaitLast = pSRB; } + pDCB->pWaitLast = pSRB; } -static void -SendSRB( PSCSICMD pcmd, PACB pACB, PSRB pSRB ) +static void dc390_SendSRB( PACB pACB, PSRB pSRB ) { - ULONG flags; PDCB pDCB; - save_flags(flags); - cli(); - pDCB = pSRB->pSRBDCB; if( !(pDCB->MaxCommand > pDCB->GoingSRBCnt) || (pACB->pActiveDCB) || (pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV)) ) { - SRBwaiting(pDCB, pSRB); + dc390_SRBwaiting(pDCB, pSRB); goto SND_EXIT; } if( pDCB->pWaitingSRB ) { - SRBwaiting(pDCB, pSRB); -/* pSRB = GetWaitingSRB(pDCB); */ + dc390_SRBwaiting(pDCB, pSRB); +/* pSRB = GetWaitingSRB(pDCB); */ /* non-existent */ pSRB = pDCB->pWaitingSRB; pDCB->pWaitingSRB = pSRB->pNextSRB; pSRB->pNextSRB = NULL; } - if( !DC390_StartSCSI(pACB, pDCB, pSRB) ) + if( !dc390_StartSCSI(pACB, pDCB, pSRB) ) { pDCB->GoingSRBCnt++; if( pDCB->pGoingSRB ) @@ -411,13 +714,52 @@ } } else - RewaitSRB0( pDCB, pSRB ); + dc390_RewaitSRB0( pDCB, pSRB ); SND_EXIT: - restore_flags(flags); return; } +static void dc390_BuildSRB (Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB) +{ + pSRB->pSRBDCB = pDCB; + pSRB->pcmd = pcmd; + pSRB->ScsiCmdLen = pcmd->cmd_len; + memcpy (pSRB->CmdBlock, pcmd->cmnd, pcmd->cmd_len); + + if( pcmd->use_sg ) + { + pSRB->SGcount = (UCHAR) pcmd->use_sg; + pSRB->pSegmentList = (PSGL) pcmd->request_buffer; + } + else if( pcmd->request_buffer ) + { + pSRB->SGcount = 1; + pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; + pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; + pSRB->Segmentx.length = pcmd->request_bufflen; + } + else + pSRB->SGcount = 0; + + pSRB->SGIndex = 0; + pSRB->AdaptStatus = 0; + pSRB->TargetStatus = 0; + pSRB->MsgCnt = 0; + if( pDCB->DevType != TYPE_TAPE ) + pSRB->RetryCnt = 1; + else + pSRB->RetryCnt = 0; + pSRB->SRBStatus = 0; + pSRB->SRBFlag = 0; + pSRB->SRBState = 0; + pSRB->TotalXferredLen = 0; + pSRB->SGBusAddr = 0; + pSRB->SGToBeXferLen = 0; + pSRB->ScsiPhase = 0; + pSRB->EndMessage = 0; +}; + /*********************************************************************** * Function : static int DC390_queue_command (Scsi_Cmnd *cmd, @@ -425,272 +767,305 @@ * * Purpose : enqueues a SCSI command * - * Inputs : cmd - SCSI command, done - function called on completion, with - * a pointer to the command descriptor. + * Inputs : cmd - SCSI command, done - callback function called on + * completion, with a pointer to the command descriptor. * - * Returns : 0 + * Returns : (depending on kernel version) + * 2.0.x: always return 0 + * 2.1.x: old model: (use_new_eh_code == 0): like 2.0.x + * TO BE DONE: + * new model: return 0 if successful + * return 1 if command cannot be queued (queue full) + * command will be inserted in midlevel queue then ... * ***********************************************************************/ -int -DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) +int DC390_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { - USHORT ioport, i; Scsi_Cmnd *pcmd; - struct Scsi_Host *psh; - PACB pACB; PDCB pDCB; PSRB pSRB; - ULONG flags; - PUCHAR ptr,ptr1; + DC390_AFLAGS + PACB pACB = (PACB) cmd->host->hostdata; - psh = cmd->host; - pACB = (PACB ) psh->hostdata; - ioport = pACB->IOPortBase; -#ifdef DC390_DEBUG0 -/* if(pACB->scan_devices) */ - printk("Cmd=%2x,ID=%d,LUN=%d,",cmd->cmnd[0],cmd->target,cmd->lun); -#endif + DEBUG0(/* if(pACB->scan_devices) */ \ + printk(KERN_DEBUG "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\ + cmd->cmnd[0],cmd->target,cmd->lun,cmd->pid);) + + DC390_LOCK_ACB; + + /* Assume BAD_TARGET; will be cleared later */ + cmd->result = DID_BAD_TARGET << 16; + + /* TODO: Change the policy: Alway accept TEST_UNIT_READY or INQUIRY + * commands and alloc a DCB for the device if not yet there. DCB will + * be removed in dc390_SRBdone if SEL_TIMEOUT */ if( (pACB->scan_devices == END_SCAN) && (cmd->cmnd[0] != INQUIRY) ) - { pACB->scan_devices = 0; - pPrevDCB->pNextDCB = pACB->pLinkDCB; - } - else if( (pACB->scan_devices) && (cmd->cmnd[0] == 8) ) - { + + else if( (pACB->scan_devices) && (cmd->cmnd[0] == READ_6) ) pACB->scan_devices = 0; - pPrevDCB->pNextDCB = pACB->pLinkDCB; - } - if ( ( cmd->target > pACB->max_id ) || (cmd->lun > pACB->max_lun) ) + if ( ( cmd->target >= pACB->pScsiHost->max_id ) || + (cmd->lun >= pACB->pScsiHost->max_lun) ) { /* printk("DC390: Ignore target %d lun %d\n", cmd->target, cmd->lun); */ - cmd->result = (DID_BAD_TARGET << 16); + DC390_UNLOCK_ACB; done(cmd); return( 0 ); } - if( (pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) + if( (pACB->scan_devices || cmd->cmnd[0] == TEST_UNIT_READY) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) { - if( pACB->DeviceCnt < MAX_DEVICES ) - { - pACB->DCBmap[cmd->target] |= (1 << cmd->lun); - pDCB = pACB->pDCB_free; -#ifdef DC390_DEBUG0 - printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target); -#endif - DC390_initDCB( pACB, pDCB, cmd ); - } - else /* ???? */ - { -/* printk("DC390: Ignore target %d lun %d\n", - cmd->target, cmd->lun); */ - cmd->result = (DID_BAD_TARGET << 16); + pACB->DCBmap[cmd->target] |= (1 << cmd->lun); + pACB->scan_devices = 1; + + dc390_initDCB( pACB, &pDCB, cmd ); + if (!pDCB) + { + printk (KERN_ERR "DC390: kmalloc for DCB failed, ID=%2x\n", cmd->target); + DC390_UNLOCK_ACB; done(cmd); return(0); - } + }; + } else if( !(pACB->scan_devices) && !(pACB->DCBmap[cmd->target] & (1 << cmd->lun)) ) { -/* printk("DC390: Ignore target %d lun %d\n", - cmd->target, cmd->lun); */ - cmd->result = (DID_BAD_TARGET << 16); + printk(KERN_INFO "DC390: Ignore target %02x lun %02x\n", + cmd->target, cmd->lun); + DC390_UNLOCK_ACB; done(cmd); return(0); } else { - pDCB = pACB->pLinkDCB; - while( (pDCB->UnitSCSIID != cmd->target) || - (pDCB->UnitSCSILUN != cmd->lun) ) - { - pDCB = pDCB->pNextDCB; - } -#ifdef DC390_DEBUG0 - printk("pDCB=%8x,ID=%2x,", (UINT) pDCB, cmd->target); -#endif + pDCB = dc390_findDCB (pACB, cmd); + if (!pDCB) + { /* should never happen */ + DC390_UNLOCK_ACB; + done(cmd); + return(0); + }; } + pACB->Cmds++; cmd->scsi_done = done; cmd->result = 0; - save_flags(flags); - cli(); - - if( pDCB->QIORBCnt ) + if( pDCB->QIORBCnt ) /* Unsent commands ? */ { - QLinkcmd( cmd, pDCB ); - pcmd = Getcmd( pDCB ); + dc390_QLinkcmd( cmd, pDCB ); + pcmd = dc390_Getcmd( pDCB ); /* Get first command */ + pACB->CmdInQ++; } else pcmd = cmd; - pSRB = GetSRB( pACB ); + pSRB = dc390_GetSRB( pACB ); if( !pSRB ) { - QLinkcmd( pcmd, pDCB ); - restore_flags(flags); + dc390_QLinkcmd( pcmd, pDCB ); /* Queue command at the end */ + pACB->CmdOutOfSRB++; + DC390_UNLOCK_ACB; return(0); } -/* BuildSRB(pSRB); */ + dc390_BuildSRB (pcmd, pDCB, pSRB); + dc390_SendSRB( pACB, pSRB ); - pSRB->pSRBDCB = pDCB; - pSRB->pcmd = pcmd; - ptr = (PUCHAR) pSRB->CmdBlock; - ptr1 = (PUCHAR) pcmd->cmnd; - pSRB->ScsiCmdLen = pcmd->cmd_len; - for(i=0; i< pcmd->cmd_len; i++) - { - *ptr = *ptr1; - ptr++; - ptr1++; - } - if( pcmd->use_sg ) - { - pSRB->SGcount = (UCHAR) pcmd->use_sg; - pSRB->pSegmentList = (PSGL) pcmd->request_buffer; - } - else if( pcmd->request_buffer ) - { - pSRB->SGcount = 1; - pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; - pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; - pSRB->Segmentx.length = pcmd->request_bufflen; - } - else - pSRB->SGcount = 0; - - pSRB->SGIndex = 0; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; - pSRB->MsgCnt = 0; - if( pDCB->DevType != TYPE_TAPE ) - pSRB->RetryCnt = 1; - else - pSRB->RetryCnt = 0; - pSRB->SRBStatus = 0; - pSRB->SRBFlag = 0; - pSRB->SRBState = 0; - pSRB->TotalXferredLen = 0; - pSRB->SGPhysAddr = 0; - pSRB->SGToBeXferLen = 0; - pSRB->ScsiPhase = 0; - pSRB->EndMessage = 0; - SendSRB( pcmd, pACB, pSRB ); - - restore_flags(flags); + DC390_UNLOCK_ACB; + DEBUG1(printk (KERN_DEBUG " ... command (%02x) queued successfully.\n", pcmd->cmnd[0]);) return(0); } -static void -DoNextCmd( PACB pACB, PDCB pDCB ) +static void dc390_DoNextCmd( PACB pACB, PDCB pDCB ) { Scsi_Cmnd *pcmd; PSRB pSRB; - ULONG flags; - PUCHAR ptr,ptr1; - USHORT i; - if( pACB->ACBFlag & (RESET_DETECT+RESET_DONE+RESET_DEV) ) return; - save_flags(flags); - cli(); - pcmd = Getcmd( pDCB ); - pSRB = GetSRB( pACB ); + pcmd = dc390_Getcmd( pDCB ); + pSRB = dc390_GetSRB( pACB ); if( !pSRB ) - { - QLinkcmd( pcmd, pDCB ); - restore_flags(flags); - return; - } - - pSRB->pSRBDCB = pDCB; - pSRB->pcmd = pcmd; - ptr = (PUCHAR) pSRB->CmdBlock; - ptr1 = (PUCHAR) pcmd->cmnd; - pSRB->ScsiCmdLen = pcmd->cmd_len; - for(i=0; i< pcmd->cmd_len; i++) - { - *ptr = *ptr1; - ptr++; - ptr1++; - } - if( pcmd->use_sg ) - { - pSRB->SGcount = (UCHAR) pcmd->use_sg; - pSRB->pSegmentList = (PSGL) pcmd->request_buffer; - } - else if( pcmd->request_buffer ) - { - pSRB->SGcount = 1; - pSRB->pSegmentList = (PSGL) &pSRB->Segmentx; - pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; - pSRB->Segmentx.length = pcmd->request_bufflen; - } + dc390_QLinkcmd( pcmd, pDCB ); else - pSRB->SGcount = 0; - - pSRB->SGIndex = 0; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; - pSRB->MsgCnt = 0; - if( pDCB->DevType != TYPE_TAPE ) - pSRB->RetryCnt = 1; - else - pSRB->RetryCnt = 0; - pSRB->SRBStatus = 0; - pSRB->SRBFlag = 0; - pSRB->SRBState = 0; - pSRB->TotalXferredLen = 0; - pSRB->SGPhysAddr = 0; - pSRB->SGToBeXferLen = 0; - pSRB->ScsiPhase = 0; - pSRB->EndMessage = 0; - SendSRB( pcmd, pACB, pSRB ); - - restore_flags(flags); - return; + { + 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 ;-) */ + +#ifdef CONFIG_SCSI_DC390T_TRADMAP +/* + * The next function, partsize(), is copied from scsicam.c. + * + * This is ugly code duplication, but I didn't find another way to solve it: + * We want to respect the partition table and if it fails, we apply the + * DC390 BIOS heuristic. Too bad, just calling scsicam_bios_param() doesn't do + * the job, because we don't know, whether the values returned are from + * the part. table or determined by setsize(). Unfortunately the setsize() + * values differ from the ones chosen by the DC390 BIOS. + * + * Looking forward to seeing suggestions for a better solution! KG, 98/10/14 + */ +#include + +/* + * Function : static int partsize(struct buffer_head *bh, unsigned long + * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs); + * + * Purpose : to determine the BIOS mapping used to create the partition + * table, storing the results in *cyls, *hds, and *secs + * + * Returns : -1 on failure, 0 on success. + * + */ + +static int partsize(struct buffer_head *bh, unsigned long capacity, + unsigned int *cyls, unsigned int *hds, unsigned int *secs) { + struct partition *p, *largest = NULL; + int i, largest_cyl; + int cyl, ext_cyl, end_head, end_cyl, end_sector; + unsigned int logical_end, physical_end, ext_physical_end; + + + if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { + for (largest_cyl = -1, p = (struct partition *) + (0x1BE + bh->b_data), i = 0; i < 4; ++i, ++p) { + if (!p->sys_ind) + continue; + cyl = p->cyl + ((p->sector & 0xc0) << 2); + if (cyl > largest_cyl) { + largest_cyl = cyl; + largest = p; + } + } + } + + if (largest) { + end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2); + end_head = largest->end_head; + end_sector = largest->end_sector & 0x3f; + + physical_end = end_cyl * (end_head + 1) * end_sector + + end_head * end_sector + end_sector; + + /* This is the actual _sector_ number at the end */ + logical_end = get_unaligned(&largest->start_sect) + + get_unaligned(&largest->nr_sects); + + /* This is for >1023 cylinders */ + ext_cyl= (logical_end-(end_head * end_sector + end_sector)) + /(end_head + 1) / end_sector; + ext_physical_end = ext_cyl * (end_head + 1) * end_sector + + end_head * end_sector + end_sector; + + if ((logical_end == physical_end) || + (end_cyl==1023 && ext_physical_end==logical_end)) { + *secs = end_sector; + *hds = end_head + 1; + *cyls = capacity / ((end_head + 1) * end_sector); + return 0; + } + } + return -1; } - /*********************************************************************** * Function: * DC390_bios_param * * Description: * Return the disk geometry for the given SCSI device. + * Respect the partition table, otherwise try own heuristic + * + * Note: + * In contrary to other externally callable funcs (DC390_), we don't lock ***********************************************************************/ -int DC390_bios_param(Disk *disk, kdev_t devno, int geom[]) +int DC390_bios_param (Disk *disk, kdev_t devno, int geom[]) { int heads, sectors, cylinders; - PACB pACB; + PACB pACB = (PACB) disk->device->host->hostdata; + struct buffer_head *bh; + int ret_code = -1; + int size = disk->capacity; - pACB = (PACB) disk->device->host->hostdata; - heads = 64; - sectors = 32; - cylinders = disk->capacity / (heads * sectors); - - if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) ) + if ((bh = bread(MKDEV(MAJOR(devno), MINOR(devno)&~0xf), 0, 1024))) { - heads = 255; - sectors = 63; - cylinders = disk->capacity / (heads * sectors); + /* try to infer mapping from partition table */ + ret_code = partsize (bh, (unsigned long) size, (unsigned int *) geom + 2, + (unsigned int *) geom + 0, (unsigned int *) geom + 1); + brelse (bh); } + if (ret_code == -1) + { + heads = 64; + sectors = 32; + cylinders = size / (heads * sectors); + + if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) ) + { + heads = 255; + sectors = 63; + cylinders = size / (heads * sectors); + } - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + } return (0); } +#else +int DC390_bios_param (Disk *disk, kdev_t devno, int geom[]) +{ + return scsicam_bios_param (disk, devno, geom); +}; +#endif + + +void dc390_dumpinfo (PACB pACB, PDCB pDCB, PSRB pSRB) +{ + USHORT pstat; PDEVDECL1; + + if (pSRB) + { + printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08lx, 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: Register dump: SCSI block:\n"); + printk ("DC390: XferCnt Cmd Stat IntS IRQS FFIS Ctl1 Ctl2 Ctl3 Ctl4\n"); + printk ("DC390: %06x %02x %02x %02x", + DC390_read8(CtcReg_Low) + (DC390_read8(CtcReg_Mid) << 8) + (DC390_read8(CtcReg_High) << 16), + DC390_read8(ScsiCmd), DC390_read8(Scsi_Status), DC390_read8(Intern_State)); + printk (" %02x %02x %02x %02x %02x %02x\n", + DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1), + DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4)); + 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", + DC390_read8(DMA_Cmd), DC390_read32(DMA_XferCnt), DC390_read32(DMA_XferAddr), + DC390_read32(DMA_Wk_ByteCntr), DC390_read32(DMA_Wk_AddrCntr), + DC390_read8(DMA_Status), DC390_read32(DMA_ScsiBusCtrl)); + PDEVSET1; PCI_READ_CONFIG_WORD(PDEV, PCI_STATUS, &pstat); + printk ("DC390: Register dump: PCI Status: %04x\n", pstat); + printk ("DC390: Please report driver trouble to K.Garloff@ping.de\n"); +}; /*********************************************************************** @@ -703,35 +1078,28 @@ * Returns : 0 on success, -1 on failure. ***********************************************************************/ -int -DC390_abort (Scsi_Cmnd *cmd) +int DC390_abort (Scsi_Cmnd *cmd) { - ULONG flags; - PACB pACB; - PDCB pDCB, pdcb; + PDCB pDCB; PSRB pSRB, psrb; - USHORT count, i; + ULONG count, i; PSCSICMD pcmd, pcmd1; int status; + 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); - -#ifdef DC390_DEBUG0 - printk("DC390 : Abort Cmd."); -#endif - - save_flags(flags); - cli(); - - pACB = (PACB) cmd->host->hostdata; - pDCB = pACB->pLinkDCB; - pdcb = pDCB; - while( (pDCB->UnitSCSIID != cmd->target) || - (pDCB->UnitSCSILUN != cmd->lun) ) - { - pDCB = pDCB->pNextDCB; - if( pDCB == pdcb ) - goto NOT_RUN; - } + if( !pDCB ) goto NOT_RUN; if( pDCB->QIORBCnt ) { @@ -761,7 +1129,12 @@ } } } - + + /* Added 98/07/02 KG */ + pSRB = pDCB->pActiveSRB; + if (pSRB && pSRB->pcmd == cmd ) + goto ON_GOING; + pSRB = pDCB->pWaitingSRB; if( !pSRB ) goto ON_GOING; @@ -778,7 +1151,7 @@ while( psrb->pNextSRB->pcmd != cmd ) { psrb = psrb->pNextSRB; - if( !(psrb->pNextSRB) ) + if( !(psrb->pNextSRB) || psrb == pSRB) goto ON_GOING; } pSRB = psrb->pNextSRB; @@ -795,6 +1168,8 @@ ON_GOING: pSRB = pDCB->pGoingSRB; + pDCB->DCBFlag |= ABORT_DEV_; + /* Now for the hard part: The command is currently processed */ for( count = pDCB->GoingSRBCnt, i=0; ipcmd != cmd ) @@ -804,6 +1179,8 @@ if( (pACB->pActiveDCB == pDCB) && (pDCB->pActiveSRB == pSRB) ) { status = SCSI_ABORT_BUSY; + printk ("DC390: Abort current command (pid %li, SRB %p)\n", + cmd->pid, pSRB); goto ABO_X; } else @@ -819,20 +1196,51 @@ ABO_X: cmd->result = DID_ABORT << 16; + printk(KERN_INFO "DC390: Aborted pid %li with status %i\n", cmd->pid, status); + 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, RESET_ATN_CMD); + DC390_write8 (ScsiCmd, NOP_CMD); + //udelay (10000); + //DC390_read8 (INT_Status); + //DC390_write8 (ScsiCmd, EN_SEL_RESEL); + }; + sbac = DC390_read32 (DMA_ScsiBusCtrl); + if (sbac & SCSI_BUSY) + { /* clear BSY, SEL and ATN */ + printk (KERN_WARNING "DC390: Reset SCSI device: "); + //DC390_write32 (DMA_ScsiBusCtrl, (sbac | SCAM) & ~SCSI_LINES); + //udelay (250); + //sbac = DC390_read32 (DMA_ScsiBusCtrl); + //printk ("%08lx ", sbac); + //DC390_write32 (DMA_ScsiBusCtrl, sbac & ~(SCSI_LINES | SCAM)); + //udelay (100); + //sbac = DC390_read32 (DMA_ScsiBusCtrl); + //printk ("%08lx ", sbac); + DC390_write8 (ScsiCmd, RST_DEVICE_CMD); + udelay (250); + DC390_write8 (ScsiCmd, NOP_CMD); + sbac = DC390_read32 (DMA_ScsiBusCtrl); + printk ("%08lx\n", sbac); + }; + dc390_lastabortedpid = cmd->pid; + DC390_UNLOCK_ACB; + //do_DC390_Interrupt (pACB->IRQLevel, 0, 0); cmd->scsi_done(cmd); - restore_flags(flags); return( status ); } -static void -ResetDevParam( PACB pACB ) +static void dc390_ResetDevParam( PACB pACB ) { PDCB pDCB, pdcb; pDCB = pACB->pLinkDCB; - if( pDCB == NULL ) - return; + if (! pDCB) return; pdcb = pDCB; do { @@ -840,24 +1248,22 @@ pDCB->SyncPeriod = 0; pDCB->SyncOffset = 0; pDCB->CtrlR3 = FAST_CLK; - pDCB->CtrlR4 &= NEGATE_REQACKDATA; - pDCB->CtrlR4 |= EATER_25NS; + pDCB->CtrlR4 &= NEGATE_REQACKDATA | CTRL4_RESERVED | NEGATE_REQACK; + pDCB->CtrlR4 |= pACB->glitch_cfg; pDCB = pDCB->pNextDCB; } while( pdcb != pDCB ); } -static void -RecoverSRB( PACB pACB ) +static void dc390_RecoverSRB( PACB pACB ) { PDCB pDCB, pdcb; PSRB psrb, psrb2; - USHORT cnt, i; + ULONG cnt, i; pDCB = pACB->pLinkDCB; - if( pDCB == NULL ) - return; + if( !pDCB ) return; pdcb = pDCB; do { @@ -867,7 +1273,7 @@ { psrb2 = psrb; psrb = psrb->pNextSRB; -/* RewaitSRB( pDCB, psrb ); */ +/* dc390_RewaitSRB( pDCB, psrb ); */ if( pdcb->pWaitingSRB ) { psrb2->pNextSRB = pdcb->pWaitingSRB; @@ -884,8 +1290,7 @@ pdcb->pGoingSRB = NULL; pdcb->TagMask = 0; pdcb = pdcb->pNextDCB; - } - while( pdcb != pDCB ); + } while( pdcb != pDCB ); } @@ -901,77 +1306,80 @@ int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags) { - USHORT ioport; - unsigned long flags; - PACB pACB; - UCHAR bval; - USHORT i; - + UCHAR bval; + ULONG i; + DC390_AFLAGS + PACB pACB = (PACB) cmd->host->hostdata; -#ifdef DC390_DEBUG1 - printk("DC390: RESET,"); -#endif + printk(KERN_INFO "DC390: RESET ... "); - pACB = (PACB ) cmd->host->hostdata; - ioport = pACB->IOPortBase; - save_flags(flags); - cli(); - bval = inb(ioport+CtrlReg1); + DC390_LOCK_ACB; + bval = DC390_read8 (CtrlReg1); bval |= DIS_INT_ON_SCSI_RST; - outb(bval,ioport+CtrlReg1); /* disable interrupt */ - DC390_ResetSCSIBus( pACB ); - for( i=0; i<500; i++ ) - mdelay(1); - bval = inb(ioport+CtrlReg1); - bval &= ~DIS_INT_ON_SCSI_RST; - outb(bval,ioport+CtrlReg1); /* re-enable interrupt */ - - bval = DMA_IDLE_CMD; - outb(bval,ioport+DMA_Cmd); - bval = CLEAR_FIFO_CMD; - outb(bval,ioport+ScsiCmd); + DC390_write8 (CtrlReg1, bval); /* disable interrupt */ - ResetDevParam( pACB ); - DoingSRB_Done( pACB ); + dc390_ResetSCSIBus( pACB ); + /* Unlock ? */ + for( i=0; i<600; i++ ) + udelay(1000); + + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + DC390_read8 (INT_Status); /* Reset Pending INT */ + + dc390_ResetDevParam( pACB ); + dc390_DoingSRB_Done( pACB ); + /* dc390_RecoverSRB (pACB); */ pACB->pActiveDCB = NULL; pACB->ACBFlag = 0; - DoWaitingSRB( pACB ); + bval = DC390_read8 (CtrlReg1); + bval &= ~DIS_INT_ON_SCSI_RST; + DC390_write8 (CtrlReg1, bval); /* re-enable interrupt */ - restore_flags(flags); -#ifdef DC390_DEBUG1 - printk("DC390: RESET1,"); -#endif + dc390_DoWaitingSRB( pACB ); + + DC390_UNLOCK_ACB; + printk("done\n"); return( SCSI_RESET_SUCCESS ); } - #include "scsiiom.c" /*********************************************************************** - * Function : static void DC390_initDCB + * Function : static void dc390_initDCB * * Purpose : initialize the internal structures for a given DCB * * Inputs : cmd - pointer to this scsi cmd request block structure * ***********************************************************************/ -void DC390_initDCB( PACB pACB, PDCB pDCB, PSCSICMD cmd ) +void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd ) { PEEprom prom; - UCHAR bval; - USHORT index; + UCHAR index; + PDCB pDCB; - if( pACB->DeviceCnt == 0 ) + 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);) + + *ppDCB = pDCB; + if (!pDCB) return; + if( pACB->DCBCnt == 0 ) { pACB->pLinkDCB = pDCB; pACB->pDCBRunRobin = pDCB; - pDCB->pNextDCB = pDCB; - pPrevDCB = pDCB; } else - pPrevDCB->pNextDCB = pDCB; + { + pACB->pLastDCB->pNextDCB = pDCB; + }; + + pACB->DCBCnt++; + + pACB->pLastDCB = pDCB; + pDCB->pNextDCB = pACB->pLinkDCB; pDCB->pDCBACB = pACB; pDCB->QIORBCnt = 0; @@ -983,122 +1391,143 @@ pDCB->pActiveSRB = NULL; pDCB->TagMask = 0; pDCB->MaxCommand = 1; - pDCB->AdaptIndex = pACB->AdapterIndex; index = pACB->AdapterIndex; pDCB->DCBFlag = 0; - prom = (PEEprom) &eepromBuf[index][cmd->target << 2]; + prom = (PEEprom) &dc390_eepromBuf[index][cmd->target << 2]; pDCB->DevMode = prom->EE_MODE1; - pDCB->AdpMode = eepromBuf[index][EE_MODE2]; - - if( pDCB->DevMode & EN_DISCONNECT_ ) - bval = 0xC0; - else - bval = 0x80; - bval |= cmd->lun; - pDCB->IdentifyMsg = bval; pDCB->SyncMode = 0; - if( pDCB->DevMode & SYNC_NEGO_ ) - { - if( !(cmd->lun) || CurrSyncOffset ) - pDCB->SyncMode = SYNC_ENABLE; - } + dc390_updateDCB(pACB, pDCB); pDCB->SyncPeriod = 0; pDCB->SyncOffset = 0; - pDCB->NegoPeriod = (clock_period1[prom->EE_SPEED] * 25) >> 2; - - pDCB->CtrlR1 = pACB->AdaptSCSIID; - if( pDCB->DevMode & PARITY_CHK_ ) - pDCB->CtrlR1 |= PARITY_ERR_REPO; + pDCB->NegoPeriod = (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2; pDCB->CtrlR3 = FAST_CLK; - pDCB->CtrlR4 = EATER_25NS; - if( pDCB->AdpMode & ACTIVE_NEGATION) - pDCB->CtrlR4 |= NEGATE_REQACKDATA; + pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED; + if( dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) + pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK; } +/*********************************************************************** + * Function : static void dc390_updateDCB + * + * Purpose : Set the configuration dependent DCB parameters + * + ***********************************************************************/ +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 &= ~(SYNC_NEGO_DONE | SYNC_ENABLE); + pDCB->SyncOffset &= ~0x0f; + }; + + 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; +}; + + +/*********************************************************************** + * Function : static void dc390_updateDCBs + * + * Purpose : Set the configuration dependent DCB params for all DCBs + * + ***********************************************************************/ +static void dc390_updateDCBs (PACB pACB) +{ + int i; + PDCB pDCB = pACB->pLinkDCB; + for (i = 0; i < pACB->DeviceCnt; i++) + { + dc390_updateDCB (pACB, pDCB); + pDCB = pDCB->pNextDCB; + }; +}; + /*********************************************************************** - * Function : static void DC390_initSRB + * Function : static void dc390_initSRB * * Purpose : initialize the internal structures for a given SRB * * Inputs : psrb - pointer to this scsi request block structure * ***********************************************************************/ -void DC390_initSRB( PSRB psrb ) +static void __inline__ dc390_initSRB( PSRB psrb ) { -#ifdef DC390_DEBUG0 - printk("DC390 init: %08lx %08lx,",(ULONG)psrb,(ULONG)virt_to_bus(psrb)); -#endif - psrb->PhysSRB = virt_to_bus( psrb ); + /* psrb->PhysSRB = virt_to_phys( psrb ); */ } -void DC390_linkSRB( PACB pACB ) +void dc390_linkSRB( PACB pACB ) { - USHORT count, i; - PSRB psrb; + ULONG count, i; count = pACB->SRBCount; - for( i=0; i< count; i++) { if( i != count - 1) pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1]; else pACB->SRB_array[i].pNextSRB = NULL; - psrb = (PSRB) &pACB->SRB_array[i]; - DC390_initSRB( psrb ); + dc390_initSRB( &pACB->SRB_array[i] ); } } /*********************************************************************** - * Function : static void DC390_initACB + * Function : static void dc390_initACB * * Purpose : initialize the internal structures for a given SCSI host * * Inputs : psh - pointer to this host adapter's structure * ***********************************************************************/ -__initfunc(void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )) +void __init dc390_initACB (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) { PACB pACB; - USHORT i; + UCHAR i; + DC390_AFLAGS psh->can_queue = MAX_CMD_QUEUE; psh->cmd_per_lun = MAX_CMD_PER_LUN; - psh->this_id = (int) eepromBuf[index][EE_ADAPT_SCSI_ID]; + psh->this_id = (int) dc390_eepromBuf[index][EE_ADAPT_SCSI_ID]; psh->io_port = io_port; psh->n_io_port = 0x80; psh->irq = Irq; pACB = (PACB) psh->hostdata; + DC390_LOCK_INIT; + DC390_LOCK_ACB; + pACB->pScsiHost = psh; + pACB->IOPortBase = (USHORT) io_port; + pACB->IRQLevel = Irq; + + DEBUG0(printk (KERN_DEBUG "DC390: Adapter index %i, ID %i, IO 0x%08x, IRQ 0x%02x\n", \ + index, psh->this_id, (int)io_port, Irq);) + psh->max_id = 8; -#ifdef CONFIG_SCSI_MULTI_LUN - if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) - psh->max_lun = 8; - else -#endif - psh->max_lun = 1; - pACB->max_id = 7; - if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] ) - pACB->max_id--; -#ifdef CONFIG_SCSI_MULTI_LUN - if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) - pACB->max_lun = 7; - else -#endif - pACB->max_lun = 0; + if( psh->max_id - 1 == dc390_eepromBuf[index][EE_ADAPT_SCSI_ID] ) + psh->max_id--; + psh->max_lun = 1; + if( dc390_eepromBuf[index][EE_MODE2] & LUN_CHECK ) + psh->max_lun = 8; - pACB->pScsiHost = psh; - pACB->IOPortBase = (USHORT) io_port; pACB->pLinkDCB = NULL; pACB->pDCBRunRobin = NULL; pACB->pActiveDCB = NULL; @@ -1106,42 +1535,39 @@ pACB->SRBCount = MAX_SRB_CNT; pACB->AdapterIndex = index; pACB->status = 0; - pACB->AdaptSCSIID = eepromBuf[index][EE_ADAPT_SCSI_ID]; - pACB->HostID_Bit = (1 << pACB->AdaptSCSIID); - pACB->AdaptSCSILUN = 0; + psh->this_id = dc390_eepromBuf[index][EE_ADAPT_SCSI_ID]; pACB->DeviceCnt = 0; - pACB->IRQLevel = Irq; - pACB->TagMaxNum = eepromBuf[index][EE_TAG_CMD_NUM] << 2; + pACB->DCBCnt = 0; + pACB->TagMaxNum = 2 << dc390_eepromBuf[index][EE_TAG_CMD_NUM]; pACB->ACBFlag = 0; pACB->scan_devices = 1; - pACB->Gmode2 = eepromBuf[index][EE_MODE2]; - if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) - pACB->LUNchk = 1; - pACB->pDCB_free = &pACB->DCB_array[0]; - DC390_linkSRB( pACB ); + pACB->Gmode2 = dc390_eepromBuf[index][EE_MODE2]; + dc390_linkSRB( pACB ); pACB->pTmpSRB = &pACB->TmpSRB; - DC390_initSRB( pACB->pTmpSRB ); + dc390_initSRB( pACB->pTmpSRB ); for(i=0; iDCBmap[i] = 0; + pACB->sel_timeout = SEL_TIMEOUT; + pACB->glitch_cfg = EATER_25NS; + pACB->Cmds = pACB->CmdInQ = pACB->CmdOutOfSRB = pACB->SelLost = 0; } /*********************************************************************** - * Function : static int DC390_initAdapter + * Function : static int dc390_initAdapter * * Purpose : initialize the SCSI chip ctrl registers * * Inputs : psh - pointer to this host adapter's structure * ***********************************************************************/ -__initfunc(int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index)) +int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index) { - USHORT ioport; - UCHAR bval; PACB pACB, pacb; - USHORT used_irq = 0; + UCHAR used_irq = 0, dstate; + int i; - pacb = pACB_start; + pacb = dc390_pACB_start; if( pacb != NULL ) { for ( ; (pacb != (PACB) -1) ; ) @@ -1158,49 +1584,54 @@ if( !used_irq ) { - if( request_irq(Irq, do_DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL)) + if( (i = request_irq(Irq, do_DC390_Interrupt, DC390_IRQ, "tmscsim", NULL) )) + { + printk(KERN_ERR "DC390: register IRQ error!\n"); + return( -1 ); + } + } + + if (check_region (io_port, psh->n_io_port)) { - printk("DC390: register IRQ error!\n"); + printk(KERN_ERR "DC390: register IO ports error!\n"); return( -1 ); } - } - - request_region(io_port,psh->n_io_port,"tmscsim"); - - ioport = (USHORT) io_port; - + else + request_region (io_port, psh->n_io_port, "tmscsim"); + pACB = (PACB) psh->hostdata; - bval = SEL_TIMEOUT; /* 250ms selection timeout */ - outb(bval,ioport+Scsi_TimeOut); - - bval = CLK_FREQ_40MHZ; /* Conversion factor = 0 , 40MHz clock */ - outb(bval,ioport+Clk_Factor); - - bval = NOP_CMD; /* NOP cmd - clear command register */ - outb(bval,ioport+ScsiCmd); - - bval = EN_FEATURE+EN_SCSI2_CMD; /* Enable Feature and SCSI-2 */ - outb(bval,ioport+CtrlReg2); - - bval = FAST_CLK; /* fast clock */ - outb(bval,ioport+CtrlReg3); + /* pACB->IOPortBase = (USHORT) io_port; */ - bval = EATER_25NS; - if( eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION ) - bval |= NEGATE_REQACKDATA; - outb(bval,ioport+CtrlReg4); + DC390_write8_ (CtrlReg1, DIS_INT_ON_SCSI_RST | psh->this_id, io_port); /* Disable SCSI bus reset interrupt */ - bval = DIS_INT_ON_SCSI_RST; /* Disable SCSI bus reset interrupt */ - outb(bval,ioport+CtrlReg1); + if (pACB->Gmode2 & RST_SCSI_BUS) + { + dc390_ResetSCSIBus( pACB ); + /* Unlock before ? */ + for( i=0; i<600; i++ ) + udelay(1000); + }; + pACB->ACBFlag = 0; + + DC390_write8 (Scsi_TimeOut, SEL_TIMEOUT); /* 250ms selection timeout */ + DC390_write8 (Clk_Factor, CLK_FREQ_40MHZ); /* Conversion factor = 0 , 40MHz clock */ + DC390_write8 (ScsiCmd, NOP_CMD); /* NOP cmd - clear command register */ + DC390_write8 (CtrlReg2, EN_FEATURE+EN_SCSI2_CMD); /* Enable Feature and SCSI-2 */ + 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 (DMA_Cmd, DMA_IDLE_CMD); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); + DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT); + dstate = DC390_read8 (DMA_Status); + DC390_write8 (DMA_Status, dstate); /* clear */ return(0); } -void -DC390_EnDisableCE( UCHAR mode, struct pci_dev *pdev, PUCHAR regval ) +static void __init dc390_EnDisableCE( UCHAR mode, PDEVDECL, PUCHAR regval ) { - UCHAR bval; bval = 0; @@ -1208,15 +1639,68 @@ *regval = 0xc0; else *regval = 0x80; - pci_write_config_byte(pdev, *regval, bval); + PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval); if(mode == DISABLE_CE) - pci_write_config_byte(pdev, *regval, bval); + PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval); udelay(160); } +#ifndef CONFIG_SCSI_DC390T_NOGENSUPP +static void __init dc390_EEpromDefaults (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 */ + + /* 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 */ + }; + dc390_adapname = "AM53C974"; +} + +static void __init dc390_checkparams (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 */ + { + tmscsim[0] = 7; tmscsim[1] = 4; + tmscsim[2] = 9; tmscsim[3] = 15; + tmscsim[4] = 2; + printk (KERN_INFO "DC390: Using safe settings.\n"); + } + else + { + /* 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; + }; +}; +/* Override defaults on cmdline: + * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped) + */ +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) + printk (KERN_NOTICE "DC390: ignore extra params!\n"); + /* dc390_checkparams (); */ +}; +#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */ + -void -DC390_EEpromOutDI( struct pci_dev *pdev, PUCHAR regval, USHORT Carry ) +static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry ) { UCHAR bval; @@ -1225,28 +1709,27 @@ { bval = 0x40; *regval = 0x80; - pci_write_config_byte(pdev, *regval, bval); + PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval); } udelay(160); bval |= 0x80; - pci_write_config_byte(pdev, *regval, bval); + PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval); udelay(160); bval = 0; - pci_write_config_byte(pdev, *regval, bval); + PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval); udelay(160); } -UCHAR -DC390_EEpromInDO( struct pci_dev *pdev ) +static UCHAR __init dc390_EEpromInDO( PDEVDECL ) { UCHAR bval; - pci_write_config_byte(pdev, 0x80, 0x80); + PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x80); udelay(160); - pci_write_config_byte(pdev, 0x80, 0x40); + PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x40); udelay(160); - pci_read_config_byte(pdev, 0x00, &bval); + PCI_READ_CONFIG_BYTE(PDEV, 0x00, &bval); if(bval == 0x22) return(1); else @@ -1254,8 +1737,7 @@ } -USHORT -EEpromGetData1( struct pci_dev *pdev ) +static USHORT __init dc390_EEpromGetData1( PDEVDECL ) { UCHAR i; UCHAR carryFlag; @@ -1265,67 +1747,59 @@ for(i=0; i<16; i++) { wval <<= 1; - carryFlag = DC390_EEpromInDO(pdev); + carryFlag = dc390_EEpromInDO(PDEV); wval |= carryFlag; } return(wval); } -void -DC390_Prepare( struct pci_dev *pdev, PUCHAR regval, UCHAR EEpromCmd ) +static void __init dc390_Prepare( PDEVDECL, PUCHAR regval, UCHAR EEpromCmd ) { UCHAR i,j; - USHORT carryFlag; + UCHAR carryFlag; carryFlag = 1; j = 0x80; for(i=0; i<9; i++) { - DC390_EEpromOutDI(pdev,regval,carryFlag); + dc390_EEpromOutDI(PDEV,regval,carryFlag); carryFlag = (EEpromCmd & j) ? 1 : 0; j >>= 1; } } -void -DC390_ReadEEprom( struct pci_dev *pdev, int index ) +static void __init dc390_ReadEEprom( PDEVDECL, PUSHORT ptr) { UCHAR regval,cmd; - PUSHORT ptr; - USHORT i; + UCHAR i; - ptr = (PUSHORT) &eepromBuf[index][0]; cmd = EEPROM_READ; for(i=0; i<0x40; i++) { - DC390_EnDisableCE(ENABLE_CE, pdev, ®val); - DC390_Prepare(pdev, ®val, cmd); - *ptr = EEpromGetData1(pdev); - ptr++; - cmd++; - DC390_EnDisableCE(DISABLE_CE, pdev, ®val); + dc390_EnDisableCE(ENABLE_CE, PDEV, ®val); + dc390_Prepare(PDEV, ®val, cmd++); + *ptr++ = dc390_EEpromGetData1(PDEV); + dc390_EnDisableCE(DISABLE_CE, PDEV, ®val); } } -USHORT -DC390_CheckEEpromCheckSum( struct pci_dev *pdev, int index ) +static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index ) { - USHORT wval, rc, *ptr; UCHAR i; + char EEbuf[128]; + USHORT wval, *ptr = (PUSHORT)EEbuf; - DC390_ReadEEprom( pdev, index ); + dc390_ReadEEprom( PDEV, ptr ); + 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); wval = 0; - ptr = (PUSHORT) &eepromBuf[index][0]; - for(i=0; i<128 ;i+=2, ptr++) + for(i=0; i<0x40; i++, ptr++) wval += *ptr; - if( wval == 0x1234 ) - rc = 0; - else - rc = -1; - return( rc ); + return (wval == 0x1234 ? 0 : 1); } @@ -1338,71 +1812,95 @@ * * Preconditions : when this function is called, the chip_type * field of the pACB structure MUST have been set. + * + * Note: written in capitals, because the locking is only done here, + * not in DC390_detect, called from outside ***********************************************************************/ -__initfunc(static int -DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, struct pci_dev *pdev, int index)) +static int __init DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, PDEVDECL, int index) { PSH psh; PACB pACB; - - if( !DC390_CheckEEpromCheckSum( pdev, index ) ) + DC390_AFLAGS + + if (dc390_CheckEEpromCheckSum (PDEV, index)) { - psh = scsi_register( psht, sizeof(DC390_ACB) ); - if( !psh ) - return( -1 ); - if( !pSH_start ) - { - pSH_start = psh; - pSH_current = psh; - } - else - { - pSH_current->next = psh; - pSH_current = psh; - } +#ifdef CONFIG_SCSI_DC390T_NOGENSUPP + 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]]; + 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); +#endif + }; + + psh = scsi_register( psht, sizeof(DC390_ACB) ); + if( !psh ) return( -1 ); + + pACB = (PACB) psh->hostdata; + DC390_LOCK_INIT; + DC390_LOCK_ACB; -#ifdef DC390_DEBUG0 - printk("DC390: pSH = %8x,", (UINT) psh); - printk("DC390: Index %02i,", index); +#if 0 + if( !dc390_pSH_start ) + { + dc390_pSH_start = psh; + dc390_pSH_current = psh; + } + else + { + dc390_pSH_current->next = psh; + dc390_pSH_current = psh; + } #endif - DC390_initACB( psh, io_port, Irq, index ); - if( !DC390_initAdapter( psh, io_port, Irq, index ) ) - { - pACB = (PACB) psh->hostdata; - if( !pACB_start ) - { - pACB_start = pACB; - pACB_current = pACB; - pACB->pNextACB = (PACB) -1; - } - else - { - pACB_current->pNextACB = pACB; - pACB_current = pACB; - pACB->pNextACB = (PACB) -1; - } + DEBUG0(printk("DC390: pSH = %8x,", (UINT) psh);) + DEBUG0(printk("DC390: Index %02i,", index);) -#ifdef DC390_DEBUG0 - printk("DC390: pACB = %8x, pDCB_array = %8x, pSRB_array = %8x\n", - (UINT) pACB, (UINT) pACB->DCB_array, (UINT) pACB->SRB_array); - printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n", - sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) ); -#endif + dc390_initACB( psh, io_port, Irq, index ); + PDEVSET; + + DC390_read8_ (INT_Status, io_port); /* Reset Pending INT */ + if( !dc390_initAdapter( psh, io_port, Irq, index ) ) + { + pACB = (PACB) psh->hostdata; + if( !dc390_pACB_start ) + { + dc390_pACB_start = pACB; + dc390_pACB_current = pACB; + pACB->pNextACB = (PACB) -1; } else { - pSH_start = NULL; - scsi_unregister( psh ); - return( -1 ); + dc390_pACB_current->pNextACB = pACB; + dc390_pACB_current = pACB; + pACB->pNextACB = (PACB) -1; } - return( 0 ); + + DEBUG0(printk("DC390: pACB = %8x, pDCBmap = %8x, pSRB_array = %8x\n",\ + (UINT) pACB, (UINT) pACB->DCBmap, (UINT) pACB->SRB_array);) + DEBUG0(printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",\ + sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );) + + DC390_read8_ (INT_Status, io_port); /* Reset Pending INT */ + + DC390_UNLOCK_ACB; + return (0); } else { - printk("DC390_init: EEPROM reading error!\n"); + //dc390_pSH_start = NULL; + scsi_unregister( psh ); + DC390_UNLOCK_ACB; return( -1 ); } } @@ -1421,54 +1919,437 @@ * ***********************************************************************/ -__initfunc(int -DC390_detect(Scsi_Host_Template *psht)) +#ifndef NEW_PCI +/* Acc. to PCI 2.1 spec it's up to the driver to enable Bus mastering: + * We use pci_set_master () for 2.1.x and this func for 2.0.x: */ +static void __init dc390_set_master (PDEVDECL) +{ + USHORT cmd; + UCHAR lat; + + PCI_READ_CONFIG_WORD (PDEV, PCI_COMMAND, &cmd); + + if (! (cmd & PCI_COMMAND_MASTER)) { + printk("PCI: Enabling bus mastering for device %02x:%02x\n", + PCI_BUS_DEV); + cmd |= PCI_COMMAND_MASTER; + PCI_WRITE_CONFIG_WORD(PDEV, PCI_COMMAND, cmd); + } + PCI_READ_CONFIG_BYTE (PDEV, PCI_LATENCY_TIMER, &lat); + if (lat < 16 /* || lat == 255 */) { + printk("PCI: Setting latency timer of device %02x:%02x from %i to 64\n", + PCI_BUS_DEV, lat); + PCI_WRITE_CONFIG_BYTE(PDEV, PCI_LATENCY_TIMER, 64); + } + +}; +#endif /* ! NEW_PCI */ + +static void __init dc390_set_pci_cfg (PDEVDECL) +{ + USHORT cmd; + PCI_READ_CONFIG_WORD (PDEV, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_IO; + PCI_WRITE_CONFIG_WORD (PDEV, PCI_COMMAND, cmd); + PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY)); +}; + + +int __init DC390_detect (Scsi_Host_Template *psht) { - struct pci_dev *pdev = NULL; - UINT irq; + PDEVDECL0; + UCHAR irq; UINT io_port; - USHORT adaptCnt = 0; /* Number of boards detected */ + UCHAR adaptCnt = 0; /* Number of boards detected */ + DC390_IFLAGS DC390_DFLAGS - psht->proc_dir = &proc_scsi_tmscsim; + DC390_LOCK_DRV; + //dc390_pSHT_start = psht; + dc390_pACB_start = NULL; - InitialTime = 1; - pSHT_start = psht; - pACB_start = NULL; - - if ( pci_present() ) - while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974, pdev))) + if ( PCI_PRESENT ) + while (PCI_FIND_DEVICE (PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974)) { - io_port = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; - irq = pdev->irq; -#ifdef DC390_DEBUG0 - printk("DC390: IO_PORT=%4x,IRQ=%x,\n",(UINT) io_port, irq); -#endif - if( !DC390_init(psht, io_port, irq, pdev, adaptCnt)) + DC390_LOCK_IO; /* Remove this when going to new eh */ + PCI_GET_IO_AND_IRQ; + DEBUG0(printk(KERN_DEBUG "DC390(%i): IO_PORT=%04x,IRQ=%x\n", adaptCnt, (UINT) io_port, irq);) + + if( !DC390_init(psht, io_port, irq, PDEV, adaptCnt)) + { + PCI_SET_MASTER; + dc390_set_pci_cfg (PDEV); adaptCnt++; + }; + DC390_UNLOCK_IO; /* Remove when going to new eh */ } - - InitialTime = 0; - adapterCnt = adaptCnt; + else + printk (KERN_ERR "DC390: No PCI BIOS found!\n"); + + if (adaptCnt) + psht->proc_dir = &DC390_proc_scsi_tmscsim; + + printk(KERN_INFO "DC390: %i adapters found\n", adaptCnt); + dc390_adapterCnt = adaptCnt; + DC390_UNLOCK_DRV; return( adaptCnt ); } +static void dc390_inquiry_done (Scsi_Cmnd* cmd) +{ + printk (KERN_INFO "DC390: INQUIRY (ID %02x LUN %02x) returned %08x\n", + cmd->target, cmd->lun, cmd->result); + if (cmd->result) + { + PACB pACB = (PACB)cmd->host->hostdata; + PDCB pDCB = dc390_findDCB (pACB, cmd); + printk ("DC390: Unsetting DsCn, Sync and TagQ!\n"); + if (pDCB) + { + pDCB->DevMode &= ~(SYNC_NEGO_ | TAG_QUEUEING_ | EN_DISCONNECT_ ); + dc390_updateDCB (pACB, pDCB); + }; + }; + kfree (cmd->buffer); + kfree (cmd); +}; + +void dc390_inquiry (PACB pACB, PDCB pDCB) +{ + char* buffer; + Scsi_Cmnd* cmd; + buffer = kmalloc (256, GFP_ATOMIC); + cmd = kmalloc (sizeof (Scsi_Cmnd), GFP_ATOMIC); + + memset (buffer, 0, 256); + memset (cmd, 0, sizeof(Scsi_Cmnd)); + cmd->cmnd[0] = INQUIRY; + cmd->cmnd[1] = (pDCB->UnitSCSILUN << 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->serial_number = 1; + cmd->bufflen = 128; + cmd->buffer = buffer; + cmd->request_bufflen = 128; + cmd->request_buffer = &buffer[128]; + cmd->done = dc390_inquiry_done; + cmd->scsi_done = dc390_inquiry_done; + cmd->timeout_per_command = HZ; + + cmd->request.rq_status = RQ_SCSI_BUSY; + + printk (KERN_INFO "DC390: Queue INQUIRY command to dev ID %02x LUN %02x\n", + pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + DC390_queue_command (cmd, dc390_inquiry_done); +}; + /******************************************************************** - * Function: tmscsim_set_info() - * - * Purpose: Set adapter info (!) + * Function: dc390_set_info() * - * Not yet implemented + * Purpose: Change adapter config * + * Strings are parsed similar to the output of tmscsim_proc_info () + * '-' means no change *******************************************************************/ -int tmscsim_set_info(char *buffer, int length, struct Scsi_Host *shpnt) +static int dc390_scanf (char** p1, char** p2, int* var) { - return(-ENOSYS); /* Currently this is a no-op */ -} + *p2 = *p1; + *var = simple_strtoul (*p2, p1, 10); + if (*p2 == *p1) return -1; + *p1 = strtok (0, " \t\n:=,;."); + return 0; +}; + +#define SCANF(p1, p2, var, min, max) \ +if (dc390_scanf (&p1, &p2, &var)) goto einv; \ +else if (varmax) goto einv2 + +static int dc390_yesno (char** p, char* var, char bmask) +{ + switch (**p) + { + case 'Y': *var |= bmask; break; + case 'N': *var &= ~bmask; break; + case '-': break; + default: return -1; + } + *p = strtok (0, " \t\n:=,;"); + return 0; +}; + +#define YESNO(p, var, bmask) \ +if (dc390_yesno (&p, &var, bmask)) goto einv; \ +else dc390_updateDCB (pACB, pDCB); \ +if (!p) goto ok + +static int dc390_search (char **p1, char **p2, char *var, char* txt, int max, int scale, char* ign) +{ + int dum; + if (! memcmp (*p1, txt, strlen(txt))) + { + *p2 = strtok (0, " \t\n:=,;"); + if (!*p2) return -1; + dum = simple_strtoul (*p2, p1, 10); + if (*p2 == *p1) return -1; + if (dum >= 0 && dum <= max) + { *var = (dum * 100) / scale; } + else return -2; + *p1 = strtok (0, " \t\n:=,;"); + if (*ign && *p1 && strlen(*p1) >= strlen(ign) && + !(memcmp (*p1, ign, strlen(ign)))) + *p1 = strtok (0, " \t\n:=,;"); + + } + return 0; +}; + +#define SEARCH(p1, p2, var, txt, max) \ +if (dc390_search (&p1, &p2, (PUCHAR)(&var), txt, max, 100, "")) goto einv2; \ +else if (!p1) goto ok2 + +#define SEARCH2(p1, p2, var, txt, max, scale) \ +if (dc390_search (&p1, &p2, &var, txt, max, scale, "")) goto einv2; \ +else if (!p1) goto ok2 + +#define SEARCH3(p1, p2, var, txt, max, scale, ign) \ +if (dc390_search (&p1, &p2, &var, txt, max, scale, ign)) goto einv2; \ +else if (!p1) goto ok2 + + +#ifdef DC390_PARSEDEBUG +static char _prstr[256]; +char* prstr (char* p, char* e) +{ + char* c = _prstr; + while (p < e) + if (*p == 0) { *c++ = ':'; p++; } + else if (*p == 10) { *c++ = '\\'; *c++ = 'n'; p++; } + else *c++ = *p++; + *c = 0; + return _prstr; +}; +#endif + +int dc390_set_info (char *buffer, int length, PACB pACB) +{ + char *pos = buffer, *p0 = buffer; + char needs_inquiry = 0; + int dum = 0; + char dev; + PDCB pDCB = pACB->pLinkDCB; + DC390_IFLAGS + DC390_AFLAGS + pos[length] = 0; + + DC390_LOCK_IO; + DC390_LOCK_ACB; + /* UPPERCASE */ + /* Don't use kernel toupper, because of 2.0.x bug: ctmp unexported */ + while (*pos) + { if (*pos >='a' && *pos <= 'z') *pos = *pos + 'A' - 'a'; pos++; }; + + /* We should protect __strtok ! */ + /* spin_lock (strtok_lock); */ + + /* Remove WS */ + pos = strtok (buffer, " \t:\n=,;"); + if (!pos) goto ok; + + next: + if (!memcmp (pos, "RESET", 5)) goto reset; + else if (!memcmp (pos, "INQUIRY", 7)) goto inquiry; + else if (!memcmp (pos, "REMOVE", 6)) goto remove; + + if (isdigit (*pos)) + { + /* Device config line */ + int dev, id, lun; char* pdec; + char olddevmode; + + SCANF (pos, p0, dev, 0, pACB->DCBCnt-1); + if (pos) { SCANF (pos, p0, id, 0, 7); } else goto einv; + if (pos) { SCANF (pos, p0, lun, 0, 7); } else goto einv; + if (!pos) goto einv; + + PARSEDEBUG(printk (KERN_INFO "DC390: config line %i %i %i:\"%s\"\n", dev, id, lun, prstr (pos, &buffer[length]));) + pDCB = pACB->pLinkDCB; + for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; + /* Sanity Check */ + if (pDCB->UnitSCSIID != id || pDCB->UnitSCSILUN != lun) + { + printk (KERN_ERR "DC390: no such device: Idx=%02i ID=%02i LUN=%02i\n", + dev, id, lun); + goto einv2; + }; + + olddevmode = pDCB->DevMode; + YESNO (pos, pDCB->DevMode, PARITY_CHK_); + needs_inquiry++; + YESNO (pos, pDCB->DevMode, SYNC_NEGO_); + if ((olddevmode & SYNC_NEGO_) == (pDCB->DevMode & SYNC_NEGO_)) needs_inquiry--; + needs_inquiry++; + YESNO (pos, pDCB->DevMode, EN_DISCONNECT_); + if ((olddevmode & EN_DISCONNECT_) == (pDCB->DevMode & EN_DISCONNECT_)) needs_inquiry--; + YESNO (pos, pDCB->DevMode, SEND_START_); + 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; + + olddevmode = pDCB->NegoPeriod; + /* Look for decimal point (Speed) */ + pdec = pos; + while (pdec++ < &buffer[length]) if (*pdec == '.') break; + /* NegoPeriod */ + if (*pos != '-') + { + SCANF (pos, p0, dum, 76, 800); + pDCB->NegoPeriod = dum >> 2; + if (pDCB->NegoPeriod != olddevmode) needs_inquiry++; + if (!pos) goto ok; + if (memcmp (pos, "NS", 2) == 0) pos = strtok (0, " \t\n:=,;."); + } + else pos = strtok (0, " \t\n:=,;."); + if (!pos) goto ok; + + /* Speed: NegoPeriod */ + if (*pos != '-') + { + SCANF (pos, p0, dum, 1, 13); + pDCB->NegoPeriod = (1000/dum) >> 2; + if (pDCB->NegoPeriod != olddevmode && !pos) needs_inquiry++; + if (!pos) goto ok; + /* decimal */ + if (pos-1 == pdec) + { + int dumold = dum; + dum = simple_strtoul (pos, &p0, 10) * 10; + for (; p0-pos > 1; p0--) dum /= 10; + pDCB->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:=,;"); + } + else pos = strtok (0, " \t\n:=,;"); + /* dc390_updateDCB (pACB, pDCB); */ + if (!pos) goto ok; + + olddevmode = pDCB->SyncOffset; + /* SyncOffs */ + if (*pos != '-') + { + SCANF (pos, p0, dum, 0, 0x0f); + pDCB->SyncOffset = dum; + if (pDCB->SyncOffset > olddevmode) needs_inquiry++; + } + else pos = strtok (0, " \t\n:=,;"); + dc390_updateDCB (pACB, pDCB); + } + else + { + char* p1 = pos; UCHAR dum; + 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, 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"); + 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_updateDCBs (pACB); + } + if (pos) goto next; + + ok: + /* spin_unlock (strtok_lock); */ + DC390_UNLOCK_ACB; + if (needs_inquiry) + { dc390_updateDCB (pACB, pDCB); dc390_inquiry (pACB, pDCB); }; + DC390_UNLOCK_IO; + return (length); + + einv2: + pos = p0; + einv: + /* spin_unlock (strtok_lock); */ + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + printk (KERN_WARNING "DC390: parse error near \"%s\"\n", (pos? pos: "NULL")); + return (-EINVAL); + + reset: + { + Scsi_Cmnd cmd; cmd.host = pACB->pScsiHost; + printk (KERN_WARNING "DC390: Driver reset requested!\n"); + DC390_UNLOCK_ACB; + DC390_reset (&cmd, 0); + DC390_UNLOCK_IO; + }; + return (length); + + inquiry: + { + pos = strtok (0, " \t\n.:;="); if (!pos) goto einv; + dev = simple_strtoul (pos, &p0, 10); + if (dev >= pACB->DCBCnt) goto einv_dev; + for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; + printk (KERN_NOTICE " DC390: Issue INQUIRY command to Dev(Idx) %i SCSI ID %i LUN %i\n", + dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + DC390_UNLOCK_ACB; + dc390_inquiry (pACB, pDCB); + DC390_UNLOCK_IO; + }; + return (length); + + remove: + { + pos = strtok (0, " \t\n.:;="); if (!pos) goto einv; + dev = simple_strtoul (pos, &p0, 10); + if (dev >= pACB->DCBCnt) goto einv_dev; + for (dum = 0; dum < dev; dum++) pDCB = pDCB->pNextDCB; + printk (KERN_NOTICE " DC390: Remove DCB for Dev(Idx) %i SCSI ID %i LUN %i\n", + dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + dc390_remove_dev (pACB, pDCB); + DC390_UNLOCK_ACB; + 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); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + return (-EINVAL); + + +} + +#undef SEARCH +#undef YESNO +#undef SCANF /******************************************************************** - * Function: tmscsim_proc_info(char* buffer, char **start, + * Function: DC390_proc_info(char* buffer, char **start, * off_t offset, int length, int hostno, int inout) * * Purpose: return SCSI Adapter/Device Info @@ -1491,79 +2372,86 @@ #undef SPRINTF #define SPRINTF(args...) pos += sprintf(pos, ## args) -#define YESNO(YN)\ -if (YN) SPRINTF(" Yes ");\ -else SPRINTF(" No ") +#define YESNO(YN) \ + if (YN) SPRINTF(" Yes "); \ + else SPRINTF(" No ") + -int tmscsim_proc_info(char *buffer, char **start, - off_t offset, int length, int hostno, int inout) +int DC390_proc_info (char *buffer, char **start, + off_t offset, int length, int hostno, int inout) { int dev, spd, spd1; char *pos = buffer; PSH shpnt; - PACB acbpnt; - PDCB dcbpnt; - unsigned long flags; -/* Scsi_Cmnd *ptr; */ + PACB pACB; + PDCB pDCB; + DC390_AFLAGS - acbpnt = pACB_start; + pACB = dc390_pACB_start; - while(acbpnt != (PACB)-1) + while(pACB != (PACB)-1) { - shpnt = acbpnt->pScsiHost; + shpnt = pACB->pScsiHost; if (shpnt->host_no == hostno) break; - acbpnt = acbpnt->pNextACB; + pACB = pACB->pNextACB; } - if (acbpnt == (PACB)-1) return(-ESRCH); + if (pACB == (PACB)-1) return(-ESRCH); if(!shpnt) return(-ESRCH); if(inout) /* Has data been written to the file ? */ - return(tmscsim_set_info(buffer, length, shpnt)); + return dc390_set_info(buffer, length, pACB); + + SPRINTF("Tekram DC390/AM53C974 PCI SCSI Host Adapter, "); + SPRINTF("Driver Version %s\n", DC390_VERSION); - SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, "); - SPRINTF("Driver Version 1.12, 1998/02/25\n"); - - save_flags(flags); - cli(); + DC390_LOCK_ACB; SPRINTF("SCSI Host Nr %i, ", shpnt->host_no); - SPRINTF("DC390 Adapter Nr %i\n", acbpnt->AdapterIndex); - SPRINTF("IOPortBase 0x%04x, ", acbpnt->IOPortBase); - SPRINTF("IRQLevel 0x%02x\n", acbpnt->IRQLevel); - - SPRINTF("MaxID %i, MaxLUN %i, ",acbpnt->max_id, acbpnt->max_lun); - SPRINTF("AdapterID %i, AdapterLUN %i\n", acbpnt->AdaptSCSIID, acbpnt->AdaptSCSILUN); - - SPRINTF("TagMaxNum %i, Status %i\n", acbpnt->TagMaxNum, acbpnt->status); + SPRINTF("%s Adapter Nr %i\n", dc390_adapname, pACB->AdapterIndex); + SPRINTF("IOPortBase 0x%04x, ", pACB->IOPortBase); + SPRINTF("IRQLevel 0x%02x\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("TagMaxNum %i, Status %i, ACBFlag %i, 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", + pACB->Cmds, pACB->CmdInQ, pACB->CmdOutOfSRB); + SPRINTF(" Lost arbitrations %li\n", pACB->SelLost); + + SPRINTF("Nr of attached devices: %i, Nr of DCBs: %i\n", pACB->DeviceCnt, pACB->DCBCnt); - SPRINTF("Nr of attached devices: %i\n", acbpnt->DeviceCnt); + SPRINTF("Idx ID LUN Prty Sync DsCn SndS TagQ STOP NegoPeriod SyncSpeed SyncOffs\n"); - SPRINTF("Un ID LUN Prty Sync DsCn SndS TagQ NegoPeriod SyncSpeed SyncOffs\n"); - - dcbpnt = acbpnt->pLinkDCB; - for (dev = 0; dev < acbpnt->DeviceCnt; dev++) + pDCB = pACB->pLinkDCB; + for (dev = 0; dev < pACB->DCBCnt; dev++) { - SPRINTF("%02i %02i %02i ", dev, dcbpnt->UnitSCSIID, dcbpnt->UnitSCSILUN); - YESNO(dcbpnt->DevMode & PARITY_CHK_); - YESNO(dcbpnt->SyncMode & SYNC_NEGO_DONE); - YESNO(dcbpnt->DevMode & EN_DISCONNECT_); - YESNO(dcbpnt->DevMode & SEND_START_); - YESNO(dcbpnt->SyncMode & EN_TAG_QUEUING); - SPRINTF(" %03i ns ", (dcbpnt->NegoPeriod) << 2); - if (dcbpnt->SyncOffset & 0x0f) + SPRINTF("%02i %02i %02i ", dev, pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + 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) { - spd = 1000/(dcbpnt->NegoPeriod <<2); - spd1 = 1000%(dcbpnt->NegoPeriod <<2); - spd1 = (spd1 * 10)/(dcbpnt->NegoPeriod <<2); - SPRINTF(" %2i.%1i M %02i\n", spd, spd1, (dcbpnt->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)); } - else SPRINTF("\n"); + else SPRINTF(" (%03i ns)\n", (pDCB->NegoPeriod) << 2); /* Add more info ...*/ - dcbpnt = dcbpnt->pNextDCB; + pDCB = pDCB->pNextDCB; } - restore_flags(flags); + DC390_UNLOCK_ACB; *start = buffer + offset; if (pos - buffer < offset) @@ -1574,75 +2462,92 @@ return length; } +#undef YESNO +#undef SPRINTF #ifdef MODULE /*********************************************************************** - * Function : static int DC390_shutdown (struct Scsi_Host *host) + * Function : static int dc390_shutdown (struct Scsi_Host *host) * * Purpose : does a clean (we hope) shutdown of the SCSI chip. * Use prior to dumping core, unloading the driver, etc. * * Returns : 0 on success ***********************************************************************/ -static int -DC390_shutdown (struct Scsi_Host *host) +static int dc390_shutdown (struct Scsi_Host *host) { UCHAR bval; - USHORT ioport; - unsigned long flags; PACB pACB = (PACB)(host->hostdata); - - ioport = (unsigned int) pACB->IOPortBase; - - save_flags (flags); - cli(); - + /* pACB->soft_reset(host); */ -#ifdef DC390_DEBUG0 - printk("DC390: shutdown,"); -#endif + printk(KERN_INFO "DC390: shutdown\n"); - bval = inb(ioport+CtrlReg1); + pACB->ACBFlag = RESET_DONE; + bval = DC390_read8 (CtrlReg1); bval |= DIS_INT_ON_SCSI_RST; - outb(bval,ioport+CtrlReg1); /* disable interrupt */ - DC390_ResetSCSIBus( pACB ); + DC390_write8 (CtrlReg1, bval); /* disable interrupt */ + if (pACB->Gmode2 & RST_SCSI_BUS) + dc390_ResetSCSIBus (pACB); - restore_flags (flags); return( 0 ); } +void dc390_freeDCBs (struct Scsi_Host *host) +{ + PDCB pDCB, nDCB; + PACB pACB = (PACB)(host->hostdata); + + pDCB = pACB->pLinkDCB; + if (!pDCB) return; + 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); + pDCB = nDCB; + } while (pDCB && pDCB != pACB->pLinkDCB); + +}; int DC390_release(struct Scsi_Host *host) { - int irq_count; - struct Scsi_Host *tmp; + 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; - DC390_shutdown (host); + dc390_shutdown (host); if (host->irq != IRQ_NONE) { - for (irq_count = 0, tmp = pSH_start; tmp; tmp = tmp->next) + for (irq_count = 0, pACB = dc390_pACB_start; + pACB && pACB != (PACB)-1; pACB = pACB->pNextACB) { - if ( tmp->irq == host->irq ) + if ( pACB->IRQLevel == host->irq ) ++irq_count; } if (irq_count == 1) { -#ifdef DC390_DEBUG0 - printk("DC390: Free IRQ %i.",host->irq); -#endif + DEBUG0(printk(KERN_DEBUG "DC390: Free IRQ %i\n",host->irq);) free_irq(host->irq,NULL); } } release_region(host->io_port,host->n_io_port); - + dc390_freeDCBs (host); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; return( 1 ); } Scsi_Host_Template driver_template = DC390_T; #include "scsi_module.c" #endif /* def MODULE */ - --- linux/drivers/scsi/tmscsim.h.old Thu Apr 2 19:12:25 1998 +++ linux/drivers/scsi/tmscsim.h Wed Oct 14 12:31:48 1998 @@ -3,12 +3,23 @@ ;* TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter * ;* Device Driver * ;***********************************************************************/ +/* $Id: tmscsim.h,v 2.1 1998/10/14 10:31:48 garloff Exp $ */ #ifndef _TMSCSIM_H #define _TMSCSIM_H #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_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; @@ -54,17 +65,6 @@ } SGentry1, *PSGE; -#define MAX_ADAPTER_NUM 4 -#define MAX_DEVICES 10 -#define MAX_SG_LIST_BUF 16 -#define MAX_CMD_QUEUE 20 -#define MAX_CMD_PER_LUN 8 -#define MAX_SCSI_ID 8 -#define MAX_SRB_CNT MAX_CMD_QUEUE+4 -#define END_SCAN 2 - -#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */ - /* ;----------------------------------------------------------------------- ; SCSI Request Block @@ -79,40 +79,46 @@ PSCSICMD pcmd; PSGL pSegmentList; -ULONG PhysSRB; +ULONG Segment0[2]; +ULONG Segment1[2]; + +/* 0x2c:*/ ULONG TotalXferredLen; -ULONG SGPhysAddr; /*;a segment starting address */ +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 */ PUCHAR pMsgPtr; -USHORT SRBState; -USHORT Revxx2; /* ??? */ -UCHAR MsgInBuf[6]; -UCHAR MsgOutBuf[6]; +UCHAR ScsiCmdLen; +UCHAR ScsiPhase; UCHAR AdaptStatus; UCHAR TargetStatus; + +/* 0x5c: */ 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 IORBFlag; /*;81h-Reset, 2-retry */ - UCHAR SRBStatus; -UCHAR RetryCnt; -UCHAR SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */ - /*; b4-settimeout,b5-Residual valid */ -UCHAR ScsiCmdLen; -UCHAR ScsiPhase; -UCHAR Reserved3[3]; /*;for dword alignment */ -ULONG Segment0[2]; -ULONG Segment1[2]; + //UCHAR IORBFlag; /*;81h-Reset, 2-retry */ + +/* 0x64: */ }; + typedef struct _SRB DC390_SRB, *PSRB; /* @@ -129,42 +135,44 @@ PSCSICMD pQIORBtail; PSCSICMD AboIORBhead; PSCSICMD AboIORBtail; -USHORT QIORBCnt; -USHORT AboIORBcnt; +ULONG QIORBCnt; +ULONG AboIORBcnt; +/* 0x20: */ PSRB pWaitingSRB; PSRB pWaitLast; PSRB pGoingSRB; PSRB pGoingLast; PSRB pActiveSRB; -USHORT GoingSRBCnt; -USHORT WaitSRBCnt; /* ??? */ +UCHAR GoingSRBCnt; +UCHAR WaitSRBCnt; /* ??? */ +UCHAR DevType; +UCHAR MaxCommand; +/* 0x38: */ ULONG TagMask; -USHORT MaxCommand; -USHORT AdaptIndex; /*; UnitInfo struc start */ -USHORT UnitIndex; /*; nth Unit on this card */ UCHAR UnitSCSIID; /*; SCSI Target ID (SCSI Only) */ UCHAR UnitSCSILUN; /*; SCSI Log. Unit (SCSI Only) */ - +UCHAR DevMode; UCHAR IdentifyMsg; + UCHAR CtrlR1; UCHAR CtrlR3; UCHAR CtrlR4; -UCHAR InqDataBuf[8]; -UCHAR CapacityBuf[8]; -UCHAR DevMode; -UCHAR AdpMode; +UCHAR DCBFlag; + +/* 0x44: */ UCHAR SyncMode; /*; 0:async mode */ UCHAR NegoPeriod; /*;for nego. */ UCHAR SyncPeriod; /*;for reg. */ UCHAR SyncOffset; /*;for reg. and nego.(low nibble) */ -UCHAR UnitCtrlFlag; -UCHAR DCBFlag; -UCHAR DevType; -UCHAR Reserved2[3]; /*;for dword alignment */ + +/* 0x48:*/ +//UCHAR InqDataBuf[8]; +//UCHAR CapacityBuf[8]; +/* 0x58: */ }; typedef struct _DCB DC390_DCB, *PDCB; @@ -175,40 +183,55 @@ */ struct _ACB { -ULONG PhysACB; PSH pScsiHost; struct _ACB *pNextACB; USHORT IOPortBase; -USHORT Revxx1; /* ??? */ +UCHAR IRQLevel; +UCHAR status; + +UCHAR SRBCount; +UCHAR AdapterIndex; /*; nth Adapter this driver */ +UCHAR DeviceCnt; +UCHAR DCBCnt; + +/* 0x10: */ +UCHAR TagMaxNum; +UCHAR ACBFlag; +UCHAR Gmode2; +UCHAR scan_devices; PDCB pLinkDCB; +PDCB pLastDCB; PDCB pDCBRunRobin; PDCB pActiveDCB; -PDCB pDCB_free; PSRB pFreeSRB; PSRB pTmpSRB; -USHORT SRBCount; -USHORT AdapterIndex; /*; nth Adapter this driver */ -USHORT max_id; -USHORT max_lun; + +/* 0x2c: */ UCHAR msgin123[4]; -UCHAR status; -UCHAR AdaptSCSIID; /*; Adapter SCSI Target ID */ -UCHAR AdaptSCSILUN; /*; Adapter SCSI LUN */ -UCHAR DeviceCnt; -UCHAR IRQLevel; -UCHAR TagMaxNum; -UCHAR ACBFlag; -UCHAR Gmode2; -UCHAR LUNchk; -UCHAR scan_devices; -UCHAR HostID_Bit; -UCHAR Reserved1[1]; /*;for dword alignment */ UCHAR DCBmap[MAX_SCSI_ID]; -DC390_DCB DCB_array[MAX_DEVICES]; /* +74h, Len=3E8 */ -DC390_SRB SRB_array[MAX_SRB_CNT]; /* +45Ch, Len= */ + +#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(__SMP__) || DEBUG_SPINLOCKS > 0) +spinlock_t lock; +#endif +UCHAR sel_timeout; +UCHAR glitch_cfg; + +UCHAR reserved[2]; /* alignment */ + +PDEVDECL1; /* Pointer to PCI cfg. space */ +/* 0x44/0x40: */ +ULONG Cmds; +ULONG CmdInQ; +ULONG CmdOutOfSRB; +ULONG SelLost; + +/* 0x50/0x4c: */ DC390_SRB TmpSRB; +/* 0xb4/0xb0: */ +DC390_SRB SRB_array[MAX_SRB_CNT]; /* 18 SRBs */ +/* 0x7bc/0x7b8: */ }; typedef struct _ACB DC390_ACB, *PACB; @@ -278,14 +301,6 @@ #define DO_SYNC_NEGO BIT13 #define SRB_UNEXPECT_RESEL BIT14 -/*;---ACBFlag */ -#define RESET_DEV BIT0 -#define RESET_DETECT BIT1 -#define RESET_DONE BIT2 - -/*;---DCBFlag */ -#define ABORT_DEV_ BIT0 - /*;---SRBstatus */ #define SRB_OK BIT0 #define ABORTION BIT1 @@ -294,6 +309,14 @@ #define PARITY_ERROR BIT4 #define SRB_ERROR BIT5 +/*;---ACBFlag */ +#define RESET_DEV BIT0 +#define RESET_DETECT BIT1 +#define RESET_DONE BIT2 + +/*;---DCBFlag */ +#define ABORT_DEV_ BIT0 + /*;---SRBFlag */ #define DATAOUT BIT7 #define DATAIN BIT6 @@ -316,7 +339,7 @@ #define H_BAD_CCB_OR_SG 0x1A #define H_ABORT 0x0FF -/*; SCSI Status byte codes*/ +/*; 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 */ @@ -335,9 +358,9 @@ #define SYNC_DISABLE 0 #define SYNC_ENABLE BIT0 #define SYNC_NEGO_DONE BIT1 -#define WIDE_ENABLE BIT2 -#define WIDE_NEGO_DONE BIT3 -#define EN_TAG_QUEUING BIT4 +#define WIDE_ENABLE BIT2 /* Not used ;-) */ +#define WIDE_NEGO_DONE BIT3 /* Not used ;-) */ +#define EN_TAG_QUEUEING BIT4 #define EN_ATN_STOP BIT5 #define SYNC_NEGO_OFFSET 15 @@ -352,7 +375,7 @@ #define SCSI_MSG_OUT 6 #define SCSI_MSG_IN 7 -/*;----SCSI MSG BYTE*/ +/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */ #define MSG_COMPLETE 0x00 #define MSG_EXTENDED 0x01 #define MSG_SAVE_PTR 0x02 @@ -373,13 +396,6 @@ #define MSG_IDENTIFY 0x80 #define MSG_HOST_ID 0x0C0 -/*;----SCSI STATUS BYTE*/ -#define STATUS_GOOD 0x00 -#define CHECK_CONDITION_ 0x02 -#define STATUS_BUSY 0x08 -#define STATUS_INTERMEDIATE 0x10 -#define RESERVE_CONFLICT 0x18 - /* cmd->result */ #define STATUS_MASK_ 0xFF #define MSG_MASK 0xFF00 @@ -389,7 +405,7 @@ ** Inquiry Data format */ -typedef struct _SCSIInqData { /* INQ */ +typedef struct _SCSIInqData { /* INQUIRY */ UCHAR DevType; /* Periph Qualifier & Periph Dev Type*/ UCHAR RMB_TypeMod; /* rem media bit & Dev Type Modifier */ @@ -412,6 +428,7 @@ #define SCSI_DEVTYPE 0x1F /* Peripheral Device Type */ #define SCSI_PERIPHQUAL 0xE0 /* Peripheral Qualifier */ +#define TYPE_NODEV SCSI_DEVTYPE /* Unknown or no device type */ /* Inquiry byte 1 mask */ @@ -420,18 +437,10 @@ /* Peripheral Device Type definitions */ +/* see include/scsi/scsi.h for the rest */ -#define SCSI_DASD 0x00 /* Direct-access Device */ -#define SCSI_SEQACESS 0x01 /* Sequential-access device */ -#define SCSI_PRINTER 0x02 /* Printer device */ -#define SCSI_PROCESSOR 0x03 /* Processor device */ -#define SCSI_WRITEONCE 0x04 /* Write-once device */ -#define SCSI_CDROM 0x05 /* CD-ROM device */ -#define SCSI_SCANNER 0x06 /* Scanner device */ -#define SCSI_OPTICAL 0x07 /* Optical memory device */ -#define SCSI_MEDCHGR 0x08 /* Medium changer device */ -#define SCSI_COMM 0x09 /* Communications device */ -#define SCSI_NODEV 0x1F /* Unknown or no device type */ +#define TYPE_PRINTER 0x02 /* Printer device */ +#define TYPE_COMM 0x09 /* Communications device */ /* ** Inquiry flag definitions (Inq data byte 7) @@ -459,17 +468,24 @@ UCHAR xx2; } EEprom, *PEEprom; -#define EE_ADAPT_SCSI_ID 64 -#define EE_MODE2 65 -#define EE_DELAY 66 -#define EE_TAG_CMD_NUM 67 +#define REAL_EE_ADAPT_SCSI_ID 64 +#define REAL_EE_MODE2 65 +#define REAL_EE_DELAY 66 +#define REAL_EE_TAG_CMD_NUM 67 + +#define EE_ADAPT_SCSI_ID 32 +#define EE_MODE2 33 +#define EE_DELAY 34 +#define EE_TAG_CMD_NUM 35 + +#define EE_LEN 40 /*; EE_MODE1 bits definition*/ #define PARITY_CHK_ BIT0 #define SYNC_NEGO_ BIT1 #define EN_DISCONNECT_ BIT2 #define SEND_START_ BIT3 -#define TAG_QUEUING_ BIT4 +#define TAG_QUEUEING_ BIT4 /*; EE_MODE2 bits definition*/ #define MORE2_DRV BIT0 @@ -494,34 +510,42 @@ ;==================== */ -/*; Command Reg.(+0CH) */ +/*; Command Reg.(+0CH) (rw) */ #define DMA_COMMAND BIT7 #define NOP_CMD 0 #define CLEAR_FIFO_CMD 1 #define RST_DEVICE_CMD 2 #define RST_SCSI_BUS_CMD 3 + #define INFO_XFER_CMD 0x10 #define INITIATOR_CMD_CMPLTE 0x11 #define MSG_ACCEPTED_CMD 0x12 #define XFER_PAD_BYTE 0x18 #define SET_ATN_CMD 0x1A #define RESET_ATN_CMD 0x1B -#define SELECT_W_ATN 0x42 + +#define SEL_WO_ATN 0x41 /* currently not used */ +#define SEL_W_ATN 0x42 #define SEL_W_ATN_STOP 0x43 +#define SEL_W_ATN3 0x46 #define EN_SEL_RESEL 0x44 -#define SEL_W_ATN2 0x46 +#define DIS_SEL_RESEL 0x45 /* currently not used */ +#define RESEL 0x40 /* " */ +#define RESEL_ATN3 0x47 /* " */ + #define DATA_XFER_CMD INFO_XFER_CMD -/*; SCSI Status Reg.(+10H) */ +/*; SCSI Status Reg.(+10H) (r) */ #define INTERRUPT BIT7 #define ILLEGAL_OP_ERR BIT6 #define PARITY_ERR BIT5 #define COUNT_2_ZERO BIT4 #define GROUP_CODE_VALID BIT3 -#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0) +#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0) +/* BIT2: MSG phase; BIT1: C/D physe; BIT0: I/O phase */ -/*; Interrupt Status Reg.(+14H) */ +/*; Interrupt Status Reg.(+14H) (r) */ #define SCSI_RESET BIT7 #define INVALID_CMD BIT6 #define DISCONNECTED BIT5 @@ -531,11 +555,12 @@ #define SEL_ATTENTION BIT1 #define SELECTED BIT0 -/*; Internal State Reg.(+18H) */ +/*; Internal State Reg.(+18H) (r) */ #define SYNC_OFFSET_FLAG BIT3 #define INTRN_STATE_MASK (BIT2+BIT1+BIT0) +/* 0x04: Sel. successful (w/o stop), 0x01: Sel. successful (w/ stop) */ -/*; Clock Factor Reg.(+24H) */ +/*; Clock Factor Reg.(+24H) (w) */ #define CLK_FREQ_40MHZ 0 #define CLK_FREQ_35MHZ (BIT2+BIT1+BIT0) #define CLK_FREQ_30MHZ (BIT2+BIT1) @@ -544,47 +569,54 @@ #define CLK_FREQ_15MHZ (BIT1+BIT0) #define CLK_FREQ_10MHZ BIT1 -/*; Control Reg. 1(+20H) */ +/*; Control Reg. 1(+20H) (rw) */ #define EXTENDED_TIMING BIT7 #define DIS_INT_ON_SCSI_RST BIT6 #define PARITY_ERR_REPO BIT4 -#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0) +#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0) /* host adapter ID */ -/*; Control Reg. 2(+2CH) */ +/*; Control Reg. 2(+2CH) (rw) */ #define EN_FEATURE BIT6 #define EN_SCSI2_CMD BIT3 -/*; Control Reg. 3(+30H) */ +/*; Control Reg. 3(+30H) (rw) */ #define ID_MSG_CHECK BIT7 #define EN_QTAG_MSG BIT6 #define EN_GRP2_CMD BIT5 #define FAST_SCSI BIT4 /* ;10MB/SEC */ #define FAST_CLK BIT3 /* ;25 - 40 MHZ */ -/*; Control Reg. 4(+34H) */ +/*; Control Reg. 4(+34H) (rw) */ #define EATER_12NS 0 #define EATER_25NS BIT7 #define EATER_35NS BIT6 #define EATER_0NS (BIT7+BIT6) +#define REDUCED_POWER BIT5 +#define CTRL4_RESERVED BIT4 /* must be 1 acc. to AM53C974.c */ #define NEGATE_REQACKDATA BIT2 #define NEGATE_REQACK BIT3 + +#define GLITCH_TO_NS(x) (((~x>>6 & 2) >> 1) | ((x>>6 & 1) << 1 ^ (x>>6 & 2))) +#define NS_TO_GLITCH(y) (((~y<<7) | ~((y<<6) ^ ((y<<5 & 1<<6) | ~0x40))) & 0xc0) + /* ;==================== ; DMA Register ;==================== */ -/*; DMA Command Reg.(+40H) */ +/*; DMA Command Reg.(+40H) (rw) */ #define READ_DIRECTION BIT7 #define WRITE_DIRECTION 0 #define EN_DMA_INT BIT6 -#define MAP_TO_MDL BIT5 -#define DIAGNOSTIC BIT4 +#define EN_PAGE_INT BIT5 /* page transfer interrupt enable */ +#define MAP_TO_MDL BIT4 +#define DIAGNOSTIC BIT2 #define DMA_IDLE_CMD 0 #define DMA_BLAST_CMD BIT0 #define DMA_ABORT_CMD BIT1 #define DMA_START_CMD (BIT1+BIT0) -/*; DMA Status Reg.(+54H) */ +/*; DMA Status Reg.(+54H) (r) */ #define PCI_MS_ABORT BIT6 #define BLAST_COMPLETE BIT5 #define SCSI_INTERRUPT BIT4 @@ -593,71 +625,77 @@ #define DMA_XFER_ERROR BIT1 #define POWER_DOWN BIT0 -/* -; DMA SCSI Bus and Ctrl.(+70H) -;EN_INT_ON_PCI_ABORT -*/ +/*; DMA SCSI Bus and Ctrl.(+70H) */ +#define EN_INT_ON_PCI_ABORT BIT25 +#define WRT_ERASE_DMA_STAT BIT24 +#define PW_DOWN_CTRL BIT21 +#define SCSI_BUSY BIT20 +#define SCLK BIT19 +#define SCAM BIT18 +#define SCSI_LINES 0x0003ffff /* ;========================================================== ; SCSI Chip register address offset ;========================================================== +;Registers are rw unless declared otherwise */ -#define CtcReg_Low 0x00 -#define CtcReg_Mid 0x04 +#define CtcReg_Low 0x00 /* r curr. transfer count */ +#define CtcReg_Mid 0x04 /* r */ +#define CtcReg_High 0x38 /* r */ #define ScsiFifo 0x08 #define ScsiCmd 0x0C -#define Scsi_Status 0x10 -#define INT_Status 0x14 -#define Sync_Period 0x18 -#define Sync_Offset 0x1C -#define CtrlReg1 0x20 -#define Clk_Factor 0x24 +#define Scsi_Status 0x10 /* r */ +#define INT_Status 0x14 /* r */ +#define Sync_Period 0x18 /* w */ +#define Sync_Offset 0x1C /* w */ +#define Clk_Factor 0x24 /* w */ +#define CtrlReg1 0x20 #define CtrlReg2 0x2C #define CtrlReg3 0x30 #define CtrlReg4 0x34 -#define CtcReg_High 0x38 #define DMA_Cmd 0x40 -#define DMA_XferCnt 0x44 -#define DMA_XferAddr 0x48 -#define DMA_Wk_ByteCntr 0x4C -#define DMA_Wk_AddrCntr 0x50 -#define DMA_Status 0x54 -#define DMA_MDL_Addr 0x58 -#define DMA_Wk_MDL_Cntr 0x5C -#define DMA_ScsiBusCtrl 0x70 - -#define StcReg_Low CtcReg_Low -#define StcReg_Mid CtcReg_Mid -#define Scsi_Dest_ID Scsi_Status -#define Scsi_TimeOut INT_Status -#define Intern_State Sync_Period -#define Current_Fifo Sync_Offset -#define StcReg_High CtcReg_High - -#define am_target Scsi_Status -#define am_timeout INT_Status -#define am_seq_step Sync_Period -#define am_fifo_count Sync_Offset - - -#define DC390_read8(address) \ - inb(DC390_ioport + (address))) - -#define DC390_read16(address) \ - inw(DC390_ioport + (address))) - -#define DC390_read32(address) \ - inl(DC390_ioport + (address))) +#define DMA_XferCnt 0x44 /* rw starting transfer count (32 bit) */ +#define DMA_XferAddr 0x48 /* rw starting physical address (32 bit) */ +#define DMA_Wk_ByteCntr 0x4C /* r working byte counter */ +#define DMA_Wk_AddrCntr 0x50 /* r working address counter */ +#define DMA_Status 0x54 /* r */ +#define DMA_MDL_Addr 0x58 /* rw starting MDL address */ +#define DMA_Wk_MDL_Cntr 0x5C /* r working MDL counter */ +#define DMA_ScsiBusCtrl 0x70 /* rw SCSI Bus, PCI/DMA Ctrl */ + +#define StcReg_Low CtcReg_Low /* w start transfer count */ +#define StcReg_Mid CtcReg_Mid /* w */ +#define StcReg_High CtcReg_High /* w */ +#define Scsi_Dest_ID Scsi_Status /* w */ +#define Scsi_TimeOut INT_Status /* w */ +#define Intern_State Sync_Period /* r */ +#define Current_Fifo Sync_Offset /* r Curr. FIFO / int. state */ + + +#define DC390_read8(address) \ + (inb (pACB->IOPortBase + (address))) + +#define DC390_read8_(address, base) \ + (inb ((USHORT)(base) + (address))) + +#define DC390_read16(address) \ + (inw (pACB->IOPortBase + (address))) + +#define DC390_read32(address) \ + (inl (pACB->IOPortBase + (address))) + +#define DC390_write8(address,value) \ + outb ((value), pACB->IOPortBase + (address)) -#define DC390_write8(address,value) \ - outb((value), DC390_ioport + (address))) +#define DC390_write8_(address,value,base) \ + outb ((value), (USHORT)(base) + (address)) -#define DC390_write16(address,value) \ - outw((value), DC390_ioport + (address))) +#define DC390_write16(address,value) \ + outw ((value), pACB->IOPortBase + (address)) -#define DC390_write32(address,value) \ - outl((value), DC390_ioport + (address))) +#define DC390_write32(address,value) \ + outl ((value), pACB->IOPortBase + (address)) #endif /* _TMSCSIM_H */ --- linux/drivers/scsi/dc390.h.old Mon Aug 3 21:39:02 1998 +++ linux/drivers/scsi/dc390.h Sat Oct 24 10:48:45 1998 @@ -4,16 +4,20 @@ * Description: Device Driver for Tekram DC-390(T) PCI SCSI * * Bus Master Host Adapter * ***********************************************************************/ +/* $Id: dc390.h,v 2.3 1998/10/24 08:45:02 garloff Exp $ */ #include /* - * AMD 53C974 driver, header file + * DC390/AMD 53C974 driver, header file */ #ifndef DC390_H #define DC390_H +#define DC390_BANNER "Tekram DC390/AM53C974" +#define DC390_VERSION "2.0b 1998/10/24" + #if defined(HOSTS_C) || defined(MODULE) #include @@ -30,24 +34,24 @@ # define DC390_release NULL #endif -extern struct proc_dir_entry proc_scsi_tmscsim; -extern int tmscsim_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); +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); -#define DC390_T { \ - proc_dir: &proc_scsi_tmscsim, \ - proc_info: tmscsim_proc_info, \ - name: "Tekram DC390(T) V1.12 Feb-25-1998",\ - detect: DC390_detect, \ - release: DC390_release, \ - queuecommand: DC390_queue_command, \ - abort: DC390_abort, \ - reset: DC390_reset, \ - bios_param: DC390_bios_param, \ - can_queue: 10, \ - this_id: 7, \ - sg_tablesize: SG_ALL, \ - cmd_per_lun: 2, \ - use_clustering: DISABLE_CLUSTERING \ +#define DC390_T { \ + proc_dir: &DC390_proc_scsi_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: 17, \ + this_id: 7, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 8, \ + use_clustering: DISABLE_CLUSTERING \ } #endif /* defined(HOSTS_C) || defined(MODULE) */ --- linux/drivers/scsi/scsiiom.c.old Thu May 21 23:24:09 1998 +++ linux/drivers/scsi/scsiiom.c Sat Oct 24 11:10:28 1998 @@ -4,198 +4,264 @@ * Description: Device Driver for Tekram DC-390 (T) PCI SCSI * * Bus Master Host Adapter * ***********************************************************************/ +/* $Id: scsiiom.c,v 2.3 1998/10/24 09:10:28 garloff Exp $ */ - -static USHORT -DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ) +UCHAR +dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ) { - USHORT ioport, rc; - UCHAR bval, bval1, i, cnt; - PUCHAR ptr; - ULONG wlval; + USHORT wlval; + UCHAR bval, bval1; pSRB->TagNumber = 31; - ioport = pACB->IOPortBase; - bval = pDCB->UnitSCSIID; - outb(bval,ioport+Scsi_Dest_ID); - bval = pDCB->SyncPeriod; - outb(bval,ioport+Sync_Period); - bval = pDCB->SyncOffset; - outb(bval,ioport+Sync_Offset); - bval = pDCB->CtrlR1; - outb(bval,ioport+CtrlReg1); - bval = pDCB->CtrlR3; - outb(bval,ioport+CtrlReg3); - bval = pDCB->CtrlR4; - outb(bval,ioport+CtrlReg4); - bval = CLEAR_FIFO_CMD; /* Flush FIFO */ - outb(bval,ioport+ScsiCmd); - + DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID); + DC390_write8 (Sync_Period, pDCB->SyncPeriod); + DC390_write8 (Sync_Offset, pDCB->SyncOffset); + DC390_write8 (CtrlReg1, pDCB->CtrlR1); + DC390_write8 (CtrlReg3, pDCB->CtrlR3); + 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) ) + 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 disconnection */ - outb(bval,ioport+ScsiFifo); - bval1 = SELECT_W_ATN; + bval &= 0xBF; /* No DisConn */ + DC390_write8 (ScsiFifo, bval); + bval1 = SEL_W_ATN; pSRB->SRBState = SRB_START_; + DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);) if( pDCB->SyncMode & SYNC_ENABLE ) - { - if( !(pDCB->IdentifyMsg & 7) || + { + if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ (pSRB->CmdBlock[0] != INQUIRY) ) { - bval1 = SEL_W_ATN_STOP; + bval1 = SEL_W_ATN_STOP; /* Try to establish SYNC nego */ pSRB->SRBState = SRB_MSGOUT; } } } - else + else /* TagQ ? */ { - if(pDCB->SyncMode & EN_TAG_QUEUING) + DC390_write8 (ScsiFifo, bval); + if(pDCB->SyncMode & EN_TAG_QUEUEING) { - outb(bval,ioport+ScsiFifo); - bval = MSG_SIMPLE_QTAG; - outb(bval,ioport+ScsiFifo); - wlval = 1; - bval = 0; - while( wlval & pDCB->TagMask ) - { - wlval = wlval << 1; - bval++; - } - outb(bval,ioport+ScsiFifo); + DC390_write8 (ScsiFifo, MSG_SIMPLE_QTAG); + DEBUG1(printk ("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; - bval1 = SEL_W_ATN2; + DEBUG1(printk ("DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);) + bval1 = SEL_W_ATN3; pSRB->SRBState = SRB_START_; } - else + else /* No TagQ */ { - outb(bval,ioport+ScsiFifo); - bval1 = SELECT_W_ATN; + bval1 = SEL_W_ATN; + DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);) pSRB->SRBState = SRB_START_; } } - if( pSRB->SRBFlag & AUTO_REQSENSE ) - { - bval = REQUEST_SENSE; - outb(bval,ioport+ScsiFifo); - bval = pDCB->IdentifyMsg << 5; - outb(bval,ioport+ScsiFifo); - bval = 0; - outb(bval,ioport+ScsiFifo); - outb(bval,ioport+ScsiFifo); - bval = sizeof(pSRB->pcmd->sense_buffer); - outb(bval,ioport+ScsiFifo); - bval = 0; - outb(bval,ioport+ScsiFifo); - } - else - { - cnt = pSRB->ScsiCmdLen; - ptr = (PUCHAR) pSRB->CmdBlock; - for(i=0; iCmdBlock[0] == INQUIRY) || (pSRB->CmdBlock[0] == REQUEST_SENSE) || (pSRB->SRBFlag & AUTO_REQSENSE) ) { - bval &= 0xBF; - outb(bval,ioport+ScsiFifo); - bval1 = SELECT_W_ATN; + bval &= 0xBF; /* No DisConn */ + DC390_write8 (ScsiFifo, bval); + bval1 = SEL_W_ATN; + DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);) pSRB->SRBState = SRB_START_; + /* ??? */ if( pDCB->SyncMode & SYNC_ENABLE ) { - if( !(pDCB->IdentifyMsg & 7) || + if( !(pDCB->IdentifyMsg & 7) || /* LUN == 0 || Cmd != INQUIRY */ (pSRB->CmdBlock[0] != INQUIRY) ) { - bval1 = SEL_W_ATN_STOP; + bval1 = SEL_W_ATN_STOP; /* Try to establish Sync nego */ pSRB->SRBState = SRB_MSGOUT; } } } - else + else /* TagQ ? */ { - if(pDCB->SyncMode & EN_TAG_QUEUING) + DC390_write8 (ScsiFifo, bval); + if(pDCB->SyncMode & EN_TAG_QUEUEING) { - outb(bval,ioport+ScsiFifo); pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG; - wlval = 1; - bval = 0; - while( wlval & pDCB->TagMask ) - { - wlval = wlval << 1; - bval++; - } + DEBUG1(printk ("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 ("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_; + pSRB->SRBState = SRB_START_; /* ?? */ } - else + else /* No TagQ */ { - outb(bval,ioport+ScsiFifo); pSRB->MsgOutBuf[0] = MSG_NOP; pSRB->MsgCnt = 1; pSRB->SRBState = SRB_START_; bval1 = SEL_W_ATN_STOP; - } + DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);) + }; } } - bval = inb( ioport+Scsi_Status ); - if( bval & INTERRUPT ) + if (bval1 != SEL_W_ATN_STOP) + { /* Command is written in CommandPhase, if 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, sizeof(pSRB->pcmd->sense_buffer)); + DC390_write8 (ScsiFifo, bval); + DEBUG1(printk ("DC390: AutoReqSense !\n");) + } + else /* write cmnd to bus */ + { + PUCHAR ptr; UCHAR i; + ptr = (PUCHAR) pSRB->CmdBlock; + for (i=0; iScsiCmdLen; i++) + DC390_write8 (ScsiFifo, *(ptr++)); + }; + } + + /* Check if we can't win arbitration */ + if (DC390_read8 (Scsi_Status) & INTERRUPT) { pSRB->SRBState = SRB_READY; pDCB->TagMask &= ~( 1 << pSRB->TagNumber ); - rc = 1; + DEBUG0(printk ("DC390: Interrupt during StartSCSI!\n");) + return 1; } else { pSRB->ScsiPhase = SCSI_NOP1; + DEBUG0(if (pACB->pActiveDCB) \ + printk ("DC390: ActiveDCB != 0\n");) + DEBUG0(if (pDCB->pActiveSRB) \ + printk ("DC390: ActiveSRB != 0\n");) pACB->pActiveDCB = pDCB; pDCB->pActiveSRB = pSRB; - rc = 0; - outb(bval1,ioport+ScsiCmd); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + DC390_write8 (ScsiCmd, bval1); + return 0; } - return( rc ); } +//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/ +#define DMA_INT 0 + +#if DMA_INT +/* This is similar to AM53C974.c ... */ +static UCHAR +dc390_dma_intr (PACB pACB) +{ + PSRB pSRB; + UCHAR dstate; + DEBUG0(USHORT pstate;PDEVDECL1;) + + DEBUG0(PDEVSET1;) + DEBUG0(PCI_READ_CONFIG_WORD (PDEV, PCI_STATUS, &pstate);) + DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\ + { printk("DC390: PCI state = %04x!\n", pstate); \ + PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));};) + + dstate = DC390_read8 (DMA_Status); + DC390_write8 (DMA_Status, dstate); /* clear */ + //DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */ + + if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate; + else pSRB = pACB->pActiveDCB->pActiveSRB; + + if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT)) + { + printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate); + return dstate; + }; + if (dstate & DMA_XFER_DONE) + { + ULONG residual, xferCnt; int ctr = 5000000; + if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION)) + { + do + { + DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n");) + dstate = DC390_read8 (DMA_Status); + DC390_write8 (DMA_Status, dstate); /* clear */ + residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 | + DC390_read8 (CtcReg_High) << 16; + residual += DC390_read8 (Current_Fifo) & 0x1f; + } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr); + if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr)); + /* residual = ... */ + } + else + residual = 0; + + /* ??? */ + + xferCnt = pSRB->SGToBeXferLen - residual; + pSRB->SGBusAddr += xferCnt; + pSRB->TotalXferredLen += xferCnt; + pSRB->SGToBeXferLen = residual; +# ifdef DC390_DEBUG0 + printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", + (unsigned int)residual, (unsigned int)xferCnt); +# endif + + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + } + return dstate; +}; +#endif -static void +void __inline__ DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) { PACB pACB; PDCB pDCB; PSRB pSRB; - USHORT ioport = 0; - USHORT phase, i; + UCHAR sstatus=0; + UCHAR phase, i; void (*stateV)( PACB, PSRB, PUCHAR ); - UCHAR istate = 0; - UCHAR sstatus=0, istatus; + UCHAR istate, istatus; + UCHAR dstatus; + DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS + + pACB = dc390_pACB_start; - pACB = pACB_start; - if( pACB == NULL ) + if (pACB == 0) + { + printk(KERN_ERR "DC390: Interrupt on uninitialized adapter!\n"); return; - for( i=0; i < adapterCnt; i++ ) + } + DC390_LOCK_DRV; + + for( i=0; i < dc390_adapterCnt; i++ ) { if( pACB->IRQLevel == (UCHAR) irq ) { - ioport = pACB->IOPortBase; - sstatus = inb( ioport+Scsi_Status ); + sstatus = DC390_read8 (Scsi_Status); if( sstatus & INTERRUPT ) break; else @@ -207,99 +273,128 @@ } } -#ifdef DC390_DEBUG1 - printk("sstatus=%2x,",sstatus); -#endif + DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);) - if( pACB == (PACB )-1 ) - { - printk("DC390: Spurious interrupt detected!\n"); + if( pACB == (PACB )-1) { DC390_UNLOCK_DRV; return; }; + +#if DMA_INT + DC390_LOCK_IO; + DC390_LOCK_ACB; + dstatus = dc390_dma_intr (pACB); + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + + DEBUG1(printk ("dstatus=%02x,", dstatus);) + if (! (dstatus & SCSI_INTERRUPT)) + { + DEBUG0(printk ("DC390 Int w/o SCSI actions (only DMA?)\n");) + DC390_UNLOCK_DRV; return; - } - - istate = inb( ioport+Intern_State ); - istatus = inb( ioport+INT_Status ); - -#ifdef DC390_DEBUG1 - printk("Istatus=%2x,",istatus); + }; +#else + dstatus = DC390_read8 (DMA_Status); #endif + DC390_LOCK_IO; + DC390_LOCK_ACB; + 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 ! */ + + DEBUG1(printk ("Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus);) + dc390_laststatus = dstatus<<24 | sstatus<<16 | istate<<8 | istatus; + + if (sstatus & ILLEGAL_OP_ERR) + { + printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus); + dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB); + }; + if(istatus & DISCONNECTED) { - DC390_Disconnect( pACB ); - return; + dc390_Disconnect( pACB ); + goto unlock; } if(istatus & RESELECTED) { - DC390_Reselect( pACB ); - return; + dc390_Reselect( pACB ); + goto unlock; } if(istatus & INVALID_CMD) { - DC390_InvalidCmd( pACB ); - return; + dc390_InvalidCmd( pACB ); + goto unlock; } if(istatus & SCSI_RESET) { - DC390_ScsiRstDetect( pACB ); - return; + dc390_ScsiRstDetect( pACB ); + goto unlock; } - if( istatus & (SUCCESSFUL_OP+SERVICE_REQUEST) ) + if( istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) ) { pDCB = pACB->pActiveDCB; - pSRB = pDCB->pActiveSRB; - if( pDCB ) + if (!pDCB) { - if( pDCB->DCBFlag & ABORT_DEV_ ) - EnableMsgOut( pACB, pSRB ); - } + printk (KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n"); + goto unlock; + }; + pSRB = pDCB->pActiveSRB; + if( pDCB->DCBFlag & ABORT_DEV_ ) + dc390_EnableMsgOut( pACB, pSRB ); - phase = (USHORT) pSRB->ScsiPhase; - stateV = (void *) DC390_phase0[phase]; - stateV( pACB, pSRB, &sstatus ); + phase = pSRB->ScsiPhase; + DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus);) + stateV = (void *) dc390_phase0[phase]; + ( *stateV )( pACB, pSRB, &sstatus ); pSRB->ScsiPhase = sstatus & 7; - phase = (USHORT) sstatus & 7; - stateV = (void *) DC390_phase1[phase]; - stateV( pACB, pSRB, &sstatus ); - } + phase = (UCHAR) sstatus & 7; + DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus);) + stateV = (void *) dc390_phase1[phase]; + ( *stateV )( pACB, pSRB, &sstatus ); + } + unlock: + DC390_LOCK_DRV_NI; + DC390_UNLOCK_ACB; + DC390_UNLOCK_IO; + DC390_UNLOCK_DRV; /* Restore initial flags */ } -static void +void do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs) { - unsigned long flags; - - spin_lock_irqsave(&io_request_lock, flags); + DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq);) + /* Locking is done in DC390_Interrupt */ DC390_Interrupt(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); + DEBUG1(printk (".. IRQ returned\n");) } -static void -DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +void +dc390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR sstatus, bval; - USHORT ioport; + UCHAR sstatus; PSGL psgl; ULONG ResidCnt, xferCnt; - ioport = pACB->IOPortBase; sstatus = *psstatus; if( !(pSRB->SRBState & SRB_XFERPAD) ) { - if( sstatus & PARITY_ERR ) + if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR) ) pSRB->SRBStatus |= PARITY_ERROR; if( sstatus & COUNT_2_ZERO ) { - bval = inb(ioport+DMA_Status); - while( !(bval & DMA_XFER_DONE) ) - bval = inb(ioport+DMA_Status); + int ctr = 5000000; /* only try for about a tenth of a second */ + while( --ctr && !(DC390_read8 (DMA_Status) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ) + DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */ + if (!ctr) printk (KERN_CRIT "DC390: DataOut_0: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr)); + DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */ pSRB->TotalXferredLen += pSRB->SGToBeXferLen; pSRB->SGIndex++; if( pSRB->SGIndex < pSRB->SGcount ) @@ -307,7 +402,7 @@ pSRB->pSegmentList++; psgl = pSRB->pSegmentList; - pSRB->SGPhysAddr = virt_to_phys( psgl->address ); + pSRB->SGBusAddr = virt_to_bus( psgl->address ); pSRB->SGToBeXferLen = (ULONG) psgl->length; } else @@ -315,51 +410,50 @@ } else { - bval = inb( ioport+Current_Fifo ); - bval &= 0x1f; - ResidCnt = (ULONG) inb(ioport+CtcReg_High); - ResidCnt = ResidCnt << 8; - ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid); - ResidCnt = ResidCnt << 8; - ResidCnt |= (ULONG) inb(ioport+CtcReg_Low); - ResidCnt += (ULONG) bval; + 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); xferCnt = pSRB->SGToBeXferLen - ResidCnt; - pSRB->SGPhysAddr += xferCnt; + pSRB->SGBusAddr += xferCnt; pSRB->TotalXferredLen += xferCnt; pSRB->SGToBeXferLen = ResidCnt; } } - bval = WRITE_DIRECTION+DMA_IDLE_CMD; - outb( bval, ioport+DMA_Cmd); + DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ } -static void -DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +void +dc390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR sstatus, bval; - USHORT i, ioport, residual; + UCHAR sstatus, residual, bval; PSGL psgl; - ULONG ResidCnt, xferCnt; + ULONG ResidCnt, xferCnt, i; PUCHAR ptr; - - ioport = pACB->IOPortBase; sstatus = *psstatus; if( !(pSRB->SRBState & SRB_XFERPAD) ) { - if( sstatus & PARITY_ERR ) + if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR)) pSRB->SRBStatus |= PARITY_ERROR; if( sstatus & COUNT_2_ZERO ) { - bval = inb(ioport+DMA_Status); - while( !(bval & DMA_XFER_DONE) ) - bval = inb(ioport+DMA_Status); + int ctr = 5000000; /* only try for about a tenth of a second */ + int dstate = 0; + while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen ) + DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */ + if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr)); + if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate); + DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16) \ + + ((ULONG) DC390_read8 (CtcReg_Mid) << 8) \ + + ((ULONG) DC390_read8 (CtcReg_Low));) + DEBUG1(printk ("Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);) + DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */ - bval = READ_DIRECTION+DMA_IDLE_CMD; - outb( bval, ioport+DMA_Cmd); + DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ pSRB->TotalXferredLen += pSRB->SGToBeXferLen; pSRB->SGIndex++; @@ -368,7 +462,7 @@ pSRB->pSegmentList++; psgl = pSRB->pSegmentList; - pSRB->SGPhysAddr = virt_to_phys( psgl->address ); + pSRB->SGBusAddr = virt_to_bus( psgl->address ); pSRB->SGToBeXferLen = (ULONG) psgl->length; } else @@ -377,14 +471,15 @@ else /* phase changed */ { residual = 0; - bval = inb(ioport+Current_Fifo); + bval = DC390_read8 (Current_Fifo); while( bval & 0x1f ) { + DEBUG1(printk ("Check for residuals,");) if( (bval & 0x1f) == 1 ) { - for(i=0; i< 0x100; i++) + for(i=0; i < 0x100; i++) { - bval = inb(ioport+Current_Fifo); + bval = DC390_read8 (Current_Fifo); if( !(bval & 0x1f) ) goto din_1; else if( i == 0x0ff ) @@ -395,87 +490,85 @@ } } else - bval = inb(ioport+Current_Fifo); + bval = DC390_read8 (Current_Fifo); } din_1: - bval = READ_DIRECTION+DMA_BLAST_CMD; - outb(bval, ioport+DMA_Cmd); - for(i=0; i<0x8000; i++) + DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD); + for (i=0; i<0x8000; i++) { - bval = inb(ioport+DMA_Status); - if(bval & BLAST_COMPLETE) + bval = DC390_read8 (DMA_Status); + DC390_write8 (DMA_Status, BLAST_COMPLETE | DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT); /* clear */ + if (bval & BLAST_COMPLETE) break; } - bval = READ_DIRECTION+DMA_IDLE_CMD; - outb(bval, ioport+DMA_Cmd); + if (i == 0x8000) printk (KERN_CRIT "DC390: DMA Blast aborted unfinished!!\n"); + //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */ - ResidCnt = (ULONG) inb(ioport+CtcReg_High); - ResidCnt = ResidCnt << 8; - ResidCnt |= (ULONG) inb(ioport+CtcReg_Mid); - ResidCnt = ResidCnt << 8; - ResidCnt |= (ULONG) inb(ioport+CtcReg_Low); + DEBUG1(printk ("Blast: Read %i times DMA_Status %02x", i, bval);) + ResidCnt = (ULONG) DC390_read8 (CtcReg_High); + ResidCnt <<= 8; + ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid); + ResidCnt <<= 8; + ResidCnt |= (ULONG) DC390_read8 (CtcReg_Low); xferCnt = pSRB->SGToBeXferLen - ResidCnt; - pSRB->SGPhysAddr += xferCnt; + pSRB->SGBusAddr += xferCnt; pSRB->TotalXferredLen += xferCnt; pSRB->SGToBeXferLen = ResidCnt; if( residual ) { - bval = inb(ioport+ScsiFifo); /* get residual byte */ - ptr = (PUCHAR) phys_to_virt( pSRB->SGPhysAddr ); + bval = DC390_read8 (ScsiFifo); /* get one residual byte */ + ptr = (PUCHAR) bus_to_virt( pSRB->SGBusAddr ); *ptr = bval; - pSRB->SGPhysAddr++; + pSRB->SGBusAddr++; xferCnt++; pSRB->TotalXferredLen++; pSRB->SGToBeXferLen--; } + DEBUG1(printk ("Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\ + pSRB->TotalXferredLen, pSRB->SGToBeXferLen);) + } } } static void -DC390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_Command_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { } static void -DC390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_Status_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR bval; - USHORT ioport; - ioport = pACB->IOPortBase; - bval = inb(ioport+ScsiFifo); - pSRB->TargetStatus = bval; - bval++; - bval = inb(ioport+ScsiFifo); /* get message */ - pSRB->EndMessage = bval; + pSRB->TargetStatus = DC390_read8 (ScsiFifo); + //udelay (1); + pSRB->EndMessage = DC390_read8 (ScsiFifo); /* get message */ *psstatus = SCSI_NOP0; pSRB->SRBState = SRB_COMPLETED; - bval = MSG_ACCEPTED_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); } static void -DC390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_MsgOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) ) *psstatus = SCSI_NOP0; + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); } -static void -DC390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +void +dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { UCHAR bval; - USHORT ioport, wval, wval1; + USHORT wval, wval1; PDCB pDCB; PSRB psrb; - ioport = pACB->IOPortBase; pDCB = pACB->pActiveDCB; - bval = inb( ioport+ScsiFifo ); + bval = DC390_read8 (ScsiFifo); if( !(pSRB->SRBState & SRB_MSGIN_MULTI) ) { if(bval == MSG_DISCONNECT) @@ -490,12 +583,12 @@ pSRB->SRBState |= SRB_MSGIN_MULTI; pSRB->MsgInBuf[0] = bval; pSRB->MsgCnt = 1; - pSRB->pMsgPtr = &pSRB->MsgInBuf[1]; + pSRB->pMsgPtr = &(pSRB->MsgInBuf[1]); } else if(bval == MSG_REJECT_) { - bval = RESET_ATN_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, RESET_ATN_CMD); + pDCB->NegoPeriod = 50; if( pSRB->SRBState & DO_SYNC_NEGO) goto set_async; } @@ -521,7 +614,7 @@ psrb = pDCB->pGoingLast; if( pSRB ) { - for( ;; ) + for( ;pSRB ; ) { if(pSRB->TagNumber != bval) { @@ -535,7 +628,7 @@ if( pDCB->DCBFlag & ABORT_DEV_ ) { pSRB->SRBState = SRB_ABORT_SENT; - EnableMsgOut( pACB, pSRB ); + dc390_EnableMsgOut( pACB, pSRB ); } if( !(pSRB->SRBState & SRB_DISCONNECT) ) goto mingx0; @@ -549,234 +642,199 @@ pSRB->SRBState = SRB_UNEXPECT_RESEL; pDCB->pActiveSRB = pSRB; pSRB->MsgOutBuf[0] = MSG_ABORT_TAG; - EnableMsgOut2( pACB, pSRB ); + dc390_EnableMsgOut2( pACB, pSRB ); } } } else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgCnt == 5) ) - { - pSRB->SRBState &= ~(SRB_MSGIN_MULTI+DO_SYNC_NEGO); - if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != 1) ) + { /* Note: This will fail for target initiated SDTR ? */ + pSRB->SRBState &= ~(SRB_MSGIN_MULTI); + if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != EXTENDED_SDTR) ) { /* reject_msg: */ pSRB->MsgCnt = 1; pSRB->MsgInBuf[0] = MSG_REJECT_; - bval = SET_ATN_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, SET_ATN_CMD); } else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) ) { set_async: pDCB = pSRB->pSRBDCB; + if (!(pSRB->SRBState & DO_SYNC_NEGO)) + printk ("DC390: Target (%i,%i) initiates Non-Sync?\n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + pSRB->SRBState &= ~DO_SYNC_NEGO; pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE); pDCB->SyncPeriod = 0; pDCB->SyncOffset = 0; - pDCB->CtrlR3 = FAST_CLK; /* ;non_fast */ + pDCB->CtrlR3 = FAST_CLK; /* fast clock / normal scsi */ pDCB->CtrlR4 &= 0x3f; - pDCB->CtrlR4 |= EATER_25NS; /* ; 25ns glitch eater */ - goto re_prog; + pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ + goto re_prog; } else { /* set_sync: */ pDCB = pSRB->pSRBDCB; + if (!(pSRB->SRBState & DO_SYNC_NEGO)) + printk ("DC390: Target (%i,%i) initiates Sync: %ins %i ?\n", + pDCB->UnitSCSIID, pDCB->UnitSCSILUN, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]); + pSRB->SRBState &= ~DO_SYNC_NEGO; pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE; pDCB->SyncOffset &= 0x0f0; pDCB->SyncOffset |= pSRB->MsgInBuf[4]; pDCB->NegoPeriod = pSRB->MsgInBuf[3]; wval = (USHORT) pSRB->MsgInBuf[3]; - wval = wval << 2; - wval--; - wval1 = wval / 25; + wval = wval << 2; wval -= 3; wval1 = wval / 25; /* compute speed */ if( (wval1 * 25) != wval) wval1++; - bval = FAST_CLK+FAST_SCSI; - pDCB->CtrlR4 &= 0x3f; - if(wval1 >= 8) + bval = FAST_CLK+FAST_SCSI; /* fast clock / fast scsi */ + pDCB->CtrlR4 &= 0x3f; /* Glitch eater: 12ns less than normal */ + if (pACB->glitch_cfg != NS_TO_GLITCH(0)) + pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1)); + else + pDCB->CtrlR4 |= NS_TO_GLITCH(0); + if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */ + if (wval1 >= 8) { - wval1--; - bval = FAST_CLK; /* ;fast clock/normal scsi */ - pDCB->CtrlR4 |= EATER_25NS; /* ;25 ns glitch eater */ + wval1--; /* Timing computation differs by 1 from FAST_SCSI */ + bval = FAST_CLK; /* fast clock / normal scsi */ + pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ } pDCB->CtrlR3 = bval; pDCB->SyncPeriod = (UCHAR)wval1; re_prog: - bval = pDCB->SyncPeriod; - outb(bval, ioport+Sync_Period); - bval = pDCB->SyncOffset; - outb(bval, ioport+Sync_Offset); - bval = pDCB->CtrlR3; - outb(bval, ioport+CtrlReg3); - bval = pDCB->CtrlR4; - outb(bval, ioport+CtrlReg4); - SetXferRate( pACB, pDCB); + DC390_write8 (Sync_Period, pDCB->SyncPeriod); + DC390_write8 (Sync_Offset, pDCB->SyncOffset); + DC390_write8 (CtrlReg3, pDCB->CtrlR3); + DC390_write8 (CtrlReg4, pDCB->CtrlR4); + dc390_SetXferRate (pACB, pDCB); } } } min6: *psstatus = SCSI_NOP0; - bval = MSG_ACCEPTED_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); } -static void -DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir) +void +dc390_DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir) { PSGL psgl; - UCHAR bval; - USHORT ioport; ULONG lval; - - ioport = pACB->IOPortBase; if( pSRB->SGIndex < pSRB->SGcount ) { - bval = DMA_IDLE_CMD | ioDir; /* ;+EN_DMA_INT */ - outb( bval, ioport+DMA_Cmd); + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */); if( !pSRB->SGToBeXferLen ) { psgl = pSRB->pSegmentList; - pSRB->SGPhysAddr = virt_to_phys( psgl->address ); + pSRB->SGBusAddr = virt_to_bus( psgl->address ); pSRB->SGToBeXferLen = (ULONG) psgl->length; + DEBUG1(printk (" DC390: Next SG segment.");) } lval = pSRB->SGToBeXferLen; - bval = (UCHAR) lval; - outb(bval,ioport+CtcReg_Low); - lval = lval >> 8; - bval = (UCHAR) lval; - outb(bval,ioport+CtcReg_Mid); - lval = lval >> 8; - bval = (UCHAR) lval; - outb(bval,ioport+CtcReg_High); + DEBUG1(printk (" DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);) + DC390_write8 (CtcReg_Low, (UCHAR) lval); + lval >>= 8; + DC390_write8 (CtcReg_Mid, (UCHAR) lval); + lval >>= 8; + DC390_write8 (CtcReg_High, (UCHAR) lval); - lval = pSRB->SGToBeXferLen; - outl(lval, ioport+DMA_XferCnt); - - lval = pSRB->SGPhysAddr; - outl( lval, ioport+DMA_XferAddr); - - bval = DMA_COMMAND+INFO_XFER_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen); + DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */ pSRB->SRBState = SRB_DATA_XFER; - bval = DMA_IDLE_CMD | ioDir; /* ;+EN_DMA_INT */ - outb(bval, ioport+DMA_Cmd); + DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD); - bval = DMA_START_CMD | ioDir; /* ;+EN_DMA_INT */ - outb(bval, ioport+DMA_Cmd); + DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); + //DEBUG1(printk ("DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));) } else /* xfer pad */ { + UCHAR bval = 0; if( pSRB->SGcount ) { pSRB->AdaptStatus = H_OVER_UNDER_RUN; pSRB->SRBStatus |= OVER_RUN; + DEBUG0(printk (" DC390: Overrun -");) } - bval = 0; - outb(bval,ioport+CtcReg_Low); - outb(bval,ioport+CtcReg_Mid); - outb(bval,ioport+CtcReg_High); + DEBUG0(printk (" Clear transfer pad \n");) + DC390_write8 (CtcReg_Low, bval); + DC390_write8 (CtcReg_Mid, bval); + DC390_write8 (CtcReg_High, bval); pSRB->SRBState |= SRB_XFERPAD; - bval = DMA_COMMAND+XFER_PAD_BYTE; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE); /* - bval = DMA_IDLE_CMD | ioDir; ;+EN_DMA_INT - outb(bval, ioport+DMA_Cmd); - bval = DMA_START_CMD | ioDir; ;+EN_DMA_INT - outb(bval, ioport+DMA_Cmd); + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT; + DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT); */ } } static void -DC390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_DataOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR ioDir; - - ioDir = WRITE_DIRECTION; - DataIO_Comm( pACB, pSRB, ioDir); + dc390_DataIO_Comm (pACB, pSRB, WRITE_DIRECTION); } static void -DC390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_DataInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR ioDir; - - ioDir = READ_DIRECTION; - DataIO_Comm( pACB, pSRB, ioDir); + dc390_DataIO_Comm (pACB, pSRB, READ_DIRECTION); } -static void -DC390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +void +dc390_CommandPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) { PDCB pDCB; - UCHAR bval; + UCHAR i, cnt; PUCHAR ptr; - USHORT ioport, i, cnt; - - ioport = pACB->IOPortBase; - bval = RESET_ATN_CMD; - outb(bval, ioport+ScsiCmd); - bval = CLEAR_FIFO_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, RESET_ATN_CMD); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); if( !(pSRB->SRBFlag & AUTO_REQSENSE) ) { - cnt = (USHORT) pSRB->ScsiCmdLen; + cnt = (UCHAR) pSRB->ScsiCmdLen; ptr = (PUCHAR) pSRB->CmdBlock; for(i=0; i < cnt; i++) - { - outb(*ptr, ioport+ScsiFifo); - ptr++; - } + DC390_write8 (ScsiFifo, *(ptr++)); } else { - bval = REQUEST_SENSE; - outb(bval, ioport+ScsiFifo); + UCHAR bval = 0; + DC390_write8 (ScsiFifo, REQUEST_SENSE); pDCB = pACB->pActiveDCB; - bval = pDCB->IdentifyMsg << 5; - outb(bval, ioport+ScsiFifo); - bval = 0; - outb(bval, ioport+ScsiFifo); - outb(bval, ioport+ScsiFifo); - bval = sizeof(pSRB->pcmd->sense_buffer); - outb(bval, ioport+ScsiFifo); - bval = 0; - outb(bval, ioport+ScsiFifo); + DC390_write8 (ScsiFifo, pDCB->IdentifyMsg << 5); + DC390_write8 (ScsiFifo, bval); + DC390_write8 (ScsiFifo, bval); + DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer)); + DC390_write8 (ScsiFifo, bval); } pSRB->SRBState = SRB_COMMAND; - bval = INFO_XFER_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, INFO_XFER_CMD); } static void -DC390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_StatusPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR bval; - USHORT ioport; - - ioport = pACB->IOPortBase; - bval = CLEAR_FIFO_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); pSRB->SRBState = SRB_STATUS; - bval = INITIATOR_CMD_CMPLTE; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, INITIATOR_CMD_CMPLTE); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); } -static void -DC390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +void +dc390_MsgOutPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR bval; - USHORT ioport, i, cnt; + UCHAR bval, i, cnt; PUCHAR ptr; PDCB pDCB; - ioport = pACB->IOPortBase; - bval = CLEAR_FIFO_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); pDCB = pACB->pActiveDCB; if( !(pSRB->SRBState & SRB_MSGOUT) ) { @@ -785,10 +843,7 @@ { ptr = (PUCHAR) pSRB->MsgOutBuf; for(i=0; i < cnt; i++) - { - outb(*ptr, ioport+ScsiFifo); - ptr++; - } + DC390_write8 (ScsiFifo, *(ptr++)); pSRB->MsgCnt = 0; if( (pDCB->DCBFlag & ABORT_DEV_) && (pSRB->MsgOutBuf[0] == MSG_ABORT) ) @@ -804,76 +859,67 @@ if( pDCB->SyncMode & SYNC_ENABLE ) goto mop1; } - outb(bval, ioport+ScsiFifo); + DC390_write8 (ScsiFifo, bval); } - bval = INFO_XFER_CMD; - outb( bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, INFO_XFER_CMD); } else { mop1: - bval = MSG_EXTENDED; - outb(bval, ioport+ScsiFifo); - bval = 3; /* ;length of extended msg */ - outb(bval, ioport+ScsiFifo); - bval = 1; /* ; sync nego */ - outb(bval, ioport+ScsiFifo); - bval = pDCB->NegoPeriod; - outb(bval, ioport+ScsiFifo); - bval = SYNC_NEGO_OFFSET; - outb(bval, ioport+ScsiFifo); + //printk ("DC390: Send SDTR message to %i %i ... \n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN); + DC390_write8 (ScsiFifo, MSG_EXTENDED); + DC390_write8 (ScsiFifo, 3); /* ;length of extended msg */ + DC390_write8 (ScsiFifo, EXTENDED_SDTR); /* ; sync nego */ + DC390_write8 (ScsiFifo, pDCB->NegoPeriod); + if (pDCB->SyncOffset & 0x0f) + DC390_write8 (ScsiFifo, pDCB->SyncOffset); + else + DC390_write8 (ScsiFifo, SYNC_NEGO_OFFSET); pSRB->SRBState |= DO_SYNC_NEGO; - bval = INFO_XFER_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, INFO_XFER_CMD); } } static void -DC390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_MsgInPhase( PACB pACB, PSRB pSRB, PUCHAR psstatus) { - UCHAR bval; - USHORT ioport; - - ioport = pACB->IOPortBase; - bval = CLEAR_FIFO_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); if( !(pSRB->SRBState & SRB_MSGIN) ) { - pSRB->SRBState &= SRB_DISCONNECT; + pSRB->SRBState &= ~SRB_DISCONNECT; pSRB->SRBState |= SRB_MSGIN; } - bval = INFO_XFER_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, INFO_XFER_CMD); + //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); } static void -DC390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_Nop_0( PACB pACB, PSRB pSRB, PUCHAR psstatus) { } static void -DC390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus) +dc390_Nop_1( PACB pACB, PSRB pSRB, PUCHAR psstatus) { } static void -SetXferRate( PACB pACB, PDCB pDCB ) +dc390_SetXferRate( PACB pACB, PDCB pDCB ) { - UCHAR bval; - USHORT cnt, i; + UCHAR bval, i, cnt; PDCB ptr; if( !(pDCB->IdentifyMsg & 0x07) ) { if( pACB->scan_devices ) { - CurrSyncOffset = pDCB->SyncOffset; + dc390_CurrSyncOffset = pDCB->SyncOffset; } else { ptr = pACB->pLinkDCB; - cnt = pACB->DeviceCnt; + cnt = pACB->DCBCnt; bval = pDCB->UnitSCSIID; for(i=0; iIOPortBase; pDCB = pACB->pActiveDCB; if (!pDCB) { -#ifdef DC390_DEBUG0 - printk("ACB:%08lx->ActiveDCB:%08lx !,",(ULONG)pACB,(ULONG)pDCB); -#endif - restore_flags(flags); return; + int j = 400; + DEBUG0(printk(KERN_WARNING "ACB:%08lx->ActiveDCB:%08lx IOPort:%04x IRQ:%02x !\n",\ + (ULONG)pACB,(ULONG)pDCB,pACB->IOPortBase,pACB->IRQLevel);) + while (--j) udelay (1000); + DC390_read8 (INT_Status); /* Reset Pending INT */ + DC390_write8 (ScsiCmd, EN_SEL_RESEL); + return; } pSRB = pDCB->pActiveSRB; pACB->pActiveDCB = 0; pSRB->ScsiPhase = SCSI_NOP0; - bval = EN_SEL_RESEL; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, EN_SEL_RESEL); if( pSRB->SRBState & SRB_UNEXPECT_RESEL ) { pSRB->SRBState = 0; - DoWaitingSRB( pACB ); + dc390_DoWaitingSRB( pACB ); } else if( pSRB->SRBState & SRB_ABORT_SENT ) { @@ -942,7 +983,7 @@ pSRB = psrb; } pDCB->pGoingSRB = 0; - DoWaitingSRB( pACB ); + dc390_DoWaitingSRB( pACB ); } else { @@ -952,7 +993,7 @@ if( !(pACB->scan_devices) ) { pSRB->SRBState = SRB_READY; - RewaitSRB( pDCB, pSRB); + dc390_RewaitSRB( pDCB, pSRB); } else { @@ -962,76 +1003,66 @@ } else if( pSRB->SRBState & SRB_DISCONNECT ) { - DoWaitingSRB( pACB ); + dc390_DoWaitingSRB( pACB ); } else if( pSRB->SRBState & SRB_COMPLETED ) { disc1: if(pDCB->MaxCommand > 1) { - bval = pSRB->TagNumber; - pDCB->TagMask &= (~(1 << bval)); /* free tag mask */ + pDCB->TagMask &= (~(1 << pSRB->TagNumber)); /* free tag mask */ } pDCB->pActiveSRB = 0; pSRB->SRBState = SRB_FREE; - SRBdone( pACB, pDCB, pSRB); + dc390_SRBdone( pACB, pDCB, pSRB); } } - restore_flags(flags); return; } -static void -DC390_Reselect( PACB pACB ) +void +dc390_Reselect( PACB pACB ) { - PDCB pDCB, pdcb; + PDCB pDCB; PSRB pSRB; - USHORT ioport, wval; - UCHAR bval, bval1; - + USHORT wval; + UCHAR bval; -#ifdef DC390_DEBUG0 - printk("RSEL,"); -#endif - ioport = pACB->IOPortBase; + DEBUG0(printk(KERN_INFO "RSEL,");) pDCB = pACB->pActiveDCB; if( pDCB ) { /* Arbitration lost but Reselection win */ + DEBUG0(printk ("(ActiveDCB != 0)");) pSRB = pDCB->pActiveSRB; if( !( pACB->scan_devices ) ) { pSRB->SRBState = SRB_READY; - RewaitSRB( pDCB, pSRB); + dc390_RewaitSRB( pDCB, pSRB); } } - bval = inb(ioport+ScsiFifo); /* get ID */ - bval = bval ^ pACB->HostID_Bit; + bval = DC390_read8 (ScsiFifo); /* get ID */ + DEBUG0(printk ("Dev %02x,", bval);) + bval ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */ wval = 0; - bval1 = 1; - for(;;) - { - if( !(bval & bval1) ) - { - bval1 = bval1 << 1; - wval++; - } - else - break; - } - wval |= ( (USHORT) inb(ioport+ScsiFifo) & 7) << 8; /* get LUN */ + 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; - pdcb = pDCB; while( wval != *((PUSHORT) &pDCB->UnitSCSIID) ) { pDCB = pDCB->pNextDCB; - if( pDCB == pdcb ) + if( pDCB == pACB->pLinkDCB ) + { + printk (KERN_ERR "DC390: Reselect from non existing device (ID %02x, LUN %02x)\n", + wval & 0xff, (wval & 0xff00) >> 8); return; + } } pACB->pActiveDCB = pDCB; - if( pDCB->SyncMode & EN_TAG_QUEUING ) + if( pDCB->SyncMode & EN_TAG_QUEUEING ) { - pSRB = pACB->pTmpSRB; + pSRB = pACB->pTmpSRB; /* ?? */ pDCB->pActiveSRB = pSRB; } else @@ -1041,57 +1072,163 @@ { 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); pDCB->pActiveSRB = pSRB; - EnableMsgOut( pACB, pSRB ); + dc390_EnableMsgOut( pACB, pSRB ); } else { if( pDCB->DCBFlag & ABORT_DEV_ ) { pSRB->SRBState = SRB_ABORT_SENT; - EnableMsgOut( pACB, pSRB ); + printk (KERN_NOTICE "DC390: Reselect: Abort (ID %02x, LUN %02x)\n", + wval & 0xff, (wval & 0xff00) >> 8); + dc390_EnableMsgOut( pACB, pSRB ); } else pSRB->SRBState = SRB_DATA_XFER; } } + + DEBUG1(printk ("Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);) pSRB->ScsiPhase = SCSI_NOP0; - bval = pDCB->UnitSCSIID; - outb( bval, ioport+Scsi_Dest_ID); - bval = pDCB->SyncPeriod; - outb(bval, ioport+Sync_Period); - bval = pDCB->SyncOffset; - outb( bval, ioport+Sync_Offset); - bval = pDCB->CtrlR1; - outb(bval, ioport+CtrlReg1); - bval = pDCB->CtrlR3; - outb(bval, ioport+CtrlReg3); - bval = pDCB->CtrlR4; /* ; Glitch eater */ - outb(bval, ioport+CtrlReg4); - bval = MSG_ACCEPTED_CMD; /* ;to rls the /ACK signal */ - outb(bval, ioport+ScsiCmd); + DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID); + DC390_write8 (Sync_Period, pDCB->SyncPeriod); + DC390_write8 (Sync_Offset, pDCB->SyncOffset); + DC390_write8 (CtrlReg1, pDCB->CtrlR1); + DC390_write8 (CtrlReg3, pDCB->CtrlR3); + DC390_write8 (CtrlReg4, pDCB->CtrlR4); /* ; Glitch eater */ + DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); /* ;to release the /ACK signal */ } -static void -SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) +static void +dc390_remove_dev (PACB pACB, PDCB pDCB) +{ + 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);) + return; + }; + + if (pDCB == pACB->pLinkDCB) + { + if (pDCB->pNextDCB == pDCB) pDCB->pNextDCB = 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; + pACB->DCBCnt--; + /* pACB->DeviceCnt--; */ +}; + + +static UCHAR __inline__ +dc390_tagq_blacklist (char* name) +{ + UCHAR i; + for(i=0; iVers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2 ) + { + if ( (ptr->Flags & SCSI_INQ_CMDQUEUE) && + (pDCB->DevMode & TAG_QUEUEING_) && + /* ((pDCB->DevType == TYPE_DISK) + || (pDCB->DevType == TYPE_MOD)) &&*/ + !dc390_tagq_blacklist (((char*)ptr)+8) ) + { + pDCB->MaxCommand = pDCB->pDCBACB->TagMaxNum; + pDCB->SyncMode |= EN_TAG_QUEUEING /* | EN_ATN_STOP */; + 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; + } + } +}; + + +static void +dc390_add_dev (PACB pACB, PDCB pDCB, PSCSI_INQDATA ptr) +{ + UCHAR bval1 = ptr->DevType & SCSI_DEVTYPE; + pDCB->DevType = bval1; + /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */ + dc390_disc_tagq_set (pDCB, ptr); +}; + + +void +dc390_SRBdone( PACB pACB, PDCB pDCB, PSRB pSRB ) { PSRB psrb; - UCHAR bval, bval1, i, j, status; + UCHAR bval, status, i; PSCSICMD pcmd; PSCSI_INQDATA ptr; - USHORT disable_tag; - ULONG flags; PSGL ptr2; ULONG swlval; pcmd = pSRB->pcmd; status = pSRB->TargetStatus; + 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; +#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, + 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, + 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, + 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, + 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, + status, pACB->scan_devices); break; + } +#endif + //pcmd->result = DRIVER_SENSE << 24 | DID_OK << 16 | status; if(status == SCSI_STAT_CHECKCOND) { pcmd->result = DID_BAD_TARGET << 16; @@ -1099,7 +1236,7 @@ } if(pSRB->RetryCnt == 0) { - *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; + (ULONG)(pSRB->CmdBlock[0]) = pSRB->Segment0[0]; pSRB->TotalXferredLen = pSRB->Segment1[1]; if( (pSRB->TotalXferredLen) && (pSRB->TotalXferredLen >= pcmd->underflow) ) @@ -1107,28 +1244,29 @@ else pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) | SCSI_STAT_CHECKCOND; -#ifdef DC390_DEBUG0 - printk("Cmd=%2x,Result=%8x,XferL=%8x,",pSRB->CmdBlock[0], - (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen); -#endif + REMOVABLEDEBUG(printk("Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\ + (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);) goto ckc_e; } - else + else /* Retry */ { pSRB->RetryCnt--; pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; *((PULONG) &(pSRB->CmdBlock[0])) = pSRB->Segment0[0]; *((PULONG) &(pSRB->CmdBlock[4])) = pSRB->Segment0[1]; - if( pSRB->CmdBlock[0] == TEST_UNIT_READY ) + /* Don't retry on TEST_UNIT_READY */ + if( pSRB->CmdBlock[0] == TEST_UNIT_READY /* || pSRB->CmdBlock[0] == START_STOP */) { - pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) | - SCSI_STAT_CHECKCOND; + pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) + | SCSI_STAT_CHECKCOND; + REMOVABLEDEBUG(printk("Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[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); + pSRB->SGcount = (UCHAR) pSRB->Segment1[0]; + pSRB->ScsiCmdLen = (UCHAR) (pSRB->Segment1[0] >> 8); pSRB->SGIndex = 0; pSRB->TotalXferredLen = 0; pSRB->SGToBeXferLen = 0; @@ -1140,8 +1278,8 @@ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; pSRB->Segmentx.length = pcmd->request_bufflen; } - if( DC390_StartSCSI( pACB, pDCB, pSRB ) ) - RewaitSRB( pDCB, pSRB ); + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) + dc390_RewaitSRB( pDCB, pSRB ); return; } } @@ -1149,6 +1287,8 @@ { if( status == SCSI_STAT_CHECKCOND) { + REMOVABLEDEBUG(printk (KERN_INFO "DC390: Scsi_Stat_CheckCond (Cmd %02x, Id %02x, LUN %02x)\n",\ + pcmd->cmnd[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) if( (pSRB->SGIndex < pSRB->SGcount) && (pSRB->SGcount) && (pSRB->SGToBeXferLen) ) { bval = pSRB->SGcount; @@ -1159,12 +1299,10 @@ swlval += ptr2->length; ptr2++; } -#ifdef DC390_DEBUG0 - printk("XferredLen=%8x,NotXferLen=%8x,", - (UINT) pSRB->TotalXferredLen, (UINT) swlval); -#endif + REMOVABLEDEBUG(printk("XferredLen=%08x,NotXferLen=%08x\n",\ + (UINT) pSRB->TotalXferredLen, (UINT) swlval);) } - RequestSense( pACB, pDCB, pSRB ); + dc390_RequestSense( pACB, pDCB, pSRB ); return; } else if( status == SCSI_STAT_QUEUEFULL ) @@ -1172,7 +1310,7 @@ bval = (UCHAR) pDCB->GoingSRBCnt; bval--; pDCB->MaxCommand = bval; - RewaitSRB( pDCB, pSRB ); + dc390_RewaitSRB( pDCB, pSRB ); pSRB->AdaptStatus = 0; pSRB->TargetStatus = 0; return; @@ -1182,12 +1320,22 @@ pSRB->AdaptStatus = H_SEL_TIMEOUT; pSRB->TargetStatus = 0; pcmd->result = DID_BAD_TARGET << 16; + /* Devices are removed below ... */ } - else + else if (status == SCSI_STAT_BUSY && + (pSRB->CmdBlock[0] == TEST_UNIT_READY || pSRB->CmdBlock[0] == INQUIRY) && + pACB->scan_devices) { pSRB->AdaptStatus = 0; + pSRB->TargetStatus = status; + pcmd->result = (ULONG) (pSRB->EndMessage << 8) + /* | (ULONG) status */; + } + else + { /* Another error */ + pSRB->AdaptStatus = 0; if( pSRB->RetryCnt ) - { + { /* Retry */ pSRB->RetryCnt--; pSRB->TargetStatus = 0; pSRB->SGIndex = 0; @@ -1201,19 +1349,19 @@ pSRB->Segmentx.address = (PUCHAR) pcmd->request_buffer; pSRB->Segmentx.length = pcmd->request_bufflen; } - if( DC390_StartSCSI( pACB, pDCB, pSRB ) ) - RewaitSRB( pDCB, pSRB ); + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) + dc390_RewaitSRB( pDCB, pSRB ); return; } else - { + { /* Report error */ pcmd->result |= (DID_ERROR << 16) | (ULONG) (pSRB->EndMessage << 8) | (ULONG) status; } } } else - { + { /* Target status == 0 */ status = pSRB->AdaptStatus; if(status & H_OVER_UNDER_RUN) { @@ -1237,95 +1385,57 @@ { if( pSRB->CmdBlock[0] == TEST_UNIT_READY ) { - if(pcmd->result != (DID_OK << 16)) - { - if( pcmd->result & SCSI_STAT_CHECKCOND ) - { - goto RTN_OK; - } - else - { - pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun); - pPrevDCB->pNextDCB = pACB->pLinkDCB; - if( (pcmd->target == pACB->max_id) && - ((pcmd->lun == 0) || (pcmd->lun == pACB->max_lun)) ) - { - pACB->scan_devices = 0; - } - } - } - else - { -RTN_OK: - pPrevDCB->pNextDCB = pDCB; - pDCB->pNextDCB = pACB->pLinkDCB; - if( (pcmd->target == pACB->max_id) && (pcmd->lun == pACB->max_lun) ) - pACB->scan_devices = END_SCAN; - } - } - else if( pSRB->CmdBlock[0] == INQUIRY ) - { - if( (pcmd->target == pACB->max_id) && - (pcmd->lun == pACB->max_lun) ) - { - pACB->scan_devices = 0; - } - ptr = (PSCSI_INQDATA) (pcmd->request_buffer); - if( pcmd->use_sg ) - ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); - bval1 = ptr->DevType & SCSI_DEVTYPE; - if(bval1 == SCSI_NODEV) - { - pACB->DCBmap[pcmd->target] &= ~(1 << pcmd->lun); - pPrevDCB->pNextDCB = pACB->pLinkDCB; +#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", + 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) + { + /* device not present: remove */ + dc390_remove_dev (pACB, pDCB); + + if( (pcmd->target == pACB->pScsiHost->max_id - 1) && + ((pcmd->lun == 0) || (pcmd->lun == pACB->pScsiHost->max_lun - 1)) ) + pACB->scan_devices = 0; } else { - pACB->DeviceCnt++; - pPrevDCB = pDCB; - pACB->pDCB_free = (PDCB) ((ULONG) (pACB->pDCB_free) + sizeof( DC390_DCB )); - pDCB->DevType = bval1; - if(bval1 == TYPE_DISK || bval1 == TYPE_MOD) - { - if( (((ptr->Vers & 0x07) >= 2) || ((ptr->RDF & 0x0F) == 2)) && - (ptr->Flags & SCSI_INQ_CMDQUEUE) && - (pDCB->DevMode & TAG_QUEUING_) && - (pDCB->DevMode & EN_DISCONNECT_) ) - { - disable_tag = 0; - for(i=0; iMaxCommand = pACB->TagMaxNum; - pDCB->SyncMode |= EN_TAG_QUEUING; - pDCB->TagMask = 0; - } - else - { - pDCB->SyncMode |= EN_ATN_STOP; - } - } - } + /* device present: add */ + if( (pcmd->target == pACB->pScsiHost->max_id - 1) && + (pcmd->lun == pACB->pScsiHost->max_lun - 1) ) + pACB->scan_devices = END_SCAN ; + /* pACB->DeviceCnt++; */ /* Dev is added on INQUIRY */ } } } - - save_flags( flags ); - cli(); -/* ReleaseSRB( pDCB, pSRB ); */ + + if( pSRB->CmdBlock[0] == INQUIRY && + (pcmd->result == DID_OK << 16 || pcmd->result & SCSI_STAT_CHECKCOND) ) + { + ptr = (PSCSI_INQDATA) (pcmd->request_buffer); + if( pcmd->use_sg ) + ptr = (PSCSI_INQDATA) (((PSGL) ptr)->address); + if ((ptr->DevType & SCSI_DEVTYPE) == TYPE_NODEV) + { + /* device not present: remove */ + dc390_remove_dev (pACB, pDCB); + } + else + { + /* device found: add */ + dc390_add_dev (pACB, pDCB, ptr); + if (pACB->scan_devices) pACB->DeviceCnt++; + } + if( (pcmd->target == pACB->pScsiHost->max_id - 1) && + (pcmd->lun == pACB->pScsiHost->max_lun - 1) ) + pACB->scan_devices = 0; + }; +/* dc390_ReleaseSRB( pDCB, pSRB ); */ if(pSRB == pDCB->pGoingSRB ) { @@ -1344,33 +1454,34 @@ pACB->pFreeSRB = pSRB; pDCB->GoingSRBCnt--; - DoWaitingSRB( pACB ); - restore_flags(flags); + dc390_DoWaitingSRB( pACB ); -/* Notify cmd done */ + DC390_UNLOCK_ACB_NI; pcmd->scsi_done( pcmd ); + DC390_LOCK_ACB_NI; if( pDCB->QIORBCnt ) - DoNextCmd( pACB, pDCB ); + dc390_DoNextCmd( pACB, pDCB ); return; } -static void -DoingSRB_Done( PACB pACB ) +/* Remove all SRBs and tell midlevel code DID_RESET */ +void +dc390_DoingSRB_Done( PACB pACB ) { - PDCB pDCB, pdcb; - PSRB psrb, psrb2; - USHORT cnt, i; + PDCB pDCB, pdcb; + PSRB psrb, psrb2; + UCHAR i; PSCSICMD pcmd; pDCB = pACB->pLinkDCB; pdcb = pDCB; + if (! pdcb) return; do { - cnt = pdcb->GoingSRBCnt; psrb = pdcb->pGoingSRB; - for( i=0; iGoingSRBCnt; i++) { psrb2 = psrb->pNextSRB; pcmd = psrb->pcmd; @@ -1381,63 +1492,46 @@ psrb->pNextSRB = pACB->pFreeSRB; pACB->pFreeSRB = psrb; + DC390_UNLOCK_ACB_NI; pcmd->scsi_done( pcmd ); + DC390_LOCK_ACB_NI; psrb = psrb2; } pdcb->GoingSRBCnt = 0;; pdcb->pGoingSRB = NULL; pdcb->TagMask = 0; pdcb = pdcb->pNextDCB; - } - while( pdcb != pDCB ); + } while( pdcb != pDCB ); } static void -DC390_ResetSCSIBus( PACB pACB ) +dc390_ResetSCSIBus( PACB pACB ) { - USHORT ioport; - UCHAR bval; - ULONG flags; - - save_flags(flags); - cli(); pACB->ACBFlag |= RESET_DEV; - ioport = pACB->IOPortBase; - - bval = DMA_IDLE_CMD; - outb(bval,ioport+DMA_Cmd); - bval = RST_SCSI_BUS_CMD; - outb(bval,ioport+ScsiCmd); + 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); - restore_flags(flags); return; } - static void -DC390_ScsiRstDetect( PACB pACB ) +dc390_ScsiRstDetect( PACB pACB ) { - ULONG wlval, flags; - USHORT ioport; - UCHAR bval; - -#ifdef DC390_DEBUG0 - printk("RST_DETEC"); -#endif + printk ("DC390: Rst_Detect: laststat = %08lx\n", dc390_laststatus); + //DEBUG0(printk(KERN_INFO "RST_DETECT,");) + DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); + /* Unlock before ? */ /* delay a second */ - mdelay(1000); - - save_flags(flags); - cli(); - - ioport = pACB->IOPortBase; - bval = DMA_IDLE_CMD; - outb(bval,ioport+DMA_Cmd); - bval = CLEAR_FIFO_CMD; - outb(bval,ioport+ScsiCmd); + { unsigned int msec = 1*1000; while (--msec) udelay(1000); } + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); if( pACB->ACBFlag & RESET_DEV ) pACB->ACBFlag |= RESET_DONE; @@ -1445,30 +1539,32 @@ { pACB->ACBFlag |= RESET_DETECT; - ResetDevParam( pACB ); -/* DoingSRB_Done( pACB ); ???? */ - RecoverSRB( pACB ); + dc390_ResetDevParam( pACB ); +/* dc390_DoingSRB_Done( pACB ); ???? */ + dc390_RecoverSRB( pACB ); pACB->pActiveDCB = NULL; pACB->ACBFlag = 0; - DoWaitingSRB( pACB ); + dc390_DoWaitingSRB( pACB ); } - restore_flags(flags); return; } -static void -RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ) +static void __inline__ +dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB ) { PSCSICMD pcmd; + REMOVABLEDEBUG(printk (KERN_INFO "DC390: RequestSense (Cmd %02x, Id %02x, LUN %02x)\n",\ + pSRB->CmdBlock[0], pDCB->UnitSCSIID, pDCB->UnitSCSILUN);) + pSRB->SRBFlag |= AUTO_REQSENSE; - pSRB->Segment0[0] = *((PULONG) &(pSRB->CmdBlock[0])); - pSRB->Segment0[1] = *((PULONG) &(pSRB->CmdBlock[4])); + 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->AdaptStatus = 0; - pSRB->TargetStatus = 0; + pSRB->TargetStatus = 0; /* SCSI_STAT_CHECKCOND; */ pcmd = pSRB->pcmd; @@ -1478,52 +1574,40 @@ pSRB->SGcount = 1; pSRB->SGIndex = 0; - *((PULONG) &(pSRB->CmdBlock[0])) = 0x00000003; + pSRB->CmdBlock[0] = REQUEST_SENSE; pSRB->CmdBlock[1] = pDCB->IdentifyMsg << 5; - *((PUSHORT) &(pSRB->CmdBlock[4])) = sizeof(pcmd->sense_buffer); + (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 ) ) - RewaitSRB( pDCB, pSRB ); + if( dc390_StartSCSI( pACB, pDCB, pSRB ) ) + dc390_RewaitSRB( pDCB, pSRB ); } -static void -EnableMsgOut2( PACB pACB, PSRB pSRB ) +static void __inline__ +dc390_EnableMsgOut2( PACB pACB, PSRB pSRB ) { - USHORT ioport; - UCHAR bval; - - ioport = pACB->IOPortBase; pSRB->MsgCnt = 1; - bval = SET_ATN_CMD; - outb(bval, ioport+ScsiCmd); + DC390_write8 (ScsiCmd, SET_ATN_CMD); } -static void -EnableMsgOut( PACB pACB, PSRB pSRB ) +static void __inline__ +dc390_EnableMsgOut( PACB pACB, PSRB pSRB ) { pSRB->MsgOutBuf[0] = MSG_ABORT; - EnableMsgOut2( pACB, pSRB ); + dc390_EnableMsgOut2( pACB, pSRB ); + pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_; } -static void -DC390_InvalidCmd( PACB pACB ) +static void __inline__ +dc390_InvalidCmd( PACB pACB ) { - UCHAR bval; - USHORT ioport; - PSRB pSRB; - - pSRB = pACB->pActiveDCB->pActiveSRB; - if( pSRB->SRBState & (SRB_START_+SRB_MSGOUT) ) - { - ioport = pACB->IOPortBase; - bval = CLEAR_FIFO_CMD; - outb(bval,(ioport+ScsiCmd)); - } + if( pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_+SRB_MSGOUT) ) + DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); }